diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_display.c')
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 80 | 
1 files changed, 80 insertions, 0 deletions
| diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index b119d27271c1..35c778426a7c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -33,6 +33,7 @@  #include "soc15_common.h"  #include "gc/gc_11_0_0_offset.h"  #include "gc/gc_11_0_0_sh_mask.h" +#include "bif/bif_4_1_d.h"  #include <asm/div64.h>  #include <linux/pci.h> @@ -1788,3 +1789,82 @@ int amdgpu_display_resume_helper(struct amdgpu_device *adev)  	return 0;  } +/* panic_bo is set in amdgpu_dm_plane_get_scanout_buffer() and only used in amdgpu_dm_set_pixel() + * they are called from the panic handler, and protected by the drm_panic spinlock. + */ +static struct amdgpu_bo *panic_abo; + +/* Use the indirect MMIO to write each pixel to the GPU VRAM, + * This is a simplified version of amdgpu_device_mm_access() + */ +static void amdgpu_display_set_pixel(struct drm_scanout_buffer *sb, +				     unsigned int x, +				     unsigned int y, +				     u32 color) +{ +	struct amdgpu_res_cursor cursor; +	unsigned long offset; +	struct amdgpu_bo *abo = panic_abo; +	struct amdgpu_device *adev = amdgpu_ttm_adev(abo->tbo.bdev); +	uint32_t tmp; + +	offset = x * 4 + y * sb->pitch[0]; +	amdgpu_res_first(abo->tbo.resource, offset, 4, &cursor); + +	tmp = cursor.start >> 31; +	WREG32_NO_KIQ(mmMM_INDEX, ((uint32_t) cursor.start) | 0x80000000); +	if (tmp != 0xffffffff) +		WREG32_NO_KIQ(mmMM_INDEX_HI, tmp); +	WREG32_NO_KIQ(mmMM_DATA, color); +} + +int amdgpu_display_get_scanout_buffer(struct drm_plane *plane, +				      struct drm_scanout_buffer *sb) +{ +	struct amdgpu_bo *abo; +	struct drm_framebuffer *fb = plane->state->fb; + +	if (!fb) +		return -EINVAL; + +	DRM_DEBUG_KMS("Framebuffer %dx%d %p4cc\n", fb->width, fb->height, &fb->format->format); + +	abo = gem_to_amdgpu_bo(fb->obj[0]); +	if (!abo) +		return -EINVAL; + +	sb->width = fb->width; +	sb->height = fb->height; +	/* Use the generic linear format, because tiling will be disabled in panic_flush() */ +	sb->format = drm_format_info(fb->format->format); +	if (!sb->format) +		return -EINVAL; + +	sb->pitch[0] = fb->pitches[0]; + +	if (abo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS) { +		if (abo->tbo.resource->mem_type != TTM_PL_VRAM) { +			drm_warn(plane->dev, "amdgpu panic, framebuffer not in VRAM\n"); +			return -EINVAL; +		} +		/* Only handle 32bits format, to simplify mmio access */ +		if (fb->format->cpp[0] != 4) { +			drm_warn(plane->dev, "amdgpu panic, pixel format is not 32bits\n"); +			return -EINVAL; +		} +		sb->set_pixel = amdgpu_display_set_pixel; +		panic_abo = abo; +		return 0; +	} +	if (!abo->kmap.virtual && +	    ttm_bo_kmap(&abo->tbo, 0, PFN_UP(abo->tbo.base.size), &abo->kmap)) { +		drm_warn(plane->dev, "amdgpu bo map failed, panic won't be displayed\n"); +		return -ENOMEM; +	} +	if (abo->kmap.bo_kmap_type & TTM_BO_MAP_IOMEM_MASK) +		iosys_map_set_vaddr_iomem(&sb->map[0], abo->kmap.virtual); +	else +		iosys_map_set_vaddr(&sb->map[0], abo->kmap.virtual); + +	return 0; +} | 
