From 9a042e9ca512beaaa2cb450274313fc477141241 Mon Sep 17 00:00:00 2001 From: Jerry Van Baren Date: Sat, 8 Mar 2008 13:48:01 -0500 Subject: Flash programming progress countdown. Signed-off-by: Gerald Van Baren --- drivers/mtd/cfi_flash.c | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c index 439c950cf2..48286e5803 100644 --- a/drivers/mtd/cfi_flash.c +++ b/drivers/mtd/cfi_flash.c @@ -1179,6 +1179,22 @@ void flash_print_info (flash_info_t * info) return; } +/*----------------------------------------------------------------------- + * This is used in a few places in write_buf() to show programming + * progress. Making it a function is nasty because it needs to do side + * effect updates to digit and dots. Repeated code is nasty too, so + * we define it once here. + */ +#define FLASH_SHOW_PROGRESS(scale, dots, digit) \ + if ((scale > 0) && (dots <= 0)) { \ + if ((digit % 5) == 0) \ + printf ("%d", digit / 5); \ + else \ + putc ('.'); \ + digit--; \ + dots += scale; \ + } + /*----------------------------------------------------------------------- * Copy memory to flash, returns: * 0 - OK @@ -1192,10 +1208,23 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) int aln; cfiword_t cword; int i, rc; - #ifdef CFG_FLASH_USE_BUFFER_WRITE int buffered_size; #endif +#ifdef CONFIG_FLASH_SHOW_PROGRESS + int digit = CONFIG_FLASH_SHOW_PROGRESS; + int scale = 0; + int dots = 0; + + /* + * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes. + */ + if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) { + scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) / + CONFIG_FLASH_SHOW_PROGRESS); + } +#endif + /* get lower aligned address */ wp = (addr & ~(info->portwidth - 1)); @@ -1219,6 +1248,10 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) return rc; wp += i; +#ifdef CONFIG_FLASH_SHOW_PROGRESS + dots -= i; + FLASH_SHOW_PROGRESS(scale, dots, digit); +#endif } /* handle the aligned part */ @@ -1248,6 +1281,10 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) wp += i; src += i; cnt -= i; +#ifdef CONFIG_FLASH_SHOW_PROGRESS + dots -= i; + FLASH_SHOW_PROGRESS(scale, dots, digit); +#endif } #else while (cnt >= info->portwidth) { @@ -1259,8 +1296,13 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) return rc; wp += info->portwidth; cnt -= info->portwidth; +#ifdef CONFIG_FLASH_SHOW_PROGRESS + dots -= info->portwidth; + FLASH_SHOW_PROGRESS(scale, dots, digit); +#endif } #endif /* CFG_FLASH_USE_BUFFER_WRITE */ + if (cnt == 0) { return (0); } -- cgit From f0105727d132f56a21fa3ed8b162309cca6cac44 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 19 Mar 2008 07:09:26 +0100 Subject: CFI: Small cleanup for FLASH_SHOW_PROGRESS With this patch we don't need that many #ifdef's in the code. It moves the subtraction into the macro and defines a NOP-macro when CONFIG_FLASH_SHOW_PROGRESS is not defined. Signed-off-by: Stefan Roese Acked-by: Gerald Van Baren --- drivers/mtd/cfi_flash.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c index 48286e5803..f04c72d05a 100644 --- a/drivers/mtd/cfi_flash.c +++ b/drivers/mtd/cfi_flash.c @@ -1185,7 +1185,9 @@ void flash_print_info (flash_info_t * info) * effect updates to digit and dots. Repeated code is nasty too, so * we define it once here. */ -#define FLASH_SHOW_PROGRESS(scale, dots, digit) \ +#ifdef CONFIG_FLASH_SHOW_PROGRESS +#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) \ + dots -= dots_sub; \ if ((scale > 0) && (dots <= 0)) { \ if ((digit % 5) == 0) \ printf ("%d", digit / 5); \ @@ -1194,6 +1196,9 @@ void flash_print_info (flash_info_t * info) digit--; \ dots += scale; \ } +#else +#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) +#endif /*----------------------------------------------------------------------- * Copy memory to flash, returns: @@ -1248,10 +1253,7 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) return rc; wp += i; -#ifdef CONFIG_FLASH_SHOW_PROGRESS - dots -= i; - FLASH_SHOW_PROGRESS(scale, dots, digit); -#endif + FLASH_SHOW_PROGRESS(scale, dots, digit, i); } /* handle the aligned part */ @@ -1281,10 +1283,7 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) wp += i; src += i; cnt -= i; -#ifdef CONFIG_FLASH_SHOW_PROGRESS - dots -= i; - FLASH_SHOW_PROGRESS(scale, dots, digit); -#endif + FLASH_SHOW_PROGRESS(scale, dots, digit, i); } #else while (cnt >= info->portwidth) { @@ -1296,10 +1295,7 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) return rc; wp += info->portwidth; cnt -= info->portwidth; -#ifdef CONFIG_FLASH_SHOW_PROGRESS - dots -= info->portwidth; - FLASH_SHOW_PROGRESS(scale, dots, digit); -#endif + FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth); } #endif /* CFG_FLASH_USE_BUFFER_WRITE */ -- cgit From 55774b512fdf63c0516d441cc5da7c54bbffb7f2 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Fri, 7 Mar 2008 16:04:25 +0900 Subject: pci: Add CONFIG_PCI_SKIP_HOST_BRIDGE config option In current source code, when the device number of PCI is 0, process PCI bridge without fail. However, when the device number is 0, it is not PCI always bridge. There are times when device of PCI allocates. When CONFIG_PCI_SKIP_HOST_BRIDGE is enable, this problem is solved when use this patch. Signed-off-by: Nobuhiro Iwamatsu Acked-by: Stefan Roese --- drivers/pci/pci.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 50ca6b0bad..7944b6684a 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -425,6 +425,9 @@ int pci_hose_scan_bus(struct pci_controller *hose, int bus) dev < PCI_BDF(bus,PCI_MAX_PCI_DEVICES-1,PCI_MAX_PCI_FUNCTIONS-1); dev += PCI_BDF(0,0,1)) { + + /* Bus 0 is not necessarily PCI bridge. */ +#if defined(CONFIG_PCI_SKIP_HOST_BRIDGE) /* Skip our host bridge */ if ( dev == PCI_BDF(hose->first_busno,0,0) ) { #if defined(CONFIG_PCI_CONFIG_HOST_BRIDGE) /* don't skip host bridge */ @@ -434,10 +437,11 @@ int pci_hose_scan_bus(struct pci_controller *hose, int bus) if (getenv("pciconfighost") == NULL) { continue; /* Skip our host bridge */ } -#else +#else /* CONFIG_PCI_CONFIG_HOST_BRIDGE */ continue; /* Skip our host bridge */ -#endif +#endif /* CONFIG_PCI_CONFIG_HOST_BRIDGE */ } +#endif /* CONFIG_PCI_SKIP_HOST_BRIDGE */ if (PCI_FUNC(dev) && !found_multi) continue; @@ -473,8 +477,11 @@ int pci_hose_scan_bus(struct pci_controller *hose, int bus) hose->fixup_irq(hose, dev); #ifdef CONFIG_PCI_SCAN_SHOW +#if defined(CONFIG_PCI_SKIP_HOST_BRIDGE) /* Skip our host bridge */ - if ( dev != PCI_BDF(hose->first_busno,0,0) ) { + if ( dev != PCI_BDF(hose->first_busno,0,0) ) +#endif + { unsigned char int_line; pci_hose_read_config_byte(hose, dev, PCI_INTERRUPT_LINE, -- cgit From 0d48926c87ec96f974a6ac4034f4a2f2eab3255f Mon Sep 17 00:00:00 2001 From: Yuri Tikhonov Date: Mon, 24 Mar 2008 11:30:54 +0100 Subject: lwmon5 SYSMON POST: fix backlight control If the LWMON5 config has SYSMON POST among CONFIG_POSTs which may be run on the board, then the SYSMON POST controls the display backlight (doesn't switch backlight ON if POST FAILED, and does switch the backlight ON if PASSED). If not, then the video driver controls the display backlight (just switch ON the backlight upon initialization). Signed-off-by: Yuri Tikhonov --- drivers/video/mb862xx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/mb862xx.c b/drivers/video/mb862xx.c index bfb057f513..9684cf3b7c 100644 --- a/drivers/video/mb862xx.c +++ b/drivers/video/mb862xx.c @@ -36,6 +36,9 @@ #include "videomodes.h" #include +#if defined(CONFIG_POST) +#include +#endif /* * Graphic Device */ @@ -354,7 +357,7 @@ void *video_hw_init (void) board_disp_init(); #endif -#if defined(CONFIG_LWMON5) +#if defined(CONFIG_LWMON5) && !(CONFIG_POST & CFG_POST_SYSMON) /* Lamp on */ board_backlight_switch (1); #endif -- cgit From 8a30b4700942f37495d2e67f5998cdffb6e3ba8a Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 24 Feb 2008 23:52:35 -0500 Subject: smc91111: use SSYNC() rather than asm(ssync) for Blackfin Since the "ssync" instruction may have hardware anomalies associated with it, have the smc91111 driver use the SSYNC macro rather than invoking it directly. We workaround all the anomalies via this macro. Signed-off-by: Mike Frysinger --- drivers/net/smc91111.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/smc91111.h b/drivers/net/smc91111.h index d03cbc320b..8dcbb3e2aa 100644 --- a/drivers/net/smc91111.h +++ b/drivers/net/smc91111.h @@ -186,7 +186,7 @@ typedef unsigned long int dword; #ifdef CONFIG_ADNPESC1 #define SMC_inw(r) (*((volatile word *)(SMC_BASE_ADDRESS+((r)<<1)))) #elif CONFIG_BLACKFIN -#define SMC_inw(r) ({ word __v = (*((volatile word *)(SMC_BASE_ADDRESS+(r)))); asm("ssync;"); __v;}) +#define SMC_inw(r) ({ word __v = (*((volatile word *)(SMC_BASE_ADDRESS+(r)))); SSYNC(); __v;}) #else #define SMC_inw(r) (*((volatile word *)(SMC_BASE_ADDRESS+(r)))) #endif @@ -195,7 +195,7 @@ typedef unsigned long int dword; #ifdef CONFIG_ADNPESC1 #define SMC_outw(d,r) (*((volatile word *)(SMC_BASE_ADDRESS+((r)<<1))) = d) #elif CONFIG_BLACKFIN -#define SMC_outw(d,r) {(*((volatile word *)(SMC_BASE_ADDRESS+(r))) = d);asm("ssync;");} +#define SMC_outw(d,r) {(*((volatile word *)(SMC_BASE_ADDRESS+(r))) = d); SSYNC();} #else #define SMC_outw(d,r) (*((volatile word *)(SMC_BASE_ADDRESS+(r))) = d) #endif -- cgit From 395bce4f59a507a60a475f7ee46bed47de9482df Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 24 Feb 2008 23:58:13 -0500 Subject: net/Blackfin: move on-chip MAC driver into drivers/net/ The Blackfin on-chip MAC driver was being managed in the BF537-STAMP board directory, but it is not board specific, so relocate it to the drivers dir so that other Blackfin ports can utilize it. Signed-off-by: Mike Frysinger --- drivers/net/Makefile | 1 + drivers/net/bfin_mac.c | 523 +++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/bfin_mac.h | 89 +++++++++ 3 files changed, 613 insertions(+) create mode 100644 drivers/net/bfin_mac.c create mode 100644 drivers/net/bfin_mac.h (limited to 'drivers') diff --git a/drivers/net/Makefile b/drivers/net/Makefile index b9723fa78f..321bd08adb 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -27,6 +27,7 @@ LIB := $(obj)libnet.a COBJS-y += 3c589.o COBJS-y += bcm570x.o bcm570x_autoneg.o 5701rls.o +COBJS-$(CONFIG_BFIN_MAC) += bfin_mac.o COBJS-y += cs8900.o COBJS-y += dc2114x.o COBJS-y += dm9000x.o diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c new file mode 100644 index 0000000000..afe122a337 --- /dev/null +++ b/drivers/net/bfin_mac.c @@ -0,0 +1,523 @@ +/* + * Driver for Blackfin On-Chip MAC device + * + * Copyright (c) 2005-2008 Analog Device, Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "bfin_mac.h" + +#ifdef CONFIG_POST +#include +#endif + +#undef DEBUG_ETHERNET + +#ifdef DEBUG_ETHERNET +#define DEBUGF(fmt, args...) printf(fmt, ##args) +#else +#define DEBUGF(fmt, args...) +#endif + +#define RXBUF_BASE_ADDR 0xFF900000 +#define TXBUF_BASE_ADDR 0xFF800000 +#define TX_BUF_CNT 1 + +#define TOUT_LOOP 1000000 + +ADI_ETHER_BUFFER *txbuf[TX_BUF_CNT]; +ADI_ETHER_BUFFER *rxbuf[PKTBUFSRX]; +static u16 txIdx; /* index of the current RX buffer */ +static u16 rxIdx; /* index of the current TX buffer */ + +u16 PHYregs[NO_PHY_REGS]; /* u16 PHYADDR; */ + +/* DMAx_CONFIG values at DMA Restart */ +const ADI_DMA_CONFIG_REG rxdmacfg = { + .b_DMA_EN = 1, /* enabled */ + .b_WNR = 1, /* write to memory */ + .b_WDSIZE = 2, /* wordsize is 32 bits */ + .b_DMA2D = 0, + .b_RESTART = 0, + .b_DI_SEL = 0, + .b_DI_EN = 0, /* no interrupt */ + .b_NDSIZE = 5, /* 5 half words is desc size */ + .b_FLOW = 7 /* large desc flow */ +}; + +const ADI_DMA_CONFIG_REG txdmacfg = { + .b_DMA_EN = 1, /* enabled */ + .b_WNR = 0, /* read from memory */ + .b_WDSIZE = 2, /* wordsize is 32 bits */ + .b_DMA2D = 0, + .b_RESTART = 0, + .b_DI_SEL = 0, + .b_DI_EN = 0, /* no interrupt */ + .b_NDSIZE = 5, /* 5 half words is desc size */ + .b_FLOW = 7 /* large desc flow */ +}; + +int bfin_EMAC_initialize(bd_t *bis) +{ + struct eth_device *dev; + dev = (struct eth_device *)malloc(sizeof(*dev)); + if (dev == NULL) + hang(); + + memset(dev, 0, sizeof(*dev)); + sprintf(dev->name, "Blackfin EMAC"); + + dev->iobase = 0; + dev->priv = 0; + dev->init = bfin_EMAC_init; + dev->halt = bfin_EMAC_halt; + dev->send = bfin_EMAC_send; + dev->recv = bfin_EMAC_recv; + + eth_register(dev); + + return 1; +} + +static int bfin_EMAC_send(struct eth_device *dev, volatile void *packet, + int length) +{ + int i; + int result = 0; + unsigned int *buf; + buf = (unsigned int *)packet; + + if (length <= 0) { + printf("Ethernet: bad packet size: %d\n", length); + goto out; + } + + if ((*pDMA2_IRQ_STATUS & DMA_ERR) != 0) { + printf("Ethernet: tx DMA error\n"); + goto out; + } + + for (i = 0; (*pDMA2_IRQ_STATUS & DMA_RUN) != 0; i++) { + if (i > TOUT_LOOP) { + puts("Ethernet: tx time out\n"); + goto out; + } + } + txbuf[txIdx]->FrmData->NoBytes = length; + memcpy(txbuf[txIdx]->FrmData->Dest, (void *)packet, length); + txbuf[txIdx]->Dma[0].START_ADDR = (u32) txbuf[txIdx]->FrmData; + *pDMA2_NEXT_DESC_PTR = &txbuf[txIdx]->Dma[0]; + *pDMA2_CONFIG = *(u16 *) (void *)(&txdmacfg); + *pEMAC_OPMODE |= TE; + + for (i = 0; (txbuf[txIdx]->StatusWord & TX_COMP) == 0; i++) { + if (i > TOUT_LOOP) { + puts("Ethernet: tx error\n"); + goto out; + } + } + result = txbuf[txIdx]->StatusWord; + txbuf[txIdx]->StatusWord = 0; + if ((txIdx + 1) >= TX_BUF_CNT) + txIdx = 0; + else + txIdx++; + out: + DEBUGF("BFIN EMAC send: length = %d\n", length); + return result; +} + +static int bfin_EMAC_recv(struct eth_device *dev) +{ + int length = 0; + + for (;;) { + if ((rxbuf[rxIdx]->StatusWord & RX_COMP) == 0) { + length = -1; + break; + } + if ((rxbuf[rxIdx]->StatusWord & RX_DMAO) != 0) { + printf("Ethernet: rx dma overrun\n"); + break; + } + if ((rxbuf[rxIdx]->StatusWord & RX_OK) == 0) { + printf("Ethernet: rx error\n"); + break; + } + length = rxbuf[rxIdx]->StatusWord & 0x000007FF; + if (length <= 4) { + printf("Ethernet: bad frame\n"); + break; + } + NetRxPackets[rxIdx] = + (volatile uchar *)(rxbuf[rxIdx]->FrmData->Dest); + NetReceive(NetRxPackets[rxIdx], length - 4); + *pDMA1_IRQ_STATUS |= DMA_DONE | DMA_ERR; + rxbuf[rxIdx]->StatusWord = 0x00000000; + if ((rxIdx + 1) >= PKTBUFSRX) + rxIdx = 0; + else + rxIdx++; + } + + return length; +} + +/************************************************************** + * + * Ethernet Initialization Routine + * + *************************************************************/ + +static int bfin_EMAC_init(struct eth_device *dev, bd_t *bd) +{ + u32 opmode; + int dat; + int i; + DEBUGF("Eth_init: ......\n"); + + txIdx = 0; + rxIdx = 0; + +/* Initialize System Register */ + if (SetupSystemRegs(&dat) < 0) + return -1; + +/* Initialize EMAC address */ + bfin_EMAC_setup_addr(bd); + +/* Initialize TX and RX buffer */ + for (i = 0; i < PKTBUFSRX; i++) { + rxbuf[i] = SetupRxBuffer(i); + if (i > 0) { + rxbuf[i - 1]->Dma[1].NEXT_DESC_PTR = + &(rxbuf[i]->Dma[0]); + if (i == (PKTBUFSRX - 1)) + rxbuf[i]->Dma[1].NEXT_DESC_PTR = + &(rxbuf[0]->Dma[0]); + } + } + for (i = 0; i < TX_BUF_CNT; i++) { + txbuf[i] = SetupTxBuffer(i); + if (i > 0) { + txbuf[i - 1]->Dma[1].NEXT_DESC_PTR = + &(txbuf[i]->Dma[0]); + if (i == (TX_BUF_CNT - 1)) + txbuf[i]->Dma[1].NEXT_DESC_PTR = + &(txbuf[0]->Dma[0]); + } + } + + /* Set RX DMA */ + *pDMA1_NEXT_DESC_PTR = &rxbuf[0]->Dma[0]; + *pDMA1_CONFIG = *((u16 *) (void *)&rxbuf[0]->Dma[0].CONFIG); + + /* Wait MII done */ + PollMdcDone(); + + /* We enable only RX here */ + /* ASTP : Enable Automatic Pad Stripping + PR : Promiscuous Mode for test + PSF : Receive frames with total length less than 64 bytes. + FDMODE : Full Duplex Mode + LB : Internal Loopback for test + RE : Receiver Enable */ + if (dat == FDMODE) + opmode = ASTP | FDMODE | PSF; + else + opmode = ASTP | PSF; + opmode |= RE; +#ifdef CONFIG_BFIN_MAC_RMII + opmode |= TE | RMII; +#endif + /* Turn on the EMAC */ + *pEMAC_OPMODE = opmode; + return 0; +} + +static void bfin_EMAC_halt(struct eth_device *dev) +{ + DEBUGF("Eth_halt: ......\n"); + /* Turn off the EMAC */ + *pEMAC_OPMODE = 0x00000000; + /* Turn off the EMAC RX DMA */ + *pDMA1_CONFIG = 0x0000; + *pDMA2_CONFIG = 0x0000; + +} + +void bfin_EMAC_setup_addr(bd_t *bd) +{ + *pEMAC_ADDRLO = + bd->bi_enetaddr[0] | + bd->bi_enetaddr[1] << 8 | + bd->bi_enetaddr[2] << 16 | + bd->bi_enetaddr[3] << 24; + *pEMAC_ADDRHI = + bd->bi_enetaddr[4] | + bd->bi_enetaddr[5] << 8; +} + +static void PollMdcDone(void) +{ + /* poll the STABUSY bit */ + while (*pEMAC_STAADD & STABUSY) ; +} + +static void WrPHYReg(u16 PHYAddr, u16 RegAddr, u16 Data) +{ + PollMdcDone(); + + *pEMAC_STADAT = Data; + + *pEMAC_STAADD = SET_PHYAD(PHYAddr) | SET_REGAD(RegAddr) | + STAOP | STAIE | STABUSY; +} + +/********************************************************************************* + * Read an off-chip register in a PHY through the MDC/MDIO port * + *********************************************************************************/ +static u16 RdPHYReg(u16 PHYAddr, u16 RegAddr) +{ + u16 Data; + + PollMdcDone(); + + *pEMAC_STAADD = SET_PHYAD(PHYAddr) | SET_REGAD(RegAddr) | + STAIE | STABUSY; + + PollMdcDone(); + + Data = (u16) * pEMAC_STADAT; + + PHYregs[RegAddr] = Data; /* save shadow copy */ + + return Data; +} + +#if 0 /* dead code ? */ +static void SoftResetPHY(void) +{ + u16 phydat; + /* set the reset bit */ + WrPHYReg(PHYADDR, PHY_MODECTL, PHY_RESET); + /* and clear it again */ + WrPHYReg(PHYADDR, PHY_MODECTL, 0x0000); + do { + /* poll until reset is complete */ + phydat = RdPHYReg(PHYADDR, PHY_MODECTL); + } while ((phydat & PHY_RESET) != 0); +} +#endif + +static int SetupSystemRegs(int *opmode) +{ + u16 sysctl, phydat; + int count = 0; + /* Enable PHY output */ + *pVR_CTL |= CLKBUFOE; + /* Set all the pins to peripheral mode */ + +#ifndef CONFIG_BFIN_MAC_RMII + *pPORTH_FER = 0xFFFF; +#ifdef __ADSPBF52x__ + *pPORTH_MUX = PORT_x_MUX_0_FUNC_2 | PORT_x_MUX_1_FUNC_2 | PORT_x_MUX_2_FUNC_2; +#endif +#else +#if defined(__ADSPBF536__) || defined(__ADSPBF537__) + *pPORTH_FER = 0xC373; +#endif +#ifdef __ADSPBF52x__ + *pPORTH_FER = 0x01FF; + *pPORTH_MUX = PORT_x_MUX_0_FUNC_2 | PORT_x_MUX_1_FUNC_2; +#endif +#endif + /* MDC = 2.5 MHz */ + sysctl = SET_MDCDIV(24); + /* Odd word alignment for Receive Frame DMA word */ + /* Configure checksum support and rcve frame word alignment */ + sysctl |= RXDWA | RXCKS; + *pEMAC_SYSCTL = sysctl; + /* auto negotiation on */ + /* full duplex */ + /* 100 Mbps */ + phydat = PHY_ANEG_EN | PHY_DUPLEX | PHY_SPD_SET; + WrPHYReg(PHYADDR, PHY_MODECTL, phydat); + do { + udelay(1000); + phydat = RdPHYReg(PHYADDR, PHY_MODESTAT); + if (count > 3000) { + printf + ("Link is down, please check your network connection\n"); + return -1; + } + count++; + } while (!(phydat & 0x0004)); + + phydat = RdPHYReg(PHYADDR, PHY_ANLPAR); + + if ((phydat & 0x0100) || (phydat & 0x0040)) + *opmode = FDMODE; + else + *opmode = 0; + + *pEMAC_MMC_CTL = RSTC | CROLL; + + /* Initialize the TX DMA channel registers */ + *pDMA2_X_COUNT = 0; + *pDMA2_X_MODIFY = 4; + *pDMA2_Y_COUNT = 0; + *pDMA2_Y_MODIFY = 0; + + /* Initialize the RX DMA channel registers */ + *pDMA1_X_COUNT = 0; + *pDMA1_X_MODIFY = 4; + *pDMA1_Y_COUNT = 0; + *pDMA1_Y_MODIFY = 0; + return 0; +} + +ADI_ETHER_BUFFER *SetupRxBuffer(int no) +{ + ADI_ETHER_FRAME_BUFFER *frmbuf; + ADI_ETHER_BUFFER *buf; + int nobytes_buffer = sizeof(ADI_ETHER_BUFFER[2]) / 2; /* ensure a multi. of 4 */ + int total_size = nobytes_buffer + RECV_BUFSIZE; + + buf = (ADI_ETHER_BUFFER *) (RXBUF_BASE_ADDR + no * total_size); + frmbuf = + (ADI_ETHER_FRAME_BUFFER *) (RXBUF_BASE_ADDR + no * total_size + + nobytes_buffer); + + memset(buf, 0x00, nobytes_buffer); + buf->FrmData = frmbuf; + memset(frmbuf, 0xfe, RECV_BUFSIZE); + + /* set up first desc to point to receive frame buffer */ + buf->Dma[0].NEXT_DESC_PTR = &(buf->Dma[1]); + buf->Dma[0].START_ADDR = (u32) buf->FrmData; + buf->Dma[0].CONFIG.b_DMA_EN = 1; /* enabled */ + buf->Dma[0].CONFIG.b_WNR = 1; /* Write to memory */ + buf->Dma[0].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */ + buf->Dma[0].CONFIG.b_NDSIZE = 5; /* 5 half words is desc size. */ + buf->Dma[0].CONFIG.b_FLOW = 7; /* large desc flow */ + + /* set up second desc to point to status word */ + buf->Dma[1].NEXT_DESC_PTR = &(buf->Dma[0]); + buf->Dma[1].START_ADDR = (u32) & buf->IPHdrChksum; + buf->Dma[1].CONFIG.b_DMA_EN = 1; /* enabled */ + buf->Dma[1].CONFIG.b_WNR = 1; /* Write to memory */ + buf->Dma[1].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */ + buf->Dma[1].CONFIG.b_DI_EN = 1; /* enable interrupt */ + buf->Dma[1].CONFIG.b_NDSIZE = 5; /* must be 0 when FLOW is 0 */ + buf->Dma[1].CONFIG.b_FLOW = 7; /* stop */ + + return buf; +} + +ADI_ETHER_BUFFER *SetupTxBuffer(int no) +{ + ADI_ETHER_FRAME_BUFFER *frmbuf; + ADI_ETHER_BUFFER *buf; + int nobytes_buffer = sizeof(ADI_ETHER_BUFFER[2]) / 2; /* ensure a multi. of 4 */ + int total_size = nobytes_buffer + RECV_BUFSIZE; + + buf = (ADI_ETHER_BUFFER *) (TXBUF_BASE_ADDR + no * total_size); + frmbuf = + (ADI_ETHER_FRAME_BUFFER *) (TXBUF_BASE_ADDR + no * total_size + + nobytes_buffer); + + memset(buf, 0x00, nobytes_buffer); + buf->FrmData = frmbuf; + memset(frmbuf, 0x00, RECV_BUFSIZE); + + /* set up first desc to point to receive frame buffer */ + buf->Dma[0].NEXT_DESC_PTR = &(buf->Dma[1]); + buf->Dma[0].START_ADDR = (u32) buf->FrmData; + buf->Dma[0].CONFIG.b_DMA_EN = 1; /* enabled */ + buf->Dma[0].CONFIG.b_WNR = 0; /* Read to memory */ + buf->Dma[0].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */ + buf->Dma[0].CONFIG.b_NDSIZE = 5; /* 5 half words is desc size. */ + buf->Dma[0].CONFIG.b_FLOW = 7; /* large desc flow */ + + /* set up second desc to point to status word */ + buf->Dma[1].NEXT_DESC_PTR = &(buf->Dma[0]); + buf->Dma[1].START_ADDR = (u32) & buf->StatusWord; + buf->Dma[1].CONFIG.b_DMA_EN = 1; /* enabled */ + buf->Dma[1].CONFIG.b_WNR = 1; /* Write to memory */ + buf->Dma[1].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */ + buf->Dma[1].CONFIG.b_DI_EN = 1; /* enable interrupt */ + buf->Dma[1].CONFIG.b_NDSIZE = 0; /* must be 0 when FLOW is 0 */ + buf->Dma[1].CONFIG.b_FLOW = 0; /* stop */ + + return buf; +} + +#if defined(CONFIG_POST) && defined(CFG_POST_ETHER) +int ether_post_test(int flags) +{ + uchar buf[64]; + int i, value = 0; + int length; + + printf("\n--------"); + bfin_EMAC_init(NULL, NULL); + /* construct the package */ + buf[0] = buf[6] = (unsigned char)(*pEMAC_ADDRLO & 0xFF); + buf[1] = buf[7] = (unsigned char)((*pEMAC_ADDRLO & 0xFF00) >> 8); + buf[2] = buf[8] = (unsigned char)((*pEMAC_ADDRLO & 0xFF0000) >> 16); + buf[3] = buf[9] = (unsigned char)((*pEMAC_ADDRLO & 0xFF000000) >> 24); + buf[4] = buf[10] = (unsigned char)(*pEMAC_ADDRHI & 0xFF); + buf[5] = buf[11] = (unsigned char)((*pEMAC_ADDRHI & 0xFF00) >> 8); + buf[12] = 0x08; /* Type: ARP */ + buf[13] = 0x06; + buf[14] = 0x00; /* Hardware type: Ethernet */ + buf[15] = 0x01; + buf[16] = 0x08; /* Protocal type: IP */ + buf[17] = 0x00; + buf[18] = 0x06; /* Hardware size */ + buf[19] = 0x04; /* Protocol size */ + buf[20] = 0x00; /* Opcode: request */ + buf[21] = 0x01; + + for (i = 0; i < 42; i++) + buf[i + 22] = i; + printf("--------Send 64 bytes......\n"); + bfin_EMAC_send(NULL, (volatile void *)buf, 64); + for (i = 0; i < 100; i++) { + udelay(10000); + if ((rxbuf[rxIdx]->StatusWord & RX_COMP) != 0) { + value = 1; + break; + } + } + if (value == 0) { + printf("--------EMAC can't receive any data\n"); + eth_halt(); + return -1; + } + length = rxbuf[rxIdx]->StatusWord & 0x000007FF - 4; + for (i = 0; i < length; i++) { + if (rxbuf[rxIdx]->FrmData->Dest[i] != buf[i]) { + printf("--------EMAC receive error data!\n"); + eth_halt(); + return -1; + } + } + printf("--------receive %d bytes, matched\n", length); + bfin_EMAC_halt(NULL); + return 0; +} +#endif diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h new file mode 100644 index 0000000000..c8a94d0c9f --- /dev/null +++ b/drivers/net/bfin_mac.h @@ -0,0 +1,89 @@ +/* + * bfin_mac.h - some defines/structures for the Blackfin on-chip MAC. + * + * Copyright (c) 2005-2008 Analog Device, Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef __BFIN_MAC_H__ +#define __BFIN_MAC_H__ + +#define PHYADDR 0x01 +#define NO_PHY_REGS 0x20 + +#define DEFAULT_PHY_PHYID1 0x0007 +#define DEFAULT_PHY_PHYID2 0xC0A3 +#define PHY_MODECTL 0x00 +#define PHY_MODESTAT 0x01 +#define PHY_PHYID1 0x02 +#define PHY_PHYID2 0x03 +#define PHY_ANAR 0x04 +#define PHY_ANLPAR 0x05 +#define PHY_ANER 0x06 + +#define PHY_RESET 0x8000 +#define PHY_ANEG_EN 0x1000 +#define PHY_DUPLEX 0x0100 +#define PHY_SPD_SET 0x2000 + +#define RECV_BUFSIZE (0x614) + +typedef volatile u32 reg32; +typedef volatile u16 reg16; + +typedef struct ADI_DMA_CONFIG_REG { + u16 b_DMA_EN:1; /* 0 Enabled */ + u16 b_WNR:1; /* 1 Direction */ + u16 b_WDSIZE:2; /* 2:3 Transfer word size */ + u16 b_DMA2D:1; /* 4 DMA mode */ + u16 b_RESTART:1; /* 5 Retain FIFO */ + u16 b_DI_SEL:1; /* 6 Data interrupt timing select */ + u16 b_DI_EN:1; /* 7 Data interrupt enabled */ + u16 b_NDSIZE:4; /* 8:11 Flex descriptor size */ + u16 b_FLOW:3; /* 12:14Flow */ +} ADI_DMA_CONFIG_REG; + +typedef struct adi_ether_frame_buffer { + u16 NoBytes; /* the no. of following bytes */ + u8 Dest[6]; /* destination MAC address */ + u8 Srce[6]; /* source MAC address */ + u16 LTfield; /* length/type field */ + u8 Data[0]; /* payload bytes */ +} ADI_ETHER_FRAME_BUFFER; +/* 16 bytes/struct */ + +typedef struct dma_descriptor { + struct dma_descriptor *NEXT_DESC_PTR; + u32 START_ADDR; + ADI_DMA_CONFIG_REG CONFIG; +} DMA_DESCRIPTOR; +/* 10 bytes/struct in 12 bytes */ + +typedef struct adi_ether_buffer { + DMA_DESCRIPTOR Dma[2]; /* first for the frame, second for the status */ + ADI_ETHER_FRAME_BUFFER *FrmData;/* pointer to data */ + struct adi_ether_buffer *pNext; /* next buffer */ + struct adi_ether_buffer *pPrev; /* prev buffer */ + u16 IPHdrChksum; /* the IP header checksum */ + u16 IPPayloadChksum; /* the IP header and payload checksum */ + volatile u32 StatusWord; /* the frame status word */ +} ADI_ETHER_BUFFER; +/* 40 bytes/struct in 44 bytes */ + +static ADI_ETHER_BUFFER *SetupRxBuffer(int no); +static ADI_ETHER_BUFFER *SetupTxBuffer(int no); + +static int bfin_EMAC_init(struct eth_device *dev, bd_t *bd); +static void bfin_EMAC_halt(struct eth_device *dev); +static int bfin_EMAC_send(struct eth_device *dev, volatile void *packet, int length); +static int bfin_EMAC_recv(struct eth_device *dev); + +static void PollMdcDone(void); +static void WrPHYReg(u16 PHYAddr, u16 RegAddr, u16 Data); +static u16 RdPHYReg(u16 PHYAddr, u16 RegAddr); +static int SetupSystemRegs(int *opmode); + +static void bfin_EMAC_setup_addr(bd_t *bd); + +#endif -- cgit From e710185aae90c64d39c2d453e40e58ceefe4f250 Mon Sep 17 00:00:00 2001 From: "goda.yusuke" Date: Wed, 5 Mar 2008 17:08:20 +0900 Subject: net: Divided code of NE2000 ethernet driver There are more devices of the NE2000 base. A present code is difficult for us to support more devices. To support more NE2000 clone devices, separated the function. Signed-off-by: Yusuke Goda Acked-by: Nobuhiro Iwamatsu --- drivers/net/ne2000.c | 213 ++++++++++--------------------- drivers/net/ne2000.h | 316 ++++++++++++++++------------------------------ drivers/net/ne2000_base.h | 282 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 456 insertions(+), 355 deletions(-) create mode 100644 drivers/net/ne2000_base.h (limited to 'drivers') diff --git a/drivers/net/ne2000.c b/drivers/net/ne2000.c index b100657539..49280148d2 100644 --- a/drivers/net/ne2000.c +++ b/drivers/net/ne2000.c @@ -82,25 +82,11 @@ Add SNMP #ifdef CONFIG_DRIVER_NE2000 -/* wor around udelay resetting OCR */ -static void my_udelay(long us) { - long tmo; - - tmo = get_timer (0) + us * CFG_HZ / 1000000; /* will this be much greater than 0 ? */ - while (get_timer (0) < tmo); -} - -#define mdelay(n) my_udelay((n)*1000) - +#define mdelay(n) udelay((n)*1000) /* forward definition of function used for the uboot interface */ void uboot_push_packet_len(int len); void uboot_push_tx_done(int key, int val); -/* timeout for tx/rx in s */ -#define TOUT 5 - -#define ETHER_ADDR_LEN 6 - /* ------------------------------------------------------------------------ Debugging details @@ -118,18 +104,18 @@ void uboot_push_tx_done(int key, int val); #if DEBUG & 1 #define DEBUG_FUNCTION() do { printf("%s\n", __FUNCTION__); } while (0) #define DEBUG_LINE() do { printf("%d\n", __LINE__); } while (0) +#define PRINTK(args...) printf(args) #else #define DEBUG_FUNCTION() do {} while(0) #define DEBUG_LINE() do {} while(0) +#define PRINTK(args...) #endif -#include "ne2000.h" +/* NE2000 base header file */ +#include "ne2000_base.h" -#if DEBUG & 1 -#define PRINTK(args...) printf(args) -#else -#define PRINTK(args...) -#endif +/* Basic NE2000 chip support */ +#include "ne2000.h" static dp83902a_priv_data_t nic; /* just one instance of the card supported */ @@ -137,8 +123,7 @@ static bool dp83902a_init(void) { dp83902a_priv_data_t *dp = &nic; - cyg_uint8* base; - int i; + u8* base; DEBUG_FUNCTION(); @@ -147,6 +132,7 @@ dp83902a_init(void) DEBUG_LINE(); +#if defined(NE2000_BASIC_INIT) /* Prepare ESA */ DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1); /* Select page 1 */ /* Use the address from the serial EEPROM */ @@ -163,6 +149,7 @@ dp83902a_init(void) dp->esa[4], dp->esa[5] ); +#endif /* NE2000_BASIC_INIT */ return true; } @@ -170,7 +157,7 @@ static void dp83902a_stop(void) { dp83902a_priv_data_t *dp = &nic; - cyg_uint8 *base = dp->base; + u8 *base = dp->base; DEBUG_FUNCTION(); @@ -188,10 +175,10 @@ dp83902a_stop(void) the hardware ready to send/receive packets. */ static void -dp83902a_start(unsigned char * enaddr) +dp83902a_start(u8 * enaddr) { dp83902a_priv_data_t *dp = &nic; - cyg_uint8 *base = dp->base; + u8 *base = dp->base; int i; DEBUG_FUNCTION(); @@ -206,15 +193,20 @@ dp83902a_start(unsigned char * enaddr) dp->tx1 = dp->tx2 = 0; dp->tx_next = dp->tx_buf1; dp->tx_started = false; + dp->running = true; DP_OUT(base, DP_PSTART, dp->rx_buf_start); /* Receive ring start page */ DP_OUT(base, DP_BNDRY, dp->rx_buf_end-1); /* Receive ring boundary */ DP_OUT(base, DP_PSTOP, dp->rx_buf_end); /* Receive ring end page */ dp->rx_next = dp->rx_buf_start-1; + dp->running = true; DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */ DP_OUT(base, DP_IMR, DP_IMR_All); /* Enable all interrupts */ DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1 | DP_CR_STOP); /* Select page 1 */ DP_OUT(base, DP_P1_CURP, dp->rx_buf_start); /* Current page - next free page for Rx */ + dp->running = true; for (i = 0; i < ETHER_ADDR_LEN; i++) { + /* FIXME */ + //*((vu_short*)( base + ((DP_P1_PAR0 + i) * 2) + 0x1400)) = enaddr[i]; DP_OUT(base, DP_P1_PAR0+i, enaddr[i]); } /* Enable and start device */ @@ -222,6 +214,7 @@ dp83902a_start(unsigned char * enaddr) DP_OUT(base, DP_TCR, DP_TCR_NORMAL); /* Normal transmit operations */ DP_OUT(base, DP_RCR, DP_RCR_AB); /* Accept broadcast, no errors, no multicast */ dp->running = true; + } /* @@ -234,7 +227,7 @@ static void dp83902a_start_xmit(int start_page, int len) { dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *) &nic; - cyg_uint8 *base = dp->base; + u8 *base = dp->base; DEBUG_FUNCTION(); @@ -259,10 +252,10 @@ dp83902a_start_xmit(int start_page, int len) that there is free buffer space (dp->tx_next). */ static void -dp83902a_send(unsigned char *data, int total_len, unsigned long key) +dp83902a_send(u8 *data, int total_len, u32 key) { struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; - cyg_uint8 *base = dp->base; + u8 *base = dp->base; int len, start_page, pkt_len, i, isr; #if DEBUG & 4 int dx; @@ -296,7 +289,7 @@ dp83902a_send(unsigned char *data, int total_len, unsigned long key) /* but the code is extended a bit to do what Hitachi's monitor */ /* does (i.e., also read data). */ - cyg_uint16 tmp; + u16 tmp; int len = 1; DP_OUT(base, DP_RSAL, 0x100-len); @@ -322,7 +315,7 @@ dp83902a_send(unsigned char *data, int total_len, unsigned long key) /* Put data into buffer */ #if DEBUG & 4 - printf(" sg buf %08lx len %08x\n ", (unsigned long) data, len); + printf(" sg buf %08lx len %08x\n ", (u32)data, len); dx = 0; #endif while (len > 0) { @@ -330,6 +323,7 @@ dp83902a_send(unsigned char *data, int total_len, unsigned long key) printf(" %02x", *data); if (0 == (++dx % 16)) printf("\n "); #endif + DP_OUT_DATA(dp->data, *data++); len--; } @@ -358,6 +352,7 @@ dp83902a_send(unsigned char *data, int total_len, unsigned long key) do { DP_IN(base, DP_ISR, isr); } while ((isr & DP_ISR_RDC) == 0); + /* Then disable DMA */ DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); @@ -383,9 +378,9 @@ static void dp83902a_RxEvent(void) { struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; - cyg_uint8 *base = dp->base; - unsigned char rsr; - unsigned char rcv_hdr[4]; + u8 *base = dp->base; + u8 rsr; + u8 rcv_hdr[4]; int i, len, pkt, cur; DEBUG_FUNCTION(); @@ -423,6 +418,7 @@ dp83902a_RxEvent(void) CYGACC_CALL_IF_DELAY_US(10); #endif + /* read header (get data size)*/ for (i = 0; i < sizeof(rcv_hdr);) { DP_IN_DATA(dp->data, rcv_hdr[i++]); } @@ -432,7 +428,10 @@ dp83902a_RxEvent(void) rcv_hdr[0], rcv_hdr[1], rcv_hdr[2], rcv_hdr[3]); #endif len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr); + + /* data read */ uboot_push_packet_len(len); + if (rcv_hdr[1] == dp->rx_buf_start) DP_OUT(base, DP_BNDRY, dp->rx_buf_end-1); else @@ -448,12 +447,12 @@ dp83902a_RxEvent(void) efficient processing in the upper layers of the stack. */ static void -dp83902a_recv(unsigned char *data, int len) +dp83902a_recv(u8 *data, int len) { struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; - cyg_uint8 *base = dp->base; + u8 *base = dp->base; int i, mlen; - cyg_uint8 saved_char = 0; + u8 saved_char = 0; bool saved; #if DEBUG & 4 int dx; @@ -482,7 +481,7 @@ dp83902a_recv(unsigned char *data, int len) if (data) { mlen = len; #if DEBUG & 4 - printf(" sg buf %08lx len %08x \n", (unsigned long) data, mlen); + printf(" sg buf %08lx len %08x \n", (u32) data, mlen); dx = 0; #endif while (0 < mlen) { @@ -495,7 +494,7 @@ dp83902a_recv(unsigned char *data, int len) } { - cyg_uint8 tmp; + u8 tmp; DP_IN_DATA(dp->data, tmp); #if DEBUG & 4 printf(" %02x", tmp); @@ -516,9 +515,9 @@ static void dp83902a_TxEvent(void) { struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; - cyg_uint8 *base = dp->base; - unsigned char tsr; - unsigned long key; + u8 *base = dp->base; + u8 tsr; + u32 key; DEBUG_FUNCTION(); @@ -551,8 +550,8 @@ static void dp83902a_ClearCounters(void) { struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; - cyg_uint8 *base = dp->base; - cyg_uint8 cnt1, cnt2, cnt3; + u8 *base = dp->base; + u8 cnt1, cnt2, cnt3; DP_IN(base, DP_FER, cnt1); DP_IN(base, DP_CER, cnt2); @@ -566,8 +565,8 @@ static void dp83902a_Overflow(void) { struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)&nic; - cyg_uint8 *base = dp->base; - cyg_uint8 isr; + u8 *base = dp->base; + u8 isr; /* Issue a stop command and wait 1.6ms for it to complete. */ DP_OUT(base, DP_CR, DP_CR_STOP | DP_CR_NODMA); @@ -603,8 +602,8 @@ static void dp83902a_poll(void) { struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; - cyg_uint8 *base = dp->base; - unsigned char isr; + u8 *base = dp->base; + u8 isr; DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START); DP_IN(base, DP_ISR, isr); @@ -642,13 +641,13 @@ dp83902a_poll(void) /* find prom (taken from pc_net_cs.c from Linux) */ #include "8390.h" - +/* typedef struct hw_info_t { u_int offset; u_char a0, a1, a2; u_int flags; } hw_info_t; - +*/ #define DELAY_OUTPUT 0x01 #define HAS_MISC_REG 0x02 #define USE_BIG_BUF 0x04 @@ -731,102 +730,17 @@ static hw_info_t hw_info[] = { static hw_info_t default_info = { 0, 0, 0, 0, 0 }; -unsigned char dev_addr[6]; +u8 dev_addr[6]; #define PCNET_CMD 0x00 #define PCNET_DATAPORT 0x10 /* NatSemi-defined port window offset. */ #define PCNET_RESET 0x1f /* Issue a read to reset, a write to clear. */ #define PCNET_MISC 0x18 /* For IBM CCAE and Socket EA cards */ -unsigned long nic_base; - -static void pcnet_reset_8390(void) -{ - int i, r; - - PRINTK("nic base is %lx\n", nic_base); - - n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD); - PRINTK("cmd (at %lx) is %x\n", nic_base+ E8390_CMD, n2k_inb(E8390_CMD)); - n2k_outb(E8390_NODMA+E8390_PAGE1+E8390_STOP, E8390_CMD); - PRINTK("cmd (at %lx) is %x\n", nic_base+ E8390_CMD, n2k_inb(E8390_CMD)); - n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD); - PRINTK("cmd (at %lx) is %x\n", nic_base+ E8390_CMD, n2k_inb(E8390_CMD)); - n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD); - - n2k_outb(n2k_inb(PCNET_RESET), PCNET_RESET); - - for (i = 0; i < 100; i++) { - if ((r = (n2k_inb(EN0_ISR) & ENISR_RESET)) != 0) - break; - PRINTK("got %x in reset\n", r); - my_udelay(100); - } - n2k_outb(ENISR_RESET, EN0_ISR); /* Ack intr. */ - - if (i == 100) - printf("pcnet_reset_8390() did not complete.\n"); -} /* pcnet_reset_8390 */ - -static hw_info_t * get_prom(void ) { - unsigned char prom[32]; - int i, j; - struct { - u_char value, offset; - } program_seq[] = { - {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/ - {0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */ - {0x00, EN0_RCNTLO}, /* Clear the count regs. */ - {0x00, EN0_RCNTHI}, - {0x00, EN0_IMR}, /* Mask completion irq. */ - {0xFF, EN0_ISR}, - {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */ - {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */ - {32, EN0_RCNTLO}, - {0x00, EN0_RCNTHI}, - {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */ - {0x00, EN0_RSARHI}, - {E8390_RREAD+E8390_START, E8390_CMD}, - }; - - PRINTK("trying to get MAC via prom reading\n"); - - pcnet_reset_8390(); - - mdelay(10); - - for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) - n2k_outb(program_seq[i].value, program_seq[i].offset); - - PRINTK("PROM:"); - for (i = 0; i < 32; i++) { - prom[i] = n2k_inb(PCNET_DATAPORT); - PRINTK(" %02x", prom[i]); - } - PRINTK("\n"); - for (i = 0; i < NR_INFO; i++) { - if ((prom[0] == hw_info[i].a0) && - (prom[2] == hw_info[i].a1) && - (prom[4] == hw_info[i].a2)) { - PRINTK("matched board %d\n", i); - break; - } - } - if ((i < NR_INFO) || ((prom[28] == 0x57) && (prom[30] == 0x57))) { - for (j = 0; j < 6; j++) - dev_addr[j] = prom[j<<1]; - PRINTK("on exit i is %d/%ld\n", i, NR_INFO); - PRINTK("MAC address is %02x:%02x:%02x:%02x:%02x:%02x\n", - dev_addr[0],dev_addr[1],dev_addr[2],dev_addr[3],dev_addr[4],dev_addr[5]); - return (i < NR_INFO) ? hw_info+i : &default_info; - } - return NULL; -} +u32 nic_base; /* U-boot specific routines */ - - -static unsigned char *pbuf = NULL; +static u8 *pbuf = NULL; static int pkey = -1; static int initialized=0; @@ -839,7 +753,7 @@ void uboot_push_packet_len(int len) { } dp83902a_recv(&pbuf[0], len); - /* Just pass it to the upper layer */ + /*Just pass it to the upper layer*/ NetReceive(&pbuf[0], len); } @@ -864,7 +778,7 @@ int eth_init(bd_t *bd) { #ifdef CONFIG_DRIVER_NE2000_CCR { - volatile unsigned char *p = (volatile unsigned char *) CONFIG_DRIVER_NE2000_CCR; + vu_char *p = (vu_char *) CONFIG_DRIVER_NE2000_CCR; PRINTK("CCR before is %x\n", *p); *p = CONFIG_DRIVER_NE2000_VAL; @@ -873,9 +787,9 @@ int eth_init(bd_t *bd) { #endif nic_base = CONFIG_DRIVER_NE2000_BASE; - nic.base = (cyg_uint8 *) CONFIG_DRIVER_NE2000_BASE; + nic.base = (u8 *) CONFIG_DRIVER_NE2000_BASE; - r = get_prom(); + r = get_prom(dev_addr); if (!r) return -1; @@ -886,22 +800,23 @@ int eth_init(bd_t *bd) { PRINTK("Set environment from HW MAC addr = \"%s\"\n", ethaddr); setenv ("ethaddr", ethaddr); - -#define DP_DATA 0x10 nic.data = nic.base + DP_DATA; - nic.tx_buf1 = 0x40; - nic.tx_buf2 = 0x48; - nic.rx_buf_start = 0x50; - nic.rx_buf_end = 0x80; + nic.tx_buf1 = START_PG; + nic.tx_buf2 = START_PG2; + nic.rx_buf_start = RX_START; + nic.rx_buf_end = RX_END; if (dp83902a_init() == false) return -1; + dp83902a_start(dev_addr); initialized=1; + return 0; } void eth_halt() { + PRINTK("### eth_halt\n"); if(initialized) dp83902a_stop(); @@ -920,7 +835,7 @@ int eth_send(volatile void *packet, int length) { pkey = -1; - dp83902a_send((unsigned char *) packet, length, 666); + dp83902a_send((u8 *) packet, length, 666); tmo = get_timer (0) + TOUT * CFG_HZ; while(1) { dp83902a_poll(); diff --git a/drivers/net/ne2000.h b/drivers/net/ne2000.h index c13d9f0bbb..06e9a2844e 100644 --- a/drivers/net/ne2000.h +++ b/drivers/net/ne2000.h @@ -71,209 +71,113 @@ are GPL, so this is, of course, GPL. */ /* - ------------------------------------------------------------------------ - Macros for accessing DP registers - These can be overridden by the platform header -*/ - -#define DP_IN(_b_, _o_, _d_) (_d_) = *( (volatile unsigned char *) ((_b_)+(_o_))) -#define DP_OUT(_b_, _o_, _d_) *( (volatile unsigned char *) ((_b_)+(_o_))) = (_d_) - -#define DP_IN_DATA(_b_, _d_) (_d_) = *( (volatile unsigned char *) ((_b_))) -#define DP_OUT_DATA(_b_, _d_) *( (volatile unsigned char *) ((_b_))) = (_d_) - - -/* here is all the data */ - -#define cyg_uint8 unsigned char -#define cyg_uint16 unsigned short -#define bool int - -#define false 0 -#define true 1 - -#define CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA 1 -#define CYGACC_CALL_IF_DELAY_US(X) my_udelay(X) - -typedef struct dp83902a_priv_data { - cyg_uint8* base; - cyg_uint8* data; - cyg_uint8* reset; - int tx_next; /* First free Tx page */ - int tx_int; /* Expecting interrupt from this buffer */ - int rx_next; /* First free Rx page */ - int tx1, tx2; /* Page numbers for Tx buffers */ - unsigned long tx1_key, tx2_key; /* Used to ack when packet sent */ - int tx1_len, tx2_len; - bool tx_started, running, hardwired_esa; - cyg_uint8 esa[6]; - void* plf_priv; - - /* Buffer allocation */ - int tx_buf1, tx_buf2; - int rx_buf_start, rx_buf_end; -} dp83902a_priv_data_t; - -/* - ------------------------------------------------------------------------ - Some forward declarations -*/ -static void dp83902a_poll(void); - -/* ------------------------------------------------------------------------ */ -/* Register offsets */ - -#define DP_CR 0x00 -#define DP_CLDA0 0x01 -#define DP_PSTART 0x01 /* write */ -#define DP_CLDA1 0x02 -#define DP_PSTOP 0x02 /* write */ -#define DP_BNDRY 0x03 -#define DP_TSR 0x04 -#define DP_TPSR 0x04 /* write */ -#define DP_NCR 0x05 -#define DP_TBCL 0x05 /* write */ -#define DP_FIFO 0x06 -#define DP_TBCH 0x06 /* write */ -#define DP_ISR 0x07 -#define DP_CRDA0 0x08 -#define DP_RSAL 0x08 /* write */ -#define DP_CRDA1 0x09 -#define DP_RSAH 0x09 /* write */ -#define DP_RBCL 0x0a /* write */ -#define DP_RBCH 0x0b /* write */ -#define DP_RSR 0x0c -#define DP_RCR 0x0c /* write */ -#define DP_FER 0x0d -#define DP_TCR 0x0d /* write */ -#define DP_CER 0x0e -#define DP_DCR 0x0e /* write */ -#define DP_MISSED 0x0f -#define DP_IMR 0x0f /* write */ -#define DP_DATAPORT 0x10 /* "eprom" data port */ - -#define DP_P1_CR 0x00 -#define DP_P1_PAR0 0x01 -#define DP_P1_PAR1 0x02 -#define DP_P1_PAR2 0x03 -#define DP_P1_PAR3 0x04 -#define DP_P1_PAR4 0x05 -#define DP_P1_PAR5 0x06 -#define DP_P1_CURP 0x07 -#define DP_P1_MAR0 0x08 -#define DP_P1_MAR1 0x09 -#define DP_P1_MAR2 0x0a -#define DP_P1_MAR3 0x0b -#define DP_P1_MAR4 0x0c -#define DP_P1_MAR5 0x0d -#define DP_P1_MAR6 0x0e -#define DP_P1_MAR7 0x0f - -#define DP_P2_CR 0x00 -#define DP_P2_PSTART 0x01 -#define DP_P2_CLDA0 0x01 /* write */ -#define DP_P2_PSTOP 0x02 -#define DP_P2_CLDA1 0x02 /* write */ -#define DP_P2_RNPP 0x03 -#define DP_P2_TPSR 0x04 -#define DP_P2_LNPP 0x05 -#define DP_P2_ACH 0x06 -#define DP_P2_ACL 0x07 -#define DP_P2_RCR 0x0c -#define DP_P2_TCR 0x0d -#define DP_P2_DCR 0x0e -#define DP_P2_IMR 0x0f - -/* Command register - common to all pages */ - -#define DP_CR_STOP 0x01 /* Stop: software reset */ -#define DP_CR_START 0x02 /* Start: initialize device */ -#define DP_CR_TXPKT 0x04 /* Transmit packet */ -#define DP_CR_RDMA 0x08 /* Read DMA (recv data from device) */ -#define DP_CR_WDMA 0x10 /* Write DMA (send data to device) */ -#define DP_CR_SEND 0x18 /* Send packet */ -#define DP_CR_NODMA 0x20 /* Remote (or no) DMA */ -#define DP_CR_PAGE0 0x00 /* Page select */ -#define DP_CR_PAGE1 0x40 -#define DP_CR_PAGE2 0x80 -#define DP_CR_PAGEMSK 0x3F /* Used to mask out page bits */ - -/* Data configuration register */ - -#define DP_DCR_WTS 0x01 /* 1=16 bit word transfers */ -#define DP_DCR_BOS 0x02 /* 1=Little Endian */ -#define DP_DCR_LAS 0x04 /* 1=Single 32 bit DMA mode */ -#define DP_DCR_LS 0x08 /* 1=normal mode, 0=loopback */ -#define DP_DCR_ARM 0x10 /* 0=no send command (program I/O) */ -#define DP_DCR_FIFO_1 0x00 /* FIFO threshold */ -#define DP_DCR_FIFO_2 0x20 -#define DP_DCR_FIFO_4 0x40 -#define DP_DCR_FIFO_6 0x60 - -#define DP_DCR_INIT (DP_DCR_LS|DP_DCR_FIFO_4) - -/* Interrupt status register */ - -#define DP_ISR_RxP 0x01 /* Packet received */ -#define DP_ISR_TxP 0x02 /* Packet transmitted */ -#define DP_ISR_RxE 0x04 /* Receive error */ -#define DP_ISR_TxE 0x08 /* Transmit error */ -#define DP_ISR_OFLW 0x10 /* Receive overflow */ -#define DP_ISR_CNT 0x20 /* Tally counters need emptying */ -#define DP_ISR_RDC 0x40 /* Remote DMA complete */ -#define DP_ISR_RESET 0x80 /* Device has reset (shutdown, error) */ - -/* Interrupt mask register */ - -#define DP_IMR_RxP 0x01 /* Packet received */ -#define DP_IMR_TxP 0x02 /* Packet transmitted */ -#define DP_IMR_RxE 0x04 /* Receive error */ -#define DP_IMR_TxE 0x08 /* Transmit error */ -#define DP_IMR_OFLW 0x10 /* Receive overflow */ -#define DP_IMR_CNT 0x20 /* Tall counters need emptying */ -#define DP_IMR_RDC 0x40 /* Remote DMA complete */ - -#define DP_IMR_All 0x3F /* Everything but remote DMA */ - -/* Receiver control register */ - -#define DP_RCR_SEP 0x01 /* Save bad(error) packets */ -#define DP_RCR_AR 0x02 /* Accept runt packets */ -#define DP_RCR_AB 0x04 /* Accept broadcast packets */ -#define DP_RCR_AM 0x08 /* Accept multicast packets */ -#define DP_RCR_PROM 0x10 /* Promiscuous mode */ -#define DP_RCR_MON 0x20 /* Monitor mode - 1=accept no packets */ - -/* Receiver status register */ - -#define DP_RSR_RxP 0x01 /* Packet received */ -#define DP_RSR_CRC 0x02 /* CRC error */ -#define DP_RSR_FRAME 0x04 /* Framing error */ -#define DP_RSR_FO 0x08 /* FIFO overrun */ -#define DP_RSR_MISS 0x10 /* Missed packet */ -#define DP_RSR_PHY 0x20 /* 0=pad match, 1=mad match */ -#define DP_RSR_DIS 0x40 /* Receiver disabled */ -#define DP_RSR_DFR 0x80 /* Receiver processing deferred */ - -/* Transmitter control register */ - -#define DP_TCR_NOCRC 0x01 /* 1=inhibit CRC */ -#define DP_TCR_NORMAL 0x00 /* Normal transmitter operation */ -#define DP_TCR_LOCAL 0x02 /* Internal NIC loopback */ -#define DP_TCR_INLOOP 0x04 /* Full internal loopback */ -#define DP_TCR_OUTLOOP 0x08 /* External loopback */ -#define DP_TCR_ATD 0x10 /* Auto transmit disable */ -#define DP_TCR_OFFSET 0x20 /* Collision offset adjust */ - -/* Transmit status register */ - -#define DP_TSR_TxP 0x01 /* Packet transmitted */ -#define DP_TSR_COL 0x04 /* Collision (at least one) */ -#define DP_TSR_ABT 0x08 /* Aborted because of too many collisions */ -#define DP_TSR_CRS 0x10 /* Lost carrier */ -#define DP_TSR_FU 0x20 /* FIFO underrun */ -#define DP_TSR_CDH 0x40 /* Collision Detect Heartbeat */ -#define DP_TSR_OWC 0x80 /* Collision outside normal window */ - -#define IEEE_8023_MAX_FRAME 1518 /* Largest possible ethernet frame */ -#define IEEE_8023_MIN_FRAME 64 /* Smallest possible ethernet frame */ + * NE2000 support header file. + * Created by Nobuhiro Iwamatsu + */ + +#ifndef __DRIVERS_NE2000_H__ +#define __DRIVERS_NE2000_H__ + +/* Enable NE2000 basic init function */ +#define NE2000_BASIC_INIT + +#define DP_DATA 0x10 +#define START_PG 0x50 /* First page of TX buffer */ +#define STOP_PG 0x80 /* Last page +1 of RX ring */ + +#define RX_START 0x50 +#define RX_END 0x80 + +#define DP_IN(_b_, _o_, _d_) (_d_) = *( (vu_char *) ((_b_)+(_o_))) +#define DP_OUT(_b_, _o_, _d_) *( (vu_char *) ((_b_)+(_o_))) = (_d_) +#define DP_IN_DATA(_b_, _d_) (_d_) = *( (vu_char *) ((_b_))) +#define DP_OUT_DATA(_b_, _d_) *( (vu_char *) ((_b_))) = (_d_) + +static void pcnet_reset_8390(void) +{ + int i, r; + + PRINTK("nic base is %lx\n", nic_base); + + n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD); + PRINTK("cmd (at %lx) is %x\n", nic_base+ E8390_CMD, n2k_inb(E8390_CMD)); + n2k_outb(E8390_NODMA+E8390_PAGE1+E8390_STOP, E8390_CMD); + PRINTK("cmd (at %lx) is %x\n", nic_base+ E8390_CMD, n2k_inb(E8390_CMD)); + n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD); + PRINTK("cmd (at %lx) is %x\n", nic_base+ E8390_CMD, n2k_inb(E8390_CMD)); + n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD); + + n2k_outb(n2k_inb(PCNET_RESET), PCNET_RESET); + + for (i = 0; i < 100; i++) { + if ((r = (n2k_inb(EN0_ISR) & ENISR_RESET)) != 0) + break; + PRINTK("got %x in reset\n", r); + udelay(100); + } + n2k_outb(ENISR_RESET, EN0_ISR); /* Ack intr. */ + + if (i == 100) + printf("pcnet_reset_8390() did not complete.\n"); +} /* pcnet_reset_8390 */ + +int get_prom(u8* mac_addr) +{ + u8 prom[32]; + int i, j; + struct { + u_char value, offset; + } program_seq[] = { + {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/ + {0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */ + {0x00, EN0_RCNTLO}, /* Clear the count regs. */ + {0x00, EN0_RCNTHI}, + {0x00, EN0_IMR}, /* Mask completion irq. */ + {0xFF, EN0_ISR}, + {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */ + {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */ + {32, EN0_RCNTLO}, + {0x00, EN0_RCNTHI}, + {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */ + {0x00, EN0_RSARHI}, + {E8390_RREAD+E8390_START, E8390_CMD}, + }; + + PRINTK("trying to get MAC via prom reading\n"); + + pcnet_reset_8390(); + + mdelay(10); + + for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) + n2k_outb(program_seq[i].value, program_seq[i].offset); + + PRINTK("PROM:"); + for (i = 0; i < 32; i++) { + prom[i] = n2k_inb(PCNET_DATAPORT); + PRINTK(" %02x", prom[i]); + } + PRINTK("\n"); + for (i = 0; i < NR_INFO; i++) { + if ((prom[0] == hw_info[i].a0) && + (prom[2] == hw_info[i].a1) && + (prom[4] == hw_info[i].a2)) { + PRINTK("matched board %d\n", i); + break; + } + } + if ((i < NR_INFO) || ((prom[28] == 0x57) && (prom[30] == 0x57))) { + PRINTK("on exit i is %d/%ld\n", i, NR_INFO); + PRINTK("MAC address is "); + for (j = 0; j < 6; j++){ + mac_addr[j] = prom[j<<1]; + PRINTK("%02x:",mac_addr[i]); + } + PRINTK("\n"); + return (i < NR_INFO) ? i : 0; + } + return NULL; +} + + +#endif /* __DRIVERS_NE2000_H__ */ diff --git a/drivers/net/ne2000_base.h b/drivers/net/ne2000_base.h new file mode 100644 index 0000000000..1badf62bf2 --- /dev/null +++ b/drivers/net/ne2000_base.h @@ -0,0 +1,282 @@ +/* +Ported to U-Boot by Christian Pellegrin + +Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and +eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world +are GPL, so this is, of course, GPL. + + +========================================================================== + + dev/dp83902a.h + + National Semiconductor DP83902a ethernet chip + +========================================================================== +####ECOSGPLCOPYRIGHTBEGIN#### + ------------------------------------------- + This file is part of eCos, the Embedded Configurable Operating System. + Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. + + eCos 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 or (at your option) any later version. + + eCos is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with eCos; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + + As a special exception, if other files instantiate templates or use macros + or inline functions from this file, or you compile this file and link it + with other works to produce a work based on this file, this file does not + by itself cause the resulting work to be covered by the GNU General Public + License. However the source code for this file must still be made available + in accordance with section (3) of the GNU General Public License. + + This exception does not invalidate any other reasons why a work based on + this file might be covered by the GNU General Public License. + + Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. + at http://sources.redhat.com/ecos/ecos-license/ + ------------------------------------------- +####ECOSGPLCOPYRIGHTEND#### +####BSDCOPYRIGHTBEGIN#### + + ------------------------------------------- + + Portions of this software may have been derived from OpenBSD or other sources, + and are covered by the appropriate copyright disclaimers included herein. + + ------------------------------------------- + +####BSDCOPYRIGHTEND#### +========================================================================== +#####DESCRIPTIONBEGIN#### + + Author(s): gthomas + Contributors: gthomas, jskov + Date: 2001-06-13 + Purpose: + Description: + +####DESCRIPTIONEND#### + +========================================================================== + +*/ + +/* + ------------------------------------------------------------------------ + Macros for accessing DP registers + These can be overridden by the platform header +*/ + +#define bool int + +#define false 0 +#define true 1 + +/* timeout for tx/rx in s */ +#define TOUT 5 +/* Ether MAC address size */ +#define ETHER_ADDR_LEN 6 + + +#define CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA 1 +#define CYGACC_CALL_IF_DELAY_US(X) udelay(X) + +/* H/W infomation struct */ +typedef struct hw_info_t { + u32 offset; + u8 a0, a1, a2; + u32 flags; +} hw_info_t; + +typedef struct dp83902a_priv_data { + u8* base; + u8* data; + u8* reset; + int tx_next; /* First free Tx page */ + int tx_int; /* Expecting interrupt from this buffer */ + int rx_next; /* First free Rx page */ + int tx1, tx2; /* Page numbers for Tx buffers */ + u32 tx1_key, tx2_key; /* Used to ack when packet sent */ + int tx1_len, tx2_len; + bool tx_started, running, hardwired_esa; + u8 esa[6]; + void* plf_priv; + + /* Buffer allocation */ + int tx_buf1, tx_buf2; + int rx_buf_start, rx_buf_end; +} dp83902a_priv_data_t; + +/* + ------------------------------------------------------------------------ + Some forward declarations +*/ +int get_prom( u8* mac_addr); +static void dp83902a_poll(void); + +/* ------------------------------------------------------------------------ */ +/* Register offsets */ + +#define DP_CR 0x00 +#define DP_CLDA0 0x01 +#define DP_PSTART 0x01 /* write */ +#define DP_CLDA1 0x02 +#define DP_PSTOP 0x02 /* write */ +#define DP_BNDRY 0x03 +#define DP_TSR 0x04 +#define DP_TPSR 0x04 /* write */ +#define DP_NCR 0x05 +#define DP_TBCL 0x05 /* write */ +#define DP_FIFO 0x06 +#define DP_TBCH 0x06 /* write */ +#define DP_ISR 0x07 +#define DP_CRDA0 0x08 +#define DP_RSAL 0x08 /* write */ +#define DP_CRDA1 0x09 +#define DP_RSAH 0x09 /* write */ +#define DP_RBCL 0x0a /* write */ +#define DP_RBCH 0x0b /* write */ +#define DP_RSR 0x0c +#define DP_RCR 0x0c /* write */ +#define DP_FER 0x0d +#define DP_TCR 0x0d /* write */ +#define DP_CER 0x0e +#define DP_DCR 0x0e /* write */ +#define DP_MISSED 0x0f +#define DP_IMR 0x0f /* write */ +#define DP_DATAPORT 0x10 /* "eprom" data port */ + +#define DP_P1_CR 0x00 +#define DP_P1_PAR0 0x01 +#define DP_P1_PAR1 0x02 +#define DP_P1_PAR2 0x03 +#define DP_P1_PAR3 0x04 +#define DP_P1_PAR4 0x05 +#define DP_P1_PAR5 0x06 +#define DP_P1_CURP 0x07 +#define DP_P1_MAR0 0x08 +#define DP_P1_MAR1 0x09 +#define DP_P1_MAR2 0x0a +#define DP_P1_MAR3 0x0b +#define DP_P1_MAR4 0x0c +#define DP_P1_MAR5 0x0d +#define DP_P1_MAR6 0x0e +#define DP_P1_MAR7 0x0f + +#define DP_P2_CR 0x00 +#define DP_P2_PSTART 0x01 +#define DP_P2_CLDA0 0x01 /* write */ +#define DP_P2_PSTOP 0x02 +#define DP_P2_CLDA1 0x02 /* write */ +#define DP_P2_RNPP 0x03 +#define DP_P2_TPSR 0x04 +#define DP_P2_LNPP 0x05 +#define DP_P2_ACH 0x06 +#define DP_P2_ACL 0x07 +#define DP_P2_RCR 0x0c +#define DP_P2_TCR 0x0d +#define DP_P2_DCR 0x0e +#define DP_P2_IMR 0x0f + +/* Command register - common to all pages */ + +#define DP_CR_STOP 0x01 /* Stop: software reset */ +#define DP_CR_START 0x02 /* Start: initialize device */ +#define DP_CR_TXPKT 0x04 /* Transmit packet */ +#define DP_CR_RDMA 0x08 /* Read DMA (recv data from device) */ +#define DP_CR_WDMA 0x10 /* Write DMA (send data to device) */ +#define DP_CR_SEND 0x18 /* Send packet */ +#define DP_CR_NODMA 0x20 /* Remote (or no) DMA */ +#define DP_CR_PAGE0 0x00 /* Page select */ +#define DP_CR_PAGE1 0x40 +#define DP_CR_PAGE2 0x80 +#define DP_CR_PAGEMSK 0x3F /* Used to mask out page bits */ + +/* Data configuration register */ + +#define DP_DCR_WTS 0x01 /* 1=16 bit word transfers */ +#define DP_DCR_BOS 0x02 /* 1=Little Endian */ +#define DP_DCR_LAS 0x04 /* 1=Single 32 bit DMA mode */ +#define DP_DCR_LS 0x08 /* 1=normal mode, 0=loopback */ +#define DP_DCR_ARM 0x10 /* 0=no send command (program I/O) */ +#define DP_DCR_FIFO_1 0x00 /* FIFO threshold */ +#define DP_DCR_FIFO_2 0x20 +#define DP_DCR_FIFO_4 0x40 +#define DP_DCR_FIFO_6 0x60 + +#define DP_DCR_INIT (DP_DCR_LS|DP_DCR_FIFO_4) + +/* Interrupt status register */ + +#define DP_ISR_RxP 0x01 /* Packet received */ +#define DP_ISR_TxP 0x02 /* Packet transmitted */ +#define DP_ISR_RxE 0x04 /* Receive error */ +#define DP_ISR_TxE 0x08 /* Transmit error */ +#define DP_ISR_OFLW 0x10 /* Receive overflow */ +#define DP_ISR_CNT 0x20 /* Tally counters need emptying */ +#define DP_ISR_RDC 0x40 /* Remote DMA complete */ +#define DP_ISR_RESET 0x80 /* Device has reset (shutdown, error) */ + +/* Interrupt mask register */ + +#define DP_IMR_RxP 0x01 /* Packet received */ +#define DP_IMR_TxP 0x02 /* Packet transmitted */ +#define DP_IMR_RxE 0x04 /* Receive error */ +#define DP_IMR_TxE 0x08 /* Transmit error */ +#define DP_IMR_OFLW 0x10 /* Receive overflow */ +#define DP_IMR_CNT 0x20 /* Tall counters need emptying */ +#define DP_IMR_RDC 0x40 /* Remote DMA complete */ + +#define DP_IMR_All 0x3F /* Everything but remote DMA */ + +/* Receiver control register */ + +#define DP_RCR_SEP 0x01 /* Save bad(error) packets */ +#define DP_RCR_AR 0x02 /* Accept runt packets */ +#define DP_RCR_AB 0x04 /* Accept broadcast packets */ +#define DP_RCR_AM 0x08 /* Accept multicast packets */ +#define DP_RCR_PROM 0x10 /* Promiscuous mode */ +#define DP_RCR_MON 0x20 /* Monitor mode - 1=accept no packets */ + +/* Receiver status register */ + +#define DP_RSR_RxP 0x01 /* Packet received */ +#define DP_RSR_CRC 0x02 /* CRC error */ +#define DP_RSR_FRAME 0x04 /* Framing error */ +#define DP_RSR_FO 0x08 /* FIFO overrun */ +#define DP_RSR_MISS 0x10 /* Missed packet */ +#define DP_RSR_PHY 0x20 /* 0=pad match, 1=mad match */ +#define DP_RSR_DIS 0x40 /* Receiver disabled */ +#define DP_RSR_DFR 0x80 /* Receiver processing deferred */ + +/* Transmitter control register */ + +#define DP_TCR_NOCRC 0x01 /* 1=inhibit CRC */ +#define DP_TCR_NORMAL 0x00 /* Normal transmitter operation */ +#define DP_TCR_LOCAL 0x02 /* Internal NIC loopback */ +#define DP_TCR_INLOOP 0x04 /* Full internal loopback */ +#define DP_TCR_OUTLOOP 0x08 /* External loopback */ +#define DP_TCR_ATD 0x10 /* Auto transmit disable */ +#define DP_TCR_OFFSET 0x20 /* Collision offset adjust */ + +/* Transmit status register */ + +#define DP_TSR_TxP 0x01 /* Packet transmitted */ +#define DP_TSR_COL 0x04 /* Collision (at least one) */ +#define DP_TSR_ABT 0x08 /* Aborted because of too many collisions */ +#define DP_TSR_CRS 0x10 /* Lost carrier */ +#define DP_TSR_FU 0x20 /* FIFO underrun */ +#define DP_TSR_CDH 0x40 /* Collision Detect Heartbeat */ +#define DP_TSR_OWC 0x80 /* Collision outside normal window */ + +#define IEEE_8023_MAX_FRAME 1518 /* Largest possible ethernet frame */ +#define IEEE_8023_MIN_FRAME 64 /* Smallest possible ethernet frame */ -- cgit From e0a6140dd381e1eed1ada2291166ef2616d8822b Mon Sep 17 00:00:00 2001 From: Wolfgang Denk Date: Tue, 25 Mar 2008 22:50:41 +0100 Subject: ne2000 driver: change #ifdef to Makefile conditional compilation Signed-off-by: Wolfgang Denk --- drivers/net/Makefile | 2 +- drivers/net/ne2000.c | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 321bd08adb..7d7df9cab7 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -41,7 +41,7 @@ COBJS-y += lan91c96.o COBJS-y += macb.o COBJS-y += mcffec.o COBJS-y += natsemi.o -COBJS-y += ne2000.o +COBJS-$(CONFIG_DRIVER_NE2000) += ne2000.o COBJS-y += netarm_eth.o COBJS-y += netconsole.o COBJS-y += ns7520_eth.o diff --git a/drivers/net/ne2000.c b/drivers/net/ne2000.c index 49280148d2..36ea35b2c2 100644 --- a/drivers/net/ne2000.c +++ b/drivers/net/ne2000.c @@ -80,8 +80,6 @@ Add SNMP #include #include -#ifdef CONFIG_DRIVER_NE2000 - #define mdelay(n) udelay((n)*1000) /* forward definition of function used for the uboot interface */ void uboot_push_packet_len(int len); @@ -851,4 +849,3 @@ int eth_send(volatile void *packet, int length) { } return 0; } -#endif -- cgit From 6a8a5dc4759867c45aa95580deb8bf26669a5d97 Mon Sep 17 00:00:00 2001 From: "goda.yusuke" Date: Wed, 5 Mar 2008 17:08:33 +0900 Subject: net: Add support AX88796L ethernet device AX88796L is device of NE2000 compatible. This patch support AX88796L ethernet device. Signed-off-by: Yusuke Goda Acked-by: Nobuhiro Iwamatsu --- drivers/net/ax88796.h | 217 ++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/ne2000.c | 6 ++ 2 files changed, 223 insertions(+) create mode 100644 drivers/net/ax88796.h (limited to 'drivers') diff --git a/drivers/net/ax88796.h b/drivers/net/ax88796.h new file mode 100644 index 0000000000..069ae80fa8 --- /dev/null +++ b/drivers/net/ax88796.h @@ -0,0 +1,217 @@ +/* + * AX88796L(NE2000) support + * + * (c) 2007 Nobuhiro Iwamatsu + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef __DRIVERS_AX88796L_H__ +#define __DRIVERS_AX88796L_H__ + +#define DP_DATA (0x10 << 1) +#define START_PG 0x40 /* First page of TX buffer */ +#define START_PG2 0x48 +#define STOP_PG 0x80 /* Last page +1 of RX ring */ +#define TX_PAGES 12 +#define RX_START (START_PG+TX_PAGES) +#define RX_END STOP_PG + +#define AX88796L_BASE_ADDRESS CONFIG_DRIVER_NE2000_BASE +#define AX88796L_BYTE_ACCESS 0x00001000 +#define AX88796L_OFFSET 0x00000400 +#define AX88796L_ADDRESS_BYTE AX88796L_BASE_ADDRESS + \ + AX88796L_BYTE_ACCESS + AX88796L_OFFSET +#define AX88796L_REG_MEMR AX88796L_ADDRESS_BYTE + (0x14<<1) +#define AX88796L_REG_CR AX88796L_ADDRESS_BYTE + (0x00<<1) + +#define AX88796L_CR (*(vu_short *)(AX88796L_REG_CR)) +#define AX88796L_MEMR (*(vu_short *)(AX88796L_REG_MEMR)) + +#define EECS_HIGH (AX88796L_MEMR |= 0x10) +#define EECS_LOW (AX88796L_MEMR &= 0xef) +#define EECLK_HIGH (AX88796L_MEMR |= 0x80) +#define EECLK_LOW (AX88796L_MEMR &= 0x7f) +#define EEDI_HIGH (AX88796L_MEMR |= 0x20) +#define EEDI_LOW (AX88796L_MEMR &= 0xdf) +#define EEDO ((AX88796L_MEMR & 0x40)>>6) + +#define PAGE0_SET (AX88796L_CR &= 0x3f) +#define PAGE1_SET (AX88796L_CR = (AX88796L_CR & 0x3f) | 0x40) + +#define BIT_DUMMY 0 +#define MAC_EEP_READ 1 +#define MAC_EEP_WRITE 2 +#define MAC_EEP_ERACE 3 +#define MAC_EEP_EWEN 4 +#define MAC_EEP_EWDS 5 + +/* R7780MP Specific code */ +#if defined(CONFIG_R7780MP) +#define ISA_OFFSET 0x1400 +#define DP_IN(_b_, _o_, _d_) (_d_) = \ + *( (vu_short *) ((_b_) + ((_o_) * 2) + ISA_OFFSET)) +#define DP_OUT(_b_, _o_, _d_) \ + *((vu_short *)((_b_) + ((_o_) * 2) + ISA_OFFSET)) = (_d_) +#define DP_IN_DATA(_b_, _d_) (_d_) = *( (vu_short *) ((_b_) + ISA_OFFSET)) +#define DP_OUT_DATA(_b_, _d_) *( (vu_short *) ((_b_)+ISA_OFFSET)) = (_d_) +#else +/* Please change for your target boards */ +#define ISA_OFFSET 0x0000 +#define DP_IN(_b_, _o_, _d_) (_d_) = *( (vu_short *)((_b_)+(_o_ )+ISA_OFFSET)) +#define DP_OUT(_b_, _o_, _d_) *((vu_short *)((_b_)+(_o_)+ISA_OFFSET)) = (_d_) +#define DP_IN_DATA(_b_, _d_) (_d_) = *( (vu_short *) ((_b_)+ISA_OFFSET)) +#define DP_OUT_DATA(_b_, _d_) *( (vu_short *) ((_b_)+ISA_OFFSET)) = (_d_) +#endif + + +/* + * Set 1 bit data + */ +static void ax88796_bitset(u32 bit) +{ + /* DATA1 */ + if( bit ) + EEDI_HIGH; + else + EEDI_LOW; + + EECLK_LOW; + udelay(1000); + EECLK_HIGH; + udelay(1000); + EEDI_LOW; +} + +/* + * Get 1 bit data + */ +static u8 ax88796_bitget(void) +{ + u8 bit; + + EECLK_LOW; + udelay(1000); + /* DATA */ + bit = EEDO; + EECLK_HIGH; + udelay(1000); + + return bit; +} + +/* + * Send COMMAND to EEPROM + */ +static void ax88796_eep_cmd(u8 cmd) +{ + ax88796_bitset(BIT_DUMMY); + switch(cmd){ + case MAC_EEP_READ: + ax88796_bitset(1); + ax88796_bitset(1); + ax88796_bitset(0); + break; + + case MAC_EEP_WRITE: + ax88796_bitset(1); + ax88796_bitset(0); + ax88796_bitset(1); + break; + + case MAC_EEP_ERACE: + ax88796_bitset(1); + ax88796_bitset(1); + ax88796_bitset(1); + break; + + case MAC_EEP_EWEN: + ax88796_bitset(1); + ax88796_bitset(0); + ax88796_bitset(0); + break; + + case MAC_EEP_EWDS: + ax88796_bitset(1); + ax88796_bitset(0); + ax88796_bitset(0); + break; + default: + break; + } +} + +static void ax88796_eep_setaddr(u16 addr) +{ + int i ; + for( i = 7 ; i >= 0 ; i-- ) + ax88796_bitset(addr & (1 << i)); +} + +/* + * Get data from EEPROM + */ +static u16 ax88796_eep_getdata(void) +{ + ushort data = 0; + int i; + + ax88796_bitget(); /* DUMMY */ + for( i = 0 ; i < 16 ; i++ ){ + data <<= 1; + data |= ax88796_bitget(); + } + return data; +} + +static void ax88796_mac_read(u8 *buff) +{ + int i ; + u16 data, addr = 0; + + for( i = 0 ; i < 3; i++ ) + { + EECS_HIGH; + EEDI_LOW; + udelay(1000); + /* READ COMMAND */ + ax88796_eep_cmd(MAC_EEP_READ); + /* ADDRESS */ + ax88796_eep_setaddr(addr++); + /* GET DATA */ + data = ax88796_eep_getdata(); + *buff++ = (uchar)(data & 0xff); + *buff++ = (uchar)((data >> 8) & 0xff); + EECLK_LOW; + EEDI_LOW; + EECS_LOW; + } +} + +int get_prom(u8* mac_addr) +{ + u8 prom[32]; + int i; + + ax88796_mac_read(prom); + for (i = 0; i < 6; i++){ + mac_addr[i] = prom[i]; + } + return 1; +} + +#endif /* __DRIVERS_AX88796L_H__ */ diff --git a/drivers/net/ne2000.c b/drivers/net/ne2000.c index 36ea35b2c2..abf910c54f 100644 --- a/drivers/net/ne2000.c +++ b/drivers/net/ne2000.c @@ -112,8 +112,13 @@ void uboot_push_tx_done(int key, int val); /* NE2000 base header file */ #include "ne2000_base.h" +#if defined(CONFIG_DRIVER_AX88796L) +/* AX88796L support */ +#include "ax88796.h" +#else /* Basic NE2000 chip support */ #include "ne2000.h" +#endif static dp83902a_priv_data_t nic; /* just one instance of the card supported */ @@ -131,6 +136,7 @@ dp83902a_init(void) DEBUG_LINE(); #if defined(NE2000_BASIC_INIT) + /* AX88796L doesn't need */ /* Prepare ESA */ DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1); /* Select page 1 */ /* Use the address from the serial EEPROM */ -- cgit From 1bb707c39a0833e91d9f797dd862aaaaf4af264d Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Mon, 17 Mar 2008 08:54:06 +0900 Subject: Add Flex-OneNAND booting support Flex-OneNAND is a monolithic integrated circuit with a NAND Flash array using a NOR Flash interface. This on-chip integration enables system designers to reduce external system logic and use high-density NAND Flash in applications that would otherwise have to use more NOR components. Flex-OneNAND enables users to configure to partition it into SLC and MLC areas in more flexible way. While MLC area of Flex-OneNAND can be used to store data that require low reliability and high density, SLC area of Flex-OneNAND to store data that need high reliability and high performance. Flex-OneNAND can let users take advantage of storing these two different types of data into one chip, which is making Flex-OneNAND more cost- and space-effective. Signed-off-by: Kyungmin Park --- drivers/mtd/onenand/onenand_base.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index d4003a20f2..3b828fb627 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1180,6 +1180,12 @@ static int onenand_probe(struct mtd_info *mtd) if (maf_id != bram_maf_id || dev_id != bram_dev_id) return -ENXIO; + /* FIXME : Current OneNAND MTD doesn't support Flex-OneNAND */ + if (dev_id & (1 << 9)) { + printk("Not yet support Flex-OneNAND\n"); + return -ENXIO; + } + /* Flash device information */ onenand_print_device_info(dev_id, 0); this->device_id = dev_id; -- cgit From 22ed2285743359fd1fe73e411dff914b2256e68f Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 17 Mar 2008 10:49:25 +0100 Subject: rtc: Remove 2nd reference to max6900.o in drivers/rtc/Makefile Signed-off-by: Stefan Roese --- drivers/rtc/Makefile | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 9be2130e1b..800ab9934a 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -43,7 +43,6 @@ COBJS-$(CONFIG_RTC_ISL1208) += isl1208.o COBJS-y += m41t11.o COBJS-y += m41t60.o COBJS-$(CONFIG_RTC_M41T62) += m41t62.o -COBJS-y += max6900.o COBJS-y += m48t35ax.o COBJS-y += max6900.o COBJS-y += mc146818.o -- cgit From aa6f6d171a1f9f46ee4f03ad6acb97a6bfb71855 Mon Sep 17 00:00:00 2001 From: Wolfgang Denk Date: Wed, 26 Mar 2008 00:52:10 +0100 Subject: Coding Style cleanyp; update CHANGELOG Signed-off-by: Wolfgang Denk --- drivers/net/ne2000.c | 7 ++--- drivers/net/ne2000.h | 82 +++++++++++++++++++++++++--------------------------- 2 files changed, 41 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ne2000.c b/drivers/net/ne2000.c index abf910c54f..99baeea3e8 100644 --- a/drivers/net/ne2000.c +++ b/drivers/net/ne2000.c @@ -5,7 +5,6 @@ Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world are GPL, so this is, of course, GPL. - ========================================================================== dev/if_dp83902a.c @@ -70,9 +69,7 @@ Add SNMP ####DESCRIPTIONEND#### - ========================================================================== - */ #include @@ -210,7 +207,8 @@ dp83902a_start(u8 * enaddr) dp->running = true; for (i = 0; i < ETHER_ADDR_LEN; i++) { /* FIXME */ - //*((vu_short*)( base + ((DP_P1_PAR0 + i) * 2) + 0x1400)) = enaddr[i]; + /*((vu_short*)( base + ((DP_P1_PAR0 + i) * 2) + + * 0x1400)) = enaddr[i];*/ DP_OUT(base, DP_P1_PAR0+i, enaddr[i]); } /* Enable and start device */ @@ -218,7 +216,6 @@ dp83902a_start(u8 * enaddr) DP_OUT(base, DP_TCR, DP_TCR_NORMAL); /* Normal transmit operations */ DP_OUT(base, DP_RCR, DP_RCR_AB); /* Accept broadcast, no errors, no multicast */ dp->running = true; - } /* diff --git a/drivers/net/ne2000.h b/drivers/net/ne2000.h index 06e9a2844e..d324a00084 100644 --- a/drivers/net/ne2000.h +++ b/drivers/net/ne2000.h @@ -5,7 +5,6 @@ Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world are GPL, so this is, of course, GPL. - ========================================================================== dev/dp83902a.h @@ -67,7 +66,6 @@ are GPL, so this is, of course, GPL. ####DESCRIPTIONEND#### ========================================================================== - */ /* @@ -129,55 +127,53 @@ int get_prom(u8* mac_addr) u_char value, offset; } program_seq[] = { {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/ - {0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */ - {0x00, EN0_RCNTLO}, /* Clear the count regs. */ + {0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */ + {0x00, EN0_RCNTLO}, /* Clear the count regs. */ {0x00, EN0_RCNTHI}, - {0x00, EN0_IMR}, /* Mask completion irq. */ + {0x00, EN0_IMR}, /* Mask completion irq. */ {0xFF, EN0_ISR}, - {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */ - {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */ + {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */ + {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */ {32, EN0_RCNTLO}, {0x00, EN0_RCNTHI}, - {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */ + {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */ {0x00, EN0_RSARHI}, {E8390_RREAD+E8390_START, E8390_CMD}, }; - PRINTK("trying to get MAC via prom reading\n"); - - pcnet_reset_8390(); - - mdelay(10); - - for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) - n2k_outb(program_seq[i].value, program_seq[i].offset); - - PRINTK("PROM:"); - for (i = 0; i < 32; i++) { - prom[i] = n2k_inb(PCNET_DATAPORT); - PRINTK(" %02x", prom[i]); - } - PRINTK("\n"); - for (i = 0; i < NR_INFO; i++) { - if ((prom[0] == hw_info[i].a0) && - (prom[2] == hw_info[i].a1) && - (prom[4] == hw_info[i].a2)) { - PRINTK("matched board %d\n", i); - break; - } - } - if ((i < NR_INFO) || ((prom[28] == 0x57) && (prom[30] == 0x57))) { - PRINTK("on exit i is %d/%ld\n", i, NR_INFO); - PRINTK("MAC address is "); - for (j = 0; j < 6; j++){ - mac_addr[j] = prom[j<<1]; - PRINTK("%02x:",mac_addr[i]); - } - PRINTK("\n"); - return (i < NR_INFO) ? i : 0; - } - return NULL; -} + PRINTK ("trying to get MAC via prom reading\n"); + + pcnet_reset_8390 (); + + mdelay (10); + for (i = 0; i < sizeof (program_seq) / sizeof (program_seq[0]); i++) + n2k_outb (program_seq[i].value, program_seq[i].offset); + PRINTK ("PROM:"); + for (i = 0; i < 32; i++) { + prom[i] = n2k_inb (PCNET_DATAPORT); + PRINTK (" %02x", prom[i]); + } + PRINTK ("\n"); + for (i = 0; i < NR_INFO; i++) { + if ((prom[0] == hw_info[i].a0) && + (prom[2] == hw_info[i].a1) && + (prom[4] == hw_info[i].a2)) { + PRINTK ("matched board %d\n", i); + break; + } + } + if ((i < NR_INFO) || ((prom[28] == 0x57) && (prom[30] == 0x57))) { + PRINTK ("on exit i is %d/%ld\n", i, NR_INFO); + PRINTK ("MAC address is "); + for (j = 0; j < 6; j++) { + mac_addr[j] = prom[j << 1]; + PRINTK ("%02x:", mac_addr[i]); + } + PRINTK ("\n"); + return (i < NR_INFO) ? i : 0; + } + return NULL; +} #endif /* __DRIVERS_NE2000_H__ */ -- cgit From b55d98c6d5b8694e560a0e727b14cb6921d7cfcc Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Fri, 8 Feb 2008 13:15:54 -0600 Subject: NET: Add Vitesse VSC7385 firmware uploading The Vitesse VSC7385 is a 5-port switch found on the Freescale MPC8349E-mITX and other boards. A small firwmare must be uploaded to its on-board memory before it can be enabled. This patch adds the code which uploads firmware (but not the firmware itself). Previously, this feature was provided by a U-Boot application that was made available only on Freescale BSPs. The VSC7385 firmware must still be obtained separately, but at least there is no longer a need for a separate application. Signed-off-by: Timur Tabi Acked-by: Ben Warren --- drivers/net/Makefile | 1 + drivers/net/vsc7385.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 drivers/net/vsc7385.c (limited to 'drivers') diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 7d7df9cab7..320dc3ebac 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -58,6 +58,7 @@ COBJS-y += tigon3.o COBJS-y += tsec.o COBJS-y += tsi108_eth.o COBJS-y += uli526x.o +COBJS-y += vsc7385.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/net/vsc7385.c b/drivers/net/vsc7385.c new file mode 100644 index 0000000000..f440ce07e2 --- /dev/null +++ b/drivers/net/vsc7385.c @@ -0,0 +1,101 @@ +/* + * Vitesse 7385 Switch Firmware Upload + * + * Author: Timur Tabi + * + * Copyright 2008 Freescale Semiconductor, Inc. This file is licensed + * under the terms of the GNU General Public License version 2. This + * program is licensed "as is" without any warranty of any kind, whether + * express or implied. + * + * This module uploads proprietary firmware for the Vitesse VSC7385 5-port + * switch. + */ + +#include + +#ifdef CONFIG_VSC7385_ENET + +#include +#include +#include + +/* + * Upload a Vitesse VSC7385 firmware image to the hardware + * + * This function takes a pointer to a VSC7385 firmware image and a size, and + * uploads that firmware to the VSC7385. + * + * This firmware is typically located at a board-specific flash address, + * and the size is typically 8KB. + * + * The firmware is Vitesse proprietary. + * + * Further details on the register information can be obtained from Vitesse. + */ +int vsc7385_upload_firmware(void *firmware, unsigned int size) +{ + u8 *fw = firmware; + unsigned int i; + + u32 *gloreset = (u32 *) (CFG_VSC7385_BASE + 0x1c050); + u32 *icpu_ctrl = (u32 *) (CFG_VSC7385_BASE + 0x1c040); + u32 *icpu_addr = (u32 *) (CFG_VSC7385_BASE + 0x1c044); + u32 *icpu_data = (u32 *) (CFG_VSC7385_BASE + 0x1c048); + u32 *icpu_rom_map = (u32 *) (CFG_VSC7385_BASE + 0x1c070); +#ifdef DEBUG + u32 *chipid = (u32 *) (CFG_VSC7385_BASE + 0x1c060); +#endif + + out_be32(gloreset, 3); + udelay(200); + + out_be32(icpu_ctrl, 0x8E); + udelay(20); + + out_be32(icpu_rom_map, 1); + udelay(20); + + /* Write the firmware to I-RAM */ + out_be32(icpu_addr, 0); + udelay(20); + + for (i = 0; i < size; i++) { + out_be32(icpu_data, fw[i]); + udelay(20); + if (ctrlc()) + return -EINTR; + } + + /* Read back and compare */ + out_be32(icpu_addr, 0); + udelay(20); + + for (i = 0; i < size; i++) { + u8 value; + + value = (u8) in_be32(icpu_data); + udelay(20); + if (value != fw[i]) { + debug("VSC7385: Upload mismatch: address 0x%x, " + "read value 0x%x, image value 0x%x\n", + i, value, fw[i]); + + return -EIO; + } + if (ctrlc()) + break; + } + + out_be32(icpu_ctrl, 0x0B); + udelay(20); + +#ifdef DEBUG + printf("VSC7385: Chip ID is %08x\n", in_be32(chipid)); + udelay(20); +#endif + + return 0; +} + +#endif -- cgit From 91cdaa3a9d7562b869d96774e9c9ddf142c0848d Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Mon, 24 Mar 2008 20:46:24 +0300 Subject: uec: add support for gbit mii status readings Signed-off-by: Anton Vorontsov --- drivers/qe/uec_phy.c | 28 +++++++++++++++++++--------- drivers/qe/uec_phy.h | 5 +++++ 2 files changed, 24 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/qe/uec_phy.c b/drivers/qe/uec_phy.c index a42701c59b..8c4a558d82 100644 --- a/drivers/qe/uec_phy.c +++ b/drivers/qe/uec_phy.c @@ -318,16 +318,26 @@ static int genmii_read_status (struct uec_mii_info *mii_info) return err; if (mii_info->autoneg) { - status = phy_read (mii_info, PHY_ANLPAR); + status = phy_read(mii_info, MII_1000BASETSTATUS); - if (status & (PHY_ANLPAR_10FD | PHY_ANLPAR_TXFD)) - mii_info->duplex = DUPLEX_FULL; - else - mii_info->duplex = DUPLEX_HALF; - if (status & (PHY_ANLPAR_TXFD | PHY_ANLPAR_TX)) - mii_info->speed = SPEED_100; - else - mii_info->speed = SPEED_10; + if (status & (LPA_1000FULL | LPA_1000HALF)) { + mii_info->speed = SPEED_1000; + if (status & LPA_1000FULL) + mii_info->duplex = DUPLEX_FULL; + else + mii_info->duplex = DUPLEX_HALF; + } else { + status = phy_read(mii_info, PHY_ANLPAR); + + if (status & (PHY_ANLPAR_10FD | PHY_ANLPAR_TXFD)) + mii_info->duplex = DUPLEX_FULL; + else + mii_info->duplex = DUPLEX_HALF; + if (status & (PHY_ANLPAR_TXFD | PHY_ANLPAR_TX)) + mii_info->speed = SPEED_100; + else + mii_info->speed = SPEED_10; + } mii_info->pause = 0; } /* On non-aneg, we assume what we put in BMCR is the speed, diff --git a/drivers/qe/uec_phy.h b/drivers/qe/uec_phy.h index e59a940e0d..6f769fb50b 100644 --- a/drivers/qe/uec_phy.h +++ b/drivers/qe/uec_phy.h @@ -29,6 +29,11 @@ #define MII_1000BASETCONTROL_FULLDUPLEXCAP 0x0200 #define MII_1000BASETCONTROL_HALFDUPLEXCAP 0x0100 +/* 1000BT status */ +#define MII_1000BASETSTATUS 0x0a +#define LPA_1000FULL 0x0400 +#define LPA_1000HALF 0x0200 + /* Cicada Extended Control Register 1 */ #define MII_CIS8201_EXT_CON1 0x17 #define MII_CIS8201_EXTCON1_INIT 0x0000 -- cgit From 6a600c3a1876bc203445df4f0fd6b12648259666 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Mon, 24 Mar 2008 20:46:28 +0300 Subject: uec: add support for RGMII_RXID interface mode PHY drivers will use it to setup software delay between RXD and RXC signals. Signed-off-by: Anton Vorontsov --- drivers/qe/uec.c | 1 + drivers/qe/uec.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/qe/uec.c b/drivers/qe/uec.c index 55f37cb55c..d34430c659 100644 --- a/drivers/qe/uec.c +++ b/drivers/qe/uec.c @@ -417,6 +417,7 @@ static int uec_set_mac_if_mode(uec_private_t *uec, enet_interface_e if_mode) maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; upsmr |= (UPSMR_RPM | UPSMR_TBIM); break; + case ENET_1000_RGMII_RXID: case ENET_1000_RGMII: maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; upsmr |= UPSMR_RPM; diff --git a/drivers/qe/uec.h b/drivers/qe/uec.h index c384055ceb..7762de6a8d 100644 --- a/drivers/qe/uec.h +++ b/drivers/qe/uec.h @@ -642,6 +642,7 @@ typedef enum enet_interface { ENET_100_RGMII, ENET_1000_GMII, ENET_1000_RGMII, + ENET_1000_RGMII_RXID, ENET_1000_TBI, ENET_1000_RTBI } enet_interface_e; -- cgit From 300615dc5d9b0a2022fbc6af0c13159e33fd752e Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Mon, 24 Mar 2008 20:46:34 +0300 Subject: uec: add support for Broadcom BCM5481 Gigabit PHY This patch adds basic support for Broadcom BCM5481 PHY. RXD-RXC delay quirk comes from MPC8360E-RDK BSP source, author is Peter Barada . Signed-off-by: Anton Vorontsov --- drivers/qe/uec_phy.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'drivers') diff --git a/drivers/qe/uec_phy.c b/drivers/qe/uec_phy.c index 8c4a558d82..423ba789e9 100644 --- a/drivers/qe/uec_phy.c +++ b/drivers/qe/uec_phy.c @@ -347,6 +347,37 @@ static int genmii_read_status (struct uec_mii_info *mii_info) return 0; } +static int bcm_init(struct uec_mii_info *mii_info) +{ + struct eth_device *edev = mii_info->dev; + uec_private_t *uec = edev->priv; + + gbit_config_aneg(mii_info); + + if (uec->uec_info->enet_interface == ENET_1000_RGMII_RXID) { + u16 val; + int cnt = 50; + + /* Wait for aneg to complete. */ + do + val = phy_read(mii_info, PHY_BMSR); + while (--cnt && !(val & PHY_BMSR_AUTN_COMP)); + + /* Set RDX clk delay. */ + phy_write(mii_info, 0x18, 0x7 | (7 << 12)); + + val = phy_read(mii_info, 0x18); + /* Set RDX-RXC skew. */ + val |= (1 << 8); + val |= (7 | (7 << 12)); + /* Write bits 14:0. */ + val |= (1 << 15); + phy_write(mii_info, 0x18, val); + } + + return 0; +} + static int marvell_read_status (struct uec_mii_info *mii_info) { u16 status; @@ -515,6 +546,15 @@ static struct phy_info phy_info_marvell = { .config_intr = &marvell_config_intr, }; +static struct phy_info phy_info_bcm5481 = { + .phy_id = 0x0143bca0, + .phy_id_mask = 0xffffff0, + .name = "Broadcom 5481", + .features = MII_GBIT_FEATURES, + .read_status = genmii_read_status, + .init = bcm_init, +}; + static struct phy_info phy_info_genmii = { .phy_id = 0x00000000, .phy_id_mask = 0x00000000, @@ -528,6 +568,7 @@ static struct phy_info *phy_info[] = { &phy_info_dm9161, &phy_info_dm9161a, &phy_info_marvell, + &phy_info_bcm5481, &phy_info_genmii, NULL }; -- cgit From c7604783b236e368f225efb7b3efb418fe20b404 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Fri, 14 Mar 2008 23:20:30 +0300 Subject: tsec: fix link detection for the RTL8211B PHY RTL8211B sets link state register after autonegotiation complete, so with bootdelay=0 RTL8211B will report lack of the link. To fix this, we should wait for aneg to complete, even if the link is currently down. Signed-off-by: Anton Vorontsov Signed-off-by: Kim Phillips --- drivers/net/tsec.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index e91d9eadc1..431a8d2f23 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -583,10 +583,11 @@ uint mii_parse_RTL8211B_sr(uint mii_reg, struct tsec_private * priv) uint speed; mii_reg = read_phy_reg(priv, MIIM_RTL8211B_PHY_STATUS); - if ((mii_reg & MIIM_RTL8211B_PHYSTAT_LINK) && - !(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) { + if (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) { int i = 0; + /* in case of timeout ->link is cleared */ + priv->link = 1; puts("Waiting for PHY realtime link"); while (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) { /* Timeout reached ? */ -- cgit From 438a4c11260b4ea9805039b0b4f92f9df5306b02 Mon Sep 17 00:00:00 2001 From: Wolfgang Denk Date: Wed, 26 Mar 2008 11:48:46 +0100 Subject: Cleanup coding style, update CHANGELOG Signed-off-by: Wolfgang Denk --- drivers/net/vsc7385.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vsc7385.c b/drivers/net/vsc7385.c index f440ce07e2..4095bce5bf 100644 --- a/drivers/net/vsc7385.c +++ b/drivers/net/vsc7385.c @@ -56,7 +56,7 @@ int vsc7385_upload_firmware(void *firmware, unsigned int size) out_be32(icpu_rom_map, 1); udelay(20); - /* Write the firmware to I-RAM */ + /* Write the firmware to I-RAM */ out_be32(icpu_addr, 0); udelay(20); @@ -78,8 +78,8 @@ int vsc7385_upload_firmware(void *firmware, unsigned int size) udelay(20); if (value != fw[i]) { debug("VSC7385: Upload mismatch: address 0x%x, " - "read value 0x%x, image value 0x%x\n", - i, value, fw[i]); + "read value 0x%x, image value 0x%x\n", + i, value, fw[i]); return -EIO; } -- cgit From da8808df7a9cef5a3d2ee286ef9ebf9de1780660 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Wed, 26 Mar 2008 13:02:13 +0100 Subject: Add CFG_RTC_DS1337_NOOSC to turn off OSC output The default settings for RTC DS1337 keeps the OSC output, 32,768 Hz, on. This add CFG_RTC_DS1337_NOOSC to turn it off. Signed-off-by: Joakim Tjernlund --- drivers/rtc/ds1337.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/ds1337.c b/drivers/rtc/ds1337.c index 50ab44690c..69ab2bf9db 100644 --- a/drivers/rtc/ds1337.c +++ b/drivers/rtc/ds1337.c @@ -158,11 +158,18 @@ void rtc_set (struct rtc_time *tmp) * SQW/INTB* pin and program it for 32,768 Hz output. Note that * according to the datasheet, turning on the square wave output * increases the current drain on the backup battery from about - * 600 nA to 2uA. + * 600 nA to 2uA. Define CFG_RTC_DS1337_NOOSC if you wish to turn + * off the OSC output. */ +#ifdef CFG_RTC_DS1337_NOOSC + #define RTC_DS1337_RESET_VAL \ + (RTC_CTL_BIT_INTCN | RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS2) +#else + #define RTC_DS1337_RESET_VAL (RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS2) +#endif void rtc_reset (void) { - rtc_write (RTC_CTL_REG_ADDR, RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS2); + rtc_write (RTC_CTL_REG_ADDR, RTC_DS1337_RESET_VAL); } -- cgit From 5b5eb9ca5b778f763bcf332697b35cc1e747626e Mon Sep 17 00:00:00 2001 From: Wolfgang Denk Date: Wed, 26 Mar 2008 15:38:47 +0100 Subject: Coding style cleanup. Signed-off-by: Wolfgang Denk --- drivers/rtc/ds1337.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/ds1337.c b/drivers/rtc/ds1337.c index 69ab2bf9db..e908749ef8 100644 --- a/drivers/rtc/ds1337.c +++ b/drivers/rtc/ds1337.c @@ -1,5 +1,5 @@ /* - * (C) Copyright 2001, 2002 + * (C) Copyright 2001-2008 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * Keith Outwater, keith_outwater@mvis.com` * @@ -60,19 +60,19 @@ /* * RTC control register bits */ -#define RTC_CTL_BIT_A1IE 0x1 /* Alarm 1 interrupt enable */ -#define RTC_CTL_BIT_A2IE 0x2 /* Alarm 2 interrupt enable */ -#define RTC_CTL_BIT_INTCN 0x4 /* Interrupt control */ -#define RTC_CTL_BIT_RS1 0x8 /* Rate select 1 */ -#define RTC_CTL_BIT_RS2 0x10 /* Rate select 2 */ -#define RTC_CTL_BIT_DOSC 0x80 /* Disable Oscillator */ +#define RTC_CTL_BIT_A1IE 0x1 /* Alarm 1 interrupt enable */ +#define RTC_CTL_BIT_A2IE 0x2 /* Alarm 2 interrupt enable */ +#define RTC_CTL_BIT_INTCN 0x4 /* Interrupt control */ +#define RTC_CTL_BIT_RS1 0x8 /* Rate select 1 */ +#define RTC_CTL_BIT_RS2 0x10 /* Rate select 2 */ +#define RTC_CTL_BIT_DOSC 0x80 /* Disable Oscillator */ /* * RTC status register bits */ -#define RTC_STAT_BIT_A1F 0x1 /* Alarm 1 flag */ -#define RTC_STAT_BIT_A2F 0x2 /* Alarm 2 flag */ -#define RTC_STAT_BIT_OSF 0x80 /* Oscillator stop flag */ +#define RTC_STAT_BIT_A1F 0x1 /* Alarm 1 flag */ +#define RTC_STAT_BIT_A2F 0x2 /* Alarm 2 flag */ +#define RTC_STAT_BIT_OSF 0x80 /* Oscillator stop flag */ static uchar rtc_read (uchar reg); @@ -163,7 +163,7 @@ void rtc_set (struct rtc_time *tmp) */ #ifdef CFG_RTC_DS1337_NOOSC #define RTC_DS1337_RESET_VAL \ - (RTC_CTL_BIT_INTCN | RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS2) + (RTC_CTL_BIT_INTCN | RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS2) #else #define RTC_DS1337_RESET_VAL (RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS2) #endif -- cgit From 9eef62804d9695425b24c87b46a61a7fa74afee0 Mon Sep 17 00:00:00 2001 From: Dave Liu Date: Wed, 26 Mar 2008 22:47:06 +0800 Subject: ata: merge the ata_piix driver move the cmd_sata.c from common/ to drivers/ata_piix.c, the cmd_sata.c have some part of ata_piix controller drivers. consolidate the driver to have better framework. Signed-off-by: Dave Liu --- drivers/block/ata_piix.c | 672 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 671 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/ata_piix.c b/drivers/block/ata_piix.c index 42456d7be3..806ec1a3fc 100644 --- a/drivers/block/ata_piix.c +++ b/drivers/block/ata_piix.c @@ -26,10 +26,12 @@ */ #include +#include #include #include #include #include +#include #include #include @@ -37,9 +39,9 @@ #define DEBUG_SATA 0 /*For debug prints set DEBUG_SATA to 1 */ +#define SATA_DECL #define DRV_DECL /*For file specific declarations */ #include -#undef DRV_DECL /*Macros realted to PCI*/ #define PCI_SATA_BUS 0x00 @@ -213,4 +215,672 @@ init_sata (void) } return 0; } + +static u8 __inline__ +sata_inb (unsigned long ioaddr) +{ + return inb (ioaddr); +} + +static void __inline__ +sata_outb (unsigned char val, unsigned long ioaddr) +{ + outb (val, ioaddr); +} + +static void +output_data (struct sata_ioports *ioaddr, ulong * sect_buf, int words) +{ + outsw (ioaddr->data_addr, sect_buf, words << 1); +} + +static int +input_data (struct sata_ioports *ioaddr, ulong * sect_buf, int words) +{ + insw (ioaddr->data_addr, sect_buf, words << 1); + return 0; +} + +static void +sata_cpy (unsigned char *dst, unsigned char *src, unsigned int len) +{ + unsigned char *end, *last; + + last = dst; + end = src + len - 1; + + /* reserve space for '\0' */ + if (len < 2) + goto OUT; + + /* skip leading white space */ + while ((*src) && (src < end) && (*src == ' ')) + ++src; + + /* copy string, omitting trailing white space */ + while ((*src) && (src < end)) { + *dst++ = *src; + if (*src++ != ' ') + last = dst; + } + OUT: + *last = '\0'; +} + +int +sata_bus_softreset (int num) +{ + u8 dev = 0, status = 0, i; + + port[num].dev_mask = 0; + + for (i = 0; i < CFG_SATA_DEVS_PER_BUS; i++) { + if (!(sata_devchk (&port[num].ioaddr, i))) { + PRINTF ("dev_chk failed for dev#%d\n", i); + } else { + port[num].dev_mask |= (1 << i); + PRINTF ("dev_chk passed for dev#%d\n", i); + } + } + + if (!(port[num].dev_mask)) { + printf ("no devices on port%d\n", num); + return 1; + } + + dev_select (&port[num].ioaddr, dev); + + port[num].ctl_reg = 0x08; /*Default value of control reg */ + sata_outb (port[num].ctl_reg, port[num].ioaddr.ctl_addr); + udelay (10); + sata_outb (port[num].ctl_reg | ATA_SRST, port[num].ioaddr.ctl_addr); + udelay (10); + sata_outb (port[num].ctl_reg, port[num].ioaddr.ctl_addr); + + /* spec mandates ">= 2ms" before checking status. + * We wait 150ms, because that was the magic delay used for + * ATAPI devices in Hale Landis's ATADRVR, for the period of time + * between when the ATA command register is written, and then + * status is checked. Because waiting for "a while" before + * checking status is fine, post SRST, we perform this magic + * delay here as well. + */ + msleep (150); + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 300); + while ((status & ATA_BUSY)) { + msleep (100); + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 3); + } + + if (status & ATA_BUSY) + printf ("ata%u is slow to respond,plz be patient\n", port); + + while ((status & ATA_BUSY)) { + msleep (100); + status = sata_chk_status (&port[num].ioaddr); + } + + if (status & ATA_BUSY) { + printf ("ata%u failed to respond : ", port); + printf ("bus reset failed\n"); + return 1; + } + return 0; +} + +void +sata_identify (int num, int dev) +{ + u8 cmd = 0, status = 0, devno = num * CFG_SATA_DEVS_PER_BUS + dev; + u16 iobuf[ATA_SECT_SIZE]; + u64 n_sectors = 0; + u8 mask = 0; + + memset (iobuf, 0, sizeof (iobuf)); + hd_driveid_t *iop = (hd_driveid_t *) iobuf; + + if (dev == 0) + mask = 0x01; + else + mask = 0x02; + + if (!(port[num].dev_mask & mask)) { + printf ("dev%d is not present on port#%d\n", dev, num); + return; + } + + printf ("port=%d dev=%d\n", num, dev); + + dev_select (&port[num].ioaddr, dev); + + status = 0; + cmd = ATA_CMD_IDENT; /*Device Identify Command */ + sata_outb (cmd, port[num].ioaddr.command_addr); + sata_inb (port[num].ioaddr.altstatus_addr); + udelay (10); + + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 1000); + if (status & ATA_ERR) { + printf ("\ndevice not responding\n"); + port[num].dev_mask &= ~mask; + return; + } + + input_data (&port[num].ioaddr, (ulong *) iobuf, ATA_SECTORWORDS); + + PRINTF ("\nata%u: dev %u cfg 49:%04x 82:%04x 83:%04x 84:%04x85:%04x" + "86:%04x" "87:%04x 88:%04x\n", num, dev, iobuf[49], + iobuf[82], iobuf[83], iobuf[84], iobuf[85], iobuf[86], + iobuf[87], iobuf[88]); + + /* we require LBA and DMA support (bits 8 & 9 of word 49) */ + if (!ata_id_has_dma (iobuf) || !ata_id_has_lba (iobuf)) { + PRINTF ("ata%u: no dma/lba\n", num); + } + ata_dump_id (iobuf); + + if (ata_id_has_lba48 (iobuf)) { + n_sectors = ata_id_u64 (iobuf, 100); + } else { + n_sectors = ata_id_u32 (iobuf, 60); + } + PRINTF ("no. of sectors %u\n", ata_id_u64 (iobuf, 100)); + PRINTF ("no. of sectors %u\n", ata_id_u32 (iobuf, 60)); + + if (n_sectors == 0) { + port[num].dev_mask &= ~mask; + return; + } + + sata_cpy (sata_dev_desc[devno].revision, iop->fw_rev, + sizeof (sata_dev_desc[devno].revision)); + sata_cpy (sata_dev_desc[devno].vendor, iop->model, + sizeof (sata_dev_desc[devno].vendor)); + sata_cpy (sata_dev_desc[devno].product, iop->serial_no, + sizeof (sata_dev_desc[devno].product)); + strswab (sata_dev_desc[devno].revision); + strswab (sata_dev_desc[devno].vendor); + + if ((iop->config & 0x0080) == 0x0080) { + sata_dev_desc[devno].removable = 1; + } else { + sata_dev_desc[devno].removable = 0; + } + + sata_dev_desc[devno].lba = iop->lba_capacity; + PRINTF ("lba=0x%x", sata_dev_desc[devno].lba); + +#ifdef CONFIG_LBA48 + if (iop->command_set_2 & 0x0400) { + sata_dev_desc[devno].lba48 = 1; + lba = (unsigned long long) iop->lba48_capacity[0] | + ((unsigned long long) iop->lba48_capacity[1] << 16) | + ((unsigned long long) iop->lba48_capacity[2] << 32) | + ((unsigned long long) iop->lba48_capacity[3] << 48); + } else { + sata_dev_desc[devno].lba48 = 0; + } +#endif + + /* assuming HD */ + sata_dev_desc[devno].type = DEV_TYPE_HARDDISK; + sata_dev_desc[devno].blksz = ATA_BLOCKSIZE; + sata_dev_desc[devno].lun = 0; /* just to fill something in... */ +} + +void +set_Feature_cmd (int num, int dev) +{ + u8 mask = 0x00, status = 0; + + if (dev == 0) + mask = 0x01; + else + mask = 0x02; + + if (!(port[num].dev_mask & mask)) { + PRINTF ("dev%d is not present on port#%d\n", dev, num); + return; + } + + dev_select (&port[num].ioaddr, dev); + + sata_outb (SETFEATURES_XFER, port[num].ioaddr.feature_addr); + sata_outb (XFER_PIO_4, port[num].ioaddr.nsect_addr); + sata_outb (0, port[num].ioaddr.lbal_addr); + sata_outb (0, port[num].ioaddr.lbam_addr); + sata_outb (0, port[num].ioaddr.lbah_addr); + + sata_outb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); + sata_outb (ATA_CMD_SETF, port[num].ioaddr.command_addr); + + udelay (50); + msleep (150); + + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 5000); + if ((status & (ATA_STAT_BUSY | ATA_STAT_ERR))) { + printf ("Error : status 0x%02x\n", status); + port[num].dev_mask &= ~mask; + } +} + +void +sata_port (struct sata_ioports *ioport) +{ + ioport->data_addr = ioport->cmd_addr + ATA_REG_DATA; + ioport->error_addr = ioport->cmd_addr + ATA_REG_ERR; + ioport->feature_addr = ioport->cmd_addr + ATA_REG_FEATURE; + ioport->nsect_addr = ioport->cmd_addr + ATA_REG_NSECT; + ioport->lbal_addr = ioport->cmd_addr + ATA_REG_LBAL; + ioport->lbam_addr = ioport->cmd_addr + ATA_REG_LBAM; + ioport->lbah_addr = ioport->cmd_addr + ATA_REG_LBAH; + ioport->device_addr = ioport->cmd_addr + ATA_REG_DEVICE; + ioport->status_addr = ioport->cmd_addr + ATA_REG_STATUS; + ioport->command_addr = ioport->cmd_addr + ATA_REG_CMD; +} + +int +sata_devchk (struct sata_ioports *ioaddr, int dev) +{ + u8 nsect, lbal; + + dev_select (ioaddr, dev); + + sata_outb (0x55, ioaddr->nsect_addr); + sata_outb (0xaa, ioaddr->lbal_addr); + + sata_outb (0xaa, ioaddr->nsect_addr); + sata_outb (0x55, ioaddr->lbal_addr); + + sata_outb (0x55, ioaddr->nsect_addr); + sata_outb (0xaa, ioaddr->lbal_addr); + + nsect = sata_inb (ioaddr->nsect_addr); + lbal = sata_inb (ioaddr->lbal_addr); + + if ((nsect == 0x55) && (lbal == 0xaa)) + return 1; /* we found a device */ + else + return 0; /* nothing found */ +} + +void +dev_select (struct sata_ioports *ioaddr, int dev) +{ + u8 tmp = 0; + + if (dev == 0) + tmp = ATA_DEVICE_OBS; + else + tmp = ATA_DEVICE_OBS | ATA_DEV1; + + sata_outb (tmp, ioaddr->device_addr); + sata_inb (ioaddr->altstatus_addr); + udelay (5); +} + +u8 +sata_busy_wait (struct sata_ioports *ioaddr, int bits, unsigned int max) +{ + u8 status; + + do { + udelay (1000); + status = sata_chk_status (ioaddr); + max--; + } while ((status & bits) && (max > 0)); + + return status; +} + +u8 +sata_chk_status (struct sata_ioports * ioaddr) +{ + return sata_inb (ioaddr->status_addr); +} + +void +msleep (int count) +{ + int i; + + for (i = 0; i < count; i++) + udelay (1000); +} + +ulong +sata_read (int device, ulong blknr,lbaint_t blkcnt, void * buff) +{ + ulong n = 0, *buffer = (ulong *)buff; + u8 dev = 0, num = 0, mask = 0, status = 0; + +#ifdef CONFIG_LBA48 + unsigned char lba48 = 0; + + if (blknr & 0x0000fffff0000000) { + if (!sata_dev_desc[devno].lba48) { + printf ("Drive doesn't support 48-bit addressing\n"); + return 0; + } + /* more than 28 bits used, use 48bit mode */ + lba48 = 1; + } +#endif + /*Port Number */ + num = device / CFG_SATA_DEVS_PER_BUS; + /*dev on the port */ + if (device >= CFG_SATA_DEVS_PER_BUS) + dev = device - CFG_SATA_DEVS_PER_BUS; + else + dev = device; + + if (dev == 0) + mask = 0x01; + else + mask = 0x02; + + if (!(port[num].dev_mask & mask)) { + printf ("dev%d is not present on port#%d\n", dev, num); + return 0; + } + + /* Select device */ + dev_select (&port[num].ioaddr, dev); + + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500); + if (status & ATA_BUSY) { + printf ("ata%u failed to respond\n", port[num].port_no); + return n; + } + while (blkcnt-- > 0) { + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500); + if (status & ATA_BUSY) { + printf ("ata%u failed to respond\n", 0); + return n; + } +#ifdef CONFIG_LBA48 + if (lba48) { + /* write high bits */ + sata_outb (0, port[num].ioaddr.nsect_addr); + sata_outb ((blknr >> 24) & 0xFF, + port[num].ioaddr.lbal_addr); + sata_outb ((blknr >> 32) & 0xFF, + port[num].ioaddr.lbam_addr); + sata_outb ((blknr >> 40) & 0xFF, + port[num].ioaddr.lbah_addr); + } +#endif + sata_outb (1, port[num].ioaddr.nsect_addr); + sata_outb (((blknr) >> 0) & 0xFF, + port[num].ioaddr.lbal_addr); + sata_outb ((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr); + sata_outb ((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr); + +#ifdef CONFIG_LBA48 + if (lba48) { + sata_outb (ATA_LBA, port[num].ioaddr.device_addr); + sata_outb (ATA_CMD_READ_EXT, + port[num].ioaddr.command_addr); + } else +#endif + { + sata_outb (ATA_LBA | ((blknr >> 24) & 0xF), + port[num].ioaddr.device_addr); + sata_outb (ATA_CMD_READ, + port[num].ioaddr.command_addr); + } + + msleep (50); + /*may take up to 4 sec */ + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 4000); + + if ((status & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) + != ATA_STAT_DRQ) { + u8 err = 0; + + printf ("Error no DRQ dev %d blk %ld: sts 0x%02x\n", + device, (ulong) blknr, status); + err = sata_inb (port[num].ioaddr.error_addr); + printf ("Error reg = 0x%x\n", err); + return (n); + } + input_data (&port[num].ioaddr, buffer, ATA_SECTORWORDS); + sata_inb (port[num].ioaddr.altstatus_addr); + udelay (50); + + ++n; + ++blknr; + buffer += ATA_SECTORWORDS; + } + return n; +} + +ulong +sata_write (int device, ulong blknr,lbaint_t blkcnt, void * buff) +{ + ulong n = 0, *buffer = (ulong *)buff; + unsigned char status = 0, num = 0, dev = 0, mask = 0; + +#ifdef CONFIG_LBA48 + unsigned char lba48 = 0; + + if (blknr & 0x0000fffff0000000) { + if (!sata_dev_desc[devno].lba48) { + printf ("Drive doesn't support 48-bit addressing\n"); + return 0; + } + /* more than 28 bits used, use 48bit mode */ + lba48 = 1; + } +#endif + /*Port Number */ + num = device / CFG_SATA_DEVS_PER_BUS; + /*dev on the Port */ + if (device >= CFG_SATA_DEVS_PER_BUS) + dev = device - CFG_SATA_DEVS_PER_BUS; + else + dev = device; + + if (dev == 0) + mask = 0x01; + else + mask = 0x02; + + /* Select device */ + dev_select (&port[num].ioaddr, dev); + + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500); + if (status & ATA_BUSY) { + printf ("ata%u failed to respond\n", port[num].port_no); + return n; + } + + while (blkcnt-- > 0) { + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500); + if (status & ATA_BUSY) { + printf ("ata%u failed to respond\n", + port[num].port_no); + return n; + } +#ifdef CONFIG_LBA48 + if (lba48) { + /* write high bits */ + sata_outb (0, port[num].ioaddr.nsect_addr); + sata_outb ((blknr >> 24) & 0xFF, + port[num].ioaddr.lbal_addr); + sata_outb ((blknr >> 32) & 0xFF, + port[num].ioaddr.lbam_addr); + sata_outb ((blknr >> 40) & 0xFF, + port[num].ioaddr.lbah_addr); + } +#endif + sata_outb (1, port[num].ioaddr.nsect_addr); + sata_outb ((blknr >> 0) & 0xFF, port[num].ioaddr.lbal_addr); + sata_outb ((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr); + sata_outb ((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr); +#ifdef CONFIG_LBA48 + if (lba48) { + sata_outb (ATA_LBA, port[num].ioaddr.device_addr); + sata_outb (ATA_CMD_WRITE_EXT, + port[num].ioaddr.command_addr); + } else +#endif + { + sata_outb (ATA_LBA | ((blknr >> 24) & 0xF), + port[num].ioaddr.device_addr); + sata_outb (ATA_CMD_WRITE, + port[num].ioaddr.command_addr); + } + + msleep (50); + /*may take up to 4 sec */ + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 4000); + if ((status & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) + != ATA_STAT_DRQ) { + printf ("Error no DRQ dev %d blk %ld: sts 0x%02x\n", + device, (ulong) blknr, status); + return (n); + } + + output_data (&port[num].ioaddr, buffer, ATA_SECTORWORDS); + sata_inb (port[num].ioaddr.altstatus_addr); + udelay (50); + + ++n; + ++blknr; + buffer += ATA_SECTORWORDS; + } + return n; +} + +block_dev_desc_t *sata_get_dev (int dev); + +block_dev_desc_t * +sata_get_dev (int dev) +{ + return ((block_dev_desc_t *) & sata_dev_desc[dev]); +} + +int +do_sata (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + + switch (argc) { + case 0: + case 1: + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + case 2: + if (strncmp (argv[1], "init", 4) == 0) { + int rcode = 0; + + rcode = init_sata (); + if (rcode) + printf ("Sata initialization Failed\n"); + return rcode; + } else if (strncmp (argv[1], "inf", 3) == 0) { + int i; + + putc ('\n'); + for (i = 0; i < CFG_SATA_MAXDEVICES; ++i) { + /*List only known devices */ + if (sata_dev_desc[i].type == + DEV_TYPE_UNKNOWN) + continue; + printf ("sata dev %d: ", i); + dev_print (&sata_dev_desc[i]); + } + return 0; + } + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + case 3: + if (strcmp (argv[1], "dev") == 0) { + int dev = (int) simple_strtoul (argv[2], NULL, 10); + + if (dev >= CFG_SATA_MAXDEVICES) { + printf ("\nSata dev %d not available\n", + dev); + return 1; + } + printf ("\nSATA dev %d: ", dev); + dev_print (&sata_dev_desc[dev]); + if (sata_dev_desc[dev].type == DEV_TYPE_UNKNOWN) + return 1; + curr_dev = dev; + return 0; + } else if (strcmp (argv[1], "part") == 0) { + int dev = (int) simple_strtoul (argv[2], NULL, 10); + + if (dev >= CFG_SATA_MAXDEVICES) { + printf ("\nSata dev %d not available\n", + dev); + return 1; + } + PRINTF ("\nSATA dev %d: ", dev); + if (sata_dev_desc[dev].part_type != + PART_TYPE_UNKNOWN) { + print_part (&sata_dev_desc[dev]); + } else { + printf ("\nSata dev %d partition type " + "unknown\n", dev); + return 1; + } + return 0; + } + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + default: + if (argc < 5) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + if (strcmp (argv[1], "read") == 0) { + ulong addr = simple_strtoul (argv[2], NULL, 16); + ulong cnt = simple_strtoul (argv[4], NULL, 16); + ulong n; + lbaint_t blk = simple_strtoul (argv[3], NULL, 16); + + memset ((int *) addr, 0, cnt * 512); + printf ("\nSATA read: dev %d blk # %ld," + "count %ld ... ", curr_dev, blk, cnt); + n = sata_read (curr_dev, blk, cnt, (ulong *) addr); + /* flush cache after read */ + flush_cache (addr, cnt * 512); + printf ("%ld blocks read: %s\n", n, + (n == cnt) ? "OK" : "ERR"); + if (n == cnt) + return 1; + else + return 0; + } else if (strcmp (argv[1], "write") == 0) { + ulong addr = simple_strtoul (argv[2], NULL, 16); + ulong cnt = simple_strtoul (argv[4], NULL, 16); + ulong n; + lbaint_t blk = simple_strtoul (argv[3], NULL, 16); + + printf ("\nSata write: dev %d blk # %ld," + "count %ld ... ", curr_dev, blk, cnt); + n = sata_write (curr_dev, blk, cnt, (ulong *) addr); + printf ("%ld blocks written: %s\n", n, + (n == cnt) ? "OK" : "ERR"); + if (n == cnt) + return 1; + else + return 0; + } else { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + } /*End OF SWITCH */ +} + +U_BOOT_CMD (sata, 5, 1, do_sata, + "sata init\n" + "sata info\n" + "sata part device\n" + "sata dev device\n" + "sata read addr blk# cnt\n" + "sata write addr blk# cnt\n", "cmd for init,rw and dev-info\n"); + #endif -- cgit From 83c7f470a4ce94f33600f11ae85ce4dcf00aa90c Mon Sep 17 00:00:00 2001 From: Dave Liu Date: Wed, 26 Mar 2008 22:48:18 +0800 Subject: ata: merge the header of ata_piix driver move the sata.h from include/ to drivers/block/ata_piix.h Signed-off-by: Dave Liu --- drivers/block/ata_piix.c | 2 +- drivers/block/ata_piix.h | 92 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 drivers/block/ata_piix.h (limited to 'drivers') diff --git a/drivers/block/ata_piix.c b/drivers/block/ata_piix.c index 806ec1a3fc..9ba69189a5 100644 --- a/drivers/block/ata_piix.c +++ b/drivers/block/ata_piix.c @@ -41,7 +41,7 @@ #define SATA_DECL #define DRV_DECL /*For file specific declarations */ -#include +#include "ata_piix.h" /*Macros realted to PCI*/ #define PCI_SATA_BUS 0x00 diff --git a/drivers/block/ata_piix.h b/drivers/block/ata_piix.h new file mode 100644 index 0000000000..bb1acb3878 --- /dev/null +++ b/drivers/block/ata_piix.h @@ -0,0 +1,92 @@ + +#if (DEBUG_SATA) +#define PRINTF(fmt,args...) printf (fmt ,##args) +#else +#define PRINTF(fmt,args...) +#endif + +struct sata_ioports { + unsigned long cmd_addr; + unsigned long data_addr; + unsigned long error_addr; + unsigned long feature_addr; + unsigned long nsect_addr; + unsigned long lbal_addr; + unsigned long lbam_addr; + unsigned long lbah_addr; + unsigned long device_addr; + unsigned long status_addr; + unsigned long command_addr; + unsigned long altstatus_addr; + unsigned long ctl_addr; + unsigned long bmdma_addr; + unsigned long scr_addr; +}; + +struct sata_port { + unsigned char port_no; /* primary=0, secondary=1 */ + struct sata_ioports ioaddr; /* ATA cmd/ctl/dma reg blks */ + unsigned char ctl_reg; + unsigned char last_ctl; + unsigned char port_state; /* 1-port is available and */ + /* 0-port is not available */ + unsigned char dev_mask; +}; + +/***********SATA LIBRARY SPECIFIC DEFINITIONS AND DECLARATIONS**************/ +#ifdef SATA_DECL /*SATA library specific declarations */ +#define ata_id_has_lba48(id) ((id)[83] & (1 << 10)) +#define ata_id_has_lba(id) ((id)[49] & (1 << 9)) +#define ata_id_has_dma(id) ((id)[49] & (1 << 8)) +#define ata_id_u32(id,n) \ + (((u32) (id)[(n) + 1] << 16) | ((u32) (id)[(n)])) +#define ata_id_u64(id,n) \ + (((u64) (id)[(n) + 3] << 48) | \ + ((u64) (id)[(n) + 2] << 32) | \ + ((u64) (id)[(n) + 1] << 16) | \ + ((u64) (id)[(n) + 0]) ) +#endif + +#ifdef SATA_DECL /*SATA library specific declarations */ +static inline void +ata_dump_id (u16 * id) +{ + PRINTF ("49==0x%04x " + "53==0x%04x " + "63==0x%04x " + "64==0x%04x " + "75==0x%04x \n", id[49], id[53], id[63], id[64], id[75]); + PRINTF ("80==0x%04x " + "81==0x%04x " + "82==0x%04x " + "83==0x%04x " + "84==0x%04x \n", id[80], id[81], id[82], id[83], id[84]); + PRINTF ("88==0x%04x " "93==0x%04x\n", id[88], id[93]); +} +#endif + +#ifdef SATA_DECL /*SATA library specific declarations */ +int sata_bus_softreset (int num); +void sata_identify (int num, int dev); +void sata_port (struct sata_ioports *ioport); +void set_Feature_cmd (int num, int dev); +int sata_devchk (struct sata_ioports *ioaddr, int dev); +void dev_select (struct sata_ioports *ioaddr, int dev); +u8 sata_busy_wait (struct sata_ioports *ioaddr, int bits, unsigned int max); +u8 sata_chk_status (struct sata_ioports *ioaddr); +ulong sata_read (int device, ulong blknr,lbaint_t blkcnt, void * buffer); +ulong sata_write (int device,ulong blknr, lbaint_t blkcnt, void * buffer); +void msleep (int count); +#endif + +/************DRIVER SPECIFIC DEFINITIONS AND DECLARATIONS**************/ + +#ifdef DRV_DECL /*Driver specific declaration */ +int init_sata (void); +#endif + +#ifdef DRV_DECL /*Defines Driver Specific variables */ +struct sata_port port[CFG_SATA_MAXBUS]; +block_dev_desc_t sata_dev_desc[CFG_SATA_MAXDEVICES]; +int curr_dev = -1; +#endif -- cgit From 8e9bb43429e50df55fa41932cbe65841ff579220 Mon Sep 17 00:00:00 2001 From: Dave Liu Date: Wed, 26 Mar 2008 22:50:45 +0800 Subject: ata: make the ata_piix driver using new SATA framework original ata_piix driver is using IDE framework, not real SATA framework. For now, the ata_piix driver is only used by x86 sc520_cdp board. This patch makes the ata_piix driver use the new SATA framework, so - remove the duplicated command stuff - remove the CONFIG_CMD_IDE define in the sc520_cdp.h - add the CONFIG_CMD_SATA define to sc520_cdp.h Signed-off-by: Dave Liu --- drivers/block/ata_piix.c | 152 ++++------------------------------------------- drivers/block/ata_piix.h | 4 +- 2 files changed, 14 insertions(+), 142 deletions(-) (limited to 'drivers') diff --git a/drivers/block/ata_piix.c b/drivers/block/ata_piix.c index 9ba69189a5..441a4dcd8d 100644 --- a/drivers/block/ata_piix.c +++ b/drivers/block/ata_piix.c @@ -37,6 +37,9 @@ #ifdef CFG_ATA_PIIX /*ata_piix driver */ +extern block_dev_desc_t sata_dev_desc[CFG_SATA_MAX_DEVICE]; +extern int curr_device; + #define DEBUG_SATA 0 /*For debug prints set DEBUG_SATA to 1 */ #define SATA_DECL @@ -144,19 +147,15 @@ sata_bus_probe (int port_no) } int -init_sata (void) +init_sata (int dev) { + static int done = 0; u8 i, rv = 0; - for (i = 0; i < CFG_SATA_MAXDEVICES; i++) { - sata_dev_desc[i].type = DEV_TYPE_UNKNOWN; - sata_dev_desc[i].if_type = IF_TYPE_IDE; - sata_dev_desc[i].dev = i; - sata_dev_desc[i].part_type = PART_TYPE_UNKNOWN; - sata_dev_desc[i].blksz = 0; - sata_dev_desc[i].lba = 0; - sata_dev_desc[i].block_read = sata_read; - } + if (!done) + done = 1; + else + return 0; rv = pci_sata_init (); if (rv == 1) { @@ -207,8 +206,8 @@ init_sata (void) dev_print (&sata_dev_desc[devno]); /* initialize partition type */ init_part (&sata_dev_desc[devno]); - if (curr_dev < 0) - curr_dev = + if (curr_device < 0) + curr_device = i * CFG_SATA_DEVS_PER_BUS + j; } } @@ -753,134 +752,9 @@ sata_write (int device, ulong blknr,lbaint_t blkcnt, void * buff) return n; } -block_dev_desc_t *sata_get_dev (int dev); - -block_dev_desc_t * -sata_get_dev (int dev) +int scan_sata(int dev) { - return ((block_dev_desc_t *) & sata_dev_desc[dev]); -} - -int -do_sata (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) -{ - - switch (argc) { - case 0: - case 1: - printf ("Usage:\n%s\n", cmdtp->usage); - return 1; - case 2: - if (strncmp (argv[1], "init", 4) == 0) { - int rcode = 0; - - rcode = init_sata (); - if (rcode) - printf ("Sata initialization Failed\n"); - return rcode; - } else if (strncmp (argv[1], "inf", 3) == 0) { - int i; - - putc ('\n'); - for (i = 0; i < CFG_SATA_MAXDEVICES; ++i) { - /*List only known devices */ - if (sata_dev_desc[i].type == - DEV_TYPE_UNKNOWN) - continue; - printf ("sata dev %d: ", i); - dev_print (&sata_dev_desc[i]); - } - return 0; - } - printf ("Usage:\n%s\n", cmdtp->usage); - return 1; - case 3: - if (strcmp (argv[1], "dev") == 0) { - int dev = (int) simple_strtoul (argv[2], NULL, 10); - - if (dev >= CFG_SATA_MAXDEVICES) { - printf ("\nSata dev %d not available\n", - dev); - return 1; - } - printf ("\nSATA dev %d: ", dev); - dev_print (&sata_dev_desc[dev]); - if (sata_dev_desc[dev].type == DEV_TYPE_UNKNOWN) - return 1; - curr_dev = dev; - return 0; - } else if (strcmp (argv[1], "part") == 0) { - int dev = (int) simple_strtoul (argv[2], NULL, 10); - - if (dev >= CFG_SATA_MAXDEVICES) { - printf ("\nSata dev %d not available\n", - dev); - return 1; - } - PRINTF ("\nSATA dev %d: ", dev); - if (sata_dev_desc[dev].part_type != - PART_TYPE_UNKNOWN) { - print_part (&sata_dev_desc[dev]); - } else { - printf ("\nSata dev %d partition type " - "unknown\n", dev); - return 1; - } - return 0; - } - printf ("Usage:\n%s\n", cmdtp->usage); - return 1; - default: - if (argc < 5) { - printf ("Usage:\n%s\n", cmdtp->usage); - return 1; - } - if (strcmp (argv[1], "read") == 0) { - ulong addr = simple_strtoul (argv[2], NULL, 16); - ulong cnt = simple_strtoul (argv[4], NULL, 16); - ulong n; - lbaint_t blk = simple_strtoul (argv[3], NULL, 16); - - memset ((int *) addr, 0, cnt * 512); - printf ("\nSATA read: dev %d blk # %ld," - "count %ld ... ", curr_dev, blk, cnt); - n = sata_read (curr_dev, blk, cnt, (ulong *) addr); - /* flush cache after read */ - flush_cache (addr, cnt * 512); - printf ("%ld blocks read: %s\n", n, - (n == cnt) ? "OK" : "ERR"); - if (n == cnt) - return 1; - else - return 0; - } else if (strcmp (argv[1], "write") == 0) { - ulong addr = simple_strtoul (argv[2], NULL, 16); - ulong cnt = simple_strtoul (argv[4], NULL, 16); - ulong n; - lbaint_t blk = simple_strtoul (argv[3], NULL, 16); - - printf ("\nSata write: dev %d blk # %ld," - "count %ld ... ", curr_dev, blk, cnt); - n = sata_write (curr_dev, blk, cnt, (ulong *) addr); - printf ("%ld blocks written: %s\n", n, - (n == cnt) ? "OK" : "ERR"); - if (n == cnt) - return 1; - else - return 0; - } else { - printf ("Usage:\n%s\n", cmdtp->usage); - return 1; - } - } /*End OF SWITCH */ + return 0; } -U_BOOT_CMD (sata, 5, 1, do_sata, - "sata init\n" - "sata info\n" - "sata part device\n" - "sata dev device\n" - "sata read addr blk# cnt\n" - "sata write addr blk# cnt\n", "cmd for init,rw and dev-info\n"); - #endif diff --git a/drivers/block/ata_piix.h b/drivers/block/ata_piix.h index bb1acb3878..ed2e4d57d6 100644 --- a/drivers/block/ata_piix.h +++ b/drivers/block/ata_piix.h @@ -82,11 +82,9 @@ void msleep (int count); /************DRIVER SPECIFIC DEFINITIONS AND DECLARATIONS**************/ #ifdef DRV_DECL /*Driver specific declaration */ -int init_sata (void); +int init_sata (int dev); #endif #ifdef DRV_DECL /*Defines Driver Specific variables */ struct sata_port port[CFG_SATA_MAXBUS]; -block_dev_desc_t sata_dev_desc[CFG_SATA_MAXDEVICES]; -int curr_dev = -1; #endif -- cgit From ffc664e80dfb2e17de0df5ad39e91a02e9c361bc Mon Sep 17 00:00:00 2001 From: Dave Liu Date: Wed, 26 Mar 2008 22:51:44 +0800 Subject: ata: add the libata support add simple libata support in u-boot Signed-off-by: Dave Liu --- drivers/block/Makefile | 1 + drivers/block/libata.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 drivers/block/libata.c (limited to 'drivers') diff --git a/drivers/block/Makefile b/drivers/block/Makefile index e069969e68..d63ca2d0bf 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -27,6 +27,7 @@ LIB := $(obj)libblock.a COBJS-y += ahci.o COBJS-y += ata_piix.o +COBJS-$(CONFIG_LIBATA) += libata.o COBJS-y += sil680.o COBJS-y += sym53c8xx.o COBJS-y += systemace.o diff --git a/drivers/block/libata.c b/drivers/block/libata.c new file mode 100644 index 0000000000..a0cf90d9a8 --- /dev/null +++ b/drivers/block/libata.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2008 Freescale Semiconductor, Inc. + * Dave Liu + * port from the libata of linux kernel + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include + +u64 ata_id_n_sectors(u16 *id) +{ + if (ata_id_has_lba(id)) { + if (ata_id_has_lba48(id)) + return ata_id_u64(id, ATA_ID_LBA48_SECTORS); + else + return ata_id_u32(id, ATA_ID_LBA_SECTORS); + } else { + return 0; + } +} + +u32 ata_dev_classify(u32 sig) +{ + u8 lbam, lbah; + + lbam = (sig >> 16) & 0xff; + lbah = (sig >> 24) & 0xff; + + if (((lbam == 0) && (lbah == 0)) || + ((lbam == 0x3c) && (lbah == 0xc3))) + return ATA_DEV_ATA; + + if ((lbam == 0x14) && (lbah == 0xeb)) + return ATA_DEV_ATAPI; + + if ((lbam == 0x69) && (lbah == 0x96)) + return ATA_DEV_PMP; + + return ATA_DEV_UNKNOWN; +} + +static void ata_id_string(const u16 *id, unsigned char *s, + unsigned int ofs, unsigned int len) +{ + unsigned int c; + + while (len > 0) { + c = id[ofs] >> 8; + *s = c; + s++; + + c = id[ofs] & 0xff; + *s = c; + s++; + + ofs++; + len -= 2; + } +} + +void ata_id_c_string(const u16 *id, unsigned char *s, + unsigned int ofs, unsigned int len) +{ + unsigned char *p; + + ata_id_string(id, s, ofs, len - 1); + + p = s + strnlen((char *)s, len - 1); + while (p > s && p[-1] == ' ') + p--; + *p = '\0'; +} + +void ata_dump_id(u16 *id) +{ + unsigned char serial[ATA_ID_SERNO_LEN + 1]; + unsigned char firmware[ATA_ID_FW_REV_LEN + 1]; + unsigned char product[ATA_ID_PROD_LEN + 1]; + u64 n_sectors; + + /* Serial number */ + ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); + printf("S/N: %s\n\r", serial); + + /* Firmware version */ + ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); + printf("Firmware version: %s\n\r", firmware); + + /* Product model */ + ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); + printf("Product model number: %s\n\r", product); + + /* Total sectors of device */ + n_sectors = ata_id_n_sectors(id); + printf("Capablity: %d sectors\n\r", n_sectors); + + printf("id[49]: capabilities ==0x%04x\n" + "id[53]: field valid ==0x%04x\n" + "id[63]: mwdma ==0x%04x\n" + "id[64]: pio ==0x%04x\n" + "id[75]: queue depth ==0x%04x\n", + id[49], + id[53], + id[63], + id[64], + id[75]); + + printf("id[76]: sata capablity ==0x%04x\n" + "id[78]: sata features supported ==0x%04x\n" + "id[79]: sata features enable ==0x%04x\n", + id[76], + id[78], + id[79]); + + printf("id[80]: major version ==0x%04x\n" + "id[81]: minor version ==0x%04x\n" + "id[82]: command set supported 1 ==0x%04x\n" + "id[83]: command set supported 2 ==0x%04x\n" + "id[84]: command set extension ==0x%04x\n", + id[80], + id[81], + id[82], + id[83], + id[84]); + printf("id[85]: command set enable 1 ==0x%04x\n" + "id[86]: command set enable 2 ==0x%04x\n" + "id[87]: command set default ==0x%04x\n" + "id[88]: udma ==0x%04x\n" + "id[93]: hardware reset result ==0x%04x\n", + id[85], + id[86], + id[87], + id[88], + id[93]); +} + +void ata_swap_buf_le16(u16 *buf, unsigned int buf_words) +{ + unsigned int i; + + for (i = 0; i < buf_words; i++) + buf[i] = le16_to_cpu(buf[i]); +} -- cgit From fd0b1fe3c388a77e8fe00cdd930ca317a91198d4 Mon Sep 17 00:00:00 2001 From: Dave Liu Date: Wed, 26 Mar 2008 22:55:32 +0800 Subject: drivers: add the support for Freescale SATA controller Add the Freescale on-chip SATA controller driver to u-boot, The SATA controller is used on the 837x and 8315 targets, The driver can be used to load kernel, fs and dtb. The features list: - 1.5/3 Gbps link speed - LBA48, LBA28 support - DMA and FPDMA support - Two ports support Signed-off-by: Dave Liu --- drivers/block/Makefile | 1 + drivers/block/fsl_sata.c | 916 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/block/fsl_sata.h | 374 +++++++++++++++++++ 3 files changed, 1291 insertions(+) create mode 100644 drivers/block/fsl_sata.c create mode 100644 drivers/block/fsl_sata.h (limited to 'drivers') diff --git a/drivers/block/Makefile b/drivers/block/Makefile index d63ca2d0bf..dca3547919 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -27,6 +27,7 @@ LIB := $(obj)libblock.a COBJS-y += ahci.o COBJS-y += ata_piix.o +COBJS-$(CONFIG_FSL_SATA) += fsl_sata.o COBJS-$(CONFIG_LIBATA) += libata.o COBJS-y += sil680.o COBJS-y += sym53c8xx.o diff --git a/drivers/block/fsl_sata.c b/drivers/block/fsl_sata.c new file mode 100644 index 0000000000..7436c4d08b --- /dev/null +++ b/drivers/block/fsl_sata.c @@ -0,0 +1,916 @@ +/* + * Copyright (C) 2008 Freescale Semiconductor, Inc. + * Dave Liu + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include "fsl_sata.h" + +extern block_dev_desc_t sata_dev_desc[CFG_SATA_MAX_DEVICE]; + +#ifndef CFG_SATA1_FLAGS + #define CFG_SATA1_FLAGS FLAGS_DMA +#endif +#ifndef CFG_SATA2_FLAGS + #define CFG_SATA2_FLAGS FLAGS_DMA +#endif + +static struct fsl_sata_info fsl_sata_info[] = { +#ifdef CONFIG_SATA1 + {CFG_SATA1, CFG_SATA1_FLAGS}, +#else + {0, 0}, +#endif +#ifdef CONFIG_SATA2 + {CFG_SATA2, CFG_SATA2_FLAGS}, +#else + {0, 0}, +#endif +}; + +static inline void mdelay(unsigned long msec) +{ + unsigned long i; + for (i = 0; i < msec; i++) + udelay(1000); +} + +static inline void sdelay(unsigned long sec) +{ + unsigned long i; + for (i = 0; i < sec; i++) + mdelay(1000); +} + +void dprint_buffer(unsigned char *buf, int len) +{ + int i, j; + + i = 0; + j = 0; + printf("\n\r"); + + for (i = 0; i < len; i++) { + printf("%02x ", *buf++); + j++; + if (j == 16) { + printf("\n\r"); + j = 0; + } + } + printf("\n\r"); +} + +static void fsl_sata_dump_sfis(struct sfis *s) +{ + printf("Status FIS dump:\n\r"); + printf("fis_type: %02x\n\r", s->fis_type); + printf("pm_port_i: %02x\n\r", s->pm_port_i); + printf("status: %02x\n\r", s->status); + printf("error: %02x\n\r", s->error); + printf("lba_low: %02x\n\r", s->lba_low); + printf("lba_mid: %02x\n\r", s->lba_mid); + printf("lba_high: %02x\n\r", s->lba_high); + printf("device: %02x\n\r", s->device); + printf("lba_low_exp: %02x\n\r", s->lba_low_exp); + printf("lba_mid_exp: %02x\n\r", s->lba_mid_exp); + printf("lba_high_exp: %02x\n\r", s->lba_high_exp); + printf("res1: %02x\n\r", s->res1); + printf("sector_count: %02x\n\r", s->sector_count); + printf("sector_count_exp: %02x\n\r", s->sector_count_exp); +} + +static int ata_wait_register(volatile unsigned *addr, u32 mask, + u32 val, u32 timeout_msec) +{ + int i; + u32 temp; + + for (i = 0; (((temp = in_le32(addr)) & mask) != val) + && i < timeout_msec; i++) + mdelay(1); + return (i < timeout_msec) ? 0 : -1; +} + +int init_sata(int dev) +{ + u32 length, align; + cmd_hdr_tbl_t *cmd_hdr; + u32 cda; + u32 val32; + fsl_sata_reg_t *reg; + u32 sig; + int i; + fsl_sata_t *sata; + + if (dev < 0 || dev > (CFG_SATA_MAX_DEVICE - 1)) { + printf("the sata index %d is out of ranges\n\r", dev); + return -1; + } + + /* Allocate SATA device driver struct */ + sata = (fsl_sata_t *)malloc(sizeof(fsl_sata_t)); + if (!sata) { + printf("alloc the sata device struct failed\n\r"); + return -1; + } + /* Zero all of the device driver struct */ + memset((void *)sata, 0, sizeof(fsl_sata_t)); + + /* Save the private struct to block device struct */ + sata_dev_desc[dev].priv = (void *)sata; + + sprintf(sata->name, "SATA%d", dev); + + /* Set the controller register base address to device struct */ + reg = (fsl_sata_reg_t *)(fsl_sata_info[dev].sata_reg_base); + sata->reg_base = reg; + + /* Allocate the command header table, 4 bytes aligned */ + length = sizeof(struct cmd_hdr_tbl); + align = SATA_HC_CMD_HDR_TBL_ALIGN; + sata->cmd_hdr_tbl_offset = (void *)malloc(length + align); + if (!sata) { + printf("alloc the command header failed\n\r"); + return -1; + } + + cmd_hdr = (cmd_hdr_tbl_t *)(((u32)sata->cmd_hdr_tbl_offset + align) + & ~(align - 1)); + sata->cmd_hdr = cmd_hdr; + + /* Zero all of the command header table */ + memset((void *)sata->cmd_hdr_tbl_offset, 0, length + align); + + /* Allocate command descriptor for all command */ + length = sizeof(struct cmd_desc) * SATA_HC_MAX_CMD; + align = SATA_HC_CMD_DESC_ALIGN; + sata->cmd_desc_offset = (void *)malloc(length + align); + if (!sata->cmd_desc_offset) { + printf("alloc the command descriptor failed\n\r"); + return -1; + } + sata->cmd_desc = (cmd_desc_t *)(((u32)sata->cmd_desc_offset + align) + & ~(align - 1)); + /* Zero all of command descriptor */ + memset((void *)sata->cmd_desc_offset, 0, length + align); + + /* Link the command descriptor to command header */ + for (i = 0; i < SATA_HC_MAX_CMD; i++) { + cda = ((u32)sata->cmd_desc + SATA_HC_CMD_DESC_SIZE * i) + & ~(CMD_HDR_CDA_ALIGN - 1); + cmd_hdr->cmd_slot[i].cda = cpu_to_le32(cda); + } + + /* To have safe state, force the controller offline */ + val32 = in_le32(®->hcontrol); + val32 &= ~HCONTROL_ONOFF; + val32 |= HCONTROL_FORCE_OFFLINE; + out_le32(®->hcontrol, val32); + + /* Wait the controller offline */ + ata_wait_register(®->hstatus, HSTATUS_ONOFF, 0, 1000); + + /* Set the command header base address to CHBA register to tell DMA */ + out_le32(®->chba, (u32)cmd_hdr & ~0x3); + + /* Snoop for the command header */ + val32 = in_le32(®->hcontrol); + val32 |= HCONTROL_HDR_SNOOP; + out_le32(®->hcontrol, val32); + + /* Disable all of interrupts */ + val32 = in_le32(®->hcontrol); + val32 &= ~HCONTROL_INT_EN_ALL; + out_le32(®->hcontrol, val32); + + /* Clear all of interrupts */ + val32 = in_le32(®->hstatus); + out_le32(®->hstatus, val32); + + /* Set the ICC, no interrupt coalescing */ + out_le32(®->icc, 0x01000000); + + /* No PM attatched, the SATA device direct connect */ + out_le32(®->cqpmp, 0); + + /* Clear SError register */ + val32 = in_le32(®->serror); + out_le32(®->serror, val32); + + /* Clear CER register */ + val32 = in_le32(®->cer); + out_le32(®->cer, val32); + + /* Clear DER register */ + val32 = in_le32(®->der); + out_le32(®->der, val32); + + /* No device detection or initialization action requested */ + out_le32(®->scontrol, 0x00000300); + + /* Configure the transport layer, default value */ + out_le32(®->transcfg, 0x08000016); + + /* Configure the link layer, default value */ + out_le32(®->linkcfg, 0x0000ff34); + + /* Bring the controller online */ + val32 = in_le32(®->hcontrol); + val32 |= HCONTROL_ONOFF; + out_le32(®->hcontrol, val32); + + mdelay(100); + + /* print sata device name */ + if (!dev) + printf("%s ", sata->name); + else + printf(" %s ", sata->name); + + /* Check PHYRDY */ + val32 = in_le32(®->hstatus); + if (val32 & HSTATUS_PHY_RDY) { + sata->link = 1; + } else { + sata->link = 0; + printf("(No RDY)\n\r"); + return -1; + } + + if (val32 & HSTATUS_SIGNATURE) { + sig = in_le32(®->sig); + debug("Signature updated, the sig =%08x\n\r", sig); + sata->ata_device_type = ata_dev_classify(sig); + } + + /* Check the speed */ + val32 = in_le32(®->sstatus); + if ((val32 & SSTATUS_SPD_MASK) == SSTATUS_SPD_GEN1) + printf("(1.5 Gbps)\n\r"); + else if ((val32 & SSTATUS_SPD_MASK) == SSTATUS_SPD_GEN2) + printf("(3 Gbps)\n\r"); + + return 0; +} + +/* Hardware reset, like Power-on and COMRESET */ +void fsl_sata_hardware_reset(u32 reg_base) +{ + fsl_sata_reg_t *reg = (fsl_sata_reg_t *)reg_base; + u32 scontrol; + + /* Disable the SATA interface and put PHY offline */ + scontrol = in_le32(®->scontrol); + scontrol = (scontrol & 0x0f0) | 0x304; + out_le32(®->scontrol, scontrol); + + /* No speed strict */ + scontrol = in_le32(®->scontrol); + scontrol = scontrol & ~0x0f0; + out_le32(®->scontrol, scontrol); + + /* Issue PHY wake/reset, Hardware_reset_asserted */ + scontrol = in_le32(®->scontrol); + scontrol = (scontrol & 0x0f0) | 0x301; + out_le32(®->scontrol, scontrol); + + mdelay(100); + + /* Resume PHY, COMRESET negated, the device initialize hardware + * and execute diagnostics, send good status-signature to host, + * which is D2H register FIS, and then the device enter idle state. + */ + scontrol = in_le32(®->scontrol); + scontrol = (scontrol & 0x0f0) | 0x300; + out_le32(®->scontrol, scontrol); + + mdelay(100); + return; +} + +static void fsl_sata_dump_regs(fsl_sata_reg_t *reg) +{ + printf("\n\rSATA: %08x\n\r", (u32)reg); + printf("CQR: %08x\n\r", in_le32(®->cqr)); + printf("CAR: %08x\n\r", in_le32(®->car)); + printf("CCR: %08x\n\r", in_le32(®->ccr)); + printf("CER: %08x\n\r", in_le32(®->cer)); + printf("CQR: %08x\n\r", in_le32(®->cqr)); + printf("DER: %08x\n\r", in_le32(®->der)); + printf("CHBA: %08x\n\r", in_le32(®->chba)); + printf("HStatus: %08x\n\r", in_le32(®->hstatus)); + printf("HControl: %08x\n\r", in_le32(®->hcontrol)); + printf("CQPMP: %08x\n\r", in_le32(®->cqpmp)); + printf("SIG: %08x\n\r", in_le32(®->sig)); + printf("ICC: %08x\n\r", in_le32(®->icc)); + printf("SStatus: %08x\n\r", in_le32(®->sstatus)); + printf("SError: %08x\n\r", in_le32(®->serror)); + printf("SControl: %08x\n\r", in_le32(®->scontrol)); + printf("SNotification: %08x\n\r", in_le32(®->snotification)); + printf("TransCfg: %08x\n\r", in_le32(®->transcfg)); + printf("TransStatus: %08x\n\r", in_le32(®->transstatus)); + printf("LinkCfg: %08x\n\r", in_le32(®->linkcfg)); + printf("LinkCfg1: %08x\n\r", in_le32(®->linkcfg1)); + printf("LinkCfg2: %08x\n\r", in_le32(®->linkcfg2)); + printf("LinkStatus: %08x\n\r", in_le32(®->linkstatus)); + printf("LinkStatus1: %08x\n\r", in_le32(®->linkstatus1)); + printf("PhyCtrlCfg: %08x\n\r", in_le32(®->phyctrlcfg)); + printf("SYSPR: %08x\n\r", in_be32(®->syspr)); +} + +static int fsl_ata_exec_ata_cmd(struct fsl_sata *sata, struct cfis *cfis, + int is_ncq, int tag, u8 *buffer, u32 len) +{ + cmd_hdr_entry_t *cmd_hdr; + cmd_desc_t *cmd_desc; + sata_fis_h2d_t *h2d; + prd_entry_t *prde; + u32 ext_c_ddc; + u32 prde_count; + u32 val32; + u32 ttl; + fsl_sata_reg_t *reg = sata->reg_base; + int i; + + /* Check xfer length */ + if (len > SATA_HC_MAX_XFER_LEN) { + printf("max transfer length is 64MB\n\r"); + return 0; + } + + /* Setup the command descriptor */ + cmd_desc = sata->cmd_desc + tag; + + /* Get the pointer cfis of command descriptor */ + h2d = (sata_fis_h2d_t *)cmd_desc->cfis; + + /* Zero the cfis of command descriptor */ + memset((void *)h2d, 0, SATA_HC_CMD_DESC_CFIS_SIZE); + + /* Copy the cfis from user to command descriptor */ + h2d->fis_type = cfis->fis_type; + h2d->pm_port_c = cfis->pm_port_c; + h2d->command = cfis->command; + + h2d->features = cfis->features; + h2d->features_exp = cfis->features_exp; + + h2d->lba_low = cfis->lba_low; + h2d->lba_mid = cfis->lba_mid; + h2d->lba_high = cfis->lba_high; + h2d->lba_low_exp = cfis->lba_low_exp; + h2d->lba_mid_exp = cfis->lba_mid_exp; + h2d->lba_high_exp = cfis->lba_high_exp; + + if (!is_ncq) { + h2d->sector_count = cfis->sector_count; + h2d->sector_count_exp = cfis->sector_count_exp; + } else { /* NCQ */ + h2d->sector_count = (u8)(tag << 3); + } + + h2d->device = cfis->device; + h2d->control = cfis->control; + + /* Setup the PRD table */ + prde = (prd_entry_t *)cmd_desc->prdt; + memset((void *)prde, 0, sizeof(struct prdt)); + + prde_count = 0; + ttl = len; + for (i = 0; i < SATA_HC_MAX_PRD_DIRECT; i++) { + if (!len) + break; + prde->dba = cpu_to_le32((u32)buffer & ~0x3); + debug("dba = %08x\n\r", (u32)buffer); + + if (len < PRD_ENTRY_MAX_XFER_SZ) { + ext_c_ddc = PRD_ENTRY_DATA_SNOOP | len; + debug("ext_c_ddc1 = %08x, len = %08x\n\r", ext_c_ddc, len); + prde->ext_c_ddc = cpu_to_le32(ext_c_ddc); + prde_count++; + prde++; + break; + } else { + ext_c_ddc = PRD_ENTRY_DATA_SNOOP; /* 4M bytes */ + debug("ext_c_ddc2 = %08x, len = %08x\n\r", ext_c_ddc, len); + prde->ext_c_ddc = cpu_to_le32(ext_c_ddc); + buffer += PRD_ENTRY_MAX_XFER_SZ; + len -= PRD_ENTRY_MAX_XFER_SZ; + prde_count++; + prde++; + } + } + + /* Setup the command slot of cmd hdr */ + cmd_hdr = (cmd_hdr_entry_t *)&sata->cmd_hdr->cmd_slot[tag]; + + cmd_hdr->cda = cpu_to_le32((u32)cmd_desc & ~0x3); + + val32 = prde_count << CMD_HDR_PRD_ENTRY_SHIFT; + val32 |= sizeof(sata_fis_h2d_t); + cmd_hdr->prde_fis_len = cpu_to_le32(val32); + + cmd_hdr->ttl = cpu_to_le32(ttl); + + if (!is_ncq) { + val32 = CMD_HDR_ATTR_RES | CMD_HDR_ATTR_SNOOP; + } else { + val32 = CMD_HDR_ATTR_RES | CMD_HDR_ATTR_SNOOP | CMD_HDR_ATTR_FPDMA; + } + + tag &= CMD_HDR_ATTR_TAG; + val32 |= tag; + + debug("attribute = %08x\n\r", val32); + cmd_hdr->attribute = cpu_to_le32(val32); + + /* Make sure cmd desc and cmd slot valid before commmand issue */ + sync(); + + /* PMP*/ + val32 = (u32)(h2d->pm_port_c & 0x0f); + out_le32(®->cqpmp, val32); + + /* Wait no active */ + if (ata_wait_register(®->car, (1 << tag), 0, 10000)) + printf("Wait no active time out\n\r"); + + /* Issue command */ + if (!(in_le32(®->cqr) & (1 << tag))) { + val32 = 1 << tag; + out_le32(®->cqr, val32); + } + + /* Wait command completed for 10s */ + if (ata_wait_register(®->ccr, (1 << tag), (1 << tag), 10000)) { + if (!is_ncq) + printf("Non-NCQ command time out\n\r"); + else + printf("NCQ command time out\n\r"); + } + + val32 = in_le32(®->cer); + + if (val32) { + u32 der; + fsl_sata_dump_sfis((struct sfis *)cmd_desc->sfis); + printf("CE at device\n\r"); + fsl_sata_dump_regs(reg); + der = in_le32(®->der); + out_le32(®->cer, val32); + out_le32(®->der, der); + } + + /* Clear complete flags */ + val32 = in_le32(®->ccr); + out_le32(®->ccr, val32); + + return len; +} + +static int fsl_ata_exec_reset_cmd(struct fsl_sata *sata, struct cfis *cfis, + int tag, u8 *buffer, u32 len) +{ + return 0; +} + +static int fsl_sata_exec_cmd(struct fsl_sata *sata, struct cfis *cfis, + enum cmd_type command_type, int tag, u8 *buffer, u32 len) +{ + int rc; + + if (tag > SATA_HC_MAX_CMD || tag < 0) { + printf("tag is out of range, tag=\n\r", tag); + return -1; + } + + switch (command_type) { + case CMD_ATA: + rc = fsl_ata_exec_ata_cmd(sata, cfis, 0, tag, buffer, len); + return rc; + case CMD_RESET: + rc = fsl_ata_exec_reset_cmd(sata, cfis, tag, buffer, len); + return rc; + case CMD_NCQ: + rc = fsl_ata_exec_ata_cmd(sata, cfis, 1, tag, buffer, len); + return rc; + case CMD_ATAPI: + case CMD_VENDOR_BIST: + case CMD_BIST: + printf("not support now\n\r"); + return -1; + default: + break; + } + + return -1; +} + +static void fsl_sata_identify(int dev, u16 *id) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d; + struct cfis *cfis; + + cfis = (struct cfis *)&h2d; + memset((void *)cfis, 0, sizeof(struct cfis)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + cfis->command = ATA_CMD_ID_ATA; + + fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, (u8 *)id, ATA_ID_WORDS * 2); + ata_swap_buf_le16(id, ATA_ID_WORDS); +} + +static void fsl_sata_xfer_mode(int dev, u16 *id) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + + sata->pio = id[ATA_ID_PIO_MODES]; + sata->mwdma = id[ATA_ID_MWDMA_MODES]; + sata->udma = id[ATA_ID_UDMA_MODES]; + debug("pio %04x, mwdma %04x, udma %04x\n\r", sata->pio, sata->mwdma, sata->udma); +} + +static void fsl_sata_set_features(int dev) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d; + struct cfis *cfis; + u8 udma_cap; + + cfis = (struct cfis *)&h2d; + memset((void *)cfis, 0, sizeof(struct cfis)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + cfis->command = ATA_CMD_SET_FEATURES; + cfis->features = SETFEATURES_XFER; + + /* First check the device capablity */ + udma_cap = (u8)(sata->udma & 0xff); + debug("udma_cap %02x\n\r", udma_cap); + + if (udma_cap == ATA_UDMA6) + cfis->sector_count = XFER_UDMA_6; + if (udma_cap == ATA_UDMA5) + cfis->sector_count = XFER_UDMA_5; + if (udma_cap == ATA_UDMA4) + cfis->sector_count = XFER_UDMA_4; + if (udma_cap == ATA_UDMA3) + cfis->sector_count = XFER_UDMA_3; + + fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0); +} + +static u32 fsl_sata_rw_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d; + struct cfis *cfis; + u32 block; + + block = start; + cfis = (struct cfis *)&h2d; + + memset((void *)cfis, 0, sizeof(struct cfis)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + cfis->command = (is_write) ? ATA_CMD_WRITE_DMA : ATA_CMD_READ_DMA; + cfis->device = ATA_LBA; + + cfis->device |= (block >> 24) & 0xf; + cfis->lba_high = (block >> 16) & 0xff; + cfis->lba_mid = (block >> 8) & 0xff; + cfis->lba_low = block & 0xff; + cfis->sector_count = (u8)(blkcnt & 0xff); + + fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, buffer, ATA_SECT_SIZE * blkcnt); + return blkcnt; +} + +void fsl_sata_flush_cache(int dev) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d; + struct cfis *cfis; + + cfis = (struct cfis *)&h2d; + + memset((void *)cfis, 0, sizeof(struct cfis)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + cfis->command = ATA_CMD_FLUSH_CACHE; + + fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0); +} + +static u32 fsl_sata_rw_cmd_ext(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d; + struct cfis *cfis; + u64 block; + + block = (u64)start; + cfis = (struct cfis *)&h2d; + + memset((void *)cfis, 0, sizeof(struct cfis)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + + cfis->command = (is_write) ? ATA_CMD_WRITE_DMA_EXT + : ATA_CMD_READ_DMA_EXT; + + cfis->lba_high_exp = (block >> 40) & 0xff; + cfis->lba_mid_exp = (block >> 32) & 0xff; + cfis->lba_low_exp = (block >> 24) & 0xff; + cfis->lba_high = (block >> 16) & 0xff; + cfis->lba_mid = (block >> 8) & 0xff; + cfis->lba_low = block & 0xff; + cfis->device = ATA_LBA; + cfis->sector_count_exp = (blkcnt >> 8) & 0xff; + cfis->sector_count = blkcnt & 0xff; + + fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, buffer, ATA_SECT_SIZE * blkcnt); + return blkcnt; +} + +u32 fsl_sata_rw_ncq_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d; + struct cfis *cfis; + int ncq_channel; + u64 block; + + if (sata_dev_desc[dev].lba48 != 1) { + printf("execute FPDMA command on non-LBA48 hard disk\n\r"); + return -1; + } + + block = (u64)start; + cfis = (struct cfis *)&h2d; + + memset((void *)cfis, 0, sizeof(struct cfis)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + + cfis->command = (is_write) ? ATA_CMD_WRITE_FPDMA_QUEUED + : ATA_CMD_READ_FPDMA_QUEUED; + + cfis->lba_high_exp = (block >> 40) & 0xff; + cfis->lba_mid_exp = (block >> 32) & 0xff; + cfis->lba_low_exp = (block >> 24) & 0xff; + cfis->lba_high = (block >> 16) & 0xff; + cfis->lba_mid = (block >> 8) & 0xff; + cfis->lba_low = block & 0xff; + + cfis->device = ATA_LBA; + cfis->features_exp = (blkcnt >> 8) & 0xff; + cfis->features = blkcnt & 0xff; + + if (sata->queue_depth >= SATA_HC_MAX_CMD) + ncq_channel = SATA_HC_MAX_CMD - 1; + else + ncq_channel = sata->queue_depth - 1; + + /* Use the latest queue */ + fsl_sata_exec_cmd(sata, cfis, CMD_NCQ, ncq_channel, buffer, ATA_SECT_SIZE * blkcnt); + return blkcnt; +} + +void fsl_sata_flush_cache_ext(int dev) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d; + struct cfis *cfis; + + cfis = (struct cfis *)&h2d; + + memset((void *)cfis, 0, sizeof(struct cfis)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + cfis->command = ATA_CMD_FLUSH_CACHE_EXT; + + fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0); +} + +/* Software reset, set SRST of the Device Control register */ +void fsl_sata_software_reset(int dev) +{ + return; +} + +static void fsl_sata_init_wcache(int dev, u16 *id) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + + if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id)) + sata->wcache = 1; + if (ata_id_has_flush(id)) + sata->flush = 1; + if (ata_id_has_flush_ext(id)) + sata->flush_ext = 1; +} + +static int fsl_sata_get_wcache(int dev) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + return sata->wcache; +} + +static int fsl_sata_get_flush(int dev) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + return sata->flush; +} + +static int fsl_sata_get_flush_ext(int dev) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + return sata->flush_ext; +} + +u32 ata_low_level_rw_lba48(int dev, u32 blknr, u32 blkcnt, void *buffer, int is_write) +{ + u32 start, blks; + u8 *addr; + int max_blks; + + start = blknr; + blks = blkcnt; + addr = (u8 *)buffer; + + max_blks = ATA_MAX_SECTORS_LBA48; + do { + if (blks > max_blks) { + if (fsl_sata_info[dev].flags != FLAGS_FPDMA) + fsl_sata_rw_cmd_ext(dev, start, max_blks, addr, is_write); + else + fsl_sata_rw_ncq_cmd(dev, start, max_blks, addr, is_write); + start += max_blks; + blks -= max_blks; + addr += ATA_SECT_SIZE * max_blks; + } else { + if (fsl_sata_info[dev].flags != FLAGS_FPDMA) + fsl_sata_rw_cmd_ext(dev, start, blks, addr, is_write); + else + fsl_sata_rw_ncq_cmd(dev, start, blks, addr, is_write); + start += blks; + blks = 0; + addr += ATA_SECT_SIZE * blks; + } + } while (blks != 0); + + return blkcnt; +} + +u32 ata_low_level_rw_lba28(int dev, u32 blknr, u32 blkcnt, void *buffer, int is_write) +{ + u32 start, blks; + u8 *addr; + int max_blks; + + start = blknr; + blks = blkcnt; + addr = (u8 *)buffer; + + max_blks = ATA_MAX_SECTORS; + do { + if (blks > max_blks) { + fsl_sata_rw_cmd(dev, start, max_blks, addr, is_write); + start += max_blks; + blks -= max_blks; + addr += ATA_SECT_SIZE * max_blks; + } else { + fsl_sata_rw_cmd(dev, start, blks, addr, is_write); + start += blks; + blks = 0; + addr += ATA_SECT_SIZE * blks; + } + } while (blks != 0); + + return blkcnt; +} + +/* + * SATA interface between low level driver and command layer + */ +ulong sata_read(int dev, u32 blknr, u32 blkcnt, void *buffer) +{ + u32 rc; + + if (sata_dev_desc[dev].lba48) + rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, buffer, READ_CMD); + else + rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, buffer, READ_CMD); + return rc; +} + +ulong sata_write(int dev, u32 blknr, u32 blkcnt, void *buffer) +{ + u32 rc; + + if (sata_dev_desc[dev].lba48) { + rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, buffer, WRITE_CMD); + if (fsl_sata_get_wcache(dev) && fsl_sata_get_flush_ext(dev)) + fsl_sata_flush_cache_ext(dev); + } else { + rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, buffer, WRITE_CMD); + if (fsl_sata_get_wcache(dev) && fsl_sata_get_flush(dev)) + fsl_sata_flush_cache(dev); + } + return rc; +} + +int scan_sata(int dev) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + unsigned char serial[ATA_ID_SERNO_LEN + 1]; + unsigned char firmware[ATA_ID_FW_REV_LEN + 1]; + unsigned char product[ATA_ID_PROD_LEN + 1]; + u16 *id; + u64 n_sectors; + + /* if no detected link */ + if (!sata->link) + return -1; + + id = (u16 *)malloc(ATA_ID_WORDS * 2); + if (!id) { + printf("id malloc failed\n\r"); + return -1; + } + + /* Identify device to get information */ + fsl_sata_identify(dev, id); + + /* Serial number */ + ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); + memcpy(sata_dev_desc[dev].product, serial, sizeof(serial)); + + /* Firmware version */ + ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); + memcpy(sata_dev_desc[dev].revision, firmware, sizeof(firmware)); + + /* Product model */ + ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); + memcpy(sata_dev_desc[dev].vendor, product, sizeof(product)); + + /* Totoal sectors */ + n_sectors = ata_id_n_sectors(id); + sata_dev_desc[dev].lba = (u32)n_sectors; + + /* Check if support LBA48 */ + if (ata_id_has_lba48(id)) { + sata_dev_desc[dev].lba48 = 1; + debug("Device support LBA48\n\r"); + } + + /* Get the NCQ queue depth from device */ + sata->queue_depth = ata_id_queue_depth(id); + + /* Get the xfer mode from device */ + fsl_sata_xfer_mode(dev, id); + + /* Get the write cache status from device */ + fsl_sata_init_wcache(dev, id); + + /* Set the xfer mode to highest speed */ + fsl_sata_set_features(dev); +#ifdef DEBUG + fsl_sata_identify(dev, id); + ata_dump_id(id); +#endif + free((void *)id); + return 0; +} diff --git a/drivers/block/fsl_sata.h b/drivers/block/fsl_sata.h new file mode 100644 index 0000000000..874c0dc740 --- /dev/null +++ b/drivers/block/fsl_sata.h @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2007-2008 Freescale Semiconductor, Inc. + * Dave Liu + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __FSL_SATA_H__ +#define __FSL_SATA_H__ + +#define SATA_HC_MAX_NUM 4 /* Max host controller numbers */ +#define SATA_HC_MAX_CMD 16 /* Max command queue depth per host controller */ +#define SATA_HC_MAX_PORT 16 /* Max port number per host controller */ + +/* +* SATA Host Controller Registers +*/ +typedef struct fsl_sata_reg { + /* SATA command registers */ + u32 cqr; /* Command queue register */ + u8 res1[0x4]; + u32 car; /* Command active register */ + u8 res2[0x4]; + u32 ccr; /* Command completed register */ + u8 res3[0x4]; + u32 cer; /* Command error register */ + u8 res4[0x4]; + u32 der; /* Device error register */ + u32 chba; /* Command header base address */ + u32 hstatus; /* Host status register */ + u32 hcontrol; /* Host control register */ + u32 cqpmp; /* Port number queue register */ + u32 sig; /* Signature register */ + u32 icc; /* Interrupt coalescing control register */ + u8 res5[0xc4]; + + /* SATA supperset registers */ + u32 sstatus; /* SATA interface status register */ + u32 serror; /* SATA interface error register */ + u32 scontrol; /* SATA interface control register */ + u32 snotification; /* SATA interface notification register */ + u8 res6[0x30]; + + /* SATA control status registers */ + u32 transcfg; /* Transport layer configuration */ + u32 transstatus; /* Transport layer status */ + u32 linkcfg; /* Link layer configuration */ + u32 linkcfg1; /* Link layer configuration1 */ + u32 linkcfg2; /* Link layer configuration2 */ + u32 linkstatus; /* Link layer status */ + u32 linkstatus1; /* Link layer status1 */ + u32 phyctrlcfg; /* PHY control configuration */ + u8 res7[0x2b0]; + + /* SATA system control registers */ + u32 syspr; /* System priority register - big endian */ + u8 res8[0xbec]; +} __attribute__ ((packed)) fsl_sata_reg_t; + +/* HStatus register +*/ +#define HSTATUS_ONOFF 0x80000000 /* Online/offline status */ +#define HSTATUS_FORCE_OFFLINE 0x40000000 /* In process going offline */ +#define HSTATUS_BIST_ERR 0x20000000 + +/* Fatal error */ +#define HSTATUS_MASTER_ERR 0x00004000 +#define HSTATUS_DATA_UNDERRUN 0x00002000 +#define HSTATUS_DATA_OVERRUN 0x00001000 +#define HSTATUS_CRC_ERR_TX 0x00000800 +#define HSTATUS_CRC_ERR_RX 0x00000400 +#define HSTATUS_FIFO_OVERFLOW_TX 0x00000200 +#define HSTATUS_FIFO_OVERFLOW_RX 0x00000100 +#define HSTATUS_FATAL_ERR_ALL (HSTATUS_MASTER_ERR | \ + HSTATUS_DATA_UNDERRUN | \ + HSTATUS_DATA_OVERRUN | \ + HSTATUS_CRC_ERR_TX | \ + HSTATUS_CRC_ERR_RX | \ + HSTATUS_FIFO_OVERFLOW_TX | \ + HSTATUS_FIFO_OVERFLOW_RX) +/* Interrupt status */ +#define HSTATUS_FATAL_ERR 0x00000020 +#define HSTATUS_PHY_RDY 0x00000010 +#define HSTATUS_SIGNATURE 0x00000008 +#define HSTATUS_SNOTIFY 0x00000004 +#define HSTATUS_DEVICE_ERR 0x00000002 +#define HSTATUS_CMD_COMPLETE 0x00000001 + +/* HControl register +*/ +#define HCONTROL_ONOFF 0x80000000 /* Online or offline request */ +#define HCONTROL_FORCE_OFFLINE 0x40000000 /* Force offline request */ +#define HCONTROL_HDR_SNOOP 0x00000400 /* Command header snoop */ +#define HCONTROL_PMP_ATTACHED 0x00000200 /* Port multiplier attached */ + +/* Interrupt enable */ +#define HCONTROL_FATAL_ERR 0x00000020 +#define HCONTROL_PHY_RDY 0x00000010 +#define HCONTROL_SIGNATURE 0x00000008 +#define HCONTROL_SNOTIFY 0x00000004 +#define HCONTROL_DEVICE_ERR 0x00000002 +#define HCONTROL_CMD_COMPLETE 0x00000001 + +#define HCONTROL_INT_EN_ALL (HCONTROL_FATAL_ERR | \ + HCONTROL_PHY_RDY | \ + HCONTROL_SIGNATURE | \ + HCONTROL_SNOTIFY | \ + HCONTROL_DEVICE_ERR | \ + HCONTROL_CMD_COMPLETE) + +/* SStatus register +*/ +#define SSTATUS_IPM_MASK 0x00000780 +#define SSTATUS_IPM_NOPRESENT 0x00000000 +#define SSTATUS_IPM_ACTIVE 0x00000080 +#define SSTATUS_IPM_PATIAL 0x00000100 +#define SSTATUS_IPM_SLUMBER 0x00000300 + +#define SSTATUS_SPD_MASK 0x000000f0 +#define SSTATUS_SPD_GEN1 0x00000010 +#define SSTATUS_SPD_GEN2 0x00000020 + +#define SSTATUS_DET_MASK 0x0000000f +#define SSTATUS_DET_NODEVICE 0x00000000 +#define SSTATUS_DET_DISCONNECT 0x00000001 +#define SSTATUS_DET_CONNECT 0x00000003 +#define SSTATUS_DET_PHY_OFFLINE 0x00000004 + +/* SControl register +*/ +#define SCONTROL_SPM_MASK 0x0000f000 +#define SCONTROL_SPM_GO_PARTIAL 0x00001000 +#define SCONTROL_SPM_GO_SLUMBER 0x00002000 +#define SCONTROL_SPM_GO_ACTIVE 0x00004000 + +#define SCONTROL_IPM_MASK 0x00000f00 +#define SCONTROL_IPM_NO_RESTRICT 0x00000000 +#define SCONTROL_IPM_PARTIAL 0x00000100 +#define SCONTROL_IPM_SLUMBER 0x00000200 +#define SCONTROL_IPM_PART_SLUM 0x00000300 + +#define SCONTROL_SPD_MASK 0x000000f0 +#define SCONTROL_SPD_NO_RESTRICT 0x00000000 +#define SCONTROL_SPD_GEN1 0x00000010 +#define SCONTROL_SPD_GEN2 0x00000020 + +#define SCONTROL_DET_MASK 0x0000000f +#define SCONTROL_DET_HRESET 0x00000001 +#define SCONTROL_DET_DISABLE 0x00000004 + +/* TransCfg register +*/ +#define TRANSCFG_DFIS_SIZE_SHIFT 16 +#define TRANSCFG_RX_WATER_MARK_MASK 0x0000001f + +/* PhyCtrlCfg register +*/ +#define PHYCTRLCFG_FPRFTI_MASK 0x00000018 +#define PHYCTRLCFG_LOOPBACK_MASK 0x0000000e + +/* +* Command Header Entry +*/ +typedef struct cmd_hdr_entry { + u32 cda; /* Command Descriptor Address, 4 bytes aligned */ + u32 prde_fis_len; /* Number of PRD entries and FIS length */ + u32 ttl; /* Total transfer length */ + u32 attribute; /* the attribute of command */ +} __attribute__ ((packed)) cmd_hdr_entry_t; + +#define SATA_HC_CMD_HDR_ENTRY_SIZE sizeof(struct cmd_hdr_entry) + +/* cda +*/ +#define CMD_HDR_CDA_ALIGN 4 + +/* prde_fis_len +*/ +#define CMD_HDR_PRD_ENTRY_SHIFT 16 +#define CMD_HDR_PRD_ENTRY_MASK 0x003f0000 +#define CMD_HDR_FIS_LEN_SHIFT 2 + +/* attribute +*/ +#define CMD_HDR_ATTR_RES 0x00000800 /* Reserved bit, should be 1 */ +#define CMD_HDR_ATTR_VBIST 0x00000400 /* Vendor BIST */ +#define CMD_HDR_ATTR_SNOOP 0x00000200 /* Snoop enable for all descriptor */ +#define CMD_HDR_ATTR_FPDMA 0x00000100 /* FPDMA queued command */ +#define CMD_HDR_ATTR_RESET 0x00000080 /* Reset - a SRST or device reset */ +#define CMD_HDR_ATTR_BIST 0x00000040 /* BIST - require the host to enter BIST mode */ +#define CMD_HDR_ATTR_ATAPI 0x00000020 /* ATAPI command */ +#define CMD_HDR_ATTR_TAG 0x0000001f /* TAG mask */ + +/* command type +*/ +enum cmd_type { + CMD_VENDOR_BIST, + CMD_BIST, + CMD_RESET, /* SRST or device reset */ + CMD_ATAPI, + CMD_NCQ, + CMD_ATA, /* None of all above */ +}; + +/* +* Command Header Table +*/ +typedef struct cmd_hdr_tbl { + cmd_hdr_entry_t cmd_slot[SATA_HC_MAX_CMD]; +} __attribute__ ((packed)) cmd_hdr_tbl_t; + +#define SATA_HC_CMD_HDR_TBL_SIZE sizeof(struct cmd_hdr_tbl) +#define SATA_HC_CMD_HDR_TBL_ALIGN 4 + +/* +* PRD entry - Physical Region Descriptor entry +*/ +typedef struct prd_entry { + u32 dba; /* Data base address, 4 bytes aligned */ + u32 res1; + u32 res2; + u32 ext_c_ddc; /* Indirect PRD flags, snoop and data word count */ +} __attribute__ ((packed)) prd_entry_t; + +#define SATA_HC_CMD_DESC_PRD_SIZE sizeof(struct prd_entry) + +/* dba +*/ +#define PRD_ENTRY_DBA_ALIGN 4 + +/* ext_c_ddc +*/ +#define PRD_ENTRY_EXT 0x80000000 /* extension flag or called indirect descriptor flag */ +#define PRD_ENTRY_DATA_SNOOP 0x00400000 /* Snoop enable for all data associated with the PRD entry */ +#define PRD_ENTRY_LEN_MASK 0x003fffff /* Data word count */ + +#define PRD_ENTRY_MAX_XFER_SZ (PRD_ENTRY_LEN_MASK + 1) + +/* + * This SATA host controller supports a max of 16 direct PRD entries, but if use + * chained indirect PRD entries, then the contollers supports upto a max of 63 + * entries including direct and indirect PRD entries. + * The PRDT is an array of 63 PRD entries contigiously, but the PRD entries#15 + * will be setup as an indirect descriptor, pointing to it's next (contigious) + * PRD entries#16. + */ +#define SATA_HC_MAX_PRD 63 /* Max PRD entry numbers per command */ +#define SATA_HC_MAX_PRD_DIRECT 16 /* Direct PRDT entries */ +#define SATA_HC_MAX_PRD_USABLE (SATA_HC_MAX_PRD - 1) +#define SATA_HC_MAX_XFER_LEN 0x4000000 + +/* +* PRDT - Physical Region Descriptor Table +*/ +typedef struct prdt { + prd_entry_t prdt[SATA_HC_MAX_PRD]; +} __attribute__ ((packed)) prdt_t; + +/* +* Command Descriptor +*/ +#define SATA_HC_CMD_DESC_CFIS_SIZE 32 /* bytes */ +#define SATA_HC_CMD_DESC_SFIS_SIZE 32 /* bytes */ +#define SATA_HC_CMD_DESC_ACMD_SIZE 16 /* bytes */ +#define SATA_HC_CMD_DESC_RES 16 /* bytes */ + +typedef struct cmd_desc { + u8 cfis[SATA_HC_CMD_DESC_CFIS_SIZE]; + u8 sfis[SATA_HC_CMD_DESC_SFIS_SIZE]; + u8 acmd[SATA_HC_CMD_DESC_ACMD_SIZE]; + u8 res[SATA_HC_CMD_DESC_RES]; + prd_entry_t prdt[SATA_HC_MAX_PRD]; +} __attribute__ ((packed)) cmd_desc_t; + +#define SATA_HC_CMD_DESC_SIZE sizeof(struct cmd_desc) +#define SATA_HC_CMD_DESC_ALIGN 4 + +/* +* CFIS - Command FIS, which is H2D register FIS, the struct defination +* of Non-Queued command is different than NCQ command. see them is sata2.h +*/ +typedef struct cfis { + u8 fis_type; + u8 pm_port_c; + u8 command; + u8 features; + u8 lba_low; + u8 lba_mid; + u8 lba_high; + u8 device; + u8 lba_low_exp; + u8 lba_mid_exp; + u8 lba_high_exp; + u8 features_exp; + u8 sector_count; + u8 sector_count_exp; + u8 res1; + u8 control; + u8 res2[4]; +} __attribute__ ((packed)) cfis_t; + +/* +* SFIS - Status FIS, which is D2H register FIS. +*/ +typedef struct sfis { + u8 fis_type; + u8 pm_port_i; + u8 status; + u8 error; + u8 lba_low; + u8 lba_mid; + u8 lba_high; + u8 device; + u8 lba_low_exp; + u8 lba_mid_exp; + u8 lba_high_exp; + u8 res1; + u8 sector_count; + u8 sector_count_exp; + u8 res2[2]; + u8 res3[4]; +} __attribute__ ((packed)) sfis_t; + +/* + * SATA device driver info + */ +typedef struct fsl_sata_info { + u32 sata_reg_base; + u32 flags; +} fsl_sata_info_t; + +#define FLAGS_DMA 0x00000000 +#define FLAGS_FPDMA 0x00000001 + +/* + * SATA device driver struct + */ +typedef struct fsl_sata { + char name[12]; + fsl_sata_reg_t *reg_base; /* the base address of controller register */ + void *cmd_hdr_tbl_offset; /* alloc address of command header table */ + cmd_hdr_tbl_t *cmd_hdr; /* aligned address of command header table */ + void *cmd_desc_offset; /* alloc address of command descriptor */ + cmd_desc_t *cmd_desc; /* aligned address of command descriptor */ + int link; /* PHY link status */ + /* device attribute */ + int ata_device_type; /* device type */ + int lba48; + int queue_depth; /* Max NCQ queue depth */ + u16 pio; + u16 mwdma; + u16 udma; + int wcache; + int flush; + int flush_ext; +} fsl_sata_t; + +#define READ_CMD 0 +#define WRITE_CMD 1 + +#endif /* __FSL_SATA_H__ */ -- cgit From d049cc7f71c0d875e8f5099d1ed23666a82b8f8e Mon Sep 17 00:00:00 2001 From: Wolfgang Denk Date: Thu, 27 Mar 2008 00:03:57 +0100 Subject: Coding style cleanup, update CHANGELOG Signed-off-by: Wolfgang Denk --- drivers/block/libata.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/libata.c b/drivers/block/libata.c index a0cf90d9a8..bbe16a2287 100644 --- a/drivers/block/libata.c +++ b/drivers/block/libata.c @@ -109,7 +109,7 @@ void ata_dump_id(u16 *id) n_sectors = ata_id_n_sectors(id); printf("Capablity: %d sectors\n\r", n_sectors); - printf("id[49]: capabilities ==0x%04x\n" + printf ("id[49]: capabilities ==0x%04x\n" "id[53]: field valid ==0x%04x\n" "id[63]: mwdma ==0x%04x\n" "id[64]: pio ==0x%04x\n" @@ -120,14 +120,14 @@ void ata_dump_id(u16 *id) id[64], id[75]); - printf("id[76]: sata capablity ==0x%04x\n" + printf ("id[76]: sata capablity ==0x%04x\n" "id[78]: sata features supported ==0x%04x\n" "id[79]: sata features enable ==0x%04x\n", id[76], id[78], id[79]); - printf("id[80]: major version ==0x%04x\n" + printf ("id[80]: major version ==0x%04x\n" "id[81]: minor version ==0x%04x\n" "id[82]: command set supported 1 ==0x%04x\n" "id[83]: command set supported 2 ==0x%04x\n" @@ -137,7 +137,7 @@ void ata_dump_id(u16 *id) id[82], id[83], id[84]); - printf("id[85]: command set enable 1 ==0x%04x\n" + printf ("id[85]: command set enable 1 ==0x%04x\n" "id[86]: command set enable 2 ==0x%04x\n" "id[87]: command set default ==0x%04x\n" "id[88]: udma ==0x%04x\n" -- cgit From d8c82db482d6b535d12b419d6440b88bf7091c9b Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Fri, 14 Mar 2008 17:45:29 -0500 Subject: Add support for setting the I2C bus speed in fsl_i2c.c Add support to the Freescale I2C driver (fsl_i2c.c) for setting and querying the I2C bus speed. Current 8[356]xx boards define the CFG_I2C_SPEED macro, but fsl_i2c.c ignores it and uses conservative value when programming the I2C bus speed. Signed-off-by: Timur Tabi Acked-by: Andy Fleming --- drivers/i2c/fsl_i2c.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 105 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c index 22485ea916..dde057124e 100644 --- a/drivers/i2c/fsl_i2c.c +++ b/drivers/i2c/fsl_i2c.c @@ -32,6 +32,8 @@ #define I2C_READ_BIT 1 #define I2C_WRITE_BIT 0 +DECLARE_GLOBAL_DATA_PTR; + /* Initialize the bus pointer to whatever one the SPD EEPROM is on. * Default is bus 0. This is necessary because the DDR initialization * runs from ROM, and we can't switch buses because we can't modify @@ -43,24 +45,111 @@ static unsigned int i2c_bus_num __attribute__ ((section ("data"))) = CFG_SPD_BUS static unsigned int i2c_bus_num __attribute__ ((section ("data"))) = 0; #endif -static volatile struct fsl_i2c *i2c_dev[2] = { +static unsigned int i2c_bus_speed[2] = {CFG_I2C_SPEED, CFG_I2C_SPEED}; + +static const struct fsl_i2c *i2c_dev[2] = { (struct fsl_i2c *) (CFG_IMMR + CFG_I2C_OFFSET), #ifdef CFG_I2C2_OFFSET (struct fsl_i2c *) (CFG_IMMR + CFG_I2C2_OFFSET) #endif }; +/* I2C speed map for a DFSR value of 1 */ + +/* + * Map I2C frequency dividers to FDR and DFSR values + * + * This structure is used to define the elements of a table that maps I2C + * frequency divider (I2C clock rate divided by I2C bus speed) to a value to be + * programmed into the Frequency Divider Ratio (FDR) and Digital Filter + * Sampling Rate (DFSR) registers. + * + * The actual table should be defined in the board file, and it must be called + * fsl_i2c_speed_map[]. + * + * The last entry of the table must have a value of {-1, X}, where X is same + * FDR/DFSR values as the second-to-last entry. This guarantees that any + * search through the array will always find a match. + * + * The values of the divider must be in increasing numerical order, i.e. + * fsl_i2c_speed_map[x+1].divider > fsl_i2c_speed_map[x].divider. + * + * For this table, the values are based on a value of 1 for the DFSR + * register. See the application note AN2919 "Determining the I2C Frequency + * Divider Ratio for SCL" + */ +static const struct { + unsigned short divider; + u8 dfsr; + u8 fdr; +} fsl_i2c_speed_map[] = { + {160, 1, 32}, {192, 1, 33}, {224, 1, 34}, {256, 1, 35}, + {288, 1, 0}, {320, 1, 1}, {352, 6, 1}, {384, 1, 2}, {416, 6, 2}, + {448, 1, 38}, {480, 1, 3}, {512, 1, 39}, {544, 11, 3}, {576, 1, 4}, + {608, 22, 3}, {640, 1, 5}, {672, 32, 3}, {704, 11, 5}, {736, 43, 3}, + {768, 1, 6}, {800, 54, 3}, {832, 11, 6}, {896, 1, 42}, {960, 1, 7}, + {1024, 1, 43}, {1088, 22, 7}, {1152, 1, 8}, {1216, 43, 7}, {1280, 1, 9}, + {1408, 22, 9}, {1536, 1, 10}, {1664, 22, 10}, {1792, 1, 46}, + {1920, 1, 11}, {2048, 1, 47}, {2176, 43, 11}, {2304, 1, 12}, + {2560, 1, 13}, {2816, 43, 13}, {3072, 1, 14}, {3328, 43, 14}, + {3584, 1, 50}, {3840, 1, 15}, {4096, 1, 51}, {4608, 1, 16}, + {5120, 1, 17}, {6144, 1, 18}, {7168, 1, 54}, {7680, 1, 19}, + {8192, 1, 55}, {9216, 1, 20}, {10240, 1, 21}, {12288, 1, 22}, + {14336, 1, 58}, {15360, 1, 23}, {16384, 1, 59}, {18432, 1, 24}, + {20480, 1, 25}, {24576, 1, 26}, {28672, 1, 62}, {30720, 1, 27}, + {32768, 1, 63}, {36864, 1, 28}, {40960, 1, 29}, {49152, 1, 30}, + {61440, 1, 31}, {-1, 1, 31} +}; + +/** + * Set the I2C bus speed for a given I2C device + * + * @param dev: the I2C device + * @i2c_clk: I2C bus clock frequency + * @speed: the desired speed of the bus + * + * The I2C device must be stopped before calling this function. + * + * The return value is the actual bus speed that is set. + */ +static unsigned int set_i2c_bus_speed(const struct fsl_i2c *dev, + unsigned int i2c_clk, unsigned int speed) +{ + unsigned short divider = min(i2c_clk / speed, (unsigned short) -1); + unsigned int i; + u8 fdr, dfsr; + + /* + * We want to choose an FDR/DFSR that generates an I2C bus speed that + * is equal to or lower than the requested speed. That means that we + * want the first divider that is equal to or greater than the + * calculated divider. + */ + + for (i = 0; i < ARRAY_SIZE(fsl_i2c_speed_map); i++) + if (fsl_i2c_speed_map[i].divider >= divider) { + dfsr = fsl_i2c_speed_map[i].dfsr; + fdr = fsl_i2c_speed_map[i].fdr; + speed = i2c_clk / fsl_i2c_speed_map[i].divider; + break; + } + + writeb(fdr, &dev->fdr); /* set bus speed */ + writeb(dfsr, &dev->dfsrr); /* set default filter */ + + return speed; +} + void i2c_init(int speed, int slaveadd) { - volatile struct fsl_i2c *dev; + struct fsl_i2c *dev; dev = (struct fsl_i2c *) (CFG_IMMR + CFG_I2C_OFFSET); writeb(0, &dev->cr); /* stop I2C controller */ udelay(5); /* let it shutdown in peace */ - writeb(0x3F, &dev->fdr); /* set bus speed */ - writeb(0x3F, &dev->dfsrr); /* set default filter */ + i2c_bus_speed[0] = set_i2c_bus_speed(dev, gd->i2c1_clk, speed); writeb(slaveadd << 1, &dev->adr); /* write slave address */ writeb(0x0, &dev->sr); /* clear status register */ writeb(I2C_CR_MEN, &dev->cr); /* start I2C controller */ @@ -70,12 +159,11 @@ i2c_init(int speed, int slaveadd) writeb(0, &dev->cr); /* stop I2C controller */ udelay(5); /* let it shutdown in peace */ - writeb(0x3F, &dev->fdr); /* set bus speed */ - writeb(0x3F, &dev->dfsrr); /* set default filter */ + i2c_bus_speed[1] = set_i2c_bus_speed(dev, gd->i2c2_clk, speed); writeb(slaveadd << 1, &dev->adr); /* write slave address */ writeb(0x0, &dev->sr); /* clear status register */ writeb(I2C_CR_MEN, &dev->cr); /* start I2C controller */ -#endif /* CFG_I2C2_OFFSET */ +#endif } static __inline__ int @@ -279,7 +367,14 @@ int i2c_set_bus_num(unsigned int bus) int i2c_set_bus_speed(unsigned int speed) { - return -1; + unsigned int i2c_clk = (i2c_bus_num == 1) ? gd->i2c2_clk : gd->i2c1_clk; + + writeb(0, &i2c_dev[i2c_bus_num]->cr); /* stop controller */ + i2c_bus_speed[i2c_bus_num] = + set_i2c_bus_speed(i2c_dev[i2c_bus_num], i2c_clk, speed); + writeb(I2C_CR_MEN, &i2c_dev[i2c_bus_num]->cr); /* start controller */ + + return 0; } unsigned int i2c_get_bus_num(void) @@ -289,7 +384,8 @@ unsigned int i2c_get_bus_num(void) unsigned int i2c_get_bus_speed(void) { - return 0; + return i2c_bus_speed[i2c_bus_num]; } + #endif /* CONFIG_HARD_I2C */ #endif /* CONFIG_FSL_I2C */ -- cgit