forked from PAWPAW-Mirror/lib_xua
Fix lockup in aud->clkgen notification
This commit is contained in:
@@ -804,6 +804,7 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
|
||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
/* Notify clockgen of new mCLk */
|
||||
c_mclk_change <: mClk;
|
||||
c_mclk_change <: curFreq;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "xua_commands.h"
|
||||
#include "xua_clocking.h"
|
||||
|
||||
#include <stdio.h> // TODO DEV ONLY - DELME
|
||||
|
||||
#ifdef __XS3A__
|
||||
#define USE_SW_PLL 1
|
||||
@@ -231,7 +232,7 @@ static inline int validSamples(Counter &counter, int clockIndex)
|
||||
#endif
|
||||
|
||||
#if USE_SW_PLL
|
||||
void InitSWPLL(sw_pll_state_t &sw_pll, unsigned mClk)
|
||||
unsigned InitSWPLL(sw_pll_state_t &sw_pll, unsigned mClk)
|
||||
{
|
||||
/* Autogenerated SDM App PLL setup by dco_model.py using 22.5792_1M profile */
|
||||
/* Input freq: 24000000
|
||||
@@ -270,7 +271,7 @@ void InitSWPLL(sw_pll_state_t &sw_pll, unsigned mClk)
|
||||
const uint32_t app_pll_div_reg[2] = {APP_PLL_DIV_REG_22, APP_PLL_DIV_REG_24};
|
||||
const uint32_t app_pll_frac_reg[2] = {APP_PLL_FRAC_REG_22, APP_PLL_FRAC_REG_24};
|
||||
const uint32_t sw_pll_sdm_ctrl_mid[2] = {SW_PLL_SDM_CTRL_MID_22, SW_PLL_SDM_CTRL_MID_24};
|
||||
// const uint32_t sw_pll_sdm_rate[2] = {SW_PLL_SDM_RATE_22, SW_PLL_SDM_RATE_24};
|
||||
const uint32_t sw_pll_sdm_rate[2] = {SW_PLL_SDM_RATE_22, SW_PLL_SDM_RATE_24};
|
||||
|
||||
const int clkIndex = mClk == MCLK_48 ? 1 : 0;
|
||||
|
||||
@@ -289,38 +290,102 @@ void InitSWPLL(sw_pll_state_t &sw_pll, unsigned mClk)
|
||||
|
||||
|
||||
printstr("Init sw_pll: "); printuintln(mClk);
|
||||
|
||||
return (XS1_TIMER_HZ / sw_pll_sdm_rate[clkIndex]);
|
||||
}
|
||||
|
||||
void do_sw_pll_control(sw_pll_state_t sw_pll, unsigned short mclk_time_stamp, chanend c_sigma_delta)
|
||||
void do_sw_pll_control( sw_pll_state_t sw_pll,
|
||||
unsigned short mclk_time_stamp,
|
||||
unsigned mclks_per_sample,
|
||||
chanend c_sigma_delta,
|
||||
int receivedSamples)
|
||||
{
|
||||
static unsigned short last_mclk_time_stamp = 0;
|
||||
static unsigned count = 0;
|
||||
count++;
|
||||
|
||||
const unsigned expected_mclk_inc = mclks_per_sample * receivedSamples;
|
||||
const unsigned short expected_mclk_count = (last_mclk_time_stamp + expected_mclk_inc) & 0xffff;
|
||||
|
||||
short f_error = (int)mclk_time_stamp - (int)expected_mclk_count;
|
||||
|
||||
|
||||
if(count == 30)
|
||||
{
|
||||
printuintln(mclk_time_stamp);
|
||||
count = 0;
|
||||
//calc mclk inc
|
||||
|
||||
outuint(c_sigma_delta, (unsigned) (1000000 + f_error));
|
||||
count = 0;
|
||||
}
|
||||
|
||||
last_mclk_time_stamp = mclk_time_stamp;
|
||||
}
|
||||
|
||||
void SigmaDeltaTask(chanend c_sigma_delta){
|
||||
void SigmaDeltaTask(chanend c_sigma_delta, unsigned sdm_interval){
|
||||
/* Zero is an invalid number and the SDM will not write the frac reg until
|
||||
the first control value has been received. This avoids issues with
|
||||
channel lockup if two tasks (eg. init and SDM) try to write at the same time. */
|
||||
|
||||
int dco_setting = 0;
|
||||
sw_pll_sdm_state_t sdm_state;
|
||||
sw_pll_init_sigma_delta(&sdm_state);
|
||||
|
||||
tileref_t this_tile = get_local_tile_id();
|
||||
|
||||
timer tmr;
|
||||
int32_t time_trigger;
|
||||
tmr :> time_trigger;
|
||||
int send_ack_once = 1;
|
||||
|
||||
while(1)
|
||||
{
|
||||
c_sigma_delta :> dco_setting;
|
||||
printstr("sigma-delta got: "); printintln(dco_setting);
|
||||
if(dco_setting == 0)
|
||||
/* Poll for new SDM control value */
|
||||
unsigned tmp;
|
||||
select
|
||||
{
|
||||
c_sigma_delta <: 0; /* Send ACK */
|
||||
case inuint_byref(c_sigma_delta, tmp):
|
||||
dco_setting = (int32_t)tmp;
|
||||
printstr("sigma-delta got: "); printintln(dco_setting);
|
||||
break;
|
||||
|
||||
// Do nothing & fall-through
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Wait until the timer value has been reached
|
||||
This implements a timing barrier and keeps
|
||||
the loop rate constant. */
|
||||
select
|
||||
{
|
||||
case tmr when timerafter(time_trigger) :> int _:
|
||||
time_trigger += sdm_interval;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Do not write to the frac reg until we get out first
|
||||
control value. This will avoid the writing of the
|
||||
frac reg from two different threads which may cause
|
||||
a channel deadlock. */
|
||||
if(dco_setting != 0)
|
||||
{
|
||||
sw_pll_do_sigma_delta(&sdm_state, this_tile, dco_setting);
|
||||
send_ack_once = 1;
|
||||
}
|
||||
else if(send_ack_once)
|
||||
{
|
||||
/* Send ACK once to synchrnoise with clockgen signalling it's OK to reconfig */
|
||||
outuint(c_sigma_delta, 0); /* Send ACK to say reg writes have ceased */
|
||||
send_ack_once = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void disable_sigma_delta(chanend c_sigma_delta)
|
||||
{
|
||||
c_sigma_delta <: 0; /* Stops SD */
|
||||
c_sigma_delta :> int _; /* Wait for ACK so we know reg write is complete */
|
||||
outuint(c_sigma_delta, 0); /* Stops SD */
|
||||
inuint(c_sigma_delta); /* Wait for ACK so we know reg write is complete */
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -360,6 +425,8 @@ void clockGen ( streaming chanend ?c_spdif_rx,
|
||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
timer t_external;
|
||||
unsigned selected_mclk_rate = 0;
|
||||
unsigned selected_sample_rate = 0;
|
||||
unsigned mclks_per_sample = 0;
|
||||
unsigned short mclk_time_stamp = 0;
|
||||
/* Get MCLK count */
|
||||
asm volatile(" getts %0, res[%1]" : "=r" (mclk_time_stamp) : "r" (p_for_mclk_count_aud));
|
||||
@@ -457,11 +524,11 @@ void clockGen ( streaming chanend ?c_spdif_rx,
|
||||
#if USE_SW_PLL
|
||||
chan c_sigma_delta;
|
||||
sw_pll_state_t sw_pll;
|
||||
InitSWPLL(sw_pll, MCLK_48);
|
||||
unsigned sdm_interval = InitSWPLL(sw_pll, MCLK_48);
|
||||
|
||||
par
|
||||
{
|
||||
SigmaDeltaTask(c_sigma_delta);
|
||||
SigmaDeltaTask(c_sigma_delta, sdm_interval);
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
@@ -635,10 +702,14 @@ void clockGen ( streaming chanend ?c_spdif_rx,
|
||||
|
||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||
case c_mclk_change :> selected_mclk_rate:
|
||||
c_mclk_change :> selected_sample_rate;
|
||||
mclks_per_sample = selected_mclk_rate / selected_sample_rate;
|
||||
#if USE_SW_PLL
|
||||
printstr("c_mclk_change: "); printuintln(selected_mclk_rate);
|
||||
disable_sigma_delta(c_sigma_delta); /* Blocks until SD is idle */
|
||||
disable_sigma_delta(c_sigma_delta); /* Blocks until SDM is idle */
|
||||
InitSWPLL(sw_pll, selected_mclk_rate);
|
||||
outuint(c_sigma_delta, sw_pll.sdm_state.ctrl_mid_point); /* Send ctrl mid point to enable SDM */
|
||||
printstr("swpll int'd\n");
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
@@ -684,12 +755,14 @@ void clockGen ( streaming chanend ?c_spdif_rx,
|
||||
if(spdifSamps > MAX_SPDIF_SAMPLES-1)
|
||||
{
|
||||
spdifOverflow = 1;
|
||||
printstr("spo+\n"); // DELME
|
||||
}
|
||||
|
||||
/* Check for coming out of under flow */
|
||||
if(spdifUnderflow && (spdifSamps >= (MAX_SPDIF_SAMPLES >> 1)))
|
||||
{
|
||||
spdifUnderflow = 0;
|
||||
printstr("spu-\n"); // DELME
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -719,7 +792,7 @@ void clockGen ( streaming chanend ?c_spdif_rx,
|
||||
timeNextEdge = spdifRxTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN;
|
||||
|
||||
#if USE_SW_PLL
|
||||
do_sw_pll_control(sw_pll, mclk_time_stamp, c_sigma_delta);
|
||||
do_sw_pll_control(sw_pll, mclk_time_stamp, mclks_per_sample, c_sigma_delta, spdifCounters.receivedSamples);
|
||||
#else
|
||||
/* Toggle edge */
|
||||
i_pll_ref.toggle_timed(1);
|
||||
@@ -829,7 +902,7 @@ void clockGen ( streaming chanend ?c_spdif_rx,
|
||||
timeNextEdge = adatReceivedTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN;
|
||||
|
||||
#if USE_SW_PLL
|
||||
do_sw_pll_control(sw_pll, mclk_time_stamp, c_sigma_delta);
|
||||
do_sw_pll_control(sw_pll, mclk_time_stamp, mclks_per_sample, c_sigma_delta, adatCounters.receivedSamples);
|
||||
#else
|
||||
/* Toggle edge */
|
||||
i_pll_ref.toggle_timed(1);
|
||||
@@ -876,6 +949,7 @@ void clockGen ( streaming chanend ?c_spdif_rx,
|
||||
{
|
||||
/* We're out of S/PDIF samples, mark underflow condition */
|
||||
spdifUnderflow = 1;
|
||||
printstr("spu-\n"); // DELME
|
||||
spdifLeft = 0;
|
||||
}
|
||||
|
||||
@@ -884,6 +958,7 @@ void clockGen ( streaming chanend ?c_spdif_rx,
|
||||
if(spdifOverflow && (spdifSamps < (MAX_SPDIF_SAMPLES>>1)))
|
||||
{
|
||||
spdifOverflow = 0;
|
||||
printstr("spo-\n"); // DELME
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user