2009-05-09 01:46:40 +04:00
/*
* Marvell 88 SE64xx / 88 SE94xx register IO interface
*
* Copyright 2007 Red Hat , Inc .
* Copyright 2008 Marvell . < kewei @ marvell . com >
*
* This file is licensed under GPLv2 .
*
* 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 ; version 2 of the
* License .
*
* 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
*/
2009-05-09 01:44:01 +04:00
# ifndef _MV_CHIPS_H_
# define _MV_CHIPS_H_
2009-05-09 01:46:40 +04:00
# define mr32(reg) readl(regs + reg)
# define mw32(reg, val) writel((val), regs + reg)
# define mw32_f(reg, val) do { \
mw32 ( reg , val ) ; \
mr32 ( reg ) ; \
} while ( 0 )
2009-05-09 01:44:01 +04:00
2009-05-09 01:46:40 +04:00
# define iow32(reg, val) outl(val, (unsigned long)(regs + reg))
# define ior32(reg) inl((unsigned long)(regs + reg))
# define iow16(reg, val) outw((unsigned long)(val, regs + reg))
# define ior16(reg) inw((unsigned long)(regs + reg))
# define iow8(reg, val) outb((unsigned long)(val, regs + reg))
# define ior8(reg) inb((unsigned long)(regs + reg))
static inline u32 mvs_cr32 ( struct mvs_info * mvi , u32 addr )
2009-05-09 01:44:01 +04:00
{
2009-05-09 01:46:40 +04:00
void __iomem * regs = mvi - > regs ;
mw32 ( MVS_CMD_ADDR , addr ) ;
return mr32 ( MVS_CMD_DATA ) ;
2009-05-09 01:44:01 +04:00
}
2009-05-09 01:46:40 +04:00
static inline void mvs_cw32 ( struct mvs_info * mvi , u32 addr , u32 val )
2009-05-09 01:44:01 +04:00
{
2009-05-09 01:46:40 +04:00
void __iomem * regs = mvi - > regs ;
mw32 ( MVS_CMD_ADDR , addr ) ;
mw32 ( MVS_CMD_DATA , val ) ;
2009-05-09 01:44:01 +04:00
}
static inline u32 mvs_read_phy_ctl ( struct mvs_info * mvi , u32 port )
{
void __iomem * regs = mvi - > regs ;
2009-05-09 01:46:40 +04:00
return ( port < 4 ) ? mr32 ( MVS_P0_SER_CTLSTAT + port * 4 ) :
mr32 ( MVS_P4_SER_CTLSTAT + ( port - 4 ) * 4 ) ;
2009-05-09 01:44:01 +04:00
}
static inline void mvs_write_phy_ctl ( struct mvs_info * mvi , u32 port , u32 val )
{
void __iomem * regs = mvi - > regs ;
if ( port < 4 )
2009-05-09 01:46:40 +04:00
mw32 ( MVS_P0_SER_CTLSTAT + port * 4 , val ) ;
2009-05-09 01:44:01 +04:00
else
2009-05-09 01:46:40 +04:00
mw32 ( MVS_P4_SER_CTLSTAT + ( port - 4 ) * 4 , val ) ;
2009-05-09 01:44:01 +04:00
}
2009-05-09 01:46:40 +04:00
static inline u32 mvs_read_port ( struct mvs_info * mvi , u32 off ,
u32 off2 , u32 port )
2009-05-09 01:44:01 +04:00
{
void __iomem * regs = mvi - > regs + off ;
void __iomem * regs2 = mvi - > regs + off2 ;
2009-05-09 01:46:40 +04:00
return ( port < 4 ) ? readl ( regs + port * 8 ) :
2009-05-09 01:44:01 +04:00
readl ( regs2 + ( port - 4 ) * 8 ) ;
}
static inline void mvs_write_port ( struct mvs_info * mvi , u32 off , u32 off2 ,
u32 port , u32 val )
{
void __iomem * regs = mvi - > regs + off ;
void __iomem * regs2 = mvi - > regs + off2 ;
if ( port < 4 )
writel ( val , regs + port * 8 ) ;
else
writel ( val , regs2 + ( port - 4 ) * 8 ) ;
}
static inline u32 mvs_read_port_cfg_data ( struct mvs_info * mvi , u32 port )
{
return mvs_read_port ( mvi , MVS_P0_CFG_DATA ,
MVS_P4_CFG_DATA , port ) ;
}
2009-05-09 01:46:40 +04:00
static inline void mvs_write_port_cfg_data ( struct mvs_info * mvi ,
u32 port , u32 val )
2009-05-09 01:44:01 +04:00
{
mvs_write_port ( mvi , MVS_P0_CFG_DATA ,
MVS_P4_CFG_DATA , port , val ) ;
}
2009-05-09 01:46:40 +04:00
static inline void mvs_write_port_cfg_addr ( struct mvs_info * mvi ,
u32 port , u32 addr )
2009-05-09 01:44:01 +04:00
{
mvs_write_port ( mvi , MVS_P0_CFG_ADDR ,
MVS_P4_CFG_ADDR , port , addr ) ;
2009-05-09 01:46:40 +04:00
mdelay ( 10 ) ;
2009-05-09 01:44:01 +04:00
}
static inline u32 mvs_read_port_vsr_data ( struct mvs_info * mvi , u32 port )
{
return mvs_read_port ( mvi , MVS_P0_VSR_DATA ,
MVS_P4_VSR_DATA , port ) ;
}
2009-05-09 01:46:40 +04:00
static inline void mvs_write_port_vsr_data ( struct mvs_info * mvi ,
u32 port , u32 val )
2009-05-09 01:44:01 +04:00
{
mvs_write_port ( mvi , MVS_P0_VSR_DATA ,
MVS_P4_VSR_DATA , port , val ) ;
}
2009-05-09 01:46:40 +04:00
static inline void mvs_write_port_vsr_addr ( struct mvs_info * mvi ,
u32 port , u32 addr )
2009-05-09 01:44:01 +04:00
{
mvs_write_port ( mvi , MVS_P0_VSR_ADDR ,
MVS_P4_VSR_ADDR , port , addr ) ;
2009-05-09 01:46:40 +04:00
mdelay ( 10 ) ;
2009-05-09 01:44:01 +04:00
}
static inline u32 mvs_read_port_irq_stat ( struct mvs_info * mvi , u32 port )
{
return mvs_read_port ( mvi , MVS_P0_INT_STAT ,
MVS_P4_INT_STAT , port ) ;
}
2009-05-09 01:46:40 +04:00
static inline void mvs_write_port_irq_stat ( struct mvs_info * mvi ,
u32 port , u32 val )
2009-05-09 01:44:01 +04:00
{
mvs_write_port ( mvi , MVS_P0_INT_STAT ,
MVS_P4_INT_STAT , port , val ) ;
}
static inline u32 mvs_read_port_irq_mask ( struct mvs_info * mvi , u32 port )
{
return mvs_read_port ( mvi , MVS_P0_INT_MASK ,
MVS_P4_INT_MASK , port ) ;
2009-05-09 01:46:40 +04:00
2009-05-09 01:44:01 +04:00
}
2009-05-09 01:46:40 +04:00
static inline void mvs_write_port_irq_mask ( struct mvs_info * mvi ,
u32 port , u32 val )
2009-05-09 01:44:01 +04:00
{
mvs_write_port ( mvi , MVS_P0_INT_MASK ,
MVS_P4_INT_MASK , port , val ) ;
}
2009-05-09 01:46:40 +04:00
static inline void __devinit mvs_phy_hacks ( struct mvs_info * mvi )
{
u32 tmp ;
/* workaround for SATA R-ERR, to ignore phy glitch */
tmp = mvs_cr32 ( mvi , CMD_PHY_TIMER ) ;
tmp & = ~ ( 1 < < 9 ) ;
tmp | = ( 1 < < 10 ) ;
mvs_cw32 ( mvi , CMD_PHY_TIMER , tmp ) ;
/* enable retry 127 times */
mvs_cw32 ( mvi , CMD_SAS_CTL1 , 0x7f7f ) ;
/* extend open frame timeout to max */
tmp = mvs_cr32 ( mvi , CMD_SAS_CTL0 ) ;
tmp & = ~ 0xffff ;
tmp | = 0x3fff ;
mvs_cw32 ( mvi , CMD_SAS_CTL0 , tmp ) ;
/* workaround for WDTIMEOUT , set to 550 ms */
mvs_cw32 ( mvi , CMD_WD_TIMER , 0x7a0000 ) ;
/* not to halt for different port op during wideport link change */
mvs_cw32 ( mvi , CMD_APP_ERR_CONFIG , 0xffefbf7d ) ;
/* workaround for Seagate disk not-found OOB sequence, recv
* COMINIT before sending out COMWAKE */
tmp = mvs_cr32 ( mvi , CMD_PHY_MODE_21 ) ;
tmp & = 0x0000ffff ;
tmp | = 0x00fa0000 ;
mvs_cw32 ( mvi , CMD_PHY_MODE_21 , tmp ) ;
tmp = mvs_cr32 ( mvi , CMD_PHY_TIMER ) ;
tmp & = 0x1fffffff ;
tmp | = ( 2U < < 29 ) ; /* 8 ms retry */
mvs_cw32 ( mvi , CMD_PHY_TIMER , tmp ) ;
}
static inline void mvs_int_sata ( struct mvs_info * mvi )
{
u32 tmp ;
void __iomem * regs = mvi - > regs ;
tmp = mr32 ( MVS_INT_STAT_SRS_0 ) ;
if ( tmp )
mw32 ( MVS_INT_STAT_SRS_0 , tmp ) ;
MVS_CHIP_DISP - > clear_active_cmds ( mvi ) ;
}
static inline void mvs_int_full ( struct mvs_info * mvi )
{
void __iomem * regs = mvi - > regs ;
u32 tmp , stat ;
int i ;
stat = mr32 ( MVS_INT_STAT ) ;
mvs_int_rx ( mvi , false ) ;
for ( i = 0 ; i < mvi - > chip - > n_phy ; i + + ) {
tmp = ( stat > > i ) & ( CINT_PORT | CINT_PORT_STOPPED ) ;
if ( tmp )
mvs_int_port ( mvi , i , tmp ) ;
}
if ( stat & CINT_SRS )
mvs_int_sata ( mvi ) ;
mw32 ( MVS_INT_STAT , stat ) ;
}
static inline void mvs_start_delivery ( struct mvs_info * mvi , u32 tx )
{
void __iomem * regs = mvi - > regs ;
mw32 ( MVS_TX_PROD_IDX , tx ) ;
}
static inline u32 mvs_rx_update ( struct mvs_info * mvi )
{
void __iomem * regs = mvi - > regs ;
return mr32 ( MVS_RX_CONS_IDX ) ;
}
static inline u32 mvs_get_prd_size ( void )
{
return sizeof ( struct mvs_prd ) ;
}
static inline u32 mvs_get_prd_count ( void )
{
return MAX_SG_ENTRY ;
}
static inline void mvs_show_pcie_usage ( struct mvs_info * mvi )
{
u16 link_stat , link_spd ;
const char * spd [ ] = {
" UnKnown " ,
" 2.5 " ,
" 5.0 " ,
} ;
if ( mvi - > flags & MVF_FLAG_SOC | | mvi - > id > 0 )
return ;
pci_read_config_word ( mvi - > pdev , PCR_LINK_STAT , & link_stat ) ;
link_spd = ( link_stat & PLS_LINK_SPD ) > > PLS_LINK_SPD_OFFS ;
if ( link_spd > = 3 )
link_spd = 0 ;
dev_printk ( KERN_INFO , mvi - > dev ,
" mvsas: PCI-E x%u, Bandwidth Usage: %s Gbps \n " ,
( link_stat & PLS_NEG_LINK_WD ) > > PLS_NEG_LINK_WD_OFFS ,
spd [ link_spd ] ) ;
}
static inline u32 mvs_hw_max_link_rate ( void )
{
return MAX_LINK_RATE ;
}
# endif /* _MV_CHIPS_H_ */