phy-sun4i-usb.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. /*
  2. * Allwinner sun4i USB PHY driver
  3. *
  4. * Copyright (C) 2017 Jagan Teki <jagan@amarulasolutions.com>
  5. * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com>
  6. * Copyright (C) 2014 Roman Byshko <rbyshko@gmail.com>
  7. *
  8. * Modelled arch/arm/mach-sunxi/usb_phy.c to compatible with generic-phy.
  9. *
  10. * SPDX-License-Identifier: GPL-2.0+
  11. */
  12. #include <common.h>
  13. #include <clk.h>
  14. #include <dm.h>
  15. #include <log.h>
  16. #include <dm/device.h>
  17. #include <generic-phy.h>
  18. #include <phy-sun4i-usb.h>
  19. #include <reset.h>
  20. #include <asm/gpio.h>
  21. #include <asm/io.h>
  22. #include <asm/arch/clock.h>
  23. #include <asm/arch/cpu.h>
  24. #include <dm/device_compat.h>
  25. #include <linux/bitops.h>
  26. #include <linux/delay.h>
  27. #include <linux/err.h>
  28. #define REG_ISCR 0x00
  29. #define REG_PHYCTL_A10 0x04
  30. #define REG_PHYBIST 0x08
  31. #define REG_PHYTUNE 0x0c
  32. #define REG_PHYCTL_A33 0x10
  33. #define REG_PHY_OTGCTL 0x20
  34. #define REG_PMU_UNK1 0x10
  35. /* Common Control Bits for Both PHYs */
  36. #define PHY_PLL_BW 0x03
  37. #define PHY_RES45_CAL_EN 0x0c
  38. /* Private Control Bits for Each PHY */
  39. #define PHY_TX_AMPLITUDE_TUNE 0x20
  40. #define PHY_TX_SLEWRATE_TUNE 0x22
  41. #define PHY_DISCON_TH_SEL 0x2a
  42. #define PHY_SQUELCH_DETECT 0x3c
  43. #define PHYCTL_DATA BIT(7)
  44. #define OTGCTL_ROUTE_MUSB BIT(0)
  45. #define PHY_TX_RATE BIT(4)
  46. #define PHY_TX_MAGNITUDE BIT(2)
  47. #define PHY_TX_AMPLITUDE_LEN 5
  48. #define PHY_RES45_CAL_DATA BIT(0)
  49. #define PHY_RES45_CAL_LEN 1
  50. #define PHY_DISCON_TH_LEN 2
  51. #define SUNXI_AHB_ICHR8_EN BIT(10)
  52. #define SUNXI_AHB_INCR4_BURST_EN BIT(9)
  53. #define SUNXI_AHB_INCRX_ALIGN_EN BIT(8)
  54. #define SUNXI_ULPI_BYPASS_EN BIT(0)
  55. /* A83T specific control bits for PHY0 */
  56. #define PHY_CTL_VBUSVLDEXT BIT(5)
  57. #define PHY_CTL_SIDDQ BIT(3)
  58. /* A83T specific control bits for PHY2 HSIC */
  59. #define SUNXI_EHCI_HS_FORCE BIT(20)
  60. #define SUNXI_HSIC_CONNECT_INT BIT(16)
  61. #define SUNXI_HSIC BIT(1)
  62. #define MAX_PHYS 4
  63. enum sun4i_usb_phy_type {
  64. sun4i_a10_phy,
  65. sun6i_a31_phy,
  66. sun8i_a33_phy,
  67. sun8i_a83t_phy,
  68. sun8i_h3_phy,
  69. sun8i_r40_phy,
  70. sun8i_v3s_phy,
  71. sun50i_a64_phy,
  72. sun50i_h6_phy,
  73. };
  74. struct sun4i_usb_phy_cfg {
  75. int num_phys;
  76. enum sun4i_usb_phy_type type;
  77. u32 disc_thresh;
  78. u8 phyctl_offset;
  79. bool dedicated_clocks;
  80. bool enable_pmu_unk1;
  81. bool phy0_dual_route;
  82. int missing_phys;
  83. };
  84. struct sun4i_usb_phy_info {
  85. const char *gpio_vbus;
  86. const char *gpio_vbus_det;
  87. const char *gpio_id_det;
  88. } phy_info[] = {
  89. {
  90. .gpio_vbus = CONFIG_USB0_VBUS_PIN,
  91. .gpio_vbus_det = CONFIG_USB0_VBUS_DET,
  92. .gpio_id_det = CONFIG_USB0_ID_DET,
  93. },
  94. {
  95. .gpio_vbus = CONFIG_USB1_VBUS_PIN,
  96. .gpio_vbus_det = NULL,
  97. .gpio_id_det = NULL,
  98. },
  99. {
  100. .gpio_vbus = CONFIG_USB2_VBUS_PIN,
  101. .gpio_vbus_det = NULL,
  102. .gpio_id_det = NULL,
  103. },
  104. {
  105. .gpio_vbus = CONFIG_USB3_VBUS_PIN,
  106. .gpio_vbus_det = NULL,
  107. .gpio_id_det = NULL,
  108. },
  109. };
  110. struct sun4i_usb_phy_plat {
  111. void __iomem *pmu;
  112. int power_on_count;
  113. int gpio_vbus;
  114. int gpio_vbus_det;
  115. int gpio_id_det;
  116. struct clk clocks;
  117. struct reset_ctl resets;
  118. int id;
  119. };
  120. struct sun4i_usb_phy_data {
  121. void __iomem *base;
  122. const struct sun4i_usb_phy_cfg *cfg;
  123. struct sun4i_usb_phy_plat *usb_phy;
  124. };
  125. static int initial_usb_scan_delay = CONFIG_INITIAL_USB_SCAN_DELAY;
  126. static void sun4i_usb_phy_write(struct phy *phy, u32 addr, u32 data, int len)
  127. {
  128. struct sun4i_usb_phy_data *phy_data = dev_get_priv(phy->dev);
  129. struct sun4i_usb_phy_plat *usb_phy = &phy_data->usb_phy[phy->id];
  130. u32 temp, usbc_bit = BIT(usb_phy->id * 2);
  131. void __iomem *phyctl = phy_data->base + phy_data->cfg->phyctl_offset;
  132. int i;
  133. if (phy_data->cfg->phyctl_offset == REG_PHYCTL_A33) {
  134. /* SoCs newer than A33 need us to set phyctl to 0 explicitly */
  135. writel(0, phyctl);
  136. }
  137. for (i = 0; i < len; i++) {
  138. temp = readl(phyctl);
  139. /* clear the address portion */
  140. temp &= ~(0xff << 8);
  141. /* set the address */
  142. temp |= ((addr + i) << 8);
  143. writel(temp, phyctl);
  144. /* set the data bit and clear usbc bit*/
  145. temp = readb(phyctl);
  146. if (data & 0x1)
  147. temp |= PHYCTL_DATA;
  148. else
  149. temp &= ~PHYCTL_DATA;
  150. temp &= ~usbc_bit;
  151. writeb(temp, phyctl);
  152. /* pulse usbc_bit */
  153. temp = readb(phyctl);
  154. temp |= usbc_bit;
  155. writeb(temp, phyctl);
  156. temp = readb(phyctl);
  157. temp &= ~usbc_bit;
  158. writeb(temp, phyctl);
  159. data >>= 1;
  160. }
  161. }
  162. static void sun4i_usb_phy_passby(struct phy *phy, bool enable)
  163. {
  164. struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
  165. struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
  166. u32 bits, reg_value;
  167. if (!usb_phy->pmu)
  168. return;
  169. bits = SUNXI_AHB_ICHR8_EN | SUNXI_AHB_INCR4_BURST_EN |
  170. SUNXI_AHB_INCRX_ALIGN_EN | SUNXI_ULPI_BYPASS_EN;
  171. /* A83T USB2 is HSIC */
  172. if (data->cfg->type == sun8i_a83t_phy && usb_phy->id == 2)
  173. bits |= SUNXI_EHCI_HS_FORCE | SUNXI_HSIC_CONNECT_INT |
  174. SUNXI_HSIC;
  175. reg_value = readl(usb_phy->pmu);
  176. if (enable)
  177. reg_value |= bits;
  178. else
  179. reg_value &= ~bits;
  180. writel(reg_value, usb_phy->pmu);
  181. }
  182. static int sun4i_usb_phy_power_on(struct phy *phy)
  183. {
  184. struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
  185. struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
  186. if (initial_usb_scan_delay) {
  187. mdelay(initial_usb_scan_delay);
  188. initial_usb_scan_delay = 0;
  189. }
  190. usb_phy->power_on_count++;
  191. if (usb_phy->power_on_count != 1)
  192. return 0;
  193. if (usb_phy->gpio_vbus >= 0)
  194. gpio_set_value(usb_phy->gpio_vbus, SUNXI_GPIO_PULL_UP);
  195. return 0;
  196. }
  197. static int sun4i_usb_phy_power_off(struct phy *phy)
  198. {
  199. struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
  200. struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
  201. usb_phy->power_on_count--;
  202. if (usb_phy->power_on_count != 0)
  203. return 0;
  204. if (usb_phy->gpio_vbus >= 0)
  205. gpio_set_value(usb_phy->gpio_vbus, SUNXI_GPIO_PULL_DISABLE);
  206. return 0;
  207. }
  208. static void sun4i_usb_phy0_reroute(struct sun4i_usb_phy_data *data, bool id_det)
  209. {
  210. u32 regval;
  211. regval = readl(data->base + REG_PHY_OTGCTL);
  212. if (!id_det) {
  213. /* Host mode. Route phy0 to EHCI/OHCI */
  214. regval &= ~OTGCTL_ROUTE_MUSB;
  215. } else {
  216. /* Peripheral mode. Route phy0 to MUSB */
  217. regval |= OTGCTL_ROUTE_MUSB;
  218. }
  219. writel(regval, data->base + REG_PHY_OTGCTL);
  220. }
  221. static int sun4i_usb_phy_init(struct phy *phy)
  222. {
  223. struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
  224. struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
  225. u32 val;
  226. int ret;
  227. ret = clk_enable(&usb_phy->clocks);
  228. if (ret) {
  229. dev_err(phy->dev, "failed to enable usb_%ldphy clock\n",
  230. phy->id);
  231. return ret;
  232. }
  233. ret = reset_deassert(&usb_phy->resets);
  234. if (ret) {
  235. dev_err(phy->dev, "failed to deassert usb_%ldreset reset\n",
  236. phy->id);
  237. return ret;
  238. }
  239. if (data->cfg->type == sun8i_a83t_phy ||
  240. data->cfg->type == sun50i_h6_phy) {
  241. if (phy->id == 0) {
  242. val = readl(data->base + data->cfg->phyctl_offset);
  243. val |= PHY_CTL_VBUSVLDEXT;
  244. val &= ~PHY_CTL_SIDDQ;
  245. writel(val, data->base + data->cfg->phyctl_offset);
  246. }
  247. } else {
  248. if (usb_phy->pmu && data->cfg->enable_pmu_unk1) {
  249. val = readl(usb_phy->pmu + REG_PMU_UNK1);
  250. writel(val & ~2, usb_phy->pmu + REG_PMU_UNK1);
  251. }
  252. if (usb_phy->id == 0)
  253. sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN,
  254. PHY_RES45_CAL_DATA,
  255. PHY_RES45_CAL_LEN);
  256. /* Adjust PHY's magnitude and rate */
  257. sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE,
  258. PHY_TX_MAGNITUDE | PHY_TX_RATE,
  259. PHY_TX_AMPLITUDE_LEN);
  260. /* Disconnect threshold adjustment */
  261. sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL,
  262. data->cfg->disc_thresh, PHY_DISCON_TH_LEN);
  263. }
  264. sun4i_usb_phy_passby(phy, true);
  265. sun4i_usb_phy0_reroute(data, true);
  266. return 0;
  267. }
  268. static int sun4i_usb_phy_exit(struct phy *phy)
  269. {
  270. struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
  271. struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
  272. int ret;
  273. if (phy->id == 0) {
  274. if (data->cfg->type == sun8i_a83t_phy ||
  275. data->cfg->type == sun50i_h6_phy) {
  276. void __iomem *phyctl = data->base +
  277. data->cfg->phyctl_offset;
  278. writel(readl(phyctl) | PHY_CTL_SIDDQ, phyctl);
  279. }
  280. }
  281. sun4i_usb_phy_passby(phy, false);
  282. ret = clk_disable(&usb_phy->clocks);
  283. if (ret) {
  284. dev_err(phy->dev, "failed to disable usb_%ldphy clock\n",
  285. phy->id);
  286. return ret;
  287. }
  288. ret = reset_assert(&usb_phy->resets);
  289. if (ret) {
  290. dev_err(phy->dev, "failed to assert usb_%ldreset reset\n",
  291. phy->id);
  292. return ret;
  293. }
  294. return 0;
  295. }
  296. static int sun4i_usb_phy_xlate(struct phy *phy,
  297. struct ofnode_phandle_args *args)
  298. {
  299. struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
  300. if (args->args_count >= data->cfg->num_phys)
  301. return -EINVAL;
  302. if (data->cfg->missing_phys & BIT(args->args[0]))
  303. return -ENODEV;
  304. if (args->args_count)
  305. phy->id = args->args[0];
  306. else
  307. phy->id = 0;
  308. debug("%s: phy_id = %ld\n", __func__, phy->id);
  309. return 0;
  310. }
  311. int sun4i_usb_phy_vbus_detect(struct phy *phy)
  312. {
  313. struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
  314. struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
  315. int err, retries = 3;
  316. debug("%s: id_det = %d\n", __func__, usb_phy->gpio_id_det);
  317. if (usb_phy->gpio_vbus_det < 0)
  318. return usb_phy->gpio_vbus_det;
  319. err = gpio_get_value(usb_phy->gpio_vbus_det);
  320. /*
  321. * Vbus may have been provided by the board and just been turned of
  322. * some milliseconds ago on reset, what we're measuring then is a
  323. * residual charge on Vbus, sleep a bit and try again.
  324. */
  325. while (err > 0 && retries--) {
  326. mdelay(100);
  327. err = gpio_get_value(usb_phy->gpio_vbus_det);
  328. }
  329. return err;
  330. }
  331. int sun4i_usb_phy_id_detect(struct phy *phy)
  332. {
  333. struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
  334. struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
  335. debug("%s: id_det = %d\n", __func__, usb_phy->gpio_id_det);
  336. if (usb_phy->gpio_id_det < 0)
  337. return usb_phy->gpio_id_det;
  338. return gpio_get_value(usb_phy->gpio_id_det);
  339. }
  340. void sun4i_usb_phy_set_squelch_detect(struct phy *phy, bool enabled)
  341. {
  342. sun4i_usb_phy_write(phy, PHY_SQUELCH_DETECT, enabled ? 0 : 2, 2);
  343. }
  344. static struct phy_ops sun4i_usb_phy_ops = {
  345. .of_xlate = sun4i_usb_phy_xlate,
  346. .init = sun4i_usb_phy_init,
  347. .power_on = sun4i_usb_phy_power_on,
  348. .power_off = sun4i_usb_phy_power_off,
  349. .exit = sun4i_usb_phy_exit,
  350. };
  351. static int sun4i_usb_phy_probe(struct udevice *dev)
  352. {
  353. struct sun4i_usb_phy_plat *plat = dev_get_platdata(dev);
  354. struct sun4i_usb_phy_data *data = dev_get_priv(dev);
  355. int i, ret;
  356. data->cfg = (const struct sun4i_usb_phy_cfg *)dev_get_driver_data(dev);
  357. if (!data->cfg)
  358. return -EINVAL;
  359. data->base = (void __iomem *)devfdt_get_addr_name(dev, "phy_ctrl");
  360. if (IS_ERR(data->base))
  361. return PTR_ERR(data->base);
  362. data->usb_phy = plat;
  363. for (i = 0; i < data->cfg->num_phys; i++) {
  364. struct sun4i_usb_phy_plat *phy = &plat[i];
  365. struct sun4i_usb_phy_info *info = &phy_info[i];
  366. char name[16];
  367. if (data->cfg->missing_phys & BIT(i))
  368. continue;
  369. phy->gpio_vbus = sunxi_name_to_gpio(info->gpio_vbus);
  370. if (phy->gpio_vbus >= 0) {
  371. ret = gpio_request(phy->gpio_vbus, "usb_vbus");
  372. if (ret)
  373. return ret;
  374. ret = gpio_direction_output(phy->gpio_vbus, 0);
  375. if (ret)
  376. return ret;
  377. }
  378. phy->gpio_vbus_det = sunxi_name_to_gpio(info->gpio_vbus_det);
  379. if (phy->gpio_vbus_det >= 0) {
  380. ret = gpio_request(phy->gpio_vbus_det, "usb_vbus_det");
  381. if (ret)
  382. return ret;
  383. ret = gpio_direction_input(phy->gpio_vbus_det);
  384. if (ret)
  385. return ret;
  386. }
  387. phy->gpio_id_det = sunxi_name_to_gpio(info->gpio_id_det);
  388. if (phy->gpio_id_det >= 0) {
  389. ret = gpio_request(phy->gpio_id_det, "usb_id_det");
  390. if (ret)
  391. return ret;
  392. ret = gpio_direction_input(phy->gpio_id_det);
  393. if (ret)
  394. return ret;
  395. sunxi_gpio_set_pull(phy->gpio_id_det, SUNXI_GPIO_PULL_UP);
  396. }
  397. if (data->cfg->dedicated_clocks)
  398. snprintf(name, sizeof(name), "usb%d_phy", i);
  399. else
  400. strlcpy(name, "usb_phy", sizeof(name));
  401. ret = clk_get_by_name(dev, name, &phy->clocks);
  402. if (ret) {
  403. dev_err(dev, "failed to get usb%d_phy clock phandle\n", i);
  404. return ret;
  405. }
  406. snprintf(name, sizeof(name), "usb%d_reset", i);
  407. ret = reset_get_by_name(dev, name, &phy->resets);
  408. if (ret) {
  409. dev_err(dev, "failed to get usb%d_reset reset phandle\n", i);
  410. return ret;
  411. }
  412. if (i || data->cfg->phy0_dual_route) {
  413. snprintf(name, sizeof(name), "pmu%d", i);
  414. phy->pmu = (void __iomem *)devfdt_get_addr_name(dev, name);
  415. if (IS_ERR(phy->pmu))
  416. return PTR_ERR(phy->pmu);
  417. }
  418. phy->id = i;
  419. };
  420. debug("Allwinner Sun4I USB PHY driver loaded\n");
  421. return 0;
  422. }
  423. static const struct sun4i_usb_phy_cfg sun4i_a10_cfg = {
  424. .num_phys = 3,
  425. .type = sun4i_a10_phy,
  426. .disc_thresh = 3,
  427. .phyctl_offset = REG_PHYCTL_A10,
  428. .dedicated_clocks = false,
  429. .enable_pmu_unk1 = false,
  430. };
  431. static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = {
  432. .num_phys = 2,
  433. .type = sun4i_a10_phy,
  434. .disc_thresh = 2,
  435. .phyctl_offset = REG_PHYCTL_A10,
  436. .dedicated_clocks = false,
  437. .enable_pmu_unk1 = false,
  438. };
  439. static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = {
  440. .num_phys = 3,
  441. .type = sun6i_a31_phy,
  442. .disc_thresh = 3,
  443. .phyctl_offset = REG_PHYCTL_A10,
  444. .dedicated_clocks = true,
  445. .enable_pmu_unk1 = false,
  446. };
  447. static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = {
  448. .num_phys = 3,
  449. .type = sun4i_a10_phy,
  450. .disc_thresh = 2,
  451. .phyctl_offset = REG_PHYCTL_A10,
  452. .dedicated_clocks = false,
  453. .enable_pmu_unk1 = false,
  454. };
  455. static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = {
  456. .num_phys = 2,
  457. .type = sun4i_a10_phy,
  458. .disc_thresh = 3,
  459. .phyctl_offset = REG_PHYCTL_A10,
  460. .dedicated_clocks = true,
  461. .enable_pmu_unk1 = false,
  462. };
  463. static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = {
  464. .num_phys = 2,
  465. .type = sun8i_a33_phy,
  466. .disc_thresh = 3,
  467. .phyctl_offset = REG_PHYCTL_A33,
  468. .dedicated_clocks = true,
  469. .enable_pmu_unk1 = false,
  470. };
  471. static const struct sun4i_usb_phy_cfg sun8i_a83t_cfg = {
  472. .num_phys = 3,
  473. .type = sun8i_a83t_phy,
  474. .phyctl_offset = REG_PHYCTL_A33,
  475. .dedicated_clocks = true,
  476. };
  477. static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {
  478. .num_phys = 4,
  479. .type = sun8i_h3_phy,
  480. .disc_thresh = 3,
  481. .phyctl_offset = REG_PHYCTL_A33,
  482. .dedicated_clocks = true,
  483. .enable_pmu_unk1 = true,
  484. .phy0_dual_route = true,
  485. };
  486. static const struct sun4i_usb_phy_cfg sun8i_r40_cfg = {
  487. .num_phys = 3,
  488. .type = sun8i_r40_phy,
  489. .disc_thresh = 3,
  490. .phyctl_offset = REG_PHYCTL_A33,
  491. .dedicated_clocks = true,
  492. .enable_pmu_unk1 = true,
  493. .phy0_dual_route = true,
  494. };
  495. static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = {
  496. .num_phys = 1,
  497. .type = sun8i_v3s_phy,
  498. .disc_thresh = 3,
  499. .phyctl_offset = REG_PHYCTL_A33,
  500. .dedicated_clocks = true,
  501. .enable_pmu_unk1 = true,
  502. .phy0_dual_route = true,
  503. };
  504. static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = {
  505. .num_phys = 2,
  506. .type = sun50i_a64_phy,
  507. .disc_thresh = 3,
  508. .phyctl_offset = REG_PHYCTL_A33,
  509. .dedicated_clocks = true,
  510. .enable_pmu_unk1 = true,
  511. .phy0_dual_route = true,
  512. };
  513. static const struct sun4i_usb_phy_cfg sun50i_h6_cfg = {
  514. .num_phys = 4,
  515. .type = sun50i_h6_phy,
  516. .disc_thresh = 3,
  517. .phyctl_offset = REG_PHYCTL_A33,
  518. .dedicated_clocks = true,
  519. .enable_pmu_unk1 = true,
  520. .phy0_dual_route = true,
  521. .missing_phys = BIT(1) | BIT(2),
  522. };
  523. static const struct udevice_id sun4i_usb_phy_ids[] = {
  524. { .compatible = "allwinner,sun4i-a10-usb-phy", .data = (ulong)&sun4i_a10_cfg },
  525. { .compatible = "allwinner,sun5i-a13-usb-phy", .data = (ulong)&sun5i_a13_cfg },
  526. { .compatible = "allwinner,sun6i-a31-usb-phy", .data = (ulong)&sun6i_a31_cfg },
  527. { .compatible = "allwinner,sun7i-a20-usb-phy", .data = (ulong)&sun7i_a20_cfg },
  528. { .compatible = "allwinner,sun8i-a23-usb-phy", .data = (ulong)&sun8i_a23_cfg },
  529. { .compatible = "allwinner,sun8i-a33-usb-phy", .data = (ulong)&sun8i_a33_cfg },
  530. { .compatible = "allwinner,sun8i-a83t-usb-phy", .data = (ulong)&sun8i_a83t_cfg },
  531. { .compatible = "allwinner,sun8i-h3-usb-phy", .data = (ulong)&sun8i_h3_cfg },
  532. { .compatible = "allwinner,sun8i-r40-usb-phy", .data = (ulong)&sun8i_r40_cfg },
  533. { .compatible = "allwinner,sun8i-v3s-usb-phy", .data = (ulong)&sun8i_v3s_cfg },
  534. { .compatible = "allwinner,sun50i-a64-usb-phy", .data = (ulong)&sun50i_a64_cfg},
  535. { .compatible = "allwinner,sun50i-h6-usb-phy", .data = (ulong)&sun50i_h6_cfg},
  536. { }
  537. };
  538. U_BOOT_DRIVER(sun4i_usb_phy) = {
  539. .name = "sun4i_usb_phy",
  540. .id = UCLASS_PHY,
  541. .of_match = sun4i_usb_phy_ids,
  542. .ops = &sun4i_usb_phy_ops,
  543. .probe = sun4i_usb_phy_probe,
  544. .platdata_auto_alloc_size = sizeof(struct sun4i_usb_phy_plat[MAX_PHYS]),
  545. .priv_auto_alloc_size = sizeof(struct sun4i_usb_phy_data),
  546. };