diff options
author | Markus Klotzbuecher <mk@denx.de> | 2008-07-10 10:26:07 +0200 |
---|---|---|
committer | Markus Klotzbuecher <mk@denx.de> | 2008-07-10 10:26:07 +0200 |
commit | 794a5924972fc8073616e98a2668da4a5f9aea90 (patch) | |
tree | dd0db39b3e183b5bcb0300d5377d7a0d5ac5fd0c /drivers | |
parent | f2aeecc320f5b181b30effcaa67683aec8d5a843 (diff) | |
parent | 4188f0491886b3b486164e819c0a83fdb97efd7d (diff) | |
download | u-boot-imx-794a5924972fc8073616e98a2668da4a5f9aea90.zip u-boot-imx-794a5924972fc8073616e98a2668da4a5f9aea90.tar.gz u-boot-imx-794a5924972fc8073616e98a2668da4a5f9aea90.tar.bz2 |
Merge branch 'master' of git://www.denx.de/git/u-boot
Diffstat (limited to 'drivers')
77 files changed, 5005 insertions, 771 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/hwmon/lm75.c b/drivers/hwmon/lm75.c index e29b294..c348517 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -47,6 +47,19 @@ int dtt_read(int sensor, int reg) int dlen; uchar data[2]; +#ifdef CONFIG_DTT_AD7414 + /* + * On AD7414 the first value upon bootup is not read correctly. + * This is most likely because of the 800ms update time of the + * temp register in normal update mode. To get current values + * each time we issue the "dtt" command including upon powerup + * we switch into one-short mode. + * + * Issue one-shot mode command + */ + dtt_write(sensor, DTT_CONFIG, 0x64); +#endif + /* * Validate 'reg' param */ diff --git a/drivers/input/ps2ser.c b/drivers/input/ps2ser.c index 4e304f7..c1741ea 100644 --- a/drivers/input/ps2ser.c +++ b/drivers/input/ps2ser.c @@ -49,7 +49,8 @@ DECLARE_GLOBAL_DATA_PTR; #error CONFIG_PS2SERIAL must be in 1 ... 6 #endif -#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555) +#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ + defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555) #if CONFIG_PS2SERIAL == 1 #define COM_BASE (CFG_CCSRBAR+0x4500) @@ -65,7 +66,9 @@ static int ps2ser_getc_hw(void); static void ps2ser_interrupt(void *dev_id); extern struct serial_state rs_table[]; /* in serial.c */ -#if !defined(CONFIG_MPC5xxx) && !defined(CONFIG_MPC8540) && !defined(CONFIG_MPC8541) && !defined(CONFIG_MPC8555) +#if !defined(CONFIG_MPC5xxx) && !defined(CONFIG_MPC8540) && \ + !defined(CONFIG_MPC8541) && !defined(CONFIG_MPC8548) && \ + !defined(CONFIG_MPC8555) static struct serial_state *state; #endif @@ -120,7 +123,8 @@ int ps2ser_init(void) return (0); } -#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555) +#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ + defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555) int ps2ser_init(void) { NS16550_t com_port = (NS16550_t)COM_BASE; @@ -186,7 +190,8 @@ void ps2ser_putc(int chr) { #ifdef CONFIG_MPC5xxx volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE; -#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555) +#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ + defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555) NS16550_t com_port = (NS16550_t)COM_BASE; #endif #ifdef DEBUG @@ -197,7 +202,8 @@ void ps2ser_putc(int chr) while (!(psc->psc_status & PSC_SR_TXRDY)); psc->psc_buffer_8 = chr; -#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555) +#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ + defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555) while ((com_port->lsr & LSR_THRE) == 0); com_port->thr = chr; #else @@ -211,7 +217,8 @@ static int ps2ser_getc_hw(void) { #ifdef CONFIG_MPC5xxx volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE; -#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555) +#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ + defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555) NS16550_t com_port = (NS16550_t)COM_BASE; #endif int res = -1; @@ -220,7 +227,8 @@ static int ps2ser_getc_hw(void) if (psc->psc_status & PSC_SR_RXRDY) { res = (psc->psc_buffer_8); } -#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555) +#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ + defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555) if (com_port->lsr & LSR_DR) { res = com_port->rbr; } @@ -279,7 +287,8 @@ static void ps2ser_interrupt(void *dev_id) { #ifdef CONFIG_MPC5xxx volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE; -#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555) +#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ + defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555) NS16550_t com_port = (NS16550_t)COM_BASE; #endif int chr; @@ -289,7 +298,8 @@ static void ps2ser_interrupt(void *dev_id) chr = ps2ser_getc_hw(); #ifdef CONFIG_MPC5xxx status = psc->psc_status; -#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555) +#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ + defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555) status = com_port->lsr; #else status = ps2ser_in(UART_IIR); @@ -305,7 +315,8 @@ static void ps2ser_interrupt(void *dev_id) } #ifdef CONFIG_MPC5xxx } while (status & PSC_SR_RXRDY); -#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555) +#elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ + defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555) } while (status & LSR_DR); #else } while (status & UART_IIR_RDI); diff --git a/drivers/misc/fsl_law.c b/drivers/misc/fsl_law.c index dca6a4d..48ece4f 100644 --- a/drivers/misc/fsl_law.c +++ b/drivers/misc/fsl_law.c @@ -27,8 +27,22 @@ #include <asm/fsl_law.h> #include <asm/io.h> +DECLARE_GLOBAL_DATA_PTR; + #define LAWAR_EN 0x80000000 -#define FSL_HW_NUM_LAWS 10 /* number of LAWs in the hw implementation */ +/* number of LAWs in the hw implementation */ +#if defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ + defined(CONFIG_MPC8560) || defined(CONFIG_MPC8555) +#define FSL_HW_NUM_LAWS 8 +#elif defined(CONFIG_MPC8548) || defined(CONFIG_MPC8544) || \ + defined(CONFIG_MPC8568) || \ + defined(CONFIG_MPC8641) || defined(CONFIG_MPC8610) +#define FSL_HW_NUM_LAWS 10 +#elif defined(CONFIG_MPC8572) +#define FSL_HW_NUM_LAWS 12 +#else +#error FSL_HW_NUM_LAWS not defined for this platform +#endif void set_law(u8 idx, phys_addr_t addr, enum law_size sz, enum law_trgt_if id) { @@ -36,18 +50,53 @@ void set_law(u8 idx, phys_addr_t addr, enum law_size sz, enum law_trgt_if id) volatile u32 *lawbar = base + 8 * idx; volatile u32 *lawar = base + 8 * idx + 2; + gd->used_laws |= (1 << idx); + out_be32(lawbar, addr >> 12); out_be32(lawar, LAWAR_EN | ((u32)id << 20) | (u32)sz); return ; } +int set_next_law(phys_addr_t addr, enum law_size sz, enum law_trgt_if id) +{ + u32 idx = ffz(gd->used_laws); + + if (idx >= FSL_HW_NUM_LAWS) + return -1; + + set_law(idx, addr, sz, id); + + return idx; +} + +int set_last_law(phys_addr_t addr, enum law_size sz, enum law_trgt_if id) +{ + u32 idx; + + /* we have no LAWs free */ + if (gd->used_laws == -1) + return -1; + + /* grab the last free law */ + idx = __ilog2(~(gd->used_laws)); + + if (idx >= FSL_HW_NUM_LAWS) + return -1; + + set_law(idx, addr, sz, id); + + return idx; +} + void disable_law(u8 idx) { volatile u32 *base = (volatile u32 *)(CFG_IMMR + 0xc08); volatile u32 *lawbar = base + 8 * idx; volatile u32 *lawar = base + 8 * idx + 2; + gd->used_laws &= ~(1 << idx); + out_be32(lawar, 0); out_be32(lawbar, 0); @@ -75,14 +124,16 @@ void print_laws(void) void init_laws(void) { int i; - u8 law_idx = 0; - for (i = 0; i < num_law_entries; i++) { - if (law_table[i].index != -1) - law_idx = law_table[i].index; + gd->used_laws = ~((1 << FSL_HW_NUM_LAWS) - 1); - set_law(law_idx++, law_table[i].addr, - law_table[i].size, law_table[i].trgt_id); + for (i = 0; i < num_law_entries; i++) { + if (law_table[i].index == -1) + set_next_law(law_table[i].addr, law_table[i].size, + law_table[i].trgt_id); + else + set_law(law_table[i].index, law_table[i].addr, + law_table[i].size, law_table[i].trgt_id); } return ; 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 68ab55f..c0ea97b 100644 --- a/drivers/mtd/cfi_flash.c +++ b/drivers/mtd/cfi_flash.c @@ -76,7 +76,9 @@ #define FLASH_CMD_PROTECT_SET 0x01 #define FLASH_CMD_PROTECT_CLEAR 0xD0 #define FLASH_CMD_CLEAR_STATUS 0x50 +#define FLASH_CMD_READ_STATUS 0x70 #define FLASH_CMD_WRITE_TO_BUFFER 0xE8 +#define FLASH_CMD_WRITE_BUFFER_PROG 0xE9 #define FLASH_CMD_WRITE_BUFFER_CONFIRM 0xD0 #define FLASH_STATUS_DONE 0x80 @@ -136,6 +138,7 @@ #define CFI_CMDSET_MITSU_STANDARD 256 #define CFI_CMDSET_MITSU_EXTENDED 257 #define CFI_CMDSET_SST 258 +#define CFI_CMDSET_INTEL_PROG_REGIONS 512 #ifdef CFG_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */ # undef FLASH_CMD_RESET @@ -298,17 +301,25 @@ static inline void flash_unmap(flash_info_t *info, flash_sect_t sect, /*----------------------------------------------------------------------- * make a proper sized command based on the port and chip widths */ -static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf) +static void flash_make_cmd (flash_info_t * info, ulong cmd, void *cmdbuf) { int i; + int cword_offset; + int cp_offset; + uchar val; uchar *cp = (uchar *) cmdbuf; + for (i = info->portwidth; i > 0; i--){ + cword_offset = (info->portwidth-i)%info->chipwidth; #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) - for (i = info->portwidth; i > 0; i--) + cp_offset = info->portwidth - i; + val = *((uchar*)&cmd + cword_offset); #else - for (i = 1; i <= info->portwidth; i++) + cp_offset = i - 1; + val = *((uchar*)&cmd + sizeof(ulong) - cword_offset - 1); #endif - *cp++ = (i & (info->chipwidth - 1)) ? '\0' : cmd; + cp[cp_offset] = (cword_offset >= sizeof(ulong)) ? 0x00 : val; + } } #ifdef DEBUG @@ -422,7 +433,7 @@ static ulong flash_read_long (flash_info_t * info, flash_sect_t sect, * Write a proper sized command to the correct address */ static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, - uint offset, uchar cmd) + uint offset, ulong cmd) { void *addr; @@ -570,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; @@ -605,6 +612,7 @@ static int flash_is_busy (flash_info_t * info, flash_sect_t sect) int retval; switch (info->vendor) { + case CFI_CMDSET_INTEL_PROG_REGIONS: case CFI_CMDSET_INTEL_STANDARD: case CFI_CMDSET_INTEL_EXTENDED: retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE); @@ -664,6 +672,7 @@ static int flash_full_status_check (flash_info_t * info, flash_sect_t sector, retcode = flash_status_check (info, sector, tout, prompt); switch (info->vendor) { + case CFI_CMDSET_INTEL_PROG_REGIONS: case CFI_CMDSET_INTEL_EXTENDED: case CFI_CMDSET_INTEL_STANDARD: if ((retcode == ERR_OK) @@ -792,6 +801,7 @@ static int flash_write_cfiword (flash_info_t * info, ulong dest, flag = disable_interrupts (); switch (info->vendor) { + case CFI_CMDSET_INTEL_PROG_REGIONS: case CFI_CMDSET_INTEL_EXTENDED: case CFI_CMDSET_INTEL_STANDARD: flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS); @@ -846,6 +856,7 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, int flag = 0; uint offset = 0; unsigned int shift; + uchar write_cmd; switch (info->portwidth) { case FLASH_CFI_8BIT: @@ -900,10 +911,14 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, sector = find_sector (info, dest); switch (info->vendor) { + case CFI_CMDSET_INTEL_PROG_REGIONS: case CFI_CMDSET_INTEL_STANDARD: case CFI_CMDSET_INTEL_EXTENDED: + write_cmd = (info->vendor == CFI_CMDSET_INTEL_PROG_REGIONS) ? + FLASH_CMD_WRITE_BUFFER_PROG : FLASH_CMD_WRITE_TO_BUFFER; flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); - flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER); + flash_write_cmd (info, sector, 0, FLASH_CMD_READ_STATUS); + flash_write_cmd (info, sector, 0, write_cmd); retcode = flash_status_check (info, sector, info->buffer_write_tout, "write to buffer"); @@ -911,7 +926,7 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, /* reduce the number of loops by the width of * the port */ cnt = len >> shift; - flash_write_cmd (info, sector, 0, (uchar) cnt - 1); + flash_write_cmd (info, sector, 0, cnt - 1); while (cnt-- > 0) { switch (info->portwidth) { case FLASH_CFI_8BIT: @@ -1038,6 +1053,7 @@ int flash_erase (flash_info_t * info, int s_first, int s_last) for (sect = s_first; sect <= s_last; sect++) { if (info->protect[sect] == 0) { /* not protected */ switch (info->vendor) { + case CFI_CMDSET_INTEL_PROG_REGIONS: case CFI_CMDSET_INTEL_STANDARD: case CFI_CMDSET_INTEL_EXTENDED: flash_write_cmd (info, sect, 0, @@ -1106,6 +1122,9 @@ void flash_print_info (flash_info_t * info) info->size >> 20, info->sector_count); printf (" "); switch (info->vendor) { + case CFI_CMDSET_INTEL_PROG_REGIONS: + printf ("Intel Prog Regions"); + break; case CFI_CMDSET_INTEL_STANDARD: printf ("Intel Standard"); break; @@ -1496,6 +1515,7 @@ static void flash_read_jedec_ids (flash_info_t * info) info->device_id2 = 0; switch (info->vendor) { + case CFI_CMDSET_INTEL_PROG_REGIONS: case CFI_CMDSET_INTEL_STANDARD: case CFI_CMDSET_INTEL_EXTENDED: cmdset_intel_read_jedec_ids(info); @@ -1550,6 +1570,7 @@ static int flash_detect_legacy(ulong base, int banknum) } switch(info->vendor) { + case CFI_CMDSET_INTEL_PROG_REGIONS: case CFI_CMDSET_INTEL_STANDARD: case CFI_CMDSET_INTEL_EXTENDED: info->cmd_reset = FLASH_CMD_RESET; @@ -1720,6 +1741,8 @@ ulong flash_get_size (ulong base, int banknum) int erase_region_count; struct cfi_qry qry; + memset(&qry, 0, sizeof(qry)); + info->ext_addr = 0; info->cfi_version = 0; #ifdef CFG_FLASH_PROTECTION @@ -1745,6 +1768,7 @@ ulong flash_get_size (ulong base, int banknum) #endif switch (info->vendor) { + case CFI_CMDSET_INTEL_PROG_REGIONS: case CFI_CMDSET_INTEL_STANDARD: case CFI_CMDSET_INTEL_EXTENDED: cmdset_intel_init(info, &qry); @@ -1822,6 +1846,7 @@ ulong flash_get_size (ulong base, int banknum) * supported devices (intel...) */ switch (info->vendor) { + case CFI_CMDSET_INTEL_PROG_REGIONS: case CFI_CMDSET_INTEL_EXTENDED: case CFI_CMDSET_INTEL_STANDARD: info->protect[sect_cnt] = 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/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index 5cc410a..67ae9c8 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -20,112 +20,83 @@ #include <linux/mtd/fsl_upm.h> #include <nand.h> -#define FSL_UPM_MxMR_OP_NO (0 << 28) /* normal operation */ -#define FSL_UPM_MxMR_OP_WA (1 << 28) /* write array */ -#define FSL_UPM_MxMR_OP_RA (2 << 28) /* read array */ -#define FSL_UPM_MxMR_OP_RP (3 << 28) /* run pattern */ +static int fsl_upm_in_pattern; static void fsl_upm_start_pattern(struct fsl_upm *upm, u32 pat_offset) { - out_be32(upm->mxmr, FSL_UPM_MxMR_OP_RP | pat_offset); + clrsetbits_be32(upm->mxmr, MxMR_MAD_MSK, MxMR_OP_RUNP | pat_offset); } static void fsl_upm_end_pattern(struct fsl_upm *upm) { - out_be32(upm->mxmr, FSL_UPM_MxMR_OP_NO); - while (in_be32(upm->mxmr) != FSL_UPM_MxMR_OP_NO) + clrbits_be32(upm->mxmr, MxMR_OP_RUNP); + + while (in_be32(upm->mxmr) & MxMR_OP_RUNP) eieio(); } static void fsl_upm_run_pattern(struct fsl_upm *upm, int width, u32 cmd) { - out_be32(upm->mar, cmd << (32 - width * 8)); - out_8(upm->io_addr, 0x0); -} - -static void fsl_upm_setup(struct fsl_upm *upm) -{ - int i; - - /* write upm array */ - out_be32(upm->mxmr, FSL_UPM_MxMR_OP_WA); - - for (i = 0; i < 64; i++) { - out_be32(upm->mdr, upm->array[i]); + out_be32(upm->mar, cmd << (32 - width)); + switch (width) { + case 8: out_8(upm->io_addr, 0x0); + break; + case 16: + out_be16(upm->io_addr, 0x0); + break; + case 32: + out_be32(upm->io_addr, 0x0); + break; } - - /* normal operation */ - out_be32(upm->mxmr, FSL_UPM_MxMR_OP_NO); - while (in_be32(upm->mxmr) != FSL_UPM_MxMR_OP_NO) - eieio(); } -static void fun_cmdfunc(struct mtd_info *mtd, unsigned command, int column, - int page_addr) +static void nand_hwcontrol (struct mtd_info *mtd, int cmd) { struct nand_chip *chip = mtd->priv; struct fsl_upm_nand *fun = chip->priv; - fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset); - - if (command == NAND_CMD_SEQIN) { - int readcmd; - - if (column >= mtd->oobblock) { - /* OOB area */ - column -= mtd->oobblock; - readcmd = NAND_CMD_READOOB; - } else if (column < 256) { - /* First 256 bytes --> READ0 */ - readcmd = NAND_CMD_READ0; - } else { - column -= 256; - readcmd = NAND_CMD_READ1; - } - fsl_upm_run_pattern(&fun->upm, fun->width, readcmd); + switch (cmd) { + case NAND_CTL_SETCLE: + fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset); + fsl_upm_in_pattern++; + break; + case NAND_CTL_SETALE: + fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset); + fsl_upm_in_pattern++; + break; + case NAND_CTL_CLRCLE: + case NAND_CTL_CLRALE: + fsl_upm_end_pattern(&fun->upm); + fsl_upm_in_pattern--; + break; } +} - fsl_upm_run_pattern(&fun->upm, fun->width, command); - - fsl_upm_end_pattern(&fun->upm); - - fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset); - - if (column != -1) - fsl_upm_run_pattern(&fun->upm, fun->width, column); +static void nand_write_byte(struct mtd_info *mtd, u_char byte) +{ + struct nand_chip *chip = mtd->priv; - if (page_addr != -1) { - fsl_upm_run_pattern(&fun->upm, fun->width, page_addr); - fsl_upm_run_pattern(&fun->upm, fun->width, - (page_addr >> 8) & 0xFF); - if (chip->chipsize > (32 << 20)) { - fsl_upm_run_pattern(&fun->upm, fun->width, - (page_addr >> 16) & 0x0f); - } - } + if (fsl_upm_in_pattern) { + struct fsl_upm_nand *fun = chip->priv; - fsl_upm_end_pattern(&fun->upm); + fsl_upm_run_pattern(&fun->upm, fun->width, byte); - if (fun->wait_pattern) { /* * Some boards/chips needs this. At least on MPC8360E-RDK we * need it. Probably weird chip, because I don't see any need * for this on MPC8555E + Samsung K9F1G08U0A. Usually here are * 0-2 unexpected busy states per block read. */ - while (!fun->dev_ready()) - debug("unexpected busy state\n"); + if (fun->wait_pattern) { + while (!fun->dev_ready()) + debug("unexpected busy state\n"); + } + } else { + out_8(chip->IO_ADDR_W, byte); } } -static void nand_write_byte(struct mtd_info *mtd, u_char byte) -{ - struct nand_chip *chip = mtd->priv; - - out_8(chip->IO_ADDR_W, byte); -} - static u8 nand_read_byte(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; @@ -164,10 +135,6 @@ static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) return 0; } -static void nand_hwcontrol(struct mtd_info *mtd, int cmd) -{ -} - static int nand_dev_ready(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; @@ -178,23 +145,20 @@ static int nand_dev_ready(struct mtd_info *mtd) int fsl_upm_nand_init(struct nand_chip *chip, struct fsl_upm_nand *fun) { - /* yet only 8 bit accessors implemented */ - if (fun->width != 1) + if (fun->width != 8 && fun->width != 16 && fun->width != 32) return -ENOSYS; - fsl_upm_setup(&fun->upm); - chip->priv = fun; chip->chip_delay = fun->chip_delay; chip->eccmode = NAND_ECC_SOFT; - chip->cmdfunc = fun_cmdfunc; chip->hwcontrol = nand_hwcontrol; chip->read_byte = nand_read_byte; chip->read_buf = nand_read_buf; chip->write_byte = nand_write_byte; chip->write_buf = nand_write_buf; chip->verify_buf = nand_verify_buf; - chip->dev_ready = nand_dev_ready; + if (fun->dev_ready) + chip->dev_ready = nand_dev_ready; return 0; } diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 5aef31c..6416d15 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -113,18 +113,22 @@ static struct nand_oobinfo nand_oob_64 = { .oobfree = { {2, 38} } }; -/* This is used for padding purposes in nand_write_oob */ -static u_char ffchars[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +static struct nand_oobinfo nand_oob_128 = { + .useecc = MTD_NANDECC_AUTOPLACE, + .eccbytes = 48, + .eccpos = { + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127}, + .oobfree = { {2, 78} } }; +/* This is used for padding purposes in nand_write_oob */ +static u_char *ffchars; + /* * NAND low-level MTD interface functions */ @@ -193,6 +197,10 @@ static void nand_release_device (struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; this->select_chip(mtd, -1); /* De-select the NAND device */ + if (ffchars) { + kfree(ffchars); + ffchars = NULL; + } } #endif @@ -891,7 +899,7 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa u_char *oob_buf, struct nand_oobinfo *oobsel, int cached) { int i, status; - u_char ecc_code[32]; + u_char ecc_code[NAND_MAX_OOBSIZE]; int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; uint *oob_config = oobsel->eccpos; int datidx = 0, eccidx = 0, eccsteps = this->eccsteps; @@ -954,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 { @@ -1002,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; @@ -1010,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; @@ -1021,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 { @@ -1034,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; } } @@ -1112,8 +1130,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0; struct nand_chip *this = mtd->priv; u_char *data_poi, *oob_data = oob_buf; - u_char ecc_calc[32]; - u_char ecc_code[32]; + u_char ecc_calc[NAND_MAX_OOBSIZE]; + u_char ecc_code[NAND_MAX_OOBSIZE]; int eccmode, eccsteps; unsigned *oob_config; int datidx; @@ -1123,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; } @@ -1244,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++; } @@ -1283,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++; } } @@ -1380,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); @@ -1394,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; } @@ -1480,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; } @@ -1618,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; } @@ -1687,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 */ @@ -1711,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; @@ -1744,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 */ @@ -1769,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); @@ -1783,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; } @@ -1811,6 +1843,16 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * if (NAND_MUST_PAD(this)) { /* Write out desired data */ this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page & this->pagemask); + if (!ffchars) { + if (!(ffchars = kmalloc (mtd->oobsize, GFP_KERNEL))) { + MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " + "No memory for padding array, " + "need %d bytes", mtd->oobsize); + ret = -ENOMEM; + goto out; + } + memset(ffchars, 0xff, mtd->oobsize); + } /* prepad 0xff for partial programming */ this->write_buf(mtd, ffchars, column); /* write data */ @@ -1830,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; } @@ -1842,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; } @@ -1902,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; } @@ -2100,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; } @@ -2139,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; } @@ -2169,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; @@ -2212,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); @@ -2479,6 +2529,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips) case 64: this->autooob = &nand_oob_64; break; + case 128: + this->autooob = &nand_oob_128; + break; default: printk (KERN_WARNING "No oob scheme defined for oobsize %d\n", mtd->oobsize); 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 6c5624a..c82f77b 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -153,6 +153,13 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts) priv_nand->bbt = NULL; } + if (erase_length < meminfo->erasesize) { + printf("Warning: Erase size 0x%08x smaller than one " \ + "erase block 0x%08x\n",erase_length, meminfo->erasesize); + printf(" Erasing 0x%08x instead\n", meminfo->erasesize); + erase_length = meminfo->erasesize; + } + for (; erase.addr < opts->offset + erase_length; erase.addr += meminfo->erasesize) { 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/mtd/spi/Makefile b/drivers/mtd/spi/Makefile new file mode 100644 index 0000000..af6af97 --- /dev/null +++ b/drivers/mtd/spi/Makefile @@ -0,0 +1,47 @@ +# +# (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)libspi_flash.a + +COBJS-$(CONFIG_SPI_FLASH) += spi_flash.o +COBJS-$(CONFIG_SPI_FLASH_ATMEL) += atmel.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/mtd/spi/atmel.c b/drivers/mtd/spi/atmel.c new file mode 100644 index 0000000..fb7a4a9 --- /dev/null +++ b/drivers/mtd/spi/atmel.c @@ -0,0 +1,362 @@ +/* + * Atmel SPI DataFlash support + * + * Copyright (C) 2008 Atmel Corporation + */ +#define DEBUG +#include <common.h> +#include <malloc.h> +#include <spi_flash.h> + +#include "spi_flash_internal.h" + +/* AT45-specific commands */ +#define CMD_AT45_READ_STATUS 0xd7 +#define CMD_AT45_ERASE_PAGE 0x81 +#define CMD_AT45_LOAD_PROG_BUF1 0x82 +#define CMD_AT45_LOAD_BUF1 0x84 +#define CMD_AT45_LOAD_PROG_BUF2 0x85 +#define CMD_AT45_LOAD_BUF2 0x87 +#define CMD_AT45_PROG_BUF1 0x88 +#define CMD_AT45_PROG_BUF2 0x89 + +/* AT45 status register bits */ +#define AT45_STATUS_P2_PAGE_SIZE (1 << 0) +#define AT45_STATUS_READY (1 << 7) + +/* DataFlash family IDs, as obtained from the second idcode byte */ +#define DF_FAMILY_AT26F 0 +#define DF_FAMILY_AT45 1 +#define DF_FAMILY_AT26DF 2 /* AT25DF and AT26DF */ + +struct atmel_spi_flash_params { + u8 idcode1; + /* Log2 of page size in power-of-two mode */ + u8 l2_page_size; + u8 pages_per_block; + u8 blocks_per_sector; + u8 nr_sectors; + const char *name; +}; + +struct atmel_spi_flash { + const struct atmel_spi_flash_params *params; + struct spi_flash flash; +}; + +static inline struct atmel_spi_flash * +to_atmel_spi_flash(struct spi_flash *flash) +{ + return container_of(flash, struct atmel_spi_flash, flash); +} + +static const struct atmel_spi_flash_params atmel_spi_flash_table[] = { + { + .idcode1 = 0x28, + .l2_page_size = 10, + .pages_per_block = 8, + .blocks_per_sector = 32, + .nr_sectors = 32, + .name = "AT45DB642D", + }, +}; + +static int at45_wait_ready(struct spi_flash *flash, unsigned long timeout) +{ + struct spi_slave *spi = flash->spi; + unsigned long timebase; + int ret; + u8 cmd = CMD_AT45_READ_STATUS; + u8 status; + + timebase = get_timer(0); + + ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); + if (ret) + return -1; + + do { + ret = spi_xfer(spi, 8, NULL, &status, 0); + if (ret) + return -1; + + if (status & AT45_STATUS_READY) + break; + } while (get_timer(timebase) < timeout); + + /* Deactivate CS */ + spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); + + if (status & AT45_STATUS_READY) + return 0; + + /* Timed out */ + return -1; +} + +/* + * Assemble the address part of a command for AT45 devices in + * non-power-of-two page size mode. + */ +static void at45_build_address(struct atmel_spi_flash *asf, u8 *cmd, u32 offset) +{ + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + unsigned int page_shift; + + /* + * The "extra" space per page is the power-of-two page size + * divided by 32. + */ + page_shift = asf->params->l2_page_size; + page_size = (1 << page_shift) + (1 << (page_shift - 5)); + page_shift++; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + cmd[0] = page_addr >> (16 - page_shift); + cmd[1] = page_addr << (page_shift - 8) | (byte_addr >> 8); + cmd[2] = byte_addr; +} + +static int dataflash_read_fast_p2(struct spi_flash *flash, + u32 offset, size_t len, void *buf) +{ + u8 cmd[5]; + + cmd[0] = CMD_READ_ARRAY_FAST; + cmd[1] = offset >> 16; + cmd[2] = offset >> 8; + cmd[3] = offset; + cmd[4] = 0x00; + + return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len); +} + +static int dataflash_read_fast_at45(struct spi_flash *flash, + u32 offset, size_t len, void *buf) +{ + struct atmel_spi_flash *asf = to_atmel_spi_flash(flash); + u8 cmd[5]; + + cmd[0] = CMD_READ_ARRAY_FAST; + at45_build_address(asf, cmd + 1, offset); + cmd[4] = 0x00; + + return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len); +} + +static int dataflash_write_at45(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct atmel_spi_flash *asf = to_atmel_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + unsigned int page_shift; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_shift = asf->params->l2_page_size; + page_size = (1 << page_shift) + (1 << (page_shift - 5)); + page_shift++; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: Unable to claim SPI bus\n"); + return ret; + } + + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + /* Use the same address bits for both commands */ + cmd[0] = CMD_AT45_LOAD_BUF1; + cmd[1] = page_addr >> (16 - page_shift); + cmd[2] = page_addr << (page_shift - 8) | (byte_addr >> 8); + cmd[3] = byte_addr; + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + debug("SF: Loading AT45 buffer failed\n"); + goto out; + } + + cmd[0] = CMD_AT45_PROG_BUF1; + ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0); + if (ret < 0) { + debug("SF: AT45 page programming failed\n"); + goto out; + } + + ret = at45_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret < 0) { + debug("SF: AT45 page programming timed out\n"); + goto out; + } + + page_addr++; + byte_addr = 0; + } + + debug("SF: AT45: Successfully programmed %u bytes @ 0x%x\n", + len, offset); + ret = 0; + +out: + spi_release_bus(flash->spi); + return ret; +} + +int dataflash_erase_at45(struct spi_flash *flash, u32 offset, size_t len) +{ + struct atmel_spi_flash *asf = to_atmel_spi_flash(flash); + unsigned long page_addr; + unsigned long page_size; + unsigned int page_shift; + size_t actual; + int ret; + u8 cmd[4]; + + /* + * TODO: This function currently uses page erase only. We can + * probably speed things up by using block and/or sector erase + * when possible. + */ + + page_shift = asf->params->l2_page_size; + page_size = (1 << page_shift) + (1 << (page_shift - 5)); + page_shift++; + page_addr = offset / page_size; + + if (offset % page_size || len % page_size) { + debug("SF: Erase offset/length not multiple of page size\n"); + return -1; + } + + cmd[0] = CMD_AT45_ERASE_PAGE; + cmd[3] = 0x00; + + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: Unable to claim SPI bus\n"); + return ret; + } + + for (actual = 0; actual < len; actual += page_size) { + cmd[1] = page_addr >> (16 - page_shift); + cmd[2] = page_addr << (page_shift - 8); + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0); + if (ret < 0) { + debug("SF: AT45 page erase failed\n"); + goto out; + } + + ret = at45_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); + if (ret < 0) { + debug("SF: AT45 page erase timed out\n"); + goto out; + } + + page_addr++; + } + + debug("SF: AT45: Successfully erased %u bytes @ 0x%x\n", + len, offset); + ret = 0; + +out: + spi_release_bus(flash->spi); + return ret; +} + +struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode) +{ + const struct atmel_spi_flash_params *params; + unsigned long page_size; + unsigned int family; + struct atmel_spi_flash *asf; + unsigned int i; + int ret; + u8 status; + + for (i = 0; i < ARRAY_SIZE(atmel_spi_flash_table); i++) { + params = &atmel_spi_flash_table[i]; + if (params->idcode1 == idcode[1]) + break; + } + + if (i == ARRAY_SIZE(atmel_spi_flash_table)) { + debug("SF: Unsupported DataFlash ID %02x\n", + idcode[1]); + return NULL; + } + + asf = malloc(sizeof(struct atmel_spi_flash)); + if (!asf) { + debug("SF: Failed to allocate memory\n"); + return NULL; + } + + asf->params = params; + asf->flash.spi = spi; + asf->flash.name = params->name; + + /* Assuming power-of-two page size initially. */ + page_size = 1 << params->l2_page_size; + + family = idcode[1] >> 5; + + switch (family) { + case DF_FAMILY_AT45: + /* + * AT45 chips have configurable page size. The status + * register indicates which configuration is active. + */ + ret = spi_flash_cmd(spi, CMD_AT45_READ_STATUS, &status, 1); + if (ret) + goto err; + + debug("SF: AT45 status register: %02x\n", status); + + if (!(status & AT45_STATUS_P2_PAGE_SIZE)) { + asf->flash.read = dataflash_read_fast_at45; + asf->flash.write = dataflash_write_at45; + asf->flash.erase = dataflash_erase_at45; + page_size += 1 << (params->l2_page_size - 5); + } else { + asf->flash.read = dataflash_read_fast_p2; + } + + break; + + case DF_FAMILY_AT26F: + case DF_FAMILY_AT26DF: + asf->flash.read = dataflash_read_fast_p2; + break; + + default: + debug("SF: Unsupported DataFlash family %u\n", family); + goto err; + } + + asf->flash.size = page_size * params->pages_per_block + * params->blocks_per_sector + * params->nr_sectors; + + debug("SF: Detected %s with page size %u, total %u bytes\n", + params->name, page_size, asf->flash.size); + + return &asf->flash; + +err: + free(asf); + return NULL; +} diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c new file mode 100644 index 0000000..d581cb3 --- /dev/null +++ b/drivers/mtd/spi/spi_flash.c @@ -0,0 +1,162 @@ +/* + * SPI flash interface + * + * Copyright (C) 2008 Atmel Corporation + */ +#define DEBUG +#include <common.h> +#include <malloc.h> +#include <spi.h> +#include <spi_flash.h> + +#include "spi_flash_internal.h" + +int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len) +{ + unsigned long flags = SPI_XFER_BEGIN; + int ret; + + if (len == 0) + flags |= SPI_XFER_END; + + ret = spi_xfer(spi, 8, &cmd, NULL, flags); + if (ret) { + debug("SF: Failed to send command %02x: %d\n", cmd, ret); + return ret; + } + + if (len) { + ret = spi_xfer(spi, len * 8, NULL, response, SPI_XFER_END); + if (ret) + debug("SF: Failed to read response (%zu bytes): %d\n", + len, ret); + } + + return ret; +} + +int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) +{ + unsigned long flags = SPI_XFER_BEGIN; + int ret; + + if (data_len == 0) + flags |= SPI_XFER_END; + + ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags); + if (ret) { + debug("SF: Failed to send read command (%zu bytes): %d\n", + cmd_len, ret); + } else if (data_len != 0) { + ret = spi_xfer(spi, data_len * 8, NULL, data, SPI_XFER_END); + if (ret) + debug("SF: Failed to read %zu bytes of data: %d\n", + data_len, ret); + } + + return ret; +} + +int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, + const void *data, size_t data_len) +{ + unsigned long flags = SPI_XFER_BEGIN; + int ret; + + if (data_len == 0) + flags |= SPI_XFER_END; + + ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags); + if (ret) { + debug("SF: Failed to send read command (%zu bytes): %d\n", + cmd_len, ret); + } else if (data_len != 0) { + ret = spi_xfer(spi, data_len * 8, data, NULL, SPI_XFER_END); + if (ret) + debug("SF: Failed to read %zu bytes of data: %d\n", + data_len, ret); + } + + return ret; +} + + +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) +{ + struct spi_slave *spi = flash->spi; + int ret; + + spi_claim_bus(spi); + ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); + spi_release_bus(spi); + + return ret; +} + +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode) +{ + struct spi_slave *spi; + struct spi_flash *flash; + int ret; + u8 idcode[3]; + + spi = spi_setup_slave(bus, cs, max_hz, spi_mode); + if (!spi) { + debug("SF: Failed to set up slave\n"); + return NULL; + } + + ret = spi_claim_bus(spi); + if (ret) { + debug("SF: Failed to claim SPI bus: %d\n", ret); + goto err_claim_bus; + } + + /* Read the ID codes */ + ret = spi_flash_cmd(spi, CMD_READ_ID, &idcode, sizeof(idcode)); + if (ret) + goto err_read_id; + + debug("SF: Got idcode %02x %02x %02x\n", idcode[0], + idcode[1], idcode[2]); + + switch (idcode[0]) { +#ifdef CONFIG_SPI_FLASH_SPANSION + case 0x01: + flash = spi_flash_probe_spansion(spi, idcode); + break; +#endif +#ifdef CONFIG_SPI_FLASH_ATMEL + case 0x1F: + flash = spi_flash_probe_atmel(spi, idcode); + break; +#endif + default: + debug("SF: Unsupported manufacturer %02X\n", idcode[0]); + flash = NULL; + break; + } + + if (!flash) + goto err_manufacturer_probe; + + spi_release_bus(spi); + + return flash; + +err_manufacturer_probe: +err_read_id: + spi_release_bus(spi); +err_claim_bus: + spi_free_slave(spi); + return NULL; +} + +void spi_flash_free(struct spi_flash *flash) +{ + spi_free_slave(flash->spi); + free(flash); +} diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h new file mode 100644 index 0000000..1438050 --- /dev/null +++ b/drivers/mtd/spi/spi_flash_internal.h @@ -0,0 +1,45 @@ +/* + * SPI flash internal definitions + * + * Copyright (C) 2008 Atmel Corporation + */ + +/* Common parameters */ +#define SPI_FLASH_PROG_TIMEOUT ((10 * CFG_HZ) / 1000) +#define SPI_FLASH_PAGE_ERASE_TIMEOUT ((50 * CFG_HZ) / 1000) +#define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CFG_HZ) + +/* Common commands */ +#define CMD_READ_ID 0x9f + +#define CMD_READ_ARRAY_SLOW 0x03 +#define CMD_READ_ARRAY_FAST 0x0b +#define CMD_READ_ARRAY_LEGACY 0xe8 + +/* Send a single-byte command to the device and read the response */ +int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); + +/* + * Send a multi-byte command to the device and read the response. Used + * for flash array reads, etc. + */ +int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len); + +/* + * Send a multi-byte command to the device followed by (optional) + * data. Used for programming the flash array, etc. + */ +int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, + const void *data, size_t data_len); + +/* + * Same as spi_flash_cmd_read() except it also claims/releases the SPI + * bus. Used as common part of the ->read() operation. + */ +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len); + +/* Manufacturer-specific probe functions */ +struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode); diff --git a/drivers/net/3c589.c b/drivers/net/3c589.c index 3f1e770..0cf8dff 100644 --- a/drivers/net/3c589.c +++ b/drivers/net/3c589.c @@ -26,8 +26,6 @@ #include <command.h> #include <net.h> -#ifdef CONFIG_DRIVER_3C589 - #include "3c589.h" @@ -514,6 +512,3 @@ int eth_send(volatile void *packet, int length) { return length; } - - -#endif /* CONFIG_DRIVER_3C589 */ diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 5b031c9..bcf31cb 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -25,47 +25,48 @@ include $(TOPDIR)/config.mk LIB := $(obj)libnet.a -COBJS-y += 3c589.o -COBJS-y += bcm570x.o bcm570x_autoneg.o 5701rls.o +COBJS-$(CONFIG_DRIVER_3C589) += 3c589.o +COBJS-$(CONFIG_BCM570x) += bcm570x.o bcm570x_autoneg.o 5701rls.o COBJS-$(CONFIG_BFIN_MAC) += bfin_mac.o -COBJS-y += cs8900.o -COBJS-y += dc2114x.o -COBJS-y += dm9000x.o -COBJS-y += e1000.o -COBJS-y += eepro100.o -COBJS-y += enc28j60.o -COBJS-y += fsl_mcdmafec.o +COBJS-$(CONFIG_DRIVER_CS8900) += cs8900.o +COBJS-$(CONFIG_TULIP) += dc2114x.o +COBJS-$(CONFIG_DRIVER_DM9000) += dm9000x.o +COBJS-$(CONFIG_E1000) += e1000.o +COBJS-$(CONFIG_EEPRO100) += eepro100.o +COBJS-$(CONFIG_ENC28J60) += enc28j60.o +COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o COBJS-$(CONFIG_GRETH) += greth.o -COBJS-y += inca-ip_sw.o -COBJS-y += ks8695eth.o -COBJS-y += lan91c96.o -COBJS-y += macb.o -COBJS-y += mcffec.o -COBJS-y += natsemi.o +COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o +COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o +COBJS-$(CONFIG_DRIVER_LAN91C96) += lan91c96.o +COBJS-$(CONFIG_MACB) += macb.o +COBJS-$(CONFIG_MCFFEC) += mcffec.o +COBJS-$(CONFIG_NATSEMI) += natsemi.o ifeq ($(CONFIG_DRIVER_NE2000),y) COBJS-y += ne2000.o COBJS-$(CONFIG_DRIVER_AX88796L) += ax88796.o endif -COBJS-y += netarm_eth.o -COBJS-y += netconsole.o -COBJS-y += ns7520_eth.o -COBJS-y += ns8382x.o -COBJS-y += ns9750_eth.o -COBJS-y += pcnet.o -COBJS-y += plb2800_eth.o -COBJS-y += rtl8019.o -COBJS-y += rtl8139.o -COBJS-y += rtl8169.o -COBJS-y += s3c4510b_eth.o -COBJS-y += smc91111.o -COBJS-y += smc911x.o -COBJS-y += tigon3.o -COBJS-y += tsec.o -COBJS-y += tsi108_eth.o -COBJS-y += uli526x.o -COBJS-y += vsc7385.o +COBJS-$(CONFIG_DRIVER_NETARMETH) += netarm_eth.o +COBJS-$(CONFIG_NETCONSOLE) += netconsole.o +COBJS-$(CONFIG_DRIVER_NS7520_ETHERNET) += ns7520_eth.o +COBJS-$(CONFIG_NS8382X) += ns8382x.o +COBJS-$(CONFIG_DRIVER_NS9750_ETHERNET) += ns9750_eth.o +COBJS-$(CONFIG_PCNET) += pcnet.o +COBJS-$(CONFIG_PLB2800_ETHER) += plb2800_eth.o +COBJS-$(CONFIG_DRIVER_RTL8019) += rtl8019.o +COBJS-$(CONFIG_RTL8139) += rtl8139.o +COBJS-$(CONFIG_RTL8169) += rtl8169.o +COBJS-$(CONFIG_DRIVER_S3C4510_ETH) += s3c4510b_eth.o +COBJS-$(CONFIG_DRIVER_SMC91111) += smc91111.o +COBJS-$(CONFIG_DRIVER_SMC911X) += smc911x.o +COBJS-$(CONFIG_TIGON3) += tigon3.o bcm570x_autoneg.o 5701rls.o +COBJS-$(CONFIG_TSEC_ENET) += tsec.o +COBJS-$(CONFIG_TSI108_ETH) += tsi108_eth.o +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/bcm570x.c b/drivers/net/bcm570x.c index 5ad31d1..6b28b95 100644 --- a/drivers/net/bcm570x.c +++ b/drivers/net/bcm570x.c @@ -6,9 +6,6 @@ #include <common.h> -#if defined(CONFIG_CMD_NET) \ - && (!defined(CONFIG_NET_MULTI)) && defined(CONFIG_BCM570x) - #ifdef CONFIG_BMW #include <mpc824x.h> #endif @@ -1599,5 +1596,3 @@ PQQ_ENTRY QQ_GetTail (PQQ_CONTAINER pQueue, unsigned int Idx) return pQueue->Array[Idx]; } - -#endif diff --git a/drivers/net/cs8900.c b/drivers/net/cs8900.c index 458b517..ae1983a 100644 --- a/drivers/net/cs8900.c +++ b/drivers/net/cs8900.c @@ -41,10 +41,6 @@ #include "cs8900.h" #include <net.h> -#ifdef CONFIG_DRIVER_CS8900 - -#if defined(CONFIG_CMD_NET) - #undef DEBUG /* packet page register access functions */ @@ -315,7 +311,3 @@ int cs8900_e2prom_write(unsigned char addr, unsigned short value) return 0; } - -#endif /* CONFIG_CMD_NET */ - -#endif /* CONFIG_DRIVER_CS8900 */ diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c index 1d728d8..8117239 100644 --- a/drivers/net/dc2114x.c +++ b/drivers/net/dc2114x.c @@ -19,10 +19,6 @@ */ #include <common.h> - -#if defined(CONFIG_CMD_NET) \ - && defined(CONFIG_NET_MULTI) && defined(CONFIG_TULIP) - #include <malloc.h> #include <net.h> #include <pci.h> @@ -766,5 +762,3 @@ static void update_srom(struct eth_device *dev, bd_t *bis) } } #endif /* UPDATE_SROM */ - -#endif diff --git a/drivers/net/dm9000x.c b/drivers/net/dm9000x.c index 01e2f14..844fb76 100644 --- a/drivers/net/dm9000x.c +++ b/drivers/net/dm9000x.c @@ -36,7 +36,24 @@ v1.2 03/18/2003 Weilun Huang <weilun_huang@davicom.com.tw>: -------------------------------------- - 12/15/2003 Initial port to u-boot by Sascha Hauer <saschahauer@web.de> + 12/15/2003 Initial port to u-boot by + Sascha Hauer <saschahauer@web.de> + + 06/03/2008 Remy Bohmer <linux@bohmer.net> + - Fixed the driver to work with DM9000A. + (check on ISR receive status bit before reading the + FIFO as described in DM9000 programming guide and + application notes) + - Added autodetect of databus width. + - Made debug code compile again. + - Adapt eth_send such that it matches the DM9000* + application notes. Needed to make it work properly + for DM9000A. + - Adapted reset procedure to match DM9000 application + notes (i.e. double reset) + - some minor code cleanups + These changes are tested with DM9000{A,EP,E} together + with a 200MHz Atmel AT91SAM92161 core TODO: Homerun NIC and longrun NIC are not functional, only internal at the moment. @@ -47,8 +64,6 @@ TODO: Homerun NIC and longrun NIC are not functional, only internal at the #include <net.h> #include <asm/io.h> -#ifdef CONFIG_DRIVER_DM9000 - #include "dm9000x.h" /* Board/System/Debug information/definition ---------------- */ @@ -59,10 +74,22 @@ TODO: Homerun NIC and longrun NIC are not functional, only internal at the /* #define CONFIG_DM9000_DEBUG */ #ifdef CONFIG_DM9000_DEBUG -#define DM9000_DBG(fmt,args...) printf(fmt ,##args) -#else /* */ +#define DM9000_DBG(fmt,args...) printf(fmt, ##args) +#define DM9000_DMP_PACKET(func,packet,length) \ + do { \ + int i; \ + printf(func ": length: %d\n", length); \ + for (i = 0; i < length; i++) { \ + if (i % 8 == 0) \ + printf("\n%s: %02x: ", func, i); \ + printf("%02x ", ((unsigned char *) packet)[i]); \ + } printf("\n"); \ + } while(0) +#else #define DM9000_DBG(fmt,args...) -#endif /* */ +#define DM9000_DMP_PACKET(func,packet,length) +#endif + enum DM9000_PHY_mode { DM9000_10MHD = 0, DM9000_100MHD = 1, DM9000_10MFD = 4, DM9000_100MFD = 5, DM9000_AUTO = 8, DM9000_1M_HPNA = 0x10 @@ -84,8 +111,11 @@ typedef struct board_info { u8 device_wait_reset; /* device state */ u8 nic_type; /* NIC type */ unsigned char srom[128]; + void (*outblk)(volatile void *data_ptr, int count); + void (*inblk)(void *data_ptr, int count); + void (*rx_status)(u16 *RxStatus, u16 *RxLen); } board_info_t; -board_info_t dmfe_info; +static board_info_t dm9000_info; /* For module input parameter */ static int media_mode = DM9000_AUTO; @@ -124,10 +154,85 @@ dump_regs(void) DM9000_DBG("TSRII (0x04): %02x\n", DM9000_ior(4)); DM9000_DBG("RCR (0x05): %02x\n", DM9000_ior(5)); DM9000_DBG("RSR (0x06): %02x\n", DM9000_ior(6)); - DM9000_DBG("ISR (0xFE): %02x\n", DM9000_ior(ISR)); + DM9000_DBG("ISR (0xFE): %02x\n", DM9000_ior(DM9000_ISR)); DM9000_DBG("\n"); } -#endif /* */ +#endif + +static void dm9000_outblk_8bit(volatile void *data_ptr, int count) +{ + int i; + for (i = 0; i < count; i++) + DM9000_outb((((u8 *) data_ptr)[i] & 0xff), DM9000_DATA); +} + +static void dm9000_outblk_16bit(volatile void *data_ptr, int count) +{ + int i; + u32 tmplen = (count + 1) / 2; + + for (i = 0; i < tmplen; i++) + DM9000_outw(((u16 *) data_ptr)[i], DM9000_DATA); +} +static void dm9000_outblk_32bit(volatile void *data_ptr, int count) +{ + int i; + u32 tmplen = (count + 3) / 4; + + for (i = 0; i < tmplen; i++) + DM9000_outl(((u32 *) data_ptr)[i], DM9000_DATA); +} + +static void dm9000_inblk_8bit(void *data_ptr, int count) +{ + int i; + for (i = 0; i < count; i++) + ((u8 *) data_ptr)[i] = DM9000_inb(DM9000_DATA); +} + +static void dm9000_inblk_16bit(void *data_ptr, int count) +{ + int i; + u32 tmplen = (count + 1) / 2; + + for (i = 0; i < tmplen; i++) + ((u16 *) data_ptr)[i] = DM9000_inw(DM9000_DATA); +} +static void dm9000_inblk_32bit(void *data_ptr, int count) +{ + int i; + u32 tmplen = (count + 3) / 4; + + for (i = 0; i < tmplen; i++) + ((u32 *) data_ptr)[i] = DM9000_inl(DM9000_DATA); +} + +static void dm9000_rx_status_32bit(u16 *RxStatus, u16 *RxLen) +{ + u32 tmpdata; + + DM9000_outb(DM9000_MRCMD, DM9000_IO); + + tmpdata = DM9000_inl(DM9000_DATA); + *RxStatus = tmpdata; + *RxLen = tmpdata >> 16; +} + +static void dm9000_rx_status_16bit(u16 *RxStatus, u16 *RxLen) +{ + DM9000_outb(DM9000_MRCMD, DM9000_IO); + + *RxStatus = DM9000_inw(DM9000_DATA); + *RxLen = DM9000_inw(DM9000_DATA); +} + +static void dm9000_rx_status_8bit(u16 *RxStatus, u16 *RxLen) +{ + DM9000_outb(DM9000_MRCMD, DM9000_IO); + + *RxStatus = DM9000_inb(DM9000_DATA) + (DM9000_inb(DM9000_DATA) << 8); + *RxLen = DM9000_inb(DM9000_DATA) + (DM9000_inb(DM9000_DATA) << 8); +} /* Search DM9000 board, allocate space and register it @@ -236,7 +341,7 @@ program_dm9802(void) static void identify_nic(void) { - struct board_info *db = &dmfe_info; /* Point a board information structure */ + struct board_info *db = &dm9000_info; u16 phy_reg3; DM9000_iow(DM9000_NCR, NCR_EXT_PHY); phy_reg3 = phy_read(3); @@ -263,9 +368,35 @@ identify_nic(void) static void dm9000_reset(void) { - DM9000_DBG("resetting\n"); - DM9000_iow(DM9000_NCR, NCR_RST); - udelay(1000); /* delay 1ms */ + DM9000_DBG("resetting DM9000\n"); + + /* Reset DM9000, + see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 */ + + /* DEBUG: Make all GPIO pins outputs */ + DM9000_iow(DM9000_GPCR, 0x0F); + /* Step 1: Power internal PHY by writing 0 to GPIO0 pin */ + DM9000_iow(DM9000_GPR, 0); + /* Step 2: Software reset */ + DM9000_iow(DM9000_NCR, 3); + + do { + DM9000_DBG("resetting the DM9000, 1st reset\n"); + udelay(25); /* Wait at least 20 us */ + } while (DM9000_ior(DM9000_NCR) & 1); + + DM9000_iow(DM9000_NCR, 0); + DM9000_iow(DM9000_NCR, 3); /* Issue a second reset */ + + do { + DM9000_DBG("resetting the DM9000, 2nd reset\n"); + udelay(25); /* Wait at least 20 us */ + } while (DM9000_ior(DM9000_NCR) & 1); + + /* Check whether the ethernet controller is present */ + if ((DM9000_ior(DM9000_PIDL) != 0x0) || + (DM9000_ior(DM9000_PIDH) != 0x90)) + printf("ERROR: resetting DM9000 -> not responding\n"); } /* Initilize dm9000 board @@ -274,12 +405,46 @@ int eth_init(bd_t * bd) { int i, oft, lnk; + u8 io_mode; + struct board_info *db = &dm9000_info; + DM9000_DBG("eth_init()\n"); /* RESET device */ dm9000_reset(); dm9000_probe(); + /* Auto-detect 8/16/32 bit mode, ISR Bit 6+7 indicate bus width */ + io_mode = DM9000_ior(DM9000_ISR) >> 6; + + switch (io_mode) { + case 0x0: /* 16-bit mode */ + printf("DM9000: running in 16 bit mode\n"); + db->outblk = dm9000_outblk_16bit; + db->inblk = dm9000_inblk_16bit; + db->rx_status = dm9000_rx_status_16bit; + break; + case 0x01: /* 32-bit mode */ + printf("DM9000: running in 32 bit mode\n"); + db->outblk = dm9000_outblk_32bit; + db->inblk = dm9000_inblk_32bit; + db->rx_status = dm9000_rx_status_32bit; + break; + case 0x02: /* 8 bit mode */ + printf("DM9000: running in 8 bit mode\n"); + db->outblk = dm9000_outblk_8bit; + db->inblk = dm9000_inblk_8bit; + db->rx_status = dm9000_rx_status_8bit; + break; + default: + /* Assume 8 bit mode, will probably not work anyway */ + printf("DM9000: Undefined IO-mode:0x%x\n", io_mode); + db->outblk = dm9000_outblk_8bit; + db->inblk = dm9000_inblk_8bit; + db->rx_status = dm9000_rx_status_8bit; + break; + } + /* NIC Type: FASTETHER, HOMERUN, LONGRUN */ identify_nic(); @@ -289,19 +454,28 @@ eth_init(bd_t * bd) /* Set PHY */ set_PHY_mode(); - /* Program operating register */ - DM9000_iow(DM9000_NCR, 0x0); /* only intern phy supported by now */ - DM9000_iow(DM9000_TCR, 0); /* TX Polling clear */ - DM9000_iow(DM9000_BPTR, 0x3f); /* Less 3Kb, 200us */ - DM9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8)); /* Flow Control : High/Low Water */ - DM9000_iow(DM9000_FCR, 0x0); /* SH FIXME: This looks strange! Flow Control */ - DM9000_iow(DM9000_SMCR, 0); /* Special Mode */ - DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END); /* clear TX status */ - DM9000_iow(DM9000_ISR, 0x0f); /* Clear interrupt status */ + /* Program operating register, only intern phy supported by now */ + DM9000_iow(DM9000_NCR, 0x0); + /* TX Polling clear */ + DM9000_iow(DM9000_TCR, 0); + /* Less 3Kb, 200us */ + DM9000_iow(DM9000_BPTR, 0x3f); + /* Flow Control : High/Low Water */ + DM9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8)); + /* SH FIXME: This looks strange! Flow Control */ + DM9000_iow(DM9000_FCR, 0x0); + /* Special Mode */ + DM9000_iow(DM9000_SMCR, 0); + /* clear TX status */ + DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END); + /* Clear interrupt status */ + DM9000_iow(DM9000_ISR, 0x0f); /* Set Node address */ +#ifndef CONFIG_AT91SAM9261EK for (i = 0; i < 6; i++) ((u16 *) bd->bi_enetaddr)[i] = read_srom_word(i); +#endif if (is_zero_ether_addr(bd->bi_enetaddr) || is_multicast_ether_addr(bd->bi_enetaddr)) { @@ -331,8 +505,11 @@ eth_init(bd_t * bd) DM9000_DBG("\n"); /* Activate DM9000 */ - DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN); /* RX enable */ - DM9000_iow(DM9000_IMR, IMR_PAR); /* Enable TX/RX interrupt mask */ + /* RX enable */ + DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN); + /* Enable TX/RX interrupt mask */ + DM9000_iow(DM9000_IMR, IMR_PAR); + i = 0; while (!(phy_read(1) & 0x20)) { /* autonegation complete bit */ udelay(1000); @@ -374,54 +551,37 @@ eth_init(bd_t * bd) int eth_send(volatile void *packet, int length) { - char *data_ptr; - u32 tmplen, i; int tmo; - DM9000_DBG("eth_send: length: %d\n", length); - for (i = 0; i < length; i++) { - if (i % 8 == 0) - DM9000_DBG("\nSend: 02x: ", i); - DM9000_DBG("%02x ", ((unsigned char *) packet)[i]); - } DM9000_DBG("\n"); - - /* Move data to DM9000 TX RAM */ - data_ptr = (char *) packet; - DM9000_outb(DM9000_MWCMD, DM9000_IO); + struct board_info *db = &dm9000_info; -#ifdef CONFIG_DM9000_USE_8BIT - /* Byte mode */ - for (i = 0; i < length; i++) - DM9000_outb((data_ptr[i] & 0xff), DM9000_DATA); + DM9000_DMP_PACKET("eth_send", packet, length); -#endif /* */ -#ifdef CONFIG_DM9000_USE_16BIT - tmplen = (length + 1) / 2; - for (i = 0; i < tmplen; i++) - DM9000_outw(((u16 *) data_ptr)[i], DM9000_DATA); + DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */ -#endif /* */ -#ifdef CONFIG_DM9000_USE_32BIT - tmplen = (length + 3) / 4; - for (i = 0; i < tmplen; i++) - DM9000_outl(((u32 *) data_ptr)[i], DM9000_DATA); + /* Move data to DM9000 TX RAM */ + DM9000_outb(DM9000_MWCMD, DM9000_IO); /* Prepare for TX-data */ -#endif /* */ + /* push the data to the TX-fifo */ + (db->outblk)(packet, length); /* Set TX length to DM9000 */ DM9000_iow(DM9000_TXPLL, length & 0xff); DM9000_iow(DM9000_TXPLH, (length >> 8) & 0xff); /* Issue TX polling command */ - DM9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ + DM9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ /* wait for end of transmission */ tmo = get_timer(0) + 5 * CFG_HZ; - while (DM9000_ior(DM9000_TCR) & TCR_TXREQ) { + while ( !(DM9000_ior(DM9000_NSR) & (NSR_TX1END | NSR_TX2END)) || + !(DM9000_ior(DM9000_ISR) & IMR_PTM) ) { if (get_timer(0) >= tmo) { printf("transmission timeout\n"); break; } } + DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */ + DM9000_DBG("transmit done\n\n"); return 0; } @@ -450,86 +610,67 @@ eth_rx(void) { u8 rxbyte, *rdptr = (u8 *) NetRxPackets[0]; u16 RxStatus, RxLen = 0; - u32 tmplen, i; -#ifdef CONFIG_DM9000_USE_32BIT - u32 tmpdata; -#endif + struct board_info *db = &dm9000_info; - /* Check packet ready or not */ - DM9000_ior(DM9000_MRCMDX); /* Dummy read */ - rxbyte = DM9000_inb(DM9000_DATA); /* Got most updated data */ - if (rxbyte == 0) + /* Check packet ready or not, we must check + the ISR status first for DM9000A */ + if (!(DM9000_ior(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */ return 0; - /* Status check: this byte must be 0 or 1 */ - if (rxbyte > 1) { - DM9000_iow(DM9000_RCR, 0x00); /* Stop Device */ - DM9000_iow(DM9000_ISR, 0x80); /* Stop INT request */ - DM9000_DBG("rx status check: %d\n", rxbyte); - } - DM9000_DBG("receiving packet\n"); - - /* A packet ready now & Get status/length */ - DM9000_outb(DM9000_MRCMD, DM9000_IO); + DM9000_iow(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */ -#ifdef CONFIG_DM9000_USE_8BIT - RxStatus = DM9000_inb(DM9000_DATA) + (DM9000_inb(DM9000_DATA) << 8); - RxLen = DM9000_inb(DM9000_DATA) + (DM9000_inb(DM9000_DATA) << 8); - -#endif /* */ -#ifdef CONFIG_DM9000_USE_16BIT - RxStatus = DM9000_inw(DM9000_DATA); - RxLen = DM9000_inw(DM9000_DATA); - -#endif /* */ -#ifdef CONFIG_DM9000_USE_32BIT - tmpdata = DM9000_inl(DM9000_DATA); - RxStatus = tmpdata; - RxLen = tmpdata >> 16; + /* There is _at least_ 1 package in the fifo, read them all */ + for (;;) { + DM9000_ior(DM9000_MRCMDX); /* Dummy read */ -#endif /* */ - DM9000_DBG("rx status: 0x%04x rx len: %d\n", RxStatus, RxLen); + /* Get most updated data, + only look at bits 0:1, See application notes DM9000 */ + rxbyte = DM9000_inb(DM9000_DATA) & 0x03; - /* Move data from DM9000 */ - /* Read received packet from RX SRAM */ -#ifdef CONFIG_DM9000_USE_8BIT - for (i = 0; i < RxLen; i++) - rdptr[i] = DM9000_inb(DM9000_DATA); - -#endif /* */ -#ifdef CONFIG_DM9000_USE_16BIT - tmplen = (RxLen + 1) / 2; - for (i = 0; i < tmplen; i++) - ((u16 *) rdptr)[i] = DM9000_inw(DM9000_DATA); + /* Status check: this byte must be 0 or 1 */ + if (rxbyte > DM9000_PKT_RDY) { + DM9000_iow(DM9000_RCR, 0x00); /* Stop Device */ + DM9000_iow(DM9000_ISR, 0x80); /* Stop INT request */ + printf("DM9000 error: status check fail: 0x%x\n", + rxbyte); + return 0; + } -#endif /* */ -#ifdef CONFIG_DM9000_USE_32BIT - tmplen = (RxLen + 3) / 4; - for (i = 0; i < tmplen; i++) - ((u32 *) rdptr)[i] = DM9000_inl(DM9000_DATA); + if (rxbyte != DM9000_PKT_RDY) + return 0; /* No packet received, ignore */ + + DM9000_DBG("receiving packet\n"); + + /* A packet ready now & Get status/length */ + (db->rx_status)(&RxStatus, &RxLen); + + DM9000_DBG("rx status: 0x%04x rx len: %d\n", RxStatus, RxLen); + + /* Move data from DM9000 */ + /* Read received packet from RX SRAM */ + (db->inblk)(rdptr, RxLen); + + if ((RxStatus & 0xbf00) || (RxLen < 0x40) + || (RxLen > DM9000_PKT_MAX)) { + if (RxStatus & 0x100) { + printf("rx fifo error\n"); + } + if (RxStatus & 0x200) { + printf("rx crc error\n"); + } + if (RxStatus & 0x8000) { + printf("rx length error\n"); + } + if (RxLen > DM9000_PKT_MAX) { + printf("rx length too big\n"); + dm9000_reset(); + } + } else { + DM9000_DMP_PACKET("eth_rx", rdptr, RxLen); -#endif /* */ - if ((RxStatus & 0xbf00) || (RxLen < 0x40) - || (RxLen > DM9000_PKT_MAX)) { - if (RxStatus & 0x100) { - printf("rx fifo error\n"); + DM9000_DBG("passing packet to upper layer\n"); + NetReceive(NetRxPackets[0], RxLen); } - if (RxStatus & 0x200) { - printf("rx crc error\n"); - } - if (RxStatus & 0x8000) { - printf("rx length error\n"); - } - if (RxLen > DM9000_PKT_MAX) { - printf("rx length too big\n"); - dm9000_reset(); - } - } else { - - /* Pass to upper layer */ - DM9000_DBG("passing packet to upper layer\n"); - NetReceive(NetRxPackets[0], RxLen); - return RxLen; } return 0; } @@ -590,12 +731,12 @@ phy_read(int reg) /* Fill the phyxcer register into REG_0C */ DM9000_iow(DM9000_EPAR, DM9000_PHY | reg); DM9000_iow(DM9000_EPCR, 0xc); /* Issue phyxcer read command */ - udelay(100); /* Wait read complete */ + udelay(100); /* Wait read complete */ DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer read command */ val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL); /* The read data keeps on REG_0D & REG_0E */ - DM9000_DBG("phy_read(%d): %d\n", reg, val); + DM9000_DBG("phy_read(0x%x): 0x%x\n", reg, val); return val; } @@ -613,8 +754,7 @@ phy_write(int reg, u16 value) DM9000_iow(DM9000_EPDRL, (value & 0xff)); DM9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff)); DM9000_iow(DM9000_EPCR, 0xa); /* Issue phyxcer write command */ - udelay(500); /* Wait write complete */ + udelay(500); /* Wait write complete */ DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer write command */ - DM9000_DBG("phy_write(reg:%d, value:%d)\n", reg, value); + DM9000_DBG("phy_write(reg:0x%x, value:0x%x)\n", reg, value); } -#endif /* CONFIG_DRIVER_DM9000 */ diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c index c53c226..060b518 100644 --- a/drivers/net/e1000.c +++ b/drivers/net/e1000.c @@ -44,9 +44,6 @@ tested on both gig copper and gig fiber boards #include "e1000.h" -#if defined(CONFIG_CMD_NET) \ - && defined(CONFIG_NET_MULTI) && defined(CONFIG_E1000) - #define TOUT_LOOP 100000 #undef virt_to_bus @@ -78,11 +75,13 @@ 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}, {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82540EM_LOM}, {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82541ER}, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82541GI_LF}, }; /* Function forward declarations */ @@ -638,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; @@ -646,6 +646,7 @@ e1000_set_mac_type(struct e1000_hw *hw) hw->mac_type = e1000_82546; break; case E1000_DEV_ID_82541ER: + case E1000_DEV_ID_82541GI_LF: hw->mac_type = e1000_82541_rev_2; break; default: @@ -3059,5 +3060,3 @@ e1000_initialize(bd_t * bis) } return 1; } - -#endif diff --git a/drivers/net/e1000.h b/drivers/net/e1000.h index 851467d..c258bc2 100644 --- a/drivers/net/e1000.h +++ b/drivers/net/e1000.h @@ -217,12 +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 NUM_DEV_IDS 14 +#define E1000_DEV_ID_82541GI_LF 0x107C +#define NUM_DEV_IDS 16 #define NODE_ADDRESS_SIZE 6 #define ETH_LENGTH_OF_ADDRESS 6 diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 96ed271..9de0fb5 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -30,9 +30,6 @@ #undef DEBUG -#if defined(CONFIG_CMD_NET) \ - && defined(CONFIG_NET_MULTI) && defined(CONFIG_EEPRO100) - /* Ethernet chip registers. */ #define SCBStatus 0 /* Rx/Command Unit Status *Word* */ @@ -944,5 +941,3 @@ static void read_hw_addr (struct eth_device *dev, bd_t * bis) #endif } } - -#endif diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index 98303ac..5c24b0d 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -17,7 +17,6 @@ #include <config.h> #include <common.h> -#ifdef CONFIG_ENC28J60 #include <net.h> #include <asm/arch/hardware.h> #include <asm/arch/spi.h> @@ -979,5 +978,3 @@ static void phyWrite(unsigned char addr, unsigned short data) } } } - -#endif /* CONFIG_ENC28J60 */ diff --git a/drivers/net/fsl_mcdmafec.c b/drivers/net/fsl_mcdmafec.c index 2ef91f2..f2bdba6 100644 --- a/drivers/net/fsl_mcdmafec.c +++ b/drivers/net/fsl_mcdmafec.c @@ -31,7 +31,6 @@ #include <net.h> #include <miiphy.h> -#ifdef CONFIG_FSLDMAFEC #undef ET_DEBUG #undef MII_DEBUG @@ -49,7 +48,6 @@ #define BD_ENET_RX_ERR (BD_ENET_RX_LG | BD_ENET_RX_NO | BD_ENET_RX_CR | \ BD_ENET_RX_OV | BD_ENET_RX_TR) -#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) #include <asm/immap.h> #include <asm/fsl_mcdmafec.h> @@ -586,6 +584,3 @@ int mcdmafec_initialize(bd_t * bis) return 1; } - -#endif /* CONFIG_CMD_NET && CONFIG_NET_MULTI */ -#endif /* CONFIG_FSLDMAFEC */ diff --git a/drivers/net/inca-ip_sw.c b/drivers/net/inca-ip_sw.c index e4aaed6..d852a15 100644 --- a/drivers/net/inca-ip_sw.c +++ b/drivers/net/inca-ip_sw.c @@ -26,9 +26,6 @@ #include <common.h> -#if defined(CONFIG_CMD_NET) \ - && defined(CONFIG_NET_MULTI) && defined(CONFIG_INCA_IP_SWITCH) - #include <malloc.h> #include <net.h> #include <asm/inca-ip.h> @@ -234,7 +231,7 @@ static int inca_switch_init(struct eth_device *dev, bd_t * bis) /* Initialize the descriptor rings. */ for (i = 0; i < NUM_RX_DESC; i++) { - inca_rx_descriptor_t * rx_desc = KSEG1ADDR(&rx_ring[i]); + inca_rx_descriptor_t * rx_desc = (inca_rx_descriptor_t *)CKSEG1ADDR(&rx_ring[i]); memset(rx_desc, 0, sizeof(rx_ring[i])); /* Set maximum size of receive buffer. @@ -252,14 +249,14 @@ static int inca_switch_init(struct eth_device *dev, bd_t * bis) /* Let the last descriptor point to the first * one. */ - rx_desc->nextRxDescPtr = KSEG1ADDR((u32)rx_ring); + rx_desc->nextRxDescPtr = (u32)CKSEG1ADDR(rx_ring); } else { /* Set the address of the next descriptor. */ - rx_desc->nextRxDescPtr = (u32)KSEG1ADDR(&rx_ring[i+1]); + rx_desc->nextRxDescPtr = (u32)CKSEG1ADDR(&rx_ring[i+1]); } - rx_desc->RxDataPtr = (u32)KSEG1ADDR(NetRxPackets[i]); + rx_desc->RxDataPtr = (u32)CKSEG1ADDR(NetRxPackets[i]); } #if 0 @@ -268,7 +265,7 @@ static int inca_switch_init(struct eth_device *dev, bd_t * bis) #endif for (i = 0; i < NUM_TX_DESC; i++) { - inca_tx_descriptor_t * tx_desc = KSEG1ADDR(&tx_ring[i]); + inca_tx_descriptor_t * tx_desc = (inca_tx_descriptor_t *)CKSEG1ADDR(&tx_ring[i]); memset(tx_desc, 0, sizeof(tx_ring[i])); @@ -282,11 +279,11 @@ static int inca_switch_init(struct eth_device *dev, bd_t * bis) /* Let the last descriptor point to the * first one. */ - tx_desc->nextTxDescPtr = KSEG1ADDR((u32)tx_ring); + tx_desc->nextTxDescPtr = (u32)CKSEG1ADDR(tx_ring); } else { /* Set the address of the next descriptor. */ - tx_desc->nextTxDescPtr = (u32)KSEG1ADDR(&tx_ring[i+1]); + tx_desc->nextTxDescPtr = (u32)CKSEG1ADDR(&tx_ring[i+1]); } } @@ -346,7 +343,7 @@ static int inca_switch_send(struct eth_device *dev, volatile void *packet, int l int res = -1; u32 command; u32 regValue; - inca_tx_descriptor_t * tx_desc = KSEG1ADDR(&tx_ring[tx_new]); + inca_tx_descriptor_t * tx_desc = (inca_tx_descriptor_t *)CKSEG1ADDR(&tx_ring[tx_new]); #if 0 printf("Entered inca_switch_send()\n"); @@ -365,7 +362,7 @@ static int inca_switch_send(struct eth_device *dev, volatile void *packet, int l } if (tx_old_hold >= 0) { - KSEG1ADDR(&tx_ring[tx_old_hold])->params.field.HOLD = 1; + ((inca_tx_descriptor_t *)CKSEG1ADDR(&tx_ring[tx_old_hold]))->params.field.HOLD = 1; } tx_old_hold = tx_hold; @@ -376,7 +373,7 @@ static int inca_switch_send(struct eth_device *dev, volatile void *packet, int l tx_desc->TxDataPtr = (u32)packet; tx_desc->params.field.NBA = length; - KSEG1ADDR(&tx_ring[tx_hold])->params.field.HOLD = 0; + ((inca_tx_descriptor_t *)CKSEG1ADDR(&tx_ring[tx_hold]))->params.field.HOLD = 0; tx_hold = tx_new; tx_new = (tx_new + 1) % NUM_TX_DESC; @@ -397,7 +394,7 @@ static int inca_switch_send(struct eth_device *dev, volatile void *packet, int l DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR0, regValue); #if 1 - for(i = 0; KSEG1ADDR(&tx_ring[tx_hold])->C == 0; i++) { + for(i = 0; ((inca_tx_descriptor_t *)CKSEG1ADDR(&tx_ring[tx_hold]))->C == 0; i++) { if (i >= TOUT_LOOP) { printf("%s: tx buffer not ready\n", dev->name); goto Done; @@ -423,7 +420,7 @@ static int inca_switch_recv(struct eth_device *dev) #endif for (;;) { - rx_desc = KSEG1ADDR(&rx_ring[rx_new]); + rx_desc = (inca_rx_descriptor_t *)CKSEG1ADDR(&rx_ring[rx_new]); if (rx_desc->status.field.C == 0) { break; @@ -456,7 +453,7 @@ static int inca_switch_recv(struct eth_device *dev) #if 0 printf("Received %d bytes\n", length); #endif - NetReceive((void*)KSEG1ADDR(NetRxPackets[rx_new]), length - 4); + NetReceive((void*)CKSEG1ADDR(NetRxPackets[rx_new]), length - 4); } else { #if 1 printf("Zero length!!!\n"); @@ -464,7 +461,7 @@ static int inca_switch_recv(struct eth_device *dev) } - KSEG1ADDR(&rx_ring[rx_hold])->params.field.HOLD = 0; + ((inca_rx_descriptor_t *)CKSEG1ADDR(&rx_ring[rx_hold]))->params.field.HOLD = 0; rx_hold = rx_new; @@ -813,5 +810,3 @@ Fail: return -1; } #endif /* CONFIG_INCA_IP_SWITCH_AMDIX */ - -#endif diff --git a/drivers/net/ks8695eth.c b/drivers/net/ks8695eth.c index b598dd7..7f3e0c2 100644 --- a/drivers/net/ks8695eth.c +++ b/drivers/net/ks8695eth.c @@ -21,8 +21,6 @@ /****************************************************************************/ #include <common.h> - -#ifdef CONFIG_DRIVER_KS8695ETH #include <malloc.h> #include <net.h> #include <asm/io.h> @@ -234,5 +232,3 @@ int eth_send(volatile void *packet, int len) return len; } - -#endif /* CONFIG_DRIVER_KS8695ETH */ diff --git a/drivers/net/lan91c96.c b/drivers/net/lan91c96.c index 51cfb7e..c23a400 100644 --- a/drivers/net/lan91c96.c +++ b/drivers/net/lan91c96.c @@ -63,10 +63,6 @@ #include "lan91c96.h" #include <net.h> -#ifdef CONFIG_DRIVER_LAN91C96 - -#if defined(CONFIG_CMD_NET) - /*------------------------------------------------------------------------ * * Configuration options, for the experienced user to change. @@ -865,9 +861,6 @@ static int smc_hw_init () } #endif /* 0 */ -#endif /* CONFIG_CMD_NET */ - - /* smc_get_ethaddr (bd_t * bd) * * This checks both the environment and the ROM for an ethernet address. If @@ -963,5 +956,3 @@ int get_rom_mac (unsigned char *v_rom_mac) return (1); #endif } - -#endif /* CONFIG_DRIVER_LAN91C96 */ diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 703784e..aa39284 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -17,9 +17,6 @@ */ #include <common.h> -#if defined(CONFIG_MACB) \ - && (defined(CONFIG_CMD_NET) || defined(CONFIG_CMD_MII)) - /* * The u-boot networking stack is a little weird. It seems like the * networking core allocates receive buffers up front without any @@ -417,13 +414,15 @@ static int macb_init(struct eth_device *netdev, bd_t *bd) /* choose RMII or MII mode. This depends on the board */ #ifdef CONFIG_RMII -#if defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) +#if defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \ + defined(CONFIG_AT91SAM9263) macb_writel(macb, USRIO, MACB_BIT(RMII) | MACB_BIT(CLKEN)); #else macb_writel(macb, USRIO, 0); #endif #else -#if defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) +#if defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \ + defined(CONFIG_AT91SAM9263) macb_writel(macb, USRIO, MACB_BIT(CLKEN)); #else macb_writel(macb, USRIO, MACB_BIT(MII)); @@ -591,5 +590,3 @@ int miiphy_write(unsigned char addr, unsigned char reg, unsigned short value) } #endif - -#endif /* CONFIG_MACB */ diff --git a/drivers/net/mcffec.c b/drivers/net/mcffec.c index 5ab4726..58ed5e3 100644 --- a/drivers/net/mcffec.c +++ b/drivers/net/mcffec.c @@ -27,8 +27,6 @@ #include <common.h> #include <malloc.h> -#ifdef CONFIG_MCFFEC - #include <asm/fec.h> #include <asm/immap.h> @@ -51,8 +49,6 @@ DECLARE_GLOBAL_DATA_PTR; -#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) - struct fec_info_s fec_info[] = { #ifdef CFG_FEC0_IOBASE { @@ -125,11 +121,17 @@ void setFecDuplexSpeed(volatile fec_t * fecp, bd_t * bd, int dup_spd) } if ((dup_spd & 0xFFFF) == _100BASET) { +#ifdef CONFIG_MCF5445x + fecp->rcr &= ~0x200; /* disabled 10T base */ +#endif #ifdef MII_DEBUG printf("100Mbps\n"); #endif bd->bi_ethspeed = 100; } else { +#ifdef CONFIG_MCF5445x + fecp->rcr |= 0x200; /* enabled 10T base */ +#endif #ifdef MII_DEBUG printf("10Mbps\n"); #endif @@ -599,6 +601,3 @@ int mcffec_initialize(bd_t * bis) return 1; } - -#endif /* CONFIG_CMD_NET, FEC_ENET & NET_MULTI */ -#endif /* CONFIG_MCFFEC */ diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index a523959..4aee048 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -56,9 +56,6 @@ #include <asm/io.h> #include <pci.h> -#if defined(CONFIG_CMD_NET) \ - && defined(CONFIG_NET_MULTI) && defined(CONFIG_NATSEMI) - /* defines */ #define EEPROM_SIZE 0xb /*12 16-bit chunks, or 24 bytes*/ @@ -878,5 +875,3 @@ natsemi_disable(struct eth_device *dev) /* Restore PME enable bit */ OUTL(dev, SavedClkRun, ClkRun); } - -#endif 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/netarm_eth.c b/drivers/net/netarm_eth.c index ecf45dc..c011809 100644 --- a/drivers/net/netarm_eth.c +++ b/drivers/net/netarm_eth.c @@ -22,15 +22,11 @@ #include <common.h> - -#ifdef CONFIG_DRIVER_NETARMETH #include <command.h> #include <net.h> #include "netarm_eth.h" #include <asm/arch/netarm_registers.h> -#if defined(CONFIG_CMD_NET) - static int na_mii_poll_busy (void); static void na_get_mac_addr (void) @@ -352,7 +348,3 @@ extern int eth_send (volatile void *packet, int length) printf ("eth_send timeout\n"); return 1; } - -#endif /* CONFIG_CMD_NET */ - -#endif /* CONFIG_DRIVER_NETARMETH */ diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 69089f9..b2ee5ea 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -22,9 +22,6 @@ */ #include <common.h> - -#ifdef CONFIG_NETCONSOLE - #include <command.h> #include <devices.h> #include <net.h> @@ -263,5 +260,3 @@ int drv_nc_init (void) return (rc == 0) ? 1 : rc; } - -#endif /* CONFIG_NETCONSOLE */ diff --git a/drivers/net/ns7520_eth.c b/drivers/net/ns7520_eth.c index a5a20df..e19c223 100644 --- a/drivers/net/ns7520_eth.c +++ b/drivers/net/ns7520_eth.c @@ -15,8 +15,6 @@ #include <common.h> -#if defined(CONFIG_DRIVER_NS7520_ETHERNET) - #include <net.h> /* NetSendPacket */ #include <asm/arch/netarm_registers.h> #include <asm/arch/netarm_dma_module.h> @@ -389,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. */ @@ -440,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(); @@ -520,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 */ @@ -588,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; @@ -846,14 +840,11 @@ extern int ns7520_miiphy_write(char *devname, unsigned char const addr, return (ret); } #endif /* defined(CONFIG_MII) */ -#endif /* CONFIG_DRIVER_NS7520_ETHERNET */ int ns7520_miiphy_initialize(bd_t *bis) { -#if defined(CONFIG_DRIVER_NS7520_ETHERNET) #if defined(CONFIG_MII) miiphy_register("ns7520phy", ns7520_miiphy_read, ns7520_miiphy_write); #endif -#endif return 0; } diff --git a/drivers/net/ns8382x.c b/drivers/net/ns8382x.c index c807dd4..0b9a3ae 100644 --- a/drivers/net/ns8382x.c +++ b/drivers/net/ns8382x.c @@ -56,9 +56,6 @@ #include <asm/io.h> #include <pci.h> -#if defined(CONFIG_CMD_NET) \ - && defined(CONFIG_NET_MULTI) && defined(CONFIG_NS8382X) - /* defines */ #define DSIZE 0x00000FFF #define ETH_ALEN 6 @@ -859,5 +856,3 @@ ns8382x_disable(struct eth_device *dev) /* Restore PME enable bit */ OUTL(dev, SavedClkRun, ClkRun); } - -#endif diff --git a/drivers/net/ns9750_eth.c b/drivers/net/ns9750_eth.c index 067ff8e..cade831 100644 --- a/drivers/net/ns9750_eth.c +++ b/drivers/net/ns9750_eth.c @@ -37,9 +37,7 @@ #include "ns9750_eth.h" /* for Ethernet and PHY */ -#ifdef CONFIG_DRIVER_NS9750_ETHERNET - -/* 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:" @@ -401,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 @@ -457,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 (); @@ -497,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 (); @@ -573,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 */ @@ -594,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 { @@ -639,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; @@ -793,5 +788,3 @@ static unsigned int ns9750_mii_poll_busy (void) return unTimeout; } - -#endif /* CONFIG_DRIVER_NS9750_ETHERNET */ diff --git a/drivers/net/pcnet.c b/drivers/net/pcnet.c index aa04e8f..a4f0214 100644 --- a/drivers/net/pcnet.c +++ b/drivers/net/pcnet.c @@ -45,9 +45,6 @@ #define PCNET_DEBUG2(fmt,args...) #endif -#if defined(CONFIG_CMD_NET) \ - && defined(CONFIG_NET_MULTI) && defined(CONFIG_PCNET) - #if !defined(CONF_PCNET_79C973) && defined(CONF_PCNET_79C975) #error "Macro for PCnet chip version is not defined!" #endif @@ -537,4 +534,3 @@ static void pcnet_halt (struct eth_device *dev) printf ("%s: TIMEOUT: controller reset failed\n", dev->name); } } -#endif diff --git a/drivers/net/plb2800_eth.c b/drivers/net/plb2800_eth.c index b8cc57a..dad842c 100644 --- a/drivers/net/plb2800_eth.c +++ b/drivers/net/plb2800_eth.c @@ -24,10 +24,6 @@ */ #include <common.h> - -#if defined(CONFIG_CMD_NET) \ - && defined(CONFIG_NET_MULTI) && defined(CONFIG_PLB2800_ETHER) - #include <malloc.h> #include <net.h> #include <asm/addrspace.h> @@ -392,5 +388,3 @@ static unsigned char * plb2800_get_mac_addr(void) return addr; } - -#endif /* CONFIG_PLB2800_ETHER */ diff --git a/drivers/net/rtl8019.c b/drivers/net/rtl8019.c index 9d62cab..3ddf917 100644 --- a/drivers/net/rtl8019.c +++ b/drivers/net/rtl8019.c @@ -32,10 +32,6 @@ #include "rtl8019.h" #include <net.h> -#ifdef CONFIG_DRIVER_RTL8019 - -#if defined(CONFIG_CMD_NET) - /* packet page register access functions */ static unsigned char get_reg (unsigned int regno) @@ -271,7 +267,3 @@ extern int eth_send (volatile void *packet, int length) return 0; } - -#endif /* CONFIG_CMD_NET */ - -#endif /* CONFIG_DRIVER_RTL8019 */ diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index 097f684..4fd20ac 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -77,9 +77,6 @@ #include <asm/io.h> #include <pci.h> -#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \ - defined(CONFIG_RTL8139) - #define RTL_TIMEOUT 100000 #define ETH_FRAME_LEN 1514 @@ -545,4 +542,3 @@ static void rtl_disable(struct eth_device *dev) udelay (100); /* wait 100us */ } } -#endif diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index 6c4c9ff..7423bc0 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -58,9 +58,6 @@ #include <asm/io.h> #include <pci.h> -#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \ - defined(CONFIG_RTL8169) - #undef DEBUG_RTL8169 #undef DEBUG_RTL8169_TX #undef DEBUG_RTL8169_RX @@ -887,5 +884,3 @@ int rtl8169_initialize(bd_t *bis) } return card_number; } - -#endif diff --git a/drivers/net/s3c4510b_eth.c b/drivers/net/s3c4510b_eth.c index 3d9066a..6dcb244 100644 --- a/drivers/net/s3c4510b_eth.c +++ b/drivers/net/s3c4510b_eth.c @@ -25,9 +25,6 @@ */ #include <common.h> - -#ifdef CONFIG_DRIVER_S3C4510_ETH - #include <command.h> #include <net.h> #include <asm/hardware.h> @@ -242,5 +239,3 @@ void eth_halt(void) /* disable MAC */ PUT_REG( REG_MACCON, ETH_HaltReg); } - -#endif 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/smc91111.c b/drivers/net/smc91111.c index 8061f12..e8b235b 100644 --- a/drivers/net/smc91111.c +++ b/drivers/net/smc91111.c @@ -65,8 +65,6 @@ #include "smc91111.h" #include <net.h> -#ifdef CONFIG_DRIVER_SMC91111 - /* Use power-down feature of the chip */ #define POWER_DOWN 0 @@ -1620,4 +1618,3 @@ int get_rom_mac (uchar *v_rom_mac) return (valid_mac ? 1 : 0); #endif } -#endif /* CONFIG_DRIVER_SMC91111 */ diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 5302cb5..1484b0b 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -23,14 +23,17 @@ */ #include <common.h> - -#ifdef CONFIG_DRIVER_SMC911X - #include <command.h> #include <net.h> #include <miiphy.h> -#ifdef CONFIG_DRIVER_SMC911X_32_BIT +#if defined (CONFIG_DRIVER_SMC911X_32_BIT) && \ + defined (CONFIG_DRIVER_SMC911X_16_BIT) +#error "SMC911X: Only one of CONFIG_DRIVER_SMC911X_32_BIT and \ + CONFIG_DRIVER_SMC911X_16_BIT shall be set" +#endif + +#if defined (CONFIG_DRIVER_SMC911X_32_BIT) static inline u32 reg_read(u32 addr) { return *(volatile u32*)addr; @@ -39,9 +42,20 @@ static inline void reg_write(u32 addr, u32 val) { *(volatile u32*)addr = val; } +#elif defined (CONFIG_DRIVER_SMC911X_16_BIT) +static inline u32 reg_read(u32 addr) +{ + volatile u16 *addr_16 = (u16 *)addr; + return ((*addr_16 & 0x0000ffff) | (*(addr_16 + 1) << 16)); +} +static inline void reg_write(u32 addr, u32 val) +{ + *(volatile u16*)addr = (u16)val; + *(volatile u16*)(addr + 2) = (u16)(val >> 16); +} #else -#error "SMC911X: Only 32-bit bus is supported" -#endif +#error "SMC911X: undefined bus width" +#endif /* CONFIG_DRIVER_SMC911X_16_BIT */ #define mdelay(n) udelay((n)*1000) @@ -583,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; } @@ -682,5 +696,3 @@ int eth_rx(void) return 0; } - -#endif /* CONFIG_DRIVER_SMC911X */ diff --git a/drivers/net/tigon3.c b/drivers/net/tigon3.c index 5f6a4ec..ab448b0 100644 --- a/drivers/net/tigon3.c +++ b/drivers/net/tigon3.c @@ -12,8 +12,7 @@ /******************************************************************************/ #include <common.h> #include <asm/types.h> -#if defined(CONFIG_CMD_NET) && !defined(CONFIG_NET_MULTI) && \ - defined(CONFIG_TIGON3) + #ifdef CONFIG_BMW #include <mpc824x.h> #endif @@ -5695,5 +5694,3 @@ LM_DmaTest (PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pBufferVirt, } return LM_STATUS_SUCCESS; } - -#endif diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index c7af930..6e0f2c6 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -17,7 +17,6 @@ #include <net.h> #include <command.h> -#if defined(CONFIG_TSEC_ENET) #include "tsec.h" #include "miiphy.h" @@ -1128,6 +1127,36 @@ struct phy_info phy_info_M88E1111S = { }, }; +struct phy_info phy_info_M88E1118 = { + 0x01410e1, + "Marvell 88E1118", + 4, + (struct phy_cmd[]){ /* config */ + /* Reset and configure the PHY */ + {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, + {0x16, 0x0002, NULL}, /* Change Page Number */ + {0x15, 0x1070, NULL}, /* Delay RGMII TX and RX */ + {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, + {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, + {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, + {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, + {miim_end,} + }, + (struct phy_cmd[]){ /* startup */ + {0x16, 0x0000, NULL}, /* Change Page Number */ + /* Status is read once to clear old link state */ + {MIIM_STATUS, miim_read, NULL}, + /* Auto-negotiate */ + /* Read the status */ + {MIIM_88E1011_PHY_STATUS, miim_read, + &mii_parse_88E1011_psr}, + {miim_end,} + }, + (struct phy_cmd[]){ /* shutdown */ + {miim_end,} + }, +}; + static unsigned int m88e1145_setmode(uint mii_reg, struct tsec_private *priv) { uint mii_data = read_phy_reg(priv, mii_reg); @@ -1492,6 +1521,7 @@ struct phy_info *phy_info[] = { &phy_info_BCM5464S, &phy_info_M88E1011S, &phy_info_M88E1111S, + &phy_info_M88E1118, &phy_info_M88E1145, &phy_info_M88E1149S, &phy_info_dm9161, @@ -1710,5 +1740,3 @@ tsec_mcast_addr (struct eth_device *dev, u8 mcast_mac, u8 set) return 0; } #endif /* Multicast TFTP ? */ - -#endif /* CONFIG_TSEC_ENET */ diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index a09115e..57c0dc3 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -27,9 +27,6 @@ #include <config.h> -#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) \ - && defined(CONFIG_TSI108_ETH) - #if !defined(CONFIG_TSI108_ETH_NUM_PORTS) || (CONFIG_TSI108_ETH_NUM_PORTS > 2) #error "CONFIG_TSI108_ETH_NUM_PORTS must be defined as 1 or 2" #endif @@ -1032,5 +1029,3 @@ static void tsi108_eth_halt (struct eth_device *dev) /* Put MAC into reset state. */ reg_MAC_CONFIG_1(base) = MAC_CONFIG_1_SOFT_RESET; } - -#endif diff --git a/drivers/net/uli526x.c b/drivers/net/uli526x.c index 79d29ae..7145b72 100644 --- a/drivers/net/uli526x.c +++ b/drivers/net/uli526x.c @@ -22,9 +22,6 @@ /* some kernel function compatible define */ -#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \ - defined(CONFIG_ULI526X) - #undef DEBUG /* Board/System/Debug information/definition */ @@ -993,4 +990,3 @@ static void set_mac_addr(struct eth_device *dev) udelay(10); return; } -#endif diff --git a/drivers/net/vsc7385.c b/drivers/net/vsc7385.c index 4095bce..4e7259f 100644 --- a/drivers/net/vsc7385.c +++ b/drivers/net/vsc7385.c @@ -13,9 +13,6 @@ */ #include <config.h> - -#ifdef CONFIG_VSC7385_ENET - #include <common.h> #include <asm/io.h> #include <asm/errno.h> @@ -97,5 +94,3 @@ int vsc7385_upload_firmware(void *firmware, unsigned int size) return 0; } - -#endif diff --git a/drivers/pci/tsi108_pci.c b/drivers/pci/tsi108_pci.c index d5f11e4..4f02cb8 100644 --- a/drivers/pci/tsi108_pci.c +++ b/drivers/pci/tsi108_pci.c @@ -33,8 +33,9 @@ #include <pci.h> #include <asm/io.h> #include <tsi108.h> -#ifdef CONFIG_OF_FLAT_TREE -#include <ft_build.h> +#if defined(CONFIG_OF_LIBFDT) +#include <libfdt.h> +#include <fdt_support.h> #endif struct pci_controller local_hose; @@ -162,20 +163,24 @@ void pci_init_board (void) return; } -#ifdef CONFIG_OF_FLAT_TREE -void -ft_pci_setup (void *blob, bd_t *bd) +#if defined(CONFIG_OF_LIBFDT) +void ft_pci_setup(void *blob, bd_t *bd) { - u32 *p; - int len; - - p = (u32 *)ft_get_prop (blob, "/" OF_TSI "/pci@1000/bus-range", &len); - if (p != NULL) { - p[0] = local_hose.first_busno; - p[1] = local_hose.last_busno; + int nodeoffset; + int tmp[2]; + const char *path; + + nodeoffset = fdt_path_offset(blob, "/aliases"); + if (nodeoffset >= 0) { + path = fdt_getprop(blob, nodeoffset, "pci", NULL); + if (path) { + tmp[0] = cpu_to_be32(local_hose.first_busno); + tmp[1] = cpu_to_be32(local_hose.last_busno); + do_fixup_by_path(blob, path, "bus-range", + &tmp, sizeof(tmp), 1); + } } - } -#endif +#endif /* CONFIG_OF_LIBFDT */ #endif /* CONFIG_TSI108_PCI */ 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/ds1306.c b/drivers/rtc/ds1306.c index 1c8ac7f..29854fc 100644 --- a/drivers/rtc/ds1306.c +++ b/drivers/rtc/ds1306.c @@ -62,13 +62,6 @@ #define RTC_USER_RAM_BASE 0x20 -/* - * External table of chip select functions (see the appropriate board - * support for the actual definition of the table). - */ -extern spi_chipsel_type spi_chipsel[]; -extern int spi_chipsel_cnt; - static unsigned int bin2bcd (unsigned int n); static unsigned char bcd2bin (unsigned char c); @@ -305,11 +298,29 @@ void rtc_reset (void) static unsigned char rtc_read (unsigned char reg); static void rtc_write (unsigned char reg, unsigned char val); +static struct spi_slave *slave; + /* read clock time from DS1306 and return it in *tmp */ int rtc_get (struct rtc_time *tmp) { unsigned char sec, min, hour, mday, wday, mon, year; + /* + * Assuming Vcc = 2.0V (lowest speed) + * + * REVISIT: If we add an rtc_init() function we can do this + * step just once. + */ + if (!slave) { + slave = spi_setup_slave(0, CFG_SPI_RTC_DEVID, 600000, + SPI_MODE_3 | SPI_CS_HIGH); + if (!slave) + return; + } + + if (spi_claim_bus(slave)) + return; + sec = rtc_read (RTC_SECONDS); min = rtc_read (RTC_MINUTES); hour = rtc_read (RTC_HOURS); @@ -318,6 +329,8 @@ int rtc_get (struct rtc_time *tmp) mon = rtc_read (RTC_MONTH); year = rtc_read (RTC_YEAR); + spi_release_bus(slave); + debug ("Get RTC year: %02x mon: %02x mday: %02x wday: %02x " "hr: %02x min: %02x sec: %02x\n", year, mon, mday, wday, hour, min, sec); @@ -360,6 +373,17 @@ int rtc_get (struct rtc_time *tmp) /* set clock time from *tmp in DS1306 RTC */ void rtc_set (struct rtc_time *tmp) { + /* Assuming Vcc = 2.0V (lowest speed) */ + if (!slave) { + slave = spi_setup_slave(0, CFG_SPI_RTC_DEVID, 600000, + SPI_MODE_3 | SPI_CS_HIGH); + if (!slave) + return; + } + + if (spi_claim_bus(slave)) + return; + debug ("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); @@ -371,6 +395,8 @@ void rtc_set (struct rtc_time *tmp) rtc_write (RTC_DATE_OF_MONTH, bin2bcd (tmp->tm_mday)); rtc_write (RTC_MONTH, bin2bcd (tmp->tm_mon)); rtc_write (RTC_YEAR, bin2bcd (tmp->tm_year - 2000)); + + spi_release_bus(slave); } /* ------------------------------------------------------------------------- */ @@ -378,6 +404,17 @@ void rtc_set (struct rtc_time *tmp) /* reset the DS1306 */ void rtc_reset (void) { + /* Assuming Vcc = 2.0V (lowest speed) */ + if (!slave) { + slave = spi_setup_slave(0, CFG_SPI_RTC_DEVID, 600000, + SPI_MODE_3 | SPI_CS_HIGH); + if (!slave) + return; + } + + if (spi_claim_bus(slave)) + return; + /* clear the control register */ rtc_write (RTC_CONTROL, 0x00); /* 1st step: reset WP */ rtc_write (RTC_CONTROL, 0x00); /* 2nd step: reset 1Hz, AIE1, AIE0 */ @@ -391,22 +428,18 @@ void rtc_reset (void) rtc_write (RTC_HOURS_ALARM1, 0x00); rtc_write (RTC_DAY_OF_WEEK_ALARM0, 0x00); rtc_write (RTC_DAY_OF_WEEK_ALARM1, 0x00); + + spi_release_bus(slave); } /* ------------------------------------------------------------------------- */ static unsigned char rtc_read (unsigned char reg) { - unsigned char dout[2]; /* SPI Output Data Bytes */ - unsigned char din[2]; /* SPI Input Data Bytes */ - - dout[0] = reg; + int ret; - if (spi_xfer (spi_chipsel[CFG_SPI_RTC_DEVID], 16, dout, din) != 0) { - return 0; - } else { - return din[1]; - } + ret = spi_w8r8(slave, reg); + return ret < 0 ? 0 : ret; } /* ------------------------------------------------------------------------- */ @@ -419,7 +452,7 @@ static void rtc_write (unsigned char reg, unsigned char val) dout[0] = 0x80 | reg; dout[1] = val; - spi_xfer (spi_chipsel[CFG_SPI_RTC_DEVID], 16, dout, din); + spi_xfer (slave, 16, dout, din, SPI_XFER_BEGIN | SPI_XFER_END); } #endif /* end of code exclusion (see #ifdef CONFIG_SXNI855T above) */ diff --git a/drivers/rtc/mc13783-rtc.c b/drivers/rtc/mc13783-rtc.c index 35b1b8b..b6e1501 100644 --- a/drivers/rtc/mc13783-rtc.c +++ b/drivers/rtc/mc13783-rtc.c @@ -24,34 +24,50 @@ #include <rtc.h> #include <spi.h> +static struct spi_slave *slave; + int rtc_get(struct rtc_time *rtc) { u32 day1, day2, time; u32 reg; int err, tim, i = 0; - spi_select(1, 0, SPI_MODE_2 | SPI_CS_HIGH); + if (!slave) { + /* FIXME: Verify the max SCK rate */ + slave = spi_setup_slave(1, 0, 1000000, + SPI_MODE_2 | SPI_CS_HIGH); + if (!slave) + return -1; + } + + if (spi_claim_bus(slave)) + return -1; do { reg = 0x2c000000; - err = spi_xfer(0, 32, (uchar *)®, (uchar *)&day1); + err = spi_xfer(slave, 32, (uchar *)®, (uchar *)&day1, + SPI_XFER_BEGIN | SPI_XFER_END); if (err) return err; reg = 0x28000000; - err = spi_xfer(0, 32, (uchar *)®, (uchar *)&time); + err = spi_xfer(slave, 32, (uchar *)®, (uchar *)&time, + SPI_XFER_BEGIN | SPI_XFER_END); if (err) return err; reg = 0x2c000000; - err = spi_xfer(0, 32, (uchar *)®, (uchar *)&day2); + err = spi_xfer(slave, 32, (uchar *)®, (uchar *)&day2, + SPI_XFER_BEGIN | SPI_XFER_END); if (err) return err; } while (day1 != day2 && i++ < 3); + spi_release_bus(slave); + tim = day1 * 86400 + time; to_tm(tim, rtc); @@ -65,16 +81,31 @@ void rtc_set(struct rtc_time *rtc) { u32 time, day, reg; + if (!slave) { + /* FIXME: Verify the max SCK rate */ + slave = spi_setup_slave(1, 0, 1000000, + SPI_MODE_2 | SPI_CS_HIGH); + if (!slave) + return; + } + time = mktime(rtc->tm_year, rtc->tm_mon, rtc->tm_mday, rtc->tm_hour, rtc->tm_min, rtc->tm_sec); day = time / 86400; time %= 86400; + if (spi_claim_bus(slave)) + return; + reg = 0x2c000000 | day | 0x80000000; - spi_xfer(0, 32, (uchar *)®, (uchar *)&day); + spi_xfer(slave, 32, (uchar *)®, (uchar *)&day, + SPI_XFER_BEGIN | SPI_XFER_END); reg = 0x28000000 | time | 0x80000000; - spi_xfer(0, 32, (uchar *)®, (uchar *)&time); + spi_xfer(slave, 32, (uchar *)®, (uchar *)&time, + SPI_XFER_BEGIN | SPI_XFER_END); + + spi_release_bus(slave); } void rtc_reset(void) 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/serial/serial_sh.c b/drivers/serial/serial_sh.c index aa4ff35..0801ac4 100644 --- a/drivers/serial/serial_sh.c +++ b/drivers/serial/serial_sh.c @@ -26,6 +26,8 @@ #define SCIF_BASE SCIF0_BASE #elif defined (CONFIG_CONS_SCIF1) #define SCIF_BASE SCIF1_BASE +#elif defined (CONFIG_CONS_SCIF2) +#define SCIF_BASE SCIF2_BASE #else #error "Default SCIF doesn't set....." #endif @@ -36,17 +38,17 @@ #define SCSCR (vu_short *)(SCIF_BASE + 0x8) #define SCFCR (vu_short *)(SCIF_BASE + 0x18) #define SCFDR (vu_short *)(SCIF_BASE + 0x1C) -#ifdef CONFIG_CPU_SH7720 /* SH7720 specific */ -# define SCFSR (vu_short *)(SCIF_BASE + 0x14) /* SCSSR */ +#ifdef CONFIG_CPU_SH7720 /* SH7720 specific */ +# define SCFSR (vu_short *)(SCIF_BASE + 0x14) /* SCSSR */ # define SCFTDR (vu_char *)(SCIF_BASE + 0x20) # define SCFRDR (vu_char *)(SCIF_BASE + 0x24) #else # define SCFTDR (vu_char *)(SCIF_BASE + 0xC) -# define SCFSR (vu_short *)(SCIF_BASE + 0x10) +# define SCFSR (vu_short *)(SCIF_BASE + 0x10) # define SCFRDR (vu_char *)(SCIF_BASE + 0x14) #endif -#if defined(CONFIG_CPU_SH7780) || \ +#if defined(CONFIG_CPU_SH7780) || \ defined(CONFIG_CPU_SH7785) # define SCRFDR (vu_short *)(SCIF_BASE + 0x20) # define SCSPTR (vu_short *)(SCIF_BASE + 0x24) @@ -54,20 +56,34 @@ # define SCRER (vu_short *)(SCIF_BASE + 0x2C) # define LSR_ORER 1 # define FIFOLEVEL_MASK 0xFF +#elif defined(CONFIG_CPU_SH7763) +# if defined (CONFIG_CONS_SCIF2) +# define SCSPTR (vu_short *)(SCIF_BASE + 0x20) +# define SCLSR (vu_short *)(SCIF_BASE + 0x24) +# define LSR_ORER 1 +# define FIFOLEVEL_MASK 0x1F +# else +# define SCRFDR (vu_short *)(SCIF_BASE + 0x20) +# define SCSPTR (vu_short *)(SCIF_BASE + 0x24) +# define SCLSR (vu_short *)(SCIF_BASE + 0x28) +# define SCRER (vu_short *)(SCIF_BASE + 0x2C) +# define LSR_ORER 1 +# define FIFOLEVEL_MASK 0xFF +# endif #elif defined(CONFIG_CPU_SH7750) || \ defined(CONFIG_CPU_SH7751) || \ defined(CONFIG_CPU_SH7722) # define SCSPTR (vu_short *)(SCIF_BASE + 0x20) -# define SCLSR (vu_short *)(SCIF_BASE + 0x24) +# define SCLSR (vu_short *)(SCIF_BASE + 0x24) # define LSR_ORER 1 # define FIFOLEVEL_MASK 0x1F #elif defined(CONFIG_CPU_SH7720) -# define SCLSR (vu_short *)(SCIF_BASE + 0x24) +# define SCLSR (vu_short *)(SCIF_BASE + 0x24) # define LSR_ORER 0x0200 # define FIFOLEVEL_MASK 0x1F -#elif defined(CONFIG_CPU_SH7710) +#elif defined(CONFIG_CPU_SH7710) || \ defined(CONFIG_CPU_SH7712) -# define SCLSR SCFSR /* SCSSR */ +# define SCLSR SCFSR /* SCSSR */ # define LSR_ORER 1 # define FIFOLEVEL_MASK 0x1F #endif @@ -75,34 +91,34 @@ /* SCBRR register value setting */ #if defined(CONFIG_CPU_SH7720) # define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1) -#else /* Generic SuperH */ +#else /* Generic SuperH */ # define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(32*bps)-1) #endif -#define SCR_RE (1 << 4) -#define SCR_TE (1 << 5) -#define FCR_RFRST (1 << 1) /* RFCL */ -#define FCR_TFRST (1 << 2) /* TFCL */ -#define FSR_DR (1 << 0) -#define FSR_RDF (1 << 1) -#define FSR_FER (1 << 3) -#define FSR_BRK (1 << 4) -#define FSR_FER (1 << 3) -#define FSR_TEND (1 << 6) -#define FSR_ER (1 << 7) +#define SCR_RE (1 << 4) +#define SCR_TE (1 << 5) +#define FCR_RFRST (1 << 1) /* RFCL */ +#define FCR_TFRST (1 << 2) /* TFCL */ +#define FSR_DR (1 << 0) +#define FSR_RDF (1 << 1) +#define FSR_FER (1 << 3) +#define FSR_BRK (1 << 4) +#define FSR_FER (1 << 3) +#define FSR_TEND (1 << 6) +#define FSR_ER (1 << 7) /*----------------------------------------------------------------------*/ -void serial_setbrg (void) +void serial_setbrg(void) { DECLARE_GLOBAL_DATA_PTR; - *SCBRR = SCBRR_VALUE(gd->baudrate,CONFIG_SYS_CLK_FREQ); + *SCBRR = SCBRR_VALUE(gd->baudrate, CONFIG_SYS_CLK_FREQ); } -int serial_init (void) +int serial_init(void) { *SCSCR = (SCR_RE | SCR_TE); - *SCSMR = 0 ; + *SCSMR = 0; *SCSMR = 0; *SCFCR = (FCR_RFRST | FCR_TFRST); *SCFCR; @@ -112,21 +128,21 @@ int serial_init (void) return 0; } -static int serial_rx_fifo_level (void) +static int serial_rx_fifo_level(void) { -#if defined(CONFIG_SH4A) +#if defined(SCRFDR) return (*SCRFDR >> 0) & FIFOLEVEL_MASK; #else return (*SCFDR >> 0) & FIFOLEVEL_MASK; #endif } -void serial_raw_putc (const char c) +void serial_raw_putc(const char c) { unsigned int fsr_bits_to_clear; while (1) { - if (*SCFSR & FSR_TEND) { /* Tx fifo is empty */ + if (*SCFSR & FSR_TEND) { /* Tx fifo is empty */ fsr_bits_to_clear = FSR_TEND; break; } @@ -137,65 +153,67 @@ void serial_raw_putc (const char c) *SCFSR &= ~fsr_bits_to_clear; } -void serial_putc (const char c) +void serial_putc(const char c) { if (c == '\n') - serial_raw_putc ('\r'); - serial_raw_putc (c); + serial_raw_putc('\r'); + serial_raw_putc(c); } -void serial_puts (const char *s) +void serial_puts(const char *s) { char c; while ((c = *s++) != 0) - serial_putc (c); + serial_putc(c); } -int serial_tstc (void) +int serial_tstc(void) { - return serial_rx_fifo_level() ? 1 : 0; + return serial_rx_fifo_level()? 1 : 0; } -#define FSR_ERR_CLEAR 0x0063 -#define RDRF_CLEAR 0x00fc -void handle_error( void ){ +#define FSR_ERR_CLEAR 0x0063 +#define RDRF_CLEAR 0x00fc +void handle_error(void) +{ - (void)*SCFSR ; - *SCFSR = FSR_ERR_CLEAR ; - (void)*SCLSR ; - *SCLSR = 0x00 ; + (void)*SCFSR; + *SCFSR = FSR_ERR_CLEAR; + (void)*SCLSR; + *SCLSR = 0x00; } -int serial_getc_check( void ){ +int serial_getc_check(void) +{ unsigned short status; - status = *SCFSR ; + status = *SCFSR; - if (status & (FSR_FER | FSR_FER | FSR_ER | FSR_BRK)) + if (status & (FSR_FER | FSR_ER | FSR_BRK)) handle_error(); - if( *SCLSR & LSR_ORER ) + if (*SCLSR & LSR_ORER) handle_error(); - return (status & ( FSR_DR | FSR_RDF )); + return (status & (FSR_DR | FSR_RDF)); } -int serial_getc (void) +int serial_getc(void) { - unsigned short status ; + unsigned short status; char ch; - while(!serial_getc_check()); + while (!serial_getc_check()) ; ch = *SCFRDR; - status = *SCFSR ; + status = *SCFSR; - *SCFSR = RDRF_CLEAR ; + *SCFSR = RDRF_CLEAR; if (status & (FSR_FER | FSR_FER | FSR_ER | FSR_BRK)) handle_error(); - if( *SCLSR & LSR_ORER ) + if (*SCLSR & LSR_ORER) handle_error(); - return ch ; + return ch; } -#endif /* CFG_SCIF_CONSOLE */ +#endif /* CFG_SCIF_CONSOLE */ diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index bc8a104..4f7b679 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -25,7 +25,8 @@ 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 COBJS := $(COBJS-y) diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c new file mode 100644 index 0000000..317c0b4 --- /dev/null +++ b/drivers/spi/atmel_spi.c @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2007 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 <spi.h> +#include <malloc.h> + +#include <asm/io.h> + +#include <asm/arch/clk.h> +#include <asm/arch/memory-map.h> + +#include "atmel_spi.h" + +void spi_init() +{ + +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct atmel_spi_slave *as; + unsigned int scbr; + u32 csrx; + void *regs; + + if (cs > 3 || !spi_cs_is_valid(bus, cs)) + return NULL; + + switch (bus) { + case 0: + regs = (void *)SPI0_BASE; + break; +#ifdef SPI1_BASE + case 1: + regs = (void *)SPI1_BASE; + break; +#endif +#ifdef SPI2_BASE + case 2: + regs = (void *)SPI2_BASE; + break; +#endif +#ifdef SPI3_BASE + case 3: + regs = (void *)SPI3_BASE; + break; +#endif + default: + return NULL; + } + + + scbr = (get_spi_clk_rate(bus) + max_hz - 1) / max_hz; + if (scbr > ATMEL_SPI_CSRx_SCBR_MAX) + /* Too low max SCK rate */ + return NULL; + if (scbr < 1) + scbr = 1; + + csrx = ATMEL_SPI_CSRx_SCBR(scbr); + csrx |= ATMEL_SPI_CSRx_BITS(ATMEL_SPI_BITS_8); + if (!(mode & SPI_CPHA)) + csrx |= ATMEL_SPI_CSRx_NCPHA; + if (mode & SPI_CPOL) + csrx |= ATMEL_SPI_CSRx_CPOL; + + as = malloc(sizeof(struct atmel_spi_slave)); + if (!as) + return NULL; + + as->slave.bus = bus; + as->slave.cs = cs; + as->regs = regs; + as->mr = ATMEL_SPI_MR_MSTR | ATMEL_SPI_MR_MODFDIS + | ATMEL_SPI_MR_PCS(~(1 << cs) & 0xf); + spi_writel(as, CSR(cs), csrx); + + return &as->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + struct atmel_spi_slave *as = to_atmel_spi(slave); + + free(as); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + struct atmel_spi_slave *as = to_atmel_spi(slave); + + /* Enable the SPI hardware */ + spi_writel(as, CR, ATMEL_SPI_CR_SPIEN); + + /* + * Select the slave. This should set SCK to the correct + * initial state, etc. + */ + spi_writel(as, MR, as->mr); + + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + struct atmel_spi_slave *as = to_atmel_spi(slave); + + /* Disable the SPI hardware */ + spi_writel(as, CR, ATMEL_SPI_CR_SPIDIS); +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct atmel_spi_slave *as = to_atmel_spi(slave); + unsigned int len_tx; + unsigned int len_rx; + unsigned int len; + int ret; + u32 status; + const u8 *txp = dout; + u8 *rxp = din; + u8 value; + + ret = 0; + if (bitlen == 0) + /* Finish any previously submitted transfers */ + goto out; + + /* + * TODO: The controller can do non-multiple-of-8 bit + * transfers, but this driver currently doesn't support it. + * + * It's also not clear how such transfers are supposed to be + * represented as a stream of bytes...this is a limitation of + * the current SPI interface. + */ + if (bitlen % 8) { + /* Errors always terminate an ongoing transfer */ + flags |= SPI_XFER_END; + goto out; + } + + len = bitlen / 8; + + /* + * The controller can do automatic CS control, but it is + * somewhat quirky, and it doesn't really buy us much anyway + * in the context of U-Boot. + */ + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); + + for (len_tx = 0, len_rx = 0; len_rx < len; ) { + status = spi_readl(as, SR); + + if (status & ATMEL_SPI_SR_OVRES) + return -1; + + if (len_tx < len && (status & ATMEL_SPI_SR_TDRE)) { + if (txp) + value = *txp++; + else + value = 0; + spi_writel(as, TDR, value); + len_tx++; + } + if (status & ATMEL_SPI_SR_RDRF) { + value = spi_readl(as, RDR); + if (rxp) + *rxp++ = value; + len_rx++; + } + } + +out: + if (flags & SPI_XFER_END) { + /* + * Wait until the transfer is completely done before + * we deactivate CS. + */ + do { + status = spi_readl(as, SR); + } while (!(status & ATMEL_SPI_SR_TXEMPTY)); + + spi_cs_deactivate(slave); + } + + return 0; +} diff --git a/drivers/spi/atmel_spi.h b/drivers/spi/atmel_spi.h new file mode 100644 index 0000000..8b69a6d --- /dev/null +++ b/drivers/spi/atmel_spi.h @@ -0,0 +1,95 @@ +/* + * Register definitions for the Atmel AT32/AT91 SPI Controller + */ + +/* Register offsets */ +#define ATMEL_SPI_CR 0x0000 +#define ATMEL_SPI_MR 0x0004 +#define ATMEL_SPI_RDR 0x0008 +#define ATMEL_SPI_TDR 0x000c +#define ATMEL_SPI_SR 0x0010 +#define ATMEL_SPI_IER 0x0014 +#define ATMEL_SPI_IDR 0x0018 +#define ATMEL_SPI_IMR 0x001c +#define ATMEL_SPI_CSR(x) (0x0030 + 4 * (x)) +#define ATMEL_SPI_VERSION 0x00fc + +/* Bits in CR */ +#define ATMEL_SPI_CR_SPIEN (1 << 0) +#define ATMEL_SPI_CR_SPIDIS (1 << 1) +#define ATMEL_SPI_CR_SWRST (1 << 7) +#define ATMEL_SPI_CR_LASTXFER (1 << 24) + +/* Bits in MR */ +#define ATMEL_SPI_MR_MSTR (1 << 0) +#define ATMEL_SPI_MR_PS (1 << 1) +#define ATMEL_SPI_MR_PCSDEC (1 << 2) +#define ATMEL_SPI_MR_FDIV (1 << 3) +#define ATMEL_SPI_MR_MODFDIS (1 << 4) +#define ATMEL_SPI_MR_LLB (1 << 7) +#define ATMEL_SPI_MR_PCS(x) (((x) & 15) << 16) +#define ATMEL_SPI_MR_DLYBCS(x) ((x) << 24) + +/* Bits in RDR */ +#define ATMEL_SPI_RDR_RD(x) (x) +#define ATMEL_SPI_RDR_PCS(x) ((x) << 16) + +/* Bits in TDR */ +#define ATMEL_SPI_TDR_TD(x) (x) +#define ATMEL_SPI_TDR_PCS(x) ((x) << 16) +#define ATMEL_SPI_TDR_LASTXFER (1 << 24) + +/* Bits in SR/IER/IDR/IMR */ +#define ATMEL_SPI_SR_RDRF (1 << 0) +#define ATMEL_SPI_SR_TDRE (1 << 1) +#define ATMEL_SPI_SR_MODF (1 << 2) +#define ATMEL_SPI_SR_OVRES (1 << 3) +#define ATMEL_SPI_SR_ENDRX (1 << 4) +#define ATMEL_SPI_SR_ENDTX (1 << 5) +#define ATMEL_SPI_SR_RXBUFF (1 << 6) +#define ATMEL_SPI_SR_TXBUFE (1 << 7) +#define ATMEL_SPI_SR_NSSR (1 << 8) +#define ATMEL_SPI_SR_TXEMPTY (1 << 9) +#define ATMEL_SPI_SR_SPIENS (1 << 16) + +/* Bits in CSRx */ +#define ATMEL_SPI_CSRx_CPOL (1 << 0) +#define ATMEL_SPI_CSRx_NCPHA (1 << 1) +#define ATMEL_SPI_CSRx_CSAAT (1 << 3) +#define ATMEL_SPI_CSRx_BITS(x) ((x) << 4) +#define ATMEL_SPI_CSRx_SCBR(x) ((x) << 8) +#define ATMEL_SPI_CSRx_SCBR_MAX 0xff +#define ATMEL_SPI_CSRx_DLYBS(x) ((x) << 16) +#define ATMEL_SPI_CSRx_DLYBCT(x) ((x) << 24) + +/* Bits in VERSION */ +#define ATMEL_SPI_VERSION_REV(x) ((x) << 0) +#define ATMEL_SPI_VERSION_MFN(x) ((x) << 16) + +/* Constants for CSRx:BITS */ +#define ATMEL_SPI_BITS_8 0 +#define ATMEL_SPI_BITS_9 1 +#define ATMEL_SPI_BITS_10 2 +#define ATMEL_SPI_BITS_11 3 +#define ATMEL_SPI_BITS_12 4 +#define ATMEL_SPI_BITS_13 5 +#define ATMEL_SPI_BITS_14 6 +#define ATMEL_SPI_BITS_15 7 +#define ATMEL_SPI_BITS_16 8 + +struct atmel_spi_slave { + struct spi_slave slave; + void *regs; + u32 mr; +}; + +static inline struct atmel_spi_slave *to_atmel_spi(struct spi_slave *slave) +{ + return container_of(slave, struct atmel_spi_slave, slave); +} + +/* Register access macros */ +#define spi_readl(as, reg) \ + readl(as->regs + ATMEL_SPI_##reg) +#define spi_writel(as, reg, value) \ + writel(value, as->regs + ATMEL_SPI_##reg) diff --git a/drivers/spi/mpc8xxx_spi.c b/drivers/spi/mpc8xxx_spi.c index 2fe838c..9eaf986 100644 --- a/drivers/spi/mpc8xxx_spi.c +++ b/drivers/spi/mpc8xxx_spi.c @@ -22,8 +22,8 @@ */ #include <common.h> -#if defined(CONFIG_MPC8XXX_SPI) && defined(CONFIG_HARD_SPI) +#include <malloc.h> #include <spi.h> #include <asm/mpc8xxx_spi.h> @@ -37,6 +37,34 @@ #define SPI_TIMEOUT 1000 +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct spi_slave *slave; + + if (!spi_cs_is_valid(bus, cs)) + return NULL; + + slave = malloc(sizeof(struct spi_slave)); + if (!slave) + return NULL; + + slave->bus = bus; + slave->cs = cs; + + /* + * TODO: Some of the code in spi_init() should probably move + * here, or into spi_claim_bus() below. + */ + + return slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + free(slave); +} + void spi_init(void) { volatile spi8xxx_t *spi = &((immap_t *) (CFG_IMMR))->spi; @@ -53,7 +81,18 @@ void spi_init(void) spi->com = 0; /* LST bit doesn't do anything, so disregard */ } -int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) +int spi_claim_bus(struct spi_slave *slave) +{ + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, + void *din, unsigned long flags) { volatile spi8xxx_t *spi = &((immap_t *) (CFG_IMMR))->spi; unsigned int tmpdout, tmpdin, event; @@ -61,11 +100,11 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) int tm, isRead = 0; unsigned char charSize = 32; - debug("spi_xfer: chipsel %08X dout %08X din %08X bitlen %d\n", - (int)chipsel, *(uint *) dout, *(uint *) din, bitlen); + debug("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n", + slave->bus, slave->cs, *(uint *) dout, *(uint *) din, bitlen); - if (chipsel != NULL) - (*chipsel) (1); /* select the target chip */ + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); spi->event = 0xffffffff; /* Clear all SPI events */ @@ -135,9 +174,8 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) debug("*** spi_xfer: transfer ended. Value=%08x\n", tmpdin); } - if (chipsel != NULL) - (*chipsel) (0); /* deselect the target chip */ + if (flags & SPI_XFER_END) + spi_cs_deactivate(slave); return 0; } -#endif /* CONFIG_HARD_SPI */ diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index c166ec5..5957ada 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -19,6 +19,7 @@ */ #include <common.h> +#include <malloc.h> #include <spi.h> #include <asm/io.h> @@ -61,17 +62,18 @@ static unsigned long spi_bases[] = { 0x53f84000, }; -static unsigned long spi_base; - #endif -spi_chipsel_type spi_chipsel[] = { - (spi_chipsel_type)0, - (spi_chipsel_type)1, - (spi_chipsel_type)2, - (spi_chipsel_type)3, +struct mxc_spi_slave { + struct spi_slave slave; + unsigned long base; + u32 ctrl_reg; }; -int spi_chipsel_cnt = sizeof(spi_chipsel) / sizeof(spi_chipsel[0]); + +static inline struct mxc_spi_slave *to_mxc_spi_slave(struct spi_slave *slave) +{ + return container_of(slave, struct mxc_spi_slave, slave); +} static inline u32 reg_read(unsigned long addr) { @@ -83,30 +85,31 @@ static inline void reg_write(unsigned long addr, u32 val) *(volatile unsigned long*)addr = val; } -static u32 spi_xchg_single(u32 data, int bitlen) +static u32 spi_xchg_single(struct spi_slave *slave, u32 data, int bitlen) { - - unsigned int cfg_reg = reg_read(spi_base + MXC_CSPICTRL); + struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); + unsigned int cfg_reg = reg_read(mxcs->base + MXC_CSPICTRL); if (MXC_CSPICTRL_BITCOUNT(bitlen - 1) != (cfg_reg & MXC_CSPICTRL_BITCOUNT(31))) { cfg_reg = (cfg_reg & ~MXC_CSPICTRL_BITCOUNT(31)) | MXC_CSPICTRL_BITCOUNT(bitlen - 1); - reg_write(spi_base + MXC_CSPICTRL, cfg_reg); + reg_write(mxcs->base + MXC_CSPICTRL, cfg_reg); } - reg_write(spi_base + MXC_CSPITXDATA, data); + reg_write(mxcs->base + MXC_CSPITXDATA, data); cfg_reg |= MXC_CSPICTRL_XCH; - reg_write(spi_base + MXC_CSPICTRL, cfg_reg); + reg_write(mxcs->base + MXC_CSPICTRL, cfg_reg); - while (reg_read(spi_base + MXC_CSPICTRL) & MXC_CSPICTRL_XCH) + while (reg_read(mxcs->base + MXC_CSPICTRL) & MXC_CSPICTRL_XCH) ; - return reg_read(spi_base + MXC_CSPIRXDATA); + return reg_read(mxcs->base + MXC_CSPIRXDATA); } -int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, + void *din, unsigned long flags) { int n_blks = (bitlen + 31) / 32; u32 *out_l, *in_l; @@ -117,13 +120,10 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) return 1; } - if (!spi_base) - spi_select(CONFIG_MXC_SPI_IFACE, (int)chipsel, SPI_MODE_2 | SPI_CS_HIGH); - for (i = 0, in_l = (u32 *)din, out_l = (u32 *)dout; i < n_blks; i++, in_l++, out_l++, bitlen -= 32) - *in_l = spi_xchg_single(*out_l, bitlen); + *in_l = spi_xchg_single(slave, *out_l, bitlen); return 0; } @@ -132,17 +132,17 @@ void spi_init(void) { } -int spi_select(unsigned int bus, unsigned int dev, unsigned long mode) +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) { unsigned int ctrl_reg; + struct mxc_spi_slave *mxcs; if (bus >= sizeof(spi_bases) / sizeof(spi_bases[0]) || - dev > 3) - return 1; - - spi_base = spi_bases[bus]; + cs > 3) + return NULL; - ctrl_reg = MXC_CSPICTRL_CHIPSELECT(dev) | + ctrl_reg = MXC_CSPICTRL_CHIPSELECT(cs) | MXC_CSPICTRL_BITCOUNT(31) | MXC_CSPICTRL_DATARATE(7) | /* FIXME: calculate data rate */ MXC_CSPICTRL_EN | @@ -155,12 +155,38 @@ int spi_select(unsigned int bus, unsigned int dev, unsigned long mode) if (mode & SPI_CS_HIGH) ctrl_reg |= MXC_CSPICTRL_SSPOL; - reg_write(spi_base + MXC_CSPIRESET, 1); + mxcs = malloc(sizeof(struct mxc_spi_slave)); + if (!mxcs) + return NULL; + + mxcs->slave.bus = bus; + mxcs->slave.cs = cs; + mxcs->base = spi_bases[bus]; + mxcs->ctrl_reg = ctrl_reg; + + return &mxcs->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + free(slave); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); + + reg_write(mxcs->base + MXC_CSPIRESET, 1); udelay(1); - reg_write(spi_base + MXC_CSPICTRL, ctrl_reg); - reg_write(spi_base + MXC_CSPIPERIOD, + reg_write(mxcs->base + MXC_CSPICTRL, mxcs->ctrl_reg); + reg_write(mxcs->base + MXC_CSPIPERIOD, MXC_CSPIPERIOD_32KHZ); - reg_write(spi_base + MXC_CSPIINT, 0); + reg_write(mxcs->base + MXC_CSPIINT, 0); return 0; } + +void spi_release_bus(struct spi_slave *slave) +{ + /* TODO: Shut the controller down */ +} diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 9d2f65b..20a54c5 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk LIB := $(obj)libvideo.a COBJS-y += ati_radeon_fb.o +COBJS-$(CONFIG_ATMEL_LCD) += atmel_lcdfb.o COBJS-y += cfb_console.o COBJS-y += ct69000.o COBJS-y += mb862xx.o diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c new file mode 100644 index 0000000..27df449 --- /dev/null +++ b/drivers/video/atmel_lcdfb.c @@ -0,0 +1,160 @@ +/* + * Driver for AT91/AT32 LCD Controller + * + * Copyright (C) 2007 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 <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/gpio.h> +#include <asm/arch/clk.h> +#include <lcd.h> +#include <atmel_lcdc.h> + +int lcd_line_length; +int lcd_color_fg; +int lcd_color_bg; + +void *lcd_base; /* Start of framebuffer memory */ +void *lcd_console_address; /* Start of console buffer */ + +short console_col; +short console_row; + +/* configurable parameters */ +#define ATMEL_LCDC_CVAL_DEFAULT 0xc8 +#define ATMEL_LCDC_DMA_BURST_LEN 8 + +#if defined(CONFIG_AT91SAM9263) || defined(CONFIG_AT91CAP9) +#define ATMEL_LCDC_FIFO_SIZE 2048 +#else +#define ATMEL_LCDC_FIFO_SIZE 512 +#endif + +#define lcdc_readl(mmio, reg) __raw_readl((mmio)+(reg)) +#define lcdc_writel(mmio, reg, val) __raw_writel((val), (mmio)+(reg)) + +void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue) +{ +#if defined(CONFIG_ATMEL_LCD_BGR555) + lcdc_writel(panel_info.mmio, ATMEL_LCDC_LUT(regno), + (red >> 3) | ((green & 0xf8) << 2) | ((blue & 0xf8) << 7)); +#else + lcdc_writel(panel_info.mmio, ATMEL_LCDC_LUT(regno), + (blue >> 3) | ((green & 0xfc) << 3) | ((red & 0xf8) << 8)); +#endif +} + +void lcd_ctrl_init(void *lcdbase) +{ + unsigned long value; + + /* Turn off the LCD controller and the DMA controller */ + lcdc_writel(panel_info.mmio, ATMEL_LCDC_PWRCON, + 1 << ATMEL_LCDC_GUARDT_OFFSET); + + /* Wait for the LCDC core to become idle */ + while (lcdc_readl(panel_info.mmio, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY) + udelay(10); + + lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMACON, 0); + + /* Reset LCDC DMA */ + lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMACON, ATMEL_LCDC_DMARST); + + /* ...set frame size and burst length = 8 words (?) */ + value = (panel_info.vl_col * panel_info.vl_row * + NBITS(panel_info.vl_bpix)) / 32; + value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET); + lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMAFRMCFG, value); + + /* Set pixel clock */ + value = get_lcdc_clk_rate(0) / panel_info.vl_clk; + if (get_lcdc_clk_rate(0) % panel_info.vl_clk) + value++; + value = (value / 2) - 1; + + if (!value) { + lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS); + } else + lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCON1, + value << ATMEL_LCDC_CLKVAL_OFFSET); + + /* Initialize control register 2 */ + value = ATMEL_LCDC_MEMOR_LITTLE | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE; + if (panel_info.vl_tft) + value |= ATMEL_LCDC_DISTYPE_TFT; + + if (!(panel_info.vl_sync & ATMEL_LCDC_INVLINE_INVERTED)) + value |= ATMEL_LCDC_INVLINE_INVERTED; + if (!(panel_info.vl_sync & ATMEL_LCDC_INVFRAME_INVERTED)) + value |= ATMEL_LCDC_INVFRAME_INVERTED; + value |= (panel_info.vl_bpix << 5); + lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCON2, value); + + /* Vertical timing */ + value = (panel_info.vl_vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET; + value |= panel_info.vl_upper_margin << ATMEL_LCDC_VBP_OFFSET; + value |= panel_info.vl_lower_margin; + lcdc_writel(panel_info.mmio, ATMEL_LCDC_TIM1, value); + + /* Horizontal timing */ + value = (panel_info.vl_right_margin - 1) << ATMEL_LCDC_HFP_OFFSET; + value |= (panel_info.vl_hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET; + value |= (panel_info.vl_left_margin - 1); + lcdc_writel(panel_info.mmio, ATMEL_LCDC_TIM2, value); + + /* Display size */ + value = (panel_info.vl_col - 1) << ATMEL_LCDC_HOZVAL_OFFSET; + value |= panel_info.vl_row - 1; + lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDFRMCFG, value); + + /* FIFO Threshold: Use formula from data sheet */ + value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3); + lcdc_writel(panel_info.mmio, ATMEL_LCDC_FIFO, value); + + /* Toggle LCD_MODE every frame */ + lcdc_writel(panel_info.mmio, ATMEL_LCDC_MVAL, 0); + + /* Disable all interrupts */ + lcdc_writel(panel_info.mmio, ATMEL_LCDC_IDR, ~0UL); + + /* Set contrast */ + value = ATMEL_LCDC_PS_DIV8 | + ATMEL_LCDC_POL_POSITIVE | + ATMEL_LCDC_ENA_PWMENABLE; + lcdc_writel(panel_info.mmio, ATMEL_LCDC_CONTRAST_CTR, value); + lcdc_writel(panel_info.mmio, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); + + /* Set framebuffer DMA base address and pixel offset */ + lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMABADDR1, (u_long)lcdbase); + + lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMACON, ATMEL_LCDC_DMAEN); + lcdc_writel(panel_info.mmio, ATMEL_LCDC_PWRCON, + (1 << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR); +} + +ulong calc_fbsize(void) +{ + return ((panel_info.vl_col * panel_info.vl_row * + NBITS(panel_info.vl_bpix)) / 8) + PAGE_SIZE; +} |