I2C/SMBus framework.
[qemu] / hw / acpi.c
1 /*
2  * ACPI implementation
3  * 
4  * Copyright (c) 2006 Fabrice Bellard
5  * 
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License version 2 as published by the Free Software Foundation.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 #include "vl.h"
20
21 //#define DEBUG
22
23 /* i82731AB (PIIX4) compatible power management function */
24 #define PM_FREQ 3579545
25
26 #define ACPI_DBG_IO_ADDR  0xb044
27 #define SMB_IO_BASE       0xb100
28
29 typedef struct PIIX4PMState {
30     PCIDevice dev;
31     uint16_t pmsts;
32     uint16_t pmen;
33     uint16_t pmcntrl;
34     uint8_t apmc;
35     uint8_t apms;
36     QEMUTimer *tmr_timer;
37     int64_t tmr_overflow_time;
38     i2c_bus *smbus;
39     uint8_t smb_stat;
40     uint8_t smb_ctl;
41     uint8_t smb_cmd;
42     uint8_t smb_addr;
43     uint8_t smb_data0;
44     uint8_t smb_data1;
45     uint8_t smb_data[32];
46     uint8_t smb_index;
47 } PIIX4PMState;
48
49 #define RTC_EN (1 << 10)
50 #define PWRBTN_EN (1 << 8)
51 #define GBL_EN (1 << 5)
52 #define TMROF_EN (1 << 0)
53
54 #define SCI_EN (1 << 0)
55
56 #define SUS_EN (1 << 13)
57
58 #define SMBHSTSTS 0x00
59 #define SMBHSTCNT 0x02
60 #define SMBHSTCMD 0x03
61 #define SMBHSTADD 0x04
62 #define SMBHSTDAT0 0x05
63 #define SMBHSTDAT1 0x06
64 #define SMBBLKDAT 0x07
65
66 static uint32_t get_pmtmr(PIIX4PMState *s)
67 {
68     uint32_t d;
69     d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
70     return d & 0xffffff;
71 }
72
73 static int get_pmsts(PIIX4PMState *s)
74 {
75     int64_t d;
76     int pmsts;
77     pmsts = s->pmsts;
78     d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
79     if (d >= s->tmr_overflow_time)
80         s->pmsts |= TMROF_EN;
81     return pmsts;
82 }
83
84 static void pm_update_sci(PIIX4PMState *s)
85 {
86     int sci_level, pmsts;
87     int64_t expire_time;
88     
89     pmsts = get_pmsts(s);
90     sci_level = (((pmsts & s->pmen) & 
91                   (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0);
92     qemu_set_irq(s->dev.irq[0], sci_level);
93     /* schedule a timer interruption if needed */
94     if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) {
95         expire_time = muldiv64(s->tmr_overflow_time, ticks_per_sec, PM_FREQ);
96         qemu_mod_timer(s->tmr_timer, expire_time);
97     } else {
98         qemu_del_timer(s->tmr_timer);
99     }
100 }
101
102 static void pm_tmr_timer(void *opaque)
103 {
104     PIIX4PMState *s = opaque;
105     pm_update_sci(s);
106 }
107
108 static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
109 {
110     PIIX4PMState *s = opaque;
111     addr &= 0x3f;
112     switch(addr) {
113     case 0x00:
114         {
115             int64_t d;
116             int pmsts;
117             pmsts = get_pmsts(s);
118             if (pmsts & val & TMROF_EN) {
119                 /* if TMRSTS is reset, then compute the new overflow time */
120                 d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
121                 s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
122             }
123             s->pmsts &= ~val;
124             pm_update_sci(s);
125         }
126         break;
127     case 0x02:
128         s->pmen = val;
129         pm_update_sci(s);
130         break;
131     case 0x04:
132         {
133             int sus_typ;
134             s->pmcntrl = val & ~(SUS_EN);
135             if (val & SUS_EN) {
136                 /* change suspend type */
137                 sus_typ = (val >> 10) & 3;
138                 switch(sus_typ) {
139                 case 0: /* soft power off */
140                     qemu_system_shutdown_request();
141                     break;
142                 default:
143                     break;
144                 }
145             }
146         }
147         break;
148     default:
149         break;
150     }
151 #ifdef DEBUG
152     printf("PM writew port=0x%04x val=0x%04x\n", addr, val);
153 #endif
154 }
155
156 static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
157 {
158     PIIX4PMState *s = opaque;
159     uint32_t val;
160
161     addr &= 0x3f;
162     switch(addr) {
163     case 0x00:
164         val = get_pmsts(s);
165         break;
166     case 0x02:
167         val = s->pmen;
168         break;
169     case 0x04:
170         val = s->pmcntrl;
171         break;
172     default:
173         val = 0;
174         break;
175     }
176 #ifdef DEBUG
177     printf("PM readw port=0x%04x val=0x%04x\n", addr, val);
178 #endif
179     return val;
180 }
181
182 static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
183 {
184     //    PIIX4PMState *s = opaque;
185     addr &= 0x3f;
186 #ifdef DEBUG
187     printf("PM writel port=0x%04x val=0x%08x\n", addr, val);
188 #endif
189 }
190
191 static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
192 {
193     PIIX4PMState *s = opaque;
194     uint32_t val;
195
196     addr &= 0x3f;
197     switch(addr) {
198     case 0x08:
199         val = get_pmtmr(s);
200         break;
201     default:
202         val = 0;
203         break;
204     }
205 #ifdef DEBUG
206     printf("PM readl port=0x%04x val=0x%08x\n", addr, val);
207 #endif
208     return val;
209 }
210
211 static void pm_smi_writeb(void *opaque, uint32_t addr, uint32_t val)
212 {
213     PIIX4PMState *s = opaque;
214     addr &= 1;
215 #ifdef DEBUG
216     printf("pm_smi_writeb addr=0x%x val=0x%02x\n", addr, val);
217 #endif
218     if (addr == 0) {
219         s->apmc = val;
220         if (s->dev.config[0x5b] & (1 << 1)) {
221             cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI);
222         }
223     } else {
224         s->apms = val;
225     }
226 }
227
228 static uint32_t pm_smi_readb(void *opaque, uint32_t addr)
229 {
230     PIIX4PMState *s = opaque;
231     uint32_t val;
232     
233     addr &= 1;
234     if (addr == 0) {
235         val = s->apmc;
236     } else {
237         val = s->apms;
238     }
239 #ifdef DEBUG
240     printf("pm_smi_readb addr=0x%x val=0x%02x\n", addr, val);
241 #endif
242     return val;
243 }
244
245 static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val)
246 {
247 #if defined(DEBUG)
248     printf("ACPI: DBG: 0x%08x\n", val);
249 #endif
250 }
251
252 static void smb_transaction(PIIX4PMState *s)
253 {
254     uint8_t prot = (s->smb_ctl >> 2) & 0x07;
255     uint8_t read = s->smb_addr & 0x01;
256     uint8_t cmd = s->smb_cmd;
257     uint8_t addr = s->smb_addr >> 1;
258     i2c_bus *bus = s->smbus;
259
260 #ifdef DEBUG
261     printf("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
262 #endif
263     switch(prot) {
264     case 0x0:
265         smbus_quick_command(bus, addr, read);
266         break;
267     case 0x1:
268         if (read) {
269             s->smb_data0 = smbus_receive_byte(bus, addr);
270         } else {
271             smbus_send_byte(bus, addr, cmd);
272         }
273         break;
274     case 0x2:
275         if (read) {
276             s->smb_data0 = smbus_read_byte(bus, addr, cmd);
277         } else {
278             smbus_write_byte(bus, addr, cmd, s->smb_data0);
279         }
280         break;
281     case 0x3:
282         if (read) {
283             uint16_t val;
284             val = smbus_read_word(bus, addr, cmd);
285             s->smb_data0 = val;
286             s->smb_data1 = val >> 8;
287         } else {
288             smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0);
289         }
290         break;
291     case 0x5:
292         if (read) {
293             s->smb_data0 = smbus_read_block(bus, addr, cmd, s->smb_data);
294         } else {
295             smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0);
296         }
297         break;
298     default:
299         goto error;
300     }
301     return;
302
303   error:
304     s->smb_stat |= 0x04;
305 }
306
307 static void smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
308 {
309     PIIX4PMState *s = opaque;
310     addr &= 0x3f;
311 #ifdef DEBUG
312     printf("SMB writeb port=0x%04x val=0x%02x\n", addr, val);
313 #endif
314     switch(addr) {
315     case SMBHSTSTS:
316         s->smb_stat = 0;
317         s->smb_index = 0;
318         break;
319     case SMBHSTCNT:
320         s->smb_ctl = val;
321         if (val & 0x40)
322             smb_transaction(s);
323         break;
324     case SMBHSTCMD:
325         s->smb_cmd = val;
326         break;
327     case SMBHSTADD:
328         s->smb_addr = val;
329         break;
330     case SMBHSTDAT0:
331         s->smb_data0 = val;
332         break;
333     case SMBHSTDAT1:
334         s->smb_data1 = val;
335         break;
336     case SMBBLKDAT:
337         s->smb_data[s->smb_index++] = val;
338         if (s->smb_index > 31)
339             s->smb_index = 0;
340         break;
341     default:
342         break;
343     }
344 }
345
346 static uint32_t smb_ioport_readb(void *opaque, uint32_t addr)
347 {
348     PIIX4PMState *s = opaque;
349     uint32_t val;
350
351     addr &= 0x3f;
352     switch(addr) {
353     case SMBHSTSTS:
354         val = s->smb_stat;
355         break;
356     case SMBHSTCNT:
357         s->smb_index = 0;
358         val = s->smb_ctl & 0x1f;
359         break;
360     case SMBHSTCMD:
361         val = s->smb_cmd;
362         break;
363     case SMBHSTADD:
364         val = s->smb_addr;
365         break;
366     case SMBHSTDAT0:
367         val = s->smb_data0;
368         break;
369     case SMBHSTDAT1:
370         val = s->smb_data1;
371         break;
372     case SMBBLKDAT:
373         val = s->smb_data[s->smb_index++];
374         if (s->smb_index > 31)
375             s->smb_index = 0;
376         break;
377     default:
378         val = 0;
379         break;
380     }
381 #ifdef DEBUG
382     printf("SMB readb port=0x%04x val=0x%02x\n", addr, val);
383 #endif
384     return val;
385 }
386
387 static void pm_io_space_update(PIIX4PMState *s)
388 {
389     uint32_t pm_io_base;
390
391     if (s->dev.config[0x80] & 1) {
392         pm_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x40));
393         pm_io_base &= 0xfffe;
394
395         /* XXX: need to improve memory and ioport allocation */
396 #if defined(DEBUG)
397         printf("PM: mapping to 0x%x\n", pm_io_base);
398 #endif
399         register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s);
400         register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s);
401         register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s);
402         register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s);
403     }
404 }
405
406 static void pm_write_config(PCIDevice *d, 
407                             uint32_t address, uint32_t val, int len)
408 {
409     pci_default_write_config(d, address, val, len);
410     if (address == 0x80)
411         pm_io_space_update((PIIX4PMState *)d);
412 }
413
414 static void pm_save(QEMUFile* f,void *opaque)
415 {
416     PIIX4PMState *s = opaque;
417
418     pci_device_save(&s->dev, f);
419
420     qemu_put_be16s(f, &s->pmsts);
421     qemu_put_be16s(f, &s->pmen);
422     qemu_put_be16s(f, &s->pmcntrl);
423     qemu_put_8s(f, &s->apmc);
424     qemu_put_8s(f, &s->apms);
425     qemu_put_timer(f, s->tmr_timer);
426     qemu_put_be64s(f, &s->tmr_overflow_time);
427 }
428
429 static int pm_load(QEMUFile* f,void* opaque,int version_id)
430 {
431     PIIX4PMState *s = opaque;
432     int ret;
433
434     if (version_id > 1)
435         return -EINVAL;
436
437     ret = pci_device_load(&s->dev, f);
438     if (ret < 0)
439         return ret;
440
441     qemu_get_be16s(f, &s->pmsts);
442     qemu_get_be16s(f, &s->pmen);
443     qemu_get_be16s(f, &s->pmcntrl);
444     qemu_get_8s(f, &s->apmc);
445     qemu_get_8s(f, &s->apms);
446     qemu_get_timer(f, s->tmr_timer);
447     qemu_get_be64s(f, &s->tmr_overflow_time);
448
449     pm_io_space_update(s);
450
451     return 0;
452 }
453
454 i2c_bus *piix4_pm_init(PCIBus *bus, int devfn)
455 {
456     PIIX4PMState *s;
457     uint8_t *pci_conf;
458     uint32_t smb_io_base;
459
460     s = (PIIX4PMState *)pci_register_device(bus,
461                                          "PM", sizeof(PIIX4PMState),
462                                          devfn, NULL, pm_write_config);
463     pci_conf = s->dev.config;
464     pci_conf[0x00] = 0x86;
465     pci_conf[0x01] = 0x80;
466     pci_conf[0x02] = 0x13;
467     pci_conf[0x03] = 0x71;
468     pci_conf[0x08] = 0x00; // revision number
469     pci_conf[0x09] = 0x00;
470     pci_conf[0x0a] = 0x80; // other bridge device
471     pci_conf[0x0b] = 0x06; // bridge device
472     pci_conf[0x0e] = 0x00; // header_type
473     pci_conf[0x3d] = 0x01; // interrupt pin 1
474     
475     pci_conf[0x40] = 0x01; /* PM io base read only bit */
476     
477     register_ioport_write(0xb2, 2, 1, pm_smi_writeb, s);
478     register_ioport_read(0xb2, 2, 1, pm_smi_readb, s);
479
480     register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s);
481
482     /* XXX: which specification is used ? The i82731AB has different
483        mappings */
484     pci_conf[0x5f] = (parallel_hds[0] != NULL ? 0x80 : 0) | 0x10;
485     pci_conf[0x63] = 0x60;
486     pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) |
487         (serial_hds[1] != NULL ? 0x90 : 0);
488
489     smb_io_base = SMB_IO_BASE;
490     pci_conf[0x90] = smb_io_base | 1;
491     pci_conf[0x91] = smb_io_base >> 8;
492     pci_conf[0xd2] = 0x09;
493     register_ioport_write(smb_io_base, 64, 1, smb_ioport_writeb, s);
494     register_ioport_read(smb_io_base, 64, 1, smb_ioport_readb, s);
495
496     s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s);
497
498     register_savevm("piix4_pm", 0, 1, pm_save, pm_load, s);
499
500     s->smbus = i2c_init_bus();
501     return s->smbus;
502 }