linux/drivers/net/ethernet/mediatek/mtk_eth_path.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2// Copyright (c) 2018-2019 MediaTek Inc.
   3
   4/* A library for configuring path from GMAC/GDM to target PHY
   5 *
   6 * Author: Sean Wang <sean.wang@mediatek.com>
   7 *
   8 */
   9
  10#include <linux/phy.h>
  11#include <linux/regmap.h>
  12
  13#include "mtk_eth_soc.h"
  14
  15struct mtk_eth_muxc {
  16        const char      *name;
  17        int             cap_bit;
  18        int             (*set_path)(struct mtk_eth *eth, int path);
  19};
  20
  21static const char *mtk_eth_path_name(int path)
  22{
  23        switch (path) {
  24        case MTK_ETH_PATH_GMAC1_RGMII:
  25                return "gmac1_rgmii";
  26        case MTK_ETH_PATH_GMAC1_TRGMII:
  27                return "gmac1_trgmii";
  28        case MTK_ETH_PATH_GMAC1_SGMII:
  29                return "gmac1_sgmii";
  30        case MTK_ETH_PATH_GMAC2_RGMII:
  31                return "gmac2_rgmii";
  32        case MTK_ETH_PATH_GMAC2_SGMII:
  33                return "gmac2_sgmii";
  34        case MTK_ETH_PATH_GMAC2_GEPHY:
  35                return "gmac2_gephy";
  36        case MTK_ETH_PATH_GDM1_ESW:
  37                return "gdm1_esw";
  38        default:
  39                return "unknown path";
  40        }
  41}
  42
  43static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, int path)
  44{
  45        bool updated = true;
  46        u32 val, mask, set;
  47
  48        switch (path) {
  49        case MTK_ETH_PATH_GMAC1_SGMII:
  50                mask = ~(u32)MTK_MUX_TO_ESW;
  51                set = 0;
  52                break;
  53        case MTK_ETH_PATH_GDM1_ESW:
  54                mask = ~(u32)MTK_MUX_TO_ESW;
  55                set = MTK_MUX_TO_ESW;
  56                break;
  57        default:
  58                updated = false;
  59                break;
  60        };
  61
  62        if (updated) {
  63                val = mtk_r32(eth, MTK_MAC_MISC);
  64                val = (val & mask) | set;
  65                mtk_w32(eth, val, MTK_MAC_MISC);
  66        }
  67
  68        dev_dbg(eth->dev, "path %s in %s updated = %d\n",
  69                mtk_eth_path_name(path), __func__, updated);
  70
  71        return 0;
  72}
  73
  74static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, int path)
  75{
  76        unsigned int val = 0;
  77        bool updated = true;
  78
  79        switch (path) {
  80        case MTK_ETH_PATH_GMAC2_GEPHY:
  81                val = ~(u32)GEPHY_MAC_SEL;
  82                break;
  83        default:
  84                updated = false;
  85                break;
  86        }
  87
  88        if (updated)
  89                regmap_update_bits(eth->infra, INFRA_MISC2, GEPHY_MAC_SEL, val);
  90
  91        dev_dbg(eth->dev, "path %s in %s updated = %d\n",
  92                mtk_eth_path_name(path), __func__, updated);
  93
  94        return 0;
  95}
  96
  97static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, int path)
  98{
  99        unsigned int val = 0;
 100        bool updated = true;
 101
 102        switch (path) {
 103        case MTK_ETH_PATH_GMAC2_SGMII:
 104                val = CO_QPHY_SEL;
 105                break;
 106        default:
 107                updated = false;
 108                break;
 109        }
 110
 111        if (updated)
 112                regmap_update_bits(eth->infra, INFRA_MISC2, CO_QPHY_SEL, val);
 113
 114        dev_dbg(eth->dev, "path %s in %s updated = %d\n",
 115                mtk_eth_path_name(path), __func__, updated);
 116
 117        return 0;
 118}
 119
 120static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, int path)
 121{
 122        unsigned int val = 0;
 123        bool updated = true;
 124
 125        switch (path) {
 126        case MTK_ETH_PATH_GMAC1_SGMII:
 127                val = SYSCFG0_SGMII_GMAC1;
 128                break;
 129        case MTK_ETH_PATH_GMAC2_SGMII:
 130                val = SYSCFG0_SGMII_GMAC2;
 131                break;
 132        case MTK_ETH_PATH_GMAC1_RGMII:
 133        case MTK_ETH_PATH_GMAC2_RGMII:
 134                regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
 135                val &= SYSCFG0_SGMII_MASK;
 136
 137                if ((path == MTK_GMAC1_RGMII && val == SYSCFG0_SGMII_GMAC1) ||
 138                    (path == MTK_GMAC2_RGMII && val == SYSCFG0_SGMII_GMAC2))
 139                        val = 0;
 140                else
 141                        updated = false;
 142                break;
 143        default:
 144                updated = false;
 145                break;
 146        };
 147
 148        if (updated)
 149                regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
 150                                   SYSCFG0_SGMII_MASK, val);
 151
 152        dev_dbg(eth->dev, "path %s in %s updated = %d\n",
 153                mtk_eth_path_name(path), __func__, updated);
 154
 155        return 0;
 156}
 157
 158static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, int path)
 159{
 160        unsigned int val = 0;
 161        bool updated = true;
 162
 163        regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
 164
 165        switch (path) {
 166        case MTK_ETH_PATH_GMAC1_SGMII:
 167                val |= SYSCFG0_SGMII_GMAC1_V2;
 168                break;
 169        case MTK_ETH_PATH_GMAC2_GEPHY:
 170                val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2;
 171                break;
 172        case MTK_ETH_PATH_GMAC2_SGMII:
 173                val |= SYSCFG0_SGMII_GMAC2_V2;
 174                break;
 175        default:
 176                updated = false;
 177        };
 178
 179        if (updated)
 180                regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
 181                                   SYSCFG0_SGMII_MASK, val);
 182
 183        dev_dbg(eth->dev, "path %s in %s updated = %d\n",
 184                mtk_eth_path_name(path), __func__, updated);
 185
 186        return 0;
 187}
 188
 189static const struct mtk_eth_muxc mtk_eth_muxc[] = {
 190        {
 191                .name = "mux_gdm1_to_gmac1_esw",
 192                .cap_bit = MTK_ETH_MUX_GDM1_TO_GMAC1_ESW,
 193                .set_path = set_mux_gdm1_to_gmac1_esw,
 194        }, {
 195                .name = "mux_gmac2_gmac0_to_gephy",
 196                .cap_bit = MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY,
 197                .set_path = set_mux_gmac2_gmac0_to_gephy,
 198        }, {
 199                .name = "mux_u3_gmac2_to_qphy",
 200                .cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY,
 201                .set_path = set_mux_u3_gmac2_to_qphy,
 202        }, {
 203                .name = "mux_gmac1_gmac2_to_sgmii_rgmii",
 204                .cap_bit = MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII,
 205                .set_path = set_mux_gmac1_gmac2_to_sgmii_rgmii,
 206        }, {
 207                .name = "mux_gmac12_to_gephy_sgmii",
 208                .cap_bit = MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII,
 209                .set_path = set_mux_gmac12_to_gephy_sgmii,
 210        },
 211};
 212
 213static int mtk_eth_mux_setup(struct mtk_eth *eth, int path)
 214{
 215        int i, err = 0;
 216
 217        if (!MTK_HAS_CAPS(eth->soc->caps, path)) {
 218                dev_err(eth->dev, "path %s isn't support on the SoC\n",
 219                        mtk_eth_path_name(path));
 220                return -EINVAL;
 221        }
 222
 223        if (!MTK_HAS_CAPS(eth->soc->caps, MTK_MUX))
 224                return 0;
 225
 226        /* Setup MUX in path fabric */
 227        for (i = 0; i < ARRAY_SIZE(mtk_eth_muxc); i++) {
 228                if (MTK_HAS_CAPS(eth->soc->caps, mtk_eth_muxc[i].cap_bit)) {
 229                        err = mtk_eth_muxc[i].set_path(eth, path);
 230                        if (err)
 231                                goto out;
 232                } else {
 233                        dev_dbg(eth->dev, "mux %s isn't present on the SoC\n",
 234                                mtk_eth_muxc[i].name);
 235                }
 236        }
 237
 238out:
 239        return err;
 240}
 241
 242int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id)
 243{
 244        int err, path;
 245
 246        path = (mac_id == 0) ?  MTK_ETH_PATH_GMAC1_SGMII :
 247                                MTK_ETH_PATH_GMAC2_SGMII;
 248
 249        /* Setup proper MUXes along the path */
 250        err = mtk_eth_mux_setup(eth, path);
 251        if (err)
 252                return err;
 253
 254        return 0;
 255}
 256
 257int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id)
 258{
 259        int err, path = 0;
 260
 261        if (mac_id == 1)
 262                path = MTK_ETH_PATH_GMAC2_GEPHY;
 263
 264        if (!path)
 265                return -EINVAL;
 266
 267        /* Setup proper MUXes along the path */
 268        err = mtk_eth_mux_setup(eth, path);
 269        if (err)
 270                return err;
 271
 272        return 0;
 273}
 274
 275int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id)
 276{
 277        int err, path;
 278
 279        path = (mac_id == 0) ?  MTK_ETH_PATH_GMAC1_RGMII :
 280                                MTK_ETH_PATH_GMAC2_RGMII;
 281
 282        /* Setup proper MUXes along the path */
 283        err = mtk_eth_mux_setup(eth, path);
 284        if (err)
 285                return err;
 286
 287        return 0;
 288}
 289
 290