Commit 55c40f75 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

userspace: stripped down libswitchhw to a bare minimum

parent df8edea4
......@@ -3,9 +3,7 @@ CC = $(CROSS_COMPILE)gcc
AR = $(CROSS_COMPILE)ar
CFLAGS = -I. -O2 -I../include -DDEBUG -I./minilzo
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 \
mblaster.o pps_gen.o
OBJS = trace.o init.o fpga_io.o util.o pps_gen.o
LIB = libswitchhw.a
......
/* Analog Devices AD9516-4 PLL driver */
#include <math.h>
#include <hw/pio.h>
#include <hw/trace.h>
#include <hw/ad9516.h>
/* SPI bit delay, in microseconds */
#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);
/* for the standard PLL setups - generated by Analog Devices' software */
#include "ad9516_default_regs.h"
/* Indicates whether to generate the reference clock from the local VCTCXO (0)
or the external 10 MHz input (cesium, etc. - 1) */
static int use_ext_ref = 0;
/* Enables/disables locking the 125 MHz reference clock to an externally provided
10 Mhz Reference (when enable = 1). Otherwise, the reference clock is produced
from the local voltage controlled oscillator (which can be locked by the DMPLL
to a reference from one of the uplink ports.
Note: can *ONLY* be called before initializing the libswitchhw. Reference source
cannot be switched on-the-fly. */
int shw_use_external_reference(int enable)
{
if(enable)
TRACE(TRACE_INFO, "Using external 10 MHz reference clock (grandmaster mode)");
use_ext_ref = enable;
}
/* Reads a byte from the AD9516 SPI interface by bit-banging the CPU pins */
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;
}
/* Writes a byte (tx) to the AD9516 SPI interface by bit-banging the CPU pins */
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);
}
/* Reads an AD9516 register from address addr and returns its 8-bit value */
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;
}
/* Writes AD9516 register located at addr with value data */
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);
}
/* Performs a HW reset of the AD9516 by asserting it's RSTN pin */
static void ad9516_reset()
{
shw_pio_set0(PIN_ad9516_nrst);
shw_udelay(100);
shw_pio_set1(PIN_ad9516_nrst);
shw_udelay(100);
}
/* Checks for the presence of 10 MHz external reference signal on the AD9516 ref input.
Returns non-zero if the signal is present. */
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) ;
}
/* Loads and updates the configuration provided in "regs" into the AD9516. */
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);
/* Trigger the actual register reload (regs are just buffered after being written),
in order to load the new values simultaneously one must trigger an update. */
ad9516_write_reg(AD9516_UPDATE_ALL, 1);
return 0;
}
/* Checks if the PLL is locked (digital lock detection). Returns non-zero if true */
static int ad9516_check_lock()
{
uint8_t pll_readback = ad9516_read_reg(AD9516_PLLREADBACK);
return pll_readback & 1;
}
#define assert_init(proc) { int ret; if((ret = proc) < 0) return ret; }
/* Initializes the AD9516: sets up the reference source, PLL multiply/divide ratios,
enables clock outputs. */
int shw_ad9516_init()
{
int retries = 100;
TRACE(TRACE_INFO, "Initializing AD9516 PLL....");
/* The AD9516 uses CPU GPIO pins (it couldn't be connected to the FPGA,
because it supplies clock for it (and a clock-less FPGA wouldn't work). */
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);
/* Make sure the pins are stable after the configuration (no glitches, etc.) */
shw_udelay(100);
/* Reset AD9516 and give it some time to recover */
ad9516_reset();
shw_udelay(10000);
/* Detect the presence by comparing a read register with it's reset value */
if(ad9516_read_reg(AD9516_SERIALPORT) != 0x18)
{
TRACE(TRACE_FATAL, "AD9516 not responding!");
return -1;
}
/* Now just initialize. There are two pre-defined register sets, one for
the internal 25 MHz VCTCXO and the other for 10 MHz GPS/Cesium external reference */
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);
}
/* Signal integrity bugfix: delay Uplink 0 PHY clock a bit (to increase tSetup on
the PHY TX inputs */
shw_ad9516_set_output_delay(9, 0.5, 0);
return 0;
}
/* Finds the parameters of the output skew adjustment unit of AD9516 for a given delay value. */
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;
}
}
}
}
}
/* Sets the extra delay on given output to delay_ns. Used for de-skewing clocks.
When bypass is 1, the delay block is disabled. */
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 );
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;
}
/* Pre-defined AD9516 PLL configs, both for 25 MHz TCXO and external 10 MHz reference. */
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
/* Routines for accessing the timing FPGA */
#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
/* Some protos */
int shw_clkb_write_reg(uint32_t reg, uint32_t val);
uint32_t shw_clkb_read_reg(uint32_t reg);
/* Initializes the SPI link between the main FPGA and the timing FPGA.
clkdiv = SPI SCLK division ratio. */
static void cmi_init(int clkdiv)
{
uint32_t val = SPICTL_ENABLE(1) | SPICTL_CLKDIV(clkdiv);
_fpga_writel(FPGA_BASE_SPIM+SPI_REG_SPICTL, val);
}
/* Returns non-zero if the SPI controller is busy sending/receiving data */
static inline int cmi_busy()
{
uint32_t ctl;
ctl = _fpga_readl(FPGA_BASE_SPIM+SPI_REG_SPICTL);
return SPICTL_BUSY(ctl);
}
/* Enables (cs=1) or disables (cs=1) the SPI chip-select line */
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);
}
/* Sends/receives a number (n) of 32-bit words (d_in) to/from the timing
FPGA. Received words are stored in (d_out). */
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);
}
/* Initializes the Inter-FPGA link (just the link, not the timing FPGA). */
int shw_clkb_init_cmi()
{
TRACE(TRACE_INFO, "initializing Clocking Mezzanine Interface");
cmi_init(SPI_CLKDIV_VAL);
return 0;
}
/* Initializes the Timing FPGA. Currently the initialization is just
resetting the chip. */
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);
}
/* Writes a 32-bit value (val) to the register (reg) in the Timing FPGA.
Returns 0 on success. */
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;
}
/* Reads the value of a 32-bit register (reg) from the Timing FPGA and
returns it. */
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];
}
/* Userspace /dev/mem I/O functions for accessing the Main FPGA */
#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
/* Virtual base address of the Main FPGA address space. */
volatile uint8_t *_fpga_base_virt;
/* Initializes the mapping of the Main FPGA to the CPU address space. */
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;
}
/* Resets the Main FPGA. */
void shw_main_fpga_reset()
{
shw_pio_set0(PIN_main_fpga_nrst);
usleep(10000);
shw_pio_set1(PIN_main_fpga_nrst);
usleep(10000);
}
/* Initializes the Main FPGA - that means (currently) just resetting it. */
int shw_main_fpga_init()
{
shw_pio_configure(PIN_main_fpga_nrst);
shw_main_fpga_reset();
return 0;
}
......@@ -11,31 +11,7 @@ int shw_init()
{
/* Map the the FPGA memory space */
assert_init(shw_fpga_mmap_init());
/* Map the CPU GPIO memory space */
assert_init(shw_pio_mmap_init());
/* Initialize the AD9516 and the clock distribution. Now we can start accessing the FPGAs. */
assert_init(shw_ad9516_init());
/* Initialize the main FPGA */
assert_init(shw_main_fpga_init());
/* Sets up the directions of all CPU GPIO pins */
assert_init(shw_pio_configure_all_cpu_pins());
/* Initialize the bootloader and try to boot up the Main FPGA. */
assert_init(shw_fpgaboot_init());
assert_init(shw_boot_fpga(FPGA_ID_MAIN));
/* Initialize the main FPGA and its GPIO controller */
assert_init(shw_main_fpga_init());
assert_init(shw_pio_configure_all_fpga_pins());
/* Initialize the CMI link prior to booting the CLKB FPGA, so the FPGA bootloader could check the REVID. */
assert_init(shw_clkb_init_cmi());
/* Boot up and init the Timing FPGA */
assert_init(shw_boot_fpga(FPGA_ID_CLKB));
assert_init(shw_clkb_init());
/* Start-up the PLLs. */
/* no more shw_hpll_init(); */
/* no more shw_dmpll_init(); */
/* Initialize the calibrator (requires the DMTD clock to be operational) */
/* no more shw_cal_init(); */
/* Start-up the PPS generator */
assert_init(shw_pps_gen_init());
/* ... and the SPI link with the watchdog */
/* no more shw_watchdog_init(); */
......
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 <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);
}
}
/* GPIO pin definitions */
#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 <stdlib.h>
#include <sys/time.h>
#include <hw/switch_hw.h>
#include <hw/trace.h>
#include <hw/clkb_io.h>
#include <hw/pio.h>
// The I2C bus which goes to ADN4600 is currently connected to the GPIO pins of CLKB FPGA.
#define MASK_SCL_OUT (1<<0)
#define MASK_SDA_OUT (1<<1)
#define MASK_SCL_IN (1<<2)
#define MASK_SDA_IN (1<<3)
#define M_SDA_OUT(x) { \
if(x) \
shw_clkb_write_reg(CLKB_BASE_GPIO + GPIO_REG_SODR, MASK_SDA_OUT); \
else \
shw_clkb_write_reg(CLKB_BASE_GPIO + GPIO_REG_CODR, MASK_SDA_OUT); \
}
#define M_SCL_OUT(x) { \
if(x) \
shw_clkb_write_reg(CLKB_BASE_GPIO + GPIO_REG_SODR, MASK_SCL_OUT); \
else \
shw_clkb_write_reg(CLKB_BASE_GPIO + GPIO_REG_CODR, MASK_SCL_OUT); \
}
#define M_SDA_IN (shw_clkb_read_reg(CLKB_BASE_GPIO + GPIO_REG_PSR) & MASK_SDA_IN)
// ADN4600 register addresses
#define ADN4600_ADDR 0x90
#define ADN4600_RESET 0x0
#define ADN4600_XPT_CONFIG 0x40
#define ADN4600_XPT_UPDATE 0x41
#define ADN4600_RX_CONFIG(channel) (0x80 + channel * 8)
#define ADN4600_TX_CONFIG(channel) (((channel<4)?(0xc0 + channel * 8) : (0xe0 + (7-channel)*8)))
// crosspoint I/O map:
// up0 tx -> IN1 inverted
// up1 tx -> IN0 inverted
// sfp0 tx -> IN2 inverted
// sfp1 tx -> IN3 inverted
// up0 rx <- OUT0
// up1 rx <- OUT1
// sfp0 rx <- OUT7
// sfp1 rx <- OUT6
// feedback <- OUT3
#define XPT_UP0_TX 1
#define XPT_UP1_TX 0
#define XPT_SFP0_TX 2
#define XPT_SFP1_TX 3
#define XPT_UP0_RX 0
#define XPT_UP1_RX 1
#define XPT_SFP0_RX 7
#define XPT_SFP1_RX 6
#define XPT_FEEDBACK 3
#define RX_CONFIG_PNSWAP 0x40
#define RX_CONFIG_RXEN 0x10
#define RX_CONFIG_EQBY 0x20
#define RX_CONFIG_RXEQ(eq) (eq&0x7)
#define TX_CONFIG_TXEN 0x20
#define TX_CONFIG_TXDR 0x10
#define TX_CONFIG_TXPE(pe) (pe&0x7)
static void mi2c_start()
{
M_SDA_OUT(0);
M_SCL_OUT(0);
}
static void mi2c_repeat_start()
{
M_SDA_OUT(1);
M_SCL_OUT(1);
M_SDA_OUT(0);
M_SCL_OUT(0);
}
static void mi2c_stop()
{
M_SDA_OUT(0);
M_SCL_OUT(1);
M_SDA_OUT(1);
}
static unsigned char mi2c_put_byte(unsigned char data)
{
char i;
unsigned char ack;
for (i=0;i<8;i++, data<<=1)
{
M_SDA_OUT(data&0x80);
M_SCL_OUT(1);
M_SCL_OUT(0);
}
M_SDA_OUT(1);
M_SCL_OUT(1);
ack = M_SDA_IN; /* ack: sda is pulled low ->success. */
M_SCL_OUT(0);
M_SDA_OUT(0);
return ack!=0;
}
static void mi2c_get_byte(unsigned char *data)
{
int i;
unsigned char indata = 0;
/* assert: scl is low */
M_SCL_OUT(0);
for (i=0;i<8;i++)
{
M_SCL_OUT(1);
indata <<= 1;
if ( M_SDA_IN ) indata |= 0x01;
M_SCL_OUT(0);
}
M_SDA_OUT(1);
*data= indata;
}
static void mi2c_init()
{
shw_clkb_write_reg(CLKB_BASE_GPIO + GPIO_REG_DDR, MASK_SCL_OUT | MASK_SDA_OUT);
M_SCL_OUT(1);
M_SDA_OUT(1);
}
static uint8_t adn4600_read_reg(uint8_t reg)
{
uint8_t rval;
mi2c_start();
if(mi2c_put_byte(ADN4600_ADDR)) goto rxerr;
if(mi2c_put_byte(reg)) goto rxerr;
mi2c_repeat_start();
if(mi2c_put_byte(ADN4600_ADDR|1)) goto rxerr;
mi2c_get_byte(&rval);
mi2c_stop();
return rval;
rxerr:
TRACE(TRACE_ERROR, "No I2C ack from ADN4600!");
mi2c_stop();
return 0;
}
static void adn4600_write_reg(uint8_t reg, uint8_t value)
{
uint8_t rval;
mi2c_start();
if(mi2c_put_byte(ADN4600_ADDR)) goto txerr;
if(mi2c_put_byte(reg)) goto txerr;
if(mi2c_put_byte(value)) goto txerr;
mi2c_stop();
txerr:
TRACE(TRACE_FATAL, "No I2C ack from ADN4600!");
mi2c_stop();
}
void xpoint_route(int in, int out)
{
adn4600_write_reg(ADN4600_XPT_CONFIG, (in<<4) | out);
adn4600_write_reg(ADN4600_XPT_UPDATE, 1);
}
int xpoint_configure()
{
TRACE(TRACE_INFO, "Initializing ADN4600 crosspoint");
mi2c_init();
adn4600_write_reg(ADN4600_RESET, 0x1);
// Uplink 1 TX
adn4600_write_reg(ADN4600_RX_CONFIG(0), RX_CONFIG_PNSWAP | RX_CONFIG_RXEN | RX_CONFIG_RXEQ(0));
adn4600_write_reg(ADN4600_RX_CONFIG(1), RX_CONFIG_PNSWAP | RX_CONFIG_RXEN | RX_CONFIG_RXEQ(0));
adn4600_write_reg(ADN4600_RX_CONFIG(2), RX_CONFIG_PNSWAP | RX_CONFIG_RXEN | RX_CONFIG_RXEQ(0));
adn4600_write_reg(ADN4600_RX_CONFIG(3), RX_CONFIG_PNSWAP | RX_CONFIG_RXEN | RX_CONFIG_RXEQ(0));
adn4600_write_reg(ADN4600_RX_CONFIG(4), 0);
adn4600_write_reg(ADN4600_RX_CONFIG(5), 0);
adn4600_write_reg(ADN4600_RX_CONFIG(6), 0);
adn4600_write_reg(ADN4600_RX_CONFIG(7), 0);
adn4600_write_reg(ADN4600_TX_CONFIG(0), TX_CONFIG_TXEN | TX_CONFIG_TXPE(0));
adn4600_write_reg(ADN4600_TX_CONFIG(1), TX_CONFIG_TXEN | TX_CONFIG_TXPE(0));
adn4600_write_reg(ADN4600_TX_CONFIG(6), TX_CONFIG_TXEN | TX_CONFIG_TXPE(0));
adn4600_write_reg(ADN4600_TX_CONFIG(7), TX_CONFIG_TXEN | TX_CONFIG_TXPE(0));
adn4600_write_reg(ADN4600_TX_CONFIG(XPT_FEEDBACK), TX_CONFIG_TXPE(0));
xpoint_route(XPT_UP1_TX, XPT_SFP1_RX);
xpoint_route(XPT_UP0_TX, XPT_SFP0_RX);
xpoint_route(XPT_SFP1_TX, XPT_UP1_RX);
xpoint_route(XPT_SFP0_TX, XPT_UP0_RX);
return 0;
}
// port: 0 = uplink0, 1 = uplink 1
// txrx: 0 = tx calibration, 1 = rx calibration
// on: 0 = disable, 1= enable
void xpoint_cal_feedback(int on, int port, int txrx)
{
int port_map[] = { XPT_UP0_TX,
XPT_SFP0_TX,
XPT_UP1_TX,
XPT_SFP1_TX };
int index = (port * 2 + (txrx ? 1 : 0));
if(!on)
{
adn4600_write_reg(ADN4600_TX_CONFIG(XPT_FEEDBACK), TX_CONFIG_TXPE(0));
} else {
xpoint_route(port_map[index], XPT_FEEDBACK);
adn4600_write_reg(ADN4600_TX_CONFIG(XPT_FEEDBACK), TX_CONFIG_TXEN | TX_CONFIG_TXPE(0));
}
}
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