xref: /openbsd-src/sys/dev/fdt/rkpciephy.c (revision 5b23ee9f7fff40c3a5d303a0cc3360a43360e931)
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