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