summaryrefslogtreecommitdiffstats
path: root/bsps/arm/csb336/net/lan91c11x.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/arm/csb336/net/lan91c11x.c')
-rw-r--r--bsps/arm/csb336/net/lan91c11x.c260
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);
+
+}
+
+
+