📄 phytsk.c
字号:
/*
Copyright (c) 2002-2006 Vitesse Semiconductor Corporation "Vitesse".
All Rights Reserved. Unpublished rights reserved under the copyright laws
of the United States of America, other countries and international treaties.
The software is provided without a fee. Permission to use, copy, store and
modify, the software and its source code is granted. Permission to integrate
into other products, disclose, transmit and distribute the software in an
absolute machine readable format (e.g. HEX file) is also granted.
The source code of the software may not be disclosed, transmitted or
distributed without the written permission of Vitesse. The software and its
source code may only be used in products utilizing a Vitesse VSC73xx product.
This copyright notice must appear in any copy, modification, disclosure,
transmission or distribution of the software. Vitesse retains all ownership,
copyright, trade secret and proprietary rights in the software.
THIS SOFTWARE HAS BEEN PROVIDED "AS IS," WITHOUT EXPRESS OR IMPLIED WARRANTY
INCLUDING, WITHOUT LIMITATION, IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR USE AND NON-INFRINGEMENT.
*/
#include "common.h"
#include "hwconf.h"
#include "phyconf.h"
#include "h2reg.h"
#include "h2io.h"
#include "h2.h"
#include "phytsk.h"
#include "phymap.h"
#include "phydrv.h"
#include "timer.h"
#include "main.h"
#include "hwport.h"
#include "misc2.h"
#if TRANSIT_VERIPHY
#include "veriphy.h"
#include "misc2.h"
#endif
/* ************************************************************************ **
*
*
* Defines
*
*
*
* ************************************************************************ */
/* define states of state machine */
#define PORT_DISABLED 0
#define SET_UP_SPEED_MODE_ON_PHY 1
#define WAITING_FOR_LINK 2
#define LINK_UP 3
#define WAITING_FOR_LINK_SPECIAL_0 10
#define WAITING_FOR_LINK_SPECIAL_1 11
#define WAITING_FOR_LINK_SPECIAL_2 12
#define WAITING_FOR_LINK_SPECIAL_3 13
#define PHASE_WALKING 14
#define PHASE_WALKING_DONE 15
#define WAITING_FOR_LINK_SPECIAL 40
#define LINK_UP_SPECIAL 60
#define SPECIAL_REINIT 70
/* define periods in granularity of 10 msec */
#define POLL_PERIOD_FOR_LINK 10 /* 100 msec */
#define WAIT_ERROR_TIMEOUT_100 2 /* 20 msec */
#define WAIT_ERROR_TIMEOUT_10 1 /* 10 msec */
#define WAIT_ERROR_TIMEOUT(p) ((fix_data[(p)].phy_speed == LINK_MODE_SPEED_10) ? WAIT_ERROR_TIMEOUT_10 : WAIT_ERROR_TIMEOUT_100)
#define no_activity_action_1 2
#define no_activity_action_2 2
#define delay_a 30 /* in msec */
#define delay_b 20 /* in 10 msec */
#define delay_c 20 /* in 10 msec */
#define delay_d 20 /* in 10 msec */
/* ************************************************************************ **
*
*
* Typedefs and enums
*
*
*
* ************************************************************************ */
/* ************************************************************************ **
*
*
* Prototypes for local functions
*
*
*
* ************************************************************************ */
static uchar phy_init_state (uchar port_no);
static void handle_phy (uchar port_no);
static void do_link_up (uchar port_no);
static void do_link_down (uchar port_no);
static uchar get_link_mode (uchar port_no);
static uchar get_speed_and_fdx (uchar port_no);
static uchar start_10_100_fix(uchar port_no, uchar forced);
static void flip_sgmii_clock(uchar port_no, uchar count);
static void sgmii_write_gate_free_run(uchar port_no, uchar val);
static void phy_epg_on(uchar port_no);
static void phy_epg_restart(uchar port_no);
static void phy_epg_off(uchar port_no);
static ushort phy_epg_data (uchar port_no);
static uchar phy_epg_done (uchar port_no);
static void phy_fix_setup(uchar port_no);
static uchar phy_poll_for_lp(uchar port_no, uchar cur_state);
static uchar use_special_state_machine(uchar port_no);
static uchar suspect_port(uchar port_no);
static uchar any_errors_seen(uchar port_no);
static uchar await_activity(uchar port_no);
/* ************************************************************************ **
*
*
* Local data
*
*
*
* ************************************************************************ */
/* Link up/down state */
static port_bit_mask_t phy_link_up_mask;
/* Current state of each PHY/port state machine */
static uchar idata phy_state [MAX_PORT];
/* Flag for activate polling of PHYs */
static bit poll_phy_flag;
static xdata struct {
ushort save_reg_0;
ushort save_reg_29;
uchar timer;
uchar aux_timer;
uchar phy_speed;
uchar mac_speed;
uchar phase;
uchar iteration;
} fix_data [MAX_PORT];
/* ************************************************************************ */
void phy_init (void)
/* ------------------------------------------------------------------------ --
* Purpose : Initialize all PHYs after a power up reset.
* Remarks :
* Restrictions:
* See also :
* Example :
* ************************************************************************ */
{
uchar port_no;
phy_link_up_mask = 0;
delay(MSEC_30);
for (port_no = MIN_PORT; port_no < MAX_PORT; port_no++) {
if (phy_map(port_no)) {
phy_post_reset(port_no);
}
}
}
/* ************************************************************************ */
uchar phy_check_all (void)
/* ------------------------------------------------------------------------ --
* Purpose : Do run-time check on all PHYs.
* Remarks :
* Restrictions:
* See also :
* Example :
* ************************************************************************ */
{
uchar port_no;
uchar error;
error = FALSE;
for (port_no = MIN_PORT; port_no < MAX_PORT; port_no++) {
if (phy_map(port_no)) {
#if PHY_ID_CHECK
if (phy_read(port_no, 2) != PHY_OUI_MSB) {
error = TRUE;
}
#endif
}
}
return error;
}
/* ************************************************************************ */
void phy_tsk_init (void)
/* ------------------------------------------------------------------------ --
* Purpose : Initialize data used by phy task.
* Remarks :
* Restrictions:
* See also :
* Example :
* ************************************************************************ */
{
uchar port_no;
for (port_no = MIN_PORT; port_no < MAX_PORT; port_no++) {
phy_state[port_no] = phy_init_state(port_no);
}
}
/* ************************************************************************ */
void phy_tsk (void)
/* ------------------------------------------------------------------------ --
* Purpose : Activate state machine for each port/PHY.
* Remarks :
* Restrictions:
* See also :
* Example :
* ************************************************************************ */
{
uchar port_no;
for (port_no = MIN_PORT; port_no < MAX_PORT; port_no++) {
if (phy_map(port_no)) {
handle_phy(port_no);
}
}
#if SFP_NUM
if (poll_phy_flag) {
phy_poll_sfp();
}
#endif
poll_phy_flag = FALSE;
}
/* ************************************************************************ */
static void handle_phy (uchar port_no)
/* ------------------------------------------------------------------------ --
* Purpose : State machine for copper phy. Monitor PHY and set up
* H2 port.
* Remarks :
* Restrictions:
* See also :
* Example :
* ************************************************************************ */
{
uchar link_mode;
switch (phy_state[port_no]) {
case PORT_DISABLED:
break;
case SET_UP_SPEED_MODE_ON_PHY:
/* Update register 4 with 10/100 advertising, plus pause capability */
phy_write(port_no, 4, 0x05e1);
/* Update register 9 with 1000 Mbps advertising */
phy_write(port_no, 9, PHY_REG_9_CONFIG);
/* Restart auto-negotiation */
phy_restart_aneg(port_no);
/* shift state */
if (use_special_state_machine(port_no)) {
phy_fix_setup(port_no);
phy_state[port_no] = WAITING_FOR_LINK_SPECIAL_0;
break;
}
phy_state[port_no] = WAITING_FOR_LINK;
break;
case WAITING_FOR_LINK:
if (!poll_phy_flag) {
return;
}
/* fall through */
case WAITING_FOR_LINK_SPECIAL:
/* Check if link is up */
if (phy_link_status(port_no)) {
WRITE_PORT_BIT_MASK(port_no, 1, &phy_link_up_mask);
if (phy_state[port_no] == WAITING_FOR_LINK_SPECIAL) {
phy_write_masked(port_no, 4, 0x8000, 0x8000);
}
/* Update switch chip according to link */
link_mode = get_link_mode(port_no);
if (phy_state[port_no] == WAITING_FOR_LINK_SPECIAL) {
if (fix_data[port_no].phy_speed != (link_mode & LINK_MODE_SPEED_MASK)) {
phy_state[port_no] = SET_UP_SPEED_MODE_ON_PHY;
do_link_down(port_no);
return;
}
}
if (phy_state[port_no] == WAITING_FOR_LINK) {
h2_setup_port(port_no, link_mode);
}
else {
if ((link_mode & LINK_MODE_SPEED_MASK) == LINK_MODE_SPEED_1000) {
h2_setup_mac(port_no, link_mode);
}
h2_setup_port_special(port_no, link_mode);
}
/* Do any set-up of PHY due to link going up */
phy_do_link_up_settings(port_no, link_mode);
/* shift state */
if (phy_state[port_no] == WAITING_FOR_LINK_SPECIAL) {
phy_state[port_no] = LINK_UP_SPECIAL;
}
else {
phy_state[port_no] = LINK_UP;
}
do_link_up(port_no);
}
else if (phy_state[port_no] == WAITING_FOR_LINK_SPECIAL) {
if (fix_data[port_no].timer == 0) {
if (++fix_data[port_no].aux_timer >= 10) { /* 10 seconds */
phy_restart_aneg(port_no);
phy_fix_setup(port_no);
phy_state[port_no] = WAITING_FOR_LINK_SPECIAL_0;
}
else {
fix_data[port_no].timer = 100; /* 1 second */
}
}
}
break;
case LINK_UP:
if (poll_phy_flag) {
/* Check if link has been down */
if (!phy_link_status(port_no)) {
phy_state[port_no] = WAITING_FOR_LINK;
do_link_down(port_no);
}
}
break;
case LINK_UP_SPECIAL:
if (!phy_link_status(port_no)) {
phy_state[port_no] = SPECIAL_REINIT;
do_link_down(port_no);
}
break;
case SPECIAL_REINIT:
phy_fix_setup(port_no);
phy_state[port_no] = WAITING_FOR_LINK_SPECIAL_0;
break;
case WAITING_FOR_LINK_SPECIAL_0:
case WAITING_FOR_LINK_SPECIAL_1:
case WAITING_FOR_LINK_SPECIAL_2:
case WAITING_FOR_LINK_SPECIAL_3:
phy_state[port_no] = phy_poll_for_lp(port_no, phy_state[port_no]);
break;
case PHASE_WALKING:
if (any_errors_seen(port_no)) {
flip_sgmii_clock(port_no, 10);
phy_state[port_no] = PHASE_WALKING_DONE;
}
else if (fix_data[port_no].timer == 0) {
fix_data[port_no].phase++;
if (fix_data[port_no].phase >= ((fix_data[port_no].phy_speed == LINK_MODE_SPEED_10) ? 50 : 5)) {
if(phy_epg_done(port_no)) {
phy_state[port_no] = PHASE_WALKING_DONE;
} else {
fix_data[port_no].iteration++;
phy_epg_off(port_no);
(void) any_errors_seen(port_no); /* clear bits */
phy_epg_on(port_no);
fix_data[port_no].phase = 0;
fix_data[port_no].timer = WAIT_ERROR_TIMEOUT(port_no);
(void)await_activity(port_no);
(void) any_errors_seen(port_no); /* clear bits */
}
}
else {
flip_sgmii_clock(port_no, 20);
fix_data[port_no].timer = WAIT_ERROR_TIMEOUT(port_no);
(void) any_errors_seen(port_no); /* clear bits */
}
}
break;
case PHASE_WALKING_DONE:
phy_epg_off(port_no);
(void) any_errors_seen(port_no); /* clear bits */
if (fix_data[port_no].phy_speed == LINK_MODE_SPEED_10) {
phy_page_tp(port_no);
phy_write_masked(port_no, 8, 0x0000, 0x0200);
phy_page_std(port_no);
}
if (phy_state[port_no] == PHASE_WALKING_DONE) {
phy_page_tr(port_no);
phy_write(port_no, 16, 0xa688);
phy_write_masked(port_no, 17, 0x0000, 0x0008);
phy_write(port_no, 16, 0x8688);
phy_page_std(port_no);
phy_write(port_no, 0, fix_data[port_no].save_reg_0 | 0x0200);
}
phy_write(port_no, 29, fix_data[port_no].save_reg_29);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -