Commit 30c366fe authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

softpll: merged WRPC changes (mainly aux clock support)

parent 530698d0
......@@ -13,8 +13,8 @@
volatile int irq_count = 0;
static volatile struct SPLL_WB *SPLL = (volatile struct SPLL_WB *) BASE_SOFTPLL;
static volatile struct PPSG_WB *PPSG = (volatile struct PPSG_WB *) BASE_PPS_GEN;
static volatile struct SPLL_WB *SPLL;
static volatile struct PPSG_WB *PPSG;
/* The includes below contain code (not only declarations) to enable the compiler
to inline functions where necessary and save some CPU cycles */
......@@ -38,6 +38,16 @@ static volatile struct PPSG_WB *PPSG = (volatile struct PPSG_WB *) BASE_PPS_GEN;
#define SEQ_CLEAR_DACS 9
#define SEQ_WAIT_CLEAR_DACS 10
#define AUX_DISABLED 1
#define AUX_LOCK_PLL 2
#define AUX_ALIGN_PHASE 3
#define AUX_READY 4
struct spll_aux_state {
int state;
int32_t phase_target;
};
struct softpll_state {
int mode;
int seq_state;
......@@ -45,10 +55,13 @@ struct softpll_state {
int dac_timeout;
int default_dac_main;
int delock_count;
int32_t mpll_shift_ps;
struct spll_helper_state helper;
struct spll_external_state ext;
struct spll_main_state mpll;
struct spll_main_state aux[MAX_CHAN_AUX];
struct spll_aux_state aux_fsm[MAX_CHAN_AUX];
struct spll_ptracker_state ptrackers[MAX_PTRACKERS];
};
......@@ -80,11 +93,11 @@ void _irq_entry()
softpll.dac_timeout = timer_get_tics();
if(softpll.mode == SPLL_MODE_SLAVE)
spll_resync_dmtd_counter(softpll.mpll.id_ref);
break;
case SEQ_WAIT_CLEAR_DACS:
if(timer_get_tics() - softpll.dac_timeout > 10000)
if(timer_get_tics() - softpll.dac_timeout > TICS_PER_SECOND/20)
softpll.seq_state = (softpll.mode == SPLL_MODE_GRAND_MASTER ? SEQ_START_EXT : SEQ_START_HELPER);
break;
......@@ -143,15 +156,10 @@ void _irq_entry()
case SEQ_READY:
if(!softpll.helper.ld.locked)
{
// SPLL->OCER = 0;
// SPLL->RCER = 0;
softpll.seq_state = SEQ_CLEAR_DACS;
softpll.delock_count++;
} else if (softpll.mode == SPLL_MODE_GRAND_MASTER && !external_locked((struct spll_external_state *) &s->ext))
{
// SPLL->OCER = 0;
// SPLL->RCER = 0;
// SPLL->ECCR = 0;
softpll.seq_state = SEQ_START_EXT;
softpll.delock_count++;
} else if (softpll.mode == SPLL_MODE_SLAVE && !softpll.mpll.ld.locked)
......@@ -182,19 +190,17 @@ void _irq_entry()
if(softpll.mode == SPLL_MODE_GRAND_MASTER)
external_update((struct spll_external_state *) &s->ext, tag, src);
if(softpll.mode == SPLL_MODE_SLAVE)
{
mpll_update((struct spll_main_state *) &s->mpll, tag, src);
for(i=0;i<n_chan_out-1;i++)
mpll_update(&softpll.aux[i], tag, src);
}
for(i=0;i<n_chan_ref; i++)
if(ptracker_mask & (1<<i))
ptracker_update((struct spll_ptracker_state *) &s->ptrackers[i], tag, src);
break;
}
}
irq_count++;
......@@ -214,6 +220,9 @@ void spll_init(int mode, int slave_ref_channel, int align_pps)
volatile int dummy;
int i;
SPLL = (volatile struct SPLL_WB *) BASE_SOFTPLL;
PPSG = (volatile struct PPSG_WB *) BASE_PPS_GEN;
disable_irq();
n_chan_ref = SPLL_CSR_N_REF_R(SPLL->CSR);
......@@ -226,15 +235,14 @@ void spll_init(int mode, int slave_ref_channel, int align_pps)
SPLL->DAC_HPLL = 0;
SPLL->DAC_MAIN = 0;
//timer_delay(100000);
SPLL->CSR= 0 ;
SPLL->OCER = 0;
SPLL->RCER = 0;
SPLL->ECCR = 0;
SPLL->RCGER = 0;
SPLL->DCCR = 0;
SPLL->DEGLITCH_THR = 300;
SPLL->OCCR = 0;
SPLL->DEGLITCH_THR = 1000;
PPSG->ESCR = 0;
PPSG->CR = PPSG_CR_CNT_EN | PPSG_CR_CNT_RST | PPSG_CR_PWIDTH_W(100);
......@@ -257,7 +265,10 @@ void spll_init(int mode, int slave_ref_channel, int align_pps)
mpll_init(&softpll.mpll, slave_ref_channel, n_chan_ref);
for(i=0;i<n_chan_out-1;i++)
{
mpll_init(&softpll.aux[i], slave_ref_channel, n_chan_ref + i + 1);
softpll.aux_fsm[i].state = AUX_DISABLED;
}
break;
case SPLL_MODE_FREE_RUNNING_MASTER:
......@@ -265,12 +276,15 @@ void spll_init(int mode, int slave_ref_channel, int align_pps)
softpll.seq_state = SEQ_CLEAR_DACS;
softpll.default_dac_main = 32000;
helper_init(&softpll.helper, n_chan_ref);
helper_init(&softpll.helper, n_chan_ref + slave_ref_channel);
mpll_init(&softpll.mpll, slave_ref_channel, n_chan_ref);
for(i=0;i<n_chan_out-1;i++)
{
mpll_init(&softpll.aux[i], slave_ref_channel, n_chan_ref + i + 1);
softpll.aux_fsm[i].state = AUX_DISABLED;
}
PPSG->ESCR = PPSG_ESCR_PPS_VALID | PPSG_ESCR_TM_VALID;
break;
......@@ -286,7 +300,11 @@ void spll_init(int mode, int slave_ref_channel, int align_pps)
mpll_init(&softpll.mpll, slave_ref_channel, n_chan_ref);
for(i=0;i<n_chan_out-1;i++)
{
mpll_init(&softpll.aux[i], slave_ref_channel, n_chan_ref + i + 1);
softpll.aux_fsm[i].state = AUX_DISABLED;
}
// PPSG->ESCR = PPSG_ESCR_PPS_VALID | PPSG_ESCR_TM_VALID;
......@@ -304,9 +322,7 @@ void spll_init(int mode, int slave_ref_channel, int align_pps)
dummy = SPLL->PER_HPLL;
SPLL->EIC_IER = 1;
SPLL->OCER = 1;
// _irq_entry();
SPLL->OCER |= 1;
enable_irq();
......@@ -335,8 +351,10 @@ void spll_shutdown()
void spll_start_channel(int channel)
{
if (softpll.seq_state != SEQ_READY || !channel)
{
TRACE("Can't start channel %d, the PLL is not ready\n", channel);
return;
}
mpll_start(&softpll.aux[channel-1]);
}
......@@ -367,17 +385,33 @@ static int32_t to_picos(int32_t units)
}
/* Channel 0 = local PLL reference, 1...N = aux oscillators */
void spll_set_phase_shift(int channel, int32_t value_picoseconds)
static void set_phase_shift(int channel, int32_t value_picoseconds)
{
volatile struct spll_main_state *st = (!channel ? &softpll.mpll : &softpll.aux[channel-1]);
mpll_set_phase_shift(st, from_picos(value_picoseconds));
int div = (DIVIDE_DMTD_CLOCKS_BY_2 ? 2: 1);
mpll_set_phase_shift(st, from_picos(value_picoseconds) / div);
softpll.mpll_shift_ps = value_picoseconds;
}
void spll_set_phase_shift(int channel, int32_t value_picoseconds)
{
int i;
if(channel == SPLL_ALL_CHANNELS)
{
spll_set_phase_shift(0, value_picoseconds);
for(i=0;i<n_chan_out-1;i++)
if(softpll.aux_fsm[i].state == AUX_READY)
set_phase_shift(i+1, value_picoseconds);
} else
set_phase_shift(channel, value_picoseconds);
}
void spll_get_phase_shift(int channel, int32_t *current, int32_t *target)
{
volatile struct spll_main_state *st = (!channel ? &softpll.mpll : &softpll.aux[channel-1]);
if(current) *current = to_picos(st->phase_shift_current);
if(target) *target = to_picos(st->phase_shift_target);
int div = (DIVIDE_DMTD_CLOCKS_BY_2 ? 2: 1);
if(current) *current = to_picos(st->phase_shift_current * div);
if(target) *target = to_picos(st->phase_shift_target * div);
}
int spll_read_ptracker(int channel, int32_t *phase_ps, int *enabled)
......@@ -387,6 +421,12 @@ int spll_read_ptracker(int channel, int32_t *phase_ps, int *enabled)
if(phase < 0) phase += (1<<HPLL_N);
else if (phase >= (1<<HPLL_N)) phase -= (1<<HPLL_N);
if(DIVIDE_DMTD_CLOCKS_BY_2)
{
phase <<= 1;
phase &= (1<<HPLL_N)-1;
}
*phase_ps = to_picos(phase);
if(enabled)
*enabled = ptracker_mask & (1<<st->id_b) ? 1 : 0;
......@@ -433,8 +473,108 @@ void spll_enable_ptracker(int ref_channel, int enable)
}
}
int spll_get_delock_count()
{
return softpll.delock_count;
}
int spll_update_aux_clocks()
{
uint32_t occr_aux_en = SPLL_OCCR_OUT_EN_R(SPLL->OCCR);
int i;
for(i=0;i<n_chan_out-1;i++)
{
struct spll_aux_state *s = &softpll.aux_fsm[i];
if((! (occr_aux_en & (1<<(i+1))) && s->state != AUX_DISABLED))
{
TRACE("[aux] disabled channel %d\n", i);
spll_stop_channel(i+1);
SPLL->OCCR &= ~ (SPLL_OCCR_OUT_LOCK_W((1<<(i+1))));
s->state = AUX_DISABLED;
} else switch(s->state)
{
case AUX_DISABLED:
if(occr_aux_en & (1<<(i+1)) && softpll.mpll.ld.locked)
{
TRACE("[aux] enabled channel %d\n", i);
s->state = AUX_LOCK_PLL;
spll_start_channel(i+1);
}
break;
case AUX_LOCK_PLL:
if(softpll.aux[i].ld.locked)
{
TRACE("[aux] channel %d locked [aligning @ %d ps]\n", i, softpll.mpll_shift_ps);
set_phase_shift(i+1, softpll.mpll_shift_ps);
s->state = AUX_ALIGN_PHASE;
}
break;
case AUX_ALIGN_PHASE:
if(!mpll_shifter_busy(&softpll.aux[i]))
{
TRACE("[aux] channel %d phase aligned\n", i);
SPLL->OCCR |= SPLL_OCCR_OUT_LOCK_W((1<<(i+1)));
s->state = AUX_READY;
}
break;
case AUX_READY:
if(!softpll.mpll.ld.locked || !softpll.aux[i].ld.locked)
{
TRACE("[aux] aux channel or mpll lost lock\n");
SPLL->OCCR &= ~ (SPLL_OCCR_OUT_LOCK_W((1<<(i+1))));
s->state = AUX_DISABLED;
}
break;
}
}
}
int spll_get_aux_status(int channel)
{
int rval = 0;
if(softpll.aux_fsm[channel].state != AUX_DISABLED)
rval |= SPLL_AUX_ENABLED;
if(softpll.aux_fsm[channel].state == AUX_READY)
rval |= SPLL_AUX_LOCKED;
return rval;
}
int spll_get_dac(int index)
{
if(index < 0)
return softpll.helper.pi.y;
else if (index == 0)
return softpll.mpll.pi.y;
else if (index > 0)
return softpll.aux[index-1].pi.y;
return 0;
}
void spll_set_dac(int index, int value)
{
if(index < 0)
{
softpll.helper.pi.y = value;
SPLL->DAC_HPLL = value;
}
else {
SPLL->DAC_MAIN = SPLL_DAC_MAIN_DAC_SEL_W(index) | (value & 0xffff);
if (index == 0)
softpll.mpll.pi.y = value;
else if (index > 0)
softpll.aux[index-1].pi.y = value;
}
}
......@@ -10,6 +10,10 @@
#define SPLL_MODE_SLAVE 3
#define SPLL_MODE_DISABLED 4
#define SPLL_ALL_CHANNELS 0xffff
#define SPLL_AUX_ENABLED (1<<0)
#define SPLL_AUX_LOCKED (1<<1)
void spll_init(int mode, int slave_ref_channel, int align_pps);
void spll_shutdown();
......@@ -22,6 +26,12 @@ int spll_read_ptracker(int channel, int32_t *phase_ps, int *enabled);
void spll_get_num_channels(int *n_ref, int *n_out);
int spll_shifter_busy(int channel);
int spll_get_delock_count();
int spll_update_aux_clocks();
int spll_get_aux_status(int channel);
void spll_set_dac(int index, int value);
int spll_get_dac(int index);
#endif
......@@ -166,7 +166,7 @@ static void spll_enable_tagger(int channel, int enable)
SPLL->RCER &= ~ (1<<channel);
}
TRACE("%s: ch %d, OCER 0x%x, RCER 0x%x\n", __FUNCTION__, channel, SPLL->OCER, SPLL->RCER);
// TRACE("%s: ch %d, OCER 0x%x, RCER 0x%x\n", __FUNCTION__, channel, SPLL->OCER, SPLL->RCER);
}
static void spll_resync_dmtd_counter(int channel)
......
......@@ -15,6 +15,11 @@ WARNING: These parameters must be in sync with the generics of the HDL instantia
/* Reference clock period, in picoseconds */
#define CLOCK_PERIOD_PICOSECONDS 16000
/* optional DMTD clock division to improve FPGA timing closure by avoiding
clock nets directly driving FD inputs. Must be consistent with the
g_divide_inputs_by_2 generic. */
#define DIVIDE_DMTD_CLOCKS_BY_2 0
/* Number of bits in phase tags generated by the DMTDs. Used to sign-extend the tags.
Corresponding VHDL generic: g_tag_bits. */
#define TAG_BITS 22
......
......@@ -6,7 +6,6 @@
#define MATCH_WAIT_OUT 2
#undef WITH_SEQUENCING
//#define WITH_SEQUENCING
/* State of the Main PLL */
struct spll_main_state {
......@@ -16,7 +15,6 @@ struct spll_main_state {
spll_lock_det_t ld;
int adder_ref, adder_out, tag_ref, tag_out, tag_ref_d, tag_out_d;
int err_d0, err_d1;
// tag sequencing stuff
uint32_t seq_ref, seq_out;
......@@ -28,6 +26,7 @@ struct spll_main_state {
int id_ref, id_out; /* IDs of the reference and the output channel */
int sample_n;
int delock_count;
int dac_index;
};
......@@ -48,6 +47,7 @@ static void mpll_init(struct spll_main_state *s, int id_ref, int id_out)
s->ld.delock_samples = 100;
s->id_ref = id_ref;
s->id_out = id_out;
s->dac_index = id_out - n_chan_ref;
pi_init(&s->pi);
ld_init(&s->ld);
......@@ -63,7 +63,7 @@ static void mpll_start(struct spll_main_state *s)
s->seq_ref = 0;
s->seq_out = 0;
s->match_state = MATCH_NEXT_TAG;
s->err_d0 = s->err_d1 = 0;
s->phase_shift_target = 0;
s->phase_shift_current = 0;
s->sample_n= 0;
......@@ -155,15 +155,6 @@ static int mpll_update(struct spll_main_state *s, int tag, int source)
#ifndef WITH_SEQUENCING
/* if(s->err_d0 - s->err_d1 > -(1<<HPLL_N)/2 && err - s->err_d0 < -(1<<HPLL_N)/2 )
err += (1<<HPLL_N);
if(s->err_d0 - s->err_d1 < (1<<HPLL_N)/2 && err - s->err_d0 > (1<<HPLL_N)/2 )
err -= (1<<HPLL_N);
s->err_d1 = s->err_d0;
s->err_d0 = err;*/
/* Hack: the PLL is locked, so the tags are close to each other. But when we start phase shifting, after reaching
full clock period, one of the reference tags will flip before the other, causing a suddent 2**HPLL_N jump in the error.
So, once the PLL is locked, we just mask out everything above 2**HPLL_N.
......@@ -180,13 +171,13 @@ static int mpll_update(struct spll_main_state *s, int tag, int source)
#endif
y = pi_update(&s->pi, err);
SPLL->DAC_MAIN = SPLL_DAC_MAIN_VALUE_W(y) | SPLL_DAC_MAIN_DAC_SEL_W(s->id_out);
SPLL->DAC_MAIN = SPLL_DAC_MAIN_VALUE_W(y) | SPLL_DAC_MAIN_DAC_SEL_W(s->dac_index);
spll_debug(DBG_MAIN | DBG_REF, s->tag_ref + s->adder_ref, 0);
spll_debug(DBG_MAIN | DBG_TAG, s->tag_out + s->adder_out, 0);
spll_debug(DBG_MAIN | DBG_ERR, err, 0);
spll_debug(DBG_MAIN | DBG_SAMPLE_ID, s->sample_n++, 1);
// spll_debug(DBG_MAIN | DBG_Y, y, 1);
spll_debug(DBG_MAIN | DBG_SAMPLE_ID, s->sample_n++, 0);
spll_debug(DBG_MAIN | DBG_Y, y, 1);
s->tag_out = -1;
s->tag_ref = -1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment