URL
https://opencores.org/ocsvn/xenie/xenie/trunk
Subversion Repositories xenie
[/] [xenie/] [trunk/] [examples/] [Eth_example/] [mb_fw/] [xenie_eth_test_womtd/] [src/] [mdio.c] - Rev 4
Compare with Previous | Blame | View Log
/****************************************************************************** ** ** ** (C) Copyright 2017 DFC Design, s.r.o., Brno, Czech Republic ** Author: Marek Kvas (m.kvas@dspfpga.com) ** **************************************************************************** ** ** This file is part of Xenia Ethernet Example project. ** ** Xenia Ethernet Example project is free software: you can ** redistribute it and/or modify it under the terms of ** the GNU Lesser General Public License as published by the Free ** Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** Xenia Ethernet Example project 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 Lesser General Public License ** for more details. ** ** You should have received a copy of the GNU Lesser General Public ** License along with Xenia Ethernet Example project. If not, ** see <http://www.gnu.org/licenses/>. **************************************************************************** */ #include <stdint.h> #include "mdio.h" #define DEF_TIMEOUT 1000000 #define MDIO_START_DIRECT 1 #define MDIO_START_INDIRECT 0 #define MDIO_DIRECT_WRITE 1 #define MDIO_DIRECT_READ 2 #define MDIO_INDIRECT_ADDRESS 0 #define MDIO_INDIRECT_WRITE 1 #define MDIO_INDIRECT_READ 3 #define DPRINTF(...) static int mdio_wait_busy(volatile struct mdio_struct *dev, int timeout) { int i = 0; while(dev->ctrl & MDIO_BUSY) { if(i >= timeout) return -1; i++; } return 0; } static int mdio_wait_cmd_queue(volatile struct mdio_struct *dev, int timeout) { #ifndef USE_CMD_FIFO mdio_wait_busy(dev, timeout); #else int i = 0; while(dev->ctrl & MDIO_CMD_FIFO_FULL) { if(i >= timeout) return -1; i++; } return 0; #endif } int mdio_set_options(volatile struct mdio_struct *dev, unsigned int div, int preamble_suppression) { if (mdio_wait_busy(dev, DEF_TIMEOUT) < 0) return -1; dev->divr = (div & 0xff) | ((preamble_suppression)? MDIO_PREAMBLE_SUPPRESSION:0); return 0; } /* * Send data to mdio bus it waits until data can be written to the MDIO core. * If blocking is set, it waits for completion either. */ int mdio_send(volatile struct mdio_struct *dev, unsigned int start_seq, unsigned int operation, unsigned int phy_addr, unsigned int reg_addr, unsigned int data, int blocking) { #ifdef USE_ONE_WRITE_COMMANDING unsigned int tmp; #endif if (mdio_wait_cmd_queue(dev, DEF_TIMEOUT) < 0) return -1; #ifndef USE_ONE_WRITE_COMMANDING dev->dout = data & 0xffff; dev->opst = ((start_seq & 0x3) << MDIO_START_SEQ_SHIFT) | ((operation & 0x3) << MDIO_OPEARTION_SHIFT); dev->addr = ((reg_addr & 0x1f) << MDIO_PHYREG_SHIFT) | ((phy_addr & 0x1f) << MDIO_PHYADDR_SHIFT); /* start process */ dev->ctrl = MDIO_RUN; #else tmp = MDIO_OC_RUN | ((start_seq << MDIO_OC_START_SEQ_SHIFT) & MDIO_OC_START_SEQ_MASK) | ((operation << MDIO_OC_OPERATION_SHIFT) & MDIO_OC_OPERATION_MASK) | ((phy_addr << MDIO_OC_PHYADDR_SHIFT) & MDIO_OC_PHYADDR_MASK) | ((reg_addr << MDIO_OC_PHYREG_SHIFT) & MDIO_OC_PHYREG_MASK) | ((data << MDIO_OC_DATA_SHIFT) & MDIO_OC_DATA_MASK); dev->occmd = tmp; #endif /* wait for completion if required */ if (blocking) { if (mdio_wait_busy(dev, DEF_TIMEOUT) < 0) return -1; } return 0; } /* * Tries to read from MDIO device it always waits for completion. */ int mdio_read(volatile struct mdio_struct *dev, unsigned int start_seq, unsigned int operation, unsigned int phy_addr, unsigned int reg_addr, unsigned int *data) { #ifdef USE_ONE_WRITE_COMMANDING unsigned int tmp; #endif if (mdio_wait_cmd_queue(dev, DEF_TIMEOUT) < 0) return -1; #ifndef USE_ONE_WRITE_COMMANDING dev->opst = ((start_seq & 0x3) << MDIO_START_SEQ_SHIFT) | ((operation & 0x3) << MDIO_OPEARTION_SHIFT); dev->addr = ((reg_addr & 0x1f) << MDIO_PHYREG_SHIFT) | ((phy_addr & 0x1f) << MDIO_PHYADDR_SHIFT); /* start process */ dev->ctrl = MDIO_RUN; #else tmp = MDIO_OC_RUN | ((start_seq << MDIO_OC_START_SEQ_SHIFT) & MDIO_OC_START_SEQ_MASK) | ((operation << MDIO_OC_OPERATION_SHIFT) & MDIO_OC_OPERATION_MASK) | ((phy_addr << MDIO_OC_PHYADDR_SHIFT) & MDIO_OC_PHYADDR_MASK) | ((reg_addr << MDIO_OC_PHYREG_SHIFT) & MDIO_OC_PHYREG_MASK); dev->occmd = tmp; #endif /* wait for completion */ if (mdio_wait_busy(dev, DEF_TIMEOUT) < 0) return -1; *data = dev->din; return 0; } int mdio_write_indirect(volatile struct mdio_struct *dev, uint16_t phyaddr, uint16_t devaddr, uint16_t regaddr, uint16_t data) { /* Set address */ if (mdio_send(dev, MDIO_START_INDIRECT, MDIO_INDIRECT_ADDRESS, phyaddr, devaddr, regaddr, 0) < 0) { return -1; } /* Write data */ if (mdio_send(dev, MDIO_START_INDIRECT, MDIO_INDIRECT_WRITE, phyaddr, devaddr, data, 1) < 0) { return -1; } return 0; } int mdio_write_indirect_nonblocking(volatile struct mdio_struct *dev, uint16_t phyaddr, uint16_t devaddr, uint16_t regaddr, uint16_t data) { /* Set address */ if (mdio_send(dev, MDIO_START_INDIRECT, MDIO_INDIRECT_ADDRESS, phyaddr, devaddr, regaddr, 0) < 0) { return -1; } /* Write data */ if (mdio_send(dev, MDIO_START_INDIRECT, MDIO_INDIRECT_WRITE, phyaddr, devaddr, data, 0) < 0) { return -1; } return 0; } int mdio_write_indirect_burst(volatile struct mdio_struct *dev, uint16_t phyaddr, uint16_t devaddr, uint16_t regaddr, uint8_t *data, int size) { unsigned char lowByte, highByte; int buffCount; /* Size must be even */ if (size % 2) return -1; /* Set address */ if (mdio_send(dev, MDIO_START_INDIRECT, MDIO_INDIRECT_ADDRESS, phyaddr, devaddr, regaddr, 0) < 0) { return -1; } /* Write all data */ buffCount = 0; while (buffCount < size) { lowByte = data[buffCount++]; highByte = data[buffCount++]; if (mdio_send(dev, MDIO_START_INDIRECT, MDIO_INDIRECT_WRITE, phyaddr, devaddr, (((unsigned short)highByte)<<8)|lowByte, ((buffCount == size)?1:0)) < 0) { return -1; } } return 0; } int mdio_read_indirect(volatile struct mdio_struct *dev, uint16_t phyaddr, uint16_t devaddr, uint16_t regaddr, uint16_t *data) { unsigned int tmp; /* Set address */ if (mdio_send(dev, MDIO_START_INDIRECT, MDIO_INDIRECT_ADDRESS, phyaddr, devaddr, regaddr, 0) < 0) { DPRINTF("\r\n Timed out\r\n"); return -1; } /* Read data */ if (mdio_read(dev, MDIO_START_INDIRECT, MDIO_INDIRECT_READ, phyaddr, devaddr, &tmp) < 0) { DPRINTF("\r\n Timed out\r\n"); return -1; } *data = tmp & 0xffff; return 0; }