xref: /netbsd-src/sys/dev/pci/amdpm_smbus.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1 /*	$NetBSD: amdpm_smbus.c,v 1.21 2015/04/13 16:33:25 riastradh Exp $ */
2 
3 /*
4  * Copyright (c) 2005 Anil Gopinath (anil_public@yahoo.com)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 /* driver for SMBUS 1.0 host controller found in the
32  * AMD-8111 HyperTransport I/O Hub
33  */
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: amdpm_smbus.c,v 1.21 2015/04/13 16:33:25 riastradh Exp $");
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/device.h>
41 #include <sys/mutex.h>
42 
43 #include <dev/pci/pcireg.h>
44 #include <dev/pci/pcivar.h>
45 #include <dev/pci/pcidevs.h>
46 
47 #include <dev/i2c/i2cvar.h>
48 #include <dev/i2c/i2c_bitbang.h>
49 
50 #include <dev/pci/amdpmreg.h>
51 #include <dev/pci/amdpmvar.h>
52 
53 #include <dev/pci/amdpm_smbusreg.h>
54 
55 static int       amdpm_smbus_acquire_bus(void *, int);
56 static void      amdpm_smbus_release_bus(void *, int);
57 static int       amdpm_smbus_exec(void *, i2c_op_t, i2c_addr_t, const void *,
58 				  size_t, void *, size_t, int);
59 static int       amdpm_smbus_check_done(struct amdpm_softc *, i2c_op_t);
60 static void      amdpm_smbus_clear_gsr(struct amdpm_softc *);
61 static uint16_t	amdpm_smbus_get_gsr(struct amdpm_softc *);
62 static int       amdpm_smbus_quick(struct amdpm_softc *, i2c_op_t);
63 static int       amdpm_smbus_send_1(struct amdpm_softc *, uint8_t, i2c_op_t);
64 static int       amdpm_smbus_write_1(struct amdpm_softc *, uint8_t,
65 				     uint8_t, i2c_op_t);
66 static int       amdpm_smbus_receive_1(struct amdpm_softc *, i2c_op_t);
67 static int       amdpm_smbus_read_1(struct amdpm_softc *sc, uint8_t, i2c_op_t);
68 
69 void
70 amdpm_smbus_attach(struct amdpm_softc *sc)
71 {
72         struct i2cbus_attach_args iba;
73 
74 	/* register with iic */
75 	sc->sc_i2c.ic_cookie = sc;
76 	sc->sc_i2c.ic_acquire_bus = amdpm_smbus_acquire_bus;
77 	sc->sc_i2c.ic_release_bus = amdpm_smbus_release_bus;
78 	sc->sc_i2c.ic_send_start = NULL;
79 	sc->sc_i2c.ic_send_stop = NULL;
80 	sc->sc_i2c.ic_initiate_xfer = NULL;
81 	sc->sc_i2c.ic_read_byte = NULL;
82 	sc->sc_i2c.ic_write_byte = NULL;
83 	sc->sc_i2c.ic_exec = amdpm_smbus_exec;
84 
85 	iba.iba_tag = &sc->sc_i2c;
86 	(void)config_found_ia(sc->sc_dev, "i2cbus", &iba, iicbus_print);
87 }
88 
89 static int
90 amdpm_smbus_acquire_bus(void *cookie, int flags)
91 {
92 	struct amdpm_softc *sc = cookie;
93 
94 	mutex_enter(&sc->sc_mutex);
95 	return 0;
96 }
97 
98 static void
99 amdpm_smbus_release_bus(void *cookie, int flags)
100 {
101 	struct amdpm_softc *sc = cookie;
102 
103 	mutex_exit(&sc->sc_mutex);
104 }
105 
106 static int
107 amdpm_smbus_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmd,
108 		 size_t cmdlen, void *vbuf, size_t buflen, int flags)
109 {
110         struct amdpm_softc *sc  = (struct amdpm_softc *) cookie;
111 	sc->sc_smbus_slaveaddr  = addr;
112 	uint8_t *p = vbuf;
113 	int rv;
114 
115 	if ((cmdlen == 0) && (buflen == 0))
116 		return amdpm_smbus_quick(sc, op);
117 
118 	if (I2C_OP_READ_P(op) && (cmdlen == 0) && (buflen == 1)) {
119 		rv = amdpm_smbus_receive_1(sc, op);
120 		if (rv == -1)
121 			return -1;
122 		*p = (uint8_t)rv;
123 		return 0;
124 	}
125 
126 	if ((I2C_OP_READ_P(op)) && (cmdlen == 1) && (buflen == 1)) {
127 		rv = amdpm_smbus_read_1(sc, *(const uint8_t *)cmd, op);
128 		if (rv == -1)
129 			return -1;
130 		*p = (uint8_t)rv;
131 		return 0;
132 	}
133 
134 	if ((I2C_OP_WRITE_P(op)) && (cmdlen == 0) && (buflen == 1))
135 		return amdpm_smbus_send_1(sc, *(uint8_t*)vbuf, op);
136 
137 	if ((I2C_OP_WRITE_P(op)) && (cmdlen == 1) && (buflen == 1))
138 		return amdpm_smbus_write_1(sc,
139 					   *(const uint8_t*)cmd,
140 					   *(uint8_t*)vbuf,
141 					   op);
142 
143 	return -1;
144 }
145 
146 static int
147 amdpm_smbus_check_done(struct amdpm_softc *sc, i2c_op_t op)
148 {
149         int i;
150 
151 	for (i = 0; i < 1000; i++) {
152 	/* check gsr and wait till cycle is done */
153 		uint16_t data = amdpm_smbus_get_gsr(sc);
154 		if (data & AMDPM_8111_GSR_CYCLE_DONE)
155 			return 0;
156 	}
157 
158 	if (!(op & I2C_F_POLL))
159 	    delay(1);
160 
161 	return -1;
162 }
163 
164 
165 static void
166 amdpm_smbus_clear_gsr(struct amdpm_softc *sc)
167 {
168         /* clear register */
169         uint16_t data = 0xFFFF;
170 	int off = (sc->sc_nforce ? 0xe0 : 0);
171 	bus_space_write_2(sc->sc_iot, sc->sc_ioh,
172 	    AMDPM_8111_SMBUS_STAT - off, data);
173 }
174 
175 static uint16_t
176 amdpm_smbus_get_gsr(struct amdpm_softc *sc)
177 {
178 	int off = (sc->sc_nforce ? 0xe0 : 0);
179         return bus_space_read_2(sc->sc_iot, sc->sc_ioh,
180 	    AMDPM_8111_SMBUS_STAT - off);
181 }
182 
183 static int
184 amdpm_smbus_quick(struct amdpm_softc *sc, i2c_op_t op)
185 {
186 	uint16_t data = 0;
187 	int off = (sc->sc_nforce ? 0xe0 : 0);
188 
189 	/* first clear gsr */
190 	amdpm_smbus_clear_gsr(sc);
191 
192 	/* write smbus slave address and read/write bit to register */
193 	data = sc->sc_smbus_slaveaddr;
194 	data <<= 1;
195 	if (I2C_OP_READ_P(op))
196 		data |= AMDPM_8111_SMBUS_READ;
197 
198 	bus_space_write_1(sc->sc_iot, sc->sc_ioh,
199 	    AMDPM_8111_SMBUS_HOSTADDR - off, data);
200 
201 	/* host start */
202 	bus_space_write_2(sc->sc_iot, sc->sc_ioh,
203 	    AMDPM_8111_SMBUS_CTRL - off,
204 	    AMDPM_8111_SMBUS_GSR_QUICK);
205 
206 	return amdpm_smbus_check_done(sc, op);
207 }
208 
209 static int
210 amdpm_smbus_send_1(struct amdpm_softc *sc, uint8_t val, i2c_op_t op)
211 {
212 	uint16_t data = 0;
213 	int off = (sc->sc_nforce ? 0xe0 : 0);
214 
215 	/* first clear gsr */
216 	amdpm_smbus_clear_gsr(sc);
217 
218 	/* write smbus slave address to register */
219 	data = sc->sc_smbus_slaveaddr;
220 	data <<= 1;
221 	data |= AMDPM_8111_SMBUS_SEND;
222 	bus_space_write_1(sc->sc_iot, sc->sc_ioh,
223 	    AMDPM_8111_SMBUS_HOSTADDR - off, data);
224 
225 	data = val;
226 	/* store data */
227 	bus_space_write_2(sc->sc_iot, sc->sc_ioh,
228 	    AMDPM_8111_SMBUS_HOSTDATA - off, data);
229 	/* host start */
230 	bus_space_write_2(sc->sc_iot, sc->sc_ioh,
231 	    AMDPM_8111_SMBUS_CTRL - off,
232 	    AMDPM_8111_SMBUS_GSR_SB);
233 
234 	return amdpm_smbus_check_done(sc, op);
235 }
236 
237 
238 static int
239 amdpm_smbus_write_1(struct amdpm_softc *sc, uint8_t cmd, uint8_t val,
240 		    i2c_op_t op)
241 {
242 	uint16_t data = 0;
243 	int off = (sc->sc_nforce ? 0xe0 : 0);
244 
245 	/* first clear gsr */
246 	amdpm_smbus_clear_gsr(sc);
247 
248 	data = sc->sc_smbus_slaveaddr;
249 	data <<= 1;
250 	data |= AMDPM_8111_SMBUS_WRITE;
251 	bus_space_write_1(sc->sc_iot, sc->sc_ioh,
252 	    AMDPM_8111_SMBUS_HOSTADDR - off, data);
253 
254 	data = val;
255 	/* store cmd */
256 	bus_space_write_1(sc->sc_iot, sc->sc_ioh,
257 	    AMDPM_8111_SMBUS_HOSTCMD - off, cmd);
258 	/* store data */
259 	bus_space_write_2(sc->sc_iot, sc->sc_ioh,
260 	    AMDPM_8111_SMBUS_HOSTDATA - off, data);
261 	/* host start */
262 	bus_space_write_2(sc->sc_iot, sc->sc_ioh,
263 	    AMDPM_8111_SMBUS_CTRL - off, AMDPM_8111_SMBUS_GSR_WB);
264 
265 	return amdpm_smbus_check_done(sc, op);
266 }
267 
268 static int
269 amdpm_smbus_receive_1(struct amdpm_softc *sc, i2c_op_t op)
270 {
271 	uint16_t data = 0;
272 	int off = (sc->sc_nforce ? 0xe0 : 0);
273 
274 	/* first clear gsr */
275 	amdpm_smbus_clear_gsr(sc);
276 
277 	/* write smbus slave address to register */
278 	data = sc->sc_smbus_slaveaddr;
279 	data <<= 1;
280 	data |= AMDPM_8111_SMBUS_RX;
281 	bus_space_write_1(sc->sc_iot, sc->sc_ioh,
282 	    AMDPM_8111_SMBUS_HOSTADDR - off, data);
283 
284 	/* start smbus cycle */
285 	bus_space_write_2(sc->sc_iot, sc->sc_ioh,
286 	    AMDPM_8111_SMBUS_CTRL - off, AMDPM_8111_SMBUS_GSR_RXB);
287 
288 	/* check for errors */
289 	if (amdpm_smbus_check_done(sc, op) < 0)
290 		return -1;
291 
292 	/* read data */
293 	data = bus_space_read_2(sc->sc_iot, sc->sc_ioh,
294 	    AMDPM_8111_SMBUS_HOSTDATA - off);
295 	uint8_t ret = (uint8_t)(data & 0x00FF);
296 	return ret;
297 }
298 
299 static int
300 amdpm_smbus_read_1(struct amdpm_softc *sc, uint8_t cmd, i2c_op_t op)
301 {
302 	uint16_t data = 0;
303 	uint8_t ret;
304 	int off = (sc->sc_nforce ? 0xe0 : 0);
305 
306 	/* first clear gsr */
307 	amdpm_smbus_clear_gsr(sc);
308 
309 	/* write smbus slave address to register */
310 	data = sc->sc_smbus_slaveaddr;
311 	data <<= 1;
312 	data |= AMDPM_8111_SMBUS_READ;
313 	bus_space_write_1(sc->sc_iot, sc->sc_ioh,
314 	    AMDPM_8111_SMBUS_HOSTADDR - off, data);
315 
316 	/* store cmd */
317 	bus_space_write_1(sc->sc_iot, sc->sc_ioh,
318 	    AMDPM_8111_SMBUS_HOSTCMD - off, cmd);
319 	/* host start */
320 	bus_space_write_2(sc->sc_iot, sc->sc_ioh,
321 	    AMDPM_8111_SMBUS_CTRL - off, AMDPM_8111_SMBUS_GSR_RB);
322 
323 	/* check for errors */
324 	if (amdpm_smbus_check_done(sc, op) < 0)
325 		return -1;
326 
327 	/* store data */
328 	data = bus_space_read_2(sc->sc_iot, sc->sc_ioh,
329 	    AMDPM_8111_SMBUS_HOSTDATA - off);
330 	ret = (uint8_t)(data & 0x00FF);
331 	return ret;
332 }
333