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