218 lines
5.8 KiB
C
218 lines
5.8 KiB
C
/*
|
|
* drivers/net/titan_mdio.c - Driver for Titan ethernet ports
|
|
*
|
|
* Copyright (C) 2003 PMC-Sierra Inc.
|
|
* Author : Manish Lachwani (lachwani@pmc-sierra.com)
|
|
*
|
|
* 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.
|
|
*
|
|
* Management Data IO (MDIO) driver for the Titan GMII. Interacts with the Marvel PHY
|
|
* on the Titan. No support for the TBI as yet.
|
|
*
|
|
*/
|
|
|
|
#include "titan_mdio.h"
|
|
|
|
#define MDIO_DEBUG
|
|
|
|
/*
|
|
* Local constants
|
|
*/
|
|
#define MAX_CLKA 1023
|
|
#define MAX_PHY_DEV 31
|
|
#define MAX_PHY_REG 31
|
|
#define WRITEADDRS_OPCODE 0x0
|
|
#define READ_OPCODE 0x2
|
|
#define WRITE_OPCODE 0x1
|
|
#define MAX_MDIO_POLL 100
|
|
|
|
/*
|
|
* Titan MDIO and SCMB registers
|
|
*/
|
|
#define TITAN_GE_SCMB_CONTROL 0x01c0 /* SCMB Control */
|
|
#define TITAN_GE_SCMB_CLKA 0x01c4 /* SCMB Clock A */
|
|
#define TITAN_GE_MDIO_COMMAND 0x01d0 /* MDIO Command */
|
|
#define TITAN_GE_MDIO_DEVICE_PORT_ADDRESS 0x01d4 /* MDIO Device and Port addrs */
|
|
#define TITAN_GE_MDIO_DATA 0x01d8 /* MDIO Data */
|
|
#define TITAN_GE_MDIO_INTERRUPTS 0x01dC /* MDIO Interrupts */
|
|
|
|
/*
|
|
* Function to poll the MDIO
|
|
*/
|
|
static int titan_ge_mdio_poll(void)
|
|
{
|
|
int i, val;
|
|
|
|
for (i = 0; i < MAX_MDIO_POLL; i++) {
|
|
val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
|
|
|
|
if (!(val & 0x8000))
|
|
return TITAN_GE_MDIO_GOOD;
|
|
}
|
|
|
|
return TITAN_GE_MDIO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
* Initialize and configure the MDIO
|
|
*/
|
|
int titan_ge_mdio_setup(titan_ge_mdio_config *titan_mdio)
|
|
{
|
|
unsigned long val;
|
|
|
|
/* Reset the SCMB and program into MDIO mode*/
|
|
TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x9000);
|
|
TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x1000);
|
|
|
|
/* CLK A */
|
|
val = TITAN_GE_MDIO_READ(TITAN_GE_SCMB_CLKA);
|
|
val = ( (val & ~(0x03ff)) | (titan_mdio->clka & 0x03ff));
|
|
TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CLKA, val);
|
|
|
|
/* Preamble Suppresion */
|
|
val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
|
|
val = ( (val & ~(0x0001)) | (titan_mdio->mdio_spre & 0x0001));
|
|
TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
|
|
|
|
/* MDIO mode */
|
|
val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
|
|
val = ( (val & ~(0x4000)) | (titan_mdio->mdio_mode & 0x4000));
|
|
TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
|
|
|
|
return TITAN_GE_MDIO_GOOD;
|
|
}
|
|
|
|
/*
|
|
* Set the PHY address in indirect mode
|
|
*/
|
|
int titan_ge_mdio_inaddrs(int dev_addr, int reg_addr)
|
|
{
|
|
volatile unsigned long val;
|
|
|
|
/* Setup the PHY device */
|
|
val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
|
|
val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00));
|
|
val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f));
|
|
TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
|
|
|
|
/* Write the new address */
|
|
val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
|
|
val = ( (val & ~(0x0300)) | ( (WRITEADDRS_OPCODE << 8) & 0x0300));
|
|
TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
|
|
|
|
return TITAN_GE_MDIO_GOOD;
|
|
}
|
|
|
|
/*
|
|
* Read the MDIO register. This is what the individual parametes mean:
|
|
*
|
|
* dev_addr : PHY ID
|
|
* reg_addr : register offset
|
|
*
|
|
* See the spec for the Titan MAC. We operate in the Direct Mode.
|
|
*/
|
|
|
|
#define MAX_RETRIES 2
|
|
|
|
int titan_ge_mdio_read(int dev_addr, int reg_addr, unsigned int *pdata)
|
|
{
|
|
volatile unsigned long val;
|
|
int retries = 0;
|
|
|
|
/* Setup the PHY device */
|
|
|
|
again:
|
|
val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
|
|
val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00));
|
|
val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f));
|
|
val |= 0x4000;
|
|
TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
|
|
|
|
udelay(30);
|
|
|
|
/* Issue the read command */
|
|
val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
|
|
val = ( (val & ~(0x0300)) | ( (READ_OPCODE << 8) & 0x0300));
|
|
TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
|
|
|
|
udelay(30);
|
|
|
|
if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD)
|
|
return TITAN_GE_MDIO_ERROR;
|
|
|
|
*pdata = (unsigned int)TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DATA);
|
|
val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS);
|
|
|
|
udelay(30);
|
|
|
|
if (val & 0x2) {
|
|
if (retries == MAX_RETRIES)
|
|
return TITAN_GE_MDIO_ERROR;
|
|
else {
|
|
retries++;
|
|
goto again;
|
|
}
|
|
}
|
|
|
|
return TITAN_GE_MDIO_GOOD;
|
|
}
|
|
|
|
/*
|
|
* Write to the MDIO register
|
|
*
|
|
* dev_addr : PHY ID
|
|
* reg_addr : register that needs to be written to
|
|
*
|
|
*/
|
|
int titan_ge_mdio_write(int dev_addr, int reg_addr, unsigned int data)
|
|
{
|
|
volatile unsigned long val;
|
|
|
|
if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD)
|
|
return TITAN_GE_MDIO_ERROR;
|
|
|
|
/* Setup the PHY device */
|
|
val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
|
|
val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00));
|
|
val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f));
|
|
val |= 0x4000;
|
|
TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
|
|
|
|
udelay(30);
|
|
|
|
/* Setup the data to write */
|
|
TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DATA, data);
|
|
|
|
udelay(30);
|
|
|
|
/* Issue the write command */
|
|
val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
|
|
val = ( (val & ~(0x0300)) | ( (WRITE_OPCODE << 8) & 0x0300));
|
|
TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
|
|
|
|
udelay(30);
|
|
|
|
if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD)
|
|
return TITAN_GE_MDIO_ERROR;
|
|
|
|
val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS);
|
|
if (val & 0x2)
|
|
return TITAN_GE_MDIO_ERROR;
|
|
|
|
return TITAN_GE_MDIO_GOOD;
|
|
}
|
|
|