dwc3-sti-glue.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * STiH407 family DWC3 specific Glue layer
  4. *
  5. * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
  6. * Author(s): Patrice Chotard, <patrice.chotard@st.com> for STMicroelectronics.
  7. */
  8. #include <common.h>
  9. #include <log.h>
  10. #include <asm/io.h>
  11. #include <dm.h>
  12. #include <errno.h>
  13. #include <dm/lists.h>
  14. #include <regmap.h>
  15. #include <reset-uclass.h>
  16. #include <syscon.h>
  17. #include <usb.h>
  18. #include <linux/usb/dwc3.h>
  19. #include <linux/usb/otg.h>
  20. #include <dwc3-sti-glue.h>
  21. DECLARE_GLOBAL_DATA_PTR;
  22. /*
  23. * struct sti_dwc3_glue_plat - dwc3 STi glue driver private structure
  24. * @syscfg_base: addr for the glue syscfg
  25. * @glue_base: addr for the glue registers
  26. * @syscfg_offset: usb syscfg control offset
  27. * @powerdown_ctl: rest controller for powerdown signal
  28. * @softreset_ctl: reset controller for softreset signal
  29. * @mode: drd static host/device config
  30. */
  31. struct sti_dwc3_glue_plat {
  32. phys_addr_t syscfg_base;
  33. phys_addr_t glue_base;
  34. phys_addr_t syscfg_offset;
  35. struct reset_ctl powerdown_ctl;
  36. struct reset_ctl softreset_ctl;
  37. enum usb_dr_mode mode;
  38. };
  39. static int sti_dwc3_glue_drd_init(struct sti_dwc3_glue_plat *plat)
  40. {
  41. unsigned long val;
  42. val = readl(plat->syscfg_base + plat->syscfg_offset);
  43. val &= USB3_CONTROL_MASK;
  44. switch (plat->mode) {
  45. case USB_DR_MODE_PERIPHERAL:
  46. val &= ~(USB3_DELAY_VBUSVALID
  47. | USB3_SEL_FORCE_OPMODE | USB3_FORCE_OPMODE(0x3)
  48. | USB3_SEL_FORCE_DPPULLDOWN2 | USB3_FORCE_DPPULLDOWN2
  49. | USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2);
  50. val |= USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID;
  51. break;
  52. case USB_DR_MODE_HOST:
  53. val &= ~(USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID
  54. | USB3_SEL_FORCE_OPMODE | USB3_FORCE_OPMODE(0x3)
  55. | USB3_SEL_FORCE_DPPULLDOWN2 | USB3_FORCE_DPPULLDOWN2
  56. | USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2);
  57. val |= USB3_DELAY_VBUSVALID;
  58. break;
  59. default:
  60. pr_err("Unsupported mode of operation %d\n", plat->mode);
  61. return -EINVAL;
  62. }
  63. writel(val, plat->syscfg_base + plat->syscfg_offset);
  64. return 0;
  65. }
  66. static void sti_dwc3_glue_init(struct sti_dwc3_glue_plat *plat)
  67. {
  68. unsigned long reg;
  69. reg = readl(plat->glue_base + CLKRST_CTRL);
  70. reg |= AUX_CLK_EN | EXT_CFG_RESET_N | XHCI_REVISION;
  71. reg &= ~SW_PIPEW_RESET_N;
  72. writel(reg, plat->glue_base + CLKRST_CTRL);
  73. /* configure mux for vbus, powerpresent and bvalid signals */
  74. reg = readl(plat->glue_base + USB2_VBUS_MNGMNT_SEL1);
  75. reg |= SEL_OVERRIDE_VBUSVALID(USB2_VBUS_UTMIOTG) |
  76. SEL_OVERRIDE_POWERPRESENT(USB2_VBUS_UTMIOTG) |
  77. SEL_OVERRIDE_BVALID(USB2_VBUS_UTMIOTG);
  78. writel(reg, plat->glue_base + USB2_VBUS_MNGMNT_SEL1);
  79. setbits_le32(plat->glue_base + CLKRST_CTRL, SW_PIPEW_RESET_N);
  80. }
  81. static int sti_dwc3_glue_of_to_plat(struct udevice *dev)
  82. {
  83. struct sti_dwc3_glue_plat *plat = dev_get_plat(dev);
  84. struct udevice *syscon;
  85. struct regmap *regmap;
  86. int ret;
  87. u32 reg[4];
  88. ret = ofnode_read_u32_array(dev_ofnode(dev), "reg", reg,
  89. ARRAY_SIZE(reg));
  90. if (ret) {
  91. pr_err("unable to find st,stih407-dwc3 reg property(%d)\n", ret);
  92. return ret;
  93. }
  94. plat->glue_base = reg[0];
  95. plat->syscfg_offset = reg[2];
  96. /* get corresponding syscon phandle */
  97. ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "st,syscfg",
  98. &syscon);
  99. if (ret) {
  100. pr_err("unable to find syscon device (%d)\n", ret);
  101. return ret;
  102. }
  103. /* get syscfg-reg base address */
  104. regmap = syscon_get_regmap(syscon);
  105. if (!regmap) {
  106. pr_err("unable to find regmap\n");
  107. return -ENODEV;
  108. }
  109. plat->syscfg_base = regmap->ranges[0].start;
  110. /* get powerdown reset */
  111. ret = reset_get_by_name(dev, "powerdown", &plat->powerdown_ctl);
  112. if (ret) {
  113. pr_err("can't get powerdown reset for %s (%d)", dev->name, ret);
  114. return ret;
  115. }
  116. /* get softreset reset */
  117. ret = reset_get_by_name(dev, "softreset", &plat->softreset_ctl);
  118. if (ret)
  119. pr_err("can't get soft reset for %s (%d)", dev->name, ret);
  120. return ret;
  121. };
  122. static int sti_dwc3_glue_bind(struct udevice *dev)
  123. {
  124. struct sti_dwc3_glue_plat *plat = dev_get_plat(dev);
  125. ofnode node, dwc3_node;
  126. /* Find snps,dwc3 node from subnode */
  127. ofnode_for_each_subnode(node, dev_ofnode(dev)) {
  128. if (ofnode_device_is_compatible(node, "snps,dwc3"))
  129. dwc3_node = node;
  130. }
  131. if (!ofnode_valid(dwc3_node)) {
  132. pr_err("Can't find dwc3 subnode for %s\n", dev->name);
  133. return -ENODEV;
  134. }
  135. /* retrieve the DWC3 dual role mode */
  136. plat->mode = usb_get_dr_mode(dwc3_node);
  137. if (plat->mode == USB_DR_MODE_UNKNOWN)
  138. /* by default set dual role mode to HOST */
  139. plat->mode = USB_DR_MODE_HOST;
  140. return dm_scan_fdt_dev(dev);
  141. }
  142. static int sti_dwc3_glue_probe(struct udevice *dev)
  143. {
  144. struct sti_dwc3_glue_plat *plat = dev_get_plat(dev);
  145. int ret;
  146. /* deassert both powerdown and softreset */
  147. ret = reset_deassert(&plat->powerdown_ctl);
  148. if (ret < 0) {
  149. pr_err("DWC3 powerdown reset deassert failed: %d", ret);
  150. return ret;
  151. }
  152. ret = reset_deassert(&plat->softreset_ctl);
  153. if (ret < 0) {
  154. pr_err("DWC3 soft reset deassert failed: %d", ret);
  155. goto softreset_err;
  156. }
  157. ret = sti_dwc3_glue_drd_init(plat);
  158. if (ret)
  159. goto init_err;
  160. sti_dwc3_glue_init(plat);
  161. return 0;
  162. init_err:
  163. ret = reset_assert(&plat->softreset_ctl);
  164. if (ret < 0) {
  165. pr_err("DWC3 soft reset deassert failed: %d", ret);
  166. return ret;
  167. }
  168. softreset_err:
  169. ret = reset_assert(&plat->powerdown_ctl);
  170. if (ret < 0)
  171. pr_err("DWC3 powerdown reset deassert failed: %d", ret);
  172. return ret;
  173. }
  174. static int sti_dwc3_glue_remove(struct udevice *dev)
  175. {
  176. struct sti_dwc3_glue_plat *plat = dev_get_plat(dev);
  177. int ret;
  178. /* assert both powerdown and softreset */
  179. ret = reset_assert(&plat->powerdown_ctl);
  180. if (ret < 0) {
  181. pr_err("DWC3 powerdown reset deassert failed: %d", ret);
  182. return ret;
  183. }
  184. ret = reset_assert(&plat->softreset_ctl);
  185. if (ret < 0)
  186. pr_err("DWC3 soft reset deassert failed: %d", ret);
  187. return ret;
  188. }
  189. static const struct udevice_id sti_dwc3_glue_ids[] = {
  190. { .compatible = "st,stih407-dwc3" },
  191. { }
  192. };
  193. U_BOOT_DRIVER(dwc3_sti_glue) = {
  194. .name = "dwc3_sti_glue",
  195. .id = UCLASS_NOP,
  196. .of_match = sti_dwc3_glue_ids,
  197. .of_to_plat = sti_dwc3_glue_of_to_plat,
  198. .probe = sti_dwc3_glue_probe,
  199. .remove = sti_dwc3_glue_remove,
  200. .bind = sti_dwc3_glue_bind,
  201. .plat_auto = sizeof(struct sti_dwc3_glue_plat),
  202. .flags = DM_FLAG_ALLOC_PRIV_DMA,
  203. };