Home | History | Annotate | Download | only in net
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Copyright 2009-2010, 2013 Freescale Semiconductor, Inc.
      4  *	Jun-jie Zhang <b18070 (at) freescale.com>
      5  *	Mingkai Hu <Mingkai.hu (at) freescale.com>
      6  */
      7 
      8 #include <common.h>
      9 #include <miiphy.h>
     10 #include <phy.h>
     11 #include <fsl_mdio.h>
     12 #include <asm/io.h>
     13 #include <linux/errno.h>
     14 
     15 void tsec_local_mdio_write(struct tsec_mii_mng __iomem *phyregs, int port_addr,
     16 		int dev_addr, int regnum, int value)
     17 {
     18 	int timeout = 1000000;
     19 
     20 	out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f));
     21 	out_be32(&phyregs->miimcon, value);
     22 	/* Memory barrier */
     23 	mb();
     24 
     25 	while ((in_be32(&phyregs->miimind) & MIIMIND_BUSY) && timeout--)
     26 		;
     27 }
     28 
     29 int tsec_local_mdio_read(struct tsec_mii_mng __iomem *phyregs, int port_addr,
     30 		int dev_addr, int regnum)
     31 {
     32 	int value;
     33 	int timeout = 1000000;
     34 
     35 	/* Put the address of the phy, and the register number into MIIMADD */
     36 	out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f));
     37 
     38 	/* Clear the command register, and wait */
     39 	out_be32(&phyregs->miimcom, 0);
     40 	/* Memory barrier */
     41 	mb();
     42 
     43 	/* Initiate a read command, and wait */
     44 	out_be32(&phyregs->miimcom, MIIMCOM_READ_CYCLE);
     45 	/* Memory barrier */
     46 	mb();
     47 
     48 	/* Wait for the the indication that the read is done */
     49 	while ((in_be32(&phyregs->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY))
     50 			&& timeout--)
     51 		;
     52 
     53 	/* Grab the value read from the PHY */
     54 	value = in_be32(&phyregs->miimstat);
     55 
     56 	return value;
     57 }
     58 
     59 static int fsl_pq_mdio_reset(struct mii_dev *bus)
     60 {
     61 	struct tsec_mii_mng __iomem *regs =
     62 		(struct tsec_mii_mng __iomem *)bus->priv;
     63 
     64 	/* Reset MII (due to new addresses) */
     65 	out_be32(&regs->miimcfg, MIIMCFG_RESET_MGMT);
     66 
     67 	out_be32(&regs->miimcfg, MIIMCFG_INIT_VALUE);
     68 
     69 	while (in_be32(&regs->miimind) & MIIMIND_BUSY)
     70 		;
     71 
     72 	return 0;
     73 }
     74 
     75 int tsec_phy_read(struct mii_dev *bus, int addr, int dev_addr, int regnum)
     76 {
     77 	struct tsec_mii_mng __iomem *phyregs =
     78 		(struct tsec_mii_mng __iomem *)bus->priv;
     79 
     80 	return tsec_local_mdio_read(phyregs, addr, dev_addr, regnum);
     81 }
     82 
     83 int tsec_phy_write(struct mii_dev *bus, int addr, int dev_addr, int regnum,
     84 			u16 value)
     85 {
     86 	struct tsec_mii_mng __iomem *phyregs =
     87 		(struct tsec_mii_mng __iomem *)bus->priv;
     88 
     89 	tsec_local_mdio_write(phyregs, addr, dev_addr, regnum, value);
     90 
     91 	return 0;
     92 }
     93 
     94 int fsl_pq_mdio_init(bd_t *bis, struct fsl_pq_mdio_info *info)
     95 {
     96 	struct mii_dev *bus = mdio_alloc();
     97 
     98 	if (!bus) {
     99 		printf("Failed to allocate FSL MDIO bus\n");
    100 		return -1;
    101 	}
    102 
    103 	bus->read = tsec_phy_read;
    104 	bus->write = tsec_phy_write;
    105 	bus->reset = fsl_pq_mdio_reset;
    106 	strcpy(bus->name, info->name);
    107 
    108 	bus->priv = (void *)info->regs;
    109 
    110 	return mdio_register(bus);
    111 }
    112