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