⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smc.c

📁 aesop s3c2440a BSP for windowsce 6.0
💻 C
📖 第 1 页 / 共 4 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name:  

Abstract:  
    Routines for the SMC9000 ethernet controller used for the Windows CE
    debug ethernet services, and bootloaders.

Functions:


Notes: 
    These routines are called at system init and other times when system calls aren't allowed, so
    they can't make any system calls.
    
--*/


// Note : The Odo SMC implementation sometimes encounters read errors if we
// optimize this routine.  So for now I'm just going to turn of all 
// optimizations.
#pragma optimize("", off)

#include <windows.h>
#include <halether.h>
#include <ceddk.h>
#include "smchw.h"
#include "smcsw.h"
#include "udp.h"

// The base address of the SMC registers.  Also, allow for a multiplier, since the Odo
// platform uses 32 bit accesses of the registers.
static BYTE volatile *pbEthernetBase;
static DWORD dwRegisterMultiplier;

#define ReadWord( wOffset ) READ_PORT_USHORT((PUSHORT)(pbEthernetBase + (wOffset*dwRegisterMultiplier)))
#define WriteWord( wOffset, Value ) WRITE_PORT_USHORT((PUSHORT)(pbEthernetBase + (wOffset*dwRegisterMultiplier)),(USHORT)(Value))

// If this is defined, broadcast frames will be discarded.  Since we need to process
// ARPs, leave broadcast filter off, and filter out packets as soon as we can.  This, since
// we have to take an interrupt anyway, looking at the first few bytes isn't that bad. If
// the SMC chip could be configured so that we didn't even get interrupts for broadcast
// packets, we might look at updating the ARP cache on the desktop and filtering out all
// broadcasts...
#define NO_BROADCAST 0

#define BROADCAST_FILTER_BIT 0x4000

// If any of the following bits are set in the received status word, discard frame
#if NO_BROADCAST
#define FRAME_FILTER  (0xAC00 | BROADCAST_FILTER_BIT)  // No broadcast
#else
#define FRAME_FILTER  0xAC00   // Allow broadcast
#endif

// For debugging, if defined, this will cause all Rx/Tx data to be dumped to debug serial port
#undef SMC_DUMP_FRAMES
#define SMC_DUMP_FRAMES

// Mask to use for interrupts
static UINT16 wIntMask;

// Controls whether we filter out broadcast packets (except ARP requests...)
static DWORD dwConfigOptions;

static void SendFrameError( char *pszPrefix, UINT16 wCompletionCode );
#ifdef SMC_DUMP_FRAMES
static void DumpEtherFrame( BYTE *pFrame, WORD cwFrameLength );
#endif





// This is called to initialze the ethernet low level driver.  The base address of the ethernet hardware
// is passed into the routine.  The routine will return TRUE for a successful initialization.






static void smc_udelay(unsigned int us)
{
    volatile int i;
    
    for(i=0 ; (unsigned int)i < us ; i++)
    {
    }
}
static WORD smc_read_phy_register (unsigned char phyreg)
{
        int oldBank;
        int i;
        BYTE mask;
        WORD mii_reg;
        BYTE bits[64];
        int clk_idx = 0;
        int input_idx;
        WORD phydata;
        BYTE phyaddr = SMC_PHY_ADDR;

        /* 32 consecutive ones on MDO to establish sync */
        for (i = 0; i < 32; ++i)
                bits[clk_idx++] = MII_MDOE | MII_MDO;

        /* Start code <01> */
        bits[clk_idx++] = MII_MDOE;
        bits[clk_idx++] = MII_MDOE | MII_MDO;

        /* Read command <10> */
        bits[clk_idx++] = MII_MDOE | MII_MDO;
        bits[clk_idx++] = MII_MDOE;

        /* Output the PHY address, msb first */
        mask = (BYTE) 0x10;
        for (i = 0; i < 5; ++i) {
                if (phyaddr & mask)
                        bits[clk_idx++] = MII_MDOE | MII_MDO;
                else
                        bits[clk_idx++] = MII_MDOE;

                /* Shift to next lowest bit */
                mask >>= 1;
        }

        /* Output the phy register number, msb first */
        mask = (BYTE) 0x10;
        for (i = 0; i < 5; ++i) {
                if (phyreg & mask)
                        bits[clk_idx++] = MII_MDOE | MII_MDO;
                else
                        bits[clk_idx++] = MII_MDOE;

                /* Shift to next lowest bit */
                mask >>= 1;
        }

        /* Tristate and turnaround (2 bit times) */
        bits[clk_idx++] = 0;
        /*bits[clk_idx++] = 0; */

        /* Input starts at this bit time */
        input_idx = clk_idx;

        /* Will input 16 bits */
        for (i = 0; i < 16; ++i)
                bits[clk_idx++] = 0;

        /* Final clock bit */
        bits[clk_idx++] = 0;

        /* Save the current bank */
        oldBank = ReadWord(BANKSEL_REG);

        /* Select bank 3 */
        WriteWord( BANKSEL_REG, BANK3 );

        /* Get the current MII register value */
        mii_reg = ReadWord (MII_REG);

        /* Turn off all MII Interface bits */
        mii_reg &= ~(MII_MDOE | MII_MCLK | MII_MDI | MII_MDO);

        /* Clock all 64 cycles */
        for (i = 0; i < sizeof bits; ++i) {
                /* Clock Low - output data */
                WriteWord (MII_REG, mii_reg | bits[i]);
                smc_udelay (SMC_PHY_CLOCK_DELAY);


                /* Clock Hi - input data */
                WriteWord ( MII_REG, mii_reg | bits[i] | MII_MCLK);
                smc_udelay (SMC_PHY_CLOCK_DELAY);
                bits[i] |= ReadWord (MII_REG) & MII_MDI;
        }

        /* Return to idle state */
        /* Set clock to low, data to low, and output tristated */
        WriteWord (MII_REG, mii_reg);
        smc_udelay (SMC_PHY_CLOCK_DELAY);

        /* Restore original bank select */
        WriteWord( BANKSEL_REG, oldBank );

        /* Recover input data */
        phydata = 0;
        for (i = 0; i < 16; ++i) {
                phydata <<= 1;

                if (bits[input_idx++] & MII_MDI)
                        phydata |= 0x0001;
        }


        return (phydata);
}


/*------------------------------------------------------------
 . Writes a register to the MII Management serial interface
 .-------------------------------------------------------------*/
static void smc_write_phy_register (BYTE phyreg, WORD phydata)
{
        int oldBank;
        int i;
        WORD mask;
        WORD mii_reg;
        BYTE bits[65];
        int clk_idx = 0;
        BYTE phyaddr = SMC_PHY_ADDR;

        /* 32 consecutive ones on MDO to establish sync */
        for (i = 0; i < 32; ++i)
                bits[clk_idx++] = MII_MDOE | MII_MDO;

        /* Start code <01> */
        bits[clk_idx++] = MII_MDOE;
        bits[clk_idx++] = MII_MDOE | MII_MDO;

        /* Write command <01> */
        bits[clk_idx++] = MII_MDOE;
        bits[clk_idx++] = MII_MDOE | MII_MDO;

        /* Output the PHY address, msb first */
        mask = (BYTE) 0x10;
        for (i = 0; i < 5; ++i) {
                if (phyaddr & mask)
                        bits[clk_idx++] = MII_MDOE | MII_MDO;
                else
                        bits[clk_idx++] = MII_MDOE;

                /* Shift to next lowest bit */
                mask >>= 1;
        }

        /* Output the phy register number, msb first */
        mask = (BYTE) 0x10;
        for (i = 0; i < 5; ++i) {
                if (phyreg & mask)
                        bits[clk_idx++] = MII_MDOE | MII_MDO;
                else
                        bits[clk_idx++] = MII_MDOE;

                /* Shift to next lowest bit */
                mask >>= 1;
        }

        /* Tristate and turnaround (2 bit times) */
        bits[clk_idx++] = 0;
        bits[clk_idx++] = 0;

        /* Write out 16 bits of data, msb first */
        mask = 0x8000;
        for (i = 0; i < 16; ++i) {
                if (phydata & mask)
                        bits[clk_idx++] = MII_MDOE | MII_MDO;
                else
                        bits[clk_idx++] = MII_MDOE;

                /* Shift to next lowest bit */
                mask >>= 1;
        }
        /* Final clock bit (tristate) */
        bits[clk_idx++] = 0;

        /* Save the current bank */
        oldBank = ReadWord(BANKSEL_REG);

        /* Select bank 3 */
        WriteWord( BANKSEL_REG, BANK3 );

        /* Get the current MII register value */
        mii_reg = ReadWord (MII_REG);

        /* Turn off all MII Interface bits */
        mii_reg &= ~(MII_MDOE | MII_MCLK | MII_MDI | MII_MDO);

        /* Clock all cycles */
        for (i = 0; i < sizeof bits; ++i) {
                /* Clock Low - output data */
                WriteWord ( MII_REG, mii_reg | bits[i]);
                smc_udelay (SMC_PHY_CLOCK_DELAY);


                /* Clock Hi - input data */
                WriteWord ( MII_REG, mii_reg | bits[i] | MII_MCLK);
                smc_udelay (SMC_PHY_CLOCK_DELAY);
                bits[i] |= ReadWord (MII_REG) & MII_MDI;
        }

        /* Return to idle state */
        /* Set clock to low, data to low, and output tristated */
        WriteWord ( MII_REG, mii_reg);
        smc_udelay (SMC_PHY_CLOCK_DELAY);

        /* Restore original bank select */
        WriteWord( BANKSEL_REG, oldBank );

}



#if 1

static void smc_wait_ms(unsigned int ms)
{
    volatile int i;
    unsigned int i2;
    
    for(i2=0 ; i2 < ms ; i2++)
    {
       for(i=0 ; i < 1000 ; i++)
       {
       }
    }   
}



static void smc_phy_configure ()
{
        int timeout;
        BYTE phyaddr;
        WORD my_phy_caps;       /* My PHY capabilities */
        WORD my_ad_caps;        /* My Advertised capabilities */
        WORD status = 0;        /*;my status = 0 */
        int failed = 0;



        EdbgOutputDebugString("smc_phy_configure()\r\n");
        EdbgOutputDebugString("phy cfg reg1: 0x%x\n", smc_read_phy_register(PHY_CFG1_REG) );


        /* Get the detected phy address */
        phyaddr = SMC_PHY_ADDR;



        /* Reset the PHY, setting all other bits to zero */
        smc_write_phy_register (PHY_CNTL_REG, PHY_CNTL_RST);
        timeout = 6;            /* Wait up to 3 seconds */
        while (timeout--) {
                if (!(smc_read_phy_register (PHY_CNTL_REG) & PHY_CNTL_RST)) {
                        /* reset complete */
                        break;
                }

                smc_wait_ms (500);      /* wait 500 millisecs */
        }


        if (timeout < 1) {
                EdbgOutputDebugString ("%s:PHY reset timed out\n", SMC_DEV_NAME);
                goto smc_phy_configure_exit;
        }

        /* Read PHY Register 18, Status Output */
        /* lp->lastPhy18 = smc_read_phy_register(PHY_INT_REG); */
        /* Enable PHY Interrupts (for register 18) */
        /* Interrupts listed here are disabled */

        smc_write_phy_register (PHY_MASK_REG, 0x0000);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -