[U-Boot-Users] Xilinx PowerPC XPS_LL_TEMAC driver
Yoshio Kashiwagi
kashiwagi at co-nss.co.jp
Fri Apr 25 17:14:12 CEST 2008
Hi,
Although I included cache control in this source at the post at this
ML, I found the bug in cache control. I'll correct those bugs.
# However, this code is also checking normal operation by EDK10.1 design.
Best Regards,
Yoshio Kashiwagi - Nissin Systems
> Hi All,
>
> I am writing XPS_LL_TEMAC for Xilinx PowerPC.
> Can anyone give me an advice on which I should correct this source?
>
> Thanks in advance,
>
> Yoshio Kashiwagi - Nissin Systems
>
> /*
> *
> * xilinx_ll_temac.c ethernet driver for u-boot
> *
> * Author: Yoshio Kashiwagi kashiwagi at co-nss.co.jp
> *
> * Copyright (c) 2008 Nissin Systems Co.,Ltd.
> *
> * March 2008 created
> *
> * This program is free software; you can redistribute it and/or
modify
> it
> * under the terms of the GNU General Public License as published
by
> the
> * Free Software Foundation; either version 2 of the License, or (at
> your
> * option) any later version.
> *
> */
> #include <config.h>
> #include <common.h>
> #include <net.h>
> #include <malloc.h>
> #include <asm/errno.h>
> #include <asm/processor.h>
>
> #define S_DMA_CTRL_BASEADDR XPAR_LLTEMAC_0_LLINK_CONNECTED_BASEADDR
> #define XPS_LLTEMAC_BASEADDR XPAR_LLTEMAC_0_BASEADDR
>
> /* XPS_LL_TEMAC SDMA registers definition */
>
> #define TX_NXTDESC_PTR (S_DMA_CTRL_BASEADDR + 0x00)
> #define TX_CURBUF_ADDR (S_DMA_CTRL_BASEADDR + 0x04)
> #define TX_CURBUF_LENGTH (S_DMA_CTRL_BASEADDR + 0x08)
> #define TX_CURDESC_PTR (S_DMA_CTRL_BASEADDR + 0x0c)
> #define TX_TAILDESC_PTR (S_DMA_CTRL_BASEADDR + 0x10)
> #define TX_CHNL_CTRL (S_DMA_CTRL_BASEADDR + 0x14)
> #define TX_IRQ_REG (S_DMA_CTRL_BASEADDR + 0x18)
> #define TX_CHNL_STS (S_DMA_CTRL_BASEADDR + 0x1c)
>
> #define RX_NXTDESC_PTR (S_DMA_CTRL_BASEADDR + 0x20)
> #define RX_CURBUF_ADDR (S_DMA_CTRL_BASEADDR + 0x24)
> #define RX_CURBUF_LENGTH (S_DMA_CTRL_BASEADDR + 0x28)
> #define RX_CURDESC_PTR (S_DMA_CTRL_BASEADDR + 0x2c)
> #define RX_TAILDESC_PTR (S_DMA_CTRL_BASEADDR + 0x30)
> #define RX_CHNL_CTRL (S_DMA_CTRL_BASEADDR + 0x34)
> #define RX_IRQ_REG (S_DMA_CTRL_BASEADDR + 0x38)
> #define RX_CHNL_STS (S_DMA_CTRL_BASEADDR + 0x3c)
>
> #define DMA_CONTROL_REG (S_DMA_CTRL_BASEADDR + 0x40)
>
> /* XPS_LL_TEMAC direct registers definition */
>
> #define TEMAC_RAF0 (XPS_LLTEMAC_BASEADDR + 0x00)
> #define TEMAC_TPF0 (XPS_LLTEMAC_BASEADDR + 0x04)
> #define TEMAC_IFGP0 (XPS_LLTEMAC_BASEADDR + 0x08)
> #define TEMAC_IS0 (XPS_LLTEMAC_BASEADDR + 0x0c)
> #define TEMAC_IP0 (XPS_LLTEMAC_BASEADDR + 0x10)
> #define TEMAC_IE0 (XPS_LLTEMAC_BASEADDR + 0x14)
>
> #define TEMAC_MSW0 (XPS_LLTEMAC_BASEADDR + 0x20)
> #define TEMAC_LSW0 (XPS_LLTEMAC_BASEADDR + 0x24)
> #define TEMAC_CTL0 (XPS_LLTEMAC_BASEADDR + 0x28)
> #define TEMAC_RDY0 (XPS_LLTEMAC_BASEADDR + 0x2c)
>
> #define XTE_RSE_MIIM_RR_MASK 0x0002
> #define XTE_RSE_MIIM_WR_MASK 0x0004
> #define XTE_RSE_CFG_RR_MASK 0x0020
> #define XTE_RSE_CFG_WR_MASK 0x0040
>
> /* XPS_LL_TEMAC indirect registers offset definition */
>
> #define RCW0 0x200
> #define RCW1 0x240
> #define TC 0x280
> #define FCC 0x2c0
> #define EMMC 0x300
> #define PHYC 0x320
> #define MC 0x340
> #define UAW0 0x380
> #define UAW1 0x384
> #define MAW0 0x388
> #define MAW1 0x38c
> #define AFM 0x390
> #define TIS 0x3a0
> #define TIE 0x3a4
> #define MIIMWD 0x3b0
> #define MIIMAI 0x3b4
>
> #define CNTLREG_WRITE_ENABLE_MASK 0x8000
> #define CNTLREG_EMAC1SEL_MASK 0x0400
> #define CNTLREG_ADDRESSCODE_MASK 0x03ff
>
> #define MDIO_ENABLE_MASK 0x40
> #define MDIO_CLOCK_DIV_MASK 0x3F
> #define MDIO_CLOCK_DIV_100MHz 0x28
>
> #define ETHER_MTU 1520
> #define CACHE_LINE_SIZE 32
>
> /* SDMA descriptor status bit definitions */
>
> #define BDSTAT_ERROR_MASK 0x80
> #define BDSTAT_INT_ON_END_MASK 0x40
> #define BDSTAT_STOP_ON_END_MASK 0x20
> #define BDSTAT_COMPLETED_MASK 0x10
> #define BDSTAT_SOP_MASK 0x08
> #define BDSTAT_EOP_MASK 0x04
> #define BDSTAT_CHANBUSY_MASK 0x02
> #define BDSTAT_CHANRESET_MASK 0x01
>
> /* SDMA Buffer Descriptor */
>
> typedef struct cdmac_bd_t {
> struct cdmac_bd_t *next_p;
> unsigned char *phys_buf_p;
> unsigned long buf_len;
> unsigned char stat;
> unsigned char app1_1;
> unsigned short app1_2;
> unsigned long app2;
> unsigned long app3;
> unsigned long app4;
> unsigned long app5;
> } cdmac_bd __attribute((aligned(32))) ;
>
> static cdmac_bd tx_bd;
> static cdmac_bd rx_bd;
> static unsigned char tx_buffer[ETHER_MTU] __attribute((aligned(32)));
> static unsigned char rx_buffer[ETHER_MTU] __attribute((aligned(32)));
>
> struct xps_ll_temac_private {
> int idx;
> unsigned char dev_addr[6];
> };
>
> static void flush_dcache_range(unsigned int addr, unsigned size)
> {
> unsigned int end = addr & ~(CACHE_LINE_SIZE - 1);
>
> if(size) {
> while(addr < end) {
> __asm__ __volatile__("dcbf 0,%0; sync;" : : "r" (addr));
> addr += CACHE_LINE_SIZE;
> }
> }
> }
>
> static void invalidate_dcache_range(unsigned int addr, unsigned size)
> {
> unsigned int end = addr & ~(CACHE_LINE_SIZE - 1);
>
> if(size) {
> while(addr < end) {
> __asm__ __volatile__("dcbi 0,%0; sync;" : : "r" (addr));
> addr += CACHE_LINE_SIZE;
> }
> }
> }
>
> static unsigned int xps_ll_temac_hostif_get(int emac, int phy_addr,
int
> reg_addr)
> {
> *(unsigned int *)TEMAC_LSW0 = phy_addr << 5 | reg_addr;
> *(unsigned int *)TEMAC_CTL0 = MIIMAI | emac << 10;
>
> while(! (*(volatile unsigned int *)TEMAC_RDY0 & XTE_RSE_MIIM_RR_
MASK)
> );
> return *(unsigned int *)TEMAC_LSW0;
> }
>
> static void xps_ll_temac_indirect_set(int emac, int reg_offset, int
reg_
> data)
> {
> *(unsigned int *)TEMAC_LSW0 = reg_data;
> *(unsigned int *)TEMAC_CTL0 = CNTLREG_WRITE_ENABLE_MASK | emac <<
10
> | reg_offset;
> while(! (*(volatile unsigned int *)TEMAC_RDY0 & XTE_RSE_CFG_WR_
MASK))
> ;
> }
>
> static int xps_ll_temac_phy_ctrl(void)
> {
> static int phy_addr = -1;
> static int link = 0;
> int i;
> unsigned int result;
>
> if(phy_addr == -1) {
> for(i = 0;i < 32;i++) {
> result = xps_ll_temac_hostif_get(0, i, 1);
> if((result & 0x0ffff) != 0x0ffff) {
> phy_addr = i;
> break;
> }
> }
> } else {
> result = xps_ll_temac_hostif_get(0, phy_addr, 1);
> }
> if((result & 0x24) != 0x24) {
> if(link) {
> link = 0;
> printf("Link down\n");
> }
> return 0;
> }
> if(link == 0) {
> link = 1;
> } else {
> return 1;
> }
>
> result = xps_ll_temac_hostif_get(0, phy_addr, 10);
> if((result & 0x0800) == 0x0800) {
> xps_ll_temac_indirect_set(0, EMMC, 0x80000000);
> printf("1000BASE-T/FD\n");
> return 1;
> }
> result = xps_ll_temac_hostif_get(0, phy_addr, 5);
> if((result & 0x0100) == 0x0100) {
> xps_ll_temac_indirect_set(0, EMMC, 0x40000000);
> printf("100BASE-T/FD\n");
> } else if((result & 0x0040) == 0x0040) {
> xps_ll_temac_indirect_set(0, EMMC, 0x00000000);
> printf("10BASE-T/FD\n");
> } else {
> printf("Half Duplex not supported\n");
> }
> return 1;
> }
>
> static void xps_ll_temac_bd_init(void)
> {
> memset((void *)&tx_bd, 0, sizeof(cdmac_bd));
> memset((void *)&rx_bd, 0, sizeof(cdmac_bd));
>
> rx_bd.phys_buf_p = &rx_buffer[0];
> rx_bd.next_p = &rx_bd;
> rx_bd.buf_len = ETHER_MTU;
> flush_dcache_range((unsigned int)&rx_bd, sizeof(cdmac_bd));
> *(unsigned int *)RX_CURDESC_PTR = (unsigned int)&rx_bd;
> *(unsigned int *)RX_TAILDESC_PTR = (unsigned int)&rx_bd;
>
> tx_bd.phys_buf_p = &tx_buffer[0];
> tx_bd.next_p = &tx_bd;
> flush_dcache_range((unsigned int)&tx_bd, sizeof(cdmac_bd));
> *(unsigned int *)TX_CURDESC_PTR = (unsigned int)&tx_bd;
> }
>
> static int xps_ll_temac_send(unsigned char *buffer, int length)
> {
> if(xps_ll_temac_phy_ctrl() == 0) return 0;
>
> memcpy(tx_buffer, buffer, length);
> flush_dcache_range((unsigned int)tx_buffer, length);
>
> tx_bd.stat = BDSTAT_SOP_MASK | BDSTAT_EOP_MASK | BDSTAT_STOP_ON_
END_
> MASK;
> tx_bd.buf_len = length;
> flush_dcache_range((unsigned int)&tx_bd, sizeof(cdmac_bd));
>
> *(unsigned int *)TX_CURDESC_PTR = (unsigned int)&tx_bd;
> *(unsigned int *)TX_TAILDESC_PTR = (unsigned int)&tx_bd; /* DMA
> start */
>
> do {
> invalidate_dcache_range((unsigned int)&tx_bd, sizeof(cdmac_bd))
;
> } while(!((volatile int)tx_bd.stat & BDSTAT_COMPLETED_MASK));
>
> return length;
> }
>
> static int xps_ll_temac_recv(void)
> {
> int length;
>
> invalidate_dcache_range((unsigned int)&rx_bd, sizeof(cdmac_bd));
> if(!(rx_bd.stat & BDSTAT_COMPLETED_MASK)) return 0;
>
> length = rx_bd.app5;
> invalidate_dcache_range((unsigned int)rx_bd.phys_buf_p, length);
>
> rx_bd.buf_len = ETHER_MTU;
> rx_bd.stat = 0;
> rx_bd.app5 = 0;
> flush_dcache_range((unsigned int)&rx_bd, sizeof(cdmac_bd));
> *(unsigned int *)RX_TAILDESC_PTR = (unsigned int)&rx_bd;
>
> if(length > 0) {
> NetReceive(rx_bd.phys_buf_p, length);
> }
>
> return length;
> }
>
> static int xps_ll_temac_addr_setup(struct xps_ll_temac_private * lp)
> {
> char * env_p;
> char * end;
> int i, val;
>
> env_p = getenv("ethaddr");
> if (env_p == NULL) {
> printf("cannot get enviroment for \"ethaddr\".\n");
> return -1;
> }
>
> for (i = 0; i < 6; i++) {
> lp->dev_addr[i] = env_p ? simple_strtoul(env_p, &end,
16)
> : 0;
> if (env_p) env_p = (*end) ? end + 1 : end;
> }
>
> /* set up unicast MAC address filter */
> val = lp->dev_addr[3] << 24 | lp->dev_addr[2] << 16 |
> lp->dev_addr[1] << 8 | lp->dev_addr[0];
> xps_ll_temac_indirect_set(0, UAW0, val);
> val = lp->dev_addr[5] << 8 | lp->dev_addr[4];
> xps_ll_temac_indirect_set(0, UAW1, val);
>
> return 0;
> }
>
> static void xps_ll_temac_init(struct eth_device *dev, bd_t *bis)
> {
> struct xps_ll_temac_private *lp = (struct xps_ll_temac_private *)
> dev->priv;
>
> xps_ll_temac_bd_init();
> xps_ll_temac_indirect_set(0, MC, MDIO_ENABLE_MASK | MDIO_CLOCK_
DIV_
> 100MHz);
>
> xps_ll_temac_addr_setup(lp);
> xps_ll_temac_indirect_set(0, AFM, 0x00000000); /* Promiscuos mode
> disable */
> xps_ll_temac_indirect_set(0, RCW1, 0x10000000); /* Enable Receiver
*
> /
> xps_ll_temac_indirect_set(0, TC, 0x10000000); /* Enable
> Transmitter */
>
> }
>
> int eth_init(bd_t *bis)
> {
> static int first = 1;
> struct eth_device *dev;
> struct xps_ll_temac_private *lp;
> int i;
>
> if(!first) return 0;
> first = 0;
> dev = (struct eth_device *) calloc(1, sizeof(struct eth_device)
)
> ;
> if (NULL == dev) return 0;
>
> lp = (struct xps_ll_temac_private *) calloc(1, sizeof(struct
> xps_ll_temac_private));
> if (lp == NULL) return 0;
> dev->priv = lp;
> sprintf(dev->name, "eth0");
>
> xps_ll_temac_init(dev, bis);
>
> printf("%s: Xilinx XPS LocalLink Tri-Mode Ether MAC #%d at 0x%08X.
\
> n",
> dev->name, 0, XPS_LLTEMAC_BASEADDR);
>
> for(i = 0;i < 3;i++) {
> if(xps_ll_temac_phy_ctrl()) break;
> udelay(10000); /* wait second */
> }
> return 1;
> }
>
> int eth_send(volatile void *packet, int length)
> {
> return xps_ll_temac_send((unsigned char *)packet, length);
> }
>
> int eth_rx(void)
> {
> return xps_ll_temac_recv();
> }
>
> void eth_halt(void)
> {
> }
>
>
> ----------------------------------------------------------------------
---
> This SF.net email is sponsored by the 2008 JavaOne(SM) Conference
> Don't miss this year's exciting event. There's still time to save $100.
> Use priority code J8TL2D2.
> http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone
> _______________________________________________
> U-Boot-Users mailing list
> U-Boot-Users at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/u-boot-users
>
※ 4月1日より所属が変わりました
------------------------------------------------------------------
柏木良夫
株式会社日新システムズ 東日本営業部
本 社 〒600-8482 京都市下京区堀川通四条下ル東側 堀川四条ビル
TEL 075-344-7977 FAX 075-344-7887
東京事務所 〒101-0024 東京都千代田区神田和泉町1番地 神田和泉町ビル
TEL 03-5825-2081 FAX 03-5821-1259
E-Mail kashiwagi at co-nss.co.jp HTTP http://www.co-nss.co.jp/
------------------------------------------------------------------
More information about the U-Boot
mailing list