skl-nhlt.c 12 KB

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