nfsmb.c revision 163459
1#include <sys/cdefs.h>
2__FBSDID("$FreeBSD: head/sys/pci/nfsmb.c 163459 2006-10-17 10:26:11Z ru $");
3
4#include <sys/param.h>
5#include <sys/kernel.h>
6#include <sys/systm.h>
7#include <sys/module.h>
8#include <sys/bus.h>
9#include <sys/uio.h>
10
11#include <machine/bus.h>
12#include <machine/resource.h>
13#include <sys/rman.h>
14
15#include <dev/pci/pcivar.h>
16#include <dev/pci/pcireg.h>
17
18#include <dev/iicbus/iiconf.h>
19#include <dev/smbus/smbconf.h>
20#include "smbus_if.h"
21
22#define	NFSMB_DEBUG(x)	if (nfsmb_debug) (x)
23
24#ifdef DEBUG
25static int nfsmb_debug = 1;
26#else
27static int nfsmb_debug = 0;
28#endif
29
30/* NVIDIA nForce2/3/4 MCP */
31#define	NFSMB_VENDORID_NVIDIA		0x10de
32#define	NFSMB_DEVICEID_NF2_SMB		0x0064
33#define	NFSMB_DEVICEID_NF2_ULTRA_SMB	0x0084
34#define	NFSMB_DEVICEID_NF3_PRO150_SMB	0x00d4
35#define	NFSMB_DEVICEID_NF3_250GB_SMB	0x00e4
36#define	NFSMB_DEVICEID_NF4_SMB		0x0052
37#define	NFSMB_DEVICEID_NF4_04_SMB	0x0034
38#define	NFSMB_DEVICEID_NF4_51_SMB	0x0264
39#define	NFSMB_DEVICEID_NF4_55_SMB	0x0368
40
41/* PCI Configuration space registers */
42#define	NF2PCI_SMBASE_1		PCIR_BAR(4)
43#define	NF2PCI_SMBASE_2		PCIR_BAR(5)
44
45/*
46 * ACPI 3.0, Chapter 12, SMBus Host Controller Interface.
47 */
48#define	SMB_PRTCL		0x00	/* protocol */
49#define	SMB_STS			0x01	/* status */
50#define	SMB_ADDR		0x02	/* address */
51#define	SMB_CMD			0x03	/* command */
52#define	SMB_DATA		0x04	/* 32 data registers */
53#define	SMB_BCNT		0x24	/* number of data bytes */
54#define	SMB_ALRM_A		0x25	/* alarm address */
55#define	SMB_ALRM_D		0x26	/* 2 bytes alarm data */
56
57#define	SMB_STS_DONE		0x80
58#define	SMB_STS_ALRM		0x40
59#define	SMB_STS_RES		0x20
60#define	SMB_STS_STATUS		0x1f
61#define	SMB_STS_OK		0x00	/* OK */
62#define	SMB_STS_UF		0x07	/* Unknown Failure */
63#define	SMB_STS_DANA		0x10	/* Device Address Not Acknowledged */
64#define	SMB_STS_DED		0x11	/* Device Error Detected */
65#define	SMB_STS_DCAD		0x12	/* Device Command Access Denied */
66#define	SMB_STS_UE		0x13	/* Unknown Error */
67#define	SMB_STS_DAD		0x17	/* Device Access Denied */
68#define	SMB_STS_T		0x18	/* Timeout */
69#define	SMB_STS_HUP		0x19	/* Host Unsupported Protocol */
70#define	SMB_STS_B		0x1A	/* Busy */
71#define	SMB_STS_PEC		0x1F	/* PEC (CRC-8) Error */
72
73#define	SMB_PRTCL_WRITE		0x00
74#define	SMB_PRTCL_READ		0x01
75#define	SMB_PRTCL_QUICK		0x02
76#define	SMB_PRTCL_BYTE		0x04
77#define	SMB_PRTCL_BYTE_DATA	0x06
78#define	SMB_PRTCL_WORD_DATA	0x08
79#define	SMB_PRTCL_BLOCK_DATA	0x0a
80#define	SMB_PRTCL_PROC_CALL	0x0c
81#define	SMB_PRTCL_BLOCK_PROC_CALL 0x0d
82#define	SMB_PRTCL_PEC		0x80
83
84struct nfsmb_softc {
85	int rid;
86	struct resource *res;
87	bus_space_tag_t smbst;
88	bus_space_handle_t smbsh;
89
90	device_t smbus;
91	device_t subdev;
92};
93
94#define	NFSMB_SMBINB(nfsmb, register) \
95	(bus_space_read_1(nfsmb->smbst, nfsmb->smbsh, register))
96#define	NFSMB_SMBOUTB(nfsmb, register, value) \
97	(bus_space_write_1(nfsmb->smbst, nfsmb->smbsh, register, value))
98
99static int
100nfsmbsub_probe(device_t dev)
101{
102
103	device_set_desc(dev, "nForce2/3/4 MCP SMBus Controller");
104	return (BUS_PROBE_DEFAULT);
105}
106
107static int
108nfsmb_probe(device_t dev)
109{
110	u_int16_t vid;
111	u_int16_t did;
112
113	vid = pci_get_vendor(dev);
114	did = pci_get_device(dev);
115
116	if (vid == NFSMB_VENDORID_NVIDIA) {
117		switch(did) {
118		case NFSMB_DEVICEID_NF2_SMB:
119		case NFSMB_DEVICEID_NF2_ULTRA_SMB:
120		case NFSMB_DEVICEID_NF3_PRO150_SMB:
121		case NFSMB_DEVICEID_NF3_250GB_SMB:
122		case NFSMB_DEVICEID_NF4_SMB:
123		case NFSMB_DEVICEID_NF4_04_SMB:
124		case NFSMB_DEVICEID_NF4_51_SMB:
125		case NFSMB_DEVICEID_NF4_55_SMB:
126			device_set_desc(dev, "nForce2/3/4 MCP SMBus Controller");
127			return (BUS_PROBE_DEFAULT);
128		}
129	}
130
131	return (ENXIO);
132}
133
134static int
135nfsmbsub_attach(device_t dev)
136{
137	device_t parent;
138	struct nfsmb_softc *nfsmbsub_sc = device_get_softc(dev);
139
140	parent = device_get_parent(dev);
141
142	nfsmbsub_sc->rid = NF2PCI_SMBASE_2;
143
144	nfsmbsub_sc->res = bus_alloc_resource_any(parent, SYS_RES_IOPORT,
145	    &nfsmbsub_sc->rid, RF_ACTIVE);
146	if (nfsmbsub_sc->res == NULL) {
147		/* Older incarnations of the device used non-standard BARs. */
148		nfsmbsub_sc->rid = 0x54;
149		nfsmbsub_sc->res = bus_alloc_resource_any(parent,
150		    SYS_RES_IOPORT, &nfsmbsub_sc->rid, RF_ACTIVE);
151		if (nfsmbsub_sc->res == NULL) {
152			device_printf(dev, "could not map i/o space\n");
153			return (ENXIO);
154		}
155	}
156	nfsmbsub_sc->smbst = rman_get_bustag(nfsmbsub_sc->res);
157	nfsmbsub_sc->smbsh = rman_get_bushandle(nfsmbsub_sc->res);
158
159	nfsmbsub_sc->smbus = device_add_child(dev, "smbus", -1);
160	if (nfsmbsub_sc->smbus == NULL)
161		return (EINVAL);
162
163	bus_generic_attach(dev);
164
165	return (0);
166}
167
168static int
169nfsmb_attach(device_t dev)
170{
171	struct nfsmb_softc *nfsmb_sc = device_get_softc(dev);
172
173	/* Allocate I/O space */
174	nfsmb_sc->rid = NF2PCI_SMBASE_1;
175
176	nfsmb_sc->res = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
177		&nfsmb_sc->rid, RF_ACTIVE);
178
179	if (nfsmb_sc->res == NULL) {
180		/* Older incarnations of the device used non-standard BARs. */
181		nfsmb_sc->rid = 0x50;
182		nfsmb_sc->res = bus_alloc_resource_any(dev,
183		    SYS_RES_IOPORT, &nfsmb_sc->rid, RF_ACTIVE);
184		if (nfsmb_sc->res == NULL) {
185			device_printf(dev, "could not map i/o space\n");
186			return (ENXIO);
187		}
188	}
189
190	nfsmb_sc->smbst = rman_get_bustag(nfsmb_sc->res);
191	nfsmb_sc->smbsh = rman_get_bushandle(nfsmb_sc->res);
192
193	/* Allocate a new smbus device */
194	nfsmb_sc->smbus = device_add_child(dev, "smbus", -1);
195	if (!nfsmb_sc->smbus)
196		return (EINVAL);
197
198	nfsmb_sc->subdev = NULL;
199	switch (pci_get_device(dev)) {
200	case NFSMB_DEVICEID_NF2_SMB:
201	case NFSMB_DEVICEID_NF2_ULTRA_SMB:
202	case NFSMB_DEVICEID_NF3_PRO150_SMB:
203	case NFSMB_DEVICEID_NF3_250GB_SMB:
204	case NFSMB_DEVICEID_NF4_SMB:
205	case NFSMB_DEVICEID_NF4_04_SMB:
206	case NFSMB_DEVICEID_NF4_51_SMB:
207	case NFSMB_DEVICEID_NF4_55_SMB:
208		/* Trying to add secondary device as slave */
209		nfsmb_sc->subdev = device_add_child(dev, "nfsmb", -1);
210		if (!nfsmb_sc->subdev)
211			return (EINVAL);
212		break;
213	default:
214		break;
215	}
216
217	bus_generic_attach(dev);
218
219	return (0);
220}
221
222static int
223nfsmbsub_detach(device_t dev)
224{
225	device_t parent;
226	struct nfsmb_softc *nfsmbsub_sc = device_get_softc(dev);
227
228	parent = device_get_parent(dev);
229
230	if (nfsmbsub_sc->smbus) {
231		device_delete_child(dev, nfsmbsub_sc->smbus);
232		nfsmbsub_sc->smbus = NULL;
233	}
234	if (nfsmbsub_sc->res) {
235		bus_release_resource(parent, SYS_RES_IOPORT, nfsmbsub_sc->rid,
236		    nfsmbsub_sc->res);
237		nfsmbsub_sc->res = NULL;
238	}
239	return (0);
240}
241
242static int
243nfsmb_detach(device_t dev)
244{
245	struct nfsmb_softc *nfsmb_sc = device_get_softc(dev);
246
247	if (nfsmb_sc->subdev) {
248		device_delete_child(dev, nfsmb_sc->subdev);
249		nfsmb_sc->subdev = NULL;
250	}
251
252	if (nfsmb_sc->smbus) {
253		device_delete_child(dev, nfsmb_sc->smbus);
254		nfsmb_sc->smbus = NULL;
255	}
256
257	if (nfsmb_sc->res) {
258		bus_release_resource(dev, SYS_RES_IOPORT, nfsmb_sc->rid,
259		    nfsmb_sc->res);
260		nfsmb_sc->res = NULL;
261	}
262
263	return (0);
264}
265
266static int
267nfsmb_callback(device_t dev, int index, void *data)
268{
269	int error = 0;
270
271	switch (index) {
272	case SMB_REQUEST_BUS:
273	case SMB_RELEASE_BUS:
274		break;
275	default:
276		error = EINVAL;
277	}
278
279	return (error);
280}
281
282static int
283nfsmb_wait(struct nfsmb_softc *sc)
284{
285	u_char sts;
286	int error, count;
287
288	if (NFSMB_SMBINB(sc, SMB_PRTCL) != 0)
289	{
290		count = 10000;
291		do {
292			DELAY(500);
293		} while (NFSMB_SMBINB(sc, SMB_PRTCL) != 0 && count--);
294		if (count == 0)
295			return (SMB_ETIMEOUT);
296	}
297
298	sts = NFSMB_SMBINB(sc, SMB_STS) & SMB_STS_STATUS;
299	NFSMB_DEBUG(printf("nfsmb: STS=0x%x\n", sts));
300
301	switch (sts) {
302	case SMB_STS_OK:
303		error = SMB_ENOERR;
304		break;
305	case SMB_STS_DANA:
306		error = SMB_ENOACK;
307		break;
308	case SMB_STS_B:
309		error = SMB_EBUSY;
310		break;
311	case SMB_STS_T:
312		error = SMB_ETIMEOUT;
313		break;
314	case SMB_STS_DCAD:
315	case SMB_STS_DAD:
316	case SMB_STS_HUP:
317		error = SMB_ENOTSUPP;
318		break;
319	default:
320		error = SMB_EBUSERR;
321		break;
322	}
323
324	return (error);
325}
326
327static int
328nfsmb_quick(device_t dev, u_char slave, int how)
329{
330	struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
331	u_char protocol;
332	int error;
333
334	protocol = SMB_PRTCL_QUICK;
335
336	switch (how) {
337	case SMB_QWRITE:
338		protocol |= SMB_PRTCL_WRITE;
339		NFSMB_DEBUG(printf("nfsmb: QWRITE to 0x%x", slave));
340		break;
341	case SMB_QREAD:
342		protocol |= SMB_PRTCL_READ;
343		NFSMB_DEBUG(printf("nfsmb: QREAD to 0x%x", slave));
344		break;
345	default:
346		panic("%s: unknown QUICK command (%x)!", __func__, how);
347	}
348
349	NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
350	NFSMB_SMBOUTB(sc, SMB_PRTCL, protocol);
351
352	error = nfsmb_wait(sc);
353
354	NFSMB_DEBUG(printf(", error=0x%x\n", error));
355
356	return (error);
357}
358
359static int
360nfsmb_sendb(device_t dev, u_char slave, char byte)
361{
362	struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
363	int error;
364
365	NFSMB_SMBOUTB(sc, SMB_CMD, byte);
366	NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
367	NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE);
368
369	error = nfsmb_wait(sc);
370
371	NFSMB_DEBUG(printf("nfsmb: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
372
373	return (error);
374}
375
376static int
377nfsmb_recvb(device_t dev, u_char slave, char *byte)
378{
379	struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
380	int error;
381
382	NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
383	NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE);
384
385	if ((error = nfsmb_wait(sc)) == SMB_ENOERR)
386		*byte = NFSMB_SMBINB(sc, SMB_DATA);
387
388	NFSMB_DEBUG(printf("nfsmb: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
389
390	return (error);
391}
392
393static int
394nfsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
395{
396	struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
397	int error;
398
399	NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
400	NFSMB_SMBOUTB(sc, SMB_DATA, byte);
401	NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
402	NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE_DATA);
403
404	error = nfsmb_wait(sc);
405
406	NFSMB_DEBUG(printf("nfsmb: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
407
408	return (error);
409}
410
411static int
412nfsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
413{
414	struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
415	int error;
416
417	NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
418	NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
419	NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE_DATA);
420
421	if ((error = nfsmb_wait(sc)) == SMB_ENOERR)
422		*byte = NFSMB_SMBINB(sc, SMB_DATA);
423
424	NFSMB_DEBUG(printf("nfsmb: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, (unsigned char)*byte, error));
425
426	return (error);
427}
428
429static int
430nfsmb_writew(device_t dev, u_char slave, char cmd, short word)
431{
432	struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
433	int error;
434
435	NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
436	NFSMB_SMBOUTB(sc, SMB_DATA, word);
437	NFSMB_SMBOUTB(sc, SMB_DATA + 1, word >> 8);
438	NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
439	NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_WORD_DATA);
440
441	error = nfsmb_wait(sc);
442
443	NFSMB_DEBUG(printf("nfsmb: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
444
445	return (error);
446}
447
448static int
449nfsmb_readw(device_t dev, u_char slave, char cmd, short *word)
450{
451	struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
452	int error;
453
454	NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
455	NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
456	NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_WORD_DATA);
457
458	if ((error = nfsmb_wait(sc)) == SMB_ENOERR)
459		*word = NFSMB_SMBINB(sc, SMB_DATA) |
460		    (NFSMB_SMBINB(sc, SMB_DATA + 1) << 8);
461
462	NFSMB_DEBUG(printf("nfsmb: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, (unsigned short)*word, error));
463
464	return (error);
465}
466
467static int
468nfsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
469{
470	struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
471	u_char i;
472	int error;
473
474	if (count < 1 || count > 32)
475		return (SMB_EINVAL);
476	NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
477	NFSMB_SMBOUTB(sc, SMB_BCNT, count);
478	for (i = 0; i < count; i++)
479		NFSMB_SMBOUTB(sc, SMB_DATA + i, buf[i]);
480	NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
481	NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BLOCK_DATA);
482
483	error = nfsmb_wait(sc);
484
485	NFSMB_DEBUG(printf("nfsmb: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
486
487	return (error);
488}
489
490static int
491nfsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
492{
493	struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
494	u_char data, len, i;
495	int error;
496
497	if (*count < 1 || *count > 32)
498		return (SMB_EINVAL);
499	NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
500	NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
501	NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BLOCK_DATA);
502
503	if ((error = nfsmb_wait(sc)) == SMB_ENOERR) {
504		len = NFSMB_SMBINB(sc, SMB_BCNT);
505		for (i = 0; i < len; i++) {
506			data = NFSMB_SMBINB(sc, SMB_DATA + i);
507			if (i < *count)
508				buf[i] = data;
509		}
510		*count = len;
511	}
512
513	NFSMB_DEBUG(printf("nfsmb: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error));
514
515	return (error);
516}
517
518static device_method_t nfsmb_methods[] = {
519	/* Device interface */
520	DEVMETHOD(device_probe,		nfsmb_probe),
521	DEVMETHOD(device_attach,	nfsmb_attach),
522	DEVMETHOD(device_detach,	nfsmb_detach),
523
524	/* SMBus interface */
525	DEVMETHOD(smbus_callback,	nfsmb_callback),
526	DEVMETHOD(smbus_quick,		nfsmb_quick),
527	DEVMETHOD(smbus_sendb,		nfsmb_sendb),
528	DEVMETHOD(smbus_recvb,		nfsmb_recvb),
529	DEVMETHOD(smbus_writeb,		nfsmb_writeb),
530	DEVMETHOD(smbus_readb,		nfsmb_readb),
531	DEVMETHOD(smbus_writew,		nfsmb_writew),
532	DEVMETHOD(smbus_readw,		nfsmb_readw),
533	DEVMETHOD(smbus_bwrite,		nfsmb_bwrite),
534	DEVMETHOD(smbus_bread,		nfsmb_bread),
535
536	{ 0, 0 }
537};
538
539static device_method_t nfsmbsub_methods[] = {
540	/* Device interface */
541	DEVMETHOD(device_probe,		nfsmbsub_probe),
542	DEVMETHOD(device_attach,	nfsmbsub_attach),
543	DEVMETHOD(device_detach,	nfsmbsub_detach),
544
545	/* SMBus interface */
546	DEVMETHOD(smbus_callback,	nfsmb_callback),
547	DEVMETHOD(smbus_quick,		nfsmb_quick),
548	DEVMETHOD(smbus_sendb,		nfsmb_sendb),
549	DEVMETHOD(smbus_recvb,		nfsmb_recvb),
550	DEVMETHOD(smbus_writeb,		nfsmb_writeb),
551	DEVMETHOD(smbus_readb,		nfsmb_readb),
552	DEVMETHOD(smbus_writew,		nfsmb_writew),
553	DEVMETHOD(smbus_readw,		nfsmb_readw),
554	DEVMETHOD(smbus_bwrite,		nfsmb_bwrite),
555	DEVMETHOD(smbus_bread,		nfsmb_bread),
556
557	{ 0, 0 }
558};
559
560static devclass_t nfsmb_devclass;
561
562static driver_t nfsmb_driver = {
563	"nfsmb",
564	nfsmb_methods,
565	sizeof(struct nfsmb_softc),
566};
567
568static driver_t nfsmbsub_driver = {
569	"nfsmb",
570	nfsmbsub_methods,
571	sizeof(struct nfsmb_softc),
572};
573
574DRIVER_MODULE(nfsmb, pci, nfsmb_driver, nfsmb_devclass, 0, 0);
575DRIVER_MODULE(nfsmb, nfsmb, nfsmbsub_driver, nfsmb_devclass, 0, 0);
576DRIVER_MODULE(smbus, nfsmb, smbus_driver, smbus_devclass, 0, 0);
577
578MODULE_DEPEND(nfsmb, pci, 1, 1, 1);
579MODULE_DEPEND(nfsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
580MODULE_VERSION(nfsmb, 1);
581