Commit d294af4f authored by Alessandro Rubini's avatar Alessandro Rubini

userspace: remove phy_calibration.c

parent c64ef011
...@@ -5,7 +5,7 @@ CFLAGS = -I. -O2 -I../include -DDEBUG -I./minilzo ...@@ -5,7 +5,7 @@ CFLAGS = -I. -O2 -I../include -DDEBUG -I./minilzo
OBJS = pio.o pio_pins.o trace.o init.o fpga_io.o util.o ad9516.o \ OBJS = pio.o pio_pins.o trace.o init.o fpga_io.o util.o ad9516.o \
fpgaboot.o minilzo/minilzo.o clkb_io.o xpoint.o \ fpgaboot.o minilzo/minilzo.o clkb_io.o xpoint.o \
mblaster.o phy_calibration.o pps_gen.o watchdog.o mblaster.o pps_gen.o watchdog.o
LIB = libswitchhw.a LIB = libswitchhw.a
......
...@@ -34,7 +34,7 @@ int shw_init() ...@@ -34,7 +34,7 @@ int shw_init()
/* no more shw_hpll_init(); */ /* no more shw_hpll_init(); */
/* no more shw_dmpll_init(); */ /* no more shw_dmpll_init(); */
/* Initialize the calibrator (requires the DMTD clock to be operational) */ /* Initialize the calibrator (requires the DMTD clock to be operational) */
assert_init(shw_cal_init()); /* no more shw_cal_init(); */
/* Start-up the PPS generator */ /* Start-up the PPS generator */
assert_init(shw_pps_gen_init()); assert_init(shw_pps_gen_init());
/* ... and the SPI link with the watchdog */ /* ... and the SPI link with the watchdog */
......
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <asm/types.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <sys/ioctl.h>
#include <hw/switch_hw.h>
#include <hw/phy_calibration.h>
#include <hw/dmtd_calibrator_regs.h>
#include <hw/clkb_io.h>
#define CAL_DMTD_AVERAGING_STEPS 256
#define PORT_UPLINK 0
#define PORT_DOWNLINK 1
//driver-specific private ioctls
#define PRIV_IOCGCALIBRATE (SIOCDEVPRIVATE+1)
#define PRIV_IOCGGETPHASE (SIOCDEVPRIVATE+2)
#define CAL_CMD_TX_ON 1
#define CAL_CMD_TX_OFF 2
#define CAL_CMD_RX_ON 3
#define CAL_CMD_RX_OFF 4
#define CAL_CMD_RX_CHECK 5
struct wrmch_calibration_req {
int cmd;
int cal_present;
};
struct wrmch_phase_req {
int ready;
uint32_t phase;
};
static int cal_socket;
static char cal_current_if[16];
static int cal_in_progress = 0;
static int cal_current_lane ;
static int cal_current_port_index;
static int cal_current_port_type;
#define UPLINK_CAL_IN_UP0_RBCLK 0
#define UPLINK_CAL_IN_UP1_RBCLK 1
#define UPLINK_CAL_IN_REFCLK 2
#define DOWNLINK_CAL_IN_REFCLK 0
#define DOWNLINK_CAL_IN_RBCLK(x) (x+1)
static int uplink_calibrator_configure(int n_avg, int lane, int index)
{
int input;
if(lane == PHY_CALIBRATE_TX)
input = UPLINK_CAL_IN_REFCLK;
else if(lane == PHY_CALIBRATE_RX)
{
if(index == 0)
input = UPLINK_CAL_IN_UP0_RBCLK;
else
input = UPLINK_CAL_IN_UP1_RBCLK;
}
shw_clkb_write_reg(CLKB_BASE_CALIBRATOR + DPC_REG_CR, 0);
shw_clkb_write_reg(CLKB_BASE_CALIBRATOR + DPC_REG_CR, DPC_CR_EN | DPC_CR_N_AVG_W(n_avg) | DPC_CR_IN_SEL_W(input));
}
int route_order[8] = {0,1,2,3,4,5,6,7};
static int downlink_calibrator_configure(int n_avg, int lane, int index)
{
int input;
if(lane == PHY_CALIBRATE_TX)
input = DOWNLINK_CAL_IN_REFCLK;
else if(lane == PHY_CALIBRATE_RX)
{
input = DOWNLINK_CAL_IN_RBCLK(route_order[index]);
}
_fpga_writel(FPGA_BASE_CALIBRATOR + DPC_REG_CR, 0);
_fpga_writel(FPGA_BASE_CALIBRATOR + DPC_REG_CR, DPC_CR_EN | DPC_CR_N_AVG_W(n_avg) | DPC_CR_IN_SEL_W(input));
}
static int uplink_calibrator_measure(int *phase_raw)
{
uint32_t rval;
rval = shw_clkb_read_reg(CLKB_BASE_CALIBRATOR + DPC_REG_SR);
fprintf(stderr,"UplinkCalMeas: rval %x cr %x\n", rval, shw_clkb_read_reg(CLKB_BASE_CALIBRATOR+DPC_REG_CR));
if(rval & DPC_SR_PS_RDY)
{
shw_clkb_write_reg(CLKB_BASE_CALIBRATOR + DPC_REG_SR, 0xffffffff);
*phase_raw = (rval & (1<<23) ? 0xff000000 | rval : (rval & 0xffffff));
return 1;
}
return 0;
}
static int downlink_calibrator_measure(int *phase_raw)
{
uint32_t rval;
rval = _fpga_readl(FPGA_BASE_CALIBRATOR + DPC_REG_SR);
if(rval & DPC_SR_PS_RDY)
{
_fpga_writel(FPGA_BASE_CALIBRATOR + DPC_REG_SR, 0xffffffff);
*phase_raw = (rval & (1<<23) ? 0xff000000 | rval : (rval & 0xffffff));
return 1;
}
return 0;
}
static int decode_port_name(const char *if_name, int *type, int *index)
{
if(strlen(if_name) != 4)
return -1;
if( if_name[3] < '0' || if_name[3] > '7')
return -1;
*index = if_name[3] - '0';
if(!strncmp(if_name, "wru", 3))
*type = PORT_UPLINK;
else if(!strncmp(if_name, "wrd", 3))
*type = PORT_DOWNLINK;
else return -1;
return 0;
}
static int do_net_ioctl(const char *if_name, int request, void *data)
{
struct ifreq ifr;
ifr.ifr_addr.sa_family = AF_PACKET;
strcpy(ifr.ifr_name, if_name);
ifr.ifr_data = data;
int rv = ioctl(cal_socket, request, &ifr);
return rv;
}
int shw_cal_init()
{
TRACE(TRACE_INFO,"Initializing PHY calibrators...");
cal_in_progress = 0;
// create a raw socket for calibration/DMTD readout
cal_socket = socket(AF_PACKET, SOCK_DGRAM, 0);
if(cal_socket < 0)
return -1;
return xpoint_configure();
}
int shw_cal_enable_pattern(const char *if_name, int enable)
{
int type, index, rval;
struct wrmch_calibration_req crq;
// TRACE(TRACE_INFO,"port %s enable %d", if_name, enable);
if((rval=decode_port_name(if_name, &type, &index)) < 0) return rval;
crq.cmd = enable ? CAL_CMD_TX_ON : CAL_CMD_TX_OFF;
if(type == PORT_UPLINK)
{
if(do_net_ioctl(if_name, PRIV_IOCGCALIBRATE, &crq) < 0)
{
TRACE(TRACE_ERROR, "Can't send TX calibration pattern");
return -1;
}
}
return 0;
}
int shw_cal_enable_feedback(const char *if_name, int enable, int lane)
{
int type, index, rval;
struct wrmch_calibration_req crq;
// TRACE(TRACE_INFO,"port %s enable %d lane %d", if_name, enable, lane);
if((rval=decode_port_name(if_name, &type, &index)) < 0) return rval;
// TRACE(TRACE_INFO, "enable_feedback type:%d index:%d\n", type, index);
cal_current_lane = lane;
cal_current_port_index = index;
cal_current_port_type = type;
strcpy(cal_current_if, if_name);
if(type == PORT_UPLINK)
{
if(enable)
{
switch(lane)
{
case PHY_CALIBRATE_TX:
cal_in_progress = 1;
xpoint_cal_feedback(1, index, 0); // enable PHY TX line feedback
// TRACE(TRACE_INFO, "TX index %d", index);
uplink_calibrator_configure(CAL_DMTD_AVERAGING_STEPS, lane, index);
break;
case PHY_CALIBRATE_RX:
cal_in_progress = 1;
xpoint_cal_feedback(1, index, 1); // enable PHY RX line feedback
crq.cmd = CAL_CMD_RX_ON;
if(do_net_ioctl(if_name, PRIV_IOCGCALIBRATE, &crq) < 0)
{
TRACE(TRACE_ERROR, "Can't enable RX calibration pattern");
return -1;
}
// crq.cmd = CAL_CMD_TX_ON;
// if(do_net_ioctl(if_name, &crq) < 0) return -1;
uplink_calibrator_configure(CAL_DMTD_AVERAGING_STEPS, lane, index);
break;
}
} else { // enable == 0
TRACE(TRACE_INFO, "Disabling calibration on port: %s", if_name);
cal_in_progress = 0;
xpoint_cal_feedback(0, 0, 0);
if(lane == PHY_CALIBRATE_TX)
{
crq.cmd = CAL_CMD_TX_OFF;
if(do_net_ioctl(if_name, PRIV_IOCGCALIBRATE, &crq) < 0) return -1;
} else if (lane == PHY_CALIBRATE_RX)
{
crq.cmd = CAL_CMD_RX_OFF;
if(do_net_ioctl(if_name, PRIV_IOCGCALIBRATE, &crq) < 0) return -1;
}
}
} else if(type == PORT_DOWNLINK)
{
TRACE(TRACE_ERROR, "Sorry, no downlinks support yet...\n");
return -1;
}
}
int shw_cal_measure(uint32_t *phase)
{
int phase_raw;
struct wrmch_calibration_req crq;
if(!cal_in_progress)
return -1;
if(cal_current_port_type == PORT_UPLINK)
{
switch(cal_current_lane)
{
case PHY_CALIBRATE_TX:
fprintf(stderr,"CalTxMeasUplink\n");
if(uplink_calibrator_measure(&phase_raw))
{
*phase = (uint32_t) ((double) phase_raw / (double) CAL_DMTD_AVERAGING_STEPS / 1.0 /* shw_hpll_get_divider() */ * 8000.0);
return 1;
} else return 0;
break;
case PHY_CALIBRATE_RX:
crq.cmd = CAL_CMD_RX_CHECK;
if(do_net_ioctl(cal_current_if, PRIV_IOCGCALIBRATE, &crq) < 0) return -1;
if(crq.cal_present && uplink_calibrator_measure(&phase_raw))
{
*phase = (uint32_t) ((double) phase_raw / (double) CAL_DMTD_AVERAGING_STEPS / 1.0 /* shw_hpll_get_divider */ * 8000.0);
return 1;
} else return 0;
break;
}
} else {
// TRACE(TRACE_ERROR, "Sorry, no downlinks support yet...\n");
return -1;
}
}
int shw_poll_dmtd(const char *if_name, uint32_t *phase_ps)
{
struct wrmch_phase_req phr;
int r;
r = do_net_ioctl(if_name, PRIV_IOCGGETPHASE, &phr);
if(r < 0)
{
TRACE(TRACE_ERROR, "failed ioctl(PRIV_IOCGGETPHASE): retval %d\n", r);
return -1;
}
if(!phr.ready) // No valid DMTD measurement?
return 0;
// TRACE(TRACE_INFO,"%s: phase %d", if_name, phr.phase);
*phase_ps = 0; /* So it compiles, but this file must die as well */
return 1;
}
...@@ -164,7 +164,6 @@ int hal_init_wripc() ...@@ -164,7 +164,6 @@ int hal_init_wripc()
wripc_export(hal_ipc, T_INT32, "halexp_pll_cmd", halexp_pll_cmd, 2, T_INT32, T_STRUCT(hexp_pll_cmd_t)); wripc_export(hal_ipc, T_INT32, "halexp_pll_cmd", halexp_pll_cmd, 2, T_INT32, T_STRUCT(hexp_pll_cmd_t));
wripc_export(hal_ipc, T_INT32, "halexp_check_running", halexp_check_running, 0); wripc_export(hal_ipc, T_INT32, "halexp_check_running", halexp_check_running, 0);
wripc_export(hal_ipc, T_STRUCT(hexp_port_state_t), "halexp_get_port_state", halexp_get_port_state, 1, T_STRING); wripc_export(hal_ipc, T_STRUCT(hexp_port_state_t), "halexp_get_port_state", halexp_get_port_state, 1, T_STRING);
wripc_export(hal_ipc, T_INT32, "halexp_calibration_cmd", halexp_calibration_cmd, 3, T_STRING, T_INT32, T_INT32);
wripc_export(hal_ipc, T_INT32, "halexp_lock_cmd", halexp_lock_cmd, 3, T_STRING, T_INT32, T_INT32); wripc_export(hal_ipc, T_INT32, "halexp_lock_cmd", halexp_lock_cmd, 3, T_STRING, T_INT32, T_INT32);
wripc_export(hal_ipc, T_STRUCT(hexp_port_list_t), "halexp_query_ports", halexp_query_ports, 0); wripc_export(hal_ipc, T_STRUCT(hexp_port_list_t), "halexp_query_ports", halexp_query_ports, 0);
......
...@@ -239,47 +239,7 @@ static int check_port_presence(const char *if_name) ...@@ -239,47 +239,7 @@ static int check_port_presence(const char *if_name)
(TX latency never changes as long as the TLK1221 PHY reference clock is enabled, (TX latency never changes as long as the TLK1221 PHY reference clock is enabled,
even if the link goes down) */ even if the link goes down) */
static int port_startup_tx_calibration(hal_port_state_t *p) /* No more calibration in V3 */
{
uint32_t raw_phase;
TRACE(TRACE_INFO,"Pre-calibratinmg TX for port %s", p->name);
/* Step 1. Enable transmission of the calibration pattern, so the calibrator DMTD has a meaningful
signal for phase measurement */
if(shw_cal_enable_pattern(p->name, 1) < 0)
return -1;
/* Step 2. Tell the crosspoint/mini-backlane to feed back the TX output of the PHY we want to calibrate
to the calibrator DMTD. */
if(shw_cal_enable_feedback(p->name, 1, PHY_CALIBRATE_TX) < 0)
{
shw_cal_enable_pattern(p->name, 0);
return -1;
}
/* Step 3. Measure the delay. fixme: remove this stupid usleep. */
while(!shw_cal_measure(&raw_phase))
usleep(1000);
/* Step 4. Convert the phase into the actual delay. The calibrator measures the phase difference (A-B) between
inputs A and B. A is the reference signal (REF clock for calibrating the TX path, port's RX clock for
calibrating the RX path), B is the feedback signal from the crosspoint (i.e. the calibration pattern
outputted/coming to the PHY being calibrated). In case of the TX ports (to respect casuality), the
phase has to be reversed. */
p->calib.delta_tx_phy = fix_phy_delay(8000-raw_phase, p->calib.phy_tx_bias, p->calib.phy_tx_min, p->calib.phy_tx_range);
p->calib.tx_calibrated = 1;
TRACE(TRACE_INFO, "port %s, delta_tx_phy = %d ps", p->name, p->calib.delta_tx_phy);
/* Step 5. Disable transmission of the calibration pattern, so the port can function normally. */
shw_cal_enable_pattern(p->name, 0);
return 0;
}
/* Port initialization. Assigns the MAC address, WR timing mode, reads parameters from the config file. */ /* Port initialization. Assigns the MAC address, WR timing mode, reads parameters from the config file. */
int hal_init_port(const char *name, int index) int hal_init_port(const char *name, int index)
...@@ -381,8 +341,7 @@ int hal_init_port(const char *name, int index) ...@@ -381,8 +341,7 @@ int hal_init_port(const char *name, int index)
p->mode = HEXP_PORT_MODE_NON_WR; p->mode = HEXP_PORT_MODE_NON_WR;
} }
/* pre-calibrate the TX path for each port */ /* Used to pre-calibrate the TX path for each port. No more in V3 */
port_startup_tx_calibration(p);
return 0; return 0;
} }
...@@ -463,15 +422,7 @@ static void port_locking_fsm(hal_port_state_t *p) ...@@ -463,15 +422,7 @@ static void port_locking_fsm(hal_port_state_t *p)
/* Updates the current value of the phase shift on a given port. Called by the main update function regularly. */ /* Updates the current value of the phase shift on a given port. Called by the main update function regularly. */
static void poll_dmtd(hal_port_state_t *p) static void poll_dmtd(hal_port_state_t *p)
{ {
uint32_t phase_val; /* FIXME: what should we do here? */
if(shw_poll_dmtd(p->name, &phase_val) > 0)
{
p->phase_val = phase_val;
p->phase_val_valid = 1;
} else {
p->phase_val_valid = 0;
};
} }
...@@ -494,38 +445,8 @@ static void calibration_fsm(hal_port_state_t *p) ...@@ -494,38 +445,8 @@ static void calibration_fsm(hal_port_state_t *p)
} }
/* Is there a calibration measurement in progress for this port? */ /* Is there a calibration measurement in progress for this port? */
if(p->tx_cal_pending || p->rx_cal_pending)
{
uint32_t phase;
/* Got the phase? */
if(shw_cal_measure(&phase) > 0)
{
TRACE(TRACE_INFO,"MeasuredPhase: %d", phase); /* no, not in V3 */
if(p->tx_cal_pending)
{
/* the TX path was being calibrated - unwrap the _reversed_ phase and store the resulting deltaTX. */
p->calib.tx_calibrated =1;
p->calib.raw_delta_tx_phy = 8000-phase;
p->calib.delta_tx_phy = fix_phy_delay(8000-phase, p->calib.phy_tx_bias, p->calib.phy_tx_min, p->calib.phy_tx_range);
TRACE(TRACE_INFO, "TXCal: raw %d fixed %d\n", phase, p->calib.delta_tx_phy);
p->tx_cal_pending = 0;
}
if(p->rx_cal_pending)
{
/* the RX path was being calibrated - unwrap the phase and store the resulting deltaRX. */
p->calib.rx_calibrated =1;
p->calib.raw_delta_rx_phy = phase;
p->calib.delta_rx_phy = fix_phy_delay(phase, p->calib.phy_rx_bias, p->calib.phy_rx_min, p->calib.phy_rx_range);
TRACE(TRACE_INFO, "RXCal: raw %d fixed %d\n", phase, p->calib.delta_rx_phy);
p->rx_cal_pending = 0;
}
}
}
} }
#if 0 #if 0
...@@ -719,95 +640,8 @@ static int any_port_calibrating() ...@@ -719,95 +640,8 @@ static int any_port_calibrating()
} }
/* Public function for controlling the calibration process. Called by the PTPd during WR Link setup. */ /* Public function for controlling the calibration process. Called by the PTPd during WR Link setup. */
int halexp_calibration_cmd(const char *port_name, int command, int on_off)
{
hal_port_state_t *p = lookup_port(port_name);
if(!p)
return -1;
switch(command) /* No more calibration in V3 */
{
/* Checks if the calibrator is idle (i.e. if there are no ports being currently calibrated). */
case HEXP_CAL_CMD_CHECK_IDLE:
return !any_port_calibrating() && p->state == HAL_PORT_STATE_UP ? HEXP_CAL_RESP_OK : HEXP_CAL_RESP_BUSY;
/* Returns raw deltaTx/Rx (debug only) */
case HEXP_CAL_CMD_GET_RAW_DELTA_RX:
return p->calib.raw_delta_rx_phy;
break;
case HEXP_CAL_CMD_GET_RAW_DELTA_TX:
return p->calib.raw_delta_tx_phy;
break;
/* Enables/disables transmission of the calibration pattern */
case HEXP_CAL_CMD_TX_PATTERN:
TRACE(TRACE_INFO, "TXPattern %s, port %s", on_off ? "ON" : "OFF", port_name);
// FIXME: add some error handling
if(on_off)
p->state = HAL_PORT_STATE_CALIBRATION;
else
p->state = HAL_PORT_STATE_UP;
shw_cal_enable_pattern(p->name, on_off);
return HEXP_CAL_RESP_OK;
break;
/* Enables/disables measurement of deltaTX on a particular port. The results are available
via halexp_get_port_state(). */
case HEXP_CAL_CMD_TX_MEASURE:
TRACE(TRACE_INFO, "TXMeasure %s, port %s", on_off ? "ON" : "OFF", port_name);
/* invalidate the result of the previous calibration */
p->calib.tx_calibrated = 0;
if(on_off)
{
p->tx_cal_pending = 1;
p->calib.tx_calibrated = 0;
shw_cal_enable_feedback(p->name, 1, PHY_CALIBRATE_TX);
/* Trigger the calibration FSM */
p->state = HAL_PORT_STATE_CALIBRATION;
return HEXP_CAL_RESP_OK;
} else {
/* Go back to the default port FSM state */
p->state = HAL_PORT_STATE_UP;
p->tx_cal_pending =0;
shw_cal_enable_feedback(p->name, 0, PHY_CALIBRATE_TX);
return HEXP_CAL_RESP_OK;
}
break;
/* The same thing, but for the RX path */
case HEXP_CAL_CMD_RX_MEASURE:
TRACE(TRACE_INFO, "RXMeasure %s, port %s", on_off ? "ON" : "OFF", port_name);
if(on_off)
{
p->rx_cal_pending = 1;
p->calib.rx_calibrated = 0;
shw_cal_enable_feedback(p->name, 1, PHY_CALIBRATE_RX);
p->state = HAL_PORT_STATE_CALIBRATION;
return HEXP_CAL_RESP_OK;
} else {
shw_cal_enable_feedback(p->name, 0, PHY_CALIBRATE_RX);
p->state = HAL_PORT_STATE_UP;
p->rx_cal_pending = 0;
return HEXP_CAL_RESP_OK;
}
break;
};
return 0;
}
/* Public API function - returns the array of names of all WR network interfaces */ /* Public API function - returns the array of names of all WR network interfaces */
int halexp_query_ports(hexp_port_list_t *list) int halexp_query_ports(hexp_port_list_t *list)
......
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