diff options
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/4329-drm-amd-display-Hook-up-the-DMUB-service-in-DM.patch')
-rw-r--r-- | meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/4329-drm-amd-display-Hook-up-the-DMUB-service-in-DM.patch | 436 |
1 files changed, 436 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/4329-drm-amd-display-Hook-up-the-DMUB-service-in-DM.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/4329-drm-amd-display-Hook-up-the-DMUB-service-in-DM.patch new file mode 100644 index 00000000..1fd4fee1 --- /dev/null +++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/4329-drm-amd-display-Hook-up-the-DMUB-service-in-DM.patch @@ -0,0 +1,436 @@ +From 99fcf29399a7463d48952b81e2616f6ca5bed1ef Mon Sep 17 00:00:00 2001 +From: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com> +Date: Thu, 24 Oct 2019 20:38:48 -0400 +Subject: [PATCH 4329/4736] drm/amd/display: Hook up the DMUB service in DM + +[Why] +We need DMCUB on Renoir to support DMCU and PHY initialization. +The DMUB service provides a mechanism to load the DMCUB. + +[How] +Include the DMUB service in amdgpu_dm. + +Frontdoor loading of the DMCUB firmware needs to happen via PSP. To +pass the firmware to PSP we need to hand it off to the firmware list +in the base driver during software initialization. + +Most of the DMUB service can technically be initialized at this point +in time, but we don't want to be allocating framebuffer memory for +hardware that doesn't support the DMCUB and in order to check that we +need to be able to read registers - something DM helpers aren't setup +to do in software initialization. + +So everything but the service creation itself will get deferred to +hardware initialization. + +Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com> +Reviewed-by: Hersen Wu <hersenxs.wu@amd.com> +Acked-by: Harry Wentland <harry.wentland@amd.com> +Signed-off-by: Rahul Kumar <rahul.kumar1@amd.com> +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 270 ++++++++++++++++++ + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 50 ++++ + 2 files changed, 320 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index 5a20ce0541c6..e226e526c4df 100755 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -30,6 +30,11 @@ + #include "dc.h" + #include "dc/inc/core_types.h" + #include "dal_asic_id.h" ++#ifdef CONFIG_DRM_AMD_DC_DMUB ++#include "dmub/inc/dmub_srv.h" ++#include "dc/inc/hw/dmcu.h" ++#include "dc/inc/hw/abm.h" ++#endif + + #include "vid.h" + #include "amdgpu.h" +@@ -84,6 +89,10 @@ + #include "modules/power/power_helpers.h" + #include "modules/inc/mod_info_packet.h" + ++#ifdef CONFIG_DRM_AMD_DC_DMUB ++#define FIRMWARE_RENOIR_DMUB "amdgpu/renoir_dmcub.bin" ++MODULE_FIRMWARE(FIRMWARE_RENOIR_DMUB); ++#endif + #define FIRMWARE_RAVEN_DMCU "amdgpu/raven_dmcu.bin" + MODULE_FIRMWARE(FIRMWARE_RAVEN_DMCU); + +@@ -665,11 +674,151 @@ void amdgpu_dm_audio_eld_notify(struct amdgpu_device *adev, int pin) + } + } + ++#ifdef CONFIG_DRM_AMD_DC_DMUB ++static int dm_dmub_hw_init(struct amdgpu_device *adev) ++{ ++ const unsigned int psp_header_bytes = 0x100; ++ const unsigned int psp_footer_bytes = 0x100; ++ const struct dmcub_firmware_header_v1_0 *hdr; ++ struct dmub_srv *dmub_srv = adev->dm.dmub_srv; ++ const struct firmware *dmub_fw = adev->dm.dmub_fw; ++ struct dmcu *dmcu = adev->dm.dc->res_pool->dmcu; ++ struct abm *abm = adev->dm.dc->res_pool->abm; ++ struct dmub_srv_region_params region_params; ++ struct dmub_srv_region_info region_info; ++ struct dmub_srv_fb_params fb_params; ++ struct dmub_srv_fb_info fb_info; ++ struct dmub_srv_hw_params hw_params; ++ enum dmub_status status; ++ const unsigned char *fw_inst_const, *fw_bss_data; ++ uint32_t i; ++ int r; ++ bool has_hw_support; ++ ++ if (!dmub_srv) ++ /* DMUB isn't supported on the ASIC. */ ++ return 0; ++ ++ if (!dmub_fw) { ++ /* Firmware required for DMUB support. */ ++ DRM_ERROR("No firmware provided for DMUB.\n"); ++ return -EINVAL; ++ } ++ ++ status = dmub_srv_has_hw_support(dmub_srv, &has_hw_support); ++ if (status != DMUB_STATUS_OK) { ++ DRM_ERROR("Error checking HW support for DMUB: %d\n", status); ++ return -EINVAL; ++ } ++ ++ if (!has_hw_support) { ++ DRM_INFO("DMUB unsupported on ASIC\n"); ++ return 0; ++ } ++ ++ hdr = (const struct dmcub_firmware_header_v1_0 *)dmub_fw->data; ++ ++ /* Calculate the size of all the regions for the DMUB service. */ ++ memset(®ion_params, 0, sizeof(region_params)); ++ ++ region_params.inst_const_size = le32_to_cpu(hdr->inst_const_bytes) - ++ psp_header_bytes - psp_footer_bytes; ++ region_params.bss_data_size = le32_to_cpu(hdr->bss_data_bytes); ++ region_params.vbios_size = adev->dm.dc->ctx->dc_bios->bios_size; ++ ++ status = dmub_srv_calc_region_info(dmub_srv, ®ion_params, ++ ®ion_info); ++ ++ if (status != DMUB_STATUS_OK) { ++ DRM_ERROR("Error calculating DMUB region info: %d\n", status); ++ return -EINVAL; ++ } ++ ++ /* ++ * Allocate a framebuffer based on the total size of all the regions. ++ * TODO: Move this into GART. ++ */ ++ r = amdgpu_bo_create_kernel(adev, region_info.fb_size, PAGE_SIZE, ++ AMDGPU_GEM_DOMAIN_VRAM, &adev->dm.dmub_bo, ++ &adev->dm.dmub_bo_gpu_addr, ++ &adev->dm.dmub_bo_cpu_addr); ++ if (r) ++ return r; ++ ++ /* Rebase the regions on the framebuffer address. */ ++ memset(&fb_params, 0, sizeof(fb_params)); ++ fb_params.cpu_addr = adev->dm.dmub_bo_cpu_addr; ++ fb_params.gpu_addr = adev->dm.dmub_bo_gpu_addr; ++ fb_params.region_info = ®ion_info; ++ ++ status = dmub_srv_calc_fb_info(dmub_srv, &fb_params, &fb_info); ++ if (status != DMUB_STATUS_OK) { ++ DRM_ERROR("Error calculating DMUB FB info: %d\n", status); ++ return -EINVAL; ++ } ++ ++ fw_inst_const = dmub_fw->data + ++ le32_to_cpu(hdr->header.ucode_array_offset_bytes) + ++ psp_header_bytes; ++ ++ fw_bss_data = dmub_fw->data + ++ le32_to_cpu(hdr->header.ucode_array_offset_bytes) + ++ le32_to_cpu(hdr->inst_const_bytes); ++ ++ /* Copy firmware and bios info into FB memory. */ ++ memcpy(fb_info.fb[DMUB_WINDOW_0_INST_CONST].cpu_addr, fw_inst_const, ++ region_params.inst_const_size); ++ memcpy(fb_info.fb[DMUB_WINDOW_2_BSS_DATA].cpu_addr, fw_bss_data, ++ region_params.bss_data_size); ++ memcpy(fb_info.fb[DMUB_WINDOW_3_VBIOS].cpu_addr, ++ adev->dm.dc->ctx->dc_bios->bios, region_params.vbios_size); ++ ++ /* Initialize hardware. */ ++ memset(&hw_params, 0, sizeof(hw_params)); ++ hw_params.fb_base = adev->gmc.fb_start; ++ hw_params.fb_offset = adev->gmc.aper_base; ++ ++ if (dmcu) ++ hw_params.psp_version = dmcu->psp_version; ++ ++ for (i = 0; i < fb_info.num_fb; ++i) ++ hw_params.fb[i] = &fb_info.fb[i]; ++ ++ status = dmub_srv_hw_init(dmub_srv, &hw_params); ++ if (status != DMUB_STATUS_OK) { ++ DRM_ERROR("Error initializing DMUB HW: %d\n", status); ++ return -EINVAL; ++ } ++ ++ /* Wait for firmware load to finish. */ ++ status = dmub_srv_wait_for_auto_load(dmub_srv, 100000); ++ if (status != DMUB_STATUS_OK) ++ DRM_WARN("Wait for DMUB auto-load failed: %d\n", status); ++ ++ /* Init DMCU and ABM if available. */ ++ if (dmcu && abm) { ++ dmcu->funcs->dmcu_init(dmcu); ++ abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu); ++ } ++ ++ DRM_INFO("DMUB hardware initialized: version=0x%08X\n", ++ adev->dm.dmcub_fw_version); ++ ++ return 0; ++} ++ ++#endif ++ ++ ++ + static int amdgpu_dm_init(struct amdgpu_device *adev) + { + struct dc_init_data init_data; + #ifdef CONFIG_DRM_AMD_DC_HDCP + struct dc_callback_init init_params; ++#endif ++#ifdef CONFIG_DRM_AMD_DC_DMUB ++ int r; + #endif + adev->dm.ddev = adev->ddev; + adev->dm.adev = adev; +@@ -746,6 +895,14 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) + + dc_hardware_init(adev->dm.dc); + ++#ifdef CONFIG_DRM_AMD_DC_DMUB ++ r = dm_dmub_hw_init(adev); ++ if (r) { ++ DRM_ERROR("DMUB interface failed to initialize: status=%d\n", r); ++ goto error; ++ } ++ ++#endif + adev->dm.freesync_module = mod_freesync_create(adev->dm.dc); + if (!adev->dm.freesync_module) { + DRM_ERROR( +@@ -781,6 +938,12 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) + if (dtn_debugfs_init(adev)) + DRM_ERROR("amdgpu: failed initialize dtn debugfs support.\n"); + #endif ++#ifdef CONFIG_DRM_AMD_DC_DMUB ++ if (adev->dm.dmub_bo) ++ amdgpu_bo_free_kernel(&adev->dm.dmub_bo, ++ &adev->dm.dmub_bo_gpu_addr, ++ &adev->dm.dmub_bo_cpu_addr); ++#endif + + DRM_DEBUG_DRIVER("KMS initialized.\n"); + +@@ -914,9 +1077,104 @@ static int load_dmcu_fw(struct amdgpu_device *adev) + return 0; + } + ++#ifdef CONFIG_DRM_AMD_DC_DMUB ++static uint32_t amdgpu_dm_dmub_reg_read(void *ctx, uint32_t address) ++{ ++ struct amdgpu_device *adev = ctx; ++ ++ return dm_read_reg(adev->dm.dc->ctx, address); ++} ++ ++static void amdgpu_dm_dmub_reg_write(void *ctx, uint32_t address, ++ uint32_t value) ++{ ++ struct amdgpu_device *adev = ctx; ++ ++ return dm_write_reg(adev->dm.dc->ctx, address, value); ++} ++ ++static int dm_dmub_sw_init(struct amdgpu_device *adev) ++{ ++ struct dmub_srv_create_params create_params; ++ const struct dmcub_firmware_header_v1_0 *hdr; ++ const char *fw_name_dmub; ++ enum dmub_asic dmub_asic; ++ enum dmub_status status; ++ int r; ++ ++ switch (adev->asic_type) { ++ case CHIP_RENOIR: ++ dmub_asic = DMUB_ASIC_DCN21; ++ fw_name_dmub = FIRMWARE_RENOIR_DMUB; ++ break; ++ ++ default: ++ /* ASIC doesn't support DMUB. */ ++ return 0; ++ } ++ ++ adev->dm.dmub_srv = kzalloc(sizeof(*adev->dm.dmub_srv), GFP_KERNEL); ++ if (!adev->dm.dmub_srv) { ++ DRM_ERROR("Failed to allocate DMUB service!\n"); ++ return -ENOMEM; ++ } ++ ++ memset(&create_params, 0, sizeof(create_params)); ++ create_params.user_ctx = adev; ++ create_params.funcs.reg_read = amdgpu_dm_dmub_reg_read; ++ create_params.funcs.reg_write = amdgpu_dm_dmub_reg_write; ++ create_params.asic = dmub_asic; ++ ++ status = dmub_srv_create(adev->dm.dmub_srv, &create_params); ++ if (status != DMUB_STATUS_OK) { ++ DRM_ERROR("Error creating DMUB service: %d\n", status); ++ return -EINVAL; ++ } ++ ++ r = request_firmware_direct(&adev->dm.dmub_fw, fw_name_dmub, adev->dev); ++ if (r) { ++ DRM_ERROR("DMUB firmware loading failed: %d\n", r); ++ return 0; ++ } ++ ++ r = amdgpu_ucode_validate(adev->dm.dmub_fw); ++ if (r) { ++ DRM_ERROR("Couldn't validate DMUB firmware: %d\n", r); ++ return 0; ++ } ++ ++ if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) { ++ DRM_WARN("Only PSP firmware loading is supported for DMUB\n"); ++ return 0; ++ } ++ ++ hdr = (const struct dmcub_firmware_header_v1_0 *)adev->dm.dmub_fw->data; ++ adev->firmware.ucode[AMDGPU_UCODE_ID_DMCUB].ucode_id = ++ AMDGPU_UCODE_ID_DMCUB; ++ adev->firmware.ucode[AMDGPU_UCODE_ID_DMCUB].fw = adev->dm.dmub_fw; ++ adev->firmware.fw_size += ++ ALIGN(le32_to_cpu(hdr->inst_const_bytes), PAGE_SIZE); ++ ++ adev->dm.dmcub_fw_version = le32_to_cpu(hdr->header.ucode_version); ++ ++ DRM_INFO("Loading DMUB firmware via PSP: version=0x%08X\n", ++ adev->dm.dmcub_fw_version); ++ ++ return 0; ++} ++ ++#endif + static int dm_sw_init(void *handle) + { + struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++#ifdef CONFIG_DRM_AMD_DC_DMUB ++ int r; ++ ++ r = dm_dmub_sw_init(adev); ++ if (r) ++ return r; ++ ++#endif + + return load_dmcu_fw(adev); + } +@@ -925,6 +1183,18 @@ static int dm_sw_fini(void *handle) + { + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + ++#ifdef CONFIG_DRM_AMD_DC_DMUB ++ if (adev->dm.dmub_srv) { ++ dmub_srv_destroy(adev->dm.dmub_srv); ++ adev->dm.dmub_srv = NULL; ++ } ++ ++ if (adev->dm.dmub_fw) { ++ release_firmware(adev->dm.dmub_fw); ++ adev->dm.dmub_fw = NULL; ++ } ++ ++#endif + if(adev->dm.fw_dmcu) { + release_firmware(adev->dm.fw_dmcu); + adev->dm.fw_dmcu = NULL; +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +index 1aba070477b9..27167d2bd654 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +@@ -54,6 +54,10 @@ struct amdgpu_device; + struct drm_device; + struct amdgpu_dm_irq_handler_data; + struct dc; ++#ifdef CONFIG_DRM_AMD_DC_DMUB ++struct amdgpu_bo; ++struct dmub_srv; ++#endif + + struct common_irq_params { + struct amdgpu_device *adev; +@@ -145,6 +149,52 @@ struct amdgpu_display_manager { + */ + struct mutex dc_lock; + ++#ifdef CONFIG_DRM_AMD_DC_DMUB ++ /** ++ * @dmub_srv: ++ * ++ * DMUB service, used for controlling the DMUB on hardware ++ * that supports it. The pointer to the dmub_srv will be ++ * NULL on hardware that does not support it. ++ */ ++ struct dmub_srv *dmub_srv; ++ ++ /** ++ * @dmub_fw: ++ * ++ * DMUB firmware, required on hardware that has DMUB support. ++ */ ++ const struct firmware *dmub_fw; ++ ++ /** ++ * @dmub_bo: ++ * ++ * Buffer object for the DMUB. ++ */ ++ struct amdgpu_bo *dmub_bo; ++ ++ /** ++ * @dmub_bo_gpu_addr: ++ * ++ * GPU virtual address for the DMUB buffer object. ++ */ ++ u64 dmub_bo_gpu_addr; ++ ++ /** ++ * @dmub_bo_cpu_addr: ++ * ++ * CPU address for the DMUB buffer object. ++ */ ++ void *dmub_bo_cpu_addr; ++ ++ /** ++ * @dmcub_fw_version: ++ * ++ * DMCUB firmware version. ++ */ ++ uint32_t dmcub_fw_version; ++ ++#endif + /** + *@irq_handler_list_low_tab: + * +-- +2.17.1 + |