diff options
author | Damien Zammit <damien@zamaudio.com> | 2021-04-03 15:27:16 +1100 |
---|---|---|
committer | Damien Zammit <damien@zamaudio.com> | 2021-04-03 23:03:24 +1100 |
commit | ca5ce0c9b66a8d4128b6c9292adb328bcb732fac (patch) | |
tree | af973d9c4cdd889bd5fe9d941ed4b86868a22ff2 | |
parent | 41fb05b4944ea35a23cadfe81fb978ae34848e04 (diff) |
libacpica: Add acpi_init
-rw-r--r-- | libacpica/acpi_init.c | 612 | ||||
-rw-r--r-- | libacpica/acpi_init.h | 10 |
2 files changed, 622 insertions, 0 deletions
diff --git a/libacpica/acpi_init.c b/libacpica/acpi_init.c new file mode 100644 index 00000000..f5ab987b --- /dev/null +++ b/libacpica/acpi_init.c @@ -0,0 +1,612 @@ +#define EXPORT_ACPI_INTERFACES +#define DEFINE_ACPI_GLOBALS +#include "acpi_init.h" +#include "accommon.h" +#include "acglobal.h" +#include "utglobal.c" + +#include <stdio.h> +#include <sys/time.h> +#include <sys/io.h> +#include <stddef.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> +#include <mach/vm_param.h> +#include <errno.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdarg.h> +#include <semaphore.h> + +#define ACPI_MAX_TABLES 128 + +// Lets keep the ACPI tables in this module +static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES]; + +struct slots { + uint8_t bus; + uint16_t dev; + uint16_t func; + acpi_handle handle; + struct slots *next; +}; + +acpi_status +acpi_os_enter_sleep(u8 sleep_state, u32 pm1a, u32 pm1b) +{ + return AE_OK; +} + +void +acpi_ds_dump_method_stack(acpi_status status, ...) +// struct acpi_walk_state *walk_state, +// union acpi_parse_object *op) +{ + return; +} + +void +acpi_os_printf(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + acpi_os_vprintf(fmt, args); + va_end(args); +} + +void +acpi_os_vprintf(const char *fmt, va_list args) +{ + vprintf(fmt, args); +} + +acpi_status +acpi_os_create_lock(acpi_spinlock *lockp) +{ + acpi_semaphore sema = NULL; + if (acpi_os_create_semaphore(1, 0, &sema) == AE_OK) { + *lockp = sema; + return AE_OK; + } + return AE_ERROR; +} + +acpi_cpu_flags +acpi_os_acquire_lock(acpi_spinlock lockp) +{ + acpi_os_wait_semaphore(lockp, 1, 0); + return 0; +} + +void +acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags) +{ + acpi_os_signal_semaphore(lockp, 1); +} + +void +acpi_os_delete_lock(acpi_spinlock lockp) +{ + acpi_os_delete_semaphore(lockp); +} + +acpi_status +acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_semaphore * handle) +{ + acpi_semaphore sema = NULL; + + sema = acpi_os_allocate_zeroed(sizeof (sem_t)); + + if (!sem_init(sema, 0, initial_units)) { + *handle = sema; + return AE_OK; + } + return AE_ERROR; + + +} + +acpi_status +acpi_os_delete_semaphore(acpi_semaphore handle) +{ + if (!sem_destroy(handle)) { + free (handle); + return AE_OK; + } + return AE_ERROR; +} + +acpi_status +acpi_os_wait_semaphore(acpi_semaphore handle, u32 units, u16 timeout) +{ + int i; + + if (!timeout) + timeout = 1; + + for (i = 0; i < timeout; i++) { + if (!sem_trywait(handle)) { + return AE_OK; + } + } + + return AE_ERROR; +} + +acpi_status +acpi_os_signal_semaphore(acpi_semaphore handle, u32 units) +{ + if (!sem_post(handle)) { + return AE_OK; + } + return AE_ERROR; +} + +acpi_status +acpi_os_execute(acpi_execute_type type, + acpi_osd_exec_callback function, void *context) +{ + pthread_t thread; + + if (pthread_create (&thread, NULL, (void *)function, context)) + return AE_ERROR; + + pthread_detach(thread); + return AE_OK; +} + +acpi_physical_address +acpi_os_get_root_pointer(void) +{ + acpi_physical_address pa; + + acpi_find_root_pointer(&pa); + return pa; +} + +/* Supposed to be 64 bit free-running + * monotonic timer with 100ns granularity + */ +u64 +acpi_os_get_timer(void) +{ + struct timespec now; + + clock_gettime(CLOCK_MONOTONIC, &now); + return (u64)(now.tv_sec * 10000000 + (now.tv_nsec / 100)); +} + +void * +acpi_os_map_memory(acpi_physical_address phys, acpi_size size) +{ + int fd_mem; + void * virt_addr; + uintptr_t into_page = phys % PAGE_SIZE; + uintptr_t nearest_page = (uintptr_t)trunc_page(phys); + + if ((fd_mem = open("/dev/mem", O_RDWR)) < 0) { + acpi_os_printf("Can't open /dev/mem\n"); + return (void *)-1; + } + + /* MAP_FIXED so we can access particular physical regions */ + virt_addr = mmap(NULL, into_page + size, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED, fd_mem, nearest_page); + if (virt_addr == MAP_FAILED) { + acpi_os_printf("Can't map memory 0x%llx\n", phys); + return (void *)-1; + } + + return virt_addr + into_page; +} + +acpi_status +acpi_os_read_port(acpi_io_address port, u32 * value, u32 width) +{ + if (!value) + return AE_ERROR; + + switch (width) { + case 8: + *((u8 *)value) = inb(port); + return AE_OK; + case 16: + *((u16 *)value) = inw(port); + return AE_OK; + case 32: + *((u32 *)value) = inl(port); + return AE_OK; + default: + acpi_os_printf("ACPI: read port invalid width\n"); + return AE_ERROR; + } + return AE_ERROR; +} + +acpi_status +acpi_os_predefined_override(const struct acpi_predefined_names *init_val, + acpi_string *new_val) +{ + if (!init_val || !new_val) + return AE_BAD_PARAMETER; + + *new_val = init_val->val; + + return AE_OK; +} + +acpi_status +acpi_os_signal(u32 function, void *info) +{ + switch (function) { + case ACPI_SIGNAL_FATAL: + acpi_os_printf("ACPI: Fatal opcode executed\n"); + break; + case ACPI_SIGNAL_BREAKPOINT: + break; + default: + break; + } + return AE_OK; +} + +acpi_status +acpi_os_physical_table_override(struct acpi_table_header *existing_table, + acpi_physical_address *address, + u32 *table_length) +{ + *table_length = 0; + *address = 0; + return AE_OK; +} + +acpi_status +acpi_os_table_override(struct acpi_table_header *existing_table, + struct acpi_table_header **new_table) +{ + if (!existing_table || !new_table) + return AE_BAD_PARAMETER; + + *new_table = NULL; + return AE_OK; +} + +void +acpi_os_unmap_memory(void *virt, acpi_size size) +{ + void *freeme = (void *)trunc_page(virt); + if (!freeme) { + acpi_os_printf("Nothing to unmap\n"); + return; + } + munmap(freeme, size + size); +} + +static acpi_status +acpi_os_read_iomem(void *virt_addr, u64 *value, u32 width) +{ + + switch (width) { + case 8: + *(u8 *) value = *((volatile u8 *)virt_addr); + break; + case 16: + *(u16 *) value = *((volatile u16 *)virt_addr); + break; + case 32: + *(u32 *) value = *((volatile u32 *)virt_addr); + break; + case 64: + *(u64 *) value = *((volatile u64 *)virt_addr); + break; + default: + return AE_ERROR; + } + return AE_OK; +} + +acpi_status +acpi_os_read_memory(acpi_physical_address phys_addr, u64 *value, u32 width) +{ + void *virt_addr; + unsigned int size = width / 8; + acpi_status err = AE_BAD_ADDRESS; + + if (!value) + return err; + + virt_addr = acpi_os_map_memory (phys_addr, size); + if (!virt_addr) + return err; + + if (!acpi_os_read_iomem (virt_addr, value, width)) + err = AE_OK; + + acpi_os_unmap_memory (virt_addr, size); + + return err; +} + +void +acpi_os_sleep(u64 ms) +{ + usleep(1000 * ms); +} + +void +acpi_os_stall(u32 us) +{ + usleep(us); +} + +void acpi_os_wait_events_complete(void) +{ + return; +} + +acpi_status +acpi_os_write_memory(acpi_physical_address phys_addr, u64 value, u32 width) +{ + void *virt_addr; + unsigned int size = width / 8; + acpi_status err = AE_OK; + + virt_addr = acpi_os_map_memory (phys_addr, size); + if (!virt_addr) + return AE_BAD_ADDRESS; + + switch (width) { + case 8: + *((volatile u8 *)virt_addr) = (u8)value; + break; + case 16: + *((volatile u16 *)virt_addr) = (u16)value; + break; + case 32: + *((volatile u32 *)virt_addr) = (u32)value; + break; + case 64: + *((volatile u64 *)virt_addr) = value; + break; + default: + acpi_os_printf("ACPI: Bad write memory width\n"); + err = AE_BAD_ADDRESS; + break; + } + + acpi_os_unmap_memory (virt_addr, size); + + return err; +} + +acpi_status +acpi_os_write_port(acpi_io_address port, u32 value, u32 width) +{ + switch (width) { + case 8: + outb(port, value); + return AE_OK; + case 16: + outw(port, value); + return AE_OK; + case 32: + outl(port, value); + return AE_OK; + default: + acpi_os_printf("ACPI: Bad write port width\n"); + return AE_ERROR; + } + + return AE_ERROR; +} + + +acpi_status +acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, + void *context) +{ + acpi_os_printf("TODO: install interrupt handler for acpi\n"); + return AE_ERROR; +} + +acpi_status +acpi_os_remove_interrupt_handler(u32 gsi, acpi_osd_handler handler) +{ + acpi_os_printf("TODO: remove interrupt handler for acpi\n"); + return AE_ERROR; +} + +acpi_status +acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, + u64 *value, u32 width) +{ + acpi_os_printf("ACPI: Tried to read pci config\n"); + return AE_ERROR; +} + +acpi_status +acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, + u64 value, u32 width) +{ + acpi_os_printf("ACPI: Tried to write pci config\n"); + return AE_ERROR; +} + +acpi_status +acpi_os_initialize(void) +{ + if (ioperm(0, 0x10000, 1)) { + fprintf(stderr, "EPERM on ioperm()\n"); + return AE_IO_ERROR; + } + return AE_OK; +} + +acpi_status +acpi_os_terminate(void) +{ + acpi_os_printf("Bye!\n"); + return AE_OK; +} + +static acpi_status +register_slot(acpi_handle handle, u32 lev, void *context, void **rv) +{ + struct slots *s; + struct acpi_device *acpi_dev; + uint64_t addr; + acpi_status err; + + context = (void *)malloc(sizeof (struct slots)); + s = (struct slots *)context; + + if (acpi_get_data(handle, NULL, (void **)&acpi_dev)) + return AE_ERROR; + + { + struct acpi_buffer buffer = { 0, NULL }; + union acpi_object element; + buffer.pointer = &element; + err = acpi_evaluate_object(handle, "_BBN", NULL, &buffer); + if (ACPI_FAILURE(err)) + return err; + if (element.type != ACPI_TYPE_INTEGER) + return AE_BAD_DATA; + addr = element.integer.value; + } + + s->bus = addr & 0xff; + + { + struct acpi_buffer buffer = { 0, NULL }; + union acpi_object element; + buffer.pointer = &element; + err = acpi_evaluate_object(handle, "_ADR", NULL, &buffer); + if (ACPI_FAILURE(err)) + return err; + if (element.type != ACPI_TYPE_INTEGER) + return AE_BAD_DATA; + addr = element.integer.value; + } + + s->dev = (addr >> 16) & 0xffff; + s->func = addr & 0xffff; + s->handle = handle; + + return AE_OK; +} + +void +acpi_enter_sleep(int sleep_state) +{ + acpi_hw_legacy_sleep (sleep_state); +} + +int +acpi_get_irq_number(uint16_t bus, uint16_t dev, uint16_t func) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_pci_routing_table *entry; + acpi_handle handle = ACPI_ROOT_OBJECT; + acpi_handle parent_handle = NULL; + acpi_handle lnk = NULL; + acpi_status err = AE_OK; + u16 prt_dev, prt_func; + struct slots *pcislots = NULL, *iter; + int nslots = 0; + + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, register_slot, NULL, pcislots, NULL); + + for (iter = pcislots; iter; iter = iter->next) { + if ((iter->bus == bus) && (iter->dev == dev) && (iter->func & func)) { + handle = iter->handle; + } + nslots++; + } + + err = acpi_get_parent(handle, &parent_handle); + if (ACPI_FAILURE(err)) + return err; + + err = acpi_get_irq_routing_table(parent_handle, &buffer); + if (ACPI_FAILURE(err)) { + free(buffer.pointer); + // FIXME free the pcislots list + return -1; + } + + entry = buffer.pointer; + while (entry && (entry->length > 0)) { + /* Already applies to the bus of the device */ + prt_dev = (entry->address >> 16) & 0xffff; + prt_func = entry->address & 0xffff; + if ((prt_dev == dev) && (prt_func & func)) { + if (entry->source[0]) { + /* Dynamic: + * - source field specifies PCI interrupt LNK + * - source_index specifies which resource descriptor in + * resource template of LNK to allocate this interrupt + */ + acpi_get_handle(entry, entry->source, &lnk); + // FIXME check the LNK irq _CRS and then set it with _SRS + + } else { + /* Static: + * - source field is zero + * - source_index specifies IRQ value hardwired to + * interrupt inputs on controller + */ + return entry->source_index; + } + } + entry = (struct acpi_pci_routing_table *)((size_t)entry + entry->length); + } + return -1; +} + +void acpi_init(void) +{ + acpi_status err; + + // Hack to increase verbosity except parsing AML + //acpi_dbg_level = (ACPI_LV_ALL) & ~(ACPI_LV_FUNCTIONS); + + err = acpi_initialize_subsystem (); + if (ACPI_FAILURE (err)) { + goto die; + } + + err = acpi_initialize_tables (initial_tables, ACPI_MAX_TABLES, 0); + if (ACPI_FAILURE (err)) { + goto die; + } + + err = acpi_reallocate_root_table (); + if (ACPI_FAILURE (err)) { + goto die; + } + + err = acpi_load_tables (); + if (ACPI_FAILURE (err)) { + goto die; + } + + err = acpi_initialize_objects (ACPI_FULL_INITIALIZATION); + if (ACPI_FAILURE (err)) { + goto die; + } +/* + err = acpi_enable_subsystem (ACPI_FULL_INITIALIZATION); + if (ACPI_FAILURE (err)) { + goto die; + } +*/ + acpi_os_printf("PASS!\n"); + return; +die: + acpi_os_printf("OUCH!\n"); +} diff --git a/libacpica/acpi_init.h b/libacpica/acpi_init.h new file mode 100644 index 00000000..9d996f29 --- /dev/null +++ b/libacpica/acpi_init.h @@ -0,0 +1,10 @@ +#ifndef ACPI_INIT_H +#define ACPI_INIT_H + +#include <acpi/acpi.h> + +void acpi_enter_sleep(int sleep_state); +int acpi_get_irq_number(uint16_t bus, uint16_t dev, uint16_t func); +void acpi_init(void); + +#endif |