xref: /openbsd-src/sys/dev/fdt/rkpciephy.c (revision ff0e7be1ebbcc809ea8ad2b6dafe215824da9e46)
1 /*	$OpenBSD: rkpciephy.c,v 1.1 2023/03/19 11:17:16 kettenis 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 /* 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 struct rkpciephy_softc {
46 	struct device		sc_dev;
47 	bus_space_tag_t		sc_iot;
48 	bus_space_handle_t	sc_ioh;
49 
50 	struct phy_device	sc_pd;
51 };
52 
53 int	rkpciephy_match(struct device *, void *, void *);
54 void	rkpciephy_attach(struct device *, struct device *, void *);
55 
56 const struct cfattach rkpciephy_ca = {
57 	sizeof (struct rkpciephy_softc), rkpciephy_match, rkpciephy_attach
58 };
59 
60 struct cfdriver rkpciephy_cd = {
61 	NULL, "rkpciephy", DV_DULL
62 };
63 
64 int	rkpciephy_enable(void *, uint32_t *);
65 
66 int
67 rkpciephy_match(struct device *parent, void *match, void *aux)
68 {
69 	struct fdt_attach_args *faa = aux;
70 
71 	return OF_is_compatible(faa->fa_node, "rockchip,rk3568-pcie3-phy");
72 }
73 
74 void
75 rkpciephy_attach(struct device *parent, struct device *self, void *aux)
76 {
77 	struct rkpciephy_softc *sc = (struct rkpciephy_softc *)self;
78 	struct fdt_attach_args *faa = aux;
79 
80 	printf("\n");
81 
82 	sc->sc_pd.pd_node = faa->fa_node;
83 	sc->sc_pd.pd_cookie = sc;
84 	sc->sc_pd.pd_enable = rkpciephy_enable;
85 	phy_register(&sc->sc_pd);
86 }
87 
88 int
89 rkpciephy_enable(void *cookie, uint32_t *cells)
90 {
91 	struct rkpciephy_softc *sc = cookie;
92 	struct regmap *rm;
93 	int node = sc->sc_pd.pd_node;
94 	uint32_t data_lanes[2] = { 0, 0 };
95 	uint32_t grf, stat;
96 	int timo;
97 
98 	grf = OF_getpropint(node, "rockchip,phy-grf", 0);
99 	rm = regmap_byphandle(grf);
100 	if (rm == NULL)
101 		return ENXIO;
102 
103 	clock_enable_all(node);
104 	reset_assert(node, "phy");
105 	delay(1);
106 
107 	regmap_write_4(rm, GRF_PCIE30PHY_CON(9), GRF_PCIE30PHY_DA_OCM);
108 
109 	OF_getpropintarray(node, "data-lanes", data_lanes, sizeof(data_lanes));
110 	if (data_lanes[0] > 0) {
111 		regmap_write_4(rm, GRF_PCIE30PHY_CON(5),
112 		    GRF_PCIE30PHY_LANE0_LINK_NUM_MASK |
113 		    (data_lanes[0] - 1) << GRF_PCIE30PHY_LANE0_LINK_NUM_SHIFT);
114 	}
115 	if (data_lanes[1] > 0) {
116 		regmap_write_4(rm, GRF_PCIE30PHY_CON(6),
117 		    GRF_PCIE30PHY_LANE1_LINK_NUM_MASK |
118 		    (data_lanes[1] - 1) << GRF_PCIE30PHY_LANE1_LINK_NUM_SHIFT);
119 	}
120 	if (data_lanes[0] > 1 || data_lanes[1] > 1)
121 		regmap_write_4(rm, GRF_PCIE30PHY_CON(1), GRF_PCIE30PHY_DA_OCM);
122 
123 	reset_deassert(node, "phy");
124 
125 	for (timo = 500; timo > 0; timo--) {
126 		stat = regmap_read_4(rm, GRF_PCIE30PHY_STATUS0);
127 		if (stat & GRF_PCIE30PHY_SRAM_INIT_DONE)
128 			break;
129 		delay(100);
130 	}
131 	if (timo == 0) {
132 		printf("%s: timeout\n", sc->sc_dev.dv_xname);
133 		return ETIMEDOUT;
134 	}
135 
136 	return 0;
137 }
138