uboot/drivers/net/pic32_mdio.c
<<
>>
Prefs
   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
  17static 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(__func__, &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(__func__, &mii_regs->mind.raw, MIIMIND_BUSY,
  40                     false, CONFIG_SYS_HZ, true);
  41
  42        return 0;
  43}
  44
  45static 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(__func__, &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(__func__, &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
  77static 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(__func__, &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(__func__, &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(__func__, &mii_regs->mind.raw, MIIMIND_BUSY,
 100                     false, CONFIG_SYS_HZ, true);
 101        return 0;
 102}
 103
 104int 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