1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <inttypes.h> 6#include <limits.h> 7#include <ddk/debug.h> 8#include <ddk/device.h> 9#include <ddk/protocol/intel-hda-dsp.h> 10#include <zircon/process.h> 11 12#include "errors.h" 13#include "nhlt.h" 14 15/** 16 * Reference: 17 * 18 * Intel Smart Sound Technology Audio DSP Non-HD Audio ACPI High Level Design 19 * Architecture Guide/Overview 20 * Revision 0.7 21 * November 2015 22 * 23 * 561555_SST Non-HD Audio ACPI HLD v0 7_DRAFT.pdf 24 */ 25 26static const uint8_t NHLT_UUID[] = { 27/* 0000 */ 0x6E, 0x88, 0x9F, 0xA6, 0xEB, 0x6C, 0x94, 0x45, 28/* 0008 */ 0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53 29}; 30 31zx_status_t nhlt_publish_metadata(zx_device_t* dev, uint8_t bbn, uint64_t adr, ACPI_HANDLE object) { 32 zx_status_t status = ZX_OK; 33 34 // parameters 35 ACPI_OBJECT objs[] = { 36 { // uuid 37 .Buffer.Type = ACPI_TYPE_BUFFER, 38 .Buffer.Length = sizeof(NHLT_UUID), 39 .Buffer.Pointer = (void*)NHLT_UUID, 40 }, 41 { // revision id 42 .Integer.Type = ACPI_TYPE_INTEGER, 43 .Integer.Value = 1, 44 }, 45 { // function id 46 .Integer.Type = ACPI_TYPE_INTEGER, 47 .Integer.Value = 1, 48 }, 49 }; 50 ACPI_OBJECT_LIST params = { 51 .Count = countof(objs), 52 .Pointer = objs, 53 }; 54 55 // output buffer 56 ACPI_BUFFER out = { 57 .Length = ACPI_ALLOCATE_BUFFER, 58 .Pointer = NULL, 59 }; 60 61 // Fetch the NHLT resource 62 ACPI_STATUS acpi_status = AcpiEvaluateObject(object, (char*)"_DSM", ¶ms, &out); 63 if (acpi_status != AE_OK) { 64 zxlogf(TRACE, "acpi: failed to fetch NHLT blob (acpi_status %u)\n", acpi_status); 65 return acpi_to_zx_status(acpi_status); 66 } 67 68 ACPI_OBJECT* out_obj = out.Pointer; 69 if (out_obj->Type != ACPI_TYPE_BUFFER) { 70 zxlogf(ERROR, "acpi: unexpected object type (%u) for NHLT blob\n", out_obj->Type); 71 status = ZX_ERR_INTERNAL; 72 goto out; 73 } 74 75 ACPI_RESOURCE* res = NULL; 76 acpi_status = AcpiBufferToResource(out_obj->Buffer.Pointer, out_obj->Buffer.Length, &res); 77 if (acpi_status != AE_OK) { 78 zxlogf(ERROR, "acpi: failed to parse NHLT resource (acpi_status %u)\n", acpi_status); 79 status = acpi_to_zx_status(acpi_status); 80 goto out; 81 } 82 83 if (res->Type != ACPI_RESOURCE_TYPE_ADDRESS64) { 84 zxlogf(ERROR, "acpi: unexpected NHLT resource type (%u)\n", res->Type); 85 status = ZX_ERR_INTERNAL; 86 goto out; 87 } 88 89 zx_paddr_t paddr = (zx_paddr_t)res->Data.Address64.Address.Minimum; 90 size_t size = (size_t)res->Data.Address64.Address.AddressLength; 91 92 // Read the blob 93 zx_handle_t vmo; 94 zx_paddr_t page_start = ROUNDDOWN(paddr, PAGE_SIZE); 95 size_t page_offset = (paddr & (PAGE_SIZE-1)); 96 size_t page_size = ROUNDUP(page_offset + size, PAGE_SIZE); 97 status = zx_vmo_create_physical(get_root_resource(), page_start, page_size, &vmo); 98 if (status != ZX_OK) { 99 zxlogf(ERROR, "acpi: failed to create NHLT VMO (res %d)\n", status); 100 goto out; 101 } 102 103 // We cannot read physical VMOs directly and must map it 104 zx_vaddr_t vaddr = 0; 105 status = zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ, 0, vmo, 0, page_size, &vaddr); 106 if (status != ZX_OK) { 107 zxlogf(ERROR, "acpi: failed to map NHLT blob (res %d)\n", status); 108 goto out; 109 } 110 void* nhlt = (void*)(vaddr + page_offset); 111 112 // Publish the NHLT as metadata on the future PCI device node... 113 // The canonical path to the PCI device is /dev/sys/pci/<b:d.f> 114 char path[PATH_MAX]; 115 snprintf(path, sizeof(path), "/dev/sys/pci/%02x:%02x.%01x", bbn, 116 (unsigned)((adr >> 16) & 0xFFFF), (unsigned)(adr & 0xFFFF)); 117 status = device_publish_metadata(dev, path, MD_KEY_NHLT, nhlt, size); 118 if (status != ZX_OK) { 119 zxlogf(ERROR, "acpi: failed to publish NHLT metadata (res %d)\n", status); 120 } 121 122 zxlogf(TRACE, "acpi: published NHLT metadata for device at %s\n", path); 123 124 zx_vmar_unmap(zx_vmar_root_self(), vaddr, ROUNDUP(size, PAGE_SIZE)); 125out: 126 ACPI_FREE(out.Pointer); 127 return status; 128} 129