diff options
author | Alex Deucher <alexander.deucher@amd.com> | 2015-04-20 16:55:21 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2015-06-03 21:03:15 -0400 |
commit | d38ceaf99ed015f2a0b9af3499791bd3a3daae21 (patch) | |
tree | c8e237ea218e8ed8a5f64c1654fc01fe5d2239cb /drivers | |
parent | 97b2e202fba05b87d720318a6500a337100dab4d (diff) |
drm/amdgpu: add core driver (v4)
This adds the non-asic specific core driver code.
v2: remove extra kconfig option
v3: implement minor fixes from Fengguang Wu
v4: fix cast in amdgpu_ucode.c
Acked-by: Christian König <christian.koenig@amd.com>
Acked-by: Jammy Zhou <Jammy.Zhou@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers')
78 files changed, 33596 insertions, 0 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index d4b65457122d..c46ca311d8c3 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -120,6 +120,27 @@ config DRM_RADEON source "drivers/gpu/drm/radeon/Kconfig" +config DRM_AMDGPU + tristate "AMD GPU" + depends on DRM && PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FW_LOADER + select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER + select DRM_TTM + select POWER_SUPPLY + select HWMON + select BACKLIGHT_CLASS_DEVICE + select INTERVAL_TREE + help + Choose this option if you have a recent AMD Radeon graphics card. + + If M is selected, the module will be called amdgpu. + +source "drivers/gpu/drm/amd/amdgpu/Kconfig" + source "drivers/gpu/drm/nouveau/Kconfig" config DRM_I810 diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 15eb710ec114..5713d0534504 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_DRM_TDFX) += tdfx/ obj-$(CONFIG_DRM_R128) += r128/ obj-$(CONFIG_HSA_AMD) += amd/amdkfd/ obj-$(CONFIG_DRM_RADEON)+= radeon/ +obj-$(CONFIG_DRM_AMDGPU)+= amd/amdgpu/ obj-$(CONFIG_DRM_MGA) += mga/ obj-$(CONFIG_DRM_I810) += i810/ obj-$(CONFIG_DRM_I915) += i915/ diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig b/drivers/gpu/drm/amd/amdgpu/Kconfig new file mode 100644 index 000000000000..b30fcfa4b1f2 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/Kconfig @@ -0,0 +1,17 @@ +config DRM_AMDGPU_CIK + bool "Enable amdgpu support for CIK parts" + depends on DRM_AMDGPU + help + Choose this option if you want to enable experimental support + for CIK asics. + + CIK is already supported in radeon. CIK support in amdgpu + is for experimentation and testing. + +config DRM_AMDGPU_USERPTR + bool "Always enable userptr write support" + depends on DRM_AMDGPU + select MMU_NOTIFIER + help + This option selects CONFIG_MMU_NOTIFIER if it isn't already + selected to enabled full userptr support. diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile new file mode 100644 index 000000000000..01276a592bc5 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -0,0 +1,49 @@ +# +# Makefile for the drm device driver. This driver provides support for the +# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. + +ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/amd/include/asic_reg + +amdgpu-y := amdgpu_drv.o + +# add KMS driver +amdgpu-y += amdgpu_device.o amdgpu_kms.o \ + amdgpu_atombios.o atombios_crtc.o amdgpu_connectors.o \ + atom.o amdgpu_fence.o amdgpu_ttm.o amdgpu_object.o amdgpu_gart.o \ + amdgpu_encoders.o amdgpu_display.o amdgpu_i2c.o \ + amdgpu_fb.o amdgpu_gem.o amdgpu_ring.o \ + amdgpu_cs.o amdgpu_bios.o amdgpu_benchmark.o amdgpu_test.o \ + amdgpu_pm.o atombios_dp.o amdgpu_afmt.o amdgpu_trace_points.o \ + atombios_encoders.o amdgpu_semaphore.o amdgpu_sa.o atombios_i2c.o \ + amdgpu_prime.o amdgpu_vm.o amdgpu_ib.o amdgpu_pll.o \ + amdgpu_ucode.o amdgpu_bo_list.o amdgpu_ctx.o amdgpu_sync.o + +# add IH block +amdgpu-y += \ + amdgpu_irq.o \ + amdgpu_ih.o + +# add SMC block +amdgpu-y += \ + amdgpu_dpm.o + +# add GFX block +amdgpu-y += \ + amdgpu_gfx.o + +# add UVD block +amdgpu-y += \ + amdgpu_uvd.o + +# add VCE block +amdgpu-y += \ + amdgpu_vce.o + +amdgpu-$(CONFIG_COMPAT) += amdgpu_ioc32.o +amdgpu-$(CONFIG_VGA_SWITCHEROO) += amdgpu_atpx_handler.o +amdgpu-$(CONFIG_ACPI) += amdgpu_acpi.o +amdgpu-$(CONFIG_MMU_NOTIFIER) += amdgpu_mn.o + +obj-$(CONFIG_DRM_AMDGPU)+= amdgpu.o + +CFLAGS_amdgpu_trace_points.o := -I$(src) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c new file mode 100644 index 000000000000..aef4a7aac0f7 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -0,0 +1,768 @@ +/* + * Copyright 2012 Advanced Micro Devices, 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. + * + */ + +#include <linux/pci.h> +#include <linux/acpi.h> +#include <linux/slab.h> +#include <linux/power_supply.h> +#include <linux/vga_switcheroo.h> +#include <acpi/video.h> +#include <drm/drmP.h> +#include <drm/drm_crtc_helper.h> +#include "amdgpu.h" +#include "amdgpu_acpi.h" +#include "atom.h" + +#define ACPI_AC_CLASS "ac_adapter" + +extern void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev); + +struct atif_verify_interface { + u16 size; /* structure size in bytes (includes size field) */ + u16 version; /* version */ + u32 notification_mask; /* supported notifications mask */ + u32 function_bits; /* supported functions bit vector */ +} __packed; + +struct atif_system_params { + u16 size; /* structure size in bytes (includes size field) */ + u32 valid_mask; /* valid flags mask */ + u32 flags; /* flags */ + u8 command_code; /* notify command code */ +} __packed; + +struct atif_sbios_requests { + u16 size; /* structure size in bytes (includes size field) */ + u32 pending; /* pending sbios requests */ + u8 panel_exp_mode; /* panel expansion mode */ + u8 thermal_gfx; /* thermal state: target gfx controller */ + u8 thermal_state; /* thermal state: state id (0: exit state, non-0: state) */ + u8 forced_power_gfx; /* forced power state: target gfx controller */ + u8 forced_power_state; /* forced power state: state id */ + u8 system_power_src; /* system power source */ + u8 backlight_level; /* panel backlight level (0-255) */ +} __packed; + +#define ATIF_NOTIFY_MASK 0x3 +#define ATIF_NOTIFY_NONE 0 +#define ATIF_NOTIFY_81 1 +#define ATIF_NOTIFY_N 2 + +struct atcs_verify_interface { + u16 size; /* structure size in bytes (includes size field) */ + u16 version; /* version */ + u32 function_bits; /* supported functions bit vector */ +} __packed; + +#define ATCS_VALID_FLAGS_MASK 0x3 + +struct atcs_pref_req_input { + u16 size; /* structure size in bytes (includes size field) */ + u16 client_id; /* client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) */ + u16 valid_flags_mask; /* valid flags mask */ + u16 flags; /* flags */ + u8 req_type; /* request type */ + u8 perf_req; /* performance request */ +} __packed; + +struct atcs_pref_req_output { + u16 size; /* structure size in bytes (includes size field) */ + u8 ret_val; /* return value */ +} __packed; + +/* Call the ATIF method + */ +/** + * amdgpu_atif_call - call an ATIF method + * + * @handle: acpi handle + * @function: the ATIF function to execute + * @params: ATIF function params + * + * Executes the requested ATIF function (all asics). + * Returns a pointer to the acpi output buffer. + */ +static union acpi_object *amdgpu_atif_call(acpi_handle handle, int function, + struct acpi_buffer *params) +{ + acpi_status status; + union acpi_object atif_arg_elements[2]; + struct acpi_object_list atif_arg; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + + atif_arg.count = 2; + atif_arg.pointer = &atif_arg_elements[0]; + + atif_arg_elements[0].type = ACPI_TYPE_INTEGER; + atif_arg_elements[0].integer.value = function; + + if (params) { + atif_arg_elements[1].type = ACPI_TYPE_BUFFER; + atif_arg_elements[1].buffer.length = params->length; + atif_arg_elements[1].buffer.pointer = params->pointer; + } else { + /* We need a second fake parameter */ + atif_arg_elements[1].type = ACPI_TYPE_INTEGER; + atif_arg_elements[1].integer.value = 0; + } + + status = acpi_evaluate_object(handle, "ATIF", &atif_arg, &buffer); + + /* Fail only if calling the method fails and ATIF is supported */ + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { + DRM_DEBUG_DRIVER("failed to evaluate ATIF got %s\n", + acpi_format_exception(status)); + kfree(buffer.pointer); + return NULL; + } + + return buffer.pointer; +} + +/** + * amdgpu_atif_parse_notification - parse supported notifications + * + * @n: supported notifications struct + * @mask: supported notifications mask from ATIF + * + * Use the supported notifications mask from ATIF function + * ATIF_FUNCTION_VERIFY_INTERFACE to determine what notifications + * are supported (all asics). + */ +static void amdgpu_atif_parse_notification(struct amdgpu_atif_notifications *n, u32 mask) +{ + n->display_switch = mask & ATIF_DISPLAY_SWITCH_REQUEST_SUPPORTED; + n->expansion_mode_change = mask & ATIF_EXPANSION_MODE_CHANGE_REQUEST_SUPPORTED; + n->thermal_state = mask & ATIF_THERMAL_STATE_CHANGE_REQUEST_SUPPORTED; + n->forced_power_state = mask & ATIF_FORCED_POWER_STATE_CHANGE_REQUEST_SUPPORTED; + n->system_power_state = mask & ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST_SUPPORTED; + n->display_conf_change = mask & ATIF_DISPLAY_CONF_CHANGE_REQUEST_SUPPORTED; + n->px_gfx_switch = mask & ATIF_PX_GFX_SWITCH_REQUEST_SUPPORTED; + n->brightness_change = mask & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST_SUPPORTED; + n->dgpu_display_event = mask & ATIF_DGPU_DISPLAY_EVENT_SUPPORTED; +} + +/** + * amdgpu_atif_parse_functions - parse supported functions + * + * @f: supported functions struct + * @mask: supported functions mask from ATIF + * + * Use the supported functions mask from ATIF function + * ATIF_FUNCTION_VERIFY_INTERFACE to determine what functions + * are supported (all asics). + */ +static void amdgpu_atif_parse_functions(struct amdgpu_atif_functions *f, u32 mask) +{ + f->system_params = mask & ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED; + f->sbios_requests = mask & ATIF_GET_SYSTEM_BIOS_REQUESTS_SUPPORTED; + f->select_active_disp = mask & ATIF_SELECT_ACTIVE_DISPLAYS_SUPPORTED; + f->lid_state = mask & ATIF_GET_LID_STATE_SUPPORTED; + f->get_tv_standard = mask & ATIF_GET_TV_STANDARD_FROM_CMOS_SUPPORTED; + f->set_tv_standard = mask & ATIF_SET_TV_STANDARD_IN_CMOS_SUPPORTED; + f->get_panel_expansion_mode = mask & ATIF_GET_PANEL_EXPANSION_MODE_FROM_CMOS_SUPPORTED; + f->set_panel_expansion_mode = mask & ATIF_SET_PANEL_EXPANSION_MODE_IN_CMOS_SUPPORTED; + f->temperature_change = mask & ATIF_TEMPERATURE_CHANGE_NOTIFICATION_SUPPORTED; + f->graphics_device_types = mask & ATIF_GET_GRAPHICS_DEVICE_TYPES_SUPPORTED; +} + +/** + * amdgpu_atif_verify_interface - verify ATIF + * + * @handle: acpi handle + * @atif: amdgpu atif struct + * + * Execute the ATIF_FUNCTION_VERIFY_INTERFACE ATIF function + * to initialize ATIF and determine what features are supported + * (all asics). + * returns 0 on success, error on failure. + */ +static int amdgpu_atif_verify_interface(acpi_handle handle, + struct amdgpu_atif *atif) +{ + union acpi_object *info; + struct atif_verify_interface output; + size_t size; + int err = 0; + + info = amdgpu_atif_call(handle, ATIF_FUNCTION_VERIFY_INTERFACE, NULL); + if (!info) + return -EIO; + + memset(&output, 0, sizeof(output)); + + size = *(u16 *) info->buffer.pointer; + if (size < 12) { + DRM_INFO("ATIF buffer is too small: %zu\n", size); + err = -EINVAL; + goto out; + } + size = min(sizeof(output), size); + + memcpy(&output, info->buffer.pointer, size); + + /* TODO: check version? */ + DRM_DEBUG_DRIVER("ATIF version %u\n", output.version); + + amdgpu_atif_parse_notification(&atif->notifications, output.notification_mask); + amdgpu_atif_parse_functions(&atif->functions, output.function_bits); + +out: + kfree(info); + return err; +} + +/** + * amdgpu_atif_get_notification_params - determine notify configuration + * + * @handle: acpi handle + * @n: atif notification configuration struct + * + * Execute the ATIF_FUNCTION_GET_SYSTEM_PARAMETERS ATIF function + * to determine if a notifier is used and if so which one + * (all asics). This is either Notify(VGA, 0x81) or Notify(VGA, n) + * where n is specified in the result if a notifier is used. + * Returns 0 on success, error on failure. + */ +static int amdgpu_atif_get_notification_params(acpi_handle handle, + struct amdgpu_atif_notification_cfg *n) +{ + union acpi_object *info; + struct atif_system_params params; + size_t size; + int err = 0; + + info = amdgpu_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_PARAMETERS, NULL); + if (!info) { + err = -EIO; + goto out; + } + + size = *(u16 *) info->buffer.pointer; + if (size < 10) { + err = -EINVAL; + goto out; + } + + memset(¶ms, 0, sizeof(params)); + size = min(sizeof(params), size); + memcpy(¶ms, info->buffer.pointer, size); + + DRM_DEBUG_DRIVER("SYSTEM_PARAMS: mask = %#x, flags = %#x\n", + params.flags, params.valid_mask); + params.flags = params.flags & params.valid_mask; + + if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_NONE) { + n->enabled = false; + n->command_code = 0; + } else if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_81) { + n->enabled = true; + n->command_code = 0x81; + } else { + if (size < 11) { + err = -EINVAL; + goto out; + } + n->enabled = true; + n->command_code = params.command_code; + } + +out: + DRM_DEBUG_DRIVER("Notification %s, command code = %#x\n", + (n->enabled ? "enabled" : "disabled"), + n->command_code); + kfree(info); + return err; +} + +/** + * amdgpu_atif_get_sbios_requests - get requested sbios event + * + * @handle: acpi handle + * @req: atif sbios request struct + * + * Execute the ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS ATIF function + * to determine what requests the sbios is making to the driver + * (all asics). + * Returns 0 on success, error on failure. + */ +static int amdgpu_atif_get_sbios_requests(acpi_handle handle, + struct atif_sbios_requests *req) +{ + union acpi_object *info; + size_t size; + int count = 0; + + info = amdgpu_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS, NULL); + if (!info) + return -EIO; + + size = *(u16 *)info->buffer.pointer; + if (size < 0xd) { + count = -EINVAL; + goto out; + } + memset(req, 0, sizeof(*req)); + + size = min(sizeof(*req), size); + memcpy(req, info->buffer.pointer, size); + DRM_DEBUG_DRIVER("SBIOS pending requests: %#x\n", req->pending); + + count = hweight32(req->pending); + +out: + kfree(info); + return count; +} + +/** + * amdgpu_atif_handler - handle ATIF notify requests + * + * @adev: amdgpu_device pointer + * @event: atif sbios request struct + * + * Checks the acpi event and if it matches an atif event, + * handles it. + * Returns NOTIFY code + */ +int amdgpu_atif_handler(struct amdgpu_device *adev, + struct acpi_bus_event *event) +{ + struct amdgpu_atif *atif = &adev->atif; + struct atif_sbios_requests req; + acpi_handle handle; + int count; + + DRM_DEBUG_DRIVER("event, device_class = %s, type = %#x\n", + event->device_class, event->type); + + if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0) + return NOTIFY_DONE; + + if (!atif->notification_cfg.enabled || + event->type != atif->notification_cfg.command_code) + /* Not our event */ + return NOTIFY_DONE; + + /* Check pending SBIOS requests */ + handle = ACPI_HANDLE(&adev->pdev->dev); + count = amdgpu_atif_get_sbios_requests(handle, &req); + + if (count <= 0) + return NOTIFY_DONE; + + DRM_DEBUG_DRIVER("ATIF: %d pending SBIOS requests\n", count); + + if (req.pending & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST) { |