xref: /openbsd/sys/dev/fdt/rkemmcphy.c (revision 73471bf0)
1 /*	$OpenBSD: rkemmcphy.c,v 1.4 2021/10/24 17:52:26 mpi Exp $	*/
2 /*
3  * Copyright (c) 2019 Patrick Wildt <patrick@blueri.se>
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/fdt.h>
23 
24 #include <dev/ofw/openfirm.h>
25 #include <dev/ofw/ofw_clock.h>
26 #include <dev/ofw/ofw_misc.h>
27 #include <dev/ofw/fdt.h>
28 
29 /* Registers */
30 #define GRF_EMMCPHY_CON0		0x00
31 #define  GRF_EMMCPHY_CON0_OTAPDLYSEL_4		(0x4 << 7)
32 #define  GRF_EMMCPHY_CON0_OTAPDLYENA_EN		(1 << 11)
33 #define  GRF_EMMCPHY_CON0_FREQSEL_200M		(0x0 << 12)
34 #define  GRF_EMMCPHY_CON0_FREQSEL_50M		(0x1 << 12)
35 #define  GRF_EMMCPHY_CON0_FREQSEL_100M		(0x2 << 12)
36 #define  GRF_EMMCPHY_CON0_FREQSEL_150M		(0x3 << 12)
37 #define  GRF_EMMCPHY_CON0_OTAPDLYSEL_CLR	(0xf << 23)
38 #define  GRF_EMMCPHY_CON0_OTAPDLYENA_CLR	(1 << 27)
39 #define  GRF_EMMCPHY_CON0_FREQSEL_CLR		(0x3 << 28)
40 #define GRF_EMMCPHY_CON1		0x04
41 #define GRF_EMMCPHY_CON2		0x08
42 #define GRF_EMMCPHY_CON3		0x0c
43 #define GRF_EMMCPHY_CON4		0x10
44 #define GRF_EMMCPHY_CON5		0x14
45 #define GRF_EMMCPHY_CON6		0x18
46 #define  GRF_EMMCPHY_CON6_PDB_OFF		(0 << 0)
47 #define  GRF_EMMCPHY_CON6_PDB_ON		(1 << 0)
48 #define  GRF_EMMCPHY_CON6_ENDLL_OFF		(0 << 1)
49 #define  GRF_EMMCPHY_CON6_ENDLL_ON		(1 << 1)
50 #define  GRF_EMMCPHY_CON6_DR_50OHM		(0x0 << 4)
51 #define  GRF_EMMCPHY_CON6_DR_33OHM		(0x1 << 4)
52 #define  GRF_EMMCPHY_CON6_DR_66OHM		(0x2 << 4)
53 #define  GRF_EMMCPHY_CON6_DR_100OHM		(0x3 << 4)
54 #define  GRF_EMMCPHY_CON6_DR_40OHM		(0x4 << 4)
55 #define  GRF_EMMCPHY_CON6_PDB_CLR		(1 << 16)
56 #define  GRF_EMMCPHY_CON6_ENDLL_CLR		(1 << 17)
57 #define  GRF_EMMCPHY_CON6_DR_CLR		(0x7 << 20)
58 #define GRF_EMMCPHY_STATUS		0x20
59 #define  GRF_EMMCPHY_STATUS_DLLRDY		(1 << 5)
60 #define  GRF_EMMCPHY_STATUS_CALDONE		(1 << 6)
61 
62 #define HREAD4(sc, reg)							\
63 	(regmap_read_4((sc)->sc_rm, (sc)->sc_off + (reg)))
64 #define HWRITE4(sc, reg, val)						\
65 	regmap_write_4((sc)->sc_rm, (sc)->sc_off + (reg), (val))
66 
67 struct rkemmcphy_softc {
68 	struct device		sc_dev;
69 	struct regmap		*sc_rm;
70 	bus_size_t		sc_off;
71 
72 	struct phy_device	sc_pd;
73 };
74 
75 int rkemmcphy_match(struct device *, void *, void *);
76 void rkemmcphy_attach(struct device *, struct device *, void *);
77 
78 const struct cfattach	rkemmcphy_ca = {
79 	sizeof (struct rkemmcphy_softc), rkemmcphy_match, rkemmcphy_attach
80 };
81 
82 struct cfdriver rkemmcphy_cd = {
83 	NULL, "rkemmcphy", DV_DULL
84 };
85 
86 int	rkemmcphy_enable(void *, uint32_t *);
87 
88 int
89 rkemmcphy_match(struct device *parent, void *match, void *aux)
90 {
91 	struct fdt_attach_args *faa = aux;
92 
93 	return OF_is_compatible(faa->fa_node, "rockchip,rk3399-emmc-phy");
94 }
95 
96 void
97 rkemmcphy_attach(struct device *parent, struct device *self, void *aux)
98 {
99 	struct rkemmcphy_softc *sc = (struct rkemmcphy_softc *)self;
100 	struct fdt_attach_args *faa = aux;
101 
102 	if (faa->fa_nreg < 1) {
103 		printf(": no registers\n");
104 		return;
105 	}
106 	sc->sc_off = faa->fa_reg[0].addr;
107 
108 	sc->sc_rm = regmap_bynode(OF_parent(faa->fa_node));
109 	if (sc->sc_rm == NULL) {
110 		printf(": can't map registers\n");
111 		return;
112 	}
113 
114 	printf("\n");
115 
116 	sc->sc_pd.pd_node = faa->fa_node;
117 	sc->sc_pd.pd_cookie = sc;
118 	sc->sc_pd.pd_enable = rkemmcphy_enable;
119 	phy_register(&sc->sc_pd);
120 }
121 
122 int
123 rkemmcphy_enable(void *cookie, uint32_t *cells)
124 {
125 	struct rkemmcphy_softc *sc = cookie;
126 	uint32_t impedance, freqsel, freq, reg;
127 	int node = sc->sc_pd.pd_node;
128 	int i;
129 
130 	impedance = OF_getpropint(node, "drive-impedance-ohm", 0);
131 	freq = clock_get_frequency(node, "emmcclk");
132 
133 	switch (impedance) {
134 	case 100:
135 		impedance = GRF_EMMCPHY_CON6_DR_100OHM;
136 		break;
137 	case 66:
138 		impedance = GRF_EMMCPHY_CON6_DR_66OHM;
139 		break;
140 	case 50:
141 		impedance = GRF_EMMCPHY_CON6_DR_50OHM;
142 		break;
143 	case 40:
144 		impedance = GRF_EMMCPHY_CON6_DR_40OHM;
145 		break;
146 	case 33:
147 		impedance = GRF_EMMCPHY_CON6_DR_33OHM;
148 		break;
149 	default:
150 		impedance = GRF_EMMCPHY_CON6_DR_50OHM;
151 		break;
152 	}
153 
154 	if (freq == 0) {
155 		freqsel = GRF_EMMCPHY_CON0_FREQSEL_200M;
156 	} else if (freq < 75000000) {
157 		freqsel = GRF_EMMCPHY_CON0_FREQSEL_50M;
158 	} else if (freq < 125000000) {
159 		freqsel = GRF_EMMCPHY_CON0_FREQSEL_100M;
160 	} else if (freq < 175000000) {
161 		freqsel = GRF_EMMCPHY_CON0_FREQSEL_150M;
162 	} else {
163 		freqsel = GRF_EMMCPHY_CON0_FREQSEL_200M;
164 	}
165 
166 	HWRITE4(sc, GRF_EMMCPHY_CON6, GRF_EMMCPHY_CON6_DR_CLR | impedance);
167 
168 	HWRITE4(sc, GRF_EMMCPHY_CON0,
169 	    GRF_EMMCPHY_CON0_OTAPDLYENA_CLR | GRF_EMMCPHY_CON0_OTAPDLYENA_EN);
170 	HWRITE4(sc, GRF_EMMCPHY_CON0,
171 	    GRF_EMMCPHY_CON0_OTAPDLYSEL_CLR | GRF_EMMCPHY_CON0_OTAPDLYSEL_4);
172 
173 	HWRITE4(sc, GRF_EMMCPHY_CON6,
174 	    GRF_EMMCPHY_CON6_PDB_CLR | GRF_EMMCPHY_CON6_PDB_OFF |
175 	    GRF_EMMCPHY_CON6_ENDLL_CLR | GRF_EMMCPHY_CON6_ENDLL_OFF);
176 
177 	delay(3);
178 	HWRITE4(sc, GRF_EMMCPHY_CON6, GRF_EMMCPHY_CON6_PDB_CLR |
179 	    GRF_EMMCPHY_CON6_PDB_ON);
180 
181 	for (i = 5; i > 0; i--) {
182 		reg = HREAD4(sc, GRF_EMMCPHY_STATUS);
183 		if (reg & GRF_EMMCPHY_STATUS_CALDONE)
184 			break;
185 		delay(10);
186 	}
187 	if (i == 0)
188 		printf("%s: timeout\n", sc->sc_dev.dv_xname);
189 
190 	HWRITE4(sc, GRF_EMMCPHY_CON0, GRF_EMMCPHY_CON0_FREQSEL_CLR | freqsel);
191 	HWRITE4(sc, GRF_EMMCPHY_CON6, GRF_EMMCPHY_CON6_ENDLL_CLR |
192 	    GRF_EMMCPHY_CON6_ENDLL_ON);
193 
194 	if (freq != 0) {
195 		for (i = 5; i > 0; i--) {
196 			reg = HREAD4(sc, GRF_EMMCPHY_STATUS);
197 			if (reg & GRF_EMMCPHY_STATUS_DLLRDY)
198 				break;
199 			delay(10 * 1000);
200 		}
201 		if (i == 0)
202 			printf("%s: timeout\n", sc->sc_dev.dv_xname);
203 	}
204 
205 	return 0;
206 }
207