diff options
Diffstat (limited to 'bsps/arm/csb336/net/lan91c11x.c')
-rw-r--r-- | bsps/arm/csb336/net/lan91c11x.c | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/bsps/arm/csb336/net/lan91c11x.c b/bsps/arm/csb336/net/lan91c11x.c new file mode 100644 index 0000000000..37594776d1 --- /dev/null +++ b/bsps/arm/csb336/net/lan91c11x.c @@ -0,0 +1,260 @@ +/** + * @file + * + * @ingroup arm_csb336 + * + * @brief Helper functions for SMSC LAN91C11x + */ + +/* + * Helper functions for SMSC LAN91C11x + * + * Copyright (c) 2004 by Cogent Computer Systems + * Written by Jay Monkman <jtm@lopingdog.com> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#define __INSIDE_RTEMS_BSD_TCPIP_STACK__ + +#include <rtems.h> +#include "lan91c11x.h" + +uint16_t lan91c11x_read_reg(int reg) +{ + volatile uint16_t *ptr = (uint16_t *)LAN91C11X_BASE_ADDR; + uint16_t old_bank; + uint16_t val; + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + + /* save the bank register */ + old_bank = ptr[7] & 0x7; + + /* set the bank register */ + ptr[7] = (reg >> 4) & 0x7; + + val = ptr[((reg & 0xf) >> 1)]; + + /* restore the bank register */ + ptr[7] = old_bank; + + rtems_interrupt_enable(level); + return val; +} + +void lan91c11x_write_reg(int reg, uint16_t value) +{ + volatile uint16_t *ptr = (uint16_t *)LAN91C11X_BASE_ADDR; + uint16_t old_bank; + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + + /* save the bank register */ + old_bank = ptr[7] & 0x7; + + /* set the bank register */ + ptr[7] = (reg >> 4) & 0x7; + + ptr[((reg & 0xf) >> 1)] = value; + + /* restore the bank register */ + ptr[7] = old_bank; + + rtems_interrupt_enable(level); +} + +uint16_t lan91c11x_read_reg_fast(int reg) +{ + volatile uint16_t *ptr = (uint16_t *)LAN91C11X_BASE_ADDR; + uint16_t val; + + val = ptr[((reg & 0xf) >> 1)]; + + return val; +} + +void lan91c11x_write_reg_fast(int reg, uint16_t value) +{ + volatile uint16_t *ptr = (uint16_t *)LAN91C11X_BASE_ADDR; + + ptr[((reg & 0xf) >> 1)] = value; +} + + +uint16_t lan91c11x_read_phy_reg(int reg) +{ + int i; + uint16_t mask; + uint16_t bits[64]; + int clk_idx = 0; + int input_idx = 0; + uint16_t phydata; + + /* 32 consecutive ones on MDO to establish sync */ + for (i = 0; i < 32; ++i) { + bits[clk_idx++] = LAN91C11X_MGMT_MDOE | LAN91C11X_MGMT_MDO; + } + + /* Start code <01> */ + bits[clk_idx++] = LAN91C11X_MGMT_MDOE; + bits[clk_idx++] = LAN91C11X_MGMT_MDOE | LAN91C11X_MGMT_MDO; + + /* Read command <10> */ + bits[clk_idx++] = LAN91C11X_MGMT_MDOE | LAN91C11X_MGMT_MDO; + bits[clk_idx++] = LAN91C11X_MGMT_MDOE; + + /* Output the PHY address, msb first - Internal PHY is address 0 */ + for (i = 0; i < 5; ++i) { + bits[clk_idx++] = LAN91C11X_MGMT_MDOE; + } + + /* Output the phy register number, msb first */ + mask = 0x10; + for (i = 0; i < 5; ++i) { + if (reg & mask) { + bits[clk_idx++] = LAN91C11X_MGMT_MDOE | LAN91C11X_MGMT_MDO; + } else { + bits[clk_idx++] = LAN91C11X_MGMT_MDOE; + } + + + /* Shift to next lowest bit */ + mask >>= 1; + } + + /* 1 bit time for turnaround */ + 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; + + /* Turn off all MII Interface bits */ + lan91c11x_write_reg(LAN91C11X_MGMT, + lan91c11x_read_reg(LAN91C11X_MGMT) & 0xfff0); + + /* Clock all 64 cycles */ + for (i = 0; i < sizeof bits; ++i) { + /* Clock Low - output data */ + lan91c11x_write_reg(LAN91C11X_MGMT, bits[i]); + rtems_task_wake_after(1); + + /* Clock Hi - input data */ + lan91c11x_write_reg(LAN91C11X_MGMT, bits[i] | LAN91C11X_MGMT_MCLK); + rtems_task_wake_after(1); + bits[i] |= lan91c11x_read_reg(LAN91C11X_MGMT) & LAN91C11X_MGMT_MDI; + } + + /* Return to idle state */ + /* Set clock to low, data to low, and output tristated */ + lan91c11x_write_reg(LAN91C11X_MGMT, lan91c11x_read_reg(LAN91C11X_MGMT) & 0xfff0); + rtems_task_wake_after(1); + + /* Recover input data */ + phydata = 0; + for (i = 0; i < 16; ++i) { + phydata <<= 1; + + if (bits[input_idx++] & LAN91C11X_MGMT_MDI) { + phydata |= 0x0001; + } + } + + return phydata; +} + + + +void lan91c11x_write_phy_reg(int reg, uint16_t phydata) +{ + int i; + ushort mask; + ushort bits[64]; + int clk_idx = 0; + + /* 32 consecutive ones on MDO to establish sync */ + for (i = 0; i < 32; ++i) { + bits[clk_idx++] = LAN91C11X_MGMT_MDOE | LAN91C11X_MGMT_MDO; + } + + /* Start code <01> */ + bits[clk_idx++] = LAN91C11X_MGMT_MDOE; + bits[clk_idx++] = LAN91C11X_MGMT_MDOE | LAN91C11X_MGMT_MDO; + + /* Write command <01> */ + bits[clk_idx++] = LAN91C11X_MGMT_MDOE; + bits[clk_idx++] = LAN91C11X_MGMT_MDOE | LAN91C11X_MGMT_MDO; + + /* Output the PHY address, msb first - Internal PHY is address 0 */ + for (i = 0; i < 5; ++i) { + bits[clk_idx++] = LAN91C11X_MGMT_MDOE; + } + + /* Output the phy register number, msb first */ + mask = 0x10; + for (i = 0; i < 5; ++i) { + if (reg & mask) { + bits[clk_idx++] = LAN91C11X_MGMT_MDOE | LAN91C11X_MGMT_MDO; + } else { + bits[clk_idx++] = LAN91C11X_MGMT_MDOE; + } + + /* Shift to next lowest bit */ + mask >>= 1; + } + + /* 2 extra bit times for turnaround */ + 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++] = LAN91C11X_MGMT_MDOE | LAN91C11X_MGMT_MDO; + } else { + bits[clk_idx++] = LAN91C11X_MGMT_MDOE; + } + + /* Shift to next lowest bit */ + mask >>= 1; + } + + /* Turn off all MII Interface bits */ + lan91c11x_write_reg(LAN91C11X_MGMT, + lan91c11x_read_reg(LAN91C11X_MGMT) & 0xfff0); + + /* Clock all 64 cycles */ + for (i = 0; i < sizeof bits; ++i) { + /* Clock Low - output data */ + lan91c11x_write_reg(LAN91C11X_MGMT, bits[i]); + rtems_task_wake_after(1); + + /* Clock Hi - input data */ + lan91c11x_write_reg(LAN91C11X_MGMT, bits[i] | LAN91C11X_MGMT_MCLK); + rtems_task_wake_after(1); + bits[i] |= lan91c11x_read_reg(LAN91C11X_MGMT) & LAN91C11X_MGMT_MDI; + } + + /* Return to idle state */ + /* Set clock to low, data to low, and output tristated */ + lan91c11x_write_reg(LAN91C11X_MGMT, + lan91c11x_read_reg(LAN91C11X_MGMT) & 0xfff0); + rtems_task_wake_after(1); + +} + + + |