1 /* 2 * skl-nhlt.c - Intel SKL Platform NHLT parsing 3 * 4 * Copyright (C) 2015 Intel Corp 5 * Author: Sanjiv Kumar <sanjiv.kumar@intel.com> 6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; version 2 of the License. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 * 19 */ 20 #include "skl.h" 21 22 /* Unique identification for getting NHLT blobs */ 23 static u8 OSC_UUID[16] = {0x6E, 0x88, 0x9F, 0xA6, 0xEB, 0x6C, 0x94, 0x45, 24 0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53}; 25 26 #define DSDT_NHLT_PATH "\\_SB.PCI0.HDAS" 27 28 void *skl_nhlt_init(struct device *dev) 29 { 30 acpi_handle handle; 31 union acpi_object *obj; 32 struct nhlt_resource_desc *nhlt_ptr = NULL; 33 34 if (ACPI_FAILURE(acpi_get_handle(NULL, DSDT_NHLT_PATH, &handle))) { 35 dev_err(dev, "Requested NHLT device not found\n"); 36 return NULL; 37 } 38 39 obj = acpi_evaluate_dsm(handle, OSC_UUID, 1, 1, NULL); 40 if (obj && obj->type == ACPI_TYPE_BUFFER) { 41 nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer; 42 43 return memremap(nhlt_ptr->min_addr, nhlt_ptr->length, 44 MEMREMAP_WB); 45 } 46 47 dev_err(dev, "device specific method to extract NHLT blob failed\n"); 48 return NULL; 49 } 50 51 void skl_nhlt_free(void *addr) 52 { 53 memunmap(addr); 54 } 55 56 static struct nhlt_specific_cfg *skl_get_specific_cfg( 57 struct device *dev, struct nhlt_fmt *fmt, 58 u8 no_ch, u32 rate, u16 bps, u8 linktype) 59 { 60 struct nhlt_specific_cfg *sp_config; 61 struct wav_fmt *wfmt; 62 struct nhlt_fmt_cfg *fmt_config = fmt->fmt_config; 63 int i; 64 65 dev_dbg(dev, "Format count =%d\n", fmt->fmt_count); 66 67 for (i = 0; i < fmt->fmt_count; i++) { 68 wfmt = &fmt_config->fmt_ext.fmt; 69 dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", wfmt->channels, 70 wfmt->bits_per_sample, wfmt->samples_per_sec); 71 if (wfmt->channels == no_ch && wfmt->bits_per_sample == bps) { 72 /* 73 * if link type is dmic ignore rate check as the blob is 74 * generic for all rates 75 */ 76 sp_config = &fmt_config->config; 77 if (linktype == NHLT_LINK_DMIC) 78 return sp_config; 79 80 if (wfmt->samples_per_sec == rate) 81 return sp_config; 82 } 83 84 fmt_config = (struct nhlt_fmt_cfg *)(fmt_config->config.caps + 85 fmt_config->config.size); 86 } 87 88 return NULL; 89 } 90 91 static void dump_config(struct device *dev, u32 instance_id, u8 linktype, 92 u8 s_fmt, u8 num_channels, u32 s_rate, u8 dirn, u16 bps) 93 { 94 dev_dbg(dev, "Input configuration\n"); 95 dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", num_channels, s_fmt, s_rate); 96 dev_dbg(dev, "vbus_id=%d link_type=%d\n", instance_id, linktype); 97 dev_dbg(dev, "bits_per_sample=%d\n", bps); 98 } 99 100 static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt, 101 u32 instance_id, u8 link_type, u8 dirn) 102 { 103 dev_dbg(dev, "vbus_id=%d link_type=%d dir=%d\n", 104 epnt->virtual_bus_id, epnt->linktype, epnt->direction); 105 106 if ((epnt->virtual_bus_id == instance_id) && 107 (epnt->linktype == link_type) && 108 (epnt->direction == dirn)) 109 return true; 110 else 111 return false; 112 } 113 114 struct nhlt_specific_cfg 115 *skl_get_ep_blob(struct skl *skl, u32 instance, u8 link_type, 116 u8 s_fmt, u8 num_ch, u32 s_rate, u8 dirn) 117 { 118 struct nhlt_fmt *fmt; 119 struct nhlt_endpoint *epnt; 120 struct hdac_bus *bus = ebus_to_hbus(&skl->ebus); 121 struct device *dev = bus->dev; 122 struct nhlt_specific_cfg *sp_config; 123 struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; 124 u16 bps = (s_fmt == 16) ? 16 : 32; 125 u8 j; 126 127 dump_config(dev, instance, link_type, s_fmt, num_ch, s_rate, dirn, bps); 128 129 epnt = (struct nhlt_endpoint *)nhlt->desc; 130 131 dev_dbg(dev, "endpoint count =%d\n", nhlt->endpoint_count); 132 133 for (j = 0; j < nhlt->endpoint_count; j++) { 134 if (skl_check_ep_match(dev, epnt, instance, link_type, dirn)) { 135 fmt = (struct nhlt_fmt *)(epnt->config.caps + 136 epnt->config.size); 137 sp_config = skl_get_specific_cfg(dev, fmt, num_ch, 138 s_rate, bps, link_type); 139 if (sp_config) 140 return sp_config; 141 } 142 143 epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); 144 } 145 146 return NULL; 147 } 148