[U-Boot-Users] [PATCH] Xilinx PowerPC XPS_LL_TEMAC driver

Michal Simek monstr at seznam.cz
Sun Apr 27 14:32:07 CEST 2008


Hi Yoshio,

my description is in patch

> Signed-off-by: Yoshio Kashiwagi <kashiwagi at co-nss.co.jp>
> ---
>  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 <config.h>
> +#include <common.h>
> +#include <net.h>
> +#include <malloc.h>
> +#include <asm/errno.h>

you don't use values from errno.h. You can remove it. Microblaze cpu don't have
this header too.

> +#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;
> +       }
> +   }
> +}

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




More information about the U-Boot mailing list