832 lines · 24.3 KB · C
RawDownload
/* * Copyright 2007-8 Advanced Micro Devices, Inc. * Copyright 2008 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 *          Alex Deucher */#include <drm/drmP.h>#include <drm/amdgpu_drm.h>#include "amdgpu.h"#include "amdgpu_i2c.h"#include "atom.h"#include "amdgpu_connectors.h"#include <asm/div64.h> #include <linux/pm_runtime.h>#include <drm/drm_crtc_helper.h>#include <drm/drm_edid.h>  static void amdgpu_flip_work_func(struct work_struct *__work){	struct amdgpu_flip_work *work =		container_of(__work, struct amdgpu_flip_work, flip_work);	struct amdgpu_device *adev = work->adev;	struct amdgpu_crtc *amdgpuCrtc = adev->mode_info.crtcs[work->crtc_id]; 	struct drm_crtc *crtc = &amdgpuCrtc->base;	struct amdgpu_fence *fence;	unsigned long flags;	int r; 	down_read(&adev->exclusive_lock);	if (work->fence) {		fence = to_amdgpu_fence(work->fence);		if (fence) {			r = amdgpu_fence_wait(fence, false);			if (r == -EDEADLK) {				up_read(&adev->exclusive_lock);				r = amdgpu_gpu_reset(adev);				down_read(&adev->exclusive_lock);			}		} else			r = fence_wait(work->fence, false); 		if (r)			DRM_ERROR("failed to wait on page flip fence (%d)!\n", r); 		/* We continue with the page flip even if we failed to wait on		 * the fence, otherwise the DRM core and userspace will be		 * confused about which BO the CRTC is scanning out		 */ 		fence_put(work->fence);		work->fence = NULL;	} 	/* We borrow the event spin lock for protecting flip_status */	spin_lock_irqsave(&crtc->dev->event_lock, flags); 	/* set the proper interrupt */	amdgpu_irq_get(adev, &adev->pageflip_irq, work->crtc_id);	/* do the flip (mmio) */	adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base);	/* set the flip status */	amdgpuCrtc->pflip_status = AMDGPU_FLIP_SUBMITTED; 	spin_unlock_irqrestore(&crtc->dev->event_lock, flags);	up_read(&adev->exclusive_lock);} /* * Handle unpin events outside the interrupt handler proper. */static void amdgpu_unpin_work_func(struct work_struct *__work){	struct amdgpu_flip_work *work =		container_of(__work, struct amdgpu_flip_work, unpin_work);	int r; 	/* unpin of the old buffer */	r = amdgpu_bo_reserve(work->old_rbo, false);	if (likely(r == 0)) {		r = amdgpu_bo_unpin(work->old_rbo);		if (unlikely(r != 0)) {			DRM_ERROR("failed to unpin buffer after flip\n");		}		amdgpu_bo_unreserve(work->old_rbo);	} else		DRM_ERROR("failed to reserve buffer after flip\n"); 	drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base);	kfree(work);} int amdgpu_crtc_page_flip(struct drm_crtc *crtc,			  struct drm_framebuffer *fb,			  struct drm_pending_vblank_event *event,			  uint32_t page_flip_flags){	struct drm_device *dev = crtc->dev;	struct amdgpu_device *adev = dev->dev_private;	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);	struct amdgpu_framebuffer *old_amdgpu_fb;	struct amdgpu_framebuffer *new_amdgpu_fb;	struct drm_gem_object *obj;	struct amdgpu_flip_work *work;	struct amdgpu_bo *new_rbo;	unsigned long flags;	u64 tiling_flags;	u64 base;	int r; 	work = kzalloc(sizeof *work, GFP_KERNEL);	if (work == NULL)		return -ENOMEM; 	INIT_WORK(&work->flip_work, amdgpu_flip_work_func);	INIT_WORK(&work->unpin_work, amdgpu_unpin_work_func); 	work->event = event;	work->adev = adev;	work->crtc_id = amdgpu_crtc->crtc_id; 	/* schedule unpin of the old buffer */	old_amdgpu_fb = to_amdgpu_framebuffer(crtc->primary->fb);	obj = old_amdgpu_fb->obj; 	/* take a reference to the old object */	drm_gem_object_reference(obj);	work->old_rbo = gem_to_amdgpu_bo(obj); 	new_amdgpu_fb = to_amdgpu_framebuffer(fb);	obj = new_amdgpu_fb->obj;	new_rbo = gem_to_amdgpu_bo(obj); 	/* pin the new buffer */	r = amdgpu_bo_reserve(new_rbo, false);	if (unlikely(r != 0)) {		DRM_ERROR("failed to reserve new rbo buffer before flip\n");		goto cleanup;	} 	r = amdgpu_bo_pin_restricted(new_rbo, AMDGPU_GEM_DOMAIN_VRAM, 0, 0, &base);	if (unlikely(r != 0)) {		amdgpu_bo_unreserve(new_rbo);		r = -EINVAL;		DRM_ERROR("failed to pin new rbo buffer before flip\n");		goto cleanup;	} 	work->fence = fence_get(reservation_object_get_excl(new_rbo->tbo.resv));	amdgpu_bo_get_tiling_flags(new_rbo, &tiling_flags);	amdgpu_bo_unreserve(new_rbo); 	work->base = base; 	r = drm_vblank_get(crtc->dev, amdgpu_crtc->crtc_id);	if (r) {		DRM_ERROR("failed to get vblank before flip\n");		goto pflip_cleanup;	} 	/* we borrow the event spin lock for protecting flip_wrok */	spin_lock_irqsave(&crtc->dev->event_lock, flags);	if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_NONE) {		DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");		spin_unlock_irqrestore(&crtc->dev->event_lock, flags);		r = -EBUSY;		goto vblank_cleanup;	} 	amdgpu_crtc->pflip_status = AMDGPU_FLIP_PENDING;	amdgpu_crtc->pflip_works = work; 	/* update crtc fb */	crtc->primary->fb = fb;	spin_unlock_irqrestore(&crtc->dev->event_lock, flags);	queue_work(amdgpu_crtc->pflip_queue, &work->flip_work);	return 0; vblank_cleanup:	drm_vblank_put(crtc->dev, amdgpu_crtc->crtc_id); pflip_cleanup:	if (unlikely(amdgpu_bo_reserve(new_rbo, false) != 0)) {		DRM_ERROR("failed to reserve new rbo in error path\n");		goto cleanup;	}	if (unlikely(amdgpu_bo_unpin(new_rbo) != 0)) {		DRM_ERROR("failed to unpin new rbo in error path\n");	}	amdgpu_bo_unreserve(new_rbo); cleanup:	drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base);	fence_put(work->fence);	kfree(work); 	return r;} int amdgpu_crtc_set_config(struct drm_mode_set *set){	struct drm_device *dev;	struct amdgpu_device *adev;	struct drm_crtc *crtc;	bool active = false;	int ret; 	if (!set || !set->crtc)		return -EINVAL; 	dev = set->crtc->dev; 	ret = pm_runtime_get_sync(dev->dev);	if (ret < 0)		return ret; 	ret = drm_crtc_helper_set_config(set); 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)		if (crtc->enabled)			active = true; 	pm_runtime_mark_last_busy(dev->dev); 	adev = dev->dev_private;	/* if we have active crtcs and we don't have a power ref,	   take the current one */	if (active && !adev->have_disp_power_ref) {		adev->have_disp_power_ref = true;		return ret;	}	/* if we have no active crtcs, then drop the power ref	   we got before */	if (!active && adev->have_disp_power_ref) {		pm_runtime_put_autosuspend(dev->dev);		adev->have_disp_power_ref = false;	} 	/* drop the power reference we got coming in here */	pm_runtime_put_autosuspend(dev->dev);	return ret;} static const char *encoder_names[38] = {	"NONE",	"INTERNAL_LVDS",	"INTERNAL_TMDS1",	"INTERNAL_TMDS2",	"INTERNAL_DAC1",	"INTERNAL_DAC2",	"INTERNAL_SDVOA",	"INTERNAL_SDVOB",	"SI170B",	"CH7303",	"CH7301",	"INTERNAL_DVO1",	"EXTERNAL_SDVOA",	"EXTERNAL_SDVOB",	"TITFP513",	"INTERNAL_LVTM1",	"VT1623",	"HDMI_SI1930",	"HDMI_INTERNAL",	"INTERNAL_KLDSCP_TMDS1",	"INTERNAL_KLDSCP_DVO1",	"INTERNAL_KLDSCP_DAC1",	"INTERNAL_KLDSCP_DAC2",	"SI178",	"MVPU_FPGA",	"INTERNAL_DDI",	"VT1625",	"HDMI_SI1932",	"DP_AN9801",	"DP_DP501",	"INTERNAL_UNIPHY",	"INTERNAL_KLDSCP_LVTMA",	"INTERNAL_UNIPHY1",	"INTERNAL_UNIPHY2",	"NUTMEG",	"TRAVIS",	"INTERNAL_VCE",	"INTERNAL_UNIPHY3",}; static const char *hpd_names[6] = {	"HPD1",	"HPD2",	"HPD3",	"HPD4",	"HPD5",	"HPD6",}; void amdgpu_print_display_setup(struct drm_device *dev){	struct drm_connector *connector;	struct amdgpu_connector *amdgpu_connector;	struct drm_encoder *encoder;	struct amdgpu_encoder *amdgpu_encoder;	uint32_t devices;	int i = 0; 	DRM_INFO("AMDGPU Display Connectors\n");	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {		amdgpu_connector = to_amdgpu_connector(connector);		DRM_INFO("Connector %d:\n", i);		DRM_INFO("  %s\n", connector->name);		if (amdgpu_connector->hpd.hpd != AMDGPU_HPD_NONE)			DRM_INFO("  %s\n", hpd_names[amdgpu_connector->hpd.hpd]);		if (amdgpu_connector->ddc_bus) {			DRM_INFO("  DDC: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",				 amdgpu_connector->ddc_bus->rec.mask_clk_reg,				 amdgpu_connector->ddc_bus->rec.mask_data_reg,				 amdgpu_connector->ddc_bus->rec.a_clk_reg,				 amdgpu_connector->ddc_bus->rec.a_data_reg,				 amdgpu_connector->ddc_bus->rec.en_clk_reg,				 amdgpu_connector->ddc_bus->rec.en_data_reg,				 amdgpu_connector->ddc_bus->rec.y_clk_reg,				 amdgpu_connector->ddc_bus->rec.y_data_reg);			if (amdgpu_connector->router.ddc_valid)				DRM_INFO("  DDC Router 0x%x/0x%x\n",					 amdgpu_connector->router.ddc_mux_control_pin,					 amdgpu_connector->router.ddc_mux_state);			if (amdgpu_connector->router.cd_valid)				DRM_INFO("  Clock/Data Router 0x%x/0x%x\n",					 amdgpu_connector->router.cd_mux_control_pin,					 amdgpu_connector->router.cd_mux_state);		} else {			if (connector->connector_type == DRM_MODE_CONNECTOR_VGA ||			    connector->connector_type == DRM_MODE_CONNECTOR_DVII ||			    connector->connector_type == DRM_MODE_CONNECTOR_DVID ||			    connector->connector_type == DRM_MODE_CONNECTOR_DVIA ||			    connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||			    connector->connector_type == DRM_MODE_CONNECTOR_HDMIB)				DRM_INFO("  DDC: no ddc bus - possible BIOS bug - please report to xorg-driver-ati@lists.x.org\n");		}		DRM_INFO("  Encoders:\n");		list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {			amdgpu_encoder = to_amdgpu_encoder(encoder);			devices = amdgpu_encoder->devices & amdgpu_connector->devices;			if (devices) {				if (devices & ATOM_DEVICE_CRT1_SUPPORT)					DRM_INFO("    CRT1: %s\n", encoder_names[amdgpu_encoder->encoder_id]);				if (devices & ATOM_DEVICE_CRT2_SUPPORT)					DRM_INFO("    CRT2: %s\n", encoder_names[amdgpu_encoder->encoder_id]);				if (devices & ATOM_DEVICE_LCD1_SUPPORT)					DRM_INFO("    LCD1: %s\n", encoder_names[amdgpu_encoder->encoder_id]);				if (devices & ATOM_DEVICE_DFP1_SUPPORT)					DRM_INFO("    DFP1: %s\n", encoder_names[amdgpu_encoder->encoder_id]);				if (devices & ATOM_DEVICE_DFP2_SUPPORT)					DRM_INFO("    DFP2: %s\n", encoder_names[amdgpu_encoder->encoder_id]);				if (devices & ATOM_DEVICE_DFP3_SUPPORT)					DRM_INFO("    DFP3: %s\n", encoder_names[amdgpu_encoder->encoder_id]);				if (devices & ATOM_DEVICE_DFP4_SUPPORT)					DRM_INFO("    DFP4: %s\n", encoder_names[amdgpu_encoder->encoder_id]);				if (devices & ATOM_DEVICE_DFP5_SUPPORT)					DRM_INFO("    DFP5: %s\n", encoder_names[amdgpu_encoder->encoder_id]);				if (devices & ATOM_DEVICE_DFP6_SUPPORT)					DRM_INFO("    DFP6: %s\n", encoder_names[amdgpu_encoder->encoder_id]);				if (devices & ATOM_DEVICE_TV1_SUPPORT)					DRM_INFO("    TV1: %s\n", encoder_names[amdgpu_encoder->encoder_id]);				if (devices & ATOM_DEVICE_CV_SUPPORT)					DRM_INFO("    CV: %s\n", encoder_names[amdgpu_encoder->encoder_id]);			}		}		i++;	}} /** * amdgpu_ddc_probe * */bool amdgpu_ddc_probe(struct amdgpu_connector *amdgpu_connector,		       bool use_aux){	u8 out = 0x0;	u8 buf[8];	int ret;	struct i2c_msg msgs[] = {		{			.addr = DDC_ADDR,			.flags = 0,			.len = 1,			.buf = &out,		},		{			.addr = DDC_ADDR,			.flags = I2C_M_RD,			.len = 8,			.buf = buf,		}	}; 	/* on hw with routers, select right port */	if (amdgpu_connector->router.ddc_valid)		amdgpu_i2c_router_select_ddc_port(amdgpu_connector); 	if (use_aux) {		ret = i2c_transfer(&amdgpu_connector->ddc_bus->aux.ddc, msgs, 2);	} else {		ret = i2c_transfer(&amdgpu_connector->ddc_bus->adapter, msgs, 2);	} 	if (ret != 2)		/* Couldn't find an accessible DDC on this connector */		return false;	/* Probe also for valid EDID header	 * EDID header starts with:	 * 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00.	 * Only the first 6 bytes must be valid as	 * drm_edid_block_valid() can fix the last 2 bytes */	if (drm_edid_header_is_valid(buf) < 6) {		/* Couldn't find an accessible EDID on this		 * connector */		return false;	}	return true;} static void amdgpu_user_framebuffer_destroy(struct drm_framebuffer *fb){	struct amdgpu_framebuffer *amdgpu_fb = to_amdgpu_framebuffer(fb); 	if (amdgpu_fb->obj) {		drm_gem_object_unreference_unlocked(amdgpu_fb->obj);	}	drm_framebuffer_cleanup(fb);	kfree(amdgpu_fb);} static int amdgpu_user_framebuffer_create_handle(struct drm_framebuffer *fb,						  struct drm_file *file_priv,						  unsigned int *handle){	struct amdgpu_framebuffer *amdgpu_fb = to_amdgpu_framebuffer(fb); 	return drm_gem_handle_create(file_priv, amdgpu_fb->obj, handle);} static const struct drm_framebuffer_funcs amdgpu_fb_funcs = {	.destroy = amdgpu_user_framebuffer_destroy,	.create_handle = amdgpu_user_framebuffer_create_handle,}; intamdgpu_framebuffer_init(struct drm_device *dev,			struct amdgpu_framebuffer *rfb,			struct drm_mode_fb_cmd2 *mode_cmd,			struct drm_gem_object *obj){	int ret;	rfb->obj = obj;	drm_helper_mode_fill_fb_struct(&rfb->base, mode_cmd);	ret = drm_framebuffer_init(dev, &rfb->base, &amdgpu_fb_funcs);	if (ret) {		rfb->obj = NULL;		return ret;	}	return 0;} static struct drm_framebuffer *amdgpu_user_framebuffer_create(struct drm_device *dev,			       struct drm_file *file_priv,			       struct drm_mode_fb_cmd2 *mode_cmd){	struct drm_gem_object *obj;	struct amdgpu_framebuffer *amdgpu_fb;	int ret; 	obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);	if (obj ==  NULL) {		dev_err(&dev->pdev->dev, "No GEM object associated to handle 0x%08X, "			"can't create framebuffer\n", mode_cmd->handles[0]);		return ERR_PTR(-ENOENT);	} 	amdgpu_fb = kzalloc(sizeof(*amdgpu_fb), GFP_KERNEL);

Lines 1–500 of 832.