Commit 374a528111fa07878090bd9694a3e153814de39c
Committed by
Mark Brown
1 parent
849fc82a6f
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
ASoC: rsnd: SSI supports DMA transfer via BUSIF
This patch adds BUSIF support for R-Car sound DMAEngine transfer. The sound data will be transferred via FIFO which can cover blank time which will happen when DMA channel is switching. Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown <broonie@linaro.org>
Showing 5 changed files with 190 additions and 7 deletions Side-by-side Diff
include/sound/rcar_snd.h
... | ... | @@ -36,6 +36,7 @@ |
36 | 36 | #define RSND_SSI_CLK_PIN_SHARE (1 << 31) |
37 | 37 | #define RSND_SSI_CLK_FROM_ADG (1 << 30) /* clock parent is master */ |
38 | 38 | #define RSND_SSI_SYNC (1 << 29) /* SSI34_sync etc */ |
39 | +#define RSND_SSI_DEPENDENT (1 << 28) /* SSI needs SRU/SCU */ | |
39 | 40 | |
40 | 41 | #define RSND_SSI_PLAY (1 << 24) |
41 | 42 | |
... | ... | @@ -50,6 +51,11 @@ |
50 | 51 | int pio_irq; |
51 | 52 | u32 flags; |
52 | 53 | }; |
54 | + | |
55 | +/* | |
56 | + * flags | |
57 | + */ | |
58 | +#define RSND_SCU_USB_HPBIF (1 << 31) /* it needs RSND_SSI_DEPENDENT */ | |
53 | 59 | |
54 | 60 | struct rsnd_scu_platform_info { |
55 | 61 | u32 flags; |
sound/soc/sh/rcar/gen.c
... | ... | @@ -34,9 +34,6 @@ |
34 | 34 | |
35 | 35 | #define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) |
36 | 36 | |
37 | -#define rsnd_is_gen1(s) ((s)->info->flags & RSND_GEN1) | |
38 | -#define rsnd_is_gen2(s) ((s)->info->flags & RSND_GEN2) | |
39 | - | |
40 | 37 | /* |
41 | 38 | * Gen2 |
42 | 39 | * will be filled in the future |
43 | 40 | |
... | ... | @@ -115,8 +112,15 @@ |
115 | 112 | |
116 | 113 | static void rsnd_gen1_reg_map_init(struct rsnd_gen *gen) |
117 | 114 | { |
115 | + RSND_GEN1_REG_MAP(gen, SRU, SRC_ROUTE_SEL, 0x0, 0x00); | |
116 | + RSND_GEN1_REG_MAP(gen, SRU, SRC_TMG_SEL0, 0x0, 0x08); | |
117 | + RSND_GEN1_REG_MAP(gen, SRU, SRC_TMG_SEL1, 0x0, 0x0c); | |
118 | + RSND_GEN1_REG_MAP(gen, SRU, SRC_TMG_SEL2, 0x0, 0x10); | |
119 | + RSND_GEN1_REG_MAP(gen, SRU, SRC_CTRL, 0x0, 0xc0); | |
118 | 120 | RSND_GEN1_REG_MAP(gen, SRU, SSI_MODE0, 0x0, 0xD0); |
119 | 121 | RSND_GEN1_REG_MAP(gen, SRU, SSI_MODE1, 0x0, 0xD4); |
122 | + RSND_GEN1_REG_MAP(gen, SRU, BUSIF_MODE, 0x4, 0x20); | |
123 | + RSND_GEN1_REG_MAP(gen, SRU, BUSIF_ADINR, 0x40, 0x214); | |
120 | 124 | |
121 | 125 | RSND_GEN1_REG_MAP(gen, ADG, BRRA, 0x0, 0x00); |
122 | 126 | RSND_GEN1_REG_MAP(gen, ADG, BRRB, 0x0, 0x04); |
sound/soc/sh/rcar/rsnd.h
... | ... | @@ -32,8 +32,15 @@ |
32 | 32 | */ |
33 | 33 | enum rsnd_reg { |
34 | 34 | /* SRU/SCU */ |
35 | + RSND_REG_SRC_ROUTE_SEL, | |
36 | + RSND_REG_SRC_TMG_SEL0, | |
37 | + RSND_REG_SRC_TMG_SEL1, | |
38 | + RSND_REG_SRC_TMG_SEL2, | |
39 | + RSND_REG_SRC_CTRL, | |
35 | 40 | RSND_REG_SSI_MODE0, |
36 | 41 | RSND_REG_SSI_MODE1, |
42 | + RSND_REG_BUSIF_MODE, | |
43 | + RSND_REG_BUSIF_ADINR, | |
37 | 44 | |
38 | 45 | /* ADG */ |
39 | 46 | RSND_REG_BRRA, |
... | ... | @@ -213,6 +220,8 @@ |
213 | 220 | void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, |
214 | 221 | struct rsnd_mod *mod, |
215 | 222 | enum rsnd_reg reg); |
223 | +#define rsnd_is_gen1(s) ((s)->info->flags & RSND_GEN1) | |
224 | +#define rsnd_is_gen2(s) ((s)->info->flags & RSND_GEN2) | |
216 | 225 | |
217 | 226 | /* |
218 | 227 | * R-Car ADG |
sound/soc/sh/rcar/scu.c
... | ... | @@ -15,6 +15,18 @@ |
15 | 15 | struct rsnd_mod mod; |
16 | 16 | }; |
17 | 17 | |
18 | +#define rsnd_scu_mode_flags(p) ((p)->info->flags) | |
19 | + | |
20 | +/* | |
21 | + * ADINR | |
22 | + */ | |
23 | +#define OTBL_24 (0 << 16) | |
24 | +#define OTBL_22 (2 << 16) | |
25 | +#define OTBL_20 (4 << 16) | |
26 | +#define OTBL_18 (6 << 16) | |
27 | +#define OTBL_16 (8 << 16) | |
28 | + | |
29 | + | |
18 | 30 | #define rsnd_mod_to_scu(_mod) \ |
19 | 31 | container_of((_mod), struct rsnd_scu, mod) |
20 | 32 | |
... | ... | @@ -24,6 +36,116 @@ |
24 | 36 | ((pos) = (struct rsnd_scu *)(priv)->scu + i); \ |
25 | 37 | i++) |
26 | 38 | |
39 | +static int rsnd_scu_set_route(struct rsnd_priv *priv, | |
40 | + struct rsnd_mod *mod, | |
41 | + struct rsnd_dai *rdai, | |
42 | + struct rsnd_dai_stream *io) | |
43 | +{ | |
44 | + struct scu_route_config { | |
45 | + u32 mask; | |
46 | + int shift; | |
47 | + } routes[] = { | |
48 | + { 0xF, 0, }, /* 0 */ | |
49 | + { 0xF, 4, }, /* 1 */ | |
50 | + { 0xF, 8, }, /* 2 */ | |
51 | + { 0x7, 12, }, /* 3 */ | |
52 | + { 0x7, 16, }, /* 4 */ | |
53 | + { 0x7, 20, }, /* 5 */ | |
54 | + { 0x7, 24, }, /* 6 */ | |
55 | + { 0x3, 28, }, /* 7 */ | |
56 | + { 0x3, 30, }, /* 8 */ | |
57 | + }; | |
58 | + | |
59 | + u32 mask; | |
60 | + u32 val; | |
61 | + int shift; | |
62 | + int id; | |
63 | + | |
64 | + /* | |
65 | + * Gen1 only | |
66 | + */ | |
67 | + if (!rsnd_is_gen1(priv)) | |
68 | + return 0; | |
69 | + | |
70 | + id = rsnd_mod_id(mod); | |
71 | + if (id < 0 || id > ARRAY_SIZE(routes)) | |
72 | + return -EIO; | |
73 | + | |
74 | + /* | |
75 | + * SRC_ROUTE_SELECT | |
76 | + */ | |
77 | + val = rsnd_dai_is_play(rdai, io) ? 0x1 : 0x2; | |
78 | + val = val << routes[id].shift; | |
79 | + mask = routes[id].mask << routes[id].shift; | |
80 | + | |
81 | + rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val); | |
82 | + | |
83 | + /* | |
84 | + * SRC_TIMING_SELECT | |
85 | + */ | |
86 | + shift = (id % 4) * 8; | |
87 | + mask = 0x1F << shift; | |
88 | + if (8 == id) /* SRU8 is very special */ | |
89 | + val = id << shift; | |
90 | + else | |
91 | + val = (id + 1) << shift; | |
92 | + | |
93 | + switch (id / 4) { | |
94 | + case 0: | |
95 | + rsnd_mod_bset(mod, SRC_TMG_SEL0, mask, val); | |
96 | + break; | |
97 | + case 1: | |
98 | + rsnd_mod_bset(mod, SRC_TMG_SEL1, mask, val); | |
99 | + break; | |
100 | + case 2: | |
101 | + rsnd_mod_bset(mod, SRC_TMG_SEL2, mask, val); | |
102 | + break; | |
103 | + } | |
104 | + | |
105 | + return 0; | |
106 | +} | |
107 | + | |
108 | +static int rsnd_scu_set_mode(struct rsnd_priv *priv, | |
109 | + struct rsnd_mod *mod, | |
110 | + struct rsnd_dai *rdai, | |
111 | + struct rsnd_dai_stream *io) | |
112 | +{ | |
113 | + int id = rsnd_mod_id(mod); | |
114 | + u32 val; | |
115 | + | |
116 | + if (rsnd_is_gen1(priv)) { | |
117 | + val = (1 << id); | |
118 | + rsnd_mod_bset(mod, SRC_CTRL, val, val); | |
119 | + } | |
120 | + | |
121 | + return 0; | |
122 | +} | |
123 | + | |
124 | +static int rsnd_scu_set_hpbif(struct rsnd_priv *priv, | |
125 | + struct rsnd_mod *mod, | |
126 | + struct rsnd_dai *rdai, | |
127 | + struct rsnd_dai_stream *io) | |
128 | +{ | |
129 | + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | |
130 | + u32 adinr = runtime->channels; | |
131 | + | |
132 | + switch (runtime->sample_bits) { | |
133 | + case 16: | |
134 | + adinr |= OTBL_16; | |
135 | + break; | |
136 | + case 32: | |
137 | + adinr |= OTBL_24; | |
138 | + break; | |
139 | + default: | |
140 | + return -EIO; | |
141 | + } | |
142 | + | |
143 | + rsnd_mod_write(mod, BUSIF_MODE, 1); | |
144 | + rsnd_mod_write(mod, BUSIF_ADINR, adinr); | |
145 | + | |
146 | + return 0; | |
147 | +} | |
148 | + | |
27 | 149 | static int rsnd_scu_init(struct rsnd_mod *mod, |
28 | 150 | struct rsnd_dai *rdai, |
29 | 151 | struct rsnd_dai_stream *io) |
30 | 152 | |
31 | 153 | |
32 | 154 | |
... | ... | @@ -53,10 +175,37 @@ |
53 | 175 | struct rsnd_dai_stream *io) |
54 | 176 | { |
55 | 177 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
178 | + struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | |
56 | 179 | struct device *dev = rsnd_priv_to_dev(priv); |
180 | + u32 flags = rsnd_scu_mode_flags(scu); | |
181 | + int ret; | |
57 | 182 | |
58 | - dev_dbg(dev, "%s.%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | |
183 | + /* | |
184 | + * SCU will be used if it has RSND_SCU_USB_HPBIF flags | |
185 | + */ | |
186 | + if (!(flags & RSND_SCU_USB_HPBIF)) { | |
187 | + /* it use PIO transter */ | |
188 | + dev_dbg(dev, "%s%d is not used\n", | |
189 | + rsnd_mod_name(mod), rsnd_mod_id(mod)); | |
59 | 190 | |
191 | + return 0; | |
192 | + } | |
193 | + | |
194 | + /* it use DMA transter */ | |
195 | + ret = rsnd_scu_set_route(priv, mod, rdai, io); | |
196 | + if (ret < 0) | |
197 | + return ret; | |
198 | + | |
199 | + ret = rsnd_scu_set_mode(priv, mod, rdai, io); | |
200 | + if (ret < 0) | |
201 | + return ret; | |
202 | + | |
203 | + ret = rsnd_scu_set_hpbif(priv, mod, rdai, io); | |
204 | + if (ret < 0) | |
205 | + return ret; | |
206 | + | |
207 | + dev_dbg(dev, "%s%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | |
208 | + | |
60 | 209 | return 0; |
61 | 210 | } |
62 | 211 | |
63 | 212 | |
... | ... | @@ -112,8 +261,9 @@ |
112 | 261 | rsnd_mod_init(priv, &scu->mod, |
113 | 262 | &rsnd_scu_ops, i); |
114 | 263 | scu->info = &info->scu_info[i]; |
115 | - } | |
116 | 264 | |
265 | + dev_dbg(dev, "SCU%d probed\n", i); | |
266 | + } | |
117 | 267 | dev_dbg(dev, "scu probed\n"); |
118 | 268 | |
119 | 269 | return 0; |
sound/soc/sh/rcar/ssi.c
... | ... | @@ -104,6 +104,7 @@ |
104 | 104 | static void rsnd_ssi_mode_init(struct rsnd_priv *priv, |
105 | 105 | struct rsnd_ssiu *ssiu) |
106 | 106 | { |
107 | + struct device *dev = rsnd_priv_to_dev(priv); | |
107 | 108 | struct rsnd_ssi *ssi; |
108 | 109 | u32 flags; |
109 | 110 | u32 val; |
110 | 111 | |
... | ... | @@ -113,9 +114,18 @@ |
113 | 114 | * SSI_MODE0 |
114 | 115 | */ |
115 | 116 | ssiu->ssi_mode0 = 0; |
116 | - for_each_rsnd_ssi(ssi, priv, i) | |
117 | - ssiu->ssi_mode0 |= (1 << i); | |
117 | + for_each_rsnd_ssi(ssi, priv, i) { | |
118 | + flags = rsnd_ssi_mode_flags(ssi); | |
118 | 119 | |
120 | + /* see also BUSIF_MODE */ | |
121 | + if (!(flags & RSND_SSI_DEPENDENT)) { | |
122 | + ssiu->ssi_mode0 |= (1 << i); | |
123 | + dev_dbg(dev, "SSI%d uses INDEPENDENT mode\n", i); | |
124 | + } else { | |
125 | + dev_dbg(dev, "SSI%d uses DEPENDENT mode\n", i); | |
126 | + } | |
127 | + } | |
128 | + | |
119 | 129 | /* |
120 | 130 | * SSI_MODE1 |
121 | 131 | */ |
... | ... | @@ -670,6 +680,8 @@ |
670 | 680 | dev_info(dev, "SSI DMA failed. try PIO transter\n"); |
671 | 681 | else |
672 | 682 | ops = &rsnd_ssi_dma_ops; |
683 | + | |
684 | + dev_dbg(dev, "SSI%d use DMA transfer\n", i); | |
673 | 685 | } |
674 | 686 | |
675 | 687 | /* |
... | ... | @@ -687,6 +699,8 @@ |
687 | 699 | } |
688 | 700 | |
689 | 701 | ops = &rsnd_ssi_pio_ops; |
702 | + | |
703 | + dev_dbg(dev, "SSI%d use PIO transfer\n", i); | |
690 | 704 | } |
691 | 705 | |
692 | 706 | rsnd_mod_init(priv, &ssi->mod, ops, i); |