1 /* 2 * Copyright 2009-2010 Freescale Semiconductor, Inc. 3 * Jun-jie Zhang <b18070@freescale.com> 4 * Mingkai Hu <Mingkai.hu@freescale.com> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 19 * MA 02111-1307 USA 20 */ 21 #include <common.h> 22 #include <miiphy.h> 23 #include <phy.h> 24 #include <fsl_mdio.h> 25 #include <asm/io.h> 26 #include <asm/errno.h> 27 #include <asm/fsl_enet.h> 28 29 void tsec_local_mdio_write(struct tsec_mii_mng *phyregs, int port_addr, 30 int dev_addr, int regnum, int value) 31 { 32 int timeout = 1000000; 33 34 out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f)); 35 out_be32(&phyregs->miimcon, value); 36 asm("sync"); 37 38 while ((in_be32(&phyregs->miimind) & MIIMIND_BUSY) && timeout--) 39 ; 40 } 41 42 int tsec_local_mdio_read(struct tsec_mii_mng *phyregs, int port_addr, 43 int dev_addr, int regnum) 44 { 45 int value; 46 int timeout = 1000000; 47 48 /* Put the address of the phy, and the register 49 * number into MIIMADD */ 50 out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f)); 51 52 /* Clear the command register, and wait */ 53 out_be32(&phyregs->miimcom, 0); 54 asm("sync"); 55 56 /* Initiate a read command, and wait */ 57 out_be32(&phyregs->miimcom, MIIMCOM_READ_CYCLE); 58 asm("sync"); 59 60 /* Wait for the the indication that the read is done */ 61 while ((in_be32(&phyregs->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)) 62 && timeout--) 63 ; 64 65 /* Grab the value read from the PHY */ 66 value = in_be32(&phyregs->miimstat); 67 68 return value; 69 } 70 71 static int fsl_pq_mdio_reset(struct mii_dev *bus) 72 { 73 struct tsec_mii_mng *regs = bus->priv; 74 75 /* Reset MII (due to new addresses) */ 76 out_be32(®s->miimcfg, MIIMCFG_RESET_MGMT); 77 78 out_be32(®s->miimcfg, MIIMCFG_INIT_VALUE); 79 80 while (in_be32(®s->miimind) & MIIMIND_BUSY) 81 ; 82 83 return 0; 84 } 85 86 int tsec_phy_read(struct mii_dev *bus, int addr, int dev_addr, int regnum) 87 { 88 struct tsec_mii_mng *phyregs = bus->priv; 89 90 return tsec_local_mdio_read(phyregs, addr, dev_addr, regnum); 91 } 92 93 int tsec_phy_write(struct mii_dev *bus, int addr, int dev_addr, int regnum, 94 u16 value) 95 { 96 struct tsec_mii_mng *phyregs = bus->priv; 97 98 tsec_local_mdio_write(phyregs, addr, dev_addr, regnum, value); 99 100 return 0; 101 } 102 103 int fsl_pq_mdio_init(bd_t *bis, struct fsl_pq_mdio_info *info) 104 { 105 struct mii_dev *bus = mdio_alloc(); 106 107 if (!bus) { 108 printf("Failed to allocate FSL MDIO bus\n"); 109 return -1; 110 } 111 112 bus->read = tsec_phy_read; 113 bus->write = tsec_phy_write; 114 bus->reset = fsl_pq_mdio_reset; 115 sprintf(bus->name, info->name); 116 117 bus->priv = info->regs; 118 119 return mdio_register(bus); 120 } 121