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