210 lines
5.5 KiB
C
210 lines
5.5 KiB
C
|
/*
|
||
|
* sst_pci.c - SST (LPE) driver init file for pci enumeration.
|
||
|
*
|
||
|
* Copyright (C) 2008-14 Intel Corp
|
||
|
* Authors: Vinod Koul <vinod.koul@intel.com>
|
||
|
* Harsha Priya <priya.harsha@intel.com>
|
||
|
* Dharageswari R <dharageswari.r@intel.com>
|
||
|
* KP Jeeja <jeeja.kp@intel.com>
|
||
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; version 2 of the License.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful, but
|
||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* General Public License for more details.
|
||
|
*
|
||
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
*/
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/pci.h>
|
||
|
#include <linux/fs.h>
|
||
|
#include <linux/firmware.h>
|
||
|
#include <linux/pm_runtime.h>
|
||
|
#include <sound/core.h>
|
||
|
#include <sound/soc.h>
|
||
|
#include <asm/platform_sst_audio.h>
|
||
|
#include "../sst-mfld-platform.h"
|
||
|
#include "sst.h"
|
||
|
|
||
|
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 ret;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* 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;
|
||
|
snprintf(sst_drv_ctx->firmware_name, sizeof(sst_drv_ctx->firmware_name),
|
||
|
"%s%04x%s", "fw_sst_",
|
||
|
sst_drv_ctx->dev_id, ".bin");
|
||
|
|
||
|
ret = sst_context_init(sst_drv_ctx);
|
||
|
if (ret < 0)
|
||
|
return ret;
|
||
|
|
||
|
/* 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_free_drv_ctx;
|
||
|
}
|
||
|
sst_drv_ctx->pci = pci_dev_get(pci);
|
||
|
ret = sst_platform_get_resources(sst_drv_ctx);
|
||
|
if (ret < 0)
|
||
|
goto do_free_drv_ctx;
|
||
|
|
||
|
pci_set_drvdata(pci, sst_drv_ctx);
|
||
|
sst_configure_runtime_pm(sst_drv_ctx);
|
||
|
|
||
|
return ret;
|
||
|
|
||
|
do_free_drv_ctx:
|
||
|
sst_context_cleanup(sst_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);
|
||
|
}
|
||
|
|
||
|
/* 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);
|
||
|
|
||
|
MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine PCI Driver");
|
||
|
MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
|
||
|
MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
|
||
|
MODULE_AUTHOR("Dharageswari R <dharageswari.r@intel.com>");
|
||
|
MODULE_AUTHOR("KP Jeeja <jeeja.kp@intel.com>");
|
||
|
MODULE_LICENSE("GPL v2");
|
||
|
MODULE_ALIAS("sst");
|