Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+5 −5
Original line number Original line Diff line number Diff line
@@ -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)
	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)
				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)


	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)
	}
	}
	/* 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);
+240 −1
Original line number Original line Diff line number Diff line
@@ -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] = {
	{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)
	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)
	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;
}
+1 −1
Original line number Original line Diff line number Diff line
@@ -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)