diff options
Diffstat (limited to 'drivers')
38 files changed, 3108 insertions, 227 deletions
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 5f1298d..a09cd2a 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -29,6 +29,7 @@ COBJS-y += ahci.o COBJS-y += ata_piix.o COBJS-$(CONFIG_FSL_SATA) += fsl_sata.o COBJS-$(CONFIG_LIBATA) += libata.o +COBJS-$(CONFIG_SATA_SIL3114) += sata_sil3114.o COBJS-y += sil680.o COBJS-y += sym53c8xx.o COBJS-y += systemace.o diff --git a/drivers/block/fsl_sata.c b/drivers/block/fsl_sata.c index d14f5bc..d441a30 100644 --- a/drivers/block/fsl_sata.c +++ b/drivers/block/fsl_sata.c @@ -248,6 +248,10 @@ int init_sata(int dev) else printf(" %s ", sata->name); + /* Wait PHY RDY signal changed for 500ms */ + ata_wait_register(®->hstatus, HSTATUS_PHY_RDY, + HSTATUS_PHY_RDY, 500); + /* Check PHYRDY */ val32 = in_le32(®->hstatus); if (val32 & HSTATUS_PHY_RDY) { @@ -258,6 +262,10 @@ int init_sata(int dev) return -1; } + /* Wait for signature updated, which is 1st D2H */ + ata_wait_register(®->hstatus, HSTATUS_SIGNATURE, + HSTATUS_SIGNATURE, 10000); + if (val32 & HSTATUS_SIGNATURE) { sig = in_le32(®->sig); debug("Signature updated, the sig =%08x\n\r", sig); diff --git a/drivers/block/sata_sil3114.c b/drivers/block/sata_sil3114.c new file mode 100644 index 0000000..8399737 --- /dev/null +++ b/drivers/block/sata_sil3114.c @@ -0,0 +1,839 @@ +/* + * Copyright (C) Excito Elektronik i Skåne AB, All rights reserved. + * Author: Tor Krill <tor@excito.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 + * + * This is a driver for Silicon Image sil3114 sata chip modelled on + * the ata_piix driver + */ + +#include <common.h> +#include <pci.h> +#include <command.h> +#include <config.h> +#include <asm/byteorder.h> +#include <asm/io.h> +#include <ide.h> +#include <libata.h> +#include "sata_sil3114.h" + +/* Convert sectorsize to wordsize */ +#define ATA_SECTOR_WORDS (ATA_SECT_SIZE/2) + +/* Forwards */ +u8 sil3114_spin_up (int num); +u8 sil3114_spin_down (int num); +static int sata_bus_softreset (int num); +static void sata_identify (int num, int dev); +static u8 check_power_mode (int num); +static void sata_port (struct sata_ioports *ioport); +static void set_Feature_cmd (int num, int dev); +static u8 sata_busy_wait (struct sata_ioports *ioaddr, int bits, + unsigned int max, u8 usealtstatus); +static u8 sata_chk_status (struct sata_ioports *ioaddr, u8 usealtstatus); +static void msleep (int count); + +static u32 iobase[6] = { 0, 0, 0, 0, 0, 0}; /* PCI BAR registers for device */ +extern block_dev_desc_t sata_dev_desc[CFG_SATA_MAX_DEVICE]; + +static struct sata_port port[CFG_SATA_MAX_DEVICE]; + +static void output_data (struct sata_ioports *ioaddr, u16 * sect_buf, int words) +{ + while (words--) { + __raw_writew (*sect_buf++, (void *)ioaddr->data_addr); + } +} + +static int input_data (struct sata_ioports *ioaddr, u16 * sect_buf, int words) +{ + while (words--) { + *sect_buf++ = __raw_readw ((void *)ioaddr->data_addr); + } + return 0; +} + +static int sata_bus_softreset (int num) +{ + u8 status = 0; + + port[num].dev_mask = 1; + + port[num].ctl_reg = 0x08; /*Default value of control reg */ + writeb (port[num].ctl_reg, port[num].ioaddr.ctl_addr); + udelay (10); + writeb (port[num].ctl_reg | ATA_SRST, port[num].ioaddr.ctl_addr); + udelay (10); + writeb (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, 0); + while ((status & ATA_BUSY)) { + msleep (100); + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 3, 0); + } + + 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, 0); + } + + if (status & ATA_BUSY) { + printf ("ata%u failed to respond : ", port); + printf ("bus reset failed\n"); + port[num].dev_mask = 0; + return 1; + } + return 0; +} + +static void sata_identify (int num, int dev) +{ + u8 cmd = 0, status = 0, devno = num; + u16 iobuf[ATA_SECTOR_WORDS]; + u64 n_sectors = 0; + + memset (iobuf, 0, sizeof (iobuf)); + + if (!(port[num].dev_mask & 0x01)) { + printf ("dev%d is not present on port#%d\n", dev, num); + return; + } + + debug ("port=%d dev=%d\n", num, dev); + + status = 0; + cmd = ATA_CMD_ID_ATA; /*Device Identify Command */ + writeb (cmd, port[num].ioaddr.command_addr); + readb (port[num].ioaddr.altstatus_addr); + udelay (10); + + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 1000, 0); + if (status & ATA_ERR) { + printf ("\ndevice not responding\n"); + port[num].dev_mask &= ~0x01; + return; + } + + input_data (&port[num].ioaddr, iobuf, ATA_SECTOR_WORDS); + + ata_swap_buf_le16 (iobuf, ATA_SECTOR_WORDS); + + debug ("Specific config: %x\n", iobuf[2]); + + /* we require LBA and DMA support (bits 8 & 9 of word 49) */ + if (!ata_id_has_dma (iobuf) || !ata_id_has_lba (iobuf)) { + debug ("ata%u: no dma/lba\n", num); + } +#ifdef DEBUG + ata_dump_id (iobuf); +#endif + n_sectors = ata_id_n_sectors (iobuf); + + if (n_sectors == 0) { + port[num].dev_mask &= ~0x01; + return; + } + ata_id_c_string (iobuf, (unsigned char *)sata_dev_desc[devno].revision, + ATA_ID_FW_REV, sizeof (sata_dev_desc[devno].revision)); + ata_id_c_string (iobuf, (unsigned char *)sata_dev_desc[devno].vendor, + ATA_ID_PROD, sizeof (sata_dev_desc[devno].vendor)); + ata_id_c_string (iobuf, (unsigned char *)sata_dev_desc[devno].product, + ATA_ID_SERNO, sizeof (sata_dev_desc[devno].product)); + + /* TODO - atm we asume harddisk ie not removable */ + sata_dev_desc[devno].removable = 0; + + sata_dev_desc[devno].lba = (u32) n_sectors; + debug ("lba=0x%x\n", sata_dev_desc[devno].lba); + +#ifdef CONFIG_LBA48 + if (iobuf[83] & (1 << 10)) { + sata_dev_desc[devno].lba48 = 1; + } else { + sata_dev_desc[devno].lba48 = 0; + } +#endif + + /* assuming HD */ + sata_dev_desc[devno].type = DEV_TYPE_HARDDISK; + sata_dev_desc[devno].blksz = ATA_SECT_SIZE; + sata_dev_desc[devno].lun = 0; /* just to fill something in... */ +} + +static void set_Feature_cmd (int num, int dev) +{ + u8 status = 0; + + if (!(port[num].dev_mask & 0x01)) { + debug ("dev%d is not present on port#%d\n", dev, num); + return; + } + + writeb (SETFEATURES_XFER, port[num].ioaddr.feature_addr); + writeb (XFER_PIO_4, port[num].ioaddr.nsect_addr); + writeb (0, port[num].ioaddr.lbal_addr); + writeb (0, port[num].ioaddr.lbam_addr); + writeb (0, port[num].ioaddr.lbah_addr); + + writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); + writeb (ATA_CMD_SET_FEATURES, port[num].ioaddr.command_addr); + + udelay (50); + msleep (150); + + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 5000, 0); + if ((status & (ATA_BUSY | ATA_ERR))) { + printf ("Error : status 0x%02x\n", status); + port[num].dev_mask &= ~0x01; + } +} + +u8 sil3114_spin_down (int num) +{ + u8 status = 0; + + debug ("Spin down disk\n"); + + if (!(port[num].dev_mask & 0x01)) { + debug ("Device ata%d is not present\n", num); + return 1; + } + + if ((status = check_power_mode (num)) == 0x00) { + debug ("Already in standby\n"); + return 0; + } + + if (status == 0x01) { + printf ("Failed to check power mode on ata%d\n", num); + return 1; + } + + if (!((status = sata_chk_status (&port[num].ioaddr, 0)) & ATA_DRDY)) { + printf ("Device ata%d not ready\n", num); + return 1; + } + + writeb (0x00, port[num].ioaddr.feature_addr); + + writeb (0x00, port[num].ioaddr.nsect_addr); + writeb (0x00, port[num].ioaddr.lbal_addr); + writeb (0x00, port[num].ioaddr.lbam_addr); + writeb (0x00, port[num].ioaddr.lbah_addr); + + writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); + writeb (ATA_CMD_STANDBY, port[num].ioaddr.command_addr); + + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 30000, 0); + if ((status & (ATA_BUSY | ATA_ERR))) { + printf ("Error waiting for disk spin down: status 0x%02x\n", + status); + port[num].dev_mask &= ~0x01; + return 1; + } + return 0; +} + +u8 sil3114_spin_up (int num) +{ + u8 status = 0; + + debug ("Spin up disk\n"); + + if (!(port[num].dev_mask & 0x01)) { + debug ("Device ata%d is not present\n", num); + return 1; + } + + if ((status = check_power_mode (num)) != 0x00) { + if (status == 0x01) { + printf ("Failed to check power mode on ata%d\n", num); + return 1; + } else { + /* should be up and running already */ + return 0; + } + } + + if (!((status = sata_chk_status (&port[num].ioaddr, 0)) & ATA_DRDY)) { + printf ("Device ata%d not ready\n", num); + return 1; + } + + debug ("Stautus of device check: %d\n", status); + + writeb (0x00, port[num].ioaddr.feature_addr); + + writeb (0x00, port[num].ioaddr.nsect_addr); + writeb (0x00, port[num].ioaddr.lbal_addr); + writeb (0x00, port[num].ioaddr.lbam_addr); + writeb (0x00, port[num].ioaddr.lbah_addr); + + writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); + writeb (ATA_CMD_IDLE, port[num].ioaddr.command_addr); + + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 30000, 0); + if ((status & (ATA_BUSY | ATA_ERR))) { + printf ("Error waiting for disk spin up: status 0x%02x\n", + status); + port[num].dev_mask &= ~0x01; + return 1; + } + + /* Wait for disk to enter Active state */ + do { + msleep (10); + status = check_power_mode (num); + } while ((status == 0x00) || (status == 0x80)); + + if (status == 0x01) { + printf ("Falied waiting for disk to spin up\n"); + return 1; + } + + return 0; +} + +/* Return value is not the usual here + * 0x00 - Device stand by + * 0x01 - Operation failed + * 0x80 - Device idle + * 0xff - Device active +*/ +static u8 check_power_mode (int num) +{ + u8 status = 0; + u8 res = 0; + if (!(port[num].dev_mask & 0x01)) { + debug ("Device ata%d is not present\n", num); + return 1; + } + + if (!(sata_chk_status (&port[num].ioaddr, 0) & ATA_DRDY)) { + printf ("Device ata%d not ready\n", num); + return 1; + } + + writeb (0, port[num].ioaddr.feature_addr); + writeb (0, port[num].ioaddr.nsect_addr); + writeb (0, port[num].ioaddr.lbal_addr); + writeb (0, port[num].ioaddr.lbam_addr); + writeb (0, port[num].ioaddr.lbah_addr); + + writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); + writeb (ATA_CMD_CHK_POWER, port[num].ioaddr.command_addr); + + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 5000, 0); + if ((status & (ATA_BUSY | ATA_ERR))) { + printf + ("Error waiting for check power mode complete : status 0x%02x\n", + status); + port[num].dev_mask &= ~0x01; + return 1; + } + res = readb (port[num].ioaddr.nsect_addr); + debug ("Check powermode: %d\n", res); + return res; + +} + +static 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; +} + +static u8 wait_for_irq (int num, unsigned int max) +{ + + u32 port = iobase[5]; + switch (num) { + case 0: + port += VND_TF_CNST_CH0; + break; + case 1: + port += VND_TF_CNST_CH1; + break; + case 2: + port += VND_TF_CNST_CH2; + break; + case 3: + port += VND_TF_CNST_CH3; + break; + default: + return 1; + } + + do { + if (readl (port) & VND_TF_CNST_INTST) { + break; + } + udelay (1000); + max--; + } while ((max > 0)); + + return (max == 0); +} + +static u8 sata_busy_wait (struct sata_ioports *ioaddr, int bits, + unsigned int max, u8 usealtstatus) +{ + u8 status; + + do { + if (!((status = sata_chk_status (ioaddr, usealtstatus)) & bits)) { + break; + } + udelay (1000); + max--; + } while ((status & bits) && (max > 0)); + + return status; +} + +static u8 sata_chk_status (struct sata_ioports *ioaddr, u8 usealtstatus) +{ + if (!usealtstatus) { + return readb (ioaddr->status_addr); + } else { + return readb (ioaddr->altstatus_addr); + } +} + +static void msleep (int count) +{ + int i; + + for (i = 0; i < count; i++) + udelay (1000); +} + +/* Read up to 255 sectors + * + * Returns sectors read +*/ +static u8 do_one_read (int device, ulong block, u8 blkcnt, u16 * buff, + uchar lba48) +{ + + u8 sr = 0; + u8 status; + u64 blknr = (u64) block; + + if (!(sata_chk_status (&port[device].ioaddr, 0) & ATA_DRDY)) { + printf ("Device ata%d not ready\n", device); + return 0; + } + + /* Set up transfer */ +#ifdef CONFIG_LBA48 + if (lba48) { + /* write high bits */ + writeb (0, port[device].ioaddr.nsect_addr); + writeb ((blknr >> 24) & 0xFF, port[device].ioaddr.lbal_addr); + writeb ((blknr >> 32) & 0xFF, port[device].ioaddr.lbam_addr); + writeb ((blknr >> 40) & 0xFF, port[device].ioaddr.lbah_addr); + } +#endif + writeb (blkcnt, port[device].ioaddr.nsect_addr); + writeb (((blknr) >> 0) & 0xFF, port[device].ioaddr.lbal_addr); + writeb ((blknr >> 8) & 0xFF, port[device].ioaddr.lbam_addr); + writeb ((blknr >> 16) & 0xFF, port[device].ioaddr.lbah_addr); + +#ifdef CONFIG_LBA48 + if (lba48) { + writeb (ATA_LBA, port[device].ioaddr.device_addr); + writeb (ATA_CMD_PIO_READ_EXT, port[device].ioaddr.command_addr); + } else +#endif + { + writeb (ATA_LBA | ((blknr >> 24) & 0xF), + port[device].ioaddr.device_addr); + writeb (ATA_CMD_PIO_READ, port[device].ioaddr.command_addr); + } + + status = sata_busy_wait (&port[device].ioaddr, ATA_BUSY, 10000, 1); + + if (status & ATA_BUSY) { + u8 err = 0; + + printf ("Device %d not responding status %d\n", device, status); + err = readb (port[device].ioaddr.error_addr); + printf ("Error reg = 0x%x\n", err); + + return (sr); + } + while (blkcnt--) { + + if (wait_for_irq (device, 500)) { + printf ("ata%u irq failed\n", device); + return sr; + } + + status = sata_chk_status (&port[device].ioaddr, 0); + if (status & ATA_ERR) { + printf ("ata%u error %d\n", device, + readb (port[device].ioaddr.error_addr)); + return sr; + } + /* Read one sector */ + input_data (&port[device].ioaddr, buff, ATA_SECTOR_WORDS); + buff += ATA_SECTOR_WORDS; + sr++; + + } + return sr; +} + +ulong sata_read (int device, ulong block, lbaint_t blkcnt, void *buff) +{ + ulong n = 0, sread; + u16 *buffer = (u16 *) buff; + u8 status = 0; + u64 blknr = (u64) block; + unsigned char lba48 = 0; + +#ifdef CONFIG_LBA48 + if (blknr > 0xfffffff) { + if (!sata_dev_desc[device].lba48) { + printf ("Drive doesn't support 48-bit addressing\n"); + return 0; + } + /* more than 28 bits used, use 48bit mode */ + lba48 = 1; + } +#endif + + while (blkcnt > 0) { + + if (blkcnt > 255) { + sread = 255; + } else { + sread = blkcnt; + } + + status = do_one_read (device, blknr, sread, buffer, lba48); + if (status != sread) { + printf ("Read failed\n"); + return n; + } + + blkcnt -= sread; + blknr += sread; + n += sread; + buffer += sread * ATA_SECTOR_WORDS; + } + return n; +} + +ulong sata_write (int device, ulong block, lbaint_t blkcnt, const void *buff) +{ + ulong n = 0; + u16 *buffer = (u16 *) buff; + unsigned char status = 0, num = 0; + u64 blknr = (u64) block; +#ifdef CONFIG_LBA48 + unsigned char lba48 = 0; + + if (blknr > 0xfffffff) { + if (!sata_dev_desc[device].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; + + while (blkcnt-- > 0) { + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500, 0); + 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 */ + writeb (0, port[num].ioaddr.nsect_addr); + writeb ((blknr >> 24) & 0xFF, + port[num].ioaddr.lbal_addr); + writeb ((blknr >> 32) & 0xFF, + port[num].ioaddr.lbam_addr); + writeb ((blknr >> 40) & 0xFF, + port[num].ioaddr.lbah_addr); + } +#endif + writeb (1, port[num].ioaddr.nsect_addr); + writeb ((blknr >> 0) & 0xFF, port[num].ioaddr.lbal_addr); + writeb ((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr); + writeb ((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr); +#ifdef CONFIG_LBA48 + if (lba48) { + writeb (ATA_LBA, port[num].ioaddr.device_addr); + writeb (ATA_CMD_PIO_WRITE_EXT, port[num].ioaddr.command_addr); + } else +#endif + { + writeb (ATA_LBA | ((blknr >> 24) & 0xF), + port[num].ioaddr.device_addr); + writeb (ATA_CMD_PIO_WRITE, port[num].ioaddr.command_addr); + } + + msleep (50); + /*may take up to 4 sec */ + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 4000, 0); + if ((status & (ATA_DRQ | ATA_BUSY | ATA_ERR)) != ATA_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_SECTOR_WORDS); + readb (port[num].ioaddr.altstatus_addr); + udelay (50); + + ++n; + ++blknr; + buffer += ATA_SECTOR_WORDS; + } + return n; +} + +/* Driver implementation */ +static u8 sil_get_device_cache_line (pci_dev_t pdev) +{ + u8 cache_line = 0; + pci_read_config_byte (pdev, PCI_CACHE_LINE_SIZE, &cache_line); + return cache_line; +} + +int init_sata (int dev) +{ + static u8 init_done = 0; + static int res = 1; + pci_dev_t devno; + u8 cls = 0; + u16 cmd = 0; + u32 sconf = 0; + + if (init_done) { + return res; + } + + init_done = 1; + + if ((devno = pci_find_device (SIL_VEND_ID, SIL3114_DEVICE_ID, 0)) == -1) { + res = 1; + return res; + } + + /* Read out all BARs, even though we only use MMIO from BAR5 */ + pci_read_config_dword (devno, PCI_BASE_ADDRESS_0, &iobase[0]); + pci_read_config_dword (devno, PCI_BASE_ADDRESS_1, &iobase[1]); + pci_read_config_dword (devno, PCI_BASE_ADDRESS_2, &iobase[2]); + pci_read_config_dword (devno, PCI_BASE_ADDRESS_3, &iobase[3]); + pci_read_config_dword (devno, PCI_BASE_ADDRESS_4, &iobase[4]); + pci_read_config_dword (devno, PCI_BASE_ADDRESS_5, &iobase[5]); + + if ((iobase[0] == 0xFFFFFFFF) || (iobase[1] == 0xFFFFFFFF) || + (iobase[2] == 0xFFFFFFFF) || (iobase[3] == 0xFFFFFFFF) || + (iobase[4] == 0xFFFFFFFF) || (iobase[5] == 0xFFFFFFFF)) { + printf ("Error no base addr for SATA controller\n"); + res = 1; + return res; + } + + /* mask off unused bits */ + iobase[0] &= 0xfffffffc; + iobase[1] &= 0xfffffff8; + iobase[2] &= 0xfffffffc; + iobase[3] &= 0xfffffff8; + iobase[4] &= 0xfffffff0; + iobase[5] &= 0xfffffc00; + + /* from sata_sil in Linux kernel */ + cls = sil_get_device_cache_line (devno); + if (cls) { + cls >>= 3; + cls++; /* cls = (line_size/8)+1 */ + writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH0); + writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH1); + writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH2); + writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH3); + } else { + printf ("Cache line not set. Driver may not function\n"); + } + + /* Enable operation */ + pci_read_config_word (devno, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; + pci_write_config_word (devno, PCI_COMMAND, cmd); + + /* Disable interrupt usage */ + pci_read_config_dword (devno, VND_SYSCONFSTAT, &sconf); + sconf |= (VND_SYSCONFSTAT_CHN_0_INTBLOCK | VND_SYSCONFSTAT_CHN_1_INTBLOCK); + pci_write_config_dword (devno, VND_SYSCONFSTAT, sconf); + + res = 0; + return res; +} + +/* Check if device is connected to port */ +int sata_bus_probe (int portno) +{ + u32 port = iobase[5]; + u32 val; + switch (portno) { + case 0: + port += VND_SSTATUS_CH0; + break; + case 1: + port += VND_SSTATUS_CH1; + break; + case 2: + port += VND_SSTATUS_CH2; + break; + case 3: + port += VND_SSTATUS_CH3; + break; + default: + return 0; + } + val = readl (port); + if ((val & SATA_DET_PRES) == SATA_DET_PRES) { + return 1; + } else { + return 0; + } +} + +int sata_phy_reset (int portno) +{ + u32 port = iobase[5]; + u32 val; + switch (portno) { + case 0: + port += VND_SCONTROL_CH0; + break; + case 1: + port += VND_SCONTROL_CH1; + break; + case 2: + port += VND_SCONTROL_CH2; + break; + case 3: + port += VND_SCONTROL_CH3; + break; + default: + return 0; + } + val = readl (port); + writel (val | SATA_SC_DET_RST, port); + msleep (150); + writel (val & ~SATA_SC_DET_RST, port); + return 0; +} + +int scan_sata (int dev) +{ + /* A bit brain dead, but the code has a legacy */ + switch (dev) { + case 0: + port[0].port_no = 0; + port[0].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH0; + port[0].ioaddr.altstatus_addr = port[0].ioaddr.ctl_addr = + (iobase[5] + VND_TF2_CH0) | ATA_PCI_CTL_OFS; + port[0].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH0; + break; + case 1: + port[1].port_no = 0; + port[1].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH1; + port[1].ioaddr.altstatus_addr = port[1].ioaddr.ctl_addr = + (iobase[5] + VND_TF2_CH1) | ATA_PCI_CTL_OFS; + port[1].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH1; + break; + case 2: + port[2].port_no = 0; + port[2].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH2; + port[2].ioaddr.altstatus_addr = port[2].ioaddr.ctl_addr = + (iobase[5] + VND_TF2_CH2) | ATA_PCI_CTL_OFS; + port[2].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH2; + break; + case 3: + port[3].port_no = 0; + port[3].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH3; + port[3].ioaddr.altstatus_addr = port[3].ioaddr.ctl_addr = + (iobase[5] + VND_TF2_CH3) | ATA_PCI_CTL_OFS; + port[3].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH3; + break; + default: + printf ("Tried to scan unknown port: ata%d\n", dev); + return 1; + } + + /* Initialize other registers */ + sata_port (&port[dev].ioaddr); + + /* Check for attached device */ + if (!sata_bus_probe (dev)) { + port[dev].port_state = 0; + debug ("SATA#%d port is not present\n", dev); + } else { + debug ("SATA#%d port is present\n", dev); + if (sata_bus_softreset (dev)) { + /* soft reset failed, try a hard one */ + sata_phy_reset (dev); + if (sata_bus_softreset (dev)) { + port[dev].port_state = 0; + } else { + port[dev].port_state = 1; + } + } else { + port[dev].port_state = 1; + } + } + if (port[dev].port_state == 1) { + /* Probe device and set xfer mode */ + sata_identify (dev, 0); + set_Feature_cmd (dev, 0); + } + + return 0; +} diff --git a/drivers/block/sata_sil3114.h b/drivers/block/sata_sil3114.h new file mode 100644 index 0000000..8f2301a --- /dev/null +++ b/drivers/block/sata_sil3114.h @@ -0,0 +1,147 @@ +/* + * Copyright (C) Excito Elektronik i Skåne AB, All rights reserved. + * Author: Tor Krill <tor@excito.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 SATA_SIL3114_H +#define SATA_SIL3114_H + +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; +}; + +/* Missing ata defines */ +#define ATA_CMD_STANDBY 0xE2 +#define ATA_CMD_STANDBYNOW1 0xE0 +#define ATA_CMD_IDLE 0xE3 +#define ATA_CMD_IDLEIMMEDIATE 0xE1 + +/* Defines for SIL3114 chip */ + +/* PCI defines */ +#define SIL_VEND_ID 0x1095 +#define SIL3114_DEVICE_ID 0x3114 + +/* some vendor specific registers */ +#define VND_SYSCONFSTAT 0x88 /* System Configuration Status and Command */ +#define VND_SYSCONFSTAT_CHN_0_INTBLOCK (1<<22) +#define VND_SYSCONFSTAT_CHN_1_INTBLOCK (1<<23) +#define VND_SYSCONFSTAT_CHN_2_INTBLOCK (1<<24) +#define VND_SYSCONFSTAT_CHN_3_INTBLOCK (1<<25) + +/* internal registers mapped by BAR5 */ +/* SATA Control*/ +#define VND_SCONTROL_CH0 0x100 +#define VND_SCONTROL_CH1 0x180 +#define VND_SCONTROL_CH2 0x300 +#define VND_SCONTROL_CH3 0x380 + +#define SATA_SC_IPM_T2P (1<<16) +#define SATA_SC_IPM_T2S (2<<16) +#define SATA_SC_SPD_1_5 (1<<4) +#define SATA_SC_SPD_3_0 (2<<4) +#define SATA_SC_DET_RST (1) /* ATA Reset sequence */ +#define SATA_SC_DET_PDIS (4) /* PHY Disable */ + +/* SATA Status */ +#define VND_SSTATUS_CH0 0x104 +#define VND_SSTATUS_CH1 0x184 +#define VND_SSTATUS_CH2 0x304 +#define VND_SSTATUS_CH3 0x384 + +#define SATA_SS_IPM_ACTIVE (1<<8) +#define SATA_SS_IPM_PARTIAL (2<<8) +#define SATA_SS_IPM_SLUMBER (6<<8) +#define SATA_SS_SPD_1_5 (1<<4) +#define SATA_SS_SPD_3_0 (2<<4) +#define SATA_DET_P_NOPHY (1) /* Device presence but no PHY connection established */ +#define SATA_DET_PRES (3) /* Device presence and active PHY */ +#define SATA_DET_OFFLINE (4) /* Device offline or in loopback mode */ + +/* Task file registers in BAR5 mapping */ +#define VND_TF0_CH0 0x80 +#define VND_TF0_CH1 0xc0 +#define VND_TF0_CH2 0x280 +#define VND_TF0_CH3 0x2c0 +#define VND_TF1_CH0 0x88 +#define VND_TF1_CH1 0xc8 +#define VND_TF1_CH2 0x288 +#define VND_TF1_CH3 0x2c8 +#define VND_TF2_CH0 0x88 +#define VND_TF2_CH1 0xc8 +#define VND_TF2_CH2 0x288 +#define VND_TF2_CH3 0x2c8 + +#define VND_BMDMA_CH0 0x00 +#define VND_BMDMA_CH1 0x08 +#define VND_BMDMA_CH2 0x200 +#define VND_BMDMA_CH3 0x208 +#define VND_BMDMA2_CH0 0x10 +#define VND_BMDMA2_CH1 0x18 +#define VND_BMDMA2_CH2 0x210 +#define VND_BMDMA2_CH3 0x218 + +/* FIFO control */ +#define VND_FIFOCFG_CH0 0x40 +#define VND_FIFOCFG_CH1 0x44 +#define VND_FIFOCFG_CH2 0x240 +#define VND_FIFOCFG_CH3 0x244 + +/* Task File configuration and status */ +#define VND_TF_CNST_CH0 0xa0 +#define VND_TF_CNST_CH1 0xe0 +#define VND_TF_CNST_CH2 0x2a0 +#define VND_TF_CNST_CH3 0x2e0 + +#define VND_TF_CNST_BFCMD (1<<1) +#define VND_TF_CNST_CHNRST (1<<2) +#define VND_TF_CNST_VDMA (1<<10) +#define VND_TF_CNST_INTST (1<<11) +#define VND_TF_CNST_WDTO (1<<12) +#define VND_TF_CNST_WDEN (1<<13) +#define VND_TF_CNST_WDIEN (1<<14) + +/* for testing */ +#define VND_SSDR 0x04c /* System Software Data Register */ +#define VND_FMACS 0x050 /* Flash Memory Address control and status */ + +#endif diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile new file mode 100644 index 0000000..3dc031b --- /dev/null +++ b/drivers/mmc/Makefile @@ -0,0 +1,46 @@ +# +# (C) Copyright 2006 +# Wolfgang Denk, DENX Software Engineering, wd@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 $(TOPDIR)/config.mk + +LIB := $(obj)libmmc.a + +COBJS-$(CONFIG_ATMEL_MCI) += atmel_mci.o + +COBJS := $(COBJS-y) +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) + +all: $(LIB) + +$(LIB): $(obj).depend $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/drivers/mmc/atmel_mci.c b/drivers/mmc/atmel_mci.c new file mode 100644 index 0000000..61aa184 --- /dev/null +++ b/drivers/mmc/atmel_mci.c @@ -0,0 +1,548 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * 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 <part.h> +#include <mmc.h> + +#include <asm/io.h> +#include <asm/errno.h> +#include <asm/byteorder.h> +#include <asm/arch/clk.h> +#include <asm/arch/memory-map.h> + +#include "atmel_mci.h" + +#ifdef DEBUG +#define pr_debug(fmt, args...) printf(fmt, ##args) +#else +#define pr_debug(...) do { } while(0) +#endif + +#ifndef CFG_MMC_CLK_OD +#define CFG_MMC_CLK_OD 150000 +#endif + +#ifndef CFG_MMC_CLK_PP +#define CFG_MMC_CLK_PP 5000000 +#endif + +#ifndef CFG_MMC_OP_COND +#define CFG_MMC_OP_COND 0x00100000 +#endif + +#define MMC_DEFAULT_BLKLEN 512 +#define MMC_DEFAULT_RCA 1 + +static unsigned int mmc_rca; +static int mmc_card_is_sd; +static block_dev_desc_t mmc_blkdev; + +block_dev_desc_t *mmc_get_dev(int dev) +{ + return &mmc_blkdev; +} + +static void mci_set_mode(unsigned long hz, unsigned long blklen) +{ + unsigned long bus_hz; + unsigned long clkdiv; + + bus_hz = get_mci_clk_rate(); + clkdiv = (bus_hz / hz) / 2 - 1; + + pr_debug("mmc: setting clock %lu Hz, block size %lu\n", + hz, blklen); + + if (clkdiv & ~255UL) { + clkdiv = 255; + printf("mmc: clock %lu too low; setting CLKDIV to 255\n", + hz); + } + + blklen &= 0xfffc; + mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv) + | MMCI_BF(BLKLEN, blklen) + | MMCI_BIT(RDPROOF) + | MMCI_BIT(WRPROOF))); +} + +#define RESP_NO_CRC 1 +#define R1 MMCI_BF(RSPTYP, 1) +#define R2 MMCI_BF(RSPTYP, 2) +#define R3 (R1 | RESP_NO_CRC) +#define R6 R1 +#define NID MMCI_BF(MAXLAT, 0) +#define NCR MMCI_BF(MAXLAT, 1) +#define TRCMD_START MMCI_BF(TRCMD, 1) +#define TRDIR_READ MMCI_BF(TRDIR, 1) +#define TRTYP_BLOCK MMCI_BF(TRTYP, 0) +#define INIT_CMD MMCI_BF(SPCMD, 1) +#define OPEN_DRAIN MMCI_BF(OPDCMD, 1) + +#define ERROR_FLAGS (MMCI_BIT(DTOE) \ + | MMCI_BIT(RDIRE) \ + | MMCI_BIT(RENDE) \ + | MMCI_BIT(RINDE) \ + | MMCI_BIT(RTOE)) + +static int +mmc_cmd(unsigned long cmd, unsigned long arg, + void *resp, unsigned long flags) +{ + unsigned long *response = resp; + int i, response_words = 0; + unsigned long error_flags; + u32 status; + + pr_debug("mmc: CMD%lu 0x%lx (flags 0x%lx)\n", + cmd, arg, flags); + + error_flags = ERROR_FLAGS; + if (!(flags & RESP_NO_CRC)) + error_flags |= MMCI_BIT(RCRCE); + + flags &= ~MMCI_BF(CMDNB, ~0UL); + + if (MMCI_BFEXT(RSPTYP, flags) == MMCI_RSPTYP_48_BIT_RESP) + response_words = 1; + else if (MMCI_BFEXT(RSPTYP, flags) == MMCI_RSPTYP_136_BIT_RESP) + response_words = 4; + + mmci_writel(ARGR, arg); + mmci_writel(CMDR, cmd | flags); + do { + udelay(40); + status = mmci_readl(SR); + } while (!(status & MMCI_BIT(CMDRDY))); + + pr_debug("mmc: status 0x%08lx\n", status); + + if (status & error_flags) { + printf("mmc: command %lu failed (status: 0x%08lx)\n", + cmd, status); + return -EIO; + } + + if (response_words) + pr_debug("mmc: response:"); + + for (i = 0; i < response_words; i++) { + response[i] = mmci_readl(RSPR); + pr_debug(" %08lx", response[i]); + } + pr_debug("\n"); + + return 0; +} + +static int mmc_acmd(unsigned long cmd, unsigned long arg, + void *resp, unsigned long flags) +{ + unsigned long aresp[4]; + int ret; + + /* + * Seems like the APP_CMD part of an ACMD has 64 cycles max + * latency even though the ACMD part doesn't. This isn't + * entirely clear in the SD Card spec, but some cards refuse + * to work if we attempt to use 5 cycles max latency here... + */ + ret = mmc_cmd(MMC_CMD_APP_CMD, 0, aresp, + R1 | NCR | (flags & OPEN_DRAIN)); + if (ret) + return ret; + if ((aresp[0] & (R1_ILLEGAL_COMMAND | R1_APP_CMD)) != R1_APP_CMD) + return -ENODEV; + + ret = mmc_cmd(cmd, arg, resp, flags); + return ret; +} + +static unsigned long +mmc_bread(int dev, unsigned long start, lbaint_t blkcnt, + void *buffer) +{ + int ret, i = 0; + unsigned long resp[4]; + unsigned long card_status, data; + unsigned long wordcount; + u32 *p = buffer; + u32 status; + + if (blkcnt == 0) + return 0; + + pr_debug("mmc_bread: dev %d, start %lx, blkcnt %lx\n", + dev, start, blkcnt); + + /* Put the device into Transfer state */ + ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 | NCR); + if (ret) goto out; + + /* Set block length */ + ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 | NCR); + if (ret) goto out; + + pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR)); + + for (i = 0; i < blkcnt; i++, start++) { + ret = mmc_cmd(MMC_CMD_READ_SINGLE_BLOCK, + start * mmc_blkdev.blksz, resp, + (R1 | NCR | TRCMD_START | TRDIR_READ + | TRTYP_BLOCK)); + if (ret) goto out; + + ret = -EIO; + wordcount = 0; + do { + do { + status = mmci_readl(SR); + if (status & (ERROR_FLAGS | MMCI_BIT(OVRE))) + goto read_error; + } while (!(status & MMCI_BIT(RXRDY))); + + if (status & MMCI_BIT(RXRDY)) { + data = mmci_readl(RDR); + /* pr_debug("%x\n", data); */ + *p++ = data; + wordcount++; + } + } while(wordcount < (mmc_blkdev.blksz / 4)); + + pr_debug("mmc: read %u words, waiting for BLKE\n", wordcount); + + do { + status = mmci_readl(SR); + } while (!(status & MMCI_BIT(BLKE))); + + putc('.'); + } + +out: + /* Put the device back into Standby state */ + mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR); + return i; + +read_error: + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + printf("mmc: bread failed, status = %08x, card status = %08x\n", + status, card_status); + goto out; +} + +static void mmc_parse_cid(struct mmc_cid *cid, unsigned long *resp) +{ + cid->mid = resp[0] >> 24; + cid->oid = (resp[0] >> 8) & 0xffff; + cid->pnm[0] = resp[0]; + cid->pnm[1] = resp[1] >> 24; + cid->pnm[2] = resp[1] >> 16; + cid->pnm[3] = resp[1] >> 8; + cid->pnm[4] = resp[1]; + cid->pnm[5] = resp[2] >> 24; + cid->pnm[6] = 0; + cid->prv = resp[2] >> 16; + cid->psn = (resp[2] << 16) | (resp[3] >> 16); + cid->mdt = resp[3] >> 8; +} + +static void sd_parse_cid(struct mmc_cid *cid, unsigned long *resp) +{ + cid->mid = resp[0] >> 24; + cid->oid = (resp[0] >> 8) & 0xffff; + cid->pnm[0] = resp[0]; + cid->pnm[1] = resp[1] >> 24; + cid->pnm[2] = resp[1] >> 16; + cid->pnm[3] = resp[1] >> 8; + cid->pnm[4] = resp[1]; + cid->pnm[5] = 0; + cid->pnm[6] = 0; + cid->prv = resp[2] >> 24; + cid->psn = (resp[2] << 8) | (resp[3] >> 24); + cid->mdt = (resp[3] >> 8) & 0x0fff; +} + +static void mmc_dump_cid(const struct mmc_cid *cid) +{ + printf("Manufacturer ID: %02lX\n", cid->mid); + printf("OEM/Application ID: %04lX\n", cid->oid); + printf("Product name: %s\n", cid->pnm); + printf("Product Revision: %lu.%lu\n", + cid->prv >> 4, cid->prv & 0x0f); + printf("Product Serial Number: %lu\n", cid->psn); + printf("Manufacturing Date: %02lu/%02lu\n", + cid->mdt >> 4, cid->mdt & 0x0f); +} + +static void mmc_dump_csd(const struct mmc_csd *csd) +{ + unsigned long *csd_raw = (unsigned long *)csd; + printf("CSD data: %08lx %08lx %08lx %08lx\n", + csd_raw[0], csd_raw[1], csd_raw[2], csd_raw[3]); + printf("CSD structure version: 1.%u\n", csd->csd_structure); + printf("MMC System Spec version: %u\n", csd->spec_vers); + printf("Card command classes: %03x\n", csd->ccc); + printf("Read block length: %u\n", 1 << csd->read_bl_len); + if (csd->read_bl_partial) + puts("Supports partial reads\n"); + else + puts("Does not support partial reads\n"); + printf("Write block length: %u\n", 1 << csd->write_bl_len); + if (csd->write_bl_partial) + puts("Supports partial writes\n"); + else + puts("Does not support partial writes\n"); + if (csd->wp_grp_enable) + printf("Supports group WP: %u\n", csd->wp_grp_size + 1); + else + puts("Does not support group WP\n"); + printf("Card capacity: %u bytes\n", + (csd->c_size + 1) * (1 << (csd->c_size_mult + 2)) * + (1 << csd->read_bl_len)); + printf("File format: %u/%u\n", + csd->file_format_grp, csd->file_format); + puts("Write protection: "); + if (csd->perm_write_protect) + puts(" permanent"); + if (csd->tmp_write_protect) + puts(" temporary"); + putc('\n'); +} + +static int mmc_idle_cards(void) +{ + int ret; + + /* Reset and initialize all cards */ + ret = mmc_cmd(MMC_CMD_GO_IDLE_STATE, 0, NULL, 0); + if (ret) + return ret; + + /* Keep the bus idle for 74 clock cycles */ + return mmc_cmd(0, 0, NULL, INIT_CMD); +} + +static int sd_init_card(struct mmc_cid *cid, int verbose) +{ + unsigned long resp[4]; + int i, ret = 0; + + mmc_idle_cards(); + for (i = 0; i < 1000; i++) { + ret = mmc_acmd(SD_CMD_APP_SEND_OP_COND, CFG_MMC_OP_COND, + resp, R3 | NID); + if (ret || (resp[0] & 0x80000000)) + break; + ret = -ETIMEDOUT; + } + + if (ret) + return ret; + + ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID); + if (ret) + return ret; + sd_parse_cid(cid, resp); + if (verbose) + mmc_dump_cid(cid); + + /* Get RCA of the card that responded */ + ret = mmc_cmd(SD_CMD_SEND_RELATIVE_ADDR, 0, resp, R6 | NCR); + if (ret) + return ret; + + mmc_rca = resp[0] >> 16; + if (verbose) + printf("SD Card detected (RCA %u)\n", mmc_rca); + mmc_card_is_sd = 1; + return 0; +} + +static int mmc_init_card(struct mmc_cid *cid, int verbose) +{ + unsigned long resp[4]; + int i, ret = 0; + + mmc_idle_cards(); + for (i = 0; i < 1000; i++) { + ret = mmc_cmd(MMC_CMD_SEND_OP_COND, CFG_MMC_OP_COND, resp, + R3 | NID | OPEN_DRAIN); + if (ret || (resp[0] & 0x80000000)) + break; + ret = -ETIMEDOUT; + } + + if (ret) + return ret; + + /* Get CID of all cards. FIXME: Support more than one card */ + ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID | OPEN_DRAIN); + if (ret) + return ret; + mmc_parse_cid(cid, resp); + if (verbose) + mmc_dump_cid(cid); + + /* Set Relative Address of the card that responded */ + ret = mmc_cmd(MMC_CMD_SET_RELATIVE_ADDR, mmc_rca << 16, resp, + R1 | NCR | OPEN_DRAIN); + return ret; +} + +static void mci_set_data_timeout(struct mmc_csd *csd) +{ + static const unsigned int dtomul_to_shift[] = { + 0, 4, 7, 8, 10, 12, 16, 20, + }; + static const unsigned int taac_exp[] = { + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, + }; + static const unsigned int taac_mant[] = { + 0, 10, 12, 13, 15, 60, 25, 30, + 35, 40, 45, 50, 55, 60, 70, 80, + }; + unsigned int timeout_ns, timeout_clks; + unsigned int e, m; + unsigned int dtocyc, dtomul; + unsigned int shift; + u32 dtor; + + e = csd->taac & 0x07; + m = (csd->taac >> 3) & 0x0f; + + timeout_ns = (taac_exp[e] * taac_mant[m] + 9) / 10; + timeout_clks = csd->nsac * 100; + + timeout_clks += (((timeout_ns + 9) / 10) + * ((CFG_MMC_CLK_PP + 99999) / 100000) + 9999) / 10000; + if (!mmc_card_is_sd) + timeout_clks *= 10; + else + timeout_clks *= 100; + + dtocyc = timeout_clks; + dtomul = 0; + shift = 0; + while (dtocyc > 15 && dtomul < 8) { + dtomul++; + shift = dtomul_to_shift[dtomul]; + dtocyc = (timeout_clks + (1 << shift) - 1) >> shift; + } + + if (dtomul >= 8) { + dtomul = 7; + dtocyc = 15; + puts("Warning: Using maximum data timeout\n"); + } + + dtor = (MMCI_BF(DTOMUL, dtomul) + | MMCI_BF(DTOCYC, dtocyc)); + mmci_writel(DTOR, dtor); + + printf("mmc: Using %u cycles data timeout (DTOR=0x%x)\n", + dtocyc << shift, dtor); +} + +int mmc_init(int verbose) +{ + struct mmc_cid cid; + struct mmc_csd csd; + unsigned int max_blksz; + int ret; + + /* Initialize controller */ + mmci_writel(CR, MMCI_BIT(SWRST)); + mmci_writel(CR, MMCI_BIT(MCIEN)); + mmci_writel(DTOR, 0x5f); + mmci_writel(IDR, ~0UL); + mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN); + + mmc_card_is_sd = 0; + + ret = sd_init_card(&cid, verbose); + if (ret) { + mmc_rca = MMC_DEFAULT_RCA; + ret = mmc_init_card(&cid, verbose); + } + if (ret) + return ret; + + /* Get CSD from the card */ + ret = mmc_cmd(MMC_CMD_SEND_CSD, mmc_rca << 16, &csd, R2 | NCR); + if (ret) + return ret; + if (verbose) + mmc_dump_csd(&csd); + + mci_set_data_timeout(&csd); + + /* Initialize the blockdev structure */ + mmc_blkdev.if_type = IF_TYPE_MMC; + mmc_blkdev.part_type = PART_TYPE_DOS; + mmc_blkdev.block_read = mmc_bread; + sprintf((char *)mmc_blkdev.vendor, + "Man %02x%04x Snr %08x", + cid.mid, cid.oid, cid.psn); + strncpy((char *)mmc_blkdev.product, cid.pnm, + sizeof(mmc_blkdev.product)); + sprintf((char *)mmc_blkdev.revision, "%x %x", + cid.prv >> 4, cid.prv & 0x0f); + + /* + * If we can't use 512 byte blocks, refuse to deal with the + * card. Tons of code elsewhere seems to depend on this. + */ + max_blksz = 1 << csd.read_bl_len; + if (max_blksz < 512 || (max_blksz > 512 && !csd.read_bl_partial)) { + printf("Card does not support 512 byte reads, aborting.\n"); + return -ENODEV; + } + mmc_blkdev.blksz = 512; + mmc_blkdev.lba = (csd.c_size + 1) * (1 << (csd.c_size_mult + 2)); + + mci_set_mode(CFG_MMC_CLK_PP, mmc_blkdev.blksz); + +#if 0 + if (fat_register_device(&mmc_blkdev, 1)) + printf("Could not register MMC fat device\n"); +#else + init_part(&mmc_blkdev); +#endif + + return 0; +} + +int mmc_read(ulong src, uchar *dst, int size) +{ + return -ENOSYS; +} + +int mmc_write(uchar *src, ulong dst, int size) +{ + return -ENOSYS; +} + +int mmc2info(ulong addr) +{ + return 0; +} diff --git a/drivers/mmc/atmel_mci.h b/drivers/mmc/atmel_mci.h new file mode 100644 index 0000000..5b4f5c9 --- /dev/null +++ b/drivers/mmc/atmel_mci.h @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * 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 + */ +#ifndef __CPU_AT32AP_ATMEL_MCI_H__ +#define __CPU_AT32AP_ATMEL_MCI_H__ + +/* Atmel MultiMedia Card Interface (MCI) registers */ +#define MMCI_CR 0x0000 +#define MMCI_MR 0x0004 +#define MMCI_DTOR 0x0008 +#define MMCI_SDCR 0x000c +#define MMCI_ARGR 0x0010 +#define MMCI_CMDR 0x0014 +#define MMCI_RSPR 0x0020 +#define MMCI_RSPR1 0x0024 +#define MMCI_RSPR2 0x0028 +#define MMCI_RSPR3 0x002c +#define MMCI_RDR 0x0030 +#define MMCI_TDR 0x0034 +#define MMCI_SR 0x0040 +#define MMCI_IER 0x0044 +#define MMCI_IDR 0x0048 +#define MMCI_IMR 0x004c + +/* Bitfields in CR */ +#define MMCI_MCIEN_OFFSET 0 +#define MMCI_MCIEN_SIZE 1 +#define MMCI_MCIDIS_OFFSET 1 +#define MMCI_MCIDIS_SIZE 1 +#define MMCI_PWSEN_OFFSET 2 +#define MMCI_PWSEN_SIZE 1 +#define MMCI_PWSDIS_OFFSET 3 +#define MMCI_PWSDIS_SIZE 1 +#define MMCI_SWRST_OFFSET 7 +#define MMCI_SWRST_SIZE 1 + +/* Bitfields in MR */ +#define MMCI_CLKDIV_OFFSET 0 +#define MMCI_CLKDIV_SIZE 8 +#define MMCI_PWSDIV_OFFSET 8 +#define MMCI_PWSDIV_SIZE 3 +#define MMCI_RDPROOF_OFFSET 11 +#define MMCI_RDPROOF_SIZE 1 +#define MMCI_WRPROOF_OFFSET 12 +#define MMCI_WRPROOF_SIZE 1 +#define MMCI_PDCPADV_OFFSET 14 +#define MMCI_PDCPADV_SIZE 1 +#define MMCI_PDCMODE_OFFSET 15 +#define MMCI_PDCMODE_SIZE 1 +#define MMCI_BLKLEN_OFFSET 16 +#define MMCI_BLKLEN_SIZE 16 + +/* Bitfields in DTOR */ +#define MMCI_DTOCYC_OFFSET 0 +#define MMCI_DTOCYC_SIZE 4 +#define MMCI_DTOMUL_OFFSET 4 +#define MMCI_DTOMUL_SIZE 3 + +/* Bitfields in SDCR */ +#define MMCI_SCDSEL_OFFSET 0 +#define MMCI_SCDSEL_SIZE 4 +#define MMCI_SCDBUS_OFFSET 7 +#define MMCI_SCDBUS_SIZE 1 + +/* Bitfields in ARGR */ +#define MMCI_ARG_OFFSET 0 +#define MMCI_ARG_SIZE 32 + +/* Bitfields in CMDR */ +#define MMCI_CMDNB_OFFSET 0 +#define MMCI_CMDNB_SIZE 6 +#define MMCI_RSPTYP_OFFSET 6 +#define MMCI_RSPTYP_SIZE 2 +#define MMCI_SPCMD_OFFSET 8 +#define MMCI_SPCMD_SIZE 3 +#define MMCI_OPDCMD_OFFSET 11 +#define MMCI_OPDCMD_SIZE 1 +#define MMCI_MAXLAT_OFFSET 12 +#define MMCI_MAXLAT_SIZE 1 +#define MMCI_TRCMD_OFFSET 16 +#define MMCI_TRCMD_SIZE 2 +#define MMCI_TRDIR_OFFSET 18 +#define MMCI_TRDIR_SIZE 1 +#define MMCI_TRTYP_OFFSET 19 +#define MMCI_TRTYP_SIZE 2 + +/* Bitfields in RSPRx */ +#define MMCI_RSP_OFFSET 0 +#define MMCI_RSP_SIZE 32 + +/* Bitfields in SR/IER/IDR/IMR */ +#define MMCI_CMDRDY_OFFSET 0 +#define MMCI_CMDRDY_SIZE 1 +#define MMCI_RXRDY_OFFSET 1 +#define MMCI_RXRDY_SIZE 1 +#define MMCI_TXRDY_OFFSET 2 +#define MMCI_TXRDY_SIZE 1 +#define MMCI_BLKE_OFFSET 3 +#define MMCI_BLKE_SIZE 1 +#define MMCI_DTIP_OFFSET 4 +#define MMCI_DTIP_SIZE 1 +#define MMCI_NOTBUSY_OFFSET 5 +#define MMCI_NOTBUSY_SIZE 1 +#define MMCI_ENDRX_OFFSET 6 +#define MMCI_ENDRX_SIZE 1 +#define MMCI_ENDTX_OFFSET 7 +#define MMCI_ENDTX_SIZE 1 +#define MMCI_RXBUFF_OFFSET 14 +#define MMCI_RXBUFF_SIZE 1 +#define MMCI_TXBUFE_OFFSET 15 +#define MMCI_TXBUFE_SIZE 1 +#define MMCI_RINDE_OFFSET 16 +#define MMCI_RINDE_SIZE 1 +#define MMCI_RDIRE_OFFSET 17 +#define MMCI_RDIRE_SIZE 1 +#define MMCI_RCRCE_OFFSET 18 +#define MMCI_RCRCE_SIZE 1 +#define MMCI_RENDE_OFFSET 19 +#define MMCI_RENDE_SIZE 1 +#define MMCI_RTOE_OFFSET 20 +#define MMCI_RTOE_SIZE 1 +#define MMCI_DCRCE_OFFSET 21 +#define MMCI_DCRCE_SIZE 1 +#define MMCI_DTOE_OFFSET 22 +#define MMCI_DTOE_SIZE 1 +#define MMCI_OVRE_OFFSET 30 +#define MMCI_OVRE_SIZE 1 +#define MMCI_UNRE_OFFSET 31 +#define MMCI_UNRE_SIZE 1 + +/* Constants for DTOMUL */ +#define MMCI_DTOMUL_1_CYCLE 0 +#define MMCI_DTOMUL_16_CYCLES 1 +#define MMCI_DTOMUL_128_CYCLES 2 +#define MMCI_DTOMUL_256_CYCLES 3 +#define MMCI_DTOMUL_1024_CYCLES 4 +#define MMCI_DTOMUL_4096_CYCLES 5 +#define MMCI_DTOMUL_65536_CYCLES 6 +#define MMCI_DTOMUL_1048576_CYCLES 7 + +/* Constants for RSPTYP */ +#define MMCI_RSPTYP_NO_RESP 0 +#define MMCI_RSPTYP_48_BIT_RESP 1 +#define MMCI_RSPTYP_136_BIT_RESP 2 + +/* Constants for SPCMD */ +#define MMCI_SPCMD_NO_SPEC_CMD 0 +#define MMCI_SPCMD_INIT_CMD 1 +#define MMCI_SPCMD_SYNC_CMD 2 +#define MMCI_SPCMD_INT_CMD 4 +#define MMCI_SPCMD_INT_RESP 5 + +/* Constants for TRCMD */ +#define MMCI_TRCMD_NO_TRANS 0 +#define MMCI_TRCMD_START_TRANS 1 +#define MMCI_TRCMD_STOP_TRANS 2 + +/* Constants for TRTYP */ +#define MMCI_TRTYP_BLOCK 0 +#define MMCI_TRTYP_MULTI_BLOCK 1 +#define MMCI_TRTYP_STREAM 2 + +/* Bit manipulation macros */ +#define MMCI_BIT(name) \ + (1 << MMCI_##name##_OFFSET) +#define MMCI_BF(name,value) \ + (((value) & ((1 << MMCI_##name##_SIZE) - 1)) \ + << MMCI_##name##_OFFSET) +#define MMCI_BFEXT(name,value) \ + (((value) >> MMCI_##name##_OFFSET)\ + & ((1 << MMCI_##name##_SIZE) - 1)) +#define MMCI_BFINS(name,value,old) \ + (((old) & ~(((1 << MMCI_##name##_SIZE) - 1) \ + << MMCI_##name##_OFFSET)) \ + | MMCI_BF(name,value)) + +/* Register access macros */ +#define mmci_readl(reg) \ + readl((void *)MMCI_BASE + MMCI_##reg) +#define mmci_writel(reg,value) \ + writel((value), (void *)MMCI_BASE + MMCI_##reg) + +#endif /* __CPU_AT32AP_ATMEL_MCI_H__ */ diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c index d505bc8..c0ea97b 100644 --- a/drivers/mtd/cfi_flash.c +++ b/drivers/mtd/cfi_flash.c @@ -581,20 +581,16 @@ static int flash_toggle (flash_info_t * info, flash_sect_t sect, flash_make_cmd (info, cmd, &cword); switch (info->portwidth) { case FLASH_CFI_8BIT: - retval = ((flash_read8(addr) & cword.c) != - (flash_read8(addr) & cword.c)); + retval = flash_read8(addr) != flash_read8(addr); break; case FLASH_CFI_16BIT: - retval = ((flash_read16(addr) & cword.w) != - (flash_read16(addr) & cword.w)); + retval = flash_read16(addr) != flash_read16(addr); break; case FLASH_CFI_32BIT: - retval = ((flash_read32(addr) & cword.l) != - (flash_read32(addr) & cword.l)); + retval = flash_read32(addr) != flash_read32(addr); break; case FLASH_CFI_64BIT: - retval = ((flash_read64(addr) & cword.ll) != - (flash_read64(addr) & cword.ll)); + retval = flash_read64(addr) != flash_read64(addr); break; default: retval = 0; diff --git a/drivers/mtd/jedec_flash.c b/drivers/mtd/jedec_flash.c index b958d17..9845e93 100644 --- a/drivers/mtd/jedec_flash.c +++ b/drivers/mtd/jedec_flash.c @@ -42,7 +42,7 @@ #define MANUFACTURER_SST 0x00BF /* AMD */ -#define AM29DL800BB 0x22C8 +#define AM29DL800BB 0x22CB #define AM29DL800BT 0x224A #define AM29F800BB 0x2258 diff --git a/drivers/mtd/nand/nand.c b/drivers/mtd/nand/nand.c index 27b5792..e44470e 100644 --- a/drivers/mtd/nand/nand.c +++ b/drivers/mtd/nand/nand.c @@ -70,7 +70,7 @@ void nand_init(void) if (nand_curr_device == -1) nand_curr_device = i; } - printf("%lu MiB\n", size / (1024 * 1024)); + printf("%u MiB\n", size / (1024 * 1024)); #ifdef CFG_NAND_SELECT_DEVICE /* diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 740d3fc..6416d15 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -962,7 +962,9 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa status = this->waitfunc (mtd, this, FL_WRITING); /* See if device thinks it succeeded */ if (status & 0x01) { - DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page); + MTDDEBUG (MTD_DEBUG_LEVEL0, + "%s: Failed write, page 0x%08x, ", + __FUNCTION__, page); return -EIO; } } else { @@ -1010,7 +1012,9 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int for (j = 0; j < eccsteps; j++) { /* Loop through and verify the data */ if (this->verify_buf(mtd, &this->data_poi[datidx], mtd->eccsize)) { - DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); + MTDDEBUG (MTD_DEBUG_LEVEL0, "%s: " + "Failed write verify, page 0x%08x ", + __FUNCTION__, page); goto out; } datidx += mtd->eccsize; @@ -1018,7 +1022,9 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int if (!hweccbytes) continue; if (this->verify_buf(mtd, &this->oob_buf[oobofs], hweccbytes)) { - DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); + MTDDEBUG (MTD_DEBUG_LEVEL0, "%s: " + "Failed write verify, page 0x%08x ", + __FUNCTION__, page); goto out; } oobofs += hweccbytes; @@ -1029,7 +1035,9 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int */ if (oobmode) { if (this->verify_buf(mtd, &oob_buf[oobofs], mtd->oobsize - hweccbytes * eccsteps)) { - DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); + MTDDEBUG (MTD_DEBUG_LEVEL0, "%s: " + "Failed write verify, page 0x%08x ", + __FUNCTION__, page); goto out; } } else { @@ -1042,9 +1050,11 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int for (i = 0; i < ecccnt; i++) { int idx = oobsel->eccpos[i]; if (oobdata[idx] != oob_buf[oobofs + idx] ) { - DEBUG (MTD_DEBUG_LEVEL0, + MTDDEBUG (MTD_DEBUG_LEVEL0, "%s: Failed ECC write " - "verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i); + "verify, page 0x%08x, " + "%6i bytes were succesful\n", + __FUNCTION__, page, i); goto out; } } @@ -1131,11 +1141,13 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, int oobreadlen; - DEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); + MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", + (unsigned int) from, (int) len); /* Do not allow reads past end of device */ if ((from + len) > mtd->size) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n"); + MTDDEBUG (MTD_DEBUG_LEVEL0, + "nand_read_ecc: Attempt read beyond end of device\n"); *retlen = 0; return -EINVAL; } @@ -1252,7 +1264,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, * generator for an error, reads back the syndrome and * does the error correction on the fly */ if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " + MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); ecc_failed++; } @@ -1291,7 +1303,9 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, } if (ecc_status == -1) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); + MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " + "Failed ECC read, page 0x%08x\n", + page); ecc_failed++; } } @@ -1388,7 +1402,8 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t struct nand_chip *this = mtd->priv; int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1; - DEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); + MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", + (unsigned int) from, (int) len); /* Shift to get page */ page = (int)(from >> this->page_shift); @@ -1402,7 +1417,8 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t /* Do not allow reads past end of device */ if ((from + len) > mtd->size) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n"); + MTDDEBUG (MTD_DEBUG_LEVEL0, + "nand_read_oob: Attempt read beyond end of device\n"); *retlen = 0; return -EINVAL; } @@ -1488,7 +1504,8 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, /* Do not allow reads past end of device */ if ((from + len) > mtd->size) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt read beyond end of device\n"); + MTDDEBUG (MTD_DEBUG_LEVEL0, + "nand_read_raw: Attempt read beyond end of device\n"); return -EINVAL; } @@ -1626,14 +1643,16 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, u_char *oobbuf, *bufstart; int ppblock = (1 << (this->phys_erase_shift - this->page_shift)); - DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); + MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", + (unsigned int) to, (int) len); /* Initialize retlen, in case of early exit */ *retlen = 0; /* Do not allow write past end of device */ if ((to + len) > mtd->size) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n"); + MTDDEBUG (MTD_DEBUG_LEVEL0, + "nand_write_ecc: Attempt to write past end of page\n"); return -EINVAL; } @@ -1695,7 +1714,8 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, */ ret = nand_write_page (mtd, this, page, &oobbuf[oob], oobsel, (--numpages > 0)); if (ret) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret); + MTDDEBUG (MTD_DEBUG_LEVEL0, + "nand_write_ecc: write_page failed %d\n", ret); goto out; } /* Next oob page */ @@ -1719,7 +1739,8 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, page - startpage, oobbuf, oobsel, chipnr, (eccbuf != NULL)); if (ret) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); + MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: " + "verify_pages failed %d\n", ret); goto out; } *retlen = written; @@ -1752,7 +1773,8 @@ cmp: if (!ret) *retlen = written; else - DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); + MTDDEBUG (MTD_DEBUG_LEVEL0, + "nand_write_ecc: verify_pages failed %d\n", ret); out: /* Deselect and wake up anyone waiting on the device */ @@ -1777,7 +1799,8 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * int column, page, status, ret = -EIO, chipnr; struct nand_chip *this = mtd->priv; - DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); + MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", + (unsigned int) to, (int) len); /* Shift to get page */ page = (int) (to >> this->page_shift); @@ -1791,7 +1814,8 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * /* Do not allow write past end of page */ if ((column + len) > mtd->oobsize) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n"); + MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " + "Attempt to write past end of page\n"); return -EINVAL; } @@ -1821,8 +1845,9 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page & this->pagemask); if (!ffchars) { if (!(ffchars = kmalloc (mtd->oobsize, GFP_KERNEL))) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " - "No memory for padding array, need %d bytes", mtd->oobsize); + MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " + "No memory for padding array, " + "need %d bytes", mtd->oobsize); ret = -ENOMEM; goto out; } @@ -1847,7 +1872,8 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * /* See if device thinks it succeeded */ if (status & 0x01) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page); + MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " + "Failed write, page 0x%08x\n", page); ret = -EIO; goto out; } @@ -1859,7 +1885,8 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * this->cmdfunc (mtd, NAND_CMD_READOOB, column, page & this->pagemask); if (this->verify_buf(mtd, buf, len)) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page); + MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " + "Failed write verify, page 0x%08x\n", page); ret = -EIO; goto out; } @@ -1919,12 +1946,14 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig for (i = 0; i < count; i++) total_len += (int) vecs[i].iov_len; - DEBUG (MTD_DEBUG_LEVEL3, - "nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count); + MTDDEBUG (MTD_DEBUG_LEVEL3, + "nand_writev: to = 0x%08x, len = %i, count = %ld\n", + (unsigned int) to, (unsigned int) total_len, count); /* Do not allow write past end of page */ if ((to + total_len) > mtd->size) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n"); + MTDDEBUG (MTD_DEBUG_LEVEL0, + "nand_writev: Attempted write past end of device\n"); return -EINVAL; } @@ -2117,24 +2146,26 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb int page, len, status, pages_per_block, ret, chipnr; struct nand_chip *this = mtd->priv; - DEBUG (MTD_DEBUG_LEVEL3, - "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len); + MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n", + (unsigned int) instr->addr, (unsigned int) instr->len); /* Start address must align on block boundary */ if (instr->addr & ((1 << this->phys_erase_shift) - 1)) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n"); + MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n"); return -EINVAL; } /* Length must align on block boundary */ if (instr->len & ((1 << this->phys_erase_shift) - 1)) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n"); + MTDDEBUG (MTD_DEBUG_LEVEL0, + "nand_erase: Length not block aligned\n"); return -EINVAL; } /* Do not allow erase past end of device */ if ((instr->len + instr->addr) > mtd->size) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n"); + MTDDEBUG (MTD_DEBUG_LEVEL0, + "nand_erase: Erase past end of device\n"); return -EINVAL; } @@ -2156,7 +2187,8 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb /* Check the WP bit */ /* Check, if it is write protected */ if (nand_check_wp(mtd)) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n"); + MTDDEBUG (MTD_DEBUG_LEVEL0, + "nand_erase: Device is write protected!!!\n"); instr->state = MTD_ERASE_FAILED; goto erase_exit; } @@ -2186,7 +2218,8 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb /* See if block erase succeeded */ if (status & 0x01) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page); + MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " + "Failed erase, page 0x%08x\n", page); instr->state = MTD_ERASE_FAILED; instr->fail_addr = (page << this->page_shift); goto erase_exit; @@ -2229,7 +2262,7 @@ static void nand_sync (struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; - DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n"); + MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n"); /* Grab the lock and see if the device is available */ nand_get_device (this, mtd, FL_SYNCING); diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index eff76d7..a97743b 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -1038,8 +1038,8 @@ int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt) block = (int) (offs >> (this->bbt_erase_shift - 1)); res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; - DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", - (unsigned int)offs, res, block >> 1); + MTDDEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: " + "(block %d) 0x%02x\n", (unsigned int)offs, res, block >> 1); switch ((int)res) { case 0x00: return 0; diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index c82f77b..828cc33 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -154,7 +154,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts) } if (erase_length < meminfo->erasesize) { - printf("Warning: Erase size 0x%08x smaller than one " \ + printf("Warning: Erase size 0x%08lx smaller than one " \ "erase block 0x%08x\n",erase_length, meminfo->erasesize); printf(" Erasing 0x%08x instead\n", meminfo->erasesize); erase_length = meminfo->erasesize; @@ -498,7 +498,7 @@ int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts) * on (slow) serial consoles */ if (percent != percent_complete) { - printf("\rWriting data at 0x%x " + printf("\rWriting data at 0x%lx " "-- %3d%% complete.", mtdoffset, percent); percent_complete = percent; @@ -678,7 +678,7 @@ int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts) */ if (percent != percent_complete) { if (!opts->quiet) - printf("\rReading data from 0x%x " + printf("\rReading data from 0x%lx " "-- %3d%% complete.", mtdoffset, percent); percent_complete = percent; diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index d1b9f8f..d32e382 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -293,22 +293,22 @@ static int onenand_wait(struct mtd_info *mtd, int state) ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); if (ctrl & ONENAND_CTRL_ERROR) { - DEBUG(MTD_DEBUG_LEVEL0, - "onenand_wait: controller error = 0x%04x\n", ctrl); + MTDDEBUG (MTD_DEBUG_LEVEL0, + "onenand_wait: controller error = 0x%04x\n", ctrl); return -EAGAIN; } if (ctrl & ONENAND_CTRL_LOCK) { - DEBUG(MTD_DEBUG_LEVEL0, - "onenand_wait: it's locked error = 0x%04x\n", ctrl); + MTDDEBUG (MTD_DEBUG_LEVEL0, + "onenand_wait: it's locked error = 0x%04x\n", ctrl); return -EIO; } if (interrupt & ONENAND_INT_READ) { ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); if (ecc & ONENAND_ECC_2BIT_ALL) { - DEBUG(MTD_DEBUG_LEVEL0, - "onenand_wait: ECC error = 0x%04x\n", ecc); + MTDDEBUG (MTD_DEBUG_LEVEL0, + "onenand_wait: ECC error = 0x%04x\n", ecc); return -EBADMSG; } } @@ -524,13 +524,14 @@ static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, int thislen; int ret = 0; - DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ecc: from = 0x%08x, len = %i\n", - (unsigned int)from, (int)len); + MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_read_ecc: " + "from = 0x%08x, len = %i\n", + (unsigned int)from, (int)len); /* Do not allow reads past end of device */ if ((from + len) > mtd->size) { - DEBUG(MTD_DEBUG_LEVEL0, - "onenand_read_ecc: Attempt read beyond end of device\n"); + MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_read_ecc: " + "Attempt read beyond end of device\n"); *retlen = 0; return -EINVAL; } @@ -561,8 +562,8 @@ static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, break; if (ret) { - DEBUG(MTD_DEBUG_LEVEL0, - "onenand_read_ecc: read failed = %d\n", ret); + MTDDEBUG (MTD_DEBUG_LEVEL0, + "onenand_read_ecc: read failed = %d\n", ret); break; } @@ -615,16 +616,17 @@ int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, int read = 0, thislen, column; int ret = 0; - DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob: from = 0x%08x, len = %i\n", - (unsigned int)from, (int)len); + MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_read_oob: " + "from = 0x%08x, len = %i\n", + (unsigned int)from, (int)len); /* Initialize return length value */ *retlen = 0; /* Do not allow reads past end of device */ if (unlikely((from + len) > mtd->size)) { - DEBUG(MTD_DEBUG_LEVEL0, - "onenand_read_oob: Attempt read beyond end of device\n"); + MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_read_oob: " + "Attempt read beyond end of device\n"); return -EINVAL; } @@ -652,8 +654,8 @@ int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, break; if (ret) { - DEBUG(MTD_DEBUG_LEVEL0, - "onenand_read_oob: read failed = %d\n", ret); + MTDDEBUG (MTD_DEBUG_LEVEL0, + "onenand_read_oob: read failed = %d\n", ret); break; } @@ -733,23 +735,24 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, int written = 0; int ret = 0; - DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ecc: to = 0x%08x, len = %i\n", - (unsigned int)to, (int)len); + MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_write_ecc: " + "to = 0x%08x, len = %i\n", + (unsigned int)to, (int)len); /* Initialize retlen, in case of early exit */ *retlen = 0; /* Do not allow writes past end of device */ if (unlikely((to + len) > mtd->size)) { - DEBUG(MTD_DEBUG_LEVEL0, - "onenand_write_ecc: Attempt write to past end of device\n"); + MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_write_ecc: " + "Attempt write to past end of device\n"); return -EINVAL; } /* Reject writes, which are not page aligned */ if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { - DEBUG(MTD_DEBUG_LEVEL0, - "onenand_write_ecc: Attempt to write not page aligned data\n"); + MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_write_ecc: " + "Attempt to write not page aligned data\n"); return -EINVAL; } @@ -772,8 +775,8 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, ret = this->wait(mtd, FL_WRITING); if (ret) { - DEBUG(MTD_DEBUG_LEVEL0, - "onenand_write_ecc: write filaed %d\n", ret); + MTDDEBUG (MTD_DEBUG_LEVEL0, + "onenand_write_ecc: write filaed %d\n", ret); break; } @@ -782,8 +785,8 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, /* Only check verify write turn on */ ret = onenand_verify_page(mtd, (u_char *) buf, to, block, page); if (ret) { - DEBUG(MTD_DEBUG_LEVEL0, - "onenand_write_ecc: verify failed %d\n", ret); + MTDDEBUG (MTD_DEBUG_LEVEL0, + "onenand_write_ecc: verify failed %d\n", ret); break; } @@ -836,16 +839,17 @@ int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, int column, status; int written = 0; - DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", - (unsigned int)to, (int)len); + MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_write_oob: " + "to = 0x%08x, len = %i\n", + (unsigned int)to, (int)len); /* Initialize retlen, in case of early exit */ *retlen = 0; /* Do not allow writes past end of device */ if (unlikely((to + len) > mtd->size)) { - DEBUG(MTD_DEBUG_LEVEL0, - "onenand_write_oob: Attempt write to past end of device\n"); + MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_write_oob: " + "Attempt write to past end of device\n"); return -EINVAL; } @@ -904,28 +908,29 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) int len; int ret = 0; - DEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n", - (unsigned int)instr->addr, (unsigned int)instr->len); + MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n", + (unsigned int)instr->addr, (unsigned int)instr->len); block_size = (1 << this->erase_shift); /* Start address must align on block boundary */ if (unlikely(instr->addr & (block_size - 1))) { - DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Unaligned address\n"); + MTDDEBUG (MTD_DEBUG_LEVEL0, + "onenand_erase: Unaligned address\n"); return -EINVAL; } /* Length must align on block boundary */ if (unlikely(instr->len & (block_size - 1))) { - DEBUG(MTD_DEBUG_LEVEL0, - "onenand_erase: Length not block aligned\n"); + MTDDEBUG (MTD_DEBUG_LEVEL0, + "onenand_erase: Length not block aligned\n"); return -EINVAL; } /* Do not allow erase past end of device */ if (unlikely((instr->len + instr->addr) > mtd->size)) { - DEBUG(MTD_DEBUG_LEVEL0, - "onenand_erase: Erase past end of device\n"); + MTDDEBUG (MTD_DEBUG_LEVEL0, + "onenand_erase: Erase past end of device\n"); return -EINVAL; } @@ -950,12 +955,12 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) /* Check, if it is write protected */ if (ret) { if (ret == -EPERM) - DEBUG(MTD_DEBUG_LEVEL0, - "onenand_erase: Device is write protected!!!\n"); + MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: " + "Device is write protected!!!\n"); else - DEBUG(MTD_DEBUG_LEVEL0, - "onenand_erase: Failed erase, block %d\n", - (unsigned)(addr >> this->erase_shift)); + MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: " + "Failed erase, block %d\n", + (unsigned)(addr >> this->erase_shift)); instr->state = MTD_ERASE_FAILED; instr->fail_addr = addr; goto erase_exit; @@ -988,7 +993,7 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) */ void onenand_sync(struct mtd_info *mtd) { - DEBUG(MTD_DEBUG_LEVEL3, "onenand_sync: called\n"); + MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_sync: called\n"); /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_SYNCING); diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index 5a610ee..87344ab 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c @@ -156,9 +156,9 @@ static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) block = (int)(offs >> (bbm->bbt_erase_shift - 1)); res = (bbm->bbt[block >> 3] >> (block & 0x06)) & 0x03; - DEBUG(MTD_DEBUG_LEVEL2, - "onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n", - (unsigned int)offs, block >> 1, res); + MTDDEBUG (MTD_DEBUG_LEVEL2, + "onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n", + (unsigned int)offs, block >> 1, res); switch ((int)res) { case 0x00: diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 84be288..bcf31cb 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -66,6 +66,7 @@ COBJS-$(CONFIG_ULI526X) += uli526x.o COBJS-$(CONFIG_VSC7385_ENET) += vsc7385.o COBJS-$(CONFIG_XILINX_EMAC) += xilinx_emac.o COBJS-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o +COBJS-$(CONFIG_SH_ETHER) += sh_eth.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c index c31029a..060b518 100644 --- a/drivers/net/e1000.c +++ b/drivers/net/e1000.c @@ -75,6 +75,7 @@ static struct pci_device_id supported[] = { {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82544GC_LOM}, {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82540EM}, {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82545EM_COPPER}, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82545GM_COPPER}, {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82546EB_COPPER}, {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82545EM_FIBER}, {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82546EB_FIBER}, @@ -636,6 +637,7 @@ e1000_set_mac_type(struct e1000_hw *hw) hw->mac_type = e1000_82540; break; case E1000_DEV_ID_82545EM_COPPER: + case E1000_DEV_ID_82545GM_COPPER: case E1000_DEV_ID_82545EM_FIBER: hw->mac_type = e1000_82545; break; diff --git a/drivers/net/e1000.h b/drivers/net/e1000.h index 23b2eb9..c258bc2 100644 --- a/drivers/net/e1000.h +++ b/drivers/net/e1000.h @@ -217,13 +217,14 @@ struct e1000_phy_stats { #define E1000_DEV_ID_82544GC_LOM 0x100D #define E1000_DEV_ID_82540EM 0x100E #define E1000_DEV_ID_82540EM_LOM 0x1015 +#define E1000_DEV_ID_82545GM_COPPER 0x1026 #define E1000_DEV_ID_82545EM_COPPER 0x100F #define E1000_DEV_ID_82545EM_FIBER 0x1011 #define E1000_DEV_ID_82546EB_COPPER 0x1010 #define E1000_DEV_ID_82546EB_FIBER 0x1012 #define E1000_DEV_ID_82541ER 0x1078 #define E1000_DEV_ID_82541GI_LF 0x107C -#define NUM_DEV_IDS 15 +#define NUM_DEV_IDS 16 #define NODE_ADDRESS_SIZE 6 #define ETH_LENGTH_OF_ADDRESS 6 diff --git a/drivers/net/ne2000.c b/drivers/net/ne2000.c index 2da57b6..ec92485 100644 --- a/drivers/net/ne2000.c +++ b/drivers/net/ne2000.c @@ -758,8 +758,6 @@ static hw_info_t hw_info[] = { #define NR_INFO (sizeof(hw_info)/sizeof(hw_info_t)) -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. */ @@ -769,14 +767,14 @@ static void pcnet_reset_8390(void) { int i, r; - PRINTK("nic base is %lx\n", nic_base); + 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)); + 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)); + 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)); + 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); @@ -852,8 +850,6 @@ int __get_prom(u8* mac_addr) return 0; } -u32 nic_base; - /* U-boot specific routines */ static u8 *pbuf = NULL; @@ -879,6 +875,7 @@ void uboot_push_tx_done(int key, int val) { int eth_init(bd_t *bd) { int r; + u8 dev_addr[6]; char ethaddr[20]; PRINTK("### eth_init\n"); @@ -901,7 +898,6 @@ int eth_init(bd_t *bd) { } #endif - nic_base = CONFIG_DRIVER_NE2000_BASE; nic.base = (u8 *) CONFIG_DRIVER_NE2000_BASE; r = get_prom(dev_addr); diff --git a/drivers/net/ns7520_eth.c b/drivers/net/ns7520_eth.c index 37411df..e19c223 100644 --- a/drivers/net/ns7520_eth.c +++ b/drivers/net/ns7520_eth.c @@ -387,8 +387,8 @@ static int ns7520_eth_reset(void) ns7520_mii_get_clock_divisor(nPhyMaxMdioClock); /* reset PHY */ - ns7520_mii_write(PHY_COMMON_CTRL, PHY_COMMON_CTRL_RESET); - ns7520_mii_write(PHY_COMMON_CTRL, 0); + ns7520_mii_write(PHY_BMCR, PHY_BMCR_RESET); + ns7520_mii_write(PHY_BMCR, 0); udelay(3000); /* [2] p.70 says at least 300us reset recovery time. */ @@ -438,26 +438,23 @@ static void ns7520_link_auto_negotiate(void) /* run auto-negotation */ /* define what we are capable of */ - ns7520_mii_write(PHY_COMMON_AUTO_ADV, - PHY_COMMON_AUTO_ADV_100BTXFD | - PHY_COMMON_AUTO_ADV_100BTX | - PHY_COMMON_AUTO_ADV_10BTFD | - PHY_COMMON_AUTO_ADV_10BT | - PHY_COMMON_AUTO_ADV_802_3); + ns7520_mii_write(PHY_ANAR, + PHY_ANLPAR_TXFD | + PHY_ANLPAR_TX | + PHY_ANLPAR_10FD | + PHY_ANLPAR_10 | + PHY_ANLPAR_PSB_802_3); /* start auto-negotiation */ - ns7520_mii_write(PHY_COMMON_CTRL, - PHY_COMMON_CTRL_AUTO_NEG | - PHY_COMMON_CTRL_RES_AUTO); + ns7520_mii_write(PHY_BMCR, PHY_BMCR_AUTON | PHY_BMCR_RST_NEG); /* wait for completion */ ulStartJiffies = get_timer(0); while (get_timer(0) < ulStartJiffies + NS7520_MII_NEG_DELAY) { - uiStatus = ns7520_mii_read(PHY_COMMON_STAT); + uiStatus = ns7520_mii_read(PHY_BMSR); if ((uiStatus & - (PHY_COMMON_STAT_AN_COMP | PHY_COMMON_STAT_LNK_STAT)) - == - (PHY_COMMON_STAT_AN_COMP | PHY_COMMON_STAT_LNK_STAT)) { + (PHY_BMSR_AUTN_COMP | PHY_BMSR_LS)) == + (PHY_BMSR_AUTN_COMP | PHY_BMSR_LS)) { /* lucky we are, auto-negotiation succeeded */ ns7520_link_print_changed(); ns7520_link_update_egcr(); @@ -518,14 +515,13 @@ static void ns7520_link_print_changed(void) DEBUG_FN(DEBUG_LINK); - uiControl = ns7520_mii_read(PHY_COMMON_CTRL); + uiControl = ns7520_mii_read(PHY_BMCR); - if ((uiControl & PHY_COMMON_CTRL_AUTO_NEG) == - PHY_COMMON_CTRL_AUTO_NEG) { - /* PHY_COMMON_STAT_LNK_STAT is only set on autonegotiation */ - uiStatus = ns7520_mii_read(PHY_COMMON_STAT); + if ((uiControl & PHY_BMCR_AUTON) == PHY_BMCR_AUTON) { + /* PHY_BMSR_LS is only set on autonegotiation */ + uiStatus = ns7520_mii_read(PHY_BMSR); - if (!(uiStatus & PHY_COMMON_STAT_LNK_STAT)) { + if (!(uiStatus & PHY_BMSR_LS)) { printk(KERN_WARNING NS7520_DRIVER_NAME ": link down\n"); /* @TODO Linux: carrier_off */ @@ -586,12 +582,12 @@ static char ns7520_mii_identify_phy(void) DEBUG_FN(DEBUG_MII); - phyDetected = (PhyType) uiID1 = ns7520_mii_read(PHY_COMMON_ID1); + phyDetected = (PhyType) uiID1 = ns7520_mii_read(PHY_PHYIDR1); switch (phyDetected) { case PHY_LXT971A: szName = "LXT971A"; - uiID2 = ns7520_mii_read(PHY_COMMON_ID2); + uiID2 = ns7520_mii_read(PHY_PHYIDR2); nPhyMaxMdioClock = PHY_LXT971_MDIO_MAX_CLK; cRes = 1; break; diff --git a/drivers/net/ns8382x.c b/drivers/net/ns8382x.c index 0b9a3ae..bb58438 100644 --- a/drivers/net/ns8382x.c +++ b/drivers/net/ns8382x.c @@ -770,14 +770,14 @@ ns8382x_send(struct eth_device *dev, volatile void *packet, int length) for (i = 0; (tx_stat = le32_to_cpu(txd.cmdsts)) & DescOwn; i++) { if (i >= TOUT_LOOP) { - printf ("%s: tx error buffer not ready: txd.cmdsts %#X\n", + printf ("%s: tx error buffer not ready: txd.cmdsts %#lX\n", dev->name, tx_stat); goto Done; } } if (!(tx_stat & DescPktOK)) { - printf("ns8382x_send: Transmit error, Tx status %X.\n", tx_stat); + printf("ns8382x_send: Transmit error, Tx status %lX.\n", tx_stat); goto Done; } #ifdef NS8382X_DEBUG diff --git a/drivers/net/ns9750_eth.c b/drivers/net/ns9750_eth.c index 0559710..cade831 100644 --- a/drivers/net/ns9750_eth.c +++ b/drivers/net/ns9750_eth.c @@ -37,7 +37,7 @@ #include "ns9750_eth.h" /* for Ethernet and PHY */ -/* some definition to make transistion to linux easier */ +/* some definition to make transition to linux easier */ #define NS9750_DRIVER_NAME "eth" #define KERN_WARNING "Warning:" @@ -399,8 +399,8 @@ static int ns9750_eth_reset (void) ns9750_mii_get_clock_divisor (nPhyMaxMdioClock); /* reset PHY */ - ns9750_mii_write (PHY_COMMON_CTRL, PHY_COMMON_CTRL_RESET); - ns9750_mii_write (PHY_COMMON_CTRL, 0); + ns9750_mii_write(PHY_BMCR, PHY_BMCR_RESET); + ns9750_mii_write(PHY_BMCR, 0); /* @TODO check time */ udelay (3000); /* [2] p.70 says at least 300us reset recovery time. But @@ -455,26 +455,26 @@ static void ns9750_link_force (void) DEBUG_FN (DEBUG_LINK); - uiControl = ns9750_mii_read (PHY_COMMON_CTRL); - uiControl &= ~(PHY_COMMON_CTRL_SPD_MA | - PHY_COMMON_CTRL_AUTO_NEG | PHY_COMMON_CTRL_DUPLEX); + uiControl = ns9750_mii_read(PHY_BMCR); + uiControl &= ~(PHY_BMCR_SPEED_MASK | + PHY_BMCR_AUTON | PHY_BMCR_DPLX); uiLastLinkStatus = 0; if ((ucLinkMode & FS_EEPROM_AUTONEG_SPEED_MASK) == FS_EEPROM_AUTONEG_SPEED_100) { - uiControl |= PHY_COMMON_CTRL_SPD_100; + uiControl |= PHY_BMCR_100MB; uiLastLinkStatus |= PHY_LXT971_STAT2_100BTX; } else - uiControl |= PHY_COMMON_CTRL_SPD_10; + uiControl |= PHY_BMCR_10_MBPS; if ((ucLinkMode & FS_EEPROM_AUTONEG_DUPLEX_MASK) == FS_EEPROM_AUTONEG_DUPLEX_FULL) { - uiControl |= PHY_COMMON_CTRL_DUPLEX; + uiControl |= PHY_BMCR_DPLX; uiLastLinkStatus |= PHY_LXT971_STAT2_DUPLEX_MODE; } - ns9750_mii_write (PHY_COMMON_CTRL, uiControl); + ns9750_mii_write(PHY_BMCR, uiControl); ns9750_link_print_changed (); ns9750_link_update_egcr (); @@ -495,25 +495,23 @@ static void ns9750_link_auto_negotiate (void) /* run auto-negotation */ /* define what we are capable of */ - ns9750_mii_write (PHY_COMMON_AUTO_ADV, - PHY_COMMON_AUTO_ADV_100BTXFD | - PHY_COMMON_AUTO_ADV_100BTX | - PHY_COMMON_AUTO_ADV_10BTFD | - PHY_COMMON_AUTO_ADV_10BT | - PHY_COMMON_AUTO_ADV_802_3); + ns9750_mii_write(PHY_ANAR, + PHY_ANLPAR_TXFD | + PHY_ANLPAR_TX | + PHY_ANLPAR_10FD | + PHY_ANLPAR_10 | + PHY_ANLPAR_PSB_802_3); /* start auto-negotiation */ - ns9750_mii_write (PHY_COMMON_CTRL, - PHY_COMMON_CTRL_AUTO_NEG | - PHY_COMMON_CTRL_RES_AUTO); + ns9750_mii_write(PHY_BMCR, PHY_BMCR_AUTON | PHY_BMCR_RST_NEG); /* wait for completion */ ulStartJiffies = get_ticks (); while (get_ticks () < ulStartJiffies + NS9750_MII_NEG_DELAY) { - uiStatus = ns9750_mii_read (PHY_COMMON_STAT); + uiStatus = ns9750_mii_read(PHY_BMSR); if ((uiStatus & - (PHY_COMMON_STAT_AN_COMP | PHY_COMMON_STAT_LNK_STAT)) == - (PHY_COMMON_STAT_AN_COMP | PHY_COMMON_STAT_LNK_STAT)) { + (PHY_BMSR_AUTN_COMP | PHY_BMSR_LS)) == + (PHY_BMSR_AUTN_COMP | PHY_BMSR_LS)) { /* lucky we are, auto-negotiation succeeded */ ns9750_link_print_changed (); ns9750_link_update_egcr (); @@ -571,14 +569,13 @@ static void ns9750_link_print_changed (void) DEBUG_FN (DEBUG_LINK); - uiControl = ns9750_mii_read (PHY_COMMON_CTRL); + uiControl = ns9750_mii_read(PHY_BMCR); - if ((uiControl & PHY_COMMON_CTRL_AUTO_NEG) == - PHY_COMMON_CTRL_AUTO_NEG) { - /* PHY_COMMON_STAT_LNK_STAT is only set on autonegotiation */ - uiStatus = ns9750_mii_read (PHY_COMMON_STAT); + if ((uiControl & PHY_BMCR_AUTON) == PHY_BMCR_AUTON) { + /* PHY_BMSR_LS is only set on autonegotiation */ + uiStatus = ns9750_mii_read(PHY_BMSR); - if (!(uiStatus & PHY_COMMON_STAT_LNK_STAT)) { + if (!(uiStatus & PHY_BMSR_LS)) { printk (KERN_WARNING NS9750_DRIVER_NAME ": link down\n"); /* @TODO Linux: carrier_off */ @@ -592,7 +589,7 @@ static void ns9750_link_print_changed (void) /* mask out all uninteresting parts */ } - /* other PHYs must store there link information in + /* other PHYs must store their link information in uiStatus as PHY_LXT971 */ } } else { @@ -637,12 +634,12 @@ static char ns9750_mii_identify_phy (void) DEBUG_FN (DEBUG_MII); - phyDetected = (PhyType) uiID1 = ns9750_mii_read (PHY_COMMON_ID1); + phyDetected = (PhyType) uiID1 = ns9750_mii_read(PHY_PHYIDR1); switch (phyDetected) { case PHY_LXT971A: szName = "LXT971A"; - uiID2 = ns9750_mii_read (PHY_COMMON_ID2); + uiID2 = ns9750_mii_read(PHY_PHYIDR2); nPhyMaxMdioClock = PHY_LXT971_MDIO_MAX_CLK; cRes = 1; break; diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index 7423bc0..d069afb 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -392,7 +392,7 @@ static int rtl8169_init_board(struct eth_device *dev) /* if unknown chip, assume array element #0, original RTL-8169 in this case */ printf("PCI device %s: unknown chip version, assuming RTL-8169\n", dev->name); - printf("PCI device: TxConfig = 0x%hX\n", (unsigned long) RTL_R32(TxConfig)); + printf("PCI device: TxConfig = 0x%lX\n", (unsigned long) RTL_R32(TxConfig)); tpc->chipset = 0; match: diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c new file mode 100644 index 0000000..9e3cf98 --- /dev/null +++ b/drivers/net/sh_eth.c @@ -0,0 +1,603 @@ +/* + * sh_eth.c - Driver for Renesas SH7763's ethernet controler. + * + * Copyright (C) 2008 Renesas Solutions Corp. + * Copyright (c) 2008 Nobuhiro Iwamatsu + * Copyright (c) 2007 Carlos Munoz <carlos@kenati.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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <config.h> +#include <common.h> +#include <malloc.h> +#include <net.h> +#include <asm/errno.h> +#include <asm/io.h> + +#include "sh_eth.h" + +#ifndef CONFIG_SH_ETHER_USE_PORT +# error "Please define CONFIG_SH_ETHER_USE_PORT" +#endif +#ifndef CONFIG_SH_ETHER_PHY_ADDR +# error "Please define CONFIG_SH_ETHER_PHY_ADDR" +#endif + +extern int eth_init(bd_t *bd); +extern void eth_halt(void); +extern int eth_rx(void); +extern int eth_send(volatile void *packet, int length); + +static struct dev_info_s *dev; + +/* + * Bits are written to the PHY serially using the + * PIR register, just like a bit banger. + */ +static void sh_eth_mii_write_phy_bits(int port, u32 val, int len) +{ + int i; + u32 pir; + + /* Bit positions is 1 less than the number of bits */ + for (i = len - 1; i >= 0; i--) { + /* Write direction, bit to write, clock is low */ + pir = 2 | ((val & 1 << i) ? 1 << 2 : 0); + outl(pir, PIR(port)); + udelay(1); + /* Write direction, bit to write, clock is high */ + pir = 3 | ((val & 1 << i) ? 1 << 2 : 0); + outl(pir, PIR(port)); + udelay(1); + /* Write direction, bit to write, clock is low */ + pir = 2 | ((val & 1 << i) ? 1 << 2 : 0); + outl(pir, PIR(port)); + udelay(1); + } +} + +static void sh_eth_mii_bus_release(int port) +{ + /* Read direction, clock is low */ + outl(0, PIR(port)); + udelay(1); + /* Read direction, clock is high */ + outl(1, PIR(port)); + udelay(1); + /* Read direction, clock is low */ + outl(0, PIR(port)); + udelay(1); +} + +static void sh_eth_mii_ind_bus_release(int port) +{ + /* Read direction, clock is low */ + outl(0, PIR(port)); + udelay(1); +} + +static int sh_eth_mii_read_phy_bits(int port, u32 * val, int len) +{ + int i; + u32 pir; + + *val = 0; + for (i = len - 1; i >= 0; i--) { + /* Read direction, clock is high */ + outl(1, PIR(port)); + udelay(1); + /* Read bit */ + pir = inl(PIR(port)); + *val |= (pir & 8) ? 1 << i : 0; + /* Read direction, clock is low */ + outl(0, PIR(port)); + udelay(1); + } + + return 0; +} + +#define PHY_INIT 0xFFFFFFFF +#define PHY_READ 0x02 +#define PHY_WRITE 0x01 +/* + * To read a phy register, mii managements frames are sent to the phy. + * The frames look like this: + * pre (32 bits): 0xffff ffff + * st (2 bits): 01 + * op (2bits): 10: read 01: write + * phyad (5 bits): xxxxx + * regad (5 bits): xxxxx + * ta (Bus release): + * data (16 bits): read data + */ +static u32 sh_eth_mii_read_phy_reg(int port, u8 phy_addr, int reg) +{ + u32 val; + + /* Sent mii management frame */ + /* pre */ + sh_eth_mii_write_phy_bits(port, PHY_INIT, 32); + /* st (start of frame) */ + sh_eth_mii_write_phy_bits(port, 0x1, 2); + /* op (code) */ + sh_eth_mii_write_phy_bits(port, PHY_READ, 2); + /* phy address */ + sh_eth_mii_write_phy_bits(port, phy_addr, 5); + /* Register to read */ + sh_eth_mii_write_phy_bits(port, reg, 5); + + /* Bus release */ + sh_eth_mii_bus_release(port); + + /* Read register */ + sh_eth_mii_read_phy_bits(port, &val, 16); + + return val; +} + +/* + * To write a phy register, mii managements frames are sent to the phy. + * The frames look like this: + * pre (32 bits): 0xffff ffff + * st (2 bits): 01 + * op (2bits): 10: read 01: write + * phyad (5 bits): xxxxx + * regad (5 bits): xxxxx + * ta (2 bits): 10 + * data (16 bits): write data + * idle (Independent bus release) + */ +static void sh_eth_mii_write_phy_reg(int port, u8 phy_addr, int reg, u16 val) +{ + /* Sent mii management frame */ + /* pre */ + sh_eth_mii_write_phy_bits(port, PHY_INIT, 32); + /* st (start of frame) */ + sh_eth_mii_write_phy_bits(port, 0x1, 2); + /* op (code) */ + sh_eth_mii_write_phy_bits(port, PHY_WRITE, 2); + /* phy address */ + sh_eth_mii_write_phy_bits(port, phy_addr, 5); + /* Register to read */ + sh_eth_mii_write_phy_bits(port, reg, 5); + /* ta */ + sh_eth_mii_write_phy_bits(port, PHY_READ, 2); + /* Write register data */ + sh_eth_mii_write_phy_bits(port, val, 16); + + /* Independent bus release */ + sh_eth_mii_ind_bus_release(port); +} + +void eth_halt(void) +{ +} + +int eth_send(volatile void *packet, int len) +{ + int port = dev->port; + struct port_info_s *port_info = &dev->port_info[port]; + int timeout; + int rc = 0; + + if (!packet || len > 0xffff) { + printf("eth_send: Invalid argument\n"); + return -EINVAL; + } + + /* packet must be a 4 byte boundary */ + if ((int)packet & (4 - 1)) { + printf("eth_send: packet not 4 byte alligned\n"); + return -EFAULT; + } + + /* Update tx descriptor */ + port_info->tx_desc_cur->td2 = ADDR_TO_PHY(packet); + port_info->tx_desc_cur->td1 = len << 16; + /* Must preserve the end of descriptor list indication */ + if (port_info->tx_desc_cur->td0 & TD_TDLE) + port_info->tx_desc_cur->td0 = TD_TACT | TD_TFP | TD_TDLE; + else + port_info->tx_desc_cur->td0 = TD_TACT | TD_TFP; + + /* Restart the transmitter if disabled */ + if (!(inl(EDTRR(port)) & EDTRR_TRNS)) + outl(EDTRR_TRNS, EDTRR(port)); + + /* Wait until packet is transmitted */ + timeout = 1000; + while (port_info->tx_desc_cur->td0 & TD_TACT && timeout--) + udelay(100); + + if (timeout < 0) { + printf("eth_send: transmit timeout\n"); + rc = -1; + goto err; + } + +err: + port_info->tx_desc_cur++; + if (port_info->tx_desc_cur >= port_info->tx_desc_base + NUM_TX_DESC) + port_info->tx_desc_cur = port_info->tx_desc_base; + + return rc; +} + +int eth_rx(void) +{ + int port = dev->port; + struct port_info_s *port_info = &dev->port_info[port]; + int len = 0; + volatile u8 *packet; + + /* Check if the rx descriptor is ready */ + if (!(port_info->rx_desc_cur->rd0 & RD_RACT)) { + /* Check for errors */ + if (!(port_info->rx_desc_cur->rd0 & RD_RFE)) { + len = port_info->rx_desc_cur->rd1 & 0xffff; + packet = (volatile u8 *) + ADDR_TO_P2(port_info->rx_desc_cur->rd2); + NetReceive(packet, len); + } + + /* Make current descriptor available again */ + if (port_info->rx_desc_cur->rd0 & RD_RDLE) + port_info->rx_desc_cur->rd0 = RD_RACT | RD_RDLE; + else + port_info->rx_desc_cur->rd0 = RD_RACT; + + /* Point to the next descriptor */ + port_info->rx_desc_cur++; + if (port_info->rx_desc_cur >= + port_info->rx_desc_base + NUM_RX_DESC) + port_info->rx_desc_cur = port_info->rx_desc_base; + } + + /* Restart the receiver if disabled */ + if (!(inl(EDRRR(port)) & EDRRR_R)) + outl(EDRRR_R, EDRRR(port)); + + return len; +} + +#define EDMR_INIT_CNT 1000 +static int sh_eth_reset(struct dev_info_s *dev) +{ + int port = dev->port; + int i; + + /* Start e-dmac transmitter and receiver */ + outl(EDSR_ENALL, EDSR(port)); + + /* Perform a software reset and wait for it to complete */ + outl(EDMR_SRST, EDMR(port)); + for (i = 0; i < EDMR_INIT_CNT; i++) { + if (!(inl(EDMR(port)) & EDMR_SRST)) + break; + udelay(1000); + } + + if (i == EDMR_INIT_CNT) { + printf("Error: Software reset timeout\n"); + return -1; + } + return 0; +} + +static int sh_eth_tx_desc_init(struct dev_info_s *dev) +{ + int port = dev->port; + struct port_info_s *port_info = &dev->port_info[port]; + u32 tmp_addr; + struct tx_desc_s *cur_tx_desc; + int i; + + /* Allocate tx descriptors. They must be TX_DESC_SIZE bytes + aligned */ + if (!(port_info->tx_desc_malloc = malloc(NUM_TX_DESC * + sizeof(struct tx_desc_s) + + TX_DESC_SIZE - 1))) { + printf("Error: malloc failed\n"); + return -ENOMEM; + } + tmp_addr = (u32) (((int)port_info->tx_desc_malloc + TX_DESC_SIZE - 1) & + ~(TX_DESC_SIZE - 1)); + /* Make sure we use a P2 address (non-cacheable) */ + port_info->tx_desc_base = (struct tx_desc_s *)ADDR_TO_P2(tmp_addr); + + port_info->tx_desc_cur = port_info->tx_desc_base; + + /* Initialize all descriptors */ + for (cur_tx_desc = port_info->tx_desc_base, i = 0; i < NUM_TX_DESC; + cur_tx_desc++, i++) { + cur_tx_desc->td0 = 0x00; + cur_tx_desc->td1 = 0x00; + cur_tx_desc->td2 = 0x00; + } + + /* Mark the end of the descriptors */ + cur_tx_desc--; + cur_tx_desc->td0 |= TD_TDLE; + + /* Point the controller to the tx descriptor list. Must use physical + addresses */ + outl(ADDR_TO_PHY(port_info->tx_desc_base), TDLAR(port)); + outl(ADDR_TO_PHY(port_info->tx_desc_base), TDFAR(port)); + outl(ADDR_TO_PHY(cur_tx_desc), TDFXR(port)); + outl(0x01, TDFFR(port));/* Last discriptor bit */ + + return 0; +} + +static int sh_eth_rx_desc_init(struct dev_info_s *dev) +{ + int port = dev->port; + struct port_info_s *port_info = &dev->port_info[port]; + u32 tmp_addr; + struct rx_desc_s *cur_rx_desc; + u8 *rx_buf; + int i; + + /* Allocate rx descriptors. They must be RX_DESC_SIZE bytes + aligned */ + if (!(port_info->rx_desc_malloc = malloc(NUM_RX_DESC * + sizeof(struct rx_desc_s) + + RX_DESC_SIZE - 1))) { + printf("Error: malloc failed\n"); + return -ENOMEM; + } + tmp_addr = (u32) (((int)port_info->rx_desc_malloc + RX_DESC_SIZE - 1) & + ~(RX_DESC_SIZE - 1)); + /* Make sure we use a P2 address (non-cacheable) */ + port_info->rx_desc_base = (struct rx_desc_s *)ADDR_TO_P2(tmp_addr); + + port_info->rx_desc_cur = port_info->rx_desc_base; + + /* Allocate rx data buffers. They must be 32 bytes aligned and in + P2 area */ + if (!(port_info->rx_buf_malloc = malloc(NUM_RX_DESC * MAX_BUF_SIZE + + 31))) { + printf("Error: malloc failed\n"); + free(port_info->rx_desc_malloc); + port_info->rx_desc_malloc = NULL; + return -ENOMEM; + } + tmp_addr = (u32)(((int)port_info->rx_buf_malloc + (32 - 1)) & + ~(32 - 1)); + port_info->rx_buf_base = (u8 *)ADDR_TO_P2(tmp_addr); + + /* Initialize all descriptors */ + for (cur_rx_desc = port_info->rx_desc_base, + rx_buf = port_info->rx_buf_base, i = 0; + i < NUM_RX_DESC; cur_rx_desc++, rx_buf += MAX_BUF_SIZE, i++) { + cur_rx_desc->rd0 = RD_RACT; + cur_rx_desc->rd1 = MAX_BUF_SIZE << 16; + cur_rx_desc->rd2 = (u32) ADDR_TO_PHY(rx_buf); + } + + /* Mark the end of the descriptors */ + cur_rx_desc--; + cur_rx_desc->rd0 |= RD_RDLE; + + /* Point the controller to the rx descriptor list */ + outl(ADDR_TO_PHY(port_info->rx_desc_base), RDLAR(port)); + outl(ADDR_TO_PHY(port_info->rx_desc_base), RDFAR(port)); + outl(ADDR_TO_PHY(cur_rx_desc), RDFXR(port)); + outl(RDFFR_RDLF, RDFFR(port)); + + return 0; +} + +static void sh_eth_desc_free(struct dev_info_s *dev) +{ + int port = dev->port; + struct port_info_s *port_info = &dev->port_info[port]; + + if (port_info->tx_desc_malloc) { + free(port_info->tx_desc_malloc); + port_info->tx_desc_malloc = NULL; + } + + if (port_info->rx_desc_malloc) { + free(port_info->rx_desc_malloc); + port_info->rx_desc_malloc = NULL; + } + + if (port_info->rx_buf_malloc) { + free(port_info->rx_buf_malloc); + port_info->rx_buf_malloc = NULL; + } +} + +static int sh_eth_desc_init(struct dev_info_s *dev) +{ + int rc; + + if ((rc = sh_eth_tx_desc_init(dev)) || (rc = sh_eth_rx_desc_init(dev))) { + sh_eth_desc_free(dev); + return rc; + } + + return 0; +} + +static int sh_eth_phy_config(struct dev_info_s *dev) +{ + int port = dev->port; + struct port_info_s *port_info = &dev->port_info[port]; + int timeout; + u32 val; + /* Reset phy */ + sh_eth_mii_write_phy_reg(port, port_info->phy_addr, PHY_CTRL, PHY_C_RESET); + timeout = 10; + while (timeout--) { + val = sh_eth_mii_read_phy_reg(port, port_info->phy_addr, PHY_CTRL); + if (!(val & PHY_C_RESET)) + break; + udelay(50000); + } + if (timeout < 0) { + printf("%s phy reset timeout\n", __func__); + return -1; + } + + /* Advertise 100/10 baseT full/half duplex */ + sh_eth_mii_write_phy_reg(port, port_info->phy_addr, PHY_ANA, + (PHY_A_FDX|PHY_A_HDX|PHY_A_10FDX|PHY_A_10HDX|PHY_A_EXT)); + /* Autonegotiation, normal operation, full duplex, enable tx */ + sh_eth_mii_write_phy_reg(port, port_info->phy_addr, PHY_CTRL, + (PHY_C_ANEGEN|PHY_C_RANEG)); + /* Wait for autonegotiation to complete */ + timeout = 100; + while (timeout--) { + val = sh_eth_mii_read_phy_reg(port, port_info->phy_addr, 1); + if (val & PHY_S_ANEGC) + break; + udelay(50000); + } + if (timeout < 0) { + printf("sh_eth_phy_config() phy auto-negotiation failed\n"); + return -1; + } + + return 0; +} + +static int sh_eth_config(struct dev_info_s *dev, bd_t * bd) +{ + int port = dev->port; + struct port_info_s *port_info = &dev->port_info[port]; + u32 val; + u32 phy_status; + int rc; + + /* Configure e-dmac registers */ + outl((inl(EDMR(port)) & ~EMDR_DESC_R) | EDMR_EL, EDMR(port)); + outl(0, EESIPR(port)); + outl(0, TRSCER(port)); + outl(0, TFTR(port)); + outl((FIFO_SIZE_T | FIFO_SIZE_R), FDR(port)); + outl(RMCR_RST, RMCR(port)); + outl(0, RPADIR(port)); + outl((FIFO_F_D_RFF | FIFO_F_D_RFD), FCFTR(port)); + + /* Configure e-mac registers */ + outl(0, ECSIPR(port)); + + /* Set Mac address */ + val = bd->bi_enetaddr[0] << 24 | bd->bi_enetaddr[1] << 16 | + bd->bi_enetaddr[2] << 8 | bd->bi_enetaddr[3]; + outl(val, MAHR(port)); + + val = bd->bi_enetaddr[4] << 8 | bd->bi_enetaddr[5]; + outl(val, MALR(port)); + + outl(RFLR_RFL_MIN, RFLR(port)); + outl(0, PIPR(port)); + outl(APR_AP, APR(port)); + outl(MPR_MP, MPR(port)); + outl(TPAUSER_TPAUSE, TPAUSER(port)); + + /* Configure phy */ + if ((rc = sh_eth_phy_config(dev))) + return rc; + + /* Read phy status to finish configuring the e-mac */ + phy_status = sh_eth_mii_read_phy_reg(dev->port, + dev->port_info[dev->port].phy_addr, + 1); + + /* Set the transfer speed */ + if (phy_status & (PHY_S_100X_F|PHY_S_100X_H)) { + printf("100Base/"); + outl(GECMR_100B, GECMR(port)); + } else { + printf("10Base/"); + outl(GECMR_10B, GECMR(port)); + } + + /* Check if full duplex mode is supported by the phy */ + if (phy_status & (PHY_S_100X_F|PHY_S_10T_F)) { + printf("Full\n"); + outl((ECMR_CHG_DM|ECMR_RE|ECMR_TE|ECMR_DM), ECMR(port)); + } else { + printf("Half\n"); + outl((ECMR_CHG_DM|ECMR_RE|ECMR_TE), ECMR(port)); + } + return 0; +} + +static int sh_eth_start(struct dev_info_s *dev) +{ + /* + * Enable the e-dmac receiver only. The transmitter will be enabled when + * we have something to transmit + */ + outl(EDRRR_R, EDRRR(dev->port)); + + return 0; +} + +static int sh_eth_get_mac(bd_t *bd) +{ + char *s, *e; + int i; + + s = getenv("ethaddr"); + if (s != NULL) { + for (i = 0; i < 6; ++i) { + bd->bi_enetaddr[i] = s ? simple_strtoul(s, &e, 16) : 0; + if (s) + s = (*e) ? e + 1 : e; + } + } else { + puts("Please set MAC address\n"); + } + return 0; +} + +int eth_init(bd_t *bd) +{ + int rc; + /* Allocate main device information structure */ + if (!(dev = malloc(sizeof(*dev)))) { + printf("eth_init: malloc failed\n"); + return -ENOMEM; + } + + memset(dev, 0, sizeof(*dev)); + + dev->port = CONFIG_SH_ETHER_USE_PORT; + dev->port_info[dev->port].phy_addr = CONFIG_SH_ETHER_PHY_ADDR; + + sh_eth_get_mac(bd); + + if ((rc = sh_eth_reset(dev)) || (rc = sh_eth_desc_init(dev))) + goto err; + + if ((rc = sh_eth_config(dev, bd)) || (rc = sh_eth_start(dev))) + goto err_desc; + + return 0; + +err_desc: + sh_eth_desc_free(dev); +err: + free(dev); + printf("eth_init: Failed\n"); + return rc; +} diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h new file mode 100644 index 0000000..9cf0ea0 --- /dev/null +++ b/drivers/net/sh_eth.h @@ -0,0 +1,446 @@ +/* + * sh_eth.h - Driver for Renesas SH7763's gigabit ethernet controler. + * + * Copyright (C) 2008 Renesas Solutions Corp. + * Copyright (c) 2008 Nobuhiro Iwamatsu + * Copyright (c) 2007 Carlos Munoz <carlos@kenati.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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <asm/types.h> + +#define SHETHER_NAME "sh_eth" + +/* Malloc returns addresses in the P1 area (cacheable). However we need to + use area P2 (non-cacheable) */ +#define ADDR_TO_P2(addr) ((((int)(addr) & ~0xe0000000) | 0xa0000000)) + +/* The ethernet controller needs to use physical addresses */ +#define ADDR_TO_PHY(addr) ((int)(addr) & ~0xe0000000) + +/* Number of supported ports */ +#define MAX_PORT_NUM 2 + +/* Buffers must be big enough to hold the largest ethernet frame. Also, rx + buffers must be a multiple of 32 bytes */ +#define MAX_BUF_SIZE (48 * 32) + +/* The number of tx descriptors must be large enough to point to 5 or more + frames. If each frame uses 2 descriptors, at least 10 descriptors are needed. + We use one descriptor per frame */ +#define NUM_TX_DESC 8 + +/* The size of the tx descriptor is determined by how much padding is used. + 4, 20, or 52 bytes of padding can be used */ +#define TX_DESC_PADDING 4 +#define TX_DESC_SIZE (12 + TX_DESC_PADDING) + +/* Tx descriptor. We always use 4 bytes of padding */ +struct tx_desc_s { + volatile u32 td0; + u32 td1; + u32 td2; /* Buffer start */ + u32 padding; +}; + +/* There is no limitation in the number of rx descriptors */ +#define NUM_RX_DESC 8 + +/* The size of the rx descriptor is determined by how much padding is used. + 4, 20, or 52 bytes of padding can be used */ +#define RX_DESC_PADDING 4 +#define RX_DESC_SIZE (12 + RX_DESC_PADDING) + +/* Rx descriptor. We always use 4 bytes of padding */ +struct rx_desc_s { + volatile u32 rd0; + volatile u32 rd1; + u32 rd2; /* Buffer start */ + u32 padding; +}; + +struct port_info_s { + struct tx_desc_s *tx_desc_malloc; + struct tx_desc_s *tx_desc_base; + struct tx_desc_s *tx_desc_cur; + struct rx_desc_s *rx_desc_malloc; + struct rx_desc_s *rx_desc_base; + struct rx_desc_s *rx_desc_cur; + u8 *rx_buf_malloc; + u8 *rx_buf_base; + u8 mac_addr[6]; + u8 phy_addr; +}; + +struct dev_info_s { + int port; + struct port_info_s port_info[MAX_PORT_NUM]; +}; + +/* Register Address */ +#define BASE_IO_ADDR 0xfee00000 + +#define EDSR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0000) + +#define TDLAR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0010) +#define TDFAR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0014) +#define TDFXR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0018) +#define TDFFR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x001c) + +#define RDLAR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0030) +#define RDFAR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0034) +#define RDFXR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0038) +#define RDFFR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x003c) + +#define EDMR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0400) +#define EDTRR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0408) +#define EDRRR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0410) +#define EESR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0428) +#define EESIPR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0430) +#define TRSCER(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0438) +#define TFTR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0448) +#define FDR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0450) +#define RMCR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0458) +#define RPADIR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0460) +#define FCFTR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0468) +#define ECMR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0500) +#define RFLR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0508) +#define ECSIPR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0518) +#define PIR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0520) +#define PIPR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x052c) +#define APR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0554) +#define MPR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0558) +#define TPAUSER(port) (BASE_IO_ADDR + 0x800 * (port) + 0x0564) +#define GECMR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x05b0) +#define MALR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x05c8) +#define MAHR(port) (BASE_IO_ADDR + 0x800 * (port) + 0x05c0) + +/* + * Register's bits + * Copy from Linux driver source code + */ +#ifdef CONFIG_CPU_SH7763 +/* EDSR */ +enum EDSR_BIT { + EDSR_ENT = 0x01, EDSR_ENR = 0x02, +}; +#define EDSR_ENALL (EDSR_ENT|EDSR_ENR) +#endif + +/* EDMR */ +enum DMAC_M_BIT { + EDMR_DL1 = 0x20, EDMR_DL0 = 0x10, +#ifdef CONFIG_CPU_SH7763 + EDMR_SRST = 0x03, + EMDR_DESC_R = 0x30, /* Descriptor reserve size */ + EDMR_EL = 0x40, /* Litte endian */ +#else /* CONFIG_CPU_SH7763 */ + EDMR_SRST = 0x01, +#endif +}; + +/* RFLR */ +#define RFLR_RFL_MIN 0x05EE /* Recv Frame length 1518 byte */ + +/* EDTRR */ +enum DMAC_T_BIT { +#ifdef CONFIG_CPU_SH7763 + EDTRR_TRNS = 0x03, +#else + EDTRR_TRNS = 0x01, +#endif +}; + +/* GECMR */ +enum GECMR_BIT { + GECMR_1000B = 0x01, GECMR_100B = 0x40, GECMR_10B = 0x00, +}; + +/* EDRRR*/ +enum EDRRR_R_BIT { + EDRRR_R = 0x01, +}; + +/* TPAUSER */ +enum TPAUSER_BIT { + TPAUSER_TPAUSE = 0x0000ffff, + TPAUSER_UNLIMITED = 0, +}; + +/* BCFR */ +enum BCFR_BIT { + BCFR_RPAUSE = 0x0000ffff, + BCFR_UNLIMITED = 0, +}; + +/* PIR */ +enum PIR_BIT { + PIR_MDI = 0x08, PIR_MDO = 0x04, PIR_MMD = 0x02, PIR_MDC = 0x01, +}; + +/* PSR */ +enum PHY_STATUS_BIT { PHY_ST_LINK = 0x01, }; + +/* EESR */ +enum EESR_BIT { +#ifndef CONFIG_CPU_SH7763 + EESR_TWB = 0x40000000, +#else + EESR_TWB = 0xC0000000, + EESR_TC1 = 0x20000000, + EESR_TUC = 0x10000000, + EESR_ROC = 0x80000000, +#endif + EESR_TABT = 0x04000000, + EESR_RABT = 0x02000000, EESR_RFRMER = 0x01000000, +#ifndef CONFIG_CPU_SH7763 + EESR_ADE = 0x00800000, +#endif + EESR_ECI = 0x00400000, + EESR_FTC = 0x00200000, EESR_TDE = 0x00100000, + EESR_TFE = 0x00080000, EESR_FRC = 0x00040000, + EESR_RDE = 0x00020000, EESR_RFE = 0x00010000, +#ifndef CONFIG_CPU_SH7763 + EESR_CND = 0x00000800, +#endif + EESR_DLC = 0x00000400, + EESR_CD = 0x00000200, EESR_RTO = 0x00000100, + EESR_RMAF = 0x00000080, EESR_CEEF = 0x00000040, + EESR_CELF = 0x00000020, EESR_RRF = 0x00000010, + rESR_RTLF = 0x00000008, EESR_RTSF = 0x00000004, + EESR_PRE = 0x00000002, EESR_CERF = 0x00000001, +}; + + +#ifdef CONFIG_CPU_SH7763 +# define TX_CHECK (EESR_TC1 | EESR_FTC) +# define EESR_ERR_CHECK (EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE \ + | EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI) +# define TX_ERROR_CEHCK (EESR_TWB | EESR_TABT | EESR_TDE | EESR_TFE) + +#else +# define TX_CHECK (EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_RTO) +# define EESR_ERR_CHECK (EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE \ + | EESR_RFRMER | EESR_ADE | EESR_TFE | EESR_TDE | EESR_ECI) +# define TX_ERROR_CEHCK (EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE) +#endif + +/* EESIPR */ +enum DMAC_IM_BIT { + DMAC_M_TWB = 0x40000000, DMAC_M_TABT = 0x04000000, + DMAC_M_RABT = 0x02000000, + DMAC_M_RFRMER = 0x01000000, DMAC_M_ADF = 0x00800000, + DMAC_M_ECI = 0x00400000, DMAC_M_FTC = 0x00200000, + DMAC_M_TDE = 0x00100000, DMAC_M_TFE = 0x00080000, + DMAC_M_FRC = 0x00040000, DMAC_M_RDE = 0x00020000, + DMAC_M_RFE = 0x00010000, DMAC_M_TINT4 = 0x00000800, + DMAC_M_TINT3 = 0x00000400, DMAC_M_TINT2 = 0x00000200, + DMAC_M_TINT1 = 0x00000100, DMAC_M_RINT8 = 0x00000080, + DMAC_M_RINT5 = 0x00000010, DMAC_M_RINT4 = 0x00000008, + DMAC_M_RINT3 = 0x00000004, DMAC_M_RINT2 = 0x00000002, + DMAC_M_RINT1 = 0x00000001, +}; + +/* Receive descriptor bit */ +enum RD_STS_BIT { + RD_RACT = 0x80000000, RD_RDLE = 0x40000000, + RD_RFP1 = 0x20000000, RD_RFP0 = 0x10000000, + RD_RFE = 0x08000000, RD_RFS10 = 0x00000200, + RD_RFS9 = 0x00000100, RD_RFS8 = 0x00000080, + RD_RFS7 = 0x00000040, RD_RFS6 = 0x00000020, + RD_RFS5 = 0x00000010, RD_RFS4 = 0x00000008, + RD_RFS3 = 0x00000004, RD_RFS2 = 0x00000002, + RD_RFS1 = 0x00000001, +}; +#define RDF1ST RD_RFP1 +#define RDFEND RD_RFP0 +#define RD_RFP (RD_RFP1|RD_RFP0) + +/* RDFFR*/ +enum RDFFR_BIT { + RDFFR_RDLF = 0x01, +}; + +/* FCFTR */ +enum FCFTR_BIT { + FCFTR_RFF2 = 0x00040000, FCFTR_RFF1 = 0x00020000, + FCFTR_RFF0 = 0x00010000, FCFTR_RFD2 = 0x00000004, + FCFTR_RFD1 = 0x00000002, FCFTR_RFD0 = 0x00000001, +}; +#define FIFO_F_D_RFF (FCFTR_RFF2|FCFTR_RFF1|FCFTR_RFF0) +#define FIFO_F_D_RFD (FCFTR_RFD2|FCFTR_RFD1|FCFTR_RFD0) + +/* Transfer descriptor bit */ +enum TD_STS_BIT { +#ifdef CONFIG_CPU_SH7763 + TD_TACT = 0x80000000, +#else + TD_TACT = 0x7fffffff, +#endif + TD_TDLE = 0x40000000, TD_TFP1 = 0x20000000, + TD_TFP0 = 0x10000000, +}; +#define TDF1ST TD_TFP1 +#define TDFEND TD_TFP0 +#define TD_TFP (TD_TFP1|TD_TFP0) + +/* RMCR */ +enum RECV_RST_BIT { RMCR_RST = 0x01, }; +/* ECMR */ +enum FELIC_MODE_BIT { +#ifdef CONFIG_CPU_SH7763 + ECMR_TRCCM=0x04000000, ECMR_RCSC= 0x00800000, ECMR_DPAD= 0x00200000, + ECMR_RZPF = 0x00100000, +#endif + ECMR_ZPF = 0x00080000, ECMR_PFR = 0x00040000, ECMR_RXF = 0x00020000, + ECMR_TXF = 0x00010000, ECMR_MCT = 0x00002000, ECMR_PRCEF = 0x00001000, + ECMR_PMDE = 0x00000200, ECMR_RE = 0x00000040, ECMR_TE = 0x00000020, + ECMR_ILB = 0x00000008, ECMR_ELB = 0x00000004, ECMR_DM = 0x00000002, + ECMR_PRM = 0x00000001, +}; + +#ifdef CONFIG_CPU_SH7763 +#define ECMR_CHG_DM (ECMR_TRCCM | ECMR_RZPF | ECMR_ZPF | ECMR_PFR | ECMR_RXF | \ + ECMR_TXF | ECMR_MCT) +#else +#define ECMR_CHG_DM (ECMR_ZPF | ECMR_PFR ECMR_RXF | ECMR_TXF | ECMR_MCT) +#endif + +/* ECSR */ +enum ECSR_STATUS_BIT { +#ifndef CONFIG_CPU_SH7763 + ECSR_BRCRX = 0x20, ECSR_PSRTO = 0x10, +#endif + ECSR_LCHNG = 0x04, + ECSR_MPD = 0x02, ECSR_ICD = 0x01, +}; + +#ifdef CONFIG_CPU_SH7763 +# define ECSR_INIT (ECSR_ICD | ECSIPR_MPDIP) +#else +# define ECSR_INIT (ECSR_BRCRX | ECSR_PSRTO | \ + ECSR_LCHNG | ECSR_ICD | ECSIPR_MPDIP) +#endif + +/* ECSIPR */ +enum ECSIPR_STATUS_MASK_BIT { +#ifndef CONFIG_CPU_SH7763 + ECSIPR_BRCRXIP = 0x20, ECSIPR_PSRTOIP = 0x10, +#endif + ECSIPR_LCHNGIP = 0x04, + ECSIPR_MPDIP = 0x02, ECSIPR_ICDIP = 0x01, +}; + +#ifdef CONFIG_CPU_SH7763 +# define ECSIPR_INIT (ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP) +#else +# define ECSIPR_INIT (ECSIPR_BRCRXIP | ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | \ + ECSIPR_ICDIP | ECSIPR_MPDIP) +#endif + +/* APR */ +enum APR_BIT { + APR_AP = 0x00000004, +}; + +/* MPR */ +enum MPR_BIT { + MPR_MP = 0x00000006, +}; + +/* TRSCER */ +enum DESC_I_BIT { + DESC_I_TINT4 = 0x0800, DESC_I_TINT3 = 0x0400, DESC_I_TINT2 = 0x0200, + DESC_I_TINT1 = 0x0100, DESC_I_RINT8 = 0x0080, DESC_I_RINT5 = 0x0010, + DESC_I_RINT4 = 0x0008, DESC_I_RINT3 = 0x0004, DESC_I_RINT2 = 0x0002, + DESC_I_RINT1 = 0x0001, +}; + +/* RPADIR */ +enum RPADIR_BIT { + RPADIR_PADS1 = 0x20000, RPADIR_PADS0 = 0x10000, + RPADIR_PADR = 0x0003f, +}; + +#ifdef CONFIG_CPU_SH7763 +# define RPADIR_INIT (0x00) +#else +# define RPADIR_INIT (RPADIR_PADS1) +#endif + +/* FDR */ +enum FIFO_SIZE_BIT { + FIFO_SIZE_T = 0x00000700, FIFO_SIZE_R = 0x00000007, +}; + +enum PHY_OFFSETS { + PHY_CTRL = 0, PHY_STAT = 1, PHY_IDT1 = 2, PHY_IDT2 = 3, + PHY_ANA = 4, PHY_ANL = 5, PHY_ANE = 6, + PHY_16 = 16, +}; + +/* PHY_CTRL */ +enum PHY_CTRL_BIT { + PHY_C_RESET = 0x8000, PHY_C_LOOPBK = 0x4000, PHY_C_SPEEDSL = 0x2000, + PHY_C_ANEGEN = 0x1000, PHY_C_PWRDN = 0x0800, PHY_C_ISO = 0x0400, + PHY_C_RANEG = 0x0200, PHY_C_DUPLEX = 0x0100, PHY_C_COLT = 0x0080, +}; +#define DM9161_PHY_C_ANEGEN 0 /* auto nego special */ + +/* PHY_STAT */ +enum PHY_STAT_BIT { + PHY_S_100T4 = 0x8000, PHY_S_100X_F = 0x4000, PHY_S_100X_H = 0x2000, + PHY_S_10T_F = 0x1000, PHY_S_10T_H = 0x0800, PHY_S_ANEGC = 0x0020, + PHY_S_RFAULT = 0x0010, PHY_S_ANEGA = 0x0008, PHY_S_LINK = 0x0004, + PHY_S_JAB = 0x0002, PHY_S_EXTD = 0x0001, +}; + +/* PHY_ANA */ +enum PHY_ANA_BIT { + PHY_A_NP = 0x8000, PHY_A_ACK = 0x4000, PHY_A_RF = 0x2000, + PHY_A_FCS = 0x0400, PHY_A_T4 = 0x0200, PHY_A_FDX = 0x0100, + PHY_A_HDX = 0x0080, PHY_A_10FDX = 0x0040, PHY_A_10HDX = 0x0020, + PHY_A_SEL = 0x001e, + PHY_A_EXT = 0x0001, +}; + +/* PHY_ANL */ +enum PHY_ANL_BIT { + PHY_L_NP = 0x8000, PHY_L_ACK = 0x4000, PHY_L_RF = 0x2000, + PHY_L_FCS = 0x0400, PHY_L_T4 = 0x0200, PHY_L_FDX = 0x0100, + PHY_L_HDX = 0x0080, PHY_L_10FDX = 0x0040, PHY_L_10HDX = 0x0020, + PHY_L_SEL = 0x001f, +}; + +/* PHY_ANE */ +enum PHY_ANE_BIT { + PHY_E_PDF = 0x0010, PHY_E_LPNPA = 0x0008, PHY_E_NPA = 0x0004, + PHY_E_PRX = 0x0002, PHY_E_LPANEGA = 0x0001, +}; + +/* DM9161 */ +enum PHY_16_BIT { + PHY_16_BP4B45 = 0x8000, PHY_16_BPSCR = 0x4000, PHY_16_BPALIGN = 0x2000, + PHY_16_BP_ADPOK = 0x1000, PHY_16_Repeatmode = 0x0800, + PHY_16_TXselect = 0x0400, + PHY_16_Rsvd = 0x0200, PHY_16_RMIIEnable = 0x0100, + PHY_16_Force100LNK = 0x0080, + PHY_16_APDLED_CTL = 0x0040, PHY_16_COLLED_CTL = 0x0020, + PHY_16_RPDCTR_EN = 0x0010, + PHY_16_ResetStMch = 0x0008, PHY_16_PreamSupr = 0x0004, + PHY_16_Sleepmode = 0x0002, + PHY_16_RemoteLoopOut = 0x0001, +}; diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 7555cb9..1484b0b 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -33,7 +33,7 @@ CONFIG_DRIVER_SMC911X_16_BIT shall be set" #endif -#ifdef CONFIG_DRIVER_SMC911X_32_BIT +#if defined (CONFIG_DRIVER_SMC911X_32_BIT) static inline u32 reg_read(u32 addr) { return *(volatile u32*)addr; @@ -42,7 +42,7 @@ static inline void reg_write(u32 addr, u32 val) { *(volatile u32*)addr = val; } -#elif CONFIG_DRIVER_SMC911X_16_BIT +#elif defined (CONFIG_DRIVER_SMC911X_16_BIT) static inline u32 reg_read(u32 addr) { volatile u16 *addr_16 = (u16 *)addr; @@ -597,7 +597,7 @@ int eth_init(bd_t *bd) val = reg_read(BYTE_TEST); if (val != 0x87654321) { - printf(DRIVERNAME ": Invalid chip endian 0x08%x\n", val); + printf(DRIVERNAME ": Invalid chip endian 0x%08x\n", val); goto err_out; } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index b3ae3b1..16180cb 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -411,6 +411,40 @@ void pci_cfgfunc_do_nothing(struct pci_controller *hose, extern int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev); extern void pciauto_config_init(struct pci_controller *hose); +int __pci_skip_dev(struct pci_controller *hose, pci_dev_t dev) +{ + /* + * Check if pci device should be skipped in configuration + */ + if (dev == PCI_BDF(hose->first_busno, 0, 0)) { +#if defined(CONFIG_PCI_CONFIG_HOST_BRIDGE) /* don't skip host bridge */ + /* + * Only skip configuration if "pciconfighost" is not set + */ + if (getenv("pciconfighost") == NULL) + return 1; +#else + return 1; +#endif + } + + return 0; +} +int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev) + __attribute__((weak, alias("__pci_skip_dev"))); + +#ifdef CONFIG_PCI_SCAN_SHOW +int __pci_print_dev(struct pci_controller *hose, pci_dev_t dev) +{ + if (dev == PCI_BDF(hose->first_busno, 0, 0)) + return 0; + + return 1; +} +int pci_print_dev(struct pci_controller *hose, pci_dev_t dev) + __attribute__((weak, alias("__pci_print_dev"))); +#endif /* CONFIG_PCI_SCAN_SHOW */ + int pci_hose_scan_bus(struct pci_controller *hose, int bus) { unsigned int sub_bus, found_multi=0; @@ -423,21 +457,10 @@ int pci_hose_scan_bus(struct pci_controller *hose, int bus) for (dev = PCI_BDF(bus,0,0); dev < PCI_BDF(bus,PCI_MAX_PCI_DEVICES-1,PCI_MAX_PCI_FUNCTIONS-1); - dev += PCI_BDF(0,0,1)) - { - /* 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 */ - /* - * Only skip hostbridge configuration if "pciconfighost" is not set - */ - if (getenv("pciconfighost") == NULL) { - continue; /* Skip our host bridge */ - } -#else - continue; /* Skip our host bridge */ -#endif - } + dev += PCI_BDF(0,0,1)) { + + if (pci_skip_dev(hose, dev)) + continue; if (PCI_FUNC(dev) && !found_multi) continue; @@ -473,15 +496,14 @@ int pci_hose_scan_bus(struct pci_controller *hose, int bus) hose->fixup_irq(hose, dev); #ifdef CONFIG_PCI_SCAN_SHOW - /* Skip our host bridge */ - if ( dev != PCI_BDF(hose->first_busno,0,0) ) { - unsigned char int_line; - - pci_hose_read_config_byte(hose, dev, PCI_INTERRUPT_LINE, - &int_line); - printf(" %02x %02x %04x %04x %04x %02x\n", - PCI_BUS(dev), PCI_DEV(dev), vendor, device, class, - int_line); + if (pci_print_dev(hose, dev)) { + unsigned char int_line; + + pci_hose_read_config_byte(hose, dev, PCI_INTERRUPT_LINE, + &int_line); + printf(" %02x %02x %04x %04x %04x %02x\n", + PCI_BUS(dev), PCI_DEV(dev), vendor, device, class, + int_line); } #endif } diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index ac4378a..ba251d0 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -27,11 +27,11 @@ LIB := $(obj)libpcmcia.a COBJS-$(CONFIG_I82365) += i82365.o COBJS-y += mpc8xx_pcmcia.o -COBJS-y += pxa_pcmcia.o +COBJS-$(CONFIG_PXA_PCMCIA) += pxa_pcmcia.o COBJS-y += rpx_pcmcia.o -COBJS-y += ti_pci1410a.o +COBJS-$(CONFIG_IDE_TI_CARDBUS) += ti_pci1410a.o COBJS-y += tqm8xx_pcmcia.o -COBJS-y += marubun_pcmcia.o +COBJS-$(CONFIG_MARUBUN_PCCARD) += marubun_pcmcia.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/pcmcia/marubun_pcmcia.c b/drivers/pcmcia/marubun_pcmcia.c index a213092..d075ba3 100644 --- a/drivers/pcmcia/marubun_pcmcia.c +++ b/drivers/pcmcia/marubun_pcmcia.c @@ -31,12 +31,11 @@ #define CONFIG_PCMCIA #endif -#if defined(CONFIG_CMD_IDE) +#if defined(CONFIG_CMD_IDE) #define CONFIG_PCMCIA #endif -#if defined(CONFIG_PCMCIA) \ - && (defined(CONFIG_MARUBUN_PCCARD)) +#if defined(CONFIG_PCMCIA) /* MR-SHPC-01 register */ #define MRSHPC_MODE (CFG_MARUBUN_MRSHPC + 4) @@ -112,4 +111,4 @@ int pcmcia_off (void) return 0; } -#endif /* CONFIG_MARUBUN_PCCARD */ +#endif /* CONFIG_PCMCIA */ diff --git a/drivers/pcmcia/pxa_pcmcia.c b/drivers/pcmcia/pxa_pcmcia.c index 65427ef..11d8590 100644 --- a/drivers/pcmcia/pxa_pcmcia.c +++ b/drivers/pcmcia/pxa_pcmcia.c @@ -1,8 +1,6 @@ #include <common.h> #include <config.h> -#ifdef CONFIG_PXA_PCMCIA - #include <pcmcia.h> #include <asm/arch/pxa-regs.h> #include <asm/io.h> @@ -93,5 +91,3 @@ int pcmcia_off (void) return 0; } #endif - -#endif /* CONFIG_PXA_PCMCIA */ diff --git a/drivers/pcmcia/ti_pci1410a.c b/drivers/pcmcia/ti_pci1410a.c index 208ca50..c876d0c 100644 --- a/drivers/pcmcia/ti_pci1410a.c +++ b/drivers/pcmcia/ti_pci1410a.c @@ -64,7 +64,7 @@ #include <pcmcia.h> -#if defined(CONFIG_CMD_PCMCIA) && defined(CONFIG_IDE_TI_CARDBUS) +#if defined(CONFIG_CMD_PCMCIA) int pcmcia_on(int ide_base_bus); @@ -662,4 +662,4 @@ static int identify(volatile uchar *p) return 0; /* don't know */ } -#endif /* CONFIG_IDE_TI_CARDBUS */ +#endif /* CONFIG_CMD_PCMCIA */ diff --git a/drivers/rtc/m41t60.c b/drivers/rtc/m41t60.c index 8a32ea0..ef135ca 100644 --- a/drivers/rtc/m41t60.c +++ b/drivers/rtc/m41t60.c @@ -241,7 +241,7 @@ void rtc_reset(void) if (l <= 0x3F) { if ((data[RTC_CTRL] & 0x3F) != l) { - printf("Setting RTC calibration to 0x%02X\n", + printf("Setting RTC calibration to 0x%02lX\n", l); data[RTC_CTRL] &= 0xC0; data[RTC_CTRL] |= (uchar) l; diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index 76425d8..182ca2d 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -144,8 +144,13 @@ static int calc_divisor (NS16550_t port) #else #define MODE_X_DIV 16 #endif - return (CFG_NS16550_CLK / MODE_X_DIV / gd->baudrate); + /* Compute divisor value. Normally, we should simply return: + * CFG_NS16550_CLK) / MODE_X_DIV / gd->baudrate + * but we need to round that value by adding 0.5 or 8/16. + * Rounding is especially important at high baud rates. + */ + return (((16 * CFG_NS16550_CLK) / MODE_X_DIV / gd->baudrate) + 8) / 16; } #if !defined(CONFIG_SERIAL_MULTI) diff --git a/drivers/serial/serial_pl010.c b/drivers/serial/serial_pl010.c index 417b6ae..134ed09 100644 --- a/drivers/serial/serial_pl010.c +++ b/drivers/serial/serial_pl010.c @@ -29,6 +29,7 @@ /* Should be fairly simple to make it work with the PL010 as well */ #include <common.h> +#include <watchdog.h> #ifdef CFG_PL010_SERIAL @@ -137,7 +138,8 @@ void serial_setbrg (void) static void pl010_putc (int portnum, char c) { /* Wait until there is space in the FIFO */ - while (IO_READ (port[portnum] + UART_PL01x_FR) & UART_PL01x_FR_TXFF); + while (IO_READ (port[portnum] + UART_PL01x_FR) & UART_PL01x_FR_TXFF) + WATCHDOG_RESET(); /* Send the character */ IO_WRITE (port[portnum] + UART_PL01x_DR, c); @@ -148,7 +150,8 @@ static int pl010_getc (int portnum) unsigned int data; /* Wait until there is data in the FIFO */ - while (IO_READ (port[portnum] + UART_PL01x_FR) & UART_PL01x_FR_RXFE); + while (IO_READ (port[portnum] + UART_PL01x_FR) & UART_PL01x_FR_RXFE) + WATCHDOG_RESET(); data = IO_READ (port[portnum] + UART_PL01x_DR); @@ -164,6 +167,7 @@ static int pl010_getc (int portnum) static int pl010_tstc (int portnum) { + WATCHDOG_RESET(); return !(IO_READ (port[portnum] + UART_PL01x_FR) & UART_PL01x_FR_RXFE); } diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index e66e0ee..4f7b679 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -25,7 +25,7 @@ include $(TOPDIR)/config.mk LIB := $(obj)libspi.a -COBJS-y += mpc8xxx_spi.o +COBJS-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o COBJS-$(CONFIG_ATMEL_SPI) += atmel_spi.o COBJS-$(CONFIG_MXC_SPI) += mxc_spi.o diff --git a/drivers/spi/mpc8xxx_spi.c b/drivers/spi/mpc8xxx_spi.c index 136fb50..9eaf986 100644 --- a/drivers/spi/mpc8xxx_spi.c +++ b/drivers/spi/mpc8xxx_spi.c @@ -22,7 +22,6 @@ */ #include <common.h> -#if defined(CONFIG_MPC8XXX_SPI) && defined(CONFIG_HARD_SPI) #include <malloc.h> #include <spi.h> @@ -180,4 +179,3 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, return 0; } -#endif /* CONFIG_HARD_SPI */ diff --git a/drivers/usb/usbdcore.c b/drivers/usb/usbdcore.c index 308c7ce..a621ce7 100644 --- a/drivers/usb/usbdcore.c +++ b/drivers/usb/usbdcore.c @@ -146,12 +146,9 @@ struct usb_string_descriptor *usbd_get_string (__u8 index) static struct usb_configuration_instance *usbd_device_configuration_instance (struct usb_device_instance *device, unsigned int port, unsigned int configuration) { - /* XXX */ - configuration = configuration ? configuration - 1 : 0; - - if (configuration >= device->configurations) { + if (configuration >= device->configurations) return NULL; - } + return device->configuration_instance_array + configuration; } diff --git a/drivers/usb/usbdcore_ep0.c b/drivers/usb/usbdcore_ep0.c index 1e44f32..cf3f382 100644 --- a/drivers/usb/usbdcore_ep0.c +++ b/drivers/usb/usbdcore_ep0.c @@ -235,8 +235,8 @@ static int ep0_get_descriptor (struct usb_device_instance *device, return -1; } /*dbg_ep0(2, "%d %d", index, device_descriptor->bNumConfigurations); */ - if (index > device_descriptor->bNumConfigurations) { - dbg_ep0 (0, "index too large: %d > %d", index, + if (index >= device_descriptor->bNumConfigurations) { + dbg_ep0 (0, "index too large: %d >= %d", index, device_descriptor-> bNumConfigurations); return -1; @@ -571,14 +571,8 @@ int ep0_recv_setup (struct urb *urb) case USB_REQ_SET_CONFIGURATION: /* c.f. 9.4.7 - the top half of wValue is reserved */ - /* */ - if ((device->configuration = - le16_to_cpu (request->wValue) & 0xFF80) != 0) { - /* c.f. 9.4.7 - zero is the default or addressed state, in our case this */ - /* is the same is configuration zero */ - serial_printf("error setting dev->config to zero!\n"); - device->configuration = 0; /* TBR - ?????? */ - } + device->configuration = le16_to_cpu(request->wValue) & 0xff; + /* reset interface and alternate settings */ device->interface = device->alternate = 0; |