forked from luck/tmp_suning_uos_patched
net: dsa: b53: Add support for Broadcom RoboSwitch
This patch adds support for Broadcom's BCM53xx switch family, also known as RoboSwitch. Some of these switches are ubiquituous, found in home routers, Wi-Fi routers, DSL and cable modem gateways and other networking related products. This drivers adds the library driver (b53_common.c) as well as a few bus glue drivers for MDIO, SPI, Switch Register Access Block (SRAB) and memory-mapped I/O into a SoC's address space (Broadcom BCM63xx/33xx). Basic operations are supported to bring the Layer 1/2 up and running, but not much more at this point, subsequent patches add the remaining features. Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
409a5f27ed
commit
967dd82ffc
88
Documentation/devicetree/bindings/net/dsa/b53.txt
Normal file
88
Documentation/devicetree/bindings/net/dsa/b53.txt
Normal file
|
@ -0,0 +1,88 @@
|
|||
Broadcom BCM53xx Ethernet switches
|
||||
==================================
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: For external switch chips, compatible string must be exactly one
|
||||
of: "brcm,bcm5325"
|
||||
"brcm,bcm53115"
|
||||
"brcm,bcm53125"
|
||||
"brcm,bcm53128"
|
||||
"brcm,bcm5365"
|
||||
"brcm,bcm5395"
|
||||
"brcm,bcm5397"
|
||||
"brcm,bcm5398"
|
||||
|
||||
For the BCM5310x SoCs with an integrated switch, must be one of:
|
||||
"brcm,bcm53010-srab"
|
||||
"brcm,bcm53011-srab"
|
||||
"brcm,bcm53012-srab"
|
||||
"brcm,bcm53018-srab"
|
||||
"brcm,bcm53019-srab" and the mandatory "brcm,bcm5301x-srab" string
|
||||
|
||||
For the BCM63xx/33xx SoCs with an integrated switch, must be one of:
|
||||
"brcm,bcm3384-switch"
|
||||
"brcm,bcm6328-switch"
|
||||
"brcm,bcm6368-switch" and the mandatory "brcm,bcm63xx-switch"
|
||||
|
||||
See Documentation/devicetree/bindings/dsa/dsa.txt for a list of additional
|
||||
required and optional properties.
|
||||
|
||||
Examples:
|
||||
|
||||
Ethernet switch connected via MDIO to the host, CPU port wired to eth0:
|
||||
|
||||
eth0: ethernet@10001000 {
|
||||
compatible = "brcm,unimac";
|
||||
reg = <0x10001000 0x1000>;
|
||||
|
||||
fixed-link {
|
||||
speed = <1000>;
|
||||
duplex-full;
|
||||
};
|
||||
};
|
||||
|
||||
mdio0: mdio@10000000 {
|
||||
compatible = "brcm,unimac-mdio";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
switch0: ethernet-switch@30 {
|
||||
compatible = "brcm,bcm53125";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ports {
|
||||
port0@0 {
|
||||
reg = <0>;
|
||||
label = "lan1";
|
||||
};
|
||||
|
||||
port1@1 {
|
||||
reg = <1>;
|
||||
label = "lan2";
|
||||
};
|
||||
|
||||
port5@5 {
|
||||
reg = <5>;
|
||||
label = "cable-modem";
|
||||
fixed-link {
|
||||
speed = <1000>;
|
||||
duplex-full;
|
||||
};
|
||||
phy-mode = "rgmii-txid";
|
||||
};
|
||||
|
||||
port8@8 {
|
||||
reg = <8>;
|
||||
label = "cpu";
|
||||
fixed-link {
|
||||
speed = <1000>;
|
||||
duplex-full;
|
||||
};
|
||||
phy-mode = "rgmii-txid";
|
||||
ethernet = <ð0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -2454,6 +2454,14 @@ L: netdev@vger.kernel.org
|
|||
S: Supported
|
||||
F: drivers/net/ethernet/broadcom/b44.*
|
||||
|
||||
BROADCOM B53 ETHERNET SWITCH DRIVER
|
||||
M: Florian Fainelli <f.fainelli@gmail.com>
|
||||
L: netdev@vger.kernel.org
|
||||
L: openwrt-devel@lists.openwrt.org (subscribers-only)
|
||||
S: Supported
|
||||
F: drivers/net/dsa/b53/*
|
||||
F: include/linux/platform_data/b53.h
|
||||
|
||||
BROADCOM GENET ETHERNET DRIVER
|
||||
M: Florian Fainelli <f.fainelli@gmail.com>
|
||||
L: netdev@vger.kernel.org
|
||||
|
|
|
@ -28,4 +28,6 @@ config NET_DSA_BCM_SF2
|
|||
This enables support for the Broadcom Starfighter 2 Ethernet
|
||||
switch chips.
|
||||
|
||||
source "drivers/net/dsa/b53/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
|
||||
obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx.o
|
||||
obj-$(CONFIG_NET_DSA_BCM_SF2) += bcm_sf2.o
|
||||
|
||||
obj-y += b53/
|
||||
|
|
33
drivers/net/dsa/b53/Kconfig
Normal file
33
drivers/net/dsa/b53/Kconfig
Normal file
|
@ -0,0 +1,33 @@
|
|||
menuconfig B53
|
||||
tristate "Broadcom BCM53xx managed switch support"
|
||||
depends on NET_DSA
|
||||
help
|
||||
This driver adds support for Broadcom managed switch chips. It supports
|
||||
BCM5325E, BCM5365, BCM539x, BCM53115 and BCM53125 as well as BCM63XX
|
||||
integrated switches.
|
||||
|
||||
config B53_SPI_DRIVER
|
||||
tristate "B53 SPI connected switch driver"
|
||||
depends on B53 && SPI
|
||||
help
|
||||
Select to enable support for registering switches configured through SPI.
|
||||
|
||||
config B53_MDIO_DRIVER
|
||||
tristate "B53 MDIO connected switch driver"
|
||||
depends on B53
|
||||
help
|
||||
Select to enable support for registering switches configured through MDIO.
|
||||
|
||||
config B53_MMAP_DRIVER
|
||||
tristate "B53 MMAP connected switch driver"
|
||||
depends on B53 && HAS_IOMEM
|
||||
help
|
||||
Select to enable support for memory-mapped switches like the BCM63XX
|
||||
integrated switches.
|
||||
|
||||
config B53_SRAB_DRIVER
|
||||
tristate "B53 SRAB connected switch driver"
|
||||
depends on B53 && HAS_IOMEM
|
||||
help
|
||||
Select to enable support for memory-mapped Switch Register Access
|
||||
Bridge Registers (SRAB) like it is found on the BCM53010
|
6
drivers/net/dsa/b53/Makefile
Normal file
6
drivers/net/dsa/b53/Makefile
Normal file
|
@ -0,0 +1,6 @@
|
|||
obj-$(CONFIG_B53) += b53_common.o
|
||||
|
||||
obj-$(CONFIG_B53_SPI_DRIVER) += b53_spi.o
|
||||
obj-$(CONFIG_B53_MDIO_DRIVER) += b53_mdio.o
|
||||
obj-$(CONFIG_B53_MMAP_DRIVER) += b53_mmap.o
|
||||
obj-$(CONFIG_B53_SRAB_DRIVER) += b53_srab.o
|
1158
drivers/net/dsa/b53/b53_common.c
Normal file
1158
drivers/net/dsa/b53/b53_common.c
Normal file
File diff suppressed because it is too large
Load Diff
381
drivers/net/dsa/b53/b53_mdio.c
Normal file
381
drivers/net/dsa/b53/b53_mdio.c
Normal file
|
@ -0,0 +1,381 @@
|
|||
/*
|
||||
* B53 register access through MII registers
|
||||
*
|
||||
* Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/brcmphy.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/dsa.h>
|
||||
|
||||
#include "b53_priv.h"
|
||||
|
||||
/* MII registers */
|
||||
#define REG_MII_PAGE 0x10 /* MII Page register */
|
||||
#define REG_MII_ADDR 0x11 /* MII Address register */
|
||||
#define REG_MII_DATA0 0x18 /* MII Data register 0 */
|
||||
#define REG_MII_DATA1 0x19 /* MII Data register 1 */
|
||||
#define REG_MII_DATA2 0x1a /* MII Data register 2 */
|
||||
#define REG_MII_DATA3 0x1b /* MII Data register 3 */
|
||||
|
||||
#define REG_MII_PAGE_ENABLE BIT(0)
|
||||
#define REG_MII_ADDR_WRITE BIT(0)
|
||||
#define REG_MII_ADDR_READ BIT(1)
|
||||
|
||||
static int b53_mdio_op(struct b53_device *dev, u8 page, u8 reg, u16 op)
|
||||
{
|
||||
int i;
|
||||
u16 v;
|
||||
int ret;
|
||||
struct mii_bus *bus = dev->priv;
|
||||
|
||||
if (dev->current_page != page) {
|
||||
/* set page number */
|
||||
v = (page << 8) | REG_MII_PAGE_ENABLE;
|
||||
ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
|
||||
REG_MII_PAGE, v);
|
||||
if (ret)
|
||||
return ret;
|
||||
dev->current_page = page;
|
||||
}
|
||||
|
||||
/* set register address */
|
||||
v = (reg << 8) | op;
|
||||
ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, REG_MII_ADDR, v);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* check if operation completed */
|
||||
for (i = 0; i < 5; ++i) {
|
||||
v = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR,
|
||||
REG_MII_ADDR);
|
||||
if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ)))
|
||||
break;
|
||||
usleep_range(10, 100);
|
||||
}
|
||||
|
||||
if (WARN_ON(i == 5))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mdio_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
int ret;
|
||||
|
||||
ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR,
|
||||
REG_MII_DATA0) & 0xff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mdio_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
int ret;
|
||||
|
||||
ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, REG_MII_DATA0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mdio_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
int ret;
|
||||
|
||||
ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, REG_MII_DATA0);
|
||||
*val |= mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR,
|
||||
REG_MII_DATA1) << 16;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mdio_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
u64 temp = 0;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 2; i >= 0; i--) {
|
||||
temp <<= 16;
|
||||
temp |= mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR,
|
||||
REG_MII_DATA0 + i);
|
||||
}
|
||||
|
||||
*val = temp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mdio_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
u64 temp = 0;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 3; i >= 0; i--) {
|
||||
temp <<= 16;
|
||||
temp |= mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR,
|
||||
REG_MII_DATA0 + i);
|
||||
}
|
||||
|
||||
*val = temp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mdio_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
int ret;
|
||||
|
||||
ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
|
||||
REG_MII_DATA0, value);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
|
||||
}
|
||||
|
||||
static int b53_mdio_write16(struct b53_device *dev, u8 page, u8 reg,
|
||||
u16 value)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
int ret;
|
||||
|
||||
ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
|
||||
REG_MII_DATA0, value);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
|
||||
}
|
||||
|
||||
static int b53_mdio_write32(struct b53_device *dev, u8 page, u8 reg,
|
||||
u32 value)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
unsigned int i;
|
||||
u32 temp = value;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
int ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
|
||||
REG_MII_DATA0 + i,
|
||||
temp & 0xffff);
|
||||
if (ret)
|
||||
return ret;
|
||||
temp >>= 16;
|
||||
}
|
||||
|
||||
return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
|
||||
}
|
||||
|
||||
static int b53_mdio_write48(struct b53_device *dev, u8 page, u8 reg,
|
||||
u64 value)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
unsigned int i;
|
||||
u64 temp = value;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
int ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
|
||||
REG_MII_DATA0 + i,
|
||||
temp & 0xffff);
|
||||
if (ret)
|
||||
return ret;
|
||||
temp >>= 16;
|
||||
}
|
||||
|
||||
return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
|
||||
}
|
||||
|
||||
static int b53_mdio_write64(struct b53_device *dev, u8 page, u8 reg,
|
||||
u64 value)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
unsigned int i;
|
||||
u64 temp = value;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
int ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
|
||||
REG_MII_DATA0 + i,
|
||||
temp & 0xffff);
|
||||
if (ret)
|
||||
return ret;
|
||||
temp >>= 16;
|
||||
}
|
||||
|
||||
return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
|
||||
}
|
||||
|
||||
static int b53_mdio_phy_read16(struct b53_device *dev, int addr, int reg,
|
||||
u16 *value)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
|
||||
*value = mdiobus_read_nested(bus, addr, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mdio_phy_write16(struct b53_device *dev, int addr, int reg,
|
||||
u16 value)
|
||||
{
|
||||
struct mii_bus *bus = dev->bus;
|
||||
|
||||
return mdiobus_write_nested(bus, addr, reg, value);
|
||||
}
|
||||
|
||||
static struct b53_io_ops b53_mdio_ops = {
|
||||
.read8 = b53_mdio_read8,
|
||||
.read16 = b53_mdio_read16,
|
||||
.read32 = b53_mdio_read32,
|
||||
.read48 = b53_mdio_read48,
|
||||
.read64 = b53_mdio_read64,
|
||||
.write8 = b53_mdio_write8,
|
||||
.write16 = b53_mdio_write16,
|
||||
.write32 = b53_mdio_write32,
|
||||
.write48 = b53_mdio_write48,
|
||||
.write64 = b53_mdio_write64,
|
||||
.phy_read16 = b53_mdio_phy_read16,
|
||||
.phy_write16 = b53_mdio_phy_write16,
|
||||
};
|
||||
|
||||
#define B53_BRCM_OUI_1 0x0143bc00
|
||||
#define B53_BRCM_OUI_2 0x03625c00
|
||||
#define B53_BRCM_OUI_3 0x00406000
|
||||
|
||||
static int b53_mdio_probe(struct mdio_device *mdiodev)
|
||||
{
|
||||
struct b53_device *dev;
|
||||
u32 phy_id;
|
||||
int ret;
|
||||
|
||||
/* allow the generic PHY driver to take over the non-management MDIO
|
||||
* addresses
|
||||
*/
|
||||
if (mdiodev->addr != BRCM_PSEUDO_PHY_ADDR && mdiodev->addr != 0) {
|
||||
dev_err(&mdiodev->dev, "leaving address %d to PHY\n",
|
||||
mdiodev->addr);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* read the first port's id */
|
||||
phy_id = mdiobus_read(mdiodev->bus, 0, 2) << 16;
|
||||
phy_id |= mdiobus_read(mdiodev->bus, 0, 3);
|
||||
|
||||
/* BCM5325, BCM539x (OUI_1)
|
||||
* BCM53125, BCM53128 (OUI_2)
|
||||
* BCM5365 (OUI_3)
|
||||
*/
|
||||
if ((phy_id & 0xfffffc00) != B53_BRCM_OUI_1 &&
|
||||
(phy_id & 0xfffffc00) != B53_BRCM_OUI_2 &&
|
||||
(phy_id & 0xfffffc00) != B53_BRCM_OUI_3) {
|
||||
dev_err(&mdiodev->dev, "Unsupported device: 0x%08x\n", phy_id);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev = b53_switch_alloc(&mdiodev->dev, &b53_mdio_ops, mdiodev->bus);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
/* we don't use page 0xff, so force a page set */
|
||||
dev->current_page = 0xff;
|
||||
dev->bus = mdiodev->bus;
|
||||
|
||||
dev_set_drvdata(&mdiodev->dev, dev);
|
||||
|
||||
ret = b53_switch_register(dev);
|
||||
if (ret) {
|
||||
dev_err(&mdiodev->dev, "failed to register switch: %i\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void b53_mdio_remove(struct mdio_device *mdiodev)
|
||||
{
|
||||
struct b53_device *dev = dev_get_drvdata(&mdiodev->dev);
|
||||
struct dsa_switch *ds = dev->ds;
|
||||
|
||||
dsa_unregister_switch(ds);
|
||||
}
|
||||
|
||||
static const struct of_device_id b53_of_match[] = {
|
||||
{ .compatible = "brcm,bcm5325" },
|
||||
{ .compatible = "brcm,bcm53115" },
|
||||
{ .compatible = "brcm,bcm53125" },
|
||||
{ .compatible = "brcm,bcm53128" },
|
||||
{ .compatible = "brcm,bcm5365" },
|
||||
{ .compatible = "brcm,bcm5395" },
|
||||
{ .compatible = "brcm,bcm5397" },
|
||||
{ .compatible = "brcm,bcm5398" },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, b53_of_match);
|
||||
|
||||
static struct mdio_driver b53_mdio_driver = {
|
||||
.probe = b53_mdio_probe,
|
||||
.remove = b53_mdio_remove,
|
||||
.mdiodrv.driver = {
|
||||
.name = "bcm53xx",
|
||||
.of_match_table = b53_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init b53_mdio_driver_register(void)
|
||||
{
|
||||
return mdio_driver_register(&b53_mdio_driver);
|
||||
}
|
||||
module_init(b53_mdio_driver_register);
|
||||
|
||||
static void __exit b53_mdio_driver_unregister(void)
|
||||
{
|
||||
mdio_driver_unregister(&b53_mdio_driver);
|
||||
}
|
||||
module_exit(b53_mdio_driver_unregister);
|
||||
|
||||
MODULE_DESCRIPTION("B53 MDIO access driver");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
260
drivers/net/dsa/b53/b53_mmap.c
Normal file
260
drivers/net/dsa/b53/b53_mmap.c
Normal file
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* B53 register access through memory mapped registers
|
||||
*
|
||||
* Copyright (C) 2012-2013 Jonas Gorski <jogo@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kconfig.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/b53.h>
|
||||
|
||||
#include "b53_priv.h"
|
||||
|
||||
struct b53_mmap_priv {
|
||||
void __iomem *regs;
|
||||
};
|
||||
|
||||
static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
|
||||
*val = readb(regs + (page << 8) + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
|
||||
if (WARN_ON(reg % 2))
|
||||
return -EINVAL;
|
||||
|
||||
if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && dev->pdata &&
|
||||
dev->pdata->big_endian)
|
||||
*val = __raw_readw(regs + (page << 8) + reg);
|
||||
else
|
||||
*val = readw(regs + (page << 8) + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
|
||||
if (WARN_ON(reg % 4))
|
||||
return -EINVAL;
|
||||
|
||||
if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && dev->pdata &&
|
||||
dev->pdata->big_endian)
|
||||
*val = __raw_readl(regs + (page << 8) + reg);
|
||||
else
|
||||
*val = readl(regs + (page << 8) + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
|
||||
{
|
||||
if (WARN_ON(reg % 2))
|
||||
return -EINVAL;
|
||||
|
||||
if (reg % 4) {
|
||||
u16 lo;
|
||||
u32 hi;
|
||||
|
||||
b53_mmap_read16(dev, page, reg, &lo);
|
||||
b53_mmap_read32(dev, page, reg + 2, &hi);
|
||||
|
||||
*val = ((u64)hi << 16) | lo;
|
||||
} else {
|
||||
u32 lo;
|
||||
u16 hi;
|
||||
|
||||
b53_mmap_read32(dev, page, reg, &lo);
|
||||
b53_mmap_read16(dev, page, reg + 4, &hi);
|
||||
|
||||
*val = ((u64)hi << 32) | lo;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
|
||||
{
|
||||
u32 hi, lo;
|
||||
|
||||
if (WARN_ON(reg % 4))
|
||||
return -EINVAL;
|
||||
|
||||
b53_mmap_read32(dev, page, reg, &lo);
|
||||
b53_mmap_read32(dev, page, reg + 4, &hi);
|
||||
|
||||
*val = ((u64)hi << 32) | lo;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
|
||||
writeb(value, regs + (page << 8) + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg,
|
||||
u16 value)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
|
||||
if (WARN_ON(reg % 2))
|
||||
return -EINVAL;
|
||||
|
||||
if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && dev->pdata &&
|
||||
dev->pdata->big_endian)
|
||||
__raw_writew(value, regs + (page << 8) + reg);
|
||||
else
|
||||
writew(value, regs + (page << 8) + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mmap_write32(struct b53_device *dev, u8 page, u8 reg,
|
||||
u32 value)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
|
||||
if (WARN_ON(reg % 4))
|
||||
return -EINVAL;
|
||||
|
||||
if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && dev->pdata &&
|
||||
dev->pdata->big_endian)
|
||||
__raw_writel(value, regs + (page << 8) + reg);
|
||||
else
|
||||
writel(value, regs + (page << 8) + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mmap_write48(struct b53_device *dev, u8 page, u8 reg,
|
||||
u64 value)
|
||||
{
|
||||
if (WARN_ON(reg % 2))
|
||||
return -EINVAL;
|
||||
|
||||
if (reg % 4) {
|
||||
u32 hi = (u32)(value >> 16);
|
||||
u16 lo = (u16)value;
|
||||
|
||||
b53_mmap_write16(dev, page, reg, lo);
|
||||
b53_mmap_write32(dev, page, reg + 2, hi);
|
||||
} else {
|
||||
u16 hi = (u16)(value >> 32);
|
||||
u32 lo = (u32)value;
|
||||
|
||||
b53_mmap_write32(dev, page, reg, lo);
|
||||
b53_mmap_write16(dev, page, reg + 4, hi);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mmap_write64(struct b53_device *dev, u8 page, u8 reg,
|
||||
u64 value)
|
||||
{
|
||||
u32 hi, lo;
|
||||
|
||||
hi = upper_32_bits(value);
|
||||
lo = lower_32_bits(value);
|
||||
|
||||
if (WARN_ON(reg % 4))
|
||||
return -EINVAL;
|
||||
|
||||
b53_mmap_write32(dev, page, reg, lo);
|
||||
b53_mmap_write32(dev, page, reg + 4, hi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct b53_io_ops b53_mmap_ops = {
|
||||
.read8 = b53_mmap_read8,
|
||||
.read16 = b53_mmap_read16,
|
||||
.read32 = b53_mmap_read32,
|
||||
.read48 = b53_mmap_read48,
|
||||
.read64 = b53_mmap_read64,
|
||||
.write8 = b53_mmap_write8,
|
||||
.write16 = b53_mmap_write16,
|
||||
.write32 = b53_mmap_write32,
|
||||
.write48 = b53_mmap_write48,
|
||||
.write64 = b53_mmap_write64,
|
||||
};
|
||||
|
||||
static int b53_mmap_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct b53_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct b53_device *dev;
|
||||
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
|
||||
dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, pdata->regs);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
if (pdata)
|
||||
dev->pdata = pdata;
|
||||
|
||||
platform_set_drvdata(pdev, dev);
|
||||
|
||||
return b53_switch_register(dev);
|
||||
}
|
||||
|
||||
static int b53_mmap_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct b53_device *dev = platform_get_drvdata(pdev);
|
||||
|
||||
if (dev)
|
||||
b53_switch_remove(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id b53_mmap_of_table[] = {
|
||||
{ .compatible = "brcm,bcm3384-switch" },
|
||||
{ .compatible = "brcm,bcm6328-switch" },
|
||||
{ .compatible = "brcm,bcm6368-switch" },
|
||||
{ .compatible = "brcm,bcm63xx-switch" },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static struct platform_driver b53_mmap_driver = {
|
||||
.probe = b53_mmap_probe,
|
||||
.remove = b53_mmap_remove,
|
||||
.driver = {
|
||||
.name = "b53-switch",
|
||||
.of_match_table = b53_mmap_of_table,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(b53_mmap_driver);
|
||||
MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
|
||||
MODULE_DESCRIPTION("B53 MMAP access driver");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
322
drivers/net/dsa/b53/b53_priv.h
Normal file
322
drivers/net/dsa/b53/b53_priv.h
Normal file
|
@ -0,0 +1,322 @@
|
|||
/*
|
||||
* B53 common definitions
|
||||
*
|
||||
* Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __B53_PRIV_H
|
||||
#define __B53_PRIV_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/phy.h>
|
||||
#include <net/dsa.h>
|
||||
|
||||
struct b53_device;
|
||||
|
||||
struct b53_io_ops {
|
||||
int (*read8)(struct b53_device *dev, u8 page, u8 reg, u8 *value);
|
||||
int (*read16)(struct b53_device *dev, u8 page, u8 reg, u16 *value);
|
||||
int (*read32)(struct b53_device *dev, u8 page, u8 reg, u32 *value);
|
||||
int (*read48)(struct b53_device *dev, u8 page, u8 reg, u64 *value);
|
||||
int (*read64)(struct b53_device *dev, u8 page, u8 reg, u64 *value);
|
||||
int (*write8)(struct b53_device *dev, u8 page, u8 reg, u8 value);
|
||||
int (*write16)(struct b53_device *dev, u8 page, u8 reg, u16 value);
|
||||
int (*write32)(struct b53_device *dev, u8 page, u8 reg, u32 value);
|
||||
int (*write48)(struct b53_device *dev, u8 page, u8 reg, u64 value);
|
||||
int (*write64)(struct b53_device *dev, u8 page, u8 reg, u64 value);
|
||||
int (*phy_read16)(struct b53_device *dev, int addr, int reg, u16 *value);
|
||||
int (*phy_write16)(struct b53_device *dev, int addr, int reg, u16 value);
|
||||
};
|
||||
|
||||
enum {
|
||||
BCM5325_DEVICE_ID = 0x25,
|
||||
BCM5365_DEVICE_ID = 0x65,
|
||||
BCM5395_DEVICE_ID = 0x95,
|
||||
BCM5397_DEVICE_ID = 0x97,
|
||||
BCM5398_DEVICE_ID = 0x98,
|
||||
BCM53115_DEVICE_ID = 0x53115,
|
||||
BCM53125_DEVICE_ID = 0x53125,
|
||||
BCM53128_DEVICE_ID = 0x53128,
|
||||
BCM63XX_DEVICE_ID = 0x6300,
|
||||
BCM53010_DEVICE_ID = 0x53010,
|
||||
BCM53011_DEVICE_ID = 0x53011,
|
||||
BCM53012_DEVICE_ID = 0x53012,
|
||||
BCM53018_DEVICE_ID = 0x53018,
|
||||
BCM53019_DEVICE_ID = 0x53019,
|
||||
};
|
||||
|
||||
#define B53_N_PORTS 9
|
||||
#define B53_N_PORTS_25 6
|
||||
|
||||
struct b53_port {
|
||||
};
|
||||
|
||||
struct b53_device {
|
||||
struct dsa_switch *ds;
|
||||
struct b53_platform_data *pdata;
|
||||
const char *name;
|
||||
|
||||
struct mutex reg_mutex;
|
||||
struct mutex stats_mutex;
|
||||
const struct b53_io_ops *ops;
|
||||
|
||||
/* chip specific data */
|
||||
u32 chip_id;
|
||||
u8 core_rev;
|
||||
u8 vta_regs[3];
|
||||
u8 duplex_reg;
|
||||
u8 jumbo_pm_reg;
|
||||
u8 jumbo_size_reg;
|
||||
int reset_gpio;
|
||||
|
||||
/* used ports mask */
|
||||
u16 enabled_ports;
|
||||
unsigned int cpu_port;
|
||||
|
||||
/* connect specific data */
|
||||
u8 current_page;
|
||||
struct device *dev;
|
||||
|
||||
/* Master MDIO bus we got probed from */
|
||||
struct mii_bus *bus;
|
||||
|
||||
/* Slave MDIO bus we created */
|
||||
struct mii_bus *slave_bus;
|
||||
void *priv;
|
||||
|
||||
/* run time configuration */
|
||||
unsigned enable_jumbo:1;
|
||||
unsigned allow_vid_4095:1;
|
||||
unsigned int num_vlans;
|
||||
unsigned int num_ports;
|
||||
struct b53_port *ports;
|
||||
};
|
||||
|
||||
#define b53_for_each_port(dev, i) \
|
||||
for (i = 0; i < B53_N_PORTS; i++) \
|
||||
if (dev->enabled_ports & BIT(i))
|
||||
|
||||
|
||||
static inline int is5325(struct b53_device *dev)
|
||||
{
|
||||
return dev->chip_id == BCM5325_DEVICE_ID;
|
||||
}
|
||||
|
||||
static inline int is5365(struct b53_device *dev)
|
||||
{
|
||||
#ifdef CONFIG_BCM47XX
|
||||
return dev->chip_id == BCM5365_DEVICE_ID;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int is5397_98(struct b53_device *dev)
|
||||
{
|
||||
return dev->chip_id == BCM5397_DEVICE_ID ||
|
||||
dev->chip_id == BCM5398_DEVICE_ID;
|
||||
}
|
||||
|
||||
static inline int is539x(struct b53_device *dev)
|
||||
{
|
||||
return dev->chip_id == BCM5395_DEVICE_ID ||
|
||||
dev->chip_id == BCM5397_DEVICE_ID ||
|
||||
dev->chip_id == BCM5398_DEVICE_ID;
|
||||
}
|
||||
|
||||
static inline int is531x5(struct b53_device *dev)
|
||||
{
|
||||
return dev->chip_id == BCM53115_DEVICE_ID ||
|
||||
dev->chip_id == BCM53125_DEVICE_ID ||
|
||||
dev->chip_id == BCM53128_DEVICE_ID;
|
||||
}
|
||||
|
||||
static inline int is63xx(struct b53_device *dev)
|
||||
{
|
||||
#ifdef CONFIG_BCM63XX
|
||||
return dev->chip_id == BCM63XX_DEVICE_ID;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int is5301x(struct b53_device *dev)
|
||||
{
|
||||
return dev->chip_id == BCM53010_DEVICE_ID ||
|
||||
dev->chip_id == BCM53011_DEVICE_ID ||
|
||||
dev->chip_id == BCM53012_DEVICE_ID ||
|
||||
dev->chip_id == BCM53018_DEVICE_ID ||
|
||||
dev->chip_id == BCM53019_DEVICE_ID;
|
||||
}
|
||||
|
||||
#define B53_CPU_PORT_25 5
|
||||
#define B53_CPU_PORT 8
|
||||
|
||||
static inline int is_cpu_port(struct b53_device *dev, int port)
|
||||
{
|
||||
return dev->cpu_port;
|
||||
}
|
||||
|
||||
struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops,
|
||||
void *priv);
|
||||
|
||||
int b53_switch_detect(struct b53_device *dev);
|
||||
|
||||
int b53_switch_register(struct b53_device *dev);
|
||||
|
||||
static inline void b53_switch_remove(struct b53_device *dev)
|
||||
{
|
||||
dsa_unregister_switch(dev->ds);
|
||||
}
|
||||
|
||||
static inline int b53_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->reg_mutex);
|
||||
ret = dev->ops->read8(dev, page, reg, val);
|
||||
mutex_unlock(&dev->reg_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int b53_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->reg_mutex);
|
||||
ret = dev->ops->read16(dev, page, reg, val);
|
||||
mutex_unlock(&dev->reg_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int b53_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->reg_mutex);
|
||||
ret = dev->ops->read32(dev, page, reg, val);
|
||||
mutex_unlock(&dev->reg_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int b53_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->reg_mutex);
|
||||
ret = dev->ops->read48(dev, page, reg, val);
|
||||
mutex_unlock(&dev->reg_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int b53_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->reg_mutex);
|
||||
ret = dev->ops->read64(dev, page, reg, val);
|
||||
mutex_unlock(&dev->reg_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int b53_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->reg_mutex);
|
||||
ret = dev->ops->write8(dev, page, reg, value);
|
||||
mutex_unlock(&dev->reg_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int b53_write16(struct b53_device *dev, u8 page, u8 reg,
|
||||
u16 value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->reg_mutex);
|
||||
ret = dev->ops->write16(dev, page, reg, value);
|
||||
mutex_unlock(&dev->reg_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int b53_write32(struct b53_device *dev, u8 page, u8 reg,
|
||||
u32 value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->reg_mutex);
|
||||
ret = dev->ops->write32(dev, page, reg, value);
|
||||
mutex_unlock(&dev->reg_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int b53_write48(struct b53_device *dev, u8 page, u8 reg,
|
||||
u64 value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->reg_mutex);
|
||||
ret = dev->ops->write48(dev, page, reg, value);
|
||||
mutex_unlock(&dev->reg_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int b53_write64(struct b53_device *dev, u8 page, u8 reg,
|
||||
u64 value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->reg_mutex);
|
||||
ret = dev->ops->write64(dev, page, reg, value);
|
||||
mutex_unlock(&dev->reg_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BCM47XX
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/bcm47xx_nvram.h>
|
||||
#include <bcm47xx_board.h>
|
||||
static inline int b53_switch_get_reset_gpio(struct b53_device *dev)
|
||||
{
|
||||
enum bcm47xx_board board = bcm47xx_board_get();
|
||||
|
||||
switch (board) {
|
||||
case BCM47XX_BOARD_LINKSYS_WRT300NV11:
|
||||
case BCM47XX_BOARD_LINKSYS_WRT310NV1:
|
||||
return 8;
|
||||
default:
|
||||
return bcm47xx_nvram_gpio_pin("robo_reset");
|
||||
}
|
||||
}
|
||||
#else
|
||||
static inline int b53_switch_get_reset_gpio(struct b53_device *dev)
|
||||
{
|
||||
return -ENOENT;
|
||||
}
|
||||
#endif
|
||||
#endif
|
358
drivers/net/dsa/b53/b53_regs.h
Normal file
358
drivers/net/dsa/b53/b53_regs.h
Normal file
|
@ -0,0 +1,358 @@
|
|||
/*
|
||||
* B53 register definitions
|
||||
*
|
||||
* Copyright (C) 2004 Broadcom Corporation
|
||||
* Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __B53_REGS_H
|
||||
#define __B53_REGS_H
|
||||
|
||||
/* Management Port (SMP) Page offsets */
|
||||
#define B53_CTRL_PAGE 0x00 /* Control */
|
||||
#define B53_STAT_PAGE 0x01 /* Status */
|
||||
#define B53_MGMT_PAGE 0x02 /* Management Mode */
|
||||
#define B53_MIB_AC_PAGE 0x03 /* MIB Autocast */
|
||||
#define B53_ARLCTRL_PAGE 0x04 /* ARL Control */
|
||||
#define B53_ARLIO_PAGE 0x05 /* ARL Access */
|
||||
#define B53_FRAMEBUF_PAGE 0x06 /* Management frame access */
|
||||
#define B53_MEM_ACCESS_PAGE 0x08 /* Memory access */
|
||||
|
||||
/* PHY Registers */
|
||||
#define B53_PORT_MII_PAGE(i) (0x10 + (i)) /* Port i MII Registers */
|
||||
#define B53_IM_PORT_PAGE 0x18 /* Inverse MII Port (to EMAC) */
|
||||
#define B53_ALL_PORT_PAGE 0x19 /* All ports MII (broadcast) */
|
||||
|
||||
/* MIB registers */
|
||||
#define B53_MIB_PAGE(i) (0x20 + (i))
|
||||
|
||||
/* Quality of Service (QoS) Registers */
|
||||
#define B53_QOS_PAGE 0x30
|
||||
|
||||
/* Port VLAN Page */
|
||||
#define B53_PVLAN_PAGE 0x31
|
||||
|
||||
/* VLAN Registers */
|
||||
#define B53_VLAN_PAGE 0x34
|
||||
|
||||
/* Jumbo Frame Registers */
|
||||
#define B53_JUMBO_PAGE 0x40
|
||||
|
||||
/* CFP Configuration Registers Page */
|
||||
#define B53_CFP_PAGE 0xa1
|
||||
|
||||
/*************************************************************************
|
||||
* Control Page registers
|
||||
*************************************************************************/
|
||||
|
||||
/* Port Control Register (8 bit) */
|
||||
#define B53_PORT_CTRL(i) (0x00 + (i))
|
||||
#define PORT_CTRL_RX_DISABLE BIT(0)
|
||||
#define PORT_CTRL_TX_DISABLE BIT(1)
|
||||
#define PORT_CTRL_RX_BCST_EN BIT(2) /* Broadcast RX (P8 only) */
|
||||
#define PORT_CTRL_RX_MCST_EN BIT(3) /* Multicast RX (P8 only) */
|
||||
#define PORT_CTRL_RX_UCST_EN BIT(4) /* Unicast RX (P8 only) */
|
||||
#define PORT_CTRL_STP_STATE_S 5
|
||||
#define PORT_CTRL_STP_STATE_MASK (0x7 << PORT_CTRL_STP_STATE_S)
|
||||
|
||||
/* SMP Control Register (8 bit) */
|
||||
#define B53_SMP_CTRL 0x0a
|
||||
|
||||
/* Switch Mode Control Register (8 bit) */
|
||||
#define B53_SWITCH_MODE 0x0b
|
||||
#define SM_SW_FWD_MODE BIT(0) /* 1 = Managed Mode */
|
||||
#define SM_SW_FWD_EN BIT(1) /* Forwarding Enable */
|
||||
|
||||
/* IMP Port state override register (8 bit) */
|
||||
#define B53_PORT_OVERRIDE_CTRL 0x0e
|
||||
#define PORT_OVERRIDE_LINK BIT(0)
|
||||
#define PORT_OVERRIDE_FULL_DUPLEX BIT(1) /* 0 = Half Duplex */
|
||||
#define PORT_OVERRIDE_SPEED_S 2
|
||||
#define PORT_OVERRIDE_SPEED_10M (0 << PORT_OVERRIDE_SPEED_S)
|
||||
#define PORT_OVERRIDE_SPEED_100M (1 << PORT_OVERRIDE_SPEED_S)
|
||||
#define PORT_OVERRIDE_SPEED_1000M (2 << PORT_OVERRIDE_SPEED_S)
|
||||
#define PORT_OVERRIDE_RV_MII_25 BIT(4) /* BCM5325 only */
|
||||
#define PORT_OVERRIDE_RX_FLOW BIT(4)
|
||||
#define PORT_OVERRIDE_TX_FLOW BIT(5)
|
||||
#define PORT_OVERRIDE_SPEED_2000M BIT(6) /* BCM5301X only, requires setting 1000M */
|
||||
#define PORT_OVERRIDE_EN BIT(7) /* Use the register contents */
|
||||
|
||||
/* Power-down mode control */
|
||||
#define B53_PD_MODE_CTRL_25 0x0f
|
||||
|
||||
/* IP Multicast control (8 bit) */
|
||||
#define B53_IP_MULTICAST_CTRL 0x21
|
||||
#define B53_IPMC_FWD_EN BIT(1)
|
||||
#define B53_UC_FWD_EN BIT(6)
|
||||
#define B53_MC_FWD_EN BIT(7)
|
||||
|
||||
/* (16 bit) */
|
||||
#define B53_UC_FLOOD_MASK 0x32
|
||||
#define B53_MC_FLOOD_MASK 0x34
|
||||
#define B53_IPMC_FLOOD_MASK 0x36
|
||||
|
||||
/*
|
||||
* Override Ports 0-7 State on devices with xMII interfaces (8 bit)
|
||||
*
|
||||
* For port 8 still use B53_PORT_OVERRIDE_CTRL
|
||||
* Please note that not all ports are available on every hardware, e.g. BCM5301X
|
||||
* don't include overriding port 6, BCM63xx also have some limitations.
|
||||
*/
|
||||
#define B53_GMII_PORT_OVERRIDE_CTRL(i) (0x58 + (i))
|
||||
#define GMII_PO_LINK BIT(0)
|
||||
#define GMII_PO_FULL_DUPLEX BIT(1) /* 0 = Half Duplex */
|
||||
#define GMII_PO_SPEED_S 2
|
||||
#define GMII_PO_SPEED_10M (0 << GMII_PO_SPEED_S)
|
||||
#define GMII_PO_SPEED_100M (1 << GMII_PO_SPEED_S)
|
||||
#define GMII_PO_SPEED_1000M (2 << GMII_PO_SPEED_S)
|
||||
#define GMII_PO_RX_FLOW BIT(4)
|
||||
#define GMII_PO_TX_FLOW BIT(5)
|
||||
#define GMII_PO_EN BIT(6) /* Use the register contents */
|
||||
#define GMII_PO_SPEED_2000M BIT(7) /* BCM5301X only, requires setting 1000M */
|
||||
|
||||
#define B53_RGMII_CTRL_IMP 0x60
|
||||
#define RGMII_CTRL_ENABLE_GMII BIT(7)
|
||||
#define RGMII_CTRL_TIMING_SEL BIT(2)
|
||||
#define RGMII_CTRL_DLL_RXC BIT(1)
|
||||
#define RGMII_CTRL_DLL_TXC BIT(0)
|
||||
|
||||
#define B53_RGMII_CTRL_P(i) (B53_RGMII_CTRL_IMP + (i))
|
||||
|
||||
/* Software reset register (8 bit) */
|
||||
#define B53_SOFTRESET 0x79
|
||||
#define SW_RST BIT(7)
|
||||
#define EN_SW_RST BIT(4)
|
||||
|
||||
/* Fast Aging Control register (8 bit) */
|
||||
#define B53_FAST_AGE_CTRL 0x88
|
||||
#define FAST_AGE_STATIC BIT(0)
|
||||
#define FAST_AGE_DYNAMIC BIT(1)
|
||||
#define FAST_AGE_PORT BIT(2)
|
||||
#define FAST_AGE_VLAN BIT(3)
|
||||
#define FAST_AGE_STP BIT(4)
|
||||
#define FAST_AGE_MC BIT(5)
|
||||
#define FAST_AGE_DONE BIT(7)
|
||||
|
||||
/*************************************************************************
|
||||
* Status Page registers
|
||||
*************************************************************************/
|
||||
|
||||
/* Link Status Summary Register (16bit) */
|
||||
#define B53_LINK_STAT 0x00
|
||||
|
||||
/* Link Status Change Register (16 bit) */
|
||||
#define B53_LINK_STAT_CHANGE 0x02
|
||||
|
||||
/* Port Speed Summary Register (16 bit for FE, 32 bit for GE) */
|
||||
#define B53_SPEED_STAT 0x04
|
||||
#define SPEED_PORT_FE(reg, port) (((reg) >> (port)) & 1)
|
||||
#define SPEED_PORT_GE(reg, port) (((reg) >> 2 * (port)) & 3)
|
||||
#define SPEED_STAT_10M 0
|
||||
#define SPEED_STAT_100M 1
|
||||
#define SPEED_STAT_1000M 2
|
||||
|
||||
/* Duplex Status Summary (16 bit) */
|
||||
#define B53_DUPLEX_STAT_FE 0x06
|
||||
#define B53_DUPLEX_STAT_GE 0x08
|
||||
#define B53_DUPLEX_STAT_63XX 0x0c
|
||||
|
||||
/* Revision ID register for BCM5325 */
|
||||
#define B53_REV_ID_25 0x50
|
||||
|
||||
/* Strap Value (48 bit) */
|
||||
#define B53_STRAP_VALUE 0x70
|
||||
#define SV_GMII_CTRL_115 BIT(27)
|
||||
|
||||
/*************************************************************************
|
||||
* Management Mode Page Registers
|
||||
*************************************************************************/
|
||||
|
||||
/* Global Management Config Register (8 bit) */
|
||||
#define B53_GLOBAL_CONFIG 0x00
|
||||
#define GC_RESET_MIB 0x01
|
||||
#define GC_RX_BPDU_EN 0x02
|
||||
#define GC_MIB_AC_HDR_EN 0x10
|
||||
#define GC_MIB_AC_EN 0x20
|
||||
#define GC_FRM_MGMT_PORT_M 0xC0
|
||||
#define GC_FRM_MGMT_PORT_04 0x00
|
||||
#define GC_FRM_MGMT_PORT_MII 0x80
|
||||
|
||||
/* Broadcom Header control register (8 bit) */
|
||||
#define B53_BRCM_HDR 0x03
|
||||
#define BRCM_HDR_P8_EN BIT(0) /* Enable tagging on port 8 */
|
||||
#define BRCM_HDR_P5_EN BIT(1) /* Enable tagging on port 5 */
|
||||
|
||||
/* Device ID register (8 or 32 bit) */
|
||||
#define B53_DEVICE_ID 0x30
|
||||
|
||||
/* Revision ID register (8 bit) */
|
||||
#define B53_REV_ID 0x40
|
||||
|
||||
/*************************************************************************
|
||||
* ARL Access Page Registers
|
||||
*************************************************************************/
|
||||
|
||||
/* VLAN Table Access Register (8 bit) */
|
||||
#define B53_VT_ACCESS 0x80
|
||||
#define B53_VT_ACCESS_9798 0x60 /* for BCM5397/BCM5398 */
|
||||
#define B53_VT_ACCESS_63XX 0x60 /* for BCM6328/62/68 */
|
||||
#define VTA_CMD_WRITE 0
|
||||
#define VTA_CMD_READ 1
|
||||
#define VTA_CMD_CLEAR 2
|
||||
#define VTA_START_CMD BIT(7)
|
||||
|
||||
/* VLAN Table Index Register (16 bit) */
|
||||
#define B53_VT_INDEX 0x81
|
||||
#define B53_VT_INDEX_9798 0x61
|
||||
#define B53_VT_INDEX_63XX 0x62
|
||||
|
||||
/* VLAN Table Entry Register (32 bit) */
|
||||
#define B53_VT_ENTRY 0x83
|
||||
#define B53_VT_ENTRY_9798 0x63
|
||||
#define B53_VT_ENTRY_63XX 0x64
|
||||
#define VTE_MEMBERS 0x1ff
|
||||
#define VTE_UNTAG_S 9
|
||||
#define VTE_UNTAG (0x1ff << 9)
|
||||
|
||||
/*************************************************************************
|
||||
* Port VLAN Registers
|
||||
*************************************************************************/
|
||||
|
||||
/* Port VLAN mask (16 bit) IMP port is always 8, also on 5325 & co */
|
||||
#define B53_PVLAN_PORT_MASK(i) ((i) * 2)
|
||||
|
||||
/*************************************************************************
|
||||
* 802.1Q Page Registers
|
||||
*************************************************************************/
|
||||
|
||||
/* Global QoS Control (8 bit) */
|
||||
#define B53_QOS_GLOBAL_CTL 0x00
|
||||
|
||||
/* Enable 802.1Q for individual Ports (16 bit) */
|
||||
#define B53_802_1P_EN 0x04
|
||||
|
||||
/*************************************************************************
|
||||
* VLAN Page Registers
|
||||
*************************************************************************/
|
||||
|
||||
/* VLAN Control 0 (8 bit) */
|
||||
#define B53_VLAN_CTRL0 0x00
|
||||
#define VC0_8021PF_CTRL_MASK 0x3
|
||||
#define VC0_8021PF_CTRL_NONE 0x0
|
||||
#define VC0_8021PF_CTRL_CHANGE_PRI 0x1
|
||||
#define VC0_8021PF_CTRL_CHANGE_VID 0x2
|
||||
#define VC0_8021PF_CTRL_CHANGE_BOTH 0x3
|
||||
#define VC0_8021QF_CTRL_MASK 0xc
|
||||
#define VC0_8021QF_CTRL_CHANGE_PRI 0x1
|
||||
#define VC0_8021QF_CTRL_CHANGE_VID 0x2
|
||||
#define VC0_8021QF_CTRL_CHANGE_BOTH 0x3
|
||||
#define VC0_RESERVED_1 BIT(1)
|
||||
#define VC0_DROP_VID_MISS BIT(4)
|
||||
#define VC0_VID_HASH_VID BIT(5)
|
||||
#define VC0_VID_CHK_EN BIT(6) /* Use VID,DA or VID,SA */
|
||||
#define VC0_VLAN_EN BIT(7) /* 802.1Q VLAN Enabled */
|
||||
|
||||
/* VLAN Control 1 (8 bit) */
|
||||
#define B53_VLAN_CTRL1 0x01
|
||||
#define VC1_RX_MCST_TAG_EN BIT(1)
|
||||
#define VC1_RX_MCST_FWD_EN BIT(2)
|
||||
#define VC1_RX_MCST_UNTAG_EN BIT(3)
|
||||
|
||||
/* VLAN Control 2 (8 bit) */
|
||||
#define B53_VLAN_CTRL2 0x02
|
||||
|
||||
/* VLAN Control 3 (8 bit when BCM5325, 16 bit else) */
|
||||
#define B53_VLAN_CTRL3 0x03
|
||||
#define B53_VLAN_CTRL3_63XX 0x04
|
||||
#define VC3_MAXSIZE_1532 BIT(6) /* 5325 only */
|
||||
#define VC3_HIGH_8BIT_EN BIT(7) /* 5325 only */
|
||||
|
||||
/* VLAN Control 4 (8 bit) */
|
||||
#define B53_VLAN_CTRL4 0x05
|
||||
#define B53_VLAN_CTRL4_25 0x04
|
||||
#define B53_VLAN_CTRL4_63XX 0x06
|
||||
#define VC4_ING_VID_CHECK_S 6
|
||||
#define VC4_ING_VID_CHECK_MASK (0x3 << VC4_ING_VID_CHECK_S)
|
||||
#define VC4_ING_VID_VIO_FWD 0 /* forward, but do not learn */
|
||||
#define VC4_ING_VID_VIO_DROP 1 /* drop VID violations */
|
||||
#define VC4_NO_ING_VID_CHK 2 /* do not check */
|
||||
#define VC4_ING_VID_VIO_TO_IMP 3 /* redirect to MII port */
|
||||
|
||||
/* VLAN Control 5 (8 bit) */
|
||||
#define B53_VLAN_CTRL5 0x06
|
||||
#define B53_VLAN_CTRL5_25 0x05
|
||||
#define B53_VLAN_CTRL5_63XX 0x07
|
||||
#define VC5_VID_FFF_EN BIT(2)
|
||||
#define VC5_DROP_VTABLE_MISS BIT(3)
|
||||
|
||||
/* VLAN Control 6 (8 bit) */
|
||||
#define B53_VLAN_CTRL6 0x07
|
||||
#define B53_VLAN_CTRL6_63XX 0x08
|
||||
|
||||
/* VLAN Table Access Register (16 bit) */
|
||||
#define B53_VLAN_TABLE_ACCESS_25 0x06 /* BCM5325E/5350 */
|
||||
#define B53_VLAN_TABLE_ACCESS_65 0x08 /* BCM5365 */
|
||||
#define VTA_VID_LOW_MASK_25 0xf
|
||||
#define VTA_VID_LOW_MASK_65 0xff
|
||||
#define VTA_VID_HIGH_S_25 4
|
||||
#define VTA_VID_HIGH_S_65 8
|
||||
#define VTA_VID_HIGH_MASK_25 (0xff << VTA_VID_HIGH_S_25E)
|
||||
#define VTA_VID_HIGH_MASK_65 (0xf << VTA_VID_HIGH_S_65)
|
||||
#define VTA_RW_STATE BIT(12)
|
||||
#define VTA_RW_STATE_RD 0
|
||||
#define VTA_RW_STATE_WR BIT(12)
|
||||
#define VTA_RW_OP_EN BIT(13)
|
||||
|
||||
/* VLAN Read/Write Registers for (16/32 bit) */
|
||||
#define B53_VLAN_WRITE_25 0x08
|
||||
#define B53_VLAN_WRITE_65 0x0a
|
||||
#define B53_VLAN_READ 0x0c
|
||||
#define VA_MEMBER_MASK 0x3f
|
||||
#define VA_UNTAG_S_25 6
|
||||
#define VA_UNTAG_MASK_25 0x3f
|
||||
#define VA_UNTAG_S_65 7
|
||||
#define VA_UNTAG_MASK_65 0x1f
|
||||
#define VA_VID_HIGH_S 12
|
||||
#define VA_VID_HIGH_MASK (0xffff << VA_VID_HIGH_S)
|
||||
#define VA_VALID_25 BIT(20)
|
||||
#define VA_VALID_25_R4 BIT(24)
|
||||
#define VA_VALID_65 BIT(14)
|
||||
|
||||
/* VLAN Port Default Tag (16 bit) */
|
||||
#define B53_VLAN_PORT_DEF_TAG(i) (0x10 + 2 * (i))
|
||||
|
||||
/*************************************************************************
|
||||
* Jumbo Frame Page Registers
|
||||
*************************************************************************/
|
||||
|
||||
/* Jumbo Enable Port Mask (bit i == port i enabled) (32 bit) */
|
||||
#define B53_JUMBO_PORT_MASK 0x01
|
||||
#define B53_JUMBO_PORT_MASK_63XX 0x04
|
||||
#define JPM_10_100_JUMBO_EN BIT(24) /* GigE always enabled */
|
||||
|
||||
/* Good Frame Max Size without 802.1Q TAG (16 bit) */
|
||||
#define B53_JUMBO_MAX_SIZE 0x05
|
||||
#define B53_JUMBO_MAX_SIZE_63XX 0x08
|
||||
#define JMS_MIN_SIZE 1518
|
||||
#define JMS_MAX_SIZE 9724
|
||||
|
||||
/*************************************************************************
|
||||
* CFP Configuration Page Registers
|
||||
*************************************************************************/
|
||||
|
||||
/* CFP Control Register with ports map (8 bit) */
|
||||
#define B53_CFP_CTRL 0x00
|
||||
|
||||
#endif /* !__B53_REGS_H */
|
331
drivers/net/dsa/b53/b53_spi.c
Normal file
331
drivers/net/dsa/b53/b53_spi.c
Normal file
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
* B53 register access through SPI
|
||||
*
|
||||
* Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/platform_data/b53.h>
|
||||
|
||||
#include "b53_priv.h"
|
||||
|
||||
#define B53_SPI_DATA 0xf0
|
||||
|
||||
#define B53_SPI_STATUS 0xfe
|
||||
#define B53_SPI_CMD_SPIF BIT(7)
|
||||
#define B53_SPI_CMD_RACK BIT(5)
|
||||
|
||||
#define B53_SPI_CMD_READ 0x00
|
||||
#define B53_SPI_CMD_WRITE 0x01
|
||||
#define B53_SPI_CMD_NORMAL 0x60
|
||||
#define B53_SPI_CMD_FAST 0x10
|
||||
|
||||
#define B53_SPI_PAGE_SELECT 0xff
|
||||
|
||||
static inline int b53_spi_read_reg(struct spi_device *spi, u8 reg, u8 *val,
|
||||
unsigned int len)
|
||||
{
|
||||
u8 txbuf[2];
|
||||
|
||||
txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_READ;
|
||||
txbuf[1] = reg;
|
||||
|
||||
return spi_write_then_read(spi, txbuf, 2, val, len);
|
||||
}
|
||||
|
||||
static inline int b53_spi_clear_status(struct spi_device *spi)
|
||||
{
|
||||
unsigned int i;
|
||||
u8 rxbuf;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!(rxbuf & B53_SPI_CMD_SPIF))
|
||||
break;
|
||||
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
if (i == 10)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int b53_spi_set_page(struct spi_device *spi, u8 page)
|
||||
{
|
||||
u8 txbuf[3];
|
||||
|
||||
txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
|
||||
txbuf[1] = B53_SPI_PAGE_SELECT;
|
||||
txbuf[2] = page;
|
||||
|
||||
return spi_write(spi, txbuf, sizeof(txbuf));
|
||||
}
|
||||
|
||||
static inline int b53_prepare_reg_access(struct spi_device *spi, u8 page)
|
||||
{
|
||||
int ret = b53_spi_clear_status(spi);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return b53_spi_set_page(spi, page);
|
||||
}
|
||||
|
||||
static int b53_spi_prepare_reg_read(struct spi_device *spi, u8 reg)
|
||||
{
|
||||
u8 rxbuf;
|
||||
int retry_count;
|
||||
int ret;
|
||||
|
||||
ret = b53_spi_read_reg(spi, reg, &rxbuf, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (retry_count = 0; retry_count < 10; retry_count++) {
|
||||
ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (rxbuf & B53_SPI_CMD_RACK)
|
||||
break;
|
||||
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
if (retry_count == 10)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_spi_read(struct b53_device *dev, u8 page, u8 reg, u8 *data,
|
||||
unsigned int len)
|
||||
{
|
||||
struct spi_device *spi = dev->priv;
|
||||
int ret;
|
||||
|
||||
ret = b53_prepare_reg_access(spi, page);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = b53_spi_prepare_reg_read(spi, reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return b53_spi_read_reg(spi, B53_SPI_DATA, data, len);
|
||||
}
|
||||
|
||||
static int b53_spi_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
|
||||
{
|
||||
return b53_spi_read(dev, page, reg, val, 1);
|
||||
}
|
||||
|
||||
static int b53_spi_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
|
||||
{
|
||||
int ret = b53_spi_read(dev, page, reg, (u8 *)val, 2);
|
||||
|
||||
if (!ret)
|
||||
*val = le16_to_cpu(*val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_spi_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
|
||||
{
|
||||
int ret = b53_spi_read(dev, page, reg, (u8 *)val, 4);
|
||||
|
||||
if (!ret)
|
||||
*val = le32_to_cpu(*val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_spi_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
*val = 0;
|
||||
ret = b53_spi_read(dev, page, reg, (u8 *)val, 6);
|
||||
if (!ret)
|
||||
*val = le64_to_cpu(*val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_spi_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
|
||||
{
|
||||
int ret = b53_spi_read(dev, page, reg, (u8 *)val, 8);
|
||||
|
||||
if (!ret)
|
||||
*val = le64_to_cpu(*val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_spi_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
|
||||
{
|
||||
struct spi_device *spi = dev->priv;
|
||||
int ret;
|
||||
u8 txbuf[3];
|
||||
|
||||
ret = b53_prepare_reg_access(spi, page);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
|
||||
txbuf[1] = reg;
|
||||
txbuf[2] = value;
|
||||
|
||||
return spi_write(spi, txbuf, sizeof(txbuf));
|
||||
}
|
||||
|
||||
static int b53_spi_write16(struct b53_device *dev, u8 page, u8 reg, u16 value)
|
||||
{
|
||||
struct spi_device *spi = dev->priv;
|
||||
int ret;
|
||||
u8 txbuf[4];
|
||||
|
||||
ret = b53_prepare_reg_access(spi, page);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
|
||||
txbuf[1] = reg;
|
||||
put_unaligned_le16(value, &txbuf[2]);
|
||||
|
||||
return spi_write(spi, txbuf, sizeof(txbuf));
|
||||
}
|
||||
|
||||
static int b53_spi_write32(struct b53_device *dev, u8 page, u8 reg, u32 value)
|
||||
{
|
||||
struct spi_device *spi = dev->priv;
|
||||
int ret;
|
||||
u8 txbuf[6];
|
||||
|
||||
ret = b53_prepare_reg_access(spi, page);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
|
||||
txbuf[1] = reg;
|
||||
put_unaligned_le32(value, &txbuf[2]);
|
||||
|
||||
return spi_write(spi, txbuf, sizeof(txbuf));
|
||||
}
|
||||
|
||||
static int b53_spi_write48(struct b53_device *dev, u8 page, u8 reg, u64 value)
|
||||
{
|
||||
struct spi_device *spi = dev->priv;
|
||||
int ret;
|
||||
u8 txbuf[10];
|
||||
|
||||
ret = b53_prepare_reg_access(spi, page);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
|
||||
txbuf[1] = reg;
|
||||
put_unaligned_le64(value, &txbuf[2]);
|
||||
|
||||
return spi_write(spi, txbuf, sizeof(txbuf) - 2);
|
||||
}
|
||||
|
||||
static int b53_spi_write64(struct b53_device *dev, u8 page, u8 reg, u64 value)
|
||||
{
|
||||
struct spi_device *spi = dev->priv;
|
||||
int ret;
|
||||
u8 txbuf[10];
|
||||
|
||||
ret = b53_prepare_reg_access(spi, page);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
|
||||
txbuf[1] = reg;
|
||||
put_unaligned_le64(value, &txbuf[2]);
|
||||
|
||||
return spi_write(spi, txbuf, sizeof(txbuf));
|
||||
}
|
||||
|
||||
static struct b53_io_ops b53_spi_ops = {
|
||||
.read8 = b53_spi_read8,
|
||||
.read16 = b53_spi_read16,
|
||||
.read32 = b53_spi_read32,
|
||||
.read48 = b53_spi_read48,
|
||||
.read64 = b53_spi_read64,
|
||||
.write8 = b53_spi_write8,
|
||||
.write16 = b53_spi_write16,
|
||||
.write32 = b53_spi_write32,
|
||||
.write48 = b53_spi_write48,
|
||||
.write64 = b53_spi_write64,
|
||||
};
|
||||
|
||||
static int b53_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct b53_device *dev;
|
||||
int ret;
|
||||
|
||||
dev = b53_switch_alloc(&spi->dev, &b53_spi_ops, spi);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
if (spi->dev.platform_data)
|
||||
dev->pdata = spi->dev.platform_data;
|
||||
|
||||
ret = b53_switch_register(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spi_set_drvdata(spi, dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
struct b53_device *dev = spi_get_drvdata(spi);
|
||||
|
||||
if (dev)
|
||||
b53_switch_remove(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver b53_spi_driver = {
|
||||
.driver = {
|
||||
.name = "b53-switch",
|
||||
.bus = &spi_bus_type,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = b53_spi_probe,
|
||||
.remove = b53_spi_remove,
|
||||
};
|
||||
|
||||
module_spi_driver(b53_spi_driver);
|
||||
|
||||
MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
|
||||
MODULE_DESCRIPTION("B53 SPI access driver");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
415
drivers/net/dsa/b53/b53_srab.c
Normal file
415
drivers/net/dsa/b53/b53_srab.c
Normal file
|
@ -0,0 +1,415 @@
|
|||
/*
|
||||
* B53 register access through Switch Register Access Bridge Registers
|
||||
*
|
||||
* Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/b53.h>
|
||||
|
||||
#include "b53_priv.h"
|
||||
|
||||
/* command and status register of the SRAB */
|
||||
#define B53_SRAB_CMDSTAT 0x2c
|
||||
#define B53_SRAB_CMDSTAT_RST BIT(2)
|
||||
#define B53_SRAB_CMDSTAT_WRITE BIT(1)
|
||||
#define B53_SRAB_CMDSTAT_GORDYN BIT(0)
|
||||
#define B53_SRAB_CMDSTAT_PAGE 24
|
||||
#define B53_SRAB_CMDSTAT_REG 16
|
||||
|
||||
/* high order word of write data to switch registe */
|
||||
#define B53_SRAB_WD_H 0x30
|
||||
|
||||
/* low order word of write data to switch registe */
|
||||
#define B53_SRAB_WD_L 0x34
|
||||
|
||||
/* high order word of read data from switch register */
|
||||
#define B53_SRAB_RD_H 0x38
|
||||
|
||||
/* low order word of read data from switch register */
|
||||
#define B53_SRAB_RD_L 0x3c
|
||||
|
||||
/* command and status register of the SRAB */
|
||||
#define B53_SRAB_CTRLS 0x40
|
||||
#define B53_SRAB_CTRLS_RCAREQ BIT(3)
|
||||
#define B53_SRAB_CTRLS_RCAGNT BIT(4)
|
||||
#define B53_SRAB_CTRLS_SW_INIT_DONE BIT(6)
|
||||
|
||||
/* the register captures interrupt pulses from the switch */
|
||||
#define B53_SRAB_INTR 0x44
|
||||
#define B53_SRAB_INTR_P(x) BIT(x)
|
||||
#define B53_SRAB_SWITCH_PHY BIT(8)
|
||||
#define B53_SRAB_1588_SYNC BIT(9)
|
||||
#define B53_SRAB_IMP1_SLEEP_TIMER BIT(10)
|
||||
#define B53_SRAB_P7_SLEEP_TIMER BIT(11)
|
||||
#define B53_SRAB_IMP0_SLEEP_TIMER BIT(12)
|
||||
|
||||
struct b53_srab_priv {
|
||||
void __iomem *regs;
|
||||
};
|
||||
|
||||
static int b53_srab_request_grant(struct b53_device *dev)
|
||||
{
|
||||
struct b53_srab_priv *priv = dev->priv;
|
||||
u8 __iomem *regs = priv->regs;
|
||||
u32 ctrls;
|
||||
int i;
|
||||
|
||||
ctrls = readl(regs + B53_SRAB_CTRLS);
|
||||
ctrls |= B53_SRAB_CTRLS_RCAREQ;
|
||||
writel(ctrls, regs + B53_SRAB_CTRLS);
|
||||
|
||||
for (i = 0; i < 20; i++) {
|
||||
ctrls = readl(regs + B53_SRAB_CTRLS);
|
||||
if (ctrls & B53_SRAB_CTRLS_RCAGNT)
|
||||
break;
|
||||
usleep_range(10, 100);
|
||||
}
|
||||
if (WARN_ON(i == 5))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void b53_srab_release_grant(struct b53_device *dev)
|
||||
{
|
||||
struct b53_srab_priv *priv = dev->priv;
|
||||
u8 __iomem *regs = priv->regs;
|
||||
u32 ctrls;
|
||||
|
||||
ctrls = readl(regs + B53_SRAB_CTRLS);
|
||||
ctrls &= ~B53_SRAB_CTRLS_RCAREQ;
|
||||
writel(ctrls, regs + B53_SRAB_CTRLS);
|
||||
}
|
||||
|
||||
static int b53_srab_op(struct b53_device *dev, u8 page, u8 reg, u32 op)
|
||||
{
|
||||
struct b53_srab_priv *priv = dev->priv;
|
||||
u8 __iomem *regs = priv->regs;
|
||||
int i;
|
||||
u32 cmdstat;
|
||||
|
||||
/* set register address */
|
||||
cmdstat = (page << B53_SRAB_CMDSTAT_PAGE) |
|
||||
(reg << B53_SRAB_CMDSTAT_REG) |
|
||||
B53_SRAB_CMDSTAT_GORDYN |
|
||||
op;
|
||||
writel(cmdstat, regs + B53_SRAB_CMDSTAT);
|
||||
|
||||
/* check if operation completed */
|
||||
for (i = 0; i < 5; ++i) {
|
||||
cmdstat = readl(regs + B53_SRAB_CMDSTAT);
|
||||
if (!(cmdstat & B53_SRAB_CMDSTAT_GORDYN))
|
||||
break;
|
||||
usleep_range(10, 100);
|
||||
}
|
||||
|
||||
if (WARN_ON(i == 5))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_srab_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
|
||||
{
|
||||
struct b53_srab_priv *priv = dev->priv;
|
||||
u8 __iomem *regs = priv->regs;
|
||||
int ret = 0;
|
||||
|
||||
ret = b53_srab_request_grant(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = b53_srab_op(dev, page, reg, 0);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
*val = readl(regs + B53_SRAB_RD_L) & 0xff;
|
||||
|
||||
err:
|
||||
b53_srab_release_grant(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_srab_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
|
||||
{
|
||||
struct b53_srab_priv *priv = dev->priv;
|
||||
u8 __iomem *regs = priv->regs;
|
||||
int ret = 0;
|
||||
|
||||
ret = b53_srab_request_grant(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = b53_srab_op(dev, page, reg, 0);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
*val = readl(regs + B53_SRAB_RD_L) & 0xffff;
|
||||
|
||||
err:
|
||||
b53_srab_release_grant(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_srab_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
|
||||
{
|
||||
struct b53_srab_priv *priv = dev->priv;
|
||||
u8 __iomem *regs = priv->regs;
|
||||
int ret = 0;
|
||||
|
||||
ret = b53_srab_request_grant(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = b53_srab_op(dev, page, reg, 0);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
*val = readl(regs + B53_SRAB_RD_L);
|
||||
|
||||
err:
|
||||
b53_srab_release_grant(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_srab_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
|
||||
{
|
||||
struct b53_srab_priv *priv = dev->priv;
|
||||
u8 __iomem *regs = priv->regs;
|
||||
int ret = 0;
|
||||
|
||||
ret = b53_srab_request_grant(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = b53_srab_op(dev, page, reg, 0);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
*val = readl(regs + B53_SRAB_RD_L);
|
||||
*val += ((u64)readl(regs + B53_SRAB_RD_H) & 0xffff) << 32;
|
||||
|
||||
err:
|
||||
b53_srab_release_grant(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_srab_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
|
||||
{
|
||||
struct b53_srab_priv *priv = dev->priv;
|
||||
u8 __iomem *regs = priv->regs;
|
||||
int ret = 0;
|
||||
|
||||
ret = b53_srab_request_grant(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = b53_srab_op(dev, page, reg, 0);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
*val = readl(regs + B53_SRAB_RD_L);
|
||||
*val += (u64)readl(regs + B53_SRAB_RD_H) << 32;
|
||||
|
||||
err:
|
||||
b53_srab_release_grant(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_srab_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
|
||||
{
|
||||
struct b53_srab_priv *priv = dev->priv;
|
||||
u8 __iomem *regs = priv->regs;
|
||||
int ret = 0;
|
||||
|
||||
ret = b53_srab_request_grant(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
writel(value, regs + B53_SRAB_WD_L);
|
||||
|
||||
ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
|
||||
|
||||
err:
|
||||
b53_srab_release_grant(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_srab_write16(struct b53_device *dev, u8 page, u8 reg,
|
||||
u16 value)
|
||||
{
|
||||
struct b53_srab_priv *priv = dev->priv;
|
||||
u8 __iomem *regs = priv->regs;
|
||||
int ret = 0;
|
||||
|
||||
ret = b53_srab_request_grant(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
writel(value, regs + B53_SRAB_WD_L);
|
||||
|
||||
ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
|
||||
|
||||
err:
|
||||
b53_srab_release_grant(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_srab_write32(struct b53_device *dev, u8 page, u8 reg,
|
||||
u32 value)
|
||||
{
|
||||
struct b53_srab_priv *priv = dev->priv;
|
||||
u8 __iomem *regs = priv->regs;
|
||||
int ret = 0;
|
||||
|
||||
ret = b53_srab_request_grant(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
writel(value, regs + B53_SRAB_WD_L);
|
||||
|
||||
ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
|
||||
|
||||
err:
|
||||
b53_srab_release_grant(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_srab_write48(struct b53_device *dev, u8 page, u8 reg,
|
||||
u64 value)
|
||||
{
|
||||
struct b53_srab_priv *priv = dev->priv;
|
||||
u8 __iomem *regs = priv->regs;
|
||||
int ret = 0;
|
||||
|
||||
ret = b53_srab_request_grant(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
writel((u32)value, regs + B53_SRAB_WD_L);
|
||||
writel((u16)(value >> 32), regs + B53_SRAB_WD_H);
|
||||
|
||||
ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
|
||||
|
||||
err:
|
||||
b53_srab_release_grant(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_srab_write64(struct b53_device *dev, u8 page, u8 reg,
|
||||
u64 value)
|
||||
{
|
||||
struct b53_srab_priv *priv = dev->priv;
|
||||
u8 __iomem *regs = priv->regs;
|
||||
int ret = 0;
|
||||
|
||||
ret = b53_srab_request_grant(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
writel((u32)value, regs + B53_SRAB_WD_L);
|
||||
writel((u32)(value >> 32), regs + B53_SRAB_WD_H);
|
||||
|
||||
ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
|
||||
|
||||
err:
|
||||
b53_srab_release_grant(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct b53_io_ops b53_srab_ops = {
|
||||
.read8 = b53_srab_read8,
|
||||
.read16 = b53_srab_read16,
|
||||
.read32 = b53_srab_read32,
|
||||
.read48 = b53_srab_read48,
|
||||
.read64 = b53_srab_read64,
|
||||
.write8 = b53_srab_write8,
|
||||
.write16 = b53_srab_write16,
|
||||
.write32 = b53_srab_write32,
|
||||
.write48 = b53_srab_write48,
|
||||
.write64 = b53_srab_write64,
|
||||
};
|
||||
|
||||
static int b53_srab_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct b53_srab_priv *priv;
|
||||
struct b53_device *dev;
|
||||
struct resource *r;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->regs = devm_ioremap_resource(&pdev->dev, r);
|
||||
if (IS_ERR(priv->regs))
|
||||
return -ENOMEM;
|
||||
|
||||
dev = b53_switch_alloc(&pdev->dev, &b53_srab_ops, priv);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, dev);
|
||||
|
||||
return b53_switch_register(dev);
|
||||
}
|
||||
|
||||
static int b53_srab_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct b53_device *dev = platform_get_drvdata(pdev);
|
||||
|
||||
if (dev)
|
||||
b53_switch_remove(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id b53_srab_of_match[] = {
|
||||
{ .compatible = "brcm,bcm53010-srab" },
|
||||
{ .compatible = "brcm,bcm53011-srab" },
|
||||
{ .compatible = "brcm,bcm53012-srab" },
|
||||
{ .compatible = "brcm,bcm53018-srab" },
|
||||
{ .compatible = "brcm,bcm53019-srab" },
|
||||
{ .compatible = "brcm,bcm5301x-srab" },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static struct platform_driver b53_srab_driver = {
|
||||
.probe = b53_srab_probe,
|
||||
.remove = b53_srab_remove,
|
||||
.driver = {
|
||||
.name = "b53-srab-switch",
|
||||
.of_match_table = b53_srab_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(b53_srab_driver);
|
||||
MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
|
||||
MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
33
include/linux/platform_data/b53.h
Normal file
33
include/linux/platform_data/b53.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* B53 platform data
|
||||
*
|
||||
* Copyright (C) 2013 Jonas Gorski <jogo@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __B53_H
|
||||
#define __B53_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
struct b53_platform_data {
|
||||
u32 chip_id;
|
||||
u16 enabled_ports;
|
||||
|
||||
/* only used by MMAP'd driver */
|
||||
unsigned big_endian:1;
|
||||
void __iomem *regs;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user