/* Cleopatre project {{{ * * Copyright (C) 2008 SPiDCOM Technologies * * 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * }}} */ /** * \file driver/net/arm/synop3504_hw.c * \brief Hardware access for Synopsys 3504 driver. * \ingroup cleopatre_net_driver. * * Hardware access level part of the Ethernet 3504 Synopsys IP. */ #include #include #include "synop3504_reg.h" #include "synop3504_hw.h" #define TRACE(...) printk("Synop3504_hw:" __VA_ARGS__) //#define TRACE(...) /** * A not accurate delay. * \param delay delay value in "instructions". */ static inline void unaccuracy_delay(uint32_t delay) { while(delay--); }// synop_delay static inline uint32_t SynopsysReadMacReg(Synopsys *synop, uint32_t reg) { uint32_t data; data = __raw_readl(synop->macbase+reg); return data; } static inline void SynopsysWriteMacReg(Synopsys *synop, uint32_t reg, uint32_t data) { __raw_writel(data, synop->macbase+reg); } static inline void SynopsysSetMacReg(Synopsys *synop, uint32_t reg, uint32_t data) { uint32_t value; value = __raw_readl(synop->macbase+reg); value |= data; __raw_writel(value, synop->macbase+reg); } static inline void SynopsysClearMacReg(Synopsys *synop, uint32_t reg, uint32_t data) { uint32_t value; value = __raw_readl(synop->macbase+reg); value &= ~data; __raw_writel(value, synop->macbase+reg); } static inline uint32_t SynopsysReadDmaReg(Synopsys *synop, uint32_t reg) { uint32_t data; data = __raw_readl(synop->dmabase+reg); return data; } static inline void SynopsysWriteDmaReg(Synopsys *synop, uint32_t reg, uint32_t data) { __raw_writel(data, synop->dmabase+reg); } static inline void SynopsysSetDmaReg(Synopsys *synop, uint32_t reg, uint32_t data) { uint32_t value; value = __raw_readl(synop->dmabase+reg); value |= data; __raw_writel(value, synop->dmabase+reg); } static inline void SynopsysClearDmaReg(Synopsys *synop, uint32_t reg, uint32_t data) { uint32_t value; value = __raw_readl(synop->dmabase+reg); value &= ~data; __raw_writel(value, synop->dmabase+reg); } uint16_t SynopsysMiiRead(Synopsys *synop, uint8_t reg) { uint32_t addr; uint16_t data; uint32_t phyaddr; phyaddr = synop->phyaddr; //Enable the phy clock and set the busy bit. addr = ((phyaddr << GmiiDevShift) & GmiiDevMask) | ((reg << GmiiRegShift) & GmiiRegMask) | GmiiRead; SynopsysWriteMacReg(synop, GmacGmiiAddr, (addr | GmiiCsrClk2 | GmiiBusy)); //Wait for busy bit to clear while((SynopsysReadMacReg(synop, GmacGmiiAddr) & GmiiBusy) == GmiiBusy); //Read the phy device data data = SynopsysReadMacReg(synop, GmacGmiiData) & GmiiDataMask; return data; } void SynopsysMiiWrite(Synopsys *synop, uint8_t reg, uint16_t data) { uint32_t addr; uint32_t phyaddr; phyaddr = synop->phyaddr; SynopsysWriteMacReg(synop, GmacGmiiData, data); //Enable the phy clock and set the busy bit. addr = ((phyaddr << GmiiDevShift) & GmiiDevMask) | ((reg << GmiiRegShift) & GmiiRegMask) | GmiiWrite; SynopsysWriteMacReg(synop, GmacGmiiAddr, (addr | GmiiCsrClk2 | GmiiBusy)); //Wait for busy bit to clear while((SynopsysReadMacReg(synop, GmacGmiiAddr) & GmiiBusy) == GmiiBusy); } /** * Reset the DMA interface. * \param synop device structure. */ void SynopsysReset(Synopsys *synop) { uint32_t data; SynopsysWriteDmaReg(synop, DmaBusMode, DmaResetOn); unaccuracy_delay(10000); //TODO:wait until bit0 was cleared data = SynopsysReadDmaReg(synop, DmaBusMode); TRACE("DMA Reset (%08x)\n", data); }// SynopsysReset void SynopsysAttach(Synopsys *synop, uint32_t macbase, uint32_t dmabase, uint32_t phyaddr) { synop->macbase = macbase; synop->dmabase = dmabase; synop->phyaddr = phyaddr; TRACE("Base Addresses fixed\n"); }// SynopsysAttach /** * Initialisation of the Synopsys device. * \param synop Synopsys device structure. * \param macbase base address of MAC registers. * \param dmabase base address of DMA registers. * \param phyaddr MII phy device address. */ void SynopsysInit(Synopsys *synop, uint32_t txaddr, uint32_t rxaddr) { SynopsysWriteDmaReg(synop, DmaBusMode, DmaResetOff); SynopsysWriteDmaReg(synop, DmaControl, DmaStoreAndForward); SynopsysWriteDmaReg(synop, DmaInterrupt, 0); //All DMA Interrupts disabled SynopsysWriteDmaReg(synop, DmaTxBaseAddr, txaddr); SynopsysWriteDmaReg(synop, DmaRxBaseAddr, rxaddr); TRACE("Configure DMA Registers...\n"); TRACE(" DmaBusMode=%x\n",SynopsysReadDmaReg(synop, DmaBusMode)); TRACE(" DmaControl=%x\n",SynopsysReadDmaReg(synop, DmaControl)); TRACE(" DmaInterrupt=%x\n",SynopsysReadDmaReg(synop, DmaInterrupt)); TRACE(" DmaTxAddr=%x\n",SynopsysReadDmaReg(synop, DmaTxBaseAddr)); TRACE(" DmaRxAddr=%x\n",SynopsysReadDmaReg(synop, DmaRxBaseAddr)); TRACE("OK\n"); TRACE("Configure GMAC Registers...\n"); SynopsysWriteMacReg(synop, GmacIntMask, 0xFFFFFFFF); SynopsysWriteMacReg(synop, GmacFrameFilter, GmacFilterOff|GmacPassControl2|GmacBroadcastEnable); SynopsysWriteMacReg(synop, GmacConfig, GmacWatchdogDisable|GmacJabberDisable| GmacSelectMii|GmacLoopbackOff|GmacFESpeed10|GmacFullDuplex| GmacTxEnable|GmacRxEnable); TRACE(" GmacIntMask=%x\n",SynopsysReadMacReg(synop, GmacIntMask)); TRACE(" GmacFrameFilter=%x\n",SynopsysReadMacReg(synop, GmacFrameFilter)); TRACE(" GmacConfig=%x\n",SynopsysReadMacReg(synop, GmacConfig)); TRACE("OK\n"); }// SynopsysInit /** * Change the MAC address. * \param synop device structure. * \param addr new mac address. * \return error code. */ int SynopsysSetupEthernetAddress(Synopsys *synop, uint8_t *addr) { uint32_t datah; uint32_t datal; //Setup MAC address datah = (addr[5] << 8) | addr[4]; SynopsysWriteMacReg(synop, GmacAddr0High, datah); datal = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; SynopsysWriteMacReg(synop, GmacAddr0Low, datal); //Only for debug datah = SynopsysReadMacReg(synop, GmacAddr0High); datal = SynopsysReadMacReg(synop, GmacAddr0Low); TRACE("hardware ethernet addr =%02X:%02X:%02X:%02X:%02X:%02X\n",(datal) & 0xFF, (datal>>8) & 0xFF, (datal>>16) & 0xFF, (datal>>24) & 0xFF, (datah) & 0xFF, (datah>>8) & 0xFF); return 0; }// SynopsysSetupEthernetAddress void SynopsysEnableInt(Synopsys *synop) { SynopsysWriteDmaReg(synop, DmaStatus, 0xFFFFFFFF); SynopsysWriteDmaReg(synop, DmaInterrupt, DmaIeNormal|DmaIeAbnormal|DmaIeBusError|DmaIeRxNoBuffer|DmaIeRxOverflow| DmaIeRxCompleted|DmaIeTxUnderflow|DmaIeTxStopped|DmaIeTxCompleted); } void SynopsysDisableInt(Synopsys *synop) { SynopsysWriteDmaReg(synop, DmaInterrupt, 0); } void SynopsysStartTx(Synopsys *synop) { SynopsysSetDmaReg(synop, DmaControl, DmaTxStart); } void SynopsysStopTx(Synopsys *synop) { SynopsysClearDmaReg(synop, DmaControl, DmaTxStart); } void SynopsysRestartTx(Synopsys *synop) { SynopsysWriteDmaReg(synop, DmaTxPollDemand, 0); } void SynopsysStartRx(Synopsys *synop) { SynopsysSetDmaReg(synop, DmaControl, DmaRxStart); } void SynopsysStopRx(Synopsys *synop) { SynopsysClearDmaReg(synop, DmaControl, DmaRxStart); } void SynopsysRestartRx(Synopsys *synop) { SynopsysWriteDmaReg(synop, DmaRxPollDemand, 0); } int SynopsysSetSpeedDuplex(Synopsys *synop, int speed100, int fullduplex) { if(fullduplex) SynopsysSetMacReg(synop, GmacConfig, GmacFullDuplex); else SynopsysClearMacReg(synop, GmacConfig, GmacFullDuplex); return 0; } void SynopsysGetIntStatus(Synopsys *synop, SynopsysIntStatus *status) { uint32_t st; st = SynopsysReadDmaReg(synop, DmaStatus); SynopsysWriteDmaReg(synop, DmaStatus, st); st &= (SynopsysReadDmaReg(synop, DmaInterrupt) | 0xFFFE0000); status->val = st; } void SynopsysSetPromiscuousMode(Synopsys *synop, int value) { uint32_t st; st = SynopsysReadDmaReg(synop, GmacFrameFilter); if(value) st |= GmacPromiscuousModeOn; else st &= ~GmacPromiscuousModeOn; SynopsysWriteMacReg(synop, GmacFrameFilter, st); } void SynopsysSetMulticastFilter(Synopsys *synop, int value) { uint32_t st; st = SynopsysReadDmaReg(synop, GmacFrameFilter); if(value) st |= GmacMulticastFilterOff; else st &= ~GmacMulticastFilterOff; SynopsysWriteMacReg(synop, GmacFrameFilter, st); }