arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / sound / soc / intel / skylake / skl-nhlt.c
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 void skl_nhlt_trim_space(char *trim)
17 {
18         char *s = trim;
19         int cnt;
20         int i;
21
22         cnt = 0;
23         for (i = 0; s[i]; i++) {
24                 if (!isspace(s[i]))
25                         s[cnt++] = s[i];
26         }
27
28         s[cnt] = '\0';
29 }
30
31 int skl_nhlt_update_topology_bin(struct skl_dev *skl)
32 {
33         struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
34         struct hdac_bus *bus = skl_to_bus(skl);
35         struct device *dev = bus->dev;
36
37         dev_dbg(dev, "oem_id %.6s, oem_table_id %.8s oem_revision %d\n",
38                 nhlt->header.oem_id, nhlt->header.oem_table_id,
39                 nhlt->header.oem_revision);
40
41         snprintf(skl->tplg_name, sizeof(skl->tplg_name), "/*(DEBLOBBED)*/");
42
43         skl_nhlt_trim_space(skl->tplg_name);
44
45         return 0;
46 }
47
48 static ssize_t platform_id_show(struct device *dev,
49                                 struct device_attribute *attr, char *buf)
50 {
51         struct pci_dev *pci = to_pci_dev(dev);
52         struct hdac_bus *bus = pci_get_drvdata(pci);
53         struct skl_dev *skl = bus_to_skl(bus);
54         struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
55         char platform_id[32];
56
57         sprintf(platform_id, "%x-%.6s-%.8s-%d", skl->pci_id,
58                         nhlt->header.oem_id, nhlt->header.oem_table_id,
59                         nhlt->header.oem_revision);
60
61         skl_nhlt_trim_space(platform_id);
62         return sysfs_emit(buf, "%s\n", platform_id);
63 }
64
65 static DEVICE_ATTR_RO(platform_id);
66
67 int skl_nhlt_create_sysfs(struct skl_dev *skl)
68 {
69         struct device *dev = &skl->pci->dev;
70
71         if (sysfs_create_file(&dev->kobj, &dev_attr_platform_id.attr))
72                 dev_warn(dev, "Error creating sysfs entry\n");
73
74         return 0;
75 }
76
77 void skl_nhlt_remove_sysfs(struct skl_dev *skl)
78 {
79         struct device *dev = &skl->pci->dev;
80
81         if (skl->nhlt)
82                 sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr);
83 }
84
85 /*
86  * Queries NHLT for all the fmt configuration for a particular endpoint and
87  * stores all possible rates supported in a rate table for the corresponding
88  * sclk/sclkfs.
89  */
90 static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
91                                 struct nhlt_fmt *fmt, u8 id)
92 {
93         struct skl_i2s_config_blob_ext *i2s_config_ext;
94         struct skl_i2s_config_blob_legacy *i2s_config;
95         struct skl_clk_parent_src *parent;
96         struct skl_ssp_clk *sclk, *sclkfs;
97         struct nhlt_fmt_cfg *fmt_cfg;
98         struct wav_fmt_ext *wav_fmt;
99         unsigned long rate;
100         int rate_index = 0;
101         u16 channels, bps;
102         u8 clk_src;
103         int i, j;
104         u32 fs;
105
106         sclk = &ssp_clks[SKL_SCLK_OFS];
107         sclkfs = &ssp_clks[SKL_SCLKFS_OFS];
108
109         if (fmt->fmt_count == 0)
110                 return;
111
112         fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config;
113         for (i = 0; i < fmt->fmt_count; i++) {
114                 struct nhlt_fmt_cfg *saved_fmt_cfg = fmt_cfg;
115                 bool present = false;
116
117                 wav_fmt = &saved_fmt_cfg->fmt_ext;
118
119                 channels = wav_fmt->fmt.channels;
120                 bps = wav_fmt->fmt.bits_per_sample;
121                 fs = wav_fmt->fmt.samples_per_sec;
122
123                 /*
124                  * In case of TDM configuration on a ssp, there can
125                  * be more than one blob in which channel masks are
126                  * different for each usecase for a specific rate and bps.
127                  * But the sclk rate will be generated for the total
128                  * number of channels used for that endpoint.
129                  *
130                  * So for the given fs and bps, choose blob which has
131                  * the superset of all channels for that endpoint and
132                  * derive the rate.
133                  */
134                 for (j = i; j < fmt->fmt_count; j++) {
135                         struct nhlt_fmt_cfg *tmp_fmt_cfg = fmt_cfg;
136
137                         wav_fmt = &tmp_fmt_cfg->fmt_ext;
138                         if ((fs == wav_fmt->fmt.samples_per_sec) &&
139                            (bps == wav_fmt->fmt.bits_per_sample)) {
140                                 channels = max_t(u16, channels,
141                                                 wav_fmt->fmt.channels);
142                                 saved_fmt_cfg = tmp_fmt_cfg;
143                         }
144                         /* Move to the next nhlt_fmt_cfg */
145                         tmp_fmt_cfg = (struct nhlt_fmt_cfg *)(tmp_fmt_cfg->config.caps +
146                                                               tmp_fmt_cfg->config.size);
147                 }
148
149                 rate = channels * bps * fs;
150
151                 /* check if the rate is added already to the given SSP's sclk */
152                 for (j = 0; (j < SKL_MAX_CLK_RATES) &&
153                             (sclk[id].rate_cfg[j].rate != 0); j++) {
154                         if (sclk[id].rate_cfg[j].rate == rate) {
155                                 present = true;
156                                 break;
157                         }
158                 }
159
160                 /* Fill rate and parent for sclk/sclkfs */
161                 if (!present) {
162                         struct nhlt_fmt_cfg *first_fmt_cfg;
163
164                         first_fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config;
165                         i2s_config_ext = (struct skl_i2s_config_blob_ext *)
166                                                 first_fmt_cfg->config.caps;
167
168                         /* MCLK Divider Source Select */
169                         if (is_legacy_blob(i2s_config_ext->hdr.sig)) {
170                                 i2s_config = ext_to_legacy_blob(i2s_config_ext);
171                                 clk_src = get_clk_src(i2s_config->mclk,
172                                                 SKL_MNDSS_DIV_CLK_SRC_MASK);
173                         } else {
174                                 clk_src = get_clk_src(i2s_config_ext->mclk,
175                                                 SKL_MNDSS_DIV_CLK_SRC_MASK);
176                         }
177
178                         parent = skl_get_parent_clk(clk_src);
179
180                         /* Move to the next nhlt_fmt_cfg */
181                         fmt_cfg = (struct nhlt_fmt_cfg *)(fmt_cfg->config.caps +
182                                                           fmt_cfg->config.size);
183                         /*
184                          * Do not copy the config data if there is no parent
185                          * clock available for this clock source select
186                          */
187                         if (!parent)
188                                 continue;
189
190                         sclk[id].rate_cfg[rate_index].rate = rate;
191                         sclk[id].rate_cfg[rate_index].config = saved_fmt_cfg;
192                         sclkfs[id].rate_cfg[rate_index].rate = rate;
193                         sclkfs[id].rate_cfg[rate_index].config = saved_fmt_cfg;
194                         sclk[id].parent_name = parent->name;
195                         sclkfs[id].parent_name = parent->name;
196
197                         rate_index++;
198                 }
199         }
200 }
201
202 static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk,
203                                 struct nhlt_fmt *fmt, u8 id)
204 {
205         struct skl_i2s_config_blob_ext *i2s_config_ext;
206         struct skl_i2s_config_blob_legacy *i2s_config;
207         struct nhlt_fmt_cfg *fmt_cfg;
208         struct skl_clk_parent_src *parent;
209         u32 clkdiv, div_ratio;
210         u8 clk_src;
211
212         fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config;
213         i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->config.caps;
214
215         /* MCLK Divider Source Select and divider */
216         if (is_legacy_blob(i2s_config_ext->hdr.sig)) {
217                 i2s_config = ext_to_legacy_blob(i2s_config_ext);
218                 clk_src = get_clk_src(i2s_config->mclk,
219                                 SKL_MCLK_DIV_CLK_SRC_MASK);
220                 clkdiv = i2s_config->mclk.mdivr &
221                                 SKL_MCLK_DIV_RATIO_MASK;
222         } else {
223                 clk_src = get_clk_src(i2s_config_ext->mclk,
224                                 SKL_MCLK_DIV_CLK_SRC_MASK);
225                 clkdiv = i2s_config_ext->mclk.mdivr[0] &
226                                 SKL_MCLK_DIV_RATIO_MASK;
227         }
228
229         /* bypass divider */
230         div_ratio = 1;
231
232         if (clkdiv != SKL_MCLK_DIV_RATIO_MASK)
233                 /* Divider is 2 + clkdiv */
234                 div_ratio = clkdiv + 2;
235
236         /* Calculate MCLK rate from source using div value */
237         parent = skl_get_parent_clk(clk_src);
238         if (!parent)
239                 return;
240
241         mclk[id].rate_cfg[0].rate = parent->rate/div_ratio;
242         mclk[id].rate_cfg[0].config = fmt_cfg;
243         mclk[id].parent_name = parent->name;
244 }
245
246 void skl_get_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks)
247 {
248         struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
249         struct nhlt_endpoint *epnt;
250         struct nhlt_fmt *fmt;
251         int i;
252         u8 id;
253
254         epnt = (struct nhlt_endpoint *)nhlt->desc;
255         for (i = 0; i < nhlt->endpoint_count; i++) {
256                 if (epnt->linktype == NHLT_LINK_SSP) {
257                         id = epnt->virtual_bus_id;
258
259                         fmt = (struct nhlt_fmt *)(epnt->config.caps
260                                         + epnt->config.size);
261
262                         skl_get_ssp_clks(skl, ssp_clks, fmt, id);
263                         skl_get_mclk(skl, ssp_clks, fmt, id);
264                 }
265                 epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
266         }
267 }