Commit b490c2df authored by Jose Jimenez's avatar Jose Jimenez

debugger_sw: Base code

Signed-off-by: 's avatarJose Jimenez <ppjm@correo.ugr.es>
parent 1f19320a
mainmenu "Debugger Core software configuration"
config FINE_DEL_NODE
bool "Build code for Fine Delay Stand-Alone node"
default n
config DEBUGGER
bool
default !FINE_DEL_NODE
# most options with no prompt here are prompted-for in the "advanced" section
config PRINT_BUFSIZE
int
default 256
config PRINTF_FULL
boolean
default y
config RAMINIT
int
default 0x00000000
config RAMSIZE
int
default 92160
config STACKSIZE
int
default 22528
config HEAPSIZE
int
default 12480
config ALING
int
default 4
config MEM_CHECK_CMD
boolean"Command for memory checking/debbuging"
default y
#
# 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 "dbg-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 debugger_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 22528
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 HEAPSIZE
depends on DEVELOPER
int "Size of the heap area needed by this program"
default 12480
config PRINT_BUFSIZE
depends on DEVELOPER
int "Size for the temporary output string of pp_printf"
default 256
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.
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 debbuger-sw.
endchoice
# Jose Jimenez, 2013,2014 UGR
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
WRPC_DIR = wrpc-sw
-include $(CURDIR)/.config
AUTOCONF = $(CURDIR)/include/generated/autoconf.h
# we miss CONFIG_ARCH_LM32 as we have no other archs by now
obj-y = arch/lm32/crt0.o arch/lm32/irq.o
LDS-y = arch/lm32/ram.ld arch/lm32/sbrkr.o
obj-$(CONFIG_DEBUGGER) += dbg_main.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 -I- -include $(AUTOCONF) -Iinclude/std -Iinclude \
-I.
cflags-y += -I$(CURDIR)/$(WRPC_DIR)/pp_printf
CFLAGS_PLATFORM = -mmultiply-enabled -mbarrel-shift-enabled
LDFLAGS_PLATFORM = -mmultiply-enabled -mbarrel-shift-enabled \
-nostdlib -T $(LDS-y)
include linux/linux.mk
include fmc-delay/fine-delay.mk
include shell/shell.mk
include lib/lib.mk
include printf.mk
include dev/dev.mk
obj-y += check-error.o
obj-y += sdb-lib/libsdbfs.a
cflags-y += -Isdb-lib
CFLAGS = $(CFLAGS_PLATFORM) $(cflags-y) -Wall \
-ffunction-sections -fdata-sections -Os \
-ggdb
LDFLAGS = $(LDFLAGS_PLATFORM) \
-Wl,--gc-sections -Os -lgcc -lc
OBJS = $(obj-y)
#fine delay output included on .mk
output-$(CONFIG_DEBUGGER) = dbg
OUTPUT = $(output-y)
#REVISION=$(shell git describe --dirty --always)
all: wrpc dbg_core
dbg_core: remote_tools tools $(OUTPUT).ram $(OUTPUT).vhd $(OUTPUT).mif
.PRECIOUS: %.elf %.bin
.PHONY: all tools remote_tools clean
sdb-lib/libsdbfs.a:
$(MAKE) -C sdb-lib
$(OUTPUT).elf: $(LDS-y) $(AUTOCONF) $(OUTPUT).o config.o
${CC} -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
./$(WRPC_DIR)/tools/genraminit $*.bin 0 > $@
%.vhd: tools %.bin
./$(WRPC_DIR)/tools/genramvhd -s `. ./.config; echo $$CONFIG_RAMSIZE` $*.bin > $@
%.mif: tools %.bin
./$(WRPC_DIR)/tools/genrammif $*.bin `. ./.config; echo $$CONFIG_RAMSIZE` > $@
$(AUTOCONF): silentoldconfig
clean:
rm -f $(OBJS) *.o *.mif *.vhd *.elf *.bin *.ram *.S $(LDS)
$(MAKE) -C sdb-lib clean
$(MAKE) -C remote_tools clean
$(MAKE) -C $(WRPC_DIR) clean
%.o: %.c
${CC} $(CFLAGS) $(INCLUDE_DIR) $(LIB_DIR) -c $*.c -o $@
tools:
$(MAKE) -C $(WRPC_DIR)/tools -f Makefile
remote_tools:
$(MAKE) -C $@
install: remote_tools
$(MAKE) -C remote_tools $@
wrpc: gitmodules
$(MAKE) -C $(WRPC_DIR) etherbone_defconfig
$(MAKE) -C $(WRPC_DIR)
@cp $(WRPC_DIR)/wrc.ram ./wrc-ethb.ram
# 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 $(WRPC_DIR)/inlcude || echo "Checking out submodules"
@test -d $(WRPC_DIR)/inlcude || cd .. && 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 dbg_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)
# 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)
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 gp, hi(_gp)
ori gp, gp, lo(_gp)
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)
_HEAP_SIZE = CONFIG_HEAPSIZE;
aling = CONFIG_ALING;
MEMORY
{
ram :
ORIGIN = CONFIG_RAMINIT,
LENGTH = CONFIG_RAMSIZE,
stack :
ORIGIN = CONFIG_RAMINIT + CONFIG_RAMSIZE,
LENGTH = CONFIG_STACKSIZE
}
SECTIONS
{
.boot : { *(.boot) } > ram
.text : { *(.text .text.*) } > ram =0
.rodata : { *(.rodata .rodata.*) } > ram
.data : {
*(.data .data.*)
_gp = ALIGN(16) + 0x7ff0; /* FIXME: what is this? */
} > ram
.bss : {
_fbss = .;
*(.bss .bss.*)
*(COMMON)
_ebss = .;
} > ram
.heap : {
. = ALIGN(aling);
_heap = .;
_HEAP_START = .;
. += _HEAP_SIZE;
_HEAP_END = .;
} > 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 ptp-noposix object files, if missing */
PROVIDE(mprintf = pp_printf);
#include <stdio.h>
#include <stdlib.h>
#include <pp-printf.h>
#define GGC_MIN_HEAPSIZE_DEFAULT 32
extern unsigned int _HEAP_START;
extern unsigned int _HEAP_END;
extern unsigned int aling;
extern unsigned int _endram;
extern unsigned int _fstack;
caddr_t heap = NULL;
caddr_t _sbrk ( int increment ) {
caddr_t prevHeap;
caddr_t nextHeap;
if (heap == NULL) {
heap = (caddr_t)&_HEAP_START;
}
prevHeap = heap;
/*
* Although it is recommended to return data aligned to a 4 byte boundary,
*
* nextHeap = (caddr_t)(((unsigned int)(heap + increment) + aling) & ~aling)
*
* in our case, we don't need to do it
*/
nextHeap = (caddr_t)((unsigned int)(heap + increment));
register caddr_t stackPtr asm ("sp");
if ((((caddr_t)&_HEAP_START < stackPtr) && (nextHeap > stackPtr)) ||
(nextHeap >= (caddr_t)&_HEAP_END)) {
return NULL;
} else {
heap = nextHeap;
return (caddr_t) prevHeap;
}
}
/*
* 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 = .;
}
}
/* This work is part of the White Rabbit project
*
* Jose Jimenez <jjimenez.wr@gmail.com>, Copyright (C) 2014 UGR.
*
* Released according to the GNU GPL version 3 (GPLv3) or later.
*
* Adpated from check-error.c inlcuded on wrpc-sw project
*/
/*
* 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_debugger_sw(void);
extern void __you_should_not_divide_ll_in_debugger_sw(void);
#undef printf /* Under ptp-noposix, this is #defined to mprintf */
int printf(const char *fmt, ...)
{
__you_should_not_call_printf_from_debugger_sw();
return 0;
}
long long __moddi3 (long long A, long long B)
{
__you_should_not_divide_ll_in_debugger_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_debugger_sw();
return 0;
}
#
# Automatically generated make config: don't edit
#
# CONFIG_FINE_DEL_NODE is not set
CONFIG_DEBUGGER=y
CONFIG_PRINT_BUFSIZE=128
# CONFIG_PRINTF_FULL is not set
CONFIG_RAMINIT=0x00000000
CONFIG_RAMSIZE=38912
CONFIG_STACKSIZE=2048
CONFIG_HEAPSIZE=1024
CONFIG_ALING=4
CONFIG_MEM_CHECK_CMD=y
#
# dbg-sw is tainted if you change the following options
#
CONFIG_DEVELOPER=y
CONFIG_PRINTF_XINT=y
# CONFIG_PRINTF_MINI is not set
#
# Automatically generated make config: don't edit
#
CONFIG_FINE_DEL_NODE=y
# CONFIG_DEBUGGER is not set
CONFIG_PRINT_BUFSIZE=512
CONFIG_PRINTF_FULL=y
CONFIG_RAMINIT=0x00000000
CONFIG_RAMSIZE=92160
CONFIG_STACKSIZE=2048
CONFIG_HEAPSIZE=12480
CONFIG_ALING=4
CONFIG_MEM_CHECK_CMD=y
#
# dbg-sw is tainted if you change the following options
#
CONFIG_DEVELOPER=y
# CONFIG_PRINTF_XINT is not set
# CONFIG_PRINTF_MINI is not set
/* This work is part of the White Rabbit project
*
* Jose Jimenez <jjimenez.wr@gmail.com>, Copyright (C) 2014.
*
* Released according to the GNU GPL version 3 (GPLv3) or later.
*
*/
#include <stdio.h>
#include <stdio.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdarg.h>
#include <w1.h>
#include "uart.h"
#include "eeprom.h"
#include <pp-printf.h>
#include "shell.h"
#include "irq.h"
#include "linux/jiffies.h"
#include "linux/delay.h"
#define mprintf pp_printf
#define vprintf pp_vprintf
#define sprintf pp_sprintf
void _irq_entry(void) {}
extern uint32_t _endram;
extern uint32_t _fstack;
#define ENDRAM_MAGIC 0xbadc0ffe
void kernel_dev(int subsys, const char *fmt, ...)
{
va_list ap;
if (subsys == 0)
mprintf("Error: ");
else if (subsys == 1)
mprintf("Warning: ");
else if (subsys == 2)
mprintf("Info: ");
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
void mprint_64bit (uint64_t value)
{
char valstr[128];
uint64_t low;
uint32_t high;
high=(uint32_t) div64_u64_rem(value, (1000LLU*1000LLU*1000LLU), &low);
if (high != 0)
pp_sprintf(valstr, "%d%08d", high, (unsigned int) (low));
else
pp_sprintf(valstr, "%d", (unsigned int) (low));
mprintf("%s", valstr);
}
/*static void check_stack(void)
{
while (_endram != ENDRAM_MAGIC) {
mprintf("Stack overflow!\n");
msleep(1000);
}
}*/
int main(void)
{
sdb_find_devices();
//uart_init_sw();
uart_init_hw();
mprintf("Running....\n");
shell_exec("dbgmem");
shell_exec("dbgmem 0x80000");
shell_exec("dbgmem -b 0x80000 0x1");
shell_exec("dbgmem -b0x80000 0x1");
shell_exec("dbgmem -b0x0000");
for (;;){
shell_interactive();
//check_stack();
}
}
/*
* Trivial pll programmer using an spi controoler.
* PLL is AD9516, SPI is opencores
* Tomasz Wlostowski, Alessandro Rubini, 2011, for CERN.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <wrc.h>
#include "board.h"
#include "syscon.h"
#include "gpio-wrs.h"
#include "rt_ipc.h"
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
#endif
static inline void writel(uint32_t data, void *where)
{
* (volatile uint32_t *)where = data;
}
static inline uint32_t readl(void *where)
{
return * (volatile uint32_t *)where;
}
struct ad9516_reg {
uint16_t reg;
uint8_t val;
};
#include "ad9516_config.h"
/*
* SPI stuff, used by later code
*/
#define SPI_REG_RX0 0
#define SPI_REG_TX0 0
#define SPI_REG_RX1 4
#define SPI_REG_TX1 4
#define SPI_REG_RX2 8
#define SPI_REG_TX2 8
#define SPI_REG_RX3 12
#define SPI_REG_TX3 12
#define SPI_REG_CTRL 16
#define SPI_REG_DIVIDER 20
#define SPI_REG_SS 24
#define SPI_CTRL_ASS (1<<13)
#define SPI_CTRL_IE (1<<12)
#define SPI_CTRL_LSB (1<<11)
#define SPI_CTRL_TXNEG (1<<10)
#define SPI_CTRL_RXNEG (1<<9)
#define SPI_CTRL_GO_BSY (1<<8)
#define SPI_CTRL_CHAR_LEN(x) ((x) & 0x7f)
#define GPIO_PLL_RESET_N 1
#define GPIO_SYS_CLK_SEL 0
#define GPIO_PERIPH_RESET_N 3
#define CS_PLL 0 /* AD9516 on SPI CS0 */
static void *oc_spi_base;
int oc_spi_init(void *base_addr)
{
oc_spi_base = base_addr;
writel(100, oc_spi_base + SPI_REG_DIVIDER);
return 0;
}
int oc_spi_txrx(int ss, int nbits, uint32_t in, uint32_t *out)
{
uint32_t rval;
if (!out)
out = &rval;
writel(SPI_CTRL_ASS | SPI_CTRL_CHAR_LEN(nbits)
| SPI_CTRL_TXNEG,
oc_spi_base + SPI_REG_CTRL);
writel(in, oc_spi_base + SPI_REG_TX0);
writel((1 << ss), oc_spi_base + SPI_REG_SS);
writel(SPI_CTRL_ASS | SPI_CTRL_CHAR_LEN(nbits)
| SPI_CTRL_TXNEG | SPI_CTRL_GO_BSY,
oc_spi_base + SPI_REG_CTRL);
while(readl(oc_spi_base + SPI_REG_CTRL) & SPI_CTRL_GO_BSY)
;
*out = readl(oc_spi_base + SPI_REG_RX0);
return 0;
}
/*
* AD9516 stuff, using SPI, used by later code.
* "reg" is 12 bits, "val" is 8 bits, but both are better used as int
*/
static void ad9516_write_reg(int reg, int val)
{
oc_spi_txrx(CS_PLL, 24, (reg << 8) | val, NULL);
}
static int ad9516_read_reg(int reg)
{
uint32_t rval;
oc_spi_txrx(CS_PLL, 24, (reg << 8) | (1 << 23), &rval);
return rval & 0xff;
}
static void ad9516_load_regset(const struct ad9516_reg *regs, int n_regs, int commit)
{
int i;
for(i=0; i<n_regs; i++)
ad9516_write_reg(regs[i].reg, regs[i].val);
if(commit)
ad9516_write_reg(0x232, 1);
}
static void ad9516_wait_lock()
{
while ((ad9516_read_reg(0x1f) & 1) == 0);
}
#define SECONDARY_DIVIDER 0x100
int ad9516_set_output_divider(int output, int ratio, int phase_offset)
{
uint8_t lcycles = (ratio/2) - 1;
uint8_t hcycles = (ratio - (ratio / 2)) - 1;
int secondary = (output & SECONDARY_DIVIDER) ? 1 : 0;
output &= 0xf;
if(output >= 0 && output < 6) /* LVPECL outputs */
{
uint16_t base = (output / 2) * 0x3 + 0x190;
if(ratio == 1) /* bypass the divider */
{
uint8_t div_ctl = ad9516_read_reg(base + 1);
ad9516_write_reg(base + 1, div_ctl | (1<<7) | (phase_offset & 0xf));
} else {
uint8_t div_ctl = ad9516_read_reg(base + 1);
TRACE("DivCtl: %x\n", div_ctl);
ad9516_write_reg(base + 1, (div_ctl & (~(1<<7))) | (phase_offset & 0xf)); /* disable bypass bit */
ad9516_write_reg(base, (lcycles << 4) | hcycles);
}
} else { /* LVDS/CMOS outputs */
uint16_t base = ((output - 6) / 2) * 0x5 + 0x199;
TRACE("Output [divider %d]: %d ratio: %d base %x lc %d hc %d\n", secondary, output, ratio, base, lcycles ,hcycles);
if(!secondary)
{
if(ratio == 1) /* bypass the divider 1 */
ad9516_write_reg(base + 3, ad9516_read_reg(base + 3) | 0x10);
else {
ad9516_write_reg(base, (lcycles << 4) | hcycles);
ad9516_write_reg(base + 1, phase_offset & 0xf);
}
} else {
if(ratio == 1) /* bypass the divider 2 */
ad9516_write_reg(base + 3, ad9516_read_reg(base + 3) | 0x20);
else {
ad9516_write_reg(base + 2, (lcycles << 4) | hcycles);
// ad9516_write_reg(base + 1, phase_offset & 0xf);
}
}
}
/* update */
ad9516_write_reg(0x232, 0x0);
ad9516_write_reg(0x232, 0x1);
ad9516_write_reg(0x232, 0x0);
return 0;
}
int ad9516_set_vco_divider(int ratio) /* Sets the VCO divider (2..6) or 0 to enable static output */
{
if(ratio == 0)
ad9516_write_reg(0x1e0, 0x5); /* static mode */
else
ad9516_write_reg(0x1e0, (ratio-2));
ad9516_write_reg(0x232, 0x1);
return 0;
}
void ad9516_sync_outputs()
{
/* VCO divider: static mode */
ad9516_write_reg(0x1E0, 0x7);
ad9516_write_reg(0x232, 0x1);
/* Sync the outputs when they're inactive to avoid +-1 cycle uncertainity */
ad9516_write_reg(0x230, 1);
ad9516_write_reg(0x232, 1);
ad9516_write_reg(0x230, 0);
ad9516_write_reg(0x232, 1);
}
int ad9516_init(void)
{
TRACE("Initializing AD9516 PLL...\n");
oc_spi_init((void *)BASE_SPI);
gpio_out(GPIO_SYS_CLK_SEL, 0); /* switch to the standby reference clock, since the PLL is off after reset */
/* reset the PLL */
gpio_out(GPIO_PLL_RESET_N, 0);
timer_delay(10);
gpio_out(GPIO_PLL_RESET_N, 1);
timer_delay(10);
/* Use unidirectional SPI mode */
ad9516_write_reg(0x000, 0x99);
/* Check the presence of the chip */
if (ad9516_read_reg(0x3) != 0xc3) {
TRACE("Error: AD9516 PLL not responding.\n");
return -1;
}
ad9516_load_regset(ad9516_base_config, ARRAY_SIZE(ad9516_base_config), 0);
ad9516_load_regset(ad9516_ref_tcxo, ARRAY_SIZE(ad9516_ref_tcxo), 1);
ad9516_wait_lock();
ad9516_sync_outputs();
ad9516_set_output_divider(9, 4, 0); /* AUX/SWCore = 187.5 MHz */
ad9516_set_output_divider(7, 12, 0); /* REF = 62.5 MHz */
ad9516_set_output_divider(4, 12, 0); /* GTX = 62.5 MHz */
ad9516_sync_outputs();
ad9516_set_vco_divider(2);
TRACE("AD9516 locked.\n");
gpio_out(GPIO_SYS_CLK_SEL, 1); /* switch the system clock to the PLL reference */
gpio_out(GPIO_PERIPH_RESET_N, 0); /* reset all peripherals which use AD9516-provided clocks */
gpio_out(GPIO_PERIPH_RESET_N, 1);
return 0;
}
int rts_debug_command(int command, int value)
{
switch(command)
{
case RTS_DEBUG_ENABLE_SERDES_CLOCKS:
if(value)
{
ad9516_write_reg(0xf4, 0x08); // OUT4 enabled
ad9516_write_reg(0x232, 0x0);
ad9516_write_reg(0x232, 0x1);
} else {
ad9516_write_reg(0xf4, 0x0a); // OUT4 power-down, no serdes clock
ad9516_write_reg(0x232, 0x0);
ad9516_write_reg(0x232, 0x1);
}
break;
}
return 0;
}
/* Base configuration (global dividers, output config, reference-independent) */
const struct ad9516_reg ad9516_base_config[] = {
{0x0000, 0x99},
{0x0001, 0x00},
{0x0002, 0x10},
{0x0003, 0xC3},
{0x0004, 0x00},
{0x0010, 0x7C},
{0x0011, 0x05},
{0x0012, 0x00},
{0x0013, 0x0C},
{0x0014, 0x12},
{0x0015, 0x00},
{0x0016, 0x05},
{0x0017, 0x88},
{0x0018, 0x07},
{0x0019, 0x00},
{0x001A, 0x00},
{0x001B, 0x00},
{0x001C, 0x02},
{0x001D, 0x00},
{0x001E, 0x00},
{0x001F, 0x0E},
{0x00A0, 0x01},
{0x00A1, 0x00},
{0x00A2, 0x00},
{0x00A3, 0x01},
{0x00A4, 0x00},
{0x00A5, 0x00},
{0x00A6, 0x01},
{0x00A7, 0x00},
{0x00A8, 0x00},
{0x00A9, 0x01},
{0x00AA, 0x00},
{0x00AB, 0x00},
{0x00F0, 0x0A},
{0x00F1, 0x0A},
{0x00F2, 0x0A},
{0x00F3, 0x0A},
{0x00F4, 0x08},
{0x00F5, 0x08},
{0x0140, 0x43},
{0x0141, 0x42},
{0x0142, 0x43},
{0x0143, 0x42},
{0x0190, 0x00},
{0x0191, 0x80},
{0x0192, 0x00},
{0x0193, 0xBB},
{0x0194, 0x00},
{0x0195, 0x00},
{0x0196, 0x00},
{0x0197, 0x00},
{0x0198, 0x00},
{0x0199, 0x11},
{0x019A, 0x00},
{0x019B, 0x11},
{0x019C, 0x20},
{0x019D, 0x00},
{0x019E, 0x11},
{0x019F, 0x00},
{0x01A0, 0x11},
{0x01A1, 0x20},
{0x01A2, 0x00},
{0x01A3, 0x00},
{0x01E0, 0x04},
{0x01E1, 0x02},
{0x0230, 0x00},
{0x0231, 0x00},
};
/* Config for 25 MHz VCTCXO reference (RDiv = 5, use REF1) */
const struct ad9516_reg ad9516_ref_tcxo[] = {
{0x0011, 0x05},
{0x0012, 0x00}, /* RDiv = 5 */
{0x001C, 0x06} /* Use REF1 */
};
/* Config for 10 MHz external reference (RDiv = 2, use REF2) */
const struct ad9516_reg ad9516_ref_ext[] = {
{0x0011, 0x02},
{0x0012, 0x00}, /* RDiv = 2 */
{0x001C, 0x46} /* Use REF1 */
};
const struct {int reg; uint8_t val} ad9516_regs[] = {
{0x0000, 0x99},
{0x0001, 0x00},
{0x0002, 0x10},
{0x0003, 0xC3},
{0x0004, 0x00},
{0x0010, 0x7C},
{0x0011, 0x01},
{0x0012, 0x00},
{0x0013, 0x04},
{0x0014, 0x07},
{0x0015, 0x00},
{0x0016, 0x04},
{0x0017, 0x00},
{0x0018, 0x07},
{0x0019, 0x00},
{0x001A, 0x00},
{0x001B, 0x00},
{0x001C, 0x46},
{0x001D, 0x00},
{0x001E, 0x00},
{0x001F, 0x0E},
{0x00A0, 0x01},
{0x00A1, 0x00},
{0x00A2, 0x00},
{0x00A3, 0x01},
{0x00A4, 0x00},
{0x00A5, 0x00},
{0x00A6, 0x01},
{0x00A7, 0x00},
{0x00A8, 0x00},
{0x00A9, 0x01},
{0x00AA, 0x00},
{0x00AB, 0x00},
{0x00F0, 0x0A},
{0x00F1, 0x0A},
{0x00F2, 0x0A},
{0x00F3, 0x0A},
{0x00F4, 0x08},
{0x00F5, 0x0A},
{0x0140, 0x43},
{0x0141, 0x43},
{0x0142, 0x43},
{0x0143, 0x43},
{0x0190, 0x00},
{0x0191, 0x80},
{0x0192, 0x00},
{0x0193, 0xBB},
{0x0194, 0x00},
{0x0195, 0x00},
{0x0196, 0x00},
{0x0197, 0x00},
{0x0198, 0x00},
{0x0199, 0x22},
{0x019A, 0x00},
{0x019B, 0x11},
{0x019C, 0x00},
{0x019D, 0x00},
{0x019E, 0x22},
{0x019F, 0x00},
{0x01A0, 0x11},
{0x01A1, 0x00},
{0x01A2, 0x00},
{0x01A3, 0x00},
{0x01E0, 0x04},
{0x01E1, 0x02},
{0x0230, 0x00},
{0x0231, 0x00},
{0x0232, 0x00},
{-1, 0}};
# This work is part of the White Rabbit project
#
# Jose Jimenez <jjimenez.wr@gmail.com>, Copyright (C) 2014 UGR.
#
# Released according to the GNU GPL version 3 (GPLv3) or later.
#
obj-y += \
dev/sdb.o \
obj-y += dev/uart.o
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 "eeprom.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) 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 "eeprom.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;
}
/*SoftPLL must be locked prior calling this function*/
static int calib_t24p_slave(uint32_t *value)
{
int rv;
rxts_calibration_start();
while (!(rv = rxts_calibration_update(value))) ;
if (rv < 0) {
pp_printf("Could not calibrate t24p, trying to read from EEPROM\n");
if(eeprom_phtrans(WRPC_FMC_I2C, FMC_EEPROM_ADR, value, 0) < 0) {
pp_printf("Something went wrong while writing EEPROM\n");
return -1;
}
}
else {
pp_printf("t24p value is %d ps, storing to EEPROM\n", *value);
if(eeprom_phtrans(WRPC_FMC_I2C, FMC_EEPROM_ADR, value, 1) < 0) {
pp_printf("Something went wrong while writing EEPROM\n");
return -1;
}
}
return 0;
}
static int calib_t24p_master(uint32_t *value)
{
int rv;
rv = eeprom_phtrans(WRPC_FMC_I2C, FMC_EEPROM_ADR, value, 0);
if(rv < 0)
pp_printf("Something went wrong while reading from EEPROM: %d\n", rv);
else
pp_printf("t24p read from EEPROM: %d ps\n", *value);
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
*
* Author: Jose Jimenez <jjimenez.wr@gmail.com>, Copyright (C) 2014.
* Released according to the GNU GPL version 3 (GPLv3) or later.
*
* This is an evolution of sdb.c:
* * Copyright (C) 2012 GSI (www.gsi.de)
* * Author: Wesley W. Terpstra <w.terpstra@gsi.de>
*
*/
#include <string.h>
#include <dbg.h>
#include "hw/memlayout.h"
unsigned char *BASE_UART;
unsigned char *BASE_ONEWIRE;
unsigned char *BASE_IRQ_CTRL;
unsigned char *BASE_TIMER;
unsigned char *BASE_FINE_DELAY;
unsigned char *BASE_TICS;
//unsigned char *BASE_WRPC_RAM;
#define SDB_INTERCONNET 0x00
#define SDB_DEVICE 0x01
#define SDB_BRIDGE 0x02
#define SDB_EMPTY 0xFF
typedef struct pair64 {
uint32_t high;
uint32_t low;
} pair64_t;
struct sdb_empty {
int8_t reserved[63];
uint8_t record_type;
};
struct sdb_product {
pair64_t vendor_id;
uint32_t device_id;
uint32_t version;
uint32_t date;
int8_t name[19];
uint8_t record_type;
};
struct sdb_component {
pair64_t addr_first;
pair64_t addr_last;
struct sdb_product product;
};
struct sdb_device {
uint16_t abi_class;
uint8_t abi_ver_major;
uint8_t abi_ver_minor;
uint32_t bus_specific;
struct sdb_component sdb_component;
};
struct sdb_bridge {
pair64_t sdb_child;
struct sdb_component sdb_component;
};
struct sdb_interconnect {
uint32_t sdb_magic;
uint16_t sdb_records;
uint8_t sdb_version;
uint8_t sdb_bus_type;
struct sdb_component sdb_component;
};
typedef union sdb_record {
struct sdb_empty empty;
struct sdb_device device;
struct sdb_bridge bridge;
struct sdb_interconnect interconnect;
} sdb_record_t;
static unsigned char *find_device_deep(unsigned int base, unsigned int sdb,
unsigned int devid)
{
sdb_record_t *record = (sdb_record_t *) sdb;
int records = record->interconnect.sdb_records;
int i;
for (i = 0; i < records; ++i, ++record) {
if (record->empty.record_type == SDB_BRIDGE) {
unsigned char *out =
find_device_deep(base +
record->bridge.sdb_component.
addr_first.low,
base +
record->bridge.sdb_child.low,
devid);
if (out)
return out;
}
if (record->empty.record_type == SDB_DEVICE &&
record->device.sdb_component.product.device_id == devid) {
break;
}
}
if (i == records)
return 0;
return (unsigned char *)(base +
record->device.sdb_component.addr_first.low);
}
static int get_devices_deep(unsigned int base, unsigned int sdb,
struct sdb_component * devs, unsigned int * n_devs,
const unsigned int MAX_DEVS)
{
sdb_record_t *record = (sdb_record_t *) sdb;
int records = record->interconnect.sdb_records;
int i;
int rcode;
for (i = 0; i < records; ++i, ++record) {
if (record->empty.record_type == SDB_BRIDGE)
rcode = get_devices_deep(
base + record->bridge.sdb_component.addr_first.low,
base + record->bridge.sdb_child.low,devs,n_devs,MAX_DEVS);;
if (rcode < 0)
return -1;
if (record->empty.record_type != SDB_DEVICE)
continue;
if (*n_devs < MAX_DEVS) {
devs[*n_devs] = record->device.sdb_component;
devs[*n_devs].product.name[19] = 0;
devs[*n_devs].addr_first.low =
base + record->device.sdb_component.addr_first.low;
devs[*n_devs].addr_last.low =
base + record->device.sdb_component.addr_last.low;
(*n_devs)++;
}
else
return (*n_devs - MAX_DEVS);
}
return 0;
}
static void print_devices_deep(unsigned int base, unsigned int sdb)
{
sdb_record_t *record = (sdb_record_t *) sdb;
int records = record->interconnect.sdb_records;
int i;
char buf[20];
for (i = 0; i < records; ++i, ++record) {
if (record->empty.record_type == SDB_BRIDGE)
print_devices_deep(base +
record->bridge.sdb_component.
addr_first.low,
base +
record->bridge.sdb_child.low);
if (record->empty.record_type != SDB_DEVICE)
continue;
memcpy(buf, record->device.sdb_component.product.name, 19);
buf[19] = 0;
mprintf("%8x:%8x 0x%8x %s\n",
record->device.sdb_component.product.vendor_id.low,
record->device.sdb_component.product.device_id,
base + record->device.sdb_component.addr_first.low,
buf);
}
}
unsigned char *find_device(unsigned int devid)
{
return find_device_deep(0, SDB_ADDRESS, devid);
}
void sdb_print_devices(void)
{
mprintf("SDB memory map:\n");
print_devices_deep(0, SDB_ADDRESS);
mprintf("---\n");
}
int sdb_get_devices(struct sdb_component * devs,
unsigned int * n_devs, const int MAX_DEVS)
{
return get_devices_deep(0,SDB_ADDRESS,devs,n_devs,MAX_DEVS);
}
void sdb_find_devices(void)
{
BASE_UART = find_device(0x0deafbee);
BASE_ONEWIRE = find_device(0x779c5443);
BASE_FINE_DELAY = find_device(0xf19ede1a);
BASE_TICS = find_device(0xfade1eaf);
BASE_TIMER = find_device(0xdeadface);
BASE_IRQ_CTRL = find_device(0xe1fb1ade);
//BASE_WRPC_RAM = find_device(0x66cfeb52);
}
/*
* 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))
;
}
#include "board.h"
#include "syscon.h"
uint32_t timer_get_tics(void)
{
return *(volatile uint32_t *) (BASE_TIMER);
}
void timer_delay(uint32_t tics)
{
uint32_t t_end = timer_get_tics() + tics;
while (time_before(timer_get_tics(), t_end))
;
}
/*
* This work is part of the White Rabbit project
*
* Copyright (C) 2013 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>
#include <uart-sw.h>
static struct wrc_uart_sw __attribute__((aligned(16))) uart_sw_dev = {
.magic = UART_SW_MAGIC,
.wsize = CONFIG_UART_SW_WSIZE,
.rsize = CONFIG_UART_SW_RSIZE,
};
static uint16_t nreturned;
void uart_init_sw(void)
{
/* zero fields, as we may be reloaded */
uart_sw_dev.nwritten = uart_sw_dev.nread = 0;
}
void __attribute__((weak)) uart_init_hw(void)
{}
void uart_sw_write_byte(int b)
{
int index;
if (b == '\n')
uart_sw_write_byte('\r');
index = uart_sw_dev.nwritten % CONFIG_UART_SW_WSIZE;
uart_sw_dev.wbuffer[index] = b;
uart_sw_dev.nwritten++;
/* fake a real uart, so user-space can poll not-too-fast */
usleep(1000 * 1000 / 11520);
}
int uart_sw_write_string(const char *s)
{
const char *t = s;
while (*s)
uart_sw_write_byte(*(s++));
return s - t;
}
int uart_sw_read_byte()
{
int index;
if (nreturned == uart_sw_dev.nread) /* nread == written by host */
return -1;
index = (nreturned++) % CONFIG_UART_SW_RSIZE;
return uart_sw_dev.rbuffer[index];
}
/* alias the "hw" names to these, so this applies if !CONFIG_UART */
int puts(const char *s)
__attribute__((alias("uart_sw_write_string"), weak));
void uart_write_byte(int b)
__attribute__((alias("uart_sw_write_byte"), weak));
int uart_write_string(const char *s)
__attribute__((alias("uart_sw_write_string"), weak));
int uart_read_byte()
__attribute__((alias("uart_sw_read_byte"), weak));
/*
* 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 <inttypes.h>
#include "board.h"
#include "uart.h"
#include <hw/wb_vuart.h>
#define CALC_BAUD(baudrate) \
( ((( (unsigned long long)baudrate * 8ULL) << (16 - 7)) + \
(CPU_CLOCK >> 8)) / (CPU_CLOCK >> 7) )
volatile struct UART_WB *uart;
void uart_init_hw()
{
uart = (volatile struct UART_WB *)BASE_UART;
uart->BCR = CALC_BAUD(UART_BAUDRATE);
}
void __attribute__((weak)) uart_init_sw(void)
{}
void uart_write_byte(int b)
{
if (b == '\n')
uart_write_byte('\r');
while (uart->SR & UART_SR_TX_BUSY)
;
uart->TDR = b;
}
int uart_write_string(const char *s)
{
const char *t = s;
while (*s)
uart_write_byte(*(s++));
return s - t;
}
static int uart_poll()
{
return uart->SR & UART_SR_RX_RDY;
}
int uart_read_byte()
{
if (!uart_poll())
return -1;
return uart->RDR & 0xff;
}
int puts(const char *s)
__attribute__((alias("uart_write_string")));
/* The next alias is for ppsi log messages, that go to sw_uart if built */
int uart_sw_write_string(const char *s)
__attribute__((alias("uart_write_string"), weak));
/*
* Eeprom support (family 0x43)
* Cesar Prados, Alessandro Rubini, 2013. GNU GPL2 or later
*/
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <w1.h>
#define LSB_ADDR(X) ((X) & 0xFF)
#define MSB_ADDR(X) (((X) & 0xFF00)>>8)
static int w1_write_page(struct w1_dev *dev, int offset, const uint8_t *buffer,
int blen)
{
int i, j, es;
/* First, write scratchpad */
w1_match_rom(dev);
w1_write_byte(dev->bus, W1_CMDR_W_SPAD);
w1_write_byte(dev->bus, LSB_ADDR(offset));
w1_write_byte(dev->bus, MSB_ADDR(offset));
for(i = 0; i < blen; i++)
w1_write_byte(dev->bus, buffer[i]);
/* Then, read it back, and remember the return E/S */
w1_match_rom(dev);
w1_write_byte(dev->bus, W1_CMDR_R_SPAD);
if (w1_read_byte(dev->bus) != LSB_ADDR(offset))
return -1;
if (w1_read_byte(dev->bus) != MSB_ADDR(offset))
return -2;
es = w1_read_byte(dev->bus);
for(i = 0; i < blen; i++) {
j = w1_read_byte(dev->bus);
if (j != buffer[i])
return -3;
}
/* Finally, "copy scratchpad" to actually write */
w1_match_rom(dev);
w1_write_byte(dev->bus, W1_CMDR_C_SPAD);
w1_write_byte(dev->bus, LSB_ADDR(offset));
w1_write_byte(dev->bus, MSB_ADDR(offset));
w1_write_byte(dev->bus, es);
usleep(10000); /* 10ms, in theory */
/* Don't read back, as nothing useful is there (I get 0xf9, why?) */
return blen;
}
int w1_write_eeprom(struct w1_dev *dev, int offset, const uint8_t *buffer,
int blen)
{
int i, page, endpage;
int ret = 0;
/* Split the write into several page-local writes */
page = offset / 32;
endpage = (offset + blen - 1) / 32;
/* Traling part of first page */
if (offset % 32) {
if (endpage != page)
i = 32 - (offset % 32);
else
i = blen;
ret += w1_write_page(dev, offset, buffer, i);
if (ret < 0)
return ret;
buffer += i;
offset += i;
blen -= i;
}
/* Whole pages and leading part of last page */
while (blen > 0 ) {
i = blen;
if (blen > 32)
i = 32;
i = w1_write_page(dev, offset, buffer, i);
if (i < 0)
return i;
ret += i;
buffer += 32;
offset += 32;
blen -= 32;
}
return ret;
}
int w1_read_eeprom(struct w1_dev *dev, int offset, uint8_t *buffer, int blen)
{
int i;
w1_match_rom(dev);
w1_write_byte(dev->bus, W1_CMDR_R_MEMORY);
w1_write_byte(dev->bus, LSB_ADDR(offset));
w1_write_byte(dev->bus, MSB_ADDR(offset));
/* There is no page-size limit in reading, just go on at will */
for(i = 0; i < blen; i++)
buffer[i] = w1_read_byte(dev->bus);
return blen;
}
int w1_read_eeprom_bus(struct w1_bus *bus,
int offset, uint8_t *buffer, int blen)
{
int i, class;
for (i = 0; i < W1_MAX_DEVICES; i++) {
class = w1_class(bus->devs + i);
if (class == 0x43)
return w1_read_eeprom(bus->devs + i, offset,
buffer, blen);
}
/* not found */
return -1;
}
int w1_write_eeprom_bus(struct w1_bus *bus,
int offset, const uint8_t *buffer, int blen)
{
int i, class;
for (i = 0; i < W1_MAX_DEVICES; i++) {
class = w1_class(bus->devs + i);
if (class == 0x43)
return w1_write_eeprom(bus->devs + i, offset,
buffer, blen);
}
/* not found */
return -1;
}
/*
* This work is part of the White Rabbit project
*
* Copyright (C) 2013 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
#include <string.h>
#include <w1.h>
#include <board.h>
#include <hw/sockit_owm_regs.h>
static inline uint32_t __wait_cycle(void *base)
{
uint32_t reg;
while ((reg = IORD_SOCKIT_OWM_CTL(base)) & SOCKIT_OWM_CTL_CYC_MSK)
;
return reg;
}
static int w1_reset(struct w1_bus *bus)
{
int portnum = bus->detail;
uint32_t reg;
IOWR_SOCKIT_OWM_CTL(BASE_ONEWIRE, (portnum << SOCKIT_OWM_CTL_SEL_OFST)
| (SOCKIT_OWM_CTL_CYC_MSK)
| (SOCKIT_OWM_CTL_RST_MSK));
reg = __wait_cycle(BASE_ONEWIRE);
/* return presence-detect pulse (1 if true) */
return (reg & SOCKIT_OWM_CTL_DAT_MSK) ? 0 : 1;
}
static int w1_read_bit(struct w1_bus *bus)
{
int portnum = bus->detail;
uint32_t reg;
IOWR_SOCKIT_OWM_CTL(BASE_ONEWIRE, (portnum << SOCKIT_OWM_CTL_SEL_OFST)
| (SOCKIT_OWM_CTL_CYC_MSK)
| (SOCKIT_OWM_CTL_DAT_MSK));
reg = __wait_cycle(BASE_ONEWIRE);
return (reg & SOCKIT_OWM_CTL_DAT_MSK) ? 1 : 0;
}
static void w1_write_bit(struct w1_bus *bus, int bit)
{
int portnum = bus->detail;
IOWR_SOCKIT_OWM_CTL(BASE_ONEWIRE, (portnum << SOCKIT_OWM_CTL_SEL_OFST)
| (SOCKIT_OWM_CTL_CYC_MSK)
| (bit ? SOCKIT_OWM_CTL_DAT_MSK : 0));
__wait_cycle(BASE_ONEWIRE);
}
struct w1_ops wrpc_w1_ops = {
.reset = w1_reset,
.read_bit = w1_read_bit,
.write_bit = w1_write_bit,
};
struct w1_bus wrpc_w1_bus;
/* Init from sockitowm code */
#define CLK_DIV_NOR (CPU_CLOCK / 200000 - 1) /* normal mode */
#define CLK_DIV_OVD (CPU_CLOCK / 1000000 - 1) /* overdrive mode (not used) */
void wrpc_w1_init(void)
{
IOWR_SOCKIT_OWM_CDR(BASE_ONEWIRE,
((CLK_DIV_NOR & SOCKIT_OWM_CDR_N_MSK) |
((CLK_DIV_OVD << SOCKIT_OWM_CDR_O_OFST) &
SOCKIT_OWM_CDR_O_MSK)));
}
/*
* Onewire generic interface
* Alessandro Rubini, 2013 GNU GPL2 or later
*/
#include <wrc.h>
#include <shell.h>
#include <w1.h>
#define BLEN 32
/* A shell command, for testing write: "w1w <offset> <byte> [<byte> ...]" */
static int cmd_w1_w(const char *args[])
{
int offset, i, blen;
unsigned char buf[BLEN];
if (!args[0] || !args[1])
return -1;
offset = atoi(args[0]);
for (i = 1, blen = 0; args[i] && blen < BLEN; i++, blen++) {
buf[blen] = atoi(args[i]);
pp_printf("offset %4i (0x%03x): %3i (0x%02x)\n",
offset + blen, offset + blen, buf[blen], buf[blen]);
}
i = w1_write_eeprom_bus(&wrpc_w1_bus, offset, buf, blen);
pp_printf("write(0x%x, %i): result = %i\n", offset, blen, i);
return i == blen ? 0 : -1;
}
DEFINE_WRC_COMMAND(w1w) = {
.name = "w1w",
.exec = cmd_w1_w,
};
/* A shell command, for testing read: "w1r <offset> <len> */
static int cmd_w1_r(const char *args[])
{
int offset, i, blen;
unsigned char buf[BLEN];
if (!args[0] || !args[1])
return -1;
offset = atoi(args[0]);
blen = atoi(args[1]);
if (blen > BLEN)
blen = BLEN;
i = w1_read_eeprom_bus(&wrpc_w1_bus, offset, buf, blen);
pp_printf("read(0x%x, %i): result = %i\n", offset, blen, i);
if (i <= 0 || i > blen) return -1;
for (blen = 0; blen < i; blen++) {
pp_printf("offset %4i (0x%03x): %3i (0x%02x)\n",
offset + blen, offset + blen, buf[blen], buf[blen]);
}
return i == blen ? 0 : -1;
}
DEFINE_WRC_COMMAND(w1r) = {
.name = "w1r",
.exec = cmd_w1_r,
};
/* A shell command, for checking */
static int cmd_w1(const char *args[])
{
int i;
struct w1_dev *d;
int32_t temp;
w1_scan_bus(&wrpc_w1_bus);
for (i = 0; i < W1_MAX_DEVICES; i++) {
d = wrpc_w1_bus.devs + i;
if (d->rom) {
pp_printf("device %i: %08x%08x\n", i,
(int)(d->rom >> 32), (int)d->rom);
temp = w1_read_temp(d, 0);
pp_printf("temp: %d.%04d\n", temp >> 16,
(int)((temp & 0xffff) * 10 * 1000 >> 16));
}
}
return 0;
}
DEFINE_WRC_COMMAND(w1) = {
.name = "w1",
.exec = cmd_w1,
};
/*
* Temperature input for DS18S20 (family 0x10)
* Alessandro Rubini, 2013 GNU GPL2 or later
*/
#include <wrc.h>
#include <w1.h>
int32_t w1_read_temp(struct w1_dev *dev, unsigned long flags)
{
static uint8_t scratchpad[8];
int class = w1_class(dev);
int32_t res;
int16_t cval;
int i;
/* The caller is expected to have checked the class. but still... */
switch(class) {
case 0x10: case 0x28: case 0x42:
break; /* Supported, at least for temperature input */
default:
return 1<<31; /* very negative */
}
/* If so asked, jump over start-conversion and only collect result */
if (flags & W1_FLAG_COLLECT)
goto collect;
w1_match_rom(dev);
w1_write_byte(dev->bus, W1_CMDT_CONVERT);
/* If so asked, don't wait for the conversion to be over */
if (flags & W1_FLAG_NOWAIT)
return 0;
while(wrpc_w1_ops.read_bit(dev->bus) == 0)
;
collect:
w1_match_rom(dev);
w1_write_byte(dev->bus, W1_CMDT_R_SPAD);
for (i = 0; i < sizeof(scratchpad); i++)
scratchpad[i] = w1_read_byte(dev->bus);
res = 0;
cval = scratchpad[1] << 8 | scratchpad[0];
switch(class) {
case 0x10:
/* 18S20: two bytes plus "count remain" value */
res = (int32_t)cval << 15; /* 1 decimal points */
res -= 0x4000; /* - 0.25 degrees */
res |= scratchpad[6] << 12; /* 1/16th of degree each */
break;
case 0x28:
case 0x42:
/* 18B20 and DS28EA00: only the two bytes */
res = (int32_t)cval << 12; /* 4 decimal points */
break;
}
return res;
}
int32_t w1_read_temp_bus(struct w1_bus *bus, unsigned long flags)
{
int i, class;
for (i = 0; i < W1_MAX_DEVICES; i++) {
class = w1_class(bus->devs + i);
switch(class) {
case 0x10: case 0x28: case 0x42:
return w1_read_temp(bus->devs + i, flags);
default:
break;
}
}
/* not found */
return 1 << 31;
}
/*
* Onewire generic interface
* Alessandro Rubini, 2013 GNU GPL2 or later
*/
#include <string.h>
#include <w1.h>
#include <unistd.h>
static const struct w1_ops *ops = &wrpc_w1_ops; /* local shorter name */
void w1_write_byte(struct w1_bus *bus, int byte)
{
int i;
for (i = 1; i < 0x100; i <<= 1)
ops->write_bit(bus, byte & i ? 1 : 0);
}
int w1_read_byte(struct w1_bus *bus)
{
int i, res = 0;
for (i = 1; i < 0x100; i <<= 1)
res |= ops->read_bit(bus) ? i : 0;
usleep(100); /* inter-byte, for my eyes only */
return res;
}
/* scan_bus requires this di-bit helper */
enum __bits {B_0, B_1, B_BOTH};
/* return what we get, select it if unambiguous or the one passed */
static enum __bits __get_dibit(struct w1_bus *bus, int select)
{
int a, b;
a = ops->read_bit(bus);
b = ops->read_bit(bus);
if (a != b) {
ops->write_bit(bus, a);
return a ? B_1 : B_0;
}
ops->write_bit(bus, select);
return B_BOTH;
}
/*
* This identifies one. Returns 0 if not found, -1 on error. The current mask
* is used to return the conflicts we found: on each conflict, we follow
* what's already in our id->rom, but remember it for later scans.
*/
static int __w1_scan_one(struct w1_bus *bus, uint64_t *rom, uint64_t *cmask)
{
uint64_t mask;
int select;
enum __bits b;
if (ops->reset(bus) != 1)
return -1;
w1_write_byte(bus, 0xf0); /* search rom */
/*
* Send all bits we have (initially, zero).
* On a conflict, follow what we have in rom and possibly mark it.
*/
*cmask = 0;
for (mask = 1; mask; mask <<= 1) {
select = *rom & mask;
b = __get_dibit(bus, select);
switch(b) {
case B_1:
*rom |= mask;
case B_0:
break;
case B_BOTH:
/* if we follow 1, it's resolved, else mark it */
if (!select)
*cmask |= mask;
break;
}
}
return 0;
}
int w1_scan_bus(struct w1_bus *bus)
{
uint64_t mask;
uint64_t cmask; /* current */
struct w1_dev *d;
int i;
memset(bus->devs, 0, sizeof(bus->devs));
if (!ops->reset)
return 0; /* no devices */
for (i = 0, cmask = 0; i < W1_MAX_DEVICES; i++) {
d = bus->devs + i;
d->bus = bus;
if (i) { /* Not first: scan conflicts and resolve last */
d->rom = bus->devs[i-1].rom;
for (mask = (1ULL<<63); mask; mask >>= 1) {
/*
* Warning: lm32 compiter treats as signed!
*
* Even if mask is uint64_t, the shift in the
* for loop above is signed, so fix it.
* I prefer not to change the loop, as the
* code is in use elsewhere and I prefer to
* keep differences to a minimum
*/
if (mask & (1ULL<<62))
mask = (1ULL<<62);
if (cmask & mask)
break;
d->rom &= ~mask;
}
if (!mask) {
/* no conflicts to solve: done */
return i;
}
d->rom |= mask; /* we'll reply 1 next loop */
cmask &= ~mask;
}
if (__w1_scan_one(bus, &d->rom, &cmask)) {
/* error on this one */
return i;
}
}
return i;
}
void w1_match_rom(struct w1_dev *dev)
{
int i;
ops->reset(dev->bus);
w1_write_byte(dev->bus, W1_CMD_MATCH_ROM); /* match rom */
for (i = 0; i < 64; i+=8) {
w1_write_byte(dev->bus, (int)(dev->rom >> i) );
}
}
#ifndef __BOARD_WRC_H
#define __BOARD_WRC_H
/*
* This is meant to be automatically included by the Makefile,
* when wrpc-sw is build for wrc (node) -- as opposed to wrs (switch)
*/
#include <hw/memlayout.h>
/* Board-specific parameters */
#define TICS_PER_SECOND 1000
/* WR Core system/CPU clock frequency in Hz */
#define CPU_CLOCK 62500000ULL
/* WR Reference clock period (picoseconds) and frequency (Hz) */
#define REF_CLOCK_PERIOD_PS 8000
#define REF_CLOCK_FREQ_HZ 125000000
/* Baud rate of the builtin UART (does not apply to the VUART) */
#define UART_BAUDRATE 115200ULL
/* Maximum number of simultaneously created sockets */
#define NET_MAX_SOCKETS 4
/* Socket buffer size, determines the max. RX packet size */
#define NET_SKBUF_SIZE 512
/* Number of auxillary clock channels - usually equal to the number of FMCs */
#define NUM_AUX_CLOCKS 1
int board_init();
int board_update();
/* spll parameter that are board-specific */
#define BOARD_DIVIDE_DMTD_CLOCKS 1
#define BOARD_MAX_CHAN_REF 1
#define BOARD_MAX_CHAN_AUX 2
#define BOARD_MAX_PTRACKERS 1
#endif /* __BOARD_WRC_H */
#ifndef __BOARD_H
#define __BOARD_H
#define TICS_PER_SECOND 100000
#define CPU_CLOCK 62500000
#define REF_CLOCK_FREQ_HZ 62500000
#define REF_CLOCK_PERIOD_PS 16000
#define UART_BAUDRATE 115200
/* RT CPU Memory layout */
#define BASE_UART 0x10000
#define BASE_SOFTPLL 0x10100
#define BASE_SPI 0x10200
#define BASE_GPIO 0x10300
#define BASE_TIMER 0x10400
#define BASE_PPS_GEN 0x10500
/* spll parameter that are board-specific */
#define BOARD_DIVIDE_DMTD_CLOCKS 0
#define BOARD_MAX_CHAN_REF 18
#define BOARD_MAX_CHAN_AUX 1
#define BOARD_MAX_PTRACKERS 18
#endif
/*
* We build for both wr-switch and wr-node (core).
*
* Unfortunately, our submodules include <board.h> without using
* our own Kconfig defines. Thus, assume wr-node unless building
* specifically for wr-switch (which doesn't refer to submodules).
* Same appplies to ./tools/, where we can avoid a Makefile
* patch for add "-include ../include/generated/autoconf.h"
*/
#if defined(CONFIG_WR_SWITCH)
# include "board-wrs.h"
#else
# include "board-wrc.h"
#endif
#ifndef __DBG_H__
#define __DBG_H__
/*
* This header includes all generic prototypes that were missing
* in earlier implementations. For example, the monitor is only
* one function and doesn't deserve an header of its own.
* Also, this brings in very common and needed headers
*/
#include <inttypes.h>
#include <pp-printf.h>
#define mprintf pp_printf
#define vprintf pp_vprintf
#define sprintf pp_sprintf
#undef offsetof
#define offsetof(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER)
#undef ARRAY_SIZE
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
void shell_init(void);
void kernel_dev(int subsys, const char *fmt, ...);
void mprint_64bit (uint64_t value);
#endif /* __DBG_H__ */
#ifndef __EEPROM_H
#define __EEPROM_H
#define SFP_SECTION_PATTERN 0xdeadbeef
#define SFPS_MAX 4
#define SFP_PN_LEN 16
#define EE_BASE_CAL 4*1024
#define EE_BASE_SFP 4*1024+4
#define EE_BASE_INIT 4*1024+SFPS_MAX*29
#define EE_RET_I2CERR -1
#define EE_RET_DBFULL -2
#define EE_RET_CORRPT -3
#define EE_RET_POSERR -4
extern int32_t sfp_alpha;
extern int32_t sfp_deltaTx;
extern int32_t sfp_deltaRx;
extern uint32_t cal_phase_transition;
extern uint8_t has_eeprom;
struct s_sfpinfo {
char pn[SFP_PN_LEN];
int32_t alpha;
int32_t dTx;
int32_t dRx;
uint8_t chksum;
} __attribute__ ((__packed__));
uint8_t eeprom_present(uint8_t i2cif, uint8_t i2c_addr);
int32_t eeprom_sfpdb_erase(uint8_t i2cif, uint8_t i2c_addr);
int32_t eeprom_sfp_section(uint8_t i2cif, uint8_t i2c_addr, size_t size,
uint16_t * section_sz);
int8_t eeprom_match_sfp(uint8_t i2cif, uint8_t i2c_addr, struct s_sfpinfo *sfp);
int8_t eeprom_phtrans(uint8_t i2cif, uint8_t i2c_addr, uint32_t * val,
uint8_t write);
int8_t eeprom_init_erase(uint8_t i2cif, uint8_t i2c_addr);
int8_t eeprom_init_add(uint8_t i2cif, uint8_t i2c_addr, const char *args[]);
int32_t eeprom_init_show(uint8_t i2cif, uint8_t i2c_addr);
int8_t eeprom_init_readcmd(uint8_t i2cif, uint8_t i2c_addr, uint8_t *buf,
uint8_t bufsize, uint8_t next);
int32_t eeprom_get_sfp(uint8_t i2cif, uint8_t i2c_addr, struct s_sfpinfo * sfp,
uint8_t add, uint8_t pos);
#endif
/*
* The "official" fine-delay API
*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2 as published by the Free Software Foundation or, at your
* option, any later version.
*/
#ifndef __FDELAY_H__
#define __FDELAY_H__
#include <stdint.h>
#include "fine-delay.h"
#include <linux/math64.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
/* Convenience macro for converting the physical output connector
numbers (as seen on the mezzanine's front panel) to convention used
by the drive (0..3). We keep 0..3 indexing to maintain library
compatibility. */
#define FDELAY_OUTPUT_HW_TO_USER(out) ((out) + 1)
#define FDELAY_OUTPUT_USER_TO_HW(out) ((out) - 1)
extern struct fd_dev fd;
struct fdelay_time {
uint64_t utc;
uint32_t coarse;
uint32_t frac;
uint32_t seq_id;
uint32_t channel;
};
/* The structure used for pulse generation */
struct fdelay_pulse {
/* FD_OUT_MODE_DISABLED, FD_OUT_MODE_DELAY, FD_OUT_MODE_PULSE */
int mode;
/* -1 == infinite */
int rep;
struct fdelay_time start;
struct fdelay_time end;
struct fdelay_time loop;
};
/* An alternative structure, internally converted to the previous one */
struct fdelay_pulse_ps {
int mode;
int rep;
struct fdelay_time start;
uint64_t length;
uint64_t period;
};
extern void fdelay_pico_to_time(uint64_t *pico, struct fdelay_time *time);
extern void fdelay_time_to_pico(struct fdelay_time *time, uint64_t *pico);
extern int fdelay_config_pulse(struct fd_dev *fd,
int channel, struct fdelay_pulse *pulse);
extern int fdelay_config_pulse_ps(struct fd_dev *fd,
int channel, struct fdelay_pulse_ps *ps);
extern int fdelay_get_config_pulse_ps(struct fd_dev *fd,
int channel, struct fdelay_pulse_ps *ps);
#endif /* __FDELAY_H__ */
This diff is collapsed.
#ifndef __FMC_H__
#define __FMC_H__
#include <sys/types.h>
#include <stdlib.h>
#include <stdint.h>
#define FMC_MAX_CARDS 32
extern int usleep(useconds_t usec);
struct device {}; /* Trick or treat! */
/*
* Yeah! I know it looks bad, and 0f course it is not ellegant but if any other
* of the structure fields needs to be used this monstes makes the work faster
*/
struct fmc_device {
//unsigned long version;
//unsigned long flags;
//struct module *owner; /* char device must pin it */
// struct fmc_fru_id id; /* for EEPROM-based match */
// struct fmc_operations *op; /* carrier-provided */
// int irq; /* according to host bus. 0 == none */
int eeprom_len; /* Usually 8kB, may be less */
int eeprom_addr; /* 0x50, 0x52 etc */
uint8_t *eeprom; /* Full contents or leading part */
// char *carrier_name; /* "SPEC" or similar, for special use */
// void *carrier_data; /* "struct spec *" or equivalent */
// __iomem void *fpga_base; /* May be NULL (Etherbone) */
// __iomem void *slot_base; /* Set by the driver */
// struct fmc_device **devarray; /* Allocated by the bus */
// int slot_id; /* Index in the slot array */
// int nr_slots; /* Number of slots in this carrier */
// unsigned long memlen; /* Used for the char device */
struct device dev; /* For Linux use */
struct device *hwdev; /* The underlying hardware device */
// unsigned long sdbfs_entry;
// struct sdb_array *sdb;
// uint32_t device_id; /* Filled by the device */
// char *mezzanine_name; /* Defaults to ``fmc'' */
// void *mezzanine_data;
};
static inline uint32_t fmc_readl(struct fmc_device *fmc, int offset)
{
uint32_t *p= (uint32_t *) offset;
/* Looks unncessary? Yes, it does. But for any reason it works better than
* usleep(x). So you'd better don't remove it
*/
if (offset >= 0x480500 && offset < 0x490000)
mprintf("[READ ]: fmc_readl -> Dir %08X val %08X\n", p, *p);
return *p;
}
static inline void fmc_writel(struct fmc_device *fmc, uint32_t val, int off)
{
uint32_t *p = (uint32_t *) off;
*p = val;
}
#endif __FMC_H__
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#ifndef __REGS_H
#define __REGS_H
#define SDB_ADDRESS 0x20800
extern unsigned char *BASE_MINIC;
extern unsigned char *BASE_EP;
extern unsigned char *BASE_SOFTPLL;
extern unsigned char *BASE_PPS_GEN;
extern unsigned char *BASE_SYSCON;
extern unsigned char *BASE_UART;
extern unsigned char *BASE_ONEWIRE;
extern unsigned char *BASE_ETHERBONE_CFG;
extern unsigned char *BASE_FINE_DELAY;
extern unsigned char *BASE_WRPC_RAM;
#define FMC_EEPROM_ADR 0x50
void sdb_find_devices(void);
void sdb_print_devices(void);
#endif
This diff is collapsed.
#ifndef __TICS_H__
#define __TICS_H__
#include <stdint.h>
#define jiffies get_tics()
extern unsigned char *BASE_TICS;
static inline uint32_t get_tics(){
uint32_t *p = (uint32_t *) BASE_TICS;
return abs(*p);
};
#endif /* __TICS_H__ */
This diff is collapsed.
This diff is collapsed.
#ifndef __I2C_H
#define __I2C_H
uint8_t mi2c_devprobe(uint8_t i2cif, uint8_t i2c_addr);
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
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