]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - sitara-epos/sitara-epos-kernel.git/commitdiff
ARM: OMAP: AM33XX: NET: cpsw: Add suspend resume support
authorMugunthan V N <mugunthanvnm@ti.com>
Thu, 8 Mar 2012 12:21:47 +0000 (17:51 +0530)
committerSekhar Nori <nsekhar@ti.com>
Fri, 9 Mar 2012 14:47:26 +0000 (20:17 +0530)
Need to reset all sub-components of CPGMAC to gate the clock

Moved omap_dm_timer enable and configure to cpsw_ndo_open and disabled the
timer in cpsw_ndo_close so that during suspend/resume timer will be disabled
and enabled respectively

Added timer omap_dm_timer_free in cpsw_ndo_remove to free the dm_timer while
removing the module

Added wait_for_clock_enable to ensure that CPGMAC clock is enabled before
accessing the CPGMAC registers

TODO: Currently driver doesnot support pm runtime, so hack for wait for cpgmac
clock enable is done. Once PM runtime support is done then the hack will be
removed

Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/cpsw_ale.c
drivers/net/ethernet/ti/davinci_cpdma.c
drivers/net/ethernet/ti/davinci_mdio.c

index 640ceb877ba1b35012e63481810dc79bb93aafe4..3092588cb1be3e88c6a77faa5c35bea3fd496e47 100644 (file)
@@ -140,6 +140,7 @@ struct cpsw_regs {
        u32     soft_reset;
        u32     stat_port_en;
        u32     ptype;
+       u32     soft_idle;
 };
 
 struct cpsw_slave_regs {
@@ -746,6 +747,16 @@ static int cpsw_ndo_open(struct net_device *ndev)
                cpsw_set_coalesce(ndev, &coal);
        }
 
+       /* Enable Timer for capturing cpsw rx interrupts */
+       omap_dm_timer_set_int_enable(dmtimer_rx, OMAP_TIMER_INT_CAPTURE);
+       omap_dm_timer_set_capture(dmtimer_rx, 1, 0, 0);
+       omap_dm_timer_enable(dmtimer_rx);
+
+       /* Enable Timer for capturing cpsw tx interrupts */
+       omap_dm_timer_set_int_enable(dmtimer_tx, OMAP_TIMER_INT_CAPTURE);
+       omap_dm_timer_set_capture(dmtimer_tx, 1, 0, 0);
+       omap_dm_timer_enable(dmtimer_tx);
+
        cpdma_ctlr_start(priv->dma);
        cpsw_intr_enable(priv);
        napi_enable(&priv->napi);
@@ -770,6 +781,10 @@ static int cpsw_ndo_stop(struct net_device *ndev)
        msg(info, ifdown, "shutting down cpsw device\n");
        cpsw_intr_disable(priv);
        cpdma_ctlr_int_ctrl(priv->dma, false);
+
+       omap_dm_timer_set_int_enable(dmtimer_rx, 0);
+       omap_dm_timer_set_int_enable(dmtimer_tx, 0);
+
        netif_stop_queue(priv->ndev);
        napi_disable(&priv->napi);
        netif_carrier_off(priv->ndev);
@@ -1140,17 +1155,18 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
 
        omap_ctrl_writel(CPSW_TIMER_MASK, CPSW_TIMER_CAP_REG);
 
-       /* Enable Timer for capturing cpsw rx interrupts */
        dmtimer_rx = omap_dm_timer_request_specific(CPSW_RX_TIMER_REQ);
-       omap_dm_timer_set_int_enable(dmtimer_rx, OMAP_TIMER_INT_CAPTURE);
-       omap_dm_timer_set_capture(dmtimer_rx, 1, 0, 0);
-       omap_dm_timer_enable(dmtimer_rx);
-
-       /* Enable Timer for capturing cpsw tx interrupts */
+       if (!dmtimer_rx) {
+               dev_err(priv->dev, "Error getting Rx Timer resource\n");
+               ret = -ENODEV;
+               goto clean_iomap_ret;
+       }
        dmtimer_tx = omap_dm_timer_request_specific(CPSW_TX_TIMER_REQ);
-       omap_dm_timer_set_int_enable(dmtimer_tx, OMAP_TIMER_INT_CAPTURE);
-       omap_dm_timer_set_capture(dmtimer_tx, 1, 0, 0);
-       omap_dm_timer_enable(dmtimer_tx);
+       if (!dmtimer_tx) {
+               dev_err(priv->dev, "Error getting Tx Timer resource\n");
+               ret = -ENODEV;
+               goto clean_timer_rx_ret;
+       }
 
        memset(&dma_params, 0, sizeof(dma_params));
        dma_params.dev                  = &pdev->dev;
@@ -1196,7 +1212,7 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
        if (!priv->dma) {
                dev_err(priv->dev, "error initializing dma\n");
                ret = -ENOMEM;
-               goto clean_iomap_ret;
+               goto clean_timer_ret;
        }
 
        priv->txch = cpdma_chan_create(priv->dma, tx_chan_num(0),
@@ -1275,6 +1291,10 @@ clean_dma_ret:
        cpdma_chan_destroy(priv->txch);
        cpdma_chan_destroy(priv->rxch);
        cpdma_ctlr_destroy(priv->dma);
+clean_timer_ret:
+       omap_dm_timer_free(dmtimer_tx);
+clean_timer_rx_ret:
+       omap_dm_timer_free(dmtimer_rx);
 clean_iomap_ret:
        iounmap(priv->regs);
 clean_cpsw_ss_iores_ret:
@@ -1299,6 +1319,8 @@ static int __devexit cpsw_remove(struct platform_device *pdev)
        msg(notice, probe, "removing device\n");
        platform_set_drvdata(pdev, NULL);
 
+       omap_dm_timer_free(dmtimer_rx);
+       omap_dm_timer_free(dmtimer_tx);
        free_irq(ndev->irq, priv);
        cpsw_ale_destroy(priv->ale);
        cpdma_chan_destroy(priv->txch);
@@ -1320,9 +1342,16 @@ static int cpsw_suspend(struct device *dev)
 {
        struct platform_device  *pdev = to_platform_device(dev);
        struct net_device       *ndev = platform_get_drvdata(pdev);
+       struct cpsw_priv *priv = netdev_priv(ndev);
 
        if (netif_running(ndev))
                cpsw_ndo_stop(ndev);
+
+       soft_reset("cpsw", &priv->regs->soft_reset);
+       soft_reset("sliver 0", &priv->slaves[0].sliver->soft_reset);
+       soft_reset("sliver 1", &priv->slaves[1].sliver->soft_reset);
+       soft_reset("cpsw_ss", &priv->ss_regs->soft_reset);
+
        return 0;
 }
 
index 2ce6739084f3e0df810d79b41bf24ca459126c82..9639c31f8755f27a6c5eb51d45b8ba8a7a37cce7 100644 (file)
@@ -662,6 +662,7 @@ EXPORT_SYMBOL_GPL(cpsw_ale_start);
 
 void cpsw_ale_stop(struct cpsw_ale *ale)
 {
+       cpsw_ale_control_set(ale, 0, ALE_ENABLE, 0);
        del_timer_sync(&ale->timer);
        device_remove_file(ale->params.dev, &ale->ale_table_attr);
        device_remove_file(ale->params.dev, &ale->ale_control_attr);
index 617252c7803b1c9c5f98e5b64d362c02619fabce..306d93036c1ed69a47fc9bf041c7d287a6ffa320 100644 (file)
@@ -351,6 +351,17 @@ int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr)
 
        ctlr->state = CPDMA_STATE_IDLE;
 
+       if (ctlr->params.has_soft_reset) {
+               unsigned long timeout = jiffies + HZ/10;
+
+               dma_reg_write(ctlr, CPDMA_SOFTRESET, 1);
+               while (time_before(jiffies, timeout)) {
+                       if (dma_reg_read(ctlr, CPDMA_SOFTRESET) == 0)
+                               break;
+               }
+               WARN_ON(!time_before(jiffies, timeout));
+       }
+
        spin_unlock_irqrestore(&ctlr->lock, flags);
        return 0;
 }
index 7615040df75621dda0684732017e4d21fac425eb..213d204dbc51387b755310dc52bfa2a012fb913c 100644 (file)
@@ -48,6 +48,8 @@
 
 #define DEF_OUT_FREQ           2200000         /* 2.2 MHz */
 
+#define CPGMAC_CLK_CTRL_REG    0x44E00014
+
 struct davinci_mdio_regs {
        u32     version;
        u32     control;
@@ -402,6 +404,28 @@ static int __devexit davinci_mdio_remove(struct platform_device *pdev)
        return 0;
 }
 
+static inline int wait_for_clock_enable(struct davinci_mdio_data *data)
+{
+       unsigned long timeout = jiffies + msecs_to_jiffies(MDIO_TIMEOUT);
+       u32 __iomem *cpgmac_clk = ioremap(CPGMAC_CLK_CTRL_REG, 4);
+       u32 reg = 0;
+
+       while (time_after(timeout, jiffies)) {
+               reg = readl(cpgmac_clk);
+               if ((reg & 0x70000) == 0)
+                       goto iounmap_ret;
+       }
+       dev_err(data->dev,
+               "timed out waiting for CPGMAC clock enable, value = 0x%x\n",
+               reg);
+       iounmap(cpgmac_clk);
+       return -ETIMEDOUT;
+
+iounmap_ret:
+       iounmap(cpgmac_clk);
+       return 0;
+}
+
 static int davinci_mdio_suspend(struct device *dev)
 {
        struct davinci_mdio_data *data = dev_get_drvdata(dev);
@@ -433,12 +457,15 @@ static int davinci_mdio_resume(struct device *dev)
        if (data->clk)
                clk_enable(data->clk);
 
+       /* Need to wait till Module is enabled */
+       wait_for_clock_enable(data);
+
        /* restart the scan state machine */
        ctrl = __raw_readl(&data->regs->control);
        ctrl |= CONTROL_ENABLE;
        __raw_writel(ctrl, &data->regs->control);
-
        data->suspended = false;
+
        spin_unlock(&data->lock);
 
        return 0;