1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
|
/* $OpenBSD: amldwusb.c,v 1.4 2021/10/24 17:52:26 mpi Exp $ */
/*
* Copyright (c) 2019 Mark kettenis <kettenis@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <machine/bus.h>
#include <machine/fdt.h>
#include <arm64/dev/simplebusvar.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_clock.h>
#include <dev/ofw/ofw_misc.h>
#include <dev/ofw/ofw_power.h>
#include <dev/ofw/ofw_regulator.h>
#include <dev/ofw/fdt.h>
/* Glue registers. */
#define U2P_R0(i) (0x00 + (i) * 0x20)
#define U2P_R0_HOST_DEVICE (1 << 0)
#define U2P_R0_POWER_OK (1 << 1)
#define U2P_R0_HAST_MODE (1 << 2)
#define U2P_R0_POWER_ON_RESET (1 << 3)
#define U2P_R0_ID_PULLUP (1 << 4)
#define U2P_R0_DRV_VBUS (1 << 5)
#define U2P_R1(i) (0x04 + (i) * 0x20)
#define U2P_R1_PHY_READY (1 << 0)
#define U2P_R1_ID_DIG (1 << 1)
#define U2P_R1_OTG_SESSION_VALID (1 << 2)
#define U2P_R1_VBUS_VALID (1 << 3)
#define USB_R0 0x80
#define USB_R0_P30_LANE0_TX2RX_LOOPBACK (1 << 17)
#define USB_R0_P30_LANE0_EXT_PCLK_REQ (1 << 18)
#define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK (0x3ff << 19)
#define USB_R0_P30_PCS_RX_LOS_MASK_VAL_SHIFT 19
#define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK (0x3 << 29)
#define USB_R0_U2D_SS_SCALEDOWN_MODE_SHIFT 29
#define USB_R0_U2D_ACT (1U << 31)
#define USB_R1 0x84
#define USB_R1_U3H_BIGENDIAN_GS (1 << 0)
#define USB_R1_U3H_PME_ENABLE (1 << 1)
#define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK (0x7 << 2)
#define USB_R1_U3H_HUB_PORT_OVERCURRENT_SHIFT 2
#define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK (0x7 << 7)
#define USB_R1_U3H_HUB_PORT_PERM_ATTACH_SHIFT 7
#define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK (0x3 << 12)
#define USB_R1_U3H_HOST_U2_PORT_DISABLE_SHIFT 12
#define USB_R1_U3H_HOST_U3_PORT_DISABLE (1 << 16)
#define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT (1 << 17)
#define USB_R1_U3H_HOST_MSI_ENABLE (1 << 18)
#define USB_R1_U3H_FLADJ_30MHZ_REG_MASK (0x3f << 19)
#define USB_R1_U3H_FLADJ_30MHZ_REG_SHIFT 19
#define USB_R1_P30_PCS_TX_SWING_FULL_MASK (0x7f << 25)
#define USB_R1_P30_PCS_TX_SWING_FULL_SHIFT 25
#define USB_R2 0x88
#define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK (0x3f << 20)
#define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_SHIFT 20
#define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK (0x3f << 26)
#define USB_R2_P30_PCS_TX_DEEMPH_6DB_SHIFT 26
#define USB_R3 0x8c
#define USB_R3_P30_SSC_ENABLE (1 << 0)
#define USB_R3_P30_SSC_RANGE_MASK (0x7 << 1)
#define USB_R3_P30_SSC_RANGE_SHIFT 1
#define USB_R3_P30_SSC_REF_CLK_SEL_MASK (0x1ff << 4)
#define USB_R3_P30_SSC_REF_CLK_SEL_SHIFT 4
#define USB_R3_P30_REF_SSP_EN (1 << 13)
#define USB_R4 0x90
#define USB_R4_P21_PORT_RESET_0 (1 << 0)
#define USB_R4_P21_SLEEP_M0 (1 << 1)
#define USB_R4_MEM_PD_MASK (0x3 << 2)
#define USB_R4_MEM_PD_SHIFT 2
#define USB_R4_P21_ONLY (1 << 4)
#define USB_R5 0x94
#define USB_R5_ID_DIG_SYNC (1 << 0)
#define USB_R5_ID_DIG_REG (1 << 1)
#define USB_R5_ID_DIG_CFG_MASK (0x3 << 2)
#define USB_R5_ID_DIG_CFG_SHIFT 2
#define USB_R5_ID_DIG_EN_0 (1 << 4)
#define USB_R5_ID_DIG_EN_1 (1 << 5)
#define USB_R5_ID_DIG_CURR (1 << 6)
#define USB_R5_ID_DIG_IRQ (1 << 7)
#define USB_R5_ID_DIG_TH_MASK (0xff << 8)
#define USB_R5_ID_DIG_TH_SHIFT 8
#define USB_R5_ID_DIG_CNT_MASK (0xff << 16)
#define USB_R5_ID_DIG_CNT_SHIFT 16
#define HREAD4(sc, reg) \
(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
#define HWRITE4(sc, reg, val) \
bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
#define HSET4(sc, reg, bits) \
HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
#define HCLR4(sc, reg, bits) \
HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
struct amldwusb_softc {
struct simplebus_softc sc_sbus;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
};
int amldwusb_match(struct device *, void *, void *);
void amldwusb_attach(struct device *, struct device *, void *);
const struct cfattach amldwusb_ca = {
sizeof(struct amldwusb_softc), amldwusb_match, amldwusb_attach
};
struct cfdriver amldwusb_cd = {
NULL, "amldwusb", DV_DULL
};
void amldwusb_init_usb2(struct amldwusb_softc *);
void amldwusb_init_usb3(struct amldwusb_softc *);
int
amldwusb_match(struct device *parent, void *match, void *aux)
{
struct fdt_attach_args *faa = aux;
return OF_is_compatible(faa->fa_node, "amlogic,meson-g12a-usb-ctrl");
}
void
amldwusb_attach(struct device *parent, struct device *self, void *aux)
{
struct amldwusb_softc *sc = (struct amldwusb_softc *)self;
struct fdt_attach_args *faa = aux;
uint32_t vbus_supply;
uint32_t reg;
if (faa->fa_nreg < 1) {
printf(": no registers\n");
return;
}
sc->sc_iot = faa->fa_iot;
if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
printf(": can't map registers\n");
return;
}
power_domain_enable(faa->fa_node);
clock_enable_all(faa->fa_node);
reset_assert_all(faa->fa_node);
delay(10);
reset_deassert_all(faa->fa_node);
vbus_supply = OF_getpropint(faa->fa_node, "vbus-supply", 0);
if (vbus_supply)
regulator_enable(vbus_supply);
amldwusb_init_usb2(sc);
reg = HREAD4(sc, USB_R1);
reg &= ~USB_R1_U3H_FLADJ_30MHZ_REG_MASK;
reg |= (0x20 << USB_R1_U3H_FLADJ_30MHZ_REG_SHIFT);
HWRITE4(sc, USB_R1, reg);
HSET4(sc, USB_R5, USB_R5_ID_DIG_EN_0);
HSET4(sc, USB_R5, USB_R5_ID_DIG_EN_1);
reg = HREAD4(sc, USB_R5);
reg &= ~USB_R5_ID_DIG_TH_MASK;
reg |= (0xff << USB_R5_ID_DIG_TH_SHIFT);
HWRITE4(sc, USB_R5, reg);
/* Initialize PHYs. */
phy_enable(faa->fa_node, "usb2-phy0");
phy_enable(faa->fa_node, "usb2-phy1");
/* Only enable USB 3.0 logic and PHY if we have one. */
if (OF_getindex(faa->fa_node, "usb3-phy0", "phy-names") >= 0) {
amldwusb_init_usb3(sc);
phy_enable(faa->fa_node, "usb3-phy0");
}
simplebus_attach(parent, &sc->sc_sbus.sc_dev, faa);
}
void
amldwusb_init_usb2(struct amldwusb_softc *sc)
{
int i;
for (i = 0; i < 3; i++) {
HSET4(sc, U2P_R0(i), U2P_R0_POWER_ON_RESET);
/* We don't support device mode, so always force host mode. */
HSET4(sc, U2P_R0(i), U2P_R0_HOST_DEVICE);
HCLR4(sc, U2P_R0(i), U2P_R0_POWER_ON_RESET);
}
}
void
amldwusb_init_usb3(struct amldwusb_softc *sc)
{
uint32_t reg;
reg = HREAD4(sc, USB_R3);
reg &= ~USB_R3_P30_SSC_RANGE_MASK;
reg |= USB_R3_P30_SSC_ENABLE;
reg |= (2 << USB_R3_P30_SSC_RANGE_SHIFT);
reg |= USB_R3_P30_REF_SSP_EN;
HWRITE4(sc, USB_R3, reg);
delay(2);
reg = HREAD4(sc, USB_R2);
reg &= ~USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK;
reg |= (0x15 << USB_R2_P30_PCS_TX_DEEMPH_3P5DB_SHIFT);
HWRITE4(sc, USB_R2, reg);
reg = HREAD4(sc, USB_R2);
reg &= ~USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK;
reg |= (0x15 << USB_R2_P30_PCS_TX_DEEMPH_6DB_SHIFT);
HWRITE4(sc, USB_R2, reg);
delay(2);
HSET4(sc, USB_R1, USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT);
reg = HREAD4(sc, USB_R1);
reg &= ~USB_R1_P30_PCS_TX_SWING_FULL_MASK;
reg |= (0x7f << USB_R1_P30_PCS_TX_SWING_FULL_SHIFT);
HWRITE4(sc, USB_R1, reg);
}
|