Commit f3182b48 authored by Alessandro Rubini's avatar Alessandro Rubini

userspace/libswitchhw from svn 1116

parent 8f856722
include ../../Makedefs
CC=$(CROSS_COMPILE_ARM)gcc
AR=$(CROSS_COMPILE_ARM)ar
OBJS = pio.o pio_pins.o trace.o init.o fpga_io.o util.o ad9516.o fpgaboot.o minilzo/minilzo.o clkb_io.o xpoint.o hpll.o mblaster.o phy_calibration.o dmpll.o pps_gen.o watchdog.o
CFLAGS = -I. -O2 -I../include -I../include -DDEBUG -I./minilzo
OUTPUT = libswitchhw.a
all: $(OBJS)
${AR} rc $(OUTPUT) $(OBJS)
%.o: %.c
${CC} -c $^ $(CFLAGS) -o $@
install:all
scp $(OUTPUT) root@192.168.1.2:/root
clean:
rm -f $(OUTPUT) $(OBJS)
deploy:
\ No newline at end of file
#include <math.h>
#include <hw/pio.h>
#include <hw/trace.h>
#include <hw/ad9516.h>
#define SPI_DELAY 50
#define AD9516_OP_READ 0x80
#define AD9516_OP_WRITE 0x00
#define AD9516_MAX_REGS 1024
struct ad9516_regs {
struct {
uint16_t addr;
uint8_t value;
} regs[AD9516_MAX_REGS];
int nregs;
};
int shw_ad9516_set_output_delay(int output, float delay_ns, int bypass);
#include "ad9516_default_regs.h"
static int use_ext_ref = 0;
int shw_use_external_reference(int enable)
{
if(enable)
TRACE(TRACE_INFO, "Using external 10 MHz reference clock (grandmaster mode)");
use_ext_ref = enable;
}
static uint8_t ad9516_spi_read8()
{
uint8_t rx = 0;
int i;
shw_pio_setdir(PIN_ad9516_sdio, PIO_IN);
shw_pio_set0(PIN_ad9516_sclk);
for(i = 0; i < 8;i++)
{
shw_udelay(SPI_DELAY);
rx <<= 1;
if (shw_pio_get(PIN_ad9516_sdio))
rx |= 1;
shw_udelay(SPI_DELAY);
shw_pio_set1(PIN_ad9516_sclk);
shw_udelay(SPI_DELAY);
shw_pio_set0(PIN_ad9516_sclk);
}
shw_udelay(SPI_DELAY);
return rx;
}
static uint8_t ad9516_spi_write8(uint8_t tx)
{
int i;
shw_pio_setdir(PIN_ad9516_sdio, PIO_OUT);
shw_pio_set0(PIN_ad9516_sclk);
for(i = 0; i < 8;i++)
{
shw_udelay(SPI_DELAY);
shw_pio_set(PIN_ad9516_sdio, tx & 0x80);
tx<<=1;
shw_udelay(SPI_DELAY);
shw_pio_set1(PIN_ad9516_sclk);
shw_udelay(SPI_DELAY);
shw_pio_set0(PIN_ad9516_sclk);
}
shw_udelay(SPI_DELAY);
}
static uint8_t ad9516_read_reg(uint16_t addr)
{
uint8_t val;
shw_pio_set0(PIN_ad9516_cs);
shw_udelay(SPI_DELAY);
ad9516_spi_write8(AD9516_OP_READ | (addr >> 8));
ad9516_spi_write8(addr & 0xff);
val = ad9516_spi_read8();
shw_udelay(SPI_DELAY);
shw_pio_set1(PIN_ad9516_cs);
shw_udelay(SPI_DELAY);
return val;
}
static void ad9516_write_reg(uint16_t addr, uint8_t data)
{
shw_pio_set0(PIN_ad9516_cs);
shw_udelay(SPI_DELAY);
ad9516_spi_write8(AD9516_OP_WRITE | (addr >> 8));
ad9516_spi_write8(addr & 0xff);
ad9516_spi_write8(data);
shw_udelay(SPI_DELAY);
shw_pio_set1(PIN_ad9516_cs);
shw_udelay(SPI_DELAY);
}
static void ad9516_reset()
{
shw_pio_set0(PIN_ad9516_nrst); // reset the PLL
shw_udelay(100);
shw_pio_set1(PIN_ad9516_nrst); // un-reset the PLL
shw_udelay(100);
}
int ad9516_detect_external_ref()
{
ad9516_write_reg(0x4, 0x1); // readback active regs
ad9516_write_reg(0x1c, 0x06); // enable ref1/reg2
ad9516_write_reg(0x1b, 0xe0); // enable refin monitor
ad9516_write_reg(0x232, 1); // commit
usleep(200000);
return ad9516_read_reg(0x1f) ;
}
static int ad9516_load_regs_from_file(const char *filename, struct ad9516_regs *regs)
{
FILE *f;
char str[1024], tmp[100];
int start_read = 0, n = 0;
uint32_t addr, val;
f = fopen(filename ,"rb");
if(!f)
{
TRACE(TRACE_ERROR, "can't open AD9516 regset file: %s", filename);
return -1;
}
while(!feof(f))
{
fgets(str, 1024, f);
if(!strncmp(str, "Addr(Hex)", 8)) start_read = 1;
if(start_read)
{
if( sscanf(str, "%04x %08s %02x\n", &addr, tmp, &val) == 3)
{
//TRACE(TRACE_INFO, " -> ad9516_reg[0x%x]=0x%x", addr, val);
regs->regs[n].addr = addr;
regs->regs[n].value = val;
n++;
}
}
}
regs->nregs = n;
fclose(f);
return start_read == 1 ? 0 : -1;
}
static int ad9516_load_state(const struct ad9516_regs *regs)
{
int i;
TRACE(TRACE_INFO, "Loading AD9516 state (%d registers)", regs->nregs);
for(i=0;i<regs->nregs;i++)
ad9516_write_reg(regs->regs[i].addr, regs->regs[i].value);
ad9516_write_reg(AD9516_UPDATE_ALL, 1); // acknowledge register update
return 0;
}
static int ad9516_check_lock()
{
uint8_t pll_readback = ad9516_read_reg(AD9516_PLLREADBACK);
return pll_readback & 1;
}
static void ad9516_power_down()
{
}
#define assert_init(proc) { int ret; if((ret = proc) < 0) return ret; }
int shw_ad9516_init()
{
int retries = 100;
TRACE(TRACE_INFO, "Initializing AD9516 PLL....");
shw_pio_configure(PIN_ad9516_cs);
shw_pio_configure(PIN_ad9516_nrst);
shw_pio_configure(PIN_ad9516_refsel);
shw_pio_configure(PIN_ad9516_sclk);
shw_pio_configure(PIN_ad9516_sdio);
shw_pio_configure(PIN_ad9516_sdo);
shw_udelay(100);
ad9516_reset();
// ad9516_power_down();
shw_udelay(10000);
if(ad9516_read_reg(AD9516_SERIALPORT) != 0x18)
{
TRACE(TRACE_FATAL, "AD9516 not responding!");
return -1;
}
if(use_ext_ref)
{
assert_init(ad9516_load_state(&ad9516_regs_ext_10m));
} else {
assert_init(ad9516_load_state(&ad9516_regs_tcxo_25m));
}
// wait for the PLL to lock
while(retries--)
{
if(ad9516_check_lock()) break;
shw_udelay(1000);
}
shw_ad9516_set_output_delay(9, 0.5, 0);
// TRACE(TRACE_INFO, "LockReg: %d\n",
return 0;
}
static int find_optimal_params(float delay_ns, int *caps, int *frac, int *ramp, float *best)
{
int r, i, ncaps, f;
float best_error = 10000;
for(r = 0; r < 8; r++)
{
for(i=0;i<8;i++)
{
if(i == 0) ncaps= 0;
else if(i==1 || i==2 || i==4) ncaps = 1;
else if(i==3 || i==6 || i==5) ncaps = 2;
else ncaps = 3;
for(f= 0;f<=0x2f;f++)
{
float iramp = (float)(r+1)*200.0;
float del_range = 200.0 * ((float)(ncaps+3)/iramp) * 1.3286;
float offset = 0.34 + (1600.0 - iramp) * 10e-4 + (float)(ncaps-1)/iramp*6.0;
// printf("range: %.3f offset %.3f\n", del_range, offset);
float del_fine = del_range * (float)f / 63.0 + offset;
if(fabs(del_fine - delay_ns) < best_error)
{
// printf("New Best: %.3f\n", del_fine);
best_error = fabs(del_fine - delay_ns);
*best = del_fine;
*caps = i;
*ramp = r;
*frac = f;
}
}
}
}
}
int shw_ad9516_set_output_delay(int output, float delay_ns, int bypass)
{
uint16_t regbase = 0xa0 + 3*(output - 6);
int ramp,frac,caps;
float best_dly;
find_optimal_params(delay_ns,&caps, &frac, &ramp, &best_dly );
// printf("Opt: caps %d frac %d ramp %d best %.5f req %.5f regbase %x\n", caps, frac, ramp, best_dly, delay_ns, regbase);
ad9516_write_reg(regbase, bypass?1:0);
ad9516_write_reg(regbase+1, (caps << 3) | (ramp));
ad9516_write_reg(regbase+2, frac);
ad9516_write_reg(AD9516_UPDATE_ALL, 1); // acknowledge register update
return 0;
}
static const struct ad9516_regs ad9516_regs_tcxo_25m = {
{
{ 0x0018, 0x00},
{ 0x0232, 0x00},
{ 0x0000, 0x18},
{ 0x0001, 0x00},
{ 0x0002, 0x10},
{ 0x0003, 0xc3},
{ 0x0004, 0x00},
{ 0x0010, 0x7c},
{ 0x0011, 5}, // R div
{ 0x0012, 0x00},
{ 0x0013, 12},// A div
{ 0x0014, 18},// B div -- vco =
{ 0x0015, 0x00},
{ 0x0016, 5}, // 16/17 mode
{ 0x0017, 0x00},
{ 0x0018, 0x07},
{ 0x0019, 0x00},
{ 0x001a, 0x00},
{ 0x001b, 0x00},
{ 0x001c, 0x02}, // back to ref1
{ 0x001d, 0x00},
{ 0x001e, 0x00},
{ 0x001f, 0x0e},
{ 0x00a0, 0x01},
{ 0x00a1, 0x00},
{ 0x00a2, 0x00},
{ 0x00a3, 0x01},
{ 0x00a4, 0x00},
{ 0x00a5, 0x00},
{ 0x00a6, 0x01},
{ 0x00a7, 0x00},
{ 0x00a8, 0x00},
{ 0x00a9, 0x01},
{ 0x00aa, 0x00},
{ 0x00ab, 0x00},
{ 0x00f0, 0x0a},
{ 0x00f1, 0x0a},
{ 0x00f2, 0x0a},
{ 0x00f3, 0x0a},
{ 0x00f4, 0x0a},
{ 0x00f5, 0x08},
{ 0x0140, 0x42},
{ 0x0141, 0x42},
{ 0x0142, 0x42},
{ 0x0143, 0x5a},
{ 0x0190, 0x00},
{ 0x0191, 0x80},
{ 0x0192, 0x00},
{ 0x0193, 0x22},
{ 0x0194, 0x00},
{ 0x0195, 0x00},
{ 0x0196, 0x22},
{ 0x0197, 0x00},
{ 0x0198, 0x00},
{ 0x0199, 0x22},
{ 0x019a, 0x00},
{ 0x019b, 0x11},
{ 0x019c, 0x20},
{ 0x019d, 0x00},
{ 0x019e, 0x22},
{ 0x019f, 0x00},
{ 0x01a0, 0x11},
{ 0x01a1, 0x20},
{ 0x01a2, 0x00},
{ 0x01a3, 0x00},
{ 0x01e0, 0x00},
{ 0x01e1, 0x02},
{ 0x0230, 0x00},
{ 0x0231, 0x00},
{ 0x0232, 0x00},
{ 0x0232, 0x00},
{0}},
71
};
static const struct ad9516_regs ad9516_regs_ext_10m = {
{
{ 0x0018, 0x00},
{ 0x0232, 0x00},
{ 0x0000, 0x18},
{ 0x0001, 0x00},
{ 0x0002, 0x10},
{ 0x0003, 0xc3},
{ 0x0004, 0x00},
{ 0x0010, 0x7c},
{ 0x0011, 2}, // prescaler R div (2 = 10 MHz, 4 = 20 MHz)
{ 0x0012, 0x00},
{ 0x0013, 12},// A div
{ 0x0014, 18},// B div -- vco = 1.5 GHz
{ 0x0015, 0x00},
{ 0x0016, 5}, // 16/17 mode
{ 0x0017, 0x00},
{ 0x0018, 0x07},
{ 0x0019, 0x00},
{ 0x001a, 0x00},
{ 0x001b, 0x00},
{ 0x001c, 0x44},
{ 0x001d, 0x00},
{ 0x001e, 0x00},
{ 0x001f, 0x0e},
{ 0x00a0, 0x01},
{ 0x00a1, 0x00},
{ 0x00a2, 0x00},
{ 0x00a3, 0x01},
{ 0x00a4, 0x00},
{ 0x00a5, 0x00},
{ 0x00a6, 0x01},
{ 0x00a7, 0x00},
{ 0x00a8, 0x00},
{ 0x00a9, 0x01},
{ 0x00aa, 0x00},
{ 0x00ab, 0x00},
{ 0x00f0, 0x0a},
{ 0x00f1, 0x0a},
{ 0x00f2, 0x0a},
{ 0x00f3, 0x0a},
{ 0x00f4, 0x0a},
{ 0x00f5, 0x08},
{ 0x0140, 0x42},
{ 0x0141, 0x42},
{ 0x0142, 0x42},
{ 0x0143, 0x5a},
{ 0x0190, 0x00},
{ 0x0191, 0x80},
{ 0x0192, 0x00},
{ 0x0193, 0x22},
{ 0x0194, 0x00},
{ 0x0195, 0x00},
{ 0x0196, 0x22}, // was 0x32
{ 0x0197, 0x00},
{ 0x0198, 0x00},
{ 0x0199, 0x22},
{ 0x019a, 0x00},
{ 0x019b, 0x11},
{ 0x019c, 0x20},
{ 0x019d, 0x00},
{ 0x019e, 0x22},
{ 0x019f, 0x00},
{ 0x01a0, 0x11},
{ 0x01a1, 0x20},
{ 0x01a2, 0x00},
{ 0x01a3, 0x00},
{ 0x01e0, 0x00},
{ 0x01e1, 0x02},
{ 0x0230, 0x00},
{ 0x0231, 0x00},
{ 0x0232, 0x00},
{ 0x0232, 0x00},
{0}},
71
};
\ No newline at end of file
#!/bin/sh
. ../../settings
make CROSS_COMPILE=$CC_CPU $1
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <hw/switch_hw.h>
#include <hw/trace.h>
#include <hw/clkb_io.h>
#include <hw/pio.h>
#define SPI_CLKDIV_VAL 50
#define CLKB_IDCODE 0xdeadbeef
static void cmi_init(int clkdiv)
{
uint32_t val = SPICTL_ENABLE(1) | SPICTL_CLKDIV(clkdiv);
_fpga_writel(FPGA_BASE_SPIM+SPI_REG_SPICTL, val);
}
static inline int cmi_busy()
{
uint32_t ctl;
ctl = _fpga_readl(FPGA_BASE_SPIM+SPI_REG_SPICTL);
return SPICTL_BUSY(ctl);
}
static inline int cmi_cs(int cs)
{
uint32_t ctl;
ctl = _fpga_readl(FPGA_BASE_SPIM+SPI_REG_SPICTL);
if(cs) ctl |= SPICTL_CSEN(1);
else ctl |= SPICTL_CSDIS(1);
_fpga_writel(FPGA_BASE_SPIM+SPI_REG_SPICTL, ctl);
}
static void cmi_transfer(uint32_t *d_in, uint32_t *d_out, int n)
{
int i;
uint32_t ctl, tmp;
while(cmi_busy());
cmi_cs(1);
for(i=0;i<n;i++)
{
_fpga_writel(FPGA_BASE_SPIM+SPI_REG_SPITX, d_in[i]);
while(cmi_busy());
tmp = _fpga_readl(FPGA_BASE_SPIM+SPI_REG_SPIRX);
if(d_out) d_out[i] = tmp;
}
cmi_cs(0);
}
int shw_clkb_write_reg(uint32_t reg, uint32_t val);
uint32_t shw_clkb_read_reg(uint32_t reg);
int shw_clkb_init_cmi()
{
TRACE(TRACE_INFO, "initializing Clocking Mezzanine Interface");
cmi_init(SPI_CLKDIV_VAL);
return 0;
}
int shw_clkb_init()
{
shw_pio_configure(PIN_clkb_fpga_nrst);
shw_pio_set0(PIN_clkb_fpga_nrst);
shw_udelay(1000);
shw_pio_set1(PIN_clkb_fpga_nrst);
shw_udelay(1000);
}
int shw_clkb_write_reg(uint32_t reg, uint32_t val)
{
uint32_t rx[2], tx[2];
tx[0] = (reg >> 2) & 0x7fffffff;
tx[1] = val;
cmi_transfer(tx,rx,2);
if(rx[1]!=0xaa) {
TRACE(TRACE_ERROR, "invalid ack (0x%08x)", rx[1]);
return -1;
}
return 0;
}
uint32_t shw_clkb_read_reg(uint32_t reg)
{
uint32_t rx[2], tx[2];
tx[0]=(reg >> 2) | 0x80000000;
tx[1]= 0xffffffff;
cmi_transfer(tx,rx,2);
return rx[1];
}
/* FIXME: rewrite this _properly_ */
#include <stdio.h>
#include <inttypes.h>
#include <sys/time.h>
#include <signal.h>
#include <math.h>
#include <hw/switch_hw.h>
#include <hw/clkb_io.h>
#include <hw/dmpll_regs.h>
#define DMPLL_CHANNEL_EXT_REF 2
#define DMPLL_CHANNEL_UP0 0
#define DMPLL_CHANNEL_UP1 1
#define PI_FRACBITS 12 // was 16
typedef struct {
int deglitch_threshold;
double f_n;
double eta;
int ki;
int kp;
int channel;
double phase_setpoint[4];
} dmpll_params_t;
static dmpll_params_t cur_state;
static void dmpll_calc_gain(double f_n, double eta, int *ki, int *kp)
{
const double Kd = 2.6076e+03;
const double Kvco = 0.1816;
const double Fs = 7.6294e+03;
double omega_n = 2*M_PI*f_n;
*kp = (int)((2*eta*omega_n/(Kd*Kvco)) * (double)(1<<PI_FRACBITS));
*ki = (int)((omega_n*omega_n / (Kd*Kvco) / Fs) * (double)(1<<PI_FRACBITS));
TRACE(TRACE_INFO,"kp = %d ki = %d\n", *kp, *ki);
}
static void dmpll_set_deglitch_threshold(uint32_t reg, int thr)
{
TRACE(TRACE_INFO, "threshold %d", thr);
shw_clkb_write_reg(CLKB_BASE_DMPLL + reg, DMPLL_DGCR_IN0_THR_LO_W(thr), DMPLL_DGCR_IN0_THR_HI_W(thr));
}
static void dmpll_set_phase_shift(int channel, int ps_shift)
{
// TRACE(TRACE_INFO,"SetPS ch %d ps %d\n", channel, ps_shift);
switch(channel)
{
case DMPLL_CHANNEL_UP0:
shw_clkb_write_reg(CLKB_BASE_DMPLL + DMPLL_REG_PSCR_IN0, ps_shift);
break;
case DMPLL_CHANNEL_UP1:
shw_clkb_write_reg(CLKB_BASE_DMPLL + DMPLL_REG_PSCR_IN1, ps_shift);
break;
}
}
int shw_dmpll_check_lock()
{
uint32_t psr;
psr= shw_clkb_read_reg(CLKB_BASE_DMPLL + DMPLL_REG_PSR);
if(psr & DMPLL_PSR_LOCK_LOST) {
return 0;
shw_clkb_write_reg(CLKB_BASE_DMPLL + DMPLL_REG_PSR, DMPLL_PSR_LOCK_LOST); // clear loss-of-lock bit
}
// printf("DPSR %x\n",psr & (DMPLL_PSR_FREQ_LK | DMPLL_PSR_PHASE_LK));
return (psr & DMPLL_PSR_FREQ_LK);// && (psr & DMPLL_PSR_PHASE_LK);
}
static int dmpll_shifter_busy(int channel)
{
switch(channel)
{
case DMPLL_CHANNEL_UP0:
return shw_clkb_read_reg(CLKB_BASE_DMPLL + DMPLL_REG_PSCR_IN0) & DMPLL_PSCR_IN0_BUSY;
case DMPLL_CHANNEL_UP1:
return shw_clkb_read_reg(CLKB_BASE_DMPLL + DMPLL_REG_PSCR_IN1) & DMPLL_PSCR_IN1_BUSY;
}
return 0;
}
\
static int iface_to_channel(const char *source)
{
if(!strcmp(source,"wru0"))
return DMPLL_CHANNEL_UP0;
else if(!strcmp(source,"wru1"))
return DMPLL_CHANNEL_UP1;
return -1;
}
int shw_dmpll_lock(const char *source)
{
int ref_clk = iface_to_channel(source);
if(ref_clk < 0) {
TRACE(TRACE_ERROR, "Unknown clock source...");
return -1;
}
TRACE(TRACE_INFO,"DMPLL: Set refence input to: %s", source);
shw_clkb_write_reg(CLKB_BASE_DMPLL + DMPLL_REG_PCR, 0);
dmpll_set_deglitch_threshold(DMPLL_REG_DGCR_IN0, cur_state.deglitch_threshold);
dmpll_set_deglitch_threshold(DMPLL_REG_DGCR_IN1, cur_state.deglitch_threshold);
dmpll_set_deglitch_threshold(DMPLL_REG_DGCR_FB, cur_state.deglitch_threshold);
shw_clkb_write_reg(CLKB_BASE_DMPLL + DMPLL_REG_PSCR_IN0, 0);
shw_clkb_write_reg(CLKB_BASE_DMPLL + DMPLL_REG_PSCR_IN1, 0);
shw_clkb_write_reg(CLKB_BASE_DMPLL + DMPLL_REG_PSCR_IN2, 0);
shw_clkb_write_reg(CLKB_BASE_DMPLL + DMPLL_REG_PSCR_IN3, 0);
// gains & thresholds
shw_clkb_write_reg(CLKB_BASE_DMPLL + DMPLL_REG_FBGR, DMPLL_FBGR_F_KP_W(-100) | DMPLL_FBGR_F_KI_W(-600));
dmpll_calc_gain(cur_state.f_n, cur_state.eta, &cur_state.ki, &cur_state.kp);
shw_clkb_write_reg(CLKB_BASE_DMPLL + DMPLL_REG_PBGR, DMPLL_PBGR_P_KP_W(cur_state.kp) | DMPLL_PBGR_P_KI_W(cur_state.ki)); // -1000/-20
shw_clkb_write_reg(CLKB_BASE_DMPLL + DMPLL_REG_LDCR, DMPLL_LDCR_LD_THR_W(2000) | DMPLL_LDCR_LD_SAMP_W(2000));
shw_clkb_write_reg(CLKB_BASE_DMPLL + DMPLL_REG_PCR, DMPLL_PCR_ENABLE | DMPLL_PCR_REFSEL_W(ref_clk) | DMPLL_PCR_DAC_CLKSEL_W(2) | DMPLL_PCR_PS_SPEED_W(100) | DMPLL_PCR_SWRST);
cur_state.channel = ref_clk;
return 0;
}
int shw_dmpll_phase_shift(const char *source, int phase_shift)
{
int ref_clk = iface_to_channel(source);
double ps;
// TRACE(TRACE_INFO,"shw_DMPLL_phase_shift source %s ref %d ps %d\n", source, ref_clk, phase_shift);
if(ref_clk < 0) return -1;
ps = (double)phase_shift / 8000.0 * (double) shw_hpll_get_divider();
dmpll_set_phase_shift(ref_clk, (int) ps);
return 0;
}
int shw_dmpll_shifter_busy(const char *source)
{
int ref_clk = iface_to_channel(source);
if(ref_clk < 0) return -1;
int busy = dmpll_shifter_busy(ref_clk) ? 1 :0;
// TRACE(TRACE_INFO,"PS-busy: %d\n", busy);
return busy;
}
int shw_dmpll_init()
{
TRACE(TRACE_INFO,"Initializing DMTD main PLL...");
// DMPLL is disabled by default. Just make sure it loads the initial DAC value (middle of TCXO tuning range)
shw_clkb_write_reg(CLKB_BASE_DMPLL + DMPLL_REG_PCR, DMPLL_PCR_DAC_CLKSEL_W(2) | DMPLL_PCR_SWRST);
// these work
cur_state.f_n = 15.0; // 15.0
cur_state.eta = 0.8; // 1.8
cur_state.deglitch_threshold = 3000;
// cur_state.f_n = 5.0;
// cur_state.eta = 3;
// cur_state.deglitch_threshold = 2000;
}
#include <stdio.h>
#include <unistd.h>
#include <unistd.h>
#include <sys/mman.h>
#include <inttypes.h>
#include <fcntl.h>
#include <poll.h>
#include <hw/switch_hw.h>
#define SMC_CS0_BASE 0x70000000
#define SMC_CS0_SIZE 0x200000
#define SPI_CLKDIV_VAL 20 // clock divider for CMI SPI bus clock
volatile uint8_t *_fpga_base_virt;
int shw_fpga_mmap_init()
{
int fd;
TRACE(TRACE_INFO, "Initializing FPGA memory mapping.");
fd = open("/dev/mem", O_RDWR);
if(!fd) return -1;
_fpga_base_virt = mmap(NULL, SMC_CS0_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, SMC_CS0_BASE);
if(_fpga_base_virt == NULL)
{
perror("mmap()");
close(fd);
return -1;
}
TRACE(TRACE_INFO, "FPGA virtual base = 0x%08x", _fpga_base_virt);
return 0;
}
int shw_main_fpga_init()
{
shw_pio_configure(PIN_main_fpga_nrst);
shw_main_fpga_reset();
}
void shw_main_fpga_reset()
{
shw_pio_set0(PIN_main_fpga_nrst);
usleep(10000);
shw_pio_set1(PIN_main_fpga_nrst);
usleep(10000);
}
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <hw/pio.h>
#include <hw/fpgaboot.h>
#include <hw/trace.h>
#include <hw/util.h>
#include <hw/fpga_regs.h>
#include <hw/clkb_io.h>
#include "minilzo.h"
// directory (on the switch filesystem) containing the FPGA bitstreams
#define DEFAULT_FPGA_IMAGE_DIR "/wr/firmware"
static char fpga_image_dir[128] = DEFAULT_FPGA_IMAGE_DIR;
// firmware names for both FPGAs. Can be changed by calling shw_request_fpga_firmware()
static int force_new_firmware = 0;
static char *firmware_main = "board_test";
static char *firmware_clkb = "dmtd_pll_test";
#define REVID_MAGIC_VALUE 0xdeadbeef
#define REVID_REG_MAGIC 0x0
#define REVID_REG_FW_HASH 0x8
#define REVID_REG_FW_REVISION 0x4
static int get_fpga_revid(int fpga_id, uint32_t *fw_hash, uint32_t *rev_id)
{
if(fpga_id == FPGA_ID_MAIN)
{
// check the magic register value
if(_fpga_readl(FPGA_BASE_REVID + REVID_REG_MAGIC) != REVID_MAGIC_VALUE) return -1;
*fw_hash = _fpga_readl(FPGA_BASE_REVID + REVID_REG_FW_HASH);
*rev_id = _fpga_readl(FPGA_BASE_REVID + REVID_REG_FW_REVISION);
return 0;
} else if(fpga_id == FPGA_ID_CLKB) {
if(shw_clkb_read_reg(CLKB_BASE_REVID + REVID_REG_MAGIC) != REVID_MAGIC_VALUE) return -1;
*fw_hash = shw_clkb_read_reg(CLKB_BASE_REVID + REVID_REG_FW_HASH);
*rev_id = shw_clkb_read_reg(CLKB_BASE_REVID + REVID_REG_FW_REVISION);
return 0;
};
return -1;
}
static int read_le32(FILE *f, uint32_t *rval)
{
#if __BYTE_ORDER==__LITTLE_ENDIAN
return fread(rval, 4, 1, f) == 4 ? -1 : 0;
#else
#error "Big endian architectures not supported yet :("
#endif
}
static char * read_string(FILE *f)
{
char buf[1024];
uint32_t len;
if(read_le32(f, &len) < 0)
return NULL;
if(len > sizeof(buf)-1)
return NULL;
fread(buf, 1, len, f);
buf[len]=0;
return strdup(buf);
}
static int read_image_header(FILE *f, struct fpga_image_entry *ent)
{
struct fpga_image_header hdr;
int rc = 0;
if( fread(&hdr, sizeof(struct fpga_image_header), 1, f) != 1)
return -1;
if(memcmp(hdr.magic, FPGA_IMAGE_MAGIC, 4))
return -1;
ent->fpga_name = read_string(f);
ent->fw_name = read_string(f);
rc = read_le32(f, &ent->hash_reg);
rc |= read_le32(f, &ent->revision);
rc |= read_le32(f, &ent->size);
rc |= read_le32(f, &ent->compressed_size);
if(!ent->fpga_name || !ent->fw_name || rc) return -1;
return 0;
}
const char *expand_fpga_id(int fpga_id)
{
if(fpga_id == FPGA_ID_MAIN)
return "mch_main";
else if(fpga_id == FPGA_ID_CLKB)
return "mch_clkb";
else return "unknown?";
}
static int stat_is_file(const char *name)
{
struct stat sb;
if(stat(name, &sb) != 0) return 0;
return S_ISREG(sb.st_mode);
}
static int find_fpga_image(int fpga_id, const char *fw_name, int rev_id, uint32_t fw_hash, struct fpga_image_entry *ent_h)
{
FILE *f;
struct dirent **namelist;
int n;
char latest_image_name[1024];
int found = 0;
int max_rev = -1;
n = scandir(fpga_image_dir, &namelist, 0, alphasort);
if(n<0)
{
TRACE(TRACE_FATAL, "Scanning the FPGA image directory (%s) failed.", fpga_image_dir);
return -1;
}
while(n--)
{
char namebuf[1024];
strncpy(namebuf, fpga_image_dir, 1024);
strncat(namebuf, "/", 1024);
strncat(namebuf, namelist[n]->d_name, 1024);
if(!stat_is_file(namebuf)) continue;
f = fopen(namebuf, "rb");
if(f)
{
struct fpga_image_entry ent;
if(!read_image_header(f, &ent))
{
TRACE(TRACE_INFO,"CheckFW: %s [%s] rev %d", ent.fpga_name, ent.fw_name, ent.revision);
if(rev_id) // name-based lookup
{
if(!strcasecmp(ent.fpga_name, expand_fpga_id(fpga_id))
&& !strcasecmp(ent.fw_name, fw_name))
{
found = 1;
if((int)ent.revision > max_rev)
{
max_rev = ent.revision;
strncpy(latest_image_name, namebuf, 1024);
}
}
} else { // revid-based lookup: we look for newer firmware with matching revid
if(ent.hash_reg == fw_hash && (int)ent.revision > max_rev)
{
found = 1;
max_rev = ent.revision;
strncpy(latest_image_name, namebuf, 1024);
}
}
}
shw_free(namelist[n]);
fclose(f);
}
}
shw_free(namelist);
if(!found)
return -1;
if(rev_id >= 0 && max_rev <= rev_id)
return -1;
f = fopen(latest_image_name, "rb");
read_image_header(f, ent_h);
TRACE(TRACE_INFO, "Found most recent image: %s (FPGA: %s, firmware: %s, revision: %d)", latest_image_name, ent_h->fpga_name, ent_h->fw_name, ent_h->revision);
ent_h -> image_buf = shw_malloc(ent_h->compressed_size);
fread(ent_h->image_buf, 1, ent_h->compressed_size, f);
fclose(f);
return 0;
}
static int uncompress_and_boot_fpga(int fpga_id, struct fpga_image_entry *ent)
{
uint8_t *bitstream;
uint32_t dec_size, img_offset = 0;
bitstream = shw_malloc(ent->size);
dec_size = ent->size;
int r = lzo1x_decompress(ent->image_buf, ent->compressed_size, bitstream, (lzo_uint*) &dec_size, NULL);
if (r != LZO_E_OK || dec_size != ent->size)
{
TRACE(TRACE_ERROR, "Image decompression failed.");
shw_free(ent->image_buf);
shw_free(bitstream);
return -1;
}
int rc = shw_load_fpga_bitstream(fpga_id, bitstream, ent->size);
shw_free(bitstream);
shw_free(ent->image_buf);
return rc;
}
int shw_boot_fpga(int fpga_id)
{
char *fw_name;
char *fpga_name;
int rev_id;
uint32_t fw_hash;
struct fpga_image_entry ent;
int rc;
fpga_name = expand_fpga_id(fpga_id);
TRACE(TRACE_INFO, "%s: reading REV_ID...", fpga_name);
if(get_fpga_revid (fpga_id, &fw_hash, (uint32_t *)&rev_id) < 0)
rev_id = -1;
switch(fpga_id)
{
case FPGA_ID_MAIN:
fw_name = firmware_main; break;
case FPGA_ID_CLKB:
fw_name = firmware_clkb; break;
}
if(rev_id < 0 || force_new_firmware)
{
TRACE(TRACE_INFO, "%s: invalid REV_ID or forced firmware update. Trying to boot the FPGA with the firmware: %s", fpga_name, fw_name)
rc = find_fpga_image(fpga_id, fw_name, -1, 0, &ent);
if(rc < 0) {
TRACE(TRACE_FATAL, "%s: unable to find any image for FPGA!", fpga_name);
shw_exit_fatal();
return -1;
}
return uncompress_and_boot_fpga(fpga_id, &ent);
} else {
TRACE(TRACE_INFO, "%s: got REV_ID (rev = %d, hash = %x). Looking for newer firmware", fpga_name, rev_id, fw_hash);
rc = find_fpga_image(fpga_id, fw_name, rev_id, fw_hash, &ent);
if(rc < 0) {
TRACE(TRACE_INFO, "%s: no more recent image found", fpga_name);
return 0;
} else return uncompress_and_boot_fpga(fpga_id, &ent);
}
return -1;
}
int shw_request_fpga_firmware(int fpga_id, const char *firmware_name)
{
switch(fpga_id)
{
case FPGA_ID_MAIN:
firmware_main = strdup(firmware_name); break;
case FPGA_ID_CLKB:
firmware_clkb = strdup(firmware_name); break;
}
return 0;
}
int shw_set_fpga_firmware_path(const char *path)
{
strncpy(fpga_image_dir, path, sizeof(fpga_image_dir));
TRACE(TRACE_INFO,"FPGA firmware directory set to %s", fpga_image_dir);
return 0;
}
void shw_fpga_force_firmware_reload()
{
force_new_firmware = 1;
}
int shw_fpgaboot_init()
{
mblaster_init();
//strncpy(fpga_image_dir, DEFAULT_FPGA_IMAGE_DIR, sizeof(fpga_image_dir));
return 0;
}
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <sys/time.h>
#include <hw/clkb_io.h>
#include <hw/switch_hw.h>
#define FREQ_ERROR_FRACBITS 7
#define DEFAULT_PD_GATE_SEL HPLL_PD_GATE_16K // Phase detector gating = 16384 fbck cycles
#define DEFAULT_FD_GATE_SEL 3 // Frequency gating: 131072 fbck cycles
#define DEFAULT_LD_SAMPLES 250
#define DEFAULT_LD_THRESHOLD 100
#define FLOAT_TO_FB_COEF(x) ((int)((x) * (32.0 * 16.0 )))
#define FLOAT_TO_PB_COEF(x) ((int)((x) * (32.0 * 16.0 )))
// 0.00384, 0.0384, // target phase Ki/Kp
// 20.0 , 8.0, // freq Ki/Kp
static const hpll_params_t default_hpll_params = {
20.0 , 8.0, // freq Ki/Kp
0.256, 6.40, // target phase Ki/Kp
100, // gain steps
200000ULL, // gain step delay
16384, // N
1, // delta
HPLL_FD_GATE_128K, // freq detector gating
HPLL_PD_GATE_16K, // phase detector gating
HPLL_REFSEL_LOCAL, // reference clock select: local reference clock
0, // don't stay in the freq mode after lock
0, 0
};
static inline uint32_t hpll_read(uint32_t reg)
{
return shw_clkb_read_reg(CLKB_BASE_HPLL + reg);
}
static inline void hpll_write(uint32_t reg, uint32_t value)
{
shw_clkb_write_reg(CLKB_BASE_HPLL + reg, value);
}
/* static void hpll_poll_rfifo() */
/* { */
/* while(1) */
/* { */
/* if((hpll_read(HPLL_REG_RFIFO_CSR) & HPLL_RFIFO_CSR_EMPTY) || rfifo_nmeas >= MAX_MEAS) return; */
/* rfifo_record[rfifo_nmeas++] = hpll_read(HPLL_REG_RFIFO_R0); */
/* } */
/* } */
static double interpolate(double start, double end, int step, int nsteps)
{
double k = (double)step / (double)(nsteps - 1);
return start * (1.0-k) + k * end;
}
static hpll_params_t cur_params;
void shw_hpll_ramp_gain(double kp_new, double ki_new)
{
uint64_t init_tics = shw_get_tics();
int step = 0;
cur_params.kp_phase = kp_new;
cur_params.ki_phase = ki_new;
for(step = 0; step < cur_params.phase_gain_steps; step++)
{
// if(shw_get_tics() - init_tics > (uint64_step * cur_params.phase_gain_step_delay)
{
double kp, ki;
kp = interpolate(cur_params.kp_phase_cur,cur_params.kp_phase, step, cur_params.phase_gain_steps);
ki = interpolate(cur_params.ki_phase_cur,cur_params.ki_phase, step, cur_params.phase_gain_steps);
// TRACE(TRACE_INFO, "ramping down the HPLL gain (Kp = %.5f Ki = %.5f)", kp, ki);
hpll_write(HPLL_REG_PBGR,
HPLL_PBGR_P_KP_W(FLOAT_TO_FB_COEF(kp)) |
HPLL_PBGR_P_KI_W(FLOAT_TO_FB_COEF(ki)));
// } else {
usleep(1000);
}
}
cur_params.kp_phase_cur = cur_params.kp_phase;
cur_params.ki_phase_cur = cur_params.ki_phase;
}
void shw_hpll_load_regs(const hpll_params_t *params)
{
int target_freq_err;
double freq_gating;
hpll_write(HPLL_REG_PCR, 0); // disable the PLL
hpll_write(HPLL_REG_DIVR, // select the division ratio
HPLL_DIVR_DIV_FB_W(params->N + params->delta) |
HPLL_DIVR_DIV_REF_W(params->N));
TRACE(TRACE_INFO,"DIV_REF = %d, DIV_FB = %d", params->N, params->N + params->delta);
hpll_write(HPLL_REG_FBGR, // set frequency detector gain
HPLL_FBGR_F_KP_W(FLOAT_TO_FB_COEF(params->kp_freq)) |
HPLL_FBGR_F_KI_W(FLOAT_TO_FB_COEF(params->ki_freq)));
TRACE(TRACE_INFO,"Freq: KP = %d, KI = %d", FLOAT_TO_FB_COEF(params->kp_freq), FLOAT_TO_FB_COEF(params->ki_freq));
hpll_write(HPLL_REG_PBGR, // set phase detector gain (initial value)
HPLL_PBGR_P_KP_W(FLOAT_TO_FB_COEF(params->kp_phase)) |
HPLL_PBGR_P_KI_W(FLOAT_TO_FB_COEF(params->ki_phase)));
// params->kp_phase_cur = params->kp_phase;
// params->ki_phase_cur = params->ki_phase;
TRACE(TRACE_INFO,"Phase: KP = %d, KI = %d", FLOAT_TO_FB_COEF(params->kp_phase), FLOAT_TO_FB_COEF(params->ki_phase));
hpll_write(HPLL_REG_LDCR, // lock detection samples & threshold
HPLL_LDCR_LD_SAMP_W(DEFAULT_LD_SAMPLES) |
HPLL_LDCR_LD_THR_W(DEFAULT_LD_THRESHOLD));
TRACE(TRACE_INFO,"LockDet: SAMP = %d, THR = %d", DEFAULT_LD_SAMPLES, DEFAULT_LD_THRESHOLD);
// calculate target frequency error
freq_gating = (double) (1 << (params->freq_gating + 14));
target_freq_err = (int) ((freq_gating - (freq_gating * (double)(params->N + params->delta) / (double)(params->N))) * (double)(1<<FREQ_ERROR_FRACBITS)) ;
hpll_write(HPLL_REG_FBCR, // frequency branch control
HPLL_FBCR_FERR_SET_W(target_freq_err) | HPLL_FBCR_FD_GATE_W(params->freq_gating));
TRACE(TRACE_INFO,"TargetFreqErr = %d, FreqGating = %d PhaseGating = %d", target_freq_err, params->freq_gating, params->phase_gating);
// enable the PLL, set DAC clock, reference clock, etc.
hpll_write(HPLL_REG_PCR,
// HPLL_PCR_FORCE_F |
HPLL_PCR_ENABLE | // enable the PLL
HPLL_PCR_SWRST | // force software reset
HPLL_PCR_PD_GATE_W(params->phase_gating) | // phase detector gating
HPLL_PCR_DAC_CLKSEL_W(2) | // dac clock = system clock / 32
HPLL_PCR_REFSEL_W(params->ref_sel)); // reference select
// init_tics = shw_get_tics();
memcpy(&cur_params, params, sizeof(hpll_params_t));
cur_params.kp_phase_cur = params->kp_phase;
cur_params.ki_phase_cur = params->ki_phase;
// shw_hpll_ramp_gain(0.1, 0.00384);
shw_hpll_ramp_gain(0.0384, 0.00384);
}
void shw_hpll_reset()
{
uint32_t pcr_val = hpll_read(HPLL_REG_PCR);
pcr_val |= HPLL_PCR_SWRST;
hpll_write(HPLL_REG_PCR, pcr_val);
}
/*void shw_hpll_set_reference(int ref_clk)
{
uint32_t pcr_val = hpll_read(HPLL_REG_PCR);
pcr_val &= ~HPLL_PCR_REFSEL_MASK;
pcr_val |= HPLL_PCR_REFSEL_W(ref_clk);
hpll_write(HPLL_REG_PCR, pcr_val);
}*/
int shw_hpll_check_lock()
{
uint32_t psr;
psr= hpll_read(HPLL_REG_PSR);
if(psr & HPLL_PSR_LOCK_LOST) {
return 0;
hpll_write(HPLL_REG_PSR, HPLL_PSR_LOCK_LOST); // clear loss-of-lock bit
}
printf("PSR %x\n",psr & (HPLL_PSR_FREQ_LK | HPLL_PSR_PHASE_LK));
printf("PCR %x\n", hpll_read(HPLL_REG_PCR));
//
// return 1;
return (psr & HPLL_PSR_FREQ_LK) && (psr & HPLL_PSR_PHASE_LK);
}
int shw_hpll_get_divider()
{
return cur_params.N;
}
int shw_hpll_init()
{
TRACE(TRACE_INFO, "Initializing the DMTD Helper PLL");
shw_hpll_load_regs(&default_hpll_params);
while(!shw_hpll_check_lock()) usleep(100000);
}
int shw_hpll_switch_reference(const char *if_name)
{
hpll_params_t my_params;
TRACE(TRACE_INFO, "HPLL: Set reference input to: %s", if_name);
memcpy(&my_params, &default_hpll_params, sizeof(hpll_params_t));
if(!strcmp(if_name, "wru0"))
my_params.ref_sel = HPLL_REFSEL_UP0_RBCLK;
else if(!strcmp(if_name, "wru1"))
my_params.ref_sel = HPLL_REFSEL_UP1_RBCLK;
else if(!strcmp(if_name, "local"))
my_params.ref_sel = HPLL_REFSEL_LOCAL;
else
TRACE(TRACE_FATAL, "unrecognized HPLL reference clock: %s", if_name);
shw_hpll_load_regs(&my_params);
}
#include <stdio.h>
#include <stdlib.h>
#include <hw/switch_hw.h>
#define assert_init(proc) { int ret; if((ret = proc) < 0) return ret; }
int shw_init()
{
assert_init(shw_fpga_mmap_init());
assert_init(shw_pio_mmap_init());
assert_init(shw_main_fpga_init());
assert_init(shw_ad9516_init());
assert_init(shw_pio_configure_all_cpu_pins());
assert_init(shw_fpgaboot_init());
assert_init(shw_boot_fpga(FPGA_ID_MAIN));
assert_init(shw_main_fpga_init());
assert_init(shw_pio_configure_all_fpga_pins());
assert_init(shw_clkb_init_cmi()); // Initialize the CMI link prior to booting the CLKB FPGA, so the FPGA bootloader could check the REVID
assert_init(shw_boot_fpga(FPGA_ID_CLKB));
assert_init(shw_clkb_init());
assert_init(shw_hpll_init());
assert_init(shw_dmpll_init());
assert_init(shw_cal_init());
assert_init(shw_pps_gen_init());
assert_init(shw_watchdog_init());
// shw_fpga_boot();
TRACE(TRACE_INFO, "HW initialization done!");
}
int shw_exit_fatal()
{
TRACE(TRACE_FATAL, "exiting due to fatal error.");
exit(-1);
}
#undef assert_init
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <dirent.h>
#include <hw/pio.h>
#include <hw/fpgaboot.h>
#include <hw/trace.h>
#include <hw/util.h>
#define SIG_DCLK 0
#define SIG_NCONFIG 1
#define SIG_DATA0 2
#define SIG_NSTATUS 3
#define SIG_CONFDONE 4
#define INIT_CYCLE 50
#define RECONF_COUNT_MAX 5
#define CHECK_EVERY_X_BYTE 10240
#define CLOCK_X_CYCLE 0
static inline void Dump2Port(const pio_pin_t **pinmap, int signal, int data, int clk );
static inline void ProgramByte(const pio_pin_t **pinmap, int one_byte );
static const pio_pin_t *io_mapping_main[] = {
PIN_main_fpga_dclk,
PIN_main_fpga_nconfig,
PIN_main_fpga_data,
PIN_main_fpga_nstatus,
PIN_main_fpga_confdone
};
static const pio_pin_t *io_mapping_clkb[] = {
PIN_clkb_fpga_dclk,
PIN_clkb_fpga_nconfig,
PIN_clkb_fpga_data,
PIN_clkb_fpga_nstatus,
PIN_clkb_fpga_confdone
};
int mblaster_init()
{
int i;
TRACE(TRACE_INFO, "Configuring the FPGA setup signals");
for(i=0;i<5;i++)
{
shw_pio_configure(io_mapping_main[i]);
shw_pio_configure(io_mapping_clkb[i]);
}
}
static int mblaster_boot_fpga(const uint8_t *bitstream, uint32_t bitstream_size, const pio_pin_t **pinmap)
{
int program_done = 0; /* programming process (configuration and initialization) done = 1 */
int seek_position = 0; /* file pointer position */
int configuration_count = RECONF_COUNT_MAX; /* # reprogramming after error */
int one_byte = 0; /* the byte to program */
long int i = 0; /* standard counter variable */
int confdone_ok = 1; /* CONF_DONE pin. '1' - error */
int nstatus_ok = 0; /* NSTATUS pin. '0' - error */
int clock_x_cycle = CLOCK_X_CYCLE; /* Clock another 'x' cycles during user mode ( not necessary, for debug purpose only) */
int BBMV=0;
int BBII=0;
/* Start configuration */
while ( !program_done && (configuration_count>0) )
{
/* Drive a transition of 0 to 1 to NCONFIG to indicate start of configuration */
Dump2Port(pinmap, SIG_NCONFIG, 0, 0 );
shw_udelay(1);
Dump2Port(pinmap, SIG_NCONFIG, 1, 0 );
shw_udelay(1);
/* Loop through every single byte */
for ( i = 0; i < bitstream_size; i++ )
{
/*one_byte = fgetc( (FILE*) finputid );*/
one_byte = bitstream[i];
/* Progaram a byte */
ProgramByte(pinmap, one_byte );
/* Check for error through NSTATUS for every 10KB programmed and the last byte */
if ( !(i % CHECK_EVERY_X_BYTE) || (i == bitstream_size - 1) )
{
shw_udelay(100);
//printf("I = %d\n", i);
nstatus_ok = shw_pio_get(pinmap[SIG_NSTATUS]); //CheckSignal( SIG_NSTATUS );
if ( !nstatus_ok )
{
printf("status dupa!\n");
program_done = 0;
break;
}
else
program_done = 1;
}
}
configuration_count--;
if ( !program_done )
continue;
/* Configuration end */
/* Check CONF_DONE that indicates end of configuration */
confdone_ok = !shw_pio_get(pinmap[SIG_CONFDONE]); //!CheckSignal( SIG_CONFDONE );
if ( confdone_ok )
{
TRACE(TRACE_ERROR ,"Configuration done but contains error... CONF_DONE is %s", (confdone_ok? "LOW":"HIGH") );
program_done = 0;
if ( configuration_count == 0 )
break;
}
/* if contain error during configuration, restart configuration */
if ( !program_done )
continue;
/* program_done = 1; */
/* Start initialization */
/* Clock another extra DCLK cycles while initialization is in progress
through internal oscillator or driving clock cycles into CLKUSR pin */
/* These extra DCLK cycles do not initialize the device into USER MODE */
/* It is not required to drive extra DCLK cycles at the end of
configuration */
/* The purpose of driving extra DCLK cycles here is to insert some delay
while waiting for the initialization of the device to complete before
checking the CONFDONE and NSTATUS signals at the end of whole
configuration cycle */
for ( i = 0; i < INIT_CYCLE; i++ )
{
Dump2Port( pinmap, SIG_DCLK, 0, 0 );
Dump2Port( pinmap, SIG_DCLK, 1, 0 );
}
/* Initialization end */
nstatus_ok = shw_pio_get(pinmap[SIG_NSTATUS]); //CheckSignal( SIG_NSTATUS );
confdone_ok = !shw_pio_get(pinmap[SIG_CONFDONE]); //!CheckSignal( SIG_CONFDONE );
if ( !nstatus_ok || confdone_ok )
{
TRACE(TRACE_ERROR, "Initialization finished but contains error: NSTATUS is %s and CONF_DONE is %s. Exiting...", (nstatus_ok?"HIGH":"LOW"), (confdone_ok?"LOW":"HIGH") );
program_done = 0;
configuration_count = 0; /* No reconfiguration */
}
}
/* Add another 'x' clock cycles while the device is in user mode.
This is not necessary and optional. Only used for debugging purposes */
if ( clock_x_cycle > 0 )
{
TRACE(TRACE_INFO, "Clock another %d cycles in while device is in user mode...", clock_x_cycle );
for ( i = 0; i < CLOCK_X_CYCLE; i++ )
{
Dump2Port( pinmap, SIG_DCLK, 0, 0 );
Dump2Port( pinmap, SIG_DCLK, 1, 0 );
}
}
if ( !program_done )
{
TRACE(TRACE_ERROR, "Error: Configuration not successful! Error encountered..." );
return -1;
}
Dump2Port( pinmap, SIG_DCLK, 1, 0 );
Dump2Port( pinmap, SIG_DATA0, 1, 0 );
TRACE(TRACE_INFO, "Configuration successful!" );
return 0;
}
/********************************************************************************/
/* Name: Dump2Port */
/* */
/* Parameters: int signal, int data, int clk */
/* - name of the signal (SIG_*). */
/* - value to be dumped to the signal. */
/* - assert a LOW to HIGH transition to SIG_DCLK togther with */
/* [signal]. */
/* */
/* Return Value: None. */
/* */
/* Descriptions: Dump [data] to [signal]. If [clk] is '1', a clock pulse is */
/* generated after the [data] is dumped to [signal]. */
/* */
/********************************************************************************/
static inline void mdelay()
{
int i;
for(i=0;i<10;i++) asm volatile("nop");
}
static inline void Dump2Port(const pio_pin_t **pinmap, int signal, int data, int clk )
{
// fprintf(stderr,"d2p: %d %d %d %d\n", signal, data, clk);
if(clk)
shw_pio_set0(pinmap[SIG_DCLK]);
shw_pio_set(pinmap[signal], data);
// mdelay();
if(clk)
shw_pio_set1(pinmap[SIG_DCLK]);
//mdelay();
}
static inline void ProgramByte(const pio_pin_t **pinmap, int one_byte )
{
int bit = 0;
int i = 0;
/* write from LSb to MSb */
for ( i = 0; i < 8; i++ )
{
bit = one_byte >> i;
bit = bit & 0x1;
/* Dump to DATA0 and insert a positive edge pulse at the same time */
Dump2Port( pinmap, SIG_DATA0, bit, 1 );
}
}
int shw_load_fpga_bitstream(int fpga_id, uint8_t *bitstream, uint32_t bitstream_size)
{
switch(fpga_id)
{
case FPGA_ID_MAIN:
return mblaster_boot_fpga(bitstream, bitstream_size, io_mapping_main);
break;
case FPGA_ID_CLKB:
return mblaster_boot_fpga(bitstream, bitstream_size, io_mapping_clkb);
break;
}
return 0;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* minilzo.h -- mini subset of the LZO real-time data compression library
This file is part of the LZO real-time data compression library.
Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
All Rights Reserved.
The LZO library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
The LZO library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the LZO library; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Markus F.X.J. Oberhumer
<markus@oberhumer.com>
http://www.oberhumer.com/opensource/lzo/
*/
/*
* NOTE:
* the full LZO package can be found at
* http://www.oberhumer.com/opensource/lzo/
*/
#ifndef __MINILZO_H
#define __MINILZO_H
#define MINILZO_VERSION 0x2030
#ifdef __LZOCONF_H
# error "you cannot use both LZO and miniLZO"
#endif
#undef LZO_HAVE_CONFIG_H
#include "lzoconf.h"
#if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION)
# error "version mismatch in header files"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/***********************************************************************
//
************************************************************************/
/* Memory required for the wrkmem parameter.
* When the required size is 0, you can also pass a NULL pointer.
*/
#define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS
#define LZO1X_1_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t))
#define LZO1X_MEM_DECOMPRESS (0)
/* compression */
LZO_EXTERN(int)
lzo1x_1_compress ( const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem );
/* decompression */
LZO_EXTERN(int)
lzo1x_decompress ( const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem /* NOT USED */ );
/* safe decompression with overrun testing */
LZO_EXTERN(int)
lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem /* NOT USED */ );
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* already included */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <asm/types.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <sys/ioctl.h>
#include <hw/switch_hw.h>
#include <hw/phy_calibration.h>
#include <hw/dmtd_calibrator_regs.h>
#include <hw/clkb_io.h>
#define CAL_DMTD_AVERAGING_STEPS 256
#define PORT_UPLINK 0
#define PORT_DOWNLINK 1
//driver-specific private ioctls
#define PRIV_IOCGCALIBRATE (SIOCDEVPRIVATE+1)
#define PRIV_IOCGGETPHASE (SIOCDEVPRIVATE+2)
#define CAL_CMD_TX_ON 1
#define CAL_CMD_TX_OFF 2
#define CAL_CMD_RX_ON 3
#define CAL_CMD_RX_OFF 4
#define CAL_CMD_RX_CHECK 5
struct wrmch_calibration_req {
int cmd;
int cal_present;
};
struct wrmch_phase_req {
int ready;
uint32_t phase;
};
static int cal_socket;
static char cal_current_if[16];
static int cal_in_progress = 0;
static int cal_current_lane ;
static int cal_current_port_index;
static int cal_current_port_type;
#define UPLINK_CAL_IN_UP0_RBCLK 0
#define UPLINK_CAL_IN_UP1_RBCLK 1
#define UPLINK_CAL_IN_REFCLK 2
#define DOWNLINK_CAL_IN_REFCLK 0
#define DOWNLINK_CAL_IN_RBCLK(x) (x+1)
static int uplink_calibrator_configure(int n_avg, int lane, int index)
{
int input;
if(lane == PHY_CALIBRATE_TX)
input = UPLINK_CAL_IN_REFCLK;
else if(lane == PHY_CALIBRATE_RX)
{
if(index == 0)
input = UPLINK_CAL_IN_UP0_RBCLK;
else
input = UPLINK_CAL_IN_UP1_RBCLK;
}
shw_clkb_write_reg(CLKB_BASE_CALIBRATOR + DPC_REG_CR, 0);
shw_clkb_write_reg(CLKB_BASE_CALIBRATOR + DPC_REG_CR, DPC_CR_EN | DPC_CR_N_AVG_W(n_avg) | DPC_CR_IN_SEL_W(input));
}
int route_order[8] = {0,1,2,3,4,5,6,7};
static int downlink_calibrator_configure(int n_avg, int lane, int index)
{
int input;
if(lane == PHY_CALIBRATE_TX)
input = DOWNLINK_CAL_IN_REFCLK;
else if(lane == PHY_CALIBRATE_RX)
{
input = DOWNLINK_CAL_IN_RBCLK(route_order[index]);
}
_fpga_writel(FPGA_BASE_CALIBRATOR + DPC_REG_CR, 0);
_fpga_writel(FPGA_BASE_CALIBRATOR + DPC_REG_CR, DPC_CR_EN | DPC_CR_N_AVG_W(n_avg) | DPC_CR_IN_SEL_W(input));
}
static int uplink_calibrator_measure(int *phase_raw)
{
uint32_t rval;
rval = shw_clkb_read_reg(CLKB_BASE_CALIBRATOR + DPC_REG_SR);
fprintf(stderr,"UplinkCalMeas: rval %x cr %x\n", rval, shw_clkb_read_reg(CLKB_BASE_CALIBRATOR+DPC_REG_CR));
if(rval & DPC_SR_PS_RDY)
{
shw_clkb_write_reg(CLKB_BASE_CALIBRATOR + DPC_REG_SR, 0xffffffff);
*phase_raw = (rval & (1<<23) ? 0xff000000 | rval : (rval & 0xffffff));
return 1;
}
return 0;
}
static int downlink_calibrator_measure(int *phase_raw)
{
uint32_t rval;
rval = _fpga_readl(FPGA_BASE_CALIBRATOR + DPC_REG_SR);
if(rval & DPC_SR_PS_RDY)
{
_fpga_writel(FPGA_BASE_CALIBRATOR + DPC_REG_SR, 0xffffffff);
*phase_raw = (rval & (1<<23) ? 0xff000000 | rval : (rval & 0xffffff));
return 1;
}
return 0;
}
static int decode_port_name(const char *if_name, int *type, int *index)
{
if(strlen(if_name) != 4)
return -1;
if( if_name[3] < '0' || if_name[3] > '7')
return -1;
*index = if_name[3] - '0';
if(!strncmp(if_name, "wru", 3))
*type = PORT_UPLINK;
else if(!strncmp(if_name, "wrd", 3))
*type = PORT_DOWNLINK;
else return -1;
return 0;
}
static int do_net_ioctl(const char *if_name, int request, void *data)
{
struct ifreq ifr;
ifr.ifr_addr.sa_family = AF_PACKET;
strcpy(ifr.ifr_name, if_name);
ifr.ifr_data = data;
int rv = ioctl(cal_socket, request, &ifr);
return rv;
}
int shw_cal_init()
{
TRACE(TRACE_INFO,"Initializing PHY calibrators...");
cal_in_progress = 0;
// create a raw socket for calibration/DMTD readout
cal_socket = socket(AF_PACKET, SOCK_DGRAM, 0);
if(cal_socket < 0)
return -1;
return xpoint_configure();
}
int shw_cal_enable_pattern(const char *if_name, int enable)
{
int type, index, rval;
struct wrmch_calibration_req crq;
// TRACE(TRACE_INFO,"port %s enable %d", if_name, enable);
if((rval=decode_port_name(if_name, &type, &index)) < 0) return rval;
crq.cmd = enable ? CAL_CMD_TX_ON : CAL_CMD_TX_OFF;
if(type == PORT_UPLINK)
{
if(do_net_ioctl(if_name, PRIV_IOCGCALIBRATE, &crq) < 0)
{
TRACE(TRACE_ERROR, "Can't send TX calibration pattern");
return -1;
}
}
return 0;
}
int shw_cal_enable_feedback(const char *if_name, int enable, int lane)
{
int type, index, rval;
struct wrmch_calibration_req crq;
// TRACE(TRACE_INFO,"port %s enable %d lane %d", if_name, enable, lane);
if((rval=decode_port_name(if_name, &type, &index)) < 0) return rval;
// TRACE(TRACE_INFO, "enable_feedback type:%d index:%d\n", type, index);
cal_current_lane = lane;
cal_current_port_index = index;
cal_current_port_type = type;
strcpy(cal_current_if, if_name);
if(type == PORT_UPLINK)
{
if(enable)
{
switch(lane)
{
case PHY_CALIBRATE_TX:
cal_in_progress = 1;
xpoint_cal_feedback(1, index, 0); // enable PHY TX line feedback
// TRACE(TRACE_INFO, "TX index %d", index);
uplink_calibrator_configure(CAL_DMTD_AVERAGING_STEPS, lane, index);
break;
case PHY_CALIBRATE_RX:
cal_in_progress = 1;
xpoint_cal_feedback(1, index, 1); // enable PHY RX line feedback
crq.cmd = CAL_CMD_RX_ON;
if(do_net_ioctl(if_name, PRIV_IOCGCALIBRATE, &crq) < 0)
{
TRACE(TRACE_ERROR, "Can't enable RX calibration pattern");
return -1;
}
// crq.cmd = CAL_CMD_TX_ON;
// if(do_net_ioctl(if_name, &crq) < 0) return -1;
uplink_calibrator_configure(CAL_DMTD_AVERAGING_STEPS, lane, index);
break;
}
} else { // enable == 0
TRACE(TRACE_INFO, "Disabling calibration on port: %s", if_name);
cal_in_progress = 0;
xpoint_cal_feedback(0, 0, 0);
if(lane == PHY_CALIBRATE_TX)
{
crq.cmd = CAL_CMD_TX_OFF;
if(do_net_ioctl(if_name, PRIV_IOCGCALIBRATE, &crq) < 0) return -1;
} else if (lane == PHY_CALIBRATE_RX)
{
crq.cmd = CAL_CMD_RX_OFF;
if(do_net_ioctl(if_name, PRIV_IOCGCALIBRATE, &crq) < 0) return -1;
}
}
} else if(type == PORT_DOWNLINK)
{
TRACE(TRACE_ERROR, "Sorry, no downlinks support yet...\n");
return -1;
}
}
int shw_cal_measure(uint32_t *phase)
{
int phase_raw;
struct wrmch_calibration_req crq;
if(!cal_in_progress)
return -1;
if(cal_current_port_type == PORT_UPLINK)
{
switch(cal_current_lane)
{
case PHY_CALIBRATE_TX:
fprintf(stderr,"CalTxMeasUplink\n");
if(uplink_calibrator_measure(&phase_raw))
{
*phase = (uint32_t) ((double) phase_raw / (double) CAL_DMTD_AVERAGING_STEPS / (double)shw_hpll_get_divider() * 8000.0);
return 1;
} else return 0;
break;
case PHY_CALIBRATE_RX:
crq.cmd = CAL_CMD_RX_CHECK;
if(do_net_ioctl(cal_current_if, PRIV_IOCGCALIBRATE, &crq) < 0) return -1;
if(crq.cal_present && uplink_calibrator_measure(&phase_raw))
{
*phase = (uint32_t) ((double) phase_raw / (double) CAL_DMTD_AVERAGING_STEPS / (double)shw_hpll_get_divider() * 8000.0);
return 1;
} else return 0;
break;
}
} else {
// TRACE(TRACE_ERROR, "Sorry, no downlinks support yet...\n");
return -1;
}
}
int shw_poll_dmtd(const char *if_name, uint32_t *phase_ps)
{
struct wrmch_phase_req phr;
int r;
r = do_net_ioctl(if_name, PRIV_IOCGGETPHASE, &phr);
if(r < 0)
{
TRACE(TRACE_ERROR, "failed ioctl(PRIV_IOCGGETPHASE): retval %d\n", r);
return -1;
}
if(!phr.ready) // No valid DMTD measurement?
return 0;
// TRACE(TRACE_INFO,"%s: phase %d", if_name, phr.phase);
*phase_ps = (uint32_t) ((double)phr.phase / (double)shw_hpll_get_divider() * 8000.0);
return 1;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <inttypes.h>
#include <fcntl.h>
#include <hw/pio.h>
#include <hw/fpga_regs.h>
#include <hw/trace.h>
static const pio_pin_t pck_port_mapping[] =
{
{PIOA, 13, PIO_MODE_PERIPH_B, PIO_OUT},
{PIOB, 10, PIO_MODE_PERIPH_B, PIO_OUT},
{PIOA, 6, PIO_MODE_PERIPH_B, PIO_OUT},
{PIOE, 11, PIO_MODE_PERIPH_B, PIO_OUT},
{0}
};
volatile uint8_t *_pio_base[4][NUM_PIO_BANKS+1];
volatile uint8_t *_sys_base;
int shw_pio_mmap_init()
{
int i;
int fd = open("/dev/mem", O_RDWR);
if (!fd)
{
TRACE(TRACE_FATAL, "can't open /dev/mem! (no root?)");
exit(-1);
}
_sys_base = mmap(NULL, 0x2000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, AT91_BASE_SYS);
if (_sys_base == NULL)
{
TRACE(TRACE_FATAL, "can't mmap CPU GPIO regs");
close(fd);
exit(-1);
}
TRACE(TRACE_INFO, "AT91_SYS virtual base = 0x%08x", _sys_base);
// fprintf(stderr,"AT91_SYS mmapped to: 0x%08x\n", _sys_base);
_pio_base[REG_BASE][PIOA] = _sys_base + AT91_PIOA;
_pio_base[REG_BASE][PIOB] = _sys_base + AT91_PIOB;
_pio_base[REG_BASE][PIOC] = _sys_base + AT91_PIOC;
_pio_base[REG_BASE][PIOD] = _sys_base + AT91_PIOD;
_pio_base[REG_BASE][PIOE] = _sys_base + AT91_PIOE;
for (i=1; i<=5; i++)
{
_pio_base [REG_CODR][i] = _pio_base[REG_BASE][i] + PIO_CODR;
_pio_base [REG_SODR][i] = _pio_base[REG_BASE][i] + PIO_SODR;
_pio_base [REG_PDSR][i] = _pio_base[REG_BASE][i] + PIO_PDSR;
}
_pio_base[REG_BASE][PIO_FPGA] = _fpga_base_virt + FPGA_BASE_GPIO;
_pio_base[REG_CODR][PIO_FPGA] = _fpga_base_virt + FPGA_BASE_GPIO + GPIO_REG_CODR;
_pio_base[REG_SODR][PIO_FPGA] = _fpga_base_virt + FPGA_BASE_GPIO + GPIO_REG_SODR;
_pio_base[REG_PDSR][PIO_FPGA] = _fpga_base_virt + FPGA_BASE_GPIO + GPIO_REG_PSR;
return 0;
}
int shw_pio_configure_all_cpu_pins()
{
int i;
TRACE(TRACE_INFO,"Configuring CPU PIO pins...");
for(i=0; _all_cpu_gpio_pins[i]; i++)
{
shw_pio_configure_pins(_all_cpu_gpio_pins[i]);
}
TRACE(TRACE_INFO,"...done!");
}
int shw_pio_configure_all_fpga_pins()
{
int i;
TRACE(TRACE_INFO,"Configuring FPGA PIO pins...");
for(i=0; _all_fpga_gpio_pins[i]; i++)
{
shw_pio_configure_pins(_all_fpga_gpio_pins[i]);
}
TRACE(TRACE_INFO,"...done!");
}
void shw_pio_configure(const pio_pin_t *pin)
{
uint32_t mask = (1<<pin->pin);
uint32_t ddr;
volatile uint8_t *base = (_pio_base[REG_BASE][pin->port]);
switch (pin->port)
{
case PIOA:
case PIOB:
case PIOC:
case PIOD:
case PIOE:
// TRACE(TRACE_INFO, "-- configure CPU PIO PIN: P%c.%d base=0x%x", pin->port-PIOA+'A', pin->pin, base);
_writel(base + PIO_IDR, mask); // disable irq
if (pin->mode & PIO_MODE_PULLUP)
_writel(base + PIO_PUER, mask);// enable pullup
else
_writel(base + PIO_PUDR, mask); // disable pullup
switch (pin->mode & 0x3)
{
case PIO_MODE_GPIO:
_writel(base + PIO_PER, mask); // enable gpio mode
break;
case PIO_MODE_PERIPH_A:
_writel(base + PIO_PDR, mask); // disable gpio mode
_writel(base + PIO_ASR, mask); // select peripheral A
break;
case PIO_MODE_PERIPH_B:
_writel(base + PIO_PDR, mask); // disable gpio mode
_writel(base + PIO_BSR, mask); // select peripheral B
break;
}
if (pin->dir == PIO_OUT_1)
{
_writel(base + PIO_SODR, mask);
_writel(base + PIO_OER, mask); // select output, set it to 1
} else if (pin->dir == PIO_OUT_0)
{
_writel(base + PIO_CODR, mask);
_writel(base + PIO_OER, mask); // select output, set it to 0
} else {
_writel(base + PIO_ODR, mask); // select input
}
break;
case PIO_FPGA:
// TRACE(TRACE_INFO, "-- configure FPGA PIO PIN: P%d", pin->pin);
ddr = _readl(base + GPIO_REG_DDR);
if (pin->dir == PIO_OUT_1)
{
_writel(base + GPIO_REG_SODR, mask);
ddr |= mask;
} else if (pin->dir == PIO_OUT_0)
{
_writel(base + GPIO_REG_CODR, mask);
ddr |= mask;
} else
ddr &= ~mask;
_writel(base + GPIO_REG_DDR, ddr);
break;
}
}
void shw_pio_configure_pins(const pio_pin_t *pins)
{
while (pins->port)
{
shw_pio_configure(pins);
pins++;
}
}
int shw_clock_out_enable(int pck_num, int prescaler, int source)
{
if (pck_num > 3) return -1;
shw_pio_configure(&pck_port_mapping[pck_num]);
_writel(_sys_base + AT91_PMC_PCKR(pck_num), source | prescaler);
_writel(_sys_base + AT91_PMC_SCER, (1<< (8+pck_num)));
return 0;
}
volatile uint8_t *shw_pio_get_sys_base()
{
return _sys_base;
}
volatile uint8_t *shw_pio_get_port_base(int port)
{
return _pio_base[REG_BASE][port];
}
void shw_set_fp_led(int led, int state)
{
if(state == LED_GREEN)
{
shw_pio_set(&_fp_leds[led][0], 1);
shw_pio_set(&_fp_leds[led][1], 0);
} else if(state == LED_RED) {
shw_pio_set(&_fp_leds[led][0], 0);
shw_pio_set(&_fp_leds[led][1], 1);
} else {
shw_pio_set(&_fp_leds[led][0], 1);
shw_pio_set(&_fp_leds[led][1], 1);
}
}
#include <hw/pio.h>
#define LED_OFF 0
#define LED_RED 1
#define LED_GREEN 2
#define LED_YELLOW 3
// definitions of commonly used pins
// reset signal for main FPGA
const pio_pin_t PIN_main_fpga_nrst[] = {{ PIOB, 20, PIO_MODE_GPIO, PIO_OUT }, {0}};
// Front panel LEDs
const pio_pin_t PIN_fled0[] = {{PIOC, 5, PIO_MODE_GPIO, PIO_OUT_1},
{PIOC, 12, PIO_MODE_GPIO, PIO_OUT_1},
{0}
};
const pio_pin_t PIN_fled1[] = {{PIOC, 7, PIO_MODE_GPIO, PIO_OUT_1},
{PIOC, 19, PIO_MODE_GPIO, PIO_OUT_1},
{0}
};
const pio_pin_t PIN_fled2[] = {{PIOC, 9, PIO_MODE_GPIO, PIO_OUT_1},
{PIOC, 17, PIO_MODE_GPIO, PIO_OUT_1},
{0}
};
const pio_pin_t PIN_fled3[] = {{PIOC, 14, PIO_MODE_GPIO, PIO_OUT_1},
{PIOC, 6, PIO_MODE_GPIO, PIO_OUT_1},
{0}
};
const pio_pin_t PIN_fled4[] = {{PIO_FPGA, 0, PIO_MODE_GPIO, PIO_OUT_1},
{PIO_FPGA, 1, PIO_MODE_GPIO, PIO_OUT_1},
{0}
};
const pio_pin_t PIN_fled5[] = {{PIO_FPGA, 2, PIO_MODE_GPIO, PIO_OUT_1},
{PIO_FPGA, 3, PIO_MODE_GPIO, PIO_OUT_1},
{0}
};
const pio_pin_t PIN_fled6[] = {{PIO_FPGA, 4, PIO_MODE_GPIO, PIO_OUT_1},
{PIO_FPGA, 5, PIO_MODE_GPIO, PIO_OUT_1},
{0}
};
const pio_pin_t PIN_fled7[] = {{PIO_FPGA, 6, PIO_MODE_GPIO, PIO_OUT_1},
{PIO_FPGA, 7, PIO_MODE_GPIO, PIO_OUT_1},
{0}
};
// uTCA front panel LEDs
const pio_pin_t PIN_uled0[] = {{PIOC, 11, PIO_MODE_GPIO, PIO_OUT}, {0}};
const pio_pin_t PIN_uled1[] = {{PIOC, 15, PIO_MODE_GPIO, PIO_OUT}, {0}};
const pio_pin_t PIN_uled2[] = {{PIOC, 18, PIO_MODE_GPIO, PIO_OUT}, {0}};
const pio_pin_t PIN_uled3[] = {{PIOC, 13, PIO_MODE_GPIO, PIO_OUT}, {0}};
// AD9516 PLL control signals
const pio_pin_t PIN_ad9516_cs[] = {{PIOC, 10, PIO_MODE_GPIO, PIO_OUT_1 }, {0} }; // clkb_cpupin3 -> pc10
const pio_pin_t PIN_ad9516_sclk[] = {{PIOC, 16, PIO_MODE_GPIO, PIO_OUT_1 }, {0} }; // clkb_cpupin1 -> pc16
const pio_pin_t PIN_ad9516_sdio[] = {{PIOB, 30, PIO_MODE_GPIO, PIO_OUT_1 }, {0} }; // clkb_cpupin5 -> pb30
const pio_pin_t PIN_ad9516_sdo[] = {{PIOC, 8, PIO_MODE_GPIO, PIO_IN }, {0} }; // clkb_cpupin0 -> pc8
const pio_pin_t PIN_ad9516_refsel[] = {{PIOB, 26, PIO_MODE_GPIO, PIO_OUT_0 }, {0} }; // clkb_cpupin4 -> pb26
const pio_pin_t PIN_ad9516_nrst[] = {{PIOC, 3, PIO_MODE_GPIO, PIO_OUT_1 }, {0} }; // clkb_cpupin2 -> pc3
// uTCA Hotswap switch
const pio_pin_t PIN_hotswap_switch[] = {{PIOC, 1, PIO_MODE_GPIO, PIO_IN }, {0} };
// main FPGA passive serial configuration signals
const pio_pin_t PIN_main_fpga_dclk[] = {{ PIOB, 1, PIO_MODE_GPIO, PIO_OUT_1}, {0}};
const pio_pin_t PIN_main_fpga_nconfig[] = {{ PIOB, 22, PIO_MODE_GPIO, PIO_OUT_1}, {0}};
const pio_pin_t PIN_main_fpga_data[] = {{ PIOB, 2, PIO_MODE_GPIO, PIO_OUT_1}, {0}};
const pio_pin_t PIN_main_fpga_nstatus[] = {{ PIOB, 31, PIO_MODE_GPIO, PIO_IN}, {0}};
const pio_pin_t PIN_main_fpga_confdone[] = {{ PIOB, 18, PIO_MODE_GPIO, PIO_IN}, {0}}; // INVERTED!
// clocking board FPGA passive serial configuration signals
const pio_pin_t PIN_clkb_fpga_dclk[] = {{ PIOB, 7, PIO_MODE_GPIO, PIO_OUT_1}, {0}};
const pio_pin_t PIN_clkb_fpga_nconfig[] = {{ PIOB, 23, PIO_MODE_GPIO, PIO_OUT_1}, {0}};
const pio_pin_t PIN_clkb_fpga_data[] = {{ PIOB, 8, PIO_MODE_GPIO, PIO_OUT_1}, {0}};
const pio_pin_t PIN_clkb_fpga_nstatus[] = {{ PIOB, 28, PIO_MODE_GPIO, PIO_IN}, {0}};
const pio_pin_t PIN_clkb_fpga_confdone[] = {{ PIOB, 24, PIO_MODE_GPIO, PIO_IN}, {0}}; // INVERTED!
const pio_pin_t PIN_clkb_fpga_nrst[] = {{ PIOB, 25, PIO_MODE_GPIO, PIO_OUT_0}, {0}};
const pio_pin_t PIN_up0_sfp_sda[] = {{PIO_FPGA, 8, PIO_MODE_GPIO, PIO_OUT_1}, {0}};
const pio_pin_t PIN_up0_sfp_scl[] = {{PIO_FPGA, 9, PIO_MODE_GPIO, PIO_OUT_1}, {0}};
const pio_pin_t PIN_up0_sfp_los[] = {{PIO_FPGA, 10, PIO_MODE_GPIO, PIO_IN}, {0}};
const pio_pin_t PIN_up0_sfp_tx_fault[] = {{PIO_FPGA, 11, PIO_MODE_GPIO, PIO_IN}, {0}};
const pio_pin_t PIN_up0_sfp_tx_disable[] = {{PIO_FPGA, 12, PIO_MODE_GPIO, PIO_OUT_0}, {0}};
const pio_pin_t PIN_up0_sfp_detect[] = {{PIO_FPGA, 13, PIO_MODE_GPIO, PIO_IN}, {0}};
const pio_pin_t PIN_up1_sfp_sda[] = {{PIO_FPGA, 18, PIO_MODE_GPIO, PIO_OUT_1}, {0}};
const pio_pin_t PIN_up1_sfp_scl[] = {{PIO_FPGA, 19, PIO_MODE_GPIO, PIO_OUT_1}, {0}};
const pio_pin_t PIN_up1_sfp_los[] = {{PIO_FPGA, 20, PIO_MODE_GPIO, PIO_IN}, {0}};
const pio_pin_t PIN_up1_sfp_tx_fault[] = {{PIO_FPGA, 21, PIO_MODE_GPIO, PIO_IN}, {0}};
const pio_pin_t PIN_up1_sfp_tx_disable[] = {{PIO_FPGA, 22, PIO_MODE_GPIO, PIO_OUT_0}, {0}};
const pio_pin_t PIN_up1_sfp_detect[] = {{PIO_FPGA, 23, PIO_MODE_GPIO, PIO_IN}, {0}};
const pio_pin_t * _all_cpu_gpio_pins[] =
{
PIN_fled0,
PIN_fled1,
PIN_fled2,
PIN_fled3,
PIN_uled0,
PIN_uled1,
PIN_uled2,
PIN_uled3,
PIN_hotswap_switch,
NULL
};
const pio_pin_t * _all_fpga_gpio_pins[] =
{
PIN_fled4,
PIN_fled5,
PIN_fled6,
PIN_fled7,
PIN_up0_sfp_sda,
PIN_up0_sfp_scl,
PIN_up0_sfp_los,
PIN_up0_sfp_tx_fault,
PIN_up0_sfp_tx_disable,
PIN_up0_sfp_detect,
PIN_up1_sfp_sda,
PIN_up1_sfp_scl,
PIN_up1_sfp_los,
PIN_up1_sfp_tx_fault,
PIN_up1_sfp_tx_disable,
PIN_up1_sfp_detect,
NULL
};
const pio_pin_t * _fp_leds[] =
{
PIN_fled0,
PIN_fled1,
PIN_fled2,
PIN_fled3,
PIN_fled4,
PIN_fled5,
PIN_fled6,
PIN_fled7
};
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <sys/time.h>
#include <hw/clkb_io.h>
#include <hw/pps_gen_regs.h>
#include <hw/switch_hw.h>
#include <hw/trace.h>
#define PPS_WIDTH 100000
int shw_pps_gen_init()
{
uint32_t cr;
cr = PPSG_CR_CNT_EN | PPSG_CR_PWIDTH_W(PPS_WIDTH);
TRACE(TRACE_INFO, "Initializing PPS generator...");
_fpga_writel(FPGA_BASE_PPS_GEN + PPSG_REG_CR, cr);
_fpga_writel(FPGA_BASE_PPS_GEN + PPSG_REG_ADJ_UTCLO, 1285700840);
_fpga_writel(FPGA_BASE_PPS_GEN + PPSG_REG_ADJ_UTCHI, 0);
_fpga_writel(FPGA_BASE_PPS_GEN + PPSG_REG_ADJ_NSEC, 0);
_fpga_writel(FPGA_BASE_PPS_GEN + PPSG_REG_CR, cr | PPSG_CR_CNT_SET);
_fpga_writel(FPGA_BASE_PPS_GEN + PPSG_REG_CR, cr);
}
int shw_pps_gen_adjust_nsec(int32_t how_much)
{
uint32_t cr;
TRACE(TRACE_INFO, "AdjustPPS: %d nanoseconds", how_much);
_fpga_writel(FPGA_BASE_PPS_GEN + PPSG_REG_ADJ_UTCLO, 0);
_fpga_writel(FPGA_BASE_PPS_GEN + PPSG_REG_ADJ_UTCHI, 0);
_fpga_writel(FPGA_BASE_PPS_GEN + PPSG_REG_ADJ_NSEC, ( how_much / 8 ));
_fpga_writel(FPGA_BASE_PPS_GEN + PPSG_REG_CR, PPSG_CR_CNT_EN | PPSG_CR_PWIDTH_W(PPS_WIDTH) | PPSG_CR_CNT_ADJ);
}
int shw_pps_gen_adjust_utc(int64_t how_much)
{
uint32_t cr;
TRACE(TRACE_INFO, "AdjustUTC: %lld seconds", how_much);
_fpga_writel(FPGA_BASE_PPS_GEN + PPSG_REG_ADJ_UTCLO, (uint32_t) (how_much & 0xffffffffLL));
_fpga_writel(FPGA_BASE_PPS_GEN + PPSG_REG_ADJ_UTCHI, (uint32_t) (how_much >> 32));
_fpga_writel(FPGA_BASE_PPS_GEN + PPSG_REG_ADJ_NSEC, 0);
_fpga_writel(FPGA_BASE_PPS_GEN + PPSG_REG_CR, PPSG_CR_CNT_EN | PPSG_CR_PWIDTH_W(PPS_WIDTH) | PPSG_CR_CNT_ADJ);
}
int shw_pps_gen_busy()
{
return _fpga_readl(FPGA_BASE_PPS_GEN + PPSG_REG_CR) & PPSG_CR_CNT_ADJ ? 0 : 1;
}
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <hw/trace.h>
static FILE *trace_file = NULL;
static int trace_to_stderr = 0;
void trace_log_stderr()
{
trace_to_stderr = 1;
}
void trace_log_file(const char *filename)
{
trace_file = fopen(filename, "wb");
}
void trace_printf(const char *fname, int lineno, int level, const char *fmt, ...)
{
char linestr[40];
char typestr[10];
va_list vargs;
switch (level)
{
case TRACE_INFO: strcpy(typestr, "(I)"); break;
case TRACE_ERROR: strcpy(typestr, "(E)"); break;
case TRACE_FATAL: strcpy(typestr, "(!)"); break;
default: strcpy(typestr, "(?)"); break;
}
snprintf(linestr, 40, "%s [%s:%d]", typestr, fname, lineno);
va_start(vargs, fmt);
if(trace_file)
{
fprintf(trace_file, "%-24s ", linestr);
vfprintf(trace_file, fmt, vargs);
fflush(trace_file);
fprintf(trace_file,"\n");
}
if(trace_to_stderr)
{
fprintf(stderr, "%-24s ", linestr);
vfprintf(stderr, fmt, vargs);
fprintf(stderr,"\n");
}
va_end(vargs);
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <hw/trace.h>
#include <hw/util.h>
void shw_udelay(uint32_t microseconds)
{
uint64_t t_start, t_cur;
struct timeval tv;
gettimeofday(&tv, NULL);
t_start = (uint64_t) tv.tv_sec * 1000000ULL + (uint64_t)tv.tv_usec;
do {
gettimeofday(&tv, NULL);
t_cur = (uint64_t) tv.tv_sec * 1000000ULL + (uint64_t)tv.tv_usec;
} while(t_cur <= t_start + (uint64_t) microseconds);
}
void *shw_malloc(size_t nbytes)
{
void *p = malloc(nbytes);
if(!p)
{
TRACE(TRACE_FATAL, "malloc(%d) failed!", nbytes);
exit(-1);
}
return p;
}
void shw_free(void *ptr)
{
free(ptr);
}
uint64_t shw_get_tics()
{
struct timeval tv;
struct timezone tz={0,0};
gettimeofday(&tv, &tz);
return (uint64_t)tv.tv_usec + (uint64_t)tv.tv_sec * 1000000ULL;
}
This diff is collapsed.
This diff is collapsed.
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