From mboxrd@z Thu Jan 1 00:00:00 1970 From: Michal Simek Date: Sun, 27 Apr 2008 14:32:07 +0200 Subject: [U-Boot-Users] [PATCH] Xilinx PowerPC XPS_LL_TEMAC driver In-Reply-To: References: Message-ID: <48147247.3030200@seznam.cz> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de Hi Yoshio, my description is in patch > Signed-off-by: Yoshio Kashiwagi > --- > drivers/net/Makefile | 1 + > drivers/net/xilinx_ll_temac.c | 371 ++++++++++++++++++++++++++++++++++ > +++++++ > 2 files changed, 372 insertions(+), 0 deletions(-) > create mode 100644 drivers/net/xilinx_ll_temac.c > > 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 ^^ two brackets. > 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 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 > +#include > +#include > +#include > +#include you don't use values from errno.h. You can remove it. Microblaze cpu don't have this header too. > +#include > + > +#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; > + } > + } > +} Your previous set of patches was better than this style. You can't add assembler code to c code which is not in ppc specific folder. Please use macros for it. > +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) > +{ > +} > + BTW. Good work. Please clean it and resubmit. I check it again. Regards, Michal Simek