2 #include "../port/lib.h"
9 * SMBus support for the PIIX4
14 Piix4PMID= 0x7113, /* PIIX4 power management function */
16 /* SMBus configuration registers (function 3) */
17 SMBbase= 0x90, /* 4 byte base address (bit 0 == 1, bit 3:1 == 0) */
19 SMBintrselect= (7<<1),
20 SMIenable= (0<<1), /* interrupts sent to SMI# */
21 IRQ9enable= (4<<1), /* interrupts sent to IRQ9 */
22 SMBenable= (1<<0), /* 1 enables */
24 /* SMBus IO space registers */
25 Hoststatus= 0x0, /* (writing 1 bits reset the interrupt bits) */
26 Failed= (1<<4), /* transaction terminated by KILL */
27 Bus_error= (1<<3), /* transaction collision */
28 Dev_error= (1<<2), /* device error interrupt */
29 Host_complete= (1<<1), /* host command completion interrupt */
30 Host_busy= (1<<0), /* */
31 Slavestatus= 0x1, /* (writing 1 bits reset) */
32 Alert_sts= (1<<5), /* someone asserted SMBALERT# */
33 Shdw2_sts= (1<<4), /* slave accessed shadow 2 port */
34 Shdw1_sts= (1<<3), /* slave accessed shadow 1 port */
35 Slv_sts= (1<<2), /* slave accessed shadow 1 port */
38 Start= (1<<6), /* start execution */
39 Cmd_prot= (7<<2), /* command protocol mask */
40 Quick= (0<<2), /* address only */
41 Byte= (1<<2), /* address + cmd */
42 ByteData= (2<<2), /* address + cmd + data */
43 WordData= (3<<2), /* address + cmd + data + data */
44 Kill= (1<<1), /* abort in progress command */
45 Ienable= (1<<0), /* enable completion interrupts */
48 AddressMask= (0x7f<<1), /* target address */
49 Read= (1<<0), /* 1 == read, 0 == write */
54 Alert_en= (1<<3), /* enable inter on SMBALERT# */
55 Shdw2_en= (1<<2), /* enable inter on external shadow 2 access */
56 Shdw1_en= (1<<1), /* enable inter on external shadow 1 access */
57 Slv_en= (1<<0), /* enable inter on access of host ctlr slave port */
71 [SMBquick] { 0, 0, 0, Quick },
72 [SMBsend] { 0, 1, 0, Byte },
73 [SMBbytewrite] { 0, 1, 1, ByteData },
74 [SMBwordwrite] { 0, 1, 2, WordData },
75 [SMBrecv] { Read, 0, 1, Byte },
76 [SMBbyteread] { Read, 1, 1, ByteData },
77 [SMBwordread] { Read, 1, 2, WordData },
81 transact(SMBus *s, int type, int addr, int cmd, uchar *data)
86 if(type < 0 || type > nelem(proto))
87 panic("piix4smbus: illegal transaction type %d", type);
95 /* wait a while for the host interface to be available */
96 for(tries = 0; tries < 1000000; tries++){
97 if((inb(s->base+Hoststatus) & Host_busy) == 0)
101 if(tries >= 1000000){
102 /* try aborting current transaction */
103 outb(s->base+Hostcontrol, Kill);
104 for(tries = 0; tries < 1000000; tries++){
105 if((inb(s->base+Hoststatus) & Host_busy) == 0)
109 if(tries >= 1000000){
110 snprint(err, sizeof(err), "SMBus jammed: %2.2ux", inb(s->base+Hoststatus));
115 /* set up for transaction */
116 outb(s->base+Hostaddress, (addr<<1)|proto[type].rw);
118 outb(s->base+Hostcommand, cmd);
119 if(proto[type].rw != Read){
120 switch(proto[type].len){
122 outb(s->base+Hostdata1, data[1]);
125 outb(s->base+Hostdata0, data[0]);
131 /* reset the completion/error bits and start transaction */
132 outb(s->base+Hoststatus, Failed|Bus_error|Dev_error|Host_complete);
133 outb(s->base+Hostcontrol, Start|proto[type].proto);
135 /* wait for completion */
137 for(tries = 0; tries < 1000000; tries++){
138 status = inb(s->base+Hoststatus);
139 if(status & (Failed|Bus_error|Dev_error|Host_complete))
143 if((status & Host_complete) == 0){
144 snprint(err, sizeof(err), "SMBus request failed: %2.2ux", status);
149 if(proto[type].rw == Read){
150 switch(proto[type].len){
152 data[1] = inb(s->base+Hostdata1);
155 data[0] = inb(s->base+Hostdata0);
163 static SMBus smbusproto =
165 .transact = transact,
169 * return 0 if this is a piix4 with an smbus interface
180 p = pcimatch(nil, IntelVendID, Piix4PMID);
184 s = malloc(sizeof(*s));
186 panic("piix4smbus: no memory for SMBus");
187 memmove(s, &smbusproto, sizeof(*s));
190 /* disable the smbus */
191 pcicfgw8(p, SMBconfig, IRQ9enable|0);
193 /* see if bios gave us a viable port space */
194 s->base = pcicfgr32(p, SMBbase) & ~1;
195 print("SMB base from bios is 0x%lux\n", s->base);
196 if(ioalloc(s->base, 0xd, 0, "piix4smbus") < 0){
197 s->base = ioalloc(-1, 0xd, 2, "piix4smbus");
200 print("piix4smbus: can't allocate io port\n");
203 print("SMB base ialloc is 0x%lux\n", s->base);
204 pcicfgw32(p, SMBbase, s->base|1);
207 /* disable SMBus interrupts, abort any transaction in progress */
208 outb(s->base+Hostcontrol, Kill);
209 outb(s->base+Slavecontrol, 0);
211 /* enable the smbus */
212 pcicfgw8(p, SMBconfig, IRQ9enable|SMBenable);