Beispiel #1
0
void abe_add_sequence(abe_uint32 *id, abe_sequence_t *s)
{
	abe_seq_t *seq_src, *seq_dst;
	abe_uint32 i, no_end_of_sequence_found;

	seq_src = &(s->seq1);
	seq_dst = &((abe_all_sequence[abe_sequence_write_pointer]).seq1);

	if ((abe_sequence_write_pointer >= MAXNBSEQUENCE) || ((abe_uint32)s == 0)) {
		abe_dbg_param |= ERR_SEQ;
		abe_dbg_error_log(ABE_PARAMETER_OVERFLOW);
	} else {
		*id = abe_subroutine_write_pointer;
		(abe_all_sequence[abe_sequence_write_pointer]).mask = s->mask;	/* copy the mask */

		for (no_end_of_sequence_found = 1, i = 0; i < MAXSEQUENCESTEPS; i++, seq_src++, seq_dst++) {
			(*seq_dst) = (*seq_src);	/* sequence copied line by line */

			if ((*(abe_int32 *)seq_src) == -1) {
				/* stop when the line start with time=(-1) */
				no_end_of_sequence_found = 0;
				break;
			}
		}
		abe_subroutine_write_pointer++;

		if (no_end_of_sequence_found)
			abe_dbg_error_log(ABE_SEQTOOLONG);
	}
}
Beispiel #2
0
/**
 * 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:
		break;
	}
}
Beispiel #3
0
/*
 *  ABE_ADD_SUBROUTINE
 *
 *  Parameter  :
 *      port id
 *      pointer to the subroutines
 *      number of parameters to push on the stack before call
 *
 *  Operations :
 *      add one function pointer more and returns the index to it
 *
 *  Return value :
 *
 */
void abe_add_subroutine (abe_uint32 *id, abe_subroutine2 f, abe_uint32 nparam, abe_uint32* params)
{
	abe_uint32 i, i_found;

	if ((abe_subroutine_write_pointer >= MAXNBSUBROUTINE) || ((abe_uint32)f == 0)) {
		abe_dbg_param |= ERR_SEQ;
		abe_dbg_error_log(ABE_PARAMETER_OVERFLOW);
	} else {
		/* search if this subroutine address was not already
		 * declared, then return the previous index
		 */
		for (i_found = abe_subroutine_write_pointer, i = 0; i < abe_subroutine_write_pointer; i++) {
			if (f == abe_all_subsubroutine[i])
				i_found = i;
		}

		if (i_found == abe_subroutine_write_pointer) {
			*id = abe_subroutine_write_pointer;
			abe_all_subsubroutine[abe_subroutine_write_pointer] = (f);
			abe_all_subroutine_params[abe_subroutine_write_pointer] = params;
			abe_all_subsubroutine_nparam[abe_subroutine_write_pointer] = nparam;
			abe_subroutine_write_pointer++;
		} else {
			abe_all_subroutine_params[i_found] = params;
			*id = i_found;
		}
	}
}
Beispiel #4
0
/*
 *  ABE_READ_NEXT_PING_PONG_BUFFER
 *
 *  Parameter  :
 *	Port_ID :
 *	Returned address to the next buffer (byte offset from DMEM start)
 *
 *  Operations :
 *	Tell the next base address of the next ping_pong Buffer and its size
 *
 *
 */
void abe_read_next_ping_pong_buffer(abe_port_id port, abe_uint32 *p, abe_uint32 *n)
{
	abe_uint32 sio_pp_desc_address;
	ABE_SPingPongDescriptor desc_pp;

	_lock_enter
	_log(id_read_next_ping_pong_buffer,port,0,0)

	/* ping_pong is only supported on MM_DL */
	if (port != MM_DL_PORT) {
		abe_dbg_param |= ERR_API;
		abe_dbg_error_log(ABE_PARAMETER_ERROR);
	}

	/* read the port SIO descriptor and extract the current pointer address  after reading the counter */
	sio_pp_desc_address = D_PingPongDesc_ADDR;
	abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM, sio_pp_desc_address, (abe_uint32*)&desc_pp, sizeof(ABE_SPingPongDescriptor));

	if ((desc_pp.counter & 0x1) == 0) {
		(*p) = desc_pp.nextbuff0_BaseAddr;
	} else {
		(*p) = desc_pp.nextbuff1_BaseAddr;
	}

	/* translates the number of samples in bytes */
	(*n) = abe_size_pingpong;

	_lock_exit
}
Beispiel #5
0
/*
 *  ABE_WRITE_EVENT_GENERATOR
 *
 *  Parameter  :
 *	e: Event Generation Counter, McPDM, DMIC or default.
 *
 *  Operations :
 *	load the AESS event generator hardware source. Loads the firmware parameters
 *	accordingly. Indicates to the FW which data stream is the most important to preserve
 *	in case all the streams are asynchronous. If the parameter is "default", let the HAL
 *	decide which Event source is the best appropriate based on the opened ports.
 *
 *	When neither the DMIC and the McPDM are activated the AE will have its EVENT generator programmed
 *	with the EVENT_COUNTER. The event counter will be tuned in order to deliver a pulse frequency higher
 *	than 96 kHz. The DPLL output at 100% OPP is MCLK = (32768kHz x6000) = 196.608kHz
 *	The ratio is (MCLK/96000)+(1<<1) = 2050
 *	(1<<1) in order to have the same speed at 50% and 100% OPP (only 15 MSB bits are used at OPP50%)
 *
 *  Return value :
 *	None.
 */
void abe_write_event_generator(abe_event_id e)
{
	abe_uint32 event, selection, counter, start;

	_lock_enter
	_log(id_write_event_generator,e,0,0)

	counter = EVENT_GENERATOR_COUNTER_DEFAULT;
	start = EVENT_GENERATOR_ON;
	abe_current_event_id = e;

	switch (e) {
	case EVENT_MCPDM:
		selection = EVENT_SOURCE_DMA;
		event = ABE_ATC_MCPDMDL_DMA_REQ;
		break;
	case EVENT_DMIC:
		selection = EVENT_SOURCE_DMA;
		event = ABE_ATC_DMIC_DMA_REQ;
		break;
	case EVENT_TIMER:
		selection = EVENT_SOURCE_COUNTER;
		event = 0;
		break;
	case EVENT_McBSP:
		selection = EVENT_SOURCE_COUNTER;
		event = 0;
		break;
	case EVENT_McASP:
		selection = EVENT_SOURCE_COUNTER;
		event = 0;
		break;
	case EVENT_SLIMBUS:
		selection = EVENT_SOURCE_COUNTER;
		event = 0;
		break;
	case EVENT_44100:
		selection = EVENT_SOURCE_COUNTER;
		event = 0;
		counter = EVENT_GENERATOR_COUNTER_44100;
		break;
	case EVENT_DEFAULT:
		selection = EVENT_SOURCE_COUNTER;
		event = 0;
		break;
	default:
		abe_dbg_param |= ERR_API;
		abe_dbg_error_log(ABE_BLOCK_COPY_ERR);
	}

	abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_ATC, EVENT_GENERATOR_COUNTER, &counter, 4);
	abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_ATC, EVENT_SOURCE_SELECTION, &selection, 4);
	abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_ATC, EVENT_GENERATOR_START, &start, 4);
	abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_ATC, AUDIO_ENGINE_SCHEDULER, &event, 4);

	_lock_exit
}
Beispiel #6
0
/*
 *  ABE_SET_PING_PONG_BUFFER
 *
 *  Parameter  :
 *	Port_ID :
 *	New data
 *
 *  Operations :
 *	Updates the next ping-pong buffer with "size" bytes copied from the
 *	host processor. This API notifies the FW that the data transfer is done.
 */
void abe_set_ping_pong_buffer(abe_port_id port, abe_uint32 n_bytes)
{
	abe_uint32 sio_pp_desc_address, struct_offset, *src, n_samples, datasize, base_and_size;
	ABE_SPingPongDescriptor desc_pp;

	_lock_enter
	_log(id_set_ping_pong_buffer,port,n_bytes,n_bytes>>8)

	/* ping_pong is only supported on MM_DL */
	if (port != MM_DL_PORT) {
	    abe_dbg_param |= ERR_API;
	    abe_dbg_error_log(ABE_PARAMETER_ERROR);
	}
	/* translates the number of bytes in samples */
	/* data size in DMEM words */
	datasize = abe_dma_port_iter_factor(&((abe_port[port]).format));
	/* data size in bytes */
	datasize = datasize << 2;
	n_samples = n_bytes / datasize;

	abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM, D_PingPongDesc_ADDR,
					(abe_uint32 *)&desc_pp, sizeof(desc_pp));

	/*
	 * read the port SIO descriptor and extract the current pointer
	 * address  after reading the counter
	 */
	if ((desc_pp.counter & 0x1) == 0) {
		struct_offset = (abe_uint32)&(desc_pp.nextbuff0_BaseAddr) -
							(abe_uint32)&(desc_pp);
		base_and_size = desc_pp.nextbuff0_BaseAddr;
	} else {
		struct_offset = (abe_uint32)&(desc_pp.nextbuff1_BaseAddr) -
							(abe_uint32)&(desc_pp);
		base_and_size = desc_pp.nextbuff1_BaseAddr;
	}

	base_and_size = (base_and_size & 0xFFFFL) + ((abe_uint32)n_samples << 16);

	sio_pp_desc_address = D_PingPongDesc_ADDR + struct_offset;
	src = &base_and_size;
	abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, sio_pp_desc_address,
				(abe_uint32 *)&base_and_size, sizeof(abe_uint32));

	_lock_exit
}
Beispiel #7
0
/*
 *  ABE_SET_OPP_PROCESSING
 *
 *  Parameter  :
 *	New processing network and OPP:
 *	  0: Ultra Lowest power consumption audio player (no post-processing, no mixer)
 *	  1: OPP 25% (simple multimedia features, including low-power player)
 *	  2: OPP 50% (multimedia and voice calls)
 *	  3: OPP100% (EANC, multimedia complex use-cases)
 *
 *  Operations :
 *	Rearranges the FW task network to the corresponding OPP list of features.
 *	The corresponding AE ports are supposed to be set/reset accordingly before this switch.
 *
 *  Return value :
 *	error code when the new OPP do not corresponds the list of activated features
 */
void abe_set_opp_processing(abe_opp_t opp)
{
	abe_uint32 dOppMode32, sio_desc_address;
	ABE_SIODescriptor desc;

	_lock_enter
	_log(id_set_opp_processing,opp,0,0)

	switch(opp){
	case ABE_OPP25:
		/* OPP25% */
		dOppMode32 = DOPPMODE32_OPP25;
		break;
	case ABE_OPP50:
		/* OPP50% */
		dOppMode32 = DOPPMODE32_OPP50;
		break;
	default:
		abe_dbg_param |= ERR_API;
		abe_dbg_error_log(ABE_BLOCK_COPY_ERR);
		case ABE_OPP100:
		/* OPP100% */
		dOppMode32 = DOPPMODE32_OPP100;
		break;
	}

	/* Write Multiframe inside DMEM */
	abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
		D_maxTaskBytesInSlot_ADDR, &dOppMode32, sizeof(abe_uint32));

	sio_desc_address = dmem_port_descriptors + (MM_DL_PORT * sizeof(ABE_SIODescriptor));
	abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM, sio_desc_address,
					(abe_uint32*)&desc, sizeof (desc));
	if (dOppMode32 == DOPPMODE32_OPP100)
		desc.smem_addr1 = smem_mm_dl_opp100; /* ASRC input buffer, size 40 */
	else
		desc.smem_addr1 = smem_mm_dl_opp25; /* at OPP 25/50 or without ASRC  */
	abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, sio_desc_address,
					(abe_uint32*)&desc, sizeof (desc));

	_lock_exit

}
Beispiel #8
0
/**
* @fn abe_connect_dmareq_ping_pong_port()
*
*  Operations : enables the data echanges between a DMA and a direct access to
*   the DMEM memory of ABE. On each dma_request activation the DMA will exchange
*   "s" bytes and switch to the "pong" buffer for a new buffer exchange.
*
*    Parameters :
*    id: port name
*    f : desired data format
*    d : desired dma_request line (0..7)
*    s : half-buffer (ping) size
*
*    a : returned pointer to the base address of the ping-pong buffer and number of samples to exchange during a DMA_request.
*
* @see	ABE_API.h
*/
void abe_connect_dmareq_ping_pong_port(abe_port_id id, abe_data_format_t *f, abe_uint32 d, abe_uint32 s, abe_dma_t *returned_dma_t)
{
	abe_dma_t dma1;

	_lock_enter
	_log(id_connect_dmareq_ping_pong_port,id,f->f,f->samp_format)

	/* ping_pong is only supported on MM_DL */
	if (id != MM_DL_PORT)
	{
	    abe_dbg_param |= ERR_API;
	    abe_dbg_error_log(ABE_PARAMETER_ERROR);
	}

	/* declare PP buffer and prepare the returned dma_t */
	abe_init_ping_pong_buffer(MM_DL_PORT, s, 2, (abe_uint32 *)&(returned_dma_t->data));

	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 = dmem_ping_pong_buffer;
	(abe_port[id]).protocol.p.prot_pingpong.buf_size = s;
	(abe_port[id]).protocol.p.prot_pingpong.irq_addr = ABE_DMASTATUS_RAW;
	(abe_port[id]).protocol.p.prot_pingpong.irq_data = (1 << d);

	abe_port [id].status = RUN_P;

	/* load the micro-task parameters DESC_IO_PP */
	abe_init_io_tasks(id, &((abe_port [id]).format), &((abe_port [id]).protocol));

	/* load the dma_t with physical information from AE memory mapping */
	abe_init_dma_t(id, &((abe_port [id]).protocol));

	dma1.data = (abe_uint32 *)(abe_port [id].dma.data + ABE_DMEM_BASE_ADDRESS_L3);
	dma1.iter = abe_port [id].dma.iter;
	(*returned_dma_t) = dma1;

	_lock_exit
}
Beispiel #9
0
/**
 * abe_block_copy
 * @direction: direction of the data move (Read/Write)
 * @memory_bamk:memory bank among PMEM, DMEM, CMEM, SMEM, ATC/IO
 * @address: address of the memory copy (byte addressing)
 * @data: pointer to the data to transfer
 * @nb_bytes: number of data to move
 *
 * Memory transfer to/from ABE to MPU
 */
void abe_block_copy(u32 direction, u32 memory_bank, u32 address,
		    u32 *data, u32 nb_bytes)
{
	u32 i;
	u32 base_address = 0, *src_ptr, *dst_ptr, n;

	switch (memory_bank) {
	case ABE_PMEM:
		base_address = (u32) abe->io_base + ABE_PMEM_BASE_OFFSET_MPU;
		break;
	case ABE_CMEM:
		base_address = (u32) abe->io_base + ABE_CMEM_BASE_OFFSET_MPU;
		break;
	case ABE_SMEM:
		base_address = (u32) abe->io_base + ABE_SMEM_BASE_OFFSET_MPU;
		break;
	case ABE_DMEM:
		base_address = (u32) abe->io_base + ABE_DMEM_BASE_OFFSET_MPU;
		break;
	case ABE_ATC:
		base_address = (u32) abe->io_base + ABE_ATC_BASE_OFFSET_MPU;
		break;
	default:
		base_address = (u32) abe->io_base + ABE_SMEM_BASE_OFFSET_MPU;
		abe->dbg_param |= ERR_LIB;
		abe_dbg_error_log(ABE_BLOCK_COPY_ERR);
		break;
	}
	if (direction == COPY_FROM_HOST_TO_ABE) {
		dst_ptr = (u32 *) (base_address + address);
		src_ptr = (u32 *) data;
	} else {
		dst_ptr = (u32 *) data;
		src_ptr = (u32 *) (base_address + address);
	}
	n = (nb_bytes / 4);
	for (i = 0; i < n; i++)
		*dst_ptr++ = *src_ptr++;
}
Beispiel #10
0
/*
 *  ABE_INIT_PING_PONG_BUFFER
 *
 *  Parameter  :
 *	size of the ping pong
 *	number of buffers (2 = ping/pong)
 *	returned address of the ping-pong list of base address (byte offset from DMEM start)
 *
 *  Operations :
 *	Computes the base address of the ping_pong buffers
 *
 */
void abe_init_ping_pong_buffer(abe_port_id id, abe_uint32 size_bytes, abe_uint32 n_buffers, abe_uint32 *p)
{
	abe_uint32 i, dmem_addr;

	_lock_enter
	_log(id_init_ping_pong_buffer,id,size_bytes,n_buffers)

	/* ping_pong is supported in 2 buffers configuration right now but FW is ready for ping/pong/pung/pang... */
	if (id != MM_DL_PORT || n_buffers > MAX_PINGPONG_BUFFERS) {
		abe_dbg_param |= ERR_API;
		abe_dbg_error_log(ABE_PARAMETER_ERROR);
	}

	for (i = 0; i < n_buffers; i++) {
		dmem_addr = dmem_ping_pong_buffer + (i * size_bytes);
		abe_base_address_pingpong [i] = dmem_addr;	 /* base addresses of the ping pong buffers in U8 unit */
	}

	abe_size_pingpong = size_bytes;	/* global data */
	*p = (abe_uint32)dmem_ping_pong_buffer;
	_lock_exit
}
Beispiel #11
0
/**
*  abe_read_use_case_opp() description for void abe_read_use_case_opp().
*
*  Operations : returns the expected min OPP for a given use_case list
*
*  Parameter  : No parameter
* @param
*
* @pre	  no pre-condition
*
* @post
*
* @return	error code
*
* @see
*/
void abe_read_use_case_opp(abe_use_case_id *u, abe_opp_t *o)
{
	abe_uint32 opp, i;
	abe_use_case_id *ptr = u;

	#define MAX_READ_USE_CASE_OPP 10	/* there is no reason to have more use_cases */
	#define OPP_25	1
	#define OPP_50	2
	#define OPP_100 4

	_lock_enter
	_log(id_read_use_case_opp,(abe_uint32)(u),(abe_uint32)u>>8,(abe_uint32)u>>16)

	opp = i = 0;
	do {
		/* check for pointer errors */
		if (i > MAX_READ_USE_CASE_OPP) {
			abe_dbg_param |= ERR_API;
			abe_dbg_error_log(ABE_READ_USE_CASE_OPP_ERR);
			break;
		}

		/* check for end_of_list */
		if (*ptr <= 0)
			break;

		/* OPP selection based on current firmware implementation */
		switch (*ptr) {
		case ABE_AUDIO_PLAYER_ON_HEADSET_OR_EARPHONE:
			opp |= OPP_25;
			break;
		case ABE_DRIFT_MANAGEMENT_FOR_AUDIO_PLAYER:
			opp |= OPP_100;
			break;
		case ABE_DRIFT_MANAGEMENT_FOR_VOICE_CALL:
			opp |= OPP_100;
			break;
		case ABE_VOICE_CALL_ON_HEADSET_OR_EARPHONE_OR_BT:
			opp |= OPP_50;
			break;
		case ABE_MULTIMEDIA_AUDIO_RECORDER:
			opp |= OPP_50;
			break;
		case ABE_VIBRATOR_OR_HAPTICS:
			opp |= OPP_100;
			break;
		case ABE_VOICE_CALL_ON_HANDS_FREE_SPEAKER:
			opp |= OPP_100;
			break;
		case ABE_RINGER_TONES:
			opp |= OPP_100;
			break;
		case ABE_VOICE_CALL_WITH_EARPHONE_ACTIVE_NOISE_CANCELLER:
			opp |= OPP_100;
			break;
		default:
			break;
		}

		i++;
		ptr++;
	} while (*ptr != 0);

	if (opp & OPP_100)
		*o = ABE_OPP100;
	else if (opp & OPP_50)
		*o = ABE_OPP50;
	else
		*o = ABE_OPP25;

	_lock_exit
}