1 /* 2 * VFIO platform driver specialized for AMD xgbe reset 3 * reset code is inherited from AMD xgbe native driver 4 * 5 * Copyright (c) 2015 Linaro Ltd. 6 * www.linaro.org 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms and conditions of the GNU General Public License, 10 * version 2, as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along with 18 * this program. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 #include <linux/module.h> 22 #include <linux/kernel.h> 23 #include <linux/init.h> 24 #include <linux/io.h> 25 #include <uapi/linux/mdio.h> 26 #include <linux/delay.h> 27 28 #include "vfio_platform_private.h" 29 30 #define DMA_MR 0x3000 31 #define MAC_VR 0x0110 32 #define DMA_ISR 0x3008 33 #define MAC_ISR 0x00b0 34 #define PCS_MMD_SELECT 0xff 35 #define MDIO_AN_INT 0x8002 36 #define MDIO_AN_INTMASK 0x8001 37 38 static unsigned int xmdio_read(void *ioaddr, unsigned int mmd, 39 unsigned int reg) 40 { 41 unsigned int mmd_address, value; 42 43 mmd_address = (mmd << 16) | ((reg) & 0xffff); 44 iowrite32(mmd_address >> 8, ioaddr + (PCS_MMD_SELECT << 2)); 45 value = ioread32(ioaddr + ((mmd_address & 0xff) << 2)); 46 return value; 47 } 48 49 static void xmdio_write(void *ioaddr, unsigned int mmd, 50 unsigned int reg, unsigned int value) 51 { 52 unsigned int mmd_address; 53 54 mmd_address = (mmd << 16) | ((reg) & 0xffff); 55 iowrite32(mmd_address >> 8, ioaddr + (PCS_MMD_SELECT << 2)); 56 iowrite32(value, ioaddr + ((mmd_address & 0xff) << 2)); 57 } 58 59 int vfio_platform_amdxgbe_reset(struct vfio_platform_device *vdev) 60 { 61 struct vfio_platform_region *xgmac_regs = &vdev->regions[0]; 62 struct vfio_platform_region *xpcs_regs = &vdev->regions[1]; 63 u32 dma_mr_value, pcs_value, value; 64 unsigned int count; 65 66 if (!xgmac_regs->ioaddr) { 67 xgmac_regs->ioaddr = 68 ioremap_nocache(xgmac_regs->addr, xgmac_regs->size); 69 if (!xgmac_regs->ioaddr) 70 return -ENOMEM; 71 } 72 if (!xpcs_regs->ioaddr) { 73 xpcs_regs->ioaddr = 74 ioremap_nocache(xpcs_regs->addr, xpcs_regs->size); 75 if (!xpcs_regs->ioaddr) 76 return -ENOMEM; 77 } 78 79 /* reset the PHY through MDIO*/ 80 pcs_value = xmdio_read(xpcs_regs->ioaddr, MDIO_MMD_PCS, MDIO_CTRL1); 81 pcs_value |= MDIO_CTRL1_RESET; 82 xmdio_write(xpcs_regs->ioaddr, MDIO_MMD_PCS, MDIO_CTRL1, pcs_value); 83 84 count = 50; 85 do { 86 msleep(20); 87 pcs_value = xmdio_read(xpcs_regs->ioaddr, MDIO_MMD_PCS, 88 MDIO_CTRL1); 89 } while ((pcs_value & MDIO_CTRL1_RESET) && --count); 90 91 if (pcs_value & MDIO_CTRL1_RESET) 92 pr_warn("%s XGBE PHY reset timeout\n", __func__); 93 94 /* disable auto-negotiation */ 95 value = xmdio_read(xpcs_regs->ioaddr, MDIO_MMD_AN, MDIO_CTRL1); 96 value &= ~MDIO_AN_CTRL1_ENABLE; 97 xmdio_write(xpcs_regs->ioaddr, MDIO_MMD_AN, MDIO_CTRL1, value); 98 99 /* disable AN IRQ */ 100 xmdio_write(xpcs_regs->ioaddr, MDIO_MMD_AN, MDIO_AN_INTMASK, 0); 101 102 /* clear AN IRQ */ 103 xmdio_write(xpcs_regs->ioaddr, MDIO_MMD_AN, MDIO_AN_INT, 0); 104 105 /* MAC software reset */ 106 dma_mr_value = ioread32(xgmac_regs->ioaddr + DMA_MR); 107 dma_mr_value |= 0x1; 108 iowrite32(dma_mr_value, xgmac_regs->ioaddr + DMA_MR); 109 110 usleep_range(10, 15); 111 112 count = 2000; 113 while (--count && (ioread32(xgmac_regs->ioaddr + DMA_MR) & 1)) 114 usleep_range(500, 600); 115 116 if (!count) 117 pr_warn("%s MAC SW reset failed\n", __func__); 118 119 return 0; 120 } 121 122 module_vfio_reset_handler("amd,xgbe-seattle-v1a", vfio_platform_amdxgbe_reset); 123 124 MODULE_VERSION("0.1"); 125 MODULE_LICENSE("GPL v2"); 126 MODULE_AUTHOR("Eric Auger <eric.auger@linaro.org>"); 127 MODULE_DESCRIPTION("Reset support for AMD xgbe vfio platform device"); 128