2 * VFIO platform driver specialized for AMD xgbe reset
3 * reset code is inherited from AMD xgbe native driver
5 * Copyright (c) 2015 Linaro Ltd.
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.
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
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/>.
21 #include <linux/module.h>
22 #include <linux/kernel.h>
23 #include <linux/init.h>
25 #include <uapi/linux/mdio.h>
26 #include <linux/delay.h>
28 #include "vfio_platform_private.h"
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
38 static unsigned int xmdio_read(void *ioaddr
, unsigned int mmd
,
41 unsigned int mmd_address
, value
;
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));
49 static void xmdio_write(void *ioaddr
, unsigned int mmd
,
50 unsigned int reg
, unsigned int value
)
52 unsigned int mmd_address
;
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));
59 static int vfio_platform_amdxgbe_reset(struct vfio_platform_device
*vdev
)
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
;
66 if (!xgmac_regs
->ioaddr
) {
68 ioremap_nocache(xgmac_regs
->addr
, xgmac_regs
->size
);
69 if (!xgmac_regs
->ioaddr
)
72 if (!xpcs_regs
->ioaddr
) {
74 ioremap_nocache(xpcs_regs
->addr
, xpcs_regs
->size
);
75 if (!xpcs_regs
->ioaddr
)
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
);
87 pcs_value
= xmdio_read(xpcs_regs
->ioaddr
, MDIO_MMD_PCS
,
89 } while ((pcs_value
& MDIO_CTRL1_RESET
) && --count
);
91 if (pcs_value
& MDIO_CTRL1_RESET
)
92 pr_warn("%s XGBE PHY reset timeout\n", __func__
);
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
);
100 xmdio_write(xpcs_regs
->ioaddr
, MDIO_MMD_AN
, MDIO_AN_INTMASK
, 0);
103 xmdio_write(xpcs_regs
->ioaddr
, MDIO_MMD_AN
, MDIO_AN_INT
, 0);
105 /* MAC software reset */
106 dma_mr_value
= ioread32(xgmac_regs
->ioaddr
+ DMA_MR
);
108 iowrite32(dma_mr_value
, xgmac_regs
->ioaddr
+ DMA_MR
);
110 usleep_range(10, 15);
113 while (--count
&& (ioread32(xgmac_regs
->ioaddr
+ DMA_MR
) & 1))
114 usleep_range(500, 600);
117 pr_warn("%s MAC SW reset failed\n", __func__
);
122 module_vfio_reset_handler("amd,xgbe-seattle-v1a", vfio_platform_amdxgbe_reset
);
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");