[U-Boot-Users] Xilinx PowerPC XPS_LL_TEMAC driver

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@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) { }

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@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/javao... _______________________________________________ U-Boot-Users mailing list U-Boot-Users@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@co-nss.co.jp HTTP http://www.co-nss.co.jp/ ------------------------------------------------------------------

Hi,
I corrected some faults and checked normal operation by EDK10.1.
Best Regards,
Yoshio Kashiwagi - Nissin Systems
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index d5e413b..a11238b 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -63,6 +63,7 @@ COBJS-y += uli526x.o COBJS-y += vsc7385.o COBJS-$(CONFIG_XILINX_EMAC) += xilinx_emac.o COBJS-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o +COBJS-$(CONFIG_XILINX_LL_TEMAC)) += xilinx_ll_temac.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/net/xilinx_ll_temac.c b/drivers/net/xilinx_ll_temac. c new file mode 100644 index 0000000..2f75ebc --- /dev/null +++ b/drivers/net/xilinx_ll_temac.c @@ -0,0 +1,371 @@ +/* + * + * Xilinx xps_ll_temac ethernet driver for u-boot + * + * Author: Yoshio Kashiwagi kashiwagi@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 + size; + + if(size) { + addr = addr & ~(CACHE_LINE_SIZE - 1); + 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 + size; + + if(size) { + addr = addr & ~(CACHE_LINE_SIZE - 1); + 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) +{ +} +

In message JN200804261159205.13431171@co-nss.co.jp you wrote:
I corrected some faults and checked normal operation by EDK10.1.
Best Regards,
Yoshio Kashiwagi - Nissin Systems
If this is supposed to be a patch submission, then please don't forget to add your Signed-off-by line
diff --git a/drivers/net/xilinx_ll_temac.c b/drivers/net/xilinx_ll_temac. c
^^^^^^^^^^^^^
new file mode 100644 index 0000000..2f75ebc --- /dev/null +++ b/drivers/net/xilinx_ll_temac.c @@ -0,0 +1,371 @@ +/*
- Xilinx xps_ll_temac ethernet driver for u-boot
- Author: Yoshio Kashiwagi kashiwagi@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
^^^^^^^^^^^^^
Patch was corrupted by your mailer (line wrapping).
...
+/* 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))) ;
Indentation by TAB please (here and everywhere - please heed the Coding Style requirements, see http://www.denx.de/wiki/UBoot/CodingStyle
Please cleanup, fix your mailer, add a s-o-b line and resubmit.
Best regards,
Wolfgang Denk
participants (2)
-
Wolfgang Denk
-
Yoshio Kashiwagi