summaryrefslogtreecommitdiff
path: root/cpu/arm920t/wmt/gmii.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpu/arm920t/wmt/gmii.c')
-rwxr-xr-xcpu/arm920t/wmt/gmii.c535
1 files changed, 535 insertions, 0 deletions
diff --git a/cpu/arm920t/wmt/gmii.c b/cpu/arm920t/wmt/gmii.c
new file mode 100755
index 0000000..10fc27b
--- /dev/null
+++ b/cpu/arm920t/wmt/gmii.c
@@ -0,0 +1,535 @@
+/*++
+Copyright (c) 2010 WonderMedia Technologies, Inc.
+
+This program is free software: you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation, either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU General Public License for more details. You
+should have received a copy of the GNU General Public License along with this
+program. If not, see http://www.gnu.org/licenses/>.
+
+WonderMedia Technologies, Inc.
+10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+--*/
+
+/* #include <conio.h> */
+
+/* #if !defined(__UPC_H__) */
+/* #include "upc.h" */
+/* #endif */
+#if !defined(__UASSERT_H__)
+#include "uassert.h"
+#endif
+/* #if !defined(__TMACRO_H__) */
+/* #include "tmacro.h" */
+/* #endif */
+#if !defined(__TBIT_H__)
+#include "tbit.h"
+#endif
+#if !defined(__MAC_H__)
+#include "mac.h"
+#endif
+#if !defined(__MII_H__)
+#include "mii.h"
+#endif
+
+/*--------------------- Static Definitions -------------------------*/
+#define CB_DELAY_MII_LB_STABLE (1000)
+
+/*--------------------- Static Classes ----------------------------*/
+
+/*--------------------- Static Variables --------------------------*/
+
+/*--------------------- Static Functions --------------------------*/
+
+/*--------------------- Export Variables --------------------------*/
+
+/*--------------------- Export Functions --------------------------*/
+
+/*
+ * Description: Read a word from MII, by embeded programming
+ *
+ * Parameters:
+ * In:
+ * dwIoBase - I/O base address
+ * byRevId - chip revision id
+ * byMiiAddr - address of register in MII
+ * Out:
+ * pwData - data read
+ *
+ * Return Value: TRUE if succeeded; FALSE if failed.
+ *
+ */
+BOOL GMIIbReadEmbeded(DWORD dwIoBase, BYTE byRevId, BYTE byMiiAddr, PWORD pwData)
+{
+ byRevId = byRevId;
+ WORD ww;
+
+ /* disable MIICR_MAUTO, so that mii addr can be set normally */
+ GMACvDisableMiiAutoPoll(dwIoBase);
+
+ /* MII reg offset */
+ VNSvOutPortB(dwIoBase + MAC_REG_MIIADR, byMiiAddr);
+
+ /* turn on MIICR_RCMD */
+ MACvRegBitsOn(dwIoBase, MAC_REG_MIICR, MIICR_RCMD);
+
+ /* W_MAX_TIMEOUT is the timeout period */
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ udelay(1000);
+ if (BITbIsBitOff(GMACbyReadMIICR(dwIoBase), MIICR_RCMD))
+ break;
+ }
+
+ /* get MII data */
+ VNSvInPortW(dwIoBase + MAC_REG_MIIDATA, pwData);
+
+ GMACvEnableMiiAutoPoll(dwIoBase);
+
+ if (ww == W_MAX_TIMEOUT)
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Description: Write a word to MII, by embeded programming
+ *
+ * Parameters:
+ * In:
+ * dwIoBase - I/O base address
+ * byRevId - chip revision id
+ * byMiiAddr - address of register in MII
+ * wData - data to write
+ *
+ * Return Value: TRUE if succeeded; FALSE if failed.
+ *
+ */
+BOOL GMIIbWriteEmbeded(DWORD dwIoBase, BYTE byRevId, BYTE byMiiAddr, WORD wData)
+{
+ byRevId = byRevId;
+ WORD ww;
+
+ /* disable MIICR_MAUTO, so that mii addr can be set normally */
+ GMACvDisableMiiAutoPoll(dwIoBase);
+
+ /* MII reg offset */
+ VNSvOutPortB(dwIoBase + MAC_REG_MIIADR, byMiiAddr);
+
+ /* set MII data */
+ VNSvOutPortW(dwIoBase + MAC_REG_MIIDATA, wData);
+
+ /* turn on MIICR_WCMD */
+ MACvRegBitsOn(dwIoBase, MAC_REG_MIICR, MIICR_WCMD);
+
+ /* W_MAX_TIMEOUT is the timeout period */
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ udelay(1000);
+ if (BITbIsBitOff(GMACbyReadMIICR(dwIoBase), MIICR_WCMD))
+ break;
+ }
+
+ GMACvEnableMiiAutoPoll(dwIoBase);
+
+ if (ww == W_MAX_TIMEOUT)
+ return FALSE;
+
+ return TRUE;
+}
+
+BOOL GMIIbIsRegBitsOn(DWORD dwIoBase, BYTE byRevId, BYTE byMiiAddr, WORD wTestBits)
+{
+ static WORD wOrgData;
+
+ GMIIbReadEmbeded(dwIoBase, byRevId, byMiiAddr, &wOrgData);
+ return BITbIsAllBitsOn(wOrgData, wTestBits);
+}
+
+BOOL GMIIbIsRegBitsOff(DWORD dwIoBase, BYTE byRevId, BYTE byMiiAddr, WORD wTestBits)
+{
+ static WORD wOrgData;
+
+ GMIIbReadEmbeded(dwIoBase, byRevId, byMiiAddr, &wOrgData);
+ return BITbIsAllBitsOff(wOrgData, wTestBits);
+}
+
+BOOL GMIIbReadAllRegs(DWORD dwIoBase, BYTE byRevId, PSMiiReg pMiiRegs)
+{
+ UINT ii;
+ PWORD pwData;
+ UINT cbWords;
+
+ pwData = (PWORD)pMiiRegs;
+ cbWords = sizeof(SMiiReg) / sizeof(WORD);
+
+ /* ii = Reg Address */
+ for (ii = 0; ii < cbWords; ii++) {
+ if (!GMIIbReadEmbeded(dwIoBase, byRevId, (BYTE)ii, pwData))
+ return FALSE;
+ pwData++;
+ }
+
+ return TRUE;
+}
+
+VOID GMIIvWaitForNwayCompleted(DWORD dwIoBase, BYTE byRevId)
+{
+ UINT uu;
+
+ /* delay about 8 sec. */
+ /* wait for AUTO-NEGO to complete (may never complete if */
+ /* no link), after that then, we can get correct link status */
+ /* NOTE: because I have no timer, so looping is used, */
+ /* if timer is available in your OS, use timer */
+ /* in stead of looping */
+
+ /* wait for BMSR_AUTOCM to off */
+ for (uu = 0; uu < CB_MAX_COUNT_AUTO_COMPLETE; uu++) {
+ if (GMIIbIsRegBitsOff(dwIoBase, byRevId, MII_REG_BMSR, BMSR_AUTOCM))
+ break;
+ }
+ /* wait for BMSR_AUTOCM to on */
+ /* NOTE.... read BMSR_AUTOCM bit will also clear BMSR_LNK bit */
+ for (uu = 0; uu < CB_MAX_COUNT_AUTO_COMPLETE; uu++) {
+ /* if AUTO-NEGO completed, then go out this loop */
+ /* otherwise, count down to time out */
+ if (GMIIbIsRegBitsOn(dwIoBase, byRevId, MII_REG_BMSR, BMSR_AUTOCM))
+ break;
+ }
+}
+
+VOID GMIIvSetLoopbackMode(DWORD dwIoBase, BYTE byRevId, BYTE byLoopbackMode)
+{
+ /* handle AUTO-NEGO */
+ switch (byLoopbackMode) {
+ case MII_LB_NONE:
+ if(GMIIbIsRegBitsOn(dwIoBase, byRevId, MII_REG_BMCR, BMCR_LBK)) {
+ /* turn off MII loopback */
+ MIIvRegBitsOff(dwIoBase, byRevId, MII_REG_BMCR, BMCR_LBK);
+ /* must turn on AUTO-NEGO after turn off BMCR_LBK, otherwise */
+ /* the AUTO-NEGO process will never end in some PHY (e.g. ESI...) */
+ MIIvSetAutoNegotiationOn(dwIoBase, byRevId);
+ }/* else do not thing */
+ break;
+
+ case MII_LB_INTERNAL:
+ MIIvSetAutoNegotiationOff(dwIoBase, byRevId);
+ MIIvRegBitsOn(dwIoBase, byRevId, MII_REG_BMCR, BMCR_LBK);
+ /* select 1000M */
+ MIIvRegBitsOn(dwIoBase, byRevId, MII_REG_BMCR, BMCR_SPEED1G);
+ MIIvRegBitsOff(dwIoBase, byRevId, MII_REG_BMCR, BMCR_SPEED100);
+ break;
+
+ case MII_LB_ISO:
+ /* we achieve isolation by do loopback in MII not in Transceiver */
+ MIIvSetAutoNegotiationOff(dwIoBase, byRevId);
+ MIIvRegBitsOn(dwIoBase, byRevId, MII_REG_BMCR, BMCR_LBK);
+ /* select 1000M */
+ MIIvRegBitsOn(dwIoBase, byRevId, MII_REG_BMCR, BMCR_SPEED1G);
+ MIIvRegBitsOff(dwIoBase, byRevId, MII_REG_BMCR, BMCR_SPEED100);
+ break;
+
+ default:
+ DBG_ASSERT(FALSE);
+ break;
+ }
+
+ /* wait for MII loopback to stable */
+ PCAvDelayByIO(CB_DELAY_MII_LB_STABLE);
+}
+
+VOID GMIIvSetDuplexMode(DWORD dwIoBase, BYTE byRevId, BOOL bFullDuplexOn)
+{
+ /* when force duplex mode, */
+ /* AUTO-NEGO should off */
+ MIIvSetAutoNegotiationOff(dwIoBase, byRevId);
+
+ if (bFullDuplexOn)
+ MIIvRegBitsOn(dwIoBase, byRevId, MII_REG_BMCR, BMCR_FDX);
+ else
+ MIIvRegBitsOff(dwIoBase, byRevId, MII_REG_BMCR, BMCR_FDX);
+}
+
+VOID GMIIvSetSpeedMode(DWORD dwIoBase, BYTE byRevId, BYTE bySpeed)
+{
+ /* when force speed mode, */
+ /* AUTO-NEGO should off */
+ MIIvSetAutoNegotiationOff(dwIoBase, byRevId);
+
+ switch (bySpeed) {
+ case MII_SPD_1000:
+ MIIvRegBitsOn(dwIoBase, byRevId, MII_REG_BMCR, BMCR_SPEED1G);
+ MIIvRegBitsOff(dwIoBase, byRevId, MII_REG_BMCR, BMCR_SPEED100);
+ break;
+ case MII_SPD_100:
+ MIIvRegBitsOff(dwIoBase, byRevId, MII_REG_BMCR, BMCR_SPEED1G);
+ MIIvRegBitsOn(dwIoBase, byRevId, MII_REG_BMCR, BMCR_SPEED100);
+ break;
+ case MII_SPD_10:
+ MIIvRegBitsOff(dwIoBase, byRevId, MII_REG_BMCR, BMCR_SPEED1G);
+ MIIvRegBitsOff(dwIoBase, byRevId, MII_REG_BMCR, BMCR_SPEED100);
+ break;
+
+ default:
+ DBG_ASSERT(FALSE);
+ break;
+ }
+}
+
+BOOL GMIIbIsAutoNegotiationOn(DWORD dwIoBase, BYTE byRevId)
+{
+ return GMIIbIsRegBitsOn(dwIoBase, byRevId, MII_REG_BMCR, BMCR_AUTO);
+}
+
+/*
+BOOL MIIbIsInFullDuplexMode(DWORD dwIoBase, BYTE byRevId)
+{
+ // if in AUTO-NEGO mode
+ if (byRevId>=REV_ID_VT3106J_A0)
+ return MACbIsRegBitsOn(dwIoBase, MAC_REG_MIISR, MIISR_N_FDX);
+
+ if (MIIbIsAutoNegotiationOn(dwIoBase, byRevId)) {
+
+ // if my TX_FD on, check both TX_FD
+ if (MIIbIsRegBitsOn(dwIoBase, byRevId, MII_REG_ANAR, ANAR_TXFD)) {
+ // partner's TX_FD
+ if (MIIbIsRegBitsOn(dwIoBase, byRevId, MII_REG_ANLPAR, ANLPAR_TXFD))
+ return TRUE;
+ }
+
+ // if my T4 on, check both T4
+ if (MIIbIsRegBitsOn(dwIoBase, byRevId, MII_REG_ANAR, ANAR_T4)) {
+ // partner's T4
+ if (MIIbIsRegBitsOn(dwIoBase, byRevId, MII_REG_ANLPAR, ANLPAR_T4))
+ return FALSE;
+ }
+
+ // if my TX_HD on, check both TX_HD
+ if (MIIbIsRegBitsOn(dwIoBase, byRevId, MII_REG_ANAR, ANAR_TX)) {
+ // partner's TX_HD
+ if (MIIbIsRegBitsOn(dwIoBase, byRevId, MII_REG_ANLPAR, ANLPAR_TX))
+ return FALSE;
+ }
+
+ // if my 10_FD on, check both 10_FD
+ if (MIIbIsRegBitsOn(dwIoBase, byRevId, MII_REG_ANAR, ANAR_10FD)) {
+ // partner's 10_FD
+ if (MIIbIsRegBitsOn(dwIoBase, byRevId, MII_REG_ANLPAR, ANLPAR_10FD))
+ return TRUE;
+ }
+
+ // if all above is not, then it would be 10_HD or no link
+ // both case will be half duplex
+ return FALSE;
+ } else {
+ // if in force mode
+ if (MIIbIsRegBitsOff(dwIoBase, byRevId, MII_REG_BMCR, BMCR_FDX))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+*/
+
+BOOL GMIIbSafeSoftwareReset(DWORD dwIoBase, BYTE byRevId)
+{
+ WORD ww;
+
+ /* turn on reset only, do not write other bits */
+ GMIIbWriteEmbeded(dwIoBase, byRevId, MII_REG_BMCR, BMCR_RESET);
+
+ /* polling till MII reset complete */
+ /* W_MAX_TIMEOUT is the timeout period */
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ if (GMIIbIsRegBitsOff(dwIoBase, byRevId, MII_REG_BMCR, BMCR_RESET))
+ break;
+ }
+
+ if (ww == W_MAX_TIMEOUT)
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Description: Scan how many PHY in MII bus, and put PYH id
+ * in the pbyPhyId array
+ *
+ * Parameters:
+ * In:
+ * dwIoBase - I/O base address
+ * byRevId - chip revision id
+ * Out:
+ * puTotalPhyNum - total # of PHY
+ * pbyPhyId - PHY id array
+ *
+ * NOTE: size of pbyPhyId should larger than MAX_PHY_DEVICE
+ * otherwise, memory will corrupt
+ *
+ * Return Value: TRUE if succeeded; FALSE if failed.
+ *
+ */
+VOID GMIIvScanAllPhy(DWORD dwIoBase, BYTE byRevId, PBYTE pbyPhyId, PUINT puTotalPhyNum)
+{
+ BYTE byOrgMIIADR;
+ BYTE byOrgMIICR;
+ DWORD dwPhyCmrId;
+ UINT uPhyArrayIdx;
+ BYTE byPhyId, byOrgPhyId;
+
+ /* keep original MIICR value */
+ VNSvInPortB(dwIoBase + MAC_REG_MIIADR, &byOrgMIIADR);
+ VNSvInPortB(dwIoBase + MAC_REG_MIICR, &byOrgMIICR);
+
+ /* disable MIICR_MAUTO, so that mii addr can be set normally */
+ GMACvDisableMiiAutoPoll(dwIoBase);
+
+ /* keep original phy ID */
+ byOrgPhyId = GMACbyGetPhyId(dwIoBase);
+
+ /* scan all PHY */
+ uPhyArrayIdx = 0;
+ /* PHI id 0 is not a valid id */
+ for (byPhyId = 1; byPhyId < MAX_PHY_DEVICE; byPhyId++) {
+ GMACvSetPhyId(dwIoBase, byRevId, byPhyId);
+
+ /* detect if PHY exist? */
+ MIIvReadPhyCmrId(dwIoBase, byRevId, &dwPhyCmrId);
+ if ((dwPhyCmrId != 0xFFFFFFFFUL) && (dwPhyCmrId != 0UL)) {
+ pbyPhyId[uPhyArrayIdx] = byPhyId;
+ uPhyArrayIdx++;
+ }
+ }
+ *puTotalPhyNum = uPhyArrayIdx;
+
+ /* restore original phy id */
+ GMACvSetPhyId(dwIoBase, byRevId, byOrgPhyId);
+
+ /* restore MIICR */
+ VNSvOutPortB(dwIoBase + MAC_REG_MIIADR, byOrgMIIADR);
+ VNSvOutPortB(dwIoBase + MAC_REG_MIICR, byOrgMIICR);
+}
+
+VOID GMIIvSetActiveForcedPhy(DWORD dwIoBase, BYTE byRevId, PBYTE pbyPhyId, UINT uTotalPhyNum, BYTE byPhyId)
+{
+ UINT uu;
+ BYTE byOrgMIIADR;
+ BYTE byOrgMIICR;
+
+ /* keep original MIICR value */
+ VNSvInPortB(dwIoBase + MAC_REG_MIIADR, &byOrgMIIADR);
+ VNSvInPortB(dwIoBase + MAC_REG_MIICR, &byOrgMIICR);
+
+ /* disable MIICR_MAUTO, so that mii addr can be set normally */
+ GMACvDisableMiiAutoPoll(dwIoBase);
+
+ /* iso all PHY */
+ for (uu = 0; uu < uTotalPhyNum; uu++) {
+ GMACvSetPhyId(dwIoBase, byRevId, pbyPhyId[uu]);
+ MIIvRegBitsOn(dwIoBase, byRevId, MII_REG_BMCR, BMCR_ISO);
+ }
+
+ /* finally, set correct PHY id */
+ GMACvSetPhyId(dwIoBase, byRevId, byPhyId);
+ /* active this PHY */
+ MIIvRegBitsOff(dwIoBase, byRevId, MII_REG_BMCR, BMCR_ISO);
+
+ /* restore MIICR */
+ VNSvOutPortB(dwIoBase + MAC_REG_MIIADR, byOrgMIIADR);
+ VNSvOutPortB(dwIoBase + MAC_REG_MIICR, byOrgMIICR);
+}
+
+/* if no PHY linked, return FALSE */
+BOOL GMIIbSetActiveLinkedPhy(DWORD dwIoBase, BYTE byRevId, PBYTE pbyPhyId, UINT uTotalPhyNum)
+{
+ BOOL bRetVal = FALSE;
+ UINT uu;
+ BYTE byActPhyId, byOrgPhyId;
+ BYTE byOrgMIIADR;
+ BYTE byOrgMIICR;
+
+ /* keep original MIICR value */
+ VNSvInPortB(dwIoBase + MAC_REG_MIIADR, &byOrgMIIADR);
+ VNSvInPortB(dwIoBase + MAC_REG_MIICR, &byOrgMIICR);
+
+ /* disable MIICR_MAUTO, so that mii addr can be set normally */
+ GMACvDisableMiiAutoPoll(dwIoBase);
+
+ byOrgPhyId = GMACbyGetPhyId(dwIoBase);
+
+ for (uu = 0; uu < uTotalPhyNum; uu++) {
+ GMACvSetPhyId(dwIoBase, byRevId, pbyPhyId[uu]);
+
+ if (GMIIbIsRegBitsOn(dwIoBase, byRevId, MII_REG_BMSR, BMSR_LNK)) {
+
+ byActPhyId = pbyPhyId[uu];
+
+ /* iso all PHY */
+ for (uu = 0; uu < uTotalPhyNum; uu++) {
+ GMACvSetPhyId(dwIoBase, byRevId, pbyPhyId[uu]);
+ MIIvRegBitsOn(dwIoBase, byRevId, MII_REG_BMCR, BMCR_ISO);
+ }
+
+ /* finally, set correct PHY id */
+ GMACvSetPhyId(dwIoBase, byRevId, byActPhyId);
+ /* active this PHY */
+ MIIvRegBitsOff(dwIoBase, byRevId, MII_REG_BMCR, BMCR_ISO);
+ bRetVal = TRUE;
+ break;
+ }
+ }
+
+ if (!bRetVal)
+ /* if no link, set original PHY id */
+ GMACvSetPhyId(dwIoBase, byRevId, byOrgPhyId);
+
+ /* restore MIICR */
+ VNSvOutPortB(dwIoBase + MAC_REG_MIIADR, byOrgMIIADR);
+ VNSvOutPortB(dwIoBase + MAC_REG_MIICR, byOrgMIICR);
+ return bRetVal;
+}
+
+VOID GMIIvInitialize(DWORD dwIoBase, BYTE byRevId, DWORD dwPhyCmrId)
+{
+ WORD wOrgData;
+
+ /* PHY company/module, don't care revision id */
+ dwPhyCmrId &= CID_REV_ID_MASK_OFF;
+
+ switch (dwPhyCmrId) {
+ case CID_CICADA_CIS8201:
+ /* NOTICE!! For CICADA CS8201 PHY */
+ /* Turn on AUX_MODE (bit 2) in MII AUX register (offset 1Ch) */
+ MIIvRegBitsOn(dwIoBase, byRevId, MII_REG_AUXCSR, AUXCSR_MDPPS);
+
+ /* Turn on bit 2 in offset 0x1B, this patch code only adopt to CIS8201,
+ not for integrated PHY in VT3216 */
+ MIIvRegBitsOn(dwIoBase, byRevId, MII_REG_LED, LED_LALBE);
+
+ break;
+
+ case CID_CICADA_CIS3216I:
+ case CID_CICADA_CIS3216I64:
+ break;
+
+ case CID_MARVELL_1000:
+ case CID_MARVELL_1000S:
+ /* Assert CRS on Transmit */
+ MIIvRegBitsOn(dwIoBase, byRevId, MII_REG_PSCR, PSCR_ACRSTX);
+ break;
+
+ default:
+ break;
+ }
+
+ /* if ISO is on, turn it off */
+ GMIIbReadEmbeded(dwIoBase, byRevId, MII_REG_BMCR, &wOrgData);
+ if (BITbIsBitOn(wOrgData, BMCR_ISO)) {
+ wOrgData &= ~BMCR_ISO;
+ GMIIbWriteEmbeded(dwIoBase, byRevId, MII_REG_BMCR, wOrgData);
+ }
+}