Skip to content

Commit

Permalink
net: mv643xx_eth: add DT parsing support
Browse files Browse the repository at this point in the history
This adds device tree parsing support for the shared driver of mv643xx_eth.
As the bindings are slightly different from current PPC bindings new binding
documentation is also added. Following PPC-style device setup, the shared
driver now also adds port platform_devices and sets up port platform_data.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Sebastian Hesselbarth authored and David S. Miller committed May 31, 2013
1 parent cb85215 commit 76723bc
Show file tree
Hide file tree
Showing 2 changed files with 234 additions and 4 deletions.
85 changes: 85 additions & 0 deletions Documentation/devicetree/bindings/net/marvell-orion-net.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
Marvell Orion/Discovery ethernet controller
=============================================

The Marvell Discovery ethernet controller can be found on Marvell Orion SoCs
(Kirkwood, Dove, Orion5x, and Discovery Innovation) and as part of Marvell
Discovery system controller chips (mv64[345]60).

The Discovery ethernet controller is described with two levels of nodes. The
first level describes the ethernet controller itself and the second level
describes up to 3 ethernet port nodes within that controller. The reason for
the multiple levels is that the port registers are interleaved within a single
set of controller registers. Each port node describes port-specific properties.

Note: The above separation is only true for Discovery system controllers.
For Orion SoCs we stick to the separation, although there each controller has
only one port associated. Multiple ports are implemented as multiple single-port
controllers. As Kirkwood has some issues with proper initialization after reset,
an extra compatible string is added for it.

* Ethernet controller node

Required controller properties:
- #address-cells: shall be 1.
- #size-cells: shall be 0.
- compatible: shall be one of "marvell,orion-eth", "marvell,kirkwood-eth".
- reg: address and length of the controller registers.

Optional controller properties:
- clocks: phandle reference to the controller clock.
- marvell,tx-checksum-limit: max tx packet size for hardware checksum.

* Ethernet port node

Required port properties:
- device_type: shall be "network".
- compatible: shall be one of "marvell,orion-eth-port",
"marvell,kirkwood-eth-port".
- reg: port number relative to ethernet controller, shall be 0, 1, or 2.
- interrupts: port interrupt.
- local-mac-address: 6 bytes MAC address.

Optional port properties:
- marvell,tx-queue-size: size of the transmit ring buffer.
- marvell,tx-sram-addr: address of transmit descriptor buffer located in SRAM.
- marvell,tx-sram-size: size of transmit descriptor buffer located in SRAM.
- marvell,rx-queue-size: size of the receive ring buffer.
- marvell,rx-sram-addr: address of receive descriptor buffer located in SRAM.
- marvell,rx-sram-size: size of receive descriptor buffer located in SRAM.

and

- phy-handle: phandle reference to ethernet PHY.

or

- speed: port speed if no PHY connected.
- duplex: port mode if no PHY connected.

* Node example:

mdio-bus {
...
ethphy: ethernet-phy@8 {
device_type = "ethernet-phy";
...
};
};

eth: ethernet-controller@72000 {
compatible = "marvell,orion-eth";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x72000 0x2000>;
clocks = <&gate_clk 2>;
marvell,tx-checksum-limit = <1600>;

ethernet@0 {
device_type = "network";
compatible = "marvell,orion-eth-port";
reg = <0>;
interrupts = <29>;
phy-handle = <&ethphy>;
local-mac-address = [00 00 00 00 00 00];
};
};
153 changes: 149 additions & 4 deletions drivers/net/ethernet/marvell/mv643xx_eth.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_net.h>
#include <linux/of_mdio.h>

static char mv643xx_eth_driver_name[] = "mv643xx_eth";
Expand Down Expand Up @@ -2453,13 +2456,148 @@ static void infer_hw_params(struct mv643xx_eth_shared_private *msp)
}
}

#if defined(CONFIG_OF)
static const struct of_device_id mv643xx_eth_shared_ids[] = {
{ .compatible = "marvell,orion-eth", },
{ .compatible = "marvell,kirkwood-eth", },
{ }
};
MODULE_DEVICE_TABLE(of, mv643xx_eth_shared_ids);
#endif

#if defined(CONFIG_OF) && !defined(CONFIG_MV64X60)
#define mv643xx_eth_property(_np, _name, _v) \
do { \
u32 tmp; \
if (!of_property_read_u32(_np, "marvell," _name, &tmp)) \
_v = tmp; \
} while (0)

static struct platform_device *port_platdev[3];

static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev,
struct device_node *pnp)
{
struct platform_device *ppdev;
struct mv643xx_eth_platform_data ppd;
struct resource res;
const char *mac_addr;
int ret;

memset(&ppd, 0, sizeof(ppd));
ppd.shared = pdev;

memset(&res, 0, sizeof(res));
if (!of_irq_to_resource(pnp, 0, &res)) {
dev_err(&pdev->dev, "missing interrupt on %s\n", pnp->name);
return -EINVAL;
}

if (of_property_read_u32(pnp, "reg", &ppd.port_number)) {
dev_err(&pdev->dev, "missing reg property on %s\n", pnp->name);
return -EINVAL;
}

if (ppd.port_number >= 3) {
dev_err(&pdev->dev, "invalid reg property on %s\n", pnp->name);
return -EINVAL;
}

mac_addr = of_get_mac_address(pnp);
if (mac_addr)
memcpy(ppd.mac_addr, mac_addr, 6);

mv643xx_eth_property(pnp, "tx-queue-size", ppd.tx_queue_size);
mv643xx_eth_property(pnp, "tx-sram-addr", ppd.tx_sram_addr);
mv643xx_eth_property(pnp, "tx-sram-size", ppd.tx_sram_size);
mv643xx_eth_property(pnp, "rx-queue-size", ppd.rx_queue_size);
mv643xx_eth_property(pnp, "rx-sram-addr", ppd.rx_sram_addr);
mv643xx_eth_property(pnp, "rx-sram-size", ppd.rx_sram_size);

ppd.phy_node = of_parse_phandle(pnp, "phy-handle", 0);
if (!ppd.phy_node) {
ppd.phy_addr = MV643XX_ETH_PHY_NONE;
of_property_read_u32(pnp, "speed", &ppd.speed);
of_property_read_u32(pnp, "duplex", &ppd.duplex);
}

ppdev = platform_device_alloc(MV643XX_ETH_NAME, ppd.port_number);
if (!ppdev)
return -ENOMEM;
ppdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);

ret = platform_device_add_resources(ppdev, &res, 1);
if (ret)
goto port_err;

ret = platform_device_add_data(ppdev, &ppd, sizeof(ppd));
if (ret)
goto port_err;

ret = platform_device_add(ppdev);
if (ret)
goto port_err;

port_platdev[ppd.port_number] = ppdev;

return 0;

port_err:
platform_device_put(ppdev);
return ret;
}

static int mv643xx_eth_shared_of_probe(struct platform_device *pdev)
{
struct mv643xx_eth_shared_platform_data *pd;
struct device_node *pnp, *np = pdev->dev.of_node;
int ret;

/* bail out if not registered from DT */
if (!np)
return 0;

pd = devm_kzalloc(&pdev->dev, sizeof(*pd), GFP_KERNEL);
if (!pd)
return -ENOMEM;
pdev->dev.platform_data = pd;

mv643xx_eth_property(np, "tx-checksum-limit", pd->tx_csum_limit);

for_each_available_child_of_node(np, pnp) {
ret = mv643xx_eth_shared_of_add_port(pdev, pnp);
if (ret)
return ret;
}
return 0;
}

static void mv643xx_eth_shared_of_remove(void)
{
int n;

for (n = 0; n < 3; n++) {
platform_device_del(port_platdev[n]);
port_platdev[n] = NULL;
}
}
#else
static int mv643xx_eth_shared_of_probe(struct platform_device *pdev)
{
return 0
}

#define mv643xx_eth_shared_of_remove()
#endif

static int mv643xx_eth_shared_probe(struct platform_device *pdev)
{
static int mv643xx_eth_version_printed;
struct mv643xx_eth_shared_platform_data *pd = pdev->dev.platform_data;
struct mv643xx_eth_shared_platform_data *pd;
struct mv643xx_eth_shared_private *msp;
const struct mbus_dram_target_info *dram;
struct resource *res;
int ret;

if (!mv643xx_eth_version_printed++)
pr_notice("MV-643xx 10/100/1000 ethernet driver version %s\n",
Expand All @@ -2472,6 +2610,7 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
msp = devm_kzalloc(&pdev->dev, sizeof(*msp), GFP_KERNEL);
if (msp == NULL)
return -ENOMEM;
platform_set_drvdata(pdev, msp);

msp->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (msp->base == NULL)
Expand All @@ -2488,22 +2627,25 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
if (dram)
mv643xx_eth_conf_mbus_windows(msp, dram);

ret = mv643xx_eth_shared_of_probe(pdev);
if (ret)
return ret;
pd = pdev->dev.platform_data;

msp->tx_csum_limit = (pd != NULL && pd->tx_csum_limit) ?
pd->tx_csum_limit : 9 * 1024;
infer_hw_params(msp);

platform_set_drvdata(pdev, msp);

return 0;
}

static int mv643xx_eth_shared_remove(struct platform_device *pdev)
{
struct mv643xx_eth_shared_private *msp = platform_get_drvdata(pdev);

mv643xx_eth_shared_of_remove();
if (!IS_ERR(msp->clk))
clk_disable_unprepare(msp->clk);

return 0;
}

Expand All @@ -2513,6 +2655,7 @@ static struct platform_driver mv643xx_eth_shared_driver = {
.driver = {
.name = MV643XX_ETH_SHARED_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(mv643xx_eth_shared_ids),
},
};

Expand Down Expand Up @@ -2721,6 +2864,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
if (!IS_ERR(mp->clk)) {
clk_prepare_enable(mp->clk);
mp->t_clk = clk_get_rate(mp->clk);
} else if (!IS_ERR(mp->shared->clk)) {
mp->t_clk = clk_get_rate(mp->shared->clk);
}

set_params(mp, pd);
Expand Down

0 comments on commit 76723bc

Please sign in to comment.