Commit db9a1ba5 authored by David S. Miller's avatar David S. Miller

Merge branch 'bgmac-platform-device'

Jon Mason says:

====================
net: ethernet: bgmac: Add platform device support

David Miller, Please consider including patches 1-5 in net-next

Florian Fainelli, Please consider including patches 6 & 7 in
  devicetree/next

Changes in v2:
* Made device tree binding changes suggested by Sergei Shtylyov,
  Ray Jui, Rob Herring, Florian Fainelli, and Arnd Bergmann
* Removed devm_* error paths in the bgmac_platform.c suggested by
  Florian Fainelli
* Added Arnd Bergmann's Acked-by to the first 5 (there were changes
  outlined in the bullets above, but I believe them to be minor enough
  for him to not revoke his acks)

This patch series adds support for other, non-bcma iProc SoC's to the
bgmac driver.  This series only adds NSP support, but we are interested
in adding support for the Cygnus and NS2 families (with more possible
down the road).

To support non-bcma enabled SoCs, we need to add the standard device
tree "platform device" support.  Unfortunately, this driver is very
tighly coupled with the bcma bus and much unwinding is needed.  I tried
to break this up into a number of patches to make it more obvious what
was being done to add platform device support.  I was able to verify
that the bcma code still works using a 53012K board (NS SoC), and that
the platform code works using a 58625K board (NSP SoC).
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1db19db7 f6a95a24
...@@ -140,10 +140,18 @@ config BNX2X_SRIOV ...@@ -140,10 +140,18 @@ config BNX2X_SRIOV
allows for virtual function acceleration in virtual environments. allows for virtual function acceleration in virtual environments.
config BGMAC config BGMAC
tristate "BCMA bus GBit core support" tristate
help
This enables the integrated ethernet controller support for many
Broadcom (mostly iProc) SoCs. An appropriate bus interface driver
needs to be enabled to select this.
config BGMAC_BCMA
tristate "Broadcom iProc GBit BCMA support"
depends on BCMA && BCMA_HOST_SOC depends on BCMA && BCMA_HOST_SOC
depends on HAS_DMA depends on HAS_DMA
depends on BCM47XX || ARCH_BCM_5301X || COMPILE_TEST depends on BCM47XX || ARCH_BCM_5301X || COMPILE_TEST
select BGMAC
select PHYLIB select PHYLIB
select FIXED_PHY select FIXED_PHY
---help--- ---help---
...@@ -152,6 +160,19 @@ config BGMAC ...@@ -152,6 +160,19 @@ config BGMAC
In case of using this driver on BCM4706 it's also requires to enable In case of using this driver on BCM4706 it's also requires to enable
BCMA_DRIVER_GMAC_CMN to make it work. BCMA_DRIVER_GMAC_CMN to make it work.
config BGMAC_PLATFORM
tristate "Broadcom iProc GBit platform support"
depends on HAS_DMA
depends on ARCH_BCM_IPROC || COMPILE_TEST
depends on OF
select BGMAC
select PHYLIB
select FIXED_PHY
default ARCH_BCM_IPROC
---help---
Say Y here if you want to use the Broadcom iProc Gigabit Ethernet
controller through the generic platform interface
config SYSTEMPORT config SYSTEMPORT
tristate "Broadcom SYSTEMPORT internal MAC support" tristate "Broadcom SYSTEMPORT internal MAC support"
depends on OF depends on OF
......
...@@ -11,5 +11,7 @@ obj-$(CONFIG_BNX2X) += bnx2x/ ...@@ -11,5 +11,7 @@ obj-$(CONFIG_BNX2X) += bnx2x/
obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o
obj-$(CONFIG_TIGON3) += tg3.o obj-$(CONFIG_TIGON3) += tg3.o
obj-$(CONFIG_BGMAC) += bgmac.o obj-$(CONFIG_BGMAC) += bgmac.o
obj-$(CONFIG_BGMAC_BCMA) += bgmac-bcma.o bgmac-bcma-mdio.o
obj-$(CONFIG_BGMAC_PLATFORM) += bgmac-platform.o
obj-$(CONFIG_SYSTEMPORT) += bcmsysport.o obj-$(CONFIG_SYSTEMPORT) += bcmsysport.o
obj-$(CONFIG_BNXT) += bnxt/ obj-$(CONFIG_BNXT) += bnxt/
/*
* Driver for (BCM4706)? GBit MAC core on BCMA bus.
*
* Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com>
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bcma/bcma.h>
#include <linux/brcmphy.h>
#include "bgmac.h"
struct bcma_mdio {
struct bcma_device *core;
u8 phyaddr;
};
static bool bcma_mdio_wait_value(struct bcma_device *core, u16 reg, u32 mask,
u32 value, int timeout)
{
u32 val;
int i;
for (i = 0; i < timeout / 10; i++) {
val = bcma_read32(core, reg);
if ((val & mask) == value)
return true;
udelay(10);
}
dev_err(&core->dev, "Timeout waiting for reg 0x%X\n", reg);
return false;
}
/**************************************************
* PHY ops
**************************************************/
static u16 bcma_mdio_phy_read(struct bcma_mdio *bcma_mdio, u8 phyaddr, u8 reg)
{
struct bcma_device *core;
u16 phy_access_addr;
u16 phy_ctl_addr;
u32 tmp;
BUILD_BUG_ON(BGMAC_PA_DATA_MASK != BCMA_GMAC_CMN_PA_DATA_MASK);
BUILD_BUG_ON(BGMAC_PA_ADDR_MASK != BCMA_GMAC_CMN_PA_ADDR_MASK);
BUILD_BUG_ON(BGMAC_PA_ADDR_SHIFT != BCMA_GMAC_CMN_PA_ADDR_SHIFT);
BUILD_BUG_ON(BGMAC_PA_REG_MASK != BCMA_GMAC_CMN_PA_REG_MASK);
BUILD_BUG_ON(BGMAC_PA_REG_SHIFT != BCMA_GMAC_CMN_PA_REG_SHIFT);
BUILD_BUG_ON(BGMAC_PA_WRITE != BCMA_GMAC_CMN_PA_WRITE);
BUILD_BUG_ON(BGMAC_PA_START != BCMA_GMAC_CMN_PA_START);
BUILD_BUG_ON(BGMAC_PC_EPA_MASK != BCMA_GMAC_CMN_PC_EPA_MASK);
BUILD_BUG_ON(BGMAC_PC_MCT_MASK != BCMA_GMAC_CMN_PC_MCT_MASK);
BUILD_BUG_ON(BGMAC_PC_MCT_SHIFT != BCMA_GMAC_CMN_PC_MCT_SHIFT);
BUILD_BUG_ON(BGMAC_PC_MTE != BCMA_GMAC_CMN_PC_MTE);
if (bcma_mdio->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
core = bcma_mdio->core->bus->drv_gmac_cmn.core;
phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
} else {
core = bcma_mdio->core;
phy_access_addr = BGMAC_PHY_ACCESS;
phy_ctl_addr = BGMAC_PHY_CNTL;
}
tmp = bcma_read32(core, phy_ctl_addr);
tmp &= ~BGMAC_PC_EPA_MASK;
tmp |= phyaddr;
bcma_write32(core, phy_ctl_addr, tmp);
tmp = BGMAC_PA_START;
tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT;
tmp |= reg << BGMAC_PA_REG_SHIFT;
bcma_write32(core, phy_access_addr, tmp);
if (!bcma_mdio_wait_value(core, phy_access_addr, BGMAC_PA_START, 0,
1000)) {
dev_err(&core->dev, "Reading PHY %d register 0x%X failed\n",
phyaddr, reg);
return 0xffff;
}
return bcma_read32(core, phy_access_addr) & BGMAC_PA_DATA_MASK;
}
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphywr */
static int bcma_mdio_phy_write(struct bcma_mdio *bcma_mdio, u8 phyaddr, u8 reg,
u16 value)
{
struct bcma_device *core;
u16 phy_access_addr;
u16 phy_ctl_addr;
u32 tmp;
if (bcma_mdio->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
core = bcma_mdio->core->bus->drv_gmac_cmn.core;
phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
} else {
core = bcma_mdio->core;
phy_access_addr = BGMAC_PHY_ACCESS;
phy_ctl_addr = BGMAC_PHY_CNTL;
}
tmp = bcma_read32(core, phy_ctl_addr);
tmp &= ~BGMAC_PC_EPA_MASK;
tmp |= phyaddr;
bcma_write32(core, phy_ctl_addr, tmp);
bcma_write32(bcma_mdio->core, BGMAC_INT_STATUS, BGMAC_IS_MDIO);
if (bcma_read32(bcma_mdio->core, BGMAC_INT_STATUS) & BGMAC_IS_MDIO)
dev_warn(&core->dev, "Error setting MDIO int\n");
tmp = BGMAC_PA_START;
tmp |= BGMAC_PA_WRITE;
tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT;
tmp |= reg << BGMAC_PA_REG_SHIFT;
tmp |= value;
bcma_write32(core, phy_access_addr, tmp);
if (!bcma_mdio_wait_value(core, phy_access_addr, BGMAC_PA_START, 0,
1000)) {
dev_err(&core->dev, "Writing to PHY %d register 0x%X failed\n",
phyaddr, reg);
return -ETIMEDOUT;
}
return 0;
}
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyinit */
static void bcma_mdio_phy_init(struct bcma_mdio *bcma_mdio)
{
struct bcma_chipinfo *ci = &bcma_mdio->core->bus->chipinfo;
u8 i;
if (ci->id == BCMA_CHIP_ID_BCM5356) {
for (i = 0; i < 5; i++) {
bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x008b);
bcma_mdio_phy_write(bcma_mdio, i, 0x15, 0x0100);
bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000f);
bcma_mdio_phy_write(bcma_mdio, i, 0x12, 0x2aaa);
bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000b);
}
}
if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg != 10) ||
(ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg != 10) ||
(ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg != 9)) {
struct bcma_drv_cc *cc = &bcma_mdio->core->bus->drv_cc;
bcma_chipco_chipctl_maskset(cc, 2, ~0xc0000000, 0);
bcma_chipco_chipctl_maskset(cc, 4, ~0x80000000, 0);
for (i = 0; i < 5; i++) {
bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000f);
bcma_mdio_phy_write(bcma_mdio, i, 0x16, 0x5284);
bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000b);
bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x0010);
bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000f);
bcma_mdio_phy_write(bcma_mdio, i, 0x16, 0x5296);
bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x1073);
bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x9073);
bcma_mdio_phy_write(bcma_mdio, i, 0x16, 0x52b6);
bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x9273);
bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000b);
}
}
}
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyreset */
static int bcma_mdio_phy_reset(struct mii_bus *bus)
{
struct bcma_mdio *bcma_mdio = bus->priv;
u8 phyaddr = bcma_mdio->phyaddr;
if (bcma_mdio->phyaddr == BGMAC_PHY_NOREGS)
return 0;
bcma_mdio_phy_write(bcma_mdio, phyaddr, MII_BMCR, BMCR_RESET);
udelay(100);
if (bcma_mdio_phy_read(bcma_mdio, phyaddr, MII_BMCR) & BMCR_RESET)
dev_err(&bcma_mdio->core->dev, "PHY reset failed\n");
bcma_mdio_phy_init(bcma_mdio);
return 0;
}
/**************************************************
* MII
**************************************************/
static int bcma_mdio_mii_read(struct mii_bus *bus, int mii_id, int regnum)
{
return bcma_mdio_phy_read(bus->priv, mii_id, regnum);
}
static int bcma_mdio_mii_write(struct mii_bus *bus, int mii_id, int regnum,
u16 value)
{
return bcma_mdio_phy_write(bus->priv, mii_id, regnum, value);
}
struct mii_bus *bcma_mdio_mii_register(struct bcma_device *core, u8 phyaddr)
{
struct bcma_mdio *bcma_mdio;
struct mii_bus *mii_bus;
int err;
bcma_mdio = kzalloc(sizeof(*bcma_mdio), GFP_KERNEL);
if (!bcma_mdio)
return ERR_PTR(-ENOMEM);
mii_bus = mdiobus_alloc();
if (!mii_bus) {
err = -ENOMEM;
goto err;
}
mii_bus->name = "bcma_mdio mii bus";
sprintf(mii_bus->id, "%s-%d-%d", "bcma_mdio", core->bus->num,
core->core_unit);
mii_bus->priv = bcma_mdio;
mii_bus->read = bcma_mdio_mii_read;
mii_bus->write = bcma_mdio_mii_write;
mii_bus->reset = bcma_mdio_phy_reset;
mii_bus->parent = &core->dev;
mii_bus->phy_mask = ~(1 << phyaddr);
bcma_mdio->core = core;
bcma_mdio->phyaddr = phyaddr;
err = mdiobus_register(mii_bus);
if (err) {
dev_err(&core->dev, "Registration of mii bus failed\n");
goto err_free_bus;
}
return mii_bus;
err_free_bus:
mdiobus_free(mii_bus);
err:
kfree(bcma_mdio);
return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(bcma_mdio_mii_register);
void bcma_mdio_mii_unregister(struct mii_bus *mii_bus)
{
struct bcma_mdio *bcma_mdio;
if (!mii_bus)
return;
bcma_mdio = mii_bus->priv;
mdiobus_unregister(mii_bus);
mdiobus_free(mii_bus);
kfree(bcma_mdio);
}
EXPORT_SYMBOL_GPL(bcma_mdio_mii_unregister);
MODULE_AUTHOR("Rafał Miłecki");
MODULE_LICENSE("GPL");
/*
* Driver for (BCM4706)? GBit MAC core on BCMA bus.
*
* Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com>
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bcma/bcma.h>
#include <linux/brcmphy.h>
#include <linux/etherdevice.h>
#include "bgmac.h"
static inline bool bgmac_is_bcm4707_family(struct bcma_device *core)
{
switch (core->bus->chipinfo.id) {
case BCMA_CHIP_ID_BCM4707:
case BCMA_CHIP_ID_BCM47094:
case BCMA_CHIP_ID_BCM53018:
return true;
default:
return false;
}
}
/**************************************************
* BCMA bus ops
**************************************************/
static u32 bcma_bgmac_read(struct bgmac *bgmac, u16 offset)
{
return bcma_read32(bgmac->bcma.core, offset);
}
static void bcma_bgmac_write(struct bgmac *bgmac, u16 offset, u32 value)
{
bcma_write32(bgmac->bcma.core, offset, value);
}
static u32 bcma_bgmac_idm_read(struct bgmac *bgmac, u16 offset)
{
return bcma_aread32(bgmac->bcma.core, offset);
}
static void bcma_bgmac_idm_write(struct bgmac *bgmac, u16 offset, u32 value)
{
return bcma_awrite32(bgmac->bcma.core, offset, value);
}
static bool bcma_bgmac_clk_enabled(struct bgmac *bgmac)
{
return bcma_core_is_enabled(bgmac->bcma.core);
}
static void bcma_bgmac_clk_enable(struct bgmac *bgmac, u32 flags)
{
bcma_core_enable(bgmac->bcma.core, flags);
}
static void bcma_bgmac_cco_ctl_maskset(struct bgmac *bgmac, u32 offset,
u32 mask, u32 set)
{
struct bcma_drv_cc *cc = &bgmac->bcma.core->bus->drv_cc;
bcma_chipco_chipctl_maskset(cc, offset, mask, set);
}
static u32 bcma_bgmac_get_bus_clock(struct bgmac *bgmac)
{
struct bcma_drv_cc *cc = &bgmac->bcma.core->bus->drv_cc;
return bcma_pmu_get_bus_clock(cc);
}
static void bcma_bgmac_cmn_maskset32(struct bgmac *bgmac, u16 offset, u32 mask,
u32 set)
{
bcma_maskset32(bgmac->bcma.cmn, offset, mask, set);
}
static const struct bcma_device_id bgmac_bcma_tbl[] = {
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_4706_MAC_GBIT,
BCMA_ANY_REV, BCMA_ANY_CLASS),
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_MAC_GBIT, BCMA_ANY_REV,
BCMA_ANY_CLASS),
{},
};
MODULE_DEVICE_TABLE(bcma, bgmac_bcma_tbl);
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipattach */
static int bgmac_probe(struct bcma_device *core)
{
struct ssb_sprom *sprom = &core->bus->sprom;
struct mii_bus *mii_bus;
struct bgmac *bgmac;
u8 *mac;
int err;
bgmac = kzalloc(sizeof(*bgmac), GFP_KERNEL);
if (!bgmac)
return -ENOMEM;
bgmac->bcma.core = core;
bgmac->dev = &core->dev;
bgmac->dma_dev = core->dma_dev;
bgmac->irq = core->irq;
bcma_set_drvdata(core, bgmac);
switch (core->core_unit) {
case 0:
mac = sprom->et0mac;
break;
case 1:
mac = sprom->et1mac;
break;
case 2:
mac = sprom->et2mac;
break;
default:
dev_err(bgmac->dev, "Unsupported core_unit %d\n",
core->core_unit);
err = -ENOTSUPP;
goto err;
}
ether_addr_copy(bgmac->mac_addr, mac);
/* On BCM4706 we need common core to access PHY */
if (core->id.id == BCMA_CORE_4706_MAC_GBIT &&
!core->bus->drv_gmac_cmn.core) {
dev_err(bgmac->dev, "GMAC CMN core not found (required for BCM4706)\n");
err = -ENODEV;
goto err;
}
bgmac->bcma.cmn = core->bus->drv_gmac_cmn.core;
switch (core->core_unit) {
case 0:
bgmac->phyaddr = sprom->et0phyaddr;
break;
case 1:
bgmac->phyaddr = sprom->et1phyaddr;
break;
case 2:
bgmac->phyaddr = sprom->et2phyaddr;
break;
}
bgmac->phyaddr &= BGMAC_PHY_MASK;
if (bgmac->phyaddr == BGMAC_PHY_MASK) {
dev_err(bgmac->dev, "No PHY found\n");
err = -ENODEV;
goto err;
}
dev_info(bgmac->dev, "Found PHY addr: %d%s\n", bgmac->phyaddr,
bgmac->phyaddr == BGMAC_PHY_NOREGS ? " (NOREGS)" : "");
if (!bgmac_is_bcm4707_family(core)) {
mii_bus = bcma_mdio_mii_register(core, bgmac->phyaddr);
if (!IS_ERR(mii_bus)) {
err = PTR_ERR(mii_bus);
goto err;
}
bgmac->mii_bus = mii_bus;
}
if (core->bus->hosttype == BCMA_HOSTTYPE_PCI) {
dev_err(bgmac->dev, "PCI setup not implemented\n");
err = -ENOTSUPP;
goto err1;
}
bgmac->has_robosw = !!(core->bus->sprom.boardflags_lo &
BGMAC_BFL_ENETROBO);
if (bgmac->has_robosw)
dev_warn(bgmac->dev, "Support for Roboswitch not implemented\n");
if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM)
dev_warn(bgmac->dev, "Support for ADMtek ethernet switch not implemented\n");
/* Feature Flags */
switch (core->bus->chipinfo.id) {
case BCMA_CHIP_ID_BCM5357:
bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1;
bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY;
if (core->bus->chipinfo.pkg == BCMA_PKG_ID_BCM47186) {
bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII;
}
if (core->bus->chipinfo.pkg == BCMA_PKG_ID_BCM5358)
bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_EPHYRMII;
break;
case BCMA_CHIP_ID_BCM53572:
bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1;
bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY;
if (core->bus->chipinfo.pkg == BCMA_PKG_ID_BCM47188) {
bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII;
bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
}
break;
case BCMA_CHIP_ID_BCM4749:
bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1;
bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY;
if (core->bus->chipinfo.pkg == 10) {
bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII;
bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED;
}
break;
case BCMA_CHIP_ID_BCM4716:
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
/* fallthrough */
case BCMA_CHIP_ID_BCM47162:
bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL2;
bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
break;
/* bcm4707_family */
case BCMA_CHIP_ID_BCM4707:
case BCMA_CHIP_ID_BCM47094:
case BCMA_CHIP_ID_BCM53018:
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
bgmac->feature_flags |= BGMAC_FEAT_NO_RESET;
bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
break;
default:
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK;
}
if (!bgmac_is_bcm4707_family(core) && core->id.rev > 2)
bgmac->feature_flags |= BGMAC_FEAT_MISC_PLL_REQ;
if (core->id.id == BCMA_CORE_4706_MAC_GBIT) {
bgmac->feature_flags |= BGMAC_FEAT_CMN_PHY_CTL;
bgmac->feature_flags |= BGMAC_FEAT_NO_CLR_MIB;
}
if (core->id.rev >= 4) {
bgmac->feature_flags |= BGMAC_FEAT_CMDCFG_SR_REV4;
bgmac->feature_flags |= BGMAC_FEAT_TX_MASK_SETUP;
bgmac->feature_flags |= BGMAC_FEAT_RX_MASK_SETUP;
}
bgmac->read = bcma_bgmac_read;
bgmac->write = bcma_bgmac_write;
bgmac->idm_read = bcma_bgmac_idm_read;
bgmac->idm_write = bcma_bgmac_idm_write;
bgmac->clk_enabled = bcma_bgmac_clk_enabled;
bgmac->clk_enable = bcma_bgmac_clk_enable;
bgmac->cco_ctl_maskset = bcma_bgmac_cco_ctl_maskset;
bgmac->get_bus_clock = bcma_bgmac_get_bus_clock;
bgmac->cmn_maskset32 = bcma_bgmac_cmn_maskset32;
err = bgmac_enet_probe(bgmac);
if (err)
goto err1;
return 0;
err1:
bcma_mdio_mii_unregister(bgmac->mii_bus);
err:
kfree(bgmac);
bcma_set_drvdata(core, NULL);
return err;
}
static void bgmac_remove(struct bcma_device *core)
{
struct bgmac *bgmac = bcma_get_drvdata(core);
bcma_mdio_mii_unregister(bgmac->mii_bus);
bgmac_enet_remove(bgmac);
bcma_set_drvdata(core, NULL);
kfree(bgmac);
}
static struct bcma_driver bgmac_bcma_driver = {
.name = KBUILD_MODNAME,
.id_table = bgmac_bcma_tbl,
.probe = bgmac_probe,
.remove = bgmac_remove,
};
static int __init bgmac_init(void)
{
int err;
err = bcma_driver_register(&bgmac_bcma_driver);
if (err)
return err;
pr_info("Broadcom 47xx GBit MAC driver loaded\n");
return 0;
}
static void __exit bgmac_exit(void)
{
bcma_driver_unregister(&bgmac_bcma_driver);
}
module_init(bgmac_init)
module_exit(bgmac_exit)
MODULE_AUTHOR("Rafał Miłecki");
MODULE_LICENSE("GPL");
/*
* Copyright (C) 2016 Broadcom
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bcma/bcma.h>
#include <linux/etherdevice.h>
#include <linux/of_address.h>
#include <linux/of_net.h>
#include "bgmac.h"
static u32 platform_bgmac_read(struct bgmac *bgmac, u16 offset)
{
return readl(bgmac->plat.base + offset);
}
static void platform_bgmac_write(struct bgmac *bgmac, u16 offset, u32 value)
{
writel(value, bgmac->plat.base + offset);
}
static u32 platform_bgmac_idm_read(struct bgmac *bgmac, u16 offset)
{
return readl(bgmac->plat.idm_base + offset);
}
static void platform_bgmac_idm_write(struct bgmac *bgmac, u16 offset, u32 value)
{
return writel(value, bgmac->plat.idm_base + offset);
}
static bool platform_bgmac_clk_enabled(struct bgmac *bgmac)
{
if ((bgmac_idm_read(bgmac, BCMA_IOCTL) &
(BCMA_IOCTL_CLK | BCMA_IOCTL_FGC)) != BCMA_IOCTL_CLK)
return false;
if (bgmac_idm_read(bgmac, BCMA_RESET_CTL) & BCMA_RESET_CTL_RESET)
return false;
return true;
}
static void platform_bgmac_clk_enable(struct bgmac *bgmac, u32 flags)
{
bgmac_idm_write(bgmac, BCMA_IOCTL,
(BCMA_IOCTL_CLK | BCMA_IOCTL_FGC | flags));
bgmac_idm_read(bgmac, BCMA_IOCTL);
bgmac_idm_write(bgmac, BCMA_RESET_CTL, 0);
bgmac_idm_read(bgmac, BCMA_RESET_CTL);
udelay(1);
bgmac_idm_write(bgmac, BCMA_IOCTL, (BCMA_IOCTL_CLK | flags));
bgmac_idm_read(bgmac, BCMA_IOCTL);
udelay(1);
}
static void platform_bgmac_cco_ctl_maskset(struct bgmac *bgmac, u32 offset,
u32 mask, u32 set)
{
/* This shouldn't be encountered */
WARN_ON(1);
}
static u32 platform_bgmac_get_bus_clock(struct bgmac *bgmac)
{
/* This shouldn't be encountered */
WARN_ON(1);
return 0;
}
static void platform_bgmac_cmn_maskset32(struct bgmac *bgmac, u16 offset,
u32 mask, u32 set)
{
/* This shouldn't be encountered */
WARN_ON(1);
}
static int bgmac_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct bgmac *bgmac;
struct resource *regs;
const u8 *mac_addr;
bgmac = devm_kzalloc(&pdev->dev, sizeof(*bgmac), GFP_KERNEL);
if (!bgmac)
return -ENOMEM;
platform_set_drvdata(pdev, bgmac);
/* Set the features of the 4707 family */
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
bgmac->feature_flags |= BGMAC_FEAT_NO_RESET;
bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
bgmac->feature_flags |= BGMAC_FEAT_CMDCFG_SR_REV4;
bgmac->feature_flags |= BGMAC_FEAT_TX_MASK_SETUP;
bgmac->feature_flags |= BGMAC_FEAT_RX_MASK_SETUP;
bgmac->dev = &pdev->dev;
bgmac->dma_dev = &pdev->dev;
mac_addr = of_get_mac_address(np);
if (mac_addr)
ether_addr_copy(bgmac->mac_addr, mac_addr);
else
dev_warn(&pdev->dev, "MAC address not present in device tree\n");
bgmac->irq = platform_get_irq(pdev, 0);
if (bgmac->irq < 0) {
dev_err(&pdev->dev, "Unable to obtain IRQ\n");
return bgmac->irq;
}
regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "amac_base");
if (!regs) {
dev_err(&pdev->dev, "Unable to obtain base resource\n");
return -EINVAL;
}
bgmac->plat.base = devm_ioremap_resource(&pdev->dev, regs);
if (IS_ERR(bgmac->plat.base)) {
dev_err(&pdev->dev, "Unable to map base resource\n");
return PTR_ERR(bgmac->plat.base);
}
regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "idm_base");
if (!regs) {
dev_err(&pdev->dev, "Unable to obtain idm resource\n");
return -EINVAL;
}
bgmac->plat.idm_base = devm_ioremap_resource(&pdev->dev, regs);
if (!bgmac->plat.idm_base) {
dev_err(&pdev->dev, "Unable to map idm resource\n");
return PTR_ERR(bgmac->plat.idm_base);
}
bgmac->read = platform_bgmac_read;
bgmac->write = platform_bgmac_write;
bgmac->idm_read = platform_bgmac_idm_read;
bgmac->idm_write = platform_bgmac_idm_write;
bgmac->clk_enabled = platform_bgmac_clk_enabled;
bgmac->clk_enable = platform_bgmac_clk_enable;
bgmac->cco_ctl_maskset = platform_bgmac_cco_ctl_maskset;
bgmac->get_bus_clock = platform_bgmac_get_bus_clock;
bgmac->cmn_maskset32 = platform_bgmac_cmn_maskset32;
return bgmac_enet_probe(bgmac);
}
static int bgmac_remove(struct platform_device *pdev)
{
struct bgmac *bgmac = platform_get_drvdata(pdev);
bgmac_enet_remove(bgmac);
return 0;
}
static const struct of_device_id bgmac_of_enet_match[] = {
{.compatible = "brcm,amac",},
{.compatible = "brcm,nsp-amac",},
{},
};
MODULE_DEVICE_TABLE(of, bgmac_of_enet_match);
static struct platform_driver bgmac_enet_driver = {
.driver = {
.name = "bgmac-enet",
.of_match_table = bgmac_of_enet_match,
},
.probe = bgmac_probe,
.remove = bgmac_remove,
};
module_platform_driver(bgmac_enet_driver);
MODULE_LICENSE("GPL");
This diff is collapsed.
#ifndef _BGMAC_H #ifndef _BGMAC_H
#define _BGMAC_H #define _BGMAC_H
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define bgmac_err(bgmac, fmt, ...) \
dev_err(&(bgmac)->core->dev, fmt, ##__VA_ARGS__)
#define bgmac_warn(bgmac, fmt, ...) \
dev_warn(&(bgmac)->core->dev, fmt, ##__VA_ARGS__)
#define bgmac_info(bgmac, fmt, ...) \
dev_info(&(bgmac)->core->dev, fmt, ##__VA_ARGS__)
#define bgmac_dbg(bgmac, fmt, ...) \
dev_dbg(&(bgmac)->core->dev, fmt, ##__VA_ARGS__)
#include <linux/bcma/bcma.h>
#include <linux/brcmphy.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#define BGMAC_DEV_CTL 0x000 #define BGMAC_DEV_CTL 0x000
...@@ -201,7 +188,6 @@ ...@@ -201,7 +188,6 @@
#define BGMAC_CMDCFG_HD_SHIFT 10 #define BGMAC_CMDCFG_HD_SHIFT 10
#define BGMAC_CMDCFG_SR_REV0 0x00000800 /* Set to reset mode, for core rev 0-3 */ #define BGMAC_CMDCFG_SR_REV0 0x00000800 /* Set to reset mode, for core rev 0-3 */
#define BGMAC_CMDCFG_SR_REV4 0x00002000 /* Set to reset mode, for core rev >= 4 */ #define BGMAC_CMDCFG_SR_REV4 0x00002000 /* Set to reset mode, for core rev >= 4 */
#define BGMAC_CMDCFG_SR(rev) ((rev >= 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0)
#define BGMAC_CMDCFG_ML 0x00008000 /* Set to activate mac loopback mode */ #define BGMAC_CMDCFG_ML 0x00008000 /* Set to activate mac loopback mode */
#define BGMAC_CMDCFG_AE 0x00400000 #define BGMAC_CMDCFG_AE 0x00400000
#define BGMAC_CMDCFG_CFE 0x00800000 #define BGMAC_CMDCFG_CFE 0x00800000
...@@ -387,6 +373,24 @@ ...@@ -387,6 +373,24 @@
#define ETHER_MAX_LEN 1518 #define ETHER_MAX_LEN 1518
/* Feature Flags */
#define BGMAC_FEAT_TX_MASK_SETUP BIT(0)
#define BGMAC_FEAT_RX_MASK_SETUP BIT(1)
#define BGMAC_FEAT_IOST_ATTACHED BIT(2)
#define BGMAC_FEAT_NO_RESET BIT(3)
#define BGMAC_FEAT_MISC_PLL_REQ BIT(4)
#define BGMAC_FEAT_SW_TYPE_PHY BIT(5)
#define BGMAC_FEAT_SW_TYPE_EPHYRMII BIT(6)
#define BGMAC_FEAT_SW_TYPE_RGMII BIT(7)
#define BGMAC_FEAT_CMN_PHY_CTL BIT(8)
#define BGMAC_FEAT_FLW_CTRL1 BIT(9)
#define BGMAC_FEAT_FLW_CTRL2 BIT(10)
#define BGMAC_FEAT_SET_RXQ_CLK BIT(11)
#define BGMAC_FEAT_CLKCTLST BIT(12)
#define BGMAC_FEAT_NO_CLR_MIB BIT(13)
#define BGMAC_FEAT_FORCE_SPEED_2500 BIT(14)
#define BGMAC_FEAT_CMDCFG_SR_REV4 BIT(15)
struct bgmac_slot_info { struct bgmac_slot_info {
union { union {
struct sk_buff *skb; struct sk_buff *skb;
...@@ -436,8 +440,23 @@ struct bgmac_rx_header { ...@@ -436,8 +440,23 @@ struct bgmac_rx_header {
}; };
struct bgmac { struct bgmac {
union {
struct {
void *base;
void *idm_base;
} plat;
struct {
struct bcma_device *core; struct bcma_device *core;
struct bcma_device *cmn; /* Reference to CMN core for BCM4706 */ /* Reference to CMN core for BCM4706 */
struct bcma_device *cmn;
} bcma;
};
struct device *dev;
struct device *dma_dev;
unsigned char mac_addr[ETH_ALEN];
u32 feature_flags;
struct net_device *net_dev; struct net_device *net_dev;
struct napi_struct napi; struct napi_struct napi;
struct mii_bus *mii_bus; struct mii_bus *mii_bus;
...@@ -452,6 +471,7 @@ struct bgmac { ...@@ -452,6 +471,7 @@ struct bgmac {
u32 mib_rx_regs[BGMAC_NUM_MIB_RX_REGS]; u32 mib_rx_regs[BGMAC_NUM_MIB_RX_REGS];
/* Int */ /* Int */
int irq;
u32 int_mask; u32 int_mask;
/* Current MAC state */ /* Current MAC state */
...@@ -462,16 +482,71 @@ struct bgmac { ...@@ -462,16 +482,71 @@ struct bgmac {
bool has_robosw; bool has_robosw;
bool loopback; bool loopback;
u32 (*read)(struct bgmac *bgmac, u16 offset);
void (*write)(struct bgmac *bgmac, u16 offset, u32 value);
u32 (*idm_read)(struct bgmac *bgmac, u16 offset);
void (*idm_write)(struct bgmac *bgmac, u16 offset, u32 value);
bool (*clk_enabled)(struct bgmac *bgmac);
void (*clk_enable)(struct bgmac *bgmac, u32 flags);
void (*cco_ctl_maskset)(struct bgmac *bgmac, u32 offset, u32 mask,
u32 set);
u32 (*get_bus_clock)(struct bgmac *bgmac);
void (*cmn_maskset32)(struct bgmac *bgmac, u16 offset, u32 mask,
u32 set);
}; };
int bgmac_enet_probe(struct bgmac *info);
void bgmac_enet_remove(struct bgmac *bgmac);
struct mii_bus *bcma_mdio_mii_register(struct bcma_device *core, u8 phyaddr);
void bcma_mdio_mii_unregister(struct mii_bus *mii_bus);
static inline u32 bgmac_read(struct bgmac *bgmac, u16 offset) static inline u32 bgmac_read(struct bgmac *bgmac, u16 offset)
{ {
return bcma_read32(bgmac->core, offset); return bgmac->read(bgmac, offset);
} }
static inline void bgmac_write(struct bgmac *bgmac, u16 offset, u32 value) static inline void bgmac_write(struct bgmac *bgmac, u16 offset, u32 value)
{ {
bcma_write32(bgmac->core, offset, value); bgmac->write(bgmac, offset, value);
}
static inline u32 bgmac_idm_read(struct bgmac *bgmac, u16 offset)
{
return bgmac->idm_read(bgmac, offset);
}
static inline void bgmac_idm_write(struct bgmac *bgmac, u16 offset, u32 value)
{
bgmac->idm_write(bgmac, offset, value);
}
static inline bool bgmac_clk_enabled(struct bgmac *bgmac)
{
return bgmac->clk_enabled(bgmac);
}
static inline void bgmac_clk_enable(struct bgmac *bgmac, u32 flags)
{
bgmac->clk_enable(bgmac, flags);
}
static inline void bgmac_cco_ctl_maskset(struct bgmac *bgmac, u32 offset,
u32 mask, u32 set)
{
bgmac->cco_ctl_maskset(bgmac, offset, mask, set);
}
static inline u32 bgmac_get_bus_clock(struct bgmac *bgmac)
{
return bgmac->get_bus_clock(bgmac);
}
static inline void bgmac_cmn_maskset32(struct bgmac *bgmac, u16 offset,
u32 mask, u32 set)
{
bgmac->cmn_maskset32(bgmac, offset, mask, set);
} }
static inline void bgmac_maskset(struct bgmac *bgmac, u16 offset, u32 mask, static inline void bgmac_maskset(struct bgmac *bgmac, u16 offset, u32 mask,
...@@ -489,5 +564,4 @@ static inline void bgmac_set(struct bgmac *bgmac, u16 offset, u32 set) ...@@ -489,5 +564,4 @@ static inline void bgmac_set(struct bgmac *bgmac, u16 offset, u32 set)
{ {
bgmac_maskset(bgmac, offset, ~0, set); bgmac_maskset(bgmac, offset, ~0, set);
} }
#endif /* _BGMAC_H */ #endif /* _BGMAC_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment