/***********************************************************************/ /* */ /* MODULE: merlin_direct_access.c */ /* DATE: 01/03/2016 */ /* PURPOSE: Callback functions for Lport */ /* */ /***********************************************************************/ #ifdef _CFE_ #include "lib_types.h" #include "lib_printf.h" #else #include #include #include #include #include #endif #include "lport_defs.h" #include "lport_drv.h" #include "serdes_access.h" /* Microcode */ #include "merlin_direct_ucode_image.h" #ifndef _CFE_ #include #define UDELAY(_a) udelay(_a) #else extern void cfe_usleep(int usec); #define UDELAY(_a) cfe_usleep(_a) #endif #ifdef MERLIN_DEBUG #ifndef _CFE_ #define MERLIN_DBG(a) printk(a) #else #define MERLIN_DBG(a) xprintf(a) #endif #else #define MERLIN_DBG(a) #endif #ifndef _CFE_ #define MERLIN_ERR printk #else #define MERLIN_ERR xprintf #endif #define MERLIN_LANES_PER_CORE 2 #define MERLIN_MAX_CORE_NUMBER 2 #define MERLIN_MAX_LANE_NUMBER MERLIN_LANES_PER_CORE*MERLIN_MAX_CORE_NUMBER /*RMIC/PMI address*/ #define MMD_TYPE_OFFSET 27 #define LANE_ADDRESS_OFFSET 16 #define MASK_BIT(a) (1<<(a)) #define MASK_BITS_TO(x) ((1<<(x))-1) #define MASK_BITS_BETWEEN(l, h) (MASK_BITS_TO(((h)+1)) & ~(MASK_BITS_TO(l))) #define MASK_ALL_BITS_16 (0xFFFF) #define MARLIN_SET_BIT(reg, posn) ((reg) | (1L << (posn))) #define MARLIN_CLEAR_BIT(reg, posn) ((reg) & ~(1L << (posn))) #define MERLIN_READ_REG(dev_type, lane_index, reg_addr, mask, shift, value) \ do { \ uint32_t addr=0; \ addr = ((dev_type)<>= shift;\ } while (0); #define MERLIN_WRITE_REG(dev_type, lane_index, reg_addr, mask, shift, value) \ do { \ uint32_t addr=0; \ addr = ((dev_type)<port_up = port_up; switch (port_speed) { case 0: port_status->rate = LPORT_RATE_10MB; break; case 1: port_status->rate = LPORT_RATE_100MB; break; case 2: port_status->rate = LPORT_RATE_1000MB; break; case 3: port_status->rate = LPORT_RATE_2500MB; break; case 4: port_status->rate = LPORT_RATE_2500MB; break; case 0xD: case 0x34: port_status->rate = LPORT_RATE_1000MB; break; case 0xf: case 0x1b: case 0x1f: case 0x33: port_status->rate = LPORT_RATE_10G; break; default: port_status->rate = LPORT_RATE_UNKNOWN; break; } port_status->duplex = LPORT_FULL_DUPLEX; return 0; } static int merlin_direct_speed_set(E_MERLIN_LANE lane_id, LPORT_PORT_RATE port_rate) { switch (port_rate) { case LPORT_RATE_10G: MERLIN_WRITE_REG(0x3, lane_id, 0xc30b, MASK_BITS_BETWEEN(0, 5), 0, 0xf); /* SW_actual_speed */ break; case LPORT_RATE_2500MB: MERLIN_WRITE_REG(0x3, lane_id, 0xc30b, MASK_BITS_BETWEEN(0, 5), 0, 0x3); /* SW_actual_speed */ break; case LPORT_RATE_1000MB: MERLIN_WRITE_REG(0x3, lane_id, 0xc30b, MASK_BITS_BETWEEN(0, 5), 0, 0x2); /* SW_actual_speed */ break; case LPORT_RATE_100MB: MERLIN_WRITE_REG(0x3, lane_id, 0xc30b, MASK_BITS_BETWEEN(0, 5), 0, 0x1); /* SW_actual_speed */ break; default: MERLIN_ERR("Trying to set invalid port speed %d \n", port_rate); return -1; break; } return 0; } static int merlin_direct_lane_status_get(uint16_t lane_index, merlin_status_t *status) { MERLIN_READ_REG(3, lane_index, 0xc441, MASK_BIT(8), 8, &status->tx_LOCAL_FAULT); MERLIN_READ_REG(3, lane_index, 0xc441, MASK_BIT(7), 7, &status->tx_REMOTE_FAULT); MERLIN_READ_REG(3, lane_index, 0xc470, MASK_BIT(3), 3, &status->PMD_LOCK); MERLIN_READ_REG(3, lane_index, 0xc470, MASK_BIT(0), 0, &status->signal_ok); MERLIN_READ_REG(3, lane_index, 0xc474, MASK_BIT(8), 8, &status->rx_LOCAL_FAULT); MERLIN_READ_REG(3, lane_index, 0xc474, MASK_BIT(7), 7, &status->rx_REMOTE_FAULT); MERLIN_READ_REG(3, lane_index, 0xc474, MASK_BIT(1), 1, &status->rx_LINK_STATUS); MERLIN_READ_REG(3, lane_index, 0xc474, MASK_BIT(0), 0, &status->rx_SYNC_STATUS); MERLIN_READ_REG(1, lane_index, 0xd128, MASK_BIT(9), 9, &status->pll_lock); return 0; } static int merlin_direct_lane_stats_get(uint16_t lane_index, merlin_stats_t *stats) { MERLIN_READ_REG(3, lane_index, 0xc468, MASK_BITS_BETWEEN(0, 7), 0, &stats->kcode66ErrCount); MERLIN_READ_REG(3, lane_index, 0xc468, MASK_BITS_BETWEEN(8, 15), 8, &stats->sync66ErrCount); MERLIN_READ_REG(3, lane_index, 0xc469, MASK_BITS_BETWEEN(2, 9), 2, &stats->cl49ieee_errored_blocks); MERLIN_READ_REG(3, lane_index, 0xc46e, MASK_BITS_BETWEEN(0, 7), 0, &stats->BER_count_per_ln); MERLIN_READ_REG(3, lane_index, 0x9227, MASK_BITS_BETWEEN(0, 7), 0, &stats->cl49_invalid_sh_cnt); MERLIN_READ_REG(3, lane_index, 0x9227, MASK_BITS_BETWEEN(8, 15), 8, &stats->cl49_valid_sh_cnt); return 0; } static int merlin_direct_lane_prbs_stats_get(uint16_t lane_index, merlin_prbs_stats_t *stats) { uint16_t reg_lo, reg_hi; reg_lo = 0; MERLIN_READ_REG(1, lane_index, 0xD0D9, MASK_ALL_BITS_16, 0, ®_lo); stats->prbs_lock_status = (reg_lo & 0x1);//1- PRBS checker is locked reg_lo = reg_hi = 0; MERLIN_READ_REG(1, lane_index, 0xD0DA, MASK_ALL_BITS_16, 0, ®_hi); MERLIN_READ_REG(1, lane_index, 0xD0DB, MASK_ALL_BITS_16, 0, ®_lo); stats->prbs_lock_lost = (uint16_t)(reg_hi >> 15); // Clear bit 15 it is prbs lock lost status bit; reg_hi = MARLIN_CLEAR_BIT(reg_hi, 15); stats->prbs_error = ((uint32_t)(reg_hi) << 16) | (uint32_t)reg_lo; return 0; } static int merlin_direct_lane_prbs_generate(uint16_t lane_index, uint16_t* p_prbs_type) { uint32_t prog_patten_gen_mode = (*p_prbs_type == SERDES_PRBS_PATTERN_TYPE_8180) ? 1 : 0; //bit pattern 8 ones / 8 zeros uint16_t reg_val = 1;//Enable prbs_generator(bit 0) if (prog_patten_gen_mode) { /* In case that prbs generator was enable */ MERLIN_WRITE_REG(1, lane_index, 0xD0E1, MASK_BIT(0), 0, 0x0); /* Default fixed pattern 8 ones / 8 zeros Enable fix pattern + default fixed pattern */ MERLIN_WRITE_REG(1, lane_index, 0xD0E0, MASK_BITS_BETWEEN(0 , 15), 0, 0x3); } else { /* Disable fixed pattern */ MERLIN_WRITE_REG(1, lane_index, 0xD0E0, MASK_BIT(0), 0, 0x0); reg_val |= (*p_prbs_type << 1); /* Enable prbs_generator(bit 0) with prbs type: PRBS7|PRBS9|PRBS11|PRBS15|PRBS23|PRBS31|PRBS58 */ MERLIN_WRITE_REG(1, lane_index, 0xD0E1, MASK_BITS_BETWEEN(0,3), 0, reg_val); } return 0; } static int merlin_direct_lane_prbs_monitor(uint16_t lane_index, uint16_t* p_prbs_type) { uint16_t reg_val = 1;//Enable prbs_generator(bit 0) reg_val |= (*p_prbs_type << 1); /* Enable prbs_generator control with prbs type //PRBS7|PRBS9|PRBS11|PRBS15|PRBS23|PRBS31|PRBS58 + prbs_en bit 0*/ MERLIN_WRITE_REG(1, lane_index, 0xD0D1, MASK_BITS_BETWEEN(0,3), 0, reg_val); return 0; } static int merlin_direct_core_id_get(uint16_t lane_index, merlin_serdes_id_t *id) { MERLIN_READ_REG(3, lane_index, 0x910e, MASK_BITS_BETWEEN(14, 15), 14, &id->rev_letter); MERLIN_READ_REG(3, lane_index, 0x910e, MASK_BITS_BETWEEN(11, 13), 11, &id->rev_number); MERLIN_READ_REG(3, lane_index, 0x910e, MASK_BITS_BETWEEN(9, 10), 9, &id->bonding); MERLIN_READ_REG(3, lane_index, 0x910e, MASK_BITS_BETWEEN(6, 8), 6, &id->tech_proc); MERLIN_READ_REG(3, lane_index, 0x910e, MASK_BITS_BETWEEN(0, 5), 0, &id->model_number); return 0; } static int merlin_direct_loopback_set(E_MERLIN_LANE lane_index, merlin_loopback_set_t *in) { int ret = 0; uint16_t lane_map; switch(in->mode) { case MERLIN_PCS_LOCAL_LOOPBACK: MERLIN_READ_REG(3, lane_index, 0x9109, MASK_BITS_BETWEEN(4, 7), 4, &lane_map); if(!in->enable) lane_map |= 1<enable != 0)); MERLIN_WRITE_REG(3, lane_index, 0x9109, MASK_BITS_BETWEEN(4, 7), 4, lane_map); break; case MERLIN_PCS_REMOTE_LOOPBACK: MERLIN_READ_REG(3, lane_index, 0x9109, MASK_BITS_BETWEEN(12, 15), 12, &lane_map); if(!in->enable) lane_map |= 1<enable != 0)); MERLIN_WRITE_REG(1, lane_index, 0xd0d2, MASK_BIT(0), 0, in->enable); break; case MERLIN_PMD_REMOTE_LOOPBACK: if (in->enable) { /*locks Loop timing */ MERLIN_WRITE_REG(1, lane_index, 0xd075, MASK_BIT(2), 2, 0); MERLIN_WRITE_REG(1, lane_index, 0xd070, MASK_BIT(0), 0, 1); MERLIN_WRITE_REG(1, lane_index, 0xd070, MASK_BIT(1), 1, 1); UDELAY(25); MERLIN_WRITE_REG(1, lane_index, 0xd070, MASK_BIT(2), 2, 1); MERLIN_WRITE_REG(1, lane_index, 0xd0e2, MASK_BIT(0), 0, 1); UDELAY(50); } else { MERLIN_WRITE_REG(1, lane_index, 0xd0e2, MASK_BIT(0), 0, 0); MERLIN_WRITE_REG(1, lane_index, 0xd070, MASK_BIT(2), 2, 0); MERLIN_WRITE_REG(1, lane_index, 0xd070, MASK_BIT(1), 1, 0); MERLIN_WRITE_REG(1, lane_index, 0xd070, MASK_BIT(0), 0, 0); MERLIN_WRITE_REG(1, lane_index, 0xd075, MASK_BIT(2), 2, 1); } break; default: MERLIN_ERR("loopback mode %d is not supported\n", in->mode); ret = -1; break; } return ret; } static int merlin_direct_ioctl(E_MERLIN_LANE lane_index, merlin_command_t cmd, merlin_control_t *data) { int ret = 0; switch(cmd) { case MERLIN_CMD_STATUS_GET: ret = merlin_direct_lane_status_get(lane_index, &data->status); break; case MERLIN_CMD_STATS_GET: ret = merlin_direct_lane_stats_get(lane_index, &data->stats); break; case MERLIN_CMD_PRBS_GENRATE: ret = merlin_direct_lane_prbs_generate(lane_index, &data->prbs_type); break; case MERLIN_CMD_PRBS_MONITOR: ret = merlin_direct_lane_prbs_monitor(lane_index, &data->prbs_type); break; case MERLIN_CMD_PRBS_STATS_GET: ret = merlin_direct_lane_prbs_stats_get(lane_index, &data->prbs_stats); break; case MERLIN_CMD_FORCE_LINK_DOWN: MERLIN_WRITE_REG(1, lane_index, 0x09, 0x1, 1+lane_index, 0x0); break; case MERLIN_CMD_FORCE_LINK_UP: MERLIN_WRITE_REG(1, lane_index, 0x09, 0x1, 1+lane_index, 0x1); break; case MERLIN_CMD_ID: ret = merlin_direct_core_id_get(lane_index, &data->serdes_id); break; case MERLIN_CMD_REG_READ: MERLIN_READ_REG(data->reg_data.device_type, lane_index, data->reg_data.reg_addr, 0xffff, 0, &data->reg_data.reg_value); break; case MERLIN_CMD_REG_WRITE: MERLIN_WRITE_REG(data->reg_data.device_type, lane_index, data->reg_data.reg_addr, 0xffff, 0, data->reg_data.reg_value); break; case MERLIN_CMD_LOOPBACK_SET: ret = merlin_direct_loopback_set(lane_index, &data->loopback); break; default: MERLIN_ERR("Command %d is not supported\n", cmd); ret = -1; break; } return ret; } extern merlin_sdk_cb_s merlin_callbacks; void lport_serdes_drv_register(void) { merlin_callbacks.merlin_core_init = merlin_direct_core_init; merlin_callbacks.merlin_lane_init = merlin_direct_lane_init; merlin_callbacks.merlin_speed_set = merlin_direct_speed_set; merlin_callbacks.merlin_get_status = merlin_direct_get_status; merlin_callbacks.merlin_ioctl = merlin_direct_ioctl; } #ifndef _CFE_ int __init lport_serdes_drv_init(void) { lport_serdes_drv_register(); return 0; } postcore_initcall(lport_serdes_drv_init) #endif