@@ -453,11 +453,33 @@ static int setup_phy(struct udevice *dev)
return 1;
}
+/* Reset DMA engine */
+static void axi_dma_reset(struct axidma_priv *priv)
+{
+ u32 timeout = 500;
+
+ /* Reset the engine so the hardware starts from a known state */
+ writel(XAXIDMA_CR_RESET_MASK, &priv->dmatx->control);
+ writel(XAXIDMA_CR_RESET_MASK, &priv->dmarx->control);
+
+ /* At the initialization time, hardware should finish reset quickly */
+ while (timeout--) {
+ /* Check transmit/receive channel */
+ /* Reset is done when the reset bit is low */
+ if (!((readl(&priv->dmatx->control) |
+ readl(&priv->dmarx->control)) & XAXIDMA_CR_RESET_MASK))
+ break;
+ }
+ if (!timeout)
+ printf("%s: DMA reset timeout!\n", __func__);
+}
+
/* STOP DMA transfers */
static void axiemac_stop(struct udevice *dev)
{
struct axidma_priv *priv = dev_get_priv(dev);
u32 temp;
+ int count;
/* Stop the hardware */
temp = readl(&priv->dmatx->control);
@@ -468,6 +490,21 @@ static void axiemac_stop(struct udevice *dev)
temp &= ~XAXIDMA_CR_RUNSTOP_MASK;
writel(temp, &priv->dmarx->control);
+ /* Give DMAs a chance to halt gracefully */
+ temp = readl(&priv->dmarx->status);
+ for (count = 0; !(temp & XAXIDMA_HALTED_MASK) && count < 5; ++count) {
+ mdelay(20);
+ temp = readl(&priv->dmarx->status);
+ }
+
+ temp = readl(&priv->dmatx->status);
+ for (count = 0; !(temp & XAXIDMA_HALTED_MASK) && count < 5; ++count) {
+ mdelay(20);
+ temp = readl(&priv->dmatx->status);
+ }
+
+ axi_dma_reset(priv);
+
debug("axiemac: Halted\n");
}
@@ -552,29 +589,6 @@ static int axiemac_write_hwaddr(struct udevice *dev)
return 0;
}
-/* Reset DMA engine */
-static void axi_dma_init(struct axidma_priv *priv)
-{
- u32 timeout = 500;
-
- /* Reset the engine so the hardware starts from a known state */
- writel(XAXIDMA_CR_RESET_MASK, &priv->dmatx->control);
- writel(XAXIDMA_CR_RESET_MASK, &priv->dmarx->control);
-
- /* At the initialization time, hardware should finish reset quickly */
- while (timeout--) {
- /* Check transmit/receive channel */
- /* Reset is done when the reset bit is low */
- if (!((readl(&priv->dmatx->control) |
- readl(&priv->dmarx->control))
- & XAXIDMA_CR_RESET_MASK)) {
- break;
- }
- }
- if (!timeout)
- printf("%s: Timeout\n", __func__);
-}
-
static int axiemac_start(struct udevice *dev)
{
struct axidma_priv *priv = dev_get_priv(dev);
@@ -587,7 +601,7 @@ static int axiemac_start(struct udevice *dev)
* reset, and since AXIDMA reset line is connected to AxiEthernet, this
* would ensure a reset of AxiEthernet.
*/
- axi_dma_init(priv);
+ axi_dma_reset(priv);
/* Initialize AxiEthernet hardware. */
if (priv->mactype == EMAC_1G) {