From mboxrd@z Thu Jan 1 00:00:00 1970 From: Takashi Iwai Subject: Re: [PATCH 1/5] ASoC: Intel: Add Intel SST audio DSP low level shim driver. Date: Fri, 14 Feb 2014 09:29:35 +0100 Message-ID: References: <1392318930-8771-1-git-send-email-liam.r.girdwood@linux.intel.com> Mime-Version: 1.0 (generated by SEMI 1.14.6 - "Maruoka") Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: Received: from mx2.suse.de (cantor2.suse.de [195.135.220.15]) by alsa0.perex.cz (Postfix) with ESMTP id 5BC1D261615 for ; Fri, 14 Feb 2014 09:29:36 +0100 (CET) In-Reply-To: <1392318930-8771-1-git-send-email-liam.r.girdwood@linux.intel.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org To: Liam Girdwood Cc: alsa-devel@alsa-project.org, Mark Brown , Benson Leung List-Id: alsa-devel@alsa-project.org At Thu, 13 Feb 2014 19:15:26 +0000, Liam Girdwood wrote: > > Add support for Intel Smart Sound Technology (SST) audio DSPs. > This driver provides the low level IO, reset, boot and IRQ management > for Intel audio DSPs. These files make up the low level part of the SST > audio driver stack and will be used by many Intel SST cores like > Haswell, Broadwell and Baytrail. > > SST DSPs expose a memory mapped region (shim) for config and control. > The shim layout is mostly shared without much modification across cores > and this driver provides a uniform API to access the shim and to enable > basic shim functions. It also provides functionality to abstract some shim > functions for cores with different shim features. > > Signed-off-by: Liam Girdwood > --- > sound/soc/intel/sst-dsp-priv.h | 291 ++++++++++++++++++++++++++++++++ > sound/soc/intel/sst-dsp.c | 370 +++++++++++++++++++++++++++++++++++++++++ > sound/soc/intel/sst-dsp.h | 226 +++++++++++++++++++++++++ > 3 files changed, 887 insertions(+) > create mode 100644 sound/soc/intel/sst-dsp-priv.h > create mode 100644 sound/soc/intel/sst-dsp.c > create mode 100644 sound/soc/intel/sst-dsp.h > > diff --git a/sound/soc/intel/sst-dsp-priv.h b/sound/soc/intel/sst-dsp-priv.h > new file mode 100644 > index 0000000..c4db4c7 > --- /dev/null > +++ b/sound/soc/intel/sst-dsp-priv.h > @@ -0,0 +1,291 @@ > +/* > + * Intel Smart Sound Technology > + * > + * Copyright (C) 2013, Intel Corporation. All rights reserved. > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License version > + * 2 as published by the Free Software Foundation. > + * > + * 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. > + * > + */ > + > +#ifndef __SOUND_SOC_SST_DSP_PRIV_H > +#define __SOUND_SOC_SST_DSP_PRIV_H > + > +#include > +#include > +#include > +#include > + > +struct sst_mem_block; > +struct sst_module; > +struct sst_fw; > + > +/* > + * DSP Operations exported by platform Audio DSP driver. > + */ > +struct sst_ops { > + /* DSP core boot / reset */ > + void (*boot)(struct sst_dsp *); > + void (*reset)(struct sst_dsp *); > + > + /* Shim IO */ > + void (*write)(void __iomem *addr, u32 offset, u32 value); > + u32 (*read)(void __iomem *addr, u32 offset); > + void (*write64)(void __iomem *addr, u32 offset, u64 value); > + u64 (*read64)(void __iomem *addr, u32 offset); > + > + /* DSP I/DRAM IO */ > + void (*ram_read)(struct sst_dsp *sst, void *dest, void *src, size_t bytes); > + void (*ram_write)(struct sst_dsp *sst, void *dest, void *src, size_t bytes); > + > + void (*dump)(struct sst_dsp *); > + > + /* IRQ handlers */ > + irqreturn_t (*irq_handler)(int irq, void *context); > + > + /* SST init and free */ > + int (*init)(struct sst_dsp *sst, struct sst_pdata *pdata); > + void (*free)(struct sst_dsp *sst); > + > + /* FW module parser/loader */ > + int (*parse_fw)(struct sst_fw *sst_fw); > +}; > + > +/* > + * Audio DSP memory offsets and addresses. > + */ > +struct sst_addr { > + u32 lpe_base; > + u32 shim_offset; > + u32 iram_offset; > + void __iomem *lpe; > + void __iomem *shim; > + void __iomem *pci_cfg; > + void __iomem *fw_ext; > +}; > + > +/* > + * Audio DSP Mailbox configuration. > + */ > +struct sst_mailbox { > + void __iomem *in_base; > + void __iomem *out_base; > + size_t in_size; > + size_t out_size; > +}; > + > +/* > + * Audio DSP Firmware data types. > + */ > +enum sst_data_type { > + SST_DATA_M = 0, /* module block data */ > + SST_DATA_P = 1, /* peristant data (text, data) */ > + SST_DATA_S = 2, /* scratch data (usually buffers) */ > +}; > + > +/* > + * Audio DSP memory block types. > + */ > +enum sst_mem_type { > + SST_MEM_IRAM = 0, > + SST_MEM_DRAM = 1, > + SST_MEM_ANY = 2, > + SST_MEM_CACHE= 3, > +}; > + > +/* > + * Audio DSP Generic Firmware File. > + * > + * SST Firmware files can consist of 1..N modules. This generic structure is > + * used to manage each firmware file and it's modules regardless of SST firmware > + * type. A SST driver may load multiple FW files. > + */ > +struct sst_fw { > + struct sst_dsp *dsp; > + > + /* base addresses of FW file data */ > + dma_addr_t dmable_fw_paddr; /* physical address of fw data */ > + void *dma_buf; /* virtual address of fw data */ > + u32 size; /* size of fw data */ > + > + /* lists */ > + struct list_head list; /* DSP list of FW */ > + struct list_head module_list; /* FW list of modules */ > + > + void *private; /* core doesn't touch this */ > +}; > + > +/* > + * Audio DSP Generic Module data. > + * > + * This is used to dsecribe any sections of persistent (text and data) and > + * scratch (buffers) of module data in ADSP memory space. > + */ > +struct sst_module_data { > + > + enum sst_mem_type type; /* destination memory type */ > + enum sst_data_type data_type; /* type of module data */ > + > + u32 size; /* size in bytes */ > + u32 offset; /* offset in FW file */ > + u32 data_offset; /* offset in ADSP memory space */ > + void *data; /* module data */ > +}; > + > +/* > + * Audio DSP Generic Module Template. > + * > + * Used to define and register a new FW module. This data is extracted from > + * FW module header information. > + */ > +struct sst_module_template { > + u32 id; > + u32 entry; /* entry point */ > + struct sst_module_data s; /* scratch data */ > + struct sst_module_data p; /* peristant data */ > +}; > + > +/* > + * Audio DSP Generic Module. > + * > + * Each Firmware file can consist of 1..N modules. A module can span multiple > + * ADSP memory blocks. The simplest FW will be a file with 1 module. > + */ > +struct sst_module { > + struct sst_dsp *dsp; > + struct sst_fw *sst_fw; /* parent FW we belong too */ > + > + /* module configuration */ > + u32 id; > + u32 entry; /* module entry point */ > + u32 offset; /* module offset in firmware file */ > + u32 size; /* module size */ > + struct sst_module_data s; /* scratch data */ > + struct sst_module_data p; /* peristant data */ > + > + /* runtime */ > + u32 usage_count; /* can be unloaded if count == 0 */ > + void *private; /* core doesn't touch this */ > + > + /* lists */ > + struct list_head block_list; /* Module list of blocks in use */ > + struct list_head list; /* DSP list of modules */ > + struct list_head list_fw; /* FW list of modules */ > +}; > + > +/* > + * SST Memory Block operations. > + */ > +struct sst_block_ops { > + int (*enable)(struct sst_mem_block *block); > + int (*disable)(struct sst_mem_block *block); > +}; > + > +/* > + * SST Generic Memory Block. > + * > + * SST ADP memory has multiple IRAM and DRAM blocks. Some ADSP blocks can be > + * power gated. > + */ > +struct sst_mem_block { > + struct sst_dsp *dsp; > + struct sst_module *module; /* module that uses this block */ > + > + /* block config */ > + u32 offset; /* offset from base */ > + u32 size; /* block size */ > + u32 index; /* block index 0..N */ > + enum sst_mem_type type; /* block memory type IRAM/DRAM */ > + struct sst_block_ops *ops; /* block operations, if any */ > + > + /* block status */ > + enum sst_data_type data_type; /* data type held in this block */ > + u32 bytes_used; /* bytes in use by modules */ > + void *private; /* generic core does not touch this */ > + int users; /* number of modules using this block */ > + > + /* block lists */ > + struct list_head module_list; /* Module list of blocks */ > + struct list_head list; /* Map list of free/used blocks */ > +}; > + > +/* > + * Generic SST Shim Interface. > + */ > +struct sst_dsp { > + > + /* runtime */ > + struct sst_dsp_device *sst_dev; > + spinlock_t spinlock; /* IPC locking */ > + struct mutex mutex; /* DSP FW lock */ > + struct device *dev; > + void *thread_context; > + int irq; > + u32 id; > + > + /* list of free and used ADSP memory blocks */ > + struct list_head used_block_list; > + struct list_head free_block_list; > + > + /* operations */ > + struct sst_ops *ops; > + > + /* debug FS */ > + struct dentry *debugfs_root; > + > + /* base addresses */ > + struct sst_addr addr; > + > + /* mailbox */ > + struct sst_mailbox mailbox; > + > + /* SST FW files loaded and their modules */ > + struct list_head module_list; > + struct list_head fw_list; > + > + /* platform data */ > + struct sst_pdata *pdata; > + > + /* DMA FW loading */ > + struct sst_dma *dma; > + bool fw_use_dma; > +}; > + > +/* Create/Free FW files - can contain multiple modules */ > +struct sst_fw *sst_fw_new(struct sst_dsp *dsp, > + const struct firmware *fw, void *private); > +void sst_fw_free(struct sst_fw *sst_fw); > +void sst_fw_free_all(struct sst_dsp *dsp); > + > +/* Create/Free firmware modules */ > +struct sst_module *sst_module_new(struct sst_fw *sst_fw, > + struct sst_module_template *template, void *private); > +void sst_module_free(struct sst_module *sst_module); > +int sst_module_insert(struct sst_module *sst_module); > +int sst_module_remove(struct sst_module *sst_module); > +int sst_module_insert_fixed_block(struct sst_module *module, > + struct sst_module_data *data); > +struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id); > + > +/* allocate/free pesistent/scratch memory regions managed by drv */ > +struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp); > +void sst_mem_block_free_scratch(struct sst_dsp *dsp, > + struct sst_module *scratch); > + > +/* Register the DSPs memory blocks - would be nice to read from ACPI */ > +struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset, > + u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index, > + void *private); > +void sst_mem_block_unregister_all(struct sst_dsp *dsp); > + > +/* DMA */ > +int sst_dma_new(struct sst_dsp *sst); > +void sst_dma_free(struct sst_dma *dma); > + > +#endif > diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/sst-dsp.c > new file mode 100644 > index 0000000..beef2ef > --- /dev/null > +++ b/sound/soc/intel/sst-dsp.c > @@ -0,0 +1,370 @@ > +/* > + * Intel Smart Sound Technology (SST) DSP Core Driver > + * > + * Copyright (C) 2013, Intel Corporation. All rights reserved. > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License version > + * 2 as published by the Free Software Foundation. > + * > + * 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 > +#include > +#include > +#include > +#include > + > +#include "sst-dsp.h" > +#include "sst-dsp-priv.h" > + > +#define CREATE_TRACE_POINTS > +#include > + > +/* Public API */ > +void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value) > +{ > + unsigned long flags; > + > + spin_lock_irqsave(&sst->spinlock, flags); > + sst->ops->write(sst->addr.shim, offset, value); > + spin_unlock_irqrestore(&sst->spinlock, flags); > +} > +EXPORT_SYMBOL(sst_dsp_shim_write); Any reason not to use *_GPL() version? > + > +u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset) > +{ > + unsigned long flags; > + u32 val; > + > + spin_lock_irqsave(&sst->spinlock, flags); > + val = sst->ops->read(sst->addr.shim, offset); > + spin_unlock_irqrestore(&sst->spinlock, flags); > + > + return val; > +} > +EXPORT_SYMBOL(sst_dsp_shim_read); > + > +void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value) > +{ > + unsigned long flags; > + > + spin_lock_irqsave(&sst->spinlock, flags); > + sst->ops->write64(sst->addr.shim, offset, value); > + spin_unlock_irqrestore(&sst->spinlock, flags); > +} > +EXPORT_SYMBOL(sst_dsp_shim_write64); > + > +u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset) > +{ > + unsigned long flags; > + u64 val; > + > + spin_lock_irqsave(&sst->spinlock, flags); > + val = sst->ops->read64(sst->addr.shim, offset); > + spin_unlock_irqrestore(&sst->spinlock, flags); > + > + return val; > +} > +EXPORT_SYMBOL(sst_dsp_shim_read64); > + > +void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value) > +{ > + sst->ops->write(sst->addr.shim, offset, value); > +} > +EXPORT_SYMBOL(sst_dsp_shim_write_unlocked); > + > +u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset) > +{ > + return sst->ops->read(sst->addr.shim, offset); > +} > +EXPORT_SYMBOL(sst_dsp_shim_read_unlocked); > + > +void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value) > +{ > + sst->ops->write64(sst->addr.shim, offset, value); > +} > +EXPORT_SYMBOL(sst_dsp_shim_write64_unlocked); > + > +u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset) > +{ > + return sst->ops->read64(sst->addr.shim, offset); > +} > +EXPORT_SYMBOL(sst_dsp_shim_read64_unlocked); > + > +int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset, > + u32 mask, u32 value) > +{ > + unsigned long flags; > + bool change; > + u32 old, new; > + > + spin_lock_irqsave(&sst->spinlock, flags); > + old = sst_dsp_shim_read_unlocked(sst, offset); > + > + new = (old & (~mask)) | (value & mask); > + > + change = (old != new); > + if (change) > + sst_dsp_shim_write_unlocked(sst, offset, new); > + > + spin_unlock_irqrestore(&sst->spinlock, flags); > + return change; > +} > +EXPORT_SYMBOL(sst_dsp_shim_update_bits); > + > +int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset, > + u64 mask, u64 value) > +{ > + unsigned long flags; > + bool change; > + u64 old, new; > + > + spin_lock_irqsave(&sst->spinlock, flags); > + old = sst_dsp_shim_read64_unlocked(sst, offset); > + > + new = (old & (~mask)) | (value & mask); > + > + change = (old != new); > + if (change) > + sst_dsp_shim_write64_unlocked(sst, offset, new); > + > + spin_unlock_irqrestore(&sst->spinlock, flags); > + return change; > +} > +EXPORT_SYMBOL(sst_dsp_shim_update_bits64); > + > +int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset, > + u32 mask, u32 value) > +{ > + bool change; > + unsigned int old, new; > + u32 ret; > + > + ret = sst_dsp_shim_read_unlocked(sst, offset); > + > + old = ret; > + new = (old & (~mask)) | (value & mask); > + > + change = (old != new); > + if (change) > + sst_dsp_shim_write_unlocked(sst, offset, new); > + > + return change; > +} > +EXPORT_SYMBOL(sst_dsp_shim_update_bits_unlocked); > + > +int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset, > + u64 mask, u64 value) > +{ > + bool change; > + u64 old, new; > + > + old = sst_dsp_shim_read64_unlocked(sst, offset); > + > + new = (old & (~mask)) | (value & mask); > + > + change = (old != new); > + if (change) > + sst_dsp_shim_write64_unlocked(sst, offset, new); > + > + return change; > +} > +EXPORT_SYMBOL(sst_dsp_shim_update_bits64_unlocked); The locked versions can be simplified by calling the unlocked function. > + > +void sst_dsp_dump(struct sst_dsp *sst) > +{ > + sst->ops->dump(sst); > +} > +EXPORT_SYMBOL(sst_dsp_dump); > + > +void sst_dsp_reset(struct sst_dsp *sst) > +{ > + sst->ops->reset(sst); > +} > +EXPORT_SYMBOL(sst_dsp_reset); > + > +int sst_dsp_boot(struct sst_dsp *sst) > +{ > + sst->ops->boot(sst); > + return 0; > +} > +EXPORT_SYMBOL(sst_dsp_boot); > + > +void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg) > +{ > + sst_dsp_shim_write_unlocked(dsp, SST_IPCX, msg | SST_IPCX_BUSY); > + trace_sst_ipc_msg_tx(msg); The trace isn't defined yet in the first patch, so the build fails here. Each commit should be at least compilable. > +} > +EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_tx); > + > +u32 sst_dsp_ipc_msg_rx(struct sst_dsp *dsp) > +{ > + u32 msg; > + > + msg = sst_dsp_shim_read_unlocked(dsp, SST_IPCX); > + trace_sst_ipc_msg_rx(msg); > + > + return msg; > +} > +EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_rx); > + > +void sst_dsp_write(struct sst_dsp *sst, void *src, u32 dest_offset, > + size_t bytes) > +{ > + sst->ops->ram_write(sst, sst->addr.lpe + dest_offset, src, bytes); > +} > +EXPORT_SYMBOL(sst_dsp_write); > + > +void sst_dsp_read(struct sst_dsp *sst, void *dest, u32 src_offset, > + size_t bytes) > +{ > + sst->ops->ram_read(sst, dest, sst->addr.lpe + src_offset, bytes); > +} > +EXPORT_SYMBOL(sst_dsp_read); > + > +int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset, size_t inbox_size, > + u32 outbox_offset, size_t outbox_size) > +{ > + sst->mailbox.in_base = sst->addr.lpe + inbox_offset; > + sst->mailbox.out_base = sst->addr.lpe + outbox_offset; > + sst->mailbox.in_size = inbox_size; > + sst->mailbox.out_size = outbox_size; > + return 0; > +} > +EXPORT_SYMBOL(sst_dsp_mailbox_init); > + > +void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes) > +{ > + int i; > + > + trace_sst_ipc_outbox_write(bytes); > + > + memcpy_toio(sst->mailbox.out_base, message, bytes); > + > + for (i = 0; i < bytes; i += 4) > + trace_sst_ipc_outbox_wdata(i, *(uint32_t *)(message + i)); Mix of different types... Use u32. > +} > +EXPORT_SYMBOL(sst_dsp_outbox_write); > + > +void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes) > +{ > + int i; > + > + trace_sst_ipc_outbox_read(bytes); > + > + memcpy_fromio(message, sst->mailbox.out_base, bytes); > + > + for (i = 0; i < bytes; i += 4) > + trace_sst_ipc_outbox_rdata(i, *(uint32_t *)(message + i)); > +} > +EXPORT_SYMBOL(sst_dsp_outbox_read); > + > +void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes) > +{ > + int i; > + > + trace_sst_ipc_inbox_write(bytes); > + > + memcpy_toio(sst->mailbox.in_base, message, bytes); > + > + for (i = 0; i < bytes; i += 4) > + trace_sst_ipc_inbox_wdata(i, *(uint32_t *)(message + i)); > +} > +EXPORT_SYMBOL(sst_dsp_inbox_write); > + > +void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes) > +{ > + int i; > + > + trace_sst_ipc_inbox_read(bytes); > + > + memcpy_fromio(message, sst->mailbox.in_base, bytes); > + > + for (i = 0; i < bytes; i += 4) > + trace_sst_ipc_inbox_rdata(i, *(uint32_t *)(message + i)); > +} > +EXPORT_SYMBOL(sst_dsp_inbox_read); > + > +void *sst_dsp_get_thread_context(struct sst_dsp *sst) > +{ > + return sst->thread_context; > +} > +EXPORT_SYMBOL(sst_dsp_get_thread_context); Hrm, an exported function call just for this is an overkill. Better to use an inline function. I guess inline functions would be good for other simple calls, too, unless the code size significantly grows. Takashi > +struct sst_dsp *sst_dsp_new(struct device *dev, > + struct sst_dsp_device *sst_dev, struct sst_pdata *pdata) > +{ > + struct sst_dsp *sst; > + int err; > + > + dev_dbg(dev, "initialising audio DSP id 0x%x\n", pdata->id); > + > + sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL); > + if (sst == NULL) > + return NULL; > + > + spin_lock_init(&sst->spinlock); > + mutex_init(&sst->mutex); > + sst->dev = dev; > + sst->thread_context = sst_dev->thread_context; > + sst->sst_dev = sst_dev; > + sst->id = pdata->id; > + sst->irq = pdata->irq; > + sst->ops = sst_dev->ops; > + sst->pdata = pdata; > + INIT_LIST_HEAD(&sst->used_block_list); > + INIT_LIST_HEAD(&sst->free_block_list); > + INIT_LIST_HEAD(&sst->module_list); > + INIT_LIST_HEAD(&sst->fw_list); > + > + /* Initialise SST Audio DSP */ > + if (sst->ops->init) { > + err = sst->ops->init(sst, pdata); > + if (err < 0) > + return NULL; > + } > + > + /* Register the ISR */ > + err = request_threaded_irq(sst->irq, sst->ops->irq_handler, > + sst_dev->thread, IRQF_SHARED, "AudioDSP", sst); > + if (err) > + goto irq_err; > + > + /* Register the FW loader DMA controller if we have one */ > + if (pdata->dma_engine) > + err = sst_dma_new(sst); > + if (err) > + goto dma_err; > + > + return sst; > + > +dma_err: > + free_irq(sst->irq, sst); > +irq_err: > + if (sst->ops->free) > + sst->ops->free(sst); > + > + return NULL; > +} > +EXPORT_SYMBOL(sst_dsp_new); > + > +void sst_dsp_free(struct sst_dsp *sst) > +{ > + if (sst->pdata->dma_engine) > + sst_dma_free(sst->dma); > + free_irq(sst->irq, sst); > + if (sst->ops->free) > + sst->ops->free(sst); > +} > +EXPORT_SYMBOL(sst_dsp_free); > + > +/* Module information */ > +MODULE_AUTHOR("Liam Girdwood"); > +MODULE_DESCRIPTION("Intel SST Core"); > +MODULE_LICENSE("GPL v2"); > diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/sst-dsp.h > new file mode 100644 > index 0000000..8ea3cbe > --- /dev/null > +++ b/sound/soc/intel/sst-dsp.h > @@ -0,0 +1,226 @@ > +/* > + * Intel Smart Sound Technology (SST) Core > + * > + * Copyright (C) 2013, Intel Corporation. All rights reserved. > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License version > + * 2 as published by the Free Software Foundation. > + * > + * 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. > + * > + */ > + > +#ifndef __SOUND_SOC_SST_DSP_H > +#define __SOUND_SOC_SST_DSP_H > + > +#include > +#include > +#include > + > +/* SST Device IDs */ > +#define SST_DEV_ID_LYNX_POINT 0x33C8 > +#define SST_DEV_ID_WILDCAT_POINT 0x3438 > + > +/* Supported SST DMA Devices */ > +#define SST_DMA_TYPE_DW 1 > +#define SST_DMA_TYPE_MID 2 > + > +/* SST Shim register map > + * The register naming can differ between products. Some products also > + * contain extra functionality. > + */ > +#define SST_CSR 0x00 > +#define SST_PISR 0x08 > +#define SST_PIMR 0x10 > +#define SST_ISRX 0x18 > +#define SST_ISRD 0x20 > +#define SST_IMRX 0x28 > +#define SST_IMRD 0x30 > +#define SST_IPCX 0x38 /* IPC IA -> SST */ > +#define SST_IPCD 0x40 /* IPC SST -> IA */ > +#define SST_ISRSC 0x48 > +#define SST_ISRLPESC 0x50 > +#define SST_IMRSC 0x58 > +#define SST_IMRLPESC 0x60 > +#define SST_IPCSC 0x68 > +#define SST_IPCLPESC 0x70 > +#define SST_CLKCTL 0x78 > +#define SST_CSR2 0x80 > +#define SST_LTRC 0xE0 > +#define SST_HDMC 0xE8 > +#define SST_DBGO 0xF0 > + > +#define SST_SHIM_SIZE 0x100 > +#define SST_PWMCTRL 0x1000 > + > +/* SST Shim Register bits > + * The register bit naming can differ between products. Some products also > + * contain extra functionality. > + */ > + > +/* CSR / CS */ > +#define SST_CSR_RST (0x1 << 1) > +#define SST_CSR_SBCS0 (0x1 << 2) > +#define SST_CSR_SBCS1 (0x1 << 3) > +#define SST_CSR_DCS(x) (x << 4) > +#define SST_CSR_DCS_MASK (0x7 << 4) > +#define SST_CSR_STALL (0x1 << 10) > +#define SST_CSR_S0IOCS (0x1 << 21) > +#define SST_CSR_S1IOCS (0x1 << 23) > +#define SST_CSR_LPCS (0x1 << 31) > + > +/* ISRX / ISC */ > +#define SST_ISRX_BUSY (0x1 << 1) > +#define SST_ISRX_DONE (0x1 << 0) > + > +/* ISRD / ISD */ > +#define SST_ISRD_BUSY (0x1 << 1) > +#define SST_ISRD_DONE (0x1 << 0) > + > +/* IMRX / IMC */ > +#define SST_IMRX_BUSY (0x1 << 1) > +#define SST_IMRX_DONE (0x1 << 0) > + > +/* IPCX / IPCC */ > +#define SST_IPCX_DONE (0x1 << 30) > +#define SST_IPCX_BUSY (0x1 << 31) > + > +/* IPCD */ > +#define SST_IPCD_DONE (0x1 << 30) > +#define SST_IPCD_BUSY (0x1 << 31) > + > +/* CLKCTL */ > +#define SST_CLKCTL_SMOS(x) (x << 24) > +#define SST_CLKCTL_MASK (3 << 24) > +#define SST_CLKCTL_DCPLCG (1 << 18) > +#define SST_CLKCTL_SCOE1 (1 << 17) > +#define SST_CLKCTL_SCOE0 (1 << 16) > + > +/* CSR2 / CS2 */ > +#define SST_CSR2_SDFD_SSP0 (1 << 1) > +#define SST_CSR2_SDFD_SSP1 (1 << 2) > + > +/* LTRC */ > +#define SST_LTRC_VAL(x) (x << 0) > + > +/* HDMC */ > +#define SST_HDMC_HDDA0(x) (x << 0) > +#define SST_HDMC_HDDA1(x) (x << 7) > + > + > +/* SST Vendor Defined Registers and bits */ > +#define SST_VDRTCTL0 0xa0 > +#define SST_VDRTCTL1 0xa4 > +#define SST_VDRTCTL2 0xa8 > +#define SST_VDRTCTL3 0xaC > + > +/* VDRTCTL0 */ > +#define SST_VDRTCL0_DSRAMPGE_SHIFT 16 > +#define SST_VDRTCL0_DSRAMPGE_MASK (0xffff << SST_VDRTCL0_DSRAMPGE_SHIFT) > +#define SST_VDRTCL0_ISRAMPGE_SHIFT 6 > +#define SST_VDRTCL0_ISRAMPGE_MASK (0x3ff << SST_VDRTCL0_ISRAMPGE_SHIFT) > + > +struct sst_dsp; > + > +/* > + * SST Device. > + * > + * This structure is populated by the SST core driver. > + */ > +struct sst_dsp_device { > + /* Mandatory fields */ > + struct sst_ops *ops; > + irqreturn_t (*thread)(int irq, void *context); > + void *thread_context; > +}; > + > +/* > + * SST Platform Data. > + */ > +struct sst_pdata { > + /* ACPI data */ > + u32 lpe_base; > + u32 lpe_size; > + u32 pcicfg_base; > + u32 pcicfg_size; > + int irq; > + > + /* Firmware */ > + const char *fw_filename; > + u32 fw_base; > + u32 fw_size; > + > + /* DMA */ > + u32 dma_base; > + u32 dma_size; > + int dma_engine; > + > + /* DSP */ > + u32 id; > + void *dsp; > +}; > + > +/* Initialization */ > +struct sst_dsp *sst_dsp_new(struct device *dev, > + struct sst_dsp_device *sst_dev, struct sst_pdata *pdata); > +void sst_dsp_free(struct sst_dsp *sst); > + > +/* SHIM Read / Write */ > +void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value); > +u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset); > +int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset, > + u32 mask, u32 value); > +void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value); > +u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset); > +int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset, > + u64 mask, u64 value); > + > +/* SHIM Read / Write Unlocked for callers already holding sst lock */ > +void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value); > +u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset); > +int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset, > + u32 mask, u32 value); > +void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value); > +u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset); > +int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset, > + u64 mask, u64 value); > + > +/* Size optimised DRAM/IRAM memcpy */ > +void sst_dsp_write(struct sst_dsp *sst, void *src, u32 dest_offset, > + size_t bytes); > +void sst_dsp_bzero(struct sst_dsp *sst, u32 src_offset, size_t bytes); > +void sst_dsp_read(struct sst_dsp *sst, void *dest, u32 src_offset, > + size_t bytes); > + > +/* DSP reset & boot */ > +void sst_dsp_reset(struct sst_dsp *sst); > +int sst_dsp_boot(struct sst_dsp *sst); > + > +/* Msg IO */ > +void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg); > +u32 sst_dsp_ipc_msg_rx(struct sst_dsp *dsp); > +void *sst_dsp_get_thread_context(struct sst_dsp *sst); > + > +/* Mailbox management */ > +int sst_dsp_mailbox_init(struct sst_dsp *dsp, u32 inbox_offset, > + size_t inbox_size, u32 outbox_offset, size_t outbox_size); > +void sst_dsp_inbox_write(struct sst_dsp *dsp, void *message, size_t bytes); > +void sst_dsp_inbox_read(struct sst_dsp *dsp, void *message, size_t bytes); > +void sst_dsp_outbox_write(struct sst_dsp *dsp, void *message, size_t bytes); > +void sst_dsp_outbox_read(struct sst_dsp *dsp, void *message, size_t bytes); > +void sst_dsp_mailbox_dump(struct sst_dsp *dsp, size_t bytes); > + > +/* DMA FW maangement */ > +int sst_dsp_dma_copy(struct sst_dsp *sst, dma_addr_t src_addr, > + dma_addr_t dstn_addr, size_t size); > +int sst_dsp_dma_get_channel(struct sst_dsp *dsp, int chan_id); > +void sst_dsp_dma_put_channel(struct sst_dsp *dsp); > + > +/* Debug */ > +void sst_dsp_dump(struct sst_dsp *sst); > + > +#endif > -- > 1.8.3.2 > > _______________________________________________ > Alsa-devel mailing list > Alsa-devel@alsa-project.org > http://mailman.alsa-project.org/mailman/listinfo/alsa-devel >