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