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 <linux/errno.h> 13 14 /* 15 * PHY control register 16 */ 17 #define FTGMAC100_PHYCR_MDC_CYCTHR_MASK 0x3f 18 #define FTGMAC100_PHYCR_MDC_CYCTHR(x) ((x) & 0x3f) 19 #define FTGMAC100_PHYCR_PHYAD(x) (((x) & 0x1f) << 16) 20 #define FTGMAC100_PHYCR_REGAD(x) (((x) & 0x1f) << 21) 21 #define FTGMAC100_PHYCR_MIIRD (1 << 26) 22 #define FTGMAC100_PHYCR_MIIWR (1 << 27) 23 24 #ifdef CONFIG_MACH_ASPEED_G6 25 //G6 MDC/MDIO 26 #define FTGMAC100_PHYCR_NEW_FIRE BIT(31) 27 #define FTGMAC100_PHYCR_ST_22 BIT(28) 28 #define FTGMAC100_PHYCR_NEW_WRITE BIT(26) 29 #define FTGMAC100_PHYCR_NEW_READ BIT(27) 30 #define FTGMAC100_PHYCR_NEW_WDATA(x) (x & 0xffff) 31 #define FTGMAC100_PHYCR_NEW_PHYAD(x) (((x) & 0x1f) << 21) 32 #define FTGMAC100_PHYCR_NEW_REGAD(x) (((x) & 0x1f) << 16) 33 #else 34 //New MDC/MDIO 35 #define FTGMAC100_PHYCR_NEW_FIRE BIT(15) 36 #define FTGMAC100_PHYCR_ST_22 BIT(12) 37 #define FTGMAC100_PHYCR_NEW_WRITE BIT(10) 38 #define FTGMAC100_PHYCR_NEW_READ BIT(11) 39 #define FTGMAC100_PHYCR_NEW_WDATA(x) ((x & 0xffff) << 16) 40 #define FTGMAC100_PHYCR_NEW_PHYAD(x) (((x) & 0x1f) << 5) 41 #define FTGMAC100_PHYCR_NEW_REGAD(x) ((x) & 0x1f) 42 #endif 43 44 /* 45 * PHY data register 46 */ 47 #define FTGMAC100_PHYDATA_MIIWDATA(x) ((x) & 0xffff) 48 #define FTGMAC100_PHYDATA_MIIRDATA(phydata) (((phydata) >> 16) & 0xffff) 49 50 #define FTGMAC100_PHYDATA_NEW_MIIWDATA(x) ((x) & 0xffff) 51 52 struct aspeed_mdio_regs { 53 unsigned int phycr; 54 unsigned int phydata; 55 }; 56 57 extern int aspeed_mdio_read(struct mii_dev *bus, int phy_addr, int dev_addr, 58 int reg_addr) 59 { 60 struct aspeed_mdio_regs __iomem *mdio_regs = (struct aspeed_mdio_regs __iomem *)bus->priv; 61 u32 phycr; 62 int i; 63 64 #if 1 65 phycr = FTGMAC100_PHYCR_NEW_FIRE | FTGMAC100_PHYCR_ST_22 | FTGMAC100_PHYCR_NEW_READ | 66 FTGMAC100_PHYCR_NEW_PHYAD(phy_addr) | // 20141114 67 FTGMAC100_PHYCR_NEW_REGAD(reg_addr); // 20141114 68 69 writel(phycr, &mdio_regs->phycr); 70 mb(); 71 72 for (i = 0; i < 10; i++) { 73 phycr = readl(&mdio_regs->phycr); 74 75 if ((phycr & FTGMAC100_PHYCR_NEW_FIRE) == 0) { 76 u32 data; 77 78 data = readl(&mdio_regs->phydata); 79 return FTGMAC100_PHYDATA_NEW_MIIWDATA(data); 80 } 81 82 mdelay(10); 83 } 84 #else 85 phycr = readl(&mdio_regs->phycr); 86 87 /* preserve MDC cycle threshold */ 88 // phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK; 89 90 phycr = FTGMAC100_PHYCR_PHYAD(addr) 91 | FTGMAC100_PHYCR_REGAD(reg) 92 | FTGMAC100_PHYCR_MIIRD | 0x34; 93 94 writel(phycr, &mdio_regs->phycr); 95 96 for (i = 0; i < 10; i++) { 97 phycr = readl(&mdio_regs->phycr); 98 99 if ((phycr & FTGMAC100_PHYCR_MIIRD) == 0) { 100 int data; 101 102 data = readl(&mdio_regs->phydata); 103 return FTGMAC100_PHYDATA_MIIRDATA(data); 104 } 105 106 mdelay(10); 107 } 108 #endif 109 debug("mdio read timed out\n"); 110 return -1; 111 112 } 113 114 extern int aspeed_mdio_write(struct mii_dev *bus, int phy_addr, int dev_addr, 115 int reg_addr, u16 value) 116 { 117 struct aspeed_mdio_regs __iomem *mdio_regs = (struct aspeed_mdio_regs __iomem *)bus->priv; 118 int phycr; 119 int i; 120 121 #ifdef CONFIG_MACH_ASPEED_G4 122 int data; 123 124 phycr = readl(&mdio_regs->phycr); 125 126 /* preserve MDC cycle threshold */ 127 // phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK; 128 129 phycr = FTGMAC100_PHYCR_PHYAD(phy_addr) 130 | FTGMAC100_PHYCR_REGAD(reg_addr) 131 | FTGMAC100_PHYCR_MIIWR | 0x34; 132 133 data = FTGMAC100_PHYDATA_MIIWDATA(value); 134 135 writel(data, &mdio_regs->phydata); 136 writel(phycr, &mdio_regs->phycr); 137 138 for (i = 0; i < 10; i++) { 139 phycr = readl(&mdio_regs->phycr); 140 141 if ((phycr & FTGMAC100_PHYCR_MIIWR) == 0) { 142 debug("(phycr & FTGMAC100_PHYCR_MIIWR) == 0: " \ 143 "phy_addr: %x\n", phy_addr); 144 return 0; 145 } 146 147 mdelay(1); 148 } 149 #else 150 151 phycr = FTGMAC100_PHYCR_NEW_WDATA(value) | 152 FTGMAC100_PHYCR_NEW_FIRE | FTGMAC100_PHYCR_ST_22 | 153 FTGMAC100_PHYCR_NEW_WRITE | 154 FTGMAC100_PHYCR_NEW_PHYAD(phy_addr) | 155 FTGMAC100_PHYCR_NEW_REGAD(reg_addr); 156 157 writel(phycr, &mdio_regs->phycr); 158 mb(); 159 160 for (i = 0; i < 10; i++) { 161 phycr = readl(&mdio_regs->phycr); 162 163 if ((phycr & FTGMAC100_PHYCR_NEW_FIRE) == 0) { 164 debug("(phycr & FTGMAC100_PHYCR_MIIWR) == 0: " \ 165 "phy_addr: %x\n", phy_addr); 166 return 0; 167 } 168 169 mdelay(10); 170 } 171 #endif 172 debug("mdio write timed out\n"); 173 174 return -1; 175 } 176