From bf3911b06fa9c551b852af563fed393a02e48a7a Mon Sep 17 00:00:00 2001 From: Jammy Zhou Date: Wed, 13 May 2015 18:58:05 +0800 Subject: [PATCH] drm/amdgpu: add cgs_get_firmware_info interface v2 This new interface can be used by IP components to retrieve the firmware information from the core driver. v2: fix one typo Signed-off-by: Jammy Zhou Signed-off-by: Rex Zhu Signed-off-by: Young Yang Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c | 122 ++++++++++++++++++++++- drivers/gpu/drm/amd/include/cgs_common.h | 46 +++++++++ 2 files changed, 167 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c index ac0f124cf6d0..520d01715737 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c @@ -25,10 +25,13 @@ #include #include #include +#include #include #include "amdgpu.h" #include "cgs_linux.h" #include "atom.h" +#include "amdgpu_ucode.h" + struct amdgpu_cgs_device { struct cgs_device base; @@ -611,6 +614,122 @@ static int amdgpu_cgs_irq_put(void *cgs_device, unsigned src_id, unsigned type) return amdgpu_irq_put(adev, adev->irq.sources[src_id], type); } +static uint32_t fw_type_convert(void *cgs_device, uint32_t fw_type) +{ + CGS_FUNC_ADEV; + enum AMDGPU_UCODE_ID result = AMDGPU_UCODE_ID_MAXIMUM; + + switch (fw_type) { + case CGS_UCODE_ID_SDMA0: + result = AMDGPU_UCODE_ID_SDMA0; + break; + case CGS_UCODE_ID_SDMA1: + result = AMDGPU_UCODE_ID_SDMA1; + break; + case CGS_UCODE_ID_CP_CE: + result = AMDGPU_UCODE_ID_CP_CE; + break; + case CGS_UCODE_ID_CP_PFP: + result = AMDGPU_UCODE_ID_CP_PFP; + break; + case CGS_UCODE_ID_CP_ME: + result = AMDGPU_UCODE_ID_CP_ME; + break; + case CGS_UCODE_ID_CP_MEC: + case CGS_UCODE_ID_CP_MEC_JT1: + result = AMDGPU_UCODE_ID_CP_MEC1; + break; + case CGS_UCODE_ID_CP_MEC_JT2: + if (adev->asic_type == CHIP_TONGA) + result = AMDGPU_UCODE_ID_CP_MEC2; + else if (adev->asic_type == CHIP_CARRIZO) + result = AMDGPU_UCODE_ID_CP_MEC1; + break; + case CGS_UCODE_ID_RLC_G: + result = AMDGPU_UCODE_ID_RLC_G; + break; + default: + DRM_ERROR("Firmware type not supported\n"); + } + return result; +} + +static int amdgpu_cgs_get_firmware_info(void *cgs_device, + enum cgs_ucode_id type, + struct cgs_firmware_info *info) +{ + CGS_FUNC_ADEV; + + if (CGS_UCODE_ID_SMU != type) { + uint64_t gpu_addr; + uint32_t data_size; + const struct gfx_firmware_header_v1_0 *header; + enum AMDGPU_UCODE_ID id; + struct amdgpu_firmware_info *ucode; + + id = fw_type_convert(cgs_device, type); + ucode = &adev->firmware.ucode[id]; + if (ucode->fw == NULL) + return -EINVAL; + + gpu_addr = ucode->mc_addr; + header = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data; + data_size = le32_to_cpu(header->header.ucode_size_bytes); + + if ((type == CGS_UCODE_ID_CP_MEC_JT1) || + (type == CGS_UCODE_ID_CP_MEC_JT2)) { + gpu_addr += le32_to_cpu(header->jt_offset) << 2; + data_size = le32_to_cpu(header->jt_size) << 2; + } + info->mc_addr = gpu_addr; + info->image_size = data_size; + info->version = (uint16_t)le32_to_cpu(header->header.ucode_version); + info->feature_version = (uint16_t)le32_to_cpu(header->ucode_feature_version); + } else { + char fw_name[30] = {0}; + int err = 0; + uint32_t ucode_size; + uint32_t ucode_start_address; + const uint8_t *src; + const struct smc_firmware_header_v1_0 *hdr; + + switch (adev->asic_type) { + case CHIP_TONGA: + strcpy(fw_name, "amdgpu/tonga_smc.bin"); + break; + default: + DRM_ERROR("SMC firmware not supported\n"); + return -EINVAL; + } + + err = request_firmware(&adev->pm.fw, fw_name, adev->dev); + if (err) { + DRM_ERROR("Failed to request firmware\n"); + return err; + } + + err = amdgpu_ucode_validate(adev->pm.fw); + if (err) { + DRM_ERROR("Failed to load firmware \"%s\"", fw_name); + release_firmware(adev->pm.fw); + adev->pm.fw = NULL; + return err; + } + + hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data; + adev->pm.fw_version = le32_to_cpu(hdr->header.ucode_version); + ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes); + ucode_start_address = le32_to_cpu(hdr->ucode_start_addr); + src = (const uint8_t *)(adev->pm.fw->data + + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); + + info->version = adev->pm.fw_version; + info->image_size = ucode_size; + info->kptr = (void *)src; + } + return 0; +} + static const struct cgs_ops amdgpu_cgs_ops = { amdgpu_cgs_gpu_mem_info, amdgpu_cgs_gmap_kmem, @@ -640,7 +759,8 @@ static const struct cgs_ops amdgpu_cgs_ops = { amdgpu_cgs_pm_request_clock, amdgpu_cgs_pm_request_engine, amdgpu_cgs_pm_query_clock_limits, - amdgpu_cgs_set_camera_voltages + amdgpu_cgs_set_camera_voltages, + amdgpu_cgs_get_firmware_info }; static const struct cgs_os_ops amdgpu_cgs_os_ops = { diff --git a/drivers/gpu/drm/amd/include/cgs_common.h b/drivers/gpu/drm/amd/include/cgs_common.h index f8cdb8875d89..d586c24a3d31 100644 --- a/drivers/gpu/drm/amd/include/cgs_common.h +++ b/drivers/gpu/drm/amd/include/cgs_common.h @@ -24,6 +24,7 @@ #ifndef _CGS_COMMON_H #define _CGS_COMMON_H + /** * enum cgs_gpu_mem_type - GPU memory types */ @@ -85,6 +86,24 @@ enum cgs_voltage_planes { /* ... */ }; +/* + * enum cgs_ucode_id - Firmware types for different IPs + */ +enum cgs_ucode_id { + CGS_UCODE_ID_SMU = 0, + CGS_UCODE_ID_SDMA0, + CGS_UCODE_ID_SDMA1, + CGS_UCODE_ID_CP_CE, + CGS_UCODE_ID_CP_PFP, + CGS_UCODE_ID_CP_ME, + CGS_UCODE_ID_CP_MEC, + CGS_UCODE_ID_CP_MEC_JT1, + CGS_UCODE_ID_CP_MEC_JT2, + CGS_UCODE_ID_GMCON_RENG, + CGS_UCODE_ID_RLC_G, + CGS_UCODE_ID_MAXIMUM, +}; + /** * struct cgs_clock_limits - Clock limits * @@ -96,6 +115,17 @@ struct cgs_clock_limits { unsigned sustainable; /**< Thermally sustainable frequency */ }; +/** + * struct cgs_firmware_info - Firmware information + */ +struct cgs_firmware_info { + uint16_t version; + uint16_t feature_version; + uint32_t image_size; + uint64_t mc_addr; + void *kptr; +}; + typedef unsigned long cgs_handle_t; /** @@ -442,6 +472,18 @@ typedef int (*cgs_pm_query_clock_limits_t)(void *cgs_device, */ typedef int (*cgs_set_camera_voltages_t)(void *cgs_device, uint32_t mask, const uint32_t *voltages); +/** + * cgs_get_firmware_info - Get the firmware information from core driver + * @cgs_device: opaque device handle + * @type: the firmware type + * @info: returend firmware information + * + * Return: 0 on success, -errno otherwise + */ +typedef int (*cgs_get_firmware_info)(void *cgs_device, + enum cgs_ucode_id type, + struct cgs_firmware_info *info); + struct cgs_ops { /* memory management calls (similar to KFD interface) */ @@ -478,6 +520,8 @@ struct cgs_ops { cgs_pm_request_engine_t pm_request_engine; cgs_pm_query_clock_limits_t pm_query_clock_limits; cgs_set_camera_voltages_t set_camera_voltages; + /* Firmware Info */ + cgs_get_firmware_info get_firmware_info; /* ACPI (TODO) */ }; @@ -559,5 +603,7 @@ struct cgs_device CGS_CALL(pm_query_clock_limits,dev,clock,limits) #define cgs_set_camera_voltages(dev,mask,voltages) \ CGS_CALL(set_camera_voltages,dev,mask,voltages) +#define cgs_get_firmware_info(dev, type, info) \ + CGS_CALL(get_firmware_info, dev, type, info) #endif /* _CGS_COMMON_H */