root/sound/soc/intel/skylake/skl-nhlt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. skl_get_specific_cfg
  2. dump_config
  3. skl_check_ep_match
  4. skl_get_ep_blob
  5. skl_nhlt_trim_space
  6. skl_nhlt_update_topology_bin
  7. skl_nhlt_platform_id_show
  8. skl_nhlt_create_sysfs
  9. skl_nhlt_remove_sysfs
  10. skl_get_ssp_clks
  11. skl_get_mclk
  12. skl_get_clks

   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 }

/* [<][>][^][v][top][bottom][index][help] */