xref: /freebsd/sys/dev/enetc/enetc_mdio.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
159061c7eSMarcin Wojtas /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
359061c7eSMarcin Wojtas  *
459061c7eSMarcin Wojtas  * Copyright (c) 2021 Alstom Group.
559061c7eSMarcin Wojtas  * Copyright (c) 2021 Semihalf.
659061c7eSMarcin Wojtas  *
759061c7eSMarcin Wojtas  * Redistribution and use in source and binary forms, with or without
859061c7eSMarcin Wojtas  * modification, are permitted provided that the following conditions
959061c7eSMarcin Wojtas  * are met:
1059061c7eSMarcin Wojtas  * 1. Redistributions of source code must retain the above copyright
1159061c7eSMarcin Wojtas  *    notice, this list of conditions and the following disclaimer.
1259061c7eSMarcin Wojtas  * 2. Redistributions in binary form must reproduce the above copyright
1359061c7eSMarcin Wojtas  *    notice, this list of conditions and the following disclaimer in the
1459061c7eSMarcin Wojtas  *    documentation and/or other materials provided with the distribution.
1559061c7eSMarcin Wojtas  *
1659061c7eSMarcin Wojtas  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1759061c7eSMarcin Wojtas  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1859061c7eSMarcin Wojtas  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1959061c7eSMarcin Wojtas  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2059061c7eSMarcin Wojtas  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2159061c7eSMarcin Wojtas  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2259061c7eSMarcin Wojtas  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2359061c7eSMarcin Wojtas  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2459061c7eSMarcin Wojtas  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2559061c7eSMarcin Wojtas  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2659061c7eSMarcin Wojtas  */
2759061c7eSMarcin Wojtas 
2859061c7eSMarcin Wojtas #include <sys/param.h>
2959061c7eSMarcin Wojtas #include <sys/bus.h>
3059061c7eSMarcin Wojtas #include <sys/endian.h>
3159061c7eSMarcin Wojtas #include <sys/kernel.h>
3259061c7eSMarcin Wojtas #include <sys/module.h>
3359061c7eSMarcin Wojtas #include <sys/rman.h>
3459061c7eSMarcin Wojtas 
3559061c7eSMarcin Wojtas #include <machine/bus.h>
3659061c7eSMarcin Wojtas #include <machine/resource.h>
3759061c7eSMarcin Wojtas 
3859061c7eSMarcin Wojtas #include <dev/enetc/enetc_hw.h>
3959061c7eSMarcin Wojtas #include <dev/enetc/enetc_mdio.h>
4059061c7eSMarcin Wojtas 
4159061c7eSMarcin Wojtas #define ENETC_MDIO_RD4(regs, base, off) \
4259061c7eSMarcin Wojtas 	bus_read_4((regs), (base) + (off))
4359061c7eSMarcin Wojtas #define ENETC_MDIO_WR4(regs, base, off, value) \
4459061c7eSMarcin Wojtas 	bus_write_4((regs), (base) + (off), (value))
4559061c7eSMarcin Wojtas 
4659061c7eSMarcin Wojtas static int
enetc_mdio_wait(struct resource * regs,int mdio_base)4759061c7eSMarcin Wojtas enetc_mdio_wait(struct resource *regs, int mdio_base)
4859061c7eSMarcin Wojtas {
4959061c7eSMarcin Wojtas 	int i;
5059061c7eSMarcin Wojtas 	uint32_t val;
5159061c7eSMarcin Wojtas 
5259061c7eSMarcin Wojtas 	i = 0;
5359061c7eSMarcin Wojtas 	do {
5459061c7eSMarcin Wojtas 		DELAY(100);
5559061c7eSMarcin Wojtas 		val = ENETC_MDIO_RD4(regs, mdio_base, ENETC_MDIO_CFG);
5659061c7eSMarcin Wojtas 		if ((val & MDIO_CFG_BSY) == 0)
5759061c7eSMarcin Wojtas 			return (0);
5859061c7eSMarcin Wojtas 	} while (i++ < ENETC_TIMEOUT);
5959061c7eSMarcin Wojtas 
6059061c7eSMarcin Wojtas 	return (ETIMEDOUT);
6159061c7eSMarcin Wojtas }
6259061c7eSMarcin Wojtas 
6359061c7eSMarcin Wojtas int
enetc_mdio_read(struct resource * regs,int mdio_base,int phy,int reg)6459061c7eSMarcin Wojtas enetc_mdio_read(struct resource *regs, int mdio_base, int phy, int reg)
6559061c7eSMarcin Wojtas {
6659061c7eSMarcin Wojtas 	uint32_t mdio_cfg, mdio_ctl;
6759061c7eSMarcin Wojtas 	uint16_t dev_addr;
6859061c7eSMarcin Wojtas 
6959061c7eSMarcin Wojtas 	mdio_cfg = MDIO_CFG_CLKDIV(ENETC_MDC_DIV) | MDIO_CFG_NEG;
7059061c7eSMarcin Wojtas 	if (reg & MII_ADDR_C45) {
7159061c7eSMarcin Wojtas 		/* clause 45 */
7259061c7eSMarcin Wojtas 		dev_addr = (reg >> 16) & 0x1f;
7359061c7eSMarcin Wojtas 		mdio_cfg |= MDIO_CFG_ENC45;
7459061c7eSMarcin Wojtas 	} else {
7559061c7eSMarcin Wojtas 		/* clause 22 */
7659061c7eSMarcin Wojtas 		dev_addr = reg & 0x1f;
7759061c7eSMarcin Wojtas 		mdio_cfg &= ~MDIO_CFG_ENC45;
7859061c7eSMarcin Wojtas 	}
7959061c7eSMarcin Wojtas 
8059061c7eSMarcin Wojtas 	ENETC_MDIO_WR4(regs, mdio_base, ENETC_MDIO_CFG, mdio_cfg);
8159061c7eSMarcin Wojtas 
8259061c7eSMarcin Wojtas 	if (enetc_mdio_wait(regs, mdio_base) == ETIMEDOUT)
8359061c7eSMarcin Wojtas 		return (EIO);
8459061c7eSMarcin Wojtas 
8559061c7eSMarcin Wojtas 	/* Set port and device addr. */
8659061c7eSMarcin Wojtas 	mdio_ctl = MDIO_CTL_PORT_ADDR(phy) | MDIO_CTL_DEV_ADDR(dev_addr);
8759061c7eSMarcin Wojtas 	ENETC_MDIO_WR4(regs, mdio_base, ENETC_MDIO_CTL, mdio_ctl);
8859061c7eSMarcin Wojtas 
8959061c7eSMarcin Wojtas 	/* Set the register address. */
9059061c7eSMarcin Wojtas 	if (reg & MII_ADDR_C45) {
9159061c7eSMarcin Wojtas 		ENETC_MDIO_WR4(regs, mdio_base, ENETC_MDIO_ADDR, reg & 0xffff);
9259061c7eSMarcin Wojtas 
9359061c7eSMarcin Wojtas 		if (enetc_mdio_wait(regs, mdio_base) == ETIMEDOUT)
9459061c7eSMarcin Wojtas 			return (EIO);
9559061c7eSMarcin Wojtas 	}
9659061c7eSMarcin Wojtas 
9759061c7eSMarcin Wojtas 	/* Initiate the read. */
9859061c7eSMarcin Wojtas 	ENETC_MDIO_WR4(regs, mdio_base, ENETC_MDIO_CTL, mdio_ctl | MDIO_CTL_READ);
9959061c7eSMarcin Wojtas 
10059061c7eSMarcin Wojtas 	if (enetc_mdio_wait(regs, mdio_base) == ETIMEDOUT)
10159061c7eSMarcin Wojtas 		return (EIO);
10259061c7eSMarcin Wojtas 
10359061c7eSMarcin Wojtas 	/* Check if any error occurred while reading PHY register. */
10459061c7eSMarcin Wojtas 	if (ENETC_MDIO_RD4(regs, mdio_base, ENETC_MDIO_CFG) & MDIO_CFG_RD_ER)
10559061c7eSMarcin Wojtas 		return (ENXIO);
10659061c7eSMarcin Wojtas 
10759061c7eSMarcin Wojtas 	return (MDIO_DATA(ENETC_MDIO_RD4(regs, mdio_base, ENETC_MDIO_DATA)));
10859061c7eSMarcin Wojtas }
10959061c7eSMarcin Wojtas 
11059061c7eSMarcin Wojtas int
enetc_mdio_write(struct resource * regs,int mdio_base,int phy,int reg,int data)11159061c7eSMarcin Wojtas enetc_mdio_write(struct resource *regs, int mdio_base, int phy, int reg,
11259061c7eSMarcin Wojtas     int data)
11359061c7eSMarcin Wojtas {
11459061c7eSMarcin Wojtas 	uint32_t mdio_cfg, mdio_ctl;
11559061c7eSMarcin Wojtas 	uint16_t dev_addr;
11659061c7eSMarcin Wojtas 
11759061c7eSMarcin Wojtas 	mdio_cfg = MDIO_CFG_CLKDIV(ENETC_MDC_DIV) | MDIO_CFG_NEG;
11859061c7eSMarcin Wojtas 	if (reg & MII_ADDR_C45) {
11959061c7eSMarcin Wojtas 		/* clause 45 */
12059061c7eSMarcin Wojtas 		dev_addr = (reg >> 16) & 0x1f;
12159061c7eSMarcin Wojtas 		mdio_cfg |= MDIO_CFG_ENC45;
12259061c7eSMarcin Wojtas 	} else {
12359061c7eSMarcin Wojtas 		/* clause 22 */
12459061c7eSMarcin Wojtas 		dev_addr = reg & 0x1f;
12559061c7eSMarcin Wojtas 		mdio_cfg &= ~MDIO_CFG_ENC45;
12659061c7eSMarcin Wojtas 	}
12759061c7eSMarcin Wojtas 
12859061c7eSMarcin Wojtas 	ENETC_MDIO_WR4(regs, mdio_base, ENETC_MDIO_CFG, mdio_cfg);
12959061c7eSMarcin Wojtas 
13059061c7eSMarcin Wojtas 	if (enetc_mdio_wait(regs, mdio_base) == ETIMEDOUT)
13159061c7eSMarcin Wojtas 		return (EIO);
13259061c7eSMarcin Wojtas 
13359061c7eSMarcin Wojtas 	/* Set port and device addr. */
13459061c7eSMarcin Wojtas 	mdio_ctl = MDIO_CTL_PORT_ADDR(phy) | MDIO_CTL_DEV_ADDR(dev_addr);
13559061c7eSMarcin Wojtas 	ENETC_MDIO_WR4(regs, mdio_base, ENETC_MDIO_CTL, mdio_ctl);
13659061c7eSMarcin Wojtas 
13759061c7eSMarcin Wojtas 	/* Set the register address. */
13859061c7eSMarcin Wojtas 	if (reg & MII_ADDR_C45) {
13959061c7eSMarcin Wojtas 		ENETC_MDIO_WR4(regs, mdio_base, ENETC_MDIO_ADDR, reg & 0xffff);
14059061c7eSMarcin Wojtas 
14159061c7eSMarcin Wojtas 		if (enetc_mdio_wait(regs, mdio_base) == ETIMEDOUT)
14259061c7eSMarcin Wojtas 			return (EIO);
14359061c7eSMarcin Wojtas 	}
14459061c7eSMarcin Wojtas 
14559061c7eSMarcin Wojtas 	/* Write the value. */
14659061c7eSMarcin Wojtas 	ENETC_MDIO_WR4(regs, mdio_base, ENETC_MDIO_DATA, MDIO_DATA(data));
14759061c7eSMarcin Wojtas 
14859061c7eSMarcin Wojtas 	if (enetc_mdio_wait(regs, mdio_base) == ETIMEDOUT)
14959061c7eSMarcin Wojtas 		return (EIO);
15059061c7eSMarcin Wojtas 
15159061c7eSMarcin Wojtas 	return (0);
15259061c7eSMarcin Wojtas }
153