linux/drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* 10G controller driver for Samsung SoCs
   3 *
   4 * Copyright (C) 2013 Samsung Electronics Co., Ltd.
   5 *              http://www.samsung.com
   6 *
   7 * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
   8 */
   9
  10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  11
  12#include <linux/export.h>
  13#include <linux/io.h>
  14#include <linux/netdevice.h>
  15#include <linux/phy.h>
  16
  17#include "sxgbe_common.h"
  18#include "sxgbe_reg.h"
  19
  20/* MAC core initialization */
  21static void sxgbe_core_init(void __iomem *ioaddr)
  22{
  23        u32 regval;
  24
  25        /* TX configuration */
  26        regval = readl(ioaddr + SXGBE_CORE_TX_CONFIG_REG);
  27        /* Other configurable parameters IFP, IPG, ISR, ISM
  28         * needs to be set if needed
  29         */
  30        regval |= SXGBE_TX_JABBER_DISABLE;
  31        writel(regval, ioaddr + SXGBE_CORE_TX_CONFIG_REG);
  32
  33        /* RX configuration */
  34        regval = readl(ioaddr + SXGBE_CORE_RX_CONFIG_REG);
  35        /* Other configurable parameters CST, SPEN, USP, GPSLCE
  36         * WD, LM, S2KP, HDSMS, GPSL, ELEN, ARPEN needs to be
  37         * set if needed
  38         */
  39        regval |= SXGBE_RX_JUMBPKT_ENABLE | SXGBE_RX_ACS_ENABLE;
  40        writel(regval, ioaddr + SXGBE_CORE_RX_CONFIG_REG);
  41}
  42
  43/* Dump MAC registers */
  44static void sxgbe_core_dump_regs(void __iomem *ioaddr)
  45{
  46}
  47
  48static int sxgbe_get_lpi_status(void __iomem *ioaddr, const u32 irq_status)
  49{
  50        int status = 0;
  51        int lpi_status;
  52
  53        /* Reading this register shall clear all the LPI status bits */
  54        lpi_status = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
  55
  56        if (lpi_status & LPI_CTRL_STATUS_TLPIEN)
  57                status |= TX_ENTRY_LPI_MODE;
  58        if (lpi_status & LPI_CTRL_STATUS_TLPIEX)
  59                status |= TX_EXIT_LPI_MODE;
  60        if (lpi_status & LPI_CTRL_STATUS_RLPIEN)
  61                status |= RX_ENTRY_LPI_MODE;
  62        if (lpi_status & LPI_CTRL_STATUS_RLPIEX)
  63                status |= RX_EXIT_LPI_MODE;
  64
  65        return status;
  66}
  67
  68/* Handle extra events on specific interrupts hw dependent */
  69static int sxgbe_core_host_irq_status(void __iomem *ioaddr,
  70                                      struct sxgbe_extra_stats *x)
  71{
  72        int irq_status, status = 0;
  73
  74        irq_status = readl(ioaddr + SXGBE_CORE_INT_STATUS_REG);
  75
  76        if (unlikely(irq_status & LPI_INT_STATUS))
  77                status |= sxgbe_get_lpi_status(ioaddr, irq_status);
  78
  79        return status;
  80}
  81
  82/* Set power management mode (e.g. magic frame) */
  83static void sxgbe_core_pmt(void __iomem *ioaddr, unsigned long mode)
  84{
  85}
  86
  87/* Set/Get Unicast MAC addresses */
  88static void sxgbe_core_set_umac_addr(void __iomem *ioaddr, unsigned char *addr,
  89                                     unsigned int reg_n)
  90{
  91        u32 high_word, low_word;
  92
  93        high_word = (addr[5] << 8) | (addr[4]);
  94        low_word = (addr[3] << 24) | (addr[2] << 16) |
  95                   (addr[1] << 8) | (addr[0]);
  96        writel(high_word, ioaddr + SXGBE_CORE_ADD_HIGHOFFSET(reg_n));
  97        writel(low_word, ioaddr + SXGBE_CORE_ADD_LOWOFFSET(reg_n));
  98}
  99
 100static void sxgbe_core_get_umac_addr(void __iomem *ioaddr, unsigned char *addr,
 101                                     unsigned int reg_n)
 102{
 103        u32 high_word, low_word;
 104
 105        high_word = readl(ioaddr + SXGBE_CORE_ADD_HIGHOFFSET(reg_n));
 106        low_word = readl(ioaddr + SXGBE_CORE_ADD_LOWOFFSET(reg_n));
 107
 108        /* extract and assign address */
 109        addr[5] = (high_word & 0x0000FF00) >> 8;
 110        addr[4] = (high_word & 0x000000FF);
 111        addr[3] = (low_word & 0xFF000000) >> 24;
 112        addr[2] = (low_word & 0x00FF0000) >> 16;
 113        addr[1] = (low_word & 0x0000FF00) >> 8;
 114        addr[0] = (low_word & 0x000000FF);
 115}
 116
 117static void sxgbe_enable_tx(void __iomem *ioaddr, bool enable)
 118{
 119        u32 tx_config;
 120
 121        tx_config = readl(ioaddr + SXGBE_CORE_TX_CONFIG_REG);
 122        tx_config &= ~SXGBE_TX_ENABLE;
 123
 124        if (enable)
 125                tx_config |= SXGBE_TX_ENABLE;
 126        writel(tx_config, ioaddr + SXGBE_CORE_TX_CONFIG_REG);
 127}
 128
 129static void sxgbe_enable_rx(void __iomem *ioaddr, bool enable)
 130{
 131        u32 rx_config;
 132
 133        rx_config = readl(ioaddr + SXGBE_CORE_RX_CONFIG_REG);
 134        rx_config &= ~SXGBE_RX_ENABLE;
 135
 136        if (enable)
 137                rx_config |= SXGBE_RX_ENABLE;
 138        writel(rx_config, ioaddr + SXGBE_CORE_RX_CONFIG_REG);
 139}
 140
 141static int sxgbe_get_controller_version(void __iomem *ioaddr)
 142{
 143        return readl(ioaddr + SXGBE_CORE_VERSION_REG);
 144}
 145
 146/* If supported then get the optional core features */
 147static unsigned int sxgbe_get_hw_feature(void __iomem *ioaddr,
 148                                         unsigned char feature_index)
 149{
 150        return readl(ioaddr + (SXGBE_CORE_HW_FEA_REG(feature_index)));
 151}
 152
 153static void sxgbe_core_set_speed(void __iomem *ioaddr, unsigned char speed)
 154{
 155        u32 tx_cfg = readl(ioaddr + SXGBE_CORE_TX_CONFIG_REG);
 156
 157        /* clear the speed bits */
 158        tx_cfg &= ~0x60000000;
 159        tx_cfg |= (speed << SXGBE_SPEED_LSHIFT);
 160
 161        /* set the speed */
 162        writel(tx_cfg, ioaddr + SXGBE_CORE_TX_CONFIG_REG);
 163}
 164
 165static void sxgbe_core_enable_rxqueue(void __iomem *ioaddr, int queue_num)
 166{
 167        u32 reg_val;
 168
 169        reg_val = readl(ioaddr + SXGBE_CORE_RX_CTL0_REG);
 170        reg_val &= ~(SXGBE_CORE_RXQ_ENABLE_MASK << queue_num);
 171        reg_val |= SXGBE_CORE_RXQ_ENABLE;
 172        writel(reg_val, ioaddr + SXGBE_CORE_RX_CTL0_REG);
 173}
 174
 175static void sxgbe_core_disable_rxqueue(void __iomem *ioaddr, int queue_num)
 176{
 177        u32 reg_val;
 178
 179        reg_val = readl(ioaddr + SXGBE_CORE_RX_CTL0_REG);
 180        reg_val &= ~(SXGBE_CORE_RXQ_ENABLE_MASK << queue_num);
 181        reg_val |= SXGBE_CORE_RXQ_DISABLE;
 182        writel(reg_val, ioaddr + SXGBE_CORE_RX_CTL0_REG);
 183}
 184
 185static void  sxgbe_set_eee_mode(void __iomem *ioaddr)
 186{
 187        u32 ctrl;
 188
 189        /* Enable the LPI mode for transmit path with Tx automate bit set.
 190         * When Tx Automate bit is set, MAC internally handles the entry
 191         * to LPI mode after all outstanding and pending packets are
 192         * transmitted.
 193         */
 194        ctrl = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
 195        ctrl |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_TXA;
 196        writel(ctrl, ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
 197}
 198
 199static void  sxgbe_reset_eee_mode(void __iomem *ioaddr)
 200{
 201        u32 ctrl;
 202
 203        ctrl = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
 204        ctrl &= ~(LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_TXA);
 205        writel(ctrl, ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
 206}
 207
 208static void  sxgbe_set_eee_pls(void __iomem *ioaddr, const int link)
 209{
 210        u32 ctrl;
 211
 212        ctrl = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
 213
 214        /* If the PHY link status is UP then set PLS */
 215        if (link)
 216                ctrl |= LPI_CTRL_STATUS_PLS;
 217        else
 218                ctrl &= ~LPI_CTRL_STATUS_PLS;
 219
 220        writel(ctrl, ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
 221}
 222
 223static void  sxgbe_set_eee_timer(void __iomem *ioaddr,
 224                                 const int ls, const int tw)
 225{
 226        int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16);
 227
 228        /* Program the timers in the LPI timer control register:
 229         * LS: minimum time (ms) for which the link
 230         *  status from PHY should be ok before transmitting
 231         *  the LPI pattern.
 232         * TW: minimum time (us) for which the core waits
 233         *  after it has stopped transmitting the LPI pattern.
 234         */
 235        writel(value, ioaddr + SXGBE_CORE_LPI_TIMER_CTRL);
 236}
 237
 238static void sxgbe_enable_rx_csum(void __iomem *ioaddr)
 239{
 240        u32 ctrl;
 241
 242        ctrl = readl(ioaddr + SXGBE_CORE_RX_CONFIG_REG);
 243        ctrl |= SXGBE_RX_CSUMOFFLOAD_ENABLE;
 244        writel(ctrl, ioaddr + SXGBE_CORE_RX_CONFIG_REG);
 245}
 246
 247static void sxgbe_disable_rx_csum(void __iomem *ioaddr)
 248{
 249        u32 ctrl;
 250
 251        ctrl = readl(ioaddr + SXGBE_CORE_RX_CONFIG_REG);
 252        ctrl &= ~SXGBE_RX_CSUMOFFLOAD_ENABLE;
 253        writel(ctrl, ioaddr + SXGBE_CORE_RX_CONFIG_REG);
 254}
 255
 256static const struct sxgbe_core_ops core_ops = {
 257        .core_init              = sxgbe_core_init,
 258        .dump_regs              = sxgbe_core_dump_regs,
 259        .host_irq_status        = sxgbe_core_host_irq_status,
 260        .pmt                    = sxgbe_core_pmt,
 261        .set_umac_addr          = sxgbe_core_set_umac_addr,
 262        .get_umac_addr          = sxgbe_core_get_umac_addr,
 263        .enable_rx              = sxgbe_enable_rx,
 264        .enable_tx              = sxgbe_enable_tx,
 265        .get_controller_version = sxgbe_get_controller_version,
 266        .get_hw_feature         = sxgbe_get_hw_feature,
 267        .set_speed              = sxgbe_core_set_speed,
 268        .set_eee_mode           = sxgbe_set_eee_mode,
 269        .reset_eee_mode         = sxgbe_reset_eee_mode,
 270        .set_eee_timer          = sxgbe_set_eee_timer,
 271        .set_eee_pls            = sxgbe_set_eee_pls,
 272        .enable_rx_csum         = sxgbe_enable_rx_csum,
 273        .disable_rx_csum        = sxgbe_disable_rx_csum,
 274        .enable_rxqueue         = sxgbe_core_enable_rxqueue,
 275        .disable_rxqueue        = sxgbe_core_disable_rxqueue,
 276};
 277
 278const struct sxgbe_core_ops *sxgbe_get_core_ops(void)
 279{
 280        return &core_ops;
 281}
 282