mirror of
				https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
				synced 2025-10-31 00:01:35 +00:00 
			
		
		
		
	 43861f713c
			
		
	
	
		43861f713c
		
	
	
	
	
		
			
			Signed-off-by: Marek Olšák <maraeo@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
		
			
				
	
	
		
			368 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			368 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright 2008 Advanced Micro Devices, Inc.
 | |
|  * Copyright 2008 Red Hat Inc.
 | |
|  * Copyright 2009 Jerome Glisse.
 | |
|  *
 | |
|  * 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
 | |
|  *          Jerome Glisse
 | |
|  */
 | |
| #include "drmP.h"
 | |
| #include "drm_sarea.h"
 | |
| #include "radeon.h"
 | |
| #include "radeon_drm.h"
 | |
| 
 | |
| #include <linux/vga_switcheroo.h>
 | |
| #include <linux/slab.h>
 | |
| 
 | |
| int radeon_driver_unload_kms(struct drm_device *dev)
 | |
| {
 | |
| 	struct radeon_device *rdev = dev->dev_private;
 | |
| 
 | |
| 	if (rdev == NULL)
 | |
| 		return 0;
 | |
| 	radeon_modeset_fini(rdev);
 | |
| 	radeon_device_fini(rdev);
 | |
| 	kfree(rdev);
 | |
| 	dev->dev_private = NULL;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)
 | |
| {
 | |
| 	struct radeon_device *rdev;
 | |
| 	int r, acpi_status;
 | |
| 
 | |
| 	rdev = kzalloc(sizeof(struct radeon_device), GFP_KERNEL);
 | |
| 	if (rdev == NULL) {
 | |
| 		return -ENOMEM;
 | |
| 	}
 | |
| 	dev->dev_private = (void *)rdev;
 | |
| 
 | |
| 	/* update BUS flag */
 | |
| 	if (drm_device_is_agp(dev)) {
 | |
| 		flags |= RADEON_IS_AGP;
 | |
| 	} else if (drm_device_is_pcie(dev)) {
 | |
| 		flags |= RADEON_IS_PCIE;
 | |
| 	} else {
 | |
| 		flags |= RADEON_IS_PCI;
 | |
| 	}
 | |
| 
 | |
| 	/* radeon_device_init should report only fatal error
 | |
| 	 * like memory allocation failure or iomapping failure,
 | |
| 	 * or memory manager initialization failure, it must
 | |
| 	 * properly initialize the GPU MC controller and permit
 | |
| 	 * VRAM allocation
 | |
| 	 */
 | |
| 	r = radeon_device_init(rdev, dev, dev->pdev, flags);
 | |
| 	if (r) {
 | |
| 		dev_err(&dev->pdev->dev, "Fatal error during GPU init\n");
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	/* Call ACPI methods */
 | |
| 	acpi_status = radeon_acpi_init(rdev);
 | |
| 	if (acpi_status)
 | |
| 		dev_dbg(&dev->pdev->dev, "Error during ACPI methods call\n");
 | |
| 
 | |
| 	/* Again modeset_init should fail only on fatal error
 | |
| 	 * otherwise it should provide enough functionalities
 | |
| 	 * for shadowfb to run
 | |
| 	 */
 | |
| 	r = radeon_modeset_init(rdev);
 | |
| 	if (r)
 | |
| 		dev_err(&dev->pdev->dev, "Fatal error during modeset init\n");
 | |
| out:
 | |
| 	if (r)
 | |
| 		radeon_driver_unload_kms(dev);
 | |
| 	return r;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Userspace get informations ioctl
 | |
|  */
 | |
| int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 | |
| {
 | |
| 	struct radeon_device *rdev = dev->dev_private;
 | |
| 	struct drm_radeon_info *info;
 | |
| 	struct radeon_mode_info *minfo = &rdev->mode_info;
 | |
| 	uint32_t *value_ptr;
 | |
| 	uint32_t value;
 | |
| 	struct drm_crtc *crtc;
 | |
| 	int i, found;
 | |
| 
 | |
| 	info = data;
 | |
| 	value_ptr = (uint32_t *)((unsigned long)info->value);
 | |
| 	if (DRM_COPY_FROM_USER(&value, value_ptr, sizeof(value)))
 | |
| 		return -EFAULT;
 | |
| 
 | |
| 	switch (info->request) {
 | |
| 	case RADEON_INFO_DEVICE_ID:
 | |
| 		value = dev->pci_device;
 | |
| 		break;
 | |
| 	case RADEON_INFO_NUM_GB_PIPES:
 | |
| 		value = rdev->num_gb_pipes;
 | |
| 		break;
 | |
| 	case RADEON_INFO_NUM_Z_PIPES:
 | |
| 		value = rdev->num_z_pipes;
 | |
| 		break;
 | |
| 	case RADEON_INFO_ACCEL_WORKING:
 | |
| 		/* xf86-video-ati 6.13.0 relies on this being false for evergreen */
 | |
| 		if ((rdev->family >= CHIP_CEDAR) && (rdev->family <= CHIP_HEMLOCK))
 | |
| 			value = false;
 | |
| 		else
 | |
| 			value = rdev->accel_working;
 | |
| 		break;
 | |
| 	case RADEON_INFO_CRTC_FROM_ID:
 | |
| 		for (i = 0, found = 0; i < rdev->num_crtc; i++) {
 | |
| 			crtc = (struct drm_crtc *)minfo->crtcs[i];
 | |
| 			if (crtc && crtc->base.id == value) {
 | |
| 				struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
 | |
| 				value = radeon_crtc->crtc_id;
 | |
| 				found = 1;
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 		if (!found) {
 | |
| 			DRM_DEBUG_KMS("unknown crtc id %d\n", value);
 | |
| 			return -EINVAL;
 | |
| 		}
 | |
| 		break;
 | |
| 	case RADEON_INFO_ACCEL_WORKING2:
 | |
| 		value = rdev->accel_working;
 | |
| 		break;
 | |
| 	case RADEON_INFO_TILING_CONFIG:
 | |
| 		if (rdev->family >= CHIP_CEDAR)
 | |
| 			value = rdev->config.evergreen.tile_config;
 | |
| 		else if (rdev->family >= CHIP_RV770)
 | |
| 			value = rdev->config.rv770.tile_config;
 | |
| 		else if (rdev->family >= CHIP_R600)
 | |
| 			value = rdev->config.r600.tile_config;
 | |
| 		else {
 | |
| 			DRM_DEBUG_KMS("tiling config is r6xx+ only!\n");
 | |
| 			return -EINVAL;
 | |
| 		}
 | |
| 	case RADEON_INFO_WANT_HYPERZ:
 | |
| 		/* The "value" here is both an input and output parameter.
 | |
| 		 * If the input value is 1, filp requests hyper-z access.
 | |
| 		 * If the input value is 0, filp revokes its hyper-z access.
 | |
| 		 *
 | |
| 		 * When returning, the value is 1 if filp owns hyper-z access,
 | |
| 		 * 0 otherwise. */
 | |
| 		if (value >= 2) {
 | |
| 			DRM_DEBUG_KMS("WANT_HYPERZ: invalid value %d\n", value);
 | |
| 			return -EINVAL;
 | |
| 		}
 | |
| 		mutex_lock(&dev->struct_mutex);
 | |
| 		if (value == 1) {
 | |
| 			/* wants hyper-z */
 | |
| 			if (!rdev->hyperz_filp)
 | |
| 				rdev->hyperz_filp = filp;
 | |
| 		} else if (value == 0) {
 | |
| 			/* revokes hyper-z */
 | |
| 			if (rdev->hyperz_filp == filp)
 | |
| 				rdev->hyperz_filp = NULL;
 | |
| 		}
 | |
| 		value = rdev->hyperz_filp == filp ?  1 : 0;
 | |
| 		mutex_unlock(&dev->struct_mutex);
 | |
| 		break;
 | |
| 	default:
 | |
| 		DRM_DEBUG_KMS("Invalid request %d\n", info->request);
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 	if (DRM_COPY_TO_USER(value_ptr, &value, sizeof(uint32_t))) {
 | |
| 		DRM_ERROR("copy_to_user\n");
 | |
| 		return -EFAULT;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Outdated mess for old drm with Xorg being in charge (void function now).
 | |
|  */
 | |
| int radeon_driver_firstopen_kms(struct drm_device *dev)
 | |
| {
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| void radeon_driver_lastclose_kms(struct drm_device *dev)
 | |
| {
 | |
| 	vga_switcheroo_process_delayed_switch();
 | |
| }
 | |
| 
 | |
| int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
 | |
| {
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void radeon_driver_postclose_kms(struct drm_device *dev,
 | |
| 				 struct drm_file *file_priv)
 | |
| {
 | |
| }
 | |
| 
 | |
| void radeon_driver_preclose_kms(struct drm_device *dev,
 | |
| 				struct drm_file *file_priv)
 | |
| {
 | |
| 	struct radeon_device *rdev = dev->dev_private;
 | |
| 	if (rdev->hyperz_filp == file_priv)
 | |
| 		rdev->hyperz_filp = NULL;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * VBlank related functions.
 | |
|  */
 | |
| u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc)
 | |
| {
 | |
| 	struct radeon_device *rdev = dev->dev_private;
 | |
| 
 | |
| 	if (crtc < 0 || crtc >= rdev->num_crtc) {
 | |
| 		DRM_ERROR("Invalid crtc %d\n", crtc);
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	return radeon_get_vblank_counter(rdev, crtc);
 | |
| }
 | |
| 
 | |
| int radeon_enable_vblank_kms(struct drm_device *dev, int crtc)
 | |
| {
 | |
| 	struct radeon_device *rdev = dev->dev_private;
 | |
| 
 | |
| 	if (crtc < 0 || crtc >= rdev->num_crtc) {
 | |
| 		DRM_ERROR("Invalid crtc %d\n", crtc);
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	rdev->irq.crtc_vblank_int[crtc] = true;
 | |
| 
 | |
| 	return radeon_irq_set(rdev);
 | |
| }
 | |
| 
 | |
| void radeon_disable_vblank_kms(struct drm_device *dev, int crtc)
 | |
| {
 | |
| 	struct radeon_device *rdev = dev->dev_private;
 | |
| 
 | |
| 	if (crtc < 0 || crtc >= rdev->num_crtc) {
 | |
| 		DRM_ERROR("Invalid crtc %d\n", crtc);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	rdev->irq.crtc_vblank_int[crtc] = false;
 | |
| 
 | |
| 	radeon_irq_set(rdev);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * IOCTL.
 | |
|  */
 | |
| int radeon_dma_ioctl_kms(struct drm_device *dev, void *data,
 | |
| 			 struct drm_file *file_priv)
 | |
| {
 | |
| 	/* Not valid in KMS. */
 | |
| 	return -EINVAL;
 | |
| }
 | |
| 
 | |
| #define KMS_INVALID_IOCTL(name)						\
 | |
| 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)
 | |
| 
 | |
| 
 | |
| struct drm_ioctl_desc radeon_ioctls_kms[] = {
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_CP_INIT, radeon_cp_init_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_CP_START, radeon_cp_start_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_CP_STOP, radeon_cp_stop_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_CP_RESET, radeon_cp_reset_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_CP_IDLE, radeon_cp_idle_kms, DRM_AUTH),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_CP_RESUME, radeon_cp_resume_kms, DRM_AUTH),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_RESET, radeon_engine_reset_kms, DRM_AUTH),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_FULLSCREEN, radeon_fullscreen_kms, DRM_AUTH),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_SWAP, radeon_cp_swap_kms, DRM_AUTH),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_CLEAR, radeon_cp_clear_kms, DRM_AUTH),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_VERTEX, radeon_cp_vertex_kms, DRM_AUTH),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_INDICES, radeon_cp_indices_kms, DRM_AUTH),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_TEXTURE, radeon_cp_texture_kms, DRM_AUTH),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_STIPPLE, radeon_cp_stipple_kms, DRM_AUTH),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_INDIRECT, radeon_cp_indirect_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_VERTEX2, radeon_cp_vertex2_kms, DRM_AUTH),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_CMDBUF, radeon_cp_cmdbuf_kms, DRM_AUTH),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_GETPARAM, radeon_cp_getparam_kms, DRM_AUTH),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_FLIP, radeon_cp_flip_kms, DRM_AUTH),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_ALLOC, radeon_mem_alloc_kms, DRM_AUTH),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_FREE, radeon_mem_free_kms, DRM_AUTH),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_INIT_HEAP, radeon_mem_init_heap_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_IRQ_EMIT, radeon_irq_emit_kms, DRM_AUTH),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_IRQ_WAIT, radeon_irq_wait_kms, DRM_AUTH),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_SETPARAM, radeon_cp_setparam_kms, DRM_AUTH),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_SURF_ALLOC, radeon_surface_alloc_kms, DRM_AUTH),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free_kms, DRM_AUTH),
 | |
| 	/* KMS */
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_GEM_INFO, radeon_gem_info_ioctl, DRM_AUTH|DRM_UNLOCKED),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_GEM_CREATE, radeon_gem_create_ioctl, DRM_AUTH|DRM_UNLOCKED),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_GEM_MMAP, radeon_gem_mmap_ioctl, DRM_AUTH|DRM_UNLOCKED),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_DOMAIN, radeon_gem_set_domain_ioctl, DRM_AUTH|DRM_UNLOCKED),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_GEM_PREAD, radeon_gem_pread_ioctl, DRM_AUTH|DRM_UNLOCKED),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_GEM_PWRITE, radeon_gem_pwrite_ioctl, DRM_AUTH|DRM_UNLOCKED),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_GEM_WAIT_IDLE, radeon_gem_wait_idle_ioctl, DRM_AUTH|DRM_UNLOCKED),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_CS, radeon_cs_ioctl, DRM_AUTH|DRM_UNLOCKED),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_INFO, radeon_info_ioctl, DRM_AUTH|DRM_UNLOCKED),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_TILING, radeon_gem_set_tiling_ioctl, DRM_AUTH|DRM_UNLOCKED),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_GEM_GET_TILING, radeon_gem_get_tiling_ioctl, DRM_AUTH|DRM_UNLOCKED),
 | |
| 	DRM_IOCTL_DEF(DRM_RADEON_GEM_BUSY, radeon_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED),
 | |
| };
 | |
| int radeon_max_kms_ioctl = DRM_ARRAY_SIZE(radeon_ioctls_kms);
 |