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