Reviewed-by: Luben Tuikov <[email protected]>

On 2020-03-04 11:23, Andrey Grodzovsky wrote:
> Starts USBC PD FW download and reads back the latest FW version.
> 
> v2:
> Move sysfs file creation to late init
> Add locking around PSP calls to avoid concurrent access to PSP's C2P registers
> 
> Signed-off-by: Andrey Grodzovsky <[email protected]>
> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 110 
> +++++++++++++++++++++++++++++++-
>  1 file changed, 109 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
> index d33f741..cff0fd2 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:
> @@ -113,6 +117,16 @@ static int psp_early_init(void *handle)
>       return 0;
>  }
>  
> +static int psp_late_init(void *handle)
> +{
> +     struct amdgpu_device *adev = (struct amdgpu_device *)handle;
> +
> +     if (adev->asic_type == CHIP_NAVI10)
> +             return psp_sysfs_init(adev);
> +
> +     return 0;
> +}
> +
>  static int psp_sw_init(void *handle)
>  {
>       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
> @@ -152,6 +166,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,10 +1834,85 @@ 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;
> +
> +     mutex_lock(&adev->psp.mutex);
> +     ret = psp_read_usbc_pd_fw(&adev->psp, &fw_ver);
> +     mutex_unlock(&adev->psp.mutex);
> +
> +     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;
> +     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)));
> +
> +     mutex_lock(&adev->psp.mutex);
> +     ret = psp_load_usbc_pd_fw(&adev->psp, dma_addr);
> +     mutex_unlock(&adev->psp.mutex);
> +
> +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,
> -     .late_init = NULL,
> +     .late_init = psp_late_init,
>       .sw_init = psp_sw_init,
>       .sw_fini = psp_sw_fini,
>       .hw_init = psp_hw_init,
> @@ -1834,6 +1927,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,
>  };
> 

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

Reply via email to