コード例 #1
0
/**
 * omap_abe_init_ping_pong_buffer
 * @abe: Pointer on abe handle
 * @id: ABE port ID
 * @size_bytes:size of the ping pong
 * @n_buffers:number of buffers (2 = ping/pong)
 * @p:returned address of the ping-pong list of base addresses
 *	(byte offset from DMEM start)
 *
 * Computes the base address of the ping_pong buffers
 */
int omap_abe_init_ping_pong_buffer(struct omap_abe *abe,
				   u32 id, u32 size_bytes, u32 n_buffers,
				   u32 *p)
{
	u32 i, dmem_addr;

	_log(ABE_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 != OMAP_ABE_MM_DL_PORT || n_buffers > MAX_PINGPONG_BUFFERS) {
		omap_abe_dbg_error(abe, OMAP_ABE_ERR_API,
				   ABE_PARAMETER_ERROR);
	}
	for (i = 0; i < n_buffers; i++) {
		dmem_addr = OMAP_ABE_D_PING_ADDR + (i * size_bytes);
		/* base addresses of the ping pong buffers in U8 unit */
		abe_base_address_pingpong[i] = dmem_addr;
	}

	for (i = 0; i < 4; i++)
		abe->pp_buf_addr[i] = OMAP_ABE_D_PING_ADDR + (i * size_bytes);
	abe->pp_buf_id = 0;
	abe->pp_buf_id_next = 0;
	abe->pp_first_irq = 1;

	/* global data */
	abe_size_pingpong = size_bytes;
	*p = (u32) OMAP_ABE_D_PING_ADDR;
	return 0;
}
コード例 #2
0
/**
 * omap_abe_read_next_ping_pong_buffer
 * @abe: Pointer on abe handle
 * @port: ABE portID
 * @p: Next buffer address (pointer)
 * @n: Next buffer size (pointer)
 *
 * Tell the next base address of the next ping_pong Buffer and its size
 */
int omap_abe_read_next_ping_pong_buffer(struct omap_abe *abe, u32 port, u32 *p, u32 *n)
{
	u32 sio_pp_desc_address;
	struct ABE_SPingPongDescriptor desc_pp;

	_log(ABE_ID_READ_NEXT_PING_PONG_BUFFER, port, 0, 0);

	/* ping_pong is only supported on MM_DL */
	if (port != OMAP_ABE_MM_DL_PORT) {
		omap_abe_dbg_error(abe, OMAP_ABE_ERR_API,
				   ABE_PARAMETER_ERROR);
	}
	/* 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));
	if ((desc_pp.counter & 0x1) == 0) {
		_log(ABE_ID_READ_NEXT_PING_PONG_BUFFER, port, 0, 0);
		*p = desc_pp.nextbuff0_BaseAddr;
	} else {
		_log(ABE_ID_READ_NEXT_PING_PONG_BUFFER, port, 1, 0);
		*p = desc_pp.nextbuff1_BaseAddr;
	}
	/* translates the number of samples in bytes */
	*n = abe_size_pingpong;

	return 0;
}
コード例 #3
0
/**
 * abe_write_event_generator - Selects event generator source
 * @abe: Pointer on abe handle
 * @e: Event Generation Counter, McPDM, DMIC or default.
 *
 * Loads 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", then HAL decides 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%)
 */
int omap_abe_write_event_generator(struct omap_abe *abe, u32 e)
{
	u32 event, selection;
	u32 counter = EVENT_GENERATOR_COUNTER_DEFAULT;

	_log(ABE_ID_WRITE_EVENT_GENERATOR, e, 0, 0);

	switch (e) {
	case EVENT_TIMER:
		selection = EVENT_SOURCE_COUNTER;
		event = 0;
		break;
	case EVENT_44100:
		selection = EVENT_SOURCE_COUNTER;
		event = 0;
		counter = EVENT_GENERATOR_COUNTER_44100;
		break;
	default:
		omap_abe_dbg_error(abe, OMAP_ABE_ERR_API, ABE_BLOCK_COPY_ERR);
	}
	omap_abe_reg_writel(abe, EVENT_GENERATOR_COUNTER, counter);
	omap_abe_reg_writel(abe, EVENT_SOURCE_SELECTION, selection);
	omap_abe_reg_writel(abe, EVENT_GENERATOR_START, EVENT_GENERATOR_ON);
	omap_abe_reg_writel(abe, AUDIO_ENGINE_SCHEDULER, event);
	return 0;
}
コード例 #4
0
/**
 * omap_abe_read_offset_from_ping_buffer
 * @abe: Pointer on abe handle
 * @id: ABE port ID
 * @n:  returned address of the offset
 *	from the ping buffer start address (in samples)
 *
 * Computes the current firmware ping pong read pointer location,
 * expressed in samples, as the offset from the start address of ping buffer.
 */
int omap_abe_read_offset_from_ping_buffer(struct omap_abe *abe,
					  u32 id, u32 *n)
{
	u32 sio_pp_desc_address;
	struct ABE_SPingPongDescriptor desc_pp;

	/* 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);
	} else {
		/* read the port SIO ping pong descriptor */
		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));
		/* extract the current ping pong buffer read pointer based on
		   the value of the counter */
		if ((desc_pp.counter & 0x1) == 0) {
			/* the next is buffer0, hence the current is buffer1 */
			*n = desc_pp.nextbuff1_Samples -
				desc_pp.workbuff_Samples;
		} else {
			/* the next is buffer1, hence the current is buffer0 */
			*n = desc_pp.nextbuff0_Samples -
				desc_pp.workbuff_Samples;
		}
		switch (abe_port[OMAP_ABE_MM_DL_PORT].format.samp_format) {
		case MONO_MSB:
		case MONO_RSHIFTED_16:
		case STEREO_16_16:
			*n +=  abe->pp_buf_id * abe_size_pingpong / 4;
			break;
		case STEREO_MSB:
		case STEREO_RSHIFTED_16:
			*n += abe->pp_buf_id * abe_size_pingpong / 8;
			break;
		default:
			omap_abe_dbg_error(abe, OMAP_ABE_ERR_API,
					   ABE_PARAMETER_ERROR);
			return -EINVAL;
		}
	}

	return 0;
}
コード例 #5
0
/**
 * oamp_abe_set_ping_pong_buffer
 * @abe: Pointer on abe handle
 * @port: ABE port ID
 * @n_bytes: Size of Ping/Pong buffer
 *
 * 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.
 */
int omap_abe_set_ping_pong_buffer(struct omap_abe *abe, u32 port, u32 n_bytes)
{
	u32 sio_pp_desc_address, struct_offset, n_samples, datasize,
		base_and_size, *src;
	struct ABE_SPingPongDescriptor desc_pp;

	_log(ABE_ID_SET_PING_PONG_BUFFER, port, n_bytes, n_bytes >> 8);

	/* ping_pong is only supported on MM_DL */
	if (port != OMAP_ABE_MM_DL_PORT) {
		omap_abe_dbg_error(abe, OMAP_ABE_ERR_API,
				   ABE_PARAMETER_ERROR);
	}
	/* translates the number of bytes in samples */
	/* data size in DMEM words */
	datasize = omap_abe_dma_port_iter_factor((struct omap_abe_data_format *)&((abe_port[port]).format));
	/* data size in bytes */
	datasize = datasize << 2;
	n_samples = n_bytes / datasize;
	omap_abe_mem_read(abe, OMAP_ABE_DMEM, OMAP_ABE_D_PINGPONGDESC_ADDR,
			(u32 *) &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 = (u32) &(desc_pp.nextbuff0_BaseAddr) -
			(u32) &(desc_pp);
		base_and_size = desc_pp.nextbuff0_BaseAddr;
	} else {
		struct_offset = (u32) &(desc_pp.nextbuff1_BaseAddr) -
			(u32) &(desc_pp);
		base_and_size = desc_pp.nextbuff1_BaseAddr;
	}

	base_and_size = abe->pp_buf_addr[abe->pp_buf_id_next];
	abe->pp_buf_id_next = (abe->pp_buf_id_next + 1) & 0x03;

	base_and_size = (base_and_size & 0xFFFFL) + (n_samples << 16);
	sio_pp_desc_address = OMAP_ABE_D_PINGPONGDESC_ADDR + struct_offset;
	src = &base_and_size;
	omap_abe_mem_write(abe, OMAP_ABE_DMEM, sio_pp_desc_address,
			(u32 *) &base_and_size, sizeof(u32));

	return 0;
}