sst-acpi.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /*
  2. * Intel SST loader on ACPI systems
  3. *
  4. * Copyright (C) 2013, Intel Corporation. All rights reserved.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License version
  8. * 2 as published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. */
  16. #include <linux/acpi.h>
  17. #include <linux/device.h>
  18. #include <linux/firmware.h>
  19. #include <linux/module.h>
  20. #include <linux/platform_device.h>
  21. #include "sst-dsp.h"
  22. #include "sst-acpi.h"
  23. #define SST_LPT_DSP_DMA_ADDR_OFFSET 0x0F0000
  24. #define SST_WPT_DSP_DMA_ADDR_OFFSET 0x0FE000
  25. #define SST_LPT_DSP_DMA_SIZE (1024 - 1)
  26. /* Descriptor for setting up SST platform data */
  27. struct sst_acpi_desc {
  28. const char *drv_name;
  29. struct sst_acpi_mach *machines;
  30. /* Platform resource indexes. Must set to -1 if not used */
  31. int resindex_lpe_base;
  32. int resindex_pcicfg_base;
  33. int resindex_fw_base;
  34. int irqindex_host_ipc;
  35. int resindex_dma_base;
  36. /* Unique number identifying the SST core on platform */
  37. int sst_id;
  38. /* DMA only valid when resindex_dma_base != -1*/
  39. int dma_engine;
  40. int dma_size;
  41. };
  42. struct sst_acpi_priv {
  43. struct platform_device *pdev_mach;
  44. struct platform_device *pdev_pcm;
  45. struct sst_pdata sst_pdata;
  46. struct sst_acpi_desc *desc;
  47. struct sst_acpi_mach *mach;
  48. };
  49. static void sst_acpi_fw_cb(const struct firmware *fw, void *context)
  50. {
  51. struct platform_device *pdev = context;
  52. struct device *dev = &pdev->dev;
  53. struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev);
  54. struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata;
  55. struct sst_acpi_desc *desc = sst_acpi->desc;
  56. struct sst_acpi_mach *mach = sst_acpi->mach;
  57. sst_pdata->fw = fw;
  58. if (!fw) {
  59. dev_err(dev, "Cannot load firmware %s\n", mach->fw_filename);
  60. return;
  61. }
  62. /* register PCM and DAI driver */
  63. sst_acpi->pdev_pcm =
  64. platform_device_register_data(dev, desc->drv_name, -1,
  65. sst_pdata, sizeof(*sst_pdata));
  66. if (IS_ERR(sst_acpi->pdev_pcm)) {
  67. dev_err(dev, "Cannot register device %s. Error %d\n",
  68. desc->drv_name, (int)PTR_ERR(sst_acpi->pdev_pcm));
  69. }
  70. return;
  71. }
  72. static int sst_acpi_probe(struct platform_device *pdev)
  73. {
  74. const struct acpi_device_id *id;
  75. struct device *dev = &pdev->dev;
  76. struct sst_acpi_priv *sst_acpi;
  77. struct sst_pdata *sst_pdata;
  78. struct sst_acpi_mach *mach;
  79. struct sst_acpi_desc *desc;
  80. struct resource *mmio;
  81. int ret = 0;
  82. sst_acpi = devm_kzalloc(dev, sizeof(*sst_acpi), GFP_KERNEL);
  83. if (sst_acpi == NULL)
  84. return -ENOMEM;
  85. id = acpi_match_device(dev->driver->acpi_match_table, dev);
  86. if (!id)
  87. return -ENODEV;
  88. desc = (struct sst_acpi_desc *)id->driver_data;
  89. mach = sst_acpi_find_machine(desc->machines);
  90. if (mach == NULL) {
  91. dev_err(dev, "No matching ASoC machine driver found\n");
  92. return -ENODEV;
  93. }
  94. sst_pdata = &sst_acpi->sst_pdata;
  95. sst_pdata->id = desc->sst_id;
  96. sst_pdata->dma_dev = dev;
  97. sst_acpi->desc = desc;
  98. sst_acpi->mach = mach;
  99. sst_pdata->resindex_dma_base = desc->resindex_dma_base;
  100. if (desc->resindex_dma_base >= 0) {
  101. sst_pdata->dma_engine = desc->dma_engine;
  102. sst_pdata->dma_base = desc->resindex_dma_base;
  103. sst_pdata->dma_size = desc->dma_size;
  104. }
  105. if (desc->irqindex_host_ipc >= 0)
  106. sst_pdata->irq = platform_get_irq(pdev, desc->irqindex_host_ipc);
  107. if (desc->resindex_lpe_base >= 0) {
  108. mmio = platform_get_resource(pdev, IORESOURCE_MEM,
  109. desc->resindex_lpe_base);
  110. if (mmio) {
  111. sst_pdata->lpe_base = mmio->start;
  112. sst_pdata->lpe_size = resource_size(mmio);
  113. }
  114. }
  115. if (desc->resindex_pcicfg_base >= 0) {
  116. mmio = platform_get_resource(pdev, IORESOURCE_MEM,
  117. desc->resindex_pcicfg_base);
  118. if (mmio) {
  119. sst_pdata->pcicfg_base = mmio->start;
  120. sst_pdata->pcicfg_size = resource_size(mmio);
  121. }
  122. }
  123. if (desc->resindex_fw_base >= 0) {
  124. mmio = platform_get_resource(pdev, IORESOURCE_MEM,
  125. desc->resindex_fw_base);
  126. if (mmio) {
  127. sst_pdata->fw_base = mmio->start;
  128. sst_pdata->fw_size = resource_size(mmio);
  129. }
  130. }
  131. platform_set_drvdata(pdev, sst_acpi);
  132. /* register machine driver */
  133. sst_acpi->pdev_mach =
  134. platform_device_register_data(dev, mach->drv_name, -1,
  135. sst_pdata, sizeof(*sst_pdata));
  136. if (IS_ERR(sst_acpi->pdev_mach))
  137. return PTR_ERR(sst_acpi->pdev_mach);
  138. /* continue SST probing after firmware is loaded */
  139. ret = reject_firmware_nowait(THIS_MODULE, true, mach->fw_filename,
  140. dev, GFP_KERNEL, pdev, sst_acpi_fw_cb);
  141. if (ret)
  142. platform_device_unregister(sst_acpi->pdev_mach);
  143. return ret;
  144. }
  145. static int sst_acpi_remove(struct platform_device *pdev)
  146. {
  147. struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev);
  148. struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata;
  149. platform_device_unregister(sst_acpi->pdev_mach);
  150. if (!IS_ERR_OR_NULL(sst_acpi->pdev_pcm))
  151. platform_device_unregister(sst_acpi->pdev_pcm);
  152. release_firmware(sst_pdata->fw);
  153. return 0;
  154. }
  155. static struct sst_acpi_mach haswell_machines[] = {
  156. { "INT33CA", "haswell-audio", "/*(DEBLOBBED)*/", NULL, NULL, NULL },
  157. {}
  158. };
  159. static struct sst_acpi_desc sst_acpi_haswell_desc = {
  160. .drv_name = "haswell-pcm-audio",
  161. .machines = haswell_machines,
  162. .resindex_lpe_base = 0,
  163. .resindex_pcicfg_base = 1,
  164. .resindex_fw_base = -1,
  165. .irqindex_host_ipc = 0,
  166. .sst_id = SST_DEV_ID_LYNX_POINT,
  167. .dma_engine = SST_DMA_TYPE_DW,
  168. .resindex_dma_base = SST_LPT_DSP_DMA_ADDR_OFFSET,
  169. .dma_size = SST_LPT_DSP_DMA_SIZE,
  170. };
  171. static struct sst_acpi_mach broadwell_machines[] = {
  172. { "INT343A", "broadwell-audio", "/*(DEBLOBBED)*/", NULL, NULL, NULL },
  173. { "RT5677CE", "bdw-rt5677", "/*(DEBLOBBED)*/", NULL, NULL, NULL },
  174. {}
  175. };
  176. static struct sst_acpi_desc sst_acpi_broadwell_desc = {
  177. .drv_name = "haswell-pcm-audio",
  178. .machines = broadwell_machines,
  179. .resindex_lpe_base = 0,
  180. .resindex_pcicfg_base = 1,
  181. .resindex_fw_base = -1,
  182. .irqindex_host_ipc = 0,
  183. .sst_id = SST_DEV_ID_WILDCAT_POINT,
  184. .dma_engine = SST_DMA_TYPE_DW,
  185. .resindex_dma_base = SST_WPT_DSP_DMA_ADDR_OFFSET,
  186. .dma_size = SST_LPT_DSP_DMA_SIZE,
  187. };
  188. #if !IS_ENABLED(CONFIG_SND_SST_IPC_ACPI)
  189. static struct sst_acpi_mach baytrail_machines[] = {
  190. { "10EC5640", "byt-rt5640", "/*(DEBLOBBED)*/", NULL, NULL, NULL },
  191. { "193C9890", "byt-max98090", "/*(DEBLOBBED)*/", NULL, NULL, NULL },
  192. {}
  193. };
  194. static struct sst_acpi_desc sst_acpi_baytrail_desc = {
  195. .drv_name = "baytrail-pcm-audio",
  196. .machines = baytrail_machines,
  197. .resindex_lpe_base = 0,
  198. .resindex_pcicfg_base = 1,
  199. .resindex_fw_base = 2,
  200. .irqindex_host_ipc = 5,
  201. .sst_id = SST_DEV_ID_BYT,
  202. .resindex_dma_base = -1,
  203. };
  204. #endif
  205. static const struct acpi_device_id sst_acpi_match[] = {
  206. { "INT33C8", (unsigned long)&sst_acpi_haswell_desc },
  207. { "INT3438", (unsigned long)&sst_acpi_broadwell_desc },
  208. #if !IS_ENABLED(CONFIG_SND_SST_IPC_ACPI)
  209. { "80860F28", (unsigned long)&sst_acpi_baytrail_desc },
  210. #endif
  211. { }
  212. };
  213. MODULE_DEVICE_TABLE(acpi, sst_acpi_match);
  214. static struct platform_driver sst_acpi_driver = {
  215. .probe = sst_acpi_probe,
  216. .remove = sst_acpi_remove,
  217. .driver = {
  218. .name = "sst-acpi",
  219. .acpi_match_table = ACPI_PTR(sst_acpi_match),
  220. },
  221. };
  222. module_platform_driver(sst_acpi_driver);
  223. MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>");
  224. MODULE_DESCRIPTION("Intel SST loader on ACPI systems");
  225. MODULE_LICENSE("GPL v2");