[PATCH 3/3] drm/amdgpu: Add support for USBC PD FW download
Alex Deucher
alexdeucher at gmail.com
Mon Mar 2 21:33:56 UTC 2020
On Mon, Mar 2, 2020 at 2:24 PM Andrey Grodzovsky
<andrey.grodzovsky at amd.com> wrote:
>
> Starts USBC PD FW download and reads back the latest FW version.
>
> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky at amd.com>
> ---
> drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 94 +++++++++++++++++++++++++++++++++
> 1 file changed, 94 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
> index d33f741..76630b9 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
> @@ -24,6 +24,7 @@
> */
>
> #include <linux/firmware.h>
> +#include <linux/dma-mapping.h>
>
> #include "amdgpu.h"
> #include "amdgpu_psp.h"
> @@ -38,6 +39,9 @@
>
> static void psp_set_funcs(struct amdgpu_device *adev);
>
> +static int psp_sysfs_init(struct amdgpu_device *adev);
> +static void psp_sysfs_fini(struct amdgpu_device *adev);
> +
> /*
> * Due to DF Cstate management centralized to PMFW, the firmware
> * loading sequence will be updated as below:
> @@ -94,6 +98,7 @@ static int psp_early_init(void *handle)
> psp->autoload_supported = false;
> break;
> case CHIP_NAVI10:
> + psp_sysfs_init(adev);
We should add the file as late as possible. Maybe add a new
psp_late_init() function in amdgpu_psp.c? Otherwise, you'll get
processes trying to use the sysfs interface before the driver is
ready.
Alex
> case CHIP_NAVI14:
> case CHIP_NAVI12:
> psp_v11_0_set_psp_funcs(psp);
> @@ -152,6 +157,10 @@ static int psp_sw_fini(void *handle)
> release_firmware(adev->psp.ta_fw);
> adev->psp.ta_fw = NULL;
> }
> +
> + if (adev->asic_type == CHIP_NAVI10)
> + psp_sysfs_fini(adev);
> +
> return 0;
> }
>
> @@ -1816,6 +1825,76 @@ static int psp_set_powergating_state(void *handle,
> return 0;
> }
>
> +static ssize_t psp_usbc_pd_fw_sysfs_read(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + struct drm_device *ddev = dev_get_drvdata(dev);
> + struct amdgpu_device *adev = ddev->dev_private;
> + uint32_t fw_ver;
> + int ret;
> +
> + ret = psp_read_usbc_pd_fw(&adev->psp, &fw_ver);
> + if (ret) {
> + DRM_ERROR("Failed to read USBC PD FW, err = %d", ret);
> + return ret;
> + }
> +
> + return snprintf(buf, PAGE_SIZE, "%x\n", fw_ver);
> +}
> +
> +static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf,
> + size_t count)
> +{
> + struct drm_device *ddev = dev_get_drvdata(dev);
> + struct amdgpu_device *adev = ddev->dev_private;
> + void *cpu_addr;
> + dma_addr_t dma_addr;
> + int ret = 0;
> + char fw_name[100];
> + const struct firmware *usbc_pd_fw;
> +
> +
> + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s", buf);
> + ret = request_firmware(&usbc_pd_fw, fw_name, adev->dev);
> + if (ret)
> + goto fail;
> +
> + /* We need contiguous physical mem to place the FW for psp to access */
> + cpu_addr = dma_alloc_coherent(adev->dev, usbc_pd_fw->size, &dma_addr, GFP_KERNEL);
> +
> + ret = dma_mapping_error(adev->dev, dma_addr);
> + if (ret)
> + goto rel_buf;
> +
> + memcpy_toio(cpu_addr, usbc_pd_fw->data, usbc_pd_fw->size);
> +
> + /*TODO Remove once PSP starts snooping CPU cache */
> + clflush_cache_range(cpu_addr, (usbc_pd_fw->size & ~(L1_CACHE_BYTES - 1)));
> +
> + ret = psp_load_usbc_pd_fw(&adev->psp, dma_addr);
> +
> +rel_buf:
> + dma_free_coherent(adev->dev, usbc_pd_fw->size, cpu_addr, dma_addr);
> + release_firmware(usbc_pd_fw);
> +
> +fail:
> + if (ret) {
> + DRM_ERROR("Failed to load USBC PD FW, err = %d", ret);
> + return ret;
> + }
> +
> + return count;
> +}
> +
> +static DEVICE_ATTR(usbc_pd_fw, S_IRUGO | S_IWUSR,
> + psp_usbc_pd_fw_sysfs_read,
> + psp_usbc_pd_fw_sysfs_write);
> +
> +
> +
> const struct amd_ip_funcs psp_ip_funcs = {
> .name = "psp",
> .early_init = psp_early_init,
> @@ -1834,6 +1913,21 @@ const struct amd_ip_funcs psp_ip_funcs = {
> .set_powergating_state = psp_set_powergating_state,
> };
>
> +static int psp_sysfs_init(struct amdgpu_device *adev)
> +{
> + int ret = device_create_file(adev->dev, &dev_attr_usbc_pd_fw);
> +
> + if (ret)
> + DRM_ERROR("Failed to create USBC PD FW control file!");
> +
> + return ret;
> +}
> +
> +static void psp_sysfs_fini(struct amdgpu_device *adev)
> +{
> + device_remove_file(adev->dev, &dev_attr_usbc_pd_fw);
> +}
> +
> static const struct amdgpu_psp_funcs psp_funcs = {
> .check_fw_loading_status = psp_check_fw_loading_status,
> };
> --
> 2.7.4
>
> _______________________________________________
> amd-gfx mailing list
> amd-gfx at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/amd-gfx
More information about the amd-gfx
mailing list