xref: /netbsd-src/sys/dev/pci/nfsmb.c (revision 3816d47b2c42fcd6e549e3407f842a5b1a1d23ad)
1 /*	$NetBSD: nfsmb.c,v 1.20 2009/05/09 07:13:57 pgoyette Exp $	*/
2 /*
3  * Copyright (c) 2007 KIYOHARA Takashi
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: nfsmb.c,v 1.20 2009/05/09 07:13:57 pgoyette Exp $");
30 
31 #include <sys/param.h>
32 #include <sys/device.h>
33 #include <sys/errno.h>
34 #include <sys/kernel.h>
35 #include <sys/rwlock.h>
36 #include <sys/proc.h>
37 
38 #include <sys/bus.h>
39 
40 #include <dev/i2c/i2cvar.h>
41 
42 #include <dev/pci/pcivar.h>
43 #include <dev/pci/pcireg.h>
44 #include <dev/pci/pcidevs.h>
45 
46 #include <dev/pci/nfsmbreg.h>
47 
48 
49 struct nfsmbc_attach_args {
50 	int nfsmb_num;
51 	bus_space_tag_t nfsmb_iot;
52 	int nfsmb_addr;
53 };
54 
55 struct nfsmb_softc;
56 struct nfsmbc_softc {
57 	device_t sc_dev;
58 
59 	pci_chipset_tag_t sc_pc;
60 	pcitag_t sc_tag;
61 	struct pci_attach_args *sc_pa;
62 
63 	bus_space_tag_t sc_iot;
64 	device_t sc_nfsmb[2];
65 };
66 
67 struct nfsmb_softc {
68 	device_t sc_dev;
69 	int sc_num;
70 	device_t sc_nfsmbc;
71 
72 	bus_space_tag_t sc_iot;
73 	bus_space_handle_t sc_ioh;
74 
75 	struct i2c_controller sc_i2c;	/* i2c controller info */
76 	krwlock_t sc_rwlock;
77 };
78 
79 
80 static int nfsmbc_match(device_t, cfdata_t, void *);
81 static void nfsmbc_attach(device_t, device_t, void *);
82 static int nfsmbc_print(void *, const char *);
83 
84 static int nfsmb_match(device_t, cfdata_t, void *);
85 static void nfsmb_attach(device_t, device_t, void *);
86 static int nfsmb_acquire_bus(void *, int);
87 static void nfsmb_release_bus(void *, int);
88 static int nfsmb_exec(
89     void *, i2c_op_t, i2c_addr_t, const void *, size_t, void *, size_t, int);
90 static int nfsmb_check_done(struct nfsmb_softc *);
91 static int
92     nfsmb_send_1(struct nfsmb_softc *, uint8_t, i2c_addr_t, i2c_op_t, int);
93 static int nfsmb_write_1(
94     struct nfsmb_softc *, uint8_t, uint8_t, i2c_addr_t, i2c_op_t, int);
95 static int nfsmb_write_2(
96     struct nfsmb_softc *, uint8_t, uint16_t, i2c_addr_t, i2c_op_t, int);
97 static int nfsmb_receive_1(struct nfsmb_softc *, i2c_addr_t, i2c_op_t, int);
98 static int
99     nfsmb_read_1(struct nfsmb_softc *, uint8_t, i2c_addr_t, i2c_op_t, int);
100 static int
101     nfsmb_read_2(struct nfsmb_softc *, uint8_t, i2c_addr_t, i2c_op_t, int);
102 static int
103     nfsmb_quick(struct nfsmb_softc *, i2c_addr_t, i2c_op_t, int);
104 
105 CFATTACH_DECL_NEW(nfsmbc, sizeof(struct nfsmbc_softc),
106     nfsmbc_match, nfsmbc_attach, NULL, NULL);
107 
108 static int
109 nfsmbc_match(device_t parent, cfdata_t match, void *aux)
110 {
111 	struct pci_attach_args *pa = aux;
112 
113 	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NVIDIA) {
114 		switch (PCI_PRODUCT(pa->pa_id)) {
115 		case PCI_PRODUCT_NVIDIA_NFORCE2_SMBUS:
116 		case PCI_PRODUCT_NVIDIA_NFORCE2_400_SMBUS:
117 		case PCI_PRODUCT_NVIDIA_NFORCE3_SMBUS:
118 		case PCI_PRODUCT_NVIDIA_NFORCE3_250_SMBUS:
119 		case PCI_PRODUCT_NVIDIA_NFORCE4_SMBUS:
120 		case PCI_PRODUCT_NVIDIA_NFORCE430_SMBUS:
121 		case PCI_PRODUCT_NVIDIA_MCP04_SMBUS:
122 		case PCI_PRODUCT_NVIDIA_MCP55_SMB:
123 		case PCI_PRODUCT_NVIDIA_MCP61_SMB:
124 		case PCI_PRODUCT_NVIDIA_MCP65_SMB:
125 		case PCI_PRODUCT_NVIDIA_MCP67_SMB:
126 		case PCI_PRODUCT_NVIDIA_MCP73_SMB:
127 			return 1;
128 		}
129 	}
130 
131 	return 0;
132 }
133 
134 static void
135 nfsmbc_attach(device_t parent, device_t self, void *aux)
136 {
137 	struct nfsmbc_softc *sc = device_private(self);
138 	struct pci_attach_args *pa = aux;
139 	struct nfsmbc_attach_args nfsmbca;
140 	pcireg_t reg;
141 	int baseregs[2];
142 	char devinfo[256];
143 
144 	aprint_naive("\n");
145 	pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo));
146 	aprint_normal(": %s (rev. 0x%02x)\n", devinfo,
147 	    PCI_REVISION(pa->pa_class));
148 
149 	sc->sc_dev = self;
150 	sc->sc_pc = pa->pa_pc;
151 	sc->sc_tag = pa->pa_tag;
152 	sc->sc_pa = pa;
153 	sc->sc_iot = pa->pa_iot;
154 
155 	nfsmbca.nfsmb_iot = sc->sc_iot;
156 
157 	switch (PCI_PRODUCT(pa->pa_id)) {
158 	case PCI_PRODUCT_NVIDIA_NFORCE2_SMBUS:
159 	case PCI_PRODUCT_NVIDIA_NFORCE2_400_SMBUS:
160 	case PCI_PRODUCT_NVIDIA_NFORCE3_SMBUS:
161 	case PCI_PRODUCT_NVIDIA_NFORCE3_250_SMBUS:
162 	case PCI_PRODUCT_NVIDIA_NFORCE4_SMBUS:
163 		baseregs[0] = NFORCE_OLD_SMB1;
164 		baseregs[1] = NFORCE_OLD_SMB2;
165 		break;
166 	default:
167 		baseregs[0] = NFORCE_SMB1;
168 		baseregs[1] = NFORCE_SMB2;
169 		break;
170 	}
171 
172 	reg = pci_conf_read(pa->pa_pc, pa->pa_tag, baseregs[0]);
173 	nfsmbca.nfsmb_num = 1;
174 	nfsmbca.nfsmb_addr = NFORCE_SMBBASE(reg);
175 	sc->sc_nfsmb[0] = config_found(sc->sc_dev, &nfsmbca, nfsmbc_print);
176 
177 	reg = pci_conf_read(pa->pa_pc, pa->pa_tag, baseregs[1]);
178 	nfsmbca.nfsmb_num = 2;
179 	nfsmbca.nfsmb_addr = NFORCE_SMBBASE(reg);
180 	sc->sc_nfsmb[1] = config_found(sc->sc_dev, &nfsmbca, nfsmbc_print);
181 
182 	/* This driver is similar to an ISA bridge that doesn't
183 	 * need any special handling. So registering NULL handlers
184 	 * are sufficent. */
185 	if (!pmf_device_register(self, NULL, NULL))
186 		aprint_error_dev(self, "couldn't establish power handler\n");
187 }
188 
189 static int
190 nfsmbc_print(void *aux, const char *pnp)
191 {
192 	struct nfsmbc_attach_args *nfsmbcap = aux;
193 
194 	if (pnp)
195 		aprint_normal("nfsmb SMBus %d at %s",
196 		    nfsmbcap->nfsmb_num, pnp);
197 	else
198 		aprint_normal(" SMBus %d", nfsmbcap->nfsmb_num);
199 	return UNCONF;
200 }
201 
202 
203 CFATTACH_DECL_NEW(nfsmb, sizeof(struct nfsmb_softc),
204     nfsmb_match, nfsmb_attach, NULL, NULL);
205 
206 static int
207 nfsmb_match(device_t parent, cfdata_t match, void *aux)
208 {
209 	struct nfsmbc_attach_args *nfsmbcap = aux;
210 
211 	if (nfsmbcap->nfsmb_num == 1 || nfsmbcap->nfsmb_num == 2)
212 		return 1;
213 	return 0;
214 }
215 
216 static void
217 nfsmb_attach(device_t parent, device_t self, void *aux)
218 {
219 	struct nfsmb_softc *sc = device_private(self);
220 	struct nfsmbc_attach_args *nfsmbcap = aux;
221 	struct i2cbus_attach_args iba;
222 
223 	aprint_naive("\n");
224 	aprint_normal("\n");
225 
226 	sc->sc_dev = self;
227 	sc->sc_nfsmbc = parent;
228 	sc->sc_num = nfsmbcap->nfsmb_num;
229 	sc->sc_iot = nfsmbcap->nfsmb_iot;
230 
231 	/* register with iic */
232 	sc->sc_i2c.ic_cookie = sc;
233 	sc->sc_i2c.ic_acquire_bus = nfsmb_acquire_bus;
234 	sc->sc_i2c.ic_release_bus = nfsmb_release_bus;
235 	sc->sc_i2c.ic_send_start = NULL;
236 	sc->sc_i2c.ic_send_stop = NULL;
237 	sc->sc_i2c.ic_initiate_xfer = NULL;
238 	sc->sc_i2c.ic_read_byte = NULL;
239 	sc->sc_i2c.ic_write_byte = NULL;
240 	sc->sc_i2c.ic_exec = nfsmb_exec;
241 
242 	rw_init(&sc->sc_rwlock);
243 
244 	if (bus_space_map(sc->sc_iot, nfsmbcap->nfsmb_addr, NFORCE_SMBSIZE, 0,
245 	    &sc->sc_ioh) != 0) {
246 		aprint_error_dev(self, "failed to map SMBus space\n");
247 		return;
248 	}
249 
250 	iba.iba_type = I2C_TYPE_SMBUS;
251 	iba.iba_tag = &sc->sc_i2c;
252 	(void) config_found_ia(sc->sc_dev, "i2cbus", &iba, iicbus_print);
253 
254 	/* This driver is similar to an ISA bridge that doesn't
255 	 * need any special handling. So registering NULL handlers
256 	 * are sufficent. */
257 	if (!pmf_device_register(self, NULL, NULL))
258 		aprint_error_dev(self, "couldn't establish power handler\n");
259 }
260 
261 static int
262 nfsmb_acquire_bus(void *cookie, int flags)
263 {
264 	struct nfsmb_softc *sc = cookie;
265 
266 	rw_enter(&sc->sc_rwlock, RW_WRITER);
267 	return 0;
268 }
269 
270 static void
271 nfsmb_release_bus(void *cookie, int flags)
272 {
273 	struct nfsmb_softc *sc = cookie;
274 
275 	rw_exit(&sc->sc_rwlock);
276 }
277 
278 static int
279 nfsmb_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmd,
280 	   size_t cmdlen, void *vbuf, size_t buflen, int flags)
281 {
282 	struct nfsmb_softc *sc  = (struct nfsmb_softc *)cookie;
283 	uint8_t *p = vbuf;
284 	int rv;
285 
286 	if ((cmdlen == 0) && (buflen == 0)) {
287 		return nfsmb_quick(sc, addr, op, flags);
288 	}
289 
290 	if (I2C_OP_READ_P(op) && (cmdlen == 0) && (buflen == 1)) {
291 		rv = nfsmb_receive_1(sc, addr, op, flags);
292 		if (rv == -1)
293 			return -1;
294 		*p = (uint8_t)rv;
295 		return 0;
296 	}
297 
298 	if ((I2C_OP_READ_P(op)) && (cmdlen == 1) && (buflen == 1)) {
299 		rv = nfsmb_read_1(sc, *(const uint8_t*)cmd, addr, op, flags);
300 		if (rv == -1)
301 			return -1;
302 		*p = (uint8_t)rv;
303 		return 0;
304 	}
305 
306 	if ((I2C_OP_READ_P(op)) && (cmdlen == 1) && (buflen == 2)) {
307 		rv = nfsmb_read_2(sc, *(const uint8_t*)cmd, addr, op, flags);
308 		if (rv == -1)
309 			return -1;
310 		*(uint16_t *)p = (uint16_t)rv;
311 		return 0;
312 	}
313 
314 	if ((I2C_OP_WRITE_P(op)) && (cmdlen == 0) && (buflen == 1))
315 		return nfsmb_send_1(sc, *(uint8_t*)vbuf, addr, op, flags);
316 
317 	if ((I2C_OP_WRITE_P(op)) && (cmdlen == 1) && (buflen == 1))
318 		return nfsmb_write_1(sc, *(const uint8_t*)cmd, *(uint8_t*)vbuf,
319 		    addr, op, flags);
320 
321 	if ((I2C_OP_WRITE_P(op)) && (cmdlen == 1) && (buflen == 2))
322 		return nfsmb_write_2(sc,
323 		    *(const uint8_t*)cmd, *((uint16_t *)vbuf), addr, op, flags);
324 
325 	return -1;
326 }
327 
328 static int
329 nfsmb_check_done(struct nfsmb_softc *sc)
330 {
331 	int us;
332 	uint8_t stat;
333 
334 	us = 10 * 1000;	/* XXXX: wait maximum 10 msec */
335 	do {
336 		delay(10);
337 		us -= 10;
338 		if (us <= 0)
339 			return -1;
340 	} while (bus_space_read_1(sc->sc_iot, sc->sc_ioh,
341 	    NFORCE_SMB_PROTOCOL) != 0);
342 
343 	stat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_STATUS);
344 	if ((stat & NFORCE_SMB_STATUS_DONE) &&
345 	    !(stat & NFORCE_SMB_STATUS_STATUS))
346 		return 0;
347 	return -1;
348 }
349 
350 /* ARGSUSED */
351 static int
352 nfsmb_quick(struct nfsmb_softc *sc, i2c_addr_t addr, i2c_op_t op, int flags)
353 {
354 	uint8_t data;
355 
356 	/* write smbus slave address to register */
357 	data = addr << 1;
358 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data);
359 
360 	/* write smbus protocol to register */
361 	data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_QUICK;
362 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data);
363 
364 	return nfsmb_check_done(sc);
365 }
366 
367 /* ARGSUSED */
368 static int
369 nfsmb_send_1(struct nfsmb_softc *sc, uint8_t val, i2c_addr_t addr, i2c_op_t op,
370 	     int flags)
371 {
372 	uint8_t data;
373 
374 	/* store cmd */
375 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_COMMAND, val);
376 
377 	/* write smbus slave address to register */
378 	data = addr << 1;
379 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data);
380 
381 	/* write smbus protocol to register */
382 	data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_BYTE;
383 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data);
384 
385 	return nfsmb_check_done(sc);
386 }
387 
388 /* ARGSUSED */
389 static int
390 nfsmb_write_1(struct nfsmb_softc *sc, uint8_t cmd, uint8_t val, i2c_addr_t addr,
391 	      i2c_op_t op, int flags)
392 {
393 	uint8_t data;
394 
395 	/* store cmd */
396 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_COMMAND, cmd);
397 
398 	/* store data */
399 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA, val);
400 
401 	/* write smbus slave address to register */
402 	data = addr << 1;
403 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data);
404 
405 	/* write smbus protocol to register */
406 	data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_BYTE_DATA;
407 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data);
408 
409 	return nfsmb_check_done(sc);
410 }
411 
412 static int
413 nfsmb_write_2(struct nfsmb_softc *sc, uint8_t cmd, uint16_t val,
414 	      i2c_addr_t addr, i2c_op_t op, int flags)
415 {
416 	uint8_t data, low, high;
417 
418 	/* store cmd */
419 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_COMMAND, cmd);
420 
421 	/* store data */
422 	low = val;
423 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA, low);
424 	high = val >> 8;
425 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA + 1, high);
426 
427 	/* write smbus slave address to register */
428 	data = addr << 1;
429 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data);
430 
431 	/* write smbus protocol to register */
432 	data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_WORD_DATA;
433 	if (flags & I2C_F_PEC)
434 		data |= NFORCE_SMB_PROTOCOL_PEC;
435 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data);
436 
437 	return nfsmb_check_done(sc);
438 }
439 
440 /* ARGSUSED */
441 static int
442 nfsmb_receive_1(struct nfsmb_softc *sc, i2c_addr_t addr, i2c_op_t op, int flags)
443 {
444 	uint8_t data;
445 
446 	/* write smbus slave address to register */
447 	data = addr << 1;
448 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data);
449 
450 	/* write smbus protocol to register */
451 	data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_BYTE;
452 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data);
453 
454 	/* check for errors */
455 	if (nfsmb_check_done(sc) < 0)
456 		return -1;
457 
458 	/* read data */
459 	return bus_space_read_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA);
460 }
461 
462 /* ARGSUSED */
463 static int
464 nfsmb_read_1(struct nfsmb_softc *sc, uint8_t cmd, i2c_addr_t addr, i2c_op_t op,
465 	     int flags)
466 {
467 	uint8_t data;
468 
469 	/* store cmd */
470 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_COMMAND, cmd);
471 
472 	/* write smbus slave address to register */
473 	data = addr << 1;
474 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data);
475 
476 	/* write smbus protocol to register */
477 	data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_BYTE_DATA;
478 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data);
479 
480 	/* check for errors */
481 	if (nfsmb_check_done(sc) < 0)
482 		return -1;
483 
484 	/* read data */
485 	return bus_space_read_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA);
486 }
487 
488 static int
489 nfsmb_read_2(struct nfsmb_softc *sc, uint8_t cmd, i2c_addr_t addr, i2c_op_t op,
490 	     int flags)
491 {
492 	uint8_t data, low, high;
493 
494 	/* store cmd */
495 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_COMMAND, cmd);
496 
497 	/* write smbus slave address to register */
498 	data = addr << 1;
499 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data);
500 
501 	/* write smbus protocol to register */
502 	data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_WORD_DATA;
503 	if (flags & I2C_F_PEC)
504 		data |= NFORCE_SMB_PROTOCOL_PEC;
505 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data);
506 
507 	/* check for errors */
508 	if (nfsmb_check_done(sc) < 0)
509 		return -1;
510 
511 	/* read data */
512 	low = bus_space_read_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA);
513 	high = bus_space_read_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA + 1);
514 	return low | high << 8;
515 }
516