uboot/drivers/phy/marvell/comphy_core.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2015-2016 Marvell International Ltd.
   4 *
   5 * Copyright (C) 2016 Stefan Roese <sr@denx.de>
   6 */
   7
   8#include <common.h>
   9#include <dm.h>
  10#include <fdtdec.h>
  11#include <linux/errno.h>
  12#include <asm/io.h>
  13
  14#include "comphy.h"
  15
  16#define COMPHY_MAX_CHIP 4
  17
  18DECLARE_GLOBAL_DATA_PTR;
  19
  20static char *get_speed_string(u32 speed)
  21{
  22        char *speed_strings[] = {"1.25 Gbps", "1.5 Gbps", "2.5 Gbps",
  23                                 "3.0 Gbps", "3.125 Gbps", "5 Gbps", "6 Gbps",
  24                                 "6.25 Gbps", "10.31 Gbps" };
  25
  26        if (speed < 0 || speed > PHY_SPEED_MAX)
  27                return "invalid";
  28
  29        return speed_strings[speed];
  30}
  31
  32static char *get_type_string(u32 type)
  33{
  34        char *type_strings[] = {"UNCONNECTED", "PEX0", "PEX1", "PEX2", "PEX3",
  35                                "SATA0", "SATA1", "SATA2", "SATA3", "SGMII0",
  36                                "SGMII1", "SGMII2", "SGMII3", "QSGMII",
  37                                "USB3_HOST0", "USB3_HOST1", "USB3_DEVICE",
  38                                "XAUI0", "XAUI1", "XAUI2", "XAUI3",
  39                                "RXAUI0", "RXAUI1", "SFI", "IGNORE"};
  40
  41        if (type < 0 || type > PHY_TYPE_MAX)
  42                return "invalid";
  43
  44        return type_strings[type];
  45}
  46
  47void reg_set(void __iomem *addr, u32 data, u32 mask)
  48{
  49        debug("Write to address = %#010lx, data = %#010x (mask = %#010x) - ",
  50              (unsigned long)addr, data, mask);
  51        debug("old value = %#010x ==> ", readl(addr));
  52        reg_set_silent(addr, data, mask);
  53        debug("new value %#010x\n", readl(addr));
  54}
  55
  56void reg_set_silent(void __iomem *addr, u32 data, u32 mask)
  57{
  58        u32 reg_data;
  59
  60        reg_data = readl(addr);
  61        reg_data &= ~mask;
  62        reg_data |= data;
  63        writel(reg_data, addr);
  64}
  65
  66void reg_set16(void __iomem *addr, u16 data, u16 mask)
  67{
  68        debug("Write to address = %#010lx, data = %#06x (mask = %#06x) - ",
  69              (unsigned long)addr, data, mask);
  70        debug("old value = %#06x ==> ", readw(addr));
  71        reg_set_silent16(addr, data, mask);
  72        debug("new value %#06x\n", readw(addr));
  73}
  74
  75void reg_set_silent16(void __iomem *addr, u16 data, u16 mask)
  76{
  77        u16 reg_data;
  78
  79        reg_data = readw(addr);
  80        reg_data &= ~mask;
  81        reg_data |= data;
  82        writew(reg_data, addr);
  83}
  84
  85void comphy_print(struct chip_serdes_phy_config *chip_cfg,
  86                  struct comphy_map *comphy_map_data)
  87{
  88        u32 lane;
  89
  90        for (lane = 0; lane < chip_cfg->comphy_lanes_count;
  91             lane++, comphy_map_data++) {
  92                if (comphy_map_data->speed == PHY_SPEED_INVALID) {
  93                        printf("Comphy-%d: %-13s\n", lane,
  94                               get_type_string(comphy_map_data->type));
  95                } else {
  96                        printf("Comphy-%d: %-13s %-10s\n", lane,
  97                               get_type_string(comphy_map_data->type),
  98                               get_speed_string(comphy_map_data->speed));
  99                }
 100        }
 101}
 102
 103static int comphy_probe(struct udevice *dev)
 104{
 105        const void *blob = gd->fdt_blob;
 106        int node = dev_of_offset(dev);
 107        struct chip_serdes_phy_config *chip_cfg = dev_get_priv(dev);
 108        struct comphy_map comphy_map_data[MAX_LANE_OPTIONS];
 109        int subnode;
 110        int lane;
 111        int last_idx = 0;
 112        static int current_idx;
 113
 114        /* Save base addresses for later use */
 115        chip_cfg->comphy_base_addr = (void *)devfdt_get_addr_index(dev, 0);
 116        if (IS_ERR(chip_cfg->comphy_base_addr))
 117                return PTR_ERR(chip_cfg->comphy_base_addr);
 118
 119        chip_cfg->hpipe3_base_addr = (void *)devfdt_get_addr_index(dev, 1);
 120        if (IS_ERR(chip_cfg->hpipe3_base_addr))
 121                return PTR_ERR(chip_cfg->hpipe3_base_addr);
 122
 123        chip_cfg->comphy_lanes_count = fdtdec_get_int(blob, node,
 124                                                      "max-lanes", 0);
 125        if (chip_cfg->comphy_lanes_count <= 0) {
 126                dev_err(&dev->dev, "comphy max lanes is wrong\n");
 127                return -EINVAL;
 128        }
 129
 130        chip_cfg->comphy_mux_bitcount = fdtdec_get_int(blob, node,
 131                                                       "mux-bitcount", 0);
 132        if (chip_cfg->comphy_mux_bitcount <= 0) {
 133                dev_err(&dev->dev, "comphy mux bit count is wrong\n");
 134                return -EINVAL;
 135        }
 136
 137        if (device_is_compatible(dev, "marvell,comphy-armada-3700"))
 138                chip_cfg->ptr_comphy_chip_init = comphy_a3700_init;
 139
 140        if (device_is_compatible(dev, "marvell,comphy-cp110"))
 141                chip_cfg->ptr_comphy_chip_init = comphy_cp110_init;
 142
 143        /*
 144         * Bail out if no chip_init function is defined, e.g. no
 145         * compatible node is found
 146         */
 147        if (!chip_cfg->ptr_comphy_chip_init) {
 148                dev_err(&dev->dev, "comphy: No compatible DT node found\n");
 149                return -ENODEV;
 150        }
 151
 152        lane = 0;
 153        fdt_for_each_subnode(subnode, blob, node) {
 154                /* Skip disabled ports */
 155                if (!fdtdec_get_is_enabled(blob, subnode))
 156                        continue;
 157
 158                comphy_map_data[lane].speed = fdtdec_get_int(
 159                        blob, subnode, "phy-speed", PHY_TYPE_INVALID);
 160                comphy_map_data[lane].type = fdtdec_get_int(
 161                        blob, subnode, "phy-type", PHY_SPEED_INVALID);
 162                comphy_map_data[lane].invert = fdtdec_get_int(
 163                        blob, subnode, "phy-invert", PHY_POLARITY_NO_INVERT);
 164                comphy_map_data[lane].clk_src = fdtdec_get_bool(blob, subnode,
 165                                                                "clk-src");
 166                comphy_map_data[lane].end_point = fdtdec_get_bool(blob, subnode,
 167                                                                  "end_point");
 168                if (comphy_map_data[lane].type == PHY_TYPE_INVALID) {
 169                        printf("no phy type for lane %d, setting lane as unconnected\n",
 170                               lane + 1);
 171                }
 172
 173                lane++;
 174        }
 175
 176        /* Save CP index for MultiCP devices (A8K) */
 177        chip_cfg->cp_index = current_idx++;
 178        /* PHY power UP sequence */
 179        chip_cfg->ptr_comphy_chip_init(chip_cfg, comphy_map_data);
 180        /* PHY print SerDes status */
 181        if (of_machine_is_compatible("marvell,armada8040"))
 182                printf("Comphy chip #%d:\n", chip_cfg->cp_index);
 183        comphy_print(chip_cfg, comphy_map_data);
 184
 185        /*
 186         * Only run the dedicated PHY init code once, in the last PHY init call
 187         */
 188        if (of_machine_is_compatible("marvell,armada8040"))
 189                last_idx = 1;
 190
 191        if (chip_cfg->cp_index == last_idx) {
 192                /* Initialize dedicated PHYs (not muxed SerDes lanes) */
 193                comphy_dedicated_phys_init();
 194        }
 195
 196        return 0;
 197}
 198
 199static const struct udevice_id comphy_ids[] = {
 200        { .compatible = "marvell,mvebu-comphy" },
 201        { }
 202};
 203
 204U_BOOT_DRIVER(mvebu_comphy) = {
 205        .name   = "mvebu_comphy",
 206        .id     = UCLASS_MISC,
 207        .of_match = comphy_ids,
 208        .probe  = comphy_probe,
 209        .priv_auto_alloc_size = sizeof(struct chip_serdes_phy_config),
 210};
 211