* Re: [PATCH 2/3] drm/amdgpu: Add USBC PD FW load to PSP 11
2020-03-02 19:24 ` [PATCH 2/3] drm/amdgpu: Add USBC PD FW load to PSP 11 Andrey Grodzovsky
@ 2020-03-02 21:19 ` Luben Tuikov
2020-03-02 21:51 ` Andrey Grodzovsky
2020-03-02 21:30 ` Luben Tuikov
2020-03-02 21:30 ` Alex Deucher
2 siblings, 1 reply; 13+ messages in thread
From: Luben Tuikov @ 2020-03-02 21:19 UTC (permalink / raw)
To: Andrey Grodzovsky, amd-gfx; +Cc: Alexander.Deucher, Slava.Abramov
On 2020-03-02 2:24 p.m., Andrey Grodzovsky wrote:
> Add the programming sequence.
>
> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
> ---
> drivers/gpu/drm/amd/amdgpu/psp_v11_0.c | 76 ++++++++++++++++++++++++++++++++++
> 1 file changed, 76 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
> index 8ab3bf3..621b99c 100644
> --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
> @@ -65,6 +65,9 @@ MODULE_FIRMWARE("amdgpu/arcturus_ta.bin");
> /* memory training timeout define */
> #define MEM_TRAIN_SEND_MSG_TIMEOUT_US 3000000
>
> +/* USBC PD FW version retrieval command */
> +#define C2PMSG_CMD_GFX_USB_PD_FW_VER 0x2000000
> +
> static int psp_v11_0_init_microcode(struct psp_context *psp)
> {
> struct amdgpu_device *adev = psp->adev;
> @@ -1109,6 +1112,77 @@ static void psp_v11_0_ring_set_wptr(struct psp_context *psp, uint32_t value)
> WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, value);
> }
>
> +static int psp_v11_0_load_usbc_pd_fw(struct psp_context *psp, dma_addr_t dma_addr)
> +{
> + struct amdgpu_device *adev = psp->adev;
> + uint32_t reg_status;
> + int ret;
> +
> + /* Write lower 32-bit address of the PD Controller FW */
> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, lower_32_bits(dma_addr));
> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
> + 0x80000000, 0x80000000, false);
> + if (ret)
> + return ret;
> +
> + // Fireup interrupt so PSP can pick up the lower address
> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x800000);
> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
> + 0x80000000, 0x80000000, false);
> + if (ret)
> + return ret;
> +
> + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35);
> +
> + if ((reg_status & 0xFFFF) != 0) {
> + DRM_ERROR("Lower address load failed - MP0_SMN_C2PMSG_35.Bits [15:0] = %02x...\n",
> + reg_status & 0xFFFF);
> + return -EIO;
> + }
> +
> + /* Write upper 32-bit address of the PD Controller FW */
> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, upper_32_bits(dma_addr));
> +
> +
> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
> + 0x80000000, 0x80000000, false);
> + if (ret)
> + return ret;
> +
> + // Fireup interrupt so PSP can pick up the upper address
> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x4000000);
> +
> + /* FW load takes long time */
> + while(psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
> + 0x80000000, 0x80000000, false))
1. The LKCS wants a space after a keyword, "while" and before the opening parenthesis.
https://www.kernel.org/doc/html/v4.10/process/coding-style.html#placing-braces-and-spaces
2. I'd rather include a polling limit in this loop, so that if the PSP goes haywire,
we don't spend too long (forever) here. Also, I'd convert this loop into
a do-while loop, and let the "while" check for the polling limit, while in the body
of the loop, we receive the status from psp_wait_for() and decide whether
to continue or "break".
> + msleep(1000);
That's a rather large timeout given that "psp_wait_for()" polls every micro-second
for 100 microseconds.
And also note that you poll immediately after writing to MP0_SMN_C2PMSG_35, i.e.
you don't give the PSP any time to process the timeout. I'd rather do
something like this:
WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x4000000);
usleep(100); <-- Or some optimal timeout which gives the PSP FW ample time to react and process the interrupt.
do {
res = psp_wait_for(psp, ...);
if (res == 0)
break;
while (++polling_limit < POLLING_LIMIT);
The advantage here is that if you hit the polling limit and
a subsequent read of the address is not what you want,
you know for sure that the PSP is stuck.
> +
> + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35);
> +
> + if ((reg_status & 0xFFFF) != 0) {
> + DRM_ERROR("Upper address load failed - MP0_SMN_C2PMSG_35.Bits [15:0] = %02x...\n",
> + reg_status & 0xFFFF);
Perhaps you want to say "%04X" so the field width is always 4 hexadecimal chars.
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +
> +static int psp_v11_0_read_usbc_pd_fw(struct psp_context *psp, uint32_t *fw_ver)
> +{
> + struct amdgpu_device *adev = psp->adev;
> +
> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, C2PMSG_CMD_GFX_USB_PD_FW_VER);
> +
> + while(psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
> + 0x80000000, 0x80000000, false))
Space after a keyword ("while") and before "(".
Same sentiment as above:
After writing the interrupt, wait some nominal time for the PSP to react,
then psp_wait_for() in a do-while loop also with a polling limit.
Regards,
Luben
> + msleep(1);
> +
> + *fw_ver = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36);
> +
> + return 0;
> +}
> +
> static const struct psp_funcs psp_v11_0_funcs = {
> .init_microcode = psp_v11_0_init_microcode,
> .bootloader_load_kdb = psp_v11_0_bootloader_load_kdb,
> @@ -1133,6 +1207,8 @@ static const struct psp_funcs psp_v11_0_funcs = {
> .mem_training = psp_v11_0_memory_training,
> .ring_get_wptr = psp_v11_0_ring_get_wptr,
> .ring_set_wptr = psp_v11_0_ring_set_wptr,
> + .load_usbc_pd_fw = psp_v11_0_load_usbc_pd_fw,
> + .read_usbc_pd_fw = psp_v11_0_read_usbc_pd_fw
> };
>
> void psp_v11_0_set_psp_funcs(struct psp_context *psp)
>
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/3] drm/amdgpu: Add USBC PD FW load to PSP 11
2020-03-02 21:19 ` Luben Tuikov
@ 2020-03-02 21:51 ` Andrey Grodzovsky
2020-03-02 23:04 ` Luben Tuikov
0 siblings, 1 reply; 13+ messages in thread
From: Andrey Grodzovsky @ 2020-03-02 21:51 UTC (permalink / raw)
To: Luben Tuikov, amd-gfx; +Cc: Alexander.Deucher, Slava.Abramov
On 3/2/20 4:19 PM, Luben Tuikov wrote:
> On 2020-03-02 2:24 p.m., Andrey Grodzovsky wrote:
>> Add the programming sequence.
>>
>> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
>> ---
>> drivers/gpu/drm/amd/amdgpu/psp_v11_0.c | 76 ++++++++++++++++++++++++++++++++++
>> 1 file changed, 76 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>> index 8ab3bf3..621b99c 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>> @@ -65,6 +65,9 @@ MODULE_FIRMWARE("amdgpu/arcturus_ta.bin");
>> /* memory training timeout define */
>> #define MEM_TRAIN_SEND_MSG_TIMEOUT_US 3000000
>>
>> +/* USBC PD FW version retrieval command */
>> +#define C2PMSG_CMD_GFX_USB_PD_FW_VER 0x2000000
>> +
>> static int psp_v11_0_init_microcode(struct psp_context *psp)
>> {
>> struct amdgpu_device *adev = psp->adev;
>> @@ -1109,6 +1112,77 @@ static void psp_v11_0_ring_set_wptr(struct psp_context *psp, uint32_t value)
>> WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, value);
>> }
>>
>> +static int psp_v11_0_load_usbc_pd_fw(struct psp_context *psp, dma_addr_t dma_addr)
>> +{
>> + struct amdgpu_device *adev = psp->adev;
>> + uint32_t reg_status;
>> + int ret;
>> +
>> + /* Write lower 32-bit address of the PD Controller FW */
>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, lower_32_bits(dma_addr));
>> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
>> + 0x80000000, 0x80000000, false);
>> + if (ret)
>> + return ret;
>> +
>> + // Fireup interrupt so PSP can pick up the lower address
>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x800000);
>> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
>> + 0x80000000, 0x80000000, false);
>> + if (ret)
>> + return ret;
>> +
>> + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35);
>> +
>> + if ((reg_status & 0xFFFF) != 0) {
>> + DRM_ERROR("Lower address load failed - MP0_SMN_C2PMSG_35.Bits [15:0] = %02x...\n",
>> + reg_status & 0xFFFF);
>> + return -EIO;
>> + }
>> +
>> + /* Write upper 32-bit address of the PD Controller FW */
>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, upper_32_bits(dma_addr));
>> +
>> +
>> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
>> + 0x80000000, 0x80000000, false);
>> + if (ret)
>> + return ret;
>> +
>> + // Fireup interrupt so PSP can pick up the upper address
>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x4000000);
>> +
>> + /* FW load takes long time */
>> + while(psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
>> + 0x80000000, 0x80000000, false))
> 1. The LKCS wants a space after a keyword, "while" and before the opening parenthesis.
> https://www.kernel.org/doc/html/v4.10/process/coding-style.html#placing-braces-and-spaces
>
> 2. I'd rather include a polling limit in this loop, so that if the PSP goes haywire,
> we don't spend too long (forever) here. Also, I'd convert this loop into
> a do-while loop, and let the "while" check for the polling limit, while in the body
> of the loop, we receive the status from psp_wait_for() and decide whether
> to continue or "break".
>
>> + msleep(1000);
> That's a rather large timeout given that "psp_wait_for()" polls every micro-second
> for 100 microseconds.
The download from PSP to USBC chip over I2C takes between 20s - 40s
depending on the PD FW file size to download, only at the end of this
time interval will the PSP respond by setting mmMP0_SMN_C2PMSG_35 to
0x80000000, psp_wait_for is using udelay which is busy wait and so to
avoid blocking the CPU for to much time during this long 20-40s wait i
prefer the 1s interval between each busy wait of psp_wait_for
>
> And also note that you poll immediately after writing to MP0_SMN_C2PMSG_35, i.e.
> you don't give the PSP any time to process the timeout.
What do you mean here - why I need to give PSP any time here before
starting the wait loop ?
> I'd rather do
> something like this:
>
> WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x4000000);
> usleep(100); <-- Or some optimal timeout which gives the PSP FW ample time to react and process the interrupt.
React to what ? The next time PSP will react will be when the I2C
download finish or an error will happen and this will be caught during
the next cycle of psp_wait_for
Andrey
> do {
> res = psp_wait_for(psp, ...);
> if (res == 0)
> break;
> while (++polling_limit < POLLING_LIMIT);
>
> The advantage here is that if you hit the polling limit and
> a subsequent read of the address is not what you want,
> you know for sure that the PSP is stuck.
>
>> +
>> + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35);
>> +
>> + if ((reg_status & 0xFFFF) != 0) {
>> + DRM_ERROR("Upper address load failed - MP0_SMN_C2PMSG_35.Bits [15:0] = %02x...\n",
>> + reg_status & 0xFFFF);
> Perhaps you want to say "%04X" so the field width is always 4 hexadecimal chars.
>
>> + return -EIO;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int psp_v11_0_read_usbc_pd_fw(struct psp_context *psp, uint32_t *fw_ver)
>> +{
>> + struct amdgpu_device *adev = psp->adev;
>> +
>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, C2PMSG_CMD_GFX_USB_PD_FW_VER);
>> +
>> + while(psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
>> + 0x80000000, 0x80000000, false))
> Space after a keyword ("while") and before "(".
>
> Same sentiment as above:
> After writing the interrupt, wait some nominal time for the PSP to react,
> then psp_wait_for() in a do-while loop also with a polling limit.
>
> Regards,
> Luben
>
>> + msleep(1);
>> +
>> + *fw_ver = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36);
>> +
>> + return 0;
>> +}
>> +
>> static const struct psp_funcs psp_v11_0_funcs = {
>> .init_microcode = psp_v11_0_init_microcode,
>> .bootloader_load_kdb = psp_v11_0_bootloader_load_kdb,
>> @@ -1133,6 +1207,8 @@ static const struct psp_funcs psp_v11_0_funcs = {
>> .mem_training = psp_v11_0_memory_training,
>> .ring_get_wptr = psp_v11_0_ring_get_wptr,
>> .ring_set_wptr = psp_v11_0_ring_set_wptr,
>> + .load_usbc_pd_fw = psp_v11_0_load_usbc_pd_fw,
>> + .read_usbc_pd_fw = psp_v11_0_read_usbc_pd_fw
>> };
>>
>> void psp_v11_0_set_psp_funcs(struct psp_context *psp)
>>
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/3] drm/amdgpu: Add USBC PD FW load to PSP 11
2020-03-02 21:51 ` Andrey Grodzovsky
@ 2020-03-02 23:04 ` Luben Tuikov
0 siblings, 0 replies; 13+ messages in thread
From: Luben Tuikov @ 2020-03-02 23:04 UTC (permalink / raw)
To: Andrey Grodzovsky, amd-gfx; +Cc: Alexander.Deucher, Slava.Abramov
On 2020-03-02 4:51 p.m., Andrey Grodzovsky wrote:
>
> On 3/2/20 4:19 PM, Luben Tuikov wrote:
>> On 2020-03-02 2:24 p.m., Andrey Grodzovsky wrote:
>>> Add the programming sequence.
>>>
>>> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
>>> ---
>>> drivers/gpu/drm/amd/amdgpu/psp_v11_0.c | 76 ++++++++++++++++++++++++++++++++++
>>> 1 file changed, 76 insertions(+)
>>>
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>> index 8ab3bf3..621b99c 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>>> @@ -65,6 +65,9 @@ MODULE_FIRMWARE("amdgpu/arcturus_ta.bin");
>>> /* memory training timeout define */
>>> #define MEM_TRAIN_SEND_MSG_TIMEOUT_US 3000000
>>>
>>> +/* USBC PD FW version retrieval command */
>>> +#define C2PMSG_CMD_GFX_USB_PD_FW_VER 0x2000000
>>> +
>>> static int psp_v11_0_init_microcode(struct psp_context *psp)
>>> {
>>> struct amdgpu_device *adev = psp->adev;
>>> @@ -1109,6 +1112,77 @@ static void psp_v11_0_ring_set_wptr(struct psp_context *psp, uint32_t value)
>>> WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, value);
>>> }
>>>
>>> +static int psp_v11_0_load_usbc_pd_fw(struct psp_context *psp, dma_addr_t dma_addr)
>>> +{
>>> + struct amdgpu_device *adev = psp->adev;
>>> + uint32_t reg_status;
>>> + int ret;
>>> +
>>> + /* Write lower 32-bit address of the PD Controller FW */
>>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, lower_32_bits(dma_addr));
>>> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
>>> + 0x80000000, 0x80000000, false);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + // Fireup interrupt so PSP can pick up the lower address
>>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x800000);
>>> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
>>> + 0x80000000, 0x80000000, false);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35);
>>> +
>>> + if ((reg_status & 0xFFFF) != 0) {
>>> + DRM_ERROR("Lower address load failed - MP0_SMN_C2PMSG_35.Bits [15:0] = %02x...\n",
>>> + reg_status & 0xFFFF);
>>> + return -EIO;
>>> + }
>>> +
>>> + /* Write upper 32-bit address of the PD Controller FW */
>>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, upper_32_bits(dma_addr));
>>> +
>>> +
>>> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
>>> + 0x80000000, 0x80000000, false);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + // Fireup interrupt so PSP can pick up the upper address
>>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x4000000);
>>> +
>>> + /* FW load takes long time */
>>> + while(psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
>>> + 0x80000000, 0x80000000, false))
>> 1. The LKCS wants a space after a keyword, "while" and before the opening parenthesis.
>> https://www.kernel.org/doc/html/v4.10/process/coding-style.html#placing-braces-and-spaces
>>
>> 2. I'd rather include a polling limit in this loop, so that if the PSP goes haywire,
>> we don't spend too long (forever) here. Also, I'd convert this loop into
>> a do-while loop, and let the "while" check for the polling limit, while in the body
>> of the loop, we receive the status from psp_wait_for() and decide whether
>> to continue or "break".
>>
>>> + msleep(1000);
>> That's a rather large timeout given that "psp_wait_for()" polls every micro-second
>> for 100 microseconds.
>
>
> The download from PSP to USBC chip over I2C takes between 20s - 40s
> depending on the PD FW file size to download, only at the end of this
> time interval will the PSP respond by setting mmMP0_SMN_C2PMSG_35 to
> 0x80000000, psp_wait_for is using udelay which is busy wait and so to
> avoid blocking the CPU for to much time during this long 20-40s wait i
> prefer the 1s interval between each busy wait of psp_wait_for
>
>
>>
>> And also note that you poll immediately after writing to MP0_SMN_C2PMSG_35, i.e.
>> you don't give the PSP any time to process the timeout.
>
>
> What do you mean here - why I need to give PSP any time here before
> starting the wait loop ?
Because nothing would've been done in 0 or near-0 time. Effectively
you do WREG() immediately followed by a busy loop of RREG() (from psp_wait_for())
and there is no point in that busy loop.
>
>
>> I'd rather do
>> something like this:
>>
>> WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x4000000);
>> usleep(100); <-- Or some optimal timeout which gives the PSP FW ample time to react and process the interrupt.
>
>
> React to what ? The next time PSP will react will be when the I2C
> download finish or an error will happen and this will be caught during
> the next cycle of psp_wait_for
Since you're waiting 1 second (msleep(1000)), it'd be better
to wait 1 second immediately after telling the PSP to load the firmware,
and after that point in time, start polling for status.
I'd also suggest not using psp_wait_for() as it does a busy loop for
100,000 polls waiting 1 us in between--not very interactive-OS-friendly.
I'd suggest the following code:
...
/* Fire up the interrupt so that PSP can pick up
* the upper address.
*/
WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x4000000);
A: msleep(500);
for (poll_count = 0; poll_count < USBC_PD_POLLING_LIMIT; poll_count++) {
B: msleep(500);
reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35);
if ((reg_status & 0x80000000) == 0x80000000)
break;
}
if ((reg_status & 0xFFFF) != 0) {
DRM_ERROR("Upper address load failed: "
"MP0_SMN_C2PMSG_35.Bits[15:0]: %04X ...\n",
reg_status & 0xFFFF);
return -EIO;
}
return 0;
}
This way you wait 1 second after telling the PSP to download
the firmware and before you poll the first time, but 500 ms
polling for status every polling loop, after that.
Note that you can eliminate timeout A and add it to
timeout B, if you don't want to have different timeout
times for work-being-done and for polling-status. Or,
you can increase A and decrease B.
Note also that the above avoids,
1. the busy loop in psp_wait_for(), and
2. an extraneous read after the loop to check for status.
Regards,
Luben
>
> Andrey
>
>
>> do {
>> res = psp_wait_for(psp, ...);
>> if (res == 0)
>> break;
>> while (++polling_limit < POLLING_LIMIT);
>>
>> The advantage here is that if you hit the polling limit and
>> a subsequent read of the address is not what you want,
>> you know for sure that the PSP is stuck.
>>
>>> +
>>> + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35);
>>> +
>>> + if ((reg_status & 0xFFFF) != 0) {
>>> + DRM_ERROR("Upper address load failed - MP0_SMN_C2PMSG_35.Bits [15:0] = %02x...\n",
>>> + reg_status & 0xFFFF);
>> Perhaps you want to say "%04X" so the field width is always 4 hexadecimal chars.
>>
>>> + return -EIO;
>>> + }
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int psp_v11_0_read_usbc_pd_fw(struct psp_context *psp, uint32_t *fw_ver)
>>> +{
>>> + struct amdgpu_device *adev = psp->adev;
>>> +
>>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, C2PMSG_CMD_GFX_USB_PD_FW_VER);
>>> +
>>> + while(psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
>>> + 0x80000000, 0x80000000, false))
>> Space after a keyword ("while") and before "(".
>>
>> Same sentiment as above:
>> After writing the interrupt, wait some nominal time for the PSP to react,
>> then psp_wait_for() in a do-while loop also with a polling limit.
>>
>> Regards,
>> Luben
>>
>>> + msleep(1);
>>> +
>>> + *fw_ver = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> static const struct psp_funcs psp_v11_0_funcs = {
>>> .init_microcode = psp_v11_0_init_microcode,
>>> .bootloader_load_kdb = psp_v11_0_bootloader_load_kdb,
>>> @@ -1133,6 +1207,8 @@ static const struct psp_funcs psp_v11_0_funcs = {
>>> .mem_training = psp_v11_0_memory_training,
>>> .ring_get_wptr = psp_v11_0_ring_get_wptr,
>>> .ring_set_wptr = psp_v11_0_ring_set_wptr,
>>> + .load_usbc_pd_fw = psp_v11_0_load_usbc_pd_fw,
>>> + .read_usbc_pd_fw = psp_v11_0_read_usbc_pd_fw
>>> };
>>>
>>> void psp_v11_0_set_psp_funcs(struct psp_context *psp)
>>>
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/3] drm/amdgpu: Add USBC PD FW load to PSP 11
2020-03-02 19:24 ` [PATCH 2/3] drm/amdgpu: Add USBC PD FW load to PSP 11 Andrey Grodzovsky
2020-03-02 21:19 ` Luben Tuikov
@ 2020-03-02 21:30 ` Luben Tuikov
2020-03-02 21:30 ` Alex Deucher
2 siblings, 0 replies; 13+ messages in thread
From: Luben Tuikov @ 2020-03-02 21:30 UTC (permalink / raw)
To: Andrey Grodzovsky, amd-gfx; +Cc: Alexander.Deucher, Slava.Abramov
On 2020-03-02 2:24 p.m., Andrey Grodzovsky wrote:
> Add the programming sequence.
>
> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
> ---
> drivers/gpu/drm/amd/amdgpu/psp_v11_0.c | 76 ++++++++++++++++++++++++++++++++++
> 1 file changed, 76 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
> index 8ab3bf3..621b99c 100644
> --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
> @@ -65,6 +65,9 @@ MODULE_FIRMWARE("amdgpu/arcturus_ta.bin");
> /* memory training timeout define */
> #define MEM_TRAIN_SEND_MSG_TIMEOUT_US 3000000
>
> +/* USBC PD FW version retrieval command */
> +#define C2PMSG_CMD_GFX_USB_PD_FW_VER 0x2000000
> +
> static int psp_v11_0_init_microcode(struct psp_context *psp)
> {
> struct amdgpu_device *adev = psp->adev;
> @@ -1109,6 +1112,77 @@ static void psp_v11_0_ring_set_wptr(struct psp_context *psp, uint32_t value)
> WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, value);
> }
>
> +static int psp_v11_0_load_usbc_pd_fw(struct psp_context *psp, dma_addr_t dma_addr)
> +{
> + struct amdgpu_device *adev = psp->adev;
> + uint32_t reg_status;
> + int ret;
> +
> + /* Write lower 32-bit address of the PD Controller FW */
> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, lower_32_bits(dma_addr));
> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
> + 0x80000000, 0x80000000, false);
> + if (ret)
> + return ret;
> +
> + // Fireup interrupt so PSP can pick up the lower address
C++ comment?
> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x800000);
> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
> + 0x80000000, 0x80000000, false);
> + if (ret)
> + return ret;
> +
> + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35);
> +
> + if ((reg_status & 0xFFFF) != 0) {
> + DRM_ERROR("Lower address load failed - MP0_SMN_C2PMSG_35.Bits [15:0] = %02x...\n",
> + reg_status & 0xFFFF);
> + return -EIO;
> + }
> +
> + /* Write upper 32-bit address of the PD Controller FW */
> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, upper_32_bits(dma_addr));
> +
> +
> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
> + 0x80000000, 0x80000000, false);
> + if (ret)
> + return ret;
> +
> + // Fireup interrupt so PSP can pick up the upper address
C++ comment?
> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x4000000);
> +
> + /* FW load takes long time */
> + while(psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
> + 0x80000000, 0x80000000, false))
> + msleep(1000);
> +
> + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35);
> +
> + if ((reg_status & 0xFFFF) != 0) {
> + DRM_ERROR("Upper address load failed - MP0_SMN_C2PMSG_35.Bits [15:0] = %02x...\n",
> + reg_status & 0xFFFF);
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +
> +static int psp_v11_0_read_usbc_pd_fw(struct psp_context *psp, uint32_t *fw_ver)
> +{
> + struct amdgpu_device *adev = psp->adev;
> +
> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, C2PMSG_CMD_GFX_USB_PD_FW_VER);
> +
> + while(psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
> + 0x80000000, 0x80000000, false))
> + msleep(1);
> +
> + *fw_ver = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36);
> +
> + return 0;
> +}
> +
> static const struct psp_funcs psp_v11_0_funcs = {
> .init_microcode = psp_v11_0_init_microcode,
> .bootloader_load_kdb = psp_v11_0_bootloader_load_kdb,
> @@ -1133,6 +1207,8 @@ static const struct psp_funcs psp_v11_0_funcs = {
> .mem_training = psp_v11_0_memory_training,
> .ring_get_wptr = psp_v11_0_ring_get_wptr,
> .ring_set_wptr = psp_v11_0_ring_set_wptr,
> + .load_usbc_pd_fw = psp_v11_0_load_usbc_pd_fw,
> + .read_usbc_pd_fw = psp_v11_0_read_usbc_pd_fw
> };
>
> void psp_v11_0_set_psp_funcs(struct psp_context *psp)
>
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/3] drm/amdgpu: Add USBC PD FW load to PSP 11
2020-03-02 19:24 ` [PATCH 2/3] drm/amdgpu: Add USBC PD FW load to PSP 11 Andrey Grodzovsky
2020-03-02 21:19 ` Luben Tuikov
2020-03-02 21:30 ` Luben Tuikov
@ 2020-03-02 21:30 ` Alex Deucher
2020-03-03 16:18 ` Andrey Grodzovsky
2 siblings, 1 reply; 13+ messages in thread
From: Alex Deucher @ 2020-03-02 21:30 UTC (permalink / raw)
To: Andrey Grodzovsky; +Cc: Deucher, Alexander, Abramov, Slava, amd-gfx list
On Mon, Mar 2, 2020 at 2:24 PM Andrey Grodzovsky
<andrey.grodzovsky@amd.com> wrote:
>
> Add the programming sequence.
>
> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
> ---
> drivers/gpu/drm/amd/amdgpu/psp_v11_0.c | 76 ++++++++++++++++++++++++++++++++++
> 1 file changed, 76 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
> index 8ab3bf3..621b99c 100644
> --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
> @@ -65,6 +65,9 @@ MODULE_FIRMWARE("amdgpu/arcturus_ta.bin");
> /* memory training timeout define */
> #define MEM_TRAIN_SEND_MSG_TIMEOUT_US 3000000
>
> +/* USBC PD FW version retrieval command */
> +#define C2PMSG_CMD_GFX_USB_PD_FW_VER 0x2000000
> +
This probably belongs in psp_gfx_if.h.
> static int psp_v11_0_init_microcode(struct psp_context *psp)
> {
> struct amdgpu_device *adev = psp->adev;
> @@ -1109,6 +1112,77 @@ static void psp_v11_0_ring_set_wptr(struct psp_context *psp, uint32_t value)
> WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, value);
> }
>
> +static int psp_v11_0_load_usbc_pd_fw(struct psp_context *psp, dma_addr_t dma_addr)
> +{
> + struct amdgpu_device *adev = psp->adev;
> + uint32_t reg_status;
> + int ret;
> +
> + /* Write lower 32-bit address of the PD Controller FW */
> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, lower_32_bits(dma_addr));
> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
> + 0x80000000, 0x80000000, false);
> + if (ret)
> + return ret;
> +
> + // Fireup interrupt so PSP can pick up the lower address
C style comments please.
> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x800000);
> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
> + 0x80000000, 0x80000000, false);
> + if (ret)
> + return ret;
> +
> + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35);
> +
> + if ((reg_status & 0xFFFF) != 0) {
> + DRM_ERROR("Lower address load failed - MP0_SMN_C2PMSG_35.Bits [15:0] = %02x...\n",
> + reg_status & 0xFFFF);
> + return -EIO;
> + }
> +
> + /* Write upper 32-bit address of the PD Controller FW */
> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, upper_32_bits(dma_addr));
> +
> +
> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
> + 0x80000000, 0x80000000, false);
> + if (ret)
> + return ret;
> +
> + // Fireup interrupt so PSP can pick up the upper address
C style comments.
> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x4000000);
> +
> + /* FW load takes long time */
> + while(psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
> + 0x80000000, 0x80000000, false))
> + msleep(1000);
> +
Are we actually waiting for the full loading here or just the ack of
the command?
> + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35);
> +
> + if ((reg_status & 0xFFFF) != 0) {
> + DRM_ERROR("Upper address load failed - MP0_SMN_C2PMSG_35.Bits [15:0] = %02x...\n",
> + reg_status & 0xFFFF);
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +
> +static int psp_v11_0_read_usbc_pd_fw(struct psp_context *psp, uint32_t *fw_ver)
> +{
> + struct amdgpu_device *adev = psp->adev;
> +
> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, C2PMSG_CMD_GFX_USB_PD_FW_VER);
> +
> + while(psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
> + 0x80000000, 0x80000000, false))
> + msleep(1);
> +
> + *fw_ver = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36);
> +
> + return 0;
> +}
I think we need locking for mmMP0_SMN_C2PMSG_35/mmMP0_SMN_C2PMSG_36
since they are the mailbox registers for communicating with the PSP.
Maybe just a generic psp lock since I don't think we need fine grained
locking for psp.
Alex
> +
> static const struct psp_funcs psp_v11_0_funcs = {
> .init_microcode = psp_v11_0_init_microcode,
> .bootloader_load_kdb = psp_v11_0_bootloader_load_kdb,
> @@ -1133,6 +1207,8 @@ static const struct psp_funcs psp_v11_0_funcs = {
> .mem_training = psp_v11_0_memory_training,
> .ring_get_wptr = psp_v11_0_ring_get_wptr,
> .ring_set_wptr = psp_v11_0_ring_set_wptr,
> + .load_usbc_pd_fw = psp_v11_0_load_usbc_pd_fw,
> + .read_usbc_pd_fw = psp_v11_0_read_usbc_pd_fw
> };
>
> void psp_v11_0_set_psp_funcs(struct psp_context *psp)
> --
> 2.7.4
>
> _______________________________________________
> amd-gfx mailing list
> amd-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/amd-gfx
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/3] drm/amdgpu: Add USBC PD FW load to PSP 11
2020-03-02 21:30 ` Alex Deucher
@ 2020-03-03 16:18 ` Andrey Grodzovsky
0 siblings, 0 replies; 13+ messages in thread
From: Andrey Grodzovsky @ 2020-03-03 16:18 UTC (permalink / raw)
To: Alex Deucher; +Cc: Deucher, Alexander, Abramov, Slava, amd-gfx list
On 3/2/20 4:30 PM, Alex Deucher wrote:
> On Mon, Mar 2, 2020 at 2:24 PM Andrey Grodzovsky
> <andrey.grodzovsky@amd.com> wrote:
>> Add the programming sequence.
>>
>> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
>> ---
>> drivers/gpu/drm/amd/amdgpu/psp_v11_0.c | 76 ++++++++++++++++++++++++++++++++++
>> 1 file changed, 76 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>> index 8ab3bf3..621b99c 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
>> @@ -65,6 +65,9 @@ MODULE_FIRMWARE("amdgpu/arcturus_ta.bin");
>> /* memory training timeout define */
>> #define MEM_TRAIN_SEND_MSG_TIMEOUT_US 3000000
>>
>> +/* USBC PD FW version retrieval command */
>> +#define C2PMSG_CMD_GFX_USB_PD_FW_VER 0x2000000
>> +
> This probably belongs in psp_gfx_if.h.
>
>> static int psp_v11_0_init_microcode(struct psp_context *psp)
>> {
>> struct amdgpu_device *adev = psp->adev;
>> @@ -1109,6 +1112,77 @@ static void psp_v11_0_ring_set_wptr(struct psp_context *psp, uint32_t value)
>> WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, value);
>> }
>>
>> +static int psp_v11_0_load_usbc_pd_fw(struct psp_context *psp, dma_addr_t dma_addr)
>> +{
>> + struct amdgpu_device *adev = psp->adev;
>> + uint32_t reg_status;
>> + int ret;
>> +
>> + /* Write lower 32-bit address of the PD Controller FW */
>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, lower_32_bits(dma_addr));
>> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
>> + 0x80000000, 0x80000000, false);
>> + if (ret)
>> + return ret;
>> +
>> + // Fireup interrupt so PSP can pick up the lower address
> C style comments please.
>
>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x800000);
>> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
>> + 0x80000000, 0x80000000, false);
>> + if (ret)
>> + return ret;
>> +
>> + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35);
>> +
>> + if ((reg_status & 0xFFFF) != 0) {
>> + DRM_ERROR("Lower address load failed - MP0_SMN_C2PMSG_35.Bits [15:0] = %02x...\n",
>> + reg_status & 0xFFFF);
>> + return -EIO;
>> + }
>> +
>> + /* Write upper 32-bit address of the PD Controller FW */
>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, upper_32_bits(dma_addr));
>> +
>> +
>> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
>> + 0x80000000, 0x80000000, false);
>> + if (ret)
>> + return ret;
>> +
>> + // Fireup interrupt so PSP can pick up the upper address
> C style comments.
>
>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x4000000);
>> +
>> + /* FW load takes long time */
>> + while(psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
>> + 0x80000000, 0x80000000, false))
>> + msleep(1000);
>> +
> Are we actually waiting for the full loading here or just the ack of
> the command?
>
>> + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35);
>> +
>> + if ((reg_status & 0xFFFF) != 0) {
>> + DRM_ERROR("Upper address load failed - MP0_SMN_C2PMSG_35.Bits [15:0] = %02x...\n",
>> + reg_status & 0xFFFF);
>> + return -EIO;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int psp_v11_0_read_usbc_pd_fw(struct psp_context *psp, uint32_t *fw_ver)
>> +{
>> + struct amdgpu_device *adev = psp->adev;
>> +
>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, C2PMSG_CMD_GFX_USB_PD_FW_VER);
>> +
>> + while(psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
>> + 0x80000000, 0x80000000, false))
>> + msleep(1);
>> +
>> + *fw_ver = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36);
>> +
>> + return 0;
>> +}
> I think we need locking for mmMP0_SMN_C2PMSG_35/mmMP0_SMN_C2PMSG_36
> since they are the mailbox registers for communicating with the PSP.
> Maybe just a generic psp lock since I don't think we need fine grained
> locking for psp.
>
> Alex
I wonder why we don't lock in any other place we access them (e.g.
psp_v11_0_memory_training_send_msg or psp_v11_0_bootloader_load_sos) ?
Andrey
>
>> +
>> static const struct psp_funcs psp_v11_0_funcs = {
>> .init_microcode = psp_v11_0_init_microcode,
>> .bootloader_load_kdb = psp_v11_0_bootloader_load_kdb,
>> @@ -1133,6 +1207,8 @@ static const struct psp_funcs psp_v11_0_funcs = {
>> .mem_training = psp_v11_0_memory_training,
>> .ring_get_wptr = psp_v11_0_ring_get_wptr,
>> .ring_set_wptr = psp_v11_0_ring_set_wptr,
>> + .load_usbc_pd_fw = psp_v11_0_load_usbc_pd_fw,
>> + .read_usbc_pd_fw = psp_v11_0_read_usbc_pd_fw
>> };
>>
>> void psp_v11_0_set_psp_funcs(struct psp_context *psp)
>> --
>> 2.7.4
>>
>> _______________________________________________
>> amd-gfx mailing list
>> amd-gfx@lists.freedesktop.org
>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.freedesktop.org%2Fmailman%2Flistinfo%2Famd-gfx&data=02%7C01%7Candrey.grodzovsky%40amd.com%7Cf3c9cee87052401e07f508d7bef10174%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637187814630848721&sdata=Mo9%2BR4Nrh0rPxZ7xJrBzHl71M6rWL7KcrgEWOne6yQE%3D&reserved=0
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
^ permalink raw reply [flat|nested] 13+ messages in thread