1 /* $OpenBSD: rkpciephy.c,v 1.3 2023/07/09 19:11:30 patrick Exp $ */
2 /*
3 * Copyright (c) 2023 Mark Kettenis <kettenis@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21
22 #include <machine/intr.h>
23 #include <machine/bus.h>
24 #include <machine/fdt.h>
25
26 #include <dev/ofw/openfirm.h>
27 #include <dev/ofw/ofw_clock.h>
28 #include <dev/ofw/ofw_misc.h>
29 #include <dev/ofw/fdt.h>
30
31 /* RK3568 GRF registers */
32 #define GRF_PCIE30PHY_CON(idx) ((idx) * 4)
33 /* CON1 */
34 #define GRF_PCIE30PHY_DA_OCM 0x80008000
35 /* CON5 */
36 #define GRF_PCIE30PHY_LANE0_LINK_NUM_MASK (0xf << 16)
37 #define GRF_PCIE30PHY_LANE0_LINK_NUM_SHIFT 0
38 /* CON6 */
39 #define GRF_PCIE30PHY_LANE1_LINK_NUM_MASK (0xf << 16)
40 #define GRF_PCIE30PHY_LANE1_LINK_NUM_SHIFT 0
41 /* STATUS0 */
42 #define GRF_PCIE30PHY_STATUS0 0x80
43 #define GRF_PCIE30PHY_SRAM_INIT_DONE (1 << 14)
44
45 /* RK3588 GRF registers */
46 #define RK3588_PCIE3PHY_GRF_CMN_CON(idx) ((idx) * 4)
47 #define RK3588_GRF_PCIE3PHY_DA_OCM ((0x1 << 24) | (1 << 8))
48 #define RK3588_GRF_PCIE3PHY_LANE_BIFURCATE_0_1 (1 << 0)
49 #define RK3588_GRF_PCIE3PHY_LANE_BIFURCATE_2_3 (1 << 1)
50 #define RK3588_GRF_PCIE3PHY_LANE_AGGREGATE (1 << 2)
51 #define RK3588_GRF_PCIE3PHY_LANE_MASK (0x7 << 16)
52 #define RK3588_PCIE3PHY_GRF_PHY0_STATUS1 0x904
53 #define RK3588_PCIE3PHY_GRF_PHY1_STATUS1 0xa04
54 #define RK3588_PCIE3PHY_SRAM_INIT_DONE (1 << 0)
55 #define RK3588_PHP_GRF_PCIESEL_CON 0x100
56 #define RK3588_PHP_GRF_PCIE0L0_PCIE3 (1 << 0)
57 #define RK3588_PHP_GRF_PCIE0L1_PCIE3 (1 << 1)
58 #define RK3588_PHP_GRF_PCIE0L0_MASK (0x1 << 16)
59 #define RK3588_PHP_GRF_PCIE0L1_MASK (0x1 << 17)
60
61 struct rkpciephy_softc {
62 struct device sc_dev;
63 bus_space_tag_t sc_iot;
64 bus_space_handle_t sc_ioh;
65
66 struct phy_device sc_pd;
67 };
68
69 int rkpciephy_match(struct device *, void *, void *);
70 void rkpciephy_attach(struct device *, struct device *, void *);
71
72 const struct cfattach rkpciephy_ca = {
73 sizeof (struct rkpciephy_softc), rkpciephy_match, rkpciephy_attach
74 };
75
76 struct cfdriver rkpciephy_cd = {
77 NULL, "rkpciephy", DV_DULL
78 };
79
80 int rk3568_pciephy_enable(void *, uint32_t *);
81 int rk3588_pciephy_enable(void *, uint32_t *);
82
83 int
rkpciephy_match(struct device * parent,void * match,void * aux)84 rkpciephy_match(struct device *parent, void *match, void *aux)
85 {
86 struct fdt_attach_args *faa = aux;
87
88 return (OF_is_compatible(faa->fa_node, "rockchip,rk3568-pcie3-phy") ||
89 OF_is_compatible(faa->fa_node, "rockchip,rk3588-pcie3-phy"));
90 }
91
92 void
rkpciephy_attach(struct device * parent,struct device * self,void * aux)93 rkpciephy_attach(struct device *parent, struct device *self, void *aux)
94 {
95 struct rkpciephy_softc *sc = (struct rkpciephy_softc *)self;
96 struct fdt_attach_args *faa = aux;
97
98 printf("\n");
99
100 sc->sc_pd.pd_node = faa->fa_node;
101 sc->sc_pd.pd_cookie = sc;
102 if (OF_is_compatible(faa->fa_node, "rockchip,rk3568-pcie3-phy"))
103 sc->sc_pd.pd_enable = rk3568_pciephy_enable;
104 if (OF_is_compatible(faa->fa_node, "rockchip,rk3588-pcie3-phy"))
105 sc->sc_pd.pd_enable = rk3588_pciephy_enable;
106 phy_register(&sc->sc_pd);
107 }
108
109 int
rk3568_pciephy_enable(void * cookie,uint32_t * cells)110 rk3568_pciephy_enable(void *cookie, uint32_t *cells)
111 {
112 struct rkpciephy_softc *sc = cookie;
113 struct regmap *rm;
114 int node = sc->sc_pd.pd_node;
115 uint32_t data_lanes[2] = { 0, 0 };
116 uint32_t grf, stat;
117 int timo;
118
119 grf = OF_getpropint(node, "rockchip,phy-grf", 0);
120 rm = regmap_byphandle(grf);
121 if (rm == NULL)
122 return ENXIO;
123
124 clock_enable_all(node);
125 reset_assert(node, "phy");
126 delay(1);
127
128 regmap_write_4(rm, GRF_PCIE30PHY_CON(9), GRF_PCIE30PHY_DA_OCM);
129
130 OF_getpropintarray(node, "data-lanes", data_lanes, sizeof(data_lanes));
131 if (data_lanes[0] > 0) {
132 regmap_write_4(rm, GRF_PCIE30PHY_CON(5),
133 GRF_PCIE30PHY_LANE0_LINK_NUM_MASK |
134 (data_lanes[0] - 1) << GRF_PCIE30PHY_LANE0_LINK_NUM_SHIFT);
135 }
136 if (data_lanes[1] > 0) {
137 regmap_write_4(rm, GRF_PCIE30PHY_CON(6),
138 GRF_PCIE30PHY_LANE1_LINK_NUM_MASK |
139 (data_lanes[1] - 1) << GRF_PCIE30PHY_LANE1_LINK_NUM_SHIFT);
140 }
141 if (data_lanes[0] > 1 || data_lanes[1] > 1)
142 regmap_write_4(rm, GRF_PCIE30PHY_CON(1), GRF_PCIE30PHY_DA_OCM);
143
144 reset_deassert(node, "phy");
145
146 for (timo = 500; timo > 0; timo--) {
147 stat = regmap_read_4(rm, GRF_PCIE30PHY_STATUS0);
148 if (stat & GRF_PCIE30PHY_SRAM_INIT_DONE)
149 break;
150 delay(100);
151 }
152 if (timo == 0) {
153 printf("%s: timeout\n", sc->sc_dev.dv_xname);
154 return ETIMEDOUT;
155 }
156
157 return 0;
158 }
159
160 int
rk3588_pciephy_enable(void * cookie,uint32_t * cells)161 rk3588_pciephy_enable(void *cookie, uint32_t *cells)
162 {
163 struct rkpciephy_softc *sc = cookie;
164 struct regmap *phy, *pipe;
165 int node = sc->sc_pd.pd_node;
166 uint32_t data_lanes[4] = { 1, 1, 1, 1 };
167 uint32_t grf, reg, stat;
168 int num_lanes, timo;
169
170 grf = OF_getpropint(node, "rockchip,phy-grf", 0);
171 phy = regmap_byphandle(grf);
172 if (phy == NULL)
173 return ENXIO;
174
175 clock_enable_all(node);
176 reset_assert(node, "phy");
177 delay(1);
178
179 regmap_write_4(phy, RK3588_PCIE3PHY_GRF_CMN_CON(0),
180 RK3588_GRF_PCIE3PHY_DA_OCM);
181
182 num_lanes = OF_getpropintarray(node, "data-lanes", data_lanes,
183 sizeof(data_lanes));
184 /* Use default setting in case of missing properties. */
185 if (num_lanes <= 0)
186 num_lanes = sizeof(data_lanes);
187 num_lanes /= sizeof(uint32_t);
188
189 reg = RK3588_GRF_PCIE3PHY_LANE_MASK;
190 /* If all links go to the first, aggregate toward x4 */
191 if (num_lanes >= 4 &&
192 data_lanes[0] == 1 && data_lanes[1] == 1 &&
193 data_lanes[2] == 1 && data_lanes[3] == 1) {
194 reg |= RK3588_GRF_PCIE3PHY_LANE_AGGREGATE;
195 } else {
196 /* If lanes 0+1 are not towards the same controller, split. */
197 if (num_lanes >= 2 && data_lanes[0] != data_lanes[1])
198 reg |= RK3588_GRF_PCIE3PHY_LANE_BIFURCATE_0_1;
199 /* If lanes 2+3 are not towards the same controller, split. */
200 if (num_lanes >= 4 && data_lanes[2] != data_lanes[3])
201 reg |= RK3588_GRF_PCIE3PHY_LANE_BIFURCATE_2_3;
202 }
203 regmap_write_4(phy, RK3588_PCIE3PHY_GRF_CMN_CON(0), reg);
204
205 grf = OF_getpropint(node, "rockchip,pipe-grf", 0);
206 pipe = regmap_byphandle(grf);
207 if (pipe != NULL) {
208 reg = RK3588_PHP_GRF_PCIE0L0_MASK | RK3588_PHP_GRF_PCIE0L1_MASK;
209 /* If lane 1 goes to PCIe3_1L0, move from Combo to PCIE3 PHY */
210 if (num_lanes >= 2 && data_lanes[1] == 2)
211 reg |= RK3588_PHP_GRF_PCIE0L0_PCIE3;
212 /* If lane 3 goes to PCIe3_1L1, move from Combo to PCIE3 PHY */
213 if (num_lanes >= 4 && data_lanes[3] == 4)
214 reg |= RK3588_PHP_GRF_PCIE0L1_PCIE3;
215 regmap_write_4(pipe, RK3588_PHP_GRF_PCIESEL_CON, reg);
216 }
217
218 reset_deassert(node, "phy");
219
220 for (timo = 500; timo > 0; timo--) {
221 stat = regmap_read_4(phy, RK3588_PCIE3PHY_GRF_PHY0_STATUS1);
222 if (stat & RK3588_PCIE3PHY_SRAM_INIT_DONE)
223 break;
224 delay(100);
225 }
226 for (; timo > 0; timo--) {
227 stat = regmap_read_4(phy, RK3588_PCIE3PHY_GRF_PHY1_STATUS1);
228 if (stat & RK3588_PCIE3PHY_SRAM_INIT_DONE)
229 break;
230 delay(100);
231 }
232 if (timo == 0) {
233 printf("%s: timeout\n", sc->sc_dev.dv_xname);
234 return ETIMEDOUT;
235 }
236
237 return 0;
238 }
239