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 */ 89872b736SBin Meng 9063c1263SAndy Fleming #include <common.h> 10063c1263SAndy Fleming #include <miiphy.h> 11063c1263SAndy Fleming #include <phy.h> 12063c1263SAndy Fleming #include <fsl_mdio.h> 13063c1263SAndy Fleming #include <asm/io.h> 14*1221ce45SMasahiro Yamada #include <linux/errno.h> 15063c1263SAndy Fleming 165be00a01SClaudiu Manoil void tsec_local_mdio_write(struct tsec_mii_mng __iomem *phyregs, int port_addr, 17063c1263SAndy Fleming int dev_addr, int regnum, int value) 18063c1263SAndy Fleming { 19063c1263SAndy Fleming int timeout = 1000000; 20063c1263SAndy Fleming 21063c1263SAndy Fleming out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f)); 22063c1263SAndy Fleming out_be32(&phyregs->miimcon, value); 23d2614ea0SAlison Wang /* Memory barrier */ 24d2614ea0SAlison Wang mb(); 25063c1263SAndy Fleming 26063c1263SAndy Fleming while ((in_be32(&phyregs->miimind) & MIIMIND_BUSY) && timeout--) 27063c1263SAndy Fleming ; 28063c1263SAndy Fleming } 29063c1263SAndy Fleming 305be00a01SClaudiu Manoil int tsec_local_mdio_read(struct tsec_mii_mng __iomem *phyregs, int port_addr, 31063c1263SAndy Fleming int dev_addr, int regnum) 32063c1263SAndy Fleming { 33063c1263SAndy Fleming int value; 34063c1263SAndy Fleming int timeout = 1000000; 35063c1263SAndy Fleming 369872b736SBin Meng /* Put the address of the phy, and the register 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); 41d2614ea0SAlison Wang /* Memory barrier */ 42d2614ea0SAlison Wang mb(); 43063c1263SAndy Fleming 44063c1263SAndy Fleming /* Initiate a read command, and wait */ 45063c1263SAndy Fleming out_be32(&phyregs->miimcom, MIIMCOM_READ_CYCLE); 46d2614ea0SAlison Wang /* Memory barrier */ 47d2614ea0SAlison 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; 107192bc694SBen Whitten strcpy(bus->name, info->name); 108063c1263SAndy Fleming 1095be00a01SClaudiu Manoil bus->priv = (void *)info->regs; 110063c1263SAndy Fleming 111063c1263SAndy Fleming return mdio_register(bus); 112063c1263SAndy Fleming } 113