Commit 373e515d authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/intel', 'asoc/topic/kirkwood',...

Merge remote-tracking branches 'asoc/topic/intel', 'asoc/topic/kirkwood', 'asoc/topic/lm49453', 'asoc/topic/max9768' and 'asoc/topic/max98088' into asoc-next
......@@ -188,7 +188,6 @@ static struct reg_default lm49453_reg_defs[] = {
/* codec private data */
struct lm49453_priv {
struct regmap *regmap;
int fs_rate;
};
/* capture path controls */
......@@ -1112,13 +1111,10 @@ static int lm49453_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct lm49453_priv *lm49453 = snd_soc_codec_get_drvdata(codec);
u16 clk_div = 0;
lm49453->fs_rate = params_rate(params);
/* Setting DAC clock dividers based on substream sample rate. */
switch (lm49453->fs_rate) {
switch (params_rate(params)) {
case 8000:
case 16000:
case 32000:
......
......@@ -43,8 +43,8 @@ static struct reg_default max9768_default_regs[] = {
static int max9768_get_gpio(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
struct max9768 *max9768 = snd_soc_component_get_drvdata(c);
int val = gpio_get_value_cansleep(max9768->mute_gpio);
ucontrol->value.integer.value[0] = !val;
......@@ -55,8 +55,8 @@ static int max9768_get_gpio(struct snd_kcontrol *kcontrol,
static int max9768_set_gpio(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
struct max9768 *max9768 = snd_soc_component_get_drvdata(c);
gpio_set_value_cansleep(max9768->mute_gpio, !ucontrol->value.integer.value[0]);
......@@ -130,19 +130,20 @@ static const struct snd_soc_dapm_route max9768_dapm_routes[] = {
{ "OUT-", NULL, "IN" },
};
static int max9768_probe(struct snd_soc_codec *codec)
static int max9768_probe(struct snd_soc_component *component)
{
struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec);
struct max9768 *max9768 = snd_soc_component_get_drvdata(component);
int ret;
if (max9768->flags & MAX9768_FLAG_CLASSIC_PWM) {
ret = snd_soc_write(codec, MAX9768_CTRL, MAX9768_CTRL_PWM);
ret = regmap_write(max9768->regmap, MAX9768_CTRL,
MAX9768_CTRL_PWM);
if (ret)
return ret;
}
if (gpio_is_valid(max9768->mute_gpio)) {
ret = snd_soc_add_codec_controls(codec, max9768_mute,
ret = snd_soc_add_component_controls(component, max9768_mute,
ARRAY_SIZE(max9768_mute));
if (ret)
return ret;
......@@ -151,7 +152,7 @@ static int max9768_probe(struct snd_soc_codec *codec)
return 0;
}
static struct snd_soc_codec_driver max9768_codec_driver = {
static struct snd_soc_component_driver max9768_component_driver = {
.probe = max9768_probe,
.controls = max9768_volume,
.num_controls = ARRAY_SIZE(max9768_volume),
......@@ -183,11 +184,13 @@ static int max9768_i2c_probe(struct i2c_client *client,
if (pdata) {
/* Mute on powerup to avoid clicks */
err = gpio_request_one(pdata->mute_gpio, GPIOF_INIT_HIGH, "MAX9768 Mute");
err = devm_gpio_request_one(&client->dev, pdata->mute_gpio,
GPIOF_INIT_HIGH, "MAX9768 Mute");
max9768->mute_gpio = err ?: pdata->mute_gpio;
/* Activate chip by releasing shutdown, enables I2C */
err = gpio_request_one(pdata->shdn_gpio, GPIOF_INIT_HIGH, "MAX9768 Shutdown");
err = devm_gpio_request_one(&client->dev, pdata->shdn_gpio,
GPIOF_INIT_HIGH, "MAX9768 Shutdown");
max9768->shdn_gpio = err ?: pdata->shdn_gpio;
max9768->flags = pdata->flags;
......@@ -199,38 +202,11 @@ static int max9768_i2c_probe(struct i2c_client *client,
i2c_set_clientdata(client, max9768);
max9768->regmap = devm_regmap_init_i2c(client, &max9768_i2c_regmap_config);
if (IS_ERR(max9768->regmap)) {
err = PTR_ERR(max9768->regmap);
goto err_gpio_free;
}
err = snd_soc_register_codec(&client->dev, &max9768_codec_driver, NULL, 0);
if (err)
goto err_gpio_free;
return 0;
err_gpio_free:
if (gpio_is_valid(max9768->shdn_gpio))
gpio_free(max9768->shdn_gpio);
if (gpio_is_valid(max9768->mute_gpio))
gpio_free(max9768->mute_gpio);
return err;
}
static int max9768_i2c_remove(struct i2c_client *client)
{
struct max9768 *max9768 = i2c_get_clientdata(client);
if (IS_ERR(max9768->regmap))
return PTR_ERR(max9768->regmap);
snd_soc_unregister_codec(&client->dev);
if (gpio_is_valid(max9768->shdn_gpio))
gpio_free(max9768->shdn_gpio);
if (gpio_is_valid(max9768->mute_gpio))
gpio_free(max9768->mute_gpio);
return 0;
return devm_snd_soc_register_component(&client->dev,
&max9768_component_driver, NULL, 0);
}
static const struct i2c_device_id max9768_i2c_id[] = {
......@@ -244,7 +220,6 @@ static struct i2c_driver max9768_i2c_driver = {
.name = "max9768",
},
.probe = max9768_i2c_probe,
.remove = max9768_i2c_remove,
.id_table = max9768_i2c_id,
};
module_i2c_driver(max9768_i2c_driver);
......
This diff is collapsed.
......@@ -16,7 +16,7 @@
*/
#define M98088_REG_00_IRQ_STATUS 0x00
#define M98088_REG_01_MIC_STATUS 0x01
#define M98088_REG_02_JACK_STAUS 0x02
#define M98088_REG_02_JACK_STATUS 0x02
#define M98088_REG_03_BATTERY_VOLTAGE 0x03
#define M98088_REG_0F_IRQ_ENABLE 0x0F
#define M98088_REG_10_SYS_CLK 0x10
......
......@@ -26,14 +26,9 @@ config SND_SST_IPC_ACPI
depends on ACPI
config SND_SOC_INTEL_SST
tristate "ASoC support for Intel(R) Smart Sound Technology"
tristate
select SND_SOC_INTEL_SST_ACPI if ACPI
depends on (X86 || COMPILE_TEST)
depends on DW_DMAC_CORE
help
This adds support for Intel(R) Smart Sound Technology (SST).
Say Y if you have such a device
If unsure select "N".
config SND_SOC_INTEL_SST_ACPI
tristate
......@@ -46,8 +41,9 @@ config SND_SOC_INTEL_BAYTRAIL
config SND_SOC_INTEL_HASWELL_MACH
tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \
I2C_DESIGNWARE_PLATFORM
depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
depends on DW_DMAC_CORE
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_HASWELL
select SND_SOC_RT5640
help
......@@ -58,7 +54,9 @@ config SND_SOC_INTEL_HASWELL_MACH
config SND_SOC_INTEL_BYT_RT5640_MACH
tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C
depends on X86_INTEL_LPSS && I2C
depends on DW_DMAC_CORE
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_BAYTRAIL
select SND_SOC_RT5640
help
......@@ -67,7 +65,9 @@ config SND_SOC_INTEL_BYT_RT5640_MACH
config SND_SOC_INTEL_BYT_MAX98090_MACH
tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec"
depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C
depends on X86_INTEL_LPSS && I2C
depends on DW_DMAC_CORE
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_BAYTRAIL
select SND_SOC_MAX98090
help
......@@ -76,8 +76,10 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH
config SND_SOC_INTEL_BROADWELL_MACH
tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \
depends on X86_INTEL_LPSS && I2C && DW_DMAC && \
I2C_DESIGNWARE_PLATFORM
depends on DW_DMAC_CORE
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_HASWELL
select SND_SOC_RT286
help
......@@ -132,3 +134,8 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
platforms with MAX98090 audio codec it also can support TI jack chip as aux device.
If unsure select "N".
config SND_SOC_INTEL_SKYLAKE
tristate
select SND_HDA_EXT_CORE
select SND_SOC_INTEL_SST
......@@ -5,6 +5,7 @@ obj-$(CONFIG_SND_SOC_INTEL_SST) += common/
obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/
obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += baytrail/
obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += atom/
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += skylake/
# Machine support
obj-$(CONFIG_SND_SOC) += boards/
......@@ -132,7 +132,7 @@ static int sst_send_slot_map(struct sst_data *drv)
sizeof(cmd.header) + cmd.header.length);
}
int sst_slot_enum_info(struct snd_kcontrol *kcontrol,
static int sst_slot_enum_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct sst_enum *e = (struct sst_enum *)kcontrol->private_value;
......
......@@ -33,7 +33,6 @@
struct sst_device *sst;
static DEFINE_MUTEX(sst_lock);
extern struct snd_compr_ops sst_platform_compr_ops;
int sst_register_dsp(struct sst_device *dev)
{
......
......@@ -25,6 +25,7 @@
#include "sst-atom-controls.h"
extern struct sst_device *sst;
extern struct snd_compr_ops sst_platform_compr_ops;
#define SST_MONO 1
#define SST_STEREO 2
......
......@@ -151,6 +151,7 @@ static int sst_power_control(struct device *dev, bool state)
usage_count = GET_USAGE_COUNT(dev);
dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", usage_count);
if (ret < 0) {
pm_runtime_put_sync(dev);
dev_err(ctx->dev, "Runtime get failed with err: %d\n", ret);
return ret;
}
......@@ -204,8 +205,10 @@ static int sst_cdev_open(struct device *dev,
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
retval = pm_runtime_get_sync(ctx->dev);
if (retval < 0)
if (retval < 0) {
pm_runtime_put_sync(ctx->dev);
return retval;
}
str_id = sst_get_stream(ctx, str_params);
if (str_id > 0) {
......@@ -672,8 +675,10 @@ static int sst_send_byte_stream(struct device *dev,
if (NULL == bytes)
return -EINVAL;
ret_val = pm_runtime_get_sync(ctx->dev);
if (ret_val < 0)
if (ret_val < 0) {
pm_runtime_put_sync(ctx->dev);
return ret_val;
}
ret_val = sst_send_byte_stream_mrfld(ctx, bytes);
sst_pm_runtime_put(ctx);
......
......@@ -352,10 +352,9 @@ void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx,
* copy from mailbox
**/
if (msg_high.part.large) {
data = kzalloc(msg_low, GFP_KERNEL);
data = kmemdup((void *)msg->mailbox_data, msg_low, GFP_KERNEL);
if (!data)
return;
memcpy(data, (void *) msg->mailbox_data, msg_low);
/* Copy command id so that we can use to put sst to reset */
dsp_hdr = (struct ipc_dsp_hdr *)data;
cmd_id = dsp_hdr->cmd_id;
......
......@@ -22,6 +22,8 @@
#include <linux/interrupt.h>
#include <linux/firmware.h>
#include "../skylake/skl-sst-dsp.h"
struct sst_mem_block;
struct sst_module;
struct sst_fw;
......@@ -258,6 +260,8 @@ struct sst_mem_block {
*/
struct sst_dsp {
/* Shared for all platforms */
/* runtime */
struct sst_dsp_device *sst_dev;
spinlock_t spinlock; /* IPC locking */
......@@ -268,10 +272,6 @@ struct sst_dsp {
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;
......@@ -284,6 +284,12 @@ struct sst_dsp {
/* mailbox */
struct sst_mailbox mailbox;
/* HSW/Byt data */
/* list of free and used ADSP memory blocks */
struct list_head used_block_list;
struct list_head free_block_list;
/* SST FW files loaded and their modules */
struct list_head module_list;
struct list_head fw_list;
......@@ -299,6 +305,15 @@ struct sst_dsp {
/* DMA FW loading */
struct sst_dma *dma;
bool fw_use_dma;
/* SKL data */
/* To allocate CL dma buffers */
struct skl_dsp_loader_ops dsp_ops;
struct skl_dsp_fw_ops fw_ops;
int sst_state;
struct skl_cl_dev cl_dev;
u32 intr_status;
};
/* Size optimised DRAM/IRAM memcpy */
......
......@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/delay.h>
#include "sst-dsp.h"
#include "sst-dsp-priv.h"
......@@ -196,6 +197,22 @@ int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset,
}
EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64_unlocked);
/* This is for registers bits with attribute RWC */
void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp *sst, u32 offset,
u32 mask, u32 value)
{
unsigned int old, new;
u32 ret;
ret = sst_dsp_shim_read_unlocked(sst, offset);
old = ret;
new = (old & (~mask)) | (value & mask);
sst_dsp_shim_write_unlocked(sst, offset, new);
}
EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced_unlocked);
int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset,
u32 mask, u32 value)
{
......@@ -222,6 +239,60 @@ int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset,
}
EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64);
/* This is for registers bits with attribute RWC */
void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset,
u32 mask, u32 value)
{
unsigned long flags;
spin_lock_irqsave(&sst->spinlock, flags);
sst_dsp_shim_update_bits_forced_unlocked(sst, offset, mask, value);
spin_unlock_irqrestore(&sst->spinlock, flags);
}
EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced);
int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask,
u32 target, u32 timeout, char *operation)
{
int time, ret;
u32 reg;
bool done = false;
/*
* we will poll for couple of ms using mdelay, if not successful
* then go to longer sleep using usleep_range
*/
/* check if set state successful */
for (time = 0; time < 5; time++) {
if ((sst_dsp_shim_read_unlocked(ctx, offset) & mask) == target) {
done = true;
break;
}
mdelay(1);
}
if (done == false) {
/* sleeping in 10ms steps so adjust timeout value */
timeout /= 10;
for (time = 0; time < timeout; time++) {
if ((sst_dsp_shim_read_unlocked(ctx, offset) & mask) == target)
break;
usleep_range(5000, 10000);
}
}
reg = sst_dsp_shim_read_unlocked(ctx, offset);
dev_info(ctx->dev, "FW Poll Status: reg=%#x %s %s\n", reg, operation,
(time < timeout) ? "successful" : "timedout");
ret = time < timeout ? 0 : -ETIME;
return ret;
}
EXPORT_SYMBOL_GPL(sst_dsp_register_poll);
void sst_dsp_dump(struct sst_dsp *sst)
{
if (sst->ops->dump)
......
......@@ -230,6 +230,8 @@ 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);
void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset,
u32 mask, u32 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);
......@@ -240,6 +242,8 @@ 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);
void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp *sst, u32 offset,
u32 mask, u32 value);
/* Internal generic low-level SST IO functions - can be overidden */
void sst_shim32_write(void __iomem *addr, u32 offset, u32 value);
......@@ -278,6 +282,8 @@ 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);
int sst_dsp_register_poll(struct sst_dsp *dsp, u32 offset, u32 mask,
u32 expected_value, u32 timeout, char *operation);
/* Debug */
void sst_dsp_dump(struct sst_dsp *sst);
......
snd-soc-skl-objs := skl.o skl-pcm.o skl-nhlt.o skl-messages.o
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o
# Skylake IPC Support
snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o \
skl-sst.o
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o
This diff is collapsed.
/*
* skl-nhlt.c - Intel SKL Platform NHLT parsing
*
* Copyright (C) 2015 Intel Corp
* Author: Sanjiv Kumar <sanjiv.kumar@intel.com>
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
*/
#include "skl.h"
/* Unique identification for getting NHLT blobs */
static u8 OSC_UUID[16] = {0x6E, 0x88, 0x9F, 0xA6, 0xEB, 0x6C, 0x94, 0x45,
0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53};
#define DSDT_NHLT_PATH "\\_SB.PCI0.HDAS"
void __iomem *skl_nhlt_init(struct device *dev)
{
acpi_handle handle;
union acpi_object *obj;
struct nhlt_resource_desc *nhlt_ptr = NULL;
if (ACPI_FAILURE(acpi_get_handle(NULL, DSDT_NHLT_PATH, &handle))) {
dev_err(dev, "Requested NHLT device not found\n");
return NULL;
}
obj = acpi_evaluate_dsm(handle, OSC_UUID, 1, 1, NULL);
if (obj && obj->type == ACPI_TYPE_BUFFER) {
nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer;
return ioremap_cache(nhlt_ptr->min_addr, nhlt_ptr->length);
}
dev_err(dev, "device specific method to extract NHLT blob failed\n");
return NULL;
}
void skl_nhlt_free(void __iomem *addr)
{
iounmap(addr);
addr = NULL;
}
static struct nhlt_specific_cfg *skl_get_specific_cfg(
struct device *dev, struct nhlt_fmt *fmt,
u8 no_ch, u32 rate, u16 bps)
{
struct nhlt_specific_cfg *sp_config;
struct wav_fmt *wfmt;
struct nhlt_fmt_cfg *fmt_config = fmt->fmt_config;
int i;
dev_dbg(dev, "Format count =%d\n", fmt->fmt_count);
for (i = 0; i < fmt->fmt_count; i++) {
wfmt = &fmt_config->fmt_ext.fmt;
dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", wfmt->channels,
wfmt->bits_per_sample, wfmt->samples_per_sec);
if (wfmt->channels == no_ch && wfmt->samples_per_sec == rate &&
wfmt->bits_per_sample == bps) {
sp_config = &fmt_config->config;
return sp_config;
}
fmt_config = (struct nhlt_fmt_cfg *)(fmt_config->config.caps +
fmt_config->config.size);
}
return NULL;
}
static void dump_config(struct device *dev, u32 instance_id, u8 linktype,
u8 s_fmt, u8 num_channels, u32 s_rate, u8 dirn, u16 bps)
{
dev_dbg(dev, "Input configuration\n");
dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", num_channels, s_fmt, s_rate);
dev_dbg(dev, "vbus_id=%d link_type=%d\n", instance_id, linktype);
dev_dbg(dev, "bits_per_sample=%d\n", bps);
}
static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt,
u32 instance_id, u8 link_type, u8 dirn)
{
dev_dbg(dev, "vbus_id=%d link_type=%d dir=%d\n",
epnt->virtual_bus_id, epnt->linktype, epnt->direction);
if ((epnt->virtual_bus_id == instance_id) &&
(epnt->linktype == link_type) &&
(epnt->direction == dirn))
return true;
else
return false;
}
struct nhlt_specific_cfg
*skl_get_ep_blob(struct skl *skl, u32 instance, u8 link_type,
u8 s_fmt, u8 num_ch, u32 s_rate, u8 dirn)
{
struct nhlt_fmt *fmt;
struct nhlt_endpoint *epnt;
struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
struct device *dev = bus->dev;
struct nhlt_specific_cfg *sp_config;
struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
u16 bps = num_ch * s_fmt;
u8 j;
dump_config(dev, instance, link_type, s_fmt, num_ch, s_rate, dirn, bps);
epnt = (struct nhlt_endpoint *)nhlt->desc;
dev_dbg(dev, "endpoint count =%d\n", nhlt->endpoint_count);
for (j = 0; j < nhlt->endpoint_count; j++) {
if (skl_check_ep_match(dev, epnt, instance, link_type, dirn)) {
fmt = (struct nhlt_fmt *)(epnt->config.caps +
epnt->config.size);
sp_config = skl_get_specific_cfg(dev, fmt, num_ch, s_rate, bps);
if (sp_config)
return sp_config;
}
epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
}
return NULL;
}
/*
* skl-nhlt.h - Intel HDA Platform NHLT header
*
* Copyright (C) 2015 Intel Corp
* Author: Sanjiv Kumar <sanjiv.kumar@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.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
*/
#ifndef __SKL_NHLT_H__
#define __SKL_NHLT_H__
#include <linux/acpi.h>
struct wav_fmt {
u16 fmt_tag;
u16 channels;
u32 samples_per_sec;
u32 avg_bytes_per_sec;
u16 block_align;
u16 bits_per_sample;
u16 cb_size;
} __packed;
struct wav_fmt_ext {
struct wav_fmt fmt;
union samples {
u16 valid_bits_per_sample;
u16 samples_per_block;
u16 reserved;
} sample;
u32 channel_mask;
u8 sub_fmt[16];
} __packed;
enum nhlt_link_type {
NHLT_LINK_HDA = 0,
NHLT_LINK_DSP = 1,
NHLT_LINK_DMIC = 2,
NHLT_LINK_SSP = 3,
NHLT_LINK_INVALID
};
enum nhlt_device_type {
NHLT_DEVICE_BT = 0,
NHLT_DEVICE_DMIC = 1,
NHLT_DEVICE_I2S = 4,
NHLT_DEVICE_INVALID
};
struct nhlt_specific_cfg {
u32 size;
u8 caps[0];
} __packed;
struct nhlt_fmt_cfg {
struct wav_fmt_ext fmt_ext;
struct nhlt_specific_cfg config;
} __packed;
struct nhlt_fmt {
u8 fmt_count;
struct nhlt_fmt_cfg fmt_config[0];
} __packed;
struct nhlt_endpoint {
u32 length;
u8 linktype;
u8 instance_id;
u16 vendor_id;
u16 device_id;
u16 revision_id;
u32 subsystem_id;
u8 device_type;
u8 direction;
u8 virtual_bus_id;
struct nhlt_specific_cfg config;
} __packed;
struct nhlt_acpi_table {
struct acpi_table_header header;
u8 endpoint_count;
struct nhlt_endpoint desc[0];
} __packed;
struct nhlt_resource_desc {
u32 extra;
u16 flags;
u64 addr_spc_gra;
u64 min_addr;
u64 max_addr;
u64 addr_trans_offset;
u64 length;
} __packed;
#endif
This diff is collapsed.
/*
* skl-sst-cldma.c - Code Loader DMA handler
*
* Copyright (C) 2015, Intel Corporation.
* Author: Subhransu S. Prusty <subhransu.s.prusty@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 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/device.h>
#include <linux/mm.h>
#include <linux/kthread.h>
#include "../common/sst-dsp.h"
#include "../common/sst-dsp-priv.h"
static void skl_cldma_int_enable(struct sst_dsp *ctx)
{
sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPIC,
SKL_ADSPIC_CL_DMA, SKL_ADSPIC_CL_DMA);
}
void skl_cldma_int_disable(struct sst_dsp *ctx)
{
sst_dsp_shim_update_bits_unlocked(ctx,
SKL_ADSP_REG_ADSPIC, SKL_ADSPIC_CL_DMA, 0);
}
/* Code loader helper APIs */
static void skl_cldma_setup_bdle(struct sst_dsp *ctx,
struct snd_dma_buffer *dmab_data,
u32 **bdlp, int size, int with_ioc)
{
u32 *bdl = *bdlp;
ctx->cl_dev.frags = 0;
while (size > 0) {
phys_addr_t addr = virt_to_phys(dmab_data->area +
(ctx->cl_dev.frags * ctx->cl_dev.bufsize));
bdl[0] = cpu_to_le32(lower_32_bits(addr));
bdl[1] = cpu_to_le32(upper_32_bits(addr));
bdl[2] = cpu_to_le32(ctx->cl_dev.bufsize);
size -= ctx->cl_dev.bufsize;
bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01);
bdl += 4;
ctx->cl_dev.frags++;
}
}
/*
* Setup controller
* Configure the registers to update the dma buffer address and
* enable interrupts.
* Note: Using the channel 1 for transfer
*/
static void skl_cldma_setup_controller(struct sst_dsp *ctx,
struct snd_dma_buffer *dmab_bdl, unsigned int max_size,
u32 count)
{
sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL,
CL_SD_BDLPLBA(dmab_bdl->addr));
sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU,
CL_SD_BDLPUBA(dmab_bdl->addr));
sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, max_size);
sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, count - 1);
sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(1));
sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(1));
sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(1));
sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(FW_CL_STREAM_NUMBER));
}
static void skl_cldma_setup_spb(struct sst_dsp *ctx,
unsigned int size, bool enable)
{
if (enable)
sst_dsp_shim_update_bits_unlocked(ctx,
SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL,
CL_SPBFIFO_SPBFCCTL_SPIBE_MASK,
CL_SPBFIFO_SPBFCCTL_SPIBE(1));
sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, size);
}
static void skl_cldma_cleanup_spb(struct sst_dsp *ctx)
{
sst_dsp_shim_update_bits_unlocked(ctx,
SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL,
CL_SPBFIFO_SPBFCCTL_SPIBE_MASK,
CL_SPBFIFO_SPBFCCTL_SPIBE(0));
sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, 0);
}
static void skl_cldma_trigger(struct sst_dsp *ctx, bool enable)
{
if (enable)
sst_dsp_shim_update_bits_unlocked(ctx,
SKL_ADSP_REG_CL_SD_CTL,
CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(1));
else
sst_dsp_shim_update_bits_unlocked(ctx,
SKL_ADSP_REG_CL_SD_CTL,
CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(0));
}
static void skl_cldma_cleanup(struct sst_dsp *ctx)
{
skl_cldma_cleanup_spb(ctx);
sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(0));
sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(0));
sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(0));
sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL,
CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(0));
sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, CL_SD_BDLPLBA(0));
sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, 0);
sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0);
sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0);
}
static int skl_cldma_wait_interruptible(struct sst_dsp *ctx)
{
int ret = 0;
if (!wait_event_timeout(ctx->cl_dev.wait_queue,
ctx->cl_dev.wait_condition,
msecs_to_jiffies(SKL_WAIT_TIMEOUT))) {
dev_err(ctx->dev, "%s: Wait timeout\n", __func__);
ret = -EIO;
goto cleanup;
}
dev_dbg(ctx->dev, "%s: Event wake\n", __func__);
if (ctx->cl_dev.wake_status != SKL_CL_DMA_BUF_COMPLETE) {
dev_err(ctx->dev, "%s: DMA Error\n", __func__);
ret = -EIO;
}
cleanup:
ctx->cl_dev.wake_status = SKL_CL_DMA_STATUS_NONE;
return ret;
}
static void skl_cldma_stop(struct sst_dsp *ctx)
{
ctx->cl_dev.ops.cl_trigger(ctx, false);
}
static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size,
const void *curr_pos, bool intr_enable, bool trigger)
{
dev_dbg(ctx->dev, "Size: %x, intr_enable: %d\n", size, intr_enable);
dev_dbg(ctx->dev, "buf_pos_index:%d, trigger:%d\n",
ctx->cl_dev.dma_buffer_offset, trigger);
dev_dbg(ctx->dev, "spib position: %d\n", ctx->cl_dev.curr_spib_pos);
memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset,
curr_pos, size);
if (ctx->cl_dev.curr_spib_pos == ctx->cl_dev.bufsize)
ctx->cl_dev.dma_buffer_offset = 0;
else
ctx->cl_dev.dma_buffer_offset = ctx->cl_dev.curr_spib_pos;
ctx->cl_dev.wait_condition = false;
if (intr_enable)
skl_cldma_int_enable(ctx);
ctx->cl_dev.ops.cl_setup_spb(ctx, ctx->cl_dev.curr_spib_pos, trigger);
if (trigger)
ctx->cl_dev.ops.cl_trigger(ctx, true);
}
/*
* The CL dma doesn't have any way to update the transfer status until a BDL
* buffer is fully transferred
*
* So Copying is divided in two parts.
* 1. Interrupt on buffer done where the size to be transferred is more than
* ring buffer size.
* 2. Polling on fw register to identify if data left to transferred doesn't
* fill the ring buffer. Caller takes care of polling the required status
* register to identify the transfer status.
*/
static int
skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, u32 total_size)
{
int ret = 0;
bool start = true;
unsigned int excess_bytes;
u32 size;
unsigned int bytes_left = total_size;
const void *curr_pos = bin;
if (total_size <= 0)
return -EINVAL;
dev_dbg(ctx->dev, "%s: Total binary size: %u\n", __func__, bytes_left);
while (bytes_left) {
if (bytes_left > ctx->cl_dev.bufsize) {
/*
* dma transfers only till the write pointer as
* updated in spib
*/
if (ctx->cl_dev.curr_spib_pos == 0)
ctx->cl_dev.curr_spib_pos = ctx->cl_dev.bufsize;
size = ctx->cl_dev.bufsize;
skl_cldma_fill_buffer(ctx, size, curr_pos, true, start);
start = false;
ret = skl_cldma_wait_interruptible(ctx);
if (ret < 0) {
skl_cldma_stop(ctx);
return ret;
}
} else {
skl_cldma_int_disable(ctx);
if ((ctx->cl_dev.curr_spib_pos + bytes_left)
<= ctx->cl_dev.bufsize) {
ctx->cl_dev.curr_spib_pos += bytes_left;
} else {
excess_bytes = bytes_left -
(ctx->cl_dev.bufsize -
ctx->cl_dev.curr_spib_pos);
ctx->cl_dev.curr_spib_pos = excess_bytes;
}
size = bytes_left;
skl_cldma_fill_buffer(ctx, size,
curr_pos, false, start);
}
bytes_left -= size;
curr_pos = curr_pos + size;
}
return ret;
}
void skl_cldma_process_intr(struct sst_dsp *ctx)
{
u8 cl_dma_intr_status;
cl_dma_intr_status =
sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_CL_SD_STS);
if (!(cl_dma_intr_status & SKL_CL_DMA_SD_INT_COMPLETE))
ctx->cl_dev.wake_status = SKL_CL_DMA_ERR;
else
ctx->cl_dev.wake_status = SKL_CL_DMA_BUF_COMPLETE;
ctx->cl_dev.wait_condition = true;
wake_up(&ctx->cl_dev.wait_queue);
}
int skl_cldma_prepare(struct sst_dsp *ctx)
{
int ret;
u32 *bdl;
ctx->cl_dev.bufsize = SKL_MAX_BUFFER_SIZE;
/* Allocate cl ops */
ctx->cl_dev.ops.cl_setup_bdle = skl_cldma_setup_bdle;
ctx->cl_dev.ops.cl_setup_controller = skl_cldma_setup_controller;
ctx->cl_dev.ops.cl_setup_spb = skl_cldma_setup_spb;
ctx->cl_dev.ops.cl_cleanup_spb = skl_cldma_cleanup_spb;
ctx->cl_dev.ops.cl_trigger = skl_cldma_trigger;
ctx->cl_dev.ops.cl_cleanup_controller = skl_cldma_cleanup;
ctx->cl_dev.ops.cl_copy_to_dmabuf = skl_cldma_copy_to_buf;
ctx->cl_dev.ops.cl_stop_dma = skl_cldma_stop;
/* Allocate buffer*/
ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev,
&ctx->cl_dev.dmab_data, ctx->cl_dev.bufsize);
if (ret < 0) {
dev_err(ctx->dev, "Alloc buffer for base fw failed: %x", ret);
return ret;
}
/* Setup Code loader BDL */
ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev,
&ctx->cl_dev.dmab_bdl, PAGE_SIZE);
if (ret < 0) {
dev_err(ctx->dev, "Alloc buffer for blde failed: %x", ret);
ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data);
return ret;
}
bdl = (u32 *)ctx->cl_dev.dmab_bdl.area;
/* Allocate BDLs */
ctx->cl_dev.ops.cl_setup_bdle(ctx, &ctx->cl_dev.dmab_data,
&bdl, ctx->cl_dev.bufsize, 1);
ctx->cl_dev.ops.cl_setup_controller(ctx, &ctx->cl_dev.dmab_bdl,
ctx->cl_dev.bufsize, ctx->cl_dev.frags);
ctx->cl_dev.curr_spib_pos = 0;
ctx->cl_dev.dma_buffer_offset = 0;
init_waitqueue_head(&ctx->cl_dev.wait_queue);
return ret;
}
/*
* Intel Code Loader DMA support
*
* Copyright (C) 2015, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as 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 SKL_SST_CLDMA_H_
#define SKL_SST_CLDMA_H_
#define FW_CL_STREAM_NUMBER 0x1
#define DMA_ADDRESS_128_BITS_ALIGNMENT 7
#define BDL_ALIGN(x) (x >> DMA_ADDRESS_128_BITS_ALIGNMENT)
#define SKL_ADSPIC_CL_DMA 0x2
#define SKL_ADSPIS_CL_DMA 0x2
#define SKL_CL_DMA_SD_INT_DESC_ERR 0x10 /* Descriptor error interrupt */
#define SKL_CL_DMA_SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */
#define SKL_CL_DMA_SD_INT_COMPLETE 0x04 /* Buffer completion interrupt */
/* Intel HD Audio Code Loader DMA Registers */
#define HDA_ADSP_LOADER_BASE 0x80
/* Stream Registers */
#define SKL_ADSP_REG_CL_SD_CTL (HDA_ADSP_LOADER_BASE + 0x00)
#define SKL_ADSP_REG_CL_SD_STS (HDA_ADSP_LOADER_BASE + 0x03)
#define SKL_ADSP_REG_CL_SD_LPIB (HDA_ADSP_LOADER_BASE + 0x04)
#define SKL_ADSP_REG_CL_SD_CBL (HDA_ADSP_LOADER_BASE + 0x08)
#define SKL_ADSP_REG_CL_SD_LVI (HDA_ADSP_LOADER_BASE + 0x0c)
#define SKL_ADSP_REG_CL_SD_FIFOW (HDA_ADSP_LOADER_BASE + 0x0e)
#define SKL_ADSP_REG_CL_SD_FIFOSIZE (HDA_ADSP_LOADER_BASE + 0x10)
#define SKL_ADSP_REG_CL_SD_FORMAT (HDA_ADSP_LOADER_BASE + 0x12)
#define SKL_ADSP_REG_CL_SD_FIFOL (HDA_ADSP_LOADER_BASE + 0x14)
#define SKL_ADSP_REG_CL_SD_BDLPL (HDA_ADSP_LOADER_BASE + 0x18)
#define SKL_ADSP_REG_CL_SD_BDLPU (HDA_ADSP_LOADER_BASE + 0x1c)
/* CL: Software Position Based FIFO Capability Registers */
#define SKL_ADSP_REG_CL_SPBFIFO (HDA_ADSP_LOADER_BASE + 0x20)
#define SKL_ADSP_REG_CL_SPBFIFO_SPBFCH (SKL_ADSP_REG_CL_SPBFIFO + 0x0)
#define SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL (SKL_ADSP_REG_CL_SPBFIFO + 0x4)
#define SKL_ADSP_REG_CL_SPBFIFO_SPIB (SKL_ADSP_REG_CL_SPBFIFO + 0x8)
#define SKL_ADSP_REG_CL_SPBFIFO_MAXFIFOS (SKL_ADSP_REG_CL_SPBFIFO + 0xc)
/* CL: Stream Descriptor x Control */
/* Stream Reset */
#define CL_SD_CTL_SRST_SHIFT 0
#define CL_SD_CTL_SRST_MASK (1 << CL_SD_CTL_SRST_SHIFT)
#define CL_SD_CTL_SRST(x) \
((x << CL_SD_CTL_SRST_SHIFT) & CL_SD_CTL_SRST_MASK)
/* Stream Run */
#define CL_SD_CTL_RUN_SHIFT 1
#define CL_SD_CTL_RUN_MASK (1 << CL_SD_CTL_RUN_SHIFT)
#define CL_SD_CTL_RUN(x) \
((x << CL_SD_CTL_RUN_SHIFT) & CL_SD_CTL_RUN_MASK)
/* Interrupt On Completion Enable */
#define CL_SD_CTL_IOCE_SHIFT 2
#define CL_SD_CTL_IOCE_MASK (1 << CL_SD_CTL_IOCE_SHIFT)
#define CL_SD_CTL_IOCE(x) \
((x << CL_SD_CTL_IOCE_SHIFT) & CL_SD_CTL_IOCE_MASK)
/* FIFO Error Interrupt Enable */
#define CL_SD_CTL_FEIE_SHIFT 3
#define CL_SD_CTL_FEIE_MASK (1 << CL_SD_CTL_FEIE_SHIFT)
#define CL_SD_CTL_FEIE(x) \
((x << CL_SD_CTL_FEIE_SHIFT) & CL_SD_CTL_FEIE_MASK)
/* Descriptor Error Interrupt Enable */
#define CL_SD_CTL_DEIE_SHIFT 4
#define CL_SD_CTL_DEIE_MASK (1 << CL_SD_CTL_DEIE_SHIFT)
#define CL_SD_CTL_DEIE(x) \
((x << CL_SD_CTL_DEIE_SHIFT) & CL_SD_CTL_DEIE_MASK)
/* FIFO Limit Change */
#define CL_SD_CTL_FIFOLC_SHIFT 5
#define CL_SD_CTL_FIFOLC_MASK (1 << CL_SD_CTL_FIFOLC_SHIFT)
#define CL_SD_CTL_FIFOLC(x) \
((x << CL_SD_CTL_FIFOLC_SHIFT) & CL_SD_CTL_FIFOLC_MASK)
/* Stripe Control */
#define CL_SD_CTL_STRIPE_SHIFT 16
#define CL_SD_CTL_STRIPE_MASK (0x3 << CL_SD_CTL_STRIPE_SHIFT)
#define CL_SD_CTL_STRIPE(x) \
((x << CL_SD_CTL_STRIPE_SHIFT) & CL_SD_CTL_STRIPE_MASK)
/* Traffic Priority */
#define CL_SD_CTL_TP_SHIFT 18
#define CL_SD_CTL_TP_MASK (1 << CL_SD_CTL_TP_SHIFT)
#define CL_SD_CTL_TP(x) \
((x << CL_SD_CTL_TP_SHIFT) & CL_SD_CTL_TP_MASK)
/* Bidirectional Direction Control */
#define CL_SD_CTL_DIR_SHIFT 19
#define CL_SD_CTL_DIR_MASK (1 << CL_SD_CTL_DIR_SHIFT)
#define CL_SD_CTL_DIR(x) \
((x << CL_SD_CTL_DIR_SHIFT) & CL_SD_CTL_DIR_MASK)
/* Stream Number */
#define CL_SD_CTL_STRM_SHIFT 20
#define CL_SD_CTL_STRM_MASK (0xf << CL_SD_CTL_STRM_SHIFT)
#define CL_SD_CTL_STRM(x) \
((x << CL_SD_CTL_STRM_SHIFT) & CL_SD_CTL_STRM_MASK)
/* CL: Stream Descriptor x Status */
/* Buffer Completion Interrupt Status */
#define CL_SD_STS_BCIS(x) CL_SD_CTL_IOCE(x)
/* FIFO Error */
#define CL_SD_STS_FIFOE(x) CL_SD_CTL_FEIE(x)
/* Descriptor Error */
#define CL_SD_STS_DESE(x) CL_SD_CTL_DEIE(x)
/* FIFO Ready */
#define CL_SD_STS_FIFORDY(x) CL_SD_CTL_FIFOLC(x)
/* CL: Stream Descriptor x Last Valid Index */
#define CL_SD_LVI_SHIFT 0
#define CL_SD_LVI_MASK (0xff << CL_SD_LVI_SHIFT)
#define CL_SD_LVI(x) ((x << CL_SD_LVI_SHIFT) & CL_SD_LVI_MASK)
/* CL: Stream Descriptor x FIFO Eviction Watermark */
#define CL_SD_FIFOW_SHIFT 0
#define CL_SD_FIFOW_MASK (0x7 << CL_SD_FIFOW_SHIFT)
#define CL_SD_FIFOW(x) \
((x << CL_SD_FIFOW_SHIFT) & CL_SD_FIFOW_MASK)
/* CL: Stream Descriptor x Buffer Descriptor List Pointer Lower Base Address */
/* Protect Bits */
#define CL_SD_BDLPLBA_PROT_SHIFT 0
#define CL_SD_BDLPLBA_PROT_MASK (1 << CL_SD_BDLPLBA_PROT_SHIFT)
#define CL_SD_BDLPLBA_PROT(x) \
((x << CL_SD_BDLPLBA_PROT_SHIFT) & CL_SD_BDLPLBA_PROT_MASK)
/* Buffer Descriptor List Lower Base Address */
#define CL_SD_BDLPLBA_SHIFT 7
#define CL_SD_BDLPLBA_MASK (0x1ffffff << CL_SD_BDLPLBA_SHIFT)
#define CL_SD_BDLPLBA(x) \
((BDL_ALIGN(lower_32_bits(x)) << CL_SD_BDLPLBA_SHIFT) & CL_SD_BDLPLBA_MASK)
/* Buffer Descriptor List Upper Base Address */
#define CL_SD_BDLPUBA_SHIFT 0
#define CL_SD_BDLPUBA_MASK (0xffffffff << CL_SD_BDLPUBA_SHIFT)
#define CL_SD_BDLPUBA(x) \
((upper_32_bits(x) << CL_SD_BDLPUBA_SHIFT) & CL_SD_BDLPUBA_MASK)
/*
* Code Loader - Software Position Based FIFO
* Capability Registers x Software Position Based FIFO Header
*/
/* Next Capability Pointer */
#define CL_SPBFIFO_SPBFCH_PTR_SHIFT 0
#define CL_SPBFIFO_SPBFCH_PTR_MASK (0xff << CL_SPBFIFO_SPBFCH_PTR_SHIFT)
#define CL_SPBFIFO_SPBFCH_PTR(x) \
((x << CL_SPBFIFO_SPBFCH_PTR_SHIFT) & CL_SPBFIFO_SPBFCH_PTR_MASK)
/* Capability Identifier */
#define CL_SPBFIFO_SPBFCH_ID_SHIFT 16
#define CL_SPBFIFO_SPBFCH_ID_MASK (0xfff << CL_SPBFIFO_SPBFCH_ID_SHIFT)
#define CL_SPBFIFO_SPBFCH_ID(x) \
((x << CL_SPBFIFO_SPBFCH_ID_SHIFT) & CL_SPBFIFO_SPBFCH_ID_MASK)
/* Capability Version */
#define CL_SPBFIFO_SPBFCH_VER_SHIFT 28
#define CL_SPBFIFO_SPBFCH_VER_MASK (0xf << CL_SPBFIFO_SPBFCH_VER_SHIFT)
#define CL_SPBFIFO_SPBFCH_VER(x) \
((x << CL_SPBFIFO_SPBFCH_VER_SHIFT) & CL_SPBFIFO_SPBFCH_VER_MASK)
/* Software Position in Buffer Enable */
#define CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT 0
#define CL_SPBFIFO_SPBFCCTL_SPIBE_MASK (1 << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT)
#define CL_SPBFIFO_SPBFCCTL_SPIBE(x) \
((x << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) & CL_SPBFIFO_SPBFCCTL_SPIBE_MASK)
/* SST IPC SKL defines */
#define SKL_WAIT_TIMEOUT 500 /* 500 msec */
#define SKL_MAX_BUFFER_SIZE (32 * PAGE_SIZE)
enum skl_cl_dma_wake_states {
SKL_CL_DMA_STATUS_NONE = 0,
SKL_CL_DMA_BUF_COMPLETE,
SKL_CL_DMA_ERR, /* TODO: Expand the error states */
};
struct sst_dsp;
struct skl_cl_dev_ops {
void (*cl_setup_bdle)(struct sst_dsp *ctx,
struct snd_dma_buffer *dmab_data,
u32 **bdlp, int size, int with_ioc);
void (*cl_setup_controller)(struct sst_dsp *ctx,
struct snd_dma_buffer *dmab_bdl,
unsigned int max_size, u32 page_count);
void (*cl_setup_spb)(struct sst_dsp *ctx,
unsigned int size, bool enable);
void (*cl_cleanup_spb)(struct sst_dsp *ctx);
void (*cl_trigger)(struct sst_dsp *ctx, bool enable);
void (*cl_cleanup_controller)(struct sst_dsp *ctx);
int (*cl_copy_to_dmabuf)(struct sst_dsp *ctx,
const void *bin, u32 size);
void (*cl_stop_dma)(struct sst_dsp *ctx);
};
/**
* skl_cl_dev - holds information for code loader dma transfer
*
* @dmab_data: buffer pointer
* @dmab_bdl: buffer descriptor list
* @bufsize: ring buffer size
* @frags: Last valid buffer descriptor index in the BDL
* @curr_spib_pos: Current position in ring buffer
* @dma_buffer_offset: dma buffer offset
* @ops: operations supported on CL dma
* @wait_queue: wait queue to wake for wake event
* @wake_status: DMA wake status
* @wait_condition: condition to wait on wait queue
* @cl_dma_lock: for synchronized access to cldma
*/
struct skl_cl_dev {
struct snd_dma_buffer dmab_data;
struct snd_dma_buffer dmab_bdl;
unsigned int bufsize;
unsigned int frags;
unsigned int curr_spib_pos;
unsigned int dma_buffer_offset;
struct skl_cl_dev_ops ops;
wait_queue_head_t wait_queue;
int wake_status;
bool wait_condition;
};
#endif /* SKL_SST_CLDMA_H_ */
/*
* skl-sst-dsp.c - SKL SST library generic function
*
* Copyright (C) 2014-15, Intel Corporation.
* Author:Rafal Redzimski <rafal.f.redzimski@intel.com>
* Jeeja KP <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 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 <sound/pcm.h>
#include "../common/sst-dsp.h"
#include "../common/sst-ipc.h"
#include "../common/sst-dsp-priv.h"
#include "skl-sst-ipc.h"
/* various timeout values */
#define SKL_DSP_PU_TO 50
#define SKL_DSP_PD_TO 50
#define SKL_DSP_RESET_TO 50
void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state)
{
mutex_lock(&ctx->mutex);
ctx->sst_state = state;
mutex_unlock(&ctx->mutex);
}
static int skl_dsp_core_set_reset_state(struct sst_dsp *ctx)
{
int ret;
/* update bits */
sst_dsp_shim_update_bits_unlocked(ctx,
SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_CRST_MASK,
SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK));
/* poll with timeout to check if operation successful */
ret = sst_dsp_register_poll(ctx,
SKL_ADSP_REG_ADSPCS,
SKL_ADSPCS_CRST_MASK,
SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK),
SKL_DSP_RESET_TO,
"Set reset");
if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) !=
SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) {
dev_err(ctx->dev, "Set reset state failed\n");
ret = -EIO;
}
return ret;
}
static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx)
{
int ret;
dev_dbg(ctx->dev, "In %s\n", __func__);
/* update bits */
sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
SKL_ADSPCS_CRST_MASK, 0);
/* poll with timeout to check if operation successful */
ret = sst_dsp_register_poll(ctx,
SKL_ADSP_REG_ADSPCS,
SKL_ADSPCS_CRST_MASK,
0,
SKL_DSP_RESET_TO,
"Unset reset");
if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) != 0) {
dev_err(ctx->dev, "Unset reset state failed\n");
ret = -EIO;
}
return ret;
}
static bool is_skl_dsp_core_enable(struct sst_dsp *ctx)
{
int val;
bool is_enable;
val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS);
is_enable = ((val & SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) &&
(val & SKL_ADSPCS_SPA(SKL_DSP_CORES_MASK)) &&
!(val & SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) &&
!(val & SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK)));
dev_dbg(ctx->dev, "DSP core is enabled=%d\n", is_enable);
return is_enable;
}
static int skl_dsp_reset_core(struct sst_dsp *ctx)
{
/* stall core */
sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK));
/* set reset state */
return skl_dsp_core_set_reset_state(ctx);
}
static int skl_dsp_start_core(struct sst_dsp *ctx)
{
int ret;
/* unset reset state */
ret = skl_dsp_core_unset_reset_state(ctx);
if (ret < 0) {
dev_dbg(ctx->dev, "dsp unset reset fails\n");
return ret;
}
/* run core */
dev_dbg(ctx->dev, "run core...\n");
sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
~SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK));
if (!is_skl_dsp_core_enable(ctx)) {
skl_dsp_reset_core(ctx);
dev_err(ctx->dev, "DSP core enable failed\n");
ret = -EIO;
}
return ret;
}
static int skl_dsp_core_power_up(struct sst_dsp *ctx)
{
int ret;
/* update bits */
sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
SKL_ADSPCS_SPA_MASK, SKL_ADSPCS_SPA(SKL_DSP_CORES_MASK));
/* poll with timeout to check if operation successful */
ret = sst_dsp_register_poll(ctx,
SKL_ADSP_REG_ADSPCS,
SKL_ADSPCS_CPA_MASK,
SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK),
SKL_DSP_PU_TO,
"Power up");
if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) !=
SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) {
dev_err(ctx->dev, "DSP core power up failed\n");
ret = -EIO;
}
return ret;
}
static int skl_dsp_core_power_down(struct sst_dsp *ctx)
{
/* update bits */
sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
SKL_ADSPCS_SPA_MASK, 0);
/* poll with timeout to check if operation successful */
return sst_dsp_register_poll(ctx,
SKL_ADSP_REG_ADSPCS,
SKL_ADSPCS_SPA_MASK,
0,
SKL_DSP_PD_TO,
"Power down");
}
static int skl_dsp_enable_core(struct sst_dsp *ctx)
{
int ret;
/* power up */
ret = skl_dsp_core_power_up(ctx);
if (ret < 0) {
dev_dbg(ctx->dev, "dsp core power up failed\n");
return ret;
}
return skl_dsp_start_core(ctx);
}
int skl_dsp_disable_core(struct sst_dsp *ctx)
{
int ret;
ret = skl_dsp_reset_core(ctx);
if (ret < 0) {
dev_err(ctx->dev, "dsp core reset failed\n");
return ret;
}
/* power down core*/
ret = skl_dsp_core_power_down(ctx);
if (ret < 0) {
dev_err(ctx->dev, "dsp core power down failed\n");
return ret;
}
if (is_skl_dsp_core_enable(ctx)) {
dev_err(ctx->dev, "DSP core disable failed\n");
ret = -EIO;
}
return ret;
}
int skl_dsp_boot(struct sst_dsp *ctx)
{
int ret;
if (is_skl_dsp_core_enable(ctx)) {
dev_dbg(ctx->dev, "dsp core is already enabled, so reset the dap core\n");
ret = skl_dsp_reset_core(ctx);
if (ret < 0) {
dev_err(ctx->dev, "dsp reset failed\n");
return ret;
}
ret = skl_dsp_start_core(ctx);
if (ret < 0) {
dev_err(ctx->dev, "dsp start failed\n");
return ret;
}
} else {
dev_dbg(ctx->dev, "disable and enable to make sure DSP is invalid state\n");
ret = skl_dsp_disable_core(ctx);
if (ret < 0) {
dev_err(ctx->dev, "dsp disable core failes\n");
return ret;
}
ret = skl_dsp_enable_core(ctx);
}
return ret;
}
irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id)
{
struct sst_dsp *ctx = dev_id;
u32 val;
irqreturn_t result = IRQ_NONE;
spin_lock(&ctx->spinlock);
val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPIS);
ctx->intr_status = val;
if (val & SKL_ADSPIS_IPC) {
skl_ipc_int_disable(ctx);
result = IRQ_WAKE_THREAD;
}
if (val & SKL_ADSPIS_CL_DMA) {
skl_cldma_int_disable(ctx);
result = IRQ_WAKE_THREAD;
}
spin_unlock(&ctx->spinlock);
return result;
}
int skl_dsp_wake(struct sst_dsp *ctx)
{
return ctx->fw_ops.set_state_D0(ctx);
}
EXPORT_SYMBOL_GPL(skl_dsp_wake);
int skl_dsp_sleep(struct sst_dsp *ctx)
{
return ctx->fw_ops.set_state_D3(ctx);
}
EXPORT_SYMBOL_GPL(skl_dsp_sleep);
struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
struct sst_dsp_device *sst_dev, int irq)
{
int ret;
struct sst_dsp *sst;
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->sst_dev = sst_dev;
sst->irq = irq;
sst->ops = sst_dev->ops;
sst->thread_context = sst_dev->thread_context;
/* Initialise SST Audio DSP */
if (sst->ops->init) {
ret = sst->ops->init(sst, NULL);
if (ret < 0)
return NULL;
}
/* Register the ISR */
ret = request_threaded_irq(sst->irq, sst->ops->irq_handler,
sst_dev->thread, IRQF_SHARED, "AudioDSP", sst);
if (ret) {
dev_err(sst->dev, "unable to grab threaded IRQ %d, disabling device\n",
sst->irq);
return NULL;
}
return sst;
}
void skl_dsp_free(struct sst_dsp *dsp)
{
skl_ipc_int_disable(dsp);
free_irq(dsp->irq, dsp);
skl_dsp_disable_core(dsp);
}
EXPORT_SYMBOL_GPL(skl_dsp_free);
bool is_skl_dsp_running(struct sst_dsp *ctx)
{
return (ctx->sst_state == SKL_DSP_RUNNING);
}
EXPORT_SYMBOL_GPL(is_skl_dsp_running);
/*
* Skylake SST DSP Support
*
* Copyright (C) 2014-15, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as 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 __SKL_SST_DSP_H__
#define __SKL_SST_DSP_H__
#include <linux/interrupt.h>
#include <sound/memalloc.h>
#include "skl-sst-cldma.h"
struct sst_dsp;
struct skl_sst;
struct sst_dsp_device;
/* Intel HD Audio General DSP Registers */
#define SKL_ADSP_GEN_BASE 0x0
#define SKL_ADSP_REG_ADSPCS (SKL_ADSP_GEN_BASE + 0x04)
#define SKL_ADSP_REG_ADSPIC (SKL_ADSP_GEN_BASE + 0x08)
#define SKL_ADSP_REG_ADSPIS (SKL_ADSP_GEN_BASE + 0x0C)
#define SKL_ADSP_REG_ADSPIC2 (SKL_ADSP_GEN_BASE + 0x10)
#define SKL_ADSP_REG_ADSPIS2 (SKL_ADSP_GEN_BASE + 0x14)
/* Intel HD Audio Inter-Processor Communication Registers */
#define SKL_ADSP_IPC_BASE 0x40
#define SKL_ADSP_REG_HIPCT (SKL_ADSP_IPC_BASE + 0x00)
#define SKL_ADSP_REG_HIPCTE (SKL_ADSP_IPC_BASE + 0x04)
#define SKL_ADSP_REG_HIPCI (SKL_ADSP_IPC_BASE + 0x08)
#define SKL_ADSP_REG_HIPCIE (SKL_ADSP_IPC_BASE + 0x0C)
#define SKL_ADSP_REG_HIPCCTL (SKL_ADSP_IPC_BASE + 0x10)
/* HIPCI */
#define SKL_ADSP_REG_HIPCI_BUSY BIT(31)
/* HIPCIE */
#define SKL_ADSP_REG_HIPCIE_DONE BIT(30)
/* HIPCCTL */
#define SKL_ADSP_REG_HIPCCTL_DONE BIT(1)
#define SKL_ADSP_REG_HIPCCTL_BUSY BIT(0)
/* HIPCT */
#define SKL_ADSP_REG_HIPCT_BUSY BIT(31)
/* Intel HD Audio SRAM Window 1 */
#define SKL_ADSP_SRAM1_BASE 0xA000
#define SKL_ADSP_MMIO_LEN 0x10000
#define SKL_ADSP_W0_STAT_SZ 0x800
#define SKL_ADSP_W0_UP_SZ 0x800
#define SKL_ADSP_W1_SZ 0x1000
#define SKL_FW_STS_MASK 0xf
#define SKL_FW_INIT 0x1
#define SKL_FW_RFW_START 0xf
#define SKL_ADSPIC_IPC 1
#define SKL_ADSPIS_IPC 1
/* ADSPCS - Audio DSP Control & Status */
#define SKL_DSP_CORES 1
#define SKL_DSP_CORE0_MASK 1
#define SKL_DSP_CORES_MASK ((1 << SKL_DSP_CORES) - 1)
/* Core Reset - asserted high */
#define SKL_ADSPCS_CRST_SHIFT 0
#define SKL_ADSPCS_CRST_MASK (SKL_DSP_CORES_MASK << SKL_ADSPCS_CRST_SHIFT)
#define SKL_ADSPCS_CRST(x) ((x << SKL_ADSPCS_CRST_SHIFT) & SKL_ADSPCS_CRST_MASK)
/* Core run/stall - when set to '1' core is stalled */
#define SKL_ADSPCS_CSTALL_SHIFT 8
#define SKL_ADSPCS_CSTALL_MASK (SKL_DSP_CORES_MASK << \
SKL_ADSPCS_CSTALL_SHIFT)
#define SKL_ADSPCS_CSTALL(x) ((x << SKL_ADSPCS_CSTALL_SHIFT) & \
SKL_ADSPCS_CSTALL_MASK)
/* Set Power Active - when set to '1' turn cores on */
#define SKL_ADSPCS_SPA_SHIFT 16
#define SKL_ADSPCS_SPA_MASK (SKL_DSP_CORES_MASK << SKL_ADSPCS_SPA_SHIFT)
#define SKL_ADSPCS_SPA(x) ((x << SKL_ADSPCS_SPA_SHIFT) & SKL_ADSPCS_SPA_MASK)
/* Current Power Active - power status of cores, set by hardware */
#define SKL_ADSPCS_CPA_SHIFT 24
#define SKL_ADSPCS_CPA_MASK (SKL_DSP_CORES_MASK << SKL_ADSPCS_CPA_SHIFT)
#define SKL_ADSPCS_CPA(x) ((x << SKL_ADSPCS_CPA_SHIFT) & SKL_ADSPCS_CPA_MASK)
#define SST_DSP_POWER_D0 0x0 /* full On */
#define SST_DSP_POWER_D3 0x3 /* Off */
enum skl_dsp_states {
SKL_DSP_RUNNING = 1,
SKL_DSP_RESET,
};
struct skl_dsp_fw_ops {
int (*load_fw)(struct sst_dsp *ctx);
/* FW module parser/loader */
int (*parse_fw)(struct sst_dsp *ctx);
int (*set_state_D0)(struct sst_dsp *ctx);
int (*set_state_D3)(struct sst_dsp *ctx);
unsigned int (*get_fw_errcode)(struct sst_dsp *ctx);
};
struct skl_dsp_loader_ops {
int (*alloc_dma_buf)(struct device *dev,
struct snd_dma_buffer *dmab, size_t size);
int (*free_dma_buf)(struct device *dev,
struct snd_dma_buffer *dmab);
};
void skl_cldma_process_intr(struct sst_dsp *ctx);
void skl_cldma_int_disable(struct sst_dsp *ctx);
int skl_cldma_prepare(struct sst_dsp *ctx);
void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state);
struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
struct sst_dsp_device *sst_dev, int irq);
int skl_dsp_disable_core(struct sst_dsp *ctx);
bool is_skl_dsp_running(struct sst_dsp *ctx);
irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id);
int skl_dsp_wake(struct sst_dsp *ctx);
int skl_dsp_sleep(struct sst_dsp *ctx);
void skl_dsp_free(struct sst_dsp *dsp);
int skl_dsp_boot(struct sst_dsp *ctx);
int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp);
void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx);
#endif /*__SKL_SST_DSP_H__*/
This diff is collapsed.
/*
* Intel SKL IPC Support
*
* Copyright (C) 2014-15, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as 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 __SKL_IPC_H
#define __SKL_IPC_H
#include <linux/kthread.h>
#include <linux/irqreturn.h>
#include "../common/sst-ipc.h"
struct sst_dsp;
struct skl_sst;
struct sst_generic_ipc;
enum skl_ipc_pipeline_state {
PPL_INVALID_STATE = 0,
PPL_UNINITIALIZED = 1,
PPL_RESET = 2,
PPL_PAUSED = 3,
PPL_RUNNING = 4,
PPL_ERROR_STOP = 5,
PPL_SAVED = 6,
PPL_RESTORED = 7
};
struct skl_ipc_dxstate_info {
u32 core_mask;
u32 dx_mask;
};
struct skl_ipc_header {
u32 primary;
u32 extension;
};
struct skl_sst {
struct device *dev;
struct sst_dsp *dsp;
/* boot */
wait_queue_head_t boot_wait;
bool boot_complete;
/* IPC messaging */
struct sst_generic_ipc ipc;
};
struct skl_ipc_init_instance_msg {
u32 module_id;
u32 instance_id;
u16 param_data_size;
u8 ppl_instance_id;
u8 core_id;
};
struct skl_ipc_bind_unbind_msg {
u32 module_id;
u32 instance_id;
u32 dst_module_id;
u32 dst_instance_id;
u8 src_queue;
u8 dst_queue;
bool bind;
};
struct skl_ipc_large_config_msg {
u32 module_id;
u32 instance_id;
u32 large_param_id;
u32 param_data_size;
};
#define SKL_IPC_BOOT_MSECS 3000
#define SKL_IPC_D3_MASK 0
#define SKL_IPC_D0_MASK 3
irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context);
int skl_ipc_create_pipeline(struct sst_generic_ipc *sst_ipc,
u16 ppl_mem_size, u8 ppl_type, u8 instance_id);
int skl_ipc_delete_pipeline(struct sst_generic_ipc *sst_ipc, u8 instance_id);
int skl_ipc_set_pipeline_state(struct sst_generic_ipc *sst_ipc,
u8 instance_id, enum skl_ipc_pipeline_state state);
int skl_ipc_save_pipeline(struct sst_generic_ipc *ipc,
u8 instance_id, int dma_id);
int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id);
int skl_ipc_init_instance(struct sst_generic_ipc *sst_ipc,
struct skl_ipc_init_instance_msg *msg, void *param_data);
int skl_ipc_bind_unbind(struct sst_generic_ipc *sst_ipc,
struct skl_ipc_bind_unbind_msg *msg);
int skl_ipc_set_dx(struct sst_generic_ipc *ipc,
u8 instance_id, u16 module_id, struct skl_ipc_dxstate_info *dx);
int skl_ipc_set_large_config(struct sst_generic_ipc *ipc,
struct skl_ipc_large_config_msg *msg, u32 *param);
void skl_ipc_int_enable(struct sst_dsp *dsp);
void skl_ipc_op_int_enable(struct sst_dsp *ctx);
void skl_ipc_int_disable(struct sst_dsp *dsp);
bool skl_ipc_int_status(struct sst_dsp *dsp);
void skl_ipc_free(struct sst_generic_ipc *ipc);
int skl_ipc_init(struct device *dev, struct skl_sst *skl);
#endif /* __SKL_IPC_H */
This diff is collapsed.
This diff is collapsed.
/*
* skl-tplg-interface.h - Intel DSP FW private data interface
*
* Copyright (C) 2015 Intel Corp
* Author: Jeeja KP <jeeja.kp@intel.com>
* Nilofer, Samreen <samreen.nilofer@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 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 __HDA_TPLG_INTERFACE_H__
#define __HDA_TPLG_INTERFACE_H__
/**
* enum skl_ch_cfg - channel configuration
*
* @SKL_CH_CFG_MONO: One channel only
* @SKL_CH_CFG_STEREO: L & R
* @SKL_CH_CFG_2_1: L, R & LFE
* @SKL_CH_CFG_3_0: L, C & R
* @SKL_CH_CFG_3_1: L, C, R & LFE
* @SKL_CH_CFG_QUATRO: L, R, Ls & Rs
* @SKL_CH_CFG_4_0: L, C, R & Cs
* @SKL_CH_CFG_5_0: L, C, R, Ls & Rs
* @SKL_CH_CFG_5_1: L, C, R, Ls, Rs & LFE
* @SKL_CH_CFG_DUAL_MONO: One channel replicated in two
* @SKL_CH_CFG_I2S_DUAL_STEREO_0: Stereo(L,R) in 4 slots, 1st stream:[ L, R, -, - ]
* @SKL_CH_CFG_I2S_DUAL_STEREO_1: Stereo(L,R) in 4 slots, 2nd stream:[ -, -, L, R ]
* @SKL_CH_CFG_INVALID: Invalid
*/
enum skl_ch_cfg {
SKL_CH_CFG_MONO = 0,
SKL_CH_CFG_STEREO = 1,
SKL_CH_CFG_2_1 = 2,
SKL_CH_CFG_3_0 = 3,
SKL_CH_CFG_3_1 = 4,
SKL_CH_CFG_QUATRO = 5,
SKL_CH_CFG_4_0 = 6,
SKL_CH_CFG_5_0 = 7,
SKL_CH_CFG_5_1 = 8,
SKL_CH_CFG_DUAL_MONO = 9,
SKL_CH_CFG_I2S_DUAL_STEREO_0 = 10,
SKL_CH_CFG_I2S_DUAL_STEREO_1 = 11,
SKL_CH_CFG_INVALID
};
enum skl_module_type {
SKL_MODULE_TYPE_MIXER = 0,
SKL_MODULE_TYPE_COPIER,
SKL_MODULE_TYPE_UPDWMIX,
SKL_MODULE_TYPE_SRCINT
};
enum skl_core_affinity {
SKL_AFFINITY_CORE_0 = 0,
SKL_AFFINITY_CORE_1,
SKL_AFFINITY_CORE_MAX
};
enum skl_pipe_conn_type {
SKL_PIPE_CONN_TYPE_NONE = 0,
SKL_PIPE_CONN_TYPE_FE,
SKL_PIPE_CONN_TYPE_BE
};
enum skl_hw_conn_type {
SKL_CONN_NONE = 0,
SKL_CONN_SOURCE = 1,
SKL_CONN_SINK = 2
};
enum skl_dev_type {
SKL_DEVICE_BT = 0x0,
SKL_DEVICE_DMIC = 0x1,
SKL_DEVICE_I2S = 0x2,
SKL_DEVICE_SLIMBUS = 0x3,
SKL_DEVICE_HDALINK = 0x4,
SKL_DEVICE_NONE
};
#endif
This diff is collapsed.
/*
* skl.h - HD Audio skylake defintions.
*
* Copyright (C) 2015 Intel Corp
* Author: Jeeja KP <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.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
*/
#ifndef __SOUND_SOC_SKL_H
#define __SOUND_SOC_SKL_H
#include <sound/hda_register.h>
#include <sound/hdaudio_ext.h>
#include "skl-nhlt.h"
#define SKL_SUSPEND_DELAY 2000
/* Vendor Specific Registers */
#define AZX_REG_VS_EM1 0x1000
#define AZX_REG_VS_INRC 0x1004
#define AZX_REG_VS_OUTRC 0x1008
#define AZX_REG_VS_FIFOTRK 0x100C
#define AZX_REG_VS_FIFOTRK2 0x1010
#define AZX_REG_VS_EM2 0x1030
#define AZX_REG_VS_EM3L 0x1038
#define AZX_REG_VS_EM3U 0x103C
#define AZX_REG_VS_EM4L 0x1040
#define AZX_REG_VS_EM4U 0x1044
#define AZX_REG_VS_LTRC 0x1048
#define AZX_REG_VS_D0I3C 0x104A
#define AZX_REG_VS_PCE 0x104B
#define AZX_REG_VS_L2MAGC 0x1050
#define AZX_REG_VS_L2LAHPT 0x1054
#define AZX_REG_VS_SDXDPIB_XBASE 0x1084
#define AZX_REG_VS_SDXDPIB_XINTERVAL 0x20
#define AZX_REG_VS_SDXEFIFOS_XBASE 0x1094
#define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20
struct skl {
struct hdac_ext_bus ebus;
struct pci_dev *pci;
unsigned int init_failed:1; /* delayed init failed */
struct platform_device *dmic_dev;
void __iomem *nhlt; /* nhlt ptr */
struct skl_sst *skl_sst; /* sst skl ctx */
};
#define skl_to_ebus(s) (&(s)->ebus)
#define ebus_to_skl(sbus) \
container_of(sbus, struct skl, sbus)
/* to pass dai dma data */
struct skl_dma_params {
u32 format;
u8 stream_tag;
};
int skl_platform_unregister(struct device *dev);
int skl_platform_register(struct device *dev);
void __iomem *skl_nhlt_init(struct device *dev);
void skl_nhlt_free(void __iomem *addr);
struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance,
u8 link_type, u8 s_fmt, u8 no_ch, u32 s_rate, u8 dirn);
int skl_init_dsp(struct skl *skl);
void skl_free_dsp(struct skl *skl);
int skl_suspend_dsp(struct skl *skl);
int skl_resume_dsp(struct skl *skl);
#endif /* __SOUND_SOC_SKL_H */
......@@ -148,10 +148,14 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
dram = mv_mbus_dram_info();
addr = substream->dma_buffer.addr;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (priv->substream_play)
return -EBUSY;
priv->substream_play = substream;
kirkwood_dma_conf_mbus_windows(priv->io,
KIRKWOOD_PLAYBACK_WIN, addr, dram);
} else {
if (priv->substream_rec)
return -EBUSY;
priv->substream_rec = substream;
kirkwood_dma_conf_mbus_windows(priv->io,
KIRKWOOD_RECORD_WIN, addr, dram);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment