blob: d872de53c6330cef867e5eb33c43cf0a9e17787b [file] [log] [blame]
/*
This file is provided under a dual BSD/GPLv2 license. When using or
redistributing this file, you may do so under either license.
GPL LICENSE SUMMARY
Copyright(c) 2010-2011 Texas Instruments Incorporated,
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License 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.
The full GNU General Public License is included in this distribution
in the file called LICENSE.GPL.
BSD LICENSE
Copyright(c) 2010-2011 Texas Instruments Incorporated,
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Texas Instruments Incorporated nor the names of
its contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/slab.h>
#include "abe_legacy.h"
#include "abe_port.h"
#include "abe_dbg.h"
#include "abe_mem.h"
#include "abe_gain.h"
/**
* abe_clean_temporay buffers
*
* clear temporary buffers
*/
void omap_abe_clean_temporary_buffers(struct omap_abe *abe, u32 id)
{
switch (id) {
case OMAP_ABE_DMIC_PORT:
omap_abe_reset_mem(abe, OMAP_ABE_DMEM,
OMAP_ABE_D_DMIC_UL_FIFO_ADDR,
OMAP_ABE_D_DMIC_UL_FIFO_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_DMIC0_96_48_DATA_ADDR,
OMAP_ABE_S_DMIC0_96_48_DATA_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_DMIC1_96_48_DATA_ADDR,
OMAP_ABE_S_DMIC1_96_48_DATA_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_DMIC2_96_48_DATA_ADDR,
OMAP_ABE_S_DMIC2_96_48_DATA_SIZE);
/* reset working values of the gain, target gain is preserved */
omap_abe_reset_gain_mixer(abe, GAINS_DMIC1, GAIN_LEFT_OFFSET);
omap_abe_reset_gain_mixer(abe, GAINS_DMIC1, GAIN_RIGHT_OFFSET);
omap_abe_reset_gain_mixer(abe, GAINS_DMIC2, GAIN_LEFT_OFFSET);
omap_abe_reset_gain_mixer(abe, GAINS_DMIC2, GAIN_RIGHT_OFFSET);
omap_abe_reset_gain_mixer(abe, GAINS_DMIC3, GAIN_LEFT_OFFSET);
omap_abe_reset_gain_mixer(abe, GAINS_DMIC3, GAIN_RIGHT_OFFSET);
break;
case OMAP_ABE_PDM_UL_PORT:
omap_abe_reset_mem(abe, OMAP_ABE_DMEM,
OMAP_ABE_D_MCPDM_UL_FIFO_ADDR,
OMAP_ABE_D_MCPDM_UL_FIFO_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_AMIC_96_48_DATA_ADDR,
OMAP_ABE_S_AMIC_96_48_DATA_SIZE);
/* reset working values of the gain, target gain is preserved */
omap_abe_reset_gain_mixer(abe, GAINS_AMIC, GAIN_LEFT_OFFSET);
omap_abe_reset_gain_mixer(abe, GAINS_AMIC, GAIN_RIGHT_OFFSET);
break;
case OMAP_ABE_BT_VX_UL_PORT:
omap_abe_reset_mem(abe, OMAP_ABE_DMEM,
OMAP_ABE_D_BT_UL_FIFO_ADDR,
OMAP_ABE_D_BT_UL_FIFO_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_BT_UL_ADDR,
OMAP_ABE_S_BT_UL_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_BT_UL_8_48_HP_DATA_ADDR,
OMAP_ABE_S_BT_UL_8_48_HP_DATA_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_BT_UL_8_48_LP_DATA_ADDR,
OMAP_ABE_S_BT_UL_8_48_LP_DATA_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_BT_UL_16_48_HP_DATA_ADDR,
OMAP_ABE_S_BT_UL_16_48_HP_DATA_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_BT_UL_16_48_LP_DATA_ADDR,
OMAP_ABE_S_BT_UL_16_48_LP_DATA_SIZE);
/* reset working values of the gain, target gain is preserved */
omap_abe_reset_gain_mixer(abe, GAINS_BTUL, GAIN_LEFT_OFFSET);
omap_abe_reset_gain_mixer(abe, GAINS_BTUL, GAIN_RIGHT_OFFSET);
break;
case OMAP_ABE_MM_UL_PORT:
omap_abe_reset_mem(abe, OMAP_ABE_DMEM,
OMAP_ABE_D_MM_UL_FIFO_ADDR,
OMAP_ABE_D_MM_UL_FIFO_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_MM_UL_ADDR,
OMAP_ABE_S_MM_UL_SIZE);
break;
case OMAP_ABE_MM_UL2_PORT:
omap_abe_reset_mem(abe, OMAP_ABE_DMEM,
OMAP_ABE_D_MM_UL2_FIFO_ADDR,
OMAP_ABE_D_MM_UL2_FIFO_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_MM_UL2_ADDR,
OMAP_ABE_S_MM_UL2_SIZE);
break;
case OMAP_ABE_VX_UL_PORT:
omap_abe_reset_mem(abe, OMAP_ABE_DMEM,
OMAP_ABE_D_VX_UL_FIFO_ADDR,
OMAP_ABE_D_VX_UL_FIFO_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_VX_UL_ADDR,
OMAP_ABE_S_VX_UL_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_VX_UL_48_8_HP_DATA_ADDR,
OMAP_ABE_S_VX_UL_48_8_HP_DATA_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_VX_UL_48_8_LP_DATA_ADDR,
OMAP_ABE_S_VX_UL_48_8_LP_DATA_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_VX_UL_48_16_HP_DATA_ADDR,
OMAP_ABE_S_VX_UL_48_16_HP_DATA_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_VX_UL_48_16_LP_DATA_ADDR,
OMAP_ABE_S_VX_UL_48_16_LP_DATA_SIZE);
omap_abe_reset_gain_mixer(abe, MIXAUDUL, MIX_AUDUL_INPUT_UPLINK);
break;
case OMAP_ABE_MM_DL_PORT:
omap_abe_reset_mem(abe, OMAP_ABE_DMEM,
OMAP_ABE_D_MM_DL_FIFO_ADDR,
OMAP_ABE_D_MM_DL_FIFO_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_MM_DL_ADDR,
OMAP_ABE_S_MM_DL_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_MM_DL_44P1_ADDR,
OMAP_ABE_S_MM_DL_44P1_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_MM_DL_44P1_XK_ADDR,
OMAP_ABE_S_MM_DL_44P1_XK_SIZE);
omap_abe_reset_gain_mixer(abe, MIXDL1, MIX_DL1_INPUT_MM_DL);
omap_abe_reset_gain_mixer(abe, MIXDL2, MIX_DL2_INPUT_MM_DL);
break;
case OMAP_ABE_VX_DL_PORT:
omap_abe_reset_mem(abe, OMAP_ABE_DMEM,
OMAP_ABE_D_VX_DL_FIFO_ADDR,
OMAP_ABE_D_VX_DL_FIFO_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_VX_DL_ADDR,
OMAP_ABE_S_VX_DL_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_VX_DL_8_48_HP_DATA_ADDR,
OMAP_ABE_S_VX_DL_8_48_HP_DATA_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_VX_DL_8_48_LP_DATA_ADDR,
OMAP_ABE_S_VX_DL_8_48_LP_DATA_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_VX_DL_8_48_OSR_LP_DATA_ADDR,
OMAP_ABE_S_VX_DL_8_48_OSR_LP_DATA_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_VX_DL_16_48_HP_DATA_ADDR,
OMAP_ABE_S_VX_DL_16_48_HP_DATA_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_VX_DL_16_48_LP_DATA_ADDR,
OMAP_ABE_S_VX_DL_16_48_LP_DATA_SIZE);
omap_abe_reset_gain_mixer(abe, MIXDL1, MIX_DL1_INPUT_VX_DL);
omap_abe_reset_gain_mixer(abe, MIXDL2, MIX_DL2_INPUT_VX_DL);
break;
case OMAP_ABE_TONES_DL_PORT:
omap_abe_reset_mem(abe, OMAP_ABE_DMEM,
OMAP_ABE_D_TONES_DL_FIFO_ADDR,
OMAP_ABE_D_TONES_DL_FIFO_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_TONES_ADDR,
OMAP_ABE_S_TONES_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_TONES_44P1_ADDR,
OMAP_ABE_S_TONES_44P1_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_TONES_44P1_XK_ADDR,
OMAP_ABE_S_TONES_44P1_XK_SIZE);
omap_abe_reset_gain_mixer(abe, MIXDL1, MIX_DL1_INPUT_TONES);
omap_abe_reset_gain_mixer(abe, MIXDL2, MIX_DL2_INPUT_TONES);
break;
case OMAP_ABE_VIB_DL_PORT:
omap_abe_reset_mem(abe, OMAP_ABE_DMEM,
OMAP_ABE_D_VIB_DL_FIFO_ADDR,
OMAP_ABE_D_VIB_DL_FIFO_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_VIBRA_ADDR,
OMAP_ABE_S_VIBRA_SIZE);
break;
case OMAP_ABE_BT_VX_DL_PORT:
omap_abe_reset_mem(abe, OMAP_ABE_DMEM,
OMAP_ABE_D_BT_DL_FIFO_ADDR,
OMAP_ABE_D_BT_DL_FIFO_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_BT_DL_ADDR,
OMAP_ABE_S_BT_DL_SIZE);
#if !defined(CONFIG_SND_OMAP4_ABE_USE_ALT_FW)
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_BT_DL_8_48_OSR_LP_DATA_ADDR,
OMAP_ABE_S_BT_DL_8_48_OSR_LP_DATA_SIZE);
#endif
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_BT_DL_48_8_HP_DATA_ADDR,
OMAP_ABE_S_BT_DL_48_8_HP_DATA_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_BT_DL_48_8_LP_DATA_ADDR,
OMAP_ABE_S_BT_DL_48_8_LP_DATA_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_BT_DL_48_16_HP_DATA_ADDR,
OMAP_ABE_S_BT_DL_48_16_HP_DATA_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_BT_DL_48_16_LP_DATA_ADDR,
OMAP_ABE_S_BT_DL_48_16_LP_DATA_SIZE);
break;
case OMAP_ABE_PDM_DL_PORT:
omap_abe_reset_mem(abe, OMAP_ABE_DMEM,
OMAP_ABE_D_MCPDM_DL_FIFO_ADDR,
OMAP_ABE_D_MCPDM_DL_FIFO_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_DL2_M_LR_EQ_DATA_ADDR,
OMAP_ABE_S_DL2_M_LR_EQ_DATA_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_DL1_M_EQ_DATA_ADDR,
OMAP_ABE_S_DL1_M_EQ_DATA_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_EARP_48_96_LP_DATA_ADDR,
OMAP_ABE_S_EARP_48_96_LP_DATA_SIZE);
omap_abe_reset_mem(abe, OMAP_ABE_SMEM,
OMAP_ABE_S_IHF_48_96_LP_DATA_ADDR,
OMAP_ABE_S_IHF_48_96_LP_DATA_SIZE);
omap_abe_reset_gain_mixer(abe, GAINS_DL1, GAIN_LEFT_OFFSET);
omap_abe_reset_gain_mixer(abe, GAINS_DL1, GAIN_RIGHT_OFFSET);
omap_abe_reset_gain_mixer(abe, GAINS_DL2, GAIN_LEFT_OFFSET);
omap_abe_reset_gain_mixer(abe, GAINS_DL2, GAIN_RIGHT_OFFSET);
omap_abe_reset_gain_mixer(abe, MIXSDT, MIX_SDT_INPUT_UP_MIXER);
omap_abe_reset_gain_mixer(abe, MIXSDT, MIX_SDT_INPUT_DL1_MIXER);
break;
case OMAP_ABE_MM_EXT_OUT_PORT:
omap_abe_reset_mem(abe, OMAP_ABE_DMEM,
OMAP_ABE_D_MM_EXT_OUT_FIFO_ADDR,
OMAP_ABE_D_MM_EXT_OUT_FIFO_SIZE);
break;
case OMAP_ABE_MM_EXT_IN_PORT:
omap_abe_reset_mem(abe, OMAP_ABE_DMEM,
OMAP_ABE_D_MM_EXT_IN_FIFO_ADDR,
OMAP_ABE_D_MM_EXT_IN_FIFO_SIZE);
break;
}
}
/**
* omap_abe_disable_enable_dma_request
* Parameter:
* Operations:
* Return value:
*/
void omap_abe_disable_enable_dma_request(struct omap_abe *abe, u32 id,
u32 on_off)
{
u8 desc_third_word[4], irq_dmareq_field;
u32 sio_desc_address;
u32 struct_offset;
struct ABE_SIODescriptor sio_desc;
struct ABE_SPingPongDescriptor desc_pp;
if (abe_port[id].protocol.protocol_switch == PINGPONG_PORT_PROT) {
irq_dmareq_field =
(u8) (on_off *
abe_port[id].protocol.p.prot_pingpong.irq_data);
sio_desc_address = OMAP_ABE_D_PINGPONGDESC_ADDR;
struct_offset = (u32) &(desc_pp.data_size) - (u32) &(desc_pp);
omap_abe_mem_read(abe, OMAP_ABE_DMEM,
sio_desc_address + struct_offset,
(u32 *) desc_third_word, 4);
desc_third_word[2] = irq_dmareq_field;
omap_abe_mem_write(abe, OMAP_ABE_DMEM,
sio_desc_address + struct_offset,
(u32 *) desc_third_word, 4);
} else {
/* serial interface: sync ATC with Firmware activity */
sio_desc_address =
OMAP_ABE_D_IODESCR_ADDR +
(id * sizeof(struct ABE_SIODescriptor));
omap_abe_mem_read(abe, OMAP_ABE_DMEM,
sio_desc_address, (u32 *) &sio_desc,
sizeof(sio_desc));
if (on_off) {
if (abe_port[id].protocol.protocol_switch != SERIAL_PORT_PROT)
sio_desc.atc_irq_data =
(u8) abe_port[id].protocol.p.prot_dmareq.
dma_data;
sio_desc.on_off = 0x80;
} else {
sio_desc.atc_irq_data = 0;
sio_desc.on_off = 0;
}
omap_abe_mem_write(abe, OMAP_ABE_DMEM,
sio_desc_address, (u32 *) &sio_desc,
sizeof(sio_desc));
}
}
/**
* omap_abe_enable_dma_request
*
* Parameter:
* Operations:
* Return value:
*
*/
void omap_abe_enable_dma_request(struct omap_abe *abe, u32 id)
{
omap_abe_disable_enable_dma_request(abe, id, 1);
}
/**
* omap_abe_disable_dma_request
*
* Parameter:
* Operations:
* Return value:
*
*/
void omap_abe_disable_dma_request(struct omap_abe *abe, u32 id)
{
omap_abe_disable_enable_dma_request(abe, id, 0);
}
/**
* abe_init_atc
* @id: ABE port ID
*
* load the DMEM ATC/AESS descriptors
*/
void omap_abe_init_atc(struct omap_abe *abe, u32 id)
{
u8 iter;
s32 datasize;
struct omap_abe_atc_desc atc_desc;
#define JITTER_MARGIN 4
/* load default values of the descriptor */
atc_desc.rdpt = 0;
atc_desc.wrpt = 0;
atc_desc.irqdest = 0;
atc_desc.cberr = 0;
atc_desc.desen = 0;
atc_desc.nw = 0;
atc_desc.reserved0 = 0;
atc_desc.reserved1 = 0;
atc_desc.reserved2 = 0;
atc_desc.srcid = 0;
atc_desc.destid = 0;
atc_desc.badd = 0;
atc_desc.iter = 0;
atc_desc.cbsize = 0;
datasize = abe_dma_port_iter_factor(&((abe_port[id]).format));
iter = (u8) abe_dma_port_iteration(&((abe_port[id]).format));
/* if the ATC FIFO is too small there will be two ABE firmware
utasks to do the copy this happems on DMIC and MCPDMDL */
/* VXDL_8kMono = 4 = 2 + 2x1 */
/* VXDL_16kstereo = 12 = 8 + 2x2 */
/* MM_DL_1616 = 14 = 12 + 2x1 */
/* DMIC = 84 = 72 + 2x6 */
/* VXUL_8kMono = 2 */
/* VXUL_16kstereo = 4 */
/* MM_UL2_Stereo = 4 */
/* PDMDL = 12 */
/* IN from AESS point of view */
if (abe_port[id].protocol.direction == ABE_ATC_DIRECTION_IN)
if (iter + 2 * datasize > 126)
atc_desc.wrpt = (iter >> 1) +
((JITTER_MARGIN-1) * datasize);
else
atc_desc.wrpt = iter + ((JITTER_MARGIN-1) * datasize);
else
atc_desc.wrpt = 0 + ((JITTER_MARGIN+1) * datasize);
switch ((abe_port[id]).protocol.protocol_switch) {
case SLIMBUS_PORT_PROT:
atc_desc.cbdir = (abe_port[id]).protocol.direction;
atc_desc.cbsize =
(abe_port[id]).protocol.p.prot_slimbus.buf_size;
atc_desc.badd =
((abe_port[id]).protocol.p.prot_slimbus.buf_addr1) >> 4;
atc_desc.iter = (abe_port[id]).protocol.p.prot_slimbus.iter;
atc_desc.srcid =
abe_atc_srcid[(abe_port[id]).protocol.p.prot_slimbus.
desc_addr1 >> 3];
omap_abe_mem_write(abe, OMAP_ABE_DMEM,
(abe_port[id]).protocol.p.prot_slimbus.
desc_addr1, (u32 *) &atc_desc, sizeof(atc_desc));
atc_desc.badd =
(abe_port[id]).protocol.p.prot_slimbus.buf_addr2;
atc_desc.srcid =
abe_atc_srcid[(abe_port[id]).protocol.p.prot_slimbus.
desc_addr2 >> 3];
omap_abe_mem_write(abe, OMAP_ABE_DMEM,
(abe_port[id]).protocol.p.prot_slimbus.
desc_addr2, (u32 *) &atc_desc, sizeof(atc_desc));
break;
case SERIAL_PORT_PROT:
atc_desc.cbdir = (abe_port[id]).protocol.direction;
atc_desc.cbsize =
(abe_port[id]).protocol.p.prot_serial.buf_size;
atc_desc.badd =
((abe_port[id]).protocol.p.prot_serial.buf_addr) >> 4;
atc_desc.iter = (abe_port[id]).protocol.p.prot_serial.iter;
atc_desc.srcid =
abe_atc_srcid[(abe_port[id]).protocol.p.prot_serial.
desc_addr >> 3];
atc_desc.destid =
abe_atc_dstid[(abe_port[id]).protocol.p.prot_serial.
desc_addr >> 3];
omap_abe_mem_write(abe, OMAP_ABE_DMEM,
(abe_port[id]).protocol.p.prot_serial.desc_addr,
(u32 *) &atc_desc, sizeof(atc_desc));
break;
case DMIC_PORT_PROT:
atc_desc.cbdir = ABE_ATC_DIRECTION_IN;
atc_desc.cbsize = (abe_port[id]).protocol.p.prot_dmic.buf_size;
atc_desc.badd =
((abe_port[id]).protocol.p.prot_dmic.buf_addr) >> 4;
atc_desc.iter = DMIC_ITER;
atc_desc.srcid = abe_atc_srcid[ABE_ATC_DMIC_DMA_REQ];
omap_abe_mem_write(abe, OMAP_ABE_DMEM,
(ABE_ATC_DMIC_DMA_REQ*ATC_SIZE),
(u32 *) &atc_desc, sizeof(atc_desc));
break;
case MCPDMDL_PORT_PROT:
atc_desc.cbdir = ABE_ATC_DIRECTION_OUT;
atc_desc.cbsize =
(abe_port[id]).protocol.p.prot_mcpdmdl.buf_size;
atc_desc.badd =
((abe_port[id]).protocol.p.prot_mcpdmdl.buf_addr) >> 4;
atc_desc.iter = MCPDM_DL_ITER;
atc_desc.destid = abe_atc_dstid[ABE_ATC_MCPDMDL_DMA_REQ];
omap_abe_mem_write(abe, OMAP_ABE_DMEM,
(ABE_ATC_MCPDMDL_DMA_REQ*ATC_SIZE),
(u32 *) &atc_desc, sizeof(atc_desc));
break;
case MCPDMUL_PORT_PROT:
atc_desc.cbdir = ABE_ATC_DIRECTION_IN;
atc_desc.cbsize =
(abe_port[id]).protocol.p.prot_mcpdmul.buf_size;
atc_desc.badd =
((abe_port[id]).protocol.p.prot_mcpdmul.buf_addr) >> 4;
atc_desc.iter = MCPDM_UL_ITER;
atc_desc.srcid = abe_atc_srcid[ABE_ATC_MCPDMUL_DMA_REQ];
omap_abe_mem_write(abe, OMAP_ABE_DMEM,
(ABE_ATC_MCPDMUL_DMA_REQ*ATC_SIZE),
(u32 *) &atc_desc, sizeof(atc_desc));
break;
case PINGPONG_PORT_PROT:
/* software protocol, nothing to do on ATC */
break;
case DMAREQ_PORT_PROT:
atc_desc.cbdir = (abe_port[id]).protocol.direction;
atc_desc.cbsize =
(abe_port[id]).protocol.p.prot_dmareq.buf_size;
atc_desc.badd =
((abe_port[id]).protocol.p.prot_dmareq.buf_addr) >> 4;
/* CBPr needs ITER=1.
It is the job of eDMA to do the iterations */
atc_desc.iter = 1;
/* input from ABE point of view */
if (abe_port[id].protocol.direction == ABE_ATC_DIRECTION_IN) {
/* atc_atc_desc.rdpt = 127; */
/* atc_atc_desc.wrpt = 0; */
atc_desc.srcid = abe_atc_srcid
[(abe_port[id]).protocol.p.prot_dmareq.
desc_addr >> 3];
} else {
/* atc_atc_desc.rdpt = 0; */
/* atc_atc_desc.wrpt = 127; */
atc_desc.destid = abe_atc_dstid
[(abe_port[id]).protocol.p.prot_dmareq.
desc_addr >> 3];
}
omap_abe_mem_write(abe, OMAP_ABE_DMEM,
(abe_port[id]).protocol.p.prot_dmareq.desc_addr,
(u32 *) &atc_desc, sizeof(atc_desc));
break;
}
}
/**
* omap_abe_enable_pp_io_task
* @id: port_id
*
*
*/
void omap_abe_enable_pp_io_task(struct omap_abe *abe, u32 id)
{
if (OMAP_ABE_MM_DL_PORT == id) {
/* MM_DL managed in ping-pong */
abe->MultiFrame[TASK_IO_MM_DL_SLT][TASK_IO_MM_DL_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_IO_PING_PONG);
abe->MultiFrame[18][1] =
ABE_TASK_ID(C_ABE_FW_TASK_SRC44P1_MMDL_PP);
omap_abe_mem_write(abe, OMAP_ABE_DMEM,
OMAP_ABE_D_MULTIFRAME_ADDR, (u32 *) abe->MultiFrame,
sizeof(abe->MultiFrame));
} else {
/* ping_pong is only supported on MM_DL */
omap_abe_dbg_error(abe, OMAP_ABE_ERR_API,
ABE_PARAMETER_ERROR);
}
}
/**
* omap_abe_disable_pp_io_task
* @id: port_id
*
*
*/
void omap_abe_disable_pp_io_task(struct omap_abe *abe, u32 id)
{
if (OMAP_ABE_MM_DL_PORT == id) {
/* MM_DL managed in ping-pong */
abe->MultiFrame[TASK_IO_MM_DL_SLT][TASK_IO_MM_DL_IDX] = 0;
abe->MultiFrame[18][1] = 0;
omap_abe_mem_write(abe, OMAP_ABE_DMEM,
OMAP_ABE_D_MULTIFRAME_ADDR, (u32 *) abe->MultiFrame,
sizeof(abe->MultiFrame));
} else {
/* ping_pong is only supported on MM_DL */
omap_abe_dbg_error(abe, OMAP_ABE_ERR_API,
ABE_PARAMETER_ERROR);
}
}
/**
* omap_abe_disable_data_transfer
* @id: ABE port id
*
* disables the ATC descriptor and stop IO/port activities
* disable the IO task (@f = 0)
* clear ATC DMEM buffer, ATC enabled
*/
int omap_abe_disable_data_transfer(struct omap_abe *abe, u32 id)
{
_log(ABE_ID_DISABLE_DATA_TRANSFER, id, 0, 0);
/* MM_DL managed in ping-pong */
if (id == OMAP_ABE_MM_DL_PORT) {
if (abe_port[OMAP_ABE_MM_DL_PORT].protocol.protocol_switch == PINGPONG_PORT_PROT)
omap_abe_disable_pp_io_task(abe, OMAP_ABE_MM_DL_PORT);
}
/* local host variable status= "port is running" */
abe_port[id].status = OMAP_ABE_PORT_ACTIVITY_IDLE;
/* disable DMA requests */
omap_abe_disable_dma_request(abe, id);
/* disable ATC transfers */
omap_abe_init_atc(abe, id);
omap_abe_clean_temporary_buffers(abe, id);
/* select the main port based on the desactivation of this port */
abe_decide_main_port();
return 0;
}
EXPORT_SYMBOL(omap_abe_disable_data_transfer);
/**
* omap_abe_enable_data_transfer
* @ip: ABE port id
*
* enables the ATC descriptor
* reset ATC pointers
* enable the IO task (@f <> 0)
*/
int omap_abe_enable_data_transfer(struct omap_abe *abe, u32 id)
{
abe_port_protocol_t *protocol;
abe_data_format_t format;
_log(ABE_ID_ENABLE_DATA_TRANSFER, id, 0, 0);
omap_abe_clean_temporary_buffers(abe, id);
switch (id) {
case OMAP_ABE_PDM_UL_PORT:
case OMAP_ABE_PDM_DL_PORT:
case OMAP_ABE_DMIC_PORT:
/* initializes the ABE ATC descriptors in DMEM for BE ports */
protocol = &(abe_port[id].protocol);
format = abe_port[id].format;
omap_abe_init_atc(abe, id);
abe_init_io_tasks(id, &format, protocol);
break;
case OMAP_ABE_MM_DL_PORT:
protocol = &(abe_port[OMAP_ABE_MM_DL_PORT].protocol);
if (protocol->protocol_switch == PINGPONG_PORT_PROT)
abe->MultiFrame[TASK_IO_MM_DL_SLT][TASK_IO_MM_DL_IDX] = ABE_TASK_ID(C_ABE_FW_TASK_IO_PING_PONG);
else
abe->MultiFrame[TASK_IO_MM_DL_SLT][TASK_IO_MM_DL_IDX] = ABE_TASK_ID(C_ABE_FW_TASK_IO_MM_DL);
break;
case OMAP_ABE_VX_UL_PORT:
break;
case OMAP_ABE_VX_DL_PORT:
break;
case OMAP_ABE_MM_UL2_PORT:
abe->MultiFrame[17][3] = ABE_TASK_ID(C_ABE_FW_TASK_IO_MM_UL2);
break;
case OMAP_ABE_TONES_DL_PORT:
abe->MultiFrame[20][0] = ABE_TASK_ID(C_ABE_FW_TASK_IO_TONES_DL);
break;
case OMAP_ABE_MM_UL_PORT:
abe->MultiFrame[19][6] = ABE_TASK_ID(C_ABE_FW_TASK_IO_MM_UL);
break;
case OMAP_ABE_BT_VX_DL_PORT:
abe->MultiFrame[13][5] = ABE_TASK_ID(C_ABE_FW_TASK_IO_BT_VX_DL);
break;
case OMAP_ABE_BT_VX_UL_PORT:
abe->MultiFrame[15][3] = ABE_TASK_ID(C_ABE_FW_TASK_IO_BT_VX_UL);
break;
case OMAP_ABE_MM_EXT_IN_PORT:
abe->MultiFrame[21][3] = ABE_TASK_ID(C_ABE_FW_TASK_IO_MM_EXT_IN);
break;
case OMAP_ABE_MM_EXT_OUT_PORT:
abe->MultiFrame[15][0] = ABE_TASK_ID(C_ABE_FW_TASK_IO_MM_EXT_OUT);
break;
default:
break;
}
omap_abe_mem_write(abe, OMAP_ABE_DMEM, OMAP_ABE_D_MULTIFRAME_ADDR,
(u32 *) abe->MultiFrame, sizeof(abe->MultiFrame));
/* local host variable status= "port is running" */
abe_port[id].status = OMAP_ABE_PORT_ACTIVITY_RUNNING;
/* enable DMA requests */
omap_abe_enable_dma_request(abe, id);
/* select the main port based on the activation of this new port */
abe_decide_main_port();
return 0;
}
EXPORT_SYMBOL(omap_abe_enable_data_transfer);
/**
* omap_abe_connect_cbpr_dmareq_port
* @id: port name
* @f: desired data format
* @d: desired dma_request line (0..7)
* @a: returned pointer to the base address of the CBPr register and number of
* samples to exchange during a DMA_request.
*
* enables the data echange between a DMA and the ABE through the
* CBPr registers of AESS.
*/
int omap_abe_connect_cbpr_dmareq_port(struct omap_abe *abe,
u32 id, abe_data_format_t *f,
u32 d,
abe_dma_t *returned_dma_t)
{
_log(ABE_ID_CONNECT_CBPR_DMAREQ_PORT, id, f->f, f->samp_format);
abe_port[id] = ((abe_port_t *) abe_port_init)[id];
(abe_port[id]).format = (*f);
abe_port[id].protocol.protocol_switch = DMAREQ_PORT_PROT;
abe_port[id].protocol.p.prot_dmareq.iter = abe_dma_port_iteration(f);
abe_port[id].protocol.p.prot_dmareq.dma_addr = ABE_DMASTATUS_RAW;
abe_port[id].protocol.p.prot_dmareq.dma_data = (1 << d);
/* load the dma_t with physical information from AE memory mapping */
abe_init_dma_t(id, &((abe_port[id]).protocol));
/* load the ATC descriptors - disabled */
omap_abe_init_atc(abe, id);
/* load the micro-task parameters */
abe_init_io_tasks(id, &((abe_port[id]).format),
&((abe_port[id]).protocol));
abe_port[id].status = OMAP_ABE_PORT_INITIALIZED;
/* return the dma pointer address */
abe_read_port_address(id, returned_dma_t);
return 0;
}
EXPORT_SYMBOL(omap_abe_connect_cbpr_dmareq_port);
/**
* omap_abe_connect_irq_ping_pong_port
* @id: port name
* @f: desired data format
* @I: index of the call-back subroutine to call
* @s: half-buffer (ping) size
* @p: returned base address of the first (ping) buffer)
*
* enables the data echanges between a direct access to the DMEM
* memory of ABE using cache flush. On each IRQ activation a subroutine
* registered with "abe_plug_subroutine" will be called. This subroutine
* will generate an amount of samples, send them to DMEM memory and call
* "abe_set_ping_pong_buffer" to notify the new amount of samples in the
* pong buffer.
*/
int omap_abe_connect_irq_ping_pong_port(struct omap_abe *abe,
u32 id, abe_data_format_t *f,
u32 subroutine_id, u32 size,
u32 *sink, u32 dsp_mcu_flag)
{
_log(ABE_ID_CONNECT_IRQ_PING_PONG_PORT, id, f->f, f->samp_format);
/* ping_pong is only supported on MM_DL */
if (id != OMAP_ABE_MM_DL_PORT) {
omap_abe_dbg_error(abe, OMAP_ABE_ERR_API,
ABE_PARAMETER_ERROR);
}
abe_port[id] = ((abe_port_t *) abe_port_init)[id];
(abe_port[id]).format = (*f);
(abe_port[id]).protocol.protocol_switch = PINGPONG_PORT_PROT;
(abe_port[id]).protocol.p.prot_pingpong.buf_addr =
OMAP_ABE_D_PING_ADDR;
(abe_port[id]).protocol.p.prot_pingpong.buf_size = size;
(abe_port[id]).protocol.p.prot_pingpong.irq_data = (1);
abe_init_ping_pong_buffer(OMAP_ABE_MM_DL_PORT, size, 2, sink);
if (dsp_mcu_flag == PING_PONG_WITH_MCU_IRQ)
(abe_port[id]).protocol.p.prot_pingpong.irq_addr =
ABE_MCU_IRQSTATUS_RAW;
if (dsp_mcu_flag == PING_PONG_WITH_DSP_IRQ)
(abe_port[id]).protocol.p.prot_pingpong.irq_addr =
ABE_DSP_IRQSTATUS_RAW;
abe_port[id].status = OMAP_ABE_PORT_INITIALIZED;
/* load the ATC descriptors - disabled */
omap_abe_init_atc(abe, id);
/* load the micro-task parameters */
abe_init_io_tasks(id, &((abe_port[id]).format),
&((abe_port[id]).protocol));
*sink = (abe_port[id]).protocol.p.prot_pingpong.buf_addr;
return 0;
}
EXPORT_SYMBOL(omap_abe_connect_irq_ping_pong_port);
/**
* omap_abe_connect_serial_port()
* @id: port name
* @f: data format
* @i: peripheral ID (McBSP #1, #2, #3)
*
* Operations : enables the data echanges between a McBSP and an ATC buffer in
* DMEM. This API is used connect 48kHz McBSP streams to MM_DL and 8/16kHz
* voice streams to VX_UL, VX_DL, BT_VX_UL, BT_VX_DL. It abstracts the
* abe_write_port API.
*/
int omap_abe_connect_serial_port(struct omap_abe *abe,
u32 id, abe_data_format_t *f,
u32 mcbsp_id)
{
_log(ABE_ID_CONNECT_SERIAL_PORT, id, f->samp_format, mcbsp_id);
abe_port[id] = ((abe_port_t *) abe_port_init)[id];
(abe_port[id]).format = (*f);
(abe_port[id]).protocol.protocol_switch = SERIAL_PORT_PROT;
/* McBSP peripheral connected to ATC */
(abe_port[id]).protocol.p.prot_serial.desc_addr = mcbsp_id*ATC_SIZE;
/* check the iteration of ATC */
(abe_port[id]).protocol.p.prot_serial.iter =
abe_dma_port_iter_factor(f);
/* load the ATC descriptors - disabled */
omap_abe_init_atc(abe, id);
/* load the micro-task parameters */
abe_init_io_tasks(id, &((abe_port[id]).format),
&((abe_port[id]).protocol));
abe_port[id].status = OMAP_ABE_PORT_INITIALIZED;
return 0;
}
EXPORT_SYMBOL(omap_abe_connect_serial_port);
/**
* omap_abe_read_port_address
* @dma: output pointer to the DMA iteration and data destination pointer
*
* This API returns the address of the DMA register used on this audio port.
* Depending on the protocol being used, adds the base address offset L3
* (DMA) or MPU (ARM)
*/
int omap_abe_read_port_address(struct omap_abe *abe,
u32 port, abe_dma_t *dma2)
{
abe_dma_t_offset dma1;
u32 protocol_switch;
_log(ABE_ID_READ_PORT_ADDRESS, port, 0, 0);
dma1 = (abe_port[port]).dma;
protocol_switch = abe_port[port].protocol.protocol_switch;
switch (protocol_switch) {
case PINGPONG_PORT_PROT:
/* return the base address of the buffer in L3 and L4 spaces */
(*dma2).data = (void *)(dma1.data +
ABE_DEFAULT_BASE_ADDRESS_L3 + ABE_DMEM_BASE_OFFSET_MPU);
(*dma2).l3_dmem = (void *)(dma1.data +
ABE_DEFAULT_BASE_ADDRESS_L3 + ABE_DMEM_BASE_OFFSET_MPU);
(*dma2).l4_dmem = (void *)(dma1.data +
ABE_DEFAULT_BASE_ADDRESS_L4 + ABE_DMEM_BASE_OFFSET_MPU);
break;
case DMAREQ_PORT_PROT:
/* return the CBPr(L3), DMEM(L3), DMEM(L4) address */
(*dma2).data = (void *)(dma1.data +
ABE_DEFAULT_BASE_ADDRESS_L3 + ABE_ATC_BASE_OFFSET_MPU);
(*dma2).l3_dmem =
(void *)((abe_port[port]).protocol.p.prot_dmareq.buf_addr +
ABE_DEFAULT_BASE_ADDRESS_L3 + ABE_DMEM_BASE_OFFSET_MPU);
(*dma2).l4_dmem =
(void *)((abe_port[port]).protocol.p.prot_dmareq.buf_addr +
ABE_DEFAULT_BASE_ADDRESS_L4 + ABE_DMEM_BASE_OFFSET_MPU);
break;
default:
break;
}
(*dma2).iter = (dma1.iter);
return 0;
}
EXPORT_SYMBOL(omap_abe_read_port_address);
/**
* abe_init_dma_t
* @ id: ABE port ID
* @ prot: protocol being used
*
* load the dma_t with physical information from AE memory mapping
*/
void abe_init_dma_t(u32 id, abe_port_protocol_t *prot)
{
abe_dma_t_offset dma;
u32 idx;
/* default dma_t points to address 0000... */
dma.data = 0;
dma.iter = 0;
switch (prot->protocol_switch) {
case PINGPONG_PORT_PROT:
for (idx = 0; idx < 32; idx++) {
if (((prot->p).prot_pingpong.irq_data) ==
(u32) (1 << idx))
break;
}
(prot->p).prot_dmareq.desc_addr =
((CBPr_DMA_RTX0 + idx)*ATC_SIZE);
/* translate byte address/size in DMEM words */
dma.data = (prot->p).prot_pingpong.buf_addr >> 2;
dma.iter = (prot->p).prot_pingpong.buf_size >> 2;
break;
case DMAREQ_PORT_PROT:
for (idx = 0; idx < 32; idx++) {
if (((prot->p).prot_dmareq.dma_data) ==
(u32) (1 << idx))
break;
}
dma.data = (CIRCULAR_BUFFER_PERIPHERAL_R__0 + (idx << 2));
dma.iter = (prot->p).prot_dmareq.iter;
(prot->p).prot_dmareq.desc_addr =
((CBPr_DMA_RTX0 + idx)*ATC_SIZE);
break;
case SLIMBUS_PORT_PROT:
case SERIAL_PORT_PROT:
case DMIC_PORT_PROT:
case MCPDMDL_PORT_PROT:
case MCPDMUL_PORT_PROT:
default:
break;
}
/* upload the dma type */
abe_port[id].dma = dma;
}
/**
* abe_enable_atc
* Parameter:
* Operations:
* Return value:
*/
void abe_enable_atc(u32 id)
{
struct omap_abe_atc_desc atc_desc;
omap_abe_mem_read(abe, OMAP_ABE_DMEM,
(abe_port[id]).protocol.p.prot_dmareq.desc_addr,
(u32 *) &atc_desc, sizeof(atc_desc));
atc_desc.desen = 1;
omap_abe_mem_write(abe, OMAP_ABE_DMEM,
(abe_port[id]).protocol.p.prot_dmareq.desc_addr,
(u32 *) &atc_desc, sizeof(atc_desc));
}
/**
* abe_disable_atc
* Parameter:
* Operations:
* Return value:
*/
void abe_disable_atc(u32 id)
{
struct omap_abe_atc_desc atc_desc;
omap_abe_mem_read(abe, OMAP_ABE_DMEM,
(abe_port[id]).protocol.p.prot_dmareq.desc_addr,
(u32 *) &atc_desc, sizeof(atc_desc));
atc_desc.desen = 0;
omap_abe_mem_write(abe, OMAP_ABE_DMEM,
(abe_port[id]).protocol.p.prot_dmareq.desc_addr,
(u32 *) &atc_desc, sizeof(atc_desc));
}
/**
* abe_init_io_tasks
* @prot : protocol being used
*
* load the micro-task parameters doing to DMEM <==> SMEM data moves
*
* I/O descriptors input parameters :
* For Read from DMEM usually THR1/THR2 = X+1/X-1
* For Write to DMEM usually THR1/THR2 = 2/0
* UP_1/2 =X+1/X-1
*/
void abe_init_io_tasks(u32 id, abe_data_format_t *format,
abe_port_protocol_t *prot)
{
u32 x_io, direction, iter_samples, smem1, smem2, smem3, io_sub_id,
io_flag;
u32 copy_func_index, before_func_index, after_func_index;
u32 dmareq_addr, dmareq_field;
u32 sio_desc_address, datasize, iter, nsamp, datasize2, dOppMode32;
u32 atc_ptr_saved, atc_ptr_saved2, copy_func_index1;
u32 copy_func_index2, atc_desc_address1, atc_desc_address2;
struct ABE_SPingPongDescriptor desc_pp;
struct ABE_SIODescriptor sio_desc;
if (prot->protocol_switch == PINGPONG_PORT_PROT) {
/* ping_pong is only supported on MM_DL */
if (OMAP_ABE_MM_DL_PORT != id) {
omap_abe_dbg_error(abe, OMAP_ABE_ERR_API,
ABE_PARAMETER_ERROR);
}
if (abe_port[id].format.f == 44100) {
abe->MultiFrame[18][1] = ABE_TASK_ID(C_ABE_FW_TASK_SRC44P1_MMDL_PP);
smem1 = MM_DL_44P1_WPTR_labelID;
} else {
abe->MultiFrame[18][1] = 0;
smem1 = smem_mm_dl;
}
copy_func_index = (u8) abe_dma_port_copy_subroutine_id(id);
dmareq_addr = abe_port[id].protocol.p.prot_pingpong.irq_addr;
dmareq_field = abe_port[id].protocol.p.prot_pingpong.irq_data;
datasize = abe_dma_port_iter_factor(format);
/* number of "samples" either mono or stereo */
iter = abe_dma_port_iteration(format);
iter_samples = (iter / datasize);
/* load the IO descriptor */
/* no drift */
desc_pp.drift_ASRC = 0;
/* no drift */
desc_pp.drift_io = 0;
desc_pp.hw_ctrl_addr = (u16) dmareq_addr;
desc_pp.copy_func_index = (u8) copy_func_index;
desc_pp.smem_addr = (u8) smem1;
/* DMA req 0 is used for CBPr0 */
desc_pp.atc_irq_data = (u8) dmareq_field;
/* size of block transfer */
desc_pp.x_io = (u8) iter_samples;
desc_pp.data_size = (u8) datasize;
/* address comunicated in Bytes */
desc_pp.workbuff_BaseAddr =
(u16) (abe_base_address_pingpong[1]);
/* size comunicated in XIO sample */
desc_pp.workbuff_Samples = 0;
desc_pp.nextbuff0_BaseAddr =
(u16) (abe_base_address_pingpong[0]);
desc_pp.nextbuff1_BaseAddr =
(u16) (abe_base_address_pingpong[1]);
if (dmareq_addr == ABE_DMASTATUS_RAW) {
desc_pp.nextbuff0_Samples =
(u16) ((abe_size_pingpong >> 2) / datasize);
desc_pp.nextbuff1_Samples =
(u16) ((abe_size_pingpong >> 2) / datasize);
} else {
desc_pp.nextbuff0_Samples = 0;
desc_pp.nextbuff1_Samples = 0;
}
/* next buffer to send is B1, first IRQ fills B0 */
desc_pp.counter = 0;
/* send a DMA req to fill B0 with N samples
abe_block_copy (COPY_FROM_HOST_TO_ABE,
ABE_ATC,
ABE_DMASTATUS_RAW,
&(abe_port[id].protocol.p.prot_pingpong.irq_data),
4); */
sio_desc_address = OMAP_ABE_D_PINGPONGDESC_ADDR;
omap_abe_mem_write(abe, OMAP_ABE_DMEM,
sio_desc_address, (u32 *) &desc_pp,
sizeof(desc_pp));
} else {
io_sub_id = dmareq_addr = ABE_DMASTATUS_RAW;
dmareq_field = 0;
atc_desc_address1 = atc_desc_address2 = 0;
/* default: repeat of the last downlink samples in case of
DMA errors, (disable=0x00) */
io_flag = 0xFF;
datasize2 = datasize = abe_dma_port_iter_factor(format);
x_io = (u8) abe_dma_port_iteration(format);
nsamp = (x_io / datasize);
atc_ptr_saved2 = atc_ptr_saved = DMIC_ATC_PTR_labelID + id;
smem1 = abe_port[id].smem_buffer1;
smem3 = smem2 = abe_port[id].smem_buffer2;
copy_func_index1 = (u8) abe_dma_port_copy_subroutine_id(id);
before_func_index = after_func_index =
copy_func_index2 = NULL_COPY_CFPID;
switch (prot->protocol_switch) {
case DMIC_PORT_PROT:
/* DMIC port is read in two steps */
x_io = x_io >> 1;
nsamp = nsamp >> 1;
atc_desc_address1 = (ABE_ATC_DMIC_DMA_REQ*ATC_SIZE);
io_sub_id = IO_IP_CFPID;
break;
case MCPDMDL_PORT_PROT:
/* PDMDL port is written to in two steps */
x_io = x_io >> 1;
atc_desc_address1 =
(ABE_ATC_MCPDMDL_DMA_REQ*ATC_SIZE);
io_sub_id = IO_IP_CFPID;
break;
case MCPDMUL_PORT_PROT:
atc_desc_address1 =
(ABE_ATC_MCPDMUL_DMA_REQ*ATC_SIZE);
io_sub_id = IO_IP_CFPID;
break;
case SLIMBUS_PORT_PROT:
atc_desc_address1 =
abe_port[id].protocol.p.prot_slimbus.desc_addr1;
atc_desc_address2 =
abe_port[id].protocol.p.prot_slimbus.desc_addr2;
copy_func_index2 = NULL_COPY_CFPID;
/* @@@@@@
#define SPLIT_SMEM_CFPID 9
#define MERGE_SMEM_CFPID 10
#define SPLIT_TDM_12_CFPID 11
#define MERGE_TDM_12_CFPID 12
*/
io_sub_id = IO_IP_CFPID;
break;
case SERIAL_PORT_PROT: /* McBSP/McASP */
atc_desc_address1 =
(s16) abe_port[id].protocol.p.prot_serial.
desc_addr;
io_sub_id = IO_IP_CFPID;
break;
case DMAREQ_PORT_PROT: /* DMA w/wo CBPr */
dmareq_addr =
abe_port[id].protocol.p.prot_dmareq.dma_addr;
dmareq_field = 0;
atc_desc_address1 =
abe_port[id].protocol.p.prot_dmareq.desc_addr;
io_sub_id = IO_IP_CFPID;
break;
}
/* special situation of the PING_PONG protocol which
has its own SIO descriptor format */
/*
Sequence of operations on ping-pong buffers B0/B1
-------------- time ----------------------------
Host Application is ready to send data from DDR to B0
SDMA is initialized from "abe_connect_irq_ping_pong_port" to B0
FIRMWARE starts with #12 B1 data,
sends IRQ/DMAreq, sends #pong B1 data,
sends IRQ/DMAreq, sends #ping B0,
sends B1 samples
ARM / SDMA | fills B0 | fills B1 ... | fills B0 ...
Counter 0 1 2 3
*/
switch (id) {
case OMAP_ABE_PDM_DL_PORT:
abe->MultiFrame[7][0] = ABE_TASK_ID(C_ABE_FW_TASK_IO_PDM_DL);
abe->MultiFrame[19][0] = ABE_TASK_ID(C_ABE_FW_TASK_IO_PDM_DL);
break;
case OMAP_ABE_TONES_DL_PORT:
if (abe_port[id].format.f == 44100) {
smem1 = TONES_44P1_WPTR_labelID;
abe->MultiFrame[20][1] = ABE_TASK_ID(C_ABE_FW_TASK_SRC44P1_TONES_1211);
} else {
abe->MultiFrame[20][1] = 0;
smem1 = smem_tones_dl;
}
break;
case OMAP_ABE_PDM_UL_PORT:
abe->MultiFrame[0][0] = ABE_TASK_ID(C_ABE_FW_TASK_IO_PDM_UL);
break;
case OMAP_ABE_DMIC_PORT:
abe->MultiFrame[2][5] = ABE_TASK_ID(C_ABE_FW_TASK_IO_DMIC);
abe->MultiFrame[14][3] = ABE_TASK_ID(C_ABE_FW_TASK_IO_DMIC);
break;
case OMAP_ABE_MM_UL_PORT:
copy_func_index1 = COPY_MM_UL_CFPID;
before_func_index = ROUTE_MM_UL_CFPID;
break;
case OMAP_ABE_MM_UL2_PORT:
break;
case OMAP_ABE_VX_DL_PORT:
abe->MultiFrame[22][2] = ABE_TASK_ID(C_ABE_FW_TASK_IO_VX_DL);
/* check for 8kHz/16kHz */
if (abe_port[id].format.f == 8000) {
abe->MultiFrame[21][2] =
ABE_TASK_ID(C_ABE_FW_TASK_CHECK_IIR_RIGHT_8K);
abe->MultiFrame[23][2] =
ABE_TASK_ID(C_ABE_FW_TASK_CHECK_IIR_LEFT_8K);
abe->MultiFrame[TASK_VX_DL_SLT][TASK_VX_DL_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_VX_DL_8_48_FIR);
/*Voice_8k_DL_labelID */
smem1 = IO_VX_DL_ASRC_labelID;
if ((abe_port[OMAP_ABE_VX_DL_PORT].status ==
OMAP_ABE_PORT_ACTIVITY_IDLE) &&
(abe_port[OMAP_ABE_VX_UL_PORT].status ==
OMAP_ABE_PORT_ACTIVITY_IDLE)) {
/* the 1st opened port is VX_DL_PORT
* both VX_UL ASRC and VX_DL ASRC will add/remove sample
* referring to VX_DL flow_counter */
abe->MultiFrame[TASK_ASRC_VX_DL_SLT][TASK_ASRC_VX_DL_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_DL_8);
abe->MultiFrame[TASK_ASRC_VX_UL_SLT][TASK_ASRC_VX_UL_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_UL_8_SIB);
/* Init VX_UL ASRC & VX_DL ASRC and enable its adaptation */
abe_init_asrc_vx_ul(-250);
abe_init_asrc_vx_dl(250);
} else {
/* Do nothing, Scheduling Table has already been patched */
}
} else {
abe->MultiFrame[21][2] =
ABE_TASK_ID(C_ABE_FW_TASK_CHECK_IIR_RIGHT_16K);
abe->MultiFrame[23][2] =
ABE_TASK_ID(C_ABE_FW_TASK_CHECK_IIR_LEFT_16K);
abe->MultiFrame[TASK_VX_DL_SLT][TASK_VX_DL_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_VX_DL_16_48);
/* Voice_16k_DL_labelID */
smem1 = IO_VX_DL_ASRC_labelID;
if ((abe_port[OMAP_ABE_VX_DL_PORT].status ==
OMAP_ABE_PORT_ACTIVITY_IDLE) &&
(abe_port[OMAP_ABE_VX_UL_PORT].status ==
OMAP_ABE_PORT_ACTIVITY_IDLE)) {
/* the 1st opened port is VX_DL_PORT
* both VX_UL ASRC and VX_DL ASRC will add/remove sample
* referring to VX_DL flow_counter */
abe->MultiFrame[TASK_ASRC_VX_DL_SLT][TASK_ASRC_VX_DL_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_DL_16);
abe->MultiFrame[TASK_ASRC_VX_UL_SLT][TASK_ASRC_VX_UL_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_UL_16_SIB);
/* Init VX_UL ASRC & VX_DL ASRC and enable its adaptation */
abe_init_asrc_vx_ul(-250);
abe_init_asrc_vx_dl(250);
} else {
/* Do nothing, Scheduling Table has already been patched */
}
}
break;
case OMAP_ABE_VX_UL_PORT:
abe->MultiFrame[16][3] = ABE_TASK_ID(C_ABE_FW_TASK_IO_VX_UL);
/* check for 8kHz/16kHz */
if (abe_port[id].format.f == 8000) {
abe->MultiFrame[21][2] =
ABE_TASK_ID(C_ABE_FW_TASK_CHECK_IIR_RIGHT_8K);
abe->MultiFrame[23][2] =
ABE_TASK_ID(C_ABE_FW_TASK_CHECK_IIR_LEFT_8K);
abe->MultiFrame[TASK_VX_UL_SLT][TASK_VX_UL_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_VX_UL_48_8);
/* MultiFrame[TASK_ECHO_SLT][TASK_ECHO_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_ECHO_REF_48_8); */
smem1 = Voice_8k_UL_labelID;
if ((abe_port[OMAP_ABE_VX_DL_PORT].status ==
OMAP_ABE_PORT_ACTIVITY_IDLE) &&
(abe_port[OMAP_ABE_VX_UL_PORT].status ==
OMAP_ABE_PORT_ACTIVITY_IDLE)) {
/* the 1st opened port is VX_UL_PORT
* both VX_UL ASRC and VX_DL ASRC will add/remove sample
* referring to VX_UL flow_counter */
abe->MultiFrame[TASK_ASRC_VX_DL_SLT][TASK_ASRC_VX_DL_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_DL_8_SIB);
abe->MultiFrame[TASK_ASRC_VX_UL_SLT][TASK_ASRC_VX_UL_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_UL_8);
/* Init VX_UL ASRC & VX_DL ASRC and enable its adaptation */
abe_init_asrc_vx_ul(-250);
abe_init_asrc_vx_dl(250);
} else {
/* Do nothing, Scheduling Table has already been patched */
}
} else {
abe->MultiFrame[21][2] =
ABE_TASK_ID(C_ABE_FW_TASK_CHECK_IIR_RIGHT_16K);
abe->MultiFrame[23][2] =
ABE_TASK_ID(C_ABE_FW_TASK_CHECK_IIR_LEFT_16K);
abe->MultiFrame[TASK_VX_UL_SLT][TASK_VX_UL_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_VX_UL_48_16);
/* MultiFrame[TASK_ECHO_SLT][TASK_ECHO_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_ECHO_REF_48_16); */
smem1 = Voice_16k_UL_labelID;
if ((abe_port[OMAP_ABE_VX_DL_PORT].status ==
OMAP_ABE_PORT_ACTIVITY_IDLE) &&
(abe_port[OMAP_ABE_VX_UL_PORT].status ==
OMAP_ABE_PORT_ACTIVITY_IDLE)) {
/* the 1st opened port is VX_UL_PORT
* both VX_UL ASRC and VX_DL ASRC will add/remove sample
* referring to VX_UL flow_counter */
abe->MultiFrame[TASK_ASRC_VX_DL_SLT][TASK_ASRC_VX_DL_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_DL_16_SIB);
abe->MultiFrame[TASK_ASRC_VX_UL_SLT][TASK_ASRC_VX_UL_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_UL_16);
/* Init VX_UL ASRC & VX_DL ASRC and enable its adaptation */
abe_init_asrc_vx_ul(-250);
abe_init_asrc_vx_dl(250);
} else {
/* Do nothing, Scheduling Table has already been patched */
}
}
break;
case OMAP_ABE_BT_VX_DL_PORT:
/* check for 8kHz/16kHz */
omap_abe_mem_read(abe, OMAP_ABE_DMEM,
OMAP_ABE_D_MAXTASKBYTESINSLOT_ADDR, &dOppMode32,
sizeof(u32));
/* Disable BT ASRC */
dOppMode32 = DOPPMODE32_OPP50;
if (abe_port[id].format.f == 8000) {
if (dOppMode32 == DOPPMODE32_OPP100) {
abe->MultiFrame[TASK_BT_DL_48_8_SLT][TASK_BT_DL_48_8_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_BT_DL_48_8_FIR_OPP100_FW_COMPAT);
smem1 = BT_DL_8k_opp100_labelID;
} else {
abe->MultiFrame[TASK_BT_DL_48_8_SLT][TASK_BT_DL_48_8_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_BT_DL_48_8_FIR_FW_COMPAT);
smem1 = BT_DL_8k_labelID;
}
#if 0
if ((abe_port[OMAP_ABE_BT_VX_DL_PORT].status ==
OMAP_ABE_PORT_ACTIVITY_IDLE) &&
(abe_port[OMAP_ABE_BT_VX_UL_PORT].status ==
OMAP_ABE_PORT_ACTIVITY_IDLE)) {
/* the 1st opened port is BT_VX_DL_PORT
* both BT_VX_DL ASRC and BT_VX_UL ASRC will add/remove sample
* referring to BT_VX_DL flow_counter */
abe->MultiFrame[TASK_ASRC_BT_DL_SLT][TASK_ASRC_BT_DL_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_DL_8);
abe->MultiFrame[TASK_ASRC_BT_UL_SLT][TASK_ASRC_BT_UL_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_UL_8_SIB);
} else {
/* Do nothing, Scheduling Table has already been patched */
}
#endif
} else {
if (dOppMode32 == DOPPMODE32_OPP100) {
abe->MultiFrame[TASK_BT_DL_48_8_SLT][TASK_BT_DL_48_8_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_BT_DL_48_16_OPP100);
smem1 = BT_DL_16k_opp100_labelID;
} else {
abe->MultiFrame[TASK_BT_DL_48_8_SLT][TASK_BT_DL_48_8_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_BT_DL_48_16);
smem1 = BT_DL_16k_labelID;
}
#if 0
if ((abe_port[OMAP_ABE_BT_VX_DL_PORT].status ==
OMAP_ABE_PORT_ACTIVITY_IDLE) &&
(abe_port[OMAP_ABE_BT_VX_UL_PORT].status ==
OMAP_ABE_PORT_ACTIVITY_IDLE)) {
/* the 1st opened port is BT_VX_DL_PORT
* both BT_VX_DL ASRC and BT_VX_UL ASRC will add/remove sample
* referring to BT_VX_DL flow_counter */
abe->MultiFrame[TASK_ASRC_BT_DL_SLT][TASK_ASRC_BT_DL_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_DL_16);
abe->MultiFrame[TASK_ASRC_BT_UL_SLT][TASK_ASRC_BT_UL_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_UL_16_SIB);
} else {
/* Do nothing, Scheduling Table has already been patched */
}
#endif
}
break;
case OMAP_ABE_BT_VX_UL_PORT:
/* check for 8kHz/16kHz */
/* set the SMEM buffer -- programming sequence */
omap_abe_mem_read(abe, OMAP_ABE_DMEM,
OMAP_ABE_D_MAXTASKBYTESINSLOT_ADDR, &dOppMode32,
sizeof(u32));
/* Disable BT ASRC */
dOppMode32 = DOPPMODE32_OPP50;
if (abe_port[id].format.f == 8000) {
abe->MultiFrame[TASK_BT_UL_8_48_SLT][TASK_BT_UL_8_48_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_BT_UL_8_48);
if (dOppMode32 == DOPPMODE32_OPP100)
/* ASRC input buffer, size 40 */
smem1 = smem_bt_vx_ul_opp100;
else
/* at OPP 50 without ASRC */
smem1 = BT_UL_8k_labelID;
#if 0
if ((abe_port[OMAP_ABE_BT_VX_UL_PORT].status ==
OMAP_ABE_PORT_ACTIVITY_IDLE) &&
(abe_port[OMAP_ABE_BT_VX_DL_PORT].status ==
OMAP_ABE_PORT_ACTIVITY_IDLE)) {
/* the 1st opened port is BT_VX_UL_PORT */
/* both BT_VX_UL ASRC and BT_VX_DL ASRC will add/remove sample
referring to BT_VX_UL flow_counter */
abe->MultiFrame[TASK_ASRC_BT_UL_SLT][TASK_ASRC_BT_UL_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_UL_8);
abe->MultiFrame[TASK_ASRC_BT_DL_SLT][TASK_ASRC_BT_DL_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_DL_8_SIB);
} else {
/* Do nothing, Scheduling Table has already been patched */
}
#endif
} else {
abe->MultiFrame[TASK_BT_UL_8_48_SLT][TASK_BT_UL_8_48_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_BT_UL_16_48);
if (dOppMode32 == DOPPMODE32_OPP100)
/* ASRC input buffer, size 40 */
smem1 = smem_bt_vx_ul_opp100;
else
/* at OPP 50 without ASRC */
smem1 = BT_UL_16k_labelID;
#if 0
if ((abe_port[OMAP_ABE_BT_VX_UL_PORT].status ==
OMAP_ABE_PORT_ACTIVITY_IDLE) &&
(abe_port[OMAP_ABE_BT_VX_DL_PORT].status ==
OMAP_ABE_PORT_ACTIVITY_IDLE)) {
/* the 1st opened port is BT_VX_UL_PORT */
/* both BT_VX_UL ASRC and BT_VX_DL ASRC will add/remove sample
referring to BT_VX_UL flow_counter */
abe->MultiFrame[TASK_ASRC_BT_UL_SLT][TASK_ASRC_BT_UL_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_UL_16);
abe->MultiFrame[TASK_ASRC_BT_DL_SLT][TASK_ASRC_BT_DL_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_DL_16_SIB);
} else {
/* Do nothing, Scheduling Table has already been patched */
}
#endif
}
break;
case OMAP_ABE_MM_DL_PORT:
/* check for CBPr / serial_port / Ping-pong access */
if (abe_port[id].format.f == 44100) {
smem1 = MM_DL_44P1_WPTR_labelID;
abe->MultiFrame[18][1] = ABE_TASK_ID(C_ABE_FW_TASK_SRC44P1_MMDL);
} else {
abe->MultiFrame[18][1] = 0;
smem1 = smem_mm_dl;
}
break;
case OMAP_ABE_MM_EXT_IN_PORT:
/* set the SMEM buffer -- programming sequence */
omap_abe_mem_read(abe, OMAP_ABE_DMEM,
OMAP_ABE_D_MAXTASKBYTESINSLOT_ADDR, &dOppMode32,
sizeof(u32));
/* Disable MM EXT ASRC */
dOppMode32 = DOPPMODE32_OPP50;
if (dOppMode32 == DOPPMODE32_OPP100)
/* ASRC input buffer, size 40 */
smem1 = smem_mm_ext_in_opp100;
else
/* at OPP 50 without ASRC */
smem1 = smem_mm_ext_in_opp50;
break;
case OMAP_ABE_MM_EXT_OUT_PORT:
break;
default:
break;
}
if (abe_port[id].protocol.direction == ABE_ATC_DIRECTION_IN)
direction = 0;
else
/* offset of the write pointer in the ATC descriptor */
direction = 3;
sio_desc.drift_ASRC = 0;
sio_desc.drift_io = 0;
sio_desc.io_type_idx = (u8) io_sub_id;
sio_desc.samp_size = (u8) datasize;
sio_desc.hw_ctrl_addr = (u16) (dmareq_addr << 2);
sio_desc.atc_irq_data = (u8) dmareq_field;
sio_desc.flow_counter = (u16) 0;
sio_desc.direction_rw = (u8) direction;
sio_desc.repeat_last_samp = (u8) io_flag;
sio_desc.nsamp = (u8) nsamp;
sio_desc.x_io = (u8) x_io;
/* set ATC ON */
sio_desc.on_off = 0x80;
sio_desc.split_addr1 = (u16) smem1;
sio_desc.split_addr2 = (u16) smem2;
sio_desc.split_addr3 = (u16) smem3;
sio_desc.before_f_index = (u8) before_func_index;
sio_desc.after_f_index = (u8) after_func_index;
sio_desc.smem_addr1 = (u16) smem1;
sio_desc.atc_address1 = (u16) atc_desc_address1;
sio_desc.atc_pointer_saved1 = (u16) atc_ptr_saved;
sio_desc.data_size1 = (u8) datasize;
sio_desc.copy_f_index1 = (u8) copy_func_index1;
sio_desc.smem_addr2 = (u16) smem2;
sio_desc.atc_address2 = (u16) atc_desc_address2;
sio_desc.atc_pointer_saved2 = (u16) atc_ptr_saved2;
sio_desc.data_size2 = (u8) datasize2;
sio_desc.copy_f_index2 = (u8) copy_func_index2;
sio_desc_address = OMAP_ABE_D_IODESCR_ADDR + (id *
sizeof(struct ABE_SIODescriptor));
omap_abe_mem_write(abe, OMAP_ABE_DMEM,
sio_desc_address, (u32 *) &sio_desc,
sizeof(sio_desc));
}
omap_abe_mem_write(abe, OMAP_ABE_DMEM,
OMAP_ABE_D_MULTIFRAME_ADDR, (u32 *) abe->MultiFrame,
sizeof(abe->MultiFrame));
}
/**
* omap_abe_select_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
*/
int omap_abe_select_main_port(u32 id)
{
u32 selection;
_log(ABE_ID_SELECT_MAIN_PORT, id, 0, 0);
/* flow control */
selection = OMAP_ABE_D_IODESCR_ADDR + id * sizeof(struct ABE_SIODescriptor) +
flow_counter_;
/* when the main port is a sink port from AESS point of view
the sign the firmware task analysis must be changed */
selection &= 0xFFFFL;
if (abe_port[id].protocol.direction == ABE_ATC_DIRECTION_IN)
selection |= 0x80000;
omap_abe_mem_write(abe, OMAP_ABE_DMEM, OMAP_ABE_D_SLOT23_CTRL_ADDR,
&selection, 4);
return 0;
}
/**
* 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)
omap_abe_select_main_port(OMAP_ABE_PDM_DL_PORT);
else
omap_abe_select_main_port(abe_port_priority[id]);
}
/**
* 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;
}
/**
* omap_abe_dma_port_iter_factor
* @f: port format
*
* returns the multiplier factor to apply during data move with DMEM
*/
u32 omap_abe_dma_port_iter_factor(struct omap_abe_data_format *f)
{
u32 iter, mulfac;
abe_format_switch((abe_data_format_t *)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 == OMAP_ABE_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 == OMAP_ABE_PDM_DL_PORT) {
sub_id = COPY_MCPDM_DL_CFPID;
break;
}
if (port_id == OMAP_ABE_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_read_remaining_data
* @id: ABE port_ID
* @n: size pointer to the remaining number of 32bits words
*
* computes the remaining amount of data in the buffer.
*/
abehal_status abe_read_remaining_data(u32 port, u32 *n)
{
u32 sio_pp_desc_address;
struct ABE_SPingPongDescriptor desc_pp;
_log(ABE_ID_READ_REMAINING_DATA, port, 0, 0);
/*
* read the port SIO descriptor and extract the
* current pointer address after reading the counter
*/
sio_pp_desc_address = OMAP_ABE_D_PINGPONGDESC_ADDR;
omap_abe_mem_read(abe, OMAP_ABE_DMEM, sio_pp_desc_address,
(u32 *) &desc_pp, sizeof(struct ABE_SPingPongDescriptor));
*n = desc_pp.workbuff_Samples;
return 0;
}
EXPORT_SYMBOL(abe_read_remaining_data);
/**
* omap_abe_mono_mixer
* @id: name of the mixer (MIXDL1, MIXDL2 or MIXAUDUL)
* on_off: enable\disable flag
*
* This API Programs DL1Mixer or DL2Mixer to output mono data
* on both left and right data paths.
*/
int omap_abe_mono_mixer(struct omap_abe *abe, u32 id, u32 on_off)
{
switch (id) {
case MIXDL1:
if (on_off)
abe->MultiFrame[TASK_DL1Mixer_SLT][TASK_DL1Mixer_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_DL1Mixer_dual_mono);
else
abe->MultiFrame[TASK_DL1Mixer_SLT][TASK_DL1Mixer_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_DL1Mixer);
break;
case MIXDL2:
if (on_off)
abe->MultiFrame[TASK_DL2Mixer_SLT][TASK_DL2Mixer_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_DL2Mixer_dual_mono);
else
abe->MultiFrame[TASK_DL2Mixer_SLT][TASK_DL2Mixer_IDX] =
ABE_TASK_ID(C_ABE_FW_TASK_DL2Mixer);
break;
case MIXAUDUL:
if (on_off)
abe->MultiFrame[12][4] =
ABE_TASK_ID(C_ABE_FW_TASK_ULMixer_dual_mono);
else
abe->MultiFrame[12][4] =
ABE_TASK_ID(C_ABE_FW_TASK_ULMixer);
break;
default:
break;
}
omap_abe_mem_write(abe, OMAP_ABE_DMEM, OMAP_ABE_D_MULTIFRAME_ADDR,
(u32 *) abe->MultiFrame, sizeof(abe->MultiFrame));
return 0;
}
EXPORT_SYMBOL(omap_abe_mono_mixer);
/**
* abe_write_pdmdl_offset - write the desired offset on the DL1/DL2 paths
*
* Parameters:
* path: 1 for the DL1 ABE path, 2 for the DL2 ABE path
* offset_left: integer value that will be added on all PDM left samples
* offset_right: integer value that will be added on all PDM right samples
*
*/
void abe_write_pdmdl_offset(u32 path, u32 offset_left, u32 offset_right)
{
switch (path) {
case 1:
omap_abe_mem_write(abe, OMAP_ABE_SMEM, OMAP_ABE_S_DC_HS_ADDR + 4,
&offset_left, sizeof(u32));
omap_abe_mem_write(abe, OMAP_ABE_SMEM, OMAP_ABE_S_DC_HS_ADDR,
&offset_right, sizeof(u32));
break;
case 2:
omap_abe_mem_write(abe, OMAP_ABE_SMEM, OMAP_ABE_S_DC_HF_ADDR + 4,
&offset_left, sizeof(u32));
omap_abe_mem_write(abe, OMAP_ABE_SMEM, OMAP_ABE_S_DC_HF_ADDR,
&offset_right, sizeof(u32));
break;
default:
break;
}
}
EXPORT_SYMBOL(abe_write_pdmdl_offset);