omap2430.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2005-2007 by Texas Instruments
  4. * Some code has been taken from tusb6010.c
  5. * Copyrights for that are attributable to:
  6. * Copyright (C) 2006 Nokia Corporation
  7. * Tony Lindgren <tony@atomide.com>
  8. *
  9. * This file is part of the Inventra Controller Driver for Linux.
  10. */
  11. #include <common.h>
  12. #include <dm.h>
  13. #include <log.h>
  14. #include <serial.h>
  15. #include <dm/device-internal.h>
  16. #include <dm/device_compat.h>
  17. #include <dm/lists.h>
  18. #include <linux/err.h>
  19. #include <linux/usb/otg.h>
  20. #include <asm/global_data.h>
  21. #include <asm/omap_common.h>
  22. #include <asm/omap_musb.h>
  23. #include <twl4030.h>
  24. #include <twl6030.h>
  25. #include "linux-compat.h"
  26. #include "musb_core.h"
  27. #include "omap2430.h"
  28. #include "musb_uboot.h"
  29. static inline void omap2430_low_level_exit(struct musb *musb)
  30. {
  31. u32 l;
  32. /* in any role */
  33. l = musb_readl(musb->mregs, OTG_FORCESTDBY);
  34. l |= ENABLEFORCE; /* enable MSTANDBY */
  35. musb_writel(musb->mregs, OTG_FORCESTDBY, l);
  36. }
  37. static inline void omap2430_low_level_init(struct musb *musb)
  38. {
  39. u32 l;
  40. l = musb_readl(musb->mregs, OTG_FORCESTDBY);
  41. l &= ~ENABLEFORCE; /* disable MSTANDBY */
  42. musb_writel(musb->mregs, OTG_FORCESTDBY, l);
  43. }
  44. #ifdef CONFIG_DM_USB_GADGET
  45. int dm_usb_gadget_handle_interrupts(struct udevice *dev)
  46. {
  47. struct musb_host_data *host = dev_get_priv(dev);
  48. host->host->isr(0, host->host);
  49. return 0;
  50. }
  51. #endif
  52. static int omap2430_musb_init(struct musb *musb)
  53. {
  54. u32 l;
  55. int status = 0;
  56. unsigned long int start;
  57. struct omap_musb_board_data *data =
  58. (struct omap_musb_board_data *)musb->controller;
  59. /* Reset the controller */
  60. musb_writel(musb->mregs, OTG_SYSCONFIG, SOFTRST);
  61. start = get_timer(0);
  62. while (1) {
  63. l = musb_readl(musb->mregs, OTG_SYSCONFIG);
  64. if ((l & SOFTRST) == 0)
  65. break;
  66. if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
  67. dev_err(musb->controller, "MUSB reset is taking too long\n");
  68. return -ENODEV;
  69. }
  70. }
  71. l = musb_readl(musb->mregs, OTG_INTERFSEL);
  72. if (data->interface_type == MUSB_INTERFACE_UTMI) {
  73. /* OMAP4 uses Internal PHY GS70 which uses UTMI interface */
  74. l &= ~ULPI_12PIN; /* Disable ULPI */
  75. l |= UTMI_8BIT; /* Enable UTMI */
  76. } else {
  77. l |= ULPI_12PIN;
  78. }
  79. musb_writel(musb->mregs, OTG_INTERFSEL, l);
  80. pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
  81. "sysstatus 0x%x, intrfsel 0x%x, simenable 0x%x\n",
  82. musb_readl(musb->mregs, OTG_REVISION),
  83. musb_readl(musb->mregs, OTG_SYSCONFIG),
  84. musb_readl(musb->mregs, OTG_SYSSTATUS),
  85. musb_readl(musb->mregs, OTG_INTERFSEL),
  86. musb_readl(musb->mregs, OTG_SIMENABLE));
  87. return 0;
  88. err1:
  89. return status;
  90. }
  91. static int omap2430_musb_enable(struct musb *musb)
  92. {
  93. #ifdef CONFIG_TWL4030_USB
  94. if (twl4030_usb_ulpi_init()) {
  95. serial_printf("ERROR: %s Could not initialize PHY\n",
  96. __PRETTY_FUNCTION__);
  97. }
  98. #endif
  99. #ifdef CONFIG_TWL6030_POWER
  100. twl6030_usb_device_settings();
  101. #endif
  102. #ifdef CONFIG_OMAP44XX
  103. u32 *usbotghs_control = (u32 *)((*ctrl)->control_usbotghs_ctrl);
  104. *usbotghs_control = USBOTGHS_CONTROL_AVALID |
  105. USBOTGHS_CONTROL_VBUSVALID | USBOTGHS_CONTROL_IDDIG;
  106. #endif
  107. return 0;
  108. }
  109. static void omap2430_musb_disable(struct musb *musb)
  110. {
  111. }
  112. static int omap2430_musb_exit(struct musb *musb)
  113. {
  114. del_timer_sync(&musb_idle_timer);
  115. omap2430_low_level_exit(musb);
  116. return 0;
  117. }
  118. const struct musb_platform_ops omap2430_ops = {
  119. .init = omap2430_musb_init,
  120. .exit = omap2430_musb_exit,
  121. .enable = omap2430_musb_enable,
  122. .disable = omap2430_musb_disable,
  123. };
  124. #if CONFIG_IS_ENABLED(DM_USB)
  125. struct omap2430_musb_plat {
  126. void *base;
  127. void *ctrl_mod_base;
  128. struct musb_hdrc_platform_data plat;
  129. struct musb_hdrc_config musb_config;
  130. struct omap_musb_board_data otg_board_data;
  131. };
  132. static int omap2430_musb_of_to_plat(struct udevice *dev)
  133. {
  134. struct omap2430_musb_plat *plat = dev_get_plat(dev);
  135. const void *fdt = gd->fdt_blob;
  136. int node = dev_of_offset(dev);
  137. plat->base = (void *)dev_read_addr_ptr(dev);
  138. plat->musb_config.multipoint = fdtdec_get_int(fdt, node, "multipoint",
  139. -1);
  140. if (plat->musb_config.multipoint < 0) {
  141. pr_err("MUSB multipoint DT entry missing\n");
  142. return -ENOENT;
  143. }
  144. plat->musb_config.dyn_fifo = 1;
  145. plat->musb_config.num_eps = fdtdec_get_int(fdt, node, "num-eps", -1);
  146. if (plat->musb_config.num_eps < 0) {
  147. pr_err("MUSB num-eps DT entry missing\n");
  148. return -ENOENT;
  149. }
  150. plat->musb_config.ram_bits = fdtdec_get_int(fdt, node, "ram-bits", -1);
  151. if (plat->musb_config.ram_bits < 0) {
  152. pr_err("MUSB ram-bits DT entry missing\n");
  153. return -ENOENT;
  154. }
  155. plat->plat.power = fdtdec_get_int(fdt, node, "power", -1);
  156. if (plat->plat.power < 0) {
  157. pr_err("MUSB power DT entry missing\n");
  158. return -ENOENT;
  159. }
  160. plat->otg_board_data.interface_type = fdtdec_get_int(fdt, node,
  161. "interface-type",
  162. -1);
  163. if (plat->otg_board_data.interface_type < 0) {
  164. pr_err("MUSB interface-type DT entry missing\n");
  165. return -ENOENT;
  166. }
  167. #if 0 /* In a perfect world, mode would be set to OTG, mode 3 from DT */
  168. plat->plat.mode = fdtdec_get_int(fdt, node, "mode", -1);
  169. if (plat->plat.mode < 0) {
  170. pr_err("MUSB mode DT entry missing\n");
  171. return -ENOENT;
  172. }
  173. #else /* MUSB_OTG, it doesn't work */
  174. #ifdef CONFIG_USB_MUSB_HOST /* Host seems to be the only option that works */
  175. plat->plat.mode = MUSB_HOST;
  176. #else /* For that matter, MUSB_PERIPHERAL doesn't either */
  177. plat->plat.mode = MUSB_PERIPHERAL;
  178. #endif
  179. #endif
  180. plat->otg_board_data.dev = dev;
  181. plat->plat.config = &plat->musb_config;
  182. plat->plat.platform_ops = &omap2430_ops;
  183. plat->plat.board_data = &plat->otg_board_data;
  184. return 0;
  185. }
  186. static int omap2430_musb_probe(struct udevice *dev)
  187. {
  188. struct omap2430_musb_plat *plat = dev_get_plat(dev);
  189. struct omap_musb_board_data *otg_board_data;
  190. int ret = 0;
  191. void *base = dev_read_addr_ptr(dev);
  192. struct musb *musbp;
  193. otg_board_data = &plat->otg_board_data;
  194. if (IS_ENABLED(CONFIG_USB_MUSB_HOST)) {
  195. struct musb_host_data *host = dev_get_priv(dev);
  196. struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
  197. priv->desc_before_addr = true;
  198. host->host = musb_init_controller(&plat->plat,
  199. (struct device *)otg_board_data,
  200. plat->base);
  201. if (!host->host)
  202. return -EIO;
  203. return musb_lowlevel_init(host);
  204. } else if (CONFIG_IS_ENABLED(DM_USB_GADGET)) {
  205. struct musb_host_data *host = dev_get_priv(dev);
  206. host->host = musb_init_controller(&plat->plat,
  207. (struct device *)otg_board_data,
  208. plat->base);
  209. if (!host->host)
  210. return -EIO;
  211. return usb_add_gadget_udc((struct device *)otg_board_data, &host->host->g);
  212. }
  213. musbp = musb_register(&plat->plat, (struct device *)otg_board_data,
  214. plat->base);
  215. if (IS_ERR_OR_NULL(musbp))
  216. return -EINVAL;
  217. return 0;
  218. }
  219. static int omap2430_musb_remove(struct udevice *dev)
  220. {
  221. struct musb_host_data *host = dev_get_priv(dev);
  222. musb_stop(host->host);
  223. return 0;
  224. }
  225. static const struct udevice_id omap2430_musb_ids[] = {
  226. { .compatible = "ti,omap3-musb" },
  227. { .compatible = "ti,omap4-musb" },
  228. { }
  229. };
  230. U_BOOT_DRIVER(omap2430_musb) = {
  231. .name = "omap2430-musb",
  232. #ifdef CONFIG_USB_MUSB_HOST
  233. .id = UCLASS_USB,
  234. #else
  235. .id = UCLASS_USB_GADGET_GENERIC,
  236. #endif
  237. .of_match = omap2430_musb_ids,
  238. .of_to_plat = omap2430_musb_of_to_plat,
  239. .probe = omap2430_musb_probe,
  240. .remove = omap2430_musb_remove,
  241. #ifdef CONFIG_USB_MUSB_HOST
  242. .ops = &musb_usb_ops,
  243. #endif
  244. .plat_auto = sizeof(struct omap2430_musb_plat),
  245. .priv_auto = sizeof(struct musb_host_data),
  246. };
  247. #endif /* CONFIG_IS_ENABLED(DM_USB) */