Re: [PATCH v10 4/5] usb: renesas-xhci: Add ROM loader for uPD720201

2020-04-30 Thread Vinod Koul
On 29-04-20, 17:39, Mathias Nyman wrote:
> On 24.4.2020 13.14, Vinod Koul wrote:
> > uPD720201 supports ROM and allows software to program the ROM and boot
> > from it. Add support for detecting if ROM is present, if so load the ROM
> > if not programmed earlier.
> > 
> > Signed-off-by: Vinod Koul 
> > Cc: Yoshihiro Shimoda 
> > Cc: Christian Lamparter 
> > ---
> >  drivers/usb/host/xhci-pci-renesas.c | 342 +++-
> >  1 file changed, 341 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/usb/host/xhci-pci-renesas.c 
> > b/drivers/usb/host/xhci-pci-renesas.c
> > index 402e86912c9f..6bb537999754 100644
> > --- a/drivers/usb/host/xhci-pci-renesas.c
> > +++ b/drivers/usb/host/xhci-pci-renesas.c
> > @@ -50,6 +50,22 @@
> >  #define RENESAS_RETRY  1
> >  #define RENESAS_DELAY  10
> >  
> > +#define ROM_VALID_01 0x2013
> > +#define ROM_VALID_02 0x2026
> > +
> > +static int renesas_verify_fw_version(struct pci_dev *pdev, u32 version)
> > +{
> > +   switch (version) {
> > +   case ROM_VALID_01:
> > +   case ROM_VALID_02:
> > +   return 0;
> > +   default:
> > +   dev_err(>dev, "FW has invalid version :%d\n", version);
> > +   return 1;
> > +   }
> > +   return -EINVAL;
> 
> This never returns -EINVAL
> Maybe just get rid of the default case and print
> the error message before returning

Correct, this seems to be leftover, have cleaned it up now.

> > +static bool renesas_download_rom(struct pci_dev *pdev,
> > +const u32 *fw, size_t step)
> > +{
> > +   bool data0_or_data1;
> > +   u8 fw_status;
> > +   size_t i;
> > +   int err;
> > +
> > +   /*
> > +* The hardware does alternate between two 32-bit pages.
> > +* (This is because each row of the firmware is 8 bytes).
> > +*
> > +* for even steps we use DATA0, for odd steps DATA1.
> > +*/
> > +   data0_or_data1 = (step & 1) == 1;
> > +
> > +   /* Read "Set DATAX" and confirm it is cleared. */
> > +   for (i = 0; i < RENESAS_RETRY; i++) {
> > +   err = pci_read_config_byte(pdev, RENESAS_ROM_STATUS_MSB,
> > +  _status);
> > +   if (err) {
> > +   dev_err(>dev, "Read ROM Status failed: %d\n",
> > +   pcibios_err_to_errno(err));
> > +   return false;
> > +   }
> > +   if (!(fw_status & BIT(data0_or_data1)))
> > +   break;
> > +
> > +   udelay(RENESAS_DELAY);
> > +   }
> > +   if (i == RENESAS_RETRY) {
> > +   dev_err(>dev, "Timeout for Set DATAX step: %zd\n", step);
> > +   return false;
> > +   }
> > +
> > +   /*
> > +* Write FW data to "DATAX".
> > +* "LSB is left" => force little endian
> > +*/
> > +   err = pci_write_config_dword(pdev, data0_or_data1 ?
> > +RENESAS_DATA1 : RENESAS_DATA0,
> > +(__force u32)cpu_to_le32(fw[step]));
> > +   if (err) {
> > +   dev_err(>dev, "Write to DATAX failed: %d\n",
> > +   pcibios_err_to_errno(err));
> > +   return false;
> > +   }
> > +
> > +   udelay(100);
> > +
> > +   /* Set "Set DATAX". */
> > +   err = pci_write_config_byte(pdev, RENESAS_ROM_STATUS_MSB,
> > +   BIT(data0_or_data1));
> > +   if (err) {
> > +   dev_err(>dev, "Write config for DATAX failed: %d\n",
> > +   pcibios_err_to_errno(err));
> > +   return false;
> > +   }
> > +
> > +   return true;
> > +}
> 
> The above function is almost identical to renesas_fw_download_image() added 
> in a 
> previous patch.
> To avoid code duplication I'm sure one function that handles both cases would 
> be possible. 

The registers are different, but that doesn't mean it can't be done. I
have added additional argument for rom and select the register to use
(ROM/RAM) and reused the rest of the fn

Thanks
-- 
~Vinod


Re: [PATCH v10 4/5] usb: renesas-xhci: Add ROM loader for uPD720201

2020-04-29 Thread Mathias Nyman
On 24.4.2020 13.14, Vinod Koul wrote:
> uPD720201 supports ROM and allows software to program the ROM and boot
> from it. Add support for detecting if ROM is present, if so load the ROM
> if not programmed earlier.
> 
> Signed-off-by: Vinod Koul 
> Cc: Yoshihiro Shimoda 
> Cc: Christian Lamparter 
> ---
>  drivers/usb/host/xhci-pci-renesas.c | 342 +++-
>  1 file changed, 341 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/usb/host/xhci-pci-renesas.c 
> b/drivers/usb/host/xhci-pci-renesas.c
> index 402e86912c9f..6bb537999754 100644
> --- a/drivers/usb/host/xhci-pci-renesas.c
> +++ b/drivers/usb/host/xhci-pci-renesas.c
> @@ -50,6 +50,22 @@
>  #define RENESAS_RETRY1
>  #define RENESAS_DELAY10
>  
> +#define ROM_VALID_01 0x2013
> +#define ROM_VALID_02 0x2026
> +
> +static int renesas_verify_fw_version(struct pci_dev *pdev, u32 version)
> +{
> + switch (version) {
> + case ROM_VALID_01:
> + case ROM_VALID_02:
> + return 0;
> + default:
> + dev_err(>dev, "FW has invalid version :%d\n", version);
> + return 1;
> + }
> + return -EINVAL;

This never returns -EINVAL
Maybe just get rid of the default case and print
the error message before returning

> +}
> +
>  static int renesas_fw_download_image(struct pci_dev *dev,
>const u32 *fw,
>size_t step)
> @@ -144,10 +160,84 @@ static int renesas_fw_verify(const void *fw_data,
>   return 0;
>  }
>  
> -static int renesas_fw_check_running(struct pci_dev *pdev)
> +static bool renesas_check_rom(struct pci_dev *pdev)
>  {
> + u16 rom_status;
> + int retval;
> +
> + /* Check if external ROM exists */
> + retval = pci_read_config_word(pdev, RENESAS_ROM_STATUS, _status);
> + if (retval)
> + return false;
> +
> + rom_status &= RENESAS_ROM_STATUS_ROM_EXISTS;
> + if (rom_status) {
> + dev_dbg(>dev, "External ROM exists\n");
> + return true; /* External ROM exists */
> + }
> +
> + return false;
> +}
> +
> +static int renesas_check_rom_state(struct pci_dev *pdev)
> +{
> + u16 rom_state;
> + u32 version;
>   int err;
> +
> + /* check FW version */
> + err = pci_read_config_dword(pdev, RENESAS_FW_VERSION, );
> + if (err)
> + return pcibios_err_to_errno(err);
> +
> + version &= RENESAS_FW_VERSION_FIELD;
> + version = version >> RENESAS_FW_VERSION_OFFSET;
> +
> + err = renesas_verify_fw_version(pdev, version);
> + if (err)
> + return err;
> +
> + /*
> +  * Test if ROM is present and loaded, if so we can skip everything
> +  */
> + err = pci_read_config_word(pdev, RENESAS_ROM_STATUS, _state);
> + if (err)
> + return pcibios_err_to_errno(err);
> +
> + if (rom_state & BIT(15)) {
> + /* ROM exists */
> + dev_dbg(>dev, "ROM exists\n");
> +
> + /* Check the "Result Code" Bits (6:4) and act accordingly */
> + switch (rom_state & RENESAS_ROM_STATUS_RESULT) {
> + case RENESAS_ROM_STATUS_SUCCESS:
> + return 0;
> +
> + case RENESAS_ROM_STATUS_NO_RESULT: /* No result yet */
> + return 0;
> +
> + case RENESAS_ROM_STATUS_ERROR: /* Error State */
> + default: /* All other states are marked as "Reserved states" */
> + dev_err(>dev, "Invalid ROM..");
> + break;
> + }
> + }
> +
> + return -EIO;
> +}
> +
> +static int renesas_fw_check_running(struct pci_dev *pdev)
> +{
>   u8 fw_state;
> + int err;
> +
> + /* Check if device has ROM and loaded, if so skip everything */
> + err = renesas_check_rom(pdev);
> + if (err) { /* we have rom */
> + err = renesas_check_rom_state(pdev);
> + if (!err)
> + return err;
> + }
>  
>   /*
>* Test if the device is actually needing the firmware. As most
> @@ -303,11 +393,261 @@ static int renesas_fw_download(struct pci_dev *pdev,
>   return 0;
>  }
>  
> +static void renesas_rom_erase(struct pci_dev *pdev)
> +{
> + int retval, i;
> + u8 status;
> +
> + dev_dbg(>dev, "Performing ROM Erase...\n");
> + retval = pci_write_config_dword(pdev, RENESAS_DATA0,
> + RENESAS_ROM_ERASE_MAGIC);
> + if (retval) {
> + dev_err(>dev, "ROM erase, magic word write failed: %d\n",
> + pcibios_err_to_errno(retval));
> + return;
> + }
> +
> + retval = pci_read_config_byte(pdev, RENESAS_ROM_STATUS, );
> + if (retval) {
> + dev_err(>dev, "ROM status read failed: %d\n",
> + pcibios_err_to_errno(retval));
> + return;
> + }
> + status |= RENESAS_ROM_STATUS_ERASE;
> + retval = pci_write_config_byte(pdev,