[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