Commit 26630513 authored by Grzegorz Daniluk's avatar Grzegorz Daniluk

Merge branch 'v3-switch_for_wrpc'

Conflicts:
	wrc_main.c
parents 313f9397 9ce4ae00
PLATFORM = lm32
OBJS_WRC = wrc_main.o dev/uart.o dev/endpoint.o dev/minic.o dev/pps_gen.o dev/timer.o dev/softpll.o lib/mprintf.o monitor/monitor.o
OBJS_WRC = wrc_main.o dev/uart.o dev/endpoint.o dev/minic.o dev/pps_gen.o dev/syscon.o dev/softpll_ng.o lib/mprintf.o dev/ep_pfilter.o dev/dna.o dev/i2c.o monitor/monitor.o dev/onewire.o dev/eeprom.o
D = ptp-noposix
PTPD_CFLAGS = -ffreestanding -DPTPD_FREESTANDING -DWRPC_EXTRA_SLIM -DPTPD_MSBF -DPTPD_DBG
PTPD_CFLAGS += -Wall -ggdb -I$D/wrsw_hal \
-I$D/libptpnetif -I$D/PTPWRd \
-include $D/compat.h -include $D/PTPWRd/dep/trace.h -include $D/libposix/ptpd-wrappers.h
PTPD_CFLAGS += -DPTPD_NO_DAEMON -DNEW_SINGLE_WRFSM -DPTPD_TRACE_MASK=TRACE_SERVO
PTPD_CFLAGS += -DPTPD_NO_DAEMON -DNEW_SINGLE_WRFSM -DPTPD_TRACE_MASK=0
OBJS_PTPD = $D/PTPWRd/arith.o
OBJS_PTPD += $D/PTPWRd/bmc.o
......@@ -29,7 +29,7 @@ CFLAGS_PLATFORM = -abel -Wl,--relax -Wl,--gc-sections
LDFLAGS_PLATFORM = -abel -Wl,--relax -Wl,--gc-sections
OBJS_PLATFORM=
else
CROSS_COMPILE ?= /opt/gcc-lm32/bin/lm32-elf-
CROSS_COMPILE ?= lm32-elf-
CFLAGS_PLATFORM = -mmultiply-enabled -mbarrel-shift-enabled
########################################################################
......@@ -75,7 +75,7 @@ clean:
%.o: %.c
${CC} $(CFLAGS) $(PTPD_CFLAGS) $(INCLUDE_DIR) $(LIB_DIR) -c $^ -o $@
load: all
load: #all
./tools/lm32-loader $(OUTPUT).bin
tools:
......
#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 "types.h"
#include "i2c.h"
#include "eeprom.h"
#include "board.h"
#include "syscon.h"
/*
* The SFP section is placed somewhere inside FMC EEPROM and it really does not
* matter where (can be a binary data inside the Board Info section but can be
* placed also outside the FMC standardized EEPROM structure. The only requirement
* is that it starts with 0xdeadbeef pattern. The structure of SFP section is:
*
* --------------------------------
* | 0xdeadbeef (4B) | count (4B) |
* -------------------------------------------------------------------------------
* | SFP(1) part number (16B) | alpha (4B) | deltaTx (4B) | deltaRx (4B) |
* -------------------------------------------------------------------------------
* | SFP(2) part number (16B) | alpha (4B) | deltaTx (4B) | deltaRx (4B) |
* -------------------------------------------------------------------------------
* | (....) | (....) | (....) | (....) |
* -------------------------------------------------------------------------------
* | SFP(count) part number (16B) | alpha (4B) | deltaTx (4B) | deltaRx (4B) |
* -------------------------------------------------------------------------------
* | checksum (1B) |
* -----------------
*
* Fields description:
* count - how many SFPs are described in the list (binary)
* SFP(n) part number - SFP PN as read from SFP's EEPROM (e.g. AXGE-1254-0531)
* (16 ascii chars)
* checksum - low order 8 bits of the sum of all bytes starting from
* _count_ (without 0xdeadbeef)
*
*/
int eeprom_read(uint8_t i2cif, uint8_t i2c_addr, uint32_t offset, uint8_t *buf, size_t size)
{
int i;
unsigned char c;
mi2c_start(i2cif);
if(mi2c_put_byte(i2cif, i2c_addr << 1) < 0)
{
mi2c_stop(i2cif);
return -1;
}
mi2c_put_byte(i2cif, (offset>>8) & 0xff);
mi2c_put_byte(i2cif, offset & 0xff);
mi2c_repeat_start(i2cif);
mi2c_put_byte(i2cif, (i2c_addr << 1) | 1);
for(i=0; i<size-1; ++i)
{
mi2c_get_byte(i2cif, &c, 0);
*buf++ = c;
}
mi2c_get_byte(i2cif, &c, 1);
*buf++ = c;
mi2c_stop(i2cif);
return size;
}
//int eeprom_write(uint8_t i2cif, uint8_t i2c_addr, uint32_t offset, uint8_t *buf, size_t size)
//{
// int i, busy;
//
// for(i=0;i<size;i++)
// {
// mi2c_start(i2cif);
//
// if(mi2c_put_byte(i2cif, i2c_addr << 1) < 0)
// {
// mi2c_stop(i2cif);
// return -1;
// }
// mi2c_put_byte(i2cif, (offset >> 8) & 0xff);
// mi2c_put_byte(i2cif, offset & 0xff);
// mi2c_put_byte(i2cif, *buf++);
// offset++;
// mi2c_stop(i2cif);
//
// do /* wait until the chip becomes ready */
// {
// mi2c_start(i2cif);
// busy = mi2c_put_byte(i2cif, i2c_addr << 1);
// mi2c_stop(i2cif);
// } while(busy);
//
// }
// return size;
//}
int32_t eeprom_sfp_section(uint8_t i2cif, uint8_t i2c_addr, size_t size, uint16_t *section_sz)
{
uint8_t c, match;
uint16_t i;
uint32_t sfp_pattern = SFP_SECTION_PATTERN;
match = 0x00;
*section_sz = 0x0000;
mi2c_start(i2cif);
if(mi2c_put_byte(i2cif, i2c_addr << 1) != 0)
{
mi2c_stop(i2cif);
return -1;
}
mi2c_put_byte(i2cif, 0x00);
mi2c_put_byte(i2cif, 0x00);
mi2c_repeat_start(i2cif);
mi2c_put_byte(i2cif, (i2c_addr << 1) | 1);
for(i=0; i<size-1; ++i)
{
mi2c_get_byte(i2cif, &c, 0);
if(match==0x0f)
{
*section_sz = ((uint16_t)c ) << 8;
match |= 0x10;
}
else if(match==0x1f)
{
*section_sz |= ((uint16_t)c ) & 0xff;
match |= 0x20;
}
else if( c== (uint8_t)(sfp_pattern>>24) )
match = 0x01;
else if( c== (uint8_t)((sfp_pattern>>16)&0xff) )
match |= 0x02;
else if( c== (uint8_t)((sfp_pattern>>8)&0xff) )
match |= 0x04;
else if( c== (uint8_t)(sfp_pattern&0xff) )
match |= 0x08;
else
match = 0x00;
if(match == 0x3f)
{
mi2c_get_byte(i2cif, &c, 1);
mi2c_stop(i2cif);
return i+1; //first address of first SFP in the list
}
}
mi2c_get_byte(i2cif, &c, 1);
mi2c_stop(i2cif);
return 0;
}
int8_t eeprom_get_sfpinfo(uint8_t i2cif, uint8_t i2c_addr, uint32_t offset, struct s_sfpinfo *sfpinfo, uint16_t section_sz)
{
uint8_t *buf;
uint32_t i;
uint8_t checksum, sum;
buf = (uint8_t *)sfpinfo;
eeprom_read(i2cif, i2c_addr, offset, buf, section_sz * sizeof(struct s_sfpinfo));
//read checksum
eeprom_read(i2cif, i2c_addr, offset+section_sz*sizeof(struct s_sfpinfo), &checksum, 1);
//count checksum
sum = (uint8_t) (section_sz>>8 & 0xff);
sum = (uint8_t) ((uint16_t) sum + (section_sz & 0xff)) & 0xff;
for(i=0; i<section_sz*sizeof(struct s_sfpinfo); ++i)
sum = (uint8_t) ((uint16_t)sum + *(buf+i)) & 0xff;
if(sum == checksum)
{
mprintf("%s: checksum match\n", __FUNCTION__);
return 0;
}
else
{
mprintf("%s: checksum error, %x | %x\n", __FUNCTION__, sum, checksum);
return -1;
}
}
int8_t access_eeprom(char *sfp_pn, int32_t *alpha, int32_t *deltaTx, int32_t *deltaRx)
{
uint16_t i;
uint8_t j;
uint16_t sfp_sz;
int32_t sfp_adr;
struct s_sfpinfo sfpinfo[SFPINFO_MAX];
mi2c_init(WRPC_FMC_I2C);
sfp_adr = eeprom_sfp_section(WRPC_FMC_I2C, FMC_EEPROM_ADR, 64*1024, &sfp_sz);
if(sfp_adr == -1)
{
mprintf("FMC EEPROM not found\n");
return -1;
}
else if(sfp_sz > SFPINFO_MAX)
{
//Ooops, there are too many of them, print warning
mprintf("! Warning ! too many SFP entries (%d)\n", sfp_sz);
sfp_sz = SFPINFO_MAX;
}
else if(sfp_sz == 0)
{
mprintf("EEPROM: could no find SFP section, staring with defaults\n");
return -1;
}
mprintf("EEPROM: found SFP section at %d size %d\n", (uint32_t)sfp_adr, (uint32_t)sfp_sz);
if( eeprom_get_sfpinfo(WRPC_FMC_I2C, FMC_EEPROM_ADR, sfp_adr, sfpinfo, sfp_sz))
{
mprintf("EEPROM ERROR\n");
return -1;
}
for(i=0; i<sfp_sz; ++i)
{
for(j=0; j<16; ++j)
{
if(sfp_pn[j] != sfpinfo[i].pn[j])
break;
}
if( j==16 ) //which means sfp_pn = sfpinfo[i].pn
{
mprintf("match SFP%d: pn=", i+1);
for(j=0; j<16; ++j)
mprintf("%c", sfpinfo[i].pn[j]);
//mprintf(" alpha=%x deltaTx=%x deltaRx=%x\n", sfpinfo[i].alpha, sfpinfo[i].deltaTx, sfpinfo[i].deltaRx);
*alpha = sfpinfo[i].alpha;
*deltaTx = sfpinfo[i].deltaTx;
*deltaRx = sfpinfo[i].deltaRx;
}
}
return 0;
}
/*
WR Endpoint (WR-compatible Ethernet MAC driver
Tomasz Wlostowski/CERN 2011
LGPL 2.1
*/
#include <stdio.h>
#include "board.h"
#include<endpoint.h>
#include "syscon.h"
#include <endpoint.h>
#include <hw/endpoint_regs.h>
#include <hw/endpoint_mdio.h>
#define UIS_PER_SERIAL_BIT 800
static int autoneg_enabled;
/* Length of a single bit on the gigabit serial link in picoseconds. Used for calculating deltaRx/deltaTx
from the serdes bitslip value */
#define PICOS_PER_SERIAL_BIT 800
static volatile struct EP_WB *EP = (volatile struct EP_WB *) BASE_EP;
/* Number of raw phase samples averaged by the DMTD detector in the Endpoint during single phase measurement.
The bigger, the better precision, but slower rate */
#define DMTD_AVG_SAMPLES 256
/* functions for accessing PCS registers */
static int autoneg_enabled;
static volatile struct EP_WB *EP = (volatile struct EP_WB *) BASE_EP;
static uint16_t pcs_read(int location)
/* functions for accessing PCS (MDIO) registers */
uint16_t pcs_read(int location)
{
EP->MDIO_CR = EP_MDIO_CR_ADDR_W(location >> 2);
while ((EP->MDIO_SR & EP_MDIO_SR_READY) == 0);
return EP_MDIO_SR_RDATA_R(EP->MDIO_SR) & 0xffff;
while ((EP->MDIO_ASR & EP_MDIO_ASR_READY) == 0);
return EP_MDIO_ASR_RDATA_R(EP->MDIO_ASR) & 0xffff;
}
static void pcs_write(int location,
int value)
void pcs_write(int location, int value)
{
EP->MDIO_CR = EP_MDIO_CR_ADDR_W(location >> 2)
| EP_MDIO_CR_DATA_W(value)
| EP_MDIO_CR_RW;
while ((EP->MDIO_SR & EP_MDIO_SR_READY) == 0);
while ((EP->MDIO_ASR & EP_MDIO_ASR_READY) == 0);
}
/* MAC address setting */
static void set_mac_addr(uint8_t dev_addr[])
{
EP->MACL = ((uint32_t)dev_addr[2] << 24)
......@@ -44,28 +60,34 @@ static void set_mac_addr(uint8_t dev_addr[])
void get_mac_addr(uint8_t dev_addr[])
{
dev_addr[5] = (uint8_t)(EP->MACL & 0x000000ff);
dev_addr[4] = (uint8_t)(EP->MACL & 0x0000ff00) >> 8;
dev_addr[3] = (uint8_t)(EP->MACL & 0x00ff0000) >> 16;
dev_addr[2] = (uint8_t)(EP->MACL & 0xff000000) >> 24;
dev_addr[1] = (uint8_t)(EP->MACH & 0x000000ff);
dev_addr[0] = (uint8_t)(EP->MACH & 0x0000ff00) >> 8;
dev_addr[5] = (EP->MACL & 0x000000ff);
dev_addr[4] = (EP->MACL & 0x0000ff00) >> 8;
dev_addr[3] = (EP->MACL & 0x00ff0000) >> 16;
dev_addr[2] = (EP->MACL & 0xff000000) >> 24;
dev_addr[1] = (EP->MACH & 0x000000ff);
dev_addr[0] = (EP->MACH & 0x0000ff00) >> 8;
}
/* Initializes the endpoint and sets its local MAC address */
void ep_init(uint8_t mac_addr[])
{
int i;
set_mac_addr(mac_addr);
EP->ECR = 0;
*(unsigned int *)(0x62000) = 0x2; // reset network stuff (cleanup required!)
*(unsigned int *)(0x62000) = 0;
EP->ECR = 0; /* disable Endpoint */
EP->VCR0 = EP_VCR0_QMODE_W(3); /* disable VLAN unit - not used by WRPC */
EP->RFCR = EP_RFCR_MRU_W(1518); /* Set the max RX packet size */
EP->TSCR = EP_TSCR_EN_TXTS | EP_TSCR_EN_RXTS; /* Enable timestamping */
/* Configure DMTD phase tracking */
EP->DMCR = EP_DMCR_EN | EP_DMCR_N_AVG_W(DMTD_AVG_SAMPLES);
EP->RFCR = 3 << EP_RFCR_QMODE_SHIFT;
EP->TSCR = EP_TSCR_EN_TXTS | EP_TSCR_EN_RXTS;
EP->FCR = 0;
}
/* Enables/disables transmission and reception. When autoneg is set to 1,
starts up 802.3 autonegotiation process */
int ep_enable(int enabled, int autoneg)
{
uint16_t mcr;
......@@ -73,30 +95,43 @@ int ep_enable(int enabled, int autoneg)
if(!enabled)
{
EP->ECR = 0;
return;
return 0;
}
EP->ECR = EP_ECR_TX_EN_FRA | EP_ECR_RX_EN_FRA | EP_ECR_RST_CNT;
/* Disable the endpoint */
EP->ECR = 0;
mprintf("ID: %x", EP->IDCODE);
/* Load default packet classifier rules - see ep_pfilter.c for details */
pfilter_init_default();
/* Enable TX/RX paths, reset RMON counters */
EP->ECR = EP_ECR_TX_EN | EP_ECR_RX_EN | EP_ECR_RST_CNT;
autoneg_enabled = autoneg;
#if 1
/* Reset the GTP Transceiver - it's important to do the GTP phase alignment every time
we start up the software, otherwise the calibration RX/TX deltas may not be correct */
pcs_write(MDIO_REG_MCR, MDIO_MCR_PDOWN); /* reset the PHY */
timer_delay(2000);
timer_delay(200);
pcs_write(MDIO_REG_MCR, MDIO_MCR_RESET); /* reset the PHY */
pcs_write(MDIO_REG_MCR, 0); /* reset the PHY */
// pcs_write(MDIO_REG_MCR, MDIO_MCR_RESET); /* reset the PHY */
#endif
/* Don't advertise anything - we don't want flow control */
pcs_write(MDIO_REG_ADVERTISE, 0);
mcr = MDIO_MCR_SPEED1000_MASK | MDIO_MCR_FULLDPLX_MASK;
if(autoneg)
mcr |= MDIO_MCR_ANENABLE | MDIO_MCR_ANRESTART;
pcs_write(MDIO_REG_MCR, mcr);
return 0;
}
int ep_link_up()
/* Checks the link status. If the link is up, returns non-zero
and stores the Link Partner Ability (LPA) autonegotiation register at *lpa */
int ep_link_up(uint16_t *lpa)
{
uint16_t flags = MDIO_MSR_LSTATUS;
volatile uint16_t msr;
......@@ -104,21 +139,26 @@ int ep_link_up()
if(autoneg_enabled)
flags |= MDIO_MSR_ANEGCOMPLETE;
msr = pcs_read(MDIO_REG_MSR);
msr = pcs_read(MDIO_REG_MSR);
msr = pcs_read(MDIO_REG_MSR); /* Read this flag twice to make sure the status is updated */
if(lpa) *lpa = pcs_read(MDIO_REG_LPA);
return (msr & flags) == flags ? 1 : 0;
}
/* Returns the TX/RX latencies. They are valid only when the link is up. */
int ep_get_deltas(uint32_t *delta_tx, uint32_t *delta_rx)
{
// mprintf("called ep_get_deltas()\n");
*delta_tx = 0;
*delta_rx = 15000 - 7000 + 195000 + 32000 + UIS_PER_SERIAL_BIT * MDIO_WR_SPEC_BSLIDE_R(pcs_read(MDIO_REG_WR_SPEC)) + 2800 - 9000;
/* fixme: these values should be stored in calibration block in the EEPROM on the FMC. Also, the TX/RX delays of a particular SFP
should be added here */
*delta_tx = 46407;
*delta_rx = 273593 + PICOS_PER_SERIAL_BIT * MDIO_WR_SPEC_BSLIDE_R(pcs_read(MDIO_REG_WR_SPEC));
return 0;
}
/* Prints out the RMON statistic counters */
void ep_show_counters()
{
int i;
......@@ -129,6 +169,7 @@ void ep_show_counters()
int ep_get_psval(int32_t *psval)
{
uint32_t val;
val = EP->DMSR;
if(val & EP_DMSR_PS_RDY)
......@@ -136,7 +177,7 @@ int ep_get_psval(int32_t *psval)
else
*psval = 0;
return val & EP_DMSR_PS_RDY;
return val & EP_DMSR_PS_RDY ? 1 : 0;
}
int ep_cal_pattern_enable()
......@@ -155,4 +196,6 @@ int ep_cal_pattern_disable()
val = pcs_read(MDIO_REG_WR_SPEC);
val &= (~MDIO_WR_SPEC_TX_CAL);
pcs_write(MDIO_REG_WR_SPEC, val);
return 0;
}
/* Endpoint Packet Filter/Classifier driver
A little explanation: The WR core needs to classify the incoming packets into
two (or more categories):
- PTP, ARP, DHCP packets, which should go to the WRCore CPU packet queue (mini-nic)
- Other packets matching user's provided pattern, which shall go to the external fabric
port - for example to Etherbone, host network controller, etc.
- packets to be dropped (used neither by the WR Core or the user application)
WR Endpoint (WR MAC) inside the WR Core therefore contains a simple microprogrammable
packet filter/classifier. The classifier processes the incoming packet, and assigns it
to one of 8 classes (an 8-bit word, where each bit corresponds to a particular class) or
eventually drops it. Hardware implementation of the unit is a simple VLIW processor with
32 single-bit registers (0 - 31). The registers are organized as follows:
- 0: don't touch (always 0)
- 1 - 22: general purpose registers
- 23: drop packet flag: if 1 at the end of the packet processing, the packet will be dropped.
- 24..31: packet class (class 0 = reg 24, class 7 = reg 31).
Program memory has 64 36-bit words. Packet filtering program is restarted every time a new packet comes.
There are 5 possible instructions:
1. CMP offset, value, mask, oper, Rd:
------------------------------------------
* Rd = Rd oper ((((uint16_t *)packet) [offset] & mask) == value)
Examples:
* CMP 3, 0xcafe, 0xffff, MOV, Rd
will compare the 3rd word of the packet (bytes 6, 7) against 0xcafe and if the words are equal,
1 will be written to Rd register.
* CMP 4, 0xbabe, 0xffff, AND, Rd
will do the same with the 4th word and write to Rd its previous value ANDed with the result
of the comparison. Effectively, Rd now will be 1 only if bytes [6..9] of the payload contain word
0xcafebabe.
Note that the mask value is nibble-granular. That means you can choose a particular
set of nibbles within a word to be compared, but not an arbitrary set of bits (e.g. 0xf00f, 0xff00
and 0xf0f0 masks are ok, but 0x8001 is wrong.
2. BTST offset, bit_number, oper, Rd
------------------------------------------
* Rd = Rd oper (((uint16_t *)packet) [offset] & (1<<bit_number) ? 1 : 0)
Examples:
* BTST 3, 10, MOV, 11
will write 1 to reg 11 if the 10th bit in the 3rd word of the packet is set (and 0 if it's clear)
3. Logic opearations:
-----------------------------------------
* LOGIC2 Rd, Ra, OPER Rb - 2 argument logic (Rd = Ra OPER Rb). If the operation is MOV or NOT, Ra is
taken as the source register.
* LOGIC3 Rd, Ra, OPER Rb, OPER2, Rc - 3 argument logic Rd = (Ra OPER Rb) OPER2 Rc.
4. Misc
-----------------------------------------
FIN instruction terminates the program.
NOP executes a dummy instruction (LOGIC2 0, 0, AND, 0)
IMPORTANT:
- the program counter is advanved each time a 16-bit words of the packet arrives.
- the CPU doesn't have any interlocks to simplify the HW, so you can't compare the
10th word when PC = 2. Max comparison offset is always equal to the address of the instruction.
- Code may contain up to 64 operations, but it must classify shorter packets faster than in
32 instructions (there's no flow throttling)
*/
#include <stdio.h>
#include "board.h"
#include <endpoint.h>
#include <hw/endpoint_regs.h>
#define PFILTER_MAX_CODE_SIZE 32
#define pfilter_dbg
static volatile struct EP_WB *EP = (volatile struct EP_WB *) BASE_EP;
static const uint64_t PF_MODE_LOGIC = (1ULL<<34);
static const uint64_t PF_MODE_CMP = 0ULL;
static int code_pos;
static uint64_t code_buf[32];
/* begins assembling a new packet filter program */
void pfilter_new()
{
code_pos = 0;
}
static void check_size()
{
if(code_pos == PFILTER_MAX_CODE_SIZE - 1)
{
pfilter_dbg("microcode: code too big (max size: %d)\n", PFILTER_MAX_CODE_SIZE);
}
}
static void check_reg_range(int val, int minval, int maxval, char *name)
{
if(val < minval || val > maxval)
{
pfilter_dbg("microcode: %s register out of range (%d to %d)", name, minval,maxval);
}
}
void pfilter_cmp(int offset, int value, int mask, pfilter_op_t op, int rd)
{
uint64_t ir;
check_size();
if(offset > code_pos)
pfilter_dbg("microcode: comparison offset is bigger than current PC. Insert some nops before comparing");
check_reg_range(rd, 1, 15, "ra/rd");
ir = (PF_MODE_CMP | ((uint64_t)offset << 7)
| ((mask & 0x1) ? (1ULL<<29) : 0)
| ((mask & 0x10) ? (1ULL<<30) : 0)
| ((mask & 0x100) ? (1ULL<<31) : 0)
| ((mask & 0x1000) ? (1ULL<<32) : 0))
| op | (rd << 3);
ir = ir | ((uint64_t)value & 0xffffULL) << 13;
code_buf[code_pos++] = ir;
}
// rd = (packet[offset] & (1<<bit_index)) op rd
void pfilter_btst(int offset, int bit_index, pfilter_op_t op, int rd)
{
uint64_t ir;
check_size();
if(offset > code_pos)
pfilter_dbg("microcode: comparison offset is bigger than current PC. Insert some nops before comparing");
check_reg_range(rd, 1, 15, "ra/rd");
check_reg_range(bit_index, 0, 15, "bit index");
ir = ((1ULL<<33) | PF_MODE_CMP | ((uint64_t)offset << 7) | ((uint64_t)bit_index << 29) | (uint64_t)op | ((uint64_t)rd << 3));
code_buf[code_pos++] = ir;
}
void pfilter_nop()
{
uint64_t ir;
check_size();
ir = PF_MODE_LOGIC;
code_buf[code_pos++] = ir;
}
// rd = ra op rb
void pfilter_logic2(int rd, int ra, pfilter_op_t op, int rb)
{
uint64_t ir;
check_size();
check_reg_range(ra, 0, 31, "ra");
check_reg_range(rb, 0, 31, "rb");
check_reg_range(rd, 1, 31, "rd");
ir = ((uint64_t)ra << 8) | ((uint64_t)rb << 13) | (((uint64_t)rd & 0xf) << 3) | (((uint64_t)rd & 0x10) ? (1ULL<<7) : 0) | (uint64_t)op;
ir = ir | PF_MODE_LOGIC | (3ULL<<23);
code_buf[code_pos++] = ir;
}
static void pfilter_logic3(int rd, int ra, pfilter_op_t op, int rb, pfilter_op_t op2, int rc)
{
uint64_t ir;
check_size();
check_reg_range(ra, 0, 31, "ra");
check_reg_range(rb, 0, 31, "rb");
check_reg_range(rc, 0, 31, "rb");
check_reg_range(rd, 1, 31, "rd");
ir = (ra << 8) | (rb << 13) | (rc << 18) | ((rd & 0xf) << 3) | ((rd & 0x10) ? (1<<7) : 0) | op;
ir = ir | PF_MODE_LOGIC | (op2<<23);
code_buf[code_pos++] = ir;
}
/* Terminates the microcode, loads it to the endpoint and enables the pfilter */
void pfilter_load()
{
int i;
code_buf[code_pos++] = (1ULL<<35); // insert FIN instruction
EP->PFCR0 = 0; // disable pfilter
for(i=0;i<code_pos;i++)
{
uint32_t cr0, cr1;
cr1 = EP_PFCR1_MM_DATA_LSB_W(code_buf[i] & 0xfff);
cr0 = EP_PFCR0_MM_ADDR_W(i) | EP_PFCR0_MM_DATA_MSB_W(code_buf[i]>>12) | EP_PFCR0_MM_WRITE_MASK;
EP->PFCR1 = cr1;
EP->PFCR0 = cr0;
}
EP->PFCR0 = EP_PFCR0_ENABLE;
}
/* sample packet filter initialization:
- redirects broadcasts and PTP packets to the WR Core
- redirects unicasts addressed to self with ethertype 0xa0a0 to the external fabric */
#define R_CLASS(x) (24 + x)
#define R_DROP 23
void pfilter_init_default()
{
pfilter_new();
pfilter_nop();
pfilter_cmp(0, 0xffff, 0xffff, MOV, 1);
pfilter_cmp(1, 0xffff, 0xffff, AND, 1);
pfilter_cmp(2, 0xffff, 0xffff, AND, 1); /* r1 = 1 when dst mac is broadcast */
pfilter_cmp(0, 0x011b, 0xffff, MOV, 2);
pfilter_cmp(1, 0x1900, 0xffff, AND, 2);
pfilter_cmp(2, 0x0000, 0xffff, AND, 2); /* r2 = 1 when dst mac is PTP multicast (01:1b:19:00:00:00) */
pfilter_cmp(0, EP->MACH & 0xffff, 0xffff, MOV, 3);
pfilter_cmp(1, EP->MACL >> 16, 0xffff, AND, 3);
pfilter_cmp(2, EP->MACL & 0xffff, 0xffff, AND, 3); /* r3 = 1 when the packet is unicast to our own MAC */
pfilter_cmp(6, 0xa0a0, 0xffff, MOV, 4); /* r4 = 1 when ethertype = 0xa0a0 */
pfilter_cmp(6, 0x88f7, 0xffff, MOV, 5); /* r5 = 1 when ethertype = PTPv2 */
pfilter_logic3(7, 3, AND, 4, OR, 5); /* r5 = PTP or etherbone */
pfilter_logic2(R_DROP, 7, NOT, 0); /* Neither PTP or etherbone? drop */
pfilter_logic2(R_CLASS(7), 3, AND, 4); // class 7: minibone unicasts
pfilter_logic2(R_CLASS(0), 5, MOV, 0); // class 7: minibone unicasts
pfilter_load();
}
\ No newline at end of file
#include "types.h"
#include "board.h"
#include "gpio.h"
#include "syscon.h"
#define I2C_DELAY 100
#define I2C_DELAY 300
static void mi2c_delay()
void mi2c_delay()
{
int i;
for(i=0;i<I2C_DELAY;i++) asm volatile ("nop");
}
#define M_SDA_OUT(x) { gpio_out(GPIO_PIN_SDA_OUT, x); mi2c_delay(); }
#define M_SCL_OUT(x) { gpio_out(GPIO_PIN_SCL_OUT, x); mi2c_delay(); }
#define M_SDA_IN gpio_in(GPIO_PIN_SDA_IN)
#define M_SDA_OUT(i, x) { gpio_out(i2c_if[i].sda, x); mi2c_delay(); }
#define M_SCL_OUT(i, x) { gpio_out(i2c_if[i].scl, x); mi2c_delay(); }
#define M_SDA_IN(i) gpio_in(i2c_if[i].sda)
void mi2c_start()
void mi2c_start(uint8_t i2cif)
{
M_SDA_OUT(0);
M_SCL_OUT(0);
M_SDA_OUT(i2cif, 0);
M_SCL_OUT(i2cif, 0);
}
void mi2c_repeat_start()
void mi2c_repeat_start(uint8_t i2cif)
{
M_SDA_OUT(1);
M_SCL_OUT(1);
M_SDA_OUT(0);
M_SCL_OUT(0);
M_SDA_OUT(i2cif, 1);
M_SCL_OUT(i2cif, 1);
M_SDA_OUT(i2cif, 0);
M_SCL_OUT(i2cif, 0);
}
void mi2c_stop()
void mi2c_stop(uint8_t i2cif)
{
M_SDA_OUT(0);
M_SCL_OUT(1);
M_SDA_OUT(1);
M_SDA_OUT(i2cif, 0);
M_SCL_OUT(i2cif, 1);
M_SDA_OUT(i2cif, 1);
}
unsigned char mi2c_put_byte(unsigned char data)
unsigned char mi2c_put_byte(uint8_t i2cif, 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(i2cif, data&0x80);
M_SCL_OUT(i2cif, 1);
M_SCL_OUT(i2cif, 0);
}
M_SDA_OUT(1);
M_SCL_OUT(1);
M_SDA_OUT(i2cif, 1);
M_SCL_OUT(i2cif, 1);
ack = M_SDA_IN; /* ack: sda is pulled low ->success. */
ack = M_SDA_IN(i2cif); /* ack: sda is pulled low ->success. */
M_SCL_OUT(0);
M_SDA_OUT(0);
M_SCL_OUT(i2cif, 0);
M_SDA_OUT(i2cif, 0);
return ack!=0;
}
void mi2c_get_byte(unsigned char *data)
void mi2c_get_byte(uint8_t i2cif, unsigned char *data, uint8_t last)
{
int i;
unsigned char indata = 0;
M_SDA_OUT(i2cif, 1);
/* assert: scl is low */
M_SCL_OUT(0);
M_SCL_OUT(i2cif, 0);
for (i=0;i<8;i++)
{
M_SCL_OUT(1);
M_SCL_OUT(i2cif, 1);
indata <<= 1;
if ( M_SDA_IN ) indata |= 0x01;
M_SCL_OUT(0);
if ( M_SDA_IN(i2cif) ) indata |= 0x01;
M_SCL_OUT(i2cif, 0);
}
if(last)
{
M_SDA_OUT(i2cif, 1); //noack
M_SCL_OUT(i2cif, 1);
M_SCL_OUT(i2cif, 0);
}
else
{
M_SDA_OUT(i2cif, 0); //ack
M_SCL_OUT(i2cif, 1);
M_SCL_OUT(i2cif, 0);
}
M_SDA_OUT(1);
*data= indata;
}
void mi2c_init()
void mi2c_init(uint8_t i2cif)
{
gpio_dir(GPIO_PIN_SDA_OUT, 1);
gpio_dir(GPIO_PIN_SCL_OUT, 1);
gpio_dir(GPIO_PIN_SDA_IN, 0);
M_SCL_OUT(1);
M_SDA_OUT(1);
M_SCL_OUT(i2cif, 1);
M_SDA_OUT(i2cif, 1);
}
void mi2c_scan()
{
int i;
for(i=0;i<0x80;i++)
{
mi2c_start();
mprintf("scan %d\n",i);
if(!mi2c_put_byte(i<<1)) mprintf("found : %x\n", i);
mi2c_stop();
}
}
//void mi2c_scan(uint8_t i2cif)
//{
// int i;
//
// for(i=0;i<0x80;i++)
// {
// mi2c_start(i2cif);
// if(!mi2c_put_byte(i2cif, i<<1)) mprintf("found : %x\n", i);
// mi2c_stop(i2cif);
//
// }
//}
......@@ -18,7 +18,9 @@
#define RX_DESC_VALID(d) ((d) & (1<<31) ? 1 : 0)
#define RX_DESC_ERROR(d) ((d) & (1<<30) ? 1 : 0)
#define RX_DESC_HAS_OOB(d) ((d) & (1<<29) ? 1 : 0)
#define RX_DESC_SIZE(d) (((d) & (1<<0) ? -1 : 0) + (d & 0xfffe))
#define RX_DESC_SIZE(d) (((d) & (1<<0) ? -1 : 0) + (d & 0xffe))
#define RXOOB_TS_INCORRECT (1<<11)
#define TX_DESC_VALID (1<<31)
#define TX_DESC_WITH_OOB (1<<30)
......@@ -77,6 +79,8 @@ static void minic_new_rx_buffer()
// TRACE_DEV("Sizeof: %d Size : %d Avail: %d\n", minic.rx_size, (minic.rx_size - MINIC_MTU) >> 2);
minic_writel(MINIC_REG_MCR, MINIC_MCR_RX_EN);
//mprintf("Base : %x Avail: %d\n", minic_readl(MINIC_REG_RX_ADDR), minic_readl(MINIC_REG_RX_AVAIL));
}
static void minic_new_tx_buffer()
......@@ -90,20 +94,29 @@ static void minic_new_tx_buffer()
void minic_init()
{
uint32_t lo , hi;
minic_writel(MINIC_REG_EIC_IDR, MINIC_EIC_IDR_RX);
minic_writel(MINIC_REG_EIC_ISR, MINIC_EIC_ISR_RX);
minic.rx_base = dma_rx_buf;
minic.rx_size = sizeof(dma_rx_buf);
/* FIXME: now we have a temporary HW protection against accidentally overwriting the memory - there's some
very well hidden bug in Minic's RX logic which sometimes causes an overwrite of the memory outside
the buffer. */
lo = (uint32_t)minic.rx_base >> 2;
hi = ((uint32_t)minic.rx_base >> 2) + (sizeof(dma_rx_buf)>>2) - 1;
minic_writel(MINIC_REG_MPROT, MINIC_MPROT_LO_W(lo) | MINIC_MPROT_HI_W(hi));
minic.tx_base = dma_tx_buf;
minic.tx_size = sizeof(dma_tx_buf);
minic.tx_count = 0;
minic.rx_count = 0;
minic_new_rx_buffer();
minic_writel(MINIC_REG_EIC_IER, MINIC_EIC_IER_RX);
}
......@@ -128,19 +141,18 @@ int minic_rx_frame(uint8_t *hdr, uint8_t *payload, uint32_t buf_size, struct hw_
uint32_t desc_hdr;
uint32_t raw_ts;
uint32_t rx_addr_cur;
int i;
int n_recvd;
// mprintf("erxf\n");
if(! (minic_readl(MINIC_REG_EIC_ISR) & MINIC_EIC_ISR_RX))
return 0;
desc_hdr = *minic.rx_head;
//TRACE_DEV("minic: got sthx \n");
// TRACE_DEV("RX_FRAME_ENTER\n\nRxHead %x buffer at %x\n", minic.rx_head, minic.rx_base);
desc_hdr = *minic.rx_head;
if(!RX_DESC_VALID(desc_hdr)) /* invalid descriptor? Weird, the RX_ADDR seems to be saying something different. Ignore the packet and purge the RX buffer. */
{
TRACE_DEV("weird, invalid RX descriptor (%x, head %x)\n", desc_hdr, minic.rx_head);
minic_new_rx_buffer();
return 0;
}
......@@ -148,8 +160,8 @@ int minic_rx_frame(uint8_t *hdr, uint8_t *payload, uint32_t buf_size, struct hw_
payload_size = RX_DESC_SIZE(desc_hdr);
num_words = ((payload_size + 3) >> 2) + 1;
// mprintf("Payload: %d\n", payload_size);
// TRACE_DEV("NWords %d\n", num_words);
/* valid packet */
if(!RX_DESC_ERROR(desc_hdr))
{
......@@ -158,11 +170,12 @@ int minic_rx_frame(uint8_t *hdr, uint8_t *payload, uint32_t buf_size, struct hw_
{
uint32_t counter_r, counter_f, counter_ppsg, utc;
int cntr_diff;
uint16_t dhdr;
payload_size -= RX_OOB_SIZE;
memcpy(&raw_ts, (uint8_t *)minic.rx_head + payload_size + 6, 4); /* fixme: ugly way of doing unaligned read */
memcpy(&dhdr, (uint8_t *)minic.rx_head + payload_size + 4, 2);
EXPLODE_WR_TIMESTAMP(raw_ts, counter_r, counter_f);
pps_gen_get_time(&utc, &counter_ppsg);
......@@ -179,39 +192,33 @@ int minic_rx_frame(uint8_t *hdr, uint8_t *payload, uint32_t buf_size, struct hw_
else
hwts->ahead = 0;
hwts->nsec = counter_r * 8;
hwts->valid = (dhdr & RXOOB_TS_INCORRECT) ? 0 : 1;
}
n_recvd = (buf_size < payload_size ? buf_size : payload_size);
TRACE_DEV("minic_rx_frame [%d bytes] TS: %d.%d\n", n_recvd, hwts->utc, hwts->nsec);
minic.rx_count++;
memcpy(hdr, (void*)minic.rx_head + 4, ETH_HEADER_SIZE);
memcpy(payload, (void*)minic.rx_head + 4 + ETH_HEADER_SIZE, n_recvd - ETH_HEADER_SIZE);
minic.rx_head += num_words;
} else { // RX_DESC_ERROR
// TRACE_DEV("nwords_avant_err: %d\n", num_words);
} else {
minic.rx_head += num_words;
n_recvd = -1;
}
rx_addr_cur = minic_readl(MINIC_REG_RX_ADDR) & 0xffff;
if(rx_addr_cur < (uint32_t)minic.rx_head) /* nothing new in the buffer? */
{
// TRACE_DEV("MoreData? %x, head %x\n", rx_addr_cur, minic.rx_head);
if(minic_readl(MINIC_REG_MCR) & MINIC_MCR_RX_FULL)
minic_new_rx_buffer();
minic_writel(MINIC_REG_EIC_ISR, MINIC_EIC_ISR_RX);
}
// TRACE_DEV("minic: num_rx %d\n", n_recvd);
return n_recvd;
}
......@@ -221,10 +228,11 @@ static uint16_t tx_oob_val = 0;
int minic_tx_frame(uint8_t *hdr, uint8_t *payload, uint32_t size, struct hw_timestamp *hwts)
{
uint32_t d_hdr, mcr, nwords;
uint8_t ts_valid;
minic_new_tx_buffer();
TRACE_DEV("minic_tx_frame: head %x size %d\n", minic.tx_head, size);
// TRACE_DEV("minic_tx_frame: head %x size %d\n", minic.tx_head, size);
memset(minic.tx_head, 0x0, size + 16);
memset((void*)minic.tx_head + 4, 0, size < 60 ? 60 : size);
memcpy((void*)minic.tx_head + 4, hdr, ETH_HEADER_SIZE);
......@@ -233,18 +241,12 @@ int minic_tx_frame(uint8_t *hdr, uint8_t *payload, uint32_t size, struct hw_time
if(size < 60)
size = 60;
nwords = ((size + 1) >> 1) - 1;
nwords = ((size + 1) >> 1);
d_hdr = 0;
if(hwts)
{
memcpy((void *) minic.tx_head + 4 + size, &tx_oob_val, sizeof(uint16_t));
nwords++;
d_hdr = TX_DESC_WITH_OOB;
} else
d_hdr = 0;
d_hdr = TX_DESC_WITH_OOB | (tx_oob_val << 12);
d_hdr |= TX_DESC_VALID | nwords;
......@@ -254,7 +256,9 @@ int minic_tx_frame(uint8_t *hdr, uint8_t *payload, uint32_t size, struct hw_time
mcr = minic_readl(MINIC_REG_MCR);
minic_writel(MINIC_REG_MCR, mcr | MINIC_MCR_TX_START);
while((minic_readl(MINIC_REG_MCR) & MINIC_MCR_TX_IDLE) == 0);
#if 1
if(hwts) /* wait for the timestamp */
{
uint32_t raw_ts;
......@@ -262,16 +266,12 @@ int minic_tx_frame(uint8_t *hdr, uint8_t *payload, uint32_t size, struct hw_time
uint32_t counter_r, counter_f;
uint32_t utc;
uint32_t nsec;
uint8_t ts_tout;
//while((minic_readl(MINIC_REG_TSR0) & MINIC_TSR0_VALID) == 0);
ts_valid = (uint8_t) (minic_readl(MINIC_REG_TSR0) & MINIC_TSR0_VALID);
ts_tout=0;
while( (minic_readl(MINIC_REG_TSFIFO_CSR) & MINIC_TSFIFO_CSR_EMPTY ) && ts_tout<10)
ts_tout++;
raw_ts = minic_readl(MINIC_REG_TSFIFO_R0);
fid = (minic_readl(MINIC_REG_TSFIFO_R1) >> 5) & 0xffff;
raw_ts = minic_readl(MINIC_REG_TSR1);
fid = MINIC_TSR0_FID_R(minic_readl(MINIC_REG_TSR0));
if(fid != tx_oob_val)
{
......@@ -283,15 +283,16 @@ int minic_tx_frame(uint8_t *hdr, uint8_t *payload, uint32_t size, struct hw_time
if(counter_r > 3*125000000/4 && nsec < 125000000/4)
utc--;
hwts->valid = ts_valid;
hwts->utc = utc;
hwts->ahead = 0;
hwts->nsec = counter_r * 8;
TRACE_DEV("minic_tx_frame [%d bytes] TS: %d.%d\n", size, hwts->utc, hwts->nsec);
// TRACE_DEV("minic_tx_frame [%d bytes] TS: %d.%d valid %d\n", size, hwts->utc, hwts->nsec, hwts->valid);
minic.tx_count++;
}
#endif
tx_oob_val++;
return size;
......
#include <stdio.h>
#include "board.h"
#define R_CSR 0x0
#define R_CDR 0x4
#define CSR_DAT_MSK (1<<0)
#define CSR_RST_MSK (1<<1)
#define CSR_OVD_MSK (1<<2)
#define CSR_CYC_MSK (1<<3)
#define CSR_PWR_MSK (1<<4)
#define CSR_IRQ_MSK (1<<6)
#define CSR_IEN_MSK (1<<7)
#define CSR_SEL_OFS 8
#define CSR_SEL_MSK (0xF<<8)
#define CSR_POWER_OFS 16
#define CSR_POWER_MSK (0xFFFF<<16)
#define CDR_NOR_MSK (0xFFFF<<0)
#define CDR_OVD_OFS 16
#define CDR_OVD_MSK (0xFFFF<<16)
#define CLK_DIV_NOR 175 //clock divider for normal mode
#define CLK_DIV_OVD 124/2 //clock divider for overdrive mode
static inline void ow_writel(uint32_t reg, uint32_t data)
{
*(volatile uint32_t *) (BASE_ONEWIRE + reg) = data;
}
static inline uint32_t ow_readl(uint32_t reg)
{
return *(volatile uint32_t *)(BASE_ONEWIRE + reg);
}
void ow_init()
{
//set clock dividers for normal and overdrive mode
ow_writel( R_CDR, ((CLK_DIV_NOR & CDR_NOR_MSK) | (( CLK_DIV_OVD << CDR_OVD_OFS) & CDR_OVD_MSK)) );
}
static uint32_t ow_reset(uint32_t port)
{
uint32_t reg, data;
data = ( (port<<CSR_SEL_OFS) & CSR_SEL_MSK) |
CSR_CYC_MSK | CSR_RST_MSK; //start cycle, rst pulse request
ow_writel(R_CSR, data);
//wait until cycle done
while(ow_readl(R_CSR) & CSR_CYC_MSK);
reg = ow_readl(R_CSR);
return ~reg & CSR_DAT_MSK;
}
static uint32_t slot(uint32_t port, uint32_t bit)
{
uint32_t data, reg;
data = ( (port<<CSR_SEL_OFS) & CSR_SEL_MSK) |
CSR_CYC_MSK | (bit & CSR_DAT_MSK); //start cycle, write bit
ow_writel(R_CSR, data);
//wait until cycle done
while( ow_readl(R_CSR) & CSR_CYC_MSK );
reg = ow_readl(R_CSR);
return reg & CSR_DAT_MSK;
}
static uint32_t ow_read_bit(uint32_t port) { return slot(port, 0x1); }
static uint32_t ow_write_bit(uint32_t port, uint32_t bit) { return slot(port, bit); }
uint8_t ow_read_byte(uint32_t port)
{
uint32_t data = 0, i;
for(i=0;i<8;i++)
data |= ow_read_bit(port) << i;
return (uint8_t)data;
}
int8_t ow_write_byte(uint32_t port, uint32_t byte)
{
uint32_t data = 0;
uint8_t i;
uint32_t byte_old = byte;
for (i=0;i<8;i++)
{
data |= ow_write_bit(port, (byte & 0x1)) << i;
byte >>= 1;
}
return byte_old == data ? 0 : -1;
}
int ow_write_block(int port, uint8_t *block, int len)
{
uint32_t i;
for(i=0;i<len;i++)
*block++ = ow_write_byte(port, *block);
return 0;
}
int ow_read_block(int port, uint8_t *block, int len)
{
uint32_t i;
for(i=0;i<len;i++)
*block++ = ow_read_byte(port);
return 0;
}
#define ROM_SEARCH 0xF0
#define ROM_READ 0x33
#define ROM_MATCH 0x55
#define ROM_SKIP 0xCC
#define ROM_ALARM_SEARCH 0xEC
#define CONVERT_TEMP 0x44
#define WRITE_SCRATCHPAD 0x4E
#define READ_SCRATCHPAD 0xBE
#define COPY_SCRATCHPAD 0x48
#define RECALL_EEPROM 0xB8
#define READ_POWER_SUPPLY 0xB4
static uint8_t ds18x_id [8];
int8_t ds18x_read_serial(uint8_t *id)
{
uint8_t i;
if(!ow_reset(0))
return -1;
if(ow_write_byte(0, ROM_READ) < 0)
return -1;
for(i=0;i<8;i++)
{
*id = ow_read_byte(0);
id++;
}
return 0;
}
static int8_t ds18x_access(uint8_t *id)
{
int i;
if(!ow_reset(0))
return -1;
if(ow_write_byte(0, ROM_MATCH) < 0)
return -1;
for(i=0;i<8;i++)
if(ow_write_byte(0, id[i]) < 0)
return -1;
return 0;
}
int8_t ds18x_read_temp(uint8_t *id, int *temp_r)
{
int i, temp;
uint8_t data[9];
if(ds18x_access(id) < 0)
return -1;
ow_write_byte(0, READ_SCRATCHPAD);
for(i=0;i<9;i++) data[i] = ow_read_byte(0);
temp = ((int)data[1] << 8) | ((int)data[0]);
if(temp & 0x1000)
temp = -0x10000 + temp;
ds18x_access(id);
ow_write_byte(0, CONVERT_TEMP);
if(temp_r) *temp_r = temp;
return 0;
}
int ds18x_init()
{
ow_init();
if(ds18x_read_serial(ds18x_id) < 0)
return -1;
return ds18x_read_temp(ds18x_id, NULL);
}
......@@ -6,15 +6,7 @@
#define PPS_PULSE_WIDTH 100000
static inline void ppsg_writel(uint32_t reg,uint32_t data)
{
*(volatile uint32_t *) (BASE_PPSGEN + reg) = data;
}
static inline uint32_t ppsg_readl(uint32_t reg)
{
return *(volatile uint32_t *)(BASE_PPSGEN + reg);
}
static volatile struct PPSG_WB *PPSG = (volatile struct PPS_GEN_WB *) BASE_PPS_GEN;
void pps_gen_init()
{
......@@ -22,49 +14,38 @@ void pps_gen_init()
cr = PPSG_CR_CNT_EN | PPSG_CR_PWIDTH_W(PPS_PULSE_WIDTH);
ppsg_writel( PPSG_REG_CR, cr);
PPSG->CR = cr;
PPSG->ESCR = 0;
ppsg_writel( PPSG_REG_ADJ_UTCLO, 100 );
ppsg_writel( PPSG_REG_ADJ_UTCHI, 0);
ppsg_writel( PPSG_REG_ADJ_NSEC, 0);
PPSG->ADJ_UTCLO = 100;
PPSG->ADJ_UTCHI = 0;
PPSG->ADJ_NSEC = 0;
ppsg_writel( PPSG_REG_CR, cr | PPSG_CR_CNT_SET);
ppsg_writel( PPSG_REG_CR, cr);
PPSG->CR = cr | PPSG_CR_CNT_SET;
PPSG->CR = cr;
}
void pps_gen_adjust_nsec(int32_t how_much)
{
uint32_t cr;
TRACE_DEV("ADJ: nsec %d nanoseconds\n", how_much);
#if 1
ppsg_writel( PPSG_REG_ADJ_UTCLO, 0);
ppsg_writel( PPSG_REG_ADJ_UTCHI, 0);
ppsg_writel( PPSG_REG_ADJ_NSEC, ( how_much / 8 ));
ppsg_writel( PPSG_REG_CR, PPSG_CR_CNT_EN | PPSG_CR_PWIDTH_W(PPS_PULSE_WIDTH) | PPSG_CR_CNT_ADJ);
#endif
PPSG->ADJ_UTCLO = 0;
PPSG->ADJ_UTCHI = 0;
PPSG->ADJ_NSEC = ( how_much / 8 );
PPSG->CR = PPSG_CR_CNT_EN | PPSG_CR_PWIDTH_W(PPS_PULSE_WIDTH) | PPSG_CR_CNT_ADJ;
}
void pps_gen_adjust_utc(int32_t how_much)
{
uint32_t cr;
#if 1
TRACE_DEV("ADJ: utc %d seconds\n", how_much);
ppsg_writel( PPSG_REG_ADJ_UTCLO, how_much);
ppsg_writel( PPSG_REG_ADJ_UTCHI, 0);
ppsg_writel( PPSG_REG_ADJ_NSEC, 0);
ppsg_writel( PPSG_REG_CR, PPSG_CR_CNT_EN | PPSG_CR_PWIDTH_W(PPS_PULSE_WIDTH) | PPSG_CR_CNT_ADJ);
#endif
PPSG->ADJ_UTCLO = how_much;
PPSG->ADJ_UTCHI = 0;
PPSG->ADJ_NSEC = 0;
PPSG->CR = PPSG_CR_CNT_EN | PPSG_CR_PWIDTH_W(PPS_PULSE_WIDTH) | PPSG_CR_CNT_ADJ;
}
int pps_gen_busy()
{
return ppsg_readl(PPSG_REG_CR) & PPSG_CR_CNT_ADJ ? 0 : 1;
return PPSG->CR & PPSG_CR_CNT_ADJ ? 0 : 1;
}
void pps_gen_get_time(uint32_t *utc, uint32_t *cntr_nsec)
......@@ -73,13 +54,23 @@ void pps_gen_get_time(uint32_t *utc, uint32_t *cntr_nsec)
uint32_t utc_lo;
do {
cyc_before =ppsg_readl(PPSG_REG_CNTR_NSEC) & 0xfffffff;
utc_lo = ppsg_readl(PPSG_REG_CNTR_UTCLO) ;
cyc_after = ppsg_readl(PPSG_REG_CNTR_NSEC) & 0xfffffff;
cyc_before = PPSG->CNTR_NSEC & 0xfffffff;
utc_lo = PPSG->CNTR_UTCLO ;
cyc_after = PPSG->CNTR_NSEC & 0xfffffff;
} while (cyc_after < cyc_before);
delay(100000);
// delay(100000);
if(utc) *utc = utc_lo;
if(cntr_nsec) *cntr_nsec = cyc_after;
}
void pps_gen_enable_output(int enable)
{
if(enable)
PPSG->ESCR = PPSG_ESCR_PPS_VALID | PPSG_ESCR_TM_VALID;
else
PPSG->ESCR = 0;
}
#include "board.h"
#include "irq.h"
#include <hw/softpll_regs.h>
#include "gpio.h"
#define TAG_BITS 20
#define HPLL_N 14
#define HPLL_DAC_BIAS 30000
#define PI_FRACBITS 12
#define CHAN_FB 8
#define CHAN_REF 4
#define CHAN_PERIOD 2
//#define CHAN_HPLL 1
#define READY_FB (8<<4)
#define READY_REF (4<<4)
#define READY_PERIOD (2<<4)
//#define READY_HPLL (1<<4)
static volatile struct SPLL_WB *SPLL = (volatile struct SPLL_WB *) BASE_SOFTPLL;
struct softpll_config {
int hpll_f_kp;
int hpll_f_ki;
int hpll_f_setpoint;
int hpll_ld_f_samples;
int hpll_ld_f_threshold;
int hpll_p_kp;
int hpll_p_ki;
int hpll_ld_p_samples;
int hpll_ld_p_threshold;
int hpll_delock_threshold;
int hpll_dac_bias;
int dpll_f_kp;
int dpll_f_ki;
int dpll_p_kp;
int dpll_p_ki;
int dpll_ld_samples;
int dpll_ld_threshold;
int dpll_delock_threshold;
int dpll_dac_bias;
int dpll_deglitcher_threshold;
};
const struct softpll_config pll_cfg =
{
/* Helper PLL */
28*32*16, // f_kp
50*32*16, // f_ki
16, // setpoint
2000, // lock detect freq samples
2, // lock detect freq threshold
2.0*32*16, // p_kp
0.05*32*16, // p_ki
1000, // lock detect phase samples
1000, // lock detect phase threshold
2000, // delock threshold
32000, // HPLL dac bias
/* DMTD PLL */
100, // f_kp
600, // f_ki
1304, // p_kp
10, // p_ki
1000, // lock detect samples
500, // lock detect threshold
500, // delock threshold
32000, // DPLL dac bias
2000 // deglitcher threshold
};
struct softpll_state {
int h_lock_counter;
int h_i;
int h_dac_bias;
int h_p_setpoint;
int h_freq_mode;
int h_locked;
int h_dac_val;
int h_freq_err;
int h_tag;
int d_dac_bias;
int d_tag_ref_d0;
int d_tag_fb_d0;
int d_tag_ref_ready;
int d_tag_fb_ready;
int d_period_ref;
int d_period_fb;
int d_freq_mode;
int d_lock_counter;
int d_freq_error;
int d_i;
int d_p_setpoint;
int d_phase_shift;
int d_locked;
};
int eee, dve;
static volatile struct softpll_state pstate;
volatile int irq_cnt = 0;
volatile int sp_limit = 0xffff;
void _irq_entry()
{
int dv;
int tag_ref_ready = 0;
int tag_fb_ready = 0;
int tag_ref;
int tag_fb;
// int sp = _get_sp();
irq_cnt ++;
gpio_out(GPIO_PIN_LED_STATUS, 1);
if(SPLL->CSR & READY_REF)
{
tag_ref = SPLL->TAG_REF;
tag_ref_ready = 1;
}
if(SPLL->CSR & READY_FB)
{
tag_fb = SPLL->TAG_FB;
tag_fb_ready = 1;
}
/* HPLL: active frequency branch */
if(pstate.h_freq_mode)
{
int freq_err = SPLL->PER_HPLL;
if(freq_err & 0x100) freq_err |= 0xffffff00; /* sign-extend */
freq_err += pll_cfg.hpll_f_setpoint;
pstate.h_freq_err = freq_err;
/* PI control */
if(pstate.h_dac_val > 0 && pstate.h_dac_val < 65530)
pstate.h_i += freq_err;
dv = ((pstate.h_i * pll_cfg.hpll_f_ki + freq_err * pll_cfg.hpll_f_kp) >> PI_FRACBITS) + pll_cfg.hpll_dac_bias;
if(dv >= 65530) dv = 65530;
if(dv < 0) dv = 0;
pstate.h_dac_val = dv;
SPLL->DAC_HPLL = dv; /* update DAC */
pstate.h_dac_val = dv;
/* lock detection */
if(freq_err >= -pll_cfg.hpll_ld_f_threshold && freq_err <= pll_cfg.hpll_ld_f_threshold)
pstate.h_lock_counter++;
else
pstate.h_lock_counter=0;
/* frequency has been stable for quite a while? switch to phase branch */
if(pstate.h_lock_counter == pll_cfg.hpll_ld_f_samples)
{
pstate.h_freq_mode = 0;
pstate.h_dac_bias = dv;
pstate.h_i = 0;
pstate.h_lock_counter = 0;
pstate.h_p_setpoint = -1;
SPLL->CSR = SPLL_CSR_TAG_EN_W(CHAN_REF);
}
/* HPLL: active phase branch */
} else if (tag_ref_ready) {
if(pstate.h_p_setpoint < 0) /* we don't have yet any phase samples? */
pstate.h_p_setpoint = tag_ref; // & 0x3fff;
else {
int phase_err;
// if(tag_ref > 16384) tag_ref -= 16384;
// tag_ref &x7fff;
phase_err = tag_ref - pstate.h_p_setpoint;
if(pstate.h_dac_val > 0 && pstate.h_dac_val < 65530)
pstate.h_i += phase_err;
pstate.h_p_setpoint += 16384;
pstate.h_p_setpoint &= ((1<<TAG_BITS)-1);
dv = ((pstate.h_i * pll_cfg.hpll_p_ki + phase_err * pll_cfg.hpll_p_kp) >> PI_FRACBITS) + pstate.h_dac_bias;
if(dv >= 65530) dv = 65530;
if(dv < 0) dv = 0;
pstate.h_dac_val = dv;
SPLL->DAC_HPLL = dv; /* Update DAC */
pstate.h_tag = tag_ref;
if(abs(phase_err) >= pll_cfg.hpll_delock_threshold && pstate.h_locked)
{
SPLL->CSR = SPLL_CSR_TAG_EN_W(CHAN_PERIOD); /* fall back to freq mode */
pstate.h_locked = 0;
pstate.h_freq_mode = 1;
}
if(abs(phase_err) <= pll_cfg.hpll_ld_p_threshold && !pstate.h_locked)
pstate.h_lock_counter++;
else
pstate.h_lock_counter = 0;
if(pstate.h_lock_counter == pll_cfg.hpll_ld_p_samples)
{
#if 1
SPLL->CSR |= SPLL_CSR_TAG_EN_W(CHAN_FB); /* enable feedback channel and start DMPLL */
pstate.h_locked = 1;
pstate.d_tag_ref_d0 = -1;
pstate.d_tag_fb_d0 = -1;
pstate.d_freq_mode = 1;
pstate.d_p_setpoint = 0;
pstate.d_lock_counter = 0;
pstate.d_i = 0;
pstate.d_locked = 0;
#endif
}
}
}
/* DMPLL */
if(pstate.h_locked && pstate.d_freq_mode)
{
int freq_err;
if(tag_ref_ready)
{
if(pstate.d_tag_ref_d0 > 0)
{
int tmp = tag_ref - pstate.d_tag_ref_d0;
if(tmp < 0) tmp += (1<<TAG_BITS)-1;
pstate.d_period_ref = tmp;
}
pstate.d_tag_ref_d0 = tag_ref;
}
if(tag_fb_ready)
{
if(pstate.d_tag_fb_d0 > 0)
{
int tmp = tag_fb - pstate.d_tag_fb_d0;
if(tmp < 0) tmp += (1<<TAG_BITS)-1;
pstate.d_period_fb = tmp;
}
pstate.d_tag_fb_d0 = tag_fb;
}
freq_err = - pstate.d_period_fb + pstate.d_period_ref;
pstate.d_freq_error = freq_err;
pstate.d_i += freq_err;
dv = ((pstate.d_i * pll_cfg.dpll_f_ki + freq_err * pll_cfg.dpll_f_kp) >> PI_FRACBITS) + pll_cfg.dpll_dac_bias;
SPLL->DAC_DMPLL = dv;
if(abs(freq_err) <= pll_cfg.dpll_ld_threshold)
pstate.d_lock_counter++;
else
pstate.d_lock_counter=0;
/* frequency has been stable for quite a while? switch to phase branch */
if(pstate.d_lock_counter == pll_cfg.dpll_ld_samples)
{
pstate.d_freq_mode = 0;
pstate.d_dac_bias = dv;
pstate.d_i = 0;
pstate.d_lock_counter = 0;
pstate.d_tag_ref_ready = 0;
pstate.d_tag_fb_ready = 0;
pstate.d_p_setpoint = 0;
}
}
/* DMPLL phase-lock */
if(pstate.h_locked && !pstate.d_freq_mode)
{
int phase_err = 0;
if(tag_ref_ready)
pstate.d_tag_ref_d0 = tag_ref;
tag_ref = pstate.d_tag_ref_d0 ;
tag_fb += pstate.d_p_setpoint; // was tag_fb
tag_fb &= (1<<TAG_BITS)-1;
//if(tag_ref > (1<<TAG_BITS)) tag_ref -= (1<<TAG_BITS);
//if(tag_ref < 0) tag_ref += (1<<TAG_BITS);
if(tag_fb_ready)
{
while (tag_ref > 16384 ) tag_ref-=16384;
while (tag_fb > 16384 ) tag_fb-=16384;
phase_err = tag_ref-tag_fb;
pstate.d_i += phase_err;
dv = ((pstate.d_i * pll_cfg.dpll_p_ki + phase_err * pll_cfg.dpll_p_kp) >> PI_FRACBITS) + pll_cfg.dpll_dac_bias;
SPLL->DAC_DMPLL = dv;
eee=phase_err;
}
if(pstate.d_p_setpoint < pstate.d_phase_shift)
pstate.d_p_setpoint++;
else if(pstate.d_p_setpoint > pstate.d_phase_shift)
pstate.d_p_setpoint--;
if(abs(phase_err) <= pll_cfg.dpll_ld_threshold && !pstate.d_locked)
pstate.d_lock_counter++;
else
pstate.d_lock_counter = 0;
if(pstate.d_lock_counter == pll_cfg.dpll_ld_samples)
pstate.d_locked = 1;
}
gpio_out(GPIO_PIN_LED_STATUS, 0);
clear_irq();
}
static int prev_lck = 0;
void softpll_enable()
{
SPLL->CSR = 0;
disable_irq();
SPLL->DAC_HPLL = pll_cfg.hpll_dac_bias;
SPLL->DAC_DMPLL = pll_cfg.dpll_dac_bias;
SPLL->DEGLITCH_THR = pll_cfg.dpll_deglitcher_threshold;
pstate.h_p_setpoint = -1;
pstate.h_i = 0;
pstate.h_freq_mode = 1;
pstate.h_lock_counter = 0;
pstate.h_locked = 0;
pstate.d_p_setpoint = 0;
pstate.d_phase_shift = 0;
pstate.h_dac_val = pll_cfg.hpll_dac_bias;
SPLL->CSR = SPLL_CSR_TAG_EN_W(CHAN_PERIOD);// | SPLL_CSR_TAG_EN_W(CHAN_REF);
SPLL->EIC_IER = 1;
enable_irq();
// softpll_test();
prev_lck = 0;
TRACE_DEV("[softpll]: enabled\n");
}
int softpll_check_lock()
{
TRACE_DEV("[softpll] Helper: lock %d freqmode %d, Main: lock %d freqmode %d\n",
pstate.h_locked, pstate.h_freq_mode,
pstate.d_locked,pstate.d_freq_mode);
int lck = pstate.h_locked && pstate.d_locked;
if(lck && !prev_lck)
TRACE_DEV("[softpll]: got lock\n");
else if (!lck && prev_lck)
TRACE_DEV("[softpll]: lost lock\n");
prev_lck = lck;
return lck;
}
int softpll_busy()
{
return pstate.d_p_setpoint != pstate.d_phase_shift;
}
void softpll_set_phase(int ps)
{
pstate.d_phase_shift = -(int32_t) ((int64_t)ps * 16384LL / 8000LL);
TRACE_DEV("ADJdelta: phase %d [ps], %d units\n", ps, pstate.d_phase_shift);
}
void softpll_disable()
{
SPLL->CSR = 0;
disable_irq();
}
int softpll_get_setpoint()
{
return pstate.d_p_setpoint;
}
This diff is collapsed.
#include "syscon.h"
struct s_i2c_if i2c_if[2] = { {SYSC_GPSR_FMC_SCL, SYSC_GPSR_FMC_SDA},
{SYSC_GPSR_SFP_SCL, SYSC_GPSR_SFP_SDA} };
/****************************
* TIMER
***************************/
void timer_init(uint32_t enable)
{
mprintf("MEMSIZE %x\n", syscon->HWFR & 0xf);
if(enable)
syscon->TCR |= SYSC_TCR_ENABLE;
else
syscon->TCR &= ~SYSC_TCR_ENABLE;
}
uint32_t timer_get_tics()
{
return syscon->TVR;
}
void timer_delay(uint32_t how_long)
{
uint32_t t_start;
// timer_init(1);
do
{
t_start = timer_get_tics();
} while(t_start > UINT32_MAX - how_long); //in case of overflow
while(t_start + how_long > timer_get_tics());
}
#ifndef __BOARD_H
#define __BOARD_H
#define BASE_UART 0x60800
#define BASE_GPIO 0x60400
#define BASE_TIMER 0x61000
#define BASE_PPSGEN 0x50000
#define BASE_EP 0x20000
#define BASE_MINIC 0x10000
#define BASE_SOFTPLL 0x40000
#define BASE_MINIC 0x20000
#define BASE_EP 0x20100
#define BASE_SOFTPLL 0x20200
#define BASE_PPS_GEN 0x20300
#define BASE_SYSCON 0x20400
#define BASE_UART 0x20500
#define BASE_ONEWIRE 0x20600
#define FMC_EEPROM_ADR 0x50
#define CPU_CLOCK 62500000ULL
#define UART_BAUDRATE 115200ULL /* not a real UART */
#define GPIO_PIN_LED_LINK 0
#define GPIO_PIN_LED_STATUS 1
#define GPIO_PIN_SCL_OUT 2
#define GPIO_PIN_SDA_OUT 3
#define GPIO_PIN_SDA_IN 4
#define GPIO_PIN_BTN1 5
#define GPIO_PIN_BTN2 6
static inline int delay(int x)
static inline void delay(int x)
{
while(x--) asm volatile("nop");
}
......
#ifndef __EEPROM_H
#define __EEPROM_H
#define SFP_SECTION_PATTERN 0xdeadbeef
#define SFPINFO_MAX 4
__attribute__ ((packed)) struct s_sfpinfo
{
char pn[16];
int32_t alpha;
int32_t deltaTx;
int32_t deltaRx;
};
int eeprom_read(uint8_t i2cif, uint8_t i2c_addr, uint32_t offset, uint8_t *buf, size_t size);
int eeprom_write(uint8_t i2cif, uint8_t i2c_addr, uint32_t offset, uint8_t *buf, size_t size);
int32_t eeprom_sfp_section(uint8_t i2cif, uint8_t i2c_addr, size_t size, uint16_t *section_sz);
int8_t eeprom_get_sfpinfo(uint8_t i2cif, uint8_t i2c_addr, uint32_t offset, struct s_sfpinfo *sfpinfo, uint16_t section_sz);
int8_t access_eeprom(char *sfp_pn, int32_t *alpha, int32_t *deltaTx, int32_t *deltaRx);
#endif
......@@ -4,12 +4,38 @@
#define DMTD_AVG_SAMPLES 256
#define DMTD_MAX_PHASE 16384
#include <stdint.h>
typedef enum {
AND=0,
NAND=4,
OR=1,
NOR=5,
XOR=2,
XNOR=6,
MOV=3,
NOT=7
} pfilter_op_t;
void ep_init(uint8_t mac_addr[]);
void get_mac_addr(uint8_t dev_addr[]);
int ep_enable(int enabled, int autoneg);
int ep_link_up();
int ep_link_up(uint16_t *lpa);
int ep_get_deltas(uint32_t *delta_tx, uint32_t *delta_rx);
int ep_get_psval(int32_t *psval);
int ep_cal_pattern_enable();
int ep_cal_pattern_disable();
void pfilter_new();
void pfilter_cmp(int offset, int value, int mask, pfilter_op_t op, int rd);
void pfilter_btst(int offset, int bit_index, pfilter_op_t op, int rd);
void pfilter_nop();
void pfilter_logic2(int rd, int ra, pfilter_op_t op, int rb);
static void pfilter_logic3(int rd, int ra, pfilter_op_t op, int rb, pfilter_op_t op2, int rc);
void pfilter_load();
void pfilter_init_default();
uint16_t pcs_read(int location);
void pcs_write(int location, int value);
#endif
#ifndef __GPIO_H
#define __GPIO_H
#include <inttypes.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 pin)
{
return __gpio->PSR & (1<<pin) ? 1: 0;
}
#endif
This diff is collapsed.
/*
Register definitions for slave core: Mini NIC for WhiteRabbit
* File : ../../../software/include/hw/minic_regs.h
* File : minic_regs.h
* Author : auto-generated by wbgen2 from mini_nic.wb
* Created : Fri Aug 13 02:17:20 2010
* Created : Wed Nov 2 02:18:19 2011
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE mini_nic.wb
......@@ -51,12 +51,43 @@
/* definitions for field: RX DMA enable in reg: miNIC Control Register */
#define MINIC_MCR_RX_EN WBGEN2_GEN_MASK(10, 1)
/* definitions for field: RX Accepted Packet Classes in reg: miNIC Control Register */
#define MINIC_MCR_RX_CLASS_MASK WBGEN2_GEN_MASK(16, 8)
#define MINIC_MCR_RX_CLASS_SHIFT 16
#define MINIC_MCR_RX_CLASS_W(value) WBGEN2_GEN_WRITE(value, 16, 8)
#define MINIC_MCR_RX_CLASS_R(reg) WBGEN2_GEN_READ(reg, 16, 8)
/* definitions for register: TX DMA Address */
/* definitions for register: RX DMA Address */
/* definitions for register: RX buffer size register */
/* definitions for register: TX timestamp register 0 */
/* definitions for field: Timestamp valid in reg: TX timestamp register 0 */
#define MINIC_TSR0_VALID WBGEN2_GEN_MASK(0, 1)
/* definitions for field: Port ID in reg: TX timestamp register 0 */
#define MINIC_TSR0_PID_MASK WBGEN2_GEN_MASK(1, 5)
#define MINIC_TSR0_PID_SHIFT 1
#define MINIC_TSR0_PID_W(value) WBGEN2_GEN_WRITE(value, 1, 5)
#define MINIC_TSR0_PID_R(reg) WBGEN2_GEN_READ(reg, 1, 5)
/* definitions for field: Frame ID in reg: TX timestamp register 0 */
#define MINIC_TSR0_FID_MASK WBGEN2_GEN_MASK(6, 16)
#define MINIC_TSR0_FID_SHIFT 6
#define MINIC_TSR0_FID_W(value) WBGEN2_GEN_WRITE(value, 6, 16)
#define MINIC_TSR0_FID_R(reg) WBGEN2_GEN_READ(reg, 6, 16)
/* definitions for register: TX timestamp register 1 */
/* definitions for field: Timestamp value in reg: TX timestamp register 1 */
#define MINIC_TSR1_TSVAL_MASK WBGEN2_GEN_MASK(0, 32)
#define MINIC_TSR1_TSVAL_SHIFT 0
#define MINIC_TSR1_TSVAL_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define MINIC_TSR1_TSVAL_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: Debug register */
/* definitions for field: interrupt counter in reg: Debug register */
......@@ -68,6 +99,20 @@
/* definitions for field: status of wb_irq_o line in reg: Debug register */
#define MINIC_DBGR_WB_IRQ_VAL WBGEN2_GEN_MASK(24, 1)
/* definitions for register: Memory protection reg */
/* definitions for field: address range lo in reg: Memory protection reg */
#define MINIC_MPROT_LO_MASK WBGEN2_GEN_MASK(0, 16)
#define MINIC_MPROT_LO_SHIFT 0
#define MINIC_MPROT_LO_W(value) WBGEN2_GEN_WRITE(value, 0, 16)
#define MINIC_MPROT_LO_R(reg) WBGEN2_GEN_READ(reg, 0, 16)
/* definitions for field: address range hi in reg: Memory protection reg */
#define MINIC_MPROT_HI_MASK WBGEN2_GEN_MASK(16, 16)
#define MINIC_MPROT_HI_SHIFT 16
#define MINIC_MPROT_HI_W(value) WBGEN2_GEN_WRITE(value, 16, 16)
#define MINIC_MPROT_HI_R(reg) WBGEN2_GEN_READ(reg, 16, 16)
/* definitions for register: Interrupt disable register */
/* definitions for field: TX DMA interrupt in reg: Interrupt disable register */
......@@ -111,33 +156,6 @@
/* definitions for field: TX timestamp available in reg: Interrupt status register */
#define MINIC_EIC_ISR_TXTS WBGEN2_GEN_MASK(2, 1)
/* definitions for register: FIFO 'TX timestamp FIFO' data output register 0 */
/* definitions for field: Timestamp value in reg: FIFO 'TX timestamp FIFO' data output register 0 */
#define MINIC_TSFIFO_R0_TSVAL_MASK WBGEN2_GEN_MASK(0, 32)
#define MINIC_TSFIFO_R0_TSVAL_SHIFT 0
#define MINIC_TSFIFO_R0_TSVAL_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define MINIC_TSFIFO_R0_TSVAL_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: FIFO 'TX timestamp FIFO' data output register 1 */
/* definitions for field: Port ID in reg: FIFO 'TX timestamp FIFO' data output register 1 */
#define MINIC_TSFIFO_R1_PID_MASK WBGEN2_GEN_MASK(0, 5)
#define MINIC_TSFIFO_R1_PID_SHIFT 0
#define MINIC_TSFIFO_R1_PID_W(value) WBGEN2_GEN_WRITE(value, 0, 5)
#define MINIC_TSFIFO_R1_PID_R(reg) WBGEN2_GEN_READ(reg, 0, 5)
/* definitions for field: Frame ID in reg: FIFO 'TX timestamp FIFO' data output register 1 */
#define MINIC_TSFIFO_R1_FID_MASK WBGEN2_GEN_MASK(5, 16)
#define MINIC_TSFIFO_R1_FID_SHIFT 5
#define MINIC_TSFIFO_R1_FID_W(value) WBGEN2_GEN_WRITE(value, 5, 16)
#define MINIC_TSFIFO_R1_FID_R(reg) WBGEN2_GEN_READ(reg, 5, 16)
/* definitions for register: FIFO 'TX timestamp FIFO' control/status register */
/* definitions for field: FIFO empty flag in reg: FIFO 'TX timestamp FIFO' control/status register */
#define MINIC_TSFIFO_CSR_EMPTY WBGEN2_GEN_MASK(17, 1)
/* [0x0]: REG miNIC Control Register */
#define MINIC_REG_MCR 0x00000000
/* [0x4]: REG TX DMA Address */
......@@ -146,8 +164,14 @@
#define MINIC_REG_RX_ADDR 0x00000008
/* [0xc]: REG RX buffer size register */
#define MINIC_REG_RX_AVAIL 0x0000000c
/* [0x10]: REG Debug register */
#define MINIC_REG_DBGR 0x00000010
/* [0x10]: REG TX timestamp register 0 */
#define MINIC_REG_TSR0 0x00000010
/* [0x14]: REG TX timestamp register 1 */
#define MINIC_REG_TSR1 0x00000014
/* [0x18]: REG Debug register */
#define MINIC_REG_DBGR 0x00000018
/* [0x1c]: REG Memory protection reg */
#define MINIC_REG_MPROT 0x0000001c
/* [0x20]: REG Interrupt disable register */
#define MINIC_REG_EIC_IDR 0x00000020
/* [0x24]: REG Interrupt enable register */
......@@ -156,10 +180,4 @@
#define MINIC_REG_EIC_IMR 0x00000028
/* [0x2c]: REG Interrupt status register */
#define MINIC_REG_EIC_ISR 0x0000002c
/* [0x30]: REG FIFO 'TX timestamp FIFO' data output register 0 */
#define MINIC_REG_TSFIFO_R0 0x00000030
/* [0x34]: REG FIFO 'TX timestamp FIFO' data output register 1 */
#define MINIC_REG_TSFIFO_R1 0x00000034
/* [0x38]: REG FIFO 'TX timestamp FIFO' control/status register */
#define MINIC_REG_TSFIFO_CSR 0x00000038
#endif
/*
Register definitions for slave core: WR Switch PPS generator and RTC
* File : ../../../software/include/hw/pps_gen_regs.h
* File : pps_gen_regs.h
* Author : auto-generated by wbgen2 from wrsw_pps_gen.wb
* Created : Sat Sep 11 22:22:55 2010
* Created : Thu Oct 27 21:29:19 2011
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE wrsw_pps_gen.wb
......@@ -60,18 +60,35 @@
/* definitions for register: UTC Adjustment register (least-significant part) */
/* definitions for register: UTC Adjustment register (most-significant part) */
/* [0x0]: REG Control Register */
#define PPSG_REG_CR 0x00000000
/* [0x4]: REG Nanosecond counter register */
#define PPSG_REG_CNTR_NSEC 0x00000004
/* [0x8]: REG UTC Counter register (least-significant part) */
#define PPSG_REG_CNTR_UTCLO 0x00000008
/* [0xc]: REG UTC Counter register (most-significant part) */
#define PPSG_REG_CNTR_UTCHI 0x0000000c
/* [0x10]: REG Nanosecond adjustment register */
#define PPSG_REG_ADJ_NSEC 0x00000010
/* [0x14]: REG UTC Adjustment register (least-significant part) */
#define PPSG_REG_ADJ_UTCLO 0x00000014
/* [0x18]: REG UTC Adjustment register (most-significant part) */
#define PPSG_REG_ADJ_UTCHI 0x00000018
/* definitions for register: External sync control register */
/* definitions for field: Sync to external PPS input in reg: External sync control register */
#define PPSG_ESCR_SYNC WBGEN2_GEN_MASK(0, 1)
/* definitions for field: PPS output valid in reg: External sync control register */
#define PPSG_ESCR_PPS_VALID WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Timecode output(UTC+cycles) valid in reg: External sync control register */
#define PPSG_ESCR_TM_VALID WBGEN2_GEN_MASK(2, 1)
PACKED struct PPSG_WB {
/* [0x0]: REG Control Register */
uint32_t CR;
/* [0x4]: REG Nanosecond counter register */
uint32_t CNTR_NSEC;
/* [0x8]: REG UTC Counter register (least-significant part) */
uint32_t CNTR_UTCLO;
/* [0xc]: REG UTC Counter register (most-significant part) */
uint32_t CNTR_UTCHI;
/* [0x10]: REG Nanosecond adjustment register */
uint32_t ADJ_NSEC;
/* [0x14]: REG UTC Adjustment register (least-significant part) */
uint32_t ADJ_UTCLO;
/* [0x18]: REG UTC Adjustment register (most-significant part) */
uint32_t ADJ_UTCHI;
/* [0x1c]: REG External sync control register */
uint32_t ESCR;
};
#endif
This diff is collapsed.
/*
Register definitions for slave core: WR Core System Controller
* File : wrc_syscon_regs.h
* Author : auto-generated by wbgen2 from wrc_syscon_wb.wb
* Created : Fri Feb 17 10:20:14 2012
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE wrc_syscon_wb.wb
DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
*/
#ifndef __WBGEN2_REGDEFS_WRC_SYSCON_WB_WB
#define __WBGEN2_REGDEFS_WRC_SYSCON_WB_WB
#include <inttypes.h>
#if defined( __GNUC__)
#define PACKED __attribute__ ((packed))
#else
#error "Unsupported compiler?"
#endif
#ifndef __WBGEN2_MACROS_DEFINED__
#define __WBGEN2_MACROS_DEFINED__
#define WBGEN2_GEN_MASK(offset, size) (((1<<(size))-1) << (offset))
#define WBGEN2_GEN_WRITE(value, offset, size) (((value) & ((1<<(size))-1)) << (offset))
#define WBGEN2_GEN_READ(reg, offset, size) (((reg) >> (offset)) & ((1<<(size))-1))
#define WBGEN2_SIGN_EXTEND(value, bits) (((value) & (1<<bits) ? ~((1<<(bits))-1): 0 ) | (value))
#endif
/* definitions for register: Syscon reset register */
/* definitions for field: Reset trigger in reg: Syscon reset register */
#define SYSC_RSTR_TRIG_MASK WBGEN2_GEN_MASK(0, 28)
#define SYSC_RSTR_TRIG_SHIFT 0
#define SYSC_RSTR_TRIG_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define SYSC_RSTR_TRIG_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for field: Reset line state value in reg: Syscon reset register */
#define SYSC_RSTR_RST WBGEN2_GEN_MASK(28, 1)
/* definitions for register: GPIO Set/Readback Register */
/* definitions for field: Status LED in reg: GPIO Set/Readback Register */
#define SYSC_GPSR_LED_STAT WBGEN2_GEN_MASK(0, 1)
/* definitions for field: Link LED in reg: GPIO Set/Readback Register */
#define SYSC_GPSR_LED_LINK WBGEN2_GEN_MASK(1, 1)
/* definitions for field: FMC I2C bitbanged SCL in reg: GPIO Set/Readback Register */
#define SYSC_GPSR_FMC_SCL WBGEN2_GEN_MASK(2, 1)
/* definitions for field: FMC I2C bitbanged SDA in reg: GPIO Set/Readback Register */
#define SYSC_GPSR_FMC_SDA WBGEN2_GEN_MASK(3, 1)
/* definitions for field: Network AP reset in reg: GPIO Set/Readback Register */
#define SYSC_GPSR_NET_RST WBGEN2_GEN_MASK(4, 1)
/* definitions for field: SPEC Pushbutton 1 state in reg: GPIO Set/Readback Register */
#define SYSC_GPSR_BTN1 WBGEN2_GEN_MASK(5, 1)
/* definitions for field: SPEC Pushbutton 2 state in reg: GPIO Set/Readback Register */
#define SYSC_GPSR_BTN2 WBGEN2_GEN_MASK(6, 1)
/* definitions for field: SFP detect (MOD_DEF0 signal) in reg: GPIO Set/Readback Register */
#define SYSC_GPSR_SFP_DET WBGEN2_GEN_MASK(7, 1)
/* definitions for field: SFP I2C bitbanged SCL in reg: GPIO Set/Readback Register */
#define SYSC_GPSR_SFP_SCL WBGEN2_GEN_MASK(8, 1)
/* definitions for field: SFP I2C bitbanged SDA in reg: GPIO Set/Readback Register */
#define SYSC_GPSR_SFP_SDA WBGEN2_GEN_MASK(9, 1)
/* definitions for register: GPIO Clear Register */
/* definitions for field: Status LED in reg: GPIO Clear Register */
#define SYSC_GPCR_LED_STAT WBGEN2_GEN_MASK(0, 1)
/* definitions for field: Link LED in reg: GPIO Clear Register */
#define SYSC_GPCR_LED_LINK WBGEN2_GEN_MASK(1, 1)
/* definitions for field: FMC I2C bitbanged SCL in reg: GPIO Clear Register */
#define SYSC_GPCR_FMC_SCL WBGEN2_GEN_MASK(2, 1)
/* definitions for field: FMC I2C bitbanged SDA in reg: GPIO Clear Register */
#define SYSC_GPCR_FMC_SDA WBGEN2_GEN_MASK(3, 1)
/* definitions for field: SFP I2C bitbanged SCL in reg: GPIO Clear Register */
#define SYSC_GPCR_SFP_SCL WBGEN2_GEN_MASK(8, 1)
/* definitions for field: FMC I2C bitbanged SDA in reg: GPIO Clear Register */
#define SYSC_GPCR_SFP_SDA WBGEN2_GEN_MASK(9, 1)
/* definitions for register: Hardware Feature Register */
/* definitions for field: Memory size in reg: Hardware Feature Register */
#define SYSC_HWFR_MEMSIZE_MASK WBGEN2_GEN_MASK(0, 4)
#define SYSC_HWFR_MEMSIZE_SHIFT 0
#define SYSC_HWFR_MEMSIZE_W(value) WBGEN2_GEN_WRITE(value, 0, 4)
#define SYSC_HWFR_MEMSIZE_R(reg) WBGEN2_GEN_READ(reg, 0, 4)
/* definitions for register: Timer Control Register */
/* definitions for field: Timer Divider in reg: Timer Control Register */
#define SYSC_TCR_TDIV_MASK WBGEN2_GEN_MASK(0, 12)
#define SYSC_TCR_TDIV_SHIFT 0
#define SYSC_TCR_TDIV_W(value) WBGEN2_GEN_WRITE(value, 0, 12)
#define SYSC_TCR_TDIV_R(reg) WBGEN2_GEN_READ(reg, 0, 12)
/* definitions for field: Timer Enable in reg: Timer Control Register */
#define SYSC_TCR_ENABLE WBGEN2_GEN_MASK(31, 1)
/* definitions for register: Timer Counter Value Register */
/* [0x0]: REG Syscon reset register */
#define SYSC_REG_RSTR 0x00000000
/* [0x4]: REG GPIO Set/Readback Register */
#define SYSC_REG_GPSR 0x00000004
/* [0x8]: REG GPIO Clear Register */
#define SYSC_REG_GPCR 0x00000008
/* [0xc]: REG Hardware Feature Register */
#define SYSC_REG_HWFR 0x0000000c
/* [0x10]: REG Timer Control Register */
#define SYSC_REG_TCR 0x00000010
/* [0x14]: REG Timer Counter Value Register */
#define SYSC_REG_TVR 0x00000014
#endif
#ifndef __I2C_H
#define __I2C_H
void mi2c_init(uint8_t i2cif);
void mi2c_start(uint8_t i2cif);
void mi2c_repeat_start(uint8_t i2cif);
void mi2c_stop(uint8_t i2cif);
void mi2c_get_byte(uint8_t i2cif, unsigned char *data, uint8_t last);
unsigned char mi2c_put_byte(uint8_t i2cif, unsigned char data);
void mi2c_delay();
//void mi2c_scan(uint8_t i2cif);
#endif
......@@ -11,4 +11,6 @@ typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
#define UINT32_MAX 4294967295U
#endif
......@@ -7,4 +7,7 @@ static inline void clear_irq()
asm volatile ("wcsr ip, %0"::"r"(val));
}
void disable_irq();
void enable_irq();
#endif
......@@ -8,6 +8,7 @@
void minic_init();
void minic_disable();
int minic_poll_rx();
void minic_get_stats(int *tx_frames, int *rx_frames);
int minic_rx_frame(uint8_t *hdr, uint8_t *payload, uint32_t buf_size, struct hw_timestamp *hwts);
int minic_tx_frame(uint8_t *hdr, uint8_t *payload, uint32_t size, struct hw_timestamp *hwts);
......
#ifndef __ONEWIRE_H
#define __ONEWIRE_H
void ow_init();
uint32_t ow_reset(uint32_t port);
uint8_t ow_read_byte(uint32_t port);
int8_t ow_write_byte(uint32_t port, uint32_t byte);
int ow_write_block(int port, uint8_t *block, int len);
int ow_read_block(int port, uint8_t *block, int len);
int8_t ds18x_read_serial(uint8_t *id);
int8_t ds18x_read_temp(uint8_t *id, int *temp_r);
int ds18x_init();
#endif
#ifndef __SOFTPLL_H
#define __SOFTPLL_H
void softpll_enable();
int softpll_check_lock();
void softpll_disable();
int softpll_busy();
void softpll_set_phase(int ps);
int softpll_get_setpoint();
#endif
#ifndef __SOFTPLL_NG_H
#define __SOFTPLL_NG_H
#include <stdio.h>
#include <stdlib.h>
/* Modes */
#define SPLL_MODE_GRAND_MASTER 1
#define SPLL_MODE_FREE_RUNNING_MASTER 2
#define SPLL_MODE_SLAVE 3
#define SPLL_MODE_DISABLED 4
#define SPLL_ALL_CHANNELS 0xffff
#define SPLL_AUX_ENABLED (1<<0)
#define SPLL_AUX_LOCKED (1<<1)
void spll_init(int mode, int slave_ref_channel, int align_pps);
void spll_shutdown();
void spll_start_channel(int channel);
void spll_stop_channel(int channel);
int spll_check_lock(int channel);
void spll_set_phase_shift(int channel, int32_t value_picoseconds);
void spll_get_phase_shift(int channel, int32_t *current, int32_t *target);
int spll_read_ptracker(int channel, int32_t *phase_ps, int *enabled);
void spll_get_num_channels(int *n_ref, int *n_out);
int spll_shifter_busy(int channel);
int spll_get_delock_count();
int spll_update_aux_clocks();
int spll_get_aux_status(int channel);
#endif
/*
White Rabbit Softcore PLL (SoftPLL) - common definitions
Copyright (c) 2010 - 2012 CERN / BE-CO-HT (Tomasz Włostowski)
Licensed under LGPL 2.1.
spll_common.h - common data structures and functions
*/
/* Number of reference/output channels. Currently we support only one SoftPLL instantiation per project,
so these can remain static. */
static int n_chan_ref, n_chan_out;
/* PI regulator state */
typedef struct {
int ki, kp; /* integral and proportional gains (1<<PI_FRACBITS == 1.0f) */
int integrator; /* current integrator value */
int bias; /* DC offset always added to the output */
int anti_windup; /* when non-zero, anti-windup is enabled */
int y_min; /* min/max output range, used by clapming and antiwindup algorithms */
int y_max;
int x, y; /* Current input (x) and output value (y) */
} spll_pi_t;
/* lock detector state */
typedef struct {
int lock_cnt; /* Lock sample counter */
int lock_samples; /* Number of samples below the (threshold) to assume that we are locked */
int delock_samples; /* Accumulated number of samples that causes the PLL go get out of lock.
delock_samples < lock_samples. */
int threshold; /* Error threshold */
int locked; /* Non-zero: we are locked */
} spll_lock_det_t;
/* simple, 1st-order lowpass filter */
typedef struct {
int alpha;
int y_d;
} spll_lowpass_t;
/* Processes a single sample (x) with PI control algorithm (pi). Returns the value (y) to
drive the actuator. */
static inline int pi_update(spll_pi_t *pi, int x)
{
int i_new, y;
pi->x = x;
i_new = pi->integrator + x;
y = ((i_new * pi->ki + x * pi->kp) >> PI_FRACBITS) + pi->bias;
/* clamping (output has to be in <y_min, y_max>) and anti-windup:
stop the integrator if the output is already out of range and the output
is going further away from y_min/y_max. */
if(y < pi->y_min)
{
y = pi->y_min;
if((pi->anti_windup && (i_new > pi->integrator)) || !pi->anti_windup)
pi->integrator = i_new;
} else if (y > pi->y_max) {
y = pi->y_max;
if((pi->anti_windup && (i_new < pi->integrator)) || !pi->anti_windup)
pi->integrator = i_new;
} else /* No antiwindup/clamping? */
pi->integrator = i_new;
pi->y = y;
return y;
}
/* initializes the PI controller state. Currently almost a stub. */
static inline void pi_init(spll_pi_t *pi)
{
pi->integrator = 0;
}
/* Lock detector state machine. Takes an error sample (y) and checks if it's withing an acceptable range
(i.e. <-ld.threshold, ld.threshold>. If it has been inside the range for (ld.lock_samples) cyckes, the
FSM assumes the PLL is locked.
Return value:
0: PLL not locked
1: PLL locked
-1: PLL just got out of lock
*/
static inline int ld_update(spll_lock_det_t *ld, int y)
{
if (abs(y) <= ld->threshold)
{
if(ld->lock_cnt < ld->lock_samples)
ld->lock_cnt++;
if(ld->lock_cnt == ld->lock_samples)
{
ld->locked = 1;
return 1;
}
} else {
if(ld->lock_cnt > ld->delock_samples)
ld->lock_cnt--;
if(ld->lock_cnt == ld->delock_samples)
{
ld->lock_cnt= 0;
ld->locked = 0;
return -1;
}
}
return ld->locked;
}
static void ld_init(spll_lock_det_t *ld)
{
ld->locked = 0;
ld->lock_cnt = 0;
}
static void lowpass_init(spll_lowpass_t *lp, int alpha)
{
lp->y_d = 0x80000000;
lp->alpha = alpha;
}
static int lowpass_update(spll_lowpass_t *lp, int x)
{
if(lp->y_d == 0x80000000)
{
lp->y_d = x;
return x;
} else {
int scaled = (lp->alpha * (x - lp->y_d)) >> 15;
lp->y_d = lp->y_d + (scaled >> 1) + (scaled & 1);
return lp->y_d;
}
}
/* Enables/disables DDMTD tag generation on a given (channel).
Channels (0 ... n_chan_ref - 1) are the reference channels (e.g. transceivers' RX clocks
or a local reference)
Channels (n_chan_ref ... n_chan_out + n_chan_ref-1) are the output channels (local voltage
controlled oscillators). One output (usually the first one) is always used to drive the
oscillator which produces the reference clock for the transceiver. Other outputs can be
used to discipline external oscillators (e.g. on FMCs).
*/
static void spll_enable_tagger(int channel, int enable)
{
if(channel >= n_chan_ref) /* Output channel? */
{
if(enable)
SPLL->OCER |= 1<< (channel - n_chan_ref);
else
SPLL->OCER &= ~ (1<< (channel - n_chan_ref));
} else { /* Reference channel */
if(enable)
SPLL->RCER |= 1<<channel;
else
SPLL->RCER &= ~ (1<<channel);
}
// TRACE("%s: ch %d, OCER 0x%x, RCER 0x%x\n", __FUNCTION__, channel, SPLL->OCER, SPLL->RCER);
}
/*
White Rabbit Softcore PLL (SoftPLL) - common definitions
Copyright (c) 2010 - 2012 CERN / BE-CO-HT (Tomasz Włostowski)
Licensed under LGPL 2.1.
spll_debug.h - debugging/diagnostic interface
The so-called debug inteface is a large, interrupt-driven FIFO which passes
various realtime parameters (e.g. error value, tags, DAC drive) to an external
application where they are further analyzed. It's very useful for optimizing PI coefficients
and/or lock thresholds.
The data is organized as a stream of samples, where each sample can store a number of parameters.
For example, a stream samples with Y and ERR parameters can be used to evaluate the impact of
integral/proportional gains on the response of the system.
*/
#define DBG_Y 0
#define DBG_ERR 1
#define DBG_TAG 2
#define DBG_REF 5
#define DBG_PERIOD 3
#define DBG_EVENT 4
#define DBG_SAMPLE_ID 6
#define DBG_HELPER 0x20 /* Sample source: Helper PLL */
#define DBG_EXT 0x40 /* Sample source: External Reference PLL */
#define DBG_MAIN 0x0 /* ... : Main PLL */
#define DBG_EVT_START 1 /* PLL has just started */
#define DBG_EVT_LOCKED 2 /* PLL has just become locked */
/* Writes a parameter to the debug FIFO.
value: value of the parameter.
what: type of the parameter and its' source. For example,
- DBG_ERR | DBG_HELPER means that (value) contains the phase error of the helper PLL.
- DBG_EVENT indicates an asynchronous event. (value) must contain the event type (DBG_EVT_xxx)
last: when non-zero, indicates the last parameter in a sample.
*/
static inline void spll_debug(int what, int value, int last)
{
SPLL->DFR_SPLL = (last ? 0x80000000 : 0) | (value & 0xffffff) | (what << 24);
}
/*
White Rabbit Softcore PLL (SoftPLL) - common definitions
WARNING: These parameters must be in sync with the generics of the HDL instantiation of wr_softpll_ng.
*/
#include <stdio.h>
/* Reference clock frequency, in [Hz] */
#define CLOCK_FREQ 125000000
/* Reference clock period, in picoseconds */
#define CLOCK_PERIOD_PICOSECONDS 8000
/* 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
/* Number of bits in phase tags generated by the DMTDs. Used to sign-extend the tags.
Corresponding VHDL generic: g_tag_bits. */
#define TAG_BITS 22
/* Helper PLL N divider (2**(-N) is the frequency offset). Must be big enough
to offer reasonable PLL bandwidth, and small enough so the offset frequency fits
within the tuning range of the helper oscillator. */
#define HPLL_N 14
/* Fractional bits in PI controller coefficients */
#define PI_FRACBITS 12
/* Max. allowed number of reference channels. Can be used to tweak memory usage. */
#define MAX_CHAN_REF 1
/* Max. allowed number of auxillary channels */
#define MAX_CHAN_AUX 1
/* Max. allowed number of phase trackers */
#define MAX_PTRACKERS 1
/* Number of bits of the DAC(s) driving the oscillator(s). Must be the same for
all the outputs. */
#define DAC_BITS 16
/* 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
#include <timer.h>
/* Number of bits of the BB phase detector error counter. Bit [BB_ERROR_BITS] is the wrap-around bit */
#define BB_ERROR_BITS 16
/* Alignment FSM states */
/* 1st alignment stage, done before starting the ext channel PLL: alignment of the rising edge
of the external clock (10 MHz), with the rising edge of the local reference (62.5/125 MHz)
and the PPS signal. Because of non-integer ratio (6.25 or 12.5), the PLL must know which edges
shall be kept at phase==0. We align to the edge of the 10 MHz clock which comes right after the edge
of the PPS pulse (see drawing below):
PLL reference (62.5 MHz) ____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|
External clock (10 MHz) ^^^^^^^^^|________________________|^^^^^^^^^^^^^^^^^^^^^^^^^|________________________|^^^^^^^^^^^^^^^^^^^^^^^^^|___
External PPS ___________|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*/
#define REALIGN_STAGE1 1
#define REALIGN_STAGE1_WAIT 2
/* 2nd alignment stage, done after the ext channel PLL has locked. We make sure that the switch's internal PPS signal
is produced exactly on the edge of PLL reference in-phase with 10 MHz clock edge, which has come right after the PPS input
PLL reference (62.5 MHz) ____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|
External clock (10 MHz) ^^^^^^^^^|________________________|^^^^^^^^^^^^^^^^^^^^^^^^^|________________________|^^^^^^^^^^^^^^^^^^^^^^^^^|___
External PPS ___________|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Internal PPS __________________________________|^^^^^^^^^|______________________________________________________________________
^ aligned clock edges and PPS
*/
#define REALIGN_STAGE2 3
#define REALIGN_STAGE2_WAIT 4
/* Error state - PPS signal missing or of bad frequency */
#define REALIGN_PPS_INVALID 5
/* Realignment is disabled (i.e. the switch inputs only the reference frequency, but not time) */
#define REALIGN_DISABLED 6
/* Realignment done */
#define REALIGN_DONE 7
struct spll_external_state {
int ref_src;
int sample_n;
int ph_err_offset, ph_err_cur, ph_err_d0, ph_raw_d0;
int realign_clocks;
int realign_state;
int realign_timer;
spll_pi_t pi;
spll_lowpass_t lp_short, lp_long;
spll_lock_det_t ld;
};
static void external_init( struct spll_external_state *s, int ext_ref, int realign_clocks)
{
s->pi.y_min = 5;
s->pi.y_max = (1 << DAC_BITS) - 5;
s->pi.kp = (int)(300);
s->pi.ki = (int)(1);
s->pi.anti_windup = 1;
s->pi.bias = 32768;
/* Phase branch lock detection */
s->ld.threshold = 250;
s->ld.lock_samples = 10000;
s->ld.delock_samples = 9990;
s->ref_src = ext_ref;
s->ph_err_cur = 0;
s->ph_err_d0 = 0;
s->ph_raw_d0 = 0;
s->realign_clocks = realign_clocks;
s->realign_state = (realign_clocks ? REALIGN_STAGE1 : REALIGN_DISABLED);
pi_init(&s->pi);
ld_init(&s->ld);
lowpass_init(&s->lp_short, 4000);
lowpass_init(&s->lp_long, 300);
}
static inline void realign_fsm( struct spll_external_state *s)
{
uint32_t eccr;
switch(s->realign_state)
{
case REALIGN_STAGE1:
SPLL->ECCR |= SPLL_ECCR_ALIGN_EN;
s->realign_state = REALIGN_STAGE1_WAIT;
s->realign_timer = timer_get_tics();
break;
case REALIGN_STAGE1_WAIT:
if(SPLL->ECCR & SPLL_ECCR_ALIGN_DONE)
s->realign_state = REALIGN_STAGE2;
else if (timer_get_tics() - s->realign_timer > 2*TICS_PER_SECOND)
{
SPLL->ECCR &= ~SPLL_ECCR_ALIGN_EN;
s->realign_state = REALIGN_PPS_INVALID;
}
break;
case REALIGN_STAGE2:
if(s->ld.locked)
{
PPSG->CR = PPSG_CR_CNT_RST | PPSG_CR_CNT_EN;
PPSG->ADJ_UTCLO = 0;
PPSG->ADJ_UTCHI = 0;
PPSG->ADJ_NSEC = 0;
PPSG->ESCR = PPSG_ESCR_SYNC;
s->realign_state = REALIGN_STAGE2_WAIT;
s->realign_timer = timer_get_tics();
}
break;
case REALIGN_STAGE2_WAIT:
if(PPSG->ESCR & PPSG_ESCR_SYNC)
{
PPSG->ESCR = PPSG_ESCR_PPS_VALID | PPSG_ESCR_TM_VALID;
s->realign_state = REALIGN_DONE;
} else if (timer_get_tics() - s->realign_timer > 2*TICS_PER_SECOND)
{
PPSG->ESCR = 0;
s->realign_state = REALIGN_PPS_INVALID;
}
break;
case REALIGN_PPS_INVALID:
case REALIGN_DISABLED:
case REALIGN_DONE:
return ;
}
}
static int external_update( struct spll_external_state *s, int tag, int source)
{
int err, y, y2, yd, ylt;
if(source == s->ref_src)
{
int wrap = tag & (1<<BB_ERROR_BITS) ? 1 : 0;
realign_fsm(s);
tag &= ((1<<BB_ERROR_BITS) - 1);
// mprintf("err %d\n", tag);
if(wrap)
{
if(tag > s->ph_raw_d0)
s->ph_err_offset -= (1<<BB_ERROR_BITS);
else if(tag <= s->ph_raw_d0)
s->ph_err_offset += (1<<BB_ERROR_BITS);
}
s->ph_raw_d0 = tag;
err = (tag + s->ph_err_offset) - s->ph_err_d0;
s->ph_err_d0 = (tag + s->ph_err_offset);
y = pi_update(&s->pi, err);
y2 = lowpass_update(&s->lp_short, y);
ylt = lowpass_update(&s->lp_long, y);
if(! (SPLL->ECCR & SPLL_ECCR_EXT_REF_PRESENT)) /* no reference? de-lock now */
{
ld_init(&s->ld);
y2 = 32000;
}
SPLL->DAC_MAIN = y2 & 0xffff;
spll_debug(DBG_ERR | DBG_EXT, ylt, 0);
spll_debug(DBG_SAMPLE_ID | DBG_EXT, s->sample_n++, 0);
spll_debug(DBG_Y | DBG_EXT, y2, 1);
if(ld_update(&s->ld, y2 - ylt))
return SPLL_LOCKED;
}
return SPLL_LOCKING;
}
static void external_start( struct spll_external_state *s)
{
// mprintf("ExtStartup\n");
SPLL->ECCR = 0;
s->sample_n = 0;
s->realign_state = (s->realign_clocks ? REALIGN_STAGE1 : REALIGN_DISABLED);
SPLL->ECCR = SPLL_ECCR_EXT_EN;
spll_debug(DBG_EVENT | DBG_EXT, DBG_EVT_START, 1);
}
static inline int external_locked( struct spll_external_state *s)
{
return (s->ld.locked && (s->realign_clocks ? s->realign_state == REALIGN_DONE : 1));
}
/* State of the Helper PLL producing a clock (clk_dmtd_i) which is
slightly offset in frequency from the recovered/reference clock (clk_rx_i or clk_ref_i), so the
Main PLL can use it to perform linear phase measurements.
*/
#define SPLL_LOCKED 1
#define SPLL_LOCKING 0
#define HELPER_TAG_WRAPAROUND 100000000
/* Maximum abs value of the phase error. If the error is bigger, it's clamped to this value. */
#define HELPER_ERROR_CLAMP 150000
struct spll_helper_state {
int p_adder; /* anti wrap-around adder */
int p_setpoint, tag_d0;
int ref_src;
int sample_n;
int delock_count;
spll_pi_t pi;
spll_lock_det_t ld;
};
static void helper_init(struct spll_helper_state *s, int ref_channel)
{
/* Phase branch PI controller */
s->pi.y_min = 5;
s->pi.y_max = (1 << DAC_BITS) - 5;
s->pi.kp = (int)(0.3 * 32.0 * 16.0);// / 2;
s->pi.ki = (int)(0.03 * 32.0 * 3.0);// / 2;
s->pi.anti_windup = 1;
/* Phase branch lock detection */
s->ld.threshold = 200;
s->ld.lock_samples = 10000;
s->ld.delock_samples = 100;
s->ref_src = ref_channel;
s->delock_count = 0;
}
static int helper_update(struct spll_helper_state *s, int tag, int source)
{
int err, y;
if(source == s->ref_src)
{
spll_debug(DBG_TAG | DBG_HELPER, tag, 0);
spll_debug(DBG_REF | DBG_HELPER, s->p_setpoint, 0);
if(s->tag_d0 < 0)
{
s->p_setpoint = tag;
s->tag_d0 = tag;
return SPLL_LOCKING;
}
if(s->tag_d0 > tag)
s->p_adder += (1<<TAG_BITS);
err = (tag + s->p_adder) - s->p_setpoint;
if(HELPER_ERROR_CLAMP)
{
if(err < -HELPER_ERROR_CLAMP) err = -HELPER_ERROR_CLAMP;
if(err > HELPER_ERROR_CLAMP) err = HELPER_ERROR_CLAMP;
}
if((tag + s->p_adder) > HELPER_TAG_WRAPAROUND && s->p_setpoint > HELPER_TAG_WRAPAROUND)
{
s->p_adder -= HELPER_TAG_WRAPAROUND;
s->p_setpoint -= HELPER_TAG_WRAPAROUND;
}
s->p_setpoint += (1<<HPLL_N);
s->tag_d0 = tag;
y = pi_update(&s->pi, err);
SPLL->DAC_HPLL = y;
spll_debug(DBG_SAMPLE_ID | DBG_HELPER, s->sample_n++, 0);
spll_debug(DBG_Y | DBG_HELPER, y, 0);
spll_debug(DBG_ERR | DBG_HELPER, err, 1);
if(ld_update(&s->ld, err))
return SPLL_LOCKED;
}
return SPLL_LOCKING;
}
static void helper_start(struct spll_helper_state *s)
{
/* Set the bias to the upper end of tuning range. This is to ensure that
the HPLL will always lock on positive frequency offset. */
s->pi.bias = s->pi.y_max;
s->p_setpoint = 0;
s->p_adder = 0;
s->sample_n = 0;
s->tag_d0 = -1;
pi_init(&s->pi);
ld_init(&s->ld);
spll_enable_tagger(s->ref_src, 1);
spll_debug(DBG_EVENT | DBG_HELPER, DBG_EVT_START, 1);
}
#define MPLL_TAG_WRAPAROUND 100000000
#define MATCH_NEXT_TAG 0
#define MATCH_WAIT_REF 1
#define MATCH_WAIT_OUT 2
#undef WITH_SEQUENCING
/* State of the Main PLL */
struct spll_main_state {
int state;
spll_pi_t pi;
spll_lock_det_t ld;
int adder_ref, adder_out, tag_ref, tag_out, tag_ref_d, tag_out_d;
// tag sequencing stuff
uint32_t seq_ref, seq_out;
int match_state;
int match_seq;
int phase_shift_target;
int phase_shift_current;
int id_ref, id_out; /* IDs of the reference and the output channel */
int sample_n;
int delock_count;
int dac_index;
};
static void mpll_init(struct spll_main_state *s, int id_ref, int id_out)
{
/* Frequency branch PI controller */
s->pi.y_min = 5;
s->pi.y_max = 65530;
s->pi.anti_windup = 1;
s->pi.bias = 65000;
s->pi.kp = 1100;// / 2;
s->pi.ki = 30;// / 2;
s->delock_count = 0;
/* Freqency branch lock detection */
s->ld.threshold = 1200;
s->ld.lock_samples = 1000;
s->ld.delock_samples = 100;
s->id_ref = id_ref;
s->id_out = id_out;
s->dac_index = id_out - n_chan_ref;
mprintf("DACindex : %d\n", s->dac_index);
pi_init(&s->pi);
ld_init(&s->ld);
}
static void mpll_start(struct spll_main_state *s)
{
s->adder_ref = s->adder_out = 0;
s->tag_ref = -1;
s->tag_out = -1;
s->tag_ref_d = -1;
s->tag_out_d = -1;
s->seq_ref = 0;
s->seq_out = 0;
s->match_state = MATCH_NEXT_TAG;
s->phase_shift_target = 0;
s->phase_shift_current = 0;
s->sample_n= 0;
pi_init(&s->pi);
ld_init(&s->ld);
spll_enable_tagger(s->id_ref, 1);
spll_enable_tagger(s->id_out, 1);
spll_debug(DBG_EVENT | DBG_MAIN, DBG_EVT_START, 1);
}
static void mpll_stop(struct spll_main_state *s)
{
spll_enable_tagger(s->id_out, 0);
}
static int mpll_update(struct spll_main_state *s, int tag, int source)
{
int err, y, tmp;
#ifdef WITH_SEQUENCING
int new_ref = -1, new_out = -1;
if(source == s->id_ref)
{
new_ref = tag;
s->seq_ref++;
} else if(source == s->id_out) {
new_out = tag;
s->seq_out++;
}
switch(s->match_state)
{
case MATCH_NEXT_TAG:
if(new_ref > 0 && s->seq_out < s->seq_ref)
{
s->tag_ref = new_ref;
s->match_seq = s->seq_ref;
s->match_state = MATCH_WAIT_OUT;
}
if (new_out > 0 && s->seq_out > s->seq_ref)
{
s->tag_out = new_out;
s->match_seq = s->seq_out;
s->match_state = MATCH_WAIT_REF;
}
break;
case MATCH_WAIT_REF:
if(new_ref > 0 && s->seq_ref == s->match_seq)
{
s->match_state = MATCH_NEXT_TAG;
s->tag_ref = new_ref;
}
break;
case MATCH_WAIT_OUT:
if(new_out > 0 && s->seq_out == s->match_seq)
{
s->match_state = MATCH_NEXT_TAG;
s->tag_out = new_out;
}
break;
}
#else
if(source == s->id_ref)
s->tag_ref = tag;
if(source == s->id_out)
s->tag_out = tag;
#endif
if(s->tag_ref >= 0 && s->tag_out >= 0)
{
if(s->tag_ref_d >= 0 && s->tag_ref_d > s->tag_ref)
s->adder_ref += (1<<TAG_BITS);
if(s->tag_out_d >= 0 && s->tag_out_d > s->tag_out)
s->adder_out += (1<<TAG_BITS);
s->tag_ref_d = s->tag_ref;
s->tag_out_d = s->tag_out;
err = s->adder_ref + s->tag_ref - s->adder_out - s->tag_out;
#ifndef WITH_SEQUENCING
/* Hack: the PLL is locked, so the tags are close to each other. But when we start phase shifting, after reaching
full clock period, one of the reference tags will flip before the other, causing a suddent 2**HPLL_N jump in the error.
So, once the PLL is locked, we just mask out everything above 2**HPLL_N.
Proper solution: tag sequence numbers */
if(s->ld.locked)
{
err &= (1<<HPLL_N)-1;
if(err & (1<<(HPLL_N-1)))
err |= ~((1<<HPLL_N)-1);
}
#endif
y = pi_update(&s->pi, err);
SPLL->DAC_MAIN = SPLL_DAC_MAIN_VALUE_W(y) | SPLL_DAC_MAIN_DAC_SEL_W(s->dac_index);
spll_debug(DBG_MAIN | DBG_REF, s->tag_ref + s->adder_ref, 0);
spll_debug(DBG_MAIN | DBG_TAG, s->tag_out + s->adder_out, 0);
spll_debug(DBG_MAIN | DBG_ERR, err, 0);
spll_debug(DBG_MAIN | DBG_SAMPLE_ID, s->sample_n++, 0);
spll_debug(DBG_MAIN | DBG_Y, y, 1);
s->tag_out = -1;
s->tag_ref = -1;
if(s->adder_ref > 2*MPLL_TAG_WRAPAROUND && s->adder_out > 2*MPLL_TAG_WRAPAROUND)
{
s->adder_ref -= MPLL_TAG_WRAPAROUND;
s->adder_out -= MPLL_TAG_WRAPAROUND;
}
if(s->ld.locked)
{
if(s->phase_shift_current < s->phase_shift_target)
{
s->phase_shift_current++;
s->adder_ref++;
} else if(s->phase_shift_current > s->phase_shift_target) {
s->phase_shift_current--;
s->adder_ref--;
}
}
if(ld_update(&s->ld, err))
return SPLL_LOCKED;
}
return SPLL_LOCKING;
}
static int mpll_set_phase_shift(struct spll_main_state *s, int desired_shift)
{
s->phase_shift_target = desired_shift;
}
static int mpll_shifter_busy(struct spll_main_state *s)
{
return s->phase_shift_target != s->phase_shift_current;
}
/* State of a Phase Tracker */
struct spll_ptracker_state {
int id_a, id_b;
int n_avg, acc, avg_count;
int phase_val, ready;
int tag_a, tag_b;
int sample_n;
int preserve_sign;
};
static void ptracker_init(struct spll_ptracker_state *s, int id_a, int id_b, int num_avgs)
{
s->tag_a = s->tag_b = -1;
s->id_a = id_a;
s->id_b = id_b;
s->ready = 0;
s->n_avg = num_avgs;
s->acc = 0;
s->avg_count = 0;
s->sample_n= 0;
s->preserve_sign = 0;
}
static void ptracker_start(struct spll_ptracker_state *s)
{
s->tag_a = s->tag_b = -1;
s->ready = 0;
s->acc = 0;
s->avg_count = 0;
s->sample_n= 0;
s->preserve_sign = 0;
spll_enable_tagger(s->id_a, 1);
spll_enable_tagger(s->id_b, 1);
}
#define PTRACK_WRAP_LO (1<<(HPLL_N-2))
#define PTRACK_WRAP_HI (3*(1<<(HPLL_N-2)))
static int ptracker_update(struct spll_ptracker_state *s, int tag, int source)
{
if(source == s->id_a)
s->tag_a = tag;
if(source == s->id_b)
s->tag_b = tag;
if(s->tag_a >= 0 && s->tag_b >= 0)
{
int delta = (s->tag_a - s->tag_b) & ((1<<HPLL_N) - 1);
s->sample_n++;
if(s->avg_count == 0)
{
if(delta <= PTRACK_WRAP_LO)
s->preserve_sign = -1;
else if (delta >= PTRACK_WRAP_HI)
s->preserve_sign = 1;
else
s->preserve_sign = 0;
s->avg_count++;
s->acc = delta;
} else {
if(delta <= PTRACK_WRAP_LO && s->preserve_sign > 0)
s->acc += delta + (1<<HPLL_N);
else if (delta >= PTRACK_WRAP_HI && s->preserve_sign < 0)
s->acc += delta - (1<<HPLL_N);
else
s->acc += delta;
s->avg_count++;
if(s->avg_count == s->n_avg)
{
s->phase_val = s->acc / s->n_avg;
s->ready = 1;
s->acc = 0;
s->avg_count = 0;
}
}
s->tag_b = s->tag_a = -1;
}
return SPLL_LOCKING;
}
#ifndef __STDINT_H__
#define __STDINT_H__
#include<inttypes.h>
#endif
#ifndef __SYSCON_H
#define __SYSCON_H
#include <inttypes.h>
#include "board.h"
#include <hw/wrc_syscon_regs.h>
struct SYSCON_WB
{
uint32_t RSTR; /*Syscon Reset Register*/
uint32_t GPSR; /*GPIO Set/Readback Register*/
uint32_t GPCR; /*GPIO Clear Register*/
uint32_t HWFR; /*Hardware Feature Register*/
uint32_t TCR; /*Timer Control Register*/
uint32_t TVR; /*Timer Counter Value Register*/
};
/*GPIO pins*/
#define GPIO_LED_LINK SYSC_GPSR_LED_LINK
#define GPIO_LED_STAT SYSC_GPSR_LED_STAT
#define GPIO_BTN1 SYSC_GPSR_BTN1
#define GPIO_BTN2 SYSC_GPSR_BTN2
#define GPIO_SFP_DET SYSC_GPSR_SFP_DET
#define WRPC_FMC_I2C 0
#define WRPC_SFP_I2C 1
struct s_i2c_if
{
uint32_t scl;
uint32_t sda;
};
extern struct s_i2c_if i2c_if[2];
void timer_init(uint32_t enable);
uint32_t timer_get_tics();
void timer_delay(uint32_t how_long);
static volatile struct SYSCON_WB *syscon = (volatile struct SYSCON_WB *) BASE_SYSCON;
/****************************
* GPIO
***************************/
static inline void gpio_out(int pin, int val)
{
if(val)
syscon->GPSR = pin;
else
syscon->GPCR = pin;
}
static inline int gpio_in(int pin)
{
return syscon->GPSR & pin ? 1: 0;
}
#endif
......@@ -3,6 +3,8 @@
#include "types.h"
#define TICS_PER_SECOND 1000
uint32_t timer_get_tics();
void timer_delay(uint32_t how_long);
......
......@@ -4,6 +4,7 @@
#include <inttypes.h>
struct hw_timestamp {
uint8_t valid;
int ahead;
uint32_t utc;
uint32_t nsec;
......
#include "board.h"
#include "ptpd_exports.h"
#include "hal_exports.h"
#include "softpll_ng.h"
extern ptpdexp_sync_state_t cur_servo_state;
extern int wrc_man_phase;
......@@ -27,6 +28,7 @@ int wrc_mon_gui(void)
static uint32_t last = 0;
hexp_port_state_t ps;
int tx, rx;
int aux_stat;
if(timer_get_tics() - last < 1000)
return 0;
......@@ -73,6 +75,17 @@ int wrc_mon_gui(void)
m_cprintf(C_GREY, "Phase tracking: "); if(cur_servo_state.tracking_enabled) m_cprintf(C_GREEN, "ON\n"); else m_cprintf(C_RED,"OFF\n");
m_cprintf(C_GREY, "Synchronization source: "); m_cprintf(C_WHITE, "%s\n", cur_servo_state.sync_source);
m_cprintf(C_GREY, "Aux clock status: ");
aux_stat = spll_get_aux_status(0);
if(aux_stat & SPLL_AUX_ENABLED)
m_cprintf(C_GREEN,"enabled");
if(aux_stat & SPLL_AUX_LOCKED)
m_cprintf(C_GREEN,", locked");
mprintf("\n");
m_cprintf(C_BLUE, "\nTiming parameters:\n\n");
m_cprintf(C_GREY, "Round-trip time (mu): "); m_cprintf(C_WHITE, "%d ps\n", (int32_t)(cur_servo_state.mu));
......@@ -80,6 +93,9 @@ int wrc_mon_gui(void)
m_cprintf(C_GREY, "Master PHY delays: "); m_cprintf(C_WHITE, "TX: %d ps, RX: %d ps\n", (int32_t)cur_servo_state.delta_tx_m, (int32_t)cur_servo_state.delta_rx_m);
m_cprintf(C_GREY, "Slave PHY delays: "); m_cprintf(C_WHITE, "TX: %d ps, RX: %d ps\n", (int32_t)cur_servo_state.delta_tx_s, (int32_t)cur_servo_state.delta_rx_s);
m_cprintf(C_GREY, "Total link asymmetry: "); m_cprintf(C_WHITE, "%d ps\n", (int32_t)(cur_servo_state.total_asymmetry));
m_cprintf(C_GREY, "Cable rtt delay: "); m_cprintf(C_WHITE, "%d ps\n",
(int32_t)(cur_servo_state.mu) - (int32_t)cur_servo_state.delta_tx_m - (int32_t)cur_servo_state.delta_rx_m -
(int32_t)cur_servo_state.delta_tx_s - (int32_t)cur_servo_state.delta_rx_s);
m_cprintf(C_GREY, "Clock offset: "); m_cprintf(C_WHITE, "%d ps\n", (int32_t)(cur_servo_state.cur_offset));
m_cprintf(C_GREY, "Phase setpoint: "); m_cprintf(C_WHITE, "%d ps\n", (int32_t)(cur_servo_state.cur_setpoint));
m_cprintf(C_GREY, "Skew: "); m_cprintf(C_WHITE, "%d ps\n", (int32_t)(cur_servo_state.cur_skew));
......@@ -92,3 +108,45 @@ int wrc_mon_gui(void)
return 0;
}
int wrc_log_stats(void)
{
static char* slave_states[] = {"Uninitialized", "SYNC_UTC", "SYNC_NSEC", "SYNC_PHASE", "TRACK_PHASE"};
static uint32_t last = 0;
hexp_port_state_t ps;
int tx, rx;
int aux_stat;
if(timer_get_tics() - last < 1000)
return 0;
last = timer_get_tics();
halexp_get_port_state(&ps, NULL);
minic_get_stats(&tx, &rx);
mprintf("-->STAT Link:%d rx:%d tx:%d ", ps.up, rx, tx);
mprintf("Lock:%d ", ps.is_locked?1:0);
mprintf("ServoValid:%d ", cur_servo_state.valid?1:0);
mprintf("ServoState:'%s' ", cur_servo_state.slave_servo_state);
aux_stat = spll_get_aux_status(0);
mprintf("aux:%x ", aux_stat);
mprintf("mu:%d ", cur_servo_state.mu);
mprintf("dms:%d ", cur_servo_state.delay_ms);
mprintf("dtxm:%d drxm:%d ", (int32_t)cur_servo_state.delta_tx_m, (int32_t)cur_servo_state.delta_rx_m);
mprintf("dtxs:%d drxs:%d ", (int32_t)cur_servo_state.delta_tx_s, (int32_t)cur_servo_state.delta_rx_s);
mprintf("asym:%d ", (int32_t)(cur_servo_state.total_asymmetry));
mprintf("cable_rtt:%d ",
(int32_t)(cur_servo_state.mu) - (int32_t)cur_servo_state.delta_tx_m - (int32_t)cur_servo_state.delta_rx_m -
(int32_t)cur_servo_state.delta_tx_s - (int32_t)cur_servo_state.delta_rx_s);
mprintf("ckoffs:%d ", (int32_t)(cur_servo_state.cur_offset));
mprintf("setpoint:%d ", (int32_t)(cur_servo_state.cur_setpoint));
mprintf("HDAC:%d MDAC:%d ADAC:%d ",
spll_get_dac(-1),
spll_get_dac(0),
spll_get_dac(1)
);
mprintf("\n");
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <wr_ipc.h>
#include "term.h"
#include "ptpd_exports.h"
#include "hal_client.h"
hexp_port_list_t port_list;
wripc_handle_t h_ptp;
void init()
{
halexp_client_init();
if( (h_ptp = wripc_connect("ptpd")) < 0)
{
fprintf(stderr,"Can't establish WRIPC connection to the PTP daemon!\n");
exit(-1);
}
term_init();
halexp_query_ports(&port_list);
}
void show_ports()
{
int i;
term_pcprintf(3, 1, C_BLUE, "Switch ports:");
for(i=0; i<port_list.num_ports;i++)
{
hexp_port_state_t state;
halexp_get_port_state(&state, port_list.port_names[i]);
term_pcprintf(5+i, 1, C_WHITE, "%s: ", port_list.port_names[i]);
if(state.up) term_cprintf(C_GREEN, "Link up "); else term_cprintf(C_RED, "Link down ");
term_cprintf(C_GREY, "mode: ");
switch(state.mode)
{
case HEXP_PORT_MODE_WR_MASTER:term_cprintf(C_WHITE, "WR Master ");break;
case HEXP_PORT_MODE_WR_SLAVE:term_cprintf(C_WHITE, "WR Slave ");break;
}
if(state.is_locked) term_cprintf(C_GREEN, "Locked "); else term_cprintf(C_RED, "NoLock ");
if(state.rx_calibrated && state.tx_calibrated) term_cprintf(C_GREEN, "Calibrated "); else term_cprintf(C_RED, "Uncalibrated ");
}
}
int ph_adjust = 0;
void show_servo()
{
ptpdexp_sync_state_t ss;
wripc_call(h_ptp, "ptpdexp_get_sync_state", &ss, 0);
term_cprintf(C_BLUE, "\n\nSynchronization status:\n\n");
if(!ss.valid)
{
term_cprintf(C_RED, "Master mode or sync info not valid\n\n");
return;
}
term_cprintf(C_GREY, "Servo state: "); term_cprintf(C_WHITE, "%s\n", ss.slave_servo_state);
term_cprintf(C_GREY, "Phase tracking: "); if(ss.tracking_enabled) term_cprintf(C_GREEN, "ON\n"); else term_cprintf(C_RED,"OFF\n");
term_cprintf(C_GREY, "Synchronization source: "); term_cprintf(C_WHITE, "%s\n", ss.sync_source);
term_cprintf(C_BLUE, "\nTiming parameters:\n\n");
term_cprintf(C_GREY, "Round-trip time (mu): "); term_cprintf(C_WHITE, "%.2f nsec\n", ss.mu/1000.0);
term_cprintf(C_GREY, "Master-slave delay: "); term_cprintf(C_WHITE, "%.2f nsec\n", ss.delay_ms/1000.0);
term_cprintf(C_GREY, "Link length: "); term_cprintf(C_WHITE, "%.0f meters \n", ss.delay_ms/1e12 * 300e6 / 1.55);
term_cprintf(C_GREY, "Master PHY delays: "); term_cprintf(C_WHITE, "TX: %.2f nsec, RX: %.2f nsec\n", ss.delta_tx_m/1000.0, ss.delta_rx_m/1000.0);
term_cprintf(C_GREY, "Slave PHY delays: "); term_cprintf(C_WHITE, "TX: %.2f nsec, RX: %.2f nsec\n", ss.delta_tx_s/1000.0, ss.delta_rx_s/1000.0);
term_cprintf(C_GREY, "Total link asymmetry: "); term_cprintf(C_WHITE, "%.2f nsec\n", ss.total_asymmetry/1000.0);
// term_cprintf(C_GREY, "Fiber asymmetry: "); term_cprintf(C_WHITE, "%.2f nsec\n", ss.fiber_asymmetry/1000.0);
term_cprintf(C_GREY, "Clock offset: "); term_cprintf(C_WHITE, "%.2f nsec\n", ss.cur_offset/1000.0);
term_cprintf(C_GREY, "Phase setpoint: "); term_cprintf(C_WHITE, "%.2f nsec\n", ss.cur_setpoint/1000.0);
term_cprintf(C_GREY, "Skew: "); term_cprintf(C_WHITE, "%.2f nsec\n", ss.cur_skew/1000.0);
term_cprintf(C_GREY, "Phase extra adjust: "); term_cprintf(C_WHITE, "%.2f nsec\n", (double) ph_adjust/1000.0);
}
int ki=20, kp=1000;
void show_pll()
{
term_cprintf(C_BLUE, "\n\nDMPLL:\n\n");
term_cprintf(C_GREY, "KI: %d KP: %d", ki, kp);
}
void show_menu()
{
term_pcprintf(30, 1, C_BLUE, "q = quit, t = toggle tracking");
}
int track_onoff = 1;
void show_screen()
{
term_clear();
term_pcprintf(1, 1, C_BLUE, "WR Switch Sync Monitor v 0.1");
show_ports();
show_servo();
show_menu();
// handle_toggle();
}
void pll_set_gain(int kp, int ki)
{
hexp_pll_cmd_t cmd;
cmd.pll = HEXP_DMPLL;
cmd.branch = HEXP_PHASE;
cmd.ki = ki;
cmd.kp = kp;
// halexp_pll_cmd(0, &cmd);
}
main()
{
int rval;
init();
for(;;)
{
if(term_poll())
{
int c = term_get();
if(c=='q') break;
else if(c=='t') {
track_onoff = 1-track_onoff;
wripc_call(h_ptp, "ptpdexp_cmd", &rval, 2, A_INT32(PTPDEXP_COMMAND_TRACKING), A_INT32(track_onoff));
} else if (c=='a')
{
ph_adjust += 500;
wripc_call(h_ptp, "ptpdexp_cmd", &rval, 2, A_INT32(PTPDEXP_COMMAND_MAN_ADJUST_PHASE), A_INT32(ph_adjust));
} else if (c=='z')
{
ph_adjust -= 500;
wripc_call(h_ptp, "ptpdexp_cmd", &rval, 2, A_INT32(PTPDEXP_COMMAND_MAN_ADJUST_PHASE), A_INT32(ph_adjust));
}
else if (c=='s')
{
ki += 10;
pll_set_gain(kp, ki);
} else if (c=='x')
{
ki -= 10;
pll_set_gain(kp, ki);
}
else if (c=='d')
{
kp += 10;
pll_set_gain(kp, ki);
} else if (c=='c')
{
kp -= 10;
pll_set_gain(kp, ki);
}
}
show_screen();
usleep(500000);
}
term_cprintf(C_GREY,"bye...\n\n");
term_clear();
term_restore();
}
\ No newline at end of file
......@@ -89,11 +89,9 @@
.global _start
_start:
.weak _debug_unit
.global _reset_handler
.type _reset_handler, @function
.align 256
_debug_unit:
_reset_handler:
xor r0, r0, r0
wcsr IE, r0
......@@ -105,45 +103,10 @@ _reset_handler:
nop
.size _reset_handler, .-_reset_handler
.extern _breakpoint_handler
.global _breakpoint_handler
.type _breakpoint_handler, @function
.align 32
_breakpoint_handler:
bret
.extern _instruction_bus_error_handler
.global _instruction_bus_error_handler
.type _instruction_bus_error_handler, @function
.align 32
_instruction_bus_error_handler:
eret
.extern _watchpoint_handler
.global _watchpoint_handler
.type _watchpoint_handler, @function
.align 32
_watchpoint_handler:
bret
.extern _data_bus_error_handler
.global _data_bus_error_handler
.type _data_bus_error_handler, @function
.align 32
_data_bus_error_handler:
eret
.extern _divide_by_zero_handler
.global _divide_by_zero_handler
.type _divide_by_zero_handler, @function
.align 32
_divide_by_zero_handler:
eret
.extern _irq_entry
.org 0xc0
.global _interrupt_handler
.type _interrupt_handler, @function
.align 32
_interrupt_handler:
sw (sp+0), ra
calli _save_all
......@@ -158,25 +121,12 @@ _interrupt_handler:
nop
nop
.extern _system_call_handler
.global _system_call_handler
.type _system_call_handler, @function
.align 32
_system_call_handler:
eret
.org 0x100
.global _crt0
.type _crt0, @function
_crt0:
/* Clear r0 */
xor r0, r0, r0
/* Setup the debug ROM if it's linked in */
mvhi r1, hi(_debug_unit)
ori r1, r1, lo(_debug_unit)
wcsr DEBA, r1
/* Setup stack and global pointer */
mvhi sp, hi(_fstack)
ori sp, sp, lo(_fstack)
......
......@@ -31,7 +31,7 @@ GROUP(-lgcc -lc)
MEMORY
{
ram : ORIGIN = 0x00000000, LENGTH = 0x10000
ram : ORIGIN = 0x00000000, LENGTH = 0x14000
}
SECTIONS
......
This diff is collapsed.
This diff is collapsed.
CFLAGS = -Wall -ggdb -I. -I../include
CFLAGS = -Wall -ggdb -I. -I../include -Imini_bone
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
......@@ -12,9 +12,10 @@ OBJDUMP = $(CROSS_COMPILE)objdump
all: lm32-loader genraminit vuart_console
OBJS_LOADER = lm32-loader.o rr_io.o
OBJS_LOADER = lm32-loader.o rr_io.o mini_bone/ptpd_netif.o mini_bone/minibone_lib.o
lm32-loader: $(OBJS_LOADER)
make -C mini_bone
${CC} -o lm32-loader $(OBJS_LOADER)
genraminit: genraminit.o
......@@ -27,4 +28,4 @@ vuart_console: vuart_console.o rr_io.o
${CC} -c $^ $(CFLAGS) -O0
clean:
rm -f $(ALL) *.o *~
rm -f $(ALL) *.o *~ mini_bone/*.o mini_bone/*~
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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