예제 #1
0
파일: ftgmac100.c 프로젝트: openbmc/qemu
/*
 * This is purely informative. The HW can poll the RW (and RX) ring
 * buffers for available descriptors but we don't need to trigger a
 * timer for that in qemu.
 */
static void ftgmac100_rxpoll(Ftgmac100State *s)
{
    /* Polling times :
     *
     * Speed      TIME_SEL=0    TIME_SEL=1
     *
     *    10         51.2 ms      819.2 ms
     *   100         5.12 ms      81.92 ms
     *  1000        1.024 ms     16.384 ms
     */
    static const int div[] = { 20, 200, 1000 };

    uint32_t cnt = 1024 * FTGMAC100_APTC_RXPOLL_CNT(s->aptcr);
    uint32_t speed = (s->maccr & FTGMAC100_MACCR_FAST_MODE) ? 1 : 0;
    uint32_t period __attribute__ ((unused));

    if (s->aptcr & FTGMAC100_APTC_RXPOLL_TIME_SEL) {
        cnt <<= 4;
    }

    if (s->maccr & FTGMAC100_MACCR_GIGA_MODE) {
        speed = 2;
    }

    period = cnt / div[speed];

    DEBUG("polling in %d ms\n", period);
}
예제 #2
0
	iowrite32(laddr, priv->base + FTGMAC100_OFFSET_MAC_LADR);
}

static void ftgmac100_init_hw(struct ftgmac100 *priv)
{
	/* setup ring buffer base registers */
	ftgmac100_set_rx_ring_base(priv,
				   priv->descs_dma_addr +
				   offsetof(struct ftgmac100_descs, rxdes));
	ftgmac100_set_normal_prio_tx_ring_base(priv,
					       priv->descs_dma_addr +
					       offsetof(struct ftgmac100_descs, txdes));

	ftgmac100_set_rx_buffer_size(priv, RX_BUF_SIZE);

	iowrite32(FTGMAC100_APTC_RXPOLL_CNT(1), priv->base + FTGMAC100_OFFSET_APTC);

	ftgmac100_set_mac(priv, priv->netdev->dev_addr);
}

#define MACCR_ENABLE_ALL	(FTGMAC100_MACCR_TXDMA_EN	| \
				 FTGMAC100_MACCR_RXDMA_EN	| \
				 FTGMAC100_MACCR_TXMAC_EN	| \
				 FTGMAC100_MACCR_RXMAC_EN	| \
				 FTGMAC100_MACCR_FULLDUP	| \
				 FTGMAC100_MACCR_CRC_APD	| \
				 FTGMAC100_MACCR_RX_RUNT	| \
				 FTGMAC100_MACCR_RX_BROADPKT)

static void ftgmac100_start_hw(struct ftgmac100 *priv, int speed)
{
예제 #3
0
파일: ftgmac100.c 프로젝트: OpenNoah/u-boot
static int ftgmac100_init(struct eth_device *dev, bd_t *bd)
{
	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
	struct ftgmac100_data *priv = dev->priv;
	struct ftgmac100_txdes *txdes;
	struct ftgmac100_rxdes *rxdes;
	unsigned int maccr;
	void *buf;
	int i;

	debug("%s()\n", __func__);

	if (!priv->txdes) {
		txdes = dma_alloc_coherent(
			sizeof(*txdes) * PKTBUFSTX, &priv->txdes_dma);
		if (!txdes)
			panic("ftgmac100: out of memory\n");
		memset(txdes, 0, sizeof(*txdes) * PKTBUFSTX);
		priv->txdes = txdes;
	}
	txdes = priv->txdes;

	if (!priv->rxdes) {
		rxdes = dma_alloc_coherent(
			sizeof(*rxdes) * PKTBUFSRX, &priv->rxdes_dma);
		if (!rxdes)
			panic("ftgmac100: out of memory\n");
		memset(rxdes, 0, sizeof(*rxdes) * PKTBUFSRX);
		priv->rxdes = rxdes;
	}
	rxdes = priv->rxdes;

	/* set the ethernet address */
	ftgmac100_set_mac_from_env(dev);

	/* disable all interrupts */
	writel(0, &ftgmac100->ier);

	/* initialize descriptors */
	priv->tx_index = 0;
	priv->rx_index = 0;

	txdes[PKTBUFSTX - 1].txdes0	= FTGMAC100_TXDES0_EDOTR;
	rxdes[PKTBUFSRX - 1].rxdes0	= FTGMAC100_RXDES0_EDORR;

	for (i = 0; i < PKTBUFSTX; i++) {
		/* TXBUF_BADR */
		if (!txdes[i].txdes2) {
			buf = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE);
			if (!buf)
				panic("ftgmac100: out of memory\n");
			txdes[i].txdes3 = virt_to_phys(buf);
			txdes[i].txdes2 = (uint)buf;
		}
		txdes[i].txdes1 = 0;
	}

	for (i = 0; i < PKTBUFSRX; i++) {
		/* RXBUF_BADR */
		if (!rxdes[i].rxdes2) {
			buf = net_rx_packets[i];
			rxdes[i].rxdes3 = virt_to_phys(buf);
			rxdes[i].rxdes2 = (uint)buf;
		}
		rxdes[i].rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
	}

	/* transmit ring */
	writel(priv->txdes_dma, &ftgmac100->txr_badr);

	/* receive ring */
	writel(priv->rxdes_dma, &ftgmac100->rxr_badr);

	/* poll receive descriptor automatically */
	writel(FTGMAC100_APTC_RXPOLL_CNT(1), &ftgmac100->aptc);

	/* config receive buffer size register */
	writel(FTGMAC100_RBSR_SIZE(RBSR_DEFAULT_VALUE), &ftgmac100->rbsr);

	/* enable transmitter, receiver */
	maccr = FTGMAC100_MACCR_TXMAC_EN |
		FTGMAC100_MACCR_RXMAC_EN |
		FTGMAC100_MACCR_TXDMA_EN |
		FTGMAC100_MACCR_RXDMA_EN |
		FTGMAC100_MACCR_CRC_APD |
		FTGMAC100_MACCR_FULLDUP |
		FTGMAC100_MACCR_RX_RUNT |
		FTGMAC100_MACCR_RX_BROADPKT;

	writel(maccr, &ftgmac100->maccr);

	if (!ftgmac100_phy_init(dev)) {
		if (!ftgmac100_update_link_speed(dev))
			return -1;
	}

	return 0;
}
예제 #4
0
파일: ftgmac100.c 프로젝트: openbmc/qemu
static void ftgmac100_write(void *opaque, hwaddr addr,
                          uint64_t value, unsigned size)
{
    Ftgmac100State *s = FTGMAC100(opaque);

    DEBUG("writing 0x%08x @ 0x%" HWADDR_PRIx "\n", (int)value, addr);

    switch (addr & 0xff) {
    case FTGMAC100_ISR: /* Interrupt status */
        s->isr &= ~value;
        break;
    case FTGMAC100_IER:  /* Interrupt control */
        s->ier = value;
        break;
    case FTGMAC100_MAC_MADR: /* MAC */
        s->conf.macaddr.a[0] = value >> 8;
        s->conf.macaddr.a[1] = value;
        break;
    case FTGMAC100_MAC_LADR:
        s->conf.macaddr.a[2] = value >> 24;
        s->conf.macaddr.a[3] = value >> 16;
        s->conf.macaddr.a[4] = value >> 8;
        s->conf.macaddr.a[5] = value;
        break;

    case FTGMAC100_RXR_BADR:  /* Ring buffer address */
        s->rx_ring = value;
        s->rx_descriptor = s->rx_ring;
        break;

    case FTGMAC100_RBSR: /* DMA buffer size */
        s->rbsr = value;
        break;

    case FTGMAC100_NPTXR_BADR:  /* Transmit buffer address */
        s->tx_ring = value;
        s->tx_descriptor = s->tx_ring;
        break;

    case FTGMAC100_NPTXPD: /* Trigger transmit */
        if (s->maccr & FTGMAC100_MACCR_TXDMA_EN) {
            ftgmac100_do_tx(s);
        }
        break;

    case FTGMAC100_RXPD: /* Receive Poll Demand Register */
        if ((s->maccr & FTGMAC100_MACCR_RXDMA_EN) && !s->rx_enabled) {
            /*
             * TODO: This is required for u-boot but clearly, this is
             * broken.
             */
            ftgmac100_enable_rx(s);
        }
        break;

    case FTGMAC100_APTC: /* Automatic polling */
        s->aptcr = value;

        if (FTGMAC100_APTC_RXPOLL_CNT(s->aptcr)) {
            ftgmac100_rxpoll(s);
        }

        if (FTGMAC100_APTC_TXPOLL_CNT(s->aptcr)) {
            qemu_log_mask(LOG_UNIMP, "%s: no transmit polling\n", __func__);
        }
        break;

    case FTGMAC100_MACCR: /* MAC Device control */
        s->maccr = value;
        if (value & FTGMAC100_MACCR_SW_RST) {
            ftgmac100_reset(DEVICE(s));
        }

        if ((s->maccr & FTGMAC100_MACCR_RXDMA_EN) && !s->rx_enabled) {
            ftgmac100_enable_rx(s);
        }

        if ((s->maccr & FTGMAC100_MACCR_RXDMA_EN) == 0) {
            s->rx_enabled = 0;
        }
        break;

    case FTGMAC100_PHYCR:  /* PHY Device control */
        s->phycr = value;
        if (value & FTGMAC100_PHYCR_MIIWR) {
            do_phy_write(s, extract32(value, 21, 5), s->phydata & 0xffff);
            s->phycr &= ~FTGMAC100_PHYCR_MIIWR;
       } else {
            s->phydata = do_phy_read(s, extract32(value, 21, 5)) << 16;
            s->phycr &= ~FTGMAC100_PHYCR_MIIRD;
       }
        break;
    case FTGMAC100_PHYDATA:
        s->phydata = value;
        break;
    default:
        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%"
                      HWADDR_PRIx "\n", TYPE_FTGMAC100, __func__, addr);
        break;
    }

    ftgmac100_update_irq(s);
}
예제 #5
0
파일: ftgmac100.c 프로젝트: Noltari/u-boot
static int ftgmac100_start(struct udevice *dev)
{
	struct eth_pdata *plat = dev_get_platdata(dev);
	struct ftgmac100_data *priv = dev_get_priv(dev);
	struct ftgmac100 *ftgmac100 = priv->iobase;
	struct phy_device *phydev = priv->phydev;
	unsigned int maccr;
	ulong start, end;
	int ret;
	int i;

	debug("%s()\n", __func__);

	ftgmac100_reset(priv);

	/* set the ethernet address */
	ftgmac100_set_mac(priv, plat->enetaddr);

	/* disable all interrupts */
	writel(0, &ftgmac100->ier);

	/* initialize descriptors */
	priv->tx_index = 0;
	priv->rx_index = 0;

	for (i = 0; i < PKTBUFSTX; i++) {
		priv->txdes[i].txdes3 = 0;
		priv->txdes[i].txdes0 = 0;
	}
	priv->txdes[PKTBUFSTX - 1].txdes0 = priv->txdes0_edotr_mask;

	start = (ulong)&priv->txdes[0];
	end = start + roundup(sizeof(priv->txdes), ARCH_DMA_MINALIGN);
	flush_dcache_range(start, end);

	for (i = 0; i < PKTBUFSRX; i++) {
		priv->rxdes[i].rxdes3 = (unsigned int)net_rx_packets[i];
		priv->rxdes[i].rxdes0 = 0;
	}
	priv->rxdes[PKTBUFSRX - 1].rxdes0 = priv->rxdes0_edorr_mask;

	start = (ulong)&priv->rxdes[0];
	end = start + roundup(sizeof(priv->rxdes), ARCH_DMA_MINALIGN);
	flush_dcache_range(start, end);

	/* transmit ring */
	writel((u32)priv->txdes, &ftgmac100->txr_badr);

	/* receive ring */
	writel((u32)priv->rxdes, &ftgmac100->rxr_badr);

	/* poll receive descriptor automatically */
	writel(FTGMAC100_APTC_RXPOLL_CNT(1), &ftgmac100->aptc);

	/* config receive buffer size register */
	writel(FTGMAC100_RBSR_SIZE(FTGMAC100_RBSR_DEFAULT), &ftgmac100->rbsr);

	/* enable transmitter, receiver */
	maccr = FTGMAC100_MACCR_TXMAC_EN |
		FTGMAC100_MACCR_RXMAC_EN |
		FTGMAC100_MACCR_TXDMA_EN |
		FTGMAC100_MACCR_RXDMA_EN |
		FTGMAC100_MACCR_CRC_APD |
		FTGMAC100_MACCR_FULLDUP |
		FTGMAC100_MACCR_RX_RUNT |
		FTGMAC100_MACCR_RX_BROADPKT;

	writel(maccr, &ftgmac100->maccr);

	ret = phy_startup(phydev);
	if (ret) {
		dev_err(phydev->dev, "Could not start PHY\n");
		return ret;
	}

	ret = ftgmac100_phy_adjust_link(priv);
	if (ret) {
		dev_err(phydev->dev,  "Could not adjust link\n");
		return ret;
	}

	printf("%s: link up, %d Mbps %s-duplex mac:%pM\n", phydev->dev->name,
	       phydev->speed, phydev->duplex ? "full" : "half", plat->enetaddr);

	return 0;
}