1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * pic32_mdio.c: PIC32 MDIO/MII driver, part of pic32_eth.c. 4 * 5 * Copyright 2015 Microchip Inc. 6 * Purna Chandra Mandal <purna.mandal@microchip.com> 7 */ 8 #include <common.h> 9 #include <phy.h> 10 #include <miiphy.h> 11 #include <errno.h> 12 #include <wait_bit.h> 13 #include <asm/io.h> 14 #include "pic32_eth.h" 15 16 static int pic32_mdio_write(struct mii_dev *bus, 17 int addr, int dev_addr, 18 int reg, u16 value) 19 { 20 u32 v; 21 struct pic32_mii_regs *mii_regs = bus->priv; 22 23 /* Wait for the previous operation to finish */ 24 wait_for_bit_le32(&mii_regs->mind.raw, MIIMIND_BUSY, 25 false, CONFIG_SYS_HZ, true); 26 27 /* Put phyaddr and regaddr into MIIMADD */ 28 v = (addr << MIIMADD_PHYADDR_SHIFT) | (reg & MIIMADD_REGADDR); 29 writel(v, &mii_regs->madr.raw); 30 31 /* Initiate a write command */ 32 writel(value, &mii_regs->mwtd.raw); 33 34 /* Wait 30 clock cycles for busy flag to be set */ 35 udelay(12); 36 37 /* Wait for write to complete */ 38 wait_for_bit_le32(&mii_regs->mind.raw, MIIMIND_BUSY, 39 false, CONFIG_SYS_HZ, true); 40 41 return 0; 42 } 43 44 static int pic32_mdio_read(struct mii_dev *bus, int addr, int devaddr, int reg) 45 { 46 u32 v; 47 struct pic32_mii_regs *mii_regs = bus->priv; 48 49 /* Wait for the previous operation to finish */ 50 wait_for_bit_le32(&mii_regs->mind.raw, MIIMIND_BUSY, 51 false, CONFIG_SYS_HZ, true); 52 53 /* Put phyaddr and regaddr into MIIMADD */ 54 v = (addr << MIIMADD_PHYADDR_SHIFT) | (reg & MIIMADD_REGADDR); 55 writel(v, &mii_regs->madr.raw); 56 57 /* Initiate a read command */ 58 writel(MIIMCMD_READ, &mii_regs->mcmd.raw); 59 60 /* Wait 30 clock cycles for busy flag to be set */ 61 udelay(12); 62 63 /* Wait for read to complete */ 64 wait_for_bit_le32(&mii_regs->mind.raw, 65 MIIMIND_NOTVALID | MIIMIND_BUSY, 66 false, CONFIG_SYS_HZ, false); 67 68 /* Clear the command register */ 69 writel(0, &mii_regs->mcmd.raw); 70 71 /* Grab the value read from the PHY */ 72 v = readl(&mii_regs->mrdd.raw); 73 return v; 74 } 75 76 static int pic32_mdio_reset(struct mii_dev *bus) 77 { 78 struct pic32_mii_regs *mii_regs = bus->priv; 79 80 /* Reset MII (due to new addresses) */ 81 writel(MIIMCFG_RSTMGMT, &mii_regs->mcfg.raw); 82 83 /* Wait for the operation to finish */ 84 wait_for_bit_le32(&mii_regs->mind.raw, MIIMIND_BUSY, 85 false, CONFIG_SYS_HZ, true); 86 87 /* Clear reset bit */ 88 writel(0, &mii_regs->mcfg); 89 90 /* Wait for the operation to finish */ 91 wait_for_bit_le32(&mii_regs->mind.raw, MIIMIND_BUSY, 92 false, CONFIG_SYS_HZ, true); 93 94 /* Set the MII Management Clock (MDC) - no faster than 2.5 MHz */ 95 writel(MIIMCFG_CLKSEL_DIV40, &mii_regs->mcfg.raw); 96 97 /* Wait for the operation to finish */ 98 wait_for_bit_le32(&mii_regs->mind.raw, MIIMIND_BUSY, 99 false, CONFIG_SYS_HZ, true); 100 return 0; 101 } 102 103 int pic32_mdio_init(const char *name, ulong ioaddr) 104 { 105 struct mii_dev *bus; 106 107 bus = mdio_alloc(); 108 if (!bus) { 109 printf("Failed to allocate PIC32-MDIO bus\n"); 110 return -ENOMEM; 111 } 112 113 bus->read = pic32_mdio_read; 114 bus->write = pic32_mdio_write; 115 bus->reset = pic32_mdio_reset; 116 strncpy(bus->name, name, sizeof(bus->name)); 117 bus->priv = (void *)ioaddr; 118 119 return mdio_register(bus); 120 } 121