ASoC: Intel: sst - add compressed ops handling

This patch add low level IPC handling for compressed stream operations

Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Vinod Koul 2014-10-30 16:20:59 +05:30 коммит произвёл Mark Brown
Родитель fdcc4a039f
Коммит 7adab122a5
1 изменённых файлов: 285 добавлений и 0 удалений

Просмотреть файл

@ -172,6 +172,273 @@ static int sst_open_pcm_stream(struct device *dev,
return retval;
}
static int sst_cdev_open(struct device *dev,
struct snd_sst_params *str_params, struct sst_compress_cb *cb)
{
int str_id, retval;
struct stream_info *stream;
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
retval = pm_runtime_get_sync(ctx->dev);
if (retval < 0)
return retval;
str_id = sst_get_stream(ctx, str_params);
if (str_id > 0) {
dev_dbg(dev, "stream allocated in sst_cdev_open %d\n", str_id);
stream = &ctx->streams[str_id];
stream->compr_cb = cb->compr_cb;
stream->compr_cb_param = cb->param;
stream->drain_notify = cb->drain_notify;
stream->drain_cb_param = cb->drain_cb_param;
} else {
dev_err(dev, "stream encountered error during alloc %d\n", str_id);
str_id = -EINVAL;
sst_pm_runtime_put(ctx);
}
return str_id;
}
static int sst_cdev_close(struct device *dev, unsigned int str_id)
{
int retval;
struct stream_info *stream;
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
stream = get_stream_info(ctx, str_id);
if (!stream) {
dev_err(dev, "stream info is NULL for str %d!!!\n", str_id);
return -EINVAL;
}
if (stream->status == STREAM_RESET) {
dev_dbg(dev, "stream in reset state...\n");
stream->status = STREAM_UN_INIT;
retval = 0;
goto put;
}
retval = sst_free_stream(ctx, str_id);
put:
stream->compr_cb_param = NULL;
stream->compr_cb = NULL;
if (retval)
dev_err(dev, "free stream returned err %d\n", retval);
dev_dbg(dev, "End\n");
return retval;
}
static int sst_cdev_ack(struct device *dev, unsigned int str_id,
unsigned long bytes)
{
struct stream_info *stream;
struct snd_sst_tstamp fw_tstamp = {0,};
int offset;
void __iomem *addr;
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
stream = get_stream_info(ctx, str_id);
if (!stream)
return -EINVAL;
/* update bytes sent */
stream->cumm_bytes += bytes;
dev_dbg(dev, "bytes copied %d inc by %ld\n", stream->cumm_bytes, bytes);
memcpy_fromio(&fw_tstamp,
((void *)(ctx->mailbox + ctx->tstamp)
+(str_id * sizeof(fw_tstamp))),
sizeof(fw_tstamp));
fw_tstamp.bytes_copied = stream->cumm_bytes;
dev_dbg(dev, "bytes sent to fw %llu inc by %ld\n",
fw_tstamp.bytes_copied, bytes);
addr = ((void *)(ctx->mailbox + ctx->tstamp)) +
(str_id * sizeof(fw_tstamp));
offset = offsetof(struct snd_sst_tstamp, bytes_copied);
sst_shim_write(addr, offset, fw_tstamp.bytes_copied);
return 0;
}
static int sst_cdev_set_metadata(struct device *dev,
unsigned int str_id, struct snd_compr_metadata *metadata)
{
int retval = 0;
struct stream_info *str_info;
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
dev_dbg(dev, "set metadata for stream %d\n", str_id);
str_info = get_stream_info(ctx, str_id);
if (!str_info)
return -EINVAL;
dev_dbg(dev, "pipe id = %d\n", str_info->pipe_id);
retval = sst_prepare_and_post_msg(ctx, str_info->task_id, IPC_CMD,
IPC_IA_SET_STREAM_PARAMS_MRFLD, str_info->pipe_id,
sizeof(*metadata), metadata, NULL,
true, true, true, false);
return retval;
}
static int sst_cdev_stream_pause(struct device *dev, unsigned int str_id)
{
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
return sst_pause_stream(ctx, str_id);
}
static int sst_cdev_stream_pause_release(struct device *dev,
unsigned int str_id)
{
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
return sst_resume_stream(ctx, str_id);
}
static int sst_cdev_stream_start(struct device *dev, unsigned int str_id)
{
struct stream_info *str_info;
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
str_info = get_stream_info(ctx, str_id);
if (!str_info)
return -EINVAL;
str_info->prev = str_info->status;
str_info->status = STREAM_RUNNING;
return sst_start_stream(ctx, str_id);
}
static int sst_cdev_stream_drop(struct device *dev, unsigned int str_id)
{
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
return sst_drop_stream(ctx, str_id);
}
static int sst_cdev_stream_drain(struct device *dev, unsigned int str_id)
{
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
return sst_drain_stream(ctx, str_id, false);
}
static int sst_cdev_stream_partial_drain(struct device *dev,
unsigned int str_id)
{
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
return sst_drain_stream(ctx, str_id, true);
}
static int sst_cdev_tstamp(struct device *dev, unsigned int str_id,
struct snd_compr_tstamp *tstamp)
{
struct snd_sst_tstamp fw_tstamp = {0,};
struct stream_info *stream;
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
memcpy_fromio(&fw_tstamp,
((void *)(ctx->mailbox + ctx->tstamp)
+(str_id * sizeof(fw_tstamp))),
sizeof(fw_tstamp));
stream = get_stream_info(ctx, str_id);
if (!stream)
return -EINVAL;
dev_dbg(dev, "rb_counter %llu in bytes\n", fw_tstamp.ring_buffer_counter);
tstamp->copied_total = fw_tstamp.ring_buffer_counter;
tstamp->pcm_frames = fw_tstamp.frames_decoded;
tstamp->pcm_io_frames = div_u64(fw_tstamp.hardware_counter,
(u64)((stream->num_ch) * SST_GET_BYTES_PER_SAMPLE(24)));
tstamp->sampling_rate = fw_tstamp.sampling_frequency;
dev_dbg(dev, "PCM = %u\n", tstamp->pcm_io_frames);
dev_dbg(dev, "Ptr Query on strid = %d copied_total %d, decodec %d\n",
str_id, tstamp->copied_total, tstamp->pcm_frames);
dev_dbg(dev, "rendered %d\n", tstamp->pcm_io_frames);
return 0;
}
static int sst_cdev_caps(struct snd_compr_caps *caps)
{
caps->num_codecs = NUM_CODEC;
caps->min_fragment_size = MIN_FRAGMENT_SIZE; /* 50KB */
caps->max_fragment_size = MAX_FRAGMENT_SIZE; /* 1024KB */
caps->min_fragments = MIN_FRAGMENT;
caps->max_fragments = MAX_FRAGMENT;
caps->codecs[0] = SND_AUDIOCODEC_MP3;
caps->codecs[1] = SND_AUDIOCODEC_AAC;
return 0;
}
static struct snd_compr_codec_caps caps_mp3 = {
.num_descriptors = 1,
.descriptor[0].max_ch = 2,
.descriptor[0].sample_rates[0] = 48000,
.descriptor[0].sample_rates[1] = 44100,
.descriptor[0].sample_rates[2] = 32000,
.descriptor[0].sample_rates[3] = 16000,
.descriptor[0].sample_rates[4] = 8000,
.descriptor[0].num_sample_rates = 5,
.descriptor[0].bit_rate[0] = 320,
.descriptor[0].bit_rate[1] = 192,
.descriptor[0].num_bitrates = 2,
.descriptor[0].profiles = 0,
.descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO,
.descriptor[0].formats = 0,
};
static struct snd_compr_codec_caps caps_aac = {
.num_descriptors = 2,
.descriptor[1].max_ch = 2,
.descriptor[0].sample_rates[0] = 48000,
.descriptor[0].sample_rates[1] = 44100,
.descriptor[0].sample_rates[2] = 32000,
.descriptor[0].sample_rates[3] = 16000,
.descriptor[0].sample_rates[4] = 8000,
.descriptor[0].num_sample_rates = 5,
.descriptor[1].bit_rate[0] = 320,
.descriptor[1].bit_rate[1] = 192,
.descriptor[1].num_bitrates = 2,
.descriptor[1].profiles = 0,
.descriptor[1].modes = 0,
.descriptor[1].formats =
(SND_AUDIOSTREAMFORMAT_MP4ADTS |
SND_AUDIOSTREAMFORMAT_RAW),
};
static int sst_cdev_codec_caps(struct snd_compr_codec_caps *codec)
{
if (codec->codec == SND_AUDIOCODEC_MP3)
*codec = caps_mp3;
else if (codec->codec == SND_AUDIOCODEC_AAC)
*codec = caps_aac;
else
return -EINVAL;
return 0;
}
void sst_cdev_fragment_elapsed(struct intel_sst_drv *ctx, int str_id)
{
struct stream_info *stream;
dev_dbg(ctx->dev, "fragment elapsed from firmware for str_id %d\n",
str_id);
stream = &ctx->streams[str_id];
if (stream->compr_cb)
stream->compr_cb(stream->compr_cb_param);
}
/*
* sst_close_pcm_stream - Close PCM interface
*
@ -372,10 +639,28 @@ static struct sst_ops pcm_ops = {
.power = sst_power_control,
};
static struct compress_sst_ops compr_ops = {
.open = sst_cdev_open,
.close = sst_cdev_close,
.stream_pause = sst_cdev_stream_pause,
.stream_pause_release = sst_cdev_stream_pause_release,
.stream_start = sst_cdev_stream_start,
.stream_drop = sst_cdev_stream_drop,
.stream_drain = sst_cdev_stream_drain,
.stream_partial_drain = sst_cdev_stream_partial_drain,
.tstamp = sst_cdev_tstamp,
.ack = sst_cdev_ack,
.get_caps = sst_cdev_caps,
.get_codec_caps = sst_cdev_codec_caps,
.set_metadata = sst_cdev_set_metadata,
.power = sst_power_control,
};
static struct sst_device sst_dsp_device = {
.name = "Intel(R) SST LPE",
.dev = NULL,
.ops = &pcm_ops,
.compr_ops = &compr_ops,
};
/*