summaryrefslogtreecommitdiff
path: root/sound/soc/omap/abe/abe_lib.c
blob: d95afe74343fcea81d9ed82620f1ea4ca162f647 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
/*
 * ALSA SoC OMAP ABE driver
 *
 * Author:	Laurent Le Faucheur <l-le-faucheur@ti.com>
 *	Liam Girdwood <lrg@slimlogic.co.uk>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */
#include "abe_main.h"
/**
* abe_fprintf
* @line: character line to be printed
*
* Print ABE debug messages.
*/
/**
 * abe_read_feature_from_port
 * @x: d
 *
 * TBD
 *
 */
void abe_read_feature_from_port(u32 x)
{
}
/**
 * abe_write_feature_to_port
 * @x: d
 *
 * TBD
 *
 */
void abe_write_feature_to_port(u32 x)
{
}
/**
 * abe_read_fifo
 * @x: d
 *
 * TBD
 */
void abe_read_fifo(u32 x)
{
}
/**
 * abe_write_fifo
 * @mem_bank: currently only ABE_DMEM supported
 * @addr: FIFO descriptor address ( descriptor fields : READ ptr, WRITE ptr,
 * FIFO START_ADDR, FIFO END_ADDR)
 * @data: data to write to FIFO
 * @number: number of 32-bit words to write to DMEM FIFO
 *
 * write DMEM FIFO and update FIFO descriptor, it is assumed that FIFO descriptor
 * is located in DMEM
 */
void abe_write_fifo(u32 memory_bank, u32 descr_addr, u32 *data, u32 nb_data32)
{
	u32 fifo_addr[4];
	u32 i;
	/* read FIFO descriptor from DMEM */
	abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM, descr_addr,
		       &fifo_addr[0], 4 * sizeof(u32));
	/* WRITE ptr < FIFO start address */
	if (fifo_addr[1] < fifo_addr[2])
		abe_dbg_error_log(ABE_FW_FIFO_WRITE_PTR_ERR);
	/* WRITE ptr > FIFO end address */
	if (fifo_addr[1] > fifo_addr[3])
		abe_dbg_error_log(ABE_FW_FIFO_WRITE_PTR_ERR);
	switch (memory_bank) {
	case ABE_DMEM:
		for (i = 0; i < nb_data32; i++) {
			abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
				       (s32) fifo_addr[1], (u32 *) (data + i),
				       4);
			/* increment WRITE pointer */
			fifo_addr[1] = fifo_addr[1] + 4;
			if (fifo_addr[1] > fifo_addr[3])
				fifo_addr[1] = fifo_addr[2];
			if (fifo_addr[1] == fifo_addr[0])
				abe_dbg_error_log(ABE_FW_FIFO_WRITE_PTR_ERR);
		}
		/* update WRITE pointer in DMEM */
		abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, descr_addr +
			       sizeof(u32), &fifo_addr[1], 4);
		break;
	default:
		/* printf("currently only DMEM FIFO write supported ERROR\n"); */
		break;
	}
}
/**
 * abe_monitoring
 *
 * checks the internal status of ABE and HAL
 */
void abe_monitoring(void)
{
	abe_dbg_param = 0;
}
/**
 * abe_format_switch
 * @f: port format
 * @iter: port iteration
 * @mulfac: multiplication factor
 *
 * translates the sampling and data length to ITER number for the DMA
 * and the multiplier factor to apply during data move with DMEM
 *
 */
void abe_format_switch(abe_data_format_t *f, u32 *iter, u32 *mulfac)
{
	u32 n_freq;
#if FW_SCHED_LOOP_FREQ==4000
	switch (f->f) {
		/* nb of samples processed by scheduling loop */
	case 8000:
		n_freq = 2;
		break;
	case 16000:
		n_freq = 4;
		break;
	case 24000:
		n_freq = 6;
		break;
	case 44100:
		n_freq = 12;
		break;
	case 96000:
		n_freq = 24;
		break;
	default/*case 48000 */ :
		n_freq = 12;
		break;
	}
#else
	/* erroneous cases */
	n_freq = 0;
#endif
	switch (f->samp_format) {
	case MONO_MSB:
	case MONO_RSHIFTED_16:
	case STEREO_16_16:
		*mulfac = 1;
		break;
	case STEREO_MSB:
	case STEREO_RSHIFTED_16:
		*mulfac = 2;
		break;
	case THREE_MSB:
		*mulfac = 3;
		break;
	case FOUR_MSB:
		*mulfac = 4;
		break;
	case FIVE_MSB:
		*mulfac = 5;
		break;
	case SIX_MSB:
		*mulfac = 6;
		break;
	case SEVEN_MSB:
		*mulfac = 7;
		break;
	case EIGHT_MSB:
		*mulfac = 8;
		break;
	case NINE_MSB:
		*mulfac = 9;
		break;
	default:
		*mulfac = 1;
		break;
	}
	*iter = (n_freq * (*mulfac));
}
/**
 * abe_dma_port_iteration
 * @f: port format
 *
 * translates the sampling and data length to ITER number for the DMA
 */
u32 abe_dma_port_iteration(abe_data_format_t *f)
{
	u32 iter, mulfac;
	abe_format_switch(f, &iter, &mulfac);
	return iter;
}
/**
 * abe_dma_port_iter_factor
 * @f: port format
 *
 * returns the multiplier factor to apply during data move with DMEM
 */
u32 abe_dma_port_iter_factor(abe_data_format_t *f)
{
	u32 iter, mulfac;
	abe_format_switch(f, &iter, &mulfac);
	return mulfac;
}
/**
 * abe_dma_port_copy_subroutine_id
 *
 * @port_id: ABE port ID
 *
 * returns the index of the function doing the copy in I/O tasks
 */
u32 abe_dma_port_copy_subroutine_id(u32 port_id)
{
	u32 sub_id;
	if (abe_port[port_id].protocol.direction == ABE_ATC_DIRECTION_IN) {
		switch (abe_port[port_id].format.samp_format) {
		case MONO_MSB:
			sub_id = D2S_MONO_MSB_CFPID;
			break;
		case MONO_RSHIFTED_16:
			sub_id = D2S_MONO_RSHIFTED_16_CFPID;
			break;
		case STEREO_RSHIFTED_16:
			sub_id = D2S_STEREO_RSHIFTED_16_CFPID;
			break;
		case STEREO_16_16:
			sub_id = D2S_STEREO_16_16_CFPID;
			break;
		case STEREO_MSB:
			sub_id = D2S_STEREO_MSB_CFPID;
			break;
		case SIX_MSB:
			if (port_id == DMIC_PORT) {
				sub_id = COPY_DMIC_CFPID;
				break;
			}
		default:
			sub_id = NULL_COPY_CFPID;
			break;
		}
	} else {
		switch (abe_port[port_id].format.samp_format) {
		case MONO_MSB:
			sub_id = S2D_MONO_MSB_CFPID;
			break;
		case MONO_RSHIFTED_16:
			sub_id = S2D_MONO_RSHIFTED_16_CFPID;
			break;
		case STEREO_RSHIFTED_16:
			sub_id = S2D_STEREO_RSHIFTED_16_CFPID;
			break;
		case STEREO_16_16:
			sub_id = S2D_STEREO_16_16_CFPID;
			break;
		case STEREO_MSB:
			sub_id = S2D_STEREO_MSB_CFPID;
			break;
		case SIX_MSB:
			if (port_id == PDM_DL_PORT) {
				sub_id = COPY_MCPDM_DL_CFPID;
				break;
			}
			if (port_id == MM_UL_PORT) {
				sub_id = COPY_MM_UL_CFPID;
				break;
			}
		case THREE_MSB:
		case FOUR_MSB:
		case FIVE_MSB:
		case SEVEN_MSB:
		case EIGHT_MSB:
		case NINE_MSB:
			sub_id = COPY_MM_UL_CFPID;
			break;
		default:
			sub_id = NULL_COPY_CFPID;
			break;
		}
	}
	return sub_id;
}
/**
 * abe_int_2_float
 * returns a mantissa on 16 bits and the exponent
 * 0x4000.0000 leads to M=0x4000 X=15
 * 0x0004.0000 leads to M=0x4000 X=4
 * 0x0000.0001 leads to M=0x4000 X=-14
 *
 */
void abe_int_2_float16(u32 data, u32 *mantissa, u32 *exp)
{
	u32 i;
	*exp = 0;
	*mantissa = 0;
	for (i = 0; i < 32; i++) {
		if ((1 << i) > data)
			break;
	}
	*exp = i - 15;
	*mantissa = (*exp > 0) ? data >> (*exp) : data << (*exp);
}
/**
 * abe_gain_offset
 * returns the offset to firmware data structures
 *
 */
void abe_gain_offset(u32 id, u32 *mixer_offset)
{
	switch (id) {
	default:
	case GAINS_DMIC1:
		*mixer_offset = dmic1_gains_offset;
		break;
	case GAINS_DMIC2:
		*mixer_offset = dmic2_gains_offset;
		break;
	case GAINS_DMIC3:
		*mixer_offset = dmic3_gains_offset;
		break;
	case GAINS_AMIC:
		*mixer_offset = amic_gains_offset;
		break;
	case GAINS_DL1:
		*mixer_offset = dl1_gains_offset;
		break;
	case GAINS_DL2:
		*mixer_offset = dl2_gains_offset;
		break;
	case GAINS_SPLIT:
		*mixer_offset = splitters_gains_offset;
		break;
	case MIXDL1:
		*mixer_offset = mixer_dl1_offset;
		break;
	case MIXDL2:
		*mixer_offset = mixer_dl2_offset;
		break;
	case MIXECHO:
		*mixer_offset = mixer_echo_offset;
		break;
	case MIXSDT:
		*mixer_offset = mixer_sdt_offset;
		break;
	case MIXVXREC:
		*mixer_offset = mixer_vxrec_offset;
		break;
	case MIXAUDUL:
		*mixer_offset = mixer_audul_offset;
		break;
	}
}
/**
 * abe_decide_main_port - Select stynchronization port for Event generator.
 * @id: audio port name
 *
 * tells the FW which is the reference stream for adjusting
 * the processing on 23/24/25 slots
 *
 * takes the first port in a list which is slave on the data interface
 */
u32 abe_valid_port_for_synchro(u32 id)
{
	if ((abe_port[id].protocol.protocol_switch ==
	     DMAREQ_PORT_PROT) ||
	    (abe_port[id].protocol.protocol_switch ==
	     PINGPONG_PORT_PROT) ||
	    (abe_port[id].status != OMAP_ABE_PORT_ACTIVITY_RUNNING))
		return 0;
	else
		return 1;
}
void abe_decide_main_port(void)
{
	u32 id, id_not_found;
	id_not_found = 1;
	for (id = 0; id < LAST_PORT_ID - 1; id++) {
		if (abe_valid_port_for_synchro(abe_port_priority[id])) {
			id_not_found = 0;
			break;
		}
	}
	/* if no port is currently activated, the default one is PDM_DL */
	if (id_not_found)
		abe_select_main_port(PDM_DL_PORT);
	else
		abe_select_main_port(abe_port_priority[id]);
}