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