/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }