topology: plugins: nhlt: add ssp aux controls

Intel ssp blob can have auxiliary controls catenated as tlv array at the
end of its "normal" data blob. These are needed in some platforms for
example to enable hardware clocks earlier than streaming starts.

In topology the auxiliary data classes are embedded into hw_config and
can be instantiated like:

Object.Base.hw_config."SSP0_0" {
	id              0
	mclk_freq       38400000
	bclk_freq       256000
	tdm_slot_width  16
	format          "DSP_A"
	bclk            "codec_provider"
	fsync           "codec_provider"
	fsync_freq      16000

	Object.Base.mn_config."MN_0" {
		m_div   100
		n_div   200
	}

	Object.Base.clk_config."CLK_0" {
		clock_warm_up          1
		mclk                   2
		warm_up_ovr            3
		clock_stop_delay       4
		keep_running           5
		clock_stop_ovr         6
	}
}

Fixes: https://github.com/alsa-project/alsa-utils/pull/184
Signed-off-by: Jaska Uimonen <jaska.uimonen@linux.intel.com>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
Jaska Uimonen 2022-10-12 13:44:55 +03:00 committed by Jaroslav Kysela
parent 4e3843d0ed
commit 1ad140f641
6 changed files with 1066 additions and 38 deletions

View file

@ -16,41 +16,330 @@
#include "intel-nhlt.h" #include "intel-nhlt.h"
#include "ssp-nhlt.h" #include "ssp-nhlt.h"
#include "ssp/ssp-process.h" #include "ssp/ssp-process.h"
#include "ssp/ssp-internal.h"
static int set_ssp_data(struct intel_nhlt_params *nhlt, snd_config_t *dai_cfg, snd_config_t *top) static int set_mn_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
{ {
const char *tdm_padding_per_slot = NULL; long m_div;
const char *direction = NULL; long n_div;
const char *quirks = NULL; long ret;
long frame_pulse_width = 0;
long clks_control = 0;
long sample_bits = 0;
long bclk_delay = 0;
long dai_index = 0;
long mclk_id = 0;
long io_clk = 0;
int ret;
struct dai_values ssp_data[] = { struct dai_values ssp_mn_data[] = {
{ "io_clk", SND_CONFIG_TYPE_INTEGER, NULL, &io_clk, NULL}, {"m_div", SND_CONFIG_TYPE_INTEGER, NULL, &m_div, NULL},
{ "direction", SND_CONFIG_TYPE_STRING, NULL, NULL, &direction}, {"n_div", SND_CONFIG_TYPE_INTEGER, NULL, &n_div, NULL},
{ "quirks", SND_CONFIG_TYPE_STRING, NULL, NULL, &quirks},
{ "dai_index", SND_CONFIG_TYPE_INTEGER, NULL, &dai_index, NULL},
{ "sample_bits", SND_CONFIG_TYPE_INTEGER, NULL, &sample_bits, NULL},
{ "bclk_delay", SND_CONFIG_TYPE_INTEGER, NULL, &bclk_delay, NULL},
{ "mclk_id", SND_CONFIG_TYPE_INTEGER, NULL, &mclk_id, NULL},
{ "clks_control", SND_CONFIG_TYPE_INTEGER, NULL, &clks_control, NULL},
{ "frame_pulse_width", SND_CONFIG_TYPE_INTEGER, NULL, &frame_pulse_width, NULL},
{ "tdm_padding_per_slot", SND_CONFIG_TYPE_STRING, NULL, NULL,
&tdm_padding_per_slot},
}; };
ret = find_set_values(&ssp_data[0], ARRAY_SIZE(ssp_data), dai_cfg, top, "Class.Dai.SSP"); ret = find_set_values(&ssp_mn_data[0], ARRAY_SIZE(ssp_mn_data), cfg, top,
"Class.Base.mn_config");
if (ret < 0) if (ret < 0)
return ret; return ret;
return ssp_set_params(nhlt, direction, dai_index, io_clk, bclk_delay, sample_bits, mclk_id, return ssp_mn_set_params(nhlt, m_div, n_div);
clks_control, frame_pulse_width, tdm_padding_per_slot, quirks); }
static int set_clk_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
{
long clock_warm_up;
long mclk;
long warm_up_ovr;
long clock_stop_delay;
long keep_running;
long clock_stop_ovr;
long ret;
struct dai_values ssp_clk_data[] = {
{"clock_warm_up", SND_CONFIG_TYPE_INTEGER, NULL, &clock_warm_up, NULL},
{"mclk", SND_CONFIG_TYPE_INTEGER, NULL, &mclk, NULL},
{"warm_up_ovr", SND_CONFIG_TYPE_INTEGER, NULL, &warm_up_ovr, NULL},
{"clock_stop_delay", SND_CONFIG_TYPE_INTEGER, NULL, &clock_stop_delay, NULL},
{"keep_running", SND_CONFIG_TYPE_INTEGER, NULL, &keep_running, NULL},
{"clock_stop_ovr", SND_CONFIG_TYPE_INTEGER, NULL, &clock_stop_ovr, NULL},
};
ret = find_set_values(&ssp_clk_data[0], ARRAY_SIZE(ssp_clk_data), cfg, top,
"Class.Base.clk_config");
if (ret < 0)
return ret;
return ssp_clk_set_params(nhlt, clock_warm_up, mclk, warm_up_ovr, clock_stop_delay,
keep_running, clock_stop_ovr);
}
static int set_tr_start_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
{
long sampling_frequency;
long bit_depth;
long channel_map;
long channel_config;
long interleaving_style;
long number_of_channels;
long valid_bit_depth;
long sample_type;
long ret;
struct dai_values ssp_tr_data[] = {
{"sampling_frequency", SND_CONFIG_TYPE_INTEGER, NULL, &sampling_frequency, NULL},
{"bit_depth", SND_CONFIG_TYPE_INTEGER, NULL, &bit_depth, NULL},
{"channel_map", SND_CONFIG_TYPE_INTEGER, NULL, &channel_map, NULL},
{"channel_config", SND_CONFIG_TYPE_INTEGER, NULL, &channel_config, NULL},
{"interleaving_style", SND_CONFIG_TYPE_INTEGER, NULL, &interleaving_style, NULL},
{"number_of_channels", SND_CONFIG_TYPE_INTEGER, NULL, &number_of_channels, NULL},
{"valid_bit_depth", SND_CONFIG_TYPE_INTEGER, NULL, &valid_bit_depth, NULL},
{"sample_type", SND_CONFIG_TYPE_INTEGER, NULL, &sample_type, NULL},
};
ret = find_set_values(&ssp_tr_data[0], ARRAY_SIZE(ssp_tr_data), cfg, top,
"Class.Base.tr_start_config");
if (ret < 0)
return ret;
return ssp_tr_start_set_params(nhlt, sampling_frequency, bit_depth, channel_map,
channel_config, interleaving_style, number_of_channels,
valid_bit_depth,sample_type);
}
static int set_tr_stop_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
{
long sampling_frequency;
long bit_depth;
long channel_map;
long channel_config;
long interleaving_style;
long number_of_channels;
long valid_bit_depth;
long sample_type;
long ret;
struct dai_values ssp_tr_data[] = {
{"sampling_frequency", SND_CONFIG_TYPE_INTEGER, NULL, &sampling_frequency, NULL},
{"bit_depth", SND_CONFIG_TYPE_INTEGER, NULL, &bit_depth, NULL},
{"channel_map", SND_CONFIG_TYPE_INTEGER, NULL, &channel_map, NULL},
{"channel_config", SND_CONFIG_TYPE_INTEGER, NULL, &channel_config, NULL},
{"interleaving_style", SND_CONFIG_TYPE_INTEGER, NULL, &interleaving_style, NULL},
{"number_of_channels", SND_CONFIG_TYPE_INTEGER, NULL, &number_of_channels, NULL},
{"valid_bit_depth", SND_CONFIG_TYPE_INTEGER, NULL, &valid_bit_depth, NULL},
{"sample_type", SND_CONFIG_TYPE_INTEGER, NULL, &sample_type, NULL},
};
ret = find_set_values(&ssp_tr_data[0], ARRAY_SIZE(ssp_tr_data), cfg, top,
"Class.Base.tr_stop_config");
if (ret < 0)
return ret;
return ssp_tr_stop_set_params(nhlt, sampling_frequency, bit_depth, channel_map,
channel_config, interleaving_style, number_of_channels,
valid_bit_depth,sample_type);
}
static int set_run_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
{
long always_run;
long ret;
struct dai_values ssp_run_data[] = {
{"always_run", SND_CONFIG_TYPE_INTEGER, NULL, &always_run, NULL},
};
ret = find_set_values(&ssp_run_data[0], ARRAY_SIZE(ssp_run_data), cfg, top,
"Class.Base.run_config");
if (ret < 0)
return ret;
return ssp_run_set_params(nhlt, always_run);
}
static int set_node_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
{
long sampling_rate;
long node_id;
long ret;
struct dai_values ssp_node_data[] = {
{"node_id", SND_CONFIG_TYPE_INTEGER, NULL, &node_id, NULL},
{"sampling_rate", SND_CONFIG_TYPE_INTEGER, NULL, &sampling_rate, NULL},
};
ret = find_set_values(&ssp_node_data[0], ARRAY_SIZE(ssp_node_data), cfg, top,
"Class.Base.node_config");
if (ret < 0)
return ret;
return ssp_node_set_params(nhlt, node_id, sampling_rate);
}
static int set_sync_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
{
long sync_denominator;
long ret;
struct dai_values ssp_sync_data[] = {
{"sync_denominator", SND_CONFIG_TYPE_INTEGER, NULL, &sync_denominator, NULL},
};
ret = find_set_values(&ssp_sync_data[0], ARRAY_SIZE(ssp_sync_data), cfg, top,
"Class.Base.sync_config");
if (ret < 0)
return ret;
return ssp_sync_set_params(nhlt, sync_denominator);
}
static int set_ext_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
{
long mclk_policy_override;
long mclk_always_running;
long mclk_starts_on_gtw_init;
long mclk_starts_on_run;
long mclk_starts_on_pause;
long mclk_stops_on_pause;
long mclk_stops_on_reset;
long bclk_policy_override;
long bclk_always_running;
long bclk_starts_on_gtw_init;
long bclk_starts_on_run;
long bclk_starts_on_pause;
long bclk_stops_on_pause;
long bclk_stops_on_reset;
long sync_policy_override;
long sync_always_running;
long sync_starts_on_gtw_init;
long sync_starts_on_run;
long sync_starts_on_pause;
long sync_stops_on_pause;
long sync_stops_on_reset;
long ret;
struct dai_values ssp_ext_data[] = {
{"mclk_policy_override", SND_CONFIG_TYPE_INTEGER, NULL, &mclk_policy_override, NULL},
{"mclk_always_running", SND_CONFIG_TYPE_INTEGER, NULL, &mclk_always_running, NULL},
{"mclk_starts_on_gtw_init", SND_CONFIG_TYPE_INTEGER, NULL, &mclk_starts_on_gtw_init, NULL},
{"mclk_starts_on_run", SND_CONFIG_TYPE_INTEGER, NULL, &mclk_starts_on_run, NULL},
{"mclk_starts_on_pause", SND_CONFIG_TYPE_INTEGER, NULL, &mclk_starts_on_pause, NULL},
{"mclk_stops_on_pause", SND_CONFIG_TYPE_INTEGER, NULL, &mclk_stops_on_pause, NULL},
{"mclk_stops_on_reset", SND_CONFIG_TYPE_INTEGER, NULL, &mclk_stops_on_reset, NULL},
{"bclk_policy_override", SND_CONFIG_TYPE_INTEGER, NULL, &bclk_policy_override, NULL},
{"bclk_always_running", SND_CONFIG_TYPE_INTEGER, NULL, &bclk_always_running, NULL},
{"bclk_starts_on_gtw_init", SND_CONFIG_TYPE_INTEGER, NULL, &bclk_starts_on_gtw_init, NULL},
{"bclk_starts_on_run", SND_CONFIG_TYPE_INTEGER, NULL, &bclk_starts_on_run, NULL},
{"bclk_starts_on_pause", SND_CONFIG_TYPE_INTEGER, NULL, &bclk_starts_on_pause, NULL},
{"bclk_stops_on_pause", SND_CONFIG_TYPE_INTEGER, NULL, &bclk_stops_on_pause, NULL},
{"bclk_stops_on_reset", SND_CONFIG_TYPE_INTEGER, NULL, &bclk_stops_on_reset, NULL},
{"sync_policy_override", SND_CONFIG_TYPE_INTEGER, NULL, &sync_policy_override, NULL},
{"sync_always_running", SND_CONFIG_TYPE_INTEGER, NULL, &sync_always_running, NULL},
{"sync_starts_on_gtw_init", SND_CONFIG_TYPE_INTEGER, NULL, &sync_starts_on_gtw_init, NULL},
{"sync_starts_on_run", SND_CONFIG_TYPE_INTEGER, NULL, &sync_starts_on_run, NULL},
{"sync_starts_on_pause", SND_CONFIG_TYPE_INTEGER, NULL, &sync_starts_on_pause, NULL},
{"sync_stops_on_pause", SND_CONFIG_TYPE_INTEGER, NULL, &sync_stops_on_pause, NULL},
{"sync_stops_on_reset", SND_CONFIG_TYPE_INTEGER, NULL, &sync_stops_on_reset, NULL},
};
ret = find_set_values(&ssp_ext_data[0], ARRAY_SIZE(ssp_ext_data), cfg, top,
"Class.Base.ext_config");
if (ret < 0)
return ret;
return ssp_ext_set_params(nhlt, mclk_policy_override, mclk_always_running,
mclk_starts_on_gtw_init, mclk_starts_on_run, mclk_starts_on_pause,
mclk_stops_on_pause, mclk_stops_on_reset,
bclk_policy_override, bclk_always_running,
bclk_starts_on_gtw_init, bclk_starts_on_run, bclk_starts_on_pause,
bclk_stops_on_pause, bclk_stops_on_reset,
sync_policy_override, sync_always_running,
sync_starts_on_gtw_init, sync_starts_on_run, sync_starts_on_pause,
sync_stops_on_pause, sync_stops_on_reset);
}
static int set_link_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
{
long clock_source;
long ret;
struct dai_values ssp_link_data[] = {
{"clock_source", SND_CONFIG_TYPE_INTEGER, NULL, &clock_source, NULL},
};
ret = find_set_values(&ssp_link_data[0], ARRAY_SIZE(ssp_link_data), cfg, top,
"Class.Base.link_config");
if (ret < 0)
return ret;
return ssp_link_set_params(nhlt, clock_source);
}
static int set_aux_params(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
{
struct aux_map {
const char *name;
int id;
};
struct aux_map aux_maps[] = {
{ "Object.Base.mn_config", SSP_MN_DIVIDER_CONTROLS },
{"Object.Base.clk_config", SSP_DMA_CLK_CONTROLS },
{"Object.Base.tr_start_config", SSP_DMA_TRANSMISSION_START },
{"Object.Base.tr_stop_config", SSP_DMA_TRANSMISSION_STOP },
{"Object.Base.run_config", SSP_DMA_ALWAYS_RUNNING_MODE} ,
{"Object.Base.sync_config", SSP_DMA_SYNC_DATA },
{"Object.Base.ext_config", SSP_DMA_CLK_CONTROLS_EXT },
{"Object.Base.link_config", SSP_LINK_CLK_SOURCE },
{"Object.Base.node_config", SSP_DMA_SYNC_NODE },
};
snd_config_iterator_t iter, next;
snd_config_t *items, *n;
const char *id;
int i, ret = 0;
for (i = 0; i < ARRAY_SIZE(aux_maps); i++) {
if (snd_config_search(cfg, aux_maps[i].name, &items) < 0)
continue;
snd_config_for_each(iter, next, items) {
n = snd_config_iterator_entry(iter);
if (snd_config_get_id(n, &id) < 0)
continue;
switch(aux_maps[i].id) {
case SSP_MN_DIVIDER_CONTROLS:
ret = set_mn_config(nhlt, n, top);
break;
case SSP_DMA_CLK_CONTROLS:
ret = set_clk_config(nhlt, n, top);
break;
case SSP_DMA_TRANSMISSION_START:
ret = set_tr_start_config(nhlt, n, top);
break;
case SSP_DMA_TRANSMISSION_STOP:
ret = set_tr_stop_config(nhlt, n, top);
break;
case SSP_DMA_ALWAYS_RUNNING_MODE:
ret = set_run_config(nhlt, n, top);
break;
case SSP_DMA_SYNC_DATA:
ret = set_sync_config(nhlt, n, top);
break;
case SSP_DMA_CLK_CONTROLS_EXT:
ret = set_ext_config(nhlt, n, top);
break;
case SSP_LINK_CLK_SOURCE:
ret = set_link_config(nhlt, n, top);
break;
case SSP_DMA_SYNC_NODE:
ret = set_node_config(nhlt, n, top);
break;
default:
ret = -EINVAL;
}
if (ret < 0)
return ret;
}
}
return ret;
} }
static int set_hw_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top) static int set_hw_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
@ -91,11 +380,51 @@ static int set_hw_config(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = set_aux_params(nhlt, cfg, top);
if (ret < 0)
return ret;
return ssp_hw_set_params(nhlt, format, mclk, bclk, bclk_invert, fsync, fsync_invert, return ssp_hw_set_params(nhlt, format, mclk, bclk, bclk_invert, fsync, fsync_invert,
mclk_freq, bclk_freq, fsync_freq, tdm_slots, tdm_slot_width, mclk_freq, bclk_freq, fsync_freq, tdm_slots, tdm_slot_width,
tx_slots, rx_slots); tx_slots, rx_slots);
} }
static int set_ssp_data(struct intel_nhlt_params *nhlt, snd_config_t *dai_cfg, snd_config_t *top)
{
const char *tdm_padding_per_slot = NULL;
const char *direction = NULL;
const char *quirks = NULL;
long frame_pulse_width = 0;
long clks_control = 0;
long sample_bits = 0;
long bclk_delay = 0;
long dai_index = 0;
long mclk_id = 0;
long io_clk = 0;
int ret;
struct dai_values ssp_data[] = {
{ "io_clk", SND_CONFIG_TYPE_INTEGER, NULL, &io_clk, NULL},
{ "direction", SND_CONFIG_TYPE_STRING, NULL, NULL, &direction},
{ "quirks", SND_CONFIG_TYPE_STRING, NULL, NULL, &quirks},
{ "dai_index", SND_CONFIG_TYPE_INTEGER, NULL, &dai_index, NULL},
{ "sample_bits", SND_CONFIG_TYPE_INTEGER, NULL, &sample_bits, NULL},
{ "bclk_delay", SND_CONFIG_TYPE_INTEGER, NULL, &bclk_delay, NULL},
{ "mclk_id", SND_CONFIG_TYPE_INTEGER, NULL, &mclk_id, NULL},
{ "clks_control", SND_CONFIG_TYPE_INTEGER, NULL, &clks_control, NULL},
{ "frame_pulse_width", SND_CONFIG_TYPE_INTEGER, NULL, &frame_pulse_width, NULL},
{ "tdm_padding_per_slot", SND_CONFIG_TYPE_STRING, NULL, NULL,
&tdm_padding_per_slot},
};
ret = find_set_values(&ssp_data[0], ARRAY_SIZE(ssp_data), dai_cfg, top, "Class.Dai.SSP");
if (ret < 0)
return ret;
return ssp_set_params(nhlt, direction, dai_index, io_clk, bclk_delay, sample_bits, mclk_id,
clks_control, frame_pulse_width, tdm_padding_per_slot, quirks);
}
/* init ssp parameters, should be called before parsing dais */ /* init ssp parameters, should be called before parsing dais */
int nhlt_ssp_init_params(struct intel_nhlt_params *nhlt) int nhlt_ssp_init_params(struct intel_nhlt_params *nhlt)
{ {
@ -194,7 +523,7 @@ int nhlt_ssp_get_ep(struct intel_nhlt_params *nhlt, struct endpoint_descriptor *
f_conf1[i].format.SubFormat[2] = 0; f_conf1[i].format.SubFormat[2] = 0;
f_conf1[i].format.SubFormat[3] = 0; f_conf1[i].format.SubFormat[3] = 0;
ret = ssp_get_vendor_blob_size(nhlt, &blob_size); ret = ssp_get_vendor_blob_size(nhlt, dai_index, i, &blob_size);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "nhlt_ssp_get_ep: dmic_get_vendor_blob_size failed\n"); fprintf(stderr, "nhlt_ssp_get_ep: dmic_get_vendor_blob_size failed\n");
return ret; return ret;

View file

@ -7,14 +7,17 @@
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include "ssp-debug.h" #include "ssp-debug.h"
#include "../intel-nhlt.h"
#ifdef NHLT_DEBUG #ifdef NHLT_DEBUG
void ssp_print_calculated(struct intel_ssp_params *ssp) void ssp_print_calculated(struct intel_ssp_params *ssp)
{ {
struct ssp_intel_config_data *blob; struct ssp_intel_config_data *blob;
struct ssp_aux_blob *blob_aux;
int ssp_index = ssp->ssp_count; int ssp_index = ssp->ssp_count;
int i; uint32_t *ptr;
int i, j;
fprintf(stdout, "printing ssp nhlt calculated data:\n"); fprintf(stdout, "printing ssp nhlt calculated data:\n");
@ -29,7 +32,7 @@ void ssp_print_calculated(struct intel_ssp_params *ssp)
fprintf(stdout, "\n"); fprintf(stdout, "\n");
for (i = 0; i < ssp->ssp_hw_config_count[ssp_index]; i++) { for (i = 0; i < ssp->ssp_hw_config_count[ssp_index]; i++) {
blob = &ssp->ssp_blob[ssp->ssp_count][i]; blob = &ssp->ssp_blob[ssp_index][i];
fprintf(stdout, "ssp blob %d hw_config %d\n", ssp->ssp_count, i); fprintf(stdout, "ssp blob %d hw_config %d\n", ssp->ssp_count, i);
fprintf(stdout, "gateway_attributes %u\n", blob->gateway_attributes); fprintf(stdout, "gateway_attributes %u\n", blob->gateway_attributes);
fprintf(stdout, "ts_group[0] 0x%08x\n", blob->ts_group[0]); fprintf(stdout, "ts_group[0] 0x%08x\n", blob->ts_group[0]);
@ -52,6 +55,15 @@ void ssp_print_calculated(struct intel_ssp_params *ssp)
fprintf(stdout, "ssioc 0x%08x\n", blob->ssioc); fprintf(stdout, "ssioc 0x%08x\n", blob->ssioc);
fprintf(stdout, "mdivc 0x%08x\n", blob->mdivc); fprintf(stdout, "mdivc 0x%08x\n", blob->mdivc);
fprintf(stdout, "mdivr 0x%08x\n", blob->mdivr); fprintf(stdout, "mdivr 0x%08x\n", blob->mdivr);
blob_aux = (struct ssp_aux_blob *)&(ssp->ssp_blob_ext[ssp_index][i]);
fprintf(stdout, "aux_blob size %u\n", blob_aux->size);
for (j = 0; j < blob_aux->size; j += 4) {
ptr = (uint32_t *)&(blob_aux->aux_blob[j]);
fprintf(stdout, "aux_blob %d 0x%08x\n", j, *ptr);
}
fprintf(stdout, "\n");
} }
fprintf(stdout, "\n"); fprintf(stdout, "\n");
@ -59,9 +71,17 @@ void ssp_print_calculated(struct intel_ssp_params *ssp)
void ssp_print_internal(struct intel_ssp_params *ssp) void ssp_print_internal(struct intel_ssp_params *ssp)
{ {
struct ssp_config_hw *hw_conf; struct ssp_aux_config_link *link;
struct ssp_aux_config_sync *sync;
struct ssp_aux_config_ext *ext;
struct ssp_aux_config_run *run;
struct ssp_aux_config_clk *clk;
struct ssp_aux_config_mn *mn;
struct ssp_aux_config_tr *tr;
struct ssp_config_dai *dai; struct ssp_config_dai *dai;
int i; struct ssp_config_hw *hw_conf;
uint32_t enabled;
int i, j;
dai = &ssp->ssp_prm[ssp->ssp_count]; dai = &ssp->ssp_prm[ssp->ssp_count];
@ -92,6 +112,106 @@ void ssp_print_internal(struct intel_ssp_params *ssp)
fprintf(stdout, "tx_slots %u\n", hw_conf->tx_slots); fprintf(stdout, "tx_slots %u\n", hw_conf->tx_slots);
fprintf(stdout, "rx_slots %u\n", hw_conf->rx_slots); fprintf(stdout, "rx_slots %u\n", hw_conf->rx_slots);
fprintf(stdout, "format %u\n", hw_conf->format); fprintf(stdout, "format %u\n", hw_conf->format);
enabled = dai->aux_cfg[i].enabled;
fprintf(stdout, "aux enabled %x\n", enabled);
fprintf(stdout, "\n");
mn = (struct ssp_aux_config_mn *)&(dai->aux_cfg[i].mn);
clk = (struct ssp_aux_config_clk *)&(dai->aux_cfg[i].clk);
tr = (struct ssp_aux_config_tr *)&(dai->aux_cfg[i].tr_start);
tr = (struct ssp_aux_config_tr *)&(dai->aux_cfg[i].tr_stop);
run = (struct ssp_aux_config_run *)&(dai->aux_cfg[i].run);
sync = (struct ssp_aux_config_sync *)&(dai->aux_cfg[i].sync);
ext = (struct ssp_aux_config_ext *)&(dai->aux_cfg[i].ext);
link = (struct ssp_aux_config_link *)&(dai->aux_cfg[i].link);
if (enabled & BIT(SSP_MN_DIVIDER_CONTROLS)) {
fprintf(stdout, "aux mn m_div %u\n", mn->m_div);
fprintf(stdout, "aux mn n_div %u\n", mn->n_div);
fprintf(stdout, "\n");
}
if (enabled & BIT(SSP_DMA_CLK_CONTROLS)) {
fprintf(stdout, "aux clk clock_warm_up %u\n", clk->clock_warm_up);
fprintf(stdout, "aux clk mclk %u\n", clk->mclk);
fprintf(stdout, "aux clk warm_up_ovr %u\n", clk->warm_up_ovr);
fprintf(stdout, "aux clk clock_stop_delay %u\n", clk->clock_stop_delay);
fprintf(stdout, "aux clk keep_running %u\n", clk->keep_running);
fprintf(stdout, "aux clk keep_running %u\n", clk->clock_stop_ovr);
fprintf(stdout, "\n");
}
if (enabled & BIT(SSP_DMA_TRANSMISSION_START)) {
fprintf(stdout, "aux tr start sampling_frequency %u\n", tr->sampling_frequency);
fprintf(stdout, "aux tr start bit_depth %u\n", tr->bit_depth);
fprintf(stdout, "aux tr start channel_map %u\n", tr->channel_map);
fprintf(stdout, "aux tr start channel_config %u\n", tr->channel_config);
fprintf(stdout, "aux tr start interleaving_style %u\n", tr->interleaving_style);
fprintf(stdout, "aux tr start number_of_channels %u\n", tr->number_of_channels);
fprintf(stdout, "aux tr start valid_bit_depth %u\n", tr->valid_bit_depth);
fprintf(stdout, "aux tr start sample_types %u\n", tr->sample_type);
fprintf(stdout, "\n");
}
if (enabled & BIT(SSP_DMA_TRANSMISSION_STOP)) {
fprintf(stdout, "aux tr start sampling_frequency %u\n", tr->sampling_frequency);
fprintf(stdout, "aux tr start bit_depth %u\n", tr->bit_depth);
fprintf(stdout, "aux tr start channel_map %u\n", tr->channel_map);
fprintf(stdout, "aux tr start channel_config %u\n", tr->channel_config);
fprintf(stdout, "aux tr start interleaving_style %u\n", tr->interleaving_style);
fprintf(stdout, "aux tr start number_of_channels %u\n", tr->number_of_channels);
fprintf(stdout, "aux tr start valid_bit_depth %u\n", tr->valid_bit_depth);
fprintf(stdout, "aux tr start sample_types %u\n", tr->sample_type);
fprintf(stdout, "\n");
}
if (enabled & BIT(SSP_DMA_ALWAYS_RUNNING_MODE)) {
fprintf(stdout, "aux run always_run %u\n", run->always_run);
fprintf(stdout, "\n");
}
if (enabled & BIT(SSP_DMA_SYNC_DATA)) {
fprintf(stdout, "aux sync sync_denominator %u\n", sync->sync_denominator);
fprintf(stdout, "aux sync count %u\n", sync->count);
for (j = 0; j < sync->count; j++) {
fprintf(stdout, "aux sync node_id %u\n", sync->nodes[j].node_id);
fprintf(stdout, "aux sync sampling_rate %u\n", sync->nodes[j].sampling_rate);
}
fprintf(stdout, "\n");
}
if (enabled & BIT(SSP_DMA_CLK_CONTROLS_EXT)) {
fprintf(stdout, "aux ext mclk_policy_override %u\n", ext->mclk_policy_override);
fprintf(stdout, "aux ext mclk_always_running %u\n", ext->mclk_always_running);
fprintf(stdout, "aux ext mclk_starts_on_gtw_init %u\n", ext->mclk_starts_on_gtw_init);
fprintf(stdout, "aux ext mclk_starts_on_run %u\n", ext->mclk_starts_on_run);
fprintf(stdout, "aux ext mclk_starts_on_pause %u\n", ext->mclk_starts_on_pause);
fprintf(stdout, "aux ext mclk_stops_on_pause %u\n", ext->mclk_stops_on_pause);
fprintf(stdout, "aux ext mclk_stops_on_reset %u\n", ext->mclk_stops_on_reset);
fprintf(stdout, "aux ext bclk_policy_override %u\n", ext->bclk_policy_override);
fprintf(stdout, "aux ext bclk_always_running %u\n", ext->bclk_always_running);
fprintf(stdout, "aux ext bclk_starts_on_gtw_init %u\n", ext->bclk_starts_on_gtw_init);
fprintf(stdout, "aux ext bclk_starts_on_run %u\n", ext->bclk_starts_on_run);
fprintf(stdout, "aux ext bclk_starts_on_pause %u\n", ext->bclk_starts_on_pause);
fprintf(stdout, "aux ext bclk_stops_on_pause %u\n", ext->bclk_stops_on_pause);
fprintf(stdout, "aux ext bclk_stops_on_reset %u\n", ext->bclk_stops_on_reset);
fprintf(stdout, "aux ext sync_policy_override %u\n", ext->sync_policy_override);
fprintf(stdout, "aux ext sync_always_running %u\n", ext->sync_always_running);
fprintf(stdout, "aux ext sync_starts_on_gtw_init %u\n", ext->sync_starts_on_gtw_init);
fprintf(stdout, "aux ext sync_starts_on_run %u\n", ext->sync_starts_on_run);
fprintf(stdout, "aux ext sync_starts_on_pause %u\n", ext->sync_starts_on_pause);
fprintf(stdout, "aux ext sync_stops_on_pause %u\n", ext->sync_stops_on_pause);
fprintf(stdout, "aux ext sync_stops_on_reset %u\n", ext->sync_stops_on_reset);
fprintf(stdout, "\n");
}
if (enabled & BIT(SSP_LINK_CLK_SOURCE)) {
fprintf(stdout, "aux link clock_source %u\n", link->clock_source);
fprintf(stdout, "\n");
}
} }
fprintf(stdout, "\n"); fprintf(stdout, "\n");

View file

@ -52,4 +52,51 @@ struct ssp_intel_config_data_1_5 {
uint32_t mdivr[]; uint32_t mdivr[];
} __attribute__((packed)); } __attribute__((packed));
struct ssp_intel_aux_tlv {
uint32_t type;
uint32_t size;
uint32_t val[];
} __attribute__((packed));
struct ssp_intel_mn_ctl {
uint32_t div_m;
uint32_t div_n;
} __attribute__((packed));
struct ssp_intel_clk_ctl {
uint32_t start;
uint32_t stop;
} __attribute__((packed));
struct ssp_intel_tr_ctl {
uint32_t sampling_frequency;
uint32_t bit_depth;
uint32_t channel_map;
uint32_t channel_config;
uint32_t interleaving_style;
uint32_t format;
} __attribute__((packed));
struct ssp_intel_run_ctl {
uint32_t enabled;
} __attribute__((packed));
struct ssp_intel_node_ctl {
uint32_t node_id;
uint32_t sampling_rate;
} __attribute__((packed));
struct ssp_intel_sync_ctl {
uint32_t sync_denominator;
uint32_t count;
} __attribute__((packed));
struct ssp_intel_ext_ctl {
uint32_t ext_data;
} __attribute__((packed));
struct ssp_intel_link_ctl {
uint32_t clock_source;
} __attribute__((packed));
#endif /* __SSP_INTEL_H */ #endif /* __SSP_INTEL_H */

View file

@ -16,7 +16,91 @@
#define SSP_MAX_HW_CONFIG 8 #define SSP_MAX_HW_CONFIG 8
#define SSP_TDM_MAX_SLOT_MAP_COUNT 8 #define SSP_TDM_MAX_SLOT_MAP_COUNT 8
struct ssp_aux_config_mn {
uint32_t m_div;
uint32_t n_div;
};
struct ssp_aux_config_clk {
uint32_t clock_warm_up;
uint32_t mclk;
uint32_t warm_up_ovr;
uint32_t clock_stop_delay;
uint32_t keep_running;
uint32_t clock_stop_ovr;
};
struct ssp_aux_config_tr {
uint32_t sampling_frequency;
uint32_t bit_depth;
uint32_t channel_map;
uint32_t channel_config;
uint32_t interleaving_style;
uint32_t number_of_channels;
uint32_t valid_bit_depth;
uint32_t sample_type;
};
struct ssp_aux_config_run {
uint32_t always_run;
};
struct ssp_aux_config_node {
uint32_t node_id;
uint32_t sampling_rate;
};
struct ssp_aux_config_sync {
uint32_t sync_denominator;
uint32_t count;
struct ssp_aux_config_node nodes[SSP_MAX_DAIS];
};
struct ssp_aux_config_ext {
uint32_t mclk_policy_override;
uint32_t mclk_always_running;
uint32_t mclk_starts_on_gtw_init;
uint32_t mclk_starts_on_run;
uint32_t mclk_starts_on_pause;
uint32_t mclk_stops_on_pause;
uint32_t mclk_stops_on_reset;
uint32_t bclk_policy_override;
uint32_t bclk_always_running;
uint32_t bclk_starts_on_gtw_init;
uint32_t bclk_starts_on_run;
uint32_t bclk_starts_on_pause;
uint32_t bclk_stops_on_pause;
uint32_t bclk_stops_on_reset;
uint32_t sync_policy_override;
uint32_t sync_always_running;
uint32_t sync_starts_on_gtw_init;
uint32_t sync_starts_on_run;
uint32_t sync_starts_on_pause;
uint32_t sync_stops_on_pause;
uint32_t sync_stops_on_reset;
};
struct ssp_aux_config_link {
uint32_t clock_source;
};
struct ssp_config_aux {
/* bits set for found aux structs */
uint32_t enabled;
struct ssp_aux_config_mn mn;
struct ssp_aux_config_clk clk;
struct ssp_aux_config_tr tr_start;
struct ssp_aux_config_tr tr_stop;
struct ssp_aux_config_run run;
struct ssp_aux_config_sync sync;
struct ssp_aux_config_ext ext;
struct ssp_aux_config_link link;
};
struct ssp_aux_blob {
uint32_t size;
uint8_t aux_blob[256];
};
/* structs for gathering the ssp parameters from topology */ /* structs for gathering the ssp parameters from topology */
struct ssp_config_hw { struct ssp_config_hw {
@ -43,6 +127,7 @@ struct ssp_config_dai {
uint32_t bclk_delay; uint32_t bclk_delay;
uint8_t direction; uint8_t direction;
struct ssp_config_hw hw_cfg[SSP_MAX_HW_CONFIG]; struct ssp_config_hw hw_cfg[SSP_MAX_HW_CONFIG];
struct ssp_config_aux aux_cfg[SSP_MAX_HW_CONFIG];
}; };
struct intel_ssp_params { struct intel_ssp_params {
@ -54,8 +139,20 @@ struct intel_ssp_params {
/* ssp vendor blob structs */ /* ssp vendor blob structs */
struct ssp_intel_config_data ssp_blob[SSP_MAX_DAIS][SSP_MAX_HW_CONFIG]; struct ssp_intel_config_data ssp_blob[SSP_MAX_DAIS][SSP_MAX_HW_CONFIG];
struct ssp_aux_blob ssp_blob_ext[SSP_MAX_DAIS][SSP_MAX_HW_CONFIG];
}; };
#define SSP_MN_DIVIDER_CONTROLS 0
#define SSP_DMA_CLK_CONTROLS 1
#define SSP_DMA_TRANSMISSION_START 2
#define SSP_DMA_TRANSMISSION_STOP 3
#define SSP_DMA_ALWAYS_RUNNING_MODE 4
#define SSP_DMA_SYNC_DATA 5
#define SSP_DMA_CLK_CONTROLS_EXT 6
#define SSP_LINK_CLK_SOURCE 7
/* officially "undefined" node for topology parsing */
#define SSP_DMA_SYNC_NODE 32
#define SSP_CLOCK_XTAL_OSCILLATOR 0x0 #define SSP_CLOCK_XTAL_OSCILLATOR 0x0
#define SSP_CLOCK_AUDIO_CARDINAL 0x1 #define SSP_CLOCK_AUDIO_CARDINAL 0x1
#define SSP_CLOCK_PLL_FIXED 0x2 #define SSP_CLOCK_PLL_FIXED 0x2

View file

@ -511,6 +511,186 @@ static int ssp_calculate_intern(struct intel_nhlt_params *nhlt, int hwi)
return 0; return 0;
} }
static int ssp_calculate_intern_ext(struct intel_nhlt_params *nhlt, int hwi)
{
size_t aux_size, mn_size, clk_size, tr_size, run_size, sync_size, node_size, ext_size,
link_size, size, total_size;
struct intel_ssp_params *ssp;
struct ssp_config_aux *aux;
struct ssp_intel_aux_tlv *tlv;
struct ssp_intel_mn_ctl *mn;
struct ssp_intel_clk_ctl *clk;
struct ssp_intel_tr_ctl *tr;
struct ssp_intel_run_ctl *run;
struct ssp_intel_sync_ctl *sync;
struct ssp_intel_node_ctl *node;
struct ssp_intel_ext_ctl *ext;
struct ssp_intel_link_ctl *link;
uint8_t *aux_blob;
uint32_t enabled;
int di, i;
aux_size = sizeof(struct ssp_intel_aux_tlv);
mn_size = sizeof(struct ssp_intel_mn_ctl);
clk_size = sizeof(struct ssp_intel_clk_ctl);
tr_size = sizeof(struct ssp_intel_tr_ctl);
run_size = sizeof(struct ssp_intel_run_ctl);
sync_size = sizeof(struct ssp_intel_sync_ctl);
node_size = sizeof(struct ssp_intel_node_ctl);
ext_size = sizeof(struct ssp_intel_ext_ctl);
link_size = sizeof(struct ssp_intel_link_ctl);
ssp = (struct intel_ssp_params *)nhlt->ssp_params;
di = ssp->ssp_count;
enabled = ssp->ssp_prm[di].aux_cfg[hwi].enabled;
aux = &(ssp->ssp_prm[di].aux_cfg[hwi]);
aux_blob = ssp->ssp_blob_ext[di][hwi].aux_blob;
total_size = 0;
size = 0;
if (enabled & BIT(SSP_MN_DIVIDER_CONTROLS)) {
tlv = (struct ssp_intel_aux_tlv *)aux_blob;
mn = (struct ssp_intel_mn_ctl *)(aux_blob + aux_size);
size = mn_size + aux_size;
tlv->type = SSP_MN_DIVIDER_CONTROLS;
tlv->size = mn_size;
mn->div_m = aux->mn.m_div;
mn->div_n = aux->mn.n_div;
aux_blob += size;
total_size += size;
}
if (enabled & BIT(SSP_DMA_CLK_CONTROLS)) {
tlv = (struct ssp_intel_aux_tlv *)aux_blob;
clk = (struct ssp_intel_clk_ctl *)(aux_blob + aux_size);
size = clk_size + aux_size;
tlv->type = SSP_DMA_CLK_CONTROLS;
tlv->size = clk_size;
clk->start |= SET_BITS(15, 0, aux->clk.clock_warm_up);
clk->start |= SET_BIT(16, aux->clk.mclk);
clk->start |= SET_BIT(17, aux->clk.warm_up_ovr);
clk->stop |= SET_BITS(15, 0, aux->clk.clock_stop_delay);
clk->stop |= SET_BIT(16, aux->clk.keep_running);
clk->stop |= SET_BIT(17, aux->clk.clock_stop_ovr);
aux_blob += size;
total_size += size;
}
if (enabled & BIT(SSP_DMA_TRANSMISSION_START)) {
tlv = (struct ssp_intel_aux_tlv *)aux_blob;
tr = (struct ssp_intel_tr_ctl *)(aux_blob + aux_size);
size = tr_size + aux_size;
tlv->type = SSP_DMA_TRANSMISSION_START;
tlv->size = tr_size;
tr->sampling_frequency = aux->tr_start.sampling_frequency;
tr->bit_depth = aux->tr_start.bit_depth;
tr->channel_map = aux->tr_start.channel_map;
tr->channel_config = aux->tr_start.channel_config;
tr->interleaving_style = aux->tr_start.interleaving_style;
tr->format |= SET_BITS(7, 0, aux->tr_start.number_of_channels);
tr->format |= SET_BITS(15, 8, aux->tr_start.valid_bit_depth);
tr->format |= SET_BITS(23, 16, aux->tr_start.sample_type);
aux_blob += size;
total_size += size;
}
if (enabled & BIT(SSP_DMA_TRANSMISSION_STOP)) {
tlv = (struct ssp_intel_aux_tlv *)aux_blob;
tr = (struct ssp_intel_tr_ctl *)(aux_blob + aux_size);
size = tr_size + aux_size;
tlv->type = SSP_DMA_TRANSMISSION_STOP;
tlv->size = tr_size;
tr->sampling_frequency = aux->tr_stop.sampling_frequency;
tr->bit_depth = aux->tr_stop.bit_depth;
tr->channel_map = aux->tr_stop.channel_map;
tr->channel_config = aux->tr_stop.channel_config;
tr->interleaving_style = aux->tr_stop.interleaving_style;
tr->format |= SET_BITS(7, 0, aux->tr_stop.number_of_channels);
tr->format |= SET_BITS(15, 8, aux->tr_stop.valid_bit_depth);
tr->format |= SET_BITS(23, 16, aux->tr_stop.sample_type);
aux_blob += size;
total_size += size;
}
if (enabled & BIT(SSP_DMA_ALWAYS_RUNNING_MODE)) {
tlv = (struct ssp_intel_aux_tlv *)aux_blob;
run = (struct ssp_intel_run_ctl *)(aux_blob + aux_size);
size = run_size + aux_size;
tlv->type = SSP_DMA_ALWAYS_RUNNING_MODE;
tlv->size = run_size;
run->enabled = aux->run.always_run;
aux_blob += size;
total_size += size;
}
if (enabled & BIT(SSP_DMA_SYNC_DATA)) {
tlv = (struct ssp_intel_aux_tlv *)aux_blob;
sync = (struct ssp_intel_sync_ctl *)(aux_blob + aux_size);
size = sync_size + aux_size;
tlv->type = SSP_DMA_SYNC_DATA;
tlv->size = sync_size;
sync->sync_denominator = aux->sync.sync_denominator;
sync->count = aux->sync.count;
aux_blob += size;
total_size += size;
for (i = 0; i < sync->count; i++) {
node = (struct ssp_intel_node_ctl *)(aux_blob);
size = node_size;
node->node_id = aux->sync.nodes[i].node_id;
node->sampling_rate = aux->sync.nodes[i].sampling_rate;
tlv->size += node_size;
aux_blob += size;
total_size += size;
}
}
if (enabled & BIT(SSP_DMA_CLK_CONTROLS_EXT)) {
tlv = (struct ssp_intel_aux_tlv *)aux_blob;
ext = (struct ssp_intel_ext_ctl *)(aux_blob + aux_size);
size = ext_size + aux_size;
tlv->type = SSP_DMA_CLK_CONTROLS_EXT;
tlv->size = ext_size;
ext->ext_data |= SET_BIT(0, aux->ext.mclk_policy_override);
ext->ext_data |= SET_BIT(1, aux->ext.mclk_always_running);
ext->ext_data |= SET_BIT(2, aux->ext.mclk_starts_on_gtw_init);
ext->ext_data |= SET_BIT(3, aux->ext.mclk_starts_on_run);
ext->ext_data |= SET_BIT(4, aux->ext.mclk_starts_on_pause);
ext->ext_data |= SET_BIT(5, aux->ext.mclk_stops_on_pause);
ext->ext_data |= SET_BIT(6, aux->ext.mclk_stops_on_reset);
ext->ext_data |= SET_BIT(8, aux->ext.bclk_policy_override);
ext->ext_data |= SET_BIT(9, aux->ext.bclk_always_running);
ext->ext_data |= SET_BIT(10, aux->ext.bclk_starts_on_gtw_init);
ext->ext_data |= SET_BIT(11, aux->ext.bclk_starts_on_run);
ext->ext_data |= SET_BIT(12, aux->ext.bclk_starts_on_pause);
ext->ext_data |= SET_BIT(13, aux->ext.bclk_stops_on_pause);
ext->ext_data |= SET_BIT(14, aux->ext.bclk_stops_on_reset);
ext->ext_data |= SET_BIT(16, aux->ext.sync_policy_override);
ext->ext_data |= SET_BIT(17, aux->ext.sync_always_running);
ext->ext_data |= SET_BIT(18, aux->ext.sync_starts_on_gtw_init);
ext->ext_data |= SET_BIT(19, aux->ext.sync_starts_on_run);
ext->ext_data |= SET_BIT(20, aux->ext.sync_starts_on_pause);
ext->ext_data |= SET_BIT(21, aux->ext.sync_stops_on_pause);
ext->ext_data |= SET_BIT(22, aux->ext.sync_stops_on_reset);
aux_blob += size;
total_size += size;
}
if (enabled & BIT(SSP_LINK_CLK_SOURCE)) {
tlv = (struct ssp_intel_aux_tlv *)aux_blob;
link = (struct ssp_intel_link_ctl *)(aux_blob + aux_size);
size = link_size + aux_size;
tlv->type = SSP_LINK_CLK_SOURCE;
tlv->size = link_size;
link->clock_source = aux->link.clock_source;
aux_blob += size;
total_size += size;
}
ssp->ssp_blob_ext[di][hwi].size = total_size;
return 0;
}
int ssp_calculate(struct intel_nhlt_params *nhlt) int ssp_calculate(struct intel_nhlt_params *nhlt)
{ {
struct intel_ssp_params *ssp = (struct intel_ssp_params *)nhlt->ssp_params; struct intel_ssp_params *ssp = (struct intel_ssp_params *)nhlt->ssp_params;
@ -520,9 +700,12 @@ int ssp_calculate(struct intel_nhlt_params *nhlt)
return -EINVAL; return -EINVAL;
/* calculate blob for every hw config */ /* calculate blob for every hw config */
for (i = 0; i < ssp->ssp_hw_config_count[ssp->ssp_count]; i++) for (i = 0; i < ssp->ssp_hw_config_count[ssp->ssp_count]; i++) {
if (ssp_calculate_intern(nhlt, i) < 0) if (ssp_calculate_intern(nhlt, i) < 0)
return -EINVAL; return -EINVAL;
if (ssp_calculate_intern_ext(nhlt, i) < 0)
return -EINVAL;
}
ssp_print_internal(ssp); ssp_print_internal(ssp);
ssp_print_calculated(ssp); ssp_print_calculated(ssp);
@ -579,9 +762,13 @@ int ssp_get_hw_params(struct intel_nhlt_params *nhlt, int dai_index, int hw_inde
* Supposed to be called after all ssp DAIs are parsed from topology and the final nhlt blob is * Supposed to be called after all ssp DAIs are parsed from topology and the final nhlt blob is
* generated. * generated.
*/ */
int ssp_get_vendor_blob_size(struct intel_nhlt_params *nhlt, size_t *size) int ssp_get_vendor_blob_size(struct intel_nhlt_params *nhlt, int dai_index,
int hw_config_index, size_t *size)
{ {
*size = sizeof(struct ssp_intel_config_data); struct intel_ssp_params *ssp = (struct intel_ssp_params *)nhlt->ssp_params;
*size = sizeof(struct ssp_intel_config_data) +
ssp->ssp_blob_ext[dai_index][hw_config_index].size;
return 0; return 0;
} }
@ -609,6 +796,11 @@ int ssp_get_vendor_blob(struct intel_nhlt_params *nhlt, uint8_t *vendor_blob,
memcpy(vendor_blob, &ssp->ssp_blob[dai_index][hw_config_index], memcpy(vendor_blob, &ssp->ssp_blob[dai_index][hw_config_index],
sizeof(struct ssp_intel_config_data)); sizeof(struct ssp_intel_config_data));
/* ext data */
memcpy(vendor_blob + sizeof(struct ssp_intel_config_data),
ssp->ssp_blob_ext[dai_index][hw_config_index].aux_blob,
ssp->ssp_blob_ext[dai_index][hw_config_index].size);
return 0; return 0;
} }
@ -726,11 +918,224 @@ int ssp_hw_set_params(struct intel_nhlt_params *nhlt, const char *format, const
return 0; return 0;
} }
int ssp_mn_set_params(struct intel_nhlt_params *nhlt, int m_div, int n_div)
{
struct intel_ssp_params *ssp = (struct intel_ssp_params *)nhlt->ssp_params;
int di = ssp->ssp_count;
int hwi = ssp->ssp_hw_config_count[di];
if (di < 0 || hwi < 0)
return -EINVAL;
ssp->ssp_prm[di].aux_cfg[hwi].enabled |= BIT(SSP_MN_DIVIDER_CONTROLS);
ssp->ssp_prm[di].aux_cfg[hwi].mn.m_div = m_div;
ssp->ssp_prm[di].aux_cfg[hwi].mn.n_div = n_div;
return 0;
}
int ssp_clk_set_params(struct intel_nhlt_params *nhlt, int clock_warm_up, int mclk, int warm_up_ovr,
int clock_stop_delay, int keep_running, int clock_stop_ovr)
{
struct intel_ssp_params *ssp = (struct intel_ssp_params *)nhlt->ssp_params;
int di = ssp->ssp_count;
int hwi = ssp->ssp_hw_config_count[di];
if (di < 0 || hwi < 0)
return -EINVAL;
ssp->ssp_prm[di].aux_cfg[hwi].enabled |= BIT(SSP_DMA_CLK_CONTROLS);
ssp->ssp_prm[di].aux_cfg[hwi].clk.clock_warm_up = clock_warm_up;
ssp->ssp_prm[di].aux_cfg[hwi].clk.mclk = mclk;
ssp->ssp_prm[di].aux_cfg[hwi].clk.warm_up_ovr = warm_up_ovr;
ssp->ssp_prm[di].aux_cfg[hwi].clk.clock_stop_delay = clock_stop_delay;
ssp->ssp_prm[di].aux_cfg[hwi].clk.keep_running = keep_running;
ssp->ssp_prm[di].aux_cfg[hwi].clk.clock_stop_ovr = clock_stop_ovr;
return 0;
}
int ssp_tr_start_set_params(struct intel_nhlt_params *nhlt, int sampling_frequency,
int bit_depth, int channel_map, int channel_config,
int interleaving_style, int number_of_channels,
int valid_bit_depth, int sample_type)
{
struct intel_ssp_params *ssp;
struct ssp_aux_config_tr *tr;
int di, hwi;
ssp = (struct intel_ssp_params *)nhlt->ssp_params;
di = ssp->ssp_count;
hwi = ssp->ssp_hw_config_count[di];
if (di < 0 || hwi < 0)
return -EINVAL;
tr = (struct ssp_aux_config_tr *)&(ssp->ssp_prm[di].aux_cfg[hwi].tr_start);
ssp->ssp_prm[di].aux_cfg[hwi].enabled |= BIT(SSP_DMA_TRANSMISSION_START);
tr->sampling_frequency = sampling_frequency;
tr->bit_depth = bit_depth;
tr->channel_map = channel_map;
tr->channel_config = channel_config;
tr->interleaving_style = interleaving_style;
tr->number_of_channels = number_of_channels;
tr->valid_bit_depth = valid_bit_depth;
tr->sample_type = sample_type;
return 0;
}
int ssp_tr_stop_set_params(struct intel_nhlt_params *nhlt, int sampling_frequency,
int bit_depth, int channel_map, int channel_config,
int interleaving_style, int number_of_channels,
int valid_bit_depth, int sample_type)
{
struct intel_ssp_params *ssp;
struct ssp_aux_config_tr *tr;
int di, hwi;
ssp = (struct intel_ssp_params *)nhlt->ssp_params;
di = ssp->ssp_count;
hwi = ssp->ssp_hw_config_count[di];
if (di < 0 || hwi < 0)
return -EINVAL;
tr = (struct ssp_aux_config_tr *)&(ssp->ssp_prm[di].aux_cfg[hwi].tr_stop);
ssp->ssp_prm[di].aux_cfg[hwi].enabled |= BIT(SSP_DMA_TRANSMISSION_STOP);
tr->sampling_frequency = sampling_frequency;
tr->bit_depth = bit_depth;
tr->channel_map = channel_map;
tr->channel_config = channel_config;
tr->interleaving_style = interleaving_style;
tr->number_of_channels = number_of_channels;
tr->valid_bit_depth = valid_bit_depth;
tr->sample_type = sample_type;
return 0;
}
int ssp_run_set_params(struct intel_nhlt_params *nhlt, int always_run)
{
struct intel_ssp_params *ssp = (struct intel_ssp_params *)nhlt->ssp_params;
int di = ssp->ssp_count;
int hwi = ssp->ssp_hw_config_count[di];
if (di < 0 || hwi < 0)
return -EINVAL;
ssp->ssp_prm[di].aux_cfg[hwi].enabled |= BIT(SSP_DMA_ALWAYS_RUNNING_MODE);
ssp->ssp_prm[di].aux_cfg[hwi].run.always_run = always_run;
return 0;
}
int ssp_sync_set_params(struct intel_nhlt_params *nhlt, int sync_denominator)
{
struct intel_ssp_params *ssp = (struct intel_ssp_params *)nhlt->ssp_params;
int di = ssp->ssp_count;
int hwi = ssp->ssp_hw_config_count[di];
if (di < 0 || hwi < 0)
return -EINVAL;
ssp->ssp_prm[di].aux_cfg[hwi].enabled |= BIT(SSP_DMA_SYNC_DATA);
ssp->ssp_prm[di].aux_cfg[hwi].sync.sync_denominator = sync_denominator;
return 0;
}
int ssp_node_set_params(struct intel_nhlt_params *nhlt, int node_id, int sampling_rate)
{
struct intel_ssp_params *ssp = (struct intel_ssp_params *)nhlt->ssp_params;
int di = ssp->ssp_count;
int hwi = ssp->ssp_hw_config_count[di];
int count;
if (di < 0 || hwi < 0)
return -EINVAL;
count = ssp->ssp_prm[di].aux_cfg[hwi].sync.count;
if (count > SSP_MAX_DAIS)
return -EINVAL;
ssp->ssp_prm[di].aux_cfg[hwi].sync.nodes[count].node_id = node_id;
ssp->ssp_prm[di].aux_cfg[hwi].sync.nodes[count].sampling_rate = sampling_rate;
ssp->ssp_prm[di].aux_cfg[hwi].sync.count++;
return 0;
}
int ssp_ext_set_params(struct intel_nhlt_params *nhlt, int mclk_policy_override,
int mclk_always_running, int mclk_starts_on_gtw_init, int mclk_starts_on_run,
int mclk_starts_on_pause, int mclk_stops_on_pause, int mclk_stops_on_reset,
int bclk_policy_override, int bclk_always_running,
int bclk_starts_on_gtw_init, int bclk_starts_on_run,
int bclk_starts_on_pause, int bclk_stops_on_pause, int bclk_stops_on_reset,
int sync_policy_override, int sync_always_running,
int sync_starts_on_gtw_init, int sync_starts_on_run,
int sync_starts_on_pause, int sync_stops_on_pause, int sync_stops_on_reset)
{
struct intel_ssp_params *ssp = (struct intel_ssp_params *)nhlt->ssp_params;
int di = ssp->ssp_count;
int hwi = ssp->ssp_hw_config_count[di];
if (di < 0 || hwi < 0)
return -EINVAL;
ssp->ssp_prm[di].aux_cfg[hwi].enabled |= BIT(SSP_DMA_CLK_CONTROLS_EXT);
ssp->ssp_prm[di].aux_cfg[hwi].ext.mclk_policy_override = mclk_policy_override;
ssp->ssp_prm[di].aux_cfg[hwi].ext.mclk_always_running = mclk_always_running;
ssp->ssp_prm[di].aux_cfg[hwi].ext.mclk_starts_on_gtw_init = mclk_starts_on_gtw_init;
ssp->ssp_prm[di].aux_cfg[hwi].ext.mclk_starts_on_run = mclk_starts_on_run;
ssp->ssp_prm[di].aux_cfg[hwi].ext.mclk_starts_on_pause = mclk_starts_on_pause;
ssp->ssp_prm[di].aux_cfg[hwi].ext.mclk_stops_on_pause = mclk_stops_on_pause;
ssp->ssp_prm[di].aux_cfg[hwi].ext.mclk_stops_on_reset = mclk_stops_on_reset;
ssp->ssp_prm[di].aux_cfg[hwi].ext.bclk_policy_override = bclk_policy_override;
ssp->ssp_prm[di].aux_cfg[hwi].ext.bclk_always_running = bclk_always_running;
ssp->ssp_prm[di].aux_cfg[hwi].ext.bclk_starts_on_gtw_init = bclk_starts_on_gtw_init;
ssp->ssp_prm[di].aux_cfg[hwi].ext.bclk_starts_on_run = bclk_starts_on_run;
ssp->ssp_prm[di].aux_cfg[hwi].ext.bclk_starts_on_pause = bclk_starts_on_pause;
ssp->ssp_prm[di].aux_cfg[hwi].ext.bclk_stops_on_pause = bclk_stops_on_pause;
ssp->ssp_prm[di].aux_cfg[hwi].ext.bclk_stops_on_reset = bclk_stops_on_reset;
ssp->ssp_prm[di].aux_cfg[hwi].ext.sync_policy_override = sync_policy_override;
ssp->ssp_prm[di].aux_cfg[hwi].ext.sync_always_running = sync_always_running;
ssp->ssp_prm[di].aux_cfg[hwi].ext.sync_starts_on_gtw_init = sync_starts_on_gtw_init;
ssp->ssp_prm[di].aux_cfg[hwi].ext.sync_starts_on_run = sync_starts_on_run;
ssp->ssp_prm[di].aux_cfg[hwi].ext.sync_starts_on_pause = sync_starts_on_pause;
ssp->ssp_prm[di].aux_cfg[hwi].ext.sync_stops_on_pause = sync_stops_on_pause;
ssp->ssp_prm[di].aux_cfg[hwi].ext.sync_stops_on_reset = sync_stops_on_reset;
return 0;
}
int ssp_link_set_params(struct intel_nhlt_params *nhlt, int clock_source)
{
struct intel_ssp_params *ssp = (struct intel_ssp_params *)nhlt->ssp_params;
int di = ssp->ssp_count;
int hwi = ssp->ssp_hw_config_count[di];
if (di < 0 || hwi < 0)
return -EINVAL;
ssp->ssp_prm[di].aux_cfg[hwi].enabled |= BIT(SSP_LINK_CLK_SOURCE);
ssp->ssp_prm[di].aux_cfg[hwi].link.clock_source = clock_source;
return 0;
}
/* init ssp parameters, should be called before parsing dais */ /* init ssp parameters, should be called before parsing dais */
int ssp_init_params(struct intel_nhlt_params *nhlt) int ssp_init_params(struct intel_nhlt_params *nhlt)
{ {
struct intel_ssp_params *ssp; struct intel_ssp_params *ssp;
int i; int i, j;
ssp = calloc(1, sizeof(struct intel_ssp_params)); ssp = calloc(1, sizeof(struct intel_ssp_params));
if (!ssp) if (!ssp)
@ -739,8 +1144,11 @@ int ssp_init_params(struct intel_nhlt_params *nhlt)
nhlt->ssp_params = ssp; nhlt->ssp_params = ssp;
ssp->ssp_count = 0; ssp->ssp_count = 0;
for (i = 0; i < SSP_MAX_DAIS; i++) for (i = 0; i < SSP_MAX_DAIS; i++) {
ssp->ssp_hw_config_count[i] = 0; ssp->ssp_hw_config_count[i] = 0;
for (j = 0; j < SSP_MAX_HW_CONFIG; j++)
ssp->ssp_prm[i].aux_cfg[j].sync.count = 0;
}
return 0; return 0;
} }

View file

@ -24,6 +24,32 @@ int ssp_hw_set_params(struct intel_nhlt_params *nhlt, const char *format, const
const char *fsync_invert, int mclk_freq, int bclk_freq, int fsync_freq, const char *fsync_invert, int mclk_freq, int bclk_freq, int fsync_freq,
int tdm_slots, int tdm_slot_width, int tx_slots, int rx_slots); int tdm_slots, int tdm_slot_width, int tx_slots, int rx_slots);
/* set aux params when parsing topology2 conf */
int ssp_mn_set_params(struct intel_nhlt_params *nhlt, int m_div, int n_div);
int ssp_clk_set_params(struct intel_nhlt_params *nhlt, int clock_warm_up, int mclk, int warm_up_ovr,
int clock_stop_delay, int keep_running, int clock_stop_ovr);
int ssp_tr_start_set_params(struct intel_nhlt_params *nhlt, int sampling_frequency,
int bit_depth, int channel_map, int hannel_config,
int interleaving_style, int number_of_channels,
int valid_bit_depth, int sample_type);
int ssp_tr_stop_set_params(struct intel_nhlt_params *nhlt, int sampling_frequency,
int bit_depth, int channel_map, int hannel_config,
int interleaving_style, int number_of_channels,
int valid_bit_depth, int sample_type);
int ssp_run_set_params(struct intel_nhlt_params *nhlt, int always_run);
int ssp_sync_set_params(struct intel_nhlt_params *nhlt, int sync_denominator);
int ssp_node_set_params(struct intel_nhlt_params *nhlt, int node_id, int sampling_rate);
int ssp_ext_set_params(struct intel_nhlt_params *nhlt, int mclk_policy_override,
int mclk_always_running, int mclk_starts_on_gtw_init, int mclk_starts_on_run,
int mclk_starts_on_pause, int mclk_stops_on_pause, int mclk_stops_on_reset,
int bclk_policy_override, int bclk_always_running,
int bclk_starts_on_gtw_init, int bclk_starts_on_run,
int bclk_starts_on_pause, int bclk_stops_on_pause, int bclk_stops_on_reset,
int sync_policy_override, int sync_always_running,
int sync_starts_on_gtw_init, int sync_starts_on_run,
int sync_starts_on_pause, int sync_stops_on_pause, int sync_stops_on_reset);
int ssp_link_set_params(struct intel_nhlt_params *nhlt, int clock_source);
/* calculate the blob after parsing the values*/ /* calculate the blob after parsing the values*/
int ssp_calculate(struct intel_nhlt_params *nhlt); int ssp_calculate(struct intel_nhlt_params *nhlt);
/* get spec parameters when building the nhlt endpoint */ /* get spec parameters when building the nhlt endpoint */
@ -34,7 +60,8 @@ int ssp_get_hw_params(struct intel_nhlt_params *nhlt, int dai_index, int hw_inde
int ssp_get_dir(struct intel_nhlt_params *nhlt, int dai_index, uint8_t *dir); int ssp_get_dir(struct intel_nhlt_params *nhlt, int dai_index, uint8_t *dir);
/* get vendor specific blob when building the nhlt endpoint */ /* get vendor specific blob when building the nhlt endpoint */
int ssp_get_vendor_blob_count(struct intel_nhlt_params *nhlt); int ssp_get_vendor_blob_count(struct intel_nhlt_params *nhlt);
int ssp_get_vendor_blob_size(struct intel_nhlt_params *nhlt, size_t *size); int ssp_get_vendor_blob_size(struct intel_nhlt_params *nhlt, int dai_index, int hw_config_index,
size_t *size);
int ssp_get_vendor_blob(struct intel_nhlt_params *nhlt, uint8_t *vendor_blob, int dai_index, int ssp_get_vendor_blob(struct intel_nhlt_params *nhlt, uint8_t *vendor_blob, int dai_index,
int hw_config_index); int hw_config_index);