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
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 \
mblaster.o phy_calibration.o pps_gen.o watchdog.o
mblaster.o pps_gen.o watchdog.o
LIB = libswitchhw.a
......
......@@ -34,7 +34,7 @@ int shw_init()
/* no more shw_hpll_init(); */
/* no more shw_dmpll_init(); */
/* 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 */
assert_init(shw_pps_gen_init());
/* ... 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()
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_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_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)
(TX latency never changes as long as the TLK1221 PHY reference clock is enabled,
even if the link goes down) */
static int port_startup_tx_calibration(hal_port_state_t *p)
{
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;
}
/* No more calibration in V3 */
/* Port initialization. Assigns the MAC address, WR timing mode, reads parameters from the config file. */
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;
}
/* pre-calibrate the TX path for each port */
port_startup_tx_calibration(p);
/* Used to pre-calibrate the TX path for each port. No more in V3 */
return 0;
}
......@@ -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. */
static void poll_dmtd(hal_port_state_t *p)
{
uint32_t phase_val;
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;
};
/* FIXME: what should we do here? */
}
......@@ -494,38 +445,8 @@ static void calibration_fsm(hal_port_state_t *p)
}
/* 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);
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;
}
}
}
/* no, not in V3 */
}
#if 0
......@@ -719,95 +640,8 @@ static int any_port_calibrating()
}
/* 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)
{
/* 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;
}
/* No more calibration in V3 */
/* Public API function - returns the array of names of all WR network interfaces */
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