1 /* 2 * Copyright (C) ASPEED Technology Inc. 3 * Ryan Chen <ryan_chen@aspeedtech.com> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <miiphy.h> 10 #include <phy.h> 11 #include <asm/io.h> 12 #include <reset.h> 13 #include <linux/errno.h> 14 15 /* 16 * PHY control register 17 */ 18 #define FTGMAC100_PHYCR_MDC_CYCTHR_MASK 0x3f 19 #define FTGMAC100_PHYCR_MDC_CYCTHR(x) ((x) & 0x3f) 20 #define FTGMAC100_PHYCR_PHYAD(x) (((x) & 0x1f) << 16) 21 #define FTGMAC100_PHYCR_REGAD(x) (((x) & 0x1f) << 21) 22 #define FTGMAC100_PHYCR_MIIRD (1 << 26) 23 #define FTGMAC100_PHYCR_MIIWR (1 << 27) 24 25 #ifdef CONFIG_ASPEED_AST2600 26 //G6 MDC/MDIO 27 #define FTGMAC100_PHYCR_NEW_FIRE BIT(31) 28 #define FTGMAC100_PHYCR_ST_22 BIT(28) 29 #define FTGMAC100_PHYCR_NEW_WRITE BIT(26) 30 #define FTGMAC100_PHYCR_NEW_READ BIT(27) 31 #define FTGMAC100_PHYCR_NEW_WDATA(x) (x & 0xffff) 32 #define FTGMAC100_PHYCR_NEW_PHYAD(x) (((x) & 0x1f) << 21) 33 #define FTGMAC100_PHYCR_NEW_REGAD(x) (((x) & 0x1f) << 16) 34 #else 35 //New MDC/MDIO 36 #define FTGMAC100_PHYCR_NEW_FIRE BIT(15) 37 #define FTGMAC100_PHYCR_ST_22 BIT(12) 38 #define FTGMAC100_PHYCR_NEW_WRITE BIT(10) 39 #define FTGMAC100_PHYCR_NEW_READ BIT(11) 40 #define FTGMAC100_PHYCR_NEW_WDATA(x) ((x & 0xffff) << 16) 41 #define FTGMAC100_PHYCR_NEW_PHYAD(x) (((x) & 0x1f) << 5) 42 #define FTGMAC100_PHYCR_NEW_REGAD(x) ((x) & 0x1f) 43 #endif 44 45 /* 46 * PHY data register 47 */ 48 #define FTGMAC100_PHYDATA_MIIWDATA(x) ((x) & 0xffff) 49 #define FTGMAC100_PHYDATA_MIIRDATA(phydata) (((phydata) >> 16) & 0xffff) 50 51 #define FTGMAC100_PHYDATA_NEW_MIIWDATA(x) ((x) & 0xffff) 52 53 struct aspeed_mdio_regs { 54 unsigned int phycr; 55 unsigned int phydata; 56 }; 57 58 extern int aspeed_mdio_read(struct mii_dev *bus, int phy_addr, int dev_addr, 59 int reg_addr) 60 { 61 struct aspeed_mdio_regs __iomem *mdio_regs = (struct aspeed_mdio_regs __iomem *)bus->priv; 62 u32 phycr; 63 int i; 64 65 #if 1 66 phycr = FTGMAC100_PHYCR_NEW_FIRE | FTGMAC100_PHYCR_ST_22 | FTGMAC100_PHYCR_NEW_READ | 67 FTGMAC100_PHYCR_NEW_PHYAD(phy_addr) | 68 FTGMAC100_PHYCR_NEW_REGAD(reg_addr); 69 70 writel(phycr, &mdio_regs->phycr); 71 mb(); 72 73 for (i = 0; i < 10; i++) { 74 phycr = readl(&mdio_regs->phycr); 75 76 if ((phycr & FTGMAC100_PHYCR_NEW_FIRE) == 0) { 77 u32 data; 78 79 data = readl(&mdio_regs->phydata); 80 return FTGMAC100_PHYDATA_NEW_MIIWDATA(data); 81 } 82 83 mdelay(10); 84 } 85 #else 86 phycr = readl(&mdio_regs->phycr); 87 88 /* preserve MDC cycle threshold */ 89 // phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK; 90 91 phycr = FTGMAC100_PHYCR_PHYAD(addr) 92 | FTGMAC100_PHYCR_REGAD(reg) 93 | FTGMAC100_PHYCR_MIIRD | 0x34; 94 95 writel(phycr, &mdio_regs->phycr); 96 97 for (i = 0; i < 10; i++) { 98 phycr = readl(&mdio_regs->phycr); 99 100 if ((phycr & FTGMAC100_PHYCR_MIIRD) == 0) { 101 int data; 102 103 data = readl(&mdio_regs->phydata); 104 return FTGMAC100_PHYDATA_MIIRDATA(data); 105 } 106 107 mdelay(10); 108 } 109 #endif 110 debug("mdio read timed out\n"); 111 return -1; 112 113 } 114 115 extern int aspeed_mdio_write(struct mii_dev *bus, int phy_addr, int dev_addr, 116 int reg_addr, u16 value) 117 { 118 struct aspeed_mdio_regs __iomem *mdio_regs = (struct aspeed_mdio_regs __iomem *)bus->priv; 119 int phycr; 120 int i; 121 122 #ifdef CONFIG_MACH_ASPEED_G4 123 int data; 124 125 phycr = readl(&mdio_regs->phycr); 126 127 /* preserve MDC cycle threshold */ 128 // phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK; 129 130 phycr = FTGMAC100_PHYCR_PHYAD(phy_addr) 131 | FTGMAC100_PHYCR_REGAD(reg_addr) 132 | FTGMAC100_PHYCR_MIIWR | 0x34; 133 134 data = FTGMAC100_PHYDATA_MIIWDATA(value); 135 136 writel(data, &mdio_regs->phydata); 137 writel(phycr, &mdio_regs->phycr); 138 139 for (i = 0; i < 10; i++) { 140 phycr = readl(&mdio_regs->phycr); 141 142 if ((phycr & FTGMAC100_PHYCR_MIIWR) == 0) { 143 debug("(phycr & FTGMAC100_PHYCR_MIIWR) == 0: " \ 144 "phy_addr: %x\n", phy_addr); 145 return 0; 146 } 147 148 mdelay(1); 149 } 150 #else 151 152 phycr = FTGMAC100_PHYCR_NEW_WDATA(value) | 153 FTGMAC100_PHYCR_NEW_FIRE | FTGMAC100_PHYCR_ST_22 | 154 FTGMAC100_PHYCR_NEW_WRITE | 155 FTGMAC100_PHYCR_NEW_PHYAD(phy_addr) | 156 FTGMAC100_PHYCR_NEW_REGAD(reg_addr); 157 158 writel(phycr, &mdio_regs->phycr); 159 mb(); 160 161 for (i = 0; i < 10; i++) { 162 phycr = readl(&mdio_regs->phycr); 163 164 if ((phycr & FTGMAC100_PHYCR_NEW_FIRE) == 0) { 165 debug("(phycr & FTGMAC100_PHYCR_MIIWR) == 0: " \ 166 "phy_addr: %x\n", phy_addr); 167 return 0; 168 } 169 170 mdelay(10); 171 } 172 #endif 173 debug("mdio write timed out\n"); 174 175 return -1; 176 } 177 178 static int aspeed_mdio_probe(struct udevice *dev) 179 { 180 // struct mii_dev *bus = (struct mii_dev *)dev_get_uclass_platdata(dev); 181 struct reset_ctl reset_ctl; 182 int ret = 0; 183 184 debug("%s(dev=%p) \n", __func__, dev); 185 186 ret = reset_get_by_index(dev, 0, &reset_ctl); 187 188 if (ret) { 189 printf("%s(): Failed to get reset signal\n", __func__); 190 return ret; 191 } 192 193 reset_assert(&reset_ctl); 194 reset_deassert(&reset_ctl); 195 196 return 0; 197 } 198 199 static const struct udevice_id aspeed_mdio_ids[] = { 200 { .compatible = "aspeed,aspeed-mdio" }, 201 { } 202 }; 203 204 U_BOOT_DRIVER(aspeed_mdio) = { 205 .name = "aspeed_mdio", 206 .id = UCLASS_MDIO, 207 .of_match = aspeed_mdio_ids, 208 .probe = aspeed_mdio_probe, 209 .priv_auto_alloc_size = sizeof(struct mii_dev), 210 }; 211 212 213