diff options
Diffstat (limited to 'drivers')
85 files changed, 7919 insertions, 1160 deletions
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index e069969e6..dca354791 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -27,6 +27,8 @@ 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 COBJS-y += systemace.o diff --git a/drivers/block/ata_piix.c b/drivers/block/ata_piix.c index 42456d7be..441a4dcd8 100644 --- a/drivers/block/ata_piix.c +++ b/drivers/block/ata_piix.c @@ -26,20 +26,25 @@ */ #include <common.h> +#include <asm/io.h> #include <pci.h> #include <command.h> #include <config.h> #include <asm/byteorder.h> +#include <part.h> #include <ide.h> #include <ata.h> #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 #define DRV_DECL /*For file specific declarations */ -#include <sata.h> -#undef DRV_DECL +#include "ata_piix.h" /*Macros realted to PCI*/ #define PCI_SATA_BUS 0x00 @@ -142,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) { @@ -205,12 +206,555 @@ 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; } } } 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; +} + +int scan_sata(int dev) +{ + return 0; +} + #endif diff --git a/drivers/block/ata_piix.h b/drivers/block/ata_piix.h new file mode 100644 index 000000000..f9f019470 --- /dev/null +++ b/drivers/block/ata_piix.h @@ -0,0 +1,94 @@ +#ifndef __ATA_PIIX_H__ +#define __ATA_PIIX_H__ + +#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 (int dev); +#endif + +#ifdef DRV_DECL /*Defines Driver Specific variables */ +struct sata_port port[CFG_SATA_MAXBUS]; +#endif + +#endif /* __ATA_PIIX_H__ */ diff --git a/drivers/block/fsl_sata.c b/drivers/block/fsl_sata.c new file mode 100644 index 000000000..d14f5bc6b --- /dev/null +++ b/drivers/block/fsl_sata.c @@ -0,0 +1,916 @@ +/* + * Copyright (C) 2008 Freescale Semiconductor, Inc. + * Dave Liu <daveliu@freescale.com> + * + * 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 <common.h> +#include <command.h> +#include <asm/io.h> +#include <malloc.h> +#include <libata.h> +#include <fis.h> +#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 : ATA_CMD_READ; + 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; + + 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_EXT + : ATA_CMD_READ_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_FPDMA_WRITE + : ATA_CMD_FPDMA_READ; + + 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_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 000000000..874c0dc74 --- /dev/null +++ b/drivers/block/fsl_sata.h @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2007-2008 Freescale Semiconductor, Inc. + * Dave Liu <daveliu@freescale.com> + * + * 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__ */ diff --git a/drivers/block/libata.c b/drivers/block/libata.c new file mode 100644 index 000000000..90e9a43ca --- /dev/null +++ b/drivers/block/libata.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2008 Freescale Semiconductor, Inc. + * Dave Liu <daveliu@freescale.com> + * 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 <libata.h> + +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]); +} diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c index db8ef662a..98e8bd298 100644 --- a/drivers/hwmon/lm73.c +++ b/drivers/hwmon/lm73.c @@ -1,5 +1,5 @@ /* - * (C) Copyright 2007 + * (C) Copyright 2007-2008 * Larry Johnson, lrj@acm.org * * based on dtt/lm75.c which is ... @@ -39,10 +39,10 @@ */ #define DTT_I2C_DEV_CODE 0x48 /* National Semi's LM73 device */ -int dtt_read(int sensor, int reg) +int dtt_read(int const sensor, int const reg) { int dlen; - uchar data[2]; + uint8_t data[2]; /* * Validate 'reg' param and get register size. @@ -62,27 +62,24 @@ int dtt_read(int sensor, int reg) return -1; } /* - * Calculate sensor address and register. + * Try to read the register at the calculated sensor address. */ - sensor = DTT_I2C_DEV_CODE + (sensor & 0x07); /* calculate LM73 addr */ - /* - * Now try to read the register. - */ - if (i2c_read(sensor, reg, 1, data, dlen) != 0) + if (0 != + i2c_read(DTT_I2C_DEV_CODE + (sensor & 0x07), reg, 1, data, dlen)) return -1; /* * Handle 2 byte result. */ if (2 == dlen) - return ((int)((short)data[1] + (((short)data[0]) << 8))); + return (int)((unsigned)data[0] << 8 | (unsigned)data[1]); return (int)data[0]; } /* dtt_read() */ -int dtt_write(int sensor, int reg, int val) +int dtt_write(int const sensor, int const reg, int const val) { int dlen; - uchar data[2]; + uint8_t data[2]; /* * Validate 'reg' param and handle register size @@ -91,28 +88,25 @@ int dtt_write(int sensor, int reg, int val) case DTT_CONFIG: case DTT_CONTROL: dlen = 1; - data[0] = (char)(val & 0xff); + data[0] = (uint8_t) val; break; case DTT_TEMP_HIGH: case DTT_TEMP_LOW: dlen = 2; - data[0] = (char)((val >> 8) & 0xff); /* MSB first */ - data[1] = (char)(val & 0xff); + data[0] = (uint8_t) (val >> 8); /* MSB first */ + data[1] = (uint8_t) val; break; default: return -1; } /* - * Calculate sensor address and register. - */ - sensor = DTT_I2C_DEV_CODE + (sensor & 0x07); /* calculate LM73 addr */ - /* - * Write value to register. + * Write value to register at the calculated sensor address. */ - return i2c_write(sensor, reg, 1, data, dlen) != 0; + return 0 != i2c_write(DTT_I2C_DEV_CODE + (sensor & 0x07), reg, 1, data, + dlen); } /* dtt_write() */ -static int _dtt_init(int sensor) +static int _dtt_init(int const sensor) { int val; @@ -120,31 +114,31 @@ static int _dtt_init(int sensor) * Validate the Identification register */ if (0x0190 != dtt_read(sensor, DTT_ID)) - return 1; + return -1; /* * Setup THIGH (upper-limit) and TLOW (lower-limit) registers */ val = CFG_DTT_MAX_TEMP << 7; if (dtt_write(sensor, DTT_TEMP_HIGH, val)) - return 1; + return -1; val = CFG_DTT_MIN_TEMP << 7; if (dtt_write(sensor, DTT_TEMP_LOW, val)) - return 1; + return -1; /* * Setup configuraton register */ /* config = alert active low, disabled, and reset */ val = 0x64; if (dtt_write(sensor, DTT_CONFIG, val)) - return 1; + return -1; /* * Setup control/status register */ /* control = temp resolution 0.25C */ val = 0x00; if (dtt_write(sensor, DTT_CONTROL, val)) - return 1; + return -1; dtt_read(sensor, DTT_CONTROL); /* clear temperature flags */ return 0; @@ -157,7 +151,7 @@ int dtt_init(void) const char *const header = "DTT: "; for (i = 0; i < sizeof(sensors); i++) { - if (_dtt_init(sensors[i]) != 0) + if (0 != _dtt_init(sensors[i])) printf("%s%d FAILED INIT\n", header, i + 1); else printf("%s%d is %i C\n", header, i + 1, @@ -166,7 +160,13 @@ int dtt_init(void) return 0; } /* dtt_init() */ -int dtt_get_temp(int sensor) +int dtt_get_temp(int const sensor) { - return (dtt_read(sensor, DTT_READ_TEMP) + 0x0040) >> 7; + int const ret = dtt_read(sensor, DTT_READ_TEMP); + + if (ret < 0) { + printf("DTT temperature read failed.\n"); + return 0; + } + return (int)((int16_t) ret + 0x0040) >> 7; } /* dtt_get_temp() */ diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 29d6c03db..071ef00b1 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -29,6 +29,7 @@ COBJS-y += fsl_i2c.o COBJS-y += omap1510_i2c.o COBJS-y += omap24xx_i2c.o COBJS-y += tsi108_i2c.o +COBJS-y += mxc_i2c.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c index 22485ea91..9f2c1eced 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,110 @@ 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; + + /* + * 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) { + u8 fdr, dfsr; + dfsr = fsl_i2c_speed_map[i].dfsr; + fdr = fsl_i2c_speed_map[i].fdr; + speed = i2c_clk / fsl_i2c_speed_map[i].divider; + writeb(fdr, &dev->fdr); /* set bus speed */ + writeb(dfsr, &dev->dfsrr); /* set default filter */ + break; + } + + 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 +158,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 +366,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 +383,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 */ diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c new file mode 100644 index 000000000..a21832944 --- /dev/null +++ b/drivers/i2c/mxc_i2c.c @@ -0,0 +1,202 @@ +/* + * i2c driver for Freescale mx31 + * + * (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <common.h> + +#if defined(CONFIG_HARD_I2C) && defined (CONFIG_I2C_MXC) + +#include <asm/arch/mx31.h> +#include <asm/arch/mx31-regs.h> + +#define IADR 0x00 +#define IFDR 0x04 +#define I2CR 0x08 +#define I2SR 0x0c +#define I2DR 0x10 + +#define I2CR_IEN (1 << 7) +#define I2CR_IIEN (1 << 6) +#define I2CR_MSTA (1 << 5) +#define I2CR_MTX (1 << 4) +#define I2CR_TX_NO_AK (1 << 3) +#define I2CR_RSTA (1 << 2) + +#define I2SR_ICF (1 << 7) +#define I2SR_IBB (1 << 5) +#define I2SR_IIF (1 << 1) +#define I2SR_RX_NO_AK (1 << 0) + +#ifdef CFG_I2C_MX31_PORT1 +#define I2C_BASE 0x43f80000 +#elif defined (CFG_I2C_MX31_PORT2) +#define I2C_BASE 0x43f98000 +#elif defined (CFG_I2C_MX31_PORT3) +#define I2C_BASE 0x43f84000 +#else +#error "define CFG_I2C_MX31_PORTx to use the mx31 I2C driver" +#endif + +#ifdef DEBUG +#define DPRINTF(args...) printf(args) +#else +#define DPRINTF(args...) +#endif + +static u16 div[] = { 30, 32, 36, 42, 48, 52, 60, 72, 80, 88, 104, 128, 144, + 160, 192, 240, 288, 320, 384, 480, 576, 640, 768, 960, + 1152, 1280, 1536, 1920, 2304, 2560, 3072, 3840}; + +void i2c_init(int speed, int unused) +{ + int freq = mx31_get_ipg_clk(); + int i; + + for (i = 0; i < 0x1f; i++) + if (freq / div[i] <= speed) + break; + + DPRINTF("%s: speed: %d\n",__FUNCTION__, speed); + + __REG16(I2C_BASE + I2CR) = 0; /* Reset module */ + __REG16(I2C_BASE + IFDR) = i; + __REG16(I2C_BASE + I2CR) = I2CR_IEN; + __REG16(I2C_BASE + I2SR) = 0; +} + +static int wait_busy(void) +{ + int timeout = 10000; + + while (!(__REG16(I2C_BASE + I2SR) & I2SR_IIF) && --timeout) + udelay(1); + __REG16(I2C_BASE + I2SR) = 0; /* clear interrupt */ + + return timeout; +} + +static int tx_byte(u8 byte) +{ + __REG16(I2C_BASE + I2DR) = byte; + + if (!wait_busy() || __REG16(I2C_BASE + I2SR) & I2SR_RX_NO_AK) + return -1; + return 0; +} + +static int rx_byte(void) +{ + if (!wait_busy()) + return -1; + + return __REG16(I2C_BASE + I2DR); +} + +int i2c_probe(uchar chip) +{ + int ret; + + __REG16(I2C_BASE + I2CR) = 0; /* Reset module */ + __REG16(I2C_BASE + I2CR) = I2CR_IEN; + + __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | I2CR_MTX; + ret = tx_byte(chip << 1); + __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MTX; + + return ret; +} + +static int i2c_addr(uchar chip, uint addr, int alen) +{ + __REG16(I2C_BASE + I2SR) = 0; /* clear interrupt */ + __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | I2CR_MTX; + + if (tx_byte(chip << 1)) + return -1; + + while (alen--) + if (tx_byte((addr >> (alen * 8)) & 0xff)) + return -1; + return 0; +} + +int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) +{ + int timeout = 10000; + int ret; + + DPRINTF("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n",__FUNCTION__, chip, addr, alen, len); + + if (i2c_addr(chip, addr, alen)) { + printf("i2c_addr failed\n"); + return -1; + } + + __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | I2CR_MTX | I2CR_RSTA; + + if (tx_byte(chip << 1 | 1)) + return -1; + + __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | ((len == 1) ? I2CR_TX_NO_AK : 0); + + ret = __REG16(I2C_BASE + I2DR); + + while (len--) { + if ((ret = rx_byte()) < 0) + return -1; + *buf++ = ret; + if (len <= 1) + __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | I2CR_TX_NO_AK; + } + + wait_busy(); + + __REG16(I2C_BASE + I2CR) = I2CR_IEN; + + while (__REG16(I2C_BASE + I2SR) & I2SR_IBB && --timeout) + udelay(1); + + return 0; +} + +int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len) +{ + int timeout = 10000; + DPRINTF("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n",__FUNCTION__, chip, addr, alen, len); + + if (i2c_addr(chip, addr, alen)) + return -1; + + while (len--) + if (tx_byte(*buf++)) + return -1; + + __REG16(I2C_BASE + I2CR) = I2CR_IEN; + + while (__REG16(I2C_BASE + I2SR) & I2SR_IBB && --timeout) + udelay(1); + + return 0; +} + +#endif /* CONFIG_HARD_I2C */ diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 952e91984..ff932a1b6 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -23,17 +23,17 @@ include $(TOPDIR)/config.mk -LIB := $(obj)libmtd.a +LIB := $(obj)libmtd.a COBJS-y += at45.o COBJS-y += cfi_flash.o -COBJS-y += dataflash.o +COBJS-$(CONFIG_HAS_DATAFLASH) += dataflash.o COBJS-y += mw_eeprom.o COBJS-$(CONFIG_FLASH_CFI_LEGACY) += jedec_flash.o COBJS := $(COBJS-y) -SRCS := $(COBJS:.o=.c) -OBJS := $(addprefix $(obj),$(COBJS)) +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) all: $(LIB) diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c index 439c950cf..e3cfb8a1a 100644 --- a/drivers/mtd/cfi_flash.c +++ b/drivers/mtd/cfi_flash.c @@ -239,12 +239,14 @@ static u32 flash_read32(void *addr) return __raw_readl(addr); } -static u64 flash_read64(void *addr) +static u64 __flash_read64(void *addr) { /* No architectures currently implement __raw_readq() */ return *(volatile u64 *)addr; } +u64 flash_read64(void *addr)__attribute__((weak, alias("__flash_read64"))); + /*----------------------------------------------------------------------- */ #if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE) @@ -365,6 +367,20 @@ static inline uchar flash_read_uchar (flash_info_t * info, uint offset) } /*----------------------------------------------------------------------- + * read a word at a port width address, assume 16bit bus + */ +static inline ushort flash_read_word (flash_info_t * info, uint offset) +{ + ushort *addr, retval; + + addr = flash_map (info, 0, offset); + retval = flash_read16 (addr); + flash_unmap (info, 0, offset, addr); + return retval; +} + + +/*----------------------------------------------------------------------- * read a long word by picking the least significant byte of each maximum * port size word. Swap for ppc format. */ @@ -828,25 +844,29 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, void *dst = map_physmem(dest, len, MAP_NOCACHE); void *dst2 = dst; int flag = 0; + uint offset = 0; + unsigned int shift; switch (info->portwidth) { case FLASH_CFI_8BIT: - cnt = len; + shift = 0; break; case FLASH_CFI_16BIT: - cnt = len >> 1; + shift = 1; break; case FLASH_CFI_32BIT: - cnt = len >> 2; + shift = 2; break; case FLASH_CFI_64BIT: - cnt = len >> 3; + shift = 3; break; default: retcode = ERR_INVAL; goto out_unmap; } + cnt = len >> shift; + while ((cnt-- > 0) && (flag == 0)) { switch (info->portwidth) { case FLASH_CFI_8BIT: @@ -890,23 +910,7 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, if (retcode == ERR_OK) { /* reduce the number of loops by the width of * the port */ - switch (info->portwidth) { - case FLASH_CFI_8BIT: - cnt = len; - break; - case FLASH_CFI_16BIT: - cnt = len >> 1; - break; - case FLASH_CFI_32BIT: - cnt = len >> 2; - break; - case FLASH_CFI_64BIT: - cnt = len >> 3; - break; - default: - retcode = ERR_INVAL; - goto out_unmap; - } + cnt = len >> shift; flash_write_cmd (info, sector, 0, (uchar) cnt - 1); while (cnt-- > 0) { switch (info->portwidth) { @@ -943,36 +947,34 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, case CFI_CMDSET_AMD_STANDARD: case CFI_CMDSET_AMD_EXTENDED: flash_unlock_seq(info,0); - flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_TO_BUFFER); + +#ifdef CONFIG_FLASH_SPANSION_S29WS_N + offset = ((unsigned long)dst - info->start[sector]) >> shift; +#endif + flash_write_cmd(info, sector, offset, AMD_CMD_WRITE_TO_BUFFER); + cnt = len >> shift; + flash_write_cmd(info, sector, offset, (uchar)cnt - 1); switch (info->portwidth) { case FLASH_CFI_8BIT: - cnt = len; - flash_write_cmd (info, sector, 0, (uchar) cnt - 1); while (cnt-- > 0) { flash_write8(flash_read8(src), dst); src += 1, dst += 1; } break; case FLASH_CFI_16BIT: - cnt = len >> 1; - flash_write_cmd (info, sector, 0, (uchar) cnt - 1); while (cnt-- > 0) { flash_write16(flash_read16(src), dst); src += 2, dst += 2; } break; case FLASH_CFI_32BIT: - cnt = len >> 2; - flash_write_cmd (info, sector, 0, (uchar) cnt - 1); while (cnt-- > 0) { flash_write32(flash_read32(src), dst); src += 4, dst += 4; } break; case FLASH_CFI_64BIT: - cnt = len >> 3; - flash_write_cmd (info, sector, 0, (uchar) cnt - 1); while (cnt-- > 0) { flash_write64(flash_read64(src), dst); src += 8, dst += 8; @@ -1180,6 +1182,27 @@ void flash_print_info (flash_info_t * info) } /*----------------------------------------------------------------------- + * 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. + */ +#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); \ + else \ + putc ('.'); \ + digit--; \ + dots += scale; \ + } +#else +#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) +#endif + +/*----------------------------------------------------------------------- * Copy memory to flash, returns: * 0 - OK * 1 - write timeout @@ -1192,10 +1215,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 +1255,7 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) return rc; wp += i; + FLASH_SHOW_PROGRESS(scale, dots, digit, i); } /* handle the aligned part */ @@ -1248,6 +1285,7 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) wp += i; src += i; cnt -= i; + FLASH_SHOW_PROGRESS(scale, dots, digit, i); } #else while (cnt >= info->portwidth) { @@ -1259,8 +1297,10 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) return rc; wp += info->portwidth; cnt -= info->portwidth; + FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth); } #endif /* CFG_FLASH_USE_BUFFER_WRITE */ + if (cnt == 0) { return (0); } @@ -1411,17 +1451,29 @@ static void cmdset_amd_read_jedec_ids(flash_info_t *info) flash_unlock_seq(info, 0); flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID); udelay(1000); /* some flash are slow to respond */ + info->manufacturer_id = flash_read_uchar (info, FLASH_OFFSET_MANUFACTURER_ID); - info->device_id = flash_read_uchar (info, - FLASH_OFFSET_DEVICE_ID); - if (info->device_id == 0x7E) { - /* AMD 3-byte (expanded) device ids */ - info->device_id2 = flash_read_uchar (info, - FLASH_OFFSET_DEVICE_ID2); - info->device_id2 <<= 8; - info->device_id2 |= flash_read_uchar (info, - FLASH_OFFSET_DEVICE_ID3); + + switch (info->chipwidth){ + case FLASH_CFI_8BIT: + info->device_id = flash_read_uchar (info, + FLASH_OFFSET_DEVICE_ID); + if (info->device_id == 0x7E) { + /* AMD 3-byte (expanded) device ids */ + info->device_id2 = flash_read_uchar (info, + FLASH_OFFSET_DEVICE_ID2); + info->device_id2 <<= 8; + info->device_id2 |= flash_read_uchar (info, + FLASH_OFFSET_DEVICE_ID3); + } + break; + case FLASH_CFI_16BIT: + info->device_id = flash_read_word (info, + FLASH_OFFSET_DEVICE_ID); + break; + default: + break; } flash_write_cmd(info, 0, 0, AMD_CMD_RESET); } diff --git a/drivers/mtd/dataflash.c b/drivers/mtd/dataflash.c index 36c99a049..8247aa03b 100644 --- a/drivers/mtd/dataflash.c +++ b/drivers/mtd/dataflash.c @@ -19,81 +19,11 @@ */ #include <common.h> #include <config.h> -#ifdef CONFIG_HAS_DATAFLASH #include <asm/hardware.h> #include <dataflash.h> -AT91S_DATAFLASH_INFO dataflash_info[CFG_MAX_DATAFLASH_BANKS]; static AT91S_DataFlash DataFlashInst; -struct dataflash_addr { - unsigned long addr; - int cs; -}; - -#ifdef CONFIG_AT91SAM9260EK -struct dataflash_addr cs[CFG_MAX_DATAFLASH_BANKS] = { - {CFG_DATAFLASH_LOGIC_ADDR_CS0, 0}, /* Logical adress, CS */ - {CFG_DATAFLASH_LOGIC_ADDR_CS1, 1} -}; -#elif defined(CONFIG_AT91SAM9263EK) || defined(CONFIG_AT91CAP9ADK) -struct dataflash_addr cs[CFG_MAX_DATAFLASH_BANKS] = { - {CFG_DATAFLASH_LOGIC_ADDR_CS0, 0}, /* Logical adress, CS */ -}; -#else -struct dataflash_addr cs[CFG_MAX_DATAFLASH_BANKS] = { - {CFG_DATAFLASH_LOGIC_ADDR_CS0, 0}, /* Logical adress, CS */ - {CFG_DATAFLASH_LOGIC_ADDR_CS3, 3} -}; -#endif - -/*define the area offsets*/ -#if defined(CONFIG_AT91SAM9261EK) || defined(CONFIG_AT91SAM9260EK) || \ - defined(CONFIG_AT91SAM9263EK) || defined(CONFIG_AT91CAP9ADK) -#if defined(CONFIG_NEW_PARTITION) -dataflash_protect_t area_list[NB_DATAFLASH_AREA] = { - {0x00000000, 0x00003FFF, FLAG_PROTECT_SET, 0, "Bootstrap"}, /* ROM code */ - {0x00004200, 0x000083FF, FLAG_PROTECT_CLEAR, 0, "Environment"}, /* u-boot environment */ - {0x00008400, 0x0003DDFF, FLAG_PROTECT_SET, 0, "U-Boot"}, /* u-boot code */ - {0x0003DE00, 0x00041FFF, FLAG_PROTECT_CLEAR, FLAG_SETENV, "MON"}, /* Room for alternative boot monitor */ - {0x00042000, 0x0018BFFF, FLAG_PROTECT_CLEAR, FLAG_SETENV, "OS"}, /* data area size to tune */ - {0x0018C000, 0xFFFFFFFF, FLAG_PROTECT_CLEAR, FLAG_SETENV, "FS"}, /* data area size to tune */ -}; -#else -dataflash_protect_t area_list[NB_DATAFLASH_AREA] = { - {0, 0x3fff, FLAG_PROTECT_SET}, /* ROM code */ - {0x4000, 0x7fff, FLAG_PROTECT_CLEAR}, /* u-boot environment */ - {0x8000, 0x37fff, FLAG_PROTECT_SET}, /* u-boot code */ - {0x38000, 0x1fffff, FLAG_PROTECT_CLEAR}, /* data area size to tune */ -}; -#endif -#elif defined(CONFIG_NEW_PARTITION) -/*define the area offsets*/ -/* Invalid partitions should be defined with start > end */ -dataflash_protect_t area_list[NB_DATAFLASH_AREA*CFG_MAX_DATAFLASH_BANKS] = { - {0x00000000, 0x000083ff, FLAG_PROTECT_SET, 0, "Bootstrap"}, /* ROM code */ - {0x00008400, 0x00020fff, FLAG_PROTECT_SET, 0, "U-Boot"}, /* u-boot code */ - {0x00021000, 0x000293ff, FLAG_PROTECT_CLEAR, 0, "Environment"}, /* u-boot environment 8Kb */ - {0x00029400, 0x00041fff, FLAG_PROTECT_INVALID, 0, "<Unused>"}, /* Rest of Sector 1 */ - {0x00042000, 0x0018Bfff, FLAG_PROTECT_CLEAR, FLAG_SETENV, "OS"}, /* data area size to tune */ - {0x0018C000, 0xffffffff, FLAG_PROTECT_CLEAR, FLAG_SETENV, "FS"}, /* data area size to tune */ - - {0x00000000, 0xffffffff, FLAG_PROTECT_CLEAR, FLAG_SETENV, "Data"}, /* data area */ - {0xffffffff, 0x00000000, FLAG_PROTECT_INVALID, 0, "<Invalid>"}, /* Invalid */ - {0xffffffff, 0x00000000, FLAG_PROTECT_INVALID, 0, "<Invalid>"}, /* Invalid */ - {0xffffffff, 0x00000000, FLAG_PROTECT_INVALID, 0, "<Invalid>"}, /* Invalid */ - {0xffffffff, 0x00000000, FLAG_PROTECT_INVALID, 0, "<Invalid>"}, /* Invalid */ - {0xffffffff, 0x00000000, FLAG_PROTECT_INVALID, 0, "<Invalid>"}, /* Invalid */ -}; -#else -dataflash_protect_t area_list[NB_DATAFLASH_AREA] = { - {0, 0x7fff, FLAG_PROTECT_SET}, /* ROM code */ - {0x8000, 0x1ffff, FLAG_PROTECT_SET}, /* u-boot code */ - {0x20000, 0x27fff, FLAG_PROTECT_CLEAR}, /* u-boot environment */ - {0x28000, 0x1fffff, FLAG_PROTECT_CLEAR}, /* data area size to tune */ -}; -#endif - extern void AT91F_SpiInit (void); extern int AT91F_DataflashProbe (int i, AT91PS_DataflashDesc pDesc); extern int AT91F_DataFlashRead (AT91PS_DataFlash pDataFlash, @@ -108,7 +38,7 @@ int AT91F_DataflashInit (void) { int i, j; int dfcode; - int part = 0; + int part; int last_part; int found[CFG_MAX_DATAFLASH_BANKS]; unsigned char protected; @@ -181,7 +111,8 @@ int AT91F_DataflashInit (void) (dataflash_info[i].Device.pages_number * dataflash_info[i].Device.pages_size)-1; - last_part=0; + part = 0; + last_part = 0; /* set the area addresses */ for(j = 0; j<NB_DATAFLASH_AREA; j++) { if(found[i]!=0) { @@ -216,14 +147,14 @@ int AT91F_DataflashInit (void) return found[0]; } -#ifdef CONFIG_NEW_DF_PARTITION -int AT91F_DataflashSetEnv (void) +void AT91F_DataflashSetEnv (void) { int i, j; int part; unsigned char env; unsigned char s[32]; /* Will fit a long int in hex */ unsigned long start; + for (i = 0, part= 0; i < CFG_MAX_DATAFLASH_BANKS; i++) { for(j = 0; j<NB_DATAFLASH_AREA; j++) { env = area_list[part].setenv; @@ -231,14 +162,13 @@ int AT91F_DataflashSetEnv (void) if((env & FLAG_SETENV) == FLAG_SETENV) { start = dataflash_info[i].Device.area_list[j].start; - sprintf(s,"%X",start); - setenv(area_list[part].label,s); + sprintf((char*) s,"%X",start); + setenv((char*) area_list[part].label,(char*) s); } part++; } } } -#endif void dataflash_print_info (void) { @@ -281,25 +211,18 @@ void dataflash_print_info (void) dataflash_info[i].Device.area_list[j].start, dataflash_info[i].Device.area_list[j].end, (dataflash_info[i].Device.area_list[j].protected==FLAG_PROTECT_SET) ? "(RO)" : " "); -#ifdef CONFIG_NEW_DF_PARTITION printf(" %s\n", dataflash_info[i].Device.area_list[j].label); -#else - printf("\n"); -#endif break; -#ifdef CONFIG_NEW_DF_PARTITION case FLAG_PROTECT_INVALID: break; -#endif } } } } } - /*---------------------------------------------------------------------------*/ -/* Function Name : AT91F_DataflashSelect */ +/* Function Name : AT91F_DataflashSelect */ /* Object : Select the correct device */ /*---------------------------------------------------------------------------*/ AT91PS_DataFlash AT91F_DataflashSelect (AT91PS_DataFlash pFlash, @@ -326,7 +249,7 @@ AT91PS_DataFlash AT91F_DataflashSelect (AT91PS_DataFlash pFlash, } /*---------------------------------------------------------------------------*/ -/* Function Name : addr_dataflash */ +/* Function Name : addr_dataflash */ /* Object : Test if address is valid */ /*---------------------------------------------------------------------------*/ int addr_dataflash (unsigned long addr) @@ -344,8 +267,9 @@ int addr_dataflash (unsigned long addr) return addr_valid; } + /*---------------------------------------------------------------------------*/ -/* Function Name : size_dataflash */ +/* Function Name : size_dataflash */ /* Object : Test if address is valid regarding the size */ /*---------------------------------------------------------------------------*/ int size_dataflash (AT91PS_DataFlash pdataFlash, unsigned long addr, @@ -361,13 +285,15 @@ int size_dataflash (AT91PS_DataFlash pdataFlash, unsigned long addr, return 1; } + /*---------------------------------------------------------------------------*/ -/* Function Name : prot_dataflash */ +/* Function Name : prot_dataflash */ /* Object : Test if destination area is protected */ /*---------------------------------------------------------------------------*/ int prot_dataflash (AT91PS_DataFlash pdataFlash, unsigned long addr) { -int area; + int area; + /* find area */ for (area=0; area < NB_DATAFLASH_AREA; area++) { if ((addr >= pdataFlash->pDevice->area_list[area].start) && @@ -385,6 +311,7 @@ int area; return 1; } + /*--------------------------------------------------------------------------*/ /* Function Name : dataflash_real_protect */ /* Object : protect/unprotect area */ @@ -392,7 +319,8 @@ int area; int dataflash_real_protect (int flag, unsigned long start_addr, unsigned long end_addr) { -int i,j, area1, area2, addr_valid = 0; + int i,j, area1, area2, addr_valid = 0; + /* find dataflash */ for (i = 0; i < CFG_MAX_DATAFLASH_BANKS; i++) { if ((((int) start_addr) & 0xF0000000) == @@ -435,7 +363,7 @@ int i,j, area1, area2, addr_valid = 0; } /*---------------------------------------------------------------------------*/ -/* Function Name : read_dataflash */ +/* Function Name : read_dataflash */ /* Object : dataflash memory read */ /*---------------------------------------------------------------------------*/ int read_dataflash (unsigned long addr, unsigned long size, char *result) @@ -454,9 +382,8 @@ int read_dataflash (unsigned long addr, unsigned long size, char *result) return (AT91F_DataFlashRead (pFlash, AddrToRead, size, result)); } - /*---------------------------------------------------------------------------*/ -/* Function Name : write_dataflash */ +/* Function Name : write_dataflash */ /* Object : write a block in dataflash */ /*---------------------------------------------------------------------------*/ int write_dataflash (unsigned long addr_dest, unsigned long addr_src, @@ -483,7 +410,6 @@ int write_dataflash (unsigned long addr_dest, unsigned long addr_src, AddrToWrite, size); } - void dataflash_perror (int err) { switch (err) { @@ -509,5 +435,3 @@ void dataflash_perror (int err) break; } } - -#endif diff --git a/drivers/mtd/jedec_flash.c b/drivers/mtd/jedec_flash.c index 41aad3bd6..b958d1723 100644 --- a/drivers/mtd/jedec_flash.c +++ b/drivers/mtd/jedec_flash.c @@ -216,6 +216,25 @@ static const struct amd_flash_info jedec_table[] = { } }, #endif +#ifdef CFG_FLASH_LEGACY_512Kx16 + { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV400BB, + .name = "AMD AM29LV400BB", + .uaddr = { + [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = CFI_CMDSET_AMD_LEGACY, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,7), + } + }, +#endif }; static inline void fill_info(flash_info_t *info, const struct amd_flash_info *jedec_entry, ulong base) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 151f535c5..2da1d4621 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -931,7 +931,7 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa for (i = 0; i < eccbytes; i++, eccidx++) oob_buf[oob_config[eccidx]] = ecc_code[i]; /* If the hardware ecc provides syndromes then - * the ecc code must be written immidiately after + * the ecc code must be written immediately after * the data bytes (words) */ if (this->options & NAND_HWECC_SYNDROME) this->write_buf(mtd, ecc_code, eccbytes); @@ -1299,7 +1299,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, for (i = 0, j = 0; j < mtd->oobavail; i++) { int from = oobsel->oobfree[i][0]; int num = oobsel->oobfree[i][1]; - memcpy(&oob_buf[oob], &oob_data[from], num); + memcpy(&oob_buf[oob+j], &oob_data[from], num); j+= num; } oob += mtd->oobavail; @@ -1644,8 +1644,10 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, this->select_chip(mtd, chipnr); /* Check, if it is write protected */ - if (nand_check_wp(mtd)) + if (nand_check_wp(mtd)) { + printk (KERN_NOTICE "nand_write_ecc: Device is write protected\n"); goto out; + } /* if oobsel is NULL, use chip defaults */ if (oobsel == NULL) @@ -2486,12 +2488,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips) /* The number of bytes available for the filesystem to place fs dependend * oob data */ - if (this->options & NAND_BUSWIDTH_16) { - mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 2); - if (this->autooob->eccbytes & 0x01) - mtd->oobavail--; - } else - mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 1); + mtd->oobavail = 0; + for (i=0; this->autooob->oobfree[i][1]; i++) + mtd->oobavail += this->autooob->oobfree[i][1]; /* * check ECC mode, default to software diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 6d7e347fb..524b6b19a 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -67,8 +67,6 @@ struct nand_flash_dev nand_flash_ids[] = { {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0}, - {"NAND 512MiB 3,3V 8-bit", 0xDC, 512, 512, 0x4000, 0}, - /* These are the new chips with large page size. The pagesize * and the erasesize is determined from the extended id bytes */ diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index d4003a20f..174384eab 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -20,6 +20,19 @@ #include <asm/io.h> #include <asm/errno.h> +/* It should access 16-bit instead of 8-bit */ +static inline void *memcpy(void *dst, const void *src, unsigned int len) +{ + void *ret = dst; + short *d = dst; + const short *s = src; + + len >>= 1; + while (len-- > 0) + *d++ = *s++; + return ret; +} + static const unsigned char ffchars[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16 */ @@ -1180,6 +1193,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; diff --git a/drivers/net/Makefile b/drivers/net/Makefile index b9723fa78..d5e413b79 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 @@ -34,13 +35,14 @@ COBJS-y += e1000.o COBJS-y += eepro100.o COBJS-y += enc28j60.o COBJS-y += fsl_mcdmafec.o +COBJS-$(CONFIG_GRETH) += greth.o COBJS-y += inca-ip_sw.o COBJS-y += ks8695eth.o 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 @@ -53,10 +55,14 @@ COBJS-y += rtl8139.o COBJS-y += rtl8169.o COBJS-y += s3c4510b_eth.o COBJS-y += smc91111.o +COBJS-y += smc911x.o COBJS-y += tigon3.o COBJS-y += tsec.o COBJS-y += tsi108_eth.o COBJS-y += uli526x.o +COBJS-y += vsc7385.o +COBJS-$(CONFIG_XILINX_EMAC) += xilinx_emac.o +COBJS-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/net/ax88796.h b/drivers/net/ax88796.h new file mode 100644 index 000000000..0e6f8a201 --- /dev/null +++ b/drivers/net/ax88796.h @@ -0,0 +1,217 @@ +/* + * AX88796L(NE2000) support + * + * (c) 2007 Nobuhiro Iwamatsu <iwamatsu@nigauri.org> + * + * 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/bfin_mac.c b/drivers/net/bfin_mac.c new file mode 100644 index 000000000..afe122a33 --- /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 <common.h> +#include <config.h> +#include <net.h> +#include <command.h> +#include <malloc.h> + +#include <asm/blackfin.h> +#include <asm/mach-common/bits/dma.h> +#include <asm/mach-common/bits/emac.h> +#include <asm/mach-common/bits/pll.h> + +#include "bfin_mac.h" + +#ifdef CONFIG_POST +#include <post.h> +#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 000000000..c8a94d0c9 --- /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 diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c index f0741da82..c53c226d2 100644 --- a/drivers/net/e1000.c +++ b/drivers/net/e1000.c @@ -1,5 +1,5 @@ /************************************************************************** -Inter Pro 1000 for ppcboot/das-u-boot +Intel Pro 1000 for ppcboot/das-u-boot Drivers are port from Intel's Linux driver e1000-4.3.15 and from Etherboot pro 1000 driver by mrakes at vivato dot net tested on both gig copper and gig fiber boards @@ -21,7 +21,7 @@ tested on both gig copper and gig fiber boards 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. + Temple Place - Suite 330, Boston, MA 02111-1307, USA. The full GNU General Public License is included in this distribution in the file called LICENSE. @@ -52,7 +52,7 @@ tested on both gig copper and gig fiber boards #undef virt_to_bus #define virt_to_bus(x) ((unsigned long)x) #define bus_to_phys(devno, a) pci_mem_to_phys(devno, a) -#define mdelay(n) udelay((n)*1000) +#define mdelay(n) udelay((n)*1000) #define E1000_DEFAULT_PBA 0x00000030 @@ -82,6 +82,7 @@ static struct pci_device_id supported[] = { {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82545EM_FIBER}, {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82546EB_FIBER}, {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82540EM_LOM}, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82541ER}, }; /* Function forward declarations */ @@ -512,6 +513,11 @@ e1000_read_mac_addr(struct eth_device *nic) /* Invert the last bit if this is the second device */ nic->enetaddr[5] += 1; } +#ifdef CONFIG_E1000_FALLBACK_MAC + if ( *(u32*)(nic->enetaddr) == 0 || *(u32*)(nic->enetaddr) == ~0 ) + for ( i=0; i < NODE_ADDRESS_SIZE; i++ ) + nic->enetaddr[i] = (CONFIG_E1000_FALLBACK_MAC >> (8*(5-i))) & 0xff; +#endif #else /* * The AP1000's e1000 has no eeprom; the MAC address is stored in the @@ -639,6 +645,9 @@ e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82546EB_FIBER: hw->mac_type = e1000_82546; break; + case E1000_DEV_ID_82541ER: + hw->mac_type = e1000_82541_rev_2; + break; default: /* Should never have loaded on this device */ return -E1000_ERR_MAC_TYPE; @@ -1052,12 +1061,12 @@ e1000_setup_fiber_link(struct eth_device *nic) * configure the two flow control enable bits in the CTRL register. * * The possible values of the "fc" parameter are: - * 0: Flow control is completely disabled - * 1: Rx flow control is enabled (we can receive pause frames, but - * not send pause frames). - * 2: Tx flow control is enabled (we can send pause frames but we do - * not support receiving pause frames). - * 3: Both Rx and TX flow control (symmetric) are enabled. + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames, but + * not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames but we do + * not support receiving pause frames). + * 3: Both Rx and TX flow control (symmetric) are enabled. */ switch (hw->fc) { case e1000_fc_none: @@ -1220,7 +1229,7 @@ e1000_setup_copper_link(struct eth_device *nic) #if 0 /* Options: * disable_polarity_correction = 0 (default) - * Automatic Correction for Reversed Cable Polarity + * Automatic Correction for Reversed Cable Polarity * 0 - Disabled * 1 - Enabled */ @@ -1262,14 +1271,14 @@ e1000_setup_copper_link(struct eth_device *nic) /* Options: * autoneg = 1 (default) - * PHY will advertise value(s) parsed from - * autoneg_advertised and fc + * PHY will advertise value(s) parsed from + * autoneg_advertised and fc * autoneg = 0 - * PHY will be set to 10H, 10F, 100H, or 100F - * depending on value parsed from forced_speed_duplex. + * PHY will be set to 10H, 10F, 100H, or 100F + * depending on value parsed from forced_speed_duplex. */ - /* Is autoneg enabled? This is enabled by default or by software override. + /* Is autoneg enabled? This is enabled by default or by software override. * If so, call e1000_phy_setup_autoneg routine to parse the * autoneg_advertised and fc options. If autoneg is NOT enabled, then the * user should have provided a speed/duplex override. If so, then call @@ -1344,11 +1353,11 @@ e1000_setup_copper_link(struct eth_device *nic) if (phy_data & MII_SR_LINK_STATUS) { /* We have link, so we need to finish the config process: * 1) Set up the MAC to the current PHY speed/duplex - * if we are on 82543. If we - * are on newer silicon, we only need to configure - * collision distance in the Transmit Control Register. + * if we are on 82543. If we + * are on newer silicon, we only need to configure + * collision distance in the Transmit Control Register. * 2) Set up flow control on the MAC to that established with - * the link partner. + * the link partner. */ if (hw->mac_type >= e1000_82544) { e1000_config_collision_dist(hw); @@ -1409,7 +1418,7 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw) /* First we clear all the 10/100 mb speed bits in the Auto-Neg * Advertisement Register (Address 4) and the 1000 mb speed bits in - * the 1000Base-T Control Register (Address 9). + * the 1000Base-T Control Register (Address 9). */ mii_autoneg_adv_reg &= ~REG4_SPEED_MASK; mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK; @@ -1459,14 +1468,14 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw) * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation. * * The possible values of the "fc" parameter are: - * 0: Flow control is completely disabled - * 1: Rx flow control is enabled (we can receive pause frames - * but not send pause frames). - * 2: Tx flow control is enabled (we can send pause frames - * but we do not support receiving pause frames). - * 3: Both Rx and TX flow control (symmetric) are enabled. + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * but we do not support receiving pause frames). + * 3: Both Rx and TX flow control (symmetric) are enabled. * other: No software override. The flow control configuration - * in the EEPROM is used. + * in the EEPROM is used. */ switch (hw->fc) { case e1000_fc_none: /* 0 */ @@ -1621,12 +1630,12 @@ e1000_force_mac_fc(struct e1000_hw *hw) * according to the "hw->fc" parameter. * * The possible values of the "fc" parameter are: - * 0: Flow control is completely disabled - * 1: Rx flow control is enabled (we can receive pause - * frames but not send pause frames). - * 2: Tx flow control is enabled (we can send pause frames - * frames but we do not receive pause frames). - * 3: Both Rx and TX flow control (symmetric) is enabled. + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause + * frames but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * frames but we do not receive pause frames). + * 3: Both Rx and TX flow control (symmetric) is enabled. * other: No other values should be possible at this point. */ @@ -1743,14 +1752,14 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw) * LOCAL DEVICE | LINK PARTNER * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution *-------|---------|-------|---------|-------------------- - * 0 | 0 | DC | DC | e1000_fc_none - * 0 | 1 | 0 | DC | e1000_fc_none - * 0 | 1 | 1 | 0 | e1000_fc_none - * 0 | 1 | 1 | 1 | e1000_fc_tx_pause - * 1 | 0 | 0 | DC | e1000_fc_none - * 1 | DC | 1 | DC | e1000_fc_full - * 1 | 1 | 0 | 0 | e1000_fc_none - * 1 | 1 | 0 | 1 | e1000_fc_rx_pause + * 0 | 0 | DC | DC | e1000_fc_none + * 0 | 1 | 0 | DC | e1000_fc_none + * 0 | 1 | 1 | 0 | e1000_fc_none + * 0 | 1 | 1 | 1 | e1000_fc_tx_pause + * 1 | 0 | 0 | DC | e1000_fc_none + * 1 | DC | 1 | DC | e1000_fc_full + * 1 | 1 | 0 | 0 | e1000_fc_none + * 1 | 1 | 0 | 1 | e1000_fc_rx_pause * */ /* Are both PAUSE bits set to 1? If so, this implies @@ -1762,7 +1771,7 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw) * LOCAL DEVICE | LINK PARTNER * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result *-------|---------|-------|---------|-------------------- - * 1 | DC | 1 | DC | e1000_fc_full + * 1 | DC | 1 | DC | e1000_fc_full * */ if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && @@ -1787,7 +1796,7 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw) * LOCAL DEVICE | LINK PARTNER * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result *-------|---------|-------|---------|-------------------- - * 0 | 1 | 1 | 1 | e1000_fc_tx_pause + * 0 | 1 | 1 | 1 | e1000_fc_tx_pause * */ else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) && @@ -1804,7 +1813,7 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw) * LOCAL DEVICE | LINK PARTNER * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result *-------|---------|-------|---------|-------------------- - * 1 | 1 | 0 | 1 | e1000_fc_rx_pause + * 1 | 1 | 0 | 1 | e1000_fc_rx_pause * */ else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && @@ -1846,7 +1855,7 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw) ("Flow Control = RX PAUSE frames only.\r\n"); } - /* Now we need to do one last check... If we auto- + /* Now we need to do one last check... If we auto- * negotiated to HALF DUPLEX, flow control should not be * enabled per IEEE 802.3 spec. */ @@ -1910,7 +1919,7 @@ e1000_check_for_link(struct eth_device *nic) /* If we have a copper PHY then we only want to go out to the PHY * registers to see if Auto-Neg has completed and/or if our link - * status has changed. The get_link_status flag will be set if we + * status has changed. The get_link_status flag will be set if we * receive a Link Status Change interrupt or we have Rx Sequence * Errors. */ @@ -1967,7 +1976,7 @@ e1000_check_for_link(struct eth_device *nic) /* At this point we know that we are on copper and we have * auto-negotiated link. These are conditions for checking the link - * parter capability register. We use the link partner capability to + * parter capability register. We use the link partner capability to * determine if TBI Compatibility needs to be turned on or off. If * the link partner advertises any speed in addition to Gigabit, then * we assume that they are GMII-based, and TBI compatibility is not @@ -2485,6 +2494,35 @@ e1000_phy_reset(struct e1000_hw *hw) return 0; } +static int e1000_set_phy_type (struct e1000_hw *hw) +{ + DEBUGFUNC (); + + if (hw->mac_type == e1000_undefined) + return -E1000_ERR_PHY_TYPE; + + switch (hw->phy_id) { + case M88E1000_E_PHY_ID: + case M88E1000_I_PHY_ID: + case M88E1011_I_PHY_ID: + hw->phy_type = e1000_phy_m88; + break; + case IGP01E1000_I_PHY_ID: + if (hw->mac_type == e1000_82541 || + hw->mac_type == e1000_82541_rev_2) { + hw->phy_type = e1000_phy_igp; + break; + } + /* Fall Through */ + default: + /* Should never have loaded on this device */ + hw->phy_type = e1000_phy_undefined; + return -E1000_ERR_PHY_TYPE; + } + + return E1000_SUCCESS; +} + /****************************************************************************** * Probes the expected PHY address for known PHY IDs * @@ -2493,6 +2531,7 @@ e1000_phy_reset(struct e1000_hw *hw) static int e1000_detect_gig_phy(struct e1000_hw *hw) { + int32_t phy_init_status; uint16_t phy_id_high, phy_id_low; int match = FALSE; @@ -2526,11 +2565,19 @@ e1000_detect_gig_phy(struct e1000_hw *hw) if (hw->phy_id == M88E1011_I_PHY_ID) match = TRUE; break; + case e1000_82541_rev_2: + if(hw->phy_id == IGP01E1000_I_PHY_ID) + match = TRUE; + + break; default: DEBUGOUT("Invalid MAC type %d\n", hw->mac_type); return -E1000_ERR_CONFIG; } - if (match) { + + phy_init_status = e1000_set_phy_type(hw); + + if ((match) && (phy_init_status == E1000_SUCCESS)) { DEBUGOUT("PHY ID 0x%X detected\n", hw->phy_id); return 0; } @@ -2777,8 +2824,8 @@ e1000_configure_rx(struct e1000_hw *hw) #endif /* Set the interrupt throttling rate. Value is calculated * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */ -#define MAX_INTS_PER_SEC 8000 -#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256) +#define MAX_INTS_PER_SEC 8000 +#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256) E1000_WRITE_REG(hw, ITR, DEFAULT_ITR); } @@ -2985,7 +3032,7 @@ e1000_initialize(bd_t * bis) free(nic); return 0; } -#ifndef CONFIG_AP1000 +#if !(defined(CONFIG_AP1000) || defined(CONFIG_MVBC_1G)) if (e1000_validate_eeprom_checksum(nic) < 0) { printf("The EEPROM Checksum Is Not Valid\n"); free(hw); diff --git a/drivers/net/e1000.h b/drivers/net/e1000.h index 0fbdc90b1..822afc566 100644 --- a/drivers/net/e1000.h +++ b/drivers/net/e1000.h @@ -71,6 +71,8 @@ typedef enum { e1000_82540, e1000_82545, e1000_82546, + e1000_82541, + e1000_82541_rev_2, e1000_num_macs } e1000_mac_type; @@ -168,6 +170,13 @@ typedef enum { e1000_1000t_rx_status_undefined = 0xFF } e1000_1000t_rx_status; +typedef enum { + e1000_phy_m88 = 0, + e1000_phy_igp, + e1000_phy_igp_2, + e1000_phy_undefined = 0xFF +} e1000_phy_type; + struct e1000_phy_info { e1000_cable_length cable_length; e1000_10bt_ext_dist_enable extended_10bt_distance; @@ -184,14 +193,19 @@ struct e1000_phy_stats { }; /* Error Codes */ -#define E1000_SUCCESS 0 -#define E1000_ERR_EEPROM 1 -#define E1000_ERR_PHY 2 -#define E1000_ERR_CONFIG 3 -#define E1000_ERR_PARAM 4 -#define E1000_ERR_MAC_TYPE 5 -#define E1000_ERR_NOLINK 6 -#define E1000_ERR_TIMEOUT 7 +#define E1000_SUCCESS 0 +#define E1000_ERR_EEPROM 1 +#define E1000_ERR_PHY 2 +#define E1000_ERR_CONFIG 3 +#define E1000_ERR_PARAM 4 +#define E1000_ERR_MAC_TYPE 5 +#define E1000_ERR_PHY_TYPE 6 +#define E1000_ERR_NOLINK 7 +#define E1000_ERR_TIMEOUT 8 +#define E1000_ERR_RESET 9 +#define E1000_ERR_MASTER_REQUESTS_PENDING 10 +#define E1000_ERR_HOST_INTERFACE_COMMAND 11 +#define E1000_BLK_PHY_RESET 12 /* PCI Device IDs */ #define E1000_DEV_ID_82542 0x1000 @@ -207,7 +221,8 @@ struct e1000_phy_stats { #define E1000_DEV_ID_82545EM_FIBER 0x1011 #define E1000_DEV_ID_82546EB_COPPER 0x1010 #define E1000_DEV_ID_82546EB_FIBER 0x1012 -#define NUM_DEV_IDS 13 +#define E1000_DEV_ID_82541ER 0x1078 +#define NUM_DEV_IDS 14 #define NODE_ADDRESS_SIZE 6 #define ETH_LENGTH_OF_ADDRESS 6 @@ -799,6 +814,8 @@ struct e1000_hw { pci_dev_t pdev; uint8_t *hw_addr; e1000_mac_type mac_type; + e1000_phy_type phy_type; + uint32_t phy_init_script; e1000_media_type media_type; e1000_lan_loc lan_loc; e1000_fc_type fc; @@ -1517,7 +1534,22 @@ struct e1000_hw { #define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */ #define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */ -#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ +#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ + +/* IGP01E1000 specifics */ +#define IGP01E1000_IEEE_REGS_PAGE 0x0000 +#define IGP01E1000_IEEE_RESTART_AUTONEG 0x3300 +#define IGP01E1000_IEEE_FORCE_GIGA 0x0140 + +/* IGP01E1000 Specific Registers */ +#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* PHY Specific Port Config Register */ +#define IGP01E1000_PHY_PORT_STATUS 0x11 /* PHY Specific Status Register */ +#define IGP01E1000_PHY_PORT_CTRL 0x12 /* PHY Specific Control Register */ +#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health Register */ +#define IGP01E1000_GMII_FIFO 0x14 /* GMII FIFO Register */ +#define IGP01E1000_PHY_CHANNEL_QUALITY 0x15 /* PHY Channel Quality Register */ +#define IGP02E1000_PHY_POWER_MGMT 0x19 +#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* PHY Page Select Core Register */ /* PHY Control Register */ #define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ @@ -1729,6 +1761,7 @@ struct e1000_hw { #define M88E1011_I_PHY_ID 0x01410C20 #define M88E1000_12_PHY_ID M88E1000_E_PHY_ID #define M88E1000_14_PHY_ID M88E1000_E_PHY_ID +#define IGP01E1000_I_PHY_ID 0x02A80380 /* Miscellaneous PHY bit definitions. */ #define PHY_PREAMBLE 0xFFFFFFFF diff --git a/drivers/net/greth.c b/drivers/net/greth.c new file mode 100644 index 000000000..76ece59b3 --- /dev/null +++ b/drivers/net/greth.c @@ -0,0 +1,661 @@ +/* Gaisler.com GRETH 10/100/1000 Ethernet MAC driver + * + * Driver use polling mode (no Interrupt) + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <common.h> +#include <command.h> +#include <net.h> +#include <malloc.h> +#include <asm/processor.h> +#include <ambapp.h> +#include <asm/leon.h> + +/* #define DEBUG */ + +#include "greth.h" + +/* Default to 3s timeout on autonegotiation */ +#ifndef GRETH_PHY_TIMEOUT_MS +#define GRETH_PHY_TIMEOUT_MS 3000 +#endif + +/* ByPass Cache when reading regs */ +#define GRETH_REGLOAD(addr) SPARC_NOCACHE_READ(addr) +/* Write-through cache ==> no bypassing needed on writes */ +#define GRETH_REGSAVE(addr,data) (*(unsigned int *)(addr) = (data)) +#define GRETH_REGORIN(addr,data) GRETH_REGSAVE(addr,GRETH_REGLOAD(addr)|data) +#define GRETH_REGANDIN(addr,data) GRETH_REGSAVE(addr,GRETH_REGLOAD(addr)&data) + +#define GRETH_RXBD_CNT 4 +#define GRETH_TXBD_CNT 1 + +#define GRETH_RXBUF_SIZE 1540 +#define GRETH_BUF_ALIGN 4 +#define GRETH_RXBUF_EFF_SIZE \ + ( (GRETH_RXBUF_SIZE&~(GRETH_BUF_ALIGN-1))+GRETH_BUF_ALIGN ) + +typedef struct { + greth_regs *regs; + int irq; + struct eth_device *dev; + + /* Hardware info */ + unsigned char phyaddr; + int gbit_mac; + + /* Current operating Mode */ + int gb; /* GigaBit */ + int fd; /* Full Duplex */ + int sp; /* 10/100Mbps speed (1=100,0=10) */ + int auto_neg; /* Auto negotiate done */ + + unsigned char hwaddr[6]; /* MAC Address */ + + /* Descriptors */ + greth_bd *rxbd_base, *rxbd_max; + greth_bd *txbd_base, *txbd_max; + + greth_bd *rxbd_curr; + + /* rx buffers in rx descriptors */ + void *rxbuf_base; /* (GRETH_RXBUF_SIZE+ALIGNBYTES) * GRETH_RXBD_CNT */ + + /* unused for gbit_mac, temp buffer for sending packets with unligned + * start. + * Pointer to packet allocated with malloc. + */ + void *txbuf; + + struct { + /* rx status */ + unsigned int rx_packets, + rx_crc_errors, rx_frame_errors, rx_length_errors, rx_errors; + + /* tx stats */ + unsigned int tx_packets, + tx_latecol_errors, + tx_underrun_errors, tx_limit_errors, tx_errors; + } stats; +} greth_priv; + +/* Read MII register 'addr' from core 'regs' */ +static int read_mii(int addr, volatile greth_regs * regs) +{ + while (GRETH_REGLOAD(®s->mdio) & GRETH_MII_BUSY) { + } + + GRETH_REGSAVE(®s->mdio, (0 << 11) | ((addr & 0x1F) << 6) | 2); + + while (GRETH_REGLOAD(®s->mdio) & GRETH_MII_BUSY) { + } + + if (!(GRETH_REGLOAD(®s->mdio) & GRETH_MII_NVALID)) { + return (GRETH_REGLOAD(®s->mdio) >> 16) & 0xFFFF; + } else { + return -1; + } +} + +static void write_mii(int addr, int data, volatile greth_regs * regs) +{ + while (GRETH_REGLOAD(®s->mdio) & GRETH_MII_BUSY) { + } + + GRETH_REGSAVE(®s->mdio, + ((data & 0xFFFF) << 16) | (0 << 11) | ((addr & 0x1F) << 6) + | 1); + + while (GRETH_REGLOAD(®s->mdio) & GRETH_MII_BUSY) { + } + +} + +/* init/start hardware and allocate descriptor buffers for rx side + * + */ +int greth_init(struct eth_device *dev, bd_t * bis) +{ + int i; + + greth_priv *greth = dev->priv; + greth_regs *regs = greth->regs; +#ifdef DEBUG + printf("greth_init\n"); +#endif + + GRETH_REGSAVE(®s->control, 0); + + if (!greth->rxbd_base) { + + /* allocate descriptors */ + greth->rxbd_base = (greth_bd *) + memalign(0x1000, GRETH_RXBD_CNT * sizeof(greth_bd)); + greth->txbd_base = (greth_bd *) + memalign(0x1000, GRETH_RXBD_CNT * sizeof(greth_bd)); + + /* allocate buffers to all descriptors */ + greth->rxbuf_base = + malloc(GRETH_RXBUF_EFF_SIZE * GRETH_RXBD_CNT); + } + + /* initate rx decriptors */ + for (i = 0; i < GRETH_RXBD_CNT; i++) { + greth->rxbd_base[i].addr = (unsigned int) + greth->rxbuf_base + (GRETH_RXBUF_EFF_SIZE * i); + /* enable desciptor & set wrap bit if last descriptor */ + if (i >= (GRETH_RXBD_CNT - 1)) { + greth->rxbd_base[i].stat = GRETH_BD_EN | GRETH_BD_WR; + } else { + greth->rxbd_base[i].stat = GRETH_BD_EN; + } + } + + /* initiate indexes */ + greth->rxbd_curr = greth->rxbd_base; + greth->rxbd_max = greth->rxbd_base + (GRETH_RXBD_CNT - 1); + greth->txbd_max = greth->txbd_base + (GRETH_TXBD_CNT - 1); + /* + * greth->txbd_base->addr = 0; + * greth->txbd_base->stat = GRETH_BD_WR; + */ + + /* initate tx decriptors */ + for (i = 0; i < GRETH_TXBD_CNT; i++) { + greth->txbd_base[i].addr = 0; + /* enable desciptor & set wrap bit if last descriptor */ + if (i >= (GRETH_RXBD_CNT - 1)) { + greth->txbd_base[i].stat = GRETH_BD_WR; + } else { + greth->txbd_base[i].stat = 0; + } + } + + /**** SET HARDWARE REGS ****/ + + /* Set pointer to tx/rx descriptor areas */ + GRETH_REGSAVE(®s->rx_desc_p, (unsigned int)&greth->rxbd_base[0]); + GRETH_REGSAVE(®s->tx_desc_p, (unsigned int)&greth->txbd_base[0]); + + /* Enable Transmitter, GRETH will now scan descriptors for packets + * to transmitt */ +#ifdef DEBUG + printf("greth_init: enabling receiver\n"); +#endif + GRETH_REGORIN(®s->control, GRETH_RXEN); + + return 0; +} + +/* Initiate PHY to a relevant speed + * return: + * - 0 = success + * - 1 = timeout/fail + */ +int greth_init_phy(greth_priv * dev, bd_t * bis) +{ + greth_regs *regs = dev->regs; + int tmp, tmp1, tmp2, i; + unsigned int start, timeout; + + /* X msecs to ticks */ + timeout = usec2ticks(GRETH_PHY_TIMEOUT_MS * 1000); + + /* Get system timer0 current value + * Total timeout is 5s + */ + start = get_timer(0); + + /* get phy control register default values */ + + while ((tmp = read_mii(0, regs)) & 0x8000) { + if (get_timer(start) > timeout) + return 1; /* Fail */ + } + + /* reset PHY and wait for completion */ + write_mii(0, 0x8000 | tmp, regs); + + while (((tmp = read_mii(0, regs))) & 0x8000) { + if (get_timer(start) > timeout) + return 1; /* Fail */ + } + + /* Check if PHY is autoneg capable and then determine operating + * mode, otherwise force it to 10 Mbit halfduplex + */ + dev->gb = 0; + dev->fd = 0; + dev->sp = 0; + dev->auto_neg = 0; + if (!((tmp >> 12) & 1)) { + write_mii(0, 0, regs); + } else { + /* wait for auto negotiation to complete and then check operating mode */ + dev->auto_neg = 1; + i = 0; + while (!(((tmp = read_mii(1, regs)) >> 5) & 1)) { + if (get_timer(start) > timeout) { + printf("Auto negotiation timed out. " + "Selecting default config\n"); + tmp = read_mii(0, regs); + dev->gb = ((tmp >> 6) & 1) + && !((tmp >> 13) & 1); + dev->sp = !((tmp >> 6) & 1) + && ((tmp >> 13) & 1); + dev->fd = (tmp >> 8) & 1; + goto auto_neg_done; + } + } + if ((tmp >> 8) & 1) { + tmp1 = read_mii(9, regs); + tmp2 = read_mii(10, regs); + if ((tmp1 & GRETH_MII_EXTADV_1000FD) && + (tmp2 & GRETH_MII_EXTPRT_1000FD)) { + dev->gb = 1; + dev->fd = 1; + } + if ((tmp1 & GRETH_MII_EXTADV_1000HD) && + (tmp2 & GRETH_MII_EXTPRT_1000HD)) { + dev->gb = 1; + dev->fd = 0; + } + } + if ((dev->gb == 0) || ((dev->gb == 1) && (dev->gbit_mac == 0))) { + tmp1 = read_mii(4, regs); + tmp2 = read_mii(5, regs); + if ((tmp1 & GRETH_MII_100TXFD) && + (tmp2 & GRETH_MII_100TXFD)) { + dev->sp = 1; + dev->fd = 1; + } + if ((tmp1 & GRETH_MII_100TXHD) && + (tmp2 & GRETH_MII_100TXHD)) { + dev->sp = 1; + dev->fd = 0; + } + if ((tmp1 & GRETH_MII_10FD) && (tmp2 & GRETH_MII_10FD)) { + dev->fd = 1; + } + if ((dev->gb == 1) && (dev->gbit_mac == 0)) { + dev->gb = 0; + dev->fd = 0; + write_mii(0, dev->sp << 13, regs); + } + } + + } + auto_neg_done: +#ifdef DEBUG + printf("%s GRETH Ethermac at [0x%x] irq %d. Running \ + %d Mbps %s duplex\n", dev->gbit_mac ? "10/100/1000" : "10/100", (unsigned int)(regs), (unsigned int)(dev->irq), dev->gb ? 1000 : (dev->sp ? 100 : 10), dev->fd ? "full" : "half"); +#endif + /* Read out PHY info if extended registers are available */ + if (tmp & 1) { + tmp1 = read_mii(2, regs); + tmp2 = read_mii(3, regs); + tmp1 = (tmp1 << 6) | ((tmp2 >> 10) & 0x3F); + tmp = tmp2 & 0xF; + + tmp2 = (tmp2 >> 4) & 0x3F; +#ifdef DEBUG + printf("PHY: Vendor %x Device %x Revision %d\n", tmp1, + tmp2, tmp); +#endif + } else { + printf("PHY info not available\n"); + } + + /* set speed and duplex bits in control register */ + GRETH_REGORIN(®s->control, + (dev->gb << 8) | (dev->sp << 7) | (dev->fd << 4)); + + return 0; +} + +void greth_halt(struct eth_device *dev) +{ + greth_priv *greth; + greth_regs *regs; + int i; +#ifdef DEBUG + printf("greth_halt\n"); +#endif + if (!dev || !dev->priv) + return; + + greth = dev->priv; + regs = greth->regs; + + if (!regs) + return; + + /* disable receiver/transmitter by clearing the enable bits */ + GRETH_REGANDIN(®s->control, ~(GRETH_RXEN | GRETH_TXEN)); + + /* reset rx/tx descriptors */ + if (greth->rxbd_base) { + for (i = 0; i < GRETH_RXBD_CNT; i++) { + greth->rxbd_base[i].stat = + (i >= (GRETH_RXBD_CNT - 1)) ? GRETH_BD_WR : 0; + } + } + + if (greth->txbd_base) { + for (i = 0; i < GRETH_TXBD_CNT; i++) { + greth->txbd_base[i].stat = + (i >= (GRETH_TXBD_CNT - 1)) ? GRETH_BD_WR : 0; + } + } +} + +int greth_send(struct eth_device *dev, volatile void *eth_data, int data_length) +{ + greth_priv *greth = dev->priv; + greth_regs *regs = greth->regs; + greth_bd *txbd; + void *txbuf; + unsigned int status; +#ifdef DEBUG + printf("greth_send\n"); +#endif + /* send data, wait for data to be sent, then return */ + if (((unsigned int)eth_data & (GRETH_BUF_ALIGN - 1)) + && !greth->gbit_mac) { + /* data not aligned as needed by GRETH 10/100, solve this by allocating 4 byte aligned buffer + * and copy data to before giving it to GRETH. + */ + if (!greth->txbuf) { + greth->txbuf = malloc(GRETH_RXBUF_SIZE); +#ifdef DEBUG + printf("GRETH: allocated aligned tx-buf\n"); +#endif + } + + txbuf = greth->txbuf; + + /* copy data info buffer */ + memcpy((char *)txbuf, (char *)eth_data, data_length); + + /* keep buffer to next time */ + } else { + txbuf = (void *)eth_data; + } + /* get descriptor to use, only 1 supported... hehe easy */ + txbd = greth->txbd_base; + + /* setup descriptor to wrap around to it self */ + txbd->addr = (unsigned int)txbuf; + txbd->stat = GRETH_BD_EN | GRETH_BD_WR | data_length; + + /* Remind Core which descriptor to use when sending */ + GRETH_REGSAVE(®s->tx_desc_p, (unsigned int)txbd); + + /* initate send by enabling transmitter */ + GRETH_REGORIN(®s->control, GRETH_TXEN); + + /* Wait for data to be sent */ + while ((status = GRETH_REGLOAD(&txbd->stat)) & GRETH_BD_EN) { + ; + } + + /* was the packet transmitted succesfully? */ + if (status & GRETH_TXBD_ERR_AL) { + greth->stats.tx_limit_errors++; + } + + if (status & GRETH_TXBD_ERR_UE) { + greth->stats.tx_underrun_errors++; + } + + if (status & GRETH_TXBD_ERR_LC) { + greth->stats.tx_latecol_errors++; + } + + if (status & + (GRETH_TXBD_ERR_LC | GRETH_TXBD_ERR_UE | GRETH_TXBD_ERR_AL)) { + /* any error */ + greth->stats.tx_errors++; + return -1; + } + + /* bump tx packet counter */ + greth->stats.tx_packets++; + + /* return succefully */ + return 0; +} + +int greth_recv(struct eth_device *dev) +{ + greth_priv *greth = dev->priv; + greth_regs *regs = greth->regs; + greth_bd *rxbd; + unsigned int status, len = 0, bad; + unsigned char *d; + int enable = 0; + int i; +#ifdef DEBUG +/* printf("greth_recv\n"); */ +#endif + /* Receive One packet only, but clear as many error packets as there are + * available. + */ + { + /* current receive descriptor */ + rxbd = greth->rxbd_curr; + + /* get status of next received packet */ + status = GRETH_REGLOAD(&rxbd->stat); + + bad = 0; + + /* stop if no more packets received */ + if (status & GRETH_BD_EN) { + goto done; + } +#ifdef DEBUG + printf("greth_recv: packet 0x%lx, 0x%lx, len: %d\n", + (unsigned int)rxbd, status, status & GRETH_BD_LEN); +#endif + + /* Check status for errors. + */ + if (status & GRETH_RXBD_ERR_FT) { + greth->stats.rx_length_errors++; + bad = 1; + } + if (status & (GRETH_RXBD_ERR_AE | GRETH_RXBD_ERR_OE)) { + greth->stats.rx_frame_errors++; + bad = 1; + } + if (status & GRETH_RXBD_ERR_CRC) { + greth->stats.rx_crc_errors++; + bad = 1; + } + if (bad) { + greth->stats.rx_errors++; + printf + ("greth_recv: Bad packet (%d, %d, %d, 0x%08x, %d)\n", + greth->stats.rx_length_errors, + greth->stats.rx_frame_errors, + greth->stats.rx_crc_errors, status, + greth->stats.rx_packets); + /* print all rx descriptors */ + for (i = 0; i < GRETH_RXBD_CNT; i++) { + printf("[%d]: Stat=0x%lx, Addr=0x%lx\n", i, + GRETH_REGLOAD(&greth->rxbd_base[i].stat), + GRETH_REGLOAD(&greth->rxbd_base[i]. + addr)); + } + } else { + /* Process the incoming packet. */ + len = status & GRETH_BD_LEN; + d = (char *)rxbd->addr; +#ifdef DEBUG + printf + ("greth_recv: new packet, length: %d. data: %x %x %x %x %x %x %x %x\n", + len, d[0], d[1], d[2], d[3], d[4], d[5], d[6], + d[7]); +#endif + /* flush all data cache to make sure we're not reading old packet data */ + sparc_dcache_flush_all(); + + /* pass packet on to network subsystem */ + NetReceive((void *)d, len); + + /* bump stats counters */ + greth->stats.rx_packets++; + + /* bad is now 0 ==> will stop loop */ + } + + /* reenable descriptor to receive more packet with this descriptor, wrap around if needed */ + rxbd->stat = + GRETH_BD_EN | + (((unsigned int)greth->rxbd_curr >= + (unsigned int)greth->rxbd_max) ? GRETH_BD_WR : 0); + enable = 1; + + /* increase index */ + greth->rxbd_curr = + ((unsigned int)greth->rxbd_curr >= + (unsigned int)greth->rxbd_max) ? greth-> + rxbd_base : (greth->rxbd_curr + 1); + + }; + + if (enable) { + GRETH_REGORIN(®s->control, GRETH_RXEN); + } + done: + /* return positive length of packet or 0 if non recieved */ + return len; +} + +void greth_set_hwaddr(greth_priv * greth, unsigned char *mac) +{ + /* save new MAC address */ + greth->dev->enetaddr[0] = greth->hwaddr[0] = mac[0]; + greth->dev->enetaddr[1] = greth->hwaddr[1] = mac[1]; + greth->dev->enetaddr[2] = greth->hwaddr[2] = mac[2]; + greth->dev->enetaddr[3] = greth->hwaddr[3] = mac[3]; + greth->dev->enetaddr[4] = greth->hwaddr[4] = mac[4]; + greth->dev->enetaddr[5] = greth->hwaddr[5] = mac[5]; + greth->regs->esa_msb = (mac[0] << 8) | mac[1]; + greth->regs->esa_lsb = + (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5]; +#ifdef DEBUG + printf("GRETH: New MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); +#endif +} + +int greth_initialize(bd_t * bis) +{ + greth_priv *greth; + ambapp_apbdev apbdev; + struct eth_device *dev; + int i; + char *addr_str, *end; + unsigned char addr[6]; +#ifdef DEBUG + printf("Scanning for GRETH\n"); +#endif + /* Find Device & IRQ via AMBA Plug&Play information */ + if (ambapp_apb_first(VENDOR_GAISLER, GAISLER_ETHMAC, &apbdev) != 1) { + return -1; /* GRETH not found */ + } + + greth = (greth_priv *) malloc(sizeof(greth_priv)); + dev = (struct eth_device *)malloc(sizeof(struct eth_device)); + memset(dev, 0, sizeof(struct eth_device)); + memset(greth, 0, sizeof(greth_priv)); + + greth->regs = (greth_regs *) apbdev.address; + greth->irq = apbdev.irq; +#ifdef DEBUG + printf("Found GRETH at 0x%lx, irq %d\n", greth->regs, greth->irq); +#endif + dev->priv = (void *)greth; + dev->iobase = (unsigned int)greth->regs; + dev->init = greth_init; + dev->halt = greth_halt; + dev->send = greth_send; + dev->recv = greth_recv; + greth->dev = dev; + + /* Reset Core */ + GRETH_REGSAVE(&greth->regs->control, GRETH_RESET); + + /* Wait for core to finish reset cycle */ + while (GRETH_REGLOAD(&greth->regs->control) & GRETH_RESET) ; + + /* Get the phy address which assumed to have been set + correctly with the reset value in hardware */ + greth->phyaddr = (GRETH_REGLOAD(&greth->regs->mdio) >> 11) & 0x1F; + + /* Check if mac is gigabit capable */ + greth->gbit_mac = (GRETH_REGLOAD(&greth->regs->control) >> 27) & 1; + + /* Make descriptor string */ + if (greth->gbit_mac) { + sprintf(dev->name, "GRETH 10/100/GB"); + } else { + sprintf(dev->name, "GRETH 10/100"); + } + + /* initiate PHY, select speed/duplex depending on connected PHY */ + if (greth_init_phy(greth, bis)) { + /* Failed to init PHY (timedout) */ + return -1; + } + + /* Register Device to EtherNet subsystem */ + eth_register(dev); + + /* Get MAC address */ + if ((addr_str = getenv("ethaddr")) != NULL) { + for (i = 0; i < 6; i++) { + addr[i] = + addr_str ? simple_strtoul(addr_str, &end, 16) : 0; + if (addr_str) { + addr_str = (*end) ? end + 1 : end; + } + } + } else { + /* HW Address not found in environment, Set default HW address */ + addr[0] = GRETH_HWADDR_0; /* MSB */ + addr[1] = GRETH_HWADDR_1; + addr[2] = GRETH_HWADDR_2; + addr[3] = GRETH_HWADDR_3; + addr[4] = GRETH_HWADDR_4; + addr[5] = GRETH_HWADDR_5; /* LSB */ + } + + /* set and remember MAC address */ + greth_set_hwaddr(greth, addr); + + return 1; +} diff --git a/drivers/net/greth.h b/drivers/net/greth.h new file mode 100644 index 000000000..7d5fbd327 --- /dev/null +++ b/drivers/net/greth.h @@ -0,0 +1,97 @@ +/* Gaisler.com GRETH 10/100/1000 Ethernet MAC driver + * + * (C) Copyright 2007 + * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 + */ + +#define GRETH_FD 0x10 +#define GRETH_RESET 0x40 +#define GRETH_MII_BUSY 0x8 +#define GRETH_MII_NVALID 0x10 + +/* MII registers */ +#define GRETH_MII_EXTADV_1000FD 0x00000200 +#define GRETH_MII_EXTADV_1000HD 0x00000100 +#define GRETH_MII_EXTPRT_1000FD 0x00000800 +#define GRETH_MII_EXTPRT_1000HD 0x00000400 + +#define GRETH_MII_100T4 0x00000200 +#define GRETH_MII_100TXFD 0x00000100 +#define GRETH_MII_100TXHD 0x00000080 +#define GRETH_MII_10FD 0x00000040 +#define GRETH_MII_10HD 0x00000020 + +#define GRETH_BD_EN 0x800 +#define GRETH_BD_WR 0x1000 +#define GRETH_BD_IE 0x2000 +#define GRETH_BD_LEN 0x7FF + +#define GRETH_TXEN 0x1 +#define GRETH_INT_TX 0x8 +#define GRETH_TXI 0x4 +#define GRETH_TXBD_STATUS 0x0001C000 +#define GRETH_TXBD_MORE 0x20000 +#define GRETH_TXBD_IPCS 0x40000 +#define GRETH_TXBD_TCPCS 0x80000 +#define GRETH_TXBD_UDPCS 0x100000 +#define GRETH_TXBD_ERR_LC 0x10000 +#define GRETH_TXBD_ERR_UE 0x4000 +#define GRETH_TXBD_ERR_AL 0x8000 +#define GRETH_TXBD_NUM 128 +#define GRETH_TXBD_NUM_MASK (GRETH_TXBD_NUM-1) +#define GRETH_TX_BUF_SIZE 2048 + +#define GRETH_INT_RX 0x4 +#define GRETH_RXEN 0x2 +#define GRETH_RXI 0x8 +#define GRETH_RXBD_STATUS 0xFFFFC000 +#define GRETH_RXBD_ERR_AE 0x4000 +#define GRETH_RXBD_ERR_FT 0x8000 +#define GRETH_RXBD_ERR_CRC 0x10000 +#define GRETH_RXBD_ERR_OE 0x20000 +#define GRETH_RXBD_ERR_LE 0x40000 +#define GRETH_RXBD_IP_DEC 0x80000 +#define GRETH_RXBD_IP_CSERR 0x100000 +#define GRETH_RXBD_UDP_DEC 0x200000 +#define GRETH_RXBD_UDP_CSERR 0x400000 +#define GRETH_RXBD_TCP_DEC 0x800000 +#define GRETH_RXBD_TCP_CSERR 0x1000000 + +#define GRETH_RXBD_NUM 128 +#define GRETH_RXBD_NUM_MASK (GRETH_RXBD_NUM-1) +#define GRETH_RX_BUF_SIZE 2048 + +/* Ethernet configuration registers */ +typedef struct _greth_regs { + volatile unsigned int control; + volatile unsigned int status; + volatile unsigned int esa_msb; + volatile unsigned int esa_lsb; + volatile unsigned int mdio; + volatile unsigned int tx_desc_p; + volatile unsigned int rx_desc_p; +} greth_regs; + +/* Ethernet buffer descriptor */ +typedef struct _greth_bd { + volatile unsigned int stat; + unsigned int addr; /* Buffer address not changed by HW */ +} greth_bd; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 9c98338f7..703784ee0 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -417,13 +417,13 @@ static int macb_init(struct eth_device *netdev, bd_t *bd) /* choose RMII or MII mode. This depends on the board */ #ifdef CONFIG_RMII -#ifdef CONFIG_AT91CAP9ADK +#if defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) macb_writel(macb, USRIO, MACB_BIT(RMII) | MACB_BIT(CLKEN)); #else macb_writel(macb, USRIO, 0); #endif #else -#ifdef CONFIG_AT91CAP9ADK +#if defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) macb_writel(macb, USRIO, MACB_BIT(CLKEN)); #else macb_writel(macb, USRIO, MACB_BIT(MII)); diff --git a/drivers/net/mcffec.c b/drivers/net/mcffec.c index 3b812585b..71d19608e 100644 --- a/drivers/net/mcffec.c +++ b/drivers/net/mcffec.c @@ -166,6 +166,13 @@ int fec_send(struct eth_device *dev, volatile void *packet, int length) /* Activate transmit Buffer Descriptor polling */ fecp->tdar = 0x01000000; /* Descriptor polling active */ + /* FEC fix for MCF5275, FEC unable to initial transmit data packet. + * A nop will ensure the descriptor polling active completed. + */ +#ifdef CONFIG_M5275 + __asm__ ("nop"); +#endif + #ifdef CFG_UNIFY_CACHE icache_invalid(); #endif diff --git a/drivers/net/ne2000.c b/drivers/net/ne2000.c index b10065753..d09da7829 100644 --- a/drivers/net/ne2000.c +++ b/drivers/net/ne2000.c @@ -1,11 +1,10 @@ /* -Ported to U-Boot by Christian Pellegrin <chri@ascensit.com> +Ported to U-Boot by Christian Pellegrin <chri@ascensit.com> 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 @@ -58,21 +57,19 @@ and are covered by the appropriate copyright disclaimers included herein. ========================================================================== #####DESCRIPTIONBEGIN#### -Author(s): gthomas -Contributors: gthomas, jskov, rsandifo -Date: 2001-06-13 +Author(s): gthomas +Contributors: gthomas, jskov, rsandifo +Date: 2001-06-13 Purpose: Description: -FIXME: Will fail if pinged with large packets (1520 bytes) +FIXME: Will fail if pinged with large packets (1520 bytes) Add promisc config Add SNMP ####DESCRIPTIONEND#### - ========================================================================== - */ #include <common.h> @@ -80,55 +77,46 @@ Add SNMP #include <net.h> #include <malloc.h> -#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 - - Set to perms of: - 0 disables all debug output - 1 for process debug output - 2 for added data IO output: get_reg, put_reg - 4 for packet allocation/free output - 8 for only startup status, so we can tell we're installed OK -*/ -/*#define DEBUG 0xf*/ + * Debugging details + * + * Set to perms of: + * 0 disables all debug output + * 1 for process debug output + * 2 for added data IO output: get_reg, put_reg + * 4 for packet allocation/free output + * 8 for only startup status, so we can tell we're installed OK + */ +#if 0 +#define DEBUG 0xf +#else #define DEBUG 0 +#endif #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) +#if defined(CONFIG_DRIVER_AX88796L) +/* AX88796L support */ +#include "ax88796.h" #else -#define PRINTK(args...) +/* Basic NE2000 chip support */ +#include "ne2000.h" #endif static dp83902a_priv_data_t nic; /* just one instance of the card supported */ @@ -137,32 +125,35 @@ static bool dp83902a_init(void) { dp83902a_priv_data_t *dp = &nic; - cyg_uint8* base; - int i; + u8* base; DEBUG_FUNCTION(); base = dp->base; - if (!base) return false; /* No device found */ + if (!base) + return false; /* No device found */ 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 */ + DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1); /* Select page 1 */ /* Use the address from the serial EEPROM */ for (i = 0; i < 6; i++) DP_IN(base, DP_P1_PAR0+i, dp->esa[i]); - DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0); /* Select page 0 */ + DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0); /* Select page 0 */ printf("NE2000 - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n", - "eeprom", - dp->esa[0], - dp->esa[1], - dp->esa[2], - dp->esa[3], - dp->esa[4], - dp->esa[5] ); + "eeprom", + dp->esa[0], + dp->esa[1], + dp->esa[2], + dp->esa[3], + dp->esa[4], + dp->esa[5] ); +#endif /* NE2000_BASIC_INIT */ return true; } @@ -170,11 +161,11 @@ static void dp83902a_stop(void) { dp83902a_priv_data_t *dp = &nic; - cyg_uint8 *base = dp->base; + u8 *base = dp->base; DEBUG_FUNCTION(); - DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */ + DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */ DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */ DP_OUT(base, DP_IMR, 0x00); /* Disable all interrupts */ @@ -182,16 +173,16 @@ dp83902a_stop(void) } /* - This function is called to "start up" the interface. It may be called - multiple times, even when the hardware is already running. It will be - called whenever something "hardware oriented" changes and should leave - the hardware ready to send/receive packets. -*/ + * This function is called to "start up" the interface. It may be called + * multiple times, even when the hardware is already running. It will be + * called whenever something "hardware oriented" changes and should leave + * 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,35 +197,41 @@ 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_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->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 */ - for (i = 0; i < ETHER_ADDR_LEN; i++) { + 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 */ DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); 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_OUT(base, DP_RCR, DP_RCR_AB); /* Accept broadcast, no errors, no multicast */ dp->running = true; } /* - This routine is called to start the transmitter. It is split out from the - data handling routine so it may be called either when data becomes first - available or when an Tx interrupt occurs -*/ + * This routine is called to start the transmitter. It is split out from the + * data handling routine so it may be called either when data becomes first + * available or when an Tx interrupt occurs + */ 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(); @@ -255,14 +252,14 @@ dp83902a_start_xmit(int start_page, int len) } /* - This routine is called to send data to the hardware. It is known a-priori - that there is free buffer space (dp->tx_next). -*/ + * This routine is called to send data to the hardware. It is known a-priori + * 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; @@ -271,7 +268,8 @@ dp83902a_send(unsigned char *data, int total_len, unsigned long key) DEBUG_FUNCTION(); len = pkt_len = total_len; - if (pkt_len < IEEE_8023_MIN_FRAME) pkt_len = IEEE_8023_MIN_FRAME; + if (pkt_len < IEEE_8023_MIN_FRAME) + pkt_len = IEEE_8023_MIN_FRAME; start_page = dp->tx_next; if (dp->tx_next == dp->tx_buf1) { @@ -290,17 +288,19 @@ dp83902a_send(unsigned char *data, int total_len, unsigned long key) printf("TX prep page %d len %d\n", start_page, pkt_len); #endif - DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */ + DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */ { - /* Dummy read. The manual sez something slightly different, */ - /* but the code is extended a bit to do what Hitachi's monitor */ - /* does (i.e., also read data). */ + /* + * Dummy read. The manual sez something slightly different, + * 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); - DP_OUT(base, DP_RSAH, (start_page-1) & 0xff); + DP_OUT(base, DP_RSAL, 0x100 - len); + DP_OUT(base, DP_RSAH, (start_page - 1) & 0xff); DP_OUT(base, DP_RBCL, len); DP_OUT(base, DP_RBCH, 0); DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START); @@ -308,8 +308,10 @@ dp83902a_send(unsigned char *data, int total_len, unsigned long key) } #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA - /* Stall for a bit before continuing to work around random data */ - /* corruption problems on some platforms. */ + /* + * Stall for a bit before continuing to work around random data + * corruption problems on some platforms. + */ CYGACC_CALL_IF_DELAY_US(1); #endif @@ -322,7 +324,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 +332,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--; } @@ -341,16 +344,18 @@ dp83902a_send(unsigned char *data, int total_len, unsigned long key) printf(" + %d bytes of padding\n", pkt_len - total_len); #endif /* Padding to 802.3 length was required */ - for (i = total_len; i < pkt_len;) { + for (i = total_len; i < pkt_len;) { i++; DP_OUT_DATA(dp->data, 0); } } #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA - /* After last data write, delay for a bit before accessing the */ - /* device again, or we may get random data corruption in the last */ - /* datum (on some platforms). */ + /* + * After last data write, delay for a bit before accessing the + * device again, or we may get random data corruption in the last + * datum (on some platforms). + */ CYGACC_CALL_IF_DELAY_US(1); #endif @@ -358,34 +363,35 @@ 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); /* Start transmit if not already going */ if (!dp->tx_started) { if (start_page == dp->tx1) { - dp->tx_int = 1; /* Expecting interrupt from BUF1 */ + dp->tx_int = 1; /* Expecting interrupt from BUF1 */ } else { - dp->tx_int = 2; /* Expecting interrupt from BUF2 */ + dp->tx_int = 2; /* Expecting interrupt from BUF2 */ } dp83902a_start_xmit(start_page, pkt_len); } } /* - This function is called when a packet has been received. It's job is - to prepare to unload the packet from the hardware. Once the length of - the packet is known, the upper layer of the driver can be told. When - the upper layer is ready to unload the packet, the internal function - 'dp83902a_recv' will be called to actually fetch it from the hardware. -*/ + * This function is called when a packet has been received. It's job is + * to prepare to unload the packet from the hardware. Once the length of + * the packet is known, the upper layer of the driver can be told. When + * the upper layer is ready to unload the packet, the internal function + * 'dp83902a_recv' will be called to actually fetch it from the hardware. + */ 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(); @@ -411,9 +417,9 @@ dp83902a_RxEvent(void) DP_OUT(base, DP_RSAH, pkt); if (dp->rx_next == pkt) { if (cur == dp->rx_buf_start) - DP_OUT(base, DP_BNDRY, dp->rx_buf_end-1); + DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); else - DP_OUT(base, DP_BNDRY, cur-1); /* Update pointer */ + DP_OUT(base, DP_BNDRY, cur - 1); /* Update pointer */ return; } dp->rx_next = pkt; @@ -423,37 +429,41 @@ dp83902a_RxEvent(void) CYGACC_CALL_IF_DELAY_US(10); #endif - for (i = 0; i < sizeof(rcv_hdr);) { + /* read header (get data size)*/ + for (i = 0; i < sizeof(rcv_hdr);) { DP_IN_DATA(dp->data, rcv_hdr[i++]); } #if DEBUG & 5 printf("rx hdr %02x %02x %02x %02x\n", - rcv_hdr[0], rcv_hdr[1], rcv_hdr[2], rcv_hdr[3]); + 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); + DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); else - DP_OUT(base, DP_BNDRY, rcv_hdr[1]-1); /* Update pointer */ + DP_OUT(base, DP_BNDRY, rcv_hdr[1] - 1); /* Update pointer */ } } /* - This function is called as a result of the "eth_drv_recv()" call above. - It's job is to actually fetch data for a packet from the hardware once - memory buffers have been allocated for the packet. Note that the buffers - may come in pieces, using a scatter-gather list. This allows for more - efficient processing in the upper layers of the stack. -*/ + * This function is called as a result of the "eth_drv_recv()" call above. + * It's job is to actually fetch data for a packet from the hardware once + * memory buffers have been allocated for the packet. Note that the buffers + * may come in pieces, using a scatter-gather list. This allows for more + * 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; @@ -478,11 +488,11 @@ dp83902a_recv(unsigned char *data, int len) #endif saved = false; - for (i = 0; i < 1; i++) { + for (i = 0; i < 1; i++) { 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 +505,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 +526,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(); @@ -545,14 +555,16 @@ dp83902a_TxEvent(void) uboot_push_tx_done(key, 0); } -/* Read the tally counters to clear them. Called in response to a CNT */ -/* interrupt. */ +/* + * Read the tally counters to clear them. Called in response to a CNT + * interrupt. + */ 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); @@ -560,14 +572,16 @@ dp83902a_ClearCounters(void) DP_OUT(base, DP_ISR, DP_ISR_CNT); } -/* Deal with an overflow condition. This code follows the procedure set */ -/* out in section 7.0 of the datasheet. */ +/* + * Deal with an overflow condition. This code follows the procedure set + * out in section 7.0 of the datasheet. + */ 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); @@ -581,9 +595,11 @@ dp83902a_Overflow(void) DP_OUT(base, DP_TCR, DP_TCR_LOCAL); DP_OUT(base, DP_CR, DP_CR_START | DP_CR_NODMA); - /* Read in as many packets as we can and acknowledge any and receive */ - /* interrupts. Since the buffer has overflowed, a receive event of */ - /* some kind will have occured. */ + /* + * Read in as many packets as we can and acknowledge any and receive + * interrupts. Since the buffer has overflowed, a receive event of + * some kind will have occured. + */ dp83902a_RxEvent(); DP_OUT(base, DP_ISR, DP_ISR_RxP|DP_ISR_RxE); @@ -591,8 +607,10 @@ dp83902a_Overflow(void) DP_OUT(base, DP_ISR, DP_ISR_OFLW); DP_OUT(base, DP_TCR, DP_TCR_NORMAL); - /* If a transmit command was issued, but no transmit event has occured, */ - /* restart it here. */ + /* + * If a transmit command was issued, but no transmit event has occured, + * restart it here. + */ DP_IN(base, DP_ISR, isr); if (dp->tx_started && !(isr & (DP_ISR_TxP|DP_ISR_TxE))) { DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START); @@ -603,31 +621,39 @@ 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); while (0 != isr) { - /* The CNT interrupt triggers when the MSB of one of the error */ - /* counters is set. We don't much care about these counters, but */ - /* we should read their values to reset them. */ + /* + * The CNT interrupt triggers when the MSB of one of the error + * counters is set. We don't much care about these counters, but + * we should read their values to reset them. + */ if (isr & DP_ISR_CNT) { dp83902a_ClearCounters(); } - /* Check for overflow. It's a special case, since there's a */ - /* particular procedure that must be followed to get back into */ - /* a running state.a */ + /* + * Check for overflow. It's a special case, since there's a + * particular procedure that must be followed to get back into + * a running state.a + */ if (isr & DP_ISR_OFLW) { dp83902a_Overflow(); } else { - /* Other kinds of interrupts can be acknowledged simply by */ - /* clearing the relevant bits of the ISR. Do that now, then */ - /* handle the interrupts we care about. */ - DP_OUT(base, DP_ISR, isr); /* Clear set bits */ + /* + * Other kinds of interrupts can be acknowledged simply by + * clearing the relevant bits of the ISR. Do that now, then + * handle the interrupts we care about. + */ + DP_OUT(base, DP_ISR, isr); /* Clear set bits */ if (!dp->running) break; /* Is this necessary? */ - /* Check for tx_started on TX event since these may happen */ - /* spuriously it seems. */ + /* + * Check for tx_started on TX event since these may happen + * spuriously it seems. + */ if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) { dp83902a_TxEvent(); } @@ -642,13 +668,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 @@ -658,8 +684,8 @@ typedef struct hw_info_t { #define HAS_MII 0x40 #define USE_SHMEM 0x80 /* autodetected */ -#define AM79C9XX_HOME_PHY 0x00006B90 /* HomePNA PHY */ -#define AM79C9XX_ETH_PHY 0x00006B70 /* 10baseT PHY */ +#define AM79C9XX_HOME_PHY 0x00006B90 /* HomePNA PHY */ +#define AM79C9XX_ETH_PHY 0x00006B70 /* 10baseT PHY */ #define MII_PHYID_REV_MASK 0xfffffff0 #define MII_PHYID_REG1 0x02 #define MII_PHYID_REG2 0x03 @@ -669,7 +695,7 @@ static hw_info_t hw_info[] = { { /* Allied Telesis LA-PCM */ 0x0ff0, 0x00, 0x00, 0xf4, 0 }, { /* APEX MultiCard */ 0x03f4, 0x00, 0x20, 0xe5, 0 }, { /* ASANTE FriendlyNet */ 0x4910, 0x00, 0x00, 0x94, - DELAY_OUTPUT | HAS_IBM_MISC }, + DELAY_OUTPUT | HAS_IBM_MISC }, { /* Danpex EN-6200P2 */ 0x0110, 0x00, 0x40, 0xc7, 0 }, { /* DataTrek NetCard */ 0x0ff0, 0x00, 0x20, 0xe8, 0 }, { /* Dayna CommuniCard E */ 0x0110, 0x00, 0x80, 0x19, 0 }, @@ -677,48 +703,48 @@ static hw_info_t hw_info[] = { { /* EP-210 Ethernet */ 0x0110, 0x00, 0x40, 0x33, 0 }, { /* EP4000 Ethernet */ 0x01c0, 0x00, 0x00, 0xb4, 0 }, { /* Epson EEN10B */ 0x0ff0, 0x00, 0x00, 0x48, - HAS_MISC_REG | HAS_IBM_MISC }, + HAS_MISC_REG | HAS_IBM_MISC }, { /* ELECOM Laneed LD-CDWA */ 0xb8, 0x08, 0x00, 0x42, 0 }, { /* Hypertec Ethernet */ 0x01c0, 0x00, 0x40, 0x4c, 0 }, { /* IBM CCAE */ 0x0ff0, 0x08, 0x00, 0x5a, - HAS_MISC_REG | HAS_IBM_MISC }, + HAS_MISC_REG | HAS_IBM_MISC }, { /* IBM CCAE */ 0x0ff0, 0x00, 0x04, 0xac, - HAS_MISC_REG | HAS_IBM_MISC }, + HAS_MISC_REG | HAS_IBM_MISC }, { /* IBM CCAE */ 0x0ff0, 0x00, 0x06, 0x29, - HAS_MISC_REG | HAS_IBM_MISC }, + HAS_MISC_REG | HAS_IBM_MISC }, { /* IBM FME */ 0x0374, 0x08, 0x00, 0x5a, - HAS_MISC_REG | HAS_IBM_MISC }, + HAS_MISC_REG | HAS_IBM_MISC }, { /* IBM FME */ 0x0374, 0x00, 0x04, 0xac, - HAS_MISC_REG | HAS_IBM_MISC }, + HAS_MISC_REG | HAS_IBM_MISC }, { /* Kansai KLA-PCM/T */ 0x0ff0, 0x00, 0x60, 0x87, - HAS_MISC_REG | HAS_IBM_MISC }, + HAS_MISC_REG | HAS_IBM_MISC }, { /* NSC DP83903 */ 0x0374, 0x08, 0x00, 0x17, - HAS_MISC_REG | HAS_IBM_MISC }, + HAS_MISC_REG | HAS_IBM_MISC }, { /* NSC DP83903 */ 0x0374, 0x00, 0xc0, 0xa8, - HAS_MISC_REG | HAS_IBM_MISC }, + HAS_MISC_REG | HAS_IBM_MISC }, { /* NSC DP83903 */ 0x0374, 0x00, 0xa0, 0xb0, - HAS_MISC_REG | HAS_IBM_MISC }, + HAS_MISC_REG | HAS_IBM_MISC }, { /* NSC DP83903 */ 0x0198, 0x00, 0x20, 0xe0, - HAS_MISC_REG | HAS_IBM_MISC }, + HAS_MISC_REG | HAS_IBM_MISC }, { /* I-O DATA PCLA/T */ 0x0ff0, 0x00, 0xa0, 0xb0, 0 }, { /* Katron PE-520 */ 0x0110, 0x00, 0x40, 0xf6, 0 }, { /* Kingston KNE-PCM/x */ 0x0ff0, 0x00, 0xc0, 0xf0, - HAS_MISC_REG | HAS_IBM_MISC }, + HAS_MISC_REG | HAS_IBM_MISC }, { /* Kingston KNE-PCM/x */ 0x0ff0, 0xe2, 0x0c, 0x0f, - HAS_MISC_REG | HAS_IBM_MISC }, + HAS_MISC_REG | HAS_IBM_MISC }, { /* Kingston KNE-PC2 */ 0x0180, 0x00, 0xc0, 0xf0, 0 }, { /* Maxtech PCN2000 */ 0x5000, 0x00, 0x00, 0xe8, 0 }, { /* NDC Instant-Link */ 0x003a, 0x00, 0x80, 0xc6, 0 }, { /* NE2000 Compatible */ 0x0ff0, 0x00, 0xa0, 0x0c, 0 }, { /* Network General Sniffer */ 0x0ff0, 0x00, 0x00, 0x65, - HAS_MISC_REG | HAS_IBM_MISC }, + HAS_MISC_REG | HAS_IBM_MISC }, { /* Panasonic VEL211 */ 0x0ff0, 0x00, 0x80, 0x45, - HAS_MISC_REG | HAS_IBM_MISC }, + HAS_MISC_REG | HAS_IBM_MISC }, { /* PreMax PE-200 */ 0x07f0, 0x00, 0x20, 0xe0, 0 }, { /* RPTI EP400 */ 0x0110, 0x00, 0x40, 0x95, 0 }, { /* SCM Ethernet */ 0x0ff0, 0x00, 0x20, 0xcb, 0 }, { /* Socket EA */ 0x4000, 0x00, 0xc0, 0x1b, - DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF }, + DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF }, { /* Socket LP-E CF+ */ 0x01c0, 0x00, 0xc0, 0x1b, 0 }, { /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 }, { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 }, @@ -731,115 +757,30 @@ 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; +static int initialized = 0; void uboot_push_packet_len(int len) { PRINTK("pushed len = %d\n", len); - if (len>=2000) { + if (len >= 2000) { printf("NE2000: packet too big\n"); return; } 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 +805,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 +814,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,26 +827,27 @@ 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; + initialized = 1; + return 0; } void eth_halt() { + PRINTK("### eth_halt\n"); if(initialized) dp83902a_stop(); - initialized=0; + initialized = 0; } int eth_rx() { @@ -920,7 +862,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(); @@ -936,4 +878,3 @@ int eth_send(volatile void *packet, int length) { } return 0; } -#endif diff --git a/drivers/net/ne2000.h b/drivers/net/ne2000.h index c13d9f0bb..604948286 100644 --- a/drivers/net/ne2000.h +++ b/drivers/net/ne2000.h @@ -1,16 +1,15 @@ /* -Ported to U-Boot by Christian Pellegrin <chri@ascensit.com> +Ported to U-Boot by Christian Pellegrin <chri@ascensit.com> 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 + dev/dp83902a.h - National Semiconductor DP83902a ethernet chip + National Semiconductor DP83902a ethernet chip ========================================================================== ####ECOSGPLCOPYRIGHTBEGIN#### @@ -58,222 +57,123 @@ are GPL, so this is, of course, GPL. ========================================================================== #####DESCRIPTIONBEGIN#### - Author(s): gthomas - Contributors: gthomas, jskov - Date: 2001-06-13 + 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 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 */ + * NE2000 support header file. + * Created by Nobuhiro Iwamatsu <iwamatsu@nigauri.org> + */ -/* Data configuration register */ +#ifndef __DRIVERS_NE2000_H__ +#define __DRIVERS_NE2000_H__ -#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 +/* Enable NE2000 basic init function */ +#define NE2000_BASIC_INIT -#define DP_DCR_INIT (DP_DCR_LS|DP_DCR_FIFO_4) +#define DP_DATA 0x10 +#define START_PG 0x50 /* First page of TX buffer */ +#define STOP_PG 0x80 /* Last page +1 of RX ring */ -/* Interrupt status register */ +#define RX_START 0x50 +#define RX_END 0x80 -#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) */ +#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_) -/* Interrupt mask register */ +static void pcnet_reset_8390(void) +{ + int i, r; -#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 */ + PRINTK("nic base is %lx\n", nic_base); -#define DP_IMR_All 0x3F /* Everything but remote DMA */ + 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); -/* Receiver control register */ + n2k_outb(n2k_inb(PCNET_RESET), PCNET_RESET); -#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 */ + 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. */ -/* Receiver status register */ + if (i == 100) + printf("pcnet_reset_8390() did not complete.\n"); +} /* pcnet_reset_8390 */ -#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 */ +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}, + }; -/* Transmitter control register */ + PRINTK ("trying to get MAC via prom reading\n"); -#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 */ + pcnet_reset_8390 (); -/* Transmit status register */ + mdelay (10); -#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 */ + for (i = 0; i < sizeof (program_seq) / sizeof (program_seq[0]); i++) + n2k_outb (program_seq[i].value, program_seq[i].offset); -#define IEEE_8023_MAX_FRAME 1518 /* Largest possible ethernet frame */ -#define IEEE_8023_MIN_FRAME 64 /* Smallest possible ethernet frame */ + 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 000000000..990d7488c --- /dev/null +++ b/drivers/net/ne2000_base.h @@ -0,0 +1,285 @@ +/* +Ported to U-Boot by Christian Pellegrin <chri@ascensit.com> + +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 +*/ + +#ifndef __NE2000_BASE_H__ +#define __NE2000_BASE_H__ + +#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 */ +#endif /* __NE2000_BASE_H__ */ diff --git a/drivers/net/pcnet.c b/drivers/net/pcnet.c index 4e270c9f7..386fa50bd 100644 --- a/drivers/net/pcnet.c +++ b/drivers/net/pcnet.c @@ -30,7 +30,7 @@ #include <pci.h> #if 0 -#define PCNET_DEBUG_LEVEL 0 /* 0=off, 1=init, 2=rx/tx */ +#define PCNET_DEBUG_LEVEL 0 /* 0=off, 1=init, 2=rx/tx */ #endif #if PCNET_DEBUG_LEVEL > 0 @@ -70,42 +70,42 @@ /* The PCNET Rx and Tx ring descriptors. */ struct pcnet_rx_head { - u32 base; - s16 buf_length; - s16 status; - u32 msg_length; - u32 reserved; + u32 base; + s16 buf_length; + s16 status; + u32 msg_length; + u32 reserved; }; struct pcnet_tx_head { - u32 base; - s16 length; - s16 status; - u32 misc; - u32 reserved; + u32 base; + s16 length; + s16 status; + u32 misc; + u32 reserved; }; /* The PCNET 32-Bit initialization block, described in databook. */ struct pcnet_init_block { - u16 mode; - u16 tlen_rlen; - u8 phys_addr[6]; - u16 reserved; - u32 filter[2]; - /* Receive and transmit ring base, along with extra bits. */ - u32 rx_ring; - u32 tx_ring; - u32 reserved2; + u16 mode; + u16 tlen_rlen; + u8 phys_addr[6]; + u16 reserved; + u32 filter[2]; + /* Receive and transmit ring base, along with extra bits. */ + u32 rx_ring; + u32 tx_ring; + u32 reserved2; }; typedef struct pcnet_priv { - struct pcnet_rx_head rx_ring[RX_RING_SIZE]; - struct pcnet_tx_head tx_ring[TX_RING_SIZE]; - struct pcnet_init_block init_block; - /* Receive Buffer space */ - unsigned char rx_buf[RX_RING_SIZE][PKT_BUF_SZ + 4]; - int cur_rx; - int cur_tx; + struct pcnet_rx_head rx_ring[RX_RING_SIZE]; + struct pcnet_tx_head tx_ring[TX_RING_SIZE]; + struct pcnet_init_block init_block; + /* Receive Buffer space */ + unsigned char rx_buf[RX_RING_SIZE][PKT_BUF_SZ + 4]; + int cur_rx; + int cur_tx; } pcnet_priv_t; static pcnet_priv_t *lp; @@ -118,57 +118,121 @@ static pcnet_priv_t *lp; static u16 pcnet_read_csr (struct eth_device *dev, int index) { - outw (index, dev->iobase+PCNET_RAP); - return inw (dev->iobase+PCNET_RDP); + outw (index, dev->iobase + PCNET_RAP); + return inw (dev->iobase + PCNET_RDP); } static void pcnet_write_csr (struct eth_device *dev, int index, u16 val) { - outw (index, dev->iobase+PCNET_RAP); - outw (val, dev->iobase+PCNET_RDP); + outw (index, dev->iobase + PCNET_RAP); + outw (val, dev->iobase + PCNET_RDP); } static u16 pcnet_read_bcr (struct eth_device *dev, int index) { - outw (index, dev->iobase+PCNET_RAP); - return inw (dev->iobase+PCNET_BDP); + outw (index, dev->iobase + PCNET_RAP); + return inw (dev->iobase + PCNET_BDP); } static void pcnet_write_bcr (struct eth_device *dev, int index, u16 val) { - outw (index, dev->iobase+PCNET_RAP); - outw (val, dev->iobase+PCNET_BDP); + outw (index, dev->iobase + PCNET_RAP); + outw (val, dev->iobase + PCNET_BDP); } static void pcnet_reset (struct eth_device *dev) { - inw (dev->iobase+PCNET_RESET); + inw (dev->iobase + PCNET_RESET); } static int pcnet_check (struct eth_device *dev) { - outw (88, dev->iobase+PCNET_RAP); - return (inw (dev->iobase+PCNET_RAP) == 88); + outw (88, dev->iobase + PCNET_RAP); + return (inw (dev->iobase + PCNET_RAP) == 88); } -static int pcnet_init( struct eth_device* dev, bd_t *bis); -static int pcnet_send (struct eth_device* dev, volatile void *packet, - int length); -static int pcnet_recv (struct eth_device* dev); -static void pcnet_halt (struct eth_device* dev); -static int pcnet_probe(struct eth_device* dev, bd_t *bis, int dev_num); +static int pcnet_init (struct eth_device *dev, bd_t * bis); +static int pcnet_send (struct eth_device *dev, volatile void *packet, + int length); +static int pcnet_recv (struct eth_device *dev); +static void pcnet_halt (struct eth_device *dev); +static int pcnet_probe (struct eth_device *dev, bd_t * bis, int dev_num); #define PCI_TO_MEM(d,a) pci_phys_to_mem((pci_dev_t)d->priv, (u_long)(a)) #define PCI_TO_MEM_LE(d,a) (u32)(cpu_to_le32(PCI_TO_MEM(d,a))) static struct pci_device_id supported[] = { - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE }, - { } + {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE}, + {} }; -int pcnet_initialize(bd_t *bis) +int pcnet_initialize (bd_t * bis) { +<<<<<<< HEAD:drivers/net/pcnet.c + pci_dev_t devbusfn; + struct eth_device *dev; + u16 command, status; + int dev_nr = 0; + + PCNET_DEBUG1 ("\npcnet_initialize...\n"); + + for (dev_nr = 0;; dev_nr++) { + + /* + * Find the PCnet PCI device(s). + */ + if ((devbusfn = pci_find_devices (supported, dev_nr)) < 0) { + break; + } + + /* + * Allocate and pre-fill the device structure. + */ + dev = (struct eth_device *) malloc (sizeof *dev); + dev->priv = (void *) devbusfn; + sprintf (dev->name, "pcnet#%d", dev_nr); + + /* + * Setup the PCI device. + */ + pci_read_config_dword (devbusfn, PCI_BASE_ADDRESS_0, + (unsigned int *) &dev->iobase); + dev->iobase=pci_io_to_phys (devbusfn, dev->iobase); + dev->iobase &= ~0xf; + + PCNET_DEBUG1 ("%s: devbusfn=0x%x iobase=0x%x: ", + dev->name, devbusfn, dev->iobase); + + command = PCI_COMMAND_IO | PCI_COMMAND_MASTER; + pci_write_config_word (devbusfn, PCI_COMMAND, command); + pci_read_config_word (devbusfn, PCI_COMMAND, &status); + if ((status & command) != command) { + printf ("%s: Couldn't enable IO access or Bus Mastering\n", dev->name); + free (dev); + continue; + } + + pci_write_config_byte (devbusfn, PCI_LATENCY_TIMER, 0x40); + + /* + * Probe the PCnet chip. + */ + if (pcnet_probe (dev, bis, dev_nr) < 0) { + free (dev); + continue; + } + + /* + * Setup device structure and register the driver. + */ + dev->init = pcnet_init; + dev->halt = pcnet_halt; + dev->send = pcnet_send; + dev->recv = pcnet_recv; + + eth_register (dev); +======= pci_dev_t devbusfn; struct eth_device* dev; u16 command, status; @@ -196,6 +260,7 @@ int pcnet_initialize(bd_t *bis) * Setup the PCI device. */ pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_0, (unsigned int *)&dev->iobase); + dev->iobase=pci_io_to_phys(devbusfn,dev->iobase); dev->iobase &= ~0xf; PCNET_DEBUG1("%s: devbusfn=0x%x iobase=0x%x: ", @@ -219,308 +284,311 @@ int pcnet_initialize(bd_t *bis) if (pcnet_probe(dev, bis, dev_nr) < 0) { free(dev); continue; +>>>>>>> Fixed pcnet io_base:drivers/net/pcnet.c } - /* - * Setup device structure and register the driver. - */ - dev->init = pcnet_init; - dev->halt = pcnet_halt; - dev->send = pcnet_send; - dev->recv = pcnet_recv; - - eth_register(dev); - } + udelay (10 * 1000); - udelay(10 * 1000); - - return dev_nr; + return dev_nr; } -static int pcnet_probe(struct eth_device* dev, bd_t *bis, int dev_nr) +static int pcnet_probe (struct eth_device *dev, bd_t * bis, int dev_nr) { - int chip_version; - char *chipname; + int chip_version; + char *chipname; + #ifdef PCNET_HAS_PROM - int i; + int i; #endif - /* Reset the PCnet controller */ - pcnet_reset(dev); + /* Reset the PCnet controller */ + pcnet_reset (dev); - /* Check if register access is working */ - if (pcnet_read_csr(dev, 0) != 4 || !pcnet_check(dev)) { - printf("%s: CSR register access check failed\n", dev->name); - return -1; - } + /* Check if register access is working */ + if (pcnet_read_csr (dev, 0) != 4 || !pcnet_check (dev)) { + printf ("%s: CSR register access check failed\n", dev->name); + return -1; + } - /* Identify the chip */ - chip_version = pcnet_read_csr(dev, 88) | (pcnet_read_csr(dev,89) << 16); - if ((chip_version & 0xfff) != 0x003) - return -1; - chip_version = (chip_version >> 12) & 0xffff; - switch (chip_version) { + /* Identify the chip */ + chip_version = + pcnet_read_csr (dev, 88) | (pcnet_read_csr (dev, 89) << 16); + if ((chip_version & 0xfff) != 0x003) + return -1; + chip_version = (chip_version >> 12) & 0xffff; + switch (chip_version) { + case 0x2621: + chipname = "PCnet/PCI II 79C970A"; /* PCI */ + break; #ifdef CONFIG_PCNET_79C973 - case 0x2625: - chipname = "PCnet/FAST III 79C973"; /* PCI */ - break; + case 0x2625: + chipname = "PCnet/FAST III 79C973"; /* PCI */ + break; #endif #ifdef CONFIG_PCNET_79C975 - case 0x2627: - chipname = "PCnet/FAST III 79C975"; /* PCI */ - break; + case 0x2627: + chipname = "PCnet/FAST III 79C975"; /* PCI */ + break; #endif - default: - printf("%s: PCnet version %#x not supported\n", - dev->name, chip_version); - return -1; - } + default: + printf ("%s: PCnet version %#x not supported\n", + dev->name, chip_version); + return -1; + } - PCNET_DEBUG1("AMD %s\n", chipname); + PCNET_DEBUG1 ("AMD %s\n", chipname); #ifdef PCNET_HAS_PROM - /* - * In most chips, after a chip reset, the ethernet address is read from - * the station address PROM at the base address and programmed into the - * "Physical Address Registers" CSR12-14. - */ - for (i = 0; i < 3; i++) { - unsigned int val; - val = pcnet_read_csr(dev, i+12) & 0x0ffff; - /* There may be endianness issues here. */ - dev->enetaddr[2*i ] = val & 0x0ff; - dev->enetaddr[2*i+1] = (val >> 8) & 0x0ff; - } + /* + * In most chips, after a chip reset, the ethernet address is read from + * the station address PROM at the base address and programmed into the + * "Physical Address Registers" CSR12-14. + */ + for (i = 0; i < 3; i++) { + unsigned int val; + + val = pcnet_read_csr (dev, i + 12) & 0x0ffff; + /* There may be endianness issues here. */ + dev->enetaddr[2 * i] = val & 0x0ff; + dev->enetaddr[2 * i + 1] = (val >> 8) & 0x0ff; + } #endif /* PCNET_HAS_PROM */ - return 0; + return 0; } -static int pcnet_init(struct eth_device* dev, bd_t *bis) +static int pcnet_init (struct eth_device *dev, bd_t * bis) { - int i, val; - u32 addr; + int i, val; + u32 addr; - PCNET_DEBUG1("%s: pcnet_init...\n", dev->name); + PCNET_DEBUG1 ("%s: pcnet_init...\n", dev->name); - /* Switch pcnet to 32bit mode */ - pcnet_write_bcr (dev, 20, 2); + /* Switch pcnet to 32bit mode */ + pcnet_write_bcr (dev, 20, 2); #ifdef CONFIG_PN62 - /* Setup LED registers */ - val = pcnet_read_bcr (dev, 2) | 0x1000; - pcnet_write_bcr (dev, 2, val); /* enable LEDPE */ - pcnet_write_bcr (dev, 4, 0x5080); /* 100MBit */ - pcnet_write_bcr (dev, 5, 0x40c0); /* LNKSE */ - pcnet_write_bcr (dev, 6, 0x4090); /* TX Activity */ - pcnet_write_bcr (dev, 7, 0x4084); /* RX Activity */ + /* Setup LED registers */ + val = pcnet_read_bcr (dev, 2) | 0x1000; + pcnet_write_bcr (dev, 2, val); /* enable LEDPE */ + pcnet_write_bcr (dev, 4, 0x5080); /* 100MBit */ + pcnet_write_bcr (dev, 5, 0x40c0); /* LNKSE */ + pcnet_write_bcr (dev, 6, 0x4090); /* TX Activity */ + pcnet_write_bcr (dev, 7, 0x4084); /* RX Activity */ #endif - /* Set/reset autoselect bit */ - val = pcnet_read_bcr (dev, 2) & ~2; - val |= 2; - pcnet_write_bcr (dev, 2, val); + /* Set/reset autoselect bit */ + val = pcnet_read_bcr (dev, 2) & ~2; + val |= 2; + pcnet_write_bcr (dev, 2, val); - /* Enable auto negotiate, setup, disable fd */ - val = pcnet_read_bcr(dev, 32) & ~0x98; - val |= 0x20; - pcnet_write_bcr(dev, 32, val); + /* Enable auto negotiate, setup, disable fd */ + val = pcnet_read_bcr (dev, 32) & ~0x98; + val |= 0x20; + pcnet_write_bcr (dev, 32, val); - /* - * We only maintain one structure because the drivers will never - * be used concurrently. In 32bit mode the RX and TX ring entries - * must be aligned on 16-byte boundaries. - */ - if (lp == NULL) { - addr = (u32)malloc(sizeof(pcnet_priv_t) + 0x10); - addr = (addr + 0xf) & ~0xf; - lp = (pcnet_priv_t *)addr; - } + /* + * We only maintain one structure because the drivers will never + * be used concurrently. In 32bit mode the RX and TX ring entries + * must be aligned on 16-byte boundaries. + */ + if (lp == NULL) { + addr = (u32) malloc (sizeof (pcnet_priv_t) + 0x10); + addr = (addr + 0xf) & ~0xf; + lp = (pcnet_priv_t *) addr; + } - lp->init_block.mode = cpu_to_le16(0x0000); - lp->init_block.filter[0] = 0x00000000; - lp->init_block.filter[1] = 0x00000000; + lp->init_block.mode = cpu_to_le16 (0x0000); + lp->init_block.filter[0] = 0x00000000; + lp->init_block.filter[1] = 0x00000000; - /* - * Initialize the Rx ring. - */ - lp->cur_rx = 0; - for (i = 0; i < RX_RING_SIZE; i++) { - lp->rx_ring[i].base = PCI_TO_MEM_LE(dev, lp->rx_buf[i]); - lp->rx_ring[i].buf_length = cpu_to_le16(-PKT_BUF_SZ); - lp->rx_ring[i].status = cpu_to_le16(0x8000); - PCNET_DEBUG1("Rx%d: base=0x%x buf_length=0x%hx status=0x%hx\n", - i, lp->rx_ring[i].base, lp->rx_ring[i].buf_length, - lp->rx_ring[i].status); - } + /* + * Initialize the Rx ring. + */ + lp->cur_rx = 0; + for (i = 0; i < RX_RING_SIZE; i++) { + lp->rx_ring[i].base = PCI_TO_MEM_LE (dev, lp->rx_buf[i]); + lp->rx_ring[i].buf_length = cpu_to_le16 (-PKT_BUF_SZ); + lp->rx_ring[i].status = cpu_to_le16 (0x8000); + PCNET_DEBUG1 + ("Rx%d: base=0x%x buf_length=0x%hx status=0x%hx\n", i, + lp->rx_ring[i].base, lp->rx_ring[i].buf_length, + lp->rx_ring[i].status); + } - /* - * Initialize the Tx ring. The Tx buffer address is filled in as - * needed, but we do need to clear the upper ownership bit. - */ - lp->cur_tx = 0; - for (i = 0; i < TX_RING_SIZE; i++) { - lp->tx_ring[i].base = 0; - lp->tx_ring[i].status = 0; - } + /* + * Initialize the Tx ring. The Tx buffer address is filled in as + * needed, but we do need to clear the upper ownership bit. + */ + lp->cur_tx = 0; + for (i = 0; i < TX_RING_SIZE; i++) { + lp->tx_ring[i].base = 0; + lp->tx_ring[i].status = 0; + } - /* - * Setup Init Block. - */ - PCNET_DEBUG1("Init block at 0x%p: MAC", &lp->init_block); + /* + * Setup Init Block. + */ + PCNET_DEBUG1 ("Init block at 0x%p: MAC", &lp->init_block); - for (i = 0; i < 6; i++) { - lp->init_block.phys_addr[i] = dev->enetaddr[i]; - PCNET_DEBUG1(" %02x", lp->init_block.phys_addr[i]); - } + for (i = 0; i < 6; i++) { + lp->init_block.phys_addr[i] = dev->enetaddr[i]; + PCNET_DEBUG1 (" %02x", lp->init_block.phys_addr[i]); + } - lp->init_block.tlen_rlen = cpu_to_le16(TX_RING_LEN_BITS | - RX_RING_LEN_BITS); - lp->init_block.rx_ring = PCI_TO_MEM_LE(dev, lp->rx_ring); - lp->init_block.tx_ring = PCI_TO_MEM_LE(dev, lp->tx_ring); + lp->init_block.tlen_rlen = cpu_to_le16 (TX_RING_LEN_BITS | + RX_RING_LEN_BITS); + lp->init_block.rx_ring = PCI_TO_MEM_LE (dev, lp->rx_ring); + lp->init_block.tx_ring = PCI_TO_MEM_LE (dev, lp->tx_ring); - PCNET_DEBUG1("\ntlen_rlen=0x%x rx_ring=0x%x tx_ring=0x%x\n", - lp->init_block.tlen_rlen, - lp->init_block.rx_ring, lp->init_block.tx_ring); + PCNET_DEBUG1 ("\ntlen_rlen=0x%x rx_ring=0x%x tx_ring=0x%x\n", + lp->init_block.tlen_rlen, + lp->init_block.rx_ring, lp->init_block.tx_ring); - /* - * Tell the controller where the Init Block is located. - */ - addr = PCI_TO_MEM(dev, &lp->init_block); - pcnet_write_csr(dev, 1, addr & 0xffff); - pcnet_write_csr(dev, 2, (addr >> 16) & 0xffff); + /* + * Tell the controller where the Init Block is located. + */ + addr = PCI_TO_MEM (dev, &lp->init_block); + pcnet_write_csr (dev, 1, addr & 0xffff); + pcnet_write_csr (dev, 2, (addr >> 16) & 0xffff); - pcnet_write_csr (dev, 4, 0x0915); - pcnet_write_csr (dev, 0, 0x0001); /* start */ + pcnet_write_csr (dev, 4, 0x0915); + pcnet_write_csr (dev, 0, 0x0001); /* start */ - /* Wait for Init Done bit */ - for (i = 10000; i > 0; i--) { - if (pcnet_read_csr (dev, 0) & 0x0100) - break; - udelay(10); - } - if (i <= 0) { - printf("%s: TIMEOUT: controller init failed\n", dev->name); - pcnet_reset (dev); - return -1; - } + /* Wait for Init Done bit */ + for (i = 10000; i > 0; i--) { + if (pcnet_read_csr (dev, 0) & 0x0100) + break; + udelay (10); + } + if (i <= 0) { + printf ("%s: TIMEOUT: controller init failed\n", dev->name); + pcnet_reset (dev); + return -1; + } - /* - * Finally start network controller operation. - */ - pcnet_write_csr (dev, 0, 0x0002); + /* + * Finally start network controller operation. + */ + pcnet_write_csr (dev, 0, 0x0002); - return 0; + return 0; } -static int pcnet_send(struct eth_device* dev, volatile void *packet, int pkt_len) +static int pcnet_send (struct eth_device *dev, volatile void *packet, + int pkt_len) { - int i, status; - struct pcnet_tx_head *entry = &lp->tx_ring[lp->cur_tx]; + int i, status; + struct pcnet_tx_head *entry = &lp->tx_ring[lp->cur_tx]; - PCNET_DEBUG2("Tx%d: %d bytes from 0x%p ", lp->cur_tx, pkt_len, packet); + PCNET_DEBUG2 ("Tx%d: %d bytes from 0x%p ", lp->cur_tx, pkt_len, + packet); - /* Wait for completion by testing the OWN bit */ - for (i = 1000; i > 0; i--) { - status = le16_to_cpu(entry->status); - if ((status & 0x8000) == 0) - break; - udelay(100); - PCNET_DEBUG2("."); - } - if (i <= 0) { - printf("%s: TIMEOUT: Tx%d failed (status = 0x%x)\n", - dev->name, lp->cur_tx, status); - pkt_len = 0; - goto failure; - } + /* Wait for completion by testing the OWN bit */ + for (i = 1000; i > 0; i--) { + status = le16_to_cpu (entry->status); + if ((status & 0x8000) == 0) + break; + udelay (100); + PCNET_DEBUG2 ("."); + } + if (i <= 0) { + printf ("%s: TIMEOUT: Tx%d failed (status = 0x%x)\n", + dev->name, lp->cur_tx, status); + pkt_len = 0; + goto failure; + } - /* - * Setup Tx ring. Caution: the write order is important here, - * set the status with the "ownership" bits last. - */ - status = 0x8300; - entry->length = le16_to_cpu(-pkt_len); - entry->misc = 0x00000000; - entry->base = PCI_TO_MEM_LE(dev, packet); - entry->status = le16_to_cpu(status); + /* + * Setup Tx ring. Caution: the write order is important here, + * set the status with the "ownership" bits last. + */ + status = 0x8300; + entry->length = le16_to_cpu (-pkt_len); + entry->misc = 0x00000000; + entry->base = PCI_TO_MEM_LE (dev, packet); + entry->status = le16_to_cpu (status); - /* Trigger an immediate send poll. */ - pcnet_write_csr (dev, 0, 0x0008); + /* Trigger an immediate send poll. */ + pcnet_write_csr (dev, 0, 0x0008); - failure: - if (++lp->cur_tx >= TX_RING_SIZE) - lp->cur_tx = 0; + failure: + if (++lp->cur_tx >= TX_RING_SIZE) + lp->cur_tx = 0; - PCNET_DEBUG2("done\n"); - return pkt_len; + PCNET_DEBUG2 ("done\n"); + return pkt_len; } -static int pcnet_recv(struct eth_device* dev) +static int pcnet_recv (struct eth_device *dev) { - struct pcnet_rx_head *entry; - int pkt_len = 0; - u16 status; + struct pcnet_rx_head *entry; + int pkt_len = 0; + u16 status; - while (1) { - entry = &lp->rx_ring[lp->cur_rx]; - /* - * If we own the next entry, it's a new packet. Send it up. - */ - if (((status = le16_to_cpu(entry->status)) & 0x8000) != 0) { - break; - } - status >>= 8; + while (1) { + entry = &lp->rx_ring[lp->cur_rx]; + /* + * If we own the next entry, it's a new packet. Send it up. + */ + if (((status = le16_to_cpu (entry->status)) & 0x8000) != 0) { + break; + } + status >>= 8; - if (status != 0x03) { /* There was an error. */ + if (status != 0x03) { /* There was an error. */ - printf("%s: Rx%d", dev->name, lp->cur_rx); - PCNET_DEBUG1(" (status=0x%x)", status); - if (status & 0x20) printf(" Frame"); - if (status & 0x10) printf(" Overflow"); - if (status & 0x08) printf(" CRC"); - if (status & 0x04) printf(" Fifo"); - printf(" Error\n"); - entry->status &= le16_to_cpu(0x03ff); + printf ("%s: Rx%d", dev->name, lp->cur_rx); + PCNET_DEBUG1 (" (status=0x%x)", status); + if (status & 0x20) + printf (" Frame"); + if (status & 0x10) + printf (" Overflow"); + if (status & 0x08) + printf (" CRC"); + if (status & 0x04) + printf (" Fifo"); + printf (" Error\n"); + entry->status &= le16_to_cpu (0x03ff); - } else { + } else { - pkt_len = (le32_to_cpu(entry->msg_length) & 0xfff) - 4; - if (pkt_len < 60) { - printf("%s: Rx%d: invalid packet length %d\n", - dev->name, lp->cur_rx, pkt_len); - } else { - NetReceive(lp->rx_buf[lp->cur_rx], pkt_len); - PCNET_DEBUG2("Rx%d: %d bytes from 0x%p\n", - lp->cur_rx, pkt_len, lp->rx_buf[lp->cur_rx]); - } - } - entry->status |= cpu_to_le16(0x8000); + pkt_len = + (le32_to_cpu (entry->msg_length) & 0xfff) - 4; + if (pkt_len < 60) { + printf ("%s: Rx%d: invalid packet length %d\n", dev->name, lp->cur_rx, pkt_len); + } else { + NetReceive (lp->rx_buf[lp->cur_rx], pkt_len); + PCNET_DEBUG2 ("Rx%d: %d bytes from 0x%p\n", + lp->cur_rx, pkt_len, + lp->rx_buf[lp->cur_rx]); + } + } + entry->status |= cpu_to_le16 (0x8000); - if (++lp->cur_rx >= RX_RING_SIZE) - lp->cur_rx = 0; - } - return pkt_len; + if (++lp->cur_rx >= RX_RING_SIZE) + lp->cur_rx = 0; + } + return pkt_len; } -static void pcnet_halt(struct eth_device* dev) +static void pcnet_halt (struct eth_device *dev) { - int i; + int i; - PCNET_DEBUG1("%s: pcnet_halt...\n", dev->name); + PCNET_DEBUG1 ("%s: pcnet_halt...\n", dev->name); - /* Reset the PCnet controller */ - pcnet_reset (dev); + /* Reset the PCnet controller */ + pcnet_reset (dev); - /* Wait for Stop bit */ - for (i = 1000; i > 0; i--) { - if (pcnet_read_csr (dev, 0) & 0x4) - break; - udelay(10); - } - if (i <= 0) { - printf("%s: TIMEOUT: controller reset failed\n", dev->name); - } + /* Wait for Stop bit */ + for (i = 1000; i > 0; i--) { + if (pcnet_read_csr (dev, 0) & 0x4) + break; + udelay (10); + } + if (i <= 0) { + printf ("%s: TIMEOUT: controller reset failed\n", dev->name); + } } - #endif diff --git a/drivers/net/s3c4510b_eth.h b/drivers/net/s3c4510b_eth.h index cbddba71a..048307f21 100644 --- a/drivers/net/s3c4510b_eth.h +++ b/drivers/net/s3c4510b_eth.h @@ -30,8 +30,6 @@ * */ -#define __packed __attribute__ ((packed)) - #define ETH_MAC_ADDR_SIZE (6) /* dst,src addr is 6bytes each */ #define ETH_MaxTxFrames (16) /* Max number of Tx Frames */ @@ -283,12 +281,14 @@ typedef struct __RX_FrameDescriptor { } RX_FrameDescriptor; /* MAC Frame Structure */ -typedef struct __MACFrame { - u8 m_dstAddr[6] __packed; - u8 m_srcAddr[6] __packed; - u16 m_lengthOrType __packed; - u8 m_payload[1506] __packed; -} MACFrame; +struct __MACFrame { + u8 m_dstAddr[6]; + u8 m_srcAddr[6]; + u16 m_lengthOrType; + u8 m_payload[1506]; +} __attribute__ ((packed)); + +typedef struct __MACFrame MACFrame; /* Ethernet Control block */ typedef struct __ETH { diff --git a/drivers/net/smc91111.h b/drivers/net/smc91111.h index d03cbc320..96ff04d36 100644 --- a/drivers/net/smc91111.h +++ b/drivers/net/smc91111.h @@ -79,7 +79,7 @@ typedef unsigned long int dword; #ifdef CONFIG_XSENGINE #define SMC_inl(r) (*((volatile dword *)(SMC_BASE_ADDRESS+(r<<1)))) #define SMC_inw(r) (*((volatile word *)(SMC_BASE_ADDRESS+(r<<1)))) -#define SMC_inb(p) ({ \ +#define SMC_inb(p) ({ \ unsigned int __p = (unsigned int)(SMC_BASE_ADDRESS + (p<<1)); \ unsigned int __v = *(volatile unsigned short *)((__p) & ~2); \ if (__p & 2) __v >>= 8; \ @@ -176,7 +176,76 @@ typedef unsigned long int dword; }; \ }) -#else /* if not CONFIG_PXA250 */ +#elif defined(CONFIG_LEON) /* if not CONFIG_PXA250 */ + +#define SMC_LEON_SWAP16(_x_) ({ word _x = (_x_); ((_x << 8) | (_x >> 8)); }) + +#define SMC_LEON_SWAP32(_x_) \ + ({ dword _x = (_x_); \ + ((_x << 24) | \ + ((0x0000FF00UL & _x) << 8) | \ + ((0x00FF0000UL & _x) >> 8) | \ + (_x >> 24)); }) + +#define SMC_inl(r) (SMC_LEON_SWAP32((*(volatile dword *)(SMC_BASE_ADDRESS+((r)<<0))))) +#define SMC_inl_nosw(r) ((*(volatile dword *)(SMC_BASE_ADDRESS+((r)<<0)))) +#define SMC_inw(r) (SMC_LEON_SWAP16((*(volatile word *)(SMC_BASE_ADDRESS+((r)<<0))))) +#define SMC_inw_nosw(r) ((*(volatile word *)(SMC_BASE_ADDRESS+((r)<<0)))) +#define SMC_inb(p) ({ \ + word ___v = SMC_inw((p) & ~1); \ + if ((p) & 1) ___v >>= 8; \ + else ___v &= 0xff; \ + ___v; }) + +#define SMC_outl(d,r) (*(volatile dword *)(SMC_BASE_ADDRESS+((r)<<0))=SMC_LEON_SWAP32(d)) +#define SMC_outl_nosw(d,r) (*(volatile dword *)(SMC_BASE_ADDRESS+((r)<<0))=(d)) +#define SMC_outw(d,r) (*(volatile word *)(SMC_BASE_ADDRESS+((r)<<0))=SMC_LEON_SWAP16(d)) +#define SMC_outw_nosw(d,r) (*(volatile word *)(SMC_BASE_ADDRESS+((r)<<0))=(d)) +#define SMC_outb(d,r) do{ word __d = (byte)(d); \ + word __w = SMC_inw((r)&~1); \ + __w &= ((r)&1) ? 0x00FF : 0xFF00; \ + __w |= ((r)&1) ? __d<<8 : __d; \ + SMC_outw(__w,(r)&~1); \ + }while(0) +#define SMC_outsl(r,b,l) do{ int __i; \ + dword *__b2; \ + __b2 = (dword *) b; \ + for (__i = 0; __i < l; __i++) { \ + SMC_outl_nosw( *(__b2 + __i), r); \ + } \ + }while(0) +#define SMC_outsw(r,b,l) do{ int __i; \ + word *__b2; \ + __b2 = (word *) b; \ + for (__i = 0; __i < l; __i++) { \ + SMC_outw_nosw( *(__b2 + __i), r); \ + } \ + }while(0) +#define SMC_insl(r,b,l) do{ int __i ; \ + dword *__b2; \ + __b2 = (dword *) b; \ + for (__i = 0; __i < l; __i++) { \ + *(__b2 + __i) = SMC_inl_nosw(r); \ + }; \ + }while(0) + +#define SMC_insw(r,b,l) do{ int __i ; \ + word *__b2; \ + __b2 = (word *) b; \ + for (__i = 0; __i < l; __i++) { \ + *(__b2 + __i) = SMC_inw_nosw(r); \ + }; \ + }while(0) + +#define SMC_insb(r,b,l) do{ int __i ; \ + byte *__b2; \ + __b2 = (byte *) b; \ + for (__i = 0; __i < l; __i++) { \ + *(__b2 + __i) = SMC_inb(r); \ + }; \ + }while(0) + +#else /* if not CONFIG_PXA250 and not CONFIG_LEON */ #ifndef CONFIG_SMC_USE_IOFUNCS /* these macros don't work on some boards */ /* @@ -186,7 +255,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 +264,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 diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c new file mode 100644 index 000000000..d22c8895d --- /dev/null +++ b/drivers/net/smc911x.c @@ -0,0 +1,686 @@ +/* + * SMSC LAN9[12]1[567] Network driver + * + * (c) 2007 Pengutronix, Sascha Hauer <s.hauer <at> pengutronix.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <common.h> + +#ifdef CONFIG_DRIVER_SMC911X + +#include <command.h> +#include <net.h> +#include <miiphy.h> + +#ifdef CONFIG_DRIVER_SMC911X_32_BIT +static inline u32 reg_read(u32 addr) +{ + return *(volatile u32*)addr; +} +static inline void reg_write(u32 addr, u32 val) +{ + *(volatile u32*)addr = val; +} +#else +#error "SMC911X: Only 32-bit bus is supported" +#endif + +#define mdelay(n) udelay((n)*1000) + +/* Below are the register offsets and bit definitions + * of the Lan911x memory space + */ +#define RX_DATA_FIFO (CONFIG_DRIVER_SMC911X_BASE + 0x00) + +#define TX_DATA_FIFO (CONFIG_DRIVER_SMC911X_BASE + 0x20) +#define TX_CMD_A_INT_ON_COMP 0x80000000 +#define TX_CMD_A_INT_BUF_END_ALGN 0x03000000 +#define TX_CMD_A_INT_4_BYTE_ALGN 0x00000000 +#define TX_CMD_A_INT_16_BYTE_ALGN 0x01000000 +#define TX_CMD_A_INT_32_BYTE_ALGN 0x02000000 +#define TX_CMD_A_INT_DATA_OFFSET 0x001F0000 +#define TX_CMD_A_INT_FIRST_SEG 0x00002000 +#define TX_CMD_A_INT_LAST_SEG 0x00001000 +#define TX_CMD_A_BUF_SIZE 0x000007FF +#define TX_CMD_B_PKT_TAG 0xFFFF0000 +#define TX_CMD_B_ADD_CRC_DISABLE 0x00002000 +#define TX_CMD_B_DISABLE_PADDING 0x00001000 +#define TX_CMD_B_PKT_BYTE_LENGTH 0x000007FF + +#define RX_STATUS_FIFO (CONFIG_DRIVER_SMC911X_BASE + 0x40) +#define RX_STS_PKT_LEN 0x3FFF0000 +#define RX_STS_ES 0x00008000 +#define RX_STS_BCST 0x00002000 +#define RX_STS_LEN_ERR 0x00001000 +#define RX_STS_RUNT_ERR 0x00000800 +#define RX_STS_MCAST 0x00000400 +#define RX_STS_TOO_LONG 0x00000080 +#define RX_STS_COLL 0x00000040 +#define RX_STS_ETH_TYPE 0x00000020 +#define RX_STS_WDOG_TMT 0x00000010 +#define RX_STS_MII_ERR 0x00000008 +#define RX_STS_DRIBBLING 0x00000004 +#define RX_STS_CRC_ERR 0x00000002 +#define RX_STATUS_FIFO_PEEK (CONFIG_DRIVER_SMC911X_BASE + 0x44) +#define TX_STATUS_FIFO (CONFIG_DRIVER_SMC911X_BASE + 0x48) +#define TX_STS_TAG 0xFFFF0000 +#define TX_STS_ES 0x00008000 +#define TX_STS_LOC 0x00000800 +#define TX_STS_NO_CARR 0x00000400 +#define TX_STS_LATE_COLL 0x00000200 +#define TX_STS_MANY_COLL 0x00000100 +#define TX_STS_COLL_CNT 0x00000078 +#define TX_STS_MANY_DEFER 0x00000004 +#define TX_STS_UNDERRUN 0x00000002 +#define TX_STS_DEFERRED 0x00000001 +#define TX_STATUS_FIFO_PEEK (CONFIG_DRIVER_SMC911X_BASE + 0x4C) +#define ID_REV (CONFIG_DRIVER_SMC911X_BASE + 0x50) +#define ID_REV_CHIP_ID 0xFFFF0000 /* RO */ +#define ID_REV_REV_ID 0x0000FFFF /* RO */ + +#define INT_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x54) +#define INT_CFG_INT_DEAS 0xFF000000 /* R/W */ +#define INT_CFG_INT_DEAS_CLR 0x00004000 +#define INT_CFG_INT_DEAS_STS 0x00002000 +#define INT_CFG_IRQ_INT 0x00001000 /* RO */ +#define INT_CFG_IRQ_EN 0x00000100 /* R/W */ +#define INT_CFG_IRQ_POL 0x00000010 /* R/W Not Affected by SW Reset */ +#define INT_CFG_IRQ_TYPE 0x00000001 /* R/W Not Affected by SW Reset */ + +#define INT_STS (CONFIG_DRIVER_SMC911X_BASE + 0x58) +#define INT_STS_SW_INT 0x80000000 /* R/WC */ +#define INT_STS_TXSTOP_INT 0x02000000 /* R/WC */ +#define INT_STS_RXSTOP_INT 0x01000000 /* R/WC */ +#define INT_STS_RXDFH_INT 0x00800000 /* R/WC */ +#define INT_STS_RXDF_INT 0x00400000 /* R/WC */ +#define INT_STS_TX_IOC 0x00200000 /* R/WC */ +#define INT_STS_RXD_INT 0x00100000 /* R/WC */ +#define INT_STS_GPT_INT 0x00080000 /* R/WC */ +#define INT_STS_PHY_INT 0x00040000 /* RO */ +#define INT_STS_PME_INT 0x00020000 /* R/WC */ +#define INT_STS_TXSO 0x00010000 /* R/WC */ +#define INT_STS_RWT 0x00008000 /* R/WC */ +#define INT_STS_RXE 0x00004000 /* R/WC */ +#define INT_STS_TXE 0x00002000 /* R/WC */ +/*#define INT_STS_ERX 0x00001000*/ /* R/WC */ +#define INT_STS_TDFU 0x00000800 /* R/WC */ +#define INT_STS_TDFO 0x00000400 /* R/WC */ +#define INT_STS_TDFA 0x00000200 /* R/WC */ +#define INT_STS_TSFF 0x00000100 /* R/WC */ +#define INT_STS_TSFL 0x00000080 /* R/WC */ +/*#define INT_STS_RXDF 0x00000040*/ /* R/WC */ +#define INT_STS_RDFO 0x00000040 /* R/WC */ +#define INT_STS_RDFL 0x00000020 /* R/WC */ +#define INT_STS_RSFF 0x00000010 /* R/WC */ +#define INT_STS_RSFL 0x00000008 /* R/WC */ +#define INT_STS_GPIO2_INT 0x00000004 /* R/WC */ +#define INT_STS_GPIO1_INT 0x00000002 /* R/WC */ +#define INT_STS_GPIO0_INT 0x00000001 /* R/WC */ +#define INT_EN (CONFIG_DRIVER_SMC911X_BASE + 0x5C) +#define INT_EN_SW_INT_EN 0x80000000 /* R/W */ +#define INT_EN_TXSTOP_INT_EN 0x02000000 /* R/W */ +#define INT_EN_RXSTOP_INT_EN 0x01000000 /* R/W */ +#define INT_EN_RXDFH_INT_EN 0x00800000 /* R/W */ +/*#define INT_EN_RXDF_INT_EN 0x00400000*/ /* R/W */ +#define INT_EN_TIOC_INT_EN 0x00200000 /* R/W */ +#define INT_EN_RXD_INT_EN 0x00100000 /* R/W */ +#define INT_EN_GPT_INT_EN 0x00080000 /* R/W */ +#define INT_EN_PHY_INT_EN 0x00040000 /* R/W */ +#define INT_EN_PME_INT_EN 0x00020000 /* R/W */ +#define INT_EN_TXSO_EN 0x00010000 /* R/W */ +#define INT_EN_RWT_EN 0x00008000 /* R/W */ +#define INT_EN_RXE_EN 0x00004000 /* R/W */ +#define INT_EN_TXE_EN 0x00002000 /* R/W */ +/*#define INT_EN_ERX_EN 0x00001000*/ /* R/W */ +#define INT_EN_TDFU_EN 0x00000800 /* R/W */ +#define INT_EN_TDFO_EN 0x00000400 /* R/W */ +#define INT_EN_TDFA_EN 0x00000200 /* R/W */ +#define INT_EN_TSFF_EN 0x00000100 /* R/W */ +#define INT_EN_TSFL_EN 0x00000080 /* R/W */ +/*#define INT_EN_RXDF_EN 0x00000040*/ /* R/W */ +#define INT_EN_RDFO_EN 0x00000040 /* R/W */ +#define INT_EN_RDFL_EN 0x00000020 /* R/W */ +#define INT_EN_RSFF_EN 0x00000010 /* R/W */ +#define INT_EN_RSFL_EN 0x00000008 /* R/W */ +#define INT_EN_GPIO2_INT 0x00000004 /* R/W */ +#define INT_EN_GPIO1_INT 0x00000002 /* R/W */ +#define INT_EN_GPIO0_INT 0x00000001 /* R/W */ + +#define BYTE_TEST (CONFIG_DRIVER_SMC911X_BASE + 0x64) +#define FIFO_INT (CONFIG_DRIVER_SMC911X_BASE + 0x68) +#define FIFO_INT_TX_AVAIL_LEVEL 0xFF000000 /* R/W */ +#define FIFO_INT_TX_STS_LEVEL 0x00FF0000 /* R/W */ +#define FIFO_INT_RX_AVAIL_LEVEL 0x0000FF00 /* R/W */ +#define FIFO_INT_RX_STS_LEVEL 0x000000FF /* R/W */ + +#define RX_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x6C) +#define RX_CFG_RX_END_ALGN 0xC0000000 /* R/W */ +#define RX_CFG_RX_END_ALGN4 0x00000000 /* R/W */ +#define RX_CFG_RX_END_ALGN16 0x40000000 /* R/W */ +#define RX_CFG_RX_END_ALGN32 0x80000000 /* R/W */ +#define RX_CFG_RX_DMA_CNT 0x0FFF0000 /* R/W */ +#define RX_CFG_RX_DUMP 0x00008000 /* R/W */ +#define RX_CFG_RXDOFF 0x00001F00 /* R/W */ +/*#define RX_CFG_RXBAD 0x00000001*/ /* R/W */ + +#define TX_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x70) +/*#define TX_CFG_TX_DMA_LVL 0xE0000000*/ /* R/W */ +/*#define TX_CFG_TX_DMA_CNT 0x0FFF0000*/ /* R/W Self Clearing */ +#define TX_CFG_TXS_DUMP 0x00008000 /* Self Clearing */ +#define TX_CFG_TXD_DUMP 0x00004000 /* Self Clearing */ +#define TX_CFG_TXSAO 0x00000004 /* R/W */ +#define TX_CFG_TX_ON 0x00000002 /* R/W */ +#define TX_CFG_STOP_TX 0x00000001 /* Self Clearing */ + +#define HW_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x74) +#define HW_CFG_TTM 0x00200000 /* R/W */ +#define HW_CFG_SF 0x00100000 /* R/W */ +#define HW_CFG_TX_FIF_SZ 0x000F0000 /* R/W */ +#define HW_CFG_TR 0x00003000 /* R/W */ +#define HW_CFG_PHY_CLK_SEL 0x00000060 /* R/W */ +#define HW_CFG_PHY_CLK_SEL_INT_PHY 0x00000000 /* R/W */ +#define HW_CFG_PHY_CLK_SEL_EXT_PHY 0x00000020 /* R/W */ +#define HW_CFG_PHY_CLK_SEL_CLK_DIS 0x00000040 /* R/W */ +#define HW_CFG_SMI_SEL 0x00000010 /* R/W */ +#define HW_CFG_EXT_PHY_DET 0x00000008 /* RO */ +#define HW_CFG_EXT_PHY_EN 0x00000004 /* R/W */ +#define HW_CFG_32_16_BIT_MODE 0x00000004 /* RO */ +#define HW_CFG_SRST_TO 0x00000002 /* RO */ +#define HW_CFG_SRST 0x00000001 /* Self Clearing */ + +#define RX_DP_CTRL (CONFIG_DRIVER_SMC911X_BASE + 0x78) +#define RX_DP_CTRL_RX_FFWD 0x80000000 /* R/W */ +#define RX_DP_CTRL_FFWD_BUSY 0x80000000 /* RO */ + +#define RX_FIFO_INF (CONFIG_DRIVER_SMC911X_BASE + 0x7C) +#define RX_FIFO_INF_RXSUSED 0x00FF0000 /* RO */ +#define RX_FIFO_INF_RXDUSED 0x0000FFFF /* RO */ + +#define TX_FIFO_INF (CONFIG_DRIVER_SMC911X_BASE + 0x80) +#define TX_FIFO_INF_TSUSED 0x00FF0000 /* RO */ +#define TX_FIFO_INF_TDFREE 0x0000FFFF /* RO */ + +#define PMT_CTRL (CONFIG_DRIVER_SMC911X_BASE + 0x84) +#define PMT_CTRL_PM_MODE 0x00003000 /* Self Clearing */ +#define PMT_CTRL_PHY_RST 0x00000400 /* Self Clearing */ +#define PMT_CTRL_WOL_EN 0x00000200 /* R/W */ +#define PMT_CTRL_ED_EN 0x00000100 /* R/W */ +#define PMT_CTRL_PME_TYPE 0x00000040 /* R/W Not Affected by SW Reset */ +#define PMT_CTRL_WUPS 0x00000030 /* R/WC */ +#define PMT_CTRL_WUPS_NOWAKE 0x00000000 /* R/WC */ +#define PMT_CTRL_WUPS_ED 0x00000010 /* R/WC */ +#define PMT_CTRL_WUPS_WOL 0x00000020 /* R/WC */ +#define PMT_CTRL_WUPS_MULTI 0x00000030 /* R/WC */ +#define PMT_CTRL_PME_IND 0x00000008 /* R/W */ +#define PMT_CTRL_PME_POL 0x00000004 /* R/W */ +#define PMT_CTRL_PME_EN 0x00000002 /* R/W Not Affected by SW Reset */ +#define PMT_CTRL_READY 0x00000001 /* RO */ + +#define GPIO_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x88) +#define GPIO_CFG_LED3_EN 0x40000000 /* R/W */ +#define GPIO_CFG_LED2_EN 0x20000000 /* R/W */ +#define GPIO_CFG_LED1_EN 0x10000000 /* R/W */ +#define GPIO_CFG_GPIO2_INT_POL 0x04000000 /* R/W */ +#define GPIO_CFG_GPIO1_INT_POL 0x02000000 /* R/W */ +#define GPIO_CFG_GPIO0_INT_POL 0x01000000 /* R/W */ +#define GPIO_CFG_EEPR_EN 0x00700000 /* R/W */ +#define GPIO_CFG_GPIOBUF2 0x00040000 /* R/W */ +#define GPIO_CFG_GPIOBUF1 0x00020000 /* R/W */ +#define GPIO_CFG_GPIOBUF0 0x00010000 /* R/W */ +#define GPIO_CFG_GPIODIR2 0x00000400 /* R/W */ +#define GPIO_CFG_GPIODIR1 0x00000200 /* R/W */ +#define GPIO_CFG_GPIODIR0 0x00000100 /* R/W */ +#define GPIO_CFG_GPIOD4 0x00000010 /* R/W */ +#define GPIO_CFG_GPIOD3 0x00000008 /* R/W */ +#define GPIO_CFG_GPIOD2 0x00000004 /* R/W */ +#define GPIO_CFG_GPIOD1 0x00000002 /* R/W */ +#define GPIO_CFG_GPIOD0 0x00000001 /* R/W */ + +#define GPT_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x8C) +#define GPT_CFG_TIMER_EN 0x20000000 /* R/W */ +#define GPT_CFG_GPT_LOAD 0x0000FFFF /* R/W */ + +#define GPT_CNT (CONFIG_DRIVER_SMC911X_BASE + 0x90) +#define GPT_CNT_GPT_CNT 0x0000FFFF /* RO */ + +#define ENDIAN (CONFIG_DRIVER_SMC911X_BASE + 0x98) +#define FREE_RUN (CONFIG_DRIVER_SMC911X_BASE + 0x9C) +#define RX_DROP (CONFIG_DRIVER_SMC911X_BASE + 0xA0) +#define MAC_CSR_CMD (CONFIG_DRIVER_SMC911X_BASE + 0xA4) +#define MAC_CSR_CMD_CSR_BUSY 0x80000000 /* Self Clearing */ +#define MAC_CSR_CMD_R_NOT_W 0x40000000 /* R/W */ +#define MAC_CSR_CMD_CSR_ADDR 0x000000FF /* R/W */ + +#define MAC_CSR_DATA (CONFIG_DRIVER_SMC911X_BASE + 0xA8) +#define AFC_CFG (CONFIG_DRIVER_SMC911X_BASE + 0xAC) +#define AFC_CFG_AFC_HI 0x00FF0000 /* R/W */ +#define AFC_CFG_AFC_LO 0x0000FF00 /* R/W */ +#define AFC_CFG_BACK_DUR 0x000000F0 /* R/W */ +#define AFC_CFG_FCMULT 0x00000008 /* R/W */ +#define AFC_CFG_FCBRD 0x00000004 /* R/W */ +#define AFC_CFG_FCADD 0x00000002 /* R/W */ +#define AFC_CFG_FCANY 0x00000001 /* R/W */ + +#define E2P_CMD (CONFIG_DRIVER_SMC911X_BASE + 0xB0) +#define E2P_CMD_EPC_BUSY 0x80000000 /* Self Clearing */ +#define E2P_CMD_EPC_CMD 0x70000000 /* R/W */ +#define E2P_CMD_EPC_CMD_READ 0x00000000 /* R/W */ +#define E2P_CMD_EPC_CMD_EWDS 0x10000000 /* R/W */ +#define E2P_CMD_EPC_CMD_EWEN 0x20000000 /* R/W */ +#define E2P_CMD_EPC_CMD_WRITE 0x30000000 /* R/W */ +#define E2P_CMD_EPC_CMD_WRAL 0x40000000 /* R/W */ +#define E2P_CMD_EPC_CMD_ERASE 0x50000000 /* R/W */ +#define E2P_CMD_EPC_CMD_ERAL 0x60000000 /* R/W */ +#define E2P_CMD_EPC_CMD_RELOAD 0x70000000 /* R/W */ +#define E2P_CMD_EPC_TIMEOUT 0x00000200 /* RO */ +#define E2P_CMD_MAC_ADDR_LOADED 0x00000100 /* RO */ +#define E2P_CMD_EPC_ADDR 0x000000FF /* R/W */ + +#define E2P_DATA (CONFIG_DRIVER_SMC911X_BASE + 0xB4) +#define E2P_DATA_EEPROM_DATA 0x000000FF /* R/W */ +/* end of LAN register offsets and bit definitions */ + +/* MAC Control and Status registers */ +#define MAC_CR 0x01 /* R/W */ + +/* MAC_CR - MAC Control Register */ +#define MAC_CR_RXALL 0x80000000 +/* TODO: delete this bit? It is not described in the data sheet. */ +#define MAC_CR_HBDIS 0x10000000 +#define MAC_CR_RCVOWN 0x00800000 +#define MAC_CR_LOOPBK 0x00200000 +#define MAC_CR_FDPX 0x00100000 +#define MAC_CR_MCPAS 0x00080000 +#define MAC_CR_PRMS 0x00040000 +#define MAC_CR_INVFILT 0x00020000 +#define MAC_CR_PASSBAD 0x00010000 +#define MAC_CR_HFILT 0x00008000 +#define MAC_CR_HPFILT 0x00002000 +#define MAC_CR_LCOLL 0x00001000 +#define MAC_CR_BCAST 0x00000800 +#define MAC_CR_DISRTY 0x00000400 +#define MAC_CR_PADSTR 0x00000100 +#define MAC_CR_BOLMT_MASK 0x000000C0 +#define MAC_CR_DFCHK 0x00000020 +#define MAC_CR_TXEN 0x00000008 +#define MAC_CR_RXEN 0x00000004 + +#define ADDRH 0x02 /* R/W mask 0x0000FFFFUL */ +#define ADDRL 0x03 /* R/W mask 0xFFFFFFFFUL */ +#define HASHH 0x04 /* R/W */ +#define HASHL 0x05 /* R/W */ + +#define MII_ACC 0x06 /* R/W */ +#define MII_ACC_PHY_ADDR 0x0000F800 +#define MII_ACC_MIIRINDA 0x000007C0 +#define MII_ACC_MII_WRITE 0x00000002 +#define MII_ACC_MII_BUSY 0x00000001 + +#define MII_DATA 0x07 /* R/W mask 0x0000FFFFUL */ + +#define FLOW 0x08 /* R/W */ +#define FLOW_FCPT 0xFFFF0000 +#define FLOW_FCPASS 0x00000004 +#define FLOW_FCEN 0x00000002 +#define FLOW_FCBSY 0x00000001 + +#define VLAN1 0x09 /* R/W mask 0x0000FFFFUL */ +#define VLAN1_VTI1 0x0000ffff + +#define VLAN2 0x0A /* R/W mask 0x0000FFFFUL */ +#define VLAN2_VTI2 0x0000ffff + +#define WUFF 0x0B /* WO */ + +#define WUCSR 0x0C /* R/W */ +#define WUCSR_GUE 0x00000200 +#define WUCSR_WUFR 0x00000040 +#define WUCSR_MPR 0x00000020 +#define WUCSR_WAKE_EN 0x00000004 +#define WUCSR_MPEN 0x00000002 + +/* Chip ID values */ +#define CHIP_9115 0x115 +#define CHIP_9116 0x116 +#define CHIP_9117 0x117 +#define CHIP_9118 0x118 +#define CHIP_9215 0x115a +#define CHIP_9216 0x116a +#define CHIP_9217 0x117a +#define CHIP_9218 0x118a + +struct chip_id { + u16 id; + char *name; +}; + +static const struct chip_id chip_ids[] = { + { CHIP_9115, "LAN9115" }, + { CHIP_9116, "LAN9116" }, + { CHIP_9117, "LAN9117" }, + { CHIP_9118, "LAN9118" }, + { CHIP_9215, "LAN9215" }, + { CHIP_9216, "LAN9216" }, + { CHIP_9217, "LAN9217" }, + { CHIP_9218, "LAN9218" }, + { 0, NULL }, +}; + +#define DRIVERNAME "smc911x" + +u32 smc911x_get_mac_csr(u8 reg) +{ + while (reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + ; + reg_write(MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg); + while (reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + ; + + return reg_read(MAC_CSR_DATA); +} + +void smc911x_set_mac_csr(u8 reg, u32 data) +{ + while (reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + ; + reg_write(MAC_CSR_DATA, data); + reg_write(MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg); + while (reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + ; +} + +static int smx911x_handle_mac_address(bd_t *bd) +{ + unsigned long addrh, addrl; + unsigned char *m = bd->bi_enetaddr; + + /* if the environment has a valid mac address then use it */ + if ((m[0] | m[1] | m[2] | m[3] | m[4] | m[5])) { + addrl = m[0] | m[1] << 8 | m[2] << 16 | m[3] << 24; + addrh = m[4] | m[5] << 8; + smc911x_set_mac_csr(ADDRH, addrh); + smc911x_set_mac_csr(ADDRL, addrl); + } else { + /* if not, try to get one from the eeprom */ + addrh = smc911x_get_mac_csr(ADDRH); + addrl = smc911x_get_mac_csr(ADDRL); + + m[0] = (addrl ) & 0xff; + m[1] = (addrl >> 8 ) & 0xff; + m[2] = (addrl >> 16 ) & 0xff; + m[3] = (addrl >> 24 ) & 0xff; + m[4] = (addrh ) & 0xff; + m[5] = (addrh >> 8 ) & 0xff; + + /* we get 0xff when there is no eeprom connected */ + if ((m[0] & m[1] & m[2] & m[3] & m[4] & m[5]) == 0xff) { + printf(DRIVERNAME ": no valid mac address in environment " + "and no eeprom found\n"); + return -1; + } + } + + printf(DRIVERNAME ": MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + m[0], m[1], m[2], m[3], m[4], m[5]); + + return 0; +} + +static int smc911x_miiphy_read(u8 phy, u8 reg, u16 *val) +{ + while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY) + ; + + smc911x_set_mac_csr(MII_ACC, phy << 11 | reg << 6 | MII_ACC_MII_BUSY); + + while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY) + ; + + *val = smc911x_get_mac_csr(MII_DATA); + + return 0; +} + +static int smc911x_miiphy_write(u8 phy, u8 reg, u16 val) +{ + while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY) + ; + + smc911x_set_mac_csr(MII_DATA, val); + smc911x_set_mac_csr(MII_ACC, + phy << 11 | reg << 6 | MII_ACC_MII_BUSY | MII_ACC_MII_WRITE); + + while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY) + ; + return 0; +} + +static int smc911x_phy_reset(void) +{ + u32 reg; + + reg = reg_read(PMT_CTRL); + reg &= ~0xfffff030; + reg |= PMT_CTRL_PHY_RST; + reg_write(PMT_CTRL, reg); + + mdelay(100); + + return 0; +} + +static void smc911x_phy_configure(void) +{ + int timeout; + u16 status; + + smc911x_phy_reset(); + + smc911x_miiphy_write(1, PHY_BMCR, PHY_BMCR_RESET); + mdelay(1); + smc911x_miiphy_write(1, PHY_ANAR, 0x01e1); + smc911x_miiphy_write(1, PHY_BMCR, PHY_BMCR_AUTON | PHY_BMCR_RST_NEG); + + timeout = 5000; + do { + mdelay(1); + if ((timeout--) == 0) + goto err_out; + + if (smc911x_miiphy_read(1, PHY_BMSR, &status) != 0) + goto err_out; + } while (!(status & PHY_BMSR_LS)); + + printf(DRIVERNAME ": phy initialized\n"); + + return; + +err_out: + printf(DRIVERNAME ": autonegotiation timed out\n"); +} + +static void smc911x_reset(void) +{ + int timeout; + + /* Take out of PM setting first */ + if (reg_read(PMT_CTRL) & PMT_CTRL_READY) { + /* Write to the bytetest will take out of powerdown */ + reg_write(BYTE_TEST, 0x0); + + timeout = 10; + + while (timeout-- && !(reg_read(PMT_CTRL) & PMT_CTRL_READY)) + udelay(10); + if (!timeout) { + printf(DRIVERNAME + ": timeout waiting for PM restore\n"); + return; + } + } + + /* Disable interrupts */ + reg_write(INT_EN, 0); + + reg_write(HW_CFG, HW_CFG_SRST); + + timeout = 1000; + while (timeout-- && reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY) + udelay(10); + + if (!timeout) { + printf(DRIVERNAME ": reset timeout\n"); + return; + } + + /* Reset the FIFO level and flow control settings */ + smc911x_set_mac_csr(FLOW, FLOW_FCPT | FLOW_FCEN); + reg_write(AFC_CFG, 0x0050287F); + + /* Set to LED outputs */ + reg_write(GPIO_CFG, 0x70070000); +} + +static void smc911x_enable(void) +{ + /* Enable TX */ + reg_write(HW_CFG, 8 << 16 | HW_CFG_SF); + + reg_write(GPT_CFG, GPT_CFG_TIMER_EN | 10000); + + reg_write(TX_CFG, TX_CFG_TX_ON); + + /* no padding to start of packets */ + reg_write(RX_CFG, 0); + + smc911x_set_mac_csr(MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN | MAC_CR_HBDIS); + +} + +int eth_init(bd_t *bd) +{ + unsigned long val, i; + + printf(DRIVERNAME ": initializing\n"); + + val = reg_read(BYTE_TEST); + if (val != 0x87654321) { + printf(DRIVERNAME ": Invalid chip endian 0x08%x\n", val); + goto err_out; + } + + val = reg_read(ID_REV) >> 16; + for (i = 0; chip_ids[i].id != 0; i++) { + if (chip_ids[i].id == val) break; + } + if (!chip_ids[i].id) { + printf(DRIVERNAME ": Unknown chip ID %04x\n", val); + goto err_out; + } + + printf(DRIVERNAME ": detected %s controller\n", chip_ids[i].name); + + smc911x_reset(); + + /* Configure the PHY, initialize the link state */ + smc911x_phy_configure(); + + if (smx911x_handle_mac_address(bd)) + goto err_out; + + /* Turn on Tx + Rx */ + smc911x_enable(); + + return 0; + +err_out: + return -1; +} + +int eth_send(volatile void *packet, int length) +{ + u32 *data = (u32*)packet; + u32 tmplen; + u32 status; + + reg_write(TX_DATA_FIFO, TX_CMD_A_INT_FIRST_SEG | TX_CMD_A_INT_LAST_SEG | length); + reg_write(TX_DATA_FIFO, length); + + tmplen = (length + 3) / 4; + + while (tmplen--) + reg_write(TX_DATA_FIFO, *data++); + + /* wait for transmission */ + while (!((reg_read(TX_FIFO_INF) & TX_FIFO_INF_TSUSED) >> 16)); + + /* get status. Ignore 'no carrier' error, it has no meaning for + * full duplex operation + */ + status = reg_read(TX_STATUS_FIFO) & (TX_STS_LOC | TX_STS_LATE_COLL | + TX_STS_MANY_COLL | TX_STS_MANY_DEFER | TX_STS_UNDERRUN); + + if (!status) + return 0; + + printf(DRIVERNAME ": failed to send packet: %s%s%s%s%s\n", + status & TX_STS_LOC ? "TX_STS_LOC " : "", + status & TX_STS_LATE_COLL ? "TX_STS_LATE_COLL " : "", + status & TX_STS_MANY_COLL ? "TX_STS_MANY_COLL " : "", + status & TX_STS_MANY_DEFER ? "TX_STS_MANY_DEFER " : "", + status & TX_STS_UNDERRUN ? "TX_STS_UNDERRUN" : ""); + + return -1; +} + +void eth_halt(void) +{ + smc911x_reset(); +} + +int eth_rx(void) +{ + u32 *data = (u32 *)NetRxPackets[0]; + u32 pktlen, tmplen; + u32 status; + + if ((reg_read(RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) { + status = reg_read(RX_STATUS_FIFO); + pktlen = (status & RX_STS_PKT_LEN) >> 16; + + reg_write(RX_CFG, 0); + + tmplen = (pktlen + 2+ 3) / 4; + while (tmplen--) + *data++ = reg_read(RX_DATA_FIFO); + + if (status & RX_STS_ES) + printf(DRIVERNAME + ": dropped bad packet. Status: 0x%08x\n", + status); + else + NetReceive(NetRxPackets[0], pktlen); + } + + return 0; +} + +#endif /* CONFIG_DRIVER_SMC911X */ diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index e91d9eadc..9d22aa38b 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 ? */ @@ -1266,6 +1267,35 @@ struct phy_info phy_info_VSC8244 = { }, }; +struct phy_info phy_info_VSC8601 = { + 0x00007042, + "Vitesse VSC8601", + 4, + (struct phy_cmd[]){ /* config */ + /* Override PHY config settings */ + /* Configure some basic stuff */ + {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, +#ifdef CFG_VSC8601_SKEWFIX + {MIIM_VSC8601_EPHY_CON,MIIM_VSC8601_EPHY_CON_INIT_SKEW,NULL}, +#endif + {miim_end,} + }, + (struct phy_cmd[]){ /* startup */ + /* Read the Status (2x to make sure link is right) */ + {MIIM_STATUS, miim_read, NULL}, + /* Auto-negotiate */ + {MIIM_STATUS, miim_read, &mii_parse_sr}, + /* Read the status */ + {MIIM_VSC8244_AUX_CONSTAT, miim_read, + &mii_parse_vsc8244}, + {miim_end,} + }, + (struct phy_cmd[]){ /* shutdown */ + {miim_end,} + }, +}; + + struct phy_info phy_info_dm9161 = { 0x0181b88, "Davicom DM9161E", @@ -1461,6 +1491,7 @@ struct phy_info *phy_info[] = { &phy_info_dm9161, &phy_info_lxt971, &phy_info_VSC8244, + &phy_info_VSC8601, &phy_info_dp83865, &phy_info_rtl8211b, &phy_info_generic, diff --git a/drivers/net/tsec.h b/drivers/net/tsec.h index d4dc15a68..cfa7d1aad 100644 --- a/drivers/net/tsec.h +++ b/drivers/net/tsec.h @@ -159,6 +159,11 @@ #define MIIM_VSC8244_LED_CON 0x1b #define MIIM_VSC8244_LEDCON_INIT 0xF011 +/* Entry for Vitesse VSC8601 regs starts here (Not complete) */ +/* Vitesse VSC8601 Extended PHY Control Register 1 */ +#define MIIM_VSC8601_EPHY_CON 0x17 +#define MIIM_VSC8601_EPHY_CON_INIT_SKEW 0x1120 + /* 88E1011 PHY Status Register */ #define MIIM_88E1011_PHY_STATUS 0x11 #define MIIM_88E1011_PHYSTAT_SPEED 0xc000 diff --git a/drivers/net/vsc7385.c b/drivers/net/vsc7385.c new file mode 100644 index 000000000..4095bce5b --- /dev/null +++ b/drivers/net/vsc7385.c @@ -0,0 +1,101 @@ +/* + * Vitesse 7385 Switch Firmware Upload + * + * Author: Timur Tabi <timur@freescale.com> + * + * 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 <config.h> + +#ifdef CONFIG_VSC7385_ENET + +#include <common.h> +#include <asm/io.h> +#include <asm/errno.h> + +/* + * 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 diff --git a/drivers/net/xilinx_emac.c b/drivers/net/xilinx_emac.c new file mode 100644 index 000000000..c7f1a2a8d --- /dev/null +++ b/drivers/net/xilinx_emac.c @@ -0,0 +1,462 @@ +/****************************************************************************** + * + * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" + * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND + * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE, + * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, + * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION + * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT, + * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE + * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY + * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE + * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR + * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF + * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * (C) Copyright 2007-2008 Michal Simek + * Michal SIMEK <monstr@monstr.eu> + * + * (c) Copyright 2003 Xilinx Inc. + * All rights reserved. + * + ******************************************************************************/ + +#include <config.h> +#include <common.h> +#include <net.h> +#include <asm/io.h> + +#include <asm/asm.h> + +#undef DEBUG + +typedef struct { + u32 regbaseaddress; /* Base address of registers */ + u32 databaseaddress; /* Base address of data for FIFOs */ +} xpacketfifov100b; + +typedef struct { + u32 baseaddress; /* Base address (of IPIF) */ + u32 isstarted; /* Device is currently started 0-no, 1-yes */ + xpacketfifov100b recvfifo; /* FIFO used to receive frames */ + xpacketfifov100b sendfifo; /* FIFO used to send frames */ +} xemac; + +#define XIIF_V123B_IISR_OFFSET 32UL /* IP interrupt status register */ +#define XIIF_V123B_RESET_MASK 0xAUL +#define XIIF_V123B_RESETR_OFFSET 64UL /* reset register */ + +/* This constant is used with the Reset Register */ +#define XPF_RESET_FIFO_MASK 0x0000000A +#define XPF_COUNT_STATUS_REG_OFFSET 4UL + +/* These constants are used with the Occupancy/Vacancy Count Register. This + * register also contains FIFO status */ +#define XPF_COUNT_MASK 0x0000FFFF +#define XPF_DEADLOCK_MASK 0x20000000 + +/* Offset of the MAC registers from the IPIF base address */ +#define XEM_REG_OFFSET 0x1100UL + +/* + * Register offsets for the Ethernet MAC. Each register is 32 bits. + */ +#define XEM_ECR_OFFSET (XEM_REG_OFFSET + 0x4) /* MAC Control */ +#define XEM_SAH_OFFSET (XEM_REG_OFFSET + 0xC) /* Station addr, high */ +#define XEM_SAL_OFFSET (XEM_REG_OFFSET + 0x10) /* Station addr, low */ +#define XEM_RPLR_OFFSET (XEM_REG_OFFSET + 0x1C) /* Rx packet length */ +#define XEM_TPLR_OFFSET (XEM_REG_OFFSET + 0x20) /* Tx packet length */ +#define XEM_TSR_OFFSET (XEM_REG_OFFSET + 0x24) /* Tx status */ + +#define XEM_PFIFO_OFFSET 0x2000UL +/* Tx registers */ +#define XEM_PFIFO_TXREG_OFFSET (XEM_PFIFO_OFFSET + 0x0) +/* Rx registers */ +#define XEM_PFIFO_RXREG_OFFSET (XEM_PFIFO_OFFSET + 0x10) +/* Tx keyhole */ +#define XEM_PFIFO_TXDATA_OFFSET (XEM_PFIFO_OFFSET + 0x100) +/* Rx keyhole */ +#define XEM_PFIFO_RXDATA_OFFSET (XEM_PFIFO_OFFSET + 0x200) + +/* + * EMAC Interrupt Registers (Status and Enable) masks. These registers are + * part of the IPIF IP Interrupt registers + */ +/* A mask for all transmit interrupts, used in polled mode */ +#define XEM_EIR_XMIT_ALL_MASK (XEM_EIR_XMIT_DONE_MASK |\ + XEM_EIR_XMIT_ERROR_MASK | \ + XEM_EIR_XMIT_SFIFO_EMPTY_MASK |\ + XEM_EIR_XMIT_LFIFO_FULL_MASK) + +/* Xmit complete */ +#define XEM_EIR_XMIT_DONE_MASK 0x00000001UL +/* Recv complete */ +#define XEM_EIR_RECV_DONE_MASK 0x00000002UL +/* Xmit error */ +#define XEM_EIR_XMIT_ERROR_MASK 0x00000004UL +/* Recv error */ +#define XEM_EIR_RECV_ERROR_MASK 0x00000008UL +/* Xmit status fifo empty */ +#define XEM_EIR_XMIT_SFIFO_EMPTY_MASK 0x00000010UL +/* Recv length fifo empty */ +#define XEM_EIR_RECV_LFIFO_EMPTY_MASK 0x00000020UL +/* Xmit length fifo full */ +#define XEM_EIR_XMIT_LFIFO_FULL_MASK 0x00000040UL +/* Recv length fifo overrun */ +#define XEM_EIR_RECV_LFIFO_OVER_MASK 0x00000080UL +/* Recv length fifo underrun */ +#define XEM_EIR_RECV_LFIFO_UNDER_MASK 0x00000100UL +/* Xmit status fifo overrun */ +#define XEM_EIR_XMIT_SFIFO_OVER_MASK 0x00000200UL +/* Transmit status fifo underrun */ +#define XEM_EIR_XMIT_SFIFO_UNDER_MASK 0x00000400UL +/* Transmit length fifo overrun */ +#define XEM_EIR_XMIT_LFIFO_OVER_MASK 0x00000800UL +/* Transmit length fifo underrun */ +#define XEM_EIR_XMIT_LFIFO_UNDER_MASK 0x00001000UL +/* Transmit pause pkt received */ +#define XEM_EIR_XMIT_PAUSE_MASK 0x00002000UL + +/* + * EMAC Control Register (ECR) + */ +/* Full duplex mode */ +#define XEM_ECR_FULL_DUPLEX_MASK 0x80000000UL +/* Reset transmitter */ +#define XEM_ECR_XMIT_RESET_MASK 0x40000000UL +/* Enable transmitter */ +#define XEM_ECR_XMIT_ENABLE_MASK 0x20000000UL +/* Reset receiver */ +#define XEM_ECR_RECV_RESET_MASK 0x10000000UL +/* Enable receiver */ +#define XEM_ECR_RECV_ENABLE_MASK 0x08000000UL +/* Enable PHY */ +#define XEM_ECR_PHY_ENABLE_MASK 0x04000000UL +/* Enable xmit pad insert */ +#define XEM_ECR_XMIT_PAD_ENABLE_MASK 0x02000000UL +/* Enable xmit FCS insert */ +#define XEM_ECR_XMIT_FCS_ENABLE_MASK 0x01000000UL +/* Enable unicast addr */ +#define XEM_ECR_UNICAST_ENABLE_MASK 0x00020000UL +/* Enable broadcast addr */ +#define XEM_ECR_BROAD_ENABLE_MASK 0x00008000UL + +/* + * Transmit Status Register (TSR) + */ +/* Transmit excess deferral */ +#define XEM_TSR_EXCESS_DEFERRAL_MASK 0x80000000UL +/* Transmit late collision */ +#define XEM_TSR_LATE_COLLISION_MASK 0x01000000UL + +#define ENET_MAX_MTU PKTSIZE +#define ENET_ADDR_LENGTH 6 + +static unsigned int etherrxbuff[PKTSIZE_ALIGN/4]; /* Receive buffer */ + +static u8 emacaddr[ENET_ADDR_LENGTH] = { 0x00, 0x0a, 0x35, 0x00, 0x22, 0x01 }; + +static xemac emac; + +void eth_halt(void) +{ + debug ("eth_halt\n"); +} + +int eth_init(bd_t * bis) +{ + u32 helpreg; + debug ("EMAC Initialization Started\n\r"); + + if (emac.isstarted) { + puts("Emac is started\n"); + return 0; + } + + memset (&emac, 0, sizeof (xemac)); + + emac.baseaddress = XILINX_EMAC_BASEADDR; + + /* Setting up FIFOs */ + emac.recvfifo.regbaseaddress = emac.baseaddress + + XEM_PFIFO_RXREG_OFFSET; + emac.recvfifo.databaseaddress = emac.baseaddress + + XEM_PFIFO_RXDATA_OFFSET; + out_be32 (emac.recvfifo.regbaseaddress, XPF_RESET_FIFO_MASK); + + emac.sendfifo.regbaseaddress = emac.baseaddress + + XEM_PFIFO_TXREG_OFFSET; + emac.sendfifo.databaseaddress = emac.baseaddress + + XEM_PFIFO_TXDATA_OFFSET; + out_be32 (emac.sendfifo.regbaseaddress, XPF_RESET_FIFO_MASK); + + /* Reset the entire IPIF */ + out_be32 (emac.baseaddress + XIIF_V123B_RESETR_OFFSET, + XIIF_V123B_RESET_MASK); + + /* Stopping EMAC for setting up MAC */ + helpreg = in_be32 (emac.baseaddress + XEM_ECR_OFFSET); + helpreg &= ~(XEM_ECR_XMIT_ENABLE_MASK | XEM_ECR_RECV_ENABLE_MASK); + out_be32 (emac.baseaddress + XEM_ECR_OFFSET, helpreg); + + if (!getenv("ethaddr")) { + memcpy(bis->bi_enetaddr, emacaddr, ENET_ADDR_LENGTH); + } + + /* Set the device station address high and low registers */ + helpreg = (bis->bi_enetaddr[0] << 8) | bis->bi_enetaddr[1]; + out_be32 (emac.baseaddress + XEM_SAH_OFFSET, helpreg); + helpreg = (bis->bi_enetaddr[2] << 24) | (bis->bi_enetaddr[3] << 16) | + (bis->bi_enetaddr[4] << 8) | bis->bi_enetaddr[5]; + out_be32 (emac.baseaddress + XEM_SAL_OFFSET, helpreg); + + helpreg = XEM_ECR_UNICAST_ENABLE_MASK | XEM_ECR_BROAD_ENABLE_MASK | + XEM_ECR_FULL_DUPLEX_MASK | XEM_ECR_XMIT_FCS_ENABLE_MASK | + XEM_ECR_XMIT_PAD_ENABLE_MASK | XEM_ECR_PHY_ENABLE_MASK; + out_be32 (emac.baseaddress + XEM_ECR_OFFSET, helpreg); + + emac.isstarted = 1; + + /* Enable the transmitter, and receiver */ + helpreg = in_be32 (emac.baseaddress + XEM_ECR_OFFSET); + helpreg &= ~(XEM_ECR_XMIT_RESET_MASK | XEM_ECR_RECV_RESET_MASK); + helpreg |= (XEM_ECR_XMIT_ENABLE_MASK | XEM_ECR_RECV_ENABLE_MASK); + out_be32 (emac.baseaddress + XEM_ECR_OFFSET, helpreg); + + printf("EMAC Initialization complete\n\r"); + return 0; +} + +int eth_send(volatile void *ptr, int len) +{ + u32 intrstatus; + u32 xmitstatus; + u32 fifocount; + u32 wordcount; + u32 extrabytecount; + u32 *wordbuffer = (u32 *) ptr; + + if (len > ENET_MAX_MTU) + len = ENET_MAX_MTU; + + /* + * Check for overruns and underruns for the transmit status and length + * FIFOs and make sure the send packet FIFO is not deadlocked. + * Any of these conditions is bad enough that we do not want to + * continue. The upper layer software should reset the device to resolve + * the error. + */ + intrstatus = in_be32 ((emac.baseaddress) + XIIF_V123B_IISR_OFFSET); + if (intrstatus & (XEM_EIR_XMIT_SFIFO_OVER_MASK | + XEM_EIR_XMIT_LFIFO_OVER_MASK)) { + debug ("Transmitting overrun error\n"); + return 0; + } else if (intrstatus & (XEM_EIR_XMIT_SFIFO_UNDER_MASK | + XEM_EIR_XMIT_LFIFO_UNDER_MASK)) { + debug ("Transmitting underrun error\n"); + return 0; + } else if (in_be32 (emac.sendfifo.regbaseaddress + + XPF_COUNT_STATUS_REG_OFFSET) & XPF_DEADLOCK_MASK) { + debug ("Transmitting fifo error\n"); + return 0; + } + + /* + * Before writing to the data FIFO, make sure the length FIFO is not + * full. The data FIFO might not be full yet even though the length FIFO + * is. This avoids an overrun condition on the length FIFO and keeps the + * FIFOs in sync. + * + * Clear the latched LFIFO_FULL bit so next time around the most + * current status is represented + */ + if (intrstatus & XEM_EIR_XMIT_LFIFO_FULL_MASK) { + out_be32 ((emac.baseaddress) + XIIF_V123B_IISR_OFFSET, + intrstatus & XEM_EIR_XMIT_LFIFO_FULL_MASK); + debug ("Fifo is full\n"); + return 0; + } + + /* get the count of how many words may be inserted into the FIFO */ + fifocount = in_be32 (emac.sendfifo.regbaseaddress + + XPF_COUNT_STATUS_REG_OFFSET) & XPF_COUNT_MASK; + wordcount = len >> 2; + extrabytecount = len & 0x3; + + if (fifocount < wordcount) { + debug ("Sending packet is larger then size of FIFO\n"); + return 0; + } + + for (fifocount = 0; fifocount < wordcount; fifocount++) { + out_be32 (emac.sendfifo.databaseaddress, wordbuffer[fifocount]); + } + if (extrabytecount > 0) { + u32 lastword = 0; + u8 *extrabytesbuffer = (u8 *) (wordbuffer + wordcount); + + if (extrabytecount == 1) { + lastword = extrabytesbuffer[0] << 24; + } else if (extrabytecount == 2) { + lastword = extrabytesbuffer[0] << 24 | + extrabytesbuffer[1] << 16; + } else if (extrabytecount == 3) { + lastword = extrabytesbuffer[0] << 24 | + extrabytesbuffer[1] << 16 | + extrabytesbuffer[2] << 8; + } + out_be32 (emac.sendfifo.databaseaddress, lastword); + } + + /* Loop on the MAC's status to wait for any pause to complete */ + intrstatus = in_be32 ((emac.baseaddress) + XIIF_V123B_IISR_OFFSET); + while ((intrstatus & XEM_EIR_XMIT_PAUSE_MASK) != 0) { + intrstatus = in_be32 ((emac.baseaddress) + + XIIF_V123B_IISR_OFFSET); + /* Clear the pause status from the transmit status register */ + out_be32 ((emac.baseaddress) + XIIF_V123B_IISR_OFFSET, + intrstatus & XEM_EIR_XMIT_PAUSE_MASK); + } + + /* + * Set the MAC's transmit packet length register to tell it to transmit + */ + out_be32 (emac.baseaddress + XEM_TPLR_OFFSET, len); + + /* + * Loop on the MAC's status to wait for the transmit to complete. + * The transmit status is in the FIFO when the XMIT_DONE bit is set. + */ + do { + intrstatus = in_be32 ((emac.baseaddress) + + XIIF_V123B_IISR_OFFSET); + } + while ((intrstatus & XEM_EIR_XMIT_DONE_MASK) == 0); + + xmitstatus = in_be32 (emac.baseaddress + XEM_TSR_OFFSET); + + if (intrstatus & (XEM_EIR_XMIT_SFIFO_OVER_MASK | + XEM_EIR_XMIT_LFIFO_OVER_MASK)) { + debug ("Transmitting overrun error\n"); + return 0; + } else if (intrstatus & (XEM_EIR_XMIT_SFIFO_UNDER_MASK | + XEM_EIR_XMIT_LFIFO_UNDER_MASK)) { + debug ("Transmitting underrun error\n"); + return 0; + } + + /* Clear the interrupt status register of transmit statuses */ + out_be32 ((emac.baseaddress) + XIIF_V123B_IISR_OFFSET, + intrstatus & XEM_EIR_XMIT_ALL_MASK); + + /* + * Collision errors are stored in the transmit status register + * instead of the interrupt status register + */ + if ((xmitstatus & XEM_TSR_EXCESS_DEFERRAL_MASK) || + (xmitstatus & XEM_TSR_LATE_COLLISION_MASK)) { + debug ("Transmitting collision error\n"); + return 0; + } + return 1; +} + +int eth_rx(void) +{ + u32 pktlength; + u32 intrstatus; + u32 fifocount; + u32 wordcount; + u32 extrabytecount; + u32 lastword; + u8 *extrabytesbuffer; + + if (in_be32 (emac.recvfifo.regbaseaddress + XPF_COUNT_STATUS_REG_OFFSET) + & XPF_DEADLOCK_MASK) { + out_be32 (emac.recvfifo.regbaseaddress, XPF_RESET_FIFO_MASK); + debug ("Receiving FIFO deadlock\n"); + return 0; + } + + /* + * Get the interrupt status to know what happened (whether an error + * occurred and/or whether frames have been received successfully). + * When clearing the intr status register, clear only statuses that + * pertain to receive. + */ + intrstatus = in_be32 ((emac.baseaddress) + XIIF_V123B_IISR_OFFSET); + /* + * Before reading from the length FIFO, make sure the length FIFO is not + * empty. We could cause an underrun error if we try to read from an + * empty FIFO. + */ + if (!(intrstatus & XEM_EIR_RECV_DONE_MASK)) { + /* debug ("Receiving FIFO is empty\n"); */ + return 0; + } + + /* + * Determine, from the MAC, the length of the next packet available + * in the data FIFO (there should be a non-zero length here) + */ + pktlength = in_be32 (emac.baseaddress + XEM_RPLR_OFFSET); + if (!pktlength) { + return 0; + } + + /* + * Write the RECV_DONE bit in the status register to clear it. This bit + * indicates the RPLR is non-empty, and we know it's set at this point. + * We clear it so that subsequent entry into this routine will reflect + * the current status. This is done because the non-empty bit is latched + * in the IPIF, which means it may indicate a non-empty condition even + * though there is something in the FIFO. + */ + out_be32 ((emac.baseaddress) + XIIF_V123B_IISR_OFFSET, + XEM_EIR_RECV_DONE_MASK); + + fifocount = in_be32 (emac.recvfifo.regbaseaddress + + XPF_COUNT_STATUS_REG_OFFSET) & XPF_COUNT_MASK; + + if ((fifocount * 4) < pktlength) { + debug ("Receiving FIFO is smaller than packet size.\n"); + return 0; + } + + wordcount = pktlength >> 2; + extrabytecount = pktlength & 0x3; + + for (fifocount = 0; fifocount < wordcount; fifocount++) { + etherrxbuff[fifocount] = + in_be32 (emac.recvfifo.databaseaddress); + } + + /* + * if there are extra bytes to handle, read the last word from the FIFO + * and insert the extra bytes into the buffer + */ + if (extrabytecount > 0) { + extrabytesbuffer = (u8 *) (etherrxbuff + wordcount); + + lastword = in_be32 (emac.recvfifo.databaseaddress); + + /* + * one extra byte in the last word, put the byte into the next + * location of the buffer, bytes in a word of the FIFO are + * ordered from most significant byte to least + */ + if (extrabytecount == 1) { + extrabytesbuffer[0] = (u8) (lastword >> 24); + } else if (extrabytecount == 2) { + extrabytesbuffer[0] = (u8) (lastword >> 24); + extrabytesbuffer[1] = (u8) (lastword >> 16); + } else if (extrabytecount == 3) { + extrabytesbuffer[0] = (u8) (lastword >> 24); + extrabytesbuffer[1] = (u8) (lastword >> 16); + extrabytesbuffer[2] = (u8) (lastword >> 8); + } + } + NetReceive((uchar *)etherrxbuff, pktlength); + return 1; +} diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c new file mode 100644 index 000000000..9ba4096e8 --- /dev/null +++ b/drivers/net/xilinx_emaclite.c @@ -0,0 +1,351 @@ +/****************************************************************************** + * + * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" + * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND + * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE, + * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, + * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION + * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT, + * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE + * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY + * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE + * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR + * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF + * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * (C) Copyright 2007-2008 Michal Simek + * Michal SIMEK <monstr@monstr.eu> + * + * (c) Copyright 2003 Xilinx Inc. + * All rights reserved. + * + ******************************************************************************/ + +#include <common.h> +#include <net.h> +#include <config.h> +#include <asm/io.h> + +#undef DEBUG + +#define ENET_MAX_MTU PKTSIZE +#define ENET_MAX_MTU_ALIGNED PKTSIZE_ALIGN +#define ENET_ADDR_LENGTH 6 + +/* EmacLite constants */ +#define XEL_BUFFER_OFFSET 0x0800 /* Next buffer's offset */ +#define XEL_TPLR_OFFSET 0x07F4 /* Tx packet length */ +#define XEL_TSR_OFFSET 0x07FC /* Tx status */ +#define XEL_RSR_OFFSET 0x17FC /* Rx status */ +#define XEL_RXBUFF_OFFSET 0x1000 /* Receive Buffer */ + +/* Xmit complete */ +#define XEL_TSR_XMIT_BUSY_MASK 0x00000001UL +/* Xmit interrupt enable bit */ +#define XEL_TSR_XMIT_IE_MASK 0x00000008UL +/* Buffer is active, SW bit only */ +#define XEL_TSR_XMIT_ACTIVE_MASK 0x80000000UL +/* Program the MAC address */ +#define XEL_TSR_PROGRAM_MASK 0x00000002UL +/* define for programming the MAC address into the EMAC Lite */ +#define XEL_TSR_PROG_MAC_ADDR (XEL_TSR_XMIT_BUSY_MASK | XEL_TSR_PROGRAM_MASK) + +/* Transmit packet length upper byte */ +#define XEL_TPLR_LENGTH_MASK_HI 0x0000FF00UL +/* Transmit packet length lower byte */ +#define XEL_TPLR_LENGTH_MASK_LO 0x000000FFUL + +/* Recv complete */ +#define XEL_RSR_RECV_DONE_MASK 0x00000001UL +/* Recv interrupt enable bit */ +#define XEL_RSR_RECV_IE_MASK 0x00000008UL + +typedef struct { + unsigned int baseaddress; /* Base address for device (IPIF) */ + unsigned int nexttxbuffertouse; /* Next TX buffer to write to */ + unsigned int nextrxbuffertouse; /* Next RX buffer to read from */ + unsigned char deviceid; /* Unique ID of device - for future */ +} xemaclite; + +static xemaclite emaclite; + +static char etherrxbuff[PKTSIZE_ALIGN/4]; /* Receive buffer */ + +/* hardcoded MAC address for the Xilinx EMAC Core when env is nowhere*/ +#ifdef CFG_ENV_IS_NOWHERE +static u8 emacaddr[ENET_ADDR_LENGTH] = { 0x00, 0x0a, 0x35, 0x00, 0x22, 0x01 }; +#else +static u8 emacaddr[ENET_ADDR_LENGTH]; +#endif + +void xemaclite_alignedread (u32 * srcptr, void *destptr, unsigned bytecount) +{ + unsigned int i; + u32 alignbuffer; + u32 *to32ptr; + u32 *from32ptr; + u8 *to8ptr; + u8 *from8ptr; + + from32ptr = (u32 *) srcptr; + + /* Word aligned buffer, no correction needed. */ + to32ptr = (u32 *) destptr; + while (bytecount > 3) { + *to32ptr++ = *from32ptr++; + bytecount -= 4; + } + to8ptr = (u8 *) to32ptr; + + alignbuffer = *from32ptr++; + from8ptr = (u8 *) & alignbuffer; + + for (i = 0; i < bytecount; i++) { + *to8ptr++ = *from8ptr++; + } +} + +void xemaclite_alignedwrite (void *srcptr, u32 destptr, unsigned bytecount) +{ + unsigned i; + u32 alignbuffer; + u32 *to32ptr = (u32 *) destptr; + u32 *from32ptr; + u8 *to8ptr; + u8 *from8ptr; + + from32ptr = (u32 *) srcptr; + while (bytecount > 3) { + + *to32ptr++ = *from32ptr++; + bytecount -= 4; + } + + alignbuffer = 0; + to8ptr = (u8 *) & alignbuffer; + from8ptr = (u8 *) from32ptr; + + for (i = 0; i < bytecount; i++) { + *to8ptr++ = *from8ptr++; + } + + *to32ptr++ = alignbuffer; +} + +void eth_halt (void) +{ + debug ("eth_halt\n"); +} + +int eth_init (bd_t * bis) +{ + debug ("EmacLite Initialization Started\n"); + memset (&emaclite, 0, sizeof (xemaclite)); + emaclite.baseaddress = XILINX_EMACLITE_BASEADDR; + + if (!getenv("ethaddr")) { + memcpy(bis->bi_enetaddr, emacaddr, ENET_ADDR_LENGTH); + } + +/* + * TX - TX_PING & TX_PONG initialization + */ + /* Restart PING TX */ + out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET, 0); + /* Copy MAC address */ + xemaclite_alignedwrite (bis->bi_enetaddr, + emaclite.baseaddress, ENET_ADDR_LENGTH); + /* Set the length */ + out_be32 (emaclite.baseaddress + XEL_TPLR_OFFSET, ENET_ADDR_LENGTH); + /* Update the MAC address in the EMAC Lite */ + out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET, XEL_TSR_PROG_MAC_ADDR); + /* Wait for EMAC Lite to finish with the MAC address update */ + while ((in_be32 (emaclite.baseaddress + XEL_TSR_OFFSET) & + XEL_TSR_PROG_MAC_ADDR) != 0) ; + +#ifdef CONFIG_XILINX_EMACLITE_TX_PING_PONG + /* The same operation with PONG TX */ + out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET + XEL_BUFFER_OFFSET, 0); + xemaclite_alignedwrite (bis->bi_enetaddr, emaclite.baseaddress + + XEL_BUFFER_OFFSET, ENET_ADDR_LENGTH); + out_be32 (emaclite.baseaddress + XEL_TPLR_OFFSET, ENET_ADDR_LENGTH); + out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET + XEL_BUFFER_OFFSET, + XEL_TSR_PROG_MAC_ADDR); + while ((in_be32 (emaclite.baseaddress + XEL_TSR_OFFSET + + XEL_BUFFER_OFFSET) & XEL_TSR_PROG_MAC_ADDR) != 0) ; +#endif + +/* + * RX - RX_PING & RX_PONG initialization + */ + /* Write out the value to flush the RX buffer */ + out_be32 (emaclite.baseaddress + XEL_RSR_OFFSET, XEL_RSR_RECV_IE_MASK); +#ifdef CONFIG_XILINX_EMACLITE_RX_PING_PONG + out_be32 (emaclite.baseaddress + XEL_RSR_OFFSET + XEL_BUFFER_OFFSET, + XEL_RSR_RECV_IE_MASK); +#endif + + debug ("EmacLite Initialization complete\n"); + return 0; +} + +int xemaclite_txbufferavailable (xemaclite * instanceptr) +{ + u32 reg; + u32 txpingbusy; + u32 txpongbusy; + /* + * Read the other buffer register + * and determine if the other buffer is available + */ + reg = in_be32 (instanceptr->baseaddress + + instanceptr->nexttxbuffertouse + 0); + txpingbusy = ((reg & XEL_TSR_XMIT_BUSY_MASK) == + XEL_TSR_XMIT_BUSY_MASK); + + reg = in_be32 (instanceptr->baseaddress + + (instanceptr->nexttxbuffertouse ^ XEL_TSR_OFFSET) + 0); + txpongbusy = ((reg & XEL_TSR_XMIT_BUSY_MASK) == + XEL_TSR_XMIT_BUSY_MASK); + + return (!(txpingbusy && txpongbusy)); +} + +int eth_send (volatile void *ptr, int len) { + + unsigned int reg; + unsigned int baseaddress; + + unsigned maxtry = 1000; + + if (len > ENET_MAX_MTU) + len = ENET_MAX_MTU; + + while (!xemaclite_txbufferavailable (&emaclite) && maxtry) { + udelay (10); + maxtry--; + } + + if (!maxtry) { + printf ("Error: Timeout waiting for ethernet TX buffer\n"); + /* Restart PING TX */ + out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET, 0); +#ifdef CONFIG_XILINX_EMACLITE_TX_PING_PONG + out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET + + XEL_BUFFER_OFFSET, 0); +#endif + return 0; + } + + /* Determine the expected TX buffer address */ + baseaddress = (emaclite.baseaddress + emaclite.nexttxbuffertouse); + + /* Determine if the expected buffer address is empty */ + reg = in_be32 (baseaddress + XEL_TSR_OFFSET); + if (((reg & XEL_TSR_XMIT_BUSY_MASK) == 0) + && ((in_be32 ((baseaddress) + XEL_TSR_OFFSET) + & XEL_TSR_XMIT_ACTIVE_MASK) == 0)) { + +#ifdef CONFIG_XILINX_EMACLITE_TX_PING_PONG + emaclite.nexttxbuffertouse ^= XEL_BUFFER_OFFSET; +#endif + debug ("Send packet from 0x%x\n", baseaddress); + /* Write the frame to the buffer */ + xemaclite_alignedwrite ((void *) ptr, baseaddress, len); + out_be32 (baseaddress + XEL_TPLR_OFFSET,(len & + (XEL_TPLR_LENGTH_MASK_HI | XEL_TPLR_LENGTH_MASK_LO))); + reg = in_be32 (baseaddress + XEL_TSR_OFFSET); + reg |= XEL_TSR_XMIT_BUSY_MASK; + if ((reg & XEL_TSR_XMIT_IE_MASK) != 0) { + reg |= XEL_TSR_XMIT_ACTIVE_MASK; + } + out_be32 (baseaddress + XEL_TSR_OFFSET, reg); + return 1; + } +#ifdef CONFIG_XILINX_EMACLITE_TX_PING_PONG + /* Switch to second buffer */ + baseaddress ^= XEL_BUFFER_OFFSET; + /* Determine if the expected buffer address is empty */ + reg = in_be32 (baseaddress + XEL_TSR_OFFSET); + if (((reg & XEL_TSR_XMIT_BUSY_MASK) == 0) + && ((in_be32 ((baseaddress) + XEL_TSR_OFFSET) + & XEL_TSR_XMIT_ACTIVE_MASK) == 0)) { + debug ("Send packet from 0x%x\n", baseaddress); + /* Write the frame to the buffer */ + xemaclite_alignedwrite ((void *) ptr, baseaddress, len); + out_be32 (baseaddress + XEL_TPLR_OFFSET,(len & + (XEL_TPLR_LENGTH_MASK_HI | XEL_TPLR_LENGTH_MASK_LO))); + reg = in_be32 (baseaddress + XEL_TSR_OFFSET); + reg |= XEL_TSR_XMIT_BUSY_MASK; + if ((reg & XEL_TSR_XMIT_IE_MASK) != 0) { + reg |= XEL_TSR_XMIT_ACTIVE_MASK; + } + out_be32 (baseaddress + XEL_TSR_OFFSET, reg); + return 1; + } +#endif + puts ("Error while sending frame\n"); + return 0; +} + +int eth_rx (void) +{ + unsigned int length; + unsigned int reg; + unsigned int baseaddress; + + baseaddress = emaclite.baseaddress + emaclite.nextrxbuffertouse; + reg = in_be32 (baseaddress + XEL_RSR_OFFSET); + debug ("Testing data at address 0x%x\n", baseaddress); + if ((reg & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) { +#ifdef CONFIG_XILINX_EMACLITE_RX_PING_PONG + emaclite.nextrxbuffertouse ^= XEL_BUFFER_OFFSET; +#endif + } else { +#ifndef CONFIG_XILINX_EMACLITE_RX_PING_PONG + debug ("No data was available - address 0x%x\n", baseaddress); + return 0; +#else + baseaddress ^= XEL_BUFFER_OFFSET; + reg = in_be32 (baseaddress + XEL_RSR_OFFSET); + if ((reg & XEL_RSR_RECV_DONE_MASK) != + XEL_RSR_RECV_DONE_MASK) { + debug ("No data was available - address 0x%x\n", + baseaddress); + return 0; + } +#endif + } + /* Get the length of the frame that arrived */ + switch(((in_be32 (baseaddress + XEL_RXBUFF_OFFSET + 0xC)) & + 0xFFFF0000 ) >> 16) { + case 0x806: + length = 42 + 20; /* FIXME size of ARP */ + debug ("ARP Packet\n"); + break; + case 0x800: + length = 14 + 14 + + (((in_be32 (baseaddress + XEL_RXBUFF_OFFSET + 0x10)) & + 0xFFFF0000) >> 16); /* FIXME size of IP packet */ + debug ("IP Packet\n"); + break; + default: + debug ("Other Packet\n"); + length = ENET_MAX_MTU; + break; + } + + xemaclite_alignedread ((u32 *) (baseaddress + XEL_RXBUFF_OFFSET), + etherrxbuff, length); + + /* Acknowledge the frame */ + reg = in_be32 (baseaddress + XEL_RSR_OFFSET); + reg &= ~XEL_RSR_RECV_DONE_MASK; + out_be32 (baseaddress + XEL_RSR_OFFSET, reg); + + debug ("Packet receive from 0x%x, length %dB\n", baseaddress, length); + NetReceive ((uchar *) etherrxbuff, length); + return 1; + +} diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index fe4583946..ad1b7ddb4 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -31,6 +31,9 @@ COBJS-y += pci_auto.o COBJS-y += pci_indirect.o COBJS-y += tsi108_pci.o COBJS-y += w83c553f.o +COBJS-$(CONFIG_SH4_PCI) += pci_sh4.o +COBJS-$(CONFIG_SH7751_PCI) +=pci_sh7751.o +COBJS-$(CONFIG_SH7780_PCI) +=pci_sh7780.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/pci/fsl_pci_init.c b/drivers/pci/fsl_pci_init.c index 68e45e17b..7dc33be89 100644 --- a/drivers/pci/fsl_pci_init.c +++ b/drivers/pci/fsl_pci_init.c @@ -182,7 +182,8 @@ fsl_pci_init(struct pci_controller *hose) /* Clear all error indications */ - pci->pme_msg_det = 0xffffffff; + if (bridge) + pci->pme_msg_det = 0xffffffff; pci->pedr = 0xffffffff; pci_hose_read_config_word (hose, dev, PCI_DSR, &temp16); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 50ca6b0ba..7944b6684 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, diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c index acfda83ba..eb6959376 100644 --- a/drivers/pci/pci_auto.c +++ b/drivers/pci/pci_auto.c @@ -383,7 +383,7 @@ int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev) hose->current_busno++; break; -#ifdef CONFIG_MPC5200 +#if defined(CONFIG_PCIAUTO_SKIP_HOST_BRIDGE) case PCI_CLASS_BRIDGE_OTHER: DEBUGF("PCI Autoconfig: Skipping bridge device %d\n", PCI_DEV(dev)); diff --git a/drivers/pci/pci_sh4.c b/drivers/pci/pci_sh4.c new file mode 100644 index 000000000..1290c0a79 --- /dev/null +++ b/drivers/pci/pci_sh4.c @@ -0,0 +1,76 @@ +/* + * SH4 PCI Controller (PCIC) for U-Boot. + * (C) Dustin McIntire (dustin@sensoria.com) + * (C) 2007,2008 Nobuhiro Iwamatsu <iwamatsu@nigauri.org> + * (C) 2008 Yusuke Goda <goda.yusuke@renesas.com> + * + * u-boot/cpu/sh4/pci-sh4.c + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <common.h> + +#include <asm/processor.h> +#include <asm/io.h> +#include <asm/pci.h> +#include <pci.h> + +int pci_sh4_init(struct pci_controller *hose) +{ + hose->first_busno = 0; + hose->region_count = 0; + hose->last_busno = 0xff; + + /* PCI memory space */ + pci_set_region(hose->regions + 0, + CONFIG_PCI_MEM_BUS, + CONFIG_PCI_MEM_PHYS, + CONFIG_PCI_MEM_SIZE, + PCI_REGION_MEM); + hose->region_count++; + + /* PCI IO space */ + pci_set_region(hose->regions + 1, + CONFIG_PCI_IO_BUS, + CONFIG_PCI_IO_PHYS, + CONFIG_PCI_IO_SIZE, + PCI_REGION_IO); + hose->region_count++; + + udelay(1000); + + pci_set_ops(hose, + pci_hose_read_config_byte_via_dword, + pci_hose_read_config_word_via_dword, + pci_sh4_read_config_dword, + pci_hose_write_config_byte_via_dword, + pci_hose_write_config_word_via_dword, + pci_sh4_write_config_dword); + + pci_register_hose(hose); + + udelay(1000); + +#ifdef CONFIG_PCI_SCAN_SHOW + printf("PCI: Bus Dev VenId DevId Class Int\n"); +#endif + hose->last_busno = pci_hose_scan(hose); + return 0; +} diff --git a/drivers/pci/pci_sh7751.c b/drivers/pci/pci_sh7751.c new file mode 100644 index 000000000..a058e1d37 --- /dev/null +++ b/drivers/pci/pci_sh7751.c @@ -0,0 +1,199 @@ +/* + * SH7751 PCI Controller (PCIC) for U-Boot. + * (C) Dustin McIntire (dustin@sensoria.com) + * (C) 2007,2008 Nobuhiro Iwamatsu <iwamatsu@nigauri.org> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <common.h> +#include <asm/processor.h> +#include <asm/io.h> +#include <pci.h> + +/* Register addresses and such */ +#define SH7751_BCR1 (vu_long *)0xFF800000 +#define SH7751_BCR2 (vu_short*)0xFF800004 +#define SH7751_WCR1 (vu_long *)0xFF800008 +#define SH7751_WCR2 (vu_long *)0xFF80000C +#define SH7751_WCR3 (vu_long *)0xFF800010 +#define SH7751_MCR (vu_long *)0xFF800014 +#define SH7751_BCR3 (vu_short*)0xFF800050 +#define SH7751_PCICONF0 (vu_long *)0xFE200000 +#define SH7751_PCICONF1 (vu_long *)0xFE200004 +#define SH7751_PCICONF2 (vu_long *)0xFE200008 +#define SH7751_PCICONF3 (vu_long *)0xFE20000C +#define SH7751_PCICONF4 (vu_long *)0xFE200010 +#define SH7751_PCICONF5 (vu_long *)0xFE200014 +#define SH7751_PCICONF6 (vu_long *)0xFE200018 +#define SH7751_PCICR (vu_long *)0xFE200100 +#define SH7751_PCILSR0 (vu_long *)0xFE200104 +#define SH7751_PCILSR1 (vu_long *)0xFE200108 +#define SH7751_PCILAR0 (vu_long *)0xFE20010C +#define SH7751_PCILAR1 (vu_long *)0xFE200110 +#define SH7751_PCIMBR (vu_long *)0xFE2001C4 +#define SH7751_PCIIOBR (vu_long *)0xFE2001C8 +#define SH7751_PCIPINT (vu_long *)0xFE2001CC +#define SH7751_PCIPINTM (vu_long *)0xFE2001D0 +#define SH7751_PCICLKR (vu_long *)0xFE2001D4 +#define SH7751_PCIBCR1 (vu_long *)0xFE2001E0 +#define SH7751_PCIBCR2 (vu_long *)0xFE2001E4 +#define SH7751_PCIWCR1 (vu_long *)0xFE2001E8 +#define SH7751_PCIWCR2 (vu_long *)0xFE2001EC +#define SH7751_PCIWCR3 (vu_long *)0xFE2001F0 +#define SH7751_PCIMCR (vu_long *)0xFE2001F4 +#define SH7751_PCIBCR3 (vu_long *)0xFE2001F8 + +#define BCR1_BREQEN 0x00080000 +#define PCI_SH7751_ID 0x35051054 +#define PCI_SH7751R_ID 0x350E1054 +#define SH7751_PCICONF1_WCC 0x00000080 +#define SH7751_PCICONF1_PER 0x00000040 +#define SH7751_PCICONF1_BUM 0x00000004 +#define SH7751_PCICONF1_MES 0x00000002 +#define SH7751_PCICONF1_CMDS 0x000000C6 +#define SH7751_PCI_HOST_BRIDGE 0x6 +#define SH7751_PCICR_PREFIX 0xa5000000 +#define SH7751_PCICR_PRST 0x00000002 +#define SH7751_PCICR_CFIN 0x00000001 +#define SH7751_PCIPINT_D3 0x00000002 +#define SH7751_PCIPINT_D0 0x00000001 +#define SH7751_PCICLKR_PREFIX 0xa5000000 + +#define SH7751_PCI_MEM_BASE 0xFD000000 +#define SH7751_PCI_MEM_SIZE 0x01000000 +#define SH7751_PCI_IO_BASE 0xFE240000 +#define SH7751_PCI_IO_SIZE 0x00040000 + +#define SH7751_CS3_BASE_ADDR 0x0C000000 +#define SH7751_P2CS3_BASE_ADDR 0xAC000000 + +#define SH7751_PCIPAR (vu_long *)0xFE2001C0 +#define SH7751_PCIPDR (vu_long *)0xFE200220 + +#define p4_in(addr) *(addr) +#define p4_out(data,addr) *(addr) = (data) + +/* Double word */ +int pci_sh4_read_config_dword(struct pci_controller *hose, + pci_dev_t dev, int offset, u32 * value) +{ + u32 par_data = 0x80000000 | dev; + + p4_out(par_data | (offset & 0xfc), SH7751_PCIPAR); + *value = p4_in(SH7751_PCIPDR); + + return 0; +} + +int pci_sh4_write_config_dword(struct pci_controller *hose, + pci_dev_t dev, int offset, u32 * value) +{ + u32 par_data = 0x80000000 | dev; + + p4_out(par_data | (offset & 0xfc), SH7751_PCIPAR); + p4_out(value, SH7751_PCIPDR); + + return 0; +} + +int pci_sh7751_init(struct pci_controller *hose) +{ + /* Double-check that we're a 7751 or 7751R chip */ + if (p4_in(SH7751_PCICONF0) != PCI_SH7751_ID + && p4_in(SH7751_PCICONF0) != PCI_SH7751R_ID) { + printf("PCI: Unknown PCI host bridge.\n"); + return 1; + } + printf("PCI: SH7751 PCI host bridge found.\n"); + + /* Double-check some BSC config settings */ + /* (Area 3 non-MPX 32-bit, PCI bus pins) */ + if ((p4_in(SH7751_BCR1) & 0x20008) == 0x20000) { + printf("SH7751_BCR1 0x%08X\n", p4_in(SH7751_BCR1)); + return 2; + } + if ((p4_in(SH7751_BCR2) & 0xC0) != 0xC0) { + printf("SH7751_BCR2 0x%08X\n", p4_in(SH7751_BCR2)); + return 3; + } + if (p4_in(SH7751_BCR2) & 0x01) { + printf("SH7751_BCR2 0x%08X\n", p4_in(SH7751_BCR2)); + return 4; + } + + /* Force BREQEN in BCR1 to allow PCIC access */ + p4_out((p4_in(SH7751_BCR1) | BCR1_BREQEN), SH7751_BCR1); + + /* Toggle PCI reset pin */ + p4_out((SH7751_PCICR_PREFIX | SH7751_PCICR_PRST), SH7751_PCICR); + udelay(32); + p4_out(SH7751_PCICR_PREFIX, SH7751_PCICR); + + /* Set cmd bits: WCC, PER, BUM, MES */ + /* (Addr/Data stepping, Parity enabled, Bus Master, Memory enabled) */ + p4_out(0xfb900047, SH7751_PCICONF1); /* K.Kino */ + + /* Define this host as the host bridge */ + p4_out((SH7751_PCI_HOST_BRIDGE << 24), SH7751_PCICONF2); + + /* Force PCI clock(s) on */ + p4_out(0, SH7751_PCICLKR); + p4_out(0x03, SH7751_PCICLKR); + + /* Clear powerdown IRQs, also mask them (unused) */ + p4_out((SH7751_PCIPINT_D0 | SH7751_PCIPINT_D3), SH7751_PCIPINT); + p4_out(0, SH7751_PCIPINTM); + + p4_out(0xab000001, SH7751_PCICONF4); + + /* Set up target memory mappings (for external DMA access) */ + /* Map both P0 and P2 range to Area 3 RAM for ease of use */ + p4_out((64 - 1) << 20, SH7751_PCILSR0); + p4_out(SH7751_CS3_BASE_ADDR, SH7751_PCILAR0); + p4_out(0, SH7751_PCILSR1); + p4_out(0, SH7751_PCILAR1); + p4_out(SH7751_CS3_BASE_ADDR, SH7751_PCICONF5); + p4_out(0xd0000000, SH7751_PCICONF6); + + /* Map memory window to same address on PCI bus */ + p4_out(SH7751_PCI_MEM_BASE, SH7751_PCIMBR); + + /* Map IO window to same address on PCI bus */ + p4_out(0x2000 & 0xfffc0000, SH7751_PCIIOBR); + + /* set BREQEN */ + p4_out(inl(SH7751_BCR1) | 0x00080000, SH7751_BCR1); + + /* Copy BSC registers into PCI BSC */ + p4_out(inl(SH7751_BCR1), SH7751_PCIBCR1); + p4_out(inl(SH7751_BCR2), SH7751_PCIBCR2); + p4_out(inl(SH7751_BCR3), SH7751_PCIBCR3); + p4_out(inl(SH7751_WCR1), SH7751_PCIWCR1); + p4_out(inl(SH7751_WCR2), SH7751_PCIWCR2); + p4_out(inl(SH7751_WCR3), SH7751_PCIWCR3); + p4_out(inl(SH7751_MCR), SH7751_PCIMCR); + + /* Finally, set central function init complete */ + p4_out((SH7751_PCICR_PREFIX | SH7751_PCICR_CFIN), SH7751_PCICR); + + pci_sh4_init(hose); + + return 0; +} diff --git a/drivers/pci/pci_sh7780.c b/drivers/pci/pci_sh7780.c new file mode 100644 index 000000000..d63d67d2d --- /dev/null +++ b/drivers/pci/pci_sh7780.c @@ -0,0 +1,107 @@ +/* + * SH7780 PCI Controller (PCIC) for U-Boot. + * (C) Dustin McIntire (dustin@sensoria.com) + * (C) 2007,2008 Nobuhiro Iwamatsu <iwamatsu@nigauri.org> + * (C) 2008 Yusuke Goda <goda.yusuke@renesas.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <common.h> + +#include <asm/processor.h> +#include <asm/io.h> +#include <pci.h> + +#define SH7780_VENDOR_ID 0x1912 +#define SH7780_DEVICE_ID 0x0002 +#define SH7780_PCICR_PREFIX 0xA5000000 +#define SH7780_PCICR_PFCS 0x00000800 +#define SH7780_PCICR_FTO 0x00000400 +#define SH7780_PCICR_PFE 0x00000200 +#define SH7780_PCICR_TBS 0x00000100 +#define SH7780_PCICR_ARBM 0x00000040 +#define SH7780_PCICR_IOCS 0x00000004 +#define SH7780_PCICR_PRST 0x00000002 +#define SH7780_PCICR_CFIN 0x00000001 + +#define p4_in(addr) *((vu_long *)addr) +#define p4_out(data,addr) *(vu_long *)(addr) = (data) +#define p4_inw(addr) *((vu_short *)addr) +#define p4_outw(data,addr) *(vu_short *)(addr) = (data) + +int pci_sh4_read_config_dword(struct pci_controller *hose, + pci_dev_t dev, int offset, u32 *value) +{ + u32 par_data = 0x80000000 | dev; + + p4_out(par_data | (offset & 0xfc), SH7780_PCIPAR); + *value = p4_in(SH7780_PCIPDR); + + return 0; +} + +int pci_sh4_write_config_dword(struct pci_controller *hose, + pci_dev_t dev, int offset, u32 value) +{ + u32 par_data = 0x80000000 | dev; + + p4_out(par_data | (offset & 0xfc), SH7780_PCIPAR); + p4_out(value, SH7780_PCIPDR); + return 0; +} + +int pci_sh7780_init(struct pci_controller *hose) +{ + p4_out(0x01, SH7780_PCIECR); + + if (p4_inw(SH7780_PCIVID) != SH7780_VENDOR_ID + && p4_inw(SH7780_PCIDID) != SH7780_DEVICE_ID){ + printf("PCI: Unknown PCI host bridge.\n"); + return; + } + printf("PCI: SH7780 PCI host bridge found.\n"); + + /* Toggle PCI reset pin */ + p4_out((SH7780_PCICR_PREFIX | SH7780_PCICR_PRST), SH7780_PCICR); + udelay(100000); + p4_out(SH7780_PCICR_PREFIX, SH7780_PCICR); + p4_outw(0x0047, SH7780_PCICMD); + + p4_out(0x07F00001, SH7780_PCILSR0); + p4_out(0x08000000, SH7780_PCILAR0); + p4_out(0x00000000, SH7780_PCILSR1); + p4_out(0, SH7780_PCILAR1); + p4_out(0x08000000, SH7780_PCIMBAR0); + p4_out(0x00000000, SH7780_PCIMBAR1); + + p4_out(0xFD000000, SH7780_PCIMBR0); + p4_out(0x00FC0000, SH7780_PCIMBMR0); + + /* if use Operand Cache then enable PCICSCR Soonp bits. */ + p4_out(0x08000000, SH7780_PCICSAR0); + p4_out(0x0000001B, SH7780_PCICSCR0); /* Snoop bit :On */ + + p4_out((SH7780_PCICR_PREFIX | SH7780_PCICR_CFIN | SH7780_PCICR_ARBM + | SH7780_PCICR_FTO | SH7780_PCICR_PFCS | SH7780_PCICR_PFE), + SH7780_PCICR); + + pci_sh4_init(hose); + return 0; +} diff --git a/drivers/qe/uec.c b/drivers/qe/uec.c index 55f37cb55..d34430c65 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 c384055ce..7762de6a8 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; diff --git a/drivers/qe/uec_phy.c b/drivers/qe/uec_phy.c index a42701c59..423ba789e 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, @@ -337,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; @@ -505,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, @@ -518,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 }; diff --git a/drivers/qe/uec_phy.h b/drivers/qe/uec_phy.h index e59a940e0..6f769fb50 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 diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 9be2130e1..2e0c1183b 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -43,9 +43,9 @@ 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-$(CONFIG_RTC_MC13783) += mc13783-rtc.o COBJS-y += mc146818.o COBJS-y += mcfrtc.o COBJS-y += mk48t59.o diff --git a/drivers/rtc/bfin_rtc.c b/drivers/rtc/bfin_rtc.c index 5755a20bc..ce4f1711d 100644 --- a/drivers/rtc/bfin_rtc.c +++ b/drivers/rtc/bfin_rtc.c @@ -85,7 +85,7 @@ void rtc_set(struct rtc_time *tmp) } /* Read the time from the RTC_STAT. time_in_seconds is seconds since Jan 1970 */ -void rtc_get(struct rtc_time *tmp) +int rtc_get(struct rtc_time *tmp) { uint32_t cur_rtc_stat; int time_in_sec; @@ -95,7 +95,7 @@ void rtc_get(struct rtc_time *tmp) if (tmp == NULL) { puts("Error getting the date/time\n"); - return; + return -1; } wait_for_complete(); @@ -112,6 +112,8 @@ void rtc_get(struct rtc_time *tmp) /* Calculate the total number of seconds since epoch */ time_in_sec = (tm_sec) + MIN_TO_SECS(tm_min) + HRS_TO_SECS(tm_hr) + DAYS_TO_SECS(tm_day); to_tm(time_in_sec, tmp); + + return 0; } #endif diff --git a/drivers/rtc/ds12887.c b/drivers/rtc/ds12887.c index 84fecf019..57a446d30 100644 --- a/drivers/rtc/ds12887.c +++ b/drivers/rtc/ds12887.c @@ -88,7 +88,7 @@ static unsigned char bin2bcd (unsigned int n) /* ------------------------------------------------------------------------- */ -void rtc_get (struct rtc_time *tmp) +int rtc_get (struct rtc_time *tmp) { uchar sec, min, hour, mday, wday, mon, year; @@ -150,6 +150,8 @@ else tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); #endif + + return 0; } void rtc_set (struct rtc_time *tmp) diff --git a/drivers/rtc/ds1302.c b/drivers/rtc/ds1302.c index 55af1302d..3a856c840 100644 --- a/drivers/rtc/ds1302.c +++ b/drivers/rtc/ds1302.c @@ -253,9 +253,10 @@ rtc_reset(void) /* TODO */ } -void +int rtc_get(struct rtc_time *tmp) { + int rel = 0; struct ds1302_st bbclk; if(!ds1302_initted) rtc_init(); @@ -265,6 +266,7 @@ rtc_get(struct rtc_time *tmp) if (bbclk.CH) { printf("ds1302: rtc_get: Clock was halted, clock probably " "corrupt\n"); + rel = -1; } tmp->tm_sec=10*bbclk.sec10+bbclk.sec; @@ -281,6 +283,8 @@ rtc_get(struct rtc_time *tmp) DPRINTF("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec ); + + return rel; } void diff --git a/drivers/rtc/ds1306.c b/drivers/rtc/ds1306.c index 89e433dab..1c8ac7f29 100644 --- a/drivers/rtc/ds1306.c +++ b/drivers/rtc/ds1306.c @@ -91,7 +91,7 @@ static void init_spi (void); /* ------------------------------------------------------------------------- */ /* read clock time from DS1306 and return it in *tmp */ -void rtc_get (struct rtc_time *tmp) +int rtc_get (struct rtc_time *tmp) { volatile immap_t *immap = (immap_t *) CFG_IMMR; unsigned char spi_byte; /* Data Byte */ @@ -141,6 +141,8 @@ void rtc_get (struct rtc_time *tmp) debug ("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + return 0; } /* ------------------------------------------------------------------------- */ @@ -304,7 +306,7 @@ static unsigned char rtc_read (unsigned char reg); static void rtc_write (unsigned char reg, unsigned char val); /* read clock time from DS1306 and return it in *tmp */ -void rtc_get (struct rtc_time *tmp) +int rtc_get (struct rtc_time *tmp) { unsigned char sec, min, hour, mday, wday, mon, year; @@ -349,6 +351,8 @@ void rtc_get (struct rtc_time *tmp) debug ("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + return 0; } /* ------------------------------------------------------------------------- */ diff --git a/drivers/rtc/ds1307.c b/drivers/rtc/ds1307.c index c882d7989..b20f193b4 100644 --- a/drivers/rtc/ds1307.c +++ b/drivers/rtc/ds1307.c @@ -83,8 +83,9 @@ static unsigned bcd2bin (uchar c); /* * Get the current time from the RTC */ -void rtc_get (struct rtc_time *tmp) +int rtc_get (struct rtc_time *tmp) { + int rel = 0; uchar sec, min, hour, mday, wday, mon, year; sec = rtc_read (RTC_SEC_REG_ADDR); @@ -104,6 +105,7 @@ void rtc_get (struct rtc_time *tmp) /* clear the CH flag */ rtc_write (RTC_SEC_REG_ADDR, rtc_read (RTC_SEC_REG_ADDR) & ~RTC_SEC_BIT_CH); + rel = -1; } tmp->tm_sec = bcd2bin (sec & 0x7F); @@ -119,6 +121,8 @@ void rtc_get (struct rtc_time *tmp) DEBUGR ("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + return rel; } diff --git a/drivers/rtc/ds1337.c b/drivers/rtc/ds1337.c index c636ac594..e908749ef 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); @@ -84,8 +84,9 @@ static unsigned bcd2bin (uchar c); /* * Get the current time from the RTC */ -void rtc_get (struct rtc_time *tmp) +int rtc_get (struct rtc_time *tmp) { + int rel = 0; uchar sec, min, hour, mday, wday, mon_cent, year, control, status; control = rtc_read (RTC_CTL_REG_ADDR); @@ -107,6 +108,7 @@ void rtc_get (struct rtc_time *tmp) /* clear the OSF flag */ rtc_write (RTC_STAT_REG_ADDR, rtc_read (RTC_STAT_REG_ADDR) & ~RTC_STAT_BIT_OSF); + rel = -1; } tmp->tm_sec = bcd2bin (sec & 0x7F); @@ -122,6 +124,8 @@ void rtc_get (struct rtc_time *tmp) DEBUGR ("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + return rel; } @@ -154,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); } diff --git a/drivers/rtc/ds1374.c b/drivers/rtc/ds1374.c index e773dd926..f6bb2965a 100644 --- a/drivers/rtc/ds1374.c +++ b/drivers/rtc/ds1374.c @@ -107,8 +107,8 @@ static void rtc_write_raw (uchar reg, uchar val); /* * Get the current time from the RTC */ -void rtc_get (struct rtc_time *tm){ - +int rtc_get (struct rtc_time *tm){ + int rel = 0; unsigned long time1, time2; unsigned int limit; unsigned char tmp; @@ -138,18 +138,23 @@ void rtc_get (struct rtc_time *tm){ if (time1 != time2) { printf("can't get consistent time from rtc chip\n"); + rel = -1; } DEBUGR ("Get RTC s since 1.1.1970: %d\n", time1); to_tm(time1, tm); /* To Gregorian Date */ - if (rtc_read(RTC_SR_ADDR) & RTC_SR_BIT_OSF) + if (rtc_read(RTC_SR_ADDR) & RTC_SR_BIT_OSF) { printf ("### Warning: RTC oscillator has stopped\n"); + rel = -1; + } DEBUGR ("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec); + + return rel; } /* diff --git a/drivers/rtc/ds1556.c b/drivers/rtc/ds1556.c index 4365cfb98..2c496f510 100644 --- a/drivers/rtc/ds1556.c +++ b/drivers/rtc/ds1556.c @@ -69,7 +69,7 @@ static unsigned bcd2bin(uchar c); /* ------------------------------------------------------------------------- */ -void rtc_get( struct rtc_time *tmp ) +int rtc_get( struct rtc_time *tmp ) { uchar sec, min, hour; uchar mday, wday, mon, year; @@ -118,6 +118,7 @@ void rtc_get( struct rtc_time *tmp ) tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec ); #endif + return 0; } void rtc_set( struct rtc_time *tmp ) diff --git a/drivers/rtc/ds164x.c b/drivers/rtc/ds164x.c index bff22b9a0..5943f8711 100644 --- a/drivers/rtc/ds164x.c +++ b/drivers/rtc/ds164x.c @@ -70,7 +70,7 @@ static unsigned bcd2bin(uchar c); /* ------------------------------------------------------------------------- */ -void rtc_get( struct rtc_time *tmp ) +int rtc_get( struct rtc_time *tmp ) { uchar sec, min, hour; uchar mday, wday, mon, year; @@ -115,6 +115,8 @@ void rtc_get( struct rtc_time *tmp ) tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec ); #endif + + return 0; } void rtc_set( struct rtc_time *tmp ) diff --git a/drivers/rtc/ds174x.c b/drivers/rtc/ds174x.c index 5f85a6817..eb3ca88fd 100644 --- a/drivers/rtc/ds174x.c +++ b/drivers/rtc/ds174x.c @@ -65,7 +65,7 @@ static unsigned bcd2bin(uchar c); /* ------------------------------------------------------------------------- */ -void rtc_get( struct rtc_time *tmp ) +int rtc_get( struct rtc_time *tmp ) { uchar sec, min, hour; uchar mday, wday, mon, year; @@ -114,6 +114,7 @@ void rtc_get( struct rtc_time *tmp ) tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec ); #endif + return 0; } void rtc_set( struct rtc_time *tmp ) diff --git a/drivers/rtc/ds3231.c b/drivers/rtc/ds3231.c index fe11b869f..95cb18634 100644 --- a/drivers/rtc/ds3231.c +++ b/drivers/rtc/ds3231.c @@ -86,8 +86,9 @@ static unsigned bcd2bin (uchar c); /* * Get the current time from the RTC */ -void rtc_get (struct rtc_time *tmp) +int rtc_get (struct rtc_time *tmp) { + int rel = 0; uchar sec, min, hour, mday, wday, mon_cent, year, control, status; control = rtc_read (RTC_CTL_REG_ADDR); @@ -109,6 +110,7 @@ void rtc_get (struct rtc_time *tmp) /* clear the OSF flag */ rtc_write (RTC_STAT_REG_ADDR, rtc_read (RTC_STAT_REG_ADDR) & ~RTC_STAT_BIT_OSF); + rel = -1; } tmp->tm_sec = bcd2bin (sec & 0x7F); @@ -124,6 +126,8 @@ void rtc_get (struct rtc_time *tmp) DEBUGR ("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + return rel; } diff --git a/drivers/rtc/isl1208.c b/drivers/rtc/isl1208.c index d87280229..3d46fd065 100644 --- a/drivers/rtc/isl1208.c +++ b/drivers/rtc/isl1208.c @@ -73,8 +73,9 @@ static unsigned bcd2bin (uchar c); * Get the current time from the RTC */ -void rtc_get (struct rtc_time *tmp) +int rtc_get (struct rtc_time *tmp) { + int rel = 0; uchar sec, min, hour, mday, wday, mon, year, status; status = rtc_read (RTC_STAT_REG_ADDR); @@ -94,6 +95,7 @@ void rtc_get (struct rtc_time *tmp) printf ("### Warning: RTC oscillator has stopped\n"); rtc_write(RTC_STAT_REG_ADDR, rtc_read(RTC_STAT_REG_ADDR) &~ (RTC_STAT_BIT_BAT|RTC_STAT_BIT_RTCF)); + rel = -1; } tmp->tm_sec = bcd2bin (sec & 0x7F); @@ -109,6 +111,8 @@ void rtc_get (struct rtc_time *tmp) DEBUGR ("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + return rel; } /* diff --git a/drivers/rtc/m41t11.c b/drivers/rtc/m41t11.c index 81da33a31..fce00d935 100644 --- a/drivers/rtc/m41t11.c +++ b/drivers/rtc/m41t11.c @@ -96,14 +96,16 @@ static unsigned char bin2bcd (unsigned int n) #define M41T11_STORAGE_SZ (64-REG_CNT) -void rtc_get (struct rtc_time *tmp) +int rtc_get (struct rtc_time *tmp) { + int rel = 0; uchar data[RTC_REG_CNT]; i2c_read(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, data, RTC_REG_CNT); if( data[RTC_SEC_ADDR] & 0x80 ){ printf( "m41t11 RTC Clock stopped!!!\n" ); + rel = -1; } tmp->tm_sec = bcd2bin (data[RTC_SEC_ADDR] & 0x7F); tmp->tm_min = bcd2bin (data[RTC_MIN_ADDR] & 0x7F); @@ -120,6 +122,7 @@ void rtc_get (struct rtc_time *tmp) i2c_read(CFG_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, ¢, M41T11_YEAR_SIZE); if( !(data[RTC_HOUR_ADDR] & 0x80) ){ printf( "m41t11 RTC: cann't keep track of years without CEB set\n" ); + rel = -1; } if( (cent & 0x1) != ((data[RTC_HOUR_ADDR]&0x40)>>7) ){ /*century flip store off new year*/ @@ -136,6 +139,8 @@ void rtc_get (struct rtc_time *tmp) debug ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + return rel; } void rtc_set (struct rtc_time *tmp) diff --git a/drivers/rtc/m41t60.c b/drivers/rtc/m41t60.c index 7c80143e6..8a32ea074 100644 --- a/drivers/rtc/m41t60.c +++ b/drivers/rtc/m41t60.c @@ -170,12 +170,12 @@ static uchar *rtc_validate(void) return data; } -void rtc_get(struct rtc_time *tmp) +int rtc_get(struct rtc_time *tmp) { uchar const *const data = rtc_validate(); if (!data) - return; + return -1; tmp->tm_sec = bcd2bin(data[RTC_SEC] & 0x7F); tmp->tm_min = bcd2bin(data[RTC_MIN] & 0x7F); @@ -190,6 +190,8 @@ void rtc_get(struct rtc_time *tmp) debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + return 0; } void rtc_set(struct rtc_time *tmp) diff --git a/drivers/rtc/m41t62.c b/drivers/rtc/m41t62.c index 2bdca3bdf..cf2a9574a 100644 --- a/drivers/rtc/m41t62.c +++ b/drivers/rtc/m41t62.c @@ -64,7 +64,7 @@ #define M41T62_FEATURE_HT (1 << 0) #define M41T62_FEATURE_BL (1 << 1) -void rtc_get(struct rtc_time *tm) +int rtc_get(struct rtc_time *tm) { u8 buf[M41T62_DATETIME_REG_SIZE]; @@ -92,6 +92,8 @@ void rtc_get(struct rtc_time *tm) __FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); + + return 0; } void rtc_set(struct rtc_time *tm) diff --git a/drivers/rtc/m48t35ax.c b/drivers/rtc/m48t35ax.c index 0a0ffa8aa..be29279d0 100644 --- a/drivers/rtc/m48t35ax.c +++ b/drivers/rtc/m48t35ax.c @@ -42,7 +42,7 @@ static unsigned bcd2bin(uchar c); /* ------------------------------------------------------------------------- */ -void rtc_get (struct rtc_time *tmp) +int rtc_get (struct rtc_time *tmp) { uchar sec, min, hour, cent_day, date, month, year; uchar ccr; /* Clock control register */ @@ -83,6 +83,8 @@ void rtc_get (struct rtc_time *tmp) debug ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + return 0; } void rtc_set (struct rtc_time *tmp) diff --git a/drivers/rtc/max6900.c b/drivers/rtc/max6900.c index c75a8e04c..e9979f227 100644 --- a/drivers/rtc/max6900.c +++ b/drivers/rtc/max6900.c @@ -63,7 +63,7 @@ static unsigned char bin2bcd (unsigned int n) /* ------------------------------------------------------------------------- */ -void rtc_get (struct rtc_time *tmp) +int rtc_get (struct rtc_time *tmp) { uchar sec, min, hour, mday, wday, mon, cent, year; int retry = 1; @@ -103,6 +103,8 @@ void rtc_get (struct rtc_time *tmp) debug ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + return 0; } void rtc_set (struct rtc_time *tmp) diff --git a/drivers/rtc/mc13783-rtc.c b/drivers/rtc/mc13783-rtc.c new file mode 100644 index 000000000..35b1b8b25 --- /dev/null +++ b/drivers/rtc/mc13783-rtc.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2008, Guennadi Liakhovetski <lg@denx.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <common.h> +#include <rtc.h> +#include <spi.h> + +int rtc_get(struct rtc_time *rtc) +{ + u32 day1, day2, time; + u32 reg; + int err, tim, i = 0; + + spi_select(1, 0, SPI_MODE_2 | SPI_CS_HIGH); + + do { + reg = 0x2c000000; + err = spi_xfer(0, 32, (uchar *)®, (uchar *)&day1); + + if (err) + return err; + + reg = 0x28000000; + err = spi_xfer(0, 32, (uchar *)®, (uchar *)&time); + + if (err) + return err; + + reg = 0x2c000000; + err = spi_xfer(0, 32, (uchar *)®, (uchar *)&day2); + + if (err) + return err; + } while (day1 != day2 && i++ < 3); + + tim = day1 * 86400 + time; + to_tm(tim, rtc); + + rtc->tm_yday = 0; + rtc->tm_isdst = 0; + + return 0; +} + +void rtc_set(struct rtc_time *rtc) +{ + u32 time, day, reg; + + time = mktime(rtc->tm_year, rtc->tm_mon, rtc->tm_mday, + rtc->tm_hour, rtc->tm_min, rtc->tm_sec); + day = time / 86400; + time %= 86400; + + reg = 0x2c000000 | day | 0x80000000; + spi_xfer(0, 32, (uchar *)®, (uchar *)&day); + + reg = 0x28000000 | time | 0x80000000; + spi_xfer(0, 32, (uchar *)®, (uchar *)&time); +} + +void rtc_reset(void) +{ +} diff --git a/drivers/rtc/mc146818.c b/drivers/rtc/mc146818.c index ab377ed73..70f7017a3 100644 --- a/drivers/rtc/mc146818.c +++ b/drivers/rtc/mc146818.c @@ -57,7 +57,7 @@ static unsigned bcd2bin(uchar c); /* ------------------------------------------------------------------------- */ -void rtc_get (struct rtc_time *tmp) +int rtc_get (struct rtc_time *tmp) { uchar sec, min, hour, mday, wday, mon, year; /* here check if rtc can be accessed */ @@ -101,6 +101,8 @@ void rtc_get (struct rtc_time *tmp) tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); #endif + + return 0; } void rtc_set (struct rtc_time *tmp) diff --git a/drivers/rtc/mcfrtc.c b/drivers/rtc/mcfrtc.c index 27386e586..d235d10f2 100644 --- a/drivers/rtc/mcfrtc.c +++ b/drivers/rtc/mcfrtc.c @@ -39,7 +39,7 @@ #define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) #define STARTOFTIME 1970 -void rtc_get(struct rtc_time *tmp) +int rtc_get(struct rtc_time *tmp) { volatile rtc_t *rtc = (rtc_t *) (CFG_MCFRTC_BASE); @@ -64,6 +64,8 @@ void rtc_get(struct rtc_time *tmp) tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); #endif + + return 0; } void rtc_set(struct rtc_time *tmp) diff --git a/drivers/rtc/mk48t59.c b/drivers/rtc/mk48t59.c index bacdb5b70..59813998e 100644 --- a/drivers/rtc/mk48t59.c +++ b/drivers/rtc/mk48t59.c @@ -135,7 +135,7 @@ void nvram_write(short dest, const void *src, size_t count) /* ------------------------------------------------------------------------- */ -void rtc_get (struct rtc_time *tmp) +int rtc_get (struct rtc_time *tmp) { uchar save_ctrl_a; uchar sec, min, hour, mday, wday, mon, year; @@ -183,6 +183,8 @@ void rtc_get (struct rtc_time *tmp) tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); #endif + + return 0; } void rtc_set (struct rtc_time *tmp) diff --git a/drivers/rtc/mpc5xxx.c b/drivers/rtc/mpc5xxx.c index 216386aba..a6555f5eb 100644 --- a/drivers/rtc/mpc5xxx.c +++ b/drivers/rtc/mpc5xxx.c @@ -55,7 +55,7 @@ typedef struct rtc5200 { /***************************************************************************** * get time *****************************************************************************/ -void rtc_get (struct rtc_time *tmp) +int rtc_get (struct rtc_time *tmp) { RTC5200 *rtc = (RTC5200 *) (CFG_MBAR+0x800); ulong time, date, time2; @@ -81,6 +81,8 @@ void rtc_get (struct rtc_time *tmp) debug ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + return 0; } /***************************************************************************** diff --git a/drivers/rtc/mpc8xx.c b/drivers/rtc/mpc8xx.c index 8d10c0e46..057547bc3 100644 --- a/drivers/rtc/mpc8xx.c +++ b/drivers/rtc/mpc8xx.c @@ -35,7 +35,7 @@ /* ------------------------------------------------------------------------- */ -void rtc_get (struct rtc_time *tmp) +int rtc_get (struct rtc_time *tmp) { volatile immap_t *immr = (immap_t *)CFG_IMMR; ulong tim; @@ -47,6 +47,8 @@ void rtc_get (struct rtc_time *tmp) debug ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + return 0; } void rtc_set (struct rtc_time *tmp) diff --git a/drivers/rtc/pcf8563.c b/drivers/rtc/pcf8563.c index 2d73d5d7e..c384975f3 100644 --- a/drivers/rtc/pcf8563.c +++ b/drivers/rtc/pcf8563.c @@ -41,8 +41,9 @@ static unsigned bcd2bin(uchar c); /* ------------------------------------------------------------------------- */ -void rtc_get (struct rtc_time *tmp) +int rtc_get (struct rtc_time *tmp) { + int rel = 0; uchar sec, min, hour, mday, wday, mon_cent, year; sec = rtc_read (0x02); @@ -65,6 +66,7 @@ void rtc_get (struct rtc_time *tmp) if (sec & 0x80) { puts ("### Warning: RTC Low Voltage - date/time not reliable\n"); + rel = -1; } tmp->tm_sec = bcd2bin (sec & 0x7F); @@ -80,6 +82,8 @@ void rtc_get (struct rtc_time *tmp) debug ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + return rel; } void rtc_set (struct rtc_time *tmp) diff --git a/drivers/rtc/rs5c372.c b/drivers/rtc/rs5c372.c index 3d1346eaa..1c9b75242 100644 --- a/drivers/rtc/rs5c372.c +++ b/drivers/rtc/rs5c372.c @@ -166,7 +166,7 @@ rs5c372_convert_to_time(struct rtc_time *dt, unsigned char *buf) /* * Get the current time from the RTC */ -void +int rtc_get (struct rtc_time *tmp) { unsigned char buf[RS5C372_RAM_SIZE]; @@ -176,7 +176,7 @@ rtc_get (struct rtc_time *tmp) rs5c372_enable(); if (!setup_done) - return; + return -1; memset(buf, 0, sizeof(buf)); @@ -184,12 +184,12 @@ rtc_get (struct rtc_time *tmp) ret = rs5c372_readram(buf, RS5C372_RAM_SIZE); if (ret != 0) { printf("%s: failed\n", __FUNCTION__); - return; + return -1; } rs5c372_convert_to_time(tmp, buf); - return; + return 0; } /* diff --git a/drivers/rtc/rx8025.c b/drivers/rtc/rx8025.c index 9122f12fc..64eafe5c3 100644 --- a/drivers/rtc/rx8025.c +++ b/drivers/rtc/rx8025.c @@ -96,8 +96,9 @@ static unsigned bcd2bin (uchar c); /* * Get the current time from the RTC */ -void rtc_get (struct rtc_time *tmp) +int rtc_get (struct rtc_time *tmp) { + int rel = 0; uchar sec, min, hour, mday, wday, mon, year, ctl2; uchar buf[16]; @@ -118,14 +119,20 @@ void rtc_get (struct rtc_time *tmp) /* dump status */ ctl2 = rtc_read(RTC_CTL2_REG_ADDR); - if (ctl2 & RTC_CTL2_BIT_PON) + if (ctl2 & RTC_CTL2_BIT_PON) { printf("RTC: power-on detected\n"); + rel = -1; + } - if (ctl2 & RTC_CTL2_BIT_VDET) + if (ctl2 & RTC_CTL2_BIT_VDET) { printf("RTC: voltage drop detected\n"); + rel = -1; + } - if (!(ctl2 & RTC_CTL2_BIT_XST)) + if (!(ctl2 & RTC_CTL2_BIT_XST)) { printf("RTC: oscillator stop detected\n"); + rel = -1; + } tmp->tm_sec = bcd2bin (sec & 0x7F); tmp->tm_min = bcd2bin (min & 0x7F); @@ -140,6 +147,8 @@ void rtc_get (struct rtc_time *tmp) DEBUGR ("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + return rel; } /* diff --git a/drivers/rtc/s3c24x0_rtc.c b/drivers/rtc/s3c24x0_rtc.c index 7f8b4fad0..358aef751 100644 --- a/drivers/rtc/s3c24x0_rtc.c +++ b/drivers/rtc/s3c24x0_rtc.c @@ -70,7 +70,7 @@ static unsigned char bin2bcd (unsigned int n) /* ------------------------------------------------------------------------- */ -void rtc_get (struct rtc_time *tmp) +int rtc_get (struct rtc_time *tmp) { S3C24X0_RTC * const rtc = S3C24X0_GetBase_RTC(); uchar sec, min, hour, mday, wday, mon, year; @@ -131,6 +131,8 @@ void rtc_get (struct rtc_time *tmp) tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); #endif + + return 0; } void rtc_set (struct rtc_time *tmp) diff --git a/drivers/rtc/x1205.c b/drivers/rtc/x1205.c index 319f0512c..0e1813917 100644 --- a/drivers/rtc/x1205.c +++ b/drivers/rtc/x1205.c @@ -104,7 +104,7 @@ static void rtc_write(int reg, u8 val) * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch * Epoch is initialized as 2000. Time is set to UTC. */ -void rtc_get(struct rtc_time *tm) +int rtc_get(struct rtc_time *tm) { u8 buf[8]; @@ -130,6 +130,8 @@ void rtc_get(struct rtc_time *tm) __FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); + + return 0; } void rtc_set(struct rtc_time *tm) diff --git a/drivers/serial/serial_sh.c b/drivers/serial/serial_sh.c index 70fd23ff0..522f96d5d 100644 --- a/drivers/serial/serial_sh.c +++ b/drivers/serial/serial_sh.c @@ -37,39 +37,46 @@ #define SCFCR (vu_short *)(SCIF_BASE + 0x18) #define SCFDR (vu_short *)(SCIF_BASE + 0x1C) #ifdef CONFIG_CPU_SH7720 /* SH7720 specific */ -#define SCFSR (vu_short *)(SCIF_BASE + 0x14) /* SCSSR */ -#define SCFTDR (vu_char *)(SCIF_BASE + 0x20) -#define SCFRDR (vu_char *)(SCIF_BASE + 0x24) +# define SCFSR (vu_short *)(SCIF_BASE + 0x14) /* SCSSR */ +# define SCFTDR (vu_char *)(SCIF_BASE + 0x20) +# define SCFRDR (vu_char *)(SCIF_BASE + 0x24) #else -#define SCFTDR (vu_char *)(SCIF_BASE + 0xC) -#define SCFSR (vu_short *)(SCIF_BASE + 0x10) -#define SCFRDR (vu_char *)(SCIF_BASE + 0x14) +# define SCFTDR (vu_char *)(SCIF_BASE + 0xC) +# define SCFSR (vu_short *)(SCIF_BASE + 0x10) +# define SCFRDR (vu_char *)(SCIF_BASE + 0x14) #endif -#if defined(CONFIG_SH4A) -#define SCRFDR (vu_short *)(SCIF_BASE + 0x20) -#define SCSPTR (vu_short *)(SCIF_BASE + 0x24) -#define SCLSR (vu_short *)(SCIF_BASE + 0x28) -#define SCRER (vu_short *)(SCIF_BASE + 0x2C) -#define LSR_ORER 1 -#elif defined (CONFIG_SH4) -#define SCSPTR (vu_short *)(SCIF_BASE + 0x20) -#define SCLSR (vu_short *)(SCIF_BASE + 0x24) -#define LSR_ORER 1 -#elif defined (CONFIG_SH3) -#ifdef CONFIG_CPU_SH7720 /* SH7720 specific */ -#define SCLSR (vu_short *)(SCIF_BASE + 0x24) -#define LSR_ORER 0x0200 -#else -#define SCLSR SCFSR /* SCSSR */ -#define LSR_ORER 1 -#endif +#if defined(CONFIG_CPU_SH7780) || \ + defined(CONFIG_CPU_SH7785) +# define SCRFDR (vu_short *)(SCIF_BASE + 0x20) +# define SCSPTR (vu_short *)(SCIF_BASE + 0x24) +# define SCLSR (vu_short *)(SCIF_BASE + 0x28) +# define SCRER (vu_short *)(SCIF_BASE + 0x2C) +# define LSR_ORER 1 +# define FIFOLEVEL_MASK 0xFF +#elif defined(CONFIG_CPU_SH7750) || \ + defined(CONFIG_CPU_SH7751) || \ + defined(CONFIG_CPU_SH7722) +# define SCSPTR (vu_short *)(SCIF_BASE + 0x20) +# define SCLSR (vu_short *)(SCIF_BASE + 0x24) +# define LSR_ORER 1 +# define FIFOLEVEL_MASK 0x1F +#elif defined(CONFIG_CPU_SH7720) +# define SCLSR (vu_short *)(SCIF_BASE + 0x24) +# define LSR_ORER 0x0200 +# define FIFOLEVEL_MASK 0x1F +#elif defined(CONFIG_CPU_SH7710) + defined(CONFIG_CPU_SH7712) +# define SCLSR SCFSR /* SCSSR */ +# define LSR_ORER 1 +# define FIFOLEVEL_MASK 0x1F #endif +/* SCBRR register value setting */ #if defined(CONFIG_CPU_SH7720) -#define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1) +# define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1) #else /* Generic SuperH */ -#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(32*bps)-1) +# define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(32*bps)-1) #endif #define SCR_RE (1 << 4) @@ -105,14 +112,13 @@ int serial_init (void) return 0; } -static int serial_tx_fifo_level (void) -{ - return (*SCFDR >> 8) & 0x1F; -} - static int serial_rx_fifo_level (void) { - return (*SCFDR >> 0) & 0x1F; +#if defined(CONFIG_SH4A) + return (*SCRFDR >> 0) & FIFOLEVEL_MASK; +#else + return (*SCFDR >> 0) & FIFOLEVEL_MASK; +#endif } void serial_raw_putc (const char c) diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 0b7a2dfd3..bc8a10412 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk LIB := $(obj)libspi.a COBJS-y += mpc8xxx_spi.o +COBJS-$(CONFIG_MXC_SPI) += mxc_spi.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c new file mode 100644 index 000000000..b2e3ab9b6 --- /dev/null +++ b/drivers/spi/mxc_spi.c @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2008, Guennadi Liakhovetski <lg@denx.de> + * + * 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 <common.h> +#include <spi.h> +#include <asm/io.h> + +#ifdef CONFIG_MX27 +/* i.MX27 has a completely wrong register layout and register definitions in the + * datasheet, the correct one is in the Freescale's Linux driver */ + +#error "i.MX27 CSPI not supported due to drastic differences in register definisions" \ +"See linux mxc_spi driver from Freescale for details." + +#else + +#define MXC_CSPIRXDATA 0x00 +#define MXC_CSPITXDATA 0x04 +#define MXC_CSPICTRL 0x08 +#define MXC_CSPIINT 0x0C +#define MXC_CSPIDMA 0x10 +#define MXC_CSPISTAT 0x14 +#define MXC_CSPIPERIOD 0x18 +#define MXC_CSPITEST 0x1C +#define MXC_CSPIRESET 0x00 + +#define MXC_CSPICTRL_EN (1 << 0) +#define MXC_CSPICTRL_MODE (1 << 1) +#define MXC_CSPICTRL_XCH (1 << 2) +#define MXC_CSPICTRL_SMC (1 << 3) +#define MXC_CSPICTRL_POL (1 << 4) +#define MXC_CSPICTRL_PHA (1 << 5) +#define MXC_CSPICTRL_SSCTL (1 << 6) +#define MXC_CSPICTRL_SSPOL (1 << 7) +#define MXC_CSPICTRL_CHIPSELECT(x) (((x) & 0x3) << 24) +#define MXC_CSPICTRL_BITCOUNT(x) (((x) & 0x1f) << 8) +#define MXC_CSPICTRL_DATARATE(x) (((x) & 0x7) << 16) + +#define MXC_CSPIPERIOD_32KHZ (1 << 15) + +static unsigned long spi_bases[] = { + 0x43fa4000, + 0x50010000, + 0x53f84000, +}; + +static unsigned long spi_base; + +#endif + +spi_chipsel_type spi_chipsel[] = { + (spi_chipsel_type)0, + (spi_chipsel_type)1, + (spi_chipsel_type)2, + (spi_chipsel_type)3, +}; +int spi_chipsel_cnt = sizeof(spi_chipsel) / sizeof(spi_chipsel[0]); + +static inline u32 reg_read(unsigned long addr) +{ + return *(volatile unsigned long*)addr; +} + +static inline void reg_write(unsigned long addr, u32 val) +{ + *(volatile unsigned long*)addr = val; +} + +static u32 spi_xchg_single(u32 data, int bitlen) +{ + + unsigned int cfg_reg = reg_read(spi_base + MXC_CSPICTRL); + + if (MXC_CSPICTRL_BITCOUNT(bitlen - 1) != (cfg_reg & MXC_CSPICTRL_BITCOUNT(31))) { + cfg_reg = (cfg_reg & ~MXC_CSPICTRL_BITCOUNT(31)) | + MXC_CSPICTRL_BITCOUNT(bitlen - 1); + reg_write(spi_base + MXC_CSPICTRL, cfg_reg); + } + + reg_write(spi_base + MXC_CSPITXDATA, data); + + cfg_reg |= MXC_CSPICTRL_XCH; + + reg_write(spi_base + MXC_CSPICTRL, cfg_reg); + + while (reg_read(spi_base + MXC_CSPICTRL) & MXC_CSPICTRL_XCH) + ; + + return reg_read(spi_base + MXC_CSPIRXDATA); +} + +int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) +{ + int n_blks = (bitlen + 31) / 32; + u32 *out_l, *in_l; + int i; + + if ((int)dout & 3 || (int)din & 3) { + printf("Error: unaligned buffers in: %p, out: %p\n", din, dout); + return 1; + } + + if (!spi_base) + spi_select(CONFIG_MXC_SPI_IFACE, (int)chipsel, SPI_MODE_2 | SPI_CS_HIGH); + + for (i = 0, in_l = (u32 *)din, out_l = (u32 *)dout; + i < n_blks; + i++, in_l++, out_l++, bitlen -= 32) + *in_l = spi_xchg_single(*out_l, bitlen); + + return 0; +} + +void spi_init(void) +{ +} + +int spi_select(unsigned int bus, unsigned int dev, unsigned long mode) +{ + unsigned int ctrl_reg; + + if (bus >= sizeof(spi_bases) / sizeof(spi_bases[0]) || + dev > 3) + return 1; + + spi_base = spi_bases[bus]; + + ctrl_reg = MXC_CSPICTRL_CHIPSELECT(dev) | + MXC_CSPICTRL_BITCOUNT(31) | + MXC_CSPICTRL_DATARATE(7) | /* FIXME: calculate data rate */ + MXC_CSPICTRL_EN | + MXC_CSPICTRL_MODE; + + if (mode & SPI_CPHA) + ctrl_reg |= MXC_CSPICTRL_PHA; + if (!(mode & SPI_CPOL)) + ctrl_reg |= MXC_CSPICTRL_POL; + if (mode & SPI_CS_HIGH) + ctrl_reg |= MXC_CSPICTRL_SSPOL; + + reg_write(spi_base + MXC_CSPIRESET, 1); + udelay(1); + reg_write(spi_base + MXC_CSPICTRL, ctrl_reg); + reg_write(spi_base + MXC_CSPIPERIOD, + MXC_CSPIPERIOD_32KHZ); + reg_write(spi_base + MXC_CSPIINT, 0); + + return 0; +} diff --git a/drivers/usb/usb_ohci.c b/drivers/usb/usb_ohci.c index 829bbcae3..ee0f2e45b 100644 --- a/drivers/usb/usb_ohci.c +++ b/drivers/usb/usb_ohci.c @@ -86,11 +86,11 @@ * e.g. PCI controllers need this */ #ifdef CFG_OHCI_SWAP_REG_ACCESS -# define readl(a) __swap_32(*((vu_long *)(a))) -# define writel(a, b) (*((vu_long *)(b)) = __swap_32((vu_long)a)) +# define readl(a) __swap_32(*((volatile u32 *)(a))) +# define writel(a, b) (*((volatile u32 *)(b)) = __swap_32((volatile u32)a)) #else -# define readl(a) (*((vu_long *)(a))) -# define writel(a, b) (*((vu_long *)(b)) = ((vu_long)a)) +# define readl(a) (*((volatile u32 *)(a))) +# define writel(a, b) (*((volatile u32 *)(b)) = ((volatile u32)a)) #endif /* CFG_OHCI_SWAP_REG_ACCESS */ #define min_t(type,x,y) ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) @@ -111,7 +111,6 @@ static struct pci_device_id ohci_pci_ids[] = { #define dbg(format, arg...) do {} while(0) #endif /* DEBUG */ #define err(format, arg...) printf("ERROR: " format "\n", ## arg) -#undef SHOW_INFO #ifdef SHOW_INFO #define info(format, arg...) printf("INFO: " format "\n", ## arg) #else @@ -139,28 +138,14 @@ int got_rhsc; /* device which was disconnected */ struct usb_device *devgone; -/*-------------------------------------------------------------------------*/ - -/* AMD-756 (D2 rev) reports corrupt register contents in some cases. - * The erratum (#4) description is incorrect. AMD's workaround waits - * till some bits (mostly reserved) are clear; ok for all revs. - */ -#define OHCI_QUIRK_AMD756 0xabcd -#define read_roothub(hc, register, mask) ({ \ - u32 temp = readl (&hc->regs->roothub.register); \ - if (hc->flags & OHCI_QUIRK_AMD756) \ - while (temp & mask) \ - temp = readl (&hc->regs->roothub.register); \ - temp; }) - -static u32 roothub_a (struct ohci *hc) - { return read_roothub (hc, a, 0xfc0fe000); } +static inline u32 roothub_a (struct ohci *hc) + { return readl (&hc->regs->roothub.a); } static inline u32 roothub_b (struct ohci *hc) { return readl (&hc->regs->roothub.b); } static inline u32 roothub_status (struct ohci *hc) { return readl (&hc->regs->roothub.status); } -static u32 roothub_portstatus (struct ohci *hc, int i) - { return read_roothub (hc, portstatus [i], 0xffe0fce0); } +static inline u32 roothub_portstatus (struct ohci *hc, int i) + { return readl (&hc->regs->roothub.portstatus[i]); } /* forward declaration */ static int hc_interrupt (void); diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c index 4f7306725..68b9861d4 100644 --- a/drivers/video/cfb_console.c +++ b/drivers/video/cfb_console.c @@ -849,6 +849,7 @@ int video_display_bitmap (ulong bmp_image, int x, int y) if (!((bmp->header.signature[0] == 'B') && (bmp->header.signature[1] == 'M'))) { printf ("Error: no valid bmp.gz image at %lx\n", bmp_image); + free(dst); return 1; } #else @@ -869,6 +870,10 @@ int video_display_bitmap (ulong bmp_image, int x, int y) if (compression != BMP_BI_RGB) { printf ("Error: compression type %ld not supported\n", compression); +#ifdef CONFIG_VIDEO_BMP_GZIP + if (dst) + free(dst); +#endif return 1; } diff --git a/drivers/video/mb862xx.c b/drivers/video/mb862xx.c index bfb057f51..9684cf3b7 100644 --- a/drivers/video/mb862xx.c +++ b/drivers/video/mb862xx.c @@ -36,6 +36,9 @@ #include "videomodes.h" #include <mb862xx.h> +#if defined(CONFIG_POST) +#include <post.h> +#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 |