From f63edb52ef8ecf18520926b40b3c61db37081a9d Mon Sep 17 00:00:00 2001 From: Aidan MacDonald Date: Sun, 30 May 2021 19:56:44 +0100 Subject: x1000: refactor AIC initialization Have pcm-x1000 handle most work, so target's audiohw code touches only the relevant settings. Change-Id: Icf3d1b7ca428ac50a5a16ecec39ed8186ac5ae13 --- firmware/target/mips/ingenic_x1000/aic-x1000.h | 130 ++++++++++++++++++++++--- 1 file changed, 114 insertions(+), 16 deletions(-) (limited to 'firmware/target/mips/ingenic_x1000/aic-x1000.h') diff --git a/firmware/target/mips/ingenic_x1000/aic-x1000.h b/firmware/target/mips/ingenic_x1000/aic-x1000.h index eda0f80f04..f272655b9c 100644 --- a/firmware/target/mips/ingenic_x1000/aic-x1000.h +++ b/firmware/target/mips/ingenic_x1000/aic-x1000.h @@ -23,24 +23,122 @@ #define __AIC_X1000_H__ #include "clk-x1000.h" +#include "x1000/aic.h" #include +#include -/* Set frequency of I2S master clock supplied by AIC. Has no use if an - * external DAC is supplying the master clock. Must be called with the - * bit clock disabled. - * - * - clksrc can be one of EXCLK, SCLK_A, MPLL. - * - This function does not modify PLL settings. It's the caller's job - * to ensure the PLL is configured and runing. - * - fs is the audio sampling frequency (8 KHz - 192 KHz) - * - mult is multiplied by fs to get the master clock rate. - * - mult must be a multiple of 64 due to AIC bit clock requirements. - * - Note: EXCLK bypasses the decimal divider so it is not very flexible. - * If using EXCLK you must set mult=0. If EXCLK is not a multiple of - * the bit clock (= 64*fs), then the clock rate will be inaccurate. - * - * Returns zero on success and nonzero if the frequency is not achievable. +#define AIC_I2S_MASTER_MODE 0 +#define AIC_I2S_MASTER_EXCLK_MODE 1 +#define AIC_I2S_SLAVE_MODE 2 + +#define AIC_I2S_LEFT_CHANNEL_FIRST 0 +#define AIC_I2S_RIGHT_CHANNEL_FIRST 1 + +/* Nb. the functions below are intended to serve as "documentation" and make + * target audiohw code clearer, they should normally be called with immediate + * constant arguments so they are inlined to a register read-modify-write. */ + +/* Enable/disable some kind of big-endian mode. Presumably it refers to + * the endianness of the samples read or written to the FIFO. */ +static inline void aic_set_big_endian_format(bool en) +{ + jz_writef(AIC_CFG, MSB(en ? 1 : 0)); +} + +/* Set whether to send the last sample (true) or a zero sample (false) + * if the AIC FIFO underflows during playback. */ +static inline void aic_set_play_last_sample(bool en) +{ + jz_writef(AIC_CFG, LSMP(en ? 1 : 0)); +} + +/* Select the use of the internal or external codec. */ +static inline void aic_set_external_codec(bool en) +{ + jz_writef(AIC_CFG, ICDC(en ? 0 : 1)); +} + +/* Set I2S interface mode */ +static inline void aic_set_i2s_mode(int mode) +{ + switch(mode) { + default: + case AIC_I2S_MASTER_MODE: + jz_writef(AIC_CFG, BCKD(1), SYNCD(1)); + break; + + case AIC_I2S_MASTER_EXCLK_MODE: + jz_writef(AIC_CFG, BCKD(0), SYNCD(1)); + break; + + case AIC_I2S_SLAVE_MODE: + jz_writef(AIC_CFG, BCKD(0), SYNCD(0)); + break; + } +} + +/* Select the channel ordering on the I2S interface (playback only). */ +static inline void aic_set_i2s_channel_order(int order) +{ + switch(order) { + default: + case AIC_I2S_LEFT_CHANNEL_FIRST: + jz_writef(AIC_I2SCR, RFIRST(0)); + break; + + case AIC_I2S_RIGHT_CHANNEL_FIRST: + jz_writef(AIC_I2SCR, RFIRST(1)); + break; + } +} + +/* Enable/disable the I2S master clock (also called 'system clock') */ +static inline void aic_enable_i2s_master_clock(bool en) +{ + jz_writef(AIC_I2SCR, ESCLK(en ? 1 : 0)); +} + +/* Enable/disable the I2S bit clock */ +static inline void aic_enable_i2s_bit_clock(bool en) +{ + jz_writef(AIC_I2SCR, STPBK(en ? 0 : 1)); +} + +/* Select whether I2S mode is used (false) or MSB-justified mode (true). */ +static inline void aic_set_msb_justified_mode(bool en) +{ + jz_writef(AIC_I2SCR, AMSL(en ? 1 : 0)); +} + +/* Calculate frequency of I2S clocks. + * + * - 'clksrc' can be one of EXCLK, SCLK_A, or MPLL. + * - 'fs' is the audio sampling frequency in Hz, must be 8 KHz - 192 KHz. + * - The master clock frequency equals 'mult * fs' Hz. Due to hardware + * restrictions, 'mult' must be divisible by 64. + * + * - NOTE: When using EXCLK source, the master clock equals EXCLK and the + * 'mult' parameter is ignored. + * + * This function returns the actual bit clock rate which would be achieved. + * (Note the bit clock is always 64x the effective sampling rate.) + * + * If the exact rate cannot be attained, then this will return the closest + * possible rate to the desired rate. In case of invalid parameters, this + * function will return zero. That also occurs if the chosen PLL is stopped. + */ +extern uint32_t aic_calc_i2s_clock(x1000_clk_t clksrc, + uint32_t fs, uint32_t mult); + +/* Set the I2S clock frequency. + * + * Parameters are the same as 'aic_calc_i2s_clock()' except this function + * will set the clocks. If the bit clock is running, it will be automatically + * stopped and restarted properly. + * + * Returns zero on success. If an invalid state occurs (due to bad settings) + * then this function will do nothing and return a nonzero value. */ -extern int aic_i2s_set_mclk(x1000_clk_t clksrc, unsigned fs, unsigned mult); +extern int aic_set_i2s_clock(x1000_clk_t clksrc, uint32_t fs, uint32_t mult); #endif /* __AIC_X1000_H__ */ -- cgit v1.2.3