1063c1263SAndy Fleming /* 25be00a01SClaudiu Manoil * Copyright 2009-2010, 2013 Freescale Semiconductor, Inc. 3063c1263SAndy Fleming * Jun-jie Zhang <b18070@freescale.com> 4063c1263SAndy Fleming * Mingkai Hu <Mingkai.hu@freescale.com> 5063c1263SAndy Fleming * 61a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 7063c1263SAndy Fleming */ 8063c1263SAndy Fleming #include <common.h> 9063c1263SAndy Fleming #include <miiphy.h> 10063c1263SAndy Fleming #include <phy.h> 11063c1263SAndy Fleming #include <fsl_mdio.h> 12063c1263SAndy Fleming #include <asm/io.h> 13063c1263SAndy Fleming #include <asm/errno.h> 14063c1263SAndy Fleming 155be00a01SClaudiu Manoil void tsec_local_mdio_write(struct tsec_mii_mng __iomem *phyregs, int port_addr, 16063c1263SAndy Fleming int dev_addr, int regnum, int value) 17063c1263SAndy Fleming { 18063c1263SAndy Fleming int timeout = 1000000; 19063c1263SAndy Fleming 20063c1263SAndy Fleming out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f)); 21063c1263SAndy Fleming out_be32(&phyregs->miimcon, value); 22*d2614ea0SAlison Wang /* Memory barrier */ 23*d2614ea0SAlison Wang mb(); 24063c1263SAndy Fleming 25063c1263SAndy Fleming while ((in_be32(&phyregs->miimind) & MIIMIND_BUSY) && timeout--) 26063c1263SAndy Fleming ; 27063c1263SAndy Fleming } 28063c1263SAndy Fleming 295be00a01SClaudiu Manoil int tsec_local_mdio_read(struct tsec_mii_mng __iomem *phyregs, int port_addr, 30063c1263SAndy Fleming int dev_addr, int regnum) 31063c1263SAndy Fleming { 32063c1263SAndy Fleming int value; 33063c1263SAndy Fleming int timeout = 1000000; 34063c1263SAndy Fleming 35063c1263SAndy Fleming /* Put the address of the phy, and the register 36063c1263SAndy Fleming * number into MIIMADD */ 37063c1263SAndy Fleming out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f)); 38063c1263SAndy Fleming 39063c1263SAndy Fleming /* Clear the command register, and wait */ 40063c1263SAndy Fleming out_be32(&phyregs->miimcom, 0); 41*d2614ea0SAlison Wang /* Memory barrier */ 42*d2614ea0SAlison Wang mb(); 43063c1263SAndy Fleming 44063c1263SAndy Fleming /* Initiate a read command, and wait */ 45063c1263SAndy Fleming out_be32(&phyregs->miimcom, MIIMCOM_READ_CYCLE); 46*d2614ea0SAlison Wang /* Memory barrier */ 47*d2614ea0SAlison Wang mb(); 48063c1263SAndy Fleming 49063c1263SAndy Fleming /* Wait for the the indication that the read is done */ 50063c1263SAndy Fleming while ((in_be32(&phyregs->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)) 51063c1263SAndy Fleming && timeout--) 52063c1263SAndy Fleming ; 53063c1263SAndy Fleming 54063c1263SAndy Fleming /* Grab the value read from the PHY */ 55063c1263SAndy Fleming value = in_be32(&phyregs->miimstat); 56063c1263SAndy Fleming 57063c1263SAndy Fleming return value; 58063c1263SAndy Fleming } 59063c1263SAndy Fleming 60063c1263SAndy Fleming static int fsl_pq_mdio_reset(struct mii_dev *bus) 61063c1263SAndy Fleming { 625be00a01SClaudiu Manoil struct tsec_mii_mng __iomem *regs = 635be00a01SClaudiu Manoil (struct tsec_mii_mng __iomem *)bus->priv; 64063c1263SAndy Fleming 65063c1263SAndy Fleming /* Reset MII (due to new addresses) */ 66063c1263SAndy Fleming out_be32(®s->miimcfg, MIIMCFG_RESET_MGMT); 67063c1263SAndy Fleming 68063c1263SAndy Fleming out_be32(®s->miimcfg, MIIMCFG_INIT_VALUE); 69063c1263SAndy Fleming 70063c1263SAndy Fleming while (in_be32(®s->miimind) & MIIMIND_BUSY) 71063c1263SAndy Fleming ; 72063c1263SAndy Fleming 73063c1263SAndy Fleming return 0; 74063c1263SAndy Fleming } 75063c1263SAndy Fleming 76063c1263SAndy Fleming int tsec_phy_read(struct mii_dev *bus, int addr, int dev_addr, int regnum) 77063c1263SAndy Fleming { 785be00a01SClaudiu Manoil struct tsec_mii_mng __iomem *phyregs = 795be00a01SClaudiu Manoil (struct tsec_mii_mng __iomem *)bus->priv; 80063c1263SAndy Fleming 81063c1263SAndy Fleming return tsec_local_mdio_read(phyregs, addr, dev_addr, regnum); 82063c1263SAndy Fleming } 83063c1263SAndy Fleming 84063c1263SAndy Fleming int tsec_phy_write(struct mii_dev *bus, int addr, int dev_addr, int regnum, 85063c1263SAndy Fleming u16 value) 86063c1263SAndy Fleming { 875be00a01SClaudiu Manoil struct tsec_mii_mng __iomem *phyregs = 885be00a01SClaudiu Manoil (struct tsec_mii_mng __iomem *)bus->priv; 89063c1263SAndy Fleming 90063c1263SAndy Fleming tsec_local_mdio_write(phyregs, addr, dev_addr, regnum, value); 91063c1263SAndy Fleming 92063c1263SAndy Fleming return 0; 93063c1263SAndy Fleming } 94063c1263SAndy Fleming 95063c1263SAndy Fleming int fsl_pq_mdio_init(bd_t *bis, struct fsl_pq_mdio_info *info) 96063c1263SAndy Fleming { 97063c1263SAndy Fleming struct mii_dev *bus = mdio_alloc(); 98063c1263SAndy Fleming 99063c1263SAndy Fleming if (!bus) { 100063c1263SAndy Fleming printf("Failed to allocate FSL MDIO bus\n"); 101063c1263SAndy Fleming return -1; 102063c1263SAndy Fleming } 103063c1263SAndy Fleming 104063c1263SAndy Fleming bus->read = tsec_phy_read; 105063c1263SAndy Fleming bus->write = tsec_phy_write; 106063c1263SAndy Fleming bus->reset = fsl_pq_mdio_reset; 107063c1263SAndy Fleming sprintf(bus->name, info->name); 108063c1263SAndy Fleming 1095be00a01SClaudiu Manoil bus->priv = (void *)info->regs; 110063c1263SAndy Fleming 111063c1263SAndy Fleming return mdio_register(bus); 112063c1263SAndy Fleming } 113