[alsa-devel] [PATCH 1/5] ASoC: Intel: Add Intel SST audio DSP low level shim driver.
Takashi Iwai
tiwai at suse.de
Fri Feb 14 09:29:35 CET 2014
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 <liam.r.girdwood at linux.intel.com>
> ---
> 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 <linux/kernel.h>
> +#include <linux/types.h>
> +#include <linux/interrupt.h>
> +#include <linux/firmware.h>
> +
> +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 <linux/slab.h>
> +#include <linux/export.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +
> +#include "sst-dsp.h"
> +#include "sst-dsp-priv.h"
> +
> +#define CREATE_TRACE_POINTS
> +#include <trace/events/sst.h>
> +
> +/* 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 <linux/kernel.h>
> +#include <linux/types.h>
> +#include <linux/interrupt.h>
> +
> +/* 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 at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>
More information about the Alsa-devel
mailing list