forked from Imagelibrary/rtems
262 lines
6.4 KiB
C
262 lines
6.4 KiB
C
/**
|
|
* @file
|
|
*
|
|
* @ingroup RTEMSBSPsARMCSB336
|
|
*
|
|
* @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.
|
|
*/
|
|
|
|
#include <machine/rtems-bsd-kernel-space.h>
|
|
|
|
#include <sys/types.h>
|
|
#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);
|
|
|
|
}
|
|
|
|
|
|
|