123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- /*
- * 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
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
- */
- #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>
- #include "vfio_platform_private.h"
- #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
- static unsigned int xmdio_read(void *ioaddr, unsigned int mmd,
- 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;
- }
- static void xmdio_write(void *ioaddr, unsigned int mmd,
- 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));
- }
- static int vfio_platform_amdxgbe_reset(struct vfio_platform_device *vdev)
- {
- 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 =
- ioremap_nocache(xgmac_regs->addr, xgmac_regs->size);
- if (!xgmac_regs->ioaddr)
- return -ENOMEM;
- }
- if (!xpcs_regs->ioaddr) {
- xpcs_regs->ioaddr =
- ioremap_nocache(xpcs_regs->addr, xpcs_regs->size);
- 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)
- pr_warn("%s XGBE PHY reset timeout\n", __func__);
- /* 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;
- while (--count && (ioread32(xgmac_regs->ioaddr + DMA_MR) & 1))
- usleep_range(500, 600);
- if (!count)
- pr_warn("%s MAC SW reset failed\n", __func__);
- 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");
|