aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--drivers/net/ethernet/cadence/macb.c207
-rw-r--r--drivers/net/ethernet/cadence/macb.h10
2 files changed, 130 insertions, 87 deletions
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index a0a04b3638e6..448a32309dd0 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -2037,8 +2037,8 @@ static void macb_get_regs(struct net_device *dev, struct ethtool_regs *regs,
regs_buff[10] = macb_tx_dma(&bp->queues[0], tail);
regs_buff[11] = macb_tx_dma(&bp->queues[0], head);
+ regs_buff[12] = macb_or_gem_readl(bp, USRIO);
if (macb_is_gem(bp)) {
- regs_buff[12] = gem_readl(bp, USRIO);
regs_buff[13] = gem_readl(bp, DMACFG);
}
}
@@ -2129,17 +2129,19 @@ static const struct net_device_ops macb_netdev_ops = {
};
/*
- * Configure peripheral capacities according to device tree
+ * Configure peripheral capabilities according to device tree
* and integration options used
*/
-static void macb_configure_caps(struct macb *bp)
+static void macb_configure_caps(struct macb *bp, const struct macb_config *dt_conf)
{
u32 dcfg;
- if (MACB_BFEXT(IDNUM, macb_readl(bp, MID)) == 0x2)
+ if (dt_conf)
+ bp->caps = dt_conf->caps;
+
+ if (macb_is_gem_hw(bp->regs)) {
bp->caps |= MACB_CAPS_MACB_IS_GEM;
- if (macb_is_gem(bp)) {
dcfg = gem_readl(bp, DCFG1);
if (GEM_BFEXT(IRQCOR, dcfg) == 0)
bp->caps |= MACB_CAPS_ISR_CLEAR_ON_WRITE;
@@ -2156,15 +2158,17 @@ static void macb_probe_queues(void __iomem *mem,
unsigned int *num_queues)
{
unsigned int hw_q;
- u32 mid;
*queue_mask = 0x1;
*num_queues = 1;
- /* is it macb or gem ? */
- mid = readl_relaxed(mem + MACB_MID);
-
- if (MACB_BFEXT(IDNUM, mid) < 0x2)
+ /* is it macb or gem ?
+ *
+ * We need to read directly from the hardware here because
+ * we are early in the probe process and don't have the
+ * MACB_CAPS_MACB_IS_GEM flag positioned
+ */
+ if (!macb_is_gem_hw(mem))
return;
/* bit 0 is never set but queue 0 always exists */
@@ -2177,59 +2181,73 @@ static void macb_probe_queues(void __iomem *mem,
(*num_queues)++;
}
-static int macb_init(struct platform_device *pdev)
+static int macb_clk_init(struct platform_device *pdev, struct clk **pclk,
+ struct clk **hclk, struct clk **tx_clk)
{
- struct net_device *dev = platform_get_drvdata(pdev);
- unsigned int hw_q, queue_mask, q, num_queues;
- struct macb *bp = netdev_priv(dev);
- struct macb_queue *queue;
int err;
- u32 val;
- bp->pclk = devm_clk_get(&pdev->dev, "pclk");
- if (IS_ERR(bp->pclk)) {
- err = PTR_ERR(bp->pclk);
+ *pclk = devm_clk_get(&pdev->dev, "pclk");
+ if (IS_ERR(*pclk)) {
+ err = PTR_ERR(*pclk);
dev_err(&pdev->dev, "failed to get macb_clk (%u)\n", err);
return err;
}
- bp->hclk = devm_clk_get(&pdev->dev, "hclk");
- if (IS_ERR(bp->hclk)) {
- err = PTR_ERR(bp->hclk);
+ *hclk = devm_clk_get(&pdev->dev, "hclk");
+ if (IS_ERR(*hclk)) {
+ err = PTR_ERR(*hclk);
dev_err(&pdev->dev, "failed to get hclk (%u)\n", err);
return err;
}
- bp->tx_clk = devm_clk_get(&pdev->dev, "tx_clk");
- if (IS_ERR(bp->tx_clk))
- bp->tx_clk = NULL;
+ *tx_clk = devm_clk_get(&pdev->dev, "tx_clk");
+ if (IS_ERR(*tx_clk))
+ *tx_clk = NULL;
- err = clk_prepare_enable(bp->pclk);
+ err = clk_prepare_enable(*pclk);
if (err) {
dev_err(&pdev->dev, "failed to enable pclk (%u)\n", err);
return err;
}
- err = clk_prepare_enable(bp->hclk);
+ err = clk_prepare_enable(*hclk);
if (err) {
dev_err(&pdev->dev, "failed to enable hclk (%u)\n", err);
goto err_disable_pclk;
}
- err = clk_prepare_enable(bp->tx_clk);
+ err = clk_prepare_enable(*tx_clk);
if (err) {
dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err);
goto err_disable_hclk;
}
+ return 0;
+
+err_disable_hclk:
+ clk_disable_unprepare(*hclk);
+
+err_disable_pclk:
+ clk_disable_unprepare(*pclk);
+
+ return err;
+}
+
+static int macb_init(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ unsigned int hw_q, q;
+ struct macb *bp = netdev_priv(dev);
+ struct macb_queue *queue;
+ int err;
+ u32 val;
+
/* set the queue register mapping once for all: queue0 has a special
* register mapping but we don't want to test the queue index then
* compute the corresponding register offset at run time.
*/
- macb_probe_queues(bp->regs, &queue_mask, &num_queues);
-
for (hw_q = 0, q = 0; hw_q < MACB_MAX_QUEUES; ++hw_q) {
- if (!(queue_mask & (1 << hw_q)))
+ if (!(bp->queue_mask & (1 << hw_q)))
continue;
queue = &bp->queues[q];
@@ -2261,7 +2279,7 @@ static int macb_init(struct platform_device *pdev)
dev_err(&pdev->dev,
"Unable to request IRQ %d (error %d)\n",
queue->irq, err);
- goto err_disable_tx_clk;
+ return err;
}
INIT_WORK(&queue->tx_error_task, macb_tx_error_task);
@@ -2311,26 +2329,12 @@ static int macb_init(struct platform_device *pdev)
macb_or_gem_writel(bp, USRIO, val);
- /* setup capacities */
- macb_configure_caps(bp);
-
/* Set MII management clock divider */
val = macb_mdc_clk_div(bp);
val |= macb_dbw(bp);
macb_writel(bp, NCFGR, val);
return 0;
-
-err_disable_tx_clk:
- clk_disable_unprepare(bp->tx_clk);
-
-err_disable_hclk:
- clk_disable_unprepare(bp->hclk);
-
-err_disable_pclk:
- clk_disable_unprepare(bp->pclk);
-
- return err;
}
#if defined(CONFIG_OF)
@@ -2598,30 +2602,41 @@ static const struct net_device_ops at91ether_netdev_ops = {
#endif
};
-static int at91ether_init(struct platform_device *pdev)
+static int at91ether_clk_init(struct platform_device *pdev, struct clk **pclk,
+ struct clk **hclk, struct clk **tx_clk)
{
- struct net_device *dev = platform_get_drvdata(pdev);
- struct macb *bp = netdev_priv(dev);
int err;
- u32 reg;
- bp->pclk = devm_clk_get(&pdev->dev, "ether_clk");
- if (IS_ERR(bp->pclk))
- return PTR_ERR(bp->pclk);
+ *hclk = NULL;
+ *tx_clk = NULL;
+
+ *pclk = devm_clk_get(&pdev->dev, "ether_clk");
+ if (IS_ERR(*pclk))
+ return PTR_ERR(*pclk);
- err = clk_prepare_enable(bp->pclk);
+ err = clk_prepare_enable(*pclk);
if (err) {
dev_err(&pdev->dev, "failed to enable pclk (%u)\n", err);
return err;
}
+ return 0;
+}
+
+static int at91ether_init(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct macb *bp = netdev_priv(dev);
+ int err;
+ u32 reg;
+
dev->netdev_ops = &at91ether_netdev_ops;
dev->ethtool_ops = &macb_ethtool_ops;
err = devm_request_irq(&pdev->dev, dev->irq, at91ether_interrupt,
0, dev->name, dev);
if (err)
- goto err_disable_clk;
+ return err;
macb_writel(bp, NCR, 0);
@@ -2632,37 +2647,37 @@ static int at91ether_init(struct platform_device *pdev)
macb_writel(bp, NCFGR, reg);
return 0;
-
-err_disable_clk:
- clk_disable_unprepare(bp->pclk);
-
- return err;
}
static const struct macb_config at91sam9260_config = {
.caps = MACB_CAPS_USRIO_HAS_CLKEN | MACB_CAPS_USRIO_DEFAULT_IS_MII,
+ .clk_init = macb_clk_init,
.init = macb_init,
};
static const struct macb_config pc302gem_config = {
.caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE,
.dma_burst_length = 16,
+ .clk_init = macb_clk_init,
.init = macb_init,
};
static const struct macb_config sama5d3_config = {
.caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE,
.dma_burst_length = 16,
+ .clk_init = macb_clk_init,
.init = macb_init,
};
static const struct macb_config sama5d4_config = {
.caps = 0,
.dma_burst_length = 4,
+ .clk_init = macb_clk_init,
.init = macb_init,
};
static const struct macb_config emac_config = {
+ .clk_init = at91ether_clk_init,
.init = at91ether_init,
};
@@ -2683,9 +2698,13 @@ MODULE_DEVICE_TABLE(of, macb_dt_ids);
static int macb_probe(struct platform_device *pdev)
{
+ int (*clk_init)(struct platform_device *, struct clk **,
+ struct clk **, struct clk **)
+ = macb_clk_init;
int (*init)(struct platform_device *) = macb_init;
struct device_node *np = pdev->dev.of_node;
const struct macb_config *macb_config = NULL;
+ struct clk *pclk, *hclk, *tx_clk;
unsigned int queue_mask, num_queues;
struct macb_platform_data *pdata;
struct phy_device *phydev;
@@ -2696,15 +2715,34 @@ static int macb_probe(struct platform_device *pdev)
struct macb *bp;
int err;
+ if (np) {
+ const struct of_device_id *match;
+
+ match = of_match_node(macb_dt_ids, np);
+ if (match && match->data) {
+ macb_config = match->data;
+ clk_init = macb_config->clk_init;
+ init = macb_config->init;
+ }
+ }
+
+ err = clk_init(pdev, &pclk, &hclk, &tx_clk);
+ if (err)
+ return err;
+
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mem = devm_ioremap_resource(&pdev->dev, regs);
- if (IS_ERR(mem))
- return PTR_ERR(mem);
+ if (IS_ERR(mem)) {
+ err = PTR_ERR(mem);
+ goto err_disable_clocks;
+ }
macb_probe_queues(mem, &queue_mask, &num_queues);
dev = alloc_etherdev_mq(sizeof(*bp), num_queues);
- if (!dev)
- return -ENOMEM;
+ if (!dev) {
+ err = -ENOMEM;
+ goto err_disable_clocks;
+ }
dev->base_addr = regs->start;
@@ -2715,13 +2753,24 @@ static int macb_probe(struct platform_device *pdev)
bp->dev = dev;
bp->regs = mem;
bp->num_queues = num_queues;
+ bp->queue_mask = queue_mask;
+ if (macb_config)
+ bp->dma_burst_length = macb_config->dma_burst_length;
+ bp->pclk = pclk;
+ bp->hclk = hclk;
+ bp->tx_clk = tx_clk;
spin_lock_init(&bp->lock);
+ /* setup capabilities */
+ macb_configure_caps(bp, macb_config);
+
platform_set_drvdata(pdev, dev);
dev->irq = platform_get_irq(pdev, 0);
- if (dev->irq < 0)
- return dev->irq;
+ if (dev->irq < 0) {
+ err = dev->irq;
+ goto err_disable_clocks;
+ }
mac = of_get_mac_address(np);
if (mac)
@@ -2740,20 +2789,6 @@ static int macb_probe(struct platform_device *pdev)
bp->phy_interface = err;
}
- if (np) {
- const struct of_device_id *match;
-
- match = of_match_node(macb_dt_ids, np);
- if (match)
- macb_config = match->data;
- }
-
- if (macb_config) {
- bp->caps = macb_config->caps;
- bp->dma_burst_length = macb_config->dma_burst_length;
- init = macb_config->init;
- }
-
/* IP specific init */
err = init(pdev);
if (err)
@@ -2762,7 +2797,7 @@ static int macb_probe(struct platform_device *pdev)
err = register_netdev(dev);
if (err) {
dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
- goto err_disable_clocks;
+ goto err_out_unregister_netdev;
}
err = macb_mii_init(bp);
@@ -2784,14 +2819,14 @@ static int macb_probe(struct platform_device *pdev)
err_out_unregister_netdev:
unregister_netdev(dev);
-err_disable_clocks:
- clk_disable_unprepare(bp->tx_clk);
- clk_disable_unprepare(bp->hclk);
- clk_disable_unprepare(bp->pclk);
-
err_out_free_netdev:
free_netdev(dev);
+err_disable_clocks:
+ clk_disable_unprepare(tx_clk);
+ clk_disable_unprepare(hclk);
+ clk_disable_unprepare(pclk);
+
return err;
}
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index bc6e35c40822..eb7d76f7bf6a 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -11,7 +11,7 @@
#define _MACB_H
#define MACB_GREGS_NBR 16
-#define MACB_GREGS_VERSION 1
+#define MACB_GREGS_VERSION 2
#define MACB_MAX_QUEUES 8
/* MACB register offsets */
@@ -754,6 +754,8 @@ struct macb_or_gem_ops {
struct macb_config {
u32 caps;
unsigned int dma_burst_length;
+ int (*clk_init)(struct platform_device *pdev, struct clk **pclk,
+ struct clk **hclk, struct clk **tx_clk);
int (*init)(struct platform_device *pdev);
};
@@ -785,6 +787,7 @@ struct macb {
size_t rx_buffer_size;
unsigned int num_queues;
+ unsigned int queue_mask;
struct macb_queue queues[MACB_MAX_QUEUES];
spinlock_t lock;
@@ -830,4 +833,9 @@ static inline bool macb_is_gem(struct macb *bp)
return !!(bp->caps & MACB_CAPS_MACB_IS_GEM);
}
+static inline bool macb_is_gem_hw(void __iomem *addr)
+{
+ return !!(MACB_BFEXT(IDNUM, readl_relaxed(addr + MACB_MID)) >= 0x2);
+}
+
#endif /* _MACB_H */