26b8db2537
Should fix LAN speed issues on some devices. This is an updated version of the previously reverted commit with the same name. It improves the check for MACs connected to a built-in switch Signed-off-by: Felix Fietkau <nbd@nbd.name>
1264 lines
27 KiB
C
1264 lines
27 KiB
C
/*
|
|
* Atheros AR71xx SoC platform devices
|
|
*
|
|
* Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
|
|
* Copyright (C) 2008-2012 Gabor Juhos <juhosg@openwrt.org>
|
|
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
|
|
*
|
|
* Parts of this file are based on Atheros 2.6.15 BSP
|
|
* Parts of this file are based on Atheros 2.6.31 BSP
|
|
*
|
|
* 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/kernel.h>
|
|
#include <linux/init.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/etherdevice.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/serial_8250.h>
|
|
#include <linux/clk.h>
|
|
#include <linux/sizes.h>
|
|
|
|
#include <asm/mach-ath79/ath79.h>
|
|
#include <asm/mach-ath79/ar71xx_regs.h>
|
|
#include <asm/mach-ath79/irq.h>
|
|
|
|
#include "common.h"
|
|
#include "dev-eth.h"
|
|
|
|
unsigned char ath79_mac_base[ETH_ALEN] __initdata;
|
|
|
|
static struct resource ath79_mdio0_resources[] = {
|
|
{
|
|
.name = "mdio_base",
|
|
.flags = IORESOURCE_MEM,
|
|
.start = AR71XX_GE0_BASE,
|
|
.end = AR71XX_GE0_BASE + 0x200 - 1,
|
|
}
|
|
};
|
|
|
|
struct ag71xx_mdio_platform_data ath79_mdio0_data;
|
|
|
|
struct platform_device ath79_mdio0_device = {
|
|
.name = "ag71xx-mdio",
|
|
.id = 0,
|
|
.resource = ath79_mdio0_resources,
|
|
.num_resources = ARRAY_SIZE(ath79_mdio0_resources),
|
|
.dev = {
|
|
.platform_data = &ath79_mdio0_data,
|
|
},
|
|
};
|
|
|
|
static struct resource ath79_mdio1_resources[] = {
|
|
{
|
|
.name = "mdio_base",
|
|
.flags = IORESOURCE_MEM,
|
|
.start = AR71XX_GE1_BASE,
|
|
.end = AR71XX_GE1_BASE + 0x200 - 1,
|
|
}
|
|
};
|
|
|
|
struct ag71xx_mdio_platform_data ath79_mdio1_data;
|
|
|
|
struct platform_device ath79_mdio1_device = {
|
|
.name = "ag71xx-mdio",
|
|
.id = 1,
|
|
.resource = ath79_mdio1_resources,
|
|
.num_resources = ARRAY_SIZE(ath79_mdio1_resources),
|
|
.dev = {
|
|
.platform_data = &ath79_mdio1_data,
|
|
},
|
|
};
|
|
|
|
static void ath79_set_pll(u32 cfg_reg, u32 pll_reg, u32 pll_val, u32 shift)
|
|
{
|
|
void __iomem *base;
|
|
u32 t;
|
|
|
|
base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
|
|
|
|
t = __raw_readl(base + cfg_reg);
|
|
t &= ~(3 << shift);
|
|
t |= (2 << shift);
|
|
__raw_writel(t, base + cfg_reg);
|
|
udelay(100);
|
|
|
|
__raw_writel(pll_val, base + pll_reg);
|
|
|
|
t |= (3 << shift);
|
|
__raw_writel(t, base + cfg_reg);
|
|
udelay(100);
|
|
|
|
t &= ~(3 << shift);
|
|
__raw_writel(t, base + cfg_reg);
|
|
udelay(100);
|
|
|
|
printk(KERN_DEBUG "ar71xx: pll_reg %#x: %#x\n",
|
|
(unsigned int)(base + pll_reg), __raw_readl(base + pll_reg));
|
|
|
|
iounmap(base);
|
|
}
|
|
|
|
static void __init ath79_mii_ctrl_set_if(unsigned int reg,
|
|
unsigned int mii_if)
|
|
{
|
|
void __iomem *base;
|
|
u32 t;
|
|
|
|
base = ioremap(AR71XX_MII_BASE, AR71XX_MII_SIZE);
|
|
|
|
t = __raw_readl(base + reg);
|
|
t &= ~(AR71XX_MII_CTRL_IF_MASK);
|
|
t |= (mii_if & AR71XX_MII_CTRL_IF_MASK);
|
|
__raw_writel(t, base + reg);
|
|
|
|
iounmap(base);
|
|
}
|
|
|
|
static void ath79_mii_ctrl_set_speed(unsigned int reg, unsigned int speed)
|
|
{
|
|
void __iomem *base;
|
|
unsigned int mii_speed;
|
|
u32 t;
|
|
|
|
switch (speed) {
|
|
case SPEED_10:
|
|
mii_speed = AR71XX_MII_CTRL_SPEED_10;
|
|
break;
|
|
case SPEED_100:
|
|
mii_speed = AR71XX_MII_CTRL_SPEED_100;
|
|
break;
|
|
case SPEED_1000:
|
|
mii_speed = AR71XX_MII_CTRL_SPEED_1000;
|
|
break;
|
|
default:
|
|
BUG();
|
|
}
|
|
|
|
base = ioremap(AR71XX_MII_BASE, AR71XX_MII_SIZE);
|
|
|
|
t = __raw_readl(base + reg);
|
|
t &= ~(AR71XX_MII_CTRL_SPEED_MASK << AR71XX_MII_CTRL_SPEED_SHIFT);
|
|
t |= mii_speed << AR71XX_MII_CTRL_SPEED_SHIFT;
|
|
__raw_writel(t, base + reg);
|
|
|
|
iounmap(base);
|
|
}
|
|
|
|
static unsigned long ar934x_get_mdio_ref_clock(void)
|
|
{
|
|
void __iomem *base;
|
|
unsigned long ret;
|
|
u32 t;
|
|
|
|
base = ioremap(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
|
|
|
|
ret = 0;
|
|
t = __raw_readl(base + AR934X_PLL_SWITCH_CLOCK_CONTROL_REG);
|
|
if (t & AR934X_PLL_SWITCH_CLOCK_CONTROL_MDIO_CLK_SEL) {
|
|
ret = 100 * 1000 * 1000;
|
|
} else {
|
|
struct clk *clk;
|
|
|
|
clk = clk_get(NULL, "ref");
|
|
if (!IS_ERR(clk))
|
|
ret = clk_get_rate(clk);
|
|
}
|
|
|
|
iounmap(base);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void __init ath79_register_mdio(unsigned int id, u32 phy_mask)
|
|
{
|
|
struct platform_device *mdio_dev;
|
|
struct ag71xx_mdio_platform_data *mdio_data;
|
|
unsigned int max_id;
|
|
|
|
if (ath79_soc == ATH79_SOC_AR9341 ||
|
|
ath79_soc == ATH79_SOC_AR9342 ||
|
|
ath79_soc == ATH79_SOC_AR9344 ||
|
|
ath79_soc == ATH79_SOC_QCA9556 ||
|
|
ath79_soc == ATH79_SOC_QCA9558 ||
|
|
ath79_soc == ATH79_SOC_QCA956X)
|
|
max_id = 1;
|
|
else
|
|
max_id = 0;
|
|
|
|
if (id > max_id) {
|
|
printk(KERN_ERR "ar71xx: invalid MDIO id %u\n", id);
|
|
return;
|
|
}
|
|
|
|
switch (ath79_soc) {
|
|
case ATH79_SOC_AR7241:
|
|
case ATH79_SOC_AR9330:
|
|
case ATH79_SOC_AR9331:
|
|
case ATH79_SOC_QCA9533:
|
|
case ATH79_SOC_TP9343:
|
|
mdio_dev = &ath79_mdio1_device;
|
|
mdio_data = &ath79_mdio1_data;
|
|
break;
|
|
|
|
case ATH79_SOC_AR9341:
|
|
case ATH79_SOC_AR9342:
|
|
case ATH79_SOC_AR9344:
|
|
case ATH79_SOC_QCA9556:
|
|
case ATH79_SOC_QCA9558:
|
|
case ATH79_SOC_QCA956X:
|
|
if (id == 0) {
|
|
mdio_dev = &ath79_mdio0_device;
|
|
mdio_data = &ath79_mdio0_data;
|
|
} else {
|
|
mdio_dev = &ath79_mdio1_device;
|
|
mdio_data = &ath79_mdio1_data;
|
|
}
|
|
break;
|
|
|
|
case ATH79_SOC_AR7242:
|
|
ath79_set_pll(AR71XX_PLL_REG_SEC_CONFIG,
|
|
AR7242_PLL_REG_ETH0_INT_CLOCK, 0x62000000,
|
|
AR71XX_ETH0_PLL_SHIFT);
|
|
/* fall through */
|
|
default:
|
|
mdio_dev = &ath79_mdio0_device;
|
|
mdio_data = &ath79_mdio0_data;
|
|
break;
|
|
}
|
|
|
|
mdio_data->phy_mask = phy_mask;
|
|
|
|
switch (ath79_soc) {
|
|
case ATH79_SOC_AR7240:
|
|
mdio_data->is_ar7240 = 1;
|
|
/* fall through */
|
|
case ATH79_SOC_AR7241:
|
|
mdio_data->builtin_switch = 1;
|
|
break;
|
|
|
|
case ATH79_SOC_AR9330:
|
|
mdio_data->is_ar9330 = 1;
|
|
/* fall through */
|
|
case ATH79_SOC_AR9331:
|
|
mdio_data->builtin_switch = 1;
|
|
break;
|
|
|
|
case ATH79_SOC_AR9341:
|
|
case ATH79_SOC_AR9342:
|
|
case ATH79_SOC_AR9344:
|
|
if (id == 1) {
|
|
mdio_data->builtin_switch = 1;
|
|
mdio_data->ref_clock = ar934x_get_mdio_ref_clock();
|
|
mdio_data->mdio_clock = 6250000;
|
|
}
|
|
mdio_data->is_ar934x = 1;
|
|
break;
|
|
|
|
case ATH79_SOC_QCA9533:
|
|
case ATH79_SOC_TP9343:
|
|
mdio_data->builtin_switch = 1;
|
|
break;
|
|
|
|
case ATH79_SOC_QCA9556:
|
|
case ATH79_SOC_QCA9558:
|
|
mdio_data->is_ar934x = 1;
|
|
break;
|
|
|
|
case ATH79_SOC_QCA956X:
|
|
if (id == 1)
|
|
mdio_data->builtin_switch = 1;
|
|
mdio_data->is_ar934x = 1;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
platform_device_register(mdio_dev);
|
|
}
|
|
|
|
struct ath79_eth_pll_data ath79_eth0_pll_data;
|
|
struct ath79_eth_pll_data ath79_eth1_pll_data;
|
|
|
|
static u32 ath79_get_eth_pll(unsigned int mac, int speed)
|
|
{
|
|
struct ath79_eth_pll_data *pll_data;
|
|
u32 pll_val;
|
|
|
|
switch (mac) {
|
|
case 0:
|
|
pll_data = &ath79_eth0_pll_data;
|
|
break;
|
|
case 1:
|
|
pll_data = &ath79_eth1_pll_data;
|
|
break;
|
|
default:
|
|
BUG();
|
|
}
|
|
|
|
switch (speed) {
|
|
case SPEED_10:
|
|
pll_val = pll_data->pll_10;
|
|
break;
|
|
case SPEED_100:
|
|
pll_val = pll_data->pll_100;
|
|
break;
|
|
case SPEED_1000:
|
|
pll_val = pll_data->pll_1000;
|
|
break;
|
|
default:
|
|
BUG();
|
|
}
|
|
|
|
return pll_val;
|
|
}
|
|
|
|
static void ath79_set_speed_ge0(int speed)
|
|
{
|
|
u32 val = ath79_get_eth_pll(0, speed);
|
|
|
|
ath79_set_pll(AR71XX_PLL_REG_SEC_CONFIG, AR71XX_PLL_REG_ETH0_INT_CLOCK,
|
|
val, AR71XX_ETH0_PLL_SHIFT);
|
|
ath79_mii_ctrl_set_speed(AR71XX_MII_REG_MII0_CTRL, speed);
|
|
}
|
|
|
|
static void ath79_set_speed_ge1(int speed)
|
|
{
|
|
u32 val = ath79_get_eth_pll(1, speed);
|
|
|
|
ath79_set_pll(AR71XX_PLL_REG_SEC_CONFIG, AR71XX_PLL_REG_ETH1_INT_CLOCK,
|
|
val, AR71XX_ETH1_PLL_SHIFT);
|
|
ath79_mii_ctrl_set_speed(AR71XX_MII_REG_MII1_CTRL, speed);
|
|
}
|
|
|
|
static void ar7242_set_speed_ge0(int speed)
|
|
{
|
|
u32 val = ath79_get_eth_pll(0, speed);
|
|
void __iomem *base;
|
|
|
|
base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
|
|
__raw_writel(val, base + AR7242_PLL_REG_ETH0_INT_CLOCK);
|
|
iounmap(base);
|
|
}
|
|
|
|
static void ar91xx_set_speed_ge0(int speed)
|
|
{
|
|
u32 val = ath79_get_eth_pll(0, speed);
|
|
|
|
ath79_set_pll(AR913X_PLL_REG_ETH_CONFIG, AR913X_PLL_REG_ETH0_INT_CLOCK,
|
|
val, AR913X_ETH0_PLL_SHIFT);
|
|
ath79_mii_ctrl_set_speed(AR71XX_MII_REG_MII0_CTRL, speed);
|
|
}
|
|
|
|
static void ar91xx_set_speed_ge1(int speed)
|
|
{
|
|
u32 val = ath79_get_eth_pll(1, speed);
|
|
|
|
ath79_set_pll(AR913X_PLL_REG_ETH_CONFIG, AR913X_PLL_REG_ETH1_INT_CLOCK,
|
|
val, AR913X_ETH1_PLL_SHIFT);
|
|
ath79_mii_ctrl_set_speed(AR71XX_MII_REG_MII1_CTRL, speed);
|
|
}
|
|
|
|
static void ar934x_set_speed_ge0(int speed)
|
|
{
|
|
void __iomem *base;
|
|
u32 val = ath79_get_eth_pll(0, speed);
|
|
|
|
base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
|
|
__raw_writel(val, base + AR934X_PLL_ETH_XMII_CONTROL_REG);
|
|
iounmap(base);
|
|
}
|
|
|
|
static void qca955x_set_speed_xmii(int speed)
|
|
{
|
|
void __iomem *base;
|
|
u32 val = ath79_get_eth_pll(0, speed);
|
|
|
|
base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
|
|
__raw_writel(val, base + QCA955X_PLL_ETH_XMII_CONTROL_REG);
|
|
iounmap(base);
|
|
}
|
|
|
|
static void qca955x_set_speed_sgmii(int speed)
|
|
{
|
|
void __iomem *base;
|
|
u32 val = ath79_get_eth_pll(1, speed);
|
|
|
|
base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
|
|
__raw_writel(val, base + QCA955X_PLL_ETH_SGMII_CONTROL_REG);
|
|
iounmap(base);
|
|
}
|
|
|
|
static void qca956x_set_speed_sgmii(int speed)
|
|
{
|
|
void __iomem *base;
|
|
u32 val = ath79_get_eth_pll(0, speed);
|
|
|
|
base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
|
|
__raw_writel(val, base + QCA955X_PLL_ETH_SGMII_CONTROL_REG);
|
|
iounmap(base);
|
|
}
|
|
|
|
static void ath79_set_speed_dummy(int speed)
|
|
{
|
|
}
|
|
|
|
static void ath79_ddr_flush_ge0(void)
|
|
{
|
|
ath79_ddr_wb_flush(0);
|
|
}
|
|
|
|
static void ath79_ddr_flush_ge1(void)
|
|
{
|
|
ath79_ddr_wb_flush(1);
|
|
}
|
|
|
|
static struct resource ath79_eth0_resources[] = {
|
|
{
|
|
.name = "mac_base",
|
|
.flags = IORESOURCE_MEM,
|
|
.start = AR71XX_GE0_BASE,
|
|
.end = AR71XX_GE0_BASE + 0x200 - 1,
|
|
}, {
|
|
.name = "mac_irq",
|
|
.flags = IORESOURCE_IRQ,
|
|
.start = ATH79_CPU_IRQ(4),
|
|
.end = ATH79_CPU_IRQ(4),
|
|
},
|
|
};
|
|
|
|
struct ag71xx_platform_data ath79_eth0_data = {
|
|
.reset_bit = AR71XX_RESET_GE0_MAC,
|
|
};
|
|
|
|
struct platform_device ath79_eth0_device = {
|
|
.name = "ag71xx",
|
|
.id = 0,
|
|
.resource = ath79_eth0_resources,
|
|
.num_resources = ARRAY_SIZE(ath79_eth0_resources),
|
|
.dev = {
|
|
.platform_data = &ath79_eth0_data,
|
|
},
|
|
};
|
|
|
|
static struct resource ath79_eth1_resources[] = {
|
|
{
|
|
.name = "mac_base",
|
|
.flags = IORESOURCE_MEM,
|
|
.start = AR71XX_GE1_BASE,
|
|
.end = AR71XX_GE1_BASE + 0x200 - 1,
|
|
}, {
|
|
.name = "mac_irq",
|
|
.flags = IORESOURCE_IRQ,
|
|
.start = ATH79_CPU_IRQ(5),
|
|
.end = ATH79_CPU_IRQ(5),
|
|
},
|
|
};
|
|
|
|
struct ag71xx_platform_data ath79_eth1_data = {
|
|
.reset_bit = AR71XX_RESET_GE1_MAC,
|
|
};
|
|
|
|
struct platform_device ath79_eth1_device = {
|
|
.name = "ag71xx",
|
|
.id = 1,
|
|
.resource = ath79_eth1_resources,
|
|
.num_resources = ARRAY_SIZE(ath79_eth1_resources),
|
|
.dev = {
|
|
.platform_data = &ath79_eth1_data,
|
|
},
|
|
};
|
|
|
|
struct ag71xx_switch_platform_data ath79_switch_data;
|
|
|
|
#define AR71XX_PLL_VAL_1000 0x00110000
|
|
#define AR71XX_PLL_VAL_100 0x00001099
|
|
#define AR71XX_PLL_VAL_10 0x00991099
|
|
|
|
#define AR724X_PLL_VAL_1000 0x00110000
|
|
#define AR724X_PLL_VAL_100 0x00001099
|
|
#define AR724X_PLL_VAL_10 0x00991099
|
|
|
|
#define AR7242_PLL_VAL_1000 0x16000000
|
|
#define AR7242_PLL_VAL_100 0x00000101
|
|
#define AR7242_PLL_VAL_10 0x00001616
|
|
|
|
#define AR913X_PLL_VAL_1000 0x1a000000
|
|
#define AR913X_PLL_VAL_100 0x13000a44
|
|
#define AR913X_PLL_VAL_10 0x00441099
|
|
|
|
#define AR933X_PLL_VAL_1000 0x00110000
|
|
#define AR933X_PLL_VAL_100 0x00001099
|
|
#define AR933X_PLL_VAL_10 0x00991099
|
|
|
|
#define AR934X_PLL_VAL_1000 0x16000000
|
|
#define AR934X_PLL_VAL_100 0x00000101
|
|
#define AR934X_PLL_VAL_10 0x00001616
|
|
|
|
#define QCA956X_PLL_VAL_1000 0x03000000
|
|
#define QCA956X_PLL_VAL_100 0x00000101
|
|
#define QCA956X_PLL_VAL_10 0x00001919
|
|
|
|
static void __init ath79_init_eth_pll_data(unsigned int id)
|
|
{
|
|
struct ath79_eth_pll_data *pll_data;
|
|
u32 pll_10, pll_100, pll_1000;
|
|
|
|
switch (id) {
|
|
case 0:
|
|
pll_data = &ath79_eth0_pll_data;
|
|
break;
|
|
case 1:
|
|
pll_data = &ath79_eth1_pll_data;
|
|
break;
|
|
default:
|
|
BUG();
|
|
}
|
|
|
|
switch (ath79_soc) {
|
|
case ATH79_SOC_AR7130:
|
|
case ATH79_SOC_AR7141:
|
|
case ATH79_SOC_AR7161:
|
|
pll_10 = AR71XX_PLL_VAL_10;
|
|
pll_100 = AR71XX_PLL_VAL_100;
|
|
pll_1000 = AR71XX_PLL_VAL_1000;
|
|
break;
|
|
|
|
case ATH79_SOC_AR7240:
|
|
case ATH79_SOC_AR7241:
|
|
pll_10 = AR724X_PLL_VAL_10;
|
|
pll_100 = AR724X_PLL_VAL_100;
|
|
pll_1000 = AR724X_PLL_VAL_1000;
|
|
break;
|
|
|
|
case ATH79_SOC_AR7242:
|
|
pll_10 = AR7242_PLL_VAL_10;
|
|
pll_100 = AR7242_PLL_VAL_100;
|
|
pll_1000 = AR7242_PLL_VAL_1000;
|
|
break;
|
|
|
|
case ATH79_SOC_AR9130:
|
|
case ATH79_SOC_AR9132:
|
|
pll_10 = AR913X_PLL_VAL_10;
|
|
pll_100 = AR913X_PLL_VAL_100;
|
|
pll_1000 = AR913X_PLL_VAL_1000;
|
|
break;
|
|
|
|
case ATH79_SOC_AR9330:
|
|
case ATH79_SOC_AR9331:
|
|
pll_10 = AR933X_PLL_VAL_10;
|
|
pll_100 = AR933X_PLL_VAL_100;
|
|
pll_1000 = AR933X_PLL_VAL_1000;
|
|
break;
|
|
|
|
case ATH79_SOC_AR9341:
|
|
case ATH79_SOC_AR9342:
|
|
case ATH79_SOC_AR9344:
|
|
case ATH79_SOC_QCA9533:
|
|
case ATH79_SOC_QCA9556:
|
|
case ATH79_SOC_QCA9558:
|
|
case ATH79_SOC_TP9343:
|
|
pll_10 = AR934X_PLL_VAL_10;
|
|
pll_100 = AR934X_PLL_VAL_100;
|
|
pll_1000 = AR934X_PLL_VAL_1000;
|
|
break;
|
|
|
|
case ATH79_SOC_QCA956X:
|
|
pll_10 = QCA956X_PLL_VAL_10;
|
|
pll_100 = QCA956X_PLL_VAL_100;
|
|
pll_1000 = QCA956X_PLL_VAL_1000;
|
|
break;
|
|
|
|
default:
|
|
BUG();
|
|
}
|
|
|
|
if (!pll_data->pll_10)
|
|
pll_data->pll_10 = pll_10;
|
|
|
|
if (!pll_data->pll_100)
|
|
pll_data->pll_100 = pll_100;
|
|
|
|
if (!pll_data->pll_1000)
|
|
pll_data->pll_1000 = pll_1000;
|
|
}
|
|
|
|
static int __init ath79_setup_phy_if_mode(unsigned int id,
|
|
struct ag71xx_platform_data *pdata)
|
|
{
|
|
unsigned int mii_if;
|
|
|
|
switch (id) {
|
|
case 0:
|
|
switch (ath79_soc) {
|
|
case ATH79_SOC_AR7130:
|
|
case ATH79_SOC_AR7141:
|
|
case ATH79_SOC_AR7161:
|
|
case ATH79_SOC_AR9130:
|
|
case ATH79_SOC_AR9132:
|
|
switch (pdata->phy_if_mode) {
|
|
case PHY_INTERFACE_MODE_MII:
|
|
mii_if = AR71XX_MII0_CTRL_IF_MII;
|
|
break;
|
|
case PHY_INTERFACE_MODE_GMII:
|
|
mii_if = AR71XX_MII0_CTRL_IF_GMII;
|
|
break;
|
|
case PHY_INTERFACE_MODE_RGMII:
|
|
mii_if = AR71XX_MII0_CTRL_IF_RGMII;
|
|
break;
|
|
case PHY_INTERFACE_MODE_RMII:
|
|
mii_if = AR71XX_MII0_CTRL_IF_RMII;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
ath79_mii_ctrl_set_if(AR71XX_MII_REG_MII0_CTRL, mii_if);
|
|
break;
|
|
|
|
case ATH79_SOC_AR7240:
|
|
case ATH79_SOC_AR7241:
|
|
case ATH79_SOC_AR9330:
|
|
case ATH79_SOC_AR9331:
|
|
case ATH79_SOC_QCA9533:
|
|
case ATH79_SOC_TP9343:
|
|
pdata->phy_if_mode = PHY_INTERFACE_MODE_MII;
|
|
break;
|
|
|
|
case ATH79_SOC_AR7242:
|
|
/* FIXME */
|
|
|
|
case ATH79_SOC_AR9341:
|
|
case ATH79_SOC_AR9342:
|
|
case ATH79_SOC_AR9344:
|
|
switch (pdata->phy_if_mode) {
|
|
case PHY_INTERFACE_MODE_MII:
|
|
case PHY_INTERFACE_MODE_GMII:
|
|
case PHY_INTERFACE_MODE_RGMII:
|
|
case PHY_INTERFACE_MODE_RMII:
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
break;
|
|
|
|
case ATH79_SOC_QCA9556:
|
|
case ATH79_SOC_QCA9558:
|
|
case ATH79_SOC_QCA956X:
|
|
switch (pdata->phy_if_mode) {
|
|
case PHY_INTERFACE_MODE_MII:
|
|
case PHY_INTERFACE_MODE_RGMII:
|
|
case PHY_INTERFACE_MODE_SGMII:
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
BUG();
|
|
}
|
|
break;
|
|
case 1:
|
|
switch (ath79_soc) {
|
|
case ATH79_SOC_AR7130:
|
|
case ATH79_SOC_AR7141:
|
|
case ATH79_SOC_AR7161:
|
|
case ATH79_SOC_AR9130:
|
|
case ATH79_SOC_AR9132:
|
|
switch (pdata->phy_if_mode) {
|
|
case PHY_INTERFACE_MODE_RMII:
|
|
mii_if = AR71XX_MII1_CTRL_IF_RMII;
|
|
break;
|
|
case PHY_INTERFACE_MODE_RGMII:
|
|
mii_if = AR71XX_MII1_CTRL_IF_RGMII;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
ath79_mii_ctrl_set_if(AR71XX_MII_REG_MII1_CTRL, mii_if);
|
|
break;
|
|
|
|
case ATH79_SOC_AR7240:
|
|
case ATH79_SOC_AR7241:
|
|
case ATH79_SOC_AR9330:
|
|
case ATH79_SOC_AR9331:
|
|
case ATH79_SOC_QCA956X:
|
|
case ATH79_SOC_TP9343:
|
|
pdata->phy_if_mode = PHY_INTERFACE_MODE_GMII;
|
|
break;
|
|
|
|
case ATH79_SOC_AR7242:
|
|
/* FIXME */
|
|
|
|
case ATH79_SOC_AR9341:
|
|
case ATH79_SOC_AR9342:
|
|
case ATH79_SOC_AR9344:
|
|
case ATH79_SOC_QCA9533:
|
|
switch (pdata->phy_if_mode) {
|
|
case PHY_INTERFACE_MODE_MII:
|
|
case PHY_INTERFACE_MODE_GMII:
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
break;
|
|
|
|
case ATH79_SOC_QCA9556:
|
|
case ATH79_SOC_QCA9558:
|
|
switch (pdata->phy_if_mode) {
|
|
case PHY_INTERFACE_MODE_MII:
|
|
case PHY_INTERFACE_MODE_RGMII:
|
|
case PHY_INTERFACE_MODE_SGMII:
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
BUG();
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void __init ath79_setup_ar933x_phy4_switch(bool mac, bool mdio)
|
|
{
|
|
void __iomem *base;
|
|
u32 t;
|
|
|
|
base = ioremap(AR933X_GMAC_BASE, AR933X_GMAC_SIZE);
|
|
|
|
t = __raw_readl(base + AR933X_GMAC_REG_ETH_CFG);
|
|
t &= ~(AR933X_ETH_CFG_SW_PHY_SWAP | AR933X_ETH_CFG_SW_PHY_ADDR_SWAP);
|
|
if (mac)
|
|
t |= AR933X_ETH_CFG_SW_PHY_SWAP;
|
|
if (mdio)
|
|
t |= AR933X_ETH_CFG_SW_PHY_ADDR_SWAP;
|
|
__raw_writel(t, base + AR933X_GMAC_REG_ETH_CFG);
|
|
|
|
iounmap(base);
|
|
}
|
|
|
|
void __init ath79_setup_ar934x_eth_cfg(u32 mask)
|
|
{
|
|
void __iomem *base;
|
|
u32 t;
|
|
|
|
base = ioremap(AR934X_GMAC_BASE, AR934X_GMAC_SIZE);
|
|
|
|
t = __raw_readl(base + AR934X_GMAC_REG_ETH_CFG);
|
|
|
|
t &= ~(AR934X_ETH_CFG_RGMII_GMAC0 |
|
|
AR934X_ETH_CFG_MII_GMAC0 |
|
|
AR934X_ETH_CFG_GMII_GMAC0 |
|
|
AR934X_ETH_CFG_SW_ONLY_MODE |
|
|
AR934X_ETH_CFG_SW_PHY_SWAP);
|
|
|
|
t |= mask;
|
|
|
|
__raw_writel(t, base + AR934X_GMAC_REG_ETH_CFG);
|
|
/* flush write */
|
|
__raw_readl(base + AR934X_GMAC_REG_ETH_CFG);
|
|
|
|
iounmap(base);
|
|
}
|
|
|
|
void __init ath79_setup_ar934x_eth_rx_delay(unsigned int rxd,
|
|
unsigned int rxdv)
|
|
{
|
|
void __iomem *base;
|
|
u32 t;
|
|
|
|
rxd &= AR934X_ETH_CFG_RXD_DELAY_MASK;
|
|
rxdv &= AR934X_ETH_CFG_RDV_DELAY_MASK;
|
|
|
|
base = ioremap(AR934X_GMAC_BASE, AR934X_GMAC_SIZE);
|
|
|
|
t = __raw_readl(base + AR934X_GMAC_REG_ETH_CFG);
|
|
|
|
t &= ~(AR934X_ETH_CFG_RXD_DELAY_MASK << AR934X_ETH_CFG_RXD_DELAY_SHIFT |
|
|
AR934X_ETH_CFG_RDV_DELAY_MASK << AR934X_ETH_CFG_RDV_DELAY_SHIFT);
|
|
|
|
t |= (rxd << AR934X_ETH_CFG_RXD_DELAY_SHIFT |
|
|
rxdv << AR934X_ETH_CFG_RDV_DELAY_SHIFT);
|
|
|
|
__raw_writel(t, base + AR934X_GMAC_REG_ETH_CFG);
|
|
/* flush write */
|
|
__raw_readl(base + AR934X_GMAC_REG_ETH_CFG);
|
|
|
|
iounmap(base);
|
|
}
|
|
|
|
void __init ath79_setup_qca955x_eth_cfg(u32 mask)
|
|
{
|
|
void __iomem *base;
|
|
u32 t;
|
|
|
|
base = ioremap(QCA955X_GMAC_BASE, QCA955X_GMAC_SIZE);
|
|
|
|
t = __raw_readl(base + QCA955X_GMAC_REG_ETH_CFG);
|
|
|
|
t &= ~(QCA955X_ETH_CFG_RGMII_EN | QCA955X_ETH_CFG_GE0_SGMII);
|
|
|
|
t |= mask;
|
|
|
|
__raw_writel(t, base + QCA955X_GMAC_REG_ETH_CFG);
|
|
|
|
iounmap(base);
|
|
}
|
|
|
|
static int ath79_eth_instance __initdata;
|
|
void __init ath79_register_eth(unsigned int id)
|
|
{
|
|
struct platform_device *pdev;
|
|
struct ag71xx_platform_data *pdata;
|
|
int err;
|
|
|
|
if (id > 1) {
|
|
printk(KERN_ERR "ar71xx: invalid ethernet id %d\n", id);
|
|
return;
|
|
}
|
|
|
|
ath79_init_eth_pll_data(id);
|
|
|
|
if (id == 0)
|
|
pdev = &ath79_eth0_device;
|
|
else
|
|
pdev = &ath79_eth1_device;
|
|
|
|
pdata = pdev->dev.platform_data;
|
|
|
|
pdata->max_frame_len = 1540;
|
|
pdata->desc_pktlen_mask = 0xfff;
|
|
|
|
err = ath79_setup_phy_if_mode(id, pdata);
|
|
if (err) {
|
|
printk(KERN_ERR
|
|
"ar71xx: invalid PHY interface mode for GE%u\n", id);
|
|
return;
|
|
}
|
|
|
|
if (id == 0)
|
|
pdata->ddr_flush = ath79_ddr_flush_ge0;
|
|
else
|
|
pdata->ddr_flush = ath79_ddr_flush_ge1;
|
|
|
|
switch (ath79_soc) {
|
|
case ATH79_SOC_AR7130:
|
|
if (id == 0)
|
|
pdata->set_speed = ath79_set_speed_ge0;
|
|
else
|
|
pdata->set_speed = ath79_set_speed_ge1;
|
|
break;
|
|
|
|
case ATH79_SOC_AR7141:
|
|
case ATH79_SOC_AR7161:
|
|
if (id == 0)
|
|
pdata->set_speed = ath79_set_speed_ge0;
|
|
else
|
|
pdata->set_speed = ath79_set_speed_ge1;
|
|
pdata->has_gbit = 1;
|
|
break;
|
|
|
|
case ATH79_SOC_AR7242:
|
|
if (id == 0) {
|
|
pdata->reset_bit |= AR724X_RESET_GE0_MDIO |
|
|
AR71XX_RESET_GE0_PHY;
|
|
pdata->set_speed = ar7242_set_speed_ge0;
|
|
} else {
|
|
pdata->reset_bit |= AR724X_RESET_GE1_MDIO |
|
|
AR71XX_RESET_GE1_PHY;
|
|
pdata->set_speed = ath79_set_speed_dummy;
|
|
}
|
|
pdata->has_gbit = 1;
|
|
pdata->is_ar724x = 1;
|
|
|
|
if (!pdata->fifo_cfg1)
|
|
pdata->fifo_cfg1 = 0x0010ffff;
|
|
if (!pdata->fifo_cfg2)
|
|
pdata->fifo_cfg2 = 0x015500aa;
|
|
if (!pdata->fifo_cfg3)
|
|
pdata->fifo_cfg3 = 0x01f00140;
|
|
break;
|
|
|
|
case ATH79_SOC_AR7241:
|
|
if (id == 0)
|
|
pdata->reset_bit |= AR724X_RESET_GE0_MDIO;
|
|
else
|
|
pdata->reset_bit |= AR724X_RESET_GE1_MDIO;
|
|
/* fall through */
|
|
case ATH79_SOC_AR7240:
|
|
if (id == 0) {
|
|
pdata->reset_bit |= AR71XX_RESET_GE0_PHY;
|
|
pdata->set_speed = ath79_set_speed_dummy;
|
|
|
|
pdata->phy_mask = BIT(4);
|
|
} else {
|
|
pdata->reset_bit |= AR71XX_RESET_GE1_PHY;
|
|
pdata->set_speed = ath79_set_speed_dummy;
|
|
|
|
pdata->speed = SPEED_1000;
|
|
pdata->duplex = DUPLEX_FULL;
|
|
pdata->switch_data = &ath79_switch_data;
|
|
pdata->builtin_switch = 1;
|
|
|
|
ath79_switch_data.phy_poll_mask |= BIT(4);
|
|
}
|
|
pdata->has_gbit = 1;
|
|
pdata->is_ar724x = 1;
|
|
if (ath79_soc == ATH79_SOC_AR7240)
|
|
pdata->is_ar7240 = 1;
|
|
|
|
if (!pdata->fifo_cfg1)
|
|
pdata->fifo_cfg1 = 0x0010ffff;
|
|
if (!pdata->fifo_cfg2)
|
|
pdata->fifo_cfg2 = 0x015500aa;
|
|
if (!pdata->fifo_cfg3)
|
|
pdata->fifo_cfg3 = 0x01f00140;
|
|
break;
|
|
|
|
case ATH79_SOC_AR9132:
|
|
pdata->has_gbit = 1;
|
|
/* fall through */
|
|
case ATH79_SOC_AR9130:
|
|
if (id == 0)
|
|
pdata->set_speed = ar91xx_set_speed_ge0;
|
|
else
|
|
pdata->set_speed = ar91xx_set_speed_ge1;
|
|
pdata->is_ar91xx = 1;
|
|
break;
|
|
|
|
case ATH79_SOC_AR9330:
|
|
case ATH79_SOC_AR9331:
|
|
if (id == 0) {
|
|
pdata->reset_bit = AR933X_RESET_GE0_MAC |
|
|
AR933X_RESET_GE0_MDIO;
|
|
pdata->set_speed = ath79_set_speed_dummy;
|
|
|
|
pdata->phy_mask = BIT(4);
|
|
} else {
|
|
pdata->reset_bit = AR933X_RESET_GE1_MAC |
|
|
AR933X_RESET_GE1_MDIO;
|
|
pdata->set_speed = ath79_set_speed_dummy;
|
|
|
|
pdata->speed = SPEED_1000;
|
|
pdata->has_gbit = 1;
|
|
pdata->duplex = DUPLEX_FULL;
|
|
pdata->switch_data = &ath79_switch_data;
|
|
pdata->builtin_switch = 1;
|
|
|
|
ath79_switch_data.phy_poll_mask |= BIT(4);
|
|
}
|
|
|
|
pdata->is_ar724x = 1;
|
|
|
|
if (!pdata->fifo_cfg1)
|
|
pdata->fifo_cfg1 = 0x0010ffff;
|
|
if (!pdata->fifo_cfg2)
|
|
pdata->fifo_cfg2 = 0x015500aa;
|
|
if (!pdata->fifo_cfg3)
|
|
pdata->fifo_cfg3 = 0x01f00140;
|
|
break;
|
|
|
|
case ATH79_SOC_AR9341:
|
|
case ATH79_SOC_AR9342:
|
|
case ATH79_SOC_AR9344:
|
|
case ATH79_SOC_QCA9533:
|
|
if (id == 0) {
|
|
pdata->reset_bit = AR934X_RESET_GE0_MAC |
|
|
AR934X_RESET_GE0_MDIO;
|
|
pdata->set_speed = ar934x_set_speed_ge0;
|
|
} else {
|
|
pdata->reset_bit = AR934X_RESET_GE1_MAC |
|
|
AR934X_RESET_GE1_MDIO;
|
|
pdata->set_speed = ath79_set_speed_dummy;
|
|
|
|
pdata->switch_data = &ath79_switch_data;
|
|
pdata->builtin_switch = 1;
|
|
|
|
/* reset the built-in switch */
|
|
ath79_device_reset_set(AR934X_RESET_ETH_SWITCH);
|
|
ath79_device_reset_clear(AR934X_RESET_ETH_SWITCH);
|
|
}
|
|
|
|
pdata->has_gbit = 1;
|
|
pdata->is_ar724x = 1;
|
|
|
|
pdata->max_frame_len = SZ_16K - 1;
|
|
pdata->desc_pktlen_mask = SZ_16K - 1;
|
|
|
|
if (!pdata->fifo_cfg1)
|
|
pdata->fifo_cfg1 = 0x0010ffff;
|
|
if (!pdata->fifo_cfg2)
|
|
pdata->fifo_cfg2 = 0x015500aa;
|
|
if (!pdata->fifo_cfg3)
|
|
pdata->fifo_cfg3 = 0x01f00140;
|
|
break;
|
|
|
|
case ATH79_SOC_TP9343:
|
|
if (id == 0) {
|
|
pdata->reset_bit = AR933X_RESET_GE0_MAC |
|
|
AR933X_RESET_GE0_MDIO;
|
|
pdata->set_speed = ath79_set_speed_dummy;
|
|
|
|
if (!pdata->phy_mask)
|
|
pdata->phy_mask = BIT(4);
|
|
} else {
|
|
pdata->reset_bit = AR933X_RESET_GE1_MAC |
|
|
AR933X_RESET_GE1_MDIO;
|
|
pdata->set_speed = ath79_set_speed_dummy;
|
|
|
|
pdata->speed = SPEED_1000;
|
|
pdata->duplex = DUPLEX_FULL;
|
|
pdata->switch_data = &ath79_switch_data;
|
|
pdata->builtin_switch = 1;
|
|
|
|
ath79_switch_data.phy_poll_mask |= BIT(4);
|
|
}
|
|
|
|
pdata->has_gbit = 1;
|
|
pdata->is_ar724x = 1;
|
|
|
|
if (!pdata->fifo_cfg1)
|
|
pdata->fifo_cfg1 = 0x0010ffff;
|
|
if (!pdata->fifo_cfg2)
|
|
pdata->fifo_cfg2 = 0x015500aa;
|
|
if (!pdata->fifo_cfg3)
|
|
pdata->fifo_cfg3 = 0x01f00140;
|
|
break;
|
|
|
|
case ATH79_SOC_QCA9556:
|
|
case ATH79_SOC_QCA9558:
|
|
if (id == 0) {
|
|
pdata->reset_bit = QCA955X_RESET_GE0_MAC |
|
|
QCA955X_RESET_GE0_MDIO;
|
|
pdata->set_speed = qca955x_set_speed_xmii;
|
|
} else {
|
|
pdata->reset_bit = QCA955X_RESET_GE1_MAC |
|
|
QCA955X_RESET_GE1_MDIO;
|
|
pdata->set_speed = qca955x_set_speed_sgmii;
|
|
pdata->builtin_switch = 1;
|
|
}
|
|
|
|
pdata->has_gbit = 1;
|
|
pdata->is_ar724x = 1;
|
|
|
|
/*
|
|
* Limit the maximum frame length to 4095 bytes.
|
|
* Although the documentation says that the hardware
|
|
* limit is 16383 bytes but that does not work in
|
|
* practice. It seems that the hardware only updates
|
|
* the lowest 12 bits of the packet length field
|
|
* in the RX descriptor.
|
|
*/
|
|
pdata->max_frame_len = SZ_4K - 1;
|
|
pdata->desc_pktlen_mask = SZ_16K - 1;
|
|
|
|
if (!pdata->fifo_cfg1)
|
|
pdata->fifo_cfg1 = 0x0010ffff;
|
|
if (!pdata->fifo_cfg2)
|
|
pdata->fifo_cfg2 = 0x015500aa;
|
|
if (!pdata->fifo_cfg3)
|
|
pdata->fifo_cfg3 = 0x01f00140;
|
|
break;
|
|
|
|
case ATH79_SOC_QCA956X:
|
|
if (id == 0) {
|
|
pdata->reset_bit = QCA955X_RESET_GE0_MAC |
|
|
QCA955X_RESET_GE0_MDIO;
|
|
|
|
if (pdata->phy_if_mode == PHY_INTERFACE_MODE_SGMII)
|
|
pdata->set_speed = qca956x_set_speed_sgmii;
|
|
else
|
|
pdata->set_speed = ath79_set_speed_ge0;
|
|
} else {
|
|
pdata->reset_bit = QCA955X_RESET_GE1_MAC |
|
|
QCA955X_RESET_GE1_MDIO;
|
|
|
|
pdata->set_speed = ath79_set_speed_dummy;
|
|
|
|
pdata->switch_data = &ath79_switch_data;
|
|
|
|
pdata->speed = SPEED_1000;
|
|
pdata->duplex = DUPLEX_FULL;
|
|
pdata->builtin_switch = 1;
|
|
|
|
/* reset the built-in switch */
|
|
ath79_device_reset_set(AR934X_RESET_ETH_SWITCH);
|
|
ath79_device_reset_clear(AR934X_RESET_ETH_SWITCH);
|
|
}
|
|
|
|
pdata->has_gbit = 1;
|
|
pdata->is_ar724x = 1;
|
|
|
|
if (!pdata->fifo_cfg1)
|
|
pdata->fifo_cfg1 = 0x0010ffff;
|
|
if (!pdata->fifo_cfg2)
|
|
pdata->fifo_cfg2 = 0x015500aa;
|
|
if (!pdata->fifo_cfg3)
|
|
pdata->fifo_cfg3 = 0x01f00140;
|
|
break;
|
|
|
|
default:
|
|
BUG();
|
|
}
|
|
|
|
switch (pdata->phy_if_mode) {
|
|
case PHY_INTERFACE_MODE_GMII:
|
|
case PHY_INTERFACE_MODE_RGMII:
|
|
case PHY_INTERFACE_MODE_SGMII:
|
|
if (!pdata->has_gbit) {
|
|
printk(KERN_ERR "ar71xx: no gbit available on eth%d\n",
|
|
id);
|
|
return;
|
|
}
|
|
/* fallthrough */
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!is_valid_ether_addr(pdata->mac_addr)) {
|
|
random_ether_addr(pdata->mac_addr);
|
|
printk(KERN_DEBUG
|
|
"ar71xx: using random MAC address for eth%d\n",
|
|
ath79_eth_instance);
|
|
}
|
|
|
|
if (pdata->mii_bus_dev == NULL) {
|
|
switch (ath79_soc) {
|
|
case ATH79_SOC_AR9341:
|
|
case ATH79_SOC_AR9342:
|
|
case ATH79_SOC_AR9344:
|
|
if (id == 0)
|
|
pdata->mii_bus_dev = &ath79_mdio0_device.dev;
|
|
else
|
|
pdata->mii_bus_dev = &ath79_mdio1_device.dev;
|
|
break;
|
|
|
|
case ATH79_SOC_AR7241:
|
|
case ATH79_SOC_AR9330:
|
|
case ATH79_SOC_AR9331:
|
|
case ATH79_SOC_QCA9533:
|
|
case ATH79_SOC_TP9343:
|
|
pdata->mii_bus_dev = &ath79_mdio1_device.dev;
|
|
break;
|
|
|
|
case ATH79_SOC_QCA9556:
|
|
case ATH79_SOC_QCA9558:
|
|
/* don't assign any MDIO device by default */
|
|
break;
|
|
|
|
case ATH79_SOC_QCA956X:
|
|
if (pdata->phy_if_mode != PHY_INTERFACE_MODE_SGMII)
|
|
pdata->mii_bus_dev = &ath79_mdio1_device.dev;
|
|
break;
|
|
|
|
default:
|
|
pdata->mii_bus_dev = &ath79_mdio0_device.dev;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Reset the device */
|
|
ath79_device_reset_set(pdata->reset_bit);
|
|
msleep(100);
|
|
|
|
ath79_device_reset_clear(pdata->reset_bit);
|
|
msleep(100);
|
|
|
|
platform_device_register(pdev);
|
|
ath79_eth_instance++;
|
|
}
|
|
|
|
void __init ath79_set_mac_base(unsigned char *mac)
|
|
{
|
|
memcpy(ath79_mac_base, mac, ETH_ALEN);
|
|
}
|
|
|
|
void __init ath79_parse_ascii_mac(char *mac_str, u8 *mac)
|
|
{
|
|
int t;
|
|
|
|
t = sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
|
|
&mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
|
|
|
|
if (t != ETH_ALEN)
|
|
t = sscanf(mac_str, "%02hhx.%02hhx.%02hhx.%02hhx.%02hhx.%02hhx",
|
|
&mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
|
|
|
|
if (t != ETH_ALEN || !is_valid_ether_addr(mac)) {
|
|
memset(mac, 0, ETH_ALEN);
|
|
printk(KERN_DEBUG "ar71xx: invalid mac address \"%s\"\n",
|
|
mac_str);
|
|
}
|
|
}
|
|
|
|
static void __init ath79_set_mac_base_ascii(char *str)
|
|
{
|
|
u8 mac[ETH_ALEN];
|
|
|
|
ath79_parse_ascii_mac(str, mac);
|
|
ath79_set_mac_base(mac);
|
|
}
|
|
|
|
static int __init ath79_ethaddr_setup(char *str)
|
|
{
|
|
ath79_set_mac_base_ascii(str);
|
|
return 1;
|
|
}
|
|
__setup("ethaddr=", ath79_ethaddr_setup);
|
|
|
|
static int __init ath79_kmac_setup(char *str)
|
|
{
|
|
ath79_set_mac_base_ascii(str);
|
|
return 1;
|
|
}
|
|
__setup("kmac=", ath79_kmac_setup);
|
|
|
|
void __init ath79_init_mac(unsigned char *dst, const unsigned char *src,
|
|
int offset)
|
|
{
|
|
int t;
|
|
|
|
if (!dst)
|
|
return;
|
|
|
|
if (!src || !is_valid_ether_addr(src)) {
|
|
memset(dst, '\0', ETH_ALEN);
|
|
return;
|
|
}
|
|
|
|
t = (((u32) src[3]) << 16) + (((u32) src[4]) << 8) + ((u32) src[5]);
|
|
t += offset;
|
|
|
|
dst[0] = src[0];
|
|
dst[1] = src[1];
|
|
dst[2] = src[2];
|
|
dst[3] = (t >> 16) & 0xff;
|
|
dst[4] = (t >> 8) & 0xff;
|
|
dst[5] = t & 0xff;
|
|
}
|
|
|
|
void __init ath79_init_local_mac(unsigned char *dst, const unsigned char *src)
|
|
{
|
|
int i;
|
|
|
|
if (!dst)
|
|
return;
|
|
|
|
if (!src || !is_valid_ether_addr(src)) {
|
|
memset(dst, '\0', ETH_ALEN);
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < ETH_ALEN; i++)
|
|
dst[i] = src[i];
|
|
dst[0] |= 0x02;
|
|
}
|