From a7a95252afec8bfcc34ee5b8725136b17b77043f Mon Sep 17 00:00:00 2001 From: David Shao Date: Sat, 1 Apr 2017 16:32:06 -0700 Subject: [PATCH] Update drm/radeon to Linux 4.7.10 as much as possible... ...before other kernel changes. --- sys/conf/files | 2 + sys/dev/drm/radeon/Makefile | 2 + sys/dev/drm/radeon/atom.c | 227 +- sys/dev/drm/radeon/atombios.h | 4 +- sys/dev/drm/radeon/atombios_crtc.c | 75 +- sys/dev/drm/radeon/atombios_dp.c | 295 +-- sys/dev/drm/radeon/atombios_encoders.c | 175 +- sys/dev/drm/radeon/atombios_i2c.c | 13 +- sys/dev/drm/radeon/btc_dpm.c | 59 +- sys/dev/drm/radeon/cayman_blit_shaders.c | 2 +- sys/dev/drm/radeon/ci_dpm.c | 788 +++++- sys/dev/drm/radeon/ci_dpm.h | 9 + sys/dev/drm/radeon/ci_smc.c | 22 +- sys/dev/drm/radeon/cik.c | 2647 ++++++++++--------- sys/dev/drm/radeon/cik_sdma.c | 88 +- sys/dev/drm/radeon/cikd.h | 98 +- sys/dev/drm/radeon/dce3_1_afmt.c | 260 +- sys/dev/drm/radeon/dce6_afmt.c | 285 +- sys/dev/drm/radeon/evergreen.c | 872 ++++-- sys/dev/drm/radeon/evergreen_blit_shaders.c | 2 +- sys/dev/drm/radeon/evergreen_cs.c | 256 +- sys/dev/drm/radeon/evergreen_hdmi.c | 505 ++-- sys/dev/drm/radeon/evergreen_reg.h | 61 + sys/dev/drm/radeon/evergreend.h | 54 + sys/dev/drm/radeon/kv_dpm.c | 53 +- sys/dev/drm/radeon/ni.c | 335 ++- sys/dev/drm/radeon/ni_dma.c | 21 +- sys/dev/drm/radeon/ni_dpm.c | 40 +- sys/dev/drm/radeon/nid.h | 82 + sys/dev/drm/radeon/ppsmc.h | 18 +- sys/dev/drm/radeon/pptable.h | 8 + sys/dev/drm/radeon/r100.c | 105 +- sys/dev/drm/radeon/r200.c | 6 +- sys/dev/drm/radeon/r300.c | 65 +- sys/dev/drm/radeon/r420.c | 11 +- sys/dev/drm/radeon/r600.c | 419 ++- sys/dev/drm/radeon/r600_blit_shaders.c | 2 +- sys/dev/drm/radeon/r600_cs.c | 8 +- sys/dev/drm/radeon/r600_dma.c | 18 +- sys/dev/drm/radeon/r600_dpm.c | 11 +- sys/dev/drm/radeon/r600_dpm.h | 3 + sys/dev/drm/radeon/r600_hdmi.c | 410 +-- sys/dev/drm/radeon/radeon.h | 324 +-- sys/dev/drm/radeon/radeon_agp.c | 3 + sys/dev/drm/radeon/radeon_asic.c | 188 +- sys/dev/drm/radeon/radeon_asic.h | 123 +- sys/dev/drm/radeon/radeon_atombios.c | 85 +- sys/dev/drm/radeon/radeon_audio.c | 720 +++++ sys/dev/drm/radeon/radeon_audio.h | 149 ++ sys/dev/drm/radeon/radeon_bios.c | 15 +- sys/dev/drm/radeon/radeon_combios.c | 15 +- sys/dev/drm/radeon/radeon_connectors.c | 268 +- sys/dev/drm/radeon/radeon_cs.c | 61 +- sys/dev/drm/radeon/radeon_cursor.c | 251 +- sys/dev/drm/radeon/radeon_device.c | 153 +- sys/dev/drm/radeon/radeon_display.c | 222 +- sys/dev/drm/radeon/radeon_dp_auxch.c | 204 ++ sys/dev/drm/radeon/radeon_drv.c | 33 +- sys/dev/drm/radeon/radeon_encoders.c | 1 - sys/dev/drm/radeon/radeon_fb.c | 113 +- sys/dev/drm/radeon/radeon_fence.c | 37 +- sys/dev/drm/radeon/radeon_gart.c | 76 +- sys/dev/drm/radeon/radeon_gem.c | 9 +- sys/dev/drm/radeon/radeon_i2c.c | 92 +- sys/dev/drm/radeon/radeon_irq_kms.c | 95 +- sys/dev/drm/radeon/radeon_kms.c | 213 +- sys/dev/drm/radeon/radeon_legacy_crtc.c | 7 +- sys/dev/drm/radeon/radeon_legacy_encoders.c | 1 + sys/dev/drm/radeon/radeon_mode.h | 78 +- sys/dev/drm/radeon/radeon_object.c | 110 +- sys/dev/drm/radeon/radeon_object.h | 22 +- sys/dev/drm/radeon/radeon_pm.c | 443 +++- sys/dev/drm/radeon/radeon_ring.c | 36 +- sys/dev/drm/radeon/radeon_sa.c | 5 + sys/dev/drm/radeon/radeon_ttm.c | 59 +- sys/dev/drm/radeon/radeon_uvd.c | 244 +- sys/dev/drm/radeon/radeon_vce.c | 215 +- sys/dev/drm/radeon/radeon_vm.c | 136 +- sys/dev/drm/radeon/rs400.c | 25 +- sys/dev/drm/radeon/rs600.c | 48 +- sys/dev/drm/radeon/rs690.c | 28 +- sys/dev/drm/radeon/rs780_dpm.c | 22 + sys/dev/drm/radeon/rv515.c | 11 +- sys/dev/drm/radeon/rv6xx_dpm.c | 46 + sys/dev/drm/radeon/rv730_dpm.c | 2 +- sys/dev/drm/radeon/rv770.c | 109 +- sys/dev/drm/radeon/rv770_dpm.c | 48 +- sys/dev/drm/radeon/rv770_smc.c | 20 +- sys/dev/drm/radeon/rv770d.h | 3 + sys/dev/drm/radeon/si.c | 1744 +++++++----- sys/dev/drm/radeon/si_dma.c | 29 +- sys/dev/drm/radeon/si_dpm.c | 623 ++++- sys/dev/drm/radeon/si_dpm.h | 6 + sys/dev/drm/radeon/si_smc.c | 22 +- sys/dev/drm/radeon/sid.h | 107 +- sys/dev/drm/radeon/sislands_smc.h | 25 + sys/dev/drm/radeon/smu7_discrete.h | 30 +- sys/dev/drm/radeon/sumo_dpm.c | 28 + sys/dev/drm/radeon/trinity_dpm.c | 108 + sys/dev/drm/radeon/uvd_v1_0.c | 35 +- sys/dev/drm/radeon/uvd_v2_2.c | 34 +- sys/dev/drm/radeon/uvd_v4_2.c | 16 +- sys/dev/drm/radeon/vce_v1_0.c | 199 ++ sys/dev/drm/radeon/vce_v2_0.c | 19 +- 104 files changed, 11212 insertions(+), 5397 deletions(-) create mode 100644 sys/dev/drm/radeon/radeon_audio.c create mode 100644 sys/dev/drm/radeon/radeon_audio.h create mode 100644 sys/dev/drm/radeon/radeon_dp_auxch.c diff --git a/sys/conf/files b/sys/conf/files index 43c9d8d77d..0a13e90d44 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -2172,6 +2172,7 @@ dev/drm/radeon/radeon_acpi.c optional radeon drm dev/drm/radeon/radeon_agp.c optional radeon drm dev/drm/radeon/radeon_asic.c optional radeon drm dev/drm/radeon/radeon_atombios.c optional radeon drm +dev/drm/radeon/radeon_audio.c optional radeon drm dev/drm/radeon/radeon_benchmark.c optional radeon drm dev/drm/radeon/radeon_bios.c optional radeon drm dev/drm/radeon/radeon_clocks.c optional radeon drm @@ -2181,6 +2182,7 @@ dev/drm/radeon/radeon_cs.c optional radeon drm dev/drm/radeon/radeon_cursor.c optional radeon drm dev/drm/radeon/radeon_device.c optional radeon drm dev/drm/radeon/radeon_display.c optional radeon drm +dev/drm/radeon/radeon_dp_auxch.c optional radeon drm dev/drm/radeon/radeon_drv.c optional radeon drm dev/drm/radeon/radeon_encoders.c optional radeon drm dev/drm/radeon/radeon_fb.c optional radeon drm diff --git a/sys/dev/drm/radeon/Makefile b/sys/dev/drm/radeon/Makefile index 592368a601..4505b54ca3 100644 --- a/sys/dev/drm/radeon/Makefile +++ b/sys/dev/drm/radeon/Makefile @@ -22,6 +22,7 @@ SRCS += \ radeon_agp.c \ radeon_asic.c \ radeon_atombios.c \ + radeon_audio.c \ radeon_benchmark.c \ radeon_bios.c \ radeon_clocks.c \ @@ -31,6 +32,7 @@ SRCS += \ radeon_cursor.c \ radeon_device.c \ radeon_display.c \ + radeon_dp_auxch.c \ radeon_drv.c \ radeon_encoders.c \ radeon_fb.c \ diff --git a/sys/dev/drm/radeon/atom.c b/sys/dev/drm/radeon/atom.c index 73da113693..521e189026 100644 --- a/sys/dev/drm/radeon/atom.c +++ b/sys/dev/drm/radeon/atom.c @@ -65,9 +65,10 @@ typedef struct { int atom_debug = 0; static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params); -static uint32_t atom_arg_mask[8] = - { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000, -0xFF000000 }; +static uint32_t atom_arg_mask[8] = { + 0xFFFFFFFF, 0x0000FFFF, 0x00FFFF00, 0xFFFF0000, + 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 +}; static int atom_arg_shift[8] = { 0, 0, 8, 16, 0, 8, 16, 24 }; static int atom_dst_to_src[8][4] = { @@ -91,13 +92,23 @@ static void debug_print_spaces(int n) kprintf(" "); } -#define ATOM_DEBUG_PRINT(...) do if (atom_debug) { kprintf(__FILE__ __VA_ARGS__); } while (0) -#define ATOM_SDEBUG_PRINT(...) do if (atom_debug) { kprintf(__FILE__); debug_print_spaces(debug_depth); kprintf(__VA_ARGS__); } while (0) -#else -#define ATOM_DEBUG_PRINT(...) do { } while (0) -#define ATOM_SDEBUG_PRINT(...) do { } while (0) +#ifdef DEBUG +#undef DEBUG +#endif +#ifdef SDEBUG +#undef SDEBUG #endif +#define DEBUG(...) do if (atom_debug) { kprintf(__FILE__ __VA_ARGS__); } while (0) +#define SDEBUG(...) do if (atom_debug) { kprintf(__FILE__); debug_print_spaces(debug_depth); kprintf(__VA_ARGS__); } while (0) + +#else /* !ATOM_DEBUG */ + +#define DEBUG(...) do { } while (0) +#define SDEBUG(...) do { } while (0) + +#endif /* ATOM_DEBUG */ + static uint32_t atom_iio_execute(struct atom_context *ctx, int base, uint32_t index, uint32_t data) { @@ -189,7 +200,7 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, idx = U16(*ptr); (*ptr) += 2; if (print) - ATOM_DEBUG_PRINT("REG[0x%04X]", idx); + DEBUG("REG[0x%04X]", idx); idx += gctx->reg_block; switch (gctx->io_mode) { case ATOM_IO_MM: @@ -227,13 +238,13 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, * tables, noticed on a DEC Alpha. */ val = get_unaligned_le32((u32 *)&ctx->ps[idx]); if (print) - ATOM_DEBUG_PRINT("PS[0x%02X,0x%04X]", idx, val); + DEBUG("PS[0x%02X,0x%04X]", idx, val); break; case ATOM_ARG_WS: idx = U8(*ptr); (*ptr)++; if (print) - ATOM_DEBUG_PRINT("WS[0x%02X]", idx); + DEBUG("WS[0x%02X]", idx); switch (idx) { case ATOM_WS_QUOTIENT: val = gctx->divmul[0]; @@ -271,9 +282,9 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, (*ptr) += 2; if (print) { if (gctx->data_block) - ATOM_DEBUG_PRINT("ID[0x%04X+%04X]", idx, gctx->data_block); + DEBUG("ID[0x%04X+%04X]", idx, gctx->data_block); else - ATOM_DEBUG_PRINT("ID[0x%04X]", idx); + DEBUG("ID[0x%04X]", idx); } val = U32(idx + gctx->data_block); break; @@ -287,7 +298,7 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, } else val = gctx->scratch[(gctx->fb_base / 4) + idx]; if (print) - ATOM_DEBUG_PRINT("FB[0x%02X]", idx); + DEBUG("FB[0x%02X]", idx); break; case ATOM_ARG_IMM: switch (align) { @@ -295,7 +306,7 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, val = U32(*ptr); (*ptr) += 4; if (print) - ATOM_DEBUG_PRINT("IMM 0x%08X\n", val); + DEBUG("IMM 0x%08X\n", val); return val; case ATOM_SRC_WORD0: case ATOM_SRC_WORD8: @@ -303,7 +314,7 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, val = U16(*ptr); (*ptr) += 2; if (print) - ATOM_DEBUG_PRINT("IMM 0x%04X\n", val); + DEBUG("IMM 0x%04X\n", val); return val; case ATOM_SRC_BYTE0: case ATOM_SRC_BYTE8: @@ -312,7 +323,7 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, val = U8(*ptr); (*ptr)++; if (print) - ATOM_DEBUG_PRINT("IMM 0x%02X\n", val); + DEBUG("IMM 0x%02X\n", val); return val; } return 0; @@ -320,14 +331,14 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, idx = U8(*ptr); (*ptr)++; if (print) - ATOM_DEBUG_PRINT("PLL[0x%02X]", idx); + DEBUG("PLL[0x%02X]", idx); val = gctx->card->pll_read(gctx->card, idx); break; case ATOM_ARG_MC: idx = U8(*ptr); (*ptr)++; if (print) - ATOM_DEBUG_PRINT("MC[0x%02X]", idx); + DEBUG("MC[0x%02X]", idx); val = gctx->card->mc_read(gctx->card, idx); break; } @@ -338,28 +349,28 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, if (print) switch (align) { case ATOM_SRC_DWORD: - ATOM_DEBUG_PRINT(".[31:0] -> 0x%08X\n", val); + DEBUG(".[31:0] -> 0x%08X\n", val); break; case ATOM_SRC_WORD0: - ATOM_DEBUG_PRINT(".[15:0] -> 0x%04X\n", val); + DEBUG(".[15:0] -> 0x%04X\n", val); break; case ATOM_SRC_WORD8: - ATOM_DEBUG_PRINT(".[23:8] -> 0x%04X\n", val); + DEBUG(".[23:8] -> 0x%04X\n", val); break; case ATOM_SRC_WORD16: - ATOM_DEBUG_PRINT(".[31:16] -> 0x%04X\n", val); + DEBUG(".[31:16] -> 0x%04X\n", val); break; case ATOM_SRC_BYTE0: - ATOM_DEBUG_PRINT(".[7:0] -> 0x%02X\n", val); + DEBUG(".[7:0] -> 0x%02X\n", val); break; case ATOM_SRC_BYTE8: - ATOM_DEBUG_PRINT(".[15:8] -> 0x%02X\n", val); + DEBUG(".[15:8] -> 0x%02X\n", val); break; case ATOM_SRC_BYTE16: - ATOM_DEBUG_PRINT(".[23:16] -> 0x%02X\n", val); + DEBUG(".[23:16] -> 0x%02X\n", val); break; case ATOM_SRC_BYTE24: - ATOM_DEBUG_PRINT(".[31:24] -> 0x%02X\n", val); + DEBUG(".[31:24] -> 0x%02X\n", val); break; } return val; @@ -464,7 +475,7 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr, case ATOM_ARG_REG: idx = U16(*ptr); (*ptr) += 2; - ATOM_DEBUG_PRINT("REG[0x%04X]", idx); + DEBUG("REG[0x%04X]", idx); idx += gctx->reg_block; switch (gctx->io_mode) { case ATOM_IO_MM: @@ -500,13 +511,13 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr, case ATOM_ARG_PS: idx = U8(*ptr); (*ptr)++; - ATOM_DEBUG_PRINT("PS[0x%02X]", idx); + DEBUG("PS[0x%02X]", idx); ctx->ps[idx] = cpu_to_le32(val); break; case ATOM_ARG_WS: idx = U8(*ptr); (*ptr)++; - ATOM_DEBUG_PRINT("WS[0x%02X]", idx); + DEBUG("WS[0x%02X]", idx); switch (idx) { case ATOM_WS_QUOTIENT: gctx->divmul[0] = val; @@ -544,45 +555,45 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr, gctx->fb_base + (idx * 4), gctx->scratch_size_bytes); } else gctx->scratch[(gctx->fb_base / 4) + idx] = val; - ATOM_DEBUG_PRINT("FB[0x%02X]", idx); + DEBUG("FB[0x%02X]", idx); break; case ATOM_ARG_PLL: idx = U8(*ptr); (*ptr)++; - ATOM_DEBUG_PRINT("PLL[0x%02X]", idx); + DEBUG("PLL[0x%02X]", idx); gctx->card->pll_write(gctx->card, idx, val); break; case ATOM_ARG_MC: idx = U8(*ptr); (*ptr)++; - ATOM_DEBUG_PRINT("MC[0x%02X]", idx); + DEBUG("MC[0x%02X]", idx); gctx->card->mc_write(gctx->card, idx, val); return; } switch (align) { case ATOM_SRC_DWORD: - ATOM_DEBUG_PRINT(".[31:0] <- 0x%08X\n", old_val); + DEBUG(".[31:0] <- 0x%08X\n", old_val); break; case ATOM_SRC_WORD0: - ATOM_DEBUG_PRINT(".[15:0] <- 0x%04X\n", old_val); + DEBUG(".[15:0] <- 0x%04X\n", old_val); break; case ATOM_SRC_WORD8: - ATOM_DEBUG_PRINT(".[23:8] <- 0x%04X\n", old_val); + DEBUG(".[23:8] <- 0x%04X\n", old_val); break; case ATOM_SRC_WORD16: - ATOM_DEBUG_PRINT(".[31:16] <- 0x%04X\n", old_val); + DEBUG(".[31:16] <- 0x%04X\n", old_val); break; case ATOM_SRC_BYTE0: - ATOM_DEBUG_PRINT(".[7:0] <- 0x%02X\n", old_val); + DEBUG(".[7:0] <- 0x%02X\n", old_val); break; case ATOM_SRC_BYTE8: - ATOM_DEBUG_PRINT(".[15:8] <- 0x%02X\n", old_val); + DEBUG(".[15:8] <- 0x%02X\n", old_val); break; case ATOM_SRC_BYTE16: - ATOM_DEBUG_PRINT(".[23:16] <- 0x%02X\n", old_val); + DEBUG(".[23:16] <- 0x%02X\n", old_val); break; case ATOM_SRC_BYTE24: - ATOM_DEBUG_PRINT(".[31:24] <- 0x%02X\n", old_val); + DEBUG(".[31:24] <- 0x%02X\n", old_val); break; } } @@ -592,12 +603,12 @@ static void atom_op_add(atom_exec_context *ctx, int *ptr, int arg) uint8_t attr = U8((*ptr)++); uint32_t dst, src, saved; int dptr = *ptr; - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); - ATOM_SDEBUG_PRINT(" src: "); + SDEBUG(" src: "); src = atom_get_src(ctx, attr, ptr); dst += src; - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); atom_put_dst(ctx, arg, attr, &dptr, dst, saved); } @@ -606,12 +617,12 @@ static void atom_op_and(atom_exec_context *ctx, int *ptr, int arg) uint8_t attr = U8((*ptr)++); uint32_t dst, src, saved; int dptr = *ptr; - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); - ATOM_SDEBUG_PRINT(" src: "); + SDEBUG(" src: "); src = atom_get_src(ctx, attr, ptr); dst &= src; - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); atom_put_dst(ctx, arg, attr, &dptr, dst, saved); } @@ -626,9 +637,9 @@ static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg) int r = 0; if (idx < ATOM_TABLE_NAMES_CNT) - ATOM_SDEBUG_PRINT(" table: %d (%s)\n", idx, atom_table_names[idx]); + SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]); else - ATOM_SDEBUG_PRINT(" table: %d\n", idx); + SDEBUG(" table: %d\n", idx); if (U16(ctx->ctx->cmd_table + 4 + 2 * idx)) r = atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift); if (r) { @@ -644,7 +655,7 @@ static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg) attr &= 0x38; attr |= atom_def_dst[attr >> 3] << 6; atom_get_dst(ctx, arg, attr, ptr, &saved, 0); - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); atom_put_dst(ctx, arg, attr, &dptr, 0, saved); } @@ -652,20 +663,20 @@ static void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg) { uint8_t attr = U8((*ptr)++); uint32_t dst, src; - ATOM_SDEBUG_PRINT(" src1: "); + SDEBUG(" src1: "); dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); - ATOM_SDEBUG_PRINT(" src2: "); + SDEBUG(" src2: "); src = atom_get_src(ctx, attr, ptr); ctx->ctx->cs_equal = (dst == src); ctx->ctx->cs_above = (dst > src); - ATOM_SDEBUG_PRINT(" result: %s %s\n", ctx->ctx->cs_equal ? "EQ" : "NE", + SDEBUG(" result: %s %s\n", ctx->ctx->cs_equal ? "EQ" : "NE", ctx->ctx->cs_above ? "GT" : "LE"); } static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg) { unsigned count = U8((*ptr)++); - ATOM_SDEBUG_PRINT(" count: %d\n", count); + SDEBUG(" count: %d\n", count); if (arg == ATOM_UNIT_MICROSEC) udelay(count); else if (!drm_can_sleep()) @@ -678,9 +689,9 @@ static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg) { uint8_t attr = U8((*ptr)++); uint32_t dst, src; - ATOM_SDEBUG_PRINT(" src1: "); + SDEBUG(" src1: "); dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); - ATOM_SDEBUG_PRINT(" src2: "); + SDEBUG(" src2: "); src = atom_get_src(ctx, attr, ptr); if (src != 0) { ctx->ctx->divmul[0] = dst / src; @@ -726,8 +737,8 @@ static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg) break; } if (arg != ATOM_COND_ALWAYS) - ATOM_SDEBUG_PRINT(" taken: %s\n", execute ? "yes" : "no"); - ATOM_SDEBUG_PRINT(" target: 0x%04X\n", target); + SDEBUG(" taken: %s\n", execute ? "yes" : "no"); + SDEBUG(" target: 0x%04X\n", target); if (execute) { if (ctx->last_jump == (ctx->start + target)) { cjiffies = jiffies; @@ -754,15 +765,15 @@ static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg) uint8_t attr = U8((*ptr)++); uint32_t dst, mask, src, saved; int dptr = *ptr; - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); mask = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr); - ATOM_SDEBUG_PRINT(" mask: 0x%08x", mask); - ATOM_SDEBUG_PRINT(" src: "); + SDEBUG(" mask: 0x%08x", mask); + SDEBUG(" src: "); src = atom_get_src(ctx, attr, ptr); dst &= mask; dst |= src; - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); atom_put_dst(ctx, arg, attr, &dptr, dst, saved); } @@ -777,9 +788,9 @@ static void atom_op_move(atom_exec_context *ctx, int *ptr, int arg) atom_skip_dst(ctx, arg, attr, ptr); saved = 0xCDCDCDCD; } - ATOM_SDEBUG_PRINT(" src: "); + SDEBUG(" src: "); src = atom_get_src(ctx, attr, ptr); - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); atom_put_dst(ctx, arg, attr, &dptr, src, saved); } @@ -787,9 +798,9 @@ static void atom_op_mul(atom_exec_context *ctx, int *ptr, int arg) { uint8_t attr = U8((*ptr)++); uint32_t dst, src; - ATOM_SDEBUG_PRINT(" src1: "); + SDEBUG(" src1: "); dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); - ATOM_SDEBUG_PRINT(" src2: "); + SDEBUG(" src2: "); src = atom_get_src(ctx, attr, ptr); ctx->ctx->divmul[0] = dst * src; } @@ -804,19 +815,19 @@ static void atom_op_or(atom_exec_context *ctx, int *ptr, int arg) uint8_t attr = U8((*ptr)++); uint32_t dst, src, saved; int dptr = *ptr; - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); - ATOM_SDEBUG_PRINT(" src: "); + SDEBUG(" src: "); src = atom_get_src(ctx, attr, ptr); dst |= src; - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); atom_put_dst(ctx, arg, attr, &dptr, dst, saved); } static void atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg) { uint8_t val = U8((*ptr)++); - ATOM_SDEBUG_PRINT("POST card output: 0x%02X\n", val); + SDEBUG("POST card output: 0x%02X\n", val); } static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg) @@ -838,20 +849,20 @@ static void atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg) { int idx = U8(*ptr); (*ptr)++; - ATOM_SDEBUG_PRINT(" block: %d\n", idx); + SDEBUG(" block: %d\n", idx); if (!idx) ctx->ctx->data_block = 0; else if (idx == 255) ctx->ctx->data_block = ctx->start; else ctx->ctx->data_block = U16(ctx->ctx->data_table + 4 + 2 * idx); - ATOM_SDEBUG_PRINT(" base: 0x%04X\n", ctx->ctx->data_block); + SDEBUG(" base: 0x%04X\n", ctx->ctx->data_block); } static void atom_op_setfbbase(atom_exec_context *ctx, int *ptr, int arg) { uint8_t attr = U8((*ptr)++); - ATOM_SDEBUG_PRINT(" fb_base: "); + SDEBUG(" fb_base: "); ctx->ctx->fb_base = atom_get_src(ctx, attr, ptr); } @@ -862,9 +873,9 @@ static void atom_op_setport(atom_exec_context *ctx, int *ptr, int arg) case ATOM_PORT_ATI: port = U16(*ptr); if (port < ATOM_IO_NAMES_CNT) - ATOM_SDEBUG_PRINT(" port: %d (%s)\n", port, atom_io_names[port]); + SDEBUG(" port: %d (%s)\n", port, atom_io_names[port]); else - ATOM_SDEBUG_PRINT(" port: %d\n", port); + SDEBUG(" port: %d\n", port); if (!port) ctx->ctx->io_mode = ATOM_IO_MM; else @@ -886,7 +897,7 @@ static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg) { ctx->ctx->reg_block = U16(*ptr); (*ptr) += 2; - ATOM_SDEBUG_PRINT(" base: 0x%04X\n", ctx->ctx->reg_block); + SDEBUG(" base: 0x%04X\n", ctx->ctx->reg_block); } static void atom_op_shift_left(atom_exec_context *ctx, int *ptr, int arg) @@ -896,12 +907,12 @@ static void atom_op_shift_left(atom_exec_context *ctx, int *ptr, int arg) int dptr = *ptr; attr &= 0x38; attr |= atom_def_dst[attr >> 3] << 6; - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr); - ATOM_SDEBUG_PRINT(" shift: %d\n", shift); + SDEBUG(" shift: %d\n", shift); dst <<= shift; - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); atom_put_dst(ctx, arg, attr, &dptr, dst, saved); } @@ -912,12 +923,12 @@ static void atom_op_shift_right(atom_exec_context *ctx, int *ptr, int arg) int dptr = *ptr; attr &= 0x38; attr |= atom_def_dst[attr >> 3] << 6; - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr); - ATOM_SDEBUG_PRINT(" shift: %d\n", shift); + SDEBUG(" shift: %d\n", shift); dst >>= shift; - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); atom_put_dst(ctx, arg, attr, &dptr, dst, saved); } @@ -927,16 +938,16 @@ static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg) uint32_t saved, dst; int dptr = *ptr; uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3]; - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); /* op needs to full dst value */ dst = saved; shift = atom_get_src(ctx, attr, ptr); - ATOM_SDEBUG_PRINT(" shift: %d\n", shift); + SDEBUG(" shift: %d\n", shift); dst <<= shift; dst &= atom_arg_mask[dst_align]; dst >>= atom_arg_shift[dst_align]; - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); atom_put_dst(ctx, arg, attr, &dptr, dst, saved); } @@ -946,16 +957,16 @@ static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg) uint32_t saved, dst; int dptr = *ptr; uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3]; - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); /* op needs to full dst value */ dst = saved; shift = atom_get_src(ctx, attr, ptr); - ATOM_SDEBUG_PRINT(" shift: %d\n", shift); + SDEBUG(" shift: %d\n", shift); dst >>= shift; dst &= atom_arg_mask[dst_align]; dst >>= atom_arg_shift[dst_align]; - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); atom_put_dst(ctx, arg, attr, &dptr, dst, saved); } @@ -964,12 +975,12 @@ static void atom_op_sub(atom_exec_context *ctx, int *ptr, int arg) uint8_t attr = U8((*ptr)++); uint32_t dst, src, saved; int dptr = *ptr; - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); - ATOM_SDEBUG_PRINT(" src: "); + SDEBUG(" src: "); src = atom_get_src(ctx, attr, ptr); dst -= src; - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); atom_put_dst(ctx, arg, attr, &dptr, dst, saved); } @@ -977,18 +988,18 @@ static void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg) { uint8_t attr = U8((*ptr)++); uint32_t src, val, target; - ATOM_SDEBUG_PRINT(" switch: "); + SDEBUG(" switch: "); src = atom_get_src(ctx, attr, ptr); while (U16(*ptr) != ATOM_CASE_END) if (U8(*ptr) == ATOM_CASE_MAGIC) { (*ptr)++; - ATOM_SDEBUG_PRINT(" case: "); + SDEBUG(" case: "); val = atom_get_src(ctx, (attr & 0x38) | ATOM_ARG_IMM, ptr); target = U16(*ptr); if (val == src) { - ATOM_SDEBUG_PRINT(" target: %04X\n", target); + SDEBUG(" target: %04X\n", target); *ptr = ctx->start + target; return; } @@ -1004,12 +1015,12 @@ static void atom_op_test(atom_exec_context *ctx, int *ptr, int arg) { uint8_t attr = U8((*ptr)++); uint32_t dst, src; - ATOM_SDEBUG_PRINT(" src1: "); + SDEBUG(" src1: "); dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); - ATOM_SDEBUG_PRINT(" src2: "); + SDEBUG(" src2: "); src = atom_get_src(ctx, attr, ptr); ctx->ctx->cs_equal = ((dst & src) == 0); - ATOM_SDEBUG_PRINT(" result: %s\n", ctx->ctx->cs_equal ? "EQ" : "NE"); + SDEBUG(" result: %s\n", ctx->ctx->cs_equal ? "EQ" : "NE"); } static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg) @@ -1017,12 +1028,12 @@ static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg) uint8_t attr = U8((*ptr)++); uint32_t dst, src, saved; int dptr = *ptr; - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); - ATOM_SDEBUG_PRINT(" src: "); + SDEBUG(" src: "); src = atom_get_src(ctx, attr, ptr); dst ^= src; - ATOM_SDEBUG_PRINT(" dst: "); + SDEBUG(" dst: "); atom_put_dst(ctx, arg, attr, &dptr, dst, saved); } @@ -1175,7 +1186,7 @@ static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32 ps = CU8(base + ATOM_CT_PS_PTR) & ATOM_CT_PS_MASK; ptr = base + ATOM_CT_CODE_PTR; - ATOM_SDEBUG_PRINT(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps); + SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps); ectx.ctx = ctx; ectx.ps_shift = ps / 4; @@ -1192,9 +1203,9 @@ static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32 while (1) { op = CU8(ptr++); if (op < ATOM_OP_NAMES_CNT) - ATOM_SDEBUG_PRINT("%s @ 0x%04X\n", atom_op_names[op], ptr - 1); + SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1); else - ATOM_SDEBUG_PRINT("[%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); @@ -1212,7 +1223,7 @@ static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32 break; } debug_depth--; - ATOM_SDEBUG_PRINT("<<\n"); + SDEBUG("<<\n"); free: if (ws) @@ -1224,7 +1235,7 @@ int atom_execute_table_scratch_unlocked(struct atom_context *ctx, int index, uin { int r; - lockmgr(&ctx->mutex, LK_EXCLUSIVE); + mutex_lock(&ctx->mutex); /* reset data block */ ctx->data_block = 0; /* reset reg block */ @@ -1237,16 +1248,16 @@ int atom_execute_table_scratch_unlocked(struct atom_context *ctx, int index, uin ctx->divmul[0] = 0; ctx->divmul[1] = 0; r = atom_execute_table_locked(ctx, index, params); - lockmgr(&ctx->mutex, LK_RELEASE); + mutex_unlock(&ctx->mutex); return r; } int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) { int r; - lockmgr(&ctx->scratch_mutex, LK_EXCLUSIVE); + mutex_lock(&ctx->scratch_mutex); r = atom_execute_table_scratch_unlocked(ctx, index, params); - lockmgr(&ctx->scratch_mutex, LK_RELEASE); + mutex_unlock(&ctx->scratch_mutex); return r; } diff --git a/sys/dev/drm/radeon/atombios.h b/sys/dev/drm/radeon/atombios.h index 47d7123855..cd57f37ed2 100644 --- a/sys/dev/drm/radeon/atombios.h +++ b/sys/dev/drm/radeon/atombios.h @@ -7944,8 +7944,8 @@ typedef struct { typedef struct { AMD_ACPI_DESCRIPTION_HEADER SHeader; UCHAR TableUUID[16]; //0x24 - ULONG VBIOSImageOffset; //0x34. Offset to the first GOP_VBIOS_CONTENT block from the beginning of the stucture. - ULONG Lib1ImageOffset; //0x38. Offset to the first GOP_LIB1_CONTENT block from the beginning of the stucture. + ULONG VBIOSImageOffset; //0x34. Offset to the first GOP_VBIOS_CONTENT block from the beginning of the structure. + ULONG Lib1ImageOffset; //0x38. Offset to the first GOP_LIB1_CONTENT block from the beginning of the structure. ULONG Reserved[4]; //0x3C }UEFI_ACPI_VFCT; diff --git a/sys/dev/drm/radeon/atombios_crtc.c b/sys/dev/drm/radeon/atombios_crtc.c index 103c2ba6d1..d65baf526d 100644 --- a/sys/dev/drm/radeon/atombios_crtc.c +++ b/sys/dev/drm/radeon/atombios_crtc.c @@ -275,13 +275,15 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev)) atombios_enable_crtc_memreq(crtc, ATOM_ENABLE); atombios_blank_crtc(crtc, ATOM_DISABLE); - drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); + if (dev->num_crtcs > radeon_crtc->crtc_id) + drm_vblank_on(dev, radeon_crtc->crtc_id); radeon_crtc_load_lut(crtc); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); + if (dev->num_crtcs > radeon_crtc->crtc_id) + drm_vblank_off(dev, radeon_crtc->crtc_id); if (radeon_crtc->enabled) atombios_blank_crtc(crtc, ATOM_ENABLE); if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev)) @@ -331,8 +333,10 @@ atombios_set_crtc_dtd_timing(struct drm_crtc *crtc, misc |= ATOM_COMPOSITESYNC; if (mode->flags & DRM_MODE_FLAG_INTERLACE) misc |= ATOM_INTERLACE; + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + misc |= ATOM_DOUBLE_CLOCK_MODE; if (mode->flags & DRM_MODE_FLAG_DBLSCAN) - misc |= ATOM_DOUBLE_CLOCK_MODE; + misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2; args.susModeMiscInfo.usAccess = cpu_to_le16(misc); args.ucCRTC = radeon_crtc->crtc_id; @@ -375,8 +379,10 @@ static void atombios_crtc_set_timing(struct drm_crtc *crtc, misc |= ATOM_COMPOSITESYNC; if (mode->flags & DRM_MODE_FLAG_INTERLACE) misc |= ATOM_INTERLACE; + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + misc |= ATOM_DOUBLE_CLOCK_MODE; if (mode->flags & DRM_MODE_FLAG_DBLSCAN) - misc |= ATOM_DOUBLE_CLOCK_MODE; + misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2; args.susModeMiscInfo.usAccess = cpu_to_le16(misc); args.ucCRTC = radeon_crtc->crtc_id; @@ -583,7 +589,8 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev) || ASIC_IS_DCE8(rdev)) radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; /* use frac fb div on RS780/RS880 */ - if ((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880)) + if (((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880)) + && !radeon_crtc->ss_enabled) radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; if (ASIC_IS_DCE32(rdev) && mode->clock > 165000) radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; @@ -613,7 +620,9 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, if (radeon_crtc->ss.refdiv) { radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV; radeon_crtc->pll_reference_div = radeon_crtc->ss.refdiv; - if (ASIC_IS_AVIVO(rdev)) + if (ASIC_IS_AVIVO(rdev) && + rdev->family != CHIP_RS780 && + rdev->family != CHIP_RS880) radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; } } @@ -1360,6 +1369,11 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, break; } + /* Make sure surface address is updated at vertical blank rather than + * horizontal blank + */ + WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, 0); + WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, upper_32_bits(fb_location)); WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, @@ -1406,15 +1420,12 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, (x << 16) | y); viewport_w = crtc->mode.hdisplay; viewport_h = (crtc->mode.vdisplay + 1) & ~1; + if ((rdev->family >= CHIP_BONAIRE) && + (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)) + viewport_h *= 2; WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset, (viewport_w << 16) | viewport_h); - /* pageflip setup */ - /* make sure flip is at vb rather than hb */ - tmp = RREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset); - tmp &= ~EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN; - WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); - /* set pageflip to happen only at start of vblank interval (front porch) */ WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 3); @@ -1448,7 +1459,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, uint64_t fb_location; uint32_t fb_format, fb_pitch_pixels, tiling_flags; u32 fb_swap = R600_D1GRPH_SWAP_ENDIAN_NONE; - u32 tmp, viewport_w, viewport_h; + u32 viewport_w, viewport_h; int r; bool bypass_lut = false; @@ -1563,6 +1574,11 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, else WREG32(AVIVO_D2VGA_CONTROL, 0); + /* Make sure surface address is update at vertical blank rather than + * horizontal blank + */ + WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, 0); + if (rdev->family >= CHIP_RV770) { if (radeon_crtc->crtc_id) { WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); @@ -1609,12 +1625,6 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, (viewport_w << 16) | viewport_h); - /* pageflip setup */ - /* make sure flip is at vb rather than hb */ - tmp = RREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset); - tmp &= ~AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN; - WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); - /* set pageflip to happen only at start of vblank interval (front porch) */ WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 3); @@ -1724,6 +1734,7 @@ static u32 radeon_get_pll_use_mask(struct drm_crtc *crtc) static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; struct drm_crtc *test_crtc; struct radeon_crtc *test_radeon_crtc; @@ -1733,6 +1744,10 @@ static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc) test_radeon_crtc = to_radeon_crtc(test_crtc); if (test_radeon_crtc->encoder && ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) { + /* PPLL2 is exclusive to UNIPHYA on DCE61 */ + if (ASIC_IS_DCE61(rdev) && !ASIC_IS_DCE8(rdev) && + test_radeon_crtc->pll_id == ATOM_PPLL2) + continue; /* for DP use the same PLL for all */ if (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) return test_radeon_crtc->pll_id; @@ -1754,6 +1769,7 @@ static int radeon_get_shared_nondp_ppll(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; struct drm_crtc *test_crtc; struct radeon_crtc *test_radeon_crtc; u32 adjusted_clock, test_adjusted_clock; @@ -1769,6 +1785,10 @@ static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc) test_radeon_crtc = to_radeon_crtc(test_crtc); if (test_radeon_crtc->encoder && !ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_radeon_crtc->encoder))) { + /* PPLL2 is exclusive to UNIPHYA on DCE61 */ + if (ASIC_IS_DCE61(rdev) && !ASIC_IS_DCE8(rdev) && + test_radeon_crtc->pll_id == ATOM_PPLL2) + continue; /* check if we are already driving this connector with another crtc */ if (test_radeon_crtc->connector == radeon_crtc->connector) { /* if we are, return that pll */ @@ -1852,10 +1872,9 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) return pll; } /* otherwise, pick one of the plls */ - if ((rdev->family == CHIP_KAVERI) || - (rdev->family == CHIP_KABINI) || - (rdev->family == CHIP_MULLINS)) { - /* KB/KV/ML has PPLL1 and PPLL2 */ + if ((rdev->family == CHIP_KABINI) || + (rdev->family == CHIP_MULLINS)) { + /* KB/ML has PPLL1 and PPLL2 */ pll_in_use = radeon_get_pll_use_mask(crtc); if (!(pll_in_use & (1 << ATOM_PPLL2))) return ATOM_PPLL2; @@ -1864,7 +1883,7 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) DRM_ERROR("unable to allocate a PPLL\n"); return ATOM_PPLL_INVALID; } else { - /* CI has PPLL0, PPLL1, and PPLL2 */ + /* CI/KV has PPLL0, PPLL1, and PPLL2 */ pll_in_use = radeon_get_pll_use_mask(crtc); if (!(pll_in_use & (1 << ATOM_PPLL2))) return ATOM_PPLL2; @@ -2040,6 +2059,7 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, atombios_crtc_set_base(crtc, x, y, old_fb); atombios_overscan_setup(crtc, mode, adjusted_mode); atombios_scaler_setup(crtc); + radeon_cursor_reset(crtc); /* update the hw version fpr dpm */ radeon_crtc->hw_mode = *adjusted_mode; @@ -2067,6 +2087,12 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, radeon_crtc->connector = NULL; return false; } + if (radeon_crtc->encoder) { + struct radeon_encoder *radeon_encoder = + to_radeon_encoder(radeon_crtc->encoder); + + radeon_crtc->output_csc = radeon_encoder->output_csc; + } if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) return false; if (!atombios_crtc_prepare_pll(crtc, adjusted_mode)) @@ -2155,6 +2181,7 @@ static void atombios_crtc_disable(struct drm_crtc *crtc) case ATOM_PPLL0: /* disable the ppll */ if ((rdev->family == CHIP_ARUBA) || + (rdev->family == CHIP_KAVERI) || (rdev->family == CHIP_BONAIRE) || (rdev->family == CHIP_HAWAII)) atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, diff --git a/sys/dev/drm/radeon/atombios_dp.c b/sys/dev/drm/radeon/atombios_dp.c index eb026f8178..b4ecf2ece1 100644 --- a/sys/dev/drm/radeon/atombios_dp.c +++ b/sys/dev/drm/radeon/atombios_dp.c @@ -99,8 +99,8 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan, memset(&args, 0, sizeof(args)); - lockmgr(&chan->mutex, LK_EXCLUSIVE); - lockmgr(&rdev->mode_info.atom_context->scratch_mutex, LK_EXCLUSIVE); + mutex_lock(&chan->mutex); + mutex_lock(&rdev->mode_info.atom_context->scratch_mutex); base = (unsigned char *)(rdev->mode_info.atom_context->scratch + 1); @@ -148,8 +148,8 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan, r = recv_bytes; done: - lockmgr(&rdev->mode_info.atom_context->scratch_mutex, LK_RELEASE); - lockmgr(&chan->mutex, LK_RELEASE); + mutex_unlock(&rdev->mode_info.atom_context->scratch_mutex); + mutex_unlock(&chan->mutex); return r; } @@ -158,7 +158,7 @@ done: #define HEADER_SIZE (BARE_ADDRESS_SIZE + 1) static ssize_t -radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) +radeon_dp_aux_transfer_atom(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) { struct radeon_i2c_chan *chan = container_of(aux, struct radeon_i2c_chan, aux); @@ -171,13 +171,22 @@ radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) return -E2BIG; tx_buf[0] = msg->address & 0xff; - tx_buf[1] = msg->address >> 8; - tx_buf[2] = msg->request << 4; + tx_buf[1] = (msg->address >> 8) & 0xff; + tx_buf[2] = (msg->request << 4) | + ((msg->address >> 16) & 0xf); tx_buf[3] = msg->size ? (msg->size - 1) : 0; switch (msg->request & ~DP_AUX_I2C_MOT) { case DP_AUX_NATIVE_WRITE: case DP_AUX_I2C_WRITE: + case DP_AUX_I2C_WRITE_STATUS_UPDATE: + /* The atom implementation only supports writes with a max payload of + * 12 bytes since it uses 4 bits for the total count (header + payload) + * in the parameter space. The atom interface supports 16 byte + * payloads for reads. The hw itself supports up to 16 bytes of payload. + */ + if (WARN_ON_ONCE(msg->size > 12)) + return -E2BIG; /* tx_size needs to be 4 even for bare address packets since the atom * table needs the info in tx_buf[3]. */ @@ -219,98 +228,26 @@ radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) void radeon_dp_aux_init(struct radeon_connector *radeon_connector) { - struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; - - dig_connector->dp_i2c_bus->rec.hpd = radeon_connector->hpd.hpd; /* XXX check*/ - dig_connector->dp_i2c_bus->aux.dev = radeon_connector->base.kdev; - dig_connector->dp_i2c_bus->aux.transfer = radeon_dp_aux_transfer; -} - -int radeon_dp_i2c_aux_ch(device_t dev, int mode, u8 write_byte, u8 *read_byte) -{ - struct i2c_algo_dp_aux_data *algo_data = device_get_softc(dev); - struct radeon_i2c_chan *auxch = algo_data->priv; - u16 address = algo_data->address; - u8 msg[5]; - u8 reply[2]; - unsigned retry; - int msg_bytes; - int reply_bytes = 1; - int ret; - u8 ack; - - /* Set up the address */ - msg[0] = address; - msg[1] = address >> 8; - - /* Set up the command byte */ - if (mode & MODE_I2C_READ) { - msg[2] = DP_AUX_I2C_READ << 4; - msg_bytes = 4; - msg[3] = msg_bytes << 4; + struct drm_device *dev = radeon_connector->base.dev; + struct radeon_device *rdev = dev->dev_private; + int ret; + + radeon_connector->ddc_bus->rec.hpd = radeon_connector->hpd.hpd; + radeon_connector->ddc_bus->aux.dev = radeon_connector->base.kdev; + if (ASIC_IS_DCE5(rdev)) { + if (radeon_auxch) + radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer_native; + else + radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer_atom; } else { - msg[2] = DP_AUX_I2C_WRITE << 4; - msg_bytes = 5; - msg[3] = msg_bytes << 4; - msg[4] = write_byte; + radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer_atom; } - /* special handling for start/stop */ - if (mode & (MODE_I2C_START | MODE_I2C_STOP)) - msg[3] = 3 << 4; - - /* Set MOT bit for all but stop */ - if ((mode & MODE_I2C_STOP) == 0) - msg[2] |= DP_AUX_I2C_MOT << 4; - - for (retry = 0; retry < 7; retry++) { - ret = radeon_process_aux_ch(auxch, - msg, msg_bytes, reply, reply_bytes, 0, &ack); - if (ret == -EBUSY) - continue; - else if (ret < 0) { - DRM_DEBUG_KMS("aux_ch failed %d\n", ret); - return ret; - } - - switch ((ack >> 4) & DP_AUX_NATIVE_REPLY_MASK) { - case DP_AUX_NATIVE_REPLY_ACK: - /* I2C-over-AUX Reply field is only valid - * when paired with AUX ACK. - */ - break; - case DP_AUX_NATIVE_REPLY_NACK: - DRM_DEBUG_KMS("aux_ch native nack\n"); - return -EREMOTEIO; - case DP_AUX_NATIVE_REPLY_DEFER: - DRM_DEBUG_KMS("aux_ch native defer\n"); - usleep_range(500, 600); - continue; - default: - DRM_ERROR("aux_ch invalid native reply 0x%02x\n", ack); - return -EREMOTEIO; - } - - switch ((ack >> 4) & DP_AUX_I2C_REPLY_MASK) { - case DP_AUX_I2C_REPLY_ACK: - if (mode == MODE_I2C_READ) - *read_byte = reply[0]; - return (0); /* XXX: why 0 and not msg size? */ - case DP_AUX_I2C_REPLY_NACK: - DRM_DEBUG_KMS("aux_i2c nack\n"); - return -EREMOTEIO; - case DP_AUX_I2C_REPLY_DEFER: - DRM_DEBUG_KMS("aux_i2c defer\n"); - usleep_range(400, 500); - break; - default: - DRM_ERROR("aux_i2c invalid reply 0x%02x\n", ack); - return -EREMOTEIO; - } - } + ret = drm_dp_aux_register(&radeon_connector->ddc_bus->aux); + if (!ret) + radeon_connector->ddc_bus->has_aux = true; - DRM_DEBUG_KMS("aux i2c too many retries, giving up\n"); - return -EREMOTEIO; + WARN(ret, "drm_dp_aux_register() failed with error %d\n", ret); } /***** general DP utility functions *****/ @@ -318,7 +255,7 @@ int radeon_dp_i2c_aux_ch(device_t dev, int mode, u8 write_byte, u8 *read_byte) #define DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_LEVEL_3 #define DP_PRE_EMPHASIS_MAX DP_TRAIN_PRE_EMPH_LEVEL_3 -static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE], +static void dp_get_adjust_train(const u8 link_status[DP_LINK_STATUS_SIZE], int lane_count, u8 train_set[4]) { @@ -365,77 +302,43 @@ static int convert_bpc_to_bpp(int bpc) return bpc * 3; } -/* get the max pix clock supported by the link rate and lane num */ -static int dp_get_max_dp_pix_clock(int link_rate, - int lane_num, - int bpp) -{ - return (link_rate * lane_num * 8) / bpp; -} - /***** radeon specific DP functions *****/ -static int radeon_dp_get_max_link_rate(struct drm_connector *connector, - u8 dpcd[DP_DPCD_SIZE]) -{ - int max_link_rate; - - if (radeon_connector_is_dp12_capable(connector)) - max_link_rate = min(drm_dp_max_link_rate(dpcd), 540000); - else - max_link_rate = min(drm_dp_max_link_rate(dpcd), 270000); - - return max_link_rate; -} - -/* First get the min lane# when low rate is used according to pixel clock - * (prefer low rate), second check max lane# supported by DP panel, - * if the max lane# < low rate lane# then use max lane# instead. - */ -static int radeon_dp_get_dp_lane_number(struct drm_connector *connector, - u8 dpcd[DP_DPCD_SIZE], - int pix_clock) +int radeon_dp_get_dp_link_config(struct drm_connector *connector, + const u8 dpcd[DP_DPCD_SIZE], + unsigned pix_clock, + unsigned *dp_lanes, unsigned *dp_rate) { int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector)); - int max_link_rate = radeon_dp_get_max_link_rate(connector, dpcd); - int max_lane_num = drm_dp_max_lane_count(dpcd); - int lane_num; - int max_dp_pix_clock; - - for (lane_num = 1; lane_num < max_lane_num; lane_num <<= 1) { - max_dp_pix_clock = dp_get_max_dp_pix_clock(max_link_rate, lane_num, bpp); - if (pix_clock <= max_dp_pix_clock) - break; - } - - return lane_num; -} - -static int radeon_dp_get_dp_link_clock(struct drm_connector *connector, - u8 dpcd[DP_DPCD_SIZE], - int pix_clock) -{ - int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector)); - int lane_num, max_pix_clock; + static const unsigned link_rates[3] = { 162000, 270000, 540000 }; + unsigned max_link_rate = drm_dp_max_link_rate(dpcd); + unsigned max_lane_num = drm_dp_max_lane_count(dpcd); + unsigned lane_num, i, max_pix_clock; if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) == - ENCODER_OBJECT_ID_NUTMEG) - return 270000; - - lane_num = radeon_dp_get_dp_lane_number(connector, dpcd, pix_clock); - max_pix_clock = dp_get_max_dp_pix_clock(162000, lane_num, bpp); - if (pix_clock <= max_pix_clock) - return 162000; - max_pix_clock = dp_get_max_dp_pix_clock(270000, lane_num, bpp); - if (pix_clock <= max_pix_clock) - return 270000; - if (radeon_connector_is_dp12_capable(connector)) { - max_pix_clock = dp_get_max_dp_pix_clock(540000, lane_num, bpp); - if (pix_clock <= max_pix_clock) - return 540000; - } + ENCODER_OBJECT_ID_NUTMEG) { + for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) { + max_pix_clock = (lane_num * 270000 * 8) / bpp; + if (max_pix_clock >= pix_clock) { + *dp_lanes = lane_num; + *dp_rate = 270000; + return 0; + } + } + } else { + for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= max_link_rate; i++) { + for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) { + max_pix_clock = (lane_num * link_rates[i] * 8) / bpp; + if (max_pix_clock >= pix_clock) { + *dp_lanes = lane_num; + *dp_rate = link_rates[i]; + return 0; + } + } + } + } - return radeon_dp_get_max_link_rate(connector, dpcd); + return -EINVAL; } static u8 radeon_dp_encoder_service(struct radeon_device *rdev, @@ -458,12 +361,11 @@ static u8 radeon_dp_encoder_service(struct radeon_device *rdev, u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector) { - struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; struct drm_device *dev = radeon_connector->base.dev; struct radeon_device *rdev = dev->dev_private; return radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_GET_SINK_TYPE, 0, - dig_connector->dp_i2c_bus->rec.i2c_id, 0); + radeon_connector->ddc_bus->rec.i2c_id, 0); } static void radeon_dp_probe_oui(struct radeon_connector *radeon_connector) @@ -474,11 +376,11 @@ static void radeon_dp_probe_oui(struct radeon_connector *radeon_connector) if (!(dig_connector->dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT)) return; - if (drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_SINK_OUI, buf, 3) == 3) + if (drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_SINK_OUI, buf, 3) == 3) DRM_DEBUG_KMS("Sink OUI: %02hhx%02hhx%02hhx\n", buf[0], buf[1], buf[2]); - if (drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_BRANCH_OUI, buf, 3) == 3) + if (drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_BRANCH_OUI, buf, 3) == 3) DRM_DEBUG_KMS("Branch OUI: %02hhx%02hhx%02hhx\n", buf[0], buf[1], buf[2]); } @@ -487,21 +389,23 @@ bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector) { struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; u8 msg[DP_DPCD_SIZE]; - int ret; + int ret, i; char dpcd_hex_dump[DP_DPCD_SIZE * 3]; - ret = drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_DPCD_REV, msg, - DP_DPCD_SIZE); - if (ret > 0) { - memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE); - DRM_DEBUG_KMS("DPCD: %s\n", hexncpy(dig_connector->dpcd, - sizeof(dig_connector->dpcd), - dpcd_hex_dump, sizeof(dpcd_hex_dump), " ")); + for (i = 0; i < 7; i++) { + ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_DPCD_REV, msg, + DP_DPCD_SIZE); + if (ret == DP_DPCD_SIZE) { + memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE); + DRM_DEBUG_KMS("DPCD: %s\n", hexncpy(dig_connector->dpcd, + sizeof(dig_connector->dpcd), + dpcd_hex_dump, sizeof(dpcd_hex_dump), " ")); - radeon_dp_probe_oui(radeon_connector); + radeon_dp_probe_oui(radeon_connector); - return true; + return true; + } } dig_connector->dpcd[0] = 0; return false; @@ -528,7 +432,7 @@ int radeon_dp_get_panel_mode(struct drm_encoder *encoder, if (dp_bridge != ENCODER_OBJECT_ID_NONE) { /* DP bridge chips */ - if (drm_dp_dpcd_readb(&dig_connector->dp_i2c_bus->aux, + if (drm_dp_dpcd_readb(&radeon_connector->ddc_bus->aux, DP_EDP_CONFIGURATION_CAP, &tmp) == 1) { if (tmp & 1) panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; @@ -540,7 +444,7 @@ int radeon_dp_get_panel_mode(struct drm_encoder *encoder, } } else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { /* eDP */ - if (drm_dp_dpcd_readb(&dig_connector->dp_i2c_bus->aux, + if (drm_dp_dpcd_readb(&radeon_connector->ddc_bus->aux, DP_EDP_CONFIGURATION_CAP, &tmp) == 1) { if (tmp & 1) panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; @@ -555,6 +459,7 @@ void radeon_dp_set_link_config(struct drm_connector *connector, { struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct radeon_connector_atom_dig *dig_connector; + int ret; if (!radeon_connector->con_priv) return; @@ -562,10 +467,14 @@ void radeon_dp_set_link_config(struct drm_connector *connector, if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) { - dig_connector->dp_clock = - radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock); - dig_connector->dp_lane_count = - radeon_dp_get_dp_lane_number(connector, dig_connector->dpcd, mode->clock); + ret = radeon_dp_get_dp_link_config(connector, dig_connector->dpcd, + mode->clock, + &dig_connector->dp_lane_count, + &dig_connector->dp_clock); + if (ret) { + dig_connector->dp_clock = 0; + dig_connector->dp_lane_count = 0; + } } } @@ -574,7 +483,8 @@ int radeon_dp_mode_valid_helper(struct drm_connector *connector, { struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct radeon_connector_atom_dig *dig_connector; - int dp_clock; + unsigned dp_clock, dp_lanes; + int ret; if ((mode->clock > 340000) && (!radeon_connector_is_dp12_capable(connector))) @@ -584,8 +494,12 @@ int radeon_dp_mode_valid_helper(struct drm_connector *connector, return MODE_CLOCK_HIGH; dig_connector = radeon_connector->con_priv; - dp_clock = - radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock); + ret = radeon_dp_get_dp_link_config(connector, dig_connector->dpcd, + mode->clock, + &dp_lanes, + &dp_clock); + if (ret) + return MODE_CLOCK_HIGH; if ((dp_clock == 540000) && (!radeon_connector_is_dp12_capable(connector))) @@ -599,7 +513,8 @@ bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector) u8 link_status[DP_LINK_STATUS_SIZE]; struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; - if (drm_dp_dpcd_read_link_status(&dig->dp_i2c_bus->aux, link_status) <= 0) + if (drm_dp_dpcd_read_link_status(&radeon_connector->ddc_bus->aux, link_status) + <= 0) return false; if (drm_dp_channel_eq_ok(link_status, dig->dp_lane_count)) return false; @@ -619,7 +534,7 @@ void radeon_dp_set_rx_power_state(struct drm_connector *connector, /* power up/down the sink */ if (dig_connector->dpcd[0] >= 0x11) { - drm_dp_dpcd_writeb(&dig_connector->dp_i2c_bus->aux, + drm_dp_dpcd_writeb(&radeon_connector->ddc_bus->aux, DP_SET_POWER, power_state); usleep_range(1000, 2000); } @@ -706,10 +621,8 @@ static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info) drm_dp_dpcd_writeb(dp_info->aux, DP_DOWNSPREAD_CTRL, 0); - if ((dp_info->connector->connector_type == DRM_MODE_CONNECTOR_eDP) && - (dig->panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE)) { - drm_dp_dpcd_writeb(dp_info->aux, DP_EDP_CONFIGURATION_SET, 1); - } + if (dig->panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE) + drm_dp_dpcd_writeb(dp_info->aux, DP_EDP_CONFIGURATION_SET, 1); /* set the lane count on the sink */ tmp = dp_info->dp_lane_count; @@ -923,7 +836,7 @@ void radeon_dp_link_train(struct drm_encoder *encoder, else dp_info.enc_id |= ATOM_DP_CONFIG_LINK_A; - if (drm_dp_dpcd_readb(&dig_connector->dp_i2c_bus->aux, DP_MAX_LANE_COUNT, &tmp) + if (drm_dp_dpcd_readb(&radeon_connector->ddc_bus->aux, DP_MAX_LANE_COUNT, &tmp) == 1) { if (ASIC_IS_DCE5(rdev) && (tmp & DP_TPS3_SUPPORTED)) dp_info.tp3_supported = true; @@ -939,7 +852,7 @@ void radeon_dp_link_train(struct drm_encoder *encoder, dp_info.connector = connector; dp_info.dp_lane_count = dig_connector->dp_lane_count; dp_info.dp_clock = dig_connector->dp_clock; - dp_info.aux = &dig_connector->dp_i2c_bus->aux; + dp_info.aux = &radeon_connector->ddc_bus->aux; if (radeon_dp_link_train_init(&dp_info)) goto done; diff --git a/sys/dev/drm/radeon/atombios_encoders.c b/sys/dev/drm/radeon/atombios_encoders.c index ce2cae36d6..81adc91f84 100644 --- a/sys/dev/drm/radeon/atombios_encoders.c +++ b/sys/dev/drm/radeon/atombios_encoders.c @@ -27,6 +27,7 @@ #include #include #include "radeon.h" +#include "radeon_audio.h" #include "radeon_asic.h" #include "atom.h" @@ -117,6 +118,7 @@ atombios_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level) case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: if (dig->backlight_level == 0) atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0); else { @@ -235,6 +237,7 @@ void radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder, backlight_update_status(bd); DRM_INFO("radeon atom DIG backlight initialized\n"); + rdev->mode_info.bl_encoder = radeon_encoder; return; @@ -335,6 +338,7 @@ void radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder, dig->backlight_level = radeon_atom_get_backlight_level_from_reg(rdev); DRM_INFO("radeon atom DIG backlight initialized\n"); + rdev->mode_info.bl_encoder = radeon_encoder; SYSCTL_ADD_PROC(&drm_connector->dev->sysctl->ctx, &sysctl__hw_children, OID_AUTO, "backlight_max", @@ -375,6 +379,10 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2))) adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2; + /* vertical FP must be at least 1 */ + if (mode->crtc_vsync_start == mode->crtc_vdisplay) + adjusted_mode->crtc_vsync_start++; + /* get the native mode for scaling */ if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { radeon_panel_mode_fixup(encoder, adjusted_mode); @@ -731,6 +739,8 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) int atombios_get_encoder_mode(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 drm_connector *connector; struct radeon_connector *radeon_connector; @@ -795,6 +805,10 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) dig_connector = radeon_connector->con_priv; if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) { + if (radeon_audio != 0 && + drm_detect_monitor_audio(radeon_connector_edid(connector)) && + ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev)) + return ATOM_ENCODER_MODE_DP_AUDIO; return ATOM_ENCODER_MODE_DP; } else if (radeon_audio != 0) { if (radeon_connector->audio == RADEON_AUDIO_ENABLE) @@ -809,6 +823,10 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) } break; case DRM_MODE_CONNECTOR_eDP: + if (radeon_audio != 0 && + drm_detect_monitor_audio(radeon_connector_edid(connector)) && + ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev)) + return ATOM_ENCODER_MODE_DP_AUDIO; return ATOM_ENCODER_MODE_DP; case DRM_MODE_CONNECTOR_DVIA: case DRM_MODE_CONNECTOR_VGA: @@ -879,7 +897,7 @@ union dig_encoder_control { }; void -atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode) +atombios_dig_encoder_setup2(struct drm_encoder *encoder, int action, int panel_mode, int enc_override) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; @@ -939,8 +957,6 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo else args.v1.ucLaneNum = 4; - if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode) && (dp_clock == 270000)) - args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1; @@ -957,6 +973,10 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB; else args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; + + if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode) && (dp_clock == 270000)) + args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; + break; case 2: case 3: @@ -976,7 +996,10 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode) && (dp_clock == 270000)) args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ; - args.v3.acConfig.ucDigSel = dig->dig_encoder; + if (enc_override != -1) + args.v3.acConfig.ucDigSel = enc_override; + else + args.v3.acConfig.ucDigSel = dig->dig_encoder; args.v3.ucBitPerColor = radeon_atom_get_bpc(encoder); break; case 4: @@ -1004,7 +1027,11 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo else args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_1_62GHZ; } - args.v4.acConfig.ucDigSel = dig->dig_encoder; + + if (enc_override != -1) + args.v4.acConfig.ucDigSel = enc_override; + else + args.v4.acConfig.ucDigSel = dig->dig_encoder; args.v4.ucBitPerColor = radeon_atom_get_bpc(encoder); if (hpd_id == RADEON_HPD_NONE) args.v4.ucHPD_ID = 0; @@ -1025,6 +1052,12 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo } +void +atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode) +{ + atombios_dig_encoder_setup2(encoder, action, panel_mode, -1); +} + union dig_transmitter_control { DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1; DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2; @@ -1034,7 +1067,7 @@ union dig_transmitter_control { }; void -atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set) +atombios_dig_transmitter_setup2(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set, int fe) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; @@ -1384,7 +1417,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t args.v5.asConfig.ucHPDSel = 0; else args.v5.asConfig.ucHPDSel = hpd_id + 1; - args.v5.ucDigEncoderSel = 1 << dig_encoder; + args.v5.ucDigEncoderSel = (fe != -1) ? (1 << fe) : (1 << dig_encoder); args.v5.ucDPLaneSet = lane_set; break; default: @@ -1400,6 +1433,12 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } +void +atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set) +{ + atombios_dig_transmitter_setup2(encoder, action, lane_num, lane_set, -1); +} + bool atombios_set_edp_panel_power(struct drm_connector *connector, int action) { @@ -1653,8 +1692,14 @@ radeon_atom_encoder_dpms_avivo(struct drm_encoder *encoder, int mode) } else atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - args.ucAction = ATOM_LCD_BLON; - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + if (rdev->mode_info.bl_encoder) { + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + + atombios_set_backlight_level(radeon_encoder, dig->backlight_level); + } else { + args.ucAction = ATOM_LCD_BLON; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + } } break; case DRM_MODE_DPMS_STANDBY: @@ -1734,9 +1779,13 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode) if (ASIC_IS_DCE4(rdev)) atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0); } - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) - atombios_dig_transmitter_setup(encoder, - ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + if (rdev->mode_info.bl_encoder) + atombios_set_backlight_level(radeon_encoder, dig->backlight_level); + else + atombios_dig_transmitter_setup(encoder, + ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); + } if (ext_encoder) atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); break; @@ -1785,10 +1834,17 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + int encoder_mode = atombios_get_encoder_mode(encoder); DRM_DEBUG_KMS("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n", radeon_encoder->encoder_id, mode, radeon_encoder->devices, radeon_encoder->active_device); + + if ((radeon_audio != 0) && + ((encoder_mode == ATOM_ENCODER_MODE_HDMI) || + ENCODER_MODE_IS_DP(encoder_mode))) + radeon_audio_dpms(encoder, mode); + switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_TMDS1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: @@ -2050,7 +2106,14 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder, } } -static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) +void radeon_atom_release_dig_encoder(struct radeon_device *rdev, int enc_idx) +{ + if (enc_idx < 0) + return; + rdev->mode_info.active_encoders &= ~(1 << enc_idx); +} + +int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; @@ -2059,71 +2122,79 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) struct drm_encoder *test_encoder; struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; uint32_t dig_enc_in_use = 0; - + int enc_idx = -1; + + if (fe_idx >= 0) { + enc_idx = fe_idx; + goto assigned; + } if (ASIC_IS_DCE6(rdev)) { /* DCE6 */ switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: if (dig->linkb) - return 1; + enc_idx = 1; else - return 0; + enc_idx = 0; break; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: if (dig->linkb) - return 3; + enc_idx = 3; else - return 2; + enc_idx = 2; break; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: if (dig->linkb) - return 5; + enc_idx = 5; else - return 4; + enc_idx = 4; break; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: - return 6; + enc_idx = 6; break; } + goto assigned; } else if (ASIC_IS_DCE4(rdev)) { /* DCE4/5 */ if (ASIC_IS_DCE41(rdev) && !ASIC_IS_DCE61(rdev)) { /* ontario follows DCE4 */ if (rdev->family == CHIP_PALM) { if (dig->linkb) - return 1; + enc_idx = 1; else - return 0; + enc_idx = 0; } else /* llano follows DCE3.2 */ - return radeon_crtc->crtc_id; + enc_idx = radeon_crtc->crtc_id; } else { switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: if (dig->linkb) - return 1; + enc_idx = 1; else - return 0; + enc_idx = 0; break; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: if (dig->linkb) - return 3; + enc_idx = 3; else - return 2; + enc_idx = 2; break; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: if (dig->linkb) - return 5; + enc_idx = 5; else - return 4; + enc_idx = 4; break; } } + goto assigned; } /* on DCE32 and encoder can driver any block so just crtc id */ if (ASIC_IS_DCE32(rdev)) { - return radeon_crtc->crtc_id; + enc_idx = radeon_crtc->crtc_id; + goto assigned; } /* on DCE3 - LVTMA can only be driven by DIGB */ @@ -2151,6 +2222,17 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) if (!(dig_enc_in_use & 1)) return 0; return 1; + +assigned: + if (enc_idx == -1) { + DRM_ERROR("Got encoder index incorrect - returning 0\n"); + return 0; + } + if (rdev->mode_info.active_encoders & (1 << enc_idx)) { + DRM_ERROR("chosen encoder in use %d\n", enc_idx); + } + rdev->mode_info.active_encoders |= (1 << enc_idx); + return enc_idx; } /* This only needs to be called once at startup */ @@ -2190,6 +2272,8 @@ 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 drm_connector *connector = radeon_get_connector_for_encoder(encoder); + int encoder_mode; radeon_encoder->pixel_clock = adjusted_mode->clock; @@ -2238,12 +2322,11 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, atombios_apply_encoder_quirks(encoder, adjusted_mode); - if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { - if (rdev->asic->display.hdmi_enable) - radeon_hdmi_enable(rdev, encoder, true); - if (rdev->asic->display.hdmi_setmode) - radeon_hdmi_setmode(rdev, encoder, adjusted_mode); - } + encoder_mode = atombios_get_encoder_mode(encoder); + if (connector && (radeon_audio != 0) && + ((encoder_mode == ATOM_ENCODER_MODE_HDMI) || + ENCODER_MODE_IS_DP(encoder_mode))) + radeon_audio_mode_set(encoder, adjusted_mode); } static bool @@ -2407,7 +2490,9 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder) ENCODER_OBJECT_ID_NONE)) { struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; if (dig) { - dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder); + if (dig->dig_encoder >= 0) + radeon_atom_release_dig_encoder(rdev, dig->dig_encoder); + dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder, -1); if (radeon_encoder->active_device & ATOM_DEVICE_DFP_SUPPORT) { if (rdev->family >= CHIP_R600) dig->afmt = rdev->mode_info.afmt[dig->dig_encoder]; @@ -2508,15 +2593,19 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder) } disable_done: - if (radeon_encoder_is_digital(encoder)) { + if (radeon_encoder_is_digital(encoder)) { if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { if (rdev->asic->display.hdmi_enable) radeon_hdmi_enable(rdev, encoder, false); } - dig = radeon_encoder->enc_priv; - dig->dig_encoder = -1; - } - radeon_encoder->active_device = 0; + if (atombios_get_encoder_mode(encoder) != ATOM_ENCODER_MODE_DP_MST) { + dig = radeon_encoder->enc_priv; + radeon_atom_release_dig_encoder(rdev, dig->dig_encoder); + dig->dig_encoder = -1; + radeon_encoder->active_device = 0; + } + } else + radeon_encoder->active_device = 0; } /* these are handled by the primary encoders */ diff --git a/sys/dev/drm/radeon/atombios_i2c.c b/sys/dev/drm/radeon/atombios_i2c.c index 9a0e945879..dda824a165 100644 --- a/sys/dev/drm/radeon/atombios_i2c.c +++ b/sys/dev/drm/radeon/atombios_i2c.c @@ -40,6 +40,8 @@ #define ATOM_MAX_HW_I2C_WRITE 3 #define ATOM_MAX_HW_I2C_READ 255 +int radeon_atom_hw_i2c_xfer(device_t dev, struct iic_msg *msgs, u_int num); + static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan, u8 slave_addr, u8 flags, u8 *buf, u8 num) @@ -54,8 +56,8 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan, memset(&args, 0, sizeof(args)); - lockmgr(&chan->mutex, LK_EXCLUSIVE); - lockmgr(&rdev->mode_info.atom_context->scratch_mutex, LK_EXCLUSIVE); + mutex_lock(&chan->mutex); + mutex_lock(&rdev->mode_info.atom_context->scratch_mutex); base = (unsigned char *)rdev->mode_info.atom_context->scratch; @@ -103,14 +105,13 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan, radeon_atom_copy_swap(buf, base, num, false); done: - lockmgr(&rdev->mode_info.atom_context->scratch_mutex, LK_RELEASE); - lockmgr(&chan->mutex, LK_RELEASE); + mutex_unlock(&rdev->mode_info.atom_context->scratch_mutex); + mutex_unlock(&chan->mutex); return r; } -static int -radeon_atom_hw_i2c_xfer(device_t dev, struct iic_msg *msgs, u_int num) +int radeon_atom_hw_i2c_xfer(device_t dev, struct iic_msg *msgs, u_int num) { struct radeon_i2c_chan *i2c = device_get_softc(dev); struct iic_msg *p; diff --git a/sys/dev/drm/radeon/btc_dpm.c b/sys/dev/drm/radeon/btc_dpm.c index 9f4a80552b..81c280288a 100644 --- a/sys/dev/drm/radeon/btc_dpm.c +++ b/sys/dev/drm/radeon/btc_dpm.c @@ -30,6 +30,7 @@ #include "cypress_dpm.h" #include "btc_dpm.h" #include "atom.h" +#include #define MC_CG_ARB_FREQ_F0 0x0a #define MC_CG_ARB_FREQ_F1 0x0b @@ -1160,8 +1161,7 @@ u32 btc_valid_sclk[40] = 155000, 160000, 165000, 170000, 175000, 180000, 185000, 190000, 195000, 200000 }; -static const struct radeon_blacklist_clocks btc_blacklist_clocks[] = -{ +static const struct radeon_blacklist_clocks btc_blacklist_clocks[] = { { 10000, 30000, RADEON_SCLK_UP }, { 15000, 30000, RADEON_SCLK_UP }, { 20000, 30000, RADEON_SCLK_UP }, @@ -2748,13 +2748,54 @@ void btc_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, else /* current_index == 2 */ pl = &ps->high; seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); - if (rdev->family >= CHIP_CEDAR) { - seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u vddci: %u\n", - current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci); - } else { - seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u\n", - current_index, pl->sclk, pl->mclk, pl->vddc); - } + seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u vddci: %u\n", + current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci); + } +} + +u32 btc_dpm_get_current_sclk(struct radeon_device *rdev) +{ + struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); + struct radeon_ps *rps = &eg_pi->current_rps; + struct rv7xx_ps *ps = rv770_get_ps(rps); + struct rv7xx_pl *pl; + u32 current_index = + (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >> + CURRENT_PROFILE_INDEX_SHIFT; + + if (current_index > 2) { + return 0; + } else { + if (current_index == 0) + pl = &ps->low; + else if (current_index == 1) + pl = &ps->medium; + else /* current_index == 2 */ + pl = &ps->high; + return pl->sclk; + } +} + +u32 btc_dpm_get_current_mclk(struct radeon_device *rdev) +{ + struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); + struct radeon_ps *rps = &eg_pi->current_rps; + struct rv7xx_ps *ps = rv770_get_ps(rps); + struct rv7xx_pl *pl; + u32 current_index = + (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >> + CURRENT_PROFILE_INDEX_SHIFT; + + if (current_index > 2) { + return 0; + } else { + if (current_index == 0) + pl = &ps->low; + else if (current_index == 1) + pl = &ps->medium; + else /* current_index == 2 */ + pl = &ps->high; + return pl->mclk; } } diff --git a/sys/dev/drm/radeon/cayman_blit_shaders.c b/sys/dev/drm/radeon/cayman_blit_shaders.c index 98d009e154..9fec4d09f3 100644 --- a/sys/dev/drm/radeon/cayman_blit_shaders.c +++ b/sys/dev/drm/radeon/cayman_blit_shaders.c @@ -32,7 +32,7 @@ * evergreen 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 + * statically generated state tables. The register state and shaders * were hand generated to support blitting functionality. See the 3D * driver or documentation for descriptions of the registers and * shader instructions. diff --git a/sys/dev/drm/radeon/ci_dpm.c b/sys/dev/drm/radeon/ci_dpm.c index c7993355de..7d7b34e0aa 100644 --- a/sys/dev/drm/radeon/ci_dpm.c +++ b/sys/dev/drm/radeon/ci_dpm.c @@ -47,15 +47,15 @@ static const struct ci_pt_defaults defaults_hawaii_xt = { 1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0xB0000, - { 0x84, 0x0, 0x0, 0x7F, 0x0, 0x0, 0x5A, 0x60, 0x51, 0x8E, 0x79, 0x6B, 0x5F, 0x90, 0x79 }, - { 0x1EA, 0x1EA, 0x1EA, 0x224, 0x224, 0x224, 0x24F, 0x24F, 0x24F, 0x28E, 0x28E, 0x28E, 0x2BC, 0x2BC, 0x2BC } + { 0x2E, 0x00, 0x00, 0x88, 0x00, 0x00, 0x72, 0x60, 0x51, 0xA7, 0x79, 0x6B, 0x90, 0xBD, 0x79 }, + { 0x217, 0x217, 0x217, 0x242, 0x242, 0x242, 0x269, 0x269, 0x269, 0x2A1, 0x2A1, 0x2A1, 0x2C9, 0x2C9, 0x2C9 } }; static const struct ci_pt_defaults defaults_hawaii_pro = { 1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0x65062, - { 0x93, 0x0, 0x0, 0x97, 0x0, 0x0, 0x6B, 0x60, 0x51, 0x95, 0x79, 0x6B, 0x5F, 0x90, 0x79 }, - { 0x1EA, 0x1EA, 0x1EA, 0x224, 0x224, 0x224, 0x24F, 0x24F, 0x24F, 0x28E, 0x28E, 0x28E, 0x2BC, 0x2BC, 0x2BC } + { 0x2E, 0x00, 0x00, 0x88, 0x00, 0x00, 0x72, 0x60, 0x51, 0xA7, 0x79, 0x6B, 0x90, 0xBD, 0x79 }, + { 0x217, 0x217, 0x217, 0x242, 0x242, 0x242, 0x269, 0x269, 0x269, 0x2A1, 0x2A1, 0x2A1, 0x2C9, 0x2C9, 0x2C9 } }; static const struct ci_pt_defaults defaults_bonaire_xt = @@ -171,6 +171,12 @@ static int ci_set_overdrive_target_tdp(struct radeon_device *rdev, u32 target_tdp); static int ci_update_uvd_dpm(struct radeon_device *rdev, bool gate); +static PPSMC_Result ci_send_msg_to_smc_with_parameter(struct radeon_device *rdev, + PPSMC_Msg msg, u32 parameter); + +static void ci_thermal_start_smc_fan_control(struct radeon_device *rdev); +static void ci_fan_ctrl_set_default_mode(struct radeon_device *rdev); + static struct ci_power_info *ci_get_pi(struct radeon_device *rdev) { struct ci_power_info *pi = rdev->pm.dpm.priv; @@ -236,7 +242,10 @@ static void ci_initialize_powertune_defaults(struct radeon_device *rdev) if (pi->caps_power_containment) { pi->caps_cac = true; - pi->enable_bapm_feature = true; + if (rdev->family == CHIP_HAWAII) + pi->enable_bapm_feature = false; + else + pi->enable_bapm_feature = true; pi->enable_tdc_limit_feature = true; pi->enable_pkg_pwr_tracking_feature = true; } @@ -339,6 +348,21 @@ static int ci_populate_dw8(struct radeon_device *rdev) return 0; } +static int ci_populate_fuzzy_fan(struct radeon_device *rdev) +{ + struct ci_power_info *pi = ci_get_pi(rdev); + + if ((rdev->pm.dpm.fan.fan_output_sensitivity & (1 << 15)) || + (rdev->pm.dpm.fan.fan_output_sensitivity == 0)) + rdev->pm.dpm.fan.fan_output_sensitivity = + rdev->pm.dpm.fan.default_fan_output_sensitivity; + + pi->smc_powertune_table.FuzzyFan_PwmSetDelta = + cpu_to_be16(rdev->pm.dpm.fan.fan_output_sensitivity); + + return 0; +} + static int ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(struct radeon_device *rdev) { struct ci_power_info *pi = ci_get_pi(rdev); @@ -462,6 +486,9 @@ static int ci_populate_pm_base(struct radeon_device *rdev) if (ret) return ret; ret = ci_populate_dw8(rdev); + if (ret) + return ret; + ret = ci_populate_fuzzy_fan(rdev); if (ret) return ret; ret = ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(rdev); @@ -677,6 +704,25 @@ static int ci_enable_smc_cac(struct radeon_device *rdev, bool enable) return ret; } +static int ci_enable_thermal_based_sclk_dpm(struct radeon_device *rdev, + bool enable) +{ + struct ci_power_info *pi = ci_get_pi(rdev); + PPSMC_Result smc_result = PPSMC_Result_OK; + + if (pi->thermal_sclk_dpm_enabled) { + if (enable) + smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_ENABLE_THERMAL_DPM); + else + smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_DISABLE_THERMAL_DPM); + } + + if (smc_result == PPSMC_Result_OK) + return 0; + else + return -EINVAL; +} + static int ci_power_control_set_level(struct radeon_device *rdev) { struct ci_power_info *pi = ci_get_pi(rdev); @@ -687,13 +733,11 @@ static int ci_power_control_set_level(struct radeon_device *rdev) int ret = 0; bool adjust_polarity = false; /* ??? */ - if (pi->caps_power_containment && - (pi->power_containment_features & POWERCONTAINMENT_FEATURE_BAPM)) { + if (pi->caps_power_containment) { adjust_percent = adjust_polarity ? rdev->pm.dpm.tdp_adjustment : (-1 * rdev->pm.dpm.tdp_adjustment); target_tdp = ((100 + adjust_percent) * (s32)cac_tdp_table->configurable_tdp) / 100; - target_tdp *= 256; ret = ci_set_overdrive_target_tdp(rdev, (u32)target_tdp); } @@ -801,7 +845,7 @@ static void ci_apply_state_adjust_rules(struct radeon_device *rdev, } } -static int ci_set_thermal_temperature_range(struct radeon_device *rdev, +static int ci_thermal_set_temperature_range(struct radeon_device *rdev, int min_temp, int max_temp) { int low_temp = 0 * 1000; @@ -837,6 +881,380 @@ static int ci_set_thermal_temperature_range(struct radeon_device *rdev, return 0; } +static int ci_thermal_enable_alert(struct radeon_device *rdev, + bool enable) +{ + u32 thermal_int = RREG32_SMC(CG_THERMAL_INT); + PPSMC_Result result; + + if (enable) { + thermal_int &= ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW); + WREG32_SMC(CG_THERMAL_INT, thermal_int); + rdev->irq.dpm_thermal = false; + result = ci_send_msg_to_smc(rdev, PPSMC_MSG_Thermal_Cntl_Enable); + if (result != PPSMC_Result_OK) { + DRM_DEBUG_KMS("Could not enable thermal interrupts.\n"); + return -EINVAL; + } + } else { + thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW; + WREG32_SMC(CG_THERMAL_INT, thermal_int); + rdev->irq.dpm_thermal = true; + result = ci_send_msg_to_smc(rdev, PPSMC_MSG_Thermal_Cntl_Disable); + if (result != PPSMC_Result_OK) { + DRM_DEBUG_KMS("Could not disable thermal interrupts.\n"); + return -EINVAL; + } + } + + return 0; +} + +static void ci_fan_ctrl_set_static_mode(struct radeon_device *rdev, u32 mode) +{ + struct ci_power_info *pi = ci_get_pi(rdev); + u32 tmp; + + if (pi->fan_ctrl_is_in_default_mode) { + tmp = (RREG32_SMC(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK) >> FDO_PWM_MODE_SHIFT; + pi->fan_ctrl_default_mode = tmp; + tmp = (RREG32_SMC(CG_FDO_CTRL2) & TMIN_MASK) >> TMIN_SHIFT; + pi->t_min = tmp; + pi->fan_ctrl_is_in_default_mode = false; + } + + tmp = RREG32_SMC(CG_FDO_CTRL2) & ~TMIN_MASK; + tmp |= TMIN(0); + WREG32_SMC(CG_FDO_CTRL2, tmp); + + tmp = RREG32_SMC(CG_FDO_CTRL2) & ~FDO_PWM_MODE_MASK; + tmp |= FDO_PWM_MODE(mode); + WREG32_SMC(CG_FDO_CTRL2, tmp); +} + +static int ci_thermal_setup_fan_table(struct radeon_device *rdev) +{ + struct ci_power_info *pi = ci_get_pi(rdev); + SMU7_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE }; + u32 duty100; + u32 t_diff1, t_diff2, pwm_diff1, pwm_diff2; + u16 fdo_min, slope1, slope2; + u32 reference_clock, tmp; + int ret; + u64 tmp64; + + if (!pi->fan_table_start) { + rdev->pm.dpm.fan.ucode_fan_control = false; + return 0; + } + + duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT; + + if (duty100 == 0) { + rdev->pm.dpm.fan.ucode_fan_control = false; + return 0; + } + + tmp64 = (u64)rdev->pm.dpm.fan.pwm_min * duty100; + do_div(tmp64, 10000); + fdo_min = (u16)tmp64; + + t_diff1 = rdev->pm.dpm.fan.t_med - rdev->pm.dpm.fan.t_min; + t_diff2 = rdev->pm.dpm.fan.t_high - rdev->pm.dpm.fan.t_med; + + pwm_diff1 = rdev->pm.dpm.fan.pwm_med - rdev->pm.dpm.fan.pwm_min; + pwm_diff2 = rdev->pm.dpm.fan.pwm_high - rdev->pm.dpm.fan.pwm_med; + + slope1 = (u16)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100); + slope2 = (u16)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100); + + fan_table.TempMin = cpu_to_be16((50 + rdev->pm.dpm.fan.t_min) / 100); + fan_table.TempMed = cpu_to_be16((50 + rdev->pm.dpm.fan.t_med) / 100); + fan_table.TempMax = cpu_to_be16((50 + rdev->pm.dpm.fan.t_max) / 100); + + fan_table.Slope1 = cpu_to_be16(slope1); + fan_table.Slope2 = cpu_to_be16(slope2); + + fan_table.FdoMin = cpu_to_be16(fdo_min); + + fan_table.HystDown = cpu_to_be16(rdev->pm.dpm.fan.t_hyst); + + fan_table.HystUp = cpu_to_be16(1); + + fan_table.HystSlope = cpu_to_be16(1); + + fan_table.TempRespLim = cpu_to_be16(5); + + reference_clock = radeon_get_xclk(rdev); + + fan_table.RefreshPeriod = cpu_to_be32((rdev->pm.dpm.fan.cycle_delay * + reference_clock) / 1600); + + fan_table.FdoMax = cpu_to_be16((u16)duty100); + + tmp = (RREG32_SMC(CG_MULT_THERMAL_CTRL) & TEMP_SEL_MASK) >> TEMP_SEL_SHIFT; + fan_table.TempSrc = (uint8_t)tmp; + + ret = ci_copy_bytes_to_smc(rdev, + pi->fan_table_start, + (u8 *)(&fan_table), + sizeof(fan_table), + pi->sram_end); + + if (ret) { + DRM_ERROR("Failed to load fan table to the SMC."); + rdev->pm.dpm.fan.ucode_fan_control = false; + } + + return 0; +} + +static int ci_fan_ctrl_start_smc_fan_control(struct radeon_device *rdev) +{ + struct ci_power_info *pi = ci_get_pi(rdev); + PPSMC_Result ret; + + if (pi->caps_od_fuzzy_fan_control_support) { + ret = ci_send_msg_to_smc_with_parameter(rdev, + PPSMC_StartFanControl, + FAN_CONTROL_FUZZY); + if (ret != PPSMC_Result_OK) + return -EINVAL; + ret = ci_send_msg_to_smc_with_parameter(rdev, + PPSMC_MSG_SetFanPwmMax, + rdev->pm.dpm.fan.default_max_fan_pwm); + if (ret != PPSMC_Result_OK) + return -EINVAL; + } else { + ret = ci_send_msg_to_smc_with_parameter(rdev, + PPSMC_StartFanControl, + FAN_CONTROL_TABLE); + if (ret != PPSMC_Result_OK) + return -EINVAL; + } + + pi->fan_is_controlled_by_smc = true; + return 0; +} + +static int ci_fan_ctrl_stop_smc_fan_control(struct radeon_device *rdev) +{ + PPSMC_Result ret; + struct ci_power_info *pi = ci_get_pi(rdev); + + ret = ci_send_msg_to_smc(rdev, PPSMC_StopFanControl); + if (ret == PPSMC_Result_OK) { + pi->fan_is_controlled_by_smc = false; + return 0; + } else + return -EINVAL; +} + +int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev, + u32 *speed) +{ + u32 duty, duty100; + u64 tmp64; + + if (rdev->pm.no_fan) + return -ENOENT; + + duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT; + duty = (RREG32_SMC(CG_THERMAL_STATUS) & FDO_PWM_DUTY_MASK) >> FDO_PWM_DUTY_SHIFT; + + if (duty100 == 0) + return -EINVAL; + + tmp64 = (u64)duty * 100; + do_div(tmp64, duty100); + *speed = (u32)tmp64; + + if (*speed > 100) + *speed = 100; + + return 0; +} + +int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev, + u32 speed) +{ + u32 tmp; + u32 duty, duty100; + u64 tmp64; + struct ci_power_info *pi = ci_get_pi(rdev); + + if (rdev->pm.no_fan) + return -ENOENT; + + if (pi->fan_is_controlled_by_smc) + return -EINVAL; + + if (speed > 100) + return -EINVAL; + + duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT; + + if (duty100 == 0) + return -EINVAL; + + tmp64 = (u64)speed * duty100; + do_div(tmp64, 100); + duty = (u32)tmp64; + + tmp = RREG32_SMC(CG_FDO_CTRL0) & ~FDO_STATIC_DUTY_MASK; + tmp |= FDO_STATIC_DUTY(duty); + WREG32_SMC(CG_FDO_CTRL0, tmp); + + return 0; +} + +void ci_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode) +{ + if (mode) { + /* stop auto-manage */ + if (rdev->pm.dpm.fan.ucode_fan_control) + ci_fan_ctrl_stop_smc_fan_control(rdev); + ci_fan_ctrl_set_static_mode(rdev, mode); + } else { + /* restart auto-manage */ + if (rdev->pm.dpm.fan.ucode_fan_control) + ci_thermal_start_smc_fan_control(rdev); + else + ci_fan_ctrl_set_default_mode(rdev); + } +} + +u32 ci_fan_ctrl_get_mode(struct radeon_device *rdev) +{ + struct ci_power_info *pi = ci_get_pi(rdev); + u32 tmp; + + if (pi->fan_is_controlled_by_smc) + return 0; + + tmp = RREG32_SMC(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK; + return (tmp >> FDO_PWM_MODE_SHIFT); +} + +#if 0 +static int ci_fan_ctrl_get_fan_speed_rpm(struct radeon_device *rdev, + u32 *speed) +{ + u32 tach_period; + u32 xclk = radeon_get_xclk(rdev); + + if (rdev->pm.no_fan) + return -ENOENT; + + if (rdev->pm.fan_pulses_per_revolution == 0) + return -ENOENT; + + tach_period = (RREG32_SMC(CG_TACH_STATUS) & TACH_PERIOD_MASK) >> TACH_PERIOD_SHIFT; + if (tach_period == 0) + return -ENOENT; + + *speed = 60 * xclk * 10000 / tach_period; + + return 0; +} + +static int ci_fan_ctrl_set_fan_speed_rpm(struct radeon_device *rdev, + u32 speed) +{ + u32 tach_period, tmp; + u32 xclk = radeon_get_xclk(rdev); + + if (rdev->pm.no_fan) + return -ENOENT; + + if (rdev->pm.fan_pulses_per_revolution == 0) + return -ENOENT; + + if ((speed < rdev->pm.fan_min_rpm) || + (speed > rdev->pm.fan_max_rpm)) + return -EINVAL; + + if (rdev->pm.dpm.fan.ucode_fan_control) + ci_fan_ctrl_stop_smc_fan_control(rdev); + + tach_period = 60 * xclk * 10000 / (8 * speed); + tmp = RREG32_SMC(CG_TACH_CTRL) & ~TARGET_PERIOD_MASK; + tmp |= TARGET_PERIOD(tach_period); + WREG32_SMC(CG_TACH_CTRL, tmp); + + ci_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC_RPM); + + return 0; +} +#endif + +static void ci_fan_ctrl_set_default_mode(struct radeon_device *rdev) +{ + struct ci_power_info *pi = ci_get_pi(rdev); + u32 tmp; + + if (!pi->fan_ctrl_is_in_default_mode) { + tmp = RREG32_SMC(CG_FDO_CTRL2) & ~FDO_PWM_MODE_MASK; + tmp |= FDO_PWM_MODE(pi->fan_ctrl_default_mode); + WREG32_SMC(CG_FDO_CTRL2, tmp); + + tmp = RREG32_SMC(CG_FDO_CTRL2) & ~TMIN_MASK; + tmp |= TMIN(pi->t_min); + WREG32_SMC(CG_FDO_CTRL2, tmp); + pi->fan_ctrl_is_in_default_mode = true; + } +} + +static void ci_thermal_start_smc_fan_control(struct radeon_device *rdev) +{ + if (rdev->pm.dpm.fan.ucode_fan_control) { + ci_fan_ctrl_start_smc_fan_control(rdev); + ci_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC); + } +} + +static void ci_thermal_initialize(struct radeon_device *rdev) +{ + u32 tmp; + + if (rdev->pm.fan_pulses_per_revolution) { + tmp = RREG32_SMC(CG_TACH_CTRL) & ~EDGE_PER_REV_MASK; + tmp |= EDGE_PER_REV(rdev->pm.fan_pulses_per_revolution -1); + WREG32_SMC(CG_TACH_CTRL, tmp); + } + + tmp = RREG32_SMC(CG_FDO_CTRL2) & ~TACH_PWM_RESP_RATE_MASK; + tmp |= TACH_PWM_RESP_RATE(0x28); + WREG32_SMC(CG_FDO_CTRL2, tmp); +} + +static int ci_thermal_start_thermal_controller(struct radeon_device *rdev) +{ + int ret; + + ci_thermal_initialize(rdev); + ret = ci_thermal_set_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); + if (ret) + return ret; + ret = ci_thermal_enable_alert(rdev, true); + if (ret) + return ret; + if (rdev->pm.dpm.fan.ucode_fan_control) { + ret = ci_thermal_setup_fan_table(rdev); + if (ret) + return ret; + ci_thermal_start_smc_fan_control(rdev); + } + + return 0; +} + +static void ci_thermal_stop_thermal_controller(struct radeon_device *rdev) +{ + if (!rdev->pm.no_fan) + ci_fan_ctrl_set_default_mode(rdev); +} + #if 0 static int ci_read_smc_soft_register(struct radeon_device *rdev, u16 reg_offset, u32 *value) @@ -1240,7 +1658,7 @@ static int ci_dpm_force_state_sclk(struct radeon_device *rdev, u32 n) if (!pi->sclk_dpm_key_disabled) { PPSMC_Result smc_result = - ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_DPM_ForceState, n); + ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SCLKDPM_SetEnabledMask, 1 << n); if (smc_result != PPSMC_Result_OK) return -EINVAL; } @@ -1254,7 +1672,7 @@ static int ci_dpm_force_state_mclk(struct radeon_device *rdev, u32 n) if (!pi->mclk_dpm_key_disabled) { PPSMC_Result smc_result = - ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_MCLKDPM_ForceState, n); + ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_MCLKDPM_SetEnabledMask, 1 << n); if (smc_result != PPSMC_Result_OK) return -EINVAL; } @@ -2031,6 +2449,33 @@ static int ci_force_switch_to_arb_f0(struct radeon_device *rdev) return ni_copy_and_switch_arb_sets(rdev, tmp, MC_CG_ARB_FREQ_F0); } +static void ci_register_patching_mc_arb(struct radeon_device *rdev, + const u32 engine_clock, + const u32 memory_clock, + u32 *dram_timimg2) +{ + bool patch; + u32 tmp, tmp2; + + tmp = RREG32(MC_SEQ_MISC0); + patch = ((tmp & 0x0000f00) == 0x300) ? true : false; + + if (patch && + ((rdev->pdev->device == 0x67B0) || + (rdev->pdev->device == 0x67B1))) { + if ((memory_clock > 100000) && (memory_clock <= 125000)) { + tmp2 = (((0x31 * engine_clock) / 125000) - 1) & 0xff; + *dram_timimg2 &= ~0x00ff0000; + *dram_timimg2 |= tmp2 << 16; + } else if ((memory_clock > 125000) && (memory_clock <= 137500)) { + tmp2 = (((0x36 * engine_clock) / 137500) - 1) & 0xff; + *dram_timimg2 &= ~0x00ff0000; + *dram_timimg2 |= tmp2 << 16; + } + } +} + + static int ci_populate_memory_timing_parameters(struct radeon_device *rdev, u32 sclk, u32 mclk, @@ -2046,6 +2491,8 @@ static int ci_populate_memory_timing_parameters(struct radeon_device *rdev, dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2); burst_time = RREG32(MC_ARB_BURST_TIME) & STATE0_MASK; + ci_register_patching_mc_arb(rdev, sclk, mclk, &dram_timing2); + arb_regs->McArbDramTiming = cpu_to_be32(dram_timing); arb_regs->McArbDramTiming2 = cpu_to_be32(dram_timing2); arb_regs->McArbBurstTime = (u8)burst_time; @@ -2340,10 +2787,10 @@ static int ci_calculate_mclk_params(struct radeon_device *rdev, u32 tmp; u32 reference_clock = rdev->clock.mpll.reference_freq; - if (pi->mem_gddr5) - freq_nom = memory_clock * 4; + if (mpll_param.qdr == 1) + freq_nom = memory_clock * 4 * (1 << mpll_param.post_div); else - freq_nom = memory_clock * 2; + freq_nom = memory_clock * 2 * (1 << mpll_param.post_div); tmp = (freq_nom / reference_clock); tmp = tmp * tmp; @@ -2423,7 +2870,6 @@ static int ci_populate_single_memory_level(struct radeon_device *rdev, &memory_level->MinVddcPhases); memory_level->EnabledForThrottle = 1; - memory_level->EnabledForActivity = 1; memory_level->UpH = 0; memory_level->DownH = 100; memory_level->VoltageDownH = 0; @@ -2756,7 +3202,6 @@ static int ci_populate_single_graphic_level(struct radeon_device *rdev, graphic_level->CcPwrDynRm = 0; graphic_level->CcPwrDynRm1 = 0; - graphic_level->EnabledForActivity = 1; graphic_level->EnabledForThrottle = 1; graphic_level->UpH = 0; graphic_level->DownH = 0; @@ -2805,10 +3250,13 @@ static int ci_populate_all_graphic_levels(struct radeon_device *rdev) &pi->smc_state_table.GraphicsLevel[i]); if (ret) return ret; + if (i > 1) + pi->smc_state_table.GraphicsLevel[i].DeepSleepDivId = 0; if (i == (dpm_table->sclk_table.count - 1)) pi->smc_state_table.GraphicsLevel[i].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH; } + pi->smc_state_table.GraphicsLevel[0].EnabledForActivity = 1; pi->smc_state_table.GraphicsDpmLevelCount = (u8)dpm_table->sclk_table.count; pi->dpm_level_enable_mask.sclk_dpm_enable_mask = @@ -2852,6 +3300,16 @@ static int ci_populate_all_memory_levels(struct radeon_device *rdev) return ret; } + pi->smc_state_table.MemoryLevel[0].EnabledForActivity = 1; + + if ((dpm_table->mclk_table.count >= 2) && + ((rdev->pdev->device == 0x67B0) || (rdev->pdev->device == 0x67B1))) { + pi->smc_state_table.MemoryLevel[1].MinVddc = + pi->smc_state_table.MemoryLevel[0].MinVddc; + pi->smc_state_table.MemoryLevel[1].MinVddcPhases = + pi->smc_state_table.MemoryLevel[0].MinVddcPhases; + } + pi->smc_state_table.MemoryLevel[0].ActivityLevel = cpu_to_be16(0x1F); pi->smc_state_table.MemoryDpmLevelCount = (u8)dpm_table->mclk_table.count; @@ -2908,9 +3366,14 @@ static int ci_setup_default_pcie_tables(struct radeon_device *rdev) &pi->dpm_table.pcie_speed_table, SMU7_MAX_LEVELS_LINK); - ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 0, - pi->pcie_gen_powersaving.min, - pi->pcie_lane_powersaving.min); + if (rdev->family == CHIP_BONAIRE) + ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 0, + pi->pcie_gen_powersaving.min, + pi->pcie_lane_powersaving.max); + else + ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 0, + pi->pcie_gen_powersaving.min, + pi->pcie_lane_powersaving.min); ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 1, pi->pcie_gen_performance.min, pi->pcie_lane_performance.min); @@ -2977,19 +3440,21 @@ static int ci_setup_default_dpm_tables(struct radeon_device *rdev) allowed_sclk_vddc_table->entries[i].clk)) { pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count].value = allowed_sclk_vddc_table->entries[i].clk; - pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count].enabled = true; + pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count].enabled = + (i == 0) ? true : false; pi->dpm_table.sclk_table.count++; } } pi->dpm_table.mclk_table.count = 0; for (i = 0; i < allowed_mclk_table->count; i++) { - if ((i==0) || + if ((i == 0) || (pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count-1].value != allowed_mclk_table->entries[i].clk)) { pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count].value = allowed_mclk_table->entries[i].clk; - pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count].enabled = true; + pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count].enabled = + (i == 0) ? true : false; pi->dpm_table.mclk_table.count++; } } @@ -3155,7 +3620,7 @@ static int ci_init_smc_table(struct radeon_device *rdev) table->VddcVddciDelta = 4000; table->PhaseResponseTime = 0; table->MemoryThermThrottleEnable = 1; - table->PCIeBootLinkLevel = 0; + table->PCIeBootLinkLevel = pi->dpm_table.pcie_speed_table.count - 1; table->PCIeGenInterval = 1; if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2) table->SVI2Enable = 1; @@ -3309,6 +3774,8 @@ static int ci_upload_dpm_level_enable_mask(struct radeon_device *rdev) struct ci_power_info *pi = ci_get_pi(rdev); PPSMC_Result result; + ci_apply_disp_minimum_voltage_request(rdev); + if (!pi->sclk_dpm_key_disabled) { if (pi->dpm_level_enable_mask.sclk_dpm_enable_mask) { result = ci_send_msg_to_smc_with_parameter(rdev, @@ -3328,7 +3795,7 @@ static int ci_upload_dpm_level_enable_mask(struct radeon_device *rdev) return -EINVAL; } } - +#if 0 if (!pi->pcie_dpm_key_disabled) { if (pi->dpm_level_enable_mask.pcie_dpm_enable_mask) { result = ci_send_msg_to_smc_with_parameter(rdev, @@ -3338,9 +3805,7 @@ static int ci_upload_dpm_level_enable_mask(struct radeon_device *rdev) return -EINVAL; } } - - ci_apply_disp_minimum_voltage_request(rdev); - +#endif return 0; } @@ -3366,7 +3831,7 @@ static void ci_find_dpm_states_clocks_in_dpm_table(struct radeon_device *rdev, pi->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK; } else { /* XXX check display min clock requirements */ - if (0 != CISLAND_MINIMUM_ENGINE_CLOCK) + if (CISLAND_MINIMUM_ENGINE_CLOCK != CISLAND_MINIMUM_ENGINE_CLOCK) pi->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_SCLK; } @@ -3696,62 +4161,61 @@ int ci_dpm_force_performance_level(struct radeon_device *rdev, enum radeon_dpm_forced_level level) { struct ci_power_info *pi = ci_get_pi(rdev); - PPSMC_Result smc_result; u32 tmp, levels, i; int ret; if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { - if ((!pi->sclk_dpm_key_disabled) && - pi->dpm_level_enable_mask.sclk_dpm_enable_mask) { + if ((!pi->pcie_dpm_key_disabled) && + pi->dpm_level_enable_mask.pcie_dpm_enable_mask) { levels = 0; - tmp = pi->dpm_level_enable_mask.sclk_dpm_enable_mask; + tmp = pi->dpm_level_enable_mask.pcie_dpm_enable_mask; while (tmp >>= 1) levels++; if (levels) { - ret = ci_dpm_force_state_sclk(rdev, levels); + ret = ci_dpm_force_state_pcie(rdev, level); if (ret) return ret; for (i = 0; i < rdev->usec_timeout; i++) { - tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & - CURR_SCLK_INDEX_MASK) >> CURR_SCLK_INDEX_SHIFT; + tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX_1) & + CURR_PCIE_INDEX_MASK) >> CURR_PCIE_INDEX_SHIFT; if (tmp == levels) break; udelay(1); } } } - if ((!pi->mclk_dpm_key_disabled) && - pi->dpm_level_enable_mask.mclk_dpm_enable_mask) { + if ((!pi->sclk_dpm_key_disabled) && + pi->dpm_level_enable_mask.sclk_dpm_enable_mask) { levels = 0; - tmp = pi->dpm_level_enable_mask.mclk_dpm_enable_mask; + tmp = pi->dpm_level_enable_mask.sclk_dpm_enable_mask; while (tmp >>= 1) levels++; if (levels) { - ret = ci_dpm_force_state_mclk(rdev, levels); + ret = ci_dpm_force_state_sclk(rdev, levels); if (ret) return ret; for (i = 0; i < rdev->usec_timeout; i++) { tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & - CURR_MCLK_INDEX_MASK) >> CURR_MCLK_INDEX_SHIFT; + CURR_SCLK_INDEX_MASK) >> CURR_SCLK_INDEX_SHIFT; if (tmp == levels) break; udelay(1); } } } - if ((!pi->pcie_dpm_key_disabled) && - pi->dpm_level_enable_mask.pcie_dpm_enable_mask) { + if ((!pi->mclk_dpm_key_disabled) && + pi->dpm_level_enable_mask.mclk_dpm_enable_mask) { levels = 0; - tmp = pi->dpm_level_enable_mask.pcie_dpm_enable_mask; + tmp = pi->dpm_level_enable_mask.mclk_dpm_enable_mask; while (tmp >>= 1) levels++; if (levels) { - ret = ci_dpm_force_state_pcie(rdev, level); + ret = ci_dpm_force_state_mclk(rdev, levels); if (ret) return ret; for (i = 0; i < rdev->usec_timeout; i++) { - tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX_1) & - CURR_PCIE_INDEX_MASK) >> CURR_PCIE_INDEX_SHIFT; + tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & + CURR_MCLK_INDEX_MASK) >> CURR_MCLK_INDEX_SHIFT; if (tmp == levels) break; udelay(1); @@ -3805,21 +4269,17 @@ int ci_dpm_force_performance_level(struct radeon_device *rdev, } } } else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) { - if (!pi->sclk_dpm_key_disabled) { - smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel); - if (smc_result != PPSMC_Result_OK) - return -EINVAL; - } - if (!pi->mclk_dpm_key_disabled) { - smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_MCLKDPM_NoForcedLevel); - if (smc_result != PPSMC_Result_OK) - return -EINVAL; - } if (!pi->pcie_dpm_key_disabled) { - smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_PCIeDPM_UnForceLevel); + PPSMC_Result smc_result; + + smc_result = ci_send_msg_to_smc(rdev, + PPSMC_MSG_PCIeDPM_UnForceLevel); if (smc_result != PPSMC_Result_OK) return -EINVAL; } + ret = ci_upload_dpm_level_enable_mask(rdev); + if (ret) + return ret; } rdev->pm.dpm.forced_level = level; @@ -4025,6 +4485,96 @@ static int ci_copy_vbios_mc_reg_table(const struct atom_mc_reg_table *table, return 0; } +static int ci_register_patching_mc_seq(struct radeon_device *rdev, + struct ci_mc_reg_table *table) +{ + u8 i, k; + u32 tmp; + bool patch; + + tmp = RREG32(MC_SEQ_MISC0); + patch = ((tmp & 0x0000f00) == 0x300) ? true : false; + + if (patch && + ((rdev->pdev->device == 0x67B0) || + (rdev->pdev->device == 0x67B1))) { + for (i = 0; i < table->last; i++) { + if (table->last >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE) + return -EINVAL; + switch(table->mc_reg_address[i].s1 >> 2) { + case MC_SEQ_MISC1: + for (k = 0; k < table->num_entries; k++) { + if ((table->mc_reg_table_entry[k].mclk_max == 125000) || + (table->mc_reg_table_entry[k].mclk_max == 137500)) + table->mc_reg_table_entry[k].mc_data[i] = + (table->mc_reg_table_entry[k].mc_data[i] & 0xFFFFFFF8) | + 0x00000007; + } + break; + case MC_SEQ_WR_CTL_D0: + for (k = 0; k < table->num_entries; k++) { + if ((table->mc_reg_table_entry[k].mclk_max == 125000) || + (table->mc_reg_table_entry[k].mclk_max == 137500)) + table->mc_reg_table_entry[k].mc_data[i] = + (table->mc_reg_table_entry[k].mc_data[i] & 0xFFFF0F00) | + 0x0000D0DD; + } + break; + case MC_SEQ_WR_CTL_D1: + for (k = 0; k < table->num_entries; k++) { + if ((table->mc_reg_table_entry[k].mclk_max == 125000) || + (table->mc_reg_table_entry[k].mclk_max == 137500)) + table->mc_reg_table_entry[k].mc_data[i] = + (table->mc_reg_table_entry[k].mc_data[i] & 0xFFFF0F00) | + 0x0000D0DD; + } + break; + case MC_SEQ_WR_CTL_2: + for (k = 0; k < table->num_entries; k++) { + if ((table->mc_reg_table_entry[k].mclk_max == 125000) || + (table->mc_reg_table_entry[k].mclk_max == 137500)) + table->mc_reg_table_entry[k].mc_data[i] = 0; + } + break; + case MC_SEQ_CAS_TIMING: + for (k = 0; k < table->num_entries; k++) { + if (table->mc_reg_table_entry[k].mclk_max == 125000) + table->mc_reg_table_entry[k].mc_data[i] = + (table->mc_reg_table_entry[k].mc_data[i] & 0xFFE0FE0F) | + 0x000C0140; + else if (table->mc_reg_table_entry[k].mclk_max == 137500) + table->mc_reg_table_entry[k].mc_data[i] = + (table->mc_reg_table_entry[k].mc_data[i] & 0xFFE0FE0F) | + 0x000C0150; + } + break; + case MC_SEQ_MISC_TIMING: + for (k = 0; k < table->num_entries; k++) { + if (table->mc_reg_table_entry[k].mclk_max == 125000) + table->mc_reg_table_entry[k].mc_data[i] = + (table->mc_reg_table_entry[k].mc_data[i] & 0xFFFFFFE0) | + 0x00000030; + else if (table->mc_reg_table_entry[k].mclk_max == 137500) + table->mc_reg_table_entry[k].mc_data[i] = + (table->mc_reg_table_entry[k].mc_data[i] & 0xFFFFFFE0) | + 0x00000035; + } + break; + default: + break; + } + } + + WREG32(MC_SEQ_IO_DEBUG_INDEX, 3); + tmp = RREG32(MC_SEQ_IO_DEBUG_DATA); + tmp = (tmp & 0xFFF8FFFF) | (1 << 16); + WREG32(MC_SEQ_IO_DEBUG_INDEX, 3); + WREG32(MC_SEQ_IO_DEBUG_DATA, tmp); + } + + return 0; +} + static int ci_initialize_mc_reg_table(struct radeon_device *rdev) { struct ci_power_info *pi = ci_get_pi(rdev); @@ -4068,6 +4618,10 @@ static int ci_initialize_mc_reg_table(struct radeon_device *rdev) ci_set_s0_mc_reg_index(ci_table); + ret = ci_register_patching_mc_seq(rdev, ci_table); + if (ret) + goto init_mc_done; + ret = ci_set_mc_special_registers(rdev, ci_table); if (ret) goto init_mc_done; @@ -4672,34 +5226,43 @@ int ci_dpm_enable(struct radeon_device *rdev) ci_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); + ret = ci_enable_thermal_based_sclk_dpm(rdev, true); + if (ret) { + DRM_ERROR("ci_enable_thermal_based_sclk_dpm failed\n"); + return ret; + } + + ci_thermal_start_thermal_controller(rdev); + ci_update_current_ps(rdev, boot_ps); return 0; } -int ci_dpm_late_enable(struct radeon_device *rdev) +static int ci_set_temperature_range(struct radeon_device *rdev) { int ret; - if (rdev->irq.installed && - r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { -#if 0 - PPSMC_Result result; -#endif - ret = ci_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); - if (ret) { - DRM_ERROR("ci_set_thermal_temperature_range failed\n"); - return ret; - } - rdev->irq.dpm_thermal = true; - radeon_irq_set(rdev); -#if 0 - result = ci_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt); + ret = ci_thermal_enable_alert(rdev, false); + if (ret) + return ret; + ret = ci_thermal_set_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); + if (ret) + return ret; + ret = ci_thermal_enable_alert(rdev, true); + if (ret) + return ret; - if (result != PPSMC_Result_OK) - DRM_DEBUG_KMS("Could not enable thermal interrupts.\n"); -#endif - } + return ret; +} + +int ci_dpm_late_enable(struct radeon_device *rdev) +{ + int ret; + + ret = ci_set_temperature_range(rdev); + if (ret) + return ret; ci_dpm_powergate_uvd(rdev, true); @@ -4716,6 +5279,8 @@ void ci_dpm_disable(struct radeon_device *rdev) if (!ci_is_smc_running(rdev)) return; + ci_thermal_stop_thermal_controller(rdev); + if (pi->thermal_protection) ci_enable_thermal_protection(rdev, false); ci_enable_power_containment(rdev, false); @@ -4724,12 +5289,13 @@ void ci_dpm_disable(struct radeon_device *rdev) ci_enable_spread_spectrum(rdev, false); ci_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, false); ci_stop_dpm(rdev); - ci_enable_ds_master_switch(rdev, true); + ci_enable_ds_master_switch(rdev, false); ci_enable_ulv(rdev, false); ci_clear_vc(rdev); ci_reset_to_default(rdev); ci_dpm_stop_smc(rdev); ci_force_switch_to_arb_f0(rdev); + ci_enable_thermal_based_sclk_dpm(rdev, false); ci_update_current_ps(rdev, boot_ps); } @@ -5060,6 +5626,8 @@ void ci_dpm_fini(struct radeon_device *rdev) int ci_dpm_init(struct radeon_device *rdev) { int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info); + SMU7_Discrete_DpmTable *dpm_table; + struct radeon_gpio_rec gpio; u16 data_offset, size; u8 frev, crev; struct ci_power_info *pi; @@ -5129,6 +5697,7 @@ int ci_dpm_init(struct radeon_device *rdev) pi->sclk_dpm_key_disabled = 0; pi->mclk_dpm_key_disabled = 0; pi->pcie_dpm_key_disabled = 0; + pi->thermal_sclk_dpm_enabled = 0; /* mclk dpm is unstable on some R7 260X cards with the old mc ucode */ if ((rdev->pdev->device == 0x6658) && @@ -5193,6 +5762,55 @@ int ci_dpm_init(struct radeon_device *rdev) pi->uvd_enabled = false; + dpm_table = &pi->smc_state_table; + + gpio = radeon_atombios_lookup_gpio(rdev, VDDC_VRHOT_GPIO_PINID); + if (gpio.valid) { + dpm_table->VRHotGpio = gpio.shift; + rdev->pm.dpm.platform_caps |= ATOM_PP_PLATFORM_CAP_REGULATOR_HOT; + } else { + dpm_table->VRHotGpio = CISLANDS_UNUSED_GPIO_PIN; + rdev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_REGULATOR_HOT; + } + + gpio = radeon_atombios_lookup_gpio(rdev, PP_AC_DC_SWITCH_GPIO_PINID); + if (gpio.valid) { + dpm_table->AcDcGpio = gpio.shift; + rdev->pm.dpm.platform_caps |= ATOM_PP_PLATFORM_CAP_HARDWAREDC; + } else { + dpm_table->AcDcGpio = CISLANDS_UNUSED_GPIO_PIN; + rdev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_HARDWAREDC; + } + + gpio = radeon_atombios_lookup_gpio(rdev, VDDC_PCC_GPIO_PINID); + if (gpio.valid) { + u32 tmp = RREG32_SMC(CNB_PWRMGT_CNTL); + + switch (gpio.shift) { + case 0: + tmp &= ~GNB_SLOW_MODE_MASK; + tmp |= GNB_SLOW_MODE(1); + break; + case 1: + tmp &= ~GNB_SLOW_MODE_MASK; + tmp |= GNB_SLOW_MODE(2); + break; + case 2: + tmp |= GNB_SLOW; + break; + case 3: + tmp |= FORCE_NB_PS1; + break; + case 4: + tmp |= DPM_ENABLED; + break; + default: + DRM_DEBUG("Invalid PCC GPIO: %u!\n", gpio.shift); + break; + } + WREG32_SMC(CNB_PWRMGT_CNTL, tmp); + } + pi->voltage_control = CISLANDS_VOLTAGE_CONTROL_NONE; pi->vddci_control = CISLANDS_VOLTAGE_CONTROL_NONE; pi->mvdd_control = CISLANDS_VOLTAGE_CONTROL_NONE; @@ -5254,6 +5872,8 @@ int ci_dpm_init(struct radeon_device *rdev) rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc = rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; + pi->fan_ctrl_is_in_default_mode = true; + return 0; } @@ -5289,6 +5909,20 @@ void ci_dpm_print_power_state(struct radeon_device *rdev, r600_dpm_print_ps_status(rdev, rps); } +u32 ci_dpm_get_current_sclk(struct radeon_device *rdev) +{ + u32 sclk = ci_get_average_sclk_freq(rdev); + + return sclk; +} + +u32 ci_dpm_get_current_mclk(struct radeon_device *rdev) +{ + u32 mclk = ci_get_average_mclk_freq(rdev); + + return mclk; +} + u32 ci_dpm_get_sclk(struct radeon_device *rdev, bool low) { struct ci_power_info *pi = ci_get_pi(rdev); diff --git a/sys/dev/drm/radeon/ci_dpm.h b/sys/dev/drm/radeon/ci_dpm.h index 596d17e09a..8b4fd926b9 100644 --- a/sys/dev/drm/radeon/ci_dpm.h +++ b/sys/dev/drm/radeon/ci_dpm.h @@ -33,6 +33,8 @@ #define CISLANDS_MAX_HARDWARE_POWERLEVELS 2 +#define CISLANDS_UNUSED_GPIO_PIN 0x7F + struct ci_pl { u32 mclk; u32 sclk; @@ -237,6 +239,7 @@ struct ci_power_info { u32 sclk_dpm_key_disabled; u32 mclk_dpm_key_disabled; u32 pcie_dpm_key_disabled; + u32 thermal_sclk_dpm_enabled; struct ci_pcie_perf_range pcie_gen_performance; struct ci_pcie_perf_range pcie_lane_performance; struct ci_pcie_perf_range pcie_gen_powersaving; @@ -264,6 +267,7 @@ struct ci_power_info { bool caps_automatic_dc_transition; bool caps_sclk_throttle_low_notification; bool caps_dynamic_ac_timing; + bool caps_od_fuzzy_fan_control_support; /* flags */ bool thermal_protection; bool pcie_performance_request; @@ -285,6 +289,11 @@ struct ci_power_info { struct ci_ps current_ps; struct radeon_ps requested_rps; struct ci_ps requested_ps; + /* fan control */ + bool fan_ctrl_is_in_default_mode; + bool fan_is_controlled_by_smc; + u32 t_min; + u32 fan_ctrl_default_mode; }; #define CISLANDS_VOLTAGE_CONTROL_NONE 0x0 diff --git a/sys/dev/drm/radeon/ci_smc.c b/sys/dev/drm/radeon/ci_smc.c index 42efe8bc91..82c140365c 100644 --- a/sys/dev/drm/radeon/ci_smc.c +++ b/sys/dev/drm/radeon/ci_smc.c @@ -48,6 +48,7 @@ int ci_copy_bytes_to_smc(struct radeon_device *rdev, u32 smc_start_address, const u8 *src, u32 byte_count, u32 limit) { + unsigned long flags; u32 data, original_data; u32 addr; u32 extra_shift; @@ -60,7 +61,7 @@ int ci_copy_bytes_to_smc(struct radeon_device *rdev, addr = smc_start_address; - spin_lock(&rdev->smc_idx_lock); + spin_lock_irqsave(&rdev->smc_idx_lock, flags); while (byte_count >= 4) { /* SMC address space is BE */ data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]; @@ -105,7 +106,7 @@ int ci_copy_bytes_to_smc(struct radeon_device *rdev, } done: - spin_unlock(&rdev->smc_idx_lock); + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); return ret; } @@ -128,7 +129,7 @@ void ci_reset_smc(struct radeon_device *rdev) int ci_program_jump_on_start(struct radeon_device *rdev) { - static u8 data[] = { 0xE0, 0x00, 0x80, 0x40 }; + static const u8 data[] = { 0xE0, 0x00, 0x80, 0x40 }; return ci_copy_bytes_to_smc(rdev, 0x0, data, 4, sizeof(data)+1); } @@ -205,6 +206,7 @@ PPSMC_Result ci_wait_for_smc_inactive(struct radeon_device *rdev) int ci_load_smc_ucode(struct radeon_device *rdev, u32 limit) { + unsigned long flags; u32 ucode_start_address; u32 ucode_size; const u8 *src; @@ -244,7 +246,7 @@ int ci_load_smc_ucode(struct radeon_device *rdev, u32 limit) if (ucode_size & 3) return -EINVAL; - spin_lock(&rdev->smc_idx_lock); + spin_lock_irqsave(&rdev->smc_idx_lock, flags); WREG32(SMC_IND_INDEX_0, ucode_start_address); WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0); while (ucode_size >= 4) { @@ -257,7 +259,7 @@ int ci_load_smc_ucode(struct radeon_device *rdev, u32 limit) ucode_size -= 4; } WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0); - spin_unlock(&rdev->smc_idx_lock); + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); return 0; } @@ -265,13 +267,14 @@ int ci_load_smc_ucode(struct radeon_device *rdev, u32 limit) int ci_read_smc_sram_dword(struct radeon_device *rdev, u32 smc_address, u32 *value, u32 limit) { + unsigned long flags; int ret; - spin_lock(&rdev->smc_idx_lock); + spin_lock_irqsave(&rdev->smc_idx_lock, flags); ret = ci_set_smc_sram_address(rdev, smc_address, limit); if (ret == 0) *value = RREG32(SMC_IND_DATA_0); - spin_unlock(&rdev->smc_idx_lock); + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); return ret; } @@ -279,13 +282,14 @@ int ci_read_smc_sram_dword(struct radeon_device *rdev, int ci_write_smc_sram_dword(struct radeon_device *rdev, u32 smc_address, u32 value, u32 limit) { + unsigned long flags; int ret; - spin_lock(&rdev->smc_idx_lock); + spin_lock_irqsave(&rdev->smc_idx_lock, flags); ret = ci_set_smc_sram_address(rdev, smc_address, limit); if (ret == 0) WREG32(SMC_IND_DATA_0, value); - spin_unlock(&rdev->smc_idx_lock); + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); return ret; } diff --git a/sys/dev/drm/radeon/cik.c b/sys/dev/drm/radeon/cik.c index 73df88e692..d129ed0ad1 100644 --- a/sys/dev/drm/radeon/cik.c +++ b/sys/dev/drm/radeon/cik.c @@ -26,6 +26,7 @@ #include #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include "cikd.h" #include "atom.h" #include "cik_blit_shaders.h" @@ -123,6 +124,63 @@ static void cik_fini_pg(struct radeon_device *rdev); static void cik_fini_cg(struct radeon_device *rdev); static void cik_enable_gui_idle_interrupt(struct radeon_device *rdev, bool enable); +/** + * cik_get_allowed_info_register - fetch the register for the info ioctl + * + * @rdev: radeon_device pointer + * @reg: register offset in bytes + * @val: register value + * + * Returns 0 for success or -EINVAL for an invalid register + * + */ +int cik_get_allowed_info_register(struct radeon_device *rdev, + u32 reg, u32 *val) +{ + switch (reg) { + case GRBM_STATUS: + case GRBM_STATUS2: + case GRBM_STATUS_SE0: + case GRBM_STATUS_SE1: + case GRBM_STATUS_SE2: + case GRBM_STATUS_SE3: + case SRBM_STATUS: + case SRBM_STATUS2: + case (SDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET): + case (SDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET): + case UVD_STATUS: + /* TODO VCE */ + *val = RREG32(reg); + return 0; + default: + return -EINVAL; + } +} + +/* + * Indirect registers accessor + */ +u32 cik_didt_rreg(struct radeon_device *rdev, u32 reg) +{ + unsigned long flags; + u32 r; + + spin_lock_irqsave(&rdev->didt_idx_lock, flags); + WREG32(CIK_DIDT_IND_INDEX, (reg)); + r = RREG32(CIK_DIDT_IND_DATA); + spin_unlock_irqrestore(&rdev->didt_idx_lock, flags); + return r; +} + +void cik_didt_wreg(struct radeon_device *rdev, u32 reg, u32 v) +{ + unsigned long flags; + + spin_lock_irqsave(&rdev->didt_idx_lock, flags); + WREG32(CIK_DIDT_IND_INDEX, (reg)); + WREG32(CIK_DIDT_IND_DATA, (v)); + spin_unlock_irqrestore(&rdev->didt_idx_lock, flags); +} /* get temperature in millidegrees */ int ci_get_temp(struct radeon_device *rdev) @@ -166,24 +224,27 @@ int kv_get_temp(struct radeon_device *rdev) */ u32 cik_pciep_rreg(struct radeon_device *rdev, u32 reg) { + unsigned long flags; u32 r; - spin_lock(&rdev->pciep_idx_lock); + spin_lock_irqsave(&rdev->pciep_idx_lock, flags); WREG32(PCIE_INDEX, reg); (void)RREG32(PCIE_INDEX); r = RREG32(PCIE_DATA); - spin_unlock(&rdev->pciep_idx_lock); + spin_unlock_irqrestore(&rdev->pciep_idx_lock, flags); return r; } void cik_pciep_wreg(struct radeon_device *rdev, u32 reg, u32 v) { - spin_lock(&rdev->pciep_idx_lock); + unsigned long flags; + + spin_lock_irqsave(&rdev->pciep_idx_lock, flags); WREG32(PCIE_INDEX, reg); (void)RREG32(PCIE_INDEX); WREG32(PCIE_DATA, v); (void)RREG32(PCIE_DATA); - spin_unlock(&rdev->pciep_idx_lock); + spin_unlock_irqrestore(&rdev->pciep_idx_lock, flags); } static const u32 spectre_rlc_save_restore_register_list[] = @@ -1545,6 +1606,8 @@ static const u32 godavari_golden_registers[] = static void cik_init_golden_registers(struct radeon_device *rdev) { + /* Some of the registers might be dependent on GRBM_GFX_INDEX */ + mutex_lock(&rdev->grbm_idx_mutex); switch (rdev->family) { case CHIP_BONAIRE: radeon_program_register_sequence(rdev, @@ -1619,6 +1682,7 @@ static void cik_init_golden_registers(struct radeon_device *rdev) default: break; } + mutex_unlock(&rdev->grbm_idx_mutex); } /** @@ -1788,7 +1852,7 @@ int ci_mc_load_microcode(struct radeon_device *rdev) { const __be32 *fw_data = NULL; const __le32 *new_fw_data = NULL; - u32 running, blackout = 0; + u32 running, blackout = 0, tmp; u32 *io_mc_regs = NULL; const __le32 *new_io_mc_regs = NULL; int i, regs_size, ucode_size; @@ -1848,6 +1912,15 @@ int ci_mc_load_microcode(struct radeon_device *rdev) WREG32(MC_SEQ_IO_DEBUG_DATA, io_mc_regs[(i << 1) + 1]); } } + + tmp = RREG32(MC_SEQ_MISC0); + if ((rdev->pdev->device == 0x6649) && ((tmp & 0xff00) == 0x5600)) { + WREG32(MC_SEQ_IO_DEBUG_INDEX, 5); + WREG32(MC_SEQ_IO_DEBUG_DATA, 0x00000023); + WREG32(MC_SEQ_IO_DEBUG_INDEX, 9); + WREG32(MC_SEQ_IO_DEBUG_DATA, 0x000001f0); + } + /* load the MC ucode */ for (i = 0; i < ucode_size; i++) { if (rdev->new_fw) @@ -2283,9 +2356,13 @@ static void cik_fini_microcode(struct radeon_device *rdev) */ static void cik_tiling_mode_table_init(struct radeon_device *rdev) { - const u32 num_tile_mode_states = 32; - const u32 num_secondary_tile_mode_states = 16; - u32 reg_offset, gb_tile_moden, split_equal_to_row_size; + u32 *tile = rdev->config.cik.tile_mode_array; + u32 *macrotile = rdev->config.cik.macrotile_mode_array; + const u32 num_tile_mode_states = + ARRAY_SIZE(rdev->config.cik.tile_mode_array); + const u32 num_secondary_tile_mode_states = + ARRAY_SIZE(rdev->config.cik.macrotile_mode_array); + u32 reg_offset, split_equal_to_row_size; u32 num_pipe_configs; u32 num_rbs = rdev->config.cik.max_backends_per_se * rdev->config.cik.max_shader_engines; @@ -2307,1032 +2384,669 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev) if (num_pipe_configs > 8) num_pipe_configs = 16; - if (num_pipe_configs == 16) { - for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) { - switch (reg_offset) { - case 0: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B)); - break; - case 1: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B)); - break; - case 2: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); - break; - case 3: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B)); - break; - case 4: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | - TILE_SPLIT(split_equal_to_row_size)); - break; - case 5: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); - break; - case 6: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); - break; - case 7: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | - TILE_SPLIT(split_equal_to_row_size)); - break; - case 8: - gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | - PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16)); - break; - case 9: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING)); - break; - case 10: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 11: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P16_32x32_8x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 12: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 13: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | - MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING)); - break; - case 14: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 16: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P16_32x32_8x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 17: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 27: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | - MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING)); - break; - case 28: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 29: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P16_32x32_8x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 30: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - default: - gb_tile_moden = 0; - break; - } - rdev->config.cik.tile_mode_array[reg_offset] = gb_tile_moden; - WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden); - } - for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) { - switch (reg_offset) { - case 0: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 1: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 2: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 3: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 4: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | - NUM_BANKS(ADDR_SURF_8_BANK)); - break; - case 5: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | - NUM_BANKS(ADDR_SURF_4_BANK)); - break; - case 6: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | - NUM_BANKS(ADDR_SURF_2_BANK)); - break; - case 8: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 9: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 10: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 11: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | - NUM_BANKS(ADDR_SURF_8_BANK)); - break; - case 12: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | - NUM_BANKS(ADDR_SURF_4_BANK)); - break; - case 13: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | - NUM_BANKS(ADDR_SURF_2_BANK)); - break; - case 14: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | - NUM_BANKS(ADDR_SURF_2_BANK)); - break; - default: - gb_tile_moden = 0; - break; - } - rdev->config.cik.macrotile_mode_array[reg_offset] = gb_tile_moden; - WREG32(GB_MACROTILE_MODE0 + (reg_offset * 4), gb_tile_moden); - } - } else if (num_pipe_configs == 8) { - for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) { - switch (reg_offset) { - case 0: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B)); - break; - case 1: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B)); - break; - case 2: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); - break; - case 3: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B)); - break; - case 4: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | - TILE_SPLIT(split_equal_to_row_size)); - break; - case 5: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); - break; - case 6: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); - break; - case 7: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | - TILE_SPLIT(split_equal_to_row_size)); - break; - case 8: - gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16)); - break; - case 9: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING)); - break; - case 10: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 11: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 12: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 13: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | - MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING)); - break; - case 14: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 16: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 17: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 27: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | - MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING)); - break; - case 28: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 29: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 30: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - default: - gb_tile_moden = 0; - break; - } - rdev->config.cik.tile_mode_array[reg_offset] = gb_tile_moden; - WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden); - } - for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) { - switch (reg_offset) { - case 0: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 1: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 2: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 3: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 4: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | - NUM_BANKS(ADDR_SURF_8_BANK)); - break; - case 5: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | - NUM_BANKS(ADDR_SURF_4_BANK)); - break; - case 6: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | - NUM_BANKS(ADDR_SURF_2_BANK)); - break; - case 8: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 9: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 10: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 11: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 12: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | - NUM_BANKS(ADDR_SURF_8_BANK)); - break; - case 13: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | - NUM_BANKS(ADDR_SURF_4_BANK)); - break; - case 14: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | - NUM_BANKS(ADDR_SURF_2_BANK)); - break; - default: - gb_tile_moden = 0; - break; - } - rdev->config.cik.macrotile_mode_array[reg_offset] = gb_tile_moden; - WREG32(GB_MACROTILE_MODE0 + (reg_offset * 4), gb_tile_moden); - } - } else if (num_pipe_configs == 4) { + for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) + tile[reg_offset] = 0; + for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) + macrotile[reg_offset] = 0; + + switch(num_pipe_configs) { + case 16: + tile[0] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B)); + tile[1] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B)); + tile[2] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); + tile[3] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B)); + tile[4] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + TILE_SPLIT(split_equal_to_row_size)); + tile[5] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); + tile[6] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); + tile[7] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + TILE_SPLIT(split_equal_to_row_size)); + tile[8] = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16)); + tile[9] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING)); + tile[10] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[11] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_8x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[12] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[13] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING)); + tile[14] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[16] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_8x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[17] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[27] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING)); + tile[28] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[29] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_8x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[30] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + + macrotile[0] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[1] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[2] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[3] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[4] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_8_BANK)); + macrotile[5] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_4_BANK)); + macrotile[6] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); + macrotile[8] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[9] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[10] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[11] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_8_BANK)); + macrotile[12] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_4_BANK)); + macrotile[13] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); + macrotile[14] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); + + for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) + WREG32(GB_TILE_MODE0 + (reg_offset * 4), tile[reg_offset]); + for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) + WREG32(GB_MACROTILE_MODE0 + (reg_offset * 4), macrotile[reg_offset]); + break; + + case 8: + tile[0] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B)); + tile[1] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B)); + tile[2] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); + tile[3] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B)); + tile[4] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | + TILE_SPLIT(split_equal_to_row_size)); + tile[5] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); + tile[6] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); + tile[7] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | + TILE_SPLIT(split_equal_to_row_size)); + tile[8] = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16)); + tile[9] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING)); + tile[10] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[11] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[12] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[13] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING)); + tile[14] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[16] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[17] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[27] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING)); + tile[28] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[29] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[30] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + + macrotile[0] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[1] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[2] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[3] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[4] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_8_BANK)); + macrotile[5] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_4_BANK)); + macrotile[6] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); + macrotile[8] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[9] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[10] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[11] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[12] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_8_BANK)); + macrotile[13] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_4_BANK)); + macrotile[14] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); + + for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) + WREG32(GB_TILE_MODE0 + (reg_offset * 4), tile[reg_offset]); + for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) + WREG32(GB_MACROTILE_MODE0 + (reg_offset * 4), macrotile[reg_offset]); + break; + + case 4: if (num_rbs == 4) { - for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) { - switch (reg_offset) { - case 0: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_16x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B)); - break; - case 1: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_16x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B)); - break; - case 2: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_16x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); - break; - case 3: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_16x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B)); - break; - case 4: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_16x16) | - TILE_SPLIT(split_equal_to_row_size)); - break; - case 5: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - PIPE_CONFIG(ADDR_SURF_P4_16x16) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); - break; - case 6: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_16x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); - break; - case 7: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_16x16) | - TILE_SPLIT(split_equal_to_row_size)); - break; - case 8: - gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | - PIPE_CONFIG(ADDR_SURF_P4_16x16)); - break; - case 9: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - PIPE_CONFIG(ADDR_SURF_P4_16x16) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING)); - break; - case 10: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_16x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 11: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 12: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_16x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 13: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - PIPE_CONFIG(ADDR_SURF_P4_16x16) | - MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING)); - break; - case 14: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_16x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 16: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 17: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_16x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 27: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - PIPE_CONFIG(ADDR_SURF_P4_16x16) | - MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING)); - break; - case 28: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_16x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 29: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 30: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_16x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - default: - gb_tile_moden = 0; - break; - } - rdev->config.cik.tile_mode_array[reg_offset] = gb_tile_moden; - WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden); - } + tile[0] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B)); + tile[1] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B)); + tile[2] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); + tile[3] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B)); + tile[4] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + TILE_SPLIT(split_equal_to_row_size)); + tile[5] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); + tile[6] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); + tile[7] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + TILE_SPLIT(split_equal_to_row_size)); + tile[8] = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | + PIPE_CONFIG(ADDR_SURF_P4_16x16)); + tile[9] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING)); + tile[10] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[11] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[12] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[13] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING)); + tile[14] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[16] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[17] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[27] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING)); + tile[28] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[29] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[30] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + } else if (num_rbs < 4) { - for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) { - switch (reg_offset) { - case 0: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B)); - break; - case 1: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B)); - break; - case 2: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); - break; - case 3: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B)); - break; - case 4: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(split_equal_to_row_size)); - break; - case 5: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); - break; - case 6: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); - break; - case 7: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(split_equal_to_row_size)); - break; - case 8: - gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | - PIPE_CONFIG(ADDR_SURF_P4_8x16)); - break; - case 9: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING)); - break; - case 10: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 11: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 12: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 13: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING)); - break; - case 14: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 16: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 17: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 27: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING)); - break; - case 28: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 29: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 30: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - default: - gb_tile_moden = 0; - break; - } - rdev->config.cik.tile_mode_array[reg_offset] = gb_tile_moden; - WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden); - } - } - for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) { - switch (reg_offset) { - case 0: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 1: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 2: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 3: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 4: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 5: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | - NUM_BANKS(ADDR_SURF_8_BANK)); - break; - case 6: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | - NUM_BANKS(ADDR_SURF_4_BANK)); - break; - case 8: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 9: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 10: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 11: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 12: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 13: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | - NUM_BANKS(ADDR_SURF_8_BANK)); - break; - case 14: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | - NUM_BANKS(ADDR_SURF_4_BANK)); - break; - default: - gb_tile_moden = 0; - break; - } - rdev->config.cik.macrotile_mode_array[reg_offset] = gb_tile_moden; - WREG32(GB_MACROTILE_MODE0 + (reg_offset * 4), gb_tile_moden); - } - } else if (num_pipe_configs == 2) { - for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) { - switch (reg_offset) { - case 0: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P2) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B)); - break; - case 1: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P2) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B)); - break; - case 2: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P2) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); - break; - case 3: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P2) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B)); - break; - case 4: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P2) | - TILE_SPLIT(split_equal_to_row_size)); - break; - case 5: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - PIPE_CONFIG(ADDR_SURF_P2) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); - break; - case 6: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P2) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); - break; - case 7: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P2) | - TILE_SPLIT(split_equal_to_row_size)); - break; - case 8: - gb_tile_moden = ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | - PIPE_CONFIG(ADDR_SURF_P2); - break; - case 9: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P2)); - break; - case 10: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P2) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 11: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P2) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 12: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P2) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 13: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - PIPE_CONFIG(ADDR_SURF_P2) | - MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING)); - break; - case 14: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P2) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 16: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P2) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 17: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P2) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 27: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P2)); - break; - case 28: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P2) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 29: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P2) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - case 30: - gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P2) | - SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); - break; - default: - gb_tile_moden = 0; - break; - } - rdev->config.cik.tile_mode_array[reg_offset] = gb_tile_moden; - WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden); + tile[0] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B)); + tile[1] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B)); + tile[2] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); + tile[3] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B)); + tile[4] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(split_equal_to_row_size)); + tile[5] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); + tile[6] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); + tile[7] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(split_equal_to_row_size)); + tile[8] = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | + PIPE_CONFIG(ADDR_SURF_P4_8x16)); + tile[9] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING)); + tile[10] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[11] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[12] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[13] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING)); + tile[14] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[16] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[17] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[27] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING)); + tile[28] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[29] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[30] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); } - for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) { - switch (reg_offset) { - case 0: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 1: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 2: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 3: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 4: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 5: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 6: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | - NUM_BANKS(ADDR_SURF_8_BANK)); - break; - case 8: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 9: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 10: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 11: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 12: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 13: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | - NUM_BANKS(ADDR_SURF_16_BANK)); - break; - case 14: - gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | - NUM_BANKS(ADDR_SURF_8_BANK)); - break; - default: - gb_tile_moden = 0; - break; - } - rdev->config.cik.macrotile_mode_array[reg_offset] = gb_tile_moden; - WREG32(GB_MACROTILE_MODE0 + (reg_offset * 4), gb_tile_moden); - } - } else + + macrotile[0] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[1] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[2] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[3] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[4] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[5] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_8_BANK)); + macrotile[6] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_4_BANK)); + macrotile[8] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[9] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[10] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[11] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[12] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[13] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_8_BANK)); + macrotile[14] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_4_BANK)); + + for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) + WREG32(GB_TILE_MODE0 + (reg_offset * 4), tile[reg_offset]); + for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) + WREG32(GB_MACROTILE_MODE0 + (reg_offset * 4), macrotile[reg_offset]); + break; + + case 2: + tile[0] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P2) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B)); + tile[1] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P2) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B)); + tile[2] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P2) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); + tile[3] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P2) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B)); + tile[4] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P2) | + TILE_SPLIT(split_equal_to_row_size)); + tile[5] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); + tile[6] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P2) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B)); + tile[7] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P2) | + TILE_SPLIT(split_equal_to_row_size)); + tile[8] = ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | + PIPE_CONFIG(ADDR_SURF_P2); + tile[9] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P2)); + tile[10] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P2) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[11] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P2) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[12] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P2) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[13] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING)); + tile[14] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P2) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[16] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P2) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[17] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P2) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[27] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P2)); + tile[28] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P2) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[29] = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P2) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + tile[30] = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P2) | + SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2)); + + macrotile[0] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[1] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[2] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[3] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[4] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[5] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[6] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_8_BANK)); + macrotile[8] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[9] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[10] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[11] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[12] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[13] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + macrotile[14] = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_8_BANK)); + + for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) + WREG32(GB_TILE_MODE0 + (reg_offset * 4), tile[reg_offset]); + for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) + WREG32(GB_MACROTILE_MODE0 + (reg_offset * 4), macrotile[reg_offset]); + break; + + default: DRM_ERROR("unknown num pipe config: 0x%x\n", num_pipe_configs); + } } /** @@ -3431,6 +3145,7 @@ static void cik_setup_rb(struct radeon_device *rdev, u32 disabled_rbs = 0; u32 enabled_rbs = 0; + mutex_lock(&rdev->grbm_idx_mutex); for (i = 0; i < se_num; i++) { for (j = 0; j < sh_per_se; j++) { cik_select_se_sh(rdev, i, j); @@ -3442,6 +3157,7 @@ static void cik_setup_rb(struct radeon_device *rdev, } } cik_select_se_sh(rdev, 0xffffffff, 0xffffffff); + mutex_unlock(&rdev->grbm_idx_mutex); mask = 1; for (i = 0; i < max_rb_num_per_se * se_num; i++) { @@ -3452,6 +3168,7 @@ static void cik_setup_rb(struct radeon_device *rdev, rdev->config.cik.backend_enable_mask = enabled_rbs; + mutex_lock(&rdev->grbm_idx_mutex); for (i = 0; i < se_num; i++) { cik_select_se_sh(rdev, i, 0xffffffff); data = 0; @@ -3479,6 +3196,7 @@ static void cik_setup_rb(struct radeon_device *rdev, WREG32(PA_SC_RASTER_CONFIG, data); } cik_select_se_sh(rdev, 0xffffffff, 0xffffffff); + mutex_unlock(&rdev->grbm_idx_mutex); } /** @@ -3607,6 +3325,8 @@ static void cik_gpu_init(struct radeon_device *rdev) } WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff)); + WREG32(SRBM_INT_CNTL, 0x1); + WREG32(SRBM_INT_ACK, 0x1); WREG32(BIF_FB_EN, FB_READ_EN | FB_WRITE_EN); @@ -3696,6 +3416,12 @@ static void cik_gpu_init(struct radeon_device *rdev) /* set HW defaults for 3D engine */ WREG32(CP_MEQ_THRESHOLDS, MEQ1_START(0x30) | MEQ2_START(0x60)); + mutex_lock(&rdev->grbm_idx_mutex); + /* + * making sure that the following register writes will be broadcasted + * to all the shaders + */ + cik_select_se_sh(rdev, 0xffffffff, 0xffffffff); WREG32(SX_DEBUG_1, 0x20); WREG32(TA_CNTL_AUX, 0x00010000); @@ -3751,6 +3477,7 @@ static void cik_gpu_init(struct radeon_device *rdev) WREG32(PA_CL_ENHANCE, CLIP_VTX_REORDER_ENA | NUM_CLIP_SEQ(3)); WREG32(PA_SC_ENHANCE, ENABLE_PA_SC_OUT_OF_ORDER); + mutex_unlock(&rdev->grbm_idx_mutex); udelay(50); } @@ -3892,7 +3619,21 @@ void cik_fence_gfx_ring_emit(struct radeon_device *rdev, struct radeon_ring *ring = &rdev->ring[fence->ring]; u64 addr = rdev->fence_drv[fence->ring].gpu_addr; - /* EVENT_WRITE_EOP - flush caches, send int */ + /* Workaround for cache flush problems. First send a dummy EOP + * event down the pipe with seq one below. + */ + radeon_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4)); + radeon_ring_write(ring, (EOP_TCL1_ACTION_EN | + EOP_TC_ACTION_EN | + EVENT_TYPE(CACHE_FLUSH_AND_INV_TS_EVENT) | + EVENT_INDEX(5))); + radeon_ring_write(ring, addr & 0xfffffffc); + radeon_ring_write(ring, (upper_32_bits(addr) & 0xffff) | + DATA_SEL(1) | INT_SEL(0)); + radeon_ring_write(ring, fence->seq - 1); + radeon_ring_write(ring, 0); + + /* Then send the real EOP event down the pipe. */ radeon_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4)); radeon_ring_write(ring, (EOP_TCL1_ACTION_EN | EOP_TC_ACTION_EN | @@ -4048,10 +3789,10 @@ int cik_copy_cpdma(struct radeon_device *rdev, * @rdev: radeon_device pointer * @ib: radeon indirect buffer object * - * Emits an DE (drawing engine) or CE (constant engine) IB + * Emits a DE (drawing engine) or CE (constant engine) IB * on the gfx ring. IBs are usually generated by userspace * acceleration drivers and submitted to the kernel for - * sheduling on the ring. This function schedules the IB + * scheduling on the ring. This function schedules the IB * on the gfx ring for execution by the GPU. */ void cik_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) @@ -4089,11 +3830,7 @@ void cik_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) (ib->vm ? (ib->vm->id << 24) : 0); radeon_ring_write(ring, header); - radeon_ring_write(ring, -#ifdef __BIG_ENDIAN - (2 << 0) | -#endif - (ib->gpu_addr & 0xFFFFFFFC)); + radeon_ring_write(ring, (ib->gpu_addr & 0xFFFFFFFC)); radeon_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFFFF); radeon_ring_write(ring, control); } @@ -4139,13 +3876,22 @@ int cik_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); return r; } - r = radeon_fence_wait(ib.fence, false); - if (r) { + r = radeon_fence_wait_timeout(ib.fence, false, usecs_to_jiffies( + RADEON_USEC_IB_TEST_TIMEOUT)); + if (r < 0) { DRM_ERROR("radeon: fence wait failed (%d).\n", r); radeon_scratch_free(rdev, scratch); radeon_ib_free(rdev, &ib); return r; - } + } else if (r == 0) { + DRM_ERROR("radeon: fence wait timed out.\n"); +#if 0 + radeon_scratch_free(rdev, scratch); + radeon_ib_free(rdev, &ib); + return -ETIMEDOUT; +#endif + } + r = 0; for (i = 0; i < rdev->usec_timeout; i++) { tmp = RREG32(scratch); if (tmp == 0xDEADBEEF) @@ -4520,6 +4266,31 @@ void cik_compute_set_wptr(struct radeon_device *rdev, WDOORBELL32(ring->doorbell_index, ring->wptr); } +static void cik_compute_stop(struct radeon_device *rdev, + struct radeon_ring *ring) +{ + u32 j, tmp; + + cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0); + /* Disable wptr polling. */ + tmp = RREG32(CP_PQ_WPTR_POLL_CNTL); + tmp &= ~WPTR_POLL_EN; + WREG32(CP_PQ_WPTR_POLL_CNTL, tmp); + /* Disable HQD. */ + if (RREG32(CP_HQD_ACTIVE) & 1) { + WREG32(CP_HQD_DEQUEUE_REQUEST, 1); + for (j = 0; j < rdev->usec_timeout; j++) { + if (!(RREG32(CP_HQD_ACTIVE) & 1)) + break; + udelay(1); + } + WREG32(CP_HQD_DEQUEUE_REQUEST, 0); + WREG32(CP_HQD_PQ_RPTR, 0); + WREG32(CP_HQD_PQ_WPTR, 0); + } + cik_srbm_select(rdev, 0, 0, 0, 0); +} + /** * cik_cp_compute_enable - enable/disable the compute CP MEs * @@ -4533,6 +4304,15 @@ static void cik_cp_compute_enable(struct radeon_device *rdev, bool enable) if (enable) WREG32(CP_MEC_CNTL, 0); else { + /* + * To make hibernation reliable we need to clear compute ring + * configuration before halting the compute ring. + */ + mutex_lock(&rdev->srbm_mutex); + cik_compute_stop(rdev,&rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX]); + cik_compute_stop(rdev,&rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX]); + mutex_unlock(&rdev->srbm_mutex); + WREG32(CP_MEC_CNTL, (MEC_ME1_HALT | MEC_ME2_HALT)); rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX].ready = false; rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX].ready = false; @@ -5504,15 +5284,21 @@ static void cik_gpu_pci_config_reset(struct radeon_device *rdev) * cik_asic_reset - soft reset GPU * * @rdev: radeon_device pointer + * @hard: force hard reset * * Look up which blocks are hung and attempt * to reset them. * Returns 0 for success. */ -int cik_asic_reset(struct radeon_device *rdev) +int cik_asic_reset(struct radeon_device *rdev, bool hard) { u32 reset_mask; + if (hard) { + cik_gpu_pci_config_reset(rdev); + return 0; + } + reset_mask = cik_gpu_check_soft_reset(rdev); if (reset_mask) @@ -5703,6 +5489,28 @@ void cik_pcie_gart_tlb_flush(struct radeon_device *rdev) WREG32(VM_INVALIDATE_REQUEST, 0x1); } +static void cik_pcie_init_compute_vmid(struct radeon_device *rdev) +{ + int i; + uint32_t sh_mem_bases, sh_mem_config; + + sh_mem_bases = 0x6000 | 0x6000 << 16; + sh_mem_config = ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED); + sh_mem_config |= DEFAULT_MTYPE(MTYPE_NONCACHED); + + mutex_lock(&rdev->srbm_mutex); + for (i = 8; i < 16; i++) { + cik_srbm_select(rdev, 0, 0, 0, i); + /* CP and shaders */ + WREG32(SH_MEM_CONFIG, sh_mem_config); + WREG32(SH_MEM_APE1_BASE, 1); + WREG32(SH_MEM_APE1_LIMIT, 0); + WREG32(SH_MEM_BASES, sh_mem_bases); + } + cik_srbm_select(rdev, 0, 0, 0, 0); + mutex_unlock(&rdev->srbm_mutex); +} + /** * cik_pcie_gart_enable - gart enable * @@ -5761,7 +5569,7 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev) /* restore context1-15 */ /* set vm size, must be a multiple of 4 */ WREG32(VM_CONTEXT1_PAGE_TABLE_START_ADDR, 0); - WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn); + WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn - 1); for (i = 1; i < 16; i++) { if (i < 8) WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2), @@ -5816,6 +5624,8 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev) cik_srbm_select(rdev, 0, 0, 0, 0); mutex_unlock(&rdev->srbm_mutex); + cik_pcie_init_compute_vmid(rdev); + cik_pcie_gart_tlb_flush(rdev); DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n", (unsigned)(rdev->mc.gtt_size >> 20), @@ -5969,26 +5779,23 @@ static void cik_vm_decode_fault(struct radeon_device *rdev, * Update the page table base and flush the VM TLB * using the CP (CIK). */ -void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) +void cik_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, + unsigned vm_id, uint64_t pd_addr) { - struct radeon_ring *ring = &rdev->ring[ridx]; - int usepfp = (ridx == RADEON_RING_TYPE_GFX_INDEX); - - if (vm == NULL) - return; + int usepfp = (ring->idx == RADEON_RING_TYPE_GFX_INDEX); radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) | WRITE_DATA_DST_SEL(0))); - if (vm->id < 8) { - radeon_ring_write(ring, - (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2); + if (vm_id < 8) { + radeon_ring_write(ring, + (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm_id << 2)) >> 2); } else { radeon_ring_write(ring, - (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2); + (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm_id - 8) << 2)) >> 2); } radeon_ring_write(ring, 0); - radeon_ring_write(ring, vm->pd_gpu_addr >> 12); + radeon_ring_write(ring, pd_addr >> 12); /* update SH_MEM_* regs */ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); @@ -5996,7 +5803,7 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) WRITE_DATA_DST_SEL(0))); radeon_ring_write(ring, SRBM_GFX_CNTL >> 2); radeon_ring_write(ring, 0); - radeon_ring_write(ring, VMID(vm->id)); + radeon_ring_write(ring, VMID(vm_id)); radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 6)); radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) | @@ -6017,7 +5824,7 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) radeon_ring_write(ring, VMID(0)); /* HDP flush */ - cik_hdp_flush_cp_ring_emit(rdev, ridx); + cik_hdp_flush_cp_ring_emit(rdev, ring->idx); /* bits 0-15 are the VM contexts0-15 */ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); @@ -6025,7 +5832,18 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) WRITE_DATA_DST_SEL(0))); radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); radeon_ring_write(ring, 0); - radeon_ring_write(ring, 1 << vm->id); + radeon_ring_write(ring, 1 << vm_id); + + /* wait for the invalidate to complete */ + radeon_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5)); + radeon_ring_write(ring, (WAIT_REG_MEM_OPERATION(0) | /* wait */ + WAIT_REG_MEM_FUNCTION(0) | /* always */ + WAIT_REG_MEM_ENGINE(0))); /* me */ + radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); + radeon_ring_write(ring, 0); + radeon_ring_write(ring, 0); /* ref */ + radeon_ring_write(ring, 0); /* mask */ + radeon_ring_write(ring, 0x20); /* poll interval */ /* compute doesn't have PFP */ if (usepfp) { @@ -6070,6 +5888,7 @@ static void cik_wait_for_rlc_serdes(struct radeon_device *rdev) u32 i, j, k; u32 mask; + mutex_lock(&rdev->grbm_idx_mutex); for (i = 0; i < rdev->config.cik.max_shader_engines; i++) { for (j = 0; j < rdev->config.cik.max_sh_per_se; j++) { cik_select_se_sh(rdev, i, j); @@ -6081,6 +5900,7 @@ static void cik_wait_for_rlc_serdes(struct radeon_device *rdev) } } cik_select_se_sh(rdev, 0xffffffff, 0xffffffff); + mutex_unlock(&rdev->grbm_idx_mutex); mask = SE_MASTER_BUSY_MASK | GC_MASTER_BUSY | TC0_MASTER_BUSY | TC1_MASTER_BUSY; for (k = 0; k < rdev->usec_timeout; k++) { @@ -6215,10 +6035,12 @@ static int cik_rlc_resume(struct radeon_device *rdev) WREG32(RLC_LB_CNTR_INIT, 0); WREG32(RLC_LB_CNTR_MAX, 0x00008000); + mutex_lock(&rdev->grbm_idx_mutex); cik_select_se_sh(rdev, 0xffffffff, 0xffffffff); WREG32(RLC_LB_INIT_CU_MASK, 0xffffffff); WREG32(RLC_LB_PARAMS, 0x00600408); WREG32(RLC_LB_CNTL, 0x80000004); + mutex_unlock(&rdev->grbm_idx_mutex); WREG32(RLC_MC_CNTL, 0); WREG32(RLC_UCODE_CNTL, 0); @@ -6285,11 +6107,13 @@ static void cik_enable_cgcg(struct radeon_device *rdev, bool enable) tmp = cik_halt_rlc(rdev); + mutex_lock(&rdev->grbm_idx_mutex); cik_select_se_sh(rdev, 0xffffffff, 0xffffffff); WREG32(RLC_SERDES_WR_CU_MASTER_MASK, 0xffffffff); WREG32(RLC_SERDES_WR_NONCU_MASTER_MASK, 0xffffffff); tmp2 = BPM_ADDR_MASK | CGCG_OVERRIDE_0 | CGLS_ENABLE; WREG32(RLC_SERDES_WR_CTRL, tmp2); + mutex_unlock(&rdev->grbm_idx_mutex); cik_update_rlc(rdev, tmp); @@ -6325,17 +6149,20 @@ static void cik_enable_mgcg(struct radeon_device *rdev, bool enable) } orig = data = RREG32(RLC_CGTT_MGCG_OVERRIDE); + data |= 0x00000001; data &= 0xfffffffd; if (orig != data) WREG32(RLC_CGTT_MGCG_OVERRIDE, data); tmp = cik_halt_rlc(rdev); + mutex_lock(&rdev->grbm_idx_mutex); cik_select_se_sh(rdev, 0xffffffff, 0xffffffff); WREG32(RLC_SERDES_WR_CU_MASTER_MASK, 0xffffffff); WREG32(RLC_SERDES_WR_NONCU_MASTER_MASK, 0xffffffff); data = BPM_ADDR_MASK | MGCG_OVERRIDE_0; WREG32(RLC_SERDES_WR_CTRL, data); + mutex_unlock(&rdev->grbm_idx_mutex); cik_update_rlc(rdev, tmp); @@ -6356,7 +6183,7 @@ static void cik_enable_mgcg(struct radeon_device *rdev, bool enable) } } else { orig = data = RREG32(RLC_CGTT_MGCG_OVERRIDE); - data |= 0x00000002; + data |= 0x00000003; if (orig != data) WREG32(RLC_CGTT_MGCG_OVERRIDE, data); @@ -6379,11 +6206,13 @@ static void cik_enable_mgcg(struct radeon_device *rdev, bool enable) tmp = cik_halt_rlc(rdev); + mutex_lock(&rdev->grbm_idx_mutex); cik_select_se_sh(rdev, 0xffffffff, 0xffffffff); WREG32(RLC_SERDES_WR_CU_MASTER_MASK, 0xffffffff); WREG32(RLC_SERDES_WR_NONCU_MASTER_MASK, 0xffffffff); data = BPM_ADDR_MASK | MGCG_OVERRIDE_1; WREG32(RLC_SERDES_WR_CTRL, data); + mutex_unlock(&rdev->grbm_idx_mutex); cik_update_rlc(rdev, tmp); } @@ -6812,10 +6641,12 @@ static u32 cik_get_cu_active_bitmap(struct radeon_device *rdev, u32 se, u32 sh) u32 mask = 0, tmp, tmp1; int i; + mutex_lock(&rdev->grbm_idx_mutex); cik_select_se_sh(rdev, se, sh); tmp = RREG32(CC_GC_SHADER_ARRAY_CONFIG); tmp1 = RREG32(GC_USER_SHADER_ARRAY_CONFIG); cik_select_se_sh(rdev, 0xffffffff, 0xffffffff); + mutex_unlock(&rdev->grbm_idx_mutex); tmp &= 0xffff0000; @@ -7161,6 +6992,8 @@ static void cik_disable_interrupt_state(struct radeon_device *rdev) WREG32(CP_ME2_PIPE3_INT_CNTL, 0); /* grbm */ WREG32(GRBM_INT_CNTL, 0); + /* SRBM */ + WREG32(SRBM_INT_CNTL, 0); /* vline/vblank, etc. */ WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); @@ -7305,7 +7138,6 @@ int cik_irq_set(struct radeon_device *rdev) u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6; u32 grbm_int_cntl = 0; u32 dma_cntl, dma_cntl1; - u32 thermal_int; if (!rdev->irq.installed) { WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); @@ -7323,12 +7155,12 @@ int cik_irq_set(struct radeon_device *rdev) (CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE); cp_int_cntl |= PRIV_INSTR_INT_ENABLE | PRIV_REG_INT_ENABLE; - hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN; - hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN; - hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN; - hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN; - hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN; - hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN; + hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN); + hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN); + hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN); + hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN); + hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN); + hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN); dma_cntl = RREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET) & ~TRAP_ENABLE; dma_cntl1 = RREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET) & ~TRAP_ENABLE; @@ -7342,13 +7174,6 @@ int cik_irq_set(struct radeon_device *rdev) cp_m2p2 = RREG32(CP_ME2_PIPE2_INT_CNTL) & ~TIME_STAMP_INT_ENABLE; cp_m2p3 = RREG32(CP_ME2_PIPE3_INT_CNTL) & ~TIME_STAMP_INT_ENABLE; - if (rdev->flags & RADEON_IS_IGP) - thermal_int = RREG32_SMC(CG_THERMAL_INT_CTRL) & - ~(THERM_INTH_MASK | THERM_INTL_MASK); - else - thermal_int = RREG32_SMC(CG_THERMAL_INT) & - ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW); - /* enable CP interrupts on all rings */ if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) { DRM_DEBUG("cik_irq_set: sw int gfx\n"); @@ -7481,38 +7306,30 @@ int cik_irq_set(struct radeon_device *rdev) DRM_DEBUG("cik_irq_set: vblank 5\n"); crtc6 |= VBLANK_INTERRUPT_MASK; } - if (rdev->irq.hpd[0]) { - DRM_DEBUG("cik_irq_set: hpd 1\n"); - hpd1 |= DC_HPDx_INT_EN; - } - if (rdev->irq.hpd[1]) { - DRM_DEBUG("cik_irq_set: hpd 2\n"); - hpd2 |= DC_HPDx_INT_EN; - } - if (rdev->irq.hpd[2]) { - DRM_DEBUG("cik_irq_set: hpd 3\n"); - hpd3 |= DC_HPDx_INT_EN; - } - if (rdev->irq.hpd[3]) { - DRM_DEBUG("cik_irq_set: hpd 4\n"); - hpd4 |= DC_HPDx_INT_EN; - } - if (rdev->irq.hpd[4]) { - DRM_DEBUG("cik_irq_set: hpd 5\n"); - hpd5 |= DC_HPDx_INT_EN; - } - if (rdev->irq.hpd[5]) { - DRM_DEBUG("cik_irq_set: hpd 6\n"); - hpd6 |= DC_HPDx_INT_EN; - } - - if (rdev->irq.dpm_thermal) { - DRM_DEBUG("dpm thermal\n"); - if (rdev->flags & RADEON_IS_IGP) - thermal_int |= THERM_INTH_MASK | THERM_INTL_MASK; - else - thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW; - } + if (rdev->irq.hpd[0]) { + DRM_DEBUG("cik_irq_set: hpd 1\n"); + hpd1 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN; + } + if (rdev->irq.hpd[1]) { + DRM_DEBUG("cik_irq_set: hpd 2\n"); + hpd2 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN; + } + if (rdev->irq.hpd[2]) { + DRM_DEBUG("cik_irq_set: hpd 3\n"); + hpd3 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN; + } + if (rdev->irq.hpd[3]) { + DRM_DEBUG("cik_irq_set: hpd 4\n"); + hpd4 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN; + } + if (rdev->irq.hpd[4]) { + DRM_DEBUG("cik_irq_set: hpd 5\n"); + hpd5 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN; + } + if (rdev->irq.hpd[5]) { + DRM_DEBUG("cik_irq_set: hpd 6\n"); + hpd6 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN; + } WREG32(CP_INT_CNTL_RING0, cp_int_cntl); @@ -7567,10 +7384,8 @@ int cik_irq_set(struct radeon_device *rdev) WREG32(DC_HPD5_INT_CONTROL, hpd5); WREG32(DC_HPD6_INT_CONTROL, hpd6); - if (rdev->flags & RADEON_IS_IGP) - WREG32_SMC(CG_THERMAL_INT_CTRL, thermal_int); - else - WREG32_SMC(CG_THERMAL_INT, thermal_int); + /* posting read */ + RREG32(SRBM_STATUS); return 0; } @@ -7692,6 +7507,36 @@ static inline void cik_irq_ack(struct radeon_device *rdev) tmp |= DC_HPDx_INT_ACK; WREG32(DC_HPD6_INT_CONTROL, tmp); } + if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_RX_INTERRUPT) { + tmp = RREG32(DC_HPD1_INT_CONTROL); + tmp |= DC_HPDx_RX_INT_ACK; + WREG32(DC_HPD1_INT_CONTROL, tmp); + } + if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_RX_INTERRUPT) { + tmp = RREG32(DC_HPD2_INT_CONTROL); + tmp |= DC_HPDx_RX_INT_ACK; + WREG32(DC_HPD2_INT_CONTROL, tmp); + } + if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) { + tmp = RREG32(DC_HPD3_INT_CONTROL); + tmp |= DC_HPDx_RX_INT_ACK; + WREG32(DC_HPD3_INT_CONTROL, tmp); + } + if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) { + tmp = RREG32(DC_HPD4_INT_CONTROL); + tmp |= DC_HPDx_RX_INT_ACK; + WREG32(DC_HPD4_INT_CONTROL, tmp); + } + if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) { + tmp = RREG32(DC_HPD5_INT_CONTROL); + tmp |= DC_HPDx_RX_INT_ACK; + WREG32(DC_HPD5_INT_CONTROL, tmp); + } + if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) { + tmp = RREG32(DC_HPD5_INT_CONTROL); + tmp |= DC_HPDx_RX_INT_ACK; + WREG32(DC_HPD6_INT_CONTROL, tmp); + } } /** @@ -7817,6 +7662,7 @@ irqreturn_t cik_irq_process(struct radeon_device *rdev) u8 me_id, pipe_id, queue_id; u32 ring_index; bool queue_hotplug = false; + bool queue_dp = false; bool queue_reset = false; u32 addr, status, mc_client; bool queue_thermal = false; @@ -7832,7 +7678,7 @@ restart_ih: return IRQ_NONE; rptr = rdev->ih.rptr; - DRM_DEBUG_VBLANK("cik_irq_process start: rptr %d, wptr %d\n", rptr, wptr); + DRM_DEBUG("cik_irq_process start: rptr %d, wptr %d\n", rptr, wptr); /* Order reading of wptr vs. reading of IH ring data */ rmb(); @@ -7851,23 +7697,27 @@ restart_ih: case 1: /* D1 vblank/vline */ switch (src_data) { case 0: /* D1 vblank */ - if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[0]) { - drm_handle_vblank(rdev->ddev, 0); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[0])) - radeon_crtc_handle_vblank(rdev, 0); - rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VBLANK_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D1 vblank\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int & LB_D1_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[0]) { + drm_handle_vblank(rdev->ddev, 0); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (atomic_read(&rdev->irq.pflip[0])) + radeon_crtc_handle_vblank(rdev, 0); + rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D1 vblank\n"); + break; case 1: /* D1 vline */ - if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VLINE_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VLINE_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D1 vline\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int & LB_D1_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VLINE_INTERRUPT; + DRM_DEBUG("IH: D1 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -7877,23 +7727,27 @@ restart_ih: case 2: /* D2 vblank/vline */ switch (src_data) { case 0: /* D2 vblank */ - if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[1]) { - drm_handle_vblank(rdev->ddev, 1); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[1])) - radeon_crtc_handle_vblank(rdev, 1); - rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D2 vblank\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[1]) { + drm_handle_vblank(rdev->ddev, 1); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (atomic_read(&rdev->irq.pflip[1])) + radeon_crtc_handle_vblank(rdev, 1); + rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D2 vblank\n"); + break; case 1: /* D2 vline */ - if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VLINE_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D2 vline\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; + DRM_DEBUG("IH: D2 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -7903,23 +7757,27 @@ restart_ih: case 3: /* D3 vblank/vline */ switch (src_data) { case 0: /* D3 vblank */ - if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[2]) { - drm_handle_vblank(rdev->ddev, 2); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[2])) - radeon_crtc_handle_vblank(rdev, 2); - rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D3 vblank\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[2]) { + drm_handle_vblank(rdev->ddev, 2); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (atomic_read(&rdev->irq.pflip[2])) + radeon_crtc_handle_vblank(rdev, 2); + rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D3 vblank\n"); + break; case 1: /* D3 vline */ - if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D3 vline\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; + DRM_DEBUG("IH: D3 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -7929,23 +7787,27 @@ restart_ih: case 4: /* D4 vblank/vline */ switch (src_data) { case 0: /* D4 vblank */ - if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[3]) { - drm_handle_vblank(rdev->ddev, 3); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[3])) - radeon_crtc_handle_vblank(rdev, 3); - rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D4 vblank\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[3]) { + drm_handle_vblank(rdev->ddev, 3); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (atomic_read(&rdev->irq.pflip[3])) + radeon_crtc_handle_vblank(rdev, 3); + rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D4 vblank\n"); + break; case 1: /* D4 vline */ - if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D4 vline\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; + DRM_DEBUG("IH: D4 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -7955,23 +7817,27 @@ restart_ih: case 5: /* D5 vblank/vline */ switch (src_data) { case 0: /* D5 vblank */ - if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[4]) { - drm_handle_vblank(rdev->ddev, 4); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[4])) - radeon_crtc_handle_vblank(rdev, 4); - rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D5 vblank\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[4]) { + drm_handle_vblank(rdev->ddev, 4); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (atomic_read(&rdev->irq.pflip[4])) + radeon_crtc_handle_vblank(rdev, 4); + rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D5 vblank\n"); + break; case 1: /* D5 vline */ - if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D5 vline\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; + DRM_DEBUG("IH: D5 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -7981,23 +7847,27 @@ restart_ih: case 6: /* D6 vblank/vline */ switch (src_data) { case 0: /* D6 vblank */ - if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[5]) { - drm_handle_vblank(rdev->ddev, 5); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[5])) - radeon_crtc_handle_vblank(rdev, 5); - rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D6 vblank\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[5]) { + drm_handle_vblank(rdev->ddev, 5); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (atomic_read(&rdev->irq.pflip[5])) + radeon_crtc_handle_vblank(rdev, 5); + rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D6 vblank\n"); + break; case 1: /* D6 vline */ - if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D6 vline\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; + DRM_DEBUG("IH: D6 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -8010,59 +7880,129 @@ restart_ih: case 14: /* D4 page flip */ case 16: /* D5 page flip */ case 18: /* D6 page flip */ - DRM_DEBUG_VBLANK("IH: D%d flip\n", ((src_id - 8) >> 1) + 1); + DRM_DEBUG("IH: D%d flip\n", ((src_id - 8) >> 1) + 1); if (radeon_use_pflipirq > 0) radeon_crtc_handle_flip(rdev, (src_id - 8) >> 1); break; case 42: /* HPD hotplug */ switch (src_data) { case 0: - if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD1\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int & DC_HPD1_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD1\n"); + break; case 1: - if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD2\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD2\n"); + break; case 2: - if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD3\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD3\n"); + break; case 3: - if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD4\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD4\n"); + break; case 4: - if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD5\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD5\n"); + break; case 5: - if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD6\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD6\n"); + + break; + case 6: + if (!(rdev->irq.stat_regs.cik.disp_int & DC_HPD1_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 1\n"); + + break; + case 7: + if (!(rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 2\n"); + + break; + case 8: + if (!(rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 3\n"); + + break; + case 9: + if (!(rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 4\n"); + + break; + case 10: + if (!(rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 5\n"); + + break; + case 11: + if (!(rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 6\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); break; } break; + case 96: + DRM_ERROR("SRBM_READ_ERROR: 0x%x\n", RREG32(SRBM_READ_ERROR)); + WREG32(SRBM_INT_ACK, 0x1); + break; case 124: /* UVD */ DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data); radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX); @@ -8262,6 +8202,8 @@ restart_ih: rptr &= rdev->ih.ptr_mask; WREG32(IH_RB_RPTR, rptr); } + if (queue_dp) + schedule_work(&rdev->dp_work); if (queue_hotplug) taskqueue_enqueue(rdev->tq, &rdev->hotplug_work); if (queue_reset) { @@ -8284,6 +8226,164 @@ restart_ih: /* * startup/shutdown callbacks */ +static void cik_uvd_init(struct radeon_device *rdev) +{ + int r; + + if (!rdev->has_uvd) + return; + + r = radeon_uvd_init(rdev); + if (r) { + dev_err(rdev->dev, "failed UVD (%d) init.\n", r); + /* + * At this point rdev->uvd.vcpu_bo is NULL which trickles down + * to early fails cik_uvd_start() and thus nothing happens + * there. So it is pointless to try to go through that code + * hence why we disable uvd here. + */ + rdev->has_uvd = 0; + return; + } + rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL; + r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX], 4096); +} + +static void cik_uvd_start(struct radeon_device *rdev) +{ + int r; + + if (!rdev->has_uvd) + return; + + r = radeon_uvd_resume(rdev); + if (r) { + dev_err(rdev->dev, "failed UVD resume (%d).\n", r); + goto error; + } + r = uvd_v4_2_resume(rdev); + if (r) { + dev_err(rdev->dev, "failed UVD 4.2 resume (%d).\n", r); + goto error; + } + r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX); + if (r) { + dev_err(rdev->dev, "failed initializing UVD fences (%d).\n", r); + goto error; + } + return; + +error: + rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; +} + +static void cik_uvd_resume(struct radeon_device *rdev) +{ + struct radeon_ring *ring; + int r; + + if (!rdev->has_uvd || !rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size) + return; + + ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; + r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2); + if (r) { + dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r); + return; + } + r = uvd_v1_0_init(rdev); + if (r) { + dev_err(rdev->dev, "failed initializing UVD (%d).\n", r); + return; + } +} + +static void cik_vce_init(struct radeon_device *rdev) +{ + int r; + + if (!rdev->has_vce) + return; + + r = radeon_vce_init(rdev); + if (r) { + dev_err(rdev->dev, "failed VCE (%d) init.\n", r); + /* + * At this point rdev->vce.vcpu_bo is NULL which trickles down + * to early fails cik_vce_start() and thus nothing happens + * there. So it is pointless to try to go through that code + * hence why we disable vce here. + */ + rdev->has_vce = 0; + return; + } + rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_obj = NULL; + r600_ring_init(rdev, &rdev->ring[TN_RING_TYPE_VCE1_INDEX], 4096); + rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_obj = NULL; + r600_ring_init(rdev, &rdev->ring[TN_RING_TYPE_VCE2_INDEX], 4096); +} + +static void cik_vce_start(struct radeon_device *rdev) +{ + int r; + + if (!rdev->has_vce) + return; + + r = radeon_vce_resume(rdev); + if (r) { + dev_err(rdev->dev, "failed VCE resume (%d).\n", r); + goto error; + } + r = vce_v2_0_resume(rdev); + if (r) { + dev_err(rdev->dev, "failed VCE resume (%d).\n", r); + goto error; + } + r = radeon_fence_driver_start_ring(rdev, TN_RING_TYPE_VCE1_INDEX); + if (r) { + dev_err(rdev->dev, "failed initializing VCE1 fences (%d).\n", r); + goto error; + } + r = radeon_fence_driver_start_ring(rdev, TN_RING_TYPE_VCE2_INDEX); + if (r) { + dev_err(rdev->dev, "failed initializing VCE2 fences (%d).\n", r); + goto error; + } + return; + +error: + rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size = 0; + rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_size = 0; +} + +static void cik_vce_resume(struct radeon_device *rdev) +{ + struct radeon_ring *ring; + int r; + + if (!rdev->has_vce || !rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size) + return; + + ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; + r = radeon_ring_init(rdev, ring, ring->ring_size, 0, VCE_CMD_NO_OP); + if (r) { + dev_err(rdev->dev, "failed initializing VCE1 ring (%d).\n", r); + return; + } + ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; + r = radeon_ring_init(rdev, ring, ring->ring_size, 0, VCE_CMD_NO_OP); + if (r) { + dev_err(rdev->dev, "failed initializing VCE1 ring (%d).\n", r); + return; + } + r = vce_v1_0_init(rdev); + if (r) { + dev_err(rdev->dev, "failed initializing VCE (%d).\n", r); + return; + } +} + /** * cik_startup - program the asic to a functional state * @@ -8386,34 +8486,8 @@ static int cik_startup(struct radeon_device *rdev) return r; } - r = radeon_uvd_resume(rdev); - if (!r) { - r = uvd_v4_2_resume(rdev); - if (!r) { - r = radeon_fence_driver_start_ring(rdev, - R600_RING_TYPE_UVD_INDEX); - if (r) - dev_err(rdev->dev, "UVD fences init error (%d).\n", r); - } - } - if (r) - rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; - - r = radeon_vce_resume(rdev); - if (!r) { - r = vce_v2_0_resume(rdev); - if (!r) - r = radeon_fence_driver_start_ring(rdev, - TN_RING_TYPE_VCE1_INDEX); - if (!r) - r = radeon_fence_driver_start_ring(rdev, - TN_RING_TYPE_VCE2_INDEX); - } - if (r) { - dev_err(rdev->dev, "VCE init error (%d).\n", r); - rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size = 0; - rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_size = 0; - } + cik_uvd_start(rdev); + cik_vce_start(rdev); /* Enable IRQ */ if (!rdev->irq.installed) { @@ -8489,32 +8563,8 @@ static int cik_startup(struct radeon_device *rdev) if (r) return r; - ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; - if (ring->ring_size) { - r = radeon_ring_init(rdev, ring, ring->ring_size, 0, - RADEON_CP_PACKET2); - if (!r) - r = uvd_v1_0_init(rdev); - if (r) - DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); - } - - r = -ENOENT; - - ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; - if (ring->ring_size) - r = radeon_ring_init(rdev, ring, ring->ring_size, 0, - VCE_CMD_NO_OP); - - ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; - if (ring->ring_size) - r = radeon_ring_init(rdev, ring, ring->ring_size, 0, - VCE_CMD_NO_OP); - - if (!r) - r = vce_v1_0_init(rdev); - else if (r != -ENOENT) - DRM_ERROR("radeon: failed initializing VCE (%d).\n", r); + cik_uvd_resume(rdev); + cik_vce_resume(rdev); r = radeon_ib_pool_init(rdev); if (r) { @@ -8528,7 +8578,7 @@ static int cik_startup(struct radeon_device *rdev) return r; } - r = dce6_audio_init(rdev); + r = radeon_audio_init(rdev); if (r) return r; @@ -8581,12 +8631,15 @@ int cik_resume(struct radeon_device *rdev) int cik_suspend(struct radeon_device *rdev) { radeon_pm_suspend(rdev); - dce6_audio_fini(rdev); + radeon_audio_fini(rdev); radeon_vm_manager_fini(rdev); cik_cp_enable(rdev, false); cik_sdma_enable(rdev, false); + if (rdev->has_uvd) { uvd_v1_0_fini(rdev); radeon_uvd_suspend(rdev); + } + if (rdev->has_vce) radeon_vce_suspend(rdev); cik_fini_pg(rdev); cik_fini_cg(rdev); @@ -8713,23 +8766,8 @@ int cik_init(struct radeon_device *rdev) ring->ring_obj = NULL; r600_ring_init(rdev, ring, 256 * 1024); - r = radeon_uvd_init(rdev); - if (!r) { - ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; - ring->ring_obj = NULL; - r600_ring_init(rdev, ring, 4096); - } - - r = radeon_vce_init(rdev); - if (!r) { - ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; - ring->ring_obj = NULL; - r600_ring_init(rdev, ring, 4096); - - ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; - ring->ring_obj = NULL; - r600_ring_init(rdev, ring, 4096); - } + cik_uvd_init(rdev); + cik_vce_init(rdev); rdev->ih.ring_obj = NULL; r600_ih_ring_init(rdev, 64 * 1024); @@ -9417,6 +9455,9 @@ static void dce8_program_watermarks(struct radeon_device *rdev, (rdev->disp_priority == 2)) { DRM_DEBUG_KMS("force priority to high\n"); } + + /* Save number of lines the linebuffer leads before the scanout */ + radeon_crtc->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay); } /* select wm A */ diff --git a/sys/dev/drm/radeon/cik_sdma.c b/sys/dev/drm/radeon/cik_sdma.c index e6182048c7..ff04d96648 100644 --- a/sys/dev/drm/radeon/cik_sdma.c +++ b/sys/dev/drm/radeon/cik_sdma.c @@ -268,6 +268,17 @@ static void cik_sdma_gfx_stop(struct radeon_device *rdev) } rdev->ring[R600_RING_TYPE_DMA_INDEX].ready = false; rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX].ready = false; + + /* FIXME use something else than big hammer but after few days can not + * seem to find good combination so reset SDMA blocks as it seems we + * do not shut them down properly. This fix hibernation and does not + * affect suspend to ram. + */ + WREG32(SRBM_SOFT_RESET, SOFT_RESET_SDMA | SOFT_RESET_SDMA1); + (void)RREG32(SRBM_SOFT_RESET); + udelay(50); + WREG32(SRBM_SOFT_RESET, 0); + (void)RREG32(SRBM_SOFT_RESET); } /** @@ -282,6 +293,33 @@ static void cik_sdma_rlc_stop(struct radeon_device *rdev) /* XXX todo */ } +/** + * cik_sdma_ctx_switch_enable - enable/disable sdma engine preemption + * + * @rdev: radeon_device pointer + * @enable: enable/disable preemption. + * + * Halt or unhalt the async dma engines (CIK). + */ +static void cik_sdma_ctx_switch_enable(struct radeon_device *rdev, bool enable) +{ + uint32_t reg_offset, value; + int i; + + for (i = 0; i < 2; i++) { + if (i == 0) + reg_offset = SDMA0_REGISTER_OFFSET; + else + reg_offset = SDMA1_REGISTER_OFFSET; + value = RREG32(SDMA0_CNTL + reg_offset); + if (enable) + value |= AUTO_CTXSW_ENABLE; + else + value &= ~AUTO_CTXSW_ENABLE; + WREG32(SDMA0_CNTL + reg_offset, value); + } +} + /** * cik_sdma_enable - stop the async dma engines * @@ -312,6 +350,8 @@ void cik_sdma_enable(struct radeon_device *rdev, bool enable) me_cntl |= SDMA_HALT; WREG32(SDMA0_ME_CNTL + reg_offset, me_cntl); } + + cik_sdma_ctx_switch_enable(rdev, enable); } /** @@ -700,11 +740,18 @@ int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); return r; } - r = radeon_fence_wait(ib.fence, false); - if (r) { - DRM_ERROR("radeon: fence wait failed (%d).\n", r); - return r; - } + r = radeon_fence_wait_timeout(ib.fence, false, usecs_to_jiffies( + RADEON_USEC_IB_TEST_TIMEOUT)); + if (r < 0) { + DRM_ERROR("radeon: fence wait failed (%d).\n", r); + return r; + } else if (r == 0) { + DRM_ERROR("radeon: fence wait timed out.\n"); +#if 0 + return -ETIMEDOUT; +#endif + } + r = 0; for (i = 0; i < rdev->usec_timeout; i++) { tmp = le32_to_cpu(rdev->wb.wb[index/4]); if (tmp == 0xDEADBEEF) @@ -819,7 +866,6 @@ void cik_sdma_vm_write_pages(struct radeon_device *rdev, for (; ndw > 0; ndw -= 2, --count, pe += 8) { if (flags & R600_PTE_SYSTEM) { value = radeon_vm_map_gart(rdev, addr); - value &= 0xFFFFFFFFFFFFF000ULL; } else if (flags & R600_PTE_VALID) { value = addr; } else { @@ -903,25 +949,24 @@ void cik_sdma_vm_pad_ib(struct radeon_ib *ib) * Update the page table base and flush the VM TLB * using sDMA (CIK). */ -void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) +void cik_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, + unsigned vm_id, uint64_t pd_addr) { - struct radeon_ring *ring = &rdev->ring[ridx]; - - if (vm == NULL) - return; + u32 extra_bits = (SDMA_POLL_REG_MEM_EXTRA_OP(0) | + SDMA_POLL_REG_MEM_EXTRA_FUNC(0)); /* always */ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); - if (vm->id < 8) { - radeon_ring_write(ring, (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2); + if (vm_id < 8) { + radeon_ring_write(ring, (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm_id << 2)) >> 2); } else { - radeon_ring_write(ring, (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2); + radeon_ring_write(ring, (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm_id - 8) << 2)) >> 2); } - radeon_ring_write(ring, vm->pd_gpu_addr >> 12); + radeon_ring_write(ring, pd_addr >> 12); /* update SH_MEM_* regs */ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); radeon_ring_write(ring, SRBM_GFX_CNTL >> 2); - radeon_ring_write(ring, VMID(vm->id)); + radeon_ring_write(ring, VMID(vm_id)); radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); radeon_ring_write(ring, SH_MEM_BASES >> 2); @@ -944,10 +989,17 @@ void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm radeon_ring_write(ring, VMID(0)); /* flush HDP */ - cik_sdma_hdp_flush_ring_emit(rdev, ridx); + cik_sdma_hdp_flush_ring_emit(rdev, ring->idx); /* flush TLB */ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); - radeon_ring_write(ring, 1 << vm->id); + radeon_ring_write(ring, 1 << vm_id); + + radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_POLL_REG_MEM, 0, extra_bits)); + radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); + radeon_ring_write(ring, 0); + radeon_ring_write(ring, 0); /* reference */ + radeon_ring_write(ring, 0); /* mask */ + radeon_ring_write(ring, (0xfff << 16) | 10); /* retry count, poll interval */ } diff --git a/sys/dev/drm/radeon/cikd.h b/sys/dev/drm/radeon/cikd.h index 0c6e1b55d9..bd748dbc59 100644 --- a/sys/dev/drm/radeon/cikd.h +++ b/sys/dev/drm/radeon/cikd.h @@ -184,7 +184,10 @@ #define DIG_THERM_DPM(x) ((x) << 14) #define DIG_THERM_DPM_MASK 0x003FC000 #define DIG_THERM_DPM_SHIFT 14 - +#define CG_THERMAL_STATUS 0xC0300008 +#define FDO_PWM_DUTY(x) ((x) << 9) +#define FDO_PWM_DUTY_MASK (0xff << 9) +#define FDO_PWM_DUTY_SHIFT 9 #define CG_THERMAL_INT 0xC030000C #define CI_DIG_THERM_INTH(x) ((x) << 8) #define CI_DIG_THERM_INTH_MASK 0x0000FF00 @@ -194,7 +197,10 @@ #define CI_DIG_THERM_INTL_SHIFT 16 #define THERM_INT_MASK_HIGH (1 << 24) #define THERM_INT_MASK_LOW (1 << 25) - +#define CG_MULT_THERMAL_CTRL 0xC0300010 +#define TEMP_SEL(x) ((x) << 20) +#define TEMP_SEL_MASK (0xff << 20) +#define TEMP_SEL_SHIFT 20 #define CG_MULT_THERMAL_STATUS 0xC0300014 #define ASIC_MAX_TEMP(x) ((x) << 0) #define ASIC_MAX_TEMP_MASK 0x000001ff @@ -203,6 +209,36 @@ #define CTF_TEMP_MASK 0x0003fe00 #define CTF_TEMP_SHIFT 9 +#define CG_FDO_CTRL0 0xC0300064 +#define FDO_STATIC_DUTY(x) ((x) << 0) +#define FDO_STATIC_DUTY_MASK 0x000000FF +#define FDO_STATIC_DUTY_SHIFT 0 +#define CG_FDO_CTRL1 0xC0300068 +#define FMAX_DUTY100(x) ((x) << 0) +#define FMAX_DUTY100_MASK 0x000000FF +#define FMAX_DUTY100_SHIFT 0 +#define CG_FDO_CTRL2 0xC030006C +#define TMIN(x) ((x) << 0) +#define TMIN_MASK 0x000000FF +#define TMIN_SHIFT 0 +#define FDO_PWM_MODE(x) ((x) << 11) +#define FDO_PWM_MODE_MASK (7 << 11) +#define FDO_PWM_MODE_SHIFT 11 +#define TACH_PWM_RESP_RATE(x) ((x) << 25) +#define TACH_PWM_RESP_RATE_MASK (0x7f << 25) +#define TACH_PWM_RESP_RATE_SHIFT 25 +#define CG_TACH_CTRL 0xC0300070 +# define EDGE_PER_REV(x) ((x) << 0) +# define EDGE_PER_REV_MASK (0x7 << 0) +# define EDGE_PER_REV_SHIFT 0 +# define TARGET_PERIOD(x) ((x) << 3) +# define TARGET_PERIOD_MASK 0xfffffff8 +# define TARGET_PERIOD_SHIFT 3 +#define CG_TACH_STATUS 0xC0300074 +# define TACH_PERIOD(x) ((x) << 0) +# define TACH_PERIOD_MASK 0xffffffff +# define TACH_PERIOD_SHIFT 0 + #define CG_ECLK_CNTL 0xC05000AC # define ECLK_DIVIDER_MASK 0x7f # define ECLK_DIR_CNTL_EN (1 << 8) @@ -444,6 +480,10 @@ #define SOFT_RESET_ORB (1 << 23) #define SOFT_RESET_VCE (1 << 24) +#define SRBM_READ_ERROR 0xE98 +#define SRBM_INT_CNTL 0xEA0 +#define SRBM_INT_ACK 0xEA8 + #define VM_L2_CNTL 0x1400 #define ENABLE_L2_CACHE (1 << 0) #define ENABLE_L2_FRAGMENT_PROCESSING (1 << 1) @@ -1137,6 +1177,9 @@ #define SH_MEM_ALIGNMENT_MODE_UNALIGNED 3 #define DEFAULT_MTYPE(x) ((x) << 4) #define APE1_MTYPE(x) ((x) << 7) +/* valid for both DEFAULT_MTYPE and APE1_MTYPE */ +#define MTYPE_CACHED 0 +#define MTYPE_NONCACHED 3 #define SX_DEBUG_1 0x9060 @@ -1447,6 +1490,16 @@ #define CP_HQD_ACTIVE 0xC91C #define CP_HQD_VMID 0xC920 +#define CP_HQD_PERSISTENT_STATE 0xC924u +#define DEFAULT_CP_HQD_PERSISTENT_STATE (0x33U << 8) + +#define CP_HQD_PIPE_PRIORITY 0xC928u +#define CP_HQD_QUEUE_PRIORITY 0xC92Cu +#define CP_HQD_QUANTUM 0xC930u +#define QUANTUM_EN 1U +#define QUANTUM_SCALE_1MS (1U << 4) +#define QUANTUM_DURATION(x) ((x) << 8) + #define CP_HQD_PQ_BASE 0xC934 #define CP_HQD_PQ_BASE_HI 0xC938 #define CP_HQD_PQ_RPTR 0xC93C @@ -1474,12 +1527,32 @@ #define PRIV_STATE (1 << 30) #define KMD_QUEUE (1 << 31) -#define CP_HQD_DEQUEUE_REQUEST 0xC974 +#define CP_HQD_IB_BASE_ADDR 0xC95Cu +#define CP_HQD_IB_BASE_ADDR_HI 0xC960u +#define CP_HQD_IB_RPTR 0xC964u +#define CP_HQD_IB_CONTROL 0xC968u +#define IB_ATC_EN (1U << 23) +#define DEFAULT_MIN_IB_AVAIL_SIZE (3U << 20) + +#define CP_HQD_DEQUEUE_REQUEST 0xC974 +#define DEQUEUE_REQUEST_DRAIN 1 +#define DEQUEUE_REQUEST_RESET 2 #define CP_MQD_CONTROL 0xC99C #define MQD_VMID(x) ((x) << 0) #define MQD_VMID_MASK (0xf << 0) +#define CP_HQD_SEMA_CMD 0xC97Cu +#define CP_HQD_MSG_TYPE 0xC980u +#define CP_HQD_ATOMIC0_PREOP_LO 0xC984u +#define CP_HQD_ATOMIC0_PREOP_HI 0xC988u +#define CP_HQD_ATOMIC1_PREOP_LO 0xC98Cu +#define CP_HQD_ATOMIC1_PREOP_HI 0xC990u +#define CP_HQD_HQ_SCHEDULER0 0xC994u +#define CP_HQD_HQ_SCHEDULER1 0xC998u + +#define SH_STATIC_MEM_CONFIG 0x9604u + #define DB_RENDER_CONTROL 0x28000 #define PA_SC_RASTER_CONFIG 0x28350 @@ -1995,6 +2068,7 @@ #define UVD_UDEC_DBW_ADDR_CONFIG 0xef54 #define UVD_LMI_EXT40_ADDR 0xf498 +#define UVD_GP_SCRATCH4 0xf4e0 #define UVD_LMI_ADDR_EXT 0xf594 #define UVD_VCPU_CACHE_OFFSET0 0xf608 #define UVD_VCPU_CACHE_SIZE0 0xf60c @@ -2012,6 +2086,7 @@ # define CG_DT_MASK (0xf << 2) # define CLK_OD(x) ((x) << 6) # define CLK_OD_MASK (0x1f << 6) +#define UVD_STATUS 0xf6bc /* UVD clocks */ @@ -2054,6 +2129,7 @@ #define VCE_UENC_REG_CLOCK_GATING 0x207c0 #define VCE_SYS_INT_EN 0x21300 # define VCE_SYS_INT_TRAP_INTERRUPT_EN (1 << 3) +#define VCE_LMI_VCPU_CACHE_40BIT_BAR 0x2145c #define VCE_LMI_CTRL2 0x21474 #define VCE_LMI_CTRL 0x21498 #define VCE_LMI_VM_CTRL 0x214a0 @@ -2069,4 +2145,20 @@ #define VCE_CMD_IB_AUTO 0x00000005 #define VCE_CMD_SEMAPHORE 0x00000006 +#define ATC_VMID0_PASID_MAPPING 0x339Cu +#define ATC_VMID_PASID_MAPPING_UPDATE_STATUS 0x3398u +#define ATC_VMID_PASID_MAPPING_VALID (1U << 31) + +#define ATC_VM_APERTURE0_CNTL 0x3310u +#define ATS_ACCESS_MODE_NEVER 0 +#define ATS_ACCESS_MODE_ALWAYS 1 + +#define ATC_VM_APERTURE0_CNTL2 0x3318u +#define ATC_VM_APERTURE0_HIGH_ADDR 0x3308u +#define ATC_VM_APERTURE0_LOW_ADDR 0x3300u +#define ATC_VM_APERTURE1_CNTL 0x3314u +#define ATC_VM_APERTURE1_CNTL2 0x331Cu +#define ATC_VM_APERTURE1_HIGH_ADDR 0x330Cu +#define ATC_VM_APERTURE1_LOW_ADDR 0x3304u + #endif diff --git a/sys/dev/drm/radeon/dce3_1_afmt.c b/sys/dev/drm/radeon/dce3_1_afmt.c index 2fe8cfc966..cfa3a84a2a 100644 --- a/sys/dev/drm/radeon/dce3_1_afmt.c +++ b/sys/dev/drm/radeon/dce3_1_afmt.c @@ -24,37 +24,17 @@ #include #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include "r600d.h" -static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder) +void dce3_2_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count) { struct radeon_device *rdev = encoder->dev->dev_private; - struct drm_connector *connector; - struct radeon_connector *radeon_connector = NULL; u32 tmp; - u8 *sadb = NULL; - int sad_count; - - list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) { - radeon_connector = to_radeon_connector(connector); - break; - } - } - - if (!radeon_connector) { - DRM_ERROR("Couldn't find encoder's connector\n"); - return; - } - - sad_count = drm_edid_to_speaker_allocation(radeon_connector->edid, &sadb); - if (sad_count < 0) { - DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n", sad_count); - sad_count = 0; - } /* program the speaker allocation */ - tmp = RREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER); + tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER); tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK); /* set HDMI mode */ tmp |= HDMI_CONNECTION; @@ -62,19 +42,32 @@ static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder) tmp |= SPEAKER_ALLOCATION(sadb[0]); else tmp |= SPEAKER_ALLOCATION(5); /* stereo */ - WREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp); - - kfree(sadb); + WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp); } -static void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder) +void dce3_2_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count) { struct radeon_device *rdev = encoder->dev->dev_private; - struct drm_connector *connector; - struct radeon_connector *radeon_connector = NULL; - struct cea_sad *sads; - int i, sad_count; + u32 tmp; + /* program the speaker allocation */ + tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER); + tmp &= ~(HDMI_CONNECTION | SPEAKER_ALLOCATION_MASK); + /* set DP mode */ + tmp |= DP_CONNECTION; + if (sad_count) + tmp |= SPEAKER_ALLOCATION(sadb[0]); + else + tmp |= SPEAKER_ALLOCATION(5); /* stereo */ + WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp); +} + +void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder, + struct cea_sad *sads, int sad_count) +{ + int i; + struct radeon_device *rdev = encoder->dev->dev_private; static const u16 eld_reg_to_type[][2] = { { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM }, { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 }, @@ -90,25 +83,6 @@ static void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder) { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO }, }; - list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) { - radeon_connector = to_radeon_connector(connector); - break; - } - } - - if (!radeon_connector) { - DRM_ERROR("Couldn't find encoder's connector\n"); - return; - } - - sad_count = drm_edid_to_sad(radeon_connector->edid, &sads); - if (sad_count < 0) { - DRM_ERROR("Couldn't read SADs: %d\n", sad_count); - return; - } - BUG_ON(!sads); - for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) { u32 value = 0; u8 stereo_freqs = 0; @@ -135,110 +109,124 @@ static void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder) value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs); - WREG32(eld_reg_to_type[i][0], value); + WREG32_ENDPOINT(0, eld_reg_to_type[i][0], value); } - - kfree(sads); } -/* - * update the info frames with the data from the current display mode - */ -void dce3_1_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode) +void dce3_2_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned 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; - u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE]; - struct hdmi_avi_infoframe frame; - uint32_t offset; - ssize_t err; - - if (!dig || !dig->afmt) + struct radeon_encoder *radeon_encoder; + struct radeon_encoder_atom_dig *dig; + unsigned int max_ratio = clock / 24000; + u32 dto_phase; + u32 wallclock_ratio; + u32 dto_cntl; + + if (!crtc) return; - /* Silent, r600_hdmi_enable will raise WARN for us */ - if (!dig->afmt->enabled) - return; - offset = dig->afmt->offset; - - /* disable audio prior to setting up hw */ - dig->afmt->pin = r600_audio_get_pin(rdev); - r600_audio_enable(rdev, dig->afmt->pin, 0); - - r600_audio_set_dto(encoder, mode->clock); - - WREG32(HDMI0_VBI_PACKET_CONTROL + offset, - HDMI0_NULL_SEND); /* send null packets when required */ + radeon_encoder = to_radeon_encoder(crtc->encoder); + dig = radeon_encoder->enc_priv; - WREG32(HDMI0_AUDIO_CRC_CONTROL + offset, 0x1000); + if (!dig) + return; - if (ASIC_IS_DCE32(rdev)) { - WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset, - HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */ - HDMI0_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */ - WREG32(AFMT_AUDIO_PACKET_CONTROL + offset, - AFMT_AUDIO_SAMPLE_SEND | /* send audio packets */ - AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */ + if (max_ratio >= 8) { + dto_phase = 192 * 1000; + wallclock_ratio = 3; + } else if (max_ratio >= 4) { + dto_phase = 96 * 1000; + wallclock_ratio = 2; + } else if (max_ratio >= 2) { + dto_phase = 48 * 1000; + wallclock_ratio = 1; } else { - WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset, - HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */ - HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */ - HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */ - HDMI0_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */ + dto_phase = 24 * 1000; + wallclock_ratio = 0; } - if (ASIC_IS_DCE32(rdev)) { - dce3_2_afmt_write_speaker_allocation(encoder); - dce3_2_afmt_write_sad_regs(encoder); + /* Express [24MHz / target pixel clock] as an exact rational + * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE + * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator + */ + if (dig->dig_encoder == 0) { + dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; + dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio); + WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl); + WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase); + WREG32(DCCG_AUDIO_DTO0_MODULE, clock); + WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */ + } else { + dto_cntl = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; + dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio); + WREG32(DCCG_AUDIO_DTO1_CNTL, dto_cntl); + WREG32(DCCG_AUDIO_DTO1_PHASE, dto_phase); + WREG32(DCCG_AUDIO_DTO1_MODULE, clock); + WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */ } +} - WREG32(HDMI0_ACR_PACKET_CONTROL + offset, - HDMI0_ACR_SOURCE | /* select SW CTS value - XXX verify that hw CTS works on all families */ - HDMI0_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */ - - WREG32(HDMI0_VBI_PACKET_CONTROL + offset, - HDMI0_NULL_SEND | /* send null packets when required */ - HDMI0_GC_SEND | /* send general control packets */ - HDMI0_GC_CONT); /* send general control packets every frame */ - - /* TODO: HDMI0_AUDIO_INFO_UPDATE */ - WREG32(HDMI0_INFOFRAME_CONTROL0 + offset, - HDMI0_AVI_INFO_SEND | /* enable AVI info frames */ - HDMI0_AVI_INFO_CONT | /* send AVI info frames every frame/field */ - HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */ - HDMI0_AUDIO_INFO_CONT); /* send audio info frames every frame/field */ +void dce3_2_hdmi_update_acr(struct drm_encoder *encoder, long offset, + const struct radeon_hdmi_acr *acr) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; - WREG32(HDMI0_INFOFRAME_CONTROL1 + offset, - HDMI0_AVI_INFO_LINE(2) | /* anything other than 0 */ - HDMI0_AUDIO_INFO_LINE(2)); /* anything other than 0 */ + WREG32(DCE3_HDMI0_ACR_PACKET_CONTROL + offset, + HDMI0_ACR_SOURCE | /* select SW CTS value */ + HDMI0_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */ + + WREG32_P(HDMI0_ACR_32_0 + offset, + HDMI0_ACR_CTS_32(acr->cts_32khz), + ~HDMI0_ACR_CTS_32_MASK); + WREG32_P(HDMI0_ACR_32_1 + offset, + HDMI0_ACR_N_32(acr->n_32khz), + ~HDMI0_ACR_N_32_MASK); + + WREG32_P(HDMI0_ACR_44_0 + offset, + HDMI0_ACR_CTS_44(acr->cts_44_1khz), + ~HDMI0_ACR_CTS_44_MASK); + WREG32_P(HDMI0_ACR_44_1 + offset, + HDMI0_ACR_N_44(acr->n_44_1khz), + ~HDMI0_ACR_N_44_MASK); + + WREG32_P(HDMI0_ACR_48_0 + offset, + HDMI0_ACR_CTS_48(acr->cts_48khz), + ~HDMI0_ACR_CTS_48_MASK); + WREG32_P(HDMI0_ACR_48_1 + offset, + HDMI0_ACR_N_48(acr->n_48khz), + ~HDMI0_ACR_N_48_MASK); +} - WREG32(HDMI0_GC + offset, 0); /* unset HDMI0_GC_AVMUTE */ +void dce3_2_set_audio_packet(struct drm_encoder *encoder, u32 offset) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; - err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode); - if (err < 0) { - DRM_ERROR("failed to setup AVI infoframe: %zd\n", err); - return; - } + WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset, + HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */ + HDMI0_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */ - err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer)); - if (err < 0) { - DRM_ERROR("failed to pack AVI infoframe: %zd\n", err); - return; - } + WREG32(AFMT_AUDIO_PACKET_CONTROL + offset, + AFMT_AUDIO_SAMPLE_SEND | /* send audio packets */ + AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */ - r600_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer)); - r600_hdmi_update_ACR(encoder, mode->clock); + WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset, + HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */ + HDMI0_AUDIO_INFO_CONT); /* send audio info frames every frame/field */ - /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */ - WREG32(HDMI0_RAMP_CONTROL0 + offset, 0x00FFFFFF); - WREG32(HDMI0_RAMP_CONTROL1 + offset, 0x007FFFFF); - WREG32(HDMI0_RAMP_CONTROL2 + offset, 0x00000001); - WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001); + WREG32_OR(HDMI0_INFOFRAME_CONTROL1 + offset, + HDMI0_AUDIO_INFO_LINE(2)); /* anything other than 0 */ +} - r600_hdmi_audio_workaround(encoder); +void dce3_2_set_mute(struct drm_encoder *encoder, u32 offset, bool mute) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; - /* enable audio after to setting up hw */ - r600_audio_enable(rdev, dig->afmt->pin, 0xf); + if (mute) + WREG32_OR(HDMI0_GC + offset, HDMI0_GC_AVMUTE); + else + WREG32_AND(HDMI0_GC + offset, ~HDMI0_GC_AVMUTE); } diff --git a/sys/dev/drm/radeon/dce6_afmt.c b/sys/dev/drm/radeon/dce6_afmt.c index 1a51f7f306..be5360064a 100644 --- a/sys/dev/drm/radeon/dce6_afmt.c +++ b/sys/dev/drm/radeon/dce6_afmt.c @@ -24,38 +24,41 @@ #include #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include "sid.h" -static u32 dce6_endpoint_rreg(struct radeon_device *rdev, +#define DCE8_DCCG_AUDIO_DTO1_PHASE 0x05b8 +#define DCE8_DCCG_AUDIO_DTO1_MODULE 0x05bc + +u32 dce6_endpoint_rreg(struct radeon_device *rdev, u32 block_offset, u32 reg) { + unsigned long flags; u32 r; - spin_lock(&rdev->end_idx_lock); + spin_lock_irqsave(&rdev->end_idx_lock, flags); WREG32(AZ_F0_CODEC_ENDPOINT_INDEX + block_offset, reg); r = RREG32(AZ_F0_CODEC_ENDPOINT_DATA + block_offset); - spin_unlock(&rdev->end_idx_lock); + spin_unlock_irqrestore(&rdev->end_idx_lock, flags); return r; } -static void dce6_endpoint_wreg(struct radeon_device *rdev, +void dce6_endpoint_wreg(struct radeon_device *rdev, u32 block_offset, u32 reg, u32 v) { - spin_lock(&rdev->end_idx_lock); + unsigned long flags; + + spin_lock_irqsave(&rdev->end_idx_lock, flags); if (ASIC_IS_DCE8(rdev)) WREG32(AZ_F0_CODEC_ENDPOINT_INDEX + block_offset, reg); else WREG32(AZ_F0_CODEC_ENDPOINT_INDEX + block_offset, AZ_ENDPOINT_REG_WRITE_EN | AZ_ENDPOINT_REG_INDEX(reg)); WREG32(AZ_F0_CODEC_ENDPOINT_DATA + block_offset, v); - spin_unlock(&rdev->end_idx_lock); + spin_unlock_irqrestore(&rdev->end_idx_lock, flags); } -#define RREG32_ENDPOINT(block, reg) dce6_endpoint_rreg(rdev, (block), (reg)) -#define WREG32_ENDPOINT(block, reg, v) dce6_endpoint_wreg(rdev, (block), (reg), (v)) - - static void dce6_afmt_get_connected_pins(struct radeon_device *rdev) { int i; @@ -74,16 +77,35 @@ static void dce6_afmt_get_connected_pins(struct radeon_device *rdev) struct r600_audio_pin *dce6_audio_get_pin(struct radeon_device *rdev) { - int i; + struct drm_encoder *encoder; + struct radeon_encoder *radeon_encoder; + struct radeon_encoder_atom_dig *dig; + struct r600_audio_pin *pin = NULL; + int i, pin_count; dce6_afmt_get_connected_pins(rdev); for (i = 0; i < rdev->audio.num_pins; i++) { - if (rdev->audio.pin[i].connected) - return &rdev->audio.pin[i]; + if (rdev->audio.pin[i].connected) { + pin = &rdev->audio.pin[i]; + pin_count = 0; + + list_for_each_entry(encoder, &rdev->ddev->mode_config.encoder_list, head) { + if (radeon_encoder_is_digital(encoder)) { + radeon_encoder = to_radeon_encoder(encoder); + dig = radeon_encoder->enc_priv; + if (dig->pin == pin) + pin_count++; + } + } + + if (pin_count == 0) + return pin; + } } - DRM_ERROR("No connected audio pins found!\n"); - return NULL; + if (!pin) + DRM_ERROR("No connected audio pins found!\n"); + return pin; } void dce6_afmt_select_pin(struct drm_encoder *encoder) @@ -91,44 +113,26 @@ void dce6_afmt_select_pin(struct drm_encoder *encoder) struct radeon_device *rdev = encoder->dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - u32 offset; - if (!dig || !dig->afmt || !dig->afmt->pin) + if (!dig || !dig->afmt || !dig->pin) return; - offset = dig->afmt->offset; - - WREG32(AFMT_AUDIO_SRC_CONTROL + offset, - AFMT_AUDIO_SRC_SELECT(dig->afmt->pin->id)); + WREG32(AFMT_AUDIO_SRC_CONTROL + dig->afmt->offset, + AFMT_AUDIO_SRC_SELECT(dig->pin->id)); } void dce6_afmt_write_latency_fields(struct drm_encoder *encoder, + struct drm_connector *connector, struct drm_display_mode *mode) { struct radeon_device *rdev = encoder->dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - struct drm_connector *connector; - struct radeon_connector *radeon_connector = NULL; - u32 tmp = 0, offset; + u32 tmp = 0; - if (!dig || !dig->afmt || !dig->afmt->pin) + if (!dig || !dig->afmt || !dig->pin) return; - offset = dig->afmt->pin->offset; - - list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) { - radeon_connector = to_radeon_connector(connector); - break; - } - } - - if (!radeon_connector) { - DRM_ERROR("Couldn't find encoder's connector\n"); - return; - } - if (mode->flags & DRM_MODE_FLAG_INTERLACE) { if (connector->latency_present[1]) tmp = VIDEO_LIPSYNC(connector->video_latency[1]) | @@ -142,45 +146,24 @@ void dce6_afmt_write_latency_fields(struct drm_encoder *encoder, else tmp = VIDEO_LIPSYNC(0) | AUDIO_LIPSYNC(0); } - WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp); + WREG32_ENDPOINT(dig->pin->offset, + AZ_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp); } -void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder) +void dce6_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count) { struct radeon_device *rdev = encoder->dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - struct drm_connector *connector; - struct radeon_connector *radeon_connector = NULL; - u32 offset, tmp; - u8 *sadb = NULL; - int sad_count; + u32 tmp; - if (!dig || !dig->afmt || !dig->afmt->pin) + if (!dig || !dig->afmt || !dig->pin) return; - offset = dig->afmt->pin->offset; - - list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) { - radeon_connector = to_radeon_connector(connector); - break; - } - } - - if (!radeon_connector) { - DRM_ERROR("Couldn't find encoder's connector\n"); - return; - } - - sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector), &sadb); - if (sad_count < 0) { - DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n", sad_count); - sad_count = 0; - } - /* program the speaker allocation */ - tmp = RREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER); + tmp = RREG32_ENDPOINT(dig->pin->offset, + AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER); tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK); /* set HDMI mode */ tmp |= HDMI_CONNECTION; @@ -188,22 +171,42 @@ void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder) tmp |= SPEAKER_ALLOCATION(sadb[0]); else tmp |= SPEAKER_ALLOCATION(5); /* stereo */ - WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp); - - kfree(sadb); + WREG32_ENDPOINT(dig->pin->offset, + AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp); } -void dce6_afmt_write_sad_regs(struct drm_encoder *encoder) +void dce6_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count) { struct radeon_device *rdev = encoder->dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - u32 offset; - struct drm_connector *connector; - struct radeon_connector *radeon_connector = NULL; - struct cea_sad *sads; - int i, sad_count; + u32 tmp; + + if (!dig || !dig->afmt || !dig->pin) + return; + /* program the speaker allocation */ + tmp = RREG32_ENDPOINT(dig->pin->offset, + AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER); + tmp &= ~(HDMI_CONNECTION | SPEAKER_ALLOCATION_MASK); + /* set DP mode */ + tmp |= DP_CONNECTION; + if (sad_count) + tmp |= SPEAKER_ALLOCATION(sadb[0]); + else + tmp |= SPEAKER_ALLOCATION(5); /* stereo */ + WREG32_ENDPOINT(dig->pin->offset, + AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp); +} + +void dce6_afmt_write_sad_regs(struct drm_encoder *encoder, + struct cea_sad *sads, int sad_count) +{ + int i; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + struct radeon_device *rdev = encoder->dev->dev_private; static const u16 eld_reg_to_type[][2] = { { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM }, { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 }, @@ -219,30 +222,9 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder) { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO }, }; - if (!dig || !dig->afmt || !dig->afmt->pin) + if (!dig || !dig->afmt || !dig->pin) return; - offset = dig->afmt->pin->offset; - - list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) { - radeon_connector = to_radeon_connector(connector); - break; - } - } - - if (!radeon_connector) { - DRM_ERROR("Couldn't find encoder's connector\n"); - return; - } - - sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads); - if (sad_count <= 0) { - DRM_ERROR("Couldn't read SADs: %d\n", sad_count); - return; - } - BUG_ON(!sads); - for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) { u32 value = 0; u8 stereo_freqs = 0; @@ -269,15 +251,8 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder) value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs); - WREG32_ENDPOINT(offset, eld_reg_to_type[i][0], value); + WREG32_ENDPOINT(dig->pin->offset, eld_reg_to_type[i][0], value); } - - kfree(sads); -} - -static int dce6_audio_chipset_supported(struct radeon_device *rdev) -{ - return !ASIC_IS_NODCE(rdev); } void dce6_audio_enable(struct radeon_device *rdev, @@ -291,64 +266,54 @@ void dce6_audio_enable(struct radeon_device *rdev, enable_mask ? AUDIO_ENABLED : 0); } -static const u32 pin_offsets[7] = -{ - (0x5e00 - 0x5e00), - (0x5e18 - 0x5e00), - (0x5e30 - 0x5e00), - (0x5e48 - 0x5e00), - (0x5e60 - 0x5e00), - (0x5e78 - 0x5e00), - (0x5e90 - 0x5e00), -}; - -int dce6_audio_init(struct radeon_device *rdev) +void dce6_hdmi_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock) { - int i; - - if (!radeon_audio || !dce6_audio_chipset_supported(rdev)) - return 0; + /* Two dtos; generally use dto0 for HDMI */ + u32 value = 0; - rdev->audio.enabled = true; + if (crtc) + value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id); - if (ASIC_IS_DCE81(rdev)) /* KV: 4 streams, 7 endpoints */ - rdev->audio.num_pins = 7; - else if (ASIC_IS_DCE83(rdev)) /* KB: 2 streams, 3 endpoints */ - rdev->audio.num_pins = 3; - else if (ASIC_IS_DCE8(rdev)) /* BN/HW: 6 streams, 7 endpoints */ - rdev->audio.num_pins = 7; - else if (ASIC_IS_DCE61(rdev)) /* TN: 4 streams, 6 endpoints */ - rdev->audio.num_pins = 6; - else if (ASIC_IS_DCE64(rdev)) /* OL: 2 streams, 2 endpoints */ - rdev->audio.num_pins = 2; - else /* SI: 6 streams, 6 endpoints */ - rdev->audio.num_pins = 6; + WREG32(DCCG_AUDIO_DTO_SOURCE, value); - for (i = 0; i < rdev->audio.num_pins; i++) { - rdev->audio.pin[i].channels = -1; - rdev->audio.pin[i].rate = -1; - rdev->audio.pin[i].bits_per_sample = -1; - rdev->audio.pin[i].status_bits = 0; - rdev->audio.pin[i].category_code = 0; - rdev->audio.pin[i].connected = false; - rdev->audio.pin[i].offset = pin_offsets[i]; - rdev->audio.pin[i].id = i; - /* disable audio. it will be set up later */ - dce6_audio_enable(rdev, &rdev->audio.pin[i], false); - } - - return 0; + /* Express [24MHz / target pixel clock] as an exact rational + * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE + * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator + */ + WREG32(DCCG_AUDIO_DTO0_PHASE, 24000); + WREG32(DCCG_AUDIO_DTO0_MODULE, clock); } -void dce6_audio_fini(struct radeon_device *rdev) +void dce6_dp_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock) { - int i; - - if (!rdev->audio.enabled) - return; - - for (i = 0; i < rdev->audio.num_pins; i++) - dce6_audio_enable(rdev, &rdev->audio.pin[i], false); - - rdev->audio.enabled = false; + /* Two dtos; generally use dto1 for DP */ + u32 value = 0; + value |= DCCG_AUDIO_DTO_SEL; + + if (crtc) + value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id); + + WREG32(DCCG_AUDIO_DTO_SOURCE, value); + + /* Express [24MHz / target pixel clock] as an exact rational + * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE + * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator + */ + if (ASIC_IS_DCE8(rdev)) { + unsigned int div = (RREG32(DENTIST_DISPCLK_CNTL) & + DENTIST_DPREFCLK_WDIVIDER_MASK) >> + DENTIST_DPREFCLK_WDIVIDER_SHIFT; + div = radeon_audio_decode_dfs_div(div); + + if (div) + clock = clock * 100 / div; + + WREG32(DCE8_DCCG_AUDIO_DTO1_PHASE, 24000); + WREG32(DCE8_DCCG_AUDIO_DTO1_MODULE, clock); + } else { + WREG32(DCCG_AUDIO_DTO1_PHASE, 24000); + WREG32(DCCG_AUDIO_DTO1_MODULE, clock); + } } diff --git a/sys/dev/drm/radeon/evergreen.c b/sys/dev/drm/radeon/evergreen.c index 298cc6a451..b13b7d00f1 100644 --- a/sys/dev/drm/radeon/evergreen.c +++ b/sys/dev/drm/radeon/evergreen.c @@ -25,6 +25,7 @@ #include #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include #include "evergreend.h" #include "atom.h" @@ -33,6 +34,75 @@ #include "evergreen_blit_shaders.h" #include "radeon_ucode.h" +/* + * Indirect registers accessor + */ +u32 eg_cg_rreg(struct radeon_device *rdev, u32 reg) +{ + unsigned long flags; + u32 r; + + spin_lock_irqsave(&rdev->cg_idx_lock, flags); + WREG32(EVERGREEN_CG_IND_ADDR, ((reg) & 0xffff)); + r = RREG32(EVERGREEN_CG_IND_DATA); + spin_unlock_irqrestore(&rdev->cg_idx_lock, flags); + return r; +} + +void eg_cg_wreg(struct radeon_device *rdev, u32 reg, u32 v) +{ + unsigned long flags; + + spin_lock_irqsave(&rdev->cg_idx_lock, flags); + WREG32(EVERGREEN_CG_IND_ADDR, ((reg) & 0xffff)); + WREG32(EVERGREEN_CG_IND_DATA, (v)); + spin_unlock_irqrestore(&rdev->cg_idx_lock, flags); +} + +u32 eg_pif_phy0_rreg(struct radeon_device *rdev, u32 reg) +{ + unsigned long flags; + u32 r; + + spin_lock_irqsave(&rdev->pif_idx_lock, flags); + WREG32(EVERGREEN_PIF_PHY0_INDEX, ((reg) & 0xffff)); + r = RREG32(EVERGREEN_PIF_PHY0_DATA); + spin_unlock_irqrestore(&rdev->pif_idx_lock, flags); + return r; +} + +void eg_pif_phy0_wreg(struct radeon_device *rdev, u32 reg, u32 v) +{ + unsigned long flags; + + spin_lock_irqsave(&rdev->pif_idx_lock, flags); + WREG32(EVERGREEN_PIF_PHY0_INDEX, ((reg) & 0xffff)); + WREG32(EVERGREEN_PIF_PHY0_DATA, (v)); + spin_unlock_irqrestore(&rdev->pif_idx_lock, flags); +} + +u32 eg_pif_phy1_rreg(struct radeon_device *rdev, u32 reg) +{ + unsigned long flags; + u32 r; + + spin_lock_irqsave(&rdev->pif_idx_lock, flags); + WREG32(EVERGREEN_PIF_PHY1_INDEX, ((reg) & 0xffff)); + r = RREG32(EVERGREEN_PIF_PHY1_DATA); + spin_unlock_irqrestore(&rdev->pif_idx_lock, flags); + return r; +} + +void eg_pif_phy1_wreg(struct radeon_device *rdev, u32 reg, u32 v) +{ + unsigned long flags; + + spin_lock_irqsave(&rdev->pif_idx_lock, flags); + WREG32(EVERGREEN_PIF_PHY1_INDEX, ((reg) & 0xffff)); + WREG32(EVERGREEN_PIF_PHY1_DATA, (v)); + spin_unlock_irqrestore(&rdev->pif_idx_lock, flags); +} + static const u32 crtc_offsets[6] = { EVERGREEN_CRTC0_REGISTER_OFFSET, @@ -990,6 +1060,34 @@ static void evergreen_init_golden_registers(struct radeon_device *rdev) } } +/** + * evergreen_get_allowed_info_register - fetch the register for the info ioctl + * + * @rdev: radeon_device pointer + * @reg: register offset in bytes + * @val: register value + * + * Returns 0 for success or -EINVAL for an invalid register + * + */ +int evergreen_get_allowed_info_register(struct radeon_device *rdev, + u32 reg, u32 *val) +{ + switch (reg) { + case GRBM_STATUS: + case GRBM_STATUS_SE0: + case GRBM_STATUS_SE1: + case SRBM_STATUS: + case SRBM_STATUS2: + case DMA_STATUS_REG: + case UVD_STATUS: + *val = RREG32(reg); + return 0; + default: + return -EINVAL; + } +} + void evergreen_tiling_fields(unsigned tiling_flags, unsigned *bankw, unsigned *bankh, unsigned *mtaspect, unsigned *tile_split) @@ -1291,44 +1389,23 @@ void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc) * @crtc_id: crtc to cleanup pageflip on * @crtc_base: new address of the crtc (GPU MC address) * - * Does the actual pageflip (evergreen+). - * During vblank we take the crtc lock and wait for the update_pending - * bit to go high, when it does, we release the lock, and allow the - * double buffered update to take place. - * Returns the current update pending status. + * Triggers the actual pageflip by updating the primary + * surface base address (evergreen+). */ -void evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) +void evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base, + bool async) { struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; - u32 tmp = RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset); - int i; - - /* Lock the graphics update lock */ - tmp |= EVERGREEN_GRPH_UPDATE_LOCK; - WREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); /* update the scanout addresses */ - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, - upper_32_bits(crtc_base)); - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, - (u32)crtc_base); - + WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, + async ? EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN : 0); WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, upper_32_bits(crtc_base)); WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, (u32)crtc_base); - - /* Wait for update_pending to go high. */ - for (i = 0; i < rdev->usec_timeout; i++) { - if (RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset) & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING) - break; - udelay(1); - } - DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); - - /* Unlock the lock, so double-buffering can take place inside vblank */ - tmp &= ~EVERGREEN_GRPH_UPDATE_LOCK; - WREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); + /* post the write */ + RREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset); } /** @@ -1775,7 +1852,8 @@ void evergreen_hpd_init(struct radeon_device *rdev) break; } radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); - enabled |= 1 << radeon_connector->hpd.hpd; + if (radeon_connector->hpd.hpd != RADEON_HPD_NONE) + enabled |= 1 << radeon_connector->hpd.hpd; } radeon_irq_kms_enable_hpd(rdev, enabled); } @@ -1818,7 +1896,8 @@ void evergreen_hpd_fini(struct radeon_device *rdev) default: break; } - disabled |= 1 << radeon_connector->hpd.hpd; + if (radeon_connector->hpd.hpd != RADEON_HPD_NONE) + disabled |= 1 << radeon_connector->hpd.hpd; } radeon_irq_kms_disable_hpd(rdev, disabled); } @@ -2283,6 +2362,9 @@ static void evergreen_program_watermarks(struct radeon_device *rdev, c.full = dfixed_div(c, a); priority_b_mark = dfixed_trunc(c); priority_b_cnt |= priority_b_mark & PRIORITY_MARK_MASK; + + /* Save number of lines the linebuffer leads before the scanout */ + radeon_crtc->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay); } /* select wm A */ @@ -2516,10 +2598,152 @@ static void evergreen_agp_enable(struct radeon_device *rdev) WREG32(VM_CONTEXT1_CNTL, 0); } +static const unsigned ni_dig_offsets[] = +{ + NI_DIG0_REGISTER_OFFSET, + NI_DIG1_REGISTER_OFFSET, + NI_DIG2_REGISTER_OFFSET, + NI_DIG3_REGISTER_OFFSET, + NI_DIG4_REGISTER_OFFSET, + NI_DIG5_REGISTER_OFFSET +}; + +static const unsigned ni_tx_offsets[] = +{ + NI_DCIO_UNIPHY0_UNIPHY_TX_CONTROL1, + NI_DCIO_UNIPHY1_UNIPHY_TX_CONTROL1, + NI_DCIO_UNIPHY2_UNIPHY_TX_CONTROL1, + NI_DCIO_UNIPHY3_UNIPHY_TX_CONTROL1, + NI_DCIO_UNIPHY4_UNIPHY_TX_CONTROL1, + NI_DCIO_UNIPHY5_UNIPHY_TX_CONTROL1 +}; + +static const unsigned evergreen_dp_offsets[] = +{ + EVERGREEN_DP0_REGISTER_OFFSET, + EVERGREEN_DP1_REGISTER_OFFSET, + EVERGREEN_DP2_REGISTER_OFFSET, + EVERGREEN_DP3_REGISTER_OFFSET, + EVERGREEN_DP4_REGISTER_OFFSET, + EVERGREEN_DP5_REGISTER_OFFSET +}; + + +/* + * Assumption is that EVERGREEN_CRTC_MASTER_EN enable for requested crtc + * We go from crtc to connector and it is not relible since it + * should be an opposite direction .If crtc is enable then + * find the dig_fe which selects this crtc and insure that it enable. + * if such dig_fe is found then find dig_be which selects found dig_be and + * insure that it enable and in DP_SST mode. + * if UNIPHY_PLL_CONTROL1.enable then we should disconnect timing + * from dp symbols clocks . + */ +static bool evergreen_is_dp_sst_stream_enabled(struct radeon_device *rdev, + unsigned crtc_id, unsigned *ret_dig_fe) +{ + unsigned i; + unsigned dig_fe; + unsigned dig_be; + unsigned dig_en_be; + unsigned uniphy_pll; + unsigned digs_fe_selected; + unsigned dig_be_mode; + unsigned dig_fe_mask; + bool is_enabled = false; + bool found_crtc = false; + + /* loop through all running dig_fe to find selected crtc */ + for (i = 0; i < ARRAY_SIZE(ni_dig_offsets); i++) { + dig_fe = RREG32(NI_DIG_FE_CNTL + ni_dig_offsets[i]); + if (dig_fe & NI_DIG_FE_CNTL_SYMCLK_FE_ON && + crtc_id == NI_DIG_FE_CNTL_SOURCE_SELECT(dig_fe)) { + /* found running pipe */ + found_crtc = true; + dig_fe_mask = 1 << i; + dig_fe = i; + break; + } + } + + if (found_crtc) { + /* loop through all running dig_be to find selected dig_fe */ + for (i = 0; i < ARRAY_SIZE(ni_dig_offsets); i++) { + dig_be = RREG32(NI_DIG_BE_CNTL + ni_dig_offsets[i]); + /* if dig_fe_selected by dig_be? */ + digs_fe_selected = NI_DIG_BE_CNTL_FE_SOURCE_SELECT(dig_be); + dig_be_mode = NI_DIG_FE_CNTL_MODE(dig_be); + if (dig_fe_mask & digs_fe_selected && + /* if dig_be in sst mode? */ + dig_be_mode == NI_DIG_BE_DPSST) { + dig_en_be = RREG32(NI_DIG_BE_EN_CNTL + + ni_dig_offsets[i]); + uniphy_pll = RREG32(NI_DCIO_UNIPHY0_PLL_CONTROL1 + + ni_tx_offsets[i]); + /* dig_be enable and tx is running */ + if (dig_en_be & NI_DIG_BE_EN_CNTL_ENABLE && + dig_en_be & NI_DIG_BE_EN_CNTL_SYMBCLK_ON && + uniphy_pll & NI_DCIO_UNIPHY0_PLL_CONTROL1_ENABLE) { + is_enabled = true; + *ret_dig_fe = dig_fe; + break; + } + } + } + } + + return is_enabled; +} + +/* + * Blank dig when in dp sst mode + * Dig ignores crtc timing + */ +static void evergreen_blank_dp_output(struct radeon_device *rdev, + unsigned dig_fe) +{ + unsigned stream_ctrl; + unsigned fifo_ctrl; + unsigned counter = 0; + + if (dig_fe >= ARRAY_SIZE(evergreen_dp_offsets)) { + DRM_ERROR("invalid dig_fe %d\n", dig_fe); + return; + } + + stream_ctrl = RREG32(EVERGREEN_DP_VID_STREAM_CNTL + + evergreen_dp_offsets[dig_fe]); + if (!(stream_ctrl & EVERGREEN_DP_VID_STREAM_CNTL_ENABLE)) { + DRM_ERROR("dig %d , should be enable\n", dig_fe); + return; + } + + stream_ctrl &=~EVERGREEN_DP_VID_STREAM_CNTL_ENABLE; + WREG32(EVERGREEN_DP_VID_STREAM_CNTL + + evergreen_dp_offsets[dig_fe], stream_ctrl); + + stream_ctrl = RREG32(EVERGREEN_DP_VID_STREAM_CNTL + + evergreen_dp_offsets[dig_fe]); + while (counter < 32 && stream_ctrl & EVERGREEN_DP_VID_STREAM_STATUS) { + msleep(1); + counter++; + stream_ctrl = RREG32(EVERGREEN_DP_VID_STREAM_CNTL + + evergreen_dp_offsets[dig_fe]); + } + if (counter >= 32 ) + DRM_ERROR("counter exceeds %d\n", counter); + + fifo_ctrl = RREG32(EVERGREEN_DP_STEER_FIFO + evergreen_dp_offsets[dig_fe]); + fifo_ctrl |= EVERGREEN_DP_STEER_FIFO_RESET; + WREG32(EVERGREEN_DP_STEER_FIFO + evergreen_dp_offsets[dig_fe], fifo_ctrl); + +} + void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save) { u32 crtc_enabled, tmp, frame_count, blackout; int i, j; + unsigned dig_fe; bzero(save, sizeof(*save)); /* avoid gcc warning */ if (!ASIC_IS_NODCE(rdev)) { @@ -2560,7 +2784,17 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav break; udelay(1); } - + /*we should disable dig if it drives dp sst*/ + /*but we are in radeon_device_init and the topology is unknown*/ + /*and it is available after radeon_modeset_init*/ + /*the following method radeon_atom_encoder_dpms_dig*/ + /*does the job if we initialize it properly*/ + /*for now we do it this manually*/ + /**/ + if (ASIC_IS_DCE5(rdev) && + evergreen_is_dp_sst_stream_enabled(rdev, i ,&dig_fe)) + evergreen_blank_dp_output(rdev, dig_fe); + /*we could remove 6 lines below*/ /* XXX this is a hack to avoid strange behavior with EFI on certain systems */ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]); @@ -3238,6 +3472,8 @@ static void evergreen_gpu_init(struct radeon_device *rdev) } WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff)); + WREG32(SRBM_INT_CNTL, 0x1); + WREG32(SRBM_INT_ACK, 0x1); evergreen_fix_pci_max_read_req_size(rdev); @@ -3891,10 +4127,15 @@ void evergreen_gpu_pci_config_reset(struct radeon_device *rdev) } } -int evergreen_asic_reset(struct radeon_device *rdev) +int evergreen_asic_reset(struct radeon_device *rdev, bool hard) { u32 reset_mask; + if (hard) { + evergreen_gpu_pci_config_reset(rdev); + return 0; + } + reset_mask = evergreen_gpu_check_soft_reset(rdev); if (reset_mask) @@ -4314,6 +4555,7 @@ void evergreen_disable_interrupt_state(struct radeon_device *rdev) tmp = RREG32(DMA_CNTL) & ~TRAP_ENABLE; WREG32(DMA_CNTL, tmp); WREG32(GRBM_INT_CNTL, 0); + WREG32(SRBM_INT_CNTL, 0); WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); if (rdev->num_crtc >= 4) { @@ -4379,12 +4621,12 @@ int evergreen_irq_set(struct radeon_device *rdev) return 0; } - hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN; - hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN; - hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN; - hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN; - hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN; - hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN; + hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN); + hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN); + hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN); + hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN); + hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN); + hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN); if (rdev->family == CHIP_ARUBA) thermal_int = RREG32(TN_CG_THERMAL_INT_CTRL) & ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW); @@ -4473,27 +4715,27 @@ int evergreen_irq_set(struct radeon_device *rdev) } if (rdev->irq.hpd[0]) { DRM_DEBUG("evergreen_irq_set: hpd 1\n"); - hpd1 |= DC_HPDx_INT_EN; + hpd1 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN; } if (rdev->irq.hpd[1]) { DRM_DEBUG("evergreen_irq_set: hpd 2\n"); - hpd2 |= DC_HPDx_INT_EN; + hpd2 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN; } if (rdev->irq.hpd[2]) { DRM_DEBUG("evergreen_irq_set: hpd 3\n"); - hpd3 |= DC_HPDx_INT_EN; + hpd3 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN; } if (rdev->irq.hpd[3]) { DRM_DEBUG("evergreen_irq_set: hpd 4\n"); - hpd4 |= DC_HPDx_INT_EN; + hpd4 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN; } if (rdev->irq.hpd[4]) { DRM_DEBUG("evergreen_irq_set: hpd 5\n"); - hpd5 |= DC_HPDx_INT_EN; + hpd5 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN; } if (rdev->irq.hpd[5]) { DRM_DEBUG("evergreen_irq_set: hpd 6\n"); - hpd6 |= DC_HPDx_INT_EN; + hpd6 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN; } if (rdev->irq.afmt[0]) { DRM_DEBUG("evergreen_irq_set: hdmi 0\n"); @@ -4580,6 +4822,9 @@ int evergreen_irq_set(struct radeon_device *rdev) WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, afmt5); WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, afmt6); + /* posting read */ + RREG32(SRBM_STATUS); + return 0; } @@ -4684,6 +4929,38 @@ static void evergreen_irq_ack(struct radeon_device *rdev) tmp |= DC_HPDx_INT_ACK; WREG32(DC_HPD6_INT_CONTROL, tmp); } + + if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) { + tmp = RREG32(DC_HPD1_INT_CONTROL); + tmp |= DC_HPDx_RX_INT_ACK; + WREG32(DC_HPD1_INT_CONTROL, tmp); + } + if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) { + tmp = RREG32(DC_HPD2_INT_CONTROL); + tmp |= DC_HPDx_RX_INT_ACK; + WREG32(DC_HPD2_INT_CONTROL, tmp); + } + if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) { + tmp = RREG32(DC_HPD3_INT_CONTROL); + tmp |= DC_HPDx_RX_INT_ACK; + WREG32(DC_HPD3_INT_CONTROL, tmp); + } + if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) { + tmp = RREG32(DC_HPD4_INT_CONTROL); + tmp |= DC_HPDx_RX_INT_ACK; + WREG32(DC_HPD4_INT_CONTROL, tmp); + } + if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) { + tmp = RREG32(DC_HPD5_INT_CONTROL); + tmp |= DC_HPDx_RX_INT_ACK; + WREG32(DC_HPD5_INT_CONTROL, tmp); + } + if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) { + tmp = RREG32(DC_HPD5_INT_CONTROL); + tmp |= DC_HPDx_RX_INT_ACK; + WREG32(DC_HPD6_INT_CONTROL, tmp); + } + if (rdev->irq.stat_regs.evergreen.afmt_status1 & AFMT_AZ_FORMAT_WTRIG) { tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET); tmp |= AFMT_AZ_FORMAT_WTRIG_ACK; @@ -4764,6 +5041,7 @@ irqreturn_t evergreen_irq_process(struct radeon_device *rdev) u32 ring_index; bool queue_hotplug = false; bool queue_hdmi = false; + bool queue_dp = false; bool queue_thermal = false; u32 status, addr; @@ -4778,7 +5056,7 @@ restart_ih: return IRQ_NONE; rptr = rdev->ih.rptr; - DRM_DEBUG_VBLANK("evergreen_irq_process start: rptr %d, wptr %d\n", rptr, wptr); + DRM_DEBUG("evergreen_irq_process start: rptr %d, wptr %d\n", rptr, wptr); /* Order reading of wptr vs. reading of IH ring data */ rmb(); @@ -4796,23 +5074,27 @@ restart_ih: case 1: /* D1 vblank/vline */ switch (src_data) { case 0: /* D1 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[0]) { - drm_handle_vblank(rdev->ddev, 0); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[0])) - radeon_crtc_handle_vblank(rdev, 0); - rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D1 vblank\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D1 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[0]) { + drm_handle_vblank(rdev->ddev, 0); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (atomic_read(&rdev->irq.pflip[0])) + radeon_crtc_handle_vblank(rdev, 0); + rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D1 vblank\n"); + break; case 1: /* D1 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D1 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D1 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT; + DRM_DEBUG("IH: D1 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -4822,23 +5104,27 @@ restart_ih: case 2: /* D2 vblank/vline */ switch (src_data) { case 0: /* D2 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[1]) { - drm_handle_vblank(rdev->ddev, 1); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[1])) - radeon_crtc_handle_vblank(rdev, 1); - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D2 vblank\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D2 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[1]) { + drm_handle_vblank(rdev->ddev, 1); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (atomic_read(&rdev->irq.pflip[1])) + radeon_crtc_handle_vblank(rdev, 1); + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D2 vblank\n"); + break; case 1: /* D2 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D2 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D2 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; + DRM_DEBUG("IH: D2 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -4848,23 +5134,27 @@ restart_ih: case 3: /* D3 vblank/vline */ switch (src_data) { case 0: /* D3 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[2]) { - drm_handle_vblank(rdev->ddev, 2); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[2])) - radeon_crtc_handle_vblank(rdev, 2); - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D3 vblank\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D3 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[2]) { + drm_handle_vblank(rdev->ddev, 2); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (atomic_read(&rdev->irq.pflip[2])) + radeon_crtc_handle_vblank(rdev, 2); + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D3 vblank\n"); + break; case 1: /* D3 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D3 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D3 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; + DRM_DEBUG("IH: D3 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -4874,23 +5164,27 @@ restart_ih: case 4: /* D4 vblank/vline */ switch (src_data) { case 0: /* D4 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[3]) { - drm_handle_vblank(rdev->ddev, 3); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[3])) - radeon_crtc_handle_vblank(rdev, 3); - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D4 vblank\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D4 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[3]) { + drm_handle_vblank(rdev->ddev, 3); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (atomic_read(&rdev->irq.pflip[3])) + radeon_crtc_handle_vblank(rdev, 3); + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D4 vblank\n"); + break; case 1: /* D4 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D4 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D4 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; + DRM_DEBUG("IH: D4 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -4900,23 +5194,27 @@ restart_ih: case 5: /* D5 vblank/vline */ switch (src_data) { case 0: /* D5 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[4]) { - drm_handle_vblank(rdev->ddev, 4); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[4])) - radeon_crtc_handle_vblank(rdev, 4); - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D5 vblank\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D5 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[4]) { + drm_handle_vblank(rdev->ddev, 4); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (atomic_read(&rdev->irq.pflip[4])) + radeon_crtc_handle_vblank(rdev, 4); + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D5 vblank\n"); + break; case 1: /* D5 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D5 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D5 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; + DRM_DEBUG("IH: D5 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -4926,23 +5224,27 @@ restart_ih: case 6: /* D6 vblank/vline */ switch (src_data) { case 0: /* D6 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[5]) { - drm_handle_vblank(rdev->ddev, 5); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[5])) - radeon_crtc_handle_vblank(rdev, 5); - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D6 vblank\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D6 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[5]) { + drm_handle_vblank(rdev->ddev, 5); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (atomic_read(&rdev->irq.pflip[5])) + radeon_crtc_handle_vblank(rdev, 5); + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D6 vblank\n"); + break; case 1: /* D6 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D6 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D6 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; + DRM_DEBUG("IH: D6 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -4955,53 +5257,107 @@ restart_ih: case 14: /* D4 page flip */ case 16: /* D5 page flip */ case 18: /* D6 page flip */ - DRM_DEBUG_VBLANK("IH: D%d flip\n", ((src_id - 8) >> 1) + 1); + DRM_DEBUG("IH: D%d flip\n", ((src_id - 8) >> 1) + 1); if (radeon_use_pflipirq > 0) radeon_crtc_handle_flip(rdev, (src_id - 8) >> 1); break; case 42: /* HPD hotplug */ switch (src_data) { case 0: - if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD1\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD1\n"); break; case 1: - if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD2\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD2\n"); break; case 2: - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD3\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD3\n"); break; case 3: - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD4\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD4\n"); break; case 4: - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD5\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD5\n"); break; case 5: - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD6\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD6\n"); + break; + case 6: + if (!(rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 1\n"); + break; + case 7: + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 2\n"); + break; + case 8: + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 3\n"); + break; + case 9: + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 4\n"); + break; + case 10: + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 5\n"); + break; + case 11: + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 6\n"); break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -5011,51 +5367,61 @@ restart_ih: case 44: /* hdmi */ switch (src_data) { case 0: - if (rdev->irq.stat_regs.evergreen.afmt_status1 & AFMT_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.evergreen.afmt_status1 &= ~AFMT_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI0\n"); - } + if (!(rdev->irq.stat_regs.evergreen.afmt_status1 & AFMT_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.afmt_status1 &= ~AFMT_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI0\n"); break; case 1: - if (rdev->irq.stat_regs.evergreen.afmt_status2 & AFMT_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.evergreen.afmt_status2 &= ~AFMT_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI1\n"); - } + if (!(rdev->irq.stat_regs.evergreen.afmt_status2 & AFMT_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.afmt_status2 &= ~AFMT_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI1\n"); break; case 2: - if (rdev->irq.stat_regs.evergreen.afmt_status3 & AFMT_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.evergreen.afmt_status3 &= ~AFMT_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI2\n"); - } + if (!(rdev->irq.stat_regs.evergreen.afmt_status3 & AFMT_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.afmt_status3 &= ~AFMT_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI2\n"); break; case 3: - if (rdev->irq.stat_regs.evergreen.afmt_status4 & AFMT_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.evergreen.afmt_status4 &= ~AFMT_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI3\n"); - } + if (!(rdev->irq.stat_regs.evergreen.afmt_status4 & AFMT_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.afmt_status4 &= ~AFMT_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI3\n"); break; case 4: - if (rdev->irq.stat_regs.evergreen.afmt_status5 & AFMT_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.evergreen.afmt_status5 &= ~AFMT_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI4\n"); - } + if (!(rdev->irq.stat_regs.evergreen.afmt_status5 & AFMT_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.afmt_status5 &= ~AFMT_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI4\n"); break; case 5: - if (rdev->irq.stat_regs.evergreen.afmt_status6 & AFMT_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.evergreen.afmt_status6 &= ~AFMT_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI5\n"); - } + if (!(rdev->irq.stat_regs.evergreen.afmt_status6 & AFMT_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.afmt_status6 &= ~AFMT_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI5\n"); break; default: DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data); break; } + case 96: + DRM_ERROR("SRBM_READ_ERROR: 0x%x\n", RREG32(SRBM_READ_ERROR)); + WREG32(SRBM_INT_ACK, 0x1); + break; case 124: /* UVD */ DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data); radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX); @@ -5131,6 +5497,8 @@ restart_ih: rptr &= rdev->ih.ptr_mask; WREG32(IH_RB_RPTR, rptr); } + if (queue_dp) + schedule_work(&rdev->dp_work); if (queue_hotplug) taskqueue_enqueue(rdev->tq, &rdev->hotplug_work); if (queue_hdmi) @@ -5148,6 +5516,73 @@ restart_ih: return IRQ_HANDLED; } +static void evergreen_uvd_init(struct radeon_device *rdev) +{ + int r; + + if (!rdev->has_uvd) + return; + + r = radeon_uvd_init(rdev); + if (r) { + dev_err(rdev->dev, "failed UVD (%d) init.\n", r); + /* + * At this point rdev->uvd.vcpu_bo is NULL which trickles down + * to early fails uvd_v2_2_resume() and thus nothing happens + * there. So it is pointless to try to go through that code + * hence why we disable uvd here. + */ + rdev->has_uvd = 0; + return; + } + rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL; + r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX], 4096); +} + +static void evergreen_uvd_start(struct radeon_device *rdev) +{ + int r; + + if (!rdev->has_uvd) + return; + + r = uvd_v2_2_resume(rdev); + if (r) { + dev_err(rdev->dev, "failed UVD resume (%d).\n", r); + goto error; + } + r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX); + if (r) { + dev_err(rdev->dev, "failed initializing UVD fences (%d).\n", r); + goto error; + } + return; + +error: + rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; +} + +static void evergreen_uvd_resume(struct radeon_device *rdev) +{ + struct radeon_ring *ring; + int r; + + if (!rdev->has_uvd || !rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size) + return; + + ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; + r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2); + if (r) { + dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r); + return; + } + r = uvd_v1_0_init(rdev); + if (r) { + dev_err(rdev->dev, "failed initializing UVD (%d).\n", r); + return; + } +} + static int evergreen_startup(struct radeon_device *rdev) { struct radeon_ring *ring; @@ -5212,16 +5647,7 @@ static int evergreen_startup(struct radeon_device *rdev) return r; } - r = uvd_v2_2_resume(rdev); - if (!r) { - r = radeon_fence_driver_start_ring(rdev, - R600_RING_TYPE_UVD_INDEX); - if (r) - dev_err(rdev->dev, "UVD fences init error (%d).\n", r); - } - - if (r) - rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; + evergreen_uvd_start(rdev); /* Enable IRQ */ if (!rdev->irq.installed) { @@ -5260,16 +5686,7 @@ static int evergreen_startup(struct radeon_device *rdev) if (r) return r; - ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; - if (ring->ring_size) { - r = radeon_ring_init(rdev, ring, ring->ring_size, 0, - RADEON_CP_PACKET2); - if (!r) - r = uvd_v1_0_init(rdev); - - if (r) - DRM_ERROR("radeon: error initializing UVD (%d).\n", r); - } + evergreen_uvd_resume(rdev); r = radeon_ib_pool_init(rdev); if (r) { @@ -5277,7 +5694,7 @@ static int evergreen_startup(struct radeon_device *rdev) return r; } - r = r600_audio_init(rdev); + r = radeon_audio_init(rdev); if (r) { DRM_ERROR("radeon: audio init failed\n"); return r; @@ -5323,9 +5740,11 @@ int evergreen_resume(struct radeon_device *rdev) int evergreen_suspend(struct radeon_device *rdev) { radeon_pm_suspend(rdev); - r600_audio_fini(rdev); - uvd_v1_0_fini(rdev); - radeon_uvd_suspend(rdev); + radeon_audio_fini(rdev); + if (rdev->has_uvd) { + uvd_v1_0_fini(rdev); + radeon_uvd_suspend(rdev); + } r700_cp_stop(rdev); r600_dma_stop(rdev); evergreen_irq_suspend(rdev); @@ -5426,12 +5845,7 @@ int evergreen_init(struct radeon_device *rdev) rdev->ring[R600_RING_TYPE_DMA_INDEX].ring_obj = NULL; r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX], 64 * 1024); - r = radeon_uvd_init(rdev); - if (!r) { - rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL; - r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX], - 4096); - } + evergreen_uvd_init(rdev); rdev->ih.ring_obj = NULL; r600_ih_ring_init(rdev, 64 * 1024); @@ -5473,7 +5887,7 @@ int evergreen_init(struct radeon_device *rdev) void evergreen_fini(struct radeon_device *rdev) { radeon_pm_fini(rdev); - r600_audio_fini(rdev); + radeon_audio_fini(rdev); r700_cp_fini(rdev); r600_dma_fini(rdev); r600_irq_fini(rdev); @@ -5521,7 +5935,7 @@ void evergreen_pcie_gen2_enable(struct radeon_device *rdev) if (ret != 0) return; - if (!(mask & DRM_PCIE_SPEED_50)) + if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80))) return; speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); diff --git a/sys/dev/drm/radeon/evergreen_blit_shaders.c b/sys/dev/drm/radeon/evergreen_blit_shaders.c index d43383470c..1a96ddb3e5 100644 --- a/sys/dev/drm/radeon/evergreen_blit_shaders.c +++ b/sys/dev/drm/radeon/evergreen_blit_shaders.c @@ -32,7 +32,7 @@ * evergreen 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 + * statically generated state tables. The register state and shaders * were hand generated to support blitting functionality. See the 3D * driver or documentation for descriptions of the registers and * shader instructions. diff --git a/sys/dev/drm/radeon/evergreen_cs.c b/sys/dev/drm/radeon/evergreen_cs.c index de3e925935..b930ab488e 100644 --- a/sys/dev/drm/radeon/evergreen_cs.c +++ b/sys/dev/drm/radeon/evergreen_cs.c @@ -35,6 +35,8 @@ #define MAX(a,b) (((a)>(b))?(a):(b)) #define MIN(a,b) (((a)<(b))?(a):(b)) +#define REG_SAFE_BM_SIZE ARRAY_SIZE(evergreen_reg_safe_bm) + struct evergreen_cs_track { u32 group_size; u32 nbanks; @@ -82,6 +84,8 @@ struct evergreen_cs_track { u32 htile_offset; u32 htile_surface; struct radeon_bo *htile_bo; + unsigned long indirect_draw_buffer_size; + const unsigned *reg_safe_bm; }; static u32 evergreen_cs_get_aray_mode(u32 tiling_flags) @@ -442,7 +446,7 @@ static int evergreen_cs_track_validate_cb(struct radeon_cs_parser *p, unsigned i * command stream. */ if (!surf.mode) { - volatile u32 *ib = p->ib.ptr; + uint32_t *ib = p->ib.ptr; unsigned long tmp, nby, bsize, size, min = 0; /* find the height the ddx wants */ @@ -1081,41 +1085,18 @@ static int evergreen_cs_parse_packet0(struct radeon_cs_parser *p, } /** - * evergreen_cs_check_reg() - check if register is authorized or not + * evergreen_cs_handle_reg() - process registers that need special handling. * @parser: parser structure holding parsing context * @reg: register we are testing * @idx: index into the cs buffer - * - * This function will test against evergreen_reg_safe_bm and return 0 - * if register is safe. If register is not flag as safe this function - * will test it against a list of register needind special handling. */ -static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) +static int evergreen_cs_handle_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) { struct evergreen_cs_track *track = (struct evergreen_cs_track *)p->track; - struct radeon_cs_reloc *reloc; - u32 last_reg; - u32 m, i, tmp, *ib; + struct radeon_bo_list *reloc; + u32 tmp, *ib; int r; - if (p->rdev->family >= CHIP_CAYMAN) - last_reg = ARRAY_SIZE(cayman_reg_safe_bm); - else - last_reg = ARRAY_SIZE(evergreen_reg_safe_bm); - - i = (reg >> 7); - if (i >= last_reg) { - dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); - return -EINVAL; - } - m = 1 << ((reg >> 2) & 31); - if (p->rdev->family >= CHIP_CAYMAN) { - if (!(cayman_reg_safe_bm[i] & m)) - return 0; - } else { - if (!(evergreen_reg_safe_bm[i] & m)) - return 0; - } ib = p->ib.ptr; switch (reg) { /* force following reg to 0 in an attempt to disable out buffer @@ -1762,38 +1743,36 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) return 0; } -static bool evergreen_is_safe_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) +/** + * evergreen_is_safe_reg() - check if register is authorized or not + * @parser: parser structure holding parsing context + * @reg: register we are testing + * + * This function will test against reg_safe_bm and return true + * if register is safe or false otherwise. + */ +static inline bool evergreen_is_safe_reg(struct radeon_cs_parser *p, u32 reg) { - u32 last_reg, m, i; - - if (p->rdev->family >= CHIP_CAYMAN) - last_reg = ARRAY_SIZE(cayman_reg_safe_bm); - else - last_reg = ARRAY_SIZE(evergreen_reg_safe_bm); + struct evergreen_cs_track *track = p->track; + u32 m, i; i = (reg >> 7); - if (i >= last_reg) { - dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); + if (unlikely(i >= REG_SAFE_BM_SIZE)) { return false; } m = 1 << ((reg >> 2) & 31); - if (p->rdev->family >= CHIP_CAYMAN) { - if (!(cayman_reg_safe_bm[i] & m)) - return true; - } else { - if (!(evergreen_reg_safe_bm[i] & m)) - return true; - } - dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); + if (!(track->reg_safe_bm[i] & m)) + return true; + return false; } static int evergreen_packet3_check(struct radeon_cs_parser *p, struct radeon_cs_packet *pkt) { - struct radeon_cs_reloc *reloc; + struct radeon_bo_list *reloc; struct evergreen_cs_track *track; - volatile u32 *ib; + uint32_t *ib; unsigned idx; unsigned i; unsigned start_reg, end_reg, reg; @@ -1895,6 +1874,14 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p, } break; } + case PACKET3_INDEX_BUFFER_SIZE: + { + if (pkt->count != 0) { + DRM_ERROR("bad INDEX_BUFFER_SIZE\n"); + return -EINVAL; + } + break; + } case PACKET3_DRAW_INDEX: { uint64_t offset; @@ -2005,6 +1992,67 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p, return r; } break; + case PACKET3_SET_BASE: + { + /* + DW 1 HEADER Header of the packet. Shader_Type in bit 1 of the Header will correspond to the shader type of the Load, see Type-3 Packet. + 2 BASE_INDEX Bits [3:0] BASE_INDEX - Base Index specifies which base address is specified in the last two DWs. + 0001: DX11 Draw_Index_Indirect Patch Table Base: Base address for Draw_Index_Indirect data. + 3 ADDRESS_LO Bits [31:3] - Lower bits of QWORD-Aligned Address. Bits [2:0] - Reserved + 4 ADDRESS_HI Bits [31:8] - Reserved. Bits [7:0] - Upper bits of Address [47:32] + */ + if (pkt->count != 2) { + DRM_ERROR("bad SET_BASE\n"); + return -EINVAL; + } + + /* currently only supporting setting indirect draw buffer base address */ + if (idx_value != 1) { + DRM_ERROR("bad SET_BASE\n"); + return -EINVAL; + } + + r = radeon_cs_packet_next_reloc(p, &reloc, 0); + if (r) { + DRM_ERROR("bad SET_BASE\n"); + return -EINVAL; + } + + track->indirect_draw_buffer_size = radeon_bo_size(reloc->robj); + + ib[idx+1] = reloc->gpu_offset; + ib[idx+2] = upper_32_bits(reloc->gpu_offset) & 0xff; + + break; + } + case PACKET3_DRAW_INDIRECT: + case PACKET3_DRAW_INDEX_INDIRECT: + { + u64 size = pkt->opcode == PACKET3_DRAW_INDIRECT ? 16 : 20; + + /* + DW 1 HEADER + 2 DATA_OFFSET Bits [31:0] + byte aligned offset where the required data structure starts. Bits 1:0 are zero + 3 DRAW_INITIATOR Draw Initiator Register. Written to the VGT_DRAW_INITIATOR register for the assigned context + */ + if (pkt->count != 1) { + DRM_ERROR("bad DRAW_INDIRECT\n"); + return -EINVAL; + } + + if (idx_value + size > track->indirect_draw_buffer_size) { + dev_warn(p->dev, "DRAW_INDIRECT buffer too small %u + %llu > %lu\n", + idx_value, size, track->indirect_draw_buffer_size); + return -EINVAL; + } + + r = evergreen_cs_track_check(p); + if (r) { + dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); + return r; + } + break; + } case PACKET3_DISPATCH_DIRECT: if (pkt->count != 3) { DRM_ERROR("bad DISPATCH_DIRECT\n"); @@ -2250,9 +2298,10 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p, DRM_ERROR("bad PACKET3_SET_CONFIG_REG\n"); return -EINVAL; } - for (i = 0; i < pkt->count; i++) { - reg = start_reg + (4 * i); - r = evergreen_cs_check_reg(p, reg, idx+1+i); + for (reg = start_reg, idx++; reg <= end_reg; reg += 4, idx++) { + if (evergreen_is_safe_reg(p, reg)) + continue; + r = evergreen_cs_handle_reg(p, reg, idx); if (r) return r; } @@ -2266,9 +2315,10 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p, DRM_ERROR("bad PACKET3_SET_CONTEXT_REG\n"); return -EINVAL; } - for (i = 0; i < pkt->count; i++) { - reg = start_reg + (4 * i); - r = evergreen_cs_check_reg(p, reg, idx+1+i); + for (reg = start_reg, idx++; reg <= end_reg; reg += 4, idx++) { + if (evergreen_is_safe_reg(p, reg)) + continue; + r = evergreen_cs_handle_reg(p, reg, idx); if (r) return r; } @@ -2523,8 +2573,11 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p, } else { /* SRC is a reg. */ reg = radeon_get_ib_value(p, idx+1) << 2; - if (!evergreen_is_safe_reg(p, reg, idx+1)) - return -EINVAL; + if (!evergreen_is_safe_reg(p, reg)) { + dev_warn(p->dev, "forbidden register 0x%08x at %d\n", + reg, idx + 1); + return -EINVAL; + } } if (idx_value & 0x2) { u64 offset; @@ -2547,10 +2600,58 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p, } else { /* DST is a reg. */ reg = radeon_get_ib_value(p, idx+3) << 2; - if (!evergreen_is_safe_reg(p, reg, idx+3)) + if (!evergreen_is_safe_reg(p, reg)) { + dev_warn(p->dev, "forbidden register 0x%08x at %d\n", + reg, idx + 3); + return -EINVAL; + } + } + break; + case PACKET3_SET_APPEND_CNT: + { + uint32_t areg; + uint32_t allowed_reg_base; + uint32_t source_sel; + if (pkt->count != 2) { + DRM_ERROR("bad SET_APPEND_CNT (invalid count)\n"); + return -EINVAL; + } + + allowed_reg_base = GDS_APPEND_COUNT_0; + allowed_reg_base -= PACKET3_SET_CONTEXT_REG_START; + allowed_reg_base >>= 2; + + areg = idx_value >> 16; + if (areg < allowed_reg_base || areg > (allowed_reg_base + 11)) { + dev_warn(p->dev, "forbidden register for append cnt 0x%08x at %d\n", + areg, idx); + return -EINVAL; + } + + source_sel = G_PACKET3_SET_APPEND_CNT_SRC_SELECT(idx_value); + if (source_sel == PACKET3_SAC_SRC_SEL_MEM) { + uint64_t offset; + uint32_t swap; + r = radeon_cs_packet_next_reloc(p, &reloc, 0); + if (r) { + DRM_ERROR("bad SET_APPEND_CNT (missing reloc)\n"); return -EINVAL; + } + offset = radeon_get_ib_value(p, idx + 1); + swap = offset & 0x3; + offset &= ~0x3; + + offset += ((u64)(radeon_get_ib_value(p, idx + 2) & 0xff)) << 32; + + offset += reloc->gpu_offset; + ib[idx+1] = (offset & 0xfffffffc) | swap; + ib[idx+2] = upper_32_bits(offset) & 0xff; + } else { + DRM_ERROR("bad SET_APPEND_CNT (unsupported operation)\n"); + return -EINVAL; } break; + } case PACKET3_NOP: break; default: @@ -2573,11 +2674,15 @@ int evergreen_cs_parse(struct radeon_cs_parser *p) if (track == NULL) return -ENOMEM; evergreen_cs_track_init(track); - if (p->rdev->family >= CHIP_CAYMAN) + if (p->rdev->family >= CHIP_CAYMAN) { tmp = p->rdev->config.cayman.tile_config; - else - tmp = p->rdev->config.evergreen.tile_config; - + track->reg_safe_bm = cayman_reg_safe_bm; + } else { + tmp = p->rdev->config.evergreen.tile_config; + track->reg_safe_bm = evergreen_reg_safe_bm; + } + BUILD_BUG_ON(ARRAY_SIZE(cayman_reg_safe_bm) != REG_SAFE_BM_SIZE); + BUILD_BUG_ON(ARRAY_SIZE(evergreen_reg_safe_bm) != REG_SAFE_BM_SIZE); switch (tmp & 0xf) { case 0: track->npipes = 1; @@ -2684,9 +2789,9 @@ int evergreen_cs_parse(struct radeon_cs_parser *p) int evergreen_dma_cs_parse(struct radeon_cs_parser *p) { struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx]; - struct radeon_cs_reloc *src_reloc, *dst_reloc, *dst2_reloc; + struct radeon_bo_list *src_reloc, *dst_reloc, *dst2_reloc; u32 header, cmd, count, sub_cmd; - volatile u32 *ib = p->ib.ptr; + uint32_t *ib = p->ib.ptr; u32 idx; u64 src_offset, dst_offset, dst2_offset; int r; @@ -3242,7 +3347,13 @@ static int evergreen_vm_packet3_check(struct radeon_device *rdev, switch (pkt->opcode) { case PACKET3_NOP: + break; case PACKET3_SET_BASE: + if (idx_value != 1) { + DRM_ERROR("bad SET_BASE"); + return -EINVAL; + } + break; case PACKET3_CLEAR_STATE: case PACKET3_INDEX_BUFFER_SIZE: case PACKET3_DISPATCH_DIRECT: @@ -3371,6 +3482,27 @@ static int evergreen_vm_packet3_check(struct radeon_device *rdev, } } break; + case PACKET3_SET_APPEND_CNT: { + uint32_t areg; + uint32_t allowed_reg_base; + + if (pkt->count != 2) { + DRM_ERROR("bad SET_APPEND_CNT (invalid count)\n"); + return -EINVAL; + } + + allowed_reg_base = GDS_APPEND_COUNT_0; + allowed_reg_base -= PACKET3_SET_CONTEXT_REG_START; + allowed_reg_base >>= 2; + + areg = idx_value >> 16; + if (areg < allowed_reg_base || areg > (allowed_reg_base + 11)) { + DRM_ERROR("forbidden register for append cnt 0x%08x at %d\n", + areg, idx); + return -EINVAL; + } + break; + } default: return -EINVAL; } diff --git a/sys/dev/drm/radeon/evergreen_hdmi.c b/sys/dev/drm/radeon/evergreen_hdmi.c index 349664723e..3b985c1479 100644 --- a/sys/dev/drm/radeon/evergreen_hdmi.c +++ b/sys/dev/drm/radeon/evergreen_hdmi.c @@ -29,11 +29,12 @@ #include #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include "evergreend.h" #include "atom.h" /* enable the audio stream */ -static void dce4_audio_enable(struct radeon_device *rdev, +void dce4_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin, u8 enable_mask) { @@ -63,48 +64,42 @@ static void dce4_audio_enable(struct radeon_device *rdev, WREG32(AZ_HOT_PLUG_CONTROL, tmp); } -/* - * update the N and CTS parameters for a given pixel clock rate - */ -static void evergreen_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock) +void evergreen_hdmi_update_acr(struct drm_encoder *encoder, long offset, + const struct radeon_hdmi_acr *acr) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; - struct radeon_hdmi_acr acr = r600_hdmi_acr(clock); - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - uint32_t offset = dig->afmt->offset; + int bpc = 8; - WREG32(HDMI_ACR_32_0 + offset, HDMI_ACR_CTS_32(acr.cts_32khz)); - WREG32(HDMI_ACR_32_1 + offset, acr.n_32khz); + if (encoder->crtc) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + bpc = radeon_crtc->bpc; + } - WREG32(HDMI_ACR_44_0 + offset, HDMI_ACR_CTS_44(acr.cts_44_1khz)); - WREG32(HDMI_ACR_44_1 + offset, acr.n_44_1khz); + if (bpc > 8) + WREG32(HDMI_ACR_PACKET_CONTROL + offset, + HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */ + else + WREG32(HDMI_ACR_PACKET_CONTROL + offset, + HDMI_ACR_SOURCE | /* select SW CTS value */ + HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */ + + WREG32(HDMI_ACR_32_0 + offset, HDMI_ACR_CTS_32(acr->cts_32khz)); + WREG32(HDMI_ACR_32_1 + offset, acr->n_32khz); + + WREG32(HDMI_ACR_44_0 + offset, HDMI_ACR_CTS_44(acr->cts_44_1khz)); + WREG32(HDMI_ACR_44_1 + offset, acr->n_44_1khz); - WREG32(HDMI_ACR_48_0 + offset, HDMI_ACR_CTS_48(acr.cts_48khz)); - WREG32(HDMI_ACR_48_1 + offset, acr.n_48khz); + WREG32(HDMI_ACR_48_0 + offset, HDMI_ACR_CTS_48(acr->cts_48khz)); + WREG32(HDMI_ACR_48_1 + offset, acr->n_48khz); } -static void dce4_afmt_write_latency_fields(struct drm_encoder *encoder, - struct drm_display_mode *mode) +void dce4_afmt_write_latency_fields(struct drm_encoder *encoder, + struct drm_connector *connector, struct drm_display_mode *mode) { struct radeon_device *rdev = encoder->dev->dev_private; - struct drm_connector *connector; - struct radeon_connector *radeon_connector = NULL; u32 tmp = 0; - list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) { - radeon_connector = to_radeon_connector(connector); - break; - } - } - - if (!radeon_connector) { - DRM_ERROR("Couldn't find encoder's connector\n"); - return; - } - if (mode->flags & DRM_MODE_FLAG_INTERLACE) { if (connector->latency_present[1]) tmp = VIDEO_LIPSYNC(connector->video_latency[1]) | @@ -118,38 +113,17 @@ static void dce4_afmt_write_latency_fields(struct drm_encoder *encoder, else tmp = VIDEO_LIPSYNC(255) | AUDIO_LIPSYNC(255); } - WREG32(AZ_F0_CODEC_PIN0_CONTROL_RESPONSE_LIPSYNC, tmp); + WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_RESPONSE_LIPSYNC, tmp); } -static void dce4_afmt_write_speaker_allocation(struct drm_encoder *encoder) +void dce4_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count) { struct radeon_device *rdev = encoder->dev->dev_private; - struct drm_connector *connector; - struct radeon_connector *radeon_connector = NULL; u32 tmp; - u8 *sadb = NULL; - int sad_count; - - list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) { - radeon_connector = to_radeon_connector(connector); - break; - } - } - - if (!radeon_connector) { - DRM_ERROR("Couldn't find encoder's connector\n"); - return; - } - - sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector), &sadb); - if (sad_count < 0) { - DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n", sad_count); - sad_count = 0; - } /* program the speaker allocation */ - tmp = RREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER); + tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER); tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK); /* set HDMI mode */ tmp |= HDMI_CONNECTION; @@ -157,19 +131,32 @@ static void dce4_afmt_write_speaker_allocation(struct drm_encoder *encoder) tmp |= SPEAKER_ALLOCATION(sadb[0]); else tmp |= SPEAKER_ALLOCATION(5); /* stereo */ - WREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp); - - kfree(sadb); + WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp); } -static void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder) +void dce4_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count) { struct radeon_device *rdev = encoder->dev->dev_private; - struct drm_connector *connector; - struct radeon_connector *radeon_connector = NULL; - struct cea_sad *sads; - int i, sad_count; + u32 tmp; + /* program the speaker allocation */ + tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER); + tmp &= ~(HDMI_CONNECTION | SPEAKER_ALLOCATION_MASK); + /* set DP mode */ + tmp |= DP_CONNECTION; + if (sad_count) + tmp |= SPEAKER_ALLOCATION(sadb[0]); + else + tmp |= SPEAKER_ALLOCATION(5); /* stereo */ + WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp); +} + +void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder, + struct cea_sad *sads, int sad_count) +{ + int i; + struct radeon_device *rdev = encoder->dev->dev_private; static const u16 eld_reg_to_type[][2] = { { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM }, { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 }, @@ -185,25 +172,6 @@ static void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder) { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO }, }; - list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) { - radeon_connector = to_radeon_connector(connector); - break; - } - } - - if (!radeon_connector) { - DRM_ERROR("Couldn't find encoder's connector\n"); - return; - } - - sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads); - if (sad_count <= 0) { - DRM_ERROR("Couldn't read SADs: %d\n", sad_count); - return; - } - BUG_ON(!sads); - for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) { u32 value = 0; u8 stereo_freqs = 0; @@ -230,25 +198,17 @@ static void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder) value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs); - WREG32(eld_reg_to_type[i][0], value); + WREG32_ENDPOINT(0, eld_reg_to_type[i][0], value); } - - kfree(sads); } /* - * build a HDMI Video Info Frame + * build a AVI Info Frame */ -static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder, - void *buffer, size_t size) +void evergreen_set_avi_packet(struct radeon_device *rdev, u32 offset, + unsigned char *buffer, size_t size) { - 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; - uint32_t offset = dig->afmt->offset; uint8_t *frame = (uint8_t*)buffer + 3; - uint8_t *header = buffer; WREG32(AFMT_AVI_INFO0 + offset, frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24)); @@ -257,104 +217,109 @@ static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder, WREG32(AFMT_AVI_INFO2 + offset, frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24)); WREG32(AFMT_AVI_INFO3 + offset, - frame[0xC] | (frame[0xD] << 8) | (header[1] << 24)); + frame[0xC] | (frame[0xD] << 8) | (buffer[1] << 24)); + + WREG32_P(HDMI_INFOFRAME_CONTROL1 + offset, + HDMI_AVI_INFO_LINE(2), /* anything other than 0 */ + ~HDMI_AVI_INFO_LINE_MASK); } -static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock) +void dce4_hdmi_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned 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; - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); - u32 base_rate = 24000; - u32 max_ratio = clock / base_rate; - u32 dto_phase; - u32 dto_modulo = clock; + unsigned int max_ratio = clock / 24000; + u32 dto_phase; u32 wallclock_ratio; - u32 dto_cntl; - - if (!dig || !dig->afmt) - return; - - if (ASIC_IS_DCE6(rdev)) { - dto_phase = 24 * 1000; + u32 value; + + if (max_ratio >= 8) { + dto_phase = 192 * 1000; + wallclock_ratio = 3; + } else if (max_ratio >= 4) { + dto_phase = 96 * 1000; + wallclock_ratio = 2; + } else if (max_ratio >= 2) { + dto_phase = 48 * 1000; + wallclock_ratio = 1; } else { - if (max_ratio >= 8) { - dto_phase = 192 * 1000; - wallclock_ratio = 3; - } else if (max_ratio >= 4) { - dto_phase = 96 * 1000; - wallclock_ratio = 2; - } else if (max_ratio >= 2) { - dto_phase = 48 * 1000; - wallclock_ratio = 1; - } else { - dto_phase = 24 * 1000; - wallclock_ratio = 0; - } - dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; - dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio); - WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl); + dto_phase = 24 * 1000; + wallclock_ratio = 0; } - /* XXX two dtos; generally use dto0 for hdmi */ + value = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; + value |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio); + value &= ~DCCG_AUDIO_DTO1_USE_512FBR_DTO; + WREG32(DCCG_AUDIO_DTO0_CNTL, value); + + /* Two dtos; generally use dto0 for HDMI */ + value = 0; + + if (crtc) + value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id); + + WREG32(DCCG_AUDIO_DTO_SOURCE, value); + /* Express [24MHz / target pixel clock] as an exact rational * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator */ - WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id)); WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase); - WREG32(DCCG_AUDIO_DTO0_MODULE, dto_modulo); + WREG32(DCCG_AUDIO_DTO0_MODULE, clock); } - -/* - * update the info frames with the data from the current display mode - */ -void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode) +void dce4_dp_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned 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; - struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); - u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE]; - struct hdmi_avi_infoframe frame; - uint32_t offset; - ssize_t err; - uint32_t val; - int bpc = 8; + u32 value; - if (!dig || !dig->afmt) - return; + value = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; + value |= DCCG_AUDIO_DTO1_USE_512FBR_DTO; + WREG32(DCCG_AUDIO_DTO1_CNTL, value); - /* Silent, r600_hdmi_enable will raise WARN for us */ - if (!dig->afmt->enabled) - return; - offset = dig->afmt->offset; + /* Two dtos; generally use dto1 for DP */ + value = 0; + value |= DCCG_AUDIO_DTO_SEL; - /* hdmi deep color mode general control packets setup, if bpc > 8 */ - if (encoder->crtc) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); - bpc = radeon_crtc->bpc; - } + if (crtc) + value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id); - /* disable audio prior to setting up hw */ - if (ASIC_IS_DCE6(rdev)) { - dig->afmt->pin = dce6_audio_get_pin(rdev); - dce6_audio_enable(rdev, dig->afmt->pin, 0); - } else { - dig->afmt->pin = r600_audio_get_pin(rdev); - dce4_audio_enable(rdev, dig->afmt->pin, 0); + WREG32(DCCG_AUDIO_DTO_SOURCE, value); + + /* Express [24MHz / target pixel clock] as an exact rational + * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE + * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator + */ + if (ASIC_IS_DCE41(rdev)) { + unsigned int div = (RREG32(DCE41_DENTIST_DISPCLK_CNTL) & + DENTIST_DPREFCLK_WDIVIDER_MASK) >> + DENTIST_DPREFCLK_WDIVIDER_SHIFT; + div = radeon_audio_decode_dfs_div(div); + + if (div) + clock = 100 * clock / div; } - evergreen_audio_set_dto(encoder, mode->clock); + WREG32(DCCG_AUDIO_DTO1_PHASE, 24000); + WREG32(DCCG_AUDIO_DTO1_MODULE, clock); +} + +void dce4_set_vbi_packet(struct drm_encoder *encoder, u32 offset) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; WREG32(HDMI_VBI_PACKET_CONTROL + offset, - HDMI_NULL_SEND); /* send null packets when required */ + HDMI_NULL_SEND | /* send null packets when required */ + HDMI_GC_SEND | /* send general control packets */ + HDMI_GC_CONT); /* send general control packets every frame */ +} - WREG32(AFMT_AUDIO_CRC_CONTROL + offset, 0x1000); +void dce4_hdmi_set_color_depth(struct drm_encoder *encoder, u32 offset, int bpc) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + uint32_t val; val = RREG32(HDMI_CONTROL + offset); val &= ~HDMI_DEEP_COLOR_ENABLE; @@ -384,141 +349,141 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode } WREG32(HDMI_CONTROL + offset, val); +} - WREG32(HDMI_VBI_PACKET_CONTROL + offset, - HDMI_NULL_SEND | /* send null packets when required */ - HDMI_GC_SEND | /* send general control packets */ - HDMI_GC_CONT); /* send general control packets every frame */ - - WREG32(HDMI_INFOFRAME_CONTROL0 + offset, - HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */ - HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */ +void dce4_set_audio_packet(struct drm_encoder *encoder, u32 offset) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; WREG32(AFMT_INFOFRAME_CONTROL0 + offset, - AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */ - - WREG32(HDMI_INFOFRAME_CONTROL1 + offset, - HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */ - - WREG32(HDMI_GC + offset, 0); /* unset HDMI_GC_AVMUTE */ - - WREG32(HDMI_AUDIO_PACKET_CONTROL + offset, - HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */ - HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */ - - WREG32(AFMT_AUDIO_PACKET_CONTROL + offset, - AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */ - - /* fglrx clears sth in AFMT_AUDIO_PACKET_CONTROL2 here */ - - if (bpc > 8) - WREG32(HDMI_ACR_PACKET_CONTROL + offset, - HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */ - else - WREG32(HDMI_ACR_PACKET_CONTROL + offset, - HDMI_ACR_SOURCE | /* select SW CTS value */ - HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */ - - evergreen_hdmi_update_ACR(encoder, mode->clock); + AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */ WREG32(AFMT_60958_0 + offset, - AFMT_60958_CS_CHANNEL_NUMBER_L(1)); + AFMT_60958_CS_CHANNEL_NUMBER_L(1)); WREG32(AFMT_60958_1 + offset, - AFMT_60958_CS_CHANNEL_NUMBER_R(2)); + AFMT_60958_CS_CHANNEL_NUMBER_R(2)); WREG32(AFMT_60958_2 + offset, - AFMT_60958_CS_CHANNEL_NUMBER_2(3) | - AFMT_60958_CS_CHANNEL_NUMBER_3(4) | - AFMT_60958_CS_CHANNEL_NUMBER_4(5) | - AFMT_60958_CS_CHANNEL_NUMBER_5(6) | - AFMT_60958_CS_CHANNEL_NUMBER_6(7) | - AFMT_60958_CS_CHANNEL_NUMBER_7(8)); - - if (ASIC_IS_DCE6(rdev)) { - dce6_afmt_write_speaker_allocation(encoder); - } else { - dce4_afmt_write_speaker_allocation(encoder); - } + AFMT_60958_CS_CHANNEL_NUMBER_2(3) | + AFMT_60958_CS_CHANNEL_NUMBER_3(4) | + AFMT_60958_CS_CHANNEL_NUMBER_4(5) | + AFMT_60958_CS_CHANNEL_NUMBER_5(6) | + AFMT_60958_CS_CHANNEL_NUMBER_6(7) | + AFMT_60958_CS_CHANNEL_NUMBER_7(8)); WREG32(AFMT_AUDIO_PACKET_CONTROL2 + offset, - AFMT_AUDIO_CHANNEL_ENABLE(0xff)); + AFMT_AUDIO_CHANNEL_ENABLE(0xff)); - /* fglrx sets 0x40 in 0x5f80 here */ + WREG32(HDMI_AUDIO_PACKET_CONTROL + offset, + HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */ + HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */ - if (ASIC_IS_DCE6(rdev)) { - dce6_afmt_select_pin(encoder); - dce6_afmt_write_sad_regs(encoder); - dce6_afmt_write_latency_fields(encoder, mode); - } else { - evergreen_hdmi_write_sad_regs(encoder); - dce4_afmt_write_latency_fields(encoder, mode); - } + /* allow 60958 channel status and send audio packets fields to be updated */ + WREG32_OR(AFMT_AUDIO_PACKET_CONTROL + offset, + AFMT_RESET_FIFO_WHEN_AUDIO_DIS | AFMT_60958_CS_UPDATE); +} - err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode); - if (err < 0) { - DRM_ERROR("failed to setup AVI infoframe: %zd\n", err); - return; - } - err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer)); - if (err < 0) { - DRM_ERROR("failed to pack AVI infoframe: %zd\n", err); - return; - } +void dce4_set_mute(struct drm_encoder *encoder, u32 offset, bool mute) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; - evergreen_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer)); + if (mute) + WREG32_OR(HDMI_GC + offset, HDMI_GC_AVMUTE); + else + WREG32_AND(HDMI_GC + offset, ~HDMI_GC_AVMUTE); +} - WREG32_OR(HDMI_INFOFRAME_CONTROL0 + offset, - HDMI_AVI_INFO_SEND | /* enable AVI info frames */ - HDMI_AVI_INFO_CONT); /* required for audio info values to be updated */ +void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable) +{ + 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; - WREG32_P(HDMI_INFOFRAME_CONTROL1 + offset, - HDMI_AVI_INFO_LINE(2), /* anything other than 0 */ - ~HDMI_AVI_INFO_LINE_MASK); + if (!dig || !dig->afmt) + return; - WREG32_OR(AFMT_AUDIO_PACKET_CONTROL + offset, - AFMT_AUDIO_SAMPLE_SEND); /* send audio packets */ + if (enable) { + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + + if (connector && drm_detect_monitor_audio(radeon_connector_edid(connector))) { + WREG32(HDMI_INFOFRAME_CONTROL0 + dig->afmt->offset, + HDMI_AVI_INFO_SEND | /* enable AVI info frames */ + HDMI_AVI_INFO_CONT | /* required for audio info values to be updated */ + HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */ + HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */ + WREG32_OR(AFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset, + AFMT_AUDIO_SAMPLE_SEND); + } else { + WREG32(HDMI_INFOFRAME_CONTROL0 + dig->afmt->offset, + HDMI_AVI_INFO_SEND | /* enable AVI info frames */ + HDMI_AVI_INFO_CONT); /* required for audio info values to be updated */ + WREG32_AND(AFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset, + ~AFMT_AUDIO_SAMPLE_SEND); + } + } else { + WREG32_AND(AFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset, + ~AFMT_AUDIO_SAMPLE_SEND); + WREG32(HDMI_INFOFRAME_CONTROL0 + dig->afmt->offset, 0); + } - /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */ - WREG32(AFMT_RAMP_CONTROL0 + offset, 0x00FFFFFF); - WREG32(AFMT_RAMP_CONTROL1 + offset, 0x007FFFFF); - WREG32(AFMT_RAMP_CONTROL2 + offset, 0x00000001); - WREG32(AFMT_RAMP_CONTROL3 + offset, 0x00000001); + dig->afmt->enabled = enable; - /* enable audio after to setting up hw */ - if (ASIC_IS_DCE6(rdev)) - dce6_audio_enable(rdev, dig->afmt->pin, 1); - else - dce4_audio_enable(rdev, dig->afmt->pin, 0xf); + DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n", + enable ? "En" : "Dis", dig->afmt->offset, radeon_encoder->encoder_id); } -void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable) +void evergreen_dp_enable(struct drm_encoder *encoder, bool enable) { 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; + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); if (!dig || !dig->afmt) return; - /* Silent, r600_hdmi_enable will raise WARN for us */ - if (enable && dig->afmt->enabled) - return; - if (!enable && !dig->afmt->enabled) - return; + if (enable && connector && + drm_detect_monitor_audio(radeon_connector_edid(connector))) { + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *dig_connector; + uint32_t val; - if (!enable && dig->afmt->pin) { - if (ASIC_IS_DCE6(rdev)) - dce6_audio_enable(rdev, dig->afmt->pin, 0); - else - dce4_audio_enable(rdev, dig->afmt->pin, 0); - dig->afmt->pin = NULL; + WREG32_OR(AFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset, + AFMT_AUDIO_SAMPLE_SEND); + + WREG32(EVERGREEN_DP_SEC_TIMESTAMP + dig->afmt->offset, + EVERGREEN_DP_SEC_TIMESTAMP_MODE(1)); + + if (!ASIC_IS_DCE6(rdev) && radeon_connector->con_priv) { + dig_connector = radeon_connector->con_priv; + val = RREG32(EVERGREEN_DP_SEC_AUD_N + dig->afmt->offset); + val &= ~EVERGREEN_DP_SEC_N_BASE_MULTIPLE(0xf); + + if (dig_connector->dp_clock == 162000) + val |= EVERGREEN_DP_SEC_N_BASE_MULTIPLE(3); + else + val |= EVERGREEN_DP_SEC_N_BASE_MULTIPLE(5); + + WREG32(EVERGREEN_DP_SEC_AUD_N + dig->afmt->offset, val); + } + + WREG32(EVERGREEN_DP_SEC_CNTL + dig->afmt->offset, + EVERGREEN_DP_SEC_ASP_ENABLE | /* Audio packet transmission */ + EVERGREEN_DP_SEC_ATP_ENABLE | /* Audio timestamp packet transmission */ + EVERGREEN_DP_SEC_AIP_ENABLE | /* Audio infoframe packet transmission */ + EVERGREEN_DP_SEC_STREAM_ENABLE); /* Master enable for secondary stream engine */ + } else { + WREG32(EVERGREEN_DP_SEC_CNTL + dig->afmt->offset, 0); + WREG32_AND(AFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset, + ~AFMT_AUDIO_SAMPLE_SEND); } dig->afmt->enabled = enable; - - DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n", - enable ? "En" : "Dis", dig->afmt->offset, radeon_encoder->encoder_id); } diff --git a/sys/dev/drm/radeon/evergreen_reg.h b/sys/dev/drm/radeon/evergreen_reg.h index 23bff590fb..b436badf9e 100644 --- a/sys/dev/drm/radeon/evergreen_reg.h +++ b/sys/dev/drm/radeon/evergreen_reg.h @@ -250,5 +250,66 @@ /* HDMI blocks at 0x7030, 0x7c30, 0x10830, 0x11430, 0x12030, 0x12c30 */ #define EVERGREEN_HDMI_BASE 0x7030 +/*DIG block*/ +#define NI_DIG0_REGISTER_OFFSET (0x7000 - 0x7000) +#define NI_DIG1_REGISTER_OFFSET (0x7C00 - 0x7000) +#define NI_DIG2_REGISTER_OFFSET (0x10800 - 0x7000) +#define NI_DIG3_REGISTER_OFFSET (0x11400 - 0x7000) +#define NI_DIG4_REGISTER_OFFSET (0x12000 - 0x7000) +#define NI_DIG5_REGISTER_OFFSET (0x12C00 - 0x7000) + + +#define NI_DIG_FE_CNTL 0x7000 +# define NI_DIG_FE_CNTL_SOURCE_SELECT(x) ((x) & 0x3) +# define NI_DIG_FE_CNTL_SYMCLK_FE_ON (1<<24) + + +#define NI_DIG_BE_CNTL 0x7140 +# define NI_DIG_BE_CNTL_FE_SOURCE_SELECT(x) (((x) >> 8 ) & 0x3F) +# define NI_DIG_FE_CNTL_MODE(x) (((x) >> 16) & 0x7 ) + +#define NI_DIG_BE_EN_CNTL 0x7144 +# define NI_DIG_BE_EN_CNTL_ENABLE (1 << 0) +# define NI_DIG_BE_EN_CNTL_SYMBCLK_ON (1 << 8) +# define NI_DIG_BE_DPSST 0 + +/* Display Port block */ +#define EVERGREEN_DP0_REGISTER_OFFSET (0x730C - 0x730C) +#define EVERGREEN_DP1_REGISTER_OFFSET (0x7F0C - 0x730C) +#define EVERGREEN_DP2_REGISTER_OFFSET (0x10B0C - 0x730C) +#define EVERGREEN_DP3_REGISTER_OFFSET (0x1170C - 0x730C) +#define EVERGREEN_DP4_REGISTER_OFFSET (0x1230C - 0x730C) +#define EVERGREEN_DP5_REGISTER_OFFSET (0x12F0C - 0x730C) + + +#define EVERGREEN_DP_VID_STREAM_CNTL 0x730C +# define EVERGREEN_DP_VID_STREAM_CNTL_ENABLE (1 << 0) +# define EVERGREEN_DP_VID_STREAM_STATUS (1 <<16) +#define EVERGREEN_DP_STEER_FIFO 0x7310 +# define EVERGREEN_DP_STEER_FIFO_RESET (1 << 0) +#define EVERGREEN_DP_SEC_CNTL 0x7280 +# define EVERGREEN_DP_SEC_STREAM_ENABLE (1 << 0) +# define EVERGREEN_DP_SEC_ASP_ENABLE (1 << 4) +# define EVERGREEN_DP_SEC_ATP_ENABLE (1 << 8) +# define EVERGREEN_DP_SEC_AIP_ENABLE (1 << 12) +# define EVERGREEN_DP_SEC_GSP_ENABLE (1 << 20) +# define EVERGREEN_DP_SEC_AVI_ENABLE (1 << 24) +# define EVERGREEN_DP_SEC_MPG_ENABLE (1 << 28) +#define EVERGREEN_DP_SEC_TIMESTAMP 0x72a4 +# define EVERGREEN_DP_SEC_TIMESTAMP_MODE(x) (((x) & 0x3) << 0) +#define EVERGREEN_DP_SEC_AUD_N 0x7294 +# define EVERGREEN_DP_SEC_N_BASE_MULTIPLE(x) (((x) & 0xf) << 24) +# define EVERGREEN_DP_SEC_SS_EN (1 << 28) + +/*DCIO_UNIPHY block*/ +#define NI_DCIO_UNIPHY0_UNIPHY_TX_CONTROL1 (0x6600 -0x6600) +#define NI_DCIO_UNIPHY1_UNIPHY_TX_CONTROL1 (0x6640 -0x6600) +#define NI_DCIO_UNIPHY2_UNIPHY_TX_CONTROL1 (0x6680 - 0x6600) +#define NI_DCIO_UNIPHY3_UNIPHY_TX_CONTROL1 (0x66C0 - 0x6600) +#define NI_DCIO_UNIPHY4_UNIPHY_TX_CONTROL1 (0x6700 - 0x6600) +#define NI_DCIO_UNIPHY5_UNIPHY_TX_CONTROL1 (0x6740 - 0x6600) + +#define NI_DCIO_UNIPHY0_PLL_CONTROL1 0x6618 +# define NI_DCIO_UNIPHY0_PLL_CONTROL1_ENABLE (1 << 0) #endif diff --git a/sys/dev/drm/radeon/evergreend.h b/sys/dev/drm/radeon/evergreend.h index b066d6711b..0b174e14e9 100644 --- a/sys/dev/drm/radeon/evergreend.h +++ b/sys/dev/drm/radeon/evergreend.h @@ -509,6 +509,12 @@ #define DCCG_AUDIO_DTO1_MODULE 0x05c4 #define DCCG_AUDIO_DTO1_LOAD 0x05c8 #define DCCG_AUDIO_DTO1_CNTL 0x05cc +# define DCCG_AUDIO_DTO1_USE_512FBR_DTO (1 << 3) + +#define DCE41_DENTIST_DISPCLK_CNTL 0x049c +# define DENTIST_DPREFCLK_WDIVIDER(x) (((x) & 0x7f) << 24) +# define DENTIST_DPREFCLK_WDIVIDER_MASK (0x7f << 24) +# define DENTIST_DPREFCLK_WDIVIDER_SHIFT 24 /* DCE 4.0 AFMT */ #define HDMI_CONTROL 0x7030 @@ -1190,6 +1196,10 @@ #define SOFT_RESET_REGBB (1 << 22) #define SOFT_RESET_ORB (1 << 23) +#define SRBM_READ_ERROR 0xE98 +#define SRBM_INT_CNTL 0xEA0 +#define SRBM_INT_ACK 0xEA8 + /* display watermarks */ #define DC_LB_MEMORY_SPLIT 0x6b0c #define PRIORITY_A_CNT 0x6b18 @@ -1515,6 +1525,7 @@ #define UVD_UDEC_DBW_ADDR_CONFIG 0xef54 #define UVD_RBC_RB_RPTR 0xf690 #define UVD_RBC_RB_WPTR 0xf694 +#define UVD_STATUS 0xf6bc /* * PM4 @@ -1678,6 +1689,36 @@ #define PACKET3_SET_CONTEXT_REG_INDIRECT 0x73 #define PACKET3_SET_RESOURCE_INDIRECT 0x74 #define PACKET3_SET_APPEND_CNT 0x75 +/* SET_APPEND_CNT - documentation + * 1. header + * 2. COMMAND + * 1:0 - SOURCE SEL + * 15:2 - Reserved + * 31:16 - WR_REG_OFFSET - context register to write source data to. + * (one of R_02872C_GDS_APPEND_COUNT_0-11) + * 3. CONTROL + * (for source == mem) + * 31:2 SRC_ADDRESS_LO + * 0:1 SWAP + * (for source == GDS) + * 31:0 GDS offset + * (for source == DATA) + * 31:0 DATA + * (for source == REG) + * 31:0 REG + * 4. SRC_ADDRESS_HI[7:0] + * kernel driver 2.44 only supports SRC == MEM. + */ +#define PACKET3_SET_APPEND_CNT_SRC_SELECT(x) ((x) << 0) +#define G_PACKET3_SET_APPEND_CNT_SRC_SELECT(x) ((x & 0x3) >> 0) +/* source is from the data in CONTROL */ +#define PACKET3_SAC_SRC_SEL_DATA 0x0 +/* source is from register */ +#define PACKET3_SAC_SRC_SEL_REG 0x1 +/* source is from GDS offset in CONTROL */ +#define PACKET3_SAC_SRC_SEL_GDS 0x2 +/* source is from memory address */ +#define PACKET3_SAC_SRC_SEL_MEM 0x3 #define SQ_RESOURCE_CONSTANT_WORD7_0 0x3001c #define S__SQ_CONSTANT_TYPE(x) (((x) & 3) << 30) @@ -1994,6 +2035,19 @@ #define GDS_ADDR_BASE 0x28720 +#define GDS_APPEND_COUNT_0 0x2872C +#define GDS_APPEND_COUNT_1 0x28730 +#define GDS_APPEND_COUNT_2 0x28734 +#define GDS_APPEND_COUNT_3 0x28738 +#define GDS_APPEND_COUNT_4 0x2873C +#define GDS_APPEND_COUNT_5 0x28740 +#define GDS_APPEND_COUNT_6 0x28744 +#define GDS_APPEND_COUNT_7 0x28748 +#define GDS_APPEND_COUNT_8 0x2874c +#define GDS_APPEND_COUNT_9 0x28750 +#define GDS_APPEND_COUNT_10 0x28754 +#define GDS_APPEND_COUNT_11 0x28758 + #define CB_IMMED0_BASE 0x28b9c #define CB_IMMED1_BASE 0x28ba0 #define CB_IMMED2_BASE 0x28ba4 diff --git a/sys/dev/drm/radeon/kv_dpm.c b/sys/dev/drm/radeon/kv_dpm.c index 78f10d0e23..199e68cd3d 100644 --- a/sys/dev/drm/radeon/kv_dpm.c +++ b/sys/dev/drm/radeon/kv_dpm.c @@ -1164,6 +1164,19 @@ void kv_dpm_enable_bapm(struct radeon_device *rdev, bool enable) } } +static void kv_enable_thermal_int(struct radeon_device *rdev, bool enable) +{ + u32 thermal_int; + + thermal_int = RREG32_SMC(CG_THERMAL_INT_CTRL); + if (enable) + thermal_int |= THERM_INTH_MASK | THERM_INTL_MASK; + else + thermal_int &= ~(THERM_INTH_MASK | THERM_INTL_MASK); + WREG32_SMC(CG_THERMAL_INT_CTRL, thermal_int); + +} + int kv_dpm_enable(struct radeon_device *rdev) { struct kv_power_info *pi = kv_get_pi(rdev); @@ -1275,8 +1288,7 @@ int kv_dpm_late_enable(struct radeon_device *rdev) DRM_ERROR("kv_set_thermal_temperature_range failed\n"); return ret; } - rdev->irq.dpm_thermal = true; - radeon_irq_set(rdev); + kv_enable_thermal_int(rdev, true); } /* powerdown unused blocks for now */ @@ -1307,6 +1319,7 @@ void kv_dpm_disable(struct radeon_device *rdev) kv_stop_dpm(rdev); kv_enable_ulv(rdev, false); kv_reset_am(rdev); + kv_enable_thermal_int(rdev, false); kv_update_current_ps(rdev, rdev->pm.dpm.boot_ps); } @@ -2146,7 +2159,7 @@ static void kv_apply_state_adjust_rules(struct radeon_device *rdev, if (pi->caps_stable_p_state) { stable_p_state_sclk = (max_limits->sclk * 75) / 100; - for (i = table->count - 1; i >= 0; i++) { + for (i = table->count - 1; i >= 0; i--) { if (stable_p_state_sclk >= table->entries[i].clk) { stable_p_state_sclk = table->entries[i].clk; break; @@ -2742,13 +2755,11 @@ int kv_dpm_init(struct radeon_device *rdev) pi->enable_auto_thermal_throttling = true; pi->disable_nb_ps3_in_battery = false; if (radeon_bapm == -1) { - /* There are stability issues reported on with - * bapm enabled on an asrock system. - */ - if (rdev->pdev->subsystem_vendor == 0x1849) - pi->bapm_enable = false; + /* only enable bapm on KB, ML by default */ + if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) + pi->bapm_enable = true; else - pi->bapm_enable = true; + pi->bapm_enable = false; } else if (radeon_bapm == 0) { pi->bapm_enable = false; } else { @@ -2804,6 +2815,29 @@ void kv_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, } } +u32 kv_dpm_get_current_sclk(struct radeon_device *rdev) +{ + struct kv_power_info *pi = kv_get_pi(rdev); + u32 current_index = + (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_SCLK_INDEX_MASK) >> + CURR_SCLK_INDEX_SHIFT; + u32 sclk; + + if (current_index >= SMU__NUM_SCLK_DPM_STATE) { + return 0; + } else { + sclk = be32_to_cpu(pi->graphics_level[current_index].SclkFrequency); + return sclk; + } +} + +u32 kv_dpm_get_current_mclk(struct radeon_device *rdev) +{ + struct kv_power_info *pi = kv_get_pi(rdev); + + return pi->sys_info.bootup_uma_clk; +} + void kv_dpm_print_power_state(struct radeon_device *rdev, struct radeon_ps *rps) { @@ -2856,3 +2890,4 @@ u32 kv_dpm_get_mclk(struct radeon_device *rdev, bool low) return pi->sys_info.bootup_uma_clk; } + diff --git a/sys/dev/drm/radeon/ni.c b/sys/dev/drm/radeon/ni.c index 8cac7ebf0a..c56f9dafd3 100644 --- a/sys/dev/drm/radeon/ni.c +++ b/sys/dev/drm/radeon/ni.c @@ -26,6 +26,7 @@ #include #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include #include "nid.h" #include "atom.h" @@ -34,6 +35,31 @@ #include "radeon_ucode.h" #include "clearstate_cayman.h" +/* + * Indirect registers accessor + */ +u32 tn_smc_rreg(struct radeon_device *rdev, u32 reg) +{ + unsigned long flags; + u32 r; + + spin_lock_irqsave(&rdev->smc_idx_lock, flags); + WREG32(TN_SMC_IND_INDEX_0, (reg)); + r = RREG32(TN_SMC_IND_DATA_0); + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); + return r; +} + +void tn_smc_wreg(struct radeon_device *rdev, u32 reg, u32 v) +{ + unsigned long flags; + + spin_lock_irqsave(&rdev->smc_idx_lock, flags); + WREG32(TN_SMC_IND_INDEX_0, (reg)); + WREG32(TN_SMC_IND_DATA_0, (v)); + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); +} + static const u32 tn_rlc_save_restore_register_list[] = { 0x98fc, @@ -836,6 +862,35 @@ void ni_fini_microcode(struct radeon_device *rdev) rdev->smc_fw = NULL; } +/** + * cayman_get_allowed_info_register - fetch the register for the info ioctl + * + * @rdev: radeon_device pointer + * @reg: register offset in bytes + * @val: register value + * + * Returns 0 for success or -EINVAL for an invalid register + * + */ +int cayman_get_allowed_info_register(struct radeon_device *rdev, + u32 reg, u32 *val) +{ + switch (reg) { + case GRBM_STATUS: + case GRBM_STATUS_SE0: + case GRBM_STATUS_SE1: + case SRBM_STATUS: + case SRBM_STATUS2: + case (DMA_STATUS_REG + DMA0_REGISTER_OFFSET): + case (DMA_STATUS_REG + DMA1_REGISTER_OFFSET): + case UVD_STATUS: + *val = RREG32(reg); + return 0; + default: + return -EINVAL; + } +} + int tn_get_temp(struct radeon_device *rdev) { u32 temp = RREG32_SMC(TN_CURRENT_GNB_TEMP) & 0x7ff; @@ -970,6 +1025,8 @@ static void cayman_gpu_init(struct radeon_device *rdev) } WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff)); + WREG32(SRBM_INT_CNTL, 0x1); + WREG32(SRBM_INT_ACK, 0x1); evergreen_fix_pci_max_read_req_size(rdev); @@ -1094,12 +1151,12 @@ static void cayman_gpu_init(struct radeon_device *rdev) if ((rdev->config.cayman.max_backends_per_se == 1) && (rdev->flags & RADEON_IS_IGP)) { - if ((disabled_rb_mask & 3) == 1) { + if ((disabled_rb_mask & 3) == 2) { + /* RB1 disabled, RB0 enabled */ + tmp = 0x00000000; + } else { /* RB0 disabled, RB1 enabled */ tmp = 0x11111111; - } else { - /* RB1 disabled, RB0 enabled */ - tmp = 0x00000000; } } else { tmp = gb_addr_config & NUM_PIPES_MASK; @@ -1278,7 +1335,8 @@ static int cayman_pcie_gart_enable(struct radeon_device *rdev) */ for (i = 1; i < 8; i++) { WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR + (i << 2), 0); - WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR + (i << 2), rdev->vm_manager.max_pfn); + WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR + (i << 2), + rdev->vm_manager.max_pfn - 1); WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2), rdev->vm_manager.saved_table_addr[i]); } @@ -1910,10 +1968,15 @@ static void cayman_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) evergreen_print_gpu_status_regs(rdev); } -int cayman_asic_reset(struct radeon_device *rdev) +int cayman_asic_reset(struct radeon_device *rdev, bool hard) { u32 reset_mask; + if (hard) { + evergreen_gpu_pci_config_reset(rdev); + return 0; + } + reset_mask = cayman_gpu_check_soft_reset(rdev); if (reset_mask) @@ -1953,6 +2016,160 @@ bool cayman_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) return radeon_ring_test_lockup(rdev, ring); } +static void cayman_uvd_init(struct radeon_device *rdev) +{ + int r; + + if (!rdev->has_uvd) + return; + + r = radeon_uvd_init(rdev); + if (r) { + dev_err(rdev->dev, "failed UVD (%d) init.\n", r); + /* + * At this point rdev->uvd.vcpu_bo is NULL which trickles down + * to early fails uvd_v2_2_resume() and thus nothing happens + * there. So it is pointless to try to go through that code + * hence why we disable uvd here. + */ + rdev->has_uvd = 0; + return; + } + rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL; + r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX], 4096); +} + +static void cayman_uvd_start(struct radeon_device *rdev) +{ + int r; + + if (!rdev->has_uvd) + return; + + r = uvd_v2_2_resume(rdev); + if (r) { + dev_err(rdev->dev, "failed UVD resume (%d).\n", r); + goto error; + } + r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX); + if (r) { + dev_err(rdev->dev, "failed initializing UVD fences (%d).\n", r); + goto error; + } + return; + +error: + rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; +} + +static void cayman_uvd_resume(struct radeon_device *rdev) +{ + struct radeon_ring *ring; + int r; + + if (!rdev->has_uvd || !rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size) + return; + + ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; + r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2); + if (r) { + dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r); + return; + } + r = uvd_v1_0_init(rdev); + if (r) { + dev_err(rdev->dev, "failed initializing UVD (%d).\n", r); + return; + } +} + +static void cayman_vce_init(struct radeon_device *rdev) +{ + int r; + + /* Only set for CHIP_ARUBA */ + if (!rdev->has_vce) + return; + + r = radeon_vce_init(rdev); + if (r) { + dev_err(rdev->dev, "failed VCE (%d) init.\n", r); + /* + * At this point rdev->vce.vcpu_bo is NULL which trickles down + * to early fails cayman_vce_start() and thus nothing happens + * there. So it is pointless to try to go through that code + * hence why we disable vce here. + */ + rdev->has_vce = 0; + return; + } + rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_obj = NULL; + r600_ring_init(rdev, &rdev->ring[TN_RING_TYPE_VCE1_INDEX], 4096); + rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_obj = NULL; + r600_ring_init(rdev, &rdev->ring[TN_RING_TYPE_VCE2_INDEX], 4096); +} + +static void cayman_vce_start(struct radeon_device *rdev) +{ + int r; + + if (!rdev->has_vce) + return; + + r = radeon_vce_resume(rdev); + if (r) { + dev_err(rdev->dev, "failed VCE resume (%d).\n", r); + goto error; + } + r = vce_v1_0_resume(rdev); + if (r) { + dev_err(rdev->dev, "failed VCE resume (%d).\n", r); + goto error; + } + r = radeon_fence_driver_start_ring(rdev, TN_RING_TYPE_VCE1_INDEX); + if (r) { + dev_err(rdev->dev, "failed initializing VCE1 fences (%d).\n", r); + goto error; + } + r = radeon_fence_driver_start_ring(rdev, TN_RING_TYPE_VCE2_INDEX); + if (r) { + dev_err(rdev->dev, "failed initializing VCE2 fences (%d).\n", r); + goto error; + } + return; + +error: + rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size = 0; + rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_size = 0; +} + +static void cayman_vce_resume(struct radeon_device *rdev) +{ + struct radeon_ring *ring; + int r; + + if (!rdev->has_vce || !rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size) + return; + + ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; + r = radeon_ring_init(rdev, ring, ring->ring_size, 0, 0x0); + if (r) { + dev_err(rdev->dev, "failed initializing VCE1 ring (%d).\n", r); + return; + } + ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; + r = radeon_ring_init(rdev, ring, ring->ring_size, 0, 0x0); + if (r) { + dev_err(rdev->dev, "failed initializing VCE1 ring (%d).\n", r); + return; + } + r = vce_v1_0_init(rdev); + if (r) { + dev_err(rdev->dev, "failed initializing VCE (%d).\n", r); + return; + } +} + static int cayman_startup(struct radeon_device *rdev) { struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; @@ -2007,15 +2224,8 @@ static int cayman_startup(struct radeon_device *rdev) return r; } - r = uvd_v2_2_resume(rdev); - if (!r) { - r = radeon_fence_driver_start_ring(rdev, - R600_RING_TYPE_UVD_INDEX); - if (r) - dev_err(rdev->dev, "UVD fences init error (%d).\n", r); - } - if (r) - rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; + cayman_uvd_start(rdev); + cayman_vce_start(rdev); r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_CP1_INDEX); if (r) { @@ -2084,15 +2294,8 @@ static int cayman_startup(struct radeon_device *rdev) if (r) return r; - ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; - if (ring->ring_size) { - r = radeon_ring_init(rdev, ring, ring->ring_size, 0, - RADEON_CP_PACKET2); - if (!r) - r = uvd_v1_0_init(rdev); - if (r) - DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); - } + cayman_uvd_resume(rdev); + cayman_vce_resume(rdev); r = radeon_ib_pool_init(rdev); if (r) { @@ -2106,15 +2309,9 @@ static int cayman_startup(struct radeon_device *rdev) return r; } - if (ASIC_IS_DCE6(rdev)) { - r = dce6_audio_init(rdev); - if (r) - return r; - } else { - r = r600_audio_init(rdev); - if (r) - return r; - } + r = radeon_audio_init(rdev); + if (r) + return r; return 0; } @@ -2149,15 +2346,14 @@ int cayman_resume(struct radeon_device *rdev) int cayman_suspend(struct radeon_device *rdev) { radeon_pm_suspend(rdev); - if (ASIC_IS_DCE6(rdev)) - dce6_audio_fini(rdev); - else - r600_audio_fini(rdev); + radeon_audio_fini(rdev); radeon_vm_manager_fini(rdev); cayman_cp_enable(rdev, false); cayman_dma_stop(rdev); + if (rdev->has_uvd) { uvd_v1_0_fini(rdev); radeon_uvd_suspend(rdev); + } evergreen_irq_suspend(rdev); radeon_wb_disable(rdev); cayman_pcie_gart_disable(rdev); @@ -2251,12 +2447,8 @@ int cayman_init(struct radeon_device *rdev) ring->ring_obj = NULL; r600_ring_init(rdev, ring, 64 * 1024); - r = radeon_uvd_init(rdev); - if (!r) { - ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; - ring->ring_obj = NULL; - r600_ring_init(rdev, ring, 4096); - } + cayman_uvd_init(rdev); + cayman_vce_init(rdev); rdev->ih.ring_obj = NULL; r600_ih_ring_init(rdev, 64 * 1024); @@ -2311,6 +2503,8 @@ void cayman_fini(struct radeon_device *rdev) radeon_irq_kms_fini(rdev); uvd_v1_0_fini(rdev); radeon_uvd_fini(rdev); + if (rdev->has_vce) + radeon_vce_fini(rdev); cayman_pcie_gart_fini(rdev); r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); @@ -2512,15 +2706,11 @@ void cayman_vm_decode_fault(struct radeon_device *rdev, * Update the page table base and flush the VM TLB * using the CP (cayman-si). */ -void cayman_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) +void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, + unsigned vm_id, uint64_t pd_addr) { - struct radeon_ring *ring = &rdev->ring[ridx]; - - if (vm == NULL) - return; - - radeon_ring_write(ring, PACKET0(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2), 0)); - radeon_ring_write(ring, vm->pd_gpu_addr >> 12); + radeon_ring_write(ring, PACKET0(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm_id << 2), 0)); + radeon_ring_write(ring, pd_addr >> 12); /* flush hdp cache */ radeon_ring_write(ring, PACKET0(HDP_MEM_COHERENCY_FLUSH_CNTL, 0)); @@ -2528,9 +2718,50 @@ void cayman_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) /* bits 0-7 are the VM contexts0-7 */ radeon_ring_write(ring, PACKET0(VM_INVALIDATE_REQUEST, 0)); - radeon_ring_write(ring, 1 << vm->id); + radeon_ring_write(ring, 1 << vm_id); + + /* wait for the invalidate to complete */ + radeon_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5)); + radeon_ring_write(ring, (WAIT_REG_MEM_FUNCTION(0) | /* always */ + WAIT_REG_MEM_ENGINE(0))); /* me */ + radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); + radeon_ring_write(ring, 0); + radeon_ring_write(ring, 0); /* ref */ + radeon_ring_write(ring, 0); /* mask */ + radeon_ring_write(ring, 0x20); /* poll interval */ /* sync PFP to ME, otherwise we might get invalid PFP reads */ radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0)); radeon_ring_write(ring, 0x0); } + +int tn_set_vce_clocks(struct radeon_device *rdev, u32 evclk, u32 ecclk) +{ + struct atom_clock_dividers dividers; + int r, i; + + r = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, + ecclk, false, ÷rs); + if (r) + return r; + + for (i = 0; i < 100; i++) { + if (RREG32(CG_ECLK_STATUS) & ECLK_STATUS) + break; + mdelay(10); + } + if (i == 100) + return -ETIMEDOUT; + + WREG32_P(CG_ECLK_CNTL, dividers.post_div, ~(ECLK_DIR_CNTL_EN|ECLK_DIVIDER_MASK)); + + for (i = 0; i < 100; i++) { + if (RREG32(CG_ECLK_STATUS) & ECLK_STATUS) + break; + mdelay(10); + } + if (i == 100) + return -ETIMEDOUT; + + return 0; +} diff --git a/sys/dev/drm/radeon/ni_dma.c b/sys/dev/drm/radeon/ni_dma.c index 382c147672..33c9409092 100644 --- a/sys/dev/drm/radeon/ni_dma.c +++ b/sys/dev/drm/radeon/ni_dma.c @@ -371,7 +371,6 @@ void cayman_dma_vm_write_pages(struct radeon_device *rdev, for (; ndw > 0; ndw -= 2, --count, pe += 8) { if (flags & R600_PTE_SYSTEM) { value = radeon_vm_map_gart(rdev, addr); - value &= 0xFFFFFFFFFFFFF000ULL; } else if (flags & R600_PTE_VALID) { value = addr; } else { @@ -446,16 +445,12 @@ void cayman_dma_vm_pad_ib(struct radeon_ib *ib) ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0); } -void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) +void cayman_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, + unsigned vm_id, uint64_t pd_addr) { - struct radeon_ring *ring = &rdev->ring[ridx]; - - if (vm == NULL) - return; - radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0)); - radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2)); - radeon_ring_write(ring, vm->pd_gpu_addr >> 12); + radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm_id << 2)) >> 2)); + radeon_ring_write(ring, pd_addr >> 12); /* flush hdp cache */ radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0)); @@ -465,5 +460,11 @@ void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm /* bits 0-7 are the VM contexts0-7 */ radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0)); radeon_ring_write(ring, (0xf << 16) | (VM_INVALIDATE_REQUEST >> 2)); - radeon_ring_write(ring, 1 << vm->id); + radeon_ring_write(ring, 1 << vm_id); + + /* wait for invalidate to complete */ + radeon_ring_write(ring, DMA_SRBM_READ_PACKET); + radeon_ring_write(ring, (0xff << 20) | (VM_INVALIDATE_REQUEST >> 2)); + radeon_ring_write(ring, 0); /* mask */ + radeon_ring_write(ring, 0); /* value */ } diff --git a/sys/dev/drm/radeon/ni_dpm.c b/sys/dev/drm/radeon/ni_dpm.c index dc40999787..a70846216c 100644 --- a/sys/dev/drm/radeon/ni_dpm.c +++ b/sys/dev/drm/radeon/ni_dpm.c @@ -1621,9 +1621,7 @@ static int ni_populate_memory_timing_parameters(struct radeon_device *rdev, (u8)rv770_calculate_memory_refresh_rate(rdev, pl->sclk); - radeon_atom_set_engine_dram_timings(rdev, - pl->sclk, - pl->mclk); + radeon_atom_set_engine_dram_timings(rdev, pl->sclk, pl->mclk); dram_timing = RREG32(MC_ARB_DRAM_TIMING); dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2); @@ -4319,6 +4317,42 @@ void ni_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, } } +u32 ni_dpm_get_current_sclk(struct radeon_device *rdev) +{ + struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); + struct radeon_ps *rps = &eg_pi->current_rps; + struct ni_ps *ps = ni_get_ps(rps); + struct rv7xx_pl *pl; + u32 current_index = + (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >> + CURRENT_STATE_INDEX_SHIFT; + + if (current_index >= ps->performance_level_count) { + return 0; + } else { + pl = &ps->performance_levels[current_index]; + return pl->sclk; + } +} + +u32 ni_dpm_get_current_mclk(struct radeon_device *rdev) +{ + struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); + struct radeon_ps *rps = &eg_pi->current_rps; + struct ni_ps *ps = ni_get_ps(rps); + struct rv7xx_pl *pl; + u32 current_index = + (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >> + CURRENT_STATE_INDEX_SHIFT; + + if (current_index >= ps->performance_level_count) { + return 0; + } else { + pl = &ps->performance_levels[current_index]; + return pl->mclk; + } +} + u32 ni_dpm_get_sclk(struct radeon_device *rdev, bool low) { struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); diff --git a/sys/dev/drm/radeon/nid.h b/sys/dev/drm/radeon/nid.h index 2e12e4d692..47eb49b77d 100644 --- a/sys/dev/drm/radeon/nid.h +++ b/sys/dev/drm/radeon/nid.h @@ -46,6 +46,13 @@ #define DMIF_ADDR_CONFIG 0xBD4 +/* fusion vce clocks */ +#define CG_ECLK_CNTL 0x620 +# define ECLK_DIVIDER_MASK 0x7f +# define ECLK_DIR_CNTL_EN (1 << 8) +#define CG_ECLK_STATUS 0x624 +# define ECLK_STATUS (1 << 0) + /* DCE6 only */ #define DMIF_ADDR_CALC 0xC00 @@ -82,6 +89,10 @@ #define SOFT_RESET_REGBB (1 << 22) #define SOFT_RESET_ORB (1 << 23) +#define SRBM_READ_ERROR 0xE98 +#define SRBM_INT_CNTL 0xEA0 +#define SRBM_INT_ACK 0xEA8 + #define SRBM_STATUS2 0x0EC4 #define DMA_BUSY (1 << 5) #define DMA1_BUSY (1 << 6) @@ -812,6 +823,52 @@ #define MC_PMG_CMD_MRS2 0x2b5c #define MC_SEQ_PMG_CMD_MRS2_LP 0x2b60 +#define AUX_CONTROL 0x6200 +#define AUX_EN (1 << 0) +#define AUX_LS_READ_EN (1 << 8) +#define AUX_LS_UPDATE_DISABLE(x) (((x) & 0x1) << 12) +#define AUX_HPD_DISCON(x) (((x) & 0x1) << 16) +#define AUX_DET_EN (1 << 18) +#define AUX_HPD_SEL(x) (((x) & 0x7) << 20) +#define AUX_IMPCAL_REQ_EN (1 << 24) +#define AUX_TEST_MODE (1 << 28) +#define AUX_DEGLITCH_EN (1 << 29) +#define AUX_SW_CONTROL 0x6204 +#define AUX_SW_GO (1 << 0) +#define AUX_LS_READ_TRIG (1 << 2) +#define AUX_SW_START_DELAY(x) (((x) & 0xf) << 4) +#define AUX_SW_WR_BYTES(x) (((x) & 0x1f) << 16) + +#define AUX_SW_INTERRUPT_CONTROL 0x620c +#define AUX_SW_DONE_INT (1 << 0) +#define AUX_SW_DONE_ACK (1 << 1) +#define AUX_SW_DONE_MASK (1 << 2) +#define AUX_SW_LS_DONE_INT (1 << 4) +#define AUX_SW_LS_DONE_MASK (1 << 6) +#define AUX_SW_STATUS 0x6210 +#define AUX_SW_DONE (1 << 0) +#define AUX_SW_REQ (1 << 1) +#define AUX_SW_RX_TIMEOUT_STATE(x) (((x) & 0x7) << 4) +#define AUX_SW_RX_TIMEOUT (1 << 7) +#define AUX_SW_RX_OVERFLOW (1 << 8) +#define AUX_SW_RX_HPD_DISCON (1 << 9) +#define AUX_SW_RX_PARTIAL_BYTE (1 << 10) +#define AUX_SW_NON_AUX_MODE (1 << 11) +#define AUX_SW_RX_MIN_COUNT_VIOL (1 << 12) +#define AUX_SW_RX_INVALID_STOP (1 << 14) +#define AUX_SW_RX_SYNC_INVALID_L (1 << 17) +#define AUX_SW_RX_SYNC_INVALID_H (1 << 18) +#define AUX_SW_RX_INVALID_START (1 << 19) +#define AUX_SW_RX_RECV_NO_DET (1 << 20) +#define AUX_SW_RX_RECV_INVALID_H (1 << 22) +#define AUX_SW_RX_RECV_INVALID_V (1 << 23) + +#define AUX_SW_DATA 0x6218 +#define AUX_SW_DATA_RW (1 << 0) +#define AUX_SW_DATA_MASK(x) (((x) & 0xff) << 8) +#define AUX_SW_DATA_INDEX(x) (((x) & 0x1f) << 16) +#define AUX_SW_AUTOINCREMENT_DISABLE (1 << 31) + #define LB_SYNC_RESET_SEL 0x6b28 #define LB_SYNC_RESET_SEL_MASK (3 << 0) #define LB_SYNC_RESET_SEL_SHIFT 0 @@ -1082,6 +1139,7 @@ #define UVD_UDEC_DBW_ADDR_CONFIG 0xEF54 #define UVD_RBC_RB_RPTR 0xF690 #define UVD_RBC_RB_WPTR 0xF694 +#define UVD_STATUS 0xf6bc /* * PM4 @@ -1133,6 +1191,23 @@ #define PACKET3_MEM_SEMAPHORE 0x39 #define PACKET3_MPEG_INDEX 0x3A #define PACKET3_WAIT_REG_MEM 0x3C +#define WAIT_REG_MEM_FUNCTION(x) ((x) << 0) + /* 0 - always + * 1 - < + * 2 - <= + * 3 - == + * 4 - != + * 5 - >= + * 6 - > + */ +#define WAIT_REG_MEM_MEM_SPACE(x) ((x) << 4) + /* 0 - reg + * 1 - mem + */ +#define WAIT_REG_MEM_ENGINE(x) ((x) << 8) + /* 0 - me + * 1 - pfp + */ #define PACKET3_MEM_WRITE 0x3D #define PACKET3_PFP_SYNC_ME 0x42 #define PACKET3_SURFACE_SYNC 0x43 @@ -1272,6 +1347,13 @@ (1 << 21) | \ (((n) & 0xFFFFF) << 0)) +#define DMA_SRBM_POLL_PACKET ((9 << 28) | \ + (1 << 27) | \ + (1 << 26)) + +#define DMA_SRBM_READ_PACKET ((9 << 28) | \ + (1 << 27)) + /* async DMA Packet types */ #define DMA_PACKET_WRITE 0x2 #define DMA_PACKET_COPY 0x3 diff --git a/sys/dev/drm/radeon/ppsmc.h b/sys/dev/drm/radeon/ppsmc.h index 5670b82912..7e5724a12f 100644 --- a/sys/dev/drm/radeon/ppsmc.h +++ b/sys/dev/drm/radeon/ppsmc.h @@ -56,6 +56,14 @@ #define PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE 0x20 #define PPSMC_STATEFLAG_DEEPSLEEP_BYPASS 0x40 +#define FDO_MODE_HARDWARE 0 +#define FDO_MODE_PIECE_WISE_LINEAR 1 + +enum FAN_CONTROL { + FAN_CONTROL_FUZZY, + FAN_CONTROL_TABLE +}; + #define PPSMC_Result_OK ((uint8_t)0x01) #define PPSMC_Result_Failed ((uint8_t)0xFF) @@ -79,6 +87,8 @@ typedef uint8_t PPSMC_Result; #define PPSMC_MSG_DisableCac ((uint8_t)0x54) #define PPSMC_TDPClampingActive ((uint8_t)0x59) #define PPSMC_TDPClampingInactive ((uint8_t)0x5A) +#define PPSMC_StartFanControl ((uint8_t)0x5B) +#define PPSMC_StopFanControl ((uint8_t)0x5C) #define PPSMC_MSG_NoDisplay ((uint8_t)0x5D) #define PPSMC_MSG_HasDisplay ((uint8_t)0x5E) #define PPSMC_MSG_UVDPowerOFF ((uint8_t)0x60) @@ -106,6 +116,7 @@ typedef uint8_t PPSMC_Result; #define PPSMC_MSG_SAMUDPM_SetEnabledMask ((uint16_t) 0x130) #define PPSMC_MSG_MCLKDPM_ForceState ((uint16_t) 0x131) #define PPSMC_MSG_MCLKDPM_NoForcedLevel ((uint16_t) 0x132) +#define PPSMC_MSG_Thermal_Cntl_Disable ((uint16_t) 0x133) #define PPSMC_MSG_Voltage_Cntl_Disable ((uint16_t) 0x135) #define PPSMC_MSG_PCIeDPM_Enable ((uint16_t) 0x136) #define PPSMC_MSG_PCIeDPM_Disable ((uint16_t) 0x13d) @@ -149,6 +160,10 @@ typedef uint8_t PPSMC_Result; #define PPSMC_MSG_MASTER_DeepSleep_ON ((uint16_t) 0x18F) #define PPSMC_MSG_MASTER_DeepSleep_OFF ((uint16_t) 0x190) #define PPSMC_MSG_Remove_DC_Clamp ((uint16_t) 0x191) +#define PPSMC_MSG_SetFanPwmMax ((uint16_t) 0x19A) + +#define PPSMC_MSG_ENABLE_THERMAL_DPM ((uint16_t) 0x19C) +#define PPSMC_MSG_DISABLE_THERMAL_DPM ((uint16_t) 0x19D) #define PPSMC_MSG_API_GetSclkFrequency ((uint16_t) 0x200) #define PPSMC_MSG_API_GetMclkFrequency ((uint16_t) 0x201) @@ -157,10 +172,11 @@ typedef uint8_t PPSMC_Result; #define PPSMC_MSG_DPM_Config ((uint32_t) 0x102) #define PPSMC_MSG_DPM_ForceState ((uint32_t) 0x104) #define PPSMC_MSG_PG_SIMD_Config ((uint32_t) 0x108) -#define PPSMC_MSG_DPM_N_LevelsDisabled ((uint32_t) 0x112) +#define PPSMC_MSG_Thermal_Cntl_Enable ((uint32_t) 0x10a) #define PPSMC_MSG_Voltage_Cntl_Enable ((uint32_t) 0x109) #define PPSMC_MSG_VCEPowerOFF ((uint32_t) 0x10e) #define PPSMC_MSG_VCEPowerON ((uint32_t) 0x10f) +#define PPSMC_MSG_DPM_N_LevelsDisabled ((uint32_t) 0x112) #define PPSMC_MSG_DCE_RemoveVoltageAdjustment ((uint32_t) 0x11d) #define PPSMC_MSG_DCE_AllowVoltageAdjustment ((uint32_t) 0x11e) #define PPSMC_MSG_EnableBAPM ((uint32_t) 0x120) diff --git a/sys/dev/drm/radeon/pptable.h b/sys/dev/drm/radeon/pptable.h index b572616a08..8118c6f159 100644 --- a/sys/dev/drm/radeon/pptable.h +++ b/sys/dev/drm/radeon/pptable.h @@ -96,6 +96,14 @@ typedef struct _ATOM_PPLIB_FANTABLE2 USHORT usTMax; // The max temperature } ATOM_PPLIB_FANTABLE2; +typedef struct _ATOM_PPLIB_FANTABLE3 +{ + ATOM_PPLIB_FANTABLE2 basicTable2; + UCHAR ucFanControlMode; + USHORT usFanPWMMax; + USHORT usFanOutputSensitivity; +} ATOM_PPLIB_FANTABLE3; + typedef struct _ATOM_PPLIB_EXTENDEDHEADER { USHORT usSize; diff --git a/sys/dev/drm/radeon/r100.c b/sys/dev/drm/radeon/r100.c index 7ebb73da0d..b36f79556c 100644 --- a/sys/dev/drm/radeon/r100.c +++ b/sys/dev/drm/radeon/r100.c @@ -153,7 +153,7 @@ void r100_wait_for_vblank(struct radeon_device *rdev, int crtc) * bit to go high, when it does, we release the lock, and allow the * double buffered update to take place. */ -void r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) +void r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base, bool async) { struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; u32 tmp = ((u32)crtc_base) | RADEON_CRTC_OFFSET__OFFSET_LOCK; @@ -592,7 +592,8 @@ void r100_hpd_init(struct radeon_device *rdev) list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); - enable |= 1 << radeon_connector->hpd.hpd; + if (radeon_connector->hpd.hpd != RADEON_HPD_NONE) + enable |= 1 << radeon_connector->hpd.hpd; radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); } radeon_irq_kms_enable_hpd(rdev, enable); @@ -614,7 +615,8 @@ void r100_hpd_fini(struct radeon_device *rdev) list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); - disable |= 1 << radeon_connector->hpd.hpd; + if (radeon_connector->hpd.hpd != RADEON_HPD_NONE) + disable |= 1 << radeon_connector->hpd.hpd; } radeon_irq_kms_disable_hpd(rdev, disable); } @@ -644,6 +646,7 @@ int r100_pci_gart_init(struct radeon_device *rdev) return r; rdev->gart.table_size = rdev->gart.num_gpu_pages * 4; rdev->asic->gart.tlb_flush = &r100_pci_gart_tlb_flush; + rdev->asic->gart.get_page_entry = &r100_pci_gart_get_page_entry; rdev->asic->gart.set_page = &r100_pci_gart_set_page; return radeon_gart_table_ram_alloc(rdev); } @@ -681,11 +684,16 @@ void r100_pci_gart_disable(struct radeon_device *rdev) WREG32(RADEON_AIC_HI_ADDR, 0); } +uint64_t r100_pci_gart_get_page_entry(uint64_t addr, uint32_t flags) +{ + return addr; +} + void r100_pci_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags) + uint64_t entry) { u32 *gtt = rdev->gart.ptr; - gtt[i] = cpu_to_le32(lower_32_bits(addr)); + gtt[i] = cpu_to_le32(lower_32_bits(entry)); } void r100_pci_gart_fini(struct radeon_device *rdev) @@ -722,6 +730,10 @@ int r100_irq_set(struct radeon_device *rdev) tmp |= RADEON_FP2_DETECT_MASK; } WREG32(RADEON_GEN_INT_CNTL, tmp); + + /* read back to post the write */ + RREG32(RADEON_GEN_INT_CNTL); + return 0; } @@ -938,6 +950,10 @@ int r100_copy_blit(struct radeon_device *rdev, RADEON_WAIT_DMA_GUI_IDLE); if (fence) { r = radeon_fence_emit(rdev, fence, RADEON_RING_TYPE_GFX_INDEX); + if (r) { + radeon_ring_unlock_undo(rdev, ring); + return r; + } } radeon_ring_unlock_commit(rdev, ring, false); return r; @@ -1265,7 +1281,7 @@ int r100_reloc_pitch_offset(struct radeon_cs_parser *p, int r; u32 tile_flags = 0; u32 tmp; - struct radeon_cs_reloc *reloc; + struct radeon_bo_list *reloc; u32 value; r = radeon_cs_packet_next_reloc(p, &reloc, 0); @@ -1304,7 +1320,7 @@ int r100_packet3_load_vbpntr(struct radeon_cs_parser *p, int idx) { unsigned c, i; - struct radeon_cs_reloc *reloc; + struct radeon_bo_list *reloc; struct r100_cs_track *track; int r = 0; volatile uint32_t *ib; @@ -1553,7 +1569,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p, struct radeon_cs_packet *pkt, unsigned idx, unsigned reg) { - struct radeon_cs_reloc *reloc; + struct radeon_bo_list *reloc; struct r100_cs_track *track; volatile uint32_t *ib; uint32_t tmp; @@ -1912,7 +1928,7 @@ int r100_cs_track_check_pkt3_indx_buffer(struct radeon_cs_parser *p, static int r100_packet3_check(struct radeon_cs_parser *p, struct radeon_cs_packet *pkt) { - struct radeon_cs_reloc *reloc; + struct radeon_bo_list *reloc; struct r100_cs_track *track; unsigned idx; volatile uint32_t *ib; @@ -2044,8 +2060,6 @@ int r100_cs_parse(struct radeon_cs_parser *p) do { r = radeon_cs_packet_parse(p, &pkt, p->idx); if (r) { - kfree(p->track); - p->track = NULL; return r; } p->idx += pkt.count + 2; @@ -2070,18 +2084,11 @@ int r100_cs_parse(struct radeon_cs_parser *p) default: DRM_ERROR("Unknown packet type %d !\n", pkt.type); - kfree(p->track); - p->track = NULL; return -EINVAL; } - if (r) { - kfree(p->track); - p->track = NULL; + if (r) return r; - } } while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); - kfree(p->track); - p->track = NULL; return 0; } @@ -2565,7 +2572,7 @@ void r100_bm_disable(struct radeon_device *rdev) mdelay(1); } -int r100_asic_reset(struct radeon_device *rdev) +int r100_asic_reset(struct radeon_device *rdev, bool hard) { struct r100_mc_save save; u32 status, tmp; @@ -2891,25 +2898,28 @@ static void r100_pll_errata_after_data(struct radeon_device *rdev) uint32_t r100_pll_rreg(struct radeon_device *rdev, uint32_t reg) { + unsigned long flags; uint32_t data; - spin_lock(&rdev->pll_idx_lock); + spin_lock_irqsave(&rdev->pll_idx_lock, flags); WREG8(RADEON_CLOCK_CNTL_INDEX, reg & 0x3f); r100_pll_errata_after_index(rdev); data = RREG32(RADEON_CLOCK_CNTL_DATA); r100_pll_errata_after_data(rdev); - spin_unlock(&rdev->pll_idx_lock); + spin_unlock_irqrestore(&rdev->pll_idx_lock, flags); return data; } void r100_pll_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) { - spin_lock(&rdev->pll_idx_lock); + unsigned long flags; + + spin_lock_irqsave(&rdev->pll_idx_lock, flags); WREG8(RADEON_CLOCK_CNTL_INDEX, ((reg & 0x3f) | RADEON_PLL_WR_EN)); r100_pll_errata_after_index(rdev); WREG32(RADEON_CLOCK_CNTL_DATA, v); r100_pll_errata_after_data(rdev); - spin_unlock(&rdev->pll_idx_lock); + spin_unlock_irqrestore(&rdev->pll_idx_lock, flags); } static void r100_set_safe_registers(struct radeon_device *rdev) @@ -3157,7 +3167,8 @@ void r100_bandwidth_update(struct radeon_device *rdev) { fixed20_12 trcd_ff, trp_ff, tras_ff, trbs_ff, tcas_ff; fixed20_12 sclk_ff, mclk_ff, sclk_eff_ff, sclk_delay_ff; - fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff, crit_point_ff; + fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff; + fixed20_12 crit_point_ff = {0}; uint32_t temp, data, mem_trcd, mem_trp, mem_tras; fixed20_12 memtcas_ff[8] = { dfixed_init(1), @@ -3211,7 +3222,7 @@ void r100_bandwidth_update(struct radeon_device *rdev) fixed20_12 min_mem_eff; fixed20_12 mc_latency_sclk, mc_latency_mclk, k1; fixed20_12 cur_latency_mclk, cur_latency_sclk; - fixed20_12 disp_latency, disp_latency_overhead, disp_drain_rate, + fixed20_12 disp_latency, disp_latency_overhead, disp_drain_rate = {0}, disp_drain_rate2, read_return_rate; fixed20_12 time_disp1_drop_priority; int c; @@ -3224,6 +3235,9 @@ void r100_bandwidth_update(struct radeon_device *rdev) uint32_t pixel_bytes1 = 0; uint32_t pixel_bytes2 = 0; + /* Guess line buffer size to be 8192 pixels */ + u32 lb_size = 8192; + if (!rdev->mode_info.mode_config_initialized) return; @@ -3638,6 +3652,13 @@ void r100_bandwidth_update(struct radeon_device *rdev) DRM_DEBUG_KMS("GRPH2_BUFFER_CNTL from to %x\n", (unsigned int)RREG32(RADEON_GRPH2_BUFFER_CNTL)); } + + /* Save number of lines the linebuffer leads before the scanout */ + if (mode1) + rdev->mode_info.crtcs[0]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode1->crtc_hdisplay); + + if (mode2) + rdev->mode_info.crtcs[1]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode2->crtc_hdisplay); } int r100_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) @@ -3728,11 +3749,19 @@ int r100_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); goto free_ib; } - r = radeon_fence_wait(ib.fence, false); - if (r) { - DRM_ERROR("radeon: fence wait failed (%d).\n", r); + r = radeon_fence_wait_timeout(ib.fence, false, usecs_to_jiffies( + RADEON_USEC_IB_TEST_TIMEOUT)); + if (r < 0) { + DRM_ERROR("radeon: fence wait failed (%d).\n", r); + goto free_ib; + } else if (r == 0) { + DRM_ERROR("radeon: fence wait timed out.\n"); +#if 0 + r = -ETIMEDOUT; goto free_ib; - } +#endif + } + r = 0; for (i = 0; i < rdev->usec_timeout; i++) { tmp = RREG32(scratch); if (tmp == 0xDEADBEEF) { @@ -4101,15 +4130,17 @@ int r100_init(struct radeon_device *rdev) uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg, bool always_indirect) { - if (reg < rdev->rmmio_size && !always_indirect) + unsigned long flags; + /* The mmio size is 64kb at minimum. Allows the if to be optimized out. */ + if ((reg < rdev->rmmio_size || reg < RADEON_MIN_MMIO_SIZE) && !always_indirect) return bus_read_4(rdev->rmmio, reg); else { uint32_t ret; - spin_lock(&rdev->mmio_idx_lock); + spin_lock_irqsave(&rdev->mmio_idx_lock, flags); bus_write_4(rdev->rmmio, RADEON_MM_INDEX, reg); ret = bus_read_4(rdev->rmmio, RADEON_MM_DATA); - spin_unlock(&rdev->mmio_idx_lock); + spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags); return ret; } @@ -4118,13 +4149,15 @@ uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg, void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v, bool always_indirect) { - if (reg < rdev->rmmio_size && !always_indirect) + unsigned long flags; + + if ((reg < rdev->rmmio_size || reg < RADEON_MIN_MMIO_SIZE) && !always_indirect) bus_write_4(rdev->rmmio, reg, v); else { - spin_lock(&rdev->mmio_idx_lock); + spin_lock_irqsave(&rdev->mmio_idx_lock, flags); bus_write_4(rdev->rmmio, RADEON_MM_INDEX, reg); bus_write_4(rdev->rmmio, RADEON_MM_DATA, v); - spin_unlock(&rdev->mmio_idx_lock); + spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags); } } diff --git a/sys/dev/drm/radeon/r200.c b/sys/dev/drm/radeon/r200.c index a3b9c1edc3..414c949bf3 100644 --- a/sys/dev/drm/radeon/r200.c +++ b/sys/dev/drm/radeon/r200.c @@ -120,6 +120,10 @@ int r200_copy_dma(struct radeon_device *rdev, radeon_ring_write(ring, RADEON_WAIT_DMA_GUI_IDLE); if (fence) { r = radeon_fence_emit(rdev, fence, RADEON_RING_TYPE_GFX_INDEX); + if (r) { + radeon_ring_unlock_undo(rdev, ring); + return r; + } } radeon_ring_unlock_commit(rdev, ring, false); return r; @@ -143,7 +147,7 @@ int r200_packet0_check(struct radeon_cs_parser *p, struct radeon_cs_packet *pkt, unsigned idx, unsigned reg) { - struct radeon_cs_reloc *reloc; + struct radeon_bo_list *reloc; struct r100_cs_track *track; volatile uint32_t *ib; uint32_t tmp; diff --git a/sys/dev/drm/radeon/r300.c b/sys/dev/drm/radeon/r300.c index c591aaf110..1b8da7f5cd 100644 --- a/sys/dev/drm/radeon/r300.c +++ b/sys/dev/drm/radeon/r300.c @@ -47,6 +47,31 @@ * tell. (Jerome Glisse) */ +/* + * Indirect registers accessor + */ +uint32_t rv370_pcie_rreg(struct radeon_device *rdev, uint32_t reg) +{ + unsigned long flags; + uint32_t r; + + spin_lock_irqsave(&rdev->pcie_idx_lock, flags); + WREG32(RADEON_PCIE_INDEX, ((reg) & rdev->pcie_reg_mask)); + r = RREG32(RADEON_PCIE_DATA); + spin_unlock_irqrestore(&rdev->pcie_idx_lock, flags); + return r; +} + +void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) +{ + unsigned long flags; + + spin_lock_irqsave(&rdev->pcie_idx_lock, flags); + WREG32(RADEON_PCIE_INDEX, ((reg) & rdev->pcie_reg_mask)); + WREG32(RADEON_PCIE_DATA, (v)); + spin_unlock_irqrestore(&rdev->pcie_idx_lock, flags); +} + /* * rv370,rv380 PCIE GART */ @@ -71,24 +96,29 @@ void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev) #define R300_PTE_WRITEABLE (1 << 2) #define R300_PTE_READABLE (1 << 3) +uint64_t rv370_pcie_gart_get_page_entry(uint64_t addr, uint32_t flags) +{ + addr = (lower_32_bits(addr) >> 8) | + ((upper_32_bits(addr) & 0xff) << 24); + if (flags & RADEON_GART_PAGE_READ) + addr |= R300_PTE_READABLE; + if (flags & RADEON_GART_PAGE_WRITE) + addr |= R300_PTE_WRITEABLE; + if (!(flags & RADEON_GART_PAGE_SNOOP)) + addr |= R300_PTE_UNSNOOPED; + return addr; +} + void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags) + uint64_t entry) { volatile uint32_t *ptr = rdev->gart.ptr; - addr = (lower_32_bits(addr) >> 8) | - ((upper_32_bits(addr) & 0xff) << 24); - if (flags & RADEON_GART_PAGE_READ) - addr |= R300_PTE_READABLE; - if (flags & RADEON_GART_PAGE_WRITE) - addr |= R300_PTE_WRITEABLE; - if (!(flags & RADEON_GART_PAGE_SNOOP)) - addr |= R300_PTE_UNSNOOPED; /* on x86 we want this to be CPU endian, on powerpc * on powerpc without HW swappers, it'll get swapped on way * into VRAM - so no need for cpu_to_le32 on VRAM tables */ ptr += i; - *ptr = (uint32_t)addr; + *ptr = (uint32_t)entry; } int rv370_pcie_gart_init(struct radeon_device *rdev) @@ -108,6 +138,7 @@ int rv370_pcie_gart_init(struct radeon_device *rdev) DRM_ERROR("Failed to register debugfs file for PCIE gart !\n"); rdev->gart.table_size = rdev->gart.num_gpu_pages * 4; rdev->asic->gart.tlb_flush = &rv370_pcie_gart_tlb_flush; + rdev->asic->gart.get_page_entry = &rv370_pcie_gart_get_page_entry; rdev->asic->gart.set_page = &rv370_pcie_gart_set_page; return radeon_gart_table_vram_alloc(rdev); } @@ -378,7 +409,7 @@ static void r300_gpu_init(struct radeon_device *rdev) rdev->num_gb_pipes, rdev->num_z_pipes); } -int r300_asic_reset(struct radeon_device *rdev) +int r300_asic_reset(struct radeon_device *rdev, bool hard) { struct r100_mc_save save; u32 status, tmp; @@ -597,7 +628,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p, struct radeon_cs_packet *pkt, unsigned idx, unsigned reg) { - struct radeon_cs_reloc *reloc; + struct radeon_bo_list *reloc; struct r100_cs_track *track; volatile uint32_t *ib; uint32_t tmp, tile_flags = 0; @@ -1141,7 +1172,7 @@ fail: static int r300_packet3_check(struct radeon_cs_parser *p, struct radeon_cs_packet *pkt) { - struct radeon_cs_reloc *reloc; + struct radeon_bo_list *reloc; struct r100_cs_track *track; volatile uint32_t *ib; unsigned idx; @@ -1260,8 +1291,6 @@ int r300_cs_parse(struct radeon_cs_parser *p) do { r = radeon_cs_packet_parse(p, &pkt, p->idx); if (r) { - kfree(p->track); - p->track = NULL; return r; } p->idx += pkt.count + 2; @@ -1279,18 +1308,12 @@ int r300_cs_parse(struct radeon_cs_parser *p) break; default: DRM_ERROR("Unknown packet type %d !\n", pkt.type); - kfree(p->track); - p->track = NULL; return -EINVAL; } if (r) { - kfree(p->track); - p->track = NULL; return r; } } while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); - kfree(p->track); - p->track = NULL; return 0; } diff --git a/sys/dev/drm/radeon/r420.c b/sys/dev/drm/radeon/r420.c index 976aa7fd70..b2f0dd7208 100644 --- a/sys/dev/drm/radeon/r420.c +++ b/sys/dev/drm/radeon/r420.c @@ -158,22 +158,25 @@ void r420_pipes_init(struct radeon_device *rdev) u32 r420_mc_rreg(struct radeon_device *rdev, u32 reg) { + unsigned long flags; u32 r; - spin_lock(&rdev->mc_idx_lock); + spin_lock_irqsave(&rdev->mc_idx_lock, flags); WREG32(R_0001F8_MC_IND_INDEX, S_0001F8_MC_IND_ADDR(reg)); r = RREG32(R_0001FC_MC_IND_DATA); - spin_unlock(&rdev->mc_idx_lock); + spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); return r; } void r420_mc_wreg(struct radeon_device *rdev, u32 reg, u32 v) { - spin_lock(&rdev->mc_idx_lock); + unsigned long flags; + + spin_lock_irqsave(&rdev->mc_idx_lock, flags); WREG32(R_0001F8_MC_IND_INDEX, S_0001F8_MC_IND_ADDR(reg) | S_0001F8_MC_IND_WR_EN(1)); WREG32(R_0001FC_MC_IND_DATA, v); - spin_unlock(&rdev->mc_idx_lock); + spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); } static void r420_debugfs(struct radeon_device *rdev) diff --git a/sys/dev/drm/radeon/r600.c b/sys/dev/drm/radeon/r600.c index a35a1dadb5..a1a03278cf 100644 --- a/sys/dev/drm/radeon/r600.c +++ b/sys/dev/drm/radeon/r600.c @@ -32,6 +32,7 @@ #include #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include "radeon_mode.h" #include "r600d.h" #include "atom.h" @@ -107,6 +108,79 @@ static void r600_gpu_init(struct radeon_device *rdev); void r600_irq_disable(struct radeon_device *rdev); static void r600_pcie_gen2_enable(struct radeon_device *rdev); +/* + * Indirect registers accessor + */ +u32 r600_rcu_rreg(struct radeon_device *rdev, u32 reg) +{ + unsigned long flags; + u32 r; + + spin_lock_irqsave(&rdev->rcu_idx_lock, flags); + WREG32(R600_RCU_INDEX, ((reg) & 0x1fff)); + r = RREG32(R600_RCU_DATA); + spin_unlock_irqrestore(&rdev->rcu_idx_lock, flags); + return r; +} + +void r600_rcu_wreg(struct radeon_device *rdev, u32 reg, u32 v) +{ + unsigned long flags; + + spin_lock_irqsave(&rdev->rcu_idx_lock, flags); + WREG32(R600_RCU_INDEX, ((reg) & 0x1fff)); + WREG32(R600_RCU_DATA, (v)); + spin_unlock_irqrestore(&rdev->rcu_idx_lock, flags); +} + +u32 r600_uvd_ctx_rreg(struct radeon_device *rdev, u32 reg) +{ + unsigned long flags; + u32 r; + + spin_lock_irqsave(&rdev->uvd_idx_lock, flags); + WREG32(R600_UVD_CTX_INDEX, ((reg) & 0x1ff)); + r = RREG32(R600_UVD_CTX_DATA); + spin_unlock_irqrestore(&rdev->uvd_idx_lock, flags); + return r; +} + +void r600_uvd_ctx_wreg(struct radeon_device *rdev, u32 reg, u32 v) +{ + unsigned long flags; + + spin_lock_irqsave(&rdev->uvd_idx_lock, flags); + WREG32(R600_UVD_CTX_INDEX, ((reg) & 0x1ff)); + WREG32(R600_UVD_CTX_DATA, (v)); + spin_unlock_irqrestore(&rdev->uvd_idx_lock, flags); +} + +/** + * r600_get_allowed_info_register - fetch the register for the info ioctl + * + * @rdev: radeon_device pointer + * @reg: register offset in bytes + * @val: register value + * + * Returns 0 for success or -EINVAL for an invalid register + * + */ +int r600_get_allowed_info_register(struct radeon_device *rdev, + u32 reg, u32 *val) +{ + switch (reg) { + case GRBM_STATUS: + case GRBM_STATUS2: + case R_000E50_SRBM_STATUS: + case DMA_STATUS_REG: + case UVD_STATUS: + *val = RREG32(reg); + return 0; + default: + return -EINVAL; + } +} + /** * r600_get_xclk - get the xclk * @@ -928,7 +1002,8 @@ void r600_hpd_init(struct radeon_device *rdev) break; } } - enable |= 1 << radeon_connector->hpd.hpd; + if (radeon_connector->hpd.hpd != RADEON_HPD_NONE) + enable |= 1 << radeon_connector->hpd.hpd; radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); } radeon_irq_kms_enable_hpd(rdev, enable); @@ -981,7 +1056,8 @@ void r600_hpd_fini(struct radeon_device *rdev) break; } } - disable |= 1 << radeon_connector->hpd.hpd; + if (radeon_connector->hpd.hpd != RADEON_HPD_NONE) + disable |= 1 << radeon_connector->hpd.hpd; } radeon_irq_kms_disable_hpd(rdev, disable); } @@ -1195,24 +1271,27 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev) uint32_t rs780_mc_rreg(struct radeon_device *rdev, uint32_t reg) { + unsigned long flags; uint32_t r; - spin_lock(&rdev->mc_idx_lock); + spin_lock_irqsave(&rdev->mc_idx_lock, flags); WREG32(R_0028F8_MC_INDEX, S_0028F8_MC_IND_ADDR(reg)); r = RREG32(R_0028FC_MC_DATA); WREG32(R_0028F8_MC_INDEX, ~C_0028F8_MC_IND_ADDR); - spin_unlock(&rdev->mc_idx_lock); + spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); return r; } void rs780_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) { - spin_lock(&rdev->mc_idx_lock); + unsigned long flags; + + spin_lock_irqsave(&rdev->mc_idx_lock, flags); WREG32(R_0028F8_MC_INDEX, S_0028F8_MC_IND_ADDR(reg) | S_0028F8_MC_IND_WR_EN(1)); WREG32(R_0028FC_MC_DATA, v); WREG32(R_0028F8_MC_INDEX, 0x7F); - spin_unlock(&rdev->mc_idx_lock); + spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); } static void r600_mc_program(struct radeon_device *rdev) @@ -1435,15 +1514,12 @@ int r600_vram_scratch_init(struct radeon_device *rdev) } r = radeon_bo_reserve(rdev->vram_scratch.robj, false); - if (unlikely(r != 0)) { - radeon_bo_unref(&rdev->vram_scratch.robj); - return r; - } + if (unlikely(r != 0)) + return r; r = radeon_bo_pin(rdev->vram_scratch.robj, RADEON_GEM_DOMAIN_VRAM, &rdev->vram_scratch.gpu_addr); if (r) { radeon_bo_unreserve(rdev->vram_scratch.robj); - radeon_bo_unref(&rdev->vram_scratch.robj); return r; } vram_scratch_ptr_ptr = &rdev->vram_scratch.ptr; @@ -1452,8 +1528,6 @@ int r600_vram_scratch_init(struct radeon_device *rdev) if (r) radeon_bo_unpin(rdev->vram_scratch.robj); radeon_bo_unreserve(rdev->vram_scratch.robj); - if (r) - radeon_bo_unref(&rdev->vram_scratch.robj); return r; } @@ -1801,10 +1875,15 @@ static void r600_gpu_pci_config_reset(struct radeon_device *rdev) } } -int r600_asic_reset(struct radeon_device *rdev) +int r600_asic_reset(struct radeon_device *rdev, bool hard) { u32 reset_mask; + if (hard) { + r600_gpu_pci_config_reset(rdev); + return 0; + } + reset_mask = r600_gpu_check_soft_reset(rdev); if (reset_mask) @@ -2312,24 +2391,27 @@ static void r600_gpu_init(struct radeon_device *rdev) */ u32 r600_pciep_rreg(struct radeon_device *rdev, u32 reg) { + unsigned long flags; u32 r; - spin_lock(&rdev->pciep_idx_lock); + spin_lock_irqsave(&rdev->pciep_idx_lock, flags); WREG32(PCIE_PORT_INDEX, ((reg) & 0xff)); (void)RREG32(PCIE_PORT_INDEX); r = RREG32(PCIE_PORT_DATA); - spin_unlock(&rdev->pciep_idx_lock); + spin_unlock_irqrestore(&rdev->pciep_idx_lock, flags); return r; } void r600_pciep_wreg(struct radeon_device *rdev, u32 reg, u32 v) { - spin_lock(&rdev->pciep_idx_lock); + unsigned long flags; + + spin_lock_irqsave(&rdev->pciep_idx_lock, flags); WREG32(PCIE_PORT_INDEX, ((reg) & 0xff)); (void)RREG32(PCIE_PORT_INDEX); WREG32(PCIE_PORT_DATA, (v)); (void)RREG32(PCIE_PORT_DATA); - spin_unlock(&rdev->pciep_idx_lock); + spin_unlock_irqrestore(&rdev->pciep_idx_lock, flags); } /* @@ -2985,6 +3067,73 @@ void r600_clear_surface_reg(struct radeon_device *rdev, int reg) /* FIXME: implement */ } +static void r600_uvd_init(struct radeon_device *rdev) +{ + int r; + + if (!rdev->has_uvd) + return; + + r = radeon_uvd_init(rdev); + if (r) { + dev_err(rdev->dev, "failed UVD (%d) init.\n", r); + /* + * At this point rdev->uvd.vcpu_bo is NULL which trickles down + * to early fails uvd_v1_0_resume() and thus nothing happens + * there. So it is pointless to try to go through that code + * hence why we disable uvd here. + */ + rdev->has_uvd = 0; + return; + } + rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL; + r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX], 4096); +} + +static void r600_uvd_start(struct radeon_device *rdev) +{ + int r; + + if (!rdev->has_uvd) + return; + + r = uvd_v1_0_resume(rdev); + if (r) { + dev_err(rdev->dev, "failed UVD resume (%d).\n", r); + goto error; + } + r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX); + if (r) { + dev_err(rdev->dev, "failed initializing UVD fences (%d).\n", r); + goto error; + } + return; + +error: + rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; +} + +static void r600_uvd_resume(struct radeon_device *rdev) +{ + struct radeon_ring *ring; + int r; + + if (!rdev->has_uvd || !rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size) + return; + + ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; + r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2); + if (r) { + dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r); + return; + } + r = uvd_v1_0_init(rdev); + if (r) { + dev_err(rdev->dev, "failed initializing UVD (%d).\n", r); + return; + } +} + static int r600_startup(struct radeon_device *rdev) { struct radeon_ring *ring; @@ -3020,17 +3169,7 @@ static int r600_startup(struct radeon_device *rdev) return r; } - if (rdev->has_uvd) { - r = uvd_v1_0_resume(rdev); - if (!r) { - r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX); - if (r) { - dev_err(rdev->dev, "failed initializing UVD fences (%d).\n", r); - } - } - if (r) - rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; - } + r600_uvd_start(rdev); /* Enable IRQ */ if (!rdev->irq.installed) { @@ -3060,17 +3199,7 @@ static int r600_startup(struct radeon_device *rdev) if (r) return r; - if (rdev->has_uvd) { - ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; - if (ring->ring_size) { - r = radeon_ring_init(rdev, ring, ring->ring_size, 0, - RADEON_CP_PACKET2); - if (!r) - r = uvd_v1_0_init(rdev); - if (r) - DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); - } - } + r600_uvd_resume(rdev); r = radeon_ib_pool_init(rdev); if (r) { @@ -3078,7 +3207,7 @@ static int r600_startup(struct radeon_device *rdev) return r; } - r = r600_audio_init(rdev); + r = radeon_audio_init(rdev); if (r) { DRM_ERROR("radeon: audio init failed\n"); return r; @@ -3129,7 +3258,7 @@ int r600_resume(struct radeon_device *rdev) int r600_suspend(struct radeon_device *rdev) { radeon_pm_suspend(rdev); - r600_audio_fini(rdev); + radeon_audio_fini(rdev); r600_cp_stop(rdev); if (rdev->has_uvd) { uvd_v1_0_fini(rdev); @@ -3214,13 +3343,7 @@ int r600_init(struct radeon_device *rdev) rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL; r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024); - if (rdev->has_uvd) { - r = radeon_uvd_init(rdev); - if (!r) { - rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL; - r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX], 4096); - } - } + r600_uvd_init(rdev); rdev->ih.ring_obj = NULL; r600_ih_ring_init(rdev, 64 * 1024); @@ -3248,7 +3371,7 @@ int r600_init(struct radeon_device *rdev) void r600_fini(struct radeon_device *rdev) { radeon_pm_fini(rdev); - r600_audio_fini(rdev); + radeon_audio_fini(rdev); r600_cp_fini(rdev); r600_irq_fini(rdev); if (rdev->has_uvd) { @@ -3332,11 +3455,19 @@ int r600_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); goto free_ib; } - r = radeon_fence_wait(ib.fence, false); - if (r) { - DRM_ERROR("radeon: fence wait failed (%d).\n", r); + r = radeon_fence_wait_timeout(ib.fence, false, usecs_to_jiffies( + RADEON_USEC_IB_TEST_TIMEOUT)); + if (r < 0) { + DRM_ERROR("radeon: fence wait failed (%d).\n", r); + goto free_ib; + } else if (r == 0) { + DRM_ERROR("radeon: fence wait timed out.\n"); +#if 0 + r = -ETIMEDOUT; goto free_ib; - } +#endif + } + r = 0; for (i = 0; i < rdev->usec_timeout; i++) { tmp = RREG32(scratch); if (tmp == 0xDEADBEEF) @@ -3396,28 +3527,22 @@ int r600_ih_ring_alloc(struct radeon_device *rdev) return r; } r = radeon_bo_reserve(rdev->ih.ring_obj, false); - if (unlikely(r != 0)) { - radeon_bo_unref(&rdev->ih.ring_obj); - return r; - } + if (unlikely(r != 0)) + return r; r = radeon_bo_pin(rdev->ih.ring_obj, RADEON_GEM_DOMAIN_GTT, (u64 *)&rdev->ih.gpu_addr); if (r) { radeon_bo_unreserve(rdev->ih.ring_obj); - radeon_bo_unref(&rdev->ih.ring_obj); DRM_ERROR("radeon: failed to pin ih ring buffer (%d).\n", r); return r; } ring_ptr = &rdev->ih.ring; r = radeon_bo_kmap(rdev->ih.ring_obj, ring_ptr); - if (r) - radeon_bo_unpin(rdev->ih.ring_obj); radeon_bo_unreserve(rdev->ih.ring_obj); if (r) { DRM_ERROR("radeon: failed to map ih ring buffer (%d).\n", r); - radeon_bo_unref(&rdev->ih.ring_obj); return r; } } @@ -3816,6 +3941,9 @@ int r600_irq_set(struct radeon_device *rdev) WREG32(RV770_CG_THERMAL_INT, thermal_int); } + /* posting read */ + RREG32(R_000E50_SRBM_STATUS); + return 0; } @@ -4024,7 +4152,7 @@ restart_ih: return IRQ_NONE; rptr = rdev->ih.rptr; - DRM_DEBUG_VBLANK("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr); + DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr); /* Order reading of wptr vs. reading of IH ring data */ rmb(); @@ -4042,23 +4170,27 @@ restart_ih: case 1: /* D1 vblank/vline */ switch (src_data) { case 0: /* D1 vblank */ - if (rdev->irq.stat_regs.r600.disp_int & LB_D1_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[0]) { - drm_handle_vblank(rdev->ddev, 0); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[0])) - radeon_crtc_handle_vblank(rdev, 0); - rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VBLANK_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D1 vblank\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int & LB_D1_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D1 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[0]) { + drm_handle_vblank(rdev->ddev, 0); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (atomic_read(&rdev->irq.pflip[0])) + radeon_crtc_handle_vblank(rdev, 0); + rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D1 vblank\n"); + break; case 1: /* D1 vline */ - if (rdev->irq.stat_regs.r600.disp_int & LB_D1_VLINE_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VLINE_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D1 vline\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int & LB_D1_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D1 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VLINE_INTERRUPT; + DRM_DEBUG("IH: D1 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -4068,23 +4200,27 @@ restart_ih: case 5: /* D2 vblank/vline */ switch (src_data) { case 0: /* D2 vblank */ - if (rdev->irq.stat_regs.r600.disp_int & LB_D2_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[1]) { - drm_handle_vblank(rdev->ddev, 1); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[1])) - radeon_crtc_handle_vblank(rdev, 1); - rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VBLANK_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D2 vblank\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int & LB_D2_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D2 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[1]) { + drm_handle_vblank(rdev->ddev, 1); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (atomic_read(&rdev->irq.pflip[1])) + radeon_crtc_handle_vblank(rdev, 1); + rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D2 vblank\n"); + break; case 1: /* D1 vline */ - if (rdev->irq.stat_regs.r600.disp_int & LB_D2_VLINE_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VLINE_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D2 vline\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int & LB_D2_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D2 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VLINE_INTERRUPT; + DRM_DEBUG("IH: D2 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -4092,58 +4228,65 @@ restart_ih: } break; case 9: /* D1 pflip */ - DRM_DEBUG_VBLANK("IH: D1 flip\n"); + DRM_DEBUG("IH: D1 flip\n"); if (radeon_use_pflipirq > 0) radeon_crtc_handle_flip(rdev, 0); break; case 11: /* D2 pflip */ - DRM_DEBUG_VBLANK("IH: D2 flip\n"); + DRM_DEBUG("IH: D2 flip\n"); if (radeon_use_pflipirq > 0) radeon_crtc_handle_flip(rdev, 1); break; case 19: /* HPD/DAC hotplug */ switch (src_data) { case 0: - if (rdev->irq.stat_regs.r600.disp_int & DC_HPD1_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD1_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD1\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int & DC_HPD1_INTERRUPT)) + DRM_DEBUG("IH: HPD1 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD1_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD1\n"); break; case 1: - if (rdev->irq.stat_regs.r600.disp_int & DC_HPD2_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD2_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD2\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int & DC_HPD2_INTERRUPT)) + DRM_DEBUG("IH: HPD2 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD2_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD2\n"); break; case 4: - if (rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD3_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD3_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD3\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD3_INTERRUPT)) + DRM_DEBUG("IH: HPD3 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD3_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD3\n"); break; case 5: - if (rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD4_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD4_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD4\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD4_INTERRUPT)) + DRM_DEBUG("IH: HPD4 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD4_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD4\n"); break; case 10: - if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD5_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD5_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD5\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD5_INTERRUPT)) + DRM_DEBUG("IH: HPD5 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD5_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD5\n"); break; case 12: - if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD6_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD6_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD6\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD6_INTERRUPT)) + DRM_DEBUG("IH: HPD6 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD6_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD6\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -4153,18 +4296,22 @@ restart_ih: case 21: /* hdmi */ switch (src_data) { case 4: - if (rdev->irq.stat_regs.r600.hdmi0_status & HDMI0_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.r600.hdmi0_status &= ~HDMI0_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI0\n"); - } + if (!(rdev->irq.stat_regs.r600.hdmi0_status & HDMI0_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: HDMI0 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.hdmi0_status &= ~HDMI0_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI0\n"); + break; case 5: - if (rdev->irq.stat_regs.r600.hdmi1_status & HDMI0_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.r600.hdmi1_status &= ~HDMI0_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI1\n"); - } + if (!(rdev->irq.stat_regs.r600.hdmi1_status & HDMI0_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: HDMI1 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.hdmi1_status &= ~HDMI0_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI1\n"); + break; default: DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -4404,7 +4551,7 @@ static void r600_pcie_gen2_enable(struct radeon_device *rdev) if (ret != 0) return; - if (!(mask & DRM_PCIE_SPEED_50)) + if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80))) return; speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); diff --git a/sys/dev/drm/radeon/r600_blit_shaders.c b/sys/dev/drm/radeon/r600_blit_shaders.c index 34c8b2340f..443cbe59b2 100644 --- a/sys/dev/drm/radeon/r600_blit_shaders.c +++ b/sys/dev/drm/radeon/r600_blit_shaders.c @@ -32,7 +32,7 @@ * 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 + * statically generated state tables. The register state and shaders * were hand generated to support blitting functionality. See the 3D * driver or documentation for descriptions of the registers and * shader instructions. diff --git a/sys/dev/drm/radeon/r600_cs.c b/sys/dev/drm/radeon/r600_cs.c index 2ded9cf4ad..634cba85aa 100644 --- a/sys/dev/drm/radeon/r600_cs.c +++ b/sys/dev/drm/radeon/r600_cs.c @@ -970,7 +970,7 @@ static int r600_cs_parse_packet0(struct radeon_cs_parser *p, static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) { struct r600_cs_track *track = (struct r600_cs_track *)p->track; - struct radeon_cs_reloc *reloc; + struct radeon_bo_list *reloc; u32 m, i, tmp, *ib; int r; @@ -1627,7 +1627,7 @@ static bool r600_is_safe_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) static int r600_packet3_check(struct radeon_cs_parser *p, struct radeon_cs_packet *pkt) { - struct radeon_cs_reloc *reloc; + struct radeon_bo_list *reloc; struct r600_cs_track *track; volatile u32 *ib; unsigned idx; @@ -2341,7 +2341,7 @@ int r600_cs_parse(struct radeon_cs_parser *p) * GPU offset using the provided start. **/ int r600_dma_cs_next_reloc(struct radeon_cs_parser *p, - struct radeon_cs_reloc **cs_reloc) + struct radeon_bo_list **cs_reloc) { struct radeon_cs_chunk *relocs_chunk; unsigned idx; @@ -2379,7 +2379,7 @@ int r600_dma_cs_next_reloc(struct radeon_cs_parser *p, int r600_dma_cs_parse(struct radeon_cs_parser *p) { struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx]; - struct radeon_cs_reloc *src_reloc, *dst_reloc; + struct radeon_bo_list *src_reloc, *dst_reloc; u32 header, cmd, count, tiled; volatile u32 *ib = p->ib.ptr; u32 idx, idx_value; diff --git a/sys/dev/drm/radeon/r600_dma.c b/sys/dev/drm/radeon/r600_dma.c index feb1f176d3..8a51bbdfc1 100644 --- a/sys/dev/drm/radeon/r600_dma.c +++ b/sys/dev/drm/radeon/r600_dma.c @@ -366,12 +366,18 @@ int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); return r; } - r = radeon_fence_wait(ib.fence, false); - if (r) { - radeon_ib_free(rdev, &ib); /* zRJ XXX culprit */ - DRM_ERROR("radeon: fence wait failed (%d).\n", r); - return r; - } + r = radeon_fence_wait_timeout(ib.fence, false, usecs_to_jiffies( + RADEON_USEC_IB_TEST_TIMEOUT)); + if (r < 0) { + DRM_ERROR("radeon: fence wait failed (%d).\n", r); + return r; + } else if (r == 0) { + DRM_ERROR("radeon: fence wait timed out.\n"); +#if 0 + return -ETIMEDOUT; +#endif + } + r = 0; for (i = 0; i < rdev->usec_timeout; i++) { tmp = le32_to_cpu(rdev->wb.wb[index/4]); if (tmp == 0xDEADBEEF) diff --git a/sys/dev/drm/radeon/r600_dpm.c b/sys/dev/drm/radeon/r600_dpm.c index 44d3464a54..d3add9ef95 100644 --- a/sys/dev/drm/radeon/r600_dpm.c +++ b/sys/dev/drm/radeon/r600_dpm.c @@ -188,7 +188,7 @@ u32 r600_dpm_get_vrefresh(struct radeon_device *rdev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { radeon_crtc = to_radeon_crtc(crtc); if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) { - vrefresh = radeon_crtc->hw_mode.vrefresh; + vrefresh = drm_mode_vrefresh(&radeon_crtc->hw_mode); break; } } @@ -811,6 +811,7 @@ union power_info { union fan_info { struct _ATOM_PPLIB_FANTABLE fan; struct _ATOM_PPLIB_FANTABLE2 fan2; + struct _ATOM_PPLIB_FANTABLE3 fan3; }; static int r600_parse_clk_voltage_dep_table(struct radeon_clock_voltage_dependency_table *radeon_table, @@ -900,6 +901,14 @@ int r600_parse_extended_power_table(struct radeon_device *rdev) else rdev->pm.dpm.fan.t_max = 10900; rdev->pm.dpm.fan.cycle_delay = 100000; + if (fan_info->fan.ucFanTableFormat >= 3) { + rdev->pm.dpm.fan.control_mode = fan_info->fan3.ucFanControlMode; + rdev->pm.dpm.fan.default_max_fan_pwm = + le16_to_cpu(fan_info->fan3.usFanPWMMax); + rdev->pm.dpm.fan.default_fan_output_sensitivity = 4836; + rdev->pm.dpm.fan.fan_output_sensitivity = + le16_to_cpu(fan_info->fan3.usFanOutputSensitivity); + } rdev->pm.dpm.fan.ucode_fan_control = true; } } diff --git a/sys/dev/drm/radeon/r600_dpm.h b/sys/dev/drm/radeon/r600_dpm.h index 46b9d2a030..bd499d749b 100644 --- a/sys/dev/drm/radeon/r600_dpm.h +++ b/sys/dev/drm/radeon/r600_dpm.h @@ -96,6 +96,9 @@ #define R600_TEMP_RANGE_MIN (90 * 1000) #define R600_TEMP_RANGE_MAX (120 * 1000) +#define FDO_PWM_MODE_STATIC 1 +#define FDO_PWM_MODE_STATIC_RPM 5 + enum r600_power_level { R600_POWER_LEVEL_LOW = 0, R600_POWER_LEVEL_MEDIUM = 1, diff --git a/sys/dev/drm/radeon/r600_hdmi.c b/sys/dev/drm/radeon/r600_hdmi.c index ce61d863db..261e173d5f 100644 --- a/sys/dev/drm/radeon/r600_hdmi.c +++ b/sys/dev/drm/radeon/r600_hdmi.c @@ -29,6 +29,7 @@ #include #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include "r600d.h" #include "atom.h" @@ -55,30 +56,6 @@ enum r600_hdmi_iec_status_bits { AUDIO_STATUS_LEVEL = 0x80 }; -static const struct radeon_hdmi_acr r600_hdmi_predefined_acr[] = { - /* 32kHz 44.1kHz 48kHz */ - /* Clock N CTS N CTS N CTS */ - { 25175, 4096, 25175, 28224, 125875, 6144, 25175 }, /* 25,20/1.001 MHz */ - { 25200, 4096, 25200, 6272, 28000, 6144, 25200 }, /* 25.20 MHz */ - { 27000, 4096, 27000, 6272, 30000, 6144, 27000 }, /* 27.00 MHz */ - { 27027, 4096, 27027, 6272, 30030, 6144, 27027 }, /* 27.00*1.001 MHz */ - { 54000, 4096, 54000, 6272, 60000, 6144, 54000 }, /* 54.00 MHz */ - { 54054, 4096, 54054, 6272, 60060, 6144, 54054 }, /* 54.00*1.001 MHz */ - { 74176, 4096, 74176, 5733, 75335, 6144, 74176 }, /* 74.25/1.001 MHz */ - { 74250, 4096, 74250, 6272, 82500, 6144, 74250 }, /* 74.25 MHz */ - { 148352, 4096, 148352, 5733, 150670, 6144, 148352 }, /* 148.50/1.001 MHz */ - { 148500, 4096, 148500, 6272, 165000, 6144, 148500 }, /* 148.50 MHz */ -}; - - -/* - * check if the chipset is supported - */ -static int r600_audio_chipset_supported(struct radeon_device *rdev) -{ - return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev); -} - static struct r600_audio_pin r600_audio_status(struct radeon_device *rdev) { struct r600_audio_pin status; @@ -190,155 +167,56 @@ void r600_audio_enable(struct radeon_device *rdev, WREG32(AZ_HOT_PLUG_CONTROL, tmp); } -/* - * initialize the audio vars - */ -int r600_audio_init(struct radeon_device *rdev) -{ - if (!radeon_audio || !r600_audio_chipset_supported(rdev)) - return 0; - - rdev->audio.enabled = true; - - rdev->audio.num_pins = 1; - rdev->audio.pin[0].channels = -1; - rdev->audio.pin[0].rate = -1; - rdev->audio.pin[0].bits_per_sample = -1; - rdev->audio.pin[0].status_bits = 0; - rdev->audio.pin[0].category_code = 0; - rdev->audio.pin[0].id = 0; - /* disable audio. it will be set up later */ - r600_audio_enable(rdev, &rdev->audio.pin[0], 0); - - return 0; -} - -/* - * release the audio timer - * TODO: How to do this correctly on SMP systems? - */ -void r600_audio_fini(struct radeon_device *rdev) -{ - if (!rdev->audio.enabled) - return; - - r600_audio_enable(rdev, &rdev->audio.pin[0], 0); - - rdev->audio.enabled = false; -} - struct r600_audio_pin *r600_audio_get_pin(struct radeon_device *rdev) { /* only one pin on 6xx-NI */ return &rdev->audio.pin[0]; } -/* - * calculate CTS and N values if they are not found in the table - */ -static void r600_hdmi_calc_cts(uint32_t clock, int *CTS, int *N, int freq) -{ - int n, cts; - unsigned long div, mul; - - /* Safe, but overly large values */ - n = 128 * freq; - cts = clock * 1000; - - /* Smallest valid fraction */ - div = gcd64(n, cts); - - n /= div; - cts /= div; - - /* - * The optimal N is 128*freq/1000. Calculate the closest larger - * value that doesn't truncate any bits. - */ - mul = ((128*freq/1000) + (n-1))/n; - - n *= mul; - cts *= mul; - - /* Check that we are in spec (not always possible) */ - if (n < (128*freq/1500)) - printk(KERN_WARNING "Calculated ACR N value is too small. You may experience audio problems.\n"); - if (n > (128*freq/300)) - printk(KERN_WARNING "Calculated ACR N value is too large. You may experience audio problems.\n"); - - *N = n; - *CTS = cts; - - DRM_DEBUG("Calculated ACR timing N=%d CTS=%d for frequency %d\n", - *N, *CTS, freq); -} - -struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock) -{ - struct radeon_hdmi_acr res; - u8 i; - - /* Precalculated values for common clocks */ - for (i = 0; i < ARRAY_SIZE(r600_hdmi_predefined_acr); i++) { - if (r600_hdmi_predefined_acr[i].clock == clock) - return r600_hdmi_predefined_acr[i]; - } - - /* And odd clocks get manually calculated */ - r600_hdmi_calc_cts(clock, &res.cts_32khz, &res.n_32khz, 32000); - r600_hdmi_calc_cts(clock, &res.cts_44_1khz, &res.n_44_1khz, 44100); - r600_hdmi_calc_cts(clock, &res.cts_48khz, &res.n_48khz, 48000); - - return res; -} - -/* - * update the N and CTS parameters for a given pixel clock rate - */ -void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock) +void r600_hdmi_update_acr(struct drm_encoder *encoder, long offset, + const struct radeon_hdmi_acr *acr) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; - struct radeon_hdmi_acr acr = r600_hdmi_acr(clock); - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - uint32_t offset = dig->afmt->offset; + + /* DCE 3.0 uses register that's normally for CRC_CONTROL */ + uint32_t acr_ctl = ASIC_IS_DCE3(rdev) ? DCE3_HDMI0_ACR_PACKET_CONTROL : + HDMI0_ACR_PACKET_CONTROL; + WREG32_P(acr_ctl + offset, + HDMI0_ACR_SOURCE | /* select SW CTS value */ + HDMI0_ACR_AUTO_SEND, /* allow hw to sent ACR packets when required */ + ~(HDMI0_ACR_SOURCE | + HDMI0_ACR_AUTO_SEND)); WREG32_P(HDMI0_ACR_32_0 + offset, - HDMI0_ACR_CTS_32(acr.cts_32khz), - ~HDMI0_ACR_CTS_32_MASK); + HDMI0_ACR_CTS_32(acr->cts_32khz), + ~HDMI0_ACR_CTS_32_MASK); WREG32_P(HDMI0_ACR_32_1 + offset, - HDMI0_ACR_N_32(acr.n_32khz), - ~HDMI0_ACR_N_32_MASK); + HDMI0_ACR_N_32(acr->n_32khz), + ~HDMI0_ACR_N_32_MASK); WREG32_P(HDMI0_ACR_44_0 + offset, - HDMI0_ACR_CTS_44(acr.cts_44_1khz), - ~HDMI0_ACR_CTS_44_MASK); + HDMI0_ACR_CTS_44(acr->cts_44_1khz), + ~HDMI0_ACR_CTS_44_MASK); WREG32_P(HDMI0_ACR_44_1 + offset, - HDMI0_ACR_N_44(acr.n_44_1khz), - ~HDMI0_ACR_N_44_MASK); + HDMI0_ACR_N_44(acr->n_44_1khz), + ~HDMI0_ACR_N_44_MASK); WREG32_P(HDMI0_ACR_48_0 + offset, - HDMI0_ACR_CTS_48(acr.cts_48khz), - ~HDMI0_ACR_CTS_48_MASK); + HDMI0_ACR_CTS_48(acr->cts_48khz), + ~HDMI0_ACR_CTS_48_MASK); WREG32_P(HDMI0_ACR_48_1 + offset, - HDMI0_ACR_N_48(acr.n_48khz), - ~HDMI0_ACR_N_48_MASK); + HDMI0_ACR_N_48(acr->n_48khz), + ~HDMI0_ACR_N_48_MASK); } /* * build a HDMI Video Info Frame */ -void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder, void *buffer, - size_t size) +void r600_set_avi_packet(struct radeon_device *rdev, u32 offset, + unsigned char *buffer, size_t size) { - 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; - uint32_t offset = dig->afmt->offset; uint8_t *frame = (uint8_t*)buffer + 3; - uint8_t *header = buffer; WREG32(HDMI0_AVI_INFO0 + offset, frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24)); @@ -347,7 +225,15 @@ void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder, void *buffer, WREG32(HDMI0_AVI_INFO2 + offset, frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24)); WREG32(HDMI0_AVI_INFO3 + offset, - frame[0xC] | (frame[0xD] << 8) | (header[1] << 24)); + frame[0xC] | (frame[0xD] << 8) | (buffer[1] << 24)); + + WREG32_OR(HDMI0_INFOFRAME_CONTROL1 + offset, + HDMI0_AVI_INFO_LINE(2)); /* anything other than 0 */ + + WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset, + HDMI0_AVI_INFO_SEND | /* enable AVI info frames */ + HDMI0_AVI_INFO_CONT); /* send AVI info frames every frame/field */ + } /* @@ -424,188 +310,94 @@ void r600_hdmi_audio_workaround(struct drm_encoder *encoder) value, ~HDMI0_AUDIO_TEST_EN); } -void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock) +void r600_hdmi_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned 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; - u32 base_rate = 24000; - u32 max_ratio = clock / base_rate; - u32 dto_phase; - u32 dto_modulo = clock; - u32 wallclock_ratio; - u32 dto_cntl; + struct radeon_encoder *radeon_encoder; + struct radeon_encoder_atom_dig *dig; - if (!dig || !dig->afmt) + if (!crtc) return; - if (max_ratio >= 8) { - dto_phase = 192 * 1000; - wallclock_ratio = 3; - } else if (max_ratio >= 4) { - dto_phase = 96 * 1000; - wallclock_ratio = 2; - } else if (max_ratio >= 2) { - dto_phase = 48 * 1000; - wallclock_ratio = 1; - } else { - dto_phase = 24 * 1000; - wallclock_ratio = 0; - } + radeon_encoder = to_radeon_encoder(crtc->encoder); + dig = radeon_encoder->enc_priv; - /* there are two DTOs selected by DCCG_AUDIO_DTO_SELECT. - * doesn't matter which one you use. Just use the first one. - */ - /* XXX two dtos; generally use dto0 for hdmi */ - /* Express [24MHz / target pixel clock] as an exact rational - * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE - * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator - */ - if (ASIC_IS_DCE32(rdev)) { - if (dig->dig_encoder == 0) { - dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; - dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio); - WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl); - WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase); - WREG32(DCCG_AUDIO_DTO0_MODULE, dto_modulo); - WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */ - } else { - dto_cntl = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; - dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio); - WREG32(DCCG_AUDIO_DTO1_CNTL, dto_cntl); - WREG32(DCCG_AUDIO_DTO1_PHASE, dto_phase); - WREG32(DCCG_AUDIO_DTO1_MODULE, dto_modulo); - WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */ - } + if (!dig) + return; + + if (dig->dig_encoder == 0) { + WREG32(DCCG_AUDIO_DTO0_PHASE, 24000 * 100); + WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100); + WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */ } else { - /* according to the reg specs, this should DCE3.2 only, but in - * practice it seems to cover DCE2.0/3.0/3.1 as well. - */ - if (dig->dig_encoder == 0) { - WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100); - WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100); - WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */ - } else { - WREG32(DCCG_AUDIO_DTO1_PHASE, base_rate * 100); - WREG32(DCCG_AUDIO_DTO1_MODULE, clock * 100); - WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */ - } + WREG32(DCCG_AUDIO_DTO1_PHASE, 24000 * 100); + WREG32(DCCG_AUDIO_DTO1_MODULE, clock * 100); + WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */ } } -/* - * update the info frames with the data from the current display mode - */ -void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode) +void r600_set_vbi_packet(struct drm_encoder *encoder, u32 offset) { 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; - u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE]; - struct hdmi_avi_infoframe frame; - uint32_t offset; - uint32_t acr_ctl; - ssize_t err; - - if (!dig || !dig->afmt) - return; - /* Silent, r600_hdmi_enable will raise WARN for us */ - if (!dig->afmt->enabled) - return; - offset = dig->afmt->offset; - - /* disable audio prior to setting up hw */ - dig->afmt->pin = r600_audio_get_pin(rdev); - r600_audio_enable(rdev, dig->afmt->pin, 0xf); + WREG32_OR(HDMI0_VBI_PACKET_CONTROL + offset, + HDMI0_NULL_SEND | /* send null packets when required */ + HDMI0_GC_SEND | /* send general control packets */ + HDMI0_GC_CONT); /* send general control packets every frame */ +} - r600_audio_set_dto(encoder, mode->clock); +void r600_set_audio_packet(struct drm_encoder *encoder, u32 offset) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; WREG32_P(HDMI0_AUDIO_PACKET_CONTROL + offset, - HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */ - HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */ - HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */ - HDMI0_60958_CS_UPDATE, /* allow 60958 channel status fields to be updated */ - ~(HDMI0_AUDIO_SAMPLE_SEND | - HDMI0_AUDIO_DELAY_EN_MASK | - HDMI0_AUDIO_PACKETS_PER_LINE_MASK | - HDMI0_60958_CS_UPDATE)); - - /* DCE 3.0 uses register that's normally for CRC_CONTROL */ - acr_ctl = ASIC_IS_DCE3(rdev) ? DCE3_HDMI0_ACR_PACKET_CONTROL : - HDMI0_ACR_PACKET_CONTROL; - WREG32_P(acr_ctl + offset, - HDMI0_ACR_SOURCE | /* select SW CTS value - XXX verify that hw CTS works on all families */ - HDMI0_ACR_AUTO_SEND, /* allow hw to sent ACR packets when required */ - ~(HDMI0_ACR_SOURCE | - HDMI0_ACR_AUTO_SEND)); - - WREG32_OR(HDMI0_VBI_PACKET_CONTROL + offset, - HDMI0_NULL_SEND | /* send null packets when required */ - HDMI0_GC_SEND | /* send general control packets */ - HDMI0_GC_CONT); /* send general control packets every frame */ + HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */ + HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */ + HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */ + HDMI0_60958_CS_UPDATE, /* allow 60958 channel status fields to be updated */ + ~(HDMI0_AUDIO_SAMPLE_SEND | + HDMI0_AUDIO_DELAY_EN_MASK | + HDMI0_AUDIO_PACKETS_PER_LINE_MASK | + HDMI0_60958_CS_UPDATE)); WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset, - HDMI0_AVI_INFO_SEND | /* enable AVI info frames */ - HDMI0_AVI_INFO_CONT | /* send AVI info frames every frame/field */ - HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */ - HDMI0_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */ + HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */ + HDMI0_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */ WREG32_P(HDMI0_INFOFRAME_CONTROL1 + offset, - HDMI0_AVI_INFO_LINE(2) | /* anything other than 0 */ - HDMI0_AUDIO_INFO_LINE(2), /* anything other than 0 */ - ~(HDMI0_AVI_INFO_LINE_MASK | - HDMI0_AUDIO_INFO_LINE_MASK)); - - WREG32_AND(HDMI0_GC + offset, - ~HDMI0_GC_AVMUTE); /* unset HDMI0_GC_AVMUTE */ - - err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode); - if (err < 0) { - DRM_ERROR("failed to setup AVI infoframe: %zd\n", err); - return; - } - - err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer)); - if (err < 0) { - DRM_ERROR("failed to pack AVI infoframe: %zd\n", err); - return; - } - - r600_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer)); - - /* fglrx duplicates INFOFRAME_CONTROL0 & INFOFRAME_CONTROL1 ops here */ + HDMI0_AUDIO_INFO_LINE(2), /* anything other than 0 */ + ~HDMI0_AUDIO_INFO_LINE_MASK); WREG32_AND(HDMI0_GENERIC_PACKET_CONTROL + offset, - ~(HDMI0_GENERIC0_SEND | - HDMI0_GENERIC0_CONT | - HDMI0_GENERIC0_UPDATE | - HDMI0_GENERIC1_SEND | - HDMI0_GENERIC1_CONT | - HDMI0_GENERIC0_LINE_MASK | - HDMI0_GENERIC1_LINE_MASK)); - - r600_hdmi_update_ACR(encoder, mode->clock); + ~(HDMI0_GENERIC0_SEND | + HDMI0_GENERIC0_CONT | + HDMI0_GENERIC0_UPDATE | + HDMI0_GENERIC1_SEND | + HDMI0_GENERIC1_CONT | + HDMI0_GENERIC0_LINE_MASK | + HDMI0_GENERIC1_LINE_MASK)); WREG32_P(HDMI0_60958_0 + offset, - HDMI0_60958_CS_CHANNEL_NUMBER_L(1), - ~(HDMI0_60958_CS_CHANNEL_NUMBER_L_MASK | - HDMI0_60958_CS_CLOCK_ACCURACY_MASK)); + HDMI0_60958_CS_CHANNEL_NUMBER_L(1), + ~(HDMI0_60958_CS_CHANNEL_NUMBER_L_MASK | + HDMI0_60958_CS_CLOCK_ACCURACY_MASK)); WREG32_P(HDMI0_60958_1 + offset, - HDMI0_60958_CS_CHANNEL_NUMBER_R(2), - ~HDMI0_60958_CS_CHANNEL_NUMBER_R_MASK); + HDMI0_60958_CS_CHANNEL_NUMBER_R(2), + ~HDMI0_60958_CS_CHANNEL_NUMBER_R_MASK); +} - /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */ - WREG32(HDMI0_RAMP_CONTROL0 + offset, 0x00FFFFFF); - WREG32(HDMI0_RAMP_CONTROL1 + offset, 0x007FFFFF); - WREG32(HDMI0_RAMP_CONTROL2 + offset, 0x00000001); - WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001); +void r600_set_mute(struct drm_encoder *encoder, u32 offset, bool mute) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; - /* enable audio after to setting up hw */ - r600_audio_enable(rdev, dig->afmt->pin, 0xf); + if (mute) + WREG32_OR(HDMI0_GC + offset, HDMI0_GC_AVMUTE); + else + WREG32_AND(HDMI0_GC + offset, ~HDMI0_GC_AVMUTE); } /** @@ -684,17 +476,6 @@ void r600_hdmi_enable(struct drm_encoder *encoder, bool enable) if (!dig || !dig->afmt) return; - /* Silent, r600_hdmi_enable will raise WARN for us */ - if (enable && dig->afmt->enabled) - return; - if (!enable && !dig->afmt->enabled) - return; - - if (!enable && dig->afmt->pin) { - r600_audio_enable(rdev, dig->afmt->pin, 0); - dig->afmt->pin = NULL; - } - /* Older chipsets require setting HDMI and routing manually */ if (!ASIC_IS_DCE3(rdev)) { if (enable) @@ -750,3 +531,4 @@ void r600_hdmi_enable(struct drm_encoder *encoder, bool enable) DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n", enable ? "En" : "Dis", dig->afmt->offset, radeon_encoder->encoder_id); } + diff --git a/sys/dev/drm/radeon/radeon.h b/sys/dev/drm/radeon/radeon.h index 83161115fa..956af727b0 100644 --- a/sys/dev/drm/radeon/radeon.h +++ b/sys/dev/drm/radeon/radeon.h @@ -122,6 +122,9 @@ extern int radeon_deep_color; extern int radeon_use_pflipirq; extern int radeon_bapm; extern int radeon_backlight; +extern int radeon_auxch; +extern int radeon_uvd; +extern int radeon_vce; /* * Copy from radeon_drv.h so we don't have to include both and have conflicting @@ -129,6 +132,7 @@ extern int radeon_backlight; */ #define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */ #define RADEON_FENCE_JIFFIES_TIMEOUT (HZ / 2) +#define RADEON_USEC_IB_TEST_TIMEOUT 1000000 /* 1s */ /* RADEON_IB_POOL_SIZE must be a power of 2 */ #define RADEON_IB_POOL_SIZE 16 #define RADEON_DEBUGFS_MAX_COMPONENTS 32 @@ -253,6 +257,7 @@ bool radeon_get_bios(struct radeon_device *rdev); * Dummy page */ struct radeon_dummy_page { + uint64_t entry; struct drm_dma_handle *dmah; dma_addr_t addr; }; @@ -276,6 +281,7 @@ struct radeon_clock { uint32_t current_dispclk; uint32_t dp_extclk; uint32_t max_pixel_clock; + uint32_t vco_freq; }; /* @@ -384,6 +390,7 @@ void radeon_fence_driver_force_completion(struct radeon_device *rdev, int ring); int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence **fence, int ring); void radeon_fence_process(struct radeon_device *rdev, int ring); bool radeon_fence_signaled(struct radeon_fence *fence); +int radeon_fence_wait_timeout(struct radeon_fence *fence, bool interruptible, int timeout); int radeon_fence_wait(struct radeon_fence *fence, bool interruptible); int radeon_fence_wait_next(struct radeon_device *rdev, int ring); int radeon_fence_wait_empty(struct radeon_device *rdev, int ring); @@ -456,6 +463,15 @@ struct radeon_mman { #endif }; +struct radeon_bo_list { + struct radeon_bo *robj; + struct ttm_validate_buffer tv; + uint64_t gpu_offset; + unsigned prefered_domains; + unsigned allowed_domains; + uint32_t tiling_flags; +}; + /* bo virtual address in a specific vm */ struct radeon_bo_va { /* protected by bo being reserved */ @@ -480,7 +496,7 @@ struct radeon_bo { struct list_head list; /* Protected by tbo.reserved */ u32 initial_domain; - struct ttm_place placements[3]; + struct ttm_place placements[4]; struct ttm_placement placement; struct ttm_buffer_object tbo; struct ttm_bo_kmap_obj kmap; @@ -626,7 +642,7 @@ struct radeon_gart { unsigned num_cpu_pages; unsigned table_size; vm_page_t *pages; - dma_addr_t *pages_addr; + uint64_t *pages_entry; bool ready; }; @@ -716,6 +732,7 @@ struct radeon_flip_work { struct drm_pending_vblank_event *event; struct radeon_bo *old_rbo; struct radeon_fence *fence; + bool async; }; struct r500_irq_stat_regs { @@ -895,6 +912,9 @@ struct radeon_vm { struct list_head va; unsigned id; + /* protecting invalidated and freed */ + struct spinlock status_lock; + /* BOs moved, but not yet updated in the PT */ struct list_head invalidated; @@ -912,7 +932,6 @@ struct radeon_vm { struct radeon_bo_va *ib_bo_va; struct lock mutex; - /* last fence for cs using this vm */ struct radeon_fence *fence; /* last flush or NULL if we still need to flush */ struct radeon_fence *last_flush; @@ -1025,17 +1044,6 @@ void cayman_dma_fini(struct radeon_device *rdev); /* * CS. */ -struct radeon_cs_reloc { - struct drm_gem_object *gobj; - struct radeon_bo *robj; - struct ttm_validate_buffer tv; - uint64_t gpu_offset; - unsigned prefered_domains; - unsigned allowed_domains; - uint32_t tiling_flags; - uint32_t handle; -}; - struct radeon_cs_chunk { uint32_t chunk_id; uint32_t length_dw; @@ -1055,9 +1063,9 @@ struct radeon_cs_parser { unsigned idx; /* relocations */ unsigned nrelocs; - struct radeon_cs_reloc *relocs; - struct radeon_cs_reloc **relocs_ptr; - struct radeon_cs_reloc *vm_bos; + struct radeon_bo_list *relocs; + struct radeon_bo_list **relocs_ptr; + struct radeon_bo_list *vm_bos; struct list_head validated; unsigned dma_reloc_idx; /* indices of various chunks */ @@ -1490,6 +1498,10 @@ struct radeon_dpm_fan { u8 t_hyst; u32 cycle_delay; u16 t_max; + u8 control_mode; + u16 default_max_fan_pwm; + u16 default_fan_output_sensitivity; + u16 fan_output_sensitivity; bool ucode_fan_control; }; @@ -1542,6 +1554,7 @@ struct radeon_dpm { int new_active_crtc_count; u32 current_active_crtcs; int current_active_crtc_count; + bool single_display; struct radeon_dpm_dynamic_state dyn_state; struct radeon_dpm_fan fan; u32 tdp_limit; @@ -1610,9 +1623,7 @@ struct radeon_pm { /* selected pm method */ enum radeon_pm_method pm_method; /* dynpm power management */ -#ifdef DUMBBELL_WIP struct delayed_work dynpm_idle_work; -#endif /* DUMBBELL_WIP */ enum radeon_dynpm_state dynpm_state; enum radeon_dynpm_action dynpm_planned_action; unsigned long dynpm_action_timeout; @@ -1626,8 +1637,14 @@ struct radeon_pm { enum radeon_int_thermal_type int_thermal_type; struct ksensor *int_sensor; struct ksensordev *int_sensordev; + /* fan control parameters */ + bool no_fan; + u8 fan_pulses_per_revolution; + u8 fan_min_rpm; + u8 fan_max_rpm; /* dpm */ bool dpm_enabled; + bool sysfs_initialized; struct radeon_dpm dpm; }; @@ -1637,15 +1654,18 @@ int radeon_pm_get_type_index(struct radeon_device *rdev, /* * UVD */ -#define RADEON_MAX_UVD_HANDLES 10 -#define RADEON_UVD_STACK_SIZE (1024*1024) -#define RADEON_UVD_HEAP_SIZE (1024*1024) +#define RADEON_DEFAULT_UVD_HANDLES 10 +#define RADEON_MAX_UVD_HANDLES 30 +#define RADEON_UVD_STACK_SIZE (200*1024) +#define RADEON_UVD_HEAP_SIZE (256*1024) +#define RADEON_UVD_SESSION_SIZE (50*1024) struct radeon_uvd { + bool fw_header_present; struct radeon_bo *vcpu_bo; void *cpu_addr; u64 gpu_addr; - void *saved_bo; + unsigned max_handles; atomic_t handles[RADEON_MAX_UVD_HANDLES]; struct drm_file *filp[RADEON_MAX_UVD_HANDLES]; unsigned img_size[RADEON_MAX_UVD_HANDLES]; @@ -1682,8 +1702,6 @@ int radeon_uvd_send_upll_ctlreq(struct radeon_device *rdev, * VCE */ #define RADEON_MAX_VCE_HANDLES 16 -#define RADEON_VCE_STACK_SIZE (1024*1024) -#define RADEON_VCE_HEAP_SIZE (4*1024*1024) struct radeon_vce { struct radeon_bo *vcpu_bo; @@ -1694,6 +1712,7 @@ struct radeon_vce { struct drm_file *filp[RADEON_MAX_VCE_HANDLES]; unsigned img_size[RADEON_MAX_VCE_HANDLES]; struct delayed_work idle_work; + uint32_t keyselect; }; int radeon_vce_init(struct radeon_device *rdev); @@ -1733,6 +1752,9 @@ struct r600_audio { bool enabled; struct r600_audio_pin pin[RADEON_MAX_AFMT_BLOCKS]; int num_pins; + struct radeon_audio_funcs *hdmi_funcs; + struct radeon_audio_funcs *dp_funcs; + struct radeon_audio_basic_funcs *funcs; }; /* @@ -1783,7 +1805,8 @@ struct radeon_asic_ring { void (*hdp_flush)(struct radeon_device *rdev, struct radeon_ring *ring); bool (*emit_semaphore)(struct radeon_device *rdev, struct radeon_ring *cp, struct radeon_semaphore *semaphore, bool emit_wait); - void (*vm_flush)(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); + void (*vm_flush)(struct radeon_device *rdev, struct radeon_ring *ring, + unsigned vm_id, uint64_t pd_addr); /* testing functions */ int (*ring_test)(struct radeon_device *rdev, struct radeon_ring *cp); @@ -1803,7 +1826,7 @@ struct radeon_asic { int (*resume)(struct radeon_device *rdev); int (*suspend)(struct radeon_device *rdev); void (*vga_set_state)(struct radeon_device *rdev, bool state); - int (*asic_reset)(struct radeon_device *rdev); + int (*asic_reset)(struct radeon_device *rdev, bool hard); /* Flush the HDP cache via MMIO */ void (*mmio_hdp_flush)(struct radeon_device *rdev); /* check if 3D engine is idle */ @@ -1814,11 +1837,14 @@ struct radeon_asic { u32 (*get_xclk)(struct radeon_device *rdev); /* get the gpu clock counter */ uint64_t (*get_gpu_clock_counter)(struct radeon_device *rdev); + /* get register for info ioctl */ + int (*get_allowed_info_register)(struct radeon_device *rdev, u32 reg, u32 *val); /* gart */ struct { void (*tlb_flush)(struct radeon_device *rdev); + uint64_t (*get_page_entry)(uint64_t addr, uint32_t flags); void (*set_page)(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags); + uint64_t entry); } gart; struct { int (*init)(struct radeon_device *rdev); @@ -1840,7 +1866,7 @@ struct radeon_asic { void (*pad_ib)(struct radeon_ib *ib); } vm; /* ring specific callbacks */ - struct radeon_asic_ring *ring[RADEON_NUM_RINGS]; + const struct radeon_asic_ring *ring[RADEON_NUM_RINGS]; /* irqs */ struct { int (*set)(struct radeon_device *rdev); @@ -1937,10 +1963,16 @@ struct radeon_asic { bool (*vblank_too_short)(struct radeon_device *rdev); void (*powergate_uvd)(struct radeon_device *rdev, bool gate); void (*enable_bapm)(struct radeon_device *rdev, bool enable); + void (*fan_ctrl_set_mode)(struct radeon_device *rdev, u32 mode); + u32 (*fan_ctrl_get_mode)(struct radeon_device *rdev); + int (*set_fan_speed_percent)(struct radeon_device *rdev, u32 speed); + int (*get_fan_speed_percent)(struct radeon_device *rdev, u32 *speed); + u32 (*get_current_sclk)(struct radeon_device *rdev); + u32 (*get_current_mclk)(struct radeon_device *rdev); } dpm; /* pageflipping */ struct { - void (*page_flip)(struct radeon_device *rdev, int crtc, u64 crtc_base); + void (*page_flip)(struct radeon_device *rdev, int crtc, u64 crtc_base, bool async); bool (*page_flip_pending)(struct radeon_device *rdev, int crtc); } pflip; }; @@ -2275,29 +2307,29 @@ struct radeon_device { resource_size_t rmmio_base; resource_size_t rmmio_size; /* protects concurrent MM_INDEX/DATA based register access */ - struct spinlock mmio_idx_lock; + struct lock mmio_idx_lock; /* protects concurrent SMC based register access */ - struct spinlock smc_idx_lock; + struct lock smc_idx_lock; /* protects concurrent PLL register access */ - struct spinlock pll_idx_lock; + struct lock pll_idx_lock; /* protects concurrent MC register access */ - struct spinlock mc_idx_lock; + struct lock mc_idx_lock; /* protects concurrent PCIE register access */ - struct spinlock pcie_idx_lock; + struct lock pcie_idx_lock; /* protects concurrent PCIE_PORT register access */ - struct spinlock pciep_idx_lock; + struct lock pciep_idx_lock; /* protects concurrent PIF register access */ - struct spinlock pif_idx_lock; + struct lock pif_idx_lock; /* protects concurrent CG register access */ - struct spinlock cg_idx_lock; + struct lock cg_idx_lock; /* protects concurrent UVD register access */ - struct spinlock uvd_idx_lock; + struct lock uvd_idx_lock; /* protects concurrent RCU register access */ - struct spinlock rcu_idx_lock; + struct lock rcu_idx_lock; /* protects concurrent DIDT register access */ - struct spinlock didt_idx_lock; + struct lock didt_idx_lock; /* protects concurrent ENDPOINT (audio) register access */ - struct spinlock end_idx_lock; + struct lock end_idx_lock; int rmmio_rid; struct resource *rmmio; radeon_rreg_t mc_rreg; @@ -2360,10 +2392,12 @@ struct radeon_device { struct radeon_mec mec; struct taskqueue *tq; struct task hotplug_work; + struct work_struct dp_work; struct task audio_work; int num_crtc; /* number of crtcs */ struct lock dc_hw_i2c_mutex; /* display controller hw i2c mutex */ bool has_uvd; + bool has_vce; struct r600_audio audio; /* audio stuff */ struct { ACPI_HANDLE handle; @@ -2384,11 +2418,14 @@ struct radeon_device { atomic64_t vram_usage; atomic64_t gtt_usage; atomic64_t num_bytes_moved; + atomic_t gpu_reset_counter; /* ACPI interface */ struct radeon_atif atif; struct radeon_atcs atcs; /* srbm instance registers */ struct lock srbm_mutex; + /* GRBM index mutex. Protects concurrents access to GRBM index */ + struct lock grbm_idx_mutex; /* clock, powergating flags */ u32 cg_flags; u32 pg_flags; @@ -2412,6 +2449,8 @@ int radeon_device_init(struct radeon_device *rdev, void radeon_device_fini(struct radeon_device *rdev); int radeon_gpu_wait_for_idle(struct radeon_device *rdev); +#define RADEON_MIN_MMIO_SIZE 0x10000 + uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg, bool always_indirect); void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v, @@ -2479,6 +2518,13 @@ void cik_mm_wdoorbell(struct radeon_device *rdev, u32 index, u32 v); tmp_ |= ((val) & ~(mask)); \ WREG32_PLL(reg, tmp_); \ } while (0) +#define WREG32_SMC_P(reg, val, mask) \ + do { \ + uint32_t tmp_ = RREG32_SMC(reg); \ + tmp_ &= (mask); \ + tmp_ |= ((val) & ~(mask)); \ + WREG32_SMC(reg, tmp_); \ + } while (0) #define DREG32_SYS(sqf, rdev, reg) seq_printf((sqf), #reg " : 0x%08X\n", r100_mm_rreg((rdev), (reg), false)) #define RREG32_IO(reg) r100_io_rreg(rdev, (reg)) #define WREG32_IO(reg, v) r100_io_wreg(rdev, (reg), (v)) @@ -2487,160 +2533,29 @@ void cik_mm_wdoorbell(struct radeon_device *rdev, u32 index, u32 v); #define WDOORBELL32(index, v) cik_mm_wdoorbell(rdev, (index), (v)) /* - * Indirect registers accessor + * Indirect registers accessors. + * They used to be inlined, but this increases code size by ~65 kbytes. + * Since each performs a pair of MMIO ops + * within a spin_lock_irqsave/spin_unlock_irqrestore region, + * the cost of call+ret is almost negligible. MMIO and locking + * costs several dozens of cycles each at best, call+ret is ~5 cycles. */ -static inline uint32_t rv370_pcie_rreg(struct radeon_device *rdev, uint32_t reg) -{ - uint32_t r; - - spin_lock(&rdev->pcie_idx_lock); - WREG32(RADEON_PCIE_INDEX, ((reg) & rdev->pcie_reg_mask)); - r = RREG32(RADEON_PCIE_DATA); - spin_unlock(&rdev->pcie_idx_lock); - return r; -} - -static inline void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) -{ - spin_lock(&rdev->pcie_idx_lock); - WREG32(RADEON_PCIE_INDEX, ((reg) & rdev->pcie_reg_mask)); - WREG32(RADEON_PCIE_DATA, (v)); - spin_unlock(&rdev->pcie_idx_lock); -} - -static inline u32 tn_smc_rreg(struct radeon_device *rdev, u32 reg) -{ - u32 r; - - spin_lock(&rdev->smc_idx_lock); - WREG32(TN_SMC_IND_INDEX_0, (reg)); - r = RREG32(TN_SMC_IND_DATA_0); - spin_unlock(&rdev->smc_idx_lock); - return r; -} - -static inline void tn_smc_wreg(struct radeon_device *rdev, u32 reg, u32 v) -{ - spin_lock(&rdev->smc_idx_lock); - WREG32(TN_SMC_IND_INDEX_0, (reg)); - WREG32(TN_SMC_IND_DATA_0, (v)); - spin_unlock(&rdev->smc_idx_lock); -} - -static inline u32 r600_rcu_rreg(struct radeon_device *rdev, u32 reg) -{ - u32 r; - - spin_lock(&rdev->rcu_idx_lock); - WREG32(R600_RCU_INDEX, ((reg) & 0x1fff)); - r = RREG32(R600_RCU_DATA); - spin_unlock(&rdev->rcu_idx_lock); - return r; -} - -static inline void r600_rcu_wreg(struct radeon_device *rdev, u32 reg, u32 v) -{ - spin_lock(&rdev->rcu_idx_lock); - WREG32(R600_RCU_INDEX, ((reg) & 0x1fff)); - WREG32(R600_RCU_DATA, (v)); - spin_unlock(&rdev->rcu_idx_lock); -} - -static inline u32 eg_cg_rreg(struct radeon_device *rdev, u32 reg) -{ - u32 r; - - spin_lock(&rdev->cg_idx_lock); - WREG32(EVERGREEN_CG_IND_ADDR, ((reg) & 0xffff)); - r = RREG32(EVERGREEN_CG_IND_DATA); - spin_unlock(&rdev->cg_idx_lock); - return r; -} - -static inline void eg_cg_wreg(struct radeon_device *rdev, u32 reg, u32 v) -{ - spin_lock(&rdev->cg_idx_lock); - WREG32(EVERGREEN_CG_IND_ADDR, ((reg) & 0xffff)); - WREG32(EVERGREEN_CG_IND_DATA, (v)); - spin_unlock(&rdev->cg_idx_lock); -} - -static inline u32 eg_pif_phy0_rreg(struct radeon_device *rdev, u32 reg) -{ - u32 r; - - spin_lock(&rdev->pif_idx_lock); - WREG32(EVERGREEN_PIF_PHY0_INDEX, ((reg) & 0xffff)); - r = RREG32(EVERGREEN_PIF_PHY0_DATA); - spin_unlock(&rdev->pif_idx_lock); - return r; -} - -static inline void eg_pif_phy0_wreg(struct radeon_device *rdev, u32 reg, u32 v) -{ - spin_lock(&rdev->pif_idx_lock); - WREG32(EVERGREEN_PIF_PHY0_INDEX, ((reg) & 0xffff)); - WREG32(EVERGREEN_PIF_PHY0_DATA, (v)); - spin_unlock(&rdev->pif_idx_lock); -} - -static inline u32 eg_pif_phy1_rreg(struct radeon_device *rdev, u32 reg) -{ - u32 r; - - spin_lock(&rdev->pif_idx_lock); - WREG32(EVERGREEN_PIF_PHY1_INDEX, ((reg) & 0xffff)); - r = RREG32(EVERGREEN_PIF_PHY1_DATA); - spin_unlock(&rdev->pif_idx_lock); - return r; -} - -static inline void eg_pif_phy1_wreg(struct radeon_device *rdev, u32 reg, u32 v) -{ - spin_lock(&rdev->pif_idx_lock); - WREG32(EVERGREEN_PIF_PHY1_INDEX, ((reg) & 0xffff)); - WREG32(EVERGREEN_PIF_PHY1_DATA, (v)); - spin_unlock(&rdev->pif_idx_lock); -} - -static inline u32 r600_uvd_ctx_rreg(struct radeon_device *rdev, u32 reg) -{ - u32 r; - - spin_lock(&rdev->uvd_idx_lock); - WREG32(R600_UVD_CTX_INDEX, ((reg) & 0x1ff)); - r = RREG32(R600_UVD_CTX_DATA); - spin_unlock(&rdev->uvd_idx_lock); - return r; -} - -static inline void r600_uvd_ctx_wreg(struct radeon_device *rdev, u32 reg, u32 v) -{ - spin_lock(&rdev->uvd_idx_lock); - WREG32(R600_UVD_CTX_INDEX, ((reg) & 0x1ff)); - WREG32(R600_UVD_CTX_DATA, (v)); - spin_unlock(&rdev->uvd_idx_lock); -} - - -static inline u32 cik_didt_rreg(struct radeon_device *rdev, u32 reg) -{ - u32 r; - - spin_lock(&rdev->didt_idx_lock); - WREG32(CIK_DIDT_IND_INDEX, (reg)); - r = RREG32(CIK_DIDT_IND_DATA); - spin_unlock(&rdev->didt_idx_lock); - return r; -} - -static inline void cik_didt_wreg(struct radeon_device *rdev, u32 reg, u32 v) -{ - spin_lock(&rdev->didt_idx_lock); - WREG32(CIK_DIDT_IND_INDEX, (reg)); - WREG32(CIK_DIDT_IND_DATA, (v)); - spin_unlock(&rdev->didt_idx_lock); -} +uint32_t rv370_pcie_rreg(struct radeon_device *rdev, uint32_t reg); +void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); +u32 tn_smc_rreg(struct radeon_device *rdev, u32 reg); +void tn_smc_wreg(struct radeon_device *rdev, u32 reg, u32 v); +u32 r600_rcu_rreg(struct radeon_device *rdev, u32 reg); +void r600_rcu_wreg(struct radeon_device *rdev, u32 reg, u32 v); +u32 eg_cg_rreg(struct radeon_device *rdev, u32 reg); +void eg_cg_wreg(struct radeon_device *rdev, u32 reg, u32 v); +u32 eg_pif_phy0_rreg(struct radeon_device *rdev, u32 reg); +void eg_pif_phy0_wreg(struct radeon_device *rdev, u32 reg, u32 v); +u32 eg_pif_phy1_rreg(struct radeon_device *rdev, u32 reg); +void eg_pif_phy1_wreg(struct radeon_device *rdev, u32 reg, u32 v); +u32 r600_uvd_ctx_rreg(struct radeon_device *rdev, u32 reg); +void r600_uvd_ctx_wreg(struct radeon_device *rdev, u32 reg, u32 v); +u32 cik_didt_rreg(struct radeon_device *rdev, u32 reg); +void cik_didt_wreg(struct radeon_device *rdev, u32 reg, u32 v); void r100_pll_errata_after_index(struct radeon_device *rdev); @@ -2750,9 +2665,10 @@ static inline void radeon_ring_write(struct radeon_ring *ring, uint32_t v) #define radeon_suspend(rdev) (rdev)->asic->suspend((rdev)) #define radeon_cs_parse(rdev, r, p) (rdev)->asic->ring[(r)]->cs_parse((p)) #define radeon_vga_set_state(rdev, state) (rdev)->asic->vga_set_state((rdev), (state)) -#define radeon_asic_reset(rdev) (rdev)->asic->asic_reset((rdev)) +#define radeon_asic_reset(rdev) (rdev)->asic->asic_reset((rdev), false) #define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart.tlb_flush((rdev)) -#define radeon_gart_set_page(rdev, i, p, f) (rdev)->asic->gart.set_page((rdev), (i), (p), (f)) +#define radeon_gart_get_page_entry(a, f) (rdev)->asic->gart.get_page_entry((a), (f)) +#define radeon_gart_set_page(rdev, i, e) (rdev)->asic->gart.set_page((rdev), (i), (e)) #define radeon_asic_vm_init(rdev) (rdev)->asic->vm.init((rdev)) #define radeon_asic_vm_fini(rdev) (rdev)->asic->vm.fini((rdev)) #define radeon_asic_vm_copy_pages(rdev, ib, pe, src, count) ((rdev)->asic->vm.copy_pages((rdev), (ib), (pe), (src), (count))) @@ -2765,7 +2681,7 @@ static inline void radeon_ring_write(struct radeon_ring *ring, uint32_t v) #define radeon_ring_ib_execute(rdev, r, ib) (rdev)->asic->ring[(r)]->ib_execute((rdev), (ib)) #define radeon_ring_ib_parse(rdev, r, ib) (rdev)->asic->ring[(r)]->ib_parse((rdev), (ib)) #define radeon_ring_is_lockup(rdev, r, cp) (rdev)->asic->ring[(r)]->is_lockup((rdev), (cp)) -#define radeon_ring_vm_flush(rdev, r, vm) (rdev)->asic->ring[(r)]->vm_flush((rdev), (r), (vm)) +#define radeon_ring_vm_flush(rdev, r, vm_id, pd_addr) (rdev)->asic->ring[(r)->idx]->vm_flush((rdev), (r), (vm_id), (pd_addr)) #define radeon_ring_get_rptr(rdev, r) (rdev)->asic->ring[(r)->idx]->get_rptr((rdev), (r)) #define radeon_ring_get_wptr(rdev, r) (rdev)->asic->ring[(r)->idx]->get_wptr((rdev), (r)) #define radeon_ring_set_wptr(rdev, r) (rdev)->asic->ring[(r)->idx]->set_wptr((rdev), (r)) @@ -2807,12 +2723,13 @@ static inline void radeon_ring_write(struct radeon_ring *ring, uint32_t v) #define radeon_pm_finish(rdev) (rdev)->asic->pm.finish((rdev)) #define radeon_pm_init_profile(rdev) (rdev)->asic->pm.init_profile((rdev)) #define radeon_pm_get_dynpm_state(rdev) (rdev)->asic->pm.get_dynpm_state((rdev)) -#define radeon_page_flip(rdev, crtc, base) (rdev)->asic->pflip.page_flip((rdev), (crtc), (base)) +#define radeon_page_flip(rdev, crtc, base, async) (rdev)->asic->pflip.page_flip((rdev), (crtc), (base), (async)) #define radeon_page_flip_pending(rdev, crtc) (rdev)->asic->pflip.page_flip_pending((rdev), (crtc)) #define radeon_wait_for_vblank(rdev, crtc) (rdev)->asic->display.wait_for_vblank((rdev), (crtc)) #define radeon_mc_wait_for_idle(rdev) (rdev)->asic->mc_wait_for_idle((rdev)) #define radeon_get_xclk(rdev) (rdev)->asic->get_xclk((rdev)) #define radeon_get_gpu_clock_counter(rdev) (rdev)->asic->get_gpu_clock_counter((rdev)) +#define radeon_get_allowed_info_register(rdev, r, v) (rdev)->asic->get_allowed_info_register((rdev), (r), (v)) #define radeon_dpm_init(rdev) rdev->asic->dpm.init((rdev)) #define radeon_dpm_setup_asic(rdev) rdev->asic->dpm.setup_asic((rdev)) #define radeon_dpm_enable(rdev) rdev->asic->dpm.enable((rdev)) @@ -2831,6 +2748,8 @@ static inline void radeon_ring_write(struct radeon_ring *ring, uint32_t v) #define radeon_dpm_vblank_too_short(rdev) rdev->asic->dpm.vblank_too_short((rdev)) #define radeon_dpm_powergate_uvd(rdev, g) rdev->asic->dpm.powergate_uvd((rdev), (g)) #define radeon_dpm_enable_bapm(rdev, e) rdev->asic->dpm.enable_bapm((rdev), (e)) +#define radeon_dpm_get_current_sclk(rdev) rdev->asic->dpm.get_current_sclk((rdev)) +#define radeon_dpm_get_current_mclk(rdev) rdev->asic->dpm.get_current_mclk((rdev)) /* Common functions */ /* AGP */ @@ -2855,7 +2774,8 @@ extern bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo); extern void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base); extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc); extern int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon); -extern int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon); +extern int radeon_suspend_kms(struct drm_device *dev, bool suspend, + bool fbcon, bool freeze); extern void radeon_ttm_set_active_vram_size(struct radeon_device *rdev, u64 size); extern void radeon_program_register_sequence(struct radeon_device *rdev, const u32 *registers, @@ -2868,7 +2788,7 @@ int radeon_vm_manager_init(struct radeon_device *rdev); void radeon_vm_manager_fini(struct radeon_device *rdev); int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm); void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm); -struct radeon_cs_reloc *radeon_vm_get_bos(struct radeon_device *rdev, +struct radeon_bo_list *radeon_vm_get_bos(struct radeon_device *rdev, struct radeon_vm *vm, struct list_head *head); struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev, @@ -3007,7 +2927,7 @@ bool radeon_cs_packet_next_is_pkt3_nop(struct radeon_cs_parser *p); void radeon_cs_dump_packet(struct radeon_cs_parser *p, struct radeon_cs_packet *pkt); int radeon_cs_packet_next_reloc(struct radeon_cs_parser *p, - struct radeon_cs_reloc **cs_reloc, + struct radeon_bo_list **cs_reloc, int nomm); int r600_cs_common_vline_parse(struct radeon_cs_parser *p, uint32_t *vline_start_end, diff --git a/sys/dev/drm/radeon/radeon_agp.c b/sys/dev/drm/radeon/radeon_agp.c index e203e9b96c..28e133fb37 100644 --- a/sys/dev/drm/radeon/radeon_agp.c +++ b/sys/dev/drm/radeon/radeon_agp.c @@ -54,6 +54,9 @@ static struct radeon_agpmode_quirk radeon_agpmode_quirk_list[] = { /* Intel 82855PM host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (lp #195051) */ { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4e50, PCI_VENDOR_ID_IBM, 0x0550, 1}, + /* Intel 82855PM host bridge / RV250/M9 GL [Mobility FireGL 9000/Radeon 9000] needs AGPMode 1 (Thinkpad T40p) */ + { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c66, + PCI_VENDOR_ID_IBM, 0x054d, 1}, /* Intel 82855PM host bridge / Mobility M7 needs AGPMode 1 */ { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c57, PCI_VENDOR_ID_IBM, 0x0530, 1}, diff --git a/sys/dev/drm/radeon/radeon_asic.c b/sys/dev/drm/radeon/radeon_asic.c index 201dd2962a..75162ebafb 100644 --- a/sys/dev/drm/radeon/radeon_asic.c +++ b/sys/dev/drm/radeon/radeon_asic.c @@ -135,6 +135,11 @@ static void radeon_register_accessor_init(struct radeon_device *rdev) } } +static int radeon_invalid_get_allowed_info_register(struct radeon_device *rdev, + u32 reg, u32 *val) +{ + return -EINVAL; +} /* helper to disable agp */ /** @@ -158,11 +163,13 @@ void radeon_agp_disable(struct radeon_device *rdev) DRM_INFO("Forcing AGP to PCIE mode\n"); rdev->flags |= RADEON_IS_PCIE; rdev->asic->gart.tlb_flush = &rv370_pcie_gart_tlb_flush; + rdev->asic->gart.get_page_entry = &rv370_pcie_gart_get_page_entry; rdev->asic->gart.set_page = &rv370_pcie_gart_set_page; } else { DRM_INFO("Forcing AGP to PCI mode\n"); rdev->flags |= RADEON_IS_PCI; rdev->asic->gart.tlb_flush = &r100_pci_gart_tlb_flush; + rdev->asic->gart.get_page_entry = &r100_pci_gart_get_page_entry; rdev->asic->gart.set_page = &r100_pci_gart_set_page; } rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; @@ -172,7 +179,7 @@ void radeon_agp_disable(struct radeon_device *rdev) * ASIC */ -static struct radeon_asic_ring r100_gfx_ring = { +static const struct radeon_asic_ring r100_gfx_ring = { .ib_execute = &r100_ring_ib_execute, .emit_fence = &r100_fence_ring_emit, .emit_semaphore = &r100_semaphore_ring_emit, @@ -196,8 +203,10 @@ static struct radeon_asic r100_asic = { .mmio_hdp_flush = NULL, .gui_idle = &r100_gui_idle, .mc_wait_for_idle = &r100_mc_wait_for_idle, + .get_allowed_info_register = radeon_invalid_get_allowed_info_register, .gart = { .tlb_flush = &r100_pci_gart_tlb_flush, + .get_page_entry = &r100_pci_gart_get_page_entry, .set_page = &r100_pci_gart_set_page, }, .ring = { @@ -262,8 +271,10 @@ static struct radeon_asic r200_asic = { .mmio_hdp_flush = NULL, .gui_idle = &r100_gui_idle, .mc_wait_for_idle = &r100_mc_wait_for_idle, + .get_allowed_info_register = radeon_invalid_get_allowed_info_register, .gart = { .tlb_flush = &r100_pci_gart_tlb_flush, + .get_page_entry = &r100_pci_gart_get_page_entry, .set_page = &r100_pci_gart_set_page, }, .ring = { @@ -318,7 +329,7 @@ static struct radeon_asic r200_asic = { }, }; -static struct radeon_asic_ring r300_gfx_ring = { +static const struct radeon_asic_ring r300_gfx_ring = { .ib_execute = &r100_ring_ib_execute, .emit_fence = &r300_fence_ring_emit, .emit_semaphore = &r100_semaphore_ring_emit, @@ -332,7 +343,7 @@ static struct radeon_asic_ring r300_gfx_ring = { .set_wptr = &r100_gfx_set_wptr, }; -static struct radeon_asic_ring rv515_gfx_ring = { +static const struct radeon_asic_ring rv515_gfx_ring = { .ib_execute = &r100_ring_ib_execute, .emit_fence = &r300_fence_ring_emit, .emit_semaphore = &r100_semaphore_ring_emit, @@ -356,8 +367,10 @@ static struct radeon_asic r300_asic = { .mmio_hdp_flush = NULL, .gui_idle = &r100_gui_idle, .mc_wait_for_idle = &r300_mc_wait_for_idle, + .get_allowed_info_register = radeon_invalid_get_allowed_info_register, .gart = { .tlb_flush = &r100_pci_gart_tlb_flush, + .get_page_entry = &r100_pci_gart_get_page_entry, .set_page = &r100_pci_gart_set_page, }, .ring = { @@ -422,8 +435,10 @@ static struct radeon_asic r300_asic_pcie = { .mmio_hdp_flush = NULL, .gui_idle = &r100_gui_idle, .mc_wait_for_idle = &r300_mc_wait_for_idle, + .get_allowed_info_register = radeon_invalid_get_allowed_info_register, .gart = { .tlb_flush = &rv370_pcie_gart_tlb_flush, + .get_page_entry = &rv370_pcie_gart_get_page_entry, .set_page = &rv370_pcie_gart_set_page, }, .ring = { @@ -488,8 +503,10 @@ static struct radeon_asic r420_asic = { .mmio_hdp_flush = NULL, .gui_idle = &r100_gui_idle, .mc_wait_for_idle = &r300_mc_wait_for_idle, + .get_allowed_info_register = radeon_invalid_get_allowed_info_register, .gart = { .tlb_flush = &rv370_pcie_gart_tlb_flush, + .get_page_entry = &rv370_pcie_gart_get_page_entry, .set_page = &rv370_pcie_gart_set_page, }, .ring = { @@ -554,8 +571,10 @@ static struct radeon_asic rs400_asic = { .mmio_hdp_flush = NULL, .gui_idle = &r100_gui_idle, .mc_wait_for_idle = &rs400_mc_wait_for_idle, + .get_allowed_info_register = radeon_invalid_get_allowed_info_register, .gart = { .tlb_flush = &rs400_gart_tlb_flush, + .get_page_entry = &rs400_gart_get_page_entry, .set_page = &rs400_gart_set_page, }, .ring = { @@ -620,8 +639,10 @@ static struct radeon_asic rs600_asic = { .mmio_hdp_flush = NULL, .gui_idle = &r100_gui_idle, .mc_wait_for_idle = &rs600_mc_wait_for_idle, + .get_allowed_info_register = radeon_invalid_get_allowed_info_register, .gart = { .tlb_flush = &rs600_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -637,8 +658,6 @@ static struct radeon_asic rs600_asic = { .wait_for_vblank = &avivo_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &r600_hdmi_enable, - .hdmi_setmode = &r600_hdmi_setmode, }, .copy = { .blit = &r100_copy_blit, @@ -688,8 +707,10 @@ static struct radeon_asic rs690_asic = { .mmio_hdp_flush = NULL, .gui_idle = &r100_gui_idle, .mc_wait_for_idle = &rs690_mc_wait_for_idle, + .get_allowed_info_register = radeon_invalid_get_allowed_info_register, .gart = { .tlb_flush = &rs400_gart_tlb_flush, + .get_page_entry = &rs400_gart_get_page_entry, .set_page = &rs400_gart_set_page, }, .ring = { @@ -705,8 +726,6 @@ static struct radeon_asic rs690_asic = { .wait_for_vblank = &avivo_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &r600_hdmi_enable, - .hdmi_setmode = &r600_hdmi_setmode, }, .copy = { .blit = &r100_copy_blit, @@ -756,8 +775,10 @@ static struct radeon_asic rv515_asic = { .mmio_hdp_flush = NULL, .gui_idle = &r100_gui_idle, .mc_wait_for_idle = &rv515_mc_wait_for_idle, + .get_allowed_info_register = radeon_invalid_get_allowed_info_register, .gart = { .tlb_flush = &rv370_pcie_gart_tlb_flush, + .get_page_entry = &rv370_pcie_gart_get_page_entry, .set_page = &rv370_pcie_gart_set_page, }, .ring = { @@ -822,8 +843,10 @@ static struct radeon_asic r520_asic = { .mmio_hdp_flush = NULL, .gui_idle = &r100_gui_idle, .mc_wait_for_idle = &r520_mc_wait_for_idle, + .get_allowed_info_register = radeon_invalid_get_allowed_info_register, .gart = { .tlb_flush = &rv370_pcie_gart_tlb_flush, + .get_page_entry = &rv370_pcie_gart_get_page_entry, .set_page = &rv370_pcie_gart_set_page, }, .ring = { @@ -878,7 +901,7 @@ static struct radeon_asic r520_asic = { }, }; -static struct radeon_asic_ring r600_gfx_ring = { +static const struct radeon_asic_ring r600_gfx_ring = { .ib_execute = &r600_ring_ib_execute, .emit_fence = &r600_fence_ring_emit, .emit_semaphore = &r600_semaphore_ring_emit, @@ -891,7 +914,7 @@ static struct radeon_asic_ring r600_gfx_ring = { .set_wptr = &r600_gfx_set_wptr, }; -static struct radeon_asic_ring r600_dma_ring = { +static const struct radeon_asic_ring r600_dma_ring = { .ib_execute = &r600_dma_ring_ib_execute, .emit_fence = &r600_dma_fence_ring_emit, .emit_semaphore = &r600_dma_semaphore_ring_emit, @@ -916,8 +939,10 @@ static struct radeon_asic r600_asic = { .mc_wait_for_idle = &r600_mc_wait_for_idle, .get_xclk = &r600_get_xclk, .get_gpu_clock_counter = &r600_get_gpu_clock_counter, + .get_allowed_info_register = r600_get_allowed_info_register, .gart = { .tlb_flush = &r600_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -934,8 +959,6 @@ static struct radeon_asic r600_asic = { .wait_for_vblank = &avivo_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &r600_hdmi_enable, - .hdmi_setmode = &r600_hdmi_setmode, }, .copy = { .blit = &r600_copy_cpdma, @@ -976,7 +999,7 @@ static struct radeon_asic r600_asic = { }, }; -static struct radeon_asic_ring rv6xx_uvd_ring = { +static const struct radeon_asic_ring rv6xx_uvd_ring = { .ib_execute = &uvd_v1_0_ib_execute, .emit_fence = &uvd_v1_0_fence_emit, .emit_semaphore = &uvd_v1_0_semaphore_emit, @@ -1001,8 +1024,10 @@ static struct radeon_asic rv6xx_asic = { .mc_wait_for_idle = &r600_mc_wait_for_idle, .get_xclk = &r600_get_xclk, .get_gpu_clock_counter = &r600_get_gpu_clock_counter, + .get_allowed_info_register = r600_get_allowed_info_register, .gart = { .tlb_flush = &r600_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -1020,8 +1045,6 @@ static struct radeon_asic rv6xx_asic = { .wait_for_vblank = &avivo_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &r600_hdmi_enable, - .hdmi_setmode = &r600_hdmi_setmode, }, .copy = { .blit = &r600_copy_cpdma, @@ -1073,6 +1096,8 @@ static struct radeon_asic rv6xx_asic = { .print_power_state = &rv6xx_dpm_print_power_state, .debugfs_print_current_performance_level = &rv6xx_dpm_debugfs_print_current_performance_level, .force_performance_level = &rv6xx_dpm_force_performance_level, + .get_current_sclk = &rv6xx_dpm_get_current_sclk, + .get_current_mclk = &rv6xx_dpm_get_current_mclk, }, .pflip = { .page_flip = &rs600_page_flip, @@ -1092,8 +1117,10 @@ static struct radeon_asic rs780_asic = { .mc_wait_for_idle = &r600_mc_wait_for_idle, .get_xclk = &r600_get_xclk, .get_gpu_clock_counter = &r600_get_gpu_clock_counter, + .get_allowed_info_register = r600_get_allowed_info_register, .gart = { .tlb_flush = &r600_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -1111,8 +1138,6 @@ static struct radeon_asic rs780_asic = { .wait_for_vblank = &avivo_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &r600_hdmi_enable, - .hdmi_setmode = &r600_hdmi_setmode, }, .copy = { .blit = &r600_copy_cpdma, @@ -1164,6 +1189,8 @@ static struct radeon_asic rs780_asic = { .print_power_state = &rs780_dpm_print_power_state, .debugfs_print_current_performance_level = &rs780_dpm_debugfs_print_current_performance_level, .force_performance_level = &rs780_dpm_force_performance_level, + .get_current_sclk = &rs780_dpm_get_current_sclk, + .get_current_mclk = &rs780_dpm_get_current_mclk, }, .pflip = { .page_flip = &rs600_page_flip, @@ -1171,10 +1198,10 @@ static struct radeon_asic rs780_asic = { }, }; -static struct radeon_asic_ring rv770_uvd_ring = { +static const struct radeon_asic_ring rv770_uvd_ring = { .ib_execute = &uvd_v1_0_ib_execute, .emit_fence = &uvd_v2_2_fence_emit, - .emit_semaphore = &uvd_v1_0_semaphore_emit, + .emit_semaphore = &uvd_v2_2_semaphore_emit, .cs_parse = &radeon_uvd_cs_parse, .ring_test = &uvd_v1_0_ring_test, .ib_test = &uvd_v1_0_ib_test, @@ -1196,8 +1223,10 @@ static struct radeon_asic rv770_asic = { .mc_wait_for_idle = &r600_mc_wait_for_idle, .get_xclk = &rv770_get_xclk, .get_gpu_clock_counter = &r600_get_gpu_clock_counter, + .get_allowed_info_register = r600_get_allowed_info_register, .gart = { .tlb_flush = &r600_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -1215,8 +1244,6 @@ static struct radeon_asic rv770_asic = { .wait_for_vblank = &avivo_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &r600_hdmi_enable, - .hdmi_setmode = &dce3_1_hdmi_setmode, }, .copy = { .blit = &r600_copy_cpdma, @@ -1269,6 +1296,8 @@ static struct radeon_asic rv770_asic = { .debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level, .force_performance_level = &rv770_dpm_force_performance_level, .vblank_too_short = &rv770_dpm_vblank_too_short, + .get_current_sclk = &rv770_dpm_get_current_sclk, + .get_current_mclk = &rv770_dpm_get_current_mclk, }, .pflip = { .page_flip = &rv770_page_flip, @@ -1276,7 +1305,7 @@ static struct radeon_asic rv770_asic = { }, }; -static struct radeon_asic_ring evergreen_gfx_ring = { +static const struct radeon_asic_ring evergreen_gfx_ring = { .ib_execute = &evergreen_ring_ib_execute, .emit_fence = &r600_fence_ring_emit, .emit_semaphore = &r600_semaphore_ring_emit, @@ -1289,7 +1318,7 @@ static struct radeon_asic_ring evergreen_gfx_ring = { .set_wptr = &r600_gfx_set_wptr, }; -static struct radeon_asic_ring evergreen_dma_ring = { +static const struct radeon_asic_ring evergreen_dma_ring = { .ib_execute = &evergreen_dma_ring_ib_execute, .emit_fence = &evergreen_dma_fence_ring_emit, .emit_semaphore = &r600_dma_semaphore_ring_emit, @@ -1314,8 +1343,10 @@ static struct radeon_asic evergreen_asic = { .mc_wait_for_idle = &evergreen_mc_wait_for_idle, .get_xclk = &rv770_get_xclk, .get_gpu_clock_counter = &r600_get_gpu_clock_counter, + .get_allowed_info_register = evergreen_get_allowed_info_register, .gart = { .tlb_flush = &evergreen_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -1333,8 +1364,6 @@ static struct radeon_asic evergreen_asic = { .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &evergreen_hdmi_enable, - .hdmi_setmode = &evergreen_hdmi_setmode, }, .copy = { .blit = &r600_copy_cpdma, @@ -1387,6 +1416,8 @@ static struct radeon_asic evergreen_asic = { .debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level, .force_performance_level = &rv770_dpm_force_performance_level, .vblank_too_short = &cypress_dpm_vblank_too_short, + .get_current_sclk = &rv770_dpm_get_current_sclk, + .get_current_mclk = &rv770_dpm_get_current_mclk, }, .pflip = { .page_flip = &evergreen_page_flip, @@ -1406,8 +1437,10 @@ static struct radeon_asic sumo_asic = { .mc_wait_for_idle = &evergreen_mc_wait_for_idle, .get_xclk = &r600_get_xclk, .get_gpu_clock_counter = &r600_get_gpu_clock_counter, + .get_allowed_info_register = evergreen_get_allowed_info_register, .gart = { .tlb_flush = &evergreen_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -1425,8 +1458,6 @@ static struct radeon_asic sumo_asic = { .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &evergreen_hdmi_enable, - .hdmi_setmode = &evergreen_hdmi_setmode, }, .copy = { .blit = &r600_copy_cpdma, @@ -1478,6 +1509,8 @@ static struct radeon_asic sumo_asic = { .print_power_state = &sumo_dpm_print_power_state, .debugfs_print_current_performance_level = &sumo_dpm_debugfs_print_current_performance_level, .force_performance_level = &sumo_dpm_force_performance_level, + .get_current_sclk = &sumo_dpm_get_current_sclk, + .get_current_mclk = &sumo_dpm_get_current_mclk, }, .pflip = { .page_flip = &evergreen_page_flip, @@ -1497,8 +1530,10 @@ static struct radeon_asic btc_asic = { .mc_wait_for_idle = &evergreen_mc_wait_for_idle, .get_xclk = &rv770_get_xclk, .get_gpu_clock_counter = &r600_get_gpu_clock_counter, + .get_allowed_info_register = evergreen_get_allowed_info_register, .gart = { .tlb_flush = &evergreen_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -1516,8 +1551,6 @@ static struct radeon_asic btc_asic = { .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &evergreen_hdmi_enable, - .hdmi_setmode = &evergreen_hdmi_setmode, }, .copy = { .blit = &r600_copy_cpdma, @@ -1570,6 +1603,8 @@ static struct radeon_asic btc_asic = { .debugfs_print_current_performance_level = &btc_dpm_debugfs_print_current_performance_level, .force_performance_level = &rv770_dpm_force_performance_level, .vblank_too_short = &btc_dpm_vblank_too_short, + .get_current_sclk = &btc_dpm_get_current_sclk, + .get_current_mclk = &btc_dpm_get_current_mclk, }, .pflip = { .page_flip = &evergreen_page_flip, @@ -1577,7 +1612,7 @@ static struct radeon_asic btc_asic = { }, }; -static struct radeon_asic_ring cayman_gfx_ring = { +static const struct radeon_asic_ring cayman_gfx_ring = { .ib_execute = &cayman_ring_ib_execute, .ib_parse = &evergreen_ib_parse, .emit_fence = &cayman_fence_ring_emit, @@ -1592,7 +1627,7 @@ static struct radeon_asic_ring cayman_gfx_ring = { .set_wptr = &cayman_gfx_set_wptr, }; -static struct radeon_asic_ring cayman_dma_ring = { +static const struct radeon_asic_ring cayman_dma_ring = { .ib_execute = &cayman_dma_ring_ib_execute, .ib_parse = &evergreen_dma_ib_parse, .emit_fence = &evergreen_dma_fence_ring_emit, @@ -1607,7 +1642,7 @@ static struct radeon_asic_ring cayman_dma_ring = { .set_wptr = &cayman_dma_set_wptr }; -static struct radeon_asic_ring cayman_uvd_ring = { +static const struct radeon_asic_ring cayman_uvd_ring = { .ib_execute = &uvd_v1_0_ib_execute, .emit_fence = &uvd_v2_2_fence_emit, .emit_semaphore = &uvd_v3_1_semaphore_emit, @@ -1632,8 +1667,10 @@ static struct radeon_asic cayman_asic = { .mc_wait_for_idle = &evergreen_mc_wait_for_idle, .get_xclk = &rv770_get_xclk, .get_gpu_clock_counter = &r600_get_gpu_clock_counter, + .get_allowed_info_register = cayman_get_allowed_info_register, .gart = { .tlb_flush = &cayman_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .vm = { @@ -1662,8 +1699,6 @@ static struct radeon_asic cayman_asic = { .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &evergreen_hdmi_enable, - .hdmi_setmode = &evergreen_hdmi_setmode, }, .copy = { .blit = &r600_copy_cpdma, @@ -1716,6 +1751,8 @@ static struct radeon_asic cayman_asic = { .debugfs_print_current_performance_level = &ni_dpm_debugfs_print_current_performance_level, .force_performance_level = &ni_dpm_force_performance_level, .vblank_too_short = &ni_dpm_vblank_too_short, + .get_current_sclk = &ni_dpm_get_current_sclk, + .get_current_mclk = &ni_dpm_get_current_mclk, }, .pflip = { .page_flip = &evergreen_page_flip, @@ -1723,6 +1760,19 @@ static struct radeon_asic cayman_asic = { }, }; +static const struct radeon_asic_ring trinity_vce_ring = { + .ib_execute = &radeon_vce_ib_execute, + .emit_fence = &radeon_vce_fence_emit, + .emit_semaphore = &radeon_vce_semaphore_emit, + .cs_parse = &radeon_vce_cs_parse, + .ring_test = &radeon_vce_ring_test, + .ib_test = &radeon_vce_ib_test, + .is_lockup = &radeon_ring_test_lockup, + .get_rptr = &vce_v1_0_get_rptr, + .get_wptr = &vce_v1_0_get_wptr, + .set_wptr = &vce_v1_0_set_wptr, +}; + static struct radeon_asic trinity_asic = { .init = &cayman_init, .fini = &cayman_fini, @@ -1735,8 +1785,10 @@ static struct radeon_asic trinity_asic = { .mc_wait_for_idle = &evergreen_mc_wait_for_idle, .get_xclk = &r600_get_xclk, .get_gpu_clock_counter = &r600_get_gpu_clock_counter, + .get_allowed_info_register = cayman_get_allowed_info_register, .gart = { .tlb_flush = &cayman_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .vm = { @@ -1754,6 +1806,8 @@ static struct radeon_asic trinity_asic = { [R600_RING_TYPE_DMA_INDEX] = &cayman_dma_ring, [CAYMAN_RING_TYPE_DMA1_INDEX] = &cayman_dma_ring, [R600_RING_TYPE_UVD_INDEX] = &cayman_uvd_ring, + [TN_RING_TYPE_VCE1_INDEX] = &trinity_vce_ring, + [TN_RING_TYPE_VCE2_INDEX] = &trinity_vce_ring, }, .irq = { .set = &evergreen_irq_set, @@ -1765,8 +1819,6 @@ static struct radeon_asic trinity_asic = { .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &evergreen_hdmi_enable, - .hdmi_setmode = &evergreen_hdmi_setmode, }, .copy = { .blit = &r600_copy_cpdma, @@ -1800,6 +1852,7 @@ static struct radeon_asic trinity_asic = { .set_pcie_lanes = NULL, .set_clock_gating = NULL, .set_uvd_clocks = &sumo_set_uvd_clocks, + .set_vce_clocks = &tn_set_vce_clocks, .get_temperature = &tn_get_temp, }, .dpm = { @@ -1819,6 +1872,8 @@ static struct radeon_asic trinity_asic = { .debugfs_print_current_performance_level = &trinity_dpm_debugfs_print_current_performance_level, .force_performance_level = &trinity_dpm_force_performance_level, .enable_bapm = &trinity_dpm_enable_bapm, + .get_current_sclk = &trinity_dpm_get_current_sclk, + .get_current_mclk = &trinity_dpm_get_current_mclk, }, .pflip = { .page_flip = &evergreen_page_flip, @@ -1826,7 +1881,7 @@ static struct radeon_asic trinity_asic = { }, }; -static struct radeon_asic_ring si_gfx_ring = { +static const struct radeon_asic_ring si_gfx_ring = { .ib_execute = &si_ring_ib_execute, .ib_parse = &si_ib_parse, .emit_fence = &si_fence_ring_emit, @@ -1841,7 +1896,7 @@ static struct radeon_asic_ring si_gfx_ring = { .set_wptr = &cayman_gfx_set_wptr, }; -static struct radeon_asic_ring si_dma_ring = { +static const struct radeon_asic_ring si_dma_ring = { .ib_execute = &cayman_dma_ring_ib_execute, .ib_parse = &evergreen_dma_ib_parse, .emit_fence = &evergreen_dma_fence_ring_emit, @@ -1868,8 +1923,10 @@ static struct radeon_asic si_asic = { .mc_wait_for_idle = &evergreen_mc_wait_for_idle, .get_xclk = &si_get_xclk, .get_gpu_clock_counter = &si_get_gpu_clock_counter, + .get_allowed_info_register = si_get_allowed_info_register, .gart = { .tlb_flush = &si_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .vm = { @@ -1887,6 +1944,8 @@ static struct radeon_asic si_asic = { [R600_RING_TYPE_DMA_INDEX] = &si_dma_ring, [CAYMAN_RING_TYPE_DMA1_INDEX] = &si_dma_ring, [R600_RING_TYPE_UVD_INDEX] = &cayman_uvd_ring, + [TN_RING_TYPE_VCE1_INDEX] = &trinity_vce_ring, + [TN_RING_TYPE_VCE2_INDEX] = &trinity_vce_ring, }, .irq = { .set = &si_irq_set, @@ -1898,8 +1957,6 @@ static struct radeon_asic si_asic = { .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &evergreen_hdmi_enable, - .hdmi_setmode = &evergreen_hdmi_setmode, }, .copy = { .blit = &r600_copy_cpdma, @@ -1933,6 +1990,7 @@ static struct radeon_asic si_asic = { .set_pcie_lanes = &r600_set_pcie_lanes, .set_clock_gating = NULL, .set_uvd_clocks = &si_set_uvd_clocks, + .set_vce_clocks = &si_set_vce_clocks, .get_temperature = &si_get_temp, }, .dpm = { @@ -1952,6 +2010,12 @@ static struct radeon_asic si_asic = { .debugfs_print_current_performance_level = &si_dpm_debugfs_print_current_performance_level, .force_performance_level = &si_dpm_force_performance_level, .vblank_too_short = &ni_dpm_vblank_too_short, + .fan_ctrl_set_mode = &si_fan_ctrl_set_mode, + .fan_ctrl_get_mode = &si_fan_ctrl_get_mode, + .get_fan_speed_percent = &si_fan_ctrl_get_fan_speed_percent, + .set_fan_speed_percent = &si_fan_ctrl_set_fan_speed_percent, + .get_current_sclk = &si_dpm_get_current_sclk, + .get_current_mclk = &si_dpm_get_current_mclk, }, .pflip = { .page_flip = &evergreen_page_flip, @@ -1959,7 +2023,7 @@ static struct radeon_asic si_asic = { }, }; -static struct radeon_asic_ring ci_gfx_ring = { +static const struct radeon_asic_ring ci_gfx_ring = { .ib_execute = &cik_ring_ib_execute, .ib_parse = &cik_ib_parse, .emit_fence = &cik_fence_gfx_ring_emit, @@ -1974,7 +2038,7 @@ static struct radeon_asic_ring ci_gfx_ring = { .set_wptr = &cik_gfx_set_wptr, }; -static struct radeon_asic_ring ci_cp_ring = { +static const struct radeon_asic_ring ci_cp_ring = { .ib_execute = &cik_ring_ib_execute, .ib_parse = &cik_ib_parse, .emit_fence = &cik_fence_compute_ring_emit, @@ -1989,7 +2053,7 @@ static struct radeon_asic_ring ci_cp_ring = { .set_wptr = &cik_compute_set_wptr, }; -static struct radeon_asic_ring ci_dma_ring = { +static const struct radeon_asic_ring ci_dma_ring = { .ib_execute = &cik_sdma_ring_ib_execute, .ib_parse = &cik_ib_parse, .emit_fence = &cik_sdma_fence_ring_emit, @@ -2004,7 +2068,7 @@ static struct radeon_asic_ring ci_dma_ring = { .set_wptr = &cik_sdma_set_wptr, }; -static struct radeon_asic_ring ci_vce_ring = { +static const struct radeon_asic_ring ci_vce_ring = { .ib_execute = &radeon_vce_ib_execute, .emit_fence = &radeon_vce_fence_emit, .emit_semaphore = &radeon_vce_semaphore_emit, @@ -2029,8 +2093,10 @@ static struct radeon_asic ci_asic = { .mc_wait_for_idle = &evergreen_mc_wait_for_idle, .get_xclk = &cik_get_xclk, .get_gpu_clock_counter = &cik_get_gpu_clock_counter, + .get_allowed_info_register = cik_get_allowed_info_register, .gart = { .tlb_flush = &cik_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .vm = { @@ -2061,8 +2127,6 @@ static struct radeon_asic ci_asic = { .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &evergreen_hdmi_enable, - .hdmi_setmode = &evergreen_hdmi_setmode, }, .copy = { .blit = &cik_copy_cpdma, @@ -2117,6 +2181,12 @@ static struct radeon_asic ci_asic = { .force_performance_level = &ci_dpm_force_performance_level, .vblank_too_short = &ci_dpm_vblank_too_short, .powergate_uvd = &ci_dpm_powergate_uvd, + .fan_ctrl_set_mode = &ci_fan_ctrl_set_mode, + .fan_ctrl_get_mode = &ci_fan_ctrl_get_mode, + .get_fan_speed_percent = &ci_fan_ctrl_get_fan_speed_percent, + .set_fan_speed_percent = &ci_fan_ctrl_set_fan_speed_percent, + .get_current_sclk = &ci_dpm_get_current_sclk, + .get_current_mclk = &ci_dpm_get_current_mclk, }, .pflip = { .page_flip = &evergreen_page_flip, @@ -2136,8 +2206,10 @@ static struct radeon_asic kv_asic = { .mc_wait_for_idle = &evergreen_mc_wait_for_idle, .get_xclk = &cik_get_xclk, .get_gpu_clock_counter = &cik_get_gpu_clock_counter, + .get_allowed_info_register = cik_get_allowed_info_register, .gart = { .tlb_flush = &cik_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .vm = { @@ -2168,8 +2240,6 @@ static struct radeon_asic kv_asic = { .wait_for_vblank = &dce4_wait_for_vblank, .set_backlight_level = &atombios_set_backlight_level, .get_backlight_level = &atombios_get_backlight_level, - .hdmi_enable = &evergreen_hdmi_enable, - .hdmi_setmode = &evergreen_hdmi_setmode, }, .copy = { .blit = &cik_copy_cpdma, @@ -2224,6 +2294,8 @@ static struct radeon_asic kv_asic = { .force_performance_level = &kv_dpm_force_performance_level, .powergate_uvd = &kv_dpm_powergate_uvd, .enable_bapm = &kv_dpm_enable_bapm, + .get_current_sclk = &kv_dpm_get_current_sclk, + .get_current_mclk = &kv_dpm_get_current_mclk, }, .pflip = { .page_flip = &evergreen_page_flip, @@ -2252,6 +2324,7 @@ int radeon_asic_init(struct radeon_device *rdev) rdev->num_crtc = 2; rdev->has_uvd = false; + rdev->has_vce = false; switch (rdev->family) { case CHIP_R100: @@ -2382,6 +2455,9 @@ int radeon_asic_init(struct radeon_device *rdev) /* set num crtcs */ rdev->num_crtc = 4; rdev->has_uvd = true; + rdev->has_vce = true; + rdev->cg_flags = + RADEON_CG_SUPPORT_VCE_MGCG; break; case CHIP_TAHITI: case CHIP_PITCAIRN: @@ -2396,10 +2472,13 @@ int radeon_asic_init(struct radeon_device *rdev) rdev->num_crtc = 2; else rdev->num_crtc = 6; - if (rdev->family == CHIP_HAINAN) - rdev->has_uvd = false; - else - rdev->has_uvd = true; + if (rdev->family == CHIP_HAINAN) { + rdev->has_uvd = false; + rdev->has_vce = false; + } else { + rdev->has_uvd = true; + rdev->has_vce = true; + } switch (rdev->family) { case CHIP_TAHITI: rdev->cg_flags = @@ -2504,6 +2583,7 @@ int radeon_asic_init(struct radeon_device *rdev) rdev->asic = &ci_asic; rdev->num_crtc = 6; rdev->has_uvd = true; + rdev->has_vce = true; if (rdev->family == CHIP_BONAIRE) { rdev->cg_flags = RADEON_CG_SUPPORT_GFX_MGCG | @@ -2604,6 +2684,7 @@ int radeon_asic_init(struct radeon_device *rdev) RADEON_PG_SUPPORT_SAMU;*/ } rdev->has_uvd = true; + rdev->has_vce = true; break; default: /* FIXME: not supported yet */ @@ -2615,6 +2696,11 @@ int radeon_asic_init(struct radeon_device *rdev) rdev->asic->pm.set_memory_clock = NULL; } + if (!radeon_uvd) + rdev->has_uvd = false; + if (!radeon_vce) + rdev->has_vce = false; + return 0; } diff --git a/sys/dev/drm/radeon/radeon_asic.h b/sys/dev/drm/radeon/radeon_asic.h index b268152d0e..5f57d8a495 100644 --- a/sys/dev/drm/radeon/radeon_asic.h +++ b/sys/dev/drm/radeon/radeon_asic.h @@ -64,11 +64,12 @@ int r100_suspend(struct radeon_device *rdev); int r100_resume(struct radeon_device *rdev); void r100_vga_set_state(struct radeon_device *rdev, bool state); bool r100_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp); -int r100_asic_reset(struct radeon_device *rdev); +int r100_asic_reset(struct radeon_device *rdev, bool hard); u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc); void r100_pci_gart_tlb_flush(struct radeon_device *rdev); +uint64_t r100_pci_gart_get_page_entry(uint64_t addr, uint32_t flags); void r100_pci_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags); + uint64_t entry); void r100_ring_start(struct radeon_device *rdev, struct radeon_ring *ring); int r100_irq_set(struct radeon_device *rdev); irqreturn_t r100_irq_process(struct radeon_device *rdev); @@ -137,7 +138,7 @@ extern void r100_pm_finish(struct radeon_device *rdev); extern void r100_pm_init_profile(struct radeon_device *rdev); extern void r100_pm_get_dynpm_state(struct radeon_device *rdev); extern void r100_page_flip(struct radeon_device *rdev, int crtc, - u64 crtc_base); + u64 crtc_base, bool async); extern bool r100_page_flip_pending(struct radeon_device *rdev, int crtc); extern void r100_wait_for_vblank(struct radeon_device *rdev, int crtc); extern int r100_mc_wait_for_idle(struct radeon_device *rdev); @@ -166,14 +167,15 @@ extern int r300_init(struct radeon_device *rdev); extern void r300_fini(struct radeon_device *rdev); extern int r300_suspend(struct radeon_device *rdev); extern int r300_resume(struct radeon_device *rdev); -extern int r300_asic_reset(struct radeon_device *rdev); +extern int r300_asic_reset(struct radeon_device *rdev, bool hard); extern void r300_ring_start(struct radeon_device *rdev, struct radeon_ring *ring); extern void r300_fence_ring_emit(struct radeon_device *rdev, struct radeon_fence *fence); extern int r300_cs_parse(struct radeon_cs_parser *p); extern void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev); +extern uint64_t rv370_pcie_gart_get_page_entry(uint64_t addr, uint32_t flags); extern void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags); + uint64_t entry); extern void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes); extern int rv370_get_pcie_lanes(struct radeon_device *rdev); extern void r300_set_reg_safe(struct radeon_device *rdev); @@ -207,8 +209,9 @@ extern void rs400_fini(struct radeon_device *rdev); extern int rs400_suspend(struct radeon_device *rdev); extern int rs400_resume(struct radeon_device *rdev); void rs400_gart_tlb_flush(struct radeon_device *rdev); +uint64_t rs400_gart_get_page_entry(uint64_t addr, uint32_t flags); void rs400_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags); + uint64_t entry); uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg); void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); int rs400_gart_init(struct radeon_device *rdev); @@ -221,7 +224,7 @@ extern int rs400_mc_wait_for_idle(struct radeon_device *rdev); /* * rs600. */ -extern int rs600_asic_reset(struct radeon_device *rdev); +extern int rs600_asic_reset(struct radeon_device *rdev, bool hard); extern int rs600_init(struct radeon_device *rdev); extern void rs600_fini(struct radeon_device *rdev); extern int rs600_suspend(struct radeon_device *rdev); @@ -231,8 +234,9 @@ irqreturn_t rs600_irq_process(struct radeon_device *rdev); void rs600_irq_disable(struct radeon_device *rdev); u32 rs600_get_vblank_counter(struct radeon_device *rdev, int crtc); void rs600_gart_tlb_flush(struct radeon_device *rdev); +uint64_t rs600_gart_get_page_entry(uint64_t addr, uint32_t flags); void rs600_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags); + uint64_t entry); uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg); void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); void rs600_bandwidth_update(struct radeon_device *rdev); @@ -245,7 +249,7 @@ extern void rs600_pm_misc(struct radeon_device *rdev); extern void rs600_pm_prepare(struct radeon_device *rdev); extern void rs600_pm_finish(struct radeon_device *rdev); extern void rs600_page_flip(struct radeon_device *rdev, int crtc, - u64 crtc_base); + u64 crtc_base, bool async); extern bool rs600_page_flip_pending(struct radeon_device *rdev, int crtc); void rs600_set_safe_registers(struct radeon_device *rdev); extern void avivo_wait_for_vblank(struct radeon_device *rdev, int crtc); @@ -315,7 +319,7 @@ void r600_pciep_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); int r600_cs_parse(struct radeon_cs_parser *p); int r600_dma_cs_parse(struct radeon_cs_parser *p); int r600_dma_cs_next_reloc(struct radeon_cs_parser *p, - struct radeon_cs_reloc **cs_reloc); + struct radeon_bo_list **cs_reloc); u32 r600_gpu_check_soft_reset(struct radeon_device *rdev); void r600_fence_ring_emit(struct radeon_device *rdev, struct radeon_fence *fence); @@ -332,7 +336,7 @@ bool r600_dma_semaphore_ring_emit(struct radeon_device *rdev, void r600_dma_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); bool r600_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring); bool r600_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp); -int r600_asic_reset(struct radeon_device *rdev); +int r600_asic_reset(struct radeon_device *rdev, bool hard); int r600_set_surface_reg(struct radeon_device *rdev, int reg, uint32_t tiling_flags, uint32_t pitch, uint32_t offset, uint32_t obj_size); @@ -381,6 +385,8 @@ u32 r600_gfx_get_wptr(struct radeon_device *rdev, void r600_gfx_set_wptr(struct radeon_device *rdev, struct radeon_ring *ring); void r600_fini_microcode(struct radeon_device *rdev); +int r600_get_allowed_info_register(struct radeon_device *rdev, + u32 reg, u32 *val); /* r600 irq */ irqreturn_t r600_irq_process(struct radeon_device *rdev); int r600_irq_init(struct radeon_device *rdev); @@ -391,7 +397,6 @@ void r600_irq_suspend(struct radeon_device *rdev); void r600_disable_interrupts(struct radeon_device *rdev); void r600_rlc_stop(struct radeon_device *rdev); /* r600 audio */ -int r600_audio_init(struct radeon_device *rdev); void r600_audio_fini(struct radeon_device *rdev); void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock); void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder, void *buffer, @@ -400,8 +405,6 @@ void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock); void r600_hdmi_audio_workaround(struct drm_encoder *encoder); int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder); void r600_hdmi_update_audio_settings(struct drm_encoder *encoder); -void r600_hdmi_enable(struct drm_encoder *encoder, bool enable); -void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode); u32 r600_get_xclk(struct radeon_device *rdev); uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev); int rv6xx_get_temp(struct radeon_device *rdev); @@ -432,6 +435,8 @@ void rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rde struct seq_file *m); int rv6xx_dpm_force_performance_level(struct radeon_device *rdev, enum radeon_dpm_forced_level level); +u32 rv6xx_dpm_get_current_sclk(struct radeon_device *rdev); +u32 rv6xx_dpm_get_current_mclk(struct radeon_device *rdev); /* rs780 dpm */ int rs780_dpm_init(struct radeon_device *rdev); int rs780_dpm_enable(struct radeon_device *rdev); @@ -448,6 +453,8 @@ void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rde struct seq_file *m); int rs780_dpm_force_performance_level(struct radeon_device *rdev, enum radeon_dpm_forced_level level); +u32 rs780_dpm_get_current_sclk(struct radeon_device *rdev); +u32 rs780_dpm_get_current_mclk(struct radeon_device *rdev); /* * rv770,rv730,rv710,rv740 @@ -457,7 +464,8 @@ void rv770_fini(struct radeon_device *rdev); int rv770_suspend(struct radeon_device *rdev); int rv770_resume(struct radeon_device *rdev); void rv770_pm_misc(struct radeon_device *rdev); -void rv770_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base); +void rv770_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base, + bool async); bool rv770_page_flip_pending(struct radeon_device *rdev, int crtc); void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc); void r700_cp_stop(struct radeon_device *rdev); @@ -469,8 +477,6 @@ int rv770_copy_dma(struct radeon_device *rdev, u32 rv770_get_xclk(struct radeon_device *rdev); int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk); int rv770_get_temp(struct radeon_device *rdev); -/* hdmi */ -void dce3_1_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode); /* rv7xx pm */ int rv770_dpm_init(struct radeon_device *rdev); int rv770_dpm_enable(struct radeon_device *rdev); @@ -487,6 +493,8 @@ void rv770_dpm_print_power_state(struct radeon_device *rdev, void rv770_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, struct seq_file *m); bool rv770_dpm_vblank_too_short(struct radeon_device *rdev); +u32 rv770_dpm_get_current_sclk(struct radeon_device *rdev); +u32 rv770_dpm_get_current_mclk(struct radeon_device *rdev); void rv770_set_clk_bypass_mode(struct radeon_device *rdev); /* @@ -505,7 +513,7 @@ int evergreen_suspend(struct radeon_device *rdev); int evergreen_resume(struct radeon_device *rdev); bool evergreen_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp); bool evergreen_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp); -int evergreen_asic_reset(struct radeon_device *rdev); +int evergreen_asic_reset(struct radeon_device *rdev, bool hard); void evergreen_bandwidth_update(struct radeon_device *rdev); void evergreen_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); void evergreen_hpd_init(struct radeon_device *rdev); @@ -526,7 +534,7 @@ extern void btc_pm_init_profile(struct radeon_device *rdev); int sumo_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk); int evergreen_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk); extern void evergreen_page_flip(struct radeon_device *rdev, int crtc, - u64 crtc_base); + u64 crtc_base, bool async); extern bool evergreen_page_flip_pending(struct radeon_device *rdev, int crtc); extern void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc); void evergreen_disable_interrupt_state(struct radeon_device *rdev); @@ -555,9 +563,9 @@ void evergreen_mc_program(struct radeon_device *rdev); int evergreen_mc_init(struct radeon_device *rdev); void evergreen_irq_suspend(struct radeon_device *rdev); bool evergreen_is_display_hung(struct radeon_device *rdev); -void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable); -void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode); int evergreen_get_temp(struct radeon_device *rdev); +int evergreen_get_allowed_info_register(struct radeon_device *rdev, + u32 reg, u32 *val); int sumo_get_temp(struct radeon_device *rdev); int tn_get_temp(struct radeon_device *rdev); int cypress_dpm_init(struct radeon_device *rdev); @@ -581,6 +589,8 @@ u32 btc_dpm_get_mclk(struct radeon_device *rdev, bool low); bool btc_dpm_vblank_too_short(struct radeon_device *rdev); void btc_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, struct seq_file *m); +u32 btc_dpm_get_current_sclk(struct radeon_device *rdev); +u32 btc_dpm_get_current_mclk(struct radeon_device *rdev); int sumo_dpm_init(struct radeon_device *rdev); int sumo_dpm_enable(struct radeon_device *rdev); int sumo_dpm_late_enable(struct radeon_device *rdev); @@ -599,6 +609,8 @@ void sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev struct seq_file *m); int sumo_dpm_force_performance_level(struct radeon_device *rdev, enum radeon_dpm_forced_level level); +u32 sumo_dpm_get_current_sclk(struct radeon_device *rdev); +u32 sumo_dpm_get_current_mclk(struct radeon_device *rdev); /* * cayman @@ -610,11 +622,12 @@ int cayman_init(struct radeon_device *rdev); void cayman_fini(struct radeon_device *rdev); int cayman_suspend(struct radeon_device *rdev); int cayman_resume(struct radeon_device *rdev); -int cayman_asic_reset(struct radeon_device *rdev); +int cayman_asic_reset(struct radeon_device *rdev, bool hard); void cayman_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); int cayman_vm_init(struct radeon_device *rdev); void cayman_vm_fini(struct radeon_device *rdev); -void cayman_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); +void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, + unsigned vm_id, uint64_t pd_addr); uint32_t cayman_vm_page_flags(struct radeon_device *rdev, uint32_t flags); void cayman_vm_decode_fault(struct radeon_device *rdev, u32 status, u32 addr); @@ -642,7 +655,8 @@ void cayman_dma_vm_set_pages(struct radeon_device *rdev, uint32_t incr, uint32_t flags); void cayman_dma_vm_pad_ib(struct radeon_ib *ib); -void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); +void cayman_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, + unsigned vm_id, uint64_t pd_addr); u32 cayman_gfx_get_rptr(struct radeon_device *rdev, struct radeon_ring *ring); @@ -656,6 +670,8 @@ uint32_t cayman_dma_get_wptr(struct radeon_device *rdev, struct radeon_ring *ring); void cayman_dma_set_wptr(struct radeon_device *rdev, struct radeon_ring *ring); +int cayman_get_allowed_info_register(struct radeon_device *rdev, + u32 reg, u32 *val); void cayman_cp_int_cntl_setup(struct radeon_device *rdev, int ring, u32 cp_int_cntl); @@ -676,6 +692,8 @@ void ni_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, int ni_dpm_force_performance_level(struct radeon_device *rdev, enum radeon_dpm_forced_level level); //bool ni_dpm_vblank_too_short(struct radeon_device *rdev); +u32 ni_dpm_get_current_sclk(struct radeon_device *rdev); +u32 ni_dpm_get_current_mclk(struct radeon_device *rdev); int trinity_dpm_init(struct radeon_device *rdev); int trinity_dpm_enable(struct radeon_device *rdev); int trinity_dpm_late_enable(struct radeon_device *rdev); @@ -695,17 +713,15 @@ void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *r int trinity_dpm_force_performance_level(struct radeon_device *rdev, enum radeon_dpm_forced_level level); void trinity_dpm_enable_bapm(struct radeon_device *rdev, bool enable); +u32 trinity_dpm_get_current_sclk(struct radeon_device *rdev); +u32 trinity_dpm_get_current_mclk(struct radeon_device *rdev); +int tn_set_vce_clocks(struct radeon_device *rdev, u32 evclk, u32 ecclk); /* DCE6 - SI */ void dce6_bandwidth_update(struct radeon_device *rdev); -int dce6_audio_init(struct radeon_device *rdev); void dce6_audio_fini(struct radeon_device *rdev); -void dce6_afmt_write_sad_regs(struct drm_encoder *encoder); -void dce6_afmt_select_pin(struct drm_encoder *encoder); void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder); -void dce6_afmt_write_latency_fields(struct drm_encoder *encoder, - struct drm_display_mode *mode); /* * si @@ -719,13 +735,14 @@ int si_suspend(struct radeon_device *rdev); int si_resume(struct radeon_device *rdev); bool si_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp); bool si_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp); -int si_asic_reset(struct radeon_device *rdev); +int si_asic_reset(struct radeon_device *rdev, bool hard); void si_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); int si_irq_set(struct radeon_device *rdev); irqreturn_t si_irq_process(struct radeon_device *rdev); int si_vm_init(struct radeon_device *rdev); void si_vm_fini(struct radeon_device *rdev); -void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); +void si_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, + unsigned vm_id, uint64_t pd_addr); int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib); int si_copy_dma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, @@ -755,11 +772,15 @@ void si_dma_vm_set_pages(struct radeon_device *rdev, uint64_t addr, unsigned count, uint32_t incr, uint32_t flags); -void si_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); +void si_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, + unsigned vm_id, uint64_t pd_addr); u32 si_get_xclk(struct radeon_device *rdev); uint64_t si_get_gpu_clock_counter(struct radeon_device *rdev); int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk); +int si_set_vce_clocks(struct radeon_device *rdev, u32 evclk, u32 ecclk); int si_get_temp(struct radeon_device *rdev); +int si_get_allowed_info_register(struct radeon_device *rdev, + u32 reg, u32 *val); void si_rlc_fini(struct radeon_device *rdev); int si_rlc_init(struct radeon_device *rdev); void si_rlc_reset(struct radeon_device *rdev); @@ -782,6 +803,15 @@ void si_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, int si_dpm_force_performance_level(struct radeon_device *rdev, enum radeon_dpm_forced_level level); +int si_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev, + u32 *speed); +int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev, + u32 speed); +u32 si_fan_ctrl_get_mode(struct radeon_device *rdev); +void si_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode); +u32 si_dpm_get_current_sclk(struct radeon_device *rdev); +u32 si_dpm_get_current_mclk(struct radeon_device *rdev); + /* DCE8 - CIK */ void dce8_bandwidth_update(struct radeon_device *rdev); @@ -834,7 +864,7 @@ void cik_fini(struct radeon_device *rdev); int cik_suspend(struct radeon_device *rdev); int cik_resume(struct radeon_device *rdev); bool cik_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp); -int cik_asic_reset(struct radeon_device *rdev); +int cik_asic_reset(struct radeon_device *rdev, bool hard); void cik_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); int cik_ring_test(struct radeon_device *rdev, struct radeon_ring *ring); int cik_ib_test(struct radeon_device *rdev, struct radeon_ring *ring); @@ -842,7 +872,8 @@ int cik_irq_set(struct radeon_device *rdev); irqreturn_t cik_irq_process(struct radeon_device *rdev); int cik_vm_init(struct radeon_device *rdev); void cik_vm_fini(struct radeon_device *rdev); -void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); +void cik_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, + unsigned vm_id, uint64_t pd_addr); void cik_sdma_vm_copy_pages(struct radeon_device *rdev, struct radeon_ib *ib, @@ -860,7 +891,8 @@ void cik_sdma_vm_set_pages(struct radeon_device *rdev, uint32_t incr, uint32_t flags); void cik_sdma_vm_pad_ib(struct radeon_ib *ib); -void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); +void cik_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, + unsigned vm_id, uint64_t pd_addr); int cik_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib); u32 cik_gfx_get_rptr(struct radeon_device *rdev, struct radeon_ring *ring); @@ -889,6 +921,8 @@ int cik_sdma_resume(struct radeon_device *rdev); void cik_sdma_fini(struct radeon_device *rdev); int ci_get_temp(struct radeon_device *rdev); int kv_get_temp(struct radeon_device *rdev); +int cik_get_allowed_info_register(struct radeon_device *rdev, + u32 reg, u32 *val); int ci_dpm_init(struct radeon_device *rdev); int ci_dpm_enable(struct radeon_device *rdev); @@ -910,6 +944,15 @@ int ci_dpm_force_performance_level(struct radeon_device *rdev, enum radeon_dpm_forced_level level); bool ci_dpm_vblank_too_short(struct radeon_device *rdev); void ci_dpm_powergate_uvd(struct radeon_device *rdev, bool gate); +u32 ci_dpm_get_current_sclk(struct radeon_device *rdev); +u32 ci_dpm_get_current_mclk(struct radeon_device *rdev); + +int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev, + u32 *speed); +int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev, + u32 speed); +u32 ci_fan_ctrl_get_mode(struct radeon_device *rdev); +void ci_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode); int kv_dpm_init(struct radeon_device *rdev); int kv_dpm_enable(struct radeon_device *rdev); @@ -931,6 +974,8 @@ int kv_dpm_force_performance_level(struct radeon_device *rdev, enum radeon_dpm_forced_level level); void kv_dpm_powergate_uvd(struct radeon_device *rdev, bool gate); void kv_dpm_enable_bapm(struct radeon_device *rdev, bool enable); +u32 kv_dpm_get_current_sclk(struct radeon_device *rdev); +u32 kv_dpm_get_current_mclk(struct radeon_device *rdev); /* uvd v1.0 */ uint32_t uvd_v1_0_get_rptr(struct radeon_device *rdev, @@ -960,6 +1005,10 @@ void uvd_v1_0_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); int uvd_v2_2_resume(struct radeon_device *rdev); void uvd_v2_2_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence); +bool uvd_v2_2_semaphore_emit(struct radeon_device *rdev, + struct radeon_ring *ring, + struct radeon_semaphore *semaphore, + bool emit_wait); /* uvd v3.1 */ bool uvd_v3_1_semaphore_emit(struct radeon_device *rdev, @@ -977,10 +1026,14 @@ uint32_t vce_v1_0_get_wptr(struct radeon_device *rdev, struct radeon_ring *ring); void vce_v1_0_set_wptr(struct radeon_device *rdev, struct radeon_ring *ring); +int vce_v1_0_load_fw(struct radeon_device *rdev, uint32_t *data); +unsigned vce_v1_0_bo_size(struct radeon_device *rdev); +int vce_v1_0_resume(struct radeon_device *rdev); int vce_v1_0_init(struct radeon_device *rdev); int vce_v1_0_start(struct radeon_device *rdev); /* vce v2.0 */ +unsigned vce_v2_0_bo_size(struct radeon_device *rdev); int vce_v2_0_resume(struct radeon_device *rdev); void vce_v2_0_enable_mgcg(struct radeon_device *rdev, bool enable); diff --git a/sys/dev/drm/radeon/radeon_atombios.c b/sys/dev/drm/radeon/radeon_atombios.c index 620b94e6fd..10c6d9dab8 100644 --- a/sys/dev/drm/radeon/radeon_atombios.c +++ b/sys/dev/drm/radeon/radeon_atombios.c @@ -191,8 +191,8 @@ void radeon_atombios_i2c_init(struct radeon_device *rdev) } } -static struct radeon_gpio_rec radeon_lookup_gpio(struct radeon_device *rdev, - u8 id) +struct radeon_gpio_rec radeon_atombios_lookup_gpio(struct radeon_device *rdev, + u8 id) { struct atom_context *ctx = rdev->mode_info.atom_context; struct radeon_gpio_rec gpio; @@ -216,6 +216,7 @@ static struct radeon_gpio_rec radeon_lookup_gpio(struct radeon_device *rdev, if (id == pin->ucGPIO_ID) { gpio.id = pin->ucGPIO_ID; gpio.reg = le16_to_cpu(pin->usGpioPin_AIndex) * 4; + gpio.shift = pin->ucGpioPinBitShift; gpio.mask = (1 << pin->ucGpioPinBitShift); gpio.valid = true; break; @@ -431,7 +432,9 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, } /* Fujitsu D3003-S2 board lists DVI-I as DVI-D and VGA */ - if (((dev->pdev->device == 0x9802) || (dev->pdev->device == 0x9806)) && + if (((dev->pdev->device == 0x9802) || + (dev->pdev->device == 0x9805) || + (dev->pdev->device == 0x9806)) && (dev->pdev->subsystem_vendor == 0x1734) && (dev->pdev->subsystem_device == 0x11bd)) { if (*connector_type == DRM_MODE_CONNECTOR_VGA) { @@ -442,14 +445,6 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, } } - /* Fujitsu D3003-S2 board lists DVI-I as DVI-I and VGA */ - if ((dev->pdev->device == 0x9805) && - (dev->pdev->subsystem_vendor == 0x1734) && - (dev->pdev->subsystem_device == 0x11bd)) { - if (*connector_type == DRM_MODE_CONNECTOR_VGA) - return false; - } - return true; } @@ -796,7 +791,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) hpd_record = (ATOM_HPD_INT_RECORD *) record; - gpio = radeon_lookup_gpio(rdev, + gpio = radeon_atombios_lookup_gpio(rdev, hpd_record->ucHPDIntGPIOID); hpd = radeon_atom_get_hpd_info_from_gpio(rdev, &gpio); hpd.plugged_state = hpd_record->ucPlugged_PinState; @@ -1105,6 +1100,31 @@ union firmware_info { ATOM_FIRMWARE_INFO_V2_2 info_22; }; +union igp_info { + struct _ATOM_INTEGRATED_SYSTEM_INFO info; + struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2; + struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6; + struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7; + struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8; +}; + +static void radeon_atombios_get_dentist_vco_freq(struct radeon_device *rdev) +{ + struct radeon_mode_info *mode_info = &rdev->mode_info; + int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); + union igp_info *igp_info; + u8 frev, crev; + u16 data_offset; + + if (atom_parse_data_header(mode_info->atom_context, index, NULL, + &frev, &crev, &data_offset)) { + igp_info = (union igp_info *)(mode_info->atom_context->bios + + data_offset); + rdev->clock.vco_freq = + le32_to_cpu(igp_info->info_6.ulDentistVCOFreq); + } +} + bool radeon_atom_get_clock_info(struct drm_device *dev) { struct radeon_device *rdev = dev->dev_private; @@ -1129,7 +1149,7 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) le16_to_cpu(firmware_info->info.usReferenceClock); p1pll->reference_div = 0; - if (crev < 2) + if ((frev < 2) && (crev < 2)) p1pll->pll_out_min = le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output); else @@ -1138,7 +1158,7 @@ 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) { + if (((frev < 2) && (crev >= 4)) || (frev >= 2)) { p1pll->lcd_pll_out_min = le16_to_cpu(firmware_info->info_14.usLcdMinPixelClockPLL_Output) * 100; if (p1pll->lcd_pll_out_min == 0) @@ -1256,20 +1276,25 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) rdev->mode_info.firmware_flags = le16_to_cpu(firmware_info->info.usFirmwareCapability.susAccess); + if (ASIC_IS_DCE8(rdev)) + rdev->clock.vco_freq = + le32_to_cpu(firmware_info->info_22.ulGPUPLL_OutputFreq); + else if (ASIC_IS_DCE5(rdev)) + rdev->clock.vco_freq = rdev->clock.current_dispclk; + else if (ASIC_IS_DCE41(rdev)) + radeon_atombios_get_dentist_vco_freq(rdev); + else + rdev->clock.vco_freq = rdev->clock.current_dispclk; + + if (rdev->clock.vco_freq == 0) + rdev->clock.vco_freq = 360000; /* 3.6 GHz */ + return true; } return false; } -union igp_info { - struct _ATOM_INTEGRATED_SYSTEM_INFO info; - struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2; - struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6; - struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7; - struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8; -}; - bool radeon_atombios_sideport_present(struct radeon_device *rdev) { struct radeon_mode_info *mode_info = &rdev->mode_info; @@ -2125,7 +2150,7 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_GPIO; rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = - radeon_lookup_gpio(rdev, + radeon_atombios_lookup_gpio(rdev, power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex); if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = @@ -2161,7 +2186,7 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_GPIO; rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = - radeon_lookup_gpio(rdev, + radeon_atombios_lookup_gpio(rdev, power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex); if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = @@ -2197,7 +2222,7 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_GPIO; rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = - radeon_lookup_gpio(rdev, + radeon_atombios_lookup_gpio(rdev, power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex); if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = @@ -2245,6 +2270,14 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r /* add the i2c bus for thermal/fan chip */ if (controller->ucType > 0) { + if (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) + rdev->pm.no_fan = true; + rdev->pm.fan_pulses_per_revolution = + controller->ucFanParameters & ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK; + if (rdev->pm.fan_pulses_per_revolution) { + rdev->pm.fan_min_rpm = controller->ucFanMinRPM; + rdev->pm.fan_max_rpm = controller->ucFanMaxRPM; + } if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) { DRM_INFO("Internal thermal controller %s fan control\n", (controller->ucFanParameters & @@ -2309,6 +2342,7 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r controller->ucI2cAddress >> 1, (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + rdev->pm.int_thermal_type = THERMAL_TYPE_EXTERNAL; i2c_bus = radeon_lookup_i2c_gpio(rdev, controller->ucI2cLine); rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus); #ifdef DUMBBELL_WIP @@ -3278,6 +3312,7 @@ int radeon_atom_get_voltage_evv(struct radeon_device *rdev, args.in.ucVoltageType = VOLTAGE_TYPE_VDDC; args.in.ucVoltageMode = ATOM_GET_VOLTAGE_EVV_VOLTAGE; + args.in.usVoltageLevel = cpu_to_le16(virtual_voltage_id); args.in.ulSCLKFreq = cpu_to_le32(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[entry_id].clk); diff --git a/sys/dev/drm/radeon/radeon_audio.c b/sys/dev/drm/radeon/radeon_audio.c new file mode 100644 index 0000000000..2db205d436 --- /dev/null +++ b/sys/dev/drm/radeon/radeon_audio.c @@ -0,0 +1,720 @@ +/* + * Copyright 2014 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 shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Slava Grigorev + */ + +#include +#include +#include +#include "radeon.h" +#include "atom.h" +#include "radeon_audio.h" + +static void radeon_audio_hdmi_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode); +static void radeon_audio_dp_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode); + +static const u32 pin_offsets[7] = +{ + (0x5e00 - 0x5e00), + (0x5e18 - 0x5e00), + (0x5e30 - 0x5e00), + (0x5e48 - 0x5e00), + (0x5e60 - 0x5e00), + (0x5e78 - 0x5e00), + (0x5e90 - 0x5e00), +}; + +static u32 radeon_audio_rreg(struct radeon_device *rdev, u32 offset, u32 reg) +{ + return RREG32(reg); +} + +static void radeon_audio_wreg(struct radeon_device *rdev, u32 offset, + u32 reg, u32 v) +{ + WREG32(reg, v); +} + +static struct radeon_audio_basic_funcs r600_funcs = { + .endpoint_rreg = radeon_audio_rreg, + .endpoint_wreg = radeon_audio_wreg, + .enable = r600_audio_enable, +}; + +static struct radeon_audio_basic_funcs dce32_funcs = { + .endpoint_rreg = radeon_audio_rreg, + .endpoint_wreg = radeon_audio_wreg, + .enable = r600_audio_enable, +}; + +static struct radeon_audio_basic_funcs dce4_funcs = { + .endpoint_rreg = radeon_audio_rreg, + .endpoint_wreg = radeon_audio_wreg, + .enable = dce4_audio_enable, +}; + +static struct radeon_audio_basic_funcs dce6_funcs = { + .endpoint_rreg = dce6_endpoint_rreg, + .endpoint_wreg = dce6_endpoint_wreg, + .enable = dce6_audio_enable, +}; + +static struct radeon_audio_funcs r600_hdmi_funcs = { + .get_pin = r600_audio_get_pin, + .set_dto = r600_hdmi_audio_set_dto, + .update_acr = r600_hdmi_update_acr, + .set_vbi_packet = r600_set_vbi_packet, + .set_avi_packet = r600_set_avi_packet, + .set_audio_packet = r600_set_audio_packet, + .set_mute = r600_set_mute, + .mode_set = radeon_audio_hdmi_mode_set, + .dpms = r600_hdmi_enable, +}; + +static struct radeon_audio_funcs dce32_hdmi_funcs = { + .get_pin = r600_audio_get_pin, + .write_sad_regs = dce3_2_afmt_write_sad_regs, + .write_speaker_allocation = dce3_2_afmt_hdmi_write_speaker_allocation, + .set_dto = dce3_2_audio_set_dto, + .update_acr = dce3_2_hdmi_update_acr, + .set_vbi_packet = r600_set_vbi_packet, + .set_avi_packet = r600_set_avi_packet, + .set_audio_packet = dce3_2_set_audio_packet, + .set_mute = dce3_2_set_mute, + .mode_set = radeon_audio_hdmi_mode_set, + .dpms = r600_hdmi_enable, +}; + +static struct radeon_audio_funcs dce32_dp_funcs = { + .get_pin = r600_audio_get_pin, + .write_sad_regs = dce3_2_afmt_write_sad_regs, + .write_speaker_allocation = dce3_2_afmt_dp_write_speaker_allocation, + .set_dto = dce3_2_audio_set_dto, + .set_avi_packet = r600_set_avi_packet, + .set_audio_packet = dce3_2_set_audio_packet, +}; + +static struct radeon_audio_funcs dce4_hdmi_funcs = { + .get_pin = r600_audio_get_pin, + .write_sad_regs = evergreen_hdmi_write_sad_regs, + .write_speaker_allocation = dce4_afmt_hdmi_write_speaker_allocation, + .write_latency_fields = dce4_afmt_write_latency_fields, + .set_dto = dce4_hdmi_audio_set_dto, + .update_acr = evergreen_hdmi_update_acr, + .set_vbi_packet = dce4_set_vbi_packet, + .set_color_depth = dce4_hdmi_set_color_depth, + .set_avi_packet = evergreen_set_avi_packet, + .set_audio_packet = dce4_set_audio_packet, + .set_mute = dce4_set_mute, + .mode_set = radeon_audio_hdmi_mode_set, + .dpms = evergreen_hdmi_enable, +}; + +static struct radeon_audio_funcs dce4_dp_funcs = { + .get_pin = r600_audio_get_pin, + .write_sad_regs = evergreen_hdmi_write_sad_regs, + .write_speaker_allocation = dce4_afmt_dp_write_speaker_allocation, + .write_latency_fields = dce4_afmt_write_latency_fields, + .set_dto = dce4_dp_audio_set_dto, + .set_avi_packet = evergreen_set_avi_packet, + .set_audio_packet = dce4_set_audio_packet, + .mode_set = radeon_audio_dp_mode_set, + .dpms = evergreen_dp_enable, +}; + +static struct radeon_audio_funcs dce6_hdmi_funcs = { + .select_pin = dce6_afmt_select_pin, + .get_pin = dce6_audio_get_pin, + .write_sad_regs = dce6_afmt_write_sad_regs, + .write_speaker_allocation = dce6_afmt_hdmi_write_speaker_allocation, + .write_latency_fields = dce6_afmt_write_latency_fields, + .set_dto = dce6_hdmi_audio_set_dto, + .update_acr = evergreen_hdmi_update_acr, + .set_vbi_packet = dce4_set_vbi_packet, + .set_color_depth = dce4_hdmi_set_color_depth, + .set_avi_packet = evergreen_set_avi_packet, + .set_audio_packet = dce4_set_audio_packet, + .set_mute = dce4_set_mute, + .mode_set = radeon_audio_hdmi_mode_set, + .dpms = evergreen_hdmi_enable, +}; + +static struct radeon_audio_funcs dce6_dp_funcs = { + .select_pin = dce6_afmt_select_pin, + .get_pin = dce6_audio_get_pin, + .write_sad_regs = dce6_afmt_write_sad_regs, + .write_speaker_allocation = dce6_afmt_dp_write_speaker_allocation, + .write_latency_fields = dce6_afmt_write_latency_fields, + .set_dto = dce6_dp_audio_set_dto, + .set_avi_packet = evergreen_set_avi_packet, + .set_audio_packet = dce4_set_audio_packet, + .mode_set = radeon_audio_dp_mode_set, + .dpms = evergreen_dp_enable, +}; + +static void radeon_audio_enable(struct radeon_device *rdev, + struct r600_audio_pin *pin, u8 enable_mask) +{ + struct drm_encoder *encoder; + struct radeon_encoder *radeon_encoder; + struct radeon_encoder_atom_dig *dig; + int pin_count = 0; + + if (!pin) + return; + + if (rdev->mode_info.mode_config_initialized) { + list_for_each_entry(encoder, &rdev->ddev->mode_config.encoder_list, head) { + if (radeon_encoder_is_digital(encoder)) { + radeon_encoder = to_radeon_encoder(encoder); + dig = radeon_encoder->enc_priv; + if (dig->pin == pin) + pin_count++; + } + } + + if ((pin_count > 1) && (enable_mask == 0)) + return; + } + + if (rdev->audio.funcs->enable) + rdev->audio.funcs->enable(rdev, pin, enable_mask); +} + +static void radeon_audio_interface_init(struct radeon_device *rdev) +{ + if (ASIC_IS_DCE6(rdev)) { + rdev->audio.funcs = &dce6_funcs; + rdev->audio.hdmi_funcs = &dce6_hdmi_funcs; + rdev->audio.dp_funcs = &dce6_dp_funcs; + } else if (ASIC_IS_DCE4(rdev)) { + rdev->audio.funcs = &dce4_funcs; + rdev->audio.hdmi_funcs = &dce4_hdmi_funcs; + rdev->audio.dp_funcs = &dce4_dp_funcs; + } else if (ASIC_IS_DCE32(rdev)) { + rdev->audio.funcs = &dce32_funcs; + rdev->audio.hdmi_funcs = &dce32_hdmi_funcs; + rdev->audio.dp_funcs = &dce32_dp_funcs; + } else { + rdev->audio.funcs = &r600_funcs; + rdev->audio.hdmi_funcs = &r600_hdmi_funcs; + rdev->audio.dp_funcs = 0; + } +} + +static int radeon_audio_chipset_supported(struct radeon_device *rdev) +{ + return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev); +} + +int radeon_audio_init(struct radeon_device *rdev) +{ + int i; + + if (!radeon_audio || !radeon_audio_chipset_supported(rdev)) + return 0; + + rdev->audio.enabled = true; + + if (ASIC_IS_DCE83(rdev)) /* KB: 2 streams, 3 endpoints */ + rdev->audio.num_pins = 3; + else if (ASIC_IS_DCE81(rdev)) /* KV: 4 streams, 7 endpoints */ + rdev->audio.num_pins = 7; + else if (ASIC_IS_DCE8(rdev)) /* BN/HW: 6 streams, 7 endpoints */ + rdev->audio.num_pins = 7; + else if (ASIC_IS_DCE64(rdev)) /* OL: 2 streams, 2 endpoints */ + rdev->audio.num_pins = 2; + else if (ASIC_IS_DCE61(rdev)) /* TN: 4 streams, 6 endpoints */ + rdev->audio.num_pins = 6; + else if (ASIC_IS_DCE6(rdev)) /* SI: 6 streams, 6 endpoints */ + rdev->audio.num_pins = 6; + else + rdev->audio.num_pins = 1; + + for (i = 0; i < rdev->audio.num_pins; i++) { + rdev->audio.pin[i].channels = -1; + rdev->audio.pin[i].rate = -1; + rdev->audio.pin[i].bits_per_sample = -1; + rdev->audio.pin[i].status_bits = 0; + rdev->audio.pin[i].category_code = 0; + rdev->audio.pin[i].connected = false; + rdev->audio.pin[i].offset = pin_offsets[i]; + rdev->audio.pin[i].id = i; + } + + radeon_audio_interface_init(rdev); + + /* disable audio. it will be set up later */ + for (i = 0; i < rdev->audio.num_pins; i++) + radeon_audio_enable(rdev, &rdev->audio.pin[i], 0); + + return 0; +} + +u32 radeon_audio_endpoint_rreg(struct radeon_device *rdev, u32 offset, u32 reg) +{ + if (rdev->audio.funcs->endpoint_rreg) + return rdev->audio.funcs->endpoint_rreg(rdev, offset, reg); + + return 0; +} + +void radeon_audio_endpoint_wreg(struct radeon_device *rdev, u32 offset, + u32 reg, u32 v) +{ + if (rdev->audio.funcs->endpoint_wreg) + rdev->audio.funcs->endpoint_wreg(rdev, offset, reg, v); +} + +static void radeon_audio_write_sad_regs(struct drm_encoder *encoder) +{ + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct cea_sad *sads; + int sad_count; + + if (!connector) + return; + + sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads); + if (sad_count <= 0) { + DRM_ERROR("Couldn't read SADs: %d\n", sad_count); + return; + } + BUG_ON(!sads); + + if (radeon_encoder->audio && radeon_encoder->audio->write_sad_regs) + radeon_encoder->audio->write_sad_regs(encoder, sads, sad_count); + + kfree(sads); +} + +static void radeon_audio_write_speaker_allocation(struct drm_encoder *encoder) +{ + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + u8 *sadb = NULL; + int sad_count; + + if (!connector) + return; + + sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector), + &sadb); + if (sad_count < 0) { + DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n", + sad_count); + sad_count = 0; + } + + if (radeon_encoder->audio && radeon_encoder->audio->write_speaker_allocation) + radeon_encoder->audio->write_speaker_allocation(encoder, sadb, sad_count); + + kfree(sadb); +} + +static void radeon_audio_write_latency_fields(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + if (!connector) + return; + + if (radeon_encoder->audio && radeon_encoder->audio->write_latency_fields) + radeon_encoder->audio->write_latency_fields(encoder, connector, mode); +} + +struct r600_audio_pin* radeon_audio_get_pin(struct drm_encoder *encoder) +{ + struct radeon_device *rdev = encoder->dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + if (radeon_encoder->audio && radeon_encoder->audio->get_pin) + return radeon_encoder->audio->get_pin(rdev); + + return NULL; +} + +static void radeon_audio_select_pin(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + if (radeon_encoder->audio && radeon_encoder->audio->select_pin) + radeon_encoder->audio->select_pin(encoder); +} + +void radeon_audio_detect(struct drm_connector *connector, + struct drm_encoder *encoder, + enum drm_connector_status status) +{ + struct drm_device *dev = connector->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig; + + if (!radeon_audio_chipset_supported(rdev)) + return; + + if (!radeon_encoder_is_digital(encoder)) + return; + + dig = radeon_encoder->enc_priv; + + if (status == connector_status_connected) { + if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + + if (radeon_dp_getsinktype(radeon_connector) == + CONNECTOR_OBJECT_ID_DISPLAYPORT) + radeon_encoder->audio = rdev->audio.dp_funcs; + else + radeon_encoder->audio = rdev->audio.hdmi_funcs; + } else { + radeon_encoder->audio = rdev->audio.hdmi_funcs; + } + + if (drm_detect_monitor_audio(radeon_connector_edid(connector))) { + if (!dig->pin) + dig->pin = radeon_audio_get_pin(encoder); + radeon_audio_enable(rdev, dig->pin, 0xf); + } else { + radeon_audio_enable(rdev, dig->pin, 0); + dig->pin = NULL; + } + } else { + radeon_audio_enable(rdev, dig->pin, 0); + dig->pin = NULL; + } +} + +void radeon_audio_fini(struct radeon_device *rdev) +{ + int i; + + if (!rdev->audio.enabled) + return; + + for (i = 0; i < rdev->audio.num_pins; i++) + radeon_audio_enable(rdev, &rdev->audio.pin[i], 0); + + rdev->audio.enabled = false; +} + +static void radeon_audio_set_dto(struct drm_encoder *encoder, unsigned int clock) +{ + struct radeon_device *rdev = encoder->dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_crtc *crtc = to_radeon_crtc(encoder->crtc); + + if (radeon_encoder->audio && radeon_encoder->audio->set_dto) + radeon_encoder->audio->set_dto(rdev, crtc, clock); +} + +static int radeon_audio_set_avi_packet(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct radeon_device *rdev = encoder->dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE]; + struct hdmi_avi_infoframe frame; + int err; + + if (!connector) + return -EINVAL; + + err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode); + if (err < 0) { + DRM_ERROR("failed to setup AVI infoframe: %d\n", err); + return err; + } + + if (radeon_encoder->output_csc != RADEON_OUTPUT_CSC_BYPASS) { + if (drm_rgb_quant_range_selectable(radeon_connector_edid(connector))) { + if (radeon_encoder->output_csc == RADEON_OUTPUT_CSC_TVRGB) + frame.quantization_range = HDMI_QUANTIZATION_RANGE_LIMITED; + else + frame.quantization_range = HDMI_QUANTIZATION_RANGE_FULL; + } else { + frame.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT; + } + } + + err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer)); + if (err < 0) { + DRM_ERROR("failed to pack AVI infoframe: %d\n", err); + return err; + } + + if (dig && dig->afmt && radeon_encoder->audio && + radeon_encoder->audio->set_avi_packet) + radeon_encoder->audio->set_avi_packet(rdev, dig->afmt->offset, + buffer, sizeof(buffer)); + + return 0; +} + +/* + * calculate CTS and N values if they are not found in the table + */ +static void radeon_audio_calc_cts(unsigned int clock, int *CTS, int *N, int freq) +{ + int n, cts; + unsigned long div, mul; + + /* Safe, but overly large values */ + n = 128 * freq; + cts = clock * 1000; + + /* Smallest valid fraction */ + div = gcd64(n, cts); + + n /= div; + cts /= div; + + /* + * The optimal N is 128*freq/1000. Calculate the closest larger + * value that doesn't truncate any bits. + */ + mul = ((128*freq/1000) + (n-1))/n; + + n *= mul; + cts *= mul; + + /* Check that we are in spec (not always possible) */ + if (n < (128*freq/1500)) + printk(KERN_WARNING "Calculated ACR N value is too small. You may experience audio problems.\n"); + if (n > (128*freq/300)) + printk(KERN_WARNING "Calculated ACR N value is too large. You may experience audio problems.\n"); + + *N = n; + *CTS = cts; + + DRM_DEBUG("Calculated ACR timing N=%d CTS=%d for frequency %d\n", + *N, *CTS, freq); +} + +static const struct radeon_hdmi_acr* radeon_audio_acr(unsigned int clock) +{ + static struct radeon_hdmi_acr res; + u8 i; + + static const struct radeon_hdmi_acr hdmi_predefined_acr[] = { + /* 32kHz 44.1kHz 48kHz */ + /* Clock N CTS N CTS N CTS */ + { 25175, 4096, 25175, 28224, 125875, 6144, 25175 }, /* 25,20/1.001 MHz */ + { 25200, 4096, 25200, 6272, 28000, 6144, 25200 }, /* 25.20 MHz */ + { 27000, 4096, 27000, 6272, 30000, 6144, 27000 }, /* 27.00 MHz */ + { 27027, 4096, 27027, 6272, 30030, 6144, 27027 }, /* 27.00*1.001 MHz */ + { 54000, 4096, 54000, 6272, 60000, 6144, 54000 }, /* 54.00 MHz */ + { 54054, 4096, 54054, 6272, 60060, 6144, 54054 }, /* 54.00*1.001 MHz */ + { 74176, 4096, 74176, 5733, 75335, 6144, 74176 }, /* 74.25/1.001 MHz */ + { 74250, 4096, 74250, 6272, 82500, 6144, 74250 }, /* 74.25 MHz */ + { 148352, 4096, 148352, 5733, 150670, 6144, 148352 }, /* 148.50/1.001 MHz */ + { 148500, 4096, 148500, 6272, 165000, 6144, 148500 }, /* 148.50 MHz */ + }; + + /* Precalculated values for common clocks */ + for (i = 0; i < ARRAY_SIZE(hdmi_predefined_acr); i++) + if (hdmi_predefined_acr[i].clock == clock) + return &hdmi_predefined_acr[i]; + + /* And odd clocks get manually calculated */ + radeon_audio_calc_cts(clock, &res.cts_32khz, &res.n_32khz, 32000); + radeon_audio_calc_cts(clock, &res.cts_44_1khz, &res.n_44_1khz, 44100); + radeon_audio_calc_cts(clock, &res.cts_48khz, &res.n_48khz, 48000); + + return &res; +} + +/* + * update the N and CTS parameters for a given pixel clock rate + */ +static void radeon_audio_update_acr(struct drm_encoder *encoder, unsigned int clock) +{ + const struct radeon_hdmi_acr *acr = radeon_audio_acr(clock); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + + if (!dig || !dig->afmt) + return; + + if (radeon_encoder->audio && radeon_encoder->audio->update_acr) + radeon_encoder->audio->update_acr(encoder, dig->afmt->offset, acr); +} + +static void radeon_audio_set_vbi_packet(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + + if (!dig || !dig->afmt) + return; + + if (radeon_encoder->audio && radeon_encoder->audio->set_vbi_packet) + radeon_encoder->audio->set_vbi_packet(encoder, dig->afmt->offset); +} + +static void radeon_hdmi_set_color_depth(struct drm_encoder *encoder) +{ + int bpc = 8; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + + if (!dig || !dig->afmt) + return; + + if (encoder->crtc) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + bpc = radeon_crtc->bpc; + } + + if (radeon_encoder->audio && radeon_encoder->audio->set_color_depth) + radeon_encoder->audio->set_color_depth(encoder, dig->afmt->offset, bpc); +} + +static void radeon_audio_set_audio_packet(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + + if (!dig || !dig->afmt) + return; + + if (radeon_encoder->audio && radeon_encoder->audio->set_audio_packet) + radeon_encoder->audio->set_audio_packet(encoder, dig->afmt->offset); +} + +static void radeon_audio_set_mute(struct drm_encoder *encoder, bool mute) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + + if (!dig || !dig->afmt) + return; + + if (radeon_encoder->audio && radeon_encoder->audio->set_mute) + radeon_encoder->audio->set_mute(encoder, dig->afmt->offset, mute); +} + +/* + * update the info frames with the data from the current display mode + */ +static void radeon_audio_hdmi_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + + if (!dig || !dig->afmt) + return; + + if (!connector) + return; + + if (drm_detect_monitor_audio(radeon_connector_edid(connector))) { + radeon_audio_set_mute(encoder, true); + + radeon_audio_write_speaker_allocation(encoder); + radeon_audio_write_sad_regs(encoder); + radeon_audio_write_latency_fields(encoder, mode); + radeon_audio_set_dto(encoder, mode->clock); + radeon_audio_set_vbi_packet(encoder); + radeon_hdmi_set_color_depth(encoder); + radeon_audio_update_acr(encoder, mode->clock); + radeon_audio_set_audio_packet(encoder); + radeon_audio_select_pin(encoder); + + if (radeon_audio_set_avi_packet(encoder, mode) < 0) + return; + + radeon_audio_set_mute(encoder, false); + } else { + radeon_hdmi_set_color_depth(encoder); + + if (radeon_audio_set_avi_packet(encoder, mode) < 0) + return; + } +} + +static void radeon_audio_dp_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + 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; + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + + if (!dig || !dig->afmt) + return; + + if (!connector) + return; + + if (drm_detect_monitor_audio(radeon_connector_edid(connector))) { + radeon_audio_write_speaker_allocation(encoder); + radeon_audio_write_sad_regs(encoder); + radeon_audio_write_latency_fields(encoder, mode); + radeon_audio_set_dto(encoder, rdev->clock.vco_freq * 10); + radeon_audio_set_audio_packet(encoder); + radeon_audio_select_pin(encoder); + + if (radeon_audio_set_avi_packet(encoder, mode) < 0) + return; + } +} + +void radeon_audio_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + if (radeon_encoder->audio && radeon_encoder->audio->mode_set) + radeon_encoder->audio->mode_set(encoder, mode); +} + +void radeon_audio_dpms(struct drm_encoder *encoder, int mode) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + if (radeon_encoder->audio && radeon_encoder->audio->dpms) + radeon_encoder->audio->dpms(encoder, mode == DRM_MODE_DPMS_ON); +} + +unsigned int radeon_audio_decode_dfs_div(unsigned int div) +{ + if (div >= 8 && div < 64) + return (div - 8) * 25 + 200; + else if (div >= 64 && div < 96) + return (div - 64) * 50 + 1600; + else if (div >= 96 && div < 128) + return (div - 96) * 100 + 3200; + else + return 0; +} diff --git a/sys/dev/drm/radeon/radeon_audio.h b/sys/dev/drm/radeon/radeon_audio.h new file mode 100644 index 0000000000..3f3858da88 --- /dev/null +++ b/sys/dev/drm/radeon/radeon_audio.h @@ -0,0 +1,149 @@ +/* + * Copyright 2014 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 shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Slava Grigorev + */ + +#ifndef __RADEON_AUDIO_H__ +#define __RADEON_AUDIO_H__ + +#include + +#define RREG32_ENDPOINT(block, reg) \ + radeon_audio_endpoint_rreg(rdev, (block), (reg)) +#define WREG32_ENDPOINT(block, reg, v) \ + radeon_audio_endpoint_wreg(rdev, (block), (reg), (v)) + +struct radeon_audio_basic_funcs +{ + u32 (*endpoint_rreg)(struct radeon_device *rdev, u32 offset, u32 reg); + void (*endpoint_wreg)(struct radeon_device *rdev, + u32 offset, u32 reg, u32 v); + void (*enable)(struct radeon_device *rdev, + struct r600_audio_pin *pin, u8 enable_mask); +}; + +struct radeon_audio_funcs +{ + void (*select_pin)(struct drm_encoder *encoder); + struct r600_audio_pin* (*get_pin)(struct radeon_device *rdev); + void (*write_latency_fields)(struct drm_encoder *encoder, + struct drm_connector *connector, struct drm_display_mode *mode); + void (*write_sad_regs)(struct drm_encoder *encoder, + struct cea_sad *sads, int sad_count); + void (*write_speaker_allocation)(struct drm_encoder *encoder, + u8 *sadb, int sad_count); + void (*set_dto)(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock); + void (*update_acr)(struct drm_encoder *encoder, long offset, + const struct radeon_hdmi_acr *acr); + void (*set_vbi_packet)(struct drm_encoder *encoder, u32 offset); + void (*set_color_depth)(struct drm_encoder *encoder, u32 offset, int bpc); + void (*set_avi_packet)(struct radeon_device *rdev, u32 offset, + unsigned char *buffer, size_t size); + void (*set_audio_packet)(struct drm_encoder *encoder, u32 offset); + void (*set_mute)(struct drm_encoder *encoder, u32 offset, bool mute); + void (*mode_set)(struct drm_encoder *encoder, + struct drm_display_mode *mode); + void (*dpms)(struct drm_encoder *encoder, bool mode); +}; + +int radeon_audio_init(struct radeon_device *rdev); +void radeon_audio_detect(struct drm_connector *connector, + struct drm_encoder *encoder, + enum drm_connector_status status); +u32 radeon_audio_endpoint_rreg(struct radeon_device *rdev, + u32 offset, u32 reg); +void radeon_audio_endpoint_wreg(struct radeon_device *rdev, + u32 offset, u32 reg, u32 v); +struct r600_audio_pin *radeon_audio_get_pin(struct drm_encoder *encoder); +void radeon_audio_fini(struct radeon_device *rdev); +void radeon_audio_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode); +void radeon_audio_dpms(struct drm_encoder *encoder, int mode); +unsigned int radeon_audio_decode_dfs_div(unsigned int div); + +/* DragonFly compilation */ +void dce4_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin, + u8 enable_mask); +u32 dce6_endpoint_rreg(struct radeon_device *rdev, u32 offset, u32 reg); +void dce6_endpoint_wreg(struct radeon_device *rdev, + u32 offset, u32 reg, u32 v); +void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder, + struct cea_sad *sads, int sad_count); +void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder, + struct cea_sad *sads, int sad_count); +void dce6_afmt_write_sad_regs(struct drm_encoder *encoder, + struct cea_sad *sads, int sad_count); +void dce3_2_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count); +void dce3_2_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count); +void dce4_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count); +void dce4_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count); +void dce6_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count); +void dce6_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder, + u8 *sadb, int sad_count); +void dce4_afmt_write_latency_fields(struct drm_encoder *encoder, + struct drm_connector *connector, struct drm_display_mode *mode); +void dce6_afmt_write_latency_fields(struct drm_encoder *encoder, + struct drm_connector *connector, struct drm_display_mode *mode); +void dce6_afmt_select_pin(struct drm_encoder *encoder); +void r600_hdmi_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock); +void dce3_2_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock); +void dce4_hdmi_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock); +void dce4_dp_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock); +void dce6_hdmi_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock); +void dce6_dp_audio_set_dto(struct radeon_device *rdev, + struct radeon_crtc *crtc, unsigned int clock); +void r600_set_avi_packet(struct radeon_device *rdev, u32 offset, + unsigned char *buffer, size_t size); +void evergreen_set_avi_packet(struct radeon_device *rdev, u32 offset, + unsigned char *buffer, size_t size); +void r600_hdmi_update_acr(struct drm_encoder *encoder, long offset, + const struct radeon_hdmi_acr *acr); +void dce3_2_hdmi_update_acr(struct drm_encoder *encoder, long offset, + const struct radeon_hdmi_acr *acr); +void evergreen_hdmi_update_acr(struct drm_encoder *encoder, long offset, + const struct radeon_hdmi_acr *acr); +void r600_set_vbi_packet(struct drm_encoder *encoder, u32 offset); +void dce4_set_vbi_packet(struct drm_encoder *encoder, u32 offset); +void dce4_hdmi_set_color_depth(struct drm_encoder *encoder, + u32 offset, int bpc); +void r600_set_audio_packet(struct drm_encoder *encoder, u32 offset); +void dce3_2_set_audio_packet(struct drm_encoder *encoder, u32 offset); +void dce4_set_audio_packet(struct drm_encoder *encoder, u32 offset); +void r600_set_mute(struct drm_encoder *encoder, u32 offset, bool mute); +void dce3_2_set_mute(struct drm_encoder *encoder, u32 offset, bool mute); +void dce4_set_mute(struct drm_encoder *encoder, u32 offset, bool mute); +void r600_hdmi_enable(struct drm_encoder *encoder, bool enable); +void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable); +void evergreen_dp_enable(struct drm_encoder *encoder, bool enable); + +#endif diff --git a/sys/dev/drm/radeon/radeon_bios.c b/sys/dev/drm/radeon/radeon_bios.c index 64cac56fbc..27332090fc 100644 --- a/sys/dev/drm/radeon/radeon_bios.c +++ b/sys/dev/drm/radeon/radeon_bios.c @@ -78,7 +78,7 @@ static bool igp_read_bios_from_vram(struct radeon_device *rdev) static bool radeon_read_bios(struct radeon_device *rdev) { device_t vga_dev; - uint8_t __iomem *bios; + uint8_t __iomem *bios, val1, val2; size_t size; DRM_INFO("%s: ===> Try PCI Expansion ROM...\n", __func__); @@ -92,7 +92,10 @@ static bool radeon_read_bios(struct radeon_device *rdev) } DRM_INFO("%s: Map address: %p (%zu bytes)\n", __func__, bios, size); - if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) { + val1 = readb(&bios[0]); + val2 = readb(&bios[1]); + + if (size == 0 || val1 != 0x55 || val2 != 0xaa) { if (size == 0) { DRM_INFO("%s: Incorrect BIOS size\n", __func__); } else { @@ -102,8 +105,12 @@ static bool radeon_read_bios(struct radeon_device *rdev) vga_pci_unmap_bios(vga_dev, bios); return false; } - rdev->bios = kmalloc(size, M_DRM, M_WAITOK); - memcpy(rdev->bios, bios, size); + rdev->bios = kmalloc(size, M_DRM, M_WAITOK | M_ZERO); + if (rdev->bios == NULL) { + vga_pci_unmap_bios(vga_dev, bios); + return false; + } + memcpy_fromio(rdev->bios, bios, size); vga_pci_unmap_bios(vga_dev, bios); return true; } diff --git a/sys/dev/drm/radeon/radeon_combios.c b/sys/dev/drm/radeon/radeon_combios.c index 801ce035f3..2d95e1c51c 100644 --- a/sys/dev/drm/radeon/radeon_combios.c +++ b/sys/dev/drm/radeon/radeon_combios.c @@ -1254,10 +1254,15 @@ struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder if ((RBIOS16(tmp) == lvds->native_mode.hdisplay) && (RBIOS16(tmp + 2) == lvds->native_mode.vdisplay)) { + u32 hss = (RBIOS16(tmp + 21) - RBIOS16(tmp + 19) - 1) * 8; + + if (hss > lvds->native_mode.hdisplay) + hss = (10 - 1) * 8; + lvds->native_mode.htotal = lvds->native_mode.hdisplay + (RBIOS16(tmp + 17) - RBIOS16(tmp + 19)) * 8; lvds->native_mode.hsync_start = lvds->native_mode.hdisplay + - (RBIOS16(tmp + 21) - RBIOS16(tmp + 19) - 1) * 8; + hss; lvds->native_mode.hsync_end = lvds->native_mode.hsync_start + (RBIOS8(tmp + 23) * 8); @@ -3385,6 +3390,14 @@ void radeon_combios_asic_init(struct drm_device *dev) rdev->pdev->subsystem_device == 0x30ae) return; + /* quirk for rs4xx HP Compaq dc5750 Small Form Factor to make it resume + * - it hangs on resume inside the dynclk 1 table. + */ + if (rdev->family == CHIP_RS480 && + rdev->pdev->subsystem_vendor == 0x103c && + rdev->pdev->subsystem_device == 0x280a) + return; + /* DYN CLK 1 */ table = combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE); if (table) diff --git a/sys/dev/drm/radeon/radeon_connectors.c b/sys/dev/drm/radeon/radeon_connectors.c index c34f622bba..6a33e9dca7 100644 --- a/sys/dev/drm/radeon/radeon_connectors.c +++ b/sys/dev/drm/radeon/radeon_connectors.c @@ -29,6 +29,7 @@ #include #include #include "radeon.h" +#include "radeon_audio.h" #include "atom.h" #include @@ -76,6 +77,11 @@ void radeon_connector_hotplug(struct drm_connector *connector) if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) { drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); } else if (radeon_dp_needs_link_train(radeon_connector)) { + /* Don't try to start link training before we + * have the dpcd */ + if (!radeon_dp_getdpcd(radeon_connector)) + return; + /* set it to OFF so that drm_helper_connector_dpms() * won't return immediately since the current state * is ON at this point. @@ -290,10 +296,11 @@ struct edid *radeon_connector_edid(struct drm_connector *connector) return radeon_connector->edid; } -static void radeon_connector_get_edid(struct radeon_connector *radeon_connector) +static void radeon_connector_get_edid(struct drm_connector *connector) { - struct drm_device *dev = radeon_connector->base.dev; - struct radeon_device *rdev = dev->dev_private; + struct drm_device *dev = connector->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_connector *radeon_connector = to_radeon_connector(connector); if (radeon_connector->edid) return; @@ -302,34 +309,40 @@ static void radeon_connector_get_edid(struct radeon_connector *radeon_connector) if (radeon_connector->router.ddc_valid) radeon_router_select_ddc_port(radeon_connector); - if (radeon_connector_encoder_get_dp_bridge_encoder_id(&radeon_connector->base) != - ENCODER_OBJECT_ID_NONE) { - struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; - - if (dig->dp_i2c_bus) - radeon_connector->edid = drm_get_edid_iic(&radeon_connector->base, - dig->dp_i2c_bus->adapter); - } else if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) || - (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) { + if ((radeon_connector_encoder_get_dp_bridge_encoder_id(connector) != + ENCODER_OBJECT_ID_NONE) && + radeon_connector->ddc_bus->has_aux) { + radeon_connector->edid = drm_get_edid_iic(connector, + radeon_connector->ddc_bus->aux.dev->bsddev); + } else if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) || + (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) { struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT || - dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && dig->dp_i2c_bus) + dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && + radeon_connector->ddc_bus->has_aux) radeon_connector->edid = drm_get_edid_iic(&radeon_connector->base, - dig->dp_i2c_bus->adapter); - else if (radeon_connector->ddc_bus && !radeon_connector->edid) + radeon_connector->ddc_bus->aux.dev->bsddev); + else if (radeon_connector->ddc_bus) radeon_connector->edid = drm_get_edid_iic(&radeon_connector->base, - radeon_connector->ddc_bus->adapter); + radeon_connector->ddc_bus->adapter_dev); + } else if (radeon_connector->ddc_bus) { radeon_connector->edid = drm_get_edid_iic(&radeon_connector->base, - radeon_connector->ddc_bus->adapter); + radeon_connector->ddc_bus->adapter_dev); } if (!radeon_connector->edid) { + /* don't fetch the edid from the vbios if ddc fails and runpm is + * enabled so we report disconnected. + */ + if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0)) + return; + if (rdev->is_atom_bios) { /* some laptops provide a hardcoded edid in rom for LCDs */ - if (((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_LVDS) || - (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP))) + if (((connector->connector_type == DRM_MODE_CONNECTOR_LVDS) || + (connector->connector_type == DRM_MODE_CONNECTOR_eDP))) radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev); } else { /* some servers provide a hardcoded edid in rom for KVMs */ @@ -338,25 +351,28 @@ static void radeon_connector_get_edid(struct radeon_connector *radeon_connector) } } -static void radeon_connector_free_edid(struct radeon_connector *radeon_connector) +static void radeon_connector_free_edid(struct drm_connector *connector) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + if (radeon_connector->edid) { kfree(radeon_connector->edid); radeon_connector->edid = NULL; } } -static int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) +static int radeon_ddc_get_modes(struct drm_connector *connector) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); int ret; if (radeon_connector->edid) { - drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); - ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid); - drm_edid_to_eld(&radeon_connector->base, radeon_connector->edid); + drm_mode_connector_update_edid_property(connector, radeon_connector->edid); + ret = drm_add_edid_modes(connector, radeon_connector->edid); + drm_edid_to_eld(connector, radeon_connector->edid); return ret; } - drm_mode_connector_update_edid_property(&radeon_connector->base, NULL); + drm_mode_connector_update_edid_property(connector, NULL); return 0; } @@ -719,6 +735,30 @@ static int radeon_connector_set_property(struct drm_connector *connector, struct radeon_property_change_mode(&radeon_encoder->base); } + if (property == rdev->mode_info.output_csc_property) { + if (connector->encoder) + radeon_encoder = to_radeon_encoder(connector->encoder); + else { + const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; + radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector)); + } + + if (radeon_encoder->output_csc == val) + return 0; + + radeon_encoder->output_csc = val; + + if (connector->encoder->crtc) { + struct drm_crtc *crtc = connector->encoder->crtc; + const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + + radeon_crtc->output_csc = radeon_encoder->output_csc; + + (*crtc_funcs->load_lut)(crtc); + } + } + return 0; } @@ -759,14 +799,14 @@ static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder, static int radeon_lvds_get_modes(struct drm_connector *connector) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); +// struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder; int ret = 0; struct drm_display_mode *mode; - if (radeon_connector->ddc_bus) { - radeon_connector_get_edid(radeon_connector); - ret = radeon_ddc_get_modes(radeon_connector); +// if (radeon_connector->ddc_bus) { + radeon_connector_get_edid(connector); + ret = radeon_ddc_get_modes(connector); if (ret > 0) { encoder = radeon_best_single_encoder(connector); if (encoder) { @@ -776,7 +816,7 @@ static int radeon_lvds_get_modes(struct drm_connector *connector) } return ret; } - } +// } encoder = radeon_best_single_encoder(connector); if (!encoder) @@ -830,6 +870,8 @@ static int radeon_lvds_mode_valid(struct drm_connector *connector, static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connector, bool force) { + struct drm_device *dev = connector->dev; + struct radeon_device *rdev = dev->dev_private; struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder = radeon_best_single_encoder(connector); enum drm_connector_status ret = connector_status_disconnected; @@ -848,21 +890,27 @@ radeon_lvds_detect(struct drm_connector *connector, bool force) /* check if panel is valid */ if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240) ret = connector_status_connected; - + /* don't fetch the edid from the vbios if ddc fails and runpm is + * enabled so we report disconnected. + */ + if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0)) + ret = connector_status_disconnected; } /* check for edid as well */ - radeon_connector_get_edid(radeon_connector); + radeon_connector_get_edid(connector); if (radeon_connector->edid) ret = connector_status_connected; +#if defined(__DragonFly__) else { if (radeon_connector->ddc_bus) { radeon_connector->edid = drm_get_edid_iic(&radeon_connector->base, - radeon_connector->ddc_bus->adapter); + radeon_connector->ddc_bus->adapter_dev); if (radeon_connector->edid) ret = connector_status_connected; } } +#endif /* check acpi lid status ??? */ radeon_connector_update_scratch_regs(connector, ret); @@ -877,7 +925,7 @@ static void radeon_connector_destroy(struct drm_connector *connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); - radeon_connector_free_edid(radeon_connector); + radeon_connector_free_edid(connector); kfree(radeon_connector->con_priv); drm_connector_unregister(connector); drm_connector_cleanup(connector); @@ -936,11 +984,10 @@ static const struct drm_connector_funcs radeon_lvds_connector_funcs = { static int radeon_vga_get_modes(struct drm_connector *connector) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); int ret; - radeon_connector_get_edid(radeon_connector); - ret = radeon_ddc_get_modes(radeon_connector); + radeon_connector_get_edid(connector); + ret = radeon_ddc_get_modes(connector); radeon_get_native_mode(connector); @@ -987,8 +1034,8 @@ radeon_vga_detect(struct drm_connector *connector, bool force) dret = radeon_ddc_probe(radeon_connector, false); if (dret) { radeon_connector->detected_by_load = false; - radeon_connector_free_edid(radeon_connector); - radeon_connector_get_edid(radeon_connector); + radeon_connector_free_edid(connector); + radeon_connector_get_edid(connector); if (!radeon_connector->edid) { DRM_ERROR("%s: probed a monitor but no|invalid EDID\n", @@ -1002,7 +1049,7 @@ radeon_vga_detect(struct drm_connector *connector, bool force) * with a shared ddc line (often vga + hdmi) */ if (radeon_connector->use_digital && radeon_connector->shared_ddc) { - radeon_connector_free_edid(radeon_connector); + radeon_connector_free_edid(connector); ret = connector_status_disconnected; } else { ret = connector_status_connected; @@ -1208,8 +1255,8 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) dret = radeon_ddc_probe(radeon_connector, false); if (dret) { radeon_connector->detected_by_load = false; - radeon_connector_free_edid(radeon_connector); - radeon_connector_get_edid(radeon_connector); + radeon_connector_free_edid(connector); + radeon_connector_get_edid(connector); if (!radeon_connector->edid) { DRM_ERROR("%s: probed a monitor but no|invalid EDID\n", @@ -1234,7 +1281,7 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) * with a shared ddc line (often vga + hdmi) */ if ((!radeon_connector->use_digital) && radeon_connector->shared_ddc) { - radeon_connector_free_edid(radeon_connector); + radeon_connector_free_edid(connector); ret = connector_status_disconnected; } else { ret = connector_status_connected; @@ -1258,7 +1305,7 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) { /* hpd is our only option in this case */ if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) { - radeon_connector_free_edid(radeon_connector); + radeon_connector_free_edid(connector); ret = connector_status_disconnected; } } @@ -1349,6 +1396,17 @@ out: /* updated in get modes as well since we need to know if it's analog or digital */ radeon_connector_update_scratch_regs(connector, ret); + if ((radeon_audio != 0) && radeon_connector->use_digital) { + const struct drm_connector_helper_funcs *connector_funcs = + connector->helper_private; + + encoder = connector_funcs->best_encoder(connector); + if (encoder && (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)) { + radeon_connector_get_edid(connector); + radeon_audio_detect(connector, encoder, ret); + } + } + exit: #ifdef PM_TODO pm_runtime_mark_last_busy(connector->dev->dev); @@ -1454,20 +1512,6 @@ static const struct drm_connector_funcs radeon_dvi_connector_funcs = { .force = radeon_dvi_force, }; -static void radeon_dp_connector_destroy(struct drm_connector *connector) -{ - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; - - radeon_connector_free_edid(radeon_connector); - if (radeon_dig_connector->dp_i2c_bus) - radeon_i2c_destroy(radeon_dig_connector->dp_i2c_bus); - kfree(radeon_connector->con_priv); - drm_connector_unregister(connector); - drm_connector_cleanup(connector); - kfree(connector); -} - static int radeon_dp_get_modes(struct drm_connector *connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); @@ -1483,8 +1527,8 @@ static int radeon_dp_get_modes(struct drm_connector *connector) if (!radeon_dig_connector->edp_on) atombios_set_edp_panel_power(connector, ATOM_TRANSMITTER_ACTION_POWER_ON); - radeon_connector_get_edid(radeon_connector); - ret = radeon_ddc_get_modes(radeon_connector); + radeon_connector_get_edid(connector); + ret = radeon_ddc_get_modes(connector); if (!radeon_dig_connector->edp_on) atombios_set_edp_panel_power(connector, ATOM_TRANSMITTER_ACTION_POWER_OFF); @@ -1495,8 +1539,8 @@ static int radeon_dp_get_modes(struct drm_connector *connector) if (encoder) radeon_atom_ext_encoder_setup_ddc(encoder); } - radeon_connector_get_edid(radeon_connector); - ret = radeon_ddc_get_modes(radeon_connector); + radeon_connector_get_edid(connector); + ret = radeon_ddc_get_modes(connector); } if (ret > 0) { @@ -1529,8 +1573,8 @@ static int radeon_dp_get_modes(struct drm_connector *connector) if (encoder) radeon_atom_ext_encoder_setup_ddc(encoder); } - radeon_connector_get_edid(radeon_connector); - ret = radeon_ddc_get_modes(radeon_connector); + radeon_connector_get_edid(connector); + ret = radeon_ddc_get_modes(connector); radeon_get_native_mode(connector); } @@ -1625,7 +1669,7 @@ radeon_dp_detect(struct drm_connector *connector, bool force) goto out; } - radeon_connector_free_edid(radeon_connector); + radeon_connector_free_edid(connector); if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) || (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) { @@ -1636,6 +1680,11 @@ radeon_dp_detect(struct drm_connector *connector, bool force) /* check if panel is valid */ if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240) ret = connector_status_connected; + /* don't fetch the edid from the vbios if ddc fails and runpm is + * enabled so we report disconnected. + */ + if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0)) + ret = connector_status_disconnected; } /* eDP is always DP */ radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT; @@ -1684,6 +1733,12 @@ radeon_dp_detect(struct drm_connector *connector, bool force) } radeon_connector_update_scratch_regs(connector, ret); + + if ((radeon_audio != 0) && encoder) { + radeon_connector_get_edid(connector); + radeon_audio_detect(connector, encoder, ret); + } + out: #ifdef PM_TODO pm_runtime_mark_last_busy(connector->dev->dev); @@ -1758,7 +1813,7 @@ static const struct drm_connector_funcs radeon_dp_connector_funcs = { .detect = radeon_dp_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = radeon_connector_set_property, - .destroy = radeon_dp_connector_destroy, + .destroy = radeon_connector_destroy, .force = radeon_dvi_force, }; @@ -1767,7 +1822,7 @@ static const struct drm_connector_funcs radeon_edp_connector_funcs = { .detect = radeon_dp_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = radeon_lvds_set_property, - .destroy = radeon_dp_connector_destroy, + .destroy = radeon_connector_destroy, .force = radeon_dvi_force, }; @@ -1776,7 +1831,7 @@ static const struct drm_connector_funcs radeon_lvds_bridge_connector_funcs = { .detect = radeon_dp_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = radeon_lvds_set_property, - .destroy = radeon_dp_connector_destroy, + .destroy = radeon_connector_destroy, .force = radeon_dvi_force, }; @@ -1873,17 +1928,10 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_dig_connector->igp_lane_info = igp_lane_info; radeon_connector->con_priv = radeon_dig_connector; if (i2c_bus->valid) { - /* add DP i2c bus */ - if (connector_type == DRM_MODE_CONNECTOR_eDP) - radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch"); - else - radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch"); - if (radeon_dig_connector->dp_i2c_bus) + radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); + if (radeon_connector->ddc_bus) has_aux = true; else - DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); - radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); - if (!radeon_connector->ddc_bus) DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } switch (connector_type) { @@ -1903,6 +1951,10 @@ radeon_add_atom_connector(struct drm_device *dev, drm_object_attach_property(&radeon_connector->base.base, dev->mode_config.scaling_mode_property, DRM_MODE_SCALE_NONE); + if (ASIC_IS_DCE5(rdev)) + drm_object_attach_property(&radeon_connector->base.base, + rdev->mode_info.output_csc_property, + RADEON_OUTPUT_CSC_BYPASS); break; case DRM_MODE_CONNECTOR_DVII: case DRM_MODE_CONNECTOR_DVID: @@ -1931,10 +1983,16 @@ radeon_add_atom_connector(struct drm_device *dev, rdev->mode_info.dither_property, RADEON_FMT_DITHER_DISABLE); - if (radeon_audio != 0) + if (radeon_audio != 0) { + drm_object_attach_property(&radeon_connector->base.base, + rdev->mode_info.audio_property, + RADEON_AUDIO_AUTO); + radeon_connector->audio = RADEON_AUDIO_AUTO; + } + if (ASIC_IS_DCE5(rdev)) drm_object_attach_property(&radeon_connector->base.base, - rdev->mode_info.audio_property, - RADEON_AUDIO_AUTO); + rdev->mode_info.output_csc_property, + RADEON_OUTPUT_CSC_BYPASS); subpixel_order = SubPixelHorizontalRGB; connector->interlace_allowed = true; @@ -1981,9 +2039,12 @@ radeon_add_atom_connector(struct drm_device *dev, drm_object_attach_property(&radeon_connector->base.base, dev->mode_config.scaling_mode_property, DRM_MODE_SCALE_NONE); + if (ASIC_IS_DCE5(rdev)) + drm_object_attach_property(&radeon_connector->base.base, + rdev->mode_info.output_csc_property, + RADEON_OUTPUT_CSC_BYPASS); /* no HPD on analog connectors */ radeon_connector->hpd.hpd = RADEON_HPD_NONE; - connector->polled = DRM_CONNECTOR_POLL_CONNECT; connector->interlace_allowed = true; connector->doublescan_allowed = true; break; @@ -2003,6 +2064,10 @@ radeon_add_atom_connector(struct drm_device *dev, drm_object_attach_property(&radeon_connector->base.base, dev->mode_config.scaling_mode_property, DRM_MODE_SCALE_NONE); + if (ASIC_IS_DCE5(rdev)) + drm_object_attach_property(&radeon_connector->base.base, + rdev->mode_info.output_csc_property, + RADEON_OUTPUT_CSC_BYPASS); /* no HPD on analog connectors */ radeon_connector->hpd.hpd = RADEON_HPD_NONE; connector->interlace_allowed = true; @@ -2047,6 +2112,7 @@ radeon_add_atom_connector(struct drm_device *dev, drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.audio_property, RADEON_AUDIO_AUTO); + radeon_connector->audio = RADEON_AUDIO_AUTO; } if (connector_type == DRM_MODE_CONNECTOR_DVII) { radeon_connector->dac_load_detect = true; @@ -2054,6 +2120,10 @@ radeon_add_atom_connector(struct drm_device *dev, rdev->mode_info.load_detect_property, 1); } + if (ASIC_IS_DCE5(rdev)) + drm_object_attach_property(&radeon_connector->base.base, + rdev->mode_info.output_csc_property, + RADEON_OUTPUT_CSC_BYPASS); connector->interlace_allowed = true; if (connector_type == DRM_MODE_CONNECTOR_DVII) connector->doublescan_allowed = true; @@ -2098,7 +2168,12 @@ radeon_add_atom_connector(struct drm_device *dev, drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.audio_property, RADEON_AUDIO_AUTO); + radeon_connector->audio = RADEON_AUDIO_AUTO; } + if (ASIC_IS_DCE5(rdev)) + drm_object_attach_property(&radeon_connector->base.base, + rdev->mode_info.output_csc_property, + RADEON_OUTPUT_CSC_BYPASS); subpixel_order = SubPixelHorizontalRGB; connector->interlace_allowed = true; if (connector_type == DRM_MODE_CONNECTOR_HDMIB) @@ -2115,10 +2190,6 @@ radeon_add_atom_connector(struct drm_device *dev, drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type); drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs); if (i2c_bus->valid) { - /* add DP i2c bus */ - radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch"); - if (!radeon_dig_connector->dp_i2c_bus) - DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (radeon_connector->ddc_bus) has_aux = true; @@ -2150,7 +2221,12 @@ radeon_add_atom_connector(struct drm_device *dev, drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.audio_property, RADEON_AUDIO_AUTO); + radeon_connector->audio = RADEON_AUDIO_AUTO; } + if (ASIC_IS_DCE5(rdev)) + drm_object_attach_property(&radeon_connector->base.base, + rdev->mode_info.output_csc_property, + RADEON_OUTPUT_CSC_BYPASS); connector->interlace_allowed = true; /* in theory with a DP to VGA converter... */ connector->doublescan_allowed = false; @@ -2164,14 +2240,10 @@ radeon_add_atom_connector(struct drm_device *dev, drm_connector_init(dev, &radeon_connector->base, &radeon_edp_connector_funcs, connector_type); drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs); if (i2c_bus->valid) { - /* add DP i2c bus */ - radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch"); - if (radeon_dig_connector->dp_i2c_bus) + radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); + if (radeon_connector->ddc_bus) has_aux = true; else - DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); - radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); - if (!radeon_connector->ddc_bus) DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } drm_object_attach_property(&radeon_connector->base.base, @@ -2222,8 +2294,10 @@ radeon_add_atom_connector(struct drm_device *dev, } if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) { - if (i2c_bus->valid) - connector->polled = DRM_CONNECTOR_POLL_CONNECT; + if (i2c_bus->valid) { + connector->polled = DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT; + } } else connector->polled = DRM_CONNECTOR_POLL_HPD; @@ -2299,7 +2373,6 @@ radeon_add_legacy_connector(struct drm_device *dev, 1); /* no HPD on analog connectors */ radeon_connector->hpd.hpd = RADEON_HPD_NONE; - connector->polled = DRM_CONNECTOR_POLL_CONNECT; connector->interlace_allowed = true; connector->doublescan_allowed = true; break; @@ -2384,10 +2457,13 @@ radeon_add_legacy_connector(struct drm_device *dev, } if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) { - if (i2c_bus->valid) - connector->polled = DRM_CONNECTOR_POLL_CONNECT; + if (i2c_bus->valid) { + connector->polled = DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT; + } } else connector->polled = DRM_CONNECTOR_POLL_HPD; + connector->display_info.subpixel_order = subpixel_order; drm_connector_register(connector); } diff --git a/sys/dev/drm/radeon/radeon_cs.c b/sys/dev/drm/radeon/radeon_cs.c index f962a3fd82..34fdee4316 100644 --- a/sys/dev/drm/radeon/radeon_cs.c +++ b/sys/dev/drm/radeon/radeon_cs.c @@ -92,7 +92,7 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p) if (p->relocs_ptr == NULL) { return -ENOMEM; } - p->relocs = kcalloc(p->nrelocs, sizeof(struct radeon_cs_reloc), GFP_KERNEL); + p->relocs = kcalloc(p->nrelocs, sizeof(struct radeon_bo_list), GFP_KERNEL); if (p->relocs == NULL) { return -ENOMEM; } @@ -101,30 +101,32 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p) for (i = 0; i < p->nrelocs; i++) { struct drm_radeon_cs_reloc *r; + struct drm_gem_object *gobj; unsigned priority; duplicate = false; r = (struct drm_radeon_cs_reloc *)&chunk->kdata[i*4]; for (j = 0; j < i; j++) { - if (r->handle == p->relocs[j].handle) { + struct drm_radeon_cs_reloc *other; + other = (void *)&chunk->kdata[j*4]; + if (r->handle == other->handle) { p->relocs_ptr[i] = &p->relocs[j]; duplicate = true; break; } } if (duplicate) { - p->relocs[i].handle = 0; continue; } - p->relocs[i].gobj = drm_gem_object_lookup(p->filp, r->handle); - if (p->relocs[i].gobj == NULL) { + gobj = drm_gem_object_lookup(p->filp, r->handle); + if (gobj == NULL) { DRM_ERROR("gem object lookup failed 0x%x\n", r->handle); return -ENOENT; } p->relocs_ptr[i] = &p->relocs[i]; - p->relocs[i].robj = gem_to_radeon_bo(p->relocs[i].gobj); + p->relocs[i].robj = gem_to_radeon_bo(gobj); /* The userspace buffer priorities are from 0 to 15. A higher * number means the buffer is more important. @@ -169,7 +171,6 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p) } p->relocs[i].tv.bo = &p->relocs[i].robj->tbo; - p->relocs[i].handle = r->handle; radeon_cs_buckets_add(&buckets, &p->relocs[i].tv.head, priority); @@ -229,14 +230,11 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority static void radeon_cs_sync_rings(struct radeon_cs_parser *p) { - int i; - - for (i = 0; i < p->nrelocs; i++) { - if (!p->relocs[i].robj) - continue; + struct radeon_bo_list *reloc; + list_for_each_entry(reloc, &p->validated, tv.head) { radeon_semaphore_sync_to(p->ib.semaphore, - p->relocs[i].robj->tbo.sync_obj); + reloc->robj->tbo.sync_obj); } } @@ -249,11 +247,13 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) u32 ring = RADEON_CS_RING_GFX; s32 priority = 0; + INIT_LIST_HEAD(&p->validated); + if (!cs->num_chunks) { return 0; } + /* get chunks */ - INIT_LIST_HEAD(&p->validated); p->idx = 0; p->ib.sa_bo = NULL; p->ib.semaphore = NULL; @@ -372,8 +372,8 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) static int cmp_size_smaller_first(void *priv, struct list_head *a, struct list_head *b) { - struct radeon_cs_reloc *la = list_entry(a, struct radeon_cs_reloc, tv.head); - struct radeon_cs_reloc *lb = list_entry(b, struct radeon_cs_reloc, tv.head); + struct radeon_bo_list *la = list_entry(a, struct radeon_bo_list, tv.head); + struct radeon_bo_list *lb = list_entry(b, struct radeon_bo_list, tv.head); /* Sort A before B if A is smaller. */ return (int)la->robj->tbo.num_pages - (int)lb->robj->tbo.num_pages; @@ -414,8 +414,11 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error, bo if (parser->relocs != NULL) { for (i = 0; i < parser->nrelocs; i++) { - if (parser->relocs[i].gobj) - drm_gem_object_unreference_unlocked(parser->relocs[i].gobj); + struct radeon_bo *bo = parser->relocs[i].robj; + if (bo == NULL) + continue; + + drm_gem_object_unreference_unlocked(&bo->gem_base); } } kfree(parser->track); @@ -535,7 +538,7 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev, if (parser->ring == R600_RING_TYPE_UVD_INDEX) radeon_uvd_note_usage(rdev); - lockmgr(&vm->mutex, LK_EXCLUSIVE); + mutex_lock(&vm->mutex); r = radeon_bo_vm_update_pte(parser, vm); if (r) { goto out; @@ -551,7 +554,7 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev, } out: - lockmgr(&vm->mutex, LK_RELEASE); + mutex_unlock(&vm->mutex); return r; } @@ -702,6 +705,7 @@ int radeon_cs_packet_parse(struct radeon_cs_parser *p, struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx]; struct radeon_device *rdev = p->rdev; uint32_t header; + int ret = 0, i; if (idx >= ib_chunk->length_dw) { DRM_ERROR("Can not parse packet at %d after CS end %d !\n", @@ -730,14 +734,25 @@ int radeon_cs_packet_parse(struct radeon_cs_parser *p, break; default: DRM_ERROR("Unknown packet type %d at %d !\n", pkt->type, idx); - return -EINVAL; + ret = -EINVAL; + goto dump_ib; } if ((pkt->count + 1 + pkt->idx) >= ib_chunk->length_dw) { DRM_ERROR("Packet (%d:%d:%d) end after CS buffer (%d) !\n", pkt->idx, pkt->type, pkt->count, ib_chunk->length_dw); - return -EINVAL; + ret = -EINVAL; + goto dump_ib; } return 0; + +dump_ib: + for (i = 0; i < ib_chunk->length_dw; i++) { + if (i == idx) + printk("\t0x%08x <---\n", radeon_get_ib_value(p, i)); + else + printk("\t0x%08x\n", radeon_get_ib_value(p, i)); + } + return ret; } /** @@ -793,7 +808,7 @@ void radeon_cs_dump_packet(struct radeon_cs_parser *p, * GPU offset using the provided start. **/ int radeon_cs_packet_next_reloc(struct radeon_cs_parser *p, - struct radeon_cs_reloc **cs_reloc, + struct radeon_bo_list **cs_reloc, int nomm) { struct radeon_cs_chunk *relocs_chunk; diff --git a/sys/dev/drm/radeon/radeon_cursor.c b/sys/dev/drm/radeon/radeon_cursor.c index 1f6149fc73..77aa74b364 100644 --- a/sys/dev/drm/radeon/radeon_cursor.c +++ b/sys/dev/drm/radeon/radeon_cursor.c @@ -91,15 +91,34 @@ static void radeon_show_cursor(struct drm_crtc *crtc) struct radeon_device *rdev = crtc->dev->dev_private; if (ASIC_IS_DCE4(rdev)) { + WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, + upper_32_bits(radeon_crtc->cursor_addr)); + WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, + lower_32_bits(radeon_crtc->cursor_addr)); WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset); WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN | EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) | EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2)); } else if (ASIC_IS_AVIVO(rdev)) { + if (rdev->family >= CHIP_RV770) { + if (radeon_crtc->crtc_id) + WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, + upper_32_bits(radeon_crtc->cursor_addr)); + else + WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, + upper_32_bits(radeon_crtc->cursor_addr)); + } + + WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, + lower_32_bits(radeon_crtc->cursor_addr)); WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset); WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN | (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT)); } else { + /* offset is from DISP(2)_BASE_ADDRESS */ + WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, + radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr); + switch (radeon_crtc->crtc_id) { case 0: WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL); @@ -117,106 +136,7 @@ static void radeon_show_cursor(struct drm_crtc *crtc) } } -static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj, - uint64_t gpu_addr) -{ - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - struct radeon_device *rdev = crtc->dev->dev_private; - - if (ASIC_IS_DCE4(rdev)) { - WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, - upper_32_bits(gpu_addr)); - WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, - gpu_addr & 0xffffffff); - } else if (ASIC_IS_AVIVO(rdev)) { - if (rdev->family >= CHIP_RV770) { - if (radeon_crtc->crtc_id) - WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr)); - else - WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr)); - } - WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, - gpu_addr & 0xffffffff); - } else { - radeon_crtc->legacy_cursor_offset = gpu_addr - radeon_crtc->legacy_display_base_addr; - /* offset is from DISP(2)_BASE_ADDRESS */ - WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, radeon_crtc->legacy_cursor_offset); - } -} - -int radeon_crtc_cursor_set(struct drm_crtc *crtc, - struct drm_file *file_priv, - uint32_t handle, - uint32_t width, - uint32_t height) -{ - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - struct radeon_device *rdev = crtc->dev->dev_private; - struct drm_gem_object *obj; - struct radeon_bo *robj; - u64 gpu_addr; - int ret; - - if (!handle) { - /* turn off cursor */ - radeon_hide_cursor(crtc); - obj = NULL; - goto unpin; - } - - if ((width > radeon_crtc->max_cursor_width) || - (height > radeon_crtc->max_cursor_height)) { - DRM_ERROR("bad cursor width or height %d x %d\n", width, height); - return -EINVAL; - } - - obj = drm_gem_object_lookup(file_priv, handle); - if (!obj) { - DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id); - return -ENOENT; - } - - robj = gem_to_radeon_bo(obj); - ret = radeon_bo_reserve(robj, false); - if (unlikely(ret != 0)) - goto fail; - /* Only 27 bit offset for legacy cursor */ - ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM, - ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27, - &gpu_addr); - radeon_bo_unreserve(robj); - if (ret) - goto fail; - - radeon_crtc->cursor_width = width; - radeon_crtc->cursor_height = height; - - radeon_lock_cursor(crtc, true); - radeon_set_cursor(crtc, obj, gpu_addr); - radeon_show_cursor(crtc); - radeon_lock_cursor(crtc, false); - -unpin: - if (radeon_crtc->cursor_bo) { - robj = gem_to_radeon_bo(radeon_crtc->cursor_bo); - ret = radeon_bo_reserve(robj, false); - if (likely(ret == 0)) { - radeon_bo_unpin(robj); - radeon_bo_unreserve(robj); - } - drm_gem_object_unreference_unlocked(radeon_crtc->cursor_bo); - } - - radeon_crtc->cursor_bo = obj; - return 0; -fail: - drm_gem_object_unreference_unlocked(obj); - - return ret; -} - -int radeon_crtc_cursor_move(struct drm_crtc *crtc, - int x, int y) +static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct radeon_device *rdev = crtc->dev->dev_private; @@ -281,7 +201,6 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, } } - radeon_lock_cursor(crtc, true); if (ASIC_IS_DCE4(rdev)) { WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y); WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin); @@ -305,10 +224,136 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, | (x << 16) | y)); /* offset is from DISP(2)_BASE_ADDRESS */ - WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset + - (yorigin * 256))); + WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, + radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr + + yorigin * 256); } + + radeon_crtc->cursor_x = x; + radeon_crtc->cursor_y = y; + + return 0; +} + +int radeon_crtc_cursor_move(struct drm_crtc *crtc, + int x, int y) +{ + int ret; + + radeon_lock_cursor(crtc, true); + ret = radeon_cursor_move_locked(crtc, x, y); + radeon_lock_cursor(crtc, false); + + return ret; +} + +int radeon_crtc_cursor_set2(struct drm_crtc *crtc, + struct drm_file *file_priv, + uint32_t handle, + uint32_t width, + uint32_t height, + int32_t hot_x, + int32_t hot_y) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct radeon_device *rdev = crtc->dev->dev_private; + struct drm_gem_object *obj; + struct radeon_bo *robj; + int ret; + + if (!handle) { + /* turn off cursor */ + radeon_hide_cursor(crtc); + obj = NULL; + goto unpin; + } + + if ((width > radeon_crtc->max_cursor_width) || + (height > radeon_crtc->max_cursor_height)) { + DRM_ERROR("bad cursor width or height %d x %d\n", width, height); + return -EINVAL; + } + + obj = drm_gem_object_lookup(file_priv, handle); + if (!obj) { + DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id); + return -ENOENT; + } + + robj = gem_to_radeon_bo(obj); + ret = radeon_bo_reserve(robj, false); + if (ret != 0) { + drm_gem_object_unreference_unlocked(obj); + return ret; + } + /* Only 27 bit offset for legacy cursor */ + ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM, + ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27, + (u64 *)&radeon_crtc->cursor_addr); + radeon_bo_unreserve(robj); + if (ret) { + DRM_ERROR("Failed to pin new cursor BO (%d)\n", ret); + drm_gem_object_unreference_unlocked(obj); + return ret; + } + + radeon_crtc->cursor_width = width; + radeon_crtc->cursor_height = height; + + radeon_lock_cursor(crtc, true); + + if (hot_x != radeon_crtc->cursor_hot_x || + hot_y != radeon_crtc->cursor_hot_y) { + int x, y; + + x = radeon_crtc->cursor_x + radeon_crtc->cursor_hot_x - hot_x; + y = radeon_crtc->cursor_y + radeon_crtc->cursor_hot_y - hot_y; + + radeon_cursor_move_locked(crtc, x, y); + + radeon_crtc->cursor_hot_x = hot_x; + radeon_crtc->cursor_hot_y = hot_y; + } + + radeon_show_cursor(crtc); + radeon_lock_cursor(crtc, false); +unpin: + if (radeon_crtc->cursor_bo) { + struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo); + ret = radeon_bo_reserve(robj, false); + if (likely(ret == 0)) { + radeon_bo_unpin(robj); + radeon_bo_unreserve(robj); + } + drm_gem_object_unreference_unlocked(radeon_crtc->cursor_bo); + } + + radeon_crtc->cursor_bo = obj; return 0; } + +/** + * radeon_cursor_reset - Re-set the current cursor, if any. + * + * @crtc: drm crtc + * + * If the CRTC passed in currently has a cursor assigned, this function + * makes sure it's visible. + */ +void radeon_cursor_reset(struct drm_crtc *crtc) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + + if (radeon_crtc->cursor_bo) { + radeon_lock_cursor(crtc, true); + + radeon_cursor_move_locked(crtc, radeon_crtc->cursor_x, + radeon_crtc->cursor_y); + + radeon_show_cursor(crtc); + + radeon_lock_cursor(crtc, false); + } +} diff --git a/sys/dev/drm/radeon/radeon_device.c b/sys/dev/drm/radeon/radeon_device.c index aac0098c8a..b2ab5360a7 100644 --- a/sys/dev/drm/radeon/radeon_device.c +++ b/sys/dev/drm/radeon/radeon_device.c @@ -461,10 +461,11 @@ int radeon_wb_init(struct radeon_device *rdev) radeon_wb_fini(rdev); return r; } - /* clear wb memory */ - memset(*(void **)wb_ptr, 0, RADEON_GPU_PAGE_SIZE); } + /* clear wb memory */ + wb_ptr = &rdev->wb.wb; + memset(*(void **)wb_ptr, 0, RADEON_GPU_PAGE_SIZE); /* disable event_write fences */ rdev->wb.use_event = false; /* disabled via module param */ @@ -741,6 +742,8 @@ int radeon_dummy_page_init(struct radeon_device *rdev) return -ENOMEM; rdev->dummy_page.addr = (dma_addr_t)rdev->dummy_page.dmah->busaddr; + rdev->dummy_page.entry = radeon_gart_get_page_entry(rdev->dummy_page.addr, + RADEON_GART_PAGE_DUMMY); return 0; } @@ -967,9 +970,6 @@ int radeon_atombios_init(struct radeon_device *rdev) void radeon_atombios_fini(struct radeon_device *rdev) { if (rdev->mode_info.atom_context) { - /* prevents leaking 512 bytes */ - kfree(rdev->mode_info.atom_context->iio); - kfree(rdev->mode_info.atom_context->scratch); } kfree(rdev->mode_info.atom_context); @@ -1048,6 +1048,22 @@ static bool radeon_check_pot_argument(int arg) return (arg & (arg - 1)) == 0; } +/** + * Determine a sensible default GART size according to ASIC family. + * + * @family ASIC family name + */ +static int radeon_gart_size_auto(enum radeon_family family) +{ + /* default to a larger gart size on newer asics */ + if (family >= CHIP_TAHITI) + return 2048; + else if (family >= CHIP_RV770) + return 1024; + else + return 512; +} + /** * radeon_check_arguments - validate module params * @@ -1066,27 +1082,17 @@ static void radeon_check_arguments(struct radeon_device *rdev) } if (radeon_gart_size == -1) { - /* default to a larger gart size on newer asics */ - if (rdev->family >= CHIP_RV770) - radeon_gart_size = 1024; - else - radeon_gart_size = 512; + radeon_gart_size = radeon_gart_size_auto(rdev->family); } /* gtt size must be power of two and greater or equal to 32M */ if (radeon_gart_size < 32) { - dev_warn(rdev->dev, "gart size (%d) too small\n", - radeon_gart_size); - if (rdev->family >= CHIP_RV770) - radeon_gart_size = 1024; - else - radeon_gart_size = 512; + dev_warn(rdev->dev, "gart size (%d) too small\n", + radeon_gart_size); + radeon_gart_size = radeon_gart_size_auto(rdev->family); } else if (!radeon_check_pot_argument(radeon_gart_size)) { - dev_warn(rdev->dev, "gart size (%d) must be a power of 2\n", - radeon_gart_size); - if (rdev->family >= CHIP_RV770) - radeon_gart_size = 1024; - else - radeon_gart_size = 512; + dev_warn(rdev->dev, "gart size (%d) must be a power of 2\n", + radeon_gart_size); + radeon_gart_size = radeon_gart_size_auto(rdev->family); } rdev->mc.gtt_size = (uint64_t)radeon_gart_size << 20; @@ -1113,7 +1119,7 @@ static void radeon_check_arguments(struct radeon_device *rdev) } if (radeon_vm_size < 1) { - dev_warn(rdev->dev, "VM size (%d) to small, min is 1GB\n", + dev_warn(rdev->dev, "VM size (%d) too small, min is 1GB\n", radeon_vm_size); radeon_vm_size = 4; } @@ -1160,7 +1166,7 @@ static void radeon_check_arguments(struct radeon_device *rdev) * radeon_switcheroo_set_state - set switcheroo state * * @pdev: pci dev pointer - * @state: vga switcheroo state + * @state: vga_switcheroo state * * Callback for the switcheroo driver. Suspends or resumes the * the asics before or after it is powered up using ACPI methods. @@ -1194,7 +1200,7 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero printk(KERN_INFO "radeon: switched off\n"); drm_kms_helper_poll_disable(dev); dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; - radeon_suspend_kms(dev, true, true); + radeon_suspend_kms(dev, true, true, false); dev->switch_power_state = DRM_SWITCH_POWER_OFF; } } @@ -1268,9 +1274,9 @@ int radeon_device_init(struct radeon_device *rdev, rdev->ring[i].idx = i; } - DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X).\n", - radeon_family_name[rdev->family], pdev->vendor, pdev->device, - pdev->subsystem_vendor, pdev->subsystem_device); + DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X 0x%02X).\n", + radeon_family_name[rdev->family], pdev->vendor, pdev->device, + pdev->subsystem_vendor, pdev->subsystem_device, pdev->revision); /* mutex initialization are all done here so we * can recall function without having locking issues */ @@ -1285,6 +1291,7 @@ int radeon_device_init(struct radeon_device *rdev, lockinit(&rdev->gpu_clock_mutex, "radeon_clockmtx", 0, LK_CANRECURSE); lockinit(&rdev->srbm_mutex, "radeon_srbm_mutex", 0, LK_CANRECURSE); + lockinit(&rdev->grbm_idx_mutex, "radeon_grbm_mutex", 0, LK_CANRECURSE); lockinit(&rdev->pm.mclk_lock, "drm__radeon_device__pm__mclk_lock", 0, LK_CANRECURSE); lockinit(&rdev->exclusive_lock, "drm__radeon_device__exclusive_lock", @@ -1313,6 +1320,9 @@ int radeon_device_init(struct radeon_device *rdev, rdev->flags &= ~RADEON_IS_AGP; } + DRM_INFO("radeon_device_init: rdev->flags & RADEON_IS_AGP (%lu)\n", + rdev->flags & RADEON_IS_AGP); + if (rdev->flags & RADEON_IS_AGP && radeon_agpmode == -1) { radeon_agp_disable(rdev); } @@ -1358,18 +1368,18 @@ int radeon_device_init(struct radeon_device *rdev, /* Registers mapping */ /* TODO: block userspace mapping of io register */ - spin_init(&rdev->mmio_idx_lock, "radeon_mpio"); - spin_init(&rdev->smc_idx_lock, "radeon_smc"); - spin_init(&rdev->pll_idx_lock, "radeon_pll"); - spin_init(&rdev->mc_idx_lock, "radeon_mc"); - spin_init(&rdev->pcie_idx_lock, "radeon_pcie"); - spin_init(&rdev->pciep_idx_lock, "radeon_pciep"); - spin_init(&rdev->pif_idx_lock, "radeon_pif"); - spin_init(&rdev->cg_idx_lock, "radeon_cg"); - spin_init(&rdev->uvd_idx_lock, "radeon_uvd"); - spin_init(&rdev->rcu_idx_lock, "radeon_rcu"); - spin_init(&rdev->didt_idx_lock, "radeon_didt"); - spin_init(&rdev->end_idx_lock, "radeon_end"); + lockinit(&rdev->mmio_idx_lock, "radeon_mpio", 0, LK_CANRECURSE); + lockinit(&rdev->smc_idx_lock, "radeon_smc", 0, LK_CANRECURSE); + lockinit(&rdev->pll_idx_lock, "radeon_pll", 0, LK_CANRECURSE); + lockinit(&rdev->mc_idx_lock, "radeon_mc", 0, LK_CANRECURSE); + lockinit(&rdev->pcie_idx_lock, "radeon_pcie", 0, LK_CANRECURSE); + lockinit(&rdev->pciep_idx_lock, "radeon_pciep", 0, LK_CANRECURSE); + lockinit(&rdev->pif_idx_lock, "radeon_pif", 0, LK_CANRECURSE); + lockinit(&rdev->cg_idx_lock, "radeon_cg", 0, LK_CANRECURSE); + lockinit(&rdev->uvd_idx_lock, "radeon_uvd", 0, LK_CANRECURSE); + lockinit(&rdev->rcu_idx_lock, "radeon_rcu", 0, LK_CANRECURSE); + lockinit(&rdev->didt_idx_lock, "radeon_didt", 0, LK_CANRECURSE); + lockinit(&rdev->end_idx_lock, "radeon_end", 0, LK_CANRECURSE); if (rdev->family >= CHIP_BONAIRE) { rdev->rmmio_rid = PCIR_BAR(5); } else { @@ -1468,6 +1478,21 @@ int radeon_device_init(struct radeon_device *rdev, } rdev->fictitious_range_registered = true; + /* + * Turks/Thames GPU will freeze whole laptop if DPM is not restarted + * after the CP ring have chew one packet at least. Hence here we stop + * and restart DPM after the radeon_ib_ring_tests(). + */ + if (rdev->pm.dpm_enabled && + (rdev->pm.pm_method == PM_METHOD_DPM) && + (rdev->family == CHIP_TURKS) && + (rdev->flags & RADEON_IS_MOBILITY)) { + mutex_lock(&rdev->pm.mutex); + radeon_dpm_disable(rdev); + radeon_dpm_enable(rdev); + mutex_unlock(&rdev->pm.mutex); + } + if ((radeon_testing & 1)) { if (rdev->accel_working) radeon_test_moves(rdev); @@ -1562,7 +1587,8 @@ void radeon_device_fini(struct radeon_device *rdev) * Returns 0 for success or an error on failure. * Called at driver suspend. */ -int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon) +int radeon_suspend_kms(struct drm_device *dev, bool suspend, + bool fbcon, bool freeze) { struct radeon_device *rdev; struct drm_crtc *crtc; @@ -1580,16 +1606,28 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon) drm_kms_helper_poll_disable(dev); + drm_modeset_lock_all(dev); /* turn off display hw */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); } + drm_modeset_unlock_all(dev); - /* unpin the front buffers */ + /* unpin the front buffers and cursors */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->primary->fb); struct radeon_bo *robj; + if (radeon_crtc->cursor_bo) { + struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo); + r = radeon_bo_reserve(robj, false); + if (r == 0) { + radeon_bo_unpin(robj); + radeon_bo_unreserve(robj); + } + } + if (rfb == NULL || rfb->obj == NULL) { continue; } @@ -1626,7 +1664,10 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon) pci_save_state(device_get_parent(rdev->dev->bsddev)); #ifdef DUMBBELL_WIP - if (suspend) { + if (freeze && rdev->family >= CHIP_R600) { + rdev->asic->asic_reset(rdev, true); + pci_restore_state(device_get_parent(rdev->dev->bsddev)); + } else if (suspend) { /* Shut down the device */ pci_disable_device(dev->pdev); #endif /* DUMBBELL_WIP */ @@ -1659,6 +1700,7 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon) { struct drm_connector *connector; struct radeon_device *rdev = dev->dev_private; + struct drm_crtc *crtc; int r; if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) @@ -1702,6 +1744,27 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon) radeon_restore_bios_scratch_regs(rdev); + /* pin cursors */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + + if (radeon_crtc->cursor_bo) { + struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo); + r = radeon_bo_reserve(robj, false); + if (r == 0) { + /* Only 27 bit offset for legacy cursor */ + r = radeon_bo_pin_restricted(robj, + RADEON_GEM_DOMAIN_VRAM, + ASIC_IS_AVIVO(rdev) ? + 0 : 1 << 27, + (u64 *)&radeon_crtc->cursor_addr); + if (r != 0) + DRM_ERROR("Failed to pin cursor BO (%d)\n", r); + radeon_bo_unreserve(robj); + } + } + } + /* init dig PHYs, disp eng pll */ if (rdev->is_atom_bios) { radeon_atom_encoder_init(rdev); @@ -1720,9 +1783,11 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon) if (fbcon) { drm_helper_resume_force_mode(dev); /* turn on display hw */ + drm_modeset_lock_all(dev); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); } + drm_modeset_unlock_all(dev); } drm_kms_helper_poll_enable(dev); @@ -1766,6 +1831,8 @@ int radeon_gpu_reset(struct radeon_device *rdev) return 0; } + atomic_inc(&rdev->gpu_reset_counter); + radeon_save_bios_scratch_regs(rdev); /* block TTM */ resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); diff --git a/sys/dev/drm/radeon/radeon_display.c b/sys/dev/drm/radeon/radeon_display.c index 89d5413503..c93facb1ac 100644 --- a/sys/dev/drm/radeon/radeon_display.c +++ b/sys/dev/drm/radeon/radeon_display.c @@ -159,7 +159,7 @@ static void dce5_crtc_load_lut(struct drm_crtc *crtc) (NI_GRPH_REGAMMA_MODE(NI_REGAMMA_BYPASS) | NI_OVL_REGAMMA_MODE(NI_REGAMMA_BYPASS))); WREG32(NI_OUTPUT_CSC_CONTROL + radeon_crtc->crtc_offset, - (NI_OUTPUT_CSC_GRPH_MODE(NI_OUTPUT_CSC_BYPASS) | + (NI_OUTPUT_CSC_GRPH_MODE(radeon_crtc->output_csc) | NI_OUTPUT_CSC_OVL_MODE(NI_OUTPUT_CSC_BYPASS))); /* XXX match this to the depth of the crtc fmt block, move to modeset? */ WREG32(0x6940 + radeon_crtc->crtc_offset, 0); @@ -291,6 +291,7 @@ static void radeon_unpin_work_func(struct work_struct *__work) void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id) { struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; + unsigned long flags; u32 update_pending; int vpos, hpos; @@ -310,13 +311,13 @@ void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id) if ((radeon_use_pflipirq == 2) && ASIC_IS_DCE4(rdev)) return; - lockmgr(&rdev->ddev->event_lock, LK_EXCLUSIVE); + spin_lock_irqsave(&rdev->ddev->event_lock, flags); if (radeon_crtc->flip_status != RADEON_FLIP_SUBMITTED) { DRM_DEBUG_DRIVER("radeon_crtc->flip_status = %d != " "RADEON_FLIP_SUBMITTED(%d)\n", radeon_crtc->flip_status, RADEON_FLIP_SUBMITTED); - lockmgr(&rdev->ddev->event_lock, LK_RELEASE); + spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); return; } @@ -326,7 +327,9 @@ void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id) * to complete in this vblank? */ if (update_pending && - (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id, 0, + (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, + crtc_id, + USE_REAL_VBLANKSTART, &vpos, &hpos, NULL, NULL, &rdev->mode_info.crtcs[crtc_id]->base.hwmode)) && ((vpos >= (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100) || @@ -339,7 +342,7 @@ void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id) */ update_pending = 0; } - lockmgr(&rdev->ddev->event_lock, LK_RELEASE); + spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); if (!update_pending) radeon_crtc_handle_flip(rdev, crtc_id); } @@ -356,19 +359,20 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id) { struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; struct radeon_flip_work *work; + unsigned long flags; /* this can happen at init */ if (radeon_crtc == NULL) return; - lockmgr(&rdev->ddev->event_lock, LK_EXCLUSIVE); + spin_lock_irqsave(&rdev->ddev->event_lock, flags); work = radeon_crtc->flip_work; if (radeon_crtc->flip_status != RADEON_FLIP_SUBMITTED) { DRM_DEBUG_DRIVER("radeon_crtc->flip_status = %d != " "RADEON_FLIP_SUBMITTED(%d)\n", radeon_crtc->flip_status, RADEON_FLIP_SUBMITTED); - lockmgr(&rdev->ddev->event_lock, LK_RELEASE); + spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); return; } @@ -378,9 +382,9 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id) /* wakeup userspace */ if (work->event) - drm_send_vblank_event(rdev->ddev, crtc_id, work->event); + drm_crtc_send_vblank_event(&radeon_crtc->base, work->event); - lockmgr(&rdev->ddev->event_lock, LK_RELEASE); + spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); drm_vblank_put(rdev->ddev, radeon_crtc->crtc_id); radeon_irq_kms_pflip_irq_put(rdev, work->crtc_id); @@ -402,17 +406,21 @@ static void radeon_flip_work_func(struct work_struct *__work) struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[work->crtc_id]; struct drm_crtc *crtc = &radeon_crtc->base; + unsigned long flags; int r; + int vpos, hpos, stat, min_udelay = 0; + unsigned repcnt = 4; + struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id]; lockmgr(&rdev->exclusive_lock, LK_EXCLUSIVE); if (work->fence) { r = radeon_fence_wait(work->fence, false); if (r == -EDEADLK) { - lockmgr(&rdev->exclusive_lock, LK_RELEASE); + lockmgr(&rdev->exclusive_lock, LK_RELEASE); do { r = radeon_gpu_reset(rdev); } while (r == -EAGAIN); - lockmgr(&rdev->exclusive_lock, LK_EXCLUSIVE); + lockmgr(&rdev->exclusive_lock, LK_EXCLUSIVE); } if (r) DRM_ERROR("failed to wait on page flip fence (%d)!\n", r); @@ -426,16 +434,64 @@ static void radeon_flip_work_func(struct work_struct *__work) } /* We borrow the event spin lock for protecting flip_status */ - lockmgr(&crtc->dev->event_lock, LK_EXCLUSIVE); + spin_lock_irqsave(&crtc->dev->event_lock, flags); /* set the proper interrupt */ radeon_irq_kms_pflip_irq_get(rdev, radeon_crtc->crtc_id); + /* If this happens to execute within the "virtually extended" vblank + * interval before the start of the real vblank interval then it needs + * to delay programming the mmio flip until the real vblank is entered. + * This prevents completing a flip too early due to the way we fudge + * our vblank counter and vblank timestamps in order to work around the + * problem that the hw fires vblank interrupts before actual start of + * vblank (when line buffer refilling is done for a frame). It + * complements the fudging logic in radeon_get_crtc_scanoutpos() for + * timestamping and radeon_get_vblank_counter_kms() for vblank counts. + * + * In practice this won't execute very often unless on very fast + * machines because the time window for this to happen is very small. + */ + while (radeon_crtc->enabled && --repcnt) { + /* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank + * start in hpos, and to the "fudged earlier" vblank start in + * vpos. + */ + stat = radeon_get_crtc_scanoutpos(rdev->ddev, work->crtc_id, + GET_DISTANCE_TO_VBLANKSTART, + &vpos, &hpos, NULL, NULL, + &crtc->hwmode); + + if ((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) != + (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE) || + !(vpos >= 0 && hpos <= 0)) + break; + + /* Sleep at least until estimated real start of hw vblank */ + min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5); + if (min_udelay > vblank->framedur_ns / 2000) { + /* Don't wait ridiculously long - something is wrong */ + repcnt = 0; + break; + } + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); + usleep_range(min_udelay, 2 * min_udelay); + spin_lock_irqsave(&crtc->dev->event_lock, flags); + + }; + + if (!repcnt) + DRM_DEBUG_DRIVER("Delay problem on crtc %d: min_udelay %d, " + "framedur %d, linedur %d, stat %d, vpos %d, " + "hpos %d\n", work->crtc_id, min_udelay, + vblank->framedur_ns / 1000, + vblank->linedur_ns / 1000, stat, vpos, hpos); + /* do the flip (mmio) */ - radeon_page_flip(rdev, radeon_crtc->crtc_id, work->base); + radeon_page_flip(rdev, radeon_crtc->crtc_id, work->base, work->async); radeon_crtc->flip_status = RADEON_FLIP_SUBMITTED; - lockmgr(&crtc->dev->event_lock, LK_RELEASE); + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); lockmgr(&rdev->exclusive_lock, LK_RELEASE); } @@ -454,6 +510,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc, struct radeon_bo *new_rbo; uint32_t tiling_flags, pitch_pixels; uint64_t base; + unsigned long flags; int r; work = kzalloc(sizeof *work, GFP_KERNEL); @@ -466,6 +523,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc, work->rdev = rdev; work->crtc_id = radeon_crtc->crtc_id; work->event = event; + work->async = (page_flip_flags & DRM_MODE_PAGE_FLIP_ASYNC) != 0; /* schedule unpin of the old buffer */ old_radeon_fb = to_radeon_framebuffer(crtc->primary->fb); @@ -549,11 +607,12 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc, } /* We borrow the event spin lock for protecting flip_work */ - lockmgr(&crtc->dev->event_lock, LK_EXCLUSIVE); + spin_lock_irqsave(&crtc->dev->event_lock, flags); if (radeon_crtc->flip_status != RADEON_FLIP_NONE) { DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); - lockmgr(&crtc->dev->event_lock, LK_RELEASE); + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); + r = -EBUSY; goto vblank_cleanup; } @@ -563,7 +622,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc, /* update crtc fb */ crtc->primary->fb = fb; - lockmgr(&crtc->dev->event_lock, LK_RELEASE); + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); queue_work(radeon_crtc->flip_queue, &work->flip_work); return 0; @@ -642,7 +701,7 @@ radeon_crtc_set_config(struct drm_mode_set *set) return ret; } static const struct drm_crtc_funcs radeon_crtc_funcs = { - .cursor_set = radeon_crtc_cursor_set, + .cursor_set2 = radeon_crtc_cursor_set2, .cursor_move = radeon_crtc_cursor_move, .gamma_set = radeon_crtc_gamma_set, .set_config = radeon_crtc_set_config, @@ -967,6 +1026,9 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV && pll->flags & RADEON_PLL_USE_REF_DIV) ref_div_max = pll->reference_div; + else if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) + /* fix for problems on RS880 */ + ref_div_max = min(pll->max_ref_div, 7u); else ref_div_max = pll->max_ref_div; @@ -1386,6 +1448,13 @@ static struct drm_prop_enum_list radeon_dither_enum_list[] = { RADEON_FMT_DITHER_ENABLE, "on" }, }; +static struct drm_prop_enum_list radeon_output_csc_enum_list[] = +{ { RADEON_OUTPUT_CSC_BYPASS, "bypass" }, + { RADEON_OUTPUT_CSC_TVRGB, "tvrgb" }, + { RADEON_OUTPUT_CSC_YCBCR601, "ycbcr601" }, + { RADEON_OUTPUT_CSC_YCBCR709, "ycbcr709" }, +}; + static int radeon_modeset_create_props(struct radeon_device *rdev) { int sz; @@ -1448,6 +1517,12 @@ static int radeon_modeset_create_props(struct radeon_device *rdev) "dither", radeon_dither_enum_list, sz); + sz = ARRAY_SIZE(radeon_output_csc_enum_list); + rdev->mode_info.output_csc_property = + drm_property_create_enum(rdev->ddev, 0, + "output_csc", + radeon_output_csc_enum_list, sz); + return 0; } @@ -1568,6 +1643,9 @@ int radeon_modeset_init(struct radeon_device *rdev) rdev->ddev->mode_config.funcs = &radeon_mode_funcs; + if (radeon_use_pflipirq == 2 && rdev->family >= CHIP_R600) + rdev->ddev->mode_config.async_page_flip = true; + if (ASIC_IS_DCE5(rdev)) { rdev->ddev->mode_config.max_width = 16384; rdev->ddev->mode_config.max_height = 16384; @@ -1624,18 +1702,8 @@ int radeon_modeset_init(struct radeon_device *rdev) radeon_fbdev_init(rdev); drm_kms_helper_poll_init(rdev->ddev); - if (rdev->pm.dpm_enabled) { - /* do dpm late init */ - ret = radeon_pm_late_init(rdev); - if (ret) { - rdev->pm.dpm_enabled = false; - DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n"); - } - /* set the dpm state for PX since there won't be - * a modeset to call this. - */ - radeon_pm_compute_clocks(rdev); - } + /* do pm late init */ + ret = radeon_pm_late_init(rdev); return 0; } @@ -1649,9 +1717,9 @@ void radeon_modeset_fini(struct radeon_device *rdev) radeon_afmt_fini(rdev); drm_kms_helper_poll_fini(rdev->ddev); radeon_hpd_fini(rdev); - DRM_UNLOCK(rdev->ddev); /* Work around lock recursion. dumbbell@ */ +// DRM_UNLOCK(rdev->ddev); /* Work around lock recursion. dumbbell@ */ drm_mode_config_cleanup(rdev->ddev); - DRM_LOCK(rdev->ddev); +// DRM_LOCK(rdev->ddev); rdev->mode_info.mode_config_initialized = false; } /* free i2c buses */ @@ -1770,6 +1838,15 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, * \param dev Device to query. * \param crtc Crtc to query. * \param flags Flags from caller (DRM_CALLED_FROM_VBLIRQ or 0). + * For driver internal use only also supports these flags: + * + * USE_REAL_VBLANKSTART to use the real start of vblank instead + * of a fudged earlier start of vblank. + * + * GET_DISTANCE_TO_VBLANKSTART to return distance to the + * fudged earlier start of vblank in *vpos and the distance + * to true start of vblank in *hpos. + * * \param *vpos Location where vertical scanout position should be stored. * \param *hpos Location where horizontal scanout position should go. * \param *stime Target location for timestamp taken immediately before @@ -1791,8 +1868,9 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, * unknown small number of scanlines wrt. real scanout position. * */ -int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int flags, - int *vpos, int *hpos, ktime_t *stime, ktime_t *etime, +int radeon_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, + unsigned int flags, int *vpos, int *hpos, + ktime_t *stime, ktime_t *etime, const struct drm_display_mode *mode) { u32 stat_crtc = 0, vbl = 0, position = 0; @@ -1808,42 +1886,42 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl *stime = ktime_get(); if (ASIC_IS_DCE4(rdev)) { - if (crtc == 0) { + if (pipe == 0) { vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + EVERGREEN_CRTC0_REGISTER_OFFSET); position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + EVERGREEN_CRTC0_REGISTER_OFFSET); ret |= DRM_SCANOUTPOS_VALID; } - if (crtc == 1) { + if (pipe == 1) { vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + EVERGREEN_CRTC1_REGISTER_OFFSET); position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + EVERGREEN_CRTC1_REGISTER_OFFSET); ret |= DRM_SCANOUTPOS_VALID; } - if (crtc == 2) { + if (pipe == 2) { vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + EVERGREEN_CRTC2_REGISTER_OFFSET); position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + EVERGREEN_CRTC2_REGISTER_OFFSET); ret |= DRM_SCANOUTPOS_VALID; } - if (crtc == 3) { + if (pipe == 3) { vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + EVERGREEN_CRTC3_REGISTER_OFFSET); position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + EVERGREEN_CRTC3_REGISTER_OFFSET); ret |= DRM_SCANOUTPOS_VALID; } - if (crtc == 4) { + if (pipe == 4) { vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + EVERGREEN_CRTC4_REGISTER_OFFSET); position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + EVERGREEN_CRTC4_REGISTER_OFFSET); ret |= DRM_SCANOUTPOS_VALID; } - if (crtc == 5) { + if (pipe == 5) { vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + EVERGREEN_CRTC5_REGISTER_OFFSET); position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + @@ -1851,19 +1929,19 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl ret |= DRM_SCANOUTPOS_VALID; } } else if (ASIC_IS_AVIVO(rdev)) { - if (crtc == 0) { + if (pipe == 0) { vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END); position = RREG32(AVIVO_D1CRTC_STATUS_POSITION); ret |= DRM_SCANOUTPOS_VALID; } - if (crtc == 1) { + if (pipe == 1) { vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END); position = RREG32(AVIVO_D2CRTC_STATUS_POSITION); ret |= DRM_SCANOUTPOS_VALID; } } else { /* Pre-AVIVO: Different encoding of scanout pos and vblank interval. */ - if (crtc == 0) { + if (pipe == 0) { /* Assume vbl_end == 0, get vbl_start from * upper 16 bits. */ @@ -1877,7 +1955,7 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl ret |= DRM_SCANOUTPOS_VALID; } - if (crtc == 1) { + if (pipe == 1) { vbl = (RREG32(RADEON_CRTC2_V_TOTAL_DISP) & RADEON_CRTC_V_DISP) >> RADEON_CRTC_V_DISP_SHIFT; position = (RREG32(RADEON_CRTC2_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; @@ -1912,10 +1990,40 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl vbl_end = 0; } + /* Called from driver internal vblank counter query code? */ + if (flags & GET_DISTANCE_TO_VBLANKSTART) { + /* Caller wants distance from real vbl_start in *hpos */ + *hpos = *vpos - vbl_start; + } + + /* Fudge vblank to start a few scanlines earlier to handle the + * problem that vblank irqs fire a few scanlines before start + * of vblank. Some driver internal callers need the true vblank + * start to be used and signal this via the USE_REAL_VBLANKSTART flag. + * + * The cause of the "early" vblank irq is that the irq is triggered + * by the line buffer logic when the line buffer read position enters + * the vblank, whereas our crtc scanout position naturally lags the + * line buffer read position. + */ + if (!(flags & USE_REAL_VBLANKSTART)) + vbl_start -= rdev->mode_info.crtcs[pipe]->lb_vblank_lead_lines; + /* Test scanout position against vblank region. */ if ((*vpos < vbl_start) && (*vpos >= vbl_end)) in_vbl = false; + /* In vblank? */ + if (in_vbl) + ret |= DRM_SCANOUTPOS_IN_VBLANK; + + /* Called from driver internal vblank counter query code? */ + if (flags & GET_DISTANCE_TO_VBLANKSTART) { + /* Caller wants distance from fudged earlier vbl_start */ + *vpos -= vbl_start; + return ret; + } + /* Check if inside vblank area and apply corrective offsets: * vpos will then be >=0 in video scanout area, but negative * within vblank area, counting down the number of lines until @@ -1931,31 +2039,5 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl /* Correct for shifted end of vbl at vbl_end. */ *vpos = *vpos - vbl_end; - /* In vblank? */ - if (in_vbl) - ret |= DRM_SCANOUTPOS_IN_VBLANK; - - /* Is vpos outside nominal vblank area, but less than - * 1/100 of a frame height away from start of vblank? - * If so, assume this isn't a massively delayed vblank - * interrupt, but a vblank interrupt that fired a few - * microseconds before true start of vblank. Compensate - * by adding a full frame duration to the final timestamp. - * Happens, e.g., on ATI R500, R600. - * - * We only do this if DRM_CALLED_FROM_VBLIRQ. - */ - if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) { - vbl_start = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vdisplay; - vtotal = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vtotal; - - if (vbl_start - *vpos < vtotal / 100) { - *vpos -= vtotal; - - /* Signal this correction as "applied". */ - ret |= 0x8; - } - } - return ret; } diff --git a/sys/dev/drm/radeon/radeon_dp_auxch.c b/sys/dev/drm/radeon/radeon_dp_auxch.c new file mode 100644 index 0000000000..dd9a03ebcb --- /dev/null +++ b/sys/dev/drm/radeon/radeon_dp_auxch.c @@ -0,0 +1,204 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + */ +#include +#include +#include "radeon.h" +#include "nid.h" + +#define AUX_RX_ERROR_FLAGS (AUX_SW_RX_OVERFLOW | \ + AUX_SW_RX_HPD_DISCON | \ + AUX_SW_RX_PARTIAL_BYTE | \ + AUX_SW_NON_AUX_MODE | \ + AUX_SW_RX_SYNC_INVALID_L | \ + AUX_SW_RX_SYNC_INVALID_H | \ + AUX_SW_RX_INVALID_START | \ + AUX_SW_RX_RECV_NO_DET | \ + AUX_SW_RX_RECV_INVALID_H | \ + AUX_SW_RX_RECV_INVALID_V) + +#define AUX_SW_REPLY_GET_BYTE_COUNT(x) (((x) >> 24) & 0x1f) + +#define BARE_ADDRESS_SIZE 3 + +static const u32 aux_offset[] = +{ + 0x6200 - 0x6200, + 0x6250 - 0x6200, + 0x62a0 - 0x6200, + 0x6300 - 0x6200, + 0x6350 - 0x6200, + 0x63a0 - 0x6200, +}; + +ssize_t +radeon_dp_aux_transfer_native(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) +{ + struct radeon_i2c_chan *chan = + container_of(aux, struct radeon_i2c_chan, aux); + struct drm_device *dev = chan->dev; + struct radeon_device *rdev = dev->dev_private; + int ret = 0, i; + uint32_t tmp, ack = 0; + int instance = chan->rec.i2c_id & 0xf; + u8 byte; + u8 *buf = msg->buffer; + int retry_count = 0; + int bytes; + int msize; + bool is_write = false; + + if (WARN_ON(msg->size > 16)) + return -E2BIG; + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + is_write = true; + break; + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + break; + default: + return -EINVAL; + } + + /* work out two sizes required */ + msize = 0; + bytes = BARE_ADDRESS_SIZE; + if (msg->size) { + msize = msg->size - 1; + bytes++; + if (is_write) + bytes += msg->size; + } + + mutex_lock(&chan->mutex); + + /* switch the pad to aux mode */ + tmp = RREG32(chan->rec.mask_clk_reg); + tmp |= (1 << 16); + WREG32(chan->rec.mask_clk_reg, tmp); + + /* setup AUX control register with correct HPD pin */ + tmp = RREG32(AUX_CONTROL + aux_offset[instance]); + + tmp &= AUX_HPD_SEL(0x7); + tmp |= AUX_HPD_SEL(chan->rec.hpd); + tmp |= AUX_EN | AUX_LS_READ_EN | AUX_HPD_DISCON(0x1); + + WREG32(AUX_CONTROL + aux_offset[instance], tmp); + + /* atombios appears to write this twice lets copy it */ + WREG32(AUX_SW_CONTROL + aux_offset[instance], + AUX_SW_WR_BYTES(bytes)); + WREG32(AUX_SW_CONTROL + aux_offset[instance], + AUX_SW_WR_BYTES(bytes)); + + /* write the data header into the registers */ + /* request, address, msg size */ + byte = (msg->request << 4) | ((msg->address >> 16) & 0xf); + WREG32(AUX_SW_DATA + aux_offset[instance], + AUX_SW_DATA_MASK(byte) | AUX_SW_AUTOINCREMENT_DISABLE); + + byte = (msg->address >> 8) & 0xff; + WREG32(AUX_SW_DATA + aux_offset[instance], + AUX_SW_DATA_MASK(byte)); + + byte = msg->address & 0xff; + WREG32(AUX_SW_DATA + aux_offset[instance], + AUX_SW_DATA_MASK(byte)); + + byte = msize; + WREG32(AUX_SW_DATA + aux_offset[instance], + AUX_SW_DATA_MASK(byte)); + + /* if we are writing - write the msg buffer */ + if (is_write) { + for (i = 0; i < msg->size; i++) { + WREG32(AUX_SW_DATA + aux_offset[instance], + AUX_SW_DATA_MASK(buf[i])); + } + } + + /* clear the ACK */ + WREG32(AUX_SW_INTERRUPT_CONTROL + aux_offset[instance], AUX_SW_DONE_ACK); + + /* write the size and GO bits */ + WREG32(AUX_SW_CONTROL + aux_offset[instance], + AUX_SW_WR_BYTES(bytes) | AUX_SW_GO); + + /* poll the status registers - TODO irq support */ + do { + tmp = RREG32(AUX_SW_STATUS + aux_offset[instance]); + if (tmp & AUX_SW_DONE) { + break; + } + usleep_range(100, 200); + } while (retry_count++ < 1000); + + if (retry_count >= 1000) { + DRM_ERROR("auxch hw never signalled completion, error %08x\n", tmp); + ret = -EIO; + goto done; + } + + if (tmp & AUX_SW_RX_TIMEOUT) { + DRM_DEBUG_KMS("dp_aux_ch timed out\n"); + ret = -ETIMEDOUT; + goto done; + } + if (tmp & AUX_RX_ERROR_FLAGS) { + DRM_DEBUG_KMS("dp_aux_ch flags not zero: %08x\n", tmp); + ret = -EIO; + goto done; + } + + bytes = AUX_SW_REPLY_GET_BYTE_COUNT(tmp); + if (bytes) { + WREG32(AUX_SW_DATA + aux_offset[instance], + AUX_SW_DATA_RW | AUX_SW_AUTOINCREMENT_DISABLE); + + tmp = RREG32(AUX_SW_DATA + aux_offset[instance]); + ack = (tmp >> 8) & 0xff; + + for (i = 0; i < bytes - 1; i++) { + tmp = RREG32(AUX_SW_DATA + aux_offset[instance]); + if (buf) + buf[i] = (tmp >> 8) & 0xff; + } + if (buf) + ret = bytes - 1; + } + + WREG32(AUX_SW_INTERRUPT_CONTROL + aux_offset[instance], AUX_SW_DONE_ACK); + + if (is_write) + ret = msg->size; +done: + mutex_unlock(&chan->mutex); + + if (ret >= 0) + msg->reply = ack >> 4; + return ret; +} diff --git a/sys/dev/drm/radeon/radeon_drv.c b/sys/dev/drm/radeon/radeon_drv.c index f23114a46e..b0bce61d9f 100644 --- a/sys/dev/drm/radeon/radeon_drv.c +++ b/sys/dev/drm/radeon/radeon_drv.c @@ -93,11 +93,17 @@ * 2.39.0 - Add INFO query for number of active CUs * 2.40.0 - Add RADEON_GEM_GTT_WC/UC, flush HDP cache before submitting * CS to GPU on >= r600 + * 2.41.0 - evergreen/cayman: Add SET_BASE/DRAW_INDIRECT command parsing support + * 2.42.0 - Add VCE/VUI (Video Usability Information) support + * 2.43.0 - RADEON_INFO_GPU_RESET_COUNTER + * 2.44.0 - SET_APPEND_CNT packet3 support + * 2.45.0 - Allow setting shader registers using DMA/COPY packet3 on SI */ #define KMS_DRIVER_MAJOR 2 -#define KMS_DRIVER_MINOR 40 +#define KMS_DRIVER_MINOR 45 #define KMS_DRIVER_PATCHLEVEL 0 -int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon); +int radeon_suspend_kms(struct drm_device *dev, bool suspend, + bool fbcon, bool freeze); int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon); u32 radeon_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe); int radeon_enable_vblank_kms(struct drm_device *dev, unsigned int pipe); @@ -173,6 +179,9 @@ int radeon_deep_color = 0; int radeon_use_pflipirq = 2; int radeon_bapm = -1; int radeon_backlight = -1; +int radeon_auxch = -1; +int radeon_uvd = 1; +int radeon_vce = 1; TUNABLE_INT("drm.radeon.no_wb", &radeon_no_wb); MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); @@ -285,6 +294,18 @@ TUNABLE_INT("drm.radeon.backlight", &radeon_backlight); MODULE_PARM_DESC(backlight, "backlight support (1 = enable, 0 = disable, -1 = auto)"); module_param_named(backlight, radeon_backlight, int, 0444); +TUNABLE_INT("drm.radeon.auxch", &radeon_auxch); +MODULE_PARM_DESC(auxch, "Use native auxch experimental support (1 = enable, 0 = disable, -1 = auto)"); +module_param_named(auxch, radeon_auxch, int, 0444); + +TUNABLE_INT("drm.radeon.uvd", &radeon_uvd); +MODULE_PARM_DESC(uvd, "uvd enable/disable uvd support (1 = enable, 0 = disable)"); +module_param_named(uvd, radeon_uvd, int, 0444); + +TUNABLE_INT("drm.radeon.vce", &radeon_vce); +MODULE_PARM_DESC(vce, "vce enable/disable vce support (1 = enable, 0 = disable)"); +module_param_named(vce, radeon_vce, int, 0444); + static drm_pci_id_list_t pciidlist[] = { radeon_PCI_IDS }; @@ -338,7 +359,7 @@ static int radeon_pmops_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); - return radeon_suspend_kms(drm_dev, true, true); + return radeon_suspend_kms(drm_dev, true, true, false); } static int radeon_pmops_resume(struct device *dev) @@ -352,7 +373,7 @@ static int radeon_pmops_freeze(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); - return radeon_suspend_kms(drm_dev, false, true); + return radeon_suspend_kms(drm_dev, false, true, true); } static int radeon_pmops_thaw(struct device *dev) @@ -379,7 +400,7 @@ static int radeon_pmops_runtime_suspend(struct device *dev) drm_kms_helper_poll_disable(drm_dev); vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF); - ret = radeon_suspend_kms(drm_dev, false, false); + ret = radeon_suspend_kms(drm_dev, false, false, false); pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3cold); @@ -612,7 +633,7 @@ radeon_suspend(device_t kdev) int ret; dev = device_get_softc(kdev); - ret = radeon_suspend_kms(dev, true, true); + ret = radeon_suspend_kms(dev, true, true, false); return (-ret); } diff --git a/sys/dev/drm/radeon/radeon_encoders.c b/sys/dev/drm/radeon/radeon_encoders.c index 8c48b60cbe..b694c259bf 100644 --- a/sys/dev/drm/radeon/radeon_encoders.c +++ b/sys/dev/drm/radeon/radeon_encoders.c @@ -184,7 +184,6 @@ static void radeon_encoder_add_backlight(struct radeon_encoder *radeon_encoder, radeon_atom_backlight_init(radeon_encoder, connector); else radeon_legacy_backlight_init(radeon_encoder, connector); - rdev->mode_info.bl_encoder = radeon_encoder; } } diff --git a/sys/dev/drm/radeon/radeon_fb.c b/sys/dev/drm/radeon/radeon_fb.c index 196bf18540..1c9c763bc5 100644 --- a/sys/dev/drm/radeon/radeon_fb.c +++ b/sys/dev/drm/radeon/radeon_fb.c @@ -25,6 +25,11 @@ * * $FreeBSD: head/sys/dev/drm2/radeon/radeon_fb.c 254885 2013-08-25 19:37:15Z dumbbell $ */ +#if 0 +#include +#include +#include +#endif #include #include @@ -34,14 +39,18 @@ #include +#if 0 +#include +#endif + /* object hierarchy - - this contains a helper + a radeon fb - the helper contains a pointer to radeon framebuffer baseclass. -*/ + * this contains a helper + a radeon fb + * the helper contains a pointer to radeon framebuffer baseclass. + */ + struct radeon_fbdev { struct drm_fb_helper helper; struct radeon_framebuffer rfb; - struct list_head fbdev_list; struct radeon_device *rdev; }; @@ -52,9 +61,9 @@ static struct fb_ops radeonfb_ops = { #endif .fb_set_par = drm_fb_helper_set_par, #if 0 - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, + .fb_fillrect = drm_fb_helper_cfb_fillrect, + .fb_copyarea = drm_fb_helper_cfb_copyarea, + .fb_imageblit = drm_fb_helper_cfb_imageblit, .fb_pan_display = drm_fb_helper_pan_display, #endif .fb_blank = drm_fb_helper_blank, @@ -202,9 +211,6 @@ static int radeonfb_create(struct drm_fb_helper *helper, struct drm_mode_fb_cmd2 mode_cmd; struct drm_gem_object *gobj = NULL; struct radeon_bo *rbo = NULL; -#ifdef DUMBBELL_WIP - device_t device = rdev->dev; -#endif /* DUMBBELL_WIP */ device_t vga_dev = device_get_parent(rdev->dev->bsddev); int ret; unsigned long tmp; @@ -227,6 +233,7 @@ static int radeonfb_create(struct drm_fb_helper *helper, rbo = gem_to_radeon_bo(gobj); + /* okay we have an object now allocate the framebuffer */ info = drm_fb_helper_alloc_fbi(helper); if (IS_ERR(info)) { ret = PTR_ERR(info); @@ -234,6 +241,9 @@ static int radeonfb_create(struct drm_fb_helper *helper, } info->par = rfbdev; +#if 0 + info->skip_vt_switch = true; +#endif ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj); if (ret) { @@ -255,17 +265,52 @@ static int radeonfb_create(struct drm_fb_helper *helper, info->stride = fb->pitches[0]; info->depth = sizes->surface_bpp; info->is_vga_boot_display = vga_pci_is_boot_display(vga_dev); +#if 0 + memset_io(rbo->kptr, 0x0, radeon_bo_size(rbo)); + + strcpy(info->fix.id, "radeondrmfb"); + + drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); + + info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT; +#endif #ifdef __DragonFly__ info->fbops = radeonfb_ops; #else info->fbops = &radeonfb_ops; #endif +#if 0 + tmp = radeon_bo_gpu_offset(rbo) - rdev->mc.vram_start; + info->fix.smem_start = rdev->mc.aper_base + tmp; + info->fix.smem_len = radeon_bo_size(rbo); + info->screen_base = rbo->kptr; + info->screen_size = radeon_bo_size(rbo); + + drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height); + + /* setup aperture base/size for vesafb takeover */ + info->apertures->ranges[0].base = rdev->ddev->mode_config.fb_base; + info->apertures->ranges[0].size = rdev->mc.aper_size; + + /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ + + if (info->screen_base == NULL) { + ret = -ENOSPC; + goto out_destroy_fbi; + } + + DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start); +#endif DRM_INFO("fb mappable at 0x%jX\n", info->paddr); DRM_INFO("vram apper at 0x%lX\n", (unsigned long)rdev->mc.aper_base); DRM_INFO("size %lu\n", (unsigned long)radeon_bo_size(rbo)); DRM_INFO("fb depth is %d\n", fb->depth); DRM_INFO(" pitch is %d\n", fb->pitches[0]); +#if 0 + + vga_switcheroo_client_fb_set(rdev->ddev->pdev, info); +#endif return 0; out_destroy_fbi: @@ -275,7 +320,7 @@ out_unref: } if (fb && ret) { - drm_gem_object_unreference(gobj); + drm_gem_object_unreference_unlocked(gobj); drm_framebuffer_unregister_private(fb); drm_framebuffer_cleanup(fb); kfree(fb); /* XXX malloc'd in radeon_user_framebuffer_create? */ @@ -285,7 +330,8 @@ out_unref: void radeon_fb_output_poll_changed(struct radeon_device *rdev) { - drm_fb_helper_hotplug_event(&rdev->mode_info.rfbdev->helper); + if (rdev->mode_info.rfbdev) + drm_fb_helper_hotplug_event(&rdev->mode_info.rfbdev->helper); } static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev) @@ -318,6 +364,10 @@ int radeon_fbdev_init(struct radeon_device *rdev) int bpp_sel = 32; int ret; + /* don't enable fbdev if no connectors */ + if (list_empty(&rdev->ddev->mode_config.connector_list)) + return 0; + /* select 8 bpp console on RN50 or 16MB cards */ if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024)) bpp_sel = 8; @@ -335,18 +385,27 @@ int radeon_fbdev_init(struct radeon_device *rdev) ret = drm_fb_helper_init(rdev->ddev, &rfbdev->helper, rdev->num_crtc, RADEONFB_CONN_LIMIT); - if (ret) { - kfree(rfbdev); - return ret; - } + if (ret) + goto free; - drm_fb_helper_single_add_all_connectors(&rfbdev->helper); + ret = drm_fb_helper_single_add_all_connectors(&rfbdev->helper); + if (ret) + goto fini; /* disable all the possible outputs/crtcs before entering KMS mode */ drm_helper_disable_unused_functions(rdev->ddev); - drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel); + ret = drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel); + if (ret) + goto fini; + return 0; + +fini: + drm_fb_helper_fini(&rfbdev->helper); +free: + kfree(rfbdev); + return ret; } void radeon_fbdev_fini(struct radeon_device *rdev) @@ -362,17 +421,33 @@ void radeon_fbdev_fini(struct radeon_device *rdev) void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state) { #ifdef DUMBBELL_WIP - fb_set_suspend(rdev->mode_info.rfbdev->helper.fbdev, state); + if (rdev->mode_info.rfbdev) + fb_set_suspend(rdev->mode_info.rfbdev->helper.fbdev, state); #endif /* DUMBBELL_WIP */ } bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj) { + if (!rdev->mode_info.rfbdev) + return false; + if (robj == gem_to_radeon_bo(rdev->mode_info.rfbdev->rfb.obj)) return true; return false; } +void radeon_fb_add_connector(struct radeon_device *rdev, struct drm_connector *connector) +{ + if (rdev->mode_info.rfbdev) + drm_fb_helper_add_one_connector(&rdev->mode_info.rfbdev->helper, connector); +} + +void radeon_fb_remove_connector(struct radeon_device *rdev, struct drm_connector *connector) +{ + if (rdev->mode_info.rfbdev) + drm_fb_helper_remove_one_connector(&rdev->mode_info.rfbdev->helper, connector); +} + void radeon_fbdev_restore_mode(struct radeon_device *rdev) { struct radeon_fbdev *rfbdev = rdev->mode_info.rfbdev; diff --git a/sys/dev/drm/radeon/radeon_fence.c b/sys/dev/drm/radeon/radeon_fence.c index ece742c47c..5fc672b522 100644 --- a/sys/dev/drm/radeon/radeon_fence.c +++ b/sys/dev/drm/radeon/radeon_fence.c @@ -419,7 +419,7 @@ static int radeon_fence_wait_seq_timeout(struct radeon_device *rdev, } /** - * radeon_fence_wait - wait for a fence to signal + * radeon_fence_wait_timeout - wait for a fence to signal with timeout * * @fence: radeon fence object * @intr: use interruptible sleep @@ -427,27 +427,54 @@ static int radeon_fence_wait_seq_timeout(struct radeon_device *rdev, * Wait for the requested fence to signal (all asics). * @intr selects whether to use interruptable (true) or non-interruptable * (false) sleep when waiting for the fence. - * Returns 0 if the fence has passed, error for all other cases. + * @timeout: maximum time to wait, or MAX_SCHEDULE_TIMEOUT for infinite wait + * Returns remaining time if the sequence number has passed, 0 when + * the wait timeout, or an error for all other cases. */ -int radeon_fence_wait(struct radeon_fence *fence, bool intr) +int radeon_fence_wait_timeout(struct radeon_fence *fence, bool intr, int timeout) { u64 seq[RADEON_NUM_RINGS] = {}; int r; + if (timeout < 0) { + DRM_ERROR("radeon_fence_wait_timeout (%d) < 0!\n", timeout); + } + if (fence == NULL) { WARN(1, "Querying an invalid fence : %p !\n", fence); return -EINVAL; } seq[fence->ring] = fence->seq; - r = radeon_fence_wait_seq_timeout(fence->rdev, seq, intr, INT_MAX); - if (r < 0) { + r = radeon_fence_wait_seq_timeout(fence->rdev, seq, intr, timeout); + if (r <= 0) { return r; } return 0; } +/** + * radeon_fence_wait - wait for a fence to signal + * + * @fence: radeon fence object + * @intr: use interruptible sleep + * + * Wait for the requested fence to signal (all asics). + * @intr selects whether to use interruptable (true) or non-interruptable + * (false) sleep when waiting for the fence. + * Returns 0 if the fence has passed, error for all other cases. + */ +int radeon_fence_wait(struct radeon_fence *fence, bool intr) +{ + int r = radeon_fence_wait_timeout(fence, intr, INT_MAX); + if (r > 0) { + return 0; + } else { + return r; + } +} + /** * radeon_fence_wait_any - wait for a fence to signal on any ring * diff --git a/sys/dev/drm/radeon/radeon_gart.c b/sys/dev/drm/radeon/radeon_gart.c index ea98105af4..0617f0434b 100644 --- a/sys/dev/drm/radeon/radeon_gart.c +++ b/sys/dev/drm/radeon/radeon_gart.c @@ -77,7 +77,7 @@ int radeon_gart_table_ram_alloc(struct radeon_device *rdev) } rdev->gart.dmah = dmah; rdev->gart.ptr = dmah->vaddr; -#if defined(__i386) || defined(__amd64) +#if defined(__i386) || defined(__amd64) || defined(__amd64__) || defined(__x86_64__) if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 || rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) { pmap_change_attr((vm_offset_t)rdev->gart.ptr, @@ -103,7 +103,7 @@ void radeon_gart_table_ram_free(struct radeon_device *rdev) if (rdev->gart.ptr == NULL) { return; } -#if defined(__i386) || defined(__amd64) +#if defined(__i386) || defined(__amd64) || defined(__amd64__) || defined(__x86_64__) if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 || rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) { pmap_change_attr((vm_offset_t)rdev->gart.ptr, @@ -153,14 +153,14 @@ int radeon_gart_table_vram_alloc(struct radeon_device *rdev) */ int radeon_gart_table_vram_pin(struct radeon_device *rdev) { - u64 gpu_addr; + uint64_t gpu_addr; int r; r = radeon_bo_reserve(rdev->gart.robj, false); if (unlikely(r != 0)) return r; r = radeon_bo_pin(rdev->gart.robj, - RADEON_GEM_DOMAIN_VRAM, &gpu_addr); + RADEON_GEM_DOMAIN_VRAM, (u64 *)&gpu_addr); if (r) { radeon_bo_unreserve(rdev->gart.robj); return r; @@ -170,6 +170,19 @@ int radeon_gart_table_vram_pin(struct radeon_device *rdev) radeon_bo_unpin(rdev->gart.robj); radeon_bo_unreserve(rdev->gart.robj); rdev->gart.table_addr = gpu_addr; + + if (!r) { + int i; + + /* We might have dropped some GART table updates while it wasn't + * mapped, restore all entries + */ + for (i = 0; i < rdev->gart.num_gpu_pages; i++) + radeon_gart_set_page(rdev, i, rdev->gart.pages_entry[i]); + mb(); + radeon_gart_tlb_flush(rdev); + } + return r; } @@ -233,7 +246,6 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, unsigned t; unsigned p; int i, j; - u64 page_base; if (!rdev->gart.ready) { WARN(1, "trying to unbind memory from uninitialized GART !\n"); @@ -244,19 +256,19 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, for (i = 0; i < pages; i++, p++) { if (rdev->gart.pages[p]) { rdev->gart.pages[p] = NULL; - rdev->gart.pages_addr[p] = rdev->dummy_page.addr; - page_base = rdev->gart.pages_addr[p]; for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { + rdev->gart.pages_entry[t] = rdev->dummy_page.entry; if (rdev->gart.ptr) { - radeon_gart_set_page(rdev, t, page_base, - RADEON_GART_PAGE_DUMMY); + radeon_gart_set_page(rdev, t, + rdev->dummy_page.entry); } - page_base += RADEON_GPU_PAGE_SIZE; } } } - mb(); - radeon_gart_tlb_flush(rdev); + if (rdev->gart.ptr) { + mb(); + radeon_gart_tlb_flush(rdev); + } } /** @@ -279,7 +291,7 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, { unsigned t; unsigned p; - uint64_t page_base; + uint64_t page_base, page_entry; int i, j; if (!rdev->gart.ready) { @@ -290,18 +302,21 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); for (i = 0; i < pages; i++, p++) { - rdev->gart.pages_addr[p] = dma_addr[i]; rdev->gart.pages[p] = pagelist[i]; - if (rdev->gart.ptr) { - page_base = rdev->gart.pages_addr[p]; - for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { - radeon_gart_set_page(rdev, t, page_base, flags); - page_base += RADEON_GPU_PAGE_SIZE; - } + page_base = dma_addr[i]; + for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { + page_entry = radeon_gart_get_page_entry(page_base, flags); + rdev->gart.pages_entry[t] = page_entry; + if (rdev->gart.ptr) { + radeon_gart_set_page(rdev, t, page_entry); + } + page_base += RADEON_GPU_PAGE_SIZE; } } - mb(); - radeon_gart_tlb_flush(rdev); + if (rdev->gart.ptr) { + mb(); + radeon_gart_tlb_flush(rdev); + } return 0; } @@ -340,16 +355,15 @@ int radeon_gart_init(struct radeon_device *rdev) radeon_gart_fini(rdev); return -ENOMEM; } - rdev->gart.pages_addr = kmalloc(sizeof(dma_addr_t) * rdev->gart.num_cpu_pages, - M_DRM, M_ZERO | M_WAITOK); - if (rdev->gart.pages_addr == NULL) { + rdev->gart.pages_entry = kmalloc(sizeof(uint64_t) * rdev->gart.num_gpu_pages, + M_DRM, M_WAITOK); + if (rdev->gart.pages_entry == NULL) { radeon_gart_fini(rdev); return -ENOMEM; } /* set GART entry to point to the dummy page by default */ - for (i = 0; i < rdev->gart.num_cpu_pages; i++) { - rdev->gart.pages_addr[i] = rdev->dummy_page.addr; - } + for (i = 0; i < rdev->gart.num_gpu_pages; i++) + rdev->gart.pages_entry[i] = rdev->dummy_page.entry; return 0; } @@ -362,15 +376,15 @@ int radeon_gart_init(struct radeon_device *rdev) */ void radeon_gart_fini(struct radeon_device *rdev) { - if (rdev->gart.pages && rdev->gart.pages_addr && rdev->gart.ready) { + if (rdev->gart.ready) { /* unbind pages */ radeon_gart_unbind(rdev, 0, rdev->gart.num_cpu_pages); } rdev->gart.ready = false; kfree(rdev->gart.pages); - kfree(rdev->gart.pages_addr); + kfree(rdev->gart.pages_entry); rdev->gart.pages = NULL; - rdev->gart.pages_addr = NULL; + rdev->gart.pages_entry = NULL; radeon_dummy_page_fini(rdev); } diff --git a/sys/dev/drm/radeon/radeon_gem.c b/sys/dev/drm/radeon/radeon_gem.c index edabdd2b21..06ec91cb92 100644 --- a/sys/dev/drm/radeon/radeon_gem.c +++ b/sys/dev/drm/radeon/radeon_gem.c @@ -149,7 +149,8 @@ int radeon_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_pri struct radeon_bo_va *bo_va; int r; - if (rdev->family < CHIP_CAYMAN) { + if ((rdev->family < CHIP_CAYMAN) || + (!rdev->accel_working)) { return 0; } @@ -179,7 +180,8 @@ void radeon_gem_object_close(struct drm_gem_object *obj, struct radeon_bo_va *bo_va; int r; - if (rdev->family < CHIP_CAYMAN) { + if ((rdev->family < CHIP_CAYMAN) || + (!rdev->accel_working)) { return; } @@ -501,6 +503,7 @@ int radeon_gem_va_ioctl(struct drm_device *dev, void *data, bo_va = radeon_vm_bo_find(&fpriv->vm, rbo); if (!bo_va) { args->operation = RADEON_VA_RESULT_ERROR; + radeon_bo_unreserve(rbo); drm_gem_object_unreference_unlocked(gobj); return -ENOENT; } @@ -510,6 +513,7 @@ int radeon_gem_va_ioctl(struct drm_device *dev, void *data, if (bo_va->soffset) { args->operation = RADEON_VA_RESULT_VA_EXIST; args->offset = bo_va->soffset; + radeon_bo_unreserve(rbo); goto out; } r = radeon_vm_bo_set_addr(rdev, bo_va, args->offset, args->flags); @@ -525,7 +529,6 @@ int radeon_gem_va_ioctl(struct drm_device *dev, void *data, args->operation = RADEON_VA_RESULT_ERROR; } out: - radeon_bo_unreserve(rbo); drm_gem_object_unreference_unlocked(gobj); return r; } diff --git a/sys/dev/drm/radeon/radeon_i2c.c b/sys/dev/drm/radeon/radeon_i2c.c index a068e8c790..d2a4bd2c11 100644 --- a/sys/dev/drm/radeon/radeon_i2c.c +++ b/sys/dev/drm/radeon/radeon_i2c.c @@ -67,10 +67,9 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux) radeon_router_select_ddc_port(radeon_connector); if (use_aux) { - struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; - ret = iicbus_transfer(dig->dp_i2c_bus->adapter, msgs, 2); + ret = iicbus_transfer(radeon_connector->ddc_bus->aux.dev->bsddev, msgs, 2); } else { - ret = iicbus_transfer(radeon_connector->ddc_bus->adapter, msgs, 2); + ret = iicbus_transfer(radeon_connector->ddc_bus->adapter_dev, msgs, 2); } if (ret != 0) @@ -98,7 +97,7 @@ static int radeon_iicbb_pre_xfer(device_t dev) struct radeon_i2c_bus_rec *rec = &i2c->rec; uint32_t temp; - lockmgr(&i2c->mutex, LK_EXCLUSIVE); + mutex_lock(&i2c->mutex); /* RV410 appears to have a bug where the hw i2c in reset * holds the i2c port in a bad state - switch hw i2c away before @@ -116,7 +115,7 @@ static int radeon_iicbb_pre_xfer(device_t dev) else reg = RADEON_GPIO_CRT2_DDC; - lockmgr(&rdev->dc_hw_i2c_mutex, LK_EXCLUSIVE); + mutex_lock(&rdev->dc_hw_i2c_mutex); if (rec->a_clk_reg == reg) { WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST | R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1))); @@ -124,7 +123,7 @@ static int radeon_iicbb_pre_xfer(device_t dev) WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST | R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3))); } - lockmgr(&rdev->dc_hw_i2c_mutex, LK_RELEASE); + mutex_unlock(&rdev->dc_hw_i2c_mutex); } } @@ -177,7 +176,7 @@ static void radeon_iicbb_post_xfer(device_t dev) WREG32(rec->mask_data_reg, temp); temp = RREG32(rec->mask_data_reg); - lockmgr(&i2c->mutex, LK_RELEASE); + mutex_unlock(&i2c->mutex); } static int radeon_iicbb_get_clock(device_t dev) @@ -414,9 +413,9 @@ static int r100_hw_i2c_xfer(struct radeon_i2c_chan *i2c, u32 i2c_cntl_0, i2c_cntl_1, i2c_data; u32 tmp, reg; - lockmgr(&rdev->dc_hw_i2c_mutex, LK_EXCLUSIVE); + mutex_lock(&rdev->dc_hw_i2c_mutex); /* take the pm lock since we need a constant sclk */ - lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE); + mutex_lock(&rdev->pm.mutex); prescale = radeon_get_i2c_prescale(rdev); @@ -646,8 +645,8 @@ done: WREG32(RADEON_BIOS_6_SCRATCH, tmp); } - lockmgr(&rdev->pm.mutex, LK_RELEASE); - lockmgr(&rdev->dc_hw_i2c_mutex, LK_RELEASE); + mutex_unlock(&rdev->pm.mutex); + mutex_unlock(&rdev->dc_hw_i2c_mutex); return ret; } @@ -666,9 +665,9 @@ static int r500_hw_i2c_xfer(struct radeon_i2c_chan *i2c, u32 tmp, reg; u32 saved1, saved2; - lockmgr(&rdev->dc_hw_i2c_mutex, LK_EXCLUSIVE); + mutex_lock(&rdev->dc_hw_i2c_mutex); /* take the pm lock since we need a constant sclk */ - lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE); + mutex_lock(&rdev->pm.mutex); prescale = radeon_get_i2c_prescale(rdev); @@ -881,8 +880,8 @@ done: tmp &= ~ATOM_S6_HW_I2C_BUSY_STATE; WREG32(RADEON_BIOS_6_SCRATCH, tmp); - lockmgr(&rdev->pm.mutex, LK_RELEASE); - lockmgr(&rdev->dc_hw_i2c_mutex, LK_RELEASE); + mutex_unlock(&rdev->pm.mutex); + mutex_unlock(&rdev->dc_hw_i2c_mutex); return ret; } @@ -895,7 +894,7 @@ static int radeon_hw_i2c_xfer(device_t dev, struct radeon_i2c_bus_rec *rec = &i2c->rec; int ret = 0; - lockmgr(&i2c->mutex, LK_EXCLUSIVE); + mutex_lock(&i2c->mutex); switch (rdev->family) { case CHIP_R100: @@ -963,7 +962,7 @@ static int radeon_hw_i2c_xfer(device_t dev, break; } - lockmgr(&i2c->mutex, LK_RELEASE); + mutex_unlock(&i2c->mutex); return ret; } @@ -1016,7 +1015,6 @@ radeon_hw_i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) return 0; } - static device_method_t radeon_hw_i2c_methods[] = { DEVMETHOD(device_probe, radeon_hw_i2c_probe), DEVMETHOD(device_attach, radeon_hw_i2c_attach), @@ -1061,7 +1059,15 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, get_mplock(); i2c->rec = *rec; +#if 0 + i2c->adapter.owner = THIS_MODULE; + i2c->adapter.class = I2C_CLASS_DDC; + i2c->adapter.dev.parent = &dev->pdev->dev; +#endif i2c->dev = dev; +#if 0 + i2c_set_adapdata(&i2c->adapter, i2c); +#endif lockinit(&i2c->mutex, "ri2cmtx", 0, LK_CANRECURSE); if (rec->mm_i2c || (rec->hw_capable && @@ -1088,12 +1094,13 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, goto out_free; } - i2c->adapter = device_find_child(iicbus_dev, "iicbus", -1); - if (i2c->adapter == NULL) { + i2c->adapter_dev = device_find_child(iicbus_dev, "iicbus", -1); + if (i2c->adapter_dev == NULL) { DRM_ERROR("hw i2c bridge doesn't have iicbus child\n"); device_delete_child(dev->dev->bsddev, iicbus_dev); goto out_free; } + DRM_INFO("Created radeon_hw_i2c bus\n"); } else if (rec->hw_capable && radeon_hw_i2c && ASIC_IS_DCE3(rdev)) { @@ -1117,12 +1124,13 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, goto out_free; } - i2c->adapter = device_find_child(iicbus_dev, "iicbus", -1); - if (i2c->adapter == NULL) { + i2c->adapter_dev = device_find_child(iicbus_dev, "iicbus", -1); + if (i2c->adapter_dev == NULL) { DRM_ERROR("hw i2c bridge doesn't have iicbus child\n"); device_delete_child(dev->dev->bsddev, iicbus_dev); goto out_free; } + DRM_INFO("Created radeon_atom_hw_bus\n"); } else { device_t iicbb_dev; @@ -1153,13 +1161,14 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, goto out_free; } - i2c->adapter = device_find_child(iicbb_dev, "iicbus", -1); - if (i2c->adapter == NULL) { + i2c->adapter_dev = device_find_child(iicbb_dev, "iicbus", -1); + if (i2c->adapter_dev == NULL) { DRM_ERROR( "bbbus bridge doesn't have iicbus grandchild\n"); device_delete_child(dev->dev->bsddev, iicbus_dev); goto out_free; } + DRM_INFO("Created Radeon i2c bit bus for (%s)\n", name); } i2c->iic_bus = iicbus_dev; @@ -1174,35 +1183,6 @@ out_free: } -struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, - struct radeon_i2c_bus_rec *rec, - const char *name) -{ - struct radeon_i2c_chan *i2c; - int ret; - - i2c = kzalloc(sizeof(struct radeon_i2c_chan), GFP_KERNEL); - if (i2c == NULL) - return NULL; - - i2c->rec = *rec; - i2c->dev = dev; - ksnprintf(i2c->name, sizeof(i2c->name), "Radeon aux bus %s", name); - ret = iic_dp_aux_add_bus(dev->dev->bsddev, i2c->name, - radeon_dp_i2c_aux_ch, i2c, &i2c->iic_bus, - &i2c->adapter); - if (ret) { - DRM_INFO("Failed to register i2c %s\n", name); - goto out_free; - } - - return i2c; -out_free: - kfree(i2c); - return NULL; - -} - void radeon_i2c_destroy(struct radeon_i2c_chan *i2c) { if (!i2c) @@ -1216,6 +1196,8 @@ void radeon_i2c_destroy(struct radeon_i2c_chan *i2c) KASSERT(ret == 0, ("unable to detach iic bus %s: %d", i2c->name, ret)); } + if (i2c->has_aux) + drm_dp_aux_unregister(&i2c->aux); kfree(i2c); } @@ -1300,7 +1282,7 @@ void radeon_i2c_get_byte(struct radeon_i2c_chan *i2c_bus, out_buf[0] = addr; out_buf[1] = 0; - if (iicbus_transfer(i2c_bus->adapter, msgs, 2) == 0) { + if (iicbus_transfer(i2c_bus->adapter_dev, msgs, 2) == 0) { *val = in_buf[0]; DRM_DEBUG("val = 0x%02x\n", *val); } else { @@ -1326,7 +1308,7 @@ void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c_bus, out_buf[0] = addr; out_buf[1] = val; - if (iicbus_transfer(i2c_bus->adapter, &msg, 1) != 0) + if (iicbus_transfer(i2c_bus->adapter_dev, &msg, 1) != 0) DRM_DEBUG("i2c 0x%02x 0x%02x write failed\n", addr, val); } diff --git a/sys/dev/drm/radeon/radeon_irq_kms.c b/sys/dev/drm/radeon/radeon_irq_kms.c index bb15445a1f..b628f02a11 100644 --- a/sys/dev/drm/radeon/radeon_irq_kms.c +++ b/sys/dev/drm/radeon/radeon_irq_kms.c @@ -85,14 +85,36 @@ static void radeon_hotplug_work_func(void *arg, int pending) struct drm_mode_config *mode_config = &dev->mode_config; struct drm_connector *connector; + /* we can race here at startup, some boards seem to trigger + * hotplug irqs when they shouldn't. */ + if (!rdev->mode_info.mode_config_initialized) + return; + + mutex_lock(&mode_config->mutex); if (mode_config->num_connector) { list_for_each_entry(connector, &mode_config->connector_list, head) radeon_connector_hotplug(connector); } + mutex_unlock(&mode_config->mutex); /* Just fire off a uevent and let userspace tell us what to do */ drm_helper_hpd_irq_event(dev); } +static void radeon_dp_work_func(struct work_struct *work) +{ + struct radeon_device *rdev = container_of(work, struct radeon_device, + dp_work); + struct drm_device *dev = rdev->ddev; + struct drm_mode_config *mode_config = &dev->mode_config; + struct drm_connector *connector; + + /* this should take a mutex */ + if (mode_config->num_connector) { + list_for_each_entry(connector, &mode_config->connector_list, head) + radeon_connector_hotplug(connector); + } +} + /** * radeon_driver_irq_preinstall_kms - drm irq preinstall callback * @@ -104,9 +126,10 @@ static void radeon_hotplug_work_func(void *arg, int pending) void radeon_driver_irq_preinstall_kms(struct drm_device *dev) { struct radeon_device *rdev = dev->dev_private; + unsigned long irqflags; unsigned i; - lockmgr(&rdev->irq.lock, LK_EXCLUSIVE); + spin_lock_irqsave(&rdev->irq.lock, irqflags); /* Disable *all* interrupts */ for (i = 0; i < RADEON_NUM_RINGS; i++) atomic_set(&rdev->irq.ring_int[i], 0); @@ -119,7 +142,7 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev) rdev->irq.afmt[i] = false; } radeon_irq_set(rdev); - lockmgr(&rdev->irq.lock, LK_RELEASE); + spin_unlock_irqrestore(&rdev->irq.lock, irqflags); /* Clear bits */ radeon_irq_process(rdev); } @@ -134,7 +157,13 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev) */ int radeon_driver_irq_postinstall_kms(struct drm_device *dev) { - dev->max_vblank_count = 0x001fffff; + struct radeon_device *rdev = dev->dev_private; + + if (ASIC_IS_AVIVO(rdev)) + dev->max_vblank_count = 0x00ffffff; + else + dev->max_vblank_count = 0x001fffff; + return 0; } @@ -148,12 +177,13 @@ int radeon_driver_irq_postinstall_kms(struct drm_device *dev) void radeon_driver_irq_uninstall_kms(struct drm_device *dev) { struct radeon_device *rdev = dev->dev_private; + unsigned long irqflags; unsigned i; if (rdev == NULL) { return; } - lockmgr(&rdev->irq.lock, LK_EXCLUSIVE); + spin_lock_irqsave(&rdev->irq.lock, irqflags); /* Disable *all* interrupts */ for (i = 0; i < RADEON_NUM_RINGS; i++) atomic_set(&rdev->irq.ring_int[i], 0); @@ -166,7 +196,7 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev) rdev->irq.afmt[i] = false; } radeon_irq_set(rdev); - lockmgr(&rdev->irq.lock, LK_RELEASE); + spin_unlock_irqrestore(&rdev->irq.lock, irqflags); } /** @@ -265,14 +295,18 @@ int radeon_irq_kms_init(struct radeon_device *rdev) /* enable msi */ rdev->msi_enabled = (rdev->ddev->irq_type == PCI_INTR_TYPE_MSI); + DRM_INFO("radeon_irq_kms_init: msi_enabled? (%d)\n", rdev->msi_enabled); + TASK_INIT(&rdev->hotplug_work, 0, radeon_hotplug_work_func, rdev); + INIT_WORK(&rdev->dp_work, radeon_dp_work_func); TASK_INIT(&rdev->audio_work, 0, r600_audio_update_hdmi, rdev); rdev->irq.installed = true; - DRM_UNLOCK(rdev->ddev); +// DRM_UNLOCK(rdev->ddev); r = drm_irq_install(rdev->ddev, rdev->ddev->irq); - DRM_LOCK(rdev->ddev); +// DRM_LOCK(rdev->ddev); if (r) { + DRM_ERROR("radeon_irq_kms_init: drm_irq_install FAILED (%d)\n", r); rdev->irq.installed = false; taskqueue_drain(rdev->tq, &rdev->hotplug_work); return r; @@ -311,13 +345,15 @@ void radeon_irq_kms_fini(struct radeon_device *rdev) */ void radeon_irq_kms_sw_irq_get(struct radeon_device *rdev, int ring) { + unsigned long irqflags; + if (!rdev->ddev->irq_enabled) return; if (atomic_inc_return(&rdev->irq.ring_int[ring]) == 1) { - lockmgr(&rdev->irq.lock, LK_EXCLUSIVE); + spin_lock_irqsave(&rdev->irq.lock, irqflags); radeon_irq_set(rdev); - lockmgr(&rdev->irq.lock, LK_RELEASE); + spin_unlock_irqrestore(&rdev->irq.lock, irqflags); } } @@ -350,13 +386,15 @@ bool radeon_irq_kms_sw_irq_get_delayed(struct radeon_device *rdev, int ring) */ void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev, int ring) { + unsigned long irqflags; + if (!rdev->ddev->irq_enabled) return; if (atomic_dec_and_test(&rdev->irq.ring_int[ring])) { - lockmgr(&rdev->irq.lock, LK_EXCLUSIVE); + spin_lock_irqsave(&rdev->irq.lock, irqflags); radeon_irq_set(rdev); - lockmgr(&rdev->irq.lock, LK_RELEASE); + spin_unlock_irqrestore(&rdev->irq.lock, irqflags); } } @@ -371,6 +409,8 @@ void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev, int ring) */ void radeon_irq_kms_pflip_irq_get(struct radeon_device *rdev, int crtc) { + unsigned long irqflags; + if (crtc < 0 || crtc >= rdev->num_crtc) return; @@ -378,9 +418,9 @@ void radeon_irq_kms_pflip_irq_get(struct radeon_device *rdev, int crtc) return; if (atomic_inc_return(&rdev->irq.pflip[crtc]) == 1) { - lockmgr(&rdev->irq.lock, LK_EXCLUSIVE); + spin_lock_irqsave(&rdev->irq.lock, irqflags); radeon_irq_set(rdev); - lockmgr(&rdev->irq.lock, LK_RELEASE); + spin_unlock_irqrestore(&rdev->irq.lock, irqflags); } } @@ -395,6 +435,8 @@ void radeon_irq_kms_pflip_irq_get(struct radeon_device *rdev, int crtc) */ void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc) { + unsigned long irqflags; + if (crtc < 0 || crtc >= rdev->num_crtc) return; @@ -402,9 +444,9 @@ void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc) return; if (atomic_dec_and_test(&rdev->irq.pflip[crtc])) { - lockmgr(&rdev->irq.lock, LK_EXCLUSIVE); + spin_lock_irqsave(&rdev->irq.lock, irqflags); radeon_irq_set(rdev); - lockmgr(&rdev->irq.lock, LK_RELEASE); + spin_unlock_irqrestore(&rdev->irq.lock, irqflags); } } @@ -418,13 +460,16 @@ void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc) */ void radeon_irq_kms_enable_afmt(struct radeon_device *rdev, int block) { + unsigned long irqflags; + if (!rdev->ddev->irq_enabled) return; - lockmgr(&rdev->irq.lock, LK_EXCLUSIVE); + spin_lock_irqsave(&rdev->irq.lock, irqflags); rdev->irq.afmt[block] = true; radeon_irq_set(rdev); - lockmgr(&rdev->irq.lock, LK_RELEASE); + spin_unlock_irqrestore(&rdev->irq.lock, irqflags); + } /** @@ -437,13 +482,15 @@ void radeon_irq_kms_enable_afmt(struct radeon_device *rdev, int block) */ void radeon_irq_kms_disable_afmt(struct radeon_device *rdev, int block) { + unsigned long irqflags; + if (!rdev->ddev->irq_enabled) return; - lockmgr(&rdev->irq.lock, LK_EXCLUSIVE); + spin_lock_irqsave(&rdev->irq.lock, irqflags); rdev->irq.afmt[block] = false; radeon_irq_set(rdev); - lockmgr(&rdev->irq.lock, LK_RELEASE); + spin_unlock_irqrestore(&rdev->irq.lock, irqflags); } /** @@ -456,16 +503,17 @@ void radeon_irq_kms_disable_afmt(struct radeon_device *rdev, int block) */ void radeon_irq_kms_enable_hpd(struct radeon_device *rdev, unsigned hpd_mask) { + unsigned long irqflags; int i; if (!rdev->ddev->irq_enabled) return; - lockmgr(&rdev->irq.lock, LK_EXCLUSIVE); + spin_lock_irqsave(&rdev->irq.lock, irqflags); for (i = 0; i < RADEON_MAX_HPD_PINS; ++i) rdev->irq.hpd[i] |= !!(hpd_mask & (1 << i)); radeon_irq_set(rdev); - lockmgr(&rdev->irq.lock, LK_RELEASE); + spin_unlock_irqrestore(&rdev->irq.lock, irqflags); } /** @@ -478,15 +526,16 @@ void radeon_irq_kms_enable_hpd(struct radeon_device *rdev, unsigned hpd_mask) */ void radeon_irq_kms_disable_hpd(struct radeon_device *rdev, unsigned hpd_mask) { + unsigned long irqflags; int i; if (!rdev->ddev->irq_enabled) return; - lockmgr(&rdev->irq.lock, LK_EXCLUSIVE); + spin_lock_irqsave(&rdev->irq.lock, irqflags); for (i = 0; i < RADEON_MAX_HPD_PINS; ++i) rdev->irq.hpd[i] &= !(hpd_mask & (1 << i)); radeon_irq_set(rdev); - lockmgr(&rdev->irq.lock, LK_RELEASE); + spin_unlock_irqrestore(&rdev->irq.lock, irqflags); } diff --git a/sys/dev/drm/radeon/radeon_kms.c b/sys/dev/drm/radeon/radeon_kms.c index 2041067367..1f1536c92d 100644 --- a/sys/dev/drm/radeon/radeon_kms.c +++ b/sys/dev/drm/radeon/radeon_kms.c @@ -121,6 +121,7 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) if ((radeon_runtime_pm != 0) && radeon_has_atpx() && ((flags & RADEON_IS_IGP) == 0)) + flags |= RADEON_IS_PX; #endif /* radeon_device_init should report only fatal error @@ -187,7 +188,9 @@ static void radeon_set_filp_rights(struct drm_device *dev, struct drm_file *applier, uint32_t *value) { - mutex_lock(&dev->struct_mutex); + struct radeon_device *rdev = dev->dev_private; + + mutex_lock(&rdev->gem.mutex); if (*value == 1) { /* wants rights */ if (!*owner) @@ -198,7 +201,7 @@ static void radeon_set_filp_rights(struct drm_device *dev, *owner = NULL; } *value = *owner == applier ? 1 : 0; - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&rdev->gem.mutex); } /* @@ -553,6 +556,38 @@ static int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file else *value = 1; break; + case RADEON_INFO_CURRENT_GPU_TEMP: + /* get temperature in millidegrees C */ + if (rdev->asic->pm.get_temperature) + *value = radeon_get_temperature(rdev); + else + *value = 0; + break; + case RADEON_INFO_CURRENT_GPU_SCLK: + /* get sclk in Mhz */ + if (rdev->pm.dpm_enabled) + *value = radeon_dpm_get_current_sclk(rdev) / 100; + else + *value = rdev->pm.current_sclk / 100; + break; + case RADEON_INFO_CURRENT_GPU_MCLK: + /* get mclk in Mhz */ + if (rdev->pm.dpm_enabled) + *value = radeon_dpm_get_current_mclk(rdev) / 100; + else + *value = rdev->pm.current_mclk / 100; + break; + case RADEON_INFO_READ_REG: + if (copy_from_user(value, value_ptr, sizeof(uint32_t))) { + DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__); + return -EFAULT; + } + if (radeon_get_allowed_info_register(rdev, *value, value)) + return -EINVAL; + break; + case RADEON_INFO_GPU_RESET_COUNTER: + *value = atomic_read(&rdev->gpu_reset_counter); + break; default: DRM_DEBUG_KMS("Invalid request %d\n", info->request); return -EINVAL; @@ -573,7 +608,7 @@ static int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file * * @dev: drm dev pointer * - * Switch vga switcheroo state after last close (all asics). + * Switch vga_switcheroo state after last close (all asics). */ void radeon_driver_lastclose_kms(struct drm_device *dev) { @@ -617,14 +652,14 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) return -ENOMEM; } - vm = &fpriv->vm; - r = radeon_vm_init(rdev, vm); - if (r) { - kfree(fpriv); - return r; - } - if (rdev->accel_working) { + vm = &fpriv->vm; + r = radeon_vm_init(rdev, vm); + if (r) { + kfree(fpriv); + return r; + } + r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false); if (r) { radeon_vm_fini(rdev, vm); @@ -641,7 +676,6 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) RADEON_VM_PAGE_READABLE | RADEON_VM_PAGE_SNOOPED); - radeon_bo_unreserve(rdev->ring_tmp_bo.bo); if (r) { radeon_vm_fini(rdev, vm); kfree(fpriv); @@ -684,9 +718,9 @@ void radeon_driver_postclose_kms(struct drm_device *dev, radeon_vm_bo_rmv(rdev, vm->ib_bo_va); radeon_bo_unreserve(rdev->ring_tmp_bo.bo); } + radeon_vm_fini(rdev, vm); } - radeon_vm_fini(rdev, vm); kfree(fpriv); file_priv->driver_priv = NULL; } @@ -705,10 +739,14 @@ void radeon_driver_preclose_kms(struct drm_device *dev, struct drm_file *file_priv) { struct radeon_device *rdev = dev->dev_private; + + mutex_lock(&rdev->gem.mutex); if (rdev->hyperz_filp == file_priv) rdev->hyperz_filp = NULL; if (rdev->cmask_filp == file_priv) rdev->cmask_filp = NULL; + mutex_unlock(&rdev->gem.mutex); + radeon_uvd_free_handles(rdev, file_priv); radeon_vce_free_handles(rdev, file_priv); } @@ -720,20 +758,20 @@ void radeon_driver_preclose_kms(struct drm_device *dev, * radeon_get_vblank_counter_kms - get frame count * * @dev: drm dev pointer - * @crtc: crtc to get the frame count from + * @pipe: crtc to get the frame count from * * Gets the frame count on the requested crtc (all asics). * Returns frame count on success, -EINVAL on failure. */ -u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc); -u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc) +u32 radeon_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe); +u32 radeon_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe) { int vpos, hpos, stat; u32 count; struct radeon_device *rdev = dev->dev_private; - if (crtc < 0 || crtc >= rdev->num_crtc) { - DRM_ERROR("Invalid crtc %d\n", crtc); + if (pipe >= rdev->num_crtc) { + DRM_ERROR("Invalid crtc %u\n", pipe); return -EINVAL; } @@ -745,29 +783,29 @@ u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc) * and start of vsync, so vpos >= 0 means to bump the hw frame counter * result by 1 to give the proper appearance to caller. */ - if (rdev->mode_info.crtcs[crtc]) { + if (rdev->mode_info.crtcs[pipe]) { /* Repeat readout if needed to provide stable result if * we cross start of vsync during the queries. */ do { - count = radeon_get_vblank_counter(rdev, crtc); + count = radeon_get_vblank_counter(rdev, pipe); /* Ask radeon_get_crtc_scanoutpos to return vpos as * distance to start of vblank, instead of regular * vertical scanout pos. */ stat = radeon_get_crtc_scanoutpos( - dev, crtc, GET_DISTANCE_TO_VBLANKSTART, + dev, pipe, GET_DISTANCE_TO_VBLANKSTART, &vpos, &hpos, NULL, NULL, - &rdev->mode_info.crtcs[crtc]->base.hwmode); - } while (count != radeon_get_vblank_counter(rdev, crtc)); + &rdev->mode_info.crtcs[pipe]->base.hwmode); + } while (count != radeon_get_vblank_counter(rdev, pipe)); if (((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) != (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE))) { DRM_DEBUG_VBL("Query failed! stat %d\n", stat); } else { - DRM_DEBUG_VBL("crtc %d: dist from vblank start %d\n", - crtc, vpos); + DRM_DEBUG_VBL("crtc %u: dist from vblank start %d\n", + pipe, vpos); /* Bump counter if we are at >= leading edge of vblank, * but before vsync where vpos would turn negative and @@ -779,7 +817,7 @@ u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc) } else { /* Fallback to use value as is. */ - count = radeon_get_vblank_counter(rdev, crtc); + count = radeon_get_vblank_counter(rdev, pipe); DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n"); } @@ -881,88 +919,51 @@ int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc, &drmcrtc->hwmode); } -#define KMS_INVALID_IOCTL(name) \ -static int name(struct drm_device *dev, void *data, struct drm_file \ - *file_priv) \ -{ \ - DRM_ERROR("invalid ioctl with kms %s\n", __func__); \ - return -EINVAL; \ -} - -/* - * All these ioctls are invalid in kms world. - */ -KMS_INVALID_IOCTL(radeon_cp_init_kms) -KMS_INVALID_IOCTL(radeon_cp_start_kms) -KMS_INVALID_IOCTL(radeon_cp_stop_kms) -KMS_INVALID_IOCTL(radeon_cp_reset_kms) -KMS_INVALID_IOCTL(radeon_cp_idle_kms) -KMS_INVALID_IOCTL(radeon_cp_resume_kms) -KMS_INVALID_IOCTL(radeon_engine_reset_kms) -KMS_INVALID_IOCTL(radeon_fullscreen_kms) -KMS_INVALID_IOCTL(radeon_cp_swap_kms) -KMS_INVALID_IOCTL(radeon_cp_clear_kms) -KMS_INVALID_IOCTL(radeon_cp_vertex_kms) -KMS_INVALID_IOCTL(radeon_cp_indices_kms) -KMS_INVALID_IOCTL(radeon_cp_texture_kms) -KMS_INVALID_IOCTL(radeon_cp_stipple_kms) -KMS_INVALID_IOCTL(radeon_cp_indirect_kms) -KMS_INVALID_IOCTL(radeon_cp_vertex2_kms) -KMS_INVALID_IOCTL(radeon_cp_cmdbuf_kms) -KMS_INVALID_IOCTL(radeon_cp_getparam_kms) -KMS_INVALID_IOCTL(radeon_cp_flip_kms) -KMS_INVALID_IOCTL(radeon_mem_alloc_kms) -KMS_INVALID_IOCTL(radeon_mem_free_kms) -KMS_INVALID_IOCTL(radeon_mem_init_heap_kms) -KMS_INVALID_IOCTL(radeon_irq_emit_kms) -KMS_INVALID_IOCTL(radeon_irq_wait_kms) -KMS_INVALID_IOCTL(radeon_cp_setparam_kms) -KMS_INVALID_IOCTL(radeon_surface_alloc_kms) -KMS_INVALID_IOCTL(radeon_surface_free_kms) - - const struct drm_ioctl_desc radeon_ioctls_kms[] = { - DRM_IOCTL_DEF_DRV(RADEON_CP_INIT, radeon_cp_init_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF_DRV(RADEON_CP_START, radeon_cp_start_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF_DRV(RADEON_CP_STOP, radeon_cp_stop_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF_DRV(RADEON_CP_RESET, radeon_cp_reset_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF_DRV(RADEON_CP_IDLE, radeon_cp_idle_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_CP_RESUME, radeon_cp_resume_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_RESET, radeon_engine_reset_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_FULLSCREEN, radeon_fullscreen_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_SWAP, radeon_cp_swap_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_CLEAR, radeon_cp_clear_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_VERTEX, radeon_cp_vertex_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_INDICES, radeon_cp_indices_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_TEXTURE, radeon_cp_texture_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_STIPPLE, radeon_cp_stipple_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_INDIRECT, radeon_cp_indirect_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF_DRV(RADEON_VERTEX2, radeon_cp_vertex2_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_CMDBUF, radeon_cp_cmdbuf_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_GETPARAM, radeon_cp_getparam_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_FLIP, radeon_cp_flip_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_ALLOC, radeon_mem_alloc_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_FREE, radeon_mem_free_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_INIT_HEAP, radeon_mem_init_heap_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF_DRV(RADEON_IRQ_EMIT, radeon_irq_emit_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_IRQ_WAIT, radeon_irq_wait_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_SETPARAM, radeon_cp_setparam_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_SURF_ALLOC, radeon_surface_alloc_kms, DRM_AUTH), - DRM_IOCTL_DEF_DRV(RADEON_SURF_FREE, radeon_surface_free_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CP_INIT, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_START, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_STOP, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_RESET, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_IDLE, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CP_RESUME, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_RESET, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_FULLSCREEN, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SWAP, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CLEAR, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_VERTEX, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_INDICES, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_TEXTURE, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_STIPPLE, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_INDIRECT, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_VERTEX2, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CMDBUF, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_GETPARAM, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_FLIP, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_ALLOC, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_FREE, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_INIT_HEAP, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_IRQ_EMIT, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_IRQ_WAIT, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SETPARAM, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SURF_ALLOC, drm_invalid_op, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SURF_FREE, drm_invalid_op, DRM_AUTH), /* KMS */ - DRM_IOCTL_DEF_DRV(RADEON_GEM_INFO, radeon_gem_info_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_GEM_CREATE, radeon_gem_create_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_GEM_MMAP, radeon_gem_mmap_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_GEM_SET_DOMAIN, radeon_gem_set_domain_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_GEM_PREAD, radeon_gem_pread_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(RADEON_GEM_PWRITE, radeon_gem_pwrite_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(RADEON_GEM_WAIT_IDLE, radeon_gem_wait_idle_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_CS, radeon_cs_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_INFO, radeon_info_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_GEM_SET_TILING, radeon_gem_set_tiling_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_GEM_GET_TILING, radeon_gem_get_tiling_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_GEM_BUSY, radeon_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_GEM_VA, radeon_gem_va_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(RADEON_GEM_OP, radeon_gem_op_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_INFO, radeon_gem_info_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_CREATE, radeon_gem_create_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_MMAP, radeon_gem_mmap_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_SET_DOMAIN, radeon_gem_set_domain_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_PREAD, radeon_gem_pread_ioctl, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_GEM_PWRITE, radeon_gem_pwrite_ioctl, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_GEM_WAIT_IDLE, radeon_gem_wait_idle_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_CS, radeon_cs_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_INFO, radeon_info_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_SET_TILING, radeon_gem_set_tiling_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_GET_TILING, radeon_gem_get_tiling_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_BUSY, radeon_gem_busy_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_VA, radeon_gem_va_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_OP, radeon_gem_op_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), +#if 0 + DRM_IOCTL_DEF_DRV(RADEON_GEM_USERPTR, radeon_gem_userptr_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), +#endif }; int radeon_max_kms_ioctl = ARRAY_SIZE(radeon_ioctls_kms); diff --git a/sys/dev/drm/radeon/radeon_legacy_crtc.c b/sys/dev/drm/radeon/radeon_legacy_crtc.c index d647941c99..3c31f6a2ab 100644 --- a/sys/dev/drm/radeon/radeon_legacy_crtc.c +++ b/sys/dev/drm/radeon/radeon_legacy_crtc.c @@ -331,13 +331,15 @@ static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) RADEON_CRTC_DISP_REQ_EN_B)); WREG32_P(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl, ~(mask | crtc_ext_cntl)); } - drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); + if (dev->num_crtcs > radeon_crtc->crtc_id) + drm_vblank_on(dev, radeon_crtc->crtc_id); radeon_crtc_load_lut(crtc); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); + if (dev->num_crtcs > radeon_crtc->crtc_id) + drm_vblank_off(dev, radeon_crtc->crtc_id); if (radeon_crtc->crtc_id) WREG32_P(RADEON_CRTC2_GEN_CNTL, mask, ~(RADEON_CRTC2_EN | mask)); else { @@ -1055,6 +1057,7 @@ static int radeon_crtc_mode_set(struct drm_crtc *crtc, DRM_ERROR("Mode need scaling but only first crtc can do that.\n"); } } + radeon_cursor_reset(crtc); return 0; } diff --git a/sys/dev/drm/radeon/radeon_legacy_encoders.c b/sys/dev/drm/radeon/radeon_legacy_encoders.c index 45bade6a2c..d4b6d3f0f5 100644 --- a/sys/dev/drm/radeon/radeon_legacy_encoders.c +++ b/sys/dev/drm/radeon/radeon_legacy_encoders.c @@ -440,6 +440,7 @@ void radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder, backlight_update_status(bd); DRM_INFO("radeon legacy LVDS backlight initialized\n"); + rdev->mode_info.bl_encoder = radeon_encoder; return; diff --git a/sys/dev/drm/radeon/radeon_mode.h b/sys/dev/drm/radeon/radeon_mode.h index 9ce08f42b6..94a9f2d00a 100644 --- a/sys/dev/drm/radeon/radeon_mode.h +++ b/sys/dev/drm/radeon/radeon_mode.h @@ -35,6 +35,9 @@ #include #include #include +#include +#include + struct radeon_bo; struct radeon_device; @@ -83,6 +86,13 @@ enum radeon_hpd_id { RADEON_HPD_NONE = 0xff, }; +enum radeon_output_csc { + RADEON_OUTPUT_CSC_BYPASS = 0, + RADEON_OUTPUT_CSC_TVRGB = 1, + RADEON_OUTPUT_CSC_YCBCR601 = 2, + RADEON_OUTPUT_CSC_YCBCR709 = 3, +}; + #define RADEON_MAX_I2C_BUS 16 /* radeon gpio-based i2c @@ -187,13 +197,16 @@ struct radeon_pll { }; struct radeon_i2c_chan { - device_t adapter; - device_t iic_bus; + struct i2c_adapter adapter; struct drm_device *dev; + struct i2c_algo_bit_data bit; struct radeon_i2c_bus_rec rec; struct drm_dp_aux aux; + bool has_aux; struct lock mutex; char name[48]; + device_t iic_bus; + device_t adapter_dev; }; /* mostly for macs, but really any system without connector tables */ @@ -227,7 +240,6 @@ struct radeon_afmt { int offset; bool last_buffer_filled_status; int id; - struct r600_audio_pin *pin; }; struct radeon_mode_info { @@ -253,6 +265,8 @@ struct radeon_mode_info { struct drm_property *audio_property; /* FMT dithering */ struct drm_property *dither_property; + /* Output CSC */ + struct drm_property *output_csc_property; /* hardcoded DFP edid from BIOS */ struct edid *bios_hardcoded_edid; int bios_hardcoded_edid_size; @@ -263,6 +277,9 @@ struct radeon_mode_info { u16 firmware_flags; /* pointer to backlight encoder */ struct radeon_encoder *bl_encoder; + + /* bitmask for active encoder frontends */ + uint32_t active_encoders; }; #define RADEON_MAX_BL_LEVEL 0xFF @@ -319,12 +336,15 @@ struct radeon_crtc { uint32_t crtc_offset; struct drm_gem_object *cursor_bo; uint64_t cursor_addr; + int cursor_x; + int cursor_y; + int cursor_hot_x; + int cursor_hot_y; int cursor_width; int cursor_height; int max_cursor_width; int max_cursor_height; uint32_t legacy_display_base_addr; - uint32_t legacy_cursor_offset; enum radeon_rmx_type rmx_type; u8 h_border; u8 v_border; @@ -350,7 +370,9 @@ struct radeon_crtc { u32 line_time; u32 wm_low; u32 wm_high; + u32 lb_vblank_lead_lines; struct drm_display_mode hw_mode; + enum radeon_output_csc output_csc; }; struct radeon_encoder_primary_dac { @@ -420,6 +442,7 @@ struct radeon_encoder_atom_dig { uint8_t backlight_level; int panel_mode; struct radeon_afmt *afmt; + struct r600_audio_pin *pin; }; struct radeon_encoder_atom_dac { @@ -443,12 +466,13 @@ struct radeon_encoder { int audio_polling_active; bool is_ext_encoder; u16 caps; + struct radeon_audio_funcs *audio; + enum radeon_output_csc output_csc; }; struct radeon_connector_atom_dig { uint32_t igp_lane_info; /* displayport */ - struct radeon_i2c_chan *dp_i2c_bus; u8 dpcd[DP_RECEIVER_CAP_SIZE]; u8 dp_sink_type; int dp_clock; @@ -461,6 +485,7 @@ struct radeon_gpio_rec { u8 id; u32 reg; u32 mask; + u32 shift; }; struct radeon_hpd { @@ -704,19 +729,28 @@ extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector); extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector); extern int radeon_dp_get_panel_mode(struct drm_encoder *encoder, struct drm_connector *connector); +extern int radeon_dp_get_dp_link_config(struct drm_connector *connector, + const u8 *dpcd, + unsigned pix_clock, + unsigned *dp_lanes, unsigned *dp_rate); extern void radeon_dp_set_rx_power_state(struct drm_connector *connector, u8 power_state); extern void radeon_dp_aux_init(struct radeon_connector *radeon_connector); +extern ssize_t +radeon_dp_aux_transfer_native(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg); + extern void atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode); +extern void atombios_dig_encoder_setup2(struct drm_encoder *encoder, int action, int panel_mode, int enc_override); extern void radeon_atom_encoder_init(struct radeon_device *rdev); extern void radeon_atom_disp_eng_pll_init(struct radeon_device *rdev); extern void atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set); +extern void atombios_dig_transmitter_setup2(struct drm_encoder *encoder, + int action, uint8_t lane_num, + uint8_t lane_set, int fe); extern void radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder); extern struct drm_encoder *radeon_get_external_encoder(struct drm_encoder *encoder); -extern int radeon_dp_i2c_aux_ch(device_t dev, int mode, - u8 write_byte, u8 *read_byte); void radeon_atom_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le); extern void radeon_i2c_init(struct radeon_device *rdev); @@ -728,9 +762,6 @@ extern void radeon_i2c_add(struct radeon_device *rdev, const char *name); extern struct radeon_i2c_chan *radeon_i2c_lookup(struct radeon_device *rdev, struct radeon_i2c_bus_rec *i2c_bus); -extern struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, - struct radeon_i2c_bus_rec *rec, - const char *name); extern struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, struct radeon_i2c_bus_rec *rec, const char *name); @@ -753,6 +784,8 @@ extern bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev, extern bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev, struct radeon_atom_ss *ss, int id, u32 clock); +extern struct radeon_gpio_rec radeon_atombios_lookup_gpio(struct radeon_device *rdev, + u8 id); extern void radeon_compute_pll_legacy(struct radeon_pll *pll, uint64_t freq, @@ -807,17 +840,19 @@ extern int radeon_crtc_set_base_atomic(struct drm_crtc *crtc, extern int radeon_crtc_do_set_base(struct drm_crtc *crtc, struct drm_framebuffer *fb, int x, int y, int atomic); -extern int radeon_crtc_cursor_set(struct drm_crtc *crtc, - struct drm_file *file_priv, - uint32_t handle, - uint32_t width, - uint32_t height); +extern int radeon_crtc_cursor_set2(struct drm_crtc *crtc, + struct drm_file *file_priv, + uint32_t handle, + uint32_t width, + uint32_t height, + int32_t hot_x, + int32_t hot_y); extern int radeon_crtc_cursor_move(struct drm_crtc *crtc, int x, int y); +extern void radeon_cursor_reset(struct drm_crtc *crtc); -extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, - unsigned int flags, - int *vpos, int *hpos, +extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, + unsigned int flags, int *vpos, int *hpos, ktime_t *stime, ktime_t *etime, const struct drm_display_mode *mode); @@ -927,7 +962,14 @@ void radeon_fbdev_restore_mode(struct radeon_device *rdev); void radeon_fb_output_poll_changed(struct radeon_device *rdev); void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id); + +void radeon_fb_add_connector(struct radeon_device *rdev, struct drm_connector *connector); +void radeon_fb_remove_connector(struct radeon_device *rdev, struct drm_connector *connector); + void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id); int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled); + +int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx); +void radeon_atom_release_dig_encoder(struct radeon_device *rdev, int enc_idx); #endif diff --git a/sys/dev/drm/radeon/radeon_object.c b/sys/dev/drm/radeon/radeon_object.c index 3b0e80f2d2..3afd3d6b65 100644 --- a/sys/dev/drm/radeon/radeon_object.c +++ b/sys/dev/drm/radeon/radeon_object.c @@ -97,22 +97,39 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain) rbo->placement.placement = rbo->placements; rbo->placement.busy_placement = rbo->placements; - if (domain & RADEON_GEM_DOMAIN_VRAM) + if (domain & RADEON_GEM_DOMAIN_VRAM) { + /* Try placing BOs which don't need CPU access outside of the + * CPU accessible part of VRAM + */ + if ((rbo->flags & RADEON_GEM_NO_CPU_ACCESS) && + rbo->rdev->mc.visible_vram_size < rbo->rdev->mc.real_vram_size) { + rbo->placements[c].fpfn = + rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT; + rbo->placements[c++].flags = TTM_PL_FLAG_WC | + TTM_PL_FLAG_UNCACHED | + TTM_PL_FLAG_VRAM; + } + + rbo->placements[c].fpfn = 0; rbo->placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM; + } if (domain & RADEON_GEM_DOMAIN_GTT) { if (rbo->flags & RADEON_GEM_GTT_UC) { + rbo->placements[c].fpfn = 0; rbo->placements[c++].flags = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_TT; } else if ((rbo->flags & RADEON_GEM_GTT_WC) || (rbo->rdev->flags & RADEON_IS_AGP)) { + rbo->placements[c].fpfn = 0; rbo->placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_TT; } else { + rbo->placements[c].fpfn = 0; rbo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_TT; } @@ -120,36 +137,42 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain) if (domain & RADEON_GEM_DOMAIN_CPU) { if (rbo->flags & RADEON_GEM_GTT_UC) { + rbo->placements[c].fpfn = 0; rbo->placements[c++].flags = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_SYSTEM; } else if ((rbo->flags & RADEON_GEM_GTT_WC) || rbo->rdev->flags & RADEON_IS_AGP) { + rbo->placements[c].fpfn = 0; rbo->placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_SYSTEM; } else { + rbo->placements[c].fpfn = 0; rbo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM; } } - if (!c) - rbo->placements[c++].flags = TTM_PL_MASK_CACHING | - TTM_PL_FLAG_SYSTEM; + if (!c) { + rbo->placements[c].fpfn = 0; + rbo->placements[c++].flags = TTM_PL_MASK_CACHING | + TTM_PL_FLAG_SYSTEM; + } rbo->placement.num_placement = c; rbo->placement.num_busy_placement = c; for (i = 0; i < c; ++i) { - rbo->placements[i].fpfn = 0; if ((rbo->flags & RADEON_GEM_CPU_ACCESS) && - (rbo->placements[i].flags & TTM_PL_FLAG_VRAM)) + (rbo->placements[i].flags & TTM_PL_FLAG_VRAM) && + !rbo->placements[i].fpfn) rbo->placements[i].lpfn = rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT; else rbo->placements[i].lpfn = 0; } +#if 0 /* * Use two-ended allocation depending on the buffer size to * improve fragmentation quality. @@ -162,6 +185,7 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain) rbo->placements[i].flags |= TTM_PL_FLAG_TOPDOWN; } } +#endif } int radeon_bo_create(struct radeon_device *rdev, @@ -209,12 +233,40 @@ int radeon_bo_create(struct radeon_device *rdev, if (!(rdev->flags & RADEON_IS_PCIE)) bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC); + /* Write-combined CPU mappings of GTT cause GPU hangs with RV6xx + * See https://bugs.freedesktop.org/show_bug.cgi?id=91268 + */ + if (rdev->family >= CHIP_RV610 && rdev->family <= CHIP_RV635) + bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC); + +/* DragonFly only supported on __x86_64__ and supports PAT */ +#if !defined (__DragonFly__) #ifdef CONFIG_X86_32 /* XXX: Write-combined CPU mappings of GTT seem broken on 32-bit * See https://bugs.freedesktop.org/show_bug.cgi?id=84627 */ - bo->flags &= ~RADEON_GEM_GTT_WC; + bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC); +#elif defined(CONFIG_X86) && !defined(CONFIG_X86_PAT) + /* Don't try to enable write-combining when it can't work, or things + * may be slow + * See https://bugs.freedesktop.org/show_bug.cgi?id=88758 + */ + +#warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance \ + thanks to write-combining + + if (bo->flags & RADEON_GEM_GTT_WC) + DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for " + "better performance thanks to write-combining\n"); + bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC); +#else + /* For architectures that don't support WC memory, + * mask out the WC flag from the BO + */ + if (!drm_arch_can_wc_memory()) + bo->flags &= ~RADEON_GEM_GTT_WC; #endif +#endif /* __DragonFly__*/ radeon_ttm_placement_from_domain(bo, domain); /* Kernel allocation are uninterruptible */ @@ -407,7 +459,7 @@ void radeon_bo_force_delete(struct radeon_device *rdev) list_del_init(&bo->list); mutex_unlock(&bo->rdev->gem.mutex); /* this should unref the ttm bo */ - drm_gem_object_unreference(&bo->gem_base); + drm_gem_object_unreference_unlocked(&bo->gem_base); } } @@ -488,7 +540,7 @@ int radeon_bo_list_validate(struct radeon_device *rdev, struct ww_acquire_ctx *ticket, struct list_head *head, int ring) { - struct radeon_cs_reloc *lobj; + struct radeon_bo_list *lobj; struct radeon_bo *bo; int r; u64 bytes_moved = 0, initial_bytes_moved; @@ -538,6 +590,7 @@ int radeon_bo_list_validate(struct radeon_device *rdev, domain = lobj->allowed_domains; goto retry; } + ttm_eu_backoff_reservation(ticket, head); return r; } } @@ -743,8 +796,8 @@ int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo) { struct radeon_device *rdev; struct radeon_bo *rbo; - unsigned long offset, size; - int r; + unsigned long offset, size, lpfn; + int i, r; if (!radeon_ttm_bo_is_radeon_bo(bo)) return 0; @@ -759,9 +812,19 @@ int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo) if ((offset + size) <= rdev->mc.visible_vram_size) return 0; + /* Can't move a pinned BO to visible VRAM */ + if (rbo->pin_count > 0) + return -EINVAL; + /* hurrah the memory is not visible ! */ radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_VRAM); - rbo->placements[0].lpfn = rdev->mc.visible_vram_size >> PAGE_SHIFT; + lpfn = rdev->mc.visible_vram_size >> PAGE_SHIFT; + for (i = 0; i < rbo->placement.num_placement; i++) { + /* Force into visible VRAM */ + if ((rbo->placements[i].flags & TTM_PL_FLAG_VRAM) && + (!rbo->placements[i].lpfn || rbo->placements[i].lpfn > lpfn)) + rbo->placements[i].lpfn = lpfn; + } r = ttm_bo_validate(bo, &rbo->placement, false, false); if (unlikely(r == -ENOMEM)) { radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_GTT); @@ -794,26 +857,3 @@ int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type, bool no_wait) ttm_bo_unreserve(&bo->tbo); return r; } - - -/** - * radeon_bo_reserve - reserve bo - * @bo: bo structure - * @no_intr: don't return -ERESTARTSYS on pending signal - * - * Returns: - * -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by - * a signal. Release all buffer reservations and return to user-space. - */ -int radeon_bo_reserve(struct radeon_bo *bo, bool no_intr) -{ - int r; - - r = ttm_bo_reserve(&bo->tbo, !no_intr, false, false, 0); - if (unlikely(r != 0)) { - if (r != -ERESTARTSYS) - dev_err(bo->rdev->dev, "%p reserve failed\n", bo); - return r; - } - return 0; -} diff --git a/sys/dev/drm/radeon/radeon_object.h b/sys/dev/drm/radeon/radeon_object.h index 62d586a7d2..ab368c63bd 100644 --- a/sys/dev/drm/radeon/radeon_object.h +++ b/sys/dev/drm/radeon/radeon_object.h @@ -59,7 +59,27 @@ static inline unsigned radeon_mem_type_to_domain(u32 mem_type) return 0; } -int radeon_bo_reserve(struct radeon_bo *bo, bool no_intr); +/** + * radeon_bo_reserve - reserve bo + * @bo: bo structure + * @no_intr: don't return -ERESTARTSYS on pending signal + * + * Returns: + * -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by + * a signal. Release all buffer reservations and return to user-space. + */ +static inline int radeon_bo_reserve(struct radeon_bo *bo, bool no_intr) +{ + int r; + + r = ttm_bo_reserve(&bo->tbo, !no_intr, false, false, 0); + if (unlikely(r != 0)) { + if (r != -ERESTARTSYS) + dev_err(bo->rdev->dev, "%p reserve failed\n", bo); + return r; + } + return 0; +} static inline void radeon_bo_unreserve(struct radeon_bo *bo) { diff --git a/sys/dev/drm/radeon/radeon_pm.c b/sys/dev/drm/radeon/radeon_pm.c index 6b8bf49317..7a98730b54 100644 --- a/sys/dev/drm/radeon/radeon_pm.c +++ b/sys/dev/drm/radeon/radeon_pm.c @@ -29,6 +29,7 @@ #include "radeon.h" #include "avivod.h" #include "atom.h" +#include "r600_dpm.h" #define RADEON_IDLE_LOOP_MS 100 #define RADEON_RECLOCK_DELAY_MS 200 @@ -42,9 +43,11 @@ static const char *radeon_pm_state_type_name[5] = { "Performance", }; -#ifdef DUMBBELL_WIP +#define DUMBBELL_PM 1 + +#ifdef DUMBBELL_PM static void radeon_dynpm_idle_work_handler(struct work_struct *work); -#endif /* DUMBBELL_WIP */ +#endif /* DUMBBELL_PM */ static int radeon_debugfs_pm_init(struct radeon_device *rdev); static bool radeon_pm_in_vbl(struct radeon_device *rdev); static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); @@ -72,7 +75,7 @@ int radeon_pm_get_type_index(struct radeon_device *rdev, void radeon_pm_acpi_event_handler(struct radeon_device *rdev) { if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { - lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE); + mutex_lock(&rdev->pm.mutex); if (power_profile_get_state() == POWER_PROFILE_PERFORMANCE) rdev->pm.dpm.ac_power = true; else @@ -81,13 +84,13 @@ void radeon_pm_acpi_event_handler(struct radeon_device *rdev) if (rdev->asic->dpm.enable_bapm) radeon_dpm_enable_bapm(rdev, rdev->pm.dpm.ac_power); } - lockmgr(&rdev->pm.mutex, LK_RELEASE); + mutex_unlock(&rdev->pm.mutex); } else if (rdev->pm.pm_method == PM_METHOD_PROFILE) { if (rdev->pm.profile == PM_PROFILE_AUTO) { - lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE); + mutex_lock(&rdev->pm.mutex); radeon_pm_update_profile(rdev); radeon_pm_set_clocks(rdev); - lockmgr(&rdev->pm.mutex, LK_RELEASE); + mutex_unlock(&rdev->pm.mutex); } } } @@ -161,11 +164,11 @@ static void radeon_sync_with_vblank(struct radeon_device *rdev) { if (rdev->pm.active_crtcs) { rdev->pm.vblank_sync = false; -#ifdef DUMBBELL_WIP +#ifdef DUMBBELL_PM wait_event_timeout( rdev->irq.vblank_queue, rdev->pm.vblank_sync, msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT)); -#endif /* DUMBBELL_WIP */ +#endif /* DUMBBELL_PM */ } } @@ -258,9 +261,8 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index)) return; - DRM_LOCK(rdev->ddev); lockmgr(&rdev->pm.mclk_lock, LK_EXCLUSIVE); // down_write - lockmgr(&rdev->ring_lock, LK_EXCLUSIVE); + mutex_lock(&rdev->ring_lock); /* wait for the rings to drain */ for (i = 0; i < RADEON_NUM_RINGS; i++) { @@ -271,9 +273,8 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) r = radeon_fence_wait_empty(rdev, i); if (r) { /* needs a GPU reset dont reset here */ - lockmgr(&rdev->ring_lock, LK_RELEASE); + mutex_unlock(&rdev->ring_lock); lockmgr(&rdev->pm.mclk_lock, LK_RELEASE); // up_write - DRM_UNLOCK(rdev->ddev); return; } } @@ -283,8 +284,13 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) if (rdev->irq.installed) { for (i = 0; i < rdev->num_crtc; i++) { if (rdev->pm.active_crtcs & (1 << i)) { - rdev->pm.req_vblank |= (1 << i); - drm_vblank_get(rdev->ddev, i); + /* This can fail if a modeset is in progress */ + if (drm_vblank_get(rdev->ddev, i) == 0) + rdev->pm.req_vblank |= (1 << i); + else + DRM_DEBUG_DRIVER("crtc %d no vblank, can glitch\n", + i); + } } } @@ -307,9 +313,8 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; - lockmgr(&rdev->ring_lock, LK_RELEASE); + mutex_unlock(&rdev->ring_lock); lockmgr(&rdev->pm.mclk_lock, LK_RELEASE); // up_write - DRM_UNLOCK(rdev->ddev); } static void radeon_pm_print_states(struct radeon_device *rdev) @@ -375,7 +380,7 @@ static ssize_t radeon_set_pm_profile(struct device *dev, (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) return -EINVAL; - lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE); + mutex_lock(&rdev->pm.mutex); if (rdev->pm.pm_method == PM_METHOD_PROFILE) { if (strncmp("default", buf, strlen("default")) == 0) rdev->pm.profile = PM_PROFILE_DEFAULT; @@ -397,7 +402,7 @@ static ssize_t radeon_set_pm_profile(struct device *dev, count = -EINVAL; fail: - lockmgr(&rdev->pm.mutex, LK_RELEASE); + mutex_unlock(&rdev->pm.mutex); return count; } @@ -437,21 +442,21 @@ static ssize_t radeon_set_pm_method(struct device *dev, } if (strncmp("dynpm", buf, strlen("dynpm")) == 0) { - lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE); + mutex_lock(&rdev->pm.mutex); rdev->pm.pm_method = PM_METHOD_DYNPM; rdev->pm.dynpm_state = DYNPM_STATE_PAUSED; rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT; - lockmgr(&rdev->pm.mutex, LK_RELEASE); + mutex_unlock(&rdev->pm.mutex); } else if (strncmp("profile", buf, strlen("profile")) == 0) { - lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE); + mutex_lock(&rdev->pm.mutex); /* disable dynpm */ rdev->pm.dynpm_state = DYNPM_STATE_DISABLED; rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; rdev->pm.pm_method = PM_METHOD_PROFILE; - lockmgr(&rdev->pm.mutex, LK_RELEASE); -#ifdef DUMBBELL_WIP + mutex_unlock(&rdev->pm.mutex); +#ifdef DUMBBELL_PM cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); -#endif /* DUMBBELL_WIP */ +#endif /* DUMBBELL_PM */ } else { count = -EINVAL; goto fail; @@ -482,7 +487,7 @@ static ssize_t radeon_set_dpm_state(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct radeon_device *rdev = ddev->dev_private; - lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE); + mutex_lock(&rdev->pm.mutex); if (strncmp("battery", buf, strlen("battery")) == 0) rdev->pm.dpm.user_state = POWER_STATE_TYPE_BATTERY; else if (strncmp("balanced", buf, strlen("balanced")) == 0) @@ -490,11 +495,11 @@ static ssize_t radeon_set_dpm_state(struct device *dev, else if (strncmp("performance", buf, strlen("performance")) == 0) rdev->pm.dpm.user_state = POWER_STATE_TYPE_PERFORMANCE; else { - lockmgr(&rdev->pm.mutex, LK_RELEASE); + mutex_unlock(&rdev->pm.mutex); count = -EINVAL; goto fail; } - lockmgr(&rdev->pm.mutex, LK_RELEASE); + mutex_unlock(&rdev->pm.mutex); /* Can't set dpm state when the card is off */ if (!(rdev->flags & RADEON_IS_PX) || @@ -537,7 +542,7 @@ static ssize_t radeon_set_dpm_forced_performance_level(struct device *dev, (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) return -EINVAL; - spin_lock(&rdev->pm.mutex); + mutex_lock(&rdev->pm.mutex); if (strncmp("low", buf, strlen("low")) == 0) { level = RADEON_DPM_FORCED_LEVEL_LOW; } else if (strncmp("high", buf, strlen("high")) == 0) { @@ -558,11 +563,105 @@ static ssize_t radeon_set_dpm_forced_performance_level(struct device *dev, count = -EINVAL; } fail: - spin_unlock(&rdev->pm.mutex); + mutex_unlock(&rdev->pm.mutex); + + return count; +} + +static ssize_t radeon_hwmon_get_pwm1_enable(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct radeon_device *rdev = dev_get_drvdata(dev); + u32 pwm_mode = 0; + + if (rdev->asic->dpm.fan_ctrl_get_mode) + pwm_mode = rdev->asic->dpm.fan_ctrl_get_mode(rdev); + + /* never 0 (full-speed), fuse or smc-controlled always */ + return sprintf(buf, "%i\n", pwm_mode == FDO_PWM_MODE_STATIC ? 1 : 2); +} + +static ssize_t radeon_hwmon_set_pwm1_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct radeon_device *rdev = dev_get_drvdata(dev); + int err; + int value; + + if(!rdev->asic->dpm.fan_ctrl_set_mode) + return -EINVAL; + + err = kstrtoint(buf, 10, &value); + if (err) + return err; + + switch (value) { + case 1: /* manual, percent-based */ + rdev->asic->dpm.fan_ctrl_set_mode(rdev, FDO_PWM_MODE_STATIC); + break; + default: /* disable */ + rdev->asic->dpm.fan_ctrl_set_mode(rdev, 0); + break; + } + + return count; +} + +static ssize_t radeon_hwmon_get_pwm1_min(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%i\n", 0); +} + +static ssize_t radeon_hwmon_get_pwm1_max(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%i\n", 255); +} + +static ssize_t radeon_hwmon_set_pwm1(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct radeon_device *rdev = dev_get_drvdata(dev); + int err; + u32 value; + + err = kstrtou32(buf, 10, &value); + if (err) + return err; + + value = (value * 100) / 255; + + err = rdev->asic->dpm.set_fan_speed_percent(rdev, value); + if (err) + return err; return count; } +static ssize_t radeon_hwmon_get_pwm1(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct radeon_device *rdev = dev_get_drvdata(dev); + int err; + u32 speed; + + err = rdev->asic->dpm.get_fan_speed_percent(rdev, &speed); + if (err) + return err; + + speed = (speed * 255) / 100; + + return sprintf(buf, "%i\n", speed); +} + static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile); static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method); static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, radeon_get_dpm_state, radeon_set_dpm_state); @@ -610,11 +709,19 @@ static ssize_t radeon_hwmon_show_temp_thresh(struct device *dev, static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, radeon_hwmon_show_temp, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 1); +static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, radeon_hwmon_get_pwm1, radeon_hwmon_set_pwm1, 0); +static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, radeon_hwmon_get_pwm1_enable, radeon_hwmon_set_pwm1_enable, 0); +static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO, radeon_hwmon_get_pwm1_min, NULL, 0); +static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO, radeon_hwmon_get_pwm1_max, NULL, 0); static struct attribute *hwmon_attributes[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_crit.dev_attr.attr, &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm1_enable.dev_attr.attr, + &sensor_dev_attr_pwm1_min.dev_attr.attr, + &sensor_dev_attr_pwm1_max.dev_attr.attr, NULL }; @@ -623,14 +730,47 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, { struct device *dev = container_of(kobj, struct device, kobj); struct radeon_device *rdev = dev_get_drvdata(dev); + umode_t effective_mode = attr->mode; - /* Skip limit attributes if DPM is not enabled */ + /* Skip attributes if DPM is not enabled */ if (rdev->pm.pm_method != PM_METHOD_DPM && (attr == &sensor_dev_attr_temp1_crit.dev_attr.attr || - attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr)) + attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr || + attr == &sensor_dev_attr_pwm1.dev_attr.attr || + attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr || + attr == &sensor_dev_attr_pwm1_max.dev_attr.attr || + attr == &sensor_dev_attr_pwm1_min.dev_attr.attr)) return 0; - return attr->mode; + /* Skip fan attributes if fan is not present */ + if (rdev->pm.no_fan && + (attr == &sensor_dev_attr_pwm1.dev_attr.attr || + attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr || + attr == &sensor_dev_attr_pwm1_max.dev_attr.attr || + attr == &sensor_dev_attr_pwm1_min.dev_attr.attr)) + return 0; + + /* mask fan attributes if we have no bindings for this asic to expose */ + if ((!rdev->asic->dpm.get_fan_speed_percent && + attr == &sensor_dev_attr_pwm1.dev_attr.attr) || /* can't query fan */ + (!rdev->asic->dpm.fan_ctrl_get_mode && + attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't query state */ + effective_mode &= ~S_IRUGO; + + if ((!rdev->asic->dpm.set_fan_speed_percent && + attr == &sensor_dev_attr_pwm1.dev_attr.attr) || /* can't manage fan */ + (!rdev->asic->dpm.fan_ctrl_set_mode && + attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't manage state */ + effective_mode &= ~S_IWUSR; + + /* hide max/min values if we can't both query and manage the fan */ + if ((!rdev->asic->dpm.set_fan_speed_percent && + !rdev->asic->dpm.get_fan_speed_percent) && + (attr == &sensor_dev_attr_pwm1_max.dev_attr.attr || + attr == &sensor_dev_attr_pwm1_min.dev_attr.attr)) + return 0; + + return effective_mode; } static const struct attribute_group hwmon_attrgroup = { @@ -760,12 +900,8 @@ static void radeon_dpm_thermal_work_handler(void *arg, int pending) radeon_pm_compute_clocks(rdev); } -static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev, - enum radeon_pm_state_type dpm_state) +static bool radeon_dpm_single_display(struct radeon_device *rdev) { - int i; - struct radeon_ps *ps; - u32 ui_class; bool single_display = (rdev->pm.dpm.new_active_crtc_count < 2) ? true : false; @@ -775,6 +911,23 @@ static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev, single_display = false; } + /* 120hz tends to be problematic even if they are under the + * vblank limit. + */ + if (single_display && (r600_dpm_get_vrefresh(rdev) >= 120)) + single_display = false; + + return single_display; +} + +static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev, + enum radeon_pm_state_type dpm_state) +{ + int i; + struct radeon_ps *ps; + u32 ui_class; + bool single_display = radeon_dpm_single_display(rdev); + /* certain older asics have a separare 3D performance state, * so try that first if the user selected performance */ @@ -900,6 +1053,7 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev) struct radeon_ps *ps; enum radeon_pm_state_type dpm_state; int ret; + bool single_display = radeon_dpm_single_display(rdev); /* if dpm init failed */ if (!rdev->pm.dpm_enabled) @@ -924,6 +1078,9 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev) /* vce just modifies an existing state so force a change */ if (ps->vce_active != rdev->pm.dpm.vce_active) goto force; + /* user has made a display change (such as timing) */ + if (rdev->pm.dpm.single_display != single_display) + goto force; if ((rdev->family < CHIP_BARTS) || (rdev->flags & RADEON_IS_IGP)) { /* for pre-BTC and APUs if the num crtcs changed but state is the same, * all we need to do is update the display configuration. @@ -968,9 +1125,8 @@ force: radeon_dpm_print_power_state(rdev, rdev->pm.dpm.requested_ps); } - lockmgr(&rdev->ddev->struct_mutex, LK_EXCLUSIVE); lockmgr(&rdev->pm.mclk_lock, LK_EXCLUSIVE); // down_write - lockmgr(&rdev->ring_lock, LK_EXCLUSIVE); + mutex_lock(&rdev->ring_lock); /* update whether vce is active */ ps->vce_active = rdev->pm.dpm.vce_active; @@ -984,9 +1140,6 @@ force: /* update displays */ radeon_dpm_display_configuration_changed(rdev); - rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs; - rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count; - /* wait for the rings to drain */ for (i = 0; i < RADEON_NUM_RINGS; i++) { struct radeon_ring *ring = &rdev->ring[i]; @@ -1002,6 +1155,10 @@ force: radeon_dpm_post_set_power_state(rdev); + rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs; + rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count; + rdev->pm.dpm.single_display = single_display; + if (rdev->asic->dpm.force_performance_level) { if (rdev->pm.dpm.thermal_active) { enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level; @@ -1016,9 +1173,8 @@ force: } done: - lockmgr(&rdev->ring_lock, LK_RELEASE); + mutex_unlock(&rdev->ring_lock); lockmgr(&rdev->pm.mclk_lock, LK_RELEASE); // up_write - lockmgr(&rdev->ddev->struct_mutex, LK_RELEASE); } void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable) @@ -1082,27 +1238,27 @@ void radeon_dpm_enable_vce(struct radeon_device *rdev, bool enable) static void radeon_pm_suspend_old(struct radeon_device *rdev) { - lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE); + mutex_lock(&rdev->pm.mutex); if (rdev->pm.pm_method == PM_METHOD_DYNPM) { if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) rdev->pm.dynpm_state = DYNPM_STATE_SUSPENDED; } - lockmgr(&rdev->pm.mutex, LK_RELEASE); + mutex_unlock(&rdev->pm.mutex); -#ifdef DUMBBELL_WIP +#ifdef DUMBBELL_PM cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); -#endif /* DUMBBELL_WIP */ +#endif /* DUMBBELL_PM */ } static void radeon_pm_suspend_dpm(struct radeon_device *rdev) { - lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE); + mutex_lock(&rdev->pm.mutex); /* disable dpm */ radeon_dpm_disable(rdev); /* reset the power state */ rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps; rdev->pm.dpm_enabled = false; - lockmgr(&rdev->pm.mutex, LK_RELEASE); + mutex_unlock(&rdev->pm.mutex); } void radeon_pm_suspend(struct radeon_device *rdev) @@ -1131,7 +1287,7 @@ static void radeon_pm_resume_old(struct radeon_device *rdev) radeon_set_memory_clock(rdev, rdev->pm.default_mclk); } /* asic init will reset the default power state */ - lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE); + mutex_lock(&rdev->pm.mutex); rdev->pm.current_power_state_index = rdev->pm.default_power_state_index; rdev->pm.current_clock_mode_index = 0; rdev->pm.current_sclk = rdev->pm.default_sclk; @@ -1143,12 +1299,12 @@ static void radeon_pm_resume_old(struct radeon_device *rdev) if (rdev->pm.pm_method == PM_METHOD_DYNPM && rdev->pm.dynpm_state == DYNPM_STATE_SUSPENDED) { rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; -#ifdef DUMBBELL_WIP +#ifdef DUMBBELL_PM schedule_delayed_work(&rdev->pm.dynpm_idle_work, msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); -#endif /* DUMBBELL_WIP */ +#endif /* DUMBBELL_PM */ } - lockmgr(&rdev->pm.mutex, LK_RELEASE); + mutex_unlock(&rdev->pm.mutex); radeon_pm_compute_clocks(rdev); } @@ -1157,11 +1313,11 @@ static void radeon_pm_resume_dpm(struct radeon_device *rdev) int ret; /* asic init will reset to the boot state */ - lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE); + mutex_lock(&rdev->pm.mutex); rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps; radeon_dpm_setup_asic(rdev); ret = radeon_dpm_enable(rdev); - lockmgr(&rdev->pm.mutex, LK_RELEASE); + mutex_unlock(&rdev->pm.mutex); if (ret) goto dpm_resume_fail; rdev->pm.dpm_enabled = true; @@ -1237,23 +1393,11 @@ static int radeon_pm_init_old(struct radeon_device *rdev) if (ret) return ret; -#ifdef DUMBBELL_WIP +#ifdef DUMBBELL_PM INIT_DELAYED_WORK(&rdev->pm.dynpm_idle_work, radeon_dynpm_idle_work_handler); -#endif /* DUMBBELL_WIP */ +#endif /* DUMBBELL_PM */ if (rdev->pm.num_power_states > 1) { - /* where's the best place to put these? */ -#ifdef DUMBBELL_WIP - ret = device_create_file(rdev->dev, &dev_attr_power_profile); -#endif /* DUMBBELL_WIP */ - if (ret) - DRM_ERROR("failed to create device file for power profile\n"); -#ifdef DUMBBELL_WIP - ret = device_create_file(rdev->dev, &dev_attr_power_method); -#endif /* DUMBBELL_WIP */ - if (ret) - DRM_ERROR("failed to create device file for power method\n"); - if (radeon_debugfs_pm_init(rdev)) { DRM_ERROR("Failed to register debugfs file for PM!\n"); } @@ -1299,33 +1443,19 @@ static int radeon_pm_init_dpm(struct radeon_device *rdev) return ret; TASK_INIT(&rdev->pm.dpm.thermal.work, 0, radeon_dpm_thermal_work_handler, rdev); - lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE); + mutex_lock(&rdev->pm.mutex); radeon_dpm_init(rdev); rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps; if (radeon_dpm == 1) radeon_dpm_print_power_states(rdev); radeon_dpm_setup_asic(rdev); ret = radeon_dpm_enable(rdev); - lockmgr(&rdev->pm.mutex, LK_RELEASE); + mutex_unlock(&rdev->pm.mutex); if (ret) goto dpm_failed; rdev->pm.dpm_enabled = true; #ifdef TODO_DEVICE_FILE - ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state); - if (ret) - DRM_ERROR("failed to create device file for dpm state\n"); - ret = device_create_file(rdev->dev, &dev_attr_power_dpm_force_performance_level); - if (ret) - DRM_ERROR("failed to create device file for dpm state\n"); - /* XXX: these are noops for dpm but are here for backwards compat */ - ret = device_create_file(rdev->dev, &dev_attr_power_profile); - if (ret) - DRM_ERROR("failed to create device file for power profile\n"); - ret = device_create_file(rdev->dev, &dev_attr_power_method); - if (ret) - DRM_ERROR("failed to create device file for power method\n"); - if (radeon_debugfs_pm_init(rdev)) { DRM_ERROR("Failed to register debugfs file for dpm!\n"); } @@ -1355,8 +1485,39 @@ dpm_failed: return ret; } +struct radeon_dpm_quirk { + u32 chip_vendor; + u32 chip_device; + u32 subsys_vendor; + u32 subsys_device; +}; + +/* cards with dpm stability problems */ +static struct radeon_dpm_quirk radeon_dpm_quirk_list[] = { + /* TURKS - https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1386534 */ + { PCI_VENDOR_ID_ATI, 0x6759, 0x1682, 0x3195 }, + /* TURKS - https://bugzilla.kernel.org/show_bug.cgi?id=83731 */ + { PCI_VENDOR_ID_ATI, 0x6840, 0x1179, 0xfb81 }, + { 0, 0, 0, 0 }, +}; + int radeon_pm_init(struct radeon_device *rdev) { + struct radeon_dpm_quirk *p = radeon_dpm_quirk_list; + bool disable_dpm = false; + + /* Apply dpm quirks */ + while (p && p->chip_device != 0) { + if (rdev->pdev->vendor == p->chip_vendor && + rdev->pdev->device == p->chip_device && + rdev->pdev->subsystem_vendor == p->subsys_vendor && + rdev->pdev->subsystem_device == p->subsys_device) { + disable_dpm = true; + break; + } + ++p; + } + /* enable dpm on rv6xx+ */ switch (rdev->family) { case CHIP_RV610: @@ -1412,6 +1573,8 @@ int radeon_pm_init(struct radeon_device *rdev) (!(rdev->flags & RADEON_IS_IGP)) && (!rdev->smc_fw)) rdev->pm.pm_method = PM_METHOD_PROFILE; + else if (disable_dpm && (radeon_dpm == -1)) + rdev->pm.pm_method = PM_METHOD_PROFILE; else if (radeon_dpm == 0) rdev->pm.pm_method = PM_METHOD_PROFILE; else @@ -1434,18 +1597,63 @@ int radeon_pm_late_init(struct radeon_device *rdev) int ret = 0; if (rdev->pm.pm_method == PM_METHOD_DPM) { - lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE); - ret = radeon_dpm_late_enable(rdev); - lockmgr(&rdev->pm.mutex, LK_RELEASE); - } + if (rdev->pm.dpm_enabled) { +#ifdef TODO_DEVICE_FILE + if (!rdev->pm.sysfs_initialized) { + ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state); + if (ret) + DRM_ERROR("failed to create device file for dpm state\n"); + ret = device_create_file(rdev->dev, &dev_attr_power_dpm_force_performance_level); + if (ret) + DRM_ERROR("failed to create device file for dpm state\n"); + /* XXX: these are noops for dpm but are here for backwards compat */ + ret = device_create_file(rdev->dev, &dev_attr_power_profile); + if (ret) + DRM_ERROR("failed to create device file for power profile\n"); + ret = device_create_file(rdev->dev, &dev_attr_power_method); + if (ret) + DRM_ERROR("failed to create device file for power method\n"); + if (!ret) + rdev->pm.sysfs_initialized = true; + } +#endif + + mutex_lock(&rdev->pm.mutex); + ret = radeon_dpm_late_enable(rdev); + mutex_unlock(&rdev->pm.mutex); + if (ret) { + rdev->pm.dpm_enabled = false; + DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n"); + } else { + /* set the dpm state for PX since there won't be + * a modeset to call this. + */ + radeon_pm_compute_clocks(rdev); + } + } + } else { +#ifdef TODO_DEVICE_FILE + if ((rdev->pm.num_power_states > 1) && + (!rdev->pm.sysfs_initialized)) { + /* where's the best place to put these? */ + ret = device_create_file(rdev->dev, &dev_attr_power_profile); + if (ret) + DRM_ERROR("failed to create device file for power profile\n"); + ret = device_create_file(rdev->dev, &dev_attr_power_method); + if (ret) + DRM_ERROR("failed to create device file for power method\n"); + if (!ret) + rdev->pm.sysfs_initialized = true; + } +#endif + } return ret; } static void radeon_pm_fini_old(struct radeon_device *rdev) { if (rdev->pm.num_power_states > 1) { - DRM_UNLOCK(rdev->ddev); /* Work around LOR. */ - lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE); + mutex_lock(&rdev->pm.mutex); if (rdev->pm.pm_method == PM_METHOD_PROFILE) { rdev->pm.profile = PM_PROFILE_DEFAULT; radeon_pm_update_profile(rdev); @@ -1456,12 +1664,13 @@ static void radeon_pm_fini_old(struct radeon_device *rdev) rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT; radeon_pm_set_clocks(rdev); } - lockmgr(&rdev->pm.mutex, LK_RELEASE); - DRM_LOCK(rdev->ddev); + mutex_unlock(&rdev->pm.mutex); -#ifdef DUMBBELL_WIP +#ifdef DUMBBELL_PM cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); +#endif /* DUMBBELL_PM */ +#ifdef DUMBBELL_WIP device_remove_file(rdev->dev, &dev_attr_power_profile); device_remove_file(rdev->dev, &dev_attr_power_method); #endif /* DUMBBELL_WIP */ @@ -1483,9 +1692,9 @@ static void radeon_pm_fini_old(struct radeon_device *rdev) static void radeon_pm_fini_dpm(struct radeon_device *rdev) { if (rdev->pm.num_power_states > 1) { - lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE); + mutex_lock(&rdev->pm.mutex); radeon_dpm_disable(rdev); - lockmgr(&rdev->pm.mutex, LK_RELEASE); + mutex_unlock(&rdev->pm.mutex); #ifdef TODO_DEVICE_FILE device_remove_file(rdev->dev, &dev_attr_power_dpm_state); @@ -1528,7 +1737,7 @@ static void radeon_pm_compute_clocks_old(struct radeon_device *rdev) if (rdev->pm.num_power_states < 2) return; - lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE); + mutex_lock(&rdev->pm.mutex); rdev->pm.active_crtcs = 0; rdev->pm.active_crtc_count = 0; @@ -1550,9 +1759,9 @@ static void radeon_pm_compute_clocks_old(struct radeon_device *rdev) if (rdev->pm.dynpm_state != DYNPM_STATE_DISABLED) { if (rdev->pm.active_crtc_count > 1) { if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) { -#ifdef DUMBBELL_WIP +#ifdef DUMBBELL_PM cancel_delayed_work(&rdev->pm.dynpm_idle_work); -#endif /* DUMBBELL_WIP */ +#endif /* DUMBBELL_PM */ rdev->pm.dynpm_state = DYNPM_STATE_PAUSED; rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT; @@ -1570,23 +1779,23 @@ static void radeon_pm_compute_clocks_old(struct radeon_device *rdev) radeon_pm_get_dynpm_state(rdev); radeon_pm_set_clocks(rdev); -#ifdef DUMBBELL_WIP +#ifdef DUMBBELL_PM schedule_delayed_work(&rdev->pm.dynpm_idle_work, msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); -#endif /* DUMBBELL_WIP */ +#endif /* DUMBBELL_PM */ } else if (rdev->pm.dynpm_state == DYNPM_STATE_PAUSED) { rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; -#ifdef DUMBBELL_WIP +#ifdef DUMBBELL_PM schedule_delayed_work(&rdev->pm.dynpm_idle_work, msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); -#endif /* DUMBBELL_WIP */ +#endif /* DUMBBELL_PM*/ DRM_DEBUG_DRIVER("radeon: dynamic power management activated\n"); } } else { /* count == 0 */ if (rdev->pm.dynpm_state != DYNPM_STATE_MINIMUM) { -#ifdef DUMBBELL_WIP +#ifdef DUMBBELL_PM cancel_delayed_work(&rdev->pm.dynpm_idle_work); -#endif /* DUMBBELL_WIP */ +#endif /* DUMBBELL_PM */ rdev->pm.dynpm_state = DYNPM_STATE_MINIMUM; rdev->pm.dynpm_planned_action = DYNPM_ACTION_MINIMUM; @@ -1597,7 +1806,7 @@ static void radeon_pm_compute_clocks_old(struct radeon_device *rdev) } } - lockmgr(&rdev->pm.mutex, LK_RELEASE); + mutex_unlock(&rdev->pm.mutex); } static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev) @@ -1609,7 +1818,7 @@ static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev) if (!rdev->pm.dpm_enabled) return; - lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE); + mutex_lock(&rdev->pm.mutex); /* update active crtc counts */ rdev->pm.dpm.new_active_crtcs = 0; @@ -1633,7 +1842,7 @@ static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev) radeon_dpm_change_power_state_locked(rdev); - lockmgr(&rdev->pm.mutex, LK_RELEASE); + mutex_unlock(&rdev->pm.mutex); } @@ -1655,7 +1864,9 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev) */ for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) { if (rdev->pm.active_crtcs & (1 << crtc)) { - vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, 0, + vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, + crtc, + USE_REAL_VBLANKSTART, &vpos, &hpos, NULL, NULL, &rdev->mode_info.crtcs[crtc]->base.hwmode); if ((vbl_status & DRM_SCANOUTPOS_VALID) && @@ -1678,7 +1889,7 @@ static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish return in_vbl; } -#ifdef DUMBBELL_WIP +#ifdef DUMBBELL_PM static void radeon_dynpm_idle_work_handler(struct work_struct *work) { struct radeon_device *rdev; @@ -1687,7 +1898,7 @@ static void radeon_dynpm_idle_work_handler(struct work_struct *work) pm.dynpm_idle_work.work); resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); - lockmgr(&rdev->pm.mutex, LK_EXCLUSIVE); + mutex_lock(&rdev->pm.mutex); if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) { int not_processed = 0; int i; @@ -1736,10 +1947,10 @@ static void radeon_dynpm_idle_work_handler(struct work_struct *work) schedule_delayed_work(&rdev->pm.dynpm_idle_work, msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); } - lockmgr(&rdev->pm.mutex, LK_RELEASE); + mutex_unlock(&rdev->pm.mutex); ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); } -#endif /* DUMBBELL_WIP */ +#endif /* DUMBBELL_PM */ /* * Debugfs info @@ -1757,12 +1968,12 @@ static int radeon_debugfs_pm_info(struct seq_file *m, void *data) (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) { seq_printf(m, "PX asic powered off\n"); } else if (rdev->pm.dpm_enabled) { - spin_lock(&rdev->pm.mutex); + mutex_lock(&rdev->pm.mutex); if (rdev->asic->dpm.debugfs_print_current_performance_level) radeon_dpm_debugfs_print_current_performance_level(rdev, m); else seq_printf(m, "Debugfs support not implemented for this asic\n"); - spin_unlock(&rdev->pm.mutex); + mutex_unlock(&rdev->pm.mutex); } else { seq_printf(m, "default engine clock: %u0 kHz\n", rdev->pm.default_sclk); /* radeon_get_engine_clock is not reliable on APUs so just print the current clock */ diff --git a/sys/dev/drm/radeon/radeon_ring.c b/sys/dev/drm/radeon/radeon_ring.c index ac8174ed7b..b13198113a 100644 --- a/sys/dev/drm/radeon/radeon_ring.c +++ b/sys/dev/drm/radeon/radeon_ring.c @@ -143,10 +143,10 @@ int radeon_ring_lock(struct radeon_device *rdev, struct radeon_ring *ring, unsig { int r; - lockmgr(&rdev->ring_lock, LK_EXCLUSIVE); + mutex_lock(&rdev->ring_lock); r = radeon_ring_alloc(rdev, ring, ndw); if (r) { - lockmgr(&rdev->ring_lock, LK_RELEASE); + mutex_unlock(&rdev->ring_lock); return r; } return 0; @@ -198,7 +198,7 @@ void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *r bool hdp_flush) { radeon_ring_commit(rdev, ring, hdp_flush); - lockmgr(&rdev->ring_lock, LK_RELEASE); + mutex_unlock(&rdev->ring_lock); } /** @@ -223,7 +223,7 @@ void radeon_ring_undo(struct radeon_ring *ring) void radeon_ring_unlock_undo(struct radeon_device *rdev, struct radeon_ring *ring) { radeon_ring_undo(ring); - lockmgr(&rdev->ring_lock, LK_RELEASE); + mutex_unlock(&rdev->ring_lock); } /** @@ -282,17 +282,17 @@ unsigned radeon_ring_backup(struct radeon_device *rdev, struct radeon_ring *ring unsigned size, ptr, i; /* just in case lock the ring */ - lockmgr(&rdev->ring_lock, LK_EXCLUSIVE); + mutex_lock(&rdev->ring_lock); *data = NULL; if (ring->ring_obj == NULL) { - lockmgr(&rdev->ring_lock, LK_RELEASE); + mutex_unlock(&rdev->ring_lock); return 0; } /* it doesn't make sense to save anything if all fences are signaled */ if (!radeon_fence_count_emitted(rdev, ring->idx)) { - lockmgr(&rdev->ring_lock, LK_RELEASE); + mutex_unlock(&rdev->ring_lock); return 0; } @@ -303,7 +303,7 @@ unsigned radeon_ring_backup(struct radeon_device *rdev, struct radeon_ring *ring ptr = le32_to_cpu(*ring->next_rptr_cpu_addr); else { /* no way to read back the next rptr */ - lockmgr(&rdev->ring_lock, LK_RELEASE); + mutex_unlock(&rdev->ring_lock); return 0; } @@ -311,14 +311,14 @@ unsigned radeon_ring_backup(struct radeon_device *rdev, struct radeon_ring *ring size -= ptr; size &= ring->ptr_mask; if (size == 0) { - lockmgr(&rdev->ring_lock, LK_RELEASE); + mutex_unlock(&rdev->ring_lock); return 0; } /* and then save the content of the ring */ *data = drm_malloc_ab(size, sizeof(uint32_t)); if (!*data) { - lockmgr(&rdev->ring_lock, LK_RELEASE); + mutex_unlock(&rdev->ring_lock); return 0; } for (i = 0; i < size; ++i) { @@ -326,7 +326,7 @@ unsigned radeon_ring_backup(struct radeon_device *rdev, struct radeon_ring *ring ptr &= ring->ptr_mask; } - lockmgr(&rdev->ring_lock, LK_RELEASE); + mutex_unlock(&rdev->ring_lock); return size; } @@ -393,15 +393,12 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsig return r; } r = radeon_bo_reserve(ring->ring_obj, false); - if (unlikely(r != 0)) { - radeon_bo_unref(&ring->ring_obj); - return r; - } + if (unlikely(r != 0)) + return r; r = radeon_bo_pin(ring->ring_obj, RADEON_GEM_DOMAIN_GTT, (u64 *)&ring->gpu_addr); if (r) { radeon_bo_unreserve(ring->ring_obj); - radeon_bo_unref(&ring->ring_obj); dev_err(rdev->dev, "(%d) ring pin failed\n", r); return r; } @@ -411,7 +408,6 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsig radeon_bo_unreserve(ring->ring_obj); if (r) { dev_err(rdev->dev, "(%d) ring map failed\n", r); - radeon_bo_unref(&ring->ring_obj); return r; } } @@ -444,12 +440,12 @@ void radeon_ring_fini(struct radeon_device *rdev, struct radeon_ring *ring) int r; struct radeon_bo *ring_obj; - lockmgr(&rdev->ring_lock, LK_EXCLUSIVE); + mutex_lock(&rdev->ring_lock); ring_obj = ring->ring_obj; ring->ready = false; ring->ring = NULL; ring->ring_obj = NULL; - lockmgr(&rdev->ring_lock, LK_RELEASE); + mutex_unlock(&rdev->ring_lock); if (ring_obj) { r = radeon_bo_reserve(ring_obj, false); @@ -505,7 +501,7 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data) seq_printf(m, "%u free dwords in ring\n", ring->ring_free_dw); seq_printf(m, "%u dwords in ring\n", count); - if (!ring->ready) + if (!ring->ring) return 0; /* print 8 dw before current rptr as often it's the last executed diff --git a/sys/dev/drm/radeon/radeon_sa.c b/sys/dev/drm/radeon/radeon_sa.c index 3131a28b6c..fe9c948035 100644 --- a/sys/dev/drm/radeon/radeon_sa.c +++ b/sys/dev/drm/radeon/radeon_sa.c @@ -357,8 +357,13 @@ int radeon_sa_bo_new(struct radeon_device *rdev, /* see if we can skip over some allocations */ } while (radeon_sa_bo_next_hole(sa_manager, fences, tries)); + for (i = 0; i < RADEON_NUM_RINGS; ++i) + radeon_fence_ref(fences[i]); + lockmgr(&sa_manager->wq_lock, LK_RELEASE); r = radeon_fence_wait_any(rdev, fences, false); + for (i = 0; i < RADEON_NUM_RINGS; ++i) + radeon_fence_unref(&fences[i]); lockmgr(&sa_manager->wq_lock, LK_EXCLUSIVE); /* if we have nothing to wait for block */ if (r == -ENOENT) { diff --git a/sys/dev/drm/radeon/radeon_ttm.c b/sys/dev/drm/radeon/radeon_ttm.c index 82e23b1c98..ac8add4609 100644 --- a/sys/dev/drm/radeon/radeon_ttm.c +++ b/sys/dev/drm/radeon/radeon_ttm.c @@ -195,9 +195,32 @@ static void radeon_evict_flags(struct ttm_buffer_object *bo, rbo = container_of(bo, struct radeon_bo, tbo); switch (bo->mem.mem_type) { case TTM_PL_VRAM: - if (rbo->rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready == false) + if (rbo->rdev->ring[radeon_copy_ring_index(rbo->rdev)].ready == false) radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_CPU); - else + else if (rbo->rdev->mc.visible_vram_size < rbo->rdev->mc.real_vram_size && + bo->mem.start < (rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT)) { + unsigned fpfn = rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT; + int i; + + /* Try evicting to the CPU inaccessible part of VRAM + * first, but only set GTT as busy placement, so this + * BO will be evicted to GTT rather than causing other + * BOs to be evicted from VRAM + */ + radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_VRAM | + RADEON_GEM_DOMAIN_GTT); + rbo->placement.num_busy_placement = 0; + for (i = 0; i < rbo->placement.num_placement; i++) { + if (rbo->placements[i].flags & TTM_PL_FLAG_VRAM) { + if (rbo->placements[0].fpfn < fpfn) + rbo->placements[0].fpfn = fpfn; + } else { + rbo->placement.busy_placement = + &rbo->placements[i]; + rbo->placement.num_busy_placement = 1; + } + } + } else radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_GTT); break; case TTM_PL_TT: @@ -234,8 +257,8 @@ static int radeon_move_blit(struct ttm_buffer_object *bo, rdev = radeon_get_rdev(bo->bdev); ridx = radeon_copy_ring_index(rdev); - old_start = old_mem->start << PAGE_SHIFT; - new_start = new_mem->start << PAGE_SHIFT; + old_start = (u64)old_mem->start << PAGE_SHIFT; + new_start = (u64)new_mem->start << PAGE_SHIFT; switch (old_mem->mem_type) { case TTM_PL_VRAM: @@ -371,9 +394,15 @@ static int radeon_bo_move(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem) { struct radeon_device *rdev; + struct radeon_bo *rbo; struct ttm_mem_reg *old_mem = &bo->mem; int r; + /* Can't move a pinned BO */ + rbo = container_of(bo, struct radeon_bo, tbo); + if (WARN_ON_ONCE(rbo->pin_count > 0)) + return -EINVAL; + rdev = radeon_get_rdev(bo->bdev); if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) { radeon_move_null(bo, new_mem); @@ -649,7 +678,7 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm) 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); if (pci_dma_mapping_error(rdev->pdev, gtt->ttm.dma_address[i])) { - while (--i) { + while (i--) { pci_unmap_page(rdev->pdev, gtt->ttm.dma_address[i], PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); gtt->ttm.dma_address[i] = 0; @@ -724,7 +753,7 @@ static struct ttm_bo_driver radeon_bo_driver = { int radeon_ttm_init(struct radeon_device *rdev) { - int r, r2; + int r; r = radeon_ttm_global_init(rdev); if (r) { @@ -757,10 +786,8 @@ int radeon_ttm_init(struct radeon_device *rdev) return r; } r = radeon_bo_reserve(rdev->stollen_vga_memory, false); - if (r) { - radeon_bo_unref(&rdev->stollen_vga_memory); - return r; - } + if (r) + return r; r = radeon_bo_pin(rdev->stollen_vga_memory, RADEON_GEM_DOMAIN_VRAM, NULL); radeon_bo_unreserve(rdev->stollen_vga_memory); if (r) { @@ -773,12 +800,6 @@ int radeon_ttm_init(struct radeon_device *rdev) rdev->mc.gtt_size >> PAGE_SHIFT); if (r) { DRM_ERROR("Failed initializing GTT heap.\n"); - r2 = radeon_bo_reserve(rdev->stollen_vga_memory, false); - if (likely(r2 == 0)) { - radeon_bo_unpin(rdev->stollen_vga_memory); - radeon_bo_unreserve(rdev->stollen_vga_memory); - } - radeon_bo_unref(&rdev->stollen_vga_memory); return r; } DRM_INFO("radeon: %uM of GTT memory ready.\n", @@ -787,12 +808,6 @@ int radeon_ttm_init(struct radeon_device *rdev) r = radeon_ttm_debugfs_init(rdev); if (r) { DRM_ERROR("Failed to init debugfs\n"); - r2 = radeon_bo_reserve(rdev->stollen_vga_memory, false); - if (likely(r2 == 0)) { - radeon_bo_unpin(rdev->stollen_vga_memory); - radeon_bo_unreserve(rdev->stollen_vga_memory); - } - radeon_bo_unref(&rdev->stollen_vga_memory); return r; } return 0; diff --git a/sys/dev/drm/radeon/radeon_uvd.c b/sys/dev/drm/radeon/radeon_uvd.c index 096420f9d8..c429fe03fe 100644 --- a/sys/dev/drm/radeon/radeon_uvd.c +++ b/sys/dev/drm/radeon/radeon_uvd.c @@ -33,6 +33,7 @@ #include #include "radeon.h" +#include "radeon_ucode.h" #include "r600d.h" /* 1 second timeout */ @@ -46,7 +47,8 @@ #define FIRMWARE_CYPRESS "radeonkmsfw_CYPRESS_uvd" #define FIRMWARE_SUMO "radeonkmsfw_SUMO_uvd" #define FIRMWARE_TAHITI "radeonkmsfw_TAHITI_uvd" -#define FIRMWARE_BONAIRE "radeonkmsfw_BONAIRE_uvd" +#define FIRMWARE_BONAIRE_LEGACY "radeonkmsfw/BONAIRE_uvd" +#define FIRMWARE_BONAIRE "radeonkmsfw_bonaire_uvd" MODULE_FIRMWARE(FIRMWARE_R600); MODULE_FIRMWARE(FIRMWARE_RS780); @@ -55,6 +57,7 @@ MODULE_FIRMWARE(FIRMWARE_RV710); MODULE_FIRMWARE(FIRMWARE_CYPRESS); MODULE_FIRMWARE(FIRMWARE_SUMO); MODULE_FIRMWARE(FIRMWARE_TAHITI); +MODULE_FIRMWARE(FIRMWARE_BONAIRE_LEGACY); MODULE_FIRMWARE(FIRMWARE_BONAIRE); static void radeon_uvd_idle_work_handler(struct work_struct *work); @@ -62,7 +65,7 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work); int radeon_uvd_init(struct radeon_device *rdev) { unsigned long bo_size; - const char *fw_name; + const char *fw_name = NULL, *legacy_fw_name = NULL; int i, r; INIT_DELAYED_WORK(&rdev->uvd.idle_work, radeon_uvd_idle_work_handler); @@ -73,22 +76,22 @@ int radeon_uvd_init(struct radeon_device *rdev) case CHIP_RV670: case CHIP_RV620: case CHIP_RV635: - fw_name = FIRMWARE_R600; + legacy_fw_name = FIRMWARE_R600; break; case CHIP_RS780: case CHIP_RS880: - fw_name = FIRMWARE_RS780; + legacy_fw_name = FIRMWARE_RS780; break; case CHIP_RV770: - fw_name = FIRMWARE_RV770; + legacy_fw_name = FIRMWARE_RV770; break; case CHIP_RV710: case CHIP_RV730: case CHIP_RV740: - fw_name = FIRMWARE_RV710; + legacy_fw_name = FIRMWARE_RV710; break; case CHIP_CYPRESS: @@ -96,7 +99,7 @@ int radeon_uvd_init(struct radeon_device *rdev) case CHIP_JUNIPER: case CHIP_REDWOOD: case CHIP_CEDAR: - fw_name = FIRMWARE_CYPRESS; + legacy_fw_name = FIRMWARE_CYPRESS; break; case CHIP_SUMO: @@ -106,7 +109,7 @@ int radeon_uvd_init(struct radeon_device *rdev) case CHIP_BARTS: case CHIP_TURKS: case CHIP_CAICOS: - fw_name = FIRMWARE_SUMO; + legacy_fw_name = FIRMWARE_SUMO; break; case CHIP_TAHITI: @@ -114,7 +117,7 @@ int radeon_uvd_init(struct radeon_device *rdev) case CHIP_PITCAIRN: case CHIP_ARUBA: case CHIP_OLAND: - fw_name = FIRMWARE_TAHITI; + legacy_fw_name = FIRMWARE_TAHITI; break; case CHIP_BONAIRE: @@ -122,6 +125,7 @@ int radeon_uvd_init(struct radeon_device *rdev) case CHIP_KAVERI: case CHIP_HAWAII: case CHIP_MULLINS: + legacy_fw_name = FIRMWARE_BONAIRE_LEGACY; fw_name = FIRMWARE_BONAIRE; break; @@ -129,16 +133,56 @@ int radeon_uvd_init(struct radeon_device *rdev) return -EINVAL; } - r = request_firmware(&rdev->uvd_fw, fw_name, rdev->dev); - if (r) { - dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n", - fw_name); - return r; + rdev->uvd.fw_header_present = false; + rdev->uvd.max_handles = RADEON_DEFAULT_UVD_HANDLES; + if (fw_name) { + /* Let's try to load the newer firmware first */ + r = request_firmware(&rdev->uvd_fw, fw_name, rdev->dev); + if (r) { + dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n", + fw_name); + } else { + const struct common_firmware_header *hdr = (const struct common_firmware_header *)rdev->uvd_fw->data; + unsigned version_major, version_minor, family_id; + + r = radeon_ucode_validate(rdev->uvd_fw); + if (r) + return r; + + rdev->uvd.fw_header_present = true; + + family_id = le32_to_cpu(hdr->ucode_version) & 0xff; + version_major = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xff; + version_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff; + DRM_INFO("Found UVD firmware Version: %hu.%hu Family ID: %hu\n", + version_major, version_minor, family_id); + + /* + * Limit the number of UVD handles depending on + * microcode major and minor versions. + */ + if ((version_major >= 0x01) && (version_minor >= 0x37)) + rdev->uvd.max_handles = RADEON_MAX_UVD_HANDLES; + } } + /* + * In case there is only legacy firmware, or we encounter an error + * while loading the new firmware, we fall back to loading the legacy + * firmware now. + */ + if (!fw_name || r) { + r = request_firmware(&rdev->uvd_fw, legacy_fw_name, rdev->dev); + if (r) { + dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n", + legacy_fw_name); + return r; + } + } + bo_size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->datasize + 8) + RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE + - RADEON_GPU_PAGE_SIZE; + RADEON_UVD_SESSION_SIZE * rdev->uvd.max_handles; r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, 0, NULL, &rdev->uvd.vcpu_bo); if (r) { @@ -170,7 +214,7 @@ int radeon_uvd_init(struct radeon_device *rdev) radeon_bo_unreserve(rdev->uvd.vcpu_bo); - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { + for (i = 0; i < rdev->uvd.max_handles; ++i) { atomic_set(&rdev->uvd.handles[i], 0); rdev->uvd.filp[i] = NULL; rdev->uvd.img_size[i] = 0; @@ -202,28 +246,32 @@ void radeon_uvd_fini(struct radeon_device *rdev) int radeon_uvd_suspend(struct radeon_device *rdev) { - unsigned size; - char *ptr; - int i; + int i, r; if (rdev->uvd.vcpu_bo == NULL) return 0; - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) - if (atomic_read(&rdev->uvd.handles[i])) - break; - - if (i == RADEON_MAX_UVD_HANDLES) - return 0; - - size = radeon_bo_size(rdev->uvd.vcpu_bo); - size -= rdev->uvd_fw->datasize; - - ptr = rdev->uvd.cpu_addr; - ptr += rdev->uvd_fw->datasize; - - rdev->uvd.saved_bo = kmalloc(size, M_DRM, M_WAITOK); - memcpy(rdev->uvd.saved_bo, ptr, size); + for (i = 0; i < rdev->uvd.max_handles; ++i) { + uint32_t handle = atomic_read(&rdev->uvd.handles[i]); + if (handle != 0) { + struct radeon_fence *fence; + + radeon_uvd_note_usage(rdev); + + r = radeon_uvd_get_destroy_msg(rdev, + R600_RING_TYPE_UVD_INDEX, handle, &fence); + if (r) { + DRM_ERROR("Error destroying UVD (%d)!\n", r); + continue; + } + + radeon_fence_wait(fence, false); + radeon_fence_unref(&fence); + + rdev->uvd.filp[i] = NULL; + atomic_set(&rdev->uvd.handles[i], 0); + } + } return 0; } @@ -244,12 +292,7 @@ int radeon_uvd_resume(struct radeon_device *rdev) ptr = rdev->uvd.cpu_addr; ptr += rdev->uvd_fw->datasize; - if (rdev->uvd.saved_bo != NULL) { - memcpy(ptr, rdev->uvd.saved_bo, size); - kfree(rdev->uvd.saved_bo); - rdev->uvd.saved_bo = NULL; - } else - memset(ptr, 0, size); + memset(ptr, 0, size); return 0; } @@ -283,7 +326,7 @@ void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo, void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp) { int i, r; - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { + for (i = 0; i < rdev->uvd.max_handles; ++i) { uint32_t handle = atomic_read(&rdev->uvd.handles[i]); if (handle != 0 && rdev->uvd.filp[i] == filp) { struct radeon_fence *fence; @@ -394,6 +437,29 @@ static int radeon_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[]) return 0; } +static int radeon_uvd_validate_codec(struct radeon_cs_parser *p, + unsigned stream_type) +{ + switch (stream_type) { + case 0: /* H264 */ + case 1: /* VC1 */ + /* always supported */ + return 0; + + case 3: /* MPEG2 */ + case 4: /* MPEG4 */ + /* only since UVD 3 */ + if (p->rdev->family >= CHIP_PALM) + return 0; + + /* fall through */ + default: + DRM_ERROR("UVD codec not supported by hardware %d!\n", + stream_type); + return -EINVAL; + } +} + static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, unsigned offset, unsigned buf_sizes[]) { @@ -432,50 +498,70 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, return -EINVAL; } - if (msg_type == 1) { - /* it's a decode msg, calc buffer sizes */ - r = radeon_uvd_cs_msg_decode(msg, buf_sizes); - /* calc image size (width * height) */ - img_size = msg[6] * msg[7]; + switch (msg_type) { + case 0: + /* it's a create msg, calc image size (width * height) */ + img_size = msg[7] * msg[8]; + + r = radeon_uvd_validate_codec(p, msg[4]); + radeon_bo_kunmap(bo); + if (r) + return r; + + /* try to alloc a new handle */ + for (i = 0; i < p->rdev->uvd.max_handles; ++i) { + if (atomic_read(&p->rdev->uvd.handles[i]) == handle) { + DRM_ERROR("Handle 0x%x already in use!\n", handle); + return -EINVAL; + } + + if (!atomic_cmpxchg(&p->rdev->uvd.handles[i], 0, handle)) { + p->rdev->uvd.filp[i] = p->filp; + p->rdev->uvd.img_size[i] = img_size; + return 0; + } + } + + DRM_ERROR("No more free UVD handles!\n"); + return -EINVAL; + + case 1: + /* it's a decode msg, validate codec and calc buffer sizes */ + r = radeon_uvd_validate_codec(p, msg[4]); + if (!r) + r = radeon_uvd_cs_msg_decode(msg, buf_sizes); radeon_bo_kunmap(bo); if (r) return r; - } else if (msg_type == 2) { + /* validate the handle */ + for (i = 0; i < p->rdev->uvd.max_handles; ++i) { + if (atomic_read(&p->rdev->uvd.handles[i]) == handle) { + if (p->rdev->uvd.filp[i] != p->filp) { + DRM_ERROR("UVD handle collision detected!\n"); + return -EINVAL; + } + return 0; + } + } + + DRM_ERROR("Invalid UVD handle 0x%x!\n", handle); + return -ENOENT; + + case 2: /* it's a destroy msg, free the handle */ - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) + for (i = 0; i < p->rdev->uvd.max_handles; ++i) atomic_cmpxchg(&p->rdev->uvd.handles[i], handle, 0); radeon_bo_kunmap(bo); return 0; - } else { - /* it's a create msg, calc image size (width * height) */ - img_size = msg[7] * msg[8]; - radeon_bo_kunmap(bo); - - if (msg_type != 0) { - DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type); - return -EINVAL; - } - /* it's a create msg, no special handling needed */ - } - - /* create or decode, validate the handle */ - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { - if (atomic_read(&p->rdev->uvd.handles[i]) == handle) - return 0; - } + default: - /* handle not found try to alloc a new one */ - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { - if (!atomic_cmpxchg(&p->rdev->uvd.handles[i], 0, handle)) { - p->rdev->uvd.filp[i] = p->filp; - p->rdev->uvd.img_size[i] = img_size; - return 0; - } + DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type); + return -EINVAL; } - DRM_ERROR("No more free UVD handles!\n"); + BUG(); return -EINVAL; } @@ -484,7 +570,7 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p, unsigned buf_sizes[], bool *has_msg_cmd) { struct radeon_cs_chunk *relocs_chunk; - struct radeon_cs_reloc *reloc; + struct radeon_bo_list *reloc; unsigned idx, cmd, offset; uint64_t start, end; int r; @@ -676,9 +762,11 @@ static int radeon_uvd_send_msg(struct radeon_device *rdev, return r; } -/* multiple fence commands without any stream commands in between can - crash the vcpu so just try to emmit a dummy create/destroy msg to - avoid this */ +/* + * multiple fence commands without any stream commands in between can + * crash the vcpu so just try to emmit a dummy create/destroy msg to + * avoid this + */ int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring, uint32_t handle, struct radeon_fence **fence) { @@ -761,7 +849,7 @@ static void radeon_uvd_count_handles(struct radeon_device *rdev, *sd = 0; *hd = 0; - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { + for (i = 0; i < rdev->uvd.max_handles; ++i) { if (!atomic_read(&rdev->uvd.handles[i])) continue; diff --git a/sys/dev/drm/radeon/radeon_vce.c b/sys/dev/drm/radeon/radeon_vce.c index 026d6ed4d1..2fe58a924d 100644 --- a/sys/dev/drm/radeon/radeon_vce.c +++ b/sys/dev/drm/radeon/radeon_vce.c @@ -37,8 +37,10 @@ #define VCE_IDLE_TIMEOUT_MS 1000 /* Firmware Names */ +#define FIRMWARE_TAHITI "radeonkmsfw/TAHITI_vce" #define FIRMWARE_BONAIRE "radeonkmsfw_BONAIRE_vce" +MODULE_FIRMWARE(FIRMWARE_TAHITI); MODULE_FIRMWARE(FIRMWARE_BONAIRE); static void radeon_vce_idle_work_handler(struct work_struct *work); @@ -62,6 +64,14 @@ int radeon_vce_init(struct radeon_device *rdev) INIT_DELAYED_WORK(&rdev->vce.idle_work, radeon_vce_idle_work_handler); switch (rdev->family) { + case CHIP_TAHITI: + case CHIP_PITCAIRN: + case CHIP_VERDE: + case CHIP_OLAND: + case CHIP_ARUBA: + fw_name = FIRMWARE_TAHITI; + break; + case CHIP_BONAIRE: case CHIP_KAVERI: case CHIP_KABINI: @@ -117,13 +127,17 @@ int radeon_vce_init(struct radeon_device *rdev) rdev->vce.fw_version = (start << 24) | (mid << 16) | (end << 8); /* we can only work with this fw version for now */ - if (rdev->vce.fw_version != ((40 << 24) | (2 << 16) | (2 << 8))) + if ((rdev->vce.fw_version != ((40 << 24) | (2 << 16) | (2 << 8))) && + (rdev->vce.fw_version != ((50 << 24) | (0 << 16) | (1 << 8))) && + (rdev->vce.fw_version != ((50 << 24) | (1 << 16) | (2 << 8)))) return -EINVAL; /* allocate firmware, stack and heap BO */ - size = RADEON_GPU_PAGE_ALIGN(rdev->vce_fw->datasize) + - RADEON_VCE_STACK_SIZE + RADEON_VCE_HEAP_SIZE; + if (rdev->family < CHIP_BONAIRE) + size = vce_v1_0_bo_size(rdev); + else + size = vce_v2_0_bo_size(rdev); r = radeon_bo_create(rdev, size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, 0, NULL, &rdev->vce.vcpu_bo); if (r) { @@ -223,13 +237,17 @@ int radeon_vce_resume(struct radeon_device *rdev) return r; } - memcpy(cpu_addr, rdev->vce_fw->data, rdev->vce_fw->datasize); + memset(cpu_addr, 0, radeon_bo_size(rdev->vce.vcpu_bo)); + if (rdev->family < CHIP_BONAIRE) + r = vce_v1_0_load_fw(rdev, cpu_addr); + else + memcpy(cpu_addr, rdev->vce_fw->data, rdev->vce_fw->datasize); radeon_bo_kunmap(rdev->vce.vcpu_bo); radeon_bo_unreserve(rdev->vce.vcpu_bo); - return 0; + return r; } /** @@ -341,31 +359,31 @@ int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring, /* stitch together an VCE create msg */ ib.length_dw = 0; - ib.ptr[ib.length_dw++] = 0x0000000c; /* len */ - ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */ - ib.ptr[ib.length_dw++] = handle; - - ib.ptr[ib.length_dw++] = 0x00000030; /* len */ - ib.ptr[ib.length_dw++] = 0x01000001; /* create cmd */ - ib.ptr[ib.length_dw++] = 0x00000000; - ib.ptr[ib.length_dw++] = 0x00000042; - ib.ptr[ib.length_dw++] = 0x0000000a; - ib.ptr[ib.length_dw++] = 0x00000001; - ib.ptr[ib.length_dw++] = 0x00000080; - ib.ptr[ib.length_dw++] = 0x00000060; - ib.ptr[ib.length_dw++] = 0x00000100; - ib.ptr[ib.length_dw++] = 0x00000100; - ib.ptr[ib.length_dw++] = 0x0000000c; - ib.ptr[ib.length_dw++] = 0x00000000; - - ib.ptr[ib.length_dw++] = 0x00000014; /* len */ - ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */ - ib.ptr[ib.length_dw++] = upper_32_bits(dummy); - ib.ptr[ib.length_dw++] = dummy; - ib.ptr[ib.length_dw++] = 0x00000001; + ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); /* len */ + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); /* session cmd */ + ib.ptr[ib.length_dw++] = cpu_to_le32(handle); + + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000030); /* len */ + ib.ptr[ib.length_dw++] = cpu_to_le32(0x01000001); /* create cmd */ + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000000); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000042); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000a); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000080); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000060); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000100); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000100); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000000); + + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000014); /* len */ + ib.ptr[ib.length_dw++] = cpu_to_le32(0x05000005); /* feedback buffer */ + ib.ptr[ib.length_dw++] = cpu_to_le32(upper_32_bits(dummy)); + ib.ptr[ib.length_dw++] = cpu_to_le32(dummy); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); for (i = ib.length_dw; i < ib_size_dw; ++i) - ib.ptr[i] = 0x0; + ib.ptr[i] = cpu_to_le32(0x0); r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { @@ -408,21 +426,21 @@ int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring, /* stitch together an VCE destroy msg */ ib.length_dw = 0; - ib.ptr[ib.length_dw++] = 0x0000000c; /* len */ - ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */ - ib.ptr[ib.length_dw++] = handle; + ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); /* len */ + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); /* session cmd */ + ib.ptr[ib.length_dw++] = cpu_to_le32(handle); - ib.ptr[ib.length_dw++] = 0x00000014; /* len */ - ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */ - ib.ptr[ib.length_dw++] = upper_32_bits(dummy); - ib.ptr[ib.length_dw++] = dummy; - ib.ptr[ib.length_dw++] = 0x00000001; + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000014); /* len */ + ib.ptr[ib.length_dw++] = cpu_to_le32(0x05000005); /* feedback buffer */ + ib.ptr[ib.length_dw++] = cpu_to_le32(upper_32_bits(dummy)); + ib.ptr[ib.length_dw++] = cpu_to_le32(dummy); + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); - ib.ptr[ib.length_dw++] = 0x00000008; /* len */ - ib.ptr[ib.length_dw++] = 0x02000001; /* destroy cmd */ + ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000008); /* len */ + ib.ptr[ib.length_dw++] = cpu_to_le32(0x02000001); /* destroy cmd */ for (i = ib.length_dw; i < ib_size_dw; ++i) - ib.ptr[i] = 0x0; + ib.ptr[i] = cpu_to_le32(0x0); r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { @@ -451,7 +469,7 @@ int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi, unsigned size) { struct radeon_cs_chunk *relocs_chunk; - struct radeon_cs_reloc *reloc; + struct radeon_bo_list *reloc; uint64_t start, end, offset; unsigned idx; @@ -491,18 +509,27 @@ int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi, * * @p: parser context * @handle: handle to validate + * @allocated: allocated a new handle? * * Validates the handle and return the found session index or -EINVAL * we we don't have another free session index. */ -static int radeon_vce_validate_handle(struct radeon_cs_parser *p, uint32_t handle) +static int radeon_vce_validate_handle(struct radeon_cs_parser *p, + uint32_t handle, bool *allocated) { unsigned i; + *allocated = false; + /* validate the handle */ for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { - if (atomic_read(&p->rdev->vce.handles[i]) == handle) - return i; + if (atomic_read(&p->rdev->vce.handles[i]) == handle) { + if (p->rdev->vce.filp[i] != p->filp) { + DRM_ERROR("VCE handle collision detected!\n"); + return -EINVAL; + } + return i; + } } /* handle not found try to alloc a new one */ @@ -510,6 +537,7 @@ static int radeon_vce_validate_handle(struct radeon_cs_parser *p, uint32_t handl if (!atomic_cmpxchg(&p->rdev->vce.handles[i], 0, handle)) { p->rdev->vce.filp[i] = p->filp; p->rdev->vce.img_size[i] = 0; + *allocated = true; return i; } } @@ -527,10 +555,10 @@ static int radeon_vce_validate_handle(struct radeon_cs_parser *p, uint32_t handl int radeon_vce_cs_parse(struct radeon_cs_parser *p) { int session_idx = -1; - bool destroyed = false; + bool destroyed = false, created = false, allocated = false; uint32_t tmp, handle = 0; uint32_t *size = &tmp; - int i, r; + int i, r = 0; while (p->idx < p->chunks[p->chunk_ib_idx].length_dw) { uint32_t len = radeon_get_ib_value(p, p->idx); @@ -538,18 +566,21 @@ int radeon_vce_cs_parse(struct radeon_cs_parser *p) if ((len < 8) || (len & 3)) { DRM_ERROR("invalid VCE command length (%d)!\n", len); - return -EINVAL; + r = -EINVAL; + goto out; } if (destroyed) { DRM_ERROR("No other command allowed after destroy!\n"); - return -EINVAL; + r = -EINVAL; + goto out; } switch (cmd) { case 0x00000001: // session handle = radeon_get_ib_value(p, p->idx + 2); - session_idx = radeon_vce_validate_handle(p, handle); + session_idx = radeon_vce_validate_handle(p, handle, + &allocated); if (session_idx < 0) return session_idx; size = &p->rdev->vce.img_size[session_idx]; @@ -559,6 +590,13 @@ int radeon_vce_cs_parse(struct radeon_cs_parser *p) break; case 0x01000001: // create + created = true; + if (!allocated) { + DRM_ERROR("Handle already in use!\n"); + r = -EINVAL; + goto out; + } + *size = radeon_get_ib_value(p, p->idx + 8) * radeon_get_ib_value(p, p->idx + 10) * 8 * 3 / 2; @@ -569,18 +607,19 @@ int radeon_vce_cs_parse(struct radeon_cs_parser *p) case 0x04000005: // rate control case 0x04000007: // motion estimation case 0x04000008: // rdo + case 0x04000009: // vui break; case 0x03000001: // encode r = radeon_vce_cs_reloc(p, p->idx + 10, p->idx + 9, *size); if (r) - return r; + goto out; r = radeon_vce_cs_reloc(p, p->idx + 12, p->idx + 11, *size / 3); if (r) - return r; + goto out; break; case 0x02000001: // destroy @@ -591,7 +630,7 @@ int radeon_vce_cs_parse(struct radeon_cs_parser *p) r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, *size * 2); if (r) - return r; + goto out; break; case 0x05000004: // video bitstream buffer @@ -599,36 +638,47 @@ int radeon_vce_cs_parse(struct radeon_cs_parser *p) r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, tmp); if (r) - return r; + goto out; break; case 0x05000005: // feedback buffer r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, 4096); if (r) - return r; + goto out; break; default: DRM_ERROR("invalid VCE command (0x%x)!\n", cmd); - return -EINVAL; + r = -EINVAL; + goto out; } if (session_idx == -1) { DRM_ERROR("no session command at start of IB\n"); - return -EINVAL; + r = -EINVAL; + goto out; } p->idx += len / 4; } - if (destroyed) { - /* IB contains a destroy msg, free the handle */ + if (allocated && !created) { + DRM_ERROR("New session without create command!\n"); + r = -ENOENT; + } + +out: + if ((!r && destroyed) || (r && allocated)) { + /* + * IB contains a destroy msg or we have allocated an + * handle and got an error, anyway free the handle + */ for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) atomic_cmpxchg(&p->rdev->vce.handles[i], handle, 0); } - return 0; + return r; } /** @@ -647,12 +697,12 @@ bool radeon_vce_semaphore_emit(struct radeon_device *rdev, { uint64_t addr = semaphore->gpu_addr; - radeon_ring_write(ring, VCE_CMD_SEMAPHORE); - radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF); - radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF); - radeon_ring_write(ring, 0x01003000 | (emit_wait ? 1 : 0)); + radeon_ring_write(ring, cpu_to_le32(VCE_CMD_SEMAPHORE)); + radeon_ring_write(ring, cpu_to_le32((addr >> 3) & 0x000FFFFF)); + radeon_ring_write(ring, cpu_to_le32((addr >> 23) & 0x000FFFFF)); + radeon_ring_write(ring, cpu_to_le32(0x01003000 | (emit_wait ? 1 : 0))); if (!emit_wait) - radeon_ring_write(ring, VCE_CMD_END); + radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END)); return true; } @@ -667,10 +717,10 @@ bool radeon_vce_semaphore_emit(struct radeon_device *rdev, void radeon_vce_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) { struct radeon_ring *ring = &rdev->ring[ib->ring]; - radeon_ring_write(ring, VCE_CMD_IB); - radeon_ring_write(ring, ib->gpu_addr); - radeon_ring_write(ring, upper_32_bits(ib->gpu_addr)); - radeon_ring_write(ring, ib->length_dw); + radeon_ring_write(ring, cpu_to_le32(VCE_CMD_IB)); + radeon_ring_write(ring, cpu_to_le32(ib->gpu_addr)); + radeon_ring_write(ring, cpu_to_le32(upper_32_bits(ib->gpu_addr))); + radeon_ring_write(ring, cpu_to_le32(ib->length_dw)); } /** @@ -686,12 +736,12 @@ void radeon_vce_fence_emit(struct radeon_device *rdev, struct radeon_ring *ring = &rdev->ring[fence->ring]; uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr; - radeon_ring_write(ring, VCE_CMD_FENCE); - radeon_ring_write(ring, addr); - radeon_ring_write(ring, upper_32_bits(addr)); - radeon_ring_write(ring, fence->seq); - radeon_ring_write(ring, VCE_CMD_TRAP); - radeon_ring_write(ring, VCE_CMD_END); + radeon_ring_write(ring, cpu_to_le32(VCE_CMD_FENCE)); + radeon_ring_write(ring, cpu_to_le32(addr)); + radeon_ring_write(ring, cpu_to_le32(upper_32_bits(addr))); + radeon_ring_write(ring, cpu_to_le32(fence->seq)); + radeon_ring_write(ring, cpu_to_le32(VCE_CMD_TRAP)); + radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END)); } /** @@ -713,7 +763,7 @@ int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) ring->idx, r); return r; } - radeon_ring_write(ring, VCE_CMD_END); + radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END)); radeon_ring_unlock_commit(rdev, ring, false); for (i = 0; i < rdev->usec_timeout; i++) { @@ -758,12 +808,19 @@ int radeon_vce_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) goto error; } - r = radeon_fence_wait(fence, false); - if (r) { + r = radeon_fence_wait_timeout(fence, false, usecs_to_jiffies( + RADEON_USEC_IB_TEST_TIMEOUT)); + if (r < 0) { DRM_ERROR("radeon: fence wait failed (%d).\n", r); - } else { - DRM_INFO("ib test on ring %d succeeded\n", ring->idx); - } + } else if (r == 0) { + DRM_ERROR("radeon: fence wait timed out.\n"); +#if 0 + r = -ETIMEDOUT; +#endif + } else { + DRM_INFO("ib test on ring %d succeeded\n", ring->idx); + r = 0; + } error: radeon_fence_unref(&fence); return r; diff --git a/sys/dev/drm/radeon/radeon_vm.c b/sys/dev/drm/radeon/radeon_vm.c index 728a399f60..1448319558 100644 --- a/sys/dev/drm/radeon/radeon_vm.c +++ b/sys/dev/drm/radeon/radeon_vm.c @@ -127,39 +127,35 @@ void radeon_vm_manager_fini(struct radeon_device *rdev) * Add the page directory to the list of BOs to * validate for command submission (cayman+). */ -struct radeon_cs_reloc *radeon_vm_get_bos(struct radeon_device *rdev, +struct radeon_bo_list *radeon_vm_get_bos(struct radeon_device *rdev, struct radeon_vm *vm, struct list_head *head) { - struct radeon_cs_reloc *list; + struct radeon_bo_list *list; unsigned i, idx; list = drm_malloc_ab(vm->max_pde_used + 2, - sizeof(struct radeon_cs_reloc)); + sizeof(struct radeon_bo_list)); if (!list) return NULL; /* add the vm page table to the list */ - list[0].gobj = NULL; list[0].robj = vm->page_directory; list[0].prefered_domains = RADEON_GEM_DOMAIN_VRAM; list[0].allowed_domains = RADEON_GEM_DOMAIN_VRAM; list[0].tv.bo = &vm->page_directory->tbo; list[0].tiling_flags = 0; - list[0].handle = 0; list_add(&list[0].tv.head, head); for (i = 0, idx = 1; i <= vm->max_pde_used; i++) { if (!vm->page_tables[i].bo) continue; - list[idx].gobj = NULL; list[idx].robj = vm->page_tables[i].bo; list[idx].prefered_domains = RADEON_GEM_DOMAIN_VRAM; list[idx].allowed_domains = RADEON_GEM_DOMAIN_VRAM; list[idx].tv.bo = &list[idx].robj->tbo; list[idx].tiling_flags = 0; - list[idx].handle = 0; list_add(&list[idx++].tv.head, head); } @@ -182,6 +178,7 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev, struct radeon_vm *vm, int ring) { struct radeon_fence *best[RADEON_NUM_RINGS] = {}; + unsigned choices[2] = {}; unsigned i; @@ -244,13 +241,14 @@ void radeon_vm_flush(struct radeon_device *rdev, uint64_t pd_addr = radeon_bo_gpu_offset(vm->page_directory); /* if we can't remember our last VM flush then flush now! */ - /* XXX figure out why we have to flush all the time */ - if (!vm->last_flush || true || pd_addr != vm->pd_gpu_addr) { + if (!vm->last_flush || pd_addr != vm->pd_gpu_addr) { #ifdef TRACE_TODO trace_radeon_vm_flush(pd_addr, ring, vm->id); #endif vm->pd_gpu_addr = pd_addr; - radeon_ring_vm_flush(rdev, ring, vm); + radeon_ring_vm_flush(rdev, &rdev->ring[ring], + vm->id, vm->pd_gpu_addr); + } } @@ -343,10 +341,10 @@ struct radeon_bo_va *radeon_vm_bo_add(struct radeon_device *rdev, INIT_LIST_HEAD(&bo_va->vm_list); INIT_LIST_HEAD(&bo_va->vm_status); - lockmgr(&vm->mutex, LK_EXCLUSIVE); + mutex_lock(&vm->mutex); list_add(&bo_va->vm_list, &vm->va); list_add_tail(&bo_va->bo_list, &bo->va); - lockmgr(&vm->mutex, LK_RELEASE); + mutex_unlock(&vm->mutex); return bo_va; } @@ -459,7 +457,7 @@ error: * Validate and set the offset requested within the vm address space. * Returns 0 for success, error for failure. * - * Object has to be reserved! + * Object has to be reserved and gets unreserved by this function! */ int radeon_vm_bo_set_addr(struct radeon_device *rdev, struct radeon_bo_va *bo_va, @@ -478,21 +476,23 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, /* make sure object fit at this offset */ eoffset = soffset + size; if (soffset >= eoffset) { - return -EINVAL; + r = -EINVAL; + goto error_unreserve; } last_pfn = eoffset / RADEON_GPU_PAGE_SIZE; if (last_pfn > rdev->vm_manager.max_pfn) { dev_err(rdev->dev, "va above limit (0x%08X > 0x%08X)\n", last_pfn, rdev->vm_manager.max_pfn); - return -EINVAL; + r = -EINVAL; + goto error_unreserve; } } else { eoffset = last_pfn = 0; } - lockmgr(&vm->mutex, LK_EXCLUSIVE); + mutex_lock(&vm->mutex); head = &vm->va; last_offset = 0; list_for_each_entry(tmp, &vm->va, vm_list) { @@ -510,8 +510,9 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, dev_err(rdev->dev, "bo %p va 0x%08X conflict with (bo %p 0x%08X 0x%08X)\n", bo_va->bo, (unsigned)bo_va->soffset, tmp->bo, (unsigned)tmp->soffset, (unsigned)tmp->eoffset); - lockmgr(&vm->mutex, LK_RELEASE); - return -EINVAL; + mutex_unlock(&vm->mutex); + r = -EINVAL; + goto error_unreserve; } last_offset = tmp->eoffset; head = &tmp->vm_list; @@ -521,13 +522,17 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, /* add a clone of the bo_va to clear the old address */ tmp = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL); if (!tmp) { - lockmgr(&vm->mutex, LK_RELEASE); - return -ENOMEM; + mutex_unlock(&vm->mutex); + r = -ENOMEM; + goto error_unreserve; } tmp->soffset = bo_va->soffset; tmp->eoffset = bo_va->eoffset; tmp->vm = vm; - list_add(&tmp->vm_status, &vm->freed); + tmp->bo = radeon_bo_ref(bo_va->bo); + spin_lock(&vm->status_lock); + list_add(&tmp->vm_status, &vm->freed); + spin_unlock(&vm->status_lock); } bo_va->soffset = soffset; @@ -554,7 +559,7 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, continue; /* drop mutex to allocate and clear page table */ - lockmgr(&vm->mutex, LK_RELEASE); + mutex_unlock(&vm->mutex); r = radeon_bo_create(rdev, RADEON_VM_PTE_COUNT * 8, RADEON_GPU_PAGE_SIZE, true, @@ -565,17 +570,16 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, r = radeon_vm_clear_bo(rdev, pt); if (r) { radeon_bo_unref(&pt); - radeon_bo_reserve(bo_va->bo, false); return r; } /* aquire mutex again */ - lockmgr(&vm->mutex, LK_EXCLUSIVE); + mutex_lock(&vm->mutex); if (vm->page_tables[pt_idx].bo) { /* someone else allocated the pt in the meantime */ - lockmgr(&vm->mutex, LK_RELEASE); + mutex_unlock(&vm->mutex); radeon_bo_unref(&pt); - lockmgr(&vm->mutex, LK_EXCLUSIVE); + mutex_lock(&vm->mutex); continue; } @@ -583,8 +587,12 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, vm->page_tables[pt_idx].bo = pt; } - lockmgr(&vm->mutex, LK_RELEASE); - return radeon_bo_reserve(bo_va->bo, false); + mutex_unlock(&vm->mutex); + return 0; + +error_unreserve: + radeon_bo_unreserve(bo_va->bo); + return r; } /** @@ -602,10 +610,8 @@ uint64_t radeon_vm_map_gart(struct radeon_device *rdev, uint64_t addr) uint64_t result; /* page table offset */ - result = rdev->gart.pages_addr[addr >> PAGE_SHIFT]; - - /* in case cpu page size != gpu page size*/ - result |= addr & (PAGE_MASK); /* XXX */ + result = rdev->gart.pages_entry[addr >> RADEON_GPU_PAGE_SHIFT]; + result &= ~RADEON_GPU_PAGE_MASK; return result; } @@ -620,6 +626,7 @@ uint64_t radeon_vm_map_gart(struct radeon_device *rdev, uint64_t addr) static uint32_t radeon_vm_page_flags(uint32_t flags) { uint32_t hw_flags = 0; + hw_flags |= (flags & RADEON_VM_PAGE_VALID) ? R600_PTE_VALID : 0; hw_flags |= (flags & RADEON_VM_PAGE_READABLE) ? R600_PTE_READABLE : 0; hw_flags |= (flags & RADEON_VM_PAGE_WRITEABLE) ? R600_PTE_WRITEABLE : 0; @@ -761,9 +768,11 @@ static void radeon_vm_frag_ptes(struct radeon_device *rdev, */ /* NI is optimized for 256KB fragments, SI and newer for 64KB */ - uint64_t frag_flags = rdev->family == CHIP_CAYMAN ? + uint64_t frag_flags = ((rdev->family == CHIP_CAYMAN) || + (rdev->family == CHIP_ARUBA)) ? R600_PTE_FRAG_256KB : R600_PTE_FRAG_64KB; - uint64_t frag_align = rdev->family == CHIP_CAYMAN ? 0x200 : 0x80; + uint64_t frag_align = ((rdev->family == CHIP_CAYMAN) || + (rdev->family == CHIP_ARUBA)) ? 0x200 : 0x80; uint64_t frag_start = ALIGN(pe_start, frag_align); uint64_t frag_end = pe_end & ~(frag_align - 1); @@ -903,7 +912,9 @@ int radeon_vm_bo_update(struct radeon_device *rdev, return -EINVAL; } - list_del_init(&bo_va->vm_status); + spin_lock(&vm->status_lock); + list_del_init(&bo_va->vm_status); + spin_unlock(&vm->status_lock); bo_va->flags &= ~RADEON_VM_PAGE_VALID; bo_va->flags &= ~RADEON_VM_PAGE_SYSTEM; @@ -1005,15 +1016,24 @@ int radeon_vm_bo_update(struct radeon_device *rdev, int radeon_vm_clear_freed(struct radeon_device *rdev, struct radeon_vm *vm) { - struct radeon_bo_va *bo_va, *tmp; + struct radeon_bo_va *bo_va; int r; - list_for_each_entry_safe(bo_va, tmp, &vm->freed, vm_status) { + spin_lock(&vm->status_lock); + while (!list_empty(&vm->freed)) { + bo_va = list_first_entry(&vm->freed, + struct radeon_bo_va, vm_status); + spin_unlock(&vm->status_lock); + r = radeon_vm_bo_update(rdev, bo_va, NULL); + radeon_bo_unref(&bo_va->bo); kfree(bo_va); if (r) return r; - } + + spin_lock(&vm->status_lock); + } + spin_unlock(&vm->status_lock); return 0; } @@ -1032,14 +1052,23 @@ int radeon_vm_clear_freed(struct radeon_device *rdev, int radeon_vm_clear_invalids(struct radeon_device *rdev, struct radeon_vm *vm) { - struct radeon_bo_va *bo_va, *tmp; + struct radeon_bo_va *bo_va; int r; - list_for_each_entry_safe(bo_va, tmp, &vm->invalidated, vm_status) { - r = radeon_vm_bo_update(rdev, bo_va, NULL); - if (r) - return r; - } + spin_lock(&vm->status_lock); + while (!list_empty(&vm->invalidated)) { + bo_va = list_first_entry(&vm->invalidated, + struct radeon_bo_va, vm_status); + spin_unlock(&vm->status_lock); + + r = radeon_vm_bo_update(rdev, bo_va, NULL); + if (r) + return r; + + spin_lock(&vm->status_lock); + } + spin_unlock(&vm->status_lock); + return 0; } @@ -1060,18 +1089,20 @@ void radeon_vm_bo_rmv(struct radeon_device *rdev, list_del(&bo_va->bo_list); - lockmgr(&vm->mutex, LK_EXCLUSIVE); + mutex_lock(&vm->mutex); list_del(&bo_va->vm_list); + spin_lock(&vm->status_lock); list_del(&bo_va->vm_status); if (bo_va->addr) { - bo_va->bo = NULL; + bo_va->bo = radeon_bo_ref(bo_va->bo); list_add(&bo_va->vm_status, &vm->freed); } else { kfree(bo_va); } + spin_unlock(&vm->status_lock); - lockmgr(&vm->mutex, LK_RELEASE); + mutex_unlock(&vm->mutex); } /** @@ -1090,10 +1121,10 @@ void radeon_vm_bo_invalidate(struct radeon_device *rdev, list_for_each_entry(bo_va, &bo->va, bo_list) { if (bo_va->addr) { - mutex_lock(&bo_va->vm->mutex); + spin_lock(&bo_va->vm->status_lock); list_del(&bo_va->vm_status); list_add(&bo_va->vm_status, &bo_va->vm->invalidated); - mutex_unlock(&bo_va->vm->mutex); + spin_unlock(&bo_va->vm->status_lock); } } } @@ -1120,6 +1151,7 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm) vm->last_id_use = NULL; lockinit(&vm->mutex, "rvmmtx", 0, LK_CANRECURSE); INIT_LIST_HEAD(&vm->va); + spin_init(&vm->status_lock, "rvmspi"); INIT_LIST_HEAD(&vm->invalidated); INIT_LIST_HEAD(&vm->freed); @@ -1176,8 +1208,10 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm) kfree(bo_va); } } - list_for_each_entry_safe(bo_va, tmp, &vm->freed, vm_status) - kfree(bo_va); + list_for_each_entry_safe(bo_va, tmp, &vm->freed, vm_status) { + radeon_bo_unref(&bo_va->bo); + kfree(bo_va); + } for (i = 0; i < radeon_vm_num_pdes(rdev); i++) radeon_bo_unref(&vm->page_tables[i].bo); diff --git a/sys/dev/drm/radeon/rs400.c b/sys/dev/drm/radeon/rs400.c index 6780424b79..8edc8598d5 100644 --- a/sys/dev/drm/radeon/rs400.c +++ b/sys/dev/drm/radeon/rs400.c @@ -210,11 +210,9 @@ void rs400_gart_fini(struct radeon_device *rdev) #define RS400_PTE_WRITEABLE (1 << 2) #define RS400_PTE_READABLE (1 << 3) -void rs400_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags) +uint64_t rs400_gart_get_page_entry(uint64_t addr, uint32_t flags) { uint32_t entry; - u32 *gtt = rdev->gart.ptr; entry = (lower_32_bits(addr) & 0xfffff000) | ((upper_32_bits(addr) & 0xff) << 4); @@ -224,8 +222,14 @@ void rs400_gart_set_page(struct radeon_device *rdev, unsigned i, entry |= RS400_PTE_WRITEABLE; if (!(flags & RADEON_GART_PAGE_SNOOP)) entry |= RS400_PTE_UNSNOOPED; - entry = cpu_to_le32(entry); - gtt[i] = entry; + return entry; +} + +void rs400_gart_set_page(struct radeon_device *rdev, unsigned i, + uint64_t entry) +{ + u32 *gtt = rdev->gart.ptr; + gtt[i] = cpu_to_le32(lower_32_bits(entry)); } int rs400_mc_wait_for_idle(struct radeon_device *rdev) @@ -273,23 +277,26 @@ static void rs400_mc_init(struct radeon_device *rdev) uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg) { + unsigned long flags; uint32_t r; - spin_lock(&rdev->mc_idx_lock); + spin_lock_irqsave(&rdev->mc_idx_lock, flags); WREG32(RS480_NB_MC_INDEX, reg & 0xff); r = RREG32(RS480_NB_MC_DATA); WREG32(RS480_NB_MC_INDEX, 0xff); - spin_unlock(&rdev->mc_idx_lock); + spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); return r; } void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) { - spin_lock(&rdev->mc_idx_lock); + unsigned long flags; + + spin_lock_irqsave(&rdev->mc_idx_lock, flags); WREG32(RS480_NB_MC_INDEX, ((reg) & 0xff) | RS480_NB_MC_IND_WR_EN); WREG32(RS480_NB_MC_DATA, (v)); WREG32(RS480_NB_MC_INDEX, 0xff); - spin_unlock(&rdev->mc_idx_lock); + spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); } #if defined(CONFIG_DEBUG_FS) diff --git a/sys/dev/drm/radeon/rs600.c b/sys/dev/drm/radeon/rs600.c index 90e84f505d..bbef9dca3b 100644 --- a/sys/dev/drm/radeon/rs600.c +++ b/sys/dev/drm/radeon/rs600.c @@ -38,6 +38,7 @@ #include #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include "atom.h" #include "rs600d.h" @@ -108,7 +109,7 @@ void avivo_wait_for_vblank(struct radeon_device *rdev, int crtc) } } -void rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) +void rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base, bool async) { struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset); @@ -119,6 +120,8 @@ void rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); /* update the scanout addresses */ + WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, + async ? AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN : 0); WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, (u32)crtc_base); WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, @@ -411,7 +414,8 @@ void rs600_hpd_init(struct radeon_device *rdev) default: break; } - enable |= 1 << radeon_connector->hpd.hpd; + if (radeon_connector->hpd.hpd != RADEON_HPD_NONE) + enable |= 1 << radeon_connector->hpd.hpd; radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); } radeon_irq_kms_enable_hpd(rdev, enable); @@ -437,12 +441,13 @@ void rs600_hpd_fini(struct radeon_device *rdev) default: break; } - disable |= 1 << radeon_connector->hpd.hpd; + if (radeon_connector->hpd.hpd != RADEON_HPD_NONE) + disable |= 1 << radeon_connector->hpd.hpd; } radeon_irq_kms_disable_hpd(rdev, disable); } -int rs600_asic_reset(struct radeon_device *rdev) +int rs600_asic_reset(struct radeon_device *rdev, bool hard) { struct rv515_mc_save save; u32 status, tmp; @@ -624,11 +629,8 @@ static void rs600_gart_fini(struct radeon_device *rdev) radeon_gart_table_vram_free(rdev); } -void rs600_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags) +uint64_t rs600_gart_get_page_entry(uint64_t addr, uint32_t flags) { - uint64_t *ptr = rdev->gart.ptr; - addr = addr & 0xFFFFFFFFFFFFF000ULL; addr |= R600_PTE_SYSTEM; if (flags & RADEON_GART_PAGE_VALID) @@ -639,7 +641,14 @@ void rs600_gart_set_page(struct radeon_device *rdev, unsigned i, addr |= R600_PTE_WRITEABLE; if (flags & RADEON_GART_PAGE_SNOOP) addr |= R600_PTE_SNOOPED; - ptr[i] = addr; + return addr; +} + +void rs600_gart_set_page(struct radeon_device *rdev, unsigned i, + uint64_t entry) +{ + uint64_t *ptr = rdev->gart.ptr; + ptr[i] = entry; } int rs600_irq_set(struct radeon_device *rdev) @@ -688,6 +697,10 @@ int rs600_irq_set(struct radeon_device *rdev) WREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL, hpd2); if (ASIC_IS_DCE2(rdev)) WREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL, hdmi0); + + /* posting read */ + RREG32(R_000040_GEN_INT_CNTL); + return 0; } @@ -904,23 +917,26 @@ void rs600_bandwidth_update(struct radeon_device *rdev) uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg) { + unsigned long flags; u32 r; - spin_lock(&rdev->mc_idx_lock); + spin_lock_irqsave(&rdev->mc_idx_lock, flags); WREG32(R_000070_MC_IND_INDEX, S_000070_MC_IND_ADDR(reg) | S_000070_MC_IND_CITF_ARB0(1)); r = RREG32(R_000074_MC_IND_DATA); - spin_unlock(&rdev->mc_idx_lock); + spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); return r; } void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) { - spin_lock(&rdev->mc_idx_lock); + unsigned long flags; + + spin_lock_irqsave(&rdev->mc_idx_lock, flags); WREG32(R_000070_MC_IND_INDEX, S_000070_MC_IND_ADDR(reg) | S_000070_MC_IND_CITF_ARB0(1) | S_000070_MC_IND_WR_EN(1)); WREG32(R_000074_MC_IND_DATA, v); - spin_unlock(&rdev->mc_idx_lock); + spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); } static void rs600_debugfs(struct radeon_device *rdev) @@ -1008,7 +1024,7 @@ static int rs600_startup(struct radeon_device *rdev) return r; } - r = r600_audio_init(rdev); + r = radeon_audio_init(rdev); if (r) { dev_err(rdev->dev, "failed initializing audio\n"); return r; @@ -1049,7 +1065,7 @@ int rs600_resume(struct radeon_device *rdev) int rs600_suspend(struct radeon_device *rdev) { radeon_pm_suspend(rdev); - r600_audio_fini(rdev); + radeon_audio_fini(rdev); r100_cp_disable(rdev); radeon_wb_disable(rdev); rs600_irq_disable(rdev); @@ -1060,7 +1076,7 @@ int rs600_suspend(struct radeon_device *rdev) void rs600_fini(struct radeon_device *rdev) { radeon_pm_fini(rdev); - r600_audio_fini(rdev); + radeon_audio_fini(rdev); r100_cp_fini(rdev); radeon_wb_fini(rdev); radeon_ib_pool_fini(rdev); diff --git a/sys/dev/drm/radeon/rs690.c b/sys/dev/drm/radeon/rs690.c index f9d31facf7..75bd883c33 100644 --- a/sys/dev/drm/radeon/rs690.c +++ b/sys/dev/drm/radeon/rs690.c @@ -28,6 +28,7 @@ #include #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include "atom.h" #include "rs690d.h" @@ -206,6 +207,9 @@ void rs690_line_buffer_adjust(struct radeon_device *rdev, { u32 tmp; + /* Guess line buffer size to be 8192 pixels */ + u32 lb_size = 8192; + /* * Line Buffer Setup * There is a single line buffer shared by both display controllers. @@ -242,6 +246,13 @@ void rs690_line_buffer_adjust(struct radeon_device *rdev, tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q; } WREG32(R_006520_DC_LB_MEMORY_SPLIT, tmp); + + /* Save number of lines the linebuffer leads before the scanout */ + if (mode1) + rdev->mode_info.crtcs[0]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode1->crtc_hdisplay); + + if (mode2) + rdev->mode_info.crtcs[1]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode2->crtc_hdisplay); } struct rs690_watermark { @@ -639,24 +650,27 @@ void rs690_bandwidth_update(struct radeon_device *rdev) uint32_t rs690_mc_rreg(struct radeon_device *rdev, uint32_t reg) { + unsigned long flags; uint32_t r; - spin_lock(&rdev->mc_idx_lock); + spin_lock_irqsave(&rdev->mc_idx_lock, flags); WREG32(R_000078_MC_INDEX, S_000078_MC_IND_ADDR(reg)); r = RREG32(R_00007C_MC_DATA); WREG32(R_000078_MC_INDEX, ~C_000078_MC_IND_ADDR); - spin_unlock(&rdev->mc_idx_lock); + spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); return r; } void rs690_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) { - spin_lock(&rdev->mc_idx_lock); + unsigned long flags; + + spin_lock_irqsave(&rdev->mc_idx_lock, flags); WREG32(R_000078_MC_INDEX, S_000078_MC_IND_ADDR(reg) | S_000078_MC_IND_WR_EN(1)); WREG32(R_00007C_MC_DATA, v); WREG32(R_000078_MC_INDEX, 0x7F); - spin_unlock(&rdev->mc_idx_lock); + spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); } static void rs690_mc_program(struct radeon_device *rdev) @@ -727,7 +741,7 @@ static int rs690_startup(struct radeon_device *rdev) return r; } - r = r600_audio_init(rdev); + r = radeon_audio_init(rdev); if (r) { dev_err(rdev->dev, "failed initializing audio\n"); return r; @@ -768,7 +782,7 @@ int rs690_resume(struct radeon_device *rdev) int rs690_suspend(struct radeon_device *rdev) { radeon_pm_suspend(rdev); - r600_audio_fini(rdev); + radeon_audio_fini(rdev); r100_cp_disable(rdev); radeon_wb_disable(rdev); rs600_irq_disable(rdev); @@ -779,7 +793,7 @@ int rs690_suspend(struct radeon_device *rdev) void rs690_fini(struct radeon_device *rdev) { radeon_pm_fini(rdev); - r600_audio_fini(rdev); + radeon_audio_fini(rdev); r100_cp_fini(rdev); radeon_wb_fini(rdev); radeon_ib_pool_fini(rdev); diff --git a/sys/dev/drm/radeon/rs780_dpm.c b/sys/dev/drm/radeon/rs780_dpm.c index fc4b41e63a..918d68577c 100644 --- a/sys/dev/drm/radeon/rs780_dpm.c +++ b/sys/dev/drm/radeon/rs780_dpm.c @@ -1001,6 +1001,28 @@ void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rde ps->sclk_high, ps->max_voltage); } +/* get the current sclk in 10 khz units */ +u32 rs780_dpm_get_current_sclk(struct radeon_device *rdev) +{ + u32 current_fb_div = RREG32(FVTHROT_STATUS_REG0) & CURRENT_FEEDBACK_DIV_MASK; + u32 func_cntl = RREG32(CG_SPLL_FUNC_CNTL); + u32 ref_div = ((func_cntl & SPLL_REF_DIV_MASK) >> SPLL_REF_DIV_SHIFT) + 1; + u32 post_div = ((func_cntl & SPLL_SW_HILEN_MASK) >> SPLL_SW_HILEN_SHIFT) + 1 + + ((func_cntl & SPLL_SW_LOLEN_MASK) >> SPLL_SW_LOLEN_SHIFT) + 1; + u32 sclk = (rdev->clock.spll.reference_freq * current_fb_div) / + (post_div * ref_div); + + return sclk; +} + +/* get the current mclk in 10 khz units */ +u32 rs780_dpm_get_current_mclk(struct radeon_device *rdev) +{ + struct igp_power_info *pi = rs780_get_pi(rdev); + + return pi->bootup_uma_clk; +} + int rs780_dpm_force_performance_level(struct radeon_device *rdev, enum radeon_dpm_forced_level level) { diff --git a/sys/dev/drm/radeon/rv515.c b/sys/dev/drm/radeon/rv515.c index 597e4647aa..b575cb5211 100644 --- a/sys/dev/drm/radeon/rv515.c +++ b/sys/dev/drm/radeon/rv515.c @@ -206,24 +206,27 @@ static void rv515_mc_init(struct radeon_device *rdev) uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg) { + unsigned long flags; uint32_t r; - spin_lock(&rdev->mc_idx_lock); + spin_lock_irqsave(&rdev->mc_idx_lock, flags); WREG32(MC_IND_INDEX, 0x7f0000 | (reg & 0xffff)); r = RREG32(MC_IND_DATA); WREG32(MC_IND_INDEX, 0); - spin_unlock(&rdev->mc_idx_lock); + spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); return r; } void rv515_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) { - spin_lock(&rdev->mc_idx_lock); + unsigned long flags; + + spin_lock_irqsave(&rdev->mc_idx_lock, flags); WREG32(MC_IND_INDEX, 0xff0000 | ((reg) & 0xffff)); WREG32(MC_IND_DATA, (v)); WREG32(MC_IND_INDEX, 0); - spin_unlock(&rdev->mc_idx_lock); + spin_unlock_irqrestore(&rdev->mc_idx_lock, flags); } #if defined(CONFIG_DEBUG_FS) diff --git a/sys/dev/drm/radeon/rv6xx_dpm.c b/sys/dev/drm/radeon/rv6xx_dpm.c index fd8ee72427..b36ec35c9a 100644 --- a/sys/dev/drm/radeon/rv6xx_dpm.c +++ b/sys/dev/drm/radeon/rv6xx_dpm.c @@ -2056,6 +2056,52 @@ void rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rde } } +/* get the current sclk in 10 khz units */ +u32 rv6xx_dpm_get_current_sclk(struct radeon_device *rdev) +{ + struct radeon_ps *rps = rdev->pm.dpm.current_ps; + struct rv6xx_ps *ps = rv6xx_get_ps(rps); + struct rv6xx_pl *pl; + u32 current_index = + (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >> + CURRENT_PROFILE_INDEX_SHIFT; + + if (current_index > 2) { + return 0; + } else { + if (current_index == 0) + pl = &ps->low; + else if (current_index == 1) + pl = &ps->medium; + else /* current_index == 2 */ + pl = &ps->high; + return pl->sclk; + } +} + +/* get the current mclk in 10 khz units */ +u32 rv6xx_dpm_get_current_mclk(struct radeon_device *rdev) +{ + struct radeon_ps *rps = rdev->pm.dpm.current_ps; + struct rv6xx_ps *ps = rv6xx_get_ps(rps); + struct rv6xx_pl *pl; + u32 current_index = + (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >> + CURRENT_PROFILE_INDEX_SHIFT; + + if (current_index > 2) { + return 0; + } else { + if (current_index == 0) + pl = &ps->low; + else if (current_index == 1) + pl = &ps->medium; + else /* current_index == 2 */ + pl = &ps->high; + return pl->mclk; + } +} + void rv6xx_dpm_fini(struct radeon_device *rdev) { int i; diff --git a/sys/dev/drm/radeon/rv730_dpm.c b/sys/dev/drm/radeon/rv730_dpm.c index 678571e044..38fdb4152e 100644 --- a/sys/dev/drm/radeon/rv730_dpm.c +++ b/sys/dev/drm/radeon/rv730_dpm.c @@ -464,7 +464,7 @@ void rv730_stop_dpm(struct radeon_device *rdev) result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_TwoLevelsDisabled); if (result != PPSMC_Result_OK) - DRM_ERROR("Could not force DPM to low\n"); + DRM_DEBUG("Could not force DPM to low\n"); WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN); diff --git a/sys/dev/drm/radeon/rv770.c b/sys/dev/drm/radeon/rv770.c index 74bfd96e00..1da646765a 100644 --- a/sys/dev/drm/radeon/rv770.c +++ b/sys/dev/drm/radeon/rv770.c @@ -29,6 +29,7 @@ #include #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include #include "rv770d.h" #include "atom.h" @@ -797,7 +798,7 @@ u32 rv770_get_xclk(struct radeon_device *rdev) return reference_clock; } -void rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) +void rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base, bool async) { struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset); @@ -808,6 +809,8 @@ void rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); /* update the scanout addresses */ + WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, + async ? AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN : 0); if (radeon_crtc->crtc_id) { WREG32(D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(crtc_base)); WREG32(D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(crtc_base)); @@ -1677,6 +1680,73 @@ static int rv770_mc_init(struct radeon_device *rdev) return 0; } +static void rv770_uvd_init(struct radeon_device *rdev) +{ + int r; + + if (!rdev->has_uvd) + return; + + r = radeon_uvd_init(rdev); + if (r) { + dev_err(rdev->dev, "failed UVD (%d) init.\n", r); + /* + * At this point rdev->uvd.vcpu_bo is NULL which trickles down + * to early fails uvd_v2_2_resume() and thus nothing happens + * there. So it is pointless to try to go through that code + * hence why we disable uvd here. + */ + rdev->has_uvd = 0; + return; + } + rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL; + r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX], 4096); +} + +static void rv770_uvd_start(struct radeon_device *rdev) +{ + int r; + + if (!rdev->has_uvd) + return; + + r = uvd_v2_2_resume(rdev); + if (r) { + dev_err(rdev->dev, "failed UVD resume (%d).\n", r); + goto error; + } + r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX); + if (r) { + dev_err(rdev->dev, "failed initializing UVD fences (%d).\n", r); + goto error; + } + return; + +error: + rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; +} + +static void rv770_uvd_resume(struct radeon_device *rdev) +{ + struct radeon_ring *ring; + int r; + + if (!rdev->has_uvd || !rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size) + return; + + ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; + r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2); + if (r) { + dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r); + return; + } + r = uvd_v1_0_init(rdev); + if (r) { + dev_err(rdev->dev, "failed initializing UVD (%d).\n", r); + return; + } +} + static int rv770_startup(struct radeon_device *rdev) { struct radeon_ring *ring; @@ -1719,16 +1789,7 @@ static int rv770_startup(struct radeon_device *rdev) return r; } - r = uvd_v2_2_resume(rdev); - if (!r) { - r = radeon_fence_driver_start_ring(rdev, - R600_RING_TYPE_UVD_INDEX); - if (r) - dev_err(rdev->dev, "UVD fences init error (%d).\n", r); - } - - if (r) - rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; + rv770_uvd_start(rdev); /* Enable IRQ */ if (!rdev->irq.installed) { @@ -1768,16 +1829,7 @@ static int rv770_startup(struct radeon_device *rdev) if (r) return r; - ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; - if (ring->ring_size) { - r = radeon_ring_init(rdev, ring, ring->ring_size, 0, - RADEON_CP_PACKET2); - if (!r) - r = uvd_v1_0_init(rdev); - - if (r) - DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); - } + rv770_uvd_resume(rdev); r = radeon_ib_pool_init(rdev); if (r) { @@ -1785,7 +1837,7 @@ static int rv770_startup(struct radeon_device *rdev) return r; } - r = r600_audio_init(rdev); + r = radeon_audio_init(rdev); if (r) { DRM_ERROR("radeon: audio init failed\n"); return r; @@ -1826,9 +1878,11 @@ int rv770_resume(struct radeon_device *rdev) int rv770_suspend(struct radeon_device *rdev) { radeon_pm_suspend(rdev); - r600_audio_fini(rdev); + radeon_audio_fini(rdev); + if (rdev->has_uvd) { uvd_v1_0_fini(rdev); radeon_uvd_suspend(rdev); + } r700_cp_stop(rdev); r600_dma_stop(rdev); r600_irq_suspend(rdev); @@ -1913,12 +1967,7 @@ int rv770_init(struct radeon_device *rdev) rdev->ring[R600_RING_TYPE_DMA_INDEX].ring_obj = NULL; r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX], 64 * 1024); - r = radeon_uvd_init(rdev); - if (!r) { - rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL; - r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX], - 4096); - } + rv770_uvd_init(rdev); rdev->ih.ring_obj = NULL; r600_ih_ring_init(rdev, 64 * 1024); @@ -1991,7 +2040,7 @@ static void rv770_pcie_gen2_enable(struct radeon_device *rdev) if (ret != 0) return; - if (!(mask & DRM_PCIE_SPEED_50)) + if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80))) return; DRM_INFO("enabling PCIE gen 2 link speeds, disable with radeon.pcie_gen2=0\n"); diff --git a/sys/dev/drm/radeon/rv770_dpm.c b/sys/dev/drm/radeon/rv770_dpm.c index 8e550d0c79..9e2164e250 100644 --- a/sys/dev/drm/radeon/rv770_dpm.c +++ b/sys/dev/drm/radeon/rv770_dpm.c @@ -197,7 +197,7 @@ void rv770_stop_dpm(struct radeon_device *rdev) result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_TwoLevelsDisabled); if (result != PPSMC_Result_OK) - DRM_ERROR("Could not force DPM to low.\n"); + DRM_DEBUG("Could not force DPM to low.\n"); WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN); @@ -1422,7 +1422,7 @@ int rv770_resume_smc(struct radeon_device *rdev) int rv770_set_sw_state(struct radeon_device *rdev) { if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToSwState) != PPSMC_Result_OK) - return -EINVAL; + DRM_DEBUG("rv770_set_sw_state failed\n"); return 0; } @@ -2496,6 +2496,50 @@ void rv770_dpm_debugfs_print_current_performance_level(struct radeon_device *rde } } +u32 rv770_dpm_get_current_sclk(struct radeon_device *rdev) +{ + struct radeon_ps *rps = rdev->pm.dpm.current_ps; + struct rv7xx_ps *ps = rv770_get_ps(rps); + struct rv7xx_pl *pl; + u32 current_index = + (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >> + CURRENT_PROFILE_INDEX_SHIFT; + + if (current_index > 2) { + return 0; + } else { + if (current_index == 0) + pl = &ps->low; + else if (current_index == 1) + pl = &ps->medium; + else /* current_index == 2 */ + pl = &ps->high; + return pl->sclk; + } +} + +u32 rv770_dpm_get_current_mclk(struct radeon_device *rdev) +{ + struct radeon_ps *rps = rdev->pm.dpm.current_ps; + struct rv7xx_ps *ps = rv770_get_ps(rps); + struct rv7xx_pl *pl; + u32 current_index = + (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >> + CURRENT_PROFILE_INDEX_SHIFT; + + if (current_index > 2) { + return 0; + } else { + if (current_index == 0) + pl = &ps->low; + else if (current_index == 1) + pl = &ps->medium; + else /* current_index == 2 */ + pl = &ps->high; + return pl->mclk; + } +} + void rv770_dpm_fini(struct radeon_device *rdev) { int i; diff --git a/sys/dev/drm/radeon/rv770_smc.c b/sys/dev/drm/radeon/rv770_smc.c index 3a570ad46e..2b7ddee398 100644 --- a/sys/dev/drm/radeon/rv770_smc.c +++ b/sys/dev/drm/radeon/rv770_smc.c @@ -296,6 +296,7 @@ int rv770_copy_bytes_to_smc(struct radeon_device *rdev, u16 smc_start_address, const u8 *src, u16 byte_count, u16 limit) { + unsigned long flags; u32 data, original_data, extra_shift; u16 addr; int ret = 0; @@ -307,7 +308,7 @@ int rv770_copy_bytes_to_smc(struct radeon_device *rdev, addr = smc_start_address; - spin_lock(&rdev->smc_idx_lock); + spin_lock_irqsave(&rdev->smc_idx_lock, flags); while (byte_count >= 4) { /* SMC address space is BE */ data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]; @@ -353,7 +354,7 @@ int rv770_copy_bytes_to_smc(struct radeon_device *rdev, } done: - spin_unlock(&rdev->smc_idx_lock); + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); return ret; } @@ -465,14 +466,15 @@ PPSMC_Result rv770_wait_for_smc_inactive(struct radeon_device *rdev) static void rv770_clear_smc_sram(struct radeon_device *rdev, u16 limit) { + unsigned long flags; u16 i; - spin_lock(&rdev->smc_idx_lock); + spin_lock_irqsave(&rdev->smc_idx_lock, flags); for (i = 0; i < limit; i += 4) { rv770_set_smc_sram_address(rdev, i, limit); WREG32(SMC_SRAM_DATA, 0); } - spin_unlock(&rdev->smc_idx_lock); + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); } int rv770_load_smc_ucode(struct radeon_device *rdev, @@ -601,13 +603,14 @@ int rv770_load_smc_ucode(struct radeon_device *rdev, int rv770_read_smc_sram_dword(struct radeon_device *rdev, u16 smc_address, u32 *value, u16 limit) { + unsigned long flags; int ret; - spin_lock(&rdev->smc_idx_lock); + spin_lock_irqsave(&rdev->smc_idx_lock, flags); ret = rv770_set_smc_sram_address(rdev, smc_address, limit); if (ret == 0) *value = RREG32(SMC_SRAM_DATA); - spin_unlock(&rdev->smc_idx_lock); + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); return ret; } @@ -615,13 +618,14 @@ int rv770_read_smc_sram_dword(struct radeon_device *rdev, int rv770_write_smc_sram_dword(struct radeon_device *rdev, u16 smc_address, u32 value, u16 limit) { + unsigned long flags; int ret; - spin_lock(&rdev->smc_idx_lock); + spin_lock_irqsave(&rdev->smc_idx_lock, flags); ret = rv770_set_smc_sram_address(rdev, smc_address, limit); if (ret == 0) WREG32(SMC_SRAM_DATA, value); - spin_unlock(&rdev->smc_idx_lock); + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); return ret; } diff --git a/sys/dev/drm/radeon/rv770d.h b/sys/dev/drm/radeon/rv770d.h index 3cf1e29215..9ef2064b1c 100644 --- a/sys/dev/drm/radeon/rv770d.h +++ b/sys/dev/drm/radeon/rv770d.h @@ -989,6 +989,9 @@ ((n) & 0x3FFF) << 16) /* UVD */ +#define UVD_SEMA_ADDR_LOW 0xef00 +#define UVD_SEMA_ADDR_HIGH 0xef04 +#define UVD_SEMA_CMD 0xef08 #define UVD_GPCOM_VCPU_CMD 0xef0c #define UVD_GPCOM_VCPU_DATA0 0xef10 #define UVD_GPCOM_VCPU_DATA1 0xef14 diff --git a/sys/dev/drm/radeon/si.c b/sys/dev/drm/radeon/si.c index 447dfb736e..efb64bb839 100644 --- a/sys/dev/drm/radeon/si.c +++ b/sys/dev/drm/radeon/si.c @@ -26,6 +26,7 @@ #include #include "radeon.h" #include "radeon_asic.h" +#include "radeon_audio.h" #include #include "sid.h" #include "atom.h" @@ -120,6 +121,8 @@ static void si_fini_pg(struct radeon_device *rdev); static void si_fini_cg(struct radeon_device *rdev); static void si_rlc_stop(struct radeon_device *rdev); +int si_vce_send_vcepll_ctlreq(struct radeon_device *rdev); + static const u32 verde_rlc_save_restore_register_list[] = { (0x8000 << 16) | (0x98f4 >> 2), @@ -1252,6 +1255,36 @@ static void si_init_golden_registers(struct radeon_device *rdev) } } +/** + * si_get_allowed_info_register - fetch the register for the info ioctl + * + * @rdev: radeon_device pointer + * @reg: register offset in bytes + * @val: register value + * + * Returns 0 for success or -EINVAL for an invalid register + * + */ +int si_get_allowed_info_register(struct radeon_device *rdev, + u32 reg, u32 *val) +{ + switch (reg) { + case GRBM_STATUS: + case GRBM_STATUS2: + case GRBM_STATUS_SE0: + case GRBM_STATUS_SE1: + case SRBM_STATUS: + case SRBM_STATUS2: + case (DMA_STATUS_REG + DMA0_REGISTER_OFFSET): + case (DMA_STATUS_REG + DMA1_REGISTER_OFFSET): + case UVD_STATUS: + *val = RREG32(reg); + return 0; + default: + return -EINVAL; + } +} + #define PCIE_BUS_CLK 10000 #define TCLK (PCIE_BUS_CLK / 10) @@ -2358,6 +2391,9 @@ static void dce6_program_watermarks(struct radeon_device *rdev, c.full = dfixed_div(c, a); priority_b_mark = dfixed_trunc(c); priority_b_cnt |= priority_b_mark & PRIORITY_MARK_MASK; + + /* Save number of lines the linebuffer leads before the scanout */ + radeon_crtc->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay); } /* select wm A */ @@ -2421,8 +2457,10 @@ void dce6_bandwidth_update(struct radeon_device *rdev) */ static void si_tiling_mode_table_init(struct radeon_device *rdev) { - const u32 num_tile_mode_states = 32; - u32 reg_offset, gb_tile_moden, split_equal_to_row_size; + u32 *tile = rdev->config.si.tile_mode_array; + const u32 num_tile_mode_states = + ARRAY_SIZE(rdev->config.si.tile_mode_array); + u32 reg_offset, split_equal_to_row_size; switch (rdev->config.si.mem_row_size_in_kb) { case 1: @@ -2437,491 +2475,442 @@ static void si_tiling_mode_table_init(struct radeon_device *rdev) break; } - if ((rdev->family == CHIP_TAHITI) || - (rdev->family == CHIP_PITCAIRN)) { - for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) { - switch (reg_offset) { - case 0: /* non-AA compressed depth or any compressed stencil */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 1: /* 2xAA/4xAA compressed depth only */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 2: /* 8xAA compressed depth only */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 3: /* 2xAA/4xAA compressed depth with stencil (for depth buffer) */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 4: /* Maps w/ a dimension less than the 2D macro-tile dimensions (for mipmapped depth textures) */ - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 5: /* Uncompressed 16bpp depth - and stencil buffer allocated with it */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(split_equal_to_row_size) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 6: /* Uncompressed 32bpp depth - and stencil buffer allocated with it */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(split_equal_to_row_size) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); - break; - case 7: /* Uncompressed 8bpp stencil without depth (drivers typically do not use) */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(split_equal_to_row_size) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 8: /* 1D and 1D Array Surfaces */ - gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | - MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 9: /* Displayable maps. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 10: /* Display 8bpp. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 11: /* Display 16bpp. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 12: /* Display 32bpp. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); - break; - case 13: /* Thin. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 14: /* Thin 8 bpp. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); - break; - case 15: /* Thin 16 bpp. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); - break; - case 16: /* Thin 32 bpp. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); - break; - case 17: /* Thin 64 bpp. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(split_equal_to_row_size) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); - break; - case 21: /* 8 bpp PRT. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 22: /* 16 bpp PRT */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); - break; - case 23: /* 32 bpp PRT */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 24: /* 64 bpp PRT */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 25: /* 128 bpp PRT */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | - NUM_BANKS(ADDR_SURF_8_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); - break; - default: - gb_tile_moden = 0; - break; - } - rdev->config.si.tile_mode_array[reg_offset] = gb_tile_moden; - WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden); - } - } else if ((rdev->family == CHIP_VERDE) || - (rdev->family == CHIP_OLAND) || - (rdev->family == CHIP_HAINAN)) { - for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) { - switch (reg_offset) { - case 0: /* non-AA compressed depth or any compressed stencil */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); - break; - case 1: /* 2xAA/4xAA compressed depth only */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); - break; - case 2: /* 8xAA compressed depth only */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); - break; - case 3: /* 2xAA/4xAA compressed depth with stencil (for depth buffer) */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); - break; - case 4: /* Maps w/ a dimension less than the 2D macro-tile dimensions (for mipmapped depth textures) */ - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 5: /* Uncompressed 16bpp depth - and stencil buffer allocated with it */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(split_equal_to_row_size) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 6: /* Uncompressed 32bpp depth - and stencil buffer allocated with it */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(split_equal_to_row_size) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 7: /* Uncompressed 8bpp stencil without depth (drivers typically do not use) */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(split_equal_to_row_size) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); - break; - case 8: /* 1D and 1D Array Surfaces */ - gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | - MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 9: /* Displayable maps. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 10: /* Display 8bpp. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); - break; - case 11: /* Display 16bpp. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 12: /* Display 32bpp. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 13: /* Thin. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 14: /* Thin 8 bpp. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 15: /* Thin 16 bpp. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 16: /* Thin 32 bpp. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 17: /* Thin 64 bpp. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(split_equal_to_row_size) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 21: /* 8 bpp PRT. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 22: /* 16 bpp PRT */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); - break; - case 23: /* 32 bpp PRT */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 24: /* 64 bpp PRT */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); - break; - case 25: /* 128 bpp PRT */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | - NUM_BANKS(ADDR_SURF_8_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); - break; - default: - gb_tile_moden = 0; - break; - } - rdev->config.si.tile_mode_array[reg_offset] = gb_tile_moden; - WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden); - } - } else + for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) + tile[reg_offset] = 0; + + switch(rdev->family) { + case CHIP_TAHITI: + case CHIP_PITCAIRN: + /* non-AA compressed depth or any compressed stencil */ + tile[0] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* 2xAA/4xAA compressed depth only */ + tile[1] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* 8xAA compressed depth only */ + tile[2] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* 2xAA/4xAA compressed depth with stencil (for depth buffer) */ + tile[3] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* Maps w/ a dimension less than the 2D macro-tile dimensions (for mipmapped depth textures) */ + tile[4] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* Uncompressed 16bpp depth - and stencil buffer allocated with it */ + tile[5] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(split_equal_to_row_size) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* Uncompressed 32bpp depth - and stencil buffer allocated with it */ + tile[6] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(split_equal_to_row_size) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); + /* Uncompressed 8bpp stencil without depth (drivers typically do not use) */ + tile[7] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(split_equal_to_row_size) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* 1D and 1D Array Surfaces */ + tile[8] = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | + MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* Displayable maps. */ + tile[9] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* Display 8bpp. */ + tile[10] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* Display 16bpp. */ + tile[11] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* Display 32bpp. */ + tile[12] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); + /* Thin. */ + tile[13] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* Thin 8 bpp. */ + tile[14] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); + /* Thin 16 bpp. */ + tile[15] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); + /* Thin 32 bpp. */ + tile[16] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); + /* Thin 64 bpp. */ + tile[17] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(split_equal_to_row_size) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); + /* 8 bpp PRT. */ + tile[21] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* 16 bpp PRT */ + tile[22] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); + /* 32 bpp PRT */ + tile[23] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* 64 bpp PRT */ + tile[24] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* 128 bpp PRT */ + tile[25] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | + NUM_BANKS(ADDR_SURF_8_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); + + for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) + WREG32(GB_TILE_MODE0 + (reg_offset * 4), tile[reg_offset]); + break; + + case CHIP_VERDE: + case CHIP_OLAND: + case CHIP_HAINAN: + /* non-AA compressed depth or any compressed stencil */ + tile[0] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); + /* 2xAA/4xAA compressed depth only */ + tile[1] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); + /* 8xAA compressed depth only */ + tile[2] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); + /* 2xAA/4xAA compressed depth with stencil (for depth buffer) */ + tile[3] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); + /* Maps w/ a dimension less than the 2D macro-tile dimensions (for mipmapped depth textures) */ + tile[4] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* Uncompressed 16bpp depth - and stencil buffer allocated with it */ + tile[5] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(split_equal_to_row_size) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* Uncompressed 32bpp depth - and stencil buffer allocated with it */ + tile[6] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(split_equal_to_row_size) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* Uncompressed 8bpp stencil without depth (drivers typically do not use) */ + tile[7] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(split_equal_to_row_size) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); + /* 1D and 1D Array Surfaces */ + tile[8] = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | + MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* Displayable maps. */ + tile[9] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* Display 8bpp. */ + tile[10] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); + /* Display 16bpp. */ + tile[11] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* Display 32bpp. */ + tile[12] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* Thin. */ + tile[13] = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* Thin 8 bpp. */ + tile[14] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* Thin 16 bpp. */ + tile[15] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* Thin 32 bpp. */ + tile[16] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* Thin 64 bpp. */ + tile[17] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(split_equal_to_row_size) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* 8 bpp PRT. */ + tile[21] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* 16 bpp PRT */ + tile[22] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); + /* 32 bpp PRT */ + tile[23] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* 64 bpp PRT */ + tile[24] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | + NUM_BANKS(ADDR_SURF_16_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + /* 128 bpp PRT */ + tile[25] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | + NUM_BANKS(ADDR_SURF_8_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); + + for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) + WREG32(GB_TILE_MODE0 + (reg_offset * 4), tile[reg_offset]); + break; + + default: DRM_ERROR("unknown asic: 0x%x\n", rdev->family); + } } static void si_select_se_sh(struct radeon_device *rdev, @@ -3174,6 +3163,8 @@ static void si_gpu_init(struct radeon_device *rdev) } WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff)); + WREG32(SRBM_INT_CNTL, 1); + WREG32(SRBM_INT_ACK, 1); evergreen_fix_pci_max_read_req_size(rdev); @@ -4058,10 +4049,15 @@ static void si_gpu_pci_config_reset(struct radeon_device *rdev) } } -int si_asic_reset(struct radeon_device *rdev) +int si_asic_reset(struct radeon_device *rdev, bool hard) { u32 reset_mask; + if (hard) { + si_gpu_pci_config_reset(rdev); + return 0; + } + reset_mask = si_gpu_check_soft_reset(rdev); if (reset_mask) @@ -4298,7 +4294,8 @@ static int si_pcie_gart_enable(struct radeon_device *rdev) /* empty context1-15 */ /* set vm size, must be a multiple of 4 */ WREG32(VM_CONTEXT1_PAGE_TABLE_START_ADDR, 0); - WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn); + WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn - 1); + /* Assign the pt base to something valid for now; the pts used for * the VMs are determined by the application and setup and assigned * on the fly in the vm part of radeon_gart.c @@ -4383,6 +4380,10 @@ static bool si_vm_reg_valid(u32 reg) if (reg >= 0x28000) return true; + /* shader regs are also fine */ + if (reg >= 0xB000 && reg < 0xC000) + return true; + /* check config regs */ switch (reg) { case GRBM_GFX_INDEX: @@ -4711,12 +4712,6 @@ int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib) switch (pkt.type) { case RADEON_PACKET_TYPE0: dev_err(rdev->dev, "Packet0 not allowed!\n"); - for (i = 0; i < ib->length_dw; i++) { - if (i == idx) - printk("\t0x%08x <---\n", ib->ptr[i]); - else - printk("\t0x%08x\n", ib->ptr[i]); - } ret = -EINVAL; break; case RADEON_PACKET_TYPE2: @@ -4748,8 +4743,15 @@ int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib) ret = -EINVAL; break; } - if (ret) - break; + if (ret) { + for (i = 0; i < ib->length_dw; i++) { + if (i == idx) + printk("\t0x%08x <---\n", ib->ptr[i]); + else + printk("\t0x%08x\n", ib->ptr[i]); + } + break; + } } while (idx < ib->length_dw); return ret; @@ -5036,27 +5038,23 @@ static void si_vm_decode_fault(struct radeon_device *rdev, block, mc_id); } -void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) +void si_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, + unsigned vm_id, uint64_t pd_addr) { - struct radeon_ring *ring = &rdev->ring[ridx]; - - if (vm == NULL) - return; - /* write new base address */ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) | WRITE_DATA_DST_SEL(0))); - if (vm->id < 8) { + if (vm_id < 8) { radeon_ring_write(ring, - (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2); + (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm_id << 2)) >> 2); } else { radeon_ring_write(ring, - (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2); + (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm_id - 8) << 2)) >> 2); } radeon_ring_write(ring, 0); - radeon_ring_write(ring, vm->pd_gpu_addr >> 12); + radeon_ring_write(ring, pd_addr >> 12); /* flush hdp cache */ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); @@ -5072,7 +5070,17 @@ void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) WRITE_DATA_DST_SEL(0))); radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); radeon_ring_write(ring, 0); - radeon_ring_write(ring, 1 << vm->id); + radeon_ring_write(ring, 1 << vm_id); + + /* wait for the invalidate to complete */ + radeon_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5)); + radeon_ring_write(ring, (WAIT_REG_MEM_FUNCTION(0) | /* always */ + WAIT_REG_MEM_ENGINE(0))); /* me */ + radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); + radeon_ring_write(ring, 0); + radeon_ring_write(ring, 0); /* ref */ + radeon_ring_write(ring, 0); /* mask */ + radeon_ring_write(ring, 0x20); /* poll interval */ /* sync PFP to ME, otherwise we might get invalid PFP reads */ radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0)); @@ -5916,6 +5924,7 @@ static void si_disable_interrupt_state(struct radeon_device *rdev) tmp = RREG32(DMA_CNTL + DMA1_REGISTER_OFFSET) & ~TRAP_ENABLE; WREG32(DMA_CNTL + DMA1_REGISTER_OFFSET, tmp); WREG32(GRBM_INT_CNTL, 0); + WREG32(SRBM_INT_CNTL, 0); if (rdev->num_crtc >= 2) { WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); @@ -6057,12 +6066,12 @@ int si_irq_set(struct radeon_device *rdev) (CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE); if (!ASIC_IS_NODCE(rdev)) { - hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN; - hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN; - hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN; - hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN; - hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN; - hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN; + hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN); + hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN); + hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN); + hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN); + hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN); + hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN); } dma_cntl = RREG32(DMA_CNTL + DMA0_REGISTER_OFFSET) & ~TRAP_ENABLE; @@ -6125,27 +6134,27 @@ int si_irq_set(struct radeon_device *rdev) } if (rdev->irq.hpd[0]) { DRM_DEBUG("si_irq_set: hpd 1\n"); - hpd1 |= DC_HPDx_INT_EN; + hpd1 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN; } if (rdev->irq.hpd[1]) { DRM_DEBUG("si_irq_set: hpd 2\n"); - hpd2 |= DC_HPDx_INT_EN; + hpd2 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN; } if (rdev->irq.hpd[2]) { DRM_DEBUG("si_irq_set: hpd 3\n"); - hpd3 |= DC_HPDx_INT_EN; + hpd3 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN; } if (rdev->irq.hpd[3]) { DRM_DEBUG("si_irq_set: hpd 4\n"); - hpd4 |= DC_HPDx_INT_EN; + hpd4 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN; } if (rdev->irq.hpd[4]) { DRM_DEBUG("si_irq_set: hpd 5\n"); - hpd5 |= DC_HPDx_INT_EN; + hpd5 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN; } if (rdev->irq.hpd[5]) { DRM_DEBUG("si_irq_set: hpd 6\n"); - hpd6 |= DC_HPDx_INT_EN; + hpd6 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN; } WREG32(CP_INT_CNTL_RING0, cp_int_cntl); @@ -6205,6 +6214,9 @@ int si_irq_set(struct radeon_device *rdev) WREG32(CG_THERMAL_INT, thermal_int); + /* posting read */ + RREG32(SRBM_STATUS); + return 0; } @@ -6305,6 +6317,37 @@ static inline void si_irq_ack(struct radeon_device *rdev) tmp |= DC_HPDx_INT_ACK; WREG32(DC_HPD6_INT_CONTROL, tmp); } + + if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) { + tmp = RREG32(DC_HPD1_INT_CONTROL); + tmp |= DC_HPDx_RX_INT_ACK; + WREG32(DC_HPD1_INT_CONTROL, tmp); + } + if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) { + tmp = RREG32(DC_HPD2_INT_CONTROL); + tmp |= DC_HPDx_RX_INT_ACK; + WREG32(DC_HPD2_INT_CONTROL, tmp); + } + if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) { + tmp = RREG32(DC_HPD3_INT_CONTROL); + tmp |= DC_HPDx_RX_INT_ACK; + WREG32(DC_HPD3_INT_CONTROL, tmp); + } + if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) { + tmp = RREG32(DC_HPD4_INT_CONTROL); + tmp |= DC_HPDx_RX_INT_ACK; + WREG32(DC_HPD4_INT_CONTROL, tmp); + } + if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) { + tmp = RREG32(DC_HPD5_INT_CONTROL); + tmp |= DC_HPDx_RX_INT_ACK; + WREG32(DC_HPD5_INT_CONTROL, tmp); + } + if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) { + tmp = RREG32(DC_HPD5_INT_CONTROL); + tmp |= DC_HPDx_RX_INT_ACK; + WREG32(DC_HPD6_INT_CONTROL, tmp); + } } static void si_irq_disable(struct radeon_device *rdev) @@ -6370,6 +6413,7 @@ irqreturn_t si_irq_process(struct radeon_device *rdev) u32 src_id, src_data, ring_id; u32 ring_index; bool queue_hotplug = false; + bool queue_dp = false; bool queue_thermal = false; u32 status, addr; @@ -6384,7 +6428,7 @@ restart_ih: return IRQ_NONE; rptr = rdev->ih.rptr; - DRM_DEBUG_VBLANK("si_irq_process start: rptr %d, wptr %d\n", rptr, wptr); + DRM_DEBUG("si_irq_process start: rptr %d, wptr %d\n", rptr, wptr); /* Order reading of wptr vs. reading of IH ring data */ rmb(); @@ -6403,23 +6447,27 @@ restart_ih: case 1: /* D1 vblank/vline */ switch (src_data) { case 0: /* D1 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[0]) { - drm_handle_vblank(rdev->ddev, 0); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[0])) - radeon_crtc_handle_vblank(rdev, 0); - rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D1 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[0]) { + drm_handle_vblank(rdev->ddev, 0); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[0])) + radeon_crtc_handle_vblank(rdev, 0); + rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D1 vblank\n"); + break; case 1: /* D1 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D1 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT; + DRM_DEBUG("IH: D1 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -6429,23 +6477,27 @@ restart_ih: case 2: /* D2 vblank/vline */ switch (src_data) { case 0: /* D2 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[1]) { - drm_handle_vblank(rdev->ddev, 1); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[1])) - radeon_crtc_handle_vblank(rdev, 1); - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D2 vblank\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[1]) { + drm_handle_vblank(rdev->ddev, 1); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (atomic_read(&rdev->irq.pflip[1])) + radeon_crtc_handle_vblank(rdev, 1); + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D2 vblank\n"); + break; case 1: /* D2 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D2 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; + DRM_DEBUG("IH: D2 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -6455,23 +6507,27 @@ restart_ih: case 3: /* D3 vblank/vline */ switch (src_data) { case 0: /* D3 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[2]) { - drm_handle_vblank(rdev->ddev, 2); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[2])) - radeon_crtc_handle_vblank(rdev, 2); - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D3 vblank\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[2]) { + drm_handle_vblank(rdev->ddev, 2); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (atomic_read(&rdev->irq.pflip[2])) + radeon_crtc_handle_vblank(rdev, 2); + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D3 vblank\n"); + break; case 1: /* D3 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D3 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; + DRM_DEBUG("IH: D3 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -6481,23 +6537,27 @@ restart_ih: case 4: /* D4 vblank/vline */ switch (src_data) { case 0: /* D4 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[3]) { - drm_handle_vblank(rdev->ddev, 3); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[3])) - radeon_crtc_handle_vblank(rdev, 3); - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D4 vblank\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[3]) { + drm_handle_vblank(rdev->ddev, 3); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (atomic_read(&rdev->irq.pflip[3])) + radeon_crtc_handle_vblank(rdev, 3); + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D4 vblank\n"); + break; case 1: /* D4 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D4 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; + DRM_DEBUG("IH: D4 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -6507,23 +6567,27 @@ restart_ih: case 5: /* D5 vblank/vline */ switch (src_data) { case 0: /* D5 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[4]) { - drm_handle_vblank(rdev->ddev, 4); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[4])) - radeon_crtc_handle_vblank(rdev, 4); - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D5 vblank\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[4]) { + drm_handle_vblank(rdev->ddev, 4); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (atomic_read(&rdev->irq.pflip[4])) + radeon_crtc_handle_vblank(rdev, 4); + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D5 vblank\n"); + break; case 1: /* D5 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D5 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; + DRM_DEBUG("IH: D5 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -6533,23 +6597,27 @@ restart_ih: case 6: /* D6 vblank/vline */ switch (src_data) { case 0: /* D6 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[5]) { - drm_handle_vblank(rdev->ddev, 5); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[5])) - radeon_crtc_handle_vblank(rdev, 5); - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D6 vblank\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[5]) { + drm_handle_vblank(rdev->ddev, 5); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); + } + if (atomic_read(&rdev->irq.pflip[5])) + radeon_crtc_handle_vblank(rdev, 5); + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D6 vblank\n"); + break; case 1: /* D6 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; - DRM_DEBUG_VBLANK("IH: D6 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; + DRM_DEBUG("IH: D6 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -6562,59 +6630,129 @@ restart_ih: case 14: /* D4 page flip */ case 16: /* D5 page flip */ case 18: /* D6 page flip */ - DRM_DEBUG_VBLANK("IH: D%d flip\n", ((src_id - 8) >> 1) + 1); + DRM_DEBUG("IH: D%d flip\n", ((src_id - 8) >> 1) + 1); if (radeon_use_pflipirq > 0) radeon_crtc_handle_flip(rdev, (src_id - 8) >> 1); break; case 42: /* HPD hotplug */ switch (src_data) { case 0: - if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD1\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD1\n"); + break; case 1: - if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD2\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD2\n"); + break; case 2: - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD3\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD3\n"); + break; case 3: - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD4\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD4\n"); + break; case 4: - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD5\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD5\n"); + break; case 5: - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD6\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD6\n"); + + break; + case 6: + if (!(rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 1\n"); + + break; + case 7: + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 2\n"); + + break; + case 8: + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 3\n"); + + break; + case 9: + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 4\n"); + + break; + case 10: + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 5\n"); + + break; + case 11: + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 6\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); break; } break; + case 96: + DRM_ERROR("SRBM_READ_ERROR: 0x%x\n", RREG32(SRBM_READ_ERROR)); + WREG32(SRBM_INT_ACK, 0x1); + break; case 124: /* UVD */ DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data); radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX); @@ -6688,6 +6826,8 @@ restart_ih: rptr &= rdev->ih.ptr_mask; WREG32(IH_RB_RPTR, rptr); } + if (queue_dp) + schedule_work(&rdev->dp_work); if (queue_hotplug) taskqueue_enqueue(rdev->tq, &rdev->hotplug_work); if (queue_thermal && rdev->pm.dpm_enabled) @@ -6706,6 +6846,159 @@ restart_ih: /* * startup/shutdown callbacks */ +static void si_uvd_init(struct radeon_device *rdev) +{ + int r; + + if (!rdev->has_uvd) + return; + + r = radeon_uvd_init(rdev); + if (r) { + dev_err(rdev->dev, "failed UVD (%d) init.\n", r); + /* + * At this point rdev->uvd.vcpu_bo is NULL which trickles down + * to early fails uvd_v2_2_resume() and thus nothing happens + * there. So it is pointless to try to go through that code + * hence why we disable uvd here. + */ + rdev->has_uvd = 0; + return; + } + rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL; + r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX], 4096); +} + +static void si_uvd_start(struct radeon_device *rdev) +{ + int r; + + if (!rdev->has_uvd) + return; + + r = uvd_v2_2_resume(rdev); + if (r) { + dev_err(rdev->dev, "failed UVD resume (%d).\n", r); + goto error; + } + r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX); + if (r) { + dev_err(rdev->dev, "failed initializing UVD fences (%d).\n", r); + goto error; + } + return; + +error: + rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; +} + +static void si_uvd_resume(struct radeon_device *rdev) +{ + struct radeon_ring *ring; + int r; + + if (!rdev->has_uvd || !rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size) + return; + + ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; + r = radeon_ring_init(rdev, ring, ring->ring_size, 0, RADEON_CP_PACKET2); + if (r) { + dev_err(rdev->dev, "failed initializing UVD ring (%d).\n", r); + return; + } + r = uvd_v1_0_init(rdev); + if (r) { + dev_err(rdev->dev, "failed initializing UVD (%d).\n", r); + return; + } +} + +static void si_vce_init(struct radeon_device *rdev) +{ + int r; + + if (!rdev->has_vce) + return; + + r = radeon_vce_init(rdev); + if (r) { + dev_err(rdev->dev, "failed VCE (%d) init.\n", r); + /* + * At this point rdev->vce.vcpu_bo is NULL which trickles down + * to early fails si_vce_start() and thus nothing happens + * there. So it is pointless to try to go through that code + * hence why we disable vce here. + */ + rdev->has_vce = 0; + return; + } + rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_obj = NULL; + r600_ring_init(rdev, &rdev->ring[TN_RING_TYPE_VCE1_INDEX], 4096); + rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_obj = NULL; + r600_ring_init(rdev, &rdev->ring[TN_RING_TYPE_VCE2_INDEX], 4096); +} + +static void si_vce_start(struct radeon_device *rdev) +{ + int r; + + if (!rdev->has_vce) + return; + + r = radeon_vce_resume(rdev); + if (r) { + dev_err(rdev->dev, "failed VCE resume (%d).\n", r); + goto error; + } + r = vce_v1_0_resume(rdev); + if (r) { + dev_err(rdev->dev, "failed VCE resume (%d).\n", r); + goto error; + } + r = radeon_fence_driver_start_ring(rdev, TN_RING_TYPE_VCE1_INDEX); + if (r) { + dev_err(rdev->dev, "failed initializing VCE1 fences (%d).\n", r); + goto error; + } + r = radeon_fence_driver_start_ring(rdev, TN_RING_TYPE_VCE2_INDEX); + if (r) { + dev_err(rdev->dev, "failed initializing VCE2 fences (%d).\n", r); + goto error; + } + return; + +error: + rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size = 0; + rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_size = 0; +} + +static void si_vce_resume(struct radeon_device *rdev) +{ + struct radeon_ring *ring; + int r; + + if (!rdev->has_vce || !rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size) + return; + + ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; + r = radeon_ring_init(rdev, ring, ring->ring_size, 0, VCE_CMD_NO_OP); + if (r) { + dev_err(rdev->dev, "failed initializing VCE1 ring (%d).\n", r); + return; + } + ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; + r = radeon_ring_init(rdev, ring, ring->ring_size, 0, VCE_CMD_NO_OP); + if (r) { + dev_err(rdev->dev, "failed initializing VCE1 ring (%d).\n", r); + return; + } + r = vce_v1_0_init(rdev); + if (r) { + dev_err(rdev->dev, "failed initializing VCE (%d).\n", r); + return; + } +} + static int si_startup(struct radeon_device *rdev) { struct radeon_ring *ring; @@ -6784,17 +7077,8 @@ static int si_startup(struct radeon_device *rdev) return r; } - if (rdev->has_uvd) { - r = uvd_v2_2_resume(rdev); - if (!r) { - r = radeon_fence_driver_start_ring(rdev, - R600_RING_TYPE_UVD_INDEX); - if (r) - dev_err(rdev->dev, "UVD fences init error (%d).\n", r); - } - if (r) - rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; - } + si_uvd_start(rdev); + si_vce_start(rdev); /* Enable IRQ */ if (!rdev->irq.installed) { @@ -6852,17 +7136,8 @@ static int si_startup(struct radeon_device *rdev) if (r) return r; - if (rdev->has_uvd) { - ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; - if (ring->ring_size) { - r = radeon_ring_init(rdev, ring, ring->ring_size, 0, - RADEON_CP_PACKET2); - if (!r) - r = uvd_v1_0_init(rdev); - if (r) - DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); - } - } + si_uvd_resume(rdev); + si_vce_resume(rdev); r = radeon_ib_pool_init(rdev); if (r) { @@ -6876,7 +7151,7 @@ static int si_startup(struct radeon_device *rdev) return r; } - r = dce6_audio_init(rdev); + r = radeon_audio_init(rdev); if (r) return r; @@ -6915,7 +7190,7 @@ int si_resume(struct radeon_device *rdev) int si_suspend(struct radeon_device *rdev) { radeon_pm_suspend(rdev); - dce6_audio_fini(rdev); + radeon_audio_fini(rdev); radeon_vm_manager_fini(rdev); si_cp_enable(rdev, false); cayman_dma_stop(rdev); @@ -6923,6 +7198,8 @@ int si_suspend(struct radeon_device *rdev) uvd_v1_0_fini(rdev); radeon_uvd_suspend(rdev); } + if (rdev->has_vce) + radeon_vce_suspend(rdev); si_fini_pg(rdev); si_fini_cg(rdev); si_irq_suspend(rdev); @@ -7020,14 +7297,8 @@ int si_init(struct radeon_device *rdev) ring->ring_obj = NULL; r600_ring_init(rdev, ring, 64 * 1024); - if (rdev->has_uvd) { - r = radeon_uvd_init(rdev); - if (!r) { - ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; - ring->ring_obj = NULL; - r600_ring_init(rdev, ring, 4096); - } - } + si_uvd_init(rdev); + si_vce_init(rdev); rdev->ih.ring_obj = NULL; r600_ih_ring_init(rdev, 64 * 1024); @@ -7081,6 +7352,8 @@ void si_fini(struct radeon_device *rdev) uvd_v1_0_fini(rdev); radeon_uvd_fini(rdev); } + if (rdev->has_vce) + radeon_vce_fini(rdev); si_pcie_gart_fini(rdev); r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); @@ -7126,8 +7399,7 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_BYPASS_EN_MASK, ~UPLL_BYPASS_EN_MASK); if (!vclk || !dclk) { - /* keep the Bypass mode, put PLL to sleep */ - WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_SLEEP_MASK, ~UPLL_SLEEP_MASK); + /* keep the Bypass mode */ return 0; } @@ -7143,8 +7415,7 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) /* set VCO_MODE to 1 */ WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_VCO_MODE_MASK, ~UPLL_VCO_MODE_MASK); - /* toggle UPLL_SLEEP to 1 then back to 0 */ - WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_SLEEP_MASK, ~UPLL_SLEEP_MASK); + /* disable sleep mode */ WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_SLEEP_MASK); /* deassert UPLL_RESET */ @@ -7567,3 +7838,124 @@ static void si_program_aspm(struct radeon_device *rdev) } } } + +int si_vce_send_vcepll_ctlreq(struct radeon_device *rdev) +{ + unsigned i; + + /* make sure VCEPLL_CTLREQ is deasserted */ + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, 0, ~UPLL_CTLREQ_MASK); + + mdelay(10); + + /* assert UPLL_CTLREQ */ + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, UPLL_CTLREQ_MASK, ~UPLL_CTLREQ_MASK); + + /* wait for CTLACK and CTLACK2 to get asserted */ + for (i = 0; i < 100; ++i) { + uint32_t mask = UPLL_CTLACK_MASK | UPLL_CTLACK2_MASK; + if ((RREG32_SMC(CG_VCEPLL_FUNC_CNTL) & mask) == mask) + break; + mdelay(10); + } + + /* deassert UPLL_CTLREQ */ + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, 0, ~UPLL_CTLREQ_MASK); + + if (i == 100) { + DRM_ERROR("Timeout setting UVD clocks!\n"); + return -ETIMEDOUT; + } + + return 0; +} + +int si_set_vce_clocks(struct radeon_device *rdev, u32 evclk, u32 ecclk) +{ + unsigned fb_div = 0, evclk_div = 0, ecclk_div = 0; + int r; + + /* bypass evclk and ecclk with bclk */ + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL_2, + EVCLK_SRC_SEL(1) | ECCLK_SRC_SEL(1), + ~(EVCLK_SRC_SEL_MASK | ECCLK_SRC_SEL_MASK)); + + /* put PLL in bypass mode */ + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, VCEPLL_BYPASS_EN_MASK, + ~VCEPLL_BYPASS_EN_MASK); + + if (!evclk || !ecclk) { + /* keep the Bypass mode, put PLL to sleep */ + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, VCEPLL_SLEEP_MASK, + ~VCEPLL_SLEEP_MASK); + return 0; + } + + r = radeon_uvd_calc_upll_dividers(rdev, evclk, ecclk, 125000, 250000, + 16384, 0x03FFFFFF, 0, 128, 5, + &fb_div, &evclk_div, &ecclk_div); + if (r) + return r; + + /* set RESET_ANTI_MUX to 0 */ + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL_5, 0, ~RESET_ANTI_MUX_MASK); + + /* set VCO_MODE to 1 */ + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, VCEPLL_VCO_MODE_MASK, + ~VCEPLL_VCO_MODE_MASK); + + /* toggle VCEPLL_SLEEP to 1 then back to 0 */ + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, VCEPLL_SLEEP_MASK, + ~VCEPLL_SLEEP_MASK); + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, 0, ~VCEPLL_SLEEP_MASK); + + /* deassert VCEPLL_RESET */ + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, 0, ~VCEPLL_RESET_MASK); + + mdelay(1); + + r = si_vce_send_vcepll_ctlreq(rdev); + if (r) + return r; + + /* assert VCEPLL_RESET again */ + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, VCEPLL_RESET_MASK, ~VCEPLL_RESET_MASK); + + /* disable spread spectrum. */ + WREG32_SMC_P(CG_VCEPLL_SPREAD_SPECTRUM, 0, ~SSEN_MASK); + + /* set feedback divider */ + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL_3, VCEPLL_FB_DIV(fb_div), ~VCEPLL_FB_DIV_MASK); + + /* set ref divider to 0 */ + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, 0, ~VCEPLL_REF_DIV_MASK); + + /* set PDIV_A and PDIV_B */ + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL_2, + VCEPLL_PDIV_A(evclk_div) | VCEPLL_PDIV_B(ecclk_div), + ~(VCEPLL_PDIV_A_MASK | VCEPLL_PDIV_B_MASK)); + + /* give the PLL some time to settle */ + mdelay(15); + + /* deassert PLL_RESET */ + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, 0, ~VCEPLL_RESET_MASK); + + mdelay(15); + + /* switch from bypass mode to normal mode */ + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL, 0, ~VCEPLL_BYPASS_EN_MASK); + + r = si_vce_send_vcepll_ctlreq(rdev); + if (r) + return r; + + /* switch VCLK and DCLK selection */ + WREG32_SMC_P(CG_VCEPLL_FUNC_CNTL_2, + EVCLK_SRC_SEL(16) | ECCLK_SRC_SEL(16), + ~(EVCLK_SRC_SEL_MASK | ECCLK_SRC_SEL_MASK)); + + mdelay(100); + + return 0; +} diff --git a/sys/dev/drm/radeon/si_dma.c b/sys/dev/drm/radeon/si_dma.c index fe15ed0ac3..5eed740114 100644 --- a/sys/dev/drm/radeon/si_dma.c +++ b/sys/dev/drm/radeon/si_dma.c @@ -123,7 +123,6 @@ void si_dma_vm_write_pages(struct radeon_device *rdev, for (; ndw > 0; ndw -= 2, --count, pe += 8) { if (flags & R600_PTE_SYSTEM) { value = radeon_vm_map_gart(rdev, addr); - value &= 0xFFFFFFFFFFFFF000ULL; } else if (flags & R600_PTE_VALID) { value = addr; } else { @@ -185,20 +184,18 @@ void si_dma_vm_set_pages(struct radeon_device *rdev, } } -void si_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) +void si_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, + unsigned vm_id, uint64_t pd_addr) + { - struct radeon_ring *ring = &rdev->ring[ridx]; - - if (vm == NULL) - return; - radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0)); - if (vm->id < 8) { - radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2)); + + if (vm_id < 8) { + radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm_id << 2)) >> 2)); } else { - radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2)); + radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm_id - 8) << 2)) >> 2)); } - radeon_ring_write(ring, vm->pd_gpu_addr >> 12); + radeon_ring_write(ring, pd_addr >> 12); /* flush hdp cache */ radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0)); @@ -208,7 +205,15 @@ void si_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) /* bits 0-7 are the VM contexts0-7 */ radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0)); radeon_ring_write(ring, (0xf << 16) | (VM_INVALIDATE_REQUEST >> 2)); - radeon_ring_write(ring, 1 << vm->id); + radeon_ring_write(ring, 1 << vm_id); + + /* wait for invalidate to complete */ + radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_POLL_REG_MEM, 0, 0, 0, 0)); + radeon_ring_write(ring, VM_INVALIDATE_REQUEST); + radeon_ring_write(ring, 0xff << 16); /* retry */ + radeon_ring_write(ring, 1 << vm_id); /* mask */ + radeon_ring_write(ring, 0); /* value */ + radeon_ring_write(ring, (0 << 28) | 0x20); /* func(always) | poll interval */ } /** diff --git a/sys/dev/drm/radeon/si_dpm.c b/sys/dev/drm/radeon/si_dpm.c index fc341bb164..52e34f579b 100644 --- a/sys/dev/drm/radeon/si_dpm.c +++ b/sys/dev/drm/radeon/si_dpm.c @@ -1739,6 +1739,8 @@ struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev); struct ni_power_info *ni_get_pi(struct radeon_device *rdev); struct ni_ps *ni_get_ps(struct radeon_ps *rps); +extern void vce_v1_0_enable_mgcg(struct radeon_device *rdev, bool enable); + static int si_populate_voltage_value(struct radeon_device *rdev, const struct atom_voltage_table *table, u16 value, SISLANDS_SMC_VOLTAGE_VALUE *voltage); @@ -1754,6 +1756,9 @@ static int si_calculate_sclk_params(struct radeon_device *rdev, u32 engine_clock, SISLANDS_SMC_SCLK_VALUE *sclk); +static void si_thermal_start_smc_fan_control(struct radeon_device *rdev); +static void si_fan_ctrl_set_default_mode(struct radeon_device *rdev); + static struct si_power_info *si_get_pi(struct radeon_device *rdev) { struct si_power_info *pi = rdev->pm.dpm.priv; @@ -2906,6 +2911,79 @@ static int si_init_smc_spll_table(struct radeon_device *rdev) return ret; } +struct si_dpm_quirk { + u32 chip_vendor; + u32 chip_device; + u32 subsys_vendor; + u32 subsys_device; + u32 max_sclk; + u32 max_mclk; +}; + +/* cards with dpm stability problems */ +static struct si_dpm_quirk si_dpm_quirk_list[] = { + /* PITCAIRN - https://bugs.freedesktop.org/show_bug.cgi?id=76490 */ + { PCI_VENDOR_ID_ATI, 0x6810, 0x1462, 0x3036, 0, 120000 }, + { PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0xe271, 0, 120000 }, + { PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0x2015, 0, 120000 }, + { PCI_VENDOR_ID_ATI, 0x6810, 0x174b, 0xe271, 85000, 90000 }, + { PCI_VENDOR_ID_ATI, 0x6811, 0x1462, 0x2015, 0, 120000 }, + { PCI_VENDOR_ID_ATI, 0x6811, 0x1043, 0x2015, 0, 120000 }, + { PCI_VENDOR_ID_ATI, 0x6811, 0x148c, 0x2015, 0, 120000 }, + { PCI_VENDOR_ID_ATI, 0x6810, 0x1682, 0x9275, 0, 120000 }, + { 0, 0, 0, 0 }, +}; + +static u16 si_get_lower_of_leakage_and_vce_voltage(struct radeon_device *rdev, + u16 vce_voltage) +{ + u16 highest_leakage = 0; + struct si_power_info *si_pi = si_get_pi(rdev); + int i; + + for (i = 0; i < si_pi->leakage_voltage.count; i++){ + if (highest_leakage < si_pi->leakage_voltage.entries[i].voltage) + highest_leakage = si_pi->leakage_voltage.entries[i].voltage; + } + + if (si_pi->leakage_voltage.count && (highest_leakage < vce_voltage)) + return highest_leakage; + + return vce_voltage; +} + +static int si_get_vce_clock_voltage(struct radeon_device *rdev, + u32 evclk, u32 ecclk, u16 *voltage) +{ + u32 i; + int ret = -EINVAL; + struct radeon_vce_clock_voltage_dependency_table *table = + &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; + + if (((evclk == 0) && (ecclk == 0)) || + (table && (table->count == 0))) { + *voltage = 0; + return 0; + } + + for (i = 0; i < table->count; i++) { + if ((evclk <= table->entries[i].evclk) && + (ecclk <= table->entries[i].ecclk)) { + *voltage = table->entries[i].v; + ret = 0; + break; + } + } + + /* if no match return the highest voltage */ + if (ret) + *voltage = table->entries[table->count - 1].v; + + *voltage = si_get_lower_of_leakage_and_vce_voltage(rdev, *voltage); + + return ret; +} + static void si_apply_state_adjust_rules(struct radeon_device *rdev, struct radeon_ps *rps) { @@ -2914,9 +2992,44 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, bool disable_mclk_switching = false; bool disable_sclk_switching = false; u32 mclk, sclk; - u16 vddc, vddci; + u16 vddc, vddci, min_vce_voltage = 0; u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc; + u32 max_sclk = 0, max_mclk = 0; int i; + struct si_dpm_quirk *p = si_dpm_quirk_list; + + /* Apply dpm quirks */ + while (p && p->chip_device != 0) { + if (rdev->pdev->vendor == p->chip_vendor && + rdev->pdev->device == p->chip_device && + rdev->pdev->subsystem_vendor == p->subsys_vendor && + rdev->pdev->subsystem_device == p->subsys_device) { + max_sclk = p->max_sclk; + max_mclk = p->max_mclk; + break; + } + ++p; + } + /* limit mclk on all R7 370 parts for stability */ + if (rdev->pdev->device == 0x6811 && + rdev->pdev->revision == 0x81) + max_mclk = 120000; + /* limit sclk/mclk on Jet parts for stability */ + if (rdev->pdev->device == 0x6665 && + rdev->pdev->revision == 0xc3) { + max_sclk = 75000; + max_mclk = 80000; + } + + if (rps->vce_active) { + rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk; + rps->ecclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].ecclk; + si_get_vce_clock_voltage(rdev, rps->evclk, rps->ecclk, + &min_vce_voltage); + } else { + rps->evclk = 0; + rps->ecclk = 0; + } if ((rdev->pm.dpm.new_active_crtc_count > 1) || ni_dpm_vblank_too_short(rdev)) @@ -2970,6 +3083,14 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, if (ps->performance_levels[i].mclk > max_mclk_vddc) ps->performance_levels[i].mclk = max_mclk_vddc; } + if (max_mclk) { + if (ps->performance_levels[i].mclk > max_mclk) + ps->performance_levels[i].mclk = max_mclk; + } + if (max_sclk) { + if (ps->performance_levels[i].sclk > max_sclk) + ps->performance_levels[i].sclk = max_sclk; + } } /* XXX validate the min clocks required for display */ @@ -2990,6 +3111,13 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, vddc = ps->performance_levels[0].vddc; } + if (rps->vce_active) { + if (sclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk) + sclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk; + if (mclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].mclk) + mclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].mclk; + } + /* adjusted low state */ ps->performance_levels[0].sclk = sclk; ps->performance_levels[0].mclk = mclk; @@ -3039,6 +3167,8 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, &ps->performance_levels[i]); for (i = 0; i < ps->performance_level_count; i++) { + if (ps->performance_levels[i].vddc < min_vce_voltage) + ps->performance_levels[i].vddc = min_vce_voltage; btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk, ps->performance_levels[i].sclk, max_limits->vddc, &ps->performance_levels[i].vddc); @@ -3065,7 +3195,6 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, if (ps->performance_levels[i].vddc > rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc) ps->dc_compatible = false; } - } #if 0 @@ -3396,6 +3525,15 @@ static int si_process_firmware_header(struct radeon_device *rdev) si_pi->mc_reg_table_start = tmp; + ret = si_read_smc_sram_dword(rdev, + SISLANDS_SMC_FIRMWARE_HEADER_LOCATION + + SISLANDS_SMC_FIRMWARE_HEADER_fanTable, + &tmp, si_pi->sram_end); + if (ret) + return ret; + + si_pi->fan_table_start = tmp; + ret = si_read_smc_sram_dword(rdev, SISLANDS_SMC_FIRMWARE_HEADER_LOCATION + SISLANDS_SMC_FIRMWARE_HEADER_mcArbDramAutoRefreshTable, @@ -5805,6 +5943,21 @@ static void si_set_pcie_lane_width_in_smc(struct radeon_device *rdev, } } +static void si_set_vce_clock(struct radeon_device *rdev, + struct radeon_ps *new_rps, + struct radeon_ps *old_rps) +{ + if ((old_rps->evclk != new_rps->evclk) || + (old_rps->ecclk != new_rps->ecclk)) { + /* turn the clocks on when encoding, off otherwise */ + if (new_rps->evclk || new_rps->ecclk) + vce_v1_0_enable_mgcg(rdev, false); + else + vce_v1_0_enable_mgcg(rdev, true); + radeon_set_vce_clocks(rdev, new_rps->evclk, new_rps->ecclk); + } +} + void si_dpm_setup_asic(struct radeon_device *rdev) { int r; @@ -5817,8 +5970,33 @@ void si_dpm_setup_asic(struct radeon_device *rdev) si_enable_acpi_power_management(rdev); } -static int si_set_thermal_temperature_range(struct radeon_device *rdev, - int min_temp, int max_temp) +static int si_thermal_enable_alert(struct radeon_device *rdev, + bool enable) +{ + u32 thermal_int = RREG32(CG_THERMAL_INT); + + if (enable) { + PPSMC_Result result; + + thermal_int &= ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW); + WREG32(CG_THERMAL_INT, thermal_int); + rdev->irq.dpm_thermal = false; + result = si_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt); + if (result != PPSMC_Result_OK) { + DRM_DEBUG_KMS("Could not enable thermal interrupts.\n"); + return -EINVAL; + } + } else { + thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW; + WREG32(CG_THERMAL_INT, thermal_int); + rdev->irq.dpm_thermal = true; + } + + return 0; +} + +static int si_thermal_set_temperature_range(struct radeon_device *rdev, + int min_temp, int max_temp) { int low_temp = 0 * 1000; int high_temp = 255 * 1000; @@ -5842,6 +6020,347 @@ static int si_set_thermal_temperature_range(struct radeon_device *rdev, return 0; } +static void si_fan_ctrl_set_static_mode(struct radeon_device *rdev, u32 mode) +{ + struct si_power_info *si_pi = si_get_pi(rdev); + u32 tmp; + + if (si_pi->fan_ctrl_is_in_default_mode) { + tmp = (RREG32(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK) >> FDO_PWM_MODE_SHIFT; + si_pi->fan_ctrl_default_mode = tmp; + tmp = (RREG32(CG_FDO_CTRL2) & TMIN_MASK) >> TMIN_SHIFT; + si_pi->t_min = tmp; + si_pi->fan_ctrl_is_in_default_mode = false; + } + + tmp = RREG32(CG_FDO_CTRL2) & ~TMIN_MASK; + tmp |= TMIN(0); + WREG32(CG_FDO_CTRL2, tmp); + + tmp = RREG32(CG_FDO_CTRL2) & ~FDO_PWM_MODE_MASK; + tmp |= FDO_PWM_MODE(mode); + WREG32(CG_FDO_CTRL2, tmp); +} + +static int si_thermal_setup_fan_table(struct radeon_device *rdev) +{ + struct si_power_info *si_pi = si_get_pi(rdev); + PP_SIslands_FanTable fan_table = { FDO_MODE_HARDWARE }; + u32 duty100; + u32 t_diff1, t_diff2, pwm_diff1, pwm_diff2; + u16 fdo_min, slope1, slope2; + u32 reference_clock, tmp; + int ret; + u64 tmp64; + + if (!si_pi->fan_table_start) { + rdev->pm.dpm.fan.ucode_fan_control = false; + return 0; + } + + duty100 = (RREG32(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT; + + if (duty100 == 0) { + rdev->pm.dpm.fan.ucode_fan_control = false; + return 0; + } + + tmp64 = (u64)rdev->pm.dpm.fan.pwm_min * duty100; + do_div(tmp64, 10000); + fdo_min = (u16)tmp64; + + t_diff1 = rdev->pm.dpm.fan.t_med - rdev->pm.dpm.fan.t_min; + t_diff2 = rdev->pm.dpm.fan.t_high - rdev->pm.dpm.fan.t_med; + + pwm_diff1 = rdev->pm.dpm.fan.pwm_med - rdev->pm.dpm.fan.pwm_min; + pwm_diff2 = rdev->pm.dpm.fan.pwm_high - rdev->pm.dpm.fan.pwm_med; + + slope1 = (u16)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100); + slope2 = (u16)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100); + + fan_table.temp_min = cpu_to_be16((50 + rdev->pm.dpm.fan.t_min) / 100); + fan_table.temp_med = cpu_to_be16((50 + rdev->pm.dpm.fan.t_med) / 100); + fan_table.temp_max = cpu_to_be16((50 + rdev->pm.dpm.fan.t_max) / 100); + + fan_table.slope1 = cpu_to_be16(slope1); + fan_table.slope2 = cpu_to_be16(slope2); + + fan_table.fdo_min = cpu_to_be16(fdo_min); + + fan_table.hys_down = cpu_to_be16(rdev->pm.dpm.fan.t_hyst); + + fan_table.hys_up = cpu_to_be16(1); + + fan_table.hys_slope = cpu_to_be16(1); + + fan_table.temp_resp_lim = cpu_to_be16(5); + + reference_clock = radeon_get_xclk(rdev); + + fan_table.refresh_period = cpu_to_be32((rdev->pm.dpm.fan.cycle_delay * + reference_clock) / 1600); + + fan_table.fdo_max = cpu_to_be16((u16)duty100); + + tmp = (RREG32(CG_MULT_THERMAL_CTRL) & TEMP_SEL_MASK) >> TEMP_SEL_SHIFT; + fan_table.temp_src = (uint8_t)tmp; + + ret = si_copy_bytes_to_smc(rdev, + si_pi->fan_table_start, + (u8 *)(&fan_table), + sizeof(fan_table), + si_pi->sram_end); + + if (ret) { + DRM_ERROR("Failed to load fan table to the SMC."); + rdev->pm.dpm.fan.ucode_fan_control = false; + } + + return 0; +} + +static int si_fan_ctrl_start_smc_fan_control(struct radeon_device *rdev) +{ + struct si_power_info *si_pi = si_get_pi(rdev); + PPSMC_Result ret; + + ret = si_send_msg_to_smc(rdev, PPSMC_StartFanControl); + if (ret == PPSMC_Result_OK) { + si_pi->fan_is_controlled_by_smc = true; + return 0; + } else { + return -EINVAL; + } +} + +static int si_fan_ctrl_stop_smc_fan_control(struct radeon_device *rdev) +{ + struct si_power_info *si_pi = si_get_pi(rdev); + PPSMC_Result ret; + + ret = si_send_msg_to_smc(rdev, PPSMC_StopFanControl); + + if (ret == PPSMC_Result_OK) { + si_pi->fan_is_controlled_by_smc = false; + return 0; + } else { + return -EINVAL; + } +} + +int si_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev, + u32 *speed) +{ + u32 duty, duty100; + u64 tmp64; + + if (rdev->pm.no_fan) + return -ENOENT; + + duty100 = (RREG32(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT; + duty = (RREG32(CG_THERMAL_STATUS) & FDO_PWM_DUTY_MASK) >> FDO_PWM_DUTY_SHIFT; + + if (duty100 == 0) + return -EINVAL; + + tmp64 = (u64)duty * 100; + do_div(tmp64, duty100); + *speed = (u32)tmp64; + + if (*speed > 100) + *speed = 100; + + return 0; +} + +int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev, + u32 speed) +{ + struct si_power_info *si_pi = si_get_pi(rdev); + u32 tmp; + u32 duty, duty100; + u64 tmp64; + + if (rdev->pm.no_fan) + return -ENOENT; + + if (si_pi->fan_is_controlled_by_smc) + return -EINVAL; + + if (speed > 100) + return -EINVAL; + + duty100 = (RREG32(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT; + + if (duty100 == 0) + return -EINVAL; + + tmp64 = (u64)speed * duty100; + do_div(tmp64, 100); + duty = (u32)tmp64; + + tmp = RREG32(CG_FDO_CTRL0) & ~FDO_STATIC_DUTY_MASK; + tmp |= FDO_STATIC_DUTY(duty); + WREG32(CG_FDO_CTRL0, tmp); + + return 0; +} + +void si_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode) +{ + if (mode) { + /* stop auto-manage */ + if (rdev->pm.dpm.fan.ucode_fan_control) + si_fan_ctrl_stop_smc_fan_control(rdev); + si_fan_ctrl_set_static_mode(rdev, mode); + } else { + /* restart auto-manage */ + if (rdev->pm.dpm.fan.ucode_fan_control) + si_thermal_start_smc_fan_control(rdev); + else + si_fan_ctrl_set_default_mode(rdev); + } +} + +u32 si_fan_ctrl_get_mode(struct radeon_device *rdev) +{ + struct si_power_info *si_pi = si_get_pi(rdev); + u32 tmp; + + if (si_pi->fan_is_controlled_by_smc) + return 0; + + tmp = RREG32(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK; + return (tmp >> FDO_PWM_MODE_SHIFT); +} + +#if 0 +static int si_fan_ctrl_get_fan_speed_rpm(struct radeon_device *rdev, + u32 *speed) +{ + u32 tach_period; + u32 xclk = radeon_get_xclk(rdev); + + if (rdev->pm.no_fan) + return -ENOENT; + + if (rdev->pm.fan_pulses_per_revolution == 0) + return -ENOENT; + + tach_period = (RREG32(CG_TACH_STATUS) & TACH_PERIOD_MASK) >> TACH_PERIOD_SHIFT; + if (tach_period == 0) + return -ENOENT; + + *speed = 60 * xclk * 10000 / tach_period; + + return 0; +} + +static int si_fan_ctrl_set_fan_speed_rpm(struct radeon_device *rdev, + u32 speed) +{ + u32 tach_period, tmp; + u32 xclk = radeon_get_xclk(rdev); + + if (rdev->pm.no_fan) + return -ENOENT; + + if (rdev->pm.fan_pulses_per_revolution == 0) + return -ENOENT; + + if ((speed < rdev->pm.fan_min_rpm) || + (speed > rdev->pm.fan_max_rpm)) + return -EINVAL; + + if (rdev->pm.dpm.fan.ucode_fan_control) + si_fan_ctrl_stop_smc_fan_control(rdev); + + tach_period = 60 * xclk * 10000 / (8 * speed); + tmp = RREG32(CG_TACH_CTRL) & ~TARGET_PERIOD_MASK; + tmp |= TARGET_PERIOD(tach_period); + WREG32(CG_TACH_CTRL, tmp); + + si_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC_RPM); + + return 0; +} +#endif + +static void si_fan_ctrl_set_default_mode(struct radeon_device *rdev) +{ + struct si_power_info *si_pi = si_get_pi(rdev); + u32 tmp; + + if (!si_pi->fan_ctrl_is_in_default_mode) { + tmp = RREG32(CG_FDO_CTRL2) & ~FDO_PWM_MODE_MASK; + tmp |= FDO_PWM_MODE(si_pi->fan_ctrl_default_mode); + WREG32(CG_FDO_CTRL2, tmp); + + tmp = RREG32(CG_FDO_CTRL2) & ~TMIN_MASK; + tmp |= TMIN(si_pi->t_min); + WREG32(CG_FDO_CTRL2, tmp); + si_pi->fan_ctrl_is_in_default_mode = true; + } +} + +static void si_thermal_start_smc_fan_control(struct radeon_device *rdev) +{ + if (rdev->pm.dpm.fan.ucode_fan_control) { + si_fan_ctrl_start_smc_fan_control(rdev); + si_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC); + } +} + +static void si_thermal_initialize(struct radeon_device *rdev) +{ + u32 tmp; + + if (rdev->pm.fan_pulses_per_revolution) { + tmp = RREG32(CG_TACH_CTRL) & ~EDGE_PER_REV_MASK; + tmp |= EDGE_PER_REV(rdev->pm.fan_pulses_per_revolution -1); + WREG32(CG_TACH_CTRL, tmp); + } + + tmp = RREG32(CG_FDO_CTRL2) & ~TACH_PWM_RESP_RATE_MASK; + tmp |= TACH_PWM_RESP_RATE(0x28); + WREG32(CG_FDO_CTRL2, tmp); +} + +static int si_thermal_start_thermal_controller(struct radeon_device *rdev) +{ + int ret; + + si_thermal_initialize(rdev); + ret = si_thermal_set_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); + if (ret) + return ret; + ret = si_thermal_enable_alert(rdev, true); + if (ret) + return ret; + if (rdev->pm.dpm.fan.ucode_fan_control) { + ret = si_halt_smc(rdev); + if (ret) + return ret; + ret = si_thermal_setup_fan_table(rdev); + if (ret) + return ret; + ret = si_resume_smc(rdev); + if (ret) + return ret; + si_thermal_start_smc_fan_control(rdev); + } + + return 0; +} + +static void si_thermal_stop_thermal_controller(struct radeon_device *rdev) +{ + if (!rdev->pm.no_fan) { + si_fan_ctrl_set_default_mode(rdev); + si_fan_ctrl_stop_smc_fan_control(rdev); + } +} + int si_dpm_enable(struct radeon_device *rdev) { struct rv7xx_power_info *pi = rv770_get_pi(rdev); @@ -5954,31 +6473,39 @@ int si_dpm_enable(struct radeon_device *rdev) si_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); + si_thermal_start_thermal_controller(rdev); + ni_update_current_ps(rdev, boot_ps); return 0; } -int si_dpm_late_enable(struct radeon_device *rdev) +static int si_set_temperature_range(struct radeon_device *rdev) { int ret; - if (rdev->irq.installed && - r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { - PPSMC_Result result; + ret = si_thermal_enable_alert(rdev, false); + if (ret) + return ret; + ret = si_thermal_set_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); + if (ret) + return ret; + ret = si_thermal_enable_alert(rdev, true); + if (ret) + return ret; - ret = si_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); - if (ret) - return ret; - rdev->irq.dpm_thermal = true; - radeon_irq_set(rdev); - result = si_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt); + return ret; +} - if (result != PPSMC_Result_OK) - DRM_DEBUG_KMS("Could not enable thermal interrupts.\n"); - } +int si_dpm_late_enable(struct radeon_device *rdev) +{ + int ret; - return 0; + ret = si_set_temperature_range(rdev); + if (ret) + return ret; + + return ret; } void si_dpm_disable(struct radeon_device *rdev) @@ -5988,6 +6515,7 @@ void si_dpm_disable(struct radeon_device *rdev) if (!si_is_smc_running(rdev)) return; + si_thermal_stop_thermal_controller(rdev); si_disable_ulv(rdev); si_clear_vc(rdev); if (pi->thermal_protection) @@ -6118,6 +6646,7 @@ int si_dpm_set_power_state(struct radeon_device *rdev) return ret; } ni_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps); + si_set_vce_clock(rdev, new_ps, old_ps); if (eg_pi->pcie_performance_request) si_notify_link_speed_change_after_state_change(rdev, new_ps, old_ps); ret = si_set_power_state_conditionally_enable_ulv(rdev, new_ps); @@ -6364,6 +6893,21 @@ static int si_parse_power_table(struct radeon_device *rdev) power_state_offset += 2 + power_state->v2.ucNumDPMLevels; } rdev->pm.dpm.num_ps = state_array->ucNumEntries; + + /* fill in the vce power states */ + for (i = 0; i < RADEON_MAX_VCE_LEVELS; i++) { + u32 sclk, mclk; + clock_array_index = rdev->pm.dpm.vce_states[i].clk_idx; + clock_info = (union pplib_clock_info *) + &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize]; + sclk = le16_to_cpu(clock_info->si.usEngineClockLow); + sclk |= clock_info->si.ucEngineClockHigh << 16; + mclk = le16_to_cpu(clock_info->si.usMemoryClockLow); + mclk |= clock_info->si.ucMemoryClockHigh << 16; + rdev->pm.dpm.vce_states[i].sclk = sclk; + rdev->pm.dpm.vce_states[i].mclk = mclk; + } + return 0; } @@ -6408,10 +6952,11 @@ int si_dpm_init(struct radeon_device *rdev) if (ret) return ret; - ret = si_parse_power_table(rdev); + ret = r600_parse_extended_power_table(rdev); if (ret) return ret; - ret = r600_parse_extended_power_table(rdev); + + ret = si_parse_power_table(rdev); if (ret) return ret; @@ -6527,6 +7072,8 @@ int si_dpm_init(struct radeon_device *rdev) rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc = rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; + si_pi->fan_ctrl_is_in_default_mode = true; + return 0; } @@ -6563,3 +7110,39 @@ void si_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci, pl->pcie_gen + 1); } } + +u32 si_dpm_get_current_sclk(struct radeon_device *rdev) +{ + struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); + struct radeon_ps *rps = &eg_pi->current_rps; + struct ni_ps *ps = ni_get_ps(rps); + struct rv7xx_pl *pl; + u32 current_index = + (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >> + CURRENT_STATE_INDEX_SHIFT; + + if (current_index >= ps->performance_level_count) { + return 0; + } else { + pl = &ps->performance_levels[current_index]; + return pl->sclk; + } +} + +u32 si_dpm_get_current_mclk(struct radeon_device *rdev) +{ + struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); + struct radeon_ps *rps = &eg_pi->current_rps; + struct ni_ps *ps = ni_get_ps(rps); + struct rv7xx_pl *pl; + u32 current_index = + (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >> + CURRENT_STATE_INDEX_SHIFT; + + if (current_index >= ps->performance_level_count) { + return 0; + } else { + pl = &ps->performance_levels[current_index]; + return pl->mclk; + } +} diff --git a/sys/dev/drm/radeon/si_dpm.h b/sys/dev/drm/radeon/si_dpm.h index 8b5c06a083..1032a68be7 100644 --- a/sys/dev/drm/radeon/si_dpm.h +++ b/sys/dev/drm/radeon/si_dpm.h @@ -182,6 +182,7 @@ struct si_power_info { u32 dte_table_start; u32 spll_table_start; u32 papm_cfg_table_start; + u32 fan_table_start; /* CAC stuff */ const struct si_cac_config_reg *cac_weights; const struct si_cac_config_reg *lcac_config; @@ -197,6 +198,11 @@ struct si_power_info { /* SVI2 */ u8 svd_gpio_id; u8 svc_gpio_id; + /* fan control */ + bool fan_ctrl_is_in_default_mode; + u32 t_min; + u32 fan_ctrl_default_mode; + bool fan_is_controlled_by_smc; }; #define SISLANDS_INITIAL_STATE_ARB_INDEX 0 diff --git a/sys/dev/drm/radeon/si_smc.c b/sys/dev/drm/radeon/si_smc.c index b99c799303..bff7f187cb 100644 --- a/sys/dev/drm/radeon/si_smc.c +++ b/sys/dev/drm/radeon/si_smc.c @@ -48,6 +48,7 @@ int si_copy_bytes_to_smc(struct radeon_device *rdev, u32 smc_start_address, const u8 *src, u32 byte_count, u32 limit) { + unsigned long flags; int ret = 0; u32 data, original_data, addr, extra_shift; @@ -58,7 +59,7 @@ int si_copy_bytes_to_smc(struct radeon_device *rdev, addr = smc_start_address; - spin_lock(&rdev->smc_idx_lock); + spin_lock_irqsave(&rdev->smc_idx_lock, flags); while (byte_count >= 4) { /* SMC address space is BE */ data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]; @@ -104,7 +105,7 @@ int si_copy_bytes_to_smc(struct radeon_device *rdev, } done: - spin_unlock(&rdev->smc_idx_lock); + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); return ret; } @@ -134,7 +135,7 @@ void si_reset_smc(struct radeon_device *rdev) int si_program_jump_on_start(struct radeon_device *rdev) { - static u8 data[] = { 0x0E, 0x00, 0x40, 0x40 }; + static const u8 data[] = { 0x0E, 0x00, 0x40, 0x40 }; return si_copy_bytes_to_smc(rdev, 0x0, data, 4, sizeof(data)+1); } @@ -209,6 +210,7 @@ PPSMC_Result si_wait_for_smc_inactive(struct radeon_device *rdev) int si_load_smc_ucode(struct radeon_device *rdev, u32 limit) { + unsigned long flags; u32 ucode_start_address; u32 ucode_size; const u8 *src; @@ -259,7 +261,7 @@ int si_load_smc_ucode(struct radeon_device *rdev, u32 limit) if (ucode_size & 3) return -EINVAL; - spin_lock(&rdev->smc_idx_lock); + spin_lock_irqsave(&rdev->smc_idx_lock, flags); WREG32(SMC_IND_INDEX_0, ucode_start_address); WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0); while (ucode_size >= 4) { @@ -272,7 +274,7 @@ int si_load_smc_ucode(struct radeon_device *rdev, u32 limit) ucode_size -= 4; } WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0); - spin_unlock(&rdev->smc_idx_lock); + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); return 0; } @@ -280,13 +282,14 @@ int si_load_smc_ucode(struct radeon_device *rdev, u32 limit) int si_read_smc_sram_dword(struct radeon_device *rdev, u32 smc_address, u32 *value, u32 limit) { + unsigned long flags; int ret; - spin_lock(&rdev->smc_idx_lock); + spin_lock_irqsave(&rdev->smc_idx_lock, flags); ret = si_set_smc_sram_address(rdev, smc_address, limit); if (ret == 0) *value = RREG32(SMC_IND_DATA_0); - spin_unlock(&rdev->smc_idx_lock); + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); return ret; } @@ -294,13 +297,14 @@ int si_read_smc_sram_dword(struct radeon_device *rdev, u32 smc_address, int si_write_smc_sram_dword(struct radeon_device *rdev, u32 smc_address, u32 value, u32 limit) { + unsigned long flags; int ret; - spin_lock(&rdev->smc_idx_lock); + spin_lock_irqsave(&rdev->smc_idx_lock, flags); ret = si_set_smc_sram_address(rdev, smc_address, limit); if (ret == 0) WREG32(SMC_IND_DATA_0, value); - spin_unlock(&rdev->smc_idx_lock); + spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); return ret; } diff --git a/sys/dev/drm/radeon/sid.h b/sys/dev/drm/radeon/sid.h index 6635da9ec9..d1a7b58dd2 100644 --- a/sys/dev/drm/radeon/sid.h +++ b/sys/dev/drm/radeon/sid.h @@ -180,7 +180,10 @@ #define DIG_THERM_DPM(x) ((x) << 14) #define DIG_THERM_DPM_MASK 0x003FC000 #define DIG_THERM_DPM_SHIFT 14 - +#define CG_THERMAL_STATUS 0x704 +#define FDO_PWM_DUTY(x) ((x) << 9) +#define FDO_PWM_DUTY_MASK (0xff << 9) +#define FDO_PWM_DUTY_SHIFT 9 #define CG_THERMAL_INT 0x708 #define DIG_THERM_INTH(x) ((x) << 8) #define DIG_THERM_INTH_MASK 0x0000FF00 @@ -191,6 +194,10 @@ #define THERM_INT_MASK_HIGH (1 << 24) #define THERM_INT_MASK_LOW (1 << 25) +#define CG_MULT_THERMAL_CTRL 0x710 +#define TEMP_SEL(x) ((x) << 20) +#define TEMP_SEL_MASK (0xff << 20) +#define TEMP_SEL_SHIFT 20 #define CG_MULT_THERMAL_STATUS 0x714 #define ASIC_MAX_TEMP(x) ((x) << 0) #define ASIC_MAX_TEMP_MASK 0x000001ff @@ -199,6 +206,37 @@ #define CTF_TEMP_MASK 0x0003fe00 #define CTF_TEMP_SHIFT 9 +#define CG_FDO_CTRL0 0x754 +#define FDO_STATIC_DUTY(x) ((x) << 0) +#define FDO_STATIC_DUTY_MASK 0x000000FF +#define FDO_STATIC_DUTY_SHIFT 0 +#define CG_FDO_CTRL1 0x758 +#define FMAX_DUTY100(x) ((x) << 0) +#define FMAX_DUTY100_MASK 0x000000FF +#define FMAX_DUTY100_SHIFT 0 +#define CG_FDO_CTRL2 0x75C +#define TMIN(x) ((x) << 0) +#define TMIN_MASK 0x000000FF +#define TMIN_SHIFT 0 +#define FDO_PWM_MODE(x) ((x) << 11) +#define FDO_PWM_MODE_MASK (7 << 11) +#define FDO_PWM_MODE_SHIFT 11 +#define TACH_PWM_RESP_RATE(x) ((x) << 25) +#define TACH_PWM_RESP_RATE_MASK (0x7f << 25) +#define TACH_PWM_RESP_RATE_SHIFT 25 + +#define CG_TACH_CTRL 0x770 +# define EDGE_PER_REV(x) ((x) << 0) +# define EDGE_PER_REV_MASK (0x7 << 0) +# define EDGE_PER_REV_SHIFT 0 +# define TARGET_PERIOD(x) ((x) << 3) +# define TARGET_PERIOD_MASK 0xfffffff8 +# define TARGET_PERIOD_SHIFT 3 +#define CG_TACH_STATUS 0x774 +# define TACH_PERIOD(x) ((x) << 0) +# define TACH_PERIOD_MASK 0xffffffff +# define TACH_PERIOD_SHIFT 0 + #define GENERAL_PWRMGT 0x780 # define GLOBAL_PWRMGT_EN (1 << 0) # define STATIC_PM_EN (1 << 1) @@ -320,6 +358,10 @@ #define CC_SYS_RB_BACKEND_DISABLE 0xe80 #define GC_USER_SYS_RB_BACKEND_DISABLE 0xe84 +#define SRBM_READ_ERROR 0xE98 +#define SRBM_INT_CNTL 0xEA0 +#define SRBM_INT_ACK 0xEA8 + #define SRBM_STATUS2 0x0EC4 #define DMA_BUSY (1 << 5) #define DMA1_BUSY (1 << 6) @@ -863,6 +905,21 @@ /* 0x6e98, 0x7a98, 0x10698, 0x11298, 0x11e98, 0x12a98 */ #define CRTC_STATUS_FRAME_COUNT 0x6e98 +/* Audio clocks */ +#define DCCG_AUDIO_DTO_SOURCE 0x05ac +# define DCCG_AUDIO_DTO0_SOURCE_SEL(x) ((x) << 0) /* crtc0 - crtc5 */ +# define DCCG_AUDIO_DTO_SEL (1 << 4) /* 0=dto0 1=dto1 */ + +#define DCCG_AUDIO_DTO0_PHASE 0x05b0 +#define DCCG_AUDIO_DTO0_MODULE 0x05b4 +#define DCCG_AUDIO_DTO1_PHASE 0x05c0 +#define DCCG_AUDIO_DTO1_MODULE 0x05c4 + +#define DENTIST_DISPCLK_CNTL 0x0490 +# define DENTIST_DPREFCLK_WDIVIDER(x) (((x) & 0x7f) << 24) +# define DENTIST_DPREFCLK_WDIVIDER_MASK (0x7f << 24) +# define DENTIST_DPREFCLK_WDIVIDER_SHIFT 24 + #define AFMT_AUDIO_SRC_CONTROL 0x713c #define AFMT_AUDIO_SRC_SELECT(x) (((x) & 7) << 0) /* AFMT_AUDIO_SRC_SELECT @@ -1504,6 +1561,7 @@ #define UVD_UDEC_DBW_ADDR_CONFIG 0xEF54 #define UVD_RBC_RB_RPTR 0xF690 #define UVD_RBC_RB_WPTR 0xF694 +#define UVD_STATUS 0xf6bc #define UVD_CGC_CTRL 0xF4B0 # define DCM (1 << 0) @@ -1594,6 +1652,23 @@ #define PACKET3_MPEG_INDEX 0x3A #define PACKET3_COPY_DW 0x3B #define PACKET3_WAIT_REG_MEM 0x3C +#define WAIT_REG_MEM_FUNCTION(x) ((x) << 0) + /* 0 - always + * 1 - < + * 2 - <= + * 3 - == + * 4 - != + * 5 - >= + * 6 - > + */ +#define WAIT_REG_MEM_MEM_SPACE(x) ((x) << 4) + /* 0 - reg + * 1 - mem + */ +#define WAIT_REG_MEM_ENGINE(x) ((x) << 8) + /* 0 - me + * 1 - pfp + */ #define PACKET3_MEM_WRITE 0x3D #define PACKET3_COPY_DATA 0x40 #define PACKET3_CP_DMA 0x41 @@ -1797,6 +1872,7 @@ #define DMA_PACKET_TRAP 0x7 #define DMA_PACKET_SRBM_WRITE 0x9 #define DMA_PACKET_CONSTANT_FILL 0xd +#define DMA_PACKET_POLL_REG_MEM 0xe #define DMA_PACKET_NOP 0xf #define VCE_STATUS 0x20004 @@ -1808,6 +1884,7 @@ #define VCE_VCPU_CACHE_SIZE1 0x20030 #define VCE_VCPU_CACHE_OFFSET2 0x20034 #define VCE_VCPU_CACHE_SIZE2 0x20038 +#define VCE_VCPU_SCRATCH7 0x200dc #define VCE_SOFT_RESET 0x20120 #define VCE_ECPU_SOFT_RESET (1 << 0) #define VCE_FME_SOFT_RESET (1 << 2) @@ -1822,6 +1899,7 @@ #define VCE_RB_RPTR 0x2018c #define VCE_RB_WPTR 0x20190 #define VCE_CLOCK_GATING_A 0x202f8 +# define CGC_DYN_CLOCK_MODE (1 << 16) #define VCE_CLOCK_GATING_B 0x202fc #define VCE_UENC_CLOCK_GATING 0x205bc #define VCE_UENC_REG_CLOCK_GATING 0x205c0 @@ -1846,4 +1924,31 @@ #define VCE_CMD_IB_AUTO 0x00000005 #define VCE_CMD_SEMAPHORE 0x00000006 +/* discrete vce clocks */ +#define CG_VCEPLL_FUNC_CNTL 0xc0030600 +# define VCEPLL_RESET_MASK 0x00000001 +# define VCEPLL_SLEEP_MASK 0x00000002 +# define VCEPLL_BYPASS_EN_MASK 0x00000004 +# define VCEPLL_CTLREQ_MASK 0x00000008 +# define VCEPLL_VCO_MODE_MASK 0x00000600 +# define VCEPLL_REF_DIV_MASK 0x003F0000 +# define VCEPLL_CTLACK_MASK 0x40000000 +# define VCEPLL_CTLACK2_MASK 0x80000000 +#define CG_VCEPLL_FUNC_CNTL_2 0xc0030601 +# define VCEPLL_PDIV_A(x) ((x) << 0) +# define VCEPLL_PDIV_A_MASK 0x0000007F +# define VCEPLL_PDIV_B(x) ((x) << 8) +# define VCEPLL_PDIV_B_MASK 0x00007F00 +# define EVCLK_SRC_SEL(x) ((x) << 20) +# define EVCLK_SRC_SEL_MASK 0x01F00000 +# define ECCLK_SRC_SEL(x) ((x) << 25) +# define ECCLK_SRC_SEL_MASK 0x3E000000 +#define CG_VCEPLL_FUNC_CNTL_3 0xc0030602 +# define VCEPLL_FB_DIV(x) ((x) << 0) +# define VCEPLL_FB_DIV_MASK 0x01FFFFFF +#define CG_VCEPLL_FUNC_CNTL_4 0xc0030603 +#define CG_VCEPLL_FUNC_CNTL_5 0xc0030604 +#define CG_VCEPLL_SPREAD_SPECTRUM 0xc0030606 +# define VCEPLL_SSEN_MASK 0x00000001 + #endif diff --git a/sys/dev/drm/radeon/sislands_smc.h b/sys/dev/drm/radeon/sislands_smc.h index ba1864e0e4..8c0f8532c2 100644 --- a/sys/dev/drm/radeon/sislands_smc.h +++ b/sys/dev/drm/radeon/sislands_smc.h @@ -245,6 +245,31 @@ typedef struct SISLANDS_SMC_STATETABLE SISLANDS_SMC_STATETABLE; #define SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svd 0x11c #define SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svc 0x120 +struct PP_SIslands_FanTable +{ + uint8_t fdo_mode; + uint8_t padding; + int16_t temp_min; + int16_t temp_med; + int16_t temp_max; + int16_t slope1; + int16_t slope2; + int16_t fdo_min; + int16_t hys_up; + int16_t hys_down; + int16_t hys_slope; + int16_t temp_resp_lim; + int16_t temp_curr; + int16_t slope_curr; + int16_t pwm_curr; + uint32_t refresh_period; + int16_t fdo_max; + uint8_t temp_src; + int8_t padding2; +}; + +typedef struct PP_SIslands_FanTable PP_SIslands_FanTable; + #define SMC_SISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES 16 #define SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES 32 diff --git a/sys/dev/drm/radeon/smu7_discrete.h b/sys/dev/drm/radeon/smu7_discrete.h index bb60650ace..2b0d8d7cdb 100644 --- a/sys/dev/drm/radeon/smu7_discrete.h +++ b/sys/dev/drm/radeon/smu7_discrete.h @@ -431,6 +431,31 @@ struct SMU7_Discrete_MCRegisters typedef struct SMU7_Discrete_MCRegisters SMU7_Discrete_MCRegisters; +struct SMU7_Discrete_FanTable +{ + uint16_t FdoMode; + int16_t TempMin; + int16_t TempMed; + int16_t TempMax; + int16_t Slope1; + int16_t Slope2; + int16_t FdoMin; + int16_t HystUp; + int16_t HystDown; + int16_t HystSlope; + int16_t TempRespLim; + int16_t TempCurr; + int16_t SlopeCurr; + int16_t PwmCurr; + uint32_t RefreshPeriod; + int16_t FdoMax; + uint8_t TempSrc; + int8_t Padding; +}; + +typedef struct SMU7_Discrete_FanTable SMU7_Discrete_FanTable; + + struct SMU7_Discrete_PmFuses { // dw0-dw1 uint8_t BapmVddCVidHiSidd[8]; @@ -462,7 +487,10 @@ struct SMU7_Discrete_PmFuses { uint8_t BapmVddCVidHiSidd2[8]; // dw11-dw12 - uint32_t Reserved6[2]; + int16_t FuzzyFan_ErrorSetDelta; + int16_t FuzzyFan_ErrorRateSetDelta; + int16_t FuzzyFan_PwmSetDelta; + uint16_t CalcMeasPowerBlend; // dw13-dw16 uint8_t GnbLPML[16]; diff --git a/sys/dev/drm/radeon/sumo_dpm.c b/sys/dev/drm/radeon/sumo_dpm.c index c40dc0dddc..c708c9cdb5 100644 --- a/sys/dev/drm/radeon/sumo_dpm.c +++ b/sys/dev/drm/radeon/sumo_dpm.c @@ -1839,6 +1839,34 @@ void sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev } } +u32 sumo_dpm_get_current_sclk(struct radeon_device *rdev) +{ + struct sumo_power_info *pi = sumo_get_pi(rdev); + struct radeon_ps *rps = &pi->current_rps; + struct sumo_ps *ps = sumo_get_ps(rps); + struct sumo_pl *pl; + u32 current_index = + (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_INDEX_MASK) >> + CURR_INDEX_SHIFT; + + if (current_index == BOOST_DPM_LEVEL) { + pl = &pi->boost_pl; + return pl->sclk; + } else if (current_index >= ps->num_levels) { + return 0; + } else { + pl = &ps->levels[current_index]; + return pl->sclk; + } +} + +u32 sumo_dpm_get_current_mclk(struct radeon_device *rdev) +{ + struct sumo_power_info *pi = sumo_get_pi(rdev); + + return pi->sys_info.bootup_uma_clk; +} + void sumo_dpm_fini(struct radeon_device *rdev) { int i; diff --git a/sys/dev/drm/radeon/trinity_dpm.c b/sys/dev/drm/radeon/trinity_dpm.c index 120fca050e..5fd253010a 100644 --- a/sys/dev/drm/radeon/trinity_dpm.c +++ b/sys/dev/drm/radeon/trinity_dpm.c @@ -336,6 +336,7 @@ static const u32 trinity_override_mgpg_sequences[] = 0x00000204, 0x00000000, }; +extern void vce_v1_0_enable_mgcg(struct radeon_device *rdev, bool enable); static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev, const u32 *seq, u32 count); static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev); @@ -985,6 +986,21 @@ static void trinity_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev trinity_setup_uvd_clocks(rdev, new_rps, old_rps); } +static void trinity_set_vce_clock(struct radeon_device *rdev, + struct radeon_ps *new_rps, + struct radeon_ps *old_rps) +{ + if ((old_rps->evclk != new_rps->evclk) || + (old_rps->ecclk != new_rps->ecclk)) { + /* turn the clocks on when encoding, off otherwise */ + if (new_rps->evclk || new_rps->ecclk) + vce_v1_0_enable_mgcg(rdev, false); + else + vce_v1_0_enable_mgcg(rdev, true); + radeon_set_vce_clocks(rdev, new_rps->evclk, new_rps->ecclk); + } +} + static void trinity_program_ttt(struct radeon_device *rdev) { struct trinity_power_info *pi = trinity_get_pi(rdev); @@ -1246,6 +1262,7 @@ int trinity_dpm_set_power_state(struct radeon_device *rdev) trinity_force_level_0(rdev); trinity_unforce_levels(rdev); trinity_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps); + trinity_set_vce_clock(rdev, new_ps, old_ps); } trinity_release_mutex(rdev); @@ -1483,7 +1500,35 @@ static void trinity_adjust_uvd_state(struct radeon_device *rdev, } } +static int trinity_get_vce_clock_voltage(struct radeon_device *rdev, + u32 evclk, u32 ecclk, u16 *voltage) +{ + u32 i; + int ret = -EINVAL; + struct radeon_vce_clock_voltage_dependency_table *table = + &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; + if (((evclk == 0) && (ecclk == 0)) || + (table && (table->count == 0))) { + *voltage = 0; + return 0; + } + + for (i = 0; i < table->count; i++) { + if ((evclk <= table->entries[i].evclk) && + (ecclk <= table->entries[i].ecclk)) { + *voltage = table->entries[i].v; + ret = 0; + break; + } + } + + /* if no match return the highest voltage */ + if (ret) + *voltage = table->entries[table->count - 1].v; + + return ret; +} static void trinity_apply_state_adjust_rules(struct radeon_device *rdev, struct radeon_ps *new_rps, @@ -1496,6 +1541,7 @@ static void trinity_apply_state_adjust_rules(struct radeon_device *rdev, u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */ u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */ u32 i; + u16 min_vce_voltage; bool force_high; u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count; @@ -1504,6 +1550,14 @@ static void trinity_apply_state_adjust_rules(struct radeon_device *rdev, trinity_adjust_uvd_state(rdev, new_rps); + if (new_rps->vce_active) { + new_rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk; + new_rps->ecclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].ecclk; + } else { + new_rps->evclk = 0; + new_rps->ecclk = 0; + } + for (i = 0; i < ps->num_levels; i++) { if (ps->levels[i].vddc_index < min_voltage) ps->levels[i].vddc_index = min_voltage; @@ -1512,6 +1566,17 @@ static void trinity_apply_state_adjust_rules(struct radeon_device *rdev, ps->levels[i].sclk = trinity_get_valid_engine_clock(rdev, min_sclk); + /* patch in vce limits */ + if (new_rps->vce_active) { + /* sclk */ + if (ps->levels[i].sclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk) + ps->levels[i].sclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk; + /* vddc */ + trinity_get_vce_clock_voltage(rdev, new_rps->evclk, new_rps->ecclk, &min_vce_voltage); + if (ps->levels[i].vddc_index < min_vce_voltage) + ps->levels[i].vddc_index = min_vce_voltage; + } + ps->levels[i].ds_divider_index = sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, sclk_in_sr); @@ -1733,6 +1798,19 @@ static int trinity_parse_power_table(struct radeon_device *rdev) power_state_offset += 2 + power_state->v2.ucNumDPMLevels; } rdev->pm.dpm.num_ps = state_array->ucNumEntries; + + /* fill in the vce power states */ + for (i = 0; i < RADEON_MAX_VCE_LEVELS; i++) { + u32 sclk; + clock_array_index = rdev->pm.dpm.vce_states[i].clk_idx; + clock_info = (union pplib_clock_info *) + &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize]; + sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow); + sclk |= clock_info->sumo.ucEngineClockHigh << 16; + rdev->pm.dpm.vce_states[i].sclk = sclk; + rdev->pm.dpm.vce_states[i].mclk = 0; + } + return 0; } @@ -1914,6 +1992,10 @@ int trinity_dpm_init(struct radeon_device *rdev) if (ret) return ret; + ret = r600_parse_extended_power_table(rdev); + if (ret) + return ret; + ret = trinity_parse_power_table(rdev); if (ret) return ret; @@ -1964,6 +2046,31 @@ void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *r } } +u32 trinity_dpm_get_current_sclk(struct radeon_device *rdev) +{ + struct trinity_power_info *pi = trinity_get_pi(rdev); + struct radeon_ps *rps = &pi->current_rps; + struct trinity_ps *ps = trinity_get_ps(rps); + struct trinity_pl *pl; + u32 current_index = + (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) >> + CURRENT_STATE_SHIFT; + + if (current_index >= ps->num_levels) { + return 0; + } else { + pl = &ps->levels[current_index]; + return pl->sclk; + } +} + +u32 trinity_dpm_get_current_mclk(struct radeon_device *rdev) +{ + struct trinity_power_info *pi = trinity_get_pi(rdev); + + return pi->sys_info.bootup_uma_clk; +} + void trinity_dpm_fini(struct radeon_device *rdev) { int i; @@ -1975,6 +2082,7 @@ void trinity_dpm_fini(struct radeon_device *rdev) } kfree(rdev->pm.dpm.ps); kfree(rdev->pm.dpm.priv); + r600_free_extended_power_table(rdev); } u32 trinity_dpm_get_sclk(struct radeon_device *rdev, bool low) diff --git a/sys/dev/drm/radeon/uvd_v1_0.c b/sys/dev/drm/radeon/uvd_v1_0.c index 047682062a..8a4736d889 100644 --- a/sys/dev/drm/radeon/uvd_v1_0.c +++ b/sys/dev/drm/radeon/uvd_v1_0.c @@ -124,12 +124,13 @@ int uvd_v1_0_resume(struct radeon_device *rdev) WREG32(UVD_VCPU_CACHE_SIZE0, size); addr += size; - size = RADEON_UVD_STACK_SIZE >> 3; + size = RADEON_UVD_HEAP_SIZE >> 3; WREG32(UVD_VCPU_CACHE_OFFSET1, addr); WREG32(UVD_VCPU_CACHE_SIZE1, size); addr += size; - size = RADEON_UVD_HEAP_SIZE >> 3; + size = (RADEON_UVD_STACK_SIZE + + (RADEON_UVD_SESSION_SIZE * rdev->uvd.max_handles)) >> 3; WREG32(UVD_VCPU_CACHE_OFFSET2, addr); WREG32(UVD_VCPU_CACHE_SIZE2, size); @@ -466,18 +467,8 @@ bool uvd_v1_0_semaphore_emit(struct radeon_device *rdev, struct radeon_semaphore *semaphore, bool emit_wait) { - uint64_t addr = semaphore->gpu_addr; - - radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_LOW, 0)); - radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF); - - radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_HIGH, 0)); - radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF); - - radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0)); - radeon_ring_write(ring, emit_wait ? 1 : 0); - - return true; + /* disable semaphores for UVD V1 hardware */ + return false; } /** @@ -532,11 +523,19 @@ int uvd_v1_0_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) goto error; } - r = radeon_fence_wait(fence, false); - if (r) { - DRM_ERROR("radeon: fence wait failed (%d).\n", r); + r = radeon_fence_wait_timeout(fence, false, usecs_to_jiffies( + RADEON_USEC_IB_TEST_TIMEOUT)); + if (r < 0) { + DRM_ERROR("radeon: fence wait failed (%d).\n", r); + goto error; + } else if (r == 0) { + DRM_ERROR("radeon: fence wait timed out.\n"); +#if 0 + r = -ETIMEDOUT; goto error; - } +#endif + } + r = 0; DRM_INFO("ib test on ring %d succeeded\n", ring->idx); error: radeon_fence_unref(&fence); diff --git a/sys/dev/drm/radeon/uvd_v2_2.c b/sys/dev/drm/radeon/uvd_v2_2.c index bbbc8372c0..76539342cf 100644 --- a/sys/dev/drm/radeon/uvd_v2_2.c +++ b/sys/dev/drm/radeon/uvd_v2_2.c @@ -59,6 +59,35 @@ void uvd_v2_2_fence_emit(struct radeon_device *rdev, radeon_ring_write(ring, 2); } +/** + * uvd_v2_2_semaphore_emit - emit semaphore command + * + * @rdev: radeon_device pointer + * @ring: radeon_ring pointer + * @semaphore: semaphore to emit commands for + * @emit_wait: true if we should emit a wait command + * + * Emit a semaphore command (either wait or signal) to the UVD ring. + */ +bool uvd_v2_2_semaphore_emit(struct radeon_device *rdev, + struct radeon_ring *ring, + struct radeon_semaphore *semaphore, + bool emit_wait) +{ + uint64_t addr = semaphore->gpu_addr; + + radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_LOW, 0)); + radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF); + + radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_HIGH, 0)); + radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF); + + radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0)); + radeon_ring_write(ring, emit_wait ? 1 : 0); + + return true; +} + /** * uvd_v2_2_resume - memory controller programming * @@ -87,12 +116,13 @@ int uvd_v2_2_resume(struct radeon_device *rdev) WREG32(UVD_VCPU_CACHE_SIZE0, size); addr += size; - size = RADEON_UVD_STACK_SIZE >> 3; + size = RADEON_UVD_HEAP_SIZE >> 3; WREG32(UVD_VCPU_CACHE_OFFSET1, addr); WREG32(UVD_VCPU_CACHE_SIZE1, size); addr += size; - size = RADEON_UVD_HEAP_SIZE >> 3; + size = (RADEON_UVD_STACK_SIZE + + (RADEON_UVD_SESSION_SIZE * rdev->uvd.max_handles)) >> 3; WREG32(UVD_VCPU_CACHE_OFFSET2, addr); WREG32(UVD_VCPU_CACHE_SIZE2, size); diff --git a/sys/dev/drm/radeon/uvd_v4_2.c b/sys/dev/drm/radeon/uvd_v4_2.c index 0e73324bdc..2f0e3b2144 100644 --- a/sys/dev/drm/radeon/uvd_v4_2.c +++ b/sys/dev/drm/radeon/uvd_v4_2.c @@ -41,18 +41,25 @@ int uvd_v4_2_resume(struct radeon_device *rdev) uint32_t size; /* programm the VCPU memory controller bits 0-27 */ - addr = rdev->uvd.gpu_addr >> 3; + + /* skip over the header of the new firmware format */ + if (rdev->uvd.fw_header_present) + addr = (rdev->uvd.gpu_addr + 0x200) >> 3; + else + addr = rdev->uvd.gpu_addr >> 3; + size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->datasize + 4) >> 3; WREG32(UVD_VCPU_CACHE_OFFSET0, addr); WREG32(UVD_VCPU_CACHE_SIZE0, size); addr += size; - size = RADEON_UVD_STACK_SIZE >> 3; + size = RADEON_UVD_HEAP_SIZE >> 3; WREG32(UVD_VCPU_CACHE_OFFSET1, addr); WREG32(UVD_VCPU_CACHE_SIZE1, size); addr += size; - size = RADEON_UVD_HEAP_SIZE >> 3; + size = (RADEON_UVD_STACK_SIZE + + (RADEON_UVD_SESSION_SIZE * rdev->uvd.max_handles)) >> 3; WREG32(UVD_VCPU_CACHE_OFFSET2, addr); WREG32(UVD_VCPU_CACHE_SIZE2, size); @@ -64,5 +71,8 @@ int uvd_v4_2_resume(struct radeon_device *rdev) addr = (rdev->uvd.gpu_addr >> 32) & 0xFF; WREG32(UVD_LMI_EXT40_ADDR, addr | (0x9 << 16) | (0x1 << 31)); + if (rdev->uvd.fw_header_present) + WREG32(UVD_GP_SCRATCH4, rdev->uvd.max_handles); + return 0; } diff --git a/sys/dev/drm/radeon/vce_v1_0.c b/sys/dev/drm/radeon/vce_v1_0.c index b44d9c842f..1021137093 100644 --- a/sys/dev/drm/radeon/vce_v1_0.c +++ b/sys/dev/drm/radeon/vce_v1_0.c @@ -31,6 +31,25 @@ #include "radeon_asic.h" #include "sid.h" +#define VCE_V1_0_FW_SIZE (256 * 1024) +#define VCE_V1_0_STACK_SIZE (64 * 1024) +#define VCE_V1_0_DATA_SIZE (7808 * (RADEON_MAX_VCE_HANDLES + 1)) + +void vce_v1_0_enable_mgcg(struct radeon_device *rdev, bool enable); + +struct vce_v1_0_fw_signature +{ + int32_t off; + uint32_t len; + int32_t num; + struct { + uint32_t chip_id; + uint32_t keyselect; + uint32_t nonce[4]; + uint32_t sigval[4]; + } val[8]; +}; + /** * vce_v1_0_get_rptr - get read pointer * @@ -82,6 +101,186 @@ void vce_v1_0_set_wptr(struct radeon_device *rdev, WREG32(VCE_RB_WPTR2, ring->wptr); } +void vce_v1_0_enable_mgcg(struct radeon_device *rdev, bool enable) +{ + u32 tmp; + + if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_VCE_MGCG)) { + tmp = RREG32(VCE_CLOCK_GATING_A); + tmp |= CGC_DYN_CLOCK_MODE; + WREG32(VCE_CLOCK_GATING_A, tmp); + + tmp = RREG32(VCE_UENC_CLOCK_GATING); + tmp &= ~0x1ff000; + tmp |= 0xff800000; + WREG32(VCE_UENC_CLOCK_GATING, tmp); + + tmp = RREG32(VCE_UENC_REG_CLOCK_GATING); + tmp &= ~0x3ff; + WREG32(VCE_UENC_REG_CLOCK_GATING, tmp); + } else { + tmp = RREG32(VCE_CLOCK_GATING_A); + tmp &= ~CGC_DYN_CLOCK_MODE; + WREG32(VCE_CLOCK_GATING_A, tmp); + + tmp = RREG32(VCE_UENC_CLOCK_GATING); + tmp |= 0x1ff000; + tmp &= ~0xff800000; + WREG32(VCE_UENC_CLOCK_GATING, tmp); + + tmp = RREG32(VCE_UENC_REG_CLOCK_GATING); + tmp |= 0x3ff; + WREG32(VCE_UENC_REG_CLOCK_GATING, tmp); + } +} + +static void vce_v1_0_init_cg(struct radeon_device *rdev) +{ + u32 tmp; + + tmp = RREG32(VCE_CLOCK_GATING_A); + tmp |= CGC_DYN_CLOCK_MODE; + WREG32(VCE_CLOCK_GATING_A, tmp); + + tmp = RREG32(VCE_CLOCK_GATING_B); + tmp |= 0x1e; + tmp &= ~0xe100e1; + WREG32(VCE_CLOCK_GATING_B, tmp); + + tmp = RREG32(VCE_UENC_CLOCK_GATING); + tmp &= ~0xff9ff000; + WREG32(VCE_UENC_CLOCK_GATING, tmp); + + tmp = RREG32(VCE_UENC_REG_CLOCK_GATING); + tmp &= ~0x3ff; + WREG32(VCE_UENC_REG_CLOCK_GATING, tmp); +} + +int vce_v1_0_load_fw(struct radeon_device *rdev, uint32_t *data) +{ + const struct vce_v1_0_fw_signature *sign = (const struct vce_v1_0_fw_signature *)rdev->vce_fw->data; + uint32_t chip_id; + int i; + + switch (rdev->family) { + case CHIP_TAHITI: + chip_id = 0x01000014; + break; + case CHIP_VERDE: + chip_id = 0x01000015; + break; + case CHIP_PITCAIRN: + case CHIP_OLAND: + chip_id = 0x01000016; + break; + case CHIP_ARUBA: + chip_id = 0x01000017; + break; + default: + return -EINVAL; + } + + for (i = 0; i < le32_to_cpu(sign->num); ++i) { + if (le32_to_cpu(sign->val[i].chip_id) == chip_id) + break; + } + + if (i == le32_to_cpu(sign->num)) + return -EINVAL; + + data += (256 - 64) / 4; + data[0] = sign->val[i].nonce[0]; + data[1] = sign->val[i].nonce[1]; + data[2] = sign->val[i].nonce[2]; + data[3] = sign->val[i].nonce[3]; + data[4] = cpu_to_le32(le32_to_cpu(sign->len) + 64); + + memset(&data[5], 0, 44); + memcpy(&data[16], &sign[1], rdev->vce_fw->datasize - sizeof(*sign)); + + data += le32_to_cpu(data[4]) / 4; + data[0] = sign->val[i].sigval[0]; + data[1] = sign->val[i].sigval[1]; + data[2] = sign->val[i].sigval[2]; + data[3] = sign->val[i].sigval[3]; + + rdev->vce.keyselect = le32_to_cpu(sign->val[i].keyselect); + + return 0; +} + +unsigned vce_v1_0_bo_size(struct radeon_device *rdev) +{ + WARN_ON(VCE_V1_0_FW_SIZE < rdev->vce_fw->datasize); + return VCE_V1_0_FW_SIZE + VCE_V1_0_STACK_SIZE + VCE_V1_0_DATA_SIZE; +} + +int vce_v1_0_resume(struct radeon_device *rdev) +{ + uint64_t addr = rdev->vce.gpu_addr; + uint32_t size; + int i; + + WREG32_P(VCE_CLOCK_GATING_A, 0, ~(1 << 16)); + WREG32_P(VCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000); + WREG32_P(VCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F); + WREG32(VCE_CLOCK_GATING_B, 0); + + WREG32_P(VCE_LMI_FW_PERIODIC_CTRL, 0x4, ~0x4); + + WREG32(VCE_LMI_CTRL, 0x00398000); + WREG32_P(VCE_LMI_CACHE_CTRL, 0x0, ~0x1); + WREG32(VCE_LMI_SWAP_CNTL, 0); + WREG32(VCE_LMI_SWAP_CNTL1, 0); + WREG32(VCE_LMI_VM_CTRL, 0); + + WREG32(VCE_VCPU_SCRATCH7, RADEON_MAX_VCE_HANDLES); + + addr += 256; + size = VCE_V1_0_FW_SIZE; + WREG32(VCE_VCPU_CACHE_OFFSET0, addr & 0x7fffffff); + WREG32(VCE_VCPU_CACHE_SIZE0, size); + + addr += size; + size = VCE_V1_0_STACK_SIZE; + WREG32(VCE_VCPU_CACHE_OFFSET1, addr & 0x7fffffff); + WREG32(VCE_VCPU_CACHE_SIZE1, size); + + addr += size; + size = VCE_V1_0_DATA_SIZE; + WREG32(VCE_VCPU_CACHE_OFFSET2, addr & 0x7fffffff); + WREG32(VCE_VCPU_CACHE_SIZE2, size); + + WREG32_P(VCE_LMI_CTRL2, 0x0, ~0x100); + + WREG32(VCE_LMI_FW_START_KEYSEL, rdev->vce.keyselect); + + for (i = 0; i < 10; ++i) { + mdelay(10); + if (RREG32(VCE_FW_REG_STATUS) & VCE_FW_REG_STATUS_DONE) + break; + } + + if (i == 10) + return -ETIMEDOUT; + + if (!(RREG32(VCE_FW_REG_STATUS) & VCE_FW_REG_STATUS_PASS)) + return -EINVAL; + + for (i = 0; i < 10; ++i) { + mdelay(10); + if (!(RREG32(VCE_FW_REG_STATUS) & VCE_FW_REG_STATUS_BUSY)) + break; + } + + if (i == 10) + return -ETIMEDOUT; + + vce_v1_0_init_cg(rdev); + + return 0; +} + /** * vce_v1_0_start - start VCE block * diff --git a/sys/dev/drm/radeon/vce_v2_0.c b/sys/dev/drm/radeon/vce_v2_0.c index bbdac2705f..f7f1772f9f 100644 --- a/sys/dev/drm/radeon/vce_v2_0.c +++ b/sys/dev/drm/radeon/vce_v2_0.c @@ -31,6 +31,10 @@ #include "radeon_asic.h" #include "cikd.h" +#define VCE_V2_0_FW_SIZE (256 * 1024) +#define VCE_V2_0_STACK_SIZE (64 * 1024) +#define VCE_V2_0_DATA_SIZE (23552 * RADEON_MAX_VCE_HANDLES) + static void vce_v2_0_set_sw_cg(struct radeon_device *rdev, bool gated) { u32 tmp; @@ -140,6 +144,12 @@ static void vce_v2_0_init_cg(struct radeon_device *rdev) WREG32(VCE_CLOCK_GATING_B, tmp); } +unsigned vce_v2_0_bo_size(struct radeon_device *rdev) +{ + WARN_ON(rdev->vce_fw->datasize > VCE_V2_0_FW_SIZE); + return VCE_V2_0_FW_SIZE + VCE_V2_0_STACK_SIZE + VCE_V2_0_DATA_SIZE; +} + int vce_v2_0_resume(struct radeon_device *rdev) { uint64_t addr = rdev->vce.gpu_addr; @@ -156,17 +166,20 @@ int vce_v2_0_resume(struct radeon_device *rdev) WREG32(VCE_LMI_SWAP_CNTL1, 0); WREG32(VCE_LMI_VM_CTRL, 0); - size = RADEON_GPU_PAGE_ALIGN(rdev->vce_fw->datasize); + WREG32(VCE_LMI_VCPU_CACHE_40BIT_BAR, addr >> 8); + + addr &= 0xff; + size = VCE_V2_0_FW_SIZE; WREG32(VCE_VCPU_CACHE_OFFSET0, addr & 0x7fffffff); WREG32(VCE_VCPU_CACHE_SIZE0, size); addr += size; - size = RADEON_VCE_STACK_SIZE; + size = VCE_V2_0_STACK_SIZE; WREG32(VCE_VCPU_CACHE_OFFSET1, addr & 0x7fffffff); WREG32(VCE_VCPU_CACHE_SIZE1, size); addr += size; - size = RADEON_VCE_HEAP_SIZE; + size = VCE_V2_0_DATA_SIZE; WREG32(VCE_VCPU_CACHE_OFFSET2, addr & 0x7fffffff); WREG32(VCE_VCPU_CACHE_SIZE2, size); -- 2.41.0