Commit 864cee90 authored by Jerome Brunet's avatar Jerome Brunet Committed by Mark Brown

ASoC: meson: axg-fifo: fix fifo threshold setup

On TODDR sm1, the fifo threshold register field is slightly different
compared to the other SoCs. This leads to the fifo A being flushed to
memory every 8kB. If the period is smaller than that, several periods
are pushed to memory and notified at once. This is not ideal.

Fix the register field update. With this, the fifos are flushed every
128B. We could still do better, like adapt the threshold depending on
the period size, but at least it consistent across the different
SoC/fifos

Fixes: 5ac825c3 ("ASoC: meson: axg-toddr: add sm1 support")
Reported-by: default avatarAlden DSouza <aldend@google.com>
Signed-off-by: default avatarJerome Brunet <jbrunet@baylibre.com>
Link: https://lore.kernel.org/r/20191218172420.1199117-2-jbrunet@baylibre.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 72b46612
...@@ -113,8 +113,10 @@ int axg_fifo_pcm_hw_params(struct snd_soc_component *component, ...@@ -113,8 +113,10 @@ int axg_fifo_pcm_hw_params(struct snd_soc_component *component,
{ {
struct snd_pcm_runtime *runtime = ss->runtime; struct snd_pcm_runtime *runtime = ss->runtime;
struct axg_fifo *fifo = axg_fifo_data(ss); struct axg_fifo *fifo = axg_fifo_data(ss);
unsigned int burst_num, period, threshold;
dma_addr_t end_ptr; dma_addr_t end_ptr;
unsigned int burst_num;
period = params_period_bytes(params);
/* Setup dma memory pointers */ /* Setup dma memory pointers */
end_ptr = runtime->dma_addr + runtime->dma_bytes - AXG_FIFO_BURST; end_ptr = runtime->dma_addr + runtime->dma_bytes - AXG_FIFO_BURST;
...@@ -122,9 +124,25 @@ int axg_fifo_pcm_hw_params(struct snd_soc_component *component, ...@@ -122,9 +124,25 @@ int axg_fifo_pcm_hw_params(struct snd_soc_component *component,
regmap_write(fifo->map, FIFO_FINISH_ADDR, end_ptr); regmap_write(fifo->map, FIFO_FINISH_ADDR, end_ptr);
/* Setup interrupt periodicity */ /* Setup interrupt periodicity */
burst_num = params_period_bytes(params) / AXG_FIFO_BURST; burst_num = period / AXG_FIFO_BURST;
regmap_write(fifo->map, FIFO_INT_ADDR, burst_num); regmap_write(fifo->map, FIFO_INT_ADDR, burst_num);
/*
* Start the fifo request on the smallest of the following:
* - Half the fifo size
* - Half the period size
*/
threshold = min(period / 2,
(unsigned int)AXG_FIFO_MIN_DEPTH / 2);
/*
* With the threshold in bytes, register value is:
* V = (threshold / burst) - 1
*/
threshold /= AXG_FIFO_BURST;
regmap_field_write(fifo->field_threshold,
threshold ? threshold - 1 : 0);
/* Enable block count irq */ /* Enable block count irq */
regmap_update_bits(fifo->map, FIFO_CTRL0, regmap_update_bits(fifo->map, FIFO_CTRL0,
CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT), CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT),
...@@ -347,6 +365,11 @@ int axg_fifo_probe(struct platform_device *pdev) ...@@ -347,6 +365,11 @@ int axg_fifo_probe(struct platform_device *pdev)
return fifo->irq; return fifo->irq;
} }
fifo->field_threshold =
devm_regmap_field_alloc(dev, fifo->map, data->field_threshold);
if (IS_ERR(fifo->field_threshold))
return PTR_ERR(fifo->field_threshold);
return devm_snd_soc_register_component(dev, data->component_drv, return devm_snd_soc_register_component(dev, data->component_drv,
data->dai_drv, 1); data->dai_drv, 1);
} }
......
...@@ -9,7 +9,9 @@ ...@@ -9,7 +9,9 @@
struct clk; struct clk;
struct platform_device; struct platform_device;
struct reg_field;
struct regmap; struct regmap;
struct regmap_field;
struct reset_control; struct reset_control;
struct snd_soc_component_driver; struct snd_soc_component_driver;
...@@ -50,8 +52,6 @@ struct snd_soc_pcm_runtime; ...@@ -50,8 +52,6 @@ struct snd_soc_pcm_runtime;
#define CTRL1_STATUS2_SEL_MASK GENMASK(11, 8) #define CTRL1_STATUS2_SEL_MASK GENMASK(11, 8)
#define CTRL1_STATUS2_SEL(x) ((x) << 8) #define CTRL1_STATUS2_SEL(x) ((x) << 8)
#define STATUS2_SEL_DDR_READ 0 #define STATUS2_SEL_DDR_READ 0
#define CTRL1_THRESHOLD_MASK GENMASK(23, 16)
#define CTRL1_THRESHOLD(x) ((x) << 16)
#define CTRL1_FRDDR_DEPTH_MASK GENMASK(31, 24) #define CTRL1_FRDDR_DEPTH_MASK GENMASK(31, 24)
#define CTRL1_FRDDR_DEPTH(x) ((x) << 24) #define CTRL1_FRDDR_DEPTH(x) ((x) << 24)
#define FIFO_START_ADDR 0x08 #define FIFO_START_ADDR 0x08
...@@ -67,12 +67,14 @@ struct axg_fifo { ...@@ -67,12 +67,14 @@ struct axg_fifo {
struct regmap *map; struct regmap *map;
struct clk *pclk; struct clk *pclk;
struct reset_control *arb; struct reset_control *arb;
struct regmap_field *field_threshold;
int irq; int irq;
}; };
struct axg_fifo_match_data { struct axg_fifo_match_data {
const struct snd_soc_component_driver *component_drv; const struct snd_soc_component_driver *component_drv;
struct snd_soc_dai_driver *dai_drv; struct snd_soc_dai_driver *dai_drv;
struct reg_field field_threshold;
}; };
int axg_fifo_pcm_open(struct snd_soc_component *component, int axg_fifo_pcm_open(struct snd_soc_component *component,
......
...@@ -50,7 +50,7 @@ static int axg_frddr_dai_startup(struct snd_pcm_substream *substream, ...@@ -50,7 +50,7 @@ static int axg_frddr_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai); struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
unsigned int fifo_depth, fifo_threshold; unsigned int fifo_depth;
int ret; int ret;
/* Enable pclk to access registers and clock the fifo ip */ /* Enable pclk to access registers and clock the fifo ip */
...@@ -68,11 +68,8 @@ static int axg_frddr_dai_startup(struct snd_pcm_substream *substream, ...@@ -68,11 +68,8 @@ static int axg_frddr_dai_startup(struct snd_pcm_substream *substream,
* Depth and threshold are zero based. * Depth and threshold are zero based.
*/ */
fifo_depth = AXG_FIFO_MIN_CNT - 1; fifo_depth = AXG_FIFO_MIN_CNT - 1;
fifo_threshold = (AXG_FIFO_MIN_CNT / 2) - 1; regmap_update_bits(fifo->map, FIFO_CTRL1, CTRL1_FRDDR_DEPTH_MASK,
regmap_update_bits(fifo->map, FIFO_CTRL1, CTRL1_FRDDR_DEPTH(fifo_depth));
CTRL1_FRDDR_DEPTH_MASK | CTRL1_THRESHOLD_MASK,
CTRL1_FRDDR_DEPTH(fifo_depth) |
CTRL1_THRESHOLD(fifo_threshold));
return 0; return 0;
} }
...@@ -158,8 +155,9 @@ static const struct snd_soc_component_driver axg_frddr_component_drv = { ...@@ -158,8 +155,9 @@ static const struct snd_soc_component_driver axg_frddr_component_drv = {
}; };
static const struct axg_fifo_match_data axg_frddr_match_data = { static const struct axg_fifo_match_data axg_frddr_match_data = {
.component_drv = &axg_frddr_component_drv, .field_threshold = REG_FIELD(FIFO_CTRL1, 16, 23),
.dai_drv = &axg_frddr_dai_drv .component_drv = &axg_frddr_component_drv,
.dai_drv = &axg_frddr_dai_drv
}; };
static const struct snd_soc_dai_ops g12a_frddr_ops = { static const struct snd_soc_dai_ops g12a_frddr_ops = {
...@@ -281,8 +279,9 @@ static const struct snd_soc_component_driver g12a_frddr_component_drv = { ...@@ -281,8 +279,9 @@ static const struct snd_soc_component_driver g12a_frddr_component_drv = {
}; };
static const struct axg_fifo_match_data g12a_frddr_match_data = { static const struct axg_fifo_match_data g12a_frddr_match_data = {
.component_drv = &g12a_frddr_component_drv, .field_threshold = REG_FIELD(FIFO_CTRL1, 16, 23),
.dai_drv = &g12a_frddr_dai_drv .component_drv = &g12a_frddr_component_drv,
.dai_drv = &g12a_frddr_dai_drv
}; };
/* On SM1, the output selection in on CTRL2 */ /* On SM1, the output selection in on CTRL2 */
...@@ -350,8 +349,9 @@ static const struct snd_soc_component_driver sm1_frddr_component_drv = { ...@@ -350,8 +349,9 @@ static const struct snd_soc_component_driver sm1_frddr_component_drv = {
}; };
static const struct axg_fifo_match_data sm1_frddr_match_data = { static const struct axg_fifo_match_data sm1_frddr_match_data = {
.component_drv = &sm1_frddr_component_drv, .field_threshold = REG_FIELD(FIFO_CTRL1, 16, 23),
.dai_drv = &g12a_frddr_dai_drv .component_drv = &sm1_frddr_component_drv,
.dai_drv = &g12a_frddr_dai_drv
}; };
static const struct of_device_id axg_frddr_of_match[] = { static const struct of_device_id axg_frddr_of_match[] = {
......
...@@ -89,7 +89,6 @@ static int axg_toddr_dai_startup(struct snd_pcm_substream *substream, ...@@ -89,7 +89,6 @@ static int axg_toddr_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai); struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
unsigned int fifo_threshold;
int ret; int ret;
/* Enable pclk to access registers and clock the fifo ip */ /* Enable pclk to access registers and clock the fifo ip */
...@@ -107,11 +106,6 @@ static int axg_toddr_dai_startup(struct snd_pcm_substream *substream, ...@@ -107,11 +106,6 @@ static int axg_toddr_dai_startup(struct snd_pcm_substream *substream,
/* Apply single buffer mode to the interface */ /* Apply single buffer mode to the interface */
regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_TODDR_PP_MODE, 0); regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_TODDR_PP_MODE, 0);
/* TODDR does not have a configurable fifo depth */
fifo_threshold = AXG_FIFO_MIN_CNT - 1;
regmap_update_bits(fifo->map, FIFO_CTRL1, CTRL1_THRESHOLD_MASK,
CTRL1_THRESHOLD(fifo_threshold));
return 0; return 0;
} }
...@@ -190,8 +184,9 @@ static const struct snd_soc_component_driver axg_toddr_component_drv = { ...@@ -190,8 +184,9 @@ static const struct snd_soc_component_driver axg_toddr_component_drv = {
}; };
static const struct axg_fifo_match_data axg_toddr_match_data = { static const struct axg_fifo_match_data axg_toddr_match_data = {
.component_drv = &axg_toddr_component_drv, .field_threshold = REG_FIELD(FIFO_CTRL1, 16, 23),
.dai_drv = &axg_toddr_dai_drv .component_drv = &axg_toddr_component_drv,
.dai_drv = &axg_toddr_dai_drv
}; };
static const struct snd_soc_dai_ops g12a_toddr_ops = { static const struct snd_soc_dai_ops g12a_toddr_ops = {
...@@ -228,8 +223,9 @@ static const struct snd_soc_component_driver g12a_toddr_component_drv = { ...@@ -228,8 +223,9 @@ static const struct snd_soc_component_driver g12a_toddr_component_drv = {
}; };
static const struct axg_fifo_match_data g12a_toddr_match_data = { static const struct axg_fifo_match_data g12a_toddr_match_data = {
.component_drv = &g12a_toddr_component_drv, .field_threshold = REG_FIELD(FIFO_CTRL1, 16, 23),
.dai_drv = &g12a_toddr_dai_drv .component_drv = &g12a_toddr_component_drv,
.dai_drv = &g12a_toddr_dai_drv
}; };
static const char * const sm1_toddr_sel_texts[] = { static const char * const sm1_toddr_sel_texts[] = {
...@@ -297,8 +293,9 @@ static const struct snd_soc_component_driver sm1_toddr_component_drv = { ...@@ -297,8 +293,9 @@ static const struct snd_soc_component_driver sm1_toddr_component_drv = {
}; };
static const struct axg_fifo_match_data sm1_toddr_match_data = { static const struct axg_fifo_match_data sm1_toddr_match_data = {
.component_drv = &sm1_toddr_component_drv, .field_threshold = REG_FIELD(FIFO_CTRL1, 12, 23),
.dai_drv = &g12a_toddr_dai_drv .component_drv = &sm1_toddr_component_drv,
.dai_drv = &g12a_toddr_dai_drv
}; };
static const struct of_device_id axg_toddr_of_match[] = { static const struct of_device_id axg_toddr_of_match[] = {
......
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