Merge branch 'bcm_sf2-platform-dev'

Florian Fainelli says:

====================
net: dsa: bcm_sf2: Platform conversion

This patch series converts the bcm_sf2 driver from a traditional DSA driver
into a platform_device driver and makes it use the new DSA binding that Andrew
introduced in the latest merge window.

Prior attempts used to coerce the code in net/dsa/dsa2.c to accept the old
binding, while really there is only one broken single user out there: bcm_sf2,
so instead, just assume the new DT binding is deployed and use it accordingly.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2016-08-19 17:15:37 -07:00
commit 484387c9a2
4 changed files with 217 additions and 126 deletions

View File

@ -6,9 +6,13 @@ Required properties:
- reg: addresses and length of the register sets for the device, must be 6
pairs of register addresses and lengths
- interrupts: interrupts for the devices, must be two interrupts
- #address-cells: must be 1, see dsa/dsa.txt
- #size-cells: must be 0, see dsa/dsa.txt
Deprecated binding required properties:
- dsa,mii-bus: phandle to the MDIO bus controller, see dsa/dsa.txt
- dsa,ethernet: phandle to the CPU network interface controller, see dsa/dsa.txt
- #size-cells: must be 0
- #address-cells: must be 2, see dsa/dsa.txt
Subnodes:
@ -39,6 +43,45 @@ Optional properties:
Example:
switch_top@f0b00000 {
compatible = "simple-bus";
#size-cells = <1>;
#address-cells = <1>;
ranges = <0 0xf0b00000 0x40804>;
ethernet_switch@0 {
compatible = "brcm,bcm7445-switch-v4.0";
#size-cells = <0>;
#address-cells = <1>;
reg = <0x0 0x40000
0x40000 0x110
0x40340 0x30
0x40380 0x30
0x40400 0x34
0x40600 0x208>;
reg-names = "core", "reg", intrl2_0", "intrl2_1",
"fcb, "acb";
interrupts = <0 0x18 0
0 0x19 0>;
brcm,num-gphy = <1>;
brcm,num-rgmii-ports = <2>;
brcm,fcb-pause-override;
brcm,acb-packets-inflight;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
label = "gphy";
reg = <0>;
};
};
};
};
Example using the old DSA DeviceTree binding:
switch_top@f0b00000 {
compatible = "simple-bus";
#size-cells = <1>;

View File

@ -136,20 +136,6 @@ static int bcm_sf2_sw_get_sset_count(struct dsa_switch *ds)
return BCM_SF2_STATS_SIZE;
}
static const char *bcm_sf2_sw_drv_probe(struct device *dsa_dev,
struct device *host_dev, int sw_addr,
void **_priv)
{
struct bcm_sf2_priv *priv;
priv = devm_kzalloc(dsa_dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return NULL;
*_priv = priv;
return "Broadcom Starfighter 2";
}
static void bcm_sf2_imp_vlan_setup(struct dsa_switch *ds, int cpu_port)
{
struct bcm_sf2_priv *priv = ds_to_priv(ds);
@ -1571,83 +1557,8 @@ static int bcm_sf2_sw_vlan_dump(struct dsa_switch *ds, int port,
static int bcm_sf2_sw_setup(struct dsa_switch *ds)
{
const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
struct bcm_sf2_priv *priv = ds_to_priv(ds);
struct device_node *dn;
void __iomem **base;
unsigned int port;
unsigned int i;
u32 reg, rev;
int ret;
spin_lock_init(&priv->indir_lock);
mutex_init(&priv->stats_mutex);
/* All the interesting properties are at the parent device_node
* level
*/
dn = ds->cd->of_node->parent;
bcm_sf2_identify_ports(priv, ds->cd->of_node);
priv->irq0 = irq_of_parse_and_map(dn, 0);
priv->irq1 = irq_of_parse_and_map(dn, 1);
base = &priv->core;
for (i = 0; i < BCM_SF2_REGS_NUM; i++) {
*base = of_iomap(dn, i);
if (*base == NULL) {
pr_err("unable to find register: %s\n", reg_names[i]);
ret = -ENOMEM;
goto out_unmap;
}
base++;
}
ret = bcm_sf2_sw_rst(priv);
if (ret) {
pr_err("unable to software reset switch: %d\n", ret);
goto out_unmap;
}
ret = bcm_sf2_mdio_register(ds);
if (ret) {
pr_err("failed to register MDIO bus\n");
goto out_unmap;
}
/* Disable all interrupts and request them */
bcm_sf2_intr_disable(priv);
ret = request_irq(priv->irq0, bcm_sf2_switch_0_isr, 0,
"switch_0", priv);
if (ret < 0) {
pr_err("failed to request switch_0 IRQ\n");
goto out_mdio;
}
ret = request_irq(priv->irq1, bcm_sf2_switch_1_isr, 0,
"switch_1", priv);
if (ret < 0) {
pr_err("failed to request switch_1 IRQ\n");
goto out_free_irq0;
}
/* Reset the MIB counters */
reg = core_readl(priv, CORE_GMNCFGCFG);
reg |= RST_MIB_CNT;
core_writel(priv, reg, CORE_GMNCFGCFG);
reg &= ~RST_MIB_CNT;
core_writel(priv, reg, CORE_GMNCFGCFG);
/* Get the maximum number of ports for this switch */
priv->hw_params.num_ports = core_readl(priv, CORE_IMP0_PRT_ID) + 1;
if (priv->hw_params.num_ports > DSA_MAX_PORTS)
priv->hw_params.num_ports = DSA_MAX_PORTS;
/* Assume a single GPHY setup if we can't read that property */
if (of_property_read_u32(dn, "brcm,num-gphy",
&priv->hw_params.num_gphy))
priv->hw_params.num_gphy = 1;
/* Enable all valid ports and disable those unused */
for (port = 0; port < priv->hw_params.num_ports; port++) {
@ -1662,38 +1573,11 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
bcm_sf2_sw_configure_vlan(ds);
rev = reg_readl(priv, REG_SWITCH_REVISION);
priv->hw_params.top_rev = (rev >> SWITCH_TOP_REV_SHIFT) &
SWITCH_TOP_REV_MASK;
priv->hw_params.core_rev = (rev & SF2_REV_MASK);
rev = reg_readl(priv, REG_PHY_REVISION);
priv->hw_params.gphy_rev = rev & PHY_REVISION_MASK;
pr_info("Starfighter 2 top: %x.%02x, core: %x.%02x base: 0x%p, IRQs: %d, %d\n",
priv->hw_params.top_rev >> 8, priv->hw_params.top_rev & 0xff,
priv->hw_params.core_rev >> 8, priv->hw_params.core_rev & 0xff,
priv->core, priv->irq0, priv->irq1);
return 0;
out_free_irq0:
free_irq(priv->irq0, priv);
out_mdio:
bcm_sf2_mdio_unregister(priv);
out_unmap:
base = &priv->core;
for (i = 0; i < BCM_SF2_REGS_NUM; i++) {
if (*base)
iounmap(*base);
base++;
}
return ret;
}
static struct dsa_switch_driver bcm_sf2_switch_driver = {
.tag_protocol = DSA_TAG_PROTO_BRCM,
.probe = bcm_sf2_sw_drv_probe,
.setup = bcm_sf2_sw_setup,
.set_addr = bcm_sf2_sw_set_addr,
.get_phy_flags = bcm_sf2_sw_get_phy_flags,
@ -1724,19 +1608,168 @@ static struct dsa_switch_driver bcm_sf2_switch_driver = {
.port_vlan_dump = bcm_sf2_sw_vlan_dump,
};
static int __init bcm_sf2_init(void)
static int bcm_sf2_sw_probe(struct platform_device *pdev)
{
register_switch_driver(&bcm_sf2_switch_driver);
const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
struct device_node *dn = pdev->dev.of_node;
struct bcm_sf2_priv *priv;
struct dsa_switch *ds;
void __iomem **base;
struct resource *r;
unsigned int i;
u32 reg, rev;
int ret;
ds = devm_kzalloc(&pdev->dev, sizeof(*ds) + sizeof(*priv), GFP_KERNEL);
if (!ds)
return -ENOMEM;
priv = (struct bcm_sf2_priv *)(ds + 1);
ds->priv = priv;
ds->dev = &pdev->dev;
ds->drv = &bcm_sf2_switch_driver;
dev_set_drvdata(&pdev->dev, ds);
spin_lock_init(&priv->indir_lock);
mutex_init(&priv->stats_mutex);
bcm_sf2_identify_ports(priv, dn->child);
priv->irq0 = irq_of_parse_and_map(dn, 0);
priv->irq1 = irq_of_parse_and_map(dn, 1);
base = &priv->core;
for (i = 0; i < BCM_SF2_REGS_NUM; i++) {
r = platform_get_resource(pdev, IORESOURCE_MEM, i);
*base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(*base)) {
pr_err("unable to find register: %s\n", reg_names[i]);
return PTR_ERR(*base);
}
base++;
}
ret = bcm_sf2_sw_rst(priv);
if (ret) {
pr_err("unable to software reset switch: %d\n", ret);
return ret;
}
ret = bcm_sf2_mdio_register(ds);
if (ret) {
pr_err("failed to register MDIO bus\n");
return ret;
}
/* Disable all interrupts and request them */
bcm_sf2_intr_disable(priv);
ret = devm_request_irq(&pdev->dev, priv->irq0, bcm_sf2_switch_0_isr, 0,
"switch_0", priv);
if (ret < 0) {
pr_err("failed to request switch_0 IRQ\n");
goto out_mdio;
}
ret = devm_request_irq(&pdev->dev, priv->irq1, bcm_sf2_switch_1_isr, 0,
"switch_1", priv);
if (ret < 0) {
pr_err("failed to request switch_1 IRQ\n");
goto out_mdio;
}
/* Reset the MIB counters */
reg = core_readl(priv, CORE_GMNCFGCFG);
reg |= RST_MIB_CNT;
core_writel(priv, reg, CORE_GMNCFGCFG);
reg &= ~RST_MIB_CNT;
core_writel(priv, reg, CORE_GMNCFGCFG);
/* Get the maximum number of ports for this switch */
priv->hw_params.num_ports = core_readl(priv, CORE_IMP0_PRT_ID) + 1;
if (priv->hw_params.num_ports > DSA_MAX_PORTS)
priv->hw_params.num_ports = DSA_MAX_PORTS;
/* Assume a single GPHY setup if we can't read that property */
if (of_property_read_u32(dn, "brcm,num-gphy",
&priv->hw_params.num_gphy))
priv->hw_params.num_gphy = 1;
rev = reg_readl(priv, REG_SWITCH_REVISION);
priv->hw_params.top_rev = (rev >> SWITCH_TOP_REV_SHIFT) &
SWITCH_TOP_REV_MASK;
priv->hw_params.core_rev = (rev & SF2_REV_MASK);
rev = reg_readl(priv, REG_PHY_REVISION);
priv->hw_params.gphy_rev = rev & PHY_REVISION_MASK;
ret = dsa_register_switch(ds, dn);
if (ret)
goto out_mdio;
pr_info("Starfighter 2 top: %x.%02x, core: %x.%02x base: 0x%p, IRQs: %d, %d\n",
priv->hw_params.top_rev >> 8, priv->hw_params.top_rev & 0xff,
priv->hw_params.core_rev >> 8, priv->hw_params.core_rev & 0xff,
priv->core, priv->irq0, priv->irq1);
return 0;
out_mdio:
bcm_sf2_mdio_unregister(priv);
return ret;
}
static int bcm_sf2_sw_remove(struct platform_device *pdev)
{
struct dsa_switch *ds = platform_get_drvdata(pdev);
struct bcm_sf2_priv *priv = ds_to_priv(ds);
/* Disable all ports and interrupts */
priv->wol_ports_mask = 0;
bcm_sf2_sw_suspend(ds);
dsa_unregister_switch(ds);
bcm_sf2_mdio_unregister(priv);
return 0;
}
module_init(bcm_sf2_init);
static void __exit bcm_sf2_exit(void)
#ifdef CONFIG_PM_SLEEP
static int bcm_sf2_suspend(struct device *dev)
{
unregister_switch_driver(&bcm_sf2_switch_driver);
struct platform_device *pdev = to_platform_device(dev);
struct dsa_switch *ds = platform_get_drvdata(pdev);
return dsa_switch_suspend(ds);
}
module_exit(bcm_sf2_exit);
static int bcm_sf2_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct dsa_switch *ds = platform_get_drvdata(pdev);
return dsa_switch_resume(ds);
}
#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(bcm_sf2_pm_ops,
bcm_sf2_suspend, bcm_sf2_resume);
static const struct of_device_id bcm_sf2_of_match[] = {
{ .compatible = "brcm,bcm7445-switch-v4.0" },
{ /* sentinel */ },
};
static struct platform_driver bcm_sf2_driver = {
.probe = bcm_sf2_sw_probe,
.remove = bcm_sf2_sw_remove,
.driver = {
.name = "brcm-sf2",
.of_match_table = bcm_sf2_of_match,
.pm = &bcm_sf2_pm_ops,
},
};
module_platform_driver(bcm_sf2_driver);
MODULE_AUTHOR("Broadcom Corporation");
MODULE_DESCRIPTION("Driver for Broadcom Starfighter 2 ethernet switch chip");

View File

@ -386,4 +386,18 @@ static inline bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst)
void dsa_unregister_switch(struct dsa_switch *ds);
int dsa_register_switch(struct dsa_switch *ds, struct device_node *np);
#ifdef CONFIG_PM_SLEEP
int dsa_switch_suspend(struct dsa_switch *ds);
int dsa_switch_resume(struct dsa_switch *ds);
#else
static inline int dsa_switch_suspend(struct dsa_switch *ds)
{
return 0;
}
static inline int dsa_switch_resume(struct dsa_switch *ds)
{
return 0;
}
#endif /* CONFIG_PM_SLEEP */
#endif

View File

@ -543,7 +543,7 @@ static void dsa_switch_destroy(struct dsa_switch *ds)
}
#ifdef CONFIG_PM_SLEEP
static int dsa_switch_suspend(struct dsa_switch *ds)
int dsa_switch_suspend(struct dsa_switch *ds)
{
int i, ret = 0;
@ -562,8 +562,9 @@ static int dsa_switch_suspend(struct dsa_switch *ds)
return ret;
}
EXPORT_SYMBOL_GPL(dsa_switch_suspend);
static int dsa_switch_resume(struct dsa_switch *ds)
int dsa_switch_resume(struct dsa_switch *ds)
{
int i, ret = 0;
@ -585,6 +586,7 @@ static int dsa_switch_resume(struct dsa_switch *ds)
return 0;
}
EXPORT_SYMBOL_GPL(dsa_switch_resume);
#endif
/* platform driver init and cleanup *****************************************/
@ -1086,7 +1088,6 @@ static int dsa_resume(struct device *d)
static SIMPLE_DEV_PM_OPS(dsa_pm_ops, dsa_suspend, dsa_resume);
static const struct of_device_id dsa_of_match_table[] = {
{ .compatible = "brcm,bcm7445-switch-v4.0" },
{ .compatible = "marvell,dsa", },
{}
};