ehci-sunxi.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Sunxi ehci glue
  4. *
  5. * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com>
  6. * Copyright (C) 2014 Roman Byshko <rbyshko@gmail.com>
  7. *
  8. * Based on code from
  9. * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
  10. */
  11. #include <common.h>
  12. #include <asm/arch/clock.h>
  13. #include <asm/arch/usb_phy.h>
  14. #include <asm/io.h>
  15. #include <dm.h>
  16. #include "ehci.h"
  17. #ifdef CONFIG_SUNXI_GEN_SUN4I
  18. #define BASE_DIST 0x8000
  19. #define AHB_CLK_DIST 2
  20. #else
  21. #define BASE_DIST 0x1000
  22. #define AHB_CLK_DIST 1
  23. #endif
  24. struct ehci_sunxi_priv {
  25. struct ehci_ctrl ehci;
  26. int ahb_gate_mask; /* Mask of ahb_gate0 clk gate bits for this hcd */
  27. int phy_index; /* Index of the usb-phy attached to this hcd */
  28. };
  29. static int ehci_usb_probe(struct udevice *dev)
  30. {
  31. struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
  32. struct usb_platdata *plat = dev_get_platdata(dev);
  33. struct ehci_sunxi_priv *priv = dev_get_priv(dev);
  34. struct ehci_hccr *hccr = (struct ehci_hccr *)devfdt_get_addr(dev);
  35. struct ehci_hcor *hcor;
  36. int extra_ahb_gate_mask = 0;
  37. /*
  38. * This should go away once we've moved to the driver model for
  39. * clocks resp. phys.
  40. */
  41. priv->ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0;
  42. #if defined(CONFIG_MACH_SUNXI_H3_H5) || defined(CONFIG_MACH_SUN50I)
  43. extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_OHCI0;
  44. #endif
  45. priv->phy_index = ((uintptr_t)hccr - SUNXI_USB1_BASE) / BASE_DIST;
  46. priv->ahb_gate_mask <<= priv->phy_index * AHB_CLK_DIST;
  47. extra_ahb_gate_mask <<= priv->phy_index * AHB_CLK_DIST;
  48. priv->phy_index++; /* Non otg phys start at 1 */
  49. setbits_le32(&ccm->ahb_gate0,
  50. priv->ahb_gate_mask | extra_ahb_gate_mask);
  51. #ifdef CONFIG_SUNXI_GEN_SUN6I
  52. setbits_le32(&ccm->ahb_reset0_cfg,
  53. priv->ahb_gate_mask | extra_ahb_gate_mask);
  54. #endif
  55. sunxi_usb_phy_init(priv->phy_index);
  56. sunxi_usb_phy_power_on(priv->phy_index);
  57. hcor = (struct ehci_hcor *)((uintptr_t)hccr +
  58. HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
  59. return ehci_register(dev, hccr, hcor, NULL, 0, plat->init_type);
  60. }
  61. static int ehci_usb_remove(struct udevice *dev)
  62. {
  63. struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
  64. struct ehci_sunxi_priv *priv = dev_get_priv(dev);
  65. int ret;
  66. ret = ehci_deregister(dev);
  67. if (ret)
  68. return ret;
  69. sunxi_usb_phy_exit(priv->phy_index);
  70. #ifdef CONFIG_SUNXI_GEN_SUN6I
  71. clrbits_le32(&ccm->ahb_reset0_cfg, priv->ahb_gate_mask);
  72. #endif
  73. clrbits_le32(&ccm->ahb_gate0, priv->ahb_gate_mask);
  74. return 0;
  75. }
  76. static const struct udevice_id ehci_usb_ids[] = {
  77. { .compatible = "allwinner,sun4i-a10-ehci", },
  78. { .compatible = "allwinner,sun5i-a13-ehci", },
  79. { .compatible = "allwinner,sun6i-a31-ehci", },
  80. { .compatible = "allwinner,sun7i-a20-ehci", },
  81. { .compatible = "allwinner,sun8i-a23-ehci", },
  82. { .compatible = "allwinner,sun8i-a83t-ehci", },
  83. { .compatible = "allwinner,sun8i-h3-ehci", },
  84. { .compatible = "allwinner,sun9i-a80-ehci", },
  85. { .compatible = "allwinner,sun50i-a64-ehci", },
  86. { }
  87. };
  88. U_BOOT_DRIVER(ehci_sunxi) = {
  89. .name = "ehci_sunxi",
  90. .id = UCLASS_USB,
  91. .of_match = ehci_usb_ids,
  92. .probe = ehci_usb_probe,
  93. .remove = ehci_usb_remove,
  94. .ops = &ehci_usb_ops,
  95. .platdata_auto_alloc_size = sizeof(struct usb_platdata),
  96. .priv_auto_alloc_size = sizeof(struct ehci_sunxi_priv),
  97. .flags = DM_FLAG_ALLOC_PRIV_DMA,
  98. };