uboot/drivers/net/mdio_mux_mmioreg.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * (C) Copyright 2021 BayLibre, SAS
   4 * Author: Neil Armstrong <narmstrong@baylibre.com>
   5 *
   6 * Based on linux/drivers/net/phy/mdio-mux-mmioreg.c :
   7 *   Copyright 2012 Freescale Semiconductor, Inc.
   8 */
   9
  10#include <dm.h>
  11#include <errno.h>
  12#include <log.h>
  13#include <miiphy.h>
  14#include <linux/io.h>
  15
  16struct mdio_mux_mmioreg_priv {
  17        struct udevice *chip;
  18        phys_addr_t phys;
  19        unsigned int iosize;
  20        unsigned int mask;
  21};
  22
  23static int mdio_mux_mmioreg_select(struct udevice *mux, int cur, int sel)
  24{
  25        struct mdio_mux_mmioreg_priv *priv = dev_get_priv(mux);
  26
  27        debug("%s: %x -> %x\n", __func__, (u32)cur, (u32)sel);
  28
  29        /* if last selection didn't change we're good to go */
  30        if (cur == sel)
  31                return 0;
  32
  33        switch (priv->iosize) {
  34        case sizeof(u8): {
  35                u8 x, y;
  36
  37                x = ioread8((void *)priv->phys);
  38                y = (x & ~priv->mask) | (u32)sel;
  39                if (x != y) {
  40                        iowrite8((x & ~priv->mask) | sel, (void *)priv->phys);
  41                        debug("%s: %02x -> %02x\n", __func__, x, y);
  42                }
  43
  44                break;
  45        }
  46        case sizeof(u16): {
  47                u16 x, y;
  48
  49                x = ioread16((void *)priv->phys);
  50                y = (x & ~priv->mask) | (u32)sel;
  51                if (x != y) {
  52                        iowrite16((x & ~priv->mask) | sel, (void *)priv->phys);
  53                        debug("%s: %04x -> %04x\n", __func__, x, y);
  54                }
  55
  56                break;
  57        }
  58        case sizeof(u32): {
  59                u32 x, y;
  60
  61                x = ioread32((void *)priv->phys);
  62                y = (x & ~priv->mask) | (u32)sel;
  63                if (x != y) {
  64                        iowrite32((x & ~priv->mask) | sel, (void *)priv->phys);
  65                        debug("%s: %08x -> %08x\n", __func__, x, y);
  66                }
  67
  68                break;
  69        }
  70        }
  71
  72        return 0;
  73}
  74
  75static const struct mdio_mux_ops mdio_mux_mmioreg_ops = {
  76        .select = mdio_mux_mmioreg_select,
  77};
  78
  79static int mdio_mux_mmioreg_probe(struct udevice *dev)
  80{
  81        struct mdio_mux_mmioreg_priv *priv = dev_get_priv(dev);
  82        phys_addr_t reg_base, reg_size;
  83        u32 reg_mask;
  84        int err;
  85
  86        reg_base = ofnode_get_addr_size_index(dev_ofnode(dev), 0, &reg_size);
  87        if (reg_base == FDT_ADDR_T_NONE)
  88                return -EINVAL;
  89
  90        if (reg_size != sizeof(u8) &&
  91            reg_size != sizeof(u16) &&
  92            reg_size != sizeof(u32)) {
  93                printf("%s: only 8/16/32-bit registers are supported\n", __func__);
  94                return -EINVAL;
  95        }
  96
  97        err = dev_read_u32(dev, "mux-mask", &reg_mask);
  98        if (err) {
  99                debug("%s: error reading mux-mask property\n", __func__);
 100                return err;
 101        }
 102
 103        if (reg_mask >= BIT(reg_size * 8)) {
 104                printf("%s: mask doesn't fix in register width\n", __func__);
 105                return -EINVAL;
 106        }
 107
 108        priv->phys = reg_base;
 109        priv->iosize = reg_size;
 110        priv->mask = reg_mask;
 111
 112        debug("%s: %llx@%lld / %x\n", __func__, reg_base, reg_size, reg_mask);
 113
 114        return 0;
 115}
 116
 117static const struct udevice_id mdio_mux_mmioreg_ids[] = {
 118        { .compatible = "mdio-mux-mmioreg" },
 119        { }
 120};
 121
 122U_BOOT_DRIVER(mdio_mux_mmioreg) = {
 123        .name           = "mdio_mux_mmioreg",
 124        .id             = UCLASS_MDIO_MUX,
 125        .of_match       = mdio_mux_mmioreg_ids,
 126        .probe          = mdio_mux_mmioreg_probe,
 127        .ops            = &mdio_mux_mmioreg_ops,
 128        .priv_auto      = sizeof(struct mdio_mux_mmioreg_priv),
 129};
 130