diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-17 13:40:25 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-17 13:40:25 -0800 | 
| commit | 984065055e6e39f8dd812529e11922374bd39352 (patch) | |
| tree | a8f1bcbd81e0fadce0cef39ab5ce09ab84b261fe /drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c | |
| parent | 12768c1e2c83b05ea1658470045789a14b6edf4c (diff) | |
| parent | 1df59b8497f47495e873c23abd6d3d290c730505 (diff) | |
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm updates from Dave Airlie:
 "This is the main drm pull request for 4.5.  I don't think I've missed
  anything too major, I'm mostly back at work now but I'll probably get
  some sleep in 5 years time.
  Summary:
  New drivers:
   - etnaviv:
     GPU driver for the 3D core on the Vivante core used in numerous
     ARM boards.
  Highlights:
  Core:
   - Atomic suspend/resume helpers
   - Move the headers to using userspace friendlier types.
   - Documentation updates
   - Lots of struct_mutex removal.
   - Bunch of DP MST fixes from AMD.
  Panel:
   - More DSI helpers
   - Support for some new basic panels
  i915:
   - Basic Kabylake support
   - DP link training and detect code refactoring
   - fbc/psr fixes
   - FIFO underrun fixes
   - SDE interrupt handling fixes
   - dma-buf/fence support in pageflip path.
   - GPU side for MST audio support
  radeon/amdgpu:
   - Drop UMS support
   - GPUVM/Scheduler optimisations
   - Initial Powerplay support for Tonga/Fiji/CZ/ST
   - ACP audio prerequisites
  nouveau:
   - GK20a instmem improvements
   - PCIE link speed change support
  msm:
   - DSI support for msm8960/apq8064
  tegra:
   - Host1X support for Tegra210 SoC
  vc4:
   - 3D acceleration support
  armada:
   - Get rid of struct mutex
  tda998x:
   - Atomic modesetting support
   - TMDS clock limitations
  omapdrm:
   - Atomic modesetting support
   - improved TILER performance
  rockchip:
   - RK3036 VOP support
   - Atomic modesetting support
   - Synopsys DW MIPI DSI support
  exynos:
   - Runtime PM support
   - of_graph binding for DP panels
   - Cleanup of IPP code
   - Configurable plane support
   - Kernel panic fixes at release time"
* 'drm-next' of git://people.freedesktop.org/~airlied/linux: (711 commits)
  drm/fb_cma_helper: Remove implicit call to disable_unused_functions
  drm/amdgpu: add missing irq.h include
  drm/vmwgfx: Fix a width / pitch mismatch on framebuffer updates
  drm/vmwgfx: Fix an incorrect lock check
  drm: nouveau: fix nouveau_debugfs_init prototype
  drm/nouveau/pci: fix check in nvkm_pcie_set_link
  drm/amdgpu: validate duplicates first
  drm/amdgpu: move VM page tables to the LRU end on CS v2
  drm/ttm: add ttm_bo_move_to_lru_tail function v2
  drm/ttm: fix adding foreign BOs to the swap LRU
  drm/ttm: fix adding foreign BOs to the LRU during init v2
  drm/radeon: use kobj_to_dev()
  drm/amdgpu: use kobj_to_dev()
  drm/amdgpu/cz: force vce clocks when sclks are forced
  drm/amdgpu/cz: force uvd clocks when sclks are forced
  drm/amdgpu/cz: add code to enable forcing VCE clocks
  drm/amdgpu/cz: add code to enable forcing UVD clocks
  drm/amdgpu: fix lost sync_to if scheduler is enabled.
  drm/amd/powerplay: fix static checker warning for return meaningless value.
  drm/sysfs: use kobj_to_dev()
  ...
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c')
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c | 328 | 
1 files changed, 326 insertions, 2 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c index 8e995148f56e..a081dda9fa2f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c @@ -24,6 +24,7 @@  #include <linux/list.h>  #include <linux/slab.h>  #include <linux/pci.h> +#include <linux/acpi.h>  #include <drm/drmP.h>  #include <linux/firmware.h>  #include <drm/amdgpu_drm.h> @@ -32,7 +33,6 @@  #include "atom.h"  #include "amdgpu_ucode.h" -  struct amdgpu_cgs_device {  	struct cgs_device base;  	struct amdgpu_device *adev; @@ -398,6 +398,41 @@ static void amdgpu_cgs_write_pci_config_dword(void *cgs_device, unsigned addr,  	WARN(ret, "pci_write_config_dword error");  } + +static int amdgpu_cgs_get_pci_resource(void *cgs_device, +				       enum cgs_resource_type resource_type, +				       uint64_t size, +				       uint64_t offset, +				       uint64_t *resource_base) +{ +	CGS_FUNC_ADEV; + +	if (resource_base == NULL) +		return -EINVAL; + +	switch (resource_type) { +	case CGS_RESOURCE_TYPE_MMIO: +		if (adev->rmmio_size == 0) +			return -ENOENT; +		if ((offset + size) > adev->rmmio_size) +			return -EINVAL; +		*resource_base = adev->rmmio_base; +		return 0; +	case CGS_RESOURCE_TYPE_DOORBELL: +		if (adev->doorbell.size == 0) +			return -ENOENT; +		if ((offset + size) > adev->doorbell.size) +			return -EINVAL; +		*resource_base = adev->doorbell.base; +		return 0; +	case CGS_RESOURCE_TYPE_FB: +	case CGS_RESOURCE_TYPE_IO: +	case CGS_RESOURCE_TYPE_ROM: +	default: +		return -EINVAL; +	} +} +  static const void *amdgpu_cgs_atom_get_data_table(void *cgs_device,  						  unsigned table, uint16_t *size,  						  uint8_t *frev, uint8_t *crev) @@ -703,6 +738,9 @@ static int amdgpu_cgs_get_firmware_info(void *cgs_device,  		case CHIP_TONGA:  			strcpy(fw_name, "amdgpu/tonga_smc.bin");  			break; +		case CHIP_FIJI: +			strcpy(fw_name, "amdgpu/fiji_smc.bin"); +			break;  		default:  			DRM_ERROR("SMC firmware not supported\n");  			return -EINVAL; @@ -736,6 +774,288 @@ static int amdgpu_cgs_get_firmware_info(void *cgs_device,  	return 0;  } +static int amdgpu_cgs_query_system_info(void *cgs_device, +				struct cgs_system_info *sys_info) +{ +	CGS_FUNC_ADEV; + +	if (NULL == sys_info) +		return -ENODEV; + +	if (sizeof(struct cgs_system_info) != sys_info->size) +		return -ENODEV; + +	switch (sys_info->info_id) { +	case CGS_SYSTEM_INFO_ADAPTER_BDF_ID: +		sys_info->value = adev->pdev->devfn | (adev->pdev->bus->number << 8); +		break; +	case CGS_SYSTEM_INFO_PCIE_GEN_INFO: +		sys_info->value = adev->pm.pcie_gen_mask; +		break; +	case CGS_SYSTEM_INFO_PCIE_MLW: +		sys_info->value = adev->pm.pcie_mlw_mask; +		break; +	default: +		return -ENODEV; +	} + +	return 0; +} + +static int amdgpu_cgs_get_active_displays_info(void *cgs_device, +					  struct cgs_display_info *info) +{ +	CGS_FUNC_ADEV; +	struct amdgpu_crtc *amdgpu_crtc; +	struct drm_device *ddev = adev->ddev; +	struct drm_crtc *crtc; +	uint32_t line_time_us, vblank_lines; + +	if (info == NULL) +		return -EINVAL; + +	if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) { +		list_for_each_entry(crtc, +				&ddev->mode_config.crtc_list, head) { +			amdgpu_crtc = to_amdgpu_crtc(crtc); +			if (crtc->enabled) { +				info->active_display_mask |= (1 << amdgpu_crtc->crtc_id); +				info->display_count++; +			} +			if (info->mode_info != NULL && +				crtc->enabled && amdgpu_crtc->enabled && +				amdgpu_crtc->hw_mode.clock) { +				line_time_us = (amdgpu_crtc->hw_mode.crtc_htotal * 1000) / +							amdgpu_crtc->hw_mode.clock; +				vblank_lines = amdgpu_crtc->hw_mode.crtc_vblank_end - +							amdgpu_crtc->hw_mode.crtc_vdisplay + +							(amdgpu_crtc->v_border * 2); +				info->mode_info->vblank_time_us = vblank_lines * line_time_us; +				info->mode_info->refresh_rate = drm_mode_vrefresh(&amdgpu_crtc->hw_mode); +				info->mode_info->ref_clock = adev->clock.spll.reference_freq; +				info->mode_info++; +			} +		} +	} + +	return 0; +} + +/** \brief evaluate acpi namespace object, handle or pathname must be valid + *  \param cgs_device + *  \param info input/output arguments for the control method + *  \return status + */ + +#if defined(CONFIG_ACPI) +static int amdgpu_cgs_acpi_eval_object(void *cgs_device, +				    struct cgs_acpi_method_info *info) +{ +	CGS_FUNC_ADEV; +	acpi_handle handle; +	struct acpi_object_list input; +	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; +	union acpi_object *params = NULL; +	union acpi_object *obj = NULL; +	uint8_t name[5] = {'\0'}; +	struct cgs_acpi_method_argument *argument = NULL; +	uint32_t i, count; +	acpi_status status; +	int result; +	uint32_t func_no = 0xFFFFFFFF; + +	handle = ACPI_HANDLE(&adev->pdev->dev); +	if (!handle) +		return -ENODEV; + +	memset(&input, 0, sizeof(struct acpi_object_list)); + +	/* validate input info */ +	if (info->size != sizeof(struct cgs_acpi_method_info)) +		return -EINVAL; + +	input.count = info->input_count; +	if (info->input_count > 0) { +		if (info->pinput_argument == NULL) +			return -EINVAL; +		argument = info->pinput_argument; +		func_no = argument->value; +		for (i = 0; i < info->input_count; i++) { +			if (((argument->type == ACPI_TYPE_STRING) || +			     (argument->type == ACPI_TYPE_BUFFER)) && +			    (argument->pointer == NULL)) +				return -EINVAL; +			argument++; +		} +	} + +	if (info->output_count > 0) { +		if (info->poutput_argument == NULL) +			return -EINVAL; +		argument = info->poutput_argument; +		for (i = 0; i < info->output_count; i++) { +			if (((argument->type == ACPI_TYPE_STRING) || +				(argument->type == ACPI_TYPE_BUFFER)) +				&& (argument->pointer == NULL)) +				return -EINVAL; +			argument++; +		} +	} + +	/* The path name passed to acpi_evaluate_object should be null terminated */ +	if ((info->field & CGS_ACPI_FIELD_METHOD_NAME) != 0) { +		strncpy(name, (char *)&(info->name), sizeof(uint32_t)); +		name[4] = '\0'; +	} + +	/* parse input parameters */ +	if (input.count > 0) { +		input.pointer = params = +				kzalloc(sizeof(union acpi_object) * input.count, GFP_KERNEL); +		if (params == NULL) +			return -EINVAL; + +		argument = info->pinput_argument; + +		for (i = 0; i < input.count; i++) { +			params->type = argument->type; +			switch (params->type) { +			case ACPI_TYPE_INTEGER: +				params->integer.value = argument->value; +				break; +			case ACPI_TYPE_STRING: +				params->string.length = argument->method_length; +				params->string.pointer = argument->pointer; +				break; +			case ACPI_TYPE_BUFFER: +				params->buffer.length = argument->method_length; +				params->buffer.pointer = argument->pointer; +				break; +			default: +				break; +			} +			params++; +			argument++; +		} +	} + +	/* parse output info */ +	count = info->output_count; +	argument = info->poutput_argument; + +	/* evaluate the acpi method */ +	status = acpi_evaluate_object(handle, name, &input, &output); + +	if (ACPI_FAILURE(status)) { +		result = -EIO; +		goto error; +	} + +	/* return the output info */ +	obj = output.pointer; + +	if (count > 1) { +		if ((obj->type != ACPI_TYPE_PACKAGE) || +			(obj->package.count != count)) { +			result = -EIO; +			goto error; +		} +		params = obj->package.elements; +	} else +		params = obj; + +	if (params == NULL) { +		result = -EIO; +		goto error; +	} + +	for (i = 0; i < count; i++) { +		if (argument->type != params->type) { +			result = -EIO; +			goto error; +		} +		switch (params->type) { +		case ACPI_TYPE_INTEGER: +			argument->value = params->integer.value; +			break; +		case ACPI_TYPE_STRING: +			if ((params->string.length != argument->data_length) || +				(params->string.pointer == NULL)) { +				result = -EIO; +				goto error; +			} +			strncpy(argument->pointer, +				params->string.pointer, +				params->string.length); +			break; +		case ACPI_TYPE_BUFFER: +			if (params->buffer.pointer == NULL) { +				result = -EIO; +				goto error; +			} +			memcpy(argument->pointer, +				params->buffer.pointer, +				argument->data_length); +			break; +		default: +			break; +		} +		argument++; +		params++; +	} + +error: +	if (obj != NULL) +		kfree(obj); +	kfree((void *)input.pointer); +	return result; +} +#else +static int amdgpu_cgs_acpi_eval_object(void *cgs_device, +				struct cgs_acpi_method_info *info) +{ +	return -EIO; +} +#endif + +int amdgpu_cgs_call_acpi_method(void *cgs_device, +					uint32_t acpi_method, +					uint32_t acpi_function, +					void *pinput, void *poutput, +					uint32_t output_count, +					uint32_t input_size, +					uint32_t output_size) +{ +	struct cgs_acpi_method_argument acpi_input[2] = { {0}, {0} }; +	struct cgs_acpi_method_argument acpi_output = {0}; +	struct cgs_acpi_method_info info = {0}; + +	acpi_input[0].type = CGS_ACPI_TYPE_INTEGER; +	acpi_input[0].method_length = sizeof(uint32_t); +	acpi_input[0].data_length = sizeof(uint32_t); +	acpi_input[0].value = acpi_function; + +	acpi_input[1].type = CGS_ACPI_TYPE_BUFFER; +	acpi_input[1].method_length = CGS_ACPI_MAX_BUFFER_SIZE; +	acpi_input[1].data_length = input_size; +	acpi_input[1].pointer = pinput; + +	acpi_output.type = CGS_ACPI_TYPE_BUFFER; +	acpi_output.method_length = CGS_ACPI_MAX_BUFFER_SIZE; +	acpi_output.data_length = output_size; +	acpi_output.pointer = poutput; + +	info.size = sizeof(struct cgs_acpi_method_info); +	info.field = CGS_ACPI_FIELD_METHOD_NAME | CGS_ACPI_FIELD_INPUT_ARGUMENT_COUNT; +	info.input_count = 2; +	info.name = acpi_method; +	info.pinput_argument = acpi_input; +	info.output_count = output_count; +	info.poutput_argument = &acpi_output; + +	return amdgpu_cgs_acpi_eval_object(cgs_device, &info); +} +  static const struct cgs_ops amdgpu_cgs_ops = {  	amdgpu_cgs_gpu_mem_info,  	amdgpu_cgs_gmap_kmem, @@ -756,6 +1076,7 @@ static const struct cgs_ops amdgpu_cgs_ops = {  	amdgpu_cgs_write_pci_config_byte,  	amdgpu_cgs_write_pci_config_word,  	amdgpu_cgs_write_pci_config_dword, +	amdgpu_cgs_get_pci_resource,  	amdgpu_cgs_atom_get_data_table,  	amdgpu_cgs_atom_get_cmd_table_revs,  	amdgpu_cgs_atom_exec_cmd_table, @@ -768,7 +1089,10 @@ static const struct cgs_ops amdgpu_cgs_ops = {  	amdgpu_cgs_set_camera_voltages,  	amdgpu_cgs_get_firmware_info,  	amdgpu_cgs_set_powergating_state, -	amdgpu_cgs_set_clockgating_state +	amdgpu_cgs_set_clockgating_state, +	amdgpu_cgs_get_active_displays_info, +	amdgpu_cgs_call_acpi_method, +	amdgpu_cgs_query_system_info,  };  static const struct cgs_os_ops amdgpu_cgs_os_ops = {  | 
