Statistics
| Branch: | Revision:

root / hw / acpi.c @ 0ff596d0

History | View | Annotate | Download (12.2 kB)

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
}