2019-05-28 10:10:04 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2015-11-03 18:20:57 +00:00
/*
* VFIO platform driver specialized for AMD xgbe reset
* reset code is inherited from AMD xgbe native driver
*
* Copyright ( c ) 2015 Linaro Ltd .
* www . linaro . org
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/io.h>
# include <uapi/linux/mdio.h>
# include <linux/delay.h>
2019-01-30 11:52:31 +09:00
# include "../vfio_platform_private.h"
2015-11-03 18:20:57 +00:00
# define DMA_MR 0x3000
# define MAC_VR 0x0110
# define DMA_ISR 0x3008
# define MAC_ISR 0x00b0
# define PCS_MMD_SELECT 0xff
# define MDIO_AN_INT 0x8002
# define MDIO_AN_INTMASK 0x8001
2019-12-18 13:35:25 +00:00
static unsigned int xmdio_read ( void __iomem * ioaddr , unsigned int mmd ,
2015-11-03 18:20:57 +00:00
unsigned int reg )
{
unsigned int mmd_address , value ;
mmd_address = ( mmd < < 16 ) | ( ( reg ) & 0xffff ) ;
iowrite32 ( mmd_address > > 8 , ioaddr + ( PCS_MMD_SELECT < < 2 ) ) ;
value = ioread32 ( ioaddr + ( ( mmd_address & 0xff ) < < 2 ) ) ;
return value ;
}
2019-12-18 13:35:25 +00:00
static void xmdio_write ( void __iomem * ioaddr , unsigned int mmd ,
2015-11-03 18:20:57 +00:00
unsigned int reg , unsigned int value )
{
unsigned int mmd_address ;
mmd_address = ( mmd < < 16 ) | ( ( reg ) & 0xffff ) ;
iowrite32 ( mmd_address > > 8 , ioaddr + ( PCS_MMD_SELECT < < 2 ) ) ;
iowrite32 ( value , ioaddr + ( ( mmd_address & 0xff ) < < 2 ) ) ;
}
2016-09-01 19:15:35 +08:00
static int vfio_platform_amdxgbe_reset ( struct vfio_platform_device * vdev )
2015-11-03 18:20:57 +00:00
{
struct vfio_platform_region * xgmac_regs = & vdev - > regions [ 0 ] ;
struct vfio_platform_region * xpcs_regs = & vdev - > regions [ 1 ] ;
u32 dma_mr_value , pcs_value , value ;
unsigned int count ;
if ( ! xgmac_regs - > ioaddr ) {
xgmac_regs - > ioaddr =
2020-01-06 09:43:50 +01:00
ioremap ( xgmac_regs - > addr , xgmac_regs - > size ) ;
2015-11-03 18:20:57 +00:00
if ( ! xgmac_regs - > ioaddr )
return - ENOMEM ;
}
if ( ! xpcs_regs - > ioaddr ) {
xpcs_regs - > ioaddr =
2020-01-06 09:43:50 +01:00
ioremap ( xpcs_regs - > addr , xpcs_regs - > size ) ;
2015-11-03 18:20:57 +00:00
if ( ! xpcs_regs - > ioaddr )
return - ENOMEM ;
}
/* reset the PHY through MDIO*/
pcs_value = xmdio_read ( xpcs_regs - > ioaddr , MDIO_MMD_PCS , MDIO_CTRL1 ) ;
pcs_value | = MDIO_CTRL1_RESET ;
xmdio_write ( xpcs_regs - > ioaddr , MDIO_MMD_PCS , MDIO_CTRL1 , pcs_value ) ;
count = 50 ;
do {
msleep ( 20 ) ;
pcs_value = xmdio_read ( xpcs_regs - > ioaddr , MDIO_MMD_PCS ,
MDIO_CTRL1 ) ;
} while ( ( pcs_value & MDIO_CTRL1_RESET ) & & - - count ) ;
if ( pcs_value & MDIO_CTRL1_RESET )
2019-03-30 09:41:35 -05:00
dev_warn ( vdev - > device , " %s: XGBE PHY reset timeout \n " ,
__func__ ) ;
2015-11-03 18:20:57 +00:00
/* disable auto-negotiation */
value = xmdio_read ( xpcs_regs - > ioaddr , MDIO_MMD_AN , MDIO_CTRL1 ) ;
value & = ~ MDIO_AN_CTRL1_ENABLE ;
xmdio_write ( xpcs_regs - > ioaddr , MDIO_MMD_AN , MDIO_CTRL1 , value ) ;
/* disable AN IRQ */
xmdio_write ( xpcs_regs - > ioaddr , MDIO_MMD_AN , MDIO_AN_INTMASK , 0 ) ;
/* clear AN IRQ */
xmdio_write ( xpcs_regs - > ioaddr , MDIO_MMD_AN , MDIO_AN_INT , 0 ) ;
/* MAC software reset */
dma_mr_value = ioread32 ( xgmac_regs - > ioaddr + DMA_MR ) ;
dma_mr_value | = 0x1 ;
iowrite32 ( dma_mr_value , xgmac_regs - > ioaddr + DMA_MR ) ;
usleep_range ( 10 , 15 ) ;
count = 2000 ;
2015-12-17 15:27:07 +03:00
while ( - - count & & ( ioread32 ( xgmac_regs - > ioaddr + DMA_MR ) & 1 ) )
2015-11-03 18:20:57 +00:00
usleep_range ( 500 , 600 ) ;
if ( ! count )
2019-03-30 09:41:35 -05:00
dev_warn ( vdev - > device , " %s: MAC SW reset failed \n " , __func__ ) ;
2015-11-03 18:20:57 +00:00
return 0 ;
}
module_vfio_reset_handler ( " amd,xgbe-seattle-v1a " , vfio_platform_amdxgbe_reset ) ;
MODULE_VERSION ( " 0.1 " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( " Eric Auger <eric.auger@linaro.org> " ) ;
MODULE_DESCRIPTION ( " Reset support for AMD xgbe vfio platform device " ) ;