aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/** $Id$ */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/** @file
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * DevE1000Phy - Intel 82540EM Ethernet Controller Internal PHY Emulation.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Implemented in accordance with the specification:
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * PCI/PCI-X Family of Gigabit Ethernet Controllers Software Developer�s Manual
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * 82540EP/EM, 82541xx, 82544GC/EI, 82545GM/EM, 82546GB/EB, and 82547xx
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * 317453-002 Revision 3.5
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/*
5e76d98665f7356332cb20eac97922d5891b903evboxsync * Copyright (C) 2007-2013 Oracle Corporation
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
dbcf44d4b4f08f03eae2903053ed8c5264b0c23fvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
dbcf44d4b4f08f03eae2903053ed8c5264b0c23fvboxsync * available from http://www.virtualbox.org. This file is free software;
dbcf44d4b4f08f03eae2903053ed8c5264b0c23fvboxsync * you can redistribute it and/or modify it under the terms of the GNU
dbcf44d4b4f08f03eae2903053ed8c5264b0c23fvboxsync * General Public License (GPL) as published by the Free Software
dbcf44d4b4f08f03eae2903053ed8c5264b0c23fvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
dbcf44d4b4f08f03eae2903053ed8c5264b0c23fvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
dbcf44d4b4f08f03eae2903053ed8c5264b0c23fvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync#define LOG_GROUP LOG_GROUP_DEV_E1000
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/** @todo Remove me! For now I want asserts to work in release code. */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync// #ifndef RT_STRICT
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync// #define RT_STRICT
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync#include <iprt/assert.h>
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync// #undef RT_STRICT
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync// #endif
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync#include <VBox/err.h>
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync#include <VBox/log.h>
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#include <VBox/vmm/ssm.h>
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync#include "DevE1000Phy.h"
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/* Little helpers ************************************************************/
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync#ifdef PHY_UNIT_TEST
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync# define SSMR3PutMem(a,b,c)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync# define SSMR3GetMem(a,b,c)
5e76d98665f7356332cb20eac97922d5891b903evboxsync# include <stdio.h>
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync# define PhyLog(a) printf a
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync#else /* PHY_UNIT_TEST */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync# define PhyLog(a) Log(a)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync#endif /* PHY_UNIT_TEST */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync#define REG(x) pPhy->au16Regs[x##_IDX]
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/* Internals */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncnamespace Phy {
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /** Retrieves state name by id */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync static const char * getStateName(uint16_t u16State);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /** Look up register index by address. */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync static int lookupRegister(uint32_t u32Address);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /** Software-triggered reset. */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync static void softReset(PPHY pPhy);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
5e76d98665f7356332cb20eac97922d5891b903evboxsync /** @name Generic handlers
5e76d98665f7356332cb20eac97922d5891b903evboxsync * @{ */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync static uint16_t regReadDefault (PPHY pPhy, uint32_t index);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync static void regWriteDefault (PPHY pPhy, uint32_t index, uint16_t u16Value);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync static uint16_t regReadForbidden (PPHY pPhy, uint32_t index);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync static void regWriteForbidden (PPHY pPhy, uint32_t index, uint16_t u16Value);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync static uint16_t regReadUnimplemented (PPHY pPhy, uint32_t index);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync static void regWriteUnimplemented(PPHY pPhy, uint32_t index, uint16_t u16Value);
5e76d98665f7356332cb20eac97922d5891b903evboxsync /** @} */
5e76d98665f7356332cb20eac97922d5891b903evboxsync /** @name Register-specific handlers
5e76d98665f7356332cb20eac97922d5891b903evboxsync * @{ */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync static void regWritePCTRL (PPHY pPhy, uint32_t index, uint16_t u16Value);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync static uint16_t regReadPSTATUS (PPHY pPhy, uint32_t index);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync static uint16_t regReadGSTATUS (PPHY pPhy, uint32_t index);
5e76d98665f7356332cb20eac97922d5891b903evboxsync /** @} */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /**
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * PHY register map table.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Override pfnRead and pfnWrite to implement register-specific behavior.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync static struct RegMap_st
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync {
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /** PHY register address. */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync uint32_t u32Address;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /** Read callback. */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync uint16_t (*pfnRead)(PPHY pPhy, uint32_t index);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /** Write callback. */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync void (*pfnWrite)(PPHY pPhy, uint32_t index, uint16_t u16Value);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /** Abbreviated name. */
5e76d98665f7356332cb20eac97922d5891b903evboxsync const char *pszAbbrev;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /** Full name. */
5e76d98665f7356332cb20eac97922d5891b903evboxsync const char *pszName;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync } s_regMap[NUM_OF_PHY_REGS] =
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync {
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /*ra read callback write callback abbrev full name */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /*-- ------------------------- -------------------------- ---------- ------------------------------*/
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync { 0, Phy::regReadDefault , Phy::regWritePCTRL , "PCTRL" , "PHY Control" },
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync { 1, Phy::regReadPSTATUS , Phy::regWriteForbidden , "PSTATUS" , "PHY Status" },
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync { 2, Phy::regReadDefault , Phy::regWriteForbidden , "PID" , "PHY Identifier" },
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync { 3, Phy::regReadDefault , Phy::regWriteForbidden , "EPID" , "Extended PHY Identifier" },
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync { 4, Phy::regReadDefault , Phy::regWriteDefault , "ANA" , "Auto-Negotiation Advertisement" },
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync { 5, Phy::regReadDefault , Phy::regWriteForbidden , "LPA" , "Link Partner Ability" },
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync { 6, Phy::regReadUnimplemented, Phy::regWriteForbidden , "ANE" , "Auto-Negotiation Expansion" },
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync { 7, Phy::regReadUnimplemented, Phy::regWriteUnimplemented, "NPT" , "Next Page Transmit" },
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync { 8, Phy::regReadUnimplemented, Phy::regWriteForbidden , "LPN" , "Link Partner Next Page" },
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync { 9, Phy::regReadDefault , Phy::regWriteUnimplemented, "GCON" , "1000BASE-T Control" },
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync { 10, Phy::regReadGSTATUS , Phy::regWriteForbidden , "GSTATUS" , "1000BASE-T Status" },
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync { 15, Phy::regReadUnimplemented, Phy::regWriteForbidden , "EPSTATUS" , "Extended PHY Status" },
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync { 16, Phy::regReadDefault , Phy::regWriteDefault , "PSCON" , "PHY Specific Control" },
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync { 17, Phy::regReadDefault , Phy::regWriteForbidden , "PSSTAT" , "PHY Specific Status" },
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync { 18, Phy::regReadUnimplemented, Phy::regWriteUnimplemented, "PINTE" , "PHY Interrupt Enable" },
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync { 19, Phy::regReadUnimplemented, Phy::regWriteForbidden , "PINTS" , "PHY Interrupt Status" },
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync { 20, Phy::regReadUnimplemented, Phy::regWriteUnimplemented, "EPSCON1" , "Extended PHY Specific Control 1" },
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync { 21, Phy::regReadUnimplemented, Phy::regWriteForbidden , "PREC" , "PHY Receive Error Counter" },
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync { 26, Phy::regReadUnimplemented, Phy::regWriteUnimplemented, "EPSCON2" , "Extended PHY Specific Control 2" },
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync { 29, Phy::regReadForbidden , Phy::regWriteUnimplemented, "R30PS" , "MDI Register 30 Page Select" },
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync { 30, Phy::regReadUnimplemented, Phy::regWriteUnimplemented, "R30AW" , "MDI Register 30 Access Window" }
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync };
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/**
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Default read handler.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Fetches register value from the state structure.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @returns Register value
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param index Register index in register array.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncstatic uint16_t Phy::regReadDefault(PPHY pPhy, uint32_t index)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync AssertReturn(index<Phy::NUM_OF_PHY_REGS, 0);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync return pPhy->au16Regs[index];
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/**
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Default write handler.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Writes the specified register value to the state structure.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param index Register index in register array.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param value The value to store (ignored).
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncstatic void Phy::regWriteDefault(PPHY pPhy, uint32_t index, uint16_t u16Value)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync AssertReturnVoid(index<NUM_OF_PHY_REGS);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->au16Regs[index] = u16Value;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/**
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Read handler for write-only registers.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Merely reports reads from write-only registers.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @returns Register value (always 0)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param index Register index in register array.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncstatic uint16_t Phy::regReadForbidden(PPHY pPhy, uint32_t index)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync PhyLog(("PHY#%d At %02d read attempted from write-only '%s'\n",
5e76d98665f7356332cb20eac97922d5891b903evboxsync pPhy->iInstance, s_regMap[index].u32Address, s_regMap[index].pszName));
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync return 0;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/**
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Write handler for read-only registers.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Merely reports writes to read-only registers.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param index Register index in register array.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param value The value to store (ignored).
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncstatic void Phy::regWriteForbidden(PPHY pPhy, uint32_t index, uint16_t u16Value)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync PhyLog(("PHY#%d At %02d write attempted to read-only '%s'\n",
5e76d98665f7356332cb20eac97922d5891b903evboxsync pPhy->iInstance, s_regMap[index].u32Address, s_regMap[index].pszName));
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/**
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Read handler for unimplemented registers.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Merely reports reads from unimplemented registers.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @returns Register value (always 0)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param index Register index in register array.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncstatic uint16_t Phy::regReadUnimplemented(PPHY pPhy, uint32_t index)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync PhyLog(("PHY#%d At %02d read attempted from unimplemented '%s'\n",
5e76d98665f7356332cb20eac97922d5891b903evboxsync pPhy->iInstance, s_regMap[index].u32Address, s_regMap[index].pszName));
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync return 0;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/**
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Write handler for unimplemented registers.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Merely reports writes to unimplemented registers.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param index Register index in register array.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param value The value to store (ignored).
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncstatic void Phy::regWriteUnimplemented(PPHY pPhy, uint32_t index, uint16_t u16Value)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync PhyLog(("PHY#%d At %02d write attempted to unimplemented '%s'\n",
5e76d98665f7356332cb20eac97922d5891b903evboxsync pPhy->iInstance, s_regMap[index].u32Address, s_regMap[index].pszName));
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/**
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Search PHY register table for register with matching address.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @returns Index in the register table or -1 if not found.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param u32Address Register address.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncstatic int Phy::lookupRegister(uint32_t u32Address)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync unsigned int index;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync for (index = 0; index < RT_ELEMENTS(s_regMap); index++)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync {
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync if (s_regMap[index].u32Address == u32Address)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync {
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync return index;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync }
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync }
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync return -1;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/**
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Read PHY register.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @returns Value of specified PHY register.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param u32Address Register address.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncuint16_t Phy::readRegister(PPHY pPhy, uint32_t u32Address)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync int index = Phy::lookupRegister(u32Address);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync uint16_t u16 = 0;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync if (index != -1)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync {
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync u16 = s_regMap[index].pfnRead(pPhy, index);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync PhyLog(("PHY#%d At %02d read %04X from %s (%s)\n",
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->iInstance, s_regMap[index].u32Address, u16,
5e76d98665f7356332cb20eac97922d5891b903evboxsync s_regMap[index].pszAbbrev, s_regMap[index].pszName));
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync }
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync else
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync {
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync PhyLog(("PHY#%d read attempted from non-existing register %08x\n",
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->iInstance, u32Address));
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync }
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync return u16;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/**
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Write to PHY register.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param u32Address Register address.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param u16Value Value to store.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncvoid Phy::writeRegister(PPHY pPhy, uint32_t u32Address, uint16_t u16Value)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync int index = Phy::lookupRegister(u32Address);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync if (index != -1)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync {
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync PhyLog(("PHY#%d At %02d write %04X to %s (%s)\n",
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->iInstance, s_regMap[index].u32Address, u16Value,
5e76d98665f7356332cb20eac97922d5891b903evboxsync s_regMap[index].pszAbbrev, s_regMap[index].pszName));
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync s_regMap[index].pfnWrite(pPhy, index, u16Value);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync }
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync else
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync {
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync PhyLog(("PHY#%d write attempted to non-existing register %08x\n",
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->iInstance, u32Address));
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync }
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/**
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * PHY constructor.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Stores E1000 instance internally. Triggers PHY hard reset.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param iNICInstance Number of network controller instance this PHY is
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * attached to.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param u16EPid Extended PHY Id.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncvoid Phy::init(PPHY pPhy, int iNICInstance, uint16_t u16EPid)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->iInstance = iNICInstance;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /* Make sure the link is down */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(PSTATUS) = 0;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /* The PHY identifier composed of bits 3 through 18 of the OUI */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /* (Organizationally Unique Identifier). OUI is 0x05043. */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(PID) = 0x0141;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /* Extended PHY identifier */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(EPID) = u16EPid;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync hardReset(pPhy);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/**
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Hardware PHY reset.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Sets all PHY registers to their initial values.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncvoid Phy::hardReset(PPHY pPhy)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync PhyLog(("PHY#%d Hard reset\n", pPhy->iInstance));
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(PCTRL) = PCTRL_SPDSELM | PCTRL_DUPMOD | PCTRL_ANEG;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /*
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * 100 and 10 FD/HD, MF Preamble Suppression, Auto-Negotiation Complete,
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * AUTO NEG AB, EXT CAP
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(PSTATUS) = (REG(PSTATUS) & ~PSTATUS_LNKSTAT) | 0x7969;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(ANA) = 0x01E1;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /* No flow control by our link partner, all speeds */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(LPA) = 0x01E0;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(ANE) = 0x0000;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(NPT) = 0x2001;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(LPN) = 0x0000;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(GCON) = 0x1E00;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(GSTATUS) = 0x0000;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(EPSTATUS) = 0x3000;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(PSCON) = 0x0068;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(PSSTAT) = 0x0000;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(PINTE) = 0x0000;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(PINTS) = 0x0000;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(EPSCON1) = 0x0D60;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(PREC) = 0x0000;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(EPSCON2) = 0x000C;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(R30PS) = 0x0000;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(R30AW) = 0x0000;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16State = MDIO_IDLE;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/**
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Software PHY reset.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncstatic void Phy::softReset(PPHY pPhy)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync PhyLog(("PHY#%d Soft reset is not yet implemented!\n", pPhy->iInstance));
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/**
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Get the current state of the link.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @returns true if link is up.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncbool Phy::isLinkUp(PPHY pPhy)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync return (REG(PSSTAT) & PSSTAT_LINK) != 0;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/**
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Set the current state of the link.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @remarks Link Status bit in PHY Status register is latched-low and does
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * not change the state when the link goes up.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param fLinkIsUp New state of the link.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncvoid Phy::setLinkStatus(PPHY pPhy, bool fLinkIsUp)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync if (fLinkIsUp)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(PSSTAT) |= PSSTAT_LINK;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync else
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync {
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(PSSTAT) &= ~PSSTAT_LINK;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(PSTATUS) &= ~PSTATUS_LNKSTAT;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync }
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync#ifdef IN_RING3
5e76d98665f7356332cb20eac97922d5891b903evboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/**
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Save PHY state.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * @remarks Since PHY is aggregated into E1K it does not currently supports
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * versioning of its own.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @returns VBox status code.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param pSSMHandle The handle to save the state to.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param pPhy The pointer to this instance.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncint Phy::saveState(PSSMHANDLE pSSMHandle, PPHY pPhy)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync SSMR3PutMem(pSSMHandle, pPhy->au16Regs, sizeof(pPhy->au16Regs));
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync return VINF_SUCCESS;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/**
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Restore previously saved PHY state.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * @remarks Since PHY is aggregated into E1K it does not currently supports
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * versioning of its own.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @returns VBox status code.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param pSSMHandle The handle to save the state to.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param pPhy The pointer to this instance.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncint Phy::loadState(PSSMHANDLE pSSMHandle, PPHY pPhy)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
b81b98e887ef9ceb50848b5585ad3b2bf0b0159dvboxsync return SSMR3GetMem(pSSMHandle, pPhy->au16Regs, sizeof(pPhy->au16Regs));
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
5e76d98665f7356332cb20eac97922d5891b903evboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync#endif /* IN_RING3 */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/* Register-specific handlers ************************************************/
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/**
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Write handler for PHY Control register.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Handles reset.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param index Register index in register array.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param value The value to store (ignored).
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncstatic void Phy::regWritePCTRL(PPHY pPhy, uint32_t index, uint16_t u16Value)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync if (u16Value & PCTRL_RESET)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync softReset(pPhy);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync else
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync regWriteDefault(pPhy, index, u16Value);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/**
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Read handler for PHY Status register.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Handles Latched-Low Link Status bit.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @returns Register value
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param index Register index in register array.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncstatic uint16_t Phy::regReadPSTATUS(PPHY pPhy, uint32_t index)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /* Read latched value */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync uint16_t u16 = REG(PSTATUS);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync if (REG(PSSTAT) & PSSTAT_LINK)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(PSTATUS) |= PSTATUS_LNKSTAT;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync else
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync REG(PSTATUS) &= ~PSTATUS_LNKSTAT;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync return u16;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/**
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * Read handler for 1000BASE-T Status register.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @returns Register value
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync *
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * @param index Register index in register array.
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncstatic uint16_t Phy::regReadGSTATUS(PPHY pPhy, uint32_t index)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /*
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * - Link partner is capable of 1000BASE-T half duplex
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * - Link partner is capable of 1000BASE-T full duplex
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * - Remote receiver OK
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * - Local receiver OK
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync * - Local PHY config resolved to SLAVE
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync return 0x3C00;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncstatic const char * Phy::getStateName(uint16_t u16State)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync static const char *pcszState[] =
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync {
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync "MDIO_IDLE",
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync "MDIO_ST",
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync "MDIO_OP_ADR",
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync "MDIO_TA_RD",
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync "MDIO_TA_WR",
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync "MDIO_READ",
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync "MDIO_WRITE"
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync };
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync return (u16State < RT_ELEMENTS(pcszState)) ? pcszState[u16State] : "<invalid>";
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncbool Phy::readMDIO(PPHY pPhy)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync bool fPin = false;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync switch (pPhy->u16State)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync {
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync case MDIO_TA_RD:
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync Assert(pPhy->u16Cnt == 1);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync fPin = false;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16State = MDIO_READ;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16Cnt = 16;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync break;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync case MDIO_READ:
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /* Bits are shifted out in MSB to LSB order */
3258df06cd987ad10cc197ada412228250d322ebvboxsync fPin = (pPhy->u16Acc & 0x8000) != 0;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16Acc <<= 1;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync if (--pPhy->u16Cnt == 0)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16State = MDIO_IDLE;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync break;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync default:
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync PhyLog(("PHY#%d WARNING! MDIO pin read in %s state\n", pPhy->iInstance, Phy::getStateName(pPhy->u16State)));
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16State = MDIO_IDLE;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync }
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync return fPin;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync/** Set the value of MDIO pin. */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsyncvoid Phy::writeMDIO(PPHY pPhy, bool fPin)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync{
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync switch (pPhy->u16State)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync {
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync case MDIO_IDLE:
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync if (!fPin)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16State = MDIO_ST;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync break;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync case MDIO_ST:
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync if (fPin)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync {
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16State = MDIO_OP_ADR;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16Cnt = 12; /* OP + PHYADR + REGADR */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16Acc = 0;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync }
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync break;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync case MDIO_OP_ADR:
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync Assert(pPhy->u16Cnt);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /* Shift in 'u16Cnt' bits into accumulator */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16Acc <<= 1;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync if (fPin)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16Acc |= 1;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync if (--pPhy->u16Cnt == 0)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync {
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /* Got OP(2) + PHYADR(5) + REGADR(5) */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync /* Note: A single PHY is supported, ignore PHYADR */
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync switch (pPhy->u16Acc >> 10)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync {
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync case MDIO_READ_OP:
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16Acc = readRegister(pPhy, pPhy->u16Acc & 0x1F);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16State = MDIO_TA_RD;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16Cnt = 1;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync break;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync case MDIO_WRITE_OP:
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16RegAdr = pPhy->u16Acc & 0x1F;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16State = MDIO_TA_WR;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16Cnt = 2;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync break;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync default:
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync PhyLog(("PHY#%d ERROR! Invalid MDIO op: %d\n", pPhy->iInstance, pPhy->u16Acc >> 10));
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16State = MDIO_IDLE;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync break;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync }
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync }
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync break;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync case MDIO_TA_WR:
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync Assert(pPhy->u16Cnt <= 2);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync Assert(pPhy->u16Cnt > 0);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync if (--pPhy->u16Cnt == 0)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync {
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16State = MDIO_WRITE;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16Cnt = 16;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync }
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync break;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync case MDIO_WRITE:
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync Assert(pPhy->u16Cnt);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16Acc <<= 1;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync if (fPin)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16Acc |= 1;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync if (--pPhy->u16Cnt == 0)
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync {
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync writeRegister(pPhy, pPhy->u16RegAdr, pPhy->u16Acc);
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16State = MDIO_IDLE;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync }
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync break;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync default:
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync PhyLog(("PHY#%d ERROR! MDIO pin write in %s state\n", pPhy->iInstance, Phy::getStateName(pPhy->u16State)));
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync pPhy->u16State = MDIO_IDLE;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync break;
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync }
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync}
aaf6eb788dab09bc8c3c8576c60fabc60037a483vboxsync