Commit 755d819e authored by Alex Deucher's avatar Alex Deucher Committed by Dave Airlie

drm/radeon/kms/cayman: add asic init/startup/fini/suspend/resume functions

Cayman is different enough from evergreen to warrant it's own functions.
Signed-off-by: default avatarAlex Deucher <alexdeucher@gmail.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent b9952a8a
...@@ -1108,7 +1108,7 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s ...@@ -1108,7 +1108,7 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s
WREG32(VGA_RENDER_CONTROL, save->vga_render_control); WREG32(VGA_RENDER_CONTROL, save->vga_render_control);
} }
static void evergreen_mc_program(struct radeon_device *rdev) void evergreen_mc_program(struct radeon_device *rdev)
{ {
struct evergreen_mc_save save; struct evergreen_mc_save save;
u32 tmp; u32 tmp;
...@@ -2565,7 +2565,7 @@ void evergreen_irq_disable(struct radeon_device *rdev) ...@@ -2565,7 +2565,7 @@ void evergreen_irq_disable(struct radeon_device *rdev)
evergreen_disable_interrupt_state(rdev); evergreen_disable_interrupt_state(rdev);
} }
static void evergreen_irq_suspend(struct radeon_device *rdev) void evergreen_irq_suspend(struct radeon_device *rdev)
{ {
evergreen_irq_disable(rdev); evergreen_irq_disable(rdev);
r600_rlc_stop(rdev); r600_rlc_stop(rdev);
...@@ -2888,7 +2888,7 @@ static int evergreen_startup(struct radeon_device *rdev) ...@@ -2888,7 +2888,7 @@ static int evergreen_startup(struct radeon_device *rdev)
return r; return r;
} }
} }
r = btc_mc_load_microcode(rdev); r = ni_mc_load_microcode(rdev);
if (r) { if (r) {
DRM_ERROR("Failed to load MC firmware!\n"); DRM_ERROR("Failed to load MC firmware!\n");
return r; return r;
...@@ -2970,7 +2970,7 @@ int evergreen_resume(struct radeon_device *rdev) ...@@ -2970,7 +2970,7 @@ int evergreen_resume(struct radeon_device *rdev)
r = evergreen_startup(rdev); r = evergreen_startup(rdev);
if (r) { if (r) {
DRM_ERROR("r600 startup failed on resume\n"); DRM_ERROR("evergreen startup failed on resume\n");
return r; return r;
} }
...@@ -3050,7 +3050,7 @@ int evergreen_init(struct radeon_device *rdev) ...@@ -3050,7 +3050,7 @@ int evergreen_init(struct radeon_device *rdev)
} }
/* Must be an ATOMBIOS */ /* Must be an ATOMBIOS */
if (!rdev->is_atom_bios) { if (!rdev->is_atom_bios) {
dev_err(rdev->dev, "Expecting atombios for R600 GPU\n"); dev_err(rdev->dev, "Expecting atombios for evergreen GPU\n");
return -EINVAL; return -EINVAL;
} }
r = radeon_atombios_init(rdev); r = radeon_atombios_init(rdev);
......
...@@ -36,6 +36,9 @@ ...@@ -36,6 +36,9 @@
extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save); extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save); extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
extern int evergreen_mc_wait_for_idle(struct radeon_device *rdev); extern int evergreen_mc_wait_for_idle(struct radeon_device *rdev);
extern void evergreen_mc_program(struct radeon_device *rdev);
extern void evergreen_irq_suspend(struct radeon_device *rdev);
extern int evergreen_mc_init(struct radeon_device *rdev);
#define EVERGREEN_PFP_UCODE_SIZE 1120 #define EVERGREEN_PFP_UCODE_SIZE 1120
#define EVERGREEN_PM4_UCODE_SIZE 1376 #define EVERGREEN_PM4_UCODE_SIZE 1376
...@@ -193,7 +196,7 @@ static const u32 cayman_io_mc_regs[BTC_IO_MC_REGS_SIZE][2] = { ...@@ -193,7 +196,7 @@ static const u32 cayman_io_mc_regs[BTC_IO_MC_REGS_SIZE][2] = {
{0x0000009f, 0x00976b00} {0x0000009f, 0x00976b00}
}; };
int btc_mc_load_microcode(struct radeon_device *rdev) int ni_mc_load_microcode(struct radeon_device *rdev)
{ {
const __be32 *fw_data; const __be32 *fw_data;
u32 mem_type, running, blackout = 0; u32 mem_type, running, blackout = 0;
...@@ -1129,6 +1132,12 @@ static int cayman_cp_start(struct radeon_device *rdev) ...@@ -1129,6 +1132,12 @@ static int cayman_cp_start(struct radeon_device *rdev)
return 0; return 0;
} }
static void cayman_cp_fini(struct radeon_device *rdev)
{
cayman_cp_enable(rdev, false);
radeon_ring_fini(rdev);
}
int cayman_cp_resume(struct radeon_device *rdev) int cayman_cp_resume(struct radeon_device *rdev)
{ {
u32 tmp; u32 tmp;
...@@ -1346,3 +1355,233 @@ int cayman_asic_reset(struct radeon_device *rdev) ...@@ -1346,3 +1355,233 @@ int cayman_asic_reset(struct radeon_device *rdev)
return cayman_gpu_soft_reset(rdev); return cayman_gpu_soft_reset(rdev);
} }
static int cayman_startup(struct radeon_device *rdev)
{
int r;
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) {
r = ni_init_microcode(rdev);
if (r) {
DRM_ERROR("Failed to load firmware!\n");
return r;
}
}
r = ni_mc_load_microcode(rdev);
if (r) {
DRM_ERROR("Failed to load MC firmware!\n");
return r;
}
evergreen_mc_program(rdev);
r = cayman_pcie_gart_enable(rdev);
if (r)
return r;
cayman_gpu_init(rdev);
#if 0
r = cayman_blit_init(rdev);
if (r) {
cayman_blit_fini(rdev);
rdev->asic->copy = NULL;
dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
}
#endif
/* allocate wb buffer */
r = radeon_wb_init(rdev);
if (r)
return r;
/* Enable IRQ */
r = r600_irq_init(rdev);
if (r) {
DRM_ERROR("radeon: IH init failed (%d).\n", r);
radeon_irq_kms_fini(rdev);
return r;
}
evergreen_irq_set(rdev);
r = radeon_ring_init(rdev, rdev->cp.ring_size);
if (r)
return r;
r = cayman_cp_load_microcode(rdev);
if (r)
return r;
r = cayman_cp_resume(rdev);
if (r)
return r;
return 0;
}
int cayman_resume(struct radeon_device *rdev)
{
int r;
/* Do not reset GPU before posting, on rv770 hw unlike on r500 hw,
* posting will perform necessary task to bring back GPU into good
* shape.
*/
/* post card */
atom_asic_init(rdev->mode_info.atom_context);
r = cayman_startup(rdev);
if (r) {
DRM_ERROR("cayman startup failed on resume\n");
return r;
}
r = r600_ib_test(rdev);
if (r) {
DRM_ERROR("radeon: failled testing IB (%d).\n", r);
return r;
}
return r;
}
int cayman_suspend(struct radeon_device *rdev)
{
/* int r; */
/* FIXME: we should wait for ring to be empty */
cayman_cp_enable(rdev, false);
rdev->cp.ready = false;
evergreen_irq_suspend(rdev);
radeon_wb_disable(rdev);
cayman_pcie_gart_disable(rdev);
#if 0
/* unpin shaders bo */
r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
if (likely(r == 0)) {
radeon_bo_unpin(rdev->r600_blit.shader_obj);
radeon_bo_unreserve(rdev->r600_blit.shader_obj);
}
#endif
return 0;
}
/* Plan is to move initialization in that function and use
* helper function so that radeon_device_init pretty much
* do nothing more than calling asic specific function. This
* should also allow to remove a bunch of callback function
* like vram_info.
*/
int cayman_init(struct radeon_device *rdev)
{
int r;
/* This don't do much */
r = radeon_gem_init(rdev);
if (r)
return r;
/* Read BIOS */
if (!radeon_get_bios(rdev)) {
if (ASIC_IS_AVIVO(rdev))
return -EINVAL;
}
/* Must be an ATOMBIOS */
if (!rdev->is_atom_bios) {
dev_err(rdev->dev, "Expecting atombios for cayman GPU\n");
return -EINVAL;
}
r = radeon_atombios_init(rdev);
if (r)
return r;
/* Post card if necessary */
if (!radeon_card_posted(rdev)) {
if (!rdev->bios) {
dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n");
return -EINVAL;
}
DRM_INFO("GPU not posted. posting now...\n");
atom_asic_init(rdev->mode_info.atom_context);
}
/* Initialize scratch registers */
r600_scratch_init(rdev);
/* Initialize surface registers */
radeon_surface_init(rdev);
/* Initialize clocks */
radeon_get_clock_info(rdev->ddev);
/* Fence driver */
r = radeon_fence_driver_init(rdev);
if (r)
return r;
/* initialize memory controller */
r = evergreen_mc_init(rdev);
if (r)
return r;
/* Memory manager */
r = radeon_bo_init(rdev);
if (r)
return r;
r = radeon_irq_kms_init(rdev);
if (r)
return r;
rdev->cp.ring_obj = NULL;
r600_ring_init(rdev, 1024 * 1024);
rdev->ih.ring_obj = NULL;
r600_ih_ring_init(rdev, 64 * 1024);
r = r600_pcie_gart_init(rdev);
if (r)
return r;
rdev->accel_working = true;
r = cayman_startup(rdev);
if (r) {
dev_err(rdev->dev, "disabling GPU acceleration\n");
cayman_cp_fini(rdev);
r600_irq_fini(rdev);
radeon_wb_fini(rdev);
radeon_irq_kms_fini(rdev);
cayman_pcie_gart_fini(rdev);
rdev->accel_working = false;
}
if (rdev->accel_working) {
r = radeon_ib_pool_init(rdev);
if (r) {
DRM_ERROR("radeon: failed initializing IB pool (%d).\n", r);
rdev->accel_working = false;
}
r = r600_ib_test(rdev);
if (r) {
DRM_ERROR("radeon: failed testing IB (%d).\n", r);
rdev->accel_working = false;
}
}
/* Don't start up if the MC ucode is missing.
* The default clocks and voltages before the MC ucode
* is loaded are not suffient for advanced operations.
*/
if (!rdev->mc_fw) {
DRM_ERROR("radeon: MC ucode required for NI+.\n");
return -EINVAL;
}
return 0;
}
void cayman_fini(struct radeon_device *rdev)
{
/* cayman_blit_fini(rdev); */
cayman_cp_fini(rdev);
r600_irq_fini(rdev);
radeon_wb_fini(rdev);
radeon_irq_kms_fini(rdev);
cayman_pcie_gart_fini(rdev);
radeon_gem_fini(rdev);
radeon_fence_driver_fini(rdev);
radeon_bo_fini(rdev);
radeon_atombios_fini(rdev);
kfree(rdev->bios);
rdev->bios = NULL;
}
...@@ -1501,7 +1501,7 @@ extern void r600_hdmi_disable(struct drm_encoder *encoder); ...@@ -1501,7 +1501,7 @@ extern void r600_hdmi_disable(struct drm_encoder *encoder);
extern void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode); extern void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
extern int ni_init_microcode(struct radeon_device *rdev); extern int ni_init_microcode(struct radeon_device *rdev);
extern int btc_mc_load_microcode(struct radeon_device *rdev); extern int ni_mc_load_microcode(struct radeon_device *rdev);
/* radeon_acpi.c */ /* radeon_acpi.c */
#if defined(CONFIG_ACPI) #if defined(CONFIG_ACPI)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment