commit
79c884d7e4
@ -0,0 +1,176 @@ |
||||
/*
|
||||
* Copyright (C) 2015, Saket Sinha <saket.sinha89@gmail.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/acpi_table.h> |
||||
#include <asm/ioapic.h> |
||||
#include <asm/tables.h> |
||||
|
||||
void acpi_create_fadt(struct acpi_fadt *fadt, struct acpi_facs *facs, |
||||
void *dsdt) |
||||
{ |
||||
acpi_header_t *header = &(fadt->header); |
||||
u16 pmbase; |
||||
|
||||
pci_dev_t bdf = PCI_BDF(0, 0x1f, 0); |
||||
pci_read_config_word(bdf, 0x40, &pmbase); |
||||
|
||||
/*
|
||||
* TODO(saket.sinha89@gmail.com): wrong value |
||||
* of pmbase by above function. Hard-coding it to |
||||
* correct value. Since no PCI register is |
||||
* programmed Power Management Interface is |
||||
* not working |
||||
*/ |
||||
pmbase = 0x0600; |
||||
|
||||
memset((void *)fadt, 0, sizeof(struct acpi_fadt)); |
||||
memcpy(header->signature, "FACP", 4); |
||||
header->length = sizeof(struct acpi_fadt); |
||||
header->revision = 3; |
||||
memcpy(header->oem_id, OEM_ID, 6); |
||||
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); |
||||
memcpy(header->asl_compiler_id, ASLC, 4); |
||||
header->asl_compiler_revision = 0; |
||||
|
||||
fadt->firmware_ctrl = (unsigned long) facs; |
||||
fadt->dsdt = (unsigned long) dsdt; |
||||
fadt->model = 0x00; |
||||
fadt->preferred_pm_profile = PM_MOBILE; |
||||
fadt->sci_int = 0x9; |
||||
fadt->smi_cmd = 0; |
||||
fadt->acpi_enable = 0; |
||||
fadt->acpi_disable = 0; |
||||
fadt->s4bios_req = 0x0; |
||||
fadt->pstate_cnt = 0; |
||||
fadt->pm1a_evt_blk = pmbase; |
||||
fadt->pm1b_evt_blk = 0x0; |
||||
fadt->pm1a_cnt_blk = pmbase + 0x4; |
||||
fadt->pm1b_cnt_blk = 0x0; |
||||
fadt->pm2_cnt_blk = pmbase + 0x50; |
||||
fadt->pm_tmr_blk = pmbase + 0x8; |
||||
fadt->gpe0_blk = pmbase + 0x20; |
||||
fadt->gpe1_blk = 0; |
||||
fadt->pm1_evt_len = 4; |
||||
/*
|
||||
* Upper word is reserved and |
||||
* Linux complains about 32 bit |
||||
*/ |
||||
fadt->pm1_cnt_len = 2; |
||||
fadt->pm2_cnt_len = 1; |
||||
fadt->pm_tmr_len = 4; |
||||
fadt->gpe0_blk_len = 16; |
||||
fadt->gpe1_blk_len = 0; |
||||
fadt->gpe1_base = 0; |
||||
fadt->cst_cnt = 0; |
||||
fadt->p_lvl2_lat = 1; |
||||
fadt->p_lvl3_lat = 0x39; |
||||
fadt->flush_size = 0; |
||||
fadt->flush_stride = 0; |
||||
fadt->duty_offset = 1; |
||||
fadt->duty_width = 3; |
||||
fadt->day_alrm = 0xd; |
||||
fadt->mon_alrm = 0x00; |
||||
fadt->century = 0x32; |
||||
fadt->iapc_boot_arch = 0x00; |
||||
fadt->flags = ACPI_FADT_WBINVD | ACPI_FADT_C1_SUPPORTED | |
||||
ACPI_FADT_SLEEP_BUTTON | ACPI_FADT_S4_RTC_WAKE | |
||||
ACPI_FADT_DOCKING_SUPPORTED | ACPI_FADT_RESET_REGISTER | |
||||
ACPI_FADT_PLATFORM_CLOCK; |
||||
fadt->reset_reg.space_id = ACPI_ADDRESS_SPACE_IO; |
||||
fadt->reset_reg.bit_width = 8; |
||||
fadt->reset_reg.bit_offset = 0; |
||||
fadt->reset_reg.resv = 0; |
||||
fadt->reset_reg.addrl = 0xcf9; |
||||
fadt->reset_reg.addrh = 0; |
||||
fadt->reset_value = 0x06; |
||||
/*
|
||||
* Set X_FIRMWARE_CTRL only if FACS is |
||||
* above 4GB. If X_FIRMWARE_CTRL is set, |
||||
* then FIRMWARE_CTRL must be zero |
||||
*/ |
||||
fadt->x_firmware_ctl_l = 0; |
||||
fadt->x_firmware_ctl_h = 0; |
||||
fadt->x_dsdt_l = (unsigned long)dsdt; |
||||
fadt->x_dsdt_h = 0; |
||||
fadt->x_pm1a_evt_blk.space_id = 1; |
||||
fadt->x_pm1a_evt_blk.bit_width = 32; |
||||
fadt->x_pm1a_evt_blk.bit_offset = 0; |
||||
fadt->x_pm1a_evt_blk.resv = 0; |
||||
fadt->x_pm1a_evt_blk.addrl = pmbase; |
||||
fadt->x_pm1a_evt_blk.addrh = 0x0; |
||||
fadt->x_pm1b_evt_blk.space_id = 0; |
||||
fadt->x_pm1b_evt_blk.bit_width = 0; |
||||
fadt->x_pm1b_evt_blk.bit_offset = 0; |
||||
fadt->x_pm1b_evt_blk.resv = 0; |
||||
fadt->x_pm1b_evt_blk.addrl = 0x0; |
||||
fadt->x_pm1b_evt_blk.addrh = 0x0; |
||||
fadt->x_pm1a_cnt_blk.space_id = 1; |
||||
/*
|
||||
* Upper word is reserved and |
||||
* Linux complains about 32 bit |
||||
*/ |
||||
fadt->x_pm1a_cnt_blk.bit_width = 16; |
||||
fadt->x_pm1a_cnt_blk.bit_offset = 0; |
||||
fadt->x_pm1a_cnt_blk.resv = 0; |
||||
fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4; |
||||
fadt->x_pm1a_cnt_blk.addrh = 0x0; |
||||
fadt->x_pm1b_cnt_blk.space_id = 0; |
||||
fadt->x_pm1b_cnt_blk.bit_width = 0; |
||||
fadt->x_pm1b_cnt_blk.bit_offset = 0; |
||||
fadt->x_pm1b_cnt_blk.resv = 0; |
||||
fadt->x_pm1b_cnt_blk.addrl = 0x0; |
||||
fadt->x_pm1b_cnt_blk.addrh = 0x0; |
||||
fadt->x_pm2_cnt_blk.space_id = 1; |
||||
fadt->x_pm2_cnt_blk.bit_width = 8; |
||||
fadt->x_pm2_cnt_blk.bit_offset = 0; |
||||
fadt->x_pm2_cnt_blk.resv = 0; |
||||
fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50; |
||||
fadt->x_pm2_cnt_blk.addrh = 0x0; |
||||
fadt->x_pm_tmr_blk.space_id = 1; |
||||
fadt->x_pm_tmr_blk.bit_width = 32; |
||||
fadt->x_pm_tmr_blk.bit_offset = 0; |
||||
fadt->x_pm_tmr_blk.resv = 0; |
||||
fadt->x_pm_tmr_blk.addrl = pmbase + 0x8; |
||||
fadt->x_pm_tmr_blk.addrh = 0x0; |
||||
fadt->x_gpe0_blk.space_id = 1; |
||||
fadt->x_gpe0_blk.bit_width = 128; |
||||
fadt->x_gpe0_blk.bit_offset = 0; |
||||
fadt->x_gpe0_blk.resv = 0; |
||||
fadt->x_gpe0_blk.addrl = pmbase + 0x20; |
||||
fadt->x_gpe0_blk.addrh = 0x0; |
||||
fadt->x_gpe1_blk.space_id = 0; |
||||
fadt->x_gpe1_blk.bit_width = 0; |
||||
fadt->x_gpe1_blk.bit_offset = 0; |
||||
fadt->x_gpe1_blk.resv = 0; |
||||
fadt->x_gpe1_blk.addrl = 0x0; |
||||
fadt->x_gpe1_blk.addrh = 0x0; |
||||
|
||||
header->checksum = table_compute_checksum((void *)fadt, header->length); |
||||
} |
||||
|
||||
unsigned long acpi_fill_madt(unsigned long current) |
||||
{ |
||||
/* create all subtables for processors */ |
||||
current = acpi_create_madt_lapics(current); |
||||
|
||||
/*
|
||||
* TODO(saket.sinha89@gmail.com): get these |
||||
* IRQ values from device tree |
||||
*/ |
||||
current += acpi_create_madt_ioapic((struct acpi_madt_ioapic *)current, |
||||
2, IO_APIC_ADDR, 0); |
||||
current += acpi_create_madt_irqoverride( |
||||
(struct acpi_madt_irqoverride *)current, 0, 0, 2, 0); |
||||
current += acpi_create_madt_irqoverride( |
||||
(struct acpi_madt_irqoverride *)current, 0, 9, 9, 0xd); |
||||
current += acpi_create_madt_irqoverride( |
||||
(struct acpi_madt_irqoverride *)current, 0, 0xd, 0xd, 0xd); |
||||
acpi_create_madt_lapic_nmi( |
||||
(struct acpi_madt_lapic_nmi *)current, 0, 0, 0); |
||||
|
||||
return current; |
||||
} |
@ -0,0 +1,80 @@ |
||||
/* CPU hotplug */ |
||||
|
||||
Scope(\_SB) { |
||||
/* Objects filled in by run-time generated SSDT */ |
||||
External(NTFY, MethodObj) |
||||
External(CPON, PkgObj) |
||||
|
||||
/* Methods called by run-time generated SSDT Processor objects */ |
||||
Method(CPMA, 1, NotSerialized) { |
||||
/* |
||||
* _MAT method - create an madt apic buffer |
||||
* Arg0 = Processor ID = Local APIC ID |
||||
* Local0 = CPON flag for this cpu |
||||
*/ |
||||
Store(DerefOf(Index(CPON, Arg0)), Local0) |
||||
/* Local1 = Buffer (in madt apic form) to return */ |
||||
Store(Buffer(8) {0x00, 0x08, 0x00, 0x00, 0x00, 0, 0, 0}, Local1) |
||||
/* Update the processor id, lapic id, and enable/disable status */ |
||||
Store(Arg0, Index(Local1, 2)) |
||||
Store(Arg0, Index(Local1, 3)) |
||||
Store(Local0, Index(Local1, 4)) |
||||
Return (Local1) |
||||
} |
||||
Method(CPST, 1, NotSerialized) { |
||||
/* |
||||
* _STA method - return ON status of cpu |
||||
* Arg0 = Processor ID = Local APIC ID |
||||
* Local0 = CPON flag for this cpu |
||||
*/ |
||||
Store(DerefOf(Index(CPON, Arg0)), Local0) |
||||
If (Local0) { |
||||
Return (0xf) |
||||
} Else { |
||||
Return (0x0) |
||||
} |
||||
} |
||||
Method(CPEJ, 2, NotSerialized) { |
||||
/* _EJ0 method - eject callback */ |
||||
Sleep(200) |
||||
} |
||||
|
||||
/* CPU hotplug notify method */ |
||||
OperationRegion(PRST, SystemIO, 0xaf00, 32) |
||||
Field(PRST, ByteAcc, NoLock, Preserve) { |
||||
PRS, 256 |
||||
} |
||||
Method(PRSC, 0) { |
||||
/* Local5 = active cpu bitmap */ |
||||
Store(PRS, Local5) |
||||
/* Local2 = last read byte from bitmap */ |
||||
Store(Zero, Local2) |
||||
/* Local0 = Processor ID / APIC ID iterator */ |
||||
Store(Zero, Local0) |
||||
While (LLess(Local0, SizeOf(CPON))) { |
||||
/* Local1 = CPON flag for this cpu */ |
||||
Store(DerefOf(Index(CPON, Local0)), Local1) |
||||
If (And(Local0, 0x07)) { |
||||
/* Shift down previously read bitmap byte */ |
||||
ShiftRight(Local2, 1, Local2) |
||||
} Else { |
||||
/* Read next byte from cpu bitmap */ |
||||
Store(DerefOf(Index(Local5, ShiftRight(Local0, 3))), Local2) |
||||
} |
||||
/* Local3 = active state for this cpu */ |
||||
Store(And(Local2, 1), Local3) |
||||
|
||||
If (LNotEqual(Local1, Local3)) { |
||||
/* State change - update CPON with new state */ |
||||
Store(Local3, Index(CPON, Local0)) |
||||
/* Do CPU notify */ |
||||
If (LEqual(Local3, 1)) { |
||||
NTFY(Local0, 1) |
||||
} Else { |
||||
NTFY(Local0, 3) |
||||
} |
||||
} |
||||
Increment(Local0) |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,25 @@ |
||||
/* Debugging */ |
||||
|
||||
Scope(\) { |
||||
/* Debug Output */ |
||||
OperationRegion(DBG, SystemIO, 0x0402, 0x01) |
||||
Field(DBG, ByteAcc, NoLock, Preserve) { |
||||
DBGB, 8, |
||||
} |
||||
/* |
||||
* Debug method - use this method to send output to the QEMU |
||||
* BIOS debug port. This method handles strings, integers, |
||||
* and buffers. For example: DBUG("abc") DBUG(0x123) |
||||
*/ |
||||
Method(DBUG, 1) { |
||||
ToHexString(Arg0, Local0) |
||||
ToBuffer(Local0, Local0) |
||||
Subtract(SizeOf(Local0), 1, Local1) |
||||
Store(Zero, Local2) |
||||
While (LLess(Local2, Local1)) { |
||||
Store(DerefOf(Index(Local0, Local2)), DBGB) |
||||
Increment(Local2) |
||||
} |
||||
Store(0x0a, dbgb) |
||||
} |
||||
} |
@ -0,0 +1,31 @@ |
||||
/* HPET */ |
||||
|
||||
Scope(\_SB) { |
||||
Device(HPET) { |
||||
Name(_HID, EISAID("PNP0103")) |
||||
Name(_UID, 0) |
||||
OperationRegion(HPTM, SystemMemory, 0xfed00000, 0x400) |
||||
Field(HPTM, DWordAcc, Lock, Preserve) { |
||||
VEND, 32, |
||||
PRD, 32, |
||||
} |
||||
Method(_STA, 0, NotSerialized) { |
||||
Store(VEND, Local0) |
||||
Store(PRD, Local1) |
||||
ShiftRight(Local0, 16, Local0) |
||||
If (LOr(LEqual(Local0, 0), LEqual(Local0, 0xffff))) { |
||||
Return (0x0) |
||||
} |
||||
If (LOr(LEqual(Local1, 0), LGreater(Local1, 100000000))) { |
||||
Return (0x0) |
||||
} |
||||
Return (0x0f) |
||||
} |
||||
Name(_CRS, ResourceTemplate() { |
||||
Memory32Fixed(ReadOnly, |
||||
0xfed00000, /* Address Base */ |
||||
0x00000400, /* Address Length */ |
||||
) |
||||
}) |
||||
} |
||||
} |
@ -0,0 +1,102 @@ |
||||
/* Common legacy ISA style devices. */ |
||||
Scope(\_SB.PCI0.ISA) { |
||||
|
||||
Device(RTC) { |
||||
Name(_HID, EisaId("PNP0B00")) |
||||
Name(_CRS, ResourceTemplate() { |
||||
IO(Decode16, 0x0070, 0x0070, 0x10, 0x02) |
||||
IRQNoFlags() { 8 } |
||||
IO(Decode16, 0x0072, 0x0072, 0x02, 0x06) |
||||
}) |
||||
} |
||||
|
||||
Device(KBD) { |
||||
Name(_HID, EisaId("PNP0303")) |
||||
Method(_STA, 0, NotSerialized) { |
||||
Return (0x0f) |
||||
} |
||||
Name(_CRS, ResourceTemplate() { |
||||
IO(Decode16, 0x0060, 0x0060, 0x01, 0x01) |
||||
IO(Decode16, 0x0064, 0x0064, 0x01, 0x01) |
||||
IRQNoFlags() { 1 } |
||||
}) |
||||
} |
||||
|
||||
Device(MOU) { |
||||
Name(_HID, EisaId("PNP0F13")) |
||||
Method(_STA, 0, NotSerialized) { |
||||
Return (0x0f) |
||||
} |
||||
Name(_CRS, ResourceTemplate() { |
||||
IRQNoFlags() { 12 } |
||||
}) |
||||
} |
||||
|
||||
Device(FDC0) { |
||||
Name(_HID, EisaId("PNP0700")) |
||||
Method(_STA, 0, NotSerialized) { |
||||
Store(FDEN, Local0) |
||||
If (LEqual(Local0, 0)) { |
||||
Return (0x00) |
||||
} Else { |
||||
Return (0x0f) |
||||
} |
||||
} |
||||
Name(_CRS, ResourceTemplate() { |
||||
IO(Decode16, 0x03f2, 0x03f2, 0x00, 0x04) |
||||
IO(Decode16, 0x03f7, 0x03f7, 0x00, 0x01) |
||||
IRQNoFlags() { 6 } |
||||
DMA(Compatibility, NotBusMaster, Transfer8) { 2 } |
||||
}) |
||||
} |
||||
|
||||
Device(LPT) { |
||||
Name(_HID, EisaId("PNP0400")) |
||||
Method(_STA, 0, NotSerialized) { |
||||
Store(LPEN, Local0) |
||||
If (LEqual(Local0, 0)) { |
||||
Return (0x00) |
||||
} Else { |
||||
Return (0x0f) |
||||
} |
||||
} |
||||
Name(_CRS, ResourceTemplate() { |
||||
IO(Decode16, 0x0378, 0x0378, 0x08, 0x08) |
||||
IRQNoFlags() { 7 } |
||||
}) |
||||
} |
||||
|
||||
Device(COM1) { |
||||
Name(_HID, EisaId("PNP0501")) |
||||
Name(_UID, 0x01) |
||||
Method(_STA, 0, NotSerialized) { |
||||
Store(CAEN, Local0) |
||||
If (LEqual(Local0, 0)) { |
||||
Return (0x00) |
||||
} Else { |
||||
Return (0x0f) |
||||
} |
||||
} |
||||
Name(_CRS, ResourceTemplate() { |
||||
IO(Decode16, 0x03f8, 0x03f8, 0x00, 0x08) |
||||
IRQNoFlags() { 4 } |
||||
}) |
||||
} |
||||
|
||||
Device(COM2) { |
||||
Name(_HID, EisaId("PNP0501")) |
||||
Name(_UID, 0x02) |
||||
Method(_STA, 0, NotSerialized) { |
||||
Store(CBEN, Local0) |
||||
If (LEqual(Local0, 0)) { |
||||
Return (0x00) |
||||
} Else { |
||||
Return (0x0f) |
||||
} |
||||
} |
||||
Name(_CRS, ResourceTemplate() { |
||||
IO(Decode16, 0x02f8, 0x02f8, 0x00, 0x08) |
||||
IRQNoFlags() { 3 } |
||||
}) |
||||
} |
||||
} |
@ -0,0 +1,61 @@ |
||||
/* PCI CRS (current resources) definition. */ |
||||
Scope(\_SB.PCI0) { |
||||
|
||||
Name(CRES, ResourceTemplate() { |
||||
WordBusNumber(ResourceProducer, MinFixed, MaxFixed, PosDecode, |
||||
0x0000, /* Address Space Granularity */ |
||||
0x0000, /* Address Range Minimum */ |
||||
0x00ff, /* Address Range Maximum */ |
||||
0x0000, /* Address Translation Offset */ |
||||
0x0100, /* Address Length */ |
||||
,, ) |
||||
IO(Decode16, |
||||
0x0cf8, /* Address Range Minimum */ |
||||
0x0cf8, /* Address Range Maximum */ |
||||
0x01, /* Address Alignment */ |
||||
0x08, /* Address Length */ |
||||
) |
||||
WordIO(ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, |
||||
0x0000, /* Address Space Granularity */ |
||||
0x0000, /* Address Range Minimum */ |
||||
0x0cf7, /* Address Range Maximum */ |
||||
0x0000, /* Address Translation Offset */ |
||||
0x0cf8, /* Address Length */ |
||||
,, , TypeStatic) |
||||
WordIO(ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, |
||||
0x0000, /* Address Space Granularity */ |
||||
0x0d00, /* Address Range Minimum */ |
||||
0xffff, /* Address Range Maximum */ |
||||
0x0000, /* Address Translation Offset */ |
||||
0xf300, /* Address Length */ |
||||
,, , TypeStatic) |
||||
DWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, |
||||
0x00000000, /* Address Space Granularity */ |
||||
0x000a0000, /* Address Range Minimum */ |
||||
0x000bffff, /* Address Range Maximum */ |
||||
0x00000000, /* Address Translation Offset */ |
||||
0x00020000, /* Address Length */ |
||||
,, , AddressRangeMemory, TypeStatic) |
||||
DWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite, |
||||
0x00000000, /* Address Space Granularity */ |
||||
0xe0000000, /* Address Range Minimum */ |
||||
0xfebfffff, /* Address Range Maximum */ |
||||
0x00000000, /* Address Translation Offset */ |
||||
0x1ec00000, /* Address Length */ |
||||
,, PW32, AddressRangeMemory, TypeStatic) |
||||
}) |
||||
|
||||
Name(CR64, ResourceTemplate() { |
||||
QWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, |
||||
0x00000000, /* Address Space Granularity */ |
||||
0x80000000, /* Address Range Minimum */ |
||||
0xffffffff, /* Address Range Maximum */ |
||||
0x00000000, /* Address Translation Offset */ |
||||
0x80000000, /* Address Length */ |
||||
,, PW64, AddressRangeMemory, TypeStatic) |
||||
}) |
||||
|
||||
Method(_CRS, 0) { |
||||
Return (CRES) |
||||
} |
||||
} |
@ -0,0 +1,412 @@ |
||||
/* |
||||
* QEMU ACPI DSDT ASL definition |
||||
* |
||||
* Copyright (c) 2006 Fabrice Bellard |
||||
* |
||||
* Copyright (c) 2010 Isaku Yamahata |
||||
* yamahata at valinux co jp |
||||
* Based on acpi-dsdt.dsl, but heavily modified for q35 chipset. |
||||
*/ |
||||
|
||||
DefinitionBlock ( |
||||
"dsdt.aml", /* Output Filename */ |
||||
"DSDT", /* Signature */ |
||||
0x01, /* DSDT Compliance Revision */ |
||||
"UBOO", /* OEMID */ |
||||
"UBOOT ", /* TABLE ID */ |
||||
0x2 /* OEM Revision */ |
||||
) |
||||
{ |
||||
|
||||
#include "acpi/dbug.asl" |
||||
|
||||
Scope(\_SB) { |
||||
OperationRegion(PCST, SystemIO, 0xae00, 0x0c) |
||||
OperationRegion(PCSB, SystemIO, 0xae0c, 0x01) |
||||
Field(PCSB, AnyAcc, NoLock, WriteAsZeros) { |
||||
PCIB, 8, |
||||
} |
||||
} |
||||
|
||||
|
||||
/* PCI Bus definition */ |
||||
|
||||
Scope(\_SB) { |
||||
Device(PCI0) { |
||||
Name(_HID, EisaId("PNP0A08")) |
||||
Name(_CID, EisaId("PNP0A03")) |
||||
Name(_ADR, 0x00) |
||||
Name(_UID, 1) |
||||
|
||||
/* _OSC: based on sample of ACPI3.0b spec */ |
||||
Name(SUPP, 0) /* PCI _OSC Support Field value */ |
||||
Name(CTRL, 0) /* PCI _OSC Control Field value */ |
||||
Method(_OSC, 4) { |
||||
/* Create DWORD-addressable fields from Capabilities Buffer */ |
||||
CreateDWordField(Arg3, 0, CDW1) |
||||
|
||||
/* Check for proper UUID */ |
||||
If (LEqual(Arg0, ToUUID("33DB4D5B-1FF7-401C-9657-7441C03DD766"))) |
||||
{ |
||||
/* Create DWORD-addressable fields from Capabilities Buffer */ |
||||
CreateDWordField(Arg3, 4, CDW2) |
||||
CreateDWordField(Arg3, 8, CDW3) |
||||
|
||||
/* Save Capabilities DWORD2 & 3 */ |
||||
Store(CDW2, SUPP) |
||||
Store(CDW3, CTRL) |
||||
|
||||
/* |
||||
* Always allow native PME, AER (no dependencies) |
||||
* Never allow SHPC (no SHPC controller in this system) |
||||
*/ |
||||
And(CTRL, 0x1d, CTRL) |
||||
|
||||
If (LNotEqual(Arg1, One)) { |
||||
/* Unknown revision */ |
||||
Or(CDW1, 0x08, CDW1) |
||||
} |
||||
If (LNotEqual(CDW3, CTRL)) { |
||||
/* Capabilities bits were masked */ |
||||
Or(CDW1, 0x10, CDW1) |
||||
} |
||||
/* Update DWORD3 in the buffer */ |
||||
Store(CTRL, CDW3) |
||||
} Else { |
||||
Or(CDW1, 4, CDW1) /* Unrecognized UUID */ |
||||
} |
||||
Return (Arg3) |
||||
} |
||||
} |
||||
} |
||||
|
||||
#include "acpi/pci-crs.asl" |
||||
#include "acpi/hpet.asl" |
||||
|
||||
|
||||
/* VGA */ |
||||
|
||||
Scope(\_SB.PCI0) { |
||||
Device(VGA) { |
||||
Name(_ADR, 0x00010000) |
||||
Method(_S1D, 0, NotSerialized) { |
||||
Return (0x00) |
||||
} |
||||
Method(_S2D, 0, NotSerialized) { |
||||
Return (0x00) |
||||
} |
||||
Method(_S3D, 0, NotSerialized) { |
||||
Return (0x00) |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/* LPC ISA bridge */ |
||||
|
||||
Scope(\_SB.PCI0) { |
||||
/* PCI D31:f0 LPC ISA bridge */ |
||||
Device(ISA) { |
||||
/* PCI D31:f0 */ |
||||
Name(_ADR, 0x001f0000) |
||||
|
||||
/* ICH9 PCI to ISA irq remapping */ |
||||
OperationRegion(PIRQ, PCI_Config, 0x60, 0x0c) |
||||
|
||||
OperationRegion(LPCD, PCI_Config, 0x80, 0x2) |
||||
Field(LPCD, AnyAcc, NoLock, Preserve) { |
||||
COMA, 3, |
||||
, 1, |
||||
COMB, 3, |
||||
|
||||
Offset(0x01), |
||||
LPTD, 2, |
||||
, 2, |
||||
FDCD, 2 |
||||
} |
||||
OperationRegion(LPCE, PCI_Config, 0x82, 0x2) |
||||
Field(LPCE, AnyAcc, NoLock, Preserve) { |
||||
CAEN, 1, |
||||
CBEN, 1, |
||||
LPEN, 1, |
||||
FDEN, 1 |
||||
} |
||||
} |
||||
} |
||||
|
||||
#include "acpi/isa.asl" |
||||
|
||||
|
||||
/* PCI IRQs */ |
||||
|
||||
/* Zero => PIC mode, One => APIC Mode */ |
||||
Name(\PICF, Zero) |
||||
Method(\_PIC, 1, NotSerialized) { |
||||
Store(Arg0, \PICF) |
||||
} |
||||
|
||||
Scope(\_SB) { |
||||
Scope(PCI0) { |
||||
#define prt_slot_lnk(nr, lnk0, lnk1, lnk2, lnk3) \ |
||||
Package() { nr##ffff, 0, lnk0, 0 }, \ |
||||
Package() { nr##ffff, 1, lnk1, 0 }, \ |
||||
Package() { nr##ffff, 2, lnk2, 0 }, \ |
||||
Package() { nr##ffff, 3, lnk3, 0 } |
||||
|
||||
#define prt_slot_lnkA(nr) prt_slot_lnk(nr, LNKA, LNKB, LNKC, LNKD) |
||||
#define prt_slot_lnkB(nr) prt_slot_lnk(nr, LNKB, LNKC, LNKD, LNKA) |
||||
#define prt_slot_lnkC(nr) prt_slot_lnk(nr, LNKC, LNKD, LNKA, LNKB) |
||||
#define prt_slot_lnkD(nr) prt_slot_lnk(nr, LNKD, LNKA, LNKB, LNKC) |
||||
|
||||
#define prt_slot_lnkE(nr) prt_slot_lnk(nr, LNKE, LNKF, LNKG, LNKH) |
||||
#define prt_slot_lnkF(nr) prt_slot_lnk(nr, LNKF, LNKG, LNKH, LNKE) |
||||
#define prt_slot_lnkG(nr) prt_slot_lnk(nr, LNKG, LNKH, LNKE, LNKF) |
||||
#define prt_slot_lnkH(nr) prt_slot_lnk(nr, LNKH, LNKE, LNKF, LNKG) |
||||
|
||||
Name(PRTP, Package() { |
||||
prt_slot_lnkE(0x0000), |
||||
prt_slot_lnkF(0x0001), |
||||
prt_slot_lnkG(0x0002), |
||||
prt_slot_lnkH(0x0003), |
||||
prt_slot_lnkE(0x0004), |
||||
prt_slot_lnkF(0x0005), |
||||
prt_slot_lnkG(0x0006), |
||||
prt_slot_lnkH(0x0007), |
||||
prt_slot_lnkE(0x0008), |
||||
prt_slot_lnkF(0x0009), |
||||
prt_slot_lnkG(0x000a), |
||||
prt_slot_lnkH(0x000b), |
||||
prt_slot_lnkE(0x000c), |
||||
prt_slot_lnkF(0x000d), |
||||
prt_slot_lnkG(0x000e), |
||||
prt_slot_lnkH(0x000f), |
||||
prt_slot_lnkE(0x0010), |
||||
prt_slot_lnkF(0x0011), |
||||
prt_slot_lnkG(0x0012), |
||||
prt_slot_lnkH(0x0013), |
||||
prt_slot_lnkE(0x0014), |
||||
prt_slot_lnkF(0x0015), |
||||
prt_slot_lnkG(0x0016), |
||||
prt_slot_lnkH(0x0017), |
||||
prt_slot_lnkE(0x0018), |
||||
|
||||
/* INTA -> PIRQA for slot 25 - 31 |
||||
see the default value of D<N>IR */ |
||||
prt_slot_lnkA(0x0019), |
||||
prt_slot_lnkA(0x001a), |
||||
prt_slot_lnkA(0x001b), |
||||
prt_slot_lnkA(0x001c), |
||||
prt_slot_lnkA(0x001d), |
||||
|
||||
/* PCIe->PCI bridge. use PIRQ[E-H] */ |
||||
prt_slot_lnkE(0x001e), |
||||
|
||||
prt_slot_lnkA(0x001f) |
||||
}) |
||||
|
||||
#define prt_slot_gsi(nr, gsi0, gsi1, gsi2, gsi3) \ |
||||
Package() { nr##ffff, 0, gsi0, 0 }, \ |
||||
Package() { nr##ffff, 1, gsi1, 0 }, \ |
||||
Package() { nr##ffff, 2, gsi2, 0 }, \ |
||||
Package() { nr##ffff, 3, gsi3, 0 } |
||||
|
||||
#define prt_slot_gsiA(nr) prt_slot_gsi(nr, GSIA, GSIB, GSIC, GSID) |
||||
#define prt_slot_gsiB(nr) prt_slot_gsi(nr, GSIB, GSIC, GSID, GSIA) |
||||
#define prt_slot_gsiC(nr) prt_slot_gsi(nr, GSIC, GSID, GSIA, GSIB) |
||||
#define prt_slot_gsiD(nr) prt_slot_gsi(nr, GSID, GSIA, GSIB, GSIC) |
||||
|
||||
#define prt_slot_gsiE(nr) prt_slot_gsi(nr, GSIE, GSIF, GSIG, GSIH) |
||||
#define prt_slot_gsiF(nr) prt_slot_gsi(nr, GSIF, GSIG, GSIH, GSIE) |
||||
#define prt_slot_gsiG(nr) prt_slot_gsi(nr, GSIG, GSIH, GSIE, GSIF) |
||||
#define prt_slot_gsiH(nr) prt_slot_gsi(nr, GSIH, GSIE, GSIF, GSIG) |
||||
|
||||
Name(PRTA, Package() { |
||||
prt_slot_gsiE(0x0000), |
||||
prt_slot_gsiF(0x0001), |
||||
prt_slot_gsiG(0x0002), |
||||
prt_slot_gsiH(0x0003), |
||||
prt_slot_gsiE(0x0004), |
||||
prt_slot_gsiF(0x0005), |
||||
prt_slot_gsiG(0x0006), |
||||
prt_slot_gsiH(0x0007), |
||||
prt_slot_gsiE(0x0008), |
||||
prt_slot_gsiF(0x0009), |
||||
prt_slot_gsiG(0x000a), |
||||
prt_slot_gsiH(0x000b), |
||||
prt_slot_gsiE(0x000c), |
||||
prt_slot_gsiF(0x000d), |
||||
prt_slot_gsiG(0x000e), |
||||
prt_slot_gsiH(0x000f), |
||||
prt_slot_gsiE(0x0010), |
||||
prt_slot_gsiF(0x0011), |
||||
prt_slot_gsiG(0x0012), |
||||
prt_slot_gsiH(0x0013), |
||||
prt_slot_gsiE(0x0014), |
||||
prt_slot_gsiF(0x0015), |
||||
prt_slot_gsiG(0x0016), |
||||
prt_slot_gsiH(0x0017), |
||||
prt_slot_gsiE(0x0018), |
||||
|
||||
/* |
||||
* INTA -> PIRQA for slot 25 - 31, but 30 |
||||
* see the default value of D<N>IR |
||||
*/ |
||||
prt_slot_gsiA(0x0019), |
||||
prt_slot_gsiA(0x001a), |
||||
prt_slot_gsiA(0x001b), |
||||
prt_slot_gsiA(0x001c), |
||||
prt_slot_gsiA(0x001d), |
||||
|
||||
/* PCIe->PCI bridge. use PIRQ[E-H] */ |
||||
prt_slot_gsiE(0x001e), |
||||
|
||||
prt_slot_gsiA(0x001f) |
||||
}) |
||||
|
||||
Method(_PRT, 0, NotSerialized) { |
||||
/* |
||||
* PCI IRQ routing table, |
||||
* example from ACPI 2.0a |
||||
* specification, section 6.2.8.1 |
||||
* Note: we provide the same info |
||||
* as the PCI routing table |
||||
* of the Bochs BIOS |
||||
*/ |
||||
If (LEqual(\PICF, Zero)) { |
||||
Return (PRTP) |
||||
} Else { |
||||
Return (PRTA) |
||||
} |
||||
} |
||||
} |
||||
|
||||
Field(PCI0.ISA.PIRQ, ByteAcc, NoLock, Preserve) { |
||||
PRQA, 8, |
||||
PRQB, 8, |
||||
PRQC, 8, |
||||
PRQD, 8, |
||||
|
||||
Offset(0x08), |
||||
PRQE, 8, |
||||
PRQF, 8, |
||||
PRQG, 8, |
||||
PRQH, 8 |
||||
} |
||||
|
||||
Method(IQST, 1, NotSerialized) { |
||||
/* _STA method - get status */ |
||||
If (And(0x80, Arg0)) { |
||||
Return (0x09) |
||||
} |
||||
Return (0x0b) |
||||
} |
||||
Method(IQCR, 1, NotSerialized) { |
||||
/* _CRS method - get current settings */ |
||||
Name(PRR0, ResourceTemplate() { |
||||
Interrupt(, Level, ActiveHigh, Shared) { 0 } |
||||
}) |
||||
CreateDWordField(PRR0, 0x05, PRRI) |
||||
Store(And(Arg0, 0x0f), PRRI) |
||||
Return (PRR0) |
||||
} |
||||
|
||||
#define define_link(link, uid, reg) \ |
||||
Device(link) { \ |
||||
Name(_HID, EISAID("PNP0C0F")) \ |
||||
Name(_UID, uid) \ |
||||
Name(_PRS, ResourceTemplate() { \ |
||||
Interrupt(, Level, ActiveHigh, Shared) { \ |
||||
5, 10, 11 \ |
||||
} \ |
||||
}) \ |
||||
Method(_STA, 0, NotSerialized) { \ |
||||
Return (IQST(reg)) \ |
||||
} \ |
||||
Method(_DIS, 0, NotSerialized) { \ |
||||
Or(reg, 0x80, reg) \ |
||||
} \ |
||||
Method(_CRS, 0, NotSerialized) { \ |
||||
Return (IQCR(reg)) \ |
||||
} \ |
||||
Method(_SRS, 1, NotSerialized) { \ |
||||
CreateDWordField(Arg0, 0x05, PRRI) \ |
||||
Store(PRRI, reg) \ |
||||
} \ |
||||
} |
||||
|
||||
define_link(LNKA, 0, PRQA) |
||||
define_link(LNKB, 1, PRQB) |
||||
define_link(LNKC, 2, PRQC) |
||||
define_link(LNKD, 3, PRQD) |
||||
define_link(LNKE, 4, PRQE) |
||||
define_link(LNKF, 5, PRQF) |
||||
define_link(LNKG, 6, PRQG) |
||||
define_link(LNKH, 7, PRQH) |
||||
|
||||
#define define_gsi_link(link, uid, gsi) \ |
||||
Device(link) { \ |
||||
Name(_HID, EISAID("PNP0C0F")) \ |
||||
Name(_UID, uid) \ |
||||
Name(_PRS, ResourceTemplate() { \ |
||||
Interrupt(, Level, ActiveHigh, Shared) { \ |
||||
gsi \ |
||||
} \ |
||||
}) \ |
||||
Name(_CRS, ResourceTemplate() { \ |
||||
Interrupt(, Level, ActiveHigh, Shared) { \ |
||||
gsi \ |
||||
} \ |
||||
}) \ |
||||
Method(_SRS, 1, NotSerialized) { \ |
||||
} \ |
||||
} |
||||
|
||||
define_gsi_link(GSIA, 0, 0x10) |
||||
define_gsi_link(GSIB, 0, 0x11) |
||||
define_gsi_link(GSIC, 0, 0x12) |
||||
define_gsi_link(GSID, 0, 0x13) |
||||
define_gsi_link(GSIE, 0, 0x14) |
||||
define_gsi_link(GSIF, 0, 0x15) |
||||
define_gsi_link(GSIG, 0, 0x16) |
||||
define_gsi_link(GSIH, 0, 0x17) |
||||
} |
||||
|
||||
/* General purpose events */ |
||||
|
||||
Scope(\_GPE) { |
||||
Name(_HID, "ACPI0006") |
||||
|
||||
Method(_L00) { |
||||
} |
||||
Method(_L01) { |
||||
} |
||||
Method(_L02) { |
||||
} |
||||
Method(_L03) { |
||||
} |
||||
Method(_L04) { |
||||
} |
||||
Method(_L05) { |
||||
} |
||||
Method(_L06) { |
||||
} |
||||
Method(_L07) { |
||||
} |
||||
Method(_L08) { |
||||
} |
||||
Method(_L09) { |
||||
} |
||||
Method(_L0A) { |
||||
} |
||||
Method(_L0B) { |
||||
} |
||||
Method(_L0C) { |
||||
} |
||||
Method(_L0D) { |
||||
} |
||||
Method(_L0E) { |
||||
} |
||||
Method(_L0F) { |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,393 @@ |
||||
/*
|
||||
* Based on acpi.c from coreboot |
||||
* |
||||
* Copyright (C) 2015, Saket Sinha <saket.sinha89@gmail.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <malloc.h> |
||||
#include <asm/post.h> |
||||
#include <linux/string.h> |
||||
|
||||
#define RSDP_SIG "RSD PTR " /* RSDT pointer signature */ |
||||
#define ACPI_TABLE_CREATOR "UBOOT " /* Must be 8 bytes long! */ |
||||
#define OEM_ID "UBOOT " /* Must be 6 bytes long! */ |
||||
#define ASLC "INTL" /* Must be 4 bytes long! */ |
||||
|
||||
#define OEM_REVISION 42 |
||||
#define ASL_COMPILER_REVISION 42 |
||||
|
||||
/* IO ports to generate SMIs */ |
||||
#define APM_CNT 0xb2 |
||||
#define APM_CNT_CST_CONTROL 0x85 |
||||
#define APM_CNT_PST_CONTROL 0x80 |
||||
#define APM_CNT_ACPI_DISABLE 0x1e |
||||
#define APM_CNT_ACPI_ENABLE 0xe1 |
||||
#define APM_CNT_MBI_UPDATE 0xeb |
||||
#define APM_CNT_GNVS_UPDATE 0xea |
||||
#define APM_CNT_FINALIZE 0xcb |
||||
#define APM_CNT_LEGACY 0xcc |
||||
#define APM_ST 0xb3 |
||||
|
||||
/* Multiple Processor Interrupts */ |
||||
#define MP_IRQ_POLARITY_DEFAULT 0x0 |
||||
#define MP_IRQ_POLARITY_HIGH 0x1 |
||||
#define MP_IRQ_POLARITY_LOW 0x3 |
||||
#define MP_IRQ_POLARITY_MASK 0x3 |
||||
#define MP_IRQ_TRIGGER_DEFAULT 0x0 |
||||
#define MP_IRQ_TRIGGER_EDGE 0x4 |
||||
#define MP_IRQ_TRIGGER_LEVEL 0xc |
||||
#define MP_IRQ_TRIGGER_MASK 0xc |
||||
|
||||
/*
|
||||
* Interrupt assigned for SCI in order to |
||||
* create the ACPI MADT IRQ override entry |
||||
*/ |
||||
#define ACTL 0x00 |
||||
#define SCIS_MASK 0x07 |
||||
#define SCIS_IRQ9 0x00 |
||||
#define SCIS_IRQ10 0x01 |
||||
#define SCIS_IRQ11 0x02 |
||||
#define SCIS_IRQ20 0x04 |
||||
#define SCIS_IRQ21 0x05 |
||||
#define SCIS_IRQ22 0x06 |
||||
#define SCIS_IRQ23 0x07 |
||||
|
||||
#define ACPI_REV_ACPI_1_0 1 |
||||
#define ACPI_REV_ACPI_2_0 1 |
||||
#define ACPI_REV_ACPI_3_0 2 |
||||
#define ACPI_REV_ACPI_4_0 3 |
||||
#define ACPI_REV_ACPI_5_0 5 |
||||
|
||||
#define ACPI_RSDP_REV_ACPI_1_0 0 |
||||
#define ACPI_RSDP_REV_ACPI_2_0 2 |
||||
|
||||
typedef struct acpi_gen_regaddr { |
||||
u8 space_id; /* Address space ID */ |
||||
u8 bit_width; /* Register size in bits */ |
||||
u8 bit_offset; /* Register bit offset */ |
||||
union { |
||||
/* Reserved in ACPI 2.0 - 2.0b */ |
||||
u8 resv; |
||||
/* Access size in ACPI 2.0c/3.0/4.0/5.0 */ |
||||
u8 access_size; |
||||
}; |
||||
u32 addrl; /* Register address, low 32 bits */ |
||||
u32 addrh; /* Register address, high 32 bits */ |
||||
} acpi_addr_t; |
||||
|
||||
|
||||
/*
|
||||
* RSDP (Root System Description Pointer) |
||||
* Note: ACPI 1.0 didn't have length, xsdt_address, and ext_checksum |
||||
*/ |
||||
struct acpi_rsdp { |
||||
char signature[8]; /* RSDP signature */ |
||||
u8 checksum; /* Checksum of the first 20 bytes */ |
||||
char oem_id[6]; /* OEM ID */ |
||||
u8 revision; /* 0 for ACPI 1.0, 2 for ACPI 2.0/3.0/4.0 */ |
||||
u32 rsdt_address; /* Physical address of RSDT (32 bits) */ |
||||
u32 length; /* Total RSDP length (incl. extended part) */ |
||||
u64 xsdt_address; /* Physical address of XSDT (64 bits) */ |
||||
u8 ext_checksum; /* Checksum of the whole table */ |
||||
u8 reserved[3]; |
||||
}; |
||||
|
||||
enum acpi_address_space_type { |
||||
ACPI_ADDRESS_SPACE_MEMORY = 0, /* System memory */ |
||||
ACPI_ADDRESS_SPACE_IO, /* System I/O */ |
||||
ACPI_ADDRESS_SPACE_PCI, /* PCI config space */ |
||||
ACPI_ADDRESS_SPACE_EC, /* Embedded controller */ |
||||
ACPI_ADDRESS_SPACE_SMBUS, /* SMBus */ |
||||
ACPI_ADDRESS_SPACE_PCC = 0x0a, /* Platform Comm. Channel */ |
||||
ACPI_ADDRESS_SPACE_FIXED = 0x7f /* Functional fixed hardware */ |
||||
}; |
||||
|
||||
/* functional fixed hardware */ |
||||
#define ACPI_FFIXEDHW_VENDOR_INTEL 1 /* Intel */ |
||||
#define ACPI_FFIXEDHW_CLASS_HLT 0 /* C1 Halt */ |
||||
#define ACPI_FFIXEDHW_CLASS_IO_HLT 1 /* C1 I/O then Halt */ |
||||
#define ACPI_FFIXEDHW_CLASS_MWAIT 2 /* MWAIT Native C-state */ |
||||
#define ACPI_FFIXEDHW_FLAG_HW_COORD 1 /* Hardware Coordination bit */ |
||||
#define ACPI_FFIXEDHW_FLAG_BM_STS 2 /* BM_STS avoidance bit */ |
||||
|
||||
/* Access size definitions for Generic address structure */ |
||||
enum acpi_address_space_size { |
||||
ACPI_ACCESS_SIZE_UNDEFINED = 0, /* Undefined (legacy reasons) */ |
||||
ACPI_ACCESS_SIZE_BYTE_ACCESS = 1, |
||||
ACPI_ACCESS_SIZE_WORD_ACCESS = 2, |
||||
ACPI_ACCESS_SIZE_DWORD_ACCESS = 3, |
||||
ACPI_ACCESS_SIZE_QWORD_ACCESS = 4 |
||||
}; |
||||
|
||||
/* Generic ACPI header, provided by (almost) all tables */ |
||||
typedef struct acpi_table_header { |
||||
char signature[4]; /* ACPI signature (4 ASCII characters) */ |
||||
u32 length; /* Table length in bytes (incl. header) */ |
||||
u8 revision; /* Table version (not ACPI version!) */ |
||||
volatile u8 checksum; /* To make sum of entire table == 0 */ |
||||
char oem_id[6]; /* OEM identification */ |
||||
char oem_table_id[8]; /* OEM table identification */ |
||||
u32 oem_revision; /* OEM revision number */ |
||||
char asl_compiler_id[4]; /* ASL compiler vendor ID */ |
||||
u32 asl_compiler_revision; /* ASL compiler revision number */ |
||||
} acpi_header_t; |
||||
|
||||
/* A maximum number of 32 ACPI tables ought to be enough for now */ |
||||
#define MAX_ACPI_TABLES 32 |
||||
|
||||
/* RSDT (Root System Description Table) */ |
||||
struct acpi_rsdt { |
||||
struct acpi_table_header header; |
||||
u32 entry[MAX_ACPI_TABLES]; |
||||
}; |
||||
|
||||
/* XSDT (Extended System Description Table) */ |
||||
struct acpi_xsdt { |
||||
struct acpi_table_header header; |
||||
u64 entry[MAX_ACPI_TABLES]; |
||||
}; |
||||
|
||||
/* MCFG (PCI Express MMIO config space BAR description table) */ |
||||
struct acpi_mcfg { |
||||
struct acpi_table_header header; |
||||
u8 reserved[8]; |
||||
}; |
||||
|
||||
struct acpi_mcfg_mmconfig { |
||||
u32 base_address; |
||||
u32 base_reserved; |
||||
u16 pci_segment_group_number; |
||||
u8 start_bus_number; |
||||
u8 end_bus_number; |
||||
u8 reserved[4]; |
||||
}; |
||||
|
||||
/* MADT (Multiple APIC Description Table) */ |
||||
struct acpi_madt { |
||||
struct acpi_table_header header; |
||||
u32 lapic_addr; /* Local APIC address */ |
||||
u32 flags; /* Multiple APIC flags */ |
||||
} acpi_madt_t; |
||||
|
||||
enum dev_scope_type { |
||||
SCOPE_PCI_ENDPOINT = 1, |
||||
SCOPE_PCI_SUB = 2, |
||||
SCOPE_IOAPIC = 3, |
||||
SCOPE_MSI_HPET = 4 |
||||
}; |
||||
|
||||
typedef struct dev_scope { |
||||
u8 type; |
||||
u8 length; |
||||
u8 reserved[2]; |
||||
u8 enumeration; |
||||
u8 start_bus; |
||||
struct { |
||||
u8 dev; |
||||
u8 fn; |
||||
} path[0]; |
||||
} __packed dev_scope_t; |
||||
|
||||
/* MADT: APIC Structure Type*/ |
||||
enum acpi_apic_types { |
||||
LOCALAPIC = 0, /* Processor local APIC */ |
||||
IOAPIC, /* I/O APIC */ |
||||
IRQSOURCEOVERRIDE, /* Interrupt source override */ |
||||
NMITYPE, /* NMI source */ |
||||
LOCALNMITYPE, /* Local APIC NMI */ |
||||
LAPICADDRESSOVERRIDE, /* Local APIC address override */ |
||||
IOSAPIC, /* I/O SAPIC */ |
||||
LOCALSAPIC, /* Local SAPIC */ |
||||
PLATFORMIRQSOURCES, /* Platform interrupt sources */ |
||||
LOCALX2SAPIC, /* Processor local x2APIC */ |
||||
LOCALX2APICNMI, /* Local x2APIC NMI */ |
||||
}; |
||||
|
||||
/* MADT: Processor Local APIC Structure */ |
||||
struct acpi_madt_lapic { |
||||
u8 type; /* Type (0) */ |
||||
u8 length; /* Length in bytes (8) */ |
||||
u8 processor_id; /* ACPI processor ID */ |
||||
u8 apic_id; /* Local APIC ID */ |
||||
u32 flags; /* Local APIC flags */ |
||||
}; |
||||
|
||||
#define LOCAL_APIC_FLAG_ENABLED (1 << 0) |
||||
/* bits 1-31: reserved */ |
||||
#define PCAT_COMPAT (1 << 0) |
||||
/* bits 1-31: reserved */ |
||||
|
||||
/* MADT: Local APIC NMI Structure */ |
||||
struct acpi_madt_lapic_nmi { |
||||
u8 type; /* Type (4) */ |
||||
u8 length; /* Length in bytes (6) */ |
||||
u8 processor_id; /* ACPI processor ID */ |
||||
u16 flags; /* MPS INTI flags */ |
||||
u8 lint; /* Local APIC LINT# */ |
||||
}; |
||||
|
||||
/* MADT: I/O APIC Structure */ |
||||
struct acpi_madt_ioapic { |
||||
u8 type; /* Type (1) */ |
||||
u8 length; /* Length in bytes (12) */ |
||||
u8 ioapic_id; /* I/O APIC ID */ |
||||
u8 reserved; |
||||
u32 ioapic_addr; /* I/O APIC address */ |
||||
u32 gsi_base; /* Global system interrupt base */ |
||||
}; |
||||
|
||||
/* MADT: Interrupt Source Override Structure */ |
||||
struct acpi_madt_irqoverride { |
||||
u8 type; /* Type (2) */ |
||||
u8 length; /* Length in bytes (10) */ |
||||
u8 bus; /* ISA (0) */ |
||||
u8 source; /* Bus-relative int. source (IRQ) */ |
||||
u32 gsirq; /* Global system interrupt */ |
||||
u16 flags; /* MPS INTI flags */ |
||||
}; |
||||
|
||||
/* FADT (Fixed ACPI Description Table) */ |
||||
struct __packed acpi_fadt { |
||||
struct acpi_table_header header; |
||||
u32 firmware_ctrl; |
||||
u32 dsdt; |
||||
u8 model; |
||||
u8 preferred_pm_profile; |
||||
u16 sci_int; |
||||
u32 smi_cmd; |
||||
u8 acpi_enable; |
||||
u8 acpi_disable; |
||||
u8 s4bios_req; |
||||
u8 pstate_cnt; |
||||
u32 pm1a_evt_blk; |
||||
u32 pm1b_evt_blk; |
||||
u32 pm1a_cnt_blk; |
||||
u32 pm1b_cnt_blk; |
||||
u32 pm2_cnt_blk; |
||||
u32 pm_tmr_blk; |
||||
u32 gpe0_blk; |
||||
u32 gpe1_blk; |
||||
u8 pm1_evt_len; |
||||
u8 pm1_cnt_len; |
||||
u8 pm2_cnt_len; |
||||
u8 pm_tmr_len; |
||||
u8 gpe0_blk_len; |
||||
u8 gpe1_blk_len; |
||||
u8 gpe1_base; |
||||
u8 cst_cnt; |
||||
u16 p_lvl2_lat; |
||||
u16 p_lvl3_lat; |
||||
u16 flush_size; |
||||
u16 flush_stride; |
||||
u8 duty_offset; |
||||
u8 duty_width; |
||||
u8 day_alrm; |
||||
u8 mon_alrm; |
||||
u8 century; |
||||
u16 iapc_boot_arch; |
||||
u8 res2; |
||||
u32 flags; |
||||
struct acpi_gen_regaddr reset_reg; |
||||
u8 reset_value; |
||||
u8 res3; |
||||
u8 res4; |
||||
u8 res5; |
||||
u32 x_firmware_ctl_l; |
||||
u32 x_firmware_ctl_h; |
||||
u32 x_dsdt_l; |
||||
u32 x_dsdt_h; |
||||
struct acpi_gen_regaddr x_pm1a_evt_blk; |
||||
struct acpi_gen_regaddr x_pm1b_evt_blk; |
||||
struct acpi_gen_regaddr x_pm1a_cnt_blk; |
||||
struct acpi_gen_regaddr x_pm1b_cnt_blk; |
||||
struct acpi_gen_regaddr x_pm2_cnt_blk; |
||||
struct acpi_gen_regaddr x_pm_tmr_blk; |
||||
struct acpi_gen_regaddr x_gpe0_blk; |
||||
struct acpi_gen_regaddr x_gpe1_blk; |
||||
}; |
||||
|
||||
/* Flags for p_lvl2_lat and p_lvl3_lat */ |
||||
#define ACPI_FADT_C2_NOT_SUPPORTED 101 |
||||
#define ACPI_FADT_C3_NOT_SUPPORTED 1001 |
||||
|
||||
/* FADT Feature Flags */ |
||||
#define ACPI_FADT_WBINVD (1 << 0) |
||||
#define ACPI_FADT_WBINVD_FLUSH (1 << 1) |
||||
#define ACPI_FADT_C1_SUPPORTED (1 << 2) |
||||
#define ACPI_FADT_C2_MP_SUPPORTED (1 << 3) |
||||
#define ACPI_FADT_POWER_BUTTON (1 << 4) |
||||
#define ACPI_FADT_SLEEP_BUTTON (1 << 5) |
||||
#define ACPI_FADT_FIXED_RTC (1 << 6) |
||||
#define ACPI_FADT_S4_RTC_WAKE (1 << 7) |
||||
#define ACPI_FADT_32BIT_TIMER (1 << 8) |
||||
#define ACPI_FADT_DOCKING_SUPPORTED (1 << 9) |
||||
#define ACPI_FADT_RESET_REGISTER (1 << 10) |
||||
#define ACPI_FADT_SEALED_CASE (1 << 11) |
||||
#define ACPI_FADT_HEADLESS (1 << 12) |
||||
#define ACPI_FADT_SLEEP_TYPE (1 << 13) |
||||
#define ACPI_FADT_PCI_EXPRESS_WAKE (1 << 14) |
||||
#define ACPI_FADT_PLATFORM_CLOCK (1 << 15) |
||||
#define ACPI_FADT_S4_RTC_VALID (1 << 16) |
||||
#define ACPI_FADT_REMOTE_POWER_ON (1 << 17) |
||||
#define ACPI_FADT_APIC_CLUSTER (1 << 18) |
||||
#define ACPI_FADT_APIC_PHYSICAL (1 << 19) |
||||
/* Bits 20-31: reserved ACPI 3.0 & 4.0 */ |
||||
#define ACPI_FADT_HW_REDUCED_ACPI (1 << 20) |
||||
#define ACPI_FADT_LOW_PWR_IDLE_S0 (1 << 21) |
||||
/* bits 22-31: reserved ACPI 5.0 */ |
||||
|
||||
/* FADT Boot Architecture Flags */ |
||||
#define ACPI_FADT_LEGACY_DEVICES (1 << 0) |
||||
#define ACPI_FADT_8042 (1 << 1) |
||||
#define ACPI_FADT_VGA_NOT_PRESENT (1 << 2) |
||||
#define ACPI_FADT_MSI_NOT_SUPPORTED (1 << 3) |
||||
#define ACPI_FADT_NO_PCIE_ASPM_CONTROL (1 << 4) |
||||
/* No legacy devices (including 8042) */ |
||||
#define ACPI_FADT_LEGACY_FREE 0x00 |
||||
|
||||
/* FADT Preferred Power Management Profile */ |
||||
#define PM_UNSPECIFIED 0 |
||||
#define PM_DESKTOP 1 |
||||
#define PM_MOBILE 2 |
||||
#define PM_WORKSTATION 3 |
||||
#define PM_ENTERPRISE_SERVER 4 |
||||
#define PM_SOHO_SERVER 5 |
||||
#define PM_APPLIANCE_PC 6 |
||||
#define PM_PERFORMANCE_SERVER 7 |
||||
#define PM_TABLET 8 /* ACPI 5.0 */ |
||||
|
||||
/* FACS (Firmware ACPI Control Structure) */ |
||||
struct acpi_facs { |
||||
char signature[4]; /* "FACS" */ |
||||
u32 length; /* Length in bytes (>= 64) */ |
||||
u32 hardware_signature; /* Hardware signature */ |
||||
u32 firmware_waking_vector; /* Firmware waking vector */ |
||||
u32 global_lock; /* Global lock */ |
||||
u32 flags; /* FACS flags */ |
||||
u32 x_firmware_waking_vector_l; /* X FW waking vector, low */ |
||||
u32 x_firmware_waking_vector_h; /* X FW waking vector, high */ |
||||
u8 version; /* ACPI 4.0: 2 */ |
||||
u8 resv[31]; /* FIXME: 4.0: ospm_flags */ |
||||
}; |
||||
|
||||
/* FACS flags */ |
||||
#define ACPI_FACS_S4BIOS_F (1 << 0) |
||||
#define ACPI_FACS_64BIT_WAKE_F (1 << 1) |
||||
/* Bits 31..2: reserved */ |
||||
|
||||
/* These can be used by the target port */ |
||||
|
||||
unsigned long acpi_create_madt_lapics(unsigned long current); |
||||
int acpi_create_madt_ioapic(struct acpi_madt_ioapic *ioapic, u8 id, u32 addr, |
||||
u32 gsi_base); |
||||
int acpi_create_madt_irqoverride(struct acpi_madt_irqoverride *irqoverride, |
||||
u8 bus, u8 source, u32 gsirq, u16 flags); |
||||
unsigned long acpi_fill_madt(unsigned long current); |
||||
void acpi_create_fadt(struct acpi_fadt *fadt, struct acpi_facs *facs, |
||||
void *dsdt); |
||||
int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi, u8 cpu, |
||||
u16 flags, u8 lint); |
||||
unsigned long write_acpi_tables(unsigned long start); |
@ -0,0 +1,436 @@ |
||||
/*
|
||||
* Based on acpi.c from coreboot |
||||
* |
||||
* Copyright (C) 2015, Saket Sinha <saket.sinha89@gmail.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <cpu.h> |
||||
#include <dm.h> |
||||
#include <dm/uclass-internal.h> |
||||
#include <dm/lists.h> |
||||
#include <asm/acpi_table.h> |
||||
#include <asm/cpu.h> |
||||
#include <asm/ioapic.h> |
||||
#include <asm/lapic.h> |
||||
#include <asm/tables.h> |
||||
#include <asm/pci.h> |
||||
|
||||
/*
|
||||
* IASL compiles the dsdt entries and |
||||
* writes the hex values to AmlCode array. |
||||
* CamelCase cannot be handled here. |
||||
*/ |
||||
extern const unsigned char AmlCode[]; |
||||
|
||||
/**
|
||||
* Add an ACPI table to the RSDT (and XSDT) structure, recalculate length |
||||
* and checksum. |
||||
*/ |
||||
static void acpi_add_table(struct acpi_rsdp *rsdp, void *table) |
||||
{ |
||||
int i, entries_num; |
||||
struct acpi_rsdt *rsdt; |
||||
struct acpi_xsdt *xsdt = NULL; |
||||
|
||||
/* The RSDT is mandatory while the XSDT is not */ |
||||
rsdt = (struct acpi_rsdt *)rsdp->rsdt_address; |
||||
|
||||
if (rsdp->xsdt_address) |
||||
xsdt = (struct acpi_xsdt *)((u32)rsdp->xsdt_address); |
||||
|
||||
/* This should always be MAX_ACPI_TABLES */ |
||||
entries_num = ARRAY_SIZE(rsdt->entry); |
||||
|
||||
for (i = 0; i < entries_num; i++) { |
||||
if (rsdt->entry[i] == 0) |
||||
break; |
||||
} |
||||
|
||||
if (i >= entries_num) { |
||||
debug("ACPI: Error: too many tables.\n"); |
||||
return; |
||||
} |
||||
|
||||
/* Add table to the RSDT */ |
||||
rsdt->entry[i] = (u32)table; |
||||
|
||||
/* Fix RSDT length or the kernel will assume invalid entries */ |
||||
rsdt->header.length = sizeof(acpi_header_t) + (sizeof(u32) * (i + 1)); |
||||
|
||||
/* Re-calculate checksum */ |
||||
rsdt->header.checksum = 0; |
||||
rsdt->header.checksum = table_compute_checksum((u8 *)rsdt, |
||||
rsdt->header.length); |
||||
|
||||
/*
|
||||
* And now the same thing for the XSDT. We use the same index as for |
||||
* now we want the XSDT and RSDT to always be in sync in U-Boot |
||||
*/ |
||||
if (xsdt) { |
||||
/* Add table to the XSDT */ |
||||
xsdt->entry[i] = (u64)(u32)table; |
||||
|
||||
/* Fix XSDT length */ |
||||
xsdt->header.length = sizeof(acpi_header_t) + |
||||
(sizeof(u64) * (i + 1)); |
||||
|
||||
/* Re-calculate checksum */ |
||||
xsdt->header.checksum = 0; |
||||
xsdt->header.checksum = table_compute_checksum((u8 *)xsdt, |
||||
xsdt->header.length); |
||||
} |
||||
} |
||||
|
||||
static int acpi_create_madt_lapic(struct acpi_madt_lapic *lapic, |
||||
u8 cpu, u8 apic) |
||||
{ |
||||
lapic->type = LOCALAPIC; /* Local APIC structure */ |
||||
lapic->length = sizeof(struct acpi_madt_lapic); |
||||
lapic->flags = LOCAL_APIC_FLAG_ENABLED; /* Processor/LAPIC enabled */ |
||||
lapic->processor_id = cpu; |
||||
lapic->apic_id = apic; |
||||
|
||||
return lapic->length; |
||||
} |
||||
|
||||
unsigned long acpi_create_madt_lapics(unsigned long current) |
||||
{ |
||||
struct udevice *dev; |
||||
|
||||
for (uclass_find_first_device(UCLASS_CPU, &dev); |
||||
dev; |
||||
uclass_find_next_device(&dev)) { |
||||
struct cpu_platdata *plat = dev_get_parent_platdata(dev); |
||||
|
||||
current += acpi_create_madt_lapic( |
||||
(struct acpi_madt_lapic *)current, |
||||
plat->cpu_id, plat->cpu_id); |
||||
} |
||||
return current; |
||||
} |
||||
|
||||
int acpi_create_madt_ioapic(struct acpi_madt_ioapic *ioapic, u8 id, u32 addr, |
||||
u32 gsi_base) |
||||
{ |
||||
ioapic->type = IOAPIC; |
||||
ioapic->length = sizeof(struct acpi_madt_ioapic); |
||||
ioapic->reserved = 0x00; |
||||
ioapic->gsi_base = gsi_base; |
||||
ioapic->ioapic_id = id; |
||||
ioapic->ioapic_addr = addr; |
||||
|
||||
return ioapic->length; |
||||
} |
||||
|
||||
int acpi_create_madt_irqoverride(struct acpi_madt_irqoverride *irqoverride, |
||||
u8 bus, u8 source, u32 gsirq, u16 flags) |
||||
{ |
||||
irqoverride->type = IRQSOURCEOVERRIDE; |
||||
irqoverride->length = sizeof(struct acpi_madt_irqoverride); |
||||
irqoverride->bus = bus; |
||||
irqoverride->source = source; |
||||
irqoverride->gsirq = gsirq; |
||||
irqoverride->flags = flags; |
||||
|
||||
return irqoverride->length; |
||||
} |
||||
|
||||
int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi, |
||||
u8 cpu, u16 flags, u8 lint) |
||||
{ |
||||
lapic_nmi->type = LOCALNMITYPE; |
||||
lapic_nmi->length = sizeof(struct acpi_madt_lapic_nmi); |
||||
lapic_nmi->flags = flags; |
||||
lapic_nmi->processor_id = cpu; |
||||
lapic_nmi->lint = lint; |
||||
|
||||
return lapic_nmi->length; |
||||
} |
||||
|
||||
static void fill_header(acpi_header_t *header, char *signature, int length) |
||||
{ |
||||
memcpy(header->signature, signature, length); |
||||
memcpy(header->oem_id, OEM_ID, 6); |
||||
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); |
||||
memcpy(header->asl_compiler_id, ASLC, 4); |
||||
} |
||||
|
||||
static void acpi_create_madt(struct acpi_madt *madt) |
||||
{ |
||||
acpi_header_t *header = &(madt->header); |
||||
unsigned long current = (unsigned long)madt + sizeof(struct acpi_madt); |
||||
|
||||
memset((void *)madt, 0, sizeof(struct acpi_madt)); |
||||
|
||||
/* Fill out header fields */ |
||||
fill_header(header, "APIC", 4); |
||||
header->length = sizeof(struct acpi_madt); |
||||
|
||||
/* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */ |
||||
header->revision = ACPI_REV_ACPI_2_0; |
||||
|
||||
madt->lapic_addr = LAPIC_DEFAULT_BASE; |
||||
madt->flags = PCAT_COMPAT; |
||||
|
||||
current = acpi_fill_madt(current); |
||||
|
||||
/* (Re)calculate length and checksum */ |
||||
header->length = current - (unsigned long)madt; |
||||
|
||||
header->checksum = table_compute_checksum((void *)madt, header->length); |
||||
} |
||||
|
||||
static int acpi_create_mcfg_mmconfig(struct acpi_mcfg_mmconfig *mmconfig, |
||||
u32 base, u16 seg_nr, u8 start, u8 end) |
||||
{ |
||||
memset(mmconfig, 0, sizeof(*mmconfig)); |
||||
mmconfig->base_address = base; |
||||
mmconfig->base_reserved = 0; |
||||
mmconfig->pci_segment_group_number = seg_nr; |
||||
mmconfig->start_bus_number = start; |
||||
mmconfig->end_bus_number = end; |
||||
|
||||
return sizeof(struct acpi_mcfg_mmconfig); |
||||
} |
||||
|
||||
static unsigned long acpi_fill_mcfg(unsigned long current) |
||||
{ |
||||
current += acpi_create_mcfg_mmconfig |
||||
((struct acpi_mcfg_mmconfig *)current, |
||||
CONFIG_PCIE_ECAM_BASE, 0x0, 0x0, 255); |
||||
|
||||
return current; |
||||
} |
||||
|
||||
/* MCFG is defined in the PCI Firmware Specification 3.0 */ |
||||
static void acpi_create_mcfg(struct acpi_mcfg *mcfg) |
||||
{ |
||||
acpi_header_t *header = &(mcfg->header); |
||||
unsigned long current = (unsigned long)mcfg + sizeof(struct acpi_mcfg); |
||||
|
||||
memset((void *)mcfg, 0, sizeof(struct acpi_mcfg)); |
||||
|
||||
/* Fill out header fields */ |
||||
fill_header(header, "MCFG", 4); |
||||
header->length = sizeof(struct acpi_mcfg); |
||||
|
||||
/* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */ |
||||
header->revision = ACPI_REV_ACPI_2_0; |
||||
|
||||
current = acpi_fill_mcfg(current); |
||||
|
||||
/* (Re)calculate length and checksum */ |
||||
header->length = current - (unsigned long)mcfg; |
||||
header->checksum = table_compute_checksum((void *)mcfg, header->length); |
||||
} |
||||
|
||||
static void acpi_create_facs(struct acpi_facs *facs) |
||||
{ |
||||
memset((void *)facs, 0, sizeof(struct acpi_facs)); |
||||
|
||||
memcpy(facs->signature, "FACS", 4); |
||||
facs->length = sizeof(struct acpi_facs); |
||||
facs->hardware_signature = 0; |
||||
facs->firmware_waking_vector = 0; |
||||
facs->global_lock = 0; |
||||
facs->flags = 0; |
||||
facs->x_firmware_waking_vector_l = 0; |
||||
facs->x_firmware_waking_vector_h = 0; |
||||
facs->version = 1; /* ACPI 1.0: 0, ACPI 2.0/3.0: 1, ACPI 4.0: 2 */ |
||||
} |
||||
|
||||
static void acpi_write_rsdt(struct acpi_rsdt *rsdt) |
||||
{ |
||||
acpi_header_t *header = &(rsdt->header); |
||||
|
||||
/* Fill out header fields */ |
||||
fill_header(header, "RSDT", 4); |
||||
header->length = sizeof(struct acpi_rsdt); |
||||
|
||||
/* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */ |
||||
header->revision = ACPI_REV_ACPI_2_0; |
||||
|
||||
/* Entries are filled in later, we come with an empty set */ |
||||
|
||||
/* Fix checksum */ |
||||
header->checksum = table_compute_checksum((void *)rsdt, |
||||
sizeof(struct acpi_rsdt)); |
||||
} |
||||
|
||||
static void acpi_write_xsdt(struct acpi_xsdt *xsdt) |
||||
{ |
||||
acpi_header_t *header = &(xsdt->header); |
||||
|
||||
/* Fill out header fields */ |
||||
fill_header(header, "XSDT", 4); |
||||
header->length = sizeof(struct acpi_xsdt); |
||||
|
||||
/* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */ |
||||
header->revision = ACPI_REV_ACPI_2_0; |
||||
|
||||
/* Entries are filled in later, we come with an empty set */ |
||||
|
||||
/* Fix checksum */ |
||||
header->checksum = table_compute_checksum((void *)xsdt, |
||||
sizeof(struct acpi_xsdt)); |
||||
} |
||||
|
||||
static void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt, |
||||
struct acpi_xsdt *xsdt) |
||||
{ |
||||
memset(rsdp, 0, sizeof(struct acpi_rsdp)); |
||||
|
||||
memcpy(rsdp->signature, RSDP_SIG, 8); |
||||
memcpy(rsdp->oem_id, OEM_ID, 6); |
||||
|
||||
rsdp->length = sizeof(struct acpi_rsdp); |
||||
rsdp->rsdt_address = (u32)rsdt; |
||||
|
||||
/*
|
||||
* Revision: ACPI 1.0: 0, ACPI 2.0/3.0/4.0: 2 |
||||
* |
||||
* Some OSes expect an XSDT to be present for RSD PTR revisions >= 2. |
||||
* If we don't have an ACPI XSDT, force ACPI 1.0 (and thus RSD PTR |
||||
* revision 0) |
||||
*/ |
||||
if (xsdt == NULL) { |
||||
rsdp->revision = ACPI_RSDP_REV_ACPI_1_0; |
||||
} else { |
||||
rsdp->xsdt_address = (u64)(u32)xsdt; |
||||
rsdp->revision = ACPI_RSDP_REV_ACPI_2_0; |
||||
} |
||||
|
||||
/* Calculate checksums */ |
||||
rsdp->checksum = table_compute_checksum((void *)rsdp, 20); |
||||
rsdp->ext_checksum = table_compute_checksum((void *)rsdp, |
||||
sizeof(struct acpi_rsdp)); |
||||
} |
||||
|
||||
static void acpi_create_ssdt_generator(acpi_header_t *ssdt, |
||||
const char *oem_table_id) |
||||
{ |
||||
unsigned long current = (unsigned long)ssdt + sizeof(acpi_header_t); |
||||
|
||||
memset((void *)ssdt, 0, sizeof(acpi_header_t)); |
||||
|
||||
memcpy(&ssdt->signature, "SSDT", 4); |
||||
/* Access size in ACPI 2.0c/3.0/4.0/5.0 */ |
||||
ssdt->revision = ACPI_REV_ACPI_3_0; |
||||
memcpy(&ssdt->oem_id, OEM_ID, 6); |
||||
memcpy(&ssdt->oem_table_id, oem_table_id, 8); |
||||
ssdt->oem_revision = OEM_REVISION; |
||||
memcpy(&ssdt->asl_compiler_id, ASLC, 4); |
||||
ssdt->asl_compiler_revision = ASL_COMPILER_REVISION; |
||||
ssdt->length = sizeof(acpi_header_t); |
||||
|
||||
/* (Re)calculate length and checksum */ |
||||
ssdt->length = current - (unsigned long)ssdt; |
||||
ssdt->checksum = table_compute_checksum((void *)ssdt, ssdt->length); |
||||
} |
||||
|
||||
unsigned long write_acpi_tables(unsigned long start) |
||||
{ |
||||
unsigned long current; |
||||
struct acpi_rsdp *rsdp; |
||||
struct acpi_rsdt *rsdt; |
||||
struct acpi_xsdt *xsdt; |
||||
struct acpi_facs *facs; |
||||
acpi_header_t *dsdt; |
||||
struct acpi_fadt *fadt; |
||||
struct acpi_mcfg *mcfg; |
||||
struct acpi_madt *madt; |
||||
acpi_header_t *ssdt; |
||||
|
||||
current = start; |
||||
|
||||
/* Align ACPI tables to 16byte */ |
||||
current = ALIGN(current, 16); |
||||
|
||||
debug("ACPI: Writing ACPI tables at %lx.\n", start); |
||||
|
||||
/* We need at least an RSDP and an RSDT Table */ |
||||
rsdp = (struct acpi_rsdp *)current; |
||||
current += sizeof(struct acpi_rsdp); |
||||
current = ALIGN(current, 16); |
||||
rsdt = (struct acpi_rsdt *)current; |
||||
current += sizeof(struct acpi_rsdt); |
||||
current = ALIGN(current, 16); |
||||
xsdt = (struct acpi_xsdt *)current; |
||||
current += sizeof(struct acpi_xsdt); |
||||
current = ALIGN(current, 16); |
||||
|
||||
/* clear all table memory */ |
||||
memset((void *)start, 0, current - start); |
||||
|
||||
acpi_write_rsdp(rsdp, rsdt, xsdt); |
||||
acpi_write_rsdt(rsdt); |
||||
acpi_write_xsdt(xsdt); |
||||
|
||||
debug("ACPI: * FACS\n"); |
||||
facs = (struct acpi_facs *)current; |
||||
current += sizeof(struct acpi_facs); |
||||
current = ALIGN(current, 16); |
||||
|
||||
acpi_create_facs(facs); |
||||
|
||||
debug("ACPI: * DSDT\n"); |
||||
dsdt = (acpi_header_t *)current; |
||||
memcpy(dsdt, &AmlCode, sizeof(acpi_header_t)); |
||||
if (dsdt->length >= sizeof(acpi_header_t)) { |
||||
current += sizeof(acpi_header_t); |
||||
memcpy((char *)current, |
||||
(char *)&AmlCode + sizeof(acpi_header_t), |
||||
dsdt->length - sizeof(acpi_header_t)); |
||||
current += dsdt->length - sizeof(acpi_header_t); |
||||
|
||||
/* (Re)calculate length and checksum */ |
||||
dsdt->length = current - (unsigned long)dsdt; |
||||
dsdt->checksum = 0; |
||||
dsdt->checksum = table_compute_checksum((void *)dsdt, |
||||
dsdt->length); |
||||
} |
||||
current = ALIGN(current, 16); |
||||
|
||||
debug("ACPI: * FADT\n"); |
||||
fadt = (struct acpi_fadt *)current; |
||||
current += sizeof(struct acpi_fadt); |
||||
current = ALIGN(current, 16); |
||||
acpi_create_fadt(fadt, facs, dsdt); |
||||
acpi_add_table(rsdp, fadt); |
||||
|
||||
debug("ACPI: * MCFG\n"); |
||||
mcfg = (struct acpi_mcfg *)current; |
||||
acpi_create_mcfg(mcfg); |
||||
if (mcfg->header.length > sizeof(struct acpi_mcfg)) { |
||||
current += mcfg->header.length; |
||||
current = ALIGN(current, 16); |
||||
acpi_add_table(rsdp, mcfg); |
||||
} |
||||
|
||||
debug("ACPI: * MADT\n"); |
||||
madt = (struct acpi_madt *)current; |
||||
acpi_create_madt(madt); |
||||
if (madt->header.length > sizeof(struct acpi_madt)) { |
||||
current += madt->header.length; |
||||
acpi_add_table(rsdp, madt); |
||||
} |
||||
current = ALIGN(current, 16); |
||||
|
||||
debug("ACPI: * SSDT\n"); |
||||
ssdt = (acpi_header_t *)current; |
||||
acpi_create_ssdt_generator(ssdt, ACPI_TABLE_CREATOR); |
||||
if (ssdt->length > sizeof(acpi_header_t)) { |
||||
current += ssdt->length; |
||||
acpi_add_table(rsdp, ssdt); |
||||
current = ALIGN(current, 16); |
||||
} |
||||
|
||||
debug("current = %lx\n", current); |
||||
|
||||
debug("ACPI: done.\n"); |
||||
|
||||
return current; |
||||
} |
Loading…
Reference in new issue