ramips: preliminary support for 4.14

- removed upstreamed patches
- 0901-spansion_nand_id_fix.patch is disabled, not clear if it's needed

Signed-off-by: Roman Yeryomin <roman@advem.lv>
Signed-off-by: John Crispin <john@phrozen.org>
This commit is contained in:
Roman Yeryomin 2018-01-17 00:07:58 +02:00 committed by John Crispin
parent a3b9cbafc3
commit f4e5880d0f
77 changed files with 27451 additions and 24 deletions

View file

@ -30,11 +30,9 @@ Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
kernel/exit.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/kernel/exit.c b/kernel/exit.c
index 6b4298a41167..df0c91d5606c 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -1755,3 +1755,11 @@ COMPAT_SYSCALL_DEFINE5(waitid,
@@ -1755,3 +1755,11 @@ Efault:
return -EFAULT;
}
#endif
@ -46,6 +44,3 @@ index 6b4298a41167..df0c91d5606c 100644
+ /* if that doesn't kill us, halt */
+ panic("Oops failed to kill thread");
+}
--
2.11.0

View file

@ -24,11 +24,9 @@ Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
kernel/exit.c | 1 +
4 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 5cf04888c581..3e26c6f7a191 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -793,7 +793,6 @@ void abort(void)
@@ -790,7 +790,6 @@ void abort(void)
/* if that doesn't kill us, halt */
panic("Oops failed to kill thread");
}
@ -36,8 +34,6 @@ index 5cf04888c581..3e26c6f7a191 100644
void __init trap_init(void)
{
diff --git a/arch/m32r/kernel/traps.c b/arch/m32r/kernel/traps.c
index cb79fba79d43..b88a8dd14933 100644
--- a/arch/m32r/kernel/traps.c
+++ b/arch/m32r/kernel/traps.c
@@ -122,7 +122,6 @@ void abort(void)
@ -48,8 +44,6 @@ index cb79fba79d43..b88a8dd14933 100644
void __init trap_init(void)
{
diff --git a/arch/unicore32/kernel/traps.c b/arch/unicore32/kernel/traps.c
index 5f25b39f04d4..c4ac6043ebb0 100644
--- a/arch/unicore32/kernel/traps.c
+++ b/arch/unicore32/kernel/traps.c
@@ -298,7 +298,6 @@ void abort(void)
@ -60,8 +54,6 @@ index 5f25b39f04d4..c4ac6043ebb0 100644
void __init trap_init(void)
{
diff --git a/kernel/exit.c b/kernel/exit.c
index df0c91d5606c..995453d9fb55 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -1763,3 +1763,4 @@ __weak void abort(void)
@ -69,6 +61,3 @@ index df0c91d5606c..995453d9fb55 100644
panic("Oops failed to kill thread");
}
+EXPORT_SYMBOL(abort);
--
2.11.0

View file

@ -133,8 +133,8 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
}
+#endif
check_modinfo_retpoline(mod, info);
check_modinfo_retpoline(mod, info);
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1982,7 +1982,9 @@ static void read_symbols(char *modname)
@ -172,12 +172,12 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
static void add_retpoline(struct buffer *b)
{
+#ifndef CONFIG_MODULE_STRIPPED
buf_printf(b, "\n#ifdef RETPOLINE\n");
buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n");
buf_printf(b, "#endif\n");
buf_printf(b, "\n#ifdef RETPOLINE\n");
buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n");
buf_printf(b, "#endif\n");
+#endif
}
static void add_staging_flag(struct buffer *b, const char *name)
{
+#ifndef CONFIG_MODULE_STRIPPED

View file

@ -0,0 +1,62 @@
config NET_VENDOR_MEDIATEK
tristate "Mediatek/Ralink ethernet driver"
depends on RALINK
help
This driver supports the ethernet mac inside the Mediatek and Ralink WiSoCs
config NET_MEDIATEK_SOC
def_tristate NET_VENDOR_MEDIATEK
if NET_MEDIATEK_SOC
choice
prompt "MAC type"
config NET_MEDIATEK_RT2880
bool "RT2882"
depends on MIPS && SOC_RT288X
config NET_MEDIATEK_RT3050
bool "RT3050/MT7628"
depends on MIPS && (SOC_RT305X || SOC_MT7620)
config NET_MEDIATEK_RT3883
bool "RT3883"
depends on MIPS && SOC_RT3883
config NET_MEDIATEK_MT7620
bool "MT7620"
depends on MIPS && SOC_MT7620
config NET_MEDIATEK_MT7621
bool "MT7621"
depends on MIPS && SOC_MT7621
endchoice
config NET_MEDIATEK_MDIO
def_bool NET_MEDIATEK_SOC
depends on (NET_MEDIATEK_RT2880 || NET_MEDIATEK_RT3883 || NET_MEDIATEK_MT7620 || NET_MEDIATEK_MT7621)
select PHYLIB
config NET_MEDIATEK_MDIO_RT2880
def_bool NET_MEDIATEK_SOC
depends on (NET_MEDIATEK_RT2880 || NET_MEDIATEK_RT3883)
select NET_MEDIATEK_MDIO
config NET_MEDIATEK_MDIO_MT7620
def_bool NET_MEDIATEK_SOC
depends on (NET_MEDIATEK_MT7620 || NET_MEDIATEK_MT7621)
select NET_MEDIATEK_MDIO
config NET_MEDIATEK_ESW_RT3050
def_tristate NET_MEDIATEK_SOC
depends on NET_MEDIATEK_RT3050
config NET_MEDIATEK_GSW_MT7620
def_tristate NET_MEDIATEK_SOC
depends on NET_MEDIATEK_MT7620
config NET_MEDIATEK_GSW_MT7621
def_tristate NET_MEDIATEK_SOC
depends on NET_MEDIATEK_MT7621
endif

View file

@ -0,0 +1,20 @@
#
# 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_RT2880) += mdio_rt2880.o
mtk-eth-soc-$(CONFIG_NET_MEDIATEK_MDIO_MT7620) += mdio_mt7620.o
mtk-eth-soc-$(CONFIG_NET_MEDIATEK_RT2880) += soc_rt2880.o
mtk-eth-soc-$(CONFIG_NET_MEDIATEK_RT3050) += soc_rt3050.o
mtk-eth-soc-$(CONFIG_NET_MEDIATEK_RT3883) += soc_rt3883.o
mtk-eth-soc-$(CONFIG_NET_MEDIATEK_MT7620) += soc_mt7620.o
mtk-eth-soc-$(CONFIG_NET_MEDIATEK_MT7621) += soc_mt7621.o
obj-$(CONFIG_NET_MEDIATEK_ESW_RT3050) += esw_rt3050.o
obj-$(CONFIG_NET_MEDIATEK_GSW_MT7620) += gsw_mt7620.o mt7530.o
obj-$(CONFIG_NET_MEDIATEK_GSW_MT7621) += gsw_mt7621.o mt7530.o
obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk-eth-soc.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,29 @@
/* 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-2015 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2013-2015 Michael Lee <igvtee@gmail.com>
*/
#ifndef _RALINK_ESW_RT3052_H__
#define _RALINK_ESW_RT3052_H__
#ifdef CONFIG_NET_MEDIATEK_ESW_RT3052
int __init mtk_switch_init(void);
void mtk_switch_exit(void);
#else
static inline int __init mtk_switch_init(void) { return 0; }
static inline void mtk_switch_exit(void) { }
#endif
#endif

View file

@ -0,0 +1,230 @@
/* 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-2015 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2013-2015 Michael Lee <igvtee@gmail.com>
*/
#include "mtk_eth_soc.h"
static const char fe_gdma_str[][ETH_GSTRING_LEN] = {
#define _FE(x...) # x,
FE_STAT_REG_DECLARE
#undef _FE
};
static int fe_get_link_ksettings(struct net_device *ndev,
struct ethtool_link_ksettings *cmd)
{
struct fe_priv *priv = netdev_priv(ndev);
if (!priv->phy_dev)
return -ENODEV;
if (priv->phy_flags == FE_PHY_FLAG_ATTACH) {
if (phy_read_status(priv->phy_dev))
return -ENODEV;
}
phy_ethtool_ksettings_get(ndev->phydev, cmd);
return 0;
}
static int fe_set_link_ksettings(struct net_device *ndev,
const struct ethtool_link_ksettings *cmd)
{
struct fe_priv *priv = netdev_priv(ndev);
if (!priv->phy_dev)
goto out_sset;
if (cmd->base.phy_address != priv->phy_dev->mdio.addr) {
if (priv->phy->phy_node[cmd->base.phy_address]) {
priv->phy_dev = priv->phy->phy[cmd->base.phy_address];
priv->phy_flags = FE_PHY_FLAG_PORT;
} else if (priv->mii_bus && mdiobus_get_phy(priv->mii_bus, cmd->base.phy_address)) {
priv->phy_dev = mdiobus_get_phy(priv->mii_bus, cmd->base.phy_address);
priv->phy_flags = FE_PHY_FLAG_ATTACH;
} else {
goto out_sset;
}
}
return phy_ethtool_ksettings_set(ndev->phydev, cmd);
out_sset:
return -ENODEV;
}
static void fe_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct fe_priv *priv = netdev_priv(dev);
struct fe_soc_data *soc = priv->soc;
strlcpy(info->driver, priv->device->driver->name, sizeof(info->driver));
strlcpy(info->version, MTK_FE_DRV_VERSION, sizeof(info->version));
strlcpy(info->bus_info, dev_name(priv->device), sizeof(info->bus_info));
if (soc->reg_table[FE_REG_FE_COUNTER_BASE])
info->n_stats = ARRAY_SIZE(fe_gdma_str);
}
static u32 fe_get_msglevel(struct net_device *dev)
{
struct fe_priv *priv = netdev_priv(dev);
return priv->msg_enable;
}
static void fe_set_msglevel(struct net_device *dev, u32 value)
{
struct fe_priv *priv = netdev_priv(dev);
priv->msg_enable = value;
}
static int fe_nway_reset(struct net_device *dev)
{
struct fe_priv *priv = netdev_priv(dev);
if (!priv->phy_dev)
goto out_nway_reset;
return genphy_restart_aneg(priv->phy_dev);
out_nway_reset:
return -EOPNOTSUPP;
}
static u32 fe_get_link(struct net_device *dev)
{
struct fe_priv *priv = netdev_priv(dev);
int err;
if (!priv->phy_dev)
goto out_get_link;
if (priv->phy_flags == FE_PHY_FLAG_ATTACH) {
err = genphy_update_link(priv->phy_dev);
if (err)
goto out_get_link;
}
return priv->phy_dev->link;
out_get_link:
return ethtool_op_get_link(dev);
}
static int fe_set_ringparam(struct net_device *dev,
struct ethtool_ringparam *ring)
{
struct fe_priv *priv = netdev_priv(dev);
if ((ring->tx_pending < 2) ||
(ring->rx_pending < 2) ||
(ring->rx_pending > MAX_DMA_DESC) ||
(ring->tx_pending > MAX_DMA_DESC))
return -EINVAL;
dev->netdev_ops->ndo_stop(dev);
priv->tx_ring.tx_ring_size = BIT(fls(ring->tx_pending) - 1);
priv->rx_ring.rx_ring_size = BIT(fls(ring->rx_pending) - 1);
dev->netdev_ops->ndo_open(dev);
return 0;
}
static void fe_get_ringparam(struct net_device *dev,
struct ethtool_ringparam *ring)
{
struct fe_priv *priv = netdev_priv(dev);
ring->rx_max_pending = MAX_DMA_DESC;
ring->tx_max_pending = MAX_DMA_DESC;
ring->rx_pending = priv->rx_ring.rx_ring_size;
ring->tx_pending = priv->tx_ring.tx_ring_size;
}
static void fe_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{
switch (stringset) {
case ETH_SS_STATS:
memcpy(data, *fe_gdma_str, sizeof(fe_gdma_str));
break;
}
}
static int fe_get_sset_count(struct net_device *dev, int sset)
{
switch (sset) {
case ETH_SS_STATS:
return ARRAY_SIZE(fe_gdma_str);
default:
return -EOPNOTSUPP;
}
}
static void fe_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *data)
{
struct fe_priv *priv = netdev_priv(dev);
struct fe_hw_stats *hwstats = priv->hw_stats;
u64 *data_src, *data_dst;
unsigned int start;
int i;
if (netif_running(dev) && netif_device_present(dev)) {
if (spin_trylock(&hwstats->stats_lock)) {
fe_stats_update(priv);
spin_unlock(&hwstats->stats_lock);
}
}
do {
data_src = &hwstats->tx_bytes;
data_dst = data;
start = u64_stats_fetch_begin_irq(&hwstats->syncp);
for (i = 0; i < ARRAY_SIZE(fe_gdma_str); i++)
*data_dst++ = *data_src++;
} while (u64_stats_fetch_retry_irq(&hwstats->syncp, start));
}
static struct ethtool_ops fe_ethtool_ops = {
.get_link_ksettings = fe_get_link_ksettings,
.set_link_ksettings = fe_set_link_ksettings,
.get_drvinfo = fe_get_drvinfo,
.get_msglevel = fe_get_msglevel,
.set_msglevel = fe_set_msglevel,
.nway_reset = fe_nway_reset,
.get_link = fe_get_link,
.set_ringparam = fe_set_ringparam,
.get_ringparam = fe_get_ringparam,
};
void fe_set_ethtool_ops(struct net_device *netdev)
{
struct fe_priv *priv = netdev_priv(netdev);
struct fe_soc_data *soc = priv->soc;
if (soc->reg_table[FE_REG_FE_COUNTER_BASE]) {
fe_ethtool_ops.get_strings = fe_get_strings;
fe_ethtool_ops.get_sset_count = fe_get_sset_count;
fe_ethtool_ops.get_ethtool_stats = fe_get_ethtool_stats;
}
netdev->ethtool_ops = &fe_ethtool_ops;
}

View file

@ -0,0 +1,22 @@
/* 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-2015 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2013-2015 Michael Lee <igvtee@gmail.com>
*/
#ifndef FE_ETHTOOL_H
#define FE_ETHTOOL_H
#include <linux/ethtool.h>
void fe_set_ethtool_ops(struct net_device *netdev);
#endif /* FE_ETHTOOL_H */

View file

@ -0,0 +1,259 @@
/* 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-2015 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2013-2015 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 reg)
{
iowrite32(val, gsw->base + reg);
}
u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned reg)
{
return ioread32(gsw->base + reg);
}
static irqreturn_t gsw_interrupt_mt7620(int irq, void *_priv)
{
struct fe_priv *priv = (struct fe_priv *)_priv;
struct mt7620_gsw *gsw = (struct mt7620_gsw *)priv->soc->swpriv;
u32 status;
int i, max = (gsw->port4 == PORT4_EPHY) ? (4) : (3);
status = mtk_switch_r32(gsw, GSW_REG_ISR);
if (status & PORT_IRQ_ST_CHG)
for (i = 0; i <= max; i++) {
u32 status = mtk_switch_r32(gsw, GSW_REG_PORT_STATUS(i));
int link = status & 0x1;
if (link != priv->link[i])
mt7620_print_link_state(priv, i, link,
(status >> 2) & 3,
(status & 0x2));
priv->link[i] = link;
}
mt7620_handle_carrier(priv);
mtk_switch_w32(gsw, status, GSW_REG_ISR);
return IRQ_HANDLED;
}
static void mt7620_hw_init(struct mt7620_gsw *gsw, struct device_node *np)
{
u32 is_BGA = (rt_sysc_r32(0x0c) >> 16) & 1;
rt_sysc_w32(rt_sysc_r32(SYSC_REG_CFG1) | BIT(8), SYSC_REG_CFG1);
mtk_switch_w32(gsw, mtk_switch_r32(gsw, GSW_REG_CKGCR) & ~(0x3 << 4), GSW_REG_CKGCR);
/* Enable MIB stats */
mtk_switch_w32(gsw, mtk_switch_r32(gsw, GSW_REG_MIB_CNT_EN) | (1 << 1), GSW_REG_MIB_CNT_EN);
if (of_property_read_bool(np, "mediatek,mt7530")) {
u32 val;
/* turn off ephy and set phy base addr to 12 */
mtk_switch_w32(gsw, mtk_switch_r32(gsw, GSW_REG_GPC1) |
(0x1f << 24) | (0xc << 16),
GSW_REG_GPC1);
/* set MT7530 central align */
val = mt7530_mdio_r32(gsw, 0x7830);
val &= ~BIT(0);
val |= BIT(1);
mt7530_mdio_w32(gsw, 0x7830, val);
val = mt7530_mdio_r32(gsw, 0x7a40);
val &= ~BIT(30);
mt7530_mdio_w32(gsw, 0x7a40, val);
mt7530_mdio_w32(gsw, 0x7a78, 0x855);
} else {
/* global page 4 */
_mt7620_mii_write(gsw, 1, 31, 0x4000);
_mt7620_mii_write(gsw, 1, 17, 0x7444);
if (is_BGA)
_mt7620_mii_write(gsw, 1, 19, 0x0114);
else
_mt7620_mii_write(gsw, 1, 19, 0x0117);
_mt7620_mii_write(gsw, 1, 22, 0x10cf);
_mt7620_mii_write(gsw, 1, 25, 0x6212);
_mt7620_mii_write(gsw, 1, 26, 0x0777);
_mt7620_mii_write(gsw, 1, 29, 0x4000);
_mt7620_mii_write(gsw, 1, 28, 0xc077);
_mt7620_mii_write(gsw, 1, 24, 0x0000);
/* global page 3 */
_mt7620_mii_write(gsw, 1, 31, 0x3000);
_mt7620_mii_write(gsw, 1, 17, 0x4838);
/* global page 2 */
_mt7620_mii_write(gsw, 1, 31, 0x2000);
if (is_BGA) {
_mt7620_mii_write(gsw, 1, 21, 0x0515);
_mt7620_mii_write(gsw, 1, 22, 0x0053);
_mt7620_mii_write(gsw, 1, 23, 0x00bf);
_mt7620_mii_write(gsw, 1, 24, 0x0aaf);
_mt7620_mii_write(gsw, 1, 25, 0x0fad);
_mt7620_mii_write(gsw, 1, 26, 0x0fc1);
} else {
_mt7620_mii_write(gsw, 1, 21, 0x0517);
_mt7620_mii_write(gsw, 1, 22, 0x0fd2);
_mt7620_mii_write(gsw, 1, 23, 0x00bf);
_mt7620_mii_write(gsw, 1, 24, 0x0aab);
_mt7620_mii_write(gsw, 1, 25, 0x00ae);
_mt7620_mii_write(gsw, 1, 26, 0x0fff);
}
/* global page 1 */
_mt7620_mii_write(gsw, 1, 31, 0x1000);
_mt7620_mii_write(gsw, 1, 17, 0xe7f8);
}
/* global page 0 */
_mt7620_mii_write(gsw, 1, 31, 0x8000);
_mt7620_mii_write(gsw, 0, 30, 0xa000);
_mt7620_mii_write(gsw, 1, 30, 0xa000);
_mt7620_mii_write(gsw, 2, 30, 0xa000);
_mt7620_mii_write(gsw, 3, 30, 0xa000);
_mt7620_mii_write(gsw, 0, 4, 0x05e1);
_mt7620_mii_write(gsw, 1, 4, 0x05e1);
_mt7620_mii_write(gsw, 2, 4, 0x05e1);
_mt7620_mii_write(gsw, 3, 4, 0x05e1);
/* global page 2 */
_mt7620_mii_write(gsw, 1, 31, 0xa000);
_mt7620_mii_write(gsw, 0, 16, 0x1111);
_mt7620_mii_write(gsw, 1, 16, 0x1010);
_mt7620_mii_write(gsw, 2, 16, 0x1515);
_mt7620_mii_write(gsw, 3, 16, 0x0f0f);
/* CPU Port6 Force Link 1G, FC ON */
mtk_switch_w32(gsw, 0x5e33b, GSW_REG_PORT_PMCR(6));
/* Set Port 6 as CPU Port */
mtk_switch_w32(gsw, 0x7f7f7fe0, 0x0010);
/* setup port 4 */
if (gsw->port4 == PORT4_EPHY) {
u32 val = rt_sysc_r32(SYSC_REG_CFG1);
val |= 3 << 14;
rt_sysc_w32(val, SYSC_REG_CFG1);
_mt7620_mii_write(gsw, 4, 30, 0xa000);
_mt7620_mii_write(gsw, 4, 4, 0x05e1);
_mt7620_mii_write(gsw, 4, 16, 0x1313);
pr_info("gsw: setting port4 to ephy mode\n");
}
}
static const struct of_device_id mediatek_gsw_match[] = {
{ .compatible = "mediatek,mt7620-gsw" },
{},
};
MODULE_DEVICE_TABLE(of, mediatek_gsw_match);
int mtk_gsw_init(struct fe_priv *priv)
{
struct device_node *np = priv->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);
priv->soc->swpriv = gsw;
mt7620_hw_init(gsw, np);
if (gsw->irq) {
request_irq(gsw->irq, gsw_interrupt_mt7620, 0,
"gsw", priv);
mtk_switch_w32(gsw, ~PORT_IRQ_ST_CHG, GSW_REG_IMR);
}
return 0;
}
static int mt7620_gsw_probe(struct platform_device *pdev)
{
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
const char *port4 = NULL;
struct mt7620_gsw *gsw;
struct device_node *np = pdev->dev.of_node;
gsw = devm_kzalloc(&pdev->dev, sizeof(struct mt7620_gsw), GFP_KERNEL);
if (!gsw)
return -ENOMEM;
gsw->base = devm_ioremap_resource(&pdev->dev, res);
if (!gsw->base)
return -EADDRNOTAVAIL;
gsw->dev = &pdev->dev;
of_property_read_string(np, "mediatek,port4", &port4);
if (port4 && !strcmp(port4, "ephy"))
gsw->port4 = PORT4_EPHY;
else if (port4 && !strcmp(port4, "gmac"))
gsw->port4 = PORT4_EXT;
else
gsw->port4 = PORT4_EPHY;
gsw->irq = platform_get_irq(pdev, 0);
platform_set_drvdata(pdev, gsw);
return 0;
}
static int mt7620_gsw_remove(struct platform_device *pdev)
{
platform_set_drvdata(pdev, NULL);
return 0;
}
static struct platform_driver gsw_driver = {
.probe = mt7620_gsw_probe,
.remove = mt7620_gsw_remove,
.driver = {
.name = "mt7620-gsw",
.owner = THIS_MODULE,
.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 MT7620 SoC");
MODULE_VERSION(MTK_FE_DRV_VERSION);

View file

@ -0,0 +1,127 @@
/* 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-2015 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2013-2015 Michael Lee <igvtee@gmail.com>
*/
#ifndef _RALINK_GSW_MT7620_H__
#define _RALINK_GSW_MT7620_H__
#define GSW_REG_PHY_TIMEOUT (5 * HZ)
#ifdef CONFIG_SOC_MT7621
#define MT7620A_GSW_REG_PIAC 0x0004
#else
#define MT7620A_GSW_REG_PIAC 0x7004
#endif
#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_MIB_CNT_EN 0x4000
#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 GSW_REG_MAC_P0_MCR 0x100
#define GSW_REG_MAC_P1_MCR 0x200
// Global MAC control register
#define GSW_REG_GMACCR 0x30E0
#define SYSC_REG_CHIP_REV_ID 0x0c
#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
#ifdef CONFIG_SOC_MT7621
#define ESW_PHY_POLLING 0x0000
#else
#define ESW_PHY_POLLING 0x7000
#endif
#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)
enum {
/* Global attributes. */
GSW_ATTR_ENABLE_VLAN,
/* Port attributes. */
GSW_ATTR_PORT_UNTAG,
};
enum {
PORT4_EPHY = 0,
PORT4_EXT,
};
struct mt7620_gsw {
struct device *dev;
void __iomem *base;
int irq;
int port4;
unsigned long int autopoll;
};
void mtk_switch_w32(struct mt7620_gsw *gsw, u32 val, unsigned reg);
u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned reg);
int mtk_gsw_init(struct fe_priv *priv);
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 fe_priv *priv, int port);
int mt7620_has_carrier(struct fe_priv *priv);
void mt7620_print_link_state(struct fe_priv *priv, 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);
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 fe_priv *priv);
#endif

View file

@ -0,0 +1,289 @@
/* 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-2015 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2013-2015 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 reg)
{
iowrite32(val, gsw->base + reg);
}
u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned reg)
{
return ioread32(gsw->base + reg);
}
static irqreturn_t gsw_interrupt_mt7621(int irq, void *_priv)
{
struct fe_priv *priv = (struct fe_priv *)_priv;
struct mt7620_gsw *gsw = (struct mt7620_gsw *)priv->soc->swpriv;
u32 reg, i;
reg = mt7530_mdio_r32(gsw, 0x700c);
for (i = 0; i < 5; i++)
if (reg & BIT(i)) {
unsigned int link;
link = mt7530_mdio_r32(gsw,
0x3008 + (i * 0x100)) & 0x1;
if (link != priv->link[i]) {
priv->link[i] = link;
if (link)
netdev_info(priv->netdev,
"port %d link up\n", i);
else
netdev_info(priv->netdev,
"port %d link down\n", i);
}
}
mt7620_handle_carrier(priv);
mt7530_mdio_w32(gsw, 0x700c, 0x1f);
return IRQ_HANDLED;
}
static void mt7621_hw_init(struct mt7620_gsw *gsw, struct device_node *np)
{
u32 i;
u32 val;
/* wardware reset the switch */
fe_reset(RST_CTRL_MCM);
mdelay(10);
/* reduce RGMII2 PAD driving strength */
rt_sysc_m32(3 << 4, 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(3 << 12, 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, 0x7000, 0x3);
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, 0x2305e30b, GSW_REG_MAC_P0_MCR);
mt7530_mdio_w32(gsw, 0x3600, 0x5e30b);
} else {
/* (GE1, Force 1000M/FD, FC ON, MAX_RX_LENGTH 1536) */
mtk_switch_w32(gsw, 0x2305e33b, GSW_REG_MAC_P0_MCR);
mt7530_mdio_w32(gsw, 0x3600, 0x5e33b);
}
/* (GE2, Link down) */
mtk_switch_w32(gsw, 0x8000, GSW_REG_MAC_P1_MCR);
/* Set switch max RX frame length to 2k */
mt7530_mdio_w32(gsw, GSW_REG_GMACCR, 0x3F0B);
/* Enable Port 6, P5 as GMAC5, P5 disable */
val = mt7530_mdio_r32(gsw, 0x7804);
val &= ~BIT(8);
val |= BIT(6) | BIT(13) | BIT(16);
mt7530_mdio_w32(gsw, 0x7804, val);
val = rt_sysc_r32(0x10);
val = (val >> 6) & 0x7;
if (val >= 6) {
/* 25Mhz Xtal - do nothing */
} else if (val >= 3) {
/* 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);
} else {
/* 20Mhz Xtal - TODO */
}
/* RGMII */
_mt7620_mii_write(gsw, 0, 14, 0x1);
/* set MT7530 central align */
val = mt7530_mdio_r32(gsw, 0x7830);
val &= ~BIT(0);
val |= BIT(1);
mt7530_mdio_w32(gsw, 0x7830, val);
val = mt7530_mdio_r32(gsw, 0x7a40);
val &= ~BIT(30);
mt7530_mdio_w32(gsw, 0x7a40, val);
mt7530_mdio_w32(gsw, 0x7a78, 0x855);
/* delay setting for 10/1000M */
mt7530_mdio_w32(gsw, 0x7b00, 0x102);
mt7530_mdio_w32(gsw, 0x7b04, 0x14);
/* lower Tx Driving*/
mt7530_mdio_w32(gsw, 0x7a54, 0x44);
mt7530_mdio_w32(gsw, 0x7a5c, 0x44);
mt7530_mdio_w32(gsw, 0x7a64, 0x44);
mt7530_mdio_w32(gsw, 0x7a6c, 0x44);
mt7530_mdio_w32(gsw, 0x7a74, 0x44);
mt7530_mdio_w32(gsw, 0x7a7c, 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);
}
/* mask irq */
mt7530_mdio_w32(gsw, 0x7008, 0x1f);
/* enable irq */
val = mt7530_mdio_r32(gsw, 0x7808);
val |= 3 << 16;
mt7530_mdio_w32(gsw, 0x7808, val);
}
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 fe_priv *priv)
{
struct device_node *np = priv->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);
priv->soc->swpriv = gsw;
if (gsw->irq) {
request_irq(gsw->irq, gsw_interrupt_mt7621, 0,
"gsw", priv);
mt7530_mdio_w32(gsw, 0x7008, ~0x1f);
}
mt7621_hw_init(gsw, np);
return 0;
}
static int mt7621_gsw_probe(struct platform_device *pdev)
{
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
const char *port4 = NULL;
struct mt7620_gsw *gsw;
struct device_node *np;
gsw = devm_kzalloc(&pdev->dev, sizeof(struct mt7620_gsw), GFP_KERNEL);
if (!gsw)
return -ENOMEM;
gsw->base = devm_ioremap_resource(&pdev->dev, res);
if (!gsw->base)
return -EADDRNOTAVAIL;
gsw->dev = &pdev->dev;
of_property_read_string(np, "mediatek,port4", &port4);
if (port4 && !strcmp(port4, "ephy"))
gsw->port4 = PORT4_EPHY;
else if (port4 && !strcmp(port4, "gmac"))
gsw->port4 = PORT4_EXT;
else
gsw->port4 = PORT4_EPHY;
gsw->irq = platform_get_irq(pdev, 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",
.owner = THIS_MODULE,
.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");
MODULE_VERSION(MTK_FE_DRV_VERSION);

View file

@ -0,0 +1,259 @@
/* 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-2015 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2013-2015 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 fe_mdio_reset(struct mii_bus *bus)
{
/* TODO */
return 0;
}
static void fe_phy_link_adjust(struct net_device *dev)
{
struct fe_priv *priv = netdev_priv(dev);
unsigned long flags;
int i;
spin_lock_irqsave(&priv->phy->lock, flags);
for (i = 0; i < 8; i++) {
if (priv->phy->phy_node[i]) {
struct phy_device *phydev = priv->phy->phy[i];
int status_change = 0;
if (phydev->link)
if (priv->phy->duplex[i] != phydev->duplex ||
priv->phy->speed[i] != phydev->speed)
status_change = 1;
if (phydev->link != priv->link[i])
status_change = 1;
switch (phydev->speed) {
case SPEED_1000:
case SPEED_100:
case SPEED_10:
priv->link[i] = phydev->link;
priv->phy->duplex[i] = phydev->duplex;
priv->phy->speed[i] = phydev->speed;
if (status_change &&
priv->soc->mdio_adjust_link)
priv->soc->mdio_adjust_link(priv, i);
break;
}
}
}
}
int fe_connect_phy_node(struct fe_priv *priv, 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("%s: invalid port id\n", phy_node->name);
return -EINVAL;
}
port = be32_to_cpu(*_port);
phy_mode = of_get_phy_mode(phy_node);
if (phy_mode < 0) {
dev_err(priv->device, "incorrect phy-mode %d\n", phy_mode);
priv->phy->phy_node[port] = NULL;
return -EINVAL;
}
phydev = of_phy_connect(priv->netdev, phy_node, fe_phy_link_adjust,
0, phy_mode);
if (IS_ERR(phydev)) {
dev_err(priv->device, "could not connect to PHY\n");
priv->phy->phy_node[port] = NULL;
return PTR_ERR(phydev);
}
phydev->supported &= PHY_GBIT_FEATURES;
phydev->advertising = phydev->supported;
phydev->no_auto_carrier_off = 1;
dev_info(priv->device,
"connected port %d to PHY at %s [uid=%08x, driver=%s]\n",
port, dev_name(&phydev->mdio.dev), phydev->phy_id,
phydev->drv->name);
priv->phy->phy[port] = phydev;
priv->link[port] = 0;
return 0;
}
static void phy_init(struct fe_priv *priv, struct phy_device *phy)
{
phy_attach(priv->netdev, dev_name(&phy->mdio.dev), PHY_INTERFACE_MODE_MII);
phy->autoneg = AUTONEG_ENABLE;
phy->speed = 0;
phy->duplex = 0;
phy->supported &= PHY_BASIC_FEATURES;
phy->advertising = phy->supported | ADVERTISED_Autoneg;
phy_start_aneg(phy);
}
static int fe_phy_connect(struct fe_priv *priv)
{
int i;
for (i = 0; i < 8; i++) {
if (priv->phy->phy_node[i]) {
if (!priv->phy_dev) {
priv->phy_dev = priv->phy->phy[i];
priv->phy_flags = FE_PHY_FLAG_PORT;
}
} else if (priv->mii_bus && mdiobus_get_phy(priv->mii_bus, i)) {
phy_init(priv, mdiobus_get_phy(priv->mii_bus, i));
if (!priv->phy_dev) {
priv->phy_dev = mdiobus_get_phy(priv->mii_bus, i);
priv->phy_flags = FE_PHY_FLAG_ATTACH;
}
}
}
return 0;
}
static void fe_phy_disconnect(struct fe_priv *priv)
{
unsigned long flags;
int i;
for (i = 0; i < 8; i++)
if (priv->phy->phy_fixed[i]) {
spin_lock_irqsave(&priv->phy->lock, flags);
priv->link[i] = 0;
if (priv->soc->mdio_adjust_link)
priv->soc->mdio_adjust_link(priv, i);
spin_unlock_irqrestore(&priv->phy->lock, flags);
} else if (priv->phy->phy[i]) {
phy_disconnect(priv->phy->phy[i]);
} else if (priv->mii_bus && mdiobus_get_phy(priv->mii_bus, i)) {
phy_detach(mdiobus_get_phy(priv->mii_bus, i));
}
}
static void fe_phy_start(struct fe_priv *priv)
{
unsigned long flags;
int i;
for (i = 0; i < 8; i++) {
if (priv->phy->phy_fixed[i]) {
spin_lock_irqsave(&priv->phy->lock, flags);
priv->link[i] = 1;
if (priv->soc->mdio_adjust_link)
priv->soc->mdio_adjust_link(priv, i);
spin_unlock_irqrestore(&priv->phy->lock, flags);
} else if (priv->phy->phy[i]) {
phy_start(priv->phy->phy[i]);
}
}
}
static void fe_phy_stop(struct fe_priv *priv)
{
unsigned long flags;
int i;
for (i = 0; i < 8; i++)
if (priv->phy->phy_fixed[i]) {
spin_lock_irqsave(&priv->phy->lock, flags);
priv->link[i] = 0;
if (priv->soc->mdio_adjust_link)
priv->soc->mdio_adjust_link(priv, i);
spin_unlock_irqrestore(&priv->phy->lock, flags);
} else if (priv->phy->phy[i]) {
phy_stop(priv->phy->phy[i]);
}
}
static struct fe_phy phy_ralink = {
.connect = fe_phy_connect,
.disconnect = fe_phy_disconnect,
.start = fe_phy_start,
.stop = fe_phy_stop,
};
int fe_mdio_init(struct fe_priv *priv)
{
struct device_node *mii_np;
int err;
if (!priv->soc->mdio_read || !priv->soc->mdio_write)
return 0;
spin_lock_init(&phy_ralink.lock);
priv->phy = &phy_ralink;
mii_np = of_get_child_by_name(priv->device->of_node, "mdio-bus");
if (!mii_np) {
dev_err(priv->device, "no %s child node found", "mdio-bus");
return -ENODEV;
}
if (!of_device_is_available(mii_np)) {
err = 0;
goto err_put_node;
}
priv->mii_bus = mdiobus_alloc();
if (!priv->mii_bus) {
err = -ENOMEM;
goto err_put_node;
}
priv->mii_bus->name = "mdio";
priv->mii_bus->read = priv->soc->mdio_read;
priv->mii_bus->write = priv->soc->mdio_write;
priv->mii_bus->reset = fe_mdio_reset;
priv->mii_bus->priv = priv;
priv->mii_bus->parent = priv->device;
snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s", mii_np->name);
err = of_mdiobus_register(priv->mii_bus, mii_np);
if (err)
goto err_free_bus;
return 0;
err_free_bus:
kfree(priv->mii_bus);
err_put_node:
of_node_put(mii_np);
priv->mii_bus = NULL;
return err;
}
void fe_mdio_cleanup(struct fe_priv *priv)
{
if (!priv->mii_bus)
return;
mdiobus_unregister(priv->mii_bus);
of_node_put(priv->mii_bus->dev.of_node);
kfree(priv->mii_bus);
}

View file

@ -0,0 +1,27 @@
/* 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-2015 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2013-2015 Michael Lee <igvtee@gmail.com>
*/
#ifndef _RALINK_MDIO_H__
#define _RALINK_MDIO_H__
#ifdef CONFIG_NET_MEDIATEK_MDIO
int fe_mdio_init(struct fe_priv *priv);
void fe_mdio_cleanup(struct fe_priv *priv);
int fe_connect_phy_node(struct fe_priv *priv,
struct device_node *phy_node);
#else
static inline int fe_mdio_init(struct fe_priv *priv) { return 0; }
static inline void fe_mdio_cleanup(struct fe_priv *priv) {}
#endif
#endif

View file

@ -0,0 +1,168 @@
/* 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-2015 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2013-2015 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, MT7620A_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,
MT7620A_GSW_REG_PIAC);
if (mt7620_mii_busy_wait(gsw))
return -1;
return 0;
}
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),
MT7620A_GSW_REG_PIAC);
if (mt7620_mii_busy_wait(gsw))
return 0xffff;
d = mtk_switch_r32(gsw, MT7620A_GSW_REG_PIAC) & 0xffff;
return d;
}
int mt7620_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val)
{
struct fe_priv *priv = bus->priv;
struct mt7620_gsw *gsw = (struct mt7620_gsw *)priv->soc->swpriv;
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 fe_priv *priv = bus->priv;
struct mt7620_gsw *gsw = (struct mt7620_gsw *)priv->soc->swpriv;
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);
}
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);
}
static unsigned char *fe_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 fe_priv *priv)
{
struct mt7620_gsw *gsw = (struct mt7620_gsw *)priv->soc->swpriv;
int i;
for (i = 0; i < GSW_PORT6; i++)
if (mtk_switch_r32(gsw, GSW_REG_PORT_STATUS(i)) & 0x1)
return 1;
return 0;
}
void mt7620_handle_carrier(struct fe_priv *priv)
{
if (!priv->phy)
return;
if (mt7620_has_carrier(priv))
netif_carrier_on(priv->netdev);
else
netif_carrier_off(priv->netdev);
}
void mt7620_print_link_state(struct fe_priv *priv, int port, int link,
int speed, int duplex)
{
if (link)
netdev_info(priv->netdev, "port %d link up (%sMbps/%s duplex)\n",
port, fe_speed_str(speed),
(duplex) ? "Full" : "Half");
else
netdev_info(priv->netdev, "port %d link down\n", port);
}
void mt7620_mdio_link_adjust(struct fe_priv *priv, int port)
{
mt7620_print_link_state(priv, port, priv->link[port],
priv->phy->speed[port],
(priv->phy->duplex[port] == DUPLEX_FULL));
mt7620_handle_carrier(priv);
}

View file

@ -0,0 +1,222 @@
/* 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-2015 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2013-2015 Michael Lee <igvtee@gmail.com>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/of_net.h>
#include <linux/of_mdio.h>
#include "mtk_eth_soc.h"
#include "mdio_rt2880.h"
#include "mdio.h"
#define FE_MDIO_RETRY 1000
static unsigned char *rt2880_speed_str(struct fe_priv *priv)
{
switch (priv->phy->speed[0]) {
case SPEED_1000:
return "1000";
case SPEED_100:
return "100";
case SPEED_10:
return "10";
}
return "?";
}
void rt2880_mdio_link_adjust(struct fe_priv *priv, int port)
{
u32 mdio_cfg;
if (!priv->link[0]) {
netif_carrier_off(priv->netdev);
netdev_info(priv->netdev, "link down\n");
return;
}
mdio_cfg = FE_MDIO_CFG_TX_CLK_SKEW_200 |
FE_MDIO_CFG_RX_CLK_SKEW_200 |
FE_MDIO_CFG_GP1_FRC_EN;
if (priv->phy->duplex[0] == DUPLEX_FULL)
mdio_cfg |= FE_MDIO_CFG_GP1_DUPLEX;
if (priv->phy->tx_fc[0])
mdio_cfg |= FE_MDIO_CFG_GP1_FC_TX;
if (priv->phy->rx_fc[0])
mdio_cfg |= FE_MDIO_CFG_GP1_FC_RX;
switch (priv->phy->speed[0]) {
case SPEED_10:
mdio_cfg |= FE_MDIO_CFG_GP1_SPEED_10;
break;
case SPEED_100:
mdio_cfg |= FE_MDIO_CFG_GP1_SPEED_100;
break;
case SPEED_1000:
mdio_cfg |= FE_MDIO_CFG_GP1_SPEED_1000;
break;
default:
BUG();
}
fe_w32(mdio_cfg, FE_MDIO_CFG);
netif_carrier_on(priv->netdev);
netdev_info(priv->netdev, "link up (%sMbps/%s duplex)\n",
rt2880_speed_str(priv),
(priv->phy->duplex[0] == DUPLEX_FULL) ? "Full" : "Half");
}
static int rt2880_mdio_wait_ready(struct fe_priv *priv)
{
int retries;
retries = FE_MDIO_RETRY;
while (1) {
u32 t;
t = fe_r32(FE_MDIO_ACCESS);
if ((t & BIT(31)) == 0)
return 0;
if (retries-- == 0)
break;
udelay(1);
}
dev_err(priv->device, "MDIO operation timed out\n");
return -ETIMEDOUT;
}
int rt2880_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg)
{
struct fe_priv *priv = bus->priv;
int err;
u32 t;
err = rt2880_mdio_wait_ready(priv);
if (err)
return 0xffff;
t = (phy_addr << 24) | (phy_reg << 16);
fe_w32(t, FE_MDIO_ACCESS);
t |= BIT(31);
fe_w32(t, FE_MDIO_ACCESS);
err = rt2880_mdio_wait_ready(priv);
if (err)
return 0xffff;
pr_debug("%s: addr=%04x, reg=%04x, value=%04x\n", __func__,
phy_addr, phy_reg, fe_r32(FE_MDIO_ACCESS) & 0xffff);
return fe_r32(FE_MDIO_ACCESS) & 0xffff;
}
int rt2880_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val)
{
struct fe_priv *priv = bus->priv;
int err;
u32 t;
pr_debug("%s: addr=%04x, reg=%04x, value=%04x\n", __func__,
phy_addr, phy_reg, fe_r32(FE_MDIO_ACCESS) & 0xffff);
err = rt2880_mdio_wait_ready(priv);
if (err)
return err;
t = (1 << 30) | (phy_addr << 24) | (phy_reg << 16) | val;
fe_w32(t, FE_MDIO_ACCESS);
t |= BIT(31);
fe_w32(t, FE_MDIO_ACCESS);
return rt2880_mdio_wait_ready(priv);
}
void rt2880_port_init(struct fe_priv *priv, struct device_node *np)
{
const __be32 *id = of_get_property(np, "reg", NULL);
const __be32 *link;
int size;
int phy_mode;
if (!id || (be32_to_cpu(*id) != 0)) {
pr_err("%s: invalid port id\n", np->name);
return;
}
priv->phy->phy_fixed[0] = of_get_property(np,
"mediatek,fixed-link", &size);
if (priv->phy->phy_fixed[0] &&
(size != (4 * sizeof(*priv->phy->phy_fixed[0])))) {
pr_err("%s: invalid fixed link property\n", np->name);
priv->phy->phy_fixed[0] = NULL;
return;
}
phy_mode = of_get_phy_mode(np);
switch (phy_mode) {
case PHY_INTERFACE_MODE_RGMII:
break;
case PHY_INTERFACE_MODE_MII:
break;
case PHY_INTERFACE_MODE_RMII:
break;
default:
if (!priv->phy->phy_fixed[0])
dev_err(priv->device, "port %d - invalid phy mode\n",
priv->phy->speed[0]);
break;
}
priv->phy->phy_node[0] = of_parse_phandle(np, "phy-handle", 0);
if (!priv->phy->phy_node[0] && !priv->phy->phy_fixed[0])
return;
if (priv->phy->phy_fixed[0]) {
link = priv->phy->phy_fixed[0];
priv->phy->speed[0] = be32_to_cpup(link++);
priv->phy->duplex[0] = be32_to_cpup(link++);
priv->phy->tx_fc[0] = be32_to_cpup(link++);
priv->phy->rx_fc[0] = be32_to_cpup(link++);
priv->link[0] = 1;
switch (priv->phy->speed[0]) {
case SPEED_10:
break;
case SPEED_100:
break;
case SPEED_1000:
break;
default:
dev_err(priv->device, "invalid link speed: %d\n",
priv->phy->speed[0]);
priv->phy->phy_fixed[0] = 0;
return;
}
dev_info(priv->device, "using fixed link parameters\n");
rt2880_mdio_link_adjust(priv, 0);
return;
}
if (priv->phy->phy_node[0] && mdiobus_get_phy(priv->mii_bus, 0))
fe_connect_phy_node(priv, priv->phy->phy_node[0]);
}

View file

@ -0,0 +1,23 @@
/* 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-2015 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2013-2015 Michael Lee <igvtee@gmail.com>
*/
#ifndef _RALINK_MDIO_RT2880_H__
#define _RALINK_MDIO_RT2880_H__
void rt2880_mdio_link_adjust(struct fe_priv *priv, int port);
int rt2880_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg);
int rt2880_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val);
void rt2880_port_init(struct fe_priv *priv, struct device_node *np);
#endif

View file

@ -0,0 +1,979 @@
/*
* 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; either version 2
* of the License, or (at your option) any later version.
*
* 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) 2013 John Crispin <blogic@openwrt.org>
* Copyright (C) 2016 Vitaly Chekryzhev <13hakta@gmail.com>
*/
#include <linux/if.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/if_ether.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/netlink.h>
#include <linux/bitops.h>
#include <net/genetlink.h>
#include <linux/switch.h>
#include <linux/delay.h>
#include <linux/phy.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/lockdep.h>
#include <linux/workqueue.h>
#include <linux/of_device.h>
#include "mt7530.h"
#define MT7530_CPU_PORT 6
#define MT7530_NUM_PORTS 8
#ifdef CONFIG_SOC_MT7621
#define MT7530_NUM_VLANS 4095
#else
#define MT7530_NUM_VLANS 16
#endif
#define MT7530_MAX_VID 4095
#define MT7530_MIN_VID 0
#define MT7530_PORT_MIB_TXB_ID 2 /* TxGOC */
#define MT7530_PORT_MIB_RXB_ID 6 /* RxGOC */
#define MT7621_PORT_MIB_TXB_ID 18 /* TxByte */
#define MT7621_PORT_MIB_RXB_ID 37 /* RxByte */
/* registers */
#define REG_ESW_VLAN_VTCR 0x90
#define REG_ESW_VLAN_VAWD1 0x94
#define REG_ESW_VLAN_VAWD2 0x98
#define REG_ESW_VLAN_VTIM(x) (0x100 + 4 * ((x) / 2))
#define REG_ESW_VLAN_VAWD1_IVL_MAC BIT(30)
#define REG_ESW_VLAN_VAWD1_VTAG_EN BIT(28)
#define REG_ESW_VLAN_VAWD1_VALID BIT(0)
/* vlan egress mode */
enum {
ETAG_CTRL_UNTAG = 0,
ETAG_CTRL_TAG = 2,
ETAG_CTRL_SWAP = 1,
ETAG_CTRL_STACK = 3,
};
#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 REG_HWTRAP 0x7804
#define MIB_DESC(_s , _o, _n) \
{ \
.size = (_s), \
.offset = (_o), \
.name = (_n), \
}
struct mt7xxx_mib_desc {
unsigned int size;
unsigned int offset;
const char *name;
};
static const struct mt7xxx_mib_desc mt7620_mibs[] = {
MIB_DESC(1, MT7620_MIB_STATS_PPE_AC_BCNT0, "PPE_AC_BCNT0"),
MIB_DESC(1, MT7620_MIB_STATS_PPE_AC_PCNT0, "PPE_AC_PCNT0"),
MIB_DESC(1, MT7620_MIB_STATS_PPE_AC_BCNT63, "PPE_AC_BCNT63"),
MIB_DESC(1, MT7620_MIB_STATS_PPE_AC_PCNT63, "PPE_AC_PCNT63"),
MIB_DESC(1, MT7620_MIB_STATS_PPE_MTR_CNT0, "PPE_MTR_CNT0"),
MIB_DESC(1, MT7620_MIB_STATS_PPE_MTR_CNT63, "PPE_MTR_CNT63"),
MIB_DESC(1, MT7620_MIB_STATS_GDM1_TX_GBCNT, "GDM1_TX_GBCNT"),
MIB_DESC(1, MT7620_MIB_STATS_GDM1_TX_GPCNT, "GDM1_TX_GPCNT"),
MIB_DESC(1, MT7620_MIB_STATS_GDM1_TX_SKIPCNT, "GDM1_TX_SKIPCNT"),
MIB_DESC(1, MT7620_MIB_STATS_GDM1_TX_COLCNT, "GDM1_TX_COLCNT"),
MIB_DESC(1, MT7620_MIB_STATS_GDM1_RX_GBCNT1, "GDM1_RX_GBCNT1"),
MIB_DESC(1, MT7620_MIB_STATS_GDM1_RX_GPCNT1, "GDM1_RX_GPCNT1"),
MIB_DESC(1, MT7620_MIB_STATS_GDM1_RX_OERCNT, "GDM1_RX_OERCNT"),
MIB_DESC(1, MT7620_MIB_STATS_GDM1_RX_FERCNT, "GDM1_RX_FERCNT"),
MIB_DESC(1, MT7620_MIB_STATS_GDM1_RX_SERCNT, "GDM1_RX_SERCNT"),
MIB_DESC(1, MT7620_MIB_STATS_GDM1_RX_LERCNT, "GDM1_RX_LERCNT"),
MIB_DESC(1, MT7620_MIB_STATS_GDM1_RX_CERCNT, "GDM1_RX_CERCNT"),
MIB_DESC(1, MT7620_MIB_STATS_GDM1_RX_FCCNT, "GDM1_RX_FCCNT"),
MIB_DESC(1, MT7620_MIB_STATS_GDM2_TX_GBCNT, "GDM2_TX_GBCNT"),
MIB_DESC(1, MT7620_MIB_STATS_GDM2_TX_GPCNT, "GDM2_TX_GPCNT"),
MIB_DESC(1, MT7620_MIB_STATS_GDM2_TX_SKIPCNT, "GDM2_TX_SKIPCNT"),
MIB_DESC(1, MT7620_MIB_STATS_GDM2_TX_COLCNT, "GDM2_TX_COLCNT"),
MIB_DESC(1, MT7620_MIB_STATS_GDM2_RX_GBCNT, "GDM2_RX_GBCNT"),
MIB_DESC(1, MT7620_MIB_STATS_GDM2_RX_GPCNT, "GDM2_RX_GPCNT"),
MIB_DESC(1, MT7620_MIB_STATS_GDM2_RX_OERCNT, "GDM2_RX_OERCNT"),
MIB_DESC(1, MT7620_MIB_STATS_GDM2_RX_FERCNT, "GDM2_RX_FERCNT"),
MIB_DESC(1, MT7620_MIB_STATS_GDM2_RX_SERCNT, "GDM2_RX_SERCNT"),
MIB_DESC(1, MT7620_MIB_STATS_GDM2_RX_LERCNT, "GDM2_RX_LERCNT"),
MIB_DESC(1, MT7620_MIB_STATS_GDM2_RX_CERCNT, "GDM2_RX_CERCNT"),
MIB_DESC(1, MT7620_MIB_STATS_GDM2_RX_FCCNT, "GDM2_RX_FCCNT")
};
static const struct mt7xxx_mib_desc mt7620_port_mibs[] = {
MIB_DESC(1, MT7620_MIB_STATS_PORT_TGPCN, "TxGPC"),
MIB_DESC(1, MT7620_MIB_STATS_PORT_TBOCN, "TxBOC"),
MIB_DESC(1, MT7620_MIB_STATS_PORT_TGOCN, "TxGOC"),
MIB_DESC(1, MT7620_MIB_STATS_PORT_TEPCN, "TxEPC"),
MIB_DESC(1, MT7620_MIB_STATS_PORT_RGPCN, "RxGPC"),
MIB_DESC(1, MT7620_MIB_STATS_PORT_RBOCN, "RxBOC"),
MIB_DESC(1, MT7620_MIB_STATS_PORT_RGOCN, "RxGOC"),
MIB_DESC(1, MT7620_MIB_STATS_PORT_REPC1N, "RxEPC1"),
MIB_DESC(1, MT7620_MIB_STATS_PORT_REPC2N, "RxEPC2")
};
static const struct mt7xxx_mib_desc mt7621_mibs[] = {
MIB_DESC(1, MT7621_STATS_TDPC, "TxDrop"),
MIB_DESC(1, MT7621_STATS_TCRC, "TxCRC"),
MIB_DESC(1, MT7621_STATS_TUPC, "TxUni"),
MIB_DESC(1, MT7621_STATS_TMPC, "TxMulti"),
MIB_DESC(1, MT7621_STATS_TBPC, "TxBroad"),
MIB_DESC(1, MT7621_STATS_TCEC, "TxCollision"),
MIB_DESC(1, MT7621_STATS_TSCEC, "TxSingleCol"),
MIB_DESC(1, MT7621_STATS_TMCEC, "TxMultiCol"),
MIB_DESC(1, MT7621_STATS_TDEC, "TxDefer"),
MIB_DESC(1, MT7621_STATS_TLCEC, "TxLateCol"),
MIB_DESC(1, MT7621_STATS_TXCEC, "TxExcCol"),
MIB_DESC(1, MT7621_STATS_TPPC, "TxPause"),
MIB_DESC(1, MT7621_STATS_TL64PC, "Tx64Byte"),
MIB_DESC(1, MT7621_STATS_TL65PC, "Tx65Byte"),
MIB_DESC(1, MT7621_STATS_TL128PC, "Tx128Byte"),
MIB_DESC(1, MT7621_STATS_TL256PC, "Tx256Byte"),
MIB_DESC(1, MT7621_STATS_TL512PC, "Tx512Byte"),
MIB_DESC(1, MT7621_STATS_TL1024PC, "Tx1024Byte"),
MIB_DESC(2, MT7621_STATS_TOC, "TxByte"),
MIB_DESC(1, MT7621_STATS_RDPC, "RxDrop"),
MIB_DESC(1, MT7621_STATS_RFPC, "RxFiltered"),
MIB_DESC(1, MT7621_STATS_RUPC, "RxUni"),
MIB_DESC(1, MT7621_STATS_RMPC, "RxMulti"),
MIB_DESC(1, MT7621_STATS_RBPC, "RxBroad"),
MIB_DESC(1, MT7621_STATS_RAEPC, "RxAlignErr"),
MIB_DESC(1, MT7621_STATS_RCEPC, "RxCRC"),
MIB_DESC(1, MT7621_STATS_RUSPC, "RxUnderSize"),
MIB_DESC(1, MT7621_STATS_RFEPC, "RxFragment"),
MIB_DESC(1, MT7621_STATS_ROSPC, "RxOverSize"),
MIB_DESC(1, MT7621_STATS_RJEPC, "RxJabber"),
MIB_DESC(1, MT7621_STATS_RPPC, "RxPause"),
MIB_DESC(1, MT7621_STATS_RL64PC, "Rx64Byte"),
MIB_DESC(1, MT7621_STATS_RL65PC, "Rx65Byte"),
MIB_DESC(1, MT7621_STATS_RL128PC, "Rx128Byte"),
MIB_DESC(1, MT7621_STATS_RL256PC, "Rx256Byte"),
MIB_DESC(1, MT7621_STATS_RL512PC, "Rx512Byte"),
MIB_DESC(1, MT7621_STATS_RL1024PC, "Rx1024Byte"),
MIB_DESC(2, MT7621_STATS_ROC, "RxByte"),
MIB_DESC(1, MT7621_STATS_RDPC_CTRL, "RxCtrlDrop"),
MIB_DESC(1, MT7621_STATS_RDPC_ING, "RxIngDrop"),
MIB_DESC(1, MT7621_STATS_RDPC_ARL, "RxARLDrop")
};
enum {
/* Global attributes. */
MT7530_ATTR_ENABLE_VLAN,
};
struct mt7530_port_entry {
u16 pvid;
};
struct mt7530_vlan_entry {
u16 vid;
u8 member;
u8 etags;
};
struct mt7530_priv {
void __iomem *base;
struct mii_bus *bus;
struct switch_dev swdev;
bool global_vlan_enable;
struct mt7530_vlan_entry vlan_entries[MT7530_NUM_VLANS];
struct mt7530_port_entry port_entries[MT7530_NUM_PORTS];
};
struct mt7530_mapping {
char *name;
u16 pvids[MT7530_NUM_PORTS];
u8 members[MT7530_NUM_VLANS];
u8 etags[MT7530_NUM_VLANS];
u16 vids[MT7530_NUM_VLANS];
} mt7530_defaults[] = {
{
.name = "llllw",
.pvids = { 1, 1, 1, 1, 2, 1, 1 },
.members = { 0, 0x6f, 0x50 },
.etags = { 0, 0x40, 0x40 },
.vids = { 0, 1, 2 },
}, {
.name = "wllll",
.pvids = { 2, 1, 1, 1, 1, 1, 1 },
.members = { 0, 0x7e, 0x41 },
.etags = { 0, 0x40, 0x40 },
.vids = { 0, 1, 2 },
}, {
.name = "lwlll",
.pvids = { 1, 2, 1, 1, 1, 1, 1 },
.members = { 0, 0x7d, 0x42 },
.etags = { 0, 0x40, 0x40 },
.vids = { 0, 1, 2 },
},
};
struct mt7530_mapping*
mt7530_find_mapping(struct device_node *np)
{
const char *map;
int i;
if (of_property_read_string(np, "mediatek,portmap", &map))
return NULL;
for (i = 0; i < ARRAY_SIZE(mt7530_defaults); i++)
if (!strcmp(map, mt7530_defaults[i].name))
return &mt7530_defaults[i];
return NULL;
}
static void
mt7530_apply_mapping(struct mt7530_priv *mt7530, struct mt7530_mapping *map)
{
int i = 0;
for (i = 0; i < MT7530_NUM_PORTS; i++)
mt7530->port_entries[i].pvid = map->pvids[i];
for (i = 0; i < MT7530_NUM_VLANS; i++) {
mt7530->vlan_entries[i].member = map->members[i];
mt7530->vlan_entries[i].etags = map->etags[i];
mt7530->vlan_entries[i].vid = map->vids[i];
}
}
static int
mt7530_reset_switch(struct switch_dev *dev)
{
struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
int i;
memset(priv->port_entries, 0, sizeof(priv->port_entries));
memset(priv->vlan_entries, 0, sizeof(priv->vlan_entries));
/* set default vid of each vlan to the same number of vlan, so the vid
* won't need be set explicitly.
*/
for (i = 0; i < MT7530_NUM_VLANS; i++) {
priv->vlan_entries[i].vid = i;
}
return 0;
}
static int
mt7530_get_vlan_enable(struct switch_dev *dev,
const struct switch_attr *attr,
struct switch_val *val)
{
struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
val->value.i = priv->global_vlan_enable;
return 0;
}
static int
mt7530_set_vlan_enable(struct switch_dev *dev,
const struct switch_attr *attr,
struct switch_val *val)
{
struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
priv->global_vlan_enable = val->value.i != 0;
return 0;
}
static u32
mt7530_r32(struct mt7530_priv *priv, u32 reg)
{
u32 val;
if (priv->bus) {
u16 high, low;
mdiobus_write(priv->bus, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
low = mdiobus_read(priv->bus, 0x1f, (reg >> 2) & 0xf);
high = mdiobus_read(priv->bus, 0x1f, 0x10);
return (high << 16) | (low & 0xffff);
}
val = ioread32(priv->base + reg);
pr_debug("MT7530 MDIO Read [%04x]=%08x\n", reg, val);
return val;
}
static void
mt7530_w32(struct mt7530_priv *priv, u32 reg, u32 val)
{
if (priv->bus) {
mdiobus_write(priv->bus, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
mdiobus_write(priv->bus, 0x1f, (reg >> 2) & 0xf, val & 0xffff);
mdiobus_write(priv->bus, 0x1f, 0x10, val >> 16);
return;
}
pr_debug("MT7530 MDIO Write[%04x]=%08x\n", reg, val);
iowrite32(val, priv->base + reg);
}
static void
mt7530_vtcr(struct mt7530_priv *priv, u32 cmd, u32 val)
{
int i;
mt7530_w32(priv, REG_ESW_VLAN_VTCR, BIT(31) | (cmd << 12) | val);
for (i = 0; i < 20; i++) {
u32 val = mt7530_r32(priv, REG_ESW_VLAN_VTCR);
if ((val & BIT(31)) == 0)
break;
udelay(1000);
}
if (i == 20)
printk("mt7530: vtcr timeout\n");
}
static int
mt7530_get_port_pvid(struct switch_dev *dev, int port, int *val)
{
struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
if (port >= MT7530_NUM_PORTS)
return -EINVAL;
*val = mt7530_r32(priv, REG_ESW_PORT_PPBV1(port));
*val &= 0xfff;
return 0;
}
static int
mt7530_set_port_pvid(struct switch_dev *dev, int port, int pvid)
{
struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
if (port >= MT7530_NUM_PORTS)
return -EINVAL;
if (pvid < MT7530_MIN_VID || pvid > MT7530_MAX_VID)
return -EINVAL;
priv->port_entries[port].pvid = pvid;
return 0;
}
static int
mt7530_get_vlan_ports(struct switch_dev *dev, struct switch_val *val)
{
struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
u32 member;
u32 etags;
int i;
val->len = 0;
if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VLANS)
return -EINVAL;
mt7530_vtcr(priv, 0, val->port_vlan);
member = mt7530_r32(priv, REG_ESW_VLAN_VAWD1);
member >>= 16;
member &= 0xff;
etags = mt7530_r32(priv, REG_ESW_VLAN_VAWD2);
for (i = 0; i < MT7530_NUM_PORTS; i++) {
struct switch_port *p;
int etag;
if (!(member & BIT(i)))
continue;
p = &val->value.ports[val->len++];
p->id = i;
etag = (etags >> (i * 2)) & 0x3;
if (etag == ETAG_CTRL_TAG)
p->flags |= BIT(SWITCH_PORT_FLAG_TAGGED);
else if (etag != ETAG_CTRL_UNTAG)
printk("vlan egress tag control neither untag nor tag.\n");
}
return 0;
}
static int
mt7530_set_vlan_ports(struct switch_dev *dev, struct switch_val *val)
{
struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
u8 member = 0;
u8 etags = 0;
int i;
if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VLANS ||
val->len > MT7530_NUM_PORTS)
return -EINVAL;
for (i = 0; i < val->len; i++) {
struct switch_port *p = &val->value.ports[i];
if (p->id >= MT7530_NUM_PORTS)
return -EINVAL;
member |= BIT(p->id);
if (p->flags & BIT(SWITCH_PORT_FLAG_TAGGED))
etags |= BIT(p->id);
}
priv->vlan_entries[val->port_vlan].member = member;
priv->vlan_entries[val->port_vlan].etags = etags;
return 0;
}
static int
mt7530_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
struct switch_val *val)
{
struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
int vlan;
u16 vid;
vlan = val->port_vlan;
vid = (u16)val->value.i;
if (vlan < 0 || vlan >= MT7530_NUM_VLANS)
return -EINVAL;
if (vid < MT7530_MIN_VID || vid > MT7530_MAX_VID)
return -EINVAL;
priv->vlan_entries[vlan].vid = vid;
return 0;
}
static int
mt7621_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
struct switch_val *val)
{
val->value.i = val->port_vlan;
return 0;
}
static int
mt7530_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
struct switch_val *val)
{
struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
u32 vid;
int vlan;
vlan = val->port_vlan;
vid = mt7530_r32(priv, REG_ESW_VLAN_VTIM(vlan));
if (vlan & 1)
vid = vid >> 12;
vid &= 0xfff;
val->value.i = vid;
return 0;
}
static void
mt7530_write_vlan_entry(struct mt7530_priv *priv, int vlan, u16 vid,
u8 ports, u8 etags)
{
int port;
u32 val;
#ifndef CONFIG_SOC_MT7621
/* vid of vlan */
val = mt7530_r32(priv, REG_ESW_VLAN_VTIM(vlan));
if (vlan % 2 == 0) {
val &= 0xfff000;
val |= vid;
} else {
val &= 0xfff;
val |= (vid << 12);
}
mt7530_w32(priv, REG_ESW_VLAN_VTIM(vlan), val);
#endif
/* vlan port membership */
if (ports)
mt7530_w32(priv, REG_ESW_VLAN_VAWD1, REG_ESW_VLAN_VAWD1_IVL_MAC |
REG_ESW_VLAN_VAWD1_VTAG_EN | (ports << 16) |
REG_ESW_VLAN_VAWD1_VALID);
else
mt7530_w32(priv, REG_ESW_VLAN_VAWD1, 0);
/* egress mode */
val = 0;
for (port = 0; port < MT7530_NUM_PORTS; port++) {
if (etags & BIT(port))
val |= ETAG_CTRL_TAG << (port * 2);
else
val |= ETAG_CTRL_UNTAG << (port * 2);
}
mt7530_w32(priv, REG_ESW_VLAN_VAWD2, val);
/* write to vlan table */
#ifdef CONFIG_SOC_MT7621
mt7530_vtcr(priv, 1, vid);
#else
mt7530_vtcr(priv, 1, vlan);
#endif
}
static int
mt7530_apply_config(struct switch_dev *dev)
{
struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
int i, j;
u8 tag_ports;
u8 untag_ports;
if (!priv->global_vlan_enable) {
for (i = 0; i < MT7530_NUM_PORTS; i++)
mt7530_w32(priv, REG_ESW_PORT_PCR(i), 0x00400000);
mt7530_w32(priv, REG_ESW_PORT_PCR(MT7530_CPU_PORT), 0x00ff0000);
for (i = 0; i < MT7530_NUM_PORTS; i++)
mt7530_w32(priv, REG_ESW_PORT_PVC(i), 0x810000c0);
return 0;
}
/* set all ports as security mode */
for (i = 0; i < MT7530_NUM_PORTS; i++)
mt7530_w32(priv, REG_ESW_PORT_PCR(i), 0x00ff0003);
/* check if a port is used in tag/untag vlan egress mode */
tag_ports = 0;
untag_ports = 0;
for (i = 0; i < MT7530_NUM_VLANS; i++) {
u8 member = priv->vlan_entries[i].member;
u8 etags = priv->vlan_entries[i].etags;
if (!member)
continue;
for (j = 0; j < MT7530_NUM_PORTS; j++) {
if (!(member & BIT(j)))
continue;
if (etags & BIT(j))
tag_ports |= 1u << j;
else
untag_ports |= 1u << j;
}
}
/* set all untag-only ports as transparent and the rest as user port */
for (i = 0; i < MT7530_NUM_PORTS; i++) {
u32 pvc_mode = 0x81000000;
if (untag_ports & BIT(i) && !(tag_ports & BIT(i)))
pvc_mode = 0x810000c0;
mt7530_w32(priv, REG_ESW_PORT_PVC(i), pvc_mode);
}
/* first clear the swtich vlan table */
for (i = 0; i < MT7530_NUM_VLANS; i++)
mt7530_write_vlan_entry(priv, i, i, 0, 0);
/* now program only vlans with members to avoid
clobbering remapped entries in later iterations */
for (i = 0; i < MT7530_NUM_VLANS; i++) {
u16 vid = priv->vlan_entries[i].vid;
u8 member = priv->vlan_entries[i].member;
u8 etags = priv->vlan_entries[i].etags;
if (member)
mt7530_write_vlan_entry(priv, i, vid, member, etags);
}
/* Port Default PVID */
for (i = 0; i < MT7530_NUM_PORTS; i++) {
int vlan = priv->port_entries[i].pvid;
u16 pvid = 0;
u32 val;
if (vlan < MT7530_NUM_VLANS && priv->vlan_entries[vlan].member)
pvid = priv->vlan_entries[vlan].vid;
val = mt7530_r32(priv, REG_ESW_PORT_PPBV1(i));
val &= ~0xfff;
val |= pvid;
mt7530_w32(priv, REG_ESW_PORT_PPBV1(i), val);
}
return 0;
}
static int
mt7530_get_port_link(struct switch_dev *dev, int port,
struct switch_port_link *link)
{
struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
u32 speed, pmsr;
if (port < 0 || port >= MT7530_NUM_PORTS)
return -EINVAL;
pmsr = mt7530_r32(priv, 0x3008 + (0x100 * port));
link->link = pmsr & 1;
link->duplex = (pmsr >> 1) & 1;
speed = (pmsr >> 2) & 3;
switch (speed) {
case 0:
link->speed = SWITCH_PORT_SPEED_10;
break;
case 1:
link->speed = SWITCH_PORT_SPEED_100;
break;
case 2:
case 3: /* forced gige speed can be 2 or 3 */
link->speed = SWITCH_PORT_SPEED_1000;
break;
default:
link->speed = SWITCH_PORT_SPEED_UNKNOWN;
break;
}
return 0;
}
static u64 get_mib_counter(struct mt7530_priv *priv, int i, int port)
{
unsigned int port_base;
u64 lo;
port_base = MT7621_MIB_COUNTER_BASE +
MT7621_MIB_COUNTER_PORT_OFFSET * port;
lo = mt7530_r32(priv, port_base + mt7621_mibs[i].offset);
if (mt7621_mibs[i].size == 2) {
u64 hi;
hi = mt7530_r32(priv, port_base + mt7621_mibs[i].offset + 4);
lo |= hi << 32;
}
return lo;
}
static int mt7621_sw_get_port_mib(struct switch_dev *dev,
const struct switch_attr *attr,
struct switch_val *val)
{
static char buf[4096];
struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
int i, len = 0;
if (val->port_vlan >= MT7530_NUM_PORTS)
return -EINVAL;
len += snprintf(buf + len, sizeof(buf) - len,
"Port %d MIB counters\n", val->port_vlan);
for (i = 0; i < ARRAY_SIZE(mt7621_mibs); ++i) {
u64 counter;
len += snprintf(buf + len, sizeof(buf) - len,
"%-11s: ", mt7621_mibs[i].name);
counter = get_mib_counter(priv, i, val->port_vlan);
len += snprintf(buf + len, sizeof(buf) - len, "%llu\n",
counter);
}
val->value.s = buf;
val->len = len;
return 0;
}
static u64 get_mib_counter_7620(struct mt7530_priv *priv, int i)
{
return mt7530_r32(priv, MT7620_MIB_COUNTER_BASE + mt7620_mibs[i].offset);
}
static u64 get_mib_counter_port_7620(struct mt7530_priv *priv, int i, int port)
{
return mt7530_r32(priv,
MT7620_MIB_COUNTER_BASE_PORT +
(MT7620_MIB_COUNTER_PORT_OFFSET * port) +
mt7620_port_mibs[i].offset);
}
static int mt7530_sw_get_mib(struct switch_dev *dev,
const struct switch_attr *attr,
struct switch_val *val)
{
static char buf[4096];
struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
int i, len = 0;
len += snprintf(buf + len, sizeof(buf) - len, "Switch MIB counters\n");
for (i = 0; i < ARRAY_SIZE(mt7620_mibs); ++i) {
u64 counter;
len += snprintf(buf + len, sizeof(buf) - len,
"%-11s: ", mt7620_mibs[i].name);
counter = get_mib_counter_7620(priv, i);
len += snprintf(buf + len, sizeof(buf) - len, "%llu\n",
counter);
}
val->value.s = buf;
val->len = len;
return 0;
}
static int mt7530_sw_get_port_mib(struct switch_dev *dev,
const struct switch_attr *attr,
struct switch_val *val)
{
static char buf[4096];
struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
int i, len = 0;
if (val->port_vlan >= MT7530_NUM_PORTS)
return -EINVAL;
len += snprintf(buf + len, sizeof(buf) - len,
"Port %d MIB counters\n", val->port_vlan);
for (i = 0; i < ARRAY_SIZE(mt7620_port_mibs); ++i) {
u64 counter;
len += snprintf(buf + len, sizeof(buf) - len,
"%-11s: ", mt7620_port_mibs[i].name);
counter = get_mib_counter_port_7620(priv, i, val->port_vlan);
len += snprintf(buf + len, sizeof(buf) - len, "%llu\n",
counter);
}
val->value.s = buf;
val->len = len;
return 0;
}
static int mt7530_get_port_stats(struct switch_dev *dev, int port,
struct switch_port_stats *stats)
{
struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
if (port < 0 || port >= MT7530_NUM_PORTS)
return -EINVAL;
stats->tx_bytes = get_mib_counter_port_7620(priv, MT7530_PORT_MIB_TXB_ID, port);
stats->rx_bytes = get_mib_counter_port_7620(priv, MT7530_PORT_MIB_RXB_ID, port);
return 0;
}
static int mt7621_get_port_stats(struct switch_dev *dev, int port,
struct switch_port_stats *stats)
{
struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
if (port < 0 || port >= MT7530_NUM_PORTS)
return -EINVAL;
stats->tx_bytes = get_mib_counter(priv, MT7621_PORT_MIB_TXB_ID, port);
stats->rx_bytes = get_mib_counter(priv, MT7621_PORT_MIB_RXB_ID, port);
return 0;
}
static const struct switch_attr mt7530_global[] = {
{
.type = SWITCH_TYPE_INT,
.name = "enable_vlan",
.description = "VLAN mode (1:enabled)",
.max = 1,
.id = MT7530_ATTR_ENABLE_VLAN,
.get = mt7530_get_vlan_enable,
.set = mt7530_set_vlan_enable,
}, {
.type = SWITCH_TYPE_STRING,
.name = "mib",
.description = "Get MIB counters for switch",
.get = mt7530_sw_get_mib,
.set = NULL,
},
};
static const struct switch_attr mt7621_port[] = {
{
.type = SWITCH_TYPE_STRING,
.name = "mib",
.description = "Get MIB counters for port",
.get = mt7621_sw_get_port_mib,
.set = NULL,
},
};
static const struct switch_attr mt7621_vlan[] = {
{
.type = SWITCH_TYPE_INT,
.name = "vid",
.description = "VLAN ID (0-4094)",
.set = mt7530_set_vid,
.get = mt7621_get_vid,
.max = 4094,
},
};
static const struct switch_attr mt7530_port[] = {
{
.type = SWITCH_TYPE_STRING,
.name = "mib",
.description = "Get MIB counters for port",
.get = mt7530_sw_get_port_mib,
.set = NULL,
},
};
static const struct switch_attr mt7530_vlan[] = {
{
.type = SWITCH_TYPE_INT,
.name = "vid",
.description = "VLAN ID (0-4094)",
.set = mt7530_set_vid,
.get = mt7530_get_vid,
.max = 4094,
},
};
static const struct switch_dev_ops mt7621_ops = {
.attr_global = {
.attr = mt7530_global,
.n_attr = ARRAY_SIZE(mt7530_global),
},
.attr_port = {
.attr = mt7621_port,
.n_attr = ARRAY_SIZE(mt7621_port),
},
.attr_vlan = {
.attr = mt7621_vlan,
.n_attr = ARRAY_SIZE(mt7621_vlan),
},
.get_vlan_ports = mt7530_get_vlan_ports,
.set_vlan_ports = mt7530_set_vlan_ports,
.get_port_pvid = mt7530_get_port_pvid,
.set_port_pvid = mt7530_set_port_pvid,
.get_port_link = mt7530_get_port_link,
.get_port_stats = mt7621_get_port_stats,
.apply_config = mt7530_apply_config,
.reset_switch = mt7530_reset_switch,
};
static const struct switch_dev_ops mt7530_ops = {
.attr_global = {
.attr = mt7530_global,
.n_attr = ARRAY_SIZE(mt7530_global),
},
.attr_port = {
.attr = mt7530_port,
.n_attr = ARRAY_SIZE(mt7530_port),
},
.attr_vlan = {
.attr = mt7530_vlan,
.n_attr = ARRAY_SIZE(mt7530_vlan),
},
.get_vlan_ports = mt7530_get_vlan_ports,
.set_vlan_ports = mt7530_set_vlan_ports,
.get_port_pvid = mt7530_get_port_pvid,
.set_port_pvid = mt7530_set_port_pvid,
.get_port_link = mt7530_get_port_link,
.get_port_stats = mt7530_get_port_stats,
.apply_config = mt7530_apply_config,
.reset_switch = mt7530_reset_switch,
};
int
mt7530_probe(struct device *dev, void __iomem *base, struct mii_bus *bus, int vlan)
{
struct switch_dev *swdev;
struct mt7530_priv *mt7530;
struct mt7530_mapping *map;
int ret;
mt7530 = devm_kzalloc(dev, sizeof(struct mt7530_priv), GFP_KERNEL);
if (!mt7530)
return -ENOMEM;
mt7530->base = base;
mt7530->bus = bus;
mt7530->global_vlan_enable = vlan;
swdev = &mt7530->swdev;
if (bus) {
swdev->alias = "mt7530";
swdev->name = "mt7530";
} else if (IS_ENABLED(CONFIG_SOC_MT7621)) {
swdev->alias = "mt7621";
swdev->name = "mt7621";
} else {
swdev->alias = "mt7620";
swdev->name = "mt7620";
}
swdev->cpu_port = MT7530_CPU_PORT;
swdev->ports = MT7530_NUM_PORTS;
swdev->vlans = MT7530_NUM_VLANS;
if (IS_ENABLED(CONFIG_SOC_MT7621))
swdev->ops = &mt7621_ops;
else
swdev->ops = &mt7530_ops;
ret = register_switch(swdev, NULL);
if (ret) {
dev_err(dev, "failed to register mt7530\n");
return ret;
}
map = mt7530_find_mapping(dev->of_node);
if (map)
mt7530_apply_mapping(mt7530, map);
mt7530_apply_config(swdev);
/* magic vodoo */
if (!IS_ENABLED(CONFIG_SOC_MT7621) && bus && mt7530_r32(mt7530, REG_HWTRAP) != 0x1117edf) {
dev_info(dev, "fixing up MHWTRAP register - bootloader probably played with it\n");
mt7530_w32(mt7530, REG_HWTRAP, 0x1117edf);
}
dev_info(dev, "loaded %s driver\n", swdev->name);
return 0;
}

View file

@ -0,0 +1,186 @@
/*
* 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; either version 2
* of the License, or (at your option) any later version.
*
* 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) 2013 John Crispin <blogic@openwrt.org>
* Copyright (C) 2016 Vitaly Chekryzhev <13hakta@gmail.com>
*/
#ifndef _MT7530_H__
#define _MT7530_H__
#define MT7620_MIB_COUNTER_BASE_PORT 0x4000
#define MT7620_MIB_COUNTER_PORT_OFFSET 0x100
#define MT7620_MIB_COUNTER_BASE 0x1010
/* PPE Accounting Group #0 Byte Counter */
#define MT7620_MIB_STATS_PPE_AC_BCNT0 0x000
/* PPE Accounting Group #0 Packet Counter */
#define MT7620_MIB_STATS_PPE_AC_PCNT0 0x004
/* PPE Accounting Group #63 Byte Counter */
#define MT7620_MIB_STATS_PPE_AC_BCNT63 0x1F8
/* PPE Accounting Group #63 Packet Counter */
#define MT7620_MIB_STATS_PPE_AC_PCNT63 0x1FC
/* PPE Meter Group #0 */
#define MT7620_MIB_STATS_PPE_MTR_CNT0 0x200
/* PPE Meter Group #63 */
#define MT7620_MIB_STATS_PPE_MTR_CNT63 0x2FC
/* Transmit good byte count for CPU GDM */
#define MT7620_MIB_STATS_GDM1_TX_GBCNT 0x300
/* Transmit good packet count for CPU GDM (exclude flow control frames) */
#define MT7620_MIB_STATS_GDM1_TX_GPCNT 0x304
/* Transmit abort count for CPU GDM */
#define MT7620_MIB_STATS_GDM1_TX_SKIPCNT 0x308
/* Transmit collision count for CPU GDM */
#define MT7620_MIB_STATS_GDM1_TX_COLCNT 0x30C
/* Received good byte count for CPU GDM */
#define MT7620_MIB_STATS_GDM1_RX_GBCNT1 0x320
/* Received good packet count for CPU GDM (exclude flow control frame) */
#define MT7620_MIB_STATS_GDM1_RX_GPCNT1 0x324
/* Received overflow error packet count for CPU GDM */
#define MT7620_MIB_STATS_GDM1_RX_OERCNT 0x328
/* Received FCS error packet count for CPU GDM */
#define MT7620_MIB_STATS_GDM1_RX_FERCNT 0x32C
/* Received too short error packet count for CPU GDM */
#define MT7620_MIB_STATS_GDM1_RX_SERCNT 0x330
/* Received too long error packet count for CPU GDM */
#define MT7620_MIB_STATS_GDM1_RX_LERCNT 0x334
/* Received IP/TCP/UDP checksum error packet count for CPU GDM */
#define MT7620_MIB_STATS_GDM1_RX_CERCNT 0x338
/* Received flow control pkt count for CPU GDM */
#define MT7620_MIB_STATS_GDM1_RX_FCCNT 0x33C
/* Transmit good byte count for PPE GDM */
#define MT7620_MIB_STATS_GDM2_TX_GBCNT 0x340
/* Transmit good packet count for PPE GDM (exclude flow control frames) */
#define MT7620_MIB_STATS_GDM2_TX_GPCNT 0x344
/* Transmit abort count for PPE GDM */
#define MT7620_MIB_STATS_GDM2_TX_SKIPCNT 0x348
/* Transmit collision count for PPE GDM */
#define MT7620_MIB_STATS_GDM2_TX_COLCNT 0x34C
/* Received good byte count for PPE GDM */
#define MT7620_MIB_STATS_GDM2_RX_GBCNT 0x360
/* Received good packet count for PPE GDM (exclude flow control frame) */
#define MT7620_MIB_STATS_GDM2_RX_GPCNT 0x364
/* Received overflow error packet count for PPE GDM */
#define MT7620_MIB_STATS_GDM2_RX_OERCNT 0x368
/* Received FCS error packet count for PPE GDM */
#define MT7620_MIB_STATS_GDM2_RX_FERCNT 0x36C
/* Received too short error packet count for PPE GDM */
#define MT7620_MIB_STATS_GDM2_RX_SERCNT 0x370
/* Received too long error packet count for PPE GDM */
#define MT7620_MIB_STATS_GDM2_RX_LERCNT 0x374
/* Received IP/TCP/UDP checksum error packet count for PPE GDM */
#define MT7620_MIB_STATS_GDM2_RX_CERCNT 0x378
/* Received flow control pkt count for PPE GDM */
#define MT7620_MIB_STATS_GDM2_RX_FCCNT 0x37C
/* Tx Packet Counter of Port n */
#define MT7620_MIB_STATS_PORT_TGPCN 0x10
/* Tx Bad Octet Counter of Port n */
#define MT7620_MIB_STATS_PORT_TBOCN 0x14
/* Tx Good Octet Counter of Port n */
#define MT7620_MIB_STATS_PORT_TGOCN 0x18
/* Tx Event Packet Counter of Port n */
#define MT7620_MIB_STATS_PORT_TEPCN 0x1C
/* Rx Packet Counter of Port n */
#define MT7620_MIB_STATS_PORT_RGPCN 0x20
/* Rx Bad Octet Counter of Port n */
#define MT7620_MIB_STATS_PORT_RBOCN 0x24
/* Rx Good Octet Counter of Port n */
#define MT7620_MIB_STATS_PORT_RGOCN 0x28
/* Rx Event Packet Counter of Port n */
#define MT7620_MIB_STATS_PORT_REPC1N 0x2C
/* Rx Event Packet Counter of Port n */
#define MT7620_MIB_STATS_PORT_REPC2N 0x30
#define MT7621_MIB_COUNTER_BASE 0x4000
#define MT7621_MIB_COUNTER_PORT_OFFSET 0x100
#define MT7621_STATS_TDPC 0x00
#define MT7621_STATS_TCRC 0x04
#define MT7621_STATS_TUPC 0x08
#define MT7621_STATS_TMPC 0x0C
#define MT7621_STATS_TBPC 0x10
#define MT7621_STATS_TCEC 0x14
#define MT7621_STATS_TSCEC 0x18
#define MT7621_STATS_TMCEC 0x1C
#define MT7621_STATS_TDEC 0x20
#define MT7621_STATS_TLCEC 0x24
#define MT7621_STATS_TXCEC 0x28
#define MT7621_STATS_TPPC 0x2C
#define MT7621_STATS_TL64PC 0x30
#define MT7621_STATS_TL65PC 0x34
#define MT7621_STATS_TL128PC 0x38
#define MT7621_STATS_TL256PC 0x3C
#define MT7621_STATS_TL512PC 0x40
#define MT7621_STATS_TL1024PC 0x44
#define MT7621_STATS_TOC 0x48
#define MT7621_STATS_RDPC 0x60
#define MT7621_STATS_RFPC 0x64
#define MT7621_STATS_RUPC 0x68
#define MT7621_STATS_RMPC 0x6C
#define MT7621_STATS_RBPC 0x70
#define MT7621_STATS_RAEPC 0x74
#define MT7621_STATS_RCEPC 0x78
#define MT7621_STATS_RUSPC 0x7C
#define MT7621_STATS_RFEPC 0x80
#define MT7621_STATS_ROSPC 0x84
#define MT7621_STATS_RJEPC 0x88
#define MT7621_STATS_RPPC 0x8C
#define MT7621_STATS_RL64PC 0x90
#define MT7621_STATS_RL65PC 0x94
#define MT7621_STATS_RL128PC 0x98
#define MT7621_STATS_RL256PC 0x9C
#define MT7621_STATS_RL512PC 0xA0
#define MT7621_STATS_RL1024PC 0xA4
#define MT7621_STATS_ROC 0xA8
#define MT7621_STATS_RDPC_CTRL 0xB0
#define MT7621_STATS_RDPC_ING 0xB4
#define MT7621_STATS_RDPC_ARL 0xB8
int mt7530_probe(struct device *dev, void __iomem *base, struct mii_bus *bus, int vlan);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,523 @@
/* 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-2015 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2013-2015 Michael Lee <igvtee@gmail.com>
*/
#ifndef FE_ETH_H
#define FE_ETH_H
#include <linux/mii.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/dma-mapping.h>
#include <linux/phy.h>
#include <linux/ethtool.h>
#include <linux/version.h>
enum fe_reg {
FE_REG_PDMA_GLO_CFG = 0,
FE_REG_PDMA_RST_CFG,
FE_REG_DLY_INT_CFG,
FE_REG_TX_BASE_PTR0,
FE_REG_TX_MAX_CNT0,
FE_REG_TX_CTX_IDX0,
FE_REG_TX_DTX_IDX0,
FE_REG_RX_BASE_PTR0,
FE_REG_RX_MAX_CNT0,
FE_REG_RX_CALC_IDX0,
FE_REG_RX_DRX_IDX0,
FE_REG_FE_INT_ENABLE,
FE_REG_FE_INT_STATUS,
FE_REG_FE_DMA_VID_BASE,
FE_REG_FE_COUNTER_BASE,
FE_REG_FE_RST_GL,
FE_REG_FE_INT_STATUS2,
FE_REG_COUNT
};
enum fe_work_flag {
FE_FLAG_RESET_PENDING,
FE_FLAG_MAX
};
#define MTK_FE_DRV_VERSION "0.1.2"
/* power of 2 to let NEXT_TX_DESP_IDX work */
#define NUM_DMA_DESC BIT(10)
#define MAX_DMA_DESC 0xfff
#define FE_DELAY_EN_INT 0x80
#define FE_DELAY_MAX_INT 0x04
#define FE_DELAY_MAX_TOUT 0x04
#define FE_DELAY_TIME 20
#define FE_DELAY_CHAN (((FE_DELAY_EN_INT | FE_DELAY_MAX_INT) << 8) | \
FE_DELAY_MAX_TOUT)
#define FE_DELAY_INIT ((FE_DELAY_CHAN << 16) | FE_DELAY_CHAN)
#define FE_PSE_FQFC_CFG_INIT 0x80504000
#define FE_PSE_FQFC_CFG_256Q 0xff908000
/* interrupt bits */
#define FE_CNT_PPE_AF BIT(31)
#define FE_CNT_GDM_AF BIT(29)
#define FE_PSE_P2_FC BIT(26)
#define FE_PSE_BUF_DROP BIT(24)
#define FE_GDM_OTHER_DROP BIT(23)
#define FE_PSE_P1_FC BIT(22)
#define FE_PSE_P0_FC BIT(21)
#define FE_PSE_FQ_EMPTY BIT(20)
#define FE_GE1_STA_CHG BIT(18)
#define FE_TX_COHERENT BIT(17)
#define FE_RX_COHERENT BIT(16)
#define FE_TX_DONE_INT3 BIT(11)
#define FE_TX_DONE_INT2 BIT(10)
#define FE_TX_DONE_INT1 BIT(9)
#define FE_TX_DONE_INT0 BIT(8)
#define FE_RX_DONE_INT0 BIT(2)
#define FE_TX_DLY_INT BIT(1)
#define FE_RX_DLY_INT BIT(0)
#define FE_RX_DONE_INT FE_RX_DONE_INT0
#define FE_TX_DONE_INT (FE_TX_DONE_INT0 | FE_TX_DONE_INT1 | \
FE_TX_DONE_INT2 | FE_TX_DONE_INT3)
#define RT5350_RX_DLY_INT BIT(30)
#define RT5350_TX_DLY_INT BIT(28)
#define RT5350_RX_DONE_INT1 BIT(17)
#define RT5350_RX_DONE_INT0 BIT(16)
#define RT5350_TX_DONE_INT3 BIT(3)
#define RT5350_TX_DONE_INT2 BIT(2)
#define RT5350_TX_DONE_INT1 BIT(1)
#define RT5350_TX_DONE_INT0 BIT(0)
#define RT5350_RX_DONE_INT (RT5350_RX_DONE_INT0 | RT5350_RX_DONE_INT1)
#define RT5350_TX_DONE_INT (RT5350_TX_DONE_INT0 | RT5350_TX_DONE_INT1 | \
RT5350_TX_DONE_INT2 | RT5350_TX_DONE_INT3)
/* registers */
#define FE_FE_OFFSET 0x0000
#define FE_GDMA_OFFSET 0x0020
#define FE_PSE_OFFSET 0x0040
#define FE_GDMA2_OFFSET 0x0060
#define FE_CDMA_OFFSET 0x0080
#define FE_DMA_VID0 0x00a8
#define FE_PDMA_OFFSET 0x0100
#define FE_PPE_OFFSET 0x0200
#define FE_CMTABLE_OFFSET 0x0400
#define FE_POLICYTABLE_OFFSET 0x1000
#define RT5350_PDMA_OFFSET 0x0800
#define RT5350_SDM_OFFSET 0x0c00
#define FE_MDIO_ACCESS (FE_FE_OFFSET + 0x00)
#define FE_MDIO_CFG (FE_FE_OFFSET + 0x04)
#define FE_FE_GLO_CFG (FE_FE_OFFSET + 0x08)
#define FE_FE_RST_GL (FE_FE_OFFSET + 0x0C)
#define FE_FE_INT_STATUS (FE_FE_OFFSET + 0x10)
#define FE_FE_INT_ENABLE (FE_FE_OFFSET + 0x14)
#define FE_MDIO_CFG2 (FE_FE_OFFSET + 0x18)
#define FE_FOC_TS_T (FE_FE_OFFSET + 0x1C)
#define FE_GDMA1_FWD_CFG (FE_GDMA_OFFSET + 0x00)
#define FE_GDMA1_SCH_CFG (FE_GDMA_OFFSET + 0x04)
#define FE_GDMA1_SHPR_CFG (FE_GDMA_OFFSET + 0x08)
#define FE_GDMA1_MAC_ADRL (FE_GDMA_OFFSET + 0x0C)
#define FE_GDMA1_MAC_ADRH (FE_GDMA_OFFSET + 0x10)
#define FE_GDMA2_FWD_CFG (FE_GDMA2_OFFSET + 0x00)
#define FE_GDMA2_SCH_CFG (FE_GDMA2_OFFSET + 0x04)
#define FE_GDMA2_SHPR_CFG (FE_GDMA2_OFFSET + 0x08)
#define FE_GDMA2_MAC_ADRL (FE_GDMA2_OFFSET + 0x0C)
#define FE_GDMA2_MAC_ADRH (FE_GDMA2_OFFSET + 0x10)
#define FE_PSE_FQ_CFG (FE_PSE_OFFSET + 0x00)
#define FE_CDMA_FC_CFG (FE_PSE_OFFSET + 0x04)
#define FE_GDMA1_FC_CFG (FE_PSE_OFFSET + 0x08)
#define FE_GDMA2_FC_CFG (FE_PSE_OFFSET + 0x0C)
#define FE_CDMA_CSG_CFG (FE_CDMA_OFFSET + 0x00)
#define FE_CDMA_SCH_CFG (FE_CDMA_OFFSET + 0x04)
#ifdef CONFIG_SOC_MT7621
#define MT7620A_GDMA_OFFSET 0x0500
#else
#define MT7620A_GDMA_OFFSET 0x0600
#endif
#define MT7620A_GDMA1_FWD_CFG (MT7620A_GDMA_OFFSET + 0x00)
#define MT7620A_FE_GDMA1_SCH_CFG (MT7620A_GDMA_OFFSET + 0x04)
#define MT7620A_FE_GDMA1_SHPR_CFG (MT7620A_GDMA_OFFSET + 0x08)
#define MT7620A_FE_GDMA1_MAC_ADRL (MT7620A_GDMA_OFFSET + 0x0C)
#define MT7620A_FE_GDMA1_MAC_ADRH (MT7620A_GDMA_OFFSET + 0x10)
#define RT5350_TX_BASE_PTR0 (RT5350_PDMA_OFFSET + 0x00)
#define RT5350_TX_MAX_CNT0 (RT5350_PDMA_OFFSET + 0x04)
#define RT5350_TX_CTX_IDX0 (RT5350_PDMA_OFFSET + 0x08)
#define RT5350_TX_DTX_IDX0 (RT5350_PDMA_OFFSET + 0x0C)
#define RT5350_TX_BASE_PTR1 (RT5350_PDMA_OFFSET + 0x10)
#define RT5350_TX_MAX_CNT1 (RT5350_PDMA_OFFSET + 0x14)
#define RT5350_TX_CTX_IDX1 (RT5350_PDMA_OFFSET + 0x18)
#define RT5350_TX_DTX_IDX1 (RT5350_PDMA_OFFSET + 0x1C)
#define RT5350_TX_BASE_PTR2 (RT5350_PDMA_OFFSET + 0x20)
#define RT5350_TX_MAX_CNT2 (RT5350_PDMA_OFFSET + 0x24)
#define RT5350_TX_CTX_IDX2 (RT5350_PDMA_OFFSET + 0x28)
#define RT5350_TX_DTX_IDX2 (RT5350_PDMA_OFFSET + 0x2C)
#define RT5350_TX_BASE_PTR3 (RT5350_PDMA_OFFSET + 0x30)
#define RT5350_TX_MAX_CNT3 (RT5350_PDMA_OFFSET + 0x34)
#define RT5350_TX_CTX_IDX3 (RT5350_PDMA_OFFSET + 0x38)
#define RT5350_TX_DTX_IDX3 (RT5350_PDMA_OFFSET + 0x3C)
#define RT5350_RX_BASE_PTR0 (RT5350_PDMA_OFFSET + 0x100)
#define RT5350_RX_MAX_CNT0 (RT5350_PDMA_OFFSET + 0x104)
#define RT5350_RX_CALC_IDX0 (RT5350_PDMA_OFFSET + 0x108)
#define RT5350_RX_DRX_IDX0 (RT5350_PDMA_OFFSET + 0x10C)
#define RT5350_RX_BASE_PTR1 (RT5350_PDMA_OFFSET + 0x110)
#define RT5350_RX_MAX_CNT1 (RT5350_PDMA_OFFSET + 0x114)
#define RT5350_RX_CALC_IDX1 (RT5350_PDMA_OFFSET + 0x118)
#define RT5350_RX_DRX_IDX1 (RT5350_PDMA_OFFSET + 0x11C)
#define RT5350_PDMA_GLO_CFG (RT5350_PDMA_OFFSET + 0x204)
#define RT5350_PDMA_RST_CFG (RT5350_PDMA_OFFSET + 0x208)
#define RT5350_DLY_INT_CFG (RT5350_PDMA_OFFSET + 0x20c)
#define RT5350_FE_INT_STATUS (RT5350_PDMA_OFFSET + 0x220)
#define RT5350_FE_INT_ENABLE (RT5350_PDMA_OFFSET + 0x228)
#define RT5350_PDMA_SCH_CFG (RT5350_PDMA_OFFSET + 0x280)
#define FE_PDMA_GLO_CFG (FE_PDMA_OFFSET + 0x00)
#define FE_PDMA_RST_CFG (FE_PDMA_OFFSET + 0x04)
#define FE_PDMA_SCH_CFG (FE_PDMA_OFFSET + 0x08)
#define FE_DLY_INT_CFG (FE_PDMA_OFFSET + 0x0C)
#define FE_TX_BASE_PTR0 (FE_PDMA_OFFSET + 0x10)
#define FE_TX_MAX_CNT0 (FE_PDMA_OFFSET + 0x14)
#define FE_TX_CTX_IDX0 (FE_PDMA_OFFSET + 0x18)
#define FE_TX_DTX_IDX0 (FE_PDMA_OFFSET + 0x1C)
#define FE_TX_BASE_PTR1 (FE_PDMA_OFFSET + 0x20)
#define FE_TX_MAX_CNT1 (FE_PDMA_OFFSET + 0x24)
#define FE_TX_CTX_IDX1 (FE_PDMA_OFFSET + 0x28)
#define FE_TX_DTX_IDX1 (FE_PDMA_OFFSET + 0x2C)
#define FE_RX_BASE_PTR0 (FE_PDMA_OFFSET + 0x30)
#define FE_RX_MAX_CNT0 (FE_PDMA_OFFSET + 0x34)
#define FE_RX_CALC_IDX0 (FE_PDMA_OFFSET + 0x38)
#define FE_RX_DRX_IDX0 (FE_PDMA_OFFSET + 0x3C)
#define FE_TX_BASE_PTR2 (FE_PDMA_OFFSET + 0x40)
#define FE_TX_MAX_CNT2 (FE_PDMA_OFFSET + 0x44)
#define FE_TX_CTX_IDX2 (FE_PDMA_OFFSET + 0x48)
#define FE_TX_DTX_IDX2 (FE_PDMA_OFFSET + 0x4C)
#define FE_TX_BASE_PTR3 (FE_PDMA_OFFSET + 0x50)
#define FE_TX_MAX_CNT3 (FE_PDMA_OFFSET + 0x54)
#define FE_TX_CTX_IDX3 (FE_PDMA_OFFSET + 0x58)
#define FE_TX_DTX_IDX3 (FE_PDMA_OFFSET + 0x5C)
#define FE_RX_BASE_PTR1 (FE_PDMA_OFFSET + 0x60)
#define FE_RX_MAX_CNT1 (FE_PDMA_OFFSET + 0x64)
#define FE_RX_CALC_IDX1 (FE_PDMA_OFFSET + 0x68)
#define FE_RX_DRX_IDX1 (FE_PDMA_OFFSET + 0x6C)
/* Switch DMA configuration */
#define RT5350_SDM_CFG (RT5350_SDM_OFFSET + 0x00)
#define RT5350_SDM_RRING (RT5350_SDM_OFFSET + 0x04)
#define RT5350_SDM_TRING (RT5350_SDM_OFFSET + 0x08)
#define RT5350_SDM_MAC_ADRL (RT5350_SDM_OFFSET + 0x0C)
#define RT5350_SDM_MAC_ADRH (RT5350_SDM_OFFSET + 0x10)
#define RT5350_SDM_TPCNT (RT5350_SDM_OFFSET + 0x100)
#define RT5350_SDM_TBCNT (RT5350_SDM_OFFSET + 0x104)
#define RT5350_SDM_RPCNT (RT5350_SDM_OFFSET + 0x108)
#define RT5350_SDM_RBCNT (RT5350_SDM_OFFSET + 0x10C)
#define RT5350_SDM_CS_ERR (RT5350_SDM_OFFSET + 0x110)
#define RT5350_SDM_ICS_EN BIT(16)
#define RT5350_SDM_TCS_EN BIT(17)
#define RT5350_SDM_UCS_EN BIT(18)
/* MDIO_CFG register bits */
#define FE_MDIO_CFG_AUTO_POLL_EN BIT(29)
#define FE_MDIO_CFG_GP1_BP_EN BIT(16)
#define FE_MDIO_CFG_GP1_FRC_EN BIT(15)
#define FE_MDIO_CFG_GP1_SPEED_10 (0 << 13)
#define FE_MDIO_CFG_GP1_SPEED_100 (1 << 13)
#define FE_MDIO_CFG_GP1_SPEED_1000 (2 << 13)
#define FE_MDIO_CFG_GP1_DUPLEX BIT(12)
#define FE_MDIO_CFG_GP1_FC_TX BIT(11)
#define FE_MDIO_CFG_GP1_FC_RX BIT(10)
#define FE_MDIO_CFG_GP1_LNK_DWN BIT(9)
#define FE_MDIO_CFG_GP1_AN_FAIL BIT(8)
#define FE_MDIO_CFG_MDC_CLK_DIV_1 (0 << 6)
#define FE_MDIO_CFG_MDC_CLK_DIV_2 (1 << 6)
#define FE_MDIO_CFG_MDC_CLK_DIV_4 (2 << 6)
#define FE_MDIO_CFG_MDC_CLK_DIV_8 (3 << 6)
#define FE_MDIO_CFG_TURBO_MII_FREQ BIT(5)
#define FE_MDIO_CFG_TURBO_MII_MODE BIT(4)
#define FE_MDIO_CFG_RX_CLK_SKEW_0 (0 << 2)
#define FE_MDIO_CFG_RX_CLK_SKEW_200 (1 << 2)
#define FE_MDIO_CFG_RX_CLK_SKEW_400 (2 << 2)
#define FE_MDIO_CFG_RX_CLK_SKEW_INV (3 << 2)
#define FE_MDIO_CFG_TX_CLK_SKEW_0 0
#define FE_MDIO_CFG_TX_CLK_SKEW_200 1
#define FE_MDIO_CFG_TX_CLK_SKEW_400 2
#define FE_MDIO_CFG_TX_CLK_SKEW_INV 3
/* uni-cast port */
#define FE_GDM1_JMB_LEN_MASK 0xf
#define FE_GDM1_JMB_LEN_SHIFT 28
#define FE_GDM1_ICS_EN BIT(22)
#define FE_GDM1_TCS_EN BIT(21)
#define FE_GDM1_UCS_EN BIT(20)
#define FE_GDM1_JMB_EN BIT(19)
#define FE_GDM1_STRPCRC BIT(16)
#define FE_GDM1_UFRC_P_CPU (0 << 12)
#define FE_GDM1_UFRC_P_GDMA1 (1 << 12)
#define FE_GDM1_UFRC_P_PPE (6 << 12)
/* checksums */
#define FE_ICS_GEN_EN BIT(2)
#define FE_UCS_GEN_EN BIT(1)
#define FE_TCS_GEN_EN BIT(0)
/* dma ring */
#define FE_PST_DRX_IDX0 BIT(16)
#define FE_PST_DTX_IDX3 BIT(3)
#define FE_PST_DTX_IDX2 BIT(2)
#define FE_PST_DTX_IDX1 BIT(1)
#define FE_PST_DTX_IDX0 BIT(0)
#define FE_RX_2B_OFFSET BIT(31)
#define FE_TX_WB_DDONE BIT(6)
#define FE_RX_DMA_BUSY BIT(3)
#define FE_TX_DMA_BUSY BIT(1)
#define FE_RX_DMA_EN BIT(2)
#define FE_TX_DMA_EN BIT(0)
#define FE_PDMA_SIZE_4DWORDS (0 << 4)
#define FE_PDMA_SIZE_8DWORDS (1 << 4)
#define FE_PDMA_SIZE_16DWORDS (2 << 4)
#define FE_US_CYC_CNT_MASK 0xff
#define FE_US_CYC_CNT_SHIFT 0x8
#define FE_US_CYC_CNT_DIVISOR 1000000
/* rxd2 */
#define RX_DMA_DONE BIT(31)
#define RX_DMA_LSO BIT(30)
#define RX_DMA_PLEN0(_x) (((_x) & 0x3fff) << 16)
#define RX_DMA_GET_PLEN0(_x) (((_x) >> 16) & 0x3fff)
#define RX_DMA_TAG BIT(15)
/* rxd3 */
#define RX_DMA_TPID(_x) (((_x) >> 16) & 0xffff)
#define RX_DMA_VID(_x) ((_x) & 0xffff)
/* rxd4 */
#define RX_DMA_L4VALID BIT(30)
struct fe_rx_dma {
unsigned int rxd1;
unsigned int rxd2;
unsigned int rxd3;
unsigned int rxd4;
} __packed __aligned(4);
#define TX_DMA_BUF_LEN 0x3fff
#define TX_DMA_PLEN0_MASK (TX_DMA_BUF_LEN << 16)
#define TX_DMA_PLEN0(_x) (((_x) & TX_DMA_BUF_LEN) << 16)
#define TX_DMA_PLEN1(_x) ((_x) & TX_DMA_BUF_LEN)
#define TX_DMA_GET_PLEN0(_x) (((_x) >> 16) & TX_DMA_BUF_LEN)
#define TX_DMA_GET_PLEN1(_x) ((_x) & TX_DMA_BUF_LEN)
#define TX_DMA_LS1 BIT(14)
#define TX_DMA_LS0 BIT(30)
#define TX_DMA_DONE BIT(31)
#define TX_DMA_INS_VLAN_MT7621 BIT(16)
#define TX_DMA_INS_VLAN BIT(7)
#define TX_DMA_INS_PPPOE BIT(12)
#define TX_DMA_QN(_x) ((_x) << 16)
#define TX_DMA_PN(_x) ((_x) << 24)
#define TX_DMA_QN_MASK TX_DMA_QN(0x7)
#define TX_DMA_PN_MASK TX_DMA_PN(0x7)
#define TX_DMA_UDF BIT(20)
#define TX_DMA_CHKSUM (0x7 << 29)
#define TX_DMA_TSO BIT(28)
/* frame engine counters */
#define FE_PPE_AC_BCNT0 (FE_CMTABLE_OFFSET + 0x00)
#define FE_GDMA1_TX_GBCNT (FE_CMTABLE_OFFSET + 0x300)
#define FE_GDMA2_TX_GBCNT (FE_GDMA1_TX_GBCNT + 0x40)
/* phy device flags */
#define FE_PHY_FLAG_PORT BIT(0)
#define FE_PHY_FLAG_ATTACH BIT(1)
struct fe_tx_dma {
unsigned int txd1;
unsigned int txd2;
unsigned int txd3;
unsigned int txd4;
} __packed __aligned(4);
struct fe_priv;
struct fe_phy {
/* make sure that phy operations are atomic */
spinlock_t lock;
struct phy_device *phy[8];
struct device_node *phy_node[8];
const __be32 *phy_fixed[8];
int duplex[8];
int speed[8];
int tx_fc[8];
int rx_fc[8];
int (*connect)(struct fe_priv *priv);
void (*disconnect)(struct fe_priv *priv);
void (*start)(struct fe_priv *priv);
void (*stop)(struct fe_priv *priv);
};
struct fe_soc_data {
const u16 *reg_table;
void (*init_data)(struct fe_soc_data *data, struct net_device *netdev);
void (*reset_fe)(void);
void (*set_mac)(struct fe_priv *priv, unsigned char *mac);
int (*fwd_config)(struct fe_priv *priv);
void (*tx_dma)(struct fe_tx_dma *txd);
int (*switch_init)(struct fe_priv *priv);
int (*switch_config)(struct fe_priv *priv);
void (*port_init)(struct fe_priv *priv, struct device_node *port);
int (*has_carrier)(struct fe_priv *priv);
int (*mdio_init)(struct fe_priv *priv);
void (*mdio_cleanup)(struct fe_priv *priv);
int (*mdio_write)(struct mii_bus *bus, int phy_addr, int phy_reg,
u16 val);
int (*mdio_read)(struct mii_bus *bus, int phy_addr, int phy_reg);
void (*mdio_adjust_link)(struct fe_priv *priv, int port);
void *swpriv;
u32 pdma_glo_cfg;
u32 rx_int;
u32 tx_int;
u32 status_int;
u32 checksum_bit;
};
#define FE_FLAG_PADDING_64B BIT(0)
#define FE_FLAG_PADDING_BUG BIT(1)
#define FE_FLAG_JUMBO_FRAME BIT(2)
#define FE_FLAG_RX_2B_OFFSET BIT(3)
#define FE_FLAG_RX_SG_DMA BIT(4)
#define FE_FLAG_RX_VLAN_CTAG BIT(5)
#define FE_FLAG_NAPI_WEIGHT BIT(6)
#define FE_FLAG_CALIBRATE_CLK BIT(7)
#define FE_FLAG_HAS_SWITCH BIT(8)
#define FE_STAT_REG_DECLARE \
_FE(tx_bytes) \
_FE(tx_packets) \
_FE(tx_skip) \
_FE(tx_collisions) \
_FE(rx_bytes) \
_FE(rx_packets) \
_FE(rx_overflow) \
_FE(rx_fcs_errors) \
_FE(rx_short_errors) \
_FE(rx_long_errors) \
_FE(rx_checksum_errors) \
_FE(rx_flow_control_packets)
struct fe_hw_stats {
/* make sure that stats operations are atomic */
spinlock_t stats_lock;
struct u64_stats_sync syncp;
#define _FE(x) u64 x;
FE_STAT_REG_DECLARE
#undef _FE
};
enum fe_tx_flags {
FE_TX_FLAGS_SINGLE0 = 0x01,
FE_TX_FLAGS_PAGE0 = 0x02,
FE_TX_FLAGS_PAGE1 = 0x04,
};
struct fe_tx_buf {
struct sk_buff *skb;
u32 flags;
DEFINE_DMA_UNMAP_ADDR(dma_addr0);
DEFINE_DMA_UNMAP_LEN(dma_len0);
DEFINE_DMA_UNMAP_ADDR(dma_addr1);
DEFINE_DMA_UNMAP_LEN(dma_len1);
};
struct fe_tx_ring {
struct fe_tx_dma *tx_dma;
struct fe_tx_buf *tx_buf;
dma_addr_t tx_phys;
u16 tx_ring_size;
u16 tx_free_idx;
u16 tx_next_idx;
u16 tx_thresh;
};
struct fe_rx_ring {
struct fe_rx_dma *rx_dma;
u8 **rx_data;
dma_addr_t rx_phys;
u16 rx_ring_size;
u16 frag_size;
u16 rx_buf_size;
u16 rx_calc_idx;
};
struct fe_priv {
/* make sure that register operations are atomic */
spinlock_t page_lock;
struct fe_soc_data *soc;
struct net_device *netdev;
struct device_node *switch_np;
u32 msg_enable;
u32 flags;
struct device *device;
unsigned long sysclk;
struct fe_rx_ring rx_ring;
struct napi_struct rx_napi;
struct fe_tx_ring tx_ring;
struct fe_phy *phy;
struct mii_bus *mii_bus;
struct phy_device *phy_dev;
u32 phy_flags;
int link[8];
struct fe_hw_stats *hw_stats;
unsigned long vlan_map;
struct work_struct pending_work;
DECLARE_BITMAP(pending_flags, FE_FLAG_MAX);
};
extern const struct of_device_id of_fe_match[];
void fe_w32(u32 val, unsigned reg);
u32 fe_r32(unsigned reg);
int fe_set_clock_cycle(struct fe_priv *priv);
void fe_csum_config(struct fe_priv *priv);
void fe_stats_update(struct fe_priv *priv);
void fe_fwd_config(struct fe_priv *priv);
void fe_reg_w32(u32 val, enum fe_reg reg);
u32 fe_reg_r32(enum fe_reg reg);
void fe_reset(u32 reset_bits);
static inline void *priv_netdev(struct fe_priv *priv)
{
return (char *)priv - ALIGN(sizeof(struct net_device), NETDEV_ALIGN);
}
#endif /* FE_ETH_H */

View file

@ -0,0 +1,335 @@
/* 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-2015 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2013-2015 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 <mt7620.h>
#include "mtk_eth_soc.h"
#include "gsw_mt7620.h"
#include "mt7530.h"
#include "mdio.h"
#define MT7620A_CDMA_CSG_CFG 0x400
#define MT7620_DMA_VID (MT7620A_CDMA_CSG_CFG | 0x30)
#define MT7621_CDMP_IG_CTRL (MT7620A_CDMA_CSG_CFG + 0x00)
#define MT7621_CDMP_EG_CTRL (MT7620A_CDMA_CSG_CFG + 0x04)
#define MT7620A_RESET_FE BIT(21)
#define MT7621_RESET_FE BIT(6)
#define MT7620A_RESET_ESW BIT(23)
#define MT7620_L4_VALID BIT(23)
#define MT7621_L4_VALID BIT(24)
#define MT7620_TX_DMA_UDF BIT(15)
#define MT7621_TX_DMA_UDF BIT(19)
#define TX_DMA_FP_BMAP ((0xff) << 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 MT7620_REG_MIB_OFFSET 0x1000
#define MT7620_PPE_AC_BCNT0 (MT7620_REG_MIB_OFFSET + 0x00)
#define MT7620_GDM1_TX_GBCNT (MT7620_REG_MIB_OFFSET + 0x300)
#define MT7620_GDM2_TX_GBCNT (MT7620_GDM1_TX_GBCNT + 0x40)
#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 MT7621_FE_RST_GL (FE_FE_OFFSET + 0x04)
#define MT7620_FE_INT_STATUS2 (FE_FE_OFFSET + 0x08)
/* FE_INT_STATUS reg on mt7620 define CNT_GDM1_AF at BIT(29)
* but after test it should be BIT(13).
*/
#define MT7620_FE_GDM1_AF BIT(13)
#define MT7621_FE_GDM1_AF BIT(28)
#define MT7621_FE_GDM2_AF BIT(29)
static const u16 mt7620_reg_table[FE_REG_COUNT] = {
[FE_REG_PDMA_GLO_CFG] = RT5350_PDMA_GLO_CFG,
[FE_REG_PDMA_RST_CFG] = RT5350_PDMA_RST_CFG,
[FE_REG_DLY_INT_CFG] = RT5350_DLY_INT_CFG,
[FE_REG_TX_BASE_PTR0] = RT5350_TX_BASE_PTR0,
[FE_REG_TX_MAX_CNT0] = RT5350_TX_MAX_CNT0,
[FE_REG_TX_CTX_IDX0] = RT5350_TX_CTX_IDX0,
[FE_REG_TX_DTX_IDX0] = RT5350_TX_DTX_IDX0,
[FE_REG_RX_BASE_PTR0] = RT5350_RX_BASE_PTR0,
[FE_REG_RX_MAX_CNT0] = RT5350_RX_MAX_CNT0,
[FE_REG_RX_CALC_IDX0] = RT5350_RX_CALC_IDX0,
[FE_REG_RX_DRX_IDX0] = RT5350_RX_DRX_IDX0,
[FE_REG_FE_INT_ENABLE] = RT5350_FE_INT_ENABLE,
[FE_REG_FE_INT_STATUS] = RT5350_FE_INT_STATUS,
[FE_REG_FE_DMA_VID_BASE] = MT7620_DMA_VID,
[FE_REG_FE_COUNTER_BASE] = MT7620_GDM1_TX_GBCNT,
[FE_REG_FE_RST_GL] = MT7621_FE_RST_GL,
[FE_REG_FE_INT_STATUS2] = MT7620_FE_INT_STATUS2,
};
static int mt7620_gsw_config(struct fe_priv *priv)
{
struct mt7620_gsw *gsw = (struct mt7620_gsw *) priv->soc->swpriv;
/* is the mt7530 internal or external */
if (priv->mii_bus && mdiobus_get_phy(priv->mii_bus, 0x1f)) {
mt7530_probe(priv->device, gsw->base, NULL, 0);
mt7530_probe(priv->device, NULL, priv->mii_bus, 1);
} else {
mt7530_probe(priv->device, gsw->base, NULL, 1);
}
return 0;
}
static void mt7620_set_mac(struct fe_priv *priv, unsigned char *mac)
{
struct mt7620_gsw *gsw = (struct mt7620_gsw *)priv->soc->swpriv;
unsigned long flags;
spin_lock_irqsave(&priv->page_lock, flags);
mtk_switch_w32(gsw, (mac[0] << 8) | mac[1], GSW_REG_SMACCR1);
mtk_switch_w32(gsw, (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5],
GSW_REG_SMACCR0);
spin_unlock_irqrestore(&priv->page_lock, flags);
}
static void mt7620_auto_poll(struct mt7620_gsw *gsw)
{
int phy;
int lsb = -1, msb = 0;
for_each_set_bit(phy, &gsw->autopoll, 32) {
if (lsb < 0)
lsb = phy;
msb = phy;
}
if (lsb == msb)
lsb--;
mtk_switch_w32(gsw, PHY_AN_EN | PHY_PRE_EN | PMY_MDC_CONF(5) |
(msb << 8) | lsb, ESW_PHY_POLLING);
}
static void mt7620_port_init(struct fe_priv *priv, struct device_node *np)
{
struct mt7620_gsw *gsw = (struct mt7620_gsw *)priv->soc->swpriv;
const __be32 *_id = of_get_property(np, "reg", NULL);
int phy_mode, size, id;
int shift = 12;
u32 val, mask = 0;
int min = (gsw->port4 == PORT4_EPHY) ? (5) : (4);
if (!_id || (be32_to_cpu(*_id) < min) || (be32_to_cpu(*_id) > 5)) {
if (_id)
pr_err("%s: invalid port id %d\n", np->name,
be32_to_cpu(*_id));
else
pr_err("%s: invalid port id\n", np->name);
return;
}
id = be32_to_cpu(*_id);
if (id == 4)
shift = 14;
priv->phy->phy_fixed[id] = of_get_property(np, "mediatek,fixed-link",
&size);
if (priv->phy->phy_fixed[id] &&
(size != (4 * sizeof(*priv->phy->phy_fixed[id])))) {
pr_err("%s: invalid fixed link property\n", np->name);
priv->phy->phy_fixed[id] = NULL;
return;
}
phy_mode = of_get_phy_mode(np);
switch (phy_mode) {
case PHY_INTERFACE_MODE_RGMII:
mask = 0;
break;
case PHY_INTERFACE_MODE_MII:
mask = 1;
break;
case PHY_INTERFACE_MODE_RMII:
mask = 2;
break;
default:
dev_err(priv->device, "port %d - invalid phy mode\n", id);
return;
}
priv->phy->phy_node[id] = of_parse_phandle(np, "phy-handle", 0);
if (!priv->phy->phy_node[id] && !priv->phy->phy_fixed[id])
return;
val = rt_sysc_r32(SYSC_REG_CFG1);
val &= ~(3 << shift);
val |= mask << shift;
rt_sysc_w32(val, SYSC_REG_CFG1);
if (priv->phy->phy_fixed[id]) {
const __be32 *link = priv->phy->phy_fixed[id];
int tx_fc, rx_fc;
u32 val = 0;
priv->phy->speed[id] = be32_to_cpup(link++);
tx_fc = be32_to_cpup(link++);
rx_fc = be32_to_cpup(link++);
priv->phy->duplex[id] = be32_to_cpup(link++);
priv->link[id] = 1;
switch (priv->phy->speed[id]) {
case SPEED_10:
val = 0;
break;
case SPEED_100:
val = 1;
break;
case SPEED_1000:
val = 2;
break;
default:
dev_err(priv->device, "invalid link speed: %d\n",
priv->phy->speed[id]);
priv->phy->phy_fixed[id] = 0;
return;
}
val = PMCR_SPEED(val);
val |= PMCR_LINK | PMCR_BACKPRES | PMCR_BACKOFF | PMCR_RX_EN |
PMCR_TX_EN | PMCR_FORCE | PMCR_MAC_MODE | PMCR_IPG;
if (tx_fc)
val |= PMCR_TX_FC;
if (rx_fc)
val |= PMCR_RX_FC;
if (priv->phy->duplex[id])
val |= PMCR_DUPLEX;
mtk_switch_w32(gsw, val, GSW_REG_PORT_PMCR(id));
dev_info(priv->device, "using fixed link parameters\n");
return;
}
if (priv->phy->phy_node[id] && mdiobus_get_phy(priv->mii_bus, id)) {
u32 val = PMCR_BACKPRES | PMCR_BACKOFF | PMCR_RX_EN |
PMCR_TX_EN | PMCR_MAC_MODE | PMCR_IPG;
mtk_switch_w32(gsw, val, GSW_REG_PORT_PMCR(id));
fe_connect_phy_node(priv, priv->phy->phy_node[id]);
gsw->autopoll |= BIT(id);
mt7620_auto_poll(gsw);
return;
}
}
static void mt7620_fe_reset(void)
{
fe_reset(MT7620A_RESET_FE | MT7620A_RESET_ESW);
}
static void mt7620_rxcsum_config(bool enable)
{
if (enable)
fe_w32(fe_r32(MT7620A_GDMA1_FWD_CFG) | (GDMA_ICS_EN |
GDMA_TCS_EN | GDMA_UCS_EN),
MT7620A_GDMA1_FWD_CFG);
else
fe_w32(fe_r32(MT7620A_GDMA1_FWD_CFG) & ~(GDMA_ICS_EN |
GDMA_TCS_EN | GDMA_UCS_EN),
MT7620A_GDMA1_FWD_CFG);
}
static void mt7620_txcsum_config(bool enable)
{
if (enable)
fe_w32(fe_r32(MT7620A_CDMA_CSG_CFG) | (CDMA_ICS_EN |
CDMA_UCS_EN | CDMA_TCS_EN),
MT7620A_CDMA_CSG_CFG);
else
fe_w32(fe_r32(MT7620A_CDMA_CSG_CFG) & ~(CDMA_ICS_EN |
CDMA_UCS_EN | CDMA_TCS_EN),
MT7620A_CDMA_CSG_CFG);
}
static int mt7620_fwd_config(struct fe_priv *priv)
{
struct net_device *dev = priv_netdev(priv);
fe_w32(fe_r32(MT7620A_GDMA1_FWD_CFG) & ~7, MT7620A_GDMA1_FWD_CFG);
mt7620_txcsum_config((dev->features & NETIF_F_IP_CSUM));
mt7620_rxcsum_config((dev->features & NETIF_F_RXCSUM));
return 0;
}
static void mt7620_tx_dma(struct fe_tx_dma *txd)
{
}
static void mt7620_init_data(struct fe_soc_data *data,
struct net_device *netdev)
{
struct fe_priv *priv = netdev_priv(netdev);
priv->flags = FE_FLAG_PADDING_64B | FE_FLAG_RX_2B_OFFSET |
FE_FLAG_RX_SG_DMA | FE_FLAG_HAS_SWITCH;
netdev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
NETIF_F_HW_VLAN_CTAG_TX;
if (mt7620_get_eco() >= 5)
netdev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
NETIF_F_IPV6_CSUM;
}
static struct fe_soc_data mt7620_data = {
.init_data = mt7620_init_data,
.reset_fe = mt7620_fe_reset,
.set_mac = mt7620_set_mac,
.fwd_config = mt7620_fwd_config,
.tx_dma = mt7620_tx_dma,
.switch_init = mtk_gsw_init,
.switch_config = mt7620_gsw_config,
.port_init = mt7620_port_init,
.reg_table = mt7620_reg_table,
.pdma_glo_cfg = FE_PDMA_SIZE_16DWORDS,
.rx_int = RT5350_RX_DONE_INT,
.tx_int = RT5350_TX_DONE_INT,
.status_int = MT7620_FE_GDM1_AF,
.checksum_bit = MT7620_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_fe_match[] = {
{ .compatible = "mediatek,mt7620-eth", .data = &mt7620_data },
{},
};
MODULE_DEVICE_TABLE(of, of_fe_match);

View file

@ -0,0 +1,185 @@
/* 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-2015 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2013-2015 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 "mt7530.h"
#include "mdio.h"
#define MT7620A_CDMA_CSG_CFG 0x400
#define MT7621_CDMP_IG_CTRL (MT7620A_CDMA_CSG_CFG + 0x00)
#define MT7621_CDMP_EG_CTRL (MT7620A_CDMA_CSG_CFG + 0x04)
#define MT7621_RESET_FE BIT(6)
#define MT7621_L4_VALID BIT(24)
#define MT7621_TX_DMA_UDF BIT(19)
#define MT7621_TX_DMA_FPORT BIT(25)
#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 MT7621_FE_RST_GL (FE_FE_OFFSET + 0x04)
#define MT7620_FE_INT_STATUS2 (FE_FE_OFFSET + 0x08)
/* FE_INT_STATUS reg on mt7620 define CNT_GDM1_AF at BIT(29)
* but after test it should be BIT(13).
*/
#define MT7620_FE_GDM1_AF BIT(13)
#define MT7621_FE_GDM1_AF BIT(28)
#define MT7621_FE_GDM2_AF BIT(29)
static const u16 mt7621_reg_table[FE_REG_COUNT] = {
[FE_REG_PDMA_GLO_CFG] = RT5350_PDMA_GLO_CFG,
[FE_REG_PDMA_RST_CFG] = RT5350_PDMA_RST_CFG,
[FE_REG_DLY_INT_CFG] = RT5350_DLY_INT_CFG,
[FE_REG_TX_BASE_PTR0] = RT5350_TX_BASE_PTR0,
[FE_REG_TX_MAX_CNT0] = RT5350_TX_MAX_CNT0,
[FE_REG_TX_CTX_IDX0] = RT5350_TX_CTX_IDX0,
[FE_REG_TX_DTX_IDX0] = RT5350_TX_DTX_IDX0,
[FE_REG_RX_BASE_PTR0] = RT5350_RX_BASE_PTR0,
[FE_REG_RX_MAX_CNT0] = RT5350_RX_MAX_CNT0,
[FE_REG_RX_CALC_IDX0] = RT5350_RX_CALC_IDX0,
[FE_REG_RX_DRX_IDX0] = RT5350_RX_DRX_IDX0,
[FE_REG_FE_INT_ENABLE] = RT5350_FE_INT_ENABLE,
[FE_REG_FE_INT_STATUS] = RT5350_FE_INT_STATUS,
[FE_REG_FE_DMA_VID_BASE] = 0,
[FE_REG_FE_COUNTER_BASE] = MT7621_GDM1_TX_GBCNT,
[FE_REG_FE_RST_GL] = MT7621_FE_RST_GL,
[FE_REG_FE_INT_STATUS2] = MT7620_FE_INT_STATUS2,
};
static int mt7621_gsw_config(struct fe_priv *priv)
{
if (priv->mii_bus && mdiobus_get_phy(priv->mii_bus, 0x1f))
mt7530_probe(priv->device, NULL, priv->mii_bus, 1);
return 0;
}
static void mt7621_fe_reset(void)
{
fe_reset(MT7621_RESET_FE);
}
static void mt7621_rxcsum_config(bool enable)
{
if (enable)
fe_w32(fe_r32(MT7620A_GDMA1_FWD_CFG) | (GDMA_ICS_EN |
GDMA_TCS_EN | GDMA_UCS_EN),
MT7620A_GDMA1_FWD_CFG);
else
fe_w32(fe_r32(MT7620A_GDMA1_FWD_CFG) & ~(GDMA_ICS_EN |
GDMA_TCS_EN | GDMA_UCS_EN),
MT7620A_GDMA1_FWD_CFG);
}
static void mt7621_rxvlan_config(bool enable)
{
if (enable)
fe_w32(1, MT7621_CDMP_EG_CTRL);
else
fe_w32(0, MT7621_CDMP_EG_CTRL);
}
static int mt7621_fwd_config(struct fe_priv *priv)
{
struct net_device *dev = priv_netdev(priv);
fe_w32(fe_r32(MT7620A_GDMA1_FWD_CFG) & ~0xffff,
MT7620A_GDMA1_FWD_CFG);
/* mt7621 doesn't have txcsum config */
mt7621_rxcsum_config((dev->features & NETIF_F_RXCSUM));
mt7621_rxvlan_config(priv->flags & FE_FLAG_RX_VLAN_CTAG);
return 0;
}
static void mt7621_tx_dma(struct fe_tx_dma *txd)
{
txd->txd4 = MT7621_TX_DMA_FPORT;
}
static void mt7621_init_data(struct fe_soc_data *data,
struct net_device *netdev)
{
struct fe_priv *priv = netdev_priv(netdev);
priv->flags = FE_FLAG_PADDING_64B | FE_FLAG_RX_2B_OFFSET |
FE_FLAG_RX_SG_DMA | FE_FLAG_NAPI_WEIGHT |
FE_FLAG_HAS_SWITCH | FE_FLAG_JUMBO_FRAME;
netdev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG | NETIF_F_TSO |
NETIF_F_TSO6 | NETIF_F_IPV6_CSUM;
}
static void mt7621_set_mac(struct fe_priv *priv, unsigned char *mac)
{
unsigned long flags;
spin_lock_irqsave(&priv->page_lock, flags);
fe_w32((mac[0] << 8) | mac[1], GSW_REG_GDMA1_MAC_ADRH);
fe_w32((mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5],
GSW_REG_GDMA1_MAC_ADRL);
spin_unlock_irqrestore(&priv->page_lock, flags);
}
static struct fe_soc_data mt7621_data = {
.init_data = mt7621_init_data,
.reset_fe = mt7621_fe_reset,
.set_mac = mt7621_set_mac,
.fwd_config = mt7621_fwd_config,
.tx_dma = mt7621_tx_dma,
.switch_init = mtk_gsw_init,
.switch_config = mt7621_gsw_config,
.reg_table = mt7621_reg_table,
.pdma_glo_cfg = FE_PDMA_SIZE_16DWORDS,
.rx_int = RT5350_RX_DONE_INT,
.tx_int = RT5350_TX_DONE_INT,
.status_int = (MT7621_FE_GDM1_AF | MT7621_FE_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_fe_match[] = {
{ .compatible = "mediatek,mt7621-eth", .data = &mt7621_data },
{},
};
MODULE_DEVICE_TABLE(of, of_fe_match);

View file

@ -0,0 +1,76 @@
/* 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-2015 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2013-2015 Michael Lee <igvtee@gmail.com>
*/
#include <linux/module.h>
#include <asm/mach-ralink/ralink_regs.h>
#include "mtk_eth_soc.h"
#include "mdio_rt2880.h"
#define RT2880_RESET_FE BIT(18)
static void rt2880_init_data(struct fe_soc_data *data,
struct net_device *netdev)
{
struct fe_priv *priv = netdev_priv(netdev);
priv->flags = FE_FLAG_PADDING_64B | FE_FLAG_PADDING_BUG |
FE_FLAG_JUMBO_FRAME | FE_FLAG_CALIBRATE_CLK;
netdev->hw_features = NETIF_F_SG | NETIF_F_HW_VLAN_CTAG_TX;
/* this should work according to the datasheet but actually does not*/
/* netdev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM; */
}
void rt2880_fe_reset(void)
{
fe_reset(RT2880_RESET_FE);
}
static int rt2880_fwd_config(struct fe_priv *priv)
{
int ret;
ret = fe_set_clock_cycle(priv);
if (ret)
return ret;
fe_fwd_config(priv);
fe_w32(FE_PSE_FQFC_CFG_INIT, FE_PSE_FQ_CFG);
fe_csum_config(priv);
return ret;
}
struct fe_soc_data rt2880_data = {
.init_data = rt2880_init_data,
.reset_fe = rt2880_fe_reset,
.fwd_config = rt2880_fwd_config,
.pdma_glo_cfg = FE_PDMA_SIZE_8DWORDS,
.checksum_bit = RX_DMA_L4VALID,
.rx_int = FE_RX_DONE_INT,
.tx_int = FE_TX_DONE_INT,
.status_int = FE_CNT_GDM_AF,
.mdio_read = rt2880_mdio_read,
.mdio_write = rt2880_mdio_write,
.mdio_adjust_link = rt2880_mdio_link_adjust,
.port_init = rt2880_port_init,
};
const struct of_device_id of_fe_match[] = {
{ .compatible = "ralink,rt2880-eth", .data = &rt2880_data },
{},
};
MODULE_DEVICE_TABLE(of, of_fe_match);

View file

@ -0,0 +1,158 @@
/* 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-2015 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2013-2015 Michael Lee <igvtee@gmail.com>
*/
#include <linux/module.h>
#include <asm/mach-ralink/ralink_regs.h>
#include "mtk_eth_soc.h"
#include "mdio_rt2880.h"
#define RT305X_RESET_FE BIT(21)
#define RT305X_RESET_ESW BIT(23)
static const u16 rt5350_reg_table[FE_REG_COUNT] = {
[FE_REG_PDMA_GLO_CFG] = RT5350_PDMA_GLO_CFG,
[FE_REG_PDMA_RST_CFG] = RT5350_PDMA_RST_CFG,
[FE_REG_DLY_INT_CFG] = RT5350_DLY_INT_CFG,
[FE_REG_TX_BASE_PTR0] = RT5350_TX_BASE_PTR0,
[FE_REG_TX_MAX_CNT0] = RT5350_TX_MAX_CNT0,
[FE_REG_TX_CTX_IDX0] = RT5350_TX_CTX_IDX0,
[FE_REG_TX_DTX_IDX0] = RT5350_TX_DTX_IDX0,
[FE_REG_RX_BASE_PTR0] = RT5350_RX_BASE_PTR0,
[FE_REG_RX_MAX_CNT0] = RT5350_RX_MAX_CNT0,
[FE_REG_RX_CALC_IDX0] = RT5350_RX_CALC_IDX0,
[FE_REG_RX_DRX_IDX0] = RT5350_RX_DRX_IDX0,
[FE_REG_FE_INT_ENABLE] = RT5350_FE_INT_ENABLE,
[FE_REG_FE_INT_STATUS] = RT5350_FE_INT_STATUS,
[FE_REG_FE_RST_GL] = 0,
[FE_REG_FE_DMA_VID_BASE] = 0,
};
static void rt305x_init_data(struct fe_soc_data *data,
struct net_device *netdev)
{
struct fe_priv *priv = netdev_priv(netdev);
priv->flags = FE_FLAG_PADDING_64B | FE_FLAG_PADDING_BUG |
FE_FLAG_CALIBRATE_CLK | FE_FLAG_HAS_SWITCH;
netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM |
NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_TX;
}
static int rt3050_fwd_config(struct fe_priv *priv)
{
int ret;
if (ralink_soc != RT305X_SOC_RT3052) {
ret = fe_set_clock_cycle(priv);
if (ret)
return ret;
}
fe_fwd_config(priv);
if (ralink_soc != RT305X_SOC_RT3352)
fe_w32(FE_PSE_FQFC_CFG_INIT, FE_PSE_FQ_CFG);
fe_csum_config(priv);
return 0;
}
static void rt305x_fe_reset(void)
{
fe_reset(RT305X_RESET_FE);
}
static void rt5350_init_data(struct fe_soc_data *data,
struct net_device *netdev)
{
struct fe_priv *priv = netdev_priv(netdev);
priv->flags = FE_FLAG_HAS_SWITCH;
netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM;
}
static void rt5350_set_mac(struct fe_priv *priv, unsigned char *mac)
{
unsigned long flags;
spin_lock_irqsave(&priv->page_lock, flags);
fe_w32((mac[0] << 8) | mac[1], RT5350_SDM_MAC_ADRH);
fe_w32((mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5],
RT5350_SDM_MAC_ADRL);
spin_unlock_irqrestore(&priv->page_lock, flags);
}
static void rt5350_rxcsum_config(bool enable)
{
if (enable)
fe_w32(fe_r32(RT5350_SDM_CFG) | (RT5350_SDM_ICS_EN |
RT5350_SDM_TCS_EN | RT5350_SDM_UCS_EN),
RT5350_SDM_CFG);
else
fe_w32(fe_r32(RT5350_SDM_CFG) & ~(RT5350_SDM_ICS_EN |
RT5350_SDM_TCS_EN | RT5350_SDM_UCS_EN),
RT5350_SDM_CFG);
}
static int rt5350_fwd_config(struct fe_priv *priv)
{
struct net_device *dev = priv_netdev(priv);
rt5350_rxcsum_config((dev->features & NETIF_F_RXCSUM));
return 0;
}
static void rt5350_tx_dma(struct fe_tx_dma *txd)
{
txd->txd4 = 0;
}
static void rt5350_fe_reset(void)
{
fe_reset(RT305X_RESET_FE | RT305X_RESET_ESW);
}
static struct fe_soc_data rt3050_data = {
.init_data = rt305x_init_data,
.reset_fe = rt305x_fe_reset,
.fwd_config = rt3050_fwd_config,
.pdma_glo_cfg = FE_PDMA_SIZE_8DWORDS,
.checksum_bit = RX_DMA_L4VALID,
.rx_int = FE_RX_DONE_INT,
.tx_int = FE_TX_DONE_INT,
.status_int = FE_CNT_GDM_AF,
};
static struct fe_soc_data rt5350_data = {
.init_data = rt5350_init_data,
.reg_table = rt5350_reg_table,
.reset_fe = rt5350_fe_reset,
.set_mac = rt5350_set_mac,
.fwd_config = rt5350_fwd_config,
.tx_dma = rt5350_tx_dma,
.pdma_glo_cfg = FE_PDMA_SIZE_8DWORDS,
.checksum_bit = RX_DMA_L4VALID,
.rx_int = RT5350_RX_DONE_INT,
.tx_int = RT5350_TX_DONE_INT,
};
const struct of_device_id of_fe_match[] = {
{ .compatible = "ralink,rt3050-eth", .data = &rt3050_data },
{ .compatible = "ralink,rt5350-eth", .data = &rt5350_data },
{},
};
MODULE_DEVICE_TABLE(of, of_fe_match);

View file

@ -0,0 +1,75 @@
/* 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-2015 John Crispin <blogic@openwrt.org>
* Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2013-2015 Michael Lee <igvtee@gmail.com>
*/
#include <linux/module.h>
#include <asm/mach-ralink/ralink_regs.h>
#include "mtk_eth_soc.h"
#include "mdio_rt2880.h"
#define RT3883_RSTCTRL_FE BIT(21)
static void rt3883_fe_reset(void)
{
fe_reset(RT3883_RSTCTRL_FE);
}
static int rt3883_fwd_config(struct fe_priv *priv)
{
int ret;
ret = fe_set_clock_cycle(priv);
if (ret)
return ret;
fe_fwd_config(priv);
fe_w32(FE_PSE_FQFC_CFG_256Q, FE_PSE_FQ_CFG);
fe_csum_config(priv);
return ret;
}
static void rt3883_init_data(struct fe_soc_data *data,
struct net_device *netdev)
{
struct fe_priv *priv = netdev_priv(netdev);
priv->flags = FE_FLAG_PADDING_64B | FE_FLAG_PADDING_BUG |
FE_FLAG_JUMBO_FRAME | FE_FLAG_CALIBRATE_CLK;
netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM |
NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_TX;
}
static struct fe_soc_data rt3883_data = {
.init_data = rt3883_init_data,
.reset_fe = rt3883_fe_reset,
.fwd_config = rt3883_fwd_config,
.pdma_glo_cfg = FE_PDMA_SIZE_8DWORDS,
.rx_int = FE_RX_DONE_INT,
.tx_int = FE_TX_DONE_INT,
.status_int = FE_CNT_GDM_AF,
.checksum_bit = RX_DMA_L4VALID,
.mdio_read = rt2880_mdio_read,
.mdio_write = rt2880_mdio_write,
.mdio_adjust_link = rt2880_mdio_link_adjust,
.port_init = rt2880_port_init,
};
const struct of_device_id of_fe_match[] = {
{ .compatible = "ralink,rt3883-eth", .data = &rt3883_data },
{},
};
MODULE_DEVICE_TABLE(of, of_fe_match);

View file

@ -0,0 +1,240 @@
CONFIG_ARCH_BINFMT_ELF_STATE=y
CONFIG_ARCH_CLOCKSOURCE_DATA=y
CONFIG_ARCH_DISCARD_MEMBLOCK=y
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
# CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set
CONFIG_ARCH_HAS_RESET_CONTROLLER=y
# CONFIG_ARCH_HAS_SG_CHAIN is not set
# CONFIG_ARCH_HAS_STRICT_KERNEL_RWX is not set
# CONFIG_ARCH_HAS_STRICT_MODULE_RWX is not set
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
CONFIG_ARCH_MMAP_RND_BITS_MAX=15
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15
# CONFIG_ARCH_OPTIONAL_KERNEL_RWX is not set
# CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT is not set
CONFIG_ARCH_SUPPORTS_UPROBES=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARCH_USE_BUILTIN_BSWAP=y
CONFIG_ARCH_USE_QUEUED_RWLOCKS=y
CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y
# CONFIG_ARCH_WANTS_THP_SWAP is not set
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
CONFIG_AT803X_PHY=y
CONFIG_BLK_MQ_PCI=y
CONFIG_CEVT_R4K=y
CONFIG_CEVT_SYSTICK_QUIRK=y
CONFIG_CLKDEV_LOOKUP=y
CONFIG_CLKEVT_RT3352=y
CONFIG_CLKSRC_MMIO=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
CONFIG_CMDLINE_BOOL=y
# CONFIG_CMDLINE_OVERRIDE is not set
CONFIG_CPU_GENERIC_DUMP_TLB=y
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_CPU_HAS_RIXI=y
CONFIG_CPU_HAS_SYNC=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32=y
# CONFIG_CPU_MIPS32_R1 is not set
CONFIG_CPU_MIPS32_R2=y
CONFIG_CPU_MIPSR2=y
CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
CONFIG_CPU_R4K_CACHE_TLB=y
CONFIG_CPU_R4K_FPU=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_CPU_SUPPORTS_MSA=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_WORKQUEUE=y
CONFIG_CSRC_R4K=y
CONFIG_DEBUG_PINCTRL=y
CONFIG_DMA_NONCOHERENT=y
# CONFIG_DMA_NOOP_OPS is not set
# CONFIG_DMA_VIRT_OPS is not set
# CONFIG_DRM_LIB_RANDOM is not set
# CONFIG_DTB_MT7620A_EVAL is not set
# CONFIG_DTB_OMEGA2P is not set
CONFIG_DTB_RT_NONE=y
# CONFIG_DTB_VOCORE2 is not set
CONFIG_DTC=y
CONFIG_EARLY_PRINTK=y
CONFIG_EXPORTFS=y
CONFIG_FIXED_PHY=y
CONFIG_FUTEX_PI=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_GENERIC_CPU_AUTOPROBE=y
CONFIG_GENERIC_IO=y
CONFIG_GENERIC_IRQ_CHIP=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_PHY=y
CONFIG_GENERIC_SCHED_CLOCK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GPIOLIB=y
# CONFIG_GPIO_MT7621 is not set
CONFIG_GPIO_RALINK=y
CONFIG_GPIO_SYSFS=y
# CONFIG_GRO_CELLS is not set
CONFIG_HANDLE_DOMAIN_IRQ=y
CONFIG_HARDWARE_WATCHPOINTS=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
# CONFIG_HAVE_ARCH_BITREVERSE is not set
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
CONFIG_HAVE_CBPF_JIT=y
CONFIG_HAVE_CC_STACKPROTECTOR=y
CONFIG_HAVE_CLK=y
CONFIG_HAVE_CONTEXT_TRACKING=y
CONFIG_HAVE_COPY_THREAD_TLS=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DEBUG_KMEMLEAK=y
CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_DMA_CONTIGUOUS=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_HAVE_IDE=y
CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
CONFIG_HAVE_KVM=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
CONFIG_HAVE_MEMBLOCK=y
CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
CONFIG_HAVE_NET_DSA=y
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
CONFIG_HW_HAS_PCI=y
CONFIG_HZ_PERIODIC=y
CONFIG_ICPLUS_PHY=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_INTC=y
CONFIG_IRQ_MIPS_CPU=y
CONFIG_IRQ_WORK=y
CONFIG_LIBFDT=y
CONFIG_MDIO_BUS=y
CONFIG_MDIO_DEVICE=y
CONFIG_MFD_SYSCON=y
CONFIG_MIPS=y
CONFIG_MIPS_ASID_BITS=8
CONFIG_MIPS_ASID_SHIFT=0
CONFIG_MIPS_CLOCK_VSYSCALL=y
# CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND is not set
# CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set
# CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set
CONFIG_MIPS_CMDLINE_FROM_DTB=y
# CONFIG_MIPS_ELF_APPENDED_DTB is not set
# CONFIG_MIPS_HUGE_TLB_SUPPORT is not set
CONFIG_MIPS_L1_CACHE_SHIFT=5
# CONFIG_MIPS_MACHINE is not set
CONFIG_MIPS_NO_APPENDED_DTB=y
# CONFIG_MIPS_RAW_APPENDED_DTB is not set
CONFIG_MIPS_SPRAM=y
CONFIG_MODULES_USE_ELF_REL=y
# CONFIG_MT7621_WDT is not set
# CONFIG_MTD_CFI_INTELEXT is not set
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_M25P80=y
CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y
CONFIG_MTD_SPI_NOR_USE_4K_SECTORS_LIMIT=16384
CONFIG_MTD_SPLIT_FIRMWARE=y
CONFIG_MTD_SPLIT_SEAMA_FW=y
CONFIG_MTD_SPLIT_TPLINK_FW=y
CONFIG_MTD_SPLIT_UIMAGE_FW=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_PER_CPU_KM=y
CONFIG_NET_MEDIATEK_GSW_MT7620=y
CONFIG_NET_MEDIATEK_MDIO=y
CONFIG_NET_MEDIATEK_MDIO_MT7620=y
CONFIG_NET_MEDIATEK_MT7620=y
# CONFIG_NET_MEDIATEK_RT3050 is not set
CONFIG_NET_MEDIATEK_SOC=y
CONFIG_NET_VENDOR_MEDIATEK=y
CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
# CONFIG_NO_IOPORT_MAP is not set
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_ADDRESS_PCI=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
CONFIG_OF_IRQ=y
CONFIG_OF_MDIO=y
CONFIG_OF_NET=y
CONFIG_OF_PCI=y
CONFIG_OF_PCI_IRQ=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_DRIVERS_LEGACY=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PGTABLE_LEVELS=2
CONFIG_PHYLIB=y
CONFIG_PHY_RALINK_USB=y
CONFIG_PINCTRL=y
CONFIG_PINCTRL_RT2880=y
# CONFIG_PINCTRL_SINGLE is not set
CONFIG_RALINK=y
CONFIG_RALINK_WDT=y
# CONFIG_RCU_NEED_SEGCBLIST is not set
# CONFIG_RCU_STALL_COMMON is not set
CONFIG_REGMAP=y
CONFIG_REGMAP_MMIO=y
CONFIG_RESET_CONTROLLER=y
# CONFIG_SCHED_INFO is not set
# CONFIG_SCSI_DMA is not set
# CONFIG_SERIAL_8250_FSL is not set
CONFIG_SERIAL_8250_RT288X=y
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SOC_MT7620=y
# CONFIG_SOC_MT7621 is not set
# CONFIG_SOC_RT288X is not set
# CONFIG_SOC_RT305X is not set
# CONFIG_SOC_RT3883 is not set
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
# CONFIG_SPI_MT7621 is not set
CONFIG_SPI_RT2880=y
CONFIG_SRCU=y
CONFIG_SWCONFIG=y
CONFIG_SWCONFIG_LEDS=y
CONFIG_SWPHY=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
CONFIG_SYS_HAS_CPU_MIPS32_R2=y
CONFIG_SYS_HAS_EARLY_PRINTK=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
CONFIG_SYS_SUPPORTS_MIPS16=y
CONFIG_THIN_ARCHIVES=y
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TIMER_OF=y
CONFIG_TIMER_PROBE=y
CONFIG_TINY_SRCU=y
CONFIG_USB_SUPPORT=y
CONFIG_USE_OF=y
CONFIG_WATCHDOG_CORE=y

View file

@ -0,0 +1,286 @@
CONFIG_ARCH_BINFMT_ELF_STATE=y
CONFIG_ARCH_CLOCKSOURCE_DATA=y
CONFIG_ARCH_DISCARD_MEMBLOCK=y
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
# CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set
CONFIG_ARCH_HAS_RESET_CONTROLLER=y
# CONFIG_ARCH_HAS_SG_CHAIN is not set
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
CONFIG_ARCH_SUPPORTS_UPROBES=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARCH_USE_BUILTIN_BSWAP=y
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
CONFIG_BLK_MQ_PCI=y
CONFIG_BOARD_SCACHE=y
CONFIG_BOUNCE=y
CONFIG_CEVT_R4K=y
# CONFIG_CEVT_SYSTICK_QUIRK is not set
CONFIG_CLKDEV_LOOKUP=y
CONFIG_CLKSRC_MIPS_GIC=y
CONFIG_CLKSRC_OF=y
CONFIG_CLKSRC_PROBE=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
CONFIG_CMDLINE_BOOL=y
# CONFIG_CMDLINE_OVERRIDE is not set
CONFIG_COMMON_CLK=y
# CONFIG_COMMON_CLK_BOSTON is not set
CONFIG_CPU_GENERIC_DUMP_TLB=y
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_CPU_HAS_RIXI=y
CONFIG_CPU_HAS_SYNC=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32=y
# CONFIG_CPU_MIPS32_R1 is not set
CONFIG_CPU_MIPS32_R2=y
CONFIG_CPU_MIPSR2=y
CONFIG_CPU_MIPSR2_IRQ_EI=y
CONFIG_CPU_MIPSR2_IRQ_VI=y
CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
CONFIG_CPU_R4K_CACHE_TLB=y
CONFIG_CPU_R4K_FPU=y
CONFIG_CPU_RMAP=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_CPU_SUPPORTS_MSA=y
CONFIG_CRC16=y
CONFIG_CRYPTO_AEAD=y
CONFIG_CRYPTO_AEAD2=y
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_HASH2=y
CONFIG_CRYPTO_LZO=y
CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_MANAGER2=y
CONFIG_CRYPTO_NULL2=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_WORKQUEUE=y
CONFIG_CSRC_R4K=y
CONFIG_DEBUG_PINCTRL=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_DTB_RT_NONE=y
CONFIG_DTC=y
CONFIG_EARLY_PRINTK=y
CONFIG_FIXED_PHY=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_GENERIC_IO=y
CONFIG_GENERIC_IRQ_CHIP=y
CONFIG_GENERIC_IRQ_IPI=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_SCHED_CLOCK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_MT7621=y
# CONFIG_GPIO_RALINK is not set
CONFIG_GPIO_SYSFS=y
CONFIG_HANDLE_DOMAIN_IRQ=y
CONFIG_HARDWARE_WATCHPOINTS=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
# CONFIG_HAVE_ARCH_BITREVERSE is not set
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
CONFIG_HAVE_CBPF_JIT=y
CONFIG_HAVE_CC_STACKPROTECTOR=y
CONFIG_HAVE_CLK=y
CONFIG_HAVE_CLK_PREPARE=y
CONFIG_HAVE_CONTEXT_TRACKING=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DEBUG_KMEMLEAK=y
CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_DMA_CONTIGUOUS=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_HAVE_IDE=y
CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
CONFIG_HAVE_KVM=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
CONFIG_HAVE_MEMBLOCK=y
CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
CONFIG_HAVE_NET_DSA=y
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
CONFIG_HIGHMEM=y
CONFIG_HW_HAS_PCI=y
CONFIG_HZ_PERIODIC=y
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
CONFIG_I2C_MT7621=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_DOMAIN_HIERARCHY=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_MIPS_CPU=y
CONFIG_IRQ_WORK=y
CONFIG_LIBFDT=y
CONFIG_LZO_COMPRESS=y
CONFIG_LZO_DECOMPRESS=y
CONFIG_MDIO_BOARDINFO=y
CONFIG_MIPS=y
CONFIG_MIPS_ASID_BITS=8
CONFIG_MIPS_ASID_SHIFT=0
CONFIG_MIPS_CLOCK_VSYSCALL=y
CONFIG_MIPS_CM=y
# CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND is not set
# CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set
# CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set
CONFIG_MIPS_CMDLINE_FROM_DTB=y
CONFIG_MIPS_CPC=y
CONFIG_MIPS_CPS=y
# CONFIG_MIPS_CPS_NS16550 is not set
CONFIG_MIPS_CPU_SCACHE=y
# CONFIG_MIPS_ELF_APPENDED_DTB is not set
CONFIG_MIPS_GIC=y
# CONFIG_MIPS_HUGE_TLB_SUPPORT is not set
CONFIG_MIPS_L1_CACHE_SHIFT=5
# CONFIG_MIPS_MACHINE is not set
CONFIG_MIPS_MT=y
CONFIG_MIPS_MT_FPAFF=y
CONFIG_MIPS_MT_SMP=y
CONFIG_MIPS_NO_APPENDED_DTB=y
CONFIG_MIPS_PERF_SHARED_TC_COUNTERS=y
# CONFIG_MIPS_RAW_APPENDED_DTB is not set
CONFIG_MIPS_SPRAM=y
# CONFIG_MIPS_VPE_LOADER is not set
CONFIG_MODULES_USE_ELF_REL=y
CONFIG_MT7621_WDT=y
# CONFIG_MTD_CFI_INTELEXT is not set
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_M25P80=y
CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_ECC=y
CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPLIT_FIRMWARE=y
CONFIG_MTD_SPLIT_SEAMA_FW=y
CONFIG_MTD_SPLIT_TPLINK_FW=y
CONFIG_MTD_SPLIT_TRX_FW=y
CONFIG_MTD_SPLIT_UIMAGE_FW=y
CONFIG_MTD_UBI=y
CONFIG_MTD_UBI_BEB_LIMIT=20
CONFIG_MTD_UBI_BLOCK=y
# CONFIG_MTD_UBI_FASTMAP is not set
# CONFIG_MTD_UBI_GLUEBI is not set
CONFIG_MTD_UBI_WL_THRESHOLD=4096
CONFIG_MTK_MTD_NAND=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NET_FLOW_LIMIT=y
CONFIG_NET_MEDIATEK_GSW_MT7621=y
CONFIG_NET_MEDIATEK_MDIO=y
CONFIG_NET_MEDIATEK_MDIO_MT7620=y
CONFIG_NET_MEDIATEK_MT7621=y
CONFIG_NET_MEDIATEK_SOC=y
CONFIG_NET_VENDOR_MEDIATEK=y
CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
# CONFIG_NO_IOPORT_MAP is not set
CONFIG_NR_CPUS=4
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_ADDRESS_PCI=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
CONFIG_OF_IRQ=y
CONFIG_OF_MDIO=y
CONFIG_OF_NET=y
CONFIG_OF_PCI=y
CONFIG_OF_PCI_IRQ=y
CONFIG_PADATA=y
CONFIG_PCI=y
CONFIG_PCI_DISABLE_COMMON_QUIRKS=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_DRIVERS_LEGACY=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PGTABLE_LEVELS=2
CONFIG_PHYLIB=y
# CONFIG_PHY_RALINK_USB is not set
CONFIG_PINCTRL=y
CONFIG_PINCTRL_RT2880=y
# CONFIG_PINCTRL_SINGLE is not set
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_GPIO=y
CONFIG_POWER_SUPPLY=y
CONFIG_RALINK=y
# CONFIG_RALINK_WDT is not set
CONFIG_RATIONAL=y
CONFIG_RCU_STALL_COMMON=y
CONFIG_REGMAP=y
CONFIG_REGMAP_I2C=y
CONFIG_REGMAP_SPI=y
CONFIG_RESET_CONTROLLER=y
CONFIG_RFS_ACCEL=y
CONFIG_RPS=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_PCF8563=y
CONFIG_RTC_I2C_AND_SPI=y
CONFIG_RTC_MC146818_LIB=y
# CONFIG_SCHED_INFO is not set
CONFIG_SCHED_SMT=y
# CONFIG_SCSI_DMA is not set
# CONFIG_SERIAL_8250_FSL is not set
CONFIG_SERIAL_8250_NR_UARTS=3
CONFIG_SERIAL_8250_RUNTIME_UARTS=3
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SMP=y
CONFIG_SMP_UP=y
# CONFIG_SOC_MT7620 is not set
CONFIG_SOC_MT7621=y
# CONFIG_SOC_RT288X is not set
# CONFIG_SOC_RT305X is not set
# CONFIG_SOC_RT3883 is not set
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_MT7621=y
# CONFIG_SPI_RT2880 is not set
CONFIG_SRCU=y
CONFIG_SWCONFIG_LEDS=y
CONFIG_SWCONFIG=y
CONFIG_SWPHY=y
CONFIG_SYNC_R4K=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
CONFIG_SYS_HAS_CPU_MIPS32_R2=y
CONFIG_SYS_HAS_EARLY_PRINTK=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_SYS_SUPPORTS_HIGHMEM=y
CONFIG_SYS_SUPPORTS_HOTPLUG_CPU=y
CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
CONFIG_SYS_SUPPORTS_MIPS16=y
CONFIG_SYS_SUPPORTS_MIPS_CPS=y
CONFIG_SYS_SUPPORTS_MULTITHREADING=y
CONFIG_SYS_SUPPORTS_SCHED_SMT=y
CONFIG_SYS_SUPPORTS_SMP=y
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TREE_RCU=y
CONFIG_UBIFS_FS=y
CONFIG_UBIFS_FS_ADVANCED_COMPR=y
CONFIG_UBIFS_FS_LZO=y
CONFIG_UBIFS_FS_ZLIB=y
CONFIG_USB_SUPPORT=y
CONFIG_USE_OF=y
CONFIG_WATCHDOG_CORE=y
CONFIG_WEAK_ORDERING=y
CONFIG_XPS=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_ZLIB_INFLATE=y

View file

@ -0,0 +1,237 @@
CONFIG_ARCH_BINFMT_ELF_STATE=y
CONFIG_ARCH_CLOCKSOURCE_DATA=y
CONFIG_ARCH_DISCARD_MEMBLOCK=y
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
# CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set
CONFIG_ARCH_HAS_RESET_CONTROLLER=y
# CONFIG_ARCH_HAS_SG_CHAIN is not set
# CONFIG_ARCH_HAS_STRICT_KERNEL_RWX is not set
# CONFIG_ARCH_HAS_STRICT_MODULE_RWX is not set
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
CONFIG_ARCH_MMAP_RND_BITS_MAX=15
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15
# CONFIG_ARCH_OPTIONAL_KERNEL_RWX is not set
# CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT is not set
CONFIG_ARCH_SUPPORTS_UPROBES=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARCH_USE_BUILTIN_BSWAP=y
CONFIG_ARCH_USE_QUEUED_RWLOCKS=y
CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y
# CONFIG_ARCH_WANTS_THP_SWAP is not set
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
CONFIG_AT803X_PHY=y
CONFIG_BLK_MQ_PCI=y
CONFIG_CEVT_R4K=y
CONFIG_CEVT_SYSTICK_QUIRK=y
CONFIG_CLKDEV_LOOKUP=y
CONFIG_CLKEVT_RT3352=y
CONFIG_CLKSRC_MMIO=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
CONFIG_CMDLINE_BOOL=y
# CONFIG_CMDLINE_OVERRIDE is not set
CONFIG_CPU_GENERIC_DUMP_TLB=y
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_CPU_HAS_RIXI=y
CONFIG_CPU_HAS_SYNC=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32=y
# CONFIG_CPU_MIPS32_R1 is not set
CONFIG_CPU_MIPS32_R2=y
CONFIG_CPU_MIPSR2=y
CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
CONFIG_CPU_R4K_CACHE_TLB=y
CONFIG_CPU_R4K_FPU=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_CPU_SUPPORTS_MSA=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_WORKQUEUE=y
CONFIG_CSRC_R4K=y
CONFIG_DEBUG_PINCTRL=y
CONFIG_DMA_NONCOHERENT=y
# CONFIG_DMA_NOOP_OPS is not set
# CONFIG_DMA_VIRT_OPS is not set
# CONFIG_DRM_LIB_RANDOM is not set
# CONFIG_DTB_MT7620A_EVAL is not set
# CONFIG_DTB_OMEGA2P is not set
CONFIG_DTB_RT_NONE=y
# CONFIG_DTB_VOCORE2 is not set
CONFIG_DTC=y
CONFIG_EARLY_PRINTK=y
CONFIG_EXPORTFS=y
CONFIG_FIXED_PHY=y
CONFIG_FUTEX_PI=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_GENERIC_CPU_AUTOPROBE=y
CONFIG_GENERIC_IO=y
CONFIG_GENERIC_IRQ_CHIP=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_PHY=y
CONFIG_GENERIC_SCHED_CLOCK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_MT7621=y
# CONFIG_GPIO_RALINK is not set
CONFIG_GPIO_SYSFS=y
# CONFIG_GRO_CELLS is not set
CONFIG_HANDLE_DOMAIN_IRQ=y
CONFIG_HARDWARE_WATCHPOINTS=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
# CONFIG_HAVE_ARCH_BITREVERSE is not set
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
CONFIG_HAVE_CBPF_JIT=y
CONFIG_HAVE_CC_STACKPROTECTOR=y
CONFIG_HAVE_CLK=y
CONFIG_HAVE_CONTEXT_TRACKING=y
CONFIG_HAVE_COPY_THREAD_TLS=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DEBUG_KMEMLEAK=y
CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_DMA_CONTIGUOUS=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_HAVE_IDE=y
CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
CONFIG_HAVE_KVM=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
CONFIG_HAVE_MEMBLOCK=y
CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
CONFIG_HAVE_NET_DSA=y
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
CONFIG_HW_HAS_PCI=y
CONFIG_HZ_PERIODIC=y
CONFIG_ICPLUS_PHY=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_INTC=y
CONFIG_IRQ_MIPS_CPU=y
CONFIG_IRQ_WORK=y
CONFIG_LIBFDT=y
CONFIG_MDIO_BUS=y
CONFIG_MDIO_DEVICE=y
CONFIG_MFD_SYSCON=y
CONFIG_MIPS=y
CONFIG_MIPS_ASID_BITS=8
CONFIG_MIPS_ASID_SHIFT=0
CONFIG_MIPS_CLOCK_VSYSCALL=y
# CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND is not set
# CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set
# CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set
CONFIG_MIPS_CMDLINE_FROM_DTB=y
# CONFIG_MIPS_ELF_APPENDED_DTB is not set
# CONFIG_MIPS_HUGE_TLB_SUPPORT is not set
CONFIG_MIPS_L1_CACHE_SHIFT=5
# CONFIG_MIPS_MACHINE is not set
CONFIG_MIPS_NO_APPENDED_DTB=y
# CONFIG_MIPS_RAW_APPENDED_DTB is not set
CONFIG_MIPS_SPRAM=y
CONFIG_MODULES_USE_ELF_REL=y
CONFIG_MT7621_WDT=y
# CONFIG_MTD_CFI_INTELEXT is not set
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_M25P80=y
CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPLIT_FIRMWARE=y
CONFIG_MTD_SPLIT_TPLINK_FW=y
CONFIG_MTD_SPLIT_TRX_FW=y
CONFIG_MTD_SPLIT_UIMAGE_FW=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_PER_CPU_KM=y
CONFIG_NET_MEDIATEK_ESW_RT3050=y
# CONFIG_NET_MEDIATEK_MT7620 is not set
CONFIG_NET_MEDIATEK_RT3050=y
CONFIG_NET_MEDIATEK_SOC=y
CONFIG_NET_VENDOR_MEDIATEK=y
CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
# CONFIG_NO_IOPORT_MAP is not set
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_ADDRESS_PCI=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
CONFIG_OF_IRQ=y
CONFIG_OF_MDIO=y
CONFIG_OF_NET=y
CONFIG_OF_PCI=y
CONFIG_OF_PCI_IRQ=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_DRIVERS_LEGACY=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PGTABLE_LEVELS=2
CONFIG_PHYLIB=y
CONFIG_PHY_RALINK_USB=y
CONFIG_PINCTRL=y
CONFIG_PINCTRL_RT2880=y
# CONFIG_PINCTRL_SINGLE is not set
CONFIG_RALINK=y
# CONFIG_RALINK_WDT is not set
# CONFIG_RCU_NEED_SEGCBLIST is not set
# CONFIG_RCU_STALL_COMMON is not set
CONFIG_REGMAP=y
CONFIG_REGMAP_MMIO=y
CONFIG_RESET_CONTROLLER=y
# CONFIG_SCHED_INFO is not set
# CONFIG_SCSI_DMA is not set
# CONFIG_SERIAL_8250_FSL is not set
CONFIG_SERIAL_8250_NR_UARTS=3
CONFIG_SERIAL_8250_RUNTIME_UARTS=3
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SOC_MT7620=y
# CONFIG_SOC_MT7621 is not set
# CONFIG_SOC_RT288X is not set
# CONFIG_SOC_RT305X is not set
# CONFIG_SOC_RT3883 is not set
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_MT7621=y
# CONFIG_SPI_RT2880 is not set
CONFIG_SRCU=y
CONFIG_SWCONFIG=y
CONFIG_SWCONFIG_LEDS=y
CONFIG_SWPHY=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
CONFIG_SYS_HAS_CPU_MIPS32_R2=y
CONFIG_SYS_HAS_EARLY_PRINTK=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
CONFIG_SYS_SUPPORTS_MIPS16=y
CONFIG_THIN_ARCHIVES=y
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TIMER_OF=y
CONFIG_TIMER_PROBE=y
CONFIG_TINY_SRCU=y
CONFIG_USB_SUPPORT=y
CONFIG_USE_OF=y
CONFIG_WATCHDOG_CORE=y

View file

@ -0,0 +1,861 @@
From fec11d4e8dc5cc79bcd7c8fd55038ac21ac39965 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 16 Mar 2014 05:22:39 +0000
Subject: [PATCH 04/53] MIPS: ralink: add MT7621 pcie driver
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/pci/Makefile | 1 +
arch/mips/pci/pci-mt7621.c | 813 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 814 insertions(+)
create mode 100644 arch/mips/pci/pci-mt7621.c
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_SNI_RM) += fixup-sni.o ops
obj-$(CONFIG_LANTIQ) += fixup-lantiq.o
obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o
obj-$(CONFIG_SOC_MT7620) += pci-mt7620.o
+obj-$(CONFIG_SOC_MT7621) += pci-mt7621.o
obj-$(CONFIG_SOC_RT288X) += pci-rt2880.o
obj-$(CONFIG_SOC_RT3883) += pci-rt3883.o
obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o
--- /dev/null
+++ b/arch/mips/pci/pci-mt7621.c
@@ -0,0 +1,836 @@
+/**************************************************************************
+ *
+ * BRIEF MODULE DESCRIPTION
+ * PCI init for Ralink RT2880 solution
+ *
+ * Copyright 2007 Ralink Inc. (bruce_chang@ralinktech.com.tw)
+ *
+ * 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; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ **************************************************************************
+ * May 2007 Bruce Chang
+ * Initial Release
+ *
+ * May 2009 Bruce Chang
+ * support RT2880/RT3883 PCIe
+ *
+ * May 2011 Bruce Chang
+ * support RT6855/MT7620 PCIe
+ *
+ **************************************************************************
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <asm/pci.h>
+#include <asm/io.h>
+#include <asm/mips-cm.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_pci.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+
+#include <ralink_regs.h>
+
+extern void pcie_phy_init(void);
+extern void chk_phy_pll(void);
+
+/*
+ * These functions and structures provide the BIOS scan and mapping of the PCI
+ * devices.
+ */
+
+#define CONFIG_PCIE_PORT0
+#define CONFIG_PCIE_PORT1
+#define CONFIG_PCIE_PORT2
+#define RALINK_PCIE0_CLK_EN (1<<24)
+#define RALINK_PCIE1_CLK_EN (1<<25)
+#define RALINK_PCIE2_CLK_EN (1<<26)
+
+#define RALINK_PCI_CONFIG_ADDR 0x20
+#define RALINK_PCI_CONFIG_DATA_VIRTUAL_REG 0x24
+#define RALINK_INT_PCIE0 pcie_irq[0]
+#define RALINK_INT_PCIE1 pcie_irq[1]
+#define RALINK_INT_PCIE2 pcie_irq[2]
+#define RALINK_PCI_MEMBASE *(volatile u32 *)(RALINK_PCI_BASE + 0x0028)
+#define RALINK_PCI_IOBASE *(volatile u32 *)(RALINK_PCI_BASE + 0x002C)
+#define RALINK_PCIE0_RST (1<<24)
+#define RALINK_PCIE1_RST (1<<25)
+#define RALINK_PCIE2_RST (1<<26)
+#define RALINK_SYSCTL_BASE 0xBE000000
+
+#define RALINK_PCI_PCICFG_ADDR *(volatile u32 *)(RALINK_PCI_BASE + 0x0000)
+#define RALINK_PCI_PCIMSK_ADDR *(volatile u32 *)(RALINK_PCI_BASE + 0x000C)
+#define RALINK_PCI_BASE 0xBE140000
+
+#define RALINK_PCIEPHY_P0P1_CTL_OFFSET (RALINK_PCI_BASE + 0x9000)
+#define RT6855_PCIE0_OFFSET 0x2000
+#define RT6855_PCIE1_OFFSET 0x3000
+#define RT6855_PCIE2_OFFSET 0x4000
+
+#define RALINK_PCI0_BAR0SETUP_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0010)
+#define RALINK_PCI0_IMBASEBAR0_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0018)
+#define RALINK_PCI0_ID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0030)
+#define RALINK_PCI0_CLASS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0034)
+#define RALINK_PCI0_SUBID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0038)
+#define RALINK_PCI0_STATUS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0050)
+#define RALINK_PCI0_DERR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0060)
+#define RALINK_PCI0_ECRC *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0064)
+
+#define RALINK_PCI1_BAR0SETUP_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0010)
+#define RALINK_PCI1_IMBASEBAR0_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0018)
+#define RALINK_PCI1_ID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0030)
+#define RALINK_PCI1_CLASS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0034)
+#define RALINK_PCI1_SUBID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0038)
+#define RALINK_PCI1_STATUS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0050)
+#define RALINK_PCI1_DERR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0060)
+#define RALINK_PCI1_ECRC *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0064)
+
+#define RALINK_PCI2_BAR0SETUP_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0010)
+#define RALINK_PCI2_IMBASEBAR0_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0018)
+#define RALINK_PCI2_ID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0030)
+#define RALINK_PCI2_CLASS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0034)
+#define RALINK_PCI2_SUBID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0038)
+#define RALINK_PCI2_STATUS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0050)
+#define RALINK_PCI2_DERR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0060)
+#define RALINK_PCI2_ECRC *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0064)
+
+#define RALINK_PCIEPHY_P0P1_CTL_OFFSET (RALINK_PCI_BASE + 0x9000)
+#define RALINK_PCIEPHY_P2_CTL_OFFSET (RALINK_PCI_BASE + 0xA000)
+
+
+#define MV_WRITE(ofs, data) \
+ *(volatile u32 *)(RALINK_PCI_BASE+(ofs)) = cpu_to_le32(data)
+#define MV_READ(ofs, data) \
+ *(data) = le32_to_cpu(*(volatile u32 *)(RALINK_PCI_BASE+(ofs)))
+#define MV_READ_DATA(ofs) \
+ le32_to_cpu(*(volatile u32 *)(RALINK_PCI_BASE+(ofs)))
+
+#define MV_WRITE_16(ofs, data) \
+ *(volatile u16 *)(RALINK_PCI_BASE+(ofs)) = cpu_to_le16(data)
+#define MV_READ_16(ofs, data) \
+ *(data) = le16_to_cpu(*(volatile u16 *)(RALINK_PCI_BASE+(ofs)))
+
+#define MV_WRITE_8(ofs, data) \
+ *(volatile u8 *)(RALINK_PCI_BASE+(ofs)) = data
+#define MV_READ_8(ofs, data) \
+ *(data) = *(volatile u8 *)(RALINK_PCI_BASE+(ofs))
+
+
+
+#define RALINK_PCI_MM_MAP_BASE 0x60000000
+#define RALINK_PCI_IO_MAP_BASE 0x1e160000
+
+#define RALINK_SYSTEM_CONTROL_BASE 0xbe000000
+#define GPIO_PERST
+#define ASSERT_SYSRST_PCIE(val) do { \
+ if (*(unsigned int *)(0xbe00000c) == 0x00030101) \
+ RALINK_RSTCTRL |= val; \
+ else \
+ RALINK_RSTCTRL &= ~val; \
+ } while(0)
+#define DEASSERT_SYSRST_PCIE(val) do { \
+ if (*(unsigned int *)(0xbe00000c) == 0x00030101) \
+ RALINK_RSTCTRL &= ~val; \
+ else \
+ RALINK_RSTCTRL |= val; \
+ } while(0)
+#define RALINK_SYSCFG1 *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x14)
+#define RALINK_CLKCFG1 *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x30)
+#define RALINK_RSTCTRL *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x34)
+#define RALINK_GPIOMODE *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x60)
+#define RALINK_PCIE_CLK_GEN *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x7c)
+#define RALINK_PCIE_CLK_GEN1 *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x80)
+#define PPLL_CFG1 *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x9c)
+#define PPLL_DRV *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0xa0)
+//RALINK_SYSCFG1 bit
+#define RALINK_PCI_HOST_MODE_EN (1<<7)
+#define RALINK_PCIE_RC_MODE_EN (1<<8)
+//RALINK_RSTCTRL bit
+#define RALINK_PCIE_RST (1<<23)
+#define RALINK_PCI_RST (1<<24)
+//RALINK_CLKCFG1 bit
+#define RALINK_PCI_CLK_EN (1<<19)
+#define RALINK_PCIE_CLK_EN (1<<21)
+//RALINK_GPIOMODE bit
+#define PCI_SLOTx2 (1<<11)
+#define PCI_SLOTx1 (2<<11)
+//MTK PCIE PLL bit
+#define PDRV_SW_SET (1<<31)
+#define LC_CKDRVPD_ (1<<19)
+
+#define MEMORY_BASE 0x0
+static int pcie_link_status = 0;
+
+#define PCI_ACCESS_READ_1 0
+#define PCI_ACCESS_READ_2 1
+#define PCI_ACCESS_READ_4 2
+#define PCI_ACCESS_WRITE_1 3
+#define PCI_ACCESS_WRITE_2 4
+#define PCI_ACCESS_WRITE_4 5
+
+static int pcie_irq[3];
+
+static int config_access(unsigned char access_type, struct pci_bus *bus,
+ unsigned int devfn, unsigned int where, u32 * data)
+{
+ unsigned int slot = PCI_SLOT(devfn);
+ u8 func = PCI_FUNC(devfn);
+ uint32_t address_reg, data_reg;
+ unsigned int address;
+
+ address_reg = RALINK_PCI_CONFIG_ADDR;
+ data_reg = RALINK_PCI_CONFIG_DATA_VIRTUAL_REG;
+
+ address = (((where&0xF00)>>8)<<24) |(bus->number << 16) | (slot << 11) | (func << 8) | (where & 0xfc) | 0x80000000;
+ MV_WRITE(address_reg, address);
+
+ switch(access_type) {
+ case PCI_ACCESS_WRITE_1:
+ MV_WRITE_8(data_reg+(where&0x3), *data);
+ break;
+ case PCI_ACCESS_WRITE_2:
+ MV_WRITE_16(data_reg+(where&0x3), *data);
+ break;
+ case PCI_ACCESS_WRITE_4:
+ MV_WRITE(data_reg, *data);
+ break;
+ case PCI_ACCESS_READ_1:
+ MV_READ_8( data_reg+(where&0x3), data);
+ break;
+ case PCI_ACCESS_READ_2:
+ MV_READ_16(data_reg+(where&0x3), data);
+ break;
+ case PCI_ACCESS_READ_4:
+ MV_READ(data_reg, data);
+ break;
+ default:
+ printk("no specify access type\n");
+ break;
+ }
+ return 0;
+}
+
+static int
+read_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 * val)
+{
+ return config_access(PCI_ACCESS_READ_1, bus, devfn, (unsigned int)where, (u32 *)val);
+}
+
+static int
+read_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 * val)
+{
+ return config_access(PCI_ACCESS_READ_2, bus, devfn, (unsigned int)where, (u32 *)val);
+}
+
+static int
+read_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 * val)
+{
+ return config_access(PCI_ACCESS_READ_4, bus, devfn, (unsigned int)where, (u32 *)val);
+}
+
+static int
+write_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 val)
+{
+ if (config_access(PCI_ACCESS_WRITE_1, bus, devfn, (unsigned int)where, (u32 *)&val))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+write_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 val)
+{
+ if (config_access(PCI_ACCESS_WRITE_2, bus, devfn, where, (u32 *)&val))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+write_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 val)
+{
+ if (config_access(PCI_ACCESS_WRITE_4, bus, devfn, where, &val))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int
+pci_config_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * val)
+{
+ switch (size) {
+ case 1:
+ return read_config_byte(bus, devfn, where, (u8 *) val);
+ case 2:
+ return read_config_word(bus, devfn, where, (u16 *) val);
+ default:
+ return read_config_dword(bus, devfn, where, val);
+ }
+}
+
+static int
+pci_config_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val)
+{
+ switch (size) {
+ case 1:
+ return write_config_byte(bus, devfn, where, (u8) val);
+ case 2:
+ return write_config_word(bus, devfn, where, (u16) val);
+ default:
+ return write_config_dword(bus, devfn, where, val);
+ }
+}
+
+struct pci_ops mt7621_pci_ops= {
+ .read = pci_config_read,
+ .write = pci_config_write,
+};
+
+static struct resource mt7621_res_pci_mem1 = {
+ .name = "PCI MEM1",
+ .start = RALINK_PCI_MM_MAP_BASE,
+ .end = (u32)((RALINK_PCI_MM_MAP_BASE + (unsigned char *)0x0fffffff)),
+ .flags = IORESOURCE_MEM,
+};
+static struct resource mt7621_res_pci_io1 = {
+ .name = "PCI I/O1",
+ .start = RALINK_PCI_IO_MAP_BASE,
+ .end = (u32)((RALINK_PCI_IO_MAP_BASE + (unsigned char *)0x0ffff)),
+ .flags = IORESOURCE_IO,
+};
+
+static struct pci_controller mt7621_controller = {
+ .pci_ops = &mt7621_pci_ops,
+ .mem_resource = &mt7621_res_pci_mem1,
+ .io_resource = &mt7621_res_pci_io1,
+ .mem_offset = 0x00000000UL,
+ .io_offset = 0x00000000UL,
+ .io_map_base = 0xa0000000,
+};
+
+static void
+read_config(unsigned long bus, unsigned long dev, unsigned long func, unsigned long reg, unsigned long *val)
+{
+ unsigned int address_reg, data_reg, address;
+
+ address_reg = RALINK_PCI_CONFIG_ADDR;
+ data_reg = RALINK_PCI_CONFIG_DATA_VIRTUAL_REG;
+ address = (((reg & 0xF00)>>8)<<24) | (bus << 16) | (dev << 11) | (func << 8) | (reg & 0xfc) | 0x80000000 ;
+ MV_WRITE(address_reg, address);
+ MV_READ(data_reg, val);
+ return;
+}
+
+static void
+write_config(unsigned long bus, unsigned long dev, unsigned long func, unsigned long reg, unsigned long val)
+{
+ unsigned int address_reg, data_reg, address;
+
+ address_reg = RALINK_PCI_CONFIG_ADDR;
+ data_reg = RALINK_PCI_CONFIG_DATA_VIRTUAL_REG;
+ address = (((reg & 0xF00)>>8)<<24) | (bus << 16) | (dev << 11) | (func << 8) | (reg & 0xfc) | 0x80000000 ;
+ MV_WRITE(address_reg, address);
+ MV_WRITE(data_reg, val);
+ return;
+}
+
+
+int __init
+pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ u16 cmd;
+ u32 val;
+ int irq = 0;
+
+ if ((dev->bus->number == 0) && (slot == 0)) {
+ write_config(0, 0, 0, PCI_BASE_ADDRESS_0, MEMORY_BASE);
+ read_config(0, 0, 0, PCI_BASE_ADDRESS_0, (unsigned long *)&val);
+ printk("BAR0 at slot 0 = %x\n", val);
+ printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot);
+ } else if((dev->bus->number == 0) && (slot == 0x1)) {
+ write_config(0, 1, 0, PCI_BASE_ADDRESS_0, MEMORY_BASE);
+ read_config(0, 1, 0, PCI_BASE_ADDRESS_0, (unsigned long *)&val);
+ printk("BAR0 at slot 1 = %x\n", val);
+ printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot);
+ } else if((dev->bus->number == 0) && (slot == 0x2)) {
+ write_config(0, 2, 0, PCI_BASE_ADDRESS_0, MEMORY_BASE);
+ read_config(0, 2, 0, PCI_BASE_ADDRESS_0, (unsigned long *)&val);
+ printk("BAR0 at slot 2 = %x\n", val);
+ printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot);
+ } else if ((dev->bus->number == 1) && (slot == 0x0)) {
+ switch (pcie_link_status) {
+ case 2:
+ case 6:
+ irq = RALINK_INT_PCIE1;
+ break;
+ case 4:
+ irq = RALINK_INT_PCIE2;
+ break;
+ default:
+ irq = RALINK_INT_PCIE0;
+ }
+ printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq);
+ } else if ((dev->bus->number == 2) && (slot == 0x0)) {
+ switch (pcie_link_status) {
+ case 5:
+ case 6:
+ irq = RALINK_INT_PCIE2;
+ break;
+ default:
+ irq = RALINK_INT_PCIE1;
+ }
+ printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq);
+ } else if ((dev->bus->number == 2) && (slot == 0x1)) {
+ switch (pcie_link_status) {
+ case 5:
+ case 6:
+ irq = RALINK_INT_PCIE2;
+ break;
+ default:
+ irq = RALINK_INT_PCIE1;
+ }
+ printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq);
+ } else if ((dev->bus->number ==3) && (slot == 0x0)) {
+ irq = RALINK_INT_PCIE2;
+ printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq);
+ } else if ((dev->bus->number ==3) && (slot == 0x1)) {
+ irq = RALINK_INT_PCIE2;
+ printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq);
+ } else if ((dev->bus->number ==3) && (slot == 0x2)) {
+ irq = RALINK_INT_PCIE2;
+ printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq);
+ } else {
+ printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot);
+ return 0;
+ }
+
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x14); //configure cache line size 0x14
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xFF); //configure latency timer 0x10
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ cmd = cmd | PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+ return irq;
+}
+
+void
+set_pcie_phy(u32 *addr, int start_b, int bits, int val)
+{
+// printk("0x%p:", addr);
+// printk(" %x", *addr);
+ *(unsigned int *)(addr) &= ~(((1<<bits) - 1)<<start_b);
+ *(unsigned int *)(addr) |= val << start_b;
+// printk(" -> %x\n", *addr);
+}
+
+void
+bypass_pipe_rst(void)
+{
+#if defined (CONFIG_PCIE_PORT0)
+ /* PCIe Port 0 */
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x02c), 12, 1, 0x01); // rg_pe1_pipe_rst_b
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x02c), 4, 1, 0x01); // rg_pe1_pipe_cmd_frc[4]
+#endif
+#if defined (CONFIG_PCIE_PORT1)
+ /* PCIe Port 1 */
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x12c), 12, 1, 0x01); // rg_pe1_pipe_rst_b
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x12c), 4, 1, 0x01); // rg_pe1_pipe_cmd_frc[4]
+#endif
+#if defined (CONFIG_PCIE_PORT2)
+ /* PCIe Port 2 */
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x02c), 12, 1, 0x01); // rg_pe1_pipe_rst_b
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x02c), 4, 1, 0x01); // rg_pe1_pipe_cmd_frc[4]
+#endif
+}
+
+void
+set_phy_for_ssc(void)
+{
+ unsigned long reg = (*(volatile u32 *)(RALINK_SYSCTL_BASE + 0x10));
+
+ reg = (reg >> 6) & 0x7;
+#if defined (CONFIG_PCIE_PORT0) || defined (CONFIG_PCIE_PORT1)
+ /* Set PCIe Port0 & Port1 PHY to disable SSC */
+ /* Debug Xtal Type */
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x400), 8, 1, 0x01); // rg_pe1_frc_h_xtal_type
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x400), 9, 2, 0x00); // rg_pe1_h_xtal_type
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000), 4, 1, 0x01); // rg_pe1_frc_phy_en //Force Port 0 enable control
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100), 4, 1, 0x01); // rg_pe1_frc_phy_en //Force Port 1 enable control
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000), 5, 1, 0x00); // rg_pe1_phy_en //Port 0 disable
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100), 5, 1, 0x00); // rg_pe1_phy_en //Port 1 disable
+ if(reg <= 5 && reg >= 3) { // 40MHz Xtal
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 6, 2, 0x01); // RG_PE1_H_PLL_PREDIV //Pre-divider ratio (for host mode)
+ printk("***** Xtal 40MHz *****\n");
+ } else { // 25MHz | 20MHz Xtal
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 6, 2, 0x00); // RG_PE1_H_PLL_PREDIV //Pre-divider ratio (for host mode)
+ if (reg >= 6) {
+ printk("***** Xtal 25MHz *****\n");
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4bc), 4, 2, 0x01); // RG_PE1_H_PLL_FBKSEL //Feedback clock select
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x49c), 0,31, 0x18000000); // RG_PE1_H_LCDDS_PCW_NCPO //DDS NCPO PCW (for host mode)
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a4), 0,16, 0x18d); // RG_PE1_H_LCDDS_SSC_PRD //DDS SSC dither period control
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a8), 0,12, 0x4a); // RG_PE1_H_LCDDS_SSC_DELTA //DDS SSC dither amplitude control
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a8), 16,12, 0x4a); // RG_PE1_H_LCDDS_SSC_DELTA1 //DDS SSC dither amplitude control for initial
+ } else {
+ printk("***** Xtal 20MHz *****\n");
+ }
+ }
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a0), 5, 1, 0x01); // RG_PE1_LCDDS_CLK_PH_INV //DDS clock inversion
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 22, 2, 0x02); // RG_PE1_H_PLL_BC
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 18, 4, 0x06); // RG_PE1_H_PLL_BP
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 12, 4, 0x02); // RG_PE1_H_PLL_IR
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 8, 4, 0x01); // RG_PE1_H_PLL_IC
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4ac), 16, 3, 0x00); // RG_PE1_H_PLL_BR
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 1, 3, 0x02); // RG_PE1_PLL_DIVEN
+ if(reg <= 5 && reg >= 3) { // 40MHz Xtal
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x414), 6, 2, 0x01); // rg_pe1_mstckdiv //value of da_pe1_mstckdiv when force mode enable
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x414), 5, 1, 0x01); // rg_pe1_frc_mstckdiv //force mode enable of da_pe1_mstckdiv
+ }
+ /* Enable PHY and disable force mode */
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000), 5, 1, 0x01); // rg_pe1_phy_en //Port 0 enable
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100), 5, 1, 0x01); // rg_pe1_phy_en //Port 1 enable
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000), 4, 1, 0x00); // rg_pe1_frc_phy_en //Force Port 0 disable control
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100), 4, 1, 0x00); // rg_pe1_frc_phy_en //Force Port 1 disable control
+#endif
+#if defined (CONFIG_PCIE_PORT2)
+ /* Set PCIe Port2 PHY to disable SSC */
+ /* Debug Xtal Type */
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x400), 8, 1, 0x01); // rg_pe1_frc_h_xtal_type
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x400), 9, 2, 0x00); // rg_pe1_h_xtal_type
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000), 4, 1, 0x01); // rg_pe1_frc_phy_en //Force Port 0 enable control
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000), 5, 1, 0x00); // rg_pe1_phy_en //Port 0 disable
+ if(reg <= 5 && reg >= 3) { // 40MHz Xtal
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 6, 2, 0x01); // RG_PE1_H_PLL_PREDIV //Pre-divider ratio (for host mode)
+ } else { // 25MHz | 20MHz Xtal
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 6, 2, 0x00); // RG_PE1_H_PLL_PREDIV //Pre-divider ratio (for host mode)
+ if (reg >= 6) { // 25MHz Xtal
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4bc), 4, 2, 0x01); // RG_PE1_H_PLL_FBKSEL //Feedback clock select
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x49c), 0,31, 0x18000000); // RG_PE1_H_LCDDS_PCW_NCPO //DDS NCPO PCW (for host mode)
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a4), 0,16, 0x18d); // RG_PE1_H_LCDDS_SSC_PRD //DDS SSC dither period control
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a8), 0,12, 0x4a); // RG_PE1_H_LCDDS_SSC_DELTA //DDS SSC dither amplitude control
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a8), 16,12, 0x4a); // RG_PE1_H_LCDDS_SSC_DELTA1 //DDS SSC dither amplitude control for initial
+ }
+ }
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a0), 5, 1, 0x01); // RG_PE1_LCDDS_CLK_PH_INV //DDS clock inversion
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 22, 2, 0x02); // RG_PE1_H_PLL_BC
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 18, 4, 0x06); // RG_PE1_H_PLL_BP
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 12, 4, 0x02); // RG_PE1_H_PLL_IR
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 8, 4, 0x01); // RG_PE1_H_PLL_IC
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4ac), 16, 3, 0x00); // RG_PE1_H_PLL_BR
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 1, 3, 0x02); // RG_PE1_PLL_DIVEN
+ if(reg <= 5 && reg >= 3) { // 40MHz Xtal
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x414), 6, 2, 0x01); // rg_pe1_mstckdiv //value of da_pe1_mstckdiv when force mode enable
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x414), 5, 1, 0x01); // rg_pe1_frc_mstckdiv //force mode enable of da_pe1_mstckdiv
+ }
+ /* Enable PHY and disable force mode */
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000), 5, 1, 0x01); // rg_pe1_phy_en //Port 0 enable
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000), 4, 1, 0x00); // rg_pe1_frc_phy_en //Force Port 0 disable control
+#endif
+}
+
+void setup_cm_memory_region(struct resource *mem_resource)
+{
+ resource_size_t mask;
+ if (mips_cps_numiocu(0)) {
+ /* FIXME: hardware doesn't accept mask values with 1s after
+ 0s (e.g. 0xffef), so it would be great to warn if that's
+ about to happen */
+ mask = ~(mem_resource->end - mem_resource->start);
+
+ write_gcr_reg1_base(mem_resource->start);
+ write_gcr_reg1_mask(mask | CM_GCR_REGn_MASK_CMTGT_IOCU0);
+ printk("PCI coherence region base: 0x%08lx, mask/settings: 0x%08lx\n",
+ read_gcr_reg1_base(),
+ read_gcr_reg1_mask());
+ }
+}
+
+static int mt7621_pci_probe(struct platform_device *pdev)
+{
+ unsigned long val = 0;
+ int i;
+
+ for (i = 0; i < 3; i++)
+ pcie_irq[i] = irq_of_parse_and_map(pdev->dev.of_node, i);
+
+ iomem_resource.start = 0;
+ iomem_resource.end= ~0;
+ ioport_resource.start= 0;
+ ioport_resource.end = ~0;
+
+#if defined (CONFIG_PCIE_PORT0)
+ val = RALINK_PCIE0_RST;
+#endif
+#if defined (CONFIG_PCIE_PORT1)
+ val |= RALINK_PCIE1_RST;
+#endif
+#if defined (CONFIG_PCIE_PORT2)
+ val |= RALINK_PCIE2_RST;
+#endif
+ ASSERT_SYSRST_PCIE(RALINK_PCIE0_RST | RALINK_PCIE1_RST | RALINK_PCIE2_RST);
+ printk("pull PCIe RST: RALINK_RSTCTRL = %x\n", RALINK_RSTCTRL);
+#if defined GPIO_PERST /* add GPIO control instead of PERST_N */ /*chhung*/
+ *(unsigned int *)(0xbe000060) &= ~(0x3<<10 | 0x3<<3);
+ *(unsigned int *)(0xbe000060) |= 0x1<<10 | 0x1<<3;
+ mdelay(100);
+ *(unsigned int *)(0xbe000600) |= 0x1<<19 | 0x1<<8 | 0x1<<7; // use GPIO19/GPIO8/GPIO7 (PERST_N/UART_RXD3/UART_TXD3)
+ mdelay(100);
+ *(unsigned int *)(0xbe000620) &= ~(0x1<<19 | 0x1<<8 | 0x1<<7); // clear DATA
+
+ mdelay(100);
+#else
+ *(unsigned int *)(0xbe000060) &= ~0x00000c00;
+#endif
+#if defined (CONFIG_PCIE_PORT0)
+ val = RALINK_PCIE0_RST;
+#endif
+#if defined (CONFIG_PCIE_PORT1)
+ val |= RALINK_PCIE1_RST;
+#endif
+#if defined (CONFIG_PCIE_PORT2)
+ val |= RALINK_PCIE2_RST;
+#endif
+ DEASSERT_SYSRST_PCIE(val);
+ printk("release PCIe RST: RALINK_RSTCTRL = %x\n", RALINK_RSTCTRL);
+
+ if ((*(unsigned int *)(0xbe00000c)&0xFFFF) == 0x0101) // MT7621 E2
+ bypass_pipe_rst();
+ set_phy_for_ssc();
+ printk("release PCIe RST: RALINK_RSTCTRL = %x\n", RALINK_RSTCTRL);
+
+#if defined (CONFIG_PCIE_PORT0)
+ read_config(0, 0, 0, 0x70c, &val);
+ printk("Port 0 N_FTS = %x\n", (unsigned int)val);
+#endif
+#if defined (CONFIG_PCIE_PORT1)
+ read_config(0, 1, 0, 0x70c, &val);
+ printk("Port 1 N_FTS = %x\n", (unsigned int)val);
+#endif
+#if defined (CONFIG_PCIE_PORT2)
+ read_config(0, 2, 0, 0x70c, &val);
+ printk("Port 2 N_FTS = %x\n", (unsigned int)val);
+#endif
+
+ RALINK_RSTCTRL = (RALINK_RSTCTRL | RALINK_PCIE_RST);
+ RALINK_SYSCFG1 &= ~(0x30);
+ RALINK_SYSCFG1 |= (2<<4);
+ RALINK_PCIE_CLK_GEN &= 0x7fffffff;
+ RALINK_PCIE_CLK_GEN1 &= 0x80ffffff;
+ RALINK_PCIE_CLK_GEN1 |= 0xa << 24;
+ RALINK_PCIE_CLK_GEN |= 0x80000000;
+ mdelay(50);
+ RALINK_RSTCTRL = (RALINK_RSTCTRL & ~RALINK_PCIE_RST);
+
+
+#if defined GPIO_PERST /* add GPIO control instead of PERST_N */ /*chhung*/
+ *(unsigned int *)(0xbe000620) |= 0x1<<19 | 0x1<<8 | 0x1<<7; // set DATA
+ mdelay(100);
+#else
+ RALINK_PCI_PCICFG_ADDR &= ~(1<<1); //de-assert PERST
+#endif
+ mdelay(500);
+
+
+ mdelay(500);
+#if defined (CONFIG_PCIE_PORT0)
+ if(( RALINK_PCI0_STATUS & 0x1) == 0)
+ {
+ printk("PCIE0 no card, disable it(RST&CLK)\n");
+ ASSERT_SYSRST_PCIE(RALINK_PCIE0_RST);
+ RALINK_CLKCFG1 = (RALINK_CLKCFG1 & ~RALINK_PCIE0_CLK_EN);
+ pcie_link_status &= ~(1<<0);
+ } else {
+ pcie_link_status |= 1<<0;
+ RALINK_PCI_PCIMSK_ADDR |= (1<<20); // enable pcie1 interrupt
+ }
+#endif
+#if defined (CONFIG_PCIE_PORT1)
+ if(( RALINK_PCI1_STATUS & 0x1) == 0)
+ {
+ printk("PCIE1 no card, disable it(RST&CLK)\n");
+ ASSERT_SYSRST_PCIE(RALINK_PCIE1_RST);
+ RALINK_CLKCFG1 = (RALINK_CLKCFG1 & ~RALINK_PCIE1_CLK_EN);
+ pcie_link_status &= ~(1<<1);
+ } else {
+ pcie_link_status |= 1<<1;
+ RALINK_PCI_PCIMSK_ADDR |= (1<<21); // enable pcie1 interrupt
+ }
+#endif
+#if defined (CONFIG_PCIE_PORT2)
+ if (( RALINK_PCI2_STATUS & 0x1) == 0) {
+ printk("PCIE2 no card, disable it(RST&CLK)\n");
+ ASSERT_SYSRST_PCIE(RALINK_PCIE2_RST);
+ RALINK_CLKCFG1 = (RALINK_CLKCFG1 & ~RALINK_PCIE2_CLK_EN);
+ pcie_link_status &= ~(1<<2);
+ } else {
+ pcie_link_status |= 1<<2;
+ RALINK_PCI_PCIMSK_ADDR |= (1<<22); // enable pcie2 interrupt
+ }
+#endif
+ if (pcie_link_status == 0)
+ return 0;
+
+/*
+pcie(2/1/0) link status pcie2_num pcie1_num pcie0_num
+3'b000 x x x
+3'b001 x x 0
+3'b010 x 0 x
+3'b011 x 1 0
+3'b100 0 x x
+3'b101 1 x 0
+3'b110 1 0 x
+3'b111 2 1 0
+*/
+ switch(pcie_link_status) {
+ case 2:
+ RALINK_PCI_PCICFG_ADDR &= ~0x00ff0000;
+ RALINK_PCI_PCICFG_ADDR |= 0x1 << 16; //port0
+ RALINK_PCI_PCICFG_ADDR |= 0x0 << 20; //port1
+ break;
+ case 4:
+ RALINK_PCI_PCICFG_ADDR &= ~0x0fff0000;
+ RALINK_PCI_PCICFG_ADDR |= 0x1 << 16; //port0
+ RALINK_PCI_PCICFG_ADDR |= 0x2 << 20; //port1
+ RALINK_PCI_PCICFG_ADDR |= 0x0 << 24; //port2
+ break;
+ case 5:
+ RALINK_PCI_PCICFG_ADDR &= ~0x0fff0000;
+ RALINK_PCI_PCICFG_ADDR |= 0x0 << 16; //port0
+ RALINK_PCI_PCICFG_ADDR |= 0x2 << 20; //port1
+ RALINK_PCI_PCICFG_ADDR |= 0x1 << 24; //port2
+ break;
+ case 6:
+ RALINK_PCI_PCICFG_ADDR &= ~0x0fff0000;
+ RALINK_PCI_PCICFG_ADDR |= 0x2 << 16; //port0
+ RALINK_PCI_PCICFG_ADDR |= 0x0 << 20; //port1
+ RALINK_PCI_PCICFG_ADDR |= 0x1 << 24; //port2
+ break;
+ }
+ printk(" -> %x\n", RALINK_PCI_PCICFG_ADDR);
+ //printk(" RALINK_PCI_ARBCTL = %x\n", RALINK_PCI_ARBCTL);
+
+/*
+ ioport_resource.start = mt7621_res_pci_io1.start;
+ ioport_resource.end = mt7621_res_pci_io1.end;
+*/
+
+ RALINK_PCI_MEMBASE = 0xffffffff; //RALINK_PCI_MM_MAP_BASE;
+ RALINK_PCI_IOBASE = RALINK_PCI_IO_MAP_BASE;
+
+#if defined (CONFIG_PCIE_PORT0)
+ //PCIe0
+ if((pcie_link_status & 0x1) != 0) {
+ RALINK_PCI0_BAR0SETUP_ADDR = 0x7FFF0001; //open 7FFF:2G; ENABLE
+ RALINK_PCI0_IMBASEBAR0_ADDR = MEMORY_BASE;
+ RALINK_PCI0_CLASS = 0x06040001;
+ printk("PCIE0 enabled\n");
+ }
+#endif
+#if defined (CONFIG_PCIE_PORT1)
+ //PCIe1
+ if ((pcie_link_status & 0x2) != 0) {
+ RALINK_PCI1_BAR0SETUP_ADDR = 0x7FFF0001; //open 7FFF:2G; ENABLE
+ RALINK_PCI1_IMBASEBAR0_ADDR = MEMORY_BASE;
+ RALINK_PCI1_CLASS = 0x06040001;
+ printk("PCIE1 enabled\n");
+ }
+#endif
+#if defined (CONFIG_PCIE_PORT2)
+ //PCIe2
+ if ((pcie_link_status & 0x4) != 0) {
+ RALINK_PCI2_BAR0SETUP_ADDR = 0x7FFF0001; //open 7FFF:2G; ENABLE
+ RALINK_PCI2_IMBASEBAR0_ADDR = MEMORY_BASE;
+ RALINK_PCI2_CLASS = 0x06040001;
+ printk("PCIE2 enabled\n");
+ }
+#endif
+
+
+ switch(pcie_link_status) {
+ case 7:
+ read_config(0, 2, 0, 0x4, &val);
+ write_config(0, 2, 0, 0x4, val|0x4);
+ // write_config(0, 1, 0, 0x4, val|0x7);
+ read_config(0, 2, 0, 0x70c, &val);
+ val &= ~(0xff)<<8;
+ val |= 0x50<<8;
+ write_config(0, 2, 0, 0x70c, val);
+ case 3:
+ case 5:
+ case 6:
+ read_config(0, 1, 0, 0x4, &val);
+ write_config(0, 1, 0, 0x4, val|0x4);
+ // write_config(0, 1, 0, 0x4, val|0x7);
+ read_config(0, 1, 0, 0x70c, &val);
+ val &= ~(0xff)<<8;
+ val |= 0x50<<8;
+ write_config(0, 1, 0, 0x70c, val);
+ default:
+ read_config(0, 0, 0, 0x4, &val);
+ write_config(0, 0, 0, 0x4, val|0x4); //bus master enable
+ // write_config(0, 0, 0, 0x4, val|0x7); //bus master enable
+ read_config(0, 0, 0, 0x70c, &val);
+ val &= ~(0xff)<<8;
+ val |= 0x50<<8;
+ write_config(0, 0, 0, 0x70c, val);
+ }
+
+ pci_load_of_ranges(&mt7621_controller, pdev->dev.of_node);
+ setup_cm_memory_region(mt7621_controller.mem_resource);
+ register_pci_controller(&mt7621_controller);
+ return 0;
+
+}
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
+
+static const struct of_device_id mt7621_pci_ids[] = {
+ { .compatible = "mediatek,mt7621-pci" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mt7621_pci_ids);
+
+static struct platform_driver mt7621_pci_driver = {
+ .probe = mt7621_pci_probe,
+ .driver = {
+ .name = "mt7621-pci",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(mt7621_pci_ids),
+ },
+};
+
+static int __init mt7621_pci_init(void)
+{
+ return platform_driver_register(&mt7621_pci_driver);
+}
+
+arch_initcall(mt7621_pci_init);

View file

@ -0,0 +1,82 @@
From ce3d4a4111a5f7e6b4e74bceae5faa6ce388e8ec Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 14 Jul 2013 23:08:11 +0200
Subject: [PATCH 05/53] MIPS: use set_mode() to enable/disable the cevt-r4k
irq
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/ralink/Kconfig | 5 +++++
1 file changed, 5 insertions(+)
--- a/arch/mips/ralink/Kconfig
+++ b/arch/mips/ralink/Kconfig
@@ -1,12 +1,17 @@
# SPDX-License-Identifier: GPL-2.0
if RALINK
+config CEVT_SYSTICK_QUIRK
+ bool
+ default n
+
config CLKEVT_RT3352
bool
depends on SOC_RT305X || SOC_MT7620
default y
select TIMER_OF
select CLKSRC_MMIO
+ select CEVT_SYSTICK_QUIRK
config RALINK_ILL_ACC
bool
--- a/arch/mips/kernel/cevt-r4k.c
+++ b/arch/mips/kernel/cevt-r4k.c
@@ -15,6 +15,26 @@
#include <asm/time.h>
#include <asm/cevt-r4k.h>
+static int mips_state_oneshot(struct clock_event_device *evt)
+{
+ if (!cp0_timer_irq_installed) {
+ cp0_timer_irq_installed = 1;
+ setup_irq(evt->irq, &c0_compare_irqaction);
+ }
+
+ return 0;
+}
+
+static int mips_state_shutdown(struct clock_event_device *evt)
+{
+ if (cp0_timer_irq_installed) {
+ cp0_timer_irq_installed = 0;
+ remove_irq(evt->irq, &c0_compare_irqaction);
+ }
+
+ return 0;
+}
+
static int mips_next_event(unsigned long delta,
struct clock_event_device *evt)
{
@@ -281,17 +301,21 @@ int r4k_clockevent_init(void)
cd->rating = 300;
cd->irq = irq;
cd->cpumask = cpumask_of(cpu);
+ cd->set_state_shutdown = mips_state_shutdown;
+ cd->set_state_oneshot = mips_state_oneshot;
cd->set_next_event = mips_next_event;
cd->event_handler = mips_event_handler;
clockevents_config_and_register(cd, mips_hpt_frequency, min_delta, 0x7fffffff);
+#ifndef CONFIG_CEVT_SYSTICK_QUIRK
if (cp0_timer_irq_installed)
return 0;
cp0_timer_irq_installed = 1;
setup_irq(irq, &c0_compare_irqaction);
+#endif
return 0;
}

View file

@ -0,0 +1,200 @@
From bd30f19a006fb52bac80c6463c49dd2f4159f4ac Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 28 Jul 2013 16:26:41 +0200
Subject: [PATCH 06/53] MIPS: ralink: add cpu frequency scaling
This feature will break udelay() and cause the delay loop to have longer delays
when the frequency is scaled causing a performance hit.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/ralink/cevt-rt3352.c | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
--- a/arch/mips/ralink/cevt-rt3352.c
+++ b/arch/mips/ralink/cevt-rt3352.c
@@ -29,6 +29,10 @@
/* enable the counter */
#define CFG_CNT_EN 0x1
+/* mt7620 frequency scaling defines */
+#define CLK_LUT_CFG 0x40
+#define SLEEP_EN BIT(31)
+
struct systick_device {
void __iomem *membase;
struct clock_event_device dev;
@@ -36,21 +40,53 @@ struct systick_device {
int freq_scale;
};
+static void (*systick_freq_scaling)(struct systick_device *sdev, int status);
+
static int systick_set_oneshot(struct clock_event_device *evt);
static int systick_shutdown(struct clock_event_device *evt);
+static inline void mt7620_freq_scaling(struct systick_device *sdev, int status)
+{
+ if (sdev->freq_scale == status)
+ return;
+
+ sdev->freq_scale = status;
+
+ pr_info("%s: %s autosleep mode\n", sdev->dev.name,
+ (status) ? ("enable") : ("disable"));
+ if (status)
+ rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) | SLEEP_EN, CLK_LUT_CFG);
+ else
+ rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) & ~SLEEP_EN, CLK_LUT_CFG);
+}
+
+static inline unsigned int read_count(struct systick_device *sdev)
+{
+ return ioread32(sdev->membase + SYSTICK_COUNT);
+}
+
+static inline unsigned int read_compare(struct systick_device *sdev)
+{
+ return ioread32(sdev->membase + SYSTICK_COMPARE);
+}
+
+static inline void write_compare(struct systick_device *sdev, unsigned int val)
+{
+ iowrite32(val, sdev->membase + SYSTICK_COMPARE);
+}
+
static int systick_next_event(unsigned long delta,
struct clock_event_device *evt)
{
struct systick_device *sdev;
- u32 count;
+ int res;
sdev = container_of(evt, struct systick_device, dev);
- count = ioread32(sdev->membase + SYSTICK_COUNT);
- count = (count + delta) % SYSTICK_FREQ;
- iowrite32(count, sdev->membase + SYSTICK_COMPARE);
+ delta += read_count(sdev);
+ write_compare(sdev, delta);
+ res = ((int)(read_count(sdev) - delta) >= 0) ? -ETIME : 0;
- return 0;
+ return res;
}
static void systick_event_handler(struct clock_event_device *dev)
@@ -60,20 +96,25 @@ static void systick_event_handler(struct
static irqreturn_t systick_interrupt(int irq, void *dev_id)
{
- struct clock_event_device *dev = (struct clock_event_device *) dev_id;
+ int ret = 0;
+ struct clock_event_device *cdev;
+ struct systick_device *sdev;
- dev->event_handler(dev);
+ if (read_c0_cause() & STATUSF_IP7) {
+ cdev = (struct clock_event_device *) dev_id;
+ sdev = container_of(cdev, struct systick_device, dev);
+
+ /* Clear Count/Compare Interrupt */
+ write_compare(sdev, read_compare(sdev));
+ cdev->event_handler(cdev);
+ ret = 1;
+ }
- return IRQ_HANDLED;
+ return IRQ_RETVAL(ret);
}
static struct systick_device systick = {
.dev = {
- /*
- * cevt-r4k uses 300, make sure systick
- * gets used if available
- */
- .rating = 310,
.features = CLOCK_EVT_FEAT_ONESHOT,
.set_next_event = systick_next_event,
.set_state_shutdown = systick_shutdown,
@@ -95,9 +136,15 @@ static int systick_shutdown(struct clock
sdev = container_of(evt, struct systick_device, dev);
if (sdev->irq_requested)
- free_irq(systick.dev.irq, &systick_irqaction);
+ remove_irq(systick.dev.irq, &systick_irqaction);
sdev->irq_requested = 0;
- iowrite32(0, systick.membase + SYSTICK_CONFIG);
+ iowrite32(CFG_CNT_EN, systick.membase + SYSTICK_CONFIG);
+
+ if (systick_freq_scaling)
+ systick_freq_scaling(sdev, 0);
+
+ if (systick_freq_scaling)
+ systick_freq_scaling(sdev, 1);
return 0;
}
@@ -117,34 +164,48 @@ static int systick_set_oneshot(struct cl
return 0;
}
+static const struct of_device_id systick_match[] = {
+ { .compatible = "ralink,mt7620a-systick", .data = mt7620_freq_scaling},
+ {},
+};
+
static int __init ralink_systick_init(struct device_node *np)
{
+ const struct of_device_id *match;
+ int rating = 200;
int ret;
systick.membase = of_iomap(np, 0);
if (!systick.membase)
return -ENXIO;
- systick_irqaction.name = np->name;
- systick.dev.name = np->name;
- clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60);
- systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev);
- systick.dev.max_delta_ticks = 0x7fff;
- systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev);
- systick.dev.min_delta_ticks = 0x3;
+ match = of_match_node(systick_match, np);
+ if (match) {
+ systick_freq_scaling = match->data;
+ /*
+ * cevt-r4k uses 300, make sure systick
+ * gets used if available
+ */
+ rating = 310;
+ }
+
+ /* enable counter than register clock source */
+ iowrite32(CFG_CNT_EN, systick.membase + SYSTICK_CONFIG);
+ clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
+ SYSTICK_FREQ, rating, 16, clocksource_mmio_readl_up);
+
+ /* register clock event */
systick.dev.irq = irq_of_parse_and_map(np, 0);
if (!systick.dev.irq) {
pr_err("%s: request_irq failed", np->name);
return -EINVAL;
}
- ret = clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
- SYSTICK_FREQ, 301, 16,
- clocksource_mmio_readl_up);
- if (ret)
- return ret;
-
- clockevents_register_device(&systick.dev);
+ systick_irqaction.name = np->name;
+ systick.dev.name = np->name;
+ systick.dev.rating = rating;
+ systick.dev.cpumask = cpumask_of(0);
+ clockevents_config_and_register(&systick.dev, SYSTICK_FREQ, 0x3, 0x7fff);
pr_info("%s: running - mult: %d, shift: %d\n",
np->name, systick.dev.mult, systick.dev.shift);

View file

@ -0,0 +1,21 @@
From 67b7bff0fd364c194e653f69baa623ba2141bd4c Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Mon, 4 Aug 2014 18:46:02 +0200
Subject: [PATCH 07/53] MIPS: ralink: copy the commandline from the devicetree
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/ralink/of.c | 2 ++
1 file changed, 2 insertions(+)
--- a/arch/mips/ralink/of.c
+++ b/arch/mips/ralink/of.c
@@ -82,6 +82,8 @@ void __init plat_mem_setup(void)
__dt_setup_arch(dtb);
+ strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
+
of_scan_flat_dt(early_init_dt_find_memory, NULL);
if (memory_dtb)
of_scan_flat_dt(early_init_dt_scan_memory, NULL);

View file

@ -0,0 +1,28 @@
From 7768798964eb0e4f95eaecffb93b5d0ca28a38af Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Sat, 3 Jun 2017 20:00:03 +0200
Subject: [PATCH] MIPS: pci-mt7620: enabled PCIe on MT7688
To: linux-mips@linux-mips.org,
John Crispin <john@phrozen.org>
Cc: Wei Yongjun <yongjun_wei@trendmicro.com.cn>,
Ralf Baechle <ralf@linux-mips.org>,
linux-mediatek@lists.infradead.org
Use PCIe support for MT7628AN also on MT7688.
Tested on WRTNODE2R.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
arch/mips/pci/pci-mt7620.c | 1 +
1 file changed, 1 insertion(+)
--- a/arch/mips/pci/pci-mt7620.c
+++ b/arch/mips/pci/pci-mt7620.c
@@ -316,6 +316,7 @@ static int mt7620_pci_probe(struct platf
break;
case MT762X_SOC_MT7628AN:
+ case MT762X_SOC_MT7688:
if (mt7628_pci_hw_init(pdev))
return -1;
break;

View file

@ -0,0 +1,28 @@
From 5ede027f6c4a57ed25da872420508b7f1168b36b Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Mon, 7 Dec 2015 17:15:32 +0100
Subject: [PATCH 13/53] owrt: hack: fix mt7688 cache issue
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/kernel/setup.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -902,7 +902,6 @@ static void __init arch_mem_init(char **
crashk_res.end - crashk_res.start + 1,
BOOTMEM_DEFAULT);
#endif
- device_tree_init();
sparse_init();
plat_swiotlb_setup();
@@ -1018,6 +1017,7 @@ void __init setup_arch(char **cmdline_p)
cpu_cache_init();
paging_init();
+ device_tree_init();
}
unsigned long kernelsp[NR_CPUS];

View file

@ -0,0 +1,25 @@
From 9e6ce539092a1dd605a20bf73c655a9de58d8641 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Mon, 7 Dec 2015 17:18:05 +0100
Subject: [PATCH 15/53] arch: mips: do not select illegal access driver by
default
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/ralink/Kconfig | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/arch/mips/ralink/Kconfig
+++ b/arch/mips/ralink/Kconfig
@@ -14,9 +14,9 @@ config CLKEVT_RT3352
select CEVT_SYSTICK_QUIRK
config RALINK_ILL_ACC
- bool
+ bool "illegal access irq"
depends on SOC_RT305X
- default y
+ default n
config IRQ_INTC
bool

View file

@ -0,0 +1,166 @@
From 4267880319bc1a2270d352e0ded6d6386242a7ef Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Tue, 12 Aug 2014 20:49:27 +0200
Subject: [PATCH 24/53] GPIO: add named gpio exports
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/gpio/gpiolib-of.c | 68 +++++++++++++++++++++++++++++++++++++++++
drivers/gpio/gpiolib-sysfs.c | 10 +++++-
include/asm-generic/gpio.h | 6 ++++
include/linux/gpio/consumer.h | 8 +++++
4 files changed, 91 insertions(+), 1 deletion(-)
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -23,6 +23,8 @@
#include <linux/pinctrl/pinctrl.h>
#include <linux/slab.h>
#include <linux/gpio/machine.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
#include "gpiolib.h"
@@ -506,3 +508,69 @@ void of_gpiochip_remove(struct gpio_chip
gpiochip_remove_pin_ranges(chip);
of_node_put(chip->of_node);
}
+
+static struct of_device_id gpio_export_ids[] = {
+ { .compatible = "gpio-export" },
+ { /* sentinel */ }
+};
+
+static int __init of_gpio_export_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *cnp;
+ u32 val;
+ int nb = 0;
+
+ for_each_child_of_node(np, cnp) {
+ const char *name = NULL;
+ int gpio;
+ bool dmc;
+ int max_gpio = 1;
+ int i;
+
+ of_property_read_string(cnp, "gpio-export,name", &name);
+
+ if (!name)
+ max_gpio = of_gpio_count(cnp);
+
+ for (i = 0; i < max_gpio; i++) {
+ unsigned flags = 0;
+ enum of_gpio_flags of_flags;
+
+ gpio = of_get_gpio_flags(cnp, i, &of_flags);
+
+ if (of_flags == OF_GPIO_ACTIVE_LOW)
+ flags |= GPIOF_ACTIVE_LOW;
+
+ if (!of_property_read_u32(cnp, "gpio-export,output", &val))
+ flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+ else
+ flags |= GPIOF_IN;
+
+ if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np)))
+ continue;
+
+ dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change");
+ gpio_export_with_name(gpio, dmc, name);
+ nb++;
+ }
+ }
+
+ dev_info(&pdev->dev, "%d gpio(s) exported\n", nb);
+
+ return 0;
+}
+
+static struct platform_driver gpio_export_driver = {
+ .driver = {
+ .name = "gpio-export",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(gpio_export_ids),
+ },
+};
+
+static int __init of_gpio_export_init(void)
+{
+ return platform_driver_probe(&gpio_export_driver, of_gpio_export_probe);
+}
+device_initcall(of_gpio_export_init);
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -553,7 +553,7 @@ static struct class gpio_class = {
*
* Returns zero on success, else an error.
*/
-int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
+int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name)
{
struct gpio_chip *chip;
struct gpio_device *gdev;
@@ -615,6 +615,8 @@ int gpiod_export(struct gpio_desc *desc,
offset = gpio_chip_hwgpio(desc);
if (chip->names && chip->names[offset])
ioname = chip->names[offset];
+ if (name)
+ ioname = name;
dev = device_create_with_groups(&gpio_class, &gdev->dev,
MKDEV(0, 0), data, gpio_groups,
@@ -636,6 +638,12 @@ err_unlock:
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
return status;
}
+EXPORT_SYMBOL_GPL(__gpiod_export);
+
+int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
+{
+ return __gpiod_export(desc, direction_may_change, NULL);
+}
EXPORT_SYMBOL_GPL(gpiod_export);
static int match_export(struct device *dev, const void *desc)
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -127,6 +127,12 @@ static inline int gpio_export(unsigned g
return gpiod_export(gpio_to_desc(gpio), direction_may_change);
}
+int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
+static inline int gpio_export_with_name(unsigned gpio, bool direction_may_change, const char *name)
+{
+ return __gpiod_export(gpio_to_desc(gpio), direction_may_change, name);
+}
+
static inline int gpio_export_link(struct device *dev, const char *name,
unsigned gpio)
{
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -451,6 +451,7 @@ struct gpio_desc *devm_fwnode_get_gpiod_
#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS)
+int _gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
int gpiod_export_link(struct device *dev, const char *name,
struct gpio_desc *desc);
@@ -458,6 +459,13 @@ void gpiod_unexport(struct gpio_desc *de
#else /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */
+static inline int _gpiod_export(struct gpio_desc *desc,
+ bool direction_may_change,
+ const char *name)
+{
+ return -ENOSYS;
+}
+
static inline int gpiod_export(struct gpio_desc *desc,
bool direction_may_change)
{

View file

@ -0,0 +1,524 @@
From 7adbe9a88c33c6e362a10b109d963b5500a21f00 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 27 Jul 2014 09:34:05 +0100
Subject: [PATCH 25/53] pinctrl: ralink: add pinctrl driver
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/Kconfig | 2 +
drivers/pinctrl/Kconfig | 5 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/pinctrl-rt2880.c | 474 ++++++++++++++++++++++++++++++++++++++
4 files changed, 482 insertions(+)
create mode 100644 drivers/pinctrl/pinctrl-rt2880.c
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -628,6 +628,8 @@ config RALINK
select CLKDEV_LOOKUP
select ARCH_HAS_RESET_CONTROLLER
select RESET_CONTROLLER
+ select PINCTRL
+ select PINCTRL_RT2880
config SGI_IP22
bool "SGI IP22 (Indy/Indigo2)"
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -143,6 +143,11 @@ config PINCTRL_LPC18XX
help
Pinctrl driver for NXP LPC18xx/43xx System Control Unit (SCU).
+config PINCTRL_RT2880
+ bool
+ depends on RALINK
+ select PINMUX
+
config PINCTRL_FALCON
bool
depends on SOC_FALCON
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_PINCTRL_PALMAS) += pinctrl-
obj-$(CONFIG_PINCTRL_PIC32) += pinctrl-pic32.o
obj-$(CONFIG_PINCTRL_PISTACHIO) += pinctrl-pistachio.o
obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
+obj-$(CONFIG_PINCTRL_RT2880) += pinctrl-rt2880.o
obj-$(CONFIG_PINCTRL_RZA1) += pinctrl-rza1.o
obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
obj-$(CONFIG_PINCTRL_SIRF) += sirf/
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-rt2880.c
@@ -0,0 +1,472 @@
+/*
+ * linux/drivers/pinctrl/pinctrl-rt2880.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * publishhed by the Free Software Foundation.
+ *
+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/machine.h>
+
+#include <asm/mach-ralink/ralink_regs.h>
+#include <asm/mach-ralink/pinmux.h>
+#include <asm/mach-ralink/mt7620.h>
+
+#include "core.h"
+
+#define SYSC_REG_GPIO_MODE 0x60
+#define SYSC_REG_GPIO_MODE2 0x64
+
+struct rt2880_priv {
+ struct device *dev;
+
+ struct pinctrl_pin_desc *pads;
+ struct pinctrl_desc *desc;
+
+ struct rt2880_pmx_func **func;
+ int func_count;
+
+ struct rt2880_pmx_group *groups;
+ const char **group_names;
+ int group_count;
+
+ uint8_t *gpio;
+ int max_pins;
+};
+
+static int rt2880_get_group_count(struct pinctrl_dev *pctrldev)
+{
+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
+
+ return p->group_count;
+}
+
+static const char *rt2880_get_group_name(struct pinctrl_dev *pctrldev,
+ unsigned group)
+{
+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
+
+ if (group >= p->group_count)
+ return NULL;
+
+ return p->group_names[group];
+}
+
+static int rt2880_get_group_pins(struct pinctrl_dev *pctrldev,
+ unsigned group,
+ const unsigned **pins,
+ unsigned *num_pins)
+{
+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
+
+ if (group >= p->group_count)
+ return -EINVAL;
+
+ *pins = p->groups[group].func[0].pins;
+ *num_pins = p->groups[group].func[0].pin_count;
+
+ return 0;
+}
+
+static void rt2880_pinctrl_dt_free_map(struct pinctrl_dev *pctrldev,
+ struct pinctrl_map *map, unsigned num_maps)
+{
+ int i;
+
+ for (i = 0; i < num_maps; i++)
+ if (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN ||
+ map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
+ kfree(map[i].data.configs.configs);
+ kfree(map);
+}
+
+static void rt2880_pinctrl_pin_dbg_show(struct pinctrl_dev *pctrldev,
+ struct seq_file *s,
+ unsigned offset)
+{
+ seq_printf(s, "ralink pio");
+}
+
+static void rt2880_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctrldev,
+ struct device_node *np,
+ struct pinctrl_map **map)
+{
+ const char *function;
+ int func = of_property_read_string(np, "ralink,function", &function);
+ int grps = of_property_count_strings(np, "ralink,group");
+ int i;
+
+ if (func || !grps)
+ return;
+
+ for (i = 0; i < grps; i++) {
+ const char *group;
+
+ of_property_read_string_index(np, "ralink,group", i, &group);
+
+ (*map)->type = PIN_MAP_TYPE_MUX_GROUP;
+ (*map)->name = function;
+ (*map)->data.mux.group = group;
+ (*map)->data.mux.function = function;
+ (*map)++;
+ }
+}
+
+static int rt2880_pinctrl_dt_node_to_map(struct pinctrl_dev *pctrldev,
+ struct device_node *np_config,
+ struct pinctrl_map **map,
+ unsigned *num_maps)
+{
+ int max_maps = 0;
+ struct pinctrl_map *tmp;
+ struct device_node *np;
+
+ for_each_child_of_node(np_config, np) {
+ int ret = of_property_count_strings(np, "ralink,group");
+
+ if (ret >= 0)
+ max_maps += ret;
+ }
+
+ if (!max_maps)
+ return -EINVAL;
+
+ *map = kzalloc(max_maps * sizeof(struct pinctrl_map), GFP_KERNEL);
+ if (!*map)
+ return -ENOMEM;
+
+ tmp = *map;
+
+ for_each_child_of_node(np_config, np)
+ rt2880_pinctrl_dt_subnode_to_map(pctrldev, np, &tmp);
+ *num_maps = max_maps;
+
+ return 0;
+}
+
+static const struct pinctrl_ops rt2880_pctrl_ops = {
+ .get_groups_count = rt2880_get_group_count,
+ .get_group_name = rt2880_get_group_name,
+ .get_group_pins = rt2880_get_group_pins,
+ .pin_dbg_show = rt2880_pinctrl_pin_dbg_show,
+ .dt_node_to_map = rt2880_pinctrl_dt_node_to_map,
+ .dt_free_map = rt2880_pinctrl_dt_free_map,
+};
+
+static int rt2880_pmx_func_count(struct pinctrl_dev *pctrldev)
+{
+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
+
+ return p->func_count;
+}
+
+static const char *rt2880_pmx_func_name(struct pinctrl_dev *pctrldev,
+ unsigned func)
+{
+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
+
+ return p->func[func]->name;
+}
+
+static int rt2880_pmx_group_get_groups(struct pinctrl_dev *pctrldev,
+ unsigned func,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
+
+ if (p->func[func]->group_count == 1)
+ *groups = &p->group_names[p->func[func]->groups[0]];
+ else
+ *groups = p->group_names;
+
+ *num_groups = p->func[func]->group_count;
+
+ return 0;
+}
+
+static int rt2880_pmx_group_enable(struct pinctrl_dev *pctrldev,
+ unsigned func,
+ unsigned group)
+{
+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
+ u32 mode = 0;
+ u32 reg = SYSC_REG_GPIO_MODE;
+ int i;
+ int shift;
+
+ /* dont allow double use */
+ if (p->groups[group].enabled) {
+ dev_err(p->dev, "%s is already enabled\n", p->groups[group].name);
+ return -EBUSY;
+ }
+
+ p->groups[group].enabled = 1;
+ p->func[func]->enabled = 1;
+
+ shift = p->groups[group].shift;
+ if (shift >= 32) {
+ shift -= 32;
+ reg = SYSC_REG_GPIO_MODE2;
+ }
+ mode = rt_sysc_r32(reg);
+ mode &= ~(p->groups[group].mask << shift);
+
+ /* mark the pins as gpio */
+ for (i = 0; i < p->groups[group].func[0].pin_count; i++)
+ p->gpio[p->groups[group].func[0].pins[i]] = 1;
+
+ /* function 0 is gpio and needs special handling */
+ if (func == 0) {
+ mode |= p->groups[group].gpio << shift;
+ } else {
+ for (i = 0; i < p->func[func]->pin_count; i++)
+ p->gpio[p->func[func]->pins[i]] = 0;
+ mode |= p->func[func]->value << shift;
+ }
+ rt_sysc_w32(mode, reg);
+
+ return 0;
+}
+
+static int rt2880_pmx_group_gpio_request_enable(struct pinctrl_dev *pctrldev,
+ struct pinctrl_gpio_range *range,
+ unsigned pin)
+{
+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
+
+ if (!p->gpio[pin]) {
+ dev_err(p->dev, "pin %d is not set to gpio mux\n", pin);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct pinmux_ops rt2880_pmx_group_ops = {
+ .get_functions_count = rt2880_pmx_func_count,
+ .get_function_name = rt2880_pmx_func_name,
+ .get_function_groups = rt2880_pmx_group_get_groups,
+ .set_mux = rt2880_pmx_group_enable,
+ .gpio_request_enable = rt2880_pmx_group_gpio_request_enable,
+};
+
+static struct pinctrl_desc rt2880_pctrl_desc = {
+ .owner = THIS_MODULE,
+ .name = "rt2880-pinmux",
+ .pctlops = &rt2880_pctrl_ops,
+ .pmxops = &rt2880_pmx_group_ops,
+};
+
+static struct rt2880_pmx_func gpio_func = {
+ .name = "gpio",
+};
+
+static int rt2880_pinmux_index(struct rt2880_priv *p)
+{
+ struct rt2880_pmx_func **f;
+ struct rt2880_pmx_group *mux = p->groups;
+ int i, j, c = 0;
+
+ /* count the mux functions */
+ while (mux->name) {
+ p->group_count++;
+ mux++;
+ }
+
+ /* allocate the group names array needed by the gpio function */
+ p->group_names = devm_kzalloc(p->dev, sizeof(char *) * p->group_count, GFP_KERNEL);
+ if (!p->group_names)
+ return -1;
+
+ for (i = 0; i < p->group_count; i++) {
+ p->group_names[i] = p->groups[i].name;
+ p->func_count += p->groups[i].func_count;
+ }
+
+ /* we have a dummy function[0] for gpio */
+ p->func_count++;
+
+ /* allocate our function and group mapping index buffers */
+ f = p->func = devm_kzalloc(p->dev, sizeof(struct rt2880_pmx_func) * p->func_count, GFP_KERNEL);
+ gpio_func.groups = devm_kzalloc(p->dev, sizeof(int) * p->group_count, GFP_KERNEL);
+ if (!f || !gpio_func.groups)
+ return -1;
+
+ /* add a backpointer to the function so it knows its group */
+ gpio_func.group_count = p->group_count;
+ for (i = 0; i < gpio_func.group_count; i++)
+ gpio_func.groups[i] = i;
+
+ f[c] = &gpio_func;
+ c++;
+
+ /* add remaining functions */
+ for (i = 0; i < p->group_count; i++) {
+ for (j = 0; j < p->groups[i].func_count; j++) {
+ f[c] = &p->groups[i].func[j];
+ f[c]->groups = devm_kzalloc(p->dev, sizeof(int), GFP_KERNEL);
+ f[c]->groups[0] = i;
+ f[c]->group_count = 1;
+ c++;
+ }
+ }
+ return 0;
+}
+
+static int rt2880_pinmux_pins(struct rt2880_priv *p)
+{
+ int i, j;
+
+ /* loop over the functions and initialize the pins array. also work out the highest pin used */
+ for (i = 0; i < p->func_count; i++) {
+ int pin;
+
+ if (!p->func[i]->pin_count)
+ continue;
+
+ p->func[i]->pins = devm_kzalloc(p->dev, sizeof(int) * p->func[i]->pin_count, GFP_KERNEL);
+ for (j = 0; j < p->func[i]->pin_count; j++)
+ p->func[i]->pins[j] = p->func[i]->pin_first + j;
+
+ pin = p->func[i]->pin_first + p->func[i]->pin_count;
+ if (pin > p->max_pins)
+ p->max_pins = pin;
+ }
+
+ /* the buffer that tells us which pins are gpio */
+ p->gpio = devm_kzalloc(p->dev,sizeof(uint8_t) * p->max_pins,
+ GFP_KERNEL);
+ /* the pads needed to tell pinctrl about our pins */
+ p->pads = devm_kzalloc(p->dev,
+ sizeof(struct pinctrl_pin_desc) * p->max_pins,
+ GFP_KERNEL);
+ if (!p->pads || !p->gpio ) {
+ dev_err(p->dev, "Failed to allocate gpio data\n");
+ return -ENOMEM;
+ }
+
+ memset(p->gpio, 1, sizeof(uint8_t) * p->max_pins);
+ for (i = 0; i < p->func_count; i++) {
+ if (!p->func[i]->pin_count)
+ continue;
+
+ for (j = 0; j < p->func[i]->pin_count; j++)
+ p->gpio[p->func[i]->pins[j]] = 0;
+ }
+
+ /* pin 0 is always a gpio */
+ p->gpio[0] = 1;
+
+ /* set the pads */
+ for (i = 0; i < p->max_pins; i++) {
+ /* strlen("ioXY") + 1 = 5 */
+ char *name = devm_kzalloc(p->dev, 5, GFP_KERNEL);
+
+ if (!name) {
+ dev_err(p->dev, "Failed to allocate pad name\n");
+ return -ENOMEM;
+ }
+ snprintf(name, 5, "io%d", i);
+ p->pads[i].number = i;
+ p->pads[i].name = name;
+ }
+ p->desc->pins = p->pads;
+ p->desc->npins = p->max_pins;
+
+ return 0;
+}
+
+static int rt2880_pinmux_probe(struct platform_device *pdev)
+{
+ struct rt2880_priv *p;
+ struct pinctrl_dev *dev;
+ struct device_node *np;
+
+ if (!rt2880_pinmux_data)
+ return -ENOSYS;
+
+ /* setup the private data */
+ p = devm_kzalloc(&pdev->dev, sizeof(struct rt2880_priv), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ p->dev = &pdev->dev;
+ p->desc = &rt2880_pctrl_desc;
+ p->groups = rt2880_pinmux_data;
+ platform_set_drvdata(pdev, p);
+
+ /* init the device */
+ if (rt2880_pinmux_index(p)) {
+ dev_err(&pdev->dev, "failed to load index\n");
+ return -EINVAL;
+ }
+ if (rt2880_pinmux_pins(p)) {
+ dev_err(&pdev->dev, "failed to load pins\n");
+ return -EINVAL;
+ }
+ dev = pinctrl_register(p->desc, &pdev->dev, p);
+ if (IS_ERR(dev))
+ return PTR_ERR(dev);
+
+ /* finalize by adding gpio ranges for enables gpio controllers */
+ for_each_compatible_node(np, NULL, "ralink,rt2880-gpio") {
+ const __be32 *ngpio, *gpiobase;
+ struct pinctrl_gpio_range *range;
+ char *name;
+
+ if (!of_device_is_available(np))
+ continue;
+
+ ngpio = of_get_property(np, "ralink,num-gpios", NULL);
+ gpiobase = of_get_property(np, "ralink,gpio-base", NULL);
+ if (!ngpio || !gpiobase) {
+ dev_err(&pdev->dev, "failed to load chip info\n");
+ return -EINVAL;
+ }
+
+ range = devm_kzalloc(p->dev, sizeof(struct pinctrl_gpio_range) + 4, GFP_KERNEL);
+ range->name = name = (char *) &range[1];
+ sprintf(name, "pio");
+ range->npins = __be32_to_cpu(*ngpio);
+ range->base = __be32_to_cpu(*gpiobase);
+ range->pin_base = range->base;
+ pinctrl_add_gpio_range(dev, range);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id rt2880_pinmux_match[] = {
+ { .compatible = "ralink,rt2880-pinmux" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rt2880_pinmux_match);
+
+static struct platform_driver rt2880_pinmux_driver = {
+ .probe = rt2880_pinmux_probe,
+ .driver = {
+ .name = "rt2880-pinmux",
+ .owner = THIS_MODULE,
+ .of_match_table = rt2880_pinmux_match,
+ },
+};
+
+int __init rt2880_pinmux_init(void)
+{
+ return platform_driver_register(&rt2880_pinmux_driver);
+}
+
+core_initcall_sync(rt2880_pinmux_init);

View file

@ -0,0 +1,59 @@
From d410e5478c622c01fcf31427533df5f433df9146 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 28 Jul 2013 19:45:30 +0200
Subject: [PATCH 26/53] DT: Add documentation for gpio-ralink
Describe gpio-ralink binding.
Signed-off-by: John Crispin <blogic@openwrt.org>
Cc: linux-mips@linux-mips.org
Cc: devicetree@vger.kernel.org
Cc: linux-gpio@vger.kernel.org
---
.../devicetree/bindings/gpio/gpio-ralink.txt | 40 ++++++++++++++++++++
1 file changed, 40 insertions(+)
create mode 100644 Documentation/devicetree/bindings/gpio/gpio-ralink.txt
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-ralink.txt
@@ -0,0 +1,40 @@
+Ralink SoC GPIO controller bindings
+
+Required properties:
+- compatible:
+ - "ralink,rt2880-gpio" for Ralink controllers
+- #gpio-cells : Should be two.
+ - first cell is the pin number
+ - second cell is used to specify optional parameters (unused)
+- gpio-controller : Marks the device node as a GPIO controller
+- reg : Physical base address and length of the controller's registers
+- interrupt-parent: phandle to the INTC device node
+- interrupts : Specify the INTC interrupt number
+- ralink,num-gpios : Specify the number of GPIOs
+- ralink,register-map : The register layout depends on the GPIO bank and actual
+ SoC type. Register offsets need to be in this order.
+ [ INT, EDGE, RENA, FENA, DATA, DIR, POL, SET, RESET, TOGGLE ]
+
+Optional properties:
+- ralink,gpio-base : Specify the GPIO chips base number
+
+Example:
+
+ gpio0: gpio@600 {
+ compatible = "ralink,rt5350-gpio", "ralink,rt2880-gpio";
+
+ #gpio-cells = <2>;
+ gpio-controller;
+
+ reg = <0x600 0x34>;
+
+ interrupt-parent = <&intc>;
+ interrupts = <6>;
+
+ ralink,gpio-base = <0>;
+ ralink,num-gpios = <24>;
+ ralink,register-map = [ 00 04 08 0c
+ 20 24 28 2c
+ 30 34 ];
+
+ };

View file

@ -0,0 +1,430 @@
From 69fdd2c4f937796b934e89c33acde9d082e27bfd Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Mon, 4 Aug 2014 20:36:29 +0200
Subject: [PATCH 27/53] GPIO: MIPS: ralink: add gpio driver for ralink SoC
Add gpio driver for Ralink SoC. This driver makes the gpio core on
RT2880, RT305x, rt3352, rt3662, rt3883, rt5350 and mt7620 work.
Signed-off-by: John Crispin <blogic@openwrt.org>
Cc: linux-mips@linux-mips.org
Cc: linux-gpio@vger.kernel.org
---
arch/mips/include/asm/mach-ralink/gpio.h | 24 ++
drivers/gpio/Kconfig | 6 +
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-ralink.c | 355 ++++++++++++++++++++++++++++++
4 files changed, 386 insertions(+)
create mode 100644 arch/mips/include/asm/mach-ralink/gpio.h
create mode 100644 drivers/gpio/gpio-ralink.c
--- /dev/null
+++ b/arch/mips/include/asm/mach-ralink/gpio.h
@@ -0,0 +1,24 @@
+/*
+ * Ralink SoC GPIO API support
+ *
+ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#ifndef __ASM_MACH_RALINK_GPIO_H
+#define __ASM_MACH_RALINK_GPIO_H
+
+#define ARCH_NR_GPIOS 128
+#include <asm-generic/gpio.h>
+
+#define gpio_get_value __gpio_get_value
+#define gpio_set_value __gpio_set_value
+#define gpio_cansleep __gpio_cansleep
+#define gpio_to_irq __gpio_to_irq
+
+#endif /* __ASM_MACH_RALINK_GPIO_H */
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -398,6 +398,12 @@ config GPIO_REG
A 32-bit single register GPIO fixed in/out implementation. This
can be used to represent any register as a set of GPIO signals.
+config GPIO_RALINK
+ bool "Ralink GPIO Support"
+ depends on RALINK
+ help
+ Say yes here to support the Ralink SoC GPIO device
+
config GPIO_SPEAR_SPICS
bool "ST SPEAr13xx SPI Chip Select as GPIO support"
depends on PLAT_SPEAR
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -98,6 +98,7 @@ obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-p
obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o
obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
+obj-$(CONFIG_GPIO_RALINK) += gpio-ralink.o
obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o
--- /dev/null
+++ b/drivers/gpio/gpio-ralink.c
@@ -0,0 +1,355 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/of_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
+
+enum ralink_gpio_reg {
+ GPIO_REG_INT = 0,
+ GPIO_REG_EDGE,
+ GPIO_REG_RENA,
+ GPIO_REG_FENA,
+ GPIO_REG_DATA,
+ GPIO_REG_DIR,
+ GPIO_REG_POL,
+ GPIO_REG_SET,
+ GPIO_REG_RESET,
+ GPIO_REG_TOGGLE,
+ GPIO_REG_MAX
+};
+
+struct ralink_gpio_chip {
+ struct gpio_chip chip;
+ u8 regs[GPIO_REG_MAX];
+
+ spinlock_t lock;
+ void __iomem *membase;
+ struct irq_domain *domain;
+ int irq;
+
+ u32 rising;
+ u32 falling;
+};
+
+#define MAP_MAX 4
+static struct irq_domain *irq_map[MAP_MAX];
+static int irq_map_count;
+static atomic_t irq_refcount = ATOMIC_INIT(0);
+
+static inline struct ralink_gpio_chip *to_ralink_gpio(struct gpio_chip *chip)
+{
+ struct ralink_gpio_chip *rg;
+
+ rg = container_of(chip, struct ralink_gpio_chip, chip);
+
+ return rg;
+}
+
+static inline void rt_gpio_w32(struct ralink_gpio_chip *rg, u8 reg, u32 val)
+{
+ iowrite32(val, rg->membase + rg->regs[reg]);
+}
+
+static inline u32 rt_gpio_r32(struct ralink_gpio_chip *rg, u8 reg)
+{
+ return ioread32(rg->membase + rg->regs[reg]);
+}
+
+static void ralink_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
+
+ rt_gpio_w32(rg, (value) ? GPIO_REG_SET : GPIO_REG_RESET, BIT(offset));
+}
+
+static int ralink_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
+
+ return !!(rt_gpio_r32(rg, GPIO_REG_DATA) & BIT(offset));
+}
+
+static int ralink_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
+ unsigned long flags;
+ u32 t;
+
+ spin_lock_irqsave(&rg->lock, flags);
+ t = rt_gpio_r32(rg, GPIO_REG_DIR);
+ t &= ~BIT(offset);
+ rt_gpio_w32(rg, GPIO_REG_DIR, t);
+ spin_unlock_irqrestore(&rg->lock, flags);
+
+ return 0;
+}
+
+static int ralink_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
+ unsigned long flags;
+ u32 t;
+
+ spin_lock_irqsave(&rg->lock, flags);
+ ralink_gpio_set(chip, offset, value);
+ t = rt_gpio_r32(rg, GPIO_REG_DIR);
+ t |= BIT(offset);
+ rt_gpio_w32(rg, GPIO_REG_DIR, t);
+ spin_unlock_irqrestore(&rg->lock, flags);
+
+ return 0;
+}
+
+static int ralink_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
+{
+ struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
+
+ if (rg->irq < 1)
+ return -1;
+
+ return irq_create_mapping(rg->domain, pin);
+}
+
+static void ralink_gpio_irq_handler(struct irq_desc *desc)
+{
+ int i;
+
+ for (i = 0; i < irq_map_count; i++) {
+ struct irq_domain *domain = irq_map[i];
+ struct ralink_gpio_chip *rg;
+ unsigned long pending;
+ int bit;
+
+ rg = (struct ralink_gpio_chip *) domain->host_data;
+ pending = rt_gpio_r32(rg, GPIO_REG_INT);
+
+ for_each_set_bit(bit, &pending, rg->chip.ngpio) {
+ u32 map = irq_find_mapping(domain, bit);
+ generic_handle_irq(map);
+ rt_gpio_w32(rg, GPIO_REG_INT, BIT(bit));
+ }
+ }
+}
+
+static void ralink_gpio_irq_unmask(struct irq_data *d)
+{
+ struct ralink_gpio_chip *rg;
+ unsigned long flags;
+ u32 rise, fall;
+
+ rg = (struct ralink_gpio_chip *) d->domain->host_data;
+ rise = rt_gpio_r32(rg, GPIO_REG_RENA);
+ fall = rt_gpio_r32(rg, GPIO_REG_FENA);
+
+ spin_lock_irqsave(&rg->lock, flags);
+ rt_gpio_w32(rg, GPIO_REG_RENA, rise | (BIT(d->hwirq) & rg->rising));
+ rt_gpio_w32(rg, GPIO_REG_FENA, fall | (BIT(d->hwirq) & rg->falling));
+ spin_unlock_irqrestore(&rg->lock, flags);
+}
+
+static void ralink_gpio_irq_mask(struct irq_data *d)
+{
+ struct ralink_gpio_chip *rg;
+ unsigned long flags;
+ u32 rise, fall;
+
+ rg = (struct ralink_gpio_chip *) d->domain->host_data;
+ rise = rt_gpio_r32(rg, GPIO_REG_RENA);
+ fall = rt_gpio_r32(rg, GPIO_REG_FENA);
+
+ spin_lock_irqsave(&rg->lock, flags);
+ rt_gpio_w32(rg, GPIO_REG_FENA, fall & ~BIT(d->hwirq));
+ rt_gpio_w32(rg, GPIO_REG_RENA, rise & ~BIT(d->hwirq));
+ spin_unlock_irqrestore(&rg->lock, flags);
+}
+
+static int ralink_gpio_irq_type(struct irq_data *d, unsigned int type)
+{
+ struct ralink_gpio_chip *rg;
+ u32 mask = BIT(d->hwirq);
+
+ rg = (struct ralink_gpio_chip *) d->domain->host_data;
+
+ if (type == IRQ_TYPE_PROBE) {
+ if ((rg->rising | rg->falling) & mask)
+ return 0;
+
+ type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
+ }
+
+ if (type & IRQ_TYPE_EDGE_RISING)
+ rg->rising |= mask;
+ else
+ rg->rising &= ~mask;
+
+ if (type & IRQ_TYPE_EDGE_FALLING)
+ rg->falling |= mask;
+ else
+ rg->falling &= ~mask;
+
+ return 0;
+}
+
+static struct irq_chip ralink_gpio_irq_chip = {
+ .name = "GPIO",
+ .irq_unmask = ralink_gpio_irq_unmask,
+ .irq_mask = ralink_gpio_irq_mask,
+ .irq_mask_ack = ralink_gpio_irq_mask,
+ .irq_set_type = ralink_gpio_irq_type,
+};
+
+static int gpio_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
+{
+ irq_set_chip_and_handler(irq, &ralink_gpio_irq_chip, handle_level_irq);
+ irq_set_handler_data(irq, d);
+
+ return 0;
+}
+
+static const struct irq_domain_ops irq_domain_ops = {
+ .xlate = irq_domain_xlate_onecell,
+ .map = gpio_map,
+};
+
+static void ralink_gpio_irq_init(struct device_node *np,
+ struct ralink_gpio_chip *rg)
+{
+ if (irq_map_count >= MAP_MAX)
+ return;
+
+ rg->irq = irq_of_parse_and_map(np, 0);
+ if (!rg->irq)
+ return;
+
+ rg->domain = irq_domain_add_linear(np, rg->chip.ngpio,
+ &irq_domain_ops, rg);
+ if (!rg->domain) {
+ dev_err(rg->chip.parent, "irq_domain_add_linear failed\n");
+ return;
+ }
+
+ irq_map[irq_map_count++] = rg->domain;
+
+ rt_gpio_w32(rg, GPIO_REG_RENA, 0x0);
+ rt_gpio_w32(rg, GPIO_REG_FENA, 0x0);
+
+ if (!atomic_read(&irq_refcount))
+ irq_set_chained_handler(rg->irq, ralink_gpio_irq_handler);
+ atomic_inc(&irq_refcount);
+
+ dev_info(rg->chip.parent, "registering %d irq handlers\n", rg->chip.ngpio);
+}
+
+static int ralink_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ int gpio = chip->base + offset;
+
+ return pinctrl_request_gpio(gpio);
+}
+
+static void ralink_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ int gpio = chip->base + offset;
+
+ pinctrl_free_gpio(gpio);
+}
+
+static int ralink_gpio_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct ralink_gpio_chip *rg;
+ const __be32 *ngpio, *gpiobase;
+
+ if (!res) {
+ dev_err(&pdev->dev, "failed to find resource\n");
+ return -ENOMEM;
+ }
+
+ rg = devm_kzalloc(&pdev->dev,
+ sizeof(struct ralink_gpio_chip), GFP_KERNEL);
+ if (!rg)
+ return -ENOMEM;
+
+ rg->membase = devm_ioremap_resource(&pdev->dev, res);
+ if (!rg->membase) {
+ dev_err(&pdev->dev, "cannot remap I/O memory region\n");
+ return -ENOMEM;
+ }
+
+ if (of_property_read_u8_array(np, "ralink,register-map",
+ rg->regs, GPIO_REG_MAX)) {
+ dev_err(&pdev->dev, "failed to read register definition\n");
+ return -EINVAL;
+ }
+
+ ngpio = of_get_property(np, "ralink,num-gpios", NULL);
+ if (!ngpio) {
+ dev_err(&pdev->dev, "failed to read number of pins\n");
+ return -EINVAL;
+ }
+
+ gpiobase = of_get_property(np, "ralink,gpio-base", NULL);
+ if (gpiobase)
+ rg->chip.base = be32_to_cpu(*gpiobase);
+ else
+ rg->chip.base = -1;
+
+ spin_lock_init(&rg->lock);
+
+ rg->chip.parent = &pdev->dev;
+ rg->chip.label = dev_name(&pdev->dev);
+ rg->chip.of_node = np;
+ rg->chip.ngpio = be32_to_cpu(*ngpio);
+ rg->chip.direction_input = ralink_gpio_direction_input;
+ rg->chip.direction_output = ralink_gpio_direction_output;
+ rg->chip.get = ralink_gpio_get;
+ rg->chip.set = ralink_gpio_set;
+ rg->chip.request = ralink_gpio_request;
+ rg->chip.to_irq = ralink_gpio_to_irq;
+ rg->chip.free = ralink_gpio_free;
+
+ /* set polarity to low for all lines */
+ rt_gpio_w32(rg, GPIO_REG_POL, 0);
+
+ dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio);
+
+ ralink_gpio_irq_init(np, rg);
+
+ return gpiochip_add(&rg->chip);
+}
+
+static const struct of_device_id ralink_gpio_match[] = {
+ { .compatible = "ralink,rt2880-gpio" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ralink_gpio_match);
+
+static struct platform_driver ralink_gpio_driver = {
+ .probe = ralink_gpio_probe,
+ .driver = {
+ .name = "rt2880_gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = ralink_gpio_match,
+ },
+};
+
+static int __init ralink_gpio_init(void)
+{
+ return platform_driver_register(&ralink_gpio_driver);
+}
+
+subsys_initcall(ralink_gpio_init);

View file

@ -0,0 +1,405 @@
From 61ac7d9b4228de8c332900902c2b93189b042eab Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 27 Jul 2014 11:00:32 +0100
Subject: [PATCH 28/53] GPIO: ralink: add mt7621 gpio controller
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/Kconfig | 3 +
drivers/gpio/Kconfig | 6 +
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-mt7621.c | 354 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 364 insertions(+)
create mode 100644 drivers/gpio/gpio-mt7621.c
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -630,6 +630,9 @@ config RALINK
select RESET_CONTROLLER
select PINCTRL
select PINCTRL_RT2880
+ select ARCH_HAS_RESET_CONTROLLER
+ select RESET_CONTROLLER
+ select ARCH_REQUIRE_GPIOLIB
config SGI_IP22
bool "SGI IP22 (Indy/Indigo2)"
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -298,6 +298,12 @@ config GPIO_MENZ127
help
Say yes here to support the MEN 16Z127 GPIO Controller
+config GPIO_MT7621
+ bool "Mediatek GPIO Support"
+ depends on SOC_MT7620 || SOC_MT7621
+ help
+ Say yes here to support the Mediatek SoC GPIO device
+
config GPIO_MM_LANTIQ
bool "Lantiq Memory mapped GPIOs"
depends on LANTIQ && SOC_XWAY
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -152,3 +152,4 @@ obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o
obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o
obj-$(CONFIG_GPIO_ZX) += gpio-zx.o
obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o
+obj-$(CONFIG_GPIO_MT7621) += gpio-mt7621.o
--- /dev/null
+++ b/drivers/gpio/gpio-mt7621.c
@@ -0,0 +1,354 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/spinlock.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#define MTK_MAX_BANK 3
+#define MTK_BANK_WIDTH 32
+
+enum mediatek_gpio_reg {
+ GPIO_REG_CTRL = 0,
+ GPIO_REG_POL,
+ GPIO_REG_DATA,
+ GPIO_REG_DSET,
+ GPIO_REG_DCLR,
+ GPIO_REG_REDGE,
+ GPIO_REG_FEDGE,
+ GPIO_REG_HLVL,
+ GPIO_REG_LLVL,
+ GPIO_REG_STAT,
+ GPIO_REG_EDGE,
+};
+
+static void __iomem *mediatek_gpio_membase;
+static int mediatek_gpio_irq;
+static struct irq_domain *mediatek_gpio_irq_domain;
+static atomic_t irq_refcount = ATOMIC_INIT(0);
+
+struct mtk_gc {
+ struct gpio_chip chip;
+ spinlock_t lock;
+ int bank;
+ u32 rising;
+ u32 falling;
+} *gc_map[MTK_MAX_BANK];
+
+static inline struct mtk_gc
+*to_mediatek_gpio(struct gpio_chip *chip)
+{
+ struct mtk_gc *mgc;
+
+ mgc = container_of(chip, struct mtk_gc, chip);
+
+ return mgc;
+}
+
+static inline void
+mtk_gpio_w32(struct mtk_gc *rg, u8 reg, u32 val)
+{
+ iowrite32(val, mediatek_gpio_membase + (reg * 0x10) + (rg->bank * 0x4));
+}
+
+static inline u32
+mtk_gpio_r32(struct mtk_gc *rg, u8 reg)
+{
+ return ioread32(mediatek_gpio_membase + (reg * 0x10) + (rg->bank * 0x4));
+}
+
+static void
+mediatek_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct mtk_gc *rg = to_mediatek_gpio(chip);
+
+ mtk_gpio_w32(rg, (value) ? GPIO_REG_DSET : GPIO_REG_DCLR, BIT(offset));
+}
+
+static int
+mediatek_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct mtk_gc *rg = to_mediatek_gpio(chip);
+
+ return !!(mtk_gpio_r32(rg, GPIO_REG_DATA) & BIT(offset));
+}
+
+static int
+mediatek_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct mtk_gc *rg = to_mediatek_gpio(chip);
+ unsigned long flags;
+ u32 t;
+
+ spin_lock_irqsave(&rg->lock, flags);
+ t = mtk_gpio_r32(rg, GPIO_REG_CTRL);
+ t &= ~BIT(offset);
+ mtk_gpio_w32(rg, GPIO_REG_CTRL, t);
+ spin_unlock_irqrestore(&rg->lock, flags);
+
+ return 0;
+}
+
+static int
+mediatek_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct mtk_gc *rg = to_mediatek_gpio(chip);
+ unsigned long flags;
+ u32 t;
+
+ spin_lock_irqsave(&rg->lock, flags);
+ t = mtk_gpio_r32(rg, GPIO_REG_CTRL);
+ t |= BIT(offset);
+ mtk_gpio_w32(rg, GPIO_REG_CTRL, t);
+ mediatek_gpio_set(chip, offset, value);
+ spin_unlock_irqrestore(&rg->lock, flags);
+
+ return 0;
+}
+
+static int
+mediatek_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+ struct mtk_gc *rg = to_mediatek_gpio(chip);
+ unsigned long flags;
+ u32 t;
+
+ spin_lock_irqsave(&rg->lock, flags);
+ t = mtk_gpio_r32(rg, GPIO_REG_CTRL);
+ spin_unlock_irqrestore(&rg->lock, flags);
+
+ if (t & BIT(offset))
+ return 0;
+
+ return 1;
+}
+
+static int
+mediatek_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
+{
+ struct mtk_gc *rg = to_mediatek_gpio(chip);
+
+ return irq_create_mapping(mediatek_gpio_irq_domain, pin + (rg->bank * MTK_BANK_WIDTH));
+}
+
+static int
+mediatek_gpio_bank_probe(struct platform_device *pdev, struct device_node *bank)
+{
+ const __be32 *id = of_get_property(bank, "reg", NULL);
+ struct mtk_gc *rg = devm_kzalloc(&pdev->dev,
+ sizeof(struct mtk_gc), GFP_KERNEL);
+
+ if (!rg || !id || be32_to_cpu(*id) > MTK_MAX_BANK)
+ return -ENOMEM;
+
+ gc_map[be32_to_cpu(*id)] = rg;
+
+ memset(rg, 0, sizeof(struct mtk_gc));
+
+ spin_lock_init(&rg->lock);
+
+ rg->chip.parent = &pdev->dev;
+ rg->chip.label = dev_name(&pdev->dev);
+ rg->chip.of_node = bank;
+ rg->chip.base = MTK_BANK_WIDTH * be32_to_cpu(*id);
+ rg->chip.ngpio = MTK_BANK_WIDTH;
+ rg->chip.direction_input = mediatek_gpio_direction_input;
+ rg->chip.direction_output = mediatek_gpio_direction_output;
+ rg->chip.get_direction = mediatek_gpio_get_direction;
+ rg->chip.get = mediatek_gpio_get;
+ rg->chip.set = mediatek_gpio_set;
+ if (mediatek_gpio_irq_domain)
+ rg->chip.to_irq = mediatek_gpio_to_irq;
+ rg->bank = be32_to_cpu(*id);
+
+ /* set polarity to low for all gpios */
+ mtk_gpio_w32(rg, GPIO_REG_POL, 0);
+
+ dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio);
+
+ return gpiochip_add(&rg->chip);
+}
+
+static void
+mediatek_gpio_irq_handler(struct irq_desc *desc)
+{
+ int i;
+
+ for (i = 0; i < MTK_MAX_BANK; i++) {
+ struct mtk_gc *rg = gc_map[i];
+ unsigned long pending;
+ int bit;
+
+ if (!rg)
+ continue;
+
+ pending = mtk_gpio_r32(rg, GPIO_REG_STAT);
+
+ for_each_set_bit(bit, &pending, MTK_BANK_WIDTH) {
+ u32 map = irq_find_mapping(mediatek_gpio_irq_domain, (MTK_BANK_WIDTH * i) + bit);
+
+ generic_handle_irq(map);
+ mtk_gpio_w32(rg, GPIO_REG_STAT, BIT(bit));
+ }
+ }
+}
+
+static void
+mediatek_gpio_irq_unmask(struct irq_data *d)
+{
+ int pin = d->hwirq;
+ int bank = pin / 32;
+ struct mtk_gc *rg = gc_map[bank];
+ unsigned long flags;
+ u32 rise, fall;
+
+ if (!rg)
+ return;
+
+ rise = mtk_gpio_r32(rg, GPIO_REG_REDGE);
+ fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE);
+
+ spin_lock_irqsave(&rg->lock, flags);
+ mtk_gpio_w32(rg, GPIO_REG_REDGE, rise | (BIT(d->hwirq) & rg->rising));
+ mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall | (BIT(d->hwirq) & rg->falling));
+ spin_unlock_irqrestore(&rg->lock, flags);
+}
+
+static void
+mediatek_gpio_irq_mask(struct irq_data *d)
+{
+ int pin = d->hwirq;
+ int bank = pin / 32;
+ struct mtk_gc *rg = gc_map[bank];
+ unsigned long flags;
+ u32 rise, fall;
+
+ if (!rg)
+ return;
+
+ rise = mtk_gpio_r32(rg, GPIO_REG_REDGE);
+ fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE);
+
+ spin_lock_irqsave(&rg->lock, flags);
+ mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall & ~BIT(d->hwirq));
+ mtk_gpio_w32(rg, GPIO_REG_REDGE, rise & ~BIT(d->hwirq));
+ spin_unlock_irqrestore(&rg->lock, flags);
+}
+
+static int
+mediatek_gpio_irq_type(struct irq_data *d, unsigned int type)
+{
+ int pin = d->hwirq;
+ int bank = pin / 32;
+ struct mtk_gc *rg = gc_map[bank];
+ u32 mask = BIT(d->hwirq);
+
+ if (!rg)
+ return -1;
+
+ if (type == IRQ_TYPE_PROBE) {
+ if ((rg->rising | rg->falling) & mask)
+ return 0;
+
+ type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
+ }
+
+ if (type & IRQ_TYPE_EDGE_RISING)
+ rg->rising |= mask;
+ else
+ rg->rising &= ~mask;
+
+ if (type & IRQ_TYPE_EDGE_FALLING)
+ rg->falling |= mask;
+ else
+ rg->falling &= ~mask;
+
+ return 0;
+}
+
+static struct irq_chip mediatek_gpio_irq_chip = {
+ .name = "GPIO",
+ .irq_unmask = mediatek_gpio_irq_unmask,
+ .irq_mask = mediatek_gpio_irq_mask,
+ .irq_mask_ack = mediatek_gpio_irq_mask,
+ .irq_set_type = mediatek_gpio_irq_type,
+};
+
+static int
+mediatek_gpio_gpio_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
+{
+ irq_set_chip_and_handler(irq, &mediatek_gpio_irq_chip, handle_level_irq);
+ irq_set_handler_data(irq, d);
+
+ return 0;
+}
+
+static const struct irq_domain_ops irq_domain_ops = {
+ .xlate = irq_domain_xlate_onecell,
+ .map = mediatek_gpio_gpio_map,
+};
+
+static int
+mediatek_gpio_probe(struct platform_device *pdev)
+{
+ struct device_node *bank, *np = pdev->dev.of_node;
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ mediatek_gpio_membase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mediatek_gpio_membase))
+ return PTR_ERR(mediatek_gpio_membase);
+
+ mediatek_gpio_irq = irq_of_parse_and_map(np, 0);
+ if (mediatek_gpio_irq) {
+ mediatek_gpio_irq_domain = irq_domain_add_linear(np,
+ MTK_MAX_BANK * MTK_BANK_WIDTH,
+ &irq_domain_ops, NULL);
+ if (!mediatek_gpio_irq_domain)
+ dev_err(&pdev->dev, "irq_domain_add_linear failed\n");
+ }
+
+ for_each_child_of_node(np, bank)
+ if (of_device_is_compatible(bank, "mtk,mt7621-gpio-bank"))
+ mediatek_gpio_bank_probe(pdev, bank);
+
+ if (mediatek_gpio_irq_domain)
+ irq_set_chained_handler(mediatek_gpio_irq, mediatek_gpio_irq_handler);
+
+ return 0;
+}
+
+static const struct of_device_id mediatek_gpio_match[] = {
+ { .compatible = "mtk,mt7621-gpio" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mediatek_gpio_match);
+
+static struct platform_driver mediatek_gpio_driver = {
+ .probe = mediatek_gpio_probe,
+ .driver = {
+ .name = "mt7621_gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = mediatek_gpio_match,
+ },
+};
+
+static int __init
+mediatek_gpio_init(void)
+{
+ return platform_driver_register(&mediatek_gpio_driver);
+}
+
+subsys_initcall(mediatek_gpio_init);

View file

@ -0,0 +1,246 @@
From 975e76214cd2516eb6cfff4c3eec581872645e88 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Thu, 19 Sep 2013 01:50:59 +0200
Subject: [PATCH 31/53] uvc: add iPassion iP2970 support
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/media/usb/uvc/uvc_driver.c | 12 +++
drivers/media/usb/uvc/uvc_status.c | 2 +
drivers/media/usb/uvc/uvc_video.c | 147 ++++++++++++++++++++++++++++++++++++
drivers/media/usb/uvc/uvcvideo.h | 5 +-
4 files changed, 165 insertions(+), 1 deletion(-)
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -2734,6 +2734,18 @@ static const struct usb_device_id uvc_id
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_FORCE_Y8 },
+ /* iPassion iP2970 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x1B3B,
+ .idProduct = 0x2970,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX
+ | UVC_QUIRK_STREAM_NO_FID
+ | UVC_QUIRK_MOTION
+ | UVC_QUIRK_SINGLE_ISO },
/* Generic USB Video Class */
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) },
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) },
--- a/drivers/media/usb/uvc/uvc_status.c
+++ b/drivers/media/usb/uvc/uvc_status.c
@@ -139,6 +139,7 @@ static void uvc_status_complete(struct u
switch (dev->status[0] & 0x0f) {
case UVC_STATUS_TYPE_CONTROL:
uvc_event_control(dev, dev->status, len);
+ dev->motion = 1;
break;
case UVC_STATUS_TYPE_STREAMING:
@@ -182,6 +183,7 @@ int uvc_status_init(struct uvc_device *d
}
pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress);
+ dev->motion = 0;
/* For high-speed interrupt endpoints, the bInterval value is used as
* an exponent of two. Some developers forgot about it.
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -21,6 +21,11 @@
#include <linux/wait.h>
#include <linux/atomic.h>
#include <asm/unaligned.h>
+#include <linux/skbuff.h>
+#include <linux/kobject.h>
+#include <linux/netlink.h>
+#include <linux/kobject.h>
+#include <linux/workqueue.h>
#include <media/v4l2-common.h>
@@ -1081,9 +1086,149 @@ static void uvc_video_decode_data(struct
}
}
+struct bh_priv {
+ unsigned long seen;
+};
+
+struct bh_event {
+ const char *name;
+ struct sk_buff *skb;
+ struct work_struct work;
+};
+
+#define BH_ERR(fmt, args...) printk(KERN_ERR "%s: " fmt, "webcam", ##args )
+#define BH_DBG(fmt, args...) do {} while (0)
+#define BH_SKB_SIZE 2048
+
+extern u64 uevent_next_seqnum(void);
+static int seen = 0;
+
+static int bh_event_add_var(struct bh_event *event, int argv,
+ const char *format, ...)
+{
+ static char buf[128];
+ char *s;
+ va_list args;
+ int len;
+
+ if (argv)
+ return 0;
+
+ va_start(args, format);
+ len = vsnprintf(buf, sizeof(buf), format, args);
+ va_end(args);
+
+ if (len >= sizeof(buf)) {
+ BH_ERR("buffer size too small\n");
+ WARN_ON(1);
+ return -ENOMEM;
+ }
+
+ s = skb_put(event->skb, len + 1);
+ strcpy(s, buf);
+
+ BH_DBG("added variable '%s'\n", s);
+
+ return 0;
+}
+
+static int motion_hotplug_fill_event(struct bh_event *event)
+{
+ int s = jiffies;
+ int ret;
+
+ if (!seen)
+ seen = jiffies;
+
+ ret = bh_event_add_var(event, 0, "HOME=%s", "/");
+ if (ret)
+ return ret;
+
+ ret = bh_event_add_var(event, 0, "PATH=%s",
+ "/sbin:/bin:/usr/sbin:/usr/bin");
+ if (ret)
+ return ret;
+
+ ret = bh_event_add_var(event, 0, "SUBSYSTEM=usb");
+ if (ret)
+ return ret;
+
+ ret = bh_event_add_var(event, 0, "ACTION=motion");
+ if (ret)
+ return ret;
+
+ ret = bh_event_add_var(event, 0, "SEEN=%d", s - seen);
+ if (ret)
+ return ret;
+ seen = s;
+
+ ret = bh_event_add_var(event, 0, "SEQNUM=%llu", uevent_next_seqnum());
+
+ return ret;
+}
+
+static void motion_hotplug_work(struct work_struct *work)
+{
+ struct bh_event *event = container_of(work, struct bh_event, work);
+ int ret = 0;
+
+ event->skb = alloc_skb(BH_SKB_SIZE, GFP_KERNEL);
+ if (!event->skb)
+ goto out_free_event;
+
+ ret = bh_event_add_var(event, 0, "%s@", "add");
+ if (ret)
+ goto out_free_skb;
+
+ ret = motion_hotplug_fill_event(event);
+ if (ret)
+ goto out_free_skb;
+
+ NETLINK_CB(event->skb).dst_group = 1;
+ broadcast_uevent(event->skb, 0, 1, GFP_KERNEL);
+
+out_free_skb:
+ if (ret) {
+ BH_ERR("work error %d\n", ret);
+ kfree_skb(event->skb);
+ }
+out_free_event:
+ kfree(event);
+}
+
+static int motion_hotplug_create_event(void)
+{
+ struct bh_event *event;
+
+ event = kzalloc(sizeof(*event), GFP_KERNEL);
+ if (!event)
+ return -ENOMEM;
+
+ event->name = "motion";
+
+ INIT_WORK(&event->work, (void *)(void *)motion_hotplug_work);
+ schedule_work(&event->work);
+
+ return 0;
+}
+
+#define MOTION_FLAG_OFFSET 4
static void uvc_video_decode_end(struct uvc_streaming *stream,
struct uvc_buffer *buf, const __u8 *data, int len)
{
+ if ((stream->dev->quirks & UVC_QUIRK_MOTION) &&
+ (data[len - 2] == 0xff) && (data[len - 1] == 0xd9)) {
+ u8 *mem;
+ buf->state = UVC_BUF_STATE_READY;
+ mem = (u8 *) (buf->mem + MOTION_FLAG_OFFSET);
+ if ( stream->dev->motion ) {
+ stream->dev->motion = 0;
+ motion_hotplug_create_event();
+ } else {
+ *mem &= 0x7f;
+ }
+ }
+
/* Mark the buffer as done if the EOF marker is set. */
if (data[1] & UVC_STREAM_EOF && buf->bytesused != 0) {
uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n");
@@ -1498,6 +1643,8 @@ static int uvc_init_video_isoc(struct uv
if (npackets == 0)
return -ENOMEM;
+ if (stream->dev->quirks & UVC_QUIRK_SINGLE_ISO)
+ npackets = 1;
size = npackets * psize;
for (i = 0; i < UVC_URBS; ++i) {
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -186,7 +186,9 @@
#define UVC_QUIRK_RESTRICT_FRAME_RATE 0x00000200
#define UVC_QUIRK_RESTORE_CTRLS_ON_INIT 0x00000400
#define UVC_QUIRK_FORCE_Y8 0x00000800
-
+#define UVC_QUIRK_MOTION 0x00001000
+#define UVC_QUIRK_SINGLE_ISO 0x00002000
+
/* Format flags */
#define UVC_FMT_FLAG_COMPRESSED 0x00000001
#define UVC_FMT_FLAG_STREAM 0x00000002
@@ -584,6 +586,7 @@ struct uvc_device {
__u8 *status;
struct input_dev *input;
char input_phys[64];
+ int motion;
};
enum uvc_handle_state {

View file

@ -0,0 +1,29 @@
From a758e0870c6d1e4b0272f6e7f9efa9face5534bb Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 27 Jul 2014 09:49:07 +0100
Subject: [PATCH 32/53] USB: dwc2: add device_reset()
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/usb/dwc2/hcd.c | 3 +++
1 file changed, 3 insertions(+)
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -48,6 +48,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/usb.h>
+#include <linux/reset.h>
#include <linux/usb/hcd.h>
#include <linux/usb/ch11.h>
@@ -5072,6 +5073,8 @@ int dwc2_hcd_init(struct dwc2_hsotg *hso
retval = -ENOMEM;
+ device_reset(hsotg->dev);
+
hcfg = dwc2_readl(hsotg->regs + HCFG);
dev_dbg(hsotg->dev, "hcfg=%08x\n", hcfg);

View file

@ -0,0 +1,59 @@
From 0b6eb1e68290243d439ee330ea8d0b239a5aec69 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 27 Jul 2014 09:38:50 +0100
Subject: [PATCH 34/53] NET: multi phy support
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/net/phy/phy.c | 9 ++++++---
include/linux/phy.h | 1 +
2 files changed, 7 insertions(+), 3 deletions(-)
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -984,7 +984,10 @@ void phy_state_machine(struct work_struc
/* If the link is down, give up on negotiation for now */
if (!phydev->link) {
phydev->state = PHY_NOLINK;
- phy_link_down(phydev, true);
+ if (!phydev->no_auto_carrier_off)
+ phy_link_down(phydev, true);
+ else
+ phy_link_down(phydev, false);
break;
}
@@ -1071,7 +1074,10 @@ void phy_state_machine(struct work_struc
phy_link_up(phydev);
} else {
phydev->state = PHY_NOLINK;
- phy_link_down(phydev, true);
+ if (!phydev->no_auto_carrier_off)
+ phy_link_down(phydev, true);
+ else
+ phy_link_down(phydev, false);
}
if (phy_interrupt_is_valid(phydev))
@@ -1081,7 +1087,10 @@ void phy_state_machine(struct work_struc
case PHY_HALTED:
if (phydev->link) {
phydev->link = 0;
- phy_link_down(phydev, true);
+ if (!phydev->no_auto_carrier_off)
+ phy_link_down(phydev, true);
+ else
+ phy_link_down(phydev, false);
do_suspend = true;
}
break;
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -412,6 +412,7 @@ struct phy_device {
bool suspended;
bool sysfs_links;
bool loopback_enabled;
+ bool no_auto_carrier_off;
enum phy_state state;

View file

@ -0,0 +1,29 @@
From 8e72a3a1be8f6328bd7ef491332ba541547b6086 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Mon, 15 Jul 2013 00:38:51 +0200
Subject: [PATCH 36/53] mtd: fix cfi cmdset 0002 erase status check
---
drivers/mtd/chips/cfi_cmdset_0002.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -2293,7 +2293,7 @@ static int __xipram do_erase_chip(struct
chip->erase_suspended = 0;
}
- if (chip_ready(map, adr))
+ if (chip_good(map, adr, map_word_ff(map)))
break;
if (time_after(jiffies, timeo)) {
@@ -2382,7 +2382,7 @@ static int __xipram do_erase_oneblock(st
chip->erase_suspended = 0;
}
- if (chip_ready(map, adr)) {
+ if (chip_good(map, adr, map_word_ff(map))) {
xip_enable(map, chip, adr);
break;
}

View file

@ -0,0 +1,70 @@
From ee9081b2726a5ca8cde5497afdc5425e21ff8f8b Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Mon, 15 Jul 2013 00:39:21 +0200
Subject: [PATCH 37/53] mtd: cfi cmdset 0002 force word write
---
drivers/mtd/chips/cfi_cmdset_0002.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -40,7 +40,7 @@
#include <linux/mtd/xip.h>
#define AMD_BOOTLOC_BUG
-#define FORCE_WORD_WRITE 0
+#define FORCE_WORD_WRITE 1
#define MAX_WORD_RETRIES 3
@@ -51,7 +51,9 @@
static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
+#if !FORCE_WORD_WRITE
static int cfi_amdstd_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
+#endif
static int cfi_amdstd_erase_chip(struct mtd_info *, struct erase_info *);
static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *);
static void cfi_amdstd_sync (struct mtd_info *);
@@ -202,6 +204,7 @@ static void fixup_amd_bootblock(struct m
}
#endif
+#if !FORCE_WORD_WRITE
static void fixup_use_write_buffers(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
@@ -211,6 +214,7 @@ static void fixup_use_write_buffers(stru
mtd->_write = cfi_amdstd_write_buffers;
}
}
+#endif /* !FORCE_WORD_WRITE */
/* Atmel chips don't use the same PRI format as AMD chips */
static void fixup_convert_atmel_pri(struct mtd_info *mtd)
@@ -1791,6 +1795,7 @@ static int cfi_amdstd_write_words(struct
/*
* FIXME: interleaved mode not tested, and probably not supported!
*/
+#if !FORCE_WORD_WRITE
static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
unsigned long adr, const u_char *buf,
int len)
@@ -1919,7 +1924,6 @@ static int __xipram do_write_buffer(stru
return ret;
}
-
static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
@@ -1994,6 +1998,7 @@ static int cfi_amdstd_write_buffers(stru
return 0;
}
+#endif /* !FORCE_WORD_WRITE */
/*
* Wait for the flash chip to become ready to write data

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,42 @@
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -885,6 +885,9 @@ struct nand_chip {
int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);
int (*erase)(struct mtd_info *mtd, int page);
int (*scan_bbt)(struct mtd_info *mtd);
+ int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
+ uint32_t offset, int data_len, const uint8_t *buf,
+ int oob_required, int page, int raw);
int (*onfi_set_features)(struct mtd_info *mtd, struct nand_chip *chip,
int feature_addr, uint8_t *subfeature_para);
int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2753,9 +2753,14 @@ static int nand_do_write_ops(struct mtd_
memset(chip->oob_poi, 0xff, mtd->oobsize);
}
- ret = nand_write_page(mtd, chip, column, bytes, wbuf,
- oob_required, page,
- (ops->mode == MTD_OPS_RAW));
+// if (chip->write_page)
+ ret = chip->write_page(mtd, chip, column, bytes, wbuf,
+ oob_required, page,
+ (ops->mode == MTD_OPS_RAW));
+// else
+// ret = nand_write_page(mtd, chip, column, bytes, wbuf,
+// oob_required, page,
+// (ops->mode == MTD_OPS_RAW));
if (ret)
break;
@@ -4711,6 +4716,9 @@ int nand_scan_tail(struct mtd_info *mtd)
}
}
+// if (!chip->write_page)
+// chip->write_page = nand_write_page;
+
/*
* Check ECC mode, default to software if 3byte/512byte hardware ECC is
* selected and we have 256 byte pagesize fallback to software ECC

View file

@ -0,0 +1,65 @@
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1903,6 +1903,9 @@ static int nand_do_read_ops(struct mtd_i
__func__, buf);
read_retry:
+#ifdef CONFIG_MTK_MTD_NAND
+ ret = chip->read_page(mtd, chip, bufpoi, page);
+#else
if (nand_standard_page_accessors(&chip->ecc))
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
@@ -1922,6 +1925,7 @@ read_retry:
else
ret = chip->ecc.read_page(mtd, chip, bufpoi,
oob_required, page);
+#endif
if (ret < 0) {
if (use_bufpoi)
/* Invalidate page cache */
@@ -3076,8 +3080,11 @@ int nand_erase_nand(struct mtd_info *mtd
(page + pages_per_block))
chip->pagebuf = -1;
+#ifdef CONFIG_MTK_MTD_NAND
+ status = chip->erase_mtk(mtd, page & chip->pagemask);
+#else
status = chip->erase(mtd, page & chip->pagemask);
-
+#endif
/* See if block erase succeeded */
if (status & NAND_STATUS_FAIL) {
pr_debug("%s: failed erase, page 0x%08x\n",
@@ -4207,6 +4214,7 @@ int nand_scan_ident(struct mtd_info *mtd
* cmdfunc() both expect cmd_ctrl() to be populated,
* so we need to check that that's the case
*/
+ printk("%s:%s[%d]%p %p %p\n", __FILE__, __func__, __LINE__, chip->cmdfunc, chip->select_chip, chip->cmd_ctrl);
pr_err("chip.cmd_ctrl() callback is not provided");
return -EINVAL;
}
--- a/drivers/mtd/nand/nand_device_list.h
+++ b/drivers/mtd/nand/nand_device_list.h
@@ -44,6 +44,8 @@ static const flashdev_info gen_FlashTabl
{0xADBC, 0x905554, 5, 16, 512, 128, 2048, 64, 0x10801011, "H9DA4GH4JJAMC", 0},
{0x01F1, 0x801D01, 4, 8, 128, 128, 2048, 64, 0x30C77fff, "S34ML01G100TF", 0},
{0x92F1, 0x8095FF, 4, 8, 128, 128, 2048, 64, 0x30C77fff, "F59L1G81A", 0},
+ {0xC8DA, 0x909544, 5, 8, 256, 128, 2048, 64, 0x30C77fff, "F59L2G81A", 0},
+ {0xC8DC, 0x909554, 5, 8, 512, 128, 2048, 64, 0x30C77fff, "F59L4G81A", 0},
{0xECD3, 0x519558, 5, 8, 1024, 128, 2048, 64, 0x44333, "K9K8G8000", 0},
{0xC2F1, 0x801DC2, 4, 8, 128, 128, 2048, 64, 0x30C77fff, "MX30LF1G08AA", 0},
{0x98D3, 0x902676, 5, 8, 1024, 256, 4096, 224, 0x00C25332, "TC58NVG3S0F", 0},
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -896,6 +896,10 @@ struct nand_chip {
int (*setup_data_interface)(struct mtd_info *mtd, int chipnr,
const struct nand_data_interface *conf);
+#ifdef CONFIG_MTK_MTD_NAND
+ int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip, u8 *buf, int page);
+ int (*erase_mtk)(struct mtd_info *mtd, int page);
+#endif /* CONFIG_MTK_MTD_NAND */
int chip_delay;
unsigned int options;

View file

@ -0,0 +1,44 @@
From da6015e7f19d749f135f7ac55c4ec47b06faa868 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Fri, 9 Aug 2013 20:12:59 +0200
Subject: [PATCH 41/53] DT: Add documentation for spi-rt2880
Describe the SPI master found on the MIPS based Ralink RT2880 SoC.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
.../devicetree/bindings/spi/spi-rt2880.txt | 28 ++++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 Documentation/devicetree/bindings/spi/spi-rt2880.txt
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-rt2880.txt
@@ -0,0 +1,28 @@
+Ralink SoC RT2880 SPI master controller.
+
+This SPI controller is found on most wireless SoCs made by ralink.
+
+Required properties:
+- compatible : "ralink,rt2880-spi"
+- reg : The register base for the controller.
+- #address-cells : <1>, as required by generic SPI binding.
+- #size-cells : <0>, also as required by generic SPI binding.
+
+Child nodes as per the generic SPI binding.
+
+Example:
+
+ spi@b00 {
+ compatible = "ralink,rt2880-spi";
+ reg = <0xb00 0x100>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ m25p80@0 {
+ compatible = "m25p80";
+ reg = <0>;
+ spi-max-frequency = <10000000>;
+ };
+ };
+

View file

@ -0,0 +1,574 @@
From 683af4ebb91a1600df1946ac4769d916b8a1be65 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 27 Jul 2014 11:15:12 +0100
Subject: [PATCH 42/53] SPI: ralink: add Ralink SoC spi driver
Add the driver needed to make SPI work on Ralink SoC.
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
Acked-by: John Crispin <blogic@openwrt.org>
---
drivers/spi/Kconfig | 6 +
drivers/spi/Makefile | 1 +
drivers/spi/spi-rt2880.c | 530 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 537 insertions(+)
create mode 100644 drivers/spi/spi-rt2880.c
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -563,6 +563,12 @@ config SPI_QUP
This driver can also be built as a module. If so, the module
will be called spi_qup.
+config SPI_RT2880
+ tristate "Ralink RT288x SPI Controller"
+ depends on RALINK
+ help
+ This selects a driver for the Ralink RT288x/RT305x SPI Controller.
+
config SPI_S3C24XX
tristate "Samsung S3C24XX series SPI"
depends on ARCH_S3C24XX
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -81,6 +81,7 @@ obj-$(CONFIG_SPI_QUP) += spi-qup.o
obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o
obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
+obj-$(CONFIG_SPI_RT2880) += spi-rt2880.o
obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
spi-s3c24xx-hw-y := spi-s3c24xx.o
spi-s3c24xx-hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi-s3c24xx-fiq.o
--- /dev/null
+++ b/drivers/spi/spi-rt2880.c
@@ -0,0 +1,530 @@
+/*
+ * spi-rt2880.c -- Ralink RT288x/RT305x SPI controller driver
+ *
+ * Copyright (C) 2011 Sergiy <piratfm@gmail.com>
+ * Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Some parts are based on spi-orion.c:
+ * Author: Shadi Ammouri <shadi@marvell.com>
+ * Copyright (C) 2007-2008 Marvell Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/reset.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#define DRIVER_NAME "spi-rt2880"
+
+#define RAMIPS_SPI_STAT 0x00
+#define RAMIPS_SPI_CFG 0x10
+#define RAMIPS_SPI_CTL 0x14
+#define RAMIPS_SPI_DATA 0x20
+#define RAMIPS_SPI_ADDR 0x24
+#define RAMIPS_SPI_BS 0x28
+#define RAMIPS_SPI_USER 0x2C
+#define RAMIPS_SPI_TXFIFO 0x30
+#define RAMIPS_SPI_RXFIFO 0x34
+#define RAMIPS_SPI_FIFO_STAT 0x38
+#define RAMIPS_SPI_MODE 0x3C
+#define RAMIPS_SPI_DEV_OFFSET 0x40
+#define RAMIPS_SPI_DMA 0x80
+#define RAMIPS_SPI_DMASTAT 0x84
+#define RAMIPS_SPI_ARBITER 0xF0
+
+/* SPISTAT register bit field */
+#define SPISTAT_BUSY BIT(0)
+
+/* SPICFG register bit field */
+#define SPICFG_ADDRMODE BIT(12)
+#define SPICFG_RXENVDIS BIT(11)
+#define SPICFG_RXCAP BIT(10)
+#define SPICFG_SPIENMODE BIT(9)
+#define SPICFG_MSBFIRST BIT(8)
+#define SPICFG_SPICLKPOL BIT(6)
+#define SPICFG_RXCLKEDGE_FALLING BIT(5)
+#define SPICFG_TXCLKEDGE_FALLING BIT(4)
+#define SPICFG_HIZSPI BIT(3)
+#define SPICFG_SPICLK_PRESCALE_MASK 0x7
+#define SPICFG_SPICLK_DIV2 0
+#define SPICFG_SPICLK_DIV4 1
+#define SPICFG_SPICLK_DIV8 2
+#define SPICFG_SPICLK_DIV16 3
+#define SPICFG_SPICLK_DIV32 4
+#define SPICFG_SPICLK_DIV64 5
+#define SPICFG_SPICLK_DIV128 6
+#define SPICFG_SPICLK_DISABLE 7
+
+/* SPICTL register bit field */
+#define SPICTL_START BIT(4)
+#define SPICTL_HIZSDO BIT(3)
+#define SPICTL_STARTWR BIT(2)
+#define SPICTL_STARTRD BIT(1)
+#define SPICTL_SPIENA BIT(0)
+
+/* SPIUSER register bit field */
+#define SPIUSER_USERMODE BIT(21)
+#define SPIUSER_INSTR_PHASE BIT(20)
+#define SPIUSER_ADDR_PHASE_MASK 0x7
+#define SPIUSER_ADDR_PHASE_OFFSET 17
+#define SPIUSER_MODE_PHASE BIT(16)
+#define SPIUSER_DUMMY_PHASE_MASK 0x3
+#define SPIUSER_DUMMY_PHASE_OFFSET 14
+#define SPIUSER_DATA_PHASE_MASK 0x3
+#define SPIUSER_DATA_PHASE_OFFSET 12
+#define SPIUSER_DATA_READ (BIT(0) << SPIUSER_DATA_PHASE_OFFSET)
+#define SPIUSER_DATA_WRITE (BIT(1) << SPIUSER_DATA_PHASE_OFFSET)
+#define SPIUSER_ADDR_TYPE_OFFSET 9
+#define SPIUSER_MODE_TYPE_OFFSET 6
+#define SPIUSER_DUMMY_TYPE_OFFSET 3
+#define SPIUSER_DATA_TYPE_OFFSET 0
+#define SPIUSER_TRANSFER_MASK 0x7
+#define SPIUSER_TRANSFER_SINGLE BIT(0)
+#define SPIUSER_TRANSFER_DUAL BIT(1)
+#define SPIUSER_TRANSFER_QUAD BIT(2)
+
+#define SPIUSER_TRANSFER_TYPE(type) ( \
+ (type << SPIUSER_ADDR_TYPE_OFFSET) | \
+ (type << SPIUSER_MODE_TYPE_OFFSET) | \
+ (type << SPIUSER_DUMMY_TYPE_OFFSET) | \
+ (type << SPIUSER_DATA_TYPE_OFFSET) \
+)
+
+/* SPIFIFOSTAT register bit field */
+#define SPIFIFOSTAT_TXEMPTY BIT(19)
+#define SPIFIFOSTAT_RXEMPTY BIT(18)
+#define SPIFIFOSTAT_TXFULL BIT(17)
+#define SPIFIFOSTAT_RXFULL BIT(16)
+#define SPIFIFOSTAT_FIFO_MASK 0xff
+#define SPIFIFOSTAT_TX_OFFSET 8
+#define SPIFIFOSTAT_RX_OFFSET 0
+
+#define SPI_FIFO_DEPTH 16
+
+/* SPIMODE register bit field */
+#define SPIMODE_MODE_OFFSET 24
+#define SPIMODE_DUMMY_OFFSET 0
+
+/* SPIARB register bit field */
+#define SPICTL_ARB_EN BIT(31)
+#define SPICTL_CSCTL1 BIT(16)
+#define SPI1_POR BIT(1)
+#define SPI0_POR BIT(0)
+
+#define RT2880_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | \
+ SPI_CS_HIGH)
+
+static atomic_t hw_reset_count = ATOMIC_INIT(0);
+
+struct rt2880_spi {
+ struct spi_master *master;
+ void __iomem *base;
+ u32 speed;
+ u16 wait_loops;
+ u16 mode;
+ struct clk *clk;
+};
+
+static inline struct rt2880_spi *spidev_to_rt2880_spi(struct spi_device *spi)
+{
+ return spi_master_get_devdata(spi->master);
+}
+
+static inline u32 rt2880_spi_read(struct rt2880_spi *rs, u32 reg)
+{
+ return ioread32(rs->base + reg);
+}
+
+static inline void rt2880_spi_write(struct rt2880_spi *rs, u32 reg,
+ const u32 val)
+{
+ iowrite32(val, rs->base + reg);
+}
+
+static inline void rt2880_spi_setbits(struct rt2880_spi *rs, u32 reg, u32 mask)
+{
+ void __iomem *addr = rs->base + reg;
+
+ iowrite32((ioread32(addr) | mask), addr);
+}
+
+static inline void rt2880_spi_clrbits(struct rt2880_spi *rs, u32 reg, u32 mask)
+{
+ void __iomem *addr = rs->base + reg;
+
+ iowrite32((ioread32(addr) & ~mask), addr);
+}
+
+static u32 rt2880_spi_baudrate_get(struct spi_device *spi, unsigned int speed)
+{
+ struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
+ u32 rate;
+ u32 prescale;
+
+ /*
+ * the supported rates are: 2, 4, 8, ... 128
+ * round up as we look for equal or less speed
+ */
+ rate = DIV_ROUND_UP(clk_get_rate(rs->clk), speed);
+ rate = roundup_pow_of_two(rate);
+
+ /* Convert the rate to SPI clock divisor value. */
+ prescale = ilog2(rate / 2);
+
+ /* some tolerance. double and add 100 */
+ rs->wait_loops = (8 * HZ * loops_per_jiffy) /
+ (clk_get_rate(rs->clk) / rate);
+ rs->wait_loops = (rs->wait_loops << 1) + 100;
+ rs->speed = speed;
+
+ dev_dbg(&spi->dev, "speed: %lu/%u, rate: %u, prescal: %u, loops: %hu\n",
+ clk_get_rate(rs->clk) / rate, speed, rate, prescale,
+ rs->wait_loops);
+
+ return prescale;
+}
+
+static u32 get_arbiter_offset(struct spi_master *master)
+{
+ u32 offset;
+
+ offset = RAMIPS_SPI_ARBITER;
+ if (master->bus_num == 1)
+ offset -= RAMIPS_SPI_DEV_OFFSET;
+
+ return offset;
+}
+
+static void rt2880_spi_set_cs(struct spi_device *spi, bool enable)
+{
+ struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
+
+ if (enable)
+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
+ else
+ rt2880_spi_clrbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
+}
+
+static int rt2880_spi_wait_ready(struct rt2880_spi *rs, int len)
+{
+ int loop = rs->wait_loops * len;
+
+ while ((rt2880_spi_read(rs, RAMIPS_SPI_STAT) & SPISTAT_BUSY) && --loop)
+ cpu_relax();
+
+ if (loop)
+ return 0;
+
+ return -ETIMEDOUT;
+}
+
+static void rt2880_dump_reg(struct spi_master *master)
+{
+ struct rt2880_spi *rs = spi_master_get_devdata(master);
+
+ dev_dbg(&master->dev, "stat: %08x, cfg: %08x, ctl: %08x, " \
+ "data: %08x, arb: %08x\n",
+ rt2880_spi_read(rs, RAMIPS_SPI_STAT),
+ rt2880_spi_read(rs, RAMIPS_SPI_CFG),
+ rt2880_spi_read(rs, RAMIPS_SPI_CTL),
+ rt2880_spi_read(rs, RAMIPS_SPI_DATA),
+ rt2880_spi_read(rs, get_arbiter_offset(master)));
+}
+
+static int rt2880_spi_transfer_one(struct spi_master *master,
+ struct spi_device *spi, struct spi_transfer *xfer)
+{
+ struct rt2880_spi *rs = spi_master_get_devdata(master);
+ unsigned len;
+ const u8 *tx = xfer->tx_buf;
+ u8 *rx = xfer->rx_buf;
+ int err = 0;
+
+ /* change clock speed */
+ if (unlikely(rs->speed != xfer->speed_hz)) {
+ u32 reg;
+ reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG);
+ reg &= ~SPICFG_SPICLK_PRESCALE_MASK;
+ reg |= rt2880_spi_baudrate_get(spi, xfer->speed_hz);
+ rt2880_spi_write(rs, RAMIPS_SPI_CFG, reg);
+ }
+
+ if (tx) {
+ len = xfer->len;
+ while (len-- > 0) {
+ rt2880_spi_write(rs, RAMIPS_SPI_DATA, *tx++);
+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTWR);
+ err = rt2880_spi_wait_ready(rs, 1);
+ if (err) {
+ dev_err(&spi->dev, "TX failed, err=%d\n", err);
+ goto out;
+ }
+ }
+ }
+
+ if (rx) {
+ len = xfer->len;
+ while (len-- > 0) {
+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTRD);
+ err = rt2880_spi_wait_ready(rs, 1);
+ if (err) {
+ dev_err(&spi->dev, "RX failed, err=%d\n", err);
+ goto out;
+ }
+ *rx++ = (u8) rt2880_spi_read(rs, RAMIPS_SPI_DATA);
+ }
+ }
+
+out:
+ return err;
+}
+
+/* copy from spi.c */
+static void spi_set_cs(struct spi_device *spi, bool enable)
+{
+ if (spi->mode & SPI_CS_HIGH)
+ enable = !enable;
+
+ if (spi->cs_gpio >= 0)
+ gpio_set_value(spi->cs_gpio, !enable);
+ else if (spi->master->set_cs)
+ spi->master->set_cs(spi, !enable);
+}
+
+static int rt2880_spi_setup(struct spi_device *spi)
+{
+ struct spi_master *master = spi->master;
+ struct rt2880_spi *rs = spi_master_get_devdata(master);
+ u32 reg, old_reg, arbit_off;
+
+ if ((spi->max_speed_hz > master->max_speed_hz) ||
+ (spi->max_speed_hz < master->min_speed_hz)) {
+ dev_err(&spi->dev, "invalide requested speed %d Hz\n",
+ spi->max_speed_hz);
+ return -EINVAL;
+ }
+
+ if (!(master->bits_per_word_mask &
+ BIT(spi->bits_per_word - 1))) {
+ dev_err(&spi->dev, "invalide bits_per_word %d\n",
+ spi->bits_per_word);
+ return -EINVAL;
+ }
+
+ /* the hardware seems can't work on mode0 force it to mode3 */
+ if ((spi->mode & (SPI_CPOL | SPI_CPHA)) == SPI_MODE_0) {
+ dev_warn(&spi->dev, "force spi mode3\n");
+ spi->mode |= SPI_MODE_3;
+ }
+
+ /* chip polarity */
+ arbit_off = get_arbiter_offset(master);
+ reg = old_reg = rt2880_spi_read(rs, arbit_off);
+ if (spi->mode & SPI_CS_HIGH) {
+ switch (master->bus_num) {
+ case 1:
+ reg |= SPI1_POR;
+ break;
+ default:
+ reg |= SPI0_POR;
+ break;
+ }
+ } else {
+ switch (master->bus_num) {
+ case 1:
+ reg &= ~SPI1_POR;
+ break;
+ default:
+ reg &= ~SPI0_POR;
+ break;
+ }
+ }
+
+ /* enable spi1 */
+ if (master->bus_num == 1)
+ reg |= SPICTL_ARB_EN;
+
+ if (reg != old_reg)
+ rt2880_spi_write(rs, arbit_off, reg);
+
+ /* deselected the spi device */
+ spi_set_cs(spi, false);
+
+ rt2880_dump_reg(master);
+
+ return 0;
+}
+
+static int rt2880_spi_prepare_message(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct rt2880_spi *rs = spi_master_get_devdata(master);
+ struct spi_device *spi = msg->spi;
+ u32 reg;
+
+ if ((rs->mode == spi->mode) && (rs->speed == spi->max_speed_hz))
+ return 0;
+
+#if 0
+ /* set spido to tri-state */
+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_HIZSDO);
+#endif
+
+ reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG);
+
+ reg &= ~(SPICFG_MSBFIRST | SPICFG_SPICLKPOL |
+ SPICFG_RXCLKEDGE_FALLING |
+ SPICFG_TXCLKEDGE_FALLING |
+ SPICFG_SPICLK_PRESCALE_MASK);
+
+ /* MSB */
+ if (!(spi->mode & SPI_LSB_FIRST))
+ reg |= SPICFG_MSBFIRST;
+
+ /* spi mode */
+ switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
+ case SPI_MODE_0:
+ reg |= SPICFG_TXCLKEDGE_FALLING;
+ break;
+ case SPI_MODE_1:
+ reg |= SPICFG_RXCLKEDGE_FALLING;
+ break;
+ case SPI_MODE_2:
+ reg |= SPICFG_SPICLKPOL | SPICFG_RXCLKEDGE_FALLING;
+ break;
+ case SPI_MODE_3:
+ reg |= SPICFG_SPICLKPOL | SPICFG_TXCLKEDGE_FALLING;
+ break;
+ }
+ rs->mode = spi->mode;
+
+#if 0
+ /* set spiclk and spiena to tri-state */
+ reg |= SPICFG_HIZSPI;
+#endif
+
+ /* clock divide */
+ reg |= rt2880_spi_baudrate_get(spi, spi->max_speed_hz);
+
+ rt2880_spi_write(rs, RAMIPS_SPI_CFG, reg);
+
+ return 0;
+}
+
+static int rt2880_spi_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct rt2880_spi *rs;
+ void __iomem *base;
+ struct resource *r;
+ struct clk *clk;
+ int ret;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "unable to get SYS clock\n");
+ return PTR_ERR(clk);
+ }
+
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ goto err_clk;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*rs));
+ if (master == NULL) {
+ dev_dbg(&pdev->dev, "master allocation failed\n");
+ ret = -ENOMEM;
+ goto err_clk;
+ }
+
+ master->dev.of_node = pdev->dev.of_node;
+ master->mode_bits = RT2880_SPI_MODE_BITS;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->min_speed_hz = clk_get_rate(clk) / 128;
+ master->max_speed_hz = clk_get_rate(clk) / 2;
+ master->flags = SPI_MASTER_HALF_DUPLEX;
+ master->setup = rt2880_spi_setup;
+ master->prepare_message = rt2880_spi_prepare_message;
+ master->set_cs = rt2880_spi_set_cs;
+ master->transfer_one = rt2880_spi_transfer_one,
+
+ dev_set_drvdata(&pdev->dev, master);
+
+ rs = spi_master_get_devdata(master);
+ rs->master = master;
+ rs->base = base;
+ rs->clk = clk;
+
+ if (atomic_inc_return(&hw_reset_count) == 1)
+ device_reset(&pdev->dev);
+
+ ret = devm_spi_register_master(&pdev->dev, master);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "devm_spi_register_master error.\n");
+ goto err_master;
+ }
+
+ return ret;
+
+err_master:
+ spi_master_put(master);
+ kfree(master);
+err_clk:
+ clk_disable_unprepare(clk);
+
+ return ret;
+}
+
+static int rt2880_spi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct rt2880_spi *rs;
+
+ master = dev_get_drvdata(&pdev->dev);
+ rs = spi_master_get_devdata(master);
+
+ clk_disable_unprepare(rs->clk);
+ atomic_dec(&hw_reset_count);
+
+ return 0;
+}
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+
+static const struct of_device_id rt2880_spi_match[] = {
+ { .compatible = "ralink,rt2880-spi" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rt2880_spi_match);
+
+static struct platform_driver rt2880_spi_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = rt2880_spi_match,
+ },
+ .probe = rt2880_spi_probe,
+ .remove = rt2880_spi_remove,
+};
+
+module_platform_driver(rt2880_spi_driver);
+
+MODULE_DESCRIPTION("Ralink SPI driver");
+MODULE_AUTHOR("Sergiy <piratfm@gmail.com>");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL");

View file

@ -0,0 +1,524 @@
From 87a5fcd57c577cd94b5b080deb98885077c13a42 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 27 Jul 2014 09:49:07 +0100
Subject: [PATCH 43/53] spi: add mt7621 support
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/spi/Kconfig | 6 +
drivers/spi/Makefile | 1 +
drivers/spi/spi-mt7621.c | 480 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 487 insertions(+)
create mode 100644 drivers/spi/spi-mt7621.c
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -569,6 +569,12 @@ config SPI_RT2880
help
This selects a driver for the Ralink RT288x/RT305x SPI Controller.
+config SPI_MT7621
+ tristate "MediaTek MT7621 SPI Controller"
+ depends on RALINK
+ help
+ This selects a driver for the MediaTek MT7621 SPI Controller.
+
config SPI_S3C24XX
tristate "Samsung S3C24XX series SPI"
depends on ARCH_S3C24XX
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -60,6 +60,7 @@ obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mp
obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o
obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o
obj-$(CONFIG_SPI_MT65XX) += spi-mt65xx.o
+obj-$(CONFIG_SPI_MT7621) += spi-mt7621.o
obj-$(CONFIG_SPI_MXS) += spi-mxs.o
obj-$(CONFIG_SPI_NUC900) += spi-nuc900.o
obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o
--- /dev/null
+++ b/drivers/spi/spi-mt7621.c
@@ -0,0 +1,483 @@
+/*
+ * spi-mt7621.c -- MediaTek MT7621 SPI controller driver
+ *
+ * Copyright (C) 2011 Sergiy <piratfm@gmail.com>
+ * Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2014-2015 Felix Fietkau <nbd@nbd.name>
+ *
+ * Some parts are based on spi-orion.c:
+ * Author: Shadi Ammouri <shadi@marvell.com>
+ * Copyright (C) 2007-2008 Marvell Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/reset.h>
+#include <linux/spi/spi.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/swab.h>
+
+#include <ralink_regs.h>
+
+#define SPI_BPW_MASK(bits) BIT((bits) - 1)
+
+#define DRIVER_NAME "spi-mt7621"
+/* in usec */
+#define RALINK_SPI_WAIT_MAX_LOOP 2000
+
+/* SPISTAT register bit field */
+#define SPISTAT_BUSY BIT(0)
+
+#define MT7621_SPI_TRANS 0x00
+#define SPITRANS_BUSY BIT(16)
+
+#define MT7621_SPI_OPCODE 0x04
+#define MT7621_SPI_DATA0 0x08
+#define MT7621_SPI_DATA4 0x18
+#define SPI_CTL_TX_RX_CNT_MASK 0xff
+#define SPI_CTL_START BIT(8)
+
+#define MT7621_SPI_POLAR 0x38
+#define MT7621_SPI_MASTER 0x28
+#define MT7621_SPI_MOREBUF 0x2c
+#define MT7621_SPI_SPACE 0x3c
+
+#define MT7621_CPHA BIT(5)
+#define MT7621_CPOL BIT(4)
+#define MT7621_LSB_FIRST BIT(3)
+
+#define RT2880_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH)
+
+struct mt7621_spi;
+
+struct mt7621_spi {
+ struct spi_master *master;
+ void __iomem *base;
+ unsigned int sys_freq;
+ unsigned int speed;
+ struct clk *clk;
+ spinlock_t lock;
+
+ struct mt7621_spi_ops *ops;
+};
+
+static inline struct mt7621_spi *spidev_to_mt7621_spi(struct spi_device *spi)
+{
+ return spi_master_get_devdata(spi->master);
+}
+
+static inline u32 mt7621_spi_read(struct mt7621_spi *rs, u32 reg)
+{
+ return ioread32(rs->base + reg);
+}
+
+static inline void mt7621_spi_write(struct mt7621_spi *rs, u32 reg, u32 val)
+{
+ iowrite32(val, rs->base + reg);
+}
+
+static void mt7621_spi_reset(struct mt7621_spi *rs, int duplex)
+{
+ u32 master = mt7621_spi_read(rs, MT7621_SPI_MASTER);
+
+ master |= 7 << 29;
+ master |= 1 << 2;
+ if (duplex)
+ master |= 1 << 10;
+ else
+ master &= ~(1 << 10);
+
+ mt7621_spi_write(rs, MT7621_SPI_MASTER, master);
+}
+
+static void mt7621_spi_set_cs(struct spi_device *spi, int enable)
+{
+ struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
+ int cs = spi->chip_select;
+ u32 polar = 0;
+
+ mt7621_spi_reset(rs, cs);
+ if (enable)
+ polar = BIT(cs);
+ mt7621_spi_write(rs, MT7621_SPI_POLAR, polar);
+}
+
+static int mt7621_spi_prepare(struct spi_device *spi, unsigned int speed)
+{
+ struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
+ u32 rate;
+ u32 reg;
+
+ dev_dbg(&spi->dev, "speed:%u\n", speed);
+
+ rate = DIV_ROUND_UP(rs->sys_freq, speed);
+ dev_dbg(&spi->dev, "rate-1:%u\n", rate);
+
+ if (rate > 4097)
+ return -EINVAL;
+
+ if (rate < 2)
+ rate = 2;
+
+ reg = mt7621_spi_read(rs, MT7621_SPI_MASTER);
+ reg &= ~(0xfff << 16);
+ reg |= (rate - 2) << 16;
+ rs->speed = speed;
+
+ reg &= ~MT7621_LSB_FIRST;
+ if (spi->mode & SPI_LSB_FIRST)
+ reg |= MT7621_LSB_FIRST;
+
+ reg &= ~(MT7621_CPHA | MT7621_CPOL);
+ switch(spi->mode & (SPI_CPOL | SPI_CPHA)) {
+ case SPI_MODE_0:
+ break;
+ case SPI_MODE_1:
+ reg |= MT7621_CPHA;
+ break;
+ case SPI_MODE_2:
+ reg |= MT7621_CPOL;
+ break;
+ case SPI_MODE_3:
+ reg |= MT7621_CPOL | MT7621_CPHA;
+ break;
+ }
+ mt7621_spi_write(rs, MT7621_SPI_MASTER, reg);
+
+ return 0;
+}
+
+static inline int mt7621_spi_wait_till_ready(struct spi_device *spi)
+{
+ struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
+ int i;
+
+ for (i = 0; i < RALINK_SPI_WAIT_MAX_LOOP; i++) {
+ u32 status;
+
+ status = mt7621_spi_read(rs, MT7621_SPI_TRANS);
+ if ((status & SPITRANS_BUSY) == 0) {
+ return 0;
+ }
+ cpu_relax();
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int mt7621_spi_transfer_half_duplex(struct spi_master *master,
+ struct spi_message *m)
+{
+ struct mt7621_spi *rs = spi_master_get_devdata(master);
+ struct spi_device *spi = m->spi;
+ unsigned int speed = spi->max_speed_hz;
+ struct spi_transfer *t = NULL;
+ int status = 0;
+ int i, len = 0;
+ int rx_len = 0;
+ u32 data[9] = { 0 };
+ u32 val;
+
+ mt7621_spi_wait_till_ready(spi);
+
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ const u8 *buf = t->tx_buf;
+
+ if (t->rx_buf)
+ rx_len += t->len;
+
+ if (!buf)
+ continue;
+
+ if (t->speed_hz < speed)
+ speed = t->speed_hz;
+
+ if (WARN_ON(len + t->len > 36)) {
+ status = -EIO;
+ goto msg_done;
+ }
+
+ for (i = 0; i < t->len; i++, len++)
+ data[len / 4] |= buf[i] << (8 * (len & 3));
+ }
+
+ if (WARN_ON(rx_len > 32)) {
+ status = -EIO;
+ goto msg_done;
+ }
+
+ if (mt7621_spi_prepare(spi, speed)) {
+ status = -EIO;
+ goto msg_done;
+ }
+ data[0] = swab32(data[0]);
+ if (len < 4)
+ data[0] >>= (4 - len) * 8;
+
+ for (i = 0; i < len; i += 4)
+ mt7621_spi_write(rs, MT7621_SPI_OPCODE + i, data[i / 4]);
+
+ val = (min_t(int, len, 4) * 8) << 24;
+ if (len > 4)
+ val |= (len - 4) * 8;
+ val |= (rx_len * 8) << 12;
+ mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val);
+
+ mt7621_spi_set_cs(spi, 1);
+
+ val = mt7621_spi_read(rs, MT7621_SPI_TRANS);
+ val |= SPI_CTL_START;
+ mt7621_spi_write(rs, MT7621_SPI_TRANS, val);
+
+ mt7621_spi_wait_till_ready(spi);
+
+ mt7621_spi_set_cs(spi, 0);
+
+ for (i = 0; i < rx_len; i += 4)
+ data[i / 4] = mt7621_spi_read(rs, MT7621_SPI_DATA0 + i);
+
+ m->actual_length = len + rx_len;
+
+ len = 0;
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ u8 *buf = t->rx_buf;
+
+ if (!buf)
+ continue;
+
+ for (i = 0; i < t->len; i++, len++)
+ buf[i] = data[len / 4] >> (8 * (len & 3));
+ }
+
+msg_done:
+ m->status = status;
+ spi_finalize_current_message(master);
+
+ return 0;
+}
+
+static int mt7621_spi_transfer_full_duplex(struct spi_master *master,
+ struct spi_message *m)
+{
+ struct mt7621_spi *rs = spi_master_get_devdata(master);
+ struct spi_device *spi = m->spi;
+ unsigned int speed = spi->max_speed_hz;
+ struct spi_transfer *t = NULL;
+ int status = 0;
+ int i, len = 0;
+ int rx_len = 0;
+ u32 data[9] = { 0 };
+ u32 val = 0;
+
+ mt7621_spi_wait_till_ready(spi);
+
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ const u8 *buf = t->tx_buf;
+
+ if (t->rx_buf)
+ rx_len += t->len;
+
+ if (!buf)
+ continue;
+
+ if (WARN_ON(len + t->len > 16)) {
+ status = -EIO;
+ goto msg_done;
+ }
+
+ for (i = 0; i < t->len; i++, len++)
+ data[len / 4] |= buf[i] << (8 * (len & 3));
+ if (speed > t->speed_hz)
+ speed = t->speed_hz;
+ }
+
+ if (WARN_ON(rx_len > 16)) {
+ status = -EIO;
+ goto msg_done;
+ }
+
+ if (mt7621_spi_prepare(spi, speed)) {
+ status = -EIO;
+ goto msg_done;
+ }
+
+ for (i = 0; i < len; i += 4)
+ mt7621_spi_write(rs, MT7621_SPI_DATA0 + i, data[i / 4]);
+
+ val |= len * 8;
+ val |= (rx_len * 8) << 12;
+ mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val);
+
+ mt7621_spi_set_cs(spi, 1);
+
+ val = mt7621_spi_read(rs, MT7621_SPI_TRANS);
+ val |= SPI_CTL_START;
+ mt7621_spi_write(rs, MT7621_SPI_TRANS, val);
+
+ mt7621_spi_wait_till_ready(spi);
+
+ mt7621_spi_set_cs(spi, 0);
+
+ for (i = 0; i < rx_len; i += 4)
+ data[i / 4] = mt7621_spi_read(rs, MT7621_SPI_DATA4 + i);
+
+ m->actual_length = rx_len;
+
+ len = 0;
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ u8 *buf = t->rx_buf;
+
+ if (!buf)
+ continue;
+
+ for (i = 0; i < t->len; i++, len++)
+ buf[i] = data[len / 4] >> (8 * (len & 3));
+ }
+
+msg_done:
+ m->status = status;
+ spi_finalize_current_message(master);
+
+ return 0;
+}
+
+static int mt7621_spi_transfer_one_message(struct spi_master *master,
+ struct spi_message *m)
+{
+ struct spi_device *spi = m->spi;
+ int cs = spi->chip_select;
+
+ if (cs)
+ return mt7621_spi_transfer_full_duplex(master, m);
+ return mt7621_spi_transfer_half_duplex(master, m);
+}
+
+static int mt7621_spi_setup(struct spi_device *spi)
+{
+ struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
+
+ if ((spi->max_speed_hz == 0) ||
+ (spi->max_speed_hz > (rs->sys_freq / 2)))
+ spi->max_speed_hz = (rs->sys_freq / 2);
+
+ if (spi->max_speed_hz < (rs->sys_freq / 4097)) {
+ dev_err(&spi->dev, "setup: requested speed is too low %d Hz\n",
+ spi->max_speed_hz);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id mt7621_spi_match[] = {
+ { .compatible = "ralink,mt7621-spi" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mt7621_spi_match);
+
+static int mt7621_spi_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct spi_master *master;
+ struct mt7621_spi *rs;
+ unsigned long flags;
+ void __iomem *base;
+ struct resource *r;
+ int status = 0;
+ struct clk *clk;
+ struct mt7621_spi_ops *ops;
+
+ match = of_match_device(mt7621_spi_match, &pdev->dev);
+ if (!match)
+ return -EINVAL;
+ ops = (struct mt7621_spi_ops *)match->data;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "unable to get SYS clock, err=%d\n",
+ status);
+ return PTR_ERR(clk);
+ }
+
+ status = clk_prepare_enable(clk);
+ if (status)
+ return status;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*rs));
+ if (master == NULL) {
+ dev_info(&pdev->dev, "master allocation failed\n");
+ return -ENOMEM;
+ }
+
+ master->mode_bits = RT2880_SPI_MODE_BITS;
+
+ master->setup = mt7621_spi_setup;
+ master->transfer_one_message = mt7621_spi_transfer_one_message;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->dev.of_node = pdev->dev.of_node;
+ master->num_chipselect = 2;
+
+ dev_set_drvdata(&pdev->dev, master);
+
+ rs = spi_master_get_devdata(master);
+ rs->base = base;
+ rs->clk = clk;
+ rs->master = master;
+ rs->sys_freq = clk_get_rate(rs->clk);
+ rs->ops = ops;
+ dev_info(&pdev->dev, "sys_freq: %u\n", rs->sys_freq);
+ spin_lock_irqsave(&rs->lock, flags);
+
+ device_reset(&pdev->dev);
+
+ mt7621_spi_reset(rs, 0);
+
+ return spi_register_master(master);
+}
+
+static int mt7621_spi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct mt7621_spi *rs;
+
+ master = dev_get_drvdata(&pdev->dev);
+ rs = spi_master_get_devdata(master);
+
+ clk_disable(rs->clk);
+ spi_unregister_master(master);
+
+ return 0;
+}
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+
+static struct platform_driver mt7621_spi_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = mt7621_spi_match,
+ },
+ .probe = mt7621_spi_probe,
+ .remove = mt7621_spi_remove,
+};
+
+module_platform_driver(mt7621_spi_driver);
+
+MODULE_DESCRIPTION("MT7621 SPI driver");
+MODULE_AUTHOR("Felix Fietkau <nbd@nbd.name>");
+MODULE_LICENSE("GPL");

View file

@ -0,0 +1,507 @@
From 723b8beaabf3c3c4b1ce69480141f1e926f3f3b2 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 27 Jul 2014 09:52:56 +0100
Subject: [PATCH 44/53] i2c: MIPS: adds ralink I2C driver
Signed-off-by: John Crispin <blogic@openwrt.org>
---
.../devicetree/bindings/i2c/i2c-ralink.txt | 27 ++
drivers/i2c/busses/Kconfig | 4 +
drivers/i2c/busses/Makefile | 1 +
drivers/i2c/busses/i2c-ralink.c | 327 ++++++++++++++++++++
4 files changed, 359 insertions(+)
create mode 100644 Documentation/devicetree/bindings/i2c/i2c-ralink.txt
create mode 100644 drivers/i2c/busses/i2c-ralink.c
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-ralink.txt
@@ -0,0 +1,27 @@
+I2C for Ralink platforms
+
+Required properties :
+- compatible : Must be "link,rt3052-i2c"
+- reg: physical base address of the controller and length of memory mapped
+ region.
+- #address-cells = <1>;
+- #size-cells = <0>;
+
+Optional properties:
+- Child nodes conforming to i2c bus binding
+
+Example :
+
+palmbus@10000000 {
+ i2c@900 {
+ compatible = "link,rt3052-i2c";
+ reg = <0x900 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ hwmon@4b {
+ compatible = "national,lm92";
+ reg = <0x4b>;
+ };
+ };
+};
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -863,6 +863,11 @@ config I2C_RK3X
This driver can also be built as a module. If so, the module will
be called i2c-rk3x.
+config I2C_RALINK
+ tristate "Ralink I2C Controller"
+ depends on RALINK && !SOC_MT7621
+ select OF_I2C
+
config HAVE_S3C2410_I2C
bool
help
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -84,6 +84,7 @@ obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o
obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o
+obj-$(CONFIG_I2C_RALINK) += i2c-ralink.o
obj-$(CONFIG_I2C_QUP) += i2c-qup.o
obj-$(CONFIG_I2C_RIIC) += i2c-riic.o
obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ralink.c
@@ -0,0 +1,435 @@
+/*
+ * drivers/i2c/busses/i2c-ralink.c
+ *
+ * Copyright (C) 2013 Steven Liu <steven_liu@mediatek.com>
+ * Copyright (C) 2016 Michael Lee <igvtee@gmail.com>
+ *
+ * Improve driver for i2cdetect from i2c-tools to detect i2c devices on the bus.
+ * (C) 2014 Sittisak <sittisaks@hotmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/reset.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#define REG_CONFIG_REG 0x00
+#define REG_CLKDIV_REG 0x04
+#define REG_DEVADDR_REG 0x08
+#define REG_ADDR_REG 0x0C
+#define REG_DATAOUT_REG 0x10
+#define REG_DATAIN_REG 0x14
+#define REG_STATUS_REG 0x18
+#define REG_STARTXFR_REG 0x1C
+#define REG_BYTECNT_REG 0x20
+
+/* REG_CONFIG_REG */
+#define I2C_ADDRLEN_OFFSET 5
+#define I2C_DEVADLEN_OFFSET 2
+#define I2C_ADDRLEN_MASK 0x3
+#define I2C_ADDR_DIS BIT(1)
+#define I2C_DEVADDR_DIS BIT(0)
+#define I2C_ADDRLEN_8 (7 << I2C_ADDRLEN_OFFSET)
+#define I2C_DEVADLEN_7 (6 << I2C_DEVADLEN_OFFSET)
+#define I2C_CONF_DEFAULT (I2C_ADDRLEN_8 | I2C_DEVADLEN_7)
+
+/* REG_CLKDIV_REG */
+#define I2C_CLKDIV_MASK 0xffff
+
+/* REG_DEVADDR_REG */
+#define I2C_DEVADDR_MASK 0x7f
+
+/* REG_ADDR_REG */
+#define I2C_ADDR_MASK 0xff
+
+/* REG_STATUS_REG */
+#define I2C_STARTERR BIT(4)
+#define I2C_ACKERR BIT(3)
+#define I2C_DATARDY BIT(2)
+#define I2C_SDOEMPTY BIT(1)
+#define I2C_BUSY BIT(0)
+
+/* REG_STARTXFR_REG */
+#define NOSTOP_CMD BIT(2)
+#define NODATA_CMD BIT(1)
+#define READ_CMD BIT(0)
+
+/* REG_BYTECNT_REG */
+#define BYTECNT_MAX 64
+#define SET_BYTECNT(x) (x - 1)
+
+/* timeout waiting for I2C devices to respond (clock streching) */
+#define TIMEOUT_MS 1000
+#define DELAY_INTERVAL_US 100
+
+struct rt_i2c {
+ void __iomem *base;
+ struct clk *clk;
+ struct device *dev;
+ struct i2c_adapter adap;
+ u32 cur_clk;
+ u32 clk_div;
+ u32 flags;
+};
+
+static void rt_i2c_w32(struct rt_i2c *i2c, u32 val, unsigned reg)
+{
+ iowrite32(val, i2c->base + reg);
+}
+
+static u32 rt_i2c_r32(struct rt_i2c *i2c, unsigned reg)
+{
+ return ioread32(i2c->base + reg);
+}
+
+static int poll_down_timeout(void __iomem *addr, u32 mask)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS);
+
+ do {
+ if (!(readl_relaxed(addr) & mask))
+ return 0;
+
+ usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50);
+ } while (time_before(jiffies, timeout));
+
+ return (readl_relaxed(addr) & mask) ? -EAGAIN : 0;
+}
+
+static int rt_i2c_wait_idle(struct rt_i2c *i2c)
+{
+ int ret;
+
+ ret = poll_down_timeout(i2c->base + REG_STATUS_REG, I2C_BUSY);
+ if (ret < 0)
+ dev_dbg(i2c->dev, "idle err(%d)\n", ret);
+
+ return ret;
+}
+
+static int poll_up_timeout(void __iomem *addr, u32 mask)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS);
+ u32 status;
+
+ do {
+ status = readl_relaxed(addr);
+
+ /* check error status */
+ if (status & I2C_STARTERR)
+ return -EAGAIN;
+ else if (status & I2C_ACKERR)
+ return -ENXIO;
+ else if (status & mask)
+ return 0;
+
+ usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50);
+ } while (time_before(jiffies, timeout));
+
+ return -ETIMEDOUT;
+}
+
+static int rt_i2c_wait_rx_done(struct rt_i2c *i2c)
+{
+ int ret;
+
+ ret = poll_up_timeout(i2c->base + REG_STATUS_REG, I2C_DATARDY);
+ if (ret < 0)
+ dev_dbg(i2c->dev, "rx err(%d)\n", ret);
+
+ return ret;
+}
+
+static int rt_i2c_wait_tx_done(struct rt_i2c *i2c)
+{
+ int ret;
+
+ ret = poll_up_timeout(i2c->base + REG_STATUS_REG, I2C_SDOEMPTY);
+ if (ret < 0)
+ dev_dbg(i2c->dev, "tx err(%d)\n", ret);
+
+ return ret;
+}
+
+static void rt_i2c_reset(struct rt_i2c *i2c)
+{
+ device_reset(i2c->adap.dev.parent);
+ barrier();
+ rt_i2c_w32(i2c, i2c->clk_div, REG_CLKDIV_REG);
+}
+
+static void rt_i2c_dump_reg(struct rt_i2c *i2c)
+{
+ dev_dbg(i2c->dev, "conf %08x, clkdiv %08x, devaddr %08x, " \
+ "addr %08x, dataout %08x, datain %08x, " \
+ "status %08x, startxfr %08x, bytecnt %08x\n",
+ rt_i2c_r32(i2c, REG_CONFIG_REG),
+ rt_i2c_r32(i2c, REG_CLKDIV_REG),
+ rt_i2c_r32(i2c, REG_DEVADDR_REG),
+ rt_i2c_r32(i2c, REG_ADDR_REG),
+ rt_i2c_r32(i2c, REG_DATAOUT_REG),
+ rt_i2c_r32(i2c, REG_DATAIN_REG),
+ rt_i2c_r32(i2c, REG_STATUS_REG),
+ rt_i2c_r32(i2c, REG_STARTXFR_REG),
+ rt_i2c_r32(i2c, REG_BYTECNT_REG));
+}
+
+static int rt_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ struct rt_i2c *i2c;
+ struct i2c_msg *pmsg;
+ unsigned char addr;
+ int i, j, ret;
+ u32 cmd;
+
+ i2c = i2c_get_adapdata(adap);
+
+ for (i = 0; i < num; i++) {
+ pmsg = &msgs[i];
+ if (i == (num - 1))
+ cmd = 0;
+ else
+ cmd = NOSTOP_CMD;
+
+ dev_dbg(i2c->dev, "addr: 0x%x, len: %d, flags: 0x%x, stop: %d\n",
+ pmsg->addr, pmsg->len, pmsg->flags,
+ (cmd == 0)? 1 : 0);
+
+ /* wait hardware idle */
+ if ((ret = rt_i2c_wait_idle(i2c)))
+ goto err_timeout;
+
+ if (pmsg->flags & I2C_M_TEN) {
+ rt_i2c_w32(i2c, I2C_CONF_DEFAULT, REG_CONFIG_REG);
+ /* 10 bits address */
+ addr = 0x78 | ((pmsg->addr >> 8) & 0x03);
+ rt_i2c_w32(i2c, addr & I2C_DEVADDR_MASK,
+ REG_DEVADDR_REG);
+ rt_i2c_w32(i2c, pmsg->addr & I2C_ADDR_MASK,
+ REG_ADDR_REG);
+ } else {
+ rt_i2c_w32(i2c, I2C_CONF_DEFAULT | I2C_ADDR_DIS,
+ REG_CONFIG_REG);
+ /* 7 bits address */
+ rt_i2c_w32(i2c, pmsg->addr & I2C_DEVADDR_MASK,
+ REG_DEVADDR_REG);
+ }
+
+ /* buffer length */
+ if (pmsg->len == 0)
+ cmd |= NODATA_CMD;
+ else
+ rt_i2c_w32(i2c, SET_BYTECNT(pmsg->len),
+ REG_BYTECNT_REG);
+
+ j = 0;
+ if (pmsg->flags & I2C_M_RD) {
+ cmd |= READ_CMD;
+ /* start transfer */
+ barrier();
+ rt_i2c_w32(i2c, cmd, REG_STARTXFR_REG);
+ do {
+ /* wait */
+ if ((ret = rt_i2c_wait_rx_done(i2c)))
+ goto err_timeout;
+ /* read data */
+ if (pmsg->len)
+ pmsg->buf[j] = rt_i2c_r32(i2c,
+ REG_DATAIN_REG);
+ j++;
+ } while (j < pmsg->len);
+ } else {
+ do {
+ /* write data */
+ if (pmsg->len)
+ rt_i2c_w32(i2c, pmsg->buf[j],
+ REG_DATAOUT_REG);
+ /* start transfer */
+ if (j == 0) {
+ barrier();
+ rt_i2c_w32(i2c, cmd, REG_STARTXFR_REG);
+ }
+ /* wait */
+ if ((ret = rt_i2c_wait_tx_done(i2c)))
+ goto err_timeout;
+ j++;
+ } while (j < pmsg->len);
+ }
+ }
+ /* the return value is number of executed messages */
+ ret = i;
+
+ return ret;
+
+err_timeout:
+ rt_i2c_dump_reg(i2c);
+ rt_i2c_reset(i2c);
+ return ret;
+}
+
+static u32 rt_i2c_func(struct i2c_adapter *a)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm rt_i2c_algo = {
+ .master_xfer = rt_i2c_master_xfer,
+ .functionality = rt_i2c_func,
+};
+
+static const struct of_device_id i2c_rt_dt_ids[] = {
+ { .compatible = "ralink,rt2880-i2c" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, i2c_rt_dt_ids);
+
+static struct i2c_adapter_quirks rt_i2c_quirks = {
+ .max_write_len = BYTECNT_MAX,
+ .max_read_len = BYTECNT_MAX,
+};
+
+static int rt_i2c_init(struct rt_i2c *i2c)
+{
+ u32 reg;
+
+ /* i2c_sclk = periph_clk / ((2 * clk_div) + 5) */
+ i2c->clk_div = (clk_get_rate(i2c->clk) - (5 * i2c->cur_clk)) /
+ (2 * i2c->cur_clk);
+ if (i2c->clk_div < 8)
+ i2c->clk_div = 8;
+ if (i2c->clk_div > I2C_CLKDIV_MASK)
+ i2c->clk_div = I2C_CLKDIV_MASK;
+
+ /* check support combinde/repeated start message */
+ rt_i2c_w32(i2c, NOSTOP_CMD, REG_STARTXFR_REG);
+ reg = rt_i2c_r32(i2c, REG_STARTXFR_REG) & NOSTOP_CMD;
+
+ rt_i2c_reset(i2c);
+
+ return reg;
+}
+
+static int rt_i2c_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct rt_i2c *i2c;
+ struct i2c_adapter *adap;
+ const struct of_device_id *match;
+ int ret, restart;
+
+ match = of_match_device(i2c_rt_dt_ids, &pdev->dev);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no memory resource found\n");
+ return -ENODEV;
+ }
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(struct rt_i2c), GFP_KERNEL);
+ if (!i2c) {
+ dev_err(&pdev->dev, "failed to allocate i2c_adapter\n");
+ return -ENOMEM;
+ }
+
+ i2c->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(i2c->base))
+ return PTR_ERR(i2c->base);
+
+ i2c->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2c->clk)) {
+ dev_err(&pdev->dev, "no clock defined\n");
+ return -ENODEV;
+ }
+ clk_prepare_enable(i2c->clk);
+ i2c->dev = &pdev->dev;
+
+ if (of_property_read_u32(pdev->dev.of_node,
+ "clock-frequency", &i2c->cur_clk))
+ i2c->cur_clk = 100000;
+
+ adap = &i2c->adap;
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ adap->algo = &rt_i2c_algo;
+ adap->retries = 3;
+ adap->dev.parent = &pdev->dev;
+ i2c_set_adapdata(adap, i2c);
+ adap->dev.of_node = pdev->dev.of_node;
+ strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name));
+ adap->quirks = &rt_i2c_quirks;
+
+ platform_set_drvdata(pdev, i2c);
+
+ restart = rt_i2c_init(i2c);
+
+ ret = i2c_add_adapter(adap);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to add adapter\n");
+ clk_disable_unprepare(i2c->clk);
+ return ret;
+ }
+
+ dev_info(&pdev->dev, "clock %uKHz, re-start %ssupport\n",
+ i2c->cur_clk/1000, restart ? "" : "not ");
+
+ return ret;
+}
+
+static int rt_i2c_remove(struct platform_device *pdev)
+{
+ struct rt_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adap);
+ clk_disable_unprepare(i2c->clk);
+
+ return 0;
+}
+
+static struct platform_driver rt_i2c_driver = {
+ .probe = rt_i2c_probe,
+ .remove = rt_i2c_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "i2c-ralink",
+ .of_match_table = i2c_rt_dt_ids,
+ },
+};
+
+static int __init i2c_rt_init (void)
+{
+ return platform_driver_register(&rt_i2c_driver);
+}
+subsys_initcall(i2c_rt_init);
+
+static void __exit i2c_rt_exit (void)
+{
+ platform_driver_unregister(&rt_i2c_driver);
+}
+module_exit(i2c_rt_exit);
+
+MODULE_AUTHOR("Steven Liu <steven_liu@mediatek.com>");
+MODULE_DESCRIPTION("Ralink I2c host driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:Ralink-I2C");

View file

@ -0,0 +1,473 @@
From d5c54ff3d1db0a4348fa04d8e78f3bf6063e3afc Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Mon, 7 Dec 2015 17:21:27 +0100
Subject: [PATCH 45/53] i2c: add mt7621 driver
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/i2c/busses/Kconfig | 4 +
drivers/i2c/busses/Makefile | 1 +
drivers/i2c/busses/i2c-mt7621.c | 303 +++++++++++++++++++++++++++++++++++++++
3 files changed, 308 insertions(+)
create mode 100644 drivers/i2c/busses/i2c-mt7621.c
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -868,6 +868,11 @@ config I2C_RALINK
depends on RALINK && !SOC_MT7621
select OF_I2C
+config I2C_MT7621
+ tristate "MT7621/MT7628 I2C Controller"
+ depends on RALINK && (SOC_MT7620 || SOC_MT7621)
+ select OF_I2C
+
config HAVE_S3C2410_I2C
bool
help
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -85,6 +85,7 @@ obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o
obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o
obj-$(CONFIG_I2C_RALINK) += i2c-ralink.o
+obj-$(CONFIG_I2C_MT7621) += i2c-mt7621.o
obj-$(CONFIG_I2C_QUP) += i2c-qup.o
obj-$(CONFIG_I2C_RIIC) += i2c-riic.o
obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o
--- /dev/null
+++ b/drivers/i2c/busses/i2c-mt7621.c
@@ -0,0 +1,433 @@
+/*
+ * drivers/i2c/busses/i2c-mt7621.c
+ *
+ * Copyright (C) 2013 Steven Liu <steven_liu@mediatek.com>
+ * Copyright (C) 2016 Michael Lee <igvtee@gmail.com>
+ *
+ * Improve driver for i2cdetect from i2c-tools to detect i2c devices on the bus.
+ * (C) 2014 Sittisak <sittisaks@hotmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/reset.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#define REG_SM0CFG0 0x08
+#define REG_SM0DOUT 0x10
+#define REG_SM0DIN 0x14
+#define REG_SM0ST 0x18
+#define REG_SM0AUTO 0x1C
+#define REG_SM0CFG1 0x20
+#define REG_SM0CFG2 0x28
+#define REG_SM0CTL0 0x40
+#define REG_SM0CTL1 0x44
+#define REG_SM0D0 0x50
+#define REG_SM0D1 0x54
+#define REG_PINTEN 0x5C
+#define REG_PINTST 0x60
+#define REG_PINTCL 0x64
+
+/* REG_SM0CFG0 */
+#define I2C_DEVADDR_MASK 0x7f
+
+/* REG_SM0ST */
+#define I2C_DATARDY BIT(2)
+#define I2C_SDOEMPTY BIT(1)
+#define I2C_BUSY BIT(0)
+
+/* REG_SM0AUTO */
+#define READ_CMD BIT(0)
+
+/* REG_SM0CFG1 */
+#define BYTECNT_MAX 64
+#define SET_BYTECNT(x) (x - 1)
+
+/* REG_SM0CFG2 */
+#define AUTOMODE_EN BIT(0)
+
+/* REG_SM0CTL0 */
+#define ODRAIN_HIGH_SM0 BIT(31)
+#define VSYNC_SHIFT 28
+#define VSYNC_MASK 0x3
+#define VSYNC_PULSE (0x1 << VSYNC_SHIFT)
+#define VSYNC_RISING (0x2 << VSYNC_SHIFT)
+#define CLK_DIV_SHIFT 16
+#define CLK_DIV_MASK 0xfff
+#define DEG_CNT_SHIFT 8
+#define DEG_CNT_MASK 0xff
+#define WAIT_HIGH BIT(6)
+#define DEG_EN BIT(5)
+#define CS_STATUA BIT(4)
+#define SCL_STATUS BIT(3)
+#define SDA_STATUS BIT(2)
+#define SM0_EN BIT(1)
+#define SCL_STRECH BIT(0)
+
+/* REG_SM0CTL1 */
+#define ACK_SHIFT 16
+#define ACK_MASK 0xff
+#define PGLEN_SHIFT 8
+#define PGLEN_MASK 0x7
+#define SM0_MODE_SHIFT 4
+#define SM0_MODE_MASK 0x7
+#define SM0_MODE_START 0x1
+#define SM0_MODE_WRITE 0x2
+#define SM0_MODE_STOP 0x3
+#define SM0_MODE_READ_NACK 0x4
+#define SM0_MODE_READ_ACK 0x5
+#define SM0_TRI_BUSY BIT(0)
+
+/* timeout waiting for I2C devices to respond (clock streching) */
+#define TIMEOUT_MS 1000
+#define DELAY_INTERVAL_US 100
+
+struct mtk_i2c {
+ void __iomem *base;
+ struct clk *clk;
+ struct device *dev;
+ struct i2c_adapter adap;
+ u32 cur_clk;
+ u32 clk_div;
+ u32 flags;
+};
+
+static void mtk_i2c_w32(struct mtk_i2c *i2c, u32 val, unsigned reg)
+{
+ iowrite32(val, i2c->base + reg);
+}
+
+static u32 mtk_i2c_r32(struct mtk_i2c *i2c, unsigned reg)
+{
+ return ioread32(i2c->base + reg);
+}
+
+static int poll_down_timeout(void __iomem *addr, u32 mask)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS);
+
+ do {
+ if (!(readl_relaxed(addr) & mask))
+ return 0;
+
+ usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50);
+ } while (time_before(jiffies, timeout));
+
+ return (readl_relaxed(addr) & mask) ? -EAGAIN : 0;
+}
+
+static int mtk_i2c_wait_idle(struct mtk_i2c *i2c)
+{
+ int ret;
+
+ ret = poll_down_timeout(i2c->base + REG_SM0ST, I2C_BUSY);
+ if (ret < 0)
+ dev_dbg(i2c->dev, "idle err(%d)\n", ret);
+
+ return ret;
+}
+
+static int poll_up_timeout(void __iomem *addr, u32 mask)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS);
+ u32 status;
+
+ do {
+ status = readl_relaxed(addr);
+ if (status & mask)
+ return 0;
+ usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50);
+ } while (time_before(jiffies, timeout));
+
+ return -ETIMEDOUT;
+}
+
+static int mtk_i2c_wait_rx_done(struct mtk_i2c *i2c)
+{
+ int ret;
+
+ ret = poll_up_timeout(i2c->base + REG_SM0ST, I2C_DATARDY);
+ if (ret < 0)
+ dev_dbg(i2c->dev, "rx err(%d)\n", ret);
+
+ return ret;
+}
+
+static int mtk_i2c_wait_tx_done(struct mtk_i2c *i2c)
+{
+ int ret;
+
+ ret = poll_up_timeout(i2c->base + REG_SM0ST, I2C_SDOEMPTY);
+ if (ret < 0)
+ dev_dbg(i2c->dev, "tx err(%d)\n", ret);
+
+ return ret;
+}
+
+static void mtk_i2c_reset(struct mtk_i2c *i2c)
+{
+ u32 reg;
+ device_reset(i2c->adap.dev.parent);
+ barrier();
+
+ /* ctrl0 */
+ reg = ODRAIN_HIGH_SM0 | VSYNC_PULSE | (i2c->clk_div << CLK_DIV_SHIFT) |
+ WAIT_HIGH | SM0_EN;
+ mtk_i2c_w32(i2c, reg, REG_SM0CTL0);
+
+ /* auto mode */
+ mtk_i2c_w32(i2c, AUTOMODE_EN, REG_SM0CFG2);
+}
+
+static void mtk_i2c_dump_reg(struct mtk_i2c *i2c)
+{
+ dev_dbg(i2c->dev, "cfg0 %08x, dout %08x, din %08x, " \
+ "status %08x, auto %08x, cfg1 %08x, " \
+ "cfg2 %08x, ctl0 %08x, ctl1 %08x\n",
+ mtk_i2c_r32(i2c, REG_SM0CFG0),
+ mtk_i2c_r32(i2c, REG_SM0DOUT),
+ mtk_i2c_r32(i2c, REG_SM0DIN),
+ mtk_i2c_r32(i2c, REG_SM0ST),
+ mtk_i2c_r32(i2c, REG_SM0AUTO),
+ mtk_i2c_r32(i2c, REG_SM0CFG1),
+ mtk_i2c_r32(i2c, REG_SM0CFG2),
+ mtk_i2c_r32(i2c, REG_SM0CTL0),
+ mtk_i2c_r32(i2c, REG_SM0CTL1));
+}
+
+static int mtk_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ struct mtk_i2c *i2c;
+ struct i2c_msg *pmsg;
+ int i, j, ret;
+ u32 cmd;
+
+ i2c = i2c_get_adapdata(adap);
+
+ for (i = 0; i < num; i++) {
+ pmsg = &msgs[i];
+ cmd = 0;
+
+ dev_dbg(i2c->dev, "addr: 0x%x, len: %d, flags: 0x%x\n",
+ pmsg->addr, pmsg->len, pmsg->flags);
+
+ /* wait hardware idle */
+ if ((ret = mtk_i2c_wait_idle(i2c)))
+ goto err_timeout;
+
+ if (pmsg->flags & I2C_M_TEN) {
+ dev_dbg(i2c->dev, "10 bits addr not supported\n");
+ return -EINVAL;
+ } else {
+ /* 7 bits address */
+ mtk_i2c_w32(i2c, pmsg->addr & I2C_DEVADDR_MASK,
+ REG_SM0CFG0);
+ }
+
+ /* buffer length */
+ if (pmsg->len == 0) {
+ dev_dbg(i2c->dev, "length is 0\n");
+ return -EINVAL;
+ } else
+ mtk_i2c_w32(i2c, SET_BYTECNT(pmsg->len),
+ REG_SM0CFG1);
+
+ j = 0;
+ if (pmsg->flags & I2C_M_RD) {
+ cmd |= READ_CMD;
+ /* start transfer */
+ barrier();
+ mtk_i2c_w32(i2c, cmd, REG_SM0AUTO);
+ do {
+ /* wait */
+ if ((ret = mtk_i2c_wait_rx_done(i2c)))
+ goto err_timeout;
+ /* read data */
+ if (pmsg->len)
+ pmsg->buf[j] = mtk_i2c_r32(i2c,
+ REG_SM0DIN);
+ j++;
+ } while (j < pmsg->len);
+ } else {
+ do {
+ /* write data */
+ if (pmsg->len)
+ mtk_i2c_w32(i2c, pmsg->buf[j],
+ REG_SM0DOUT);
+ /* start transfer */
+ if (j == 0) {
+ barrier();
+ mtk_i2c_w32(i2c, cmd, REG_SM0AUTO);
+ }
+ /* wait */
+ if ((ret = mtk_i2c_wait_tx_done(i2c)))
+ goto err_timeout;
+ j++;
+ } while (j < pmsg->len);
+ }
+ }
+ /* the return value is number of executed messages */
+ ret = i;
+
+ return ret;
+
+err_timeout:
+ mtk_i2c_dump_reg(i2c);
+ mtk_i2c_reset(i2c);
+ return ret;
+}
+
+static u32 mtk_i2c_func(struct i2c_adapter *a)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm mtk_i2c_algo = {
+ .master_xfer = mtk_i2c_master_xfer,
+ .functionality = mtk_i2c_func,
+};
+
+static const struct of_device_id i2c_mtk_dt_ids[] = {
+ { .compatible = "mediatek,mt7621-i2c" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, i2c_mtk_dt_ids);
+
+static struct i2c_adapter_quirks mtk_i2c_quirks = {
+ .max_write_len = BYTECNT_MAX,
+ .max_read_len = BYTECNT_MAX,
+};
+
+static void mtk_i2c_init(struct mtk_i2c *i2c)
+{
+ i2c->clk_div = clk_get_rate(i2c->clk) / i2c->cur_clk;
+ if (i2c->clk_div > CLK_DIV_MASK)
+ i2c->clk_div = CLK_DIV_MASK;
+
+ mtk_i2c_reset(i2c);
+}
+
+static int mtk_i2c_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct mtk_i2c *i2c;
+ struct i2c_adapter *adap;
+ const struct of_device_id *match;
+ int ret;
+
+ match = of_match_device(i2c_mtk_dt_ids, &pdev->dev);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no memory resource found\n");
+ return -ENODEV;
+ }
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(struct mtk_i2c), GFP_KERNEL);
+ if (!i2c) {
+ dev_err(&pdev->dev, "failed to allocate i2c_adapter\n");
+ return -ENOMEM;
+ }
+
+ i2c->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(i2c->base))
+ return PTR_ERR(i2c->base);
+
+ i2c->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2c->clk)) {
+ dev_err(&pdev->dev, "no clock defined\n");
+ return -ENODEV;
+ }
+ clk_prepare_enable(i2c->clk);
+ i2c->dev = &pdev->dev;
+
+ if (of_property_read_u32(pdev->dev.of_node,
+ "clock-frequency", &i2c->cur_clk))
+ i2c->cur_clk = 100000;
+
+ adap = &i2c->adap;
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ adap->algo = &mtk_i2c_algo;
+ adap->retries = 3;
+ adap->dev.parent = &pdev->dev;
+ i2c_set_adapdata(adap, i2c);
+ adap->dev.of_node = pdev->dev.of_node;
+ strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name));
+ adap->quirks = &mtk_i2c_quirks;
+
+ platform_set_drvdata(pdev, i2c);
+
+ mtk_i2c_init(i2c);
+
+ ret = i2c_add_adapter(adap);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to add adapter\n");
+ clk_disable_unprepare(i2c->clk);
+ return ret;
+ }
+
+ dev_info(&pdev->dev, "clock %uKHz, re-start not support\n",
+ i2c->cur_clk/1000);
+
+ return ret;
+}
+
+static int mtk_i2c_remove(struct platform_device *pdev)
+{
+ struct mtk_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adap);
+ clk_disable_unprepare(i2c->clk);
+
+ return 0;
+}
+
+static struct platform_driver mtk_i2c_driver = {
+ .probe = mtk_i2c_probe,
+ .remove = mtk_i2c_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "i2c-mt7621",
+ .of_match_table = i2c_mtk_dt_ids,
+ },
+};
+
+static int __init i2c_mtk_init (void)
+{
+ return platform_driver_register(&mtk_i2c_driver);
+}
+subsys_initcall(i2c_mtk_init);
+
+static void __exit i2c_mtk_exit (void)
+{
+ platform_driver_unregister(&mtk_i2c_driver);
+}
+module_exit(i2c_mtk_exit);
+
+MODULE_AUTHOR("Steven Liu <steven_liu@mediatek.com>");
+MODULE_DESCRIPTION("MT7621 I2c host driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:MT7621-I2C");

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,22 @@
From a7eb46e0ea4a11e4dfb56ab129bf816d1059a6c5 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Mon, 7 Dec 2015 17:31:08 +0100
Subject: [PATCH 51/53] serial: add ugly custom baud rate hack
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/tty/serial/serial_core.c | 3 +++
1 file changed, 3 insertions(+)
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -411,6 +411,9 @@ uart_get_baud_rate(struct uart_port *por
break;
}
+ if (tty_termios_baud_rate(termios) == 2500000)
+ return 250000;
+
for (try = 0; try < 2; try++) {
baud = tty_termios_baud_rate(termios);

View file

@ -0,0 +1,217 @@
From fc8f96309c21c1bc3276427309cd7d361347d66e Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Mon, 7 Dec 2015 17:16:50 +0100
Subject: [PATCH 52/53] pwm: add mediatek support
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/pwm/Kconfig | 9 +++
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-mediatek.c | 173 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 183 insertions(+)
create mode 100644 drivers/pwm/pwm-mediatek.c
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -302,6 +302,15 @@ config PWM_MEDIATEK
To compile this driver as a module, choose M here: the module
will be called pwm-mediatek.
+config PWM_MEDIATEK_RAMIPS
+ tristate "Mediatek PWM support"
+ depends on RALINK && OF
+ help
+ Generic PWM framework driver for Mediatek ARM SoC.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-mxs.
+
config PWM_MXS
tristate "Freescale MXS PWM support"
depends on ARCH_MXS && OF
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-p
obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o
obj-$(CONFIG_PWM_MESON) += pwm-meson.o
obj-$(CONFIG_PWM_MEDIATEK) += pwm-mediatek.o
+obj-$(CONFIG_PWM_MEDIATEK_RAMIPS) += pwm-mediatek-ramips.o
obj-$(CONFIG_PWM_MTK_DISP) += pwm-mtk-disp.o
obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o
--- /dev/null
+++ b/drivers/pwm/pwm-mediatek-ramips.c
@@ -0,0 +1,173 @@
+/*
+ * Mediatek Pulse Width Modulator driver
+ *
+ * Copyright (C) 2015 John Crispin <blogic@openwrt.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#define NUM_PWM 4
+
+/* PWM registers and bits definitions */
+#define PWMCON 0x00
+#define PWMHDUR 0x04
+#define PWMLDUR 0x08
+#define PWMGDUR 0x0c
+#define PWMWAVENUM 0x28
+#define PWMDWIDTH 0x2c
+#define PWMTHRES 0x30
+
+/**
+ * struct mtk_pwm_chip - struct representing pwm chip
+ *
+ * @mmio_base: base address of pwm chip
+ * @chip: linux pwm chip representation
+ */
+struct mtk_pwm_chip {
+ void __iomem *mmio_base;
+ struct pwm_chip chip;
+};
+
+static inline struct mtk_pwm_chip *to_mtk_pwm_chip(struct pwm_chip *chip)
+{
+ return container_of(chip, struct mtk_pwm_chip, chip);
+}
+
+static inline u32 mtk_pwm_readl(struct mtk_pwm_chip *chip, unsigned int num,
+ unsigned long offset)
+{
+ return ioread32(chip->mmio_base + 0x10 + (num * 0x40) + offset);
+}
+
+static inline void mtk_pwm_writel(struct mtk_pwm_chip *chip,
+ unsigned int num, unsigned long offset,
+ unsigned long val)
+{
+ iowrite32(val, chip->mmio_base + 0x10 + (num * 0x40) + offset);
+}
+
+static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+ int duty_ns, int period_ns)
+{
+ struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
+ u32 resolution = 100 / 4;
+ u32 clkdiv = 0;
+
+ while (period_ns / resolution > 8191) {
+ clkdiv++;
+ resolution *= 2;
+ }
+
+ if (clkdiv > 7)
+ return -1;
+
+ mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | BIT(3) | clkdiv);
+ mtk_pwm_writel(pc, pwm->hwpwm, PWMDWIDTH, period_ns / resolution);
+ mtk_pwm_writel(pc, pwm->hwpwm, PWMTHRES, duty_ns / resolution);
+ return 0;
+}
+
+static int mtk_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
+ u32 val;
+
+ val = ioread32(pc->mmio_base);
+ val |= BIT(pwm->hwpwm);
+ iowrite32(val, pc->mmio_base);
+
+ return 0;
+}
+
+static void mtk_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
+ u32 val;
+
+ val = ioread32(pc->mmio_base);
+ val &= ~BIT(pwm->hwpwm);
+ iowrite32(val, pc->mmio_base);
+}
+
+static const struct pwm_ops mtk_pwm_ops = {
+ .config = mtk_pwm_config,
+ .enable = mtk_pwm_enable,
+ .disable = mtk_pwm_disable,
+ .owner = THIS_MODULE,
+};
+
+static int mtk_pwm_probe(struct platform_device *pdev)
+{
+ struct mtk_pwm_chip *pc;
+ struct resource *r;
+ int ret;
+
+ pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
+ if (!pc)
+ return -ENOMEM;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pc->mmio_base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(pc->mmio_base))
+ return PTR_ERR(pc->mmio_base);
+
+ platform_set_drvdata(pdev, pc);
+
+ pc->chip.dev = &pdev->dev;
+ pc->chip.ops = &mtk_pwm_ops;
+ pc->chip.base = -1;
+ pc->chip.npwm = NUM_PWM;
+
+ ret = pwmchip_add(&pc->chip);
+ if (ret < 0)
+ dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
+
+ return ret;
+}
+
+static int mtk_pwm_remove(struct platform_device *pdev)
+{
+ struct mtk_pwm_chip *pc = platform_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < NUM_PWM; i++)
+ pwm_disable(&pc->chip.pwms[i]);
+
+ return pwmchip_remove(&pc->chip);
+}
+
+static const struct of_device_id mtk_pwm_of_match[] = {
+ { .compatible = "mediatek,mt7628-pwm" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, mtk_pwm_of_match);
+
+static struct platform_driver mtk_pwm_driver = {
+ .driver = {
+ .name = "mtk-pwm",
+ .owner = THIS_MODULE,
+ .of_match_table = mtk_pwm_of_match,
+ },
+ .probe = mtk_pwm_probe,
+ .remove = mtk_pwm_remove,
+};
+
+module_platform_driver(mtk_pwm_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_ALIAS("platform:mtk-pwm");

View file

@ -0,0 +1,214 @@
mtd: spi-nor: add support for switching between 3-byte and 4-byte addressing on w25q256 flash
On some devices the flash chip needs to be in 3-byte addressing mode during
reboot, otherwise the boot loader will fail to start.
This mode however does not allow regular reads/writes onto the upper 16M
half. W25Q256 has separate read commands for reading from >16M, however
it does not have any separate write commands.
This patch changes the code to leave the chip in 3-byte mode most of the
time and only switch during erase/write cycles that go to >16M
addresses.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -89,6 +89,10 @@ struct flash_info {
#define NO_CHIP_ERASE BIT(12) /* Chip does not support chip erase */
#define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */
#define USE_CLSR BIT(14) /* use CLSR command */
+#define SPI_NOR_4B_READ_OP BIT(15) /*
+ * Like SPI_NOR_4B_OPCODES, but for read
+ * op code only.
+ */
};
#define JEDEC_MFR(info) ((info)->id[0])
@@ -240,6 +244,15 @@ static inline u8 spi_nor_convert_3to4_er
ARRAY_SIZE(spi_nor_3to4_erase));
}
+static void spi_nor_set_4byte_read(struct spi_nor *nor,
+ const struct flash_info *info)
+{
+ nor->addr_width = 3;
+ nor->ext_addr = 0;
+ nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode);
+ nor->flags |= SNOR_F_4B_EXT_ADDR;
+}
+
static void spi_nor_set_4byte_opcodes(struct spi_nor *nor,
const struct flash_info *info)
{
@@ -467,6 +480,36 @@ static int spi_nor_erase_sector(struct s
return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width);
}
+static int spi_nor_check_ext_addr(struct spi_nor *nor, u32 addr)
+{
+ bool ext_addr;
+ int ret;
+ u8 cmd;
+
+ if (!(nor->flags & SNOR_F_4B_EXT_ADDR))
+ return 0;
+
+ ext_addr = !!(addr & 0xff000000);
+ if (nor->ext_addr == ext_addr)
+ return 0;
+
+ cmd = ext_addr ? SPINOR_OP_EN4B : SPINOR_OP_EX4B;
+ write_enable(nor);
+ ret = nor->write_reg(nor, cmd, NULL, 0);
+ if (ret)
+ return ret;
+
+ cmd = 0;
+ ret = nor->write_reg(nor, SPINOR_OP_WREAR, &cmd, 1);
+ if (ret)
+ return ret;
+
+ nor->addr_width = 3 + ext_addr;
+ nor->ext_addr = ext_addr;
+ write_disable(nor);
+ return 0;
+}
+
/*
* Erase an address range on the nor chip. The address range may extend
* one or more erase sectors. Return an error is there is a problem erasing.
@@ -492,6 +535,10 @@ static int spi_nor_erase(struct mtd_info
if (ret)
return ret;
+ ret = spi_nor_check_ext_addr(nor, addr + len);
+ if (ret)
+ return ret;
+
/* whole-chip erase? */
if (len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) {
unsigned long timeout;
@@ -542,6 +589,7 @@ static int spi_nor_erase(struct mtd_info
write_disable(nor);
erase_err:
+ spi_nor_check_ext_addr(nor, 0);
spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
instr->state = ret ? MTD_ERASE_FAILED : MTD_ERASE_DONE;
@@ -834,7 +882,9 @@ static int spi_nor_lock(struct mtd_info
if (ret)
return ret;
+ spi_nor_check_ext_addr(nor, ofs + len);
ret = nor->flash_lock(nor, ofs, len);
+ spi_nor_check_ext_addr(nor, 0);
spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK);
return ret;
@@ -849,7 +899,9 @@ static int spi_nor_unlock(struct mtd_inf
if (ret)
return ret;
+ spi_nor_check_ext_addr(nor, ofs + len);
ret = nor->flash_unlock(nor, ofs, len);
+ spi_nor_check_ext_addr(nor, 0);
spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK);
return ret;
@@ -1164,7 +1216,7 @@ static const struct flash_info spi_nor_i
{ "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
- { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_READ_OP) },
{ "w25m512jv", INFO(0xef7119, 0, 64 * 1024, 1024,
SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_DUAL_READ) },
@@ -1220,6 +1272,9 @@ static int spi_nor_read(struct mtd_info
if (ret)
return ret;
+ if (nor->flags & SNOR_F_4B_EXT_ADDR)
+ nor->addr_width = 4;
+
while (len) {
loff_t addr = from;
@@ -1244,6 +1299,18 @@ static int spi_nor_read(struct mtd_info
ret = 0;
read_err:
+ if (nor->flags & SNOR_F_4B_EXT_ADDR) {
+ u8 val = 0;
+
+ if ((from + len) & 0xff000000) {
+ write_enable(nor);
+ nor->write_reg(nor, SPINOR_OP_WREAR, &val, 1);
+ write_disable(nor);
+ }
+
+ nor->addr_width = 3;
+ }
+
spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ);
return ret;
}
@@ -1345,6 +1412,10 @@ static int spi_nor_write(struct mtd_info
if (ret)
return ret;
+ ret = spi_nor_check_ext_addr(nor, to + len);
+ if (ret < 0)
+ return ret;
+
for (i = 0; i < len; ) {
ssize_t written;
loff_t addr = to + i;
@@ -1392,6 +1463,7 @@ static int spi_nor_write(struct mtd_info
}
write_err:
+ spi_nor_check_ext_addr(nor, 0);
spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
return ret;
}
@@ -2808,8 +2880,10 @@ int spi_nor_scan(struct spi_nor *nor, co
} else if (mtd->size > 0x1000000) {
/* enable 4-byte addressing if the device exceeds 16MiB */
nor->addr_width = 4;
- if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
- info->flags & SPI_NOR_4B_OPCODES)
+ if (info->flags & SPI_NOR_4B_READ_OP)
+ spi_nor_set_4byte_read(nor, info);
+ else if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
+ info->flags & SPI_NOR_4B_OPCODES)
spi_nor_set_4byte_opcodes(nor, info);
else
set_4byte(nor, info, 1);
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -102,6 +102,7 @@
/* Used for Macronix and Winbond flashes. */
#define SPINOR_OP_EN4B 0xb7 /* Enter 4-byte mode */
#define SPINOR_OP_EX4B 0xe9 /* Exit 4-byte mode */
+#define SPINOR_OP_WREAR 0xc5 /* Write extended address register */
/* Used for Spansion flashes only. */
#define SPINOR_OP_BRWR 0x17 /* Bank register write */
@@ -229,6 +230,7 @@ enum spi_nor_option_flags {
SNOR_F_S3AN_ADDR_DEFAULT = BIT(3),
SNOR_F_READY_XSR_RDY = BIT(4),
SNOR_F_USE_CLSR = BIT(5),
+ SNOR_F_4B_EXT_ADDR = BIT(6),
};
/**
@@ -280,6 +282,7 @@ struct spi_nor {
enum spi_nor_protocol reg_proto;
bool sst_write_second;
u32 flags;
+ u8 ext_addr;
u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE];
int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);

View file

@ -0,0 +1,124 @@
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1468,6 +1468,67 @@ write_err:
return ret;
}
+static int spi_nor_chunked_write(struct mtd_info *mtd, loff_t _to, size_t _len,
+ size_t *_retlen, const u_char *_buf)
+{
+ struct spi_nor *nor = mtd_to_spi_nor(mtd);
+ u32 addr_width = nor->addr_width + !!(nor->flags & SNOR_F_4B_EXT_ADDR);
+ int chunk_size;
+ int retlen = 0;
+ int ret;
+
+ chunk_size = nor->chunk_size;
+ if (!chunk_size)
+ chunk_size = _len;
+
+ if (addr_width > 3)
+ chunk_size -= addr_width - 3;
+
+ while (retlen < _len) {
+ size_t len = min_t(int, chunk_size, _len - retlen);
+ const u_char *buf = _buf + retlen;
+ loff_t to = _to + retlen;
+
+ if (nor->flags & SNOR_F_SST)
+ ret = sst_write(mtd, to, len, &retlen, buf);
+ else
+ ret = spi_nor_write(mtd, to, len, &retlen, buf);
+ if (ret)
+ return ret;
+ }
+
+ *_retlen += retlen;
+ return 0;
+}
+
+static int spi_nor_chunked_read(struct mtd_info *mtd, loff_t _from, size_t _len,
+ size_t *_retlen, u_char *_buf)
+{
+ struct spi_nor *nor = mtd_to_spi_nor(mtd);
+ int chunk_size;
+ int ret;
+
+ chunk_size = nor->chunk_size;
+ if (!chunk_size)
+ chunk_size = _len;
+
+ *_retlen = 0;
+ while (*_retlen < _len) {
+ size_t len = min_t(int, chunk_size, _len - *_retlen);
+ u_char *buf = _buf + *_retlen;
+ loff_t from = _from + *_retlen;
+ int retlen = 0;
+
+ ret = spi_nor_read(mtd, from, len, &retlen, buf);
+ if (ret)
+ return ret;
+
+ *_retlen += retlen;
+ }
+
+ return 0;
+}
+
/**
* macronix_quad_enable() - set QE bit in Status Register.
* @nor: pointer to a 'struct spi_nor'
@@ -2826,10 +2887,12 @@ int spi_nor_scan(struct spi_nor *nor, co
}
/* sst nor chips use AAI word program */
- if (info->flags & SST_WRITE)
+ if (info->flags & SST_WRITE) {
mtd->_write = sst_write;
- else
+ nor->flags |= SNOR_F_SST;
+ } else {
mtd->_write = spi_nor_write;
+ }
if (info->flags & USE_FSR)
nor->flags |= SNOR_F_USE_FSR;
@@ -2848,11 +2911,20 @@ int spi_nor_scan(struct spi_nor *nor, co
mtd->writebufsize = nor->page_size;
if (np) {
+ u32 val;
+
/* If we were instantiated by DT, use it */
if (of_property_read_bool(np, "m25p,fast-read"))
params.hwcaps.mask |= SNOR_HWCAPS_READ_FAST;
else
params.hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST;
+
+ if (!of_property_read_u32(np, "m25p,chunked-io", &val)) {
+ dev_info(dev, "using chunked io (size=%d)\n", val);
+ mtd->_read = spi_nor_chunked_read;
+ mtd->_write = spi_nor_chunked_write;
+ nor->chunk_size = val;
+ }
} else {
/* If we weren't instantiated by DT, default to fast-read */
params.hwcaps.mask |= SNOR_HWCAPS_READ_FAST;
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -231,6 +231,7 @@ enum spi_nor_option_flags {
SNOR_F_READY_XSR_RDY = BIT(4),
SNOR_F_USE_CLSR = BIT(5),
SNOR_F_4B_EXT_ADDR = BIT(6),
+ SNOR_F_SST = BIT(7),
};
/**
@@ -272,6 +273,7 @@ struct spi_nor {
struct mutex lock;
struct device *dev;
u32 page_size;
+ size_t chunk_size;
u8 addr_width;
u8 erase_opcode;
u8 read_opcode;

View file

@ -0,0 +1,15 @@
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -406,6 +406,12 @@ static int dwc2_driver_probe(struct plat
if (retval)
return retval;
+ /* Enable USB port before any regs access */
+ if (dwc2_readl(hsotg->regs + PCGCTL) & 0x0f) {
+ dwc2_writel(0x00, hsotg->regs + PCGCTL);
+ /* TODO: mdelay(25) here? vendor driver don't use it */
+ }
+
retval = dwc2_get_dr_mode(hsotg);
if (retval)
goto error;

View file

@ -0,0 +1,10 @@
--- a/arch/mips/ralink/Kconfig
+++ b/arch/mips/ralink/Kconfig
@@ -57,6 +57,7 @@ choice
select COMMON_CLK
select CLKSRC_MIPS_GIC
select HW_HAS_PCI
+ select WEAK_REORDERING_BEYOND_LLSC
endchoice
choice

View file

@ -0,0 +1,41 @@
From b6f779ea9c329451b89404583b45b9eb00155b32 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 18 Nov 2015 03:58:26 +0100
Subject: [PATCH 510/513] net-next: mediatek: add Kconfig and Makefile
This patch adds the Makefile and Kconfig required to make the driver build.
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Michael Lee <igvtee@gmail.com>
---
drivers/net/ethernet/Kconfig | 1 +
drivers/net/ethernet/Makefile | 1 +
drivers/net/ethernet/mtk/Kconfig | 62 ++++++++++++++++++++++++++++++++
drivers/net/ethernet/mtk/Makefile | 20 +++++++++++
4 files changed, 84 insertions(+)
create mode 100644 drivers/net/ethernet/mtk/Kconfig
create mode 100644 drivers/net/ethernet/mtk/Makefile
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -110,7 +110,7 @@ config LANTIQ_ETOP
Support for the MII0 inside the Lantiq SoC
source "drivers/net/ethernet/marvell/Kconfig"
-source "drivers/net/ethernet/mediatek/Kconfig"
+source "drivers/net/ethernet/mtk/Kconfig"
source "drivers/net/ethernet/mellanox/Kconfig"
source "drivers/net/ethernet/micrel/Kconfig"
source "drivers/net/ethernet/microchip/Kconfig"
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -51,7 +51,7 @@ obj-$(CONFIG_JME) += jme.o
obj-$(CONFIG_KORINA) += korina.o
obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o
obj-$(CONFIG_NET_VENDOR_MARVELL) += marvell/
-obj-$(CONFIG_NET_VENDOR_MEDIATEK) += mediatek/
+obj-$(CONFIG_NET_VENDOR_MEDIATEK) += mtk/
obj-$(CONFIG_NET_VENDOR_MELLANOX) += mellanox/
obj-$(CONFIG_NET_VENDOR_MICREL) += micrel/
obj-$(CONFIG_NET_VENDOR_MICROCHIP) += microchip/

View file

@ -0,0 +1,19 @@
--- a/arch/mips/kernel/mips-cm.c
+++ b/arch/mips/kernel/mips-cm.c
@@ -237,6 +237,7 @@ int mips_cm_probe(void)
/* disable CM regions */
write_gcr_reg0_base(CM_GCR_REGn_BASE_BASEADDR);
+ /*
write_gcr_reg0_mask(CM_GCR_REGn_MASK_ADDRMASK);
write_gcr_reg1_base(CM_GCR_REGn_BASE_BASEADDR);
write_gcr_reg1_mask(CM_GCR_REGn_MASK_ADDRMASK);
@@ -244,7 +245,7 @@ int mips_cm_probe(void)
write_gcr_reg2_mask(CM_GCR_REGn_MASK_ADDRMASK);
write_gcr_reg3_base(CM_GCR_REGn_BASE_BASEADDR);
write_gcr_reg3_mask(CM_GCR_REGn_MASK_ADDRMASK);
-
+*/
/* probe for an L2-only sync region */
mips_cm_probe_l2sync();

View file

@ -0,0 +1,10 @@
--- a/arch/mips/pci/pci-mt7620.c
+++ b/arch/mips/pci/pci-mt7620.c
@@ -33,7 +33,6 @@
#define RALINK_GPIOMODE 0x60
#define PPLL_CFG1 0x9c
-#define PDRV_SW_SET BIT(23)
#define PPLL_DRV 0xa0
#define PDRV_SW_SET (1<<31)

View file

@ -0,0 +1,66 @@
From 67b7bff0fd364c194e653f69baa623ba2141bd4c Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Mon, 4 Aug 2014 18:46:02 +0200
Subject: [PATCH 07/53] MIPS: ralink: copy the commandline from the devicetree
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/ralink/of.c | 2 ++
1 file changed, 2 insertions(+)
--- a/arch/mips/ralink/of.c
+++ b/arch/mips/ralink/of.c
@@ -3,7 +3,7 @@
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
- * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (C) 2008-2014 Imre Kaloz <kaloz@openwrt.org>
* Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
* Copyright (C) 2013 John Crispin <john@phrozen.org>
*/
@@ -66,6 +66,19 @@ static int __init early_init_dt_find_mem
return 0;
}
+static int chosen_dtb;
+
+static int __init early_init_dt_find_chosen(unsigned long node, const char *uname,
+ int depth, void *data)
+{
+ if (depth == 1 && !strcmp(uname, "chosen"))
+ chosen_dtb = 1;
+
+ return 0;
+}
+
+extern struct boot_param_header __image_dtb;
+
void __init plat_mem_setup(void)
{
void *dtb = NULL;
@@ -82,7 +95,11 @@ void __init plat_mem_setup(void)
else if (__dtb_start != __dtb_end)
dtb = (void *)__dtb_start;
- __dt_setup_arch(dtb);
+ __dt_setup_arch(&__image_dtb);
+
+ of_scan_flat_dt(early_init_dt_find_chosen, NULL);
+ if (chosen_dtb)
+ strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -85,6 +85,9 @@ EXPORT(__image_cmdline)
.fill 0x400
#endif /* CONFIG_IMAGE_CMDLINE_HACK */
+ .ascii "OWRTDTB:"
+ EXPORT(__image_dtb)
+ .fill 0x4000
__REF
NESTED(kernel_entry, 16, sp) # kernel entry point

View file

@ -0,0 +1,97 @@
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -57,6 +57,7 @@ obj-$(CONFIG_CXL_BASE) += cxl/
obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o
+obj-$(CONFIG_SOC_MT7620) += linkit.o
lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o
lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o
--- /dev/null
+++ b/drivers/misc/linkit.c
@@ -0,0 +1,84 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * publishhed by the Free Software Foundation.
+ *
+ * Copyright (C) 2015 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/mtd/mtd.h>
+#include <linux/gpio.h>
+
+#define LINKIT_LATCH_GPIO 11
+
+struct linkit_hw_data {
+ char board[16];
+ char rev[16];
+};
+
+static void sanify_string(char *s)
+{
+ int i;
+
+ for (i = 0; i < 15; i++)
+ if (s[i] <= 0x20)
+ s[i] = '\0';
+ s[15] = '\0';
+}
+
+static int linkit_probe(struct platform_device *pdev)
+{
+ struct linkit_hw_data hw;
+ struct mtd_info *mtd;
+ size_t retlen;
+ int ret;
+
+ mtd = get_mtd_device_nm("factory");
+ if (IS_ERR(mtd))
+ return PTR_ERR(mtd);
+
+ ret = mtd_read(mtd, 0x400, sizeof(hw), &retlen, (u_char *) &hw);
+ put_mtd_device(mtd);
+
+ sanify_string(hw.board);
+ sanify_string(hw.rev);
+
+ dev_info(&pdev->dev, "Version : %s\n", hw.board);
+ dev_info(&pdev->dev, "Revision : %s\n", hw.rev);
+
+ if (!strcmp(hw.board, "LINKITS7688")) {
+ dev_info(&pdev->dev, "setting up bootstrap latch\n");
+
+ if (devm_gpio_request(&pdev->dev, LINKIT_LATCH_GPIO, "bootstrap")) {
+ dev_err(&pdev->dev, "failed to setup bootstrap gpio\n");
+ return -1;
+ }
+ gpio_direction_output(LINKIT_LATCH_GPIO, 0);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id linkit_match[] = {
+ { .compatible = "mediatek,linkit" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, linkit_match);
+
+static struct platform_driver linkit_driver = {
+ .probe = linkit_probe,
+ .driver = {
+ .name = "mtk-linkit",
+ .owner = THIS_MODULE,
+ .of_match_table = linkit_match,
+ },
+};
+
+int __init linkit_init(void)
+{
+ return platform_driver_register(&linkit_driver);
+}
+late_initcall_sync(linkit_init);

View file

@ -0,0 +1,61 @@
There is a variant of MT7621 which contains only one CPU core instead of 2.
This is not reflected in the config register, so the kernel detects more
physical cores, which leads to a hang on SMP bringup.
Add a hack to detect missing cores.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/arch/mips/kernel/smp-cps.c
+++ b/arch/mips/kernel/smp-cps.c
@@ -47,6 +47,11 @@ static unsigned core_vpe_count(unsigned
return mips_cps_numvps(cluster, core);
}
+bool __weak plat_cpu_core_present(int core)
+{
+ return true;
+}
+
static void __init cps_smp_setup(void)
{
unsigned int nclusters, ncores, nvpes, core_vpes;
@@ -64,6 +69,8 @@ static void __init cps_smp_setup(void)
ncores = mips_cps_numcores(cl);
for (c = 0; c < ncores; c++) {
+ if (!plat_cpu_core_present(c))
+ continue;
core_vpes = core_vpe_count(cl, c);
if (c > 0)
--- a/arch/mips/ralink/mt7621.c
+++ b/arch/mips/ralink/mt7621.c
@@ -15,6 +15,7 @@
#include <asm/mips-cps.h>
#include <asm/mach-ralink/ralink_regs.h>
#include <asm/mach-ralink/mt7621.h>
+#include <asm/mips-boards/launch.h>
#include <pinmux.h>
@@ -162,6 +163,20 @@ void __init ralink_of_remap(void)
panic("Failed to remap core resources");
}
+bool plat_cpu_core_present(int core)
+{
+ struct cpulaunch *launch = (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH);
+
+ if (!core)
+ return true;
+ launch += core * 2; /* 2 VPEs per core */
+ if (!(launch->flags & LAUNCH_FREADY))
+ return false;
+ if (launch->flags & (LAUNCH_FGO | LAUNCH_FGONE))
+ return false;
+ return true;
+}
+
void prom_soc_init(struct ralink_soc_info *soc_info)
{
void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7621_SYSC_BASE);

View file

@ -0,0 +1,98 @@
--- a/arch/mips/ralink/mt7621.c
+++ b/arch/mips/ralink/mt7621.c
@@ -16,6 +16,7 @@
#include <asm/mach-ralink/ralink_regs.h>
#include <asm/mach-ralink/mt7621.h>
#include <asm/mips-boards/launch.h>
+#include <asm/delay.h>
#include <pinmux.h>
@@ -177,6 +178,58 @@ bool plat_cpu_core_present(int core)
return true;
}
+#define LPS_PREC 8
+/*
+* Re-calibration lpj(loop-per-jiffy).
+* (derived from kernel/calibrate.c)
+*/
+static int udelay_recal(void)
+{
+ unsigned int i, lpj = 0;
+ unsigned long ticks, loopbit;
+ int lps_precision = LPS_PREC;
+
+ lpj = (1<<12);
+
+ while ((lpj <<= 1) != 0) {
+ /* wait for "start of" clock tick */
+ ticks = jiffies;
+ while (ticks == jiffies)
+ /* nothing */;
+
+ /* Go .. */
+ ticks = jiffies;
+ __delay(lpj);
+ ticks = jiffies - ticks;
+ if (ticks)
+ break;
+ }
+
+ /*
+ * Do a binary approximation to get lpj set to
+ * equal one clock (up to lps_precision bits)
+ */
+ lpj >>= 1;
+ loopbit = lpj;
+ while (lps_precision-- && (loopbit >>= 1)) {
+ lpj |= loopbit;
+ ticks = jiffies;
+ while (ticks == jiffies)
+ /* nothing */;
+ ticks = jiffies;
+ __delay(lpj);
+ if (jiffies != ticks) /* longer than 1 tick */
+ lpj &= ~loopbit;
+ }
+ printk(KERN_INFO "%d CPUs re-calibrate udelay(lpj = %d)\n", NR_CPUS, lpj);
+
+ for(i=0; i< NR_CPUS; i++)
+ cpu_data[i].udelay_val = lpj;
+
+ return 0;
+}
+device_initcall(udelay_recal);
+
void prom_soc_init(struct ralink_soc_info *soc_info)
{
void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7621_SYSC_BASE);
--- a/arch/mips/ralink/Kconfig
+++ b/arch/mips/ralink/Kconfig
@@ -58,6 +58,7 @@ choice
select CLKSRC_MIPS_GIC
select HW_HAS_PCI
select WEAK_REORDERING_BEYOND_LLSC
+ select GENERIC_CLOCKEVENTS_BROADCAST
endchoice
choice
--- a/arch/mips/ralink/timer-gic.c
+++ b/arch/mips/ralink/timer-gic.c
@@ -12,6 +12,7 @@
#include <linux/of.h>
#include <linux/clk-provider.h>
#include <linux/clocksource.h>
+#include <asm/time.h>
#include "common.h"
@@ -19,6 +20,8 @@ void __init plat_time_init(void)
{
ralink_of_remap();
+ mips_hpt_frequency = 880000000 / 2;
+
of_clk_init(NULL);
timer_probe();
}

View file

@ -0,0 +1,14 @@
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1050,6 +1050,11 @@ static const struct flash_info spi_nor_i
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
+ {
+ "gd25q512", INFO(0xc84020, 0, 64 * 1024, 1024,
+ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+ SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4B_OPCODES)
+ },
/* Intel/Numonyx -- xxxs33b */
{ "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) },

View file

@ -0,0 +1,64 @@
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1083,7 +1083,7 @@ static const struct flash_info spi_nor_i
{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) },
{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
- { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
{ "mx66u51235f", INFO(0xc2253a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
{ "mx66l1g45g", INFO(0xc2201b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
@@ -1947,7 +1947,11 @@ static int spi_nor_read_sfdp(struct spi_
nor->read_dummy = 8;
while (len) {
- ret = nor->read(nor, addr, len, (u8 *)buf);
+ size_t _len = len;
+
+ if (nor->chunk_size)
+ _len = min(len, nor->chunk_size);
+ ret = nor->read(nor, addr, _len, (u8 *)buf);
if (!ret || ret > len) {
ret = -EIO;
goto read_err;
@@ -2791,6 +2795,7 @@ int spi_nor_scan(struct spi_nor *nor, co
struct device *dev = nor->dev;
struct mtd_info *mtd = &nor->mtd;
struct device_node *np = spi_nor_get_flash_node(nor);
+ u32 val;
int ret;
int i;
@@ -2803,6 +2808,9 @@ int spi_nor_scan(struct spi_nor *nor, co
nor->read_proto = SNOR_PROTO_1_1_1;
nor->write_proto = SNOR_PROTO_1_1_1;
+ if (np && !of_property_read_u32(np, "m25p,chunked-io", &val))
+ nor->chunk_size = val;
+
if (name)
info = spi_nor_match_id(name);
/* Try to auto-detect if chip name wasn't specified or not found */
@@ -2916,19 +2924,16 @@ int spi_nor_scan(struct spi_nor *nor, co
mtd->writebufsize = nor->page_size;
if (np) {
- u32 val;
-
/* If we were instantiated by DT, use it */
if (of_property_read_bool(np, "m25p,fast-read"))
params.hwcaps.mask |= SNOR_HWCAPS_READ_FAST;
else
params.hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST;
- if (!of_property_read_u32(np, "m25p,chunked-io", &val)) {
- dev_info(dev, "using chunked io (size=%d)\n", val);
+ if (nor->chunk_size) {
+ dev_info(dev, "using chunked io (size=%d)\n", nor->chunk_size);
mtd->_read = spi_nor_chunked_read;
mtd->_write = spi_nor_chunked_write;
- nor->chunk_size = val;
}
} else {
/* If we weren't instantiated by DT, default to fast-read */

View file

@ -0,0 +1,10 @@
--- a/arch/mips/ralink/mt7621.c
+++ b/arch/mips/ralink/mt7621.c
@@ -9,6 +9,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/jiffies.h>
#include <asm/mipsregs.h>
#include <asm/smp-ops.h>

View file

@ -0,0 +1,21 @@
--- a/arch/mips/pci/pci-mt7620.c
+++ b/arch/mips/pci/pci-mt7620.c
@@ -35,6 +35,7 @@
#define PPLL_CFG1 0x9c
#define PPLL_DRV 0xa0
+#define PPLL_LD (1<<23)
#define PDRV_SW_SET (1<<31)
#define LC_CKDRVPD (1<<19)
#define LC_CKDRVOHZ (1<<18)
@@ -242,8 +243,8 @@ static int mt7620_pci_hw_init(struct pla
rt_sysc_m32(0, RALINK_PCIE0_CLK_EN, RALINK_CLKCFG1);
mdelay(100);
- if (!(rt_sysc_r32(PPLL_CFG1) & PDRV_SW_SET)) {
- dev_err(&pdev->dev, "MT7620 PPLL unlock\n");
+ if (!(rt_sysc_r32(PPLL_CFG1) & PPLL_LD)) {
+ dev_err(&pdev->dev, "MT7620 PPLL is unlocked, aborting init\n");
reset_control_assert(rstpcie0);
rt_sysc_m32(RALINK_PCIE0_CLK_EN, 0, RALINK_CLKCFG1);
return -1;

View file

@ -0,0 +1,229 @@
CONFIG_ARCH_BINFMT_ELF_STATE=y
CONFIG_ARCH_CLOCKSOURCE_DATA=y
CONFIG_ARCH_DISCARD_MEMBLOCK=y
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
# CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set
CONFIG_ARCH_HAS_RESET_CONTROLLER=y
# CONFIG_ARCH_HAS_SG_CHAIN is not set
# CONFIG_ARCH_HAS_STRICT_KERNEL_RWX is not set
# CONFIG_ARCH_HAS_STRICT_MODULE_RWX is not set
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
CONFIG_ARCH_MMAP_RND_BITS_MAX=15
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15
# CONFIG_ARCH_OPTIONAL_KERNEL_RWX is not set
# CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT is not set
CONFIG_ARCH_SUPPORTS_UPROBES=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARCH_USE_BUILTIN_BSWAP=y
CONFIG_ARCH_USE_QUEUED_RWLOCKS=y
CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y
# CONFIG_ARCH_WANTS_THP_SWAP is not set
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
CONFIG_BLK_MQ_PCI=y
CONFIG_CEVT_R4K=y
# CONFIG_CEVT_SYSTICK_QUIRK is not set
CONFIG_CLKDEV_LOOKUP=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
CONFIG_CMDLINE_BOOL=y
# CONFIG_CMDLINE_OVERRIDE is not set
CONFIG_CPU_GENERIC_DUMP_TLB=y
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_CPU_HAS_RIXI=y
CONFIG_CPU_HAS_SYNC=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32=y
# CONFIG_CPU_MIPS32_R1 is not set
CONFIG_CPU_MIPS32_R2=y
CONFIG_CPU_MIPSR2=y
CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
CONFIG_CPU_R4K_CACHE_TLB=y
CONFIG_CPU_R4K_FPU=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_CPU_SUPPORTS_MSA=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_WORKQUEUE=y
CONFIG_CSRC_R4K=y
CONFIG_DMA_NONCOHERENT=y
# CONFIG_DMA_NOOP_OPS is not set
# CONFIG_DMA_VIRT_OPS is not set
# CONFIG_DRM_LIB_RANDOM is not set
# CONFIG_DTB_RT2880_EVAL is not set
CONFIG_DTB_RT_NONE=y
CONFIG_DTC=y
CONFIG_EARLY_PRINTK=y
CONFIG_EXPORTFS=y
CONFIG_FIXED_PHY=y
CONFIG_FUTEX_PI=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_GENERIC_CPU_AUTOPROBE=y
CONFIG_GENERIC_IO=y
CONFIG_GENERIC_IRQ_CHIP=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_SCHED_CLOCK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_RALINK=y
CONFIG_GPIO_SYSFS=y
# CONFIG_GRO_CELLS is not set
CONFIG_HANDLE_DOMAIN_IRQ=y
CONFIG_HARDWARE_WATCHPOINTS=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
# CONFIG_HAVE_ARCH_BITREVERSE is not set
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
CONFIG_HAVE_CBPF_JIT=y
CONFIG_HAVE_CC_STACKPROTECTOR=y
CONFIG_HAVE_CLK=y
CONFIG_HAVE_CONTEXT_TRACKING=y
CONFIG_HAVE_COPY_THREAD_TLS=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DEBUG_KMEMLEAK=y
CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_DMA_CONTIGUOUS=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_HAVE_IDE=y
CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
CONFIG_HAVE_KVM=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
CONFIG_HAVE_MEMBLOCK=y
CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
CONFIG_HAVE_NET_DSA=y
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
CONFIG_HW_HAS_PCI=y
CONFIG_HZ_PERIODIC=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IP17XX_PHY=y
CONFIG_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_INTC=y
CONFIG_IRQ_MIPS_CPU=y
CONFIG_IRQ_WORK=y
CONFIG_LIBFDT=y
CONFIG_MDIO_BUS=y
CONFIG_MDIO_DEVICE=y
CONFIG_MIPS=y
CONFIG_MIPS_ASID_BITS=8
CONFIG_MIPS_ASID_SHIFT=0
CONFIG_MIPS_CLOCK_VSYSCALL=y
# CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND is not set
# CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set
# CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set
CONFIG_MIPS_CMDLINE_FROM_DTB=y
# CONFIG_MIPS_ELF_APPENDED_DTB is not set
# CONFIG_MIPS_HUGE_TLB_SUPPORT is not set
CONFIG_MIPS_L1_CACHE_SHIFT=4
CONFIG_MIPS_L1_CACHE_SHIFT_4=y
# CONFIG_MIPS_MACHINE is not set
# CONFIG_MIPS_NO_APPENDED_DTB is not set
CONFIG_MIPS_RAW_APPENDED_DTB=y
CONFIG_MIPS_SPRAM=y
CONFIG_MODULES_USE_ELF_REL=y
# CONFIG_MTD_CFI_INTELEXT is not set
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_M25P80=y
CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPLIT_FIRMWARE=y
CONFIG_MTD_SPLIT_LZMA_FW=y
CONFIG_MTD_SPLIT_UIMAGE_FW=y
CONFIG_MTD_SPLIT_WRGG_FW=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_PER_CPU_KM=y
CONFIG_NET_MEDIATEK_MDIO=y
CONFIG_NET_MEDIATEK_MDIO_RT2880=y
CONFIG_NET_MEDIATEK_RT2880=y
CONFIG_NET_MEDIATEK_SOC=y
CONFIG_NET_VENDOR_MEDIATEK=y
CONFIG_NLS=m
CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
# CONFIG_NO_IOPORT_MAP is not set
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_ADDRESS_PCI=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
CONFIG_OF_IRQ=y
CONFIG_OF_MDIO=y
CONFIG_OF_NET=y
CONFIG_OF_PCI=y
CONFIG_OF_PCI_IRQ=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_DRIVERS_LEGACY=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PGTABLE_LEVELS=2
CONFIG_PHYLIB=y
# CONFIG_PHY_RALINK_USB is not set
CONFIG_PINCTRL=y
CONFIG_PINCTRL_RT2880=y
# CONFIG_PINCTRL_SINGLE is not set
CONFIG_RALINK=y
CONFIG_RALINK_WDT=y
# CONFIG_RCU_NEED_SEGCBLIST is not set
# CONFIG_RCU_STALL_COMMON is not set
CONFIG_RESET_CONTROLLER=y
# CONFIG_SCHED_INFO is not set
# CONFIG_SCSI_DMA is not set
# CONFIG_SERIAL_8250_FSL is not set
CONFIG_SERIAL_8250_RT288X=y
CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_SOC_MT7620 is not set
# CONFIG_SOC_MT7621 is not set
CONFIG_SOC_RT288X=y
# CONFIG_SOC_RT305X is not set
# CONFIG_SOC_RT3883 is not set
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
# CONFIG_SPI_MT7621 is not set
CONFIG_SPI_RT2880=y
CONFIG_SRCU=y
CONFIG_SWCONFIG=y
CONFIG_SWPHY=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
CONFIG_SYS_HAS_CPU_MIPS32_R2=y
CONFIG_SYS_HAS_EARLY_PRINTK=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
CONFIG_SYS_SUPPORTS_MIPS16=y
CONFIG_THIN_ARCHIVES=y
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TINY_SRCU=y
CONFIG_USB=m
CONFIG_USB_COMMON=m
CONFIG_USB_EHCI_HCD=m
CONFIG_USB_EHCI_HCD_PLATFORM=m
CONFIG_USB_OHCI_HCD=m
CONFIG_USB_OHCI_HCD_PLATFORM=m
CONFIG_USB_SUPPORT=y
CONFIG_USE_OF=y
CONFIG_WATCHDOG_CORE=y

View file

@ -0,0 +1,198 @@
CONFIG_ARCH_BINFMT_ELF_STATE=y
CONFIG_ARCH_CLOCKSOURCE_DATA=y
CONFIG_ARCH_DISCARD_MEMBLOCK=y
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
# CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set
CONFIG_ARCH_HAS_RESET_CONTROLLER=y
# CONFIG_ARCH_HAS_SG_CHAIN is not set
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
CONFIG_ARCH_SUPPORTS_UPROBES=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARCH_USE_BUILTIN_BSWAP=y
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
CONFIG_CEVT_R4K=y
CONFIG_CEVT_SYSTICK_QUIRK=y
CONFIG_CLKDEV_LOOKUP=y
CONFIG_CLKEVT_RT3352=y
CONFIG_CLKSRC_MMIO=y
CONFIG_CLKSRC_OF=y
CONFIG_CLKSRC_PROBE=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
CONFIG_CMDLINE_BOOL=y
# CONFIG_CMDLINE_OVERRIDE is not set
CONFIG_CPU_GENERIC_DUMP_TLB=y
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_CPU_HAS_RIXI=y
CONFIG_CPU_HAS_SYNC=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32=y
# CONFIG_CPU_MIPS32_R1 is not set
CONFIG_CPU_MIPS32_R2=y
CONFIG_CPU_MIPSR2=y
CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
CONFIG_CPU_R4K_CACHE_TLB=y
CONFIG_CPU_R4K_FPU=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_CPU_SUPPORTS_MSA=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_WORKQUEUE=y
CONFIG_CSRC_R4K=y
CONFIG_DEBUG_PINCTRL=y
CONFIG_DMA_NONCOHERENT=y
# CONFIG_DTB_RT305X_EVAL is not set
CONFIG_DTB_RT_NONE=y
CONFIG_DTC=y
CONFIG_EARLY_PRINTK=y
CONFIG_FIXED_PHY=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_GENERIC_IO=y
CONFIG_GENERIC_IRQ_CHIP=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_PHY=y
CONFIG_GENERIC_SCHED_CLOCK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_RALINK=y
CONFIG_GPIO_SYSFS=y
CONFIG_HANDLE_DOMAIN_IRQ=y
CONFIG_HARDWARE_WATCHPOINTS=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
# CONFIG_HAVE_ARCH_BITREVERSE is not set
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
CONFIG_HAVE_CBPF_JIT=y
CONFIG_HAVE_CC_STACKPROTECTOR=y
CONFIG_HAVE_CLK=y
CONFIG_HAVE_CONTEXT_TRACKING=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DEBUG_KMEMLEAK=y
CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_DMA_CONTIGUOUS=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_HAVE_IDE=y
CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
CONFIG_HAVE_KVM=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
CONFIG_HAVE_MEMBLOCK=y
CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
CONFIG_HAVE_NET_DSA=y
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
CONFIG_HZ_PERIODIC=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_INTC=y
CONFIG_IRQ_MIPS_CPU=y
CONFIG_IRQ_WORK=y
CONFIG_LIBFDT=y
CONFIG_MDIO_BOARDINFO=y
CONFIG_MIPS=y
CONFIG_MIPS_ASID_BITS=8
CONFIG_MIPS_ASID_SHIFT=0
CONFIG_MIPS_CLOCK_VSYSCALL=y
# CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND is not set
# CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set
# CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set
CONFIG_MIPS_CMDLINE_FROM_DTB=y
# CONFIG_MIPS_ELF_APPENDED_DTB is not set
# CONFIG_MIPS_HUGE_TLB_SUPPORT is not set
CONFIG_MIPS_L1_CACHE_SHIFT=5
# CONFIG_MIPS_MACHINE is not set
CONFIG_MIPS_NO_APPENDED_DTB=y
# CONFIG_MIPS_RAW_APPENDED_DTB is not set
CONFIG_MIPS_SPRAM=y
CONFIG_MODULES_USE_ELF_REL=y
# CONFIG_MTD_CFI_INTELEXT is not set
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_M25P80=y
CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y
CONFIG_MTD_SPI_NOR_USE_4K_SECTORS_LIMIT=16384
CONFIG_MTD_SPLIT_FIRMWARE=y
CONFIG_MTD_SPLIT_SEAMA_FW=y
CONFIG_MTD_SPLIT_UIMAGE_FW=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_PER_CPU_KM=y
CONFIG_NET_MEDIATEK_ESW_RT3050=y
CONFIG_NET_MEDIATEK_RT3050=y
CONFIG_NET_MEDIATEK_SOC=y
CONFIG_NET_VENDOR_MEDIATEK=y
CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
# CONFIG_NO_IOPORT_MAP is not set
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
CONFIG_OF_IRQ=y
CONFIG_OF_MDIO=y
CONFIG_OF_NET=y
CONFIG_PCI_DRIVERS_LEGACY=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PGTABLE_LEVELS=2
CONFIG_PHYLIB=y
CONFIG_PHY_RALINK_USB=y
CONFIG_PINCTRL=y
CONFIG_PINCTRL_RT2880=y
# CONFIG_PINCTRL_SINGLE is not set
CONFIG_RALINK=y
# CONFIG_RALINK_ILL_ACC is not set
CONFIG_RALINK_WDT=y
# CONFIG_RCU_STALL_COMMON is not set
CONFIG_RESET_CONTROLLER=y
# CONFIG_SCHED_INFO is not set
# CONFIG_SCSI_DMA is not set
# CONFIG_SERIAL_8250_FSL is not set
CONFIG_SERIAL_8250_RT288X=y
CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_SOC_MT7620 is not set
# CONFIG_SOC_MT7621 is not set
# CONFIG_SOC_RT288X is not set
CONFIG_SOC_RT305X=y
# CONFIG_SOC_RT3883 is not set
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
# CONFIG_SPI_MT7621 is not set
CONFIG_SPI_RT2880=y
CONFIG_SRCU=y
CONFIG_SWCONFIG=y
CONFIG_SWPHY=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
CONFIG_SYS_HAS_CPU_MIPS32_R2=y
CONFIG_SYS_HAS_EARLY_PRINTK=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
CONFIG_SYS_SUPPORTS_MIPS16=y
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_USB_SUPPORT=y
CONFIG_USE_OF=y
CONFIG_WATCHDOG_CORE=y

View file

@ -0,0 +1,231 @@
CONFIG_AR8216_PHY=y
CONFIG_ARCH_BINFMT_ELF_STATE=y
CONFIG_ARCH_CLOCKSOURCE_DATA=y
CONFIG_ARCH_DISCARD_MEMBLOCK=y
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
# CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set
CONFIG_ARCH_HAS_RESET_CONTROLLER=y
# CONFIG_ARCH_HAS_SG_CHAIN is not set
# CONFIG_ARCH_HAS_STRICT_KERNEL_RWX is not set
# CONFIG_ARCH_HAS_STRICT_MODULE_RWX is not set
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
CONFIG_ARCH_MMAP_RND_BITS_MAX=15
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15
# CONFIG_ARCH_OPTIONAL_KERNEL_RWX is not set
# CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT is not set
CONFIG_ARCH_SUPPORTS_UPROBES=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARCH_USE_BUILTIN_BSWAP=y
CONFIG_ARCH_USE_QUEUED_RWLOCKS=y
CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y
# CONFIG_ARCH_WANTS_THP_SWAP is not set
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
CONFIG_BLK_MQ_PCI=y
CONFIG_CEVT_R4K=y
# CONFIG_CEVT_SYSTICK_QUIRK is not set
CONFIG_CLKDEV_LOOKUP=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
CONFIG_CMDLINE_BOOL=y
# CONFIG_CMDLINE_OVERRIDE is not set
CONFIG_CPU_GENERIC_DUMP_TLB=y
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_CPU_HAS_RIXI=y
CONFIG_CPU_HAS_SYNC=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32=y
# CONFIG_CPU_MIPS32_R1 is not set
CONFIG_CPU_MIPS32_R2=y
CONFIG_CPU_MIPSR2=y
CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
CONFIG_CPU_R4K_CACHE_TLB=y
CONFIG_CPU_R4K_FPU=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_CPU_SUPPORTS_MSA=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_WORKQUEUE=y
CONFIG_CSRC_R4K=y
CONFIG_DEBUG_PINCTRL=y
CONFIG_DMA_NONCOHERENT=y
# CONFIG_DMA_NOOP_OPS is not set
# CONFIG_DMA_VIRT_OPS is not set
# CONFIG_DRM_LIB_RANDOM is not set
# CONFIG_DTB_RT3883_EVAL is not set
CONFIG_DTB_RT_NONE=y
CONFIG_DTC=y
CONFIG_EARLY_PRINTK=y
CONFIG_ETHERNET_PACKET_MANGLE=y
CONFIG_EXPORTFS=y
CONFIG_FIXED_PHY=y
CONFIG_FUTEX_PI=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_GENERIC_CPU_AUTOPROBE=y
CONFIG_GENERIC_IO=y
CONFIG_GENERIC_IRQ_CHIP=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_PHY=y
CONFIG_GENERIC_SCHED_CLOCK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_RALINK=y
CONFIG_GPIO_SYSFS=y
# CONFIG_GRO_CELLS is not set
CONFIG_HANDLE_DOMAIN_IRQ=y
CONFIG_HARDWARE_WATCHPOINTS=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
# CONFIG_HAVE_ARCH_BITREVERSE is not set
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
CONFIG_HAVE_CBPF_JIT=y
CONFIG_HAVE_CC_STACKPROTECTOR=y
CONFIG_HAVE_CLK=y
CONFIG_HAVE_CONTEXT_TRACKING=y
CONFIG_HAVE_COPY_THREAD_TLS=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DEBUG_KMEMLEAK=y
CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_DMA_CONTIGUOUS=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_HAVE_IDE=y
CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
CONFIG_HAVE_KVM=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
CONFIG_HAVE_MEMBLOCK=y
CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
CONFIG_HAVE_NET_DSA=y
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
CONFIG_HW_HAS_PCI=y
CONFIG_HZ_PERIODIC=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_INTC=y
CONFIG_IRQ_MIPS_CPU=y
CONFIG_IRQ_WORK=y
CONFIG_LIBFDT=y
CONFIG_MDIO_BUS=y
CONFIG_MDIO_DEVICE=y
CONFIG_MFD_SYSCON=y
CONFIG_MIPS=y
CONFIG_MIPS_ASID_BITS=8
CONFIG_MIPS_ASID_SHIFT=0
CONFIG_MIPS_CLOCK_VSYSCALL=y
# CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND is not set
# CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set
# CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set
CONFIG_MIPS_CMDLINE_FROM_DTB=y
# CONFIG_MIPS_ELF_APPENDED_DTB is not set
# CONFIG_MIPS_HUGE_TLB_SUPPORT is not set
CONFIG_MIPS_L1_CACHE_SHIFT=5
# CONFIG_MIPS_MACHINE is not set
CONFIG_MIPS_NO_APPENDED_DTB=y
# CONFIG_MIPS_RAW_APPENDED_DTB is not set
CONFIG_MIPS_SPRAM=y
CONFIG_MODULES_USE_ELF_REL=y
# CONFIG_MTD_CFI_INTELEXT is not set
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_M25P80=y
CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y
CONFIG_MTD_SPI_NOR_USE_4K_SECTORS_LIMIT=16384
CONFIG_MTD_SPLIT_FIRMWARE=y
CONFIG_MTD_SPLIT_SEAMA_FW=y
CONFIG_MTD_SPLIT_UIMAGE_FW=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_PER_CPU_KM=y
CONFIG_NET_MEDIATEK_MDIO=y
CONFIG_NET_MEDIATEK_MDIO_RT2880=y
CONFIG_NET_MEDIATEK_RT3883=y
CONFIG_NET_MEDIATEK_SOC=y
CONFIG_NET_VENDOR_MEDIATEK=y
CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
# CONFIG_NO_IOPORT_MAP is not set
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_ADDRESS_PCI=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
CONFIG_OF_IRQ=y
CONFIG_OF_MDIO=y
CONFIG_OF_NET=y
CONFIG_OF_PCI=y
CONFIG_OF_PCI_IRQ=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_DRIVERS_LEGACY=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PGTABLE_LEVELS=2
CONFIG_PHYLIB=y
CONFIG_PHY_RALINK_USB=y
CONFIG_PINCTRL=y
CONFIG_PINCTRL_RT2880=y
# CONFIG_PINCTRL_SINGLE is not set
CONFIG_RALINK=y
CONFIG_RALINK_WDT=y
# CONFIG_RCU_NEED_SEGCBLIST is not set
# CONFIG_RCU_STALL_COMMON is not set
CONFIG_REGMAP=y
CONFIG_REGMAP_MMIO=y
CONFIG_RESET_CONTROLLER=y
CONFIG_RTL8366_SMI=y
CONFIG_RTL8367B_PHY=y
CONFIG_RTL8367_PHY=y
# CONFIG_SCHED_INFO is not set
# CONFIG_SCSI_DMA is not set
# CONFIG_SERIAL_8250_FSL is not set
CONFIG_SERIAL_8250_RT288X=y
CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_SOC_MT7620 is not set
# CONFIG_SOC_MT7621 is not set
# CONFIG_SOC_RT288X is not set
# CONFIG_SOC_RT305X is not set
CONFIG_SOC_RT3883=y
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
# CONFIG_SPI_MT7621 is not set
CONFIG_SPI_RT2880=y
CONFIG_SRCU=y
CONFIG_SWCONFIG=y
CONFIG_SWPHY=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
CONFIG_SYS_HAS_CPU_MIPS32_R2=y
CONFIG_SYS_HAS_EARLY_PRINTK=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
CONFIG_SYS_SUPPORTS_MIPS16=y
CONFIG_THIN_ARCHIVES=y
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TINY_SRCU=y
CONFIG_USB_SUPPORT=y
CONFIG_USE_OF=y
CONFIG_WATCHDOG_CORE=y