[PATCH 3/3] drm/amdgpu: Add support for USBC PD FW download

Luben Tuikov luben.tuikov at amd.com
Mon Mar 2 21:42:57 UTC 2020


On 2020-03-02 2:24 p.m., Andrey Grodzovsky 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);
>  	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)

Alignment of the parameters is off here. After applying your patch, the alignment
looks like the above.

> +{
> +	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);

I'd rather print the firmware version in some fixed format,
like say "%08X" (in upper hex digits), since it is not an integer, but a fixed
string (8) of hexadecimal numbers.

It'll make it easy to copy-and-paste and the visual cue is there
when displayed to a screen. Even more so when visually compared,
say in a report of what was being tested and so on.

> +}
> +
> +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;

No need to set "ret" to anything here. After all, you cannot predict
that "all will be well". Let the compiler prove that
it is never being used without being set.

> +	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;

"rel_buf" could also be the identifier of a string or a buffer.
But if you named it "Out_release_buf", then no one would ever confuse
it for a name of a variable (all lower case) or a macro (all upper-case).
Not a blocker, just style.

> +
> +	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)));

Not a blocker, but it is easier to read a commment like this:

	/* TODO: Remove once PSP starts snooping the cache.
	 */
	cflush_cache_range(cpu_addr, ...);


> +
> +	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!");

There's an extra space after the tab char in the above two lines--perhaps
from a cut-and-paste.

Regards,
Luben

> +
> +	 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,
>  };
> 



More information about the amd-gfx mailing list