blob: 296a225bc5cdf811cb1e4758026066da0f2ba3ca [file] [log] [blame]
/*
* Copyright (c) 2013 Qualcomm Atheros, Inc.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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
*/
// ----------------------------------
// S17 Initialization
// author : subha@atheros.com
// adapted: Abishek Goda <Abishek.Goda at atheros dot com>
// ----------------------------------
//#include <prototypes.h>
//#include <gmac_defines.h>
#include <config.h>
#include <common.h>
#include <malloc.h>
#include <net.h>
#include <command.h>
#include <asm/io.h>
#include <asm/addrspace.h>
#include <asm/types.h>
#include <atheros.h>
#include "qca-eth-955x.h"
#include "qca-eth-955x_phy.h"
#include "phy.h"
#include "athrs17_phy.h"
uint32_t athrs17_reg_read(uint32_t reg_addr);
void athrs17_reg_write(uint32_t reg_addr, uint32_t reg_val);
#ifdef ATH_RGMII_CAL
# define ATHR_PHY_MAX 1
#if 0
void s17_phy_write( unsigned int phy_address,
unsigned int reg_address,
unsigned int write_data ) {
unsigned int rddata;
unsigned int address;
address = ((phy_address << 8) & 0x1f00) | (reg_address & 0x1f);
reg_write(GE0_MAC_MII_MGMT_CFG, 0x7);
rddata = reg_read(GE0_MAC_MII_MGMT_PSTAT) & 0x1;
while(rddata){
rddata = reg_read(GE0_MAC_MII_MGMT_PSTAT) & 0x1;
}
reg_write(GE0_MAC_MII_MGMT_CMD, 0x0);
reg_write(GE0_MAC_MII_MGMT_ADDR, address);
reg_write(GE0_MAC_MII_MGMT_CNTR, write_data);
while(rddata){
rddata = reg_read(GE0_MAC_MII_MGMT_PSTAT) & 0x1;
}
}
unsigned int s17_phy_read(unsigned int phy_address, unsigned int reg_address) {
unsigned int rddata;
unsigned int address;
unsigned int phy_rddata;
address = ((phy_address << 8) & 0x1f00) | (reg_address & 0x1f);
reg_write(GE0_MAC_MII_MGMT_CFG, 0x7);
rddata = reg_read(GE0_MAC_MII_MGMT_PSTAT) & 0x1;
while(rddata){
rddata = reg_read(GE0_MAC_MII_MGMT_PSTAT) & 0x1;
}
reg_write(GE0_MAC_MII_MGMT_CMD, 0x0);
reg_write(GE0_MAC_MII_MGMT_ADDR, address);
reg_write(GE0_MAC_MII_MGMT_CMD, 0x1);
rddata = reg_read(GE0_MAC_MII_MGMT_PSTAT) & 0x1;
while(rddata){
rddata = reg_read(GE0_MAC_MII_MGMT_PSTAT) & 0x1;
}
phy_rddata = reg_read(GE0_MAC_MII_MGMT_STAT);
reg_write(GE0_MAC_MII_MGMT_CMD, 0x0);
return(phy_rddata);
}
void s17_reg_write(unsigned int reg_addr, unsigned int reg_val) {
unsigned int reg_word_addr;
unsigned int phy_addr;
unsigned int phy_val;
unsigned int phy_reg;
/* change reg_addr to 16-bit word address, 32-bit aligned */
reg_word_addr = (reg_addr & 0xfffffffc) >> 1;
/* configure register high address */
phy_addr = 0x18;
phy_reg = 0x0;
/* bit16-8 of reg address */
phy_val = (unsigned int) ((reg_word_addr >> 8) & 0x3ff);
s17_phy_write(phy_addr, phy_reg, phy_val);
/* For S17 registers such as ARL and VLAN, since they include BUSY bit */
/* in higher address, we should write the lower 16-bit register then the */
/* higher one */
/* write register in lower address */
phy_addr = 0x10 | ((reg_word_addr >> 5) & 0x7); /* bit7-5 of reg address */
phy_reg = (unsigned int) (reg_word_addr & 0x1f); /* bit4-0 of reg address */
phy_val = (unsigned int) (reg_val & 0xffff);
s17_phy_write( phy_addr, phy_reg, phy_val);
/* read register in higher address */
reg_word_addr++;
phy_addr = 0x10 | ((reg_word_addr >> 5) & 0x7); /* bit7-5 of reg address */
phy_reg = (unsigned int) (reg_word_addr & 0x1f); /* bit4-0 of reg address */
phy_val = (unsigned int) ((reg_val >> 16) & 0xffff);
s17_phy_write( phy_addr, phy_reg, phy_val);
}
unsigned int s17_reg_read(unsigned int reg_addr)
{
unsigned int reg_word_addr;
unsigned int phy_addr, tmp_val, reg_val;
unsigned int phy_val;
unsigned int phy_reg;
/* change reg_addr to 16-bit word address, 32-bit aligned */
reg_word_addr = (reg_addr & 0xfffffffc) >> 1;
/* configure register high address */
phy_addr = 0x18;
phy_reg = 0x0;
/* bit16-8 of reg address */
phy_val = (unsigned int) ((reg_word_addr >> 8) & 0x3ff);
s17_phy_write( phy_addr, phy_reg, phy_val);
/* For some registers such as MIBs, since it is read/clear, we should */
/* read the lower 16-bit register then the higher one */
/* read register in lower address */
phy_addr = 0x10 | ((reg_word_addr >> 5) & 0x7); /* bit7-5 of reg address */
phy_reg = (unsigned int) (reg_word_addr & 0x1f); /* bit4-0 of reg address */
reg_val = (unsigned int) s17_phy_read( phy_addr, phy_reg);
/* read register in higher address */
reg_word_addr++;
phy_addr = 0x10 | ((reg_word_addr >> 5) & 0x7); /* bit7-5 of reg address */
phy_reg = (unsigned int) (reg_word_addr & 0x1f); /* bit4-0 of reg address */
tmp_val = (unsigned int) s17_phy_read( phy_addr, phy_reg);
reg_val |= (tmp_val << 16);
return reg_val;
}
#endif
void s17_reg_rmw(unsigned int reg_addr, unsigned int reg_val)
{
reg_val |= athrs17_reg_read(reg_addr);
athrs17_reg_write(reg_addr,reg_val);
}
void init_s17(void)
{
int phyUnit = 0;
int phyBase = 0;
int phyAddr = 0;
unsigned int rddata;
athrs17_reg_write(0x624 , 0x003f3f3f);
athrs17_reg_write(0x10 , 0x40000000);
athrs17_reg_write(0x4 , 0x07500000);
athrs17_reg_write(0xc , 0x01000000);
athrs17_reg_write(0x7c , 0x000000fe); // 1gbps
//athrs17_reg_write(0x7c , 0x0000007d); // 100 mbps
//athrs17_reg_write(0x7c , 0x0000007c); // 10 mbps
for (phyUnit= 0; phyUnit <= ATHR_PHY_MAX; phyUnit++)
{
phyBase = 0;
phyAddr = phyUnit;
// To enable loopback on a phy
// rddata = s17_phy_read(phyAddr, 0x0);
// s17_phy_write(phyAddr, 0x0, (rddata | (1 << 14)));
/* For 100M waveform */
phy_reg_write(0, phyAddr, 0x1d, 0x18);
phy_reg_write(0, phyAddr, 0x1e, 0x02ea);
/* Turn On Gigabit Clock */
phy_reg_write(0, phyAddr, 0x1d, 0x3d);
phy_reg_write(0, phyAddr, 0x1e, 0x48a0);
}
/* Enable flow control */
s17_reg_rmw(0x80,0x30);
s17_reg_rmw(0x84,0x30);
s17_reg_rmw(0x88,0x30);
s17_reg_rmw(0x8c,0x30);
s17_reg_rmw(0x90,0x30);
}
void vlan_config(void)
{
athrs17_reg_write(S17_P0LOOKUP_CTRL_REG, 0x0014001e);
athrs17_reg_write(S17_P0VLAN_CTRL0_REG, 0x10001);
athrs17_reg_write(S17_P1LOOKUP_CTRL_REG, 0x0014001d);
athrs17_reg_write(S17_P1VLAN_CTRL0_REG, 0x10001);
athrs17_reg_write(S17_P2LOOKUP_CTRL_REG, 0x0014001b);
athrs17_reg_write(S17_P2VLAN_CTRL0_REG, 0x10001);
athrs17_reg_write(S17_P3LOOKUP_CTRL_REG, 0x00140017);
athrs17_reg_write(S17_P3VLAN_CTRL0_REG, 0x10001);
athrs17_reg_write(S17_P4LOOKUP_CTRL_REG, 0x0014000f);
athrs17_reg_write(S17_P4VLAN_CTRL0_REG, 0x10001);
athrs17_reg_write(S17_P5LOOKUP_CTRL_REG, 0x00140040);
athrs17_reg_write(S17_P5VLAN_CTRL0_REG, 0x20001);
athrs17_reg_write(S17_P6LOOKUP_CTRL_REG, 0x00140020);
athrs17_reg_write(S17_P6VLAN_CTRL0_REG, 0x20001);
}
void init_s17_lpbk(void)
{
int phyUnit = 0;
int phyBase = 0;
int phyAddr = 0;
unsigned int rddata;
#ifdef ATH_S17_MAC0_SGMII
athrs17_reg_write(0x4 , 0x080080);
athrs17_reg_write(0xc , 0x07600000);
athrs17_reg_write(0x94 , 0x000000fe); // 1gbps
athrs17_reg_write(0x624 , 0x007f7f7f);
printf ("Vlan config...\n");
vlan_config();
#else
athrs17_reg_write(0x624 , 0x003f3f3f);
athrs17_reg_write(0x4 , 0x07500000);
athrs17_reg_write(0xc , 0x01000000);
#endif
athrs17_reg_write(0x10 , 0x4000000);
athrs17_reg_write(0x7c , 0x000000fe); // 1gbps
//athrs17_reg_write(0x7c , 0x0000007d); // 100 mbps
//athrs17_reg_write(0x7c , 0x0000007c); // 10 mbps
phyBase = 0;
#ifdef ATH_S17_MAC0_SGMII
phyAddr = 4;
#else
phyAddr = 0;
#endif
// To enable loopback on single phy
phy_reg_write(0, phyAddr, 0x0, 0xc140);
for(rddata=0; rddata<1000; rddata++);
phy_reg_write(0, phyAddr, 0x0, 0x4140);
for(rddata=0; rddata<1000; rddata++);
rddata = phy_reg_read(0, phyAddr, 0x0);
#ifdef DEBUG
printf("s17 phy0 register value 0x%08x\n", rddata);
#endif
// power down other phys
#ifdef ATH_S17_MAC0_SGMII
phy_reg_write(0, 0x0, 0x0, 0x8800);
#else
phy_reg_write(0, 0x4, 0x0, 0x8800);
#endif
phy_reg_write(0, 0x1, 0x0, 0x8800);
phy_reg_write(0, 0x2, 0x0, 0x8800);
phy_reg_write(0, 0x3, 0x0, 0x8800);
/* For 100M waveform */
phy_reg_write(0, phyAddr, 0x1d, 0x18);
phy_reg_write(0, phyAddr, 0x1e, 0x02ea);
/* Turn On Gigabit Clock */
phy_reg_write(0, phyAddr, 0x1d, 0x3d);
phy_reg_write(0, phyAddr, 0x1e, 0x48a0);
/* Enable flow control */
s17_reg_rmw(0x80,0x30);
s17_reg_rmw(0x84,0x30);
s17_reg_rmw(0x88,0x30);
s17_reg_rmw(0x8c,0x30);
s17_reg_rmw(0x90,0x30);
}
#endif /* #ifdef RGMII_CAL */