summaryrefslogtreecommitdiff
path: root/sound/soc/omap/abe/abe_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/omap/abe/abe_lib.c')
-rw-r--r--sound/soc/omap/abe/abe_lib.c394
1 files changed, 394 insertions, 0 deletions
diff --git a/sound/soc/omap/abe/abe_lib.c b/sound/soc/omap/abe/abe_lib.c
new file mode 100644
index 00000000000..d95afe74343
--- /dev/null
+++ b/sound/soc/omap/abe/abe_lib.c
@@ -0,0 +1,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]);
+}