Revision 3fffc223 hw/acpi.c
b/hw/acpi.c | ||
---|---|---|
24 | 24 |
#define PM_FREQ 3579545 |
25 | 25 |
|
26 | 26 |
#define ACPI_DBG_IO_ADDR 0xb044 |
27 |
#define SMB_IO_BASE 0xb100 |
|
27 | 28 |
|
28 | 29 |
typedef struct PIIX4PMState { |
29 | 30 |
PCIDevice dev; |
... | ... | |
34 | 35 |
uint8_t apms; |
35 | 36 |
QEMUTimer *tmr_timer; |
36 | 37 |
int64_t tmr_overflow_time; |
38 |
SMBusDevice *smb_dev[128]; |
|
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; |
|
37 | 47 |
} PIIX4PMState; |
38 | 48 |
|
39 | 49 |
#define RTC_EN (1 << 10) |
... | ... | |
45 | 55 |
|
46 | 56 |
#define SUS_EN (1 << 13) |
47 | 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 |
/* Note: only used for piix4_smbus_register_device */ |
|
67 |
static PIIX4PMState *piix4_pm_state; |
|
68 |
|
|
48 | 69 |
static uint32_t get_pmtmr(PIIX4PMState *s) |
49 | 70 |
{ |
50 | 71 |
uint32_t d; |
... | ... | |
231 | 252 |
#endif |
232 | 253 |
} |
233 | 254 |
|
255 |
static void smb_transaction(PIIX4PMState *s) |
|
256 |
{ |
|
257 |
uint8_t prot = (s->smb_ctl >> 2) & 0x07; |
|
258 |
uint8_t read = s->smb_addr & 0x01; |
|
259 |
uint8_t cmd = s->smb_cmd; |
|
260 |
uint8_t addr = s->smb_addr >> 1; |
|
261 |
SMBusDevice *dev = s->smb_dev[addr]; |
|
262 |
|
|
263 |
#ifdef DEBUG |
|
264 |
printf("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot); |
|
265 |
#endif |
|
266 |
if (!dev) goto error; |
|
267 |
|
|
268 |
switch(prot) { |
|
269 |
case 0x0: |
|
270 |
if (!dev->quick_cmd) goto error; |
|
271 |
(*dev->quick_cmd)(dev, read); |
|
272 |
break; |
|
273 |
case 0x1: |
|
274 |
if (read) { |
|
275 |
if (!dev->receive_byte) goto error; |
|
276 |
s->smb_data0 = (*dev->receive_byte)(dev); |
|
277 |
} |
|
278 |
else { |
|
279 |
if (!dev->send_byte) goto error; |
|
280 |
(*dev->send_byte)(dev, cmd); |
|
281 |
} |
|
282 |
break; |
|
283 |
case 0x2: |
|
284 |
if (read) { |
|
285 |
if (!dev->read_byte) goto error; |
|
286 |
s->smb_data0 = (*dev->read_byte)(dev, cmd); |
|
287 |
} |
|
288 |
else { |
|
289 |
if (!dev->write_byte) goto error; |
|
290 |
(*dev->write_byte)(dev, cmd, s->smb_data0); |
|
291 |
} |
|
292 |
break; |
|
293 |
case 0x3: |
|
294 |
if (read) { |
|
295 |
uint16_t val; |
|
296 |
if (!dev->read_word) goto error; |
|
297 |
val = (*dev->read_word)(dev, cmd); |
|
298 |
s->smb_data0 = val; |
|
299 |
s->smb_data1 = val >> 8; |
|
300 |
} |
|
301 |
else { |
|
302 |
if (!dev->write_word) goto error; |
|
303 |
(*dev->write_word)(dev, cmd, (s->smb_data1 << 8) | s->smb_data0); |
|
304 |
} |
|
305 |
break; |
|
306 |
case 0x5: |
|
307 |
if (read) { |
|
308 |
if (!dev->read_block) goto error; |
|
309 |
s->smb_data0 = (*dev->read_block)(dev, cmd, s->smb_data); |
|
310 |
} |
|
311 |
else { |
|
312 |
if (!dev->write_block) goto error; |
|
313 |
(*dev->write_block)(dev, cmd, s->smb_data0, s->smb_data); |
|
314 |
} |
|
315 |
break; |
|
316 |
default: |
|
317 |
goto error; |
|
318 |
} |
|
319 |
return; |
|
320 |
|
|
321 |
error: |
|
322 |
s->smb_stat |= 0x04; |
|
323 |
} |
|
324 |
|
|
325 |
static void smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) |
|
326 |
{ |
|
327 |
PIIX4PMState *s = opaque; |
|
328 |
addr &= 0x3f; |
|
329 |
#ifdef DEBUG |
|
330 |
printf("SMB writeb port=0x%04x val=0x%02x\n", addr, val); |
|
331 |
#endif |
|
332 |
switch(addr) { |
|
333 |
case SMBHSTSTS: |
|
334 |
s->smb_stat = 0; |
|
335 |
s->smb_index = 0; |
|
336 |
break; |
|
337 |
case SMBHSTCNT: |
|
338 |
s->smb_ctl = val; |
|
339 |
if (val & 0x40) |
|
340 |
smb_transaction(s); |
|
341 |
break; |
|
342 |
case SMBHSTCMD: |
|
343 |
s->smb_cmd = val; |
|
344 |
break; |
|
345 |
case SMBHSTADD: |
|
346 |
s->smb_addr = val; |
|
347 |
break; |
|
348 |
case SMBHSTDAT0: |
|
349 |
s->smb_data0 = val; |
|
350 |
break; |
|
351 |
case SMBHSTDAT1: |
|
352 |
s->smb_data1 = val; |
|
353 |
break; |
|
354 |
case SMBBLKDAT: |
|
355 |
s->smb_data[s->smb_index++] = val; |
|
356 |
if (s->smb_index > 31) |
|
357 |
s->smb_index = 0; |
|
358 |
break; |
|
359 |
default: |
|
360 |
break; |
|
361 |
} |
|
362 |
} |
|
363 |
|
|
364 |
static uint32_t smb_ioport_readb(void *opaque, uint32_t addr) |
|
365 |
{ |
|
366 |
PIIX4PMState *s = opaque; |
|
367 |
uint32_t val; |
|
368 |
|
|
369 |
addr &= 0x3f; |
|
370 |
switch(addr) { |
|
371 |
case SMBHSTSTS: |
|
372 |
val = s->smb_stat; |
|
373 |
break; |
|
374 |
case SMBHSTCNT: |
|
375 |
s->smb_index = 0; |
|
376 |
val = s->smb_ctl & 0x1f; |
|
377 |
break; |
|
378 |
case SMBHSTCMD: |
|
379 |
val = s->smb_cmd; |
|
380 |
break; |
|
381 |
case SMBHSTADD: |
|
382 |
val = s->smb_addr; |
|
383 |
break; |
|
384 |
case SMBHSTDAT0: |
|
385 |
val = s->smb_data0; |
|
386 |
break; |
|
387 |
case SMBHSTDAT1: |
|
388 |
val = s->smb_data1; |
|
389 |
break; |
|
390 |
case SMBBLKDAT: |
|
391 |
val = s->smb_data[s->smb_index++]; |
|
392 |
if (s->smb_index > 31) |
|
393 |
s->smb_index = 0; |
|
394 |
break; |
|
395 |
default: |
|
396 |
val = 0; |
|
397 |
break; |
|
398 |
} |
|
399 |
#ifdef DEBUG |
|
400 |
printf("SMB readb port=0x%04x val=0x%02x\n", addr, val); |
|
401 |
#endif |
|
402 |
return val; |
|
403 |
} |
|
404 |
|
|
234 | 405 |
static void pm_io_space_update(PIIX4PMState *s) |
235 | 406 |
{ |
236 | 407 |
uint32_t pm_io_base; |
... | ... | |
302 | 473 |
{ |
303 | 474 |
PIIX4PMState *s; |
304 | 475 |
uint8_t *pci_conf; |
476 |
uint32_t pm_io_base, smb_io_base; |
|
305 | 477 |
|
306 | 478 |
s = (PIIX4PMState *)pci_register_device(bus, |
307 | 479 |
"PM", sizeof(PIIX4PMState), |
... | ... | |
332 | 504 |
pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) | |
333 | 505 |
(serial_hds[1] != NULL ? 0x90 : 0); |
334 | 506 |
|
507 |
smb_io_base = SMB_IO_BASE; |
|
508 |
pci_conf[0x90] = smb_io_base | 1; |
|
509 |
pci_conf[0x91] = smb_io_base >> 8; |
|
510 |
pci_conf[0xd2] = 0x09; |
|
511 |
register_ioport_write(smb_io_base, 64, 1, smb_ioport_writeb, s); |
|
512 |
register_ioport_read(smb_io_base, 64, 1, smb_ioport_readb, s); |
|
513 |
|
|
335 | 514 |
s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s); |
336 | 515 |
|
337 | 516 |
register_savevm("piix4_pm", 0, 1, pm_save, pm_load, s); |
517 |
piix4_pm_state = s; |
|
518 |
} |
|
519 |
|
|
520 |
void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr) |
|
521 |
{ |
|
522 |
piix4_pm_state->smb_dev[addr] = dev; |
|
338 | 523 |
} |
Also available in: Unified diff