Commit a76ac52d authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

added device drivers

parents
#include <stdio.h>
#include "board.h"
#include <hw/endpoint_regs.h>
#include <hw/endpoint_mdio.h>
#define DMTD_AVG_SAMPLES 256
#define DMTD_MAX_PHASE 16384
#define UIS_PER_SERIAL_BIT 800
static int autoneg_enabled;
static volatile struct EP_WB *EP = (volatile struct EP_WB *) BASE_EP;
/* functions for accessing PCS registers */
static uint16_t pcs_read(int location)
{
EP->MDIO_CR = EP_MDIO_CR_ADDR_W(location >> 2);
while ((EP->MDIO_SR & EP_MDIO_SR_READY) == 0);
return EP_MDIO_SR_RDATA_R(EP->MDIO_SR) & 0xffff;
}
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_SR & EP_MDIO_SR_READY) == 0);
}
static void set_mac_addr(uint8_t dev_addr[])
{
EP->MACL = ((uint32_t)dev_addr[3] << 24)
| ((uint32_t)dev_addr[2] << 16)
| ((uint32_t)dev_addr[1] << 8)
| ((uint32_t)dev_addr[0]);
EP->MACH = ((uint32_t)dev_addr[5] << 8)
| ((uint32_t)dev_addr[4]);
}
void ep_init(uint8_t mac_addr[])
{
int i;
set_mac_addr(mac_addr);
EP->ECR = 0;
EP->DMCR = EP_DMCR_EN | EP_DMCR_N_AVG_W(DMTD_AVG_SAMPLES);
EP->RFCR = 3 << EP_RFCR_QMODE_SHIFT;
EP->TSCR = EP_TSCR_EN_TXTS | EP_TSCR_EN_RXTS;
EP->FCR = 0;
}
int ep_enable(int enabled, int autoneg)
{
uint16_t mcr;
if(!enabled)
{
EP->ECR = 0;
return;
}
EP->ECR = EP_ECR_TX_EN_FRA | EP_ECR_RX_EN_FRA | EP_ECR_RST_CNT;
autoneg_enabled = autoneg;
pcs_write(MDIO_REG_MCR, MDIO_MCR_RESET); /* reset the PHY */
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);
}
int ep_link_up()
{
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);
return (msr & flags) == flags ? 1 : 0;
}
int ep_get_deltas(uint32_t *delta_tx, uint32_t *delta_rx)
{
*delta_tx = 0;
*delta_rx = UIS_PER_SERIAL_BIT * MDIO_WR_SPEC_BSLIDE_R(pcs_read(MDIO_REG_WR_SPEC));
}
void ep_show_counters()
{
int i;
for(i=0;i<16;i++)
mprintf("cntr%d = %d\n", i, EP->RMON_RAM[i]);
}
#include <stdio.h>
#include "types.h"
#include "board.h"
#include "pps_gen.h" /* for pps_gen_get_time() */
#include "minic.h"
#include <hw/minic_regs.h>
#define MINIC_DMA_TX_BUF_SIZE 1024
#define MINIC_DMA_RX_BUF_SIZE 2048
#define MINIC_MTU 1540
#define F_COUNTER_BITS 4
#define F_COUNTER_MASK ((1<<F_COUNTER_BITS)-1)
#define RX_DESC_VALID(d) ((d) & (1<<31) ? 1 : 0)
#define RX_DESC_ERROR(d) ((d) & (1<<30) ? 1 : 0)
#define RX_DESC_HAS_OOB(d) ((d) & (1<<29) ? 1 : 0)
#define RX_DESC_SIZE(d) (((d) & (1<<0) ? -1 : 0) + (d & 0xfffe))
#define TX_DESC_VALID (1<<31)
#define TX_DESC_WITH_OOB (1<<30)
#define TX_DESC_HAS_OWN_MAC (1<<28)
#define RX_OOB_SIZE 6
#define REFCLK_FREQ 125000000
#define ETH_HEADER_SIZE 14
// extracts the values of TS rising and falling edge counters from the descriptor header
#define EXPLODE_WR_TIMESTAMP(raw, rc, fc) \
rc = (raw) & 0xfffffff; \
fc = (raw >> 28) & 0xf;
static volatile uint32_t dma_tx_buf[MINIC_DMA_RX_BUF_SIZE / 4];
static volatile uint32_t dma_rx_buf[MINIC_DMA_TX_BUF_SIZE / 4];
struct wr_minic {
volatile uint32_t *rx_head, *rx_base;
uint32_t rx_avail, rx_size;
volatile uint32_t *tx_head, *tx_base;
uint32_t tx_avail, tx_size;
int synced;
int syncing_counters;
int iface_up;
uint32_t cur_rx_desc;
};
static struct wr_minic minic;
static inline void minic_writel(uint32_t reg,uint32_t data)
{
*(volatile uint32_t *) (BASE_MINIC + reg) = data;
}
static inline uint32_t minic_readl(uint32_t reg)
{
return *(volatile uint32_t *)(BASE_MINIC + reg);
}
static void minic_new_rx_buffer()
{
minic.rx_head = minic.rx_base;
minic_writel(MINIC_REG_MCR, 0);
minic_writel(MINIC_REG_RX_ADDR, (uint32_t) minic.rx_base);
minic_writel(MINIC_REG_RX_AVAIL, (minic.rx_size - MINIC_MTU) >> 2);
minic_writel(MINIC_REG_MCR, MINIC_MCR_RX_EN);
}
static void minic_new_tx_buffer()
{
minic.tx_head = minic.tx_base;
minic.tx_avail = (minic.tx_size - MINIC_MTU) >> 2;
minic_writel(MINIC_REG_TX_ADDR, (uint32_t) minic.tx_base);
}
void minic_init()
{
minic.rx_base = dma_rx_buf;
minic.rx_size = sizeof(dma_rx_buf);
minic.tx_base = dma_tx_buf;
minic.tx_size = sizeof(dma_tx_buf);
minic_new_rx_buffer();
minic_writel(MINIC_REG_EIC_IER, MINIC_EIC_IER_RX);
}
int minic_poll_rx()
{
uint32_t isr;
isr = minic_readl(MINIC_REG_EIC_ISR);
return isr;
}
int minic_rx_frame(uint8_t *hdr, uint8_t *payload, uint32_t buf_size, struct hw_timestamp *hwts)
{
uint32_t payload_size, num_words;
uint32_t desc_hdr;
uint32_t raw_ts;
uint32_t rx_addr_cur;
int i;
int n_recvd;
if(! (minic_readl(MINIC_REG_EIC_ISR) & MINIC_EIC_ISR_RX))
return 0;
desc_hdr = *minic.rx_head;
if(!RX_DESC_VALID(desc_hdr)) /* invalid descriptor? Weird, the RX_ADDR seems to be saying something different. Ignore the packet and purge the RX buffer. */
{
// mprintf("weird, invalid RX descriptor (%x, head %x)\n", desc_hdr, rx_head);
minic_new_rx_buffer();
return 0;
}
payload_size = RX_DESC_SIZE(desc_hdr);
num_words = ((payload_size + 3) >> 2) + 1;
/* valid packet */
if(!RX_DESC_ERROR(desc_hdr))
{
if(RX_DESC_HAS_OOB(desc_hdr) && hwts != NULL)
{
uint32_t counter_r, counter_f, counter_ppsg, utc;
int cntr_diff;
payload_size -= RX_OOB_SIZE;
memcpy(&raw_ts, (uint8_t *)minic.rx_head + payload_size + 6, 4); /* fixme: ugly way of doing unaligned read */
EXPLODE_WR_TIMESTAMP(raw_ts, counter_r, counter_f);
pps_gen_get_time(&utc, &counter_ppsg);
if(counter_r > (3*REFCLK_FREQ/4) && counter_ppsg < REFCLK_FREQ/4)
utc--;
hwts->utc = utc & 0x7fffffff ;
cntr_diff = (counter_r & F_COUNTER_MASK) - counter_f;
if(cntr_diff == 1 || cntr_diff == (-F_COUNTER_MASK))
hwts->ahead = 1;
else
hwts->ahead = 0;
hwts->nsec = counter_r * 8;
}
n_recvd = (buf_size < payload_size ? buf_size : payload_size);
/* FIXME: VLAN support */
memcpy(hdr, (void*)minic.rx_head + 4, ETH_HEADER_SIZE);
memcpy(payload, (void*)minic.rx_head + 4 + ETH_HEADER_SIZE, n_recvd - ETH_HEADER_SIZE);
/* for(i=0;i<n_recvd;i++)
mprintf("%x ", buf[i]);
mprintf("---\n");*/
minic.rx_head += num_words;
} else { // RX_DESC_ERROR
minic.rx_head += num_words;
}
rx_addr_cur = minic_readl(MINIC_REG_RX_ADDR) & 0xffff;
if(rx_addr_cur < (uint32_t)minic.rx_head) /* nothing new in the buffer? */
{
if(minic_readl(MINIC_REG_MCR) & MINIC_MCR_RX_FULL)
minic_new_rx_buffer();
minic_writel(MINIC_REG_EIC_ISR, MINIC_EIC_ISR_RX);
}
return n_recvd;
}
static uint16_t tx_oob_val = 0;
int minic_tx_frame(uint8_t *hdr, uint8_t *payload, uint32_t size, struct hw_timestamp *hwts)
{
uint32_t d_hdr, mcr, nwords;
minic_new_tx_buffer();
nwords = ((size + 1) >> 1) - 1;
memset(minic.tx_head, 0x0, size + 16);
memcpy((void*)minic.tx_head + 4, hdr, ETH_HEADER_SIZE);
memcpy((void*)minic.tx_head + 4 + ETH_HEADER_SIZE, payload, size - ETH_HEADER_SIZE);
if(hwts)
{
memcpy((void *) minic.tx_head + 4 + size, &tx_oob_val, sizeof(uint16_t));
nwords++;
d_hdr = TX_DESC_WITH_OOB;
} else
d_hdr = 0;
d_hdr |= TX_DESC_VALID | nwords;
*(volatile uint32_t *)(minic.tx_head) = d_hdr;
*(volatile uint32_t *)(minic.tx_head + nwords) = 0;
mcr = minic_readl(MINIC_REG_MCR);
minic_writel(MINIC_REG_MCR, mcr | MINIC_MCR_TX_START);
if(hwts) /* wait for the timestamp */
{
uint32_t raw_ts;
uint16_t fid;
uint32_t counter_r, counter_f;
uint32_t utc;
uint32_t nsec;
while(minic_readl(MINIC_REG_TSFIFO_CSR) & MINIC_TSFIFO_CSR_EMPTY);
raw_ts = minic_readl(MINIC_REG_TSFIFO_R0);
fid = (minic_readl(MINIC_REG_TSFIFO_R1) >> 5) & 0xffff;
EXPLODE_WR_TIMESTAMP(raw_ts, counter_r, counter_f);
pps_gen_get_time(&utc, &nsec);
if(counter_r > (3*REFCLK_FREQ/4) && nsec < REFCLK_FREQ/4)
utc--;
hwts->utc = utc;
hwts->ahead = 0;
hwts->nsec = counter_r * 8;
}
tx_oob_val++;
return size;
}
#include "board.h"
#include <inttypes.h>
#include <hw/pps_gen_regs.h>
#define PPS_PULSE_WIDTH 100000
static inline void ppsg_writel(uint32_t reg,uint32_t data)
{
*(volatile uint32_t *) (BASE_PPSGEN + reg) = data;
}
static inline uint32_t ppsg_readl(uint32_t reg)
{
return *(volatile uint32_t *)(BASE_PPSGEN + reg);
}
void pps_gen_init()
{
uint32_t cr;
cr = PPSG_CR_CNT_EN | PPSG_CR_PWIDTH_W(PPS_PULSE_WIDTH);
ppsg_writel( PPSG_REG_CR, cr);
ppsg_writel( PPSG_REG_ADJ_UTCLO, 1285700840);
ppsg_writel( PPSG_REG_ADJ_UTCHI, 0);
ppsg_writel( PPSG_REG_ADJ_NSEC, 0);
ppsg_writel( PPSG_REG_CR, cr | PPSG_CR_CNT_SET);
ppsg_writel( PPSG_REG_CR, cr);
}
void pps_gen_adjust_nsec(int32_t how_much)
{
uint32_t cr;
mprintf("AdjustPPS: %d nanoseconds\n", how_much);
ppsg_writel( PPSG_REG_ADJ_UTCLO, 0);
ppsg_writel( PPSG_REG_ADJ_UTCHI, 0);
ppsg_writel( PPSG_REG_ADJ_NSEC, ( how_much / 8 ));
ppsg_writel( PPSG_REG_CR, PPSG_CR_CNT_EN | PPSG_CR_PWIDTH_W(PPS_PULSE_WIDTH) | PPSG_CR_CNT_ADJ);
}
void shw_pps_gen_adjust_utc(int32_t how_much)
{
uint32_t cr;
mprintf("AdjustUTC: %d seconds\n", how_much);
ppsg_writel( PPSG_REG_ADJ_UTCLO, how_much);
ppsg_writel( PPSG_REG_ADJ_UTCHI, 0);
ppsg_writel( PPSG_REG_ADJ_NSEC, 0);
ppsg_writel( PPSG_REG_CR, PPSG_CR_CNT_EN | PPSG_CR_PWIDTH_W(PPS_PULSE_WIDTH) | PPSG_CR_CNT_ADJ);
}
int pps_gen_busy()
{
return ppsg_readl(PPSG_REG_CR) & PPSG_CR_CNT_ADJ ? 0 : 1;
}
void pps_gen_get_time(uint32_t *utc, uint32_t *cntr_nsec)
{
uint32_t cyc_before, cyc_after;
uint32_t utc_lo;
do {
cyc_before =ppsg_readl(PPSG_REG_CNTR_NSEC) & 0xfffffff;
utc_lo = ppsg_readl(PPSG_REG_CNTR_UTCLO) ;
cyc_after = ppsg_readl(PPSG_REG_CNTR_NSEC) & 0xfffffff;
} while (cyc_after < cyc_before);
if(utc) *utc = utc_lo;
if(cntr_nsec) *cntr_nsec = cyc_after;
}
#include "board.h"
volatile int irq_cnt = 0;
__attribute__((interrupt)) void softpll_irq()
{
irq_cnt++;
uart_write_byte('x');
}
\ No newline at end of file
#include "board.h"
#include "timer.h"
uint32_t timer_get_tics()
{
return *(volatile uint32_t *) (BASE_TIMER);
}
void timer_delay(uint32_t how_long)
{
uint32_t t_start;
t_start = timer_get_tics();
while(t_start + how_long > timer_get_tics());
}
#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))
static volatile struct UART_WB *uart = (volatile struct UART_WB *) BASE_UART;
void uart_init()
{
uart->BCR = CALC_BAUD(UART_BAUDRATE);
}
void uart_write_byte(unsigned char x)
{
while(uart->SR & UART_SR_TX_BUSY);
uart->TDR = x;
}
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