Commit fa6c9452 authored by José Luis  Gutiérrez's avatar José Luis Gutiérrez

wrpc: removing, working only on WRS

parent 96343426
*.o
*.a
*.elf
*.ram
*.bin
*.mif
*.*~
*~
*_disasm.S
*.vhd
*.cmd
*.o
.tmp_*
.config
.config.old
include/config
include/generated
[submodule "ppsi"]
path = ppsi
url = git://ohwr.org/white-rabbit/ppsi.git
This diff is collapsed.
mainmenu "WR PTP Core software configuration"
# Later we'll build wr_cpu.bin for wr-switch from this code base
config WR_SWITCH
bool "Build rt_cpu.bin, for the WR-Switch FPGA"
default n
select UART
config WR_NODE
bool
default !WR_SWITCH
# most options with no prompt here are prompted-for in the "advanced" section
config PRINT_BUFSIZE
int
default 128
config PRINTF_XINT
boolean
default y
config RAMSIZE
int
default 65536 if WR_SWITCH
default 131072
# CONFIG_WR_SWITCH has no further options at all at this point
if WR_NODE
config STACKSIZE
int
default 2048
config PPSI
boolean
default y
config UART
boolean
default y
config W1
boolean
default y
# The other ones can be set by non-developers
config ETHERBONE
boolean "Compile Etherbone support in wrpc-sw"
help
This allows to run LM32 code that is aware of Etherbone.
You need to run a gateware file that includes Etherbone support.
If in doubt, say No.
config WRNIC
boolean "Compile White Rabbit NIC support in wrpc-sw"
help
This allows to run LM32 code that is aware of Etherbone and
NIC. You need to run a gateware file that includes Etherbone
and NIC support. This option needs ETHERBONE enabled.
If in doubt, say No.
config CMD_CONFIG
boolean "Include configuration in the output binary"
help
This options adds the "config" command to the shell, which
reports the current configuration. This adds half a kilobyte
to the binary size (100b for the code plus the .config file).
config NIC_PFILTER
depends on ETHERBONE
bool "Add packet filter rules for wr-nic"
help
When using wr-nic, the host must receive frames that are not
ptp nor etherbone ones. This adds the needed filter rules
to that effect. Such rules are not needed when no Etherbone
is there, because in that case all non-ptp frames reach the
host.
#
# This is a set of configuration options that should not be changed by
# normal users. If the "developer" menu is used, the binary is tainted.
comment "wrpc-sw is tainted if you change the following options"
config DEVELOPER
bool "Advanced configurations, only for developers"
help
The following options are new features under testing, or
special customizations not normally useful for people not
directly working on this package. Please don't use unless
you are a developer of wrpc-sw.
config RAMSIZE
depends on DEVELOPER
int "Size of the RAM in the FPGA for this program"
default 90112
help
The usual configuration for wrpc-sw is 0x16000 bytes
(i.e. 88kB = 90112 bytes) but if your project has less or
more features you may want to adjust the FPGA size and
choose your preferred value here.
config STACKSIZE
depends on DEVELOPER
int "Size of the stack area needed by this program"
default 2048
help
The linker complains if the code doesn't fit into RAM, but
we must also consider the stack, or the program will crash
at run time. (However, we have a detector for overflows).
config PRINT_BUFSIZE
depends on DEVELOPER
int "Size for the temporary output string of pp_printf"
default 128
help
This buffer is constant storage (i.e. wasted space), but it
also constraints the maximum lenght of text that can be written
in a single call to printf.
config CHECK_RESET
depends on DEVELOPER
bool "Print a stack trace if reset happens"
help
If the CPU is following a NULL pointer, the program will
be restarted. If this option is activated, the main function
detects that it is re-executed and dumps a stack trace; it
then clears the stack (for next time) and restarts again.
choice
prompt "Implementation of pp_printf"
depends on DEVELOPER
config PRINTF_XINT
bool "hex-and-int"
help
This selects a printf that can only print decimal and hex
numbers, without obeying the format modifiers. %c and %s are
supported too, and %p is equivalent to %x.
See pp_printf/README for details.
config PRINTF_FULL
bool "full"
help
This selects an implementation that supports all standard
formats with modifiers, like "%08X" and "%.5s". It costs
around 2k of compiled code more than XINT.
See pp_printf/README for details.
config PRINTF_MINI
bool "minimal"
help
This selects a printf that prints all integers as hex,
without obeying the format modifiers. %c and %s are
supported too. See pp_printf/README for details.
This is not probably what you want for wrpc-sw.
config PRINTF_NONE
bool "empty"
help
This selects a printf that prints the format string
alone and ignores all further arguments. Minimal size,
but not suited for wrpc-sw. See pp_printf/README for details.
endchoice
config PPSI
boolean
help
Select this option for the ppsi engine (now only option)
config DETERMINISTIC_BINARY
depends on DEVELOPER
boolean "Build a binary that is the same every time"
help
This option is used to #ifdef __DATE__ and __TIME__ strings
out of the compiled WRC binary. If you set it you'll get the
same binary bit-by-bit at each rebuild. I am using this
option to hack the build procedure and use a simple "diff"
between the old and new output to verify I didn't introduce
changes.
If in doubt, say No.
config UART
boolean "Use hardware uart (and/or vuart if available)"
depends on DEVELOPER
default y
help
This option selects the serial driver, connected to either
the USB socket, or "vuart" (software fifo) or both, according
to how the gateware is built.
config UART_SW
depends on DEVELOPER
default !UART
boolean "Use software uart"
help
The software uart is made up of two circular buffers. It can
be used either as an alternative to the harwdare UART or as
an addition. If the option is turned on, ppsi log messages
are routed to the software uart. The interactive wrpc shell
and diagnostics run on the hardware UART if available.
config SDB_STORAGE
default y
boolean "Use SDB to manage storage (instead of legacy eeprom code)"
help
Use SDB to manage flash and eeproms (both W1 and I2C). If not, legacy code
(eeprom only) will be selected.
config LEGACY_EEPROM
boolean
default !SDB_STORAGE
endif
# CONFIG_WR_NODE
#!/bin/sh
# A trivial script to build with all known configurations
# (please add a configs/ file to test your special case
T=$(mktemp /tmp/wrpc-config.XXXXXX)
configs=$(ls configs)
if [ $# -ne 0 ]; then
configs="$*"
fi
for c in $configs; do
echo "##### Building with '$c'"
if ! make $c 2>&1 >> $T; then
echo "Error in configuration (see $T)"
exit 1
fi
make -s clean
make -s
done
rm $T
\ No newline at end of file
# Tomasz Wlostowski for CERN, 2011,2012
CROSS_COMPILE ?= lm32-elf-
export CROSS_COMPILE
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
OBJDUMP = $(CROSS_COMPILE)objdump
OBJCOPY = $(CROSS_COMPILE)objcopy
SIZE = $(CROSS_COMPILE)size
-include $(CURDIR)/.config
AUTOCONF = $(CURDIR)/include/generated/autoconf.h
PPSI = ppsi
# we miss CONFIG_ARCH_LM32 as we have no other archs by now
obj-y = arch/lm32/crt0.o arch/lm32/irq.o
LDS-$(CONFIG_WR_NODE) = arch/lm32/ram.ld
LDS-$(CONFIG_WR_SWITCH) = arch/lm32/ram-wrs.ld
obj-$(CONFIG_WR_NODE) += wrc_main.o
obj-$(CONFIG_WR_SWITCH) += wrs_main.o
obj-$(CONFIG_WR_SWITCH) += ipc/minipc-mem-server.o ipc/rt_ipc.o
# our linker script is preprocessed, so have a rule here
%.ld: %.ld.S $(AUTOCONF) .config
$(CC) -include $(AUTOCONF) -E -P $*.ld.S -o $@
cflags-y = -ffreestanding -include $(AUTOCONF) -Iinclude/std -Iinclude \
-I. -Isoftpll -Iipc
cflags-y += -I$(CURDIR)/pp_printf
cflags-$(CONFIG_PPSI) += \
-ffreestanding \
-include include/ppsi-wrappers.h \
-Iinclude \
-I$(PPSI)/include \
-I$(PPSI)/arch-wrpc \
-I$(PPSI)/arch-wrpc/include \
-I$(PPSI)/proto-ext-whiterabbit \
-Iboards/spec
obj-ppsi = \
$(PPSI)/ppsi.o
obj-$(CONFIG_PPSI) += \
monitor/monitor_ppsi.o \
lib/ppsi-wrappers.o \
$(obj-ppsi)
CFLAGS_PLATFORM = -mmultiply-enabled -mbarrel-shift-enabled
LDFLAGS_PLATFORM = -mmultiply-enabled -mbarrel-shift-enabled \
-nostdlib -T $(LDS-y)
include shell/shell.mk
include lib/lib.mk
include pp_printf/printf.mk
include dev/dev.mk
include softpll/softpll.mk
# ppsi already has div64 (the same one), so only pick it if not using ppsi
ifndef CONFIG_PPSI
obj-y += pp_printf/div64.o
endif
# And always complain if we pick the libgcc division: 64/32 = 32 is enough here.
obj-y += check-error.o
obj-$(CONFIG_WR_NODE) += sdb-lib/libsdbfs.a
cflags-$(CONFIG_WR_NODE) += -Isdb-lib
CFLAGS = $(CFLAGS_PLATFORM) $(cflags-y) -Wall \
-ffunction-sections -fdata-sections -Os \
-include include/trace.h -ggdb
LDFLAGS = $(LDFLAGS_PLATFORM) \
-Wl,--gc-sections -Os -lgcc -lc
OBJS = $(obj-y)
OUTPUT-$(CONFIG_WR_NODE) = wrc
OUTPUT-$(CONFIG_WR_SWITCH) = rt_cpu
OUTPUT := $(OUTPUT-y)
REVISION=$(shell git describe --dirty --always)
all: tools $(OUTPUT).ram $(OUTPUT).vhd $(OUTPUT).mif
.PRECIOUS: %.elf %.bin
.PHONY: all tools clean gitmodules $(PPSI)/ppsi.o
# we need to remove "ptpdump" support for ppsi if RAM size is small and
# we include etherbone
ifneq ($(CONFIG_RAMSIZE),131072)
ifdef CONFIG_ETHERBONE
PPSI_USER_CFLAGS = -DCONFIG_NO_PTPDUMP
endif
endif
PPSI_USER_CFLAGS += -DDIAG_PUTS=uart_sw_write_string
$(obj-ppsi):
test -f $(PPSI)/.config || $(MAKE) -C $(PPSI) wrpc_defconfig
$(MAKE) -C $(PPSI) WRPCSW_ROOT=.. \
CROSS_COMPILE=$(CROSS_COMPILE) CONFIG_NO_PRINTF=y \
USER_CFLAGS="$(PPSI_USER_CFLAGS)"
sdb-lib/libsdbfs.a:
$(MAKE) -C sdb-lib
$(OUTPUT).elf: $(LDS-y) $(AUTOCONF) gitmodules $(OUTPUT).o config.o
$(CC) $(CFLAGS) -DGIT_REVISION=\"$(REVISION)\" -c revision.c
${CC} -o $@ revision.o config.o $(OUTPUT).o $(LDFLAGS)
${OBJDUMP} -d $(OUTPUT).elf > $(OUTPUT)_disasm.S
$(SIZE) $@
$(OUTPUT).o: $(OBJS)
$(LD) --gc-sections -e _start -r $(OBJS) -T bigobj.lds -o $@
config.o: .config
sed '1,3d' .config > .config.bin
dd bs=1 count=1 if=/dev/zero 2> /dev/null >> .config.bin
$(OBJCOPY) -I binary -O elf32-lm32 -B lm32 \
--rename-section .data=.data.config .config.bin $@
rm -f .config.bin
%.bin: %.elf
${OBJCOPY} -O binary $^ $@
%.ram: tools %.bin
./tools/genraminit $*.bin 0 > $@
%.vhd: tools %.bin
./tools/genramvhd -s `. ./.config; echo $$CONFIG_RAMSIZE` $*.bin > $@
%.mif: tools %.bin
./tools/genrammif $*.bin `. ./.config; echo $$CONFIG_RAMSIZE` > $@
$(AUTOCONF): silentoldconfig
clean:
rm -f $(OBJS) $(OUTPUT).elf $(OUTPUT).bin $(OUTPUT).ram $(LDS)
$(MAKE) -C $(PPSI) clean
$(MAKE) -C sdb-lib clean
$(MAKE) -C tools clean
%.o: %.c
${CC} $(CFLAGS) $(PTPD_CFLAGS) $(INCLUDE_DIR) $(LIB_DIR) -c $*.c -o $@
tools:
$(MAKE) -C tools
# if needed, check out the submodules (first time only), so users
# who didn't read carefully the manual won't get confused
gitmodules:
@test -d ppsi/arch-wrpc || echo "Checking out submodules"
@test -d ppsi/arch-wrpc || git submodule update --init
# following targets from Makefile.kconfig
silentoldconfig:
@mkdir -p include/config
$(MAKE) -f Makefile.kconfig $@
scripts_basic config:
$(MAKE) -f Makefile.kconfig $@
%config:
$(MAKE) -f Makefile.kconfig $@
defconfig:
$(MAKE) -f Makefile.kconfig spec_defconfig
.config: silentoldconfig
# This forces more compilations than needed, but it's useful
# (we depend on .config and not on include/generated/autoconf.h
# because the latter is touched by silentoldconfig at each build)
$(obj-y): .config $(wildcard include/*.h)
VERSION = $(shell git describe --always --dirty)
export VERSION
# Do not:
# o use make's built-in rules and variables
# (this increases performance and avoids hard-to-debug behaviour);
# o print "Entering directory ...";
MAKEFLAGS += -rR --no-print-directory
# To put more focus on warnings, be less verbose as default
# Use 'make V=1' to see the full commands
ifdef V
ifeq ("$(origin V)", "command line")
KBUILD_VERBOSE = $(V)
endif
endif
ifndef KBUILD_VERBOSE
KBUILD_VERBOSE = 0
endif
# Cancel implicit rules on top Makefile
$(CURDIR)/Makefile Makefile: ;
# That's our default target when none is given on the command line
PHONY := _all
_all:
# SHELL used by kbuild
CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
else if [ -x /bin/bash ]; then echo /bin/bash; \
else echo sh; fi ; fi)
# Make variables (CC, etc...)
HOSTCC = gcc
HOSTCXX = g++
HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
HOSTCXXFLAGS = -O2
export HOSTCC HOSTCXX HOSTCFLAGS HOSTCXXFLAGS
KBUILD_KCONFIG = $(CURDIR)/Kconfig
export KBUILD_KCONFIG
srctree := $(CURDIR)
objtree := $(CURDIR)
src := $(srctree)
obj := $(objtree)
export srctree objtree
# We need some generic definitions (do not try to remake the file).
$(srctree)/scripts/Kbuild.include: ;
include $(srctree)/scripts/Kbuild.include
# Basic helpers built in scripts/
PHONY += scripts_basic
scripts_basic:
$(Q)$(MAKE) $(build)=scripts/basic
config: scripts_basic FORCE
$(Q)mkdir -p include/linux include/config
$(Q)$(MAKE) $(build)=scripts/kconfig $@
%config: scripts_basic FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@
clean:
@find . $(RCS_FIND_IGNORE) \
\( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
-o -name 'Module.markers' -o -name '.tmp_*.o.*' \) \
-type f -print | xargs rm -f -v
PHONY += FORCE
FORCE:
# Declare the contents of the .PHONY variable as phony. We keep that
# information in a variable so we can use it in if_changed and friends.
.PHONY: $(PHONY)
wrpc-sw implementation for HSR
ram.ld
\ No newline at end of file
/****************************************************************************
**
** Name: crt0ram.S
**
** Description:
** Implements boot-code that calls LatticeDDInit (that calls main())
** Implements exception handlers (actually, redirectors)
**
** $Revision: $
**
** Disclaimer:
**
** This source code is intended as a design reference which
** illustrates how these types of functions can be implemented. It
** is the user's responsibility to verify their design for
** consistency and functionality through the use of formal
** verification methods. Lattice Semiconductor provides no warranty
** regarding the use or functionality of this code.
**
** --------------------------------------------------------------------
**
** Lattice Semiconductor Corporation
** 5555 NE Moore Court
** Hillsboro, OR 97214
** U.S.A
**
** TEL: 1-800-Lattice (USA and Canada)
** (503)268-8001 (other locations)
**
** web: http://www.latticesemi.com
** email: techsupport@latticesemi.com
**
** --------------------------------------------------------------------------
**
** Change History (Latest changes on top)
**
** Ver Date Description
** --------------------------------------------------------------------------
** 3.8 Apr-15-2011 Added __MICO_USER_<handler>_HANDLER__ preprocessor to
** allow customers to implement their own handlers for:
** DATA_ABORT, INST_ABORT
**
** 3.1 Jun-18-2008 Added __MICO_NO_INTERRUPTS__ preprocessor
** option to exclude invoking MicoISRHandler
** to reduce code-size in apps that don't use
** interrupts
**
** 3.0 Mar-25-2008 Added Header
**
**---------------------------------------------------------------------------
*****************************************************************************/
/*
* LatticeMico32 C startup code.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/* From include/sys/signal.h */
#define SIGINT 2 /* interrupt */
#define SIGTRAP 5 /* trace trap */
#define SIGFPE 8 /* arithmetic exception */
#define SIGSEGV 11 /* segmentation violation */
//#define MICO32_FULL_CONTEXT_SAVE_RESTORE
/* Exception handlers - Must be 32 bytes long. */
.section .boot, "ax", @progbits
.global _start
_start:
.global _reset_handler
.type _reset_handler, @function
_reset_handler:
xor r0, r0, r0
wcsr IE, r0
wcsr IM, r0
mvhi r1, hi(_reset_handler)
ori r1, r1, lo(_reset_handler)
wcsr EBA, r1
calli _crt0
nop
.size _reset_handler, .-_reset_handler
.extern _irq_entry
.org 0xc0
.global _interrupt_handler
.type _interrupt_handler, @function
_interrupt_handler:
sw (sp+0), ra
calli _save_all
mvi r1, SIGINT
#ifndef __MICO_NO_INTERRUPTS__
calli _irq_entry
#else
wcsr IE, r0
#endif
bi _restore_all_and_return
nop
nop
nop
.org 0x100
.global _crt0
.type _crt0, @function
_crt0:
/* Clear r0 */
xor r0, r0, r0
/* Setup stack and global pointer */
mvhi sp, hi(_fstack)
ori sp, sp, lo(_fstack)
mvhi r1, hi(_fbss)
ori r1, r1, lo(_fbss)
mvi r2, 0
mvhi r3, hi(_ebss)
ori r3, r3, lo(_ebss)
sub r3, r3, r1
calli memset
mvi r1, 0
mvi r2, 0
mvi r3, 0
calli main
loopf:
bi loopf
.global _save_all
.type _save_all, @function
_save_all:
#ifdef MICO32_FULL_CONTEXT_SAVE_RESTORE
addi sp, sp, -128
#else
addi sp, sp, -60
#endif
sw (sp+4), r1
sw (sp+8), r2
sw (sp+12), r3
sw (sp+16), r4
sw (sp+20), r5
sw (sp+24), r6
sw (sp+28), r7
sw (sp+32), r8
sw (sp+36), r9
sw (sp+40), r10
#ifdef MICO32_FULL_CONTEXT_SAVE_RESTORE
sw (sp+44), r11
sw (sp+48), r12
sw (sp+52), r13
sw (sp+56), r14
sw (sp+60), r15
sw (sp+64), r16
sw (sp+68), r17
sw (sp+72), r18
sw (sp+76), r19
sw (sp+80), r20
sw (sp+84), r21
sw (sp+88), r22
sw (sp+92), r23
sw (sp+96), r24
sw (sp+100), r25
sw (sp+104), r26
sw (sp+108), r27
sw (sp+120), ea
sw (sp+124), ba
/* ra and sp need special handling, as they have been modified */
lw r1, (sp+128)
sw (sp+116), r1
mv r1, sp
addi r1, r1, 128
sw (sp+112), r1
#else
sw (sp+52), ea
sw (sp+56), ba
/* ra and sp need special handling, as they have been modified */
lw r1, (sp+60)
sw (sp+48), r1
mv r1, sp
addi r1, r1, 60
sw (sp+44), r1
#endif
// xor r1, r1, r1
// wcsr ie, r1
ret
.size _save_all, .-_save_all
.global _restore_all_and_return
.type _restore_all_and_return, @function
/* Restore all registers and return from exception */
_restore_all_and_return:
// addi r1, r0, 2
// wcsr ie, r1
lw r1, (sp+4)
lw r2, (sp+8)
lw r3, (sp+12)
lw r4, (sp+16)
lw r5, (sp+20)
lw r6, (sp+24)
lw r7, (sp+28)
lw r8, (sp+32)
lw r9, (sp+36)
lw r10, (sp+40)
#ifdef MICO32_FULL_CONTEXT_SAVE_RESTORE
lw r11, (sp+44)
lw r12, (sp+48)
lw r13, (sp+52)
lw r14, (sp+56)
lw r15, (sp+60)
lw r16, (sp+64)
lw r17, (sp+68)
lw r18, (sp+72)
lw r19, (sp+76)
lw r20, (sp+80)
lw r21, (sp+84)
lw r22, (sp+88)
lw r23, (sp+92)
lw r24, (sp+96)
lw r25, (sp+100)
lw r26, (sp+104)
lw r27, (sp+108)
lw ra, (sp+116)
lw ea, (sp+120)
lw ba, (sp+124)
/* Stack pointer must be restored last, in case it has been updated */
lw sp, (sp+112)
#else
lw ra, (sp+48)
lw ea, (sp+52)
lw ba, (sp+56)
/* Stack pointer must be restored last, in case it has been updated */
lw sp, (sp+44)
#endif
nop
eret
.size _restore_all_and_return, .-_restore_all_and_return
/*
* This work is part of the White Rabbit project
*
* Copyright (C) 2011 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
#include "irq.h"
void disable_irq()
{
unsigned int ie, im;
unsigned int Mask = ~1;
/* disable peripheral interrupts in case they were enabled */
asm volatile ("rcsr %0,ie":"=r" (ie));
ie &= (~0x1);
asm volatile ("wcsr ie, %0"::"r" (ie));
/* disable mask-bit in im */
asm volatile ("rcsr %0, im":"=r" (im));
im &= Mask;
asm volatile ("wcsr im, %0"::"r" (im));
}
void enable_irq()
{
unsigned int ie, im;
unsigned int Mask = 1;
/* disable peripheral interrupts in-case they were enabled */
asm volatile ("rcsr %0,ie":"=r" (ie));
ie &= (~0x1);
asm volatile ("wcsr ie, %0"::"r" (ie));
/* enable mask-bit in im */
asm volatile ("rcsr %0, im":"=r" (im));
im |= Mask;
asm volatile ("wcsr im, %0"::"r" (im));
ie |= 0x1;
asm volatile ("wcsr ie, %0"::"r" (ie));
}
/*
* Link script for Lattice Mico32. Very loosely based on
* code contributed by Jon Beniston <jon@beniston.com>
*
* Jon's license (BSD-style):
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
OUTPUT_FORMAT("elf32-lm32")
ENTRY(_start)
MEMORY
{
ram : ORIGIN = 0x0000, LENGTH = 0x6800
stats : ORIGIN = 0x6800, LENGTH = 0x0800
mbox : ORIGIN = 0x7000, LENGTH = 0x1000
stack : ORIGIN = 0x8000, LENGTH = 0x8000
}
SECTIONS
{
.boot : { *(.boot) } > ram
.text : { *(.text .text.*) } > ram =0
.rodata : { *(.rodata .rodata.*) } > ram
.data : {
*(.data .data.*)
} > ram
.bss : {
_fbss = .;
*(.bss .bss.*)
*(COMMON)
_ebss = .;
} > ram
/*
* Currently (2014-11) the above goes up to around 0x5a00,
* so we can "safely" place statistics at a known address.
* If we need to move them later, we have a magic number
* in there.
*/
.stats : {
*(.stats)
} > stats
/*
* The rt IPC buffer is placed at 0x7000. The value is hardwired
* in the RPC initialization calls (minipc_server_create() and
* wr-switch-sw::wrsw_hal in minipc_client_create()). However,
* we'd better have an ELF section here, so that the compier
* will complain if we overflow the stats structure above.
* We'll be able to move this address ahead when stats move,
* by using the magic in stats (there's no magic in minipc)
*/
.mbox : {
*(.mbox)
} > mbox
/* First location in stack is highest address in RAM (stack area) */
PROVIDE(_fstack = ORIGIN(stack) + LENGTH(stack) - 4);
}
/* We need to provide mprintf to ptp-noposix object files, if missing */
PROVIDE(mprintf = pp_printf);
/*
* Link script for Lattice Mico32. Very loosely based on
* code contributed by Jon Beniston <jon@beniston.com>
*
* Jon's license (BSD-style):
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
OUTPUT_FORMAT("elf32-lm32")
ENTRY(_start)
MEMORY
{
ram :
ORIGIN = 0x00000000,
LENGTH = CONFIG_RAMSIZE - CONFIG_STACKSIZE
stack :
ORIGIN = CONFIG_RAMSIZE - CONFIG_STACKSIZE,
LENGTH = CONFIG_STACKSIZE
}
SECTIONS
{
.boot : { *(.boot) } > ram
.text : { *(.text .text.*) } > ram =0
.rodata : { *(.rodata .rodata.*) } > ram
.data : {
*(.data .data.*)
} > ram
.bss : {
_fbss = .;
*(.bss .bss.*)
*(COMMON)
_ebss = .;
} > ram
/* End of RAM for checking stack overflows */
PROVIDE(_endram = ORIGIN(stack));
/* First location in stack is highest address in STACK */
PROVIDE(_fstack = ORIGIN(stack) + LENGTH(stack) - 4);
}
/* We need to provide mprintf to developers with old habits, if missing */
PROVIDE(mprintf = pp_printf);
/*
* This is used to generate wrc.o from all objects. We need to use
* --gc-sections because sockitowm include a lot of stuff we don't run,
* but at the same time we need to preserve all commands. So use KEEP()
*/
SECTIONS
{
.cmd : {
__cmd_begin = .;
KEEP(*(.cmd))
__cmd_end = .;
}
}
#ifndef __BOARD_H
#define __BOARD_H
#include <hw/memlayout.h>
/* Board-specific parameters */
/* WR Core system/CPU clock frequency in Hz */
#define CPU_CLOCK 62500000ULL
/* WR Reference clock period (picoseconds) and frequency (Hz) */
#define REF_CLOCK_PERIOD_PS 8000
#define REF_CLOCK_FREQ_HZ 125000000
/* Baud rate of the builtin UART (does not apply to the VUART) */
#define UART_BAUDRATE 115200ULL
/* Maximum number of simultaneously created sockets */
#define NET_MAX_SOCKETS 4
/* Socket buffer size, determines the max. RX packet size */
#define NET_SKBUF_SIZE 512
/* Number of auxillary clock channels - usually equal to the number of FMCs */
#define NUM_AUX_CLOCKS 1
int board_init();
int board_update();
#endif
/*
* This file includes stuff we don't want to link, so if it is
* called in error we get a clear error message, rather than a
* "doesn't fit in ram" error
*/
#include <stdio.h>
extern void __you_should_not_call_printf_from_wrpc_sw(void);
extern void __you_should_not_divide_ll_in_wrpc_sw(void);
int printf(const char *fmt, ...)
{
__you_should_not_call_printf_from_wrpc_sw();
return 0;
}
#ifdef CONFIG_PPSI /* with ppsi we can avoid libgcc code for division */
/* was used twice in picos_to_ts */
long long __moddi3 (long long A, long long B)
{
__you_should_not_divide_ll_in_wrpc_sw();
return 0;
}
/* was used in set_phase_shift, phase_to_cf_units */
long long __divdi3 (long long A, long long B)
{
__you_should_not_divide_ll_in_wrpc_sw();
return 0;
}
#endif /* config_ppsi */
#
# Automatically generated make config: don't edit
#
# CONFIG_WR_SWITCH is not set
CONFIG_WR_NODE=y
CONFIG_PRINT_BUFSIZE=128
CONFIG_PRINTF_XINT=y
CONFIG_STACKSIZE=2048
CONFIG_PPSI=y
CONFIG_UART=y
CONFIG_W1=y
CONFIG_ETHERBONE=y
# CONFIG_CMD_CONFIG is not set
#
# wrpc-sw is tainted if you change the following options
#
# CONFIG_DEVELOPER is not set
CONFIG_LEGACY_EEPROM=y
#
# Automatically generated make config: don't edit
#
# CONFIG_WR_SWITCH is not set
CONFIG_WR_NODE=y
CONFIG_PRINT_BUFSIZE=128
CONFIG_PRINTF_XINT=y
CONFIG_RAMSIZE=131072
CONFIG_STACKSIZE=10240
CONFIG_PPSI=y
CONFIG_UART=y
CONFIG_W1=y
CONFIG_ETHERBONE=y
CONFIG_WRNIC=y
CONFIG_CMD_CONFIG=y
CONFIG_NIC_PFILTER=y
#
# wrpc-sw is tainted if you change the following options
#
CONFIG_DEVELOPER=y
# CONFIG_CHECK_RESET is not set
# CONFIG_PRINTF_FULL is not set
# CONFIG_PRINTF_MINI is not set
# CONFIG_PRINTF_NONE is not set
# CONFIG_DETERMINISTIC_BINARY is not set
# CONFIG_UART_SW is not set
CONFIG_SDB_STORAGE=y
# CONFIG_LEGACY_EEPROM is not set
#
# Automatically generated make config: don't edit
#
# CONFIG_WR_SWITCH is not set
CONFIG_WR_NODE=y
CONFIG_PRINT_BUFSIZE=128
CONFIG_PRINTF_XINT=y
CONFIG_STACKSIZE=2048
CONFIG_PPSI=y
CONFIG_UART=y
CONFIG_W1=y
# CONFIG_ETHERBONE is not set
# CONFIG_CMD_CONFIG is not set
#
# wrpc-sw is tainted if you change the following options
#
CONFIG_DEVELOPER=y
# CONFIG_CHECK_RESET is not set
# CONFIG_PRINTF_FULL is not set
# CONFIG_PRINTF_MINI is not set
# CONFIG_PRINTF_NONE is not set
# CONFIG_PTP_NOPOSIX is not set
# CONFIG_DETERMINISTIC_BINARY is not set
# CONFIG_UART_SW is not set
# CONFIG_SDB_STORAGE is not set
CONFIG_LEGACY_EEPROM=y
#
# Automatically generated make config: don't edit
#
# CONFIG_WR_SWITCH is not set
CONFIG_WR_NODE=y
CONFIG_PRINT_BUFSIZE=128
CONFIG_PRINTF_XINT=y
CONFIG_STACKSIZE=2048
CONFIG_PPSI=y
CONFIG_UART=y
CONFIG_W1=y
# CONFIG_ETHERBONE is not set
CONFIG_CMD_CONFIG=y
#
# wrpc-sw is tainted if you change the following options
#
CONFIG_DEVELOPER=y
# CONFIG_CHECK_RESET is not set
# CONFIG_PRINTF_FULL is not set
# CONFIG_PRINTF_MINI is not set
# CONFIG_PRINTF_NONE is not set
# CONFIG_PTP_NOPOSIX is not set
# CONFIG_DETERMINISTIC_BINARY is not set
CONFIG_UART_SW=y
# CONFIG_SDB_STORAGE is not set
CONFIG_LEGACY_EEPROM=y
#
# Automatically generated make config: don't edit
#
# CONFIG_WR_SWITCH is not set
CONFIG_WR_NODE=y
CONFIG_PRINT_BUFSIZE=128
CONFIG_PRINTF_XINT=y
CONFIG_STACKSIZE=2048
CONFIG_PPSI=y
CONFIG_UART=y
CONFIG_W1=y
# CONFIG_ETHERBONE is not set
# CONFIG_CMD_CONFIG is not set
#
# wrpc-sw is tainted if you change the following options
#
# CONFIG_DEVELOPER is not set
CONFIG_LEGACY_EEPROM=y
#
# Automatically generated make config: don't edit
#
CONFIG_WR_SWITCH=y
# CONFIG_WR_NODE is not set
CONFIG_PRINT_BUFSIZE=128
CONFIG_PRINTF_XINT=y
CONFIG_RAMSIZE=65536
CONFIG_UART=y
#
# Automatically generated make config: don't edit
#
# CONFIG_WR_SWITCH is not set
CONFIG_WR_NODE=y
CONFIG_PRINT_BUFSIZE=128
CONFIG_PRINTF_XINT=y
CONFIG_STACKSIZE=2048
CONFIG_PPSI=y
CONFIG_UART=y
CONFIG_W1=y
CONFIG_ETHERBONE=y
CONFIG_NIC_PFILTER=y
# CONFIG_CMD_CONFIG is not set
#
# wrpc-sw is tainted if you change the following options
#
# CONFIG_DEVELOPER is not set
CONFIG_LEGACY_EEPROM=y
/*
* Trivial pll programmer using an spi controoler.
* PLL is AD9516, SPI is opencores
* Tomasz Wlostowski, Alessandro Rubini, 2011, for CERN.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <wrc.h>
#include "board.h"
#include "syscon.h"
#include "gpio-wrs.h"
#include "rt_ipc.h"
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
#endif
static inline void writel(uint32_t data, void *where)
{
* (volatile uint32_t *)where = data;
}
static inline uint32_t readl(void *where)
{
return * (volatile uint32_t *)where;
}
struct ad9516_reg {
uint16_t reg;
uint8_t val;
};
#include "ad9516_config.h"
/*
* SPI stuff, used by later code
*/
#define SPI_REG_RX0 0
#define SPI_REG_TX0 0
#define SPI_REG_RX1 4
#define SPI_REG_TX1 4
#define SPI_REG_RX2 8
#define SPI_REG_TX2 8
#define SPI_REG_RX3 12
#define SPI_REG_TX3 12
#define SPI_REG_CTRL 16
#define SPI_REG_DIVIDER 20
#define SPI_REG_SS 24
#define SPI_CTRL_ASS (1<<13)
#define SPI_CTRL_IE (1<<12)
#define SPI_CTRL_LSB (1<<11)
#define SPI_CTRL_TXNEG (1<<10)
#define SPI_CTRL_RXNEG (1<<9)
#define SPI_CTRL_GO_BSY (1<<8)
#define SPI_CTRL_CHAR_LEN(x) ((x) & 0x7f)
#define GPIO_PLL_RESET_N 1
#define GPIO_SYS_CLK_SEL 0
#define GPIO_PERIPH_RESET_N 3
#define CS_PLL 0 /* AD9516 on SPI CS0 */
static void *oc_spi_base;
int oc_spi_init(void *base_addr)
{
oc_spi_base = base_addr;
writel(100, oc_spi_base + SPI_REG_DIVIDER);
return 0;
}
int oc_spi_txrx(int ss, int nbits, uint32_t in, uint32_t *out)
{
uint32_t rval;
if (!out)
out = &rval;
writel(SPI_CTRL_ASS | SPI_CTRL_CHAR_LEN(nbits)
| SPI_CTRL_TXNEG,
oc_spi_base + SPI_REG_CTRL);
writel(in, oc_spi_base + SPI_REG_TX0);
writel((1 << ss), oc_spi_base + SPI_REG_SS);
writel(SPI_CTRL_ASS | SPI_CTRL_CHAR_LEN(nbits)
| SPI_CTRL_TXNEG | SPI_CTRL_GO_BSY,
oc_spi_base + SPI_REG_CTRL);
while(readl(oc_spi_base + SPI_REG_CTRL) & SPI_CTRL_GO_BSY)
;
*out = readl(oc_spi_base + SPI_REG_RX0);
return 0;
}
/*
* AD9516 stuff, using SPI, used by later code.
* "reg" is 12 bits, "val" is 8 bits, but both are better used as int
*/
static void ad9516_write_reg(int reg, int val)
{
oc_spi_txrx(CS_PLL, 24, (reg << 8) | val, NULL);
}
static int ad9516_read_reg(int reg)
{
uint32_t rval;
oc_spi_txrx(CS_PLL, 24, (reg << 8) | (1 << 23), &rval);
return rval & 0xff;
}
static void ad9516_load_regset(const struct ad9516_reg *regs, int n_regs, int commit)
{
int i;
for(i=0; i<n_regs; i++)
ad9516_write_reg(regs[i].reg, regs[i].val);
if(commit)
ad9516_write_reg(0x232, 1);
}
static void ad9516_wait_lock()
{
while ((ad9516_read_reg(0x1f) & 1) == 0);
}
#define SECONDARY_DIVIDER 0x100
int ad9516_set_output_divider(int output, int ratio, int phase_offset)
{
uint8_t lcycles = (ratio/2) - 1;
uint8_t hcycles = (ratio - (ratio / 2)) - 1;
int secondary = (output & SECONDARY_DIVIDER) ? 1 : 0;
output &= 0xf;
if(output >= 0 && output < 6) /* LVPECL outputs */
{
uint16_t base = (output / 2) * 0x3 + 0x190;
if(ratio == 1) /* bypass the divider */
{
uint8_t div_ctl = ad9516_read_reg(base + 1);
ad9516_write_reg(base + 1, div_ctl | (1<<7) | (phase_offset & 0xf));
} else {
uint8_t div_ctl = ad9516_read_reg(base + 1);
ad9516_write_reg(base + 1, (div_ctl & (~(1<<7))) | (phase_offset & 0xf)); /* disable bypass bit */
ad9516_write_reg(base, (lcycles << 4) | hcycles);
}
} else { /* LVDS/CMOS outputs */
uint16_t base = ((output - 6) / 2) * 0x5 + 0x199;
TRACE("Output [divider %d]: %d ratio: %d base %x lc %d hc %d\n", secondary, output, ratio, base, lcycles ,hcycles);
if(!secondary)
{
if(ratio == 1) /* bypass the divider 1 */
ad9516_write_reg(base + 3, ad9516_read_reg(base + 3) | 0x10);
else {
ad9516_write_reg(base, (lcycles << 4) | hcycles);
ad9516_write_reg(base + 1, phase_offset & 0xf);
}
} else {
if(ratio == 1) /* bypass the divider 2 */
ad9516_write_reg(base + 3, ad9516_read_reg(base + 3) | 0x20);
else {
ad9516_write_reg(base + 2, (lcycles << 4) | hcycles);
// ad9516_write_reg(base + 1, phase_offset & 0xf);
}
}
}
/* update */
ad9516_write_reg(0x232, 0x0);
ad9516_write_reg(0x232, 0x1);
ad9516_write_reg(0x232, 0x0);
return 0;
}
int ad9516_set_vco_divider(int ratio) /* Sets the VCO divider (2..6) or 0 to enable static output */
{
if(ratio == 0)
ad9516_write_reg(0x1e0, 0x5); /* static mode */
else
ad9516_write_reg(0x1e0, (ratio-2));
ad9516_write_reg(0x232, 0x1);
return 0;
}
void ad9516_sync_outputs()
{
/* VCO divider: static mode */
ad9516_write_reg(0x1E0, 0x7);
ad9516_write_reg(0x232, 0x1);
/* Sync the outputs when they're inactive to avoid +-1 cycle uncertainity */
ad9516_write_reg(0x230, 1);
ad9516_write_reg(0x232, 1);
ad9516_write_reg(0x230, 0);
ad9516_write_reg(0x232, 1);
}
int ad9516_init(int scb_version)
{
TRACE("Initializing AD9516 PLL...\n");
oc_spi_init((void *)BASE_SPI);
gpio_out(GPIO_SYS_CLK_SEL, 0); /* switch to the standby reference clock, since the PLL is off after reset */
/* reset the PLL */
gpio_out(GPIO_PLL_RESET_N, 0);
timer_delay(10);
gpio_out(GPIO_PLL_RESET_N, 1);
timer_delay(10);
/* Use unidirectional SPI mode */
ad9516_write_reg(0x000, 0x99);
/* Check the presence of the chip */
if (ad9516_read_reg(0x3) != 0xc3) {
TRACE("Error: AD9516 PLL not responding.\n");
return -1;
}
if( scb_version >= 34) //New SCB v3.4. 10MHz Output.
ad9516_load_regset(ad9516_base_config_34, ARRAY_SIZE(ad9516_base_config_34), 0);
else //Old one
ad9516_load_regset(ad9516_base_config_33, ARRAY_SIZE(ad9516_base_config_33), 0);
ad9516_load_regset(ad9516_ref_tcxo, ARRAY_SIZE(ad9516_ref_tcxo), 1);
ad9516_wait_lock();
ad9516_sync_outputs();
if( scb_version >= 34) { //New SCB v3.4. 10MHz Output.
ad9516_set_output_divider(2, 4, 0); // OUT2. 187.5 MHz. - not anymore
ad9516_set_output_divider(3, 4, 0); // OUT3. 187.5 MHz. - not anymore
ad9516_set_output_divider(4, 1, 0); // OUT4. 500 MHz.
/*The following PLL outputs have been configured through the ad9516_base_config_34 register,
* so it doesn't need to replicate the configuration:
*
* Output 6 => 62.5 MHz
* Output 7 => 62.5 MHz
* Output 8 => 10 MHz
* Output 9 => 10 MHz
*/
ad9516_write_reg(0x143, 0x1); //Temporary Powerdown 10MHz output
} else { //Old one
ad9516_set_output_divider(9, 4, 0); /* AUX/SWCore = 187.5 MHz */ //not needed anymore
ad9516_set_output_divider(7, 8, 0); /* REF = 62.5 MHz */
ad9516_set_output_divider(4, 8, 0); /* GTX = 62.5 MHz */
}
ad9516_sync_outputs();
ad9516_set_vco_divider(3);
TRACE("AD9516 locked.\n");
gpio_out(GPIO_SYS_CLK_SEL, 1); /* switch the system clock to the PLL reference */
gpio_out(GPIO_PERIPH_RESET_N, 0); /* reset all peripherals which use AD9516-provided clocks */
gpio_out(GPIO_PERIPH_RESET_N, 1);
return 0;
}
int rts_debug_command(int command, int value)
{
switch(command)
{
case RTS_DEBUG_ENABLE_SERDES_CLOCKS:
if(value)
{
ad9516_write_reg(0xf4, 0x08); // OUT4 enabled
ad9516_write_reg(0x232, 0x0);
ad9516_write_reg(0x232, 0x1);
} else {
ad9516_write_reg(0xf4, 0x0a); // OUT4 power-down, no serdes clock
ad9516_write_reg(0x232, 0x0);
ad9516_write_reg(0x232, 0x1);
}
break;
}
return 0;
}
/* Base configuration for the SCB version lower than 3.4 (global dividers, output config, reference-independent) */
const struct ad9516_reg ad9516_base_config_33[] = {
{0x0000, 0x99},
{0x0001, 0x00},
{0x0002, 0x10},
{0x0003, 0xC3},
{0x0004, 0x00},
{0x0010, 0x7C},
{0x0011, 0x05},
{0x0012, 0x00},
{0x0013, 0x0C},
{0x0014, 0x12},
{0x0015, 0x00},
{0x0016, 0x05},
{0x0017, 0x88},
{0x0018, 0x07},
{0x0019, 0x00},
{0x001A, 0x00},
{0x001B, 0x00},
{0x001C, 0x02},
{0x001D, 0x00},
{0x001E, 0x00},
{0x001F, 0x0E},
{0x00A0, 0x01},
{0x00A1, 0x00},
{0x00A2, 0x00},
{0x00A3, 0x01},
{0x00A4, 0x00},
{0x00A5, 0x00},
{0x00A6, 0x01},
{0x00A7, 0x00},
{0x00A8, 0x00},
{0x00A9, 0x01},
{0x00AA, 0x00},
{0x00AB, 0x00},
{0x00F0, 0x0A},
{0x00F1, 0x0A},
{0x00F2, 0x0A},
{0x00F3, 0x0A},
{0x00F4, 0x08},
{0x00F5, 0x08},
{0x0140, 0x43},
{0x0141, 0x42},
{0x0142, 0x43},
{0x0143, 0x42},
{0x0190, 0x00},
{0x0191, 0x80},
{0x0192, 0x00},
{0x0193, 0xBB},
{0x0194, 0x00},
{0x0195, 0x00},
{0x0196, 0x00},
{0x0197, 0x00},
{0x0198, 0x00},
{0x0199, 0x11},
{0x019A, 0x00},
{0x019B, 0x11},
{0x019C, 0x20},
{0x019D, 0x00},
{0x019E, 0x11},
{0x019F, 0x00},
{0x01A0, 0x11},
{0x01A1, 0x20},
{0x01A2, 0x00},
{0x01A3, 0x00},
{0x01E0, 0x04},
{0x01E1, 0x02},
{0x0230, 0x00},
{0x0231, 0x00},
};
/* Configuration for the SCB version greater than or equal 3.4: Base + 6, 7, 8, 9 outputs*/
const struct ad9516_reg ad9516_base_config_34[] = {
{0x0000, 0x99},
{0x0001, 0x00},
{0x0002, 0x10},
{0x0003, 0xC3},
{0x0004, 0x00},
{0x0010, 0x7C},
{0x0011, 0x05},
{0x0012, 0x00},
{0x0013, 0x0C},
{0x0014, 0x12},
{0x0015, 0x00},
{0x0016, 0x05},
{0x0017, 0x88},
{0x0018, 0x07},
{0x0019, 0x00},
{0x001A, 0x00},
{0x001B, 0x00},
{0x001C, 0x02},
{0x001D, 0x00},
{0x001E, 0x00},
{0x001F, 0x0E},
{0x00A0, 0x01},
{0x00A1, 0x00},
{0x00A2, 0x00},
{0x00A3, 0x01},
{0x00A4, 0x00},
{0x00A5, 0x00},
{0x00A6, 0x01},
{0x00A7, 0x00},
{0x00A8, 0x00},
{0x00A9, 0x01},
{0x00AA, 0x00},
{0x00AB, 0x00},
{0x00F0, 0x0A},
{0x00F1, 0x0A},
{0x00F2, 0x0A},
{0x00F3, 0x0A},
{0x00F4, 0x08},
{0x00F5, 0x08},
// The following registers configure the PLL outputs from 6 to 9.
{0x0140, 0x42},
{0x0141, 0x42},
{0x0142, 0x43},
{0x0143, 0x4E},
{0x0190, 0x55},
{0x0191, 0x00},
{0x0192, 0x00},
{0x0193, 0x11},
{0x0194, 0x00},
{0x0195, 0x00},
{0x0196, 0x10},
{0x0197, 0x00},
{0x0198, 0x00},
{0x0199, 0x33},
{0x019A, 0x00},
{0x019B, 0x11},
{0x019C, 0x20},
{0x019D, 0x00},
{0x019E, 0x10},
{0x019F, 0x00},
{0x01A0, 0xCB},
{0x01A1, 0x00},
{0x01A2, 0x00},
{0x01A3, 0x00},
//
{0x01E0, 0x04},
{0x01E1, 0x02},
{0x0230, 0x00},
{0x0231, 0x00},
};
/* Config for 25 MHz VCTCXO reference (RDiv = 5, use REF1) */
const struct ad9516_reg ad9516_ref_tcxo[] = {
{0x0011, 0x05},
{0x0012, 0x00}, /* RDiv = 5 */
{0x001C, 0x06} /* Use REF1 */
};
/* Config for 10 MHz external reference (RDiv = 2, use REF2) */
const struct ad9516_reg ad9516_ref_ext[] = {
{0x0011, 0x02},
{0x0012, 0x00}, /* RDiv = 2 */
{0x001C, 0x46} /* Use REF1 */
};
const struct {int reg; uint8_t val} ad9516_regs[] = {
{0x0000, 0x99},
{0x0001, 0x00},
{0x0002, 0x10},
{0x0003, 0xC3},
{0x0004, 0x00},
{0x0010, 0x7C},
{0x0011, 0x01},
{0x0012, 0x00},
{0x0013, 0x04},
{0x0014, 0x07},
{0x0015, 0x00},
{0x0016, 0x04},
{0x0017, 0x00},
{0x0018, 0x07},
{0x0019, 0x00},
{0x001A, 0x00},
{0x001B, 0x00},
{0x001C, 0x46},
{0x001D, 0x00},
{0x001E, 0x00},
{0x001F, 0x0E},
{0x00A0, 0x01},
{0x00A1, 0x00},
{0x00A2, 0x00},
{0x00A3, 0x01},
{0x00A4, 0x00},
{0x00A5, 0x00},
{0x00A6, 0x01},
{0x00A7, 0x00},
{0x00A8, 0x00},
{0x00A9, 0x01},
{0x00AA, 0x00},
{0x00AB, 0x00},
{0x00F0, 0x0A},
{0x00F1, 0x0A},
{0x00F2, 0x0A},
{0x00F3, 0x0A},
{0x00F4, 0x08},
{0x00F5, 0x0A},
{0x0140, 0x43},
{0x0141, 0x43},
{0x0142, 0x43},
{0x0143, 0x43},
{0x0190, 0x00},
{0x0191, 0x80},
{0x0192, 0x00},
{0x0193, 0xBB},
{0x0194, 0x00},
{0x0195, 0x00},
{0x0196, 0x00},
{0x0197, 0x00},
{0x0198, 0x00},
{0x0199, 0x22},
{0x019A, 0x00},
{0x019B, 0x11},
{0x019C, 0x00},
{0x019D, 0x00},
{0x019E, 0x22},
{0x019F, 0x00},
{0x01A0, 0x11},
{0x01A1, 0x00},
{0x01A2, 0x00},
{0x01A3, 0x00},
{0x01E0, 0x04},
{0x01E1, 0x02},
{0x0230, 0x00},
{0x0231, 0x00},
{0x0232, 0x00},
{-1, 0}};
obj-$(CONFIG_WR_NODE) += \
dev/endpoint.o \
dev/ep_pfilter.o \
dev/i2c.o \
dev/minic.o \
dev/pps_gen.o \
dev/syscon.o \
dev/sfp.o \
dev/devicelist.o \
dev/rxts_calibrator.o \
dev/flash.o
obj-$(CONFIG_WR_SWITCH) += dev/timer-wrs.o dev/ad9516.o
obj-$(CONFIG_LEGACY_EEPROM) += dev/eeprom.o
obj-$(CONFIG_SDB_STORAGE) += dev/sdb-storage.o
obj-$(CONFIG_W1) += dev/w1.o dev/w1-hw.o dev/w1-shell.o
obj-$(CONFIG_W1) += dev/w1-temp.o dev/w1-eeprom.o
obj-$(CONFIG_UART) += dev/uart.o
obj-$(CONFIG_UART_SW) += dev/uart-sw.o
/*
* This work is part of the White Rabbit project
*
* Copyright (C) 2014 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
#include <wrc.h>
#define SDBFS_BIG_ENDIAN
#include <libsdbfs.h>
/* The following pointers are exported */
unsigned char *BASE_MINIC;
unsigned char *BASE_EP;
unsigned char *BASE_SOFTPLL;
unsigned char *BASE_PPS_GEN;
unsigned char *BASE_SYSCON;
unsigned char *BASE_UART;
unsigned char *BASE_ONEWIRE;
unsigned char *BASE_ETHERBONE_CFG;
/* The sdb filesystem itself */
static struct sdbfs wrc_fpga_sdb = {
.name = "fpga-area",
.blocksize = 1, /* Not currently used */
.entrypoint = SDB_ADDRESS,
.data = 0,
.flags = SDBFS_F_ZEROBASED,
};
/* called by outside, at boot time */
void sdb_print_devices(void)
{
struct sdb_device *d;
int new = 1;
while ( (d = sdbfs_scan(&wrc_fpga_sdb, new)) != NULL) {
/*
* "%.19s" is not working for XINT printf, and zeroing
* d->sdb_component.product.record_type won't work, as
* the device is read straight from fpga ROM registers
*/
const int namesize = sizeof(d->sdb_component.product.name);
char name[namesize + 1];
memcpy(name, d->sdb_component.product.name, sizeof(name));
name[namesize] = '\0';
pp_printf("dev 0x%08lx @ %06lx, %s\n",
(long)(d->sdb_component.product.device_id),
wrc_fpga_sdb.f_offset, name);
new = 0;
}
}
/* To save a little size, we enumerate our vendors */
#define VID_CERN 0x0000ce42LL
#define VID_GSI 0x00000651LL
struct wrc_device {
unsigned char **base;
uint64_t vid;
uint32_t did;
};
struct wrc_device devs[] = {
{&BASE_MINIC, VID_CERN, 0xab28633a},
{&BASE_EP, VID_CERN, 0x650c2d4f},
{&BASE_SOFTPLL, VID_CERN, 0x65158dc0},
{&BASE_PPS_GEN, VID_CERN, 0xde0d8ced},
{&BASE_SYSCON, VID_CERN, 0xff07fc47},
{&BASE_UART, VID_CERN, 0xe2d13d04},
{&BASE_ONEWIRE, VID_CERN, 0x779c5443},
{&BASE_ETHERBONE_CFG, VID_GSI, 0x68202b22},
};
void sdb_find_devices(void)
{
struct wrc_device *d;
static int done;
int i;
if (!done) {
sdbfs_dev_create(&wrc_fpga_sdb);
done++;
}
for (d = devs, i = 0; i < ARRAY_SIZE(devs); d++, i++) {
*(d->base) = (void *)sdbfs_find_id(&wrc_fpga_sdb,
d->vid, d->did);
}
}
This diff is collapsed.
/*
WR Endpoint (WR-compatible Ethernet MAC driver
Tomasz Wlostowski/CERN 2011
LGPL 2.1
*/
#include <stdio.h>
#include <wrc.h>
#include "board.h"
#include "syscon.h"
#include <endpoint.h>
#include "storage.h"
#include <hw/endpoint_regs.h>
#include <hw/endpoint_mdio.h>
/* 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
/* 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
static int autoneg_enabled;
volatile struct EP_WB *EP;
/* functions for accessing PCS (MDIO) registers */
static uint16_t pcs_read(int location)
{
EP->MDIO_CR = EP_MDIO_CR_ADDR_W(location >> 2);
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)
{
EP->MDIO_CR = EP_MDIO_CR_ADDR_W(location >> 2)
| EP_MDIO_CR_DATA_W(value)
| EP_MDIO_CR_RW;
while ((EP->MDIO_ASR & EP_MDIO_ASR_READY) == 0) ;
}
/* MAC address setting */
void set_mac_addr(uint8_t dev_addr[])
{
EP->MACL = ((uint32_t) dev_addr[2] << 24)
| ((uint32_t) dev_addr[3] << 16)
| ((uint32_t) dev_addr[4] << 8)
| ((uint32_t) dev_addr[5]);
EP->MACH = ((uint32_t) dev_addr[0] << 8)
| ((uint32_t) dev_addr[1]);
}
void get_mac_addr(uint8_t dev_addr[])
{
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[])
{
EP = (volatile struct EP_WB *)BASE_EP;
set_mac_addr(mac_addr);
*(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);
}
/* 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;
if (!enabled) {
EP->ECR = 0;
return 0;
}
/* Disable the endpoint */
EP->ECR = 0;
mprintf("ID: %x\n", 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;
/* 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_ms(200);
pcs_write(MDIO_REG_MCR, MDIO_MCR_RESET); /* reset the PHY */
pcs_write(MDIO_REG_MCR, 0); /* reset the PHY */
/* 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;
}
/* 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;
if (autoneg_enabled)
flags |= MDIO_MSR_ANEGCOMPLETE;
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;
}
int ep_get_bitslide()
{
return PICOS_PER_SERIAL_BIT *
MDIO_WR_SPEC_BSLIDE_R(pcs_read(MDIO_REG_WR_SPEC));
}
/* 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)
{
/* 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 = sfp_deltaTx;
*delta_rx =
sfp_deltaRx +
PICOS_PER_SERIAL_BIT *
MDIO_WR_SPEC_BSLIDE_R(pcs_read(MDIO_REG_WR_SPEC));
return 0;
}
int ep_cal_pattern_enable()
{
uint32_t val;
val = pcs_read(MDIO_REG_WR_SPEC);
val |= MDIO_WR_SPEC_TX_CAL;
pcs_write(MDIO_REG_WR_SPEC, val);
return 0;
}
int ep_cal_pattern_disable()
{
uint32_t val;
val = pcs_read(MDIO_REG_WR_SPEC);
val &= (~MDIO_WR_SPEC_TX_CAL);
pcs_write(MDIO_REG_WR_SPEC, val);
return 0;
}
int ep_timestamper_cal_pulse()
{
EP->TSCR |= EP_TSCR_RX_CAL_START;
timer_delay_ms(1);
return EP->TSCR & EP_TSCR_RX_CAL_RESULT ? 1 : 0;
}
This diff is collapsed.
/*
* This work is part of the White Rabbit project
*
* Copyright (C) 2013 CERN (www.cern.ch)
* Author: Theodor Stana <t.stana@cern.ch>
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*/
#include <wrc.h>
#include <flash.h>
#include <types.h>
#define SDBFS_BIG_ENDIAN
#include <libsdbfs.h>
/*
* Delay function - limit SPI clock speed to 10 MHz
*/
static void delay()
{
int i;
for (i = 0; i < (int)(CPU_CLOCK/10000000); i++)
asm volatile ("nop");
}
/*
* Bit-bang SPI transfer function
*/
static uint8_t bbspi_transfer(int cspin, uint8_t val)
{
int i;
gpio_out(GPIO_SPI_NCS, cspin);
delay();
for (i = 0; i < 8; i++) {
gpio_out(GPIO_SPI_SCLK, 0);
if (val & 0x80) {
gpio_out(GPIO_SPI_MOSI, 1);
} else {
gpio_out(GPIO_SPI_MOSI, 0);
}
delay();
gpio_out(GPIO_SPI_SCLK, 1);
val <<= 1;
val |= gpio_in(GPIO_SPI_MISO);
delay();
}
gpio_out(GPIO_SPI_SCLK, 0);
return val;
}
/*
* Init function (just set the SPI pins for idle)
*/
void flash_init()
{
gpio_out(GPIO_SPI_NCS, 1);
gpio_out(GPIO_SPI_SCLK, 0);
gpio_out(GPIO_SPI_MOSI, 0);
}
/*
* Write data to flash chip
*/
int flash_write(uint32_t addr, uint8_t *buf, int count)
{
int i;
bbspi_transfer(1,0);
bbspi_transfer(0,0x06);
bbspi_transfer(1,0);
bbspi_transfer(0,0x02);
bbspi_transfer(0,(addr & 0xFF0000) >> 16);
bbspi_transfer(0,(addr & 0xFF00) >> 8);
bbspi_transfer(0,(addr & 0xFF));
for ( i = 0; i < count; i++ ) {
bbspi_transfer(0,buf[i]);
}
bbspi_transfer(1,0);
return count;
}
/*
* Read data from flash
*/
int flash_read(uint32_t addr, uint8_t *buf, int count)
{
int i;
bbspi_transfer(1,0);
bbspi_transfer(0,0x0b);
bbspi_transfer(0,(addr & 0xFF0000) >> 16);
bbspi_transfer(0,(addr & 0xFF00) >> 8);
bbspi_transfer(0,(addr & 0xFF));
bbspi_transfer(0,0);
for ( i = 0; i < count; i++ ) {
buf[i] = bbspi_transfer(0, 0);
}
bbspi_transfer(1,0);
return count;
}
int flash_erase(uint32_t addr, int count)
{
int i;
int sectors;
/*calc number of sectors to be removed*/
if(count % FLASH_BLOCKSIZE > 0)
sectors = 1;
else
sectors = 0;
sectors += (count / FLASH_BLOCKSIZE);
for(i=0; i<sectors; ++i) {
flash_serase(addr + i*FLASH_BLOCKSIZE);
while(flash_rsr() & 0x01);
}
return count;
}
/*
* Sector erase
*/
void flash_serase(uint32_t addr)
{
bbspi_transfer(1,0);
bbspi_transfer(0,0x06);
bbspi_transfer(1,0);
bbspi_transfer(0,0xD8);
bbspi_transfer(0,(addr & 0xFF0000) >> 16);
bbspi_transfer(0,(addr & 0xFF00) >> 8);
bbspi_transfer(0,(addr & 0xFF));
bbspi_transfer(1,0);
}
/*
* Bulk erase
*/
void
flash_berase()
{
bbspi_transfer(1,0);
bbspi_transfer(0,0x06);
bbspi_transfer(1,0);
bbspi_transfer(0,0xc7);
bbspi_transfer(1,0);
}
/*
* Read status register
*/
uint8_t flash_rsr()
{
uint8_t retval;
bbspi_transfer(1,0);
bbspi_transfer(0,0x05);
retval = bbspi_transfer(0,0);
bbspi_transfer(1,0);
return retval;
}
/*****************************************************************************/
/* SDB */
/*****************************************************************************/
/* The sdb filesystem itself */
static struct sdbfs wrc_sdb = {
.name = "wrpc-storage",
.blocksize = 1, /* Not currently used */
/* .read and .write according to device type */
};
/*
* SDB read and write functions
*/
static int sdb_flash_read(struct sdbfs *fs, int offset, void *buf, int count)
{
return flash_read(offset, buf, count);
}
static int sdb_flash_write(struct sdbfs *fs, int offset, void *buf, int count)
{
return flash_write(offset, buf, count);
}
/*
* A trivial dumper, just to show what's up in there
*/
static void flash_sdb_list(struct sdbfs *fs)
{
struct sdb_device *d;
int new = 1;
while ( (d = sdbfs_scan(fs, new)) != NULL) {
d->sdb_component.product.record_type = '\0';
pp_printf("file 0x%08x @ %4i, name %19s\n",
(int)(d->sdb_component.product.device_id),
(int)(d->sdb_component.addr_first),
(char *)(d->sdb_component.product.name));
new = 0;
}
}
/*
* Check for SDB presence on flash
*/
int flash_sdb_check()
{
uint32_t magic = 0;
int i;
uint32_t entry_point[] = {
0x000000, // flash base
0x100, // second page in flash
0x200, // IPMI with MultiRecord
0x300, // IPMI with larger MultiRecord
0x170000, // after first FPGA bitstream
0x2e0000 // after MultiBoot bitstream
};
for (i = 0; i < ARRAY_SIZE(entry_point); i++) {
flash_read(entry_point[i], (uint8_t *)&magic, 4);
if (magic == SDB_MAGIC)
break;
}
if (i == ARRAY_SIZE(entry_point))
return -1;
pp_printf("Found SDB magic at address 0x%06x\n", entry_point[i]);
wrc_sdb.drvdata = NULL;
wrc_sdb.entrypoint = entry_point[i];
wrc_sdb.read = sdb_flash_read;
wrc_sdb.write = sdb_flash_write;
flash_sdb_list(&wrc_sdb);
return 0;
}
/*
* This work is part of the White Rabbit project
*
* Copyright (C) 2011,2012 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Grzegorz Daniluk <grzegorz.daniluk@cern.ch>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
#include "types.h"
#include "board.h"
#include "syscon.h"
#define I2C_DELAY 300
void mi2c_delay()
{
int i;
for (i = 0; i < I2C_DELAY; i++)
asm volatile ("nop");
}
#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(uint8_t i2cif)
{
M_SDA_OUT(i2cif, 0);
M_SCL_OUT(i2cif, 0);
}
void mi2c_repeat_start(uint8_t i2cif)
{
M_SDA_OUT(i2cif, 1);
M_SCL_OUT(i2cif, 1);
M_SDA_OUT(i2cif, 0);
M_SCL_OUT(i2cif, 0);
}
void mi2c_stop(uint8_t i2cif)
{
M_SDA_OUT(i2cif, 0);
M_SCL_OUT(i2cif, 1);
M_SDA_OUT(i2cif, 1);
}
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(i2cif, data & 0x80);
M_SCL_OUT(i2cif, 1);
M_SCL_OUT(i2cif, 0);
}
M_SDA_OUT(i2cif, 1);
M_SCL_OUT(i2cif, 1);
ack = M_SDA_IN(i2cif); /* ack: sda is pulled low ->success. */
M_SCL_OUT(i2cif, 0);
M_SDA_OUT(i2cif, 0);
return ack != 0;
}
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(i2cif, 0);
for (i = 0; i < 8; i++) {
M_SCL_OUT(i2cif, 1);
indata <<= 1;
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);
}
*data = indata;
}
void mi2c_init(uint8_t i2cif)
{
M_SCL_OUT(i2cif, 1);
M_SDA_OUT(i2cif, 1);
}
uint8_t mi2c_devprobe(uint8_t i2cif, uint8_t i2c_addr)
{
uint8_t ret;
mi2c_start(i2cif);
ret = !mi2c_put_byte(i2cif, i2c_addr << 1);
mi2c_stop(i2cif);
return ret;
}
//void mi2c_scan(uint8_t i2cif)
//{
// int i;
//
// //for(i=0;i<0x80;i++)
// for(i=0x50;i<0x51;i++)
// {
// mi2c_start(i2cif);
// if(!mi2c_put_byte(i2cif, i<<1)) mprintf("found : %x\n", i);
// mi2c_stop(i2cif);
//
// }
// mprintf("Nothing more found...\n");
//}
This diff is collapsed.
/*
* This work is part of the White Rabbit project
*
* Copyright (C) 2012 CERN (www.cern.ch)
* Copyright (C) 2012 GSI (www.gsi.de)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Wesley W. Terpstra <w.terpstra@gsi.de>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
#include <wrc.h>
#include "board.h"
#include "pps_gen.h"
#include "hw/pps_gen_regs.h"
/* PPS Generator driver */
/* Warning: references to "UTC" in the registers DO NOT MEAN actual UTC time, it's just a plain second counter
It doesn't care about leap seconds. */
#define ppsg_write(reg, val) \
*(volatile uint32_t *) (BASE_PPS_GEN + (offsetof(struct PPSG_WB, reg))) = (val)
#define ppsg_read(reg) \
*(volatile uint32_t *) (BASE_PPS_GEN + (offsetof(struct PPSG_WB, reg)))
void shw_pps_gen_init()
{
uint32_t cr;
cr = PPSG_CR_CNT_EN | PPSG_CR_PWIDTH_W(PPS_WIDTH);
ppsg_write(CR, cr);
ppsg_write(ADJ_UTCLO, 0);
ppsg_write(ADJ_UTCHI, 0);
ppsg_write(ADJ_NSEC, 0);
ppsg_write(CR, cr | PPSG_CR_CNT_SET);
ppsg_write(CR, cr);
ppsg_write(ESCR, 0); /* disable PPS output */
}
/* Adjusts the nanosecond (refclk cycle) counter by atomically adding (how_much) cycles. */
int shw_pps_gen_adjust(int counter, int64_t how_much)
{
TRACE_DEV("Adjust: counter = %s [%c%d]\n",
counter == PPSG_ADJUST_SEC ? "seconds" : "nanoseconds",
how_much < 0 ? '-' : '+', (int32_t) abs(how_much));
if (counter == PPSG_ADJUST_NSEC) {
ppsg_write(ADJ_UTCLO, 0);
ppsg_write(ADJ_UTCHI, 0);
ppsg_write(ADJ_NSEC,
(int32_t) ((int64_t) how_much * 1000LL /
(int64_t) REF_CLOCK_PERIOD_PS));
} else {
ppsg_write(ADJ_UTCLO, (uint32_t) (how_much & 0xffffffffLL));
ppsg_write(ADJ_UTCHI, (uint32_t) (how_much >> 32) & 0xff);
ppsg_write(ADJ_NSEC, 0);
}
ppsg_write(CR, ppsg_read(CR) | PPSG_CR_CNT_ADJ);
return 0;
}
/* Sets the current time */
void shw_pps_gen_set_time(uint64_t seconds, uint32_t nanoseconds, int counter)
{
ppsg_write(ADJ_UTCLO, (uint32_t) (seconds & 0xffffffffLL));
ppsg_write(ADJ_UTCHI, (uint32_t) (seconds >> 32) & 0xff);
ppsg_write(ADJ_NSEC,
(int32_t) ((int64_t) nanoseconds * 1000LL /
(int64_t) REF_CLOCK_PERIOD_PS));
if (counter == PPSG_SET_ALL)
ppsg_write(CR, (ppsg_read(CR) & 0xfffffffb) | PPSG_CR_CNT_SET);
else if (counter == PPSG_SET_SEC)
ppsg_write(ESCR, (ppsg_read(ESCR) & 0xffffffe7) | PPSG_ESCR_SEC_SET);
else if (counter == PPSG_SET_NSEC)
ppsg_write(ESCR, (ppsg_read(ESCR) & 0xffffffe7) | PPSG_ESCR_NSEC_SET);
}
uint64_t pps_get_utc(void)
{
uint64_t out;
uint32_t low, high;
low = ppsg_read(CNTR_UTCLO);
high = ppsg_read(CNTR_UTCHI);
high &= 0xFF; /* CNTR_UTCHI has only 8 bits defined -- rest are HDL don't care */
out = (uint64_t) low | (uint64_t) high << 32;
return out;
}
void shw_pps_gen_get_time(uint64_t * seconds, uint32_t * nanoseconds)
{
uint32_t ns_cnt;
uint64_t sec1, sec2;
do {
sec1 = pps_get_utc();
ns_cnt = ppsg_read(CNTR_NSEC) & 0xFFFFFFFUL; /* 28-bit wide register */
sec2 = pps_get_utc();
} while (sec2 != sec1);
if (seconds)
*seconds = sec2;
if (nanoseconds)
*nanoseconds =
(uint32_t) ((int64_t) ns_cnt *
(int64_t) REF_CLOCK_PERIOD_PS / 1000LL);
}
/* Returns 1 when the adjustment operation is not yet finished */
int shw_pps_gen_busy()
{
uint32_t cr = ppsg_read(CR);
return cr & PPSG_CR_CNT_ADJ ? 0 : 1;
}
/* Enables/disables PPS output */
int shw_pps_gen_enable_output(int enable)
{
uint32_t escr = ppsg_read(ESCR);
if (enable)
ppsg_write(ESCR,
escr | PPSG_ESCR_PPS_VALID | PPSG_ESCR_TM_VALID);
else
ppsg_write(ESCR,
escr & ~(PPSG_ESCR_PPS_VALID | PPSG_ESCR_TM_VALID));
return 0;
}
/*
* This work is part of the White Rabbit project
*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
#include <stdio.h>
#include <inttypes.h>
#include <stdarg.h>
#include <wrc.h>
#include "board.h"
#include "trace.h"
#include "syscon.h"
#include "endpoint.h"
#include "softpll_ng.h"
#include "wrc_ptp.h"
#include "storage.h"
#include "ptpd_netif.h"
/* New calibrator for the transition phase value. A major pain in the ass for
the folks who frequently rebuild their gatewares. The idea is described
below:
- lock the PLL to the master
- scan the whole phase shifter range
- at each scanning step, generate a fake RX timestamp.
- check if the rising edge counter is ahead of the falling edge counter
(added a special bit for it in the TSU).
- determine phases at which positive/negative transitions occur
- transition phase value is in the middle between the rising and falling
edges.
This calibration procedure is fast enough to be run on slave nodes whenever
the link goes up. For master mode, the core must be run at least once as a
slave to calibrate itself and store the current transition phase value in
the EEPROM.
*/
/* how finely we scan the phase shift range to determine where we have the bit
* flip */
#define CAL_SCAN_STEP 100
/* deglitcher threshold (to remove 1->0->1 flip bit glitches that might occur
due to jitter) */
#define CAL_DEGLITCH_THRESHOLD 5
/* we scan at least one clock period to look for rising->falling edge transition
plus some headroom */
#define CAL_SCAN_RANGE (REF_CLOCK_PERIOD_PS + \
(3 * CAL_DEGLITCH_THRESHOLD * CAL_SCAN_STEP))
#define TD_WAIT_INACTIVE 0
#define TD_GOT_TRANSITION 1
#define TD_DONE 2
/* state of transition detector */
struct trans_detect_state {
int prev_val;
int sample_count;
int state;
int trans_phase;
};
/* finds the transition in the value of flip_bit and returns phase associated
with it. If no transition phase has been found yet, returns 0. Non-zero
polarity means we are looking for positive transitions, 0 - negative
transitions */
static int lookup_transition(struct trans_detect_state *state, int flip_bit,
int phase, int polarity)
{
if (polarity)
polarity = 1;
switch (state->state) {
case TD_WAIT_INACTIVE:
/* first, wait until we have at least CAL_DEGLITCH_THRESHOLD of
inactive state samples */
if (flip_bit != polarity)
state->sample_count++;
else
state->sample_count = 0;
if (state->sample_count >= CAL_DEGLITCH_THRESHOLD) {
state->state = TD_GOT_TRANSITION;
state->sample_count = 0;
}
break;
case TD_GOT_TRANSITION:
if (flip_bit != polarity)
state->sample_count = 0;
else {
state->sample_count++;
if (state->sample_count >= CAL_DEGLITCH_THRESHOLD) {
state->state = TD_DONE;
state->trans_phase =
phase -
CAL_DEGLITCH_THRESHOLD * CAL_SCAN_STEP;
}
}
break;
case TD_DONE:
return 1;
break;
}
return 0;
}
static struct trans_detect_state det_rising, det_falling;
static int cal_cur_phase;
/* Starts RX timestamper calibration process state machine. Invoked by
ptpnetif's check lock function when the PLL has already locked, to avoid
complicating the API of ptp-noposix/ppsi. */
void rxts_calibration_start()
{
cal_cur_phase = 0;
det_rising.prev_val = det_falling.prev_val = -1;
det_rising.state = det_falling.state = TD_WAIT_INACTIVE;
det_rising.sample_count = 0;
det_falling.sample_count = 0;
det_rising.trans_phase = 0;
det_falling.trans_phase = 0;
spll_set_phase_shift(0, 0);
}
/* Updates RX timestamper state machine. Non-zero return value means that
calibration is done. */
int rxts_calibration_update(uint32_t *t24p_value)
{
int32_t ttrans = 0;
if (spll_shifter_busy(0))
return 0;
/* generate a fake RX timestamp and check if falling edge counter is
ahead of rising edge counter */
int flip = ep_timestamper_cal_pulse();
/* look for transitions (with deglitching) */
lookup_transition(&det_rising, flip, cal_cur_phase, 1);
lookup_transition(&det_falling, flip, cal_cur_phase, 0);
if (cal_cur_phase >= CAL_SCAN_RANGE) {
if (det_rising.state != TD_DONE || det_falling.state != TD_DONE)
{
TRACE_DEV("RXTS calibration error.\n");
return -1;
}
/* normalize */
while (det_falling.trans_phase >= REF_CLOCK_PERIOD_PS)
det_falling.trans_phase -= REF_CLOCK_PERIOD_PS;
while (det_rising.trans_phase >= REF_CLOCK_PERIOD_PS)
det_rising.trans_phase -= REF_CLOCK_PERIOD_PS;
/* Use falling edge as second sample of rising edge */
if (det_falling.trans_phase > det_rising.trans_phase)
ttrans = det_falling.trans_phase - REF_CLOCK_PERIOD_PS/2;
else if(det_falling.trans_phase < det_rising.trans_phase)
ttrans = det_falling.trans_phase + REF_CLOCK_PERIOD_PS/2;
ttrans += det_rising.trans_phase;
ttrans /= 2;
/*normalize ttrans*/
if(ttrans < 0) ttrans += REF_CLOCK_PERIOD_PS;
if(ttrans >= REF_CLOCK_PERIOD_PS) ttrans -= REF_CLOCK_PERIOD_PS;
TRACE_DEV("RXTS calibration: R@%dps, F@%dps, transition@%dps\n",
det_rising.trans_phase, det_falling.trans_phase,
ttrans);
*t24p_value = (uint32_t)ttrans;
return 1;
}
cal_cur_phase += CAL_SCAN_STEP;
spll_set_phase_shift(0, cal_cur_phase);
return 0;
}
/* legacy function for 'calibration force' command */
int measure_t24p(uint32_t *value)
{
int rv;
pp_printf("Waiting for link...\n");
while (!ep_link_up(NULL))
timer_delay_ms(100);
spll_init(SPLL_MODE_SLAVE, 0, 1);
pp_printf("Locking PLL...\n");
while (!spll_check_lock(0))
timer_delay_ms(100);
pp_printf("\n");
pp_printf("Calibrating RX timestamper...\n");
rxts_calibration_start();
while (!(rv = rxts_calibration_update(value))) ;
return rv;
}
/* Delays for master must have been calibrated while running as slave */
static int calib_t24p_master(uint32_t *value)
{
int rv;
rv = storage_phtrans(value, 0);
if(rv < 0) {
pp_printf("Error %d while reading EEPROM\n", rv);
return rv;
}
pp_printf("t24p read from EEPROM: %d ps\n", *value);
return rv;
}
/*SoftPLL must be locked prior calling this function*/
static int calib_t24p_slave(uint32_t *value)
{
int rv;
uint32_t prev;
rxts_calibration_start();
while (!(rv = rxts_calibration_update(value)))
/* FIXME: timeout */;
if (rv < 0) {
/* Fall back on master == eeprom-or-error */
return calib_t24p_master(value);
}
/*
* Let's see if we have a matching value in EEPROM:
* accept a 200ps difference, otherwise rewrite eeprom
*/
rv = storage_phtrans(&prev, 0 /* rd */);
if (rv < 0 || (prev < *value - 200) || (prev > *value + 200)) {
rv = storage_phtrans(value, 1);
pp_printf("Wrote new t24p value: %d ps (%s)\n", *value,
rv < 0 ? "Failed" : "Success");
}
return rv;
}
int calib_t24p(int mode, uint32_t *value)
{
int ret;
if (mode == WRC_MODE_SLAVE)
ret = calib_t24p_slave(value);
else
ret = calib_t24p_master(value);
//update phtrans value in socket struct
ptpd_netif_set_phase_transition(*value);
return ret;
}
This diff is collapsed.
/*
* This work is part of the White Rabbit project
*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
/* SFP Detection / managenent functions */
#include <stdio.h>
#include <inttypes.h>
#include "syscon.h"
#include "i2c.h"
#include "sfp.h"
int sfp_present()
{
return !gpio_in(GPIO_SFP_DET);
}
int sfp_read_part_id(char *part_id)
{
int i;
uint8_t data, sum;
mi2c_init(WRPC_SFP_I2C);
mi2c_start(WRPC_SFP_I2C);
mi2c_put_byte(WRPC_SFP_I2C, 0xA0);
mi2c_put_byte(WRPC_SFP_I2C, 0x00);
mi2c_repeat_start(WRPC_SFP_I2C);
mi2c_put_byte(WRPC_SFP_I2C, 0xA1);
mi2c_get_byte(WRPC_SFP_I2C, &data, 1);
mi2c_stop(WRPC_SFP_I2C);
sum = data;
mi2c_start(WRPC_SFP_I2C);
mi2c_put_byte(WRPC_SFP_I2C, 0xA1);
for (i = 1; i < 63; ++i) {
mi2c_get_byte(WRPC_SFP_I2C, &data, 0);
sum = (uint8_t) ((uint16_t) sum + data) & 0xff;
if (i >= 40 && i <= 55) //Part Number
part_id[i - 40] = data;
}
mi2c_get_byte(WRPC_SFP_I2C, &data, 1); //final word, checksum
mi2c_stop(WRPC_SFP_I2C);
if (sum == data)
return 0;
return -1;
}
/*
* This work is part of the White Rabbit project
*
* Copyright (C) 2011 CERN (www.cern.ch)
* Author: Grzegorz Daniluk <grzegorz.daniluk@cern.ch>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
#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}
};
volatile struct SYSCON_WB *syscon;
/****************************
* TIMER
***************************/
void timer_init(uint32_t enable)
{
syscon = (volatile struct SYSCON_WB *)BASE_SYSCON;
if (enable)
syscon->TCR |= SYSC_TCR_ENABLE;
else
syscon->TCR &= ~SYSC_TCR_ENABLE;
}
uint32_t timer_get_tics(void)
{
return syscon->TVR;
}
void timer_delay(uint32_t tics)
{
uint32_t t_end;
// timer_init(1);
t_end = timer_get_tics() + tics;
while (time_before(timer_get_tics(), t_end))
;
}
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.
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.
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.
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.
/* usleep */
#include <syscon.h>
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.
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.
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.
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.
ppsi @ 674acb42
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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