16.12.2020 09:08, Peter Chen пишет:
> On 20-12-15 23:21:10, Dmitry Osipenko wrote:
>> From: Peter Geis <pgwipe...@gmail.com>
>>  
>>  struct tegra_usb_soc_info {
>>      unsigned long flags;
>> +    unsigned int txfifothresh;
>> +    enum usb_dr_mode dr_mode;
>> +};
>> +
>> +static const struct tegra_usb_soc_info tegra20_ehci_soc_info = {
>> +    .flags = CI_HDRC_REQUIRES_ALIGNED_DMA |
>> +             CI_HDRC_OVERRIDE_PHY_CONTROL,
>> +    .dr_mode = USB_DR_MODE_HOST,
>> +    .txfifothresh = 10,
>> +};
>> +
>> +static const struct tegra_usb_soc_info tegra30_ehci_soc_info = {
>> +    .flags = CI_HDRC_REQUIRES_ALIGNED_DMA |
>> +             CI_HDRC_OVERRIDE_PHY_CONTROL
>> +    .dr_mode = USB_DR_MODE_HOST,
>> +    .txfifothresh = 16,
>>  };
>>  
>>  static const struct tegra_usb_soc_info tegra_udc_soc_info = {
>> -    .flags = CI_HDRC_REQUIRES_ALIGNED_DMA,
>> +    .flags = CI_HDRC_REQUIRES_ALIGNED_DMA |
>> +             CI_HDRC_OVERRIDE_PHY_CONTROL,
>> +    .dr_mode = USB_DR_MODE_UNKNOWN,
>>  };
> 
> What's the usage for this dr_mode? Does these three SoCs only supports
> single mode, it usually sets dr_mode at board dts file to indicate
> USB role for this board.

All Tegra SoCs have three USB controllers.  Only one of these three
controllers supports peripheral / OTG modes, the other two controllers
are fixed to the host mode and device trees do not specify the dr_mode
for the host controllers.

Hence we need to enforce the dr_mode=host for the host-mode controllers.

For UDC the default mode is "unknown" because actual mode comes from a
board's device tree.

>>  static const struct of_device_id tegra_usb_of_match[] = {
>>      {
>> +            .compatible = "nvidia,tegra20-ehci",
>> +            .data = &tegra20_ehci_soc_info,
>> +    }, {
>> +            .compatible = "nvidia,tegra30-ehci",
>> +            .data = &tegra30_ehci_soc_info,
>> +    }, {
>>              .compatible = "nvidia,tegra20-udc",
>>              .data = &tegra_udc_soc_info,
> 
> Your compatible indicates this controller is single USB role, is it
> on purpose?

Yes, the "tegra20/30-ehci" controllers are fixed to the host-mode in
hardware.

...
>> +static int tegra_usb_internal_port_reset(struct ehci_hcd *ehci,
>> +                                     u32 __iomem *portsc_reg,
>> +                                     unsigned long *flags)
>> +{
>> +    u32 saved_usbintr, temp;
>> +    unsigned int i, tries;
>> +    int retval = 0;
>> +
>> +    saved_usbintr = ehci_readl(ehci, &ehci->regs->intr_enable);
>> +    /* disable USB interrupt */
>> +    ehci_writel(ehci, 0, &ehci->regs->intr_enable);
>> +    spin_unlock_irqrestore(&ehci->lock, *flags);
>> +
>> +    /*
>> +     * Here we have to do Port Reset at most twice for
>> +     * Port Enable bit to be set.
>> +     */
>> +    for (i = 0; i < 2; i++) {
>> +            temp = ehci_readl(ehci, portsc_reg);
>> +            temp |= PORT_RESET;
>> +            ehci_writel(ehci, temp, portsc_reg);
>> +            mdelay(10);
> 
> Needs accurate delay? How about usleep_range?

To be hones I don't know for sure whether hub_control() could be used
from interrupt context.  This mdelay is borrowed from the older
ehci-tegra driver.

Are you suggesting that it should be safe to sleep here?

...
>>  static int tegra_usb_probe(struct platform_device *pdev)
>>  {
>>      const struct tegra_usb_soc_info *soc;
>> @@ -83,24 +292,49 @@ static int tegra_usb_probe(struct platform_device *pdev)
>>              return err;
>>      }
>>  
>> +    if (device_property_present(&pdev->dev, "nvidia,needs-double-reset"))
>> +            usb->needs_double_reset = true;
>> +
>> +    err = tegra_usb_reset_controller(&pdev->dev);
>> +    if (err) {
>> +            dev_err(&pdev->dev, "failed to reset controller: %d\n", err);
>> +            goto fail_power_off;
>> +    }
>> +
>> +    /*
>> +     * USB controller registers shan't be touched before PHY is
> 
> %s/shan't/shouldn't

ok

...
>>  static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable)
>>  {
>>      struct ehci_hcd *ehci = hcd_to_ehci(hcd);
>> @@ -160,14 +166,14 @@ static int host_start(struct ci_hdrc *ci)
>>              pinctrl_select_state(ci->platdata->pctl,
>>                                   ci->platdata->pins_host);
>>  
>> +    ci->hcd = hcd;
>> +
>>      ret = usb_add_hcd(hcd, 0, 0);
>>      if (ret) {
>>              goto disable_reg;
>>      } else {
>>              struct usb_otg *otg = &ci->otg;
>>  
>> -            ci->hcd = hcd;
>> -
> 
> Why this changed?

The ci->hcd is used by tegra_usb_notify_event() to handle reset event
and the reset happens once usb_add_hcd() is invoked.  Hence we need to
pre-assign the hcd pointer, otherwise there will be a NULL dereference.

Reply via email to