summaryrefslogtreecommitdiff
path: root/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-1-8.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-1-8.patch')
-rw-r--r--meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-1-8.patch1433
1 files changed, 1433 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-1-8.patch b/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-1-8.patch
new file mode 100644
index 000000000..795bf1a3b
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-audio-driver-6.0-1-8.patch
@@ -0,0 +1,1433 @@
+From c3cccfca9868aaf6e67a77c46a859a18d6384492 Mon Sep 17 00:00:00 2001
+From: R, Dharageswari <dharageswari.r@intel.com>
+Date: Thu, 29 Apr 2010 20:14:06 +0530
+Subject: [PATCH] ADR-Post-Beta-0.05.002.03-1/8-Adding Moorestown Audio Drivers - SST driver
+
+This patch is the first patch in the series of eight patches which add up SST
+driver and MAD driver. The SST driver is a driver for the SST DSP engine.This
+patch adds the SST driver main file intel_sst.c which contains the init, exit,
+probe, interrupt routine, as well as PCI suspend and resume implementations.
+intel_sst_dsp.c file implements the SST FW initialization as well as FW and
+library download steps.This patch also contains the intel_lpe.h header file
+which is placed in include folder for MAD driver (ALSA Sound card driver for
+Moorestown given in patch 7/8) to use. This file contains the definition of
+interfaces exposed by SST drivers along with definition of all the controls
+for the sound card to be used by MAD Driver
+
+Signed-off-by: Vinod Koul <vinod.koul@intel.com>
+
+ new file: include/sound/intel_lpe.h
+ new file: sound/pci/sst/intel_sst.c
+ new file: sound/pci/sst/intel_sst_dsp.c
+Patch-mainline: 2.6.35?
+---
+ include/sound/intel_lpe.h | 148 +++++++++
+ sound/pci/sst/intel_sst.c | 527 ++++++++++++++++++++++++++++++
+ sound/pci/sst/intel_sst_dsp.c | 706 +++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 1381 insertions(+), 0 deletions(-)
+ create mode 100644 include/sound/intel_lpe.h
+ create mode 100644 sound/pci/sst/intel_sst.c
+ create mode 100644 sound/pci/sst/intel_sst_dsp.c
+
+diff --git a/include/sound/intel_lpe.h b/include/sound/intel_lpe.h
+new file mode 100644
+index 0000000..70e7a1f
+--- /dev/null
++++ b/include/sound/intel_lpe.h
+@@ -0,0 +1,148 @@
++#ifndef __INTEL_SST_H__
++#define __INTEL_SST_H__
++/*
++ * intel_lpe.h - Intel SST Driver for audio engine
++ *
++ * Copyright (C) 2008-10 Intel Corporation
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * This driver exposes the audio engine functionalities to the ALSA
++ * and middleware.
++ * This file is shared between the SST and MAD drivers
++ */
++
++#define SST_CARD_NAMES "intel_mid_card"
++
++/* control list Pmic & Lpe */
++/* Input controls */
++enum port_status {
++ ACTIVATE = 1,
++ DEACTIVATE,
++};
++
++/* Card states */
++enum sst_card_states {
++ SND_CARD_UN_INIT = 0,
++ SND_CARD_INIT_DONE,
++};
++
++enum sst_controls {
++ SST_SND_ALLOC = 0x1000,
++ SST_SND_PAUSE = 0x1001,
++ SST_SND_RESUME = 0x1002,
++ SST_SND_DROP = 0x1003,
++ SST_SND_FREE = 0x1004,
++ SST_SND_BUFFER_POINTER = 0x1005,
++ SST_SND_STREAM_INIT = 0x1006,
++ SST_SND_START = 0x1007,
++ SST_SND_STREAM_PROCESS = 0x1008,
++ SST_MAX_CONTROLS = 0x1008,
++ SST_CONTROL_BASE = 0x1000,
++ SST_ENABLE_RX_TIME_SLOT = 0x1009,
++
++};
++
++struct pcm_stream_info {
++ int str_id;
++ void *mad_substream;
++ void (*period_elapsed) (void *mad_substream);
++ unsigned long long buffer_ptr;
++ int sfreq;
++};
++
++struct stream_buffer {
++ unsigned long addr;
++ int length;
++};
++
++static inline long sst_get_time(void)
++{
++ struct timeval t;
++ do_gettimeofday(&t);
++ return t.tv_usec;
++}
++
++#ifndef CONFIG_SND_AUDIO_DBG_PRINT
++#define printk(format, arg...) do {} while (0);
++#endif
++
++struct snd_pmic_ops {
++ int card_status;
++ int num_channel;
++ int input_dev_id;
++ int mute_status;
++ int output_dev_id;
++ int (*set_input_dev) (u8 value);
++ int (*set_output_dev) (u8 value);
++
++ int (*set_mute) (int dev_id, u8 value);
++ int (*get_mute) (int dev_id, u8 *value);
++
++ int (*set_vol) (int dev_id, u8 value);
++ int (*get_vol) (int dev_id, u8 *value);
++
++ int (*init_card) (void);
++ int (*set_pcm_audio_params) (int sfreq, int word_size ,int num_channel);
++ int (*set_pcm_voice_params) (void);
++ int (*set_voice_port) (int status);
++ int (*set_audio_port) (int status);
++
++ int (*power_up_pmic_pb) (unsigned int port);
++ int (*power_up_pmic_cp) (unsigned int port);
++ int (*power_down_pmic_pb) (void);
++ int (*power_down_pmic_cp) (void);
++ int (*power_down_pmic) (void);
++};
++
++struct intel_sst_card_ops {
++ char *module_name;
++ int vendor_id;
++ int (*control_set) (int control_element, void *value);
++ int (*send_buffer) (int str_id, struct stream_buffer *mad_buf);
++ struct snd_pmic_ops *scard_ops;
++};
++
++/* periphral interrupt interface */
++enum lpe_periphral {
++ LPE_DMA = 1,
++ LPE_SSP0,
++ LPE_SSP1
++};
++
++/* modified for generic access */
++struct sc_reg_access {
++ u16 reg_addr;
++ u8 value;
++ u8 mask;
++};
++enum sc_reg_access_type {
++ PMIC_READ = 0,
++ PMIC_WRITE,
++ PMIC_READ_MODIFY,
++};
++
++int register_sst_card(struct intel_sst_card_ops *card);
++void unregister_sst_card(struct intel_sst_card_ops *card);
++int lpe_mask_periphral_intr(enum lpe_periphral device);
++int lpe_unmask_periphral_intr(enum lpe_periphral device);
++int lpe_periphral_intr_status(enum lpe_periphral device, int *status);
++#endif /* __INTEL_SST_H__ */
+diff --git a/sound/pci/sst/intel_sst.c b/sound/pci/sst/intel_sst.c
+new file mode 100644
+index 0000000..c6e68b8
+--- /dev/null
++++ b/sound/pci/sst/intel_sst.c
+@@ -0,0 +1,527 @@
++/*
++ * intel_sst.c - Intel SST Driver for audio engine
++ *
++ * Copyright (C) 2008-10 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.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * This driver exposes the audio engine functionalities to the ALSA
++ * and middleware.
++ *
++ * This file contains all init functions
++ */
++
++#include <linux/cdev.h>
++#include <linux/pci.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/syscalls.h>
++#include <linux/fs.h>
++#include <linux/file.h>
++#include <linux/interrupt.h>
++#include <linux/list.h>
++#include <linux/workqueue.h>
++#include <linux/firmware.h>
++#include <linux/mutex.h>
++#include <linux/delay.h>
++#include <linux/sched.h>
++#ifdef CONFIG_MSTWN_POWER_MGMT
++#include <linux/intel_mid.h>
++#endif
++#include <sound/intel_lpe.h>
++#include <sound/intel_sst_ioctl.h>
++#include "intel_sst_fw_ipc.h"
++#include "intel_sst_common.h"
++
++
++MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
++MODULE_DESCRIPTION("Intel (R) Moorestown Audio Engine Driver");
++MODULE_LICENSE("GPL v2");
++MODULE_VERSION(SST_DRIVER_VERSION);
++
++struct intel_sst_drv *sst_drv_ctx;
++
++/* fops Routines */
++static const struct file_operations intel_sst_fops = {
++ .owner = THIS_MODULE,
++ .open = intel_sst_open,
++ .release = intel_sst_release,
++ .read = intel_sst_read,
++ .write = intel_sst_write,
++ .ioctl = intel_sst_ioctl,
++ .mmap = intel_sst_mmap,
++ .aio_read = intel_sst_aio_read,
++ .aio_write = intel_sst_aio_write,
++};
++
++spinlock_t pe_slock;
++unsigned int pe_inprogress = 0;
++
++/**
++* intel_sst_interrupt - Interrupt service routine for SST
++* @irq: irq number of interrupt
++* @dev_id: pointer to device structre
++*
++* This function is called by OS when SST device raises
++* an interrupt. This will be result of write in IPC register
++* Source can be busy or done interrupt
++*/
++static irqreturn_t intel_sst_interrupt(int irq, void *context)
++{
++ union interrupt_reg isr;
++ union ipc_header header;
++ union interrupt_reg imr;
++ struct intel_sst_drv *drv = (struct intel_sst_drv *) context;
++ unsigned int size = 0;
++ int str_id;
++ struct stream_info *stream ;
++
++
++ /* Interrupt arrived, check src */
++ isr.full = readl(drv->shim + SST_ISRX);
++
++ if (isr.part.busy_interrupt) {
++ header.full = readl(drv->shim + SST_IPCD);
++ if (header.part.large)
++ size = header.part.data;
++ if (header.part.msg_id & REPLY_MSG) {
++ sst_drv_ctx->ipc_process_msg.header = header;
++
++ if (header.part.msg_id == IPC_SST_PERIOD_ELAPSED) {
++ sst_clear_interrupt();
++
++ /*spin_lock(&pe_slock);*/
++ if (pe_inprogress == 1) {
++ /*spin_unlock(&pe_slock);*/
++ return IRQ_HANDLED;
++ }
++
++ pe_inprogress = 1;
++ //spin_unlock(&pe_slock);
++
++ str_id = header.part.str_id;
++ stream = &sst_drv_ctx->streams[str_id];
++ if (stream->period_elapsed)
++ stream->period_elapsed(stream->pcm_substream);
++ //spin_lock(&pe_slock);
++ pe_inprogress = 0;
++ //spin_unlock(&pe_slock);
++ return IRQ_HANDLED;
++ } else {
++ memcpy_fromio(sst_drv_ctx->ipc_process_msg.mailbox,
++ drv->mailbox + SST_MAILBOX_RCV, size);
++ queue_work(sst_drv_ctx->process_msg_wq,
++ &sst_drv_ctx->ipc_process_msg.wq);
++ }
++ } else {
++ sst_drv_ctx->ipc_process_reply.header = header;
++ memcpy_fromio(sst_drv_ctx->ipc_process_reply.mailbox,
++ drv->mailbox + SST_MAILBOX_RCV, size);
++ queue_work(sst_drv_ctx->process_reply_wq,
++ &sst_drv_ctx->ipc_process_reply.wq);
++ }
++ /* mask busy inetrrupt */
++ imr.full = readl(drv->shim + SST_IMRX);
++ imr.part.busy_interrupt = 1;
++ /* dummy register for shim workaround */
++ writel(imr.full, sst_drv_ctx->shim + SST_ISRD);
++ writel(imr.full, drv->shim + SST_IMRX);
++ return IRQ_HANDLED;
++ } else if (isr.part.done_interrupt) {
++ /* Clear done bit */
++ header.full = readl(drv->shim + SST_IPCX);
++ header.part.done = 0;
++ /* dummy register for shim workaround */
++ writel(header.full, sst_drv_ctx->shim + SST_ISRD);
++ writel(header.full, drv->shim + SST_IPCX);
++ /* write 1 to clear status register */;
++ isr.part.done_interrupt = 1;
++ /* dummy register for shim workaround */
++ writel(isr.full, sst_drv_ctx->shim + SST_ISRD);
++ writel(isr.full, drv->shim + SST_ISRX);
++ queue_work(sst_drv_ctx->post_msg_wq,
++ &sst_drv_ctx->ipc_post_msg.wq);
++ return IRQ_HANDLED;
++ } else
++ return IRQ_NONE;
++
++}
++
++
++/* PCI Routines */
++
++static struct pci_device_id intel_sst_ids[] = {
++ { 0x8086, 0x080A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
++ { 0, }
++};
++MODULE_DEVICE_TABLE(pci, intel_sst_ids);
++
++
++/*
++* intel_sst_probe - PCI probe function
++* @pci: PCI device structure
++* @pci_id: PCI device ID structure
++*
++* This function is called by OS when a device is found
++* This enables the device, interrupt etc
++*/
++static int __devinit intel_sst_probe(struct pci_dev *pci,
++ const struct pci_device_id *pci_id)
++{
++ int i, ret = 0;
++ static struct mutex drv_ctx_lock;
++ mutex_init(&drv_ctx_lock);
++
++ mutex_lock(&drv_ctx_lock);
++ if (sst_drv_ctx) {
++ printk(KERN_ERR
++ "SST ERR: Only one sst handle is supported\n");
++ mutex_unlock(&drv_ctx_lock);
++ return -EBUSY;
++ }
++
++ sst_drv_ctx = kzalloc(sizeof(*sst_drv_ctx), GFP_KERNEL);
++ if (!sst_drv_ctx) {
++ printk(KERN_ERR
++ "SST ERR: intel_sst malloc fail\n");
++ mutex_unlock(&drv_ctx_lock);
++ return -ENOMEM;
++ }
++ mutex_unlock(&drv_ctx_lock);
++
++ mutex_init(&sst_drv_ctx->stream_cnt_lock);
++ sst_drv_ctx->pmic_state = SND_MAD_UN_INIT;
++
++ mutex_lock(&sst_drv_ctx->stream_cnt_lock);
++ sst_drv_ctx->stream_cnt = 0;
++ sst_drv_ctx->encoded_cnt = 0;
++ sst_drv_ctx->am_cnt = 0;
++ mutex_unlock(&sst_drv_ctx->stream_cnt_lock);
++ sst_drv_ctx->pb_streams = 0;
++ sst_drv_ctx->cp_streams = 0;
++ sst_drv_ctx->unique_id = 0;
++ sst_drv_ctx->pmic_port_instance = SST_DEFAULT_PMIC_PORT;
++
++ INIT_LIST_HEAD(&sst_drv_ctx->ipc_dispatch_list);
++ INIT_WORK(&sst_drv_ctx->ipc_post_msg.wq, sst_post_message);
++ INIT_WORK(&sst_drv_ctx->ipc_process_msg.wq, sst_process_message);
++ INIT_WORK(&sst_drv_ctx->ipc_process_reply.wq, sst_process_reply);
++ INIT_WORK(&sst_drv_ctx->mad_ops.wq, sst_process_mad_ops);
++ init_waitqueue_head(&sst_drv_ctx->wait_queue);
++
++ sst_drv_ctx->mad_wq = create_workqueue("sst_mad_wq");
++ if (!sst_drv_ctx->mad_wq)
++ goto do_free_drv_ctx;
++ sst_drv_ctx->post_msg_wq = create_workqueue("sst_post_msg_wq");
++ if (!sst_drv_ctx->post_msg_wq)
++ goto free_mad_wq;
++ sst_drv_ctx->process_msg_wq = create_workqueue("sst_process_msg_wqq");
++ if (!sst_drv_ctx->process_msg_wq)
++ goto free_post_msg_wq;
++ sst_drv_ctx->process_reply_wq = create_workqueue("sst_proces_reply_wq");
++ if (!sst_drv_ctx->process_reply_wq)
++ goto free_process_msg_wq;
++
++ for (i = 0; i < MAX_ACTIVE_STREAM; i++) {
++ sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
++ sst_drv_ctx->alloc_block[i].ops_block.condition = false;
++ }
++ mutex_init(&sst_drv_ctx->list_lock);
++
++ for (i = 1; i < MAX_NUM_STREAMS; i++) {
++ struct stream_info *stream = &sst_drv_ctx->streams[i];
++ INIT_LIST_HEAD(&stream->bufs);
++ mutex_init(&stream->lock);
++ spin_lock_init(&stream->pcm_lock);
++ }
++ sst_drv_ctx->mmap_mem = NULL;
++ sst_drv_ctx->mmap_len = SST_MMAP_PAGES * PAGE_SIZE;
++ while (sst_drv_ctx->mmap_len > 0) {
++ sst_drv_ctx->mmap_mem =
++ kzalloc(sst_drv_ctx->mmap_len, GFP_KERNEL);
++ if (sst_drv_ctx->mmap_mem) {
++ printk(KERN_DEBUG "SST DBG:Got memory %p size 0x%x \n",
++ sst_drv_ctx->mmap_mem,
++ sst_drv_ctx->mmap_len);
++ break;
++ }
++ sst_drv_ctx->mmap_len -= (SST_MMAP_STEP * PAGE_SIZE);
++ if (sst_drv_ctx->mmap_len <= 0) {
++ printk(KERN_ERR
++ "SST ERR: Couldnt get any +\
++ mem...abort!!\n");
++ ret = -ENOMEM;
++ goto free_process_reply_wq;
++ }
++ printk(KERN_DEBUG "SST DBG:Failed...trying %d\n", \
++ sst_drv_ctx->mmap_len);
++ }
++
++ /* Init the device */
++ ret = pci_enable_device(pci);
++ if (ret) {
++ printk(KERN_ERR
++ "SST ERR: device cant be enabled\n");
++ goto do_free_mem;
++ }
++ sst_drv_ctx->pci = pci_dev_get(pci);
++ ret = pci_request_regions(pci, SST_DRV_NAME);
++ if (ret)
++ goto do_disable_device;
++ /* map registers */
++ /* SST Shim */
++ sst_drv_ctx->shim_phy_add =
++ (unsigned long) pci_resource_start(pci, 1);
++ sst_drv_ctx->shim = pci_ioremap_bar(pci, 1);
++ if (!sst_drv_ctx->shim)
++ goto do_release_regions;
++ printk(KERN_DEBUG "SST DBG:SST Shim Ptr %p \n", sst_drv_ctx->shim);
++
++ /* Shared SRAM */
++ sst_drv_ctx->mailbox = pci_ioremap_bar(pci, 2);
++ if (!sst_drv_ctx->mailbox)
++ goto do_unmap_shim;
++ printk(KERN_DEBUG "SST DBG:SRAM Ptr %p \n", sst_drv_ctx->mailbox);
++
++ /* IRAM */
++ sst_drv_ctx->iram = pci_ioremap_bar(pci, 3);
++ if (!sst_drv_ctx->iram)
++ goto do_unmap_sram;
++ printk(KERN_DEBUG "SST DBG:IRAM Ptr %p \n", sst_drv_ctx->iram);
++
++ /* DRAM */
++ sst_drv_ctx->dram = pci_ioremap_bar(pci, 4);
++ if (!sst_drv_ctx->dram)
++ goto do_unmap_iram;
++ printk(KERN_DEBUG "SST DBG:DRAM Ptr %p \n", sst_drv_ctx->dram);
++
++ sst_drv_ctx->sst_state = SST_UN_INIT;
++ /* Register the ISR */
++ ret = request_irq(pci->irq, intel_sst_interrupt,
++ IRQF_SHARED, SST_DRV_NAME, sst_drv_ctx);
++ if (ret)
++ goto do_unmap_dram;
++ printk(KERN_DEBUG "SST DBG:Registered IRQ 0x%x\n", pci->irq);
++
++ /* Register with /dev */
++ ret = register_chrdev(INTEL_SST_MAJOR, SST_DRV_NAME, &intel_sst_fops);
++ if (ret) {
++ printk(KERN_ERR
++ "SST ERR: couldn't register +\
++ device number\n");
++ goto do_free_irq;
++ }
++
++ sst_drv_ctx->lpe_stalled = 0;
++ printk(KERN_DEBUG "SST DBG:...successfully done!!!\n");
++ return ret;
++
++do_free_irq:
++ free_irq(pci->irq, sst_drv_ctx);
++do_unmap_dram:
++ iounmap(sst_drv_ctx->dram);
++do_unmap_iram:
++ iounmap(sst_drv_ctx->iram);
++do_unmap_sram:
++ iounmap(sst_drv_ctx->mailbox);
++do_unmap_shim:
++ iounmap(sst_drv_ctx->shim);
++do_release_regions:
++ pci_release_regions(pci);
++do_disable_device:
++ pci_disable_device(pci);
++do_free_mem:
++ kfree(sst_drv_ctx->mmap_mem);
++free_process_reply_wq:
++ destroy_workqueue(sst_drv_ctx->process_reply_wq);
++free_process_msg_wq:
++ destroy_workqueue(sst_drv_ctx->process_msg_wq);
++free_post_msg_wq:
++ destroy_workqueue(sst_drv_ctx->post_msg_wq);
++free_mad_wq:
++ destroy_workqueue(sst_drv_ctx->mad_wq);
++do_free_drv_ctx:
++ kfree(sst_drv_ctx);
++ printk(KERN_ERR
++ "SST ERR: Probe failed with 0x%x \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 __devexit intel_sst_remove(struct pci_dev *pci)
++{
++ pci_dev_put(sst_drv_ctx->pci);
++ sst_drv_ctx->sst_state = SST_UN_INIT;
++ unregister_chrdev(INTEL_SST_MAJOR, SST_DRV_NAME);
++ free_irq(pci->irq, sst_drv_ctx);
++ iounmap(sst_drv_ctx->dram);
++ iounmap(sst_drv_ctx->iram);
++ iounmap(sst_drv_ctx->mailbox);
++ iounmap(sst_drv_ctx->shim);
++ sst_drv_ctx->pmic_state = SND_MAD_UN_INIT;
++ kfree(sst_drv_ctx->mmap_mem);
++ destroy_workqueue(sst_drv_ctx->process_reply_wq);
++ destroy_workqueue(sst_drv_ctx->process_msg_wq);
++ destroy_workqueue(sst_drv_ctx->post_msg_wq);
++ destroy_workqueue(sst_drv_ctx->mad_wq);
++ kfree(sst_drv_ctx);
++ pci_release_region(pci, 2);
++ pci_release_region(pci, 3);
++ pci_release_region(pci, 4);
++ pci_release_region(pci, 5);
++ pci_set_drvdata(pci, NULL);
++}
++
++/* Power Management */
++
++/**
++* intel_sst_suspend - PCI suspend function
++* @pci: PCI device structure
++* @state: PM message
++*
++* This function is called by OS when a power event occurs
++*/
++static int intel_sst_suspend(struct pci_dev *pci, pm_message_t state)
++{
++ int i;
++ printk(KERN_DEBUG "SST DBG:intel_sst_suspend called\n");
++
++ /* Pause all running streams */
++ for (i = 1; i < MAX_NUM_STREAMS; i++) {
++ if (sst_drv_ctx->streams[i].status == STREAM_RUNNING) {
++ sst_drv_ctx->active_streams[i] = true;
++ sst_pause_stream(i);
++ } else
++ sst_drv_ctx->active_streams[i] = false;
++ }
++
++ pci_set_drvdata(pci, sst_drv_ctx);
++
++ /* Send msg to FW FIXME */
++
++ /* Disable everything */
++ /* free_irq(pci->irq, sst_drv_ctx); */
++ pci_disable_device(pci);
++ pci_save_state(pci);
++ pci_set_power_state(pci, pci_choose_state(pci, state));
++ return 0;
++}
++
++/**
++* intel_sst_resume - PCI resume function
++* @pci: PCI device structure
++* @state: PM message
++*
++* This function is called by OS when a power event occurs
++*/
++static int intel_sst_resume(struct pci_dev *pci)
++{
++ int i;
++
++ printk(KERN_DEBUG "SST DBG:\nintel_sst_resume called\n");
++ sst_drv_ctx = pci_get_drvdata(pci);
++ if (pci->irq)
++ printk(KERN_DEBUG "SST DBG:irq %d \n", pci->irq);
++
++ pci_set_power_state(pci, PCI_D0);
++ pci_restore_state(pci);
++
++ /* ret = request_irq(pci->irq, intel_sst_interrupt,
++ IRQF_SHARED, "intel_sst_engine", sst_drv_ctx);
++ if (ret) {
++ return ret;
++ } */
++
++ /* Send msg to FW FIXME */
++
++ /* Start all paused streams */
++ for (i = 1; i < MAX_NUM_STREAMS; i++) {
++ if (sst_drv_ctx->active_streams[i] == true)
++ sst_resume_stream(i);
++ }
++ return 0;
++}
++
++
++static struct pci_driver driver = {
++ .name = SST_DRV_NAME,
++ .id_table = intel_sst_ids,
++ .probe = intel_sst_probe,
++ .remove = __devexit_p(intel_sst_remove),
++ .suspend = intel_sst_suspend,
++ .resume = intel_sst_resume,
++};
++
++/**
++* intel_sst_init - Module init function
++*
++* Registers with PCI
++* Registers with /dev
++*Init all data strutures
++*/
++static int __init intel_sst_init(void)
++{
++ /* Init all variables, data structure etc....*/
++ int ret = 0;
++ printk(KERN_ERR
++ "INFO: ******** SST DRIVER +\
++ loading.. Ver: %s\n", SST_DRIVER_VERSION);
++
++ /* Register with PCI */
++ ret = pci_register_driver(&driver);
++ if (ret)
++ printk(KERN_ERR
++ "SST ERR: PCI register failed \n");
++ sst_spi_mode_enable();
++ return ret;
++}
++
++/**
++* intel_sst_exit - Module exit function
++*
++* Unregisters with PCI
++* Unregisters with /dev
++* Frees all data strutures
++*/
++static void __exit intel_sst_exit(void)
++{
++ int i;
++
++ for (i = 0; i < MAX_NUM_STREAMS; i++)
++ sst_free_stream(i);
++
++ /* Send msg to FW TBD */
++ pci_unregister_driver(&driver);
++
++ flush_scheduled_work();
++ printk(KERN_DEBUG "SST DBG:...unloaded\n");
++ return;
++}
++
++module_init(intel_sst_init);
++module_exit(intel_sst_exit);
+diff --git a/sound/pci/sst/intel_sst_dsp.c b/sound/pci/sst/intel_sst_dsp.c
+new file mode 100644
+index 0000000..bc78918
+--- /dev/null
++++ b/sound/pci/sst/intel_sst_dsp.c
+@@ -0,0 +1,706 @@
++/*
++ * intel_sst_dsp.h - Intel SST Driver for audio engine
++ *
++ * Copyright (C) 2008-10 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.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * This driver exposes the audio engine functionalities to the ALSA
++ * and middleware.
++ *
++ * This file contains all dsp controlling functions like firmware download,
++ * setting/resetting dsp cores, etc
++ */
++#include <linux/cdev.h>
++#include <linux/pci.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/syscalls.h>
++#include <linux/fs.h>
++#include <linux/file.h>
++#include <linux/interrupt.h>
++#include <linux/list.h>
++#include <linux/workqueue.h>
++#include <linux/firmware.h>
++#include <linux/mutex.h>
++#include <linux/delay.h>
++#include <linux/sched.h>
++#include <asm/ipc_defs.h>
++#include <sound/intel_lpe.h>
++#include <sound/intel_sst_ioctl.h>
++#include "intel_sst_fw_ipc.h"
++#include "intel_sst_common.h"
++
++
++MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
++MODULE_DESCRIPTION("Intel (R) Moorestown Audio Engine Driver");
++MODULE_LICENSE("GPL v2");
++MODULE_VERSION(SST_DRIVER_VERSION);
++
++/**
++* this function writes registers through SCU IPC
++*/
++static int sst_scu_ipc_write(u32 addr, u32 value)
++{
++ int retval = 0, retry = 3;
++ struct ipc_reg_data ipc_reg = {0};
++
++ ipc_reg.address = addr;
++ ipc_reg.data = value;
++ ipc_reg.ioc = 1;
++
++ while (retry) {
++ retval = mrst_ipc_write32(&ipc_reg);
++ if (!retval)
++ break;
++ retry--;
++ /* error */
++ printk(KERN_ERR "SST ERR: IPC +\
++ write failed %x\n", retval);
++ }
++ return retval;
++}
++
++/**
++* this function reads registers through SCU IPC
++*/
++static int sst_scu_ipc_read(u32 addr, u32 *value)
++{
++ int retval = 0, retry = 3;
++ struct ipc_reg_data ipc_reg = {0};
++
++ ipc_reg.address = addr;
++ ipc_reg.data = 0;
++ ipc_reg.ioc = 1;
++
++ while (retry) {
++ retval = mrst_ipc_read32(&ipc_reg);
++ if (!retval)
++ break;
++ retry--;
++ printk(KERN_ERR
++ "SST ERR: IPC read failed %x\n ", retval);
++ }
++ *value = ipc_reg.data;
++ printk(KERN_DEBUG "SST DBG:The read value +\
++ from the mrst_ipc is ::0x%08x\n", *value);
++ return retval;
++}
++/**
++* Resetting SST DSP
++*/
++static int intel_sst_reset_dsp(void)
++{
++ union config_status_reg csr;
++ int retval;
++ unsigned int value = 0;
++
++ retval = sst_scu_ipc_read(CHIP_REV_REG, &value);
++ if (retval)
++ return retval;
++
++#if 0
++ /* A2-CHANGES */
++ if (((value & CHIP_REV_ADDR) >> 3) == CHIP_REV_A1) {
++ sst_drv_ctx->chip_rev_id = CHIP_A1_50;
++ /* SCU FW Changes*/
++ retval = sst_scu_ipc_write(AUD_SHIM_BASE_ADDR,
++ AUD_SHIM_RATIO_1_1);
++ } else {
++ if (DSP_CLOCK_SPEED == CLK_100MHZ) {
++ sst_drv_ctx->chip_rev_id = CHIP_A2_100;
++ /* SCU FW Changes*/
++ retval = sst_scu_ipc_write(AUD_SHIM_BASE_ADDR,
++ AUD_SHIM_RATIO);
++ } else if (DSP_CLOCK_SPEED == CLK_50MHZ) {
++ sst_drv_ctx->chip_rev_id = CHIP_A2_50;
++ /* SCU FW Changes*/
++
++ retval = sst_scu_ipc_write(AUD_SHIM_BASE_ADDR,
++ AUD_SHIM_RATIO_1_1);
++ } else {
++ printk(KERN_ERR "SST ERR: +\
++ Invalid clock speed\n ");
++ return -EIO;
++ }
++ } /*else {
++ printk(KERN_ERR
++ "SST ERR: Invalid chip revision Type\n");
++ return -EIO;
++ }*/
++#endif
++ /* to fix SPI driver bug, which sets to 1 */
++ csr.full = 0x3a2;
++ writel(csr.full, sst_drv_ctx->shim + SST_ISRX);
++ writel(csr.full, sst_drv_ctx->shim + SST_CSR);
++ /* ----------- */
++
++ csr.full = readl(sst_drv_ctx->shim + SST_CSR);
++ csr.part.strb_cntr_rst = 0;
++ csr.part.run_stall = 0x1;
++ csr.part.bypass = 0x7;
++ csr.part.sst_reset = 0x1;
++ writel(csr.full, sst_drv_ctx->shim + SST_ISRX);
++ writel(csr.full, sst_drv_ctx->shim + SST_CSR);
++
++ printk(KERN_DEBUG "SST DBG:Chip version +\
++ is:: %d\n", value);
++ return retval;
++}
++
++/**
++* Start the SST DSP processor
++*/
++static int sst_start(void)
++{
++ union config_status_reg csr;
++
++ csr.full = readl(sst_drv_ctx->shim + SST_CSR);
++ csr.part.bypass = 0;
++ writel(csr.full, sst_drv_ctx->shim + SST_ISRX);
++ writel(csr.full, sst_drv_ctx->shim + SST_CSR);
++
++#if 0
++ retval = sst_scu_ipc_write(
++ sst_drv_ctx->shim_phy_add + SST_CSR, csr.full);
++ if (retval != 0)
++ printk(KERN_ERR
++ "SST ERR: scu ipc write start failed %d ", retval);
++ csr.full = readl(sst_drv_ctx->shim + SST_CSR);
++ csr.part.sst_reset = 0;
++ csr.part.run_stall = 0;
++ if ((sst_drv_ctx->chip_rev_id == CHIP_A2_50) ||
++ (sst_drv_ctx->chip_rev_id == CHIP_A2_100)) {
++ csr.part.strb_cntr_rst = 1;
++ if (sst_drv_ctx->chip_rev_id == CHIP_A2_100)
++ csr.part.sst_clk = 1;
++ }
++#endif
++ csr.part.run_stall = 0;
++ csr.part.sst_reset = 0;
++ csr.part.strb_cntr_rst = 1;
++ printk(KERN_DEBUG "SST DBG:Setting SST to execute 0x%x \n", csr.full);
++ writel(csr.full, sst_drv_ctx->shim + SST_ISRX);
++ writel(csr.full, sst_drv_ctx->shim + SST_CSR);
++
++#if 0
++ return sst_scu_ipc_write(
++ sst_drv_ctx->shim_phy_add + SST_CSR, csr.full);
++#endif
++ return 0;
++}
++
++/**
++* Parse modules that need to be placed in SST IRAM and DRAM
++*/
++static int sst_parse_module(struct fw_module_header *module)
++{
++ struct dma_block_info *block;
++ u32 count;
++ void __iomem *ram;
++
++ printk(KERN_DEBUG "SST DBG:module sign=%s sz=0x%x blks=0x%x typ=0x%x ep=0x%x sz=0x%x\n",
++ module->signature, module->mod_size,
++ module->blocks, module->type,
++ module->entry_point, sizeof(*module));
++
++ block = (void *)module + sizeof(*module);
++
++ for (count = 0; count < module->blocks; count++) {
++ if (block->size <= 0) {
++ printk(KERN_ERR "SST ERR: +\
++ block size invalid\n ");
++ return -EINVAL;
++ }
++ switch (block->type) {
++ case SST_IRAM:
++ ram = sst_drv_ctx->iram;
++ break;
++ case SST_DRAM:
++ ram = sst_drv_ctx->dram;
++ break;
++ default:
++ printk(KERN_ERR
++ "SST ERR:wrng ram typ0x%x +\
++ inblock0x%x\n", block->type, count);
++ return -EINVAL;
++ }
++ memcpy_toio(ram + block->ram_offset,
++ (void *)block + sizeof(*block), block->size);
++ block = (void *)block + sizeof(*block) + block->size;
++ }
++ return 0;
++}
++
++/**
++* sst_parse_fw_image - FW parse and load
++* This function is called to parse and download the FW image
++*/
++static int sst_parse_fw_image(const struct firmware *sst_fw)
++{
++ struct fw_header *header;
++ u32 count;
++ int ret_val;
++ struct fw_module_header *module;
++
++ BUG_ON(!sst_fw);
++
++ /* Read the header information from the data pointer */
++ header = (struct fw_header *)sst_fw->data;
++
++ /* verify FW */
++ if ((strncmp(header->signature, SST_FW_SIGN, 4) != 0) ||
++ (sst_fw->size != header->file_size + sizeof(*header))) {
++ /* Invalid FW signature */
++ printk(KERN_ERR
++ "SST ERR: InvalidFW sgn/filesiz mismtch\n ");
++ return -EINVAL;
++ }
++ printk(KERN_DEBUG "SST DBG:header sign=%s size=0x%x modules=0x%x fmt=0x%x size=0x%x\n",
++ header->signature, header->file_size, header->modules,
++ header->file_format, sizeof(*header));
++ module = (void *)sst_fw->data + sizeof(*header);
++ for (count = 0; count < header->modules; count++) {
++ /* module */
++ ret_val = sst_parse_module(module);
++ if (ret_val)
++ return ret_val;
++ module = (void *)module + sizeof(*module) + module->mod_size ;
++ }
++
++ printk(KERN_DEBUG "SST DBG:done....\n");
++ return 0;
++}
++
++/**
++* sst_load_fw - function to reset FW
++* @fw: Pointer to loaded FW
++* This function is called when the FW is loaded
++*/
++int sst_load_fw(const struct firmware *fw, void *context)
++{
++ int ret_val;
++
++ printk(KERN_DEBUG "SST DBG:called \n");
++ BUG_ON(!fw);
++
++ /* TBD: Checksum, tamper check etc */
++ ret_val = intel_sst_reset_dsp();
++ if (ret_val)
++ return ret_val;
++ /* putting the sst state to init */
++ sst_drv_ctx->sst_state = SST_UN_INIT;
++
++ ret_val = sst_parse_fw_image(fw);
++ if (ret_val)
++ return ret_val;
++
++ sst_drv_ctx->sst_state = SST_FW_LOADED;
++ /* 7. ask scu to reset the bypass bits */
++ /* 8.bring sst out of reset */
++ ret_val = sst_start();
++ if (ret_val)
++ return ret_val;
++
++ printk(KERN_DEBUG "SST DBG:...successful!!!\n");
++ return ret_val;
++}
++
++/**
++* This function is called when any codec/post processing library
++* needs to be downloaded
++*/
++static int sst_download_library(const struct firmware *fw_lib,
++ struct snd_sst_lib_download_info *lib)
++{
++ /* send IPC message and wait */
++ int i;
++ u8 pvt_id;
++ struct ipc_post *msg = NULL;
++ union config_status_reg csr;
++ struct snd_sst_str_type str_type = {0};
++ int retval = 0;
++
++ if (sst_create_large_msg(&msg))
++ return -ENOMEM;
++
++ pvt_id = sst_assign_pvt_id(sst_drv_ctx);
++ i = sst_get_block_stream(sst_drv_ctx);
++ printk(KERN_DEBUG "SST DBG:alloc block +\
++ allocated = %d, pvt_id %d\n", i, pvt_id);
++ if (i < 0) {
++ kfree(msg);
++ return -ENOMEM;
++ }
++ sst_drv_ctx->alloc_block[i].sst_id = pvt_id;
++ sst_fill_header(&msg->header, IPC_IA_PREP_LIB_DNLD, 1, 0);
++ msg->header.part.data = sizeof(u32) + sizeof(str_type);
++ str_type.codec_type = lib->dload_lib.lib_info.lib_type;
++ str_type.pvt_id = pvt_id;
++ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
++ memcpy(msg->mailbox_data + sizeof(u32), &str_type, sizeof(str_type));
++ mutex_lock(&sst_drv_ctx->list_lock);
++ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
++ mutex_unlock(&sst_drv_ctx->list_lock);
++ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
++ retval = sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[i]);
++ if (retval) {
++ /* error */
++ sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
++ printk(KERN_ERR
++ "SST ERR: Prep codec downloaded failed %d\n", retval);
++ return -EIO;
++ }
++ printk(KERN_DEBUG "SST DBG:FW responded, ready for download now...\n");
++ /* downloading on success */
++ sst_drv_ctx->sst_state = SST_FW_LOADED;
++ csr.full = readl(sst_drv_ctx->shim + SST_CSR);
++ printk(KERN_DEBUG "SST DBG:CSR reg 0x%x \n", csr.full);
++ csr.part.run_stall = 1;
++ printk(KERN_DEBUG "SST DBG:HALT CSR reg setting to 0x%x \n", csr.full);
++ writel(csr.full, sst_drv_ctx->shim + SST_ISRX);
++ writel(csr.full, sst_drv_ctx->shim + SST_CSR);
++#if 0
++ retval = sst_scu_ipc_write(
++ sst_drv_ctx->shim_phy_add + SST_CSR, csr.full);
++ if (retval) {
++ /* error */
++ sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
++ printk(KERN_ERR
++ "SST ERR: IPC failed to Halt SST 0x%x\n", retval);
++ return -EAGAIN;
++ }
++#endif
++ csr.full = readl(sst_drv_ctx->shim + SST_CSR);
++ csr.part.bypass = 0x7;
++ printk(KERN_DEBUG "SST DBG:Bypass CSR reg +\
++ setting to 0x%x \n", csr.full);
++ writel(csr.full, sst_drv_ctx->shim + SST_ISRX);
++ writel(csr.full, sst_drv_ctx->shim + SST_CSR);
++#if 0
++ retval = sst_scu_ipc_write(
++ sst_drv_ctx->shim_phy_add + SST_CSR, csr.full);
++ if (retval) {
++ /* error */
++ sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
++ printk(KERN_ERR
++ "SST ERR: IPC failed to Bypass SST 0x%x\n", retval);
++ csr.part.bypass = 0x0;
++ /* bring LPE out of run stall */
++ /* send error mesages to FW- TBD FIXME */
++ csr.part.run_stall = 0x0;
++ printk(KERN_DEBUG "SST DBG:Bypass CSR reg +\
++ setting to 0x%x \n", csr.full);
++ retval = sst_scu_ipc_write(sst_drv_ctx->shim_phy_add + SST_CSR,
++ csr.full);
++ if (retval) {
++ /* prepare to download firmware again
++ for the next time TBD FIXME
++ sst_drv_ctx->sst_state = SST_UN_INIT;*/
++ }
++ return -EAGAIN;
++ }
++#endif
++ sst_parse_fw_image(fw_lib);
++
++ /* set the FW to running again */
++ csr.full = readl(sst_drv_ctx->shim + SST_CSR);
++ csr.part.bypass = 0x0;
++ printk(KERN_DEBUG "SST DBG:Bypass CSR reg +\
++ setting to 0x%x \n", csr.full);
++ writel(csr.full, sst_drv_ctx->shim + SST_ISRX);
++ writel(csr.full, sst_drv_ctx->shim + SST_CSR);
++#if 0
++ retval = sst_scu_ipc_write(
++ sst_drv_ctx->shim_phy_add + SST_CSR, csr.full);
++ if (retval) {
++ sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
++ printk(KERN_ERR\
++ "SST ERR: BypassCSR regclear failed 0x%x\n", retval);
++ /* bring LPE out of run stall */
++ /* send error mesages to FW- TBD FIXME */
++ csr.part.run_stall = 0x0;
++ printk(KERN_DEBUG "SST DBG:Bypass CSR +\
++ reg setting to 0x%x \n", csr.full);
++ retval = sst_scu_ipc_write(sst_drv_ctx->shim_phy_add + SST_CSR,
++ csr.full);
++ if (retval) {
++ /* prepare to download firmware again
++ for the next time TBD FIXME
++ sst_drv_ctx->sst_state = SST_UN_INIT;*/
++ }
++ return -EAGAIN;
++ }
++#endif
++ csr.full = readl(sst_drv_ctx->shim + SST_CSR);
++ csr.part.run_stall = 0;
++ printk(KERN_DEBUG "SST DBG:Stalll CSR reg +\
++ setting to 0x%x \n", csr.full);
++ writel(csr.full, sst_drv_ctx->shim + SST_ISRX);
++ writel(csr.full, sst_drv_ctx->shim + SST_CSR);
++#if 0
++ retval = sst_scu_ipc_write(
++ sst_drv_ctx->shim_phy_add + SST_CSR, csr.full);
++ if (retval) {
++ sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
++ printk(KERN_ERR
++ "SST ERR: Stall CSR reg clear failed 0x%x \n", retval);
++ if (retval) {
++ /* prepare to download firmware again
++ for the next time TBD FIXME
++ sst_drv_ctx->sst_state = SST_UN_INIT;*/
++ }
++ return -EAGAIN;
++ }
++#endif
++ /* send download complete and wait */
++ if (sst_create_large_msg(&msg)) {
++ sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
++ return -ENOMEM;
++ }
++
++ sst_fill_header(&msg->header, IPC_IA_LIB_DNLD_CMPLT, 1, 0);
++ msg->header.part.data = sizeof(u32) + sizeof(*lib);
++ lib->pvt_id = pvt_id;
++ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
++ memcpy(msg->mailbox_data + sizeof(u32), lib, sizeof(*lib));
++ mutex_lock(&sst_drv_ctx->list_lock);
++ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
++ mutex_unlock(&sst_drv_ctx->list_lock);
++ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
++ printk(KERN_DEBUG "SST DBG:Waiting for FW to respond on Download complete \n");
++ sst_drv_ctx->alloc_block[i].ops_block.condition = false;
++ retval = sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[i]);
++ if (retval) {
++ /* error */
++ sst_drv_ctx->sst_state = SST_FW_RUNNING;
++ /* shouldnt we set it to error state??? TBD */
++ sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
++ return -EIO;
++ }
++
++ printk(KERN_DEBUG "SST DBG:FW responded sucess on Download complete \n");
++ sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
++ sst_drv_ctx->sst_state = SST_FW_RUNNING;
++ return 0;
++
++}
++
++/**
++* This function is called befoer downloading the codec/postprocessing
++* library is set for download to SST DSP
++*/
++static int sst_validate_library(const struct firmware *fw_lib,
++ struct lib_slot_info *slot,
++ u32 *entry_point)
++{
++ struct fw_header *header;
++ struct fw_module_header *module;
++ struct dma_block_info *block;
++ unsigned int n_blk, isize = 0, dsize = 0;
++ int err = 0;
++
++ header = (struct fw_header *)fw_lib->data;
++ if (header->modules != 1) {
++ printk(KERN_ERR\
++ "SST ERR: Module no mismatch found\n ");
++ err = -EINVAL;
++ goto exit;
++ }
++ module = (void *)fw_lib->data + sizeof(*header);
++ *entry_point = module->entry_point;
++ printk(KERN_DEBUG "SST DBG:Module entry point 0x%x \n", *entry_point);
++ printk(KERN_DEBUG "SST DBG:Module Sign %s, Size 0x%x, Blocks 0x%x Type 0x%x \n",
++ module->signature, module->mod_size,
++ module->blocks, module->type);
++
++ block = (void *)module + sizeof(*module);
++ for (n_blk = 0; n_blk < module->blocks; n_blk++) {
++ switch (block->type) {
++ case SST_IRAM:
++ isize += block->size;
++ break;
++ case SST_DRAM:
++ dsize += block->size;
++ break;
++ default:
++ printk(KERN_ERR
++ "SST ERR: Invalid blk type for 0x%x\n ", n_blk);
++ err = -EINVAL;
++ goto exit;
++ }
++ block = (void *)block + sizeof(*block) + block->size;
++ }
++ if (isize > slot->iram_size || dsize > slot->dram_size) {
++ printk(KERN_ERR
++ "SST ERR: library exceeds size allocated \n");
++ err = -EINVAL;
++ goto exit;
++ } else
++ printk(KERN_DEBUG "SST DBG:Library is safe for download...\n");
++
++ printk(KERN_DEBUG "SST DBG:iram 0x%x, dram 0x%x, allowed iram 0x%x, allowed dram 0x%x\n",
++ isize, dsize, slot->iram_size, slot->dram_size);
++exit:
++ return err;
++
++}
++
++/**
++* This function is called when FW requests for a particular libary download
++* This function prepares the library to download
++*/
++int sst_load_library(struct snd_sst_lib_download *lib, u8 ops, u32 pvt_id)
++{
++ char buf[20];
++ const char *type, *dir;
++ int len = 0, error = 0;
++ u32 entry_point;
++ const struct firmware *fw_lib;
++ struct snd_sst_lib_download_info dload_info = {{{0},},};
++
++ memset(buf, 0, sizeof(buf));
++
++ printk(KERN_DEBUG "SST DBG:Lib Type 0x%x, Slot 0x%x, ops 0x%x \n",
++ lib->lib_info.lib_type, lib->slot_info.slot_num, ops);
++ printk(KERN_DEBUG "SST DBG:Version 0x%x, name %s, caps 0x%x media type 0x%x \n",
++ lib->lib_info.lib_version, lib->lib_info.lib_name,
++ lib->lib_info.lib_caps, lib->lib_info.media_type);
++
++ printk(KERN_DEBUG "SST DBG:IRAM Size 0x%x, offset 0x%x, DRAM Size 0x%x, offset 0x%x \n",
++ lib->slot_info.iram_size, lib->slot_info.iram_offset,
++ lib->slot_info.dram_size, lib->slot_info.dram_offset);
++
++ switch (lib->lib_info.lib_type) {
++ case SST_CODEC_TYPE_MP3:
++ type = "mp3_";
++ break;
++ case SST_CODEC_TYPE_AAC:
++ type = "aac_";
++ break;
++ case SST_CODEC_TYPE_AACP:
++ type = "aac_v1_";
++ break;
++ case SST_CODEC_TYPE_eAACP:
++ type = "aac_v2_";
++ break;
++ case SST_CODEC_TYPE_WMA9:
++ type = "wma9_";
++ break;
++ default:
++ printk(KERN_ERR "SST ERR: +\
++ Invalid codec type \n");
++ error = -EINVAL;
++ goto wake;
++ }
++
++ if (ops == STREAM_OPS_CAPTURE)
++ dir = "enc_";
++ else
++ dir = "dec_";
++ strncpy(buf, type, strlen(type));
++ strncpy(buf + strlen(type), dir, strlen(dir));
++ len = strlen(type) + strlen(dir);
++ len += snprintf(buf + len, sizeof(buf) - len, "%d",
++ lib->slot_info.slot_num);
++ len += snprintf(buf + len, sizeof(buf) - len, ".bin");
++
++ printk(KERN_DEBUG "SST DBG:Requesting %s \n", buf);
++
++ error = request_firmware(&fw_lib, buf, &sst_drv_ctx->pci->dev);
++ if (error) {
++ printk(KERN_ERR
++ "SST ERR: library load failed %d \n", error);
++ goto wake;
++ }
++ error = sst_validate_library(fw_lib, &lib->slot_info, &entry_point);
++ if (error)
++ goto wake_free;
++
++ lib->mod_entry_pt = entry_point;
++ memcpy(&dload_info.dload_lib, lib, sizeof(*lib));
++ error = sst_download_library(fw_lib, &dload_info);
++ if (error)
++ goto wake_free;
++
++ /* lib is downloaded and init send alloc again */
++ printk(KERN_DEBUG "SST DBG:Library is downloaded now... \n");
++wake_free:
++ /* sst_wake_up_alloc_block(sst_drv_ctx, pvt_id, error, NULL); */
++ release_firmware(fw_lib);
++wake:
++ return error;
++}
++
++/* This Function set the bit banging*/
++int sst_spi_mode_enable()
++{
++
++ void __iomem *logical_ptr_to_bang;
++ u32 regbase = SPI_MODE_ENABLE_BASE_ADDR, range = 0x38;
++ u32 data;
++ u32 mask = 0x400000;
++ int retval;
++ int i = 0;
++
++
++ logical_ptr_to_bang = ioremap_nocache(regbase, range);
++ if (!logical_ptr_to_bang) {
++ dev_err(&sst_drv_ctx->pci->dev, \
++ "SST ERR: SSP0 bit bang -IOREMAP Failed \n");
++ return -1;
++ }
++
++ /* spi mode enable */
++ iowrite32(0x0000000f, logical_ptr_to_bang);
++ iowrite32(0x33301dc3, logical_ptr_to_bang + 0x4);
++ iowrite32(0x02010007, logical_ptr_to_bang + 0x2c);
++ iowrite32(0x00000000, logical_ptr_to_bang + 0x30);
++ iowrite32(0x00000000, logical_ptr_to_bang + 0x34);
++ iowrite32(0x0000008f, logical_ptr_to_bang);
++
++
++ retval = sst_scu_ipc_write(0xff12b004, 0x3);
++ retval = sst_scu_ipc_write(0xff12b000, 0x01070034);
++ retval = sst_scu_ipc_write(0xff12b004, 0x99);
++ retval = sst_scu_ipc_write(0xff12b000, 0x01070038);
++
++ data = ioread32(logical_ptr_to_bang+0x8);
++ dev_err(&sst_drv_ctx->pci->dev,\
++ "SST ERR: SSP0 bit bang SSCR val = 0x%08x \n", data);
++ data = data & mask;
++ while (data == mask) {
++ retval = sst_scu_ipc_write(0xff12b004, 0x3);
++ retval = sst_scu_ipc_write(0xff12b000, 0x01070034);
++ retval = sst_scu_ipc_write(0xff12b004, 0x2);
++ retval = sst_scu_ipc_write(0xff12b000, 0x01070034);
++ data = ioread32(logical_ptr_to_bang+0x8);
++ data = data & mask;
++ i++;
++ }
++ dev_err(&sst_drv_ctx->pci->dev, \
++ "SST ERR: SSP0 bit bang while loop counter= %4d \n ", i);
++ retval = sst_scu_ipc_write(0xff12b004, 0x0);
++ retval = sst_scu_ipc_write(0xff12b000, 0x01070038);
++
++ return retval;
++}
+--
+1.6.2.2
+