* [PATCH 08/21] ASoC: sun4i-i2s: Use module clock as BCLK parent on newer SoCs
From: Maxime Ripard @ 2019-08-19 19:25 UTC (permalink / raw)
To: Chen-Yu Tsai, Maxime Ripard, lgirdwood, broonie
Cc: codekipper, alsa-devel, linux-kernel, linux-arm-kernel
In-Reply-To: <cover.e08aa7e33afe117e1fa8f017119d465d47c98016.1566242458.git-series.maxime.ripard@bootlin.com>
From: Maxime Ripard <maxime.ripard@bootlin.com>
On the first generation of Allwinner SoCs (A10-A31), the i2s controller was
using the MCLK as BCLK parent. However, this changed since the introduction
of the A83t and BCLK now uses the module clock as its parent.
Let's introduce a hook to get the parent rate and use that in our divider
calculations.
Fixes: 7d2993811a1e ("ASoC: sun4i-i2s: Add support for H3")
Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T")
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
sound/soc/sunxi/sun4i-i2s.c | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index ee8ee3eb2087..51be395102b2 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -152,6 +152,7 @@ struct sun4i_i2s_quirks {
struct reg_field field_fmt_bclk;
struct reg_field field_fmt_lrclk;
+ unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *);
s8 (*get_sr)(const struct sun4i_i2s *, int);
s8 (*get_wss)(const struct sun4i_i2s *, int);
int (*set_chan_cfg)(const struct sun4i_i2s *,
@@ -207,6 +208,16 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = {
/* TODO - extend divide ratio supported by newer SoCs */
};
+static unsigned long sun4i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s)
+{
+ return i2s->mclk_freq;
+}
+
+static unsigned long sun8i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s)
+{
+ return clk_get_rate(i2s->mod_clk);
+}
+
static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s,
unsigned long parent_rate,
unsigned int sampling_rate,
@@ -259,7 +270,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
unsigned int word_size)
{
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- unsigned int oversample_rate, clk_rate;
+ unsigned int oversample_rate, clk_rate, bclk_parent_rate;
int bclk_div, mclk_div;
int ret;
@@ -301,7 +312,8 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
return -EINVAL;
}
- bclk_div = sun4i_i2s_get_bclk_div(i2s, i2s->mclk_freq,
+ bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s);
+ bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate,
rate, word_size);
if (bclk_div < 0) {
dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div);
@@ -957,6 +969,7 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+ .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate,
.get_sr = sun4i_i2s_get_sr,
.get_wss = sun4i_i2s_get_wss,
.set_chan_cfg = sun4i_i2s_set_chan_cfg,
@@ -972,6 +985,7 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+ .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate,
.get_sr = sun4i_i2s_get_sr,
.get_wss = sun4i_i2s_get_wss,
.set_chan_cfg = sun4i_i2s_set_chan_cfg,
@@ -987,6 +1001,7 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = {
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+ .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate,
.get_sr = sun8i_i2s_get_sr_wss,
.get_wss = sun8i_i2s_get_sr_wss,
.set_chan_cfg = sun8i_i2s_set_chan_cfg,
@@ -1005,6 +1020,7 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19),
+ .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate,
.get_sr = sun8i_i2s_get_sr_wss,
.get_wss = sun8i_i2s_get_sr_wss,
.set_chan_cfg = sun8i_i2s_set_chan_cfg,
@@ -1020,6 +1036,7 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = {
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+ .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate,
.get_sr = sun4i_i2s_get_sr,
.get_wss = sun4i_i2s_get_wss,
.set_chan_cfg = sun4i_i2s_set_chan_cfg,
--
git-series 0.9.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 09/21] ASoC: sun4i-i2s: Fix the MCLK and BCLK dividers on newer SoCs
From: Maxime Ripard @ 2019-08-19 19:25 UTC (permalink / raw)
To: Chen-Yu Tsai, Maxime Ripard, lgirdwood, broonie
Cc: codekipper, alsa-devel, linux-kernel, linux-arm-kernel
In-Reply-To: <cover.e08aa7e33afe117e1fa8f017119d465d47c98016.1566242458.git-series.maxime.ripard@bootlin.com>
From: Maxime Ripard <maxime.ripard@bootlin.com>
From: Marcus Cooper <codekipper@gmail.com>
The clock division dividers have changed between the older (A10/A31) and
newer (H3, A64, etc) SoCs.
While this was addressed through an offset on some SoCs, it was missing
some dividers as well, so the support wasn't perfect. Let's introduce a
pointer in the quirk structure for the divider calculation functions to use
so we can have the proper range now.
Signed-off-by: Marcus Cooper <codekipper@gmail.com>
[Maxime: Fix the commit log, use a field in the quirk structure]
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
sound/soc/sunxi/sun4i-i2s.c | 63 +++++++++++++++++++++++++++++---------
1 file changed, 49 insertions(+), 14 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 51be395102b2..8d49ee7d2a95 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -129,8 +129,6 @@ struct sun4i_i2s;
* @has_fmt_set_lrck_period: SoC requires lrclk period to be set.
* @reg_offset_txdata: offset of the tx fifo.
* @sun4i_i2s_regmap: regmap config to use.
- * @mclk_offset: Value by which mclkdiv needs to be adjusted.
- * @bclk_offset: Value by which bclkdiv needs to be adjusted.
* @field_clkdiv_mclk_en: regmap field to enable mclk output.
* @field_fmt_wss: regmap field to set word select size.
* @field_fmt_sr: regmap field to set sample resolution.
@@ -142,8 +140,6 @@ struct sun4i_i2s_quirks {
bool has_fmt_set_lrck_period;
unsigned int reg_offset_txdata; /* TX FIFO */
const struct regmap_config *sun4i_i2s_regmap;
- unsigned int mclk_offset;
- unsigned int bclk_offset;
/* Register fields for i2s */
struct reg_field field_clkdiv_mclk_en;
@@ -152,6 +148,11 @@ struct sun4i_i2s_quirks {
struct reg_field field_fmt_bclk;
struct reg_field field_fmt_lrclk;
+ const struct sun4i_i2s_clk_div *bclk_dividers;
+ unsigned int num_bclk_dividers;
+ const struct sun4i_i2s_clk_div *mclk_dividers;
+ unsigned int num_mclk_dividers;
+
unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *);
s8 (*get_sr)(const struct sun4i_i2s *, int);
s8 (*get_wss)(const struct sun4i_i2s *, int);
@@ -208,6 +209,24 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = {
/* TODO - extend divide ratio supported by newer SoCs */
};
+static const struct sun4i_i2s_clk_div sun8i_i2s_clk_div[] = {
+ { .div = 1, .val = 1 },
+ { .div = 2, .val = 2 },
+ { .div = 4, .val = 3 },
+ { .div = 6, .val = 4 },
+ { .div = 8, .val = 5 },
+ { .div = 12, .val = 6 },
+ { .div = 16, .val = 7 },
+ { .div = 24, .val = 8 },
+ { .div = 32, .val = 9 },
+ { .div = 48, .val = 10 },
+ { .div = 64, .val = 11 },
+ { .div = 96, .val = 12 },
+ { .div = 128, .val = 13 },
+ { .div = 176, .val = 14 },
+ { .div = 192, .val = 15 },
+};
+
static unsigned long sun4i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s)
{
return i2s->mclk_freq;
@@ -223,11 +242,12 @@ static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s,
unsigned int sampling_rate,
unsigned int word_size)
{
+ const struct sun4i_i2s_clk_div *dividers = i2s->variant->bclk_dividers;
int div = parent_rate / sampling_rate / word_size / 2;
int i;
- for (i = 0; i < ARRAY_SIZE(sun4i_i2s_bclk_div); i++) {
- const struct sun4i_i2s_clk_div *bdiv = &sun4i_i2s_bclk_div[i];
+ for (i = 0; i < i2s->variant->num_bclk_dividers; i++) {
+ const struct sun4i_i2s_clk_div *bdiv = ÷rs[i];
if (bdiv->div == div)
return bdiv->val;
@@ -240,11 +260,12 @@ static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s,
unsigned long parent_rate,
unsigned long mclk_rate)
{
+ const struct sun4i_i2s_clk_div *dividers = i2s->variant->mclk_dividers;
int div = parent_rate / mclk_rate;
int i;
- for (i = 0; i < ARRAY_SIZE(sun4i_i2s_mclk_div); i++) {
- const struct sun4i_i2s_clk_div *mdiv = &sun4i_i2s_mclk_div[i];
+ for (i = 0; i < i2s->variant->num_mclk_dividers; i++) {
+ const struct sun4i_i2s_clk_div *mdiv = ÷rs[i];
if (mdiv->div == div)
return mdiv->val;
@@ -326,10 +347,6 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
return -EINVAL;
}
- /* Adjust the clock division values if needed */
- bclk_div += i2s->variant->bclk_offset;
- mclk_div += i2s->variant->mclk_offset;
-
regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG,
SUN4I_I2S_CLK_DIV_BCLK(bclk_div) |
SUN4I_I2S_CLK_DIV_MCLK(mclk_div));
@@ -969,6 +986,10 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+ .bclk_dividers = sun4i_i2s_bclk_div,
+ .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div),
+ .mclk_dividers = sun4i_i2s_mclk_div,
+ .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div),
.get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate,
.get_sr = sun4i_i2s_get_sr,
.get_wss = sun4i_i2s_get_wss,
@@ -985,6 +1006,10 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+ .bclk_dividers = sun4i_i2s_bclk_div,
+ .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div),
+ .mclk_dividers = sun4i_i2s_mclk_div,
+ .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div),
.get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate,
.get_sr = sun4i_i2s_get_sr,
.get_wss = sun4i_i2s_get_wss,
@@ -1001,6 +1026,10 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = {
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+ .bclk_dividers = sun8i_i2s_clk_div,
+ .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div),
+ .mclk_dividers = sun8i_i2s_clk_div,
+ .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div),
.get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate,
.get_sr = sun8i_i2s_get_sr_wss,
.get_wss = sun8i_i2s_get_sr_wss,
@@ -1012,14 +1041,16 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
.has_reset = true,
.reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap = &sun8i_i2s_regmap_config,
- .mclk_offset = 1,
- .bclk_offset = 2,
.has_fmt_set_lrck_period = true,
.field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),
.field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19),
+ .bclk_dividers = sun8i_i2s_clk_div,
+ .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div),
+ .mclk_dividers = sun8i_i2s_clk_div,
+ .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div),
.get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate,
.get_sr = sun8i_i2s_get_sr_wss,
.get_wss = sun8i_i2s_get_sr_wss,
@@ -1036,6 +1067,10 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = {
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
+ .bclk_dividers = sun4i_i2s_bclk_div,
+ .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div),
+ .mclk_dividers = sun4i_i2s_mclk_div,
+ .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div),
.get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate,
.get_sr = sun4i_i2s_get_sr,
.get_wss = sun4i_i2s_get_wss,
--
git-series 0.9.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 10/21] ASoC: sun4i-i2s: RX and TX counter registers are swapped
From: Maxime Ripard @ 2019-08-19 19:25 UTC (permalink / raw)
To: Chen-Yu Tsai, Maxime Ripard, lgirdwood, broonie
Cc: codekipper, alsa-devel, linux-kernel, linux-arm-kernel
In-Reply-To: <cover.e08aa7e33afe117e1fa8f017119d465d47c98016.1566242458.git-series.maxime.ripard@bootlin.com>
From: Maxime Ripard <maxime.ripard@bootlin.com>
The RX and TX counters registers offset have been swapped, fix that.
Fixes: fa7c0d13cb26 ("ASoC: sunxi: Add Allwinner A10 Digital Audio driver")
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
sound/soc/sunxi/sun4i-i2s.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 8d49ee7d2a95..08fc04ad3585 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -76,8 +76,8 @@
#define SUN4I_I2S_CLK_DIV_MCLK_MASK GENMASK(3, 0)
#define SUN4I_I2S_CLK_DIV_MCLK(mclk) ((mclk) << 0)
-#define SUN4I_I2S_RX_CNT_REG 0x28
-#define SUN4I_I2S_TX_CNT_REG 0x2c
+#define SUN4I_I2S_TX_CNT_REG 0x28
+#define SUN4I_I2S_RX_CNT_REG 0x2c
#define SUN4I_I2S_TX_CHAN_SEL_REG 0x30
#define SUN4I_I2S_CHAN_SEL_MASK GENMASK(2, 0)
--
git-series 0.9.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 11/21] ASoC: sun4i-i2s: Use the actual format width instead of an hardcoded one
From: Maxime Ripard @ 2019-08-19 19:25 UTC (permalink / raw)
To: Chen-Yu Tsai, Maxime Ripard, lgirdwood, broonie
Cc: codekipper, alsa-devel, linux-kernel, linux-arm-kernel
In-Reply-To: <cover.e08aa7e33afe117e1fa8f017119d465d47c98016.1566242458.git-series.maxime.ripard@bootlin.com>
From: Maxime Ripard <maxime.ripard@bootlin.com>
The LRCK period field in the FMT0 register holds the number of LRCK period
for one channel in I2S mode.
This has been hardcoded to 32, while it really should be the physical width
of the format, which creates an improper clock when using a 16bit format,
with the i2s controller as LRCK master.
Fixes: 7d2993811a1e ("ASoC: sun4i-i2s: Add support for H3")
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
sound/soc/sunxi/sun4i-i2s.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 08fc04ad3585..2996beb4f092 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -357,7 +357,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
if (i2s->variant->has_fmt_set_lrck_period)
regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
- SUN8I_I2S_FMT0_LRCK_PERIOD(32));
+ SUN8I_I2S_FMT0_LRCK_PERIOD(params_physical_width(params)));
return 0;
}
--
git-series 0.9.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 12/21] ASoC: sun4i-i2s: Fix LRCK and BCLK polarity offsets on newer SoCs
From: Maxime Ripard @ 2019-08-19 19:25 UTC (permalink / raw)
To: Chen-Yu Tsai, Maxime Ripard, lgirdwood, broonie
Cc: codekipper, alsa-devel, linux-kernel, linux-arm-kernel
In-Reply-To: <cover.e08aa7e33afe117e1fa8f017119d465d47c98016.1566242458.git-series.maxime.ripard@bootlin.com>
From: Maxime Ripard <maxime.ripard@bootlin.com>
The LRCK and BCLK polarity offsets on newer SoCs has been
changed, yet the driver didn't take it into account for all of them.
This was taken into account for the H3, but not the A83t. This was handled
using a reg_field for the H3.
However, the value in that field will not be the same, so reg_field is not
adapted in that case. Let's change for proper calls with the regular
values.
Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T")
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
sound/soc/sunxi/sun4i-i2s.c | 118 ++++++++++++++++++-------------------
1 file changed, 60 insertions(+), 58 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 2996beb4f092..e614c2d52af5 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -46,8 +46,6 @@
#define SUN4I_I2S_FMT0_FMT_RIGHT_J (2 << 0)
#define SUN4I_I2S_FMT0_FMT_LEFT_J (1 << 0)
#define SUN4I_I2S_FMT0_FMT_I2S (0 << 0)
-#define SUN4I_I2S_FMT0_POLARITY_INVERTED (1)
-#define SUN4I_I2S_FMT0_POLARITY_NORMAL (0)
#define SUN4I_I2S_FMT1_REG 0x08
#define SUN4I_I2S_FIFO_TX_REG 0x0c
@@ -98,8 +96,14 @@
#define SUN8I_I2S_CTRL_MODE_LEFT (1 << 4)
#define SUN8I_I2S_CTRL_MODE_PCM (0 << 4)
+#define SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK BIT(19)
+#define SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 19)
+#define SUN8I_I2S_FMT0_LRCLK_POLARITY_NORMAL (0 << 19)
#define SUN8I_I2S_FMT0_LRCK_PERIOD_MASK GENMASK(17, 8)
#define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period - 1) << 8)
+#define SUN8I_I2S_FMT0_BCLK_POLARITY_MASK BIT(7)
+#define SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED (1 << 7)
+#define SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL (0 << 7)
#define SUN8I_I2S_INT_STA_REG 0x0c
#define SUN8I_I2S_FIFO_TX_REG 0x20
@@ -132,8 +136,6 @@ struct sun4i_i2s;
* @field_clkdiv_mclk_en: regmap field to enable mclk output.
* @field_fmt_wss: regmap field to set word select size.
* @field_fmt_sr: regmap field to set sample resolution.
- * @field_fmt_bclk: regmap field to set clk polarity.
- * @field_fmt_lrclk: regmap field to set frame polarity.
*/
struct sun4i_i2s_quirks {
bool has_reset;
@@ -145,8 +147,6 @@ struct sun4i_i2s_quirks {
struct reg_field field_clkdiv_mclk_en;
struct reg_field field_fmt_wss;
struct reg_field field_fmt_sr;
- struct reg_field field_fmt_bclk;
- struct reg_field field_fmt_lrclk;
const struct sun4i_i2s_clk_div *bclk_dividers;
unsigned int num_bclk_dividers;
@@ -176,8 +176,6 @@ struct sun4i_i2s {
struct regmap_field *field_clkdiv_mclk_en;
struct regmap_field *field_fmt_wss;
struct regmap_field *field_fmt_sr;
- struct regmap_field *field_fmt_bclk;
- struct regmap_field *field_fmt_lrclk;
const struct sun4i_i2s_quirks *variant;
};
@@ -498,6 +496,33 @@ static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
{
u32 val;
+ /* DAI clock polarity */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_IB_IF:
+ /* Invert both clocks */
+ val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED |
+ SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ /* Invert bit clock */
+ val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ /* Invert frame clock */
+ val = SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
+ break;
+ case SND_SOC_DAIFMT_NB_NF:
+ val = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
+ SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK |
+ SUN4I_I2S_FMT0_BCLK_POLARITY_MASK,
+ val);
+
/* DAI Mode */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
@@ -545,6 +570,33 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
u32 mode, val;
u8 offset;
+ /* DAI clock polarity */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_IB_IF:
+ /* Invert both clocks */
+ val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED |
+ SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ /* Invert bit clock */
+ val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ /* Invert frame clock */
+ val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
+ break;
+ case SND_SOC_DAIFMT_NB_NF:
+ val = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
+ SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK |
+ SUN8I_I2S_FMT0_BCLK_POLARITY_MASK,
+ val);
+
/* DAI Mode */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
@@ -601,36 +653,8 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- u32 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL;
- u32 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL;
int ret;
- /* DAI clock polarity */
- switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
- case SND_SOC_DAIFMT_IB_IF:
- /* Invert both clocks */
- bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
- lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
- break;
- case SND_SOC_DAIFMT_IB_NF:
- /* Invert bit clock */
- bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
- break;
- case SND_SOC_DAIFMT_NB_IF:
- /* Invert frame clock */
- lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
- break;
- case SND_SOC_DAIFMT_NB_NF:
- break;
- default:
- dev_err(dai->dev, "Unsupported clock polarity: %d\n",
- fmt & SND_SOC_DAIFMT_INV_MASK);
- return -EINVAL;
- }
-
- regmap_field_write(i2s->field_fmt_bclk, bclk_polarity);
- regmap_field_write(i2s->field_fmt_lrclk, lrclk_polarity);
-
ret = i2s->variant->set_fmt(i2s, fmt);
if (ret) {
dev_err(dai->dev, "Unsupported format configuration\n");
@@ -984,8 +1008,6 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
.field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
.field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
- .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
- .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.bclk_dividers = sun4i_i2s_bclk_div,
.num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div),
.mclk_dividers = sun4i_i2s_mclk_div,
@@ -1004,8 +1026,6 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
.field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
.field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
- .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
- .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.bclk_dividers = sun4i_i2s_bclk_div,
.num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div),
.mclk_dividers = sun4i_i2s_mclk_div,
@@ -1024,8 +1044,6 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = {
.field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
.field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
- .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
- .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.bclk_dividers = sun8i_i2s_clk_div,
.num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div),
.mclk_dividers = sun8i_i2s_clk_div,
@@ -1045,8 +1063,6 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
.field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),
.field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
- .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
- .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19),
.bclk_dividers = sun8i_i2s_clk_div,
.num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div),
.mclk_dividers = sun8i_i2s_clk_div,
@@ -1065,8 +1081,6 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = {
.field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
.field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
- .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
- .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.bclk_dividers = sun4i_i2s_bclk_div,
.num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div),
.mclk_dividers = sun4i_i2s_mclk_div,
@@ -1099,18 +1113,6 @@ static int sun4i_i2s_init_regmap_fields(struct device *dev,
if (IS_ERR(i2s->field_fmt_sr))
return PTR_ERR(i2s->field_fmt_sr);
- i2s->field_fmt_bclk =
- devm_regmap_field_alloc(dev, i2s->regmap,
- i2s->variant->field_fmt_bclk);
- if (IS_ERR(i2s->field_fmt_bclk))
- return PTR_ERR(i2s->field_fmt_bclk);
-
- i2s->field_fmt_lrclk =
- devm_regmap_field_alloc(dev, i2s->regmap,
- i2s->variant->field_fmt_lrclk);
- if (IS_ERR(i2s->field_fmt_lrclk))
- return PTR_ERR(i2s->field_fmt_lrclk);
-
return 0;
}
--
git-series 0.9.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 13/21] ASoC: sun4i-i2s: Fix the LRCK polarity
From: Maxime Ripard @ 2019-08-19 19:25 UTC (permalink / raw)
To: Chen-Yu Tsai, Maxime Ripard, lgirdwood, broonie
Cc: codekipper, alsa-devel, linux-kernel, linux-arm-kernel
In-Reply-To: <cover.e08aa7e33afe117e1fa8f017119d465d47c98016.1566242458.git-series.maxime.ripard@bootlin.com>
From: Maxime Ripard <maxime.ripard@bootlin.com>
The LRCK polarity "normal" polarity in the I2S/TDM specs and in the
Allwinner datasheet are not the same. In the case where the i2s controller
is being used as the LRCK master, it's pretty clear when looked at under a
scope.
Let's fix this, and add a comment to clear up as much the confusion as
possible.
Fixes: 7d2993811a1e ("ASoC: sun4i-i2s: Add support for H3")
Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T")
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
sound/soc/sunxi/sun4i-i2s.c | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index e614c2d52af5..9c9061621b15 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -570,23 +570,29 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
u32 mode, val;
u8 offset;
- /* DAI clock polarity */
+ /*
+ * DAI clock polarity
+ *
+ * The setup for LRCK contradicts the datasheet, but under a
+ * scope it's clear that the LRCK polarity is reversed
+ * compared to the expected polarity on the bus.
+ */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_IB_IF:
/* Invert both clocks */
- val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED |
- SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
+ val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED;
break;
case SND_SOC_DAIFMT_IB_NF:
/* Invert bit clock */
- val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED;
+ val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED |
+ SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
break;
case SND_SOC_DAIFMT_NB_IF:
/* Invert frame clock */
- val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
+ val = 0;
break;
case SND_SOC_DAIFMT_NB_NF:
- val = 0;
+ val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
break;
default:
return -EINVAL;
--
git-series 0.9.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 04/21] ASoC: sun4i-i2s: Move the channel configuration to a callback
From: Maxime Ripard @ 2019-08-19 19:25 UTC (permalink / raw)
To: Chen-Yu Tsai, Maxime Ripard, lgirdwood, broonie
Cc: codekipper, alsa-devel, linux-kernel, linux-arm-kernel
In-Reply-To: <cover.e08aa7e33afe117e1fa8f017119d465d47c98016.1566242458.git-series.maxime.ripard@bootlin.com>
From: Maxime Ripard <maxime.ripard@bootlin.com>
The two main generations of our I2S controller require a slightly different
channel configuration, mostly because of a quite different register layout
and some additional registers being needed on the newer generation.
This used to be controlled through a bunch of booleans, however this proved
to be quite impractical, especially since a bunch of SoCs forgot to set
those parameters and therefore were broken from that point of view.
Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T")
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
sound/soc/sunxi/sun4i-i2s.c | 156 ++++++++++++++++---------------------
1 file changed, 69 insertions(+), 87 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index ac84c29224eb..657041606c2f 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -80,6 +80,7 @@
#define SUN4I_I2S_TX_CNT_REG 0x2c
#define SUN4I_I2S_TX_CHAN_SEL_REG 0x30
+#define SUN4I_I2S_CHAN_SEL_MASK GENMASK(2, 0)
#define SUN4I_I2S_CHAN_SEL(num_chan) (((num_chan) - 1) << 0)
#define SUN4I_I2S_TX_CHAN_MAP_REG 0x34
@@ -122,8 +123,6 @@ struct sun4i_i2s;
* @has_reset: SoC needs reset deasserted.
* @has_slave_select_bit: SoC has a bit to enable slave mode.
* @has_fmt_set_lrck_period: SoC requires lrclk period to be set.
- * @has_chcfg: tx and rx slot number need to be set.
- * @has_chsel_tx_chen: SoC requires that the tx channels are enabled.
* @has_chsel_offset: SoC uses offset for selecting dai operational mode.
* @reg_offset_txdata: offset of the tx fifo.
* @sun4i_i2s_regmap: regmap config to use.
@@ -135,17 +134,11 @@ struct sun4i_i2s;
* @field_fmt_bclk: regmap field to set clk polarity.
* @field_fmt_lrclk: regmap field to set frame polarity.
* @field_fmt_mode: regmap field to set the operational mode.
- * @field_txchanmap: location of the tx channel mapping register.
- * @field_rxchanmap: location of the rx channel mapping register.
- * @field_txchansel: location of the tx channel select bit fields.
- * @field_rxchansel: location of the rx channel select bit fields.
*/
struct sun4i_i2s_quirks {
bool has_reset;
bool has_slave_select_bit;
bool has_fmt_set_lrck_period;
- bool has_chcfg;
- bool has_chsel_tx_chen;
bool has_chsel_offset;
unsigned int reg_offset_txdata; /* TX FIFO */
const struct regmap_config *sun4i_i2s_regmap;
@@ -159,13 +152,11 @@ struct sun4i_i2s_quirks {
struct reg_field field_fmt_bclk;
struct reg_field field_fmt_lrclk;
struct reg_field field_fmt_mode;
- struct reg_field field_txchanmap;
- struct reg_field field_rxchanmap;
- struct reg_field field_txchansel;
- struct reg_field field_rxchansel;
s8 (*get_sr)(const struct sun4i_i2s *, int);
s8 (*get_wss)(const struct sun4i_i2s *, int);
+ int (*set_chan_cfg)(const struct sun4i_i2s *,
+ const struct snd_pcm_hw_params *);
};
struct sun4i_i2s {
@@ -186,10 +177,6 @@ struct sun4i_i2s {
struct regmap_field *field_fmt_bclk;
struct regmap_field *field_fmt_lrclk;
struct regmap_field *field_fmt_mode;
- struct regmap_field *field_txchanmap;
- struct regmap_field *field_rxchanmap;
- struct regmap_field *field_txchansel;
- struct regmap_field *field_rxchansel;
const struct sun4i_i2s_quirks *variant;
};
@@ -381,44 +368,77 @@ static s8 sun8i_i2s_get_sr_wss(const struct sun4i_i2s *i2s, int width)
return (width - 8) / 4 + 1;
}
-static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
+ const struct snd_pcm_hw_params *params)
{
- struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- int sr, wss, channels;
- u32 width;
+ unsigned int channels = params_channels(params);
- channels = params_channels(params);
- if (channels != 2) {
- dev_err(dai->dev, "Unsupported number of channels: %d\n",
- channels);
+ if (channels != 2)
return -EINVAL;
- }
- if (i2s->variant->has_chcfg) {
- regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
- SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK,
- SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels));
- regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
- SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK,
- SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels));
- }
+ /* Map the channels for playback and capture */
+ regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210);
+ regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210);
+
+ /* Configure the channels */
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG,
+ SUN4I_I2S_CHAN_SEL_MASK,
+ SUN4I_I2S_CHAN_SEL(channels));
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_RX_CHAN_SEL_REG,
+ SUN4I_I2S_CHAN_SEL_MASK,
+ SUN4I_I2S_CHAN_SEL(channels));
+
+ return 0;
+}
+
+static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
+ const struct snd_pcm_hw_params *params)
+{
+ unsigned int channels = params_channels(params);
+
+ if (channels != 2)
+ return -EINVAL;
/* Map the channels for playback and capture */
- regmap_field_write(i2s->field_txchanmap, 0x76543210);
- regmap_field_write(i2s->field_rxchanmap, 0x00003210);
+ regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210);
+ regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, 0x76543210);
/* Configure the channels */
- regmap_field_write(i2s->field_txchansel,
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
+ SUN4I_I2S_CHAN_SEL_MASK,
SUN4I_I2S_CHAN_SEL(channels));
- regmap_field_write(i2s->field_rxchansel,
+
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG,
+ SUN4I_I2S_CHAN_SEL_MASK,
SUN4I_I2S_CHAN_SEL(channels));
- if (i2s->variant->has_chsel_tx_chen)
- regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
- SUN8I_I2S_TX_CHAN_EN_MASK,
- SUN8I_I2S_TX_CHAN_EN(channels));
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
+ SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK,
+ SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels));
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
+ SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK,
+ SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels));
+
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
+ SUN8I_I2S_TX_CHAN_EN_MASK,
+ SUN8I_I2S_TX_CHAN_EN(channels));
+
+ return 0;
+}
+
+static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+ int ret, sr, wss;
+ u32 width;
+
+ ret = i2s->variant->set_chan_cfg(i2s, params);
+ if (ret < 0) {
+ dev_err(dai->dev, "Invalid channel configuration\n");
+ return ret;
+ }
switch (params_physical_width(params)) {
case 16:
@@ -916,12 +936,9 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.has_slave_select_bit = true,
.field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
- .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
- .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
- .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
- .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
.get_sr = sun4i_i2s_get_sr,
.get_wss = sun4i_i2s_get_wss,
+ .set_chan_cfg = sun4i_i2s_set_chan_cfg,
};
static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
@@ -935,12 +952,9 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.has_slave_select_bit = true,
.field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
- .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
- .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
- .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
- .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
.get_sr = sun4i_i2s_get_sr,
.get_wss = sun4i_i2s_get_wss,
+ .set_chan_cfg = sun4i_i2s_set_chan_cfg,
};
static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = {
@@ -954,12 +968,9 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = {
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.has_slave_select_bit = true,
.field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
- .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
- .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
- .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
- .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
.get_sr = sun8i_i2s_get_sr_wss,
.get_wss = sun8i_i2s_get_sr_wss,
+ .set_chan_cfg = sun8i_i2s_set_chan_cfg,
};
static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
@@ -969,8 +980,6 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
.mclk_offset = 1,
.bclk_offset = 2,
.has_fmt_set_lrck_period = true,
- .has_chcfg = true,
- .has_chsel_tx_chen = true,
.has_chsel_offset = true,
.field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),
.field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),
@@ -978,12 +987,9 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19),
.field_fmt_mode = REG_FIELD(SUN4I_I2S_CTRL_REG, 4, 5),
- .field_txchanmap = REG_FIELD(SUN8I_I2S_TX_CHAN_MAP_REG, 0, 31),
- .field_rxchanmap = REG_FIELD(SUN8I_I2S_RX_CHAN_MAP_REG, 0, 31),
- .field_txchansel = REG_FIELD(SUN8I_I2S_TX_CHAN_SEL_REG, 0, 2),
- .field_rxchansel = REG_FIELD(SUN8I_I2S_RX_CHAN_SEL_REG, 0, 2),
.get_sr = sun8i_i2s_get_sr_wss,
.get_wss = sun8i_i2s_get_sr_wss,
+ .set_chan_cfg = sun8i_i2s_set_chan_cfg,
};
static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = {
@@ -997,12 +1003,9 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = {
.field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
.field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
.field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
- .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
- .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
- .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
- .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
.get_sr = sun4i_i2s_get_sr,
.get_wss = sun4i_i2s_get_wss,
+ .set_chan_cfg = sun4i_i2s_set_chan_cfg,
};
static int sun4i_i2s_init_regmap_fields(struct device *dev,
@@ -1044,28 +1047,7 @@ static int sun4i_i2s_init_regmap_fields(struct device *dev,
if (IS_ERR(i2s->field_fmt_mode))
return PTR_ERR(i2s->field_fmt_mode);
- i2s->field_txchanmap =
- devm_regmap_field_alloc(dev, i2s->regmap,
- i2s->variant->field_txchanmap);
- if (IS_ERR(i2s->field_txchanmap))
- return PTR_ERR(i2s->field_txchanmap);
-
- i2s->field_rxchanmap =
- devm_regmap_field_alloc(dev, i2s->regmap,
- i2s->variant->field_rxchanmap);
- if (IS_ERR(i2s->field_rxchanmap))
- return PTR_ERR(i2s->field_rxchanmap);
-
- i2s->field_txchansel =
- devm_regmap_field_alloc(dev, i2s->regmap,
- i2s->variant->field_txchansel);
- if (IS_ERR(i2s->field_txchansel))
- return PTR_ERR(i2s->field_txchansel);
-
- i2s->field_rxchansel =
- devm_regmap_field_alloc(dev, i2s->regmap,
- i2s->variant->field_rxchansel);
- return PTR_ERR_OR_ZERO(i2s->field_rxchansel);
+ return 0;
}
static int sun4i_i2s_probe(struct platform_device *pdev)
--
git-series 0.9.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 16/21] ASoC: sun4i-i2s: Fix the LRCK period on A83t
From: Maxime Ripard @ 2019-08-19 19:25 UTC (permalink / raw)
To: Chen-Yu Tsai, Maxime Ripard, lgirdwood, broonie
Cc: codekipper, alsa-devel, linux-kernel, linux-arm-kernel
In-Reply-To: <cover.e08aa7e33afe117e1fa8f017119d465d47c98016.1566242458.git-series.maxime.ripard@bootlin.com>
From: Maxime Ripard <maxime.ripard@bootlin.com>
Unlike the previous SoCs, the A83t, like the newer ones, need the LRCK
bitfield to be set. Let's add it.
Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T")
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
sound/soc/sunxi/sun4i-i2s.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 5dd742f24a7e..65bc296abb37 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -1047,6 +1047,7 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = {
.has_reset = true,
.reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap = &sun4i_i2s_regmap_config,
+ .has_fmt_set_lrck_period = true,
.field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),
.field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
--
git-series 0.9.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 17/21] ASoC: sun4i-i2s: Remove duplicated quirks structure
From: Maxime Ripard @ 2019-08-19 19:25 UTC (permalink / raw)
To: Chen-Yu Tsai, Maxime Ripard, lgirdwood, broonie
Cc: codekipper, alsa-devel, linux-kernel, linux-arm-kernel
In-Reply-To: <cover.e08aa7e33afe117e1fa8f017119d465d47c98016.1566242458.git-series.maxime.ripard@bootlin.com>
From: Maxime Ripard <maxime.ripard@bootlin.com>
The A83t and H3 have the same quirks, so it doesn't make sense to duplicate
the quirks structure.
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
sound/soc/sunxi/sun4i-i2s.c | 21 +--------------------
1 file changed, 1 insertion(+), 20 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 65bc296abb37..5dcbab0b4bcb 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -1062,25 +1062,6 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = {
.set_fmt = sun8i_i2s_set_soc_fmt,
};
-static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
- .has_reset = true,
- .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
- .sun4i_i2s_regmap = &sun8i_i2s_regmap_config,
- .has_fmt_set_lrck_period = true,
- .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),
- .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),
- .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
- .bclk_dividers = sun8i_i2s_clk_div,
- .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div),
- .mclk_dividers = sun8i_i2s_clk_div,
- .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div),
- .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate,
- .get_sr = sun8i_i2s_get_sr_wss,
- .get_wss = sun8i_i2s_get_sr_wss,
- .set_chan_cfg = sun8i_i2s_set_chan_cfg,
- .set_fmt = sun8i_i2s_set_soc_fmt,
-};
-
static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = {
.has_reset = true,
.reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
@@ -1264,7 +1245,7 @@ static const struct of_device_id sun4i_i2s_match[] = {
},
{
.compatible = "allwinner,sun8i-h3-i2s",
- .data = &sun8i_h3_i2s_quirks,
+ .data = &sun8i_a83t_i2s_quirks,
},
{
.compatible = "allwinner,sun50i-a64-codec-i2s",
--
git-series 0.9.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 18/21] ASoC: sun4i-i2s: Pass the channels number as an argument
From: Maxime Ripard @ 2019-08-19 19:25 UTC (permalink / raw)
To: Chen-Yu Tsai, Maxime Ripard, lgirdwood, broonie
Cc: codekipper, alsa-devel, linux-kernel, linux-arm-kernel
In-Reply-To: <cover.e08aa7e33afe117e1fa8f017119d465d47c98016.1566242458.git-series.maxime.ripard@bootlin.com>
From: Maxime Ripard <maxime.ripard@bootlin.com>
The channels number have been hardcoded to 2 so far, while the controller
supports more than that.
Remove the instance where it has been hardcoded to compute the BCLK
divider, and pass it through as an argument to ease further support of more
channels.
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
sound/soc/sunxi/sun4i-i2s.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 5dcbab0b4bcb..905e9bd16024 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -238,10 +238,11 @@ static unsigned long sun8i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s)
static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s,
unsigned long parent_rate,
unsigned int sampling_rate,
+ unsigned int channels,
unsigned int word_size)
{
const struct sun4i_i2s_clk_div *dividers = i2s->variant->bclk_dividers;
- int div = parent_rate / sampling_rate / word_size / 2;
+ int div = parent_rate / sampling_rate / word_size / channels;
int i;
for (i = 0; i < i2s->variant->num_bclk_dividers; i++) {
@@ -286,6 +287,7 @@ static bool sun4i_i2s_oversample_is_valid(unsigned int oversample)
static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
unsigned int rate,
+ unsigned int channels,
unsigned int word_size)
{
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
@@ -333,7 +335,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s);
bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate,
- rate, word_size);
+ rate, channels, word_size);
if (bclk_div < 0) {
dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div);
return -EINVAL;
@@ -488,7 +490,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
regmap_field_write(i2s->field_fmt_sr, sr);
return sun4i_i2s_set_clk_rate(dai, params_rate(params),
- params_width(params));
+ 2, params_width(params));
}
static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
--
git-series 0.9.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 19/21] ASoC: sun4i-i2s: Support more channels
From: Maxime Ripard @ 2019-08-19 19:25 UTC (permalink / raw)
To: Chen-Yu Tsai, Maxime Ripard, lgirdwood, broonie
Cc: codekipper, alsa-devel, linux-kernel, linux-arm-kernel
In-Reply-To: <cover.e08aa7e33afe117e1fa8f017119d465d47c98016.1566242458.git-series.maxime.ripard@bootlin.com>
From: Maxime Ripard <maxime.ripard@bootlin.com>
We've been limited to 2 channels in the driver while the controller
supports from 1 to 8 channels, in both capture and playback. let's remove
the hardcoded checks and numbers, and extend the range of channel numbers
we can use.
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
sound/soc/sunxi/sun4i-i2s.c | 17 ++++++-----------
1 file changed, 6 insertions(+), 11 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 905e9bd16024..0dac09814b65 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -400,9 +400,6 @@ static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
{
unsigned int channels = params_channels(params);
- if (channels != 2)
- return -EINVAL;
-
/* Map the channels for playback and capture */
regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210);
regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210);
@@ -423,9 +420,6 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
{
unsigned int channels = params_channels(params);
- if (channels != 2)
- return -EINVAL;
-
/* Map the channels for playback and capture */
regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210);
regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, 0x76543210);
@@ -458,6 +452,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+ unsigned int channels = params_channels(params);
int ret, sr, wss;
u32 width;
@@ -490,7 +485,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
regmap_field_write(i2s->field_fmt_sr, sr);
return sun4i_i2s_set_clk_rate(dai, params_rate(params),
- 2, params_width(params));
+ channels, params_width(params));
}
static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
@@ -814,15 +809,15 @@ static struct snd_soc_dai_driver sun4i_i2s_dai = {
.probe = sun4i_i2s_dai_probe,
.capture = {
.stream_name = "Capture",
- .channels_min = 2,
- .channels_max = 2,
+ .channels_min = 1,
+ .channels_max = 8,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.playback = {
.stream_name = "Playback",
- .channels_min = 2,
- .channels_max = 2,
+ .channels_min = 1,
+ .channels_max = 8,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
--
git-series 0.9.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 20/21] ASoC: sun4i-i2s: Add support for TDM slots
From: Maxime Ripard @ 2019-08-19 19:25 UTC (permalink / raw)
To: Chen-Yu Tsai, Maxime Ripard, lgirdwood, broonie
Cc: codekipper, alsa-devel, linux-kernel, linux-arm-kernel
In-Reply-To: <cover.e08aa7e33afe117e1fa8f017119d465d47c98016.1566242458.git-series.maxime.ripard@bootlin.com>
From: Maxime Ripard <maxime.ripard@bootlin.com>
The i2s controller supports TDM, for up to 8 slots. Let's support the TDM
API.
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
sound/soc/sunxi/sun4i-i2s.c | 40 ++++++++++++++++++++++++++++++++------
1 file changed, 34 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 0dac09814b65..4f76daeaaed7 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -168,6 +168,8 @@ struct sun4i_i2s {
struct reset_control *rst;
unsigned int mclk_freq;
+ unsigned int slots;
+ unsigned int slot_width;
struct snd_dmaengine_dai_dma_data capture_dma_data;
struct snd_dmaengine_dai_dma_data playback_dma_data;
@@ -287,7 +289,7 @@ static bool sun4i_i2s_oversample_is_valid(unsigned int oversample)
static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
unsigned int rate,
- unsigned int channels,
+ unsigned int slots,
unsigned int word_size)
{
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
@@ -335,7 +337,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s);
bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate,
- rate, channels, word_size);
+ rate, slots, word_size);
if (bclk_div < 0) {
dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div);
return -EINVAL;
@@ -419,6 +421,10 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
const struct snd_pcm_hw_params *params)
{
unsigned int channels = params_channels(params);
+ unsigned int slots = channels;
+
+ if (i2s->slots)
+ slots = i2s->slots;
/* Map the channels for playback and capture */
regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210);
@@ -428,7 +434,6 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
SUN4I_I2S_CHAN_SEL_MASK,
SUN4I_I2S_CHAN_SEL(channels));
-
regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG,
SUN4I_I2S_CHAN_SEL_MASK,
SUN4I_I2S_CHAN_SEL(channels));
@@ -452,10 +457,18 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+ unsigned int word_size = params_width(params);
unsigned int channels = params_channels(params);
+ unsigned int slots = channels;
int ret, sr, wss;
u32 width;
+ if (i2s->slots)
+ slots = i2s->slots;
+
+ if (i2s->slot_width)
+ word_size = i2s->slot_width;
+
ret = i2s->variant->set_chan_cfg(i2s, params);
if (ret < 0) {
dev_err(dai->dev, "Invalid channel configuration\n");
@@ -477,15 +490,14 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
if (sr < 0)
return -EINVAL;
- wss = i2s->variant->get_wss(i2s, params_width(params));
+ wss = i2s->variant->get_wss(i2s, word_size);
if (wss < 0)
return -EINVAL;
regmap_field_write(i2s->field_fmt_wss, wss);
regmap_field_write(i2s->field_fmt_sr, sr);
- return sun4i_i2s_set_clk_rate(dai, params_rate(params),
- channels, params_width(params));
+ return sun4i_i2s_set_clk_rate(dai, params_rate(params), slots, word_size);
}
static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
@@ -785,10 +797,26 @@ static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
return 0;
}
+static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int slot_width)
+{
+ struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+ if (slots > 8)
+ return -EINVAL;
+
+ i2s->slots = slots;
+ i2s->slot_width = slot_width;
+
+ return 0;
+}
+
static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = {
.hw_params = sun4i_i2s_hw_params,
.set_fmt = sun4i_i2s_set_fmt,
.set_sysclk = sun4i_i2s_set_sysclk,
+ .set_tdm_slot = sun4i_i2s_set_tdm_slot,
.trigger = sun4i_i2s_trigger,
};
--
git-series 0.9.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 21/21] ASoC: sun4i-i2s: Add support for DSP formats
From: Maxime Ripard @ 2019-08-19 19:25 UTC (permalink / raw)
To: Chen-Yu Tsai, Maxime Ripard, lgirdwood, broonie
Cc: codekipper, alsa-devel, linux-kernel, linux-arm-kernel
In-Reply-To: <cover.e08aa7e33afe117e1fa8f017119d465d47c98016.1566242458.git-series.maxime.ripard@bootlin.com>
From: Maxime Ripard <maxime.ripard@bootlin.com>
In addition to the I2S format, the controller also supports the DSP_*
formats.
This requires some extra care on the LRCK period calculation, since the
controller, with the PCM formats, require that the value set is no longer
the periods of LRCK for a single channel, but for all of them.
Let's add the code to deal with this, and support the DSP_A and DSP_B
formats.
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
sound/soc/sunxi/sun4i-i2s.c | 44 ++++++++++++++++++++++++++++++--------
1 file changed, 35 insertions(+), 9 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 4f76daeaaed7..198e3c580297 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -130,7 +130,6 @@ struct sun4i_i2s;
* struct sun4i_i2s_quirks - Differences between SoC variants.
*
* @has_reset: SoC needs reset deasserted.
- * @has_fmt_set_lrck_period: SoC requires lrclk period to be set.
* @reg_offset_txdata: offset of the tx fifo.
* @sun4i_i2s_regmap: regmap config to use.
* @field_clkdiv_mclk_en: regmap field to enable mclk output.
@@ -139,7 +138,6 @@ struct sun4i_i2s;
*/
struct sun4i_i2s_quirks {
bool has_reset;
- bool has_fmt_set_lrck_period;
unsigned int reg_offset_txdata; /* TX FIFO */
const struct regmap_config *sun4i_i2s_regmap;
@@ -167,6 +165,7 @@ struct sun4i_i2s {
struct regmap *regmap;
struct reset_control *rst;
+ unsigned int format;
unsigned int mclk_freq;
unsigned int slots;
unsigned int slot_width;
@@ -355,12 +354,6 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
regmap_field_write(i2s->field_clkdiv_mclk_en, 1);
- /* Set sync period */
- if (i2s->variant->has_fmt_set_lrck_period)
- regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
- SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
- SUN8I_I2S_FMT0_LRCK_PERIOD(params_physical_width(params)));
-
return 0;
}
@@ -422,6 +415,7 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
{
unsigned int channels = params_channels(params);
unsigned int slots = channels;
+ unsigned int lrck_period;
if (i2s->slots)
slots = i2s->slots;
@@ -445,6 +439,26 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK,
SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels));
+ switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ lrck_period = params_physical_width(params) * slots;
+ break;
+
+ case SND_SOC_DAIFMT_I2S:
+ lrck_period = params_physical_width(params);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
+ SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
+ SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period));
+
regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
SUN8I_I2S_TX_CHAN_EN_MASK,
SUN8I_I2S_TX_CHAN_EN(channels));
@@ -614,6 +628,16 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
/* DAI Mode */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ mode = SUN8I_I2S_CTRL_MODE_PCM;
+ offset = 1;
+ break;
+
+ case SND_SOC_DAIFMT_DSP_B:
+ mode = SUN8I_I2S_CTRL_MODE_PCM;
+ offset = 0;
+ break;
+
case SND_SOC_DAIFMT_I2S:
mode = SUN8I_I2S_CTRL_MODE_LEFT;
offset = 1;
@@ -682,6 +706,9 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK,
SUN4I_I2S_FIFO_CTRL_TX_MODE(1) |
SUN4I_I2S_FIFO_CTRL_RX_MODE(1));
+
+ i2s->format = fmt;
+
return 0;
}
@@ -1072,7 +1099,6 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = {
.has_reset = true,
.reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap = &sun4i_i2s_regmap_config,
- .has_fmt_set_lrck_period = true,
.field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),
.field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
--
git-series 0.9.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 15/21] ASoC: sun4i-i2s: Fix MCLK Enable bit offset on A83t
From: Maxime Ripard @ 2019-08-19 19:25 UTC (permalink / raw)
To: Chen-Yu Tsai, Maxime Ripard, lgirdwood, broonie
Cc: codekipper, alsa-devel, linux-kernel, linux-arm-kernel
In-Reply-To: <cover.e08aa7e33afe117e1fa8f017119d465d47c98016.1566242458.git-series.maxime.ripard@bootlin.com>
From: Maxime Ripard <maxime.ripard@bootlin.com>
The A83t, unlike previous SoCs, has the MCLK enable bit at the 8th bit of
the CLK_DIV register, unlike what is declared in the driver.
Fixes: 21faaea1343f ("ASoC: sun4i-i2s: Add support for A83T")
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
sound/soc/sunxi/sun4i-i2s.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index b5c9774e2f60..5dd742f24a7e 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -1047,7 +1047,7 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = {
.has_reset = true,
.reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
.sun4i_i2s_regmap = &sun4i_i2s_regmap_config,
- .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
+ .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),
.field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),
.field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
.bclk_dividers = sun8i_i2s_clk_div,
--
git-series 0.9.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH 1/2] dt-bindings: arm: sunxi: Add compatible for Tanix TX6 board
From: Rob Herring @ 2019-08-19 19:28 UTC (permalink / raw)
To: Jernej Skrabec
Cc: Mark Rutland, devicetree, linux-kernel@vger.kernel.org,
Maxime Ripard, Chen-Yu Tsai,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20190816205342.29552-2-jernej.skrabec@siol.net>
On Fri, Aug 16, 2019 at 3:54 PM Jernej Skrabec <jernej.skrabec@siol.net> wrote:
>
> Add new Oranth Tanix TX6 board compatible string to the bindings
> documentation.
>
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> ---
> Documentation/devicetree/bindings/arm/sunxi.yaml | 5 +++++
> 1 file changed, 5 insertions(+)
Reviewed-by: Rob Herring <robh@kernel.org>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 03/11] clocksource: sun4i: Add missing compatibles
From: Daniel Lezcano @ 2019-08-19 19:43 UTC (permalink / raw)
To: Maxime Ripard
Cc: Mark Rutland, devicetree, Chen-Yu Tsai, Rob Herring, tglx,
Frank Rowand, linux-arm-kernel
In-Reply-To: <20190819191326.c27vmevrqkmjhfru@flea>
On 19/08/2019 21:13, Maxime Ripard wrote:
> On Mon, Aug 19, 2019 at 03:45:40PM +0200, Daniel Lezcano wrote:
>> On 19/08/2019 15:30, Maxime Ripard wrote:
>>> On Mon, Aug 12, 2019 at 01:24:11PM +0200, Maxime Ripard wrote:
>>>> On Mon, Aug 12, 2019 at 11:21:50AM +0200, Daniel Lezcano wrote:
>>>>> On 12/08/2019 11:16, Maxime Ripard wrote:
>>>>>> Hi,
>>>>>>
>>>>>> On Mon, Aug 12, 2019 at 10:59:51AM +0200, Daniel Lezcano wrote:
>>>>>>> On 22/07/2019 10:12, Maxime Ripard wrote:
>>>>>>>> Newer Allwinner SoCs have different number of interrupts, let's add
>>>>>>>> different compatibles for all of them to deal with this properly.
>>>>>>>>
>>>>>>>> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
>>>>>>>
>>>>>>> Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>
>>>>>>
>>>>>> Thanks!
>>>>>>
>>>>>> Can you merge this through your tree (along with the bindings)? I'll
>>>>>> merge the DT patches
>>>>>
>>>>> patches 1-4 then ?
>>>>
>>>> Yep, thanks!
>>>
>>> Ping?
>>
>> They are applied :)
>
> Oh, my bad :)
Actually, I should have tell you they were applied.
> Where is your tree these days? I couldn't find it in linux-next either
https://git.linaro.org/people/daniel.lezcano/linux.git/log/?h=clockevents/next
--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: coresight: ACPI hook for funnel on ThunderX2
From: Mathieu Poirier @ 2019-08-19 20:06 UTC (permalink / raw)
To: Tanmay Vilas Kumar Jagdale
Cc: Tomasz Nowicki, Jayachandran Chandrasekharan Nair,
Ganapatrao Kulkarni, linux-arm-kernel@lists.infradead.org,
suzuki.poulose@arm.com
In-Reply-To: <1565877479-1583-1-git-send-email-tanmay@marvell.com>
Hi Tanmay,
On Thu, Aug 15, 2019 at 01:58:21PM +0000, Tanmay Vilas Kumar Jagdale wrote:
> Coresight topology on Marvell's ThunderX2 Processor is as follows:
>
> ETM0 _ _ TPIU
> ... \ Static Dynamic /
> ... --> FUNNEL0 --> FUNNEL1 --> ETF --> REPLICATOR --
> ETM127_/ | \_ ETR
> |
> ETM128--|
> /
> Others--/
>
> To support this topology add ACPI hook for Static Funnel0.
>
> Signed-off-by: Tanmay Jagdale <tanmay@marvell.com>
There are a few things that aren't working with your patch. First it doesn't
clear checkpatch.pl - a lot of maintainers will not even look at a patch when
it is the case. Second it doesn't apply to my coresight next branch[1] and
third there are formatting issue with the subject line.
I suggest you peruse through the Documentation/process directory with a special
interest toward files submitting-patches.rst and submit-checklist.rst. Your
life (and mine) will be greatly improved in the process.
More comments below...
> ---
> drivers/hwtracing/coresight/coresight-funnel.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c
> index fa97cb9ab4f9..315691fd6f4b 100644
> --- a/drivers/hwtracing/coresight/coresight-funnel.c
> +++ b/drivers/hwtracing/coresight/coresight-funnel.c
> @@ -5,6 +5,7 @@
> * Description: CoreSight Funnel driver
> */
>
> +#include <linux/acpi.h>
> #include <linux/kernel.h>
> #include <linux/init.h>
> #include <linux/types.h>
> @@ -297,6 +298,11 @@ static int static_funnel_probe(struct platform_device *pdev)
> return ret;
> }
>
> +static const struct acpi_device_id static_funnel_acpi_ids[] = {
> + { "CAV901A" },
> + {},
> +};
> +
Is there anything different between this static funnel and ARM's static funnel?
An ACPI device for static funnels has already been added[2] - this is probably
what you should be using.
Thanks,
Mathieu
[1]. https://git.linaro.org/kernel/coresight.git/log/?h=next
[2]. 991de72831b3 coresight: acpi: Static funnel support
> static const struct of_device_id static_funnel_match[] = {
> {.compatible = "arm,coresight-static-funnel"},
> {}
> @@ -306,6 +312,7 @@ static struct platform_driver static_funnel_driver = {
> .probe = static_funnel_probe,
> .driver = {
> .name = "coresight-static-funnel",
> + .acpi_match_table = ACPI_PTR(static_funnel_acpi_ids),
> .of_match_table = static_funnel_match,
> .pm = &funnel_dev_pm_ops,
> .suppress_bind_attrs = true,
> --
> 2.17.1
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: coresight: Add ETM4.1 support for ThunderX2
From: Mathieu Poirier @ 2019-08-19 20:33 UTC (permalink / raw)
To: Tanmay Vilas Kumar Jagdale
Cc: Tomasz Nowicki, Jayachandran Chandrasekharan Nair,
Ganapatrao Kulkarni, linux-arm-kernel@lists.infradead.org,
suzuki.poulose@arm.com
In-Reply-To: <1565877215-1331-1-git-send-email-tanmay@marvell.com>
Same comment as the previous patch along with the following...
On Thu, Aug 15, 2019 at 01:53:46PM +0000, Tanmay Vilas Kumar Jagdale wrote:
> Add ETM4.1 periperhal ID for Marvell's ThunderX2 chip.
>
> Signed-off-by: Tanmay Jagdale <tanmay@marvell.com>
> ---
> drivers/hwtracing/coresight/coresight-etm4x.c | 2 ++
> drivers/hwtracing/coresight/coresight-etm4x.h | 1 +
> 2 files changed, 3 insertions(+)
>
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
> index 7bcac8896fc1..ac3bd617907b 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x.c
> @@ -58,6 +58,7 @@ static bool etm4_arch_supported(u8 arch)
> /* Mask out the minor version number */
> switch (arch & 0xf0) {
> case ETM_ARCH_V4:
> + case ETM_ARCH_V4_1:
Why add ETM_ARCH_V4_1 when the switch statement strips off the first byte?
Look at[1], someone already added support for 4.2.
[1]. 5666dfd1d8a4 coresight: etm4x: Add support to enable ETMv4.2
> break;
> default:
> return false;
> @@ -1196,6 +1197,7 @@ static const struct amba_id etm4_ids[] = {
> CS_AMBA_ID(0x000bb95e), /* Cortex-A57 */
> CS_AMBA_ID(0x000bb95a), /* Cortex-A72 */
> CS_AMBA_ID(0x000bb959), /* Cortex-A73 */
> + CS_AMBA_ID(0x000cc0af), /* Marvell ThunderX2 */
I suspect this processor also has "coresight-cpu-debug" IPs. If that is the
case it is very possible they both have the same CID and a UCI (see next line)
is required.
> CS_AMBA_UCI_ID(0x000bb9da, uci_id_etm4), /* Cortex-A35 */
> {},
> };
Thanks,
Mathieu
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
> index 4523f10ddd0f..03369e56b2eb 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x.h
> +++ b/drivers/hwtracing/coresight/coresight-etm4x.h
> @@ -137,6 +137,7 @@
> #define ETM_MAX_SS_CMP 8
>
> #define ETM_ARCH_V4 0x40
> +#define ETM_ARCH_V4_1 0x41
> #define ETMv4_SYNC_MASK 0x1F
> #define ETM_CYC_THRESHOLD_MASK 0xFFF
> #define ETM_CYC_THRESHOLD_DEFAULT 0x100
> --
> 2.17.1
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 04/26] mips: remove ioremap_cachable
From: Paul Burton @ 2019-08-19 20:57 UTC (permalink / raw)
To: Christoph Hellwig
Cc: linux-ia64@vger.kernel.org, linux-sh@vger.kernel.org, Guo Ren,
sparclinux@vger.kernel.org, linux-riscv@lists.infradead.org,
Vincent Chen, linux-arch@vger.kernel.org,
linux-s390@vger.kernel.org, linux-hexagon@vger.kernel.org,
x86@kernel.org, linux-snps-arc@lists.infradead.org,
linux-xtensa@linux-xtensa.org, Arnd Bergmann,
linux-m68k@lists.linux-m68k.org, openrisc@lists.librecores.org,
Greentime Hu, linux-mtd@lists.infradead.org, Guan Xuetao,
linux-arm-kernel@lists.infradead.org, Michal Simek,
linux-parisc@vger.kernel.org, linux-mips@vger.kernel.org,
linux-alpha@vger.kernel.org, nios2-dev@lists.rocketboards.org
In-Reply-To: <20190817073253.27819-5-hch@lst.de>
Hi Christoph,
On Sat, Aug 17, 2019 at 09:32:31AM +0200, Christoph Hellwig wrote:
> Just define ioremap_cache directly.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
Acked-by: Paul Burton <paul.burton@mips.com>
Thanks,
Paul
> ---
> arch/mips/include/asm/io.h | 7 +++----
> 1 file changed, 3 insertions(+), 4 deletions(-)
>
> diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h
> index 97a280640daf..c02db986ddf5 100644
> --- a/arch/mips/include/asm/io.h
> +++ b/arch/mips/include/asm/io.h
> @@ -262,11 +262,11 @@ static inline void __iomem *ioremap_prot(phys_addr_t offset,
> #define ioremap_uc ioremap_nocache
>
> /*
> - * ioremap_cachable - map bus memory into CPU space
> + * ioremap_cache - map bus memory into CPU space
> * @offset: bus address of the memory
> * @size: size of the resource to map
> *
> - * ioremap_nocache performs a platform specific sequence of operations to
> + * ioremap_cache performs a platform specific sequence of operations to
> * make bus memory CPU accessible via the readb/readw/readl/writeb/
> * writew/writel functions and the other mmio helpers. The returned
> * address is not guaranteed to be usable directly as a virtual
> @@ -276,9 +276,8 @@ static inline void __iomem *ioremap_prot(phys_addr_t offset,
> * the CPU. Also enables full write-combining. Useful for some
> * memory-like regions on I/O busses.
> */
> -#define ioremap_cachable(offset, size) \
> +#define ioremap_cache(offset, size) \
> __ioremap_mode((offset), (size), _page_cachable_default)
> -#define ioremap_cache ioremap_cachable
>
> /*
> * ioremap_wc - map bus memory into CPU space
> --
> 2.20.1
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 0/8] coresight: etm4x: Fixes and updates for sysfs API
From: Mike Leach @ 2019-08-19 20:57 UTC (permalink / raw)
To: mathieu.poirier, linux-arm-kernel, coresight; +Cc: suzuki.poulose, mike.leach
Review of ETMV4 sysfs code resulted in a number of minor issues being
discovered.
Patch set fixes these issues:-
1) Update for ETM v4.4 archtecture.
2) Add missing single shot comparator API.
3) Misc fixes and improvements to sysfs API
4) Updated programmers documentation and reference.
Mike Leach (8):
coresight: etm4x: Fixes for ETM v4.4 architecture updates.
coresight: etm4x: Fix input validation for sysfs.
coresight: etm4x: Add missing API to set EL match on address filters
coresight: etm4x: Fix issues with start-stop logic.
coresight: etm4x: Improve usability of sysfs API.
coresight: etm4x: Add view comparator settings API to sysfs.
coresight: etm4x: Add missing single-shot control API to sysfs
coresight: etm4x: docs: Additional documentation for ETM4x.
.../testing/sysfs-bus-coresight-devices-etm4x | 183 ++++---
.../{ => coresight}/coresight-cpu-debug.txt | 0
.../coresight/coresight-etm4x-reference.txt | 459 ++++++++++++++++++
.../trace/{ => coresight}/coresight.txt | 0
MAINTAINERS | 3 +-
.../coresight/coresight-etm4x-sysfs.c | 308 +++++++++++-
drivers/hwtracing/coresight/coresight-etm4x.c | 32 +-
drivers/hwtracing/coresight/coresight-etm4x.h | 18 +-
8 files changed, 902 insertions(+), 101 deletions(-)
rename Documentation/trace/{ => coresight}/coresight-cpu-debug.txt (100%)
create mode 100644 Documentation/trace/coresight/coresight-etm4x-reference.txt
rename Documentation/trace/{ => coresight}/coresight.txt (100%)
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 1/8] coresight: etm4x: Fixes for ETM v4.4 architecture updates.
From: Mike Leach @ 2019-08-19 20:57 UTC (permalink / raw)
To: mathieu.poirier, linux-arm-kernel, coresight; +Cc: suzuki.poulose, mike.leach
In-Reply-To: <20190819205720.24457-1-mike.leach@linaro.org>
ETMv4.4 adds in support for tracing secure EL2 (per arch 8.x updates).
Patch accounts for this new capability.
Signed-off-by: Mike Leach <mike.leach@linaro.org>
---
.../hwtracing/coresight/coresight-etm4x-sysfs.c | 12 ++++++------
drivers/hwtracing/coresight/coresight-etm4x.c | 5 ++++-
drivers/hwtracing/coresight/coresight-etm4x.h | 15 +++++++++++----
3 files changed, 21 insertions(+), 11 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
index 219c10eb752c..b6984be0c515 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -738,7 +738,7 @@ static ssize_t s_exlevel_vinst_show(struct device *dev,
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etmv4_config *config = &drvdata->config;
- val = BMVAL(config->vinst_ctrl, 16, 19);
+ val = (config->vinst_ctrl & ETM_EXLEVEL_S_VICTLR_MASK) >> 16;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -754,8 +754,8 @@ static ssize_t s_exlevel_vinst_store(struct device *dev,
return -EINVAL;
spin_lock(&drvdata->spinlock);
- /* clear all EXLEVEL_S bits (bit[18] is never implemented) */
- config->vinst_ctrl &= ~(BIT(16) | BIT(17) | BIT(19));
+ /* clear all EXLEVEL_S bits */
+ config->vinst_ctrl &= ~(ETM_EXLEVEL_S_VICTLR_MASK);
/* enable instruction tracing for corresponding exception level */
val &= drvdata->s_ex_level;
config->vinst_ctrl |= (val << 16);
@@ -773,7 +773,7 @@ static ssize_t ns_exlevel_vinst_show(struct device *dev,
struct etmv4_config *config = &drvdata->config;
/* EXLEVEL_NS, bits[23:20] */
- val = BMVAL(config->vinst_ctrl, 20, 23);
+ val = (config->vinst_ctrl & ETM_EXLEVEL_NS_VICTLR_MASK) >> 20;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -789,8 +789,8 @@ static ssize_t ns_exlevel_vinst_store(struct device *dev,
return -EINVAL;
spin_lock(&drvdata->spinlock);
- /* clear EXLEVEL_NS bits (bit[23] is never implemented */
- config->vinst_ctrl &= ~(BIT(20) | BIT(21) | BIT(22));
+ /* clear EXLEVEL_NS bits */
+ config->vinst_ctrl &= ~(ETM_EXLEVEL_NS_VICTLR_MASK);
/* enable instruction tracing for corresponding exception level */
val &= drvdata->ns_ex_level;
config->vinst_ctrl |= (val << 20);
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index a128b5063f46..52b8876de157 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -629,6 +629,7 @@ static void etm4_init_arch_data(void *info)
* TRCARCHMAJ, bits[11:8] architecture major versin number
*/
drvdata->arch = BMVAL(etmidr1, 4, 11);
+ drvdata->config.arch = drvdata->arch;
/* maximum size of resources */
etmidr2 = readl_relaxed(drvdata->base + TRCIDR2);
@@ -780,6 +781,7 @@ static u64 etm4_get_ns_access_type(struct etmv4_config *config)
static u64 etm4_get_access_type(struct etmv4_config *config)
{
u64 access_type = etm4_get_ns_access_type(config);
+ u64 s_hyp = (config->arch & 0x0f) >= 0x4 ? ETM_EXLEVEL_S_HYP : 0;
/*
* EXLEVEL_S, bits[11:8], don't trace anything happening
@@ -787,7 +789,8 @@ static u64 etm4_get_access_type(struct etmv4_config *config)
*/
access_type |= (ETM_EXLEVEL_S_APP |
ETM_EXLEVEL_S_OS |
- ETM_EXLEVEL_S_HYP);
+ s_hyp |
+ ETM_EXLEVEL_S_MON);
return access_type;
}
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index 4523f10ddd0f..60bc2fb5159b 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -180,17 +180,22 @@
/* PowerDown Control Register bits */
#define TRCPDCR_PU BIT(3)
-/* secure state access levels */
+/* secure state access levels - TRCACATRn */
#define ETM_EXLEVEL_S_APP BIT(8)
#define ETM_EXLEVEL_S_OS BIT(9)
-#define ETM_EXLEVEL_S_NA BIT(10)
-#define ETM_EXLEVEL_S_HYP BIT(11)
-/* non-secure state access levels */
+#define ETM_EXLEVEL_S_HYP BIT(10)
+#define ETM_EXLEVEL_S_MON BIT(11)
+/* non-secure state access levels - TRCACATRn */
#define ETM_EXLEVEL_NS_APP BIT(12)
#define ETM_EXLEVEL_NS_OS BIT(13)
#define ETM_EXLEVEL_NS_HYP BIT(14)
#define ETM_EXLEVEL_NS_NA BIT(15)
+/* secure / non secure masks - TRCVICTLR, IDR3 */
+#define ETM_EXLEVEL_S_VICTLR_MASK GENMASK(19, 16)
+/* NS MON (EL3) mode never implemented */
+#define ETM_EXLEVEL_NS_VICTLR_MASK GENMASK(22, 20)
+
/**
* struct etmv4_config - configuration information related to an ETMv4
* @mode: Controls various modes supported by this ETM.
@@ -237,6 +242,7 @@
* @vmid_mask0: VM ID comparator mask for comparator 0-3.
* @vmid_mask1: VM ID comparator mask for comparator 4-7.
* @ext_inp: External input selection.
+ * @arch: ETM architecture version (for arch dependent config).
*/
struct etmv4_config {
u32 mode;
@@ -279,6 +285,7 @@ struct etmv4_config {
u32 vmid_mask0;
u32 vmid_mask1;
u32 ext_inp;
+ u8 arch;
};
/**
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 4/8] coresight: etm4x: Fix issues with start-stop logic.
From: Mike Leach @ 2019-08-19 20:57 UTC (permalink / raw)
To: mathieu.poirier, linux-arm-kernel, coresight; +Cc: suzuki.poulose, mike.leach
In-Reply-To: <20190819205720.24457-1-mike.leach@linaro.org>
Fixes the following issues when using the ETMv4 start-stop logic.
1) Setting a start or a stop address should not automatically set the
start-stop status to 'on'. The value set by the user in 'mode' must
be respected or start instances could be missed.
2) Missing API for controlling TRCVIPCSSCTLR - start stop control by
PE comparators.
3) Default ETM configuration sets a trace all range, and correctly sets
the start-stop status bit. This was not being correctly reflected in
the 'mode' parameter.
Signed-off-by: Mike Leach <mike.leach@linaro.org>
---
.../coresight/coresight-etm4x-sysfs.c | 39 +++++++++++++++++--
drivers/hwtracing/coresight/coresight-etm4x.c | 1 +
2 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
index 7eab5d7d0b62..3bcc260c9e55 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -217,6 +217,7 @@ static ssize_t reset_store(struct device *dev,
/* No start-stop filtering for ViewInst */
config->vissctlr = 0x0;
+ config->vipcssctlr = 0x0;
/* Disable seq events */
for (i = 0; i < drvdata->nrseqstate-1; i++)
@@ -1059,8 +1060,6 @@ static ssize_t addr_start_store(struct device *dev,
config->addr_val[idx] = (u64)val;
config->addr_type[idx] = ETM_ADDR_TYPE_START;
config->vissctlr |= BIT(idx);
- /* SSSTATUS, bit[9] - turn on start/stop logic */
- config->vinst_ctrl |= BIT(9);
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1116,8 +1115,6 @@ static ssize_t addr_stop_store(struct device *dev,
config->addr_val[idx] = (u64)val;
config->addr_type[idx] = ETM_ADDR_TYPE_STOP;
config->vissctlr |= BIT(idx + 16);
- /* SSSTATUS, bit[9] - turn on start/stop logic */
- config->vinst_ctrl |= BIT(9);
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1271,6 +1268,39 @@ static ssize_t addr_exlevel_s_ns_store(struct device *dev,
}
static DEVICE_ATTR_RW(addr_exlevel_s_ns);
+static ssize_t vinst_pe_cmp_start_stop_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ unsigned long val;
+ struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
+
+ if (!drvdata->nr_pe_cmp)
+ return -EINVAL;
+ val = config->vipcssctlr;
+ return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+static ssize_t vinst_pe_cmp_start_stop_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned long val;
+ struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
+
+ if (kstrtoul(buf, 16, &val))
+ return -EINVAL;
+ if (!drvdata->nr_pe_cmp)
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ config->vipcssctlr = val;
+ spin_unlock(&drvdata->spinlock);
+ return size;
+}
+static DEVICE_ATTR_RW(vinst_pe_cmp_start_stop);
+
static ssize_t seq_idx_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -2077,6 +2107,7 @@ static struct attribute *coresight_etmv4_attrs[] = {
&dev_attr_addr_ctxtype.attr,
&dev_attr_addr_context.attr,
&dev_attr_addr_exlevel_s_ns.attr,
+ &dev_attr_vinst_pe_cmp_start_stop.attr,
&dev_attr_seq_idx.attr,
&dev_attr_seq_state.attr,
&dev_attr_seq_event.attr,
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index 52b8876de157..d8b078d0cc7f 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -868,6 +868,7 @@ static void etm4_set_default_filter(struct etmv4_config *config)
* in the started state
*/
config->vinst_ctrl |= BIT(9);
+ config->mode |= ETM_MODE_VIEWINST_STARTSTOP;
/* No start-stop filtering for ViewInst */
config->vissctlr = 0x0;
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 2/8] coresight: etm4x: Fix input validation for sysfs.
From: Mike Leach @ 2019-08-19 20:57 UTC (permalink / raw)
To: mathieu.poirier, linux-arm-kernel, coresight; +Cc: suzuki.poulose, mike.leach
In-Reply-To: <20190819205720.24457-1-mike.leach@linaro.org>
A number of issues are fixed relating to sysfs input validation:-
1) bb_ctrl_store() - incorrect compare of bit select field to absolute
value. Reworked per ETMv4 specification.
2) seq_event_store() - incorrect mask value - register has two
event values.
3) cyc_threshold_store() - must mask with max before checking min
otherwise wrapped values can set illegal value below min.
4) res_ctrl_store() - update to mask off all res0 bits.
Signed-off-by: Mike Leach <mike.leach@linaro.org>
---
.../coresight/coresight-etm4x-sysfs.c | 21 ++++++++++++-------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
index b6984be0c515..fa1d6a938f6c 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -652,10 +652,13 @@ static ssize_t cyc_threshold_store(struct device *dev,
if (kstrtoul(buf, 16, &val))
return -EINVAL;
+
+ /* mask off max threshold before checking min value */
+ val &= ETM_CYC_THRESHOLD_MASK;
if (val < drvdata->ccitmin)
return -EINVAL;
- config->ccctlr = val & ETM_CYC_THRESHOLD_MASK;
+ config->ccctlr = val;
return size;
}
static DEVICE_ATTR_RW(cyc_threshold);
@@ -686,14 +689,16 @@ static ssize_t bb_ctrl_store(struct device *dev,
return -EINVAL;
if (!drvdata->nr_addr_cmp)
return -EINVAL;
+
/*
- * Bit[7:0] selects which address range comparator is used for
- * branch broadcast control.
+ * Bit[8] controls include(1) / exclude(0), bits[0-7] select
+ * individual range comparators. If include then at least 1
+ * range must be selected.
*/
- if (BMVAL(val, 0, 7) > drvdata->nr_addr_cmp)
+ if ((val & BIT(8)) && (BMVAL(val, 0, 7) == 0))
return -EINVAL;
- config->bb_ctrl = val;
+ config->bb_ctrl = val & GENMASK(8, 0);
return size;
}
static DEVICE_ATTR_RW(bb_ctrl);
@@ -1324,8 +1329,8 @@ static ssize_t seq_event_store(struct device *dev,
spin_lock(&drvdata->spinlock);
idx = config->seq_idx;
- /* RST, bits[7:0] */
- config->seq_ctrl[idx] = val & 0xFF;
+ /* Seq control has two masks B[15:5] F[7:0] */
+ config->seq_ctrl[idx] = val & 0xFFFF;
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1580,7 +1585,7 @@ static ssize_t res_ctrl_store(struct device *dev,
if (idx % 2 != 0)
/* PAIRINV, bit[21] */
val &= ~BIT(21);
- config->res_ctrl[idx] = val;
+ config->res_ctrl[idx] = val & GENMASK(21, 0);
spin_unlock(&drvdata->spinlock);
return size;
}
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 5/8] coresight: etm4x: Improve usability of sysfs API.
From: Mike Leach @ 2019-08-19 20:57 UTC (permalink / raw)
To: mathieu.poirier, linux-arm-kernel, coresight; +Cc: suzuki.poulose, mike.leach
In-Reply-To: <20190819205720.24457-1-mike.leach@linaro.org>
Some changes to make the sysfs programming more intuitive.
1) Setting include / exclude on a range had to be done by setting
the bit in 'mode' before setting the range. However, setting this
bit also had the effect of altering the current range as well.
Changed to only set include / exclude setting of a range at the point of
setting that range. Either use a 3rd input parameter as the include exclude
value, or if not present use the current value of 'mode'. Do not change
current range when 'mode' changes.
2) Context ID and VM ID masks required 2 value inputs, even when the
second value is ignored as insufficient CID / VMID comparators are
implemented.
Permit a single value to be used if that is sufficient to cover all
implemented comparators.
Signed-off-by: Mike Leach <mike.leach@linaro.org>
---
.../coresight/coresight-etm4x-sysfs.c | 24 +++++++++++++------
1 file changed, 17 insertions(+), 7 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
index 3bcc260c9e55..baac5b48b7ac 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -297,8 +297,6 @@ static ssize_t mode_store(struct device *dev,
spin_lock(&drvdata->spinlock);
config->mode = val & ETMv4_MODE_ALL;
- etm4_set_mode_exclude(drvdata,
- config->mode & ETM_MODE_EXCLUDE ? true : false);
if (drvdata->instrp0 == true) {
/* start by clearing instruction P0 field */
@@ -972,8 +970,12 @@ static ssize_t addr_range_store(struct device *dev,
unsigned long val1, val2;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etmv4_config *config = &drvdata->config;
+ int elements, exclude;
- if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
+ elements = sscanf(buf, "%lx %lx %x", &val1, &val2, &exclude);
+
+ /* exclude is optional, but need at least two parameter */
+ if (elements < 2)
return -EINVAL;
/* lower address comparator cannot have a higher address value */
if (val1 > val2)
@@ -1001,9 +1003,11 @@ static ssize_t addr_range_store(struct device *dev,
/*
* Program include or exclude control bits for vinst or vdata
* whenever we change addr comparators to ETM_ADDR_TYPE_RANGE
+ * use supplied value, or default to bit set in 'mode'
*/
- etm4_set_mode_exclude(drvdata,
- config->mode & ETM_MODE_EXCLUDE ? true : false);
+ if (elements != 3)
+ exclude = config->mode & ETM_MODE_EXCLUDE;
+ etm4_set_mode_exclude(drvdata, exclude ? true : false);
spin_unlock(&drvdata->spinlock);
return size;
@@ -1787,6 +1791,7 @@ static ssize_t ctxid_masks_store(struct device *dev,
unsigned long val1, val2, mask;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etmv4_config *config = &drvdata->config;
+ int nr_inputs;
/*
* Don't use contextID tracing if coming from a PID namespace. See
@@ -1802,7 +1807,9 @@ static ssize_t ctxid_masks_store(struct device *dev,
*/
if (!drvdata->ctxid_size || !drvdata->numcidc)
return -EINVAL;
- if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
+ /* one mask if < 4 comparators, two for up to 8 */
+ nr_inputs = sscanf(buf, "%lx %lx", &val1, &val2);
+ if ((drvdata->numcidc > 4) && (nr_inputs != 2))
return -EINVAL;
spin_lock(&drvdata->spinlock);
@@ -1976,6 +1983,7 @@ static ssize_t vmid_masks_store(struct device *dev,
unsigned long val1, val2, mask;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etmv4_config *config = &drvdata->config;
+ int nr_inputs;
/*
* only implemented when vmid tracing is enabled, i.e. at least one
@@ -1983,7 +1991,9 @@ static ssize_t vmid_masks_store(struct device *dev,
*/
if (!drvdata->vmid_size || !drvdata->numvmidc)
return -EINVAL;
- if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
+ /* one mask if < 4 comparators, two for up to 8 */
+ nr_inputs = sscanf(buf, "%lx %lx", &val1, &val2);
+ if ((drvdata->numvmidc > 4) && (nr_inputs != 2))
return -EINVAL;
spin_lock(&drvdata->spinlock);
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 7/8] coresight: etm4x: Add missing single-shot control API to sysfs
From: Mike Leach @ 2019-08-19 20:57 UTC (permalink / raw)
To: mathieu.poirier, linux-arm-kernel, coresight; +Cc: suzuki.poulose, mike.leach
In-Reply-To: <20190819205720.24457-1-mike.leach@linaro.org>
An API to control single-shot comparator operation was missing from sysfs.
This adds the parameters to sysfs to allow programming of this feature.
Signed-off-by: Mike Leach <mike.leach@linaro.org>
---
.../coresight/coresight-etm4x-sysfs.c | 122 ++++++++++++++++++
drivers/hwtracing/coresight/coresight-etm4x.c | 26 +++-
drivers/hwtracing/coresight/coresight-etm4x.h | 3 +
3 files changed, 150 insertions(+), 1 deletion(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
index 483976074779..7c019dda1236 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -239,6 +239,7 @@ static ssize_t reset_store(struct device *dev,
for (i = 0; i < drvdata->nr_resource; i++)
config->res_ctrl[i] = 0x0;
+ config->ss_idx = 0x0;
for (i = 0; i < drvdata->nr_ss_cmp; i++) {
config->ss_ctrl[i] = 0x0;
config->ss_pe_cmp[i] = 0x0;
@@ -1713,6 +1714,123 @@ static ssize_t res_ctrl_store(struct device *dev,
}
static DEVICE_ATTR_RW(res_ctrl);
+static ssize_t sshot_idx_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
+
+ val = config->ss_idx;
+ return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t sshot_idx_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned long val;
+ struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
+
+ if (kstrtoul(buf, 16, &val))
+ return -EINVAL;
+ if (val >= drvdata->nr_ss_cmp)
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ config->ss_idx = val;
+ spin_unlock(&drvdata->spinlock);
+ return size;
+}
+static DEVICE_ATTR_RW(sshot_idx);
+
+static ssize_t sshot_ctrl_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ unsigned long val;
+ struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
+
+ spin_lock(&drvdata->spinlock);
+ val = config->ss_ctrl[config->ss_idx];
+ spin_unlock(&drvdata->spinlock);
+ return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t sshot_ctrl_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ u8 idx;
+ unsigned long val;
+ struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
+
+ if (kstrtoul(buf, 16, &val))
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ idx = config->ss_idx;
+ config->ss_ctrl[idx] = val & GENMASK(24, 0);
+ /* must clear bit 31 in related status register on programming */
+ config->ss_status[idx] &= ~BIT(31);
+ spin_unlock(&drvdata->spinlock);
+ return size;
+}
+static DEVICE_ATTR_RW(sshot_ctrl);
+
+static ssize_t sshot_status_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long val;
+ struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
+
+ spin_lock(&drvdata->spinlock);
+ val = config->ss_status[config->ss_idx];
+ spin_unlock(&drvdata->spinlock);
+ return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+static DEVICE_ATTR_RO(sshot_status);
+
+static ssize_t sshot_pe_ctrl_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ unsigned long val;
+ struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
+
+ spin_lock(&drvdata->spinlock);
+ val = config->ss_pe_cmp[config->ss_idx];
+ spin_unlock(&drvdata->spinlock);
+ return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t sshot_pe_ctrl_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ u8 idx;
+ unsigned long val;
+ struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etmv4_config *config = &drvdata->config;
+
+ if (kstrtoul(buf, 16, &val))
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ idx = config->ss_idx;
+ config->ss_ctrl[idx] = val & GENMASK(7, 0);
+ /* must clear bit 31 in related status register on programming */
+ config->ss_status[idx] &= ~BIT(31);
+ spin_unlock(&drvdata->spinlock);
+ return size;
+}
+static DEVICE_ATTR_RW(sshot_pe_ctrl);
+
static ssize_t ctxid_idx_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -2169,6 +2287,10 @@ static struct attribute *coresight_etmv4_attrs[] = {
&dev_attr_addr_exlevel_s_ns.attr,
&dev_attr_addr_cmp_view.attr,
&dev_attr_vinst_pe_cmp_start_stop.attr,
+ &dev_attr_sshot_idx.attr,
+ &dev_attr_sshot_ctrl.attr,
+ &dev_attr_sshot_pe_ctrl.attr,
+ &dev_attr_sshot_status.attr,
&dev_attr_seq_idx.attr,
&dev_attr_seq_state.attr,
&dev_attr_seq_event.attr,
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index d8b078d0cc7f..fb7083218410 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -149,6 +149,9 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
drvdata->base + TRCRSCTLRn(i));
for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+ /* always clear status bit on restart if using single-shot */
+ if (config->ss_ctrl[i] || config->ss_pe_cmp[i])
+ config->ss_status[i] &= ~BIT(31);
writel_relaxed(config->ss_ctrl[i],
drvdata->base + TRCSSCCRn(i));
writel_relaxed(config->ss_status[i],
@@ -448,6 +451,9 @@ static void etm4_disable_hw(void *info)
{
u32 control;
struct etmv4_drvdata *drvdata = info;
+ struct etmv4_config *config = &drvdata->config;
+ struct device *etm_dev = &drvdata->csdev->dev;
+ int i;
CS_UNLOCK(drvdata->base);
@@ -470,6 +476,18 @@ static void etm4_disable_hw(void *info)
isb();
writel_relaxed(control, drvdata->base + TRCPRGCTLR);
+ /* wait for TRCSTATR.PMSTABLE to go to '1' */
+ if (coresight_timeout(drvdata->base, TRCSTATR,
+ TRCSTATR_PMSTABLE_BIT, 1))
+ dev_err(etm_dev,
+ "timeout while waiting for PM stable Trace Status\n");
+
+ /* read the status of the single shot comparators */
+ for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+ config->ss_status[i] =
+ readl_relaxed(drvdata->base + TRCSSCSRn(i));
+ }
+
coresight_disclaim_device_unlocked(drvdata->base);
CS_LOCK(drvdata->base);
@@ -576,6 +594,7 @@ static void etm4_init_arch_data(void *info)
u32 etmidr4;
u32 etmidr5;
struct etmv4_drvdata *drvdata = info;
+ int i;
/* Make sure all registers are accessible */
etm4_os_unlock(drvdata);
@@ -699,9 +718,14 @@ static void etm4_init_arch_data(void *info)
drvdata->nr_resource = BMVAL(etmidr4, 16, 19) + 1;
/*
* NUMSSCC, bits[23:20] the number of single-shot
- * comparator control for tracing
+ * comparator control for tracing. Read any status regs as these
+ * also contain RO capability data.
*/
drvdata->nr_ss_cmp = BMVAL(etmidr4, 20, 23);
+ for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+ drvdata->config.ss_status[i] =
+ readl_relaxed(drvdata->base + TRCSSCSRn(i));
+ }
/* NUMCIDC, bits[27:24] number of Context ID comparators for tracing */
drvdata->numcidc = BMVAL(etmidr4, 24, 27);
/* NUMVMIDC, bits[31:28] number of VMID comparators for tracing */
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index 60bc2fb5159b..be8b32ea1654 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -175,6 +175,7 @@
ETM_MODE_EXCL_USER)
#define TRCSTATR_IDLE_BIT 0
+#define TRCSTATR_PMSTABLE_BIT 1
#define ETM_DEFAULT_ADDR_COMP 0
/* PowerDown Control Register bits */
@@ -226,6 +227,7 @@
* @cntr_val: Sets or returns the value for a counter.
* @res_idx: Resource index selector.
* @res_ctrl: Controls the selection of the resources in the trace unit.
+ * @ss_idx: Single-shot index selector.
* @ss_ctrl: Controls the corresponding single-shot comparator resource.
* @ss_status: The status of the corresponding single-shot comparator.
* @ss_pe_cmp: Selects the PE comparator inputs for Single-shot control.
@@ -269,6 +271,7 @@ struct etmv4_config {
u32 cntr_val[ETMv4_MAX_CNTR];
u8 res_idx;
u32 res_ctrl[ETM_MAX_RES_SEL];
+ u8 ss_idx;
u32 ss_ctrl[ETM_MAX_SS_CMP];
u32 ss_status[ETM_MAX_SS_CMP];
u32 ss_pe_cmp[ETM_MAX_SS_CMP];
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox