blob: 8a8785b8db0c13123922ced6400b92dc305dc371 [file] [log] [blame]
/*
* 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;
}