1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * skl-nhlt.c - Intel SKL Platform NHLT parsing 4 * 5 * Copyright (C) 2015 Intel Corp 6 * Author: Sanjiv Kumar <sanjiv.kumar@intel.com> 7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 * 9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 10 */ 11 #include <linux/pci.h> 12 #include <sound/intel-nhlt.h> 13 #include "skl.h" 14 #include "skl-i2s.h" 15 16 static struct nhlt_specific_cfg *skl_get_specific_cfg( 17 struct device *dev, struct nhlt_fmt *fmt, 18 u8 no_ch, u32 rate, u16 bps, u8 linktype) 19 { 20 struct nhlt_specific_cfg *sp_config; 21 struct wav_fmt *wfmt; 22 struct nhlt_fmt_cfg *fmt_config = fmt->fmt_config; 23 int i; 24 25 dev_dbg(dev, "Format count =%d\n", fmt->fmt_count); 26 27 for (i = 0; i < fmt->fmt_count; i++) { 28 wfmt = &fmt_config->fmt_ext.fmt; 29 dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", wfmt->channels, 30 wfmt->bits_per_sample, wfmt->samples_per_sec); 31 if (wfmt->channels == no_ch && wfmt->bits_per_sample == bps) { 32 /* 33 * if link type is dmic ignore rate check as the blob is 34 * generic for all rates 35 */ 36 sp_config = &fmt_config->config; 37 if (linktype == NHLT_LINK_DMIC) 38 return sp_config; 39 40 if (wfmt->samples_per_sec == rate) 41 return sp_config; 42 } 43 44 fmt_config = (struct nhlt_fmt_cfg *)(fmt_config->config.caps + 45 fmt_config->config.size); 46 } 47 48 return NULL; 49 } 50 51 static void dump_config(struct device *dev, u32 instance_id, u8 linktype, 52 u8 s_fmt, u8 num_channels, u32 s_rate, u8 dirn, u16 bps) 53 { 54 dev_dbg(dev, "Input configuration\n"); 55 dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", num_channels, s_fmt, s_rate); 56 dev_dbg(dev, "vbus_id=%d link_type=%d\n", instance_id, linktype); 57 dev_dbg(dev, "bits_per_sample=%d\n", bps); 58 } 59 60 static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt, 61 u32 instance_id, u8 link_type, u8 dirn, u8 dev_type) 62 { 63 dev_dbg(dev, "vbus_id=%d link_type=%d dir=%d dev_type = %d\n", 64 epnt->virtual_bus_id, epnt->linktype, 65 epnt->direction, epnt->device_type); 66 67 if ((epnt->virtual_bus_id == instance_id) && 68 (epnt->linktype == link_type) && 69 (epnt->direction == dirn)) { 70 /* do not check dev_type for DMIC link type */ 71 if (epnt->linktype == NHLT_LINK_DMIC) 72 return true; 73 74 if (epnt->device_type == dev_type) 75 return true; 76 } 77 78 return false; 79 } 80 81 struct nhlt_specific_cfg 82 *skl_get_ep_blob(struct skl_dev *skl, u32 instance, u8 link_type, 83 u8 s_fmt, u8 num_ch, u32 s_rate, 84 u8 dirn, u8 dev_type) 85 { 86 struct nhlt_fmt *fmt; 87 struct nhlt_endpoint *epnt; 88 struct hdac_bus *bus = skl_to_bus(skl); 89 struct device *dev = bus->dev; 90 struct nhlt_specific_cfg *sp_config; 91 struct nhlt_acpi_table *nhlt = skl->nhlt; 92 u16 bps = (s_fmt == 16) ? 16 : 32; 93 u8 j; 94 95 dump_config(dev, instance, link_type, s_fmt, num_ch, s_rate, dirn, bps); 96 97 epnt = (struct nhlt_endpoint *)nhlt->desc; 98 99 dev_dbg(dev, "endpoint count =%d\n", nhlt->endpoint_count); 100 101 for (j = 0; j < nhlt->endpoint_count; j++) { 102 if (skl_check_ep_match(dev, epnt, instance, link_type, 103 dirn, dev_type)) { 104 fmt = (struct nhlt_fmt *)(epnt->config.caps + 105 epnt->config.size); 106 sp_config = skl_get_specific_cfg(dev, fmt, num_ch, 107 s_rate, bps, link_type); 108 if (sp_config) 109 return sp_config; 110 } 111 112 epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); 113 } 114 115 return NULL; 116 } 117 118 static void skl_nhlt_trim_space(char *trim) 119 { 120 char *s = trim; 121 int cnt; 122 int i; 123 124 cnt = 0; 125 for (i = 0; s[i]; i++) { 126 if (!isspace(s[i])) 127 s[cnt++] = s[i]; 128 } 129 130 s[cnt] = '\0'; 131 } 132 133 int skl_nhlt_update_topology_bin(struct skl_dev *skl) 134 { 135 struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; 136 struct hdac_bus *bus = skl_to_bus(skl); 137 struct device *dev = bus->dev; 138 139 dev_dbg(dev, "oem_id %.6s, oem_table_id %.8s oem_revision %d\n", 140 nhlt->header.oem_id, nhlt->header.oem_table_id, 141 nhlt->header.oem_revision); 142 143 snprintf(skl->tplg_name, sizeof(skl->tplg_name), "%x-%.6s-%.8s-%d%s", 144 skl->pci_id, nhlt->header.oem_id, nhlt->header.oem_table_id, 145 nhlt->header.oem_revision, "-tplg.bin"); 146 147 skl_nhlt_trim_space(skl->tplg_name); 148 149 return 0; 150 } 151 152 static ssize_t skl_nhlt_platform_id_show(struct device *dev, 153 struct device_attribute *attr, char *buf) 154 { 155 struct pci_dev *pci = to_pci_dev(dev); 156 struct hdac_bus *bus = pci_get_drvdata(pci); 157 struct skl_dev *skl = bus_to_skl(bus); 158 struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; 159 char platform_id[32]; 160 161 sprintf(platform_id, "%x-%.6s-%.8s-%d", skl->pci_id, 162 nhlt->header.oem_id, nhlt->header.oem_table_id, 163 nhlt->header.oem_revision); 164 165 skl_nhlt_trim_space(platform_id); 166 return sprintf(buf, "%s\n", platform_id); 167 } 168 169 static DEVICE_ATTR(platform_id, 0444, skl_nhlt_platform_id_show, NULL); 170 171 int skl_nhlt_create_sysfs(struct skl_dev *skl) 172 { 173 struct device *dev = &skl->pci->dev; 174 175 if (sysfs_create_file(&dev->kobj, &dev_attr_platform_id.attr)) 176 dev_warn(dev, "Error creating sysfs entry\n"); 177 178 return 0; 179 } 180 181 void skl_nhlt_remove_sysfs(struct skl_dev *skl) 182 { 183 struct device *dev = &skl->pci->dev; 184 185 if (skl->nhlt) 186 sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr); 187 } 188 189 /* 190 * Queries NHLT for all the fmt configuration for a particular endpoint and 191 * stores all possible rates supported in a rate table for the corresponding 192 * sclk/sclkfs. 193 */ 194 static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks, 195 struct nhlt_fmt *fmt, u8 id) 196 { 197 struct skl_i2s_config_blob_ext *i2s_config_ext; 198 struct skl_i2s_config_blob_legacy *i2s_config; 199 struct skl_clk_parent_src *parent; 200 struct skl_ssp_clk *sclk, *sclkfs; 201 struct nhlt_fmt_cfg *fmt_cfg; 202 struct wav_fmt_ext *wav_fmt; 203 unsigned long rate; 204 bool present = false; 205 int rate_index = 0; 206 u16 channels, bps; 207 u8 clk_src; 208 int i, j; 209 u32 fs; 210 211 sclk = &ssp_clks[SKL_SCLK_OFS]; 212 sclkfs = &ssp_clks[SKL_SCLKFS_OFS]; 213 214 if (fmt->fmt_count == 0) 215 return; 216 217 for (i = 0; i < fmt->fmt_count; i++) { 218 fmt_cfg = &fmt->fmt_config[i]; 219 wav_fmt = &fmt_cfg->fmt_ext; 220 221 channels = wav_fmt->fmt.channels; 222 bps = wav_fmt->fmt.bits_per_sample; 223 fs = wav_fmt->fmt.samples_per_sec; 224 225 /* 226 * In case of TDM configuration on a ssp, there can 227 * be more than one blob in which channel masks are 228 * different for each usecase for a specific rate and bps. 229 * But the sclk rate will be generated for the total 230 * number of channels used for that endpoint. 231 * 232 * So for the given fs and bps, choose blob which has 233 * the superset of all channels for that endpoint and 234 * derive the rate. 235 */ 236 for (j = i; j < fmt->fmt_count; j++) { 237 fmt_cfg = &fmt->fmt_config[j]; 238 wav_fmt = &fmt_cfg->fmt_ext; 239 if ((fs == wav_fmt->fmt.samples_per_sec) && 240 (bps == wav_fmt->fmt.bits_per_sample)) 241 channels = max_t(u16, channels, 242 wav_fmt->fmt.channels); 243 } 244 245 rate = channels * bps * fs; 246 247 /* check if the rate is added already to the given SSP's sclk */ 248 for (j = 0; (j < SKL_MAX_CLK_RATES) && 249 (sclk[id].rate_cfg[j].rate != 0); j++) { 250 if (sclk[id].rate_cfg[j].rate == rate) { 251 present = true; 252 break; 253 } 254 } 255 256 /* Fill rate and parent for sclk/sclkfs */ 257 if (!present) { 258 i2s_config_ext = (struct skl_i2s_config_blob_ext *) 259 fmt->fmt_config[0].config.caps; 260 261 /* MCLK Divider Source Select */ 262 if (is_legacy_blob(i2s_config_ext->hdr.sig)) { 263 i2s_config = ext_to_legacy_blob(i2s_config_ext); 264 clk_src = get_clk_src(i2s_config->mclk, 265 SKL_MNDSS_DIV_CLK_SRC_MASK); 266 } else { 267 clk_src = get_clk_src(i2s_config_ext->mclk, 268 SKL_MNDSS_DIV_CLK_SRC_MASK); 269 } 270 271 parent = skl_get_parent_clk(clk_src); 272 273 /* 274 * Do not copy the config data if there is no parent 275 * clock available for this clock source select 276 */ 277 if (!parent) 278 continue; 279 280 sclk[id].rate_cfg[rate_index].rate = rate; 281 sclk[id].rate_cfg[rate_index].config = fmt_cfg; 282 sclkfs[id].rate_cfg[rate_index].rate = rate; 283 sclkfs[id].rate_cfg[rate_index].config = fmt_cfg; 284 sclk[id].parent_name = parent->name; 285 sclkfs[id].parent_name = parent->name; 286 287 rate_index++; 288 } 289 } 290 } 291 292 static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk, 293 struct nhlt_fmt *fmt, u8 id) 294 { 295 struct skl_i2s_config_blob_ext *i2s_config_ext; 296 struct skl_i2s_config_blob_legacy *i2s_config; 297 struct nhlt_specific_cfg *fmt_cfg; 298 struct skl_clk_parent_src *parent; 299 u32 clkdiv, div_ratio; 300 u8 clk_src; 301 302 fmt_cfg = &fmt->fmt_config[0].config; 303 i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->caps; 304 305 /* MCLK Divider Source Select and divider */ 306 if (is_legacy_blob(i2s_config_ext->hdr.sig)) { 307 i2s_config = ext_to_legacy_blob(i2s_config_ext); 308 clk_src = get_clk_src(i2s_config->mclk, 309 SKL_MCLK_DIV_CLK_SRC_MASK); 310 clkdiv = i2s_config->mclk.mdivr & 311 SKL_MCLK_DIV_RATIO_MASK; 312 } else { 313 clk_src = get_clk_src(i2s_config_ext->mclk, 314 SKL_MCLK_DIV_CLK_SRC_MASK); 315 clkdiv = i2s_config_ext->mclk.mdivr[0] & 316 SKL_MCLK_DIV_RATIO_MASK; 317 } 318 319 /* bypass divider */ 320 div_ratio = 1; 321 322 if (clkdiv != SKL_MCLK_DIV_RATIO_MASK) 323 /* Divider is 2 + clkdiv */ 324 div_ratio = clkdiv + 2; 325 326 /* Calculate MCLK rate from source using div value */ 327 parent = skl_get_parent_clk(clk_src); 328 if (!parent) 329 return; 330 331 mclk[id].rate_cfg[0].rate = parent->rate/div_ratio; 332 mclk[id].rate_cfg[0].config = &fmt->fmt_config[0]; 333 mclk[id].parent_name = parent->name; 334 } 335 336 void skl_get_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks) 337 { 338 struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; 339 struct nhlt_endpoint *epnt; 340 struct nhlt_fmt *fmt; 341 int i; 342 u8 id; 343 344 epnt = (struct nhlt_endpoint *)nhlt->desc; 345 for (i = 0; i < nhlt->endpoint_count; i++) { 346 if (epnt->linktype == NHLT_LINK_SSP) { 347 id = epnt->virtual_bus_id; 348 349 fmt = (struct nhlt_fmt *)(epnt->config.caps 350 + epnt->config.size); 351 352 skl_get_ssp_clks(skl, ssp_clks, fmt, id); 353 skl_get_mclk(skl, ssp_clks, fmt, id); 354 } 355 epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); 356 } 357 } 358