|
@@ -20,20 +20,14 @@
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
*/
|
|
*/
|
|
#include <linux/module.h>
|
|
#include <linux/module.h>
|
|
-#include <linux/pci.h>
|
|
|
|
#include <linux/fs.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/firmware.h>
|
|
#include <linux/firmware.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/pm_qos.h>
|
|
#include <linux/pm_qos.h>
|
|
#include <linux/async.h>
|
|
#include <linux/async.h>
|
|
-#include <linux/delay.h>
|
|
|
|
-#include <linux/acpi.h>
|
|
|
|
#include <sound/core.h>
|
|
#include <sound/core.h>
|
|
-#include <sound/pcm.h>
|
|
|
|
#include <sound/soc.h>
|
|
#include <sound/soc.h>
|
|
-#include <sound/compress_driver.h>
|
|
|
|
-#include <asm/intel-mid.h>
|
|
|
|
#include <asm/platform_sst_audio.h>
|
|
#include <asm/platform_sst_audio.h>
|
|
#include "../sst-mfld-platform.h"
|
|
#include "../sst-mfld-platform.h"
|
|
#include "sst.h"
|
|
#include "sst.h"
|
|
@@ -242,6 +236,7 @@ int sst_alloc_drv_context(struct intel_sst_drv **ctx,
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
+EXPORT_SYMBOL_GPL(sst_alloc_drv_context);
|
|
|
|
|
|
int sst_context_init(struct intel_sst_drv *ctx)
|
|
int sst_context_init(struct intel_sst_drv *ctx)
|
|
{
|
|
{
|
|
@@ -260,6 +255,7 @@ int sst_context_init(struct intel_sst_drv *ctx)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
sst_init_locks(ctx);
|
|
sst_init_locks(ctx);
|
|
|
|
+ sst_set_fw_state_locked(ctx, SST_RESET);
|
|
|
|
|
|
/* pvt_id 0 reserved for async messages */
|
|
/* pvt_id 0 reserved for async messages */
|
|
ctx->pvt_id = 1;
|
|
ctx->pvt_id = 1;
|
|
@@ -307,12 +303,22 @@ int sst_context_init(struct intel_sst_drv *ctx)
|
|
}
|
|
}
|
|
pm_qos_add_request(ctx->qos, PM_QOS_CPU_DMA_LATENCY,
|
|
pm_qos_add_request(ctx->qos, PM_QOS_CPU_DMA_LATENCY,
|
|
PM_QOS_DEFAULT_VALUE);
|
|
PM_QOS_DEFAULT_VALUE);
|
|
|
|
+
|
|
|
|
+ dev_dbg(ctx->dev, "Requesting FW %s now...\n", ctx->firmware_name);
|
|
|
|
+ ret = request_firmware_nowait(THIS_MODULE, true, ctx->firmware_name,
|
|
|
|
+ ctx->dev, GFP_KERNEL, ctx, sst_firmware_load_cb);
|
|
|
|
+ if (ret) {
|
|
|
|
+ dev_err(ctx->dev, "Firmware download failed:%d\n", ret);
|
|
|
|
+ goto do_free_mem;
|
|
|
|
+ }
|
|
|
|
+ sst_register(ctx->dev);
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
do_free_mem:
|
|
do_free_mem:
|
|
destroy_workqueue(ctx->post_msg_wq);
|
|
destroy_workqueue(ctx->post_msg_wq);
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
+EXPORT_SYMBOL_GPL(sst_context_init);
|
|
|
|
|
|
void sst_context_cleanup(struct intel_sst_drv *ctx)
|
|
void sst_context_cleanup(struct intel_sst_drv *ctx)
|
|
{
|
|
{
|
|
@@ -331,6 +337,7 @@ void sst_context_cleanup(struct intel_sst_drv *ctx)
|
|
sst_memcpy_free_resources(ctx);
|
|
sst_memcpy_free_resources(ctx);
|
|
ctx = NULL;
|
|
ctx = NULL;
|
|
}
|
|
}
|
|
|
|
+EXPORT_SYMBOL_GPL(sst_context_cleanup);
|
|
|
|
|
|
void sst_configure_runtime_pm(struct intel_sst_drv *ctx)
|
|
void sst_configure_runtime_pm(struct intel_sst_drv *ctx)
|
|
{
|
|
{
|
|
@@ -339,175 +346,7 @@ void sst_configure_runtime_pm(struct intel_sst_drv *ctx)
|
|
pm_runtime_allow(ctx->dev);
|
|
pm_runtime_allow(ctx->dev);
|
|
pm_runtime_put_noidle(ctx->dev);
|
|
pm_runtime_put_noidle(ctx->dev);
|
|
}
|
|
}
|
|
-
|
|
|
|
-static int sst_platform_get_resources(struct intel_sst_drv *ctx)
|
|
|
|
-{
|
|
|
|
- int ddr_base, ret = 0;
|
|
|
|
- struct pci_dev *pci = ctx->pci;
|
|
|
|
- ret = pci_request_regions(pci, SST_DRV_NAME);
|
|
|
|
- if (ret)
|
|
|
|
- return ret;
|
|
|
|
-
|
|
|
|
- /* map registers */
|
|
|
|
- /* DDR base */
|
|
|
|
- if (ctx->dev_id == SST_MRFLD_PCI_ID) {
|
|
|
|
- ctx->ddr_base = pci_resource_start(pci, 0);
|
|
|
|
- /* check that the relocated IMR base matches with FW Binary */
|
|
|
|
- ddr_base = relocate_imr_addr_mrfld(ctx->ddr_base);
|
|
|
|
- if (!ctx->pdata->lib_info) {
|
|
|
|
- dev_err(ctx->dev, "lib_info pointer NULL\n");
|
|
|
|
- ret = -EINVAL;
|
|
|
|
- goto do_release_regions;
|
|
|
|
- }
|
|
|
|
- if (ddr_base != ctx->pdata->lib_info->mod_base) {
|
|
|
|
- dev_err(ctx->dev,
|
|
|
|
- "FW LSP DDR BASE does not match with IFWI\n");
|
|
|
|
- ret = -EINVAL;
|
|
|
|
- goto do_release_regions;
|
|
|
|
- }
|
|
|
|
- ctx->ddr_end = pci_resource_end(pci, 0);
|
|
|
|
-
|
|
|
|
- ctx->ddr = pcim_iomap(pci, 0,
|
|
|
|
- pci_resource_len(pci, 0));
|
|
|
|
- if (!ctx->ddr) {
|
|
|
|
- ret = -EINVAL;
|
|
|
|
- goto do_release_regions;
|
|
|
|
- }
|
|
|
|
- dev_dbg(ctx->dev, "sst: DDR Ptr %p\n", ctx->ddr);
|
|
|
|
- } else {
|
|
|
|
- ctx->ddr = NULL;
|
|
|
|
- }
|
|
|
|
- /* SHIM */
|
|
|
|
- ctx->shim_phy_add = pci_resource_start(pci, 1);
|
|
|
|
- ctx->shim = pcim_iomap(pci, 1, pci_resource_len(pci, 1));
|
|
|
|
- if (!ctx->shim) {
|
|
|
|
- ret = -EINVAL;
|
|
|
|
- goto do_release_regions;
|
|
|
|
- }
|
|
|
|
- dev_dbg(ctx->dev, "SST Shim Ptr %p\n", ctx->shim);
|
|
|
|
-
|
|
|
|
- /* Shared SRAM */
|
|
|
|
- ctx->mailbox_add = pci_resource_start(pci, 2);
|
|
|
|
- ctx->mailbox = pcim_iomap(pci, 2, pci_resource_len(pci, 2));
|
|
|
|
- if (!ctx->mailbox) {
|
|
|
|
- ret = -EINVAL;
|
|
|
|
- goto do_release_regions;
|
|
|
|
- }
|
|
|
|
- dev_dbg(ctx->dev, "SRAM Ptr %p\n", ctx->mailbox);
|
|
|
|
-
|
|
|
|
- /* IRAM */
|
|
|
|
- ctx->iram_end = pci_resource_end(pci, 3);
|
|
|
|
- ctx->iram_base = pci_resource_start(pci, 3);
|
|
|
|
- ctx->iram = pcim_iomap(pci, 3, pci_resource_len(pci, 3));
|
|
|
|
- if (!ctx->iram) {
|
|
|
|
- ret = -EINVAL;
|
|
|
|
- goto do_release_regions;
|
|
|
|
- }
|
|
|
|
- dev_dbg(ctx->dev, "IRAM Ptr %p\n", ctx->iram);
|
|
|
|
-
|
|
|
|
- /* DRAM */
|
|
|
|
- ctx->dram_end = pci_resource_end(pci, 4);
|
|
|
|
- ctx->dram_base = pci_resource_start(pci, 4);
|
|
|
|
- ctx->dram = pcim_iomap(pci, 4, pci_resource_len(pci, 4));
|
|
|
|
- if (!ctx->dram) {
|
|
|
|
- ret = -EINVAL;
|
|
|
|
- goto do_release_regions;
|
|
|
|
- }
|
|
|
|
- dev_dbg(ctx->dev, "DRAM Ptr %p\n", ctx->dram);
|
|
|
|
-do_release_regions:
|
|
|
|
- pci_release_regions(pci);
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-/*
|
|
|
|
-* intel_sst_probe - PCI probe function
|
|
|
|
-*
|
|
|
|
-* @pci: PCI device structure
|
|
|
|
-* @pci_id: PCI device ID structure
|
|
|
|
-*
|
|
|
|
-*/
|
|
|
|
-static int intel_sst_probe(struct pci_dev *pci,
|
|
|
|
- const struct pci_device_id *pci_id)
|
|
|
|
-{
|
|
|
|
- int ret = 0;
|
|
|
|
- struct intel_sst_drv *sst_drv_ctx;
|
|
|
|
- struct sst_platform_info *sst_pdata = pci->dev.platform_data;
|
|
|
|
-
|
|
|
|
- dev_dbg(&pci->dev, "Probe for DID %x\n", pci->device);
|
|
|
|
-
|
|
|
|
- ret = sst_alloc_drv_context(&sst_drv_ctx, &pci->dev, pci->device);
|
|
|
|
- if (ret < 0)
|
|
|
|
- return ret;
|
|
|
|
-
|
|
|
|
- sst_drv_ctx->pdata = sst_pdata;
|
|
|
|
- sst_drv_ctx->irq_num = pci->irq;
|
|
|
|
-
|
|
|
|
- ret = sst_context_init(sst_drv_ctx);
|
|
|
|
- if (ret < 0)
|
|
|
|
- goto do_free_drv_ctx;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- /* Init the device */
|
|
|
|
- ret = pcim_enable_device(pci);
|
|
|
|
- if (ret) {
|
|
|
|
- dev_err(sst_drv_ctx->dev,
|
|
|
|
- "device can't be enabled. Returned err: %d\n", ret);
|
|
|
|
- goto do_destroy_wq;
|
|
|
|
- }
|
|
|
|
- sst_drv_ctx->pci = pci_dev_get(pci);
|
|
|
|
-
|
|
|
|
- ret = sst_platform_get_resources(sst_drv_ctx);
|
|
|
|
- if (ret < 0)
|
|
|
|
- goto do_destroy_wq;
|
|
|
|
-
|
|
|
|
- sst_set_fw_state_locked(sst_drv_ctx, SST_RESET);
|
|
|
|
- snprintf(sst_drv_ctx->firmware_name, sizeof(sst_drv_ctx->firmware_name),
|
|
|
|
- "%s%04x%s", "fw_sst_",
|
|
|
|
- sst_drv_ctx->dev_id, ".bin");
|
|
|
|
- dev_dbg(sst_drv_ctx->dev,
|
|
|
|
- "Requesting FW %s now...\n", sst_drv_ctx->firmware_name);
|
|
|
|
- ret = request_firmware_nowait(THIS_MODULE, 1,
|
|
|
|
- sst_drv_ctx->firmware_name, sst_drv_ctx->dev,
|
|
|
|
- GFP_KERNEL, sst_drv_ctx, sst_firmware_load_cb);
|
|
|
|
-
|
|
|
|
- if (ret) {
|
|
|
|
- dev_err(sst_drv_ctx->dev,
|
|
|
|
- "Firmware load failed with error: %d\n", ret);
|
|
|
|
- goto do_release_regions;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- pci_set_drvdata(pci, sst_drv_ctx);
|
|
|
|
- sst_configure_runtime_pm(sst_drv_ctx);
|
|
|
|
- sst_register(sst_drv_ctx->dev);
|
|
|
|
-
|
|
|
|
- return ret;
|
|
|
|
-
|
|
|
|
-do_release_regions:
|
|
|
|
- pci_release_regions(pci);
|
|
|
|
-do_destroy_wq:
|
|
|
|
- destroy_workqueue(sst_drv_ctx->post_msg_wq);
|
|
|
|
-do_free_drv_ctx:
|
|
|
|
- dev_err(sst_drv_ctx->dev, "Probe failed with %d\n", ret);
|
|
|
|
- return ret;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
-* intel_sst_remove - PCI remove function
|
|
|
|
-*
|
|
|
|
-* @pci: PCI device structure
|
|
|
|
-*
|
|
|
|
-* This function is called by OS when a device is unloaded
|
|
|
|
-* This frees the interrupt etc
|
|
|
|
-*/
|
|
|
|
-static void intel_sst_remove(struct pci_dev *pci)
|
|
|
|
-{
|
|
|
|
- struct intel_sst_drv *sst_drv_ctx = pci_get_drvdata(pci);
|
|
|
|
-
|
|
|
|
- sst_context_cleanup(sst_drv_ctx);
|
|
|
|
- pci_dev_put(sst_drv_ctx->pci);
|
|
|
|
- pci_release_regions(pci);
|
|
|
|
- pci_set_drvdata(pci, NULL);
|
|
|
|
-}
|
|
|
|
|
|
+EXPORT_SYMBOL_GPL(sst_configure_runtime_pm);
|
|
|
|
|
|
static int intel_sst_runtime_suspend(struct device *dev)
|
|
static int intel_sst_runtime_suspend(struct device *dev)
|
|
{
|
|
{
|
|
@@ -546,27 +385,8 @@ static int intel_sst_runtime_resume(struct device *dev)
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
-static const struct dev_pm_ops intel_sst_pm = {
|
|
|
|
|
|
+const struct dev_pm_ops intel_sst_pm = {
|
|
.runtime_suspend = intel_sst_runtime_suspend,
|
|
.runtime_suspend = intel_sst_runtime_suspend,
|
|
.runtime_resume = intel_sst_runtime_resume,
|
|
.runtime_resume = intel_sst_runtime_resume,
|
|
};
|
|
};
|
|
-
|
|
|
|
-/* PCI Routines */
|
|
|
|
-static struct pci_device_id intel_sst_ids[] = {
|
|
|
|
- { PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0},
|
|
|
|
- { 0, }
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-static struct pci_driver sst_driver = {
|
|
|
|
- .name = SST_DRV_NAME,
|
|
|
|
- .id_table = intel_sst_ids,
|
|
|
|
- .probe = intel_sst_probe,
|
|
|
|
- .remove = intel_sst_remove,
|
|
|
|
-#ifdef CONFIG_PM
|
|
|
|
- .driver = {
|
|
|
|
- .pm = &intel_sst_pm,
|
|
|
|
- },
|
|
|
|
-#endif
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-module_pci_driver(sst_driver);
|
|
|
|
|
|
+EXPORT_SYMBOL_GPL(intel_sst_pm);
|