Statistics
| Branch: | Revision:

root / hw / acpi.c @ bee8d684

History | View | Annotate | Download (12.5 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 "hw.h"
20
#include "pc.h"
21
#include "pci.h"
22
#include "qemu-timer.h"
23
#include "sysemu.h"
24
#include "i2c.h"
25
#include "smbus.h"
26

    
27
//#define DEBUG
28

    
29
/* i82731AB (PIIX4) compatible power management function */
30
#define PM_FREQ 3579545
31

    
32
#define ACPI_DBG_IO_ADDR  0xb044
33

    
34
typedef struct PIIX4PMState {
35
    PCIDevice dev;
36
    uint16_t pmsts;
37
    uint16_t pmen;
38
    uint16_t pmcntrl;
39
    uint8_t apmc;
40
    uint8_t apms;
41
    QEMUTimer *tmr_timer;
42
    int64_t tmr_overflow_time;
43
    i2c_bus *smbus;
44
    uint8_t smb_stat;
45
    uint8_t smb_ctl;
46
    uint8_t smb_cmd;
47
    uint8_t smb_addr;
48
    uint8_t smb_data0;
49
    uint8_t smb_data1;
50
    uint8_t smb_data[32];
51
    uint8_t smb_index;
52
} PIIX4PMState;
53

    
54
#define RTC_EN (1 << 10)
55
#define PWRBTN_EN (1 << 8)
56
#define GBL_EN (1 << 5)
57
#define TMROF_EN (1 << 0)
58

    
59
#define SCI_EN (1 << 0)
60

    
61
#define SUS_EN (1 << 13)
62

    
63
#define ACPI_ENABLE 0xf1
64
#define ACPI_DISABLE 0xf0
65

    
66
#define SMBHSTSTS 0x00
67
#define SMBHSTCNT 0x02
68
#define SMBHSTCMD 0x03
69
#define SMBHSTADD 0x04
70
#define SMBHSTDAT0 0x05
71
#define SMBHSTDAT1 0x06
72
#define SMBBLKDAT 0x07
73

    
74
static uint32_t get_pmtmr(PIIX4PMState *s)
75
{
76
    uint32_t d;
77
    d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
78
    return d & 0xffffff;
79
}
80

    
81
static int get_pmsts(PIIX4PMState *s)
82
{
83
    int64_t d;
84
    int pmsts;
85
    pmsts = s->pmsts;
86
    d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
87
    if (d >= s->tmr_overflow_time)
88
        s->pmsts |= TMROF_EN;
89
    return pmsts;
90
}
91

    
92
static void pm_update_sci(PIIX4PMState *s)
93
{
94
    int sci_level, pmsts;
95
    int64_t expire_time;
96

    
97
    pmsts = get_pmsts(s);
98
    sci_level = (((pmsts & s->pmen) &
99
                  (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0);
100
    qemu_set_irq(s->dev.irq[0], sci_level);
101
    /* schedule a timer interruption if needed */
102
    if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) {
103
        expire_time = muldiv64(s->tmr_overflow_time, ticks_per_sec, PM_FREQ);
104
        qemu_mod_timer(s->tmr_timer, expire_time);
105
    } else {
106
        qemu_del_timer(s->tmr_timer);
107
    }
108
}
109

    
110
static void pm_tmr_timer(void *opaque)
111
{
112
    PIIX4PMState *s = opaque;
113
    pm_update_sci(s);
114
}
115

    
116
static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
117
{
118
    PIIX4PMState *s = opaque;
119
    addr &= 0x3f;
120
    switch(addr) {
121
    case 0x00:
122
        {
123
            int64_t d;
124
            int pmsts;
125
            pmsts = get_pmsts(s);
126
            if (pmsts & val & TMROF_EN) {
127
                /* if TMRSTS is reset, then compute the new overflow time */
128
                d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
129
                s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
130
            }
131
            s->pmsts &= ~val;
132
            pm_update_sci(s);
133
        }
134
        break;
135
    case 0x02:
136
        s->pmen = val;
137
        pm_update_sci(s);
138
        break;
139
    case 0x04:
140
        {
141
            int sus_typ;
142
            s->pmcntrl = val & ~(SUS_EN);
143
            if (val & SUS_EN) {
144
                /* change suspend type */
145
                sus_typ = (val >> 10) & 3;
146
                switch(sus_typ) {
147
                case 0: /* soft power off */
148
                    qemu_system_shutdown_request();
149
                    break;
150
                default:
151
                    break;
152
                }
153
            }
154
        }
155
        break;
156
    default:
157
        break;
158
    }
159
#ifdef DEBUG
160
    printf("PM writew port=0x%04x val=0x%04x\n", addr, val);
161
#endif
162
}
163

    
164
static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
165
{
166
    PIIX4PMState *s = opaque;
167
    uint32_t val;
168

    
169
    addr &= 0x3f;
170
    switch(addr) {
171
    case 0x00:
172
        val = get_pmsts(s);
173
        break;
174
    case 0x02:
175
        val = s->pmen;
176
        break;
177
    case 0x04:
178
        val = s->pmcntrl;
179
        break;
180
    default:
181
        val = 0;
182
        break;
183
    }
184
#ifdef DEBUG
185
    printf("PM readw port=0x%04x val=0x%04x\n", addr, val);
186
#endif
187
    return val;
188
}
189

    
190
static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
191
{
192
    //    PIIX4PMState *s = opaque;
193
    addr &= 0x3f;
194
#ifdef DEBUG
195
    printf("PM writel port=0x%04x val=0x%08x\n", addr, val);
196
#endif
197
}
198

    
199
static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
200
{
201
    PIIX4PMState *s = opaque;
202
    uint32_t val;
203

    
204
    addr &= 0x3f;
205
    switch(addr) {
206
    case 0x08:
207
        val = get_pmtmr(s);
208
        break;
209
    default:
210
        val = 0;
211
        break;
212
    }
213
#ifdef DEBUG
214
    printf("PM readl port=0x%04x val=0x%08x\n", addr, val);
215
#endif
216
    return val;
217
}
218

    
219
static void pm_smi_writeb(void *opaque, uint32_t addr, uint32_t val)
220
{
221
    PIIX4PMState *s = opaque;
222
    addr &= 1;
223
#ifdef DEBUG
224
    printf("pm_smi_writeb addr=0x%x val=0x%02x\n", addr, val);
225
#endif
226
    if (addr == 0) {
227
        s->apmc = val;
228

    
229
        /* ACPI specs 3.0, 4.7.2.5 */
230
        if (val == ACPI_ENABLE) {
231
            s->pmcntrl |= SCI_EN;
232
        } else if (val == ACPI_DISABLE) {
233
            s->pmcntrl &= ~SCI_EN;
234
        }
235

    
236
        if (s->dev.config[0x5b] & (1 << 1)) {
237
            cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI);
238
        }
239
    } else {
240
        s->apms = val;
241
    }
242
}
243

    
244
static uint32_t pm_smi_readb(void *opaque, uint32_t addr)
245
{
246
    PIIX4PMState *s = opaque;
247
    uint32_t val;
248

    
249
    addr &= 1;
250
    if (addr == 0) {
251
        val = s->apmc;
252
    } else {
253
        val = s->apms;
254
    }
255
#ifdef DEBUG
256
    printf("pm_smi_readb addr=0x%x val=0x%02x\n", addr, val);
257
#endif
258
    return val;
259
}
260

    
261
static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val)
262
{
263
#if defined(DEBUG)
264
    printf("ACPI: DBG: 0x%08x\n", val);
265
#endif
266
}
267

    
268
static void smb_transaction(PIIX4PMState *s)
269
{
270
    uint8_t prot = (s->smb_ctl >> 2) & 0x07;
271
    uint8_t read = s->smb_addr & 0x01;
272
    uint8_t cmd = s->smb_cmd;
273
    uint8_t addr = s->smb_addr >> 1;
274
    i2c_bus *bus = s->smbus;
275

    
276
#ifdef DEBUG
277
    printf("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
278
#endif
279
    switch(prot) {
280
    case 0x0:
281
        smbus_quick_command(bus, addr, read);
282
        break;
283
    case 0x1:
284
        if (read) {
285
            s->smb_data0 = smbus_receive_byte(bus, addr);
286
        } else {
287
            smbus_send_byte(bus, addr, cmd);
288
        }
289
        break;
290
    case 0x2:
291
        if (read) {
292
            s->smb_data0 = smbus_read_byte(bus, addr, cmd);
293
        } else {
294
            smbus_write_byte(bus, addr, cmd, s->smb_data0);
295
        }
296
        break;
297
    case 0x3:
298
        if (read) {
299
            uint16_t val;
300
            val = smbus_read_word(bus, addr, cmd);
301
            s->smb_data0 = val;
302
            s->smb_data1 = val >> 8;
303
        } else {
304
            smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0);
305
        }
306
        break;
307
    case 0x5:
308
        if (read) {
309
            s->smb_data0 = smbus_read_block(bus, addr, cmd, s->smb_data);
310
        } else {
311
            smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0);
312
        }
313
        break;
314
    default:
315
        goto error;
316
    }
317
    return;
318

    
319
  error:
320
    s->smb_stat |= 0x04;
321
}
322

    
323
static void smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
324
{
325
    PIIX4PMState *s = opaque;
326
    addr &= 0x3f;
327
#ifdef DEBUG
328
    printf("SMB writeb port=0x%04x val=0x%02x\n", addr, val);
329
#endif
330
    switch(addr) {
331
    case SMBHSTSTS:
332
        s->smb_stat = 0;
333
        s->smb_index = 0;
334
        break;
335
    case SMBHSTCNT:
336
        s->smb_ctl = val;
337
        if (val & 0x40)
338
            smb_transaction(s);
339
        break;
340
    case SMBHSTCMD:
341
        s->smb_cmd = val;
342
        break;
343
    case SMBHSTADD:
344
        s->smb_addr = val;
345
        break;
346
    case SMBHSTDAT0:
347
        s->smb_data0 = val;
348
        break;
349
    case SMBHSTDAT1:
350
        s->smb_data1 = val;
351
        break;
352
    case SMBBLKDAT:
353
        s->smb_data[s->smb_index++] = val;
354
        if (s->smb_index > 31)
355
            s->smb_index = 0;
356
        break;
357
    default:
358
        break;
359
    }
360
}
361

    
362
static uint32_t smb_ioport_readb(void *opaque, uint32_t addr)
363
{
364
    PIIX4PMState *s = opaque;
365
    uint32_t val;
366

    
367
    addr &= 0x3f;
368
    switch(addr) {
369
    case SMBHSTSTS:
370
        val = s->smb_stat;
371
        break;
372
    case SMBHSTCNT:
373
        s->smb_index = 0;
374
        val = s->smb_ctl & 0x1f;
375
        break;
376
    case SMBHSTCMD:
377
        val = s->smb_cmd;
378
        break;
379
    case SMBHSTADD:
380
        val = s->smb_addr;
381
        break;
382
    case SMBHSTDAT0:
383
        val = s->smb_data0;
384
        break;
385
    case SMBHSTDAT1:
386
        val = s->smb_data1;
387
        break;
388
    case SMBBLKDAT:
389
        val = s->smb_data[s->smb_index++];
390
        if (s->smb_index > 31)
391
            s->smb_index = 0;
392
        break;
393
    default:
394
        val = 0;
395
        break;
396
    }
397
#ifdef DEBUG
398
    printf("SMB readb port=0x%04x val=0x%02x\n", addr, val);
399
#endif
400
    return val;
401
}
402

    
403
static void pm_io_space_update(PIIX4PMState *s)
404
{
405
    uint32_t pm_io_base;
406

    
407
    if (s->dev.config[0x80] & 1) {
408
        pm_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x40));
409
        pm_io_base &= 0xffc0;
410

    
411
        /* XXX: need to improve memory and ioport allocation */
412
#if defined(DEBUG)
413
        printf("PM: mapping to 0x%x\n", pm_io_base);
414
#endif
415
        register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s);
416
        register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s);
417
        register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s);
418
        register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s);
419
    }
420
}
421

    
422
static void pm_write_config(PCIDevice *d,
423
                            uint32_t address, uint32_t val, int len)
424
{
425
    pci_default_write_config(d, address, val, len);
426
    if (address == 0x80)
427
        pm_io_space_update((PIIX4PMState *)d);
428
}
429

    
430
static void pm_save(QEMUFile* f,void *opaque)
431
{
432
    PIIX4PMState *s = opaque;
433

    
434
    pci_device_save(&s->dev, f);
435

    
436
    qemu_put_be16s(f, &s->pmsts);
437
    qemu_put_be16s(f, &s->pmen);
438
    qemu_put_be16s(f, &s->pmcntrl);
439
    qemu_put_8s(f, &s->apmc);
440
    qemu_put_8s(f, &s->apms);
441
    qemu_put_timer(f, s->tmr_timer);
442
    qemu_put_be64(f, s->tmr_overflow_time);
443
}
444

    
445
static int pm_load(QEMUFile* f,void* opaque,int version_id)
446
{
447
    PIIX4PMState *s = opaque;
448
    int ret;
449

    
450
    if (version_id > 1)
451
        return -EINVAL;
452

    
453
    ret = pci_device_load(&s->dev, f);
454
    if (ret < 0)
455
        return ret;
456

    
457
    qemu_get_be16s(f, &s->pmsts);
458
    qemu_get_be16s(f, &s->pmen);
459
    qemu_get_be16s(f, &s->pmcntrl);
460
    qemu_get_8s(f, &s->apmc);
461
    qemu_get_8s(f, &s->apms);
462
    qemu_get_timer(f, s->tmr_timer);
463
    s->tmr_overflow_time=qemu_get_be64(f);
464

    
465
    pm_io_space_update(s);
466

    
467
    return 0;
468
}
469

    
470
i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base)
471
{
472
    PIIX4PMState *s;
473
    uint8_t *pci_conf;
474

    
475
    s = (PIIX4PMState *)pci_register_device(bus,
476
                                         "PM", sizeof(PIIX4PMState),
477
                                         devfn, NULL, pm_write_config);
478
    pci_conf = s->dev.config;
479
    pci_conf[0x00] = 0x86;
480
    pci_conf[0x01] = 0x80;
481
    pci_conf[0x02] = 0x13;
482
    pci_conf[0x03] = 0x71;
483
    pci_conf[0x06] = 0x80;
484
    pci_conf[0x07] = 0x02;
485
    pci_conf[0x08] = 0x00; // revision number
486
    pci_conf[0x09] = 0x00;
487
    pci_conf[0x0a] = 0x80; // other bridge device
488
    pci_conf[0x0b] = 0x06; // bridge device
489
    pci_conf[0x0e] = 0x00; // header_type
490
    pci_conf[0x3d] = 0x01; // interrupt pin 1
491

    
492
    pci_conf[0x40] = 0x01; /* PM io base read only bit */
493

    
494
    register_ioport_write(0xb2, 2, 1, pm_smi_writeb, s);
495
    register_ioport_read(0xb2, 2, 1, pm_smi_readb, s);
496

    
497
    register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s);
498

    
499
    /* XXX: which specification is used ? The i82731AB has different
500
       mappings */
501
    pci_conf[0x5f] = (parallel_hds[0] != NULL ? 0x80 : 0) | 0x10;
502
    pci_conf[0x63] = 0x60;
503
    pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) |
504
        (serial_hds[1] != NULL ? 0x90 : 0);
505

    
506
    pci_conf[0x90] = smb_io_base | 1;
507
    pci_conf[0x91] = smb_io_base >> 8;
508
    pci_conf[0xd2] = 0x09;
509
    register_ioport_write(smb_io_base, 64, 1, smb_ioport_writeb, s);
510
    register_ioport_read(smb_io_base, 64, 1, smb_ioport_readb, s);
511

    
512
    s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s);
513

    
514
    register_savevm("piix4_pm", 0, 1, pm_save, pm_load, s);
515

    
516
    s->smbus = i2c_init_bus();
517
    return s->smbus;
518
}