uboot/drivers/net/mdio_mux_meson_g12a.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
   7#include <dm.h>
   8#include <errno.h>
   9#include <log.h>
  10#include <miiphy.h>
  11#include <asm/io.h>
  12#include <linux/bitfield.h>
  13
  14#define ETH_PLL_STS             0x40
  15#define ETH_PLL_CTL0            0x44
  16#define  PLL_CTL0_LOCK_DIG      BIT(30)
  17#define  PLL_CTL0_RST           BIT(29)
  18#define  PLL_CTL0_EN            BIT(28)
  19#define  PLL_CTL0_SEL           BIT(23)
  20#define  PLL_CTL0_N             GENMASK(14, 10)
  21#define  PLL_CTL0_M             GENMASK(8, 0)
  22#define  PLL_LOCK_TIMEOUT       1000000
  23#define  PLL_MUX_NUM_PARENT     2
  24#define ETH_PLL_CTL1            0x48
  25#define ETH_PLL_CTL2            0x4c
  26#define ETH_PLL_CTL3            0x50
  27#define ETH_PLL_CTL4            0x54
  28#define ETH_PLL_CTL5            0x58
  29#define ETH_PLL_CTL6            0x5c
  30#define ETH_PLL_CTL7            0x60
  31
  32#define ETH_PHY_CNTL0           0x80
  33#define   EPHY_G12A_ID          0x33010180
  34#define ETH_PHY_CNTL1           0x84
  35#define  PHY_CNTL1_ST_MODE      GENMASK(2, 0)
  36#define  PHY_CNTL1_ST_PHYADD    GENMASK(7, 3)
  37#define   EPHY_DFLT_ADD         8
  38#define  PHY_CNTL1_MII_MODE     GENMASK(15, 14)
  39#define   EPHY_MODE_RMII        0x1
  40#define  PHY_CNTL1_CLK_EN       BIT(16)
  41#define  PHY_CNTL1_CLKFREQ      BIT(17)
  42#define  PHY_CNTL1_PHY_ENB      BIT(18)
  43#define ETH_PHY_CNTL2           0x88
  44#define  PHY_CNTL2_USE_INTERNAL BIT(5)
  45#define  PHY_CNTL2_SMI_SRC_MAC  BIT(6)
  46#define  PHY_CNTL2_RX_CLK_EPHY  BIT(9)
  47
  48#define MESON_G12A_MDIO_EXTERNAL_ID 0
  49#define MESON_G12A_MDIO_INTERNAL_ID 1
  50
  51struct mdio_mux_meson_g12a_priv {
  52        struct udevice *chip;
  53        phys_addr_t phys;
  54};
  55
  56static int meson_g12a_ephy_pll_init(struct mdio_mux_meson_g12a_priv *priv)
  57{
  58        /* Fire up the PHY PLL */
  59        writel(0x29c0040a, priv->phys + ETH_PLL_CTL0);
  60        writel(0x927e0000, priv->phys + ETH_PLL_CTL1);
  61        writel(0xac5f49e5, priv->phys + ETH_PLL_CTL2);
  62        writel(0x00000000, priv->phys + ETH_PLL_CTL3);
  63        writel(0x00000000, priv->phys + ETH_PLL_CTL4);
  64        writel(0x20200000, priv->phys + ETH_PLL_CTL5);
  65        writel(0x0000c002, priv->phys + ETH_PLL_CTL6);
  66        writel(0x00000023, priv->phys + ETH_PLL_CTL7);
  67        writel(0x39c0040a, priv->phys + ETH_PLL_CTL0);
  68        writel(0x19c0040a, priv->phys + ETH_PLL_CTL0);
  69
  70        return 0;
  71}
  72
  73static int meson_g12a_enable_internal_mdio(struct mdio_mux_meson_g12a_priv *priv)
  74{
  75        /* Initialize ephy control */
  76        writel(EPHY_G12A_ID, priv->phys + ETH_PHY_CNTL0);
  77        writel(FIELD_PREP(PHY_CNTL1_ST_MODE, 3) |
  78               FIELD_PREP(PHY_CNTL1_ST_PHYADD, EPHY_DFLT_ADD) |
  79               FIELD_PREP(PHY_CNTL1_MII_MODE, EPHY_MODE_RMII) |
  80               PHY_CNTL1_CLK_EN |
  81               PHY_CNTL1_CLKFREQ |
  82               PHY_CNTL1_PHY_ENB,
  83               priv->phys + ETH_PHY_CNTL1);
  84        writel(PHY_CNTL2_USE_INTERNAL |
  85               PHY_CNTL2_SMI_SRC_MAC |
  86               PHY_CNTL2_RX_CLK_EPHY,
  87               priv->phys + ETH_PHY_CNTL2);
  88
  89        return 0;
  90}
  91
  92static int meson_g12a_enable_external_mdio(struct mdio_mux_meson_g12a_priv *priv)
  93{
  94        /* Reset the mdio bus mux */
  95        writel(0x0, priv->phys + ETH_PHY_CNTL2);
  96
  97        return 0;
  98}
  99
 100static int mdio_mux_meson_g12a_select(struct udevice *mux, int cur, int sel)
 101{
 102        struct mdio_mux_meson_g12a_priv *priv = dev_get_priv(mux);
 103
 104        debug("%s: %x -> %x\n", __func__, (u32)cur, (u32)sel);
 105
 106        /* if last selection didn't change we're good to go */
 107        if (cur == sel)
 108                return 0;
 109
 110        switch (sel) {
 111        case MESON_G12A_MDIO_EXTERNAL_ID:
 112                return meson_g12a_enable_external_mdio(priv);
 113        case MESON_G12A_MDIO_INTERNAL_ID:
 114                return meson_g12a_enable_internal_mdio(priv);
 115        default:
 116                return -EINVAL;
 117        }
 118
 119        return 0;
 120}
 121
 122static const struct mdio_mux_ops mdio_mux_meson_g12a_ops = {
 123        .select = mdio_mux_meson_g12a_select,
 124};
 125
 126static int mdio_mux_meson_g12a_probe(struct udevice *dev)
 127{
 128        struct mdio_mux_meson_g12a_priv *priv = dev_get_priv(dev);
 129
 130        priv->phys = dev_read_addr(dev);
 131
 132        meson_g12a_ephy_pll_init(priv);
 133
 134        return 0;
 135}
 136
 137static const struct udevice_id mdio_mux_meson_g12a_ids[] = {
 138        { .compatible = "amlogic,g12a-mdio-mux" },
 139        { }
 140};
 141
 142U_BOOT_DRIVER(mdio_mux_meson_g12a) = {
 143        .name           = "mdio_mux_meson_g12a",
 144        .id             = UCLASS_MDIO_MUX,
 145        .of_match       = mdio_mux_meson_g12a_ids,
 146        .probe          = mdio_mux_meson_g12a_probe,
 147        .ops            = &mdio_mux_meson_g12a_ops,
 148        .priv_auto      = sizeof(struct mdio_mux_meson_g12a_priv),
 149};
 150