Commit 32faca66 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'staging-5.1-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging

Pull staging driver fixes from Greg KH:
 "Here are some small staging driver fixes for 5.1-rc3, and one driver
  removal.

  The biggest thing here is the removal of the mt7621-eth driver as a
  "real" network driver was merged in 5.1-rc1 for this hardware, so this
  old driver can now be removed.

  Other than that, there are just a number of small fixes, all resolving
  reported issues and some potential corner cases for error handling
  paths.

  All of these have been in linux-next with no reported issues"

* tag 'staging-5.1-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging:
  staging: vt6655: Remove vif check from vnt_interrupt
  staging: erofs: keep corrupted fs from crashing kernel in erofs_readdir()
  staging: octeon-ethernet: fix incorrect PHY mode
  staging: vc04_services: Fix an error code in vchiq_probe()
  staging: erofs: fix error handling when failed to read compresssed data
  staging: vt6655: Fix interrupt race condition on device start up.
  staging: rtlwifi: Fix potential NULL pointer dereference of kzalloc
  staging: rtl8712: uninitialized memory in read_bbreg_hdl()
  staging: rtlwifi: rtl8822b: fix to avoid potential NULL pointer dereference
  staging: rtl8188eu: Fix potential NULL pointer dereference of kcalloc
  staging, mt7621-pci: fix build without pci support
  staging: speakup_soft: Fix alternate speech with other synths
  staging: axis-fifo: add CONFIG_OF dependency
  staging: olpc_dcon_xo_1: add missing 'const' qualifier
  staging: comedi: ni_mio_common: Fix divide-by-zero for DIO cmdtest
  staging: erofs: fix to handle error path of erofs_vmap()
  staging: mt7621-dts: update ethernet settings.
  staging: remove mt7621-eth
parents 52afe190 cc26358f
......@@ -114,8 +114,6 @@ source "drivers/staging/ralink-gdma/Kconfig"
source "drivers/staging/mt7621-mmc/Kconfig"
source "drivers/staging/mt7621-eth/Kconfig"
source "drivers/staging/mt7621-dts/Kconfig"
source "drivers/staging/gasket/Kconfig"
......
......@@ -47,7 +47,6 @@ obj-$(CONFIG_SPI_MT7621) += mt7621-spi/
obj-$(CONFIG_SOC_MT7621) += mt7621-dma/
obj-$(CONFIG_DMA_RALINK) += ralink-gdma/
obj-$(CONFIG_MTK_MMC) += mt7621-mmc/
obj-$(CONFIG_NET_MEDIATEK_SOC_STAGING) += mt7621-eth/
obj-$(CONFIG_SOC_MT7621) += mt7621-dts/
obj-$(CONFIG_STAGING_GASKET_FRAMEWORK) += gasket/
obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/
......
......@@ -3,6 +3,7 @@
#
config XIL_AXIS_FIFO
tristate "Xilinx AXI-Stream FIFO IP core driver"
depends on OF
default n
help
This adds support for the Xilinx AXI-Stream
......
......@@ -1001,6 +1001,8 @@ int comedi_dio_insn_config(struct comedi_device *dev,
unsigned int mask);
unsigned int comedi_dio_update_state(struct comedi_subdevice *s,
unsigned int *data);
unsigned int comedi_bytes_per_scan_cmd(struct comedi_subdevice *s,
struct comedi_cmd *cmd);
unsigned int comedi_bytes_per_scan(struct comedi_subdevice *s);
unsigned int comedi_nscans_left(struct comedi_subdevice *s,
unsigned int nscans);
......
......@@ -394,11 +394,13 @@ unsigned int comedi_dio_update_state(struct comedi_subdevice *s,
EXPORT_SYMBOL_GPL(comedi_dio_update_state);
/**
* comedi_bytes_per_scan() - Get length of asynchronous command "scan" in bytes
* comedi_bytes_per_scan_cmd() - Get length of asynchronous command "scan" in
* bytes
* @s: COMEDI subdevice.
* @cmd: COMEDI command.
*
* Determines the overall scan length according to the subdevice type and the
* number of channels in the scan.
* number of channels in the scan for the specified command.
*
* For digital input, output or input/output subdevices, samples for
* multiple channels are assumed to be packed into one or more unsigned
......@@ -408,9 +410,9 @@ EXPORT_SYMBOL_GPL(comedi_dio_update_state);
*
* Returns the overall scan length in bytes.
*/
unsigned int comedi_bytes_per_scan(struct comedi_subdevice *s)
unsigned int comedi_bytes_per_scan_cmd(struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
struct comedi_cmd *cmd = &s->async->cmd;
unsigned int num_samples;
unsigned int bits_per_sample;
......@@ -427,6 +429,29 @@ unsigned int comedi_bytes_per_scan(struct comedi_subdevice *s)
}
return comedi_samples_to_bytes(s, num_samples);
}
EXPORT_SYMBOL_GPL(comedi_bytes_per_scan_cmd);
/**
* comedi_bytes_per_scan() - Get length of asynchronous command "scan" in bytes
* @s: COMEDI subdevice.
*
* Determines the overall scan length according to the subdevice type and the
* number of channels in the scan for the current command.
*
* For digital input, output or input/output subdevices, samples for
* multiple channels are assumed to be packed into one or more unsigned
* short or unsigned int values according to the subdevice's %SDF_LSAMPL
* flag. For other types of subdevice, samples are assumed to occupy a
* whole unsigned short or unsigned int according to the %SDF_LSAMPL flag.
*
* Returns the overall scan length in bytes.
*/
unsigned int comedi_bytes_per_scan(struct comedi_subdevice *s)
{
struct comedi_cmd *cmd = &s->async->cmd;
return comedi_bytes_per_scan_cmd(s, cmd);
}
EXPORT_SYMBOL_GPL(comedi_bytes_per_scan);
static unsigned int __comedi_nscans_left(struct comedi_subdevice *s,
......
......@@ -3545,6 +3545,7 @@ static int ni_cdio_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
struct ni_private *devpriv = dev->private;
unsigned int bytes_per_scan;
int err = 0;
/* Step 1 : check if triggers are trivially valid */
......@@ -3579,9 +3580,12 @@ static int ni_cdio_cmdtest(struct comedi_device *dev,
err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
cmd->chanlist_len);
bytes_per_scan = comedi_bytes_per_scan_cmd(s, cmd);
if (bytes_per_scan) {
err |= comedi_check_trigger_arg_max(&cmd->stop_arg,
s->async->prealloc_bufsz /
comedi_bytes_per_scan(s));
bytes_per_scan);
}
if (err)
return 3;
......
......@@ -23,6 +23,21 @@ static const unsigned char erofs_filetype_table[EROFS_FT_MAX] = {
[EROFS_FT_SYMLINK] = DT_LNK,
};
static void debug_one_dentry(unsigned char d_type, const char *de_name,
unsigned int de_namelen)
{
#ifdef CONFIG_EROFS_FS_DEBUG
/* since the on-disk name could not have the trailing '\0' */
unsigned char dbg_namebuf[EROFS_NAME_LEN + 1];
memcpy(dbg_namebuf, de_name, de_namelen);
dbg_namebuf[de_namelen] = '\0';
debugln("found dirent %s de_len %u d_type %d", dbg_namebuf,
de_namelen, d_type);
#endif
}
static int erofs_fill_dentries(struct dir_context *ctx,
void *dentry_blk, unsigned int *ofs,
unsigned int nameoff, unsigned int maxsize)
......@@ -33,14 +48,10 @@ static int erofs_fill_dentries(struct dir_context *ctx,
de = dentry_blk + *ofs;
while (de < end) {
const char *de_name;
int de_namelen;
unsigned int de_namelen;
unsigned char d_type;
#ifdef CONFIG_EROFS_FS_DEBUG
unsigned int dbg_namelen;
unsigned char dbg_namebuf[EROFS_NAME_LEN];
#endif
if (unlikely(de->file_type < EROFS_FT_MAX))
if (de->file_type < EROFS_FT_MAX)
d_type = erofs_filetype_table[de->file_type];
else
d_type = DT_UNKNOWN;
......@@ -48,26 +59,20 @@ static int erofs_fill_dentries(struct dir_context *ctx,
nameoff = le16_to_cpu(de->nameoff);
de_name = (char *)dentry_blk + nameoff;
de_namelen = unlikely(de + 1 >= end) ?
/* last directory entry */
strnlen(de_name, maxsize - nameoff) :
le16_to_cpu(de[1].nameoff) - nameoff;
/* the last dirent in the block? */
if (de + 1 >= end)
de_namelen = strnlen(de_name, maxsize - nameoff);
else
de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
/* a corrupted entry is found */
if (unlikely(de_namelen < 0)) {
if (unlikely(nameoff + de_namelen > maxsize ||
de_namelen > EROFS_NAME_LEN)) {
DBG_BUGON(1);
return -EIO;
}
#ifdef CONFIG_EROFS_FS_DEBUG
dbg_namelen = min(EROFS_NAME_LEN - 1, de_namelen);
memcpy(dbg_namebuf, de_name, dbg_namelen);
dbg_namebuf[dbg_namelen] = '\0';
debugln("%s, found de_name %s de_len %d d_type %d", __func__,
dbg_namebuf, de_namelen, d_type);
#endif
debug_one_dentry(d_type, de_name, de_namelen);
if (!dir_emit(ctx, de_name, de_namelen,
le64_to_cpu(de->nid), d_type))
/* stopped by some reason */
......
......@@ -972,6 +972,7 @@ static int z_erofs_vle_unzip(struct super_block *sb,
overlapped = false;
compressed_pages = grp->compressed_pages;
err = 0;
for (i = 0; i < clusterpages; ++i) {
unsigned int pagenr;
......@@ -981,16 +982,19 @@ static int z_erofs_vle_unzip(struct super_block *sb,
DBG_BUGON(!page);
DBG_BUGON(!page->mapping);
if (z_erofs_is_stagingpage(page))
continue;
if (!z_erofs_is_stagingpage(page)) {
#ifdef EROFS_FS_HAS_MANAGED_CACHE
if (page->mapping == MNGD_MAPPING(sbi)) {
DBG_BUGON(!PageUptodate(page));
if (unlikely(!PageUptodate(page)))
err = -EIO;
continue;
}
#endif
/* only non-head page could be reused as a compressed page */
/*
* only if non-head page can be selected
* for inplace decompression
*/
pagenr = z_erofs_onlinepage_index(page);
DBG_BUGON(pagenr >= nr_pages);
......@@ -1001,6 +1005,16 @@ static int z_erofs_vle_unzip(struct super_block *sb,
overlapped = true;
}
/* PG_error needs checking for inplaced and staging pages */
if (unlikely(PageError(page))) {
DBG_BUGON(PageUptodate(page));
err = -EIO;
}
}
if (unlikely(err))
goto out;
llen = (nr_pages << PAGE_SHIFT) - work->pageofs;
if (z_erofs_vle_workgrp_fmt(grp) == Z_EROFS_VLE_WORKGRP_FMT_PLAIN) {
......@@ -1029,6 +1043,10 @@ static int z_erofs_vle_unzip(struct super_block *sb,
skip_allocpage:
vout = erofs_vmap(pages, nr_pages);
if (!vout) {
err = -ENOMEM;
goto out;
}
err = z_erofs_vle_unzip_vmap(compressed_pages,
clusterpages, vout, llen, work->pageofs, overlapped);
......@@ -1194,6 +1212,7 @@ pickup_page_for_submission(struct z_erofs_vle_workgroup *grp,
if (page->mapping == mc) {
WRITE_ONCE(grp->compressed_pages[nr], page);
ClearPageError(page);
if (!PagePrivate(page)) {
/*
* impossible to be !PagePrivate(page) for
......
......@@ -136,10 +136,13 @@ int z_erofs_vle_unzip_fast_percpu(struct page **compressed_pages,
nr_pages = DIV_ROUND_UP(outlen + pageofs, PAGE_SIZE);
if (clusterpages == 1)
if (clusterpages == 1) {
vin = kmap_atomic(compressed_pages[0]);
else
} else {
vin = erofs_vmap(compressed_pages, clusterpages);
if (!vin)
return -ENOMEM;
}
preempt_disable();
vout = erofs_pcpubuf[smp_processor_id()].data;
......
......@@ -117,22 +117,6 @@ &pcie {
status = "okay";
};
&ethernet {
//mtd-mac-address = <&factory 0xe000>;
gmac1: mac@0 {
compatible = "mediatek,eth-mac";
reg = <0>;
phy-handle = <&phy1>;
};
mdio-bus {
phy1: ethernet-phy@1 {
reg = <1>;
phy-mode = "rgmii";
};
};
};
&pinctrl {
state_default: pinctrl0 {
gpio {
......@@ -141,3 +125,16 @@ gpio {
};
};
};
&switch0 {
ports {
port@0 {
label = "ethblack";
status = "ok";
};
port@4 {
label = "ethblue";
status = "ok";
};
};
};
......@@ -372,16 +372,83 @@ ethernet: ethernet@1e100000 {
mediatek,ethsys = <&ethsys>;
mediatek,switch = <&gsw>;
gmac0: mac@0 {
compatible = "mediatek,eth-mac";
reg = <0>;
phy-mode = "rgmii";
fixed-link {
speed = <1000>;
full-duplex;
pause;
};
};
gmac1: mac@1 {
compatible = "mediatek,eth-mac";
reg = <1>;
status = "off";
phy-mode = "rgmii";
phy-handle = <&phy5>;
};
mdio-bus {
#address-cells = <1>;
#size-cells = <0>;
phy1f: ethernet-phy@1f {
reg = <0x1f>;
phy5: ethernet-phy@5 {
reg = <5>;
phy-mode = "rgmii";
};
switch0: switch0@0 {
compatible = "mediatek,mt7621";
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
mediatek,mcm;
resets = <&rstctrl 2>;
reset-names = "mcm";
ports {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
port@0 {
status = "off";
reg = <0>;
label = "lan0";
};
port@1 {
status = "off";
reg = <1>;
label = "lan1";
};
port@2 {
status = "off";
reg = <2>;
label = "lan2";
};
port@3 {
status = "off";
reg = <3>;
label = "lan3";
};
port@4 {
status = "off";
reg = <4>;
label = "lan4";
};
port@6 {
reg = <6>;
label = "cpu";
ethernet = <&gmac0>;
phy-mode = "trgmii";
fixed-link {
speed = <1000>;
full-duplex;
};
};
};
};
};
};
......
Mediatek Gigabit Switch
=======================
The mediatek gigabit switch can be found on Mediatek SoCs.
Required properties:
- compatible: Should be "mediatek,mt7620-gsw", "mediatek,mt7621-gsw",
"mediatek,mt7623-gsw"
- reg: Address and length of the register set for the device
- interrupts: Should contain the gigabit switches interrupt
Additional required properties for ARM based SoCs:
- mediatek,reset-pin: phandle describing the reset GPIO
- clocks: the clocks used by the switch
- clock-names: the names of the clocks listed in the clocks property
these should be "trgpll", "esw", "gp2", "gp1"
- mt7530-supply: the phandle of the regulator used to power the switch
- mediatek,pctl-regmap: phandle to the port control regmap. this is used to
setup the drive current
Optional properties:
- interrupt-parent: Should be the phandle for the interrupt controller
that services interrupts for this device
Example:
gsw: switch@1b100000 {
compatible = "mediatek,mt7623-gsw";
reg = <0 0x1b110000 0 0x300000>;
interrupt-parent = <&pio>;
interrupts = <168 IRQ_TYPE_EDGE_RISING>;
clocks = <&apmixedsys CLK_APMIXED_TRGPLL>,
<&ethsys CLK_ETHSYS_ESW>,
<&ethsys CLK_ETHSYS_GP2>,
<&ethsys CLK_ETHSYS_GP1>;
clock-names = "trgpll", "esw", "gp2", "gp1";
mt7530-supply = <&mt6323_vpa_reg>;
mediatek,pctl-regmap = <&syscfg_pctl_a>;
mediatek,reset-pin = <&pio 15 0>;
status = "okay";
};
config NET_VENDOR_MEDIATEK_STAGING
bool "MediaTek ethernet driver - staging version"
depends on RALINK
---help---
If you have an MT7621 Mediatek SoC with ethernet, say Y.
if NET_VENDOR_MEDIATEK_STAGING
choice
prompt "MAC type"
config NET_MEDIATEK_MT7621
bool "MT7621"
depends on MIPS && SOC_MT7621
endchoice
config NET_MEDIATEK_SOC_STAGING
tristate "MediaTek SoC Gigabit Ethernet support"
depends on NET_VENDOR_MEDIATEK_STAGING
select PHYLIB
---help---
This driver supports the gigabit ethernet MACs in the
MediaTek SoC family.
config NET_MEDIATEK_MDIO
def_bool NET_MEDIATEK_SOC_STAGING
depends on NET_MEDIATEK_MT7621
select PHYLIB
config NET_MEDIATEK_MDIO_MT7620
def_bool NET_MEDIATEK_SOC_STAGING
depends on NET_MEDIATEK_MT7621
select NET_MEDIATEK_MDIO
config NET_MEDIATEK_GSW_MT7621
def_tristate NET_MEDIATEK_SOC_STAGING
depends on NET_MEDIATEK_MT7621
endif #NET_VENDOR_MEDIATEK_STAGING
#
# Makefile for the Ralink SoCs built-in ethernet macs
#
mtk-eth-soc-y += mtk_eth_soc.o ethtool.o
mtk-eth-soc-$(CONFIG_NET_MEDIATEK_MDIO) += mdio.o
mtk-eth-soc-$(CONFIG_NET_MEDIATEK_MDIO_MT7620) += mdio_mt7620.o
mtk-eth-soc-$(CONFIG_NET_MEDIATEK_MT7621) += soc_mt7621.o
obj-$(CONFIG_NET_MEDIATEK_GSW_MT7621) += gsw_mt7621.o
obj-$(CONFIG_NET_MEDIATEK_SOC_STAGING) += mtk-eth-soc.o
- verify devicetree documentation is consistent with code
- fix ethtool - currently doesn't return valid data.
- general code review and clean up
- add support for second MAC on mt7621
- convert gsw code to use switchdev interfaces
- md7620_mmi_write etc should probably be wrapped
in a regmap abstraction.
- Get soc_mt7621 to work with QDMA TX if possible.
- Ensure phys are correctly configured when a cable
is plugged in.
Cc: NeilBrown <neil@brown.name>
// SPDX-License-Identifier: GPL-2.0
/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
*/
#include "mtk_eth_soc.h"
#include "ethtool.h"
struct mtk_stat {
char name[ETH_GSTRING_LEN];
unsigned int idx;
};
#define MTK_HW_STAT(stat) { \
.name = #stat, \
.idx = offsetof(struct mtk_hw_stats, stat) / sizeof(u64) \
}
static const struct mtk_stat mtk_ethtool_hw_stats[] = {
MTK_HW_STAT(tx_bytes),
MTK_HW_STAT(tx_packets),
MTK_HW_STAT(tx_skip),
MTK_HW_STAT(tx_collisions),
MTK_HW_STAT(rx_bytes),
MTK_HW_STAT(rx_packets),
MTK_HW_STAT(rx_overflow),
MTK_HW_STAT(rx_fcs_errors),
MTK_HW_STAT(rx_short_errors),
MTK_HW_STAT(rx_long_errors),
MTK_HW_STAT(rx_checksum_errors),
MTK_HW_STAT(rx_flow_control_packets),
};
#define MTK_HW_STATS_LEN ARRAY_SIZE(mtk_ethtool_hw_stats)
static int mtk_get_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *cmd)
{
struct mtk_mac *mac = netdev_priv(dev);
int err;
if (!mac->phy_dev)
return -ENODEV;
if (mac->phy_flags == MTK_PHY_FLAG_ATTACH) {
err = phy_read_status(mac->phy_dev);
if (err)
return -ENODEV;
}
phy_ethtool_ksettings_get(mac->phy_dev, cmd);
return 0;
}
static int mtk_set_link_ksettings(struct net_device *dev,
const struct ethtool_link_ksettings *cmd)
{
struct mtk_mac *mac = netdev_priv(dev);
if (!mac->phy_dev)
return -ENODEV;
if (cmd->base.phy_address != mac->phy_dev->mdio.addr) {
if (mac->hw->phy->phy_node[cmd->base.phy_address]) {
mac->phy_dev = mac->hw->phy->phy[cmd->base.phy_address];
mac->phy_flags = MTK_PHY_FLAG_PORT;
} else if (mac->hw->mii_bus) {
mac->phy_dev = mdiobus_get_phy(mac->hw->mii_bus,
cmd->base.phy_address);
if (!mac->phy_dev)
return -ENODEV;
mac->phy_flags = MTK_PHY_FLAG_ATTACH;
} else {
return -ENODEV;
}
}
return phy_ethtool_ksettings_set(mac->phy_dev, cmd);
}
static void mtk_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct mtk_mac *mac = netdev_priv(dev);
struct mtk_soc_data *soc = mac->hw->soc;
strlcpy(info->driver, mac->hw->dev->driver->name, sizeof(info->driver));
strlcpy(info->bus_info, dev_name(mac->hw->dev), sizeof(info->bus_info));
if (soc->reg_table[MTK_REG_MTK_COUNTER_BASE])
info->n_stats = MTK_HW_STATS_LEN;
}
static u32 mtk_get_msglevel(struct net_device *dev)
{
struct mtk_mac *mac = netdev_priv(dev);
return mac->hw->msg_enable;
}
static void mtk_set_msglevel(struct net_device *dev, u32 value)
{
struct mtk_mac *mac = netdev_priv(dev);
mac->hw->msg_enable = value;
}
static int mtk_nway_reset(struct net_device *dev)
{
struct mtk_mac *mac = netdev_priv(dev);
if (!mac->phy_dev)
return -EOPNOTSUPP;
return genphy_restart_aneg(mac->phy_dev);
}
static u32 mtk_get_link(struct net_device *dev)
{
struct mtk_mac *mac = netdev_priv(dev);
int err;
if (!mac->phy_dev)
goto out_get_link;
if (mac->phy_flags == MTK_PHY_FLAG_ATTACH) {
err = genphy_update_link(mac->phy_dev);
if (err)
goto out_get_link;
}
return mac->phy_dev->link;
out_get_link:
return ethtool_op_get_link(dev);
}
static int mtk_set_ringparam(struct net_device *dev,
struct ethtool_ringparam *ring)
{
struct mtk_mac *mac = netdev_priv(dev);
if ((ring->tx_pending < 2) ||
(ring->rx_pending < 2) ||
(ring->rx_pending > mac->hw->soc->dma_ring_size) ||
(ring->tx_pending > mac->hw->soc->dma_ring_size))
return -EINVAL;
dev->netdev_ops->ndo_stop(dev);
mac->hw->tx_ring.tx_ring_size = BIT(fls(ring->tx_pending) - 1);
mac->hw->rx_ring[0].rx_ring_size = BIT(fls(ring->rx_pending) - 1);
return dev->netdev_ops->ndo_open(dev);
}
static void mtk_get_ringparam(struct net_device *dev,
struct ethtool_ringparam *ring)
{
struct mtk_mac *mac = netdev_priv(dev);
ring->rx_max_pending = mac->hw->soc->dma_ring_size;
ring->tx_max_pending = mac->hw->soc->dma_ring_size;
ring->rx_pending = mac->hw->rx_ring[0].rx_ring_size;
ring->tx_pending = mac->hw->tx_ring.tx_ring_size;
}
static void mtk_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{
int i;
switch (stringset) {
case ETH_SS_STATS:
for (i = 0; i < MTK_HW_STATS_LEN; i++) {
memcpy(data, mtk_ethtool_hw_stats[i].name,
ETH_GSTRING_LEN);
data += ETH_GSTRING_LEN;
}
break;
}
}
static int mtk_get_sset_count(struct net_device *dev, int sset)
{
switch (sset) {
case ETH_SS_STATS:
return MTK_HW_STATS_LEN;
default:
return -EOPNOTSUPP;
}
}
static void mtk_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *data)
{
struct mtk_mac *mac = netdev_priv(dev);
struct mtk_hw_stats *hwstats = mac->hw_stats;
unsigned int start;
int i;
if (netif_running(dev) && netif_device_present(dev)) {
if (spin_trylock(&hwstats->stats_lock)) {
mtk_stats_update_mac(mac);
spin_unlock(&hwstats->stats_lock);
}
}
do {
start = u64_stats_fetch_begin_irq(&hwstats->syncp);
for (i = 0; i < MTK_HW_STATS_LEN; i++)
data[i] = ((u64 *)hwstats)[mtk_ethtool_hw_stats[i].idx];
} while (u64_stats_fetch_retry_irq(&hwstats->syncp, start));
}
static struct ethtool_ops mtk_ethtool_ops = {
.get_link_ksettings = mtk_get_link_ksettings,
.set_link_ksettings = mtk_set_link_ksettings,
.get_drvinfo = mtk_get_drvinfo,
.get_msglevel = mtk_get_msglevel,
.set_msglevel = mtk_set_msglevel,
.nway_reset = mtk_nway_reset,
.get_link = mtk_get_link,
.set_ringparam = mtk_set_ringparam,
.get_ringparam = mtk_get_ringparam,
};
void mtk_set_ethtool_ops(struct net_device *netdev)
{
struct mtk_mac *mac = netdev_priv(netdev);
struct mtk_soc_data *soc = mac->hw->soc;
if (soc->reg_table[MTK_REG_MTK_COUNTER_BASE]) {
mtk_ethtool_ops.get_strings = mtk_get_strings;
mtk_ethtool_ops.get_sset_count = mtk_get_sset_count;
mtk_ethtool_ops.get_ethtool_stats = mtk_get_ethtool_stats;
}
netdev->ethtool_ops = &mtk_ethtool_ops;
}
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
*/
#ifndef MTK_ETHTOOL_H
#define MTK_ETHTOOL_H
#include <linux/ethtool.h>
void mtk_set_ethtool_ops(struct net_device *netdev);
#endif /* MTK_ETHTOOL_H */
/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
*/
#ifndef _RALINK_GSW_MT7620_H__
#define _RALINK_GSW_MT7620_H__
#define GSW_REG_PHY_TIMEOUT (5 * HZ)
#define MT7620_GSW_REG_PIAC 0x0004
#define GSW_NUM_VLANS 16
#define GSW_NUM_VIDS 4096
#define GSW_NUM_PORTS 7
#define GSW_PORT6 6
#define GSW_MDIO_ACCESS BIT(31)
#define GSW_MDIO_READ BIT(19)
#define GSW_MDIO_WRITE BIT(18)
#define GSW_MDIO_START BIT(16)
#define GSW_MDIO_ADDR_SHIFT 20
#define GSW_MDIO_REG_SHIFT 25
#define GSW_REG_PORT_PMCR(x) (0x3000 + (x * 0x100))
#define GSW_REG_PORT_STATUS(x) (0x3008 + (x * 0x100))
#define GSW_REG_SMACCR0 0x3fE4
#define GSW_REG_SMACCR1 0x3fE8
#define GSW_REG_CKGCR 0x3ff0
#define GSW_REG_IMR 0x7008
#define GSW_REG_ISR 0x700c
#define GSW_REG_GPC1 0x7014
#define SYSC_REG_CHIP_REV_ID 0x0c
#define SYSC_REG_CFG 0x10
#define SYSC_REG_CFG1 0x14
#define RST_CTRL_MCM BIT(2)
#define SYSC_PAD_RGMII2_MDIO 0x58
#define SYSC_GPIO_MODE 0x60
#define PORT_IRQ_ST_CHG 0x7f
#define MT7621_ESW_PHY_POLLING 0x0000
#define MT7620_ESW_PHY_POLLING 0x7000
#define PMCR_IPG BIT(18)
#define PMCR_MAC_MODE BIT(16)
#define PMCR_FORCE BIT(15)
#define PMCR_TX_EN BIT(14)
#define PMCR_RX_EN BIT(13)
#define PMCR_BACKOFF BIT(9)
#define PMCR_BACKPRES BIT(8)
#define PMCR_RX_FC BIT(5)
#define PMCR_TX_FC BIT(4)
#define PMCR_SPEED(_x) (_x << 2)
#define PMCR_DUPLEX BIT(1)
#define PMCR_LINK BIT(0)
#define PHY_AN_EN BIT(31)
#define PHY_PRE_EN BIT(30)
#define PMY_MDC_CONF(_x) ((_x & 0x3f) << 24)
/* ethernet subsystem config register */
#define ETHSYS_SYSCFG0 0x14
/* ethernet subsystem clock register */
#define ETHSYS_CLKCFG0 0x2c
#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11)
/* p5 RGMII wrapper TX clock control register */
#define MT7530_P5RGMIITXCR 0x7b04
/* p5 RGMII wrapper RX clock control register */
#define MT7530_P5RGMIIRXCR 0x7b00
/* TRGMII TDX ODT registers */
#define MT7530_TRGMII_TD0_ODT 0x7a54
#define MT7530_TRGMII_TD1_ODT 0x7a5c
#define MT7530_TRGMII_TD2_ODT 0x7a64
#define MT7530_TRGMII_TD3_ODT 0x7a6c
#define MT7530_TRGMII_TD4_ODT 0x7a74
#define MT7530_TRGMII_TD5_ODT 0x7a7c
/* TRGMII TCK ctrl register */
#define MT7530_TRGMII_TCK_CTRL 0x7a78
/* TRGMII Tx ctrl register */
#define MT7530_TRGMII_TXCTRL 0x7a40
/* port 6 extended control register */
#define MT7530_P6ECR 0x7830
/* IO driver control register */
#define MT7530_IO_DRV_CR 0x7810
/* top signal control register */
#define MT7530_TOP_SIG_CTRL 0x7808
/* modified hwtrap register */
#define MT7530_MHWTRAP 0x7804
/* hwtrap status register */
#define MT7530_HWTRAP 0x7800
/* status interrupt register */
#define MT7530_SYS_INT_STS 0x700c
/* system nterrupt register */
#define MT7530_SYS_INT_EN 0x7008
/* system control register */
#define MT7530_SYS_CTRL 0x7000
/* port MAC status register */
#define MT7530_PMSR_P(x) (0x3008 + (x * 0x100))
/* port MAC control register */
#define MT7530_PMCR_P(x) (0x3000 + (x * 0x100))
#define MT7621_XTAL_SHIFT 6
#define MT7621_XTAL_MASK 0x7
#define MT7621_XTAL_25 6
#define MT7621_XTAL_40 3
#define MT7621_MDIO_DRV_MASK (3 << 4)
#define MT7621_GE1_MODE_MASK (3 << 12)
#define TRGMII_TXCTRL_TXC_INV BIT(30)
#define P6ECR_INTF_MODE_RGMII BIT(1)
#define P5RGMIIRXCR_C_ALIGN BIT(8)
#define P5RGMIIRXCR_DELAY_2 BIT(1)
#define P5RGMIITXCR_DELAY_2 (BIT(8) | BIT(2))
/* TOP_SIG_CTRL bits */
#define TOP_SIG_CTRL_NORMAL (BIT(17) | BIT(16))
/* MHWTRAP bits */
#define MHWTRAP_MANUAL BIT(16)
#define MHWTRAP_P5_MAC_SEL BIT(13)
#define MHWTRAP_P6_DIS BIT(8)
#define MHWTRAP_P5_RGMII_MODE BIT(7)
#define MHWTRAP_P5_DIS BIT(6)
#define MHWTRAP_PHY_ACCESS BIT(5)
/* HWTRAP bits */
#define HWTRAP_XTAL_SHIFT 9
#define HWTRAP_XTAL_MASK 0x3
/* SYS_CTRL bits */
#define SYS_CTRL_SW_RST BIT(1)
#define SYS_CTRL_REG_RST BIT(0)
/* PMCR bits */
#define PMCR_IFG_XMIT_96 BIT(18)
#define PMCR_MAC_MODE BIT(16)
#define PMCR_FORCE_MODE BIT(15)
#define PMCR_TX_EN BIT(14)
#define PMCR_RX_EN BIT(13)
#define PMCR_BACK_PRES_EN BIT(9)
#define PMCR_BACKOFF_EN BIT(8)
#define PMCR_TX_FC_EN BIT(5)
#define PMCR_RX_FC_EN BIT(4)
#define PMCR_FORCE_SPEED_1000 BIT(3)
#define PMCR_FORCE_FDX BIT(1)
#define PMCR_FORCE_LNK BIT(0)
#define PMCR_FIXED_LINK (PMCR_IFG_XMIT_96 | PMCR_MAC_MODE | \
PMCR_FORCE_MODE | PMCR_TX_EN | PMCR_RX_EN | \
PMCR_BACK_PRES_EN | PMCR_BACKOFF_EN | \
PMCR_FORCE_SPEED_1000 | PMCR_FORCE_FDX | \
PMCR_FORCE_LNK)
#define PMCR_FIXED_LINK_FC (PMCR_FIXED_LINK | \
PMCR_TX_FC_EN | PMCR_RX_FC_EN)
/* TRGMII control registers */
#define GSW_INTF_MODE 0x390
#define GSW_TRGMII_TD0_ODT 0x354
#define GSW_TRGMII_TD1_ODT 0x35c
#define GSW_TRGMII_TD2_ODT 0x364
#define GSW_TRGMII_TD3_ODT 0x36c
#define GSW_TRGMII_TXCTL_ODT 0x374
#define GSW_TRGMII_TCK_ODT 0x37c
#define GSW_TRGMII_RCK_CTRL 0x300
#define INTF_MODE_TRGMII BIT(1)
#define TRGMII_RCK_CTRL_RX_RST BIT(31)
/* Mac control registers */
#define MTK_MAC_P2_MCR 0x200
#define MTK_MAC_P1_MCR 0x100
#define MAC_MCR_MAX_RX_2K BIT(29)
#define MAC_MCR_IPG_CFG (BIT(18) | BIT(16))
#define MAC_MCR_FORCE_MODE BIT(15)
#define MAC_MCR_TX_EN BIT(14)
#define MAC_MCR_RX_EN BIT(13)
#define MAC_MCR_BACKOFF_EN BIT(9)
#define MAC_MCR_BACKPR_EN BIT(8)
#define MAC_MCR_FORCE_RX_FC BIT(5)
#define MAC_MCR_FORCE_TX_FC BIT(4)
#define MAC_MCR_SPEED_1000 BIT(3)
#define MAC_MCR_FORCE_DPX BIT(1)
#define MAC_MCR_FORCE_LINK BIT(0)
#define MAC_MCR_FIXED_LINK (MAC_MCR_MAX_RX_2K | MAC_MCR_IPG_CFG | \
MAC_MCR_FORCE_MODE | MAC_MCR_TX_EN | \
MAC_MCR_RX_EN | MAC_MCR_BACKOFF_EN | \
MAC_MCR_BACKPR_EN | MAC_MCR_FORCE_RX_FC | \
MAC_MCR_FORCE_TX_FC | MAC_MCR_SPEED_1000 | \
MAC_MCR_FORCE_DPX | MAC_MCR_FORCE_LINK)
#define MAC_MCR_FIXED_LINK_FC (MAC_MCR_MAX_RX_2K | MAC_MCR_IPG_CFG | \
MAC_MCR_FIXED_LINK)
/* possible XTAL speed */
#define MT7623_XTAL_40 0
#define MT7623_XTAL_20 1
#define MT7623_XTAL_25 3
/* GPIO port control registers */
#define GPIO_OD33_CTRL8 0x4c0
#define GPIO_BIAS_CTRL 0xed0
#define GPIO_DRV_SEL10 0xf00
/* on MT7620 the functio of port 4 can be software configured */
enum {
PORT4_EPHY = 0,
PORT4_EXT,
};
/* struct mt7620_gsw - the structure that holds the SoC specific data
* @dev: The Device struct
* @base: The base address
* @piac_offset: The PIAC base may change depending on SoC
* @irq: The IRQ we are using
* @port4: The port4 mode on MT7620
* @autopoll: Is MDIO autopolling enabled
* @ethsys: The ethsys register map
* @pctl: The pin control register map
* @clk_gsw: The switch clock
* @clk_gp1: The gmac1 clock
* @clk_gp2: The gmac2 clock
* @clk_trgpll: The trgmii pll clock
*/
struct mt7620_gsw {
struct device *dev;
void __iomem *base;
u32 piac_offset;
int irq;
int port4;
unsigned long int autopoll;
struct regmap *ethsys;
struct regmap *pctl;
struct clk *clk_gsw;
struct clk *clk_gp1;
struct clk *clk_gp2;
struct clk *clk_trgpll;
};
/* switch register I/O wrappers */
void mtk_switch_w32(struct mt7620_gsw *gsw, u32 val, unsigned int reg);
u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned int reg);
/* the callback used by the driver core to bringup the switch */
int mtk_gsw_init(struct mtk_eth *eth);
/* MDIO access wrappers */
int mt7620_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val);
int mt7620_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg);
void mt7620_mdio_link_adjust(struct mtk_eth *eth, int port);
int mt7620_has_carrier(struct mtk_eth *eth);
void mt7620_print_link_state(struct mtk_eth *eth, int port, int link,
int speed, int duplex);
void mt7530_mdio_w32(struct mt7620_gsw *gsw, u32 reg, u32 val);
u32 mt7530_mdio_r32(struct mt7620_gsw *gsw, u32 reg);
void mt7530_mdio_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, u32 reg);
u32 _mt7620_mii_write(struct mt7620_gsw *gsw, u32 phy_addr,
u32 phy_register, u32 write_data);
u32 _mt7620_mii_read(struct mt7620_gsw *gsw, int phy_addr, int phy_reg);
void mt7620_handle_carrier(struct mtk_eth *eth);
#endif
/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <ralink_regs.h>
#include "mtk_eth_soc.h"
#include "gsw_mt7620.h"
void mtk_switch_w32(struct mt7620_gsw *gsw, u32 val, unsigned int reg)
{
iowrite32(val, gsw->base + reg);
}
EXPORT_SYMBOL_GPL(mtk_switch_w32);
u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned int reg)
{
return ioread32(gsw->base + reg);
}
EXPORT_SYMBOL_GPL(mtk_switch_r32);
static irqreturn_t gsw_interrupt_mt7621(int irq, void *_eth)
{
struct mtk_eth *eth = (struct mtk_eth *)_eth;
struct mt7620_gsw *gsw = (struct mt7620_gsw *)eth->sw_priv;
u32 reg, i;
reg = mt7530_mdio_r32(gsw, MT7530_SYS_INT_STS);
for (i = 0; i < 5; i++) {
unsigned int link;
if ((reg & BIT(i)) == 0)
continue;
link = mt7530_mdio_r32(gsw, MT7530_PMSR_P(i)) & 0x1;
if (link == eth->link[i])
continue;
eth->link[i] = link;
if (link)
netdev_info(*eth->netdev,
"port %d link up\n", i);
else
netdev_info(*eth->netdev,
"port %d link down\n", i);
}
mt7530_mdio_w32(gsw, MT7530_SYS_INT_STS, 0x1f);
return IRQ_HANDLED;
}
static void mt7621_hw_init(struct mtk_eth *eth, struct mt7620_gsw *gsw,
struct device_node *np)
{
u32 i;
u32 val;
/* hardware reset the switch */
mtk_reset(eth, RST_CTRL_MCM);
mdelay(10);
/* reduce RGMII2 PAD driving strength */
rt_sysc_m32(MT7621_MDIO_DRV_MASK, 0, SYSC_PAD_RGMII2_MDIO);
/* gpio mux - RGMII1=Normal mode */
rt_sysc_m32(BIT(14), 0, SYSC_GPIO_MODE);
/* set GMAC1 RGMII mode */
rt_sysc_m32(MT7621_GE1_MODE_MASK, 0, SYSC_REG_CFG1);
/* enable MDIO to control MT7530 */
rt_sysc_m32(3 << 12, 0, SYSC_GPIO_MODE);
/* turn off all PHYs */
for (i = 0; i <= 4; i++) {
val = _mt7620_mii_read(gsw, i, 0x0);
val |= BIT(11);
_mt7620_mii_write(gsw, i, 0x0, val);
}
/* reset the switch */
mt7530_mdio_w32(gsw, MT7530_SYS_CTRL,
SYS_CTRL_SW_RST | SYS_CTRL_REG_RST);
usleep_range(10, 20);
if ((rt_sysc_r32(SYSC_REG_CHIP_REV_ID) & 0xFFFF) == 0x0101) {
/* GE1, Force 1000M/FD, FC ON, MAX_RX_LENGTH 1536 */
mtk_switch_w32(gsw, MAC_MCR_FIXED_LINK, MTK_MAC_P2_MCR);
mt7530_mdio_w32(gsw, MT7530_PMCR_P(6), PMCR_FIXED_LINK);
} else {
/* GE1, Force 1000M/FD, FC ON, MAX_RX_LENGTH 1536 */
mtk_switch_w32(gsw, MAC_MCR_FIXED_LINK_FC, MTK_MAC_P1_MCR);
mt7530_mdio_w32(gsw, MT7530_PMCR_P(6), PMCR_FIXED_LINK_FC);
}
/* GE2, Link down */
mtk_switch_w32(gsw, MAC_MCR_FORCE_MODE, MTK_MAC_P2_MCR);
/* Enable Port 6, P5 as GMAC5, P5 disable */
val = mt7530_mdio_r32(gsw, MT7530_MHWTRAP);
/* Enable Port 6 */
val &= ~MHWTRAP_P6_DIS;
/* Disable Port 5 */
val |= MHWTRAP_P5_DIS;
/* manual override of HW-Trap */
val |= MHWTRAP_MANUAL;
mt7530_mdio_w32(gsw, MT7530_MHWTRAP, val);
val = rt_sysc_r32(SYSC_REG_CFG);
val = (val >> MT7621_XTAL_SHIFT) & MT7621_XTAL_MASK;
if (val < MT7621_XTAL_25 && val >= MT7621_XTAL_40) {
/* 40Mhz */
/* disable MT7530 core clock */
_mt7620_mii_write(gsw, 0, 13, 0x1f);
_mt7620_mii_write(gsw, 0, 14, 0x410);
_mt7620_mii_write(gsw, 0, 13, 0x401f);
_mt7620_mii_write(gsw, 0, 14, 0x0);
/* disable MT7530 PLL */
_mt7620_mii_write(gsw, 0, 13, 0x1f);
_mt7620_mii_write(gsw, 0, 14, 0x40d);
_mt7620_mii_write(gsw, 0, 13, 0x401f);
_mt7620_mii_write(gsw, 0, 14, 0x2020);
/* for MT7530 core clock = 500Mhz */
_mt7620_mii_write(gsw, 0, 13, 0x1f);
_mt7620_mii_write(gsw, 0, 14, 0x40e);
_mt7620_mii_write(gsw, 0, 13, 0x401f);
_mt7620_mii_write(gsw, 0, 14, 0x119);
/* enable MT7530 PLL */
_mt7620_mii_write(gsw, 0, 13, 0x1f);
_mt7620_mii_write(gsw, 0, 14, 0x40d);
_mt7620_mii_write(gsw, 0, 13, 0x401f);
_mt7620_mii_write(gsw, 0, 14, 0x2820);
usleep_range(20, 40);
/* enable MT7530 core clock */
_mt7620_mii_write(gsw, 0, 13, 0x1f);
_mt7620_mii_write(gsw, 0, 14, 0x410);
_mt7620_mii_write(gsw, 0, 13, 0x401f);
}
/* RGMII */
_mt7620_mii_write(gsw, 0, 14, 0x1);
/* set MT7530 central align */
mt7530_mdio_m32(gsw, BIT(0), P6ECR_INTF_MODE_RGMII, MT7530_P6ECR);
mt7530_mdio_m32(gsw, TRGMII_TXCTRL_TXC_INV, 0,
MT7530_TRGMII_TXCTRL);
mt7530_mdio_w32(gsw, MT7530_TRGMII_TCK_CTRL, 0x855);
/* delay setting for 10/1000M */
mt7530_mdio_w32(gsw, MT7530_P5RGMIIRXCR,
P5RGMIIRXCR_C_ALIGN | P5RGMIIRXCR_DELAY_2);
mt7530_mdio_w32(gsw, MT7530_P5RGMIITXCR, 0x14);
/* lower Tx Driving*/
mt7530_mdio_w32(gsw, MT7530_TRGMII_TD0_ODT, 0x44);
mt7530_mdio_w32(gsw, MT7530_TRGMII_TD1_ODT, 0x44);
mt7530_mdio_w32(gsw, MT7530_TRGMII_TD2_ODT, 0x44);
mt7530_mdio_w32(gsw, MT7530_TRGMII_TD3_ODT, 0x44);
mt7530_mdio_w32(gsw, MT7530_TRGMII_TD4_ODT, 0x44);
mt7530_mdio_w32(gsw, MT7530_TRGMII_TD5_ODT, 0x44);
/* turn on all PHYs */
for (i = 0; i <= 4; i++) {
val = _mt7620_mii_read(gsw, i, 0);
val &= ~BIT(11);
_mt7620_mii_write(gsw, i, 0, val);
}
#define MT7530_NUM_PORTS 8
#define REG_ESW_PORT_PCR(x) (0x2004 | ((x) << 8))
#define REG_ESW_PORT_PVC(x) (0x2010 | ((x) << 8))
#define REG_ESW_PORT_PPBV1(x) (0x2014 | ((x) << 8))
#define MT7530_CPU_PORT 6
/* This is copied from mt7530_apply_config in libreCMC driver */
{
int i;
for (i = 0; i < MT7530_NUM_PORTS; i++)
mt7530_mdio_w32(gsw, REG_ESW_PORT_PCR(i), 0x00400000);
mt7530_mdio_w32(gsw, REG_ESW_PORT_PCR(MT7530_CPU_PORT),
0x00ff0000);
for (i = 0; i < MT7530_NUM_PORTS; i++)
mt7530_mdio_w32(gsw, REG_ESW_PORT_PVC(i), 0x810000c0);
}
/* enable irq */
mt7530_mdio_m32(gsw, 0, 3 << 16, MT7530_TOP_SIG_CTRL);
mt7530_mdio_w32(gsw, MT7530_SYS_INT_EN, 0x1f);
}
static const struct of_device_id mediatek_gsw_match[] = {
{ .compatible = "mediatek,mt7621-gsw" },
{},
};
MODULE_DEVICE_TABLE(of, mediatek_gsw_match);
int mtk_gsw_init(struct mtk_eth *eth)
{
struct device_node *np = eth->switch_np;
struct platform_device *pdev = of_find_device_by_node(np);
struct mt7620_gsw *gsw;
if (!pdev)
return -ENODEV;
if (!of_device_is_compatible(np, mediatek_gsw_match->compatible))
return -EINVAL;
gsw = platform_get_drvdata(pdev);
eth->sw_priv = gsw;
if (!gsw->irq)
return -EINVAL;
request_irq(gsw->irq, gsw_interrupt_mt7621, 0,
"gsw", eth);
disable_irq(gsw->irq);
mt7621_hw_init(eth, gsw, np);
enable_irq(gsw->irq);
return 0;
}
EXPORT_SYMBOL_GPL(mtk_gsw_init);
static int mt7621_gsw_probe(struct platform_device *pdev)
{
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct mt7620_gsw *gsw;
gsw = devm_kzalloc(&pdev->dev, sizeof(struct mt7620_gsw), GFP_KERNEL);
if (!gsw)
return -ENOMEM;
gsw->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(gsw->base))
return PTR_ERR(gsw->base);
gsw->dev = &pdev->dev;
gsw->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
platform_set_drvdata(pdev, gsw);
return 0;
}
static int mt7621_gsw_remove(struct platform_device *pdev)
{
platform_set_drvdata(pdev, NULL);
return 0;
}
static struct platform_driver gsw_driver = {
.probe = mt7621_gsw_probe,
.remove = mt7621_gsw_remove,
.driver = {
.name = "mt7621-gsw",
.of_match_table = mediatek_gsw_match,
},
};
module_platform_driver(gsw_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
MODULE_DESCRIPTION("GBit switch driver for Mediatek MT7621 SoC");
/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License
*
* Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/phy.h>
#include <linux/of_net.h>
#include <linux/of_mdio.h>
#include "mtk_eth_soc.h"
#include "mdio.h"
static int mtk_mdio_reset(struct mii_bus *bus)
{
/* TODO */
return 0;
}
static void mtk_phy_link_adjust(struct net_device *dev)
{
struct mtk_eth *eth = netdev_priv(dev);
unsigned long flags;
int i;
spin_lock_irqsave(&eth->phy->lock, flags);
for (i = 0; i < 8; i++) {
if (eth->phy->phy_node[i]) {
struct phy_device *phydev = eth->phy->phy[i];
int status_change = 0;
if (phydev->link)
if (eth->phy->duplex[i] != phydev->duplex ||
eth->phy->speed[i] != phydev->speed)
status_change = 1;
if (phydev->link != eth->link[i])
status_change = 1;
switch (phydev->speed) {
case SPEED_1000:
case SPEED_100:
case SPEED_10:
eth->link[i] = phydev->link;
eth->phy->duplex[i] = phydev->duplex;
eth->phy->speed[i] = phydev->speed;
if (status_change &&
eth->soc->mdio_adjust_link)
eth->soc->mdio_adjust_link(eth, i);
break;
}
}
}
spin_unlock_irqrestore(&eth->phy->lock, flags);
}
int mtk_connect_phy_node(struct mtk_eth *eth, struct mtk_mac *mac,
struct device_node *phy_node)
{
const __be32 *_port = NULL;
struct phy_device *phydev;
int phy_mode, port;
_port = of_get_property(phy_node, "reg", NULL);
if (!_port || (be32_to_cpu(*_port) >= 0x20)) {
pr_err("%pOFn: invalid port id\n", phy_node);
return -EINVAL;
}
port = be32_to_cpu(*_port);
phy_mode = of_get_phy_mode(phy_node);
if (phy_mode < 0) {
dev_err(eth->dev, "incorrect phy-mode %d\n", phy_mode);
eth->phy->phy_node[port] = NULL;
return -EINVAL;
}
phydev = of_phy_connect(eth->netdev[mac->id], phy_node,
mtk_phy_link_adjust, 0, phy_mode);
if (!phydev) {
dev_err(eth->dev, "could not connect to PHY\n");
eth->phy->phy_node[port] = NULL;
return -ENODEV;
}
phydev->supported &= PHY_1000BT_FEATURES;
phydev->advertising = phydev->supported;
dev_info(eth->dev,
"connected port %d to PHY at %s [uid=%08x, driver=%s]\n",
port, phydev_name(phydev), phydev->phy_id,
phydev->drv->name);
eth->phy->phy[port] = phydev;
eth->link[port] = 0;
return 0;
}
static void phy_init(struct mtk_eth *eth, struct mtk_mac *mac,
struct phy_device *phy)
{
phy_attach(eth->netdev[mac->id], phydev_name(phy),
PHY_INTERFACE_MODE_MII);
phy->autoneg = AUTONEG_ENABLE;
phy->speed = 0;
phy->duplex = 0;
phy_set_max_speed(phy, SPEED_100);
phy->advertising = phy->supported | ADVERTISED_Autoneg;
phy_start_aneg(phy);
}
static int mtk_phy_connect(struct mtk_mac *mac)
{
struct mtk_eth *eth = mac->hw;
int i;
for (i = 0; i < 8; i++) {
if (eth->phy->phy_node[i]) {
if (!mac->phy_dev) {
mac->phy_dev = eth->phy->phy[i];
mac->phy_flags = MTK_PHY_FLAG_PORT;
}
} else if (eth->mii_bus) {
struct phy_device *phy;
phy = mdiobus_get_phy(eth->mii_bus, i);
if (phy) {
phy_init(eth, mac, phy);
if (!mac->phy_dev) {
mac->phy_dev = phy;
mac->phy_flags = MTK_PHY_FLAG_ATTACH;
}
}
}
}
return 0;
}
static void mtk_phy_disconnect(struct mtk_mac *mac)
{
struct mtk_eth *eth = mac->hw;
unsigned long flags;
int i;
for (i = 0; i < 8; i++)
if (eth->phy->phy_fixed[i]) {
spin_lock_irqsave(&eth->phy->lock, flags);
eth->link[i] = 0;
if (eth->soc->mdio_adjust_link)
eth->soc->mdio_adjust_link(eth, i);
spin_unlock_irqrestore(&eth->phy->lock, flags);
} else if (eth->phy->phy[i]) {
phy_disconnect(eth->phy->phy[i]);
} else if (eth->mii_bus) {
struct phy_device *phy =
mdiobus_get_phy(eth->mii_bus, i);
if (phy)
phy_detach(phy);
}
}
static void mtk_phy_start(struct mtk_mac *mac)
{
struct mtk_eth *eth = mac->hw;
unsigned long flags;
int i;
for (i = 0; i < 8; i++) {
if (eth->phy->phy_fixed[i]) {
spin_lock_irqsave(&eth->phy->lock, flags);
eth->link[i] = 1;
if (eth->soc->mdio_adjust_link)
eth->soc->mdio_adjust_link(eth, i);
spin_unlock_irqrestore(&eth->phy->lock, flags);
} else if (eth->phy->phy[i]) {
phy_start(eth->phy->phy[i]);
}
}
}
static void mtk_phy_stop(struct mtk_mac *mac)
{
struct mtk_eth *eth = mac->hw;
unsigned long flags;
int i;
for (i = 0; i < 8; i++)
if (eth->phy->phy_fixed[i]) {
spin_lock_irqsave(&eth->phy->lock, flags);
eth->link[i] = 0;
if (eth->soc->mdio_adjust_link)
eth->soc->mdio_adjust_link(eth, i);
spin_unlock_irqrestore(&eth->phy->lock, flags);
} else if (eth->phy->phy[i]) {
phy_stop(eth->phy->phy[i]);
}
}
static struct mtk_phy phy_ralink = {
.connect = mtk_phy_connect,
.disconnect = mtk_phy_disconnect,
.start = mtk_phy_start,
.stop = mtk_phy_stop,
};
int mtk_mdio_init(struct mtk_eth *eth)
{
struct device_node *mii_np;
int err;
if (!eth->soc->mdio_read || !eth->soc->mdio_write)
return 0;
spin_lock_init(&phy_ralink.lock);
eth->phy = &phy_ralink;
mii_np = of_get_child_by_name(eth->dev->of_node, "mdio-bus");
if (!mii_np) {
dev_err(eth->dev, "no %s child node found", "mdio-bus");
return -ENODEV;
}
if (!of_device_is_available(mii_np)) {
err = 0;
goto err_put_node;
}
eth->mii_bus = mdiobus_alloc();
if (!eth->mii_bus) {
err = -ENOMEM;
goto err_put_node;
}
eth->mii_bus->name = "mdio";
eth->mii_bus->read = eth->soc->mdio_read;
eth->mii_bus->write = eth->soc->mdio_write;
eth->mii_bus->reset = mtk_mdio_reset;
eth->mii_bus->priv = eth;
eth->mii_bus->parent = eth->dev;
snprintf(eth->mii_bus->id, MII_BUS_ID_SIZE, "%pOFn", mii_np);
err = of_mdiobus_register(eth->mii_bus, mii_np);
if (err)
goto err_free_bus;
return 0;
err_free_bus:
kfree(eth->mii_bus);
err_put_node:
of_node_put(mii_np);
eth->mii_bus = NULL;
return err;
}
void mtk_mdio_cleanup(struct mtk_eth *eth)
{
if (!eth->mii_bus)
return;
mdiobus_unregister(eth->mii_bus);
of_node_put(eth->mii_bus->dev.of_node);
kfree(eth->mii_bus);
}
/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
*/
#ifndef _RALINK_MDIO_H__
#define _RALINK_MDIO_H__
#ifdef CONFIG_NET_MEDIATEK_MDIO
int mtk_mdio_init(struct mtk_eth *eth);
void mtk_mdio_cleanup(struct mtk_eth *eth);
int mtk_connect_phy_node(struct mtk_eth *eth, struct mtk_mac *mac,
struct device_node *phy_node);
#else
static inline int mtk_mdio_init(struct mtk_eth *eth) { return 0; }
static inline void mtk_mdio_cleanup(struct mtk_eth *eth) {}
#endif
#endif
/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include "mtk_eth_soc.h"
#include "gsw_mt7620.h"
#include "mdio.h"
static int mt7620_mii_busy_wait(struct mt7620_gsw *gsw)
{
unsigned long t_start = jiffies;
while (1) {
if (!(mtk_switch_r32(gsw,
gsw->piac_offset + MT7620_GSW_REG_PIAC) &
GSW_MDIO_ACCESS))
return 0;
if (time_after(jiffies, t_start + GSW_REG_PHY_TIMEOUT))
break;
}
dev_err(gsw->dev, "mdio: MDIO timeout\n");
return -1;
}
u32 _mt7620_mii_write(struct mt7620_gsw *gsw, u32 phy_addr,
u32 phy_register, u32 write_data)
{
if (mt7620_mii_busy_wait(gsw))
return -1;
write_data &= 0xffff;
mtk_switch_w32(gsw, GSW_MDIO_ACCESS | GSW_MDIO_START | GSW_MDIO_WRITE |
(phy_register << GSW_MDIO_REG_SHIFT) |
(phy_addr << GSW_MDIO_ADDR_SHIFT) | write_data,
MT7620_GSW_REG_PIAC);
if (mt7620_mii_busy_wait(gsw))
return -1;
return 0;
}
EXPORT_SYMBOL_GPL(_mt7620_mii_write);
u32 _mt7620_mii_read(struct mt7620_gsw *gsw, int phy_addr, int phy_reg)
{
u32 d;
if (mt7620_mii_busy_wait(gsw))
return 0xffff;
mtk_switch_w32(gsw, GSW_MDIO_ACCESS | GSW_MDIO_START | GSW_MDIO_READ |
(phy_reg << GSW_MDIO_REG_SHIFT) |
(phy_addr << GSW_MDIO_ADDR_SHIFT),
MT7620_GSW_REG_PIAC);
if (mt7620_mii_busy_wait(gsw))
return 0xffff;
d = mtk_switch_r32(gsw, MT7620_GSW_REG_PIAC) & 0xffff;
return d;
}
EXPORT_SYMBOL_GPL(_mt7620_mii_read);
int mt7620_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val)
{
struct mtk_eth *eth = bus->priv;
struct mt7620_gsw *gsw = (struct mt7620_gsw *)eth->sw_priv;
return _mt7620_mii_write(gsw, phy_addr, phy_reg, val);
}
int mt7620_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg)
{
struct mtk_eth *eth = bus->priv;
struct mt7620_gsw *gsw = (struct mt7620_gsw *)eth->sw_priv;
return _mt7620_mii_read(gsw, phy_addr, phy_reg);
}
void mt7530_mdio_w32(struct mt7620_gsw *gsw, u32 reg, u32 val)
{
_mt7620_mii_write(gsw, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
_mt7620_mii_write(gsw, 0x1f, (reg >> 2) & 0xf, val & 0xffff);
_mt7620_mii_write(gsw, 0x1f, 0x10, val >> 16);
}
EXPORT_SYMBOL_GPL(mt7530_mdio_w32);
u32 mt7530_mdio_r32(struct mt7620_gsw *gsw, u32 reg)
{
u16 high, low;
_mt7620_mii_write(gsw, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
low = _mt7620_mii_read(gsw, 0x1f, (reg >> 2) & 0xf);
high = _mt7620_mii_read(gsw, 0x1f, 0x10);
return (high << 16) | (low & 0xffff);
}
EXPORT_SYMBOL_GPL(mt7530_mdio_r32);
void mt7530_mdio_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, u32 reg)
{
u32 val = mt7530_mdio_r32(gsw, reg);
val &= ~mask;
val |= set;
mt7530_mdio_w32(gsw, reg, val);
}
EXPORT_SYMBOL_GPL(mt7530_mdio_m32);
static unsigned char *mtk_speed_str(int speed)
{
switch (speed) {
case 2:
case SPEED_1000:
return "1000";
case 1:
case SPEED_100:
return "100";
case 0:
case SPEED_10:
return "10";
}
return "? ";
}
int mt7620_has_carrier(struct mtk_eth *eth)
{
struct mt7620_gsw *gsw = (struct mt7620_gsw *)eth->sw_priv;
int i;
for (i = 0; i < GSW_PORT6; i++)
if (mt7530_mdio_r32(gsw, GSW_REG_PORT_STATUS(i)) & 0x1)
return 1;
return 0;
}
void mt7620_print_link_state(struct mtk_eth *eth, int port, int link,
int speed, int duplex)
{
struct mt7620_gsw *gsw = eth->sw_priv;
if (link)
dev_info(gsw->dev, "port %d link up (%sMbps/%s duplex)\n",
port, mtk_speed_str(speed),
(duplex) ? "Full" : "Half");
else
dev_info(gsw->dev, "port %d link down\n", port);
}
void mt7620_mdio_link_adjust(struct mtk_eth *eth, int port)
{
mt7620_print_link_state(eth, port, eth->link[port],
eth->phy->speed[port],
(eth->phy->duplex[port] == DUPLEX_FULL));
}
This diff is collapsed.
This diff is collapsed.
/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/if_vlan.h>
#include <linux/of_net.h>
#include <asm/mach-ralink/ralink_regs.h>
#include "mtk_eth_soc.h"
#include "gsw_mt7620.h"
#include "mdio.h"
#define MT7620_CDMA_CSG_CFG 0x400
#define MT7621_CDMP_IG_CTRL (MT7620_CDMA_CSG_CFG + 0x00)
#define MT7621_CDMP_EG_CTRL (MT7620_CDMA_CSG_CFG + 0x04)
#define MT7621_RESET_FE BIT(6)
#define MT7621_L4_VALID BIT(24)
#define MT7621_TX_DMA_UDF BIT(19)
#define CDMA_ICS_EN BIT(2)
#define CDMA_UCS_EN BIT(1)
#define CDMA_TCS_EN BIT(0)
#define GDMA_ICS_EN BIT(22)
#define GDMA_TCS_EN BIT(21)
#define GDMA_UCS_EN BIT(20)
/* frame engine counters */
#define MT7621_REG_MIB_OFFSET 0x2000
#define MT7621_PPE_AC_BCNT0 (MT7621_REG_MIB_OFFSET + 0x00)
#define MT7621_GDM1_TX_GBCNT (MT7621_REG_MIB_OFFSET + 0x400)
#define MT7621_GDM2_TX_GBCNT (MT7621_GDM1_TX_GBCNT + 0x40)
#define GSW_REG_GDMA1_MAC_ADRL 0x508
#define GSW_REG_GDMA1_MAC_ADRH 0x50C
#define GSW_REG_GDMA2_MAC_ADRL 0x1508
#define GSW_REG_GDMA2_MAC_ADRH 0x150C
#define MT7621_MTK_RST_GL 0x04
#define MT7620_MTK_INT_STATUS2 0x08
/* MTK_INT_STATUS reg on mt7620 define CNT_GDM1_AF at BIT(29)
* but after test it should be BIT(13).
*/
#define MT7621_MTK_GDM1_AF BIT(28)
#define MT7621_MTK_GDM2_AF BIT(29)
static const u16 mt7621_reg_table[MTK_REG_COUNT] = {
[MTK_REG_PDMA_GLO_CFG] = RT5350_PDMA_GLO_CFG,
[MTK_REG_PDMA_RST_CFG] = RT5350_PDMA_RST_CFG,
[MTK_REG_DLY_INT_CFG] = RT5350_DLY_INT_CFG,
[MTK_REG_TX_BASE_PTR0] = RT5350_TX_BASE_PTR0,
[MTK_REG_TX_MAX_CNT0] = RT5350_TX_MAX_CNT0,
[MTK_REG_TX_CTX_IDX0] = RT5350_TX_CTX_IDX0,
[MTK_REG_TX_DTX_IDX0] = RT5350_TX_DTX_IDX0,
[MTK_REG_RX_BASE_PTR0] = RT5350_RX_BASE_PTR0,
[MTK_REG_RX_MAX_CNT0] = RT5350_RX_MAX_CNT0,
[MTK_REG_RX_CALC_IDX0] = RT5350_RX_CALC_IDX0,
[MTK_REG_RX_DRX_IDX0] = RT5350_RX_DRX_IDX0,
[MTK_REG_MTK_INT_ENABLE] = RT5350_MTK_INT_ENABLE,
[MTK_REG_MTK_INT_STATUS] = RT5350_MTK_INT_STATUS,
[MTK_REG_MTK_DMA_VID_BASE] = 0,
[MTK_REG_MTK_COUNTER_BASE] = MT7621_GDM1_TX_GBCNT,
[MTK_REG_MTK_RST_GL] = MT7621_MTK_RST_GL,
[MTK_REG_MTK_INT_STATUS2] = MT7620_MTK_INT_STATUS2,
};
static void mt7621_mtk_reset(struct mtk_eth *eth)
{
mtk_reset(eth, MT7621_RESET_FE);
}
static int mt7621_fwd_config(struct mtk_eth *eth)
{
/* Setup GMAC1 only, there is no support for GMAC2 yet */
mtk_w32(eth, mtk_r32(eth, MT7620_GDMA1_FWD_CFG) & ~0xffff,
MT7620_GDMA1_FWD_CFG);
/* Enable RX checksum */
mtk_w32(eth, mtk_r32(eth, MT7620_GDMA1_FWD_CFG) | (GDMA_ICS_EN |
GDMA_TCS_EN | GDMA_UCS_EN),
MT7620_GDMA1_FWD_CFG);
/* Enable RX VLan Offloading */
mtk_w32(eth, 0, MT7621_CDMP_EG_CTRL);
return 0;
}
static void mt7621_set_mac(struct mtk_mac *mac, unsigned char *hwaddr)
{
unsigned long flags;
spin_lock_irqsave(&mac->hw->page_lock, flags);
if (mac->id == 0) {
mtk_w32(mac->hw, (hwaddr[0] << 8) | hwaddr[1],
GSW_REG_GDMA1_MAC_ADRH);
mtk_w32(mac->hw, (hwaddr[2] << 24) | (hwaddr[3] << 16) |
(hwaddr[4] << 8) | hwaddr[5],
GSW_REG_GDMA1_MAC_ADRL);
}
if (mac->id == 1) {
mtk_w32(mac->hw, (hwaddr[0] << 8) | hwaddr[1],
GSW_REG_GDMA2_MAC_ADRH);
mtk_w32(mac->hw, (hwaddr[2] << 24) | (hwaddr[3] << 16) |
(hwaddr[4] << 8) | hwaddr[5],
GSW_REG_GDMA2_MAC_ADRL);
}
spin_unlock_irqrestore(&mac->hw->page_lock, flags);
}
static struct mtk_soc_data mt7621_data = {
.hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
NETIF_F_IPV6_CSUM,
.dma_type = MTK_PDMA,
.dma_ring_size = 256,
.napi_weight = 64,
.new_stats = 1,
.padding_64b = 1,
.rx_2b_offset = 1,
.rx_sg_dma = 1,
.has_switch = 1,
.mac_count = 2,
.reset_fe = mt7621_mtk_reset,
.set_mac = mt7621_set_mac,
.fwd_config = mt7621_fwd_config,
.switch_init = mtk_gsw_init,
.reg_table = mt7621_reg_table,
.pdma_glo_cfg = MTK_PDMA_SIZE_16DWORDS,
.rx_int = RT5350_RX_DONE_INT,
.tx_int = RT5350_TX_DONE_INT,
.status_int = MT7621_MTK_GDM1_AF | MT7621_MTK_GDM2_AF,
.checksum_bit = MT7621_L4_VALID,
.has_carrier = mt7620_has_carrier,
.mdio_read = mt7620_mdio_read,
.mdio_write = mt7620_mdio_write,
.mdio_adjust_link = mt7620_mdio_link_adjust,
};
const struct of_device_id of_mtk_match[] = {
{ .compatible = "mediatek,mt7621-eth", .data = &mt7621_data },
{},
};
MODULE_DEVICE_TABLE(of, of_mtk_match);
config PCI_MT7621
tristate "MediaTek MT7621 PCI Controller"
depends on RALINK
depends on PCI
select PCI_DRIVERS_GENERIC
help
This selects a driver for the MediaTek MT7621 PCI Controller.
......
......@@ -163,7 +163,7 @@ int cvm_oct_phy_setup_device(struct net_device *dev)
goto no_phy;
phydev = of_phy_connect(dev, phy_node, cvm_oct_adjust_link, 0,
PHY_INTERFACE_MODE_GMII);
priv->phy_mode);
of_node_put(phy_node);
if (!phydev)
......
......@@ -653,14 +653,37 @@ static struct device_node *cvm_oct_node_for_port(struct device_node *pip,
return np;
}
static void cvm_set_rgmii_delay(struct device_node *np, int iface, int port)
static void cvm_set_rgmii_delay(struct octeon_ethernet *priv, int iface,
int port)
{
struct device_node *np = priv->of_node;
u32 delay_value;
bool rx_delay;
bool tx_delay;
if (!of_property_read_u32(np, "rx-delay", &delay_value))
/* By default, both RX/TX delay is enabled in
* __cvmx_helper_rgmii_enable().
*/
rx_delay = true;
tx_delay = true;
if (!of_property_read_u32(np, "rx-delay", &delay_value)) {
cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, iface), delay_value);
if (!of_property_read_u32(np, "tx-delay", &delay_value))
rx_delay = delay_value > 0;
}
if (!of_property_read_u32(np, "tx-delay", &delay_value)) {
cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, iface), delay_value);
tx_delay = delay_value > 0;
}
if (!rx_delay && !tx_delay)
priv->phy_mode = PHY_INTERFACE_MODE_RGMII_ID;
else if (!rx_delay)
priv->phy_mode = PHY_INTERFACE_MODE_RGMII_RXID;
else if (!tx_delay)
priv->phy_mode = PHY_INTERFACE_MODE_RGMII_TXID;
else
priv->phy_mode = PHY_INTERFACE_MODE_RGMII;
}
static int cvm_oct_probe(struct platform_device *pdev)
......@@ -825,6 +848,7 @@ static int cvm_oct_probe(struct platform_device *pdev)
priv->port = port;
priv->queue = cvmx_pko_get_base_queue(priv->port);
priv->fau = fau - cvmx_pko_get_num_queues(port) * 4;
priv->phy_mode = PHY_INTERFACE_MODE_NA;
for (qos = 0; qos < 16; qos++)
skb_queue_head_init(&priv->tx_free_list[qos]);
for (qos = 0; qos < cvmx_pko_get_num_queues(port);
......@@ -856,6 +880,7 @@ static int cvm_oct_probe(struct platform_device *pdev)
break;
case CVMX_HELPER_INTERFACE_MODE_SGMII:
priv->phy_mode = PHY_INTERFACE_MODE_SGMII;
dev->netdev_ops = &cvm_oct_sgmii_netdev_ops;
strcpy(dev->name, "eth%d");
break;
......@@ -865,11 +890,16 @@ static int cvm_oct_probe(struct platform_device *pdev)
strcpy(dev->name, "spi%d");
break;
case CVMX_HELPER_INTERFACE_MODE_RGMII:
case CVMX_HELPER_INTERFACE_MODE_GMII:
priv->phy_mode = PHY_INTERFACE_MODE_GMII;
dev->netdev_ops = &cvm_oct_rgmii_netdev_ops;
strcpy(dev->name, "eth%d");
break;
case CVMX_HELPER_INTERFACE_MODE_RGMII:
dev->netdev_ops = &cvm_oct_rgmii_netdev_ops;
strcpy(dev->name, "eth%d");
cvm_set_rgmii_delay(priv->of_node, interface,
cvm_set_rgmii_delay(priv, interface,
port_index);
break;
}
......
......@@ -12,7 +12,7 @@
#define OCTEON_ETHERNET_H
#include <linux/of.h>
#include <linux/phy.h>
#include <asm/octeon/cvmx-helper-board.h>
/**
......@@ -33,6 +33,8 @@ struct octeon_ethernet {
* cvmx_helper_interface_mode_t
*/
int imode;
/* PHY mode */
phy_interface_t phy_mode;
/* List of outstanding tx buffers per queue */
struct sk_buff_head tx_free_list[16];
unsigned int last_speed;
......
......@@ -45,7 +45,7 @@ static int dcon_init_xo_1(struct dcon_priv *dcon)
{
unsigned char lob;
int ret, i;
struct dcon_gpio *pin = &gpios_asis[0];
const struct dcon_gpio *pin = &gpios_asis[0];
for (i = 0; i < ARRAY_SIZE(gpios_asis); i++) {
gpios[i] = devm_gpiod_get(&dcon->client->dev, pin[i].name,
......
This diff is collapsed.
......@@ -336,7 +336,7 @@ s32 rtw_txframes_sta_ac_pending(struct adapter *padapter,
void rtw_init_hwxmits(struct hw_xmit *phwxmit, int entry);
s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter);
void _rtw_free_xmit_priv(struct xmit_priv *pxmitpriv);
void rtw_alloc_hwxmits(struct adapter *padapter);
s32 rtw_alloc_hwxmits(struct adapter *padapter);
void rtw_free_hwxmits(struct adapter *padapter);
s32 rtw_xmit(struct adapter *padapter, struct sk_buff **pkt);
......
......@@ -147,17 +147,9 @@ static u8 write_macreg_hdl(struct _adapter *padapter, u8 *pbuf)
static u8 read_bbreg_hdl(struct _adapter *padapter, u8 *pbuf)
{
u32 val;
void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd);
struct cmd_obj *pcmd = (struct cmd_obj *)pbuf;
if (pcmd->rsp && pcmd->rspsz > 0)
memcpy(pcmd->rsp, (u8 *)&val, pcmd->rspsz);
pcmd_callback = cmd_callback[pcmd->cmdcode].callback;
if (!pcmd_callback)
r8712_free_cmd_obj(pcmd);
else
pcmd_callback(padapter, pcmd);
return H2C_SUCCESS;
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment