diff options
Diffstat (limited to 'drivers')
94 files changed, 4616 insertions, 1296 deletions
diff --git a/drivers/block/ata_piix.c b/drivers/block/ata_piix.c index 1c3ab8a733..1e33a66c45 100644 --- a/drivers/block/ata_piix.c +++ b/drivers/block/ata_piix.c @@ -34,17 +34,15 @@ #include <part.h> #include <ide.h> #include <ata.h> +#include <sata.h> -extern block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE]; -extern int sata_curr_device; - -#define DEBUG_SATA 0 /*For debug prints set DEBUG_SATA to 1 */ +#define DEBUG_SATA 0 /* For debug prints set DEBUG_SATA to 1 */ #define SATA_DECL -#define DRV_DECL /*For file specific declarations */ +#define DRV_DECL /* For file specific declarations */ #include "ata_piix.h" -/*Macros realted to PCI*/ +/* Macros realted to PCI */ #define PCI_SATA_BUS 0x00 #define PCI_SATA_DEV 0x1f #define PCI_SATA_FUNC 0x02 @@ -63,35 +61,36 @@ extern int sata_curr_device; #define PORT_ENABLED (1<<4) u32 bdf; -u32 iobase1 = 0; /*Primary cmd block */ -u32 iobase2 = 0; /*Primary ctl block */ -u32 iobase3 = 0; /*Sec cmd block */ -u32 iobase4 = 0; /*sec ctl block */ -u32 iobase5 = 0; /*BMDMA*/ -int -pci_sata_init (void) +u32 iobase1; /* Primary cmd block */ +u32 iobase2; /* Primary ctl block */ +u32 iobase3; /* Sec cmd block */ +u32 iobase4; /* sec ctl block */ +u32 iobase5; /* BMDMA*/ + +int pci_sata_init(void) { u32 bus = PCI_SATA_BUS; u32 dev = PCI_SATA_DEV; u32 fun = PCI_SATA_FUNC; u16 cmd = 0; u8 lat = 0, pcibios_max_latency = 0xff; - u8 pmr; /*Port mapping reg */ - u8 pi; /*Prgming Interface reg */ + u8 pmr; /* Port mapping reg */ + u8 pi; /* Prgming Interface reg */ - bdf = PCI_BDF (bus, dev, fun); - pci_read_config_dword (bdf, PCI_SATA_BASE1, &iobase1); - pci_read_config_dword (bdf, PCI_SATA_BASE2, &iobase2); - pci_read_config_dword (bdf, PCI_SATA_BASE3, &iobase3); - pci_read_config_dword (bdf, PCI_SATA_BASE4, &iobase4); - pci_read_config_dword (bdf, PCI_SATA_BASE5, &iobase5); + bdf = PCI_BDF(bus, dev, fun); + pci_read_config_dword(bdf, PCI_SATA_BASE1, &iobase1); + pci_read_config_dword(bdf, PCI_SATA_BASE2, &iobase2); + pci_read_config_dword(bdf, PCI_SATA_BASE3, &iobase3); + pci_read_config_dword(bdf, PCI_SATA_BASE4, &iobase4); + pci_read_config_dword(bdf, PCI_SATA_BASE5, &iobase5); if ((iobase1 == 0xFFFFFFFF) || (iobase2 == 0xFFFFFFFF) || (iobase3 == 0xFFFFFFFF) || (iobase4 == 0xFFFFFFFF) || (iobase5 == 0xFFFFFFFF)) { - printf ("error no base addr for SATA controller\n"); + /* ERROR */ + printf("error no base addr for SATA controller\n"); return 1; - /*ERROR*/} + } iobase1 &= 0xFFFFFFFE; iobase2 &= 0xFFFFFFFE; @@ -99,44 +98,42 @@ pci_sata_init (void) iobase4 &= 0xFFFFFFFE; iobase5 &= 0xFFFFFFFE; - /*check for mode */ - pci_read_config_byte (bdf, PCI_PMR, &pmr); + /* check for mode */ + pci_read_config_byte(bdf, PCI_PMR, &pmr); if (pmr > 1) { - printf ("combined mode not supported\n"); + puts("combined mode not supported\n"); return 1; } - pci_read_config_byte (bdf, PCI_PI, &pi); + pci_read_config_byte(bdf, PCI_PI, &pi); if ((pi & 0x05) != 0x05) { - printf ("Sata is in Legacy mode\n"); + puts("Sata is in Legacy mode\n"); return 1; - } else { - printf ("sata is in Native mode\n"); - } + } else + puts("sata is in Native mode\n"); - /*MASTER CFG AND IO CFG */ - pci_read_config_word (bdf, PCI_COMMAND, &cmd); + /* MASTER CFG AND IO CFG */ + pci_read_config_word(bdf, PCI_COMMAND, &cmd); cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_IO; - pci_write_config_word (bdf, PCI_COMMAND, cmd); - pci_read_config_byte (dev, PCI_LATENCY_TIMER, &lat); + pci_write_config_word(bdf, PCI_COMMAND, cmd); + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); if (lat < 16) lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; else if (lat > pcibios_max_latency) lat = pcibios_max_latency; - pci_write_config_byte (dev, PCI_LATENCY_TIMER, lat); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); return 0; } -int -sata_bus_probe (int port_no) +int sata_bus_probe(int port_no) { int orig_mask, mask; u16 pcs; mask = (PORT_PRESENT << port_no); - pci_read_config_word (bdf, PCI_PCS, &pcs); + pci_read_config_word(bdf, PCI_PCS, &pcs); orig_mask = (int) pcs & 0xff; if ((orig_mask & mask) != mask) return 0; @@ -144,10 +141,9 @@ sata_bus_probe (int port_no) return 1; } -int -init_sata (int dev) +int init_sata(int dev) { - static int done = 0; + static int done; u8 i, rv = 0; if (!done) @@ -155,9 +151,9 @@ init_sata (int dev) else return 0; - rv = pci_sata_init (); + rv = pci_sata_init(); if (rv == 1) { - printf ("pci initialization failed\n"); + puts("pci initialization failed\n"); return 1; } @@ -174,19 +170,18 @@ init_sata (int dev) port[1].ioaddr.bmdma_addr = iobase5 + 0x8; for (i = 0; i < CONFIG_SYS_SATA_MAXBUS; i++) - sata_port (&port[i].ioaddr); + sata_port(&port[i].ioaddr); for (i = 0; i < CONFIG_SYS_SATA_MAXBUS; i++) { - if (!(sata_bus_probe (i))) { + if (!(sata_bus_probe(i))) { port[i].port_state = 0; - printf ("SATA#%d port is not present \n", i); + printf("SATA#%d port is not present\n", i); } else { - printf ("SATA#%d port is present\n", i); - if (sata_bus_softreset (i)) { + printf("SATA#%d port is present\n", i); + if (sata_bus_softreset(i)) port[i].port_state = 0; - } else { + else port[i].port_state = 1; - } } } @@ -196,47 +191,43 @@ init_sata (int dev) if (port[i].port_state == 0) continue; for (j = 0; j < CONFIG_SYS_SATA_DEVS_PER_BUS; j++) { - sata_identify (i, j); - set_Feature_cmd (i, j); + sata_identify(i, j); + set_Feature_cmd(i, j); devno = i * CONFIG_SYS_SATA_DEVS_PER_BUS + j; if ((sata_dev_desc[devno].lba > 0) && (sata_dev_desc[devno].blksz > 0)) { - dev_print (&sata_dev_desc[devno]); + dev_print(&sata_dev_desc[devno]); /* initialize partition type */ - init_part (&sata_dev_desc[devno]); + init_part(&sata_dev_desc[devno]); } } } return 0; } -static u8 __inline__ -sata_inb (unsigned long ioaddr) +static inline u8 sata_inb(unsigned long ioaddr) { - return inb (ioaddr); + return inb(ioaddr); } -static void __inline__ -sata_outb (unsigned char val, unsigned long ioaddr) +static inline void sata_outb(unsigned char val, unsigned long ioaddr) { - outb (val, ioaddr); + outb(val, ioaddr); } -static void -output_data (struct sata_ioports *ioaddr, ulong * sect_buf, int words) +static void output_data(struct sata_ioports *ioaddr, ulong * sect_buf, + int words) { - outsw (ioaddr->data_addr, sect_buf, words << 1); + outsw(ioaddr->data_addr, sect_buf, words << 1); } -static int -input_data (struct sata_ioports *ioaddr, ulong * sect_buf, int words) +static int input_data(struct sata_ioports *ioaddr, ulong * sect_buf, int words) { - insw (ioaddr->data_addr, sect_buf, words << 1); + insw(ioaddr->data_addr, sect_buf, words << 1); return 0; } -static void -sata_cpy (unsigned char *dst, unsigned char *src, unsigned int len) +static void sata_cpy(unsigned char *dst, unsigned char *src, unsigned int len) { unsigned char *end, *last; @@ -257,41 +248,41 @@ sata_cpy (unsigned char *dst, unsigned char *src, unsigned int len) if (*src++ != ' ') last = dst; } - OUT: +OUT: *last = '\0'; } -int -sata_bus_softreset (int num) +int sata_bus_softreset(int num) { u8 dev = 0, status = 0, i; port[num].dev_mask = 0; for (i = 0; i < CONFIG_SYS_SATA_DEVS_PER_BUS; i++) { - if (!(sata_devchk (&port[num].ioaddr, i))) { - PRINTF ("dev_chk failed for dev#%d\n", i); + if (!(sata_devchk(&port[num].ioaddr, i))) { + debug("dev_chk failed for dev#%d\n", i); } else { port[num].dev_mask |= (1 << i); - PRINTF ("dev_chk passed for dev#%d\n", i); + debug("dev_chk passed for dev#%d\n", i); } } if (!(port[num].dev_mask)) { - printf ("no devices on port%d\n", num); + printf("no devices on port%d\n", num); return 1; } - dev_select (&port[num].ioaddr, dev); + dev_select(&port[num].ioaddr, dev); - port[num].ctl_reg = 0x08; /*Default value of control reg */ - sata_outb (port[num].ctl_reg, port[num].ioaddr.ctl_addr); - udelay (10); - sata_outb (port[num].ctl_reg | ATA_SRST, port[num].ioaddr.ctl_addr); - udelay (10); - sata_outb (port[num].ctl_reg, port[num].ioaddr.ctl_addr); + port[num].ctl_reg = 0x08; /* Default value of control reg */ + sata_outb(port[num].ctl_reg, port[num].ioaddr.ctl_addr); + udelay(10); + sata_outb(port[num].ctl_reg | ATA_SRST, port[num].ioaddr.ctl_addr); + udelay(10); + sata_outb(port[num].ctl_reg, port[num].ioaddr.ctl_addr); - /* spec mandates ">= 2ms" before checking status. + /* + * 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 @@ -299,38 +290,37 @@ sata_bus_softreset (int num) * 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); + mdelay(150); + status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 300); while ((status & ATA_BUSY)) { - msleep (100); - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 3); + mdelay(100); + status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 3); } if (status & ATA_BUSY) - printf ("ata%u is slow to respond,plz be patient\n", num); + printf("ata%u is slow to respond,plz be patient\n", num); while ((status & ATA_BUSY)) { - msleep (100); - status = sata_chk_status (&port[num].ioaddr); + mdelay(100); + status = sata_chk_status(&port[num].ioaddr); } if (status & ATA_BUSY) { - printf ("ata%u failed to respond : ", num); - printf ("bus reset failed\n"); + printf("ata%u failed to respond : bus reset failed\n", num); return 1; } return 0; } -void -sata_identify (int num, int dev) +void sata_identify(int num, int dev) { - u8 cmd = 0, status = 0, devno = num * CONFIG_SYS_SATA_DEVS_PER_BUS + dev; + u8 cmd = 0, status = 0; + u8 devno = num * CONFIG_SYS_SATA_DEVS_PER_BUS + dev; u16 iobuf[ATA_SECT_SIZE]; u64 n_sectors = 0; u8 mask = 0; - memset (iobuf, 0, sizeof (iobuf)); + memset(iobuf, 0, sizeof(iobuf)); hd_driveid_t *iop = (hd_driveid_t *) iobuf; if (dev == 0) @@ -339,70 +329,67 @@ sata_identify (int num, int dev) mask = 0x02; if (!(port[num].dev_mask & mask)) { - printf ("dev%d is not present on port#%d\n", dev, num); + printf("dev%d is not present on port#%d\n", dev, num); return; } - printf ("port=%d dev=%d\n", num, dev); + printf("port=%d dev=%d\n", num, dev); - dev_select (&port[num].ioaddr, dev); + dev_select(&port[num].ioaddr, dev); status = 0; - cmd = ATA_CMD_IDENT; /*Device Identify Command */ - sata_outb (cmd, port[num].ioaddr.command_addr); - sata_inb (port[num].ioaddr.altstatus_addr); - udelay (10); + cmd = ATA_CMD_IDENT; /* Device Identify Command */ + sata_outb(cmd, port[num].ioaddr.command_addr); + sata_inb(port[num].ioaddr.altstatus_addr); + udelay(10); - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 1000); + status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 1000); if (status & ATA_ERR) { - printf ("\ndevice not responding\n"); + puts("\ndevice not responding\n"); port[num].dev_mask &= ~mask; return; } - input_data (&port[num].ioaddr, (ulong *) iobuf, ATA_SECTORWORDS); + input_data(&port[num].ioaddr, (ulong *) iobuf, ATA_SECTORWORDS); - PRINTF ("\nata%u: dev %u cfg 49:%04x 82:%04x 83:%04x 84:%04x85:%04x" + debug("\nata%u: dev %u cfg 49:%04x 82:%04x 83:%04x 84:%04x85:%04x" "86:%04x" "87:%04x 88:%04x\n", num, dev, iobuf[49], iobuf[82], iobuf[83], iobuf[84], iobuf[85], iobuf[86], iobuf[87], iobuf[88]); /* we require LBA and DMA support (bits 8 & 9 of word 49) */ - if (!ata_id_has_dma (iobuf) || !ata_id_has_lba (iobuf)) { - PRINTF ("ata%u: no dma/lba\n", num); - } - ata_dump_id (iobuf); + if (!ata_id_has_dma(iobuf) || !ata_id_has_lba(iobuf)) + debug("ata%u: no dma/lba\n", num); + ata_dump_id(iobuf); - if (ata_id_has_lba48 (iobuf)) { - n_sectors = ata_id_u64 (iobuf, 100); - } else { - n_sectors = ata_id_u32 (iobuf, 60); - } - PRINTF ("no. of sectors %u\n", ata_id_u64 (iobuf, 100)); - PRINTF ("no. of sectors %u\n", ata_id_u32 (iobuf, 60)); + if (ata_id_has_lba48(iobuf)) + n_sectors = ata_id_u64(iobuf, 100); + else + n_sectors = ata_id_u32(iobuf, 60); + debug("no. of sectors %u\n", ata_id_u64(iobuf, 100)); + debug("no. of sectors %u\n", ata_id_u32(iobuf, 60)); if (n_sectors == 0) { port[num].dev_mask &= ~mask; return; } - sata_cpy ((unsigned char *)sata_dev_desc[devno].revision, iop->fw_rev, - sizeof (sata_dev_desc[devno].revision)); - sata_cpy ((unsigned char *)sata_dev_desc[devno].vendor, iop->model, - sizeof (sata_dev_desc[devno].vendor)); - sata_cpy ((unsigned char *)sata_dev_desc[devno].product, iop->serial_no, - sizeof (sata_dev_desc[devno].product)); - strswab (sata_dev_desc[devno].revision); - strswab (sata_dev_desc[devno].vendor); + sata_cpy((unsigned char *)sata_dev_desc[devno].revision, iop->fw_rev, + sizeof(sata_dev_desc[devno].revision)); + sata_cpy((unsigned char *)sata_dev_desc[devno].vendor, iop->model, + sizeof(sata_dev_desc[devno].vendor)); + sata_cpy((unsigned char *)sata_dev_desc[devno].product, iop->serial_no, + sizeof(sata_dev_desc[devno].product)); + strswab(sata_dev_desc[devno].revision); + strswab(sata_dev_desc[devno].vendor); - if ((iop->config & 0x0080) == 0x0080) { + if ((iop->config & 0x0080) == 0x0080) sata_dev_desc[devno].removable = 1; - } else { + else sata_dev_desc[devno].removable = 0; - } sata_dev_desc[devno].lba = iop->lba_capacity; - PRINTF ("lba=0x%x", sata_dev_desc[devno].lba); + debug("lba=0x%x", sata_dev_desc[devno].lba); #ifdef CONFIG_LBA48 if (iop->command_set_2 & 0x0400) { @@ -422,8 +409,7 @@ sata_identify (int num, int dev) sata_dev_desc[devno].lun = 0; /* just to fill something in... */ } -void -set_Feature_cmd (int num, int dev) +void set_Feature_cmd(int num, int dev) { u8 mask = 0x00, status = 0; @@ -433,33 +419,32 @@ set_Feature_cmd (int num, int dev) mask = 0x02; if (!(port[num].dev_mask & mask)) { - PRINTF ("dev%d is not present on port#%d\n", dev, num); + debug("dev%d is not present on port#%d\n", dev, num); return; } - dev_select (&port[num].ioaddr, dev); + dev_select(&port[num].ioaddr, dev); - sata_outb (SETFEATURES_XFER, port[num].ioaddr.feature_addr); - sata_outb (XFER_PIO_4, port[num].ioaddr.nsect_addr); - sata_outb (0, port[num].ioaddr.lbal_addr); - sata_outb (0, port[num].ioaddr.lbam_addr); - sata_outb (0, port[num].ioaddr.lbah_addr); + sata_outb(SETFEATURES_XFER, port[num].ioaddr.feature_addr); + sata_outb(XFER_PIO_4, port[num].ioaddr.nsect_addr); + sata_outb(0, port[num].ioaddr.lbal_addr); + sata_outb(0, port[num].ioaddr.lbam_addr); + sata_outb(0, port[num].ioaddr.lbah_addr); - sata_outb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); - sata_outb (ATA_CMD_SETF, port[num].ioaddr.command_addr); + sata_outb(ATA_DEVICE_OBS, port[num].ioaddr.device_addr); + sata_outb(ATA_CMD_SETF, port[num].ioaddr.command_addr); - udelay (50); - msleep (150); + udelay(50); + mdelay(150); - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 5000); + status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 5000); if ((status & (ATA_STAT_BUSY | ATA_STAT_ERR))) { - printf ("Error : status 0x%02x\n", status); + printf("Error : status 0x%02x\n", status); port[num].dev_mask &= ~mask; } } -void -sata_port (struct sata_ioports *ioport) +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; @@ -473,24 +458,23 @@ sata_port (struct sata_ioports *ioport) ioport->command_addr = ioport->cmd_addr + ATA_REG_CMD; } -int -sata_devchk (struct sata_ioports *ioaddr, int dev) +int sata_devchk(struct sata_ioports *ioaddr, int dev) { u8 nsect, lbal; - dev_select (ioaddr, dev); + dev_select(ioaddr, dev); - sata_outb (0x55, ioaddr->nsect_addr); - sata_outb (0xaa, ioaddr->lbal_addr); + sata_outb(0x55, ioaddr->nsect_addr); + sata_outb(0xaa, ioaddr->lbal_addr); - sata_outb (0xaa, ioaddr->nsect_addr); - sata_outb (0x55, ioaddr->lbal_addr); + sata_outb(0xaa, ioaddr->nsect_addr); + sata_outb(0x55, ioaddr->lbal_addr); - sata_outb (0x55, ioaddr->nsect_addr); - sata_outb (0xaa, ioaddr->lbal_addr); + sata_outb(0x55, ioaddr->nsect_addr); + sata_outb(0xaa, ioaddr->lbal_addr); - nsect = sata_inb (ioaddr->nsect_addr); - lbal = sata_inb (ioaddr->lbal_addr); + nsect = sata_inb(ioaddr->nsect_addr); + lbal = sata_inb(ioaddr->lbal_addr); if ((nsect == 0x55) && (lbal == 0xaa)) return 1; /* we found a device */ @@ -498,8 +482,7 @@ sata_devchk (struct sata_ioports *ioaddr, int dev) return 0; /* nothing found */ } -void -dev_select (struct sata_ioports *ioaddr, int dev) +void dev_select(struct sata_ioports *ioaddr, int dev) { u8 tmp = 0; @@ -508,42 +491,31 @@ dev_select (struct sata_ioports *ioaddr, int dev) else tmp = ATA_DEVICE_OBS | ATA_DEV1; - sata_outb (tmp, ioaddr->device_addr); - sata_inb (ioaddr->altstatus_addr); - udelay (5); + sata_outb(tmp, ioaddr->device_addr); + sata_inb(ioaddr->altstatus_addr); + udelay(5); } -u8 -sata_busy_wait (struct sata_ioports *ioaddr, int bits, unsigned int max) +u8 sata_busy_wait(struct sata_ioports *ioaddr, int bits, unsigned int max) { u8 status; do { - udelay (1000); - status = sata_chk_status (ioaddr); + udelay(1000); + status = sata_chk_status(ioaddr); max--; } while ((status & bits) && (max > 0)); return status; } -u8 -sata_chk_status (struct sata_ioports * ioaddr) +u8 sata_chk_status(struct sata_ioports *ioaddr) { - return sata_inb (ioaddr->status_addr); + return sata_inb(ioaddr->status_addr); } -void -msleep (int count) -{ - int i; - for (i = 0; i < count; i++) - udelay (1000); -} - -ulong -sata_read (int device, ulong blknr,lbaint_t blkcnt, void * buff) +ulong sata_read(int device, ulong blknr, lbaint_t blkcnt, void *buff) { ulong n = 0, *buffer = (ulong *)buff; u8 dev = 0, num = 0, mask = 0, status = 0; @@ -553,16 +525,16 @@ sata_read (int device, ulong blknr,lbaint_t blkcnt, void * buff) if (blknr & 0x0000fffff0000000) { if (!sata_dev_desc[devno].lba48) { - printf ("Drive doesn't support 48-bit addressing\n"); + printf("Drive doesn't support 48-bit addressing\n"); return 0; } /* more than 28 bits used, use 48bit mode */ lba48 = 1; } #endif - /*Port Number */ + /* Port Number */ num = device / CONFIG_SYS_SATA_DEVS_PER_BUS; - /*dev on the port */ + /* dev on the port */ if (device >= CONFIG_SYS_SATA_DEVS_PER_BUS) dev = device - CONFIG_SYS_SATA_DEVS_PER_BUS; else @@ -574,73 +546,73 @@ sata_read (int device, ulong blknr,lbaint_t blkcnt, void * buff) mask = 0x02; if (!(port[num].dev_mask & mask)) { - printf ("dev%d is not present on port#%d\n", dev, num); + printf("dev%d is not present on port#%d\n", dev, num); return 0; } /* Select device */ - dev_select (&port[num].ioaddr, dev); + dev_select(&port[num].ioaddr, dev); - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500); + status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 500); if (status & ATA_BUSY) { - printf ("ata%u failed to respond\n", port[num].port_no); + printf("ata%u failed to respond\n", port[num].port_no); return n; } while (blkcnt-- > 0) { - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500); + status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 500); if (status & ATA_BUSY) { - printf ("ata%u failed to respond\n", 0); + printf("ata%u failed to respond\n", 0); return n; } #ifdef CONFIG_LBA48 if (lba48) { /* write high bits */ - sata_outb (0, port[num].ioaddr.nsect_addr); - sata_outb ((blknr >> 24) & 0xFF, + sata_outb(0, port[num].ioaddr.nsect_addr); + sata_outb((blknr >> 24) & 0xFF, port[num].ioaddr.lbal_addr); - sata_outb ((blknr >> 32) & 0xFF, + sata_outb((blknr >> 32) & 0xFF, port[num].ioaddr.lbam_addr); - sata_outb ((blknr >> 40) & 0xFF, + sata_outb((blknr >> 40) & 0xFF, port[num].ioaddr.lbah_addr); } #endif - sata_outb (1, port[num].ioaddr.nsect_addr); - sata_outb (((blknr) >> 0) & 0xFF, + sata_outb(1, port[num].ioaddr.nsect_addr); + sata_outb(((blknr) >> 0) & 0xFF, port[num].ioaddr.lbal_addr); - sata_outb ((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr); - sata_outb ((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr); + sata_outb((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr); + sata_outb((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr); #ifdef CONFIG_LBA48 if (lba48) { - sata_outb (ATA_LBA, port[num].ioaddr.device_addr); - sata_outb (ATA_CMD_READ_EXT, + sata_outb(ATA_LBA, port[num].ioaddr.device_addr); + sata_outb(ATA_CMD_READ_EXT, port[num].ioaddr.command_addr); } else #endif { - sata_outb (ATA_LBA | ((blknr >> 24) & 0xF), + sata_outb(ATA_LBA | ((blknr >> 24) & 0xF), port[num].ioaddr.device_addr); - sata_outb (ATA_CMD_READ, + sata_outb(ATA_CMD_READ, port[num].ioaddr.command_addr); } - msleep (50); - /*may take up to 4 sec */ - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 4000); + mdelay(50); + /* may take up to 4 sec */ + status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 4000); if ((status & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) != ATA_STAT_DRQ) { u8 err = 0; - printf ("Error no DRQ dev %d blk %ld: sts 0x%02x\n", + printf("Error no DRQ dev %d blk %ld: sts 0x%02x\n", device, (ulong) blknr, status); - err = sata_inb (port[num].ioaddr.error_addr); - printf ("Error reg = 0x%x\n", err); - return (n); + err = sata_inb(port[num].ioaddr.error_addr); + printf("Error reg = 0x%x\n", err); + return n; } - input_data (&port[num].ioaddr, buffer, ATA_SECTORWORDS); - sata_inb (port[num].ioaddr.altstatus_addr); - udelay (50); + input_data(&port[num].ioaddr, buffer, ATA_SECTORWORDS); + sata_inb(port[num].ioaddr.altstatus_addr); + udelay(50); ++n; ++blknr; @@ -649,8 +621,7 @@ sata_read (int device, ulong blknr,lbaint_t blkcnt, void * buff) return n; } -ulong -sata_write (int device, ulong blknr,lbaint_t blkcnt, void * buff) +ulong sata_write(int device, ulong blknr, lbaint_t blkcnt, const void *buff) { ulong n = 0, *buffer = (ulong *)buff; unsigned char status = 0, num = 0, dev = 0, mask = 0; @@ -660,16 +631,16 @@ sata_write (int device, ulong blknr,lbaint_t blkcnt, void * buff) if (blknr & 0x0000fffff0000000) { if (!sata_dev_desc[devno].lba48) { - printf ("Drive doesn't support 48-bit addressing\n"); + printf("Drive doesn't support 48-bit addressing\n"); return 0; } /* more than 28 bits used, use 48bit mode */ lba48 = 1; } #endif - /*Port Number */ + /* Port Number */ num = device / CONFIG_SYS_SATA_DEVS_PER_BUS; - /*dev on the Port */ + /* dev on the Port */ if (device >= CONFIG_SYS_SATA_DEVS_PER_BUS) dev = device - CONFIG_SYS_SATA_DEVS_PER_BUS; else @@ -681,64 +652,64 @@ sata_write (int device, ulong blknr,lbaint_t blkcnt, void * buff) mask = 0x02; /* Select device */ - dev_select (&port[num].ioaddr, dev); + dev_select(&port[num].ioaddr, dev); - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500); + status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 500); if (status & ATA_BUSY) { - printf ("ata%u failed to respond\n", port[num].port_no); + printf("ata%u failed to respond\n", port[num].port_no); return n; } while (blkcnt-- > 0) { - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500); + status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 500); if (status & ATA_BUSY) { - printf ("ata%u failed to respond\n", + printf("ata%u failed to respond\n", port[num].port_no); return n; } #ifdef CONFIG_LBA48 if (lba48) { /* write high bits */ - sata_outb (0, port[num].ioaddr.nsect_addr); - sata_outb ((blknr >> 24) & 0xFF, + sata_outb(0, port[num].ioaddr.nsect_addr); + sata_outb((blknr >> 24) & 0xFF, port[num].ioaddr.lbal_addr); - sata_outb ((blknr >> 32) & 0xFF, + sata_outb((blknr >> 32) & 0xFF, port[num].ioaddr.lbam_addr); - sata_outb ((blknr >> 40) & 0xFF, + sata_outb((blknr >> 40) & 0xFF, port[num].ioaddr.lbah_addr); } #endif - sata_outb (1, port[num].ioaddr.nsect_addr); - sata_outb ((blknr >> 0) & 0xFF, port[num].ioaddr.lbal_addr); - sata_outb ((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr); - sata_outb ((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr); + sata_outb(1, port[num].ioaddr.nsect_addr); + sata_outb((blknr >> 0) & 0xFF, port[num].ioaddr.lbal_addr); + sata_outb((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr); + sata_outb((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr); #ifdef CONFIG_LBA48 if (lba48) { - sata_outb (ATA_LBA, port[num].ioaddr.device_addr); - sata_outb (ATA_CMD_WRITE_EXT, + sata_outb(ATA_LBA, port[num].ioaddr.device_addr); + sata_outb(ATA_CMD_WRITE_EXT, port[num].ioaddr.command_addr); } else #endif { - sata_outb (ATA_LBA | ((blknr >> 24) & 0xF), + sata_outb(ATA_LBA | ((blknr >> 24) & 0xF), port[num].ioaddr.device_addr); - sata_outb (ATA_CMD_WRITE, + sata_outb(ATA_CMD_WRITE, port[num].ioaddr.command_addr); } - msleep (50); - /*may take up to 4 sec */ - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 4000); + mdelay(50); + /* may take up to 4 sec */ + status = sata_busy_wait(&port[num].ioaddr, ATA_BUSY, 4000); if ((status & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) != ATA_STAT_DRQ) { - printf ("Error no DRQ dev %d blk %ld: sts 0x%02x\n", + printf("Error no DRQ dev %d blk %ld: sts 0x%02x\n", device, (ulong) blknr, status); - return (n); + return n; } - output_data (&port[num].ioaddr, buffer, ATA_SECTORWORDS); - sata_inb (port[num].ioaddr.altstatus_addr); - udelay (50); + output_data(&port[num].ioaddr, buffer, ATA_SECTORWORDS); + sata_inb(port[num].ioaddr.altstatus_addr); + udelay(50); ++n; ++blknr; diff --git a/drivers/block/ata_piix.h b/drivers/block/ata_piix.h index 9157cf82c0..6c68ea2f01 100644 --- a/drivers/block/ata_piix.h +++ b/drivers/block/ata_piix.h @@ -1,12 +1,6 @@ #ifndef __ATA_PIIX_H__ #define __ATA_PIIX_H__ -#if (DEBUG_SATA) -#define PRINTF(fmt,args...) printf (fmt ,##args) -#else -#define PRINTF(fmt,args...) -#endif - struct sata_ioports { unsigned long cmd_addr; unsigned long data_addr; @@ -36,45 +30,41 @@ struct sata_port { }; /***********SATA LIBRARY SPECIFIC DEFINITIONS AND DECLARATIONS**************/ -#ifdef SATA_DECL /*SATA library specific declarations */ -inline void -ata_dump_id (u16 * id) +#ifdef SATA_DECL /* SATA library specific declarations */ +inline void ata_dump_id(u16 *id) { - PRINTF ("49 = 0x%04x " + debug("49 = 0x%04x " "53 = 0x%04x " "63 = 0x%04x " "64 = 0x%04x " - "75 = 0x%04x \n", id[49], id[53], id[63], id[64], id[75]); - PRINTF ("80 = 0x%04x " + "75 = 0x%04x\n", id[49], id[53], id[63], id[64], id[75]); + debug("80 = 0x%04x " "81 = 0x%04x " "82 = 0x%04x " "83 = 0x%04x " - "84 = 0x%04x \n", id[80], id[81], id[82], id[83], id[84]); - PRINTF ("88 = 0x%04x " "93 = 0x%04x\n", id[88], id[93]); + "84 = 0x%04x\n", id[80], id[81], id[82], id[83], id[84]); + debug("88 = 0x%04x " "93 = 0x%04x\n", id[88], id[93]); } #endif #ifdef SATA_DECL /*SATA library specific declarations */ -int sata_bus_softreset (int num); -void sata_identify (int num, int dev); -void sata_port (struct sata_ioports *ioport); -void set_Feature_cmd (int num, int dev); -int sata_devchk (struct sata_ioports *ioaddr, int dev); -void dev_select (struct sata_ioports *ioaddr, int dev); -u8 sata_busy_wait (struct sata_ioports *ioaddr, int bits, unsigned int max); -u8 sata_chk_status (struct sata_ioports *ioaddr); -ulong sata_read (int device, ulong blknr,lbaint_t blkcnt, void * buffer); -ulong sata_write (int device,ulong blknr, lbaint_t blkcnt, void * buffer); -void msleep (int count); +int sata_bus_softreset(int num); +void sata_identify(int num, int dev); +void sata_port(struct sata_ioports *ioport); +void set_Feature_cmd(int num, int dev); +int sata_devchk(struct sata_ioports *ioaddr, int dev); +void dev_select(struct sata_ioports *ioaddr, int dev); +u8 sata_busy_wait(struct sata_ioports *ioaddr, int bits, unsigned int max); +u8 sata_chk_status(struct sata_ioports *ioaddr); #endif /************DRIVER SPECIFIC DEFINITIONS AND DECLARATIONS**************/ -#ifdef DRV_DECL /*Driver specific declaration */ -int init_sata (int dev); +#ifdef DRV_DECL /* Driver specific declaration */ +int init_sata(int dev); #endif -#ifdef DRV_DECL /*Defines Driver Specific variables */ +#ifdef DRV_DECL /* Defines Driver Specific variables */ struct sata_port port[CONFIG_SYS_SATA_MAXBUS]; #endif diff --git a/drivers/block/dwc_ahsata.c b/drivers/block/dwc_ahsata.c index 2703d3dc84..c9b71f7e1f 100644 --- a/drivers/block/dwc_ahsata.c +++ b/drivers/block/dwc_ahsata.c @@ -24,6 +24,7 @@ #include <libata.h> #include <ahci.h> #include <fis.h> +#include <sata.h> #include <common.h> #include <malloc.h> @@ -794,7 +795,7 @@ static void dwc_ahsata_init_wcache(int dev, u16 *id) } u32 ata_low_level_rw_lba48(int dev, u32 blknr, lbaint_t blkcnt, - void *buffer, int is_write) + const void *buffer, int is_write) { u32 start, blks; u8 *addr; @@ -828,7 +829,7 @@ u32 ata_low_level_rw_lba48(int dev, u32 blknr, lbaint_t blkcnt, } u32 ata_low_level_rw_lba28(int dev, u32 blknr, lbaint_t blkcnt, - void *buffer, int is_write) + const void *buffer, int is_write) { u32 start, blks; u8 *addr; @@ -863,7 +864,7 @@ u32 ata_low_level_rw_lba28(int dev, u32 blknr, lbaint_t blkcnt, /* * SATA interface between low level driver and command layer */ -ulong sata_read(int dev, unsigned long blknr, lbaint_t blkcnt, void *buffer) +ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) { u32 rc; @@ -876,7 +877,7 @@ ulong sata_read(int dev, unsigned long blknr, lbaint_t blkcnt, void *buffer) return rc; } -ulong sata_write(int dev, unsigned long blknr, lbaint_t blkcnt, void *buffer) +ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) { u32 rc; struct ahci_probe_ent *probe_ent = diff --git a/drivers/block/dwc_ahsata.h b/drivers/block/dwc_ahsata.h index 84860ea492..4dac5dcae2 100644 --- a/drivers/block/dwc_ahsata.h +++ b/drivers/block/dwc_ahsata.h @@ -330,6 +330,4 @@ #define READ_CMD 0 #define WRITE_CMD 1 -extern block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE]; - #endif /* __FSL_SATA_H__ */ diff --git a/drivers/block/fsl_sata.c b/drivers/block/fsl_sata.c index 3026adec0d..fda3389e8b 100644 --- a/drivers/block/fsl_sata.c +++ b/drivers/block/fsl_sata.c @@ -26,10 +26,9 @@ #include <malloc.h> #include <libata.h> #include <fis.h> +#include <sata.h> #include "fsl_sata.h" -extern block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE]; - #ifndef CONFIG_SYS_SATA1_FLAGS #define CONFIG_SYS_SATA1_FLAGS FLAGS_DMA #endif @@ -758,7 +757,8 @@ static int fsl_sata_get_flush_ext(int dev) return sata->flush_ext; } -u32 ata_low_level_rw_lba48(int dev, u32 blknr, u32 blkcnt, void *buffer, int is_write) +u32 ata_low_level_rw_lba48(int dev, u32 blknr, lbaint_t blkcnt, + const void *buffer, int is_write) { u32 start, blks; u8 *addr; @@ -792,7 +792,8 @@ u32 ata_low_level_rw_lba48(int dev, u32 blknr, u32 blkcnt, void *buffer, int is_ return blkcnt; } -u32 ata_low_level_rw_lba28(int dev, u32 blknr, u32 blkcnt, void *buffer, int is_write) +u32 ata_low_level_rw_lba28(int dev, u32 blknr, u32 blkcnt, const void *buffer, + int is_write) { u32 start, blks; u8 *addr; @@ -823,7 +824,7 @@ u32 ata_low_level_rw_lba28(int dev, u32 blknr, u32 blkcnt, void *buffer, int is_ /* * SATA interface between low level driver and command layer */ -ulong sata_read(int dev, u32 blknr, u32 blkcnt, void *buffer) +ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) { u32 rc; fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; @@ -835,7 +836,7 @@ ulong sata_read(int dev, u32 blknr, u32 blkcnt, void *buffer) return rc; } -ulong sata_write(int dev, u32 blknr, u32 blkcnt, void *buffer) +ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) { u32 rc; fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; diff --git a/drivers/block/pata_bfin.c b/drivers/block/pata_bfin.c index cce21fbc54..b847dd91e7 100644 --- a/drivers/block/pata_bfin.c +++ b/drivers/block/pata_bfin.c @@ -17,6 +17,7 @@ #include <asm/portmux.h> #include <asm/mach-common/bits/pata.h> #include <ata.h> +#include <sata.h> #include <libata.h> #include "pata_bfin.h" @@ -1079,7 +1080,7 @@ static u8 do_one_read(struct ata_port *ap, u64 blknr, u8 blkcnt, u16 *buffer, return sr; } -ulong sata_read(int dev, ulong block, ulong blkcnt, void *buff) +ulong sata_read(int dev, ulong block, lbaint_t blkcnt, void *buff) { struct ata_port *ap = &port[dev]; ulong n = 0, sread; @@ -1121,7 +1122,7 @@ ulong sata_read(int dev, ulong block, ulong blkcnt, void *buff) return n; } -ulong sata_write(int dev, ulong block, ulong blkcnt, const void *buff) +ulong sata_write(int dev, ulong block, lbaint_t blkcnt, const void *buff) { struct ata_port *ap = &port[dev]; void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; diff --git a/drivers/block/pata_bfin.h b/drivers/block/pata_bfin.h index 2b3425bc95..2093cf06b4 100644 --- a/drivers/block/pata_bfin.h +++ b/drivers/block/pata_bfin.h @@ -41,8 +41,6 @@ struct ata_port { unsigned char dev_mask; }; -extern block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE]; - #define DRV_NAME "pata-bfin" #define DRV_VERSION "0.9" #define __iomem diff --git a/drivers/block/sata_dwc.c b/drivers/block/sata_dwc.c index 75101b5d79..28d87f538b 100644 --- a/drivers/block/sata_dwc.c +++ b/drivers/block/sata_dwc.c @@ -35,6 +35,7 @@ #include <asm/io.h> #include <malloc.h> #include <ata.h> +#include <sata.h> #include <linux/ctype.h> #include "sata_dwc.h" @@ -268,8 +269,6 @@ static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, unsigned int flags, u16 *id); static int check_sata_dev_state(void); -extern block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE]; - static const struct ata_port_info sata_dwc_port_info[] = { { .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | @@ -1907,7 +1906,7 @@ err_out: #define SATA_MAX_WRITE_BLK 0xFFFF #endif -ulong sata_write(int device, ulong blknr, lbaint_t blkcnt, void *buffer) +ulong sata_write(int device, ulong blknr, lbaint_t blkcnt, const void *buffer) { ulong start,blks, buf_addr; unsigned short smallblks; diff --git a/drivers/block/sata_sil.c b/drivers/block/sata_sil.c index fb7cd2aae2..245b872f99 100644 --- a/drivers/block/sata_sil.c +++ b/drivers/block/sata_sil.c @@ -25,6 +25,7 @@ #include <malloc.h> #include <asm/io.h> #include <fis.h> +#include <sata.h> #include <libata.h> #include "sata_sil.h" @@ -369,7 +370,7 @@ static ulong sil_sata_rw_cmd_ext(int dev, ulong start, ulong blkcnt, } ulong sil_sata_rw_lba28(int dev, ulong blknr, lbaint_t blkcnt, - void *buffer, int is_write) + const void *buffer, int is_write) { ulong start, blks, max_blks; u8 *addr; @@ -397,7 +398,7 @@ ulong sil_sata_rw_lba28(int dev, ulong blknr, lbaint_t blkcnt, } ulong sil_sata_rw_lba48(int dev, ulong blknr, lbaint_t blkcnt, - void *buffer, int is_write) + const void *buffer, int is_write) { ulong start, blks, max_blks; u8 *addr; @@ -502,7 +503,7 @@ ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) /* * SATA interface between low level driver and command layer */ -ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) +ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) { struct sil_sata *sata = sata_dev_desc[dev].priv; ulong rc; diff --git a/drivers/block/sata_sil.h b/drivers/block/sata_sil.h index 2dfd4a5e54..9f3a37f508 100644 --- a/drivers/block/sata_sil.h +++ b/drivers/block/sata_sil.h @@ -24,8 +24,6 @@ #define READ_CMD 0 #define WRITE_CMD 1 -extern block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE]; - /* * SATA device driver struct for each dev */ diff --git a/drivers/block/sata_sil3114.c b/drivers/block/sata_sil3114.c index 34fe038608..3a5e0328f5 100644 --- a/drivers/block/sata_sil3114.c +++ b/drivers/block/sata_sil3114.c @@ -28,6 +28,7 @@ #include <asm/byteorder.h> #include <asm/io.h> #include <ide.h> +#include <sata.h> #include <libata.h> #include "sata_sil3114.h" @@ -48,7 +49,6 @@ 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[CONFIG_SYS_SATA_MAX_DEVICE]; static struct sata_port port[CONFIG_SYS_SATA_MAX_DEVICE]; diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 17f4b739a9..d50ac3bfef 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -44,6 +44,7 @@ COBJS-$(CONFIG_SH_GPIO_PFC) += sh_pfc.o COBJS-$(CONFIG_OMAP_GPIO) += omap_gpio.o COBJS-$(CONFIG_DB8500_GPIO) += db8500_gpio.o COBJS-$(CONFIG_BCM2835_GPIO) += bcm2835_gpio.o +COBJS-$(CONFIG_S3C2440_GPIO) += s3c2440_gpio.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 359fdeea23..be13745921 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -221,7 +221,7 @@ cmd_tbl_t cmd_pca953x[] = { int do_pca953x(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { static uint8_t chip = CONFIG_SYS_I2C_PCA953X_ADDR; - int val; + int ret = CMD_RET_USAGE, val; ulong ul_arg2 = 0; ulong ul_arg3 = 0; cmd_tbl_t *c; @@ -232,7 +232,7 @@ int do_pca953x(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (!c || !((argc == (c->maxargs)) || (((int)c->cmd == PCA953X_CMD_DEVICE) && (argc == (c->maxargs - 1))))) { - return cmd_usage(cmdtp); + return CMD_RET_USAGE; } /* arg2 used as chip number or pin number */ @@ -246,32 +246,53 @@ int do_pca953x(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) switch ((int)c->cmd) { #ifdef CONFIG_CMD_PCA953X_INFO case PCA953X_CMD_INFO: - return pca953x_info(chip); + ret = pca953x_info(chip); + if (ret) + ret = CMD_RET_FAILURE; + break; #endif + case PCA953X_CMD_DEVICE: if (argc == 3) chip = (uint8_t)ul_arg2; printf("Current device address: 0x%x\n", chip); - return 0; + ret = CMD_RET_SUCCESS; + break; + case PCA953X_CMD_INPUT: - pca953x_set_dir(chip, (1 << ul_arg2), + ret = pca953x_set_dir(chip, (1 << ul_arg2), PCA953X_DIR_IN << ul_arg2); val = (pca953x_get_val(chip) & (1 << ul_arg2)) != 0; - printf("chip 0x%02x, pin 0x%lx = %d\n", chip, ul_arg2, val); - return val; + if (ret) + ret = CMD_RET_FAILURE; + else + printf("chip 0x%02x, pin 0x%lx = %d\n", chip, ul_arg2, + val); + break; + case PCA953X_CMD_OUTPUT: - pca953x_set_dir(chip, (1 << ul_arg2), + ret = pca953x_set_dir(chip, (1 << ul_arg2), (PCA953X_DIR_OUT << ul_arg2)); - return pca953x_set_val(chip, (1 << ul_arg2), - (ul_arg3 << ul_arg2)); + if (!ret) + ret = pca953x_set_val(chip, (1 << ul_arg2), + (ul_arg3 << ul_arg2)); + if (ret) + ret = CMD_RET_FAILURE; + break; + case PCA953X_CMD_INVERT: - return pca953x_set_pol(chip, (1 << ul_arg2), + ret = pca953x_set_pol(chip, (1 << ul_arg2), (ul_arg3 << ul_arg2)); - default: - /* We should never get here */ - return 1; + if (ret) + ret = CMD_RET_FAILURE; + break; } + + if (ret == CMD_RET_FAILURE) + eprintf("Error talking to chip at 0x%x\n", chip); + + return ret; } U_BOOT_CMD( @@ -287,7 +308,7 @@ U_BOOT_CMD( " - set pin as output and drive low or high\n" "pca953x invert pin 0|1\n" " - disable/enable polarity inversion for reads\n" - "pca953x intput pin\n" + "pca953x input pin\n" " - set pin as input and read value" ); diff --git a/drivers/gpio/s3c2440_gpio.c b/drivers/gpio/s3c2440_gpio.c new file mode 100644 index 0000000000..43bbf1160c --- /dev/null +++ b/drivers/gpio/s3c2440_gpio.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2012 + * Gabriel Huau <contact@huau-gabriel.fr> + * + * 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/arch/s3c2440.h> +#include <asm/gpio.h> +#include <asm/io.h> + +#define GPIO_INPUT 0x0 +#define GPIO_OUTPUT 0x1 + +/* 0x4 means that we want DAT and not CON register */ +#define GPIO_PORT(x) ((((x) >> 5) & 0x3) + 0x4) +#define GPIO_BIT(x) ((x) & 0x3f) + +/* + * It's how we calculate the full port address + * We have to get the number of the port + 1 (Port A is at 0x56000001 ...) + * We move it at the second digit, and finally we add 0x4 because we want + * to modify GPIO DAT and not CON + */ +#define GPIO_FULLPORT(x) (S3C24X0_GPIO_BASE | ((GPIO_PORT(gpio) + 1) << 1)) + +int gpio_set_value(unsigned gpio, int value) +{ + unsigned l = readl(GPIO_FULLPORT(gpio)); + unsigned bit; + unsigned port = GPIO_FULLPORT(gpio); + + /* + * All GPIO Port have a configuration on + * 2 bits excepted the first GPIO (A) which + * have only 1 bit of configuration. + */ + if (!GPIO_PORT(gpio)) + bit = (0x1 << GPIO_BIT(gpio)); + else + bit = (0x3 << GPIO_BIT(gpio)); + + if (value) + l |= bit; + else + l &= ~bit; + + return writel(port, l); +} + +int gpio_get_value(unsigned gpio) +{ + unsigned l = readl(GPIO_FULLPORT(gpio)); + + if (GPIO_PORT(gpio) == 0) /* PORT A */ + return (l >> GPIO_BIT(gpio)) & 0x1; + return (l >> GPIO_BIT(gpio)) & 0x3; +} + +int gpio_request(unsigned gpio, const char *label) +{ + return 0; +} + +int gpio_free(unsigned gpio) +{ + return 0; +} + +int gpio_direction_input(unsigned gpio) +{ + return writel(GPIO_FULLPORT(gpio), GPIO_INPUT << GPIO_BIT(gpio)); +} + +int gpio_direction_output(unsigned gpio, int value) +{ + writel(GPIO_FULLPORT(gpio), GPIO_OUTPUT << GPIO_BIT(gpio)); + return gpio_set_value(gpio, value); +} diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c index 747f4cf921..2417968214 100644 --- a/drivers/gpio/tegra_gpio.c +++ b/drivers/gpio/tegra_gpio.c @@ -30,7 +30,7 @@ #include <common.h> #include <asm/io.h> #include <asm/bitops.h> -#include <asm/arch/tegra20.h> +#include <asm/arch/tegra.h> #include <asm/gpio.h> enum { diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 73d8958701..18270b9de6 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -98,7 +98,7 @@ static uint8_t i2c_imx_get_clk(unsigned int rate) #endif /* Divider value calculation */ - i2c_clk_rate = mxc_get_clock(MXC_IPG_PERCLK); + i2c_clk_rate = mxc_get_clock(MXC_I2C_CLK); div = (i2c_clk_rate + rate - 1) / rate; if (div < i2c_clk_div[0][0]) clk_div = 0; @@ -142,7 +142,7 @@ unsigned int bus_i2c_get_bus_speed(void *base) for (clk_div = 0; i2c_clk_div[clk_div][1] != clk_idx; clk_div++) ; - return mxc_get_clock(MXC_IPG_PERCLK) / i2c_clk_div[clk_div][0]; + return mxc_get_clock(MXC_I2C_CLK) / i2c_clk_div[clk_div][0]; } #define ST_BUS_IDLE (0 | (I2SR_IBB << 8)) diff --git a/drivers/i2c/sh_i2c.c b/drivers/i2c/sh_i2c.c index fd8cb9285c..3147123bba 100644 --- a/drivers/i2c/sh_i2c.c +++ b/drivers/i2c/sh_i2c.c @@ -52,22 +52,6 @@ static u8 iccl, icch; #define IRQ_WAIT 1000 -static void irq_wait(struct sh_i2c *base) -{ - int i; - u8 status; - - for (i = 0 ; i < IRQ_WAIT ; i++) { - status = readb(&base->icsr); - if (SH_IC_WAIT & status) - break; - - udelay(10); - } - - writeb(status & ~SH_IC_WAIT, &base->icsr); -} - static void irq_dte(struct sh_i2c *base) { int i; diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c index e3be14e3cf..efc77fa910 100644 --- a/drivers/i2c/tegra_i2c.c +++ b/drivers/i2c/tegra_i2c.c @@ -26,12 +26,12 @@ #include <fdtdec.h> #include <i2c.h> #include <asm/io.h> -#include <asm/arch/clk_rst.h> #include <asm/arch/clock.h> #include <asm/arch/funcmux.h> #include <asm/arch/gpio.h> #include <asm/arch/pinmux.h> -#include <asm/arch/tegra_i2c.h> +#include <asm/arch-tegra/clk_rst.h> +#include <asm/arch-tegra/tegra_i2c.h> DECLARE_GLOBAL_DATA_PTR; diff --git a/drivers/input/input.c b/drivers/input/input.c index 4eadd773b4..5b2b4b0714 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -356,7 +356,8 @@ int input_send_keycodes(struct input_config *config, * insert another character if we later realise that we * have missed a repeat slot. */ - is_repeat = (int)get_timer(config->next_repeat_ms) >= 0; + is_repeat = config->repeat_rate_ms && + (int)get_timer(config->next_repeat_ms) >= 0; if (!is_repeat) return 0; } @@ -392,13 +393,17 @@ int input_add_table(struct input_config *config, int left_keycode, return 0; } -int input_init(struct input_config *config, int leds, int repeat_delay_ms, +void input_set_delays(struct input_config *config, int repeat_delay_ms, int repeat_rate_ms) { - memset(config, '\0', sizeof(*config)); - config->leds = leds; config->repeat_delay_ms = repeat_delay_ms; config->repeat_rate_ms = repeat_rate_ms; +} + +int input_init(struct input_config *config, int leds) +{ + memset(config, '\0', sizeof(*config)); + config->leds = leds; if (input_add_table(config, -1, -1, kbd_plain_xlate, ARRAY_SIZE(kbd_plain_xlate)) || input_add_table(config, KEY_LEFTSHIFT, KEY_RIGHTSHIFT, diff --git a/drivers/input/key_matrix.c b/drivers/input/key_matrix.c index 715e57a2af..946a186a1f 100644 --- a/drivers/input/key_matrix.c +++ b/drivers/input/key_matrix.c @@ -46,6 +46,9 @@ static int has_ghosting(struct key_matrix *config, struct key_matrix_key *keys, int key_in_same_col = 0, key_in_same_row = 0; int i, j; + if (!config->ghost_filter || valid < 3) + return 0; + for (i = 0; i < valid; i++) { /* * Find 2 keys such that one key is in the same row @@ -92,7 +95,7 @@ int key_matrix_decode(struct key_matrix *config, struct key_matrix_key keys[], } /* For a ghost key config, ignore the keypresses for this iteration. */ - if (valid >= 3 && has_ghosting(config, keys, valid)) { + if (has_ghosting(config, keys, valid)) { valid = 0; debug(" ghosting detected!\n"); } @@ -142,6 +145,8 @@ static uchar *create_keymap(struct key_matrix *config, u32 *data, int len, key_code = tmp & 0xffff; entry = row * config->num_cols + col; map[entry] = key_code; + debug(" map %d, %d: pos=%d, keycode=%d\n", row, col, + entry, key_code); if (pos && map_keycode == key_code) *pos = entry; } @@ -153,6 +158,8 @@ int key_matrix_decode_fdt(struct key_matrix *config, const void *blob, int node) { const struct fdt_property *prop; + const char prefix[] = "linux,"; + int plen = sizeof(prefix) - 1; int offset; /* Check each property name for ones that we understand */ @@ -168,16 +175,17 @@ int key_matrix_decode_fdt(struct key_matrix *config, const void *blob, /* Name needs to match "1,<type>keymap" */ debug("%s: property '%s'\n", __func__, name); - if (strncmp(name, "1,", 2) || len < 8 || - strcmp(name + len - 6, "keymap")) + if (strncmp(name, prefix, plen) || + len < plen + 6 || + strcmp(name + len - 6, "keymap")) continue; - len -= 8; + len -= plen + 6; if (len == 0) { config->plain_keycode = create_keymap(config, (u32 *)prop->data, fdt32_to_cpu(prop->len), KEY_FN, &config->fn_pos); - } else if (0 == strncmp(name + 2, "fn-", len)) { + } else if (0 == strncmp(name + plen, "fn-", len)) { config->fn_keycode = create_keymap(config, (u32 *)prop->data, fdt32_to_cpu(prop->len), -1, NULL); @@ -197,12 +205,14 @@ int key_matrix_decode_fdt(struct key_matrix *config, const void *blob, return 0; } -int key_matrix_init(struct key_matrix *config, int rows, int cols) +int key_matrix_init(struct key_matrix *config, int rows, int cols, + int ghost_filter) { memset(config, '\0', sizeof(*config)); config->num_rows = rows; config->num_cols = cols; config->key_count = rows * cols; + config->ghost_filter = ghost_filter; assert(config->key_count > 0); return 0; diff --git a/drivers/input/tegra-kbc.c b/drivers/input/tegra-kbc.c index f164791bee..ab7a9e33ee 100644 --- a/drivers/input/tegra-kbc.c +++ b/drivers/input/tegra-kbc.c @@ -30,7 +30,7 @@ #include <asm/io.h> #include <asm/arch/clock.h> #include <asm/arch/funcmux.h> -#include <asm/arch/timer.h> +#include <asm/arch-tegra/timer.h> #include <linux/input.h> DECLARE_GLOBAL_DATA_PTR; @@ -321,9 +321,11 @@ static int init_tegra_keyboard(void) debug("%s: No keyboard register found\n", __func__); return -1; } + input_set_delays(&config.input, KBC_REPEAT_DELAY_MS, + KBC_REPEAT_RATE_MS); /* Decode the keyboard matrix information (16 rows, 8 columns) */ - if (key_matrix_init(&config.matrix, 16, 8)) { + if (key_matrix_init(&config.matrix, 16, 8, 1)) { debug("%s: Could not init key matrix\n", __func__); return -1; } @@ -356,8 +358,7 @@ int drv_keyboard_init(void) { struct stdio_dev dev; - if (input_init(&config.input, 0, KBC_REPEAT_DELAY_MS, - KBC_REPEAT_RATE_MS)) { + if (input_init(&config.input, 0)) { debug("%s: Cannot set up input\n", __func__); return -1; } diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c index ca8fad8657..8fea6a6bfb 100644 --- a/drivers/mmc/tegra_mmc.c +++ b/drivers/mmc/tegra_mmc.c @@ -20,12 +20,12 @@ */ #include <common.h> -#include <mmc.h> #include <asm/gpio.h> #include <asm/io.h> -#include <asm/arch/clk_rst.h> #include <asm/arch/clock.h> -#include <asm/arch/tegra_mmc.h> +#include <asm/arch-tegra/clk_rst.h> +#include <asm/arch-tegra/tegra_mmc.h> +#include <mmc.h> /* support 4 mmc hosts */ struct mmc mmc_dev[4]; diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index c6aa5db33c..994dd9f095 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -652,8 +652,9 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand, sector_size = host->pmecc_sector_size = CONFIG_PMECC_SECTOR_SIZE; host->pmecc_index_table_offset = CONFIG_PMECC_INDEX_TABLE_OFFSET; - printk(KERN_INFO "Initialize PMECC params, cap: %d, sector: %d\n", - cap, sector_size); + MTDDEBUG(MTD_DEBUG_LEVEL1, + "Initialize PMECC params, cap: %d, sector: %d\n", + cap, sector_size); host->pmecc = (struct pmecc_regs __iomem *) ATMEL_BASE_PMECC; host->pmerrloc = (struct pmecc_errloc_regs __iomem *) diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index 31c174bd3b..11eb167e37 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -57,7 +57,7 @@ static void fun_wait(struct fsl_upm_nand *fun) debug("unexpected busy state\n"); } else { /* - * If the R/B pin is not connected, like on the TQM8548, + * If the R/B pin is not connected, * a short delay is necessary. */ udelay(1); @@ -115,10 +115,10 @@ static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) fsl_upm_run_pattern(&fun->upm, fun->width, io_addr, mar); /* - * Some boards/chips needs this. At least the MPC8360E-RDK and - * TQM8548 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. + * Some boards/chips needs this. At least the MPC8360E-RDK + * needs 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. */ if (fun->wait_flags & FSL_UPM_WAIT_RUN_PATTERN) fun_wait(fun); diff --git a/drivers/mtd/nand/tegra_nand.c b/drivers/mtd/nand/tegra_nand.c index 8c1de34455..5408c51ffb 100644 --- a/drivers/mtd/nand/tegra_nand.c +++ b/drivers/mtd/nand/tegra_nand.c @@ -26,12 +26,11 @@ #include <common.h> #include <asm/io.h> #include <nand.h> -#include <asm/arch/clk_rst.h> #include <asm/arch/clock.h> #include <asm/arch/funcmux.h> -#include <asm/arch/gpio.h> +#include <asm/arch-tegra/clk_rst.h> #include <asm/errno.h> -#include <asm-generic/gpio.h> +#include <asm/gpio.h> #include <fdtdec.h> #include "tegra_nand.h" @@ -993,7 +992,6 @@ int tegra_nand_init(struct nand_chip *nand, int devnum) /* Adjust timing for NAND device */ setup_timing(config->timing, info->reg); - funcmux_select(PERIPH_ID_NDFLASH, FUNCMUX_DEFAULT); fdtdec_setup_gpio(&config->wp_gpio); gpio_direction_output(config->wp_gpio.gpio, 1); diff --git a/drivers/mtd/spi/atmel.c b/drivers/mtd/spi/atmel.c index 1ecece0d78..006f6d5d04 100644 --- a/drivers/mtd/spi/atmel.c +++ b/drivers/mtd/spi/atmel.c @@ -109,6 +109,14 @@ static const struct atmel_spi_flash_params atmel_spi_flash_table[] = { .nr_sectors = 32, .name = "AT45DB642D", }, + { + .idcode1 = 0x47, + .l2_page_size = 8, + .pages_per_block = 16, + .blocks_per_sector = 16, + .nr_sectors = 64, + .name = "AT25DF321", + }, }; static int at45_wait_ready(struct spi_flash *flash, unsigned long timeout) @@ -510,11 +518,19 @@ struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode) asf->flash.erase = dataflash_erase_p2; } + asf->flash.page_size = page_size; + asf->flash.sector_size = page_size; break; case DF_FAMILY_AT26F: case DF_FAMILY_AT26DF: asf->flash.read = spi_flash_cmd_read_fast; + asf->flash.write = spi_flash_cmd_write_multi; + asf->flash.erase = spi_flash_cmd_erase; + asf->flash.page_size = page_size; + asf->flash.sector_size = 4096; + /* clear SPRL# bit for locked flash */ + spi_flash_cmd_write_status(&asf->flash, 0); break; default: @@ -522,7 +538,6 @@ struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode) goto err; } - asf->flash.sector_size = page_size; asf->flash.size = page_size * params->pages_per_block * params->blocks_per_sector * params->nr_sectors; diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index b2516d1768..1db586d6b2 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -897,7 +897,8 @@ int davinci_emac_initialize(void) } #if defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \ - defined(CONFIG_MACH_DAVINCI_DA850_EVM) + defined(CONFIG_MACH_DAVINCI_DA850_EVM) && \ + !defined(CONFIG_DRIVER_TI_EMAC_RMII_NO_NEGOTIATE) for (i = 0; i < num_phy; i++) { if (phy[i].is_phy_connected(i)) phy[i].auto_negotiate(i); diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c index 94b2a41e14..2d4da4b386 100644 --- a/drivers/net/e1000.c +++ b/drivers/net/e1000.c @@ -135,7 +135,6 @@ static void e1000_set_media_type(struct e1000_hw *hw); static int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask); static int32_t e1000_check_phy_reset_block(struct e1000_hw *hw); -#ifndef CONFIG_AP1000 /* remove for warnings */ static int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data); @@ -942,7 +941,6 @@ e1000_set_phy_mode(struct e1000_hw *hw) return E1000_SUCCESS; } -#endif /* #ifndef CONFIG_AP1000 */ /*************************************************************************** * @@ -1123,7 +1121,6 @@ static boolean_t e1000_is_second_port(struct e1000_hw *hw) static int e1000_read_mac_addr(struct eth_device *nic) { -#ifndef CONFIG_AP1000 struct e1000_hw *hw = nic->priv; uint16_t offset; uint16_t eeprom_data; @@ -1152,31 +1149,6 @@ e1000_read_mac_addr(struct eth_device *nic) memcpy (nic->enetaddr, fb_mac, NODE_ADDRESS_SIZE); } #endif -#else - /* - * The AP1000's e1000 has no eeprom; the MAC address is stored in the - * environment variables. Currently this does not support the addition - * of a PMC e1000 card, which is certainly a possibility, so this should - * be updated to properly use the env variable only for the onboard e1000 - */ - - int ii; - char *s, *e; - - DEBUGFUNC(); - - s = getenv ("ethaddr"); - if (s == NULL) { - return -E1000_ERR_EEPROM; - } else { - for(ii = 0; ii < 6; ii++) { - nic->enetaddr[ii] = s ? simple_strtoul (s, &e, 16) : 0; - if (s){ - s = (*e) ? e + 1 : e; - } - } - } -#endif return 0; } @@ -1808,7 +1780,6 @@ e1000_setup_link(struct eth_device *nic) if (e1000_check_phy_reset_block(hw)) return E1000_SUCCESS; -#ifndef CONFIG_AP1000 /* Read and store word 0x0F of the EEPROM. This word contains bits * that determine the hardware's default PAUSE (flow control) mode, * a bit that determines whether the HW defaults to enabling or @@ -1822,11 +1793,6 @@ e1000_setup_link(struct eth_device *nic) DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } -#else - /* we have to hardcode the proper value for our hardware. */ - /* this value is for the 82540EM pci card used for prototyping, and it works. */ - eeprom_data = 0xb220; -#endif if (hw->fc == e1000_fc_default) { switch (hw->mac_type) { @@ -1836,16 +1802,12 @@ e1000_setup_link(struct eth_device *nic) hw->fc = e1000_fc_full; break; default: -#ifndef CONFIG_AP1000 ret_val = e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data); if (ret_val) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } -#else - eeprom_data = 0xb220; -#endif if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0) hw->fc = e1000_fc_none; else if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == @@ -2109,12 +2071,10 @@ e1000_copper_link_preconfig(struct e1000_hw *hw) } DEBUGOUT("Phy ID = %x \n", hw->phy_id); -#ifndef CONFIG_AP1000 /* Set PHY to class A mode (if necessary) */ ret_val = e1000_set_phy_mode(hw); if (ret_val) return ret_val; -#endif if ((hw->mac_type == e1000_82545_rev_3) || (hw->mac_type == e1000_82546_rev_3)) { ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, @@ -5242,7 +5202,7 @@ e1000_initialize(bd_t * bis) list_add_tail(&hw->list_node, &e1000_hw_list); /* Validate the EEPROM and get chipset information */ -#if !(defined(CONFIG_AP1000) || defined(CONFIG_MVBC_1G)) +#if !defined(CONFIG_MVBC_1G) if (e1000_init_eeprom_params(hw)) { E1000_ERR(nic, "EEPROM is invalid!\n"); continue; diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 65d0f234e7..3c32f97abb 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -25,6 +25,8 @@ include $(TOPDIR)/config.mk LIB := $(obj)libserial.o +COBJS-y += serial.o + COBJS-$(CONFIG_ALTERA_UART) += altera_uart.o COBJS-$(CONFIG_ALTERA_JTAG_UART) += altera_jtag_uart.o COBJS-$(CONFIG_ARM_DCC) += arm_dcc.o @@ -37,7 +39,7 @@ COBJS-$(CONFIG_SYS_NS16550) += ns16550.o COBJS-$(CONFIG_DRIVER_S3C4510_UART) += s3c4510b_uart.o COBJS-$(CONFIG_S3C64XX) += s3c64xx.o COBJS-$(CONFIG_S5P) += serial_s5p.o -COBJS-$(CONFIG_SYS_NS16550_SERIAL) += serial.o +COBJS-$(CONFIG_SYS_NS16550_SERIAL) += serial_ns16550.o COBJS-$(CONFIG_CLPS7111_SERIAL) += serial_clps7111.o COBJS-$(CONFIG_IMX_SERIAL) += serial_imx.o COBJS-$(CONFIG_IXP_SERIAL) += serial_ixp.o @@ -56,6 +58,7 @@ COBJS-$(CONFIG_S3C44B0_SERIAL) += serial_s3c44b0.o COBJS-$(CONFIG_XILINX_UARTLITE) += serial_xuartlite.o COBJS-$(CONFIG_SANDBOX_SERIAL) += sandbox.o COBJS-$(CONFIG_SCIF_CONSOLE) += serial_sh.o +COBJS-$(CONFIG_ZYNQ_SERIAL) += serial_zynq.o ifndef CONFIG_SPL_BUILD COBJS-$(CONFIG_USB_TTY) += usbtty.o diff --git a/drivers/serial/altera_jtag_uart.c b/drivers/serial/altera_jtag_uart.c index 2980e4d07c..654b5019eb 100644 --- a/drivers/serial/altera_jtag_uart.c +++ b/drivers/serial/altera_jtag_uart.c @@ -25,6 +25,8 @@ #include <watchdog.h> #include <asm/io.h> #include <nios2-io.h> +#include <linux/compiler.h> +#include <serial.h> DECLARE_GLOBAL_DATA_PTR; @@ -33,10 +35,16 @@ DECLARE_GLOBAL_DATA_PTR; *-----------------------------------------------------------------*/ static nios_jtag_t *jtag = (nios_jtag_t *)CONFIG_SYS_NIOS_CONSOLE; -void serial_setbrg( void ){ return; } -int serial_init( void ) { return(0);} +static void altera_jtag_serial_setbrg(void) +{ +} + +static int altera_jtag_serial_init(void) +{ + return 0; +} -void serial_putc (char c) +static void altera_jtag_serial_putc(char c) { while (1) { unsigned st = readl(&jtag->control); @@ -51,18 +59,18 @@ void serial_putc (char c) writel ((unsigned char)c, &jtag->data); } -void serial_puts (const char *s) +static void altera_jtag_serial_puts(const char *s) { while (*s != 0) serial_putc (*s++); } -int serial_tstc (void) +static int altera_jtag_serial_tstc(void) { return ( readl (&jtag->control) & NIOS_JTAG_RRDY); } -int serial_getc (void) +static int altera_jtag_serial_getc(void) { int c; unsigned val; @@ -76,3 +84,24 @@ int serial_getc (void) c = val & 0x0ff; return (c); } + +static struct serial_device altera_jtag_serial_drv = { + .name = "altera_jtag_uart", + .start = altera_jtag_serial_init, + .stop = NULL, + .setbrg = altera_jtag_serial_setbrg, + .putc = altera_jtag_serial_putc, + .puts = altera_jtag_serial_puts, + .getc = altera_jtag_serial_getc, + .tstc = altera_jtag_serial_tstc, +}; + +void altera_jtag_serial_initialize(void) +{ + serial_register(&altera_jtag_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &altera_jtag_serial_drv; +} diff --git a/drivers/serial/altera_uart.c b/drivers/serial/altera_uart.c index 045f1197a3..27550ed48d 100644 --- a/drivers/serial/altera_uart.c +++ b/drivers/serial/altera_uart.c @@ -26,6 +26,8 @@ #include <watchdog.h> #include <asm/io.h> #include <nios2-io.h> +#include <linux/compiler.h> +#include <serial.h> DECLARE_GLOBAL_DATA_PTR; @@ -37,27 +39,33 @@ static nios_uart_t *uart = (nios_uart_t *) CONFIG_SYS_NIOS_CONSOLE; #if defined(CONFIG_SYS_NIOS_FIXEDBAUD) -/* Everything's already setup for fixed-baud PTF +/* + * Everything's already setup for fixed-baud PTF * assignment */ -void serial_setbrg (void){ return; } -int serial_init (void) { return (0);} +static void altera_serial_setbrg(void) +{ +} + +static int altera_serial_init(void) +{ + return 0; +} #else -void serial_setbrg (void) +static void altera_serial_setbrg(void) { unsigned div; div = (CONFIG_SYS_CLK_FREQ/gd->baudrate)-1; writel (div, &uart->divisor); - return; } -int serial_init (void) +static int altera_serial_init(void) { - serial_setbrg (); - return (0); + serial_setbrg(); + return 0; } #endif /* CONFIG_SYS_NIOS_FIXEDBAUD */ @@ -65,7 +73,7 @@ int serial_init (void) /*----------------------------------------------------------------------- * UART CONSOLE *---------------------------------------------------------------------*/ -void serial_putc (char c) +static void altera_serial_putc(char c) { if (c == '\n') serial_putc ('\r'); @@ -74,21 +82,42 @@ void serial_putc (char c) writel ((unsigned char)c, &uart->txdata); } -void serial_puts (const char *s) +static void altera_serial_puts(const char *s) { while (*s != 0) { serial_putc (*s++); } } -int serial_tstc (void) +static int altera_serial_tstc(void) { return (readl (&uart->status) & NIOS_UART_RRDY); } -int serial_getc (void) +static int altera_serial_getc(void) { while (serial_tstc () == 0) WATCHDOG_RESET (); return (readl (&uart->rxdata) & 0x00ff ); } + +static struct serial_device altera_serial_drv = { + .name = "altera_serial", + .start = altera_serial_init, + .stop = NULL, + .setbrg = altera_serial_setbrg, + .putc = altera_serial_putc, + .puts = altera_serial_puts, + .getc = altera_serial_getc, + .tstc = altera_serial_tstc, +}; + +void altera_serial_initialize(void) +{ + serial_register(&altera_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &altera_serial_drv; +} diff --git a/drivers/serial/atmel_usart.c b/drivers/serial/atmel_usart.c index 943ef70fa6..130303129e 100644 --- a/drivers/serial/atmel_usart.c +++ b/drivers/serial/atmel_usart.c @@ -20,6 +20,8 @@ */ #include <common.h> #include <watchdog.h> +#include <serial.h> +#include <linux/compiler.h> #include <asm/io.h> #include <asm/arch/clk.h> @@ -29,7 +31,7 @@ DECLARE_GLOBAL_DATA_PTR; -void serial_setbrg(void) +static void atmel_serial_setbrg(void) { atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE; unsigned long divisor; @@ -45,7 +47,7 @@ void serial_setbrg(void) writel(USART3_BF(CD, divisor), &usart->brgr); } -int serial_init(void) +static int atmel_serial_init(void) { atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE; @@ -73,7 +75,7 @@ int serial_init(void) return 0; } -void serial_putc(char c) +static void atmel_serial_putc(char c) { atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE; @@ -84,13 +86,13 @@ void serial_putc(char c) writel(c, &usart->thr); } -void serial_puts(const char *s) +static void atmel_serial_puts(const char *s) { while (*s) serial_putc(*s++); } -int serial_getc(void) +static int atmel_serial_getc(void) { atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE; @@ -99,8 +101,29 @@ int serial_getc(void) return readl(&usart->rhr); } -int serial_tstc(void) +static int atmel_serial_tstc(void) { atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE; return (readl(&usart->csr) & USART3_BIT(RXRDY)) != 0; } + +static struct serial_device atmel_serial_drv = { + .name = "atmel_serial", + .start = atmel_serial_init, + .stop = NULL, + .setbrg = atmel_serial_setbrg, + .putc = atmel_serial_putc, + .puts = atmel_serial_puts, + .getc = atmel_serial_getc, + .tstc = atmel_serial_tstc, +}; + +void atmel_serial_initialize(void) +{ + serial_register(&atmel_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &atmel_serial_drv; +} diff --git a/drivers/serial/lpc32xx_hsuart.c b/drivers/serial/lpc32xx_hsuart.c index 8ce3382d86..02429b5541 100644 --- a/drivers/serial/lpc32xx_hsuart.c +++ b/drivers/serial/lpc32xx_hsuart.c @@ -22,12 +22,14 @@ #include <asm/arch/clk.h> #include <asm/arch/uart.h> #include <asm/io.h> +#include <serial.h> +#include <linux/compiler.h> DECLARE_GLOBAL_DATA_PTR; static struct hsuart_regs *hsuart = (struct hsuart_regs *)HS_UART_BASE; -static void lpc32xx_hsuart_set_baudrate(void) +static void lpc32xx_serial_setbrg(void) { u32 div; @@ -39,7 +41,7 @@ static void lpc32xx_hsuart_set_baudrate(void) writel(div, &hsuart->rate); } -static int lpc32xx_hsuart_getc(void) +static int lpc32xx_serial_getc(void) { while (!(readl(&hsuart->level) & HSUART_LEVEL_RX)) /* NOP */; @@ -47,7 +49,7 @@ static int lpc32xx_hsuart_getc(void) return readl(&hsuart->rx) & HSUART_RX_DATA; } -static void lpc32xx_hsuart_putc(const char c) +static void lpc32xx_serial_putc(const char c) { writel(c, &hsuart->tx); @@ -56,7 +58,7 @@ static void lpc32xx_hsuart_putc(const char c) /* NOP */; } -static int lpc32xx_hsuart_tstc(void) +static int lpc32xx_serial_tstc(void) { if (readl(&hsuart->level) & HSUART_LEVEL_RX) return 1; @@ -64,49 +66,40 @@ static int lpc32xx_hsuart_tstc(void) return 0; } -static void lpc32xx_hsuart_init(void) +static int lpc32xx_serial_init(void) { - lpc32xx_hsuart_set_baudrate(); + lpc32xx_serial_setbrg(); /* Disable hardware RTS and CTS flow control, set up RX and TX FIFO */ writel(HSUART_CTRL_TMO_16 | HSUART_CTRL_HSU_OFFSET(20) | HSUART_CTRL_HSU_RX_TRIG_32 | HSUART_CTRL_HSU_TX_TRIG_0, &hsuart->ctrl); + return 0; } -void serial_setbrg(void) -{ - return lpc32xx_hsuart_set_baudrate(); -} - -void serial_putc(const char c) -{ - lpc32xx_hsuart_putc(c); - - /* If \n, also do \r */ - if (c == '\n') - lpc32xx_hsuart_putc('\r'); -} - -int serial_getc(void) -{ - return lpc32xx_hsuart_getc(); -} - -void serial_puts(const char *s) +static void lpc32xx_serial_puts(const char *s) { while (*s) serial_putc(*s++); } -int serial_tstc(void) +static struct serial_device lpc32xx_serial_drv = { + .name = "lpc32xx_serial", + .start = lpc32xx_serial_init, + .stop = NULL, + .setbrg = lpc32xx_serial_setbrg, + .putc = lpc32xx_serial_putc, + .puts = lpc32xx_serial_puts, + .getc = lpc32xx_serial_getc, + .tstc = lpc32xx_serial_tstc, +}; + +void lpc32xx_serial_initialize(void) { - return lpc32xx_hsuart_tstc(); + serial_register(&lpc32xx_serial_drv); } -int serial_init(void) +__weak struct serial_device *default_serial_console(void) { - lpc32xx_hsuart_init(); - - return 0; + return &lpc32xx_serial_drv; } diff --git a/drivers/serial/mcfuart.c b/drivers/serial/mcfuart.c index d93b24b897..00a7114691 100644 --- a/drivers/serial/mcfuart.c +++ b/drivers/serial/mcfuart.c @@ -36,7 +36,7 @@ DECLARE_GLOBAL_DATA_PTR; extern void uart_port_conf(int port); -int serial_init(void) +static int mcf_serial_init(void) { volatile uart_t *uart; u32 counter; @@ -74,7 +74,7 @@ int serial_init(void) return (0); } -void serial_putc(const char c) +static void mcf_serial_putc(const char c) { volatile uart_t *uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE); @@ -87,14 +87,14 @@ void serial_putc(const char c) uart->utb = c; } -void serial_puts(const char *s) +static void mcf_serial_puts(const char *s) { while (*s) { serial_putc(*s++); } } -int serial_getc(void) +static int mcf_serial_getc(void) { volatile uart_t *uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE); @@ -103,14 +103,14 @@ int serial_getc(void) return uart->urb; } -int serial_tstc(void) +static int mcf_serial_tstc(void) { volatile uart_t *uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE); return (uart->usr & UART_USR_RXRDY); } -void serial_setbrg(void) +static void mcf_serial_setbrg(void) { volatile uart_t *uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE); u32 counter; @@ -129,3 +129,24 @@ void serial_setbrg(void) uart->ucr = UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED; } + +static struct serial_device mcf_serial_drv = { + .name = "mcf_serial", + .start = mcf_serial_init, + .stop = NULL, + .setbrg = mcf_serial_setbrg, + .putc = mcf_serial_putc, + .puts = mcf_serial_puts, + .getc = mcf_serial_getc, + .tstc = mcf_serial_tstc, +}; + +void mcf_serial_initialize(void) +{ + serial_register(&mcf_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &mcf_serial_drv; +} diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index facadd2f5c..9027781445 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -101,7 +101,7 @@ void NS16550_putc(NS16550_t com_port, char c) char NS16550_getc(NS16550_t com_port) { while ((serial_in(&com_port->lsr) & UART_LSR_DR) == 0) { -#ifdef CONFIG_USB_TTY +#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_TTY) extern void usbtty_poll(void); usbtty_poll(); #endif diff --git a/drivers/serial/ns9750_serial.c b/drivers/serial/ns9750_serial.c index e9645a053d..cb545c4065 100644 --- a/drivers/serial/ns9750_serial.c +++ b/drivers/serial/ns9750_serial.c @@ -52,7 +52,7 @@ static unsigned int unCharCache; /* unCharCache is only valid if * @Descr: configures GPIOs and UART. Requires BBUS Master Reset turned off ***********************************************************************/ -int serial_init( void ) +static int ns9750_serial_init(void) { unsigned int aunGPIOTxD[] = { 0, 8, 40, 44 }; unsigned int aunGPIORxD[] = { 1, 9, 41, 45 }; @@ -85,7 +85,7 @@ int serial_init( void ) * @Descr: writes one character to the FIFO. Blocks until FIFO is not full ***********************************************************************/ -void serial_putc( const char c ) +static void ns9750_serial_putc(const char c) { if (c == '\n') serial_putc( '\r' ); @@ -105,7 +105,7 @@ void serial_putc( const char c ) * @Descr: writes non-zero string to the FIFO. ***********************************************************************/ -void serial_puts( const char *s ) +static void ns9750_serial_puts(const char *s) { while (*s) { serial_putc( *s++ ); @@ -118,7 +118,7 @@ void serial_puts( const char *s ) * @Descr: performs only 8bit accesses to the FIFO. No error handling ***********************************************************************/ -int serial_getc( void ) +static int ns9750_serial_getc(void) { int i; @@ -142,7 +142,7 @@ int serial_getc( void ) * unCharCache and the numbers of characters in cCharsAvailable ***********************************************************************/ -int serial_tstc( void ) +static int ns9750_serial_tstc(void) { unsigned int unRegCache; @@ -171,7 +171,7 @@ int serial_tstc( void ) return 0; } -void serial_setbrg( void ) +static void ns9750_serial_setbrg(void) { *get_ser_reg_addr_channel( NS9750_SER_BITRATE, CONSOLE ) = calcBitrateRegister(); @@ -208,3 +208,24 @@ static unsigned int calcRxCharGapRegister( void ) { return NS9750_SER_RX_CHAR_TIMER_TRUN; } + +static struct serial_device ns9750_serial_drv = { + .name = "ns9750_serial", + .start = ns9750_serial_init, + .stop = NULL, + .setbrg = ns9750_serial_setbrg, + .putc = ns9750_serial_putc, + .puts = ns9750_serial_puts, + .getc = ns9750_serial_getc, + .tstc = ns9750_serial_tstc, +}; + +void ns9750_serial_initialize(void) +{ + serial_register(&ns9750_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &ns9750_serial_drv; +} diff --git a/drivers/serial/opencores_yanu.c b/drivers/serial/opencores_yanu.c index f3830112aa..49bccf3a6c 100644 --- a/drivers/serial/opencores_yanu.c +++ b/drivers/serial/opencores_yanu.c @@ -37,7 +37,7 @@ static yanu_uart_t *uart = (yanu_uart_t *)CONFIG_SYS_NIOS_CONSOLE; /* Everything's already setup for fixed-baud PTF assignment*/ -void serial_setbrg (void) +static void oc_serial_setbrg(void) { int n, k; const unsigned max_uns = 0xFFFFFFFF; @@ -68,7 +68,7 @@ void serial_setbrg (void) #else -void serial_setbrg (void) +static void oc_serial_setbrg(void) { int n, k; const unsigned max_uns = 0xFFFFFFFF; @@ -100,7 +100,7 @@ void serial_setbrg (void) #endif /* CONFIG_SYS_NIOS_FIXEDBAUD */ -int serial_init (void) +static int oc_serial_init(void) { unsigned action,control; @@ -141,7 +141,7 @@ int serial_init (void) /*----------------------------------------------------------------------- * YANU CONSOLE *---------------------------------------------------------------------*/ -void serial_putc (char c) +static void oc_serial_putc(char c) { int tx_chars; unsigned status; @@ -161,7 +161,7 @@ void serial_putc (char c) writel((unsigned char)c, &uart->data); } -void serial_puts (const char *s) +static void oc_serial_puts(const char *s) { while (*s != 0) { serial_putc (*s++); @@ -169,7 +169,7 @@ void serial_puts (const char *s) } -int serial_tstc(void) +static int oc_serial_tstc(void) { unsigned status ; @@ -178,7 +178,7 @@ int serial_tstc(void) ((1 << YANU_RFIFO_CHARS_N) - 1)) > 0); } -int serial_getc (void) +statoc int oc_serial_getc(void) { while (serial_tstc() == 0) WATCHDOG_RESET (); @@ -188,3 +188,24 @@ int serial_getc (void) return(readl(&uart->data) & YANU_DATA_CHAR_MASK); } + +static struct serial_device oc_serial_drv = { + .name = "oc_serial", + .start = oc_serial_init, + .stop = NULL, + .setbrg = oc_serial_setbrg, + .putc = oc_serial_putc, + .puts = oc_serial_puts, + .getc = oc_serial_getc, + .tstc = oc_serial_tstc, +}; + +void oc_serial_initialize(void) +{ + serial_register(&oc_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &oc_serial_drv; +} diff --git a/drivers/serial/s3c4510b_uart.c b/drivers/serial/s3c4510b_uart.c index aa378e1ac1..423d26e678 100644 --- a/drivers/serial/s3c4510b_uart.c +++ b/drivers/serial/s3c4510b_uart.c @@ -80,7 +80,7 @@ static int serial_flush_output(void) } -void serial_setbrg (void) +static void s3c4510b_serial_setbrg(void) { UART_LINE_CTRL ulctrl; UART_CTRL uctrl; @@ -135,7 +135,7 @@ void serial_setbrg (void) * are always 8 data bits, no parity, 1 stop bit, no start bits. * */ -int serial_init (void) +static int s3c4510b_serial_init(void) { #if CONFIG_SERIAL1 == 1 @@ -155,7 +155,7 @@ int serial_init (void) /* * Output a single byte to the serial port. */ -void serial_putc (const char c) +static void s3c4510_serial_putc(const char c) { /* wait for room in the transmit FIFO */ while( !uart->m_stat.bf.txBufEmpty); @@ -174,7 +174,7 @@ void serial_putc (const char c) * Test if an input byte is ready from the serial port. Returns non-zero on * success, 0 otherwise. */ -int serial_tstc (void) +static int s3c4510b_serial_tstc(void) { return uart->m_stat.bf.rxReady; } @@ -184,7 +184,7 @@ int serial_tstc (void) * otherwise. When the function is succesfull, the character read is * written into its argument c. */ -int serial_getc (void) +static int s3c4510b_serial_getc(void) { int rv; @@ -197,7 +197,7 @@ int serial_getc (void) } } -void serial_puts (const char *s) +static void s3c4510b_serial_puts(const char *s) { while (*s) { serial_putc (*s++); @@ -210,3 +210,24 @@ void serial_puts (const char *s) uart->m_ctrl.bf.sendBreak = 0; } + +static struct serial_device s3c4510b_serial_drv = { + .name = "s3c4510b_serial", + .start = s3c4510b_serial_init, + .stop = NULL, + .setbrg = s3c4510b_serial_setbrg, + .putc = s3c4510b_serial_putc, + .puts = s3c4510b_serial_puts, + .getc = s3c4510b_serial_getc, + .tstc = s3c4510b_serial_tstc, +}; + +void s3c4510b_serial_initialize(void) +{ + serial_register(&s3c4510b_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &s3c4510b_serial_drv; +} diff --git a/drivers/serial/s3c64xx.c b/drivers/serial/s3c64xx.c index a88e930945..9ab8a28d83 100644 --- a/drivers/serial/s3c64xx.c +++ b/drivers/serial/s3c64xx.c @@ -68,7 +68,7 @@ static const int udivslot[] = { 0xffdf, }; -void serial_setbrg(void) +static void s3c64xx_serial_setbrg(void) { s3c64xx_uart *const uart = s3c64xx_get_base_uart(UART_NR); u32 pclk = get_PCLK(); @@ -88,7 +88,7 @@ void serial_setbrg(void) * Initialise the serial port with the given baudrate. The settings * are always 8 data bits, no parity, 1 stop bit, no start bits. */ -int serial_init(void) +static int s3c64xx_serial_init(void) { s3c64xx_uart *const uart = s3c64xx_get_base_uart(UART_NR); @@ -110,7 +110,7 @@ int serial_init(void) * otherwise. When the function is succesfull, the character read is * written into its argument c. */ -int serial_getc(void) +static int s3c64xx_serial_getc(void) { s3c64xx_uart *const uart = s3c64xx_get_base_uart(UART_NR); @@ -137,7 +137,7 @@ void enable_putc(void) /* * Output a single byte to the serial port. */ -void serial_putc(const char c) +static void s3c64xx_serial_putc(const char c) { s3c64xx_uart *const uart = s3c64xx_get_base_uart(UART_NR); @@ -159,15 +159,36 @@ void serial_putc(const char c) /* * Test whether a character is in the RX buffer */ -int serial_tstc(void) +static int s3c64xx_serial_tstc(void) { s3c64xx_uart *const uart = s3c64xx_get_base_uart(UART_NR); return uart->UTRSTAT & 0x1; } -void serial_puts(const char *s) +static void s3c64xx_serial_puts(const char *s) { while (*s) serial_putc(*s++); } + +static struct serial_device s3c64xx_serial_drv = { + .name = "s3c64xx_serial", + .start = s3c64xx_serial_init, + .stop = NULL, + .setbrg = s3c64xx_serial_setbrg, + .putc = s3c64xx_serial_putc, + .puts = s3c64xx_serial_puts, + .getc = s3c64xx_serial_getc, + .tstc = s3c64xx_serial_tstc, +}; + +void s3c64xx_serial_initialize(void) +{ + serial_register(&s3c64xx_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &s3c64xx_serial_drv; +} diff --git a/drivers/serial/sandbox.c b/drivers/serial/sandbox.c index 1927c167bb..cb19401df6 100644 --- a/drivers/serial/sandbox.c +++ b/drivers/serial/sandbox.c @@ -27,28 +27,30 @@ #include <common.h> #include <os.h> +#include <serial.h> +#include <linux/compiler.h> -int serial_init(void) +static int sandbox_serial_init(void) { os_tty_raw(0); return 0; } -void serial_setbrg(void) +static void sandbox_serial_setbrg(void) { } -void serial_putc(const char ch) +static void sandbox_serial_putc(const char ch) { os_write(1, &ch, 1); } -void serial_puts(const char *str) +static void sandbox_serial_puts(const char *str) { os_write(1, str, strlen(str)); } -int serial_getc(void) +static int sandbox_serial_getc(void) { char buf; ssize_t count; @@ -57,7 +59,28 @@ int serial_getc(void) return count == 1 ? buf : 0; } -int serial_tstc(void) +static int sandbox_serial_tstc(void) { return 0; } + +static struct serial_device sandbox_serial_drv = { + .name = "sandbox_serial", + .start = sandbox_serial_init, + .stop = NULL, + .setbrg = sandbox_serial_setbrg, + .putc = sandbox_serial_putc, + .puts = sandbox_serial_puts, + .getc = sandbox_serial_getc, + .tstc = sandbox_serial_tstc, +}; + +void sandbox_serial_initialize(void) +{ + serial_register(&sandbox_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &sandbox_serial_drv; +} diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index b10bab70d0..5bbf3aeb44 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -1,6 +1,6 @@ /* - * (C) Copyright 2000 - * Rob Taylor, Flying Pig Systems. robt@flyingpig.com. + * (C) Copyright 2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * See file CREDITS for list of people who contributed to this * project. @@ -22,321 +22,341 @@ */ #include <common.h> -#include <linux/compiler.h> - -#include <ns16550.h> -#ifdef CONFIG_NS87308 -#include <ns87308.h> -#endif - -#if defined (CONFIG_SERIAL_MULTI) #include <serial.h> -#endif +#include <stdio_dev.h> +#include <post.h> +#include <linux/compiler.h> DECLARE_GLOBAL_DATA_PTR; -#if !defined(CONFIG_CONS_INDEX) -#if defined (CONFIG_SERIAL_MULTI) -/* with CONFIG_SERIAL_MULTI we might have no console - * on these devices - */ -#else -#error "No console index specified." -#endif /* CONFIG_SERIAL_MULTI */ -#elif (CONFIG_CONS_INDEX < 1) || (CONFIG_CONS_INDEX > 4) -#error "Invalid console index value." -#endif +static struct serial_device *serial_devices; +static struct serial_device *serial_current; -#if CONFIG_CONS_INDEX == 1 && !defined(CONFIG_SYS_NS16550_COM1) -#error "Console port 1 defined but not configured." -#elif CONFIG_CONS_INDEX == 2 && !defined(CONFIG_SYS_NS16550_COM2) -#error "Console port 2 defined but not configured." -#elif CONFIG_CONS_INDEX == 3 && !defined(CONFIG_SYS_NS16550_COM3) -#error "Console port 3 defined but not configured." -#elif CONFIG_CONS_INDEX == 4 && !defined(CONFIG_SYS_NS16550_COM4) -#error "Console port 4 defined but not configured." -#endif +static void serial_null(void) +{ +} -/* Note: The port number specified in the functions is 1 based. - * the array is 0 based. - */ -static NS16550_t serial_ports[4] = { -#ifdef CONFIG_SYS_NS16550_COM1 - (NS16550_t)CONFIG_SYS_NS16550_COM1, -#else - NULL, -#endif -#ifdef CONFIG_SYS_NS16550_COM2 - (NS16550_t)CONFIG_SYS_NS16550_COM2, -#else - NULL, -#endif -#ifdef CONFIG_SYS_NS16550_COM3 - (NS16550_t)CONFIG_SYS_NS16550_COM3, -#else - NULL, -#endif -#ifdef CONFIG_SYS_NS16550_COM4 - (NS16550_t)CONFIG_SYS_NS16550_COM4 -#else - NULL -#endif -}; - -#define PORT serial_ports[port-1] - -#if defined(CONFIG_SERIAL_MULTI) - -/* Multi serial device functions */ -#define DECLARE_ESERIAL_FUNCTIONS(port) \ - int eserial##port##_init (void) {\ - int clock_divisor; \ - clock_divisor = calc_divisor(serial_ports[port-1]); \ - NS16550_init(serial_ports[port-1], clock_divisor); \ - return(0);}\ - void eserial##port##_setbrg (void) {\ - serial_setbrg_dev(port);}\ - int eserial##port##_getc (void) {\ - return serial_getc_dev(port);}\ - int eserial##port##_tstc (void) {\ - return serial_tstc_dev(port);}\ - void eserial##port##_putc (const char c) {\ - serial_putc_dev(port, c);}\ - void eserial##port##_puts (const char *s) {\ - serial_puts_dev(port, s);} - -/* Serial device descriptor */ -#define INIT_ESERIAL_STRUCTURE(port, name) {\ - name,\ - eserial##port##_init,\ - NULL,\ - eserial##port##_setbrg,\ - eserial##port##_getc,\ - eserial##port##_tstc,\ - eserial##port##_putc,\ - eserial##port##_puts, } - -#endif /* CONFIG_SERIAL_MULTI */ - -static int calc_divisor (NS16550_t port) +#define serial_initfunc(name) \ + void name(void) \ + __attribute__((weak, alias("serial_null"))); + +serial_initfunc(mpc8xx_serial_initialize); +serial_initfunc(ns16550_serial_initialize); +serial_initfunc(pxa_serial_initialize); +serial_initfunc(s3c24xx_serial_initialize); +serial_initfunc(s5p_serial_initialize); +serial_initfunc(zynq_serial_initalize); +serial_initfunc(bfin_serial_initialize); +serial_initfunc(bfin_jtag_initialize); +serial_initfunc(mpc512x_serial_initialize); +serial_initfunc(uartlite_serial_initialize); +serial_initfunc(au1x00_serial_initialize); +serial_initfunc(asc_serial_initialize); +serial_initfunc(jz_serial_initialize); +serial_initfunc(mpc5xx_serial_initialize); +serial_initfunc(mpc8220_serial_initialize); +serial_initfunc(mpc8260_scc_serial_initialize); +serial_initfunc(mpc8260_smc_serial_initialize); +serial_initfunc(mpc85xx_serial_initialize); +serial_initfunc(iop480_serial_initialize); +serial_initfunc(leon2_serial_initialize); +serial_initfunc(leon3_serial_initialize); +serial_initfunc(marvell_serial_initialize); +serial_initfunc(amirix_serial_initialize); +serial_initfunc(bmw_serial_initialize); +serial_initfunc(cogent_serial_initialize); +serial_initfunc(cpci750_serial_initialize); +serial_initfunc(evb64260_serial_initialize); +serial_initfunc(ml2_serial_initialize); +serial_initfunc(sconsole_serial_initialize); +serial_initfunc(p3mx_serial_initialize); +serial_initfunc(altera_jtag_serial_initialize); +serial_initfunc(altera_serial_initialize); +serial_initfunc(atmel_serial_initialize); +serial_initfunc(lpc32xx_serial_initialize); +serial_initfunc(mcf_serial_initialize); +serial_initfunc(ns9750_serial_initialize); +serial_initfunc(oc_serial_initialize); +serial_initfunc(s3c4510b_serial_initialize); +serial_initfunc(s3c64xx_serial_initialize); +serial_initfunc(sandbox_serial_initialize); +serial_initfunc(clps7111_serial_initialize); +serial_initfunc(imx_serial_initialize); +serial_initfunc(ixp_serial_initialize); +serial_initfunc(ks8695_serial_initialize); +serial_initfunc(lh7a40x_serial_initialize); +serial_initfunc(lpc2292_serial_initialize); +serial_initfunc(max3100_serial_initialize); +serial_initfunc(mxc_serial_initialize); +serial_initfunc(netarm_serial_initialize); +serial_initfunc(pl01x_serial_initialize); +serial_initfunc(s3c44b0_serial_initialize); +serial_initfunc(sa1100_serial_initialize); +serial_initfunc(sh_serial_initialize); + +void serial_register(struct serial_device *dev) { -#ifdef CONFIG_OMAP1510 - /* If can't cleanly clock 115200 set div to 1 */ - if ((CONFIG_SYS_NS16550_CLK == 12000000) && (gd->baudrate == 115200)) { - port->osc_12m_sel = OSC_12M_SEL; /* enable 6.5 * divisor */ - return (1); /* return 1 for base divisor */ - } - port->osc_12m_sel = 0; /* clear if previsouly set */ -#endif -#ifdef CONFIG_OMAP1610 - /* If can't cleanly clock 115200 set div to 1 */ - if ((CONFIG_SYS_NS16550_CLK == 48000000) && (gd->baudrate == 115200)) { - return (26); /* return 26 for base divisor */ - } +#ifdef CONFIG_NEEDS_MANUAL_RELOC + if (dev->start) + dev->start += gd->reloc_off; + if (dev->stop) + dev->stop += gd->reloc_off; + if (dev->setbrg) + dev->setbrg += gd->reloc_off; + if (dev->getc) + dev->getc += gd->reloc_off; + if (dev->tstc) + dev->tstc += gd->reloc_off; + if (dev->putc) + dev->putc += gd->reloc_off; + if (dev->puts) + dev->puts += gd->reloc_off; #endif -#ifdef CONFIG_APTIX -#define MODE_X_DIV 13 -#else -#define MODE_X_DIV 16 -#endif + dev->next = serial_devices; + serial_devices = dev; +} - /* Compute divisor value. Normally, we should simply return: - * CONFIG_SYS_NS16550_CLK) / MODE_X_DIV / gd->baudrate - * but we need to round that value by adding 0.5. - * Rounding is especially important at high baud rates. - */ - return (CONFIG_SYS_NS16550_CLK + (gd->baudrate * (MODE_X_DIV / 2))) / - (MODE_X_DIV * gd->baudrate); +void serial_initialize(void) +{ + mpc8xx_serial_initialize(); + ns16550_serial_initialize(); + pxa_serial_initialize(); + s3c24xx_serial_initialize(); + s5p_serial_initialize(); + mpc512x_serial_initialize(); + bfin_serial_initialize(); + bfin_jtag_initialize(); + uartlite_serial_initialize(); + zynq_serial_initalize(); + au1x00_serial_initialize(); + asc_serial_initialize(); + jz_serial_initialize(); + mpc5xx_serial_initialize(); + mpc8220_serial_initialize(); + mpc8260_scc_serial_initialize(); + mpc8260_smc_serial_initialize(); + mpc85xx_serial_initialize(); + iop480_serial_initialize(); + leon2_serial_initialize(); + leon3_serial_initialize(); + marvell_serial_initialize(); + amirix_serial_initialize(); + bmw_serial_initialize(); + cogent_serial_initialize(); + cpci750_serial_initialize(); + evb64260_serial_initialize(); + ml2_serial_initialize(); + sconsole_serial_initialize(); + p3mx_serial_initialize(); + altera_jtag_serial_initialize(); + altera_serial_initialize(); + atmel_serial_initialize(); + lpc32xx_serial_initialize(); + mcf_serial_initialize(); + ns9750_serial_initialize(); + oc_serial_initialize(); + s3c4510b_serial_initialize(); + s3c64xx_serial_initialize(); + sandbox_serial_initialize(); + clps7111_serial_initialize(); + imx_serial_initialize(); + ixp_serial_initialize(); + ks8695_serial_initialize(); + lh7a40x_serial_initialize(); + lpc2292_serial_initialize(); + max3100_serial_initialize(); + mxc_serial_initialize(); + netarm_serial_initialize(); + pl01x_serial_initialize(); + s3c44b0_serial_initialize(); + sa1100_serial_initialize(); + sh_serial_initialize(); + + serial_assign(default_serial_console()->name); } -#if !defined(CONFIG_SERIAL_MULTI) -int serial_init (void) +void serial_stdio_init(void) { - int clock_divisor; + struct stdio_dev dev; + struct serial_device *s = serial_devices; -#ifdef CONFIG_NS87308 - initialise_ns87308(); -#endif + while (s) { + memset(&dev, 0, sizeof(dev)); -#ifdef CONFIG_SYS_NS16550_COM1 - clock_divisor = calc_divisor(serial_ports[0]); - NS16550_init(serial_ports[0], clock_divisor); -#endif -#ifdef CONFIG_SYS_NS16550_COM2 - clock_divisor = calc_divisor(serial_ports[1]); - NS16550_init(serial_ports[1], clock_divisor); -#endif -#ifdef CONFIG_SYS_NS16550_COM3 - clock_divisor = calc_divisor(serial_ports[2]); - NS16550_init(serial_ports[2], clock_divisor); -#endif -#ifdef CONFIG_SYS_NS16550_COM4 - clock_divisor = calc_divisor(serial_ports[3]); - NS16550_init(serial_ports[3], clock_divisor); -#endif + strcpy(dev.name, s->name); + dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT; - return (0); -} -#endif + dev.start = s->start; + dev.stop = s->stop; + dev.putc = s->putc; + dev.puts = s->puts; + dev.getc = s->getc; + dev.tstc = s->tstc; -void -_serial_putc(const char c,const int port) -{ - if (c == '\n') - NS16550_putc(PORT, '\r'); + stdio_register(&dev); - NS16550_putc(PORT, c); + s = s->next; + } } -void -_serial_putc_raw(const char c,const int port) +int serial_assign(const char *name) { - NS16550_putc(PORT, c); -} + struct serial_device *s; -void -_serial_puts (const char *s,const int port) -{ - while (*s) { - _serial_putc (*s++,port); + for (s = serial_devices; s; s = s->next) { + if (strcmp(s->name, name) == 0) { + serial_current = s; + return 0; + } } -} - -int -_serial_getc(const int port) -{ - return NS16550_getc(PORT); + return 1; } -int -_serial_tstc(const int port) +void serial_reinit_all(void) { - return NS16550_tstc(PORT); + struct serial_device *s; + + for (s = serial_devices; s; s = s->next) + s->start(); } -void -_serial_setbrg (const int port) +static struct serial_device *get_current(void) { - int clock_divisor; + struct serial_device *dev; - clock_divisor = calc_divisor(PORT); - NS16550_reinit(PORT, clock_divisor); -} + if (!(gd->flags & GD_FLG_RELOC) || !serial_current) { + dev = default_serial_console(); -#if defined(CONFIG_SERIAL_MULTI) -static inline void -serial_putc_dev(unsigned int dev_index,const char c) -{ - _serial_putc(c,dev_index); -} + /* We must have a console device */ + if (!dev) { +#ifdef CONFIG_SPL_BUILD + puts("Cannot find console\n"); + hang(); #else -void -serial_putc(const char c) -{ - _serial_putc(c,CONFIG_CONS_INDEX); -} + panic("Cannot find console\n"); #endif - -#if defined(CONFIG_SERIAL_MULTI) -static inline void -serial_putc_raw_dev(unsigned int dev_index,const char c) -{ - _serial_putc_raw(c,dev_index); -} -#else -void -serial_putc_raw(const char c) -{ - _serial_putc_raw(c,CONFIG_CONS_INDEX); + } + } else + dev = serial_current; + return dev; } -#endif -#if defined(CONFIG_SERIAL_MULTI) -static inline void -serial_puts_dev(unsigned int dev_index,const char *s) -{ - _serial_puts(s,dev_index); -} -#else -void -serial_puts(const char *s) +int serial_init(void) { - _serial_puts(s,CONFIG_CONS_INDEX); + return get_current()->start(); } -#endif -#if defined(CONFIG_SERIAL_MULTI) -static inline int -serial_getc_dev(unsigned int dev_index) +void serial_setbrg(void) { - return _serial_getc(dev_index); + get_current()->setbrg(); } -#else -int -serial_getc(void) -{ - return _serial_getc(CONFIG_CONS_INDEX); -} -#endif -#if defined(CONFIG_SERIAL_MULTI) -static inline int -serial_tstc_dev(unsigned int dev_index) +int serial_getc(void) { - return _serial_tstc(dev_index); + return get_current()->getc(); } -#else -int -serial_tstc(void) + +int serial_tstc(void) { - return _serial_tstc(CONFIG_CONS_INDEX); + return get_current()->tstc(); } -#endif -#if defined(CONFIG_SERIAL_MULTI) -static inline void -serial_setbrg_dev(unsigned int dev_index) +void serial_putc(const char c) { - _serial_setbrg(dev_index); + get_current()->putc(c); } -#else -void -serial_setbrg(void) + +void serial_puts(const char *s) { - _serial_setbrg(CONFIG_CONS_INDEX); + get_current()->puts(s); } -#endif -#if defined(CONFIG_SERIAL_MULTI) - -DECLARE_ESERIAL_FUNCTIONS(1); -struct serial_device eserial1_device = - INIT_ESERIAL_STRUCTURE(1, "eserial0"); -DECLARE_ESERIAL_FUNCTIONS(2); -struct serial_device eserial2_device = - INIT_ESERIAL_STRUCTURE(2, "eserial1"); -DECLARE_ESERIAL_FUNCTIONS(3); -struct serial_device eserial3_device = - INIT_ESERIAL_STRUCTURE(3, "eserial2"); -DECLARE_ESERIAL_FUNCTIONS(4); -struct serial_device eserial4_device = - INIT_ESERIAL_STRUCTURE(4, "eserial3"); - -__weak struct serial_device *default_serial_console(void) +#if CONFIG_POST & CONFIG_SYS_POST_UART +static const int bauds[] = CONFIG_SYS_BAUDRATE_TABLE; + +/* Mark weak until post/cpu/.../uart.c migrate over */ +__weak +int uart_post_test(int flags) { -#if CONFIG_CONS_INDEX == 1 - return &eserial1_device; -#elif CONFIG_CONS_INDEX == 2 - return &eserial2_device; -#elif CONFIG_CONS_INDEX == 3 - return &eserial3_device; -#elif CONFIG_CONS_INDEX == 4 - return &eserial4_device; -#else -#error "Bad CONFIG_CONS_INDEX." -#endif -} + unsigned char c; + int ret, saved_baud, b; + struct serial_device *saved_dev, *s; + bd_t *bd = gd->bd; + + /* Save current serial state */ + ret = 0; + saved_dev = serial_current; + saved_baud = bd->bi_baudrate; + + for (s = serial_devices; s; s = s->next) { + /* If this driver doesn't support loop back, skip it */ + if (!s->loop) + continue; + + /* Test the next device */ + serial_current = s; + + ret = serial_init(); + if (ret) + goto done; + + /* Consume anything that happens to be queued */ + while (serial_tstc()) + serial_getc(); + + /* Enable loop back */ + s->loop(1); + + /* Test every available baud rate */ + for (b = 0; b < ARRAY_SIZE(bauds); ++b) { + bd->bi_baudrate = bauds[b]; + serial_setbrg(); + + /* + * Stick to printable chars to avoid issues: + * - terminal corruption + * - serial program reacting to sequences and sending + * back random extra data + * - most serial drivers add in extra chars (like \r\n) + */ + for (c = 0x20; c < 0x7f; ++c) { + /* Send it out */ + serial_putc(c); + + /* Make sure it's the same one */ + ret = (c != serial_getc()); + if (ret) { + s->loop(0); + goto done; + } + + /* Clean up the output in case it was sent */ + serial_putc('\b'); + ret = ('\b' != serial_getc()); + if (ret) { + s->loop(0); + goto done; + } + } + } + + /* Disable loop back */ + s->loop(0); + + /* XXX: There is no serial_stop() !? */ + if (s->stop) + s->stop(); + } + + done: + /* Restore previous serial state */ + serial_current = saved_dev; + bd->bi_baudrate = saved_baud; + serial_reinit_all(); + serial_setbrg(); -#endif /* CONFIG_SERIAL_MULTI */ + return ret; +} +#endif diff --git a/drivers/serial/serial_clps7111.c b/drivers/serial/serial_clps7111.c index a6aecadd13..65473e8608 100644 --- a/drivers/serial/serial_clps7111.c +++ b/drivers/serial/serial_clps7111.c @@ -33,7 +33,7 @@ DECLARE_GLOBAL_DATA_PTR; -void serial_setbrg (void) +static void clps7111_serial_setbrg(void) { unsigned int reg = 0; @@ -63,7 +63,7 @@ void serial_setbrg (void) * are always 8 data bits, no parity, 1 stop bit, no start bits. * */ -int serial_init (void) +static int clps7111_serial_init(void) { serial_setbrg (); @@ -74,7 +74,7 @@ int serial_init (void) /* * Output a single byte to the serial port. */ -void serial_putc (const char c) +static void clps7111_serial_putc(const char c) { int tmo; @@ -95,7 +95,7 @@ void serial_putc (const char c) * otherwise. When the function is succesfull, the character read is * written into its argument c. */ -int serial_tstc (void) +static int clps7111_serial_tstc(void) { return !(IO_SYSFLG1 & SYSFLG1_URXFE); } @@ -105,17 +105,37 @@ int serial_tstc (void) * otherwise. When the function is succesfull, the character read is * written into its argument c. */ -int serial_getc (void) +static int clps7111_serial_getc(void) { while (IO_SYSFLG1 & SYSFLG1_URXFE); return IO_UARTDR1 & 0xff; } -void -serial_puts (const char *s) +static void clps7111_serial_puts(const char *s) { while (*s) { serial_putc (*s++); } } + +static struct serial_device clps7111_serial_drv = { + .name = "clps7111_serial", + .start = clps7111_serial_init, + .stop = NULL, + .setbrg = clps7111_serial_setbrg, + .putc = clps7111_serial_putc, + .puts = clps7111_serial_puts, + .getc = clps7111_serial_getc, + .tstc = clps7111_serial_tstc, +}; + +void clps7111_serial_initialize(void) +{ + serial_register(&clps7111_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &clps7111_serial_drv; +} diff --git a/drivers/serial/serial_imx.c b/drivers/serial/serial_imx.c index b9ca748f69..6c075b5b91 100644 --- a/drivers/serial/serial_imx.c +++ b/drivers/serial/serial_imx.c @@ -19,6 +19,8 @@ #include <common.h> #include <asm/arch/imx-regs.h> +#include <serial.h> +#include <linux/compiler.h> #if defined CONFIG_IMX_SERIAL1 #define UART_BASE IMX_UART1_BASE @@ -50,7 +52,7 @@ struct imx_serial { DECLARE_GLOBAL_DATA_PTR; -void serial_setbrg (void) +static void imx_serial_setbrg(void) { serial_init(); } @@ -62,7 +64,7 @@ extern void imx_gpio_mode(int gpio_mode); * are always 8 data bits, no parity, 1 stop bit, no start bits. * */ -int serial_init (void) +static int imx_serial_init(void) { volatile struct imx_serial* base = (struct imx_serial *)UART_BASE; unsigned int ufcr_rfdiv; @@ -163,7 +165,7 @@ int serial_init (void) * otherwise. When the function is successful, the character read is * written into its argument c. */ -int serial_getc (void) +static int imx_serial_getc(void) { volatile struct imx_serial* base = (struct imx_serial *)UART_BASE; unsigned char ch; @@ -185,7 +187,7 @@ int hwflow_onoff(int on) /* * Output a single byte to the serial port. */ -void serial_putc (const char c) +static void imx_serial_putc(const char c) { volatile struct imx_serial* base = (struct imx_serial *)UART_BASE; @@ -202,7 +204,7 @@ void serial_putc (const char c) /* * Test whether a character is in the RX buffer */ -int serial_tstc (void) +static int imx_serial_tstc(void) { volatile struct imx_serial* base = (struct imx_serial *)UART_BASE; @@ -212,10 +214,30 @@ int serial_tstc (void) return 1; } -void -serial_puts (const char *s) +static void imx_serial_puts(const char *s) { while (*s) { serial_putc (*s++); } } + +static struct serial_device imx_serial_drv = { + .name = "imx_serial", + .start = imx_serial_init, + .stop = NULL, + .setbrg = imx_serial_setbrg, + .putc = imx_serial_putc, + .puts = imx_serial_puts, + .getc = imx_serial_getc, + .tstc = imx_serial_tstc, +}; + +void imx_serial_initialize(void) +{ + serial_register(&imx_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &imx_serial_drv; +} diff --git a/drivers/serial/serial_ixp.c b/drivers/serial/serial_ixp.c index a9acd476c4..c8b3658d47 100644 --- a/drivers/serial/serial_ixp.c +++ b/drivers/serial/serial_ixp.c @@ -31,6 +31,8 @@ #include <common.h> #include <asm/arch/ixp425.h> #include <watchdog.h> +#include <serial.h> +#include <linux/compiler.h> /* * 14.7456 MHz @@ -41,7 +43,7 @@ DECLARE_GLOBAL_DATA_PTR; -void serial_setbrg (void) +static void ixp_serial_setbrg(void) { unsigned int quot = 0; int uart = CONFIG_SYS_IXP425_CONSOLE; @@ -72,7 +74,7 @@ void serial_setbrg (void) * are always 8 data bits, no parity, 1 stop bit, no start bits. * */ -int serial_init (void) +static int ixp_serial_init(void) { serial_setbrg (); @@ -83,7 +85,7 @@ int serial_init (void) /* * Output a single byte to the serial port. */ -void serial_putc (const char c) +static void ixp_serial_putc(const char c) { /* wait for room in the tx FIFO on UART */ while ((LSR(CONFIG_SYS_IXP425_CONSOLE) & LSR_TEMT) == 0) @@ -101,7 +103,7 @@ void serial_putc (const char c) * otherwise. When the function is succesfull, the character read is * written into its argument c. */ -int serial_tstc (void) +static int ixp_serial_tstc(void) { return LSR(CONFIG_SYS_IXP425_CONSOLE) & LSR_DR; } @@ -111,7 +113,7 @@ int serial_tstc (void) * otherwise. When the function is succesfull, the character read is * written into its argument c. */ -int serial_getc (void) +static int ixp_serial_getc(void) { while (!(LSR(CONFIG_SYS_IXP425_CONSOLE) & LSR_DR)) WATCHDOG_RESET(); /* Reset HW Watchdog, if needed */ @@ -119,10 +121,30 @@ int serial_getc (void) return (char) RBR(CONFIG_SYS_IXP425_CONSOLE) & 0xff; } -void -serial_puts (const char *s) +static void ixp_serial_puts(const char *s) { while (*s) { serial_putc (*s++); } } + +static struct serial_device ixp_serial_drv = { + .name = "ixp_serial", + .start = ixp_serial_init, + .stop = NULL, + .setbrg = ixp_serial_setbrg, + .putc = ixp_serial_putc, + .puts = ixp_serial_puts, + .getc = ixp_serial_getc, + .tstc = ixp_serial_tstc, +}; + +void ixp_serial_initialize(void) +{ + serial_register(&ixp_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &ixp_serial_drv; +} diff --git a/drivers/serial/serial_ks8695.c b/drivers/serial/serial_ks8695.c index aacd1be630..60e8007201 100644 --- a/drivers/serial/serial_ks8695.c +++ b/drivers/serial/serial_ks8695.c @@ -20,6 +20,8 @@ #include <common.h> #include <asm/arch/platform.h> +#include <serial.h> +#include <linux/compiler.h> #ifndef CONFIG_SERIAL1 #error "Bad: you didn't configure serial ..." @@ -54,7 +56,7 @@ struct ks8695uart { int serial_console = 1; -void serial_setbrg(void) +static void ks8695_serial_setbrg(void) { volatile struct ks8695uart *uartp = KS8695_UART_ADDR; @@ -63,14 +65,14 @@ void serial_setbrg(void) uartp->LCR = KS8695_UART_LINEC_WLEN8; } -int serial_init(void) +static int ks8695_serial_init(void) { serial_console = 1; serial_setbrg(); return 0; } -void serial_raw_putc(const char c) +static void ks8695_serial_raw_putc(const char c) { volatile struct ks8695uart *uartp = KS8695_UART_ADDR; int i; @@ -83,16 +85,16 @@ void serial_raw_putc(const char c) uartp->TX = c; } -void serial_putc(const char c) +static void ks8695_serial_putc(const char c) { if (serial_console) { - serial_raw_putc(c); + ks8695_serial_raw_putc(c); if (c == '\n') - serial_raw_putc('\r'); + ks8695_serial_raw_putc('\r'); } } -int serial_tstc(void) +static int ks8695_serial_tstc(void) { volatile struct ks8695uart *uartp = KS8695_UART_ADDR; if (serial_console) @@ -100,14 +102,14 @@ int serial_tstc(void) return 0; } -void serial_puts(const char *s) +static void ks8695_serial_puts(const char *s) { char c; while ((c = *s++) != 0) serial_putc(c); } -int serial_getc(void) +static int ks8695_serial_getc(void) { volatile struct ks8695uart *uartp = KS8695_UART_ADDR; @@ -115,3 +117,24 @@ int serial_getc(void) ; return (uartp->RX); } + +static struct serial_device ks8695_serial_drv = { + .name = "ks8695_serial", + .start = ks8695_serial_init, + .stop = NULL, + .setbrg = ks8695_serial_setbrg, + .putc = ks8695_serial_putc, + .puts = ks8695_serial_puts, + .getc = ks8695_serial_getc, + .tstc = ks8695_serial_tstc, +}; + +void ks8695_serial_initialize(void) +{ + serial_register(&ks8695_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &ks8695_serial_drv; +} diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c index 4767489aef..6c9628581b 100644 --- a/drivers/serial/serial_lh7a40x.c +++ b/drivers/serial/serial_lh7a40x.c @@ -33,7 +33,7 @@ DECLARE_GLOBAL_DATA_PTR; # error "No console configured ... " #endif -void serial_setbrg (void) +static void lh7a40x_serial_setbrg(void) { lh7a40x_uart_t* uart = LH7A40X_UART_PTR(UART_CONSOLE); int i; @@ -61,7 +61,7 @@ void serial_setbrg (void) * are always 8 data bits, no parity, 1 stop bit, no start bits. * */ -int serial_init (void) +static int lh7a40x_serial_init(void) { lh7a40x_uart_t* uart = LH7A40X_UART_PTR(UART_CONSOLE); @@ -95,7 +95,7 @@ int serial_init (void) * otherwise. When the function is succesfull, the character read is * written into its argument c. */ -int serial_getc (void) +static int lh7a40x_serial_getc(void) { lh7a40x_uart_t* uart = LH7A40X_UART_PTR(UART_CONSOLE); @@ -141,7 +141,7 @@ void enable_putc(void) /* * Output a single byte to the serial port. */ -void serial_putc (const char c) +static void lh7a40x_serial_putc(const char c) { lh7a40x_uart_t* uart = LH7A40X_UART_PTR(UART_CONSOLE); @@ -168,17 +168,37 @@ void serial_putc (const char c) /* * Test whether a character is in the RX buffer */ -int serial_tstc (void) +static int lh7a40x_serial_tstc(void) { lh7a40x_uart_t* uart = LH7A40X_UART_PTR(UART_CONSOLE); return(!(uart->status & UART_RXFE)); } -void -serial_puts (const char *s) +static void lh7a40x_serial_puts(const char *s) { while (*s) { serial_putc (*s++); } } + +static struct serial_device lh7a40x_serial_drv = { + .name = "lh7a40x_serial", + .start = lh7a40x_serial_init, + .stop = NULL, + .setbrg = lh7a40x_serial_setbrg, + .putc = lh7a40x_serial_putc, + .puts = lh7a40x_serial_puts, + .getc = lh7a40x_serial_getc, + .tstc = lh7a40x_serial_tstc, +}; + +void lh7a40x_serial_initialize(void) +{ + serial_register(&lh7a40x_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &lh7a40x_serial_drv; +} diff --git a/drivers/serial/serial_lpc2292.c b/drivers/serial/serial_lpc2292.c index e3a60b6cb4..fcab20280e 100644 --- a/drivers/serial/serial_lpc2292.c +++ b/drivers/serial/serial_lpc2292.c @@ -33,7 +33,7 @@ DECLARE_GLOBAL_DATA_PTR; -void serial_setbrg (void) +static void lpc2292_serial_setbrg(void) { unsigned short divisor = 0; @@ -57,7 +57,7 @@ void serial_setbrg (void) PUT8(U0FCR, 1); /* Enable RX and TX FIFOs */ } -int serial_init (void) +static int lpc2292_serial_init(void) { unsigned long pinsel0; @@ -71,7 +71,7 @@ int serial_init (void) return (0); } -void serial_putc (const char c) +static void lpc2292_serial_putc(const char c) { if (c == '\n') { @@ -83,14 +83,13 @@ void serial_putc (const char c) PUT8(U0THR, c); } -int serial_getc (void) +static int lpc2292_serial_getc(void) { while((GET8(U0LSR) & 1) == 0); return GET8(U0RBR); } -void -serial_puts (const char *s) +static void lpc2292_serial_puts(const char *s) { while (*s) { serial_putc (*s++); @@ -98,7 +97,28 @@ serial_puts (const char *s) } /* Test if there is a byte to read */ -int serial_tstc (void) +static int lpc2292_serial_tstc(void) { return (GET8(U0LSR) & 1); } + +static struct serial_device lpc2292_serial_drv = { + .name = "lpc2292_serial", + .start = lpc2292_serial_init, + .stop = NULL, + .setbrg = lpc2292_serial_setbrg, + .putc = lpc2292_serial_putc, + .puts = lpc2292_serial_puts, + .getc = lpc2292_serial_getc, + .tstc = lpc2292_serial_tstc, +}; + +void lpc2292_serial_initialize(void) +{ + serial_register(&lpc2292_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &lpc2292_serial_drv; +} diff --git a/drivers/serial/serial_max3100.c b/drivers/serial/serial_max3100.c index 4abc27109b..3533cfc6d7 100644 --- a/drivers/serial/serial_max3100.c +++ b/drivers/serial/serial_max3100.c @@ -25,6 +25,8 @@ #include <common.h> #include <watchdog.h> +#include <serial.h> +#include <linux/compiler.h> DECLARE_GLOBAL_DATA_PTR; @@ -149,7 +151,7 @@ static int rxfifo_in; static int rxfifo_out; static unsigned char rxfifo_buf[16]; -static void max3100_putc(int c) +static void max3100_serial_putc_raw(int c) { unsigned int rx; @@ -164,7 +166,7 @@ static void max3100_putc(int c) } } -static int max3100_getc(void) +static int max3100_serial_getc(void) { int c; unsigned int rx; @@ -190,7 +192,7 @@ static int max3100_getc(void) return c; } -static int max3100_tstc(void) +static int max3100_serial_tstc(void) { unsigned int rx; @@ -213,7 +215,7 @@ static int max3100_tstc(void) return 1; } -int serial_init(void) +static int max3100_serial_init(void) { unsigned int wconf, rconf; int i; @@ -268,31 +270,41 @@ int serial_init(void) return (0); } -void serial_putc(const char c) +static void max3100_serial_putc(const char c) { if (c == '\n') - max3100_putc('\r'); + max3100_serial_putc_raw('\r'); - max3100_putc(c); + max3100_serial_putc_raw(c); } -void serial_puts(const char *s) +static void max3100_serial_puts(const char *s) { while (*s) - serial_putc (*s++); + max3100_serial_putc_raw(*s++); } -int serial_getc(void) +static void max3100_serial_setbrg(void) { - return max3100_getc(); } -int serial_tstc(void) +static struct serial_device max3100_serial_drv = { + .name = "max3100_serial", + .start = max3100_serial_init, + .stop = NULL, + .setbrg = max3100_serial_setbrg, + .putc = max3100_serial_putc, + .puts = max3100_serial_puts, + .getc = max3100_serial_getc, + .tstc = max3100_serial_tstc, +}; + +void max3100_serial_initialize(void) { - return max3100_tstc(); + serial_register(&max3100_serial_drv); } -/* XXX WTF? */ -void serial_setbrg(void) +__weak struct serial_device *default_serial_console(void) { + return &max3100_serial_drv; } diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c index af00b9c0ec..b0612f5aca 100644 --- a/drivers/serial/serial_mxc.c +++ b/drivers/serial/serial_mxc.c @@ -21,6 +21,8 @@ #include <watchdog.h> #include <asm/arch/imx-regs.h> #include <asm/arch/clock.h> +#include <serial.h> +#include <linux/compiler.h> #define __REG(x) (*((volatile u32 *)(x))) @@ -30,10 +32,6 @@ #define UART_PHYS CONFIG_MXC_UART_BASE -#ifdef CONFIG_SERIAL_MULTI -#warning "MXC driver does not support MULTI serials." -#endif - /* Register definitions */ #define URXD 0x0 /* Receiver Register */ #define UTXD 0x40 /* Transmitter Register */ @@ -145,7 +143,7 @@ DECLARE_GLOBAL_DATA_PTR; -void serial_setbrg (void) +static void mxc_serial_setbrg(void) { u32 clk = imx_get_uartclk(); @@ -158,14 +156,14 @@ void serial_setbrg (void) } -int serial_getc (void) +static int mxc_serial_getc(void) { while (__REG(UART_PHYS + UTS) & UTS_RXEMPTY) WATCHDOG_RESET(); return (__REG(UART_PHYS + URXD) & URXD_RX_DATA); /* mask out status from upper word */ } -void serial_putc (const char c) +static void mxc_serial_putc(const char c) { __REG(UART_PHYS + UTXD) = c; @@ -181,7 +179,7 @@ void serial_putc (const char c) /* * Test whether a character is in the RX buffer */ -int serial_tstc (void) +static int mxc_serial_tstc(void) { /* If receive fifo is empty, return false */ if (__REG(UART_PHYS + UTS) & UTS_RXEMPTY) @@ -189,8 +187,7 @@ int serial_tstc (void) return 1; } -void -serial_puts (const char *s) +static void mxc_serial_puts(const char *s) { while (*s) { serial_putc (*s++); @@ -202,7 +199,7 @@ serial_puts (const char *s) * are always 8 data bits, no parity, 1 stop bit, no start bits. * */ -int serial_init (void) +static int mxc_serial_init(void) { __REG(UART_PHYS + UCR1) = 0x0; __REG(UART_PHYS + UCR2) = 0x0; @@ -224,3 +221,24 @@ int serial_init (void) return 0; } + +static struct serial_device mxc_serial_drv = { + .name = "mxc_serial", + .start = mxc_serial_init, + .stop = NULL, + .setbrg = mxc_serial_setbrg, + .putc = mxc_serial_putc, + .puts = mxc_serial_puts, + .getc = mxc_serial_getc, + .tstc = mxc_serial_tstc, +}; + +void mxc_serial_initialize(void) +{ + serial_register(&mxc_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &mxc_serial_drv; +} diff --git a/drivers/serial/serial_netarm.c b/drivers/serial/serial_netarm.c index d04790d270..d30adc3183 100644 --- a/drivers/serial/serial_netarm.c +++ b/drivers/serial/serial_netarm.c @@ -59,7 +59,7 @@ extern void _netarm_led_FAIL1(void); /* * Setup both serial i/f with given baudrate */ -void serial_setbrg (void) +static void netarm_serial_setbrg(void) { /* set 0 ... make sure pins are configured for serial */ #if !defined(CONFIG_NETARM_NS7520) @@ -108,7 +108,7 @@ void serial_setbrg (void) * Initialise the serial port with the given baudrate. The settings * are always 8 data bits, no parity, 1 stop bit, no start bits. */ -int serial_init (void) +static int netarm_serial_init(void) { serial_setbrg (); return 0; @@ -118,7 +118,7 @@ int serial_init (void) /* * Output a single byte to the serial port. */ -void serial_putc (const char c) +static void netarm_serial_putc(const char c) { volatile unsigned char *fifo; @@ -135,7 +135,7 @@ void serial_putc (const char c) * Test of a single byte from the serial port. Returns 1 on success, 0 * otherwise. */ -int serial_tstc(void) +static int netarm_serial_tstc(void) { return serial_reg_ch1->status_a & NETARM_SER_STATA_RX_RDY; } @@ -144,7 +144,7 @@ int serial_tstc(void) * Read a single byte from the serial port. Returns 1 on success, 0 * otherwise. */ -int serial_getc (void) +static int netarm_serial_getc(void) { unsigned int ch_uint; volatile unsigned int *fifo; @@ -182,9 +182,30 @@ int serial_getc (void) return ch_uint & 0xff; } -void serial_puts (const char *s) +static void netarm_serial_puts(const char *s) { while (*s) { serial_putc (*s++); } } + +static struct serial_device netarm_serial_drv = { + .name = "netarm_serial", + .start = netarm_serial_init, + .stop = NULL, + .setbrg = netarm_serial_setbrg, + .putc = netarm_serial_putc, + .puts = netarm_serial_puts, + .getc = netarm_serial_getc, + .tstc = netarm_serial_tstc, +}; + +void netarm_serial_initialize(void) +{ + serial_register(&netarm_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &netarm_serial_drv; +} diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c new file mode 100644 index 0000000000..b5d12481ca --- /dev/null +++ b/drivers/serial/serial_ns16550.c @@ -0,0 +1,264 @@ +/* + * (C) Copyright 2000 + * Rob Taylor, Flying Pig Systems. robt@flyingpig.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <linux/compiler.h> + +#include <ns16550.h> +#ifdef CONFIG_NS87308 +#include <ns87308.h> +#endif + +#include <serial.h> + +DECLARE_GLOBAL_DATA_PTR; + +#if !defined(CONFIG_CONS_INDEX) +#elif (CONFIG_CONS_INDEX < 1) || (CONFIG_CONS_INDEX > 4) +#error "Invalid console index value." +#endif + +#if CONFIG_CONS_INDEX == 1 && !defined(CONFIG_SYS_NS16550_COM1) +#error "Console port 1 defined but not configured." +#elif CONFIG_CONS_INDEX == 2 && !defined(CONFIG_SYS_NS16550_COM2) +#error "Console port 2 defined but not configured." +#elif CONFIG_CONS_INDEX == 3 && !defined(CONFIG_SYS_NS16550_COM3) +#error "Console port 3 defined but not configured." +#elif CONFIG_CONS_INDEX == 4 && !defined(CONFIG_SYS_NS16550_COM4) +#error "Console port 4 defined but not configured." +#endif + +/* Note: The port number specified in the functions is 1 based. + * the array is 0 based. + */ +static NS16550_t serial_ports[4] = { +#ifdef CONFIG_SYS_NS16550_COM1 + (NS16550_t)CONFIG_SYS_NS16550_COM1, +#else + NULL, +#endif +#ifdef CONFIG_SYS_NS16550_COM2 + (NS16550_t)CONFIG_SYS_NS16550_COM2, +#else + NULL, +#endif +#ifdef CONFIG_SYS_NS16550_COM3 + (NS16550_t)CONFIG_SYS_NS16550_COM3, +#else + NULL, +#endif +#ifdef CONFIG_SYS_NS16550_COM4 + (NS16550_t)CONFIG_SYS_NS16550_COM4 +#else + NULL +#endif +}; + +#define PORT serial_ports[port-1] + +/* Multi serial device functions */ +#define DECLARE_ESERIAL_FUNCTIONS(port) \ + int eserial##port##_init (void) {\ + int clock_divisor; \ + clock_divisor = calc_divisor(serial_ports[port-1]); \ + NS16550_init(serial_ports[port-1], clock_divisor); \ + return(0);}\ + void eserial##port##_setbrg (void) {\ + serial_setbrg_dev(port);}\ + int eserial##port##_getc (void) {\ + return serial_getc_dev(port);}\ + int eserial##port##_tstc (void) {\ + return serial_tstc_dev(port);}\ + void eserial##port##_putc (const char c) {\ + serial_putc_dev(port, c);}\ + void eserial##port##_puts (const char *s) {\ + serial_puts_dev(port, s);} + +/* Serial device descriptor */ +#define INIT_ESERIAL_STRUCTURE(port, __name) { \ + .name = __name, \ + .start = eserial##port##_init, \ + .stop = NULL, \ + .setbrg = eserial##port##_setbrg, \ + .getc = eserial##port##_getc, \ + .tstc = eserial##port##_tstc, \ + .putc = eserial##port##_putc, \ + .puts = eserial##port##_puts, \ +} + +static int calc_divisor (NS16550_t port) +{ +#ifdef CONFIG_OMAP1510 + /* If can't cleanly clock 115200 set div to 1 */ + if ((CONFIG_SYS_NS16550_CLK == 12000000) && (gd->baudrate == 115200)) { + port->osc_12m_sel = OSC_12M_SEL; /* enable 6.5 * divisor */ + return (1); /* return 1 for base divisor */ + } + port->osc_12m_sel = 0; /* clear if previsouly set */ +#endif +#ifdef CONFIG_OMAP1610 + /* If can't cleanly clock 115200 set div to 1 */ + if ((CONFIG_SYS_NS16550_CLK == 48000000) && (gd->baudrate == 115200)) { + return (26); /* return 26 for base divisor */ + } +#endif + +#ifdef CONFIG_APTIX +#define MODE_X_DIV 13 +#else +#define MODE_X_DIV 16 +#endif + + /* Compute divisor value. Normally, we should simply return: + * CONFIG_SYS_NS16550_CLK) / MODE_X_DIV / gd->baudrate + * but we need to round that value by adding 0.5. + * Rounding is especially important at high baud rates. + */ + return (CONFIG_SYS_NS16550_CLK + (gd->baudrate * (MODE_X_DIV / 2))) / + (MODE_X_DIV * gd->baudrate); +} + +void +_serial_putc(const char c,const int port) +{ + if (c == '\n') + NS16550_putc(PORT, '\r'); + + NS16550_putc(PORT, c); +} + +void +_serial_putc_raw(const char c,const int port) +{ + NS16550_putc(PORT, c); +} + +void +_serial_puts (const char *s,const int port) +{ + while (*s) { + _serial_putc (*s++,port); + } +} + + +int +_serial_getc(const int port) +{ + return NS16550_getc(PORT); +} + +int +_serial_tstc(const int port) +{ + return NS16550_tstc(PORT); +} + +void +_serial_setbrg (const int port) +{ + int clock_divisor; + + clock_divisor = calc_divisor(PORT); + NS16550_reinit(PORT, clock_divisor); +} + +static inline void +serial_putc_dev(unsigned int dev_index,const char c) +{ + _serial_putc(c,dev_index); +} + +static inline void +serial_putc_raw_dev(unsigned int dev_index,const char c) +{ + _serial_putc_raw(c,dev_index); +} + +static inline void +serial_puts_dev(unsigned int dev_index,const char *s) +{ + _serial_puts(s,dev_index); +} + +static inline int +serial_getc_dev(unsigned int dev_index) +{ + return _serial_getc(dev_index); +} + +static inline int +serial_tstc_dev(unsigned int dev_index) +{ + return _serial_tstc(dev_index); +} + +static inline void +serial_setbrg_dev(unsigned int dev_index) +{ + _serial_setbrg(dev_index); +} + +DECLARE_ESERIAL_FUNCTIONS(1); +struct serial_device eserial1_device = + INIT_ESERIAL_STRUCTURE(1, "eserial0"); +DECLARE_ESERIAL_FUNCTIONS(2); +struct serial_device eserial2_device = + INIT_ESERIAL_STRUCTURE(2, "eserial1"); +DECLARE_ESERIAL_FUNCTIONS(3); +struct serial_device eserial3_device = + INIT_ESERIAL_STRUCTURE(3, "eserial2"); +DECLARE_ESERIAL_FUNCTIONS(4); +struct serial_device eserial4_device = + INIT_ESERIAL_STRUCTURE(4, "eserial3"); + +__weak struct serial_device *default_serial_console(void) +{ +#if CONFIG_CONS_INDEX == 1 + return &eserial1_device; +#elif CONFIG_CONS_INDEX == 2 + return &eserial2_device; +#elif CONFIG_CONS_INDEX == 3 + return &eserial3_device; +#elif CONFIG_CONS_INDEX == 4 + return &eserial4_device; +#else +#error "Bad CONFIG_CONS_INDEX." +#endif +} + +void ns16550_serial_initialize(void) +{ +#if defined(CONFIG_SYS_NS16550_COM1) + serial_register(&eserial1_device); +#endif +#if defined(CONFIG_SYS_NS16550_COM2) + serial_register(&eserial2_device); +#endif +#if defined(CONFIG_SYS_NS16550_COM3) + serial_register(&eserial3_device); +#endif +#if defined(CONFIG_SYS_NS16550_COM4) + serial_register(&eserial4_device); +#endif +} diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c index d4c5137092..7db7b65c3f 100644 --- a/drivers/serial/serial_pl01x.c +++ b/drivers/serial/serial_pl01x.c @@ -30,6 +30,8 @@ #include <common.h> #include <watchdog.h> #include <asm/io.h> +#include <serial.h> +#include <linux/compiler.h> #include "serial_pl01x.h" /* @@ -54,7 +56,7 @@ static struct pl01x_regs *pl01x_get_regs(int portnum) #ifdef CONFIG_PL010_SERIAL -int serial_init (void) +static int pl01x_serial_init(void) { struct pl01x_regs *regs = pl01x_get_regs(CONSOLE_PORT); unsigned int divisor; @@ -104,7 +106,7 @@ int serial_init (void) #ifdef CONFIG_PL011_SERIAL -int serial_init (void) +static int pl01x_serial_init(void) { struct pl01x_regs *regs = pl01x_get_regs(CONSOLE_PORT); unsigned int temp; @@ -169,7 +171,7 @@ int serial_init (void) #endif /* CONFIG_PL011_SERIAL */ -void serial_putc (const char c) +static void pl01x_serial_putc(const char c) { if (c == '\n') pl01x_putc (CONSOLE_PORT, '\r'); @@ -177,24 +179,24 @@ void serial_putc (const char c) pl01x_putc (CONSOLE_PORT, c); } -void serial_puts (const char *s) +static void pl01x_serial_puts(const char *s) { while (*s) { serial_putc (*s++); } } -int serial_getc (void) +static int pl01x_serial_getc(void) { return pl01x_getc (CONSOLE_PORT); } -int serial_tstc (void) +static int pl01x_serial_tstc(void) { return pl01x_tstc (CONSOLE_PORT); } -void serial_setbrg (void) +static void pl01x_serial_setbrg(void) { struct pl01x_regs *regs = pl01x_get_regs(CONSOLE_PORT); @@ -250,3 +252,24 @@ static int pl01x_tstc (int portnum) WATCHDOG_RESET(); return !(readl(®s->fr) & UART_PL01x_FR_RXFE); } + +static struct serial_device pl01x_serial_drv = { + .name = "pl01x_serial", + .start = pl01x_serial_init, + .stop = NULL, + .setbrg = pl01x_serial_setbrg, + .putc = pl01x_serial_putc, + .puts = pl01x_serial_puts, + .getc = pl01x_serial_getc, + .tstc = pl01x_serial_tstc, +}; + +void pl01x_serial_initialize(void) +{ + serial_register(&pl01x_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &pl01x_serial_drv; +} diff --git a/drivers/serial/serial_pxa.c b/drivers/serial/serial_pxa.c index a9976d709a..ad391004b9 100644 --- a/drivers/serial/serial_pxa.c +++ b/drivers/serial/serial_pxa.c @@ -36,6 +36,7 @@ #include <asm/arch/pxa-regs.h> #include <asm/arch/regs-uart.h> #include <asm/io.h> +#include <linux/compiler.h> DECLARE_GLOBAL_DATA_PTR; @@ -72,21 +73,7 @@ DECLARE_GLOBAL_DATA_PTR; #define HWUART_INDEX 0xff #endif -#ifndef CONFIG_SERIAL_MULTI -#if defined(CONFIG_FFUART) -#define UART_INDEX FFUART_INDEX -#elif defined(CONFIG_BTUART) -#define UART_INDEX BTUART_INDEX -#elif defined(CONFIG_STUART) -#define UART_INDEX STUART_INDEX -#elif defined(CONFIG_HWUART) -#define UART_INDEX HWUART_INDEX -#else -#error "Please select CONFIG_(FF|BT|ST|HW)UART in board config file." -#endif -#endif - -uint32_t pxa_uart_get_baud_divider(void) +static uint32_t pxa_uart_get_baud_divider(void) { if (gd->baudrate == 1200) return 768; @@ -104,7 +91,7 @@ uint32_t pxa_uart_get_baud_divider(void) return 0; } -struct pxa_uart_regs *pxa_uart_index_to_regs(uint32_t uart_index) +static struct pxa_uart_regs *pxa_uart_index_to_regs(uint32_t uart_index) { switch (uart_index) { case FFUART_INDEX: return (struct pxa_uart_regs *)FFUART_BASE; @@ -116,7 +103,7 @@ struct pxa_uart_regs *pxa_uart_index_to_regs(uint32_t uart_index) } } -void pxa_uart_toggle_clock(uint32_t uart_index, int enable) +static void pxa_uart_toggle_clock(uint32_t uart_index, int enable) { uint32_t clk_reg, clk_offset, reg; @@ -269,14 +256,14 @@ void pxa_puts_dev(unsigned int uart_index, const char *s) #define pxa_uart_desc(uart) \ struct serial_device serial_##uart##_device = \ { \ - "serial_"#uart, \ - uart##_init, \ - NULL, \ - uart##_setbrg, \ - uart##_getc, \ - uart##_tstc, \ - uart##_putc, \ - uart##_puts, \ + .name = "serial_"#uart, \ + .start = uart##_init, \ + .stop = NULL, \ + .setbrg = uart##_setbrg, \ + .getc = uart##_getc, \ + .tstc = uart##_tstc, \ + .putc = uart##_putc, \ + .puts = uart##_puts, \ }; #define pxa_uart_multi(uart, UART) \ @@ -296,6 +283,30 @@ void pxa_puts_dev(unsigned int uart_index, const char *s) pxa_uart_multi(btuart, BTUART) #endif -#ifndef CONFIG_SERIAL_MULTI - pxa_uart(serial, UART) +__weak struct serial_device *default_serial_console(void) +{ +#if CONFIG_CONS_INDEX == 1 + return &serial_hwuart_device; +#elif CONFIG_CONS_INDEX == 2 + return &serial_stuart_device; +#elif CONFIG_CONS_INDEX == 3 + return &serial_ffuart_device; +#elif CONFIG_CONS_INDEX == 4 + return &serial_btuart_device; +#else +#error "Bad CONFIG_CONS_INDEX." #endif +} + +void pxa_serial_initialize(void) +{ +#if defined(CONFIG_FFUART) + serial_register(&serial_ffuart_device); +#endif +#if defined(CONFIG_BTUART) + serial_register(&serial_btuart_device); +#endif +#if defined(CONFIG_STUART) + serial_register(&serial_stuart_device); +#endif +} diff --git a/drivers/serial/serial_s3c24x0.c b/drivers/serial/serial_s3c24x0.c index 12bcdd3dbf..4d214c396f 100644 --- a/drivers/serial/serial_s3c24x0.c +++ b/drivers/serial/serial_s3c24x0.c @@ -38,8 +38,6 @@ DECLARE_GLOBAL_DATA_PTR; #endif #include <asm/io.h> - -#if defined(CONFIG_SERIAL_MULTI) #include <serial.h> /* Multi serial device functions */ @@ -69,19 +67,17 @@ DECLARE_GLOBAL_DATA_PTR; serial_puts_dev(port, s); \ } -#define INIT_S3C_SERIAL_STRUCTURE(port, name) { \ - name, \ - s3serial##port##_init, \ - NULL,\ - s3serial##port##_setbrg, \ - s3serial##port##_getc, \ - s3serial##port##_tstc, \ - s3serial##port##_putc, \ - s3serial##port##_puts, \ +#define INIT_S3C_SERIAL_STRUCTURE(port, __name) { \ + .name = __name, \ + .start = s3serial##port##_init, \ + .stop = NULL, \ + .setbrg = s3serial##port##_setbrg, \ + .getc = s3serial##port##_getc, \ + .tstc = s3serial##port##_tstc, \ + .putc = s3serial##port##_putc, \ + .puts = s3serial##port##_puts, \ } -#endif /* CONFIG_SERIAL_MULTI */ - #ifdef CONFIG_HWFLOW static int hwflow; #endif @@ -100,18 +96,10 @@ void _serial_setbrg(const int dev_index) /* Delay */ ; } -#if defined(CONFIG_SERIAL_MULTI) static inline void serial_setbrg_dev(unsigned int dev_index) { _serial_setbrg(dev_index); } -#else -void serial_setbrg(void) -{ - _serial_setbrg(UART_NR); -} -#endif - /* Initialise the serial port. The settings are always 8 data bits, no parity, * 1 stop bit, no start bits. @@ -151,16 +139,6 @@ static int serial_init_dev(const int dev_index) return (0); } -#if !defined(CONFIG_SERIAL_MULTI) -/* Initialise the serial port. The settings are always 8 data bits, no parity, - * 1 stop bit, no start bits. - */ -int serial_init(void) -{ - return serial_init_dev(UART_NR); -} -#endif - /* * Read a single byte from the serial port. Returns 1 on success, 0 * otherwise. When the function is succesfull, the character read is @@ -176,17 +154,10 @@ int _serial_getc(const int dev_index) return readb(&uart->urxh) & 0xff; } -#if defined(CONFIG_SERIAL_MULTI) static inline int serial_getc_dev(unsigned int dev_index) { return _serial_getc(dev_index); } -#else -int serial_getc(void) -{ - return _serial_getc(UART_NR); -} -#endif #ifdef CONFIG_HWFLOW int hwflow_onoff(int on) @@ -246,18 +217,10 @@ void _serial_putc(const char c, const int dev_index) serial_putc('\r'); } -#if defined(CONFIG_SERIAL_MULTI) static inline void serial_putc_dev(unsigned int dev_index, const char c) { _serial_putc(c, dev_index); } -#else -void serial_putc(const char c) -{ - _serial_putc(c, UART_NR); -} -#endif - /* * Test whether a character is in the RX buffer @@ -269,17 +232,10 @@ int _serial_tstc(const int dev_index) return readl(&uart->utrstat) & 0x1; } -#if defined(CONFIG_SERIAL_MULTI) static inline int serial_tstc_dev(unsigned int dev_index) { return _serial_tstc(dev_index); } -#else -int serial_tstc(void) -{ - return _serial_tstc(UART_NR); -} -#endif void _serial_puts(const char *s, const int dev_index) { @@ -288,19 +244,11 @@ void _serial_puts(const char *s, const int dev_index) } } -#if defined(CONFIG_SERIAL_MULTI) static inline void serial_puts_dev(int dev_index, const char *s) { _serial_puts(s, dev_index); } -#else -void serial_puts(const char *s) -{ - _serial_puts(s, UART_NR); -} -#endif -#if defined(CONFIG_SERIAL_MULTI) DECLARE_S3C_SERIAL_FUNCTIONS(0); struct serial_device s3c24xx_serial0_device = INIT_S3C_SERIAL_STRUCTURE(0, "s3ser0"); @@ -323,4 +271,10 @@ __weak struct serial_device *default_serial_console(void) #error "CONFIG_SERIAL? missing." #endif } -#endif /* CONFIG_SERIAL_MULTI */ + +void s3c24xx_serial_initialize(void) +{ + serial_register(&s3c24xx_serial0_device); + serial_register(&s3c24xx_serial1_device); + serial_register(&s3c24xx_serial2_device); +} diff --git a/drivers/serial/serial_s3c44b0.c b/drivers/serial/serial_s3c44b0.c index 95d0266c6c..a4428e0f47 100644 --- a/drivers/serial/serial_s3c44b0.c +++ b/drivers/serial/serial_s3c44b0.c @@ -68,7 +68,7 @@ static int serial_flush_output(void) } -void serial_setbrg (void) +static void s3c44b0_serial_setbrg(void) { u32 divisor = 0; @@ -156,7 +156,7 @@ void serial_setbrg (void) * are always 8 data bits, no parity, 1 stop bit, no start bits. * */ -int serial_init (void) +static int s3c44b0_serial_init(void) { serial_setbrg (); @@ -167,7 +167,7 @@ int serial_init (void) /* * Output a single byte to the serial port. */ -void serial_putc (const char c) +static void s3c44b0_serial_putc(const char c) { /* wait for room in the transmit FIFO */ while(!(UTRSTAT0 & 0x02)); @@ -187,7 +187,7 @@ void serial_putc (const char c) * otherwise. When the function is succesfull, the character read is * written into its argument c. */ -int serial_tstc (void) +static int s3c44b0_serial_tstc(void) { return (UTRSTAT0 & 0x01); } @@ -197,22 +197,42 @@ int serial_tstc (void) * otherwise. When the function is succesfull, the character read is * written into its argument c. */ -int serial_getc (void) +static int s3c44b0_serial_getc(void) { int rv; for(;;) { - rv = serial_tstc(); + rv = s3c44b0_serial_tstc(); if(rv > 0) return URXH0; } } -void -serial_puts (const char *s) +static void s3c44b0_serial_puts(const char *s) { while (*s) { serial_putc (*s++); } } + +static struct serial_device s3c44b0_serial_drv = { + .name = "s3c44b0_serial", + .start = s3c44b0_serial_init, + .stop = NULL, + .setbrg = s3c44b0_serial_setbrg, + .putc = s3c44b0_serial_putc, + .puts = s3c44b0_serial_puts, + .getc = s3c44b0_serial_getc, + .tstc = s3c44b0_serial_tstc, +}; + +void s3c44b0_serial_initialize(void) +{ + serial_register(&s3c44b0_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &s3c44b0_serial_drv; +} diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c index 6819bb07b7..3c41242a8e 100644 --- a/drivers/serial/serial_s5p.c +++ b/drivers/serial/serial_s5p.c @@ -183,15 +183,16 @@ int s5p_serial##port##_tstc(void) { return serial_tstc_dev(port); } \ void s5p_serial##port##_putc(const char c) { serial_putc_dev(c, port); } \ void s5p_serial##port##_puts(const char *s) { serial_puts_dev(s, port); } -#define INIT_S5P_SERIAL_STRUCTURE(port, name) { \ - name, \ - s5p_serial##port##_init, \ - NULL, \ - s5p_serial##port##_setbrg, \ - s5p_serial##port##_getc, \ - s5p_serial##port##_tstc, \ - s5p_serial##port##_putc, \ - s5p_serial##port##_puts, } +#define INIT_S5P_SERIAL_STRUCTURE(port, __name) { \ + .name = __name, \ + .start = s5p_serial##port##_init, \ + .stop = NULL, \ + .setbrg = s5p_serial##port##_setbrg, \ + .getc = s5p_serial##port##_getc, \ + .tstc = s5p_serial##port##_tstc, \ + .putc = s5p_serial##port##_putc, \ + .puts = s5p_serial##port##_puts, \ +} DECLARE_S5P_SERIAL_FUNCTIONS(0); struct serial_device s5p_serial0_device = @@ -220,3 +221,11 @@ __weak struct serial_device *default_serial_console(void) #error "CONFIG_SERIAL? missing." #endif } + +void s5p_serial_initialize(void) +{ + serial_register(&s5p_serial0_device); + serial_register(&s5p_serial1_device); + serial_register(&s5p_serial2_device); + serial_register(&s5p_serial3_device); +} diff --git a/drivers/serial/serial_sa1100.c b/drivers/serial/serial_sa1100.c index 5d1887580d..c6b34db7c6 100644 --- a/drivers/serial/serial_sa1100.c +++ b/drivers/serial/serial_sa1100.c @@ -30,10 +30,12 @@ #include <common.h> #include <SA-1100.h> +#include <serial.h> +#include <linux/compiler.h> DECLARE_GLOBAL_DATA_PTR; -void serial_setbrg (void) +static void sa1100_serial_setbrg(void) { unsigned int reg = 0; @@ -89,7 +91,7 @@ void serial_setbrg (void) * are always 8 data bits, no parity, 1 stop bit, no start bits. * */ -int serial_init (void) +static int sa1100_serial_init(void) { serial_setbrg (); @@ -100,7 +102,7 @@ int serial_init (void) /* * Output a single byte to the serial port. */ -void serial_putc (const char c) +static void sa1100_serial_putc(const char c) { #ifdef CONFIG_SERIAL1 /* wait for room in the tx FIFO on SERIAL1 */ @@ -124,7 +126,7 @@ void serial_putc (const char c) * otherwise. When the function is succesfull, the character read is * written into its argument c. */ -int serial_tstc (void) +static int sa1100_serial_tstc(void) { #ifdef CONFIG_SERIAL1 return Ser1UTSR1 & UTSR1_RNE; @@ -138,7 +140,7 @@ int serial_tstc (void) * otherwise. When the function is succesfull, the character read is * written into its argument c. */ -int serial_getc (void) +static int sa1100_serial_getc(void) { #ifdef CONFIG_SERIAL1 while (!(Ser1UTSR1 & UTSR1_RNE)); @@ -151,10 +153,30 @@ int serial_getc (void) #endif } -void -serial_puts (const char *s) +static void sa1100_serial_puts(const char *s) { while (*s) { serial_putc (*s++); } } + +static struct serial_device sa1100_serial_drv = { + .name = "sa1100_serial", + .start = sa1100_serial_init, + .stop = NULL, + .setbrg = sa1100_serial_setbrg, + .putc = sa1100_serial_putc, + .puts = sa1100_serial_puts, + .getc = sa1100_serial_getc, + .tstc = sa1100_serial_tstc, +}; + +void sa1100_serial_initialize(void) +{ + serial_register(&sa1100_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &sa1100_serial_drv; +} diff --git a/drivers/serial/serial_sh.c b/drivers/serial/serial_sh.c index 13919c623b..1ddfc7d87f 100644 --- a/drivers/serial/serial_sh.c +++ b/drivers/serial/serial_sh.c @@ -22,6 +22,8 @@ #include <asm/io.h> #include <asm/processor.h> #include "serial_sh.h" +#include <serial.h> +#include <linux/compiler.h> #if defined(CONFIG_CONS_SCIF0) # define SCIF_BASE SCIF0_BASE @@ -55,13 +57,13 @@ static struct uart_port sh_sci = { .type = SCIF_BASE_PORT, }; -void serial_setbrg(void) +static void sh_serial_setbrg(void) { DECLARE_GLOBAL_DATA_PTR; sci_out(&sh_sci, SCBRR, SCBRR_VALUE(gd->baudrate, CONFIG_SYS_CLK_FREQ)); } -int serial_init(void) +static int sh_serial_init(void) { sci_out(&sh_sci, SCSCR , SCSCR_INIT(&sh_sci)); sci_out(&sh_sci, SCSCR , SCSCR_INIT(&sh_sci)); @@ -127,21 +129,21 @@ void serial_raw_putc(const char c) sci_out(&sh_sci, SCxSR, sci_in(&sh_sci, SCxSR) & ~SCxSR_TEND(&sh_sci)); } -void serial_putc(const char c) +static void sh_serial_putc(const char c) { if (c == '\n') serial_raw_putc('\r'); serial_raw_putc(c); } -void serial_puts(const char *s) +static void sh_serial_puts(const char *s) { char c; while ((c = *s++) != 0) serial_putc(c); } -int serial_tstc(void) +static int sh_serial_tstc(void) { return serial_rx_fifo_level() ? 1 : 0; } @@ -167,7 +169,7 @@ int serial_getc_check(void) return status & (SCIF_DR | SCxSR_RDxF(&sh_sci)); } -int serial_getc(void) +static int sh_serial_getc(void) { unsigned short status; char ch; @@ -187,3 +189,24 @@ int serial_getc(void) handle_error(); return ch; } + +static struct serial_device sh_serial_drv = { + .name = "sh_serial", + .start = sh_serial_init, + .stop = NULL, + .setbrg = sh_serial_setbrg, + .putc = sh_serial_putc, + .puts = sh_serial_puts, + .getc = sh_serial_getc, + .tstc = sh_serial_tstc, +}; + +void sh_serial_initialize(void) +{ + serial_register(&sh_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &sh_serial_drv; +} diff --git a/drivers/serial/serial_xuartlite.c b/drivers/serial/serial_xuartlite.c index 2bdb68ba4a..9cc0b7f1d2 100644 --- a/drivers/serial/serial_xuartlite.c +++ b/drivers/serial/serial_xuartlite.c @@ -96,39 +96,6 @@ static int uartlite_serial_init(const int port) return -1; } -#if !defined(CONFIG_SERIAL_MULTI) -int serial_init(void) -{ - return uartlite_serial_init(0); -} - -void serial_setbrg(void) -{ - /* FIXME: what's this for? */ -} - -void serial_putc(const char c) -{ - uartlite_serial_putc(c, 0); -} - -void serial_puts(const char *s) -{ - uartlite_serial_puts(s, 0); -} - -int serial_getc(void) -{ - return uartlite_serial_getc(0); -} - -int serial_tstc(void) -{ - return uartlite_serial_tstc(0); -} -#endif - -#if defined(CONFIG_SERIAL_MULTI) /* Multi serial device functions */ #define DECLARE_ESERIAL_FUNCTIONS(port) \ int userial##port##_init(void) \ @@ -144,15 +111,16 @@ int serial_tstc(void) { uartlite_serial_puts(s, port); } /* Serial device descriptor */ -#define INIT_ESERIAL_STRUCTURE(port, name) {\ - name,\ - userial##port##_init,\ - NULL,\ - userial##port##_setbrg,\ - userial##port##_getc,\ - userial##port##_tstc,\ - userial##port##_putc,\ - userial##port##_puts, } +#define INIT_ESERIAL_STRUCTURE(port, __name) { \ + .name = __name, \ + .start = userial##port##_init, \ + .stop = NULL, \ + .setbrg = userial##port##_setbrg, \ + .getc = userial##port##_getc, \ + .tstc = userial##port##_tstc, \ + .putc = userial##port##_putc, \ + .puts = userial##port##_puts, \ +} DECLARE_ESERIAL_FUNCTIONS(0); struct serial_device uartlite_serial0_device = @@ -180,4 +148,19 @@ __weak struct serial_device *default_serial_console(void) return NULL; } -#endif /* CONFIG_SERIAL_MULTI */ + +void uartlite_serial_initialize(void) +{ +#ifdef XILINX_UARTLITE_BASEADDR + serial_register(&uartlite_serial0_device); +#endif /* XILINX_UARTLITE_BASEADDR */ +#ifdef XILINX_UARTLITE_BASEADDR1 + serial_register(&uartlite_serial1_device); +#endif /* XILINX_UARTLITE_BASEADDR1 */ +#ifdef XILINX_UARTLITE_BASEADDR2 + serial_register(&uartlite_serial2_device); +#endif /* XILINX_UARTLITE_BASEADDR2 */ +#ifdef XILINX_UARTLITE_BASEADDR3 + serial_register(&uartlite_serial3_device); +#endif /* XILINX_UARTLITE_BASEADDR3 */ +} diff --git a/drivers/serial/serial_zynq.c b/drivers/serial/serial_zynq.c new file mode 100644 index 0000000000..c09aa271b5 --- /dev/null +++ b/drivers/serial/serial_zynq.c @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2012 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2011-2012 Xilinx, Inc. All rights reserved. + * + * 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 <watchdog.h> +#include <asm/io.h> +#include <linux/compiler.h> +#include <serial.h> + +#define ZYNQ_UART_SR_TXFULL 0x00000010 /* TX FIFO full */ +#define ZYNQ_UART_SR_RXEMPTY 0x00000002 /* RX FIFO empty */ + +#define ZYNQ_UART_CR_TX_EN 0x00000010 /* TX enabled */ +#define ZYNQ_UART_CR_RX_EN 0x00000004 /* RX enabled */ +#define ZYNQ_UART_CR_TXRST 0x00000002 /* TX logic reset */ +#define ZYNQ_UART_CR_RXRST 0x00000001 /* RX logic reset */ + +#define ZYNQ_UART_MR_PARITY_NONE 0x00000020 /* No parity mode */ + +/* Some clock/baud constants */ +#define ZYNQ_UART_BDIV 15 /* Default/reset BDIV value */ +#define ZYNQ_UART_BASECLK 3125000L /* master / (bdiv + 1) */ + +struct uart_zynq { + u32 control; /* Control Register [8:0] */ + u32 mode; /* Mode Register [10:0] */ + u32 reserved1[4]; + u32 baud_rate_gen; /* Baud Rate Generator [15:0] */ + u32 reserved2[4]; + u32 channel_sts; /* Channel Status [11:0] */ + u32 tx_rx_fifo; /* FIFO [15:0] or [7:0] */ + u32 baud_rate_divider; /* Baud Rate Divider [7:0] */ +}; + +static struct uart_zynq *uart_zynq_ports[2] = { +#ifdef CONFIG_ZYNQ_SERIAL_BASEADDR0 + [0] = (struct uart_zynq *)CONFIG_ZYNQ_SERIAL_BASEADDR0, +#endif +#ifdef CONFIG_ZYNQ_SERIAL_BASEADDR1 + [1] = (struct uart_zynq *)CONFIG_ZYNQ_SERIAL_BASEADDR1, +#endif +}; + +struct uart_zynq_params { + u32 baudrate; + u32 clock; +}; + +static struct uart_zynq_params uart_zynq_ports_param[2] = { +#if defined(CONFIG_ZYNQ_SERIAL_BAUDRATE0) && defined(CONFIG_ZYNQ_SERIAL_CLOCK0) + [0].baudrate = CONFIG_ZYNQ_SERIAL_BAUDRATE0, + [0].clock = CONFIG_ZYNQ_SERIAL_CLOCK0, +#endif +#if defined(CONFIG_ZYNQ_SERIAL_BAUDRATE1) && defined(CONFIG_ZYNQ_SERIAL_CLOCK1) + [1].baudrate = CONFIG_ZYNQ_SERIAL_BAUDRATE1, + [1].clock = CONFIG_ZYNQ_SERIAL_CLOCK1, +#endif +}; + +/* Set up the baud rate in gd struct */ +static void uart_zynq_serial_setbrg(const int port) +{ + /* Calculation results. */ + unsigned int calc_bauderror, bdiv, bgen; + unsigned long calc_baud = 0; + unsigned long baud = uart_zynq_ports_param[port].baudrate; + unsigned long clock = uart_zynq_ports_param[port].clock; + struct uart_zynq *regs = uart_zynq_ports[port]; + + /* master clock + * Baud rate = ------------------ + * bgen * (bdiv + 1) + * + * Find acceptable values for baud generation. + */ + for (bdiv = 4; bdiv < 255; bdiv++) { + bgen = clock / (baud * (bdiv + 1)); + if (bgen < 2 || bgen > 65535) + continue; + + calc_baud = clock / (bgen * (bdiv + 1)); + + /* + * Use first calculated baudrate with + * an acceptable (<3%) error + */ + if (baud > calc_baud) + calc_bauderror = baud - calc_baud; + else + calc_bauderror = calc_baud - baud; + if (((calc_bauderror * 100) / baud) < 3) + break; + } + + writel(bdiv, ®s->baud_rate_divider); + writel(bgen, ®s->baud_rate_gen); +} + +/* Initialize the UART, with...some settings. */ +static int uart_zynq_serial_init(const int port) +{ + struct uart_zynq *regs = uart_zynq_ports[port]; + + if (!regs) + return -1; + + /* RX/TX enabled & reset */ + writel(ZYNQ_UART_CR_TX_EN | ZYNQ_UART_CR_RX_EN | ZYNQ_UART_CR_TXRST | \ + ZYNQ_UART_CR_RXRST, ®s->control); + writel(ZYNQ_UART_MR_PARITY_NONE, ®s->mode); /* 8 bit, no parity */ + uart_zynq_serial_setbrg(port); + + return 0; +} + +static void uart_zynq_serial_putc(const char c, const int port) +{ + struct uart_zynq *regs = uart_zynq_ports[port]; + + while ((readl(®s->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0) + WATCHDOG_RESET(); + + if (c == '\n') { + writel('\r', ®s->tx_rx_fifo); + while ((readl(®s->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0) + WATCHDOG_RESET(); + } + writel(c, ®s->tx_rx_fifo); +} + +static void uart_zynq_serial_puts(const char *s, const int port) +{ + while (*s) + uart_zynq_serial_putc(*s++, port); +} + +static int uart_zynq_serial_tstc(const int port) +{ + struct uart_zynq *regs = uart_zynq_ports[port]; + + return (readl(®s->channel_sts) & ZYNQ_UART_SR_RXEMPTY) == 0; +} + +static int uart_zynq_serial_getc(const int port) +{ + struct uart_zynq *regs = uart_zynq_ports[port]; + + while (!uart_zynq_serial_tstc(port)) + WATCHDOG_RESET(); + return readl(®s->tx_rx_fifo); +} + +/* Multi serial device functions */ +#define DECLARE_PSSERIAL_FUNCTIONS(port) \ + int uart_zynq##port##_init(void) \ + { return uart_zynq_serial_init(port); } \ + void uart_zynq##port##_setbrg(void) \ + { return uart_zynq_serial_setbrg(port); } \ + int uart_zynq##port##_getc(void) \ + { return uart_zynq_serial_getc(port); } \ + int uart_zynq##port##_tstc(void) \ + { return uart_zynq_serial_tstc(port); } \ + void uart_zynq##port##_putc(const char c) \ + { uart_zynq_serial_putc(c, port); } \ + void uart_zynq##port##_puts(const char *s) \ + { uart_zynq_serial_puts(s, port); } + +/* Serial device descriptor */ +#define INIT_PSSERIAL_STRUCTURE(port, __name) { \ + .name = __name, \ + .start = uart_zynq##port##_init, \ + .stop = NULL, \ + .setbrg = uart_zynq##port##_setbrg, \ + .getc = uart_zynq##port##_getc, \ + .tstc = uart_zynq##port##_tstc, \ + .putc = uart_zynq##port##_putc, \ + .puts = uart_zynq##port##_puts, \ +} + +DECLARE_PSSERIAL_FUNCTIONS(0); +struct serial_device uart_zynq_serial0_device = + INIT_PSSERIAL_STRUCTURE(0, "ttyPS0"); +DECLARE_PSSERIAL_FUNCTIONS(1); +struct serial_device uart_zynq_serial1_device = + INIT_PSSERIAL_STRUCTURE(1, "ttyPS1"); + +__weak struct serial_device *default_serial_console(void) +{ + if (uart_zynq_ports[0]) + return &uart_zynq_serial0_device; + if (uart_zynq_ports[1]) + return &uart_zynq_serial1_device; + + return NULL; +} + +void zynq_serial_initalize(void) +{ +#ifdef CONFIG_ZYNQ_SERIAL_BASEADDR0 + serial_register(&uart_zynq_serial0_device); +#endif +#ifdef CONFIG_ZYNQ_SERIAL_BASEADDR1 + serial_register(&uart_zynq_serial1_device); +#endif +} diff --git a/drivers/spi/tegra_spi.c b/drivers/spi/tegra_spi.c index 18b00b2cae..9bb34e2938 100644 --- a/drivers/spi/tegra_spi.c +++ b/drivers/spi/tegra_spi.c @@ -23,16 +23,15 @@ */ #include <common.h> - #include <malloc.h> -#include <spi.h> #include <asm/io.h> #include <asm/gpio.h> -#include <asm/arch/clk_rst.h> #include <asm/arch/clock.h> #include <asm/arch/pinmux.h> #include <asm/arch/uart-spi-switch.h> -#include <asm/arch/tegra_spi.h> +#include <asm/arch-tegra/clk_rst.h> +#include <asm/arch-tegra/tegra_spi.h> +#include <spi.h> #if defined(CONFIG_SPI_CORRUPTS_UART) #define corrupt_delay() udelay(CONFIG_SPI_CORRUPTS_UART_DLY); diff --git a/drivers/usb/eth/usb_ether.c b/drivers/usb/eth/usb_ether.c index 6cad6c87ca..f361e8b168 100644 --- a/drivers/usb/eth/usb_ether.c +++ b/drivers/usb/eth/usb_ether.c @@ -123,7 +123,7 @@ int usb_host_eth_scan(int mode) if (mode == 1) - printf(" scanning bus for ethernet devices... "); + printf(" scanning usb for ethernet devices... "); old_async = usb_disable_asynch(1); /* asynch transfer not allowed */ diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 5bbdd368f4..040eaba3bc 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -36,6 +36,7 @@ ifdef CONFIG_USB_ETHER COBJS-y += ether.o epautoconf.o config.o usbstring.o COBJS-$(CONFIG_USB_ETH_RNDIS) += rndis.o COBJS-$(CONFIG_MV_UDC) += mv_udc.o +COBJS-$(CONFIG_CPU_PXA25X) += pxa25x_udc.o else # Devices not related to the new gadget layer depend on CONFIG_USB_DEVICE ifdef CONFIG_USB_DEVICE diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index d975fb680e..1e187e5b52 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -44,7 +44,6 @@ extern struct platform_data brd; unsigned packet_received, packet_sent; -#define DEV_CONFIG_CDC 1 #define GFP_ATOMIC ((gfp_t) 0) #define GFP_KERNEL ((gfp_t) 0) @@ -160,9 +159,9 @@ static struct usb_gadget_driver eth_driver; /* "main" config is either CDC, or its simple subset */ static inline int is_cdc(struct eth_dev *dev) { -#if !defined(DEV_CONFIG_SUBSET) +#if !defined(CONFIG_USB_ETH_SUBSET) return 1; /* only cdc possible */ -#elif !defined(DEV_CONFIG_CDC) +#elif !defined(CONFIG_USB_ETH_CDC) return 0; /* only subset possible */ #else return dev->cdc; /* depends on what hardware we found */ @@ -406,7 +405,7 @@ rndis_config = { * get those drivers from MCCI, or bundled with various products. */ -#ifdef DEV_CONFIG_CDC +#ifdef CONFIG_USB_ETH_CDC static struct usb_interface_descriptor control_intf = { .bLength = sizeof control_intf, @@ -445,7 +444,7 @@ static const struct usb_cdc_header_desc header_desc = { .bcdCDC = __constant_cpu_to_le16(0x0110), }; -#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) +#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS) static const struct usb_cdc_union_desc union_desc = { .bLength = sizeof union_desc, @@ -479,7 +478,7 @@ static const struct usb_cdc_acm_descriptor acm_descriptor = { #endif -#ifndef DEV_CONFIG_CDC +#ifndef CONFIG_USB_ETH_CDC /* * "SAFE" loosely follows CDC WMC MDLM, violating the spec in various @@ -529,7 +528,7 @@ static const struct usb_cdc_ether_desc ether_desc = { .bNumberPowerFilters = 0, }; -#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) +#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS) /* * include the status endpoint if we can, even where it's optional. @@ -561,7 +560,7 @@ fs_status_desc = { }; #endif -#ifdef DEV_CONFIG_CDC +#ifdef CONFIG_USB_ETH_CDC /* the default data interface has no endpoints ... */ @@ -616,7 +615,7 @@ rndis_data_intf = { #endif -#ifdef DEV_CONFIG_SUBSET +#ifdef CONFIG_USB_ETH_SUBSET /* * "Simple" CDC-subset option is a simple vendor-neutral model that most @@ -662,7 +661,7 @@ fs_sink_desc = { static const struct usb_descriptor_header *fs_eth_function[11] = { (struct usb_descriptor_header *) &otg_descriptor, -#ifdef DEV_CONFIG_CDC +#ifdef CONFIG_USB_ETH_CDC /* "cdc" mode descriptors */ (struct usb_descriptor_header *) &control_intf, (struct usb_descriptor_header *) &header_desc, @@ -676,12 +675,12 @@ static const struct usb_descriptor_header *fs_eth_function[11] = { (struct usb_descriptor_header *) &fs_source_desc, (struct usb_descriptor_header *) &fs_sink_desc, NULL, -#endif /* DEV_CONFIG_CDC */ +#endif /* CONFIG_USB_ETH_CDC */ }; static inline void fs_subset_descriptors(void) { -#ifdef DEV_CONFIG_SUBSET +#ifdef CONFIG_USB_ETH_SUBSET /* behavior is "CDC Subset"; extra descriptors say "SAFE" */ fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf; fs_eth_function[2] = (struct usb_descriptor_header *) &header_desc; @@ -719,7 +718,7 @@ static const struct usb_descriptor_header *fs_rndis_function[] = { * descriptors, unless they only run at full speed. */ -#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) +#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS) static struct usb_endpoint_descriptor hs_status_desc = { .bLength = USB_DT_ENDPOINT_SIZE, @@ -729,7 +728,7 @@ hs_status_desc = { .wMaxPacketSize = __constant_cpu_to_le16(STATUS_BYTECOUNT), .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, }; -#endif /* DEV_CONFIG_CDC */ +#endif /* CONFIG_USB_ETH_CDC */ static struct usb_endpoint_descriptor hs_source_desc = { @@ -762,7 +761,7 @@ dev_qualifier = { static const struct usb_descriptor_header *hs_eth_function[11] = { (struct usb_descriptor_header *) &otg_descriptor, -#ifdef DEV_CONFIG_CDC +#ifdef CONFIG_USB_ETH_CDC /* "cdc" mode descriptors */ (struct usb_descriptor_header *) &control_intf, (struct usb_descriptor_header *) &header_desc, @@ -776,12 +775,12 @@ static const struct usb_descriptor_header *hs_eth_function[11] = { (struct usb_descriptor_header *) &hs_source_desc, (struct usb_descriptor_header *) &hs_sink_desc, NULL, -#endif /* DEV_CONFIG_CDC */ +#endif /* CONFIG_USB_ETH_CDC */ }; static inline void hs_subset_descriptors(void) { -#ifdef DEV_CONFIG_SUBSET +#ifdef CONFIG_USB_ETH_SUBSET /* behavior is "CDC Subset"; extra descriptors say "SAFE" */ hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf; hs_eth_function[2] = (struct usb_descriptor_header *) &header_desc; @@ -843,11 +842,11 @@ static struct usb_string strings[] = { { STRING_SERIALNUMBER, serial_number, }, { STRING_DATA, "Ethernet Data", }, { STRING_ETHADDR, ethaddr, }, -#ifdef DEV_CONFIG_CDC +#ifdef CONFIG_USB_ETH_CDC { STRING_CDC, "CDC Ethernet", }, { STRING_CONTROL, "CDC Communications Control", }, #endif -#ifdef DEV_CONFIG_SUBSET +#ifdef CONFIG_USB_ETH_SUBSET { STRING_SUBSET, "CDC Ethernet Subset", }, #endif #ifdef CONFIG_USB_ETH_RNDIS @@ -864,7 +863,9 @@ static struct usb_gadget_strings stringtab = { /*============================================================================*/ static u8 control_req[USB_BUFSIZ]; +#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS) static u8 status_req[STATUS_BYTECOUNT] __attribute__ ((aligned(4))); +#endif /** @@ -951,7 +952,7 @@ set_ether_config(struct eth_dev *dev, gfp_t gfp_flags) int result = 0; struct usb_gadget *gadget = dev->gadget; -#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) +#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS) /* status endpoint used for RNDIS and (optionally) CDC */ if (!subset_active(dev) && dev->status_ep) { dev->status = ep_desc(gadget, &hs_status_desc, @@ -1132,7 +1133,7 @@ static int eth_set_config(struct eth_dev *dev, unsigned number, /*-------------------------------------------------------------------------*/ -#ifdef DEV_CONFIG_CDC +#ifdef CONFIG_USB_ETH_CDC /* * The interrupt endpoint is used in CDC networking models (Ethernet, ATM) @@ -1352,10 +1353,18 @@ eth_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (gadget_is_pxa(gadget)) { value = eth_set_config(dev, DEV_CONFIG_VALUE, GFP_ATOMIC); + /* + * PXA25x driver use non-CDC ethernet gadget. + * But only _CDC and _RNDIS code can signalize + * that network is working. So we signalize it + * here. + */ + l_ethdev.network_started = 1; + debug("USB network up!\n"); goto done_set_intf; } -#ifdef DEV_CONFIG_CDC +#ifdef CONFIG_USB_ETH_CDC switch (wIndex) { case 0: /* control/master intf */ if (wValue != 0) @@ -1397,7 +1406,7 @@ eth_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) * all non-PXA hardware talks real CDC ... */ debug("set_interface ignored!\n"); -#endif /* DEV_CONFIG_CDC */ +#endif /* CONFIG_USB_ETH_CDC */ done_set_intf: break; @@ -1420,7 +1429,7 @@ done_set_intf: value = min(wLength, (u16) 1); break; -#ifdef DEV_CONFIG_CDC +#ifdef CONFIG_USB_ETH_CDC case USB_CDC_SET_ETHERNET_PACKET_FILTER: /* * see 6.2.30: no data, wIndex = interface, @@ -1444,7 +1453,7 @@ done_set_intf: * case USB_CDC_GET_ETHERNET_STATISTIC: */ -#endif /* DEV_CONFIG_CDC */ +#endif /* CONFIG_USB_ETH_CDC */ #ifdef CONFIG_USB_ETH_RNDIS /* @@ -2015,7 +2024,7 @@ static int eth_bind(struct usb_gadget *gadget) u8 tmp[7]; /* these flags are only ever cleared; compiler take note */ -#ifndef DEV_CONFIG_CDC +#ifndef CONFIG_USB_ETH_CDC cdc = 0; #endif #ifndef CONFIG_USB_ETH_RNDIS @@ -2127,7 +2136,7 @@ autoconf_fail: goto autoconf_fail; out_ep->driver_data = out_ep; /* claim */ -#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) +#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS) /* * CDC Ethernet control interface doesn't require a status endpoint. * Since some hosts expect one, try to allocate one anyway. @@ -2139,7 +2148,7 @@ autoconf_fail: } else if (rndis) { error("can't run RNDIS on %s", gadget->name); return -ENODEV; -#ifdef DEV_CONFIG_CDC +#ifdef CONFIG_USB_ETH_CDC } else if (cdc) { control_intf.bNumEndpoints = 0; /* FIXME remove endpoint from descriptor list */ @@ -2182,7 +2191,7 @@ autoconf_fail: fs_source_desc.bEndpointAddress; hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; -#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) +#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS) if (status_ep) hs_status_desc.bEndpointAddress = fs_status_desc.bEndpointAddress; @@ -2251,7 +2260,7 @@ autoconf_fail: dev->req->complete = eth_setup_complete; /* ... and maybe likewise for status transfer */ -#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) +#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS) if (dev->status_ep) { dev->stat_req = usb_ep_alloc_request(dev->status_ep, GFP_KERNEL); diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c new file mode 100644 index 0000000000..dd741439ae --- /dev/null +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -0,0 +1,2059 @@ +/* + * Intel PXA25x and IXP4xx on-chip full speed USB device controllers + * + * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker) + * Copyright (C) 2003 Robert Schwebel, Pengutronix + * Copyright (C) 2003 Benedikt Spranger, Pengutronix + * Copyright (C) 2003 David Brownell + * Copyright (C) 2003 Joshua Wise + * Copyright (C) 2012 Lukasz Dalek <luk0104@gmail.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 + * + * MODULE_AUTHOR("Frank Becker, Robert Schwebel, David Brownell"); + */ + +#define CONFIG_USB_PXA25X_SMALL +#define DRIVER_NAME "pxa25x_udc_linux" +#define ARCH_HAS_PREFETCH + +#include <common.h> +#include <errno.h> +#include <asm/byteorder.h> +#include <asm/system.h> +#include <asm/mach-types.h> +#include <asm/unaligned.h> +#include <linux/compat.h> +#include <malloc.h> +#include <asm/io.h> +#include <asm/arch/pxa.h> + +#include <usbdescriptors.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <usb/lin_gadget_compat.h> +#include <asm/arch/pxa-regs.h> + +#include "pxa25x_udc.h" + +/* + * This driver handles the USB Device Controller (UDC) in Intel's PXA 25x + * series processors. The UDC for the IXP 4xx series is very similar. + * There are fifteen endpoints, in addition to ep0. + * + * Such controller drivers work with a gadget driver. The gadget driver + * returns descriptors, implements configuration and data protocols used + * by the host to interact with this device, and allocates endpoints to + * the different protocol interfaces. The controller driver virtualizes + * usb hardware so that the gadget drivers will be more portable. + * + * This UDC hardware wants to implement a bit too much USB protocol, so + * it constrains the sorts of USB configuration change events that work. + * The errata for these chips are misleading; some "fixed" bugs from + * pxa250 a0/a1 b0/b1/b2 sure act like they're still there. + * + * Note that the UDC hardware supports DMA (except on IXP) but that's + * not used here. IN-DMA (to host) is simple enough, when the data is + * suitably aligned (16 bytes) ... the network stack doesn't do that, + * other software can. OUT-DMA is buggy in most chip versions, as well + * as poorly designed (data toggle not automatic). So this driver won't + * bother using DMA. (Mostly-working IN-DMA support was available in + * kernels before 2.6.23, but was never enabled or well tested.) + */ + +#define DRIVER_VERSION "18-August-2012" +#define DRIVER_DESC "PXA 25x USB Device Controller driver" + +static const char driver_name[] = "pxa25x_udc"; +static const char ep0name[] = "ep0"; + +/* Watchdog */ +static inline void start_watchdog(struct pxa25x_udc *udc) +{ + debug("Started watchdog\n"); + udc->watchdog.base = get_timer(0); + udc->watchdog.running = 1; +} + +static inline void stop_watchdog(struct pxa25x_udc *udc) +{ + udc->watchdog.running = 0; + debug("Stopped watchdog\n"); +} + +static inline void test_watchdog(struct pxa25x_udc *udc) +{ + if (!udc->watchdog.running) + return; + + debug("watchdog %ld %ld\n", get_timer(udc->watchdog.base), + udc->watchdog.period); + + if (get_timer(udc->watchdog.base) >= udc->watchdog.period) { + stop_watchdog(udc); + udc->watchdog.function(udc); + } +} + +static void udc_watchdog(struct pxa25x_udc *dev) +{ + uint32_t udccs0 = readl(&dev->regs->udccs[0]); + + debug("Fired up udc_watchdog\n"); + + local_irq_disable(); + if (dev->ep0state == EP0_STALL + && (udccs0 & UDCCS0_FST) == 0 + && (udccs0 & UDCCS0_SST) == 0) { + writel(UDCCS0_FST|UDCCS0_FTF, &dev->regs->udccs[0]); + debug("ep0 re-stall\n"); + start_watchdog(dev); + } + local_irq_enable(); +} + +#ifdef DEBUG + +static const char * const state_name[] = { + "EP0_IDLE", + "EP0_IN_DATA_PHASE", "EP0_OUT_DATA_PHASE", + "EP0_END_XFER", "EP0_STALL" +}; + +static void +dump_udccr(const char *label) +{ + u32 udccr = readl(&UDC_REGS->udccr); + debug("%s %02X =%s%s%s%s%s%s%s%s\n", + label, udccr, + (udccr & UDCCR_REM) ? " rem" : "", + (udccr & UDCCR_RSTIR) ? " rstir" : "", + (udccr & UDCCR_SRM) ? " srm" : "", + (udccr & UDCCR_SUSIR) ? " susir" : "", + (udccr & UDCCR_RESIR) ? " resir" : "", + (udccr & UDCCR_RSM) ? " rsm" : "", + (udccr & UDCCR_UDA) ? " uda" : "", + (udccr & UDCCR_UDE) ? " ude" : ""); +} + +static void +dump_udccs0(const char *label) +{ + u32 udccs0 = readl(&UDC_REGS->udccs[0]); + + debug("%s %s %02X =%s%s%s%s%s%s%s%s\n", + label, state_name[the_controller->ep0state], udccs0, + (udccs0 & UDCCS0_SA) ? " sa" : "", + (udccs0 & UDCCS0_RNE) ? " rne" : "", + (udccs0 & UDCCS0_FST) ? " fst" : "", + (udccs0 & UDCCS0_SST) ? " sst" : "", + (udccs0 & UDCCS0_DRWF) ? " dwrf" : "", + (udccs0 & UDCCS0_FTF) ? " ftf" : "", + (udccs0 & UDCCS0_IPR) ? " ipr" : "", + (udccs0 & UDCCS0_OPR) ? " opr" : ""); +} + +static void +dump_state(struct pxa25x_udc *dev) +{ + u32 tmp; + unsigned i; + + debug("%s, uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n", + state_name[dev->ep0state], + readl(&UDC_REGS->uicr1), readl(&UDC_REGS->uicr0), + readl(&UDC_REGS->usir1), readl(&UDC_REGS->usir0), + readl(&UDC_REGS->ufnrh), readl(&UDC_REGS->ufnrl)); + dump_udccr("udccr"); + if (dev->has_cfr) { + tmp = readl(&UDC_REGS->udccfr); + debug("udccfr %02X =%s%s\n", tmp, + (tmp & UDCCFR_AREN) ? " aren" : "", + (tmp & UDCCFR_ACM) ? " acm" : ""); + } + + if (!dev->driver) { + debug("no gadget driver bound\n"); + return; + } else + debug("ep0 driver '%s'\n", "ether"); + + dump_udccs0("udccs0"); + debug("ep0 IN %lu/%lu, OUT %lu/%lu\n", + dev->stats.write.bytes, dev->stats.write.ops, + dev->stats.read.bytes, dev->stats.read.ops); + + for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) { + if (dev->ep[i].desc == NULL) + continue; + debug("udccs%d = %02x\n", i, *dev->ep->reg_udccs); + } +} + +#else /* DEBUG */ + +static inline void dump_udccr(const char *label) { } +static inline void dump_udccs0(const char *label) { } +static inline void dump_state(struct pxa25x_udc *dev) { } + +#endif /* DEBUG */ + +/* + * --------------------------------------------------------------------------- + * endpoint related parts of the api to the usb controller hardware, + * used by gadget driver; and the inner talker-to-hardware core. + * --------------------------------------------------------------------------- + */ + +static void pxa25x_ep_fifo_flush(struct usb_ep *ep); +static void nuke(struct pxa25x_ep *, int status); + +/* one GPIO should control a D+ pullup, so host sees this device (or not) */ +static void pullup_off(void) +{ + struct pxa2xx_udc_mach_info *mach = the_controller->mach; + + if (mach->udc_command) + mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); +} + +static void pullup_on(void) +{ + struct pxa2xx_udc_mach_info *mach = the_controller->mach; + + if (mach->udc_command) + mach->udc_command(PXA2XX_UDC_CMD_CONNECT); +} + +static void pio_irq_enable(int bEndpointAddress) +{ + bEndpointAddress &= 0xf; + if (bEndpointAddress < 8) { + clrbits_le32(&the_controller->regs->uicr0, + 1 << bEndpointAddress); + } else { + bEndpointAddress -= 8; + clrbits_le32(&the_controller->regs->uicr1, + 1 << bEndpointAddress); + } +} + +static void pio_irq_disable(int bEndpointAddress) +{ + bEndpointAddress &= 0xf; + if (bEndpointAddress < 8) { + setbits_le32(&the_controller->regs->uicr0, + 1 << bEndpointAddress); + } else { + bEndpointAddress -= 8; + setbits_le32(&the_controller->regs->uicr1, + 1 << bEndpointAddress); + } +} + +static inline void udc_set_mask_UDCCR(int mask) +{ + /* + * The UDCCR reg contains mask and interrupt status bits, + * so using '|=' isn't safe as it may ack an interrupt. + */ + const uint32_t mask_bits = UDCCR_REM | UDCCR_SRM | UDCCR_UDE; + + mask &= mask_bits; + clrsetbits_le32(&the_controller->regs->udccr, ~mask_bits, mask); +} + +static inline void udc_clear_mask_UDCCR(int mask) +{ + const uint32_t mask_bits = UDCCR_REM | UDCCR_SRM | UDCCR_UDE; + + mask = ~mask & mask_bits; + clrbits_le32(&the_controller->regs->udccr, ~mask); +} + +static inline void udc_ack_int_UDCCR(int mask) +{ + const uint32_t mask_bits = UDCCR_REM | UDCCR_SRM | UDCCR_UDE; + + mask &= ~mask_bits; + clrsetbits_le32(&the_controller->regs->udccr, ~mask_bits, mask); +} + +/* + * endpoint enable/disable + * + * we need to verify the descriptors used to enable endpoints. since pxa25x + * endpoint configurations are fixed, and are pretty much always enabled, + * there's not a lot to manage here. + * + * because pxa25x can't selectively initialize bulk (or interrupt) endpoints, + * (resetting endpoint halt and toggle), SET_INTERFACE is unusable except + * for a single interface (with only the default altsetting) and for gadget + * drivers that don't halt endpoints (not reset by set_interface). that also + * means that if you use ISO, you must violate the USB spec rule that all + * iso endpoints must be in non-default altsettings. + */ +static int pxa25x_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct pxa25x_ep *ep; + struct pxa25x_udc *dev; + + ep = container_of(_ep, struct pxa25x_ep, ep); + if (!_ep || !desc || ep->desc || _ep->name == ep0name + || desc->bDescriptorType != USB_DT_ENDPOINT + || ep->bEndpointAddress != desc->bEndpointAddress + || ep->fifo_size < le16_to_cpu(desc->wMaxPacketSize)) { + printf("%s, bad ep or descriptor\n", __func__); + return -EINVAL; + } + + /* xfer types must match, except that interrupt ~= bulk */ + if (ep->bmAttributes != desc->bmAttributes + && ep->bmAttributes != USB_ENDPOINT_XFER_BULK + && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { + printf("%s, %s type mismatch\n", __func__, _ep->name); + return -EINVAL; + } + + /* hardware _could_ do smaller, but driver doesn't */ + if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK + && le16_to_cpu(desc->wMaxPacketSize) + != BULK_FIFO_SIZE) + || !desc->wMaxPacketSize) { + printf("%s, bad %s maxpacket\n", __func__, _ep->name); + return -ERANGE; + } + + dev = ep->dev; + if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { + printf("%s, bogus device state\n", __func__); + return -ESHUTDOWN; + } + + ep->desc = desc; + ep->stopped = 0; + ep->pio_irqs = 0; + ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize); + + /* flush fifo (mostly for OUT buffers) */ + pxa25x_ep_fifo_flush(_ep); + + /* ... reset halt state too, if we could ... */ + + debug("enabled %s\n", _ep->name); + return 0; +} + +static int pxa25x_ep_disable(struct usb_ep *_ep) +{ + struct pxa25x_ep *ep; + unsigned long flags; + + ep = container_of(_ep, struct pxa25x_ep, ep); + if (!_ep || !ep->desc) { + printf("%s, %s not enabled\n", __func__, + _ep ? ep->ep.name : NULL); + return -EINVAL; + } + local_irq_save(flags); + + nuke(ep, -ESHUTDOWN); + + /* flush fifo (mostly for IN buffers) */ + pxa25x_ep_fifo_flush(_ep); + + ep->desc = NULL; + ep->stopped = 1; + + local_irq_restore(flags); + debug("%s disabled\n", _ep->name); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* + * for the pxa25x, these can just wrap kmalloc/kfree. gadget drivers + * must still pass correctly initialized endpoints, since other controller + * drivers may care about how it's currently set up (dma issues etc). + */ + +/* + * pxa25x_ep_alloc_request - allocate a request data structure + */ +static struct usb_request * +pxa25x_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) +{ + struct pxa25x_request *req; + + req = kzalloc(sizeof(*req), gfp_flags); + if (!req) + return NULL; + + INIT_LIST_HEAD(&req->queue); + return &req->req; +} + + +/* + * pxa25x_ep_free_request - deallocate a request data structure + */ +static void +pxa25x_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ + struct pxa25x_request *req; + + req = container_of(_req, struct pxa25x_request, req); + WARN_ON(!list_empty(&req->queue)); + kfree(req); +} + +/*-------------------------------------------------------------------------*/ + +/* + * done - retire a request; caller blocked irqs + */ +static void done(struct pxa25x_ep *ep, struct pxa25x_request *req, int status) +{ + unsigned stopped = ep->stopped; + + list_del_init(&req->queue); + + if (likely(req->req.status == -EINPROGRESS)) + req->req.status = status; + else + status = req->req.status; + + if (status && status != -ESHUTDOWN) + debug("complete %s req %p stat %d len %u/%u\n", + ep->ep.name, &req->req, status, + req->req.actual, req->req.length); + + /* don't modify queue heads during completion callback */ + ep->stopped = 1; + req->req.complete(&ep->ep, &req->req); + ep->stopped = stopped; +} + + +static inline void ep0_idle(struct pxa25x_udc *dev) +{ + dev->ep0state = EP0_IDLE; +} + +static int +write_packet(u32 *uddr, struct pxa25x_request *req, unsigned max) +{ + u8 *buf; + unsigned length, count; + + debug("%s(): uddr %p\n", __func__, uddr); + + buf = req->req.buf + req->req.actual; + prefetch(buf); + + /* how big will this packet be? */ + length = min(req->req.length - req->req.actual, max); + req->req.actual += length; + + count = length; + while (likely(count--)) + writeb(*buf++, uddr); + + return length; +} + +/* + * write to an IN endpoint fifo, as many packets as possible. + * irqs will use this to write the rest later. + * caller guarantees at least one packet buffer is ready (or a zlp). + */ +static int +write_fifo(struct pxa25x_ep *ep, struct pxa25x_request *req) +{ + unsigned max; + + max = le16_to_cpu(ep->desc->wMaxPacketSize); + do { + unsigned count; + int is_last, is_short; + + count = write_packet(ep->reg_uddr, req, max); + + /* last packet is usually short (or a zlp) */ + if (unlikely(count != max)) + is_last = is_short = 1; + else { + if (likely(req->req.length != req->req.actual) + || req->req.zero) + is_last = 0; + else + is_last = 1; + /* interrupt/iso maxpacket may not fill the fifo */ + is_short = unlikely(max < ep->fifo_size); + } + + debug_cond(NOISY, "wrote %s %d bytes%s%s %d left %p\n", + ep->ep.name, count, + is_last ? "/L" : "", is_short ? "/S" : "", + req->req.length - req->req.actual, req); + + /* + * let loose that packet. maybe try writing another one, + * double buffering might work. TSP, TPC, and TFS + * bit values are the same for all normal IN endpoints. + */ + writel(UDCCS_BI_TPC, ep->reg_udccs); + if (is_short) + writel(UDCCS_BI_TSP, ep->reg_udccs); + + /* requests complete when all IN data is in the FIFO */ + if (is_last) { + done(ep, req, 0); + if (list_empty(&ep->queue)) + pio_irq_disable(ep->bEndpointAddress); + return 1; + } + + /* + * TODO experiment: how robust can fifo mode tweaking be? + * double buffering is off in the default fifo mode, which + * prevents TFS from being set here. + */ + + } while (readl(ep->reg_udccs) & UDCCS_BI_TFS); + return 0; +} + +/* + * caller asserts req->pending (ep0 irq status nyet cleared); starts + * ep0 data stage. these chips want very simple state transitions. + */ +static inline +void ep0start(struct pxa25x_udc *dev, u32 flags, const char *tag) +{ + writel(flags|UDCCS0_SA|UDCCS0_OPR, &dev->regs->udccs[0]); + writel(USIR0_IR0, &dev->regs->usir0); + dev->req_pending = 0; + debug_cond(NOISY, "%s() %s, udccs0: %02x/%02x usir: %X.%X\n", + __func__, tag, readl(&dev->regs->udccs[0]), flags, + readl(&dev->regs->usir1), readl(&dev->regs->usir0)); +} + +static int +write_ep0_fifo(struct pxa25x_ep *ep, struct pxa25x_request *req) +{ + unsigned count; + int is_short; + + count = write_packet(&ep->dev->regs->uddr0, req, EP0_FIFO_SIZE); + ep->dev->stats.write.bytes += count; + + /* last packet "must be" short (or a zlp) */ + is_short = (count != EP0_FIFO_SIZE); + + debug_cond(NOISY, "ep0in %d bytes %d left %p\n", count, + req->req.length - req->req.actual, req); + + if (unlikely(is_short)) { + if (ep->dev->req_pending) + ep0start(ep->dev, UDCCS0_IPR, "short IN"); + else + writel(UDCCS0_IPR, &ep->dev->regs->udccs[0]); + + count = req->req.length; + done(ep, req, 0); + ep0_idle(ep->dev); + + /* + * This seems to get rid of lost status irqs in some cases: + * host responds quickly, or next request involves config + * change automagic, or should have been hidden, or ... + * + * FIXME get rid of all udelays possible... + */ + if (count >= EP0_FIFO_SIZE) { + count = 100; + do { + if ((readl(&ep->dev->regs->udccs[0]) & + UDCCS0_OPR) != 0) { + /* clear OPR, generate ack */ + writel(UDCCS0_OPR, + &ep->dev->regs->udccs[0]); + break; + } + count--; + udelay(1); + } while (count); + } + } else if (ep->dev->req_pending) + ep0start(ep->dev, 0, "IN"); + + return is_short; +} + + +/* + * read_fifo - unload packet(s) from the fifo we use for usb OUT + * transfers and put them into the request. caller should have made + * sure there's at least one packet ready. + * + * returns true if the request completed because of short packet or the + * request buffer having filled (and maybe overran till end-of-packet). + */ +static int +read_fifo(struct pxa25x_ep *ep, struct pxa25x_request *req) +{ + u32 udccs; + u8 *buf; + unsigned bufferspace, count, is_short; + + for (;;) { + /* + * make sure there's a packet in the FIFO. + * UDCCS_{BO,IO}_RPC are all the same bit value. + * UDCCS_{BO,IO}_RNE are all the same bit value. + */ + udccs = readl(ep->reg_udccs); + if (unlikely((udccs & UDCCS_BO_RPC) == 0)) + break; + buf = req->req.buf + req->req.actual; + prefetchw(buf); + bufferspace = req->req.length - req->req.actual; + + /* read all bytes from this packet */ + if (likely(udccs & UDCCS_BO_RNE)) { + count = 1 + (0x0ff & readl(ep->reg_ubcr)); + req->req.actual += min(count, bufferspace); + } else /* zlp */ + count = 0; + is_short = (count < ep->ep.maxpacket); + debug_cond(NOISY, "read %s %02x, %d bytes%s req %p %d/%d\n", + ep->ep.name, udccs, count, + is_short ? "/S" : "", + req, req->req.actual, req->req.length); + while (likely(count-- != 0)) { + u8 byte = readb(ep->reg_uddr); + + if (unlikely(bufferspace == 0)) { + /* + * this happens when the driver's buffer + * is smaller than what the host sent. + * discard the extra data. + */ + if (req->req.status != -EOVERFLOW) + printf("%s overflow %d\n", + ep->ep.name, count); + req->req.status = -EOVERFLOW; + } else { + *buf++ = byte; + bufferspace--; + } + } + writel(UDCCS_BO_RPC, ep->reg_udccs); + /* RPC/RSP/RNE could now reflect the other packet buffer */ + + /* iso is one request per packet */ + if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) { + if (udccs & UDCCS_IO_ROF) + req->req.status = -EHOSTUNREACH; + /* more like "is_done" */ + is_short = 1; + } + + /* completion */ + if (is_short || req->req.actual == req->req.length) { + done(ep, req, 0); + if (list_empty(&ep->queue)) + pio_irq_disable(ep->bEndpointAddress); + return 1; + } + + /* finished that packet. the next one may be waiting... */ + } + return 0; +} + +/* + * special ep0 version of the above. no UBCR0 or double buffering; status + * handshaking is magic. most device protocols don't need control-OUT. + * CDC vendor commands (and RNDIS), mass storage CB/CBI, and some other + * protocols do use them. + */ +static int +read_ep0_fifo(struct pxa25x_ep *ep, struct pxa25x_request *req) +{ + u8 *buf, byte; + unsigned bufferspace; + + buf = req->req.buf + req->req.actual; + bufferspace = req->req.length - req->req.actual; + + while (readl(&ep->dev->regs->udccs[0]) & UDCCS0_RNE) { + byte = (u8)readb(&ep->dev->regs->uddr0); + + if (unlikely(bufferspace == 0)) { + /* + * this happens when the driver's buffer + * is smaller than what the host sent. + * discard the extra data. + */ + if (req->req.status != -EOVERFLOW) + printf("%s overflow\n", ep->ep.name); + req->req.status = -EOVERFLOW; + } else { + *buf++ = byte; + req->req.actual++; + bufferspace--; + } + } + + writel(UDCCS0_OPR | UDCCS0_IPR, &ep->dev->regs->udccs[0]); + + /* completion */ + if (req->req.actual >= req->req.length) + return 1; + + /* finished that packet. the next one may be waiting... */ + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static int +pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) +{ + struct pxa25x_request *req; + struct pxa25x_ep *ep; + struct pxa25x_udc *dev; + unsigned long flags; + + req = container_of(_req, struct pxa25x_request, req); + if (unlikely(!_req || !_req->complete || !_req->buf + || !list_empty(&req->queue))) { + printf("%s, bad params\n", __func__); + return -EINVAL; + } + + ep = container_of(_ep, struct pxa25x_ep, ep); + if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { + printf("%s, bad ep\n", __func__); + return -EINVAL; + } + + dev = ep->dev; + if (unlikely(!dev->driver + || dev->gadget.speed == USB_SPEED_UNKNOWN)) { + printf("%s, bogus device state\n", __func__); + return -ESHUTDOWN; + } + + /* + * iso is always one packet per request, that's the only way + * we can report per-packet status. that also helps with dma. + */ + if (unlikely(ep->bmAttributes == USB_ENDPOINT_XFER_ISOC + && req->req.length > + le16_to_cpu(ep->desc->wMaxPacketSize))) + return -EMSGSIZE; + + debug_cond(NOISY, "%s queue req %p, len %d buf %p\n", + _ep->name, _req, _req->length, _req->buf); + + local_irq_save(flags); + + _req->status = -EINPROGRESS; + _req->actual = 0; + + /* kickstart this i/o queue? */ + if (list_empty(&ep->queue) && !ep->stopped) { + if (ep->desc == NULL/* ep0 */) { + unsigned length = _req->length; + + switch (dev->ep0state) { + case EP0_IN_DATA_PHASE: + dev->stats.write.ops++; + if (write_ep0_fifo(ep, req)) + req = NULL; + break; + + case EP0_OUT_DATA_PHASE: + dev->stats.read.ops++; + /* messy ... */ + if (dev->req_config) { + debug("ep0 config ack%s\n", + dev->has_cfr ? "" : " raced"); + if (dev->has_cfr) + writel(UDCCFR_AREN|UDCCFR_ACM + |UDCCFR_MB1, + &ep->dev->regs->udccfr); + done(ep, req, 0); + dev->ep0state = EP0_END_XFER; + local_irq_restore(flags); + return 0; + } + if (dev->req_pending) + ep0start(dev, UDCCS0_IPR, "OUT"); + if (length == 0 || + ((readl( + &ep->dev->regs->udccs[0]) + & UDCCS0_RNE) != 0 + && read_ep0_fifo(ep, req))) { + ep0_idle(dev); + done(ep, req, 0); + req = NULL; + } + break; + + default: + printf("ep0 i/o, odd state %d\n", + dev->ep0state); + local_irq_restore(flags); + return -EL2HLT; + } + /* can the FIFO can satisfy the request immediately? */ + } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) { + if ((readl(ep->reg_udccs) & UDCCS_BI_TFS) != 0 + && write_fifo(ep, req)) + req = NULL; + } else if ((readl(ep->reg_udccs) & UDCCS_BO_RFS) != 0 + && read_fifo(ep, req)) { + req = NULL; + } + + if (likely(req && ep->desc)) + pio_irq_enable(ep->bEndpointAddress); + } + + /* pio or dma irq handler advances the queue. */ + if (likely(req != NULL)) + list_add_tail(&req->queue, &ep->queue); + local_irq_restore(flags); + + return 0; +} + + +/* + * nuke - dequeue ALL requests + */ +static void nuke(struct pxa25x_ep *ep, int status) +{ + struct pxa25x_request *req; + + /* called with irqs blocked */ + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, + struct pxa25x_request, + queue); + done(ep, req, status); + } + if (ep->desc) + pio_irq_disable(ep->bEndpointAddress); +} + + +/* dequeue JUST ONE request */ +static int pxa25x_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct pxa25x_ep *ep; + struct pxa25x_request *req; + unsigned long flags; + + ep = container_of(_ep, struct pxa25x_ep, ep); + if (!_ep || ep->ep.name == ep0name) + return -EINVAL; + + local_irq_save(flags); + + /* make sure it's actually queued on this endpoint */ + list_for_each_entry(req, &ep->queue, queue) { + if (&req->req == _req) + break; + } + if (&req->req != _req) { + local_irq_restore(flags); + return -EINVAL; + } + + done(ep, req, -ECONNRESET); + + local_irq_restore(flags); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static int pxa25x_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct pxa25x_ep *ep; + unsigned long flags; + + ep = container_of(_ep, struct pxa25x_ep, ep); + if (unlikely(!_ep + || (!ep->desc && ep->ep.name != ep0name)) + || ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) { + printf("%s, bad ep\n", __func__); + return -EINVAL; + } + if (value == 0) { + /* + * this path (reset toggle+halt) is needed to implement + * SET_INTERFACE on normal hardware. but it can't be + * done from software on the PXA UDC, and the hardware + * forgets to do it as part of SET_INTERFACE automagic. + */ + printf("only host can clear %s halt\n", _ep->name); + return -EROFS; + } + + local_irq_save(flags); + + if ((ep->bEndpointAddress & USB_DIR_IN) != 0 + && ((readl(ep->reg_udccs) & UDCCS_BI_TFS) == 0 + || !list_empty(&ep->queue))) { + local_irq_restore(flags); + return -EAGAIN; + } + + /* FST bit is the same for control, bulk in, bulk out, interrupt in */ + writel(UDCCS_BI_FST|UDCCS_BI_FTF, ep->reg_udccs); + + /* ep0 needs special care */ + if (!ep->desc) { + start_watchdog(ep->dev); + ep->dev->req_pending = 0; + ep->dev->ep0state = EP0_STALL; + + /* and bulk/intr endpoints like dropping stalls too */ + } else { + unsigned i; + for (i = 0; i < 1000; i += 20) { + if (readl(ep->reg_udccs) & UDCCS_BI_SST) + break; + udelay(20); + } + } + local_irq_restore(flags); + + debug("%s halt\n", _ep->name); + return 0; +} + +static int pxa25x_ep_fifo_status(struct usb_ep *_ep) +{ + struct pxa25x_ep *ep; + + ep = container_of(_ep, struct pxa25x_ep, ep); + if (!_ep) { + printf("%s, bad ep\n", __func__); + return -ENODEV; + } + /* pxa can't report unclaimed bytes from IN fifos */ + if ((ep->bEndpointAddress & USB_DIR_IN) != 0) + return -EOPNOTSUPP; + if (ep->dev->gadget.speed == USB_SPEED_UNKNOWN + || (readl(ep->reg_udccs) & UDCCS_BO_RFS) == 0) + return 0; + else + return (readl(ep->reg_ubcr) & 0xfff) + 1; +} + +static void pxa25x_ep_fifo_flush(struct usb_ep *_ep) +{ + struct pxa25x_ep *ep; + + ep = container_of(_ep, struct pxa25x_ep, ep); + if (!_ep || ep->ep.name == ep0name || !list_empty(&ep->queue)) { + printf("%s, bad ep\n", __func__); + return; + } + + /* toggle and halt bits stay unchanged */ + + /* for OUT, just read and discard the FIFO contents. */ + if ((ep->bEndpointAddress & USB_DIR_IN) == 0) { + while (((readl(ep->reg_udccs)) & UDCCS_BO_RNE) != 0) + (void)readb(ep->reg_uddr); + return; + } + + /* most IN status is the same, but ISO can't stall */ + writel(UDCCS_BI_TPC|UDCCS_BI_FTF|UDCCS_BI_TUR + | (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC + ? 0 : UDCCS_BI_SST), ep->reg_udccs); +} + + +static struct usb_ep_ops pxa25x_ep_ops = { + .enable = pxa25x_ep_enable, + .disable = pxa25x_ep_disable, + + .alloc_request = pxa25x_ep_alloc_request, + .free_request = pxa25x_ep_free_request, + + .queue = pxa25x_ep_queue, + .dequeue = pxa25x_ep_dequeue, + + .set_halt = pxa25x_ep_set_halt, + .fifo_status = pxa25x_ep_fifo_status, + .fifo_flush = pxa25x_ep_fifo_flush, +}; + + +/* --------------------------------------------------------------------------- + * device-scoped parts of the api to the usb controller hardware + * --------------------------------------------------------------------------- + */ + +static int pxa25x_udc_get_frame(struct usb_gadget *_gadget) +{ + return ((readl(&the_controller->regs->ufnrh) & 0x07) << 8) | + (readl(&the_controller->regs->ufnrl) & 0xff); +} + +static int pxa25x_udc_wakeup(struct usb_gadget *_gadget) +{ + /* host may not have enabled remote wakeup */ + if ((readl(&the_controller->regs->udccs[0]) & UDCCS0_DRWF) == 0) + return -EHOSTUNREACH; + udc_set_mask_UDCCR(UDCCR_RSM); + return 0; +} + +static void stop_activity(struct pxa25x_udc *, struct usb_gadget_driver *); +static void udc_enable(struct pxa25x_udc *); +static void udc_disable(struct pxa25x_udc *); + +/* + * We disable the UDC -- and its 48 MHz clock -- whenever it's not + * in active use. + */ +static int pullup(struct pxa25x_udc *udc) +{ + if (udc->pullup) + pullup_on(); + else + pullup_off(); + + + int is_active = udc->pullup; + if (is_active) { + if (!udc->active) { + udc->active = 1; + udc_enable(udc); + } + } else { + if (udc->active) { + if (udc->gadget.speed != USB_SPEED_UNKNOWN) + stop_activity(udc, udc->driver); + udc_disable(udc); + udc->active = 0; + } + + } + return 0; +} + +/* VBUS reporting logically comes from a transceiver */ +static int pxa25x_udc_vbus_session(struct usb_gadget *_gadget, int is_active) +{ + struct pxa25x_udc *udc; + + udc = container_of(_gadget, struct pxa25x_udc, gadget); + printf("vbus %s\n", is_active ? "supplied" : "inactive"); + pullup(udc); + return 0; +} + +/* drivers may have software control over D+ pullup */ +static int pxa25x_udc_pullup(struct usb_gadget *_gadget, int is_active) +{ + struct pxa25x_udc *udc; + + udc = container_of(_gadget, struct pxa25x_udc, gadget); + + /* not all boards support pullup control */ + if (!udc->mach->udc_command) + return -EOPNOTSUPP; + + udc->pullup = (is_active != 0); + pullup(udc); + return 0; +} + +/* + * boards may consume current from VBUS, up to 100-500mA based on config. + * the 500uA suspend ceiling means that exclusively vbus-powered PXA designs + * violate USB specs. + */ +static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA) +{ + return -EOPNOTSUPP; +} + +static const struct usb_gadget_ops pxa25x_udc_ops = { + .get_frame = pxa25x_udc_get_frame, + .wakeup = pxa25x_udc_wakeup, + .vbus_session = pxa25x_udc_vbus_session, + .pullup = pxa25x_udc_pullup, + .vbus_draw = pxa25x_udc_vbus_draw, +}; + +/*-------------------------------------------------------------------------*/ + +/* + * udc_disable - disable USB device controller + */ +static void udc_disable(struct pxa25x_udc *dev) +{ + /* block all irqs */ + udc_set_mask_UDCCR(UDCCR_SRM|UDCCR_REM); + writel(0xff, &dev->regs->uicr0); + writel(0xff, &dev->regs->uicr1); + writel(UFNRH_SIM, &dev->regs->ufnrh); + + /* if hardware supports it, disconnect from usb */ + pullup_off(); + + udc_clear_mask_UDCCR(UDCCR_UDE); + + ep0_idle(dev); + dev->gadget.speed = USB_SPEED_UNKNOWN; +} + +/* + * udc_reinit - initialize software state + */ +static void udc_reinit(struct pxa25x_udc *dev) +{ + u32 i; + + /* device/ep0 records init */ + INIT_LIST_HEAD(&dev->gadget.ep_list); + INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); + dev->ep0state = EP0_IDLE; + + /* basic endpoint records init */ + for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) { + struct pxa25x_ep *ep = &dev->ep[i]; + + if (i != 0) + list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); + + ep->desc = NULL; + ep->stopped = 0; + INIT_LIST_HEAD(&ep->queue); + ep->pio_irqs = 0; + } + + /* the rest was statically initialized, and is read-only */ +} + +/* + * until it's enabled, this UDC should be completely invisible + * to any USB host. + */ +static void udc_enable(struct pxa25x_udc *dev) +{ + debug("udc: enabling udc\n"); + + udc_clear_mask_UDCCR(UDCCR_UDE); + + /* + * Try to clear these bits before we enable the udc. + * Do not touch reset ack bit, we would take care of it in + * interrupt handle routine + */ + udc_ack_int_UDCCR(UDCCR_SUSIR|UDCCR_RESIR); + + ep0_idle(dev); + dev->gadget.speed = USB_SPEED_UNKNOWN; + dev->stats.irqs = 0; + + /* + * sequence taken from chapter 12.5.10, PXA250 AppProcDevManual: + * - enable UDC + * - if RESET is already in progress, ack interrupt + * - unmask reset interrupt + */ + udc_set_mask_UDCCR(UDCCR_UDE); + if (!(readl(&dev->regs->udccr) & UDCCR_UDA)) + udc_ack_int_UDCCR(UDCCR_RSTIR); + + if (dev->has_cfr /* UDC_RES2 is defined */) { + /* + * pxa255 (a0+) can avoid a set_config race that could + * prevent gadget drivers from configuring correctly + */ + writel(UDCCFR_ACM | UDCCFR_MB1, &dev->regs->udccfr); + } + + /* enable suspend/resume and reset irqs */ + udc_clear_mask_UDCCR(UDCCR_SRM | UDCCR_REM); + + /* enable ep0 irqs */ + clrbits_le32(&dev->regs->uicr0, UICR0_IM0); + + /* if hardware supports it, pullup D+ and wait for reset */ + pullup_on(); +} + +static inline void clear_ep_state(struct pxa25x_udc *dev) +{ + unsigned i; + + /* + * hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint + * fifos, and pending transactions mustn't be continued in any case. + */ + for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) + nuke(&dev->ep[i], -ECONNABORTED); +} + +static void handle_ep0(struct pxa25x_udc *dev) +{ + u32 udccs0 = readl(&dev->regs->udccs[0]); + struct pxa25x_ep *ep = &dev->ep[0]; + struct pxa25x_request *req; + union { + struct usb_ctrlrequest r; + u8 raw[8]; + u32 word[2]; + } u; + + if (list_empty(&ep->queue)) + req = NULL; + else + req = list_entry(ep->queue.next, struct pxa25x_request, queue); + + /* clear stall status */ + if (udccs0 & UDCCS0_SST) { + nuke(ep, -EPIPE); + writel(UDCCS0_SST, &dev->regs->udccs[0]); + stop_watchdog(dev); + ep0_idle(dev); + } + + /* previous request unfinished? non-error iff back-to-back ... */ + if ((udccs0 & UDCCS0_SA) != 0 && dev->ep0state != EP0_IDLE) { + nuke(ep, 0); + stop_watchdog(dev); + ep0_idle(dev); + } + + switch (dev->ep0state) { + case EP0_IDLE: + /* late-breaking status? */ + udccs0 = readl(&dev->regs->udccs[0]); + + /* start control request? */ + if (likely((udccs0 & (UDCCS0_OPR|UDCCS0_SA|UDCCS0_RNE)) + == (UDCCS0_OPR|UDCCS0_SA|UDCCS0_RNE))) { + int i; + + nuke(ep, -EPROTO); + + /* read SETUP packet */ + for (i = 0; i < 8; i++) { + if (unlikely(!(readl(&dev->regs->udccs[0]) & + UDCCS0_RNE))) { +bad_setup: + debug("SETUP %d!\n", i); + goto stall; + } + u.raw[i] = (u8)readb(&dev->regs->uddr0); + } + if (unlikely((readl(&dev->regs->udccs[0]) & + UDCCS0_RNE) != 0)) + goto bad_setup; + +got_setup: + debug("SETUP %02x.%02x v%04x i%04x l%04x\n", + u.r.bRequestType, u.r.bRequest, + le16_to_cpu(u.r.wValue), + le16_to_cpu(u.r.wIndex), + le16_to_cpu(u.r.wLength)); + + /* cope with automagic for some standard requests. */ + dev->req_std = (u.r.bRequestType & USB_TYPE_MASK) + == USB_TYPE_STANDARD; + dev->req_config = 0; + dev->req_pending = 1; + switch (u.r.bRequest) { + /* hardware restricts gadget drivers here! */ + case USB_REQ_SET_CONFIGURATION: + debug("GOT SET_CONFIGURATION\n"); + if (u.r.bRequestType == USB_RECIP_DEVICE) { + /* + * reflect hardware's automagic + * up to the gadget driver. + */ +config_change: + dev->req_config = 1; + clear_ep_state(dev); + /* + * if !has_cfr, there's no synch + * else use AREN (later) not SA|OPR + * USIR0_IR0 acts edge sensitive + */ + } + break; + /* ... and here, even more ... */ + case USB_REQ_SET_INTERFACE: + if (u.r.bRequestType == USB_RECIP_INTERFACE) { + /* + * udc hardware is broken by design: + * - altsetting may only be zero; + * - hw resets all interfaces' eps; + * - ep reset doesn't include halt(?). + */ + printf("broken set_interface (%d/%d)\n", + le16_to_cpu(u.r.wIndex), + le16_to_cpu(u.r.wValue)); + goto config_change; + } + break; + /* hardware was supposed to hide this */ + case USB_REQ_SET_ADDRESS: + debug("GOT SET ADDRESS\n"); + if (u.r.bRequestType == USB_RECIP_DEVICE) { + ep0start(dev, 0, "address"); + return; + } + break; + } + + if (u.r.bRequestType & USB_DIR_IN) + dev->ep0state = EP0_IN_DATA_PHASE; + else + dev->ep0state = EP0_OUT_DATA_PHASE; + + i = dev->driver->setup(&dev->gadget, &u.r); + if (i < 0) { + /* hardware automagic preventing STALL... */ + if (dev->req_config) { + /* + * hardware sometimes neglects to tell + * tell us about config change events, + * so later ones may fail... + */ + printf("config change %02x fail %d?\n", + u.r.bRequest, i); + return; + /* + * TODO experiment: if has_cfr, + * hardware didn't ACK; maybe we + * could actually STALL! + */ + } + if (0) { +stall: + /* uninitialized when goto stall */ + i = 0; + } + debug("protocol STALL, " + "%02x err %d\n", + readl(&dev->regs->udccs[0]), i); + + /* + * the watchdog timer helps deal with cases + * where udc seems to clear FST wrongly, and + * then NAKs instead of STALLing. + */ + ep0start(dev, UDCCS0_FST|UDCCS0_FTF, "stall"); + start_watchdog(dev); + dev->ep0state = EP0_STALL; + + /* deferred i/o == no response yet */ + } else if (dev->req_pending) { + if (likely(dev->ep0state == EP0_IN_DATA_PHASE + || dev->req_std || u.r.wLength)) + ep0start(dev, 0, "defer"); + else + ep0start(dev, UDCCS0_IPR, "defer/IPR"); + } + + /* expect at least one data or status stage irq */ + return; + + } else if (likely((udccs0 & (UDCCS0_OPR|UDCCS0_SA)) + == (UDCCS0_OPR|UDCCS0_SA))) { + unsigned i; + + /* + * pxa210/250 erratum 131 for B0/B1 says RNE lies. + * still observed on a pxa255 a0. + */ + debug("e131\n"); + nuke(ep, -EPROTO); + + /* read SETUP data, but don't trust it too much */ + for (i = 0; i < 8; i++) + u.raw[i] = (u8)readb(&dev->regs->uddr0); + if ((u.r.bRequestType & USB_RECIP_MASK) + > USB_RECIP_OTHER) + goto stall; + if (u.word[0] == 0 && u.word[1] == 0) + goto stall; + goto got_setup; + } else { + /* + * some random early IRQ: + * - we acked FST + * - IPR cleared + * - OPR got set, without SA (likely status stage) + */ + debug("random IRQ %X %X\n", udccs0, + readl(&dev->regs->udccs[0])); + writel(udccs0 & (UDCCS0_SA|UDCCS0_OPR), + &dev->regs->udccs[0]); + } + break; + case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR etc */ + if (udccs0 & UDCCS0_OPR) { + debug("ep0in premature status\n"); + if (req) + done(ep, req, 0); + ep0_idle(dev); + } else /* irq was IPR clearing */ { + if (req) { + debug("next ep0 in packet\n"); + /* this IN packet might finish the request */ + (void) write_ep0_fifo(ep, req); + } /* else IN token before response was written */ + } + break; + case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR etc */ + if (udccs0 & UDCCS0_OPR) { + if (req) { + /* this OUT packet might finish the request */ + if (read_ep0_fifo(ep, req)) + done(ep, req, 0); + /* else more OUT packets expected */ + } /* else OUT token before read was issued */ + } else /* irq was IPR clearing */ { + debug("ep0out premature status\n"); + if (req) + done(ep, req, 0); + ep0_idle(dev); + } + break; + case EP0_END_XFER: + if (req) + done(ep, req, 0); + /* + * ack control-IN status (maybe in-zlp was skipped) + * also appears after some config change events. + */ + if (udccs0 & UDCCS0_OPR) + writel(UDCCS0_OPR, &dev->regs->udccs[0]); + ep0_idle(dev); + break; + case EP0_STALL: + writel(UDCCS0_FST, &dev->regs->udccs[0]); + break; + } + + writel(USIR0_IR0, &dev->regs->usir0); +} + +static void handle_ep(struct pxa25x_ep *ep) +{ + struct pxa25x_request *req; + int is_in = ep->bEndpointAddress & USB_DIR_IN; + int completed; + u32 udccs, tmp; + + do { + completed = 0; + if (likely(!list_empty(&ep->queue))) + req = list_entry(ep->queue.next, + struct pxa25x_request, queue); + else + req = NULL; + + /* TODO check FST handling */ + + udccs = readl(ep->reg_udccs); + if (unlikely(is_in)) { /* irq from TPC, SST, or (ISO) TUR */ + tmp = UDCCS_BI_TUR; + if (likely(ep->bmAttributes == USB_ENDPOINT_XFER_BULK)) + tmp |= UDCCS_BI_SST; + tmp &= udccs; + if (likely(tmp)) + writel(tmp, ep->reg_udccs); + if (req && likely((udccs & UDCCS_BI_TFS) != 0)) + completed = write_fifo(ep, req); + + } else { /* irq from RPC (or for ISO, ROF) */ + if (likely(ep->bmAttributes == USB_ENDPOINT_XFER_BULK)) + tmp = UDCCS_BO_SST | UDCCS_BO_DME; + else + tmp = UDCCS_IO_ROF | UDCCS_IO_DME; + tmp &= udccs; + if (likely(tmp)) + writel(tmp, ep->reg_udccs); + + /* fifos can hold packets, ready for reading... */ + if (likely(req)) + completed = read_fifo(ep, req); + else + pio_irq_disable(ep->bEndpointAddress); + } + ep->pio_irqs++; + } while (completed); +} + +/* + * pxa25x_udc_irq - interrupt handler + * + * avoid delays in ep0 processing. the control handshaking isn't always + * under software control (pxa250c0 and the pxa255 are better), and delays + * could cause usb protocol errors. + */ +static struct pxa25x_udc memory; +static int +pxa25x_udc_irq(void) +{ + struct pxa25x_udc *dev = &memory; + int handled; + + test_watchdog(dev); + + dev->stats.irqs++; + do { + u32 udccr = readl(&dev->regs->udccr); + + handled = 0; + + /* SUSpend Interrupt Request */ + if (unlikely(udccr & UDCCR_SUSIR)) { + udc_ack_int_UDCCR(UDCCR_SUSIR); + handled = 1; + debug("USB suspend\n"); + + if (dev->gadget.speed != USB_SPEED_UNKNOWN + && dev->driver + && dev->driver->suspend) + dev->driver->suspend(&dev->gadget); + ep0_idle(dev); + } + + /* RESume Interrupt Request */ + if (unlikely(udccr & UDCCR_RESIR)) { + udc_ack_int_UDCCR(UDCCR_RESIR); + handled = 1; + debug("USB resume\n"); + + if (dev->gadget.speed != USB_SPEED_UNKNOWN + && dev->driver + && dev->driver->resume) + dev->driver->resume(&dev->gadget); + } + + /* ReSeT Interrupt Request - USB reset */ + if (unlikely(udccr & UDCCR_RSTIR)) { + udc_ack_int_UDCCR(UDCCR_RSTIR); + handled = 1; + + if ((readl(&dev->regs->udccr) & UDCCR_UDA) == 0) { + debug("USB reset start\n"); + + /* + * reset driver and endpoints, + * in case that's not yet done + */ + stop_activity(dev, dev->driver); + + } else { + debug("USB reset end\n"); + dev->gadget.speed = USB_SPEED_FULL; + memset(&dev->stats, 0, sizeof dev->stats); + /* driver and endpoints are still reset */ + } + + } else { + u32 uicr0 = readl(&dev->regs->uicr0); + u32 uicr1 = readl(&dev->regs->uicr1); + u32 usir0 = readl(&dev->regs->usir0); + u32 usir1 = readl(&dev->regs->usir1); + + usir0 = usir0 & ~uicr0; + usir1 = usir1 & ~uicr1; + int i; + + if (unlikely(!usir0 && !usir1)) + continue; + + debug_cond(NOISY, "irq %02x.%02x\n", usir1, usir0); + + /* control traffic */ + if (usir0 & USIR0_IR0) { + dev->ep[0].pio_irqs++; + handle_ep0(dev); + handled = 1; + } + + /* endpoint data transfers */ + for (i = 0; i < 8; i++) { + u32 tmp = 1 << i; + + if (i && (usir0 & tmp)) { + handle_ep(&dev->ep[i]); + setbits_le32(&dev->regs->usir0, tmp); + handled = 1; + } +#ifndef CONFIG_USB_PXA25X_SMALL + if (usir1 & tmp) { + handle_ep(&dev->ep[i+8]); + setbits_le32(&dev->regs->usir1, tmp); + handled = 1; + } +#endif + } + } + + /* we could also ask for 1 msec SOF (SIR) interrupts */ + + } while (handled); + return IRQ_HANDLED; +} + +/*-------------------------------------------------------------------------*/ + +/* + * this uses load-time allocation and initialization (instead of + * doing it at run-time) to save code, eliminate fault paths, and + * be more obviously correct. + */ +static struct pxa25x_udc memory = { + .regs = UDC_REGS, + + .gadget = { + .ops = &pxa25x_udc_ops, + .ep0 = &memory.ep[0].ep, + .name = driver_name, + }, + + /* control endpoint */ + .ep[0] = { + .ep = { + .name = ep0name, + .ops = &pxa25x_ep_ops, + .maxpacket = EP0_FIFO_SIZE, + }, + .dev = &memory, + .reg_udccs = &UDC_REGS->udccs[0], + .reg_uddr = &UDC_REGS->uddr0, + }, + + /* first group of endpoints */ + .ep[1] = { + .ep = { + .name = "ep1in-bulk", + .ops = &pxa25x_ep_ops, + .maxpacket = BULK_FIFO_SIZE, + }, + .dev = &memory, + .fifo_size = BULK_FIFO_SIZE, + .bEndpointAddress = USB_DIR_IN | 1, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .reg_udccs = &UDC_REGS->udccs[1], + .reg_uddr = &UDC_REGS->uddr1, + }, + .ep[2] = { + .ep = { + .name = "ep2out-bulk", + .ops = &pxa25x_ep_ops, + .maxpacket = BULK_FIFO_SIZE, + }, + .dev = &memory, + .fifo_size = BULK_FIFO_SIZE, + .bEndpointAddress = 2, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .reg_udccs = &UDC_REGS->udccs[2], + .reg_ubcr = &UDC_REGS->ubcr2, + .reg_uddr = &UDC_REGS->uddr2, + }, +#ifndef CONFIG_USB_PXA25X_SMALL + .ep[3] = { + .ep = { + .name = "ep3in-iso", + .ops = &pxa25x_ep_ops, + .maxpacket = ISO_FIFO_SIZE, + }, + .dev = &memory, + .fifo_size = ISO_FIFO_SIZE, + .bEndpointAddress = USB_DIR_IN | 3, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .reg_udccs = &UDC_REGS->udccs[3], + .reg_uddr = &UDC_REGS->uddr3, + }, + .ep[4] = { + .ep = { + .name = "ep4out-iso", + .ops = &pxa25x_ep_ops, + .maxpacket = ISO_FIFO_SIZE, + }, + .dev = &memory, + .fifo_size = ISO_FIFO_SIZE, + .bEndpointAddress = 4, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .reg_udccs = &UDC_REGS->udccs[4], + .reg_ubcr = &UDC_REGS->ubcr4, + .reg_uddr = &UDC_REGS->uddr4, + }, + .ep[5] = { + .ep = { + .name = "ep5in-int", + .ops = &pxa25x_ep_ops, + .maxpacket = INT_FIFO_SIZE, + }, + .dev = &memory, + .fifo_size = INT_FIFO_SIZE, + .bEndpointAddress = USB_DIR_IN | 5, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .reg_udccs = &UDC_REGS->udccs[5], + .reg_uddr = &UDC_REGS->uddr5, + }, + + /* second group of endpoints */ + .ep[6] = { + .ep = { + .name = "ep6in-bulk", + .ops = &pxa25x_ep_ops, + .maxpacket = BULK_FIFO_SIZE, + }, + .dev = &memory, + .fifo_size = BULK_FIFO_SIZE, + .bEndpointAddress = USB_DIR_IN | 6, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .reg_udccs = &UDC_REGS->udccs[6], + .reg_uddr = &UDC_REGS->uddr6, + }, + .ep[7] = { + .ep = { + .name = "ep7out-bulk", + .ops = &pxa25x_ep_ops, + .maxpacket = BULK_FIFO_SIZE, + }, + .dev = &memory, + .fifo_size = BULK_FIFO_SIZE, + .bEndpointAddress = 7, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .reg_udccs = &UDC_REGS->udccs[7], + .reg_ubcr = &UDC_REGS->ubcr7, + .reg_uddr = &UDC_REGS->uddr7, + }, + .ep[8] = { + .ep = { + .name = "ep8in-iso", + .ops = &pxa25x_ep_ops, + .maxpacket = ISO_FIFO_SIZE, + }, + .dev = &memory, + .fifo_size = ISO_FIFO_SIZE, + .bEndpointAddress = USB_DIR_IN | 8, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .reg_udccs = &UDC_REGS->udccs[8], + .reg_uddr = &UDC_REGS->uddr8, + }, + .ep[9] = { + .ep = { + .name = "ep9out-iso", + .ops = &pxa25x_ep_ops, + .maxpacket = ISO_FIFO_SIZE, + }, + .dev = &memory, + .fifo_size = ISO_FIFO_SIZE, + .bEndpointAddress = 9, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .reg_udccs = &UDC_REGS->udccs[9], + .reg_ubcr = &UDC_REGS->ubcr9, + .reg_uddr = &UDC_REGS->uddr9, + }, + .ep[10] = { + .ep = { + .name = "ep10in-int", + .ops = &pxa25x_ep_ops, + .maxpacket = INT_FIFO_SIZE, + }, + .dev = &memory, + .fifo_size = INT_FIFO_SIZE, + .bEndpointAddress = USB_DIR_IN | 10, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .reg_udccs = &UDC_REGS->udccs[10], + .reg_uddr = &UDC_REGS->uddr10, + }, + + /* third group of endpoints */ + .ep[11] = { + .ep = { + .name = "ep11in-bulk", + .ops = &pxa25x_ep_ops, + .maxpacket = BULK_FIFO_SIZE, + }, + .dev = &memory, + .fifo_size = BULK_FIFO_SIZE, + .bEndpointAddress = USB_DIR_IN | 11, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .reg_udccs = &UDC_REGS->udccs[11], + .reg_uddr = &UDC_REGS->uddr11, + }, + .ep[12] = { + .ep = { + .name = "ep12out-bulk", + .ops = &pxa25x_ep_ops, + .maxpacket = BULK_FIFO_SIZE, + }, + .dev = &memory, + .fifo_size = BULK_FIFO_SIZE, + .bEndpointAddress = 12, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .reg_udccs = &UDC_REGS->udccs[12], + .reg_ubcr = &UDC_REGS->ubcr12, + .reg_uddr = &UDC_REGS->uddr12, + }, + .ep[13] = { + .ep = { + .name = "ep13in-iso", + .ops = &pxa25x_ep_ops, + .maxpacket = ISO_FIFO_SIZE, + }, + .dev = &memory, + .fifo_size = ISO_FIFO_SIZE, + .bEndpointAddress = USB_DIR_IN | 13, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .reg_udccs = &UDC_REGS->udccs[13], + .reg_uddr = &UDC_REGS->uddr13, + }, + .ep[14] = { + .ep = { + .name = "ep14out-iso", + .ops = &pxa25x_ep_ops, + .maxpacket = ISO_FIFO_SIZE, + }, + .dev = &memory, + .fifo_size = ISO_FIFO_SIZE, + .bEndpointAddress = 14, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .reg_udccs = &UDC_REGS->udccs[14], + .reg_ubcr = &UDC_REGS->ubcr14, + .reg_uddr = &UDC_REGS->uddr14, + }, + .ep[15] = { + .ep = { + .name = "ep15in-int", + .ops = &pxa25x_ep_ops, + .maxpacket = INT_FIFO_SIZE, + }, + .dev = &memory, + .fifo_size = INT_FIFO_SIZE, + .bEndpointAddress = USB_DIR_IN | 15, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .reg_udccs = &UDC_REGS->udccs[15], + .reg_uddr = &UDC_REGS->uddr15, + }, +#endif /* !CONFIG_USB_PXA25X_SMALL */ +}; + +static void udc_command(int cmd) +{ + switch (cmd) { + case PXA2XX_UDC_CMD_CONNECT: + setbits_le32(GPDR(CONFIG_USB_DEV_PULLUP_GPIO), + GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO)); + + /* enable pullup */ + writel(GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO), + GPCR(CONFIG_USB_DEV_PULLUP_GPIO)); + + debug("Connected to USB\n"); + break; + + case PXA2XX_UDC_CMD_DISCONNECT: + /* disable pullup resistor */ + writel(GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO), + GPSR(CONFIG_USB_DEV_PULLUP_GPIO)); + + /* setup pin as input, line will float */ + clrbits_le32(GPDR(CONFIG_USB_DEV_PULLUP_GPIO), + GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO)); + + debug("Disconnected from USB\n"); + break; + } +} + +static struct pxa2xx_udc_mach_info mach_info = { + .udc_command = udc_command, +}; + +/* + * when a driver is successfully registered, it will receive + * control requests including set_configuration(), which enables + * non-control requests. then usb traffic follows until a + * disconnect is reported. then a host may connect again, or + * the driver might get unbound. + */ +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + struct pxa25x_udc *dev = &memory; + int retval; + uint32_t chiprev; + + if (!driver + || driver->speed < USB_SPEED_FULL + || !driver->disconnect + || !driver->setup) + return -EINVAL; + if (!dev) + return -ENODEV; + if (dev->driver) + return -EBUSY; + + /* Enable clock for usb controller */ + setbits_le32(CKEN, CKEN11_USB); + + /* first hook up the driver ... */ + dev->driver = driver; + dev->pullup = 1; + + /* trigger chiprev-specific logic */ + switch ((chiprev = pxa_get_cpu_revision())) { + case PXA255_A0: + dev->has_cfr = 1; + break; + case PXA250_A0: + case PXA250_A1: + /* A0/A1 "not released"; ep 13, 15 unusable */ + /* fall through */ + case PXA250_B2: case PXA210_B2: + case PXA250_B1: case PXA210_B1: + case PXA250_B0: case PXA210_B0: + /* OUT-DMA is broken ... */ + /* fall through */ + case PXA250_C0: case PXA210_C0: + break; + default: + printf("%s: unrecognized processor: %08x\n", + DRIVER_NAME, chiprev); + return -ENODEV; + } + + the_controller = dev; + + /* prepare watchdog timer */ + dev->watchdog.running = 0; + dev->watchdog.period = 5000 * CONFIG_SYS_HZ / 1000000; /* 5 ms */ + dev->watchdog.function = udc_watchdog; + + udc_disable(dev); + udc_reinit(dev); + + dev->mach = &mach_info; + + dev->gadget.name = "pxa2xx_udc"; + retval = driver->bind(&dev->gadget); + if (retval) { + printf("bind to driver %s --> error %d\n", + DRIVER_NAME, retval); + dev->driver = NULL; + return retval; + } + + /* + * ... then enable host detection and ep0; and we're ready + * for set_configuration as well as eventual disconnect. + */ + printf("registered gadget driver '%s'\n", DRIVER_NAME); + + pullup(dev); + dump_state(dev); + return 0; +} + +static void +stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver) +{ + int i; + + /* don't disconnect drivers more than once */ + if (dev->gadget.speed == USB_SPEED_UNKNOWN) + driver = NULL; + dev->gadget.speed = USB_SPEED_UNKNOWN; + + /* prevent new request submissions, kill any outstanding requests */ + for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) { + struct pxa25x_ep *ep = &dev->ep[i]; + + ep->stopped = 1; + nuke(ep, -ESHUTDOWN); + } + stop_watchdog(dev); + + /* report disconnect; the driver is already quiesced */ + if (driver) + driver->disconnect(&dev->gadget); + + /* re-init driver-visible data structures */ + udc_reinit(dev); +} + +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct pxa25x_udc *dev = the_controller; + + if (!dev) + return -ENODEV; + if (!driver || driver != dev->driver || !driver->unbind) + return -EINVAL; + + local_irq_disable(); + dev->pullup = 0; + pullup(dev); + stop_activity(dev, driver); + local_irq_enable(); + + driver->unbind(&dev->gadget); + dev->driver = NULL; + + printf("unregistered gadget driver '%s'\n", DRIVER_NAME); + dump_state(dev); + + the_controller = NULL; + + clrbits_le32(CKEN, CKEN11_USB); + + return 0; +} + +extern void udc_disconnect(void) +{ + setbits_le32(CKEN, CKEN11_USB); + udc_clear_mask_UDCCR(UDCCR_UDE); + udc_command(PXA2XX_UDC_CMD_DISCONNECT); + clrbits_le32(CKEN, CKEN11_USB); +} + +/*-------------------------------------------------------------------------*/ + +extern int +usb_gadget_handle_interrupts(void) +{ + return pxa25x_udc_irq(); +} diff --git a/drivers/usb/gadget/pxa25x_udc.h b/drivers/usb/gadget/pxa25x_udc.h new file mode 100644 index 0000000000..de28a697f6 --- /dev/null +++ b/drivers/usb/gadget/pxa25x_udc.h @@ -0,0 +1,162 @@ +/* + * Intel PXA25x on-chip full speed USB device controller + * + * Copyright (C) 2003 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix + * Copyright (C) 2003 David Brownell + * Copyright (C) 2012 Lukasz Dalek <luk0104@gmail.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 __LINUX_USB_GADGET_PXA25X_H +#define __LINUX_USB_GADGET_PXA25X_H + +#include <linux/types.h> +#include <asm/arch/regs-usb.h> + +/* + * Prefetching support - only ARMv5. + */ + +#ifdef ARCH_HAS_PREFETCH +static inline void prefetch(const void *ptr) +{ + __asm__ __volatile__( + "pld\t%a0" + : + : "p" (ptr) + : "cc"); +} + +#define prefetchw(ptr) prefetch(ptr) +#endif /* ARCH_HAS_PREFETCH */ + +/*-------------------------------------------------------------------------*/ + +#define UDC_REGS ((struct pxa25x_udc_regs *)PXA25X_UDC_BASE) + +/*-------------------------------------------------------------------------*/ + +struct pxa2xx_udc_mach_info { + int (*udc_is_connected)(void); /* do we see host? */ + void (*udc_command)(int cmd); +#define PXA2XX_UDC_CMD_CONNECT 0 /* let host see us */ +#define PXA2XX_UDC_CMD_DISCONNECT 1 /* so host won't see us */ +}; + +struct pxa25x_udc; + +struct pxa25x_ep { + struct usb_ep ep; + struct pxa25x_udc *dev; + + const struct usb_endpoint_descriptor *desc; + struct list_head queue; + unsigned long pio_irqs; + + unsigned short fifo_size; + u8 bEndpointAddress; + u8 bmAttributes; + + unsigned stopped:1; + + /* UDCCS = UDC Control/Status for this EP + * UBCR = UDC Byte Count Remaining (contents of OUT fifo) + * UDDR = UDC Endpoint Data Register (the fifo) + * DRCM = DMA Request Channel Map + */ + u32 *reg_udccs; + u32 *reg_ubcr; + u32 *reg_uddr; +}; + +struct pxa25x_request { + struct usb_request req; + struct list_head queue; +}; + +enum ep0_state { + EP0_IDLE, + EP0_IN_DATA_PHASE, + EP0_OUT_DATA_PHASE, + EP0_END_XFER, + EP0_STALL, +}; + +#define EP0_FIFO_SIZE 16U +#define BULK_FIFO_SIZE 64U +#define ISO_FIFO_SIZE 256U +#define INT_FIFO_SIZE 8U + +struct udc_stats { + struct ep0stats { + unsigned long ops; + unsigned long bytes; + } read, write; + unsigned long irqs; +}; + +#ifdef CONFIG_USB_PXA25X_SMALL +/* when memory's tight, SMALL config saves code+data. */ +#define PXA_UDC_NUM_ENDPOINTS 3 +#endif + +#ifndef PXA_UDC_NUM_ENDPOINTS +#define PXA_UDC_NUM_ENDPOINTS 16 +#endif + +struct pxa25x_watchdog { + unsigned running:1; + ulong period; + ulong base; + struct pxa25x_udc *udc; + + void (*function)(struct pxa25x_udc *udc); +}; + +struct pxa25x_udc { + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + struct pxa25x_udc_regs *regs; + + enum ep0_state ep0state; + struct udc_stats stats; + unsigned got_irq:1, + pullup:1, + has_cfr:1, + req_pending:1, + req_std:1, + req_config:1, + active:1; + + struct clk *clk; + struct pxa2xx_udc_mach_info *mach; + u64 dma_mask; + struct pxa25x_ep ep[PXA_UDC_NUM_ENDPOINTS]; + + struct pxa25x_watchdog watchdog; +}; + +/*-------------------------------------------------------------------------*/ + +static struct pxa25x_udc *the_controller; + +/*-------------------------------------------------------------------------*/ + +#ifndef DEBUG +# define NOISY 0 +#endif + +#endif /* __LINUX_USB_GADGET_PXA25X_H */ diff --git a/drivers/usb/host/ehci-armada100.c b/drivers/usb/host/ehci-armada100.c index 7725641487..d24ed3e3f2 100644 --- a/drivers/usb/host/ehci-armada100.c +++ b/drivers/usb/host/ehci-armada100.c @@ -31,7 +31,6 @@ #include <asm/io.h> #include <usb.h> #include "ehci.h" -#include "ehci-core.h" #include <asm/arch/cpu.h> #include <asm/arch/armada100.h> #include <asm/arch/utmi-armada100.h> @@ -39,18 +38,18 @@ /* * EHCI host controller init */ -int ehci_hcd_init(void) +int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { if (utmi_init() < 0) return -1; - hccr = (struct ehci_hccr *)(ARMD1_USB_HOST_BASE + 0x100); - hcor = (struct ehci_hcor *)((uint32_t) hccr - + HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + *hccr = (struct ehci_hccr *)(ARMD1_USB_HOST_BASE + 0x100); + *hcor = (struct ehci_hcor *)((uint32_t) *hccr + + HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); debug("armada100-ehci: init hccr %x and hcor %x hc_length %d\n", - (uint32_t)hccr, (uint32_t)hcor, - (uint32_t)HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + (uint32_t)*hccr, (uint32_t)*hcor, + (uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); return 0; } @@ -58,7 +57,7 @@ int ehci_hcd_init(void) /* * EHCI host controller stop */ -int ehci_hcd_stop(void) +int ehci_hcd_stop(int index) { return 0; } diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c index 15b9b60eb4..05058d3e33 100644 --- a/drivers/usb/host/ehci-atmel.c +++ b/drivers/usb/host/ehci-atmel.c @@ -31,14 +31,13 @@ #include <asm/arch/clk.h> #include "ehci.h" -#include "ehci-core.h" /* Enable UTMI PLL time out 500us * 10 times as datasheet specified */ #define EN_UPLL_TIMEOUT 500UL -int ehci_hcd_init(void) +int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { at91_pmc_t *pmc = (at91_pmc_t *)ATMEL_BASE_PMC; ulong start_time, tmp_time; @@ -58,14 +57,14 @@ int ehci_hcd_init(void) /* Enable USB Host clock */ writel(1 << ATMEL_ID_UHPHS, &pmc->pcer); - hccr = (struct ehci_hccr *)ATMEL_BASE_EHCI; - hcor = (struct ehci_hcor *)((uint32_t)hccr + - HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + *hccr = (struct ehci_hccr *)ATMEL_BASE_EHCI; + *hcor = (struct ehci_hcor *)((uint32_t)*hccr + + HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); return 0; } -int ehci_hcd_stop(void) +int ehci_hcd_stop(int index) { at91_pmc_t *pmc = (at91_pmc_t *)ATMEL_BASE_PMC; ulong start_time, tmp_time; diff --git a/drivers/usb/host/ehci-core.h b/drivers/usb/host/ehci-core.h deleted file mode 100644 index 39e5c5e58c..0000000000 --- a/drivers/usb/host/ehci-core.h +++ /dev/null @@ -1,29 +0,0 @@ -/*- - * Copyright (c) 2007-2008, Juniper Networks, Inc. - * Copyright (c) 2008, Excito Elektronik i SkÃ¥ne AB - * All rights reserved. - * - * 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 version 2 of - * the License. - * - * 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 USB_EHCI_CORE_H -#define USB_EHCI_CORE_H - -extern int rootdev; -extern struct ehci_hccr *hccr; -extern volatile struct ehci_hcor *hcor; - -#endif diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index a71b3977d8..9f0ed06a85 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -27,7 +27,6 @@ #include <asm/arch/system.h> #include <asm/arch/power.h> #include "ehci.h" -#include "ehci-core.h" /* Setup the EHCI host controller. */ static void setup_usb_phy(struct exynos_usb_phy *usb) @@ -85,20 +84,20 @@ static void reset_usb_phy(struct exynos_usb_phy *usb) * Create the appropriate control structures to manage * a new EHCI host controller. */ -int ehci_hcd_init(void) +int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { struct exynos_usb_phy *usb; usb = (struct exynos_usb_phy *)samsung_get_base_usb_phy(); setup_usb_phy(usb); - hccr = (struct ehci_hccr *)samsung_get_base_usb_ehci(); - hcor = (struct ehci_hcor *)((uint32_t) hccr - + HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + *hccr = (struct ehci_hccr *)samsung_get_base_usb_ehci(); + *hcor = (struct ehci_hcor *)((uint32_t) *hccr + + HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); debug("Exynos5-ehci: init hccr %x and hcor %x hc_length %d\n", - (uint32_t)hccr, (uint32_t)hcor, - (uint32_t)HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + (uint32_t)*hccr, (uint32_t)*hcor, + (uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); return 0; } @@ -107,7 +106,7 @@ int ehci_hcd_init(void) * Destroy the appropriate control structures corresponding * the EHCI host controller. */ -int ehci_hcd_stop() +int ehci_hcd_stop(int index) { struct exynos_usb_phy *usb; diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index b2d294ee88..7b8f033b03 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -29,7 +29,6 @@ #include <hwconfig.h> #include "ehci.h" -#include "ehci-core.h" /* * Create the appropriate control structures to manage @@ -37,7 +36,7 @@ * * Excerpts from linux ehci fsl driver. */ -int ehci_hcd_init(void) +int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { struct usb_ehci *ehci; const char *phy_type = NULL; @@ -49,9 +48,9 @@ int ehci_hcd_init(void) #endif ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB_ADDR; - hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); - hcor = (struct ehci_hcor *)((uint32_t) hccr + - HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); + *hcor = (struct ehci_hcor *)((uint32_t) *hccr + + HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); /* Set to Host mode */ setbits_le32(&ehci->usbmode, CM_HOST); @@ -82,14 +81,14 @@ int ehci_hcd_init(void) setbits_be32(&ehci->control, UTMI_PHY_EN); udelay(1000); /* delay required for PHY Clk to appear */ #endif - out_le32(&(hcor->or_portsc[0]), PORT_PTS_UTMI); + out_le32(&(*hcor)->or_portsc[0], PORT_PTS_UTMI); } else { #if defined(CONFIG_SYS_FSL_USB_INTERNAL_UTMI_PHY) clrbits_be32(&ehci->control, UTMI_PHY_EN); setbits_be32(&ehci->control, PHY_CLK_SEL_ULPI); udelay(1000); /* delay required for PHY Clk to appear */ #endif - out_le32(&(hcor->or_portsc[0]), PORT_PTS_ULPI); + out_le32(&(*hcor)->or_portsc[0], PORT_PTS_ULPI); } /* Enable interface. */ @@ -108,7 +107,7 @@ int ehci_hcd_init(void) * Destroy the appropriate control structures corresponding * the the EHCI host controller. */ -int ehci_hcd_stop(void) +int ehci_hcd_stop(int index) { return 0; } diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 392e286224..d90e94d810 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -30,12 +30,17 @@ #include "ehci.h" -int rootdev; -struct ehci_hccr *hccr; /* R/O registers, not need for volatile */ -volatile struct ehci_hcor *hcor; +#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT +#define CONFIG_USB_MAX_CONTROLLER_COUNT 1 +#endif -static uint16_t portreset; -DEFINE_ALIGN_BUFFER(struct QH, qh_list, 1, USB_DMA_MINALIGN); +static struct ehci_ctrl { + struct ehci_hccr *hccr; /* R/O registers, not need for volatile */ + struct ehci_hcor *hcor; + int rootdev; + uint16_t portreset; + struct QH qh_list __attribute__((aligned(USB_DMA_MINALIGN))); +} ehcic[CONFIG_USB_MAX_CONTROLLER_COUNT]; #define ALIGN_END_ADDR(type, ptr, size) \ ((uint32_t)(ptr) + roundup((size) * sizeof(type), USB_DMA_MINALIGN)) @@ -136,24 +141,25 @@ static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec) return -1; } -static int ehci_reset(void) +static int ehci_reset(int index) { uint32_t cmd; uint32_t tmp; uint32_t *reg_ptr; int ret = 0; - cmd = ehci_readl(&hcor->or_usbcmd); + cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd); cmd = (cmd & ~CMD_RUN) | CMD_RESET; - ehci_writel(&hcor->or_usbcmd, cmd); - ret = handshake((uint32_t *)&hcor->or_usbcmd, CMD_RESET, 0, 250 * 1000); + ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd); + ret = handshake((uint32_t *)&ehcic[index].hcor->or_usbcmd, + CMD_RESET, 0, 250 * 1000); if (ret < 0) { printf("EHCI fail to reset\n"); goto out; } if (ehci_is_TDI()) { - reg_ptr = (uint32_t *)((u8 *)hcor + USBMODE); + reg_ptr = (uint32_t *)((u8 *)ehcic[index].hcor + USBMODE); tmp = ehci_readl(reg_ptr); tmp |= USBMODE_CM_HC; #if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN) @@ -163,10 +169,10 @@ static int ehci_reset(void) } #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH - cmd = ehci_readl(&hcor->or_txfilltuning); + cmd = ehci_readl(&ehcic[index].hcor->or_txfilltuning); cmd &= ~TXFIFO_THRESH_MASK; cmd |= TXFIFO_THRESH(CONFIG_USB_EHCI_TXFIFO_THRESH); - ehci_writel(&hcor->or_txfilltuning, cmd); + ehci_writel(&ehcic[index].hcor->or_txfilltuning, cmd); #endif out: return ret; @@ -212,7 +218,6 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, struct qTD *qtd; int qtd_count = 0; int qtd_counter = 0; - volatile struct qTD *vtd; unsigned long ts; uint32_t *tdp; @@ -221,6 +226,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, uint32_t cmd; int timeout; int ret = 0; + struct ehci_ctrl *ctrl = dev->controller; debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe, buffer, length, req); @@ -311,7 +317,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, * qh_overlay.qt_next ...... 13-10 H * - qh_overlay.qt_altnext */ - qh->qh_link = cpu_to_hc32((uint32_t)qh_list | QH_LINK_TYPE_QH); + qh->qh_link = cpu_to_hc32((uint32_t)&ctrl->qh_list | QH_LINK_TYPE_QH); c = usb_pipespeed(pipe) != USB_SPEED_HIGH && !usb_pipeendpoint(pipe); maxpacket = usb_maxpacket(dev, pipe); endpt = QH_ENDPT1_RL(8) | QH_ENDPT1_C(c) | @@ -445,27 +451,27 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, tdp = &qtd[qtd_counter++].qt_next; } - qh_list->qh_link = cpu_to_hc32((uint32_t)qh | QH_LINK_TYPE_QH); + ctrl->qh_list.qh_link = cpu_to_hc32((uint32_t)qh | QH_LINK_TYPE_QH); /* Flush dcache */ - flush_dcache_range((uint32_t)qh_list, - ALIGN_END_ADDR(struct QH, qh_list, 1)); + flush_dcache_range((uint32_t)&ctrl->qh_list, + ALIGN_END_ADDR(struct QH, &ctrl->qh_list, 1)); flush_dcache_range((uint32_t)qh, ALIGN_END_ADDR(struct QH, qh, 1)); flush_dcache_range((uint32_t)qtd, ALIGN_END_ADDR(struct qTD, qtd, qtd_count)); /* Set async. queue head pointer. */ - ehci_writel(&hcor->or_asynclistaddr, (uint32_t)qh_list); + ehci_writel(&ctrl->hcor->or_asynclistaddr, (uint32_t)&ctrl->qh_list); - usbsts = ehci_readl(&hcor->or_usbsts); - ehci_writel(&hcor->or_usbsts, (usbsts & 0x3f)); + usbsts = ehci_readl(&ctrl->hcor->or_usbsts); + ehci_writel(&ctrl->hcor->or_usbsts, (usbsts & 0x3f)); /* Enable async. schedule. */ - cmd = ehci_readl(&hcor->or_usbcmd); + cmd = ehci_readl(&ctrl->hcor->or_usbcmd); cmd |= CMD_ASE; - ehci_writel(&hcor->or_usbcmd, cmd); + ehci_writel(&ctrl->hcor->or_usbcmd, cmd); - ret = handshake((uint32_t *)&hcor->or_usbsts, STS_ASS, STS_ASS, + ret = handshake((uint32_t *)&ctrl->hcor->or_usbsts, STS_ASS, STS_ASS, 100 * 1000); if (ret < 0) { printf("EHCI fail timeout STS_ASS set\n"); @@ -478,8 +484,8 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, timeout = USB_TIMEOUT_MS(pipe); do { /* Invalidate dcache */ - invalidate_dcache_range((uint32_t)qh_list, - ALIGN_END_ADDR(struct QH, qh_list, 1)); + invalidate_dcache_range((uint32_t)&ctrl->qh_list, + ALIGN_END_ADDR(struct QH, &ctrl->qh_list, 1)); invalidate_dcache_range((uint32_t)qh, ALIGN_END_ADDR(struct QH, qh, 1)); invalidate_dcache_range((uint32_t)qtd, @@ -508,11 +514,11 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, printf("EHCI timed out on TD - token=%#x\n", token); /* Disable async schedule. */ - cmd = ehci_readl(&hcor->or_usbcmd); + cmd = ehci_readl(&ctrl->hcor->or_usbcmd); cmd &= ~CMD_ASE; - ehci_writel(&hcor->or_usbcmd, cmd); + ehci_writel(&ctrl->hcor->or_usbcmd, cmd); - ret = handshake((uint32_t *)&hcor->or_usbsts, STS_ASS, 0, + ret = handshake((uint32_t *)&ctrl->hcor->or_usbsts, STS_ASS, 0, 100 * 1000); if (ret < 0) { printf("EHCI fail timeout STS_ASS reset\n"); @@ -551,9 +557,9 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, } else { dev->act_len = 0; debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n", - dev->devnum, ehci_readl(&hcor->or_usbsts), - ehci_readl(&hcor->or_portsc[0]), - ehci_readl(&hcor->or_portsc[1])); + dev->devnum, ehci_readl(&ctrl->hcor->or_usbsts), + ehci_readl(&ctrl->hcor->or_portsc[0]), + ehci_readl(&ctrl->hcor->or_portsc[1])); } free(qtd); @@ -584,13 +590,14 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, int len, srclen; uint32_t reg; uint32_t *status_reg; + struct ehci_ctrl *ctrl = dev->controller; if (le16_to_cpu(req->index) > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) { printf("The request port(%d) is not configured\n", le16_to_cpu(req->index) - 1); return -1; } - status_reg = (uint32_t *)&hcor->or_portsc[ + status_reg = (uint32_t *)&ctrl->hcor->or_portsc[ le16_to_cpu(req->index) - 1]; srclen = 0; @@ -658,7 +665,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, break; case USB_REQ_SET_ADDRESS | (USB_RECIP_DEVICE << 8): debug("USB_REQ_SET_ADDRESS\n"); - rootdev = le16_to_cpu(req->value); + ctrl->rootdev = le16_to_cpu(req->value); break; case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: debug("USB_REQ_SET_CONFIGURATION\n"); @@ -708,7 +715,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, tmpbuf[2] |= USB_PORT_STAT_C_ENABLE; if (reg & EHCI_PS_OCC) tmpbuf[2] |= USB_PORT_STAT_C_OVERCURRENT; - if (portreset & (1 << le16_to_cpu(req->index))) + if (ctrl->portreset & (1 << le16_to_cpu(req->index))) tmpbuf[2] |= USB_PORT_STAT_C_RESET; srcptr = tmpbuf; @@ -723,7 +730,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, ehci_writel(status_reg, reg); break; case USB_PORT_FEAT_POWER: - if (HCS_PPC(ehci_readl(&hccr->cr_hcsparams))) { + if (HCS_PPC(ehci_readl(&ctrl->hccr->cr_hcsparams))) { reg |= EHCI_PS_PP; ehci_writel(status_reg, reg); } @@ -760,7 +767,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, ret = handshake(status_reg, EHCI_PS_PR, 0, 2 * 1000); if (!ret) - portreset |= + ctrl->portreset |= 1 << le16_to_cpu(req->index); else printf("port(%d) reset error\n", @@ -772,7 +779,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, goto unknown; } /* unblock posted writes */ - (void) ehci_readl(&hcor->or_usbcmd); + (void) ehci_readl(&ctrl->hcor->or_usbcmd); break; case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8): reg = ehci_readl(status_reg); @@ -784,7 +791,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_PE; break; case USB_PORT_FEAT_POWER: - if (HCS_PPC(ehci_readl(&hccr->cr_hcsparams))) + if (HCS_PPC(ehci_readl(&ctrl->hccr->cr_hcsparams))) reg = reg & ~(EHCI_PS_CLEAR | EHCI_PS_PP); case USB_PORT_FEAT_C_CONNECTION: reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_CSC; @@ -793,7 +800,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_OCC; break; case USB_PORT_FEAT_C_RESET: - portreset &= ~(1 << le16_to_cpu(req->index)); + ctrl->portreset &= ~(1 << le16_to_cpu(req->index)); break; default: debug("unknown feature %x\n", le16_to_cpu(req->value)); @@ -801,7 +808,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, } ehci_writel(status_reg, reg); /* unblock posted write */ - (void) ehci_readl(&hcor->or_usbcmd); + (void) ehci_readl(&ctrl->hcor->or_usbcmd); break; default: debug("Unknown request\n"); @@ -829,28 +836,31 @@ unknown: return -1; } -int usb_lowlevel_stop(void) +int usb_lowlevel_stop(int index) { - return ehci_hcd_stop(); + return ehci_hcd_stop(index); } -int usb_lowlevel_init(void) +int usb_lowlevel_init(int index, void **controller) { uint32_t reg; uint32_t cmd; + struct QH *qh_list; - if (ehci_hcd_init()) + if (ehci_hcd_init(index, &ehcic[index].hccr, &ehcic[index].hcor)) return -1; /* EHCI spec section 4.1 */ - if (ehci_reset()) + if (ehci_reset(index)) return -1; #if defined(CONFIG_EHCI_HCD_INIT_AFTER_RESET) - if (ehci_hcd_init()) + if (ehci_hcd_init(index, &ehcic[index].hccr, &ehcic[index].hcor)) return -1; #endif + qh_list = &ehcic[index].qh_list; + /* Set head of reclaim list */ memset(qh_list, 0, sizeof(*qh_list)); qh_list->qh_link = cpu_to_hc32((uint32_t)qh_list | QH_LINK_TYPE_QH); @@ -862,9 +872,9 @@ int usb_lowlevel_init(void) qh_list->qh_overlay.qt_token = cpu_to_hc32(QT_TOKEN_STATUS(QT_TOKEN_STATUS_HALTED)); - reg = ehci_readl(&hccr->cr_hcsparams); + reg = ehci_readl(&ehcic[index].hccr->cr_hcsparams); descriptor.hub.bNbrPorts = HCS_N_PORTS(reg); - printf("Register %x NbrPorts %d\n", reg, descriptor.hub.bNbrPorts); + debug("Register %x NbrPorts %d\n", reg, descriptor.hub.bNbrPorts); /* Port Indicators */ if (HCS_INDICATOR(reg)) put_unaligned(get_unaligned(&descriptor.hub.wHubCharacteristics) @@ -875,27 +885,28 @@ int usb_lowlevel_init(void) | 0x01, &descriptor.hub.wHubCharacteristics); /* Start the host controller. */ - cmd = ehci_readl(&hcor->or_usbcmd); + cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd); /* * Philips, Intel, and maybe others need CMD_RUN before the * root hub will detect new devices (why?); NEC doesn't */ cmd &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); cmd |= CMD_RUN; - ehci_writel(&hcor->or_usbcmd, cmd); + ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd); /* take control over the ports */ - cmd = ehci_readl(&hcor->or_configflag); + cmd = ehci_readl(&ehcic[index].hcor->or_configflag); cmd |= FLAG_CF; - ehci_writel(&hcor->or_configflag, cmd); + ehci_writel(&ehcic[index].hcor->or_configflag, cmd); /* unblock posted write */ - cmd = ehci_readl(&hcor->or_usbcmd); + cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd); mdelay(5); - reg = HC_VERSION(ehci_readl(&hccr->cr_capbase)); + reg = HC_VERSION(ehci_readl(&ehcic[index].hccr->cr_capbase)); printf("USB EHCI %x.%02x\n", reg >> 8, reg & 0xff); - rootdev = 0; + ehcic[index].rootdev = 0; + *controller = &ehcic[index]; return 0; } @@ -915,14 +926,15 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int length, struct devrequest *setup) { + struct ehci_ctrl *ctrl = dev->controller; if (usb_pipetype(pipe) != PIPE_CONTROL) { debug("non-control pipe (type=%lu)", usb_pipetype(pipe)); return -1; } - if (usb_pipedevice(pipe) == rootdev) { - if (!rootdev) + if (usb_pipedevice(pipe) == ctrl->rootdev) { + if (!ctrl->rootdev) dev->speed = USB_SPEED_HIGH; return ehci_submit_root(dev, pipe, buffer, length, setup); } diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c index b8f15ae52a..cf3d5f5fd7 100644 --- a/drivers/usb/host/ehci-ixp4xx.c +++ b/drivers/usb/host/ehci-ixp4xx.c @@ -23,20 +23,19 @@ #include <usb.h> #include "ehci.h" -#include "ehci-core.h" /* * Create the appropriate control structures to manage * a new EHCI host controller. */ -int ehci_hcd_init(void) +int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { - hccr = (struct ehci_hccr *)(0xcd000100); - hcor = (struct ehci_hcor *)((uint32_t) hccr - + HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + *hccr = (struct ehci_hccr *)(0xcd000100); + *hcor = (struct ehci_hcor *)((uint32_t) *hccr + + HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); printf("IXP4XX init hccr %x and hcor %x hc_length %d\n", - (uint32_t)hccr, (uint32_t)hcor, - (uint32_t)HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + (uint32_t)*hccr, (uint32_t)*hcor, + (uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); return 0; } @@ -44,7 +43,7 @@ int ehci_hcd_init(void) * Destroy the appropriate control structures corresponding * the the EHCI host controller. */ -int ehci_hcd_stop(void) +int ehci_hcd_stop(int index) { return 0; } diff --git a/drivers/usb/host/ehci-marvell.c b/drivers/usb/host/ehci-marvell.c index 89c8af7287..2b73e4ad6a 100644 --- a/drivers/usb/host/ehci-marvell.c +++ b/drivers/usb/host/ehci-marvell.c @@ -26,7 +26,6 @@ #include <asm/io.h> #include <usb.h> #include "ehci.h" -#include "ehci-core.h" #include <asm/arch/cpu.h> #if defined(CONFIG_KIRKWOOD) @@ -91,17 +90,17 @@ static void usb_brg_adrdec_setup(void) * Create the appropriate control structures to manage * a new EHCI host controller. */ -int ehci_hcd_init(void) +int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { usb_brg_adrdec_setup(); - hccr = (struct ehci_hccr *)(MVUSB0_BASE + 0x100); - hcor = (struct ehci_hcor *)((uint32_t) hccr - + HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + *hccr = (struct ehci_hccr *)(MVUSB0_BASE + 0x100); + *hcor = (struct ehci_hcor *)((uint32_t) *hccr + + HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); debug("ehci-marvell: init hccr %x and hcor %x hc_length %d\n", - (uint32_t)hccr, (uint32_t)hcor, - (uint32_t)HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + (uint32_t)*hccr, (uint32_t)*hcor, + (uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); return 0; } @@ -110,7 +109,7 @@ int ehci_hcd_init(void) * Destroy the appropriate control structures corresponding * the the EHCI host controller. */ -int ehci_hcd_stop(void) +int ehci_hcd_stop(int index) { return 0; } diff --git a/drivers/usb/host/ehci-mpc512x.c b/drivers/usb/host/ehci-mpc512x.c index d36010826b..e98f79f9cc 100644 --- a/drivers/usb/host/ehci-mpc512x.c +++ b/drivers/usb/host/ehci-mpc512x.c @@ -33,7 +33,6 @@ #include <usb/ehci-fsl.h> #include "ehci.h" -#include "ehci-core.h" static void fsl_setup_phy(volatile struct ehci_hcor *); static void fsl_platform_set_host_mode(volatile struct usb_ehci *ehci); @@ -46,21 +45,21 @@ static void usb_platform_dr_init(volatile struct usb_ehci *ehci); * This code is derived from EHCI FSL USB Linux driver for MPC5121 * */ -int ehci_hcd_init(void) +int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { volatile struct usb_ehci *ehci; /* Hook the memory mapped registers for EHCI-Controller */ ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB_ADDR; - hccr = (struct ehci_hccr *)((uint32_t)&(ehci->caplength)); - hcor = (struct ehci_hcor *)((uint32_t) hccr + - HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + *hccr = (struct ehci_hccr *)((uint32_t)&(ehci->caplength)); + *hcor = (struct ehci_hcor *)((uint32_t) *hccr + + HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); /* configure interface for UTMI_WIDE */ usb_platform_dr_init(ehci); /* Init Phy USB0 to UTMI+ */ - fsl_setup_phy(hcor); + fsl_setup_phy(*hcor); /* Set to host mode */ fsl_platform_set_host_mode(ehci); @@ -89,20 +88,14 @@ int ehci_hcd_init(void) * Destroy the appropriate control structures corresponding * the the EHCI host controller. */ -int ehci_hcd_stop(void) +int ehci_hcd_stop(int index) { volatile struct usb_ehci *ehci; int exit_status = 0; - if (hcor) { - /* Unhook struct */ - hccr = NULL; - hcor = NULL; - - /* Reset the USB controller */ - ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB_ADDR; - exit_status = reset_usb_controller(ehci); - } + /* Reset the USB controller */ + ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB_ADDR; + exit_status = reset_usb_controller(ehci); return exit_status; } diff --git a/drivers/usb/host/ehci-mx5.c b/drivers/usb/host/ehci-mx5.c index 58cdcbedf2..9a2c295ec5 100644 --- a/drivers/usb/host/ehci-mx5.c +++ b/drivers/usb/host/ehci-mx5.c @@ -25,7 +25,6 @@ #include <asm/arch/iomux.h> #include "ehci.h" -#include "ehci-core.h" #define MX5_USBOTHER_REGS_OFFSET 0x800 @@ -206,7 +205,7 @@ void __board_ehci_hcd_postinit(struct usb_ehci *ehci, int port) void board_ehci_hcd_postinit(struct usb_ehci *ehci, int port) __attribute((weak, alias("__board_ehci_hcd_postinit"))); -int ehci_hcd_init(void) +int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { struct usb_ehci *ehci; #ifdef CONFIG_MX53 @@ -221,7 +220,8 @@ int ehci_hcd_init(void) set_usboh3_clk(); enable_usboh3_clk(1); - set_usb_phy2_clk(); + set_usb_phy_clk(); + enable_usb_phy1_clk(1); enable_usb_phy2_clk(1); mdelay(1); @@ -230,9 +230,9 @@ int ehci_hcd_init(void) ehci = (struct usb_ehci *)(OTG_BASE_ADDR + (0x200 * CONFIG_MXC_USB_PORT)); - hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); - hcor = (struct ehci_hcor *)((uint32_t)hccr + - HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); + *hcor = (struct ehci_hcor *)((uint32_t)*hccr + + HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); setbits_le32(&ehci->usbmode, CM_HOST); __raw_writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); @@ -247,7 +247,7 @@ int ehci_hcd_init(void) return 0; } -int ehci_hcd_stop(void) +int ehci_hcd_stop(int index) { return 0; } diff --git a/drivers/usb/host/ehci-mx6.c b/drivers/usb/host/ehci-mx6.c index 028024298d..9ce25da598 100644 --- a/drivers/usb/host/ehci-mx6.c +++ b/drivers/usb/host/ehci-mx6.c @@ -25,7 +25,6 @@ #include <asm/imx-common/iomux-v3.h> #include "ehci.h" -#include "ehci-core.h" #define USB_OTGREGS_OFFSET 0x000 #define USB_H1REGS_OFFSET 0x200 @@ -160,7 +159,7 @@ static void usbh1_oc_config(void) __raw_writel(val, usbother_base + USB_H1_CTRL_OFFSET); } -int ehci_hcd_init(void) +int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { struct usb_ehci *ehci; @@ -182,9 +181,9 @@ int ehci_hcd_init(void) ehci = (struct usb_ehci *)(USBOH3_USB_BASE_ADDR + (0x200 * CONFIG_MXC_USB_PORT)); - hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); - hcor = (struct ehci_hcor *)((uint32_t)hccr + - HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); + *hcor = (struct ehci_hcor *)((uint32_t)*hccr + + HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); setbits_le32(&ehci->usbmode, CM_HOST); __raw_writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); @@ -195,7 +194,7 @@ int ehci_hcd_init(void) return 0; } -int ehci_hcd_stop(void) +int ehci_hcd_stop(int index) { return 0; } diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index 45cbd18a00..a38bc9c1bb 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c @@ -25,7 +25,6 @@ #include <errno.h> #include "ehci.h" -#include "ehci-core.h" #define USBCTRL_OTGBASE_OFFSET 0x600 @@ -106,7 +105,7 @@ static int mxc_set_usbcontrol(int port, unsigned int flags) return 0; } -int ehci_hcd_init(void) +int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { struct usb_ehci *ehci; #ifdef CONFIG_MX31 @@ -121,9 +120,9 @@ int ehci_hcd_init(void) ehci = (struct usb_ehci *)(IMX_USB_BASE + (0x200 * CONFIG_MXC_USB_PORT)); - hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); - hcor = (struct ehci_hcor *)((uint32_t) hccr + - HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); + *hcor = (struct ehci_hcor *)((uint32_t) *hccr + + HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); setbits_le32(&ehci->usbmode, CM_HOST); __raw_writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); mxc_set_usbcontrol(CONFIG_MXC_USB_PORT, CONFIG_MXC_USB_FLAGS); @@ -137,7 +136,7 @@ int ehci_hcd_init(void) * Destroy the appropriate control structures corresponding * the the EHCI host controller. */ -int ehci_hcd_stop(void) +int ehci_hcd_stop(int index) { return 0; } diff --git a/drivers/usb/host/ehci-mxs.c b/drivers/usb/host/ehci-mxs.c index 6e21669d5a..5062af5559 100644 --- a/drivers/usb/host/ehci-mxs.c +++ b/drivers/usb/host/ehci-mxs.c @@ -27,7 +27,6 @@ #include <asm/arch/regs-usb.h> #include <asm/arch/regs-usbphy.h> -#include "ehci-core.h" #include "ehci.h" #if (CONFIG_EHCI_MXS_PORT != 0) && (CONFIG_EHCI_MXS_PORT != 1) @@ -70,7 +69,7 @@ int mxs_ehci_get_port(struct ehci_mxs *mxs_usb, int port) #define HW_DIGCTL_CTRL_USB0_CLKGATE (1 << 2) #define HW_DIGCTL_CTRL_USB1_CLKGATE (1 << 16) -int ehci_hcd_init(void) +int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { int ret; @@ -107,28 +106,35 @@ int ehci_hcd_init(void) &ehci_mxs.phy_regs->hw_usbphy_ctrl_set); usb_base = ((uint32_t)ehci_mxs.usb_regs) + 0x100; - hccr = (struct ehci_hccr *)usb_base; + *hccr = (struct ehci_hccr *)usb_base; - cap_base = ehci_readl(&hccr->cr_capbase); - hcor = (struct ehci_hcor *)(usb_base + HC_LENGTH(cap_base)); + cap_base = ehci_readl(&(*hccr)->cr_capbase); + *hcor = (struct ehci_hcor *)(usb_base + HC_LENGTH(cap_base)); return 0; } -int ehci_hcd_stop(void) +int ehci_hcd_stop(int index) { int ret; - uint32_t tmp; + uint32_t usb_base, cap_base, tmp; struct mxs_register_32 *digctl_ctrl = (struct mxs_register_32 *)HW_DIGCTL_CTRL; struct mxs_clkctrl_regs *clkctrl_regs = (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + struct ehci_hccr *hccr; + struct ehci_hcor *hcor; ret = mxs_ehci_get_port(&ehci_mxs, CONFIG_EHCI_MXS_PORT); if (ret) return ret; /* Stop the USB port */ + usb_base = ((uint32_t)ehci_mxs.usb_regs) + 0x100; + hccr = (struct ehci_hccr *)usb_base; + cap_base = ehci_readl(&hccr->cr_capbase); + hcor = (struct ehci_hcor *)(usb_base + HC_LENGTH(cap_base)); + tmp = ehci_readl(&hcor->or_usbcmd); tmp &= ~CMD_RUN; ehci_writel(tmp, &hcor->or_usbcmd); diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 292673bf00..086c6978e1 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -33,7 +33,8 @@ #include <asm/gpio.h> #include <asm/arch/ehci.h> #include <asm/ehci-omap.h> -#include "ehci-core.h" + +#include "ehci.h" static struct omap_uhh *const uhh = (struct omap_uhh *)OMAP_UHH_BASE; static struct omap_usbtll *const usbtll = (struct omap_usbtll *)OMAP_USBTLL_BASE; @@ -155,7 +156,8 @@ int omap_ehci_hcd_stop(void) * Based on "drivers/usb/host/ehci-omap.c" from Linux 3.1 * See there for additional Copyrights. */ -int omap_ehci_hcd_init(struct omap_usbhs_board_data *usbhs_pdata) +int omap_ehci_hcd_init(struct omap_usbhs_board_data *usbhs_pdata, + struct ehci_hccr **hccr, struct ehci_hcor **hcor) { int ret; unsigned int i, reg = 0, rev = 0; @@ -246,8 +248,8 @@ int omap_ehci_hcd_init(struct omap_usbhs_board_data *usbhs_pdata) if (is_ehci_phy_mode(usbhs_pdata->port_mode[i])) omap_ehci_soft_phy_reset(i); - hccr = (struct ehci_hccr *)(OMAP_EHCI_BASE); - hcor = (struct ehci_hcor *)(OMAP_EHCI_BASE + 0x10); + *hccr = (struct ehci_hccr *)(OMAP_EHCI_BASE); + *hcor = (struct ehci_hcor *)(OMAP_EHCI_BASE + 0x10); debug("OMAP EHCI init done\n"); return 0; diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 020ab11355..29af02dc5b 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -23,7 +23,6 @@ #include <usb.h> #include "ehci.h" -#include "ehci-core.h" #ifdef CONFIG_PCI_EHCI_DEVICE static struct pci_device_id ehci_pci_ids[] = { @@ -39,7 +38,7 @@ static struct pci_device_id ehci_pci_ids[] = { * Create the appropriate control structures to manage * a new EHCI host controller. */ -int ehci_hcd_init(void) +int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { pci_dev_t pdev; @@ -49,14 +48,14 @@ int ehci_hcd_init(void) return -1; } - hccr = (struct ehci_hccr *)pci_map_bar(pdev, + *hccr = (struct ehci_hccr *)pci_map_bar(pdev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM); - hcor = (struct ehci_hcor *)((uint32_t) hccr + - HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + *hcor = (struct ehci_hcor *)((uint32_t) *hccr + + HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); debug("EHCI-PCI init hccr 0x%x and hcor 0x%x hc_length %d\n", - (uint32_t)hccr, (uint32_t)hcor, - (uint32_t)HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + (uint32_t)*hccr, (uint32_t)*hcor, + (uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); return 0; } @@ -65,7 +64,7 @@ int ehci_hcd_init(void) * Destroy the appropriate control structures corresponding * the the EHCI host controller. */ -int ehci_hcd_stop(void) +int ehci_hcd_stop(int index) { return 0; } diff --git a/drivers/usb/host/ehci-ppc4xx.c b/drivers/usb/host/ehci-ppc4xx.c index 1179919987..e389c755e1 100644 --- a/drivers/usb/host/ehci-ppc4xx.c +++ b/drivers/usb/host/ehci-ppc4xx.c @@ -23,17 +23,16 @@ #include <usb.h> #include "ehci.h" -#include "ehci-core.h" /* * Create the appropriate control structures to manage * a new EHCI host controller. */ -int ehci_hcd_init(void) +int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { - hccr = (struct ehci_hccr *)(CONFIG_SYS_PPC4XX_USB_ADDR); - hcor = (struct ehci_hcor *)((uint32_t) hccr + - HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + *hccr = (struct ehci_hccr *)(CONFIG_SYS_PPC4XX_USB_ADDR); + *hcor = (struct ehci_hcor *)((uint32_t) *hccr + + HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); return 0; } @@ -41,7 +40,7 @@ int ehci_hcd_init(void) * Destroy the appropriate control structures corresponding * the the EHCI host controller. */ -int ehci_hcd_stop(void) +int ehci_hcd_stop(int index) { return 0; } diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 4646b29508..a1c43f8331 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -24,7 +24,6 @@ #include <usb.h> #include "ehci.h" -#include "ehci-core.h" #include <asm/errno.h> #include <asm/arch/usb.h> @@ -50,7 +49,7 @@ void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg) * Create the appropriate control structures to manage * a new EHCI host controller. */ -int ehci_hcd_init(void) +int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { u32 our_hccr, our_hcor; @@ -58,11 +57,11 @@ int ehci_hcd_init(void) * Select the first port, as we don't have a way of selecting others * yet */ - if (tegrausb_start_port(0, &our_hccr, &our_hcor)) + if (tegrausb_start_port(index, &our_hccr, &our_hcor)) return -1; - hccr = (struct ehci_hccr *)our_hccr; - hcor = (struct ehci_hcor *)our_hcor; + *hccr = (struct ehci_hccr *)our_hccr; + *hcor = (struct ehci_hcor *)our_hcor; return 0; } @@ -71,8 +70,7 @@ int ehci_hcd_init(void) * Destroy the appropriate control structures corresponding * the the EHCI host controller. */ -int ehci_hcd_stop(void) +int ehci_hcd_stop(int index) { - tegrausb_stop_port(); - return 0; + return tegrausb_stop_port(index); } diff --git a/drivers/usb/host/ehci-vct.c b/drivers/usb/host/ehci-vct.c index 3063dd172f..5f8a159e72 100644 --- a/drivers/usb/host/ehci-vct.c +++ b/drivers/usb/host/ehci-vct.c @@ -21,7 +21,6 @@ #include <usb.h> #include "ehci.h" -#include "ehci-core.h" int vct_ehci_hcd_init(u32 *hccr, u32 *hcor); @@ -29,7 +28,7 @@ int vct_ehci_hcd_init(u32 *hccr, u32 *hcor); * Create the appropriate control structures to manage * a new EHCI host controller. */ -int ehci_hcd_init(void) +int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { int ret; u32 vct_hccr; @@ -42,8 +41,8 @@ int ehci_hcd_init(void) if (ret) return ret; - hccr = (struct ehci_hccr *)vct_hccr; - hcor = (struct ehci_hcor *)vct_hcor; + *hccr = (struct ehci_hccr *)vct_hccr; + *hcor = (struct ehci_hcor *)vct_hcor; return 0; } @@ -52,7 +51,7 @@ int ehci_hcd_init(void) * Destroy the appropriate control structures corresponding * the the EHCI host controller. */ -int ehci_hcd_stop(void) +int ehci_hcd_stop(int index) { return 0; } diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 39acdf9656..1e3cd793b6 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -249,7 +249,7 @@ struct QH { }; /* Low level init functions */ -int ehci_hcd_init(void); -int ehci_hcd_stop(void); +int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor); +int ehci_hcd_stop(int index); #endif /* USB_EHCI_H */ diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 5ef34c30fd..19e16a4a80 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1391,7 +1391,7 @@ int isp116x_check_id(struct isp116x *isp116x) return 0; } -int usb_lowlevel_init(void) +int usb_lowlevel_init(int index, void **controller)) { struct isp116x *isp116x = &isp116x_dev; @@ -1428,7 +1428,7 @@ int usb_lowlevel_init(void) return 0; } -int usb_lowlevel_stop(void) +int usb_lowlevel_stop(int index) { struct isp116x *isp116x = &isp116x_dev; diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 9f4735167a..c2106adbd3 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1865,7 +1865,7 @@ static void hc_release_ohci(ohci_t *ohci) */ static char ohci_inited = 0; -int usb_lowlevel_init(void) +int usb_lowlevel_init(int index, void **controller) { #ifdef CONFIG_PCI_OHCI pci_dev_t pdev; @@ -1971,7 +1971,7 @@ int usb_lowlevel_init(void) return 0; } -int usb_lowlevel_stop(void) +int usb_lowlevel_stop(int index) { /* this gets called really early - before the controller has */ /* even been initialized! */ diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index ab1b8d0d8b..2a4e7ff4b3 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -908,7 +908,7 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, return 0; } -int usb_lowlevel_init(void) +int usb_lowlevel_init(int index, void **controller)) { struct r8a66597 *r8a66597 = &gr8a66597; @@ -931,7 +931,7 @@ int usb_lowlevel_init(void) return 0; } -int usb_lowlevel_stop(void) +int usb_lowlevel_stop(int index) { disable_controller(&gr8a66597); diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index bb27dd514a..2830616046 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -210,14 +210,14 @@ static int sl811_hc_reset(void) return 1; } -int usb_lowlevel_init(void) +int usb_lowlevel_init(int index, void **controller) { root_hub_devnum = 0; sl811_hc_reset(); return 0; } -int usb_lowlevel_stop(void) +int usb_lowlevel_stop(int index) { sl811_hc_reset(); return 0; diff --git a/drivers/usb/musb/musb_hcd.c b/drivers/usb/musb/musb_hcd.c index 8d44c4657f..06be38d1cf 100644 --- a/drivers/usb/musb/musb_hcd.c +++ b/drivers/usb/musb/musb_hcd.c @@ -1092,7 +1092,7 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, /* * This function initializes the usb controller module. */ -int usb_lowlevel_init(void) +int usb_lowlevel_init(int index, void **controller) { u8 power; u32 timeout; @@ -1144,7 +1144,7 @@ int usb_lowlevel_init(void) /* * This function stops the operation of the davinci usb module. */ -int usb_lowlevel_stop(void) +int usb_lowlevel_stop(int index) { /* Reset the USB module */ musb_platform_deinit(); diff --git a/drivers/usb/ulpi/ulpi.c b/drivers/usb/ulpi/ulpi.c index dde2585c58..23b59e740f 100644 --- a/drivers/usb/ulpi/ulpi.c +++ b/drivers/usb/ulpi/ulpi.c @@ -106,20 +106,44 @@ int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed) return ulpi_write(ulpi_vp, &ulpi->function_ctrl, val); } -int ulpi_set_vbus(struct ulpi_viewport *ulpi_vp, int on, int ext_power, - int ext_ind) +int ulpi_set_vbus(struct ulpi_viewport *ulpi_vp, int on, int ext_power) { u32 flags = ULPI_OTG_DRVVBUS; u8 *reg = on ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear; if (ext_power) flags |= ULPI_OTG_DRVVBUS_EXT; - if (ext_ind) - flags |= ULPI_OTG_EXTVBUSIND; return ulpi_write(ulpi_vp, reg, flags); } +int ulpi_set_vbus_indicator(struct ulpi_viewport *ulpi_vp, int external, + int passthu, int complement) +{ + u32 flags, val; + u8 *reg; + + reg = external ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear; + val = ulpi_write(ulpi_vp, reg, ULPI_OTG_EXTVBUSIND); + if (val) + return val; + + flags = passthu ? ULPI_IFACE_PASSTHRU : 0; + flags |= complement ? ULPI_IFACE_EXTVBUS_COMPLEMENT : 0; + + val = ulpi_read(ulpi_vp, &ulpi->iface_ctrl); + if (val == ULPI_ERROR) + return val; + + val = val & ~(ULPI_IFACE_PASSTHRU & ULPI_IFACE_EXTVBUS_COMPLEMENT); + val |= flags; + val = ulpi_write(ulpi_vp, &ulpi->iface_ctrl, val); + if (val) + return val; + + return 0; +} + int ulpi_set_pd(struct ulpi_viewport *ulpi_vp, int enable) { u32 val = ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN; diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c index 19d061f6cb..9f7794fe53 100644 --- a/drivers/video/cfb_console.c +++ b/drivers/video/cfb_console.c @@ -66,7 +66,11 @@ * CONFIG_CONSOLE_TIME - display time/date in upper right * corner, needs CONFIG_CMD_DATE and * CONFIG_CONSOLE_CURSOR - * CONFIG_VIDEO_LOGO - display Linux Logo in upper left corner + * CONFIG_VIDEO_LOGO - display Linux Logo in upper left corner. + * Use CONFIG_SPLASH_SCREEN_ALIGN with + * environment variable "splashpos" to place + * the logo on other position. In this case + * no CONSOLE_EXTRA_INFO is possible. * CONFIG_VIDEO_BMP_LOGO - use bmp_logo instead of linux_logo * CONFIG_CONSOLE_EXTRA_INFO - display additional board information * strings that normaly goes to serial @@ -1480,7 +1484,42 @@ int video_display_bitmap(ulong bmp_image, int x, int y) #ifdef CONFIG_VIDEO_LOGO -void logo_plot(void *screen, int width, int x, int y) +static int video_logo_xpos; +static int video_logo_ypos; + +static void plot_logo_or_black(void *screen, int width, int x, int y, \ + int black); + +static void logo_plot(void *screen, int width, int x, int y) +{ + plot_logo_or_black(screen, width, x, y, 0); +} + +static void logo_black(void) +{ + plot_logo_or_black(video_fb_address, \ + VIDEO_COLS, \ + video_logo_xpos, \ + video_logo_ypos, \ + 1); +} + +static int do_clrlogo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + if (argc != 1) + return cmd_usage(cmdtp); + + logo_black(); + return 0; +} + +U_BOOT_CMD( + clrlogo, 1, 0, do_clrlogo, + "fill the boot logo area with black", + " " + ); + +static void plot_logo_or_black(void *screen, int width, int x, int y, int black) { int xcount, i; @@ -1488,8 +1527,21 @@ void logo_plot(void *screen, int width, int x, int y) int ycount = video_logo_height; unsigned char r, g, b, *logo_red, *logo_blue, *logo_green; unsigned char *source; - unsigned char *dest = (unsigned char *) screen + - ((y * width * VIDEO_PIXEL_SIZE) + x * VIDEO_PIXEL_SIZE); + unsigned char *dest; + +#ifdef CONFIG_SPLASH_SCREEN_ALIGN + if (x == BMP_ALIGN_CENTER) + x = max(0, (VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH) / 2); + else if (x < 0) + x = max(0, VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH + x + 1); + + if (y == BMP_ALIGN_CENTER) + y = max(0, (VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT) / 2); + else if (y < 0) + y = max(0, VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT + y + 1); +#endif /* CONFIG_SPLASH_SCREEN_ALIGN */ + + dest = (unsigned char *)screen + (y * width + x) * VIDEO_PIXEL_SIZE; #ifdef CONFIG_VIDEO_BMP_LOGO source = bmp_logo_bitmap; @@ -1525,9 +1577,15 @@ void logo_plot(void *screen, int width, int x, int y) #endif xcount = VIDEO_LOGO_WIDTH; while (xcount--) { - r = logo_red[*source - VIDEO_LOGO_LUT_OFFSET]; - g = logo_green[*source - VIDEO_LOGO_LUT_OFFSET]; - b = logo_blue[*source - VIDEO_LOGO_LUT_OFFSET]; + if (black) { + r = 0x00; + g = 0x00; + b = 0x00; + } else { + r = logo_red[*source - VIDEO_LOGO_LUT_OFFSET]; + g = logo_green[*source - VIDEO_LOGO_LUT_OFFSET]; + b = logo_blue[*source - VIDEO_LOGO_LUT_OFFSET]; + } switch (VIDEO_DATA_FORMAT) { case GDF__8BIT_INDEX: @@ -1592,42 +1650,66 @@ static void *video_logo(void) char info[128]; int space, len; __maybe_unused int y_off = 0; + __maybe_unused ulong addr; + __maybe_unused char *s; -#ifdef CONFIG_SPLASH_SCREEN - char *s; - ulong addr; - - s = getenv("splashimage"); +#ifdef CONFIG_SPLASH_SCREEN_ALIGN + s = getenv("splashpos"); if (s != NULL) { - int x = 0, y = 0; + if (s[0] == 'm') + video_logo_xpos = BMP_ALIGN_CENTER; + else + video_logo_xpos = simple_strtol(s, NULL, 0); - addr = simple_strtoul(s, NULL, 16); -#ifdef CONFIG_SPLASH_SCREEN_ALIGN - s = getenv("splashpos"); + s = strchr(s + 1, ','); if (s != NULL) { - if (s[0] == 'm') - x = BMP_ALIGN_CENTER; + if (s[1] == 'm') + video_logo_ypos = BMP_ALIGN_CENTER; else - x = simple_strtol(s, NULL, 0); - - s = strchr(s + 1, ','); - if (s != NULL) { - if (s[1] == 'm') - y = BMP_ALIGN_CENTER; - else - y = simple_strtol(s + 1, NULL, 0); - } + video_logo_ypos = simple_strtol(s + 1, NULL, 0); } + } #endif /* CONFIG_SPLASH_SCREEN_ALIGN */ - if (video_display_bitmap(addr, x, y) == 0) { +#ifdef CONFIG_SPLASH_SCREEN + s = getenv("splashimage"); + if (s != NULL) { + + addr = simple_strtoul(s, NULL, 16); + + + if (video_display_bitmap(addr, + video_logo_xpos, + video_logo_ypos) == 0) { video_logo_height = 0; return ((void *) (video_fb_address)); } } #endif /* CONFIG_SPLASH_SCREEN */ - logo_plot(video_fb_address, VIDEO_COLS, 0, 0); + logo_plot(video_fb_address, VIDEO_COLS, + video_logo_xpos, video_logo_ypos); + +#ifdef CONFIG_SPLASH_SCREEN_ALIGN + /* + * when using splashpos for video_logo, skip any info + * output on video console if the logo is not at 0,0 + */ + if (video_logo_xpos || video_logo_ypos) { + /* + * video_logo_height is used in text and cursor offset + * calculations. Since the console is below the logo, + * we need to adjust the logo height + */ + if (video_logo_ypos == BMP_ALIGN_CENTER) + video_logo_height += max(0, (VIDEO_VISIBLE_ROWS - \ + VIDEO_LOGO_HEIGHT) / 2); + else if (video_logo_ypos > 0) + video_logo_height += video_logo_ypos; + + return video_fb_address + video_logo_height * VIDEO_LINE_LEN; + } +#endif sprintf(info, " %s", version_string); diff --git a/drivers/video/ipu_common.c b/drivers/video/ipu_common.c index 2020da98d2..0f2d113a6f 100644 --- a/drivers/video/ipu_common.c +++ b/drivers/video/ipu_common.c @@ -163,13 +163,13 @@ int clk_set_parent(struct clk *clk, struct clk *parent) static int clk_ipu_enable(struct clk *clk) { -#if defined(CONFIG_MX51) || defined(CONFIG_MX53) u32 reg; reg = __raw_readl(clk->enable_reg); reg |= MXC_CCM_CCGR_CG_MASK << clk->enable_shift; __raw_writel(reg, clk->enable_reg); +#if defined(CONFIG_MX51) || defined(CONFIG_MX53) /* Handshake with IPU when certain clock rates are changed. */ reg = __raw_readl(&mxc_ccm->ccdr); reg &= ~MXC_CCM_CCDR_IPU_HS_MASK; @@ -185,13 +185,13 @@ static int clk_ipu_enable(struct clk *clk) static void clk_ipu_disable(struct clk *clk) { -#if defined(CONFIG_MX51) || defined(CONFIG_MX53) u32 reg; reg = __raw_readl(clk->enable_reg); reg &= ~(MXC_CCM_CCGR_CG_MASK << clk->enable_shift); __raw_writel(reg, clk->enable_reg); +#if defined(CONFIG_MX51) || defined(CONFIG_MX53) /* * No handshake with IPU whe dividers are changed * as its not enabled. @@ -211,9 +211,15 @@ static void clk_ipu_disable(struct clk *clk) static struct clk ipu_clk = { .name = "ipu_clk", .rate = CONFIG_IPUV3_CLK, +#if defined(CONFIG_MX51) || defined(CONFIG_MX53) .enable_reg = (u32 *)(CCM_BASE_ADDR + offsetof(struct mxc_ccm_reg, CCGR5)), - .enable_shift = MXC_CCM_CCGR5_CG5_OFFSET, + .enable_shift = MXC_CCM_CCGR5_IPU_OFFSET, +#else + .enable_reg = (u32 *)(CCM_BASE_ADDR + + offsetof(struct mxc_ccm_reg, CCGR3)), + .enable_shift = MXC_CCM_CCGR3_IPU1_IPU_DI0_OFFSET, +#endif .enable = clk_ipu_enable, .disable = clk_ipu_disable, .usecount = 0, diff --git a/drivers/video/mxc_ipuv3_fb.c b/drivers/video/mxc_ipuv3_fb.c index c38e22de1f..47b336e7aa 100644 --- a/drivers/video/mxc_ipuv3_fb.c +++ b/drivers/video/mxc_ipuv3_fb.c @@ -38,6 +38,7 @@ #include "videomodes.h" #include "ipu.h" #include "mxcfb.h" +#include "ipu_regs.h" static int mxcfb_map_video_memory(struct fb_info *fbi); static int mxcfb_unmap_video_memory(struct fb_info *fbi); @@ -576,6 +577,25 @@ err0: return ret; } +void ipuv3_fb_shutdown(void) +{ + int i; + struct ipu_stat *stat = (struct ipu_stat *)IPU_STAT; + + for (i = 0; i < ARRAY_SIZE(mxcfb_info); i++) { + struct fb_info *fbi = mxcfb_info[i]; + if (fbi) { + struct mxcfb_info *mxc_fbi = fbi->par; + ipu_disable_channel(mxc_fbi->ipu_ch); + ipu_uninit_channel(mxc_fbi->ipu_ch); + } + } + for (i = 0; i < ARRAY_SIZE(stat->int_stat); i++) { + __raw_writel(__raw_readl(&stat->int_stat[i]), + &stat->int_stat[i]); + } +} + void *video_hw_init(void) { int ret; |