]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/piix4smbus.c
fix typo
[plan9front.git] / sys / src / 9 / pc / piix4smbus.c
1 #include        "u.h"
2 #include        "../port/lib.h"
3 #include        "mem.h"
4 #include        "dat.h"
5 #include        "fns.h"
6 #include        "io.h"
7
8 /*
9  *      SMBus support for the PIIX4
10  */
11 enum
12 {
13         IntelVendID=    0x8086,
14         Piix4PMID=      0x7113,         /* PIIX4 power management function */
15
16         /* SMBus configuration registers (function 3) */
17         SMBbase=        0x90, /* 4 byte base address (bit 0 == 1, bit 3:1 == 0) */
18         SMBconfig=      0xd2,
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 */
23
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 */
36         Slv_bsy=        (1<<0),
37         Hostcontrol=    0x2,
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 */
46         Hostcommand=    0x3,
47         Hostaddress=    0x4,
48         AddressMask=    (0x7f<<1),      /* target address */
49         Read=           (1<<0),         /* 1 == read, 0 == write */
50         Hostdata0=      0x5,
51         Hostdata1=      0x6,
52         Blockdata=      0x7,
53         Slavecontrol=   0x8,
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 */
58         Shadowcommand=  0x9,
59         Slaveevent=     0xa,
60         Slavedata=      0xc,
61 };
62
63 static struct
64 {
65         int     rw;
66         int     cmd;
67         int     len;
68         int     proto;
69 } proto[] =
70 {
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 },
78 };
79
80 static void
81 transact(SMBus *s, int type, int addr, int cmd, uchar *data)
82 {
83         int tries, status;
84         char err[256];
85
86         if(type < 0 || type > nelem(proto))
87                 panic("piix4smbus: illegal transaction type %d", type);
88
89         if(waserror()){
90                 qunlock(s);
91                 nexterror();
92         }
93         qlock(s);
94
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)
98                         break;
99                 sched();
100         }
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)
106                                 break;
107                         sched();
108                 }
109                 if(tries >= 1000000){
110                         snprint(err, sizeof(err), "SMBus jammed: %2.2ux", inb(s->base+Hoststatus));
111                         error(err);
112                 }
113         }
114
115         /* set up for transaction */
116         outb(s->base+Hostaddress, (addr<<1)|proto[type].rw);
117         if(proto[type].cmd)
118                 outb(s->base+Hostcommand, cmd);
119         if(proto[type].rw != Read){
120                 switch(proto[type].len){
121                 case 2:
122                         outb(s->base+Hostdata1, data[1]);
123                         /* fall through */
124                 case 1:
125                         outb(s->base+Hostdata0, data[0]);
126                         break;
127                 }
128         }
129
130
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);
134
135         /* wait for completion */
136         status = 0;
137         for(tries = 0; tries < 1000000; tries++){
138                 status = inb(s->base+Hoststatus);
139                 if(status & (Failed|Bus_error|Dev_error|Host_complete))
140                         break;
141                 sched();
142         }
143         if((status & Host_complete) == 0){
144                 snprint(err, sizeof(err), "SMBus request failed: %2.2ux", status);
145                 error(err);
146         }
147
148         /* get results */
149         if(proto[type].rw == Read){
150                 switch(proto[type].len){
151                 case 2:
152                         data[1] = inb(s->base+Hostdata1);
153                         /* fall through */
154                 case 1:
155                         data[0] = inb(s->base+Hostdata0);
156                         break;
157                 }
158         }
159         qunlock(s);
160         poperror();
161 }
162
163 static SMBus smbusproto =
164 {
165         .transact = transact,
166 };
167
168 /*
169  *  return 0 if this is a piix4 with an smbus interface
170  */
171 SMBus*
172 piix4smbus(void)
173 {
174         Pcidev *p;
175         static SMBus *s;
176
177         if(s != nil)
178                 return s;
179
180         p = pcimatch(nil, IntelVendID, Piix4PMID);
181         if(p == nil)
182                 return nil;
183
184         s = malloc(sizeof(*s));
185         if(s == nil)
186                 panic("piix4smbus: no memory for SMBus");
187         memmove(s, &smbusproto, sizeof(*s));
188         s->arg = p;
189
190         /* disable the smbus */
191         pcicfgw8(p, SMBconfig, IRQ9enable|0);
192
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");
198                 if(s->base < 0){
199                         free(s);
200                         print("piix4smbus: can't allocate io port\n");
201                         return nil;
202                 }
203 print("SMB base ialloc is 0x%lux\n", s->base);
204                 pcicfgw32(p, SMBbase, s->base|1);
205         }
206
207         /* disable SMBus interrupts, abort any transaction in progress */
208         outb(s->base+Hostcontrol, Kill);
209         outb(s->base+Slavecontrol, 0);
210
211         /* enable the smbus */
212         pcicfgw8(p, SMBconfig, IRQ9enable|SMBenable);
213
214         return s;
215 }