Re: [PATCH 2/3] drm/amdgpu: Add USBC PD FW load to PSP 11
On 3/2/20 4:30 PM, Alex Deucher wrote: On Mon, Mar 2, 2020 at 2:24 PM Andrey Grodzovsky wrote: Add the programming sequence. Signed-off-by: Andrey Grodzovsky --- 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 300 +/* USBC PD FW version retrieval command */ +#define C2PMSG_CMD_GFX_USB_PD_FW_VER 0x200 + 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), +0x8000, 0x8000, 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, 0x80); + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), +0x8000, 0x8000, false); + if (ret) + return ret; + + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35); + + if ((reg_status & 0x) != 0) { + DRM_ERROR("Lower address load failed - MP0_SMN_C2PMSG_35.Bits [15:0] = %02x...\n", + reg_status & 0x); + 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), +0x8000, 0x8000, 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, 0x400); + + /* FW load takes long time */ + while(psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), +0x8000, 0x8000, 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 & 0x) != 0) { + DRM_ERROR("Upper address load failed - MP0_SMN_C2PMSG_35.Bits [15:0] = %02x...\n", + reg_status & 0x); + 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), +0x8000, 0x8000, 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
Re: [PATCH 2/3] drm/amdgpu: Add USBC PD FW load to PSP 11
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 >>> --- >>> 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 300 >>> >>> +/* USBC PD FW version retrieval command */ >>> +#define C2PMSG_CMD_GFX_USB_PD_FW_VER 0x200 >>> + >>> 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), >>> +0x8000, 0x8000, false); >>> + if (ret) >>> + return ret; >>> + >>> +// Fireup interrupt so PSP can pick up the lower address >>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x80); >>> + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), >>> +0x8000, 0x8000, false); >>> + if (ret) >>> + return ret; >>> + >>> + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35); >>> + >>> + if ((reg_status & 0x) != 0) { >>> + DRM_ERROR("Lower address load failed - MP0_SMN_C2PMSG_35.Bits >>> [15:0] = %02x...\n", >>> + reg_status & 0x); >>> + 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), >>> +0x8000, 0x8000, false); >>> + if (ret) >>> + return ret; >>> + >>> +// Fireup interrupt so PSP can pick up the upper address >>> + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x400); >>> + >>> + /* FW load takes long time */ >>> + while(psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), >>> +0x8000, 0x8000, 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 > 0x8000, 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, 0x400); >> 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
Re: [PATCH 2/3] drm/amdgpu: Add USBC PD FW load to PSP 11
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 --- 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 300 +/* USBC PD FW version retrieval command */ +#define C2PMSG_CMD_GFX_USB_PD_FW_VER 0x200 + 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), +0x8000, 0x8000, false); + if (ret) + return ret; + +// Fireup interrupt so PSP can pick up the lower address + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x80); + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), +0x8000, 0x8000, false); + if (ret) + return ret; + + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35); + + if ((reg_status & 0x) != 0) { + DRM_ERROR("Lower address load failed - MP0_SMN_C2PMSG_35.Bits [15:0] = %02x...\n", + reg_status & 0x); + 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), +0x8000, 0x8000, false); + if (ret) + return ret; + +// Fireup interrupt so PSP can pick up the upper address + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x400); + + /* FW load takes long time */ + while(psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), +0x8000, 0x8000, 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 0x8000, 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, 0x400); 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 & 0x) != 0) {
Re: [PATCH 2/3] drm/amdgpu: Add USBC PD FW load to PSP 11
On Mon, Mar 2, 2020 at 2:24 PM Andrey Grodzovsky wrote: > > Add the programming sequence. > > Signed-off-by: Andrey Grodzovsky > --- > 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 300 > > +/* USBC PD FW version retrieval command */ > +#define C2PMSG_CMD_GFX_USB_PD_FW_VER 0x200 > + 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), > +0x8000, 0x8000, 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, 0x80); > + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), > +0x8000, 0x8000, false); > + if (ret) > + return ret; > + > + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35); > + > + if ((reg_status & 0x) != 0) { > + DRM_ERROR("Lower address load failed - MP0_SMN_C2PMSG_35.Bits > [15:0] = %02x...\n", > + reg_status & 0x); > + 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), > +0x8000, 0x8000, 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, 0x400); > + > + /* FW load takes long time */ > + while(psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), > +0x8000, 0x8000, 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 & 0x) != 0) { > + DRM_ERROR("Upper address load failed - MP0_SMN_C2PMSG_35.Bits > [15:0] = %02x...\n", > + reg_status & 0x); > + 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), > +0x8000, 0x8000, 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
Re: [PATCH 2/3] drm/amdgpu: Add USBC PD FW load to PSP 11
On 2020-03-02 2:24 p.m., Andrey Grodzovsky wrote: > Add the programming sequence. > > Signed-off-by: Andrey Grodzovsky > --- > 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_US300 > > +/* USBC PD FW version retrieval command */ > +#define C2PMSG_CMD_GFX_USB_PD_FW_VER 0x200 > + > 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), > + 0x8000, 0x8000, 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, 0x80); > + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), > + 0x8000, 0x8000, false); > + if (ret) > + return ret; > + > + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35); > + > + if ((reg_status & 0x) != 0) { > + DRM_ERROR("Lower address load failed - MP0_SMN_C2PMSG_35.Bits > [15:0] = %02x...\n", > + reg_status & 0x); > + 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), > + 0x8000, 0x8000, 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, 0x400); > + > + /* FW load takes long time */ > + while(psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), > + 0x8000, 0x8000, false)) > + msleep(1000); > + > + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35); > + > + if ((reg_status & 0x) != 0) { > + DRM_ERROR("Upper address load failed - MP0_SMN_C2PMSG_35.Bits > [15:0] = %02x...\n", > + reg_status & 0x); > + 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), > + 0x8000, 0x8000, 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
Re: [PATCH 2/3] drm/amdgpu: Add USBC PD FW load to PSP 11
On 2020-03-02 2:24 p.m., Andrey Grodzovsky wrote: > Add the programming sequence. > > Signed-off-by: Andrey Grodzovsky > --- > 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_US300 > > +/* USBC PD FW version retrieval command */ > +#define C2PMSG_CMD_GFX_USB_PD_FW_VER 0x200 > + > 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), > + 0x8000, 0x8000, false); > + if (ret) > + return ret; > + > + // Fireup interrupt so PSP can pick up the lower address > + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x80); > + ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), > + 0x8000, 0x8000, false); > + if (ret) > + return ret; > + > + reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35); > + > + if ((reg_status & 0x) != 0) { > + DRM_ERROR("Lower address load failed - MP0_SMN_C2PMSG_35.Bits > [15:0] = %02x...\n", > + reg_status & 0x); > + 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), > + 0x8000, 0x8000, false); > + if (ret) > + return ret; > + > + // Fireup interrupt so PSP can pick up the upper address > + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x400); > + > + /* FW load takes long time */ > + while(psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), > + 0x8000, 0x8000, 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, 0x400); 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 & 0x) != 0) { > + DRM_ERROR("Upper address load failed - MP0_SMN_C2PMSG_35.Bits > [15:0] = %02x...\n", > + reg_status & 0x); 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), > + 0x8000, 0x8000,