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 sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr); 186 } 187 188 /* 189 * Queries NHLT for all the fmt configuration for a particular endpoint and 190 * stores all possible rates supported in a rate table for the corresponding 191 * sclk/sclkfs. 192 */ 193 static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks, 194 struct nhlt_fmt *fmt, u8 id) 195 { 196 struct skl_i2s_config_blob_ext *i2s_config_ext; 197 struct skl_i2s_config_blob_legacy *i2s_config; 198 struct skl_clk_parent_src *parent; 199 struct skl_ssp_clk *sclk, *sclkfs; 200 struct nhlt_fmt_cfg *fmt_cfg; 201 struct wav_fmt_ext *wav_fmt; 202 unsigned long rate = 0; 203 bool present = false; 204 int rate_index = 0; 205 u16 channels, bps; 206 u8 clk_src; 207 int i, j; 208 u32 fs; 209 210 sclk = &ssp_clks[SKL_SCLK_OFS]; 211 sclkfs = &ssp_clks[SKL_SCLKFS_OFS]; 212 213 if (fmt->fmt_count == 0) 214 return; 215 216 for (i = 0; i < fmt->fmt_count; i++) { 217 fmt_cfg = &fmt->fmt_config[i]; 218 wav_fmt = &fmt_cfg->fmt_ext; 219 220 channels = wav_fmt->fmt.channels; 221 bps = wav_fmt->fmt.bits_per_sample; 222 fs = wav_fmt->fmt.samples_per_sec; 223 224 /* 225 * In case of TDM configuration on a ssp, there can 226 * be more than one blob in which channel masks are 227 * different for each usecase for a specific rate and bps. 228 * But the sclk rate will be generated for the total 229 * number of channels used for that endpoint. 230 * 231 * So for the given fs and bps, choose blob which has 232 * the superset of all channels for that endpoint and 233 * derive the rate. 234 */ 235 for (j = i; j < fmt->fmt_count; j++) { 236 fmt_cfg = &fmt->fmt_config[j]; 237 wav_fmt = &fmt_cfg->fmt_ext; 238 if ((fs == wav_fmt->fmt.samples_per_sec) && 239 (bps == wav_fmt->fmt.bits_per_sample)) 240 channels = max_t(u16, channels, 241 wav_fmt->fmt.channels); 242 } 243 244 rate = channels * bps * fs; 245 246 /* check if the rate is added already to the given SSP's sclk */ 247 for (j = 0; (j < SKL_MAX_CLK_RATES) && 248 (sclk[id].rate_cfg[j].rate != 0); j++) { 249 if (sclk[id].rate_cfg[j].rate == rate) { 250 present = true; 251 break; 252 } 253 } 254 255 /* Fill rate and parent for sclk/sclkfs */ 256 if (!present) { 257 i2s_config_ext = (struct skl_i2s_config_blob_ext *) 258 fmt->fmt_config[0].config.caps; 259 260 /* MCLK Divider Source Select */ 261 if (is_legacy_blob(i2s_config_ext->hdr.sig)) { 262 i2s_config = ext_to_legacy_blob(i2s_config_ext); 263 clk_src = get_clk_src(i2s_config->mclk, 264 SKL_MNDSS_DIV_CLK_SRC_MASK); 265 } else { 266 clk_src = get_clk_src(i2s_config_ext->mclk, 267 SKL_MNDSS_DIV_CLK_SRC_MASK); 268 } 269 270 parent = skl_get_parent_clk(clk_src); 271 272 /* 273 * Do not copy the config data if there is no parent 274 * clock available for this clock source select 275 */ 276 if (!parent) 277 continue; 278 279 sclk[id].rate_cfg[rate_index].rate = rate; 280 sclk[id].rate_cfg[rate_index].config = fmt_cfg; 281 sclkfs[id].rate_cfg[rate_index].rate = rate; 282 sclkfs[id].rate_cfg[rate_index].config = fmt_cfg; 283 sclk[id].parent_name = parent->name; 284 sclkfs[id].parent_name = parent->name; 285 286 rate_index++; 287 } 288 } 289 } 290 291 static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk, 292 struct nhlt_fmt *fmt, u8 id) 293 { 294 struct skl_i2s_config_blob_ext *i2s_config_ext; 295 struct skl_i2s_config_blob_legacy *i2s_config; 296 struct nhlt_specific_cfg *fmt_cfg; 297 struct skl_clk_parent_src *parent; 298 u32 clkdiv, div_ratio; 299 u8 clk_src; 300 301 fmt_cfg = &fmt->fmt_config[0].config; 302 i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->caps; 303 304 /* MCLK Divider Source Select and divider */ 305 if (is_legacy_blob(i2s_config_ext->hdr.sig)) { 306 i2s_config = ext_to_legacy_blob(i2s_config_ext); 307 clk_src = get_clk_src(i2s_config->mclk, 308 SKL_MCLK_DIV_CLK_SRC_MASK); 309 clkdiv = i2s_config->mclk.mdivr & 310 SKL_MCLK_DIV_RATIO_MASK; 311 } else { 312 clk_src = get_clk_src(i2s_config_ext->mclk, 313 SKL_MCLK_DIV_CLK_SRC_MASK); 314 clkdiv = i2s_config_ext->mclk.mdivr[0] & 315 SKL_MCLK_DIV_RATIO_MASK; 316 } 317 318 /* bypass divider */ 319 div_ratio = 1; 320 321 if (clkdiv != SKL_MCLK_DIV_RATIO_MASK) 322 /* Divider is 2 + clkdiv */ 323 div_ratio = clkdiv + 2; 324 325 /* Calculate MCLK rate from source using div value */ 326 parent = skl_get_parent_clk(clk_src); 327 if (!parent) 328 return; 329 330 mclk[id].rate_cfg[0].rate = parent->rate/div_ratio; 331 mclk[id].rate_cfg[0].config = &fmt->fmt_config[0]; 332 mclk[id].parent_name = parent->name; 333 } 334 335 void skl_get_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks) 336 { 337 struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; 338 struct nhlt_endpoint *epnt; 339 struct nhlt_fmt *fmt; 340 int i; 341 u8 id; 342 343 epnt = (struct nhlt_endpoint *)nhlt->desc; 344 for (i = 0; i < nhlt->endpoint_count; i++) { 345 if (epnt->linktype == NHLT_LINK_SSP) { 346 id = epnt->virtual_bus_id; 347 348 fmt = (struct nhlt_fmt *)(epnt->config.caps 349 + epnt->config.size); 350 351 skl_get_ssp_clks(skl, ssp_clks, fmt, id); 352 skl_get_mclk(skl, ssp_clks, fmt, id); 353 } 354 epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); 355 } 356 } 357