summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Zammit <damien@zamaudio.com>2021-04-03 15:27:16 +1100
committerDamien Zammit <damien@zamaudio.com>2021-04-03 23:03:24 +1100
commitca5ce0c9b66a8d4128b6c9292adb328bcb732fac (patch)
treeaf973d9c4cdd889bd5fe9d941ed4b86868a22ff2
parent41fb05b4944ea35a23cadfe81fb978ae34848e04 (diff)
libacpica: Add acpi_init
-rw-r--r--libacpica/acpi_init.c612
-rw-r--r--libacpica/acpi_init.h10
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