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 *   Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
8 */
9
10#include <dm.h>
11#include <dm/lists.h>
12#include <linux/bitops.h>
13#include <linux/usb/gadget.h>
14
15#include "core.h"
16#include "gadget.h"
17#include "dwc3-generic.h"
18
19#define UNIPHIER_PRO4_DWC3_RESET	0x40
20#define   UNIPHIER_PRO4_DWC3_RESET_XIOMMU	BIT(5)
21#define   UNIPHIER_PRO4_DWC3_RESET_XLINK	BIT(4)
22#define   UNIPHIER_PRO4_DWC3_RESET_PHY_SS	BIT(2)
23
24#define UNIPHIER_PRO5_DWC3_RESET	0x00
25#define   UNIPHIER_PRO5_DWC3_RESET_PHY_S1	BIT(17)
26#define   UNIPHIER_PRO5_DWC3_RESET_PHY_S0	BIT(16)
27#define   UNIPHIER_PRO5_DWC3_RESET_XLINK	BIT(15)
28#define   UNIPHIER_PRO5_DWC3_RESET_XIOMMU	BIT(14)
29
30#define UNIPHIER_PXS2_DWC3_RESET	0x00
31#define   UNIPHIER_PXS2_DWC3_RESET_XLINK	BIT(15)
32
33static void uniphier_pro4_dwc3_init(struct udevice *dev, int index,
34				    enum usb_dr_mode mode)
35{
36	struct dwc3_glue_data *glue = dev_get_plat(dev);
37	void *regs = map_physmem(glue->regs, glue->size, MAP_NOCACHE);
38	u32 tmp;
39
40	tmp = readl(regs + UNIPHIER_PRO4_DWC3_RESET);
41	tmp &= ~UNIPHIER_PRO4_DWC3_RESET_PHY_SS;
42	tmp |= UNIPHIER_PRO4_DWC3_RESET_XIOMMU | UNIPHIER_PRO4_DWC3_RESET_XLINK;
43	writel(tmp, regs + UNIPHIER_PRO4_DWC3_RESET);
44
45	unmap_physmem(regs, MAP_NOCACHE);
46}
47
48static void uniphier_pro5_dwc3_init(struct udevice *dev, int index,
49				    enum usb_dr_mode mode)
50{
51	struct dwc3_glue_data *glue = dev_get_plat(dev);
52	void *regs = map_physmem(glue->regs, glue->size, MAP_NOCACHE);
53	u32 tmp;
54
55	tmp = readl(regs + UNIPHIER_PRO5_DWC3_RESET);
56	tmp &= ~(UNIPHIER_PRO5_DWC3_RESET_PHY_S1 |
57		 UNIPHIER_PRO5_DWC3_RESET_PHY_S0);
58	tmp |= UNIPHIER_PRO5_DWC3_RESET_XLINK | UNIPHIER_PRO5_DWC3_RESET_XIOMMU;
59	writel(tmp, regs + UNIPHIER_PRO5_DWC3_RESET);
60
61	unmap_physmem(regs, MAP_NOCACHE);
62}
63
64static void uniphier_pxs2_dwc3_init(struct udevice *dev, int index,
65				    enum usb_dr_mode mode)
66{
67	struct dwc3_glue_data *glue = dev_get_plat(dev);
68	void *regs = map_physmem(glue->regs, glue->size, MAP_NOCACHE);
69	u32 tmp;
70
71	tmp = readl(regs + UNIPHIER_PXS2_DWC3_RESET);
72	tmp |= UNIPHIER_PXS2_DWC3_RESET_XLINK;
73	writel(tmp, regs + UNIPHIER_PXS2_DWC3_RESET);
74
75	unmap_physmem(regs, MAP_NOCACHE);
76}
77
78static int dwc3_uniphier_glue_get_ctrl_dev(struct udevice *dev, ofnode *node)
79{
80	struct udevice *child;
81	const char *name;
82	ofnode subnode;
83
84	/*
85	 * "controller reset" belongs to glue logic, and it should be
86	 * accessible in .glue_configure() before access to the controller
87	 * begins.
88	 */
89	ofnode_for_each_subnode(subnode, dev_ofnode(dev)) {
90		name = ofnode_get_name(subnode);
91		if (!strncmp(name, "reset", 5))
92			device_bind_driver_to_node(dev, "uniphier-reset",
93						   name, subnode, &child);
94	}
95
96	/* Get controller node that is placed separately from the glue node */
97	*node = ofnode_by_compatible(dev_ofnode(dev->parent),
98				     "socionext,uniphier-dwc3");
99
100	return 0;
101}
102
103static const struct dwc3_glue_ops uniphier_pro4_dwc3_ops = {
104	.glue_get_ctrl_dev = dwc3_uniphier_glue_get_ctrl_dev,
105	.glue_configure = uniphier_pro4_dwc3_init,
106};
107
108static const struct dwc3_glue_ops uniphier_pro5_dwc3_ops = {
109	.glue_get_ctrl_dev = dwc3_uniphier_glue_get_ctrl_dev,
110	.glue_configure = uniphier_pro5_dwc3_init,
111};
112
113static const struct dwc3_glue_ops uniphier_pxs2_dwc3_ops = {
114	.glue_get_ctrl_dev = dwc3_uniphier_glue_get_ctrl_dev,
115	.glue_configure = uniphier_pxs2_dwc3_init,
116};
117
118static const struct udevice_id uniphier_dwc3_match[] = {
119	{
120		.compatible = "socionext,uniphier-pro4-dwc3-glue",
121		.data = (ulong)&uniphier_pro4_dwc3_ops,
122	},
123	{
124		.compatible = "socionext,uniphier-pro5-dwc3-glue",
125		.data = (ulong)&uniphier_pro5_dwc3_ops,
126	},
127	{
128		.compatible = "socionext,uniphier-pxs2-dwc3-glue",
129		.data = (ulong)&uniphier_pxs2_dwc3_ops,
130	},
131	{
132		.compatible = "socionext,uniphier-ld20-dwc3-glue",
133		.data = (ulong)&uniphier_pxs2_dwc3_ops,
134	},
135	{
136		.compatible = "socionext,uniphier-pxs3-dwc3-glue",
137		.data = (ulong)&uniphier_pxs2_dwc3_ops,
138	},
139	{
140		.compatible = "socionext,uniphier-nx1-dwc3-glue",
141		.data = (ulong)&uniphier_pxs2_dwc3_ops,
142	},
143	{ /* sentinel */ }
144};
145
146U_BOOT_DRIVER(dwc3_uniphier_wrapper) = {
147	.name = "uniphier-dwc3",
148	.id = UCLASS_SIMPLE_BUS,
149	.of_match = uniphier_dwc3_match,
150	.bind = dwc3_glue_bind,
151	.probe = dwc3_glue_probe,
152	.remove = dwc3_glue_remove,
153	.plat_auto = sizeof(struct dwc3_glue_data),
154};
155