1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * UniPhier Specific Glue Layer for DWC3
4  *
5  * Copyright (C) 2016-2017 Socionext Inc.
6  *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
7  */
8 
9 #include <dm.h>
10 #include <linux/bitops.h>
11 #include <linux/errno.h>
12 #include <linux/io.h>
13 #include <linux/sizes.h>
14 
15 #define UNIPHIER_PRO4_DWC3_RESET	0x40
16 #define   UNIPHIER_PRO4_DWC3_RESET_XIOMMU	BIT(5)
17 #define   UNIPHIER_PRO4_DWC3_RESET_XLINK	BIT(4)
18 #define   UNIPHIER_PRO4_DWC3_RESET_PHY_SS	BIT(2)
19 
20 #define UNIPHIER_PRO5_DWC3_RESET	0x00
21 #define   UNIPHIER_PRO5_DWC3_RESET_PHY_S1	BIT(17)
22 #define   UNIPHIER_PRO5_DWC3_RESET_PHY_S0	BIT(16)
23 #define   UNIPHIER_PRO5_DWC3_RESET_XLINK	BIT(15)
24 #define   UNIPHIER_PRO5_DWC3_RESET_XIOMMU	BIT(14)
25 
26 #define UNIPHIER_PXS2_DWC3_RESET	0x00
27 #define   UNIPHIER_PXS2_DWC3_RESET_XLINK	BIT(15)
28 
29 static int uniphier_pro4_dwc3_init(void __iomem *regs)
30 {
31 	u32 tmp;
32 
33 	tmp = readl(regs + UNIPHIER_PRO4_DWC3_RESET);
34 	tmp &= ~UNIPHIER_PRO4_DWC3_RESET_PHY_SS;
35 	tmp |= UNIPHIER_PRO4_DWC3_RESET_XIOMMU | UNIPHIER_PRO4_DWC3_RESET_XLINK;
36 	writel(tmp, regs + UNIPHIER_PRO4_DWC3_RESET);
37 
38 	return 0;
39 }
40 
41 static int uniphier_pro5_dwc3_init(void __iomem *regs)
42 {
43 	u32 tmp;
44 
45 	tmp = readl(regs + UNIPHIER_PRO5_DWC3_RESET);
46 	tmp &= ~(UNIPHIER_PRO5_DWC3_RESET_PHY_S1 |
47 		 UNIPHIER_PRO5_DWC3_RESET_PHY_S0);
48 	tmp |= UNIPHIER_PRO5_DWC3_RESET_XLINK | UNIPHIER_PRO5_DWC3_RESET_XIOMMU;
49 	writel(tmp, regs + UNIPHIER_PRO5_DWC3_RESET);
50 
51 	return 0;
52 }
53 
54 static int uniphier_pxs2_dwc3_init(void __iomem *regs)
55 {
56 	u32 tmp;
57 
58 	tmp = readl(regs + UNIPHIER_PXS2_DWC3_RESET);
59 	tmp |= UNIPHIER_PXS2_DWC3_RESET_XLINK;
60 	writel(tmp, regs + UNIPHIER_PXS2_DWC3_RESET);
61 
62 	return 0;
63 }
64 
65 static int uniphier_dwc3_probe(struct udevice *dev)
66 {
67 	fdt_addr_t base;
68 	void __iomem *regs;
69 	int (*init)(void __iomem *regs);
70 	int ret;
71 
72 	base = devfdt_get_addr(dev);
73 	if (base == FDT_ADDR_T_NONE)
74 		return -EINVAL;
75 
76 	regs = ioremap(base, SZ_32K);
77 	if (!regs)
78 		return -ENOMEM;
79 
80 	init = (typeof(init))dev_get_driver_data(dev);
81 	ret = init(regs);
82 	if (ret)
83 		dev_err(dev, "failed to init glue layer\n");
84 
85 	iounmap(regs);
86 
87 	return ret;
88 }
89 
90 static const struct udevice_id uniphier_dwc3_match[] = {
91 	{
92 		.compatible = "socionext,uniphier-pro4-dwc3",
93 		.data = (ulong)uniphier_pro4_dwc3_init,
94 	},
95 	{
96 		.compatible = "socionext,uniphier-pro5-dwc3",
97 		.data = (ulong)uniphier_pro5_dwc3_init,
98 	},
99 	{
100 		.compatible = "socionext,uniphier-pxs2-dwc3",
101 		.data = (ulong)uniphier_pxs2_dwc3_init,
102 	},
103 	{
104 		.compatible = "socionext,uniphier-ld20-dwc3",
105 		.data = (ulong)uniphier_pxs2_dwc3_init,
106 	},
107 	{
108 		.compatible = "socionext,uniphier-pxs3-dwc3",
109 		.data = (ulong)uniphier_pxs2_dwc3_init,
110 	},
111 	{ /* sentinel */ }
112 };
113 
114 U_BOOT_DRIVER(usb_xhci) = {
115 	.name = "uniphier-dwc3",
116 	.id = UCLASS_SIMPLE_BUS,
117 	.of_match = uniphier_dwc3_match,
118 	.probe = uniphier_dwc3_probe,
119 };
120