Commit d983ca82 authored by Alessandro Rubini's avatar Alessandro Rubini

Merge branch 'softpll-unify'

parents adaece69 566aa532
......@@ -6,9 +6,8 @@
*.mif
*.*~
*~
wrc_disasm.S
wrc.ram
wrc.vhd
*_disasm.S
*.vhd
*.cmd
*.o
......
mainmenu "WR PTP Core software configuration"
# most options with no prompt here are prompted-for in the "advanced" section
# Later we'll build wr_cpu.bin for wr-switch from this code base
config WR_SWITCH
bool "Build rt_cpu.bin, for the WR-Switch FPGA"
default n
select UART
config RAMSIZE
int
default 90112
config WR_NODE
bool
default !WR_SWITCH
config STACKSIZE
int
default 2048
# most options with no prompt here are prompted-for in the "advanced" section
config PRINT_BUFSIZE
int
......@@ -19,6 +21,18 @@ config PRINTF_XINT
boolean
default y
config RAMSIZE
int
default 28672 if WR_SWITCH
default 90112
# CONFIG_WR_SWITCH has no further options at all at this point
if WR_NODE
config STACKSIZE
int
default 2048
config PPSI
boolean
default y
......@@ -209,3 +223,6 @@ config SDB_EEPROM
config LEGACY_EEPROM
boolean
default !SDB_EEPROM
endif
# CONFIG_WR_NODE
......@@ -17,17 +17,21 @@ PTP_NOPOSIX = ptp-noposix
PPSI = ppsi
# we miss CONFIG_ARCH_LM32 as we have no other archs by now
obj-y = arch/lm32/crt0.o arch/lm32/irq.o arch/lm32/debug.o
LDS = arch/lm32/ram.ld
obj-y = arch/lm32/crt0.o arch/lm32/irq.o
LDS-$(CONFIG_WR_NODE) = arch/lm32/ram.ld
LDS-$(CONFIG_WR_SWITCH) = arch/lm32/ram-wrs.ld
obj-y += wrc_main.o
obj-$(CONFIG_WR_NODE) += wrc_main.o
obj-$(CONFIG_WR_SWITCH) += wrs_main.o
obj-$(CONFIG_WR_SWITCH) += ipc/minipc-mem-server.o ipc/rt_ipc.o
# our linker script is preprocessed, so have a rule here
%.ld: %.ld.S $(AUTOCONF)
%.ld: %.ld.S $(AUTOCONF) .config
$(CC) -include $(AUTOCONF) -E -P $*.ld.S -o $@
cflags-y = -ffreestanding -include $(AUTOCONF) -Iinclude/std -Iinclude -I. -Isoftpll
cflags-y = -ffreestanding -include $(AUTOCONF) -Iinclude/std -Iinclude \
-I. -Isoftpll -Iipc
cflags-y += -I$(CURDIR)/pp_printf
cflags-$(CONFIG_PTP_NOPOSIX) += \
......@@ -80,7 +84,7 @@ obj-$(CONFIG_PPSI) += \
CFLAGS_PLATFORM = -mmultiply-enabled -mbarrel-shift-enabled
LDFLAGS_PLATFORM = -mmultiply-enabled -mbarrel-shift-enabled \
-nostdlib -T $(LDS)
-nostdlib -T $(LDS-y)
include shell/shell.mk
include lib/lib.mk
......@@ -88,10 +92,10 @@ include pp_printf/printf.mk
include dev/dev.mk
include softpll/softpll.mk
obj-y += check-error.o
obj-$(CONFIG_WR_NODE) += check-error.o
obj-y += sdb-lib/libsdbfs.a
cflags-y += -Isdb-lib
obj-$(CONFIG_WR_NODE) += sdb-lib/libsdbfs.a
cflags-$(CONFIG_WR_NODE) += -Isdb-lib
CFLAGS = $(CFLAGS_PLATFORM) $(cflags-y) -Wall \
-ffunction-sections -fdata-sections -Os \
......@@ -102,7 +106,9 @@ LDFLAGS = $(LDFLAGS_PLATFORM) \
OBJS = $(obj-y)
OUTPUT = wrc
OUTPUT-$(CONFIG_WR_NODE) = wrc
OUTPUT-$(CONFIG_WR_SWITCH) = rt_cpu
OUTPUT := $(OUTPUT-y)
REVISION=$(shell git describe --dirty --always)
......@@ -129,7 +135,7 @@ $(obj-ppsi):
sdb-lib/libsdbfs.a:
$(MAKE) -C sdb-lib
$(OUTPUT).elf: $(LDS) $(AUTOCONF) gitmodules $(OUTPUT).o config.o
$(OUTPUT).elf: $(LDS-y) $(AUTOCONF) gitmodules $(OUTPUT).o config.o
$(CC) $(CFLAGS) -DGIT_REVISION=\"$(REVISION)\" -c revision.c
${CC} -o $@ revision.o config.o $(OUTPUT).o $(LDFLAGS)
${OBJDUMP} -d $(OUTPUT).elf > $(OUTPUT)_disasm.S
......
This diff is collapsed.
/*
* Link script for Lattice Mico32. Very loosely based on
* code contributed by Jon Beniston <jon@beniston.com>
*
* Jon's license (BSD-style):
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
OUTPUT_FORMAT("elf32-lm32")
ENTRY(_start)
MEMORY
{
ram : ORIGIN = 0x00000000, LENGTH = 0x7000
mbox : ORIGIN = 0x7000, LENGTH = 0x1000
}
SECTIONS
{
.boot : { *(.boot) } > ram
.text : { *(.text .text.*) } > ram =0
.rodata : { *(.rodata .rodata.*) } > ram
.data : {
*(.data .data.*)
_gp = ALIGN(16) + 0x7ff0; /* FIXME: what is this? */
} > ram
.bss : {
_fbss = .;
*(.bss .bss.*)
*(COMMON)
_ebss = .;
} > ram
.mbox : {
. = ALIGN(4);
_fmbox = .;
*(.mbox)
} > mbox
/* First location in stack is highest address in RAM */
PROVIDE(_fstack = ORIGIN(ram) + LENGTH(ram) - 4);
}
/* We need to provide mprintf to ptp-noposix object files, if missing */
PROVIDE(mprintf = pp_printf);
#
# Automatically generated make config: don't edit
#
CONFIG_RAMSIZE=90112
CONFIG_STACKSIZE=2048
# CONFIG_WR_SWITCH is not set
CONFIG_WR_NODE=y
CONFIG_PRINT_BUFSIZE=128
CONFIG_PRINTF_XINT=y
CONFIG_RAMSIZE=90112
CONFIG_STACKSIZE=2048
CONFIG_PPSI=y
CONFIG_UART=y
CONFIG_W1=y
......
#
# Automatically generated make config: don't edit
#
CONFIG_RAMSIZE=131072
CONFIG_STACKSIZE=10240
# CONFIG_WR_SWITCH is not set
CONFIG_WR_NODE=y
CONFIG_PRINT_BUFSIZE=128
CONFIG_PRINTF_XINT=y
CONFIG_RAMSIZE=131072
CONFIG_STACKSIZE=10240
CONFIG_PPSI=y
CONFIG_UART=y
CONFIG_W1=y
......
#
# Automatically generated make config: don't edit
#
CONFIG_RAMSIZE=90112
CONFIG_STACKSIZE=2048
# CONFIG_WR_SWITCH is not set
CONFIG_WR_NODE=y
CONFIG_PRINT_BUFSIZE=128
CONFIG_PRINTF_XINT=y
CONFIG_RAMSIZE=90112
CONFIG_STACKSIZE=2048
CONFIG_PPSI=y
CONFIG_UART=y
CONFIG_W1=y
......
#
# Automatically generated make config: don't edit
#
CONFIG_RAMSIZE=90112
CONFIG_STACKSIZE=2048
# CONFIG_WR_SWITCH is not set
CONFIG_WR_NODE=y
CONFIG_PRINT_BUFSIZE=128
CONFIG_PRINTF_XINT=y
CONFIG_RAMSIZE=90112
CONFIG_STACKSIZE=2048
CONFIG_PPSI=y
CONFIG_UART=y
CONFIG_W1=y
......
#
# Automatically generated make config: don't edit
#
CONFIG_RAMSIZE=90112
CONFIG_STACKSIZE=2048
# CONFIG_WR_SWITCH is not set
CONFIG_WR_NODE=y
CONFIG_PRINT_BUFSIZE=128
CONFIG_PRINTF_XINT=y
CONFIG_RAMSIZE=90112
CONFIG_STACKSIZE=2048
CONFIG_PPSI=y
CONFIG_UART=y
CONFIG_W1=y
......
#
# Automatically generated make config: don't edit
#
# CONFIG_WR_SWITCH is not set
CONFIG_WR_NODE=y
CONFIG_PRINT_BUFSIZE=128
CONFIG_PRINTF_XINT=y
CONFIG_RAMSIZE=90112
CONFIG_STACKSIZE=2048
# CONFIG_PPSI is not set
CONFIG_UART=y
CONFIG_W1=y
# CONFIG_ETHERBONE is not set
# CONFIG_CMD_CONFIG is not set
#
# wrpc-sw is tainted if you change the following options
#
CONFIG_DEVELOPER=y
# CONFIG_CHECK_RESET is not set
# CONFIG_PRINTF_FULL is not set
# CONFIG_PRINTF_MINI is not set
# CONFIG_PRINTF_NONE is not set
CONFIG_PTP_NOPOSIX=y
# CONFIG_DETERMINISTIC_BINARY is not set
# CONFIG_UART_SW is not set
# CONFIG_SDB_EEPROM is not set
CONFIG_LEGACY_EEPROM=y
#
# Automatically generated make config: don't edit
#
CONFIG_WR_SWITCH=y
# CONFIG_WR_NODE is not set
CONFIG_PRINT_BUFSIZE=128
CONFIG_PRINTF_XINT=y
CONFIG_RAMSIZE=28672
CONFIG_UART=y
#
# Automatically generated make config: don't edit
#
CONFIG_RAMSIZE=90112
CONFIG_STACKSIZE=2048
# CONFIG_WR_SWITCH is not set
CONFIG_WR_NODE=y
CONFIG_PRINT_BUFSIZE=128
CONFIG_PRINTF_XINT=y
CONFIG_RAMSIZE=90112
CONFIG_STACKSIZE=2048
CONFIG_PPSI=y
CONFIG_UART=y
CONFIG_W1=y
......
/*
* Trivial pll programmer using an spi controoler.
* PLL is AD9516, SPI is opencores
* Tomasz Wlostowski, Alessandro Rubini, 2011, for CERN.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <wrc.h>
#include "board.h"
#include "syscon.h"
#include "gpio-wrs.h"
#include "rt_ipc.h"
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
#endif
static inline void writel(uint32_t data, void *where)
{
* (volatile uint32_t *)where = data;
}
static inline uint32_t readl(void *where)
{
return * (volatile uint32_t *)where;
}
struct ad9516_reg {
uint16_t reg;
uint8_t val;
};
#include "ad9516_config.h"
/*
* SPI stuff, used by later code
*/
#define SPI_REG_RX0 0
#define SPI_REG_TX0 0
#define SPI_REG_RX1 4
#define SPI_REG_TX1 4
#define SPI_REG_RX2 8
#define SPI_REG_TX2 8
#define SPI_REG_RX3 12
#define SPI_REG_TX3 12
#define SPI_REG_CTRL 16
#define SPI_REG_DIVIDER 20
#define SPI_REG_SS 24
#define SPI_CTRL_ASS (1<<13)
#define SPI_CTRL_IE (1<<12)
#define SPI_CTRL_LSB (1<<11)
#define SPI_CTRL_TXNEG (1<<10)
#define SPI_CTRL_RXNEG (1<<9)
#define SPI_CTRL_GO_BSY (1<<8)
#define SPI_CTRL_CHAR_LEN(x) ((x) & 0x7f)
#define GPIO_PLL_RESET_N 1
#define GPIO_SYS_CLK_SEL 0
#define GPIO_PERIPH_RESET_N 3
#define CS_PLL 0 /* AD9516 on SPI CS0 */
static void *oc_spi_base;
int oc_spi_init(void *base_addr)
{
oc_spi_base = base_addr;
writel(100, oc_spi_base + SPI_REG_DIVIDER);
return 0;
}
int oc_spi_txrx(int ss, int nbits, uint32_t in, uint32_t *out)
{
uint32_t rval;
if (!out)
out = &rval;
writel(SPI_CTRL_ASS | SPI_CTRL_CHAR_LEN(nbits)
| SPI_CTRL_TXNEG,
oc_spi_base + SPI_REG_CTRL);
writel(in, oc_spi_base + SPI_REG_TX0);
writel((1 << ss), oc_spi_base + SPI_REG_SS);
writel(SPI_CTRL_ASS | SPI_CTRL_CHAR_LEN(nbits)
| SPI_CTRL_TXNEG | SPI_CTRL_GO_BSY,
oc_spi_base + SPI_REG_CTRL);
while(readl(oc_spi_base + SPI_REG_CTRL) & SPI_CTRL_GO_BSY)
;
*out = readl(oc_spi_base + SPI_REG_RX0);
return 0;
}
/*
* AD9516 stuff, using SPI, used by later code.
* "reg" is 12 bits, "val" is 8 bits, but both are better used as int
*/
static void ad9516_write_reg(int reg, int val)
{
oc_spi_txrx(CS_PLL, 24, (reg << 8) | val, NULL);
}
static int ad9516_read_reg(int reg)
{
uint32_t rval;
oc_spi_txrx(CS_PLL, 24, (reg << 8) | (1 << 23), &rval);
return rval & 0xff;
}
static void ad9516_load_regset(const struct ad9516_reg *regs, int n_regs, int commit)
{
int i;
for(i=0; i<n_regs; i++)
ad9516_write_reg(regs[i].reg, regs[i].val);
if(commit)
ad9516_write_reg(0x232, 1);
}
static void ad9516_wait_lock()
{
while ((ad9516_read_reg(0x1f) & 1) == 0);
}
#define SECONDARY_DIVIDER 0x100
int ad9516_set_output_divider(int output, int ratio, int phase_offset)
{
uint8_t lcycles = (ratio/2) - 1;
uint8_t hcycles = (ratio - (ratio / 2)) - 1;
int secondary = (output & SECONDARY_DIVIDER) ? 1 : 0;
output &= 0xf;
if(output >= 0 && output < 6) /* LVPECL outputs */
{
uint16_t base = (output / 2) * 0x3 + 0x190;
if(ratio == 1) /* bypass the divider */
{
uint8_t div_ctl = ad9516_read_reg(base + 1);
ad9516_write_reg(base + 1, div_ctl | (1<<7) | (phase_offset & 0xf));
} else {
uint8_t div_ctl = ad9516_read_reg(base + 1);
TRACE("DivCtl: %x\n", div_ctl);
ad9516_write_reg(base + 1, (div_ctl & (~(1<<7))) | (phase_offset & 0xf)); /* disable bypass bit */
ad9516_write_reg(base, (lcycles << 4) | hcycles);
}
} else { /* LVDS/CMOS outputs */
uint16_t base = ((output - 6) / 2) * 0x5 + 0x199;
TRACE("Output [divider %d]: %d ratio: %d base %x lc %d hc %d\n", secondary, output, ratio, base, lcycles ,hcycles);
if(!secondary)
{
if(ratio == 1) /* bypass the divider 1 */
ad9516_write_reg(base + 3, ad9516_read_reg(base + 3) | 0x10);
else {
ad9516_write_reg(base, (lcycles << 4) | hcycles);
ad9516_write_reg(base + 1, phase_offset & 0xf);
}
} else {
if(ratio == 1) /* bypass the divider 2 */
ad9516_write_reg(base + 3, ad9516_read_reg(base + 3) | 0x20);
else {
ad9516_write_reg(base + 2, (lcycles << 4) | hcycles);
// ad9516_write_reg(base + 1, phase_offset & 0xf);
}
}
}
/* update */
ad9516_write_reg(0x232, 0x0);
ad9516_write_reg(0x232, 0x1);
ad9516_write_reg(0x232, 0x0);
return 0;
}
int ad9516_set_vco_divider(int ratio) /* Sets the VCO divider (2..6) or 0 to enable static output */
{
if(ratio == 0)
ad9516_write_reg(0x1e0, 0x5); /* static mode */
else
ad9516_write_reg(0x1e0, (ratio-2));
ad9516_write_reg(0x232, 0x1);
return 0;
}
void ad9516_sync_outputs()
{
/* VCO divider: static mode */
ad9516_write_reg(0x1E0, 0x7);
ad9516_write_reg(0x232, 0x1);
/* Sync the outputs when they're inactive to avoid +-1 cycle uncertainity */
ad9516_write_reg(0x230, 1);
ad9516_write_reg(0x232, 1);
ad9516_write_reg(0x230, 0);
ad9516_write_reg(0x232, 1);
}
int ad9516_init(void)
{
TRACE("Initializing AD9516 PLL...\n");
oc_spi_init((void *)BASE_SPI);
gpio_out(GPIO_SYS_CLK_SEL, 0); /* switch to the standby reference clock, since the PLL is off after reset */
/* reset the PLL */
gpio_out(GPIO_PLL_RESET_N, 0);
timer_delay(10);
gpio_out(GPIO_PLL_RESET_N, 1);
timer_delay(10);
/* Use unidirectional SPI mode */
ad9516_write_reg(0x000, 0x99);
/* Check the presence of the chip */
if (ad9516_read_reg(0x3) != 0xc3) {
TRACE("Error: AD9516 PLL not responding.\n");
return -1;
}
ad9516_load_regset(ad9516_base_config, ARRAY_SIZE(ad9516_base_config), 0);
ad9516_load_regset(ad9516_ref_tcxo, ARRAY_SIZE(ad9516_ref_tcxo), 1);
ad9516_wait_lock();
ad9516_sync_outputs();
ad9516_set_output_divider(9, 4, 0); /* AUX/SWCore = 187.5 MHz */
ad9516_set_output_divider(7, 12, 0); /* REF = 62.5 MHz */
ad9516_set_output_divider(4, 12, 0); /* GTX = 62.5 MHz */
ad9516_sync_outputs();
ad9516_set_vco_divider(2);
TRACE("AD9516 locked.\n");
gpio_out(GPIO_SYS_CLK_SEL, 1); /* switch the system clock to the PLL reference */
gpio_out(GPIO_PERIPH_RESET_N, 0); /* reset all peripherals which use AD9516-provided clocks */
gpio_out(GPIO_PERIPH_RESET_N, 1);
return 0;
}
int rts_debug_command(int command, int value)
{
switch(command)
{
case RTS_DEBUG_ENABLE_SERDES_CLOCKS:
if(value)
{
ad9516_write_reg(0xf4, 0x08); // OUT4 enabled
ad9516_write_reg(0x232, 0x0);
ad9516_write_reg(0x232, 0x1);
} else {
ad9516_write_reg(0xf4, 0x0a); // OUT4 power-down, no serdes clock
ad9516_write_reg(0x232, 0x0);
ad9516_write_reg(0x232, 0x1);
}
break;
}
return 0;
}
/* Base configuration (global dividers, output config, reference-independent) */
const struct ad9516_reg ad9516_base_config[] = {
{0x0000, 0x99},
{0x0001, 0x00},
{0x0002, 0x10},
{0x0003, 0xC3},
{0x0004, 0x00},
{0x0010, 0x7C},
{0x0011, 0x05},
{0x0012, 0x00},
{0x0013, 0x0C},
{0x0014, 0x12},
{0x0015, 0x00},
{0x0016, 0x05},
{0x0017, 0x88},
{0x0018, 0x07},
{0x0019, 0x00},
{0x001A, 0x00},
{0x001B, 0x00},
{0x001C, 0x02},
{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, 0x08},
{0x00F5, 0x08},
{0x0140, 0x43},
{0x0141, 0x42},
{0x0142, 0x43},
{0x0143, 0x42},
{0x0190, 0x00},
{0x0191, 0x80},
{0x0192, 0x00},
{0x0193, 0xBB},
{0x0194, 0x00},
{0x0195, 0x00},
{0x0196, 0x00},
{0x0197, 0x00},
{0x0198, 0x00},
{0x0199, 0x11},
{0x019A, 0x00},
{0x019B, 0x11},
{0x019C, 0x20},
{0x019D, 0x00},
{0x019E, 0x11},
{0x019F, 0x00},
{0x01A0, 0x11},
{0x01A1, 0x20},
{0x01A2, 0x00},
{0x01A3, 0x00},
{0x01E0, 0x04},
{0x01E1, 0x02},
{0x0230, 0x00},
{0x0231, 0x00},
};
/* Config for 25 MHz VCTCXO reference (RDiv = 5, use REF1) */
const struct ad9516_reg ad9516_ref_tcxo[] = {
{0x0011, 0x05},
{0x0012, 0x00}, /* RDiv = 5 */
{0x001C, 0x06} /* Use REF1 */
};
/* Config for 10 MHz external reference (RDiv = 2, use REF2) */
const struct ad9516_reg ad9516_ref_ext[] = {
{0x0011, 0x02},
{0x0012, 0x00}, /* RDiv = 2 */
{0x001C, 0x46} /* Use REF1 */
};
const struct {int reg; uint8_t val} ad9516_regs[] = {
{0x0000, 0x99},
{0x0001, 0x00},
{0x0002, 0x10},
{0x0003, 0xC3},
{0x0004, 0x00},
{0x0010, 0x7C},
{0x0011, 0x01},
{0x0012, 0x00},
{0x0013, 0x04},
{0x0014, 0x07},
{0x0015, 0x00},
{0x0016, 0x04},
{0x0017, 0x00},
{0x0018, 0x07},
{0x0019, 0x00},
{0x001A, 0x00},
{0x001B, 0x00},
{0x001C, 0x46},
{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, 0x08},
{0x00F5, 0x0A},
{0x0140, 0x43},
{0x0141, 0x43},
{0x0142, 0x43},
{0x0143, 0x43},
{0x0190, 0x00},
{0x0191, 0x80},
{0x0192, 0x00},
{0x0193, 0xBB},
{0x0194, 0x00},
{0x0195, 0x00},
{0x0196, 0x00},
{0x0197, 0x00},
{0x0198, 0x00},
{0x0199, 0x22},
{0x019A, 0x00},
{0x019B, 0x11},
{0x019C, 0x00},
{0x019D, 0x00},
{0x019E, 0x22},
{0x019F, 0x00},
{0x01A0, 0x11},
{0x01A1, 0x00},
{0x01A2, 0x00},
{0x01A3, 0x00},
{0x01E0, 0x04},
{0x01E1, 0x02},
{0x0230, 0x00},
{0x0231, 0x00},
{0x0232, 0x00},
{-1, 0}};
obj-y += \
obj-$(CONFIG_WR_NODE) += \
dev/endpoint.o \
dev/ep_pfilter.o \
dev/i2c.o \
......@@ -9,6 +9,8 @@ obj-y += \
dev/sdb.o \
dev/rxts_calibrator.o
obj-$(CONFIG_WR_SWITCH) += dev/timer-wrs.o dev/ad9516.o
obj-$(CONFIG_LEGACY_EEPROM) += dev/eeprom.o
obj-$(CONFIG_SDB_EEPROM) += dev/sdb-eeprom.o
......
/*
* This work is part of the White Rabbit project
*
* Copyright (C) 2011 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
#include "board.h"
#include "syscon.h"
#define DNA_DATA 1
#define DNA_CLK 4
#define DNA_SHIFT 3
#define DNA_READ 2
void dna_read(uint32_t * lo, uint32_t * hi)
{
uint64_t dna = 0;
int i;
gpio_out(DNA_DATA, 0);
delay(10);
gpio_out(DNA_CLK, 0);
delay(10);
gpio_out(DNA_READ, 1);
delay(10);
gpio_out(DNA_SHIFT, 0);
delay(10);
delay(10);
gpio_out(DNA_CLK, 1);
delay(10);
if (gpio_in(DNA_DATA))
dna |= 1;
delay(10);
gpio_out(DNA_CLK, 0);
delay(10);
gpio_out(DNA_READ, 0);
gpio_out(DNA_SHIFT, 1);
delay(10);
for (i = 0; i < 57; i++) {
dna <<= 1;
delay(10);
delay(10);
gpio_out(DNA_CLK, 1);
delay(10);
if (gpio_in(DNA_DATA))
dna |= 1;
delay(10);
gpio_out(DNA_CLK, 0);
delay(10);
}
*hi = (uint32_t) (dna >> 32);
*lo = (uint32_t) dna;
}
#include "board.h"
#include "syscon.h"
uint32_t timer_get_tics()
{
return *(volatile uint32_t *) (BASE_TIMER);
}
void timer_delay(uint32_t how_long)
{
uint32_t t_start;
t_start = timer_get_tics();
if(t_start + how_long < t_start)
while(t_start + how_long < timer_get_tics());
while(t_start + how_long > timer_get_tics());
}
#ifndef __BOARD_WRC_H
#define __BOARD_WRC_H
/*
* This is meant to be automatically included by the Makefile,
* when wrpc-sw is build for wrc (node) -- as opposed to wrs (switch)
*/
#include <hw/memlayout.h>
/* Board-specific parameters */
/* WR Core system/CPU clock frequency in Hz */
#define CPU_CLOCK 62500000ULL
/* WR Reference clock period (picoseconds) and frequency (Hz) */
#define REF_CLOCK_PERIOD_PS 8000
#define REF_CLOCK_FREQ_HZ 125000000
/* Baud rate of the builtin UART (does not apply to the VUART) */
#define UART_BAUDRATE 115200ULL
/* Maximum number of simultaneously created sockets */
#define NET_MAX_SOCKETS 4
/* Socket buffer size, determines the max. RX packet size */
#define NET_SKBUF_SIZE 512
/* Number of auxillary clock channels - usually equal to the number of FMCs */
#define NUM_AUX_CLOCKS 1
int board_init();
int board_update();
/* spll parameter that are board-specific */
#define BOARD_DIVIDE_DMTD_CLOCKS 1
#define BOARD_MAX_CHAN_REF 1
#define BOARD_MAX_CHAN_AUX 2
#define BOARD_MAX_PTRACKERS 1
#endif /* __BOARD_WRC_H */
#ifndef __BOARD_H
#define __BOARD_H
/* RT CPU Memory layout */
#define CPU_CLOCK 62500000
#define REF_CLOCK_FREQ_HZ 62500000
#define REF_CLOCK_PERIOD_PS 16000
#define UART_BAUDRATE 115200
#define BASE_UART 0x10000
#define BASE_SOFTPLL 0x10100
#define BASE_SPI 0x10200
#define BASE_GPIO 0x10300
#define BASE_TIMER 0x10400
#define BASE_PPS_GEN 0x10500
/* spll parameter that are board-specific */
#define BOARD_DIVIDE_DMTD_CLOCKS 0
#define BOARD_MAX_CHAN_REF 18
#define BOARD_MAX_CHAN_AUX 1
#define BOARD_MAX_PTRACKERS 18
#endif
#ifndef __BOARD_H
#define __BOARD_H
#include <hw/memlayout.h>
/* Board-specific parameters */
/* WR Core system/CPU clock frequency in Hz */
#define CPU_CLOCK 62500000ULL
/* WR Reference clock period (picoseconds) and frequency (Hz) */
#define REF_CLOCK_PERIOD_PS 8000
#define REF_CLOCK_FREQ_HZ 125000000
/* Baud rate of the builtin UART (does not apply to the VUART) */
#define UART_BAUDRATE 115200ULL
/* Maximum number of simultaneously created sockets */
#define NET_MAX_SOCKETS 4
/* Socket buffer size, determines the max. RX packet size */
#define NET_SKBUF_SIZE 512
/* Number of auxillary clock channels - usually equal to the number of FMCs */
#define NUM_AUX_CLOCKS 1
int board_init();
int board_update();
/*
* We build for both wr-switch and wr-node (core).
*
* Unfortunately, our submodules include <board.h> without using
* our own Kconfig defines. Thus, assume wr-node unless building
* specifically for wr-switch (which doesn't refer to submodules).
* Same appplies to ./tools/, where we can avoid a Makefile
* patch for add "-include ../include/generated/autoconf.h"
*/
#if defined(CONFIG_WR_SWITCH)
# include "board-wrs.h"
#else
# include "board-wrc.h"
#endif
#ifndef __GPIO_H
#define __GPIO_H
#include <stdint.h>
#include "board.h"
struct GPIO_WB
{
uint32_t CODR; /*Clear output register*/
uint32_t SODR; /*Set output register*/
uint32_t DDR; /*Data direction register (1 means out)*/
uint32_t PSR; /*Pin state register*/
};
static volatile struct GPIO_WB *__gpio = (volatile struct GPIO_WB *) BASE_GPIO;
static inline void gpio_out(int pin, int val)
{
if(val)
__gpio->SODR = (1<<pin);
else
__gpio->CODR = (1<<pin);
}
static inline void gpio_dir(int pin, int val)
{
if(val)
__gpio->DDR |= (1<<pin);
else
__gpio->DDR &= ~(1<<pin);
}
static inline int gpio_in(int bank, int pin)
{
return __gpio->PSR & (1<<pin) ? 1: 0;
}
#endif
......@@ -18,8 +18,8 @@ WARNING: These parameters must be in sync with the generics of the HDL instantia
/* optional DMTD clock division to improve FPGA timing closure by avoiding
clock nets directly driving FD inputs. Must be consistent with the
g_divide_inputs_by_2 generic. */
#define DIVIDE_DMTD_CLOCKS_BY_2 1
g_divide_inputs_by_2 generic. This is different in wrs and wrc */
#define DIVIDE_DMTD_CLOCKS_BY_2 BOARD_DIVIDE_DMTD_CLOCKS
/* Number of bits in phase tags generated by the DMTDs. Used to sign-extend the tags.
Corresponding VHDL generic: g_tag_bits. */
......@@ -34,13 +34,13 @@ WARNING: These parameters must be in sync with the generics of the HDL instantia
#define PI_FRACBITS 12
/* Max. allowed number of reference channels. Can be used to tweak memory usage. */
#define MAX_CHAN_REF 1
#define MAX_CHAN_REF BOARD_MAX_CHAN_REF /* Depends on wrc/wrs */
/* Max. allowed number of auxillary channels */
#define MAX_CHAN_AUX 2
#define MAX_CHAN_AUX BOARD_MAX_CHAN_AUX /* Depends on wrc/wrs */
/* Max. allowed number of phase trackers */
#define MAX_PTRACKERS 1
#define MAX_PTRACKERS BOARD_MAX_PTRACKERS /* Depends on wrc/wrs */
/* Number of bits of the DAC(s) driving the oscillator(s). Must be the same for
all the outputs. */
......@@ -48,7 +48,3 @@ WARNING: These parameters must be in sync with the generics of the HDL instantia
/* Number of samples in a single ptracker averaging bin */
#define PTRACKER_AVERAGE_SAMPLES 512
/* 1.0 / (Speed of the phase shifter) - the higher value, the slower phase shifting.
Used to prevent de-locking PLLs when shifting large offsets. */
#define PHASE_SHIFTER_SPEED 1
......@@ -4,6 +4,16 @@
#include <inttypes.h>
#include <sys/types.h>
#ifdef CONFIG_WR_SWITCH
#define TICS_PER_SECOND 100000
uint32_t timer_get_tics();
void timer_delay(uint32_t how_long);
int timer_expired(uint32_t t_start, uint32_t how_long);
#else /* CONFIG_WR_NODE */
#include "board.h"
#undef PACKED /* if we already included a regs file, we'd get a warning */
#include <hw/wrc_syscon_regs.h>
......@@ -68,4 +78,5 @@ static inline int sysc_get_memsize()
return (SYSC_HWFR_MEMSIZE_R(syscon->HWFR) + 1) * 16;
}
#endif /* CONFIG_WR_NODE */
#endif
#ifndef __FREESTANDING_TRACE_H__
#define __FREESTANDING_TRACE_H__
#ifdef CONFIG_WR_NODE
#define TRACE_WRAP(...)
#define TRACE_DEV(...) wrc_debug_printf(0, __VA_ARGS__)
#else /* WR_SWITCH */
#define TRACE(...) pp_printf(__VA_ARGS__)
#define TRACE_DEV(...) pp_printf(__VA_ARGS__)
#endif /* node/switch */
#endif
......@@ -24,9 +24,15 @@ void shell_init(void);
int wrc_log_stats(uint8_t onetime);
void wrc_debug_printf(int subsys, const char *fmt, ...);
/* Default width (in 8ns units) of the pulses on the PPS output */
#define PPS_WIDTH (10 * 1000 * 1000 / 8) /* 10ms */
/* This header is included by softpll: manage wrc/wrs difference */
#ifdef CONFIG_WR_NODE
#define NS_PER_CLOCK 8
#else /* CONFIG_WR_SWITCH */
#define NS_PER_CLOCK 16
#endif
/* Default width (in 8ns/16ns units) of the pulses on the PPS output */
#define PPS_WIDTH (10 * 1000 * 1000 / NS_PER_CLOCK) /* 10ms */
/* This is in the library, somewhere */
extern int abs(int val);
......@@ -38,5 +44,11 @@ void update_rx_queues(void);
/* refresh period for _gui_ and _stat_ commands */
extern int wrc_ui_refperiod;
/* Init functions for the wrs build */
int ad9516_init(void);
void rts_init(void);
int rtipc_init(void);
void rts_update(void);
void rtipc_action(void);
#endif /* __WRC_H__ */
/*
* Private definition for mini-ipc
*
* Copyright (C) 2011 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
* Based on ideas by Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* This program 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.
*/
#ifndef __MINIPC_INT_H__
#define __MINIPC_INT_H__
#include <sys/types.h>
#if __STDC_HOSTED__ /* freestanding servers have less material */
#include <sys/un.h>
#include <sys/select.h>
#endif
#include "minipc.h"
/* be safe, in case some other header had them slightly differntly */
#undef container_of
#undef offsetof
#undef ARRAY_SIZE
/* We are strongly based on container_of internally */
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
/*
* While public symbols are minipc_* internal ones are mpc_* to be shorter.
* The connection includes an fd, which is the only thing returned back
*/
/* The list of functions attached to a service */
struct mpc_flist {
const struct minipc_pd *pd;
struct mpc_flist *next;
};
/*
* The main server or client structure. Server links have client sockets
* hooking on it.
*/
struct mpc_link {
struct minipc_ch ch;
int magic;
int pid;
int flags;
struct mpc_link *nextl;
struct mpc_flist *flist;
void *memaddr;
int memsize;
#if __STDC_HOSTED__ /* these fields are not used in freestanding uC */
FILE *logf;
struct sockaddr_un addr;
int fd[MINIPC_MAX_CLIENTS];
fd_set fdset;
#endif
char name[MINIPC_MAX_NAME];
};
#define MPC_MAGIC 0xc0ffee99
#define MPC_FLAG_SERVER 0x00010000
#define MPC_FLAG_CLIENT 0x00020000
#define MPC_FLAG_SHMEM 0x00040000
#define MPC_FLAG_DEVMEM 0x00080000
#define MPC_USER_FLAGS(x) ((x) & 0xffff)
/* The request packet being transferred */
struct mpc_req_packet {
char name[MINIPC_MAX_NAME];
uint32_t args[MINIPC_MAX_ARGUMENTS];
};
/* The reply packet being transferred */
struct mpc_rep_packet {
uint32_t type;
uint8_t val[MINIPC_MAX_REPLY];
};
/* A structure for shared memory (takes more than 2kB) */
struct mpc_shmem {
uint32_t nrequest; /* incremented at each request */
uint32_t nreply; /* incremented at each reply */
struct mpc_req_packet request;
struct mpc_rep_packet reply;
};
#define MPC_TIMEOUT 1000 /* msec, hardwired */
static inline struct mpc_link *mpc_get_link(struct minipc_ch *ch)
{
return container_of(ch, struct mpc_link, ch);
}
#define CHECK_LINK(link) /* Horrible shortcut, don't tell around... */ \
if ((link)->magic != MPC_MAGIC) { \
errno = EINVAL; \
return -1; \
}
extern struct mpc_link *__mpc_base;
extern void mpc_free_flist(struct mpc_link *link, struct mpc_flist *flist);
extern struct minipc_ch *__minipc_link_create(const char *name, int flags);
/* Used for lists and structures -- sizeof(uint32_t) is 4, is it? */
#define MINIPC_GET_ANUM(len) (((len) + 3) >> 2)
#endif /* __MINIPC_INT_H__ */
/*
* Mini-ipc: Exported functions for freestanding server
*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* This replicates some code of minipc-core and minipc-server.
* It implements the functions needed to make a freestanding server
* (for example, an lm32 running on an FPGA -- the case I actually need).
*/
#include "minipc-int.h"
#include <string.h>
#include <sys/errno.h>
/* HACK: use a static link, one only */
static struct mpc_link __static_link;
/* The create function just picks an hex address from the name "mem:AABBCC" */
struct minipc_ch *minipc_server_create(const char *name, int flags)
{
struct mpc_link *link = &__static_link;
int i, c, addr = 0;
int memsize = sizeof(struct mpc_shmem);
if (link->magic) {
errno = EBUSY;
return NULL;
}
/* Most code from __minipc_link_create and __minipc_memlink_create */
flags |= MPC_FLAG_SERVER;
if (strncmp(name, "mem:", 4)) {
errno = EINVAL;
return NULL;
}
/* Ok, valid name. Hopefully */
link->magic = MPC_MAGIC;
link->flags = flags;
strncpy(link->name, name, sizeof(link->name) -1);
/* Parse the hex address */
for (i = 4; (c = name[i]); i++) {
addr *= 0x10;
if (c >= '0' && c <= '9') addr += c - '0';
if (c >= 'a' && c <= 'f') addr += c - 'a' + 10;
if (c >= 'A' && c <= 'F') addr += c - 'A' + 10;
}
link->flags |= MPC_FLAG_SHMEM; /* needed? */
link->memaddr = (void *)addr;
link->memsize = memsize;
link->pid = 0; /* hack: nrequest */
if (link->flags & MPC_FLAG_SERVER)
memset(link->memaddr, 0, memsize);
return &link->ch;
}
/* Close only marks the link as available */
int minipc_close(struct minipc_ch *ch)
{
struct mpc_link *link = mpc_get_link(ch);
CHECK_LINK(link);
link->magic = 0; /* available */
return 0;
}
/* HACK: use a static array of flist, to avoid malloc and free */
static struct mpc_flist __static_flist[MINIPC_MAX_EXPORT];
static void *calloc(size_t unused, size_t unused2)
{
int i;
struct mpc_flist *p;
for (p = __static_flist, i = 0; i < MINIPC_MAX_EXPORT; p++, i++)
if (!p->pd)
break;
if (i == MINIPC_MAX_EXPORT) {
errno = ENOMEM;
return NULL;
}
return p;
}
static void free(void *ptr)
{
struct mpc_flist *p = ptr;
p->pd = NULL;
}
/* From: minipc-core.c, but relying on fake free above */
void mpc_free_flist(struct mpc_link *link, struct mpc_flist *flist)
{
struct mpc_flist **nextp;
/* Look for flist and release it*/
for (nextp = &link->flist; (*nextp); nextp = &(*nextp)->next)
if (*nextp == flist)
break;
if (!*nextp) {
return;
}
*nextp = flist->next;
free(flist);
}
/* From: minipc-server.c -- but no log and relies on fake calloc above */
int minipc_export(struct minipc_ch *ch, const struct minipc_pd *pd)
{
struct mpc_link *link = mpc_get_link(ch);
struct mpc_flist *flist;
CHECK_LINK(link);
flist = calloc(1, sizeof(*flist));
if (!flist)
return -1;
flist->pd = pd;
flist->next = link->flist;
link->flist = flist;
return 0;
}
/* From: minipc-server.c -- but no log file */
int minipc_unexport(struct minipc_ch *ch, const struct minipc_pd *pd)
{
struct mpc_link *link = mpc_get_link(ch);
struct mpc_flist *flist;
CHECK_LINK(link);
/* We must find the flist that points to pd */
for (flist = link->flist; flist; flist = flist->next)
if (flist->pd == pd)
break;
if (!flist) {
errno = EINVAL;
return -1;
}
flist = container_of(&pd, struct mpc_flist, pd);
mpc_free_flist(link, flist);
return 0;
}
/* From: minipc-server.c */
uint32_t *minipc_get_next_arg(uint32_t arg[], uint32_t atype)
{
int asize;
char *s = (void *)arg;
if (MINIPC_GET_ATYPE(atype) != MINIPC_ATYPE_STRING)
asize = MINIPC_GET_ANUM(MINIPC_GET_ASIZE(atype));
else
asize = MINIPC_GET_ANUM(strlen(s) + 1);
return arg + asize;
}
/* From: minipc-server.c (mostly: mpc_handle_client) */
int minipc_server_action(struct minipc_ch *ch, int timeoutms)
{
struct mpc_link *link = mpc_get_link(ch);
struct mpc_req_packet *p_in;
struct mpc_rep_packet *p_out;
struct mpc_shmem *shm = link->memaddr;
const struct minipc_pd *pd;
struct mpc_flist *flist;
int i;
CHECK_LINK(link);
/* keep track of the request in an otherwise unused field */
if (shm->nrequest == link->pid)
return 0;
link->pid = shm->nrequest;
p_in = &shm->request;
p_out = &shm->reply;
/* use p_in->name to look for the function */
for (flist = link->flist; flist; flist = flist->next)
if (!(strcmp(p_in->name, flist->pd->name)))
break;
if (!flist) {
p_out->type = MINIPC_ARG_ENCODE(MINIPC_ATYPE_ERROR, int);
*(int *)(&p_out->val) = EOPNOTSUPP;
goto send_reply;
}
pd = flist->pd;
/* call the function and send back stuff */
i = pd->f(pd, p_in->args, p_out->val);
if (i < 0) {
p_out->type = MINIPC_ARG_ENCODE(MINIPC_ATYPE_ERROR, int);
*(int *)(&p_out->val) = errno;
} else {
/* Use retval, but fix the length for strings */
if (MINIPC_GET_ATYPE(pd->retval) == MINIPC_ATYPE_STRING) {
int size = strlen((char *)p_out->val) + 1;
size = (size + 3) & ~3; /* align */
p_out->type =
__MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRING, size);
} else {
p_out->type = pd->retval;
}
}
send_reply:
shm->nreply++; /* message already in place */
return 0;
}
/*
* Public definition for mini-ipc
*
* Copyright (C) 2011 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
* Based on ideas by Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* This program 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.
*/
#ifndef __MINIPC_H__
#define __MINIPC_H__
#include <stdint.h>
#if __STDC_HOSTED__ /* freestanding servers have less material */
#include <stdio.h>
#include <sys/select.h>
#endif
/* Hard limits */
#define MINIPC_MAX_NAME 20 /* includes trailing 0 */
#define MINIPC_MAX_CLIENTS 64
#define MINIPC_MAX_ARGUMENTS 256 /* Also, max size of packet words -- 1k */
#define MINIPC_MAX_REPLY 1024 /* bytes */
#if !__STDC_HOSTED__
#define MINIPC_MAX_EXPORT 12 /* freestanding: static allocation */
#endif
/* The base pathname, mkdir is performed as needed */
#define MINIPC_BASE_PATH "/tmp/.minipc"
/* Default polling interval for memory-based channels */
#define MINIPC_DEFAULT_POLL (10*1000)
/* Argument type (and retval type). The size is encoded in the same word */
enum minipc_at {
MINIPC_ATYPE_ERROR = 0xffff,
MINIPC_ATYPE_NONE = 0, /* used as terminator */
MINIPC_ATYPE_INT = 1,
MINIPC_ATYPE_INT64,
MINIPC_ATYPE_DOUBLE, /* float is promoted to double */
MINIPC_ATYPE_STRING, /* size of strings is strlen() each time */
MINIPC_ATYPE_STRUCT
};
/* Encoding of argument type and size in one word */
#define __MINIPC_ARG_ENCODE(atype, asize) (((atype) << 16) | (asize))
#define MINIPC_ARG_ENCODE(atype, type) __MINIPC_ARG_ENCODE(atype, sizeof(type))
#define MINIPC_GET_ATYPE(word) ((word) >> 16)
#define MINIPC_GET_ASIZE(word) ((word) & 0xffff)
#define MINIPC_ARG_END __MINIPC_ARG_ENCODE(MINIPC_ATYPE_NONE, 0) /* zero */
/* The exported procedure looks like this */
struct minipc_pd;
typedef int (minipc_f)(const struct minipc_pd *, uint32_t *args, void *retval);
/* This is the "procedure definition" */
struct minipc_pd {
minipc_f *f; /* pointer to the function */
char name[MINIPC_MAX_NAME]; /* name of the function */
uint32_t flags;
uint32_t retval; /* type of return value */
uint32_t args[]; /* zero-terminated */
};
/* Flags: verbosity is about argument and retval marshall/unmarshall */
#define MINIPC_FLAG_VERBOSE 1
/* This is the channel definition */
struct minipc_ch {
int fd;
};
static inline int minipc_fileno(struct minipc_ch *ch) {return ch->fd;}
/* These return NULL with errno on error, name is the socket pathname */
struct minipc_ch *minipc_server_create(const char *name, int flags);
struct minipc_ch *minipc_client_create(const char *name, int flags);
int minipc_close(struct minipc_ch *ch);
/* Generic: set the default polling interval for mem-based channels */
int minipc_set_poll(int usec);
/* Server: register exported functions */
int minipc_export(struct minipc_ch *ch, const struct minipc_pd *pd);
int minipc_unexport(struct minipc_ch *ch, const struct minipc_pd *pd);
/* Server: helpers to unmarshall a string or struct from a request */
uint32_t *minipc_get_next_arg(uint32_t arg[], uint32_t atype);
/* Handle a request if pending, otherwise -1 and EAGAIN */
int minipc_server_action(struct minipc_ch *ch, int timeoutms);
#if __STDC_HOSTED__
/* Generic: attach diagnostics to a log file */
int minipc_set_logfile(struct minipc_ch *ch, FILE *logf);
/* Return an fdset for the user to select() on the service */
int minipc_server_get_fdset(struct minipc_ch *ch, fd_set *setptr);
/* Client: make requests */
int minipc_call(struct minipc_ch *ch, int millisec_timeout,
const struct minipc_pd *pd, void *ret, ...);
#endif /* __STDC_HOSTED__ */
#endif /* __MINIPC_H__ */
/*
* Mini-ipc: an example freestanding server, based in memory
*
* Copyright (C) 2011,2012 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* This code is copied from trivial-server, and made even more trivial
*/
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <wrc.h>
#include "minipc.h"
#define RTIPC_EXPORT_STRUCTURES
#include "rt_ipc.h"
#include <softpll_ng.h>
static struct rts_pll_state pstate;
static void clear_state()
{
int i;
for(i=0;i<RTS_PLL_CHANNELS;i++)
{
pstate.channels[i].priority = 0;
pstate.channels[i].phase_setpoint = 0;
pstate.channels[i].phase_loopback = 0;
pstate.channels[i].flags = CHAN_REF_VALID;
}
pstate.flags = 0;
pstate.current_ref = 0;
pstate.mode = RTS_MODE_DISABLED;
pstate.ipc_count = 0;
}
/* Sets the phase setpoint on a given channel */
int rts_adjust_phase(int channel, int32_t phase_setpoint)
{
// TRACE("Adjusting phase: ref channel %d, setpoint=%d ps.\n", channel, phase_setpoint);
spll_set_phase_shift(0, phase_setpoint);
pstate.channels[channel].phase_setpoint = phase_setpoint;
return 0;
}
/* Sets the RT subsystem mode (Boundary Clock or Grandmaster) */
int rts_set_mode(int mode)
{
int i;
const struct {
int mode_rt;
int mode_spll;
int do_init;
char *desc;
} options[] = {
{ RTS_MODE_GM_EXTERNAL, SPLL_MODE_GRAND_MASTER, 1, "Grand Master (external clock)" },
{ RTS_MODE_GM_FREERUNNING, SPLL_MODE_FREE_RUNNING_MASTER, 1, "Grand Master (free-running clock)" },
{ RTS_MODE_BC, SPLL_MODE_SLAVE, 0, "Boundary Clock (slave)" },
{ RTS_MODE_DISABLED, SPLL_MODE_DISABLED, 1, "PLL disabled" },
{ 0,0,0, NULL }
};
pstate.mode = mode;
for(i=0;options[i].desc != NULL;i++)
if(mode == options[i].mode_rt)
{
TRACE("RT: Setting mode to %s.\n", options[i].desc);
if(options[i].do_init)
spll_init(options[i].mode_spll, 0, 1);
else
spll_init(SPLL_MODE_DISABLED, 0, 0);
}
return 0;
}
/* Reference channel configuration (BC mode only) */
int rts_lock_channel(int channel, int priority)
{
if(pstate.mode != RTS_MODE_BC)
{
TRACE("trying to lock while not in slave mode,..\n");
return -1;
}
TRACE("RT [slave]: Locking to: %d (prio %d)\n", channel, priority);
spll_init(SPLL_MODE_SLAVE, channel, 0);
pstate.current_ref = channel;
return 0;
}
void rts_init(void)
{
clear_state();
}
void rts_update(void)
{
int i;
int n_ref;
int enabled;
spll_get_num_channels(&n_ref, NULL);
pstate.flags = (spll_check_lock(0) ? RTS_DMTD_LOCKED | RTS_REF_LOCKED : 0);
for(i=0;i<RTS_PLL_CHANNELS;i++)
{
#define CH pstate.channels[i]
CH.flags = 0;
CH.phase_loopback = 0;
CH.phase_current = 0;
// CH.phase_setpoint = 0;
CH.phase_loopback = 0;
if(i >= n_ref)
CH.flags = CHAN_DISABLED;
else {
if(i==pstate.current_ref)
{
spll_get_phase_shift(0, &CH.phase_current, NULL);
if(spll_shifter_busy(0))
CH.flags |= CHAN_SHIFTING;
}
if(spll_read_ptracker(i, &CH.phase_loopback, &enabled))
CH.flags |= CHAN_PMEAS_READY;
CH.flags |= (enabled ? CHAN_PTRACKER_ENABLED : 0);
}
#undef CH
}
}
/* fixme: this assumes the host is BE */
static int htonl(int i)
{
return i;
}
static int rts_get_state_func(const struct minipc_pd *pd, uint32_t *args, void *ret)
{
struct rts_pll_state *tmp = (struct rts_pll_state *)ret;
int i;
pstate.ipc_count++;
/* gaaaah, somebody should write a SWIG plugin for generating this stuff. */
tmp->current_ref = htonl(pstate.current_ref);
tmp->flags = htonl(pstate.flags);
tmp->holdover_duration = htonl(pstate.holdover_duration);
tmp->mode = htonl(pstate.mode);
tmp->delock_count = spll_get_delock_count();
tmp->ipc_count = pstate.ipc_count;
for(i=0; i<RTS_PLL_CHANNELS;i++)
{
tmp->channels[i].priority = htonl(pstate.channels[i].priority);
tmp->channels[i].phase_setpoint = htonl(pstate.channels[i].phase_setpoint);
tmp->channels[i].phase_current = htonl(pstate.channels[i].phase_current);
tmp->channels[i].phase_loopback = htonl(pstate.channels[i].phase_loopback);
tmp->channels[i].flags = htonl(pstate.channels[i].flags);
}
return 0;
}
static int rts_set_mode_func(const struct minipc_pd *pd, uint32_t *args, void *ret)
{
pstate.ipc_count++;
*(int *) ret = rts_set_mode(args[0]);
return 0;
}
static int rts_lock_channel_func(const struct minipc_pd *pd, uint32_t *args, void *ret)
{
pstate.ipc_count++;
*(int *) ret = rts_lock_channel(args[0], (int)args[1]);
return 0;
}
static int rts_adjust_phase_func(const struct minipc_pd *pd, uint32_t *args, void *ret)
{
pstate.ipc_count++;
*(int *) ret = rts_adjust_phase((int)args[0], (int)args[1]);
return 0;
}
static int rts_enable_ptracker_func(const struct minipc_pd *pd, uint32_t *args, void *ret)
{
pstate.ipc_count++;
spll_enable_ptracker((int)args[0], (int)args[1]);
*(int *) ret = 0;
return 0;
}
static int rts_debug_command_func(const struct minipc_pd *pd, uint32_t *args, void *ret)
{
pstate.ipc_count++;
*(int *) ret = rts_debug_command((int)args[0], (int)args[1]);
return 0;
}
static struct minipc_ch *server;
int rtipc_init(void)
{
/* The mailbox is mapped at 0x7000 in the linker script */
server = minipc_server_create("mem:7000", 0);
if (!server)
return 1;
rtipc_rts_set_mode_struct.f = rts_set_mode_func;
rtipc_rts_get_state_struct.f = rts_get_state_func;
rtipc_rts_lock_channel_struct.f = rts_lock_channel_func;
rtipc_rts_adjust_phase_struct.f = rts_adjust_phase_func;
rtipc_rts_enable_ptracker_struct.f = rts_enable_ptracker_func;
rtipc_rts_debug_command_struct.f = rts_debug_command_func;
minipc_export(server, &rtipc_rts_set_mode_struct);
minipc_export(server, &rtipc_rts_get_state_struct);
minipc_export(server, &rtipc_rts_lock_channel_struct);
minipc_export(server, &rtipc_rts_adjust_phase_struct);
minipc_export(server, &rtipc_rts_enable_ptracker_struct);
minipc_export(server, &rtipc_rts_debug_command_struct);
return 0;
}
void rtipc_action(void)
{
minipc_server_action(server, 1000);
}
#ifndef __RT_IPC_H
#define __RT_IPC_H
#include <stdint.h>
#define RTS_PLL_CHANNELS 18
/* Individual channel flags */
/* Reference input frequency valid */
#define CHAN_REF_VALID (1<<0)
/* Frequency out of range */
#define CHAN_FREQ_OUT_OF_RANGE (1<<1)
/* Phase is drifting too fast */
#define CHAN_DRIFTING (1<<2)
/* Channel phase measurement is ready */
#define CHAN_PMEAS_READY (1<<3)
/* Channel not available/disabled */
#define CHAN_DISABLED (1<<4)
/* Channel is busy adjusting phase */
#define CHAN_SHIFTING (1<<5)
/* Channel is busy adjusting phase */
#define CHAN_PTRACKER_ENABLED (1<<6)
/* DMTD clock is present */
#define RTS_DMTD_LOCKED (1<<0)
/* 125 MHz reference locked */
#define RTS_REF_LOCKED (1<<1)
/* External 10 MHz reference present */
#define RTS_EXT_10M_VALID (1<<2)
/* External 1-PPS present */
#define RTS_EXT_PPS_VALID (1<<3)
/* External 10 MHz frequency out-of-range */
#define RTS_EXT_10M_OUT_OF_RANGE (1<<4)
/* External 1-PPS frequency out-of-range */
#define RTS_EXT_PPS_OUT_OF_RANGE (1<<5)
/* Holdover mode active */
#define RTS_HOLDOVER_ACTIVE (1<<6)
/* Grandmaster mode active (uses 10 MHz / 1-PPS reference) */
#define RTS_MODE_GM_EXTERNAL 1
/* Free-running grandmaster (uses local TCXO) */
#define RTS_MODE_GM_FREERUNNING 2
/* Boundary clock mode active (uses network reference) */
#define RTS_MODE_BC 3
/* PLL disabled */
#define RTS_MODE_DISABLED 4
/* null reference input */
#define REF_NONE 255
/* RT Subsystem debug commands, handled via rts_debug_command() */
/* Serdes reference clock enable/disable */
#define RTS_DEBUG_ENABLE_SERDES_CLOCKS 1
struct rts_pll_state {
/* State of an individual input channel (i.e. switch port) */
struct channel {
/* Switchover priority: 0 = highest, 1 - 254 = high..low, 255 = channel disabled (a master port) */
uint32_t priority;
/* channel phase setpoint in picoseconds. Used only when channel is a slave. */
int32_t phase_setpoint;
/* current phase shift in picoseconds. Used only when channel is a slave. */
int32_t phase_current;
/* TX-RX Loopback phase measurement in picoseconds. */
int32_t phase_loopback;
/* flags (per channel - see CHAN_xxx defines) */
uint32_t flags;
} channels[RTS_PLL_CHANNELS];
/* flags (global - RTS_xxx defines) */
uint32_t flags;
/* duration of current holdover period in 10us units */
int32_t holdover_duration;
/* current reference source - or REF_NONE if free-running or grandmaster */
uint32_t current_ref;
/* mode of operation (RTS_MODE_xxx) */
uint32_t mode;
uint32_t delock_count;
uint32_t ipc_count;
uint32_t debug_data[8];
};
/* API */
/* Connects to the RT CPU */
int rts_connect();
/* Queries the RT CPU PLL state */
int rts_get_state(struct rts_pll_state *state);
/* Sets the phase setpoint on a given channel */
int rts_adjust_phase(int channel, int32_t phase_setpoint);
/* Sets the RT subsystem mode (Boundary Clock or Grandmaster) */
int rts_set_mode(int mode);
/* Reference channel configuration (BC mode only) */
int rts_lock_channel(int channel, int priority);
/* Enabled/disables phase tracking on a particular port */
int rts_enable_ptracker(int channel, int enable);
/* Enabled/disables phase tracking on a particular port */
int rts_debug_command(int param, int value);
#ifdef RTIPC_EXPORT_STRUCTURES
static struct minipc_pd rtipc_rts_get_state_struct = {
.name = "aaaa",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRUCT, struct rts_pll_state),
.args = {
MINIPC_ARG_END
},
};
static struct minipc_pd rtipc_rts_set_mode_struct = {
.name = "bbbb",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
.args = {
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int ),
MINIPC_ARG_END
},
};
static struct minipc_pd rtipc_rts_lock_channel_struct = {
.name = "cccc",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
.args = {
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int ),
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int ),
MINIPC_ARG_END
},
};
static struct minipc_pd rtipc_rts_adjust_phase_struct = {
.name = "dddd",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
.args = {
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int ),
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int ),
MINIPC_ARG_END
},
};
static struct minipc_pd rtipc_rts_enable_ptracker_struct = {
.name = "eeee",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
.args = {
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int ),
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int ),
MINIPC_ARG_END
},
};
static struct minipc_pd rtipc_rts_debug_command_struct = {
.name = "ffff",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
.args = {
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int ),
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int ),
MINIPC_ARG_END
},
};
#endif
#endif
obj-y += lib/util.o lib/atoi.o
obj-y += lib/usleep.o
obj-y += lib/net.o
obj-$(CONFIG_WR_NODE) += lib/net.o
obj-$(CONFIG_ETHERBONE) += lib/arp.o lib/icmp.o lib/ipv4.o lib/bootp.o
obj-y += \
obj-$(CONFIG_WR_NODE) += \
shell/shell.o \
shell/cmd_version.o \
shell/cmd_pll.o \
......
......@@ -45,6 +45,7 @@ int pi_update(spll_pi_t *pi, int x)
void pi_init(spll_pi_t *pi)
{
pi->integrator = 0;
pi->y = pi->bias;
}
/* Lock detector state machine. Takes an error sample (y) and checks
......
......@@ -28,8 +28,15 @@ void mpll_init(struct spll_main_state *s, int id_ref,
s->pi.y_max = 65530;
s->pi.anti_windup = 1;
s->pi.bias = 65000;
s->pi.kp = 1100; // / 2;
s->pi.ki = 30; // / 2;
#if defined(CONFIG_WR_SWITCH)
s->pi.kp = 1500; // / 2;
s->pi.ki = 7; // / 2;
#elif defined(CONFIG_WR_NODE)
s->pi.kp = 1100; // / 2;
s->pi.ki = 30; // / 2;
#else
#error "Please set CONFIG for wr switch or wr node"
#endif
s->delock_count = 0;
/* Freqency branch lock detection */
......
#include <wrc.h>
#include "uart.h"
#include "softpll_ng.h"
#include "minipc.h"
const char *build_revision;
const char *build_date;
int main(void)
{
uint32_t start_tics = 0;
uart_init_hw();
TRACE("WR Switch Real Time Subsystem (c) CERN 2011 - 2013\n");
TRACE("Revision: %s, built %s.\n", build_revision, build_date);
TRACE("--");
ad9516_init();
rts_init();
rtipc_init();
for(;;)
{
uint32_t tics = timer_get_tics();
if(tics - start_tics > TICS_PER_SECOND/5)
{
// TRACE("tick!\n");
spll_show_stats();
start_tics = tics;
}
rts_update();
rtipc_action();
}
return 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