if_ppc405.c
来自「eCos操作系统源码」· C语言 代码 · 共 673 行 · 第 1/2 页
C
673 行
//==========================================================================//// dev/if_ppc405.c//// Ethernet device driver for PowerPC PPC405 boards////==========================================================================//####ECOSGPLCOPYRIGHTBEGIN####// -------------------------------------------// This file is part of eCos, the Embedded Configurable Operating System.// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.// Copyright (C) 2002, 2003 Gary Thomas//// eCos 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 or (at your option) any later version.//// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.//// As a special exception, if other files instantiate templates or use macros// or inline functions from this file, or you compile this file and link it// with other works to produce a work based on this file, this file does not// by itself cause the resulting work to be covered by the GNU General Public// License. However the source code for this file must still be made available// in accordance with section (3) of the GNU General Public License.//// This exception does not invalidate any other reasons why a work based on// this file might be covered by the GNU General Public License.//// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.// at http://sources.redhat.com/ecos/ecos-license/// -------------------------------------------//####ECOSGPLCOPYRIGHTEND####//==========================================================================//#####DESCRIPTIONBEGIN####//// Author(s): gthomas// Contributors: gthomas// Date: 2003-08-15// Purpose: // Description: hardware driver for PPC405// ////####DESCRIPTIONEND####////==========================================================================// Ethernet device driver for PPC405#include <pkgconf/system.h>#include <pkgconf/devs_eth_powerpc_ppc405.h>#include <pkgconf/io_eth_drivers.h>#ifdef CYGPKG_NET#include <pkgconf/net.h>#endif#include <cyg/infra/cyg_type.h>#include <cyg/infra/diag.h>#include <cyg/hal/hal_arch.h>#include <cyg/hal/hal_cache.h>#include <cyg/hal/hal_intr.h>#include <cyg/hal/drv_api.h>#include <cyg/hal/hal_if.h>#include <cyg/hal/ppc_regs.h>#include <cyg/io/eth/netdev.h>#include <cyg/io/eth/eth_drv.h>#include <cyg/io/eth_phy.h>//// PHY access functions//static void ppc405_eth_phy_init(void);static void ppc405_eth_phy_put_reg(int reg, int phy, unsigned short data);static bool ppc405_eth_phy_get_reg(int reg, int phy, unsigned short *val);#include "ppc405_enet.h"#include CYGDAT_DEVS_PPC405_ETH_INL#define os_printf diag_printf// For fetching the ESA from RedBoot#include <cyg/hal/hal_if.h>#ifndef CONFIG_ESA#define CONFIG_ESA 6#endifstatic void ppc405_eth_int(struct eth_drv_sc *data);#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIREDstatic cyg_interrupt ppc405_emac_interrupt;static cyg_handle_t ppc405_emac_interrupt_handle;static cyg_interrupt ppc405_mal_txeob_interrupt;static cyg_handle_t ppc405_mal_txeob_interrupt_handle;static cyg_interrupt ppc405_mal_rxeob_interrupt;static cyg_handle_t ppc405_mal_rxeob_interrupt_handle;static cyg_interrupt ppc405_mal_txde_interrupt;static cyg_handle_t ppc405_mal_txde_interrupt_handle;static cyg_interrupt ppc405_mal_rxde_interrupt;static cyg_handle_t ppc405_mal_rxde_interrupt_handle;static cyg_interrupt ppc405_mal_serr_interrupt;static cyg_handle_t ppc405_mal_serr_interrupt_handle;#define EMAC_INTERRUPT_HANDLER(_int_,_hdlr_) \ cyg_drv_interrupt_create(_int_, \ 0, \ (cyg_addrword_t)sc, /* Data item passed to interrupt handler */ \ (cyg_ISR_t *)ppc405_eth_isr, \ (cyg_DSR_t *)eth_drv_dsr, \ &ppc405_##_hdlr_##_interrupt_handle, \ &ppc405_##_hdlr_##_interrupt); \ cyg_drv_interrupt_attach(ppc405_##_hdlr_##_interrupt_handle); \ cyg_drv_interrupt_acknowledge(_int_); \ cyg_drv_interrupt_unmask(_int_);// This ISR is called when the ethernet interrupt occursstatic intppc405_eth_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs){ struct eth_drv_sc *sc = (struct eth_drv_sc *)data; struct ppc405_eth_info *qi = (struct ppc405_eth_info *)sc->driver_private; cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_MAL_SERR); cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_MAL_TX_EOB); cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_MAL_RX_EOB); cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_MAL_TX_DE); cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_MAL_RX_DE); cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_EMAC0); qi->ints = vector; return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR); // Run the DSR}#endif// Deliver function (ex-DSR) handles the ethernet [logical] processingstatic voidppc405_eth_deliver(struct eth_drv_sc *sc){#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED struct ppc405_eth_info *qi = (struct ppc405_eth_info *)sc->driver_private; cyg_uint32 old_ints;#endif ppc405_eth_int(sc);#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED // Allow interrupts to happen again HAL_DISABLE_INTERRUPTS(old_ints); cyg_drv_interrupt_acknowledge(qi->ints); cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_MAL_SERR); cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_MAL_TX_EOB); cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_MAL_RX_EOB); cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_MAL_TX_DE); cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_MAL_RX_DE); cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_EMAC0); HAL_RESTORE_INTERRUPTS(old_ints);#endif}//// PHY unit access//static void ppc405_eth_phy_init(void){ // Set up MII hardware - nothing to do on this platform}static void ppc405_eth_phy_put_reg(int reg, int phy, unsigned short data){ unsigned long reg_val; reg_val = EMAC0_STACR_STAC_WRITE | EMAC0_STACR_OPBC_66; reg_val |= (phy << EMAC0_STACR_PCDA_SHIFT) | reg; reg_val |= (data << EMAC0_STACR_PHYD_SHIFT);#ifdef PHY_DEBUG os_printf("PHY PUT - reg: %d, phy: %d, val: %04x [%08x]\n", reg, phy, data, reg_val);#endif while ((EMAC0_STACR & EMAC0_STACR_OC) == 0) ; // Wait for MII free EMAC0_STACR = reg_val; while ((EMAC0_STACR & EMAC0_STACR_OC) == 0) ; // Wait for MII complete}static bool ppc405_eth_phy_get_reg(int reg, int phy, unsigned short *val){ unsigned long reg_val; reg_val = EMAC0_STACR_STAC_READ | EMAC0_STACR_OPBC_66; reg_val |= (phy << EMAC0_STACR_PCDA_SHIFT) | reg;#ifdef PHY_DEBUG os_printf("PHY GET - reg: %d, phy: %d [%08x] = ", reg, phy, reg_val);#endif while ((EMAC0_STACR & EMAC0_STACR_OC) == 0) ; // Wait for MII free EMAC0_STACR = reg_val; while ((EMAC0_STACR & EMAC0_STACR_OC) == 0) ; // Wait for MII complete if ((EMAC0_STACR & EMAC0_STACR_PHYE) == 0) { // Operation completed with no error *val = (EMAC0_STACR & EMAC0_STACR_PHYD) >> EMAC0_STACR_PHYD_SHIFT;#ifdef PHY_DEBUG os_printf("%04x\n", *val);#endif return true; } else { // No response#ifdef PHY_DEBUG os_printf("***ERROR***\n");#endif return false; }}//// [re]Initialize the ethernet controller// Done separately since shutting down the device requires a // full reconfiguration when re-enabling.// when static boolppc405_eth_reset(struct eth_drv_sc *sc, unsigned char *enaddr, int flags){ struct ppc405_eth_info *qi = (struct ppc405_eth_info *)sc->driver_private; volatile mal_bd_t *rxbd, *RxBD, *txbd, *TxBD; unsigned char *RxBUF, *TxBUF; int i, int_state; unsigned long mal_status, mode; unsigned short phy_state = 0; // Ignore unless device is idle/stopped if ((EMAC0_MR0 & (EMAC0_MR0_RXI|EMAC0_MR0_TXI)) != (EMAC0_MR0_RXI|EMAC0_MR0_TXI)) { return true; } // Make sure interrupts are off while we mess with the device HAL_DISABLE_INTERRUPTS(int_state); // Reset EMAC controller EMAC0_MR0 |= EMAC0_MR0_SRST; i = 0; while ((EMAC0_MR0 & EMAC0_MR0_SRST) != 0) { if (++i >= 500000) { os_printf("PPC405 Ethernet does not reset\n"); HAL_RESTORE_INTERRUPTS(int_state); return false; } } TxBD = qi->txbd_table; txbd = (mal_bd_t *)CYGARC_UNCACHED_ADDRESS(TxBD); RxBD = qi->rxbd_table; rxbd = (mal_bd_t *)CYGARC_UNCACHED_ADDRESS(RxBD); qi->tbase = qi->txbd = qi->tnext = txbd; qi->rbase = qi->rxbd = qi->rnext = rxbd; qi->txactive = 0; RxBUF = qi->rxbuf; TxBUF = qi->txbuf; // setup buffer descriptors for (i = 0; i < CYGNUM_DEVS_ETH_POWERPC_PPC405_RxNUM; i++) { rxbd->length = 0; rxbd->buffer = (unsigned long)RxBUF; rxbd->status = MAL_BD_R | MAL_BD_I; RxBUF += CYGNUM_DEVS_ETH_POWERPC_PPC405_BUFSIZE; rxbd++; } rxbd--; rxbd->status |= MAL_BD_W; // Last buffer for (i = 0; i < CYGNUM_DEVS_ETH_POWERPC_PPC405_TxNUM; i++) { txbd->length = 0; txbd->buffer = (unsigned long)TxBUF; txbd->status = 0; TxBUF += CYGNUM_DEVS_ETH_POWERPC_PPC405_BUFSIZE; txbd++; } txbd--; txbd->status |= MAL_BD_W; // Last buffer // Tell memory access layer where the buffer descriptors are CYGARC_MTDCR(MAL0_TXCARR, MAL_CASR_C0|MAL_CASR_C1); // Disable/reset channel #0 & #1 CYGARC_MTDCR(MAL0_RXCARR, MAL_CASR_C0); // Disable/reset channel #0 CYGARC_MTDCR(MAL0_CFG, MAL_CFG_SR); i = 0; CYGARC_MFDCR(MAL0_CFG, mal_status); while ((mal_status & MAL_CFG_SR) != 0) { if (++i >= 500000) { os_printf("PPC405 MAL does not reset\n"); HAL_RESTORE_INTERRUPTS(int_state); return false; } } CYGARC_MTDCR(MAL0_CFG, MAL_CFG_PLBB | MAL_CFG_OPBBL | MAL_CFG_LEA | MAL_CFG_PLBT_DEFAULT); CYGARC_MTDCR(MAL0_TXCTP0R, TxBD); CYGARC_MTDCR(MAL0_RXCTP0R, RxBD); CYGARC_MTDCR(MAL0_RXBS0, (CYGNUM_DEVS_ETH_POWERPC_PPC405_BUFSIZE/16)); // Receive buffer size // Set device physical address (ESA) EMAC0_IAHR = (enaddr[0]<<8) | (enaddr[1]<<0); EMAC0_IALR = (enaddr[2]<<24) | (enaddr[3]<<16) | (enaddr[4]<<8) | (enaddr[5]<<0); // Operating mode if (!_eth_phy_init(qi->phy)) { return false; } phy_state = _eth_phy_state(qi->phy); os_printf("PPC405 ETH: "); mode = EMAC0_MR1_RFS_4096 | EMAC0_MR1_TFS_2048 | EMAC0_MR1_TR0_MULTI | EMAC0_MR1_APP; if ((phy_state & ETH_PHY_STAT_LINK) != 0) { if ((phy_state & ETH_PHY_STAT_100MB) != 0) { // Link can handle 100Mb mode |= EMAC0_MR1_MF_100MB; os_printf("100Mb"); if ((phy_state & ETH_PHY_STAT_FDX) != 0) { mode |= EMAC0_MR1_FDE | EMAC0_MR1_EIFC | EMAC0_MR1_IST; os_printf("/Full Duplex"); } } else { // Assume 10Mb, half duplex mode |= EMAC0_MR1_MF_10MB; os_printf("10Mb"); } } else { os_printf("/***NO LINK***"); return false; } os_printf("\n"); EMAC0_MR1 = mode; // Configure receiver EMAC0_RMR = EMAC0_RMR_IAE | EMAC0_RMR_BAE | EMAC0_RMR_RRP | EMAC0_RMR_RFP;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?