From 6011dabd0ae0c01991e4ccd85a15bb2225b7e8bd Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 8 Nov 2013 11:18:43 +0000 Subject: pcnet: code style cleanup Fix up the code to match Documentation/CodingStyle. This is mostly removing extraneous spaces. No functional change is intended. Signed-off-by: Paul Burton --- drivers/net/pcnet.c | 248 ++++++++++++++++++++++++++-------------------------- 1 file changed, 123 insertions(+), 125 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pcnet.c b/drivers/net/pcnet.c index 283cb48..a30a0bc 100644 --- a/drivers/net/pcnet.c +++ b/drivers/net/pcnet.c @@ -89,39 +89,39 @@ static pcnet_priv_t *lp; #define PCNET_RESET 0x14 #define PCNET_BDP 0x16 -static u16 pcnet_read_csr (struct eth_device *dev, int index) +static u16 pcnet_read_csr(struct eth_device *dev, int index) { - outw (index, dev->iobase + PCNET_RAP); - return inw (dev->iobase + PCNET_RDP); + outw(index, dev->iobase + PCNET_RAP); + return inw(dev->iobase + PCNET_RDP); } -static void pcnet_write_csr (struct eth_device *dev, int index, u16 val) +static void pcnet_write_csr(struct eth_device *dev, int index, u16 val) { - outw (index, dev->iobase + PCNET_RAP); - outw (val, dev->iobase + PCNET_RDP); + outw(index, dev->iobase + PCNET_RAP); + outw(val, dev->iobase + PCNET_RDP); } -static u16 pcnet_read_bcr (struct eth_device *dev, int index) +static u16 pcnet_read_bcr(struct eth_device *dev, int index) { - outw (index, dev->iobase + PCNET_RAP); - return inw (dev->iobase + PCNET_BDP); + outw(index, dev->iobase + PCNET_RAP); + return inw(dev->iobase + PCNET_BDP); } -static void pcnet_write_bcr (struct eth_device *dev, int index, u16 val) +static void pcnet_write_bcr(struct eth_device *dev, int index, u16 val) { - outw (index, dev->iobase + PCNET_RAP); - outw (val, dev->iobase + PCNET_BDP); + outw(index, dev->iobase + PCNET_RAP); + outw(val, dev->iobase + PCNET_BDP); } -static void pcnet_reset (struct eth_device *dev) +static void pcnet_reset(struct eth_device *dev) { - inw (dev->iobase + PCNET_RESET); + inw(dev->iobase + PCNET_RESET); } -static int pcnet_check (struct eth_device *dev) +static int pcnet_check(struct eth_device *dev) { - outw (88, dev->iobase + PCNET_RAP); - return (inw (dev->iobase + PCNET_RAP) == 88); + outw(88, dev->iobase + PCNET_RAP); + return inw(dev->iobase + PCNET_RAP) == 88; } static int pcnet_init (struct eth_device *dev, bd_t * bis); @@ -139,63 +139,64 @@ static struct pci_device_id supported[] = { }; -int pcnet_initialize (bd_t * bis) +int pcnet_initialize(bd_t *bis) { pci_dev_t devbusfn; struct eth_device *dev; u16 command, status; int dev_nr = 0; - PCNET_DEBUG1 ("\npcnet_initialize...\n"); + PCNET_DEBUG1("\npcnet_initialize...\n"); for (dev_nr = 0;; dev_nr++) { /* * Find the PCnet PCI device(s). */ - if ((devbusfn = pci_find_devices (supported, dev_nr)) < 0) { + devbusfn = pci_find_devices(supported, dev_nr); + if (devbusfn < 0) break; - } /* * Allocate and pre-fill the device structure. */ - dev = (struct eth_device *) malloc (sizeof *dev); + dev = (struct eth_device *)malloc(sizeof(*dev)); if (!dev) { printf("pcnet: Can not allocate memory\n"); break; } memset(dev, 0, sizeof(*dev)); - dev->priv = (void *) devbusfn; - sprintf (dev->name, "pcnet#%d", dev_nr); + dev->priv = (void *)devbusfn; + sprintf(dev->name, "pcnet#%d", dev_nr); /* * Setup the PCI device. */ - pci_read_config_dword (devbusfn, PCI_BASE_ADDRESS_0, - (unsigned int *) &dev->iobase); - dev->iobase=pci_io_to_phys (devbusfn, dev->iobase); + pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_0, + (unsigned int *)&dev->iobase); + dev->iobase = pci_io_to_phys(devbusfn, dev->iobase); dev->iobase &= ~0xf; - PCNET_DEBUG1 ("%s: devbusfn=0x%x iobase=0x%x: ", - dev->name, devbusfn, dev->iobase); + PCNET_DEBUG1("%s: devbusfn=0x%x iobase=0x%x: ", + dev->name, devbusfn, dev->iobase); command = PCI_COMMAND_IO | PCI_COMMAND_MASTER; - pci_write_config_word (devbusfn, PCI_COMMAND, command); - pci_read_config_word (devbusfn, PCI_COMMAND, &status); + pci_write_config_word(devbusfn, PCI_COMMAND, command); + pci_read_config_word(devbusfn, PCI_COMMAND, &status); if ((status & command) != command) { - printf ("%s: Couldn't enable IO access or Bus Mastering\n", dev->name); - free (dev); + printf("%s: Couldn't enable IO access or Bus Mastering\n", + dev->name); + free(dev); continue; } - pci_write_config_byte (devbusfn, PCI_LATENCY_TIMER, 0x40); + pci_write_config_byte(devbusfn, PCI_LATENCY_TIMER, 0x40); /* * Probe the PCnet chip. */ - if (pcnet_probe (dev, bis, dev_nr) < 0) { - free (dev); + if (pcnet_probe(dev, bis, dev_nr) < 0) { + free(dev); continue; } @@ -207,15 +208,15 @@ int pcnet_initialize (bd_t * bis) dev->send = pcnet_send; dev->recv = pcnet_recv; - eth_register (dev); + eth_register(dev); } - udelay (10 * 1000); + udelay(10 * 1000); return dev_nr; } -static int pcnet_probe (struct eth_device *dev, bd_t * bis, int dev_nr) +static int pcnet_probe(struct eth_device *dev, bd_t *bis, int dev_nr) { int chip_version; char *chipname; @@ -225,17 +226,17 @@ static int pcnet_probe (struct eth_device *dev, bd_t * bis, int dev_nr) #endif /* Reset the PCnet controller */ - pcnet_reset (dev); + pcnet_reset(dev); /* Check if register access is working */ - if (pcnet_read_csr (dev, 0) != 4 || !pcnet_check (dev)) { - printf ("%s: CSR register access check failed\n", dev->name); + if (pcnet_read_csr(dev, 0) != 4 || !pcnet_check(dev)) { + printf("%s: CSR register access check failed\n", dev->name); return -1; } /* Identify the chip */ chip_version = - pcnet_read_csr (dev, 88) | (pcnet_read_csr (dev, 89) << 16); + pcnet_read_csr(dev, 88) | (pcnet_read_csr(dev, 89) << 16); if ((chip_version & 0xfff) != 0x003) return -1; chip_version = (chip_version >> 12) & 0xffff; @@ -254,12 +255,12 @@ static int pcnet_probe (struct eth_device *dev, bd_t * bis, int dev_nr) break; #endif default: - printf ("%s: PCnet version %#x not supported\n", - dev->name, chip_version); + printf("%s: PCnet version %#x not supported\n", + dev->name, chip_version); return -1; } - PCNET_DEBUG1 ("AMD %s\n", chipname); + PCNET_DEBUG1("AMD %s\n", chipname); #ifdef PCNET_HAS_PROM /* @@ -270,7 +271,7 @@ static int pcnet_probe (struct eth_device *dev, bd_t * bis, int dev_nr) for (i = 0; i < 3; i++) { unsigned int val; - val = pcnet_read_csr (dev, i + 12) & 0x0ffff; + val = pcnet_read_csr(dev, i + 12) & 0x0ffff; /* There may be endianness issues here. */ dev->enetaddr[2 * i] = val & 0x0ff; dev->enetaddr[2 * i + 1] = (val >> 8) & 0x0ff; @@ -280,35 +281,35 @@ static int pcnet_probe (struct eth_device *dev, bd_t * bis, int dev_nr) return 0; } -static int pcnet_init (struct eth_device *dev, bd_t * bis) +static int pcnet_init(struct eth_device *dev, bd_t *bis) { int i, val; u32 addr; - PCNET_DEBUG1 ("%s: pcnet_init...\n", dev->name); + PCNET_DEBUG1("%s: pcnet_init...\n", dev->name); /* Switch pcnet to 32bit mode */ - pcnet_write_bcr (dev, 20, 2); + pcnet_write_bcr(dev, 20, 2); #ifdef CONFIG_PN62 /* Setup LED registers */ - val = pcnet_read_bcr (dev, 2) | 0x1000; - pcnet_write_bcr (dev, 2, val); /* enable LEDPE */ - pcnet_write_bcr (dev, 4, 0x5080); /* 100MBit */ - pcnet_write_bcr (dev, 5, 0x40c0); /* LNKSE */ - pcnet_write_bcr (dev, 6, 0x4090); /* TX Activity */ - pcnet_write_bcr (dev, 7, 0x4084); /* RX Activity */ + val = pcnet_read_bcr(dev, 2) | 0x1000; + pcnet_write_bcr(dev, 2, val); /* enable LEDPE */ + pcnet_write_bcr(dev, 4, 0x5080); /* 100MBit */ + pcnet_write_bcr(dev, 5, 0x40c0); /* LNKSE */ + pcnet_write_bcr(dev, 6, 0x4090); /* TX Activity */ + pcnet_write_bcr(dev, 7, 0x4084); /* RX Activity */ #endif /* Set/reset autoselect bit */ - val = pcnet_read_bcr (dev, 2) & ~2; + val = pcnet_read_bcr(dev, 2) & ~2; val |= 2; - pcnet_write_bcr (dev, 2, val); + pcnet_write_bcr(dev, 2, val); /* Enable auto negotiate, setup, disable fd */ - val = pcnet_read_bcr (dev, 32) & ~0x98; + val = pcnet_read_bcr(dev, 32) & ~0x98; val |= 0x20; - pcnet_write_bcr (dev, 32, val); + pcnet_write_bcr(dev, 32, val); /* * We only maintain one structure because the drivers will never @@ -316,12 +317,12 @@ static int pcnet_init (struct eth_device *dev, bd_t * bis) * must be aligned on 16-byte boundaries. */ if (lp == NULL) { - addr = (u32) malloc (sizeof (pcnet_priv_t) + 0x10); + addr = (u32)malloc(sizeof(pcnet_priv_t) + 0x10); addr = (addr + 0xf) & ~0xf; - lp = (pcnet_priv_t *) addr; + lp = (pcnet_priv_t *)addr; } - lp->init_block.mode = cpu_to_le16 (0x0000); + lp->init_block.mode = cpu_to_le16(0x0000); lp->init_block.filter[0] = 0x00000000; lp->init_block.filter[1] = 0x00000000; @@ -330,9 +331,9 @@ static int pcnet_init (struct eth_device *dev, bd_t * bis) */ lp->cur_rx = 0; for (i = 0; i < RX_RING_SIZE; i++) { - lp->rx_ring[i].base = PCI_TO_MEM_LE (dev, lp->rx_buf[i]); - lp->rx_ring[i].buf_length = cpu_to_le16 (-PKT_BUF_SZ); - lp->rx_ring[i].status = cpu_to_le16 (0x8000); + lp->rx_ring[i].base = PCI_TO_MEM_LE(dev, lp->rx_buf[i]); + lp->rx_ring[i].buf_length = cpu_to_le16(-PKT_BUF_SZ); + lp->rx_ring[i].status = cpu_to_le16(0x8000); PCNET_DEBUG1 ("Rx%d: base=0x%x buf_length=0x%hx status=0x%hx\n", i, lp->rx_ring[i].base, lp->rx_ring[i].buf_length, @@ -352,48 +353,48 @@ static int pcnet_init (struct eth_device *dev, bd_t * bis) /* * Setup Init Block. */ - PCNET_DEBUG1 ("Init block at 0x%p: MAC", &lp->init_block); + PCNET_DEBUG1("Init block at 0x%p: MAC", &lp->init_block); for (i = 0; i < 6; i++) { lp->init_block.phys_addr[i] = dev->enetaddr[i]; - PCNET_DEBUG1 (" %02x", lp->init_block.phys_addr[i]); + PCNET_DEBUG1(" %02x", lp->init_block.phys_addr[i]); } - lp->init_block.tlen_rlen = cpu_to_le16 (TX_RING_LEN_BITS | - RX_RING_LEN_BITS); - lp->init_block.rx_ring = PCI_TO_MEM_LE (dev, lp->rx_ring); - lp->init_block.tx_ring = PCI_TO_MEM_LE (dev, lp->tx_ring); + lp->init_block.tlen_rlen = cpu_to_le16(TX_RING_LEN_BITS | + RX_RING_LEN_BITS); + lp->init_block.rx_ring = PCI_TO_MEM_LE(dev, lp->rx_ring); + lp->init_block.tx_ring = PCI_TO_MEM_LE(dev, lp->tx_ring); - PCNET_DEBUG1 ("\ntlen_rlen=0x%x rx_ring=0x%x tx_ring=0x%x\n", - lp->init_block.tlen_rlen, - lp->init_block.rx_ring, lp->init_block.tx_ring); + PCNET_DEBUG1("\ntlen_rlen=0x%x rx_ring=0x%x tx_ring=0x%x\n", + lp->init_block.tlen_rlen, + lp->init_block.rx_ring, lp->init_block.tx_ring); /* * Tell the controller where the Init Block is located. */ - addr = PCI_TO_MEM (dev, &lp->init_block); - pcnet_write_csr (dev, 1, addr & 0xffff); - pcnet_write_csr (dev, 2, (addr >> 16) & 0xffff); + addr = PCI_TO_MEM(dev, &lp->init_block); + pcnet_write_csr(dev, 1, addr & 0xffff); + pcnet_write_csr(dev, 2, (addr >> 16) & 0xffff); - pcnet_write_csr (dev, 4, 0x0915); - pcnet_write_csr (dev, 0, 0x0001); /* start */ + pcnet_write_csr(dev, 4, 0x0915); + pcnet_write_csr(dev, 0, 0x0001); /* start */ /* Wait for Init Done bit */ for (i = 10000; i > 0; i--) { - if (pcnet_read_csr (dev, 0) & 0x0100) + if (pcnet_read_csr(dev, 0) & 0x0100) break; - udelay (10); + udelay(10); } if (i <= 0) { - printf ("%s: TIMEOUT: controller init failed\n", dev->name); - pcnet_reset (dev); + printf("%s: TIMEOUT: controller init failed\n", dev->name); + pcnet_reset(dev); return -1; } /* * Finally start network controller operation. */ - pcnet_write_csr (dev, 0, 0x0002); + pcnet_write_csr(dev, 0, 0x0002); return 0; } @@ -403,20 +404,20 @@ static int pcnet_send(struct eth_device *dev, void *packet, int pkt_len) int i, status; struct pcnet_tx_head *entry = &lp->tx_ring[lp->cur_tx]; - PCNET_DEBUG2 ("Tx%d: %d bytes from 0x%p ", lp->cur_tx, pkt_len, - packet); + PCNET_DEBUG2("Tx%d: %d bytes from 0x%p ", lp->cur_tx, pkt_len, + packet); /* Wait for completion by testing the OWN bit */ for (i = 1000; i > 0; i--) { - status = le16_to_cpu (entry->status); + status = le16_to_cpu(entry->status); if ((status & 0x8000) == 0) break; - udelay (100); - PCNET_DEBUG2 ("."); + udelay(100); + PCNET_DEBUG2("."); } if (i <= 0) { - printf ("%s: TIMEOUT: Tx%d failed (status = 0x%x)\n", - dev->name, lp->cur_tx, status); + printf("%s: TIMEOUT: Tx%d failed (status = 0x%x)\n", + dev->name, lp->cur_tx, status); pkt_len = 0; goto failure; } @@ -426,19 +427,19 @@ static int pcnet_send(struct eth_device *dev, void *packet, int pkt_len) * set the status with the "ownership" bits last. */ status = 0x8300; - entry->length = le16_to_cpu (-pkt_len); + entry->length = le16_to_cpu(-pkt_len); entry->misc = 0x00000000; - entry->base = PCI_TO_MEM_LE (dev, packet); - entry->status = le16_to_cpu (status); + entry->base = PCI_TO_MEM_LE(dev, packet); + entry->status = le16_to_cpu(status); /* Trigger an immediate send poll. */ - pcnet_write_csr (dev, 0, 0x0008); + pcnet_write_csr(dev, 0, 0x0008); failure: if (++lp->cur_tx >= TX_RING_SIZE) lp->cur_tx = 0; - PCNET_DEBUG2 ("done\n"); + PCNET_DEBUG2("done\n"); return pkt_len; } @@ -453,40 +454,38 @@ static int pcnet_recv (struct eth_device *dev) /* * If we own the next entry, it's a new packet. Send it up. */ - if (((status = le16_to_cpu (entry->status)) & 0x8000) != 0) { + status = le16_to_cpu(entry->status); + if ((status & 0x8000) != 0) break; - } status >>= 8; if (status != 0x03) { /* There was an error. */ - - printf ("%s: Rx%d", dev->name, lp->cur_rx); - PCNET_DEBUG1 (" (status=0x%x)", status); + printf("%s: Rx%d", dev->name, lp->cur_rx); + PCNET_DEBUG1(" (status=0x%x)", status); if (status & 0x20) - printf (" Frame"); + printf(" Frame"); if (status & 0x10) - printf (" Overflow"); + printf(" Overflow"); if (status & 0x08) - printf (" CRC"); + printf(" CRC"); if (status & 0x04) - printf (" Fifo"); - printf (" Error\n"); - entry->status &= le16_to_cpu (0x03ff); + printf(" Fifo"); + printf(" Error\n"); + entry->status &= le16_to_cpu(0x03ff); } else { - - pkt_len = - (le32_to_cpu (entry->msg_length) & 0xfff) - 4; + pkt_len = (le32_to_cpu(entry->msg_length) & 0xfff) - 4; if (pkt_len < 60) { - printf ("%s: Rx%d: invalid packet length %d\n", dev->name, lp->cur_rx, pkt_len); + printf("%s: Rx%d: invalid packet length %d\n", + dev->name, lp->cur_rx, pkt_len); } else { - NetReceive (lp->rx_buf[lp->cur_rx], pkt_len); - PCNET_DEBUG2 ("Rx%d: %d bytes from 0x%p\n", - lp->cur_rx, pkt_len, - lp->rx_buf[lp->cur_rx]); + NetReceive(lp->rx_buf[lp->cur_rx], pkt_len); + PCNET_DEBUG2("Rx%d: %d bytes from 0x%p\n", + lp->cur_rx, pkt_len, + lp->rx_buf[lp->cur_rx]); } } - entry->status |= cpu_to_le16 (0x8000); + entry->status |= cpu_to_le16(0x8000); if (++lp->cur_rx >= RX_RING_SIZE) lp->cur_rx = 0; @@ -494,22 +493,21 @@ static int pcnet_recv (struct eth_device *dev) return pkt_len; } -static void pcnet_halt (struct eth_device *dev) +static void pcnet_halt(struct eth_device *dev) { int i; - PCNET_DEBUG1 ("%s: pcnet_halt...\n", dev->name); + PCNET_DEBUG1("%s: pcnet_halt...\n", dev->name); /* Reset the PCnet controller */ - pcnet_reset (dev); + pcnet_reset(dev); /* Wait for Stop bit */ for (i = 1000; i > 0; i--) { - if (pcnet_read_csr (dev, 0) & 0x4) + if (pcnet_read_csr(dev, 0) & 0x4) break; - udelay (10); - } - if (i <= 0) { - printf ("%s: TIMEOUT: controller reset failed\n", dev->name); + udelay(10); } + if (i <= 0) + printf("%s: TIMEOUT: controller reset failed\n", dev->name); } -- cgit v1.1 From a95400411b0938b1ef6d87090f4b22026c56e55b Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 8 Nov 2013 11:18:44 +0000 Subject: pcnet: s/le16_to_cpu/cpu_to_le16/ in pcnet_send This should cause no change to the generated code, but is semantically correct. Signed-off-by: Paul Burton --- drivers/net/pcnet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pcnet.c b/drivers/net/pcnet.c index a30a0bc..843a6fc 100644 --- a/drivers/net/pcnet.c +++ b/drivers/net/pcnet.c @@ -427,10 +427,10 @@ static int pcnet_send(struct eth_device *dev, void *packet, int pkt_len) * set the status with the "ownership" bits last. */ status = 0x8300; - entry->length = le16_to_cpu(-pkt_len); + entry->length = cpu_to_le16(-pkt_len); entry->misc = 0x00000000; entry->base = PCI_TO_MEM_LE(dev, packet); - entry->status = le16_to_cpu(status); + entry->status = cpu_to_le16(status); /* Trigger an immediate send poll. */ pcnet_write_csr(dev, 0, 0x0008); -- cgit v1.1 From f3ac866c78f7f0d91eb345967350830d46c3a563 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 8 Nov 2013 11:18:45 +0000 Subject: pcnet: add cache flushing & invalidation Ensure that the view of memory from the CPU & the ethernet controller is coherent at the various points where they exchange data. This prevents stale data from being transmitted or received, and prevents the driver from getting stuck waiting for the ethernet controller to update descriptors when in reality it has but the old values are being read from cache. Signed-off-by: Paul Burton --- drivers/net/pcnet.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/net/pcnet.c b/drivers/net/pcnet.c index 843a6fc..7b87660 100644 --- a/drivers/net/pcnet.c +++ b/drivers/net/pcnet.c @@ -364,6 +364,7 @@ static int pcnet_init(struct eth_device *dev, bd_t *bis) RX_RING_LEN_BITS); lp->init_block.rx_ring = PCI_TO_MEM_LE(dev, lp->rx_ring); lp->init_block.tx_ring = PCI_TO_MEM_LE(dev, lp->tx_ring); + flush_dcache_range((unsigned long)lp, (unsigned long)&lp->rx_buf); PCNET_DEBUG1("\ntlen_rlen=0x%x rx_ring=0x%x tx_ring=0x%x\n", lp->init_block.tlen_rlen, @@ -407,8 +408,13 @@ static int pcnet_send(struct eth_device *dev, void *packet, int pkt_len) PCNET_DEBUG2("Tx%d: %d bytes from 0x%p ", lp->cur_tx, pkt_len, packet); + flush_dcache_range((unsigned long)packet, + (unsigned long)packet + pkt_len); + /* Wait for completion by testing the OWN bit */ for (i = 1000; i > 0; i--) { + invalidate_dcache_range((unsigned long)entry, + (unsigned long)entry + sizeof(*entry)); status = le16_to_cpu(entry->status); if ((status & 0x8000) == 0) break; @@ -431,6 +437,8 @@ static int pcnet_send(struct eth_device *dev, void *packet, int pkt_len) entry->misc = 0x00000000; entry->base = PCI_TO_MEM_LE(dev, packet); entry->status = cpu_to_le16(status); + flush_dcache_range((unsigned long)entry, + (unsigned long)entry + sizeof(*entry)); /* Trigger an immediate send poll. */ pcnet_write_csr(dev, 0, 0x0008); @@ -451,6 +459,8 @@ static int pcnet_recv (struct eth_device *dev) while (1) { entry = &lp->rx_ring[lp->cur_rx]; + invalidate_dcache_range((unsigned long)entry, + (unsigned long)entry + sizeof(*entry)); /* * If we own the next entry, it's a new packet. Send it up. */ @@ -479,6 +489,10 @@ static int pcnet_recv (struct eth_device *dev) printf("%s: Rx%d: invalid packet length %d\n", dev->name, lp->cur_rx, pkt_len); } else { + invalidate_dcache_range( + (unsigned long)lp->rx_buf[lp->cur_rx], + (unsigned long)lp->rx_buf[lp->cur_rx] + + pkt_len); NetReceive(lp->rx_buf[lp->cur_rx], pkt_len); PCNET_DEBUG2("Rx%d: %d bytes from 0x%p\n", lp->cur_rx, pkt_len, @@ -486,6 +500,8 @@ static int pcnet_recv (struct eth_device *dev) } } entry->status |= cpu_to_le16(0x8000); + flush_dcache_range((unsigned long)entry, + (unsigned long)entry + sizeof(*entry)); if (++lp->cur_rx >= RX_RING_SIZE) lp->cur_rx = 0; -- cgit v1.1 From 62715a2c57c01630af8198ed108874def5a99cf7 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 8 Nov 2013 11:18:46 +0000 Subject: pcnet: enable the NOUFLO feature On relatively slow boards (such as the MIPS Malta with an FPGA core card) it can be extremely common for transmits to underflow - to the point where it appears they simply do not work at all. Setting the NOUFLO bit causes the ethernet controller to not begin transmission on the wire until a transmit start point is reached. Setting that transmit start point to the full packet will cause the controller to only transmit the packet once it has buffered it entirely thus preventing any transmit underflows from occuring and allowing the controller to function on slower boards. Signed-off-by: Paul Burton --- drivers/net/pcnet.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/net/pcnet.c b/drivers/net/pcnet.c index 7b87660..5b248be 100644 --- a/drivers/net/pcnet.c +++ b/drivers/net/pcnet.c @@ -312,6 +312,21 @@ static int pcnet_init(struct eth_device *dev, bd_t *bis) pcnet_write_bcr(dev, 32, val); /* + * Enable NOUFLO on supported controllers, with the transmit + * start point set to the full packet. This will cause entire + * packets to be buffered by the ethernet controller before + * transmission, eliminating underflows which are common on + * slower devices. Controllers which do not support NOUFLO will + * simply be left with a larger transmit FIFO threshold. + */ + val = pcnet_read_bcr(dev, 18); + val |= 1 << 11; + pcnet_write_bcr(dev, 18, val); + val = pcnet_read_csr(dev, 80); + val |= 0x3 << 10; + pcnet_write_csr(dev, 80, val); + + /* * We only maintain one structure because the drivers will never * be used concurrently. In 32bit mode the RX and TX ring entries * must be aligned on 16-byte boundaries. -- cgit v1.1 From baf37f06c5cc51d2b9d71a2c83d5d92de60203a9 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 8 Nov 2013 11:18:50 +0000 Subject: malta: support for coreFPGA6 boards This patch adds support for running on Malta boards using coreFPGA6 core cards, including support for the msc01 system controller used with them. The system controller is detected at runtime allowing one U-boot binary to run on a Malta with either. Due to the PCI I/O base differing between Maltas using gt64120 & msc01 system controllers, the UART setup is modified slightly. A second UART is added so that there is one pointing at the correct address for each system controller. The Malta board then defines its own default_serial_console function to select the correct one at runtime. The incorrect UART will simply not function. Tested on: - A coreFPGA6 Malta running interAptiv and proAptiv bitstreams, both with and without an L2 cache. - QEMU. Signed-off-by: Paul Burton --- drivers/pci/Makefile | 1 + drivers/pci/pci_msc01.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 drivers/pci/pci_msc01.c (limited to 'drivers') diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 99d51a6..6182a59 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_FSL_PCI_INIT) += fsl_pci_init.o obj-$(CONFIG_PCI) += pci.o pci_auto.o obj-$(CONFIG_PCI_INDIRECT_BRIDGE) += pci_indirect.o obj-$(CONFIG_PCI_GT64120) += pci_gt64120.o +obj-$(CONFIG_PCI_MSC01) += pci_msc01.o obj-$(CONFIG_FTPCI100) += pci_ftpci100.o obj-$(CONFIG_IXP_PCI) += pci_ixp.o obj-$(CONFIG_SH4_PCI) += pci_sh4.o diff --git a/drivers/pci/pci_msc01.c b/drivers/pci/pci_msc01.c new file mode 100644 index 0000000..284ffa0 --- /dev/null +++ b/drivers/pci/pci_msc01.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2013 Imagination Technologies + * Author: Paul Burton + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#define PCI_ACCESS_READ 0 +#define PCI_ACCESS_WRITE 1 + +struct msc01_pci_controller { + struct pci_controller hose; + void *base; +}; + +static inline struct msc01_pci_controller * +hose_to_msc01(struct pci_controller *hose) +{ + return container_of(hose, struct msc01_pci_controller, hose); +} + +static int msc01_config_access(struct msc01_pci_controller *msc01, + unsigned char access_type, pci_dev_t bdf, + int where, u32 *data) +{ + const u32 aborts = MSC01_PCI_INTSTAT_MA_MSK | MSC01_PCI_INTSTAT_TA_MSK; + void *intstat = msc01->base + MSC01_PCI_INTSTAT_OFS; + void *cfgdata = msc01->base + MSC01_PCI_CFGDATA_OFS; + unsigned int bus = PCI_BUS(bdf); + unsigned int dev = PCI_DEV(bdf); + unsigned int devfn = PCI_DEV(bdf) << 3 | PCI_FUNC(bdf); + + /* clear abort status */ + __raw_writel(aborts, intstat); + + /* setup address */ + __raw_writel((bus << MSC01_PCI_CFGADDR_BNUM_SHF) | + (dev << MSC01_PCI_CFGADDR_DNUM_SHF) | + (devfn << MSC01_PCI_CFGADDR_FNUM_SHF) | + ((where / 4) << MSC01_PCI_CFGADDR_RNUM_SHF), + msc01->base + MSC01_PCI_CFGADDR_OFS); + + /* perform access */ + if (access_type == PCI_ACCESS_WRITE) + __raw_writel(*data, cfgdata); + else + *data = __raw_readl(cfgdata); + + /* check for aborts */ + if (__raw_readl(intstat) & aborts) { + /* clear abort status */ + __raw_writel(aborts, intstat); + return -1; + } + + return 0; +} + +static int msc01_read_config_dword(struct pci_controller *hose, pci_dev_t dev, + int where, u32 *value) +{ + struct msc01_pci_controller *msc01 = hose_to_msc01(hose); + + *value = 0xffffffff; + return msc01_config_access(msc01, PCI_ACCESS_READ, dev, where, value); +} + +static int msc01_write_config_dword(struct pci_controller *hose, pci_dev_t dev, + int where, u32 value) +{ + struct msc01_pci_controller *gt = hose_to_msc01(hose); + u32 data = value; + + return msc01_config_access(gt, PCI_ACCESS_WRITE, dev, where, &data); +} + +void msc01_pci_init(void *base, unsigned long sys_bus, unsigned long sys_phys, + unsigned long sys_size, unsigned long mem_bus, + unsigned long mem_phys, unsigned long mem_size, + unsigned long io_bus, unsigned long io_phys, + unsigned long io_size) +{ + static struct msc01_pci_controller global_msc01; + struct msc01_pci_controller *msc01; + struct pci_controller *hose; + + msc01 = &global_msc01; + msc01->base = base; + + hose = &msc01->hose; + + hose->first_busno = 0; + hose->last_busno = 0; + + /* System memory space */ + pci_set_region(&hose->regions[0], sys_bus, sys_phys, sys_size, + PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); + + /* PCI memory space */ + pci_set_region(&hose->regions[1], mem_bus, mem_phys, mem_size, + PCI_REGION_MEM); + + /* PCI I/O space */ + pci_set_region(&hose->regions[2], io_bus, io_phys, io_size, + PCI_REGION_IO); + + hose->region_count = 3; + + pci_set_ops(hose, + pci_hose_read_config_byte_via_dword, + pci_hose_read_config_word_via_dword, + msc01_read_config_dword, + pci_hose_write_config_byte_via_dword, + pci_hose_write_config_word_via_dword, + msc01_write_config_dword); + + pci_register_hose(hose); + hose->last_busno = pci_hose_scan(hose); +} -- cgit v1.1 From 3ced12a06baaf90039fa171688d33358b15613d1 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 8 Nov 2013 11:18:55 +0000 Subject: malta: enable RTC support This is actually required in order for a Linux kernel to boot successfully on a physical Malta board. Without enabling the RTC, a Malta Linux kernel will get stuck in its estimate_frequencies function on boot. Signed-off-by: Paul Burton --- drivers/rtc/mc146818.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/mc146818.c b/drivers/rtc/mc146818.c index 5f9d359..f7cf106 100644 --- a/drivers/rtc/mc146818.c +++ b/drivers/rtc/mc146818.c @@ -15,7 +15,7 @@ #include #include -#ifdef __I386__ +#if defined(__I386__) || defined(CONFIG_MALTA) #include #define in8(p) inb(p) #define out8(p, v) outb(v, p) -- cgit v1.1 From 649acfe149e8a534a17eab54004a51d69b5556ed Mon Sep 17 00:00:00 2001 From: Wolfgang Denk Date: Mon, 11 Nov 2013 20:12:19 +0100 Subject: MPC824x: remove obsolete "PN62" board The MPC824x processors have long reached EOL, and the PN62 board has not seen any board-specific updates for more than a decade. It is now causing build issues. Instead of wasting time on things nobody is interested in any more, we rather drop this board. Signed-off-by: Wolfgang Denk Cc: Wolfgang Grandegger cc: Tom Rini --- drivers/net/pcnet.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pcnet.c b/drivers/net/pcnet.c index 5b248be..71a3110 100644 --- a/drivers/net/pcnet.c +++ b/drivers/net/pcnet.c @@ -291,16 +291,6 @@ static int pcnet_init(struct eth_device *dev, bd_t *bis) /* Switch pcnet to 32bit mode */ pcnet_write_bcr(dev, 20, 2); -#ifdef CONFIG_PN62 - /* Setup LED registers */ - val = pcnet_read_bcr(dev, 2) | 0x1000; - pcnet_write_bcr(dev, 2, val); /* enable LEDPE */ - pcnet_write_bcr(dev, 4, 0x5080); /* 100MBit */ - pcnet_write_bcr(dev, 5, 0x40c0); /* LNKSE */ - pcnet_write_bcr(dev, 6, 0x4090); /* TX Activity */ - pcnet_write_bcr(dev, 7, 0x4084); /* RX Activity */ -#endif - /* Set/reset autoselect bit */ val = pcnet_read_bcr(dev, 2) & ~2; val |= 2; -- cgit v1.1 From 44376eff256da60625f99c1f3559c290f148fc1c Mon Sep 17 00:00:00 2001 From: Andre Heider Date: Sat, 9 Nov 2013 11:07:53 +0100 Subject: video: bcm2835: respect the pitch value Depending on the firmware's video options [1] the active SDTV or HDTV mode can yield a framebuffer with noncontiguous horizontal lines, giving a messed up display, for both, u-boot and the loaded kernel. Fix this by setting lcd_line_length to the pitch value of the configured framebuffer. [1] http://elinux.org/RPiconfig#Video_mode_options Signed-off-by: Andre Heider Cc: Stephen Warren Signed-off-by: Anatolij Gustschin Acked-by: Stephen Warren --- drivers/video/bcm2835.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/video/bcm2835.c b/drivers/video/bcm2835.c index 58a6163..1f18231 100644 --- a/drivers/video/bcm2835.c +++ b/drivers/video/bcm2835.c @@ -14,6 +14,8 @@ DECLARE_GLOBAL_DATA_PTR; /* Global variables that lcd.c expects to exist */ vidinfo_t panel_info; +static u32 bcm2835_pitch; + struct msg_query { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_physical_w_h physical_w_h; @@ -30,6 +32,7 @@ struct msg_setup { struct bcm2835_mbox_tag_virtual_offset virtual_offset; struct bcm2835_mbox_tag_overscan overscan; struct bcm2835_mbox_tag_allocate_buffer allocate_buffer; + struct bcm2835_mbox_tag_pitch pitch; u32 end_tag; }; @@ -80,6 +83,7 @@ void lcd_ctrl_init(void *lcdbase) msg_setup->overscan.body.req.right = 0; BCM2835_MBOX_INIT_TAG(&msg_setup->allocate_buffer, ALLOCATE_BUFFER); msg_setup->allocate_buffer.body.req.alignment = 0x100; + BCM2835_MBOX_INIT_TAG_NO_REQ(&msg_setup->pitch, GET_PITCH); ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_setup->hdr); if (ret) { @@ -90,6 +94,7 @@ void lcd_ctrl_init(void *lcdbase) w = msg_setup->physical_w_h.body.resp.width; h = msg_setup->physical_w_h.body.resp.height; + bcm2835_pitch = msg_setup->pitch.body.resp.pitch; debug("bcm2835: Final resolution is %d x %d\n", w, h); @@ -103,3 +108,9 @@ void lcd_ctrl_init(void *lcdbase) void lcd_enable(void) { } + +int lcd_get_size(int *line_length) +{ + *line_length = bcm2835_pitch; + return *line_length * panel_info.vl_row; +} -- cgit v1.1 From 54a759c880a11a6dd93704f0adba40139b595e87 Mon Sep 17 00:00:00 2001 From: Nikita Kiryanov Date: Wed, 16 Oct 2013 17:23:24 +0300 Subject: spi: omap3: remove semicolon from #define Remove unnecessary semicolon from #define SPI_WAIT_TIMEOUT Cc: Tom Rini Cc: Jagannadha Sutradharudu Teki Cc: Igor Grinberg Cc: Gerhard Sittig Signed-off-by: Nikita Kiryanov --- drivers/spi/omap3_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c index e80be8e..116276c 100644 --- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -21,7 +21,7 @@ #include "omap3_spi.h" #define WORD_LEN 8 -#define SPI_WAIT_TIMEOUT 3000000; +#define SPI_WAIT_TIMEOUT 3000000 static void spi_reset(struct omap3_spi_slave *ds) { -- cgit v1.1 From 5753d09b1064a669e3be8f27e0f1fd008b96934a Mon Sep 17 00:00:00 2001 From: Nikita Kiryanov Date: Wed, 16 Oct 2013 17:23:25 +0300 Subject: spi: omap3: add support for more word lengths Current implementation only supports 8 bit word lengths, even though omap3 can handle anything between 4 and 32. Update the spi interface to support changing the SPI word length, and implement it in omap3_spi driver to support the full range of possible word lengths. This implementation is backwards compatible by defaulting to the old behavior of 8 bit word lengths. Also, it required a change to the omap3_spi non static I/O functions, but since they are not used anywhere else, no collateral changes are required. Cc: Tom Rini Cc: Jagannadha Sutradharudu Teki Cc: Igor Grinberg Signed-off-by: Nikita Kiryanov --- drivers/spi/omap3_spi.c | 69 +++++++++++++++++++++++++++++++++++-------------- drivers/spi/omap3_spi.h | 8 +++--- drivers/spi/spi.c | 13 ++++++++++ 3 files changed, 66 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c index 116276c..a3ad056 100644 --- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -20,7 +20,6 @@ #include #include "omap3_spi.h" -#define WORD_LEN 8 #define SPI_WAIT_TIMEOUT 3000000 static void spi_reset(struct omap3_spi_slave *ds) @@ -185,7 +184,7 @@ int spi_claim_bus(struct spi_slave *slave) /* wordlength */ conf &= ~OMAP3_MCSPI_CHCONF_WL_MASK; - conf |= (WORD_LEN - 1) << 7; + conf |= (ds->slave.wordlen - 1) << 7; /* set chipselect polarity; manage with FORCE */ if (!(ds->mode & SPI_CS_HIGH)) @@ -223,7 +222,7 @@ void spi_release_bus(struct spi_slave *slave) spi_reset(ds); } -int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp, +int omap3_spi_write(struct spi_slave *slave, unsigned int len, const void *txp, unsigned long flags) { struct omap3_spi_slave *ds = to_omap3_spi(slave); @@ -234,7 +233,8 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp, /* Enable the channel */ omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN); - chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK; + chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK); + chconf |= (ds->slave.wordlen - 1) << 7; chconf |= OMAP3_MCSPI_CHCONF_TRM_TX_ONLY; chconf |= OMAP3_MCSPI_CHCONF_FORCE; omap3_spi_write_chconf(ds,chconf); @@ -250,7 +250,13 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp, } } /* Write the data */ - writel(txp[i], &ds->regs->channel[ds->slave.cs].tx); + unsigned int *tx = &ds->regs->channel[ds->slave.cs].tx; + if (ds->slave.wordlen > 16) + writel(((u32 *)txp)[i], tx); + else if (ds->slave.wordlen > 8) + writel(((u16 *)txp)[i], tx); + else + writel(((u8 *)txp)[i], tx); } /* wait to finish of transfer */ @@ -268,7 +274,7 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp, return 0; } -int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp, +int omap3_spi_read(struct spi_slave *slave, unsigned int len, void *rxp, unsigned long flags) { struct omap3_spi_slave *ds = to_omap3_spi(slave); @@ -279,7 +285,8 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp, /* Enable the channel */ omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN); - chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK; + chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK); + chconf |= (ds->slave.wordlen - 1) << 7; chconf |= OMAP3_MCSPI_CHCONF_TRM_RX_ONLY; chconf |= OMAP3_MCSPI_CHCONF_FORCE; omap3_spi_write_chconf(ds,chconf); @@ -302,7 +309,13 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp, omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS); /* Read the data */ - rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx); + unsigned int *rx = &ds->regs->channel[ds->slave.cs].rx; + if (ds->slave.wordlen > 16) + ((u32 *)rxp)[i] = readl(rx); + else if (ds->slave.wordlen > 8) + ((u16 *)rxp)[i] = (u16)readl(rx); + else + ((u8 *)rxp)[i] = (u8)readl(rx); } if (flags & SPI_XFER_END) { @@ -314,8 +327,8 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp, } /*McSPI Transmit Receive Mode*/ -int omap3_spi_txrx(struct spi_slave *slave, - unsigned int len, const u8 *txp, u8 *rxp, unsigned long flags) +int omap3_spi_txrx(struct spi_slave *slave, unsigned int len, + const void *txp, void *rxp, unsigned long flags) { struct omap3_spi_slave *ds = to_omap3_spi(slave); int timeout = SPI_WAIT_TIMEOUT; @@ -327,7 +340,8 @@ int omap3_spi_txrx(struct spi_slave *slave, omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN); /*set TRANSMIT-RECEIVE Mode*/ - chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK; + chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK); + chconf |= (ds->slave.wordlen - 1) << 7; chconf |= OMAP3_MCSPI_CHCONF_FORCE; omap3_spi_write_chconf(ds,chconf); @@ -344,7 +358,13 @@ int omap3_spi_txrx(struct spi_slave *slave, } } /* Write the data */ - writel(txp[i], &ds->regs->channel[ds->slave.cs].tx); + unsigned int *tx = &ds->regs->channel[ds->slave.cs].tx; + if (ds->slave.wordlen > 16) + writel(((u32 *)txp)[i], tx); + else if (ds->slave.wordlen > 8) + writel(((u16 *)txp)[i], tx); + else + writel(((u8 *)txp)[i], tx); /*Read: wait for RX containing data (RXS == 1)*/ while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) & @@ -356,7 +376,13 @@ int omap3_spi_txrx(struct spi_slave *slave, } } /* Read the data */ - rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx); + unsigned int *rx = &ds->regs->channel[ds->slave.cs].rx; + if (ds->slave.wordlen > 16) + ((u32 *)rxp)[i] = readl(rx); + else if (ds->slave.wordlen > 8) + ((u16 *)rxp)[i] = (u16)readl(rx); + else + ((u8 *)rxp)[i] = (u8)readl(rx); } /* Disable the channel */ omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS); @@ -375,14 +401,17 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, { struct omap3_spi_slave *ds = to_omap3_spi(slave); unsigned int len; - const u8 *txp = dout; - u8 *rxp = din; int ret = -1; - if (bitlen % 8) + if (ds->slave.wordlen < 4 || ds->slave.wordlen > 32) { + printf("omap3_spi: invalid wordlen %d\n", ds->slave.wordlen); + return -1; + } + + if (bitlen % ds->slave.wordlen) return -1; - len = bitlen / 8; + len = bitlen / ds->slave.wordlen; if (bitlen == 0) { /* only change CS */ int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf); @@ -400,11 +429,11 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, ret = 0; } else { if (dout != NULL && din != NULL) - ret = omap3_spi_txrx(slave, len, txp, rxp, flags); + ret = omap3_spi_txrx(slave, len, dout, din, flags); else if (dout != NULL) - ret = omap3_spi_write(slave, len, txp, flags); + ret = omap3_spi_write(slave, len, dout, flags); else if (din != NULL) - ret = omap3_spi_read(slave, len, rxp, flags); + ret = omap3_spi_read(slave, len, din, flags); } return ret; } diff --git a/drivers/spi/omap3_spi.h b/drivers/spi/omap3_spi.h index 01537b6..ab7cd84 100644 --- a/drivers/spi/omap3_spi.h +++ b/drivers/spi/omap3_spi.h @@ -99,11 +99,11 @@ static inline struct omap3_spi_slave *to_omap3_spi(struct spi_slave *slave) return container_of(slave, struct omap3_spi_slave, slave); } -int omap3_spi_txrx(struct spi_slave *slave, unsigned int len, const u8 *txp, - u8 *rxp, unsigned long flags); -int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp, +int omap3_spi_txrx(struct spi_slave *slave, unsigned int len, const void *txp, + void *rxp, unsigned long flags); +int omap3_spi_write(struct spi_slave *slave, unsigned int len, const void *txp, unsigned long flags); -int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp, +int omap3_spi_read(struct spi_slave *slave, unsigned int len, void *rxp, unsigned long flags); #endif /* _OMAP3_SPI_H_ */ diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index ea39d1a..b76a26c 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -8,6 +8,18 @@ #include #include +int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen) +{ + if (wordlen == 0 || wordlen > 32) { + printf("spi: invalid wordlen %d\n", wordlen); + return -1; + } + + slave->wordlen = wordlen; + + return 0; +} + void *spi_do_alloc_slave(int offset, int size, unsigned int bus, unsigned int cs) { @@ -20,6 +32,7 @@ void *spi_do_alloc_slave(int offset, int size, unsigned int bus, slave = (struct spi_slave *)(ptr + offset); slave->bus = bus; slave->cs = cs; + slave->wordlen = SPI_DEFAULT_WORDLEN; } return ptr; -- cgit v1.1 From f1a74918e1d3d9988525c12b8af2eebc1910ccf7 Mon Sep 17 00:00:00 2001 From: Nikita Kiryanov Date: Wed, 16 Oct 2013 17:23:27 +0300 Subject: lcd: add DataImage SCF0403x LCD panel support Add SPI-based driver for DataImage SCF0403852GGU04 and SCF0403526GGU20 LCD panels. Cc: Tom Rini Cc: Anatolij Gustschin Cc: Igor Grinberg Signed-off-by: Nikita Kiryanov Acked-by: Anatolij Gustschin Signed-off-by: Anatolij Gustschin --- drivers/video/Makefile | 1 + drivers/video/scf0403_lcd.c | 296 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 297 insertions(+) create mode 100644 drivers/video/scf0403_lcd.c (limited to 'drivers') diff --git a/drivers/video/Makefile b/drivers/video/Makefile index fed1c9c..a7f5469 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_FSL_DIU_FB) += fsl_diu_fb.o videomodes.o obj-$(CONFIG_L5F31188) += l5f31188.o obj-$(CONFIG_MPC8XX_LCD) += mpc8xx_lcd.o obj-$(CONFIG_PXA_LCD) += pxa_lcd.o +obj-$(CONFIG_SCF0403_LCD) += scf0403_lcd.o obj-$(CONFIG_S6E8AX0) += s6e8ax0.o obj-$(CONFIG_S6E63D6) += s6e63d6.o obj-$(CONFIG_LD9040) += ld9040.o diff --git a/drivers/video/scf0403_lcd.c b/drivers/video/scf0403_lcd.c new file mode 100644 index 0000000..2bc8bca --- /dev/null +++ b/drivers/video/scf0403_lcd.c @@ -0,0 +1,296 @@ +/* + * scf0403.c -- support for DataImage SCF0403 LCD + * + * Copyright (c) 2013 Adapted from Linux driver: + * Copyright (c) 2012 Anders Electronics plc. All Rights Reserved. + * Copyright (c) 2012 CompuLab, Ltd + * Dmitry Lifshitz + * Ilya Ledvich + * Inspired by Alberto Panizzo & + * Marek Vasut work in l4f00242t03.c + * + * U-Boot port: Nikita Kiryanov + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +struct scf0403_cmd { + u16 cmd; + u16 *params; + int count; +}; + +struct scf0403_initseq_entry { + struct scf0403_cmd cmd; + int delay_ms; +}; + +struct scf0403_priv { + struct spi_slave *spi; + unsigned int reset_gpio; + u32 rddid; + struct scf0403_initseq_entry *init_seq; + int seq_size; +}; + +struct scf0403_priv priv; + +#define SCF0403852GGU04_ID 0x000080 + +/* SCF0403526GGU20 model commands parameters */ +static u16 extcmd_params_sn20[] = {0xff, 0x98, 0x06}; +static u16 spiinttype_params_sn20[] = {0x60}; +static u16 bc_params_sn20[] = { + 0x01, 0x10, 0x61, 0x74, 0x01, 0x01, 0x1B, + 0x12, 0x71, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x05, 0x00, 0xFF, 0xF2, 0x01, 0x00, 0x40, +}; +static u16 bd_params_sn20[] = {0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67}; +static u16 be_params_sn20[] = { + 0x01, 0x22, 0x22, 0xBA, 0xDC, 0x26, 0x28, 0x22, 0x22, +}; +static u16 vcom_params_sn20[] = {0x74}; +static u16 vmesur_params_sn20[] = {0x7F, 0x0F, 0x00}; +static u16 powerctl_params_sn20[] = {0x03, 0x0b, 0x00}; +static u16 lvglvolt_params_sn20[] = {0x08}; +static u16 engsetting_params_sn20[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x20}; +static u16 dispfunc_params_sn20[] = {0xa0}; +static u16 dvddvolt_params_sn20[] = {0x74}; +static u16 dispinv_params_sn20[] = {0x00, 0x00, 0x00}; +static u16 panelres_params_sn20[] = {0x82}; +static u16 framerate_params_sn20[] = {0x00, 0x13, 0x13}; +static u16 timing_params_sn20[] = {0x80, 0x05, 0x40, 0x28}; +static u16 powerctl2_params_sn20[] = {0x17, 0x75, 0x79, 0x20}; +static u16 memaccess_params_sn20[] = {0x00}; +static u16 pixfmt_params_sn20[] = {0x66}; +static u16 pgamma_params_sn20[] = { + 0x00, 0x03, 0x0b, 0x0c, 0x0e, 0x08, 0xc5, 0x04, + 0x08, 0x0c, 0x13, 0x11, 0x11, 0x14, 0x0c, 0x10, +}; +static u16 ngamma_params_sn20[] = { + 0x00, 0x0d, 0x11, 0x0c, 0x0c, 0x04, 0x76, 0x03, + 0x08, 0x0b, 0x16, 0x10, 0x0d, 0x16, 0x0a, 0x00, +}; +static u16 tearing_params_sn20[] = {0x00}; + +/* SCF0403852GGU04 model commands parameters */ +static u16 memaccess_params_sn04[] = {0x08}; +static u16 pixfmt_params_sn04[] = {0x66}; +static u16 modectl_params_sn04[] = {0x01}; +static u16 dispfunc_params_sn04[] = {0x22, 0xe2, 0xFF, 0x04}; +static u16 vcom_params_sn04[] = {0x00, 0x6A}; +static u16 pgamma_params_sn04[] = { + 0x00, 0x07, 0x0d, 0x10, 0x13, 0x19, 0x0f, 0x0c, + 0x05, 0x08, 0x06, 0x13, 0x0f, 0x30, 0x20, 0x1f, +}; +static u16 ngamma_params_sn04[] = { + 0x1F, 0x20, 0x30, 0x0F, 0x13, 0x06, 0x08, 0x05, + 0x0C, 0x0F, 0x19, 0x13, 0x10, 0x0D, 0x07, 0x00, +}; +static u16 dispinv_params_sn04[] = {0x02}; + +/* Common commands */ +static struct scf0403_cmd scf0403_cmd_slpout = {0x11, NULL, 0}; +static struct scf0403_cmd scf0403_cmd_dison = {0x29, NULL, 0}; + +/* SCF0403852GGU04 init sequence */ +static struct scf0403_initseq_entry scf0403_initseq_sn04[] = { + {{0x36, memaccess_params_sn04, ARRAY_SIZE(memaccess_params_sn04)}, 0}, + {{0x3A, pixfmt_params_sn04, ARRAY_SIZE(pixfmt_params_sn04)}, 0}, + {{0xB6, dispfunc_params_sn04, ARRAY_SIZE(dispfunc_params_sn04)}, 0}, + {{0xC5, vcom_params_sn04, ARRAY_SIZE(vcom_params_sn04)}, 0}, + {{0xE0, pgamma_params_sn04, ARRAY_SIZE(pgamma_params_sn04)}, 0}, + {{0xE1, ngamma_params_sn04, ARRAY_SIZE(ngamma_params_sn04)}, 20}, + {{0xB0, modectl_params_sn04, ARRAY_SIZE(modectl_params_sn04)}, 0}, + {{0xB4, dispinv_params_sn04, ARRAY_SIZE(dispinv_params_sn04)}, 100}, +}; + +/* SCF0403526GGU20 init sequence */ +static struct scf0403_initseq_entry scf0403_initseq_sn20[] = { + {{0xff, extcmd_params_sn20, ARRAY_SIZE(extcmd_params_sn20)}, 0}, + {{0xba, spiinttype_params_sn20, ARRAY_SIZE(spiinttype_params_sn20)}, 0}, + {{0xbc, bc_params_sn20, ARRAY_SIZE(bc_params_sn20)}, 0}, + {{0xbd, bd_params_sn20, ARRAY_SIZE(bd_params_sn20)}, 0}, + {{0xbe, be_params_sn20, ARRAY_SIZE(be_params_sn20)}, 0}, + {{0xc7, vcom_params_sn20, ARRAY_SIZE(vcom_params_sn20)}, 0}, + {{0xed, vmesur_params_sn20, ARRAY_SIZE(vmesur_params_sn20)}, 0}, + {{0xc0, powerctl_params_sn20, ARRAY_SIZE(powerctl_params_sn20)}, 0}, + {{0xfc, lvglvolt_params_sn20, ARRAY_SIZE(lvglvolt_params_sn20)}, 0}, + {{0xb6, dispfunc_params_sn20, ARRAY_SIZE(dispfunc_params_sn20)}, 0}, + {{0xdf, engsetting_params_sn20, ARRAY_SIZE(engsetting_params_sn20)}, 0}, + {{0xf3, dvddvolt_params_sn20, ARRAY_SIZE(dvddvolt_params_sn20)}, 0}, + {{0xb4, dispinv_params_sn20, ARRAY_SIZE(dispinv_params_sn20)}, 0}, + {{0xf7, panelres_params_sn20, ARRAY_SIZE(panelres_params_sn20)}, 0}, + {{0xb1, framerate_params_sn20, ARRAY_SIZE(framerate_params_sn20)}, 0}, + {{0xf2, timing_params_sn20, ARRAY_SIZE(timing_params_sn20)}, 0}, + {{0xc1, powerctl2_params_sn20, ARRAY_SIZE(powerctl2_params_sn20)}, 0}, + {{0x36, memaccess_params_sn20, ARRAY_SIZE(memaccess_params_sn20)}, 0}, + {{0x3a, pixfmt_params_sn20, ARRAY_SIZE(pixfmt_params_sn20)}, 0}, + {{0xe0, pgamma_params_sn20, ARRAY_SIZE(pgamma_params_sn20)}, 0}, + {{0xe1, ngamma_params_sn20, ARRAY_SIZE(ngamma_params_sn20)}, 0}, + {{0x35, tearing_params_sn20, ARRAY_SIZE(tearing_params_sn20)}, 0}, +}; + +static void scf0403_gpio_reset(unsigned int gpio) +{ + if (!gpio_is_valid(gpio)) + return; + + gpio_set_value(gpio, 1); + mdelay(100); + gpio_set_value(gpio, 0); + mdelay(40); + gpio_set_value(gpio, 1); + mdelay(100); +} + +static int scf0403_spi_read_rddid(struct spi_slave *spi, u32 *rddid) +{ + int error = 0; + u8 ids_buf = 0x00; + u16 dummy_buf = 0x00; + u16 cmd = 0x04; + + error = spi_set_wordlen(spi, 9); + if (error) + return error; + + /* Here 9 bits required to transmit a command */ + error = spi_xfer(spi, 9, &cmd, NULL, SPI_XFER_ONCE); + if (error) + return error; + + /* + * Here 8 + 1 bits required to arrange extra clock cycle + * before the first data bit. + * According to the datasheet - first parameter is the dummy data. + */ + error = spi_xfer(spi, 9, NULL, &dummy_buf, SPI_XFER_ONCE); + if (error) + return error; + + error = spi_set_wordlen(spi, 8); + if (error) + return error; + + /* Read rest of the data */ + error = spi_xfer(spi, 8, NULL, &ids_buf, SPI_XFER_ONCE); + if (error) + return error; + + *rddid = ids_buf; + + return 0; +} + +static int scf0403_spi_transfer(struct spi_slave *spi, struct scf0403_cmd *cmd) +{ + int i, error; + u32 command = cmd->cmd; + u32 msg; + + error = spi_set_wordlen(spi, 9); + if (error) + return error; + + error = spi_xfer(spi, 9, &command, NULL, SPI_XFER_ONCE); + if (error) + return error; + + for (i = 0; i < cmd->count; i++) { + msg = (cmd->params[i] | 0x100); + error = spi_xfer(spi, 9, &msg, NULL, SPI_XFER_ONCE); + if (error) + return error; + } + + return 0; +} + +static void scf0403_lcd_init(struct scf0403_priv *priv) +{ + int i; + + /* reset LCD */ + scf0403_gpio_reset(priv->reset_gpio); + + for (i = 0; i < priv->seq_size; i++) { + if (scf0403_spi_transfer(priv->spi, &priv->init_seq[i].cmd) < 0) + puts("SPI transfer failed\n"); + + mdelay(priv->init_seq[i].delay_ms); + } +} + +static int scf0403_request_reset_gpio(unsigned gpio) +{ + int err = gpio_request(gpio, "lcd reset"); + + if (err) + return err; + + err = gpio_direction_output(gpio, 0); + if (err) + gpio_free(gpio); + + return err; +} + +int scf0403_init(int reset_gpio) +{ + int error; + + if (gpio_is_valid(reset_gpio)) { + error = scf0403_request_reset_gpio(reset_gpio); + if (error) { + printf("Failed requesting reset GPIO%d: %d\n", + reset_gpio, error); + return error; + } + } + + priv.reset_gpio = reset_gpio; + priv.spi = spi_setup_slave(3, 0, 1000000, SPI_MODE_0); + error = spi_claim_bus(priv.spi); + if (error) + goto bus_claim_fail; + + /* reset LCD */ + scf0403_gpio_reset(reset_gpio); + + error = scf0403_spi_read_rddid(priv.spi, &priv.rddid); + if (error) { + puts("IDs read failed\n"); + goto readid_fail; + } + + if (priv.rddid == SCF0403852GGU04_ID) { + priv.init_seq = scf0403_initseq_sn04; + priv.seq_size = ARRAY_SIZE(scf0403_initseq_sn04); + } else { + priv.init_seq = scf0403_initseq_sn20; + priv.seq_size = ARRAY_SIZE(scf0403_initseq_sn20); + } + + scf0403_lcd_init(&priv); + + /* Start operation */ + scf0403_spi_transfer(priv.spi, &scf0403_cmd_dison); + mdelay(100); + scf0403_spi_transfer(priv.spi, &scf0403_cmd_slpout); + spi_release_bus(priv.spi); + + return 0; + +readid_fail: + spi_release_bus(priv.spi); +bus_claim_fail: + if (gpio_is_valid(priv.reset_gpio)) + gpio_free(priv.reset_gpio); + + return error; +} -- cgit v1.1 From 2035d77d790044f389a18c0e6baa05e86d4b32a0 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Tue, 29 Oct 2013 13:33:51 +0900 Subject: i2c: sh_i2c: Update to new CONFIG_SYS_I2C framework This updates to new I2C framwwork on sh_i2c. And this also updates boards(kzm9g and ecovec) that using sh_i2c. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Nobuhiro Iwamatsu --- drivers/i2c/Makefile | 2 +- drivers/i2c/sh_i2c.c | 294 +++++++++++++++++++++++---------------------------- 2 files changed, 132 insertions(+), 164 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 5280bb3..0899b6e 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -18,7 +18,6 @@ obj-$(CONFIG_PCA9564_I2C) += pca9564_i2c.o obj-$(CONFIG_DRIVER_S3C24X0_I2C) += s3c24x0_i2c.o obj-$(CONFIG_TSI108_I2C) += tsi108_i2c.o obj-$(CONFIG_U8500_I2C) += u8500_i2c.o -obj-$(CONFIG_SH_I2C) += sh_i2c.o obj-$(CONFIG_SH_SH7734_I2C) += sh_sh7734_i2c.o obj-$(CONFIG_SYS_I2C) += i2c_core.o obj-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o @@ -26,6 +25,7 @@ obj-$(CONFIG_SYS_I2C_FTI2C010) += fti2c010.o obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o obj-$(CONFIG_SYS_I2C_PPC4XX) += ppc4xx_i2c.o obj-$(CONFIG_SYS_I2C_RCAR) += rcar_i2c.o +obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o obj-$(CONFIG_ZYNQ_I2C) += zynq_i2c.o diff --git a/drivers/i2c/sh_i2c.c b/drivers/i2c/sh_i2c.c index 808202c..cc19100 100644 --- a/drivers/i2c/sh_i2c.c +++ b/drivers/i2c/sh_i2c.c @@ -6,6 +6,7 @@ */ #include +#include #include DECLARE_GLOBAL_DATA_PTR; @@ -22,8 +23,6 @@ struct sh_i2c { }; #undef ureg -static struct sh_i2c *base; - /* ICCR */ #define SH_I2C_ICCR_ICE (1 << 7) #define SH_I2C_ICCR_RACK (1 << 6) @@ -43,202 +42,165 @@ static struct sh_i2c *base; #define SH_I2C_ICIC_ICCHB8 (1 << 6) #endif +static const struct sh_i2c *i2c_dev[CONFIG_SYS_I2C_SH_NUM_CONTROLLERS] = { + (struct sh_i2c *)CONFIG_SYS_I2C_SH_BASE0, +#ifdef CONFIG_SYS_I2C_SH_BASE1 + (struct sh_i2c *)CONFIG_SYS_I2C_SH_BASE1, +#endif +#ifdef CONFIG_SYS_I2C_SH_BASE2 + (struct sh_i2c *)CONFIG_SYS_I2C_SH_BASE2, +#endif +#ifdef CONFIG_SYS_I2C_SH_BASE3 + (struct sh_i2c *)CONFIG_SYS_I2C_SH_BASE3, +#endif +#ifdef CONFIG_SYS_I2C_SH_BASE4 + (struct sh_i2c *)CONFIG_SYS_I2C_SH_BASE4, +#endif +}; + static u16 iccl, icch; #define IRQ_WAIT 1000 -static void irq_dte(struct sh_i2c *base) +static void sh_irq_dte(struct sh_i2c *dev) { int i; - for (i = 0 ; i < IRQ_WAIT ; i++) { - if (SH_IC_DTE & readb(&base->icsr)) + for (i = 0; i < IRQ_WAIT; i++) { + if (SH_IC_DTE & readb(&dev->icsr)) break; udelay(10); } } -static int irq_dte_with_tack(struct sh_i2c *base) +static int sh_irq_dte_with_tack(struct sh_i2c *dev) { int i; - for (i = 0 ; i < IRQ_WAIT ; i++) { - if (SH_IC_DTE & readb(&base->icsr)) + for (i = 0; i < IRQ_WAIT; i++) { + if (SH_IC_DTE & readb(&dev->icsr)) break; - if (SH_IC_TACK & readb(&base->icsr)) + if (SH_IC_TACK & readb(&dev->icsr)) return -1; udelay(10); } return 0; } -static void irq_busy(struct sh_i2c *base) +static void sh_irq_busy(struct sh_i2c *dev) { int i; - for (i = 0 ; i < IRQ_WAIT ; i++) { - if (!(SH_IC_BUSY & readb(&base->icsr))) + for (i = 0; i < IRQ_WAIT; i++) { + if (!(SH_IC_BUSY & readb(&dev->icsr))) break; udelay(10); } } -static int i2c_set_addr(struct sh_i2c *base, u8 id, u8 reg, int stop) +static int sh_i2c_set_addr(struct sh_i2c *dev, u8 chip, u8 addr, int stop) { u8 icic = SH_IC_TACK; - clrbits_8(&base->iccr, SH_I2C_ICCR_ICE); - setbits_8(&base->iccr, SH_I2C_ICCR_ICE); + debug("%s: chip: %x, addr: %x iccl: %x, icch %x\n", + __func__, chip, addr, iccl, icch); + clrbits_8(&dev->iccr, SH_I2C_ICCR_ICE); + setbits_8(&dev->iccr, SH_I2C_ICCR_ICE); - writeb(iccl & 0xff, &base->iccl); - writeb(icch & 0xff, &base->icch); + writeb(iccl & 0xff, &dev->iccl); + writeb(icch & 0xff, &dev->icch); #ifdef CONFIG_SH_I2C_8BIT if (iccl > 0xff) icic |= SH_I2C_ICIC_ICCLB8; if (icch > 0xff) icic |= SH_I2C_ICIC_ICCHB8; #endif - writeb(icic, &base->icic); + writeb(icic, &dev->icic); - writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RTS|SH_I2C_ICCR_BUSY), &base->iccr); - irq_dte(base); + writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RTS|SH_I2C_ICCR_BUSY), &dev->iccr); + sh_irq_dte(dev); - clrbits_8(&base->icsr, SH_IC_TACK); - writeb(id << 1, &base->icdr); - if (irq_dte_with_tack(base) != 0) + clrbits_8(&dev->icsr, SH_IC_TACK); + writeb(chip << 1, &dev->icdr); + if (sh_irq_dte_with_tack(dev) != 0) return -1; - writeb(reg, &base->icdr); + writeb(addr, &dev->icdr); if (stop) - writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RTS), &base->iccr); + writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RTS), &dev->iccr); - if (irq_dte_with_tack(base) != 0) + if (sh_irq_dte_with_tack(dev) != 0) return -1; return 0; } -static void i2c_finish(struct sh_i2c *base) +static void sh_i2c_finish(struct sh_i2c *dev) { - writeb(0, &base->icsr); - clrbits_8(&base->iccr, SH_I2C_ICCR_ICE); + writeb(0, &dev->icsr); + clrbits_8(&dev->iccr, SH_I2C_ICCR_ICE); } -static int i2c_raw_write(struct sh_i2c *base, u8 id, u8 reg, u8 val) +static int +sh_i2c_raw_write(struct sh_i2c *dev, u8 chip, uint addr, u8 val) { int ret = -1; - if (i2c_set_addr(base, id, reg, 0) != 0) + if (sh_i2c_set_addr(dev, chip, addr, 0) != 0) goto exit0; udelay(10); - writeb(val, &base->icdr); - if (irq_dte_with_tack(base) != 0) + writeb(val, &dev->icdr); + if (sh_irq_dte_with_tack(dev) != 0) goto exit0; - writeb((SH_I2C_ICCR_ICE | SH_I2C_ICCR_RTS), &base->iccr); - if (irq_dte_with_tack(base) != 0) + writeb((SH_I2C_ICCR_ICE | SH_I2C_ICCR_RTS), &dev->iccr); + if (sh_irq_dte_with_tack(dev) != 0) goto exit0; - irq_busy(base); + sh_irq_busy(dev); ret = 0; + exit0: - i2c_finish(base); + sh_i2c_finish(dev); return ret; } -static int i2c_raw_read(struct sh_i2c *base, u8 id, u8 reg) +static int sh_i2c_raw_read(struct sh_i2c *dev, u8 chip, u8 addr) { int ret = -1; #if defined(CONFIG_SH73A0) - if (i2c_set_addr(base, id, reg, 0) != 0) + if (sh_i2c_set_addr(dev, chip, addr, 0) != 0) goto exit0; #else - if (i2c_set_addr(base, id, reg, 1) != 0) + if (sh_i2c_set_addr(dev, chip, addr, 1) != 0) goto exit0; udelay(100); #endif - writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RTS|SH_I2C_ICCR_BUSY), &base->iccr); - irq_dte(base); + writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RTS|SH_I2C_ICCR_BUSY), &dev->iccr); + sh_irq_dte(dev); - writeb(id << 1 | 0x01, &base->icdr); - if (irq_dte_with_tack(base) != 0) + writeb(chip << 1 | 0x01, &dev->icdr); + if (sh_irq_dte_with_tack(dev) != 0) goto exit0; - writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_SCP), &base->iccr); - if (irq_dte_with_tack(base) != 0) + writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_SCP), &dev->iccr); + if (sh_irq_dte_with_tack(dev) != 0) goto exit0; - ret = readb(&base->icdr) & 0xff; + ret = readb(&dev->icdr) & 0xff; + + writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RACK), &dev->iccr); + readb(&dev->icdr); /* Dummy read */ + sh_irq_busy(dev); - writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RACK), &base->iccr); - readb(&base->icdr); /* Dummy read */ - irq_busy(base); exit0: - i2c_finish(base); + sh_i2c_finish(dev); return ret; } -#ifdef CONFIG_I2C_MULTI_BUS -static unsigned int current_bus; - -/** - * i2c_set_bus_num - change active I2C bus - * @bus: bus index, zero based - * @returns: 0 on success, non-0 on failure - */ -int i2c_set_bus_num(unsigned int bus) -{ - if ((bus < 0) || (bus >= CONFIG_SYS_MAX_I2C_BUS)) { - printf("Bad bus: %d\n", bus); - return -1; - } - - switch (bus) { - case 0: - base = (void *)CONFIG_SH_I2C_BASE0; - break; - case 1: - base = (void *)CONFIG_SH_I2C_BASE1; - break; -#ifdef CONFIG_SH_I2C_BASE2 - case 2: - base = (void *)CONFIG_SH_I2C_BASE2; - break; -#endif -#ifdef CONFIG_SH_I2C_BASE3 - case 3: - base = (void *)CONFIG_SH_I2C_BASE3; - break; -#endif -#ifdef CONFIG_SH_I2C_BASE4 - case 4: - base = (void *)CONFIG_SH_I2C_BASE4; - break; -#endif - default: - return -1; - } - current_bus = bus; - - return 0; -} - -/** - * i2c_get_bus_num - returns index of active I2C bus - */ -unsigned int i2c_get_bus_num(void) -{ - return current_bus; -} -#endif - -#define SH_I2C_ICCL_CALC(clk, date, t_low, t_high) \ - ((clk / rate) * (t_low / t_low + t_high)) -#define SH_I2C_ICCH_CALC(clk, date, t_low, t_high) \ - ((clk / rate) * (t_high / t_low + t_high)) - -void i2c_init(int speed, int slaveaddr) +static void +sh_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd) { int num, denom, tmp; @@ -246,11 +208,6 @@ void i2c_init(int speed, int slaveaddr) if (!(gd->flags & GD_FLG_RELOC)) return; -#ifdef CONFIG_I2C_MULTI_BUS - current_bus = 0; -#endif - base = (struct sh_i2c *)CONFIG_SH_I2C_BASE0; - /* * Calculate the value for iccl. From the data sheet: * iccl = (p-clock / transfer-rate) * (L / (L + H)) @@ -272,67 +229,78 @@ void i2c_init(int speed, int slaveaddr) icch = (u16)((num/denom) + 1); else icch = (u16)(num/denom); + + debug("clock: %d, speed %d, iccl: %x, icch: %x\n", + CONFIG_SH_I2C_CLOCK, speed, iccl, icch); } -/* - * i2c_read: - Read multiple bytes from an i2c device - * - * The higher level routines take into account that this function is only - * called with len < page length of the device (see configuration file) - * - * @chip: address of the chip which is to be read - * @addr: i2c data address within the chip - * @alen: length of the i2c data address (1..2 bytes) - * @buffer: where to write the data - * @len: how much byte do we want to read - * @return: 0 in case of success - */ -int i2c_read(u8 chip, u32 addr, int alen, u8 *buffer, int len) +static int sh_i2c_read(struct i2c_adapter *adap, uint8_t chip, + uint addr, int alen, u8 *data, int len) { - int ret; - int i = 0; - for (i = 0 ; i < len ; i++) { - ret = i2c_raw_read(base, chip, addr + i); + int ret, i; + struct sh_i2c *dev = (struct sh_i2c *)i2c_dev[adap->hwadapnr]; + + for (i = 0; i < len; i++) { + ret = sh_i2c_raw_read(dev, chip, addr + i); if (ret < 0) return -1; - buffer[i] = ret & 0xff; + + data[i] = ret & 0xff; + debug("%s: data[%d]: %02x\n", __func__, i, data[i]); } + return 0; } -/* - * i2c_write: - Write multiple bytes to an i2c device - * - * The higher level routines take into account that this function is only - * called with len < page length of the device (see configuration file) - * - * @chip: address of the chip which is to be written - * @addr: i2c data address within the chip - * @alen: length of the i2c data address (1..2 bytes) - * @buffer: where to find the data to be written - * @len: how much byte do we want to read - * @return: 0 in case of success - */ -int i2c_write(u8 chip, u32 addr, int alen, u8 *buffer, int len) +static int sh_i2c_write(struct i2c_adapter *adap, uint8_t chip, uint addr, + int alen, u8 *data, int len) { - int i = 0; - for (i = 0; i < len ; i++) - if (i2c_raw_write(base, chip, addr + i, buffer[i]) != 0) + struct sh_i2c *dev = (struct sh_i2c *)i2c_dev[adap->hwadapnr]; + int i; + + for (i = 0; i < len; i++) { + debug("%s: data[%d]: %02x\n", __func__, i, data[i]); + if (sh_i2c_raw_write(dev, chip, addr + i, data[i]) != 0) return -1; + } return 0; } -/* - * i2c_probe: - Test if a chip answers for a given i2c address - * - * @chip: address of the chip which is searched for - * @return: 0 if a chip was found, -1 otherwhise - */ -int i2c_probe(u8 chip) +static int +sh_i2c_probe(struct i2c_adapter *adap, u8 dev) { - int ret; + return sh_i2c_read(adap, dev, 0, 0, NULL, 0); +} - ret = i2c_set_addr(base, chip, 0, 1); - i2c_finish(base); - return ret; +static unsigned int sh_i2c_set_bus_speed(struct i2c_adapter *adap, + unsigned int speed) +{ + struct sh_i2c *dev = (struct sh_i2c *)i2c_dev[adap->hwadapnr]; + + sh_i2c_finish(dev); + sh_i2c_init(adap, speed, 0); + + return 0; } + +/* + * Register RCAR i2c adapters + */ +U_BOOT_I2C_ADAP_COMPLETE(sh_0, sh_i2c_init, sh_i2c_probe, sh_i2c_read, + sh_i2c_write, sh_i2c_set_bus_speed, CONFIG_SYS_I2C_SH_SPEED0, 0, 0) +#ifdef CONFIG_SYS_I2C_SH_BASE1 +U_BOOT_I2C_ADAP_COMPLETE(sh_1, sh_i2c_init, sh_i2c_probe, sh_i2c_read, + sh_i2c_write, sh_i2c_set_bus_speed, CONFIG_SYS_I2C_SH_SPEED1, 0, 1) +#endif +#ifdef CONFIG_SYS_I2C_SH_BASE2 +U_BOOT_I2C_ADAP_COMPLETE(sh_2, sh_i2c_init, sh_i2c_probe, sh_i2c_read, + sh_i2c_write, sh_i2c_set_bus_speed, CONFIG_SYS_I2C_SH_SPEED2, 0, 2) +#endif +#ifdef CONFIG_SYS_I2C_SH_BASE3 +U_BOOT_I2C_ADAP_COMPLETE(sh_3, sh_i2c_init, sh_i2c_probe, sh_i2c_read, + sh_i2c_write, sh_i2c_set_bus_speed, CONFIG_SYS_I2C_SH_SPEED3, 0, 3) +#endif +#ifdef CONFIG_SYS_I2C_SH_BASE4 +U_BOOT_I2C_ADAP_COMPLETE(sh_4, sh_i2c_init, sh_i2c_probe, sh_i2c_read, + sh_i2c_write, sh_i2c_set_bus_speed, CONFIG_SYS_I2C_SH_SPEED4, 0, 4) +#endif -- cgit v1.1 From 124913556c4b99909f40b4bf4ceaefe2b555d6f8 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 4 Nov 2013 14:29:12 +0100 Subject: i2c: mxs_i2c: Squash endless loop The endless waiting for a bit to be set can cause a hang, add a timeout so we prevent such situation. A testcase for such a hang is below. The testcase assumes a device to be present at address 0x50 and a device to NOT be present at address 0x42 . Also note that the "sleep 1" induced delays are imperative for this bug to manifest . i2c read 0x42 0x0.2 0x10 0x42000000 ; sleep 1 ; \ i2c read 0x50 0x0.2 0x10 0x42000000 ; sleep 1 ; \ i2c read 0x42 0x0.2 0x10 0x42000000 The expected result of the above command is: Error reading the chip. Error reading the chip. While without this patch, we observe a hang in the last read from 0x42 precisely when waiting for this bit to be set. Signed-off-by: Marek Vasut Cc: Fabio Estevam Cc: Heiko Schocher Cc: Stefano Babic --- drivers/i2c/mxs_i2c.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/mxs_i2c.c b/drivers/i2c/mxs_i2c.c index 46106b7..a298c95 100644 --- a/drivers/i2c/mxs_i2c.c +++ b/drivers/i2c/mxs_i2c.c @@ -150,6 +150,7 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) { struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE; uint32_t tmp = 0; + int timeout = MXS_I2C_MAX_TIMEOUT; int ret; int i; @@ -169,9 +170,17 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) for (i = 0; i < len; i++) { if (!(i & 3)) { - while (readl(&i2c_regs->hw_i2c_queuestat) & - I2C_QUEUESTAT_RD_QUEUE_EMPTY) - ; + while (--timeout) { + tmp = readl(&i2c_regs->hw_i2c_queuestat); + if (!(tmp & I2C_QUEUESTAT_RD_QUEUE_EMPTY)) + break; + } + + if (!timeout) { + debug("MXS I2C: Failed receiving data!\n"); + return -ETIMEDOUT; + } + tmp = readl(&i2c_regs->hw_i2c_queuedata); } buffer[i] = tmp & 0xff; -- cgit v1.1 From 6789e84ecaa8f45d053084e08c381284a04abff7 Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Tue, 22 Oct 2013 11:03:18 +0200 Subject: i2c, omap24xx: convert driver to new mutlibus/mutliadapter framework MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - add omap24xx driver to new multibus/multiadpater support - adapted all config files, which uses this driver Tested on the am335x based siemens boards rut, dxr2 and pxm2 posted here: http://patchwork.ozlabs.org/patch/263211/ Signed-off-by: Heiko Schocher Tested-by: Tom Rini Cc: Lars Poeschel Cc: Steve Sakoman Cc: Thomas Weber Cc: Tom Rix Cc: Grazvydas Ignotas Cc: Enric Balletbo i Serra Cc: Luca Ceresoli Cc: Igor Grinberg Cc: Ilya Yanok Cc: Stefano Babic Cc: Nishanth Menon Cc: Pali Rohár Cc: Peter Barada Cc: Nagendra T S Cc: Michael Jones Cc: Raphael Assenat Acked-by: Igor Grinberg Acked-by: Stefano Babic --- drivers/i2c/Makefile | 4 +- drivers/i2c/omap24xx_i2c.c | 172 ++++++++++++++++++++++++++++----------------- 2 files changed, 110 insertions(+), 66 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 0899b6e..298b17b 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -12,8 +12,6 @@ obj-$(CONFIG_I2C_MVTWSI) += mvtwsi.o obj-$(CONFIG_I2C_MV) += mv_i2c.o obj-$(CONFIG_I2C_MXS) += mxs_i2c.o obj-$(CONFIG_DRIVER_OMAP1510_I2C) += omap1510_i2c.o -obj-$(CONFIG_DRIVER_OMAP24XX_I2C) += omap24xx_i2c.o -obj-$(CONFIG_DRIVER_OMAP34XX_I2C) += omap24xx_i2c.o obj-$(CONFIG_PCA9564_I2C) += pca9564_i2c.o obj-$(CONFIG_DRIVER_S3C24X0_I2C) += s3c24x0_i2c.o obj-$(CONFIG_TSI108_I2C) += tsi108_i2c.o @@ -23,6 +21,8 @@ obj-$(CONFIG_SYS_I2C) += i2c_core.o obj-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o obj-$(CONFIG_SYS_I2C_FTI2C010) += fti2c010.o obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o +obj-$(CONFIG_SYS_I2C_OMAP24XX) += omap24xx_i2c.o +obj-$(CONFIG_SYS_I2C_OMAP34XX) += omap24xx_i2c.o obj-$(CONFIG_SYS_I2C_PPC4XX) += ppc4xx_i2c.o obj-$(CONFIG_SYS_I2C_RCAR) += rcar_i2c.o obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c index ef38d71..3d38c03 100644 --- a/drivers/i2c/omap24xx_i2c.c +++ b/drivers/i2c/omap24xx_i2c.c @@ -35,6 +35,7 @@ */ #include +#include #include #include @@ -48,22 +49,14 @@ DECLARE_GLOBAL_DATA_PTR; /* Absolutely safe for status update at 100 kHz I2C: */ #define I2C_WAIT 200 -static int wait_for_bb(void); -static u16 wait_for_event(void); -static void flush_fifo(void); +static int wait_for_bb(struct i2c_adapter *adap); +static struct i2c *omap24_get_base(struct i2c_adapter *adap); +static u16 wait_for_event(struct i2c_adapter *adap); +static void flush_fifo(struct i2c_adapter *adap); -/* - * For SPL boot some boards need i2c before SDRAM is initialised so force - * variables to live in SRAM - */ -static struct i2c __attribute__((section (".data"))) *i2c_base = - (struct i2c *)I2C_DEFAULT_BASE; -static unsigned int __attribute__((section (".data"))) bus_initialized[I2C_BUS_MAX] = - { [0 ... (I2C_BUS_MAX-1)] = 0 }; -static unsigned int __attribute__((section (".data"))) current_bus = 0; - -void i2c_init(int speed, int slaveadd) +static void omap24_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd) { + struct i2c *i2c_base = omap24_get_base(adap); int psc, fsscll, fssclh; int hsscll = 0, hssclh = 0; u32 scll, sclh; @@ -163,16 +156,15 @@ void i2c_init(int speed, int slaveadd) I2C_IE_NACK_IE | I2C_IE_AL_IE, &i2c_base->ie); #endif udelay(1000); - flush_fifo(); + flush_fifo(adap); writew(0xFFFF, &i2c_base->stat); writew(0, &i2c_base->cnt); - - if (gd->flags & GD_FLG_RELOC) - bus_initialized[current_bus] = 1; } -static void flush_fifo(void) -{ u16 stat; +static void flush_fifo(struct i2c_adapter *adap) +{ + struct i2c *i2c_base = omap24_get_base(adap); + u16 stat; /* note: if you try and read data when its not there or ready * you get a bus error @@ -192,8 +184,9 @@ static void flush_fifo(void) * i2c_probe: Use write access. Allows to identify addresses that are * write-only (like the config register of dual-port EEPROMs) */ -int i2c_probe(uchar chip) +static int omap24_i2c_probe(struct i2c_adapter *adap, uchar chip) { + struct i2c *i2c_base = omap24_get_base(adap); u16 status; int res = 1; /* default = fail */ @@ -201,7 +194,7 @@ int i2c_probe(uchar chip) return res; /* Wait until bus is free */ - if (wait_for_bb()) + if (wait_for_bb(adap)) return res; /* No data transfer, slave addr only */ @@ -212,7 +205,7 @@ int i2c_probe(uchar chip) writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | I2C_CON_STP, &i2c_base->con); - status = wait_for_event(); + status = wait_for_event(adap); if ((status & ~I2C_STAT_XRDY) == 0 || (status & I2C_STAT_AL)) { /* @@ -223,7 +216,7 @@ int i2c_probe(uchar chip) */ if (status == I2C_STAT_XRDY) printf("i2c_probe: pads on bus %d probably not configured (status=0x%x)\n", - current_bus, status); + adap->hwadapnr, status); goto pr_exit; } @@ -239,7 +232,7 @@ int i2c_probe(uchar chip) I2C_CON_STP, &i2c_base->con); /* STP */ } pr_exit: - flush_fifo(); + flush_fifo(adap); writew(0xFFFF, &i2c_base->stat); writew(0, &i2c_base->cnt); return res; @@ -258,8 +251,10 @@ pr_exit: * or that do not need a register address at all (such as some clock * distributors). */ -int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) +static int omap24_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr, + int alen, uchar *buffer, int len) { + struct i2c *i2c_base = omap24_get_base(adap); int i2c_error = 0; u16 status; @@ -287,7 +282,7 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) } /* Wait until bus not busy */ - if (wait_for_bb()) + if (wait_for_bb(adap)) return 1; /* Zero, one or two bytes reg address (offset) */ @@ -308,12 +303,12 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) #endif /* Send register offset */ while (1) { - status = wait_for_event(); + status = wait_for_event(adap); /* Try to identify bus that is not padconf'd for I2C */ if (status == I2C_STAT_XRDY) { i2c_error = 2; printf("i2c_read (addr phase): pads on bus %d probably not configured (status=0x%x)\n", - current_bus, status); + adap->hwadapnr, status); goto rd_exit; } if (status == 0 || status & I2C_STAT_NACK) { @@ -348,7 +343,7 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) /* Receive data */ while (1) { - status = wait_for_event(); + status = wait_for_event(adap); /* * Try to identify bus that is not padconf'd for I2C. This * state could be left over from previous transactions if @@ -357,7 +352,7 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) if (status == I2C_STAT_XRDY) { i2c_error = 2; printf("i2c_read (data phase): pads on bus %d probably not configured (status=0x%x)\n", - current_bus, status); + adap->hwadapnr, status); goto rd_exit; } if (status == 0 || status & I2C_STAT_NACK) { @@ -375,15 +370,17 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) } rd_exit: - flush_fifo(); + flush_fifo(adap); writew(0xFFFF, &i2c_base->stat); writew(0, &i2c_base->cnt); return i2c_error; } /* i2c_write: Address (reg offset) may be 0, 1 or 2 bytes long. */ -int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) +static int omap24_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr, + int alen, uchar *buffer, int len) { + struct i2c *i2c_base = omap24_get_base(adap); int i; u16 status; int i2c_error = 0; @@ -415,7 +412,7 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) } /* Wait until bus not busy */ - if (wait_for_bb()) + if (wait_for_bb(adap)) return 1; /* Start address phase - will write regoffset + len bytes data */ @@ -428,12 +425,12 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) while (alen) { /* Must write reg offset (one or two bytes) */ - status = wait_for_event(); + status = wait_for_event(adap); /* Try to identify bus that is not padconf'd for I2C */ if (status == I2C_STAT_XRDY) { i2c_error = 2; printf("i2c_write: pads on bus %d probably not configured (status=0x%x)\n", - current_bus, status); + adap->hwadapnr, status); goto wr_exit; } if (status == 0 || status & I2C_STAT_NACK) { @@ -455,7 +452,7 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) } /* Address phase is over, now write data */ for (i = 0; i < len; i++) { - status = wait_for_event(); + status = wait_for_event(adap); if (status == 0 || status & I2C_STAT_NACK) { i2c_error = 1; printf("i2c_write: error waiting for data ACK (status=0x%x)\n", @@ -474,7 +471,7 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) } wr_exit: - flush_fifo(); + flush_fifo(adap); writew(0xFFFF, &i2c_base->stat); writew(0, &i2c_base->cnt); return i2c_error; @@ -484,8 +481,9 @@ wr_exit: * Wait for the bus to be free by checking the Bus Busy (BB) * bit to become clear */ -static int wait_for_bb(void) +static int wait_for_bb(struct i2c_adapter *adap) { + struct i2c *i2c_base = omap24_get_base(adap); int timeout = I2C_TIMEOUT; u16 stat; @@ -514,8 +512,9 @@ static int wait_for_bb(void) * Wait for the I2C controller to complete current action * and update status */ -static u16 wait_for_event(void) +static u16 wait_for_event(struct i2c_adapter *adap) { + struct i2c *i2c_base = omap24_get_base(adap); u16 status; int timeout = I2C_TIMEOUT; @@ -540,7 +539,7 @@ static u16 wait_for_event(void) * not been configured for I2C, and/or pull-ups are missing. */ printf("Check if pads/pull-ups of bus %d are properly configured\n", - current_bus); + adap->hwadapnr); writew(0xFFFF, &i2c_base->stat); status = 0; } @@ -548,48 +547,93 @@ static u16 wait_for_event(void) return status; } -int i2c_set_bus_num(unsigned int bus) +static struct i2c *omap24_get_base(struct i2c_adapter *adap) { - if (bus >= I2C_BUS_MAX) { - printf("Bad bus: %x\n", bus); - return -1; - } - - switch (bus) { - default: - bus = 0; /* Fall through */ + switch (adap->hwadapnr) { case 0: - i2c_base = (struct i2c *)I2C_BASE1; + return (struct i2c *)I2C_BASE1; break; case 1: - i2c_base = (struct i2c *)I2C_BASE2; + return (struct i2c *)I2C_BASE2; break; #if (I2C_BUS_MAX > 2) case 2: - i2c_base = (struct i2c *)I2C_BASE3; + return (struct i2c *)I2C_BASE3; break; #if (I2C_BUS_MAX > 3) case 3: - i2c_base = (struct i2c *)I2C_BASE4; + return (struct i2c *)I2C_BASE4; break; #if (I2C_BUS_MAX > 4) case 4: - i2c_base = (struct i2c *)I2C_BASE5; + return (struct i2c *)I2C_BASE5; break; #endif #endif #endif + default: + printf("wrong hwadapnr: %d\n", adap->hwadapnr); + break; } + return NULL; +} - current_bus = bus; +#if !defined(CONFIG_SYS_OMAP24_I2C_SPEED1) +#define CONFIG_SYS_OMAP24_I2C_SPEED1 CONFIG_SYS_OMAP24_I2C_SPEED +#endif +#if !defined(CONFIG_SYS_OMAP24_I2C_SLAVE1) +#define CONFIG_SYS_OMAP24_I2C_SLAVE1 CONFIG_SYS_OMAP24_I2C_SLAVE +#endif - if (!bus_initialized[current_bus]) - i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); +U_BOOT_I2C_ADAP_COMPLETE(omap24_0, omap24_i2c_init, omap24_i2c_probe, + omap24_i2c_read, omap24_i2c_write, NULL, + CONFIG_SYS_OMAP24_I2C_SPEED, + CONFIG_SYS_OMAP24_I2C_SLAVE, + 0) +U_BOOT_I2C_ADAP_COMPLETE(omap24_1, omap24_i2c_init, omap24_i2c_probe, + omap24_i2c_read, omap24_i2c_write, NULL, + CONFIG_SYS_OMAP24_I2C_SPEED1, + CONFIG_SYS_OMAP24_I2C_SLAVE1, + 1) +#if (I2C_BUS_MAX > 2) +#if !defined(CONFIG_SYS_OMAP24_I2C_SPEED2) +#define CONFIG_SYS_OMAP24_I2C_SPEED2 CONFIG_SYS_OMAP24_I2C_SPEED +#endif +#if !defined(CONFIG_SYS_OMAP24_I2C_SLAVE2) +#define CONFIG_SYS_OMAP24_I2C_SLAVE2 CONFIG_SYS_OMAP24_I2C_SLAVE +#endif - return 0; -} +U_BOOT_I2C_ADAP_COMPLETE(omap24_2, omap24_i2c_init, omap24_i2c_probe, + omap24_i2c_read, omap24_i2c_write, NULL, + CONFIG_SYS_OMAP24_I2C_SPEED2, + CONFIG_SYS_OMAP24_I2C_SLAVE2, + 2) +#if (I2C_BUS_MAX > 3) +#if !defined(CONFIG_SYS_OMAP24_I2C_SPEED3) +#define CONFIG_SYS_OMAP24_I2C_SPEED3 CONFIG_SYS_OMAP24_I2C_SPEED +#endif +#if !defined(CONFIG_SYS_OMAP24_I2C_SLAVE3) +#define CONFIG_SYS_OMAP24_I2C_SLAVE3 CONFIG_SYS_OMAP24_I2C_SLAVE +#endif -int i2c_get_bus_num(void) -{ - return (int) current_bus; -} +U_BOOT_I2C_ADAP_COMPLETE(omap24_3, omap24_i2c_init, omap24_i2c_probe, + omap24_i2c_read, omap24_i2c_write, NULL, + CONFIG_SYS_OMAP24_I2C_SPEED3, + CONFIG_SYS_OMAP24_I2C_SLAVE3, + 3) +#if (I2C_BUS_MAX > 4) +#if !defined(CONFIG_SYS_OMAP24_I2C_SPEED4) +#define CONFIG_SYS_OMAP24_I2C_SPEED4 CONFIG_SYS_OMAP24_I2C_SPEED +#endif +#if !defined(CONFIG_SYS_OMAP24_I2C_SLAVE4) +#define CONFIG_SYS_OMAP24_I2C_SLAVE4 CONFIG_SYS_OMAP24_I2C_SLAVE +#endif + +U_BOOT_I2C_ADAP_COMPLETE(omap24_4, omap24_i2c_init, omap24_i2c_probe, + omap24_i2c_read, omap24_i2c_write, NULL, + CONFIG_SYS_OMAP24_I2C_SPEED4, + CONFIG_SYS_OMAP24_I2C_SLAVE4, + 4) +#endif +#endif +#endif -- cgit v1.1 From 0bdffe71fddeaa46768a39305797e4512dee0f15 Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Fri, 8 Nov 2013 07:30:53 +0100 Subject: i2c, zynq: convert zynq i2c driver to new multibus/multiadapter framework - add zync i2c driver to new multibus/multiadpater support - adapted all config files, which uses this driver Signed-off-by: Heiko Schocher Cc: Joe Hershberger Cc: Michal Simek --- drivers/i2c/Makefile | 2 +- drivers/i2c/zynq_i2c.c | 29 ++++++++++++++++------------- 2 files changed, 17 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 298b17b..9dd9094 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -28,4 +28,4 @@ obj-$(CONFIG_SYS_I2C_RCAR) += rcar_i2c.o obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o -obj-$(CONFIG_ZYNQ_I2C) += zynq_i2c.o +obj-$(CONFIG_SYS_I2C_ZYNQ) += zynq_i2c.o diff --git a/drivers/i2c/zynq_i2c.c b/drivers/i2c/zynq_i2c.c index ce2d23f..70a9aea 100644 --- a/drivers/i2c/zynq_i2c.c +++ b/drivers/i2c/zynq_i2c.c @@ -74,7 +74,8 @@ static struct zynq_i2c_registers *zynq_i2c = (struct zynq_i2c_registers *)ZYNQ_I2C_BASE; /* I2C init called by cmd_i2c when doing 'i2c reset'. */ -void i2c_init(int requested_speed, int slaveadd) +static void zynq_i2c_init(struct i2c_adapter *adap, int requested_speed, + int slaveadd) { /* 111MHz / ( (3 * 17) * 22 ) = ~100KHz */ writel((16 << ZYNQ_I2C_CONTROL_DIV_B_SHIFT) | @@ -151,7 +152,7 @@ static u32 zynq_i2c_wait(u32 mask) * I2C probe called by cmd_i2c when doing 'i2c probe'. * Begin read, nak data byte, end. */ -int i2c_probe(u8 dev) +static int zynq_i2c_probe(struct i2c_adapter *adap, u8 dev) { /* Attempt to read a byte */ setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO | @@ -170,7 +171,8 @@ int i2c_probe(u8 dev) * I2C read called by cmd_i2c when doing 'i2c read' and by cmd_eeprom.c * Begin write, send address byte(s), begin read, receive data bytes, end. */ -int i2c_read(u8 dev, uint addr, int alen, u8 *data, int length) +static int zynq_i2c_read(struct i2c_adapter *adap, u8 dev, uint addr, + int alen, u8 *data, int length) { u32 status; u32 i = 0; @@ -235,7 +237,8 @@ int i2c_read(u8 dev, uint addr, int alen, u8 *data, int length) * I2C write called by cmd_i2c when doing 'i2c write' and by cmd_eeprom.c * Begin write, send address byte(s), send data bytes, end. */ -int i2c_write(u8 dev, uint addr, int alen, u8 *data, int length) +static int zynq_i2c_write(struct i2c_adapter *adap, u8 dev, uint addr, + int alen, u8 *data, int length) { u8 *cur_data = data; @@ -275,16 +278,16 @@ int i2c_write(u8 dev, uint addr, int alen, u8 *data, int length) return 0; } -int i2c_set_bus_num(unsigned int bus) +static unsigned int zynq_i2c_set_bus_speed(struct i2c_adapter *adap, + unsigned int speed) { - /* Only support bus 0 */ - if (bus > 0) - return -1; - return 0; -} + if (speed != 1000000) + return -EINVAL; -unsigned int i2c_get_bus_num(void) -{ - /* Only support bus 0 */ return 0; } + +U_BOOT_I2C_ADAP_COMPLETE(zynq_0, zynq_i2c_init, zynq_i2c_probe, zynq_i2c_read, + zynq_i2c_write, zynq_i2c_set_bus_speed, + CONFIG_SYS_I2C_ZYNQ_SPEED, CONFIG_SYS_I2C_ZYNQ_SLAVE, + 0) -- cgit v1.1 From 85bb251b393470c6d2a91b8f0f92b9f3fda856ca Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Fri, 8 Nov 2013 08:33:22 +0100 Subject: i2c, omap1510: remove i2c driver remove omap1510 i2c driver, as there is no board which uses it Signed-off-by: Heiko Schocher Cc: Tom Rini Cc: Jian Zhang --- drivers/i2c/Makefile | 1 - drivers/i2c/omap1510_i2c.c | 277 --------------------------------------------- 2 files changed, 278 deletions(-) delete mode 100644 drivers/i2c/omap1510_i2c.c (limited to 'drivers') diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 9dd9094..553b519 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -11,7 +11,6 @@ obj-$(CONFIG_DW_I2C) += designware_i2c.o obj-$(CONFIG_I2C_MVTWSI) += mvtwsi.o obj-$(CONFIG_I2C_MV) += mv_i2c.o obj-$(CONFIG_I2C_MXS) += mxs_i2c.o -obj-$(CONFIG_DRIVER_OMAP1510_I2C) += omap1510_i2c.o obj-$(CONFIG_PCA9564_I2C) += pca9564_i2c.o obj-$(CONFIG_DRIVER_S3C24X0_I2C) += s3c24x0_i2c.o obj-$(CONFIG_TSI108_I2C) += tsi108_i2c.o diff --git a/drivers/i2c/omap1510_i2c.c b/drivers/i2c/omap1510_i2c.c deleted file mode 100644 index f91ee88..0000000 --- a/drivers/i2c/omap1510_i2c.c +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Basic I2C functions - * - * Copyright (c) 2003 Texas Instruments - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the license found in the file - * named COPYING that should have accompanied this file. - * - * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: Jian Zhang jzhang@ti.com, Texas Instruments - * - * Copyright (c) 2003 Wolfgang Denk, wd@denx.de - * Rewritten to fit into the current U-Boot framework - * - */ - -#include - -static void wait_for_bb (void); -static u16 wait_for_pin (void); - -void i2c_init (int speed, int slaveadd) -{ - u16 scl; - - if (inw (I2C_CON) & I2C_CON_EN) { - outw (0, I2C_CON); - udelay (5000); - } - - /* 12MHz I2C module clock */ - outw (0, I2C_PSC); - outw (I2C_CON_EN, I2C_CON); - outw (0, I2C_SYSTEST); - /* have to enable intrrupts or OMAP i2c module doesn't work */ - outw (I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | - I2C_IE_NACK_IE | I2C_IE_AL_IE, I2C_IE); - scl = (12000000 / 2) / speed - 6; - outw (scl, I2C_SCLL); - outw (scl, I2C_SCLH); - /* own address */ - outw (slaveadd, I2C_OA); - outw (0, I2C_CNT); - udelay (1000); -} - -static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value) -{ - int i2c_error = 0; - u16 status; - - /* wait until bus not busy */ - wait_for_bb (); - - /* one byte only */ - outw (1, I2C_CNT); - /* set slave address */ - outw (devaddr, I2C_SA); - /* no stop bit needed here */ - outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX, I2C_CON); - - status = wait_for_pin (); - - if (status & I2C_STAT_XRDY) { - /* Important: have to use byte access */ - *(volatile u8 *) (I2C_DATA) = regoffset; - udelay (20000); - if (inw (I2C_STAT) & I2C_STAT_NACK) { - i2c_error = 1; - } - } else { - i2c_error = 1; - } - - if (!i2c_error) { - /* free bus, otherwise we can't use a combined transction */ - outw (0, I2C_CON); - while (inw (I2C_STAT) || (inw (I2C_CON) & I2C_CON_MST)) { - udelay (10000); - /* Have to clear pending interrupt to clear I2C_STAT */ - inw (I2C_IV); - } - - wait_for_bb (); - /* set slave address */ - outw (devaddr, I2C_SA); - /* read one byte from slave */ - outw (1, I2C_CNT); - /* need stop bit here */ - outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, - I2C_CON); - - status = wait_for_pin (); - if (status & I2C_STAT_RRDY) { - *value = inw (I2C_DATA); - udelay (20000); - } else { - i2c_error = 1; - } - - if (!i2c_error) { - outw (I2C_CON_EN, I2C_CON); - while (inw (I2C_STAT) - || (inw (I2C_CON) & I2C_CON_MST)) { - udelay (10000); - inw (I2C_IV); - } - } - } - - return i2c_error; -} - -static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value) -{ - int i2c_error = 0; - u16 status; - - /* wait until bus not busy */ - wait_for_bb (); - - /* two bytes */ - outw (2, I2C_CNT); - /* set slave address */ - outw (devaddr, I2C_SA); - /* stop bit needed here */ - outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | - I2C_CON_STP, I2C_CON); - - /* wait until state change */ - status = wait_for_pin (); - - if (status & I2C_STAT_XRDY) { - /* send out two bytes */ - outw ((value << 8) + regoffset, I2C_DATA); - /* must have enough delay to allow BB bit to go low */ - udelay (30000); - if (inw (I2C_STAT) & I2C_STAT_NACK) { - i2c_error = 1; - } - } else { - i2c_error = 1; - } - - if (!i2c_error) { - outw (I2C_CON_EN, I2C_CON); - while (inw (I2C_STAT) || (inw (I2C_CON) & I2C_CON_MST)) { - udelay (1000); - /* have to read to clear intrrupt */ - inw (I2C_IV); - } - } - - return i2c_error; -} - -int i2c_probe (uchar chip) -{ - int res = 1; - - if (chip == inw (I2C_OA)) { - return res; - } - - /* wait until bus not busy */ - wait_for_bb (); - - /* try to read one byte */ - outw (1, I2C_CNT); - /* set slave address */ - outw (chip, I2C_SA); - /* stop bit needed here */ - outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, I2C_CON); - /* enough delay for the NACK bit set */ - udelay (2000); - if (!(inw (I2C_STAT) & I2C_STAT_NACK)) { - res = 0; - } else { - outw (inw (I2C_CON) | I2C_CON_STP, I2C_CON); - udelay (20); - wait_for_bb (); - } - - return res; -} - -int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len) -{ - int i; - - if (alen > 1) { - printf ("I2C read: addr len %d not supported\n", alen); - return 1; - } - - if (addr + len > 256) { - printf ("I2C read: address out of range\n"); - return 1; - } - - for (i = 0; i < len; i++) { - if (i2c_read_byte (chip, addr + i, &buffer[i])) { - printf ("I2C read: I/O error\n"); - i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); - return 1; - } - } - - return 0; -} - -int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len) -{ - int i; - - if (alen > 1) { - printf ("I2C read: addr len %d not supported\n", alen); - return 1; - } - - if (addr + len > 256) { - printf ("I2C read: address out of range\n"); - return 1; - } - - for (i = 0; i < len; i++) { - if (i2c_write_byte (chip, addr + i, buffer[i])) { - printf ("I2C read: I/O error\n"); - i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); - return 1; - } - } - - return 0; -} - -static void wait_for_bb (void) -{ - int timeout = 10; - - while ((inw (I2C_STAT) & I2C_STAT_BB) && timeout--) { - inw (I2C_IV); - udelay (1000); - } - - if (timeout <= 0) { - printf ("timed out in wait_for_bb: I2C_STAT=%x\n", - inw (I2C_STAT)); - } -} - -static u16 wait_for_pin (void) -{ - u16 status, iv; - int timeout = 10; - - do { - udelay (1000); - status = inw (I2C_STAT); - iv = inw (I2C_IV); - } while (!iv && - !(status & - (I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY | - I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK | - I2C_STAT_AL)) && timeout--); - - if (timeout <= 0) { - printf ("timed out in wait_for_pin: I2C_STAT=%x\n", - inw (I2C_STAT)); - } - - return status; -} -- cgit v1.1 From 8b7c87253960aac0b670e606d8dbe2f64b1e5652 Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Thu, 7 Nov 2013 17:52:18 +0400 Subject: designware_i2c: disable i2c controller during target address setup As it is stated in DesignWare I2C databook: writes to IC_TAR (0x4) register succeed only when IC_ENABLE[0] is set to 0. Signed-off-by: Alexey Brodkin Cc: Tom Rini cc: Armando Visconti Cc: Stefan Roese Cc: Albert ARIBAUD Cc: Heiko Schocher Cc: Vipin KUMAR Cc: Tom Rix Cc: Mischa Jonker --- drivers/i2c/designware_i2c.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c index c2f0662..c5c6015 100644 --- a/drivers/i2c/designware_i2c.c +++ b/drivers/i2c/designware_i2c.c @@ -151,7 +151,19 @@ void i2c_init(int speed, int slaveadd) */ static void i2c_setaddress(unsigned int i2c_addr) { + unsigned int enbl; + + /* Disable i2c */ + enbl = readl(&i2c_regs_p->ic_enable); + enbl &= ~IC_ENABLE_0B; + writel(enbl, &i2c_regs_p->ic_enable); + writel(i2c_addr, &i2c_regs_p->ic_tar); + + /* Enable i2c */ + enbl = readl(&i2c_regs_p->ic_enable); + enbl |= IC_ENABLE_0B; + writel(enbl, &i2c_regs_p->ic_enable); } /* -- cgit v1.1 From f9de54e9b09b4836fb3cda9d98a6dfba367b9734 Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Thu, 7 Nov 2013 17:52:33 +0400 Subject: designware_i2c: remove 10msec delay in i2c_xfer_finish This delay applies to any data transfer on I2C bus. For example 1kB data read with per-byte access (which happens if environment is stored in I2C EEPROM) takes more than 10 seconds. Moreover data bus driver has to care about bus state and data transfer, but not about internal states of attached devices. Signed-off-by: Alexey Brodkin Cc: Tom Rini cc: Armando Visconti Cc: Stefan Roese Cc: Albert ARIBAUD Cc: Heiko Schocher Cc: Vipin KUMAR Cc: Tom Rix Cc: Mischa Jonker --- drivers/i2c/designware_i2c.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c index c5c6015..cb2ac04 100644 --- a/drivers/i2c/designware_i2c.c +++ b/drivers/i2c/designware_i2c.c @@ -249,9 +249,6 @@ static int i2c_xfer_finish(void) i2c_flush_rxfifo(); - /* Wait for read/write operation to complete on actual memory */ - udelay(10000); - return 0; } -- cgit v1.1 From 2967af6816a2b5b549a3377edf41781a51d00003 Mon Sep 17 00:00:00 2001 From: Priyanka Jain Date: Fri, 18 Oct 2013 12:30:21 +0530 Subject: powerpc/t1040: Update defines to support T1040SoC personalities T1040 Soc has four personalities: -T1040 (4 cores with L2 switch) -T1042:Reduced personality of T1040 without L2 switch -T1020:Reduced personality of T1040 with less cores(2 cores) -T1022:Reduced personality of T1040 with 2 cores and without L2 switch Update defines in arch/powerpc header files, Makefiles and in driver/net/fm/Makefile to support all T1040 personalities Signed-off-by: Poonam Aggrwal Signed-off-by: Priyanka Jain [York Sun: fixed Makefiles] Acked-by: York Sun --- drivers/net/fm/Makefile | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/fm/Makefile b/drivers/net/fm/Makefile index bec86c1..2efba76 100644 --- a/drivers/net/fm/Makefile +++ b/drivers/net/fm/Makefile @@ -26,6 +26,9 @@ obj-$(CONFIG_PPC_P4080) += p4080.o obj-$(CONFIG_PPC_P5020) += p5020.o obj-$(CONFIG_PPC_P5040) += p5040.o obj-$(CONFIG_PPC_T1040) += t1040.o +obj-$(CONFIG_PPC_T1042) += t1040.o +obj-$(CONFIG_PPC_T1020) += t1040.o +obj-$(CONFIG_PPC_T1022) += t1040.o obj-$(CONFIG_PPC_T4240) += t4240.o obj-$(CONFIG_PPC_T4160) += t4240.o obj-$(CONFIG_PPC_B4420) += b4860.o -- cgit v1.1 From 7604a3f920031aa6f3426eedf44494b69ae291e1 Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Wed, 28 Aug 2013 14:54:26 +0000 Subject: MTD: atmel_nand: support for software BCH ECC Add possible to use software BCH ECC for atmel nand driver Signed-off-by: Bo Shen --- drivers/mtd/nand/atmel_nand.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index da83f06..10011c6 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1178,7 +1178,11 @@ int atmel_nand_chip_init(int devnum, ulong base_addr) mtd->priv = nand; nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr; +#ifdef CONFIG_NAND_ECC_BCH + nand->ecc.mode = NAND_ECC_SOFT_BCH; +#else nand->ecc.mode = NAND_ECC_SOFT; +#endif #ifdef CONFIG_SYS_NAND_DBW_16 nand->options = NAND_BUSWIDTH_16; #endif -- cgit v1.1 From ed5ac34a33821809ddee6307aa6dc80aeb0245a7 Mon Sep 17 00:00:00 2001 From: Prabhakar Kushwaha Date: Thu, 3 Oct 2013 11:35:35 +0530 Subject: driver/mtd/ifc: Read Status while programming NAND flash as per controller description, "While programming a NAND flash, status read should never skipped. Because it may happen that a new command is issued to the NAND Flash, even when the device has not yet finished processing the previous request. This may result in unpredictable behaviour." IFC controller never polls for R/B signal after command send. It just return control to software. This behaviour may not occur with NAND flash access. because new commands are sent after polling R/B signal. But it may happen in scenario where GPCM-ASIC and NAND flash device are working simultaneously. Update the controller driver to take care of this requirement Signed-off-by: Prabhakar Kushwaha --- drivers/mtd/nand/fsl_ifc_nand.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 98a09c0..1d18815 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -428,20 +428,27 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, if (mtd->writesize > 512) { nand_fcr0 = (NAND_CMD_SEQIN << IFC_NAND_FCR0_CMD0_SHIFT) | - (NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD1_SHIFT); + (NAND_CMD_STATUS << IFC_NAND_FCR0_CMD1_SHIFT) | + (NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD2_SHIFT); out_be32(&ifc->ifc_nand.nand_fir0, (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP3_SHIFT) | - (IFC_FIR_OP_CW1 << IFC_NAND_FIR0_OP4_SHIFT)); - out_be32(&ifc->ifc_nand.nand_fir1, 0); + (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP4_SHIFT)); + out_be32(&ifc->ifc_nand.nand_fir1, + (IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT) | + (IFC_FIR_OP_RDSTAT << + IFC_NAND_FIR1_OP6_SHIFT) | + (IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP7_SHIFT)); } else { nand_fcr0 = ((NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD1_SHIFT) | (NAND_CMD_SEQIN << - IFC_NAND_FCR0_CMD2_SHIFT)); + IFC_NAND_FCR0_CMD2_SHIFT) | + (NAND_CMD_STATUS << + IFC_NAND_FCR0_CMD3_SHIFT)); out_be32(&ifc->ifc_nand.nand_fir0, (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | @@ -450,7 +457,11 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) | (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT)); out_be32(&ifc->ifc_nand.nand_fir1, - (IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT)); + (IFC_FIR_OP_CMD1 << IFC_NAND_FIR1_OP5_SHIFT) | + (IFC_FIR_OP_CW3 << IFC_NAND_FIR1_OP6_SHIFT) | + (IFC_FIR_OP_RDSTAT << + IFC_NAND_FIR1_OP7_SHIFT) | + (IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP8_SHIFT)); if (column >= mtd->writesize) nand_fcr0 |= -- cgit v1.1 From 7b6af41ef342199e4967735ea17424b42ed742d2 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 11 Nov 2013 14:35:51 +0900 Subject: drivers: descend into sub directories only when it is necessary - Descend into drivers/fpga/ only when CONFIG_FPGA=y - Descend into drivers/bios_emulator only when CONFIG_BIOSEMU=y Signed-off-by: Masahiro Yamada --- drivers/Makefile | 4 ++-- drivers/bios_emulator/Makefile | 2 +- drivers/fpga/Makefile | 2 -- 3 files changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/Makefile b/drivers/Makefile index 9cec2ba..95a4b80 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -1,8 +1,8 @@ -obj-y += bios_emulator/ +obj-$(CONFIG_BIOSEMU) += bios_emulator/ obj-y += block/ obj-$(CONFIG_BOOTCOUNT_LIMIT) += bootcount/ obj-y += crypto/ -obj-y += fpga/ +obj-$(CONFIG_FPGA) += fpga/ obj-y += hwmon/ obj-y += misc/ obj-y += pcmcia/ diff --git a/drivers/bios_emulator/Makefile b/drivers/bios_emulator/Makefile index dd42e0f..9aa8ea9 100644 --- a/drivers/bios_emulator/Makefile +++ b/drivers/bios_emulator/Makefile @@ -2,7 +2,7 @@ X86DIR = x86emu $(shell mkdir -p $(obj)$(X86DIR)) -obj-$(CONFIG_BIOSEMU) = atibios.o biosemu.o besys.o bios.o \ +obj-y = atibios.o biosemu.o besys.o bios.o \ $(X86DIR)/decode.o \ $(X86DIR)/ops2.o \ $(X86DIR)/ops.o \ diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index 4fcdf40..dfb2e7f 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -5,7 +5,6 @@ # SPDX-License-Identifier: GPL-2.0+ # -ifdef CONFIG_FPGA obj-y += fpga.o obj-$(CONFIG_FPGA_SPARTAN2) += spartan2.o obj-$(CONFIG_FPGA_SPARTAN3) += spartan3.o @@ -19,4 +18,3 @@ obj-$(CONFIG_FPGA_ACEX1K) += ACEX1K.o obj-$(CONFIG_FPGA_CYCLON2) += cyclon2.o obj-$(CONFIG_FPGA_STRATIX_II) += stratixII.o endif -endif -- cgit v1.1 From 36cf0a845c869c514a6cc20a953c53a086251d2f Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 11 Nov 2013 14:35:53 +0900 Subject: drivers: tpm: clean up unused code Signed-off-by: Masahiro Yamada --- drivers/tpm/Makefile | 2 - drivers/tpm/tis_i2c.c | 185 -------------------------------------------------- 2 files changed, 187 deletions(-) delete mode 100644 drivers/tpm/tis_i2c.c (limited to 'drivers') diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile index 4b8cbec..2f2353f 100644 --- a/drivers/tpm/Makefile +++ b/drivers/tpm/Makefile @@ -3,8 +3,6 @@ # SPDX-License-Identifier: GPL-2.0+ # -$(shell mkdir -p $(obj)slb9635_i2c) - # TODO: Merge tpm_tis_lpc.c with tpm.c obj-$(CONFIG_TPM_ATMEL_TWI) += tpm_atmel_twi.o obj-$(CONFIG_TPM_TIS_I2C) += tpm.o diff --git a/drivers/tpm/tis_i2c.c b/drivers/tpm/tis_i2c.c deleted file mode 100644 index 22554e1..0000000 --- a/drivers/tpm/tis_i2c.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2012 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include -#include -#include -#include -#include "slb9635_i2c/tpm.h" - -DECLARE_GLOBAL_DATA_PTR; - -/* TPM configuration */ -struct tpm { - int i2c_bus; - int slave_addr; - char inited; - int old_bus; -} tpm; - - -static int tpm_select(void) -{ - int ret; - - tpm.old_bus = i2c_get_bus_num(); - if (tpm.old_bus != tpm.i2c_bus) { - ret = i2c_set_bus_num(tpm.i2c_bus); - if (ret) { - debug("%s: Fail to set i2c bus %d\n", __func__, - tpm.i2c_bus); - return -1; - } - } - return 0; -} - -static int tpm_deselect(void) -{ - int ret; - - if (tpm.old_bus != i2c_get_bus_num()) { - ret = i2c_set_bus_num(tpm.old_bus); - if (ret) { - debug("%s: Fail to restore i2c bus %d\n", - __func__, tpm.old_bus); - return -1; - } - } - tpm.old_bus = -1; - return 0; -} - -/** - * Decode TPM configuration. - * - * @param dev Returns a configuration of TPM device - * @return 0 if ok, -1 on error - */ -static int tpm_decode_config(struct tpm *dev) -{ -#ifdef CONFIG_OF_CONTROL - const void *blob = gd->fdt_blob; - int node, parent; - int i2c_bus; - - node = fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9635_TPM); - if (node < 0) { - node = fdtdec_next_compatible(blob, 0, - COMPAT_INFINEON_SLB9645_TPM); - } - if (node < 0) { - debug("%s: Node not found\n", __func__); - return -1; - } - parent = fdt_parent_offset(blob, node); - if (parent < 0) { - debug("%s: Cannot find node parent\n", __func__); - return -1; - } - i2c_bus = i2c_get_bus_num_fdt(parent); - if (i2c_bus < 0) - return -1; - dev->i2c_bus = i2c_bus; - dev->slave_addr = fdtdec_get_addr(blob, node, "reg"); -#else - dev->i2c_bus = CONFIG_INFINEON_TPM_I2C_BUS; - dev->slave_addr = CONFIG_INFINEON_TPM_I2C_ADDR; -#endif - return 0; -} - -int tis_init(void) -{ - if (tpm.inited) - return 0; - - if (tpm_decode_config(&tpm)) - return -1; - - if (tpm_select()) - return -1; - - /* - * Probe TPM twice; the first probing might fail because TPM is asleep, - * and the probing can wake up TPM. - */ - if (i2c_probe(tpm.slave_addr) && i2c_probe(tpm.slave_addr)) { - debug("%s: fail to probe i2c addr 0x%x\n", __func__, - tpm.slave_addr); - return -1; - } - - tpm_deselect(); - - tpm.inited = 1; - - return 0; -} - -int tis_open(void) -{ - int rc; - - if (!tpm.inited) - return -1; - - if (tpm_select()) - return -1; - - rc = tpm_open(tpm.slave_addr); - - tpm_deselect(); - - return rc; -} - -int tis_close(void) -{ - if (!tpm.inited) - return -1; - - if (tpm_select()) - return -1; - - tpm_close(); - - tpm_deselect(); - - return 0; -} - -int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size, - uint8_t *recvbuf, size_t *rbuf_len) -{ - int len; - uint8_t buf[4096]; - - if (!tpm.inited) - return -1; - - if (sizeof(buf) < sbuf_size) - return -1; - - memcpy(buf, sendbuf, sbuf_size); - - if (tpm_select()) - return -1; - - len = tpm_transmit(buf, sbuf_size); - - tpm_deselect(); - - if (len < 10) { - *rbuf_len = 0; - return -1; - } - - memcpy(recvbuf, buf, len); - *rbuf_len = len; - - return 0; -} -- cgit v1.1 From e5c5301f1444ea454d17a368bb5138e0f3a59247 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 11 Nov 2013 14:35:54 +0900 Subject: Makefile: make directories by Makefile.build Signed-off-by: Masahiro Yamada --- drivers/bios_emulator/Makefile | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/bios_emulator/Makefile b/drivers/bios_emulator/Makefile index 9aa8ea9..6f74fdc 100644 --- a/drivers/bios_emulator/Makefile +++ b/drivers/bios_emulator/Makefile @@ -1,7 +1,5 @@ X86DIR = x86emu -$(shell mkdir -p $(obj)$(X86DIR)) - obj-y = atibios.o biosemu.o besys.o bios.o \ $(X86DIR)/decode.o \ $(X86DIR)/ops2.o \ -- cgit v1.1 From 4c76b552313f3a12a38789afa828c6a7e9e71d7a Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 11 Nov 2013 14:35:57 +0900 Subject: drivers/qe: move the entry to drivers/Makefile Signed-off-by: Masahiro Yamada --- drivers/Makefile | 1 + drivers/qe/Makefile | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/Makefile b/drivers/Makefile index 95a4b80..5d03f37 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -13,3 +13,4 @@ obj-y += tpm/ obj-y += twserial/ obj-y += video/ obj-y += watchdog/ +obj-$(CONFIG_QE) += qe/ diff --git a/drivers/qe/Makefile b/drivers/qe/Makefile index b8c15f8..7f1bd06 100644 --- a/drivers/qe/Makefile +++ b/drivers/qe/Makefile @@ -4,5 +4,5 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-$(and $(CONFIG_QE),$(CONFIG_OF_LIBFDT)) += fdt.o -obj-$(CONFIG_QE) += qe.o uccf.o uec.o uec_phy.o +obj-y := qe.o uccf.o uec.o uec_phy.o +obj-$(CONFIG_OF_LIBFDT) += fdt.o -- cgit v1.1 From fc9ac3565a80d571def4f2eae4ad10c4ed90cbb2 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 11 Nov 2013 14:35:58 +0900 Subject: drivers/net/fm: descend only when CONFIG_FMAN_ENET=y CONFIG_FMAN_ENET is defined only for CPU mpc85xx. We do not need to filter by CPU mpc85xx. Signed-off-by: Masahiro Yamada --- drivers/net/fm/Makefile | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fm/Makefile b/drivers/net/fm/Makefile index 2efba76..d0fd7fc 100644 --- a/drivers/net/fm/Makefile +++ b/drivers/net/fm/Makefile @@ -4,7 +4,6 @@ # SPDX-License-Identifier: GPL-2.0+ # -ifdef CONFIG_FMAN_ENET obj-y += dtsec.o obj-y += eth.o obj-y += fm.o @@ -33,4 +32,3 @@ obj-$(CONFIG_PPC_T4240) += t4240.o obj-$(CONFIG_PPC_T4160) += t4240.o obj-$(CONFIG_PPC_B4420) += b4860.o obj-$(CONFIG_PPC_B4860) += b4860.o -endif -- cgit v1.1 From fdd91faef9148fd5a52467a91f79934ee4e7f2bd Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 11 Nov 2013 14:35:59 +0900 Subject: drivers/net/npe: descend only when CONFIG_IXP4XX_NPE=y CONFIG_IXP4XX_NPE is defined only for CPU ixp. It is not necessary to filter by CPU ixp. Signed-off-by: Masahiro Yamada --- drivers/net/npe/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/npe/Makefile b/drivers/net/npe/Makefile index 7fa5ea6..e36c0bb 100644 --- a/drivers/net/npe/Makefile +++ b/drivers/net/npe/Makefile @@ -10,7 +10,7 @@ CFLAGS += $(LOCAL_CFLAGS) CPPFLAGS += $(LOCAL_CFLAGS) # needed for depend HOSTCFLAGS += $(LOCAL_CFLAGS) -obj-$(CONFIG_IXP4XX_NPE) := npe.o \ +obj-y := npe.o \ miiphy.o \ IxOsalBufferMgt.o \ IxOsalIoMem.o \ -- cgit v1.1 From 68ec9c85a9d334c7598b4972af037de05c034f8d Mon Sep 17 00:00:00 2001 From: Prabhakar Kushwaha Date: Fri, 4 Oct 2013 13:47:58 +0530 Subject: mtd: move & update nand_ecclayout structure (plus board changes) nand_ecclayout is present in mtd.h at Linux. Move this structure to mtd.h to comply with Linux. Also, increase the ecc placement locations to 640 to suport device having writesize/oobsize of 8KB/640B. This means that the maximum oobsize has gone up to 640 bytes and consequently the maximum ecc placement locations have also gone up to 640. Changes from Prabhabkar's version (squashed into one patch to preserve bisectability): - Added _LARGE to MTD_MAX_*_ENTRIES This makes the names match current Linux source, and resolves a conflict between http://patchwork.ozlabs.org/patch/280488/ and http://patchwork.ozlabs.org/patch/284513/ The former was posted first and is closer to matching Linux, but unlike Linux it does not add _LARGE to the names. The second adds _LARGE to one of the names, and depends on it in a subsequent patch (http://patchwork.ozlabs.org/patch/284512/). - Made max oobfree/eccpos configurable, and used this on tricorder, alpr, ASH405, T4160QDS, and T4240QDS (these boards failed to build for me without doing so, due to a size increase). On tricorder SPL, this saves 2576 bytes (and makes the SPL build again) versus the new default of 640 eccpos and 32 oobfree, and saves 336 bytes versus the old default of 128 eccpos and 8 oobfree. Signed-off-by: Prabhakar Kushwaha CC: Vipin Kumar [scottwood@freescale.com: changes as described above] Signed-off-by: Scott Wood Cc: Thomas Weber Cc: Matthias Fuchs Cc: Stefan Roese Cc: York Sun Cc: Tom Rini Reviewed-by: Stefan Roese --- drivers/mtd/onenand/onenand_base.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 067f8ef..979e4af 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -761,7 +761,8 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, uint8_t *oob_buf = this->oob_buf; free = this->ecclayout->oobfree; - for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { + for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE && free->length; + i++, free++) { if (readcol >= lastgap) readcol += free->offset - lastgap; if (readend >= lastgap) @@ -770,7 +771,8 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, } this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); free = this->ecclayout->oobfree; - for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { + for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE && free->length; + i++, free++) { int free_end = free->offset + free->length; if (free->offset < readend && free_end > readcol) { int st = max_t(int,free->offset,readcol); @@ -1356,7 +1358,8 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, unsigned int i; free = this->ecclayout->oobfree; - for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { + for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE && free->length; + i++, free++) { if (writecol >= lastgap) writecol += free->offset - lastgap; if (writeend >= lastgap) @@ -1364,7 +1367,8 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, lastgap = free->offset + free->length; } free = this->ecclayout->oobfree; - for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { + for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE && free->length; + i++, free++) { int free_end = free->offset + free->length; if (free->offset < writeend && free_end > writecol) { int st = max_t(int,free->offset,writecol); @@ -2750,7 +2754,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) * the out of band area */ this->ecclayout->oobavail = 0; - for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && + + for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE && this->ecclayout->oobfree[i].length; i++) this->ecclayout->oobavail += this->ecclayout->oobfree[i].length; -- cgit v1.1 From 71220f80e7489b7fc1766f573ae89c64db2419ce Mon Sep 17 00:00:00 2001 From: Prabhakar Kushwaha Date: Fri, 4 Oct 2013 10:05:36 +0530 Subject: mtd/ifc: Add support of 8K page size NAND flash Current IFC driver supports till 4K page size NAND flash. Add support of 8K NAND flash - Program Spare region size in csor_ext - Add nand_ecclayout for 4 bit & 8 bit ecc - Defines constants - Add support of 8K NAND boot. Signed-off-by: Prabhakar Kushwaha CC: Liu Po --- drivers/mtd/nand/fsl_ifc_nand.c | 78 +++++++++++++++++++++++++++++++++++++++++ drivers/mtd/nand/fsl_ifc_spl.c | 7 ++-- 2 files changed, 83 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 1d18815..49b63af 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -125,6 +125,69 @@ static struct nand_ecclayout oob_4096_ecc8 = { .oobfree = { {2, 6}, {136, 82} }, }; +/* 8192-byte page size with 4-bit ECC */ +static struct nand_ecclayout oob_8192_ecc4 = { + .eccbytes = 128, + .eccpos = { + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, + }, + .oobfree = { {2, 6}, {136, 208} }, +}; + +/* 8192-byte page size with 8-bit ECC -- requires 218-byte OOB */ +static struct nand_ecclayout oob_8192_ecc8 = { + .eccbytes = 256, + .eccpos = { + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, + 248, 249, 250, 251, 252, 253, 254, 255, + 256, 257, 258, 259, 260, 261, 262, 263, + }, + .oobfree = { {2, 6}, {264, 80} }, +}; /* * Generic flash bbt descriptors @@ -913,6 +976,21 @@ static int fsl_ifc_chip_init(int devnum, u8 *addr) priv->bufnum_mask = 1; break; + case CSOR_NAND_PGS_8K: + if ((csor & CSOR_NAND_ECC_MODE_MASK) == + CSOR_NAND_ECC_MODE_4) { + layout = &oob_8192_ecc4; + nand->ecc.strength = 4; + } else { + layout = &oob_8192_ecc8; + nand->ecc.strength = 8; + nand->ecc.bytes = 16; + } + + priv->bufnum_mask = 0; + break; + + default: printf("ifc nand: bad csor %#x: bad page size\n", csor); return -ENODEV; diff --git a/drivers/mtd/nand/fsl_ifc_spl.c b/drivers/mtd/nand/fsl_ifc_spl.c index d462265..9fa5ccb 100644 --- a/drivers/mtd/nand/fsl_ifc_spl.c +++ b/drivers/mtd/nand/fsl_ifc_spl.c @@ -112,10 +112,13 @@ static void nand_load(unsigned int offs, int uboot_size, uchar *dst) port_size = (cspr & CSPR_PORT_SIZE_16) ? 16 : 8; - if (csor & CSOR_NAND_PGS_4K) { + if ((csor & CSOR_NAND_PGS_MASK) == CSOR_NAND_PGS_8K) { + page_size = 8192; + bufnum_mask = 0x0; + } else if ((csor & CSOR_NAND_PGS_MASK) == CSOR_NAND_PGS_4K) { page_size = 4096; bufnum_mask = 0x1; - } else if (csor & CSOR_NAND_PGS_2K) { + } else if ((csor & CSOR_NAND_PGS_MASK) == CSOR_NAND_PGS_2K) { page_size = 2048; bufnum_mask = 0x3; } else { -- cgit v1.1 From 16dddef6050471f47c84b6c929ae3c4bc9c0fb46 Mon Sep 17 00:00:00 2001 From: "Wu, Josh" Date: Fri, 18 Oct 2013 17:46:31 +0800 Subject: mtd: atmel_nand: enable PMECC support for 8k bytes page NAND flash increase the delay to 75us to support the 8k bytes page nand flash Signed-off-by: Josh Wu --- drivers/mtd/nand/atmel_nand.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 10011c6..1d8c860 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -827,6 +827,7 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand, switch (mtd->writesize) { case 2048: case 4096: + case 8192: host->pmecc_degree = (sector_size == 512) ? PMECC_GF_DIMENSION_13 : PMECC_GF_DIMENSION_14; host->pmecc_cw_len = (1 << host->pmecc_degree) - 1; @@ -840,6 +841,13 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand, nand->ecc.steps = 1; nand->ecc.bytes = host->pmecc_bytes_per_sector * host->pmecc_sector_number; + + if (nand->ecc.bytes > MTD_MAX_ECCPOS_ENTRIES_LARGE) { + dev_err(host->dev, "too large eccpos entries. max support ecc.bytes is %d\n", + MTD_MAX_ECCPOS_ENTRIES_LARGE); + return -EINVAL; + } + if (nand->ecc.bytes > mtd->oobsize - 2) { printk(KERN_ERR "No room for ECC bytes\n"); return -EINVAL; @@ -1190,7 +1198,7 @@ int atmel_nand_chip_init(int devnum, ulong base_addr) #ifdef CONFIG_SYS_NAND_READY_PIN nand->dev_ready = at91_nand_ready; #endif - nand->chip_delay = 20; + nand->chip_delay = 75; ret = nand_scan_ident(mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL); if (ret) -- cgit v1.1 From c55cc573eaf1ba7318b1b692c673a28b99f5195c Mon Sep 17 00:00:00 2001 From: "Wu, Josh" Date: Fri, 18 Oct 2013 17:46:33 +0800 Subject: mtd: atmel_nand: don't print bit correction message in driver Since for some MLC nand, bit errors happened too often. Just disable it to avoid noise Signed-off-by: Josh Wu --- drivers/mtd/nand/atmel_nand.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 1d8c860..92547432 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -452,7 +452,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, *(buf + byte_pos) ^= (1 << bit_pos); pos = sector_num * host->pmecc_sector_size + byte_pos; - printk(KERN_INFO "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", + dev_dbg(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", pos, bit_pos, err_byte, *(buf + byte_pos)); } else { /* Bit flip in OOB area */ @@ -462,7 +462,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, ecc[tmp] ^= (1 << bit_pos); pos = tmp + nand_chip->ecc.layout->eccpos[0]; - printk(KERN_INFO "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", + dev_dbg(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", pos, bit_pos, err_byte, ecc[tmp]); } -- cgit v1.1 From c0dc3dec697e930d290145e127a86ff31f7c2dde Mon Sep 17 00:00:00 2001 From: "Wu, Josh" Date: Fri, 18 Oct 2013 17:46:34 +0800 Subject: mtd: atmel_nand: use dev_xxx instead of printk Signed-off-by: Josh Wu --- drivers/mtd/nand/atmel_nand.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 92547432..16b7df0 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -412,7 +412,7 @@ static int pmecc_err_location(struct mtd_info *mtd) } if (!timeout) { - printk(KERN_ERR "atmel_nand : Timeout to calculate PMECC error location\n"); + dev_err(host->dev, "atmel_nand : Timeout to calculate PMECC error location\n"); return -1; } @@ -500,7 +500,7 @@ normal_check: err_nbr = pmecc_err_location(mtd); if (err_nbr == -1) { - printk(KERN_ERR "PMECC: Too many errors\n"); + dev_err(host->dev, "PMECC: Too many errors\n"); mtd->ecc_stats.failed++; return -EIO; } else { @@ -544,7 +544,7 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, } if (!timeout) { - printk(KERN_ERR "atmel_nand : Timeout to read PMECC page\n"); + dev_err(host->dev, "atmel_nand : Timeout to read PMECC page\n"); return -1; } @@ -584,7 +584,7 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, } if (!timeout) { - printk(KERN_ERR "atmel_nand : Timeout to read PMECC status, fail to write PMECC in oob\n"); + dev_err(host->dev, "atmel_nand : Timeout to read PMECC status, fail to write PMECC in oob\n"); goto out; } @@ -849,7 +849,7 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand, } if (nand->ecc.bytes > mtd->oobsize - 2) { - printk(KERN_ERR "No room for ECC bytes\n"); + dev_err(host->dev, "No room for ECC bytes\n"); return -EINVAL; } pmecc_config_ecc_layout(&atmel_pmecc_oobinfo, @@ -860,7 +860,7 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand, case 512: case 1024: /* TODO */ - printk(KERN_ERR "Unsupported page size for PMECC, use Software ECC\n"); + dev_err(host->dev, "Unsupported page size for PMECC, use Software ECC\n"); default: /* page size not handled by HW ECC */ /* switching back to soft ECC */ @@ -1043,7 +1043,7 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, /* it doesn't seems to be a freshly * erased block. * We can't correct so many errors */ - printk(KERN_WARNING "atmel_nand : multiple errors detected." + dev_warn(host->dev, "atmel_nand : multiple errors detected." " Unable to correct.\n"); return -EIO; } @@ -1053,12 +1053,12 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, /* there's nothing much to do here. * the bit error is on the ECC itself. */ - printk(KERN_WARNING "atmel_nand : one bit error on ECC code." + dev_warn(host->dev, "atmel_nand : one bit error on ECC code." " Nothing to correct\n"); return 0; } - printk(KERN_WARNING "atmel_nand : one bit error on data." + dev_warn(host->dev, "atmel_nand : one bit error on data." " (word offset in the page :" " 0x%x bit offset : 0x%x)\n", ecc_word, ecc_bit); @@ -1070,7 +1070,7 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, /* 8 bits words */ dat[ecc_word] ^= (1 << ecc_bit); } - printk(KERN_WARNING "atmel_nand : error corrected\n"); + dev_warn(host->dev, "atmel_nand : error corrected\n"); return 1; } @@ -1226,6 +1226,6 @@ void board_nand_init(void) int i; for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) if (atmel_nand_chip_init(i, base_addr[i])) - printk(KERN_ERR "atmel_nand: Fail to initialize #%d chip", + dev_err(host->dev, "atmel_nand: Fail to initialize #%d chip", i); } -- cgit v1.1 From beba5f04f2215c81016fbfb727257ea6667aca85 Mon Sep 17 00:00:00 2001 From: pekon gupta Date: Mon, 18 Nov 2013 19:02:59 +0530 Subject: mtd: nand: omap: make am33xx/elm.c as common driver for all OMAPx and AMxxxx platforms ELM hardware engine which is used for ECC error detection, is present on all latest OMAP SoC (like OMAP4xxx, OMAP5xxx, DRA7xxx, AM33xx, AM43xx). Thus ELM driver should be moved to common drivers/mtd/nand/ folder so that all SoC having on-chip ELM hardware engine can re-use it. This patch has following changes: - mv arch/arm/include/asm/arch-am33xx/elm.h arch/arm/include/asm/omap_elm.h - mv arch/arm/cpu/armv7/am33xx/elm.c drivers/mtd/nand/omap_elm.c - update Makefiles - update #include - add CONFIG_NAND_OMAP_ELM to compile driver/mtd/nand/omap_elm.c and include in all board configs using AM33xx SoC platform. Signed-off-by: Pekon Gupta --- drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/omap_elm.c | 196 +++++++++++++++++++++++++++++++++++++++++++ drivers/mtd/nand/omap_gpmc.c | 2 +- 3 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 drivers/mtd/nand/omap_elm.c (limited to 'drivers') diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index eb1eafa..e145cd1 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -58,6 +58,7 @@ obj-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o obj-$(CONFIG_NAND_SPEAR) += spr_nand.o obj-$(CONFIG_TEGRA_NAND) += tegra_nand.o obj-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o +obj-$(CONFIG_NAND_OMAP_ELM) += omap_elm.o obj-$(CONFIG_NAND_PLAT) += nand_plat.o obj-$(CONFIG_NAND_DOCG4) += docg4.o diff --git a/drivers/mtd/nand/omap_elm.c b/drivers/mtd/nand/omap_elm.c new file mode 100644 index 0000000..2aa7807 --- /dev/null +++ b/drivers/mtd/nand/omap_elm.c @@ -0,0 +1,196 @@ +/* + * (C) Copyright 2010-2011 Texas Instruments, + * Mansoor Ahamed + * + * BCH Error Location Module (ELM) support. + * + * NOTE: + * 1. Supports only continuous mode. Dont see need for page mode in uboot + * 2. Supports only syndrome polynomial 0. i.e. poly local variable is + * always set to ELM_DEFAULT_POLY. Dont see need for other polynomial + * sets in uboot + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include + +#define ELM_DEFAULT_POLY (0) + +struct elm *elm_cfg; + +/** + * elm_load_syndromes - Load BCH syndromes based on nibble selection + * @syndrome: BCH syndrome + * @nibbles: + * @poly: Syndrome Polynomial set to use + * + * Load BCH syndromes based on nibble selection + */ +static void elm_load_syndromes(u8 *syndrome, u32 nibbles, u8 poly) +{ + u32 *ptr; + u32 val; + + /* reg 0 */ + ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[0]; + val = syndrome[0] | (syndrome[1] << 8) | (syndrome[2] << 16) | + (syndrome[3] << 24); + writel(val, ptr); + /* reg 1 */ + ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[1]; + val = syndrome[4] | (syndrome[5] << 8) | (syndrome[6] << 16) | + (syndrome[7] << 24); + writel(val, ptr); + + /* BCH 8-bit with 26 nibbles (4*8=32) */ + if (nibbles > 13) { + /* reg 2 */ + ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[2]; + val = syndrome[8] | (syndrome[9] << 8) | (syndrome[10] << 16) | + (syndrome[11] << 24); + writel(val, ptr); + /* reg 3 */ + ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[3]; + val = syndrome[12] | (syndrome[13] << 8) | + (syndrome[14] << 16) | (syndrome[15] << 24); + writel(val, ptr); + } + + /* BCH 16-bit with 52 nibbles (7*8=56) */ + if (nibbles > 26) { + /* reg 4 */ + ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[4]; + val = syndrome[16] | (syndrome[17] << 8) | + (syndrome[18] << 16) | (syndrome[19] << 24); + writel(val, ptr); + + /* reg 5 */ + ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[5]; + val = syndrome[20] | (syndrome[21] << 8) | + (syndrome[22] << 16) | (syndrome[23] << 24); + writel(val, ptr); + + /* reg 6 */ + ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6]; + val = syndrome[24] | (syndrome[25] << 8) | + (syndrome[26] << 16) | (syndrome[27] << 24); + writel(val, ptr); + } +} + +/** + * elm_check_errors - Check for BCH errors and return error locations + * @syndrome: BCH syndrome + * @nibbles: + * @error_count: Returns number of errrors in the syndrome + * @error_locations: Returns error locations (in decimal) in this array + * + * Check the provided syndrome for BCH errors and return error count + * and locations in the array passed. Returns -1 if error is not correctable, + * else returns 0 + */ +int elm_check_error(u8 *syndrome, u32 nibbles, u32 *error_count, + u32 *error_locations) +{ + u8 poly = ELM_DEFAULT_POLY; + s8 i; + u32 location_status; + + elm_load_syndromes(syndrome, nibbles, poly); + + /* start processing */ + writel((readl(&elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6]) + | ELM_SYNDROME_FRAGMENT_6_SYNDROME_VALID), + &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6]); + + /* wait for processing to complete */ + while ((readl(&elm_cfg->irqstatus) & (0x1 << poly)) != 0x1) + ; + /* clear status */ + writel((readl(&elm_cfg->irqstatus) | (0x1 << poly)), + &elm_cfg->irqstatus); + + /* check if correctable */ + location_status = readl(&elm_cfg->error_location[poly].location_status); + if (!(location_status & ELM_LOCATION_STATUS_ECC_CORRECTABLE_MASK)) + return -1; + + /* get error count */ + *error_count = readl(&elm_cfg->error_location[poly].location_status) & + ELM_LOCATION_STATUS_ECC_NB_ERRORS_MASK; + + for (i = 0; i < *error_count; i++) { + error_locations[i] = + readl(&elm_cfg->error_location[poly].error_location_x[i]); + } + + return 0; +} + + +/** + * elm_config - Configure ELM module + * @level: 4 / 8 / 16 bit BCH + * + * Configure ELM module based on BCH level. + * Set mode as continuous mode. + * Currently we are using only syndrome 0 and syndromes 1 to 6 are not used. + * Also, the mode is set only for syndrome 0 + */ +int elm_config(enum bch_level level) +{ + u32 val; + u8 poly = ELM_DEFAULT_POLY; + u32 buffer_size = 0x7FF; + + /* config size and level */ + val = (u32)(level) & ELM_LOCATION_CONFIG_ECC_BCH_LEVEL_MASK; + val |= ((buffer_size << ELM_LOCATION_CONFIG_ECC_SIZE_POS) & + ELM_LOCATION_CONFIG_ECC_SIZE_MASK); + writel(val, &elm_cfg->location_config); + + /* config continous mode */ + /* enable interrupt generation for syndrome polynomial set */ + writel((readl(&elm_cfg->irqenable) | (0x1 << poly)), + &elm_cfg->irqenable); + /* set continuous mode for the syndrome polynomial set */ + writel((readl(&elm_cfg->page_ctrl) & ~(0x1 << poly)), + &elm_cfg->page_ctrl); + + return 0; +} + +/** + * elm_reset - Do a soft reset of ELM + * + * Perform a soft reset of ELM and return after reset is done. + */ +void elm_reset(void) +{ + /* initiate reset */ + writel((readl(&elm_cfg->sysconfig) | ELM_SYSCONFIG_SOFTRESET), + &elm_cfg->sysconfig); + + /* wait for reset complete and normal operation */ + while ((readl(&elm_cfg->sysstatus) & ELM_SYSSTATUS_RESETDONE) != + ELM_SYSSTATUS_RESETDONE) + ; +} + +/** + * elm_init - Initialize ELM module + * + * Initialize ELM support. Currently it does only base address init + * and ELM reset. + */ +void elm_init(void) +{ + elm_cfg = (struct elm *)ELM_BASE; + elm_reset(); +} diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c index ec1787f..c828859 100644 --- a/drivers/mtd/nand/omap_gpmc.c +++ b/drivers/mtd/nand/omap_gpmc.c @@ -16,7 +16,7 @@ #include #include #ifdef CONFIG_AM33XX -#include +#include #endif static uint8_t cs; -- cgit v1.1 From d016dc42cedbf6102e100fa9ecb58462edfb14f8 Mon Sep 17 00:00:00 2001 From: pekon gupta Date: Mon, 18 Nov 2013 19:03:00 +0530 Subject: mtd: nand: omap: enable BCH ECC scheme using ELM for generic platform BCH8_ECC scheme implemented in omap_gpmc.c driver has following favours +-----------------------------------+-----------------+-----------------+ |ECC Scheme | ECC Calculation | Error Detection | +-----------------------------------+-----------------+-----------------+ |OMAP_ECC_BCH8_CODE_HW |GPMC |ELM H/W engine | |OMAP_ECC_BCH8_CODE_HW_DETECTION_SW |GPMC |S/W BCH library | +-----------------------------------+-----------------+-----------------+ Current implementation limits the BCH8_CODE_HW only for AM33xx device family. (using CONFIG_AM33XX). However, other SoC families (like TI81xx) also have ELM hardware module, and can support ECC error detection using ELM. This patch - removes CONFIG_AM33xx Thus this driver can be reused by all devices having ELM h/w engine. - adds omap_select_ecc_scheme() A common function to handle ecc-scheme related configurations. This can be used both during device-probe and via user-space u-boot commads to change ecc-scheme. During device probe ecc-scheme is selected based on CONFIG_NAND_OMAP_ELM or CONFIG_NAND_OMAP_BCH8 - enables CONFIG_BCH S/W library (lib/bch.c) required by OMAP_ECC_BCHx_CODE_HW_DETECTION_SW is enabled by CONFIG_BCH. - enables CONFIG_SYS_NAND_ONFI_DETECTION for auto-detection of ONFI compliant NAND devices - updates following README doc doc/README.nand board/ti/am335x/README doc/README.omap3 Signed-off-by: Pekon Gupta [scottwood@freescale.com: fixed unused variable warning] Signed-off-by: Scott Wood --- drivers/mtd/nand/omap_gpmc.c | 326 ++++++++++++++++++++++++++----------------- 1 file changed, 201 insertions(+), 125 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c index c828859..e6b289d 100644 --- a/drivers/mtd/nand/omap_gpmc.c +++ b/drivers/mtd/nand/omap_gpmc.c @@ -15,15 +15,13 @@ #include #include #include -#ifdef CONFIG_AM33XX #include -#endif + +#define BADBLOCK_MARKER_LENGTH 2 +#define SECTOR_BYTES 512 static uint8_t cs; -static __maybe_unused struct nand_ecclayout hw_nand_oob = - GPMC_NAND_HW_ECC_LAYOUT; -static __maybe_unused struct nand_ecclayout hw_bch8_nand_oob = - GPMC_NAND_HW_BCH8_ECC_LAYOUT; +static __maybe_unused struct nand_ecclayout omap_ecclayout; /* * omap_nand_hwcontrol - Set the address pointers corretly for the @@ -233,6 +231,7 @@ struct nand_bch_priv { uint8_t type; uint8_t nibbles; struct bch_control *control; + enum omap_ecc ecc_scheme; }; /* bch types */ @@ -274,17 +273,15 @@ static void omap_hwecc_init_bch(struct nand_chip *chip, int32_t mode) { uint32_t val; uint32_t dev_width = (chip->options & NAND_BUSWIDTH_16) >> 1; -#ifdef CONFIG_AM33XX uint32_t unused_length = 0; -#endif uint32_t wr_mode = BCH_WRAPMODE_6; struct nand_bch_priv *bch = chip->priv; /* Clear the ecc result registers, select ecc reg as 1 */ writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control); -#ifdef CONFIG_AM33XX - wr_mode = BCH_WRAPMODE_1; + if (bch->ecc_scheme == OMAP_ECC_BCH8_CODE_HW) { + wr_mode = BCH_WRAPMODE_1; switch (bch->nibbles) { case ECC_BCH4_NIBBLES: @@ -320,7 +317,7 @@ static void omap_hwecc_init_bch(struct nand_chip *chip, int32_t mode) val |= (unused_length << 22); break; } -#else + } else { /* * This ecc_size_config setting is for BCH sw library. * @@ -333,7 +330,7 @@ static void omap_hwecc_init_bch(struct nand_chip *chip, int32_t mode) * size1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area) */ val = (32 << 22) | (0 << 12); -#endif + } /* ecc size configuration */ writel(val, &gpmc_cfg->ecc_size_config); @@ -376,9 +373,9 @@ static void __maybe_unused omap_ecc_disable(struct mtd_info *mtd) } /* - * BCH8 support (needs ELM and thus AM33xx-only) + * BCH support using ELM module */ -#ifdef CONFIG_AM33XX +#ifdef CONFIG_NAND_OMAP_ELM /* * omap_read_bch8_result - Read BCH result for BCH8 level * @@ -631,20 +628,20 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, } return 0; } -#endif /* CONFIG_AM33XX */ +#endif /* CONFIG_NAND_OMAP_ELM */ /* * OMAP3 BCH8 support (with BCH library) */ -#ifdef CONFIG_NAND_OMAP_BCH8 +#ifdef CONFIG_BCH /* - * omap_calculate_ecc_bch - Read BCH ECC result + * omap_calculate_ecc_bch_sw - Read BCH ECC result * * @mtd: MTD device structure * @dat: The pointer to data on which ecc is computed (unused here) * @ecc: The ECC output buffer */ -static int omap_calculate_ecc_bch(struct mtd_info *mtd, const uint8_t *dat, +static int omap_calculate_ecc_bch_sw(struct mtd_info *mtd, const uint8_t *dat, uint8_t *ecc) { int ret = 0; @@ -689,13 +686,13 @@ static int omap_calculate_ecc_bch(struct mtd_info *mtd, const uint8_t *dat, } /** - * omap_correct_data_bch - Decode received data and correct errors + * omap_correct_data_bch_sw - Decode received data and correct errors * @mtd: MTD device structure * @data: page data * @read_ecc: ecc read from nand flash * @calc_ecc: ecc read from HW ECC registers */ -static int omap_correct_data_bch(struct mtd_info *mtd, u_char *data, +static int omap_correct_data_bch_sw(struct mtd_info *mtd, u_char *data, u_char *read_ecc, u_char *calc_ecc) { int i, count; @@ -752,7 +749,150 @@ static void __maybe_unused omap_free_bch(struct mtd_info *mtd) chip_priv->control = NULL; } } -#endif /* CONFIG_NAND_OMAP_BCH8 */ +#endif /* CONFIG_BCH */ + +/** + * omap_select_ecc_scheme - configures driver for particular ecc-scheme + * @nand: NAND chip device structure + * @ecc_scheme: ecc scheme to configure + * @pagesize: number of main-area bytes per page of NAND device + * @oobsize: number of OOB/spare bytes per page of NAND device + */ +static int omap_select_ecc_scheme(struct nand_chip *nand, + enum omap_ecc ecc_scheme, unsigned int pagesize, unsigned int oobsize) { + struct nand_bch_priv *bch = nand->priv; + struct nand_ecclayout *ecclayout = nand->ecc.layout; + int eccsteps = pagesize / SECTOR_BYTES; + int i; + + switch (ecc_scheme) { + case OMAP_ECC_HAM1_CODE_SW: + debug("nand: selected OMAP_ECC_HAM1_CODE_SW\n"); + /* For this ecc-scheme, ecc.bytes, ecc.layout, ... are + * initialized in nand_scan_tail(), so just set ecc.mode */ + bch_priv.control = NULL; + bch_priv.type = 0; + nand->ecc.mode = NAND_ECC_SOFT; + nand->ecc.layout = NULL; + nand->ecc.size = pagesize; + bch->ecc_scheme = OMAP_ECC_HAM1_CODE_SW; + break; + + case OMAP_ECC_HAM1_CODE_HW: + debug("nand: selected OMAP_ECC_HAM1_CODE_HW\n"); + /* check ecc-scheme requirements before updating ecc info */ + if ((3 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) { + printf("nand: error: insufficient OOB: require=%d\n", ( + (3 * eccsteps) + BADBLOCK_MARKER_LENGTH)); + return -EINVAL; + } + bch_priv.control = NULL; + bch_priv.type = 0; + /* populate ecc specific fields */ + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.strength = 1; + nand->ecc.size = SECTOR_BYTES; + nand->ecc.bytes = 3; + nand->ecc.hwctl = omap_enable_hwecc; + nand->ecc.correct = omap_correct_data; + nand->ecc.calculate = omap_calculate_ecc; + /* define ecc-layout */ + ecclayout->eccbytes = nand->ecc.bytes * eccsteps; + for (i = 0; i < ecclayout->eccbytes; i++) + ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH; + ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; + ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - + BADBLOCK_MARKER_LENGTH; + bch->ecc_scheme = OMAP_ECC_HAM1_CODE_HW; + break; + + case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: +#ifdef CONFIG_BCH + debug("nand: selected OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n"); + /* check ecc-scheme requirements before updating ecc info */ + if ((13 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) { + printf("nand: error: insufficient OOB: require=%d\n", ( + (13 * eccsteps) + BADBLOCK_MARKER_LENGTH)); + return -EINVAL; + } + /* check if BCH S/W library can be used for error detection */ + bch_priv.control = init_bch(13, 8, 0x201b); + if (!bch_priv.control) { + printf("nand: error: could not init_bch()\n"); + return -ENODEV; + } + bch_priv.type = ECC_BCH8; + /* populate ecc specific fields */ + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.strength = 8; + nand->ecc.size = SECTOR_BYTES; + nand->ecc.bytes = 13; + nand->ecc.hwctl = omap_enable_ecc_bch; + nand->ecc.correct = omap_correct_data_bch_sw; + nand->ecc.calculate = omap_calculate_ecc_bch_sw; + /* define ecc-layout */ + ecclayout->eccbytes = nand->ecc.bytes * eccsteps; + ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; + for (i = 1; i < ecclayout->eccbytes; i++) { + if (i % nand->ecc.bytes) + ecclayout->eccpos[i] = + ecclayout->eccpos[i - 1] + 1; + else + ecclayout->eccpos[i] = + ecclayout->eccpos[i - 1] + 2; + } + ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; + ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - + BADBLOCK_MARKER_LENGTH; + omap_hwecc_init_bch(nand, NAND_ECC_READ); + bch->ecc_scheme = OMAP_ECC_BCH8_CODE_HW_DETECTION_SW; + break; +#else + printf("nand: error: CONFIG_BCH required for ECC\n"); + return -EINVAL; +#endif + + case OMAP_ECC_BCH8_CODE_HW: +#ifdef CONFIG_NAND_OMAP_ELM + debug("nand: selected OMAP_ECC_BCH8_CODE_HW\n"); + /* check ecc-scheme requirements before updating ecc info */ + if ((14 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) { + printf("nand: error: insufficient OOB: require=%d\n", ( + (14 * eccsteps) + BADBLOCK_MARKER_LENGTH)); + return -EINVAL; + } + /* intialize ELM for ECC error detection */ + elm_init(); + bch_priv.type = ECC_BCH8; + /* populate ecc specific fields */ + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.strength = 8; + nand->ecc.size = SECTOR_BYTES; + nand->ecc.bytes = 14; + nand->ecc.hwctl = omap_enable_ecc_bch; + nand->ecc.correct = omap_correct_data_bch; + nand->ecc.calculate = omap_calculate_ecc_bch; + nand->ecc.read_page = omap_read_page_bch; + /* define ecc-layout */ + ecclayout->eccbytes = nand->ecc.bytes * eccsteps; + for (i = 0; i < ecclayout->eccbytes; i++) + ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH; + ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; + ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - + BADBLOCK_MARKER_LENGTH; + bch->ecc_scheme = OMAP_ECC_BCH8_CODE_HW; + break; +#else + printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n"); + return -EINVAL; +#endif + + default: + debug("nand: error: ecc scheme not enabled or supported\n"); + return -EINVAL; + } + return 0; +} #ifndef CONFIG_SPL_BUILD /* @@ -763,77 +903,45 @@ static void __maybe_unused omap_free_bch(struct mtd_info *mtd) * @eccstrength - the number of bits that could be corrected * (1 - hamming, 4 - BCH4, 8 - BCH8, 16 - BCH16) */ -void omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength) +int __maybe_unused omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength) { struct nand_chip *nand; struct mtd_info *mtd; + int err = 0; if (nand_curr_device < 0 || nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[nand_curr_device].name) { - printf("Error: Can't switch ecc, no devices available\n"); - return; + printf("nand: error: no NAND devices found\n"); + return -ENODEV; } mtd = &nand_info[nand_curr_device]; nand = mtd->priv; - nand->options |= NAND_OWN_BUFFERS; - - /* Reset ecc interface */ - nand->ecc.mode = NAND_ECC_NONE; - nand->ecc.read_page = NULL; - nand->ecc.write_page = NULL; - nand->ecc.read_oob = NULL; - nand->ecc.write_oob = NULL; - nand->ecc.hwctl = NULL; - nand->ecc.correct = NULL; - nand->ecc.calculate = NULL; - nand->ecc.strength = eccstrength; - /* Setup the ecc configurations again */ if (hardware) { if (eccstrength == 1) { - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.layout = &hw_nand_oob; - nand->ecc.size = 512; - nand->ecc.bytes = 3; - nand->ecc.hwctl = omap_enable_hwecc; - nand->ecc.correct = omap_correct_data; - nand->ecc.calculate = omap_calculate_ecc; - omap_hwecc_init(nand); - printf("1-bit hamming HW ECC selected\n"); - } -#if defined(CONFIG_AM33XX) || defined(CONFIG_NAND_OMAP_BCH8) - else if (eccstrength == 8) { - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.layout = &hw_bch8_nand_oob; - nand->ecc.size = 512; -#ifdef CONFIG_AM33XX - nand->ecc.bytes = 14; - nand->ecc.read_page = omap_read_page_bch; -#else - nand->ecc.bytes = 13; -#endif - nand->ecc.hwctl = omap_enable_ecc_bch; - nand->ecc.correct = omap_correct_data_bch; - nand->ecc.calculate = omap_calculate_ecc_bch; - omap_hwecc_init_bch(nand, NAND_ECC_READ); - printf("8-bit BCH HW ECC selected\n"); + err = omap_select_ecc_scheme(nand, + OMAP_ECC_HAM1_CODE_HW, + mtd->writesize, mtd->oobsize); + } else if (eccstrength == 8) { + err = omap_select_ecc_scheme(nand, + OMAP_ECC_BCH8_CODE_HW, + mtd->writesize, mtd->oobsize); + } else { + printf("nand: error: unsupported ECC scheme\n"); + return -EINVAL; } -#endif } else { - nand->ecc.mode = NAND_ECC_SOFT; - /* Use mtd default settings */ - nand->ecc.layout = NULL; - nand->ecc.size = 0; - printf("SW ECC selected\n"); + err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_SW, + mtd->writesize, mtd->oobsize); } /* Update NAND handling after ECC mode switch */ - nand_scan_tail(mtd); - - nand->options &= ~NAND_OWN_BUFFERS; + if (!err) + err = nand_scan_tail(mtd); + return err; } #endif /* CONFIG_SPL_BUILD */ @@ -856,7 +964,7 @@ int board_nand_init(struct nand_chip *nand) { int32_t gpmc_config = 0; cs = 0; - + int err = 0; /* * xloader/Uboot's gpmc configuration would have configured GPMC for * nand type of memory. The following logic scans and latches on to the @@ -873,7 +981,7 @@ int board_nand_init(struct nand_chip *nand) cs++; } if (cs >= GPMC_MAX_CS) { - printf("NAND: Unable to find NAND settings in " + printf("nand: error: Unable to find NAND settings in " "GPMC Configuration - quitting\n"); return -ENODEV; } @@ -885,64 +993,32 @@ int board_nand_init(struct nand_chip *nand) nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat; nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd; - - nand->cmd_ctrl = omap_nand_hwcontrol; - nand->options = NAND_NO_PADDING | NAND_CACHEPRG; + nand->priv = &bch_priv; + nand->cmd_ctrl = omap_nand_hwcontrol; + nand->options |= NAND_NO_PADDING | NAND_CACHEPRG; /* If we are 16 bit dev, our gpmc config tells us that */ if ((readl(&gpmc_cfg->cs[cs].config1) & 0x3000) == 0x1000) nand->options |= NAND_BUSWIDTH_16; nand->chip_delay = 100; - -#if defined(CONFIG_AM33XX) || defined(CONFIG_NAND_OMAP_BCH8) -#ifdef CONFIG_AM33XX - /* AM33xx uses the ELM */ - /* required in case of BCH */ - elm_init(); -#else - /* - * Whereas other OMAP based SoC do not have the ELM, they use the BCH - * SW library. - */ - bch_priv.control = init_bch(13, 8, 0x201b /* hw polynominal */); - if (!bch_priv.control) { - puts("Could not init_bch()\n"); - return -ENODEV; - } -#endif - /* BCH info that will be correct for SPL or overridden otherwise. */ - nand->priv = &bch_priv; -#endif - - /* Default ECC mode */ -#if defined(CONFIG_AM33XX) || defined(CONFIG_NAND_OMAP_BCH8) - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.layout = &hw_bch8_nand_oob; - nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE; - nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; - nand->ecc.strength = 8; - nand->ecc.hwctl = omap_enable_ecc_bch; - nand->ecc.correct = omap_correct_data_bch; - nand->ecc.calculate = omap_calculate_ecc_bch; -#ifdef CONFIG_AM33XX - nand->ecc.read_page = omap_read_page_bch; -#endif - omap_hwecc_init_bch(nand, NAND_ECC_READ); -#else -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_NAND_SOFTECC) - nand->ecc.mode = NAND_ECC_SOFT; + nand->ecc.layout = &omap_ecclayout; + + /* select ECC scheme */ +#if defined(CONFIG_NAND_OMAP_ELM) + err = omap_select_ecc_scheme(nand, OMAP_ECC_BCH8_CODE_HW, + CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE); +#elif defined(CONFIG_NAND_OMAP_BCH8) + err = omap_select_ecc_scheme(nand, OMAP_ECC_BCH8_CODE_HW_DETECTION_SW, + CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE); +#elif !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_NAND_SOFTECC) + err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_SW, + 0, 0); #else - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.layout = &hw_nand_oob; - nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE; - nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; - nand->ecc.hwctl = omap_enable_hwecc; - nand->ecc.correct = omap_correct_data; - nand->ecc.calculate = omap_calculate_ecc; - nand->ecc.strength = 1; - omap_hwecc_init(nand); -#endif + err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_HW, + CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE); #endif + if (err) + return err; #ifdef CONFIG_SPL_BUILD if (nand->options & NAND_BUSWIDTH_16) -- cgit v1.1 From 3f719069c884284b2457448a7afe32b02bd4f782 Mon Sep 17 00:00:00 2001 From: pekon gupta Date: Mon, 18 Nov 2013 19:03:01 +0530 Subject: mtd: nand: omap: add CONFIG_NAND_OMAP_ECCSCHEME for selection of ecc-scheme This patch adds new CONFIG_NAND_OMAP_ECCSCHEME, replacing other distributed CONFIG_xx used for selecting NAND ecc-schemes. This patch aims at solving following issues. 1) Currently ecc-scheme is tied to SoC platform, which prevents user to select other ecc-schemes also supported in hardware. like; - most of OMAP3 SoC platforms use only 1-bit Hamming ecc-scheme, inspite the fact that they can use higher ecc-schemes like 8-bit ecc-schemes with software based error detection (OMAP_ECC_BCH4_CODE_HW_DETECTION_SW). - most of AM33xx SoC plaforms use 8-bit BCH ecc-scheme for now, but hardware supports BCH16 ecc-scheme also. 2) Different platforms use different CONFIG_xx to select ecc-schemes, which adds confusion for user while migrating platforms. - *CONFIG_NAND_OMAP_ELM* which enables ELM hardware engine, selects only 8-bit BCH ecc-scheme with h/w based error-correction (OMAP_ECC_BCH8_CODE_HW) whereas ELM hardware engine supports other ecc-schemes also like; BCH4, and BCH16 (in future). - *CONFIG_NAND_OMAP_BCH8* selects 8-bit BCH ecc-scheme with s/w based error correction (OMAP_ECC_BCH8_CODE_HW_DETECTION_SW). - *CONFIG_SPL_NAND_SOFTECC* selects 1-bit Hamming ecc-scheme using s/w library Thus adding new *CONFIG_NAND_OMAP_ECCSCHEME* de-couples ecc-scheme dependency on SoC platform and NAND driver. And user can select ecc-scheme independently foreach board. However, selection some hardware based ecc-schemes (OMAP_ECC_BCHx_CODE_HW) still depends on presence of ELM hardware engine on SoC. (Refer doc/README.nand) Signed-off-by: Pekon Gupta --- drivers/mtd/nand/omap_gpmc.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c index e6b289d..5e7e6b3 100644 --- a/drivers/mtd/nand/omap_gpmc.c +++ b/drivers/mtd/nand/omap_gpmc.c @@ -1004,18 +1004,13 @@ int board_nand_init(struct nand_chip *nand) nand->ecc.layout = &omap_ecclayout; /* select ECC scheme */ -#if defined(CONFIG_NAND_OMAP_ELM) - err = omap_select_ecc_scheme(nand, OMAP_ECC_BCH8_CODE_HW, +#if defined(CONFIG_NAND_OMAP_ECCSCHEME) + err = omap_select_ecc_scheme(nand, CONFIG_NAND_OMAP_ECCSCHEME, CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE); -#elif defined(CONFIG_NAND_OMAP_BCH8) - err = omap_select_ecc_scheme(nand, OMAP_ECC_BCH8_CODE_HW_DETECTION_SW, - CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE); -#elif !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_NAND_SOFTECC) +#else + /* pagesize and oobsize are not required to configure sw ecc-scheme */ err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_SW, 0, 0); -#else - err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_HW, - CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE); #endif if (err) return err; -- cgit v1.1 From 626ee1e32eeb4fc89e0f406d6067ed6e71d8302f Mon Sep 17 00:00:00 2001 From: Shengzhou Liu Date: Thu, 8 Aug 2013 16:33:35 +0800 Subject: phylib: update atheros ar803x phy As AR8031 and AR8033 have same PHY ID 0x4dd074, they use the common driver. Currently AR8031_driver didn't work for AR8033, hence updated it to have it work on AR8031/AR8033. Signed-off-by: Shengzhou Liu --- drivers/net/phy/atheros.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c index 0f2dfd6..7a1453f 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -48,11 +48,11 @@ static struct phy_driver AR8021_driver = { }; static struct phy_driver AR8031_driver = { - .name = "AR8031", + .name = "AR8031/AR8033", .uid = 0x4dd074, .mask = 0xfffff0, .features = PHY_GBIT_FEATURES, - .config = genphy_config, + .config = ar8021_config, .startup = genphy_startup, .shutdown = genphy_shutdown, }; -- cgit v1.1 From 0611c6017c9fc56a731ee5f8bbd91c7ee1a50849 Mon Sep 17 00:00:00 2001 From: Sascha Silbe Date: Sun, 11 Aug 2013 17:08:23 +0200 Subject: NET: mvgbe: avoid unused variable warning when used without phylib support Avoid a recently introduced unused variable warning for boards that use mvgbe but not phylib. Signed-off-by: Sascha Silbe Patch: 266334 --- drivers/net/mvgbe.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mvgbe.c b/drivers/net/mvgbe.c index 6c901d1..0cd06b6 100644 --- a/drivers/net/mvgbe.c +++ b/drivers/net/mvgbe.c @@ -420,8 +420,9 @@ static int mvgbe_init(struct eth_device *dev) { struct mvgbe_device *dmvgbe = to_mvgbe(dev); struct mvgbe_registers *regs = dmvgbe->regs; -#if (defined (CONFIG_MII) || defined (CONFIG_CMD_MII)) \ - && defined (CONFIG_SYS_FAULT_ECHO_LINK_DOWN) +#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && \ + !defined(CONFIG_PHYLIB) && \ + defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN) int i; #endif /* setup RX rings */ -- cgit v1.1 From 870cc23f07c725e6218a77b25314193ef6fbd1b4 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Thu, 22 Aug 2013 13:22:01 +0900 Subject: net: sh-eth: Change cache API of SH The cache API of SH was changed from dcache_wback_range to flush_dcache_range. sh-eth uses dcache_wback_range. This patch changes to flush_dcache_range. Signed-off-by: Nobuhiro Iwamatsu --- drivers/net/sh_eth.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index d5a83e0..4cfd1e5 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -25,9 +25,10 @@ #ifndef CONFIG_SH_ETHER_PHY_ADDR # error "Please define CONFIG_SH_ETHER_PHY_ADDR" #endif + #ifdef CONFIG_SH_ETHER_CACHE_WRITEBACK #define flush_cache_wback(addr, len) \ - dcache_wback_range((u32)addr, (u32)(addr + len - 1)) + flush_dcache_range((u32)addr, (u32)(addr + len - 1)) #else #define flush_cache_wback(...) #endif -- cgit v1.1 From f8b7507d41e9d2607e876b74f6ce79235f6bd618 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Thu, 22 Aug 2013 13:22:02 +0900 Subject: net: sh-eth: Add control for padding size of packet descriptor sh-eth can change the alignment size of a packet descriptor according to BUS size. This patch adds this function. Signed-off-by: Hisashi Nakamura Signed-off-by: Nobuhiro Iwamatsu --- drivers/net/sh_eth.c | 13 ++++++++----- drivers/net/sh_eth.h | 27 ++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 4cfd1e5..c038929 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -238,15 +238,17 @@ static int sh_eth_rx_desc_init(struct sh_eth_dev *eth) * Allocate rx data buffers. They must be 32 bytes aligned and in * P2 area */ - port_info->rx_buf_malloc = malloc(NUM_RX_DESC * MAX_BUF_SIZE + 31); + port_info->rx_buf_malloc = malloc( + NUM_RX_DESC * MAX_BUF_SIZE + RX_BUF_ALIGNE_SIZE - 1); if (!port_info->rx_buf_malloc) { printf(SHETHER_NAME ": malloc failed\n"); ret = -ENOMEM; goto err_buf_malloc; } - tmp_addr = (u32)(((int)port_info->rx_buf_malloc + (32 - 1)) & - ~(32 - 1)); + tmp_addr = (u32)(((int)port_info->rx_buf_malloc + + (RX_BUF_ALIGNE_SIZE - 1)) & + ~(RX_BUF_ALIGNE_SIZE - 1)); port_info->rx_buf_base = (u8 *)ADDR_TO_P2(tmp_addr); /* Initialize all descriptors */ @@ -352,8 +354,9 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd) struct phy_device *phy; /* Configure e-dmac registers */ - sh_eth_write(eth, (sh_eth_read(eth, EDMR) & ~EMDR_DESC_R) | EDMR_EL, - EDMR); + sh_eth_write(eth, (sh_eth_read(eth, EDMR) & ~EMDR_DESC_R) | + (EMDR_DESC | EDMR_EL), EDMR); + sh_eth_write(eth, 0, EESIPR); sh_eth_write(eth, 0, TRSCER); sh_eth_write(eth, 0, TFTR); diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h index 9ad800e..35a1eee 100644 --- a/drivers/net/sh_eth.h +++ b/drivers/net/sh_eth.h @@ -31,6 +31,11 @@ #define ADDR_TO_P2(addr) (addr) #endif /* defined(CONFIG_SH) */ +/* base padding size is 16 */ +#ifndef CONFIG_SH_ETHER_ALIGNE_SIZE +#define CONFIG_SH_ETHER_ALIGNE_SIZE 16 +#endif + /* Number of supported ports */ #define MAX_PORT_NUM 2 @@ -45,15 +50,16 @@ /* The size of the tx descriptor is determined by how much padding is used. 4, 20, or 52 bytes of padding can be used */ -#define TX_DESC_PADDING 4 -#define TX_DESC_SIZE (12 + TX_DESC_PADDING) +#define TX_DESC_PADDING (CONFIG_SH_ETHER_ALIGNE_SIZE - 12) +/* same as CONFIG_SH_ETHER_ALIGNE_SIZE */ +#define TX_DESC_SIZE (12 + TX_DESC_PADDING) /* Tx descriptor. We always use 3 bytes of padding */ struct tx_desc_s { volatile u32 td0; u32 td1; u32 td2; /* Buffer start */ - u32 padding; + u8 padding[TX_DESC_PADDING]; /* aligned cache line size */ }; /* There is no limitation in the number of rx descriptors */ @@ -61,15 +67,18 @@ struct tx_desc_s { /* The size of the rx descriptor is determined by how much padding is used. 4, 20, or 52 bytes of padding can be used */ -#define RX_DESC_PADDING 4 +#define RX_DESC_PADDING (CONFIG_SH_ETHER_ALIGNE_SIZE - 12) +/* same as CONFIG_SH_ETHER_ALIGNE_SIZE */ #define RX_DESC_SIZE (12 + RX_DESC_PADDING) +/* aligned cache line size */ +#define RX_BUF_ALIGNE_SIZE (CONFIG_SH_ETHER_ALIGNE_SIZE > 32 ? 64 : 32) /* Rx descriptor. We always use 4 bytes of padding */ struct rx_desc_s { volatile u32 rd0; volatile u32 rd1; u32 rd2; /* Buffer start */ - u32 padding; + u8 padding[TX_DESC_PADDING]; /* aligned cache line size */ }; struct sh_eth_info { @@ -320,6 +329,14 @@ enum DMAC_M_BIT { #endif }; +#if CONFIG_SH_ETHER_ALIGNE_SIZE == 64 +# define EMDR_DESC EDMR_DL1 +#elif CONFIG_SH_ETHER_ALIGNE_SIZE == 32 +# define EMDR_DESC EDMR_DL0 +#elif CONFIG_SH_ETHER_ALIGNE_SIZE == 16 /* Default */ +# define EMDR_DESC 0 +#endif + /* RFLR */ #define RFLR_RFL_MIN 0x05EE /* Recv Frame length 1518 byte */ -- cgit v1.1 From 92f0713408859952cf82a9a4f368b2459cd1619f Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Thu, 22 Aug 2013 13:22:03 +0900 Subject: net: sh-eth: Add invalidate cache control for rmobile (ARM SoC) The sh-eth of rmobile needs to use invalidate_cache* function. This patch adds invalidate_cache* function. Signed-off-by: Hisashi Nakamura Signed-off-by: Nobuhiro Iwamatsu Patch: 268948 --- drivers/net/sh_eth.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index c038929..6a78df0 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -26,13 +26,30 @@ # error "Please define CONFIG_SH_ETHER_PHY_ADDR" #endif -#ifdef CONFIG_SH_ETHER_CACHE_WRITEBACK -#define flush_cache_wback(addr, len) \ - flush_dcache_range((u32)addr, (u32)(addr + len - 1)) +#if defined(CONFIG_SH_ETHER_CACHE_WRITEBACK) && !defined(CONFIG_SYS_DCACHE_OFF) +#define flush_cache_wback(addr, len) \ + flush_dcache_range((u32)addr, (u32)(addr + len - 1)) #else #define flush_cache_wback(...) #endif +#if defined(CONFIG_SH_ETHER_CACHE_INVALIDATE) && defined(CONFIG_ARM) +#define invalidate_cache(addr, len) \ + { \ + u32 line_size = CONFIG_SH_ETHER_ALIGNE_SIZE; \ + u32 start, end; \ + \ + start = (u32)addr; \ + end = start + len; \ + start &= ~(line_size - 1); \ + end = ((end + line_size - 1) & ~(line_size - 1)); \ + \ + invalidate_dcache_range(start, end); \ + } +#else +#define invalidate_cache(...) +#endif + #define TIMEOUT_CNT 1000 int sh_eth_send(struct eth_device *dev, void *packet, int len) @@ -70,8 +87,11 @@ int sh_eth_send(struct eth_device *dev, void *packet, int len) /* Wait until packet is transmitted */ timeout = TIMEOUT_CNT; - while (port_info->tx_desc_cur->td0 & TD_TACT && timeout--) + do { + invalidate_cache(port_info->tx_desc_cur, + sizeof(struct tx_desc_s)); udelay(100); + } while (port_info->tx_desc_cur->td0 & TD_TACT && timeout--); if (timeout < 0) { printf(SHETHER_NAME ": transmit timeout\n"); @@ -95,12 +115,14 @@ int sh_eth_recv(struct eth_device *dev) uchar *packet; /* Check if the rx descriptor is ready */ + invalidate_cache(port_info->rx_desc_cur, sizeof(struct rx_desc_s)); if (!(port_info->rx_desc_cur->rd0 & RD_RACT)) { /* Check for errors */ if (!(port_info->rx_desc_cur->rd0 & RD_RFE)) { len = port_info->rx_desc_cur->rd1 & 0xffff; packet = (uchar *) ADDR_TO_P2(port_info->rx_desc_cur->rd2); + invalidate_cache(packet, len); NetReceive(packet, len); } @@ -109,7 +131,6 @@ int sh_eth_recv(struct eth_device *dev) port_info->rx_desc_cur->rd0 = RD_RACT | RD_RDLE; else port_info->rx_desc_cur->rd0 = RD_RACT; - /* Point to the next descriptor */ port_info->rx_desc_cur++; if (port_info->rx_desc_cur >= -- cgit v1.1 From 8707678cc420050285b7694292760c29d080192c Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Thu, 22 Aug 2013 13:22:04 +0900 Subject: net: sh-eth: Add support R8A7790 R8A7790 has the same sh-ether IP core as other SH/rmobile. This patch adds support of R8A7790. Signed-off-by: Hisashi Nakamura Signed-off-by: Nobuhiro Iwamatsu --- drivers/net/sh_eth.c | 5 ++++- drivers/net/sh_eth.h | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 6a78df0..9020752 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -4,6 +4,7 @@ * Copyright (C) 2008, 2011 Renesas Solutions Corp. * Copyright (c) 2008, 2011 Nobuhiro Iwamatsu * Copyright (c) 2007 Carlos Munoz + * Copyright (C) 2013 Renesas Electronics Corporation * * SPDX-License-Identifier: GPL-2.0+ */ @@ -409,6 +410,8 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd) #if defined(CONFIG_CPU_SH7734) || defined(CONFIG_R8A7740) sh_eth_write(eth, CONFIG_SH_ETHER_SH7734_MII, RMII_MII); +#elif defined(CONFIG_R8A7790) + sh_eth_write(eth, sh_eth_read(eth, RMIIMR) | 0x1, RMIIMR); #endif /* Configure phy */ ret = sh_eth_phy_config(eth); @@ -432,7 +435,7 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd) sh_eth_write(eth, GECMR_100B, GECMR); #elif defined(CONFIG_CPU_SH7757) || defined(CONFIG_CPU_SH7752) sh_eth_write(eth, 1, RTRATE); -#elif defined(CONFIG_CPU_SH7724) +#elif defined(CONFIG_CPU_SH7724) || defined(CONFIG_R8A7790) val = ECMR_RTM; #endif } else if (phy->speed == 10) { diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h index 35a1eee..43b8ac9 100644 --- a/drivers/net/sh_eth.h +++ b/drivers/net/sh_eth.h @@ -166,6 +166,7 @@ enum { TLFRCR, CERCR, CEECR, + RMIIMR, /* R8A7790 */ MAFCR, RTRATE, CSMR, @@ -272,6 +273,7 @@ static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = { [RMCR] = 0x0058, [TFUCR] = 0x0064, [RFOCR] = 0x0068, + [RMIIMR] = 0x006C, [FCFTR] = 0x0070, [RPADIR] = 0x0078, [TRIMD] = 0x007c, @@ -299,6 +301,9 @@ static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = { #elif defined(CONFIG_R8A7740) #define SH_ETH_TYPE_GETHER #define BASE_IO_ADDR 0xE9A00000 +#elif defined(CONFIG_R8A7790) +#define SH_ETH_TYPE_ETHER +#define BASE_IO_ADDR 0xEE700200 #endif /* @@ -502,6 +507,8 @@ enum FELIC_MODE_BIT { ECMR_PRM = 0x00000001, #ifdef CONFIG_CPU_SH7724 ECMR_RTM = 0x00000010, +#elif defined(CONFIG_R8A7790) + ECMR_RTM = 0x00000004, #endif }; -- cgit v1.1 From e97a78cfed113dfbf9a0db712624bca69065c3a1 Mon Sep 17 00:00:00 2001 From: Arpit Goel Date: Fri, 23 Aug 2013 20:18:05 +0530 Subject: net: phy/vitesse: Add support for VSC8514 phy module This patch adds support for VSC8514 PHY module which can be found on Freescale's T1040RDB boards. Signed-off-by: Arpit Goel Signed-off-by: Bhupesh Sharma --- drivers/net/phy/vitesse.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c index 5cf103e..c555979 100644 --- a/drivers/net/phy/vitesse.c +++ b/drivers/net/phy/vitesse.c @@ -49,6 +49,15 @@ #define MIIM_VSC8574_18G_QSGMII 0x80e0 #define MIIM_VSC8574_18G_CMDSTAT 0x8000 +/* Vitesse VSC8514 control register */ +#define MIIM_VSC8514_GENERAL18 0x12 +#define MIIM_VSC8514_GENERAL19 0x13 +#define MIIM_VSC8514_GENERAL23 0x17 + +/* Vitesse VSC8514 gerenal purpose register 18 */ +#define MIIM_VSC8514_18G_QSGMII 0x80e0 +#define MIIM_VSC8514_18G_CMDSTAT 0x8000 + /* CIS8201 */ static int vitesse_config(struct phy_device *phydev) { @@ -148,7 +157,7 @@ static int vsc8601_config(struct phy_device *phydev) static int vsc8574_config(struct phy_device *phydev) { u32 val; - /* configure regiser 19G for MAC */ + /* configure register 19G for MAC */ phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, PHY_EXT_PAGE_ACCESS_GENERAL); @@ -188,6 +197,53 @@ static int vsc8574_config(struct phy_device *phydev) return 0; } +static int vsc8514_config(struct phy_device *phydev) +{ + u32 val; + int timeout = 1000000; + + /* configure register to access 19G */ + phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, + PHY_EXT_PAGE_ACCESS_GENERAL); + + val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL19); + if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) { + /* set bit 15:14 to '01' for QSGMII mode */ + val = (val & 0x3fff) | (1 << 14); + phy_write(phydev, MDIO_DEVAD_NONE, + MIIM_VSC8514_GENERAL19, val); + /* Enable 4 ports MAC QSGMII */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18, + MIIM_VSC8514_18G_QSGMII); + } else { + /*TODO Add SGMII functionality once spec sheet + * for VSC8514 defines complete functionality + */ + } + + val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18); + /* When bit 15 is cleared the command has completed */ + while ((val & MIIM_VSC8514_18G_CMDSTAT) && timeout--) + val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18); + + if (0 == timeout) { + printf("PHY 8514 config failed\n"); + return -1; + } + + phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); + + /* configure register to access 23 */ + val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL23); + /* set bits 10:8 to '000' */ + val = (val & 0xf8ff); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL23, val); + + genphy_config_aneg(phydev); + + return 0; +} + static struct phy_driver VSC8211_driver = { .name = "Vitesse VSC8211", .uid = 0xfc4b0, @@ -238,6 +294,16 @@ static struct phy_driver VSC8574_driver = { .shutdown = &genphy_shutdown, }; +static struct phy_driver VSC8514_driver = { + .name = "Vitesse VSC8514", + .uid = 0x70570, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &vsc8514_config, + .startup = &vitesse_startup, + .shutdown = &genphy_shutdown, +}; + static struct phy_driver VSC8601_driver = { .name = "Vitesse VSC8601", .uid = 0x70420, @@ -298,6 +364,7 @@ int phy_vitesse_init(void) phy_register(&VSC8211_driver); phy_register(&VSC8221_driver); phy_register(&VSC8574_driver); + phy_register(&VSC8514_driver); phy_register(&VSC8662_driver); phy_register(&cis8201_driver); phy_register(&cis8204_driver); -- cgit v1.1 From 42205047674d7fc9e0aa747273fbc7dcfbac3183 Mon Sep 17 00:00:00 2001 From: Bhupesh Sharma Date: Sun, 1 Sep 2013 04:40:52 +0530 Subject: net/phy: realtek: Fix the PHY ID mask to ensure the correct Realtek PHY is detected The 'get_phy_driver' code in 'drivers/net/phy/phy.c' uses the following method to determine which driver is to be loaded for a particular PHY module: list_for_each(entry, &phy_drivers) { drv = list_entry(entry, struct phy_driver, list); if ((drv->uid & drv->mask) == (phy_id & drv->mask)) return drv; } This means that a drv->mask of 0xfffff0 will return incorrect phy driver for the logic above, even if the drv->uid is anything other than something ending with a 0x0. For e.g. if the RTL8211E drv->uid is 0x1cc915 and drv->mask is 0xffffff and the RTL8211B drv->uid is 0x1cc910 and drv->mask is 0xffffff0, then the phy driver selected will always be RTL8211B even though the underlying phy connected on the board is a 8211E module. This patch fixes this issue. Signed-off-by: Bhupesh Sharma --- drivers/net/phy/realtek.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index ddbbc35..a3ace68 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -102,7 +102,7 @@ static int rtl8211x_startup(struct phy_device *phydev) static struct phy_driver RTL8211B_driver = { .name = "RealTek RTL8211B", .uid = 0x1cc910, - .mask = 0xfffff0, + .mask = 0xffffff, .features = PHY_GBIT_FEATURES, .config = &rtl8211x_config, .startup = &rtl8211x_startup, @@ -113,7 +113,7 @@ static struct phy_driver RTL8211B_driver = { static struct phy_driver RTL8211E_driver = { .name = "RealTek RTL8211E", .uid = 0x1cc915, - .mask = 0xfffff0, + .mask = 0xffffff, .features = PHY_GBIT_FEATURES, .config = &rtl8211x_config, .startup = &rtl8211x_startup, @@ -124,7 +124,7 @@ static struct phy_driver RTL8211E_driver = { static struct phy_driver RTL8211DN_driver = { .name = "RealTek RTL8211DN", .uid = 0x1cc914, - .mask = 0xfffff0, + .mask = 0xffffff, .features = PHY_GBIT_FEATURES, .config = &rtl8211x_config, .startup = &rtl8211x_startup, -- cgit v1.1 From e8194d58bd342631977d1e09d873784d145c7077 Mon Sep 17 00:00:00 2001 From: Stefano Babic Date: Mon, 2 Sep 2013 15:42:29 +0200 Subject: net: fix mask for phy Micrel KSZ9031 Signed-off-by: Stefano Babic --- drivers/net/phy/micrel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index a7450f8..f3e3054 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -174,7 +174,7 @@ int ksz9031_phy_extended_read(struct phy_device *phydev, int devaddr, static struct phy_driver ksz9031_driver = { .name = "Micrel ksz9031", .uid = 0x221620, - .mask = 0xfffffe, + .mask = 0xfffff0, .features = PHY_GBIT_FEATURES, .config = &genphy_config, .startup = &ksz90xx_startup, -- cgit v1.1 From 9ced16fefa35910b4d2cbc9c4688a037bda7f423 Mon Sep 17 00:00:00 2001 From: Stefano Babic Date: Mon, 2 Sep 2013 15:42:31 +0200 Subject: net: add function to read/write extended registers in Micrel Phy Signed-off-by: Stefano Babic --- drivers/net/phy/micrel.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'drivers') diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index f3e3054..5d7e3be 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -100,6 +100,19 @@ int ksz9021_phy_extended_read(struct phy_device *phydev, int regnum) return phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_EXTENDED_DATAR); } + +static int ksz9021_phy_extread(struct phy_device *phydev, int addr, int devaddr, + int regnum) +{ + return ksz9021_phy_extended_read(phydev, regnum); +} + +static int ksz9021_phy_extwrite(struct phy_device *phydev, int addr, + int devaddr, int regnum, u16 val) +{ + return ksz9021_phy_extended_write(phydev, regnum, val); +} + /* Micrel ksz9021 */ static int ksz9021_config(struct phy_device *phydev) { @@ -131,6 +144,8 @@ static struct phy_driver ksz9021_driver = { .config = &ksz9021_config, .startup = &ksz90xx_startup, .shutdown = &genphy_shutdown, + .writeext = &ksz9021_phy_extwrite, + .readext = &ksz9021_phy_extread, }; #endif @@ -171,6 +186,21 @@ int ksz9031_phy_extended_read(struct phy_device *phydev, int devaddr, return phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9031_MMD_REG_DATA); } +static int ksz9031_phy_extread(struct phy_device *phydev, int addr, int devaddr, + int regnum) +{ + return ksz9031_phy_extended_read(phydev, devaddr, regnum, + MII_KSZ9031_MOD_DATA_NO_POST_INC); +}; + +static int ksz9031_phy_extwrite(struct phy_device *phydev, int addr, + int devaddr, int regnum, u16 val) +{ + return ksz9031_phy_extended_write(phydev, devaddr, regnum, + MII_KSZ9031_MOD_DATA_POST_INC_RW, val); +}; + + static struct phy_driver ksz9031_driver = { .name = "Micrel ksz9031", .uid = 0x221620, @@ -179,6 +209,8 @@ static struct phy_driver ksz9031_driver = { .config = &genphy_config, .startup = &ksz90xx_startup, .shutdown = &genphy_shutdown, + .writeext = &ksz9031_phy_extwrite, + .readext = &ksz9031_phy_extread, }; int phy_micrel_init(void) -- cgit v1.1 From 7a36b9c1acb43c6be82b05c21cba1d0f14712d8c Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 20 Sep 2013 16:03:41 +0200 Subject: net: rtl8169: Fix format string currticks() is defined as get_timer(0), which returns an unsigned long, so use %lu instead of %d to print the result. Signed-off-by: Thierry Reding Patch: 276473 --- drivers/net/rtl8169.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index 13fa9c0..9dc10a5 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -501,8 +501,8 @@ static int rtl_send(struct eth_device *dev, void *packet, int length) if (currticks() >= to) { #ifdef DEBUG_RTL8169_TX - puts ("tx timeout/error\n"); - printf ("%s elapsed time : %d\n", __FUNCTION__, currticks()-stime); + puts("tx timeout/error\n"); + printf("%s elapsed time : %lu\n", __func__, currticks()-stime); #endif ret = 0; } else { @@ -604,7 +604,7 @@ static void rtl8169_hw_start(struct eth_device *dev) RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000); #ifdef DEBUG_RTL8169 - printf ("%s elapsed time : %d\n", __FUNCTION__, currticks()-stime); + printf("%s elapsed time : %lu\n", __func__, currticks()-stime); #endif } @@ -642,7 +642,7 @@ static void rtl8169_init_ring(struct eth_device *dev) } #ifdef DEBUG_RTL8169 - printf ("%s elapsed time : %d\n", __FUNCTION__, currticks()-stime); + printf("%s elapsed time : %lu\n", __func__, currticks()-stime); #endif } @@ -683,7 +683,7 @@ static int rtl_reset(struct eth_device *dev, bd_t *bis) txb[5] = dev->enetaddr[5]; #ifdef DEBUG_RTL8169 - printf ("%s elapsed time : %d\n", __FUNCTION__, currticks()-stime); + printf("%s elapsed time : %lu\n", __func__, currticks()-stime); #endif return 0; } -- cgit v1.1 From 65a6691ed3e3396c6aa8b8ca39b9e2631f37a974 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 20 Sep 2013 16:03:44 +0200 Subject: net: rtl8169: Add support for RTL8168evl/8111evl This chip is compatible with other RTL8168 chips and can be found on the NVIDIA Cardhu and Beaver boards. Signed-off-by: Thierry Reding Patch: 276475 --- drivers/net/rtl8169.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index 9dc10a5..290c988 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -246,6 +246,7 @@ static struct { {"RTL-8169sc/8110sc", 0x18, 0xff7e1880,}, {"RTL-8168b/8111sb", 0x30, 0xff7e1880,}, {"RTL-8168b/8111sb", 0x38, 0xff7e1880,}, + {"RTL-8168evl/8111evl", 0x2e, 0xff7e1880,}, {"RTL-8101e", 0x34, 0xff7e1880,}, {"RTL-8100e", 0x32, 0xff7e1880,}, }; -- cgit v1.1 From dfcaa61c33e1fc5f737318cfdbcf7f7b49f237a3 Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Sun, 22 Sep 2013 09:55:49 +0200 Subject: net, phy: fix AR8031 phy_mask AR8035 driver will be never applied because of wrong mask for AR8031 driver. Fix this. Signed-off-by: Heiko Schocher Reported-by: Pavel Nakonechny Cc: Andy Fleming Cc: Joe Hershberger Patch: 276944 --- drivers/net/phy/atheros.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c index 7a1453f..f225d93 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -50,7 +50,7 @@ static struct phy_driver AR8021_driver = { static struct phy_driver AR8031_driver = { .name = "AR8031/AR8033", .uid = 0x4dd074, - .mask = 0xfffff0, + .mask = 0xffffff, .features = PHY_GBIT_FEATURES, .config = ar8021_config, .startup = genphy_startup, -- cgit v1.1 From 47ce8890486be72ce6b634c590a0c6baa2447084 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Tue, 24 Sep 2013 15:38:33 +0900 Subject: net: sh-eth: Add support R8A7791 R8A7791 has the same sh-ether IP core as other SH/rmobile. This patch adds support of R8A7791. Signed-off-by: Nobuhiro Iwamatsu CC: Nobuhiro Iwamatsu CC: Joe Hershberger --- drivers/net/sh_eth.c | 5 +++-- drivers/net/sh_eth.h | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 9020752..5e132f2 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -410,7 +410,7 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd) #if defined(CONFIG_CPU_SH7734) || defined(CONFIG_R8A7740) sh_eth_write(eth, CONFIG_SH_ETHER_SH7734_MII, RMII_MII); -#elif defined(CONFIG_R8A7790) +#elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) sh_eth_write(eth, sh_eth_read(eth, RMIIMR) | 0x1, RMIIMR); #endif /* Configure phy */ @@ -435,7 +435,8 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd) sh_eth_write(eth, GECMR_100B, GECMR); #elif defined(CONFIG_CPU_SH7757) || defined(CONFIG_CPU_SH7752) sh_eth_write(eth, 1, RTRATE); -#elif defined(CONFIG_CPU_SH7724) || defined(CONFIG_R8A7790) +#elif defined(CONFIG_CPU_SH7724) || defined(CONFIG_R8A7790) || \ + defined(CONFIG_R8A7791) val = ECMR_RTM; #endif } else if (phy->speed == 10) { diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h index 43b8ac9..8aa7109 100644 --- a/drivers/net/sh_eth.h +++ b/drivers/net/sh_eth.h @@ -301,7 +301,7 @@ static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = { #elif defined(CONFIG_R8A7740) #define SH_ETH_TYPE_GETHER #define BASE_IO_ADDR 0xE9A00000 -#elif defined(CONFIG_R8A7790) +#elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) #define SH_ETH_TYPE_ETHER #define BASE_IO_ADDR 0xEE700200 #endif @@ -507,7 +507,7 @@ enum FELIC_MODE_BIT { ECMR_PRM = 0x00000001, #ifdef CONFIG_CPU_SH7724 ECMR_RTM = 0x00000010, -#elif defined(CONFIG_R8A7790) +#elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) ECMR_RTM = 0x00000004, #endif -- cgit v1.1 From 227ad7b2b6fab024fff6f60613b0e90c9e3a6724 Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Wed, 25 Sep 2013 17:33:10 +0400 Subject: net: designware: Respect "bus mode" register contents on SW reset "bus mode" register contains lots of fields and some of them don't expect to be written with 0 (zero). So since we're only interested in resetting MAC (which is done with setting the least significant bit of this register with "0") I believe it's better to modify only 1 bit of the register. Signed-off-by: Alexey Brodkin Acked-by: Vipin Kumar Patch: 277864 --- drivers/net/designware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 8413d57..22155b4 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -96,7 +96,7 @@ static int mac_reset(struct eth_device *dev) ulong start; int timeout = CONFIG_MACRESET_TIMEOUT; - writel(DMAMAC_SRST, &dma_p->busmode); + writel(readl(&dma_p->busmode) | DMAMAC_SRST, &dma_p->busmode); if (priv->interface != PHY_INTERFACE_MODE_RGMII) writel(MII_PORTSELECT, &mac_p->conf); -- cgit v1.1 From ed102be70f762afc39bda165ba57ea84dc9be39e Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Wed, 25 Sep 2013 19:27:48 +0400 Subject: net: designware: Fix alignment of buffer descriptors It's important that buffer descriptors are aligned in accordance to GMAC data bus width (32/64/128-bit). It's safe to align to 128-bit (16-bytes) for every bus width type. If buffer descriptor is improperly aligned GMAC discards lower bits of provided address and as a result reads from improper location that doesn't match expected fields. Commit ef76025a99247cdb8f927a2c9f15400678dfb599 "net: Multiple updates/enhancements to designware.c" introduced another structure member "link_printed" right before buffer descriptors while "padding" member was left untouched. This together with alignment of structure itself to 16-byte boundary forces buffer descriptoprs always to be 4-byte aligned that causes driver complete disfunction if GMAC bus width is 64 or 128-bit. Proposed change makes sure all buffer descriptors are 16-byte (128-bit) aligned. Signed-off-by: Alexey Brodkin Patch: 277902 --- drivers/net/designware.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/designware.h b/drivers/net/designware.h index e80002a..5440c92 100644 --- a/drivers/net/designware.h +++ b/drivers/net/designware.h @@ -112,7 +112,7 @@ struct dmamacdescr { u32 dmamac_cntl; void *dmamac_addr; struct dmamacdescr *dmamac_next; -}; +} __aligned(16); /* * txrx_status definitions @@ -224,8 +224,7 @@ struct dw_eth_dev { u32 tx_currdescnum; u32 rx_currdescnum; u32 phy_configured; - int link_printed; - u32 padding; + u32 link_printed; struct dmamacdescr tx_mac_descrtable[CONFIG_TX_DESCR_NUM]; struct dmamacdescr rx_mac_descrtable[CONFIG_RX_DESCR_NUM]; @@ -237,7 +236,7 @@ struct dw_eth_dev { struct eth_dma_regs *dma_regs_p; struct eth_device *dev; -} __attribute__ ((aligned(8))); +}; /* Speed specific definitions */ #define SPEED_10M 1 -- cgit v1.1 From 9c4cffacec7b76299e74cb09e074a21fb6609dbe Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Mon, 30 Sep 2013 12:44:39 +0300 Subject: net: Fix mcast function pointer prototype This fixes the following compiler warnings when activating CONFIG_MCAST_TFTP: tsec.c: In function 'tsec_mcast_addr': tsec.c:130:2: warning: passing argument 2 of 'ether_crc' makes pointer from integer without a cast [enabled by default] In file included from /work/u-boot-net/include/common.h:874:0, from tsec.c:15: /work/u-boot-net/include/net.h:189:5: note: expected 'const unsigned char *' but argument is of type 'u8' tsec.c: In function 'tsec_initialize': tsec.c:646:13: warning: assignment from incompatible pointer type [enabled by default] eth.c: In function 'eth_mcast_join': eth.c:358:2: warning: passing argument 2 of 'eth_current->mcast' makes integer from pointer without a cast [enabled by default] eth.c:358:2: note: expected 'u32' but argument is of type 'u8 *' In the eth_mcast_join() implementation, eth_current->mcast() takes a u8 pointer to the multicast mac address and not a ip address value as implied by its prototype. Fix parameter type mismatch for tsec_macst_addr() (tsec.c): ether_crc() takes a u8 pointer not a u8 value. mcast() is given a u8 pointer to the multicats mac address. Update parameter type for the rest of mcast() instances. Signed-off-by: Claudiu Manoil Patch: 278989 --- drivers/net/rtl8139.c | 2 +- drivers/net/tsec.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index 4186699..208ce5c 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -188,7 +188,7 @@ static int rtl_transmit(struct eth_device *dev, void *packet, int length); static int rtl_poll(struct eth_device *dev); static void rtl_disable(struct eth_device *dev); #ifdef CONFIG_MCAST_TFTP/* This driver already accepts all b/mcast */ -static int rtl_bcast_addr (struct eth_device *dev, u8 bcast_mac, u8 set) +static int rtl_bcast_addr(struct eth_device *dev, const u8 *bcast_mac, u8 set) { return (0); } diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index f5e314b..3428dd0 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -120,14 +120,14 @@ static void tsec_configure_serdes(struct tsec_private *priv) * for PowerPC (tm) is usually the case) in the tregister holds * the entry. */ static int -tsec_mcast_addr (struct eth_device *dev, u8 mcast_mac, u8 set) +tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set) { struct tsec_private *priv = privlist[1]; volatile tsec_t *regs = priv->regs; volatile u32 *reg_array, value; u8 result, whichbit, whichreg; - result = (u8)((ether_crc(MAC_ADDR_LEN,mcast_mac) >> 24) & 0xff); + result = (u8)((ether_crc(MAC_ADDR_LEN, mcast_mac) >> 24) & 0xff); whichbit = result & 0x1f; /* the 5 LSB = which bit to set */ whichreg = result >> 5; /* the 3 MSB = which reg to set it in */ value = (1 << (31-whichbit)); -- cgit v1.1 From 876d4515e38dfcec4346968caf6a0c9c8176ea0b Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Mon, 30 Sep 2013 12:44:40 +0300 Subject: net: tsec: Fix and cleanup tsec_mcast_addr() There are several implementation issues for tsec_mcast_addr() addressed by this patch: * unmanaged, not portable r/w access to registers; fixed with setbits_be32()/ clrbits_be32() * use of volatile pointers * unnecessary forced cast to u8 for the ether_crc() result * removed redundant parens * corrected some comment slips Signed-off-by: Claudiu Manoil Patch: 279000 --- drivers/net/tsec.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index 3428dd0..9ffc801 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -113,32 +113,31 @@ static void tsec_configure_serdes(struct tsec_private *priv) * result. * 2) Use the 8 most significant bits as a hash into a 256-entry * table. The table is controlled through 8 32-bit registers: - * gaddr0-7. gaddr0's MSB is entry 0, and gaddr7's LSB is - * gaddr7. This means that the 3 most significant bits in the + * gaddr0-7. gaddr0's MSB is entry 0, and gaddr7's LSB is entry + * 255. This means that the 3 most significant bits in the * hash index which gaddr register to use, and the 5 other bits * indicate which bit (assuming an IBM numbering scheme, which - * for PowerPC (tm) is usually the case) in the tregister holds + * for PowerPC (tm) is usually the case) in the register holds * the entry. */ static int tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set) { struct tsec_private *priv = privlist[1]; - volatile tsec_t *regs = priv->regs; - volatile u32 *reg_array, value; - u8 result, whichbit, whichreg; + struct tsec __iomem *regs = priv->regs; + u32 result, value; + u8 whichbit, whichreg; - result = (u8)((ether_crc(MAC_ADDR_LEN, mcast_mac) >> 24) & 0xff); - whichbit = result & 0x1f; /* the 5 LSB = which bit to set */ - whichreg = result >> 5; /* the 3 MSB = which reg to set it in */ - value = (1 << (31-whichbit)); + result = ether_crc(MAC_ADDR_LEN, mcast_mac); + whichbit = (result >> 24) & 0x1f; /* the 5 LSB = which bit to set */ + whichreg = result >> 29; /* the 3 MSB = which reg to set it in */ - reg_array = &(regs->hash.gaddr0); + value = 1 << (31-whichbit); + + if (set) + setbits_be32(®s->hash.gaddr0 + whichreg, value); + else + clrbits_be32(®s->hash.gaddr0 + whichreg, value); - if (set) { - reg_array[whichreg] |= value; - } else { - reg_array[whichreg] &= ~value; - } return 0; } #endif /* Multicast TFTP ? */ -- cgit v1.1 From b200204e8e2a2eee081d576ed578d87b75813b46 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Mon, 30 Sep 2013 12:44:41 +0300 Subject: net: tsec: Fix priv pointer in tsec_mcast_addr() Access to privlist[1] (hardcoded referece to the 2nd tsec's priv area) is neither correct nor does it make sense in the current context. Each tsec dev has access to its own priv instance only, and hence to its own set of group address registers (GADDR) to filter multicast addresses. This fix leads to removal of the unused (faulty) privlist[] and related global static vars. Note that mcast() can be called only after eth_device allocation and init, and hence after priv area allocation, so dev->priv is correctly initialized upon mcast() call. Signed-off-by: Claudiu Manoil Patch: 278990 --- drivers/net/tsec.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index 9ffc801..9371ffa 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -33,11 +33,6 @@ typedef volatile struct rtxbd { rxbd8_t rxbd[PKTBUFSRX]; } RTXBD; -#define MAXCONTROLLERS (8) - -static struct tsec_private *privlist[MAXCONTROLLERS]; -static int num_tsecs = 0; - #ifdef __GNUC__ static RTXBD rtx __attribute__ ((aligned(8))); #else @@ -122,7 +117,7 @@ static void tsec_configure_serdes(struct tsec_private *priv) static int tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set) { - struct tsec_private *priv = privlist[1]; + struct tsec_private *priv = (struct tsec_private *)dev->priv; struct tsec __iomem *regs = priv->regs; u32 result, value; u8 whichbit, whichreg; @@ -625,7 +620,6 @@ static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info) if (NULL == priv) return 0; - privlist[num_tsecs++] = priv; priv->regs = tsec_info->regs; priv->phyregs_sgmii = tsec_info->miiregs_sgmii; -- cgit v1.1 From aec84bf6719f9efcc754acfb08b8ca866c8a5e95 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Mon, 30 Sep 2013 12:44:42 +0300 Subject: net: tsec: Cleanup tsec regs init and fix __iomem warns Remove tsec_t typedef. Define macros as getters of tsec and mdio register memory regions, for consistent initialization of various 'regs' fields and also to manage overly long initialization lines. Use the __iomem address space marker to address sparse warnings in tsec.c where IO accessors are used, like: tsec.c:394:19: warning: incorrect type in argument 1 (different address spaces) tsec.c:394:19: expected unsigned int volatile [noderef] *addr tsec.c:394:19: got unsigned int * [...] Add the __iomem address space marker for the tsec pointers to struct tsec_mii_mng memory mapped register regions. This solves the sparse warnings for mixig normal pointers with __iomem pointers for tsec. Signed-off-by: Claudiu Manoil --- drivers/net/tsec.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index 9371ffa..adb6c12 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -5,7 +5,7 @@ * terms of the GNU Public License, Version 2, incorporated * herein by reference. * - * Copyright 2004-2011 Freescale Semiconductor, Inc. + * Copyright 2004-2011, 2013 Freescale Semiconductor, Inc. * (C) Copyright 2003, Motorola, Inc. * author Andy Fleming * @@ -52,7 +52,7 @@ static struct tsec_info_struct tsec_info[] = { #endif #ifdef CONFIG_MPC85XX_FEC { - .regs = (tsec_t *)(TSEC_BASE_ADDR + 0x2000), + .regs = TSEC_GET_REGS(2, 0x2000), .devname = CONFIG_MPC85XX_FEC_NAME, .phyaddr = FEC_PHY_ADDR, .flags = FEC_FLAGS, @@ -141,7 +141,7 @@ tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set) * those we don't care about (unless zero is bad, in which case, * choose a more appropriate value) */ -static void init_registers(tsec_t *regs) +static void init_registers(struct tsec __iomem *regs) { /* Clear IEVENT */ out_be32(®s->ievent, IEVENT_INIT_CLEAR); @@ -188,7 +188,7 @@ static void init_registers(tsec_t *regs) */ static void adjust_link(struct tsec_private *priv, struct phy_device *phydev) { - tsec_t *regs = priv->regs; + struct tsec __iomem *regs = priv->regs; u32 ecntrl, maccfg2; if (!phydev->link) { @@ -242,7 +242,7 @@ static void adjust_link(struct tsec_private *priv, struct phy_device *phydev) void redundant_init(struct eth_device *dev) { struct tsec_private *priv = dev->priv; - tsec_t *regs = priv->regs; + struct tsec __iomem *regs = priv->regs; uint t, count = 0; int fail = 1; static const u8 pkt[] = { @@ -321,7 +321,7 @@ static void startup_tsec(struct eth_device *dev) { int i; struct tsec_private *priv = (struct tsec_private *)dev->priv; - tsec_t *regs = priv->regs; + struct tsec __iomem *regs = priv->regs; /* reset the indices to zero */ rxIdx = 0; @@ -375,7 +375,7 @@ static int tsec_send(struct eth_device *dev, void *packet, int length) int i; int result = 0; struct tsec_private *priv = (struct tsec_private *)dev->priv; - tsec_t *regs = priv->regs; + struct tsec __iomem *regs = priv->regs; /* Find an empty buffer descriptor */ for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) { @@ -411,7 +411,7 @@ static int tsec_recv(struct eth_device *dev) { int length; struct tsec_private *priv = (struct tsec_private *)dev->priv; - tsec_t *regs = priv->regs; + struct tsec __iomem *regs = priv->regs; while (!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) { @@ -447,7 +447,7 @@ static int tsec_recv(struct eth_device *dev) static void tsec_halt(struct eth_device *dev) { struct tsec_private *priv = (struct tsec_private *)dev->priv; - tsec_t *regs = priv->regs; + struct tsec __iomem *regs = priv->regs; clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); setbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); @@ -473,7 +473,7 @@ static int tsec_init(struct eth_device *dev, bd_t * bd) char tmpbuf[MAC_ADDR_LEN]; int i; struct tsec_private *priv = (struct tsec_private *)dev->priv; - tsec_t *regs = priv->regs; + struct tsec __iomem *regs = priv->regs; int ret; /* Make sure the controller is stopped */ @@ -521,7 +521,7 @@ static int tsec_init(struct eth_device *dev, bd_t * bd) static phy_interface_t tsec_get_interface(struct tsec_private *priv) { - tsec_t *regs = priv->regs; + struct tsec __iomem *regs = priv->regs; u32 ecntrl; ecntrl = in_be32(®s->ecntrl); @@ -570,7 +570,7 @@ static int init_phy(struct eth_device *dev) { struct tsec_private *priv = (struct tsec_private *)dev->priv; struct phy_device *phydev; - tsec_t *regs = priv->regs; + struct tsec __iomem *regs = priv->regs; u32 supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | @@ -677,7 +677,7 @@ int tsec_standard_init(bd_t *bis) { struct fsl_pq_mdio_info info; - info.regs = (struct tsec_mii_mng *)CONFIG_SYS_MDIO_BASE_ADDR; + info.regs = TSEC_GET_MDIO_REGS_BASE(1); info.name = DEFAULT_MII_NAME; fsl_pq_mdio_init(bis, &info); -- cgit v1.1 From 5be00a0164892eb695fefa41fb24258072ee2185 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Mon, 30 Sep 2013 12:44:43 +0300 Subject: net: fsl_mdio: Fix warnings for __iomem pointers Add the __iomem address space marker for the tsec pointers to struct tsec_mii_mng memory mapped register regions. This solves the sparse warnings for mixig normal pointers with __iomem pointers for tsec. E.g.: fsl_mdio.c:34:19: warning: incorrect type in argument 1 (different address spaces) fsl_mdio.c:34:19: expected unsigned int volatile [noderef] *addr fsl_mdio.c:34:19: got unsigned int * [...] tsec.c:91:35: warning: incorrect type in argument 1 (different address spaces) tsec.c:91:35: expected struct tsec_mii_mng *phyregs tsec.c:91:35: got struct tsec_mii_mng [noderef] *phyregs_sgmii [...] tsec.c:680:19: warning: incorrect type in assignment (different address spaces) tsec.c:680:19: expected struct tsec_mii_mng *regs tsec.c:680:19: got struct tsec_mii_mng [noderef] * [...] Signed-off-by: Claudiu Manoil --- drivers/net/fsl_mdio.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fsl_mdio.c b/drivers/net/fsl_mdio.c index ce36bd7..1d88e65 100644 --- a/drivers/net/fsl_mdio.c +++ b/drivers/net/fsl_mdio.c @@ -1,5 +1,5 @@ /* - * Copyright 2009-2010 Freescale Semiconductor, Inc. + * Copyright 2009-2010, 2013 Freescale Semiconductor, Inc. * Jun-jie Zhang * Mingkai Hu * @@ -13,7 +13,7 @@ #include #include -void tsec_local_mdio_write(struct tsec_mii_mng *phyregs, int port_addr, +void tsec_local_mdio_write(struct tsec_mii_mng __iomem *phyregs, int port_addr, int dev_addr, int regnum, int value) { int timeout = 1000000; @@ -26,7 +26,7 @@ void tsec_local_mdio_write(struct tsec_mii_mng *phyregs, int port_addr, ; } -int tsec_local_mdio_read(struct tsec_mii_mng *phyregs, int port_addr, +int tsec_local_mdio_read(struct tsec_mii_mng __iomem *phyregs, int port_addr, int dev_addr, int regnum) { int value; @@ -57,7 +57,8 @@ int tsec_local_mdio_read(struct tsec_mii_mng *phyregs, int port_addr, static int fsl_pq_mdio_reset(struct mii_dev *bus) { - struct tsec_mii_mng *regs = bus->priv; + struct tsec_mii_mng __iomem *regs = + (struct tsec_mii_mng __iomem *)bus->priv; /* Reset MII (due to new addresses) */ out_be32(®s->miimcfg, MIIMCFG_RESET_MGMT); @@ -72,7 +73,8 @@ static int fsl_pq_mdio_reset(struct mii_dev *bus) int tsec_phy_read(struct mii_dev *bus, int addr, int dev_addr, int regnum) { - struct tsec_mii_mng *phyregs = bus->priv; + struct tsec_mii_mng __iomem *phyregs = + (struct tsec_mii_mng __iomem *)bus->priv; return tsec_local_mdio_read(phyregs, addr, dev_addr, regnum); } @@ -80,7 +82,8 @@ int tsec_phy_read(struct mii_dev *bus, int addr, int dev_addr, int regnum) int tsec_phy_write(struct mii_dev *bus, int addr, int dev_addr, int regnum, u16 value) { - struct tsec_mii_mng *phyregs = bus->priv; + struct tsec_mii_mng __iomem *phyregs = + (struct tsec_mii_mng __iomem *)bus->priv; tsec_local_mdio_write(phyregs, addr, dev_addr, regnum, value); @@ -101,7 +104,7 @@ int fsl_pq_mdio_init(bd_t *bis, struct fsl_pq_mdio_info *info) bus->reset = fsl_pq_mdio_reset; sprintf(bus->name, info->name); - bus->priv = info->regs; + bus->priv = (void *)info->regs; return mdio_register(bus); } -- cgit v1.1 From 18b338fb3486ac91291e1f94561cb47fd0f4aef2 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Mon, 30 Sep 2013 12:44:44 +0300 Subject: net: tsec: Fix CamelCase issues around BD code Fix bufPtr and the rxIdx/ txIdx occurrences to solve the related checkpatch warnings for the coming patches. Signed-off-by: Claudiu Manoil --- drivers/net/tsec.c | 60 +++++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index adb6c12..289229a 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -25,8 +25,8 @@ DECLARE_GLOBAL_DATA_PTR; #define TX_BUF_CNT 2 -static uint rxIdx; /* index of the current RX buffer */ -static uint txIdx; /* index of the current TX buffer */ +static uint rx_idx; /* index of the current RX buffer */ +static uint tx_idx; /* index of the current TX buffer */ typedef volatile struct rtxbd { txbd8_t txbd[TX_BUF_CNT]; @@ -278,20 +278,20 @@ void redundant_init(struct eth_device *dev) tsec_send(dev, (void *)pkt, sizeof(pkt)); /* Wait for buffer to be received */ - for (t = 0; rtx.rxbd[rxIdx].status & RXBD_EMPTY; t++) { + for (t = 0; rtx.rxbd[rx_idx].status & RXBD_EMPTY; t++) { if (t >= 10 * TOUT_LOOP) { printf("%s: tsec: rx error\n", dev->name); break; } } - if (!memcmp(pkt, (void *)NetRxPackets[rxIdx], sizeof(pkt))) + if (!memcmp(pkt, (void *)NetRxPackets[rx_idx], sizeof(pkt))) fail = 0; - rtx.rxbd[rxIdx].length = 0; - rtx.rxbd[rxIdx].status = - RXBD_EMPTY | (((rxIdx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0); - rxIdx = (rxIdx + 1) % PKTBUFSRX; + rtx.rxbd[rx_idx].length = 0; + rtx.rxbd[rx_idx].status = + RXBD_EMPTY | (((rx_idx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0); + rx_idx = (rx_idx + 1) % PKTBUFSRX; if (in_be32(®s->ievent) & IEVENT_BSY) { out_be32(®s->ievent, IEVENT_BSY); @@ -324,21 +324,21 @@ static void startup_tsec(struct eth_device *dev) struct tsec __iomem *regs = priv->regs; /* reset the indices to zero */ - rxIdx = 0; - txIdx = 0; + rx_idx = 0; + tx_idx = 0; #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129 uint svr; #endif /* Point to the buffer descriptors */ - out_be32(®s->tbase, (unsigned int)(&rtx.txbd[txIdx])); - out_be32(®s->rbase, (unsigned int)(&rtx.rxbd[rxIdx])); + out_be32(®s->tbase, (unsigned int)(&rtx.txbd[tx_idx])); + out_be32(®s->rbase, (unsigned int)(&rtx.rxbd[rx_idx])); /* Initialize the Rx Buffer descriptors */ for (i = 0; i < PKTBUFSRX; i++) { rtx.rxbd[i].status = RXBD_EMPTY; rtx.rxbd[i].length = 0; - rtx.rxbd[i].bufPtr = (uint) NetRxPackets[i]; + rtx.rxbd[i].bufptr = (uint) NetRxPackets[i]; } rtx.rxbd[PKTBUFSRX - 1].status |= RXBD_WRAP; @@ -346,7 +346,7 @@ static void startup_tsec(struct eth_device *dev) for (i = 0; i < TX_BUF_CNT; i++) { rtx.txbd[i].status = 0; rtx.txbd[i].length = 0; - rtx.txbd[i].bufPtr = 0; + rtx.txbd[i].bufptr = 0; } rtx.txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP; @@ -378,31 +378,31 @@ static int tsec_send(struct eth_device *dev, void *packet, int length) struct tsec __iomem *regs = priv->regs; /* Find an empty buffer descriptor */ - for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) { + for (i = 0; rtx.txbd[tx_idx].status & TXBD_READY; i++) { if (i >= TOUT_LOOP) { debug("%s: tsec: tx buffers full\n", dev->name); return result; } } - rtx.txbd[txIdx].bufPtr = (uint) packet; - rtx.txbd[txIdx].length = length; - rtx.txbd[txIdx].status |= + rtx.txbd[tx_idx].bufptr = (uint) packet; + rtx.txbd[tx_idx].length = length; + rtx.txbd[tx_idx].status |= (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT); /* Tell the DMA to go */ out_be32(®s->tstat, TSTAT_CLEAR_THALT); /* Wait for buffer to be transmitted */ - for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) { + for (i = 0; rtx.txbd[tx_idx].status & TXBD_READY; i++) { if (i >= TOUT_LOOP) { debug("%s: tsec: tx error\n", dev->name); return result; } } - txIdx = (txIdx + 1) % TX_BUF_CNT; - result = rtx.txbd[txIdx].status & TXBD_STATS; + tx_idx = (tx_idx + 1) % TX_BUF_CNT; + result = rtx.txbd[tx_idx].status & TXBD_STATS; return result; } @@ -413,25 +413,25 @@ static int tsec_recv(struct eth_device *dev) struct tsec_private *priv = (struct tsec_private *)dev->priv; struct tsec __iomem *regs = priv->regs; - while (!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) { + while (!(rtx.rxbd[rx_idx].status & RXBD_EMPTY)) { - length = rtx.rxbd[rxIdx].length; + length = rtx.rxbd[rx_idx].length; /* Send the packet up if there were no errors */ - if (!(rtx.rxbd[rxIdx].status & RXBD_STATS)) { - NetReceive(NetRxPackets[rxIdx], length - 4); + if (!(rtx.rxbd[rx_idx].status & RXBD_STATS)) { + NetReceive(NetRxPackets[rx_idx], length - 4); } else { printf("Got error %x\n", - (rtx.rxbd[rxIdx].status & RXBD_STATS)); + (rtx.rxbd[rx_idx].status & RXBD_STATS)); } - rtx.rxbd[rxIdx].length = 0; + rtx.rxbd[rx_idx].length = 0; /* Set the wrap bit if this is the last element in the list */ - rtx.rxbd[rxIdx].status = - RXBD_EMPTY | (((rxIdx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0); + rtx.rxbd[rx_idx].status = + RXBD_EMPTY | (((rx_idx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0); - rxIdx = (rxIdx + 1) % PKTBUFSRX; + rx_idx = (rx_idx + 1) % PKTBUFSRX; } if (in_be32(®s->ievent) & IEVENT_BSY) { -- cgit v1.1 From 9c9141fd04f0991209dab9fe2716ce19b2a4f552 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Fri, 4 Oct 2013 19:13:53 +0300 Subject: net: tsec: Use portable types and accessors for BDs Currently, the buffer descriptor (BD) fields cannot be correctly accessed by a little endian processor. This patch fixes the issue by making the access of BDs to be portable among different cpu architectures. Use portable data types for the Rx/Tx buffer descriptor fields. Use portable I/O accessors to insure that the big endian BDs are correctly accessed by little endian cpus too, and to insure proper sync with the H/W. Removed the redundant RTXBD "volatile" type, as proper synchronization around BD data accesses is provided by the I/O accessors now. The "sparse" tool was also used to verify the correctness of these changes. Cc: Scott Wood Signed-off-by: Claudiu Manoil --- drivers/net/tsec.c | 88 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 46 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index 289229a..e354fad 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -28,13 +28,10 @@ DECLARE_GLOBAL_DATA_PTR; static uint rx_idx; /* index of the current RX buffer */ static uint tx_idx; /* index of the current TX buffer */ -typedef volatile struct rtxbd { - txbd8_t txbd[TX_BUF_CNT]; - rxbd8_t rxbd[PKTBUFSRX]; -} RTXBD; - #ifdef __GNUC__ -static RTXBD rtx __attribute__ ((aligned(8))); +static struct txbd8 __iomem txbd[TX_BUF_CNT] __aligned(8); +static struct rxbd8 __iomem rxbd[PKTBUFSRX] __aligned(8); + #else #error "rtx must be 64-bit aligned" #endif @@ -275,10 +272,11 @@ void redundant_init(struct eth_device *dev) clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); do { + uint16_t status; tsec_send(dev, (void *)pkt, sizeof(pkt)); /* Wait for buffer to be received */ - for (t = 0; rtx.rxbd[rx_idx].status & RXBD_EMPTY; t++) { + for (t = 0; in_be16(&rxbd[rx_idx].status) & RXBD_EMPTY; t++) { if (t >= 10 * TOUT_LOOP) { printf("%s: tsec: rx error\n", dev->name); break; @@ -288,9 +286,11 @@ void redundant_init(struct eth_device *dev) if (!memcmp(pkt, (void *)NetRxPackets[rx_idx], sizeof(pkt))) fail = 0; - rtx.rxbd[rx_idx].length = 0; - rtx.rxbd[rx_idx].status = - RXBD_EMPTY | (((rx_idx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0); + out_be16(&rxbd[rx_idx].length, 0); + status = RXBD_EMPTY; + if ((rx_idx + 1) == PKTBUFSRX) + status |= RXBD_WRAP; + out_be16(&rxbd[rx_idx].status, status); rx_idx = (rx_idx + 1) % PKTBUFSRX; if (in_be32(®s->ievent) & IEVENT_BSY) { @@ -319,9 +319,10 @@ void redundant_init(struct eth_device *dev) */ static void startup_tsec(struct eth_device *dev) { - int i; struct tsec_private *priv = (struct tsec_private *)dev->priv; struct tsec __iomem *regs = priv->regs; + uint16_t status; + int i; /* reset the indices to zero */ rx_idx = 0; @@ -331,24 +332,26 @@ static void startup_tsec(struct eth_device *dev) #endif /* Point to the buffer descriptors */ - out_be32(®s->tbase, (unsigned int)(&rtx.txbd[tx_idx])); - out_be32(®s->rbase, (unsigned int)(&rtx.rxbd[rx_idx])); + out_be32(®s->tbase, (u32)&txbd[0]); + out_be32(®s->rbase, (u32)&rxbd[0]); /* Initialize the Rx Buffer descriptors */ for (i = 0; i < PKTBUFSRX; i++) { - rtx.rxbd[i].status = RXBD_EMPTY; - rtx.rxbd[i].length = 0; - rtx.rxbd[i].bufptr = (uint) NetRxPackets[i]; + out_be16(&rxbd[i].status, RXBD_EMPTY); + out_be16(&rxbd[i].length, 0); + out_be32(&rxbd[i].bufptr, (u32)NetRxPackets[i]); } - rtx.rxbd[PKTBUFSRX - 1].status |= RXBD_WRAP; + status = in_be16(&rxbd[PKTBUFSRX - 1].status); + out_be16(&rxbd[PKTBUFSRX - 1].status, status | RXBD_WRAP); /* Initialize the TX Buffer Descriptors */ for (i = 0; i < TX_BUF_CNT; i++) { - rtx.txbd[i].status = 0; - rtx.txbd[i].length = 0; - rtx.txbd[i].bufptr = 0; + out_be16(&txbd[i].status, 0); + out_be16(&txbd[i].length, 0); + out_be32(&txbd[i].bufptr, 0); } - rtx.txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP; + status = in_be16(&txbd[TX_BUF_CNT - 1].status); + out_be16(&txbd[TX_BUF_CNT - 1].status, status | TXBD_WRAP); #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129 svr = get_svr(); @@ -372,29 +375,31 @@ static void startup_tsec(struct eth_device *dev) */ static int tsec_send(struct eth_device *dev, void *packet, int length) { - int i; - int result = 0; struct tsec_private *priv = (struct tsec_private *)dev->priv; struct tsec __iomem *regs = priv->regs; + uint16_t status; + int result = 0; + int i; /* Find an empty buffer descriptor */ - for (i = 0; rtx.txbd[tx_idx].status & TXBD_READY; i++) { + for (i = 0; in_be16(&txbd[tx_idx].status) & TXBD_READY; i++) { if (i >= TOUT_LOOP) { debug("%s: tsec: tx buffers full\n", dev->name); return result; } } - rtx.txbd[tx_idx].bufptr = (uint) packet; - rtx.txbd[tx_idx].length = length; - rtx.txbd[tx_idx].status |= - (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT); + out_be32(&txbd[tx_idx].bufptr, (u32)packet); + out_be16(&txbd[tx_idx].length, length); + status = in_be16(&txbd[tx_idx].status); + out_be16(&txbd[tx_idx].status, status | + (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT)); /* Tell the DMA to go */ out_be32(®s->tstat, TSTAT_CLEAR_THALT); /* Wait for buffer to be transmitted */ - for (i = 0; rtx.txbd[tx_idx].status & TXBD_READY; i++) { + for (i = 0; in_be16(&txbd[tx_idx].status) & TXBD_READY; i++) { if (i >= TOUT_LOOP) { debug("%s: tsec: tx error\n", dev->name); return result; @@ -402,34 +407,33 @@ static int tsec_send(struct eth_device *dev, void *packet, int length) } tx_idx = (tx_idx + 1) % TX_BUF_CNT; - result = rtx.txbd[tx_idx].status & TXBD_STATS; + result = in_be16(&txbd[tx_idx].status) & TXBD_STATS; return result; } static int tsec_recv(struct eth_device *dev) { - int length; struct tsec_private *priv = (struct tsec_private *)dev->priv; struct tsec __iomem *regs = priv->regs; - while (!(rtx.rxbd[rx_idx].status & RXBD_EMPTY)) { - - length = rtx.rxbd[rx_idx].length; + while (!(in_be16(&rxbd[rx_idx].status) & RXBD_EMPTY)) { + int length = in_be16(&rxbd[rx_idx].length); + uint16_t status = in_be16(&rxbd[rx_idx].status); /* Send the packet up if there were no errors */ - if (!(rtx.rxbd[rx_idx].status & RXBD_STATS)) { + if (!(status & RXBD_STATS)) NetReceive(NetRxPackets[rx_idx], length - 4); - } else { - printf("Got error %x\n", - (rtx.rxbd[rx_idx].status & RXBD_STATS)); - } + else + printf("Got error %x\n", (status & RXBD_STATS)); - rtx.rxbd[rx_idx].length = 0; + out_be16(&rxbd[rx_idx].length, 0); + status = RXBD_EMPTY; /* Set the wrap bit if this is the last element in the list */ - rtx.rxbd[rx_idx].status = - RXBD_EMPTY | (((rx_idx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0); + if ((rx_idx + 1) == PKTBUFSRX) + status |= RXBD_WRAP; + out_be16(&rxbd[rx_idx].status, status); rx_idx = (rx_idx + 1) % PKTBUFSRX; } -- cgit v1.1 From 82ef75ca5c69c7d053c07f509a901d2ad2e29570 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Mon, 30 Sep 2013 12:44:46 +0300 Subject: net: tsec: Use portable regs type (uint->u32) Use cross arch portable u32 instead of uint for the tsec registers. Remove the typedefs for the register struct definitions in the process. Fix long lines. Signed-off-by: Claudiu Manoil --- drivers/net/tsec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index e354fad..082cdec 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -166,7 +166,7 @@ static void init_registers(struct tsec __iomem *regs) out_be32(®s->rctrl, 0x00000000); /* Init RMON mib registers */ - memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t)); + memset((void *)®s->rmon, 0, sizeof(regs->rmon)); out_be32(®s->rmon.cam1, 0xffffffff); out_be32(®s->rmon.cam2, 0xffffffff); -- cgit v1.1 From b1690bc39cfdba82be34b1a98abc319339070698 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Mon, 30 Sep 2013 12:44:47 +0300 Subject: net: tsec: Fix mac addr setup portability, cleanup Fix the 32-bit memory access that is not "endianess safe", i.e. not giving the desired byte layout for LE cpus: tempval = *((uint *) (tmpbuf + 4)), where 'char tmpbuf[]'. Free the stack from rendundant local vars: tmpbuf[] and i. Use a portable type (u32) for the 32bit tsec register value holder: tempval. Signed-off-by: Claudiu Manoil --- drivers/net/tsec.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index 082cdec..e9138f0 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -473,11 +473,9 @@ static void tsec_halt(struct eth_device *dev) */ static int tsec_init(struct eth_device *dev, bd_t * bd) { - uint tempval; - char tmpbuf[MAC_ADDR_LEN]; - int i; struct tsec_private *priv = (struct tsec_private *)dev->priv; struct tsec __iomem *regs = priv->regs; + u32 tempval; int ret; /* Make sure the controller is stopped */ @@ -490,16 +488,16 @@ static int tsec_init(struct eth_device *dev, bd_t * bd) out_be32(®s->ecntrl, ECNTRL_INIT_SETTINGS); /* Copy the station address into the address registers. - * Backwards, because little endian MACS are dumb */ - for (i = 0; i < MAC_ADDR_LEN; i++) - tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i]; - - tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) | - tmpbuf[3]; + * For a station address of 0x12345678ABCD in transmission + * order (BE), MACnADDR1 is set to 0xCDAB7856 and + * MACnADDR2 is set to 0x34120000. + */ + tempval = (dev->enetaddr[5] << 24) | (dev->enetaddr[4] << 16) | + (dev->enetaddr[3] << 8) | dev->enetaddr[2]; out_be32(®s->macstnaddr1, tempval); - tempval = *((uint *) (tmpbuf + 4)); + tempval = (dev->enetaddr[1] << 24) | (dev->enetaddr[0] << 16); out_be32(®s->macstnaddr2, tempval); -- cgit v1.1 From 317745785341774644b8bb1cbb0300155f31cee6 Mon Sep 17 00:00:00 2001 From: Chunhe Lan Date: Fri, 1 Nov 2013 17:17:44 +0800 Subject: net/phy: Fix the phy id mask of AR8031 The both AR8031 and AR8035 belong to Atheros 803x serial PHY. So the phy id mask of AR8031 is the same to the phy id mask of AR8035. The right mask value is 0x4fffff. This patch has been tested on the P1010 and P1023. Signed-off-by: Chunhe Lan Cc: Joe Hershberger Patch: 287748 --- drivers/net/phy/atheros.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c index f225d93..215658a 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -50,7 +50,7 @@ static struct phy_driver AR8021_driver = { static struct phy_driver AR8031_driver = { .name = "AR8031/AR8033", .uid = 0x4dd074, - .mask = 0xffffff, + .mask = 0x4fffff, .features = PHY_GBIT_FEATURES, .config = ar8021_config, .startup = genphy_startup, -- cgit v1.1 From e003ba5bfc57ff7d065967e263fa24e3ef28ea0a Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 2 Nov 2013 16:40:42 -0200 Subject: net: phy: atheros: Fix masks for AR8035 and AR8021 The masks were ignoring the last 4 bits which didn't allow detection differences between the ar8031 and ar8035. Signed-off-by: Jon Nettleton Signed-off-by: Fabio Estevam Patch: 288018 --- drivers/net/phy/atheros.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c index 215658a..b20b4df 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -40,7 +40,7 @@ static int ar8035_config(struct phy_device *phydev) static struct phy_driver AR8021_driver = { .name = "AR8021", .uid = 0x4dd040, - .mask = 0xfffff0, + .mask = 0x4fffff, .features = PHY_GBIT_FEATURES, .config = ar8021_config, .startup = genphy_startup, -- cgit v1.1 From 8712adfd0595ea68ce06fb22420489dacc3a6cc6 Mon Sep 17 00:00:00 2001 From: Rojhalat Ibrahim Date: Mon, 7 Oct 2013 18:30:39 +0200 Subject: drivers/net/e1000: Introduce CONFIG_E1000_NO_NVM The e1000 driver expects to always have some kind of non-volatile memory attached directly to the ethernet controller chip. This means that I would have to add an additional separate flash chip to my custom board just to store essentially the MAC address. Since I don't want to do that, this patch introduces a new config option CONFIG_E1000_NO_NVM. If defined it disables all accesses to the NVM. I have tested the patch with a 82574 controller. Signed-off-by: Rojhalat Ibrahim --- drivers/net/e1000.c | 34 +++++++++++++++++++++++++++++----- drivers/net/e1000.h | 9 +++++++++ 2 files changed, 38 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c index 57aa53d..9a66e68 100644 --- a/drivers/net/e1000.c +++ b/drivers/net/e1000.c @@ -114,12 +114,13 @@ static int e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, static int32_t e1000_phy_hw_reset(struct e1000_hw *hw); static int e1000_phy_reset(struct e1000_hw *hw); static int e1000_detect_gig_phy(struct e1000_hw *hw); -static void e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw); 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_E1000_NO_NVM +static void e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw); static int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data); @@ -885,6 +886,7 @@ static int e1000_validate_eeprom_checksum(struct e1000_hw *hw) return -E1000_ERR_EEPROM; } +#endif /* CONFIG_E1000_NO_NVM */ /***************************************************************************** * Set PHY to class A mode @@ -897,6 +899,7 @@ static int e1000_validate_eeprom_checksum(struct e1000_hw *hw) static int32_t e1000_set_phy_mode(struct e1000_hw *hw) { +#ifndef CONFIG_E1000_NO_NVM int32_t ret_val; uint16_t eeprom_data; @@ -923,10 +926,11 @@ e1000_set_phy_mode(struct e1000_hw *hw) hw->phy_reset_disable = false; } } - +#endif return E1000_SUCCESS; } +#ifndef CONFIG_E1000_NO_NVM /*************************************************************************** * * Obtaining software semaphore bit (SMBI) before resetting PHY. @@ -965,6 +969,7 @@ e1000_get_software_semaphore(struct e1000_hw *hw) return E1000_SUCCESS; } +#endif /*************************************************************************** * This function clears HW semaphore bits. @@ -977,6 +982,7 @@ e1000_get_software_semaphore(struct e1000_hw *hw) static void e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw) { +#ifndef CONFIG_E1000_NO_NVM uint32_t swsm; DEBUGFUNC(); @@ -991,6 +997,7 @@ e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw) } else swsm &= ~(E1000_SWSM_SWESMBI); E1000_WRITE_REG(hw, SWSM, swsm); +#endif } /*************************************************************************** @@ -1007,6 +1014,7 @@ e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw) static int32_t e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw) { +#ifndef CONFIG_E1000_NO_NVM int32_t timeout; uint32_t swsm; @@ -1043,7 +1051,7 @@ e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw) "SWESMBI bit is set.\n"); return -E1000_ERR_EEPROM; } - +#endif return E1000_SUCCESS; } @@ -1097,6 +1105,7 @@ static bool e1000_is_second_port(struct e1000_hw *hw) } } +#ifndef CONFIG_E1000_NO_NVM /****************************************************************************** * Reads the adapter's MAC address from the EEPROM and inverts the LSB for the * second function of dual function devices @@ -1136,6 +1145,7 @@ e1000_read_mac_addr(struct eth_device *nic) #endif return 0; } +#endif /****************************************************************************** * Initializes receive address filters. @@ -1764,9 +1774,11 @@ static int e1000_setup_link(struct eth_device *nic) { struct e1000_hw *hw = nic->priv; - uint32_t ctrl_ext; int32_t ret_val; +#ifndef CONFIG_E1000_NO_NVM + uint32_t ctrl_ext; uint16_t eeprom_data; +#endif DEBUGFUNC(); @@ -1775,6 +1787,7 @@ e1000_setup_link(struct eth_device *nic) if (e1000_check_phy_reset_block(hw)) return E1000_SUCCESS; +#ifndef CONFIG_E1000_NO_NVM /* 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 @@ -1788,7 +1801,7 @@ e1000_setup_link(struct eth_device *nic) DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } - +#endif if (hw->fc == e1000_fc_default) { switch (hw->mac_type) { case e1000_ich8lan: @@ -1797,6 +1810,7 @@ e1000_setup_link(struct eth_device *nic) hw->fc = e1000_fc_full; break; default: +#ifndef CONFIG_E1000_NO_NVM ret_val = e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data); if (ret_val) { @@ -1809,6 +1823,7 @@ e1000_setup_link(struct eth_device *nic) EEPROM_WORD0F_ASM_DIR) hw->fc = e1000_fc_tx_pause; else +#endif hw->fc = e1000_fc_full; break; } @@ -1828,6 +1843,7 @@ e1000_setup_link(struct eth_device *nic) DEBUGOUT("After fix-ups FlowControl is now = %x\n", hw->fc); +#ifndef CONFIG_E1000_NO_NVM /* Take the 4 bits from EEPROM word 0x0F that determine the initial * polarity value for the SW controlled pins, and setup the * Extended Device Control reg with that info. @@ -1840,6 +1856,7 @@ e1000_setup_link(struct eth_device *nic) SWDPIO__EXT_SHIFT); E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); } +#endif /* Call the necessary subroutine to configure the link. */ ret_val = (hw->media_type == e1000_media_type_fiber) ? @@ -5196,6 +5213,7 @@ e1000_initialize(bd_t * bis) e1000_reset_hw(hw); list_add_tail(&hw->list_node, &e1000_hw_list); +#ifndef CONFIG_E1000_NO_NVM /* Validate the EEPROM and get chipset information */ #if !defined(CONFIG_MVBC_1G) if (e1000_init_eeprom_params(hw)) { @@ -5206,11 +5224,17 @@ e1000_initialize(bd_t * bis) continue; #endif e1000_read_mac_addr(nic); +#endif e1000_get_bus_type(hw); +#ifndef CONFIG_E1000_NO_NVM printf("e1000: %02x:%02x:%02x:%02x:%02x:%02x\n ", nic->enetaddr[0], nic->enetaddr[1], nic->enetaddr[2], nic->enetaddr[3], nic->enetaddr[4], nic->enetaddr[5]); +#else + memset(nic->enetaddr, 0, 6); + printf("e1000: no NVM\n"); +#endif /* Set up the function pointers and register the device */ nic->init = e1000_init; diff --git a/drivers/net/e1000.h b/drivers/net/e1000.h index 25884f5..ff87af2 100644 --- a/drivers/net/e1000.h +++ b/drivers/net/e1000.h @@ -63,11 +63,14 @@ struct e1000_hw_stats; /* Internal E1000 helper functions */ struct e1000_hw *e1000_find_card(unsigned int cardnum); + +#ifndef CONFIG_E1000_NO_NVM int32_t e1000_acquire_eeprom(struct e1000_hw *hw); void e1000_standby_eeprom(struct e1000_hw *hw); void e1000_release_eeprom(struct e1000_hw *hw); void e1000_raise_ee_clk(struct e1000_hw *hw, uint32_t *eecd); void e1000_lower_ee_clk(struct e1000_hw *hw, uint32_t *eecd); +#endif #ifdef CONFIG_E1000_SPI int do_e1000_spi(cmd_tbl_t *cmdtp, struct e1000_hw *hw, @@ -1019,6 +1022,7 @@ struct e1000_hw_stats { uint64_t tsctfc; }; +#ifndef CONFIG_E1000_NO_NVM struct e1000_eeprom_info { e1000_eeprom_type type; uint16_t word_size; @@ -1029,6 +1033,7 @@ e1000_eeprom_type type; bool use_eerd; bool use_eewr; }; +#endif typedef enum { e1000_smart_speed_default = 0, @@ -1081,10 +1086,14 @@ struct e1000_hw { uint32_t io_base; #endif uint32_t asf_firmware_present; +#ifndef CONFIG_E1000_NO_NVM uint32_t eeprom_semaphore_present; +#endif uint32_t swfw_sync_present; uint32_t swfwhw_semaphore_present; +#ifndef CONFIG_E1000_NO_NVM struct e1000_eeprom_info eeprom; +#endif e1000_ms_type master_slave; e1000_ms_type original_master_slave; e1000_ffe_config ffe_config_state; -- cgit v1.1 From c583ee16cb5db73fc299bb679ecb75a5abb3ca47 Mon Sep 17 00:00:00 2001 From: Andrew Ruder Date: Tue, 22 Oct 2013 19:09:02 -0500 Subject: net: dm9000: random mac address support When an unprogrammed EEPROM is attached to a dm9000, the dm9000 will come up with a invalid MAC address of ff:ff:ff:ff:ff:ff. Add code that gets enabled if CONFIG_RANDOM_MACADDR is enabled that generates a random (and valid) locally administered MAC address that allows the system to network boot until a real MAC address can be configured. Signed-off-by: Andrew Ruder --- drivers/net/dm9000x.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/net/dm9000x.c b/drivers/net/dm9000x.c index f7170e0..b68d808 100644 --- a/drivers/net/dm9000x.c +++ b/drivers/net/dm9000x.c @@ -342,6 +342,15 @@ static int dm9000_init(struct eth_device *dev, bd_t *bd) DM9000_iow(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS); printf("MAC: %pM\n", dev->enetaddr); + if (!is_valid_ether_addr(dev->enetaddr)) { +#ifdef CONFIG_RANDOM_MACADDR + printf("Bad MAC address (uninitialized EEPROM?), randomizing\n"); + eth_random_enetaddr(dev->enetaddr); + printf("MAC: %pM\n", dev->enetaddr); +#else + printf("WARNING: Bad MAC address (uninitialized EEPROM?)\n"); +#endif + } /* fill device MAC address registers */ for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++) -- cgit v1.1 From 3a530d1b3e947c09e882dda8883aa608458a598c Mon Sep 17 00:00:00 2001 From: David Dueck Date: Tue, 5 Nov 2013 17:23:02 +0100 Subject: phy: Use supported field during autonegotiation The current code incorrectly detects gigabit capabilities for some 100Mbit/s phys. (lan8720a) Signed-off-by: David Dueck --- drivers/net/phy/phy.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 62925bb..c691fbb 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -275,13 +275,14 @@ int genphy_parse_link(struct phy_device *phydev) int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); /* We're using autonegotiation */ - if (mii_reg & BMSR_ANEGCAPABLE) { + if (phydev->supported & SUPPORTED_Autoneg) { u32 lpa = 0; int gblpa = 0; u32 estatus = 0; /* Check for gigabit capability */ - if (mii_reg & BMSR_ERCAP) { + if (phydev->supported & (SUPPORTED_1000baseT_Full | + SUPPORTED_1000baseT_Half)) { /* We want a list of states supported by * both PHYs in the link */ -- cgit v1.1 From f27f3b5266d28b8d3e80e0e8f4cafdd14268b62a Mon Sep 17 00:00:00 2001 From: David Dueck Date: Tue, 5 Nov 2013 17:23:03 +0100 Subject: phy: Use general phy code for smsc lan8720a Signed-off-by: David Dueck --- drivers/net/phy/smsc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index 60ed92d..bfd9815 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -12,6 +12,7 @@ */ #include +/* This code does not check the partner abilities. */ static int smsc_parse_status(struct phy_device *phydev) { int mii_reg; @@ -64,7 +65,7 @@ static struct phy_driver lan8710_driver = { .mask = 0xffff0, .features = PHY_BASIC_FEATURES, .config = &genphy_config_aneg, - .startup = &smsc_startup, + .startup = &genphy_startup, .shutdown = &genphy_shutdown, }; -- cgit v1.1 From a5144237ac6dce3a38a73a51c217636a37d1e0b6 Mon Sep 17 00:00:00 2001 From: Srikanth Thokala Date: Fri, 8 Nov 2013 22:55:48 +0530 Subject: net: zynq_gem: Add d-cache support Added d-cache support for zynq_gem.c, Observed a difference of +0.8 MiB/s when downloading a file of size of 3007944Bytes. With d-cache OFF: ---------------- Filename 'uImage'. Load address: 0x800 Loading: ################################################################# ################################################################# ################################################################# ########## 1.3 MiB/s done Bytes transferred = 3007944 (2de5c8 hex) With d-cache ON: --------------- Filename 'uImage'. Load address: 0x800 Loading: ################################################################# ################################################################# ################################################################# ########## 2.1 MiB/s done Bytes transferred = 3007944 (2de5c8 hex) Changes on zynq_gem for d-cache support: - Tx and Rx buffers are cache-aligned - Updated logic for invalidating Rx buffers and flushing Tx buffers. - Tx and Rx BD's are allocated from non-cacheable region. (When BDs are cached, we don't see a consistent link) - Use TX BD status intead of txsr status checks. Signed-off-by: Srikanth Thokala Signed-off-by: Jagannadha Sutradharudu Teki Signed-off-by: Michal Simek --- drivers/net/zynq_gem.c | 82 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 236a753..6a017a8 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -43,11 +43,6 @@ #define ZYNQ_GEM_TXBUF_WRAP_MASK 0x40000000 #define ZYNQ_GEM_TXBUF_LAST_MASK 0x00008000 /* Last buffer */ -#define ZYNQ_GEM_TXSR_HRESPNOK_MASK 0x00000100 /* Transmit hresp not OK */ -#define ZYNQ_GEM_TXSR_URUN_MASK 0x00000040 /* Transmit underrun */ -/* Transmit buffs exhausted mid frame */ -#define ZYNQ_GEM_TXSR_BUFEXH_MASK 0x00000010 - #define ZYNQ_GEM_NWCTRL_TXEN_MASK 0x00000008 /* Enable transmit */ #define ZYNQ_GEM_NWCTRL_RXEN_MASK 0x00000004 /* Enable receive */ #define ZYNQ_GEM_NWCTRL_MDEN_MASK 0x00000010 /* Enable MDIO port */ @@ -90,6 +85,11 @@ */ #define PHY_DETECT_MASK 0x1808 +/* TX BD status masks */ +#define ZYNQ_GEM_TXBUF_FRMLEN_MASK 0x000007ff +#define ZYNQ_GEM_TXBUF_EXHAUSTED 0x08000000 +#define ZYNQ_GEM_TXBUF_UNDERRUN 0x10000000 + /* Device registers */ struct zynq_gem_regs { u32 nwctrl; /* Network Control reg */ @@ -123,12 +123,18 @@ struct emac_bd { }; #define RX_BUF 3 +/* Page table entries are set to 1MB, or multiples of 1MB + * (not < 1MB). driver uses less bd's so use 1MB bdspace. + */ +#define BD_SPACE 0x100000 +/* BD separation space */ +#define BD_SEPRN_SPACE 64 /* Initialized, rxbd_current, rx_first_buf must be 0 after init */ struct zynq_gem_priv { - struct emac_bd tx_bd; - struct emac_bd rx_bd[RX_BUF]; - char rxbuffers[RX_BUF * PKTSIZE_ALIGN]; + struct emac_bd *tx_bd; + struct emac_bd *rx_bd; + char *rxbuffers; u32 rxbd_current; u32 rx_first_buf; int phyaddr; @@ -299,20 +305,18 @@ static int zynq_gem_init(struct eth_device *dev, bd_t * bis) readl(®s->stat[i]); /* Setup RxBD space */ - memset(&(priv->rx_bd), 0, sizeof(priv->rx_bd)); - /* Create the RxBD ring */ - memset(&(priv->rxbuffers), 0, sizeof(priv->rxbuffers)); + memset(priv->rx_bd, 0, RX_BUF * sizeof(struct emac_bd)); for (i = 0; i < RX_BUF; i++) { priv->rx_bd[i].status = 0xF0000000; priv->rx_bd[i].addr = - (u32)((char *)&(priv->rxbuffers) + + ((u32)(priv->rxbuffers) + (i * PKTSIZE_ALIGN)); } /* WRAP bit to last BD */ priv->rx_bd[--i].addr |= ZYNQ_GEM_RXBUF_WRAP_MASK; /* Write RxBDs to IP */ - writel((u32)&(priv->rx_bd), ®s->rxqbase); + writel((u32)priv->rx_bd, ®s->rxqbase); /* Setup for DMA Configuration register */ writel(ZYNQ_GEM_DMACR_INIT, ®s->dmacr); @@ -368,32 +372,35 @@ static int zynq_gem_init(struct eth_device *dev, bd_t * bis) static int zynq_gem_send(struct eth_device *dev, void *ptr, int len) { - u32 status; + u32 addr, size; struct zynq_gem_priv *priv = dev->priv; struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase; - const u32 mask = ZYNQ_GEM_TXSR_HRESPNOK_MASK | \ - ZYNQ_GEM_TXSR_URUN_MASK | ZYNQ_GEM_TXSR_BUFEXH_MASK; /* setup BD */ - writel((u32)&(priv->tx_bd), ®s->txqbase); + writel((u32)priv->tx_bd, ®s->txqbase); /* Setup Tx BD */ - memset((void *)&(priv->tx_bd), 0, sizeof(struct emac_bd)); + memset(priv->tx_bd, 0, sizeof(struct emac_bd)); + + priv->tx_bd->addr = (u32)ptr; + priv->tx_bd->status = (len & ZYNQ_GEM_TXBUF_FRMLEN_MASK) | + ZYNQ_GEM_TXBUF_LAST_MASK; - priv->tx_bd.addr = (u32)ptr; - priv->tx_bd.status = len | ZYNQ_GEM_TXBUF_LAST_MASK; + addr = (u32) ptr; + addr &= ~(ARCH_DMA_MINALIGN - 1); + size = roundup(len, ARCH_DMA_MINALIGN); + flush_dcache_range(addr, addr + size); + barrier(); /* Start transmit */ setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_STARTTX_MASK); - /* Read the stat register to know if the packet has been transmitted */ - status = readl(®s->txsr); - if (status & mask) - printf("Something has gone wrong here!? Status is 0x%x.\n", - status); + /* Read TX BD status */ + if (priv->tx_bd->status & ZYNQ_GEM_TXBUF_UNDERRUN) + printf("TX underrun\n"); + if (priv->tx_bd->status & ZYNQ_GEM_TXBUF_EXHAUSTED) + printf("TX buffers exhausted in mid frame\n"); - /* Clear Tx status register before leaving . */ - writel(status, ®s->txsr); return 0; } @@ -416,8 +423,12 @@ static int zynq_gem_recv(struct eth_device *dev) frame_len = current_bd->status & ZYNQ_GEM_RXBUF_LEN_MASK; if (frame_len) { - NetReceive((u8 *) (current_bd->addr & - ZYNQ_GEM_RXBUF_ADD_MASK), frame_len); + u32 addr = current_bd->addr & ZYNQ_GEM_RXBUF_ADD_MASK; + addr &= ~(ARCH_DMA_MINALIGN - 1); + u32 size = roundup(frame_len, ARCH_DMA_MINALIGN); + invalidate_dcache_range(addr, addr + size); + + NetReceive((u8 *)addr, frame_len); if (current_bd->status & ZYNQ_GEM_RXBUF_SOF_MASK) priv->rx_first_buf = priv->rxbd_current; @@ -471,6 +482,7 @@ int zynq_gem_initialize(bd_t *bis, int base_addr, int phy_addr, u32 emio) { struct eth_device *dev; struct zynq_gem_priv *priv; + void *bd_space; dev = calloc(1, sizeof(*dev)); if (dev == NULL) @@ -483,6 +495,18 @@ int zynq_gem_initialize(bd_t *bis, int base_addr, int phy_addr, u32 emio) } priv = dev->priv; + /* Align rxbuffers to ARCH_DMA_MINALIGN */ + priv->rxbuffers = memalign(ARCH_DMA_MINALIGN, RX_BUF * PKTSIZE_ALIGN); + memset(priv->rxbuffers, 0, RX_BUF * PKTSIZE_ALIGN); + + /* Align bd_space to 1MB */ + bd_space = memalign(1 << MMU_SECTION_SHIFT, BD_SPACE); + mmu_set_region_dcache_behaviour((u32)bd_space, BD_SPACE, DCACHE_OFF); + + /* Initialize the bd spaces for tx and rx bd's */ + priv->tx_bd = (struct emac_bd *)bd_space; + priv->rx_bd = (struct emac_bd *)((u32)bd_space + BD_SEPRN_SPACE); + priv->phyaddr = phy_addr; priv->emio = emio; -- cgit v1.1 From 22ece0e2e23c5cc5a23a5b8aff3dc75c9832e82f Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 20 Sep 2013 16:03:42 +0200 Subject: net: rtl8169: Improve cache maintenance Instead of directly calling the low-level invalidate_dcache_range() and flush_cache() functions, provide thin wrappers that take into account alignment requirements. While at it, fix a case where the cache was flushed but should have been invalidated, two cases where the buffer data was flushed instead of the descriptor and a missing cache invalidation before reading the packet data that the NIC just wrote to memory. Signed-off-by: Thierry Reding Patch: 276474 --- drivers/net/rtl8169.c | 61 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index 290c988..c47485a 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -395,6 +395,50 @@ match: return 0; } +/* + * Cache maintenance functions. These are simple wrappers around the more + * general purpose flush_cache() and invalidate_dcache_range() functions. + */ + +static void rtl_inval_rx_desc(struct RxDesc *desc) +{ + unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1); + unsigned long end = ALIGN(start + sizeof(*desc), ARCH_DMA_MINALIGN); + + invalidate_dcache_range(start, end); +} + +static void rtl_flush_rx_desc(struct RxDesc *desc) +{ + flush_cache((unsigned long)desc, sizeof(*desc)); +} + +static void rtl_inval_tx_desc(struct TxDesc *desc) +{ + unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1); + unsigned long end = ALIGN(start + sizeof(*desc), ARCH_DMA_MINALIGN); + + invalidate_dcache_range(start, end); +} + +static void rtl_flush_tx_desc(struct TxDesc *desc) +{ + flush_cache((unsigned long)desc, sizeof(*desc)); +} + +static void rtl_inval_buffer(void *buf, size_t size) +{ + unsigned long start = (unsigned long)buf & ~(ARCH_DMA_MINALIGN - 1); + unsigned long end = ALIGN(start + size, ARCH_DMA_MINALIGN); + + invalidate_dcache_range(start, end); +} + +static void rtl_flush_buffer(void *buf, size_t size) +{ + flush_cache((unsigned long)buf, size); +} + /************************************************************************** RECV - Receive a frame ***************************************************************************/ @@ -412,14 +456,16 @@ static int rtl_recv(struct eth_device *dev) ioaddr = dev->iobase; cur_rx = tpc->cur_rx; - flush_cache((unsigned long)&tpc->RxDescArray[cur_rx], - sizeof(struct RxDesc)); + + rtl_inval_rx_desc(&tpc->RxDescArray[cur_rx]); + if ((le32_to_cpu(tpc->RxDescArray[cur_rx].status) & OWNbit) == 0) { if (!(le32_to_cpu(tpc->RxDescArray[cur_rx].status) & RxRES)) { unsigned char rxdata[RX_BUF_LEN]; length = (int) (le32_to_cpu(tpc->RxDescArray[cur_rx]. status) & 0x00001FFF) - 4; + rtl_inval_buffer(tpc->RxBufferRing[cur_rx], length); memcpy(rxdata, tpc->RxBufferRing[cur_rx], length); NetReceive(rxdata, length); @@ -431,8 +477,7 @@ static int rtl_recv(struct eth_device *dev) cpu_to_le32(OWNbit + RX_BUF_SIZE); tpc->RxDescArray[cur_rx].buf_addr = cpu_to_le32(bus_to_phys(tpc->RxBufferRing[cur_rx])); - flush_cache((unsigned long)tpc->RxBufferRing[cur_rx], - RX_BUF_SIZE); + rtl_flush_rx_desc(&tpc->RxDescArray[cur_rx]); } else { puts("Error Rx"); } @@ -474,7 +519,7 @@ static int rtl_send(struct eth_device *dev, void *packet, int length) /* point to the current txb incase multiple tx_rings are used */ ptxb = tpc->Tx_skbuff[entry * MAX_ETH_FRAME_SIZE]; memcpy(ptxb, (char *)packet, (int)length); - flush_cache((unsigned long)ptxb, length); + rtl_flush_buffer(ptxb, length); while (len < ETH_ZLEN) ptxb[len++] = '\0'; @@ -490,13 +535,13 @@ static int rtl_send(struct eth_device *dev, void *packet, int length) cpu_to_le32((OWNbit | EORbit | FSbit | LSbit) | ((len > ETH_ZLEN) ? len : ETH_ZLEN)); } + rtl_flush_tx_desc(&tpc->TxDescArray[entry]); RTL_W8(TxPoll, 0x40); /* set polling bit */ tpc->cur_tx++; to = currticks() + TX_TIMEOUT; do { - flush_cache((unsigned long)&tpc->TxDescArray[entry], - sizeof(struct TxDesc)); + rtl_inval_tx_desc(&tpc->TxDescArray[entry]); } while ((le32_to_cpu(tpc->TxDescArray[entry].status) & OWNbit) && (currticks() < to)); /* wait */ @@ -639,7 +684,7 @@ static void rtl8169_init_ring(struct eth_device *dev) tpc->RxBufferRing[i] = &rxb[i * RX_BUF_SIZE]; tpc->RxDescArray[i].buf_addr = cpu_to_le32(bus_to_phys(tpc->RxBufferRing[i])); - flush_cache((unsigned long)tpc->RxBufferRing[i], RX_BUF_SIZE); + rtl_flush_rx_desc(&tpc->RxDescArray[i]); } #ifdef DEBUG_RTL8169 -- cgit v1.1 From 2287286be4e268d3d4ec3c0347bf31479dbd1f05 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 20 Sep 2013 16:03:43 +0200 Subject: net: rtl8169: Add support for RTL8168d/8111d This chip is compatible with the existing driver, except that it uses BAR2 instead of BAR1 for the I/O memory region. Using this patch I can use the PCIe ethernet interface on the CompuLab Trimslice to boot from the network. Signed-off-by: Thierry Reding Patch: 276477 --- drivers/net/rtl8169.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index c47485a..d040ab1 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -246,6 +246,7 @@ static struct { {"RTL-8169sc/8110sc", 0x18, 0xff7e1880,}, {"RTL-8168b/8111sb", 0x30, 0xff7e1880,}, {"RTL-8168b/8111sb", 0x38, 0xff7e1880,}, + {"RTL-8168d/8111d", 0x28, 0xff7e1880,}, {"RTL-8168evl/8111evl", 0x2e, 0xff7e1880,}, {"RTL-8101e", 0x34, 0xff7e1880,}, {"RTL-8100e", 0x32, 0xff7e1880,}, @@ -315,6 +316,7 @@ static const unsigned int rtl8169_rx_config = static struct pci_device_id supported[] = { {PCI_VENDOR_ID_REALTEK, 0x8167}, + {PCI_VENDOR_ID_REALTEK, 0x8168}, {PCI_VENDOR_ID_REALTEK, 0x8169}, {} }; @@ -915,11 +917,25 @@ int rtl8169_initialize(bd_t *bis) int idx=0; while(1){ + unsigned int region; + u16 device; + /* Find RTL8169 */ if ((devno = pci_find_devices(supported, idx++)) < 0) break; - pci_read_config_dword(devno, PCI_BASE_ADDRESS_1, &iobase); + pci_read_config_word(devno, PCI_DEVICE_ID, &device); + switch (device) { + case 0x8168: + region = 2; + break; + + default: + region = 1; + break; + } + + pci_read_config_dword(devno, PCI_BASE_ADDRESS_0 + (region * 4), &iobase); iobase &= ~0xf; debug ("rtl8169: REALTEK RTL8169 @0x%x\n", iobase); -- cgit v1.1 From 6516f81b64c71ab2be61f304d0e13dd84f730484 Mon Sep 17 00:00:00 2001 From: Igor Grinberg Date: Fri, 8 Nov 2013 01:03:51 +0200 Subject: gpio_led: check gpio_request() return value Add a check for the gpio_request() function return value and do not try to configure the GPIO if the gpio_request() call fails. Also, print an error message indicating the gpio_request() has failed. Signed-off-by: Igor Grinberg Tested-by: Ilya Ledvich --- drivers/misc/gpio_led.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/gpio_led.c b/drivers/misc/gpio_led.c index 3fedddc..de20419 100644 --- a/drivers/misc/gpio_led.c +++ b/drivers/misc/gpio_led.c @@ -11,7 +11,11 @@ void __led_init(led_id_t mask, int state) { - gpio_request(mask, "gpio_led"); + if (gpio_request(mask, "gpio_led") != 0) { + printf("%s: failed requesting GPIO%lu!\n", __func__, mask); + return; + } + gpio_direction_output(mask, state == STATUS_LED_ON); } -- cgit v1.1 From 9dfdcdfed4726f94fc38d94f29f8214f38058576 Mon Sep 17 00:00:00 2001 From: Igor Grinberg Date: Fri, 8 Nov 2013 01:03:52 +0200 Subject: gpio_led: add support for inverted polarity Some GPIO connected LEDs have inverted polarity. Introduce new config option: CONFIG_GPIO_LED_INVERTED_TABLE for the specifying the inverted GPIO LEDs list and add support for this in the gpio_led driver. Signed-off-by: Igor Grinberg Tested-by: Ilya Ledvich --- drivers/misc/gpio_led.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/gpio_led.c b/drivers/misc/gpio_led.c index de20419..3e95727 100644 --- a/drivers/misc/gpio_led.c +++ b/drivers/misc/gpio_led.c @@ -9,19 +9,42 @@ #include #include +#ifndef CONFIG_GPIO_LED_INVERTED_TABLE +#define CONFIG_GPIO_LED_INVERTED_TABLE {} +#endif + +static led_id_t gpio_led_inv[] = CONFIG_GPIO_LED_INVERTED_TABLE; + +static int gpio_led_gpio_value(led_id_t mask, int state) +{ + int i, gpio_value = (state == STATUS_LED_ON); + + for (i = 0; i < ARRAY_SIZE(gpio_led_inv); i++) { + if (gpio_led_inv[i] == mask) + gpio_value = !gpio_value; + } + + return gpio_value; +} + void __led_init(led_id_t mask, int state) { + int gpio_value; + if (gpio_request(mask, "gpio_led") != 0) { printf("%s: failed requesting GPIO%lu!\n", __func__, mask); return; } - gpio_direction_output(mask, state == STATUS_LED_ON); + gpio_value = gpio_led_gpio_value(mask, state); + gpio_direction_output(mask, gpio_value); } void __led_set(led_id_t mask, int state) { - gpio_set_value(mask, state == STATUS_LED_ON); + int gpio_value = gpio_led_gpio_value(mask, state); + + gpio_set_value(mask, gpio_value); } void __led_toggle(led_id_t mask) -- cgit v1.1 From 3c6dc17eaec13ddc622306a8ddd24b547be91aee Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 18 Nov 2013 11:18:57 +0900 Subject: drivers: delete unnecessary HOSTCFLAGS HOSTCFLAGS is meaningless because no host programs are compiled there. Signed-off-by: Masahiro Yamada --- drivers/bios_emulator/Makefile | 1 - drivers/net/npe/Makefile | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/bios_emulator/Makefile b/drivers/bios_emulator/Makefile index 6f74fdc..38fc48d 100644 --- a/drivers/bios_emulator/Makefile +++ b/drivers/bios_emulator/Makefile @@ -12,5 +12,4 @@ EXTRA_CFLAGS += -I. -I./include -I$(TOPDIR)/include \ -D__PPC__ -D__BIG_ENDIAN__ CFLAGS += $(EXTRA_CFLAGS) -HOSTCFLAGS += $(EXTRA_CFLAGS) CPPFLAGS += $(EXTRA_CFLAGS) diff --git a/drivers/net/npe/Makefile b/drivers/net/npe/Makefile index e36c0bb..0779255 100644 --- a/drivers/net/npe/Makefile +++ b/drivers/net/npe/Makefile @@ -8,7 +8,6 @@ LOCAL_CFLAGS += -I$(TOPDIR)/drivers/net/npe/include -DCONFIG_IXP425_COMPONENT_ETHDB -D__linux CFLAGS += $(LOCAL_CFLAGS) CPPFLAGS += $(LOCAL_CFLAGS) # needed for depend -HOSTCFLAGS += $(LOCAL_CFLAGS) obj-y := npe.o \ miiphy.o \ -- cgit v1.1 From f6bab6710c5502325a5c2423f09789ca201b33a7 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Nov 2013 18:14:23 +0900 Subject: bios_emulator: delete an unnecessary include path -I$(TOPDIR)/include is defined in the top config.mk. Signed-off-by: Masahiro Yamada --- drivers/bios_emulator/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bios_emulator/Makefile b/drivers/bios_emulator/Makefile index 38fc48d..52a2ceb 100644 --- a/drivers/bios_emulator/Makefile +++ b/drivers/bios_emulator/Makefile @@ -8,7 +8,7 @@ obj-y = atibios.o biosemu.o besys.o bios.o \ $(X86DIR)/sys.o \ $(X86DIR)/debug.o -EXTRA_CFLAGS += -I. -I./include -I$(TOPDIR)/include \ +EXTRA_CFLAGS += -I. -I./include \ -D__PPC__ -D__BIG_ENDIAN__ CFLAGS += $(EXTRA_CFLAGS) -- cgit v1.1 From 5614e71b4956c579cd4419b958b33fa6316eaa92 Mon Sep 17 00:00:00 2001 From: York Sun Date: Mon, 30 Sep 2013 09:22:09 -0700 Subject: Driver/DDR: Moving Freescale DDR driver to a common driver Freescale DDR driver has been used for mpc83xx, mpc85xx, mpc86xx SoCs. The similar DDR controllers will be used for ARM-based SoCs. Signed-off-by: York Sun --- drivers/ddr/fsl/Makefile | 34 + drivers/ddr/fsl/ctrl_regs.c | 1657 +++++++++++++++++++++++++++ drivers/ddr/fsl/ddr1_dimm_params.c | 343 ++++++ drivers/ddr/fsl/ddr2_dimm_params.c | 342 ++++++ drivers/ddr/fsl/ddr3_dimm_params.c | 341 ++++++ drivers/ddr/fsl/interactive.c | 1871 +++++++++++++++++++++++++++++++ drivers/ddr/fsl/lc_common_dimm_params.c | 526 +++++++++ drivers/ddr/fsl/main.c | 718 ++++++++++++ drivers/ddr/fsl/mpc85xx_ddr_gen1.c | 89 ++ drivers/ddr/fsl/mpc85xx_ddr_gen2.c | 95 ++ drivers/ddr/fsl/mpc85xx_ddr_gen3.c | 464 ++++++++ drivers/ddr/fsl/mpc86xx_ddr.c | 85 ++ drivers/ddr/fsl/options.c | 1147 +++++++++++++++++++ drivers/ddr/fsl/util.c | 265 +++++ 14 files changed, 7977 insertions(+) create mode 100644 drivers/ddr/fsl/Makefile create mode 100644 drivers/ddr/fsl/ctrl_regs.c create mode 100644 drivers/ddr/fsl/ddr1_dimm_params.c create mode 100644 drivers/ddr/fsl/ddr2_dimm_params.c create mode 100644 drivers/ddr/fsl/ddr3_dimm_params.c create mode 100644 drivers/ddr/fsl/interactive.c create mode 100644 drivers/ddr/fsl/lc_common_dimm_params.c create mode 100644 drivers/ddr/fsl/main.c create mode 100644 drivers/ddr/fsl/mpc85xx_ddr_gen1.c create mode 100644 drivers/ddr/fsl/mpc85xx_ddr_gen2.c create mode 100644 drivers/ddr/fsl/mpc85xx_ddr_gen3.c create mode 100644 drivers/ddr/fsl/mpc86xx_ddr.c create mode 100644 drivers/ddr/fsl/options.c create mode 100644 drivers/ddr/fsl/util.c (limited to 'drivers') diff --git a/drivers/ddr/fsl/Makefile b/drivers/ddr/fsl/Makefile new file mode 100644 index 0000000..a328b43 --- /dev/null +++ b/drivers/ddr/fsl/Makefile @@ -0,0 +1,34 @@ +# +# Copyright 2008-2011 Freescale Semiconductor, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# Version 2 as published by the Free Software Foundation. +# + +obj-$(CONFIG_SYS_FSL_DDR1) += main.o util.o ctrl_regs.o options.o \ + lc_common_dimm_params.o + +obj-$(CONFIG_SYS_FSL_DDR2) += main.o util.o ctrl_regs.o options.o \ + lc_common_dimm_params.o + +obj-$(CONFIG_SYS_FSL_DDR3) += main.o util.o ctrl_regs.o options.o \ + lc_common_dimm_params.o +ifdef CONFIG_DDR_SPD +SPD := y +endif +ifdef CONFIG_SPD_EEPROM +SPD := y +endif +ifdef SPD +obj-$(CONFIG_SYS_FSL_DDR1) += ddr1_dimm_params.o +obj-$(CONFIG_SYS_FSL_DDR2) += ddr2_dimm_params.o +obj-$(CONFIG_SYS_FSL_DDR3) += ddr3_dimm_params.o +endif + +obj-$(CONFIG_FSL_DDR_INTERACTIVE) += interactive.o +obj-$(CONFIG_SYS_FSL_DDRC_GEN1) += mpc85xx_ddr_gen1.o +obj-$(CONFIG_SYS_FSL_DDRC_GEN2) += mpc85xx_ddr_gen2.o +obj-$(CONFIG_SYS_FSL_DDRC_GEN3) += mpc85xx_ddr_gen3.o +obj-$(CONFIG_SYS_FSL_DDR_86XX) += mpc86xx_ddr.o +obj-$(CONFIG_FSL_DDR_INTERACTIVE) += interactive.o diff --git a/drivers/ddr/fsl/ctrl_regs.c b/drivers/ddr/fsl/ctrl_regs.c new file mode 100644 index 0000000..aed4569c --- /dev/null +++ b/drivers/ddr/fsl/ctrl_regs.c @@ -0,0 +1,1657 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * Generic driver for Freescale DDR/DDR2/DDR3 memory controller. + * Based on code from spd_sdram.c + * Author: James Yang [at freescale.com] + */ + +#include +#include + +#include +#include + +#define _DDR_ADDR CONFIG_SYS_FSL_DDR_ADDR + +static u32 fsl_ddr_get_version(void) +{ + ccsr_ddr_t *ddr; + u32 ver_major_minor_errata; + + ddr = (void *)_DDR_ADDR; + ver_major_minor_errata = (in_be32(&ddr->ip_rev1) & 0xFFFF) << 8; + ver_major_minor_errata |= (in_be32(&ddr->ip_rev2) & 0xFF00) >> 8; + + return ver_major_minor_errata; +} + +unsigned int picos_to_mclk(unsigned int picos); + +/* + * Determine Rtt value. + * + * This should likely be either board or controller specific. + * + * Rtt(nominal) - DDR2: + * 0 = Rtt disabled + * 1 = 75 ohm + * 2 = 150 ohm + * 3 = 50 ohm + * Rtt(nominal) - DDR3: + * 0 = Rtt disabled + * 1 = 60 ohm + * 2 = 120 ohm + * 3 = 40 ohm + * 4 = 20 ohm + * 5 = 30 ohm + * + * FIXME: Apparently 8641 needs a value of 2 + * FIXME: Old code seys if 667 MHz or higher, use 3 on 8572 + * + * FIXME: There was some effort down this line earlier: + * + * unsigned int i; + * for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL/2; i++) { + * if (popts->dimmslot[i].num_valid_cs + * && (popts->cs_local_opts[2*i].odt_rd_cfg + * || popts->cs_local_opts[2*i].odt_wr_cfg)) { + * rtt = 2; + * break; + * } + * } + */ +static inline int fsl_ddr_get_rtt(void) +{ + int rtt; + +#if defined(CONFIG_SYS_FSL_DDR1) + rtt = 0; +#elif defined(CONFIG_SYS_FSL_DDR2) + rtt = 3; +#else + rtt = 0; +#endif + + return rtt; +} + +/* + * compute the CAS write latency according to DDR3 spec + * CWL = 5 if tCK >= 2.5ns + * 6 if 2.5ns > tCK >= 1.875ns + * 7 if 1.875ns > tCK >= 1.5ns + * 8 if 1.5ns > tCK >= 1.25ns + * 9 if 1.25ns > tCK >= 1.07ns + * 10 if 1.07ns > tCK >= 0.935ns + * 11 if 0.935ns > tCK >= 0.833ns + * 12 if 0.833ns > tCK >= 0.75ns + */ +static inline unsigned int compute_cas_write_latency(void) +{ + unsigned int cwl; + const unsigned int mclk_ps = get_memory_clk_period_ps(); + + if (mclk_ps >= 2500) + cwl = 5; + else if (mclk_ps >= 1875) + cwl = 6; + else if (mclk_ps >= 1500) + cwl = 7; + else if (mclk_ps >= 1250) + cwl = 8; + else if (mclk_ps >= 1070) + cwl = 9; + else if (mclk_ps >= 935) + cwl = 10; + else if (mclk_ps >= 833) + cwl = 11; + else if (mclk_ps >= 750) + cwl = 12; + else { + cwl = 12; + printf("Warning: CWL is out of range\n"); + } + return cwl; +} + +/* Chip Select Configuration (CSn_CONFIG) */ +static void set_csn_config(int dimm_number, int i, fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts, + const dimm_params_t *dimm_params) +{ + unsigned int cs_n_en = 0; /* Chip Select enable */ + unsigned int intlv_en = 0; /* Memory controller interleave enable */ + unsigned int intlv_ctl = 0; /* Interleaving control */ + unsigned int ap_n_en = 0; /* Chip select n auto-precharge enable */ + unsigned int odt_rd_cfg = 0; /* ODT for reads configuration */ + unsigned int odt_wr_cfg = 0; /* ODT for writes configuration */ + unsigned int ba_bits_cs_n = 0; /* Num of bank bits for SDRAM on CSn */ + unsigned int row_bits_cs_n = 0; /* Num of row bits for SDRAM on CSn */ + unsigned int col_bits_cs_n = 0; /* Num of ocl bits for SDRAM on CSn */ + int go_config = 0; + + /* Compute CS_CONFIG only for existing ranks of each DIMM. */ + switch (i) { + case 0: + if (dimm_params[dimm_number].n_ranks > 0) { + go_config = 1; + /* These fields only available in CS0_CONFIG */ + if (!popts->memctl_interleaving) + break; + switch (popts->memctl_interleaving_mode) { + case FSL_DDR_CACHE_LINE_INTERLEAVING: + case FSL_DDR_PAGE_INTERLEAVING: + case FSL_DDR_BANK_INTERLEAVING: + case FSL_DDR_SUPERBANK_INTERLEAVING: + intlv_en = popts->memctl_interleaving; + intlv_ctl = popts->memctl_interleaving_mode; + break; + default: + break; + } + } + break; + case 1: + if ((dimm_number == 0 && dimm_params[0].n_ranks > 1) || \ + (dimm_number == 1 && dimm_params[1].n_ranks > 0)) + go_config = 1; + break; + case 2: + if ((dimm_number == 0 && dimm_params[0].n_ranks > 2) || \ + (dimm_number >= 1 && dimm_params[dimm_number].n_ranks > 0)) + go_config = 1; + break; + case 3: + if ((dimm_number == 0 && dimm_params[0].n_ranks > 3) || \ + (dimm_number == 1 && dimm_params[1].n_ranks > 1) || \ + (dimm_number == 3 && dimm_params[3].n_ranks > 0)) + go_config = 1; + break; + default: + break; + } + if (go_config) { + unsigned int n_banks_per_sdram_device; + cs_n_en = 1; + ap_n_en = popts->cs_local_opts[i].auto_precharge; + odt_rd_cfg = popts->cs_local_opts[i].odt_rd_cfg; + odt_wr_cfg = popts->cs_local_opts[i].odt_wr_cfg; + n_banks_per_sdram_device + = dimm_params[dimm_number].n_banks_per_sdram_device; + ba_bits_cs_n = __ilog2(n_banks_per_sdram_device) - 2; + row_bits_cs_n = dimm_params[dimm_number].n_row_addr - 12; + col_bits_cs_n = dimm_params[dimm_number].n_col_addr - 8; + } + ddr->cs[i].config = (0 + | ((cs_n_en & 0x1) << 31) + | ((intlv_en & 0x3) << 29) + | ((intlv_ctl & 0xf) << 24) + | ((ap_n_en & 0x1) << 23) + + /* XXX: some implementation only have 1 bit starting at left */ + | ((odt_rd_cfg & 0x7) << 20) + + /* XXX: Some implementation only have 1 bit starting at left */ + | ((odt_wr_cfg & 0x7) << 16) + + | ((ba_bits_cs_n & 0x3) << 14) + | ((row_bits_cs_n & 0x7) << 8) + | ((col_bits_cs_n & 0x7) << 0) + ); + debug("FSLDDR: cs[%d]_config = 0x%08x\n", i,ddr->cs[i].config); +} + +/* Chip Select Configuration 2 (CSn_CONFIG_2) */ +/* FIXME: 8572 */ +static void set_csn_config_2(int i, fsl_ddr_cfg_regs_t *ddr) +{ + unsigned int pasr_cfg = 0; /* Partial array self refresh config */ + + ddr->cs[i].config_2 = ((pasr_cfg & 7) << 24); + debug("FSLDDR: cs[%d]_config_2 = 0x%08x\n", i, ddr->cs[i].config_2); +} + +/* -3E = 667 CL5, -25 = CL6 800, -25E = CL5 800 */ + +#if !defined(CONFIG_SYS_FSL_DDR1) +static inline int avoid_odt_overlap(const dimm_params_t *dimm_params) +{ +#if CONFIG_DIMM_SLOTS_PER_CTLR == 1 + if (dimm_params[0].n_ranks == 4) + return 1; +#endif + +#if CONFIG_DIMM_SLOTS_PER_CTLR == 2 + if ((dimm_params[0].n_ranks == 2) && + (dimm_params[1].n_ranks == 2)) + return 1; + +#ifdef CONFIG_FSL_DDR_FIRST_SLOT_QUAD_CAPABLE + if (dimm_params[0].n_ranks == 4) + return 1; +#endif +#endif + return 0; +} + +/* + * DDR SDRAM Timing Configuration 0 (TIMING_CFG_0) + * + * Avoid writing for DDR I. The new PQ38 DDR controller + * dreams up non-zero default values to be backwards compatible. + */ +static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts, + const dimm_params_t *dimm_params) +{ + unsigned char trwt_mclk = 0; /* Read-to-write turnaround */ + unsigned char twrt_mclk = 0; /* Write-to-read turnaround */ + /* 7.5 ns on -3E; 0 means WL - CL + BL/2 + 1 */ + unsigned char trrt_mclk = 0; /* Read-to-read turnaround */ + unsigned char twwt_mclk = 0; /* Write-to-write turnaround */ + + /* Active powerdown exit timing (tXARD and tXARDS). */ + unsigned char act_pd_exit_mclk; + /* Precharge powerdown exit timing (tXP). */ + unsigned char pre_pd_exit_mclk; + /* ODT powerdown exit timing (tAXPD). */ + unsigned char taxpd_mclk; + /* Mode register set cycle time (tMRD). */ + unsigned char tmrd_mclk; + +#ifdef CONFIG_SYS_FSL_DDR3 + /* + * (tXARD and tXARDS). Empirical? + * The DDR3 spec has not tXARD, + * we use the tXP instead of it. + * tXP=max(3nCK, 7.5ns) for DDR3. + * spec has not the tAXPD, we use + * tAXPD=1, need design to confirm. + */ + int tXP = max((get_memory_clk_period_ps() * 3), 7500); /* unit=ps */ + unsigned int data_rate = get_ddr_freq(0); + tmrd_mclk = 4; + /* set the turnaround time */ + + /* + * for single quad-rank DIMM and two dual-rank DIMMs + * to avoid ODT overlap + */ + if (avoid_odt_overlap(dimm_params)) { + twwt_mclk = 2; + trrt_mclk = 1; + } + /* for faster clock, need more time for data setup */ + trwt_mclk = (data_rate/1000000 > 1800) ? 2 : 1; + + if ((data_rate/1000000 > 1150) || (popts->memctl_interleaving)) + twrt_mclk = 1; + + if (popts->dynamic_power == 0) { /* powerdown is not used */ + act_pd_exit_mclk = 1; + pre_pd_exit_mclk = 1; + taxpd_mclk = 1; + } else { + /* act_pd_exit_mclk = tXARD, see above */ + act_pd_exit_mclk = picos_to_mclk(tXP); + /* Mode register MR0[A12] is '1' - fast exit */ + pre_pd_exit_mclk = act_pd_exit_mclk; + taxpd_mclk = 1; + } +#else /* CONFIG_SYS_FSL_DDR2 */ + /* + * (tXARD and tXARDS). Empirical? + * tXARD = 2 for DDR2 + * tXP=2 + * tAXPD=8 + */ + act_pd_exit_mclk = 2; + pre_pd_exit_mclk = 2; + taxpd_mclk = 8; + tmrd_mclk = 2; +#endif + + if (popts->trwt_override) + trwt_mclk = popts->trwt; + + ddr->timing_cfg_0 = (0 + | ((trwt_mclk & 0x3) << 30) /* RWT */ + | ((twrt_mclk & 0x3) << 28) /* WRT */ + | ((trrt_mclk & 0x3) << 26) /* RRT */ + | ((twwt_mclk & 0x3) << 24) /* WWT */ + | ((act_pd_exit_mclk & 0x7) << 20) /* ACT_PD_EXIT */ + | ((pre_pd_exit_mclk & 0xF) << 16) /* PRE_PD_EXIT */ + | ((taxpd_mclk & 0xf) << 8) /* ODT_PD_EXIT */ + | ((tmrd_mclk & 0xf) << 0) /* MRS_CYC */ + ); + debug("FSLDDR: timing_cfg_0 = 0x%08x\n", ddr->timing_cfg_0); +} +#endif /* defined(CONFIG_SYS_FSL_DDR2) */ + +/* DDR SDRAM Timing Configuration 3 (TIMING_CFG_3) */ +static void set_timing_cfg_3(fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts, + const common_timing_params_t *common_dimm, + unsigned int cas_latency) +{ + /* Extended precharge to activate interval (tRP) */ + unsigned int ext_pretoact = 0; + /* Extended Activate to precharge interval (tRAS) */ + unsigned int ext_acttopre = 0; + /* Extended activate to read/write interval (tRCD) */ + unsigned int ext_acttorw = 0; + /* Extended refresh recovery time (tRFC) */ + unsigned int ext_refrec; + /* Extended MCAS latency from READ cmd */ + unsigned int ext_caslat = 0; + /* Extended last data to precharge interval (tWR) */ + unsigned int ext_wrrec = 0; + /* Control Adjust */ + unsigned int cntl_adj = 0; + + ext_pretoact = picos_to_mclk(common_dimm->trp_ps) >> 4; + ext_acttopre = picos_to_mclk(common_dimm->tras_ps) >> 4; + ext_acttorw = picos_to_mclk(common_dimm->trcd_ps) >> 4; + ext_caslat = (2 * cas_latency - 1) >> 4; + ext_refrec = (picos_to_mclk(common_dimm->trfc_ps) - 8) >> 4; + /* ext_wrrec only deals with 16 clock and above, or 14 with OTF */ + ext_wrrec = (picos_to_mclk(common_dimm->twr_ps) + + (popts->otf_burst_chop_en ? 2 : 0)) >> 4; + + ddr->timing_cfg_3 = (0 + | ((ext_pretoact & 0x1) << 28) + | ((ext_acttopre & 0x3) << 24) + | ((ext_acttorw & 0x1) << 22) + | ((ext_refrec & 0x1F) << 16) + | ((ext_caslat & 0x3) << 12) + | ((ext_wrrec & 0x1) << 8) + | ((cntl_adj & 0x7) << 0) + ); + debug("FSLDDR: timing_cfg_3 = 0x%08x\n", ddr->timing_cfg_3); +} + +/* DDR SDRAM Timing Configuration 1 (TIMING_CFG_1) */ +static void set_timing_cfg_1(fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts, + const common_timing_params_t *common_dimm, + unsigned int cas_latency) +{ + /* Precharge-to-activate interval (tRP) */ + unsigned char pretoact_mclk; + /* Activate to precharge interval (tRAS) */ + unsigned char acttopre_mclk; + /* Activate to read/write interval (tRCD) */ + unsigned char acttorw_mclk; + /* CASLAT */ + unsigned char caslat_ctrl; + /* Refresh recovery time (tRFC) ; trfc_low */ + unsigned char refrec_ctrl; + /* Last data to precharge minimum interval (tWR) */ + unsigned char wrrec_mclk; + /* Activate-to-activate interval (tRRD) */ + unsigned char acttoact_mclk; + /* Last write data pair to read command issue interval (tWTR) */ + unsigned char wrtord_mclk; + /* DDR_SDRAM_MODE doesn't support 9,11,13,15 */ + static const u8 wrrec_table[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 10, 10, 12, 12, 14, 14, 0, 0}; + + pretoact_mclk = picos_to_mclk(common_dimm->trp_ps); + acttopre_mclk = picos_to_mclk(common_dimm->tras_ps); + acttorw_mclk = picos_to_mclk(common_dimm->trcd_ps); + + /* + * Translate CAS Latency to a DDR controller field value: + * + * CAS Lat DDR I DDR II Ctrl + * Clocks SPD Bit SPD Bit Value + * ------- ------- ------- ----- + * 1.0 0 0001 + * 1.5 1 0010 + * 2.0 2 2 0011 + * 2.5 3 0100 + * 3.0 4 3 0101 + * 3.5 5 0110 + * 4.0 4 0111 + * 4.5 1000 + * 5.0 5 1001 + */ +#if defined(CONFIG_SYS_FSL_DDR1) + caslat_ctrl = (cas_latency + 1) & 0x07; +#elif defined(CONFIG_SYS_FSL_DDR2) + caslat_ctrl = 2 * cas_latency - 1; +#else + /* + * if the CAS latency more than 8 cycle, + * we need set extend bit for it at + * TIMING_CFG_3[EXT_CASLAT] + */ + caslat_ctrl = 2 * cas_latency - 1; +#endif + + refrec_ctrl = picos_to_mclk(common_dimm->trfc_ps) - 8; + wrrec_mclk = picos_to_mclk(common_dimm->twr_ps); + + if (wrrec_mclk > 16) + printf("Error: WRREC doesn't support more than 16 clocks\n"); + else + wrrec_mclk = wrrec_table[wrrec_mclk - 1]; + if (popts->otf_burst_chop_en) + wrrec_mclk += 2; + + acttoact_mclk = picos_to_mclk(common_dimm->trrd_ps); + /* + * JEDEC has min requirement for tRRD + */ +#if defined(CONFIG_SYS_FSL_DDR3) + if (acttoact_mclk < 4) + acttoact_mclk = 4; +#endif + wrtord_mclk = picos_to_mclk(common_dimm->twtr_ps); + /* + * JEDEC has some min requirements for tWTR + */ +#if defined(CONFIG_SYS_FSL_DDR2) + if (wrtord_mclk < 2) + wrtord_mclk = 2; +#elif defined(CONFIG_SYS_FSL_DDR3) + if (wrtord_mclk < 4) + wrtord_mclk = 4; +#endif + if (popts->otf_burst_chop_en) + wrtord_mclk += 2; + + ddr->timing_cfg_1 = (0 + | ((pretoact_mclk & 0x0F) << 28) + | ((acttopre_mclk & 0x0F) << 24) + | ((acttorw_mclk & 0xF) << 20) + | ((caslat_ctrl & 0xF) << 16) + | ((refrec_ctrl & 0xF) << 12) + | ((wrrec_mclk & 0x0F) << 8) + | ((acttoact_mclk & 0x0F) << 4) + | ((wrtord_mclk & 0x0F) << 0) + ); + debug("FSLDDR: timing_cfg_1 = 0x%08x\n", ddr->timing_cfg_1); +} + +/* DDR SDRAM Timing Configuration 2 (TIMING_CFG_2) */ +static void set_timing_cfg_2(fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts, + const common_timing_params_t *common_dimm, + unsigned int cas_latency, + unsigned int additive_latency) +{ + /* Additive latency */ + unsigned char add_lat_mclk; + /* CAS-to-preamble override */ + unsigned short cpo; + /* Write latency */ + unsigned char wr_lat; + /* Read to precharge (tRTP) */ + unsigned char rd_to_pre; + /* Write command to write data strobe timing adjustment */ + unsigned char wr_data_delay; + /* Minimum CKE pulse width (tCKE) */ + unsigned char cke_pls; + /* Window for four activates (tFAW) */ + unsigned short four_act; + + /* FIXME add check that this must be less than acttorw_mclk */ + add_lat_mclk = additive_latency; + cpo = popts->cpo_override; + +#if defined(CONFIG_SYS_FSL_DDR1) + /* + * This is a lie. It should really be 1, but if it is + * set to 1, bits overlap into the old controller's + * otherwise unused ACSM field. If we leave it 0, then + * the HW will magically treat it as 1 for DDR 1. Oh Yea. + */ + wr_lat = 0; +#elif defined(CONFIG_SYS_FSL_DDR2) + wr_lat = cas_latency - 1; +#else + wr_lat = compute_cas_write_latency(); +#endif + + rd_to_pre = picos_to_mclk(common_dimm->trtp_ps); + /* + * JEDEC has some min requirements for tRTP + */ +#if defined(CONFIG_SYS_FSL_DDR2) + if (rd_to_pre < 2) + rd_to_pre = 2; +#elif defined(CONFIG_SYS_FSL_DDR3) + if (rd_to_pre < 4) + rd_to_pre = 4; +#endif + if (additive_latency) + rd_to_pre += additive_latency; + if (popts->otf_burst_chop_en) + rd_to_pre += 2; /* according to UM */ + + wr_data_delay = popts->write_data_delay; + cke_pls = picos_to_mclk(popts->tcke_clock_pulse_width_ps); + four_act = picos_to_mclk(popts->tfaw_window_four_activates_ps); + + ddr->timing_cfg_2 = (0 + | ((add_lat_mclk & 0xf) << 28) + | ((cpo & 0x1f) << 23) + | ((wr_lat & 0xf) << 19) + | ((rd_to_pre & RD_TO_PRE_MASK) << RD_TO_PRE_SHIFT) + | ((wr_data_delay & WR_DATA_DELAY_MASK) << WR_DATA_DELAY_SHIFT) + | ((cke_pls & 0x7) << 6) + | ((four_act & 0x3f) << 0) + ); + debug("FSLDDR: timing_cfg_2 = 0x%08x\n", ddr->timing_cfg_2); +} + +/* DDR SDRAM Register Control Word */ +static void set_ddr_sdram_rcw(fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts, + const common_timing_params_t *common_dimm) +{ + if (common_dimm->all_dimms_registered && + !common_dimm->all_dimms_unbuffered) { + if (popts->rcw_override) { + ddr->ddr_sdram_rcw_1 = popts->rcw_1; + ddr->ddr_sdram_rcw_2 = popts->rcw_2; + } else { + ddr->ddr_sdram_rcw_1 = + common_dimm->rcw[0] << 28 | \ + common_dimm->rcw[1] << 24 | \ + common_dimm->rcw[2] << 20 | \ + common_dimm->rcw[3] << 16 | \ + common_dimm->rcw[4] << 12 | \ + common_dimm->rcw[5] << 8 | \ + common_dimm->rcw[6] << 4 | \ + common_dimm->rcw[7]; + ddr->ddr_sdram_rcw_2 = + common_dimm->rcw[8] << 28 | \ + common_dimm->rcw[9] << 24 | \ + common_dimm->rcw[10] << 20 | \ + common_dimm->rcw[11] << 16 | \ + common_dimm->rcw[12] << 12 | \ + common_dimm->rcw[13] << 8 | \ + common_dimm->rcw[14] << 4 | \ + common_dimm->rcw[15]; + } + debug("FSLDDR: ddr_sdram_rcw_1 = 0x%08x\n", ddr->ddr_sdram_rcw_1); + debug("FSLDDR: ddr_sdram_rcw_2 = 0x%08x\n", ddr->ddr_sdram_rcw_2); + } +} + +/* DDR SDRAM control configuration (DDR_SDRAM_CFG) */ +static void set_ddr_sdram_cfg(fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts, + const common_timing_params_t *common_dimm) +{ + unsigned int mem_en; /* DDR SDRAM interface logic enable */ + unsigned int sren; /* Self refresh enable (during sleep) */ + unsigned int ecc_en; /* ECC enable. */ + unsigned int rd_en; /* Registered DIMM enable */ + unsigned int sdram_type; /* Type of SDRAM */ + unsigned int dyn_pwr; /* Dynamic power management mode */ + unsigned int dbw; /* DRAM dta bus width */ + unsigned int eight_be = 0; /* 8-beat burst enable, DDR2 is zero */ + unsigned int ncap = 0; /* Non-concurrent auto-precharge */ + unsigned int threet_en; /* Enable 3T timing */ + unsigned int twot_en; /* Enable 2T timing */ + unsigned int ba_intlv_ctl; /* Bank (CS) interleaving control */ + unsigned int x32_en = 0; /* x32 enable */ + unsigned int pchb8 = 0; /* precharge bit 8 enable */ + unsigned int hse; /* Global half strength override */ + unsigned int mem_halt = 0; /* memory controller halt */ + unsigned int bi = 0; /* Bypass initialization */ + + mem_en = 1; + sren = popts->self_refresh_in_sleep; + if (common_dimm->all_dimms_ecc_capable) { + /* Allow setting of ECC only if all DIMMs are ECC. */ + ecc_en = popts->ecc_mode; + } else { + ecc_en = 0; + } + + if (common_dimm->all_dimms_registered && + !common_dimm->all_dimms_unbuffered) { + rd_en = 1; + twot_en = 0; + } else { + rd_en = 0; + twot_en = popts->twot_en; + } + + sdram_type = CONFIG_FSL_SDRAM_TYPE; + + dyn_pwr = popts->dynamic_power; + dbw = popts->data_bus_width; + /* 8-beat burst enable DDR-III case + * we must clear it when use the on-the-fly mode, + * must set it when use the 32-bits bus mode. + */ + if (sdram_type == SDRAM_TYPE_DDR3) { + if (popts->burst_length == DDR_BL8) + eight_be = 1; + if (popts->burst_length == DDR_OTF) + eight_be = 0; + if (dbw == 0x1) + eight_be = 1; + } + + threet_en = popts->threet_en; + ba_intlv_ctl = popts->ba_intlv_ctl; + hse = popts->half_strength_driver_enable; + + ddr->ddr_sdram_cfg = (0 + | ((mem_en & 0x1) << 31) + | ((sren & 0x1) << 30) + | ((ecc_en & 0x1) << 29) + | ((rd_en & 0x1) << 28) + | ((sdram_type & 0x7) << 24) + | ((dyn_pwr & 0x1) << 21) + | ((dbw & 0x3) << 19) + | ((eight_be & 0x1) << 18) + | ((ncap & 0x1) << 17) + | ((threet_en & 0x1) << 16) + | ((twot_en & 0x1) << 15) + | ((ba_intlv_ctl & 0x7F) << 8) + | ((x32_en & 0x1) << 5) + | ((pchb8 & 0x1) << 4) + | ((hse & 0x1) << 3) + | ((mem_halt & 0x1) << 1) + | ((bi & 0x1) << 0) + ); + debug("FSLDDR: ddr_sdram_cfg = 0x%08x\n", ddr->ddr_sdram_cfg); +} + +/* DDR SDRAM control configuration 2 (DDR_SDRAM_CFG_2) */ +static void set_ddr_sdram_cfg_2(fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts, + const unsigned int unq_mrs_en) +{ + unsigned int frc_sr = 0; /* Force self refresh */ + unsigned int sr_ie = 0; /* Self-refresh interrupt enable */ + unsigned int dll_rst_dis; /* DLL reset disable */ + unsigned int dqs_cfg; /* DQS configuration */ + unsigned int odt_cfg = 0; /* ODT configuration */ + unsigned int num_pr; /* Number of posted refreshes */ + unsigned int slow = 0; /* DDR will be run less than 1250 */ + unsigned int x4_en = 0; /* x4 DRAM enable */ + unsigned int obc_cfg; /* On-The-Fly Burst Chop Cfg */ + unsigned int ap_en; /* Address Parity Enable */ + unsigned int d_init; /* DRAM data initialization */ + unsigned int rcw_en = 0; /* Register Control Word Enable */ + unsigned int md_en = 0; /* Mirrored DIMM Enable */ + unsigned int qd_en = 0; /* quad-rank DIMM Enable */ + int i; + + dll_rst_dis = 1; /* Make this configurable */ + dqs_cfg = popts->dqs_config; + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (popts->cs_local_opts[i].odt_rd_cfg + || popts->cs_local_opts[i].odt_wr_cfg) { + odt_cfg = SDRAM_CFG2_ODT_ONLY_READ; + break; + } + } + + num_pr = 1; /* Make this configurable */ + + /* + * 8572 manual says + * {TIMING_CFG_1[PRETOACT] + * + [DDR_SDRAM_CFG_2[NUM_PR] + * * ({EXT_REFREC || REFREC} + 8 + 2)]} + * << DDR_SDRAM_INTERVAL[REFINT] + */ +#if defined(CONFIG_SYS_FSL_DDR3) + obc_cfg = popts->otf_burst_chop_en; +#else + obc_cfg = 0; +#endif + +#if (CONFIG_SYS_FSL_DDR_VER >= FSL_DDR_VER_4_7) + slow = get_ddr_freq(0) < 1249000000; +#endif + + if (popts->registered_dimm_en) { + rcw_en = 1; + ap_en = popts->ap_en; + } else { + ap_en = 0; + } + + x4_en = popts->x4_en ? 1 : 0; + +#if defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER) + /* Use the DDR controller to auto initialize memory. */ + d_init = popts->ecc_init_using_memctl; + ddr->ddr_data_init = CONFIG_MEM_INIT_VALUE; + debug("DDR: ddr_data_init = 0x%08x\n", ddr->ddr_data_init); +#else + /* Memory will be initialized via DMA, or not at all. */ + d_init = 0; +#endif + +#if defined(CONFIG_SYS_FSL_DDR3) + md_en = popts->mirrored_dimm; +#endif + qd_en = popts->quad_rank_present ? 1 : 0; + ddr->ddr_sdram_cfg_2 = (0 + | ((frc_sr & 0x1) << 31) + | ((sr_ie & 0x1) << 30) + | ((dll_rst_dis & 0x1) << 29) + | ((dqs_cfg & 0x3) << 26) + | ((odt_cfg & 0x3) << 21) + | ((num_pr & 0xf) << 12) + | ((slow & 1) << 11) + | (x4_en << 10) + | (qd_en << 9) + | (unq_mrs_en << 8) + | ((obc_cfg & 0x1) << 6) + | ((ap_en & 0x1) << 5) + | ((d_init & 0x1) << 4) + | ((rcw_en & 0x1) << 2) + | ((md_en & 0x1) << 0) + ); + debug("FSLDDR: ddr_sdram_cfg_2 = 0x%08x\n", ddr->ddr_sdram_cfg_2); +} + +/* DDR SDRAM Mode configuration 2 (DDR_SDRAM_MODE_2) */ +static void set_ddr_sdram_mode_2(fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts, + const common_timing_params_t *common_dimm, + const unsigned int unq_mrs_en) +{ + unsigned short esdmode2 = 0; /* Extended SDRAM mode 2 */ + unsigned short esdmode3 = 0; /* Extended SDRAM mode 3 */ + +#if defined(CONFIG_SYS_FSL_DDR3) + int i; + unsigned int rtt_wr = 0; /* Rtt_WR - dynamic ODT off */ + unsigned int srt = 0; /* self-refresh temerature, normal range */ + unsigned int asr = 0; /* auto self-refresh disable */ + unsigned int cwl = compute_cas_write_latency() - 5; + unsigned int pasr = 0; /* partial array self refresh disable */ + + if (popts->rtt_override) + rtt_wr = popts->rtt_wr_override_value; + else + rtt_wr = popts->cs_local_opts[0].odt_rtt_wr; + + if (common_dimm->extended_op_srt) + srt = common_dimm->extended_op_srt; + + esdmode2 = (0 + | ((rtt_wr & 0x3) << 9) + | ((srt & 0x1) << 7) + | ((asr & 0x1) << 6) + | ((cwl & 0x7) << 3) + | ((pasr & 0x7) << 0)); +#endif + ddr->ddr_sdram_mode_2 = (0 + | ((esdmode2 & 0xFFFF) << 16) + | ((esdmode3 & 0xFFFF) << 0) + ); + debug("FSLDDR: ddr_sdram_mode_2 = 0x%08x\n", ddr->ddr_sdram_mode_2); + +#ifdef CONFIG_SYS_FSL_DDR3 + if (unq_mrs_en) { /* unique mode registers are supported */ + for (i = 1; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (popts->rtt_override) + rtt_wr = popts->rtt_wr_override_value; + else + rtt_wr = popts->cs_local_opts[i].odt_rtt_wr; + + esdmode2 &= 0xF9FF; /* clear bit 10, 9 */ + esdmode2 |= (rtt_wr & 0x3) << 9; + switch (i) { + case 1: + ddr->ddr_sdram_mode_4 = (0 + | ((esdmode2 & 0xFFFF) << 16) + | ((esdmode3 & 0xFFFF) << 0) + ); + break; + case 2: + ddr->ddr_sdram_mode_6 = (0 + | ((esdmode2 & 0xFFFF) << 16) + | ((esdmode3 & 0xFFFF) << 0) + ); + break; + case 3: + ddr->ddr_sdram_mode_8 = (0 + | ((esdmode2 & 0xFFFF) << 16) + | ((esdmode3 & 0xFFFF) << 0) + ); + break; + } + } + debug("FSLDDR: ddr_sdram_mode_4 = 0x%08x\n", + ddr->ddr_sdram_mode_4); + debug("FSLDDR: ddr_sdram_mode_6 = 0x%08x\n", + ddr->ddr_sdram_mode_6); + debug("FSLDDR: ddr_sdram_mode_8 = 0x%08x\n", + ddr->ddr_sdram_mode_8); + } +#endif +} + +/* DDR SDRAM Interval Configuration (DDR_SDRAM_INTERVAL) */ +static void set_ddr_sdram_interval(fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts, + const common_timing_params_t *common_dimm) +{ + unsigned int refint; /* Refresh interval */ + unsigned int bstopre; /* Precharge interval */ + + refint = picos_to_mclk(common_dimm->refresh_rate_ps); + + bstopre = popts->bstopre; + + /* refint field used 0x3FFF in earlier controllers */ + ddr->ddr_sdram_interval = (0 + | ((refint & 0xFFFF) << 16) + | ((bstopre & 0x3FFF) << 0) + ); + debug("FSLDDR: ddr_sdram_interval = 0x%08x\n", ddr->ddr_sdram_interval); +} + +#if defined(CONFIG_SYS_FSL_DDR3) +/* DDR SDRAM Mode configuration set (DDR_SDRAM_MODE) */ +static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts, + const common_timing_params_t *common_dimm, + unsigned int cas_latency, + unsigned int additive_latency, + const unsigned int unq_mrs_en) +{ + unsigned short esdmode; /* Extended SDRAM mode */ + unsigned short sdmode; /* SDRAM mode */ + + /* Mode Register - MR1 */ + unsigned int qoff = 0; /* Output buffer enable 0=yes, 1=no */ + unsigned int tdqs_en = 0; /* TDQS Enable: 0=no, 1=yes */ + unsigned int rtt; + unsigned int wrlvl_en = 0; /* Write level enable: 0=no, 1=yes */ + unsigned int al = 0; /* Posted CAS# additive latency (AL) */ + unsigned int dic = 0; /* Output driver impedance, 40ohm */ + unsigned int dll_en = 0; /* DLL Enable 0=Enable (Normal), + 1=Disable (Test/Debug) */ + + /* Mode Register - MR0 */ + unsigned int dll_on; /* DLL control for precharge PD, 0=off, 1=on */ + unsigned int wr = 0; /* Write Recovery */ + unsigned int dll_rst; /* DLL Reset */ + unsigned int mode; /* Normal=0 or Test=1 */ + unsigned int caslat = 4;/* CAS# latency, default set as 6 cycles */ + /* BT: Burst Type (0=Nibble Sequential, 1=Interleaved) */ + unsigned int bt; + unsigned int bl; /* BL: Burst Length */ + + unsigned int wr_mclk; + /* + * DDR_SDRAM_MODE doesn't support 9,11,13,15 + * Please refer JEDEC Standard No. 79-3E for Mode Register MR0 + * for this table + */ + static const u8 wr_table[] = {1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 0, 0}; + + const unsigned int mclk_ps = get_memory_clk_period_ps(); + int i; + + if (popts->rtt_override) + rtt = popts->rtt_override_value; + else + rtt = popts->cs_local_opts[0].odt_rtt_norm; + + if (additive_latency == (cas_latency - 1)) + al = 1; + if (additive_latency == (cas_latency - 2)) + al = 2; + + if (popts->quad_rank_present) + dic = 1; /* output driver impedance 240/7 ohm */ + + /* + * The esdmode value will also be used for writing + * MR1 during write leveling for DDR3, although the + * bits specifically related to the write leveling + * scheme will be handled automatically by the DDR + * controller. so we set the wrlvl_en = 0 here. + */ + esdmode = (0 + | ((qoff & 0x1) << 12) + | ((tdqs_en & 0x1) << 11) + | ((rtt & 0x4) << 7) /* rtt field is split */ + | ((wrlvl_en & 0x1) << 7) + | ((rtt & 0x2) << 5) /* rtt field is split */ + | ((dic & 0x2) << 4) /* DIC field is split */ + | ((al & 0x3) << 3) + | ((rtt & 0x1) << 2) /* rtt field is split */ + | ((dic & 0x1) << 1) /* DIC field is split */ + | ((dll_en & 0x1) << 0) + ); + + /* + * DLL control for precharge PD + * 0=slow exit DLL off (tXPDLL) + * 1=fast exit DLL on (tXP) + */ + dll_on = 1; + + wr_mclk = (common_dimm->twr_ps + mclk_ps - 1) / mclk_ps; + if (wr_mclk <= 16) { + wr = wr_table[wr_mclk - 5]; + } else { + printf("Error: unsupported write recovery for mode register " + "wr_mclk = %d\n", wr_mclk); + } + + dll_rst = 0; /* dll no reset */ + mode = 0; /* normal mode */ + + /* look up table to get the cas latency bits */ + if (cas_latency >= 5 && cas_latency <= 16) { + unsigned char cas_latency_table[] = { + 0x2, /* 5 clocks */ + 0x4, /* 6 clocks */ + 0x6, /* 7 clocks */ + 0x8, /* 8 clocks */ + 0xa, /* 9 clocks */ + 0xc, /* 10 clocks */ + 0xe, /* 11 clocks */ + 0x1, /* 12 clocks */ + 0x3, /* 13 clocks */ + 0x5, /* 14 clocks */ + 0x7, /* 15 clocks */ + 0x9, /* 16 clocks */ + }; + caslat = cas_latency_table[cas_latency - 5]; + } else { + printf("Error: unsupported cas latency for mode register\n"); + } + + bt = 0; /* Nibble sequential */ + + switch (popts->burst_length) { + case DDR_BL8: + bl = 0; + break; + case DDR_OTF: + bl = 1; + break; + case DDR_BC4: + bl = 2; + break; + default: + printf("Error: invalid burst length of %u specified. " + " Defaulting to on-the-fly BC4 or BL8 beats.\n", + popts->burst_length); + bl = 1; + break; + } + + sdmode = (0 + | ((dll_on & 0x1) << 12) + | ((wr & 0x7) << 9) + | ((dll_rst & 0x1) << 8) + | ((mode & 0x1) << 7) + | (((caslat >> 1) & 0x7) << 4) + | ((bt & 0x1) << 3) + | ((caslat & 1) << 2) + | ((bl & 0x3) << 0) + ); + + ddr->ddr_sdram_mode = (0 + | ((esdmode & 0xFFFF) << 16) + | ((sdmode & 0xFFFF) << 0) + ); + + debug("FSLDDR: ddr_sdram_mode = 0x%08x\n", ddr->ddr_sdram_mode); + + if (unq_mrs_en) { /* unique mode registers are supported */ + for (i = 1; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (popts->rtt_override) + rtt = popts->rtt_override_value; + else + rtt = popts->cs_local_opts[i].odt_rtt_norm; + + esdmode &= 0xFDBB; /* clear bit 9,6,2 */ + esdmode |= (0 + | ((rtt & 0x4) << 7) /* rtt field is split */ + | ((rtt & 0x2) << 5) /* rtt field is split */ + | ((rtt & 0x1) << 2) /* rtt field is split */ + ); + switch (i) { + case 1: + ddr->ddr_sdram_mode_3 = (0 + | ((esdmode & 0xFFFF) << 16) + | ((sdmode & 0xFFFF) << 0) + ); + break; + case 2: + ddr->ddr_sdram_mode_5 = (0 + | ((esdmode & 0xFFFF) << 16) + | ((sdmode & 0xFFFF) << 0) + ); + break; + case 3: + ddr->ddr_sdram_mode_7 = (0 + | ((esdmode & 0xFFFF) << 16) + | ((sdmode & 0xFFFF) << 0) + ); + break; + } + } + debug("FSLDDR: ddr_sdram_mode_3 = 0x%08x\n", + ddr->ddr_sdram_mode_3); + debug("FSLDDR: ddr_sdram_mode_5 = 0x%08x\n", + ddr->ddr_sdram_mode_5); + debug("FSLDDR: ddr_sdram_mode_5 = 0x%08x\n", + ddr->ddr_sdram_mode_5); + } +} + +#else /* !CONFIG_SYS_FSL_DDR3 */ + +/* DDR SDRAM Mode configuration set (DDR_SDRAM_MODE) */ +static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts, + const common_timing_params_t *common_dimm, + unsigned int cas_latency, + unsigned int additive_latency, + const unsigned int unq_mrs_en) +{ + unsigned short esdmode; /* Extended SDRAM mode */ + unsigned short sdmode; /* SDRAM mode */ + + /* + * FIXME: This ought to be pre-calculated in a + * technology-specific routine, + * e.g. compute_DDR2_mode_register(), and then the + * sdmode and esdmode passed in as part of common_dimm. + */ + + /* Extended Mode Register */ + unsigned int mrs = 0; /* Mode Register Set */ + unsigned int outputs = 0; /* 0=Enabled, 1=Disabled */ + unsigned int rdqs_en = 0; /* RDQS Enable: 0=no, 1=yes */ + unsigned int dqs_en = 0; /* DQS# Enable: 0=enable, 1=disable */ + unsigned int ocd = 0; /* 0x0=OCD not supported, + 0x7=OCD default state */ + unsigned int rtt; + unsigned int al; /* Posted CAS# additive latency (AL) */ + unsigned int ods = 0; /* Output Drive Strength: + 0 = Full strength (18ohm) + 1 = Reduced strength (4ohm) */ + unsigned int dll_en = 0; /* DLL Enable 0=Enable (Normal), + 1=Disable (Test/Debug) */ + + /* Mode Register (MR) */ + unsigned int mr; /* Mode Register Definition */ + unsigned int pd; /* Power-Down Mode */ + unsigned int wr; /* Write Recovery */ + unsigned int dll_res; /* DLL Reset */ + unsigned int mode; /* Normal=0 or Test=1 */ + unsigned int caslat = 0;/* CAS# latency */ + /* BT: Burst Type (0=Sequential, 1=Interleaved) */ + unsigned int bt; + unsigned int bl; /* BL: Burst Length */ + +#if defined(CONFIG_SYS_FSL_DDR2) + const unsigned int mclk_ps = get_memory_clk_period_ps(); +#endif + dqs_en = !popts->dqs_config; + rtt = fsl_ddr_get_rtt(); + + al = additive_latency; + + esdmode = (0 + | ((mrs & 0x3) << 14) + | ((outputs & 0x1) << 12) + | ((rdqs_en & 0x1) << 11) + | ((dqs_en & 0x1) << 10) + | ((ocd & 0x7) << 7) + | ((rtt & 0x2) << 5) /* rtt field is split */ + | ((al & 0x7) << 3) + | ((rtt & 0x1) << 2) /* rtt field is split */ + | ((ods & 0x1) << 1) + | ((dll_en & 0x1) << 0) + ); + + mr = 0; /* FIXME: CHECKME */ + + /* + * 0 = Fast Exit (Normal) + * 1 = Slow Exit (Low Power) + */ + pd = 0; + +#if defined(CONFIG_SYS_FSL_DDR1) + wr = 0; /* Historical */ +#elif defined(CONFIG_SYS_FSL_DDR2) + wr = (common_dimm->twr_ps + mclk_ps - 1) / mclk_ps - 1; +#endif + dll_res = 0; + mode = 0; + +#if defined(CONFIG_SYS_FSL_DDR1) + if (1 <= cas_latency && cas_latency <= 4) { + unsigned char mode_caslat_table[4] = { + 0x5, /* 1.5 clocks */ + 0x2, /* 2.0 clocks */ + 0x6, /* 2.5 clocks */ + 0x3 /* 3.0 clocks */ + }; + caslat = mode_caslat_table[cas_latency - 1]; + } else { + printf("Warning: unknown cas_latency %d\n", cas_latency); + } +#elif defined(CONFIG_SYS_FSL_DDR2) + caslat = cas_latency; +#endif + bt = 0; + + switch (popts->burst_length) { + case DDR_BL4: + bl = 2; + break; + case DDR_BL8: + bl = 3; + break; + default: + printf("Error: invalid burst length of %u specified. " + " Defaulting to 4 beats.\n", + popts->burst_length); + bl = 2; + break; + } + + sdmode = (0 + | ((mr & 0x3) << 14) + | ((pd & 0x1) << 12) + | ((wr & 0x7) << 9) + | ((dll_res & 0x1) << 8) + | ((mode & 0x1) << 7) + | ((caslat & 0x7) << 4) + | ((bt & 0x1) << 3) + | ((bl & 0x7) << 0) + ); + + ddr->ddr_sdram_mode = (0 + | ((esdmode & 0xFFFF) << 16) + | ((sdmode & 0xFFFF) << 0) + ); + debug("FSLDDR: ddr_sdram_mode = 0x%08x\n", ddr->ddr_sdram_mode); +} +#endif + +/* DDR SDRAM Data Initialization (DDR_DATA_INIT) */ +static void set_ddr_data_init(fsl_ddr_cfg_regs_t *ddr) +{ + unsigned int init_value; /* Initialization value */ + +#ifdef CONFIG_MEM_INIT_VALUE + init_value = CONFIG_MEM_INIT_VALUE; +#else + init_value = 0xDEADBEEF; +#endif + ddr->ddr_data_init = init_value; +} + +/* + * DDR SDRAM Clock Control (DDR_SDRAM_CLK_CNTL) + * The old controller on the 8540/60 doesn't have this register. + * Hope it's OK to set it (to 0) anyway. + */ +static void set_ddr_sdram_clk_cntl(fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts) +{ + unsigned int clk_adjust; /* Clock adjust */ + + clk_adjust = popts->clk_adjust; + ddr->ddr_sdram_clk_cntl = (clk_adjust & 0xF) << 23; + debug("FSLDDR: clk_cntl = 0x%08x\n", ddr->ddr_sdram_clk_cntl); +} + +/* DDR Initialization Address (DDR_INIT_ADDR) */ +static void set_ddr_init_addr(fsl_ddr_cfg_regs_t *ddr) +{ + unsigned int init_addr = 0; /* Initialization address */ + + ddr->ddr_init_addr = init_addr; +} + +/* DDR Initialization Address (DDR_INIT_EXT_ADDR) */ +static void set_ddr_init_ext_addr(fsl_ddr_cfg_regs_t *ddr) +{ + unsigned int uia = 0; /* Use initialization address */ + unsigned int init_ext_addr = 0; /* Initialization address */ + + ddr->ddr_init_ext_addr = (0 + | ((uia & 0x1) << 31) + | (init_ext_addr & 0xF) + ); +} + +/* DDR SDRAM Timing Configuration 4 (TIMING_CFG_4) */ +static void set_timing_cfg_4(fsl_ddr_cfg_regs_t *ddr, + const memctl_options_t *popts) +{ + unsigned int rwt = 0; /* Read-to-write turnaround for same CS */ + unsigned int wrt = 0; /* Write-to-read turnaround for same CS */ + unsigned int rrt = 0; /* Read-to-read turnaround for same CS */ + unsigned int wwt = 0; /* Write-to-write turnaround for same CS */ + unsigned int dll_lock = 0; /* DDR SDRAM DLL Lock Time */ + +#if defined(CONFIG_SYS_FSL_DDR3) + if (popts->burst_length == DDR_BL8) { + /* We set BL/2 for fixed BL8 */ + rrt = 0; /* BL/2 clocks */ + wwt = 0; /* BL/2 clocks */ + } else { + /* We need to set BL/2 + 2 to BC4 and OTF */ + rrt = 2; /* BL/2 + 2 clocks */ + wwt = 2; /* BL/2 + 2 clocks */ + } + dll_lock = 1; /* tDLLK = 512 clocks from spec */ +#endif + ddr->timing_cfg_4 = (0 + | ((rwt & 0xf) << 28) + | ((wrt & 0xf) << 24) + | ((rrt & 0xf) << 20) + | ((wwt & 0xf) << 16) + | (dll_lock & 0x3) + ); + debug("FSLDDR: timing_cfg_4 = 0x%08x\n", ddr->timing_cfg_4); +} + +/* DDR SDRAM Timing Configuration 5 (TIMING_CFG_5) */ +static void set_timing_cfg_5(fsl_ddr_cfg_regs_t *ddr, unsigned int cas_latency) +{ + unsigned int rodt_on = 0; /* Read to ODT on */ + unsigned int rodt_off = 0; /* Read to ODT off */ + unsigned int wodt_on = 0; /* Write to ODT on */ + unsigned int wodt_off = 0; /* Write to ODT off */ + +#if defined(CONFIG_SYS_FSL_DDR3) + /* rodt_on = timing_cfg_1[caslat] - timing_cfg_2[wrlat] + 1 */ + rodt_on = cas_latency - ((ddr->timing_cfg_2 & 0x00780000) >> 19) + 1; + rodt_off = 4; /* 4 clocks */ + wodt_on = 1; /* 1 clocks */ + wodt_off = 4; /* 4 clocks */ +#endif + + ddr->timing_cfg_5 = (0 + | ((rodt_on & 0x1f) << 24) + | ((rodt_off & 0x7) << 20) + | ((wodt_on & 0x1f) << 12) + | ((wodt_off & 0x7) << 8) + ); + debug("FSLDDR: timing_cfg_5 = 0x%08x\n", ddr->timing_cfg_5); +} + +/* DDR ZQ Calibration Control (DDR_ZQ_CNTL) */ +static void set_ddr_zq_cntl(fsl_ddr_cfg_regs_t *ddr, unsigned int zq_en) +{ + unsigned int zqinit = 0;/* POR ZQ Calibration Time (tZQinit) */ + /* Normal Operation Full Calibration Time (tZQoper) */ + unsigned int zqoper = 0; + /* Normal Operation Short Calibration Time (tZQCS) */ + unsigned int zqcs = 0; + + if (zq_en) { + zqinit = 9; /* 512 clocks */ + zqoper = 8; /* 256 clocks */ + zqcs = 6; /* 64 clocks */ + } + + ddr->ddr_zq_cntl = (0 + | ((zq_en & 0x1) << 31) + | ((zqinit & 0xF) << 24) + | ((zqoper & 0xF) << 16) + | ((zqcs & 0xF) << 8) + ); + debug("FSLDDR: zq_cntl = 0x%08x\n", ddr->ddr_zq_cntl); +} + +/* DDR Write Leveling Control (DDR_WRLVL_CNTL) */ +static void set_ddr_wrlvl_cntl(fsl_ddr_cfg_regs_t *ddr, unsigned int wrlvl_en, + const memctl_options_t *popts) +{ + /* + * First DQS pulse rising edge after margining mode + * is programmed (tWL_MRD) + */ + unsigned int wrlvl_mrd = 0; + /* ODT delay after margining mode is programmed (tWL_ODTEN) */ + unsigned int wrlvl_odten = 0; + /* DQS/DQS_ delay after margining mode is programmed (tWL_DQSEN) */ + unsigned int wrlvl_dqsen = 0; + /* WRLVL_SMPL: Write leveling sample time */ + unsigned int wrlvl_smpl = 0; + /* WRLVL_WLR: Write leveling repeition time */ + unsigned int wrlvl_wlr = 0; + /* WRLVL_START: Write leveling start time */ + unsigned int wrlvl_start = 0; + + /* suggest enable write leveling for DDR3 due to fly-by topology */ + if (wrlvl_en) { + /* tWL_MRD min = 40 nCK, we set it 64 */ + wrlvl_mrd = 0x6; + /* tWL_ODTEN 128 */ + wrlvl_odten = 0x7; + /* tWL_DQSEN min = 25 nCK, we set it 32 */ + wrlvl_dqsen = 0x5; + /* + * Write leveling sample time at least need 6 clocks + * higher than tWLO to allow enough time for progagation + * delay and sampling the prime data bits. + */ + wrlvl_smpl = 0xf; + /* + * Write leveling repetition time + * at least tWLO + 6 clocks clocks + * we set it 64 + */ + wrlvl_wlr = 0x6; + /* + * Write leveling start time + * The value use for the DQS_ADJUST for the first sample + * when write leveling is enabled. It probably needs to be + * overriden per platform. + */ + wrlvl_start = 0x8; + /* + * Override the write leveling sample and start time + * according to specific board + */ + if (popts->wrlvl_override) { + wrlvl_smpl = popts->wrlvl_sample; + wrlvl_start = popts->wrlvl_start; + } + } + + ddr->ddr_wrlvl_cntl = (0 + | ((wrlvl_en & 0x1) << 31) + | ((wrlvl_mrd & 0x7) << 24) + | ((wrlvl_odten & 0x7) << 20) + | ((wrlvl_dqsen & 0x7) << 16) + | ((wrlvl_smpl & 0xf) << 12) + | ((wrlvl_wlr & 0x7) << 8) + | ((wrlvl_start & 0x1F) << 0) + ); + debug("FSLDDR: wrlvl_cntl = 0x%08x\n", ddr->ddr_wrlvl_cntl); + ddr->ddr_wrlvl_cntl_2 = popts->wrlvl_ctl_2; + debug("FSLDDR: wrlvl_cntl_2 = 0x%08x\n", ddr->ddr_wrlvl_cntl_2); + ddr->ddr_wrlvl_cntl_3 = popts->wrlvl_ctl_3; + debug("FSLDDR: wrlvl_cntl_3 = 0x%08x\n", ddr->ddr_wrlvl_cntl_3); + +} + +/* DDR Self Refresh Counter (DDR_SR_CNTR) */ +static void set_ddr_sr_cntr(fsl_ddr_cfg_regs_t *ddr, unsigned int sr_it) +{ + /* Self Refresh Idle Threshold */ + ddr->ddr_sr_cntr = (sr_it & 0xF) << 16; +} + +static void set_ddr_eor(fsl_ddr_cfg_regs_t *ddr, const memctl_options_t *popts) +{ + if (popts->addr_hash) { + ddr->ddr_eor = 0x40000000; /* address hash enable */ + puts("Address hashing enabled.\n"); + } +} + +static void set_ddr_cdr1(fsl_ddr_cfg_regs_t *ddr, const memctl_options_t *popts) +{ + ddr->ddr_cdr1 = popts->ddr_cdr1; + debug("FSLDDR: ddr_cdr1 = 0x%08x\n", ddr->ddr_cdr1); +} + +static void set_ddr_cdr2(fsl_ddr_cfg_regs_t *ddr, const memctl_options_t *popts) +{ + ddr->ddr_cdr2 = popts->ddr_cdr2; + debug("FSLDDR: ddr_cdr2 = 0x%08x\n", ddr->ddr_cdr2); +} + +unsigned int +check_fsl_memctl_config_regs(const fsl_ddr_cfg_regs_t *ddr) +{ + unsigned int res = 0; + + /* + * Check that DDR_SDRAM_CFG[RD_EN] and DDR_SDRAM_CFG[2T_EN] are + * not set at the same time. + */ + if (ddr->ddr_sdram_cfg & 0x10000000 + && ddr->ddr_sdram_cfg & 0x00008000) { + printf("Error: DDR_SDRAM_CFG[RD_EN] and DDR_SDRAM_CFG[2T_EN] " + " should not be set at the same time.\n"); + res++; + } + + return res; +} + +unsigned int +compute_fsl_memctl_config_regs(const memctl_options_t *popts, + fsl_ddr_cfg_regs_t *ddr, + const common_timing_params_t *common_dimm, + const dimm_params_t *dimm_params, + unsigned int dbw_cap_adj, + unsigned int size_only) +{ + unsigned int i; + unsigned int cas_latency; + unsigned int additive_latency; + unsigned int sr_it; + unsigned int zq_en; + unsigned int wrlvl_en; + unsigned int ip_rev = 0; + unsigned int unq_mrs_en = 0; + int cs_en = 1; + + memset(ddr, 0, sizeof(fsl_ddr_cfg_regs_t)); + + if (common_dimm == NULL) { + printf("Error: subset DIMM params struct null pointer\n"); + return 1; + } + + /* + * Process overrides first. + * + * FIXME: somehow add dereated caslat to this + */ + cas_latency = (popts->cas_latency_override) + ? popts->cas_latency_override_value + : common_dimm->lowest_common_SPD_caslat; + + additive_latency = (popts->additive_latency_override) + ? popts->additive_latency_override_value + : common_dimm->additive_latency; + + sr_it = (popts->auto_self_refresh_en) + ? popts->sr_it + : 0; + /* ZQ calibration */ + zq_en = (popts->zq_en) ? 1 : 0; + /* write leveling */ + wrlvl_en = (popts->wrlvl_en) ? 1 : 0; + + /* Chip Select Memory Bounds (CSn_BNDS) */ + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + unsigned long long ea, sa; + unsigned int cs_per_dimm + = CONFIG_CHIP_SELECTS_PER_CTRL / CONFIG_DIMM_SLOTS_PER_CTLR; + unsigned int dimm_number + = i / cs_per_dimm; + unsigned long long rank_density + = dimm_params[dimm_number].rank_density >> dbw_cap_adj; + + if (dimm_params[dimm_number].n_ranks == 0) { + debug("Skipping setup of CS%u " + "because n_ranks on DIMM %u is 0\n", i, dimm_number); + continue; + } + if (popts->memctl_interleaving) { + switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) { + case FSL_DDR_CS0_CS1_CS2_CS3: + break; + case FSL_DDR_CS0_CS1: + case FSL_DDR_CS0_CS1_AND_CS2_CS3: + if (i > 1) + cs_en = 0; + break; + case FSL_DDR_CS2_CS3: + default: + if (i > 0) + cs_en = 0; + break; + } + sa = common_dimm->base_address; + ea = sa + common_dimm->total_mem - 1; + } else if (!popts->memctl_interleaving) { + /* + * If memory interleaving between controllers is NOT + * enabled, the starting address for each memory + * controller is distinct. However, because rank + * interleaving is enabled, the starting and ending + * addresses of the total memory on that memory + * controller needs to be programmed into its + * respective CS0_BNDS. + */ + switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) { + case FSL_DDR_CS0_CS1_CS2_CS3: + sa = common_dimm->base_address; + ea = sa + common_dimm->total_mem - 1; + break; + case FSL_DDR_CS0_CS1_AND_CS2_CS3: + if ((i >= 2) && (dimm_number == 0)) { + sa = dimm_params[dimm_number].base_address + + 2 * rank_density; + ea = sa + 2 * rank_density - 1; + } else { + sa = dimm_params[dimm_number].base_address; + ea = sa + 2 * rank_density - 1; + } + break; + case FSL_DDR_CS0_CS1: + if (dimm_params[dimm_number].n_ranks > (i % cs_per_dimm)) { + sa = dimm_params[dimm_number].base_address; + ea = sa + rank_density - 1; + if (i != 1) + sa += (i % cs_per_dimm) * rank_density; + ea += (i % cs_per_dimm) * rank_density; + } else { + sa = 0; + ea = 0; + } + if (i == 0) + ea += rank_density; + break; + case FSL_DDR_CS2_CS3: + if (dimm_params[dimm_number].n_ranks > (i % cs_per_dimm)) { + sa = dimm_params[dimm_number].base_address; + ea = sa + rank_density - 1; + if (i != 3) + sa += (i % cs_per_dimm) * rank_density; + ea += (i % cs_per_dimm) * rank_density; + } else { + sa = 0; + ea = 0; + } + if (i == 2) + ea += (rank_density >> dbw_cap_adj); + break; + default: /* No bank(chip-select) interleaving */ + sa = dimm_params[dimm_number].base_address; + ea = sa + rank_density - 1; + if (dimm_params[dimm_number].n_ranks > (i % cs_per_dimm)) { + sa += (i % cs_per_dimm) * rank_density; + ea += (i % cs_per_dimm) * rank_density; + } else { + sa = 0; + ea = 0; + } + break; + } + } + + sa >>= 24; + ea >>= 24; + + if (cs_en) { + ddr->cs[i].bnds = (0 + | ((sa & 0xFFF) << 16)/* starting address MSB */ + | ((ea & 0xFFF) << 0) /* ending address MSB */ + ); + } else { + /* setting bnds to 0xffffffff for inactive CS */ + ddr->cs[i].bnds = 0xffffffff; + } + + debug("FSLDDR: cs[%d]_bnds = 0x%08x\n", i, ddr->cs[i].bnds); + set_csn_config(dimm_number, i, ddr, popts, dimm_params); + set_csn_config_2(i, ddr); + } + + /* + * In the case we only need to compute the ddr sdram size, we only need + * to set csn registers, so return from here. + */ + if (size_only) + return 0; + + set_ddr_eor(ddr, popts); + +#if !defined(CONFIG_SYS_FSL_DDR1) + set_timing_cfg_0(ddr, popts, dimm_params); +#endif + + set_timing_cfg_3(ddr, popts, common_dimm, cas_latency); + set_timing_cfg_1(ddr, popts, common_dimm, cas_latency); + set_timing_cfg_2(ddr, popts, common_dimm, + cas_latency, additive_latency); + + set_ddr_cdr1(ddr, popts); + set_ddr_cdr2(ddr, popts); + set_ddr_sdram_cfg(ddr, popts, common_dimm); + ip_rev = fsl_ddr_get_version(); + if (ip_rev > 0x40400) + unq_mrs_en = 1; + + set_ddr_sdram_cfg_2(ddr, popts, unq_mrs_en); + set_ddr_sdram_mode(ddr, popts, common_dimm, + cas_latency, additive_latency, unq_mrs_en); + set_ddr_sdram_mode_2(ddr, popts, common_dimm, unq_mrs_en); + set_ddr_sdram_interval(ddr, popts, common_dimm); + set_ddr_data_init(ddr); + set_ddr_sdram_clk_cntl(ddr, popts); + set_ddr_init_addr(ddr); + set_ddr_init_ext_addr(ddr); + set_timing_cfg_4(ddr, popts); + set_timing_cfg_5(ddr, cas_latency); + + set_ddr_zq_cntl(ddr, zq_en); + set_ddr_wrlvl_cntl(ddr, wrlvl_en, popts); + + set_ddr_sr_cntr(ddr, sr_it); + + set_ddr_sdram_rcw(ddr, popts, common_dimm); + +#ifdef CONFIG_SYS_FSL_DDR_EMU + /* disble DDR training for emulator */ + ddr->debug[2] = 0x00000400; + ddr->debug[4] = 0xff800000; +#endif + return check_fsl_memctl_config_regs(ddr); +} diff --git a/drivers/ddr/fsl/ddr1_dimm_params.c b/drivers/ddr/fsl/ddr1_dimm_params.c new file mode 100644 index 0000000..7df27b9 --- /dev/null +++ b/drivers/ddr/fsl/ddr1_dimm_params.c @@ -0,0 +1,343 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include +#include + +#include + +/* + * Calculate the Density of each Physical Rank. + * Returned size is in bytes. + * + * Study these table from Byte 31 of JEDEC SPD Spec. + * + * DDR I DDR II + * Bit Size Size + * --- ----- ------ + * 7 high 512MB 512MB + * 6 256MB 256MB + * 5 128MB 128MB + * 4 64MB 16GB + * 3 32MB 8GB + * 2 16MB 4GB + * 1 2GB 2GB + * 0 low 1GB 1GB + * + * Reorder Table to be linear by stripping the bottom + * 2 or 5 bits off and shifting them up to the top. + */ + +static unsigned long long +compute_ranksize(unsigned int mem_type, unsigned char row_dens) +{ + unsigned long long bsize; + + /* Bottom 2 bits up to the top. */ + bsize = ((row_dens >> 2) | ((row_dens & 3) << 6)); + bsize <<= 24ULL; + debug("DDR: DDR I rank density = 0x%16llx\n", bsize); + + return bsize; +} + +/* + * Convert a two-nibble BCD value into a cycle time. + * While the spec calls for nano-seconds, picos are returned. + * + * This implements the tables for bytes 9, 23 and 25 for both + * DDR I and II. No allowance for distinguishing the invalid + * fields absent for DDR I yet present in DDR II is made. + * (That is, cycle times of .25, .33, .66 and .75 ns are + * allowed for both DDR II and I.) + */ +static unsigned int +convert_bcd_tenths_to_cycle_time_ps(unsigned int spd_val) +{ + /* Table look up the lower nibble, allow DDR I & II. */ + unsigned int tenths_ps[16] = { + 0, + 100, + 200, + 300, + 400, + 500, + 600, + 700, + 800, + 900, + 250, /* This and the next 3 entries valid ... */ + 330, /* ... only for tCK calculations. */ + 660, + 750, + 0, /* undefined */ + 0 /* undefined */ + }; + + unsigned int whole_ns = (spd_val & 0xF0) >> 4; + unsigned int tenth_ns = spd_val & 0x0F; + unsigned int ps = whole_ns * 1000 + tenths_ps[tenth_ns]; + + return ps; +} + +static unsigned int +convert_bcd_hundredths_to_cycle_time_ps(unsigned int spd_val) +{ + unsigned int tenth_ns = (spd_val & 0xF0) >> 4; + unsigned int hundredth_ns = spd_val & 0x0F; + unsigned int ps = tenth_ns * 100 + hundredth_ns * 10; + + return ps; +} + +static unsigned int byte40_table_ps[8] = { + 0, + 250, + 330, + 500, + 660, + 750, + 0, /* supposed to be RFC, but not sure what that means */ + 0 /* Undefined */ +}; + +static unsigned int +compute_trfc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trfc) +{ + unsigned int trfc_ps; + + trfc_ps = (((trctrfc_ext & 0x1) * 256) + trfc) * 1000 + + byte40_table_ps[(trctrfc_ext >> 1) & 0x7]; + + return trfc_ps; +} + +static unsigned int +compute_trc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trc) +{ + unsigned int trc_ps; + + trc_ps = trc * 1000 + byte40_table_ps[(trctrfc_ext >> 4) & 0x7]; + + return trc_ps; +} + +/* + * tCKmax from DDR I SPD Byte 43 + * + * Bits 7:2 == whole ns + * Bits 1:0 == quarter ns + * 00 == 0.00 ns + * 01 == 0.25 ns + * 10 == 0.50 ns + * 11 == 0.75 ns + * + * Returns picoseconds. + */ +static unsigned int +compute_tckmax_from_spd_ps(unsigned int byte43) +{ + return (byte43 >> 2) * 1000 + (byte43 & 0x3) * 250; +} + +/* + * Determine Refresh Rate. Ignore self refresh bit on DDR I. + * Table from SPD Spec, Byte 12, converted to picoseconds and + * filled in with "default" normal values. + */ +static unsigned int +determine_refresh_rate_ps(const unsigned int spd_refresh) +{ + unsigned int refresh_time_ps[8] = { + 15625000, /* 0 Normal 1.00x */ + 3900000, /* 1 Reduced .25x */ + 7800000, /* 2 Extended .50x */ + 31300000, /* 3 Extended 2.00x */ + 62500000, /* 4 Extended 4.00x */ + 125000000, /* 5 Extended 8.00x */ + 15625000, /* 6 Normal 1.00x filler */ + 15625000, /* 7 Normal 1.00x filler */ + }; + + return refresh_time_ps[spd_refresh & 0x7]; +} + +/* + * The purpose of this function is to compute a suitable + * CAS latency given the DRAM clock period. The SPD only + * defines at most 3 CAS latencies. Typically the slower in + * frequency the DIMM runs at, the shorter its CAS latency can be. + * If the DIMM is operating at a sufficiently low frequency, + * it may be able to run at a CAS latency shorter than the + * shortest SPD-defined CAS latency. + * + * If a CAS latency is not found, 0 is returned. + * + * Do this by finding in the standard speed bin table the longest + * tCKmin that doesn't exceed the value of mclk_ps (tCK). + * + * An assumption made is that the SDRAM device allows the + * CL to be programmed for a value that is lower than those + * advertised by the SPD. This is not always the case, + * as those modes not defined in the SPD are optional. + * + * CAS latency de-rating based upon values JEDEC Standard No. 79-E + * Table 11. + * + * ordinal 2, ddr1_speed_bins[1] contains tCK for CL=2 + */ + /* CL2.0 CL2.5 CL3.0 */ +unsigned short ddr1_speed_bins[] = {0, 7500, 6000, 5000 }; + +unsigned int +compute_derated_DDR1_CAS_latency(unsigned int mclk_ps) +{ + const unsigned int num_speed_bins = ARRAY_SIZE(ddr1_speed_bins); + unsigned int lowest_tCKmin_found = 0; + unsigned int lowest_tCKmin_CL = 0; + unsigned int i; + + debug("mclk_ps = %u\n", mclk_ps); + + for (i = 0; i < num_speed_bins; i++) { + unsigned int x = ddr1_speed_bins[i]; + debug("i=%u, x = %u, lowest_tCKmin_found = %u\n", + i, x, lowest_tCKmin_found); + if (x && lowest_tCKmin_found <= x && x <= mclk_ps) { + lowest_tCKmin_found = x; + lowest_tCKmin_CL = i + 1; + } + } + + debug("lowest_tCKmin_CL = %u\n", lowest_tCKmin_CL); + + return lowest_tCKmin_CL; +} + +/* + * ddr_compute_dimm_parameters for DDR1 SPD + * + * Compute DIMM parameters based upon the SPD information in spd. + * Writes the results to the dimm_params_t structure pointed by pdimm. + * + * FIXME: use #define for the retvals + */ +unsigned int +ddr_compute_dimm_parameters(const ddr1_spd_eeprom_t *spd, + dimm_params_t *pdimm, + unsigned int dimm_number) +{ + unsigned int retval; + + if (spd->mem_type) { + if (spd->mem_type != SPD_MEMTYPE_DDR) { + printf("DIMM %u: is not a DDR1 SPD.\n", dimm_number); + return 1; + } + } else { + memset(pdimm, 0, sizeof(dimm_params_t)); + return 1; + } + + retval = ddr1_spd_check(spd); + if (retval) { + printf("DIMM %u: failed checksum\n", dimm_number); + return 2; + } + + /* + * The part name in ASCII in the SPD EEPROM is not null terminated. + * Guarantee null termination here by presetting all bytes to 0 + * and copying the part name in ASCII from the SPD onto it + */ + memset(pdimm->mpart, 0, sizeof(pdimm->mpart)); + memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1); + + /* DIMM organization parameters */ + pdimm->n_ranks = spd->nrows; + pdimm->rank_density = compute_ranksize(spd->mem_type, spd->bank_dens); + pdimm->capacity = pdimm->n_ranks * pdimm->rank_density; + pdimm->data_width = spd->dataw_lsb; + pdimm->primary_sdram_width = spd->primw; + pdimm->ec_sdram_width = spd->ecw; + + /* + * FIXME: Need to determine registered_dimm status. + * 1 == register buffered + * 0 == unbuffered + */ + pdimm->registered_dimm = 0; /* unbuffered */ + + /* SDRAM device parameters */ + pdimm->n_row_addr = spd->nrow_addr; + pdimm->n_col_addr = spd->ncol_addr; + pdimm->n_banks_per_sdram_device = spd->nbanks; + pdimm->edc_config = spd->config; + pdimm->burst_lengths_bitmask = spd->burstl; + pdimm->row_density = spd->bank_dens; + + /* + * Calculate the Maximum Data Rate based on the Minimum Cycle time. + * The SPD clk_cycle field (tCKmin) is measured in tenths of + * nanoseconds and represented as BCD. + */ + pdimm->tckmin_x_ps + = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle); + pdimm->tckmin_x_minus_1_ps + = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle2); + pdimm->tckmin_x_minus_2_ps + = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle3); + + pdimm->tckmax_ps = compute_tckmax_from_spd_ps(spd->tckmax); + + /* + * Compute CAS latencies defined by SPD + * The SPD caslat_x should have at least 1 and at most 3 bits set. + * + * If cas_lat after masking is 0, the __ilog2 function returns + * 255 into the variable. This behavior is abused once. + */ + pdimm->caslat_x = __ilog2(spd->cas_lat); + pdimm->caslat_x_minus_1 = __ilog2(spd->cas_lat + & ~(1 << pdimm->caslat_x)); + pdimm->caslat_x_minus_2 = __ilog2(spd->cas_lat + & ~(1 << pdimm->caslat_x) + & ~(1 << pdimm->caslat_x_minus_1)); + + /* Compute CAS latencies below that defined by SPD */ + pdimm->caslat_lowest_derated + = compute_derated_DDR1_CAS_latency(get_memory_clk_period_ps()); + + /* Compute timing parameters */ + pdimm->trcd_ps = spd->trcd * 250; + pdimm->trp_ps = spd->trp * 250; + pdimm->tras_ps = spd->tras * 1000; + + pdimm->twr_ps = mclk_to_picos(3); + pdimm->twtr_ps = mclk_to_picos(1); + pdimm->trfc_ps = compute_trfc_ps_from_spd(0, spd->trfc); + + pdimm->trrd_ps = spd->trrd * 250; + pdimm->trc_ps = compute_trc_ps_from_spd(0, spd->trc); + + pdimm->refresh_rate_ps = determine_refresh_rate_ps(spd->refresh); + + pdimm->tis_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_setup); + pdimm->tih_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_hold); + pdimm->tds_ps + = convert_bcd_hundredths_to_cycle_time_ps(spd->data_setup); + pdimm->tdh_ps + = convert_bcd_hundredths_to_cycle_time_ps(spd->data_hold); + + pdimm->trtp_ps = mclk_to_picos(2); /* By the book. */ + pdimm->tdqsq_max_ps = spd->tdqsq * 10; + pdimm->tqhs_ps = spd->tqhs * 10; + + return 0; +} diff --git a/drivers/ddr/fsl/ddr2_dimm_params.c b/drivers/ddr/fsl/ddr2_dimm_params.c new file mode 100644 index 0000000..d865df7 --- /dev/null +++ b/drivers/ddr/fsl/ddr2_dimm_params.c @@ -0,0 +1,342 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include +#include + +#include +/* + * Calculate the Density of each Physical Rank. + * Returned size is in bytes. + * + * Study these table from Byte 31 of JEDEC SPD Spec. + * + * DDR I DDR II + * Bit Size Size + * --- ----- ------ + * 7 high 512MB 512MB + * 6 256MB 256MB + * 5 128MB 128MB + * 4 64MB 16GB + * 3 32MB 8GB + * 2 16MB 4GB + * 1 2GB 2GB + * 0 low 1GB 1GB + * + * Reorder Table to be linear by stripping the bottom + * 2 or 5 bits off and shifting them up to the top. + * + */ +static unsigned long long +compute_ranksize(unsigned int mem_type, unsigned char row_dens) +{ + unsigned long long bsize; + + /* Bottom 5 bits up to the top. */ + bsize = ((row_dens >> 5) | ((row_dens & 31) << 3)); + bsize <<= 27ULL; + debug("DDR: DDR II rank density = 0x%16llx\n", bsize); + + return bsize; +} + +/* + * Convert a two-nibble BCD value into a cycle time. + * While the spec calls for nano-seconds, picos are returned. + * + * This implements the tables for bytes 9, 23 and 25 for both + * DDR I and II. No allowance for distinguishing the invalid + * fields absent for DDR I yet present in DDR II is made. + * (That is, cycle times of .25, .33, .66 and .75 ns are + * allowed for both DDR II and I.) + */ +static unsigned int +convert_bcd_tenths_to_cycle_time_ps(unsigned int spd_val) +{ + /* Table look up the lower nibble, allow DDR I & II. */ + unsigned int tenths_ps[16] = { + 0, + 100, + 200, + 300, + 400, + 500, + 600, + 700, + 800, + 900, + 250, /* This and the next 3 entries valid ... */ + 330, /* ... only for tCK calculations. */ + 660, + 750, + 0, /* undefined */ + 0 /* undefined */ + }; + + unsigned int whole_ns = (spd_val & 0xF0) >> 4; + unsigned int tenth_ns = spd_val & 0x0F; + unsigned int ps = whole_ns * 1000 + tenths_ps[tenth_ns]; + + return ps; +} + +static unsigned int +convert_bcd_hundredths_to_cycle_time_ps(unsigned int spd_val) +{ + unsigned int tenth_ns = (spd_val & 0xF0) >> 4; + unsigned int hundredth_ns = spd_val & 0x0F; + unsigned int ps = tenth_ns * 100 + hundredth_ns * 10; + + return ps; +} + +static unsigned int byte40_table_ps[8] = { + 0, + 250, + 330, + 500, + 660, + 750, + 0, /* supposed to be RFC, but not sure what that means */ + 0 /* Undefined */ +}; + +static unsigned int +compute_trfc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trfc) +{ + unsigned int trfc_ps; + + trfc_ps = (((trctrfc_ext & 0x1) * 256) + trfc) * 1000 + + byte40_table_ps[(trctrfc_ext >> 1) & 0x7]; + + return trfc_ps; +} + +static unsigned int +compute_trc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trc) +{ + unsigned int trc_ps; + + trc_ps = trc * 1000 + byte40_table_ps[(trctrfc_ext >> 4) & 0x7]; + + return trc_ps; +} + +/* + * Determine Refresh Rate. Ignore self refresh bit on DDR I. + * Table from SPD Spec, Byte 12, converted to picoseconds and + * filled in with "default" normal values. + */ +static unsigned int +determine_refresh_rate_ps(const unsigned int spd_refresh) +{ + unsigned int refresh_time_ps[8] = { + 15625000, /* 0 Normal 1.00x */ + 3900000, /* 1 Reduced .25x */ + 7800000, /* 2 Extended .50x */ + 31300000, /* 3 Extended 2.00x */ + 62500000, /* 4 Extended 4.00x */ + 125000000, /* 5 Extended 8.00x */ + 15625000, /* 6 Normal 1.00x filler */ + 15625000, /* 7 Normal 1.00x filler */ + }; + + return refresh_time_ps[spd_refresh & 0x7]; +} + +/* + * The purpose of this function is to compute a suitable + * CAS latency given the DRAM clock period. The SPD only + * defines at most 3 CAS latencies. Typically the slower in + * frequency the DIMM runs at, the shorter its CAS latency can. + * be. If the DIMM is operating at a sufficiently low frequency, + * it may be able to run at a CAS latency shorter than the + * shortest SPD-defined CAS latency. + * + * If a CAS latency is not found, 0 is returned. + * + * Do this by finding in the standard speed bin table the longest + * tCKmin that doesn't exceed the value of mclk_ps (tCK). + * + * An assumption made is that the SDRAM device allows the + * CL to be programmed for a value that is lower than those + * advertised by the SPD. This is not always the case, + * as those modes not defined in the SPD are optional. + * + * CAS latency de-rating based upon values JEDEC Standard No. 79-2C + * Table 40, "DDR2 SDRAM stanadard speed bins and tCK, tRCD, tRP, tRAS, + * and tRC for corresponding bin" + * + * ordinal 2, ddr2_speed_bins[1] contains tCK for CL=3 + * Not certain if any good value exists for CL=2 + */ + /* CL2 CL3 CL4 CL5 CL6 CL7*/ +unsigned short ddr2_speed_bins[] = { 0, 5000, 3750, 3000, 2500, 1875 }; + +unsigned int +compute_derated_DDR2_CAS_latency(unsigned int mclk_ps) +{ + const unsigned int num_speed_bins = ARRAY_SIZE(ddr2_speed_bins); + unsigned int lowest_tCKmin_found = 0; + unsigned int lowest_tCKmin_CL = 0; + unsigned int i; + + debug("mclk_ps = %u\n", mclk_ps); + + for (i = 0; i < num_speed_bins; i++) { + unsigned int x = ddr2_speed_bins[i]; + debug("i=%u, x = %u, lowest_tCKmin_found = %u\n", + i, x, lowest_tCKmin_found); + if (x && x <= mclk_ps && x >= lowest_tCKmin_found ) { + lowest_tCKmin_found = x; + lowest_tCKmin_CL = i + 2; + } + } + + debug("lowest_tCKmin_CL = %u\n", lowest_tCKmin_CL); + + return lowest_tCKmin_CL; +} + +/* + * ddr_compute_dimm_parameters for DDR2 SPD + * + * Compute DIMM parameters based upon the SPD information in spd. + * Writes the results to the dimm_params_t structure pointed by pdimm. + * + * FIXME: use #define for the retvals + */ +unsigned int +ddr_compute_dimm_parameters(const ddr2_spd_eeprom_t *spd, + dimm_params_t *pdimm, + unsigned int dimm_number) +{ + unsigned int retval; + + if (spd->mem_type) { + if (spd->mem_type != SPD_MEMTYPE_DDR2) { + printf("DIMM %u: is not a DDR2 SPD.\n", dimm_number); + return 1; + } + } else { + memset(pdimm, 0, sizeof(dimm_params_t)); + return 1; + } + + retval = ddr2_spd_check(spd); + if (retval) { + printf("DIMM %u: failed checksum\n", dimm_number); + return 2; + } + + /* + * The part name in ASCII in the SPD EEPROM is not null terminated. + * Guarantee null termination here by presetting all bytes to 0 + * and copying the part name in ASCII from the SPD onto it + */ + memset(pdimm->mpart, 0, sizeof(pdimm->mpart)); + memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1); + + /* DIMM organization parameters */ + pdimm->n_ranks = (spd->mod_ranks & 0x7) + 1; + pdimm->rank_density = compute_ranksize(spd->mem_type, spd->rank_dens); + pdimm->capacity = pdimm->n_ranks * pdimm->rank_density; + pdimm->data_width = spd->dataw; + pdimm->primary_sdram_width = spd->primw; + pdimm->ec_sdram_width = spd->ecw; + + /* These are all the types defined by the JEDEC DDR2 SPD 1.3 spec */ + switch (spd->dimm_type) { + case DDR2_SPD_DIMMTYPE_RDIMM: + case DDR2_SPD_DIMMTYPE_72B_SO_RDIMM: + case DDR2_SPD_DIMMTYPE_MINI_RDIMM: + /* Registered/buffered DIMMs */ + pdimm->registered_dimm = 1; + break; + + case DDR2_SPD_DIMMTYPE_UDIMM: + case DDR2_SPD_DIMMTYPE_SO_DIMM: + case DDR2_SPD_DIMMTYPE_MICRO_DIMM: + case DDR2_SPD_DIMMTYPE_MINI_UDIMM: + /* Unbuffered DIMMs */ + pdimm->registered_dimm = 0; + break; + + case DDR2_SPD_DIMMTYPE_72B_SO_CDIMM: + default: + printf("unknown dimm_type 0x%02X\n", spd->dimm_type); + return 1; + } + + /* SDRAM device parameters */ + pdimm->n_row_addr = spd->nrow_addr; + pdimm->n_col_addr = spd->ncol_addr; + pdimm->n_banks_per_sdram_device = spd->nbanks; + pdimm->edc_config = spd->config; + pdimm->burst_lengths_bitmask = spd->burstl; + pdimm->row_density = spd->rank_dens; + + /* + * Calculate the Maximum Data Rate based on the Minimum Cycle time. + * The SPD clk_cycle field (tCKmin) is measured in tenths of + * nanoseconds and represented as BCD. + */ + pdimm->tckmin_x_ps + = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle); + pdimm->tckmin_x_minus_1_ps + = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle2); + pdimm->tckmin_x_minus_2_ps + = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle3); + + pdimm->tckmax_ps = convert_bcd_tenths_to_cycle_time_ps(spd->tckmax); + + /* + * Compute CAS latencies defined by SPD + * The SPD caslat_x should have at least 1 and at most 3 bits set. + * + * If cas_lat after masking is 0, the __ilog2 function returns + * 255 into the variable. This behavior is abused once. + */ + pdimm->caslat_x = __ilog2(spd->cas_lat); + pdimm->caslat_x_minus_1 = __ilog2(spd->cas_lat + & ~(1 << pdimm->caslat_x)); + pdimm->caslat_x_minus_2 = __ilog2(spd->cas_lat + & ~(1 << pdimm->caslat_x) + & ~(1 << pdimm->caslat_x_minus_1)); + + /* Compute CAS latencies below that defined by SPD */ + pdimm->caslat_lowest_derated + = compute_derated_DDR2_CAS_latency(get_memory_clk_period_ps()); + + /* Compute timing parameters */ + pdimm->trcd_ps = spd->trcd * 250; + pdimm->trp_ps = spd->trp * 250; + pdimm->tras_ps = spd->tras * 1000; + + pdimm->twr_ps = spd->twr * 250; + pdimm->twtr_ps = spd->twtr * 250; + pdimm->trfc_ps = compute_trfc_ps_from_spd(spd->trctrfc_ext, spd->trfc); + + pdimm->trrd_ps = spd->trrd * 250; + pdimm->trc_ps = compute_trc_ps_from_spd(spd->trctrfc_ext, spd->trc); + + pdimm->refresh_rate_ps = determine_refresh_rate_ps(spd->refresh); + + pdimm->tis_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_setup); + pdimm->tih_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_hold); + pdimm->tds_ps + = convert_bcd_hundredths_to_cycle_time_ps(spd->data_setup); + pdimm->tdh_ps + = convert_bcd_hundredths_to_cycle_time_ps(spd->data_hold); + + pdimm->trtp_ps = spd->trtp * 250; + pdimm->tdqsq_max_ps = spd->tdqsq * 10; + pdimm->tqhs_ps = spd->tqhs * 10; + + return 0; +} diff --git a/drivers/ddr/fsl/ddr3_dimm_params.c b/drivers/ddr/fsl/ddr3_dimm_params.c new file mode 100644 index 0000000..a4b8c10 --- /dev/null +++ b/drivers/ddr/fsl/ddr3_dimm_params.c @@ -0,0 +1,341 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor, Inc. + * Dave Liu + * + * calculate the organization and timing parameter + * from ddr3 spd, please refer to the spec + * JEDEC standard No.21-C 4_01_02_11R18.pdf + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include +#include + +#include + +/* + * Calculate the Density of each Physical Rank. + * Returned size is in bytes. + * + * each rank size = + * sdram capacity(bit) / 8 * primary bus width / sdram width + * + * where: sdram capacity = spd byte4[3:0] + * primary bus width = spd byte8[2:0] + * sdram width = spd byte7[2:0] + * + * SPD byte4 - sdram density and banks + * bit[3:0] size(bit) size(byte) + * 0000 256Mb 32MB + * 0001 512Mb 64MB + * 0010 1Gb 128MB + * 0011 2Gb 256MB + * 0100 4Gb 512MB + * 0101 8Gb 1GB + * 0110 16Gb 2GB + * + * SPD byte8 - module memory bus width + * bit[2:0] primary bus width + * 000 8bits + * 001 16bits + * 010 32bits + * 011 64bits + * + * SPD byte7 - module organiztion + * bit[2:0] sdram device width + * 000 4bits + * 001 8bits + * 010 16bits + * 011 32bits + * + */ +static unsigned long long +compute_ranksize(const ddr3_spd_eeprom_t *spd) +{ + unsigned long long bsize; + + int nbit_sdram_cap_bsize = 0; + int nbit_primary_bus_width = 0; + int nbit_sdram_width = 0; + + if ((spd->density_banks & 0xf) < 7) + nbit_sdram_cap_bsize = (spd->density_banks & 0xf) + 28; + if ((spd->bus_width & 0x7) < 4) + nbit_primary_bus_width = (spd->bus_width & 0x7) + 3; + if ((spd->organization & 0x7) < 4) + nbit_sdram_width = (spd->organization & 0x7) + 2; + + bsize = 1ULL << (nbit_sdram_cap_bsize - 3 + + nbit_primary_bus_width - nbit_sdram_width); + + debug("DDR: DDR III rank density = 0x%16llx\n", bsize); + + return bsize; +} + +/* + * ddr_compute_dimm_parameters for DDR3 SPD + * + * Compute DIMM parameters based upon the SPD information in spd. + * Writes the results to the dimm_params_t structure pointed by pdimm. + * + */ +unsigned int +ddr_compute_dimm_parameters(const ddr3_spd_eeprom_t *spd, + dimm_params_t *pdimm, + unsigned int dimm_number) +{ + unsigned int retval; + unsigned int mtb_ps; + int ftb_10th_ps; + int i; + + if (spd->mem_type) { + if (spd->mem_type != SPD_MEMTYPE_DDR3) { + printf("DIMM %u: is not a DDR3 SPD.\n", dimm_number); + return 1; + } + } else { + memset(pdimm, 0, sizeof(dimm_params_t)); + return 1; + } + + retval = ddr3_spd_check(spd); + if (retval) { + printf("DIMM %u: failed checksum\n", dimm_number); + return 2; + } + + /* + * The part name in ASCII in the SPD EEPROM is not null terminated. + * Guarantee null termination here by presetting all bytes to 0 + * and copying the part name in ASCII from the SPD onto it + */ + memset(pdimm->mpart, 0, sizeof(pdimm->mpart)); + if ((spd->info_size_crc & 0xF) > 1) + memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1); + + /* DIMM organization parameters */ + pdimm->n_ranks = ((spd->organization >> 3) & 0x7) + 1; + pdimm->rank_density = compute_ranksize(spd); + pdimm->capacity = pdimm->n_ranks * pdimm->rank_density; + pdimm->primary_sdram_width = 1 << (3 + (spd->bus_width & 0x7)); + if ((spd->bus_width >> 3) & 0x3) + pdimm->ec_sdram_width = 8; + else + pdimm->ec_sdram_width = 0; + pdimm->data_width = pdimm->primary_sdram_width + + pdimm->ec_sdram_width; + pdimm->device_width = 1 << ((spd->organization & 0x7) + 2); + + /* These are the types defined by the JEDEC DDR3 SPD spec */ + pdimm->mirrored_dimm = 0; + pdimm->registered_dimm = 0; + switch (spd->module_type & DDR3_SPD_MODULETYPE_MASK) { + case DDR3_SPD_MODULETYPE_RDIMM: + case DDR3_SPD_MODULETYPE_MINI_RDIMM: + case DDR3_SPD_MODULETYPE_72B_SO_RDIMM: + /* Registered/buffered DIMMs */ + pdimm->registered_dimm = 1; + for (i = 0; i < 16; i += 2) { + u8 rcw = spd->mod_section.registered.rcw[i/2]; + pdimm->rcw[i] = (rcw >> 0) & 0x0F; + pdimm->rcw[i+1] = (rcw >> 4) & 0x0F; + } + break; + + case DDR3_SPD_MODULETYPE_UDIMM: + case DDR3_SPD_MODULETYPE_SO_DIMM: + case DDR3_SPD_MODULETYPE_MICRO_DIMM: + case DDR3_SPD_MODULETYPE_MINI_UDIMM: + case DDR3_SPD_MODULETYPE_MINI_CDIMM: + case DDR3_SPD_MODULETYPE_72B_SO_UDIMM: + case DDR3_SPD_MODULETYPE_72B_SO_CDIMM: + case DDR3_SPD_MODULETYPE_LRDIMM: + case DDR3_SPD_MODULETYPE_16B_SO_DIMM: + case DDR3_SPD_MODULETYPE_32B_SO_DIMM: + /* Unbuffered DIMMs */ + if (spd->mod_section.unbuffered.addr_mapping & 0x1) + pdimm->mirrored_dimm = 1; + break; + + default: + printf("unknown module_type 0x%02X\n", spd->module_type); + return 1; + } + + /* SDRAM device parameters */ + pdimm->n_row_addr = ((spd->addressing >> 3) & 0x7) + 12; + pdimm->n_col_addr = (spd->addressing & 0x7) + 9; + pdimm->n_banks_per_sdram_device = 8 << ((spd->density_banks >> 4) & 0x7); + + /* + * The SPD spec has not the ECC bit, + * We consider the DIMM as ECC capability + * when the extension bus exist + */ + if (pdimm->ec_sdram_width) + pdimm->edc_config = 0x02; + else + pdimm->edc_config = 0x00; + + /* + * The SPD spec has not the burst length byte + * but DDR3 spec has nature BL8 and BC4, + * BL8 -bit3, BC4 -bit2 + */ + pdimm->burst_lengths_bitmask = 0x0c; + pdimm->row_density = __ilog2(pdimm->rank_density); + + /* MTB - medium timebase + * The unit in the SPD spec is ns, + * We convert it to ps. + * eg: MTB = 0.125ns (125ps) + */ + mtb_ps = (spd->mtb_dividend * 1000) /spd->mtb_divisor; + pdimm->mtb_ps = mtb_ps; + + /* + * FTB - fine timebase + * use 1/10th of ps as our unit to avoid floating point + * eg, 10 for 1ps, 25 for 2.5ps, 50 for 5ps + */ + ftb_10th_ps = + ((spd->ftb_div & 0xf0) >> 4) * 10 / (spd->ftb_div & 0x0f); + pdimm->ftb_10th_ps = ftb_10th_ps; + /* + * sdram minimum cycle time + * we assume the MTB is 0.125ns + * eg: + * tck_min=15 MTB (1.875ns) ->DDR3-1066 + * =12 MTB (1.5ns) ->DDR3-1333 + * =10 MTB (1.25ns) ->DDR3-1600 + */ + pdimm->tckmin_x_ps = spd->tck_min * mtb_ps + + (spd->fine_tck_min * ftb_10th_ps) / 10; + + /* + * CAS latency supported + * bit4 - CL4 + * bit5 - CL5 + * bit18 - CL18 + */ + pdimm->caslat_x = ((spd->caslat_msb << 8) | spd->caslat_lsb) << 4; + + /* + * min CAS latency time + * eg: taa_min = + * DDR3-800D 100 MTB (12.5ns) + * DDR3-1066F 105 MTB (13.125ns) + * DDR3-1333H 108 MTB (13.5ns) + * DDR3-1600H 90 MTB (11.25ns) + */ + pdimm->taa_ps = spd->taa_min * mtb_ps + + (spd->fine_taa_min * ftb_10th_ps) / 10; + + /* + * min write recovery time + * eg: + * twr_min = 120 MTB (15ns) -> all speed grades. + */ + pdimm->twr_ps = spd->twr_min * mtb_ps; + + /* + * min RAS to CAS delay time + * eg: trcd_min = + * DDR3-800 100 MTB (12.5ns) + * DDR3-1066F 105 MTB (13.125ns) + * DDR3-1333H 108 MTB (13.5ns) + * DDR3-1600H 90 MTB (11.25) + */ + pdimm->trcd_ps = spd->trcd_min * mtb_ps + + (spd->fine_trcd_min * ftb_10th_ps) / 10; + + /* + * min row active to row active delay time + * eg: trrd_min = + * DDR3-800(1KB page) 80 MTB (10ns) + * DDR3-1333(1KB page) 48 MTB (6ns) + */ + pdimm->trrd_ps = spd->trrd_min * mtb_ps; + + /* + * min row precharge delay time + * eg: trp_min = + * DDR3-800D 100 MTB (12.5ns) + * DDR3-1066F 105 MTB (13.125ns) + * DDR3-1333H 108 MTB (13.5ns) + * DDR3-1600H 90 MTB (11.25ns) + */ + pdimm->trp_ps = spd->trp_min * mtb_ps + + (spd->fine_trp_min * ftb_10th_ps) / 10; + + /* min active to precharge delay time + * eg: tRAS_min = + * DDR3-800D 300 MTB (37.5ns) + * DDR3-1066F 300 MTB (37.5ns) + * DDR3-1333H 288 MTB (36ns) + * DDR3-1600H 280 MTB (35ns) + */ + pdimm->tras_ps = (((spd->tras_trc_ext & 0xf) << 8) | spd->tras_min_lsb) + * mtb_ps; + /* + * min active to actice/refresh delay time + * eg: tRC_min = + * DDR3-800D 400 MTB (50ns) + * DDR3-1066F 405 MTB (50.625ns) + * DDR3-1333H 396 MTB (49.5ns) + * DDR3-1600H 370 MTB (46.25ns) + */ + pdimm->trc_ps = (((spd->tras_trc_ext & 0xf0) << 4) | spd->trc_min_lsb) + * mtb_ps + (spd->fine_trc_min * ftb_10th_ps) / 10; + /* + * min refresh recovery delay time + * eg: tRFC_min = + * 512Mb 720 MTB (90ns) + * 1Gb 880 MTB (110ns) + * 2Gb 1280 MTB (160ns) + */ + pdimm->trfc_ps = ((spd->trfc_min_msb << 8) | spd->trfc_min_lsb) + * mtb_ps; + /* + * min internal write to read command delay time + * eg: twtr_min = 40 MTB (7.5ns) - all speed bins. + * tWRT is at least 4 mclk independent of operating freq. + */ + pdimm->twtr_ps = spd->twtr_min * mtb_ps; + + /* + * min internal read to precharge command delay time + * eg: trtp_min = 40 MTB (7.5ns) - all speed bins. + * tRTP is at least 4 mclk independent of operating freq. + */ + pdimm->trtp_ps = spd->trtp_min * mtb_ps; + + /* + * Average periodic refresh interval + * tREFI = 7.8 us at normal temperature range + * = 3.9 us at ext temperature range + */ + pdimm->refresh_rate_ps = 7800000; + if ((spd->therm_ref_opt & 0x1) && !(spd->therm_ref_opt & 0x2)) { + pdimm->refresh_rate_ps = 3900000; + pdimm->extended_op_srt = 1; + } + + /* + * min four active window delay time + * eg: tfaw_min = + * DDR3-800(1KB page) 320 MTB (40ns) + * DDR3-1066(1KB page) 300 MTB (37.5ns) + * DDR3-1333(1KB page) 240 MTB (30ns) + * DDR3-1600(1KB page) 240 MTB (30ns) + */ + pdimm->tfaw_ps = (((spd->tfaw_msb & 0xf) << 8) | spd->tfaw_min) + * mtb_ps; + + return 0; +} diff --git a/drivers/ddr/fsl/interactive.c b/drivers/ddr/fsl/interactive.c new file mode 100644 index 0000000..ebf3ed6 --- /dev/null +++ b/drivers/ddr/fsl/interactive.c @@ -0,0 +1,1871 @@ +/* + * Copyright 2010-2012 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * Generic driver for Freescale DDR/DDR2/DDR3 memory controller. + * Based on code from spd_sdram.c + * Author: James Yang [at freescale.com] + * York Sun [at freescale.com] + */ + +#include +#include +#include +#include + +#include +#include + +/* Option parameter Structures */ +struct options_string { + const char *option_name; + size_t offset; + unsigned int size; + const char printhex; +}; + +static unsigned int picos_to_mhz(unsigned int picos) +{ + return 1000000 / picos; +} + +static void print_option_table(const struct options_string *table, + int table_size, + const void *base) +{ + unsigned int i; + unsigned int *ptr; + unsigned long long *ptr_l; + + for (i = 0; i < table_size; i++) { + switch (table[i].size) { + case 4: + ptr = (unsigned int *) (base + table[i].offset); + if (table[i].printhex) { + printf("%s = 0x%08X\n", + table[i].option_name, *ptr); + } else { + printf("%s = %u\n", + table[i].option_name, *ptr); + } + break; + case 8: + ptr_l = (unsigned long long *) (base + table[i].offset); + printf("%s = %llu\n", + table[i].option_name, *ptr_l); + break; + default: + printf("Unrecognized size!\n"); + break; + } + } +} + +static int handle_option_table(const struct options_string *table, + int table_size, + void *base, + const char *opt, + const char *val) +{ + unsigned int i; + unsigned int value, *ptr; + unsigned long long value_l, *ptr_l; + + for (i = 0; i < table_size; i++) { + if (strcmp(table[i].option_name, opt) != 0) + continue; + switch (table[i].size) { + case 4: + value = simple_strtoul(val, NULL, 0); + ptr = base + table[i].offset; + *ptr = value; + break; + case 8: + value_l = simple_strtoull(val, NULL, 0); + ptr_l = base + table[i].offset; + *ptr_l = value_l; + break; + default: + printf("Unrecognized size!\n"); + break; + } + return 1; + } + + return 0; +} + +static void fsl_ddr_generic_edit(void *pdata, + void *pend, + unsigned int element_size, + unsigned int element_num, + unsigned int value) +{ + char *pcdata = (char *)pdata; /* BIG ENDIAN ONLY */ + + pcdata += element_num * element_size; + if ((pcdata + element_size) > (char *) pend) { + printf("trying to write past end of data\n"); + return; + } + + switch (element_size) { + case 1: + __raw_writeb(value, pcdata); + break; + case 2: + __raw_writew(value, pcdata); + break; + case 4: + __raw_writel(value, pcdata); + break; + default: + printf("unexpected element size %u\n", element_size); + break; + } +} + +static void fsl_ddr_spd_edit(fsl_ddr_info_t *pinfo, + unsigned int ctrl_num, + unsigned int dimm_num, + unsigned int element_num, + unsigned int value) +{ + generic_spd_eeprom_t *pspd; + + pspd = &(pinfo->spd_installed_dimms[ctrl_num][dimm_num]); + fsl_ddr_generic_edit(pspd, pspd + 1, 1, element_num, value); +} + +#define COMMON_TIMING(x) {#x, offsetof(common_timing_params_t, x), \ + sizeof((common_timing_params_t *)0)->x, 0} + +static void lowest_common_dimm_parameters_edit(fsl_ddr_info_t *pinfo, + unsigned int ctrl_num, + const char *optname_str, + const char *value_str) +{ + common_timing_params_t *p = &pinfo->common_timing_params[ctrl_num]; + + static const struct options_string options[] = { + COMMON_TIMING(tckmin_x_ps), + COMMON_TIMING(tckmax_ps), + COMMON_TIMING(tckmax_max_ps), + COMMON_TIMING(trcd_ps), + COMMON_TIMING(trp_ps), + COMMON_TIMING(tras_ps), + COMMON_TIMING(twr_ps), + COMMON_TIMING(twtr_ps), + COMMON_TIMING(trfc_ps), + COMMON_TIMING(trrd_ps), + COMMON_TIMING(trc_ps), + COMMON_TIMING(refresh_rate_ps), + COMMON_TIMING(tis_ps), + COMMON_TIMING(tih_ps), + COMMON_TIMING(tds_ps), + COMMON_TIMING(tdh_ps), + COMMON_TIMING(trtp_ps), + COMMON_TIMING(tdqsq_max_ps), + COMMON_TIMING(tqhs_ps), + COMMON_TIMING(ndimms_present), + COMMON_TIMING(lowest_common_SPD_caslat), + COMMON_TIMING(highest_common_derated_caslat), + COMMON_TIMING(additive_latency), + COMMON_TIMING(all_dimms_burst_lengths_bitmask), + COMMON_TIMING(all_dimms_registered), + COMMON_TIMING(all_dimms_unbuffered), + COMMON_TIMING(all_dimms_ecc_capable), + COMMON_TIMING(total_mem), + COMMON_TIMING(base_address), + }; + static const unsigned int n_opts = ARRAY_SIZE(options); + + if (handle_option_table(options, n_opts, p, optname_str, value_str)) + return; + + printf("Error: couldn't find option string %s\n", optname_str); +} + +#define DIMM_PARM(x) {#x, offsetof(dimm_params_t, x), \ + sizeof((dimm_params_t *)0)->x, 0} + +static void fsl_ddr_dimm_parameters_edit(fsl_ddr_info_t *pinfo, + unsigned int ctrl_num, + unsigned int dimm_num, + const char *optname_str, + const char *value_str) +{ + dimm_params_t *p = &(pinfo->dimm_params[ctrl_num][dimm_num]); + + static const struct options_string options[] = { + DIMM_PARM(n_ranks), + DIMM_PARM(data_width), + DIMM_PARM(primary_sdram_width), + DIMM_PARM(ec_sdram_width), + DIMM_PARM(registered_dimm), + DIMM_PARM(device_width), + + DIMM_PARM(n_row_addr), + DIMM_PARM(n_col_addr), + DIMM_PARM(edc_config), + DIMM_PARM(n_banks_per_sdram_device), + DIMM_PARM(burst_lengths_bitmask), + DIMM_PARM(row_density), + + DIMM_PARM(tckmin_x_ps), + DIMM_PARM(tckmin_x_minus_1_ps), + DIMM_PARM(tckmin_x_minus_2_ps), + DIMM_PARM(tckmax_ps), + + DIMM_PARM(caslat_x), + DIMM_PARM(caslat_x_minus_1), + DIMM_PARM(caslat_x_minus_2), + + DIMM_PARM(caslat_lowest_derated), + + DIMM_PARM(trcd_ps), + DIMM_PARM(trp_ps), + DIMM_PARM(tras_ps), + DIMM_PARM(twr_ps), + DIMM_PARM(twtr_ps), + DIMM_PARM(trfc_ps), + DIMM_PARM(trrd_ps), + DIMM_PARM(trc_ps), + DIMM_PARM(refresh_rate_ps), + + DIMM_PARM(tis_ps), + DIMM_PARM(tih_ps), + DIMM_PARM(tds_ps), + DIMM_PARM(tdh_ps), + DIMM_PARM(trtp_ps), + DIMM_PARM(tdqsq_max_ps), + DIMM_PARM(tqhs_ps), + + DIMM_PARM(rank_density), + DIMM_PARM(capacity), + DIMM_PARM(base_address), + }; + + static const unsigned int n_opts = ARRAY_SIZE(options); + + if (handle_option_table(options, n_opts, p, optname_str, value_str)) + return; + + printf("couldn't find option string %s\n", optname_str); +} + +static void print_dimm_parameters(const dimm_params_t *pdimm) +{ + static const struct options_string options[] = { + DIMM_PARM(n_ranks), + DIMM_PARM(data_width), + DIMM_PARM(primary_sdram_width), + DIMM_PARM(ec_sdram_width), + DIMM_PARM(registered_dimm), + DIMM_PARM(device_width), + + DIMM_PARM(n_row_addr), + DIMM_PARM(n_col_addr), + DIMM_PARM(edc_config), + DIMM_PARM(n_banks_per_sdram_device), + + DIMM_PARM(tckmin_x_ps), + DIMM_PARM(tckmin_x_minus_1_ps), + DIMM_PARM(tckmin_x_minus_2_ps), + DIMM_PARM(tckmax_ps), + + DIMM_PARM(caslat_x), + DIMM_PARM(taa_ps), + DIMM_PARM(caslat_x_minus_1), + DIMM_PARM(caslat_x_minus_2), + DIMM_PARM(caslat_lowest_derated), + + DIMM_PARM(trcd_ps), + DIMM_PARM(trp_ps), + DIMM_PARM(tras_ps), + DIMM_PARM(twr_ps), + DIMM_PARM(twtr_ps), + DIMM_PARM(trfc_ps), + DIMM_PARM(trrd_ps), + DIMM_PARM(trc_ps), + DIMM_PARM(refresh_rate_ps), + + DIMM_PARM(tis_ps), + DIMM_PARM(tih_ps), + DIMM_PARM(tds_ps), + DIMM_PARM(tdh_ps), + DIMM_PARM(trtp_ps), + DIMM_PARM(tdqsq_max_ps), + DIMM_PARM(tqhs_ps), + }; + static const unsigned int n_opts = ARRAY_SIZE(options); + + if (pdimm->n_ranks == 0) { + printf("DIMM not present\n"); + return; + } + printf("DIMM organization parameters:\n"); + printf("module part name = %s\n", pdimm->mpart); + printf("rank_density = %llu bytes (%llu megabytes)\n", + pdimm->rank_density, pdimm->rank_density / 0x100000); + printf("capacity = %llu bytes (%llu megabytes)\n", + pdimm->capacity, pdimm->capacity / 0x100000); + printf("burst_lengths_bitmask = %02X\n", + pdimm->burst_lengths_bitmask); + printf("base_addresss = %llu (%08llX %08llX)\n", + pdimm->base_address, + (pdimm->base_address >> 32), + pdimm->base_address & 0xFFFFFFFF); + print_option_table(options, n_opts, pdimm); +} + +static void print_lowest_common_dimm_parameters( + const common_timing_params_t *plcd_dimm_params) +{ + static const struct options_string options[] = { + COMMON_TIMING(tckmax_max_ps), + COMMON_TIMING(trcd_ps), + COMMON_TIMING(trp_ps), + COMMON_TIMING(tras_ps), + COMMON_TIMING(twr_ps), + COMMON_TIMING(twtr_ps), + COMMON_TIMING(trfc_ps), + COMMON_TIMING(trrd_ps), + COMMON_TIMING(trc_ps), + COMMON_TIMING(refresh_rate_ps), + COMMON_TIMING(tis_ps), + COMMON_TIMING(tds_ps), + COMMON_TIMING(tdh_ps), + COMMON_TIMING(trtp_ps), + COMMON_TIMING(tdqsq_max_ps), + COMMON_TIMING(tqhs_ps), + COMMON_TIMING(lowest_common_SPD_caslat), + COMMON_TIMING(highest_common_derated_caslat), + COMMON_TIMING(additive_latency), + COMMON_TIMING(ndimms_present), + COMMON_TIMING(all_dimms_registered), + COMMON_TIMING(all_dimms_unbuffered), + COMMON_TIMING(all_dimms_ecc_capable), + }; + static const unsigned int n_opts = ARRAY_SIZE(options); + + /* Clock frequencies */ + printf("tckmin_x_ps = %u (%u MHz)\n", + plcd_dimm_params->tckmin_x_ps, + picos_to_mhz(plcd_dimm_params->tckmin_x_ps)); + printf("tckmax_ps = %u (%u MHz)\n", + plcd_dimm_params->tckmax_ps, + picos_to_mhz(plcd_dimm_params->tckmax_ps)); + printf("all_dimms_burst_lengths_bitmask = %02X\n", + plcd_dimm_params->all_dimms_burst_lengths_bitmask); + + print_option_table(options, n_opts, plcd_dimm_params); + + printf("total_mem = %llu (%llu megabytes)\n", + plcd_dimm_params->total_mem, + plcd_dimm_params->total_mem / 0x100000); + printf("base_address = %llu (%llu megabytes)\n", + plcd_dimm_params->base_address, + plcd_dimm_params->base_address / 0x100000); +} + +#define CTRL_OPTIONS(x) {#x, offsetof(memctl_options_t, x), \ + sizeof((memctl_options_t *)0)->x, 0} +#define CTRL_OPTIONS_CS(x, y) {"cs" #x "_" #y, \ + offsetof(memctl_options_t, cs_local_opts[x].y), \ + sizeof((memctl_options_t *)0)->cs_local_opts[x].y, 0} + +static void fsl_ddr_options_edit(fsl_ddr_info_t *pinfo, + unsigned int ctl_num, + const char *optname_str, + const char *value_str) +{ + memctl_options_t *p = &(pinfo->memctl_opts[ctl_num]); + /* + * This array all on the stack and *computed* each time this + * function is rung. + */ + static const struct options_string options[] = { + CTRL_OPTIONS_CS(0, odt_rd_cfg), + CTRL_OPTIONS_CS(0, odt_wr_cfg), +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 1) + CTRL_OPTIONS_CS(1, odt_rd_cfg), + CTRL_OPTIONS_CS(1, odt_wr_cfg), +#endif +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 2) + CTRL_OPTIONS_CS(2, odt_rd_cfg), + CTRL_OPTIONS_CS(2, odt_wr_cfg), +#endif +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 2) + CTRL_OPTIONS_CS(3, odt_rd_cfg), + CTRL_OPTIONS_CS(3, odt_wr_cfg), +#endif +#if defined(CONFIG_SYS_FSL_DDR3) + CTRL_OPTIONS_CS(0, odt_rtt_norm), + CTRL_OPTIONS_CS(0, odt_rtt_wr), +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 1) + CTRL_OPTIONS_CS(1, odt_rtt_norm), + CTRL_OPTIONS_CS(1, odt_rtt_wr), +#endif +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 2) + CTRL_OPTIONS_CS(2, odt_rtt_norm), + CTRL_OPTIONS_CS(2, odt_rtt_wr), +#endif +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 2) + CTRL_OPTIONS_CS(3, odt_rtt_norm), + CTRL_OPTIONS_CS(3, odt_rtt_wr), +#endif +#endif + CTRL_OPTIONS(memctl_interleaving), + CTRL_OPTIONS(memctl_interleaving_mode), + CTRL_OPTIONS(ba_intlv_ctl), + CTRL_OPTIONS(ecc_mode), + CTRL_OPTIONS(ecc_init_using_memctl), + CTRL_OPTIONS(dqs_config), + CTRL_OPTIONS(self_refresh_in_sleep), + CTRL_OPTIONS(dynamic_power), + CTRL_OPTIONS(data_bus_width), + CTRL_OPTIONS(burst_length), + CTRL_OPTIONS(cas_latency_override), + CTRL_OPTIONS(cas_latency_override_value), + CTRL_OPTIONS(use_derated_caslat), + CTRL_OPTIONS(additive_latency_override), + CTRL_OPTIONS(additive_latency_override_value), + CTRL_OPTIONS(clk_adjust), + CTRL_OPTIONS(cpo_override), + CTRL_OPTIONS(write_data_delay), + CTRL_OPTIONS(half_strength_driver_enable), + + /* + * These can probably be changed to 2T_EN and 3T_EN + * (using a leading numerical character) without problem + */ + CTRL_OPTIONS(twot_en), + CTRL_OPTIONS(threet_en), + CTRL_OPTIONS(ap_en), + CTRL_OPTIONS(x4_en), + CTRL_OPTIONS(bstopre), + CTRL_OPTIONS(wrlvl_override), + CTRL_OPTIONS(wrlvl_sample), + CTRL_OPTIONS(wrlvl_start), + CTRL_OPTIONS(rcw_override), + CTRL_OPTIONS(rcw_1), + CTRL_OPTIONS(rcw_2), + CTRL_OPTIONS(ddr_cdr1), + CTRL_OPTIONS(ddr_cdr2), + CTRL_OPTIONS(tcke_clock_pulse_width_ps), + CTRL_OPTIONS(tfaw_window_four_activates_ps), + CTRL_OPTIONS(trwt_override), + CTRL_OPTIONS(trwt), + }; + + static const unsigned int n_opts = ARRAY_SIZE(options); + + if (handle_option_table(options, n_opts, p, + optname_str, value_str)) + return; + + printf("couldn't find option string %s\n", optname_str); +} + +#define CFG_REGS(x) {#x, offsetof(fsl_ddr_cfg_regs_t, x), \ + sizeof((fsl_ddr_cfg_regs_t *)0)->x, 1} +#define CFG_REGS_CS(x, y) {"cs" #x "_" #y, \ + offsetof(fsl_ddr_cfg_regs_t, cs[x].y), \ + sizeof((fsl_ddr_cfg_regs_t *)0)->cs[x].y, 1} + +static void print_fsl_memctl_config_regs(const fsl_ddr_cfg_regs_t *ddr) +{ + unsigned int i; + static const struct options_string options[] = { + CFG_REGS_CS(0, bnds), + CFG_REGS_CS(0, config), + CFG_REGS_CS(0, config_2), +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 1) + CFG_REGS_CS(1, bnds), + CFG_REGS_CS(1, config), + CFG_REGS_CS(1, config_2), +#endif +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 2) + CFG_REGS_CS(2, bnds), + CFG_REGS_CS(2, config), + CFG_REGS_CS(2, config_2), +#endif +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 2) + CFG_REGS_CS(3, bnds), + CFG_REGS_CS(3, config), + CFG_REGS_CS(3, config_2), +#endif + CFG_REGS(timing_cfg_3), + CFG_REGS(timing_cfg_0), + CFG_REGS(timing_cfg_1), + CFG_REGS(timing_cfg_2), + CFG_REGS(ddr_sdram_cfg), + CFG_REGS(ddr_sdram_cfg_2), + CFG_REGS(ddr_sdram_mode), + CFG_REGS(ddr_sdram_mode_2), + CFG_REGS(ddr_sdram_mode_3), + CFG_REGS(ddr_sdram_mode_4), + CFG_REGS(ddr_sdram_mode_5), + CFG_REGS(ddr_sdram_mode_6), + CFG_REGS(ddr_sdram_mode_7), + CFG_REGS(ddr_sdram_mode_8), + CFG_REGS(ddr_sdram_interval), + CFG_REGS(ddr_data_init), + CFG_REGS(ddr_sdram_clk_cntl), + CFG_REGS(ddr_init_addr), + CFG_REGS(ddr_init_ext_addr), + CFG_REGS(timing_cfg_4), + CFG_REGS(timing_cfg_5), + CFG_REGS(ddr_zq_cntl), + CFG_REGS(ddr_wrlvl_cntl), + CFG_REGS(ddr_wrlvl_cntl_2), + CFG_REGS(ddr_wrlvl_cntl_3), + CFG_REGS(ddr_sr_cntr), + CFG_REGS(ddr_sdram_rcw_1), + CFG_REGS(ddr_sdram_rcw_2), + CFG_REGS(ddr_cdr1), + CFG_REGS(ddr_cdr2), + CFG_REGS(err_disable), + CFG_REGS(err_int_en), + CFG_REGS(ddr_eor), + }; + static const unsigned int n_opts = ARRAY_SIZE(options); + + print_option_table(options, n_opts, ddr); + + for (i = 0; i < 32; i++) + printf("debug_%02d = 0x%08X\n", i+1, ddr->debug[i]); +} + +static void fsl_ddr_regs_edit(fsl_ddr_info_t *pinfo, + unsigned int ctrl_num, + const char *regname, + const char *value_str) +{ + unsigned int i; + fsl_ddr_cfg_regs_t *ddr; + char buf[20]; + static const struct options_string options[] = { + CFG_REGS_CS(0, bnds), + CFG_REGS_CS(0, config), + CFG_REGS_CS(0, config_2), +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 1) + CFG_REGS_CS(1, bnds), + CFG_REGS_CS(1, config), + CFG_REGS_CS(1, config_2), +#endif +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 2) + CFG_REGS_CS(2, bnds), + CFG_REGS_CS(2, config), + CFG_REGS_CS(2, config_2), +#endif +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 3) + CFG_REGS_CS(3, bnds), + CFG_REGS_CS(3, config), + CFG_REGS_CS(3, config_2), +#endif + CFG_REGS(timing_cfg_3), + CFG_REGS(timing_cfg_0), + CFG_REGS(timing_cfg_1), + CFG_REGS(timing_cfg_2), + CFG_REGS(ddr_sdram_cfg), + CFG_REGS(ddr_sdram_cfg_2), + CFG_REGS(ddr_sdram_mode), + CFG_REGS(ddr_sdram_mode_2), + CFG_REGS(ddr_sdram_mode_3), + CFG_REGS(ddr_sdram_mode_4), + CFG_REGS(ddr_sdram_mode_5), + CFG_REGS(ddr_sdram_mode_6), + CFG_REGS(ddr_sdram_mode_7), + CFG_REGS(ddr_sdram_mode_8), + CFG_REGS(ddr_sdram_interval), + CFG_REGS(ddr_data_init), + CFG_REGS(ddr_sdram_clk_cntl), + CFG_REGS(ddr_init_addr), + CFG_REGS(ddr_init_ext_addr), + CFG_REGS(timing_cfg_4), + CFG_REGS(timing_cfg_5), + CFG_REGS(ddr_zq_cntl), + CFG_REGS(ddr_wrlvl_cntl), + CFG_REGS(ddr_wrlvl_cntl_2), + CFG_REGS(ddr_wrlvl_cntl_3), + CFG_REGS(ddr_sr_cntr), + CFG_REGS(ddr_sdram_rcw_1), + CFG_REGS(ddr_sdram_rcw_2), + CFG_REGS(ddr_cdr1), + CFG_REGS(ddr_cdr2), + CFG_REGS(err_disable), + CFG_REGS(err_int_en), + CFG_REGS(ddr_sdram_rcw_2), + CFG_REGS(ddr_sdram_rcw_2), + CFG_REGS(ddr_eor), + }; + static const unsigned int n_opts = ARRAY_SIZE(options); + + debug("fsl_ddr_regs_edit: ctrl_num = %u, " + "regname = %s, value = %s\n", + ctrl_num, regname, value_str); + if (ctrl_num > CONFIG_NUM_DDR_CONTROLLERS) + return; + + ddr = &(pinfo->fsl_ddr_config_reg[ctrl_num]); + + if (handle_option_table(options, n_opts, ddr, regname, value_str)) + return; + + for (i = 0; i < 32; i++) { + unsigned int value = simple_strtoul(value_str, NULL, 0); + sprintf(buf, "debug_%u", i + 1); + if (strcmp(buf, regname) == 0) { + ddr->debug[i] = value; + return; + } + } + printf("Error: couldn't find register string %s\n", regname); +} + +#define CTRL_OPTIONS_HEX(x) {#x, offsetof(memctl_options_t, x), \ + sizeof((memctl_options_t *)0)->x, 1} + +static void print_memctl_options(const memctl_options_t *popts) +{ + static const struct options_string options[] = { + CTRL_OPTIONS_CS(0, odt_rd_cfg), + CTRL_OPTIONS_CS(0, odt_wr_cfg), +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 1) + CTRL_OPTIONS_CS(1, odt_rd_cfg), + CTRL_OPTIONS_CS(1, odt_wr_cfg), +#endif +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 2) + CTRL_OPTIONS_CS(2, odt_rd_cfg), + CTRL_OPTIONS_CS(2, odt_wr_cfg), +#endif +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 3) + CTRL_OPTIONS_CS(3, odt_rd_cfg), + CTRL_OPTIONS_CS(3, odt_wr_cfg), +#endif +#if defined(CONFIG_SYS_FSL_DDR3) + CTRL_OPTIONS_CS(0, odt_rtt_norm), + CTRL_OPTIONS_CS(0, odt_rtt_wr), +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 1) + CTRL_OPTIONS_CS(1, odt_rtt_norm), + CTRL_OPTIONS_CS(1, odt_rtt_wr), +#endif +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 2) + CTRL_OPTIONS_CS(2, odt_rtt_norm), + CTRL_OPTIONS_CS(2, odt_rtt_wr), +#endif +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 3) + CTRL_OPTIONS_CS(3, odt_rtt_norm), + CTRL_OPTIONS_CS(3, odt_rtt_wr), +#endif +#endif + CTRL_OPTIONS(memctl_interleaving), + CTRL_OPTIONS(memctl_interleaving_mode), + CTRL_OPTIONS_HEX(ba_intlv_ctl), + CTRL_OPTIONS(ecc_mode), + CTRL_OPTIONS(ecc_init_using_memctl), + CTRL_OPTIONS(dqs_config), + CTRL_OPTIONS(self_refresh_in_sleep), + CTRL_OPTIONS(dynamic_power), + CTRL_OPTIONS(data_bus_width), + CTRL_OPTIONS(burst_length), + CTRL_OPTIONS(cas_latency_override), + CTRL_OPTIONS(cas_latency_override_value), + CTRL_OPTIONS(use_derated_caslat), + CTRL_OPTIONS(additive_latency_override), + CTRL_OPTIONS(additive_latency_override_value), + CTRL_OPTIONS(clk_adjust), + CTRL_OPTIONS(cpo_override), + CTRL_OPTIONS(write_data_delay), + CTRL_OPTIONS(half_strength_driver_enable), + /* + * These can probably be changed to 2T_EN and 3T_EN + * (using a leading numerical character) without problem + */ + CTRL_OPTIONS(twot_en), + CTRL_OPTIONS(threet_en), + CTRL_OPTIONS(registered_dimm_en), + CTRL_OPTIONS(ap_en), + CTRL_OPTIONS(x4_en), + CTRL_OPTIONS(bstopre), + CTRL_OPTIONS(wrlvl_override), + CTRL_OPTIONS(wrlvl_sample), + CTRL_OPTIONS(wrlvl_start), + CTRL_OPTIONS(rcw_override), + CTRL_OPTIONS(rcw_1), + CTRL_OPTIONS(rcw_2), + CTRL_OPTIONS_HEX(ddr_cdr1), + CTRL_OPTIONS_HEX(ddr_cdr2), + CTRL_OPTIONS(tcke_clock_pulse_width_ps), + CTRL_OPTIONS(tfaw_window_four_activates_ps), + CTRL_OPTIONS(trwt_override), + CTRL_OPTIONS(trwt), + }; + static const unsigned int n_opts = ARRAY_SIZE(options); + + print_option_table(options, n_opts, popts); +} + +#ifdef CONFIG_SYS_FSL_DDR1 +void ddr1_spd_dump(const ddr1_spd_eeprom_t *spd) +{ + unsigned int i; + + printf("%-3d : %02x %s\n", 0, spd->info_size, + " spd->info_size, * 0 # bytes written into serial memory *"); + printf("%-3d : %02x %s\n", 1, spd->chip_size, + " spd->chip_size, * 1 Total # bytes of SPD memory device *"); + printf("%-3d : %02x %s\n", 2, spd->mem_type, + " spd->mem_type, * 2 Fundamental memory type *"); + printf("%-3d : %02x %s\n", 3, spd->nrow_addr, + " spd->nrow_addr, * 3 # of Row Addresses on this assembly *"); + printf("%-3d : %02x %s\n", 4, spd->ncol_addr, + " spd->ncol_addr, * 4 # of Column Addrs on this assembly *"); + printf("%-3d : %02x %s\n", 5, spd->nrows, + " spd->nrows * 5 # of DIMM Banks *"); + printf("%-3d : %02x %s\n", 6, spd->dataw_lsb, + " spd->dataw_lsb, * 6 Data Width lsb of this assembly *"); + printf("%-3d : %02x %s\n", 7, spd->dataw_msb, + " spd->dataw_msb, * 7 Data Width msb of this assembly *"); + printf("%-3d : %02x %s\n", 8, spd->voltage, + " spd->voltage, * 8 Voltage intf std of this assembly *"); + printf("%-3d : %02x %s\n", 9, spd->clk_cycle, + " spd->clk_cycle, * 9 SDRAM Cycle time at CL=X *"); + printf("%-3d : %02x %s\n", 10, spd->clk_access, + " spd->clk_access, * 10 SDRAM Access from Clock at CL=X *"); + printf("%-3d : %02x %s\n", 11, spd->config, + " spd->config, * 11 DIMM Configuration type *"); + printf("%-3d : %02x %s\n", 12, spd->refresh, + " spd->refresh, * 12 Refresh Rate/Type *"); + printf("%-3d : %02x %s\n", 13, spd->primw, + " spd->primw, * 13 Primary SDRAM Width *"); + printf("%-3d : %02x %s\n", 14, spd->ecw, + " spd->ecw, * 14 Error Checking SDRAM width *"); + printf("%-3d : %02x %s\n", 15, spd->min_delay, + " spd->min_delay, * 15 Back to Back Random Access *"); + printf("%-3d : %02x %s\n", 16, spd->burstl, + " spd->burstl, * 16 Burst Lengths Supported *"); + printf("%-3d : %02x %s\n", 17, spd->nbanks, + " spd->nbanks, * 17 # of Banks on Each SDRAM Device *"); + printf("%-3d : %02x %s\n", 18, spd->cas_lat, + " spd->cas_lat, * 18 CAS# Latencies Supported *"); + printf("%-3d : %02x %s\n", 19, spd->cs_lat, + " spd->cs_lat, * 19 Chip Select Latency *"); + printf("%-3d : %02x %s\n", 20, spd->write_lat, + " spd->write_lat, * 20 Write Latency/Recovery *"); + printf("%-3d : %02x %s\n", 21, spd->mod_attr, + " spd->mod_attr, * 21 SDRAM Module Attributes *"); + printf("%-3d : %02x %s\n", 22, spd->dev_attr, + " spd->dev_attr, * 22 SDRAM Device Attributes *"); + printf("%-3d : %02x %s\n", 23, spd->clk_cycle2, + " spd->clk_cycle2, * 23 Min SDRAM Cycle time at CL=X-1 *"); + printf("%-3d : %02x %s\n", 24, spd->clk_access2, + " spd->clk_access2, * 24 SDRAM Access from Clock at CL=X-1 *"); + printf("%-3d : %02x %s\n", 25, spd->clk_cycle3, + " spd->clk_cycle3, * 25 Min SDRAM Cycle time at CL=X-2 *"); + printf("%-3d : %02x %s\n", 26, spd->clk_access3, + " spd->clk_access3, * 26 Max Access from Clock at CL=X-2 *"); + printf("%-3d : %02x %s\n", 27, spd->trp, + " spd->trp, * 27 Min Row Precharge Time (tRP)*"); + printf("%-3d : %02x %s\n", 28, spd->trrd, + " spd->trrd, * 28 Min Row Active to Row Active (tRRD) *"); + printf("%-3d : %02x %s\n", 29, spd->trcd, + " spd->trcd, * 29 Min RAS to CAS Delay (tRCD) *"); + printf("%-3d : %02x %s\n", 30, spd->tras, + " spd->tras, * 30 Minimum RAS Pulse Width (tRAS) *"); + printf("%-3d : %02x %s\n", 31, spd->bank_dens, + " spd->bank_dens, * 31 Density of each bank on module *"); + printf("%-3d : %02x %s\n", 32, spd->ca_setup, + " spd->ca_setup, * 32 Cmd + Addr signal input setup time *"); + printf("%-3d : %02x %s\n", 33, spd->ca_hold, + " spd->ca_hold, * 33 Cmd and Addr signal input hold time *"); + printf("%-3d : %02x %s\n", 34, spd->data_setup, + " spd->data_setup, * 34 Data signal input setup time *"); + printf("%-3d : %02x %s\n", 35, spd->data_hold, + " spd->data_hold, * 35 Data signal input hold time *"); + printf("%-3d : %02x %s\n", 36, spd->res_36_40[0], + " spd->res_36_40[0], * 36 Reserved / tWR *"); + printf("%-3d : %02x %s\n", 37, spd->res_36_40[1], + " spd->res_36_40[1], * 37 Reserved / tWTR *"); + printf("%-3d : %02x %s\n", 38, spd->res_36_40[2], + " spd->res_36_40[2], * 38 Reserved / tRTP *"); + printf("%-3d : %02x %s\n", 39, spd->res_36_40[3], + " spd->res_36_40[3], * 39 Reserved / mem_probe *"); + printf("%-3d : %02x %s\n", 40, spd->res_36_40[4], + " spd->res_36_40[4], * 40 Reserved / trc,trfc extensions *"); + printf("%-3d : %02x %s\n", 41, spd->trc, + " spd->trc, * 41 Min Active to Auto refresh time tRC *"); + printf("%-3d : %02x %s\n", 42, spd->trfc, + " spd->trfc, * 42 Min Auto to Active period tRFC *"); + printf("%-3d : %02x %s\n", 43, spd->tckmax, + " spd->tckmax, * 43 Max device cycle time tCKmax *"); + printf("%-3d : %02x %s\n", 44, spd->tdqsq, + " spd->tdqsq, * 44 Max DQS to DQ skew *"); + printf("%-3d : %02x %s\n", 45, spd->tqhs, + " spd->tqhs, * 45 Max Read DataHold skew tQHS *"); + printf("%-3d : %02x %s\n", 46, spd->res_46, + " spd->res_46, * 46 Reserved/ PLL Relock time *"); + printf("%-3d : %02x %s\n", 47, spd->dimm_height, + " spd->dimm_height * 47 SDRAM DIMM Height *"); + + printf("%-3d-%3d: ", 48, 61); + + for (i = 0; i < 14; i++) + printf("%02x", spd->res_48_61[i]); + + printf(" * 48-61 IDD in SPD and Reserved space *\n"); + + printf("%-3d : %02x %s\n", 62, spd->spd_rev, + " spd->spd_rev, * 62 SPD Data Revision Code *"); + printf("%-3d : %02x %s\n", 63, spd->cksum, + " spd->cksum, * 63 Checksum for bytes 0-62 *"); + printf("%-3d-%3d: ", 64, 71); + + for (i = 0; i < 8; i++) + printf("%02x", spd->mid[i]); + + printf("* 64 Mfr's JEDEC ID code per JEP-108E *\n"); + printf("%-3d : %02x %s\n", 72, spd->mloc, + " spd->mloc, * 72 Manufacturing Location *"); + + printf("%-3d-%3d: >>", 73, 90); + + for (i = 0; i < 18; i++) + printf("%c", spd->mpart[i]); + + printf("<<* 73 Manufacturer's Part Number *\n"); + + printf("%-3d-%3d: %02x %02x %s\n", 91, 92, spd->rev[0], spd->rev[1], + "* 91 Revision Code *"); + printf("%-3d-%3d: %02x %02x %s\n", 93, 94, spd->mdate[0], spd->mdate[1], + "* 93 Manufacturing Date *"); + printf("%-3d-%3d: ", 95, 98); + + for (i = 0; i < 4; i++) + printf("%02x", spd->sernum[i]); + + printf("* 95 Assembly Serial Number *\n"); + + printf("%-3d-%3d: ", 99, 127); + + for (i = 0; i < 27; i++) + printf("%02x", spd->mspec[i]); + + printf("* 99 Manufacturer Specific Data *\n"); +} +#endif + +#ifdef CONFIG_SYS_FSL_DDR2 +void ddr2_spd_dump(const ddr2_spd_eeprom_t *spd) +{ + unsigned int i; + + printf("%-3d : %02x %s\n", 0, spd->info_size, + " spd->info_size, * 0 # bytes written into serial memory *"); + printf("%-3d : %02x %s\n", 1, spd->chip_size, + " spd->chip_size, * 1 Total # bytes of SPD memory device *"); + printf("%-3d : %02x %s\n", 2, spd->mem_type, + " spd->mem_type, * 2 Fundamental memory type *"); + printf("%-3d : %02x %s\n", 3, spd->nrow_addr, + " spd->nrow_addr, * 3 # of Row Addresses on this assembly *"); + printf("%-3d : %02x %s\n", 4, spd->ncol_addr, + " spd->ncol_addr, * 4 # of Column Addrs on this assembly *"); + printf("%-3d : %02x %s\n", 5, spd->mod_ranks, + " spd->mod_ranks * 5 # of Module Rows on this assembly *"); + printf("%-3d : %02x %s\n", 6, spd->dataw, + " spd->dataw, * 6 Data Width of this assembly *"); + printf("%-3d : %02x %s\n", 7, spd->res_7, + " spd->res_7, * 7 Reserved *"); + printf("%-3d : %02x %s\n", 8, spd->voltage, + " spd->voltage, * 8 Voltage intf std of this assembly *"); + printf("%-3d : %02x %s\n", 9, spd->clk_cycle, + " spd->clk_cycle, * 9 SDRAM Cycle time at CL=X *"); + printf("%-3d : %02x %s\n", 10, spd->clk_access, + " spd->clk_access, * 10 SDRAM Access from Clock at CL=X *"); + printf("%-3d : %02x %s\n", 11, spd->config, + " spd->config, * 11 DIMM Configuration type *"); + printf("%-3d : %02x %s\n", 12, spd->refresh, + " spd->refresh, * 12 Refresh Rate/Type *"); + printf("%-3d : %02x %s\n", 13, spd->primw, + " spd->primw, * 13 Primary SDRAM Width *"); + printf("%-3d : %02x %s\n", 14, spd->ecw, + " spd->ecw, * 14 Error Checking SDRAM width *"); + printf("%-3d : %02x %s\n", 15, spd->res_15, + " spd->res_15, * 15 Reserved *"); + printf("%-3d : %02x %s\n", 16, spd->burstl, + " spd->burstl, * 16 Burst Lengths Supported *"); + printf("%-3d : %02x %s\n", 17, spd->nbanks, + " spd->nbanks, * 17 # of Banks on Each SDRAM Device *"); + printf("%-3d : %02x %s\n", 18, spd->cas_lat, + " spd->cas_lat, * 18 CAS# Latencies Supported *"); + printf("%-3d : %02x %s\n", 19, spd->mech_char, + " spd->mech_char, * 19 Mechanical Characteristics *"); + printf("%-3d : %02x %s\n", 20, spd->dimm_type, + " spd->dimm_type, * 20 DIMM type *"); + printf("%-3d : %02x %s\n", 21, spd->mod_attr, + " spd->mod_attr, * 21 SDRAM Module Attributes *"); + printf("%-3d : %02x %s\n", 22, spd->dev_attr, + " spd->dev_attr, * 22 SDRAM Device Attributes *"); + printf("%-3d : %02x %s\n", 23, spd->clk_cycle2, + " spd->clk_cycle2, * 23 Min SDRAM Cycle time at CL=X-1 *"); + printf("%-3d : %02x %s\n", 24, spd->clk_access2, + " spd->clk_access2, * 24 SDRAM Access from Clock at CL=X-1 *"); + printf("%-3d : %02x %s\n", 25, spd->clk_cycle3, + " spd->clk_cycle3, * 25 Min SDRAM Cycle time at CL=X-2 *"); + printf("%-3d : %02x %s\n", 26, spd->clk_access3, + " spd->clk_access3, * 26 Max Access from Clock at CL=X-2 *"); + printf("%-3d : %02x %s\n", 27, spd->trp, + " spd->trp, * 27 Min Row Precharge Time (tRP)*"); + printf("%-3d : %02x %s\n", 28, spd->trrd, + " spd->trrd, * 28 Min Row Active to Row Active (tRRD) *"); + printf("%-3d : %02x %s\n", 29, spd->trcd, + " spd->trcd, * 29 Min RAS to CAS Delay (tRCD) *"); + printf("%-3d : %02x %s\n", 30, spd->tras, + " spd->tras, * 30 Minimum RAS Pulse Width (tRAS) *"); + printf("%-3d : %02x %s\n", 31, spd->rank_dens, + " spd->rank_dens, * 31 Density of each rank on module *"); + printf("%-3d : %02x %s\n", 32, spd->ca_setup, + " spd->ca_setup, * 32 Cmd + Addr signal input setup time *"); + printf("%-3d : %02x %s\n", 33, spd->ca_hold, + " spd->ca_hold, * 33 Cmd and Addr signal input hold time *"); + printf("%-3d : %02x %s\n", 34, spd->data_setup, + " spd->data_setup, * 34 Data signal input setup time *"); + printf("%-3d : %02x %s\n", 35, spd->data_hold, + " spd->data_hold, * 35 Data signal input hold time *"); + printf("%-3d : %02x %s\n", 36, spd->twr, + " spd->twr, * 36 Write Recovery time tWR *"); + printf("%-3d : %02x %s\n", 37, spd->twtr, + " spd->twtr, * 37 Int write to read delay tWTR *"); + printf("%-3d : %02x %s\n", 38, spd->trtp, + " spd->trtp, * 38 Int read to precharge delay tRTP *"); + printf("%-3d : %02x %s\n", 39, spd->mem_probe, + " spd->mem_probe, * 39 Mem analysis probe characteristics *"); + printf("%-3d : %02x %s\n", 40, spd->trctrfc_ext, + " spd->trctrfc_ext, * 40 Extensions to trc and trfc *"); + printf("%-3d : %02x %s\n", 41, spd->trc, + " spd->trc, * 41 Min Active to Auto refresh time tRC *"); + printf("%-3d : %02x %s\n", 42, spd->trfc, + " spd->trfc, * 42 Min Auto to Active period tRFC *"); + printf("%-3d : %02x %s\n", 43, spd->tckmax, + " spd->tckmax, * 43 Max device cycle time tCKmax *"); + printf("%-3d : %02x %s\n", 44, spd->tdqsq, + " spd->tdqsq, * 44 Max DQS to DQ skew *"); + printf("%-3d : %02x %s\n", 45, spd->tqhs, + " spd->tqhs, * 45 Max Read DataHold skew tQHS *"); + printf("%-3d : %02x %s\n", 46, spd->pll_relock, + " spd->pll_relock, * 46 PLL Relock time *"); + printf("%-3d : %02x %s\n", 47, spd->t_casemax, + " spd->t_casemax, * 47 t_casemax *"); + printf("%-3d : %02x %s\n", 48, spd->psi_ta_dram, + " spd->psi_ta_dram, * 48 Thermal Resistance of DRAM Package " + "from Top (Case) to Ambient (Psi T-A DRAM) *"); + printf("%-3d : %02x %s\n", 49, spd->dt0_mode, + " spd->dt0_mode, * 49 DRAM Case Temperature Rise from " + "Ambient due to Activate-Precharge/Mode Bits " + "(DT0/Mode Bits) *)"); + printf("%-3d : %02x %s\n", 50, spd->dt2n_dt2q, + " spd->dt2n_dt2q, * 50 DRAM Case Temperature Rise from " + "Ambient due to Precharge/Quiet Standby " + "(DT2N/DT2Q) *"); + printf("%-3d : %02x %s\n", 51, spd->dt2p, + " spd->dt2p, * 51 DRAM Case Temperature Rise from " + "Ambient due to Precharge Power-Down (DT2P) *"); + printf("%-3d : %02x %s\n", 52, spd->dt3n, + " spd->dt3n, * 52 DRAM Case Temperature Rise from " + "Ambient due to Active Standby (DT3N) *"); + printf("%-3d : %02x %s\n", 53, spd->dt3pfast, + " spd->dt3pfast, * 53 DRAM Case Temperature Rise from " + "Ambient due to Active Power-Down with Fast PDN Exit " + "(DT3Pfast) *"); + printf("%-3d : %02x %s\n", 54, spd->dt3pslow, + " spd->dt3pslow, * 54 DRAM Case Temperature Rise from " + "Ambient due to Active Power-Down with Slow PDN Exit " + "(DT3Pslow) *"); + printf("%-3d : %02x %s\n", 55, spd->dt4r_dt4r4w, + " spd->dt4r_dt4r4w, * 55 DRAM Case Temperature Rise from " + "Ambient due to Page Open Burst Read/DT4R4W Mode Bit " + "(DT4R/DT4R4W Mode Bit) *"); + printf("%-3d : %02x %s\n", 56, spd->dt5b, + " spd->dt5b, * 56 DRAM Case Temperature Rise from " + "Ambient due to Burst Refresh (DT5B) *"); + printf("%-3d : %02x %s\n", 57, spd->dt7, + " spd->dt7, * 57 DRAM Case Temperature Rise from " + "Ambient due to Bank Interleave Reads with " + "Auto-Precharge (DT7) *"); + printf("%-3d : %02x %s\n", 58, spd->psi_ta_pll, + " spd->psi_ta_pll, * 58 Thermal Resistance of PLL Package form" + " Top (Case) to Ambient (Psi T-A PLL) *"); + printf("%-3d : %02x %s\n", 59, spd->psi_ta_reg, + " spd->psi_ta_reg, * 59 Thermal Reisitance of Register Package" + " from Top (Case) to Ambient (Psi T-A Register) *"); + printf("%-3d : %02x %s\n", 60, spd->dtpllactive, + " spd->dtpllactive, * 60 PLL Case Temperature Rise from " + "Ambient due to PLL Active (DT PLL Active) *"); + printf("%-3d : %02x %s\n", 61, spd->dtregact, + " spd->dtregact, " + "* 61 Register Case Temperature Rise from Ambient due to " + "Register Active/Mode Bit (DT Register Active/Mode Bit) *"); + printf("%-3d : %02x %s\n", 62, spd->spd_rev, + " spd->spd_rev, * 62 SPD Data Revision Code *"); + printf("%-3d : %02x %s\n", 63, spd->cksum, + " spd->cksum, * 63 Checksum for bytes 0-62 *"); + + printf("%-3d-%3d: ", 64, 71); + + for (i = 0; i < 8; i++) + printf("%02x", spd->mid[i]); + + printf("* 64 Mfr's JEDEC ID code per JEP-108E *\n"); + + printf("%-3d : %02x %s\n", 72, spd->mloc, + " spd->mloc, * 72 Manufacturing Location *"); + + printf("%-3d-%3d: >>", 73, 90); + for (i = 0; i < 18; i++) + printf("%c", spd->mpart[i]); + + + printf("<<* 73 Manufacturer's Part Number *\n"); + + printf("%-3d-%3d: %02x %02x %s\n", 91, 92, spd->rev[0], spd->rev[1], + "* 91 Revision Code *"); + printf("%-3d-%3d: %02x %02x %s\n", 93, 94, spd->mdate[0], spd->mdate[1], + "* 93 Manufacturing Date *"); + printf("%-3d-%3d: ", 95, 98); + + for (i = 0; i < 4; i++) + printf("%02x", spd->sernum[i]); + + printf("* 95 Assembly Serial Number *\n"); + + printf("%-3d-%3d: ", 99, 127); + for (i = 0; i < 27; i++) + printf("%02x", spd->mspec[i]); + + + printf("* 99 Manufacturer Specific Data *\n"); +} +#endif + +#ifdef CONFIG_SYS_FSL_DDR3 +void ddr3_spd_dump(const ddr3_spd_eeprom_t *spd) +{ + unsigned int i; + + /* General Section: Bytes 0-59 */ + +#define PRINT_NXS(x, y, z...) printf("%-3d : %02x " z "\n", x, (u8)y); +#define PRINT_NNXXS(n0, n1, x0, x1, s) \ + printf("%-3d-%3d: %02x %02x " s "\n", n0, n1, x0, x1); + + PRINT_NXS(0, spd->info_size_crc, + "info_size_crc bytes written into serial memory, " + "CRC coverage"); + PRINT_NXS(1, spd->spd_rev, + "spd_rev SPD Revision"); + PRINT_NXS(2, spd->mem_type, + "mem_type Key Byte / DRAM Device Type"); + PRINT_NXS(3, spd->module_type, + "module_type Key Byte / Module Type"); + PRINT_NXS(4, spd->density_banks, + "density_banks SDRAM Density and Banks"); + PRINT_NXS(5, spd->addressing, + "addressing SDRAM Addressing"); + PRINT_NXS(6, spd->module_vdd, + "module_vdd Module Nominal Voltage, VDD"); + PRINT_NXS(7, spd->organization, + "organization Module Organization"); + PRINT_NXS(8, spd->bus_width, + "bus_width Module Memory Bus Width"); + PRINT_NXS(9, spd->ftb_div, + "ftb_div Fine Timebase (FTB) Dividend / Divisor"); + PRINT_NXS(10, spd->mtb_dividend, + "mtb_dividend Medium Timebase (MTB) Dividend"); + PRINT_NXS(11, spd->mtb_divisor, + "mtb_divisor Medium Timebase (MTB) Divisor"); + PRINT_NXS(12, spd->tck_min, + "tck_min SDRAM Minimum Cycle Time"); + PRINT_NXS(13, spd->res_13, + "res_13 Reserved"); + PRINT_NXS(14, spd->caslat_lsb, + "caslat_lsb CAS Latencies Supported, LSB"); + PRINT_NXS(15, spd->caslat_msb, + "caslat_msb CAS Latencies Supported, MSB"); + PRINT_NXS(16, spd->taa_min, + "taa_min Min CAS Latency Time"); + PRINT_NXS(17, spd->twr_min, + "twr_min Min Write REcovery Time"); + PRINT_NXS(18, spd->trcd_min, + "trcd_min Min RAS# to CAS# Delay Time"); + PRINT_NXS(19, spd->trrd_min, + "trrd_min Min Row Active to Row Active Delay Time"); + PRINT_NXS(20, spd->trp_min, + "trp_min Min Row Precharge Delay Time"); + PRINT_NXS(21, spd->tras_trc_ext, + "tras_trc_ext Upper Nibbles for tRAS and tRC"); + PRINT_NXS(22, spd->tras_min_lsb, + "tras_min_lsb Min Active to Precharge Delay Time, LSB"); + PRINT_NXS(23, spd->trc_min_lsb, + "trc_min_lsb Min Active to Active/Refresh Delay Time, LSB"); + PRINT_NXS(24, spd->trfc_min_lsb, + "trfc_min_lsb Min Refresh Recovery Delay Time LSB"); + PRINT_NXS(25, spd->trfc_min_msb, + "trfc_min_msb Min Refresh Recovery Delay Time MSB"); + PRINT_NXS(26, spd->twtr_min, + "twtr_min Min Internal Write to Read Command Delay Time"); + PRINT_NXS(27, spd->trtp_min, + "trtp_min " + "Min Internal Read to Precharge Command Delay Time"); + PRINT_NXS(28, spd->tfaw_msb, + "tfaw_msb Upper Nibble for tFAW"); + PRINT_NXS(29, spd->tfaw_min, + "tfaw_min Min Four Activate Window Delay Time"); + PRINT_NXS(30, spd->opt_features, + "opt_features SDRAM Optional Features"); + PRINT_NXS(31, spd->therm_ref_opt, + "therm_ref_opt SDRAM Thermal and Refresh Opts"); + PRINT_NXS(32, spd->therm_sensor, + "therm_sensor SDRAM Thermal Sensor"); + PRINT_NXS(33, spd->device_type, + "device_type SDRAM Device Type"); + PRINT_NXS(34, spd->fine_tck_min, + "fine_tck_min Fine offset for tCKmin"); + PRINT_NXS(35, spd->fine_taa_min, + "fine_taa_min Fine offset for tAAmin"); + PRINT_NXS(36, spd->fine_trcd_min, + "fine_trcd_min Fine offset for tRCDmin"); + PRINT_NXS(37, spd->fine_trp_min, + "fine_trp_min Fine offset for tRPmin"); + PRINT_NXS(38, spd->fine_trc_min, + "fine_trc_min Fine offset for tRCmin"); + + printf("%-3d-%3d: ", 39, 59); /* Reserved, General Section */ + + for (i = 39; i <= 59; i++) + printf("%02x ", spd->res_39_59[i - 39]); + + puts("\n"); + + switch (spd->module_type) { + case 0x02: /* UDIMM */ + case 0x03: /* SO-DIMM */ + case 0x04: /* Micro-DIMM */ + case 0x06: /* Mini-UDIMM */ + PRINT_NXS(60, spd->mod_section.unbuffered.mod_height, + "mod_height (Unbuffered) Module Nominal Height"); + PRINT_NXS(61, spd->mod_section.unbuffered.mod_thickness, + "mod_thickness (Unbuffered) Module Maximum Thickness"); + PRINT_NXS(62, spd->mod_section.unbuffered.ref_raw_card, + "ref_raw_card (Unbuffered) Reference Raw Card Used"); + PRINT_NXS(63, spd->mod_section.unbuffered.addr_mapping, + "addr_mapping (Unbuffered) Address mapping from " + "Edge Connector to DRAM"); + break; + case 0x01: /* RDIMM */ + case 0x05: /* Mini-RDIMM */ + PRINT_NXS(60, spd->mod_section.registered.mod_height, + "mod_height (Registered) Module Nominal Height"); + PRINT_NXS(61, spd->mod_section.registered.mod_thickness, + "mod_thickness (Registered) Module Maximum Thickness"); + PRINT_NXS(62, spd->mod_section.registered.ref_raw_card, + "ref_raw_card (Registered) Reference Raw Card Used"); + PRINT_NXS(63, spd->mod_section.registered.modu_attr, + "modu_attr (Registered) DIMM Module Attributes"); + PRINT_NXS(64, spd->mod_section.registered.thermal, + "thermal (Registered) Thermal Heat " + "Spreader Solution"); + PRINT_NXS(65, spd->mod_section.registered.reg_id_lo, + "reg_id_lo (Registered) Register Manufacturer ID " + "Code, LSB"); + PRINT_NXS(66, spd->mod_section.registered.reg_id_hi, + "reg_id_hi (Registered) Register Manufacturer ID " + "Code, MSB"); + PRINT_NXS(67, spd->mod_section.registered.reg_rev, + "reg_rev (Registered) Register " + "Revision Number"); + PRINT_NXS(68, spd->mod_section.registered.reg_type, + "reg_type (Registered) Register Type"); + for (i = 69; i <= 76; i++) { + printf("%-3d : %02x rcw[%d]\n", i, + spd->mod_section.registered.rcw[i-69], i-69); + } + break; + default: + /* Module-specific Section, Unsupported Module Type */ + printf("%-3d-%3d: ", 60, 116); + + for (i = 60; i <= 116; i++) + printf("%02x", spd->mod_section.uc[i - 60]); + + break; + } + + /* Unique Module ID: Bytes 117-125 */ + PRINT_NXS(117, spd->mmid_lsb, "Module MfgID Code LSB - JEP-106"); + PRINT_NXS(118, spd->mmid_msb, "Module MfgID Code MSB - JEP-106"); + PRINT_NXS(119, spd->mloc, "Mfg Location"); + PRINT_NNXXS(120, 121, spd->mdate[0], spd->mdate[1], "Mfg Date"); + + printf("%-3d-%3d: ", 122, 125); + + for (i = 122; i <= 125; i++) + printf("%02x ", spd->sernum[i - 122]); + printf(" Module Serial Number\n"); + + /* CRC: Bytes 126-127 */ + PRINT_NNXXS(126, 127, spd->crc[0], spd->crc[1], " SPD CRC"); + + /* Other Manufacturer Fields and User Space: Bytes 128-255 */ + printf("%-3d-%3d: ", 128, 145); + for (i = 128; i <= 145; i++) + printf("%02x ", spd->mpart[i - 128]); + printf(" Mfg's Module Part Number\n"); + + PRINT_NNXXS(146, 147, spd->mrev[0], spd->mrev[1], + "Module Revision code"); + + PRINT_NXS(148, spd->dmid_lsb, "DRAM MfgID Code LSB - JEP-106"); + PRINT_NXS(149, spd->dmid_msb, "DRAM MfgID Code MSB - JEP-106"); + + printf("%-3d-%3d: ", 150, 175); + for (i = 150; i <= 175; i++) + printf("%02x ", spd->msd[i - 150]); + printf(" Mfg's Specific Data\n"); + + printf("%-3d-%3d: ", 176, 255); + for (i = 176; i <= 255; i++) + printf("%02x", spd->cust[i - 176]); + printf(" Mfg's Specific Data\n"); + +} +#endif + +static inline void generic_spd_dump(const generic_spd_eeprom_t *spd) +{ +#if defined(CONFIG_SYS_FSL_DDR1) + ddr1_spd_dump(spd); +#elif defined(CONFIG_SYS_FSL_DDR2) + ddr2_spd_dump(spd); +#elif defined(CONFIG_SYS_FSL_DDR3) + ddr3_spd_dump(spd); +#endif +} + +static void fsl_ddr_printinfo(const fsl_ddr_info_t *pinfo, + unsigned int ctrl_mask, + unsigned int dimm_mask, + unsigned int do_mask) +{ + unsigned int i, j, retval; + + /* STEP 1: DIMM SPD data */ + if (do_mask & STEP_GET_SPD) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (!(ctrl_mask & (1 << i))) + continue; + + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + if (!(dimm_mask & (1 << j))) + continue; + + printf("SPD info: Controller=%u " + "DIMM=%u\n", i, j); + generic_spd_dump( + &(pinfo->spd_installed_dimms[i][j])); + printf("\n"); + } + printf("\n"); + } + printf("\n"); + } + + /* STEP 2: DIMM Parameters */ + if (do_mask & STEP_COMPUTE_DIMM_PARMS) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (!(ctrl_mask & (1 << i))) + continue; + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + if (!(dimm_mask & (1 << j))) + continue; + printf("DIMM parameters: Controller=%u " + "DIMM=%u\n", i, j); + print_dimm_parameters( + &(pinfo->dimm_params[i][j])); + printf("\n"); + } + printf("\n"); + } + printf("\n"); + } + + /* STEP 3: Common Parameters */ + if (do_mask & STEP_COMPUTE_COMMON_PARMS) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (!(ctrl_mask & (1 << i))) + continue; + printf("\"lowest common\" DIMM parameters: " + "Controller=%u\n", i); + print_lowest_common_dimm_parameters( + &pinfo->common_timing_params[i]); + printf("\n"); + } + printf("\n"); + } + + /* STEP 4: User Configuration Options */ + if (do_mask & STEP_GATHER_OPTS) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (!(ctrl_mask & (1 << i))) + continue; + printf("User Config Options: Controller=%u\n", i); + print_memctl_options(&pinfo->memctl_opts[i]); + printf("\n"); + } + printf("\n"); + } + + /* STEP 5: Address assignment */ + if (do_mask & STEP_ASSIGN_ADDRESSES) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (!(ctrl_mask & (1 << i))) + continue; + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + printf("Address Assignment: Controller=%u " + "DIMM=%u\n", i, j); + printf("Don't have this functionality yet\n"); + } + printf("\n"); + } + printf("\n"); + } + + /* STEP 6: computed controller register values */ + if (do_mask & STEP_COMPUTE_REGS) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (!(ctrl_mask & (1 << i))) + continue; + printf("Computed Register Values: Controller=%u\n", i); + print_fsl_memctl_config_regs( + &pinfo->fsl_ddr_config_reg[i]); + retval = check_fsl_memctl_config_regs( + &pinfo->fsl_ddr_config_reg[i]); + if (retval) { + printf("check_fsl_memctl_config_regs " + "result = %u\n", retval); + } + printf("\n"); + } + printf("\n"); + } +} + +struct data_strings { + const char *data_name; + unsigned int step_mask; + unsigned int dimm_number_required; +}; + +#define DATA_OPTIONS(name, step, dimm) {#name, step, dimm} + +static unsigned int fsl_ddr_parse_interactive_cmd( + char **argv, + int argc, + unsigned int *pstep_mask, + unsigned int *pctlr_mask, + unsigned int *pdimm_mask, + unsigned int *pdimm_number_required + ) { + + static const struct data_strings options[] = { + DATA_OPTIONS(spd, STEP_GET_SPD, 1), + DATA_OPTIONS(dimmparms, STEP_COMPUTE_DIMM_PARMS, 1), + DATA_OPTIONS(commonparms, STEP_COMPUTE_COMMON_PARMS, 0), + DATA_OPTIONS(opts, STEP_GATHER_OPTS, 0), + DATA_OPTIONS(addresses, STEP_ASSIGN_ADDRESSES, 0), + DATA_OPTIONS(regs, STEP_COMPUTE_REGS, 0), + }; + static const unsigned int n_opts = ARRAY_SIZE(options); + + unsigned int i, j; + unsigned int error = 0; + + for (i = 1; i < argc; i++) { + unsigned int matched = 0; + + for (j = 0; j < n_opts; j++) { + if (strcmp(options[j].data_name, argv[i]) != 0) + continue; + *pstep_mask |= options[j].step_mask; + *pdimm_number_required = + options[j].dimm_number_required; + matched = 1; + break; + } + + if (matched) + continue; + + if (argv[i][0] == 'c') { + char c = argv[i][1]; + if (isdigit(c)) + *pctlr_mask |= 1 << (c - '0'); + continue; + } + + if (argv[i][0] == 'd') { + char c = argv[i][1]; + if (isdigit(c)) + *pdimm_mask |= 1 << (c - '0'); + continue; + } + + printf("unknown arg %s\n", argv[i]); + *pstep_mask = 0; + error = 1; + break; + } + + return error; +} + +int fsl_ddr_interactive_env_var_exists(void) +{ + char buffer[CONFIG_SYS_CBSIZE]; + + if (getenv_f("ddr_interactive", buffer, CONFIG_SYS_CBSIZE) >= 0) + return 1; + + return 0; +} + +unsigned long long fsl_ddr_interactive(fsl_ddr_info_t *pinfo, int var_is_set) +{ + unsigned long long ddrsize; + const char *prompt = "FSL DDR>"; + char buffer[CONFIG_SYS_CBSIZE]; + char buffer2[CONFIG_SYS_CBSIZE]; + char *p = NULL; + char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */ + int argc; + unsigned int next_step = STEP_GET_SPD; + const char *usage = { + "commands:\n" + "print print SPD and intermediate computed data\n" + "reset reboot machine\n" + "recompute reload SPD and options to default and recompute regs\n" + "edit modify spd, parameter, or option\n" + "compute recompute registers from current next_step to end\n" + "copy copy parameters\n" + "next_step shows current next_step\n" + "help this message\n" + "go program the memory controller and continue with u-boot\n" + }; + + if (var_is_set) { + if (getenv_f("ddr_interactive", buffer2, CONFIG_SYS_CBSIZE) > 0) { + p = buffer2; + } else { + var_is_set = 0; + } + } + + /* + * The strategy for next_step is that it points to the next + * step in the computation process that needs to be done. + */ + while (1) { + if (var_is_set) { + char *pend = strchr(p, ';'); + if (pend) { + /* found command separator, copy sub-command */ + *pend = '\0'; + strcpy(buffer, p); + p = pend + 1; + } else { + /* separator not found, copy whole string */ + strcpy(buffer, p); + p = NULL; + var_is_set = 0; + } + } else { + /* + * No need to worry for buffer overflow here in + * this function; readline() maxes out at CFG_CBSIZE + */ + readline_into_buffer(prompt, buffer, 0); + } + argc = parse_line(buffer, argv); + if (argc == 0) + continue; + + + if (strcmp(argv[0], "help") == 0) { + puts(usage); + continue; + } + + if (strcmp(argv[0], "next_step") == 0) { + printf("next_step = 0x%02X (%s)\n", + next_step, + step_to_string(next_step)); + continue; + } + + if (strcmp(argv[0], "copy") == 0) { + unsigned int error = 0; + unsigned int step_mask = 0; + unsigned int src_ctlr_mask = 0; + unsigned int src_dimm_mask = 0; + unsigned int dimm_number_required = 0; + unsigned int src_ctlr_num = 0; + unsigned int src_dimm_num = 0; + unsigned int dst_ctlr_num = -1; + unsigned int dst_dimm_num = -1; + unsigned int i, num_dest_parms; + + if (argc == 1) { + printf("copy \n"); + continue; + } + + error = fsl_ddr_parse_interactive_cmd( + argv, argc, + &step_mask, + &src_ctlr_mask, + &src_dimm_mask, + &dimm_number_required + ); + + /* XXX: only dimm_number_required and step_mask will + be used by this function. Parse the controller and + DIMM number separately because it is easier. */ + + if (error) + continue; + + /* parse source destination controller / DIMM */ + + num_dest_parms = dimm_number_required ? 2 : 1; + + for (i = 0; i < argc; i++) { + if (argv[i][0] == 'c') { + char c = argv[i][1]; + if (isdigit(c)) { + src_ctlr_num = (c - '0'); + break; + } + } + } + + for (i = 0; i < argc; i++) { + if (argv[i][0] == 'd') { + char c = argv[i][1]; + if (isdigit(c)) { + src_dimm_num = (c - '0'); + break; + } + } + } + + /* parse destination controller / DIMM */ + + for (i = argc - 1; i >= argc - num_dest_parms; i--) { + if (argv[i][0] == 'c') { + char c = argv[i][1]; + if (isdigit(c)) { + dst_ctlr_num = (c - '0'); + break; + } + } + } + + for (i = argc - 1; i >= argc - num_dest_parms; i--) { + if (argv[i][0] == 'd') { + char c = argv[i][1]; + if (isdigit(c)) { + dst_dimm_num = (c - '0'); + break; + } + } + } + + /* TODO: validate inputs */ + + debug("src_ctlr_num = %u, src_dimm_num = %u, dst_ctlr_num = %u, dst_dimm_num = %u, step_mask = %x\n", + src_ctlr_num, src_dimm_num, dst_ctlr_num, dst_dimm_num, step_mask); + + + switch (step_mask) { + + case STEP_GET_SPD: + memcpy(&(pinfo->spd_installed_dimms[dst_ctlr_num][dst_dimm_num]), + &(pinfo->spd_installed_dimms[src_ctlr_num][src_dimm_num]), + sizeof(pinfo->spd_installed_dimms[0][0])); + break; + + case STEP_COMPUTE_DIMM_PARMS: + memcpy(&(pinfo->dimm_params[dst_ctlr_num][dst_dimm_num]), + &(pinfo->dimm_params[src_ctlr_num][src_dimm_num]), + sizeof(pinfo->dimm_params[0][0])); + break; + + case STEP_COMPUTE_COMMON_PARMS: + memcpy(&(pinfo->common_timing_params[dst_ctlr_num]), + &(pinfo->common_timing_params[src_ctlr_num]), + sizeof(pinfo->common_timing_params[0])); + break; + + case STEP_GATHER_OPTS: + memcpy(&(pinfo->memctl_opts[dst_ctlr_num]), + &(pinfo->memctl_opts[src_ctlr_num]), + sizeof(pinfo->memctl_opts[0])); + break; + + /* someday be able to have addresses to copy addresses... */ + + case STEP_COMPUTE_REGS: + memcpy(&(pinfo->fsl_ddr_config_reg[dst_ctlr_num]), + &(pinfo->fsl_ddr_config_reg[src_ctlr_num]), + sizeof(pinfo->memctl_opts[0])); + break; + + default: + printf("unexpected step_mask value\n"); + } + + continue; + + } + + if (strcmp(argv[0], "edit") == 0) { + unsigned int error = 0; + unsigned int step_mask = 0; + unsigned int ctlr_mask = 0; + unsigned int dimm_mask = 0; + char *p_element = NULL; + char *p_value = NULL; + unsigned int dimm_number_required = 0; + unsigned int ctrl_num; + unsigned int dimm_num; + + if (argc == 1) { + /* Only the element and value must be last */ + printf("edit " + " \n"); + printf("for spd, specify byte number for " + "element\n"); + continue; + } + + error = fsl_ddr_parse_interactive_cmd( + argv, argc - 2, + &step_mask, + &ctlr_mask, + &dimm_mask, + &dimm_number_required + ); + + if (error) + continue; + + + /* Check arguments */ + + /* ERROR: If no steps were found */ + if (step_mask == 0) { + printf("Error: No valid steps were specified " + "in argument.\n"); + continue; + } + + /* ERROR: If multiple steps were found */ + if (step_mask & (step_mask - 1)) { + printf("Error: Multiple steps specified in " + "argument.\n"); + continue; + } + + /* ERROR: Controller not specified */ + if (ctlr_mask == 0) { + printf("Error: controller number not " + "specified or no element and " + "value specified\n"); + continue; + } + + if (ctlr_mask & (ctlr_mask - 1)) { + printf("Error: multiple controllers " + "specified, %X\n", ctlr_mask); + continue; + } + + /* ERROR: DIMM number not specified */ + if (dimm_number_required && dimm_mask == 0) { + printf("Error: DIMM number number not " + "specified or no element and " + "value specified\n"); + continue; + } + + if (dimm_mask & (dimm_mask - 1)) { + printf("Error: multipled DIMMs specified\n"); + continue; + } + + p_element = argv[argc - 2]; + p_value = argv[argc - 1]; + + ctrl_num = __ilog2(ctlr_mask); + dimm_num = __ilog2(dimm_mask); + + switch (step_mask) { + case STEP_GET_SPD: + { + unsigned int element_num; + unsigned int value; + + element_num = simple_strtoul(p_element, + NULL, 0); + value = simple_strtoul(p_value, + NULL, 0); + fsl_ddr_spd_edit(pinfo, + ctrl_num, + dimm_num, + element_num, + value); + next_step = STEP_COMPUTE_DIMM_PARMS; + } + break; + + case STEP_COMPUTE_DIMM_PARMS: + fsl_ddr_dimm_parameters_edit( + pinfo, ctrl_num, dimm_num, + p_element, p_value); + next_step = STEP_COMPUTE_COMMON_PARMS; + break; + + case STEP_COMPUTE_COMMON_PARMS: + lowest_common_dimm_parameters_edit(pinfo, + ctrl_num, p_element, p_value); + next_step = STEP_GATHER_OPTS; + break; + + case STEP_GATHER_OPTS: + fsl_ddr_options_edit(pinfo, ctrl_num, + p_element, p_value); + next_step = STEP_ASSIGN_ADDRESSES; + break; + + case STEP_ASSIGN_ADDRESSES: + printf("editing of address assignment " + "not yet implemented\n"); + break; + + case STEP_COMPUTE_REGS: + { + fsl_ddr_regs_edit(pinfo, + ctrl_num, + p_element, + p_value); + next_step = STEP_PROGRAM_REGS; + } + break; + + default: + printf("programming error\n"); + while (1) + ; + break; + } + continue; + } + + if (strcmp(argv[0], "reset") == 0) { + /* + * Reboot machine. + * Args don't seem to matter because this + * doesn't return + */ + do_reset(NULL, 0, 0, NULL); + printf("Reset didn't work\n"); + } + + if (strcmp(argv[0], "recompute") == 0) { + /* + * Recalculate everything, starting with + * loading SPD EEPROM from DIMMs + */ + next_step = STEP_GET_SPD; + ddrsize = fsl_ddr_compute(pinfo, next_step, 0); + continue; + } + + if (strcmp(argv[0], "compute") == 0) { + /* + * Compute rest of steps starting at + * the current next_step/ + */ + ddrsize = fsl_ddr_compute(pinfo, next_step, 0); + continue; + } + + if (strcmp(argv[0], "print") == 0) { + unsigned int error = 0; + unsigned int step_mask = 0; + unsigned int ctlr_mask = 0; + unsigned int dimm_mask = 0; + unsigned int dimm_number_required = 0; + + if (argc == 1) { + printf("print [c] [d] [spd] [dimmparms] " + "[commonparms] [opts] [addresses] [regs]\n"); + continue; + } + + error = fsl_ddr_parse_interactive_cmd( + argv, argc, + &step_mask, + &ctlr_mask, + &dimm_mask, + &dimm_number_required + ); + + if (error) + continue; + + /* If no particular controller was found, print all */ + if (ctlr_mask == 0) + ctlr_mask = 0xFF; + + /* If no particular dimm was found, print all dimms. */ + if (dimm_mask == 0) + dimm_mask = 0xFF; + + /* If no steps were found, print all steps. */ + if (step_mask == 0) + step_mask = STEP_ALL; + + fsl_ddr_printinfo(pinfo, ctlr_mask, + dimm_mask, step_mask); + continue; + } + + if (strcmp(argv[0], "go") == 0) { + if (next_step) + ddrsize = fsl_ddr_compute(pinfo, next_step, 0); + break; + } + + printf("unknown command %s\n", argv[0]); + } + + debug("end of memory = %llu\n", (u64)ddrsize); + + return ddrsize; +} diff --git a/drivers/ddr/fsl/lc_common_dimm_params.c b/drivers/ddr/fsl/lc_common_dimm_params.c new file mode 100644 index 0000000..610318a --- /dev/null +++ b/drivers/ddr/fsl/lc_common_dimm_params.c @@ -0,0 +1,526 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include +#include + +#include + +#if defined(CONFIG_SYS_FSL_DDR3) +static unsigned int +compute_cas_latency_ddr3(const dimm_params_t *dimm_params, + common_timing_params_t *outpdimm, + unsigned int number_of_dimms) +{ + unsigned int i; + unsigned int taamin_ps = 0; + unsigned int tckmin_x_ps = 0; + unsigned int common_caslat; + unsigned int caslat_actual; + unsigned int retry = 16; + unsigned int tmp; + const unsigned int mclk_ps = get_memory_clk_period_ps(); + + /* compute the common CAS latency supported between slots */ + tmp = dimm_params[0].caslat_x; + for (i = 1; i < number_of_dimms; i++) { + if (dimm_params[i].n_ranks) + tmp &= dimm_params[i].caslat_x; + } + common_caslat = tmp; + + /* compute the max tAAmin tCKmin between slots */ + for (i = 0; i < number_of_dimms; i++) { + taamin_ps = max(taamin_ps, dimm_params[i].taa_ps); + tckmin_x_ps = max(tckmin_x_ps, dimm_params[i].tckmin_x_ps); + } + /* validate if the memory clk is in the range of dimms */ + if (mclk_ps < tckmin_x_ps) { + printf("DDR clock (MCLK cycle %u ps) is faster than " + "the slowest DIMM(s) (tCKmin %u ps) can support.\n", + mclk_ps, tckmin_x_ps); + } + /* determine the acutal cas latency */ + caslat_actual = (taamin_ps + mclk_ps - 1) / mclk_ps; + /* check if the dimms support the CAS latency */ + while (!(common_caslat & (1 << caslat_actual)) && retry > 0) { + caslat_actual++; + retry--; + } + /* once the caculation of caslat_actual is completed + * we must verify that this CAS latency value does not + * exceed tAAmax, which is 20 ns for all DDR3 speed grades + */ + if (caslat_actual * mclk_ps > 20000) { + printf("The choosen cas latency %d is too large\n", + caslat_actual); + } + outpdimm->lowest_common_SPD_caslat = caslat_actual; + + return 0; +} +#endif + +/* + * compute_lowest_common_dimm_parameters() + * + * Determine the worst-case DIMM timing parameters from the set of DIMMs + * whose parameters have been computed into the array pointed to + * by dimm_params. + */ +unsigned int +compute_lowest_common_dimm_parameters(const dimm_params_t *dimm_params, + common_timing_params_t *outpdimm, + const unsigned int number_of_dimms) +{ + unsigned int i, j; + + unsigned int tckmin_x_ps = 0; + unsigned int tckmax_ps = 0xFFFFFFFF; + unsigned int tckmax_max_ps = 0; + unsigned int trcd_ps = 0; + unsigned int trp_ps = 0; + unsigned int tras_ps = 0; + unsigned int twr_ps = 0; + unsigned int twtr_ps = 0; + unsigned int trfc_ps = 0; + unsigned int trrd_ps = 0; + unsigned int trc_ps = 0; + unsigned int refresh_rate_ps = 0; + unsigned int extended_op_srt = 1; + unsigned int tis_ps = 0; + unsigned int tih_ps = 0; + unsigned int tds_ps = 0; + unsigned int tdh_ps = 0; + unsigned int trtp_ps = 0; + unsigned int tdqsq_max_ps = 0; + unsigned int tqhs_ps = 0; + + unsigned int temp1, temp2; + unsigned int additive_latency = 0; +#if !defined(CONFIG_SYS_FSL_DDR3) + const unsigned int mclk_ps = get_memory_clk_period_ps(); + unsigned int lowest_good_caslat; + unsigned int not_ok; + + debug("using mclk_ps = %u\n", mclk_ps); +#endif + + temp1 = 0; + for (i = 0; i < number_of_dimms; i++) { + /* + * If there are no ranks on this DIMM, + * it probably doesn't exist, so skip it. + */ + if (dimm_params[i].n_ranks == 0) { + temp1++; + continue; + } + if (dimm_params[i].n_ranks == 4 && i != 0) { + printf("Found Quad-rank DIMM in wrong bank, ignored." + " Software may not run as expected.\n"); + temp1++; + continue; + } + + /* + * check if quad-rank DIMM is plugged if + * CONFIG_CHIP_SELECT_QUAD_CAPABLE is not defined + * Only the board with proper design is capable + */ +#ifndef CONFIG_FSL_DDR_FIRST_SLOT_QUAD_CAPABLE + if (dimm_params[i].n_ranks == 4 && \ + CONFIG_CHIP_SELECTS_PER_CTRL/CONFIG_DIMM_SLOTS_PER_CTLR < 4) { + printf("Found Quad-rank DIMM, not able to support."); + temp1++; + continue; + } +#endif + /* + * Find minimum tckmax_ps to find fastest slow speed, + * i.e., this is the slowest the whole system can go. + */ + tckmax_ps = min(tckmax_ps, dimm_params[i].tckmax_ps); + + /* Either find maximum value to determine slowest + * speed, delay, time, period, etc */ + tckmin_x_ps = max(tckmin_x_ps, dimm_params[i].tckmin_x_ps); + tckmax_max_ps = max(tckmax_max_ps, dimm_params[i].tckmax_ps); + trcd_ps = max(trcd_ps, dimm_params[i].trcd_ps); + trp_ps = max(trp_ps, dimm_params[i].trp_ps); + tras_ps = max(tras_ps, dimm_params[i].tras_ps); + twr_ps = max(twr_ps, dimm_params[i].twr_ps); + twtr_ps = max(twtr_ps, dimm_params[i].twtr_ps); + trfc_ps = max(trfc_ps, dimm_params[i].trfc_ps); + trrd_ps = max(trrd_ps, dimm_params[i].trrd_ps); + trc_ps = max(trc_ps, dimm_params[i].trc_ps); + tis_ps = max(tis_ps, dimm_params[i].tis_ps); + tih_ps = max(tih_ps, dimm_params[i].tih_ps); + tds_ps = max(tds_ps, dimm_params[i].tds_ps); + tdh_ps = max(tdh_ps, dimm_params[i].tdh_ps); + trtp_ps = max(trtp_ps, dimm_params[i].trtp_ps); + tqhs_ps = max(tqhs_ps, dimm_params[i].tqhs_ps); + refresh_rate_ps = max(refresh_rate_ps, + dimm_params[i].refresh_rate_ps); + /* extended_op_srt is either 0 or 1, 0 having priority */ + extended_op_srt = min(extended_op_srt, + dimm_params[i].extended_op_srt); + + /* + * Find maximum tdqsq_max_ps to find slowest. + * + * FIXME: is finding the slowest value the correct + * strategy for this parameter? + */ + tdqsq_max_ps = max(tdqsq_max_ps, dimm_params[i].tdqsq_max_ps); + } + + outpdimm->ndimms_present = number_of_dimms - temp1; + + if (temp1 == number_of_dimms) { + debug("no dimms this memory controller\n"); + return 0; + } + + outpdimm->tckmin_x_ps = tckmin_x_ps; + outpdimm->tckmax_ps = tckmax_ps; + outpdimm->tckmax_max_ps = tckmax_max_ps; + outpdimm->trcd_ps = trcd_ps; + outpdimm->trp_ps = trp_ps; + outpdimm->tras_ps = tras_ps; + outpdimm->twr_ps = twr_ps; + outpdimm->twtr_ps = twtr_ps; + outpdimm->trfc_ps = trfc_ps; + outpdimm->trrd_ps = trrd_ps; + outpdimm->trc_ps = trc_ps; + outpdimm->refresh_rate_ps = refresh_rate_ps; + outpdimm->extended_op_srt = extended_op_srt; + outpdimm->tis_ps = tis_ps; + outpdimm->tih_ps = tih_ps; + outpdimm->tds_ps = tds_ps; + outpdimm->tdh_ps = tdh_ps; + outpdimm->trtp_ps = trtp_ps; + outpdimm->tdqsq_max_ps = tdqsq_max_ps; + outpdimm->tqhs_ps = tqhs_ps; + + /* Determine common burst length for all DIMMs. */ + temp1 = 0xff; + for (i = 0; i < number_of_dimms; i++) { + if (dimm_params[i].n_ranks) { + temp1 &= dimm_params[i].burst_lengths_bitmask; + } + } + outpdimm->all_dimms_burst_lengths_bitmask = temp1; + + /* Determine if all DIMMs registered buffered. */ + temp1 = temp2 = 0; + for (i = 0; i < number_of_dimms; i++) { + if (dimm_params[i].n_ranks) { + if (dimm_params[i].registered_dimm) { + temp1 = 1; +#ifndef CONFIG_SPL_BUILD + printf("Detected RDIMM %s\n", + dimm_params[i].mpart); +#endif + } else { + temp2 = 1; +#ifndef CONFIG_SPL_BUILD + printf("Detected UDIMM %s\n", + dimm_params[i].mpart); +#endif + } + } + } + + outpdimm->all_dimms_registered = 0; + outpdimm->all_dimms_unbuffered = 0; + if (temp1 && !temp2) { + outpdimm->all_dimms_registered = 1; + } else if (!temp1 && temp2) { + outpdimm->all_dimms_unbuffered = 1; + } else { + printf("ERROR: Mix of registered buffered and unbuffered " + "DIMMs detected!\n"); + } + + temp1 = 0; + if (outpdimm->all_dimms_registered) + for (j = 0; j < 16; j++) { + outpdimm->rcw[j] = dimm_params[0].rcw[j]; + for (i = 1; i < number_of_dimms; i++) { + if (!dimm_params[i].n_ranks) + continue; + if (dimm_params[i].rcw[j] != dimm_params[0].rcw[j]) { + temp1 = 1; + break; + } + } + } + + if (temp1 != 0) + printf("ERROR: Mix different RDIMM detected!\n"); + +#if defined(CONFIG_SYS_FSL_DDR3) + if (compute_cas_latency_ddr3(dimm_params, outpdimm, number_of_dimms)) + return 1; +#else + /* + * Compute a CAS latency suitable for all DIMMs + * + * Strategy for SPD-defined latencies: compute only + * CAS latency defined by all DIMMs. + */ + + /* + * Step 1: find CAS latency common to all DIMMs using bitwise + * operation. + */ + temp1 = 0xFF; + for (i = 0; i < number_of_dimms; i++) { + if (dimm_params[i].n_ranks) { + temp2 = 0; + temp2 |= 1 << dimm_params[i].caslat_x; + temp2 |= 1 << dimm_params[i].caslat_x_minus_1; + temp2 |= 1 << dimm_params[i].caslat_x_minus_2; + /* + * FIXME: If there was no entry for X-2 (X-1) in + * the SPD, then caslat_x_minus_2 + * (caslat_x_minus_1) contains either 255 or + * 0xFFFFFFFF because that's what the glorious + * __ilog2 function returns for an input of 0. + * On 32-bit PowerPC, left shift counts with bit + * 26 set (that the value of 255 or 0xFFFFFFFF + * will have), cause the destination register to + * be 0. That is why this works. + */ + temp1 &= temp2; + } + } + + /* + * Step 2: check each common CAS latency against tCK of each + * DIMM's SPD. + */ + lowest_good_caslat = 0; + temp2 = 0; + while (temp1) { + not_ok = 0; + temp2 = __ilog2(temp1); + debug("checking common caslat = %u\n", temp2); + + /* Check if this CAS latency will work on all DIMMs at tCK. */ + for (i = 0; i < number_of_dimms; i++) { + if (!dimm_params[i].n_ranks) { + continue; + } + if (dimm_params[i].caslat_x == temp2) { + if (mclk_ps >= dimm_params[i].tckmin_x_ps) { + debug("CL = %u ok on DIMM %u at tCK=%u" + " ps with its tCKmin_X_ps of %u\n", + temp2, i, mclk_ps, + dimm_params[i].tckmin_x_ps); + continue; + } else { + not_ok++; + } + } + + if (dimm_params[i].caslat_x_minus_1 == temp2) { + unsigned int tckmin_x_minus_1_ps + = dimm_params[i].tckmin_x_minus_1_ps; + if (mclk_ps >= tckmin_x_minus_1_ps) { + debug("CL = %u ok on DIMM %u at " + "tCK=%u ps with its " + "tckmin_x_minus_1_ps of %u\n", + temp2, i, mclk_ps, + tckmin_x_minus_1_ps); + continue; + } else { + not_ok++; + } + } + + if (dimm_params[i].caslat_x_minus_2 == temp2) { + unsigned int tckmin_x_minus_2_ps + = dimm_params[i].tckmin_x_minus_2_ps; + if (mclk_ps >= tckmin_x_minus_2_ps) { + debug("CL = %u ok on DIMM %u at " + "tCK=%u ps with its " + "tckmin_x_minus_2_ps of %u\n", + temp2, i, mclk_ps, + tckmin_x_minus_2_ps); + continue; + } else { + not_ok++; + } + } + } + + if (!not_ok) { + lowest_good_caslat = temp2; + } + + temp1 &= ~(1 << temp2); + } + + debug("lowest common SPD-defined CAS latency = %u\n", + lowest_good_caslat); + outpdimm->lowest_common_SPD_caslat = lowest_good_caslat; + + + /* + * Compute a common 'de-rated' CAS latency. + * + * The strategy here is to find the *highest* dereated cas latency + * with the assumption that all of the DIMMs will support a dereated + * CAS latency higher than or equal to their lowest dereated value. + */ + temp1 = 0; + for (i = 0; i < number_of_dimms; i++) { + temp1 = max(temp1, dimm_params[i].caslat_lowest_derated); + } + outpdimm->highest_common_derated_caslat = temp1; + debug("highest common dereated CAS latency = %u\n", temp1); +#endif /* #if defined(CONFIG_SYS_FSL_DDR3) */ + + /* Determine if all DIMMs ECC capable. */ + temp1 = 1; + for (i = 0; i < number_of_dimms; i++) { + if (dimm_params[i].n_ranks && + !(dimm_params[i].edc_config & EDC_ECC)) { + temp1 = 0; + break; + } + } + if (temp1) { + debug("all DIMMs ECC capable\n"); + } else { + debug("Warning: not all DIMMs ECC capable, cant enable ECC\n"); + } + outpdimm->all_dimms_ecc_capable = temp1; + +#ifndef CONFIG_SYS_FSL_DDR3 + /* FIXME: move to somewhere else to validate. */ + if (mclk_ps > tckmax_max_ps) { + printf("Warning: some of the installed DIMMs " + "can not operate this slowly.\n"); + return 1; + } +#endif + /* + * Compute additive latency. + * + * For DDR1, additive latency should be 0. + * + * For DDR2, with ODT enabled, use "a value" less than ACTTORW, + * which comes from Trcd, and also note that: + * add_lat + caslat must be >= 4 + * + * For DDR3, we use the AL=0 + * + * When to use additive latency for DDR2: + * + * I. Because you are using CL=3 and need to do ODT on writes and + * want functionality. + * 1. Are you going to use ODT? (Does your board not have + * additional termination circuitry for DQ, DQS, DQS_, + * DM, RDQS, RDQS_ for x4/x8 configs?) + * 2. If so, is your lowest supported CL going to be 3? + * 3. If so, then you must set AL=1 because + * + * WL >= 3 for ODT on writes + * RL = AL + CL + * WL = RL - 1 + * -> + * WL = AL + CL - 1 + * AL + CL - 1 >= 3 + * AL + CL >= 4 + * QED + * + * RL >= 3 for ODT on reads + * RL = AL + CL + * + * Since CL aren't usually less than 2, AL=0 is a minimum, + * so the WL-derived AL should be the -- FIXME? + * + * II. Because you are using auto-precharge globally and want to + * use additive latency (posted CAS) to get more bandwidth. + * 1. Are you going to use auto-precharge mode globally? + * + * Use addtivie latency and compute AL to be 1 cycle less than + * tRCD, i.e. the READ or WRITE command is in the cycle + * immediately following the ACTIVATE command.. + * + * III. Because you feel like it or want to do some sort of + * degraded-performance experiment. + * 1. Do you just want to use additive latency because you feel + * like it? + * + * Validation: AL is less than tRCD, and within the other + * read-to-precharge constraints. + */ + + additive_latency = 0; + +#if defined(CONFIG_SYS_FSL_DDR2) + if (lowest_good_caslat < 4) { + additive_latency = (picos_to_mclk(trcd_ps) > lowest_good_caslat) + ? picos_to_mclk(trcd_ps) - lowest_good_caslat : 0; + if (mclk_to_picos(additive_latency) > trcd_ps) { + additive_latency = picos_to_mclk(trcd_ps); + debug("setting additive_latency to %u because it was " + " greater than tRCD_ps\n", additive_latency); + } + } + +#elif defined(CONFIG_SYS_FSL_DDR3) + /* + * The system will not use the global auto-precharge mode. + * However, it uses the page mode, so we set AL=0 + */ + additive_latency = 0; +#endif + + /* + * Validate additive latency + * FIXME: move to somewhere else to validate + * + * AL <= tRCD(min) + */ + if (mclk_to_picos(additive_latency) > trcd_ps) { + printf("Error: invalid additive latency exceeds tRCD(min).\n"); + return 1; + } + + /* + * RL = CL + AL; RL >= 3 for ODT_RD_CFG to be enabled + * WL = RL - 1; WL >= 3 for ODT_WL_CFG to be enabled + * ADD_LAT (the register) must be set to a value less + * than ACTTORW if WL = 1, then AL must be set to 1 + * RD_TO_PRE (the register) must be set to a minimum + * tRTP + AL if AL is nonzero + */ + + /* + * Additive latency will be applied only if the memctl option to + * use it. + */ + outpdimm->additive_latency = additive_latency; + + debug("tCKmin_ps = %u\n", outpdimm->tckmin_x_ps); + debug("trcd_ps = %u\n", outpdimm->trcd_ps); + debug("trp_ps = %u\n", outpdimm->trp_ps); + debug("tras_ps = %u\n", outpdimm->tras_ps); + debug("twr_ps = %u\n", outpdimm->twr_ps); + debug("twtr_ps = %u\n", outpdimm->twtr_ps); + debug("trfc_ps = %u\n", outpdimm->trfc_ps); + debug("trrd_ps = %u\n", outpdimm->trrd_ps); + debug("trc_ps = %u\n", outpdimm->trc_ps); + + return 0; +} diff --git a/drivers/ddr/fsl/main.c b/drivers/ddr/fsl/main.c new file mode 100644 index 0000000..c1cdbdf --- /dev/null +++ b/drivers/ddr/fsl/main.c @@ -0,0 +1,718 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +/* + * Generic driver for Freescale DDR/DDR2/DDR3 memory controller. + * Based on code from spd_sdram.c + * Author: James Yang [at freescale.com] + */ + +#include +#include +#include +#include + +#include + +void fsl_ddr_set_lawbar( + const common_timing_params_t *memctl_common_params, + unsigned int memctl_interleaved, + unsigned int ctrl_num); +void fsl_ddr_set_intl3r(const unsigned int granule_size); + +#if defined(SPD_EEPROM_ADDRESS) || \ + defined(SPD_EEPROM_ADDRESS1) || defined(SPD_EEPROM_ADDRESS2) || \ + defined(SPD_EEPROM_ADDRESS3) || defined(SPD_EEPROM_ADDRESS4) +#if (CONFIG_NUM_DDR_CONTROLLERS == 1) && (CONFIG_DIMM_SLOTS_PER_CTLR == 1) +u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = { + [0][0] = SPD_EEPROM_ADDRESS, +}; +#elif (CONFIG_NUM_DDR_CONTROLLERS == 1) && (CONFIG_DIMM_SLOTS_PER_CTLR == 2) +u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = { + [0][0] = SPD_EEPROM_ADDRESS1, /* controller 1 */ + [0][1] = SPD_EEPROM_ADDRESS2, /* controller 1 */ +}; +#elif (CONFIG_NUM_DDR_CONTROLLERS == 2) && (CONFIG_DIMM_SLOTS_PER_CTLR == 1) +u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = { + [0][0] = SPD_EEPROM_ADDRESS1, /* controller 1 */ + [1][0] = SPD_EEPROM_ADDRESS2, /* controller 2 */ +}; +#elif (CONFIG_NUM_DDR_CONTROLLERS == 2) && (CONFIG_DIMM_SLOTS_PER_CTLR == 2) +u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = { + [0][0] = SPD_EEPROM_ADDRESS1, /* controller 1 */ + [0][1] = SPD_EEPROM_ADDRESS2, /* controller 1 */ + [1][0] = SPD_EEPROM_ADDRESS3, /* controller 2 */ + [1][1] = SPD_EEPROM_ADDRESS4, /* controller 2 */ +}; +#elif (CONFIG_NUM_DDR_CONTROLLERS == 3) && (CONFIG_DIMM_SLOTS_PER_CTLR == 1) +u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = { + [0][0] = SPD_EEPROM_ADDRESS1, /* controller 1 */ + [1][0] = SPD_EEPROM_ADDRESS2, /* controller 2 */ + [2][0] = SPD_EEPROM_ADDRESS3, /* controller 3 */ +}; +#elif (CONFIG_NUM_DDR_CONTROLLERS == 3) && (CONFIG_DIMM_SLOTS_PER_CTLR == 2) +u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = { + [0][0] = SPD_EEPROM_ADDRESS1, /* controller 1 */ + [0][1] = SPD_EEPROM_ADDRESS2, /* controller 1 */ + [1][0] = SPD_EEPROM_ADDRESS3, /* controller 2 */ + [1][1] = SPD_EEPROM_ADDRESS4, /* controller 2 */ + [2][0] = SPD_EEPROM_ADDRESS5, /* controller 3 */ + [2][1] = SPD_EEPROM_ADDRESS6, /* controller 3 */ +}; + +#endif + +static void __get_spd(generic_spd_eeprom_t *spd, u8 i2c_address) +{ + int ret; + + i2c_set_bus_num(CONFIG_SYS_SPD_BUS_NUM); + + ret = i2c_read(i2c_address, 0, 1, (uchar *)spd, + sizeof(generic_spd_eeprom_t)); + + if (ret) { + if (i2c_address == +#ifdef SPD_EEPROM_ADDRESS + SPD_EEPROM_ADDRESS +#elif defined(SPD_EEPROM_ADDRESS1) + SPD_EEPROM_ADDRESS1 +#endif + ) { + printf("DDR: failed to read SPD from address %u\n", + i2c_address); + } else { + debug("DDR: failed to read SPD from address %u\n", + i2c_address); + } + memset(spd, 0, sizeof(generic_spd_eeprom_t)); + } +} + +__attribute__((weak, alias("__get_spd"))) +void get_spd(generic_spd_eeprom_t *spd, u8 i2c_address); + +void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd, + unsigned int ctrl_num) +{ + unsigned int i; + unsigned int i2c_address = 0; + + if (ctrl_num >= CONFIG_NUM_DDR_CONTROLLERS) { + printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num); + return; + } + + for (i = 0; i < CONFIG_DIMM_SLOTS_PER_CTLR; i++) { + i2c_address = spd_i2c_addr[ctrl_num][i]; + get_spd(&(ctrl_dimms_spd[i]), i2c_address); + } +} +#else +void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd, + unsigned int ctrl_num) +{ +} +#endif /* SPD_EEPROM_ADDRESSx */ + +/* + * ASSUMPTIONS: + * - Same number of CONFIG_DIMM_SLOTS_PER_CTLR on each controller + * - Same memory data bus width on all controllers + * + * NOTES: + * + * The memory controller and associated documentation use confusing + * terminology when referring to the orgranization of DRAM. + * + * Here is a terminology translation table: + * + * memory controller/documention |industry |this code |signals + * -------------------------------|-----------|-----------|----------------- + * physical bank/bank |rank |rank |chip select (CS) + * logical bank/sub-bank |bank |bank |bank address (BA) + * page/row |row |page |row address + * ??? |column |column |column address + * + * The naming confusion is further exacerbated by the descriptions of the + * memory controller interleaving feature, where accesses are interleaved + * _BETWEEN_ two seperate memory controllers. This is configured only in + * CS0_CONFIG[INTLV_CTL] of each memory controller. + * + * memory controller documentation | number of chip selects + * | per memory controller supported + * --------------------------------|----------------------------------------- + * cache line interleaving | 1 (CS0 only) + * page interleaving | 1 (CS0 only) + * bank interleaving | 1 (CS0 only) + * superbank interleraving | depends on bank (chip select) + * | interleraving [rank interleaving] + * | mode used on every memory controller + * + * Even further confusing is the existence of the interleaving feature + * _WITHIN_ each memory controller. The feature is referred to in + * documentation as chip select interleaving or bank interleaving, + * although it is configured in the DDR_SDRAM_CFG field. + * + * Name of field | documentation name | this code + * -----------------------------|-----------------------|------------------ + * DDR_SDRAM_CFG[BA_INTLV_CTL] | Bank (chip select) | rank interleaving + * | interleaving + */ + +const char *step_string_tbl[] = { + "STEP_GET_SPD", + "STEP_COMPUTE_DIMM_PARMS", + "STEP_COMPUTE_COMMON_PARMS", + "STEP_GATHER_OPTS", + "STEP_ASSIGN_ADDRESSES", + "STEP_COMPUTE_REGS", + "STEP_PROGRAM_REGS", + "STEP_ALL" +}; + +const char * step_to_string(unsigned int step) { + + unsigned int s = __ilog2(step); + + if ((1 << s) != step) + return step_string_tbl[7]; + + return step_string_tbl[s]; +} + +static unsigned long long __step_assign_addresses(fsl_ddr_info_t *pinfo, + unsigned int dbw_cap_adj[]) +{ + int i, j; + unsigned long long total_mem, current_mem_base, total_ctlr_mem; + unsigned long long rank_density, ctlr_density = 0; + + /* + * If a reduced data width is requested, but the SPD + * specifies a physically wider device, adjust the + * computed dimm capacities accordingly before + * assigning addresses. + */ + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + unsigned int found = 0; + + switch (pinfo->memctl_opts[i].data_bus_width) { + case 2: + /* 16-bit */ + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + unsigned int dw; + if (!pinfo->dimm_params[i][j].n_ranks) + continue; + dw = pinfo->dimm_params[i][j].primary_sdram_width; + if ((dw == 72 || dw == 64)) { + dbw_cap_adj[i] = 2; + break; + } else if ((dw == 40 || dw == 32)) { + dbw_cap_adj[i] = 1; + break; + } + } + break; + + case 1: + /* 32-bit */ + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + unsigned int dw; + dw = pinfo->dimm_params[i][j].data_width; + if (pinfo->dimm_params[i][j].n_ranks + && (dw == 72 || dw == 64)) { + /* + * FIXME: can't really do it + * like this because this just + * further reduces the memory + */ + found = 1; + break; + } + } + if (found) { + dbw_cap_adj[i] = 1; + } + break; + + case 0: + /* 64-bit */ + break; + + default: + printf("unexpected data bus width " + "specified controller %u\n", i); + return 1; + } + debug("dbw_cap_adj[%d]=%d\n", i, dbw_cap_adj[i]); + } + + current_mem_base = 0ull; + total_mem = 0; + if (pinfo->memctl_opts[0].memctl_interleaving) { + rank_density = pinfo->dimm_params[0][0].rank_density >> + dbw_cap_adj[0]; + switch (pinfo->memctl_opts[0].ba_intlv_ctl & + FSL_DDR_CS0_CS1_CS2_CS3) { + case FSL_DDR_CS0_CS1_CS2_CS3: + ctlr_density = 4 * rank_density; + break; + case FSL_DDR_CS0_CS1: + case FSL_DDR_CS0_CS1_AND_CS2_CS3: + ctlr_density = 2 * rank_density; + break; + case FSL_DDR_CS2_CS3: + default: + ctlr_density = rank_density; + break; + } + debug("rank density is 0x%llx, ctlr density is 0x%llx\n", + rank_density, ctlr_density); + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (pinfo->memctl_opts[i].memctl_interleaving) { + switch (pinfo->memctl_opts[i].memctl_interleaving_mode) { + case FSL_DDR_CACHE_LINE_INTERLEAVING: + case FSL_DDR_PAGE_INTERLEAVING: + case FSL_DDR_BANK_INTERLEAVING: + case FSL_DDR_SUPERBANK_INTERLEAVING: + total_ctlr_mem = 2 * ctlr_density; + break; + case FSL_DDR_3WAY_1KB_INTERLEAVING: + case FSL_DDR_3WAY_4KB_INTERLEAVING: + case FSL_DDR_3WAY_8KB_INTERLEAVING: + total_ctlr_mem = 3 * ctlr_density; + break; + case FSL_DDR_4WAY_1KB_INTERLEAVING: + case FSL_DDR_4WAY_4KB_INTERLEAVING: + case FSL_DDR_4WAY_8KB_INTERLEAVING: + total_ctlr_mem = 4 * ctlr_density; + break; + default: + panic("Unknown interleaving mode"); + } + pinfo->common_timing_params[i].base_address = + current_mem_base; + pinfo->common_timing_params[i].total_mem = + total_ctlr_mem; + total_mem = current_mem_base + total_ctlr_mem; + debug("ctrl %d base 0x%llx\n", i, current_mem_base); + debug("ctrl %d total 0x%llx\n", i, total_ctlr_mem); + } else { + /* when 3rd controller not interleaved */ + current_mem_base = total_mem; + total_ctlr_mem = 0; + pinfo->common_timing_params[i].base_address = + current_mem_base; + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + unsigned long long cap = + pinfo->dimm_params[i][j].capacity >> dbw_cap_adj[i]; + pinfo->dimm_params[i][j].base_address = + current_mem_base; + debug("ctrl %d dimm %d base 0x%llx\n", i, j, current_mem_base); + current_mem_base += cap; + total_ctlr_mem += cap; + } + debug("ctrl %d total 0x%llx\n", i, total_ctlr_mem); + pinfo->common_timing_params[i].total_mem = + total_ctlr_mem; + total_mem += total_ctlr_mem; + } + } + } else { + /* + * Simple linear assignment if memory + * controllers are not interleaved. + */ + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + total_ctlr_mem = 0; + pinfo->common_timing_params[i].base_address = + current_mem_base; + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + /* Compute DIMM base addresses. */ + unsigned long long cap = + pinfo->dimm_params[i][j].capacity >> dbw_cap_adj[i]; + pinfo->dimm_params[i][j].base_address = + current_mem_base; + debug("ctrl %d dimm %d base 0x%llx\n", i, j, current_mem_base); + current_mem_base += cap; + total_ctlr_mem += cap; + } + debug("ctrl %d total 0x%llx\n", i, total_ctlr_mem); + pinfo->common_timing_params[i].total_mem = + total_ctlr_mem; + total_mem += total_ctlr_mem; + } + } + debug("Total mem by %s is 0x%llx\n", __func__, total_mem); + + return total_mem; +} + +/* Use weak function to allow board file to override the address assignment */ +__attribute__((weak, alias("__step_assign_addresses"))) +unsigned long long step_assign_addresses(fsl_ddr_info_t *pinfo, + unsigned int dbw_cap_adj[]); + +unsigned long long +fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step, + unsigned int size_only) +{ + unsigned int i, j; + unsigned long long total_mem = 0; + int assert_reset; + + fsl_ddr_cfg_regs_t *ddr_reg = pinfo->fsl_ddr_config_reg; + common_timing_params_t *timing_params = pinfo->common_timing_params; + assert_reset = board_need_mem_reset(); + + /* data bus width capacity adjust shift amount */ + unsigned int dbw_capacity_adjust[CONFIG_NUM_DDR_CONTROLLERS]; + + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + dbw_capacity_adjust[i] = 0; + } + + debug("starting at step %u (%s)\n", + start_step, step_to_string(start_step)); + + switch (start_step) { + case STEP_GET_SPD: +#if defined(CONFIG_DDR_SPD) || defined(CONFIG_SPD_EEPROM) + /* STEP 1: Gather all DIMM SPD data */ + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + fsl_ddr_get_spd(pinfo->spd_installed_dimms[i], i); + } + + case STEP_COMPUTE_DIMM_PARMS: + /* STEP 2: Compute DIMM parameters from SPD data */ + + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + unsigned int retval; + generic_spd_eeprom_t *spd = + &(pinfo->spd_installed_dimms[i][j]); + dimm_params_t *pdimm = + &(pinfo->dimm_params[i][j]); + + retval = compute_dimm_parameters(spd, pdimm, i); +#ifdef CONFIG_SYS_DDR_RAW_TIMING + if (!i && !j && retval) { + printf("SPD error on controller %d! " + "Trying fallback to raw timing " + "calculation\n", i); + fsl_ddr_get_dimm_params(pdimm, i, j); + } +#else + if (retval == 2) { + printf("Error: compute_dimm_parameters" + " non-zero returned FATAL value " + "for memctl=%u dimm=%u\n", i, j); + return 0; + } +#endif + if (retval) { + debug("Warning: compute_dimm_parameters" + " non-zero return value for memctl=%u " + "dimm=%u\n", i, j); + } + } + } + +#elif defined(CONFIG_SYS_DDR_RAW_TIMING) + case STEP_COMPUTE_DIMM_PARMS: + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + dimm_params_t *pdimm = + &(pinfo->dimm_params[i][j]); + fsl_ddr_get_dimm_params(pdimm, i, j); + } + } + debug("Filling dimm parameters from board specific file\n"); +#endif + case STEP_COMPUTE_COMMON_PARMS: + /* + * STEP 3: Compute a common set of timing parameters + * suitable for all of the DIMMs on each memory controller + */ + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + debug("Computing lowest common DIMM" + " parameters for memctl=%u\n", i); + compute_lowest_common_dimm_parameters( + pinfo->dimm_params[i], + &timing_params[i], + CONFIG_DIMM_SLOTS_PER_CTLR); + } + + case STEP_GATHER_OPTS: + /* STEP 4: Gather configuration requirements from user */ + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + debug("Reloading memory controller " + "configuration options for memctl=%u\n", i); + /* + * This "reloads" the memory controller options + * to defaults. If the user "edits" an option, + * next_step points to the step after this, + * which is currently STEP_ASSIGN_ADDRESSES. + */ + populate_memctl_options( + timing_params[i].all_dimms_registered, + &pinfo->memctl_opts[i], + pinfo->dimm_params[i], i); + /* + * For RDIMMs, JEDEC spec requires clocks to be stable + * before reset signal is deasserted. For the boards + * using fixed parameters, this function should be + * be called from board init file. + */ + if (timing_params[i].all_dimms_registered) + assert_reset = 1; + } + if (assert_reset) { + debug("Asserting mem reset\n"); + board_assert_mem_reset(); + } + + case STEP_ASSIGN_ADDRESSES: + /* STEP 5: Assign addresses to chip selects */ + check_interleaving_options(pinfo); + total_mem = step_assign_addresses(pinfo, dbw_capacity_adjust); + + case STEP_COMPUTE_REGS: + /* STEP 6: compute controller register values */ + debug("FSL Memory ctrl register computation\n"); + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (timing_params[i].ndimms_present == 0) { + memset(&ddr_reg[i], 0, + sizeof(fsl_ddr_cfg_regs_t)); + continue; + } + + compute_fsl_memctl_config_regs( + &pinfo->memctl_opts[i], + &ddr_reg[i], &timing_params[i], + pinfo->dimm_params[i], + dbw_capacity_adjust[i], + size_only); + } + + default: + break; + } + + { + /* + * Compute the amount of memory available just by + * looking for the highest valid CSn_BNDS value. + * This allows us to also experiment with using + * only CS0 when using dual-rank DIMMs. + */ + unsigned int max_end = 0; + + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + for (j = 0; j < CONFIG_CHIP_SELECTS_PER_CTRL; j++) { + fsl_ddr_cfg_regs_t *reg = &ddr_reg[i]; + if (reg->cs[j].config & 0x80000000) { + unsigned int end; + /* + * 0xfffffff is a special value we put + * for unused bnds + */ + if (reg->cs[j].bnds == 0xffffffff) + continue; + end = reg->cs[j].bnds & 0xffff; + if (end > max_end) { + max_end = end; + } + } + } + } + + total_mem = 1 + (((unsigned long long)max_end << 24ULL) + | 0xFFFFFFULL); + } + + return total_mem; +} + +/* + * fsl_ddr_sdram() -- this is the main function to be called by + * initdram() in the board file. + * + * It returns amount of memory configured in bytes. + */ +phys_size_t fsl_ddr_sdram(void) +{ + unsigned int i; + unsigned int law_memctl = LAW_TRGT_IF_DDR_1; + unsigned long long total_memory; + fsl_ddr_info_t info; + int deassert_reset; + + /* Reset info structure. */ + memset(&info, 0, sizeof(fsl_ddr_info_t)); + + /* Compute it once normally. */ +#ifdef CONFIG_FSL_DDR_INTERACTIVE + if (tstc() && (getc() == 'd')) { /* we got a key press of 'd' */ + total_memory = fsl_ddr_interactive(&info, 0); + } else if (fsl_ddr_interactive_env_var_exists()) { + total_memory = fsl_ddr_interactive(&info, 1); + } else +#endif + total_memory = fsl_ddr_compute(&info, STEP_GET_SPD, 0); + + /* setup 3-way interleaving before enabling DDRC */ + if (info.memctl_opts[0].memctl_interleaving) { + switch (info.memctl_opts[0].memctl_interleaving_mode) { + case FSL_DDR_3WAY_1KB_INTERLEAVING: + case FSL_DDR_3WAY_4KB_INTERLEAVING: + case FSL_DDR_3WAY_8KB_INTERLEAVING: + fsl_ddr_set_intl3r( + info.memctl_opts[0].memctl_interleaving_mode); + break; + default: + break; + } + } + + /* + * Program configuration registers. + * JEDEC specs requires clocks to be stable before deasserting reset + * for RDIMMs. Clocks start after chip select is enabled and clock + * control register is set. During step 1, all controllers have their + * registers set but not enabled. Step 2 proceeds after deasserting + * reset through board FPGA or GPIO. + * For non-registered DIMMs, initialization can go through but it is + * also OK to follow the same flow. + */ + deassert_reset = board_need_mem_reset(); + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (info.common_timing_params[i].all_dimms_registered) + deassert_reset = 1; + } + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + debug("Programming controller %u\n", i); + if (info.common_timing_params[i].ndimms_present == 0) { + debug("No dimms present on controller %u; " + "skipping programming\n", i); + continue; + } + /* + * The following call with step = 1 returns before enabling + * the controller. It has to finish with step = 2 later. + */ + fsl_ddr_set_memctl_regs(&(info.fsl_ddr_config_reg[i]), i, + deassert_reset ? 1 : 0); + } + if (deassert_reset) { + /* Use board FPGA or GPIO to deassert reset signal */ + debug("Deasserting mem reset\n"); + board_deassert_mem_reset(); + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + /* Call with step = 2 to continue initialization */ + fsl_ddr_set_memctl_regs(&(info.fsl_ddr_config_reg[i]), + i, 2); + } + } + + /* program LAWs */ + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if (info.memctl_opts[i].memctl_interleaving) { + switch (info.memctl_opts[i].memctl_interleaving_mode) { + case FSL_DDR_CACHE_LINE_INTERLEAVING: + case FSL_DDR_PAGE_INTERLEAVING: + case FSL_DDR_BANK_INTERLEAVING: + case FSL_DDR_SUPERBANK_INTERLEAVING: + if (i == 0) { + law_memctl = LAW_TRGT_IF_DDR_INTRLV; + fsl_ddr_set_lawbar(&info.common_timing_params[i], + law_memctl, i); + } else if (i == 2) { + law_memctl = LAW_TRGT_IF_DDR_INTLV_34; + fsl_ddr_set_lawbar(&info.common_timing_params[i], + law_memctl, i); + } + break; + case FSL_DDR_3WAY_1KB_INTERLEAVING: + case FSL_DDR_3WAY_4KB_INTERLEAVING: + case FSL_DDR_3WAY_8KB_INTERLEAVING: + law_memctl = LAW_TRGT_IF_DDR_INTLV_123; + if (i == 0) { + fsl_ddr_set_lawbar(&info.common_timing_params[i], + law_memctl, i); + } + break; + case FSL_DDR_4WAY_1KB_INTERLEAVING: + case FSL_DDR_4WAY_4KB_INTERLEAVING: + case FSL_DDR_4WAY_8KB_INTERLEAVING: + law_memctl = LAW_TRGT_IF_DDR_INTLV_1234; + if (i == 0) + fsl_ddr_set_lawbar(&info.common_timing_params[i], + law_memctl, i); + /* place holder for future 4-way interleaving */ + break; + default: + break; + } + } else { + switch (i) { + case 0: + law_memctl = LAW_TRGT_IF_DDR_1; + break; + case 1: + law_memctl = LAW_TRGT_IF_DDR_2; + break; + case 2: + law_memctl = LAW_TRGT_IF_DDR_3; + break; + case 3: + law_memctl = LAW_TRGT_IF_DDR_4; + break; + default: + break; + } + fsl_ddr_set_lawbar(&info.common_timing_params[i], + law_memctl, i); + } + } + + debug("total_memory by %s = %llu\n", __func__, total_memory); + +#if !defined(CONFIG_PHYS_64BIT) + /* Check for 4G or more. Bad. */ + if (total_memory >= (1ull << 32)) { + puts("Detected "); + print_size(total_memory, " of memory\n"); + printf(" This U-Boot only supports < 4G of DDR\n"); + printf(" You could rebuild it with CONFIG_PHYS_64BIT\n"); + printf(" "); /* re-align to match init_func_ram print */ + total_memory = CONFIG_MAX_MEM_MAPPED; + } +#endif + + return total_memory; +} + +/* + * fsl_ddr_sdram_size() - This function only returns the size of the total + * memory without setting ddr control registers. + */ +phys_size_t +fsl_ddr_sdram_size(void) +{ + fsl_ddr_info_t info; + unsigned long long total_memory = 0; + + memset(&info, 0 , sizeof(fsl_ddr_info_t)); + + /* Compute it once normally. */ + total_memory = fsl_ddr_compute(&info, STEP_GET_SPD, 1); + + return total_memory; +} diff --git a/drivers/ddr/fsl/mpc85xx_ddr_gen1.c b/drivers/ddr/fsl/mpc85xx_ddr_gen1.c new file mode 100644 index 0000000..ff7d979 --- /dev/null +++ b/drivers/ddr/fsl/mpc85xx_ddr_gen1.c @@ -0,0 +1,89 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include +#include +#include + +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4) +#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL +#endif + +void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, + unsigned int ctrl_num, int step) +{ + unsigned int i; + volatile ccsr_ddr_t *ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR; + + if (ctrl_num != 0) { + printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num); + return; + } + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (i == 0) { + out_be32(&ddr->cs0_bnds, regs->cs[i].bnds); + out_be32(&ddr->cs0_config, regs->cs[i].config); + + } else if (i == 1) { + out_be32(&ddr->cs1_bnds, regs->cs[i].bnds); + out_be32(&ddr->cs1_config, regs->cs[i].config); + + } else if (i == 2) { + out_be32(&ddr->cs2_bnds, regs->cs[i].bnds); + out_be32(&ddr->cs2_config, regs->cs[i].config); + + } else if (i == 3) { + out_be32(&ddr->cs3_bnds, regs->cs[i].bnds); + out_be32(&ddr->cs3_config, regs->cs[i].config); + } + } + + out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1); + out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2); + out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode); + out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval); +#if defined(CONFIG_MPC8555) || defined(CONFIG_MPC8541) + out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl); +#endif + + /* + * 200 painful micro-seconds must elapse between + * the DDR clock setup and the DDR config enable. + */ + udelay(200); + asm volatile("sync;isync"); + + out_be32(&ddr->sdram_cfg, regs->ddr_sdram_cfg); + + asm("sync;isync;msync"); + udelay(500); +} + +#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER) +/* + * Initialize all of memory for ECC, then enable errors. + */ + +void +ddr_enable_ecc(unsigned int dram_size) +{ + volatile ccsr_ddr_t *ddr = (void *)(CONFIG_SYS_FSL_DDR_ADDR); + + dma_meminit(CONFIG_MEM_INIT_VALUE, dram_size); + + /* + * Enable errors for ECC. + */ + debug("DMA DDR: err_disable = 0x%08x\n", ddr->err_disable); + ddr->err_disable = 0x00000000; + asm("sync;isync;msync"); + debug("DMA DDR: err_disable = 0x%08x\n", ddr->err_disable); +} + +#endif /* CONFIG_DDR_ECC && ! CONFIG_ECC_INIT_VIA_DDRCONTROLLER */ diff --git a/drivers/ddr/fsl/mpc85xx_ddr_gen2.c b/drivers/ddr/fsl/mpc85xx_ddr_gen2.c new file mode 100644 index 0000000..c22dea5 --- /dev/null +++ b/drivers/ddr/fsl/mpc85xx_ddr_gen2.c @@ -0,0 +1,95 @@ +/* + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4) +#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL +#endif + +void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, + unsigned int ctrl_num, int step) +{ + unsigned int i; + ccsr_ddr_t *ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR; + +#if defined(CONFIG_SYS_FSL_ERRATUM_NMG_DDR120) && defined(CONFIG_MPC85xx) + ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); + uint svr; +#endif + + if (ctrl_num) { + printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num); + return; + } + +#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_DDR120 + /* + * Set the DDR IO receiver to an acceptable bias point. + * Fixed in Rev 2.1. + */ + svr = get_svr(); + if ((SVR_MAJ(svr) == 1) || IS_SVR_REV(svr, 2, 0)) { + if ((regs->ddr_sdram_cfg & SDRAM_CFG_SDRAM_TYPE_MASK) == + SDRAM_CFG_SDRAM_TYPE_DDR2) + out_be32(&gur->ddrioovcr, 0x90000000); + else + out_be32(&gur->ddrioovcr, 0xA8000000); + } +#endif + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (i == 0) { + out_be32(&ddr->cs0_bnds, regs->cs[i].bnds); + out_be32(&ddr->cs0_config, regs->cs[i].config); + + } else if (i == 1) { + out_be32(&ddr->cs1_bnds, regs->cs[i].bnds); + out_be32(&ddr->cs1_config, regs->cs[i].config); + + } else if (i == 2) { + out_be32(&ddr->cs2_bnds, regs->cs[i].bnds); + out_be32(&ddr->cs2_config, regs->cs[i].config); + + } else if (i == 3) { + out_be32(&ddr->cs3_bnds, regs->cs[i].bnds); + out_be32(&ddr->cs3_config, regs->cs[i].config); + } + } + + out_be32(&ddr->timing_cfg_3, regs->timing_cfg_3); + out_be32(&ddr->timing_cfg_0, regs->timing_cfg_0); + out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1); + out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2); + out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2); + out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode); + out_be32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2); + out_be32(&ddr->sdram_md_cntl, regs->ddr_sdram_md_cntl); + out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval); + out_be32(&ddr->sdram_data_init, regs->ddr_data_init); + out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl); + out_be32(&ddr->init_addr, regs->ddr_init_addr); + out_be32(&ddr->init_ext_addr, regs->ddr_init_ext_addr); + + /* + * 200 painful micro-seconds must elapse between + * the DDR clock setup and the DDR config enable. + */ + udelay(200); + asm volatile("sync;isync"); + + out_be32(&ddr->sdram_cfg, regs->ddr_sdram_cfg); + + /* Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done. */ + while (in_be32(&ddr->sdram_cfg_2) & 0x10) { + udelay(10000); /* throttle polling rate */ + } +} diff --git a/drivers/ddr/fsl/mpc85xx_ddr_gen3.c b/drivers/ddr/fsl/mpc85xx_ddr_gen3.c new file mode 100644 index 0000000..7b4e8ec --- /dev/null +++ b/drivers/ddr/fsl/mpc85xx_ddr_gen3.c @@ -0,0 +1,464 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4) +#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL +#endif + + +/* + * regs has the to-be-set values for DDR controller registers + * ctrl_num is the DDR controller number + * step: 0 goes through the initialization in one pass + * 1 sets registers and returns before enabling controller + * 2 resumes from step 1 and continues to initialize + * Dividing the initialization to two steps to deassert DDR reset signal + * to comply with JEDEC specs for RDIMMs. + */ +void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, + unsigned int ctrl_num, int step) +{ + unsigned int i, bus_width; + volatile ccsr_ddr_t *ddr; + u32 temp_sdram_cfg; + u32 total_gb_size_per_controller; + int timeout; +#ifdef CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134 + int timeout_save; + volatile ccsr_local_ecm_t *ecm = (void *)CONFIG_SYS_MPC85xx_ECM_ADDR; + unsigned int csn_bnds_backup = 0, cs_sa, cs_ea, *csn_bnds_t; + int csn = -1; +#endif + + switch (ctrl_num) { + case 0: + ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR; + break; +#if defined(CONFIG_SYS_FSL_DDR2_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 1) + case 1: + ddr = (void *)CONFIG_SYS_FSL_DDR2_ADDR; + break; +#endif +#if defined(CONFIG_SYS_FSL_DDR3_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 2) + case 2: + ddr = (void *)CONFIG_SYS_FSL_DDR3_ADDR; + break; +#endif +#if defined(CONFIG_SYS_FSL_DDR4_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 3) + case 3: + ddr = (void *)CONFIG_SYS_FSL_DDR4_ADDR; + break; +#endif + default: + printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num); + return; + } + + if (step == 2) + goto step2; + + if (regs->ddr_eor) + out_be32(&ddr->eor, regs->ddr_eor); +#ifdef CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134 + debug("Workaround for ERRATUM_DDR111_DDR134\n"); + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + cs_sa = (regs->cs[i].bnds >> 16) & 0xfff; + cs_ea = regs->cs[i].bnds & 0xfff; + if ((cs_sa <= 0xff) && (cs_ea >= 0xff)) { + csn = i; + csn_bnds_backup = regs->cs[i].bnds; + csn_bnds_t = (unsigned int *) ®s->cs[i].bnds; + if (cs_ea > 0xeff) + *csn_bnds_t = regs->cs[i].bnds + 0x01000000; + else + *csn_bnds_t = regs->cs[i].bnds + 0x01000100; + debug("Found cs%d_bns (0x%08x) covering 0xff000000, " + "change it to 0x%x\n", + csn, csn_bnds_backup, regs->cs[i].bnds); + break; + } + } +#endif + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (i == 0) { + out_be32(&ddr->cs0_bnds, regs->cs[i].bnds); + out_be32(&ddr->cs0_config, regs->cs[i].config); + out_be32(&ddr->cs0_config_2, regs->cs[i].config_2); + + } else if (i == 1) { + out_be32(&ddr->cs1_bnds, regs->cs[i].bnds); + out_be32(&ddr->cs1_config, regs->cs[i].config); + out_be32(&ddr->cs1_config_2, regs->cs[i].config_2); + + } else if (i == 2) { + out_be32(&ddr->cs2_bnds, regs->cs[i].bnds); + out_be32(&ddr->cs2_config, regs->cs[i].config); + out_be32(&ddr->cs2_config_2, regs->cs[i].config_2); + + } else if (i == 3) { + out_be32(&ddr->cs3_bnds, regs->cs[i].bnds); + out_be32(&ddr->cs3_config, regs->cs[i].config); + out_be32(&ddr->cs3_config_2, regs->cs[i].config_2); + } + } + + out_be32(&ddr->timing_cfg_3, regs->timing_cfg_3); + out_be32(&ddr->timing_cfg_0, regs->timing_cfg_0); + out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1); + out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2); + out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2); + out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode); + out_be32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2); + out_be32(&ddr->sdram_mode_3, regs->ddr_sdram_mode_3); + out_be32(&ddr->sdram_mode_4, regs->ddr_sdram_mode_4); + out_be32(&ddr->sdram_mode_5, regs->ddr_sdram_mode_5); + out_be32(&ddr->sdram_mode_6, regs->ddr_sdram_mode_6); + out_be32(&ddr->sdram_mode_7, regs->ddr_sdram_mode_7); + out_be32(&ddr->sdram_mode_8, regs->ddr_sdram_mode_8); + out_be32(&ddr->sdram_md_cntl, regs->ddr_sdram_md_cntl); + out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval); + out_be32(&ddr->sdram_data_init, regs->ddr_data_init); + out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl); + out_be32(&ddr->init_addr, regs->ddr_init_addr); + out_be32(&ddr->init_ext_addr, regs->ddr_init_ext_addr); + + out_be32(&ddr->timing_cfg_4, regs->timing_cfg_4); + out_be32(&ddr->timing_cfg_5, regs->timing_cfg_5); + out_be32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl); + out_be32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl); +#ifndef CONFIG_SYS_FSL_DDR_EMU + /* + * Skip these two registers if running on emulator + * because emulator doesn't have skew between bytes. + */ + + if (regs->ddr_wrlvl_cntl_2) + out_be32(&ddr->ddr_wrlvl_cntl_2, regs->ddr_wrlvl_cntl_2); + if (regs->ddr_wrlvl_cntl_3) + out_be32(&ddr->ddr_wrlvl_cntl_3, regs->ddr_wrlvl_cntl_3); +#endif + + out_be32(&ddr->ddr_sr_cntr, regs->ddr_sr_cntr); + out_be32(&ddr->ddr_sdram_rcw_1, regs->ddr_sdram_rcw_1); + out_be32(&ddr->ddr_sdram_rcw_2, regs->ddr_sdram_rcw_2); + out_be32(&ddr->ddr_cdr1, regs->ddr_cdr1); + out_be32(&ddr->ddr_cdr2, regs->ddr_cdr2); + out_be32(&ddr->err_disable, regs->err_disable); + out_be32(&ddr->err_int_en, regs->err_int_en); + for (i = 0; i < 32; i++) { + if (regs->debug[i]) { + debug("Write to debug_%d as %08x\n", i+1, regs->debug[i]); + out_be32(&ddr->debug[i], regs->debug[i]); + } + } +#ifdef CONFIG_SYS_FSL_ERRATUM_A_004934 + out_be32(&ddr->debug[28], 0x30003000); +#endif + +#ifdef CONFIG_SYS_FSL_ERRATUM_DDR_A003474 + out_be32(&ddr->debug[12], 0x00000015); + out_be32(&ddr->debug[21], 0x24000000); +#endif /* CONFIG_SYS_FSL_ERRATUM_DDR_A003474 */ + + /* + * For RDIMMs, JEDEC spec requires clocks to be stable before reset is + * deasserted. Clocks start when any chip select is enabled and clock + * control register is set. Because all DDR components are connected to + * one reset signal, this needs to be done in two steps. Step 1 is to + * get the clocks started. Step 2 resumes after reset signal is + * deasserted. + */ + if (step == 1) { + udelay(200); + return; + } + +step2: + /* Set, but do not enable the memory */ + temp_sdram_cfg = regs->ddr_sdram_cfg; + temp_sdram_cfg &= ~(SDRAM_CFG_MEM_EN); + out_be32(&ddr->sdram_cfg, temp_sdram_cfg); +#ifdef CONFIG_SYS_FSL_ERRATUM_DDR_A003 + debug("Workaround for ERRATUM_DDR_A003\n"); + if (regs->ddr_sdram_rcw_2 & 0x00f00000) { + out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2 & 0xf07fffff); + out_be32(&ddr->debug[2], 0x00000400); + out_be32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl & 0x7fffffff); + out_be32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl & 0x7fffffff); + out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2 & 0xffffffeb); + out_be32(&ddr->mtcr, 0); + out_be32(&ddr->debug[12], 0x00000015); + out_be32(&ddr->debug[21], 0x24000000); + out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval & 0xffff); + out_be32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_BI | SDRAM_CFG_MEM_EN); + + asm volatile("sync;isync"); + while (!(in_be32(&ddr->debug[1]) & 0x2)) + ; + + switch (regs->ddr_sdram_rcw_2 & 0x00f00000) { + case 0x00000000: + out_be32(&ddr->sdram_md_cntl, + MD_CNTL_MD_EN | + MD_CNTL_CS_SEL_CS0_CS1 | + 0x04000000 | + MD_CNTL_WRCW | + MD_CNTL_MD_VALUE(0x02)); + break; + case 0x00100000: + out_be32(&ddr->sdram_md_cntl, + MD_CNTL_MD_EN | + MD_CNTL_CS_SEL_CS0_CS1 | + 0x04000000 | + MD_CNTL_WRCW | + MD_CNTL_MD_VALUE(0x0a)); + break; + case 0x00200000: + out_be32(&ddr->sdram_md_cntl, + MD_CNTL_MD_EN | + MD_CNTL_CS_SEL_CS0_CS1 | + 0x04000000 | + MD_CNTL_WRCW | + MD_CNTL_MD_VALUE(0x12)); + break; + case 0x00300000: + out_be32(&ddr->sdram_md_cntl, + MD_CNTL_MD_EN | + MD_CNTL_CS_SEL_CS0_CS1 | + 0x04000000 | + MD_CNTL_WRCW | + MD_CNTL_MD_VALUE(0x1a)); + break; + default: + out_be32(&ddr->sdram_md_cntl, + MD_CNTL_MD_EN | + MD_CNTL_CS_SEL_CS0_CS1 | + 0x04000000 | + MD_CNTL_WRCW | + MD_CNTL_MD_VALUE(0x02)); + printf("Unsupported RC10\n"); + break; + } + + while (in_be32(&ddr->sdram_md_cntl) & 0x80000000) + ; + udelay(6); + out_be32(&ddr->sdram_cfg, temp_sdram_cfg); + out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2); + out_be32(&ddr->debug[2], 0x0); + out_be32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl); + out_be32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl); + out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2); + out_be32(&ddr->debug[12], 0x0); + out_be32(&ddr->debug[21], 0x0); + out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval); + + } +#endif + /* + * For 8572 DDR1 erratum - DDR controller may enter illegal state + * when operatiing in 32-bit bus mode with 4-beat bursts, + * This erratum does not affect DDR3 mode, only for DDR2 mode. + */ +#ifdef CONFIG_SYS_FSL_ERRATUM_DDR_115 + debug("Workaround for ERRATUM_DDR_115\n"); + if ((((in_be32(&ddr->sdram_cfg) >> 24) & 0x7) == SDRAM_TYPE_DDR2) + && in_be32(&ddr->sdram_cfg) & 0x80000) { + /* set DEBUG_1[31] */ + setbits_be32(&ddr->debug[0], 1); + } +#endif +#ifdef CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134 + debug("Workaround for ERRATUM_DDR111_DDR134\n"); + /* + * This is the combined workaround for DDR111 and DDR134 + * following the published errata for MPC8572 + */ + + /* 1. Set EEBACR[3] */ + setbits_be32(&ecm->eebacr, 0x10000000); + debug("Setting EEBACR[3] to 0x%08x\n", in_be32(&ecm->eebacr)); + + /* 2. Set DINIT in SDRAM_CFG_2*/ + setbits_be32(&ddr->sdram_cfg_2, SDRAM_CFG2_D_INIT); + debug("Setting sdram_cfg_2[D_INIT] to 0x%08x\n", + in_be32(&ddr->sdram_cfg_2)); + + /* 3. Set DEBUG_3[21] */ + setbits_be32(&ddr->debug[2], 0x400); + debug("Setting DEBUG_3[21] to 0x%08x\n", in_be32(&ddr->debug[2])); + +#endif /* part 1 of the workaound */ + + /* + * 500 painful micro-seconds must elapse between + * the DDR clock setup and the DDR config enable. + * DDR2 need 200 us, and DDR3 need 500 us from spec, + * we choose the max, that is 500 us for all of case. + */ + udelay(500); + asm volatile("sync;isync"); + + /* Let the controller go */ + temp_sdram_cfg = in_be32(&ddr->sdram_cfg) & ~SDRAM_CFG_BI; + out_be32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_MEM_EN); + asm volatile("sync;isync"); + + total_gb_size_per_controller = 0; + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (!(regs->cs[i].config & 0x80000000)) + continue; + total_gb_size_per_controller += 1 << ( + ((regs->cs[i].config >> 14) & 0x3) + 2 + + ((regs->cs[i].config >> 8) & 0x7) + 12 + + ((regs->cs[i].config >> 0) & 0x7) + 8 + + 3 - ((regs->ddr_sdram_cfg >> 19) & 0x3) - + 26); /* minus 26 (count of 64M) */ + } + if (fsl_ddr_get_intl3r() & 0x80000000) /* 3-way interleaving */ + total_gb_size_per_controller *= 3; + else if (regs->cs[0].config & 0x20000000) /* 2-way interleaving */ + total_gb_size_per_controller <<= 1; + /* + * total memory / bus width = transactions needed + * transactions needed / data rate = seconds + * to add plenty of buffer, double the time + * For example, 2GB on 666MT/s 64-bit bus takes about 402ms + * Let's wait for 800ms + */ + bus_width = 3 - ((ddr->sdram_cfg & SDRAM_CFG_DBW_MASK) + >> SDRAM_CFG_DBW_SHIFT); + timeout = ((total_gb_size_per_controller << (6 - bus_width)) * 100 / + (get_ddr_freq(0) >> 20)) << 1; +#ifdef CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134 + timeout_save = timeout; +#endif + total_gb_size_per_controller >>= 4; /* shift down to gb size */ + debug("total %d GB\n", total_gb_size_per_controller); + debug("Need to wait up to %d * 10ms\n", timeout); + + /* Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done. */ + while ((in_be32(&ddr->sdram_cfg_2) & SDRAM_CFG2_D_INIT) && + (timeout >= 0)) { + udelay(10000); /* throttle polling rate */ + timeout--; + } + + if (timeout <= 0) + printf("Waiting for D_INIT timeout. Memory may not work.\n"); + +#ifdef CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134 + /* continue this workaround */ + + /* 4. Clear DEBUG3[21] */ + clrbits_be32(&ddr->debug[2], 0x400); + debug("Clearing D3[21] to 0x%08x\n", in_be32(&ddr->debug[2])); + + /* DDR134 workaround starts */ + /* A: Clear sdram_cfg_2[odt_cfg] */ + clrbits_be32(&ddr->sdram_cfg_2, SDRAM_CFG2_ODT_CFG_MASK); + debug("Clearing SDRAM_CFG2[ODT_CFG] to 0x%08x\n", + in_be32(&ddr->sdram_cfg_2)); + + /* B: Set DEBUG1[15] */ + setbits_be32(&ddr->debug[0], 0x10000); + debug("Setting D1[15] to 0x%08x\n", in_be32(&ddr->debug[0])); + + /* C: Set timing_cfg_2[cpo] to 0b11111 */ + setbits_be32(&ddr->timing_cfg_2, TIMING_CFG_2_CPO_MASK); + debug("Setting TMING_CFG_2[CPO] to 0x%08x\n", + in_be32(&ddr->timing_cfg_2)); + + /* D: Set D6 to 0x9f9f9f9f */ + out_be32(&ddr->debug[5], 0x9f9f9f9f); + debug("Setting D6 to 0x%08x\n", in_be32(&ddr->debug[5])); + + /* E: Set D7 to 0x9f9f9f9f */ + out_be32(&ddr->debug[6], 0x9f9f9f9f); + debug("Setting D7 to 0x%08x\n", in_be32(&ddr->debug[6])); + + /* F: Set D2[20] */ + setbits_be32(&ddr->debug[1], 0x800); + debug("Setting D2[20] to 0x%08x\n", in_be32(&ddr->debug[1])); + + /* G: Poll on D2[20] until cleared */ + while (in_be32(&ddr->debug[1]) & 0x800) + udelay(10000); /* throttle polling rate */ + + /* H: Clear D1[15] */ + clrbits_be32(&ddr->debug[0], 0x10000); + debug("Setting D1[15] to 0x%08x\n", in_be32(&ddr->debug[0])); + + /* I: Set sdram_cfg_2[odt_cfg] */ + setbits_be32(&ddr->sdram_cfg_2, + regs->ddr_sdram_cfg_2 & SDRAM_CFG2_ODT_CFG_MASK); + debug("Setting sdram_cfg_2 to 0x%08x\n", in_be32(&ddr->sdram_cfg_2)); + + /* Continuing with the DDR111 workaround */ + /* 5. Set D2[21] */ + setbits_be32(&ddr->debug[1], 0x400); + debug("Setting D2[21] to 0x%08x\n", in_be32(&ddr->debug[1])); + + /* 6. Poll D2[21] until its cleared */ + while (in_be32(&ddr->debug[1]) & 0x400) + udelay(10000); /* throttle polling rate */ + + /* 7. Wait for state machine 2nd run, roughly 400ms/GB */ + debug("Wait for %d * 10ms\n", timeout_save); + udelay(timeout_save * 10000); + + /* 8. Set sdram_cfg_2[dinit] if options requires */ + setbits_be32(&ddr->sdram_cfg_2, + regs->ddr_sdram_cfg_2 & SDRAM_CFG2_D_INIT); + debug("Setting sdram_cfg_2 to 0x%08x\n", in_be32(&ddr->sdram_cfg_2)); + + /* 9. Poll until dinit is cleared */ + timeout = timeout_save; + debug("Need to wait up to %d * 10ms\n", timeout); + while ((in_be32(&ddr->sdram_cfg_2) & SDRAM_CFG2_D_INIT) && + (timeout >= 0)) { + udelay(10000); /* throttle polling rate */ + timeout--; + } + + if (timeout <= 0) + printf("Waiting for D_INIT timeout. Memory may not work.\n"); + + /* 10. Clear EEBACR[3] */ + clrbits_be32(&ecm->eebacr, 10000000); + debug("Clearing EEBACR[3] to 0x%08x\n", in_be32(&ecm->eebacr)); + + if (csn != -1) { + csn_bnds_t = (unsigned int *) ®s->cs[csn].bnds; + *csn_bnds_t = csn_bnds_backup; + debug("Change cs%d_bnds back to 0x%08x\n", + csn, regs->cs[csn].bnds); + setbits_be32(&ddr->sdram_cfg, 0x2); /* MEM_HALT */ + switch (csn) { + case 0: + out_be32(&ddr->cs0_bnds, regs->cs[csn].bnds); + break; + case 1: + out_be32(&ddr->cs1_bnds, regs->cs[csn].bnds); + break; + case 2: + out_be32(&ddr->cs2_bnds, regs->cs[csn].bnds); + break; + case 3: + out_be32(&ddr->cs3_bnds, regs->cs[csn].bnds); + break; + } + clrbits_be32(&ddr->sdram_cfg, 0x2); + } +#endif /* CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134 */ +} diff --git a/drivers/ddr/fsl/mpc86xx_ddr.c b/drivers/ddr/fsl/mpc86xx_ddr.c new file mode 100644 index 0000000..caffbaf --- /dev/null +++ b/drivers/ddr/fsl/mpc86xx_ddr.c @@ -0,0 +1,85 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include +#include +#include + +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4) +#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL +#endif + +void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, + unsigned int ctrl_num, int step) +{ + unsigned int i; + volatile ccsr_ddr_t *ddr; + + switch (ctrl_num) { + case 0: + ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR; + break; + case 1: + ddr = (void *)CONFIG_SYS_FSL_DDR2_ADDR; + break; + default: + printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num); + return; + } + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (i == 0) { + out_be32(&ddr->cs0_bnds, regs->cs[i].bnds); + out_be32(&ddr->cs0_config, regs->cs[i].config); + + } else if (i == 1) { + out_be32(&ddr->cs1_bnds, regs->cs[i].bnds); + out_be32(&ddr->cs1_config, regs->cs[i].config); + + } else if (i == 2) { + out_be32(&ddr->cs2_bnds, regs->cs[i].bnds); + out_be32(&ddr->cs2_config, regs->cs[i].config); + + } else if (i == 3) { + out_be32(&ddr->cs3_bnds, regs->cs[i].bnds); + out_be32(&ddr->cs3_config, regs->cs[i].config); + } + } + + out_be32(&ddr->timing_cfg_3, regs->timing_cfg_3); + out_be32(&ddr->timing_cfg_0, regs->timing_cfg_0); + out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1); + out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2); + out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2); + out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode); + out_be32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2); + out_be32(&ddr->sdram_mode_cntl, regs->ddr_sdram_md_cntl); + out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval); + out_be32(&ddr->sdram_data_init, regs->ddr_data_init); + out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl); + out_be32(&ddr->init_addr, regs->ddr_init_addr); + out_be32(&ddr->init_ext_addr, regs->ddr_init_ext_addr); + + debug("before go\n"); + + /* + * 200 painful micro-seconds must elapse between + * the DDR clock setup and the DDR config enable. + */ + udelay(200); + asm volatile("sync;isync"); + + out_be32(&ddr->sdram_cfg, regs->ddr_sdram_cfg); + + /* + * Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done + */ + while (in_be32(&ddr->sdram_cfg_2) & 0x10) { + udelay(10000); /* throttle polling rate */ + } +} diff --git a/drivers/ddr/fsl/options.c b/drivers/ddr/fsl/options.c new file mode 100644 index 0000000..4aafcce --- /dev/null +++ b/drivers/ddr/fsl/options.c @@ -0,0 +1,1147 @@ +/* + * Copyright 2008, 2010-2012 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +#include + +/* + * Use our own stack based buffer before relocation to allow accessing longer + * hwconfig strings that might be in the environment before we've relocated. + * This is pretty fragile on both the use of stack and if the buffer is big + * enough. However we will get a warning from getenv_f for the later. + */ + +/* Board-specific functions defined in each board's ddr.c */ +extern void fsl_ddr_board_options(memctl_options_t *popts, + dimm_params_t *pdimm, + unsigned int ctrl_num); + +struct dynamic_odt { + unsigned int odt_rd_cfg; + unsigned int odt_wr_cfg; + unsigned int odt_rtt_norm; + unsigned int odt_rtt_wr; +}; + +#ifdef CONFIG_SYS_FSL_DDR3 +static const struct dynamic_odt single_Q[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS_AND_OTHER_DIMM, + DDR3_RTT_20_OHM, + DDR3_RTT_120_OHM + }, + { /* cs1 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, /* tied high */ + DDR3_RTT_OFF, + DDR3_RTT_120_OHM + }, + { /* cs2 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS_AND_OTHER_DIMM, + DDR3_RTT_20_OHM, + DDR3_RTT_120_OHM + }, + { /* cs3 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, /* tied high */ + DDR3_RTT_OFF, + DDR3_RTT_120_OHM + } +}; + +static const struct dynamic_odt single_D[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_ALL, + DDR3_RTT_40_OHM, + DDR3_RTT_OFF + }, + { /* cs1 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, + DDR3_RTT_OFF, + DDR3_RTT_OFF + }, + {0, 0, 0, 0}, + {0, 0, 0, 0} +}; + +static const struct dynamic_odt single_S[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_ALL, + DDR3_RTT_40_OHM, + DDR3_RTT_OFF + }, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, +}; + +static const struct dynamic_odt dual_DD[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_SAME_DIMM, + DDR3_RTT_120_OHM, + DDR3_RTT_OFF + }, + { /* cs1 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_OTHER_DIMM, + DDR3_RTT_30_OHM, + DDR3_RTT_OFF + }, + { /* cs2 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_SAME_DIMM, + DDR3_RTT_120_OHM, + DDR3_RTT_OFF + }, + { /* cs3 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_OTHER_DIMM, + DDR3_RTT_30_OHM, + DDR3_RTT_OFF + } +}; + +static const struct dynamic_odt dual_DS[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_SAME_DIMM, + DDR3_RTT_120_OHM, + DDR3_RTT_OFF + }, + { /* cs1 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_OTHER_DIMM, + DDR3_RTT_30_OHM, + DDR3_RTT_OFF + }, + { /* cs2 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_ALL, + DDR3_RTT_20_OHM, + DDR3_RTT_120_OHM + }, + {0, 0, 0, 0} +}; +static const struct dynamic_odt dual_SD[4] = { + { /* cs0 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_ALL, + DDR3_RTT_20_OHM, + DDR3_RTT_120_OHM + }, + {0, 0, 0, 0}, + { /* cs2 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_SAME_DIMM, + DDR3_RTT_120_OHM, + DDR3_RTT_OFF + }, + { /* cs3 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_OTHER_DIMM, + DDR3_RTT_20_OHM, + DDR3_RTT_OFF + } +}; + +static const struct dynamic_odt dual_SS[4] = { + { /* cs0 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_ALL, + DDR3_RTT_30_OHM, + DDR3_RTT_120_OHM + }, + {0, 0, 0, 0}, + { /* cs2 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_ALL, + DDR3_RTT_30_OHM, + DDR3_RTT_120_OHM + }, + {0, 0, 0, 0} +}; + +static const struct dynamic_odt dual_D0[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_SAME_DIMM, + DDR3_RTT_40_OHM, + DDR3_RTT_OFF + }, + { /* cs1 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, + DDR3_RTT_OFF, + DDR3_RTT_OFF + }, + {0, 0, 0, 0}, + {0, 0, 0, 0} +}; + +static const struct dynamic_odt dual_0D[4] = { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + { /* cs2 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_SAME_DIMM, + DDR3_RTT_40_OHM, + DDR3_RTT_OFF + }, + { /* cs3 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, + DDR3_RTT_OFF, + DDR3_RTT_OFF + } +}; + +static const struct dynamic_odt dual_S0[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR3_RTT_40_OHM, + DDR3_RTT_OFF + }, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + +}; + +static const struct dynamic_odt dual_0S[4] = { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + { /* cs2 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR3_RTT_40_OHM, + DDR3_RTT_OFF + }, + {0, 0, 0, 0} + +}; + +static const struct dynamic_odt odt_unknown[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR3_RTT_120_OHM, + DDR3_RTT_OFF + }, + { /* cs1 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR3_RTT_120_OHM, + DDR3_RTT_OFF + }, + { /* cs2 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR3_RTT_120_OHM, + DDR3_RTT_OFF + }, + { /* cs3 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR3_RTT_120_OHM, + DDR3_RTT_OFF + } +}; +#else /* CONFIG_SYS_FSL_DDR3 */ +static const struct dynamic_odt single_Q[4] = { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} +}; + +static const struct dynamic_odt single_D[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_ALL, + DDR2_RTT_150_OHM, + DDR2_RTT_OFF + }, + { /* cs1 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, + DDR2_RTT_OFF, + DDR2_RTT_OFF + }, + {0, 0, 0, 0}, + {0, 0, 0, 0} +}; + +static const struct dynamic_odt single_S[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_ALL, + DDR2_RTT_150_OHM, + DDR2_RTT_OFF + }, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, +}; + +static const struct dynamic_odt dual_DD[4] = { + { /* cs0 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_OTHER_DIMM, + DDR2_RTT_75_OHM, + DDR2_RTT_OFF + }, + { /* cs1 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, + DDR2_RTT_OFF, + DDR2_RTT_OFF + }, + { /* cs2 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_OTHER_DIMM, + DDR2_RTT_75_OHM, + DDR2_RTT_OFF + }, + { /* cs3 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, + DDR2_RTT_OFF, + DDR2_RTT_OFF + } +}; + +static const struct dynamic_odt dual_DS[4] = { + { /* cs0 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_OTHER_DIMM, + DDR2_RTT_75_OHM, + DDR2_RTT_OFF + }, + { /* cs1 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, + DDR2_RTT_OFF, + DDR2_RTT_OFF + }, + { /* cs2 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_OTHER_DIMM, + DDR2_RTT_75_OHM, + DDR2_RTT_OFF + }, + {0, 0, 0, 0} +}; + +static const struct dynamic_odt dual_SD[4] = { + { /* cs0 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_OTHER_DIMM, + DDR2_RTT_75_OHM, + DDR2_RTT_OFF + }, + {0, 0, 0, 0}, + { /* cs2 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_OTHER_DIMM, + DDR2_RTT_75_OHM, + DDR2_RTT_OFF + }, + { /* cs3 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, + DDR2_RTT_OFF, + DDR2_RTT_OFF + } +}; + +static const struct dynamic_odt dual_SS[4] = { + { /* cs0 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_OTHER_DIMM, + DDR2_RTT_75_OHM, + DDR2_RTT_OFF + }, + {0, 0, 0, 0}, + { /* cs2 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_OTHER_DIMM, + DDR2_RTT_75_OHM, + DDR2_RTT_OFF + }, + {0, 0, 0, 0} +}; + +static const struct dynamic_odt dual_D0[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_ALL, + DDR2_RTT_150_OHM, + DDR2_RTT_OFF + }, + { /* cs1 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, + DDR2_RTT_OFF, + DDR2_RTT_OFF + }, + {0, 0, 0, 0}, + {0, 0, 0, 0} +}; + +static const struct dynamic_odt dual_0D[4] = { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + { /* cs2 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_ALL, + DDR2_RTT_150_OHM, + DDR2_RTT_OFF + }, + { /* cs3 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, + DDR2_RTT_OFF, + DDR2_RTT_OFF + } +}; + +static const struct dynamic_odt dual_S0[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR2_RTT_150_OHM, + DDR2_RTT_OFF + }, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + +}; + +static const struct dynamic_odt dual_0S[4] = { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + { /* cs2 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR2_RTT_150_OHM, + DDR2_RTT_OFF + }, + {0, 0, 0, 0} + +}; + +static const struct dynamic_odt odt_unknown[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR2_RTT_75_OHM, + DDR2_RTT_OFF + }, + { /* cs1 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, + DDR2_RTT_OFF, + DDR2_RTT_OFF + }, + { /* cs2 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR2_RTT_75_OHM, + DDR2_RTT_OFF + }, + { /* cs3 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, + DDR2_RTT_OFF, + DDR2_RTT_OFF + } +}; +#endif + +/* + * Automatically seleect bank interleaving mode based on DIMMs + * in this order: cs0_cs1_cs2_cs3, cs0_cs1, null. + * This function only deal with one or two slots per controller. + */ +static inline unsigned int auto_bank_intlv(dimm_params_t *pdimm) +{ +#if (CONFIG_DIMM_SLOTS_PER_CTLR == 1) + if (pdimm[0].n_ranks == 4) + return FSL_DDR_CS0_CS1_CS2_CS3; + else if (pdimm[0].n_ranks == 2) + return FSL_DDR_CS0_CS1; +#elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2) +#ifdef CONFIG_FSL_DDR_FIRST_SLOT_QUAD_CAPABLE + if (pdimm[0].n_ranks == 4) + return FSL_DDR_CS0_CS1_CS2_CS3; +#endif + if (pdimm[0].n_ranks == 2) { + if (pdimm[1].n_ranks == 2) + return FSL_DDR_CS0_CS1_CS2_CS3; + else + return FSL_DDR_CS0_CS1; + } +#endif + return 0; +} + +unsigned int populate_memctl_options(int all_dimms_registered, + memctl_options_t *popts, + dimm_params_t *pdimm, + unsigned int ctrl_num) +{ + unsigned int i; + char buffer[HWCONFIG_BUFFER_SIZE]; + char *buf = NULL; +#if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR2) + const struct dynamic_odt *pdodt = odt_unknown; +#endif + ulong ddr_freq; + + /* + * Extract hwconfig from environment since we have not properly setup + * the environment but need it for ddr config params + */ + if (getenv_f("hwconfig", buffer, sizeof(buffer)) > 0) + buf = buffer; + +#if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR2) + /* Chip select options. */ + if (CONFIG_DIMM_SLOTS_PER_CTLR == 1) { + switch (pdimm[0].n_ranks) { + case 1: + pdodt = single_S; + break; + case 2: + pdodt = single_D; + break; + case 4: + pdodt = single_Q; + break; + } + } else if (CONFIG_DIMM_SLOTS_PER_CTLR == 2) { + switch (pdimm[0].n_ranks) { +#ifdef CONFIG_FSL_DDR_FIRST_SLOT_QUAD_CAPABLE + case 4: + pdodt = single_Q; + if (pdimm[1].n_ranks) + printf("Error: Quad- and Dual-rank DIMMs " + "cannot be used together\n"); + break; +#endif + case 2: + switch (pdimm[1].n_ranks) { + case 2: + pdodt = dual_DD; + break; + case 1: + pdodt = dual_DS; + break; + case 0: + pdodt = dual_D0; + break; + } + break; + case 1: + switch (pdimm[1].n_ranks) { + case 2: + pdodt = dual_SD; + break; + case 1: + pdodt = dual_SS; + break; + case 0: + pdodt = dual_S0; + break; + } + break; + case 0: + switch (pdimm[1].n_ranks) { + case 2: + pdodt = dual_0D; + break; + case 1: + pdodt = dual_0S; + break; + } + break; + } + } +#endif + + /* Pick chip-select local options. */ + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { +#if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR2) + popts->cs_local_opts[i].odt_rd_cfg = pdodt[i].odt_rd_cfg; + popts->cs_local_opts[i].odt_wr_cfg = pdodt[i].odt_wr_cfg; + popts->cs_local_opts[i].odt_rtt_norm = pdodt[i].odt_rtt_norm; + popts->cs_local_opts[i].odt_rtt_wr = pdodt[i].odt_rtt_wr; +#else + popts->cs_local_opts[i].odt_rd_cfg = FSL_DDR_ODT_NEVER; + popts->cs_local_opts[i].odt_wr_cfg = FSL_DDR_ODT_CS; +#endif + popts->cs_local_opts[i].auto_precharge = 0; + } + + /* Pick interleaving mode. */ + + /* + * 0 = no interleaving + * 1 = interleaving between 2 controllers + */ + popts->memctl_interleaving = 0; + + /* + * 0 = cacheline + * 1 = page + * 2 = (logical) bank + * 3 = superbank (only if CS interleaving is enabled) + */ + popts->memctl_interleaving_mode = 0; + + /* + * 0: cacheline: bit 30 of the 36-bit physical addr selects the memctl + * 1: page: bit to the left of the column bits selects the memctl + * 2: bank: bit to the left of the bank bits selects the memctl + * 3: superbank: bit to the left of the chip select selects the memctl + * + * NOTE: ba_intlv (rank interleaving) is independent of memory + * controller interleaving; it is only within a memory controller. + * Must use superbank interleaving if rank interleaving is used and + * memory controller interleaving is enabled. + */ + + /* + * 0 = no + * 0x40 = CS0,CS1 + * 0x20 = CS2,CS3 + * 0x60 = CS0,CS1 + CS2,CS3 + * 0x04 = CS0,CS1,CS2,CS3 + */ + popts->ba_intlv_ctl = 0; + + /* Memory Organization Parameters */ + popts->registered_dimm_en = all_dimms_registered; + + /* Operational Mode Paramters */ + + /* Pick ECC modes */ + popts->ecc_mode = 0; /* 0 = disabled, 1 = enabled */ +#ifdef CONFIG_DDR_ECC + if (hwconfig_sub_f("fsl_ddr", "ecc", buf)) { + if (hwconfig_subarg_cmp_f("fsl_ddr", "ecc", "on", buf)) + popts->ecc_mode = 1; + } else + popts->ecc_mode = 1; +#endif + popts->ecc_init_using_memctl = 1; /* 0 = use DMA, 1 = use memctl */ + + /* + * Choose DQS config + * 0 for DDR1 + * 1 for DDR2 + */ +#if defined(CONFIG_SYS_FSL_DDR1) + popts->dqs_config = 0; +#elif defined(CONFIG_SYS_FSL_DDR2) || defined(CONFIG_SYS_FSL_DDR3) + popts->dqs_config = 1; +#endif + + /* Choose self-refresh during sleep. */ + popts->self_refresh_in_sleep = 1; + + /* Choose dynamic power management mode. */ + popts->dynamic_power = 0; + + /* + * check first dimm for primary sdram width + * presuming all dimms are similar + * 0 = 64-bit, 1 = 32-bit, 2 = 16-bit + */ +#if defined(CONFIG_SYS_FSL_DDR1) || defined(CONFIG_SYS_FSL_DDR2) + if (pdimm[0].n_ranks != 0) { + if ((pdimm[0].data_width >= 64) && \ + (pdimm[0].data_width <= 72)) + popts->data_bus_width = 0; + else if ((pdimm[0].data_width >= 32) || \ + (pdimm[0].data_width <= 40)) + popts->data_bus_width = 1; + else { + panic("Error: data width %u is invalid!\n", + pdimm[0].data_width); + } + } +#else + if (pdimm[0].n_ranks != 0) { + if (pdimm[0].primary_sdram_width == 64) + popts->data_bus_width = 0; + else if (pdimm[0].primary_sdram_width == 32) + popts->data_bus_width = 1; + else if (pdimm[0].primary_sdram_width == 16) + popts->data_bus_width = 2; + else { + panic("Error: primary sdram width %u is invalid!\n", + pdimm[0].primary_sdram_width); + } + } +#endif + + popts->x4_en = (pdimm[0].device_width == 4) ? 1 : 0; + + /* Choose burst length. */ +#if defined(CONFIG_SYS_FSL_DDR3) +#if defined(CONFIG_E500MC) + popts->otf_burst_chop_en = 0; /* on-the-fly burst chop disable */ + popts->burst_length = DDR_BL8; /* Fixed 8-beat burst len */ +#else + if ((popts->data_bus_width == 1) || (popts->data_bus_width == 2)) { + /* 32-bit or 16-bit bus */ + popts->otf_burst_chop_en = 0; + popts->burst_length = DDR_BL8; + } else { + popts->otf_burst_chop_en = 1; /* on-the-fly burst chop */ + popts->burst_length = DDR_OTF; /* on-the-fly BC4 and BL8 */ + } +#endif +#else + popts->burst_length = DDR_BL4; /* has to be 4 for DDR2 */ +#endif + + /* Choose ddr controller address mirror mode */ +#if defined(CONFIG_SYS_FSL_DDR3) + popts->mirrored_dimm = pdimm[0].mirrored_dimm; +#endif + + /* Global Timing Parameters. */ + debug("mclk_ps = %u ps\n", get_memory_clk_period_ps()); + + /* Pick a caslat override. */ + popts->cas_latency_override = 0; + popts->cas_latency_override_value = 3; + if (popts->cas_latency_override) { + debug("using caslat override value = %u\n", + popts->cas_latency_override_value); + } + + /* Decide whether to use the computed derated latency */ + popts->use_derated_caslat = 0; + + /* Choose an additive latency. */ + popts->additive_latency_override = 0; + popts->additive_latency_override_value = 3; + if (popts->additive_latency_override) { + debug("using additive latency override value = %u\n", + popts->additive_latency_override_value); + } + + /* + * 2T_EN setting + * + * Factors to consider for 2T_EN: + * - number of DIMMs installed + * - number of components, number of active ranks + * - how much time you want to spend playing around + */ + popts->twot_en = 0; + popts->threet_en = 0; + + /* for RDIMM, address parity enable */ + popts->ap_en = 1; + + /* + * BSTTOPRE precharge interval + * + * Set this to 0 for global auto precharge + * + * FIXME: Should this be configured in picoseconds? + * Why it should be in ps: better understanding of this + * relative to actual DRAM timing parameters such as tRAS. + * e.g. tRAS(min) = 40 ns + */ + popts->bstopre = 0x100; + + /* Minimum CKE pulse width -- tCKE(MIN) */ + popts->tcke_clock_pulse_width_ps + = mclk_to_picos(FSL_DDR_MIN_TCKE_PULSE_WIDTH_DDR); + + /* + * Window for four activates -- tFAW + * + * FIXME: UM: applies only to DDR2/DDR3 with eight logical banks only + * FIXME: varies depending upon number of column addresses or data + * FIXME: width, was considering looking at pdimm->primary_sdram_width + */ +#if defined(CONFIG_SYS_FSL_DDR1) + popts->tfaw_window_four_activates_ps = mclk_to_picos(1); + +#elif defined(CONFIG_SYS_FSL_DDR2) + /* + * x4/x8; some datasheets have 35000 + * x16 wide columns only? Use 50000? + */ + popts->tfaw_window_four_activates_ps = 37500; + +#elif defined(CONFIG_SYS_FSL_DDR3) + popts->tfaw_window_four_activates_ps = pdimm[0].tfaw_ps; +#endif + popts->zq_en = 0; + popts->wrlvl_en = 0; +#if defined(CONFIG_SYS_FSL_DDR3) + /* + * due to ddr3 dimm is fly-by topology + * we suggest to enable write leveling to + * meet the tQDSS under different loading. + */ + popts->wrlvl_en = 1; + popts->zq_en = 1; + popts->wrlvl_override = 0; +#endif + + /* + * Check interleaving configuration from environment. + * Please refer to doc/README.fsl-ddr for the detail. + * + * If memory controller interleaving is enabled, then the data + * bus widths must be programmed identically for all memory controllers. + * + * XXX: Attempt to set all controllers to the same chip select + * interleaving mode. It will do a best effort to get the + * requested ranks interleaved together such that the result + * should be a subset of the requested configuration. + */ +#if (CONFIG_NUM_DDR_CONTROLLERS > 1) + if (!hwconfig_sub_f("fsl_ddr", "ctlr_intlv", buf)) + goto done; + + if (pdimm[0].n_ranks == 0) { + printf("There is no rank on CS0 for controller %d.\n", ctrl_num); + popts->memctl_interleaving = 0; + goto done; + } + popts->memctl_interleaving = 1; + /* + * test null first. if CONFIG_HWCONFIG is not defined + * hwconfig_arg_cmp returns non-zero + */ + if (hwconfig_subarg_cmp_f("fsl_ddr", "ctlr_intlv", + "null", buf)) { + popts->memctl_interleaving = 0; + debug("memory controller interleaving disabled.\n"); + } else if (hwconfig_subarg_cmp_f("fsl_ddr", + "ctlr_intlv", + "cacheline", buf)) { + popts->memctl_interleaving_mode = + ((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ? + 0 : FSL_DDR_CACHE_LINE_INTERLEAVING; + popts->memctl_interleaving = + ((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ? + 0 : 1; + } else if (hwconfig_subarg_cmp_f("fsl_ddr", + "ctlr_intlv", + "page", buf)) { + popts->memctl_interleaving_mode = + ((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ? + 0 : FSL_DDR_PAGE_INTERLEAVING; + popts->memctl_interleaving = + ((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ? + 0 : 1; + } else if (hwconfig_subarg_cmp_f("fsl_ddr", + "ctlr_intlv", + "bank", buf)) { + popts->memctl_interleaving_mode = + ((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ? + 0 : FSL_DDR_BANK_INTERLEAVING; + popts->memctl_interleaving = + ((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ? + 0 : 1; + } else if (hwconfig_subarg_cmp_f("fsl_ddr", + "ctlr_intlv", + "superbank", buf)) { + popts->memctl_interleaving_mode = + ((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ? + 0 : FSL_DDR_SUPERBANK_INTERLEAVING; + popts->memctl_interleaving = + ((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ? + 0 : 1; +#if (CONFIG_NUM_DDR_CONTROLLERS == 3) + } else if (hwconfig_subarg_cmp_f("fsl_ddr", + "ctlr_intlv", + "3way_1KB", buf)) { + popts->memctl_interleaving_mode = + FSL_DDR_3WAY_1KB_INTERLEAVING; + } else if (hwconfig_subarg_cmp_f("fsl_ddr", + "ctlr_intlv", + "3way_4KB", buf)) { + popts->memctl_interleaving_mode = + FSL_DDR_3WAY_4KB_INTERLEAVING; + } else if (hwconfig_subarg_cmp_f("fsl_ddr", + "ctlr_intlv", + "3way_8KB", buf)) { + popts->memctl_interleaving_mode = + FSL_DDR_3WAY_8KB_INTERLEAVING; +#elif (CONFIG_NUM_DDR_CONTROLLERS == 4) + } else if (hwconfig_subarg_cmp_f("fsl_ddr", + "ctlr_intlv", + "4way_1KB", buf)) { + popts->memctl_interleaving_mode = + FSL_DDR_4WAY_1KB_INTERLEAVING; + } else if (hwconfig_subarg_cmp_f("fsl_ddr", + "ctlr_intlv", + "4way_4KB", buf)) { + popts->memctl_interleaving_mode = + FSL_DDR_4WAY_4KB_INTERLEAVING; + } else if (hwconfig_subarg_cmp_f("fsl_ddr", + "ctlr_intlv", + "4way_8KB", buf)) { + popts->memctl_interleaving_mode = + FSL_DDR_4WAY_8KB_INTERLEAVING; +#endif + } else { + popts->memctl_interleaving = 0; + printf("hwconfig has unrecognized parameter for ctlr_intlv.\n"); + } +done: +#endif + if ((hwconfig_sub_f("fsl_ddr", "bank_intlv", buf)) && + (CONFIG_CHIP_SELECTS_PER_CTRL > 1)) { + /* test null first. if CONFIG_HWCONFIG is not defined, + * hwconfig_subarg_cmp_f returns non-zero */ + if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv", + "null", buf)) + debug("bank interleaving disabled.\n"); + else if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv", + "cs0_cs1", buf)) + popts->ba_intlv_ctl = FSL_DDR_CS0_CS1; + else if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv", + "cs2_cs3", buf)) + popts->ba_intlv_ctl = FSL_DDR_CS2_CS3; + else if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv", + "cs0_cs1_and_cs2_cs3", buf)) + popts->ba_intlv_ctl = FSL_DDR_CS0_CS1_AND_CS2_CS3; + else if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv", + "cs0_cs1_cs2_cs3", buf)) + popts->ba_intlv_ctl = FSL_DDR_CS0_CS1_CS2_CS3; + else if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv", + "auto", buf)) + popts->ba_intlv_ctl = auto_bank_intlv(pdimm); + else + printf("hwconfig has unrecognized parameter for bank_intlv.\n"); + switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) { + case FSL_DDR_CS0_CS1_CS2_CS3: +#if (CONFIG_DIMM_SLOTS_PER_CTLR == 1) + if (pdimm[0].n_ranks < 4) { + popts->ba_intlv_ctl = 0; + printf("Not enough bank(chip-select) for " + "CS0+CS1+CS2+CS3 on controller %d, " + "interleaving disabled!\n", ctrl_num); + } +#elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2) +#ifdef CONFIG_FSL_DDR_FIRST_SLOT_QUAD_CAPABLE + if (pdimm[0].n_ranks == 4) + break; +#endif + if ((pdimm[0].n_ranks < 2) && (pdimm[1].n_ranks < 2)) { + popts->ba_intlv_ctl = 0; + printf("Not enough bank(chip-select) for " + "CS0+CS1+CS2+CS3 on controller %d, " + "interleaving disabled!\n", ctrl_num); + } + if (pdimm[0].capacity != pdimm[1].capacity) { + popts->ba_intlv_ctl = 0; + printf("Not identical DIMM size for " + "CS0+CS1+CS2+CS3 on controller %d, " + "interleaving disabled!\n", ctrl_num); + } +#endif + break; + case FSL_DDR_CS0_CS1: + if (pdimm[0].n_ranks < 2) { + popts->ba_intlv_ctl = 0; + printf("Not enough bank(chip-select) for " + "CS0+CS1 on controller %d, " + "interleaving disabled!\n", ctrl_num); + } + break; + case FSL_DDR_CS2_CS3: +#if (CONFIG_DIMM_SLOTS_PER_CTLR == 1) + if (pdimm[0].n_ranks < 4) { + popts->ba_intlv_ctl = 0; + printf("Not enough bank(chip-select) for CS2+CS3 " + "on controller %d, interleaving disabled!\n", ctrl_num); + } +#elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2) + if (pdimm[1].n_ranks < 2) { + popts->ba_intlv_ctl = 0; + printf("Not enough bank(chip-select) for CS2+CS3 " + "on controller %d, interleaving disabled!\n", ctrl_num); + } +#endif + break; + case FSL_DDR_CS0_CS1_AND_CS2_CS3: +#if (CONFIG_DIMM_SLOTS_PER_CTLR == 1) + if (pdimm[0].n_ranks < 4) { + popts->ba_intlv_ctl = 0; + printf("Not enough bank(CS) for CS0+CS1 and " + "CS2+CS3 on controller %d, " + "interleaving disabled!\n", ctrl_num); + } +#elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2) + if ((pdimm[0].n_ranks < 2) || (pdimm[1].n_ranks < 2)) { + popts->ba_intlv_ctl = 0; + printf("Not enough bank(CS) for CS0+CS1 and " + "CS2+CS3 on controller %d, " + "interleaving disabled!\n", ctrl_num); + } +#endif + break; + default: + popts->ba_intlv_ctl = 0; + break; + } + } + + if (hwconfig_sub_f("fsl_ddr", "addr_hash", buf)) { + if (hwconfig_subarg_cmp_f("fsl_ddr", "addr_hash", "null", buf)) + popts->addr_hash = 0; + else if (hwconfig_subarg_cmp_f("fsl_ddr", "addr_hash", + "true", buf)) + popts->addr_hash = 1; + } + + if (pdimm[0].n_ranks == 4) + popts->quad_rank_present = 1; + + ddr_freq = get_ddr_freq(0) / 1000000; + if (popts->registered_dimm_en) { + popts->rcw_override = 1; + popts->rcw_1 = 0x000a5a00; + if (ddr_freq <= 800) + popts->rcw_2 = 0x00000000; + else if (ddr_freq <= 1066) + popts->rcw_2 = 0x00100000; + else if (ddr_freq <= 1333) + popts->rcw_2 = 0x00200000; + else + popts->rcw_2 = 0x00300000; + } + + fsl_ddr_board_options(popts, pdimm, ctrl_num); + + return 0; +} + +void check_interleaving_options(fsl_ddr_info_t *pinfo) +{ + int i, j, k, check_n_ranks, intlv_invalid = 0; + unsigned int check_intlv, check_n_row_addr, check_n_col_addr; + unsigned long long check_rank_density; + struct dimm_params_s *dimm; + /* + * Check if all controllers are configured for memory + * controller interleaving. Identical dimms are recommended. At least + * the size, row and col address should be checked. + */ + j = 0; + check_n_ranks = pinfo->dimm_params[0][0].n_ranks; + check_rank_density = pinfo->dimm_params[0][0].rank_density; + check_n_row_addr = pinfo->dimm_params[0][0].n_row_addr; + check_n_col_addr = pinfo->dimm_params[0][0].n_col_addr; + check_intlv = pinfo->memctl_opts[0].memctl_interleaving_mode; + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + dimm = &pinfo->dimm_params[i][0]; + if (!pinfo->memctl_opts[i].memctl_interleaving) { + continue; + } else if (((check_rank_density != dimm->rank_density) || + (check_n_ranks != dimm->n_ranks) || + (check_n_row_addr != dimm->n_row_addr) || + (check_n_col_addr != dimm->n_col_addr) || + (check_intlv != + pinfo->memctl_opts[i].memctl_interleaving_mode))){ + intlv_invalid = 1; + break; + } else { + j++; + } + + } + if (intlv_invalid) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) + pinfo->memctl_opts[i].memctl_interleaving = 0; + printf("Not all DIMMs are identical. " + "Memory controller interleaving disabled.\n"); + } else { + switch (check_intlv) { + case FSL_DDR_CACHE_LINE_INTERLEAVING: + case FSL_DDR_PAGE_INTERLEAVING: + case FSL_DDR_BANK_INTERLEAVING: + case FSL_DDR_SUPERBANK_INTERLEAVING: + if (3 == CONFIG_NUM_DDR_CONTROLLERS) + k = 2; + else + k = CONFIG_NUM_DDR_CONTROLLERS; + break; + case FSL_DDR_3WAY_1KB_INTERLEAVING: + case FSL_DDR_3WAY_4KB_INTERLEAVING: + case FSL_DDR_3WAY_8KB_INTERLEAVING: + case FSL_DDR_4WAY_1KB_INTERLEAVING: + case FSL_DDR_4WAY_4KB_INTERLEAVING: + case FSL_DDR_4WAY_8KB_INTERLEAVING: + default: + k = CONFIG_NUM_DDR_CONTROLLERS; + break; + } + debug("%d of %d controllers are interleaving.\n", j, k); + if (j && (j != k)) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) + pinfo->memctl_opts[i].memctl_interleaving = 0; + printf("Not all controllers have compatible " + "interleaving mode. All disabled.\n"); + } + } + debug("Checking interleaving options completed\n"); +} + +int fsl_use_spd(void) +{ + int use_spd = 0; + +#ifdef CONFIG_DDR_SPD + char buffer[HWCONFIG_BUFFER_SIZE]; + char *buf = NULL; + + /* + * Extract hwconfig from environment since we have not properly setup + * the environment but need it for ddr config params + */ + if (getenv_f("hwconfig", buffer, sizeof(buffer)) > 0) + buf = buffer; + + /* if hwconfig is not enabled, or "sdram" is not defined, use spd */ + if (hwconfig_sub_f("fsl_ddr", "sdram", buf)) { + if (hwconfig_subarg_cmp_f("fsl_ddr", "sdram", "spd", buf)) + use_spd = 1; + else if (hwconfig_subarg_cmp_f("fsl_ddr", "sdram", + "fixed", buf)) + use_spd = 0; + else + use_spd = 1; + } else + use_spd = 1; +#endif + + return use_spd; +} diff --git a/drivers/ddr/fsl/util.c b/drivers/ddr/fsl/util.c new file mode 100644 index 0000000..45a7bcc --- /dev/null +++ b/drivers/ddr/fsl/util.c @@ -0,0 +1,265 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + */ + +#include +#include +#include + +#include +#include + +/* To avoid 64-bit full-divides, we factor this here */ +#define ULL_2E12 2000000000000ULL +#define UL_5POW12 244140625UL +#define UL_2POW13 (1UL << 13) + +#define ULL_8FS 0xFFFFFFFFULL + +/* + * Round up mclk_ps to nearest 1 ps in memory controller code + * if the error is 0.5ps or more. + * + * If an imprecise data rate is too high due to rounding error + * propagation, compute a suitably rounded mclk_ps to compute + * a working memory controller configuration. + */ +unsigned int get_memory_clk_period_ps(void) +{ + unsigned int data_rate = get_ddr_freq(0); + unsigned int result; + + /* Round to nearest 10ps, being careful about 64-bit multiply/divide */ + unsigned long long rem, mclk_ps = ULL_2E12; + + /* Now perform the big divide, the result fits in 32-bits */ + rem = do_div(mclk_ps, data_rate); + result = (rem >= (data_rate >> 1)) ? mclk_ps + 1 : mclk_ps; + + return result; +} + +/* Convert picoseconds into DRAM clock cycles (rounding up if needed). */ +unsigned int picos_to_mclk(unsigned int picos) +{ + unsigned long long clks, clks_rem; + unsigned long data_rate = get_ddr_freq(0); + + /* Short circuit for zero picos */ + if (!picos) + return 0; + + /* First multiply the time by the data rate (32x32 => 64) */ + clks = picos * (unsigned long long)data_rate; + /* + * Now divide by 5^12 and track the 32-bit remainder, then divide + * by 2*(2^12) using shifts (and updating the remainder). + */ + clks_rem = do_div(clks, UL_5POW12); + clks_rem += (clks & (UL_2POW13-1)) * UL_5POW12; + clks >>= 13; + + /* If we had a remainder greater than the 1ps error, then round up */ + if (clks_rem > data_rate) + clks++; + + /* Clamp to the maximum representable value */ + if (clks > ULL_8FS) + clks = ULL_8FS; + return (unsigned int) clks; +} + +unsigned int mclk_to_picos(unsigned int mclk) +{ + return get_memory_clk_period_ps() * mclk; +} + +void +__fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params, + unsigned int law_memctl, + unsigned int ctrl_num) +{ + unsigned long long base = memctl_common_params->base_address; + unsigned long long size = memctl_common_params->total_mem; + + /* + * If no DIMMs on this controller, do not proceed any further. + */ + if (!memctl_common_params->ndimms_present) { + return; + } + +#if !defined(CONFIG_PHYS_64BIT) + if (base >= CONFIG_MAX_MEM_MAPPED) + return; + if ((base + size) >= CONFIG_MAX_MEM_MAPPED) + size = CONFIG_MAX_MEM_MAPPED - base; +#endif + if (set_ddr_laws(base, size, law_memctl) < 0) { + printf("%s: ERROR (ctrl #%d, TRGT ID=%x)\n", __func__, ctrl_num, + law_memctl); + return ; + } + debug("setup ddr law base = 0x%llx, size 0x%llx, TRGT_ID 0x%x\n", + base, size, law_memctl); +} + +__attribute__((weak, alias("__fsl_ddr_set_lawbar"))) void +fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params, + unsigned int memctl_interleaved, + unsigned int ctrl_num); + +void fsl_ddr_set_intl3r(const unsigned int granule_size) +{ +#ifdef CONFIG_E6500 + u32 *mcintl3r = (void *) (CONFIG_SYS_IMMR + 0x18004); + *mcintl3r = 0x80000000 | (granule_size & 0x1f); + debug("Enable MCINTL3R with granule size 0x%x\n", granule_size); +#endif +} + +u32 fsl_ddr_get_intl3r(void) +{ + u32 val = 0; +#ifdef CONFIG_E6500 + u32 *mcintl3r = (void *) (CONFIG_SYS_IMMR + 0x18004); + val = *mcintl3r; +#endif + return val; +} + +void board_add_ram_info(int use_default) +{ + ccsr_ddr_t *ddr = (void *)(CONFIG_SYS_FSL_DDR_ADDR); + +#if defined(CONFIG_E6500) && (CONFIG_NUM_DDR_CONTROLLERS == 3) + u32 *mcintl3r = (void *) (CONFIG_SYS_IMMR + 0x18004); +#endif +#if (CONFIG_NUM_DDR_CONTROLLERS > 1) + uint32_t cs0_config = in_be32(&ddr->cs0_config); +#endif + uint32_t sdram_cfg = in_be32(&ddr->sdram_cfg); + int cas_lat; + +#if CONFIG_NUM_DDR_CONTROLLERS >= 2 + if (!(sdram_cfg & SDRAM_CFG_MEM_EN)) { + ddr = (void __iomem *)CONFIG_SYS_FSL_DDR2_ADDR; + sdram_cfg = in_be32(&ddr->sdram_cfg); + } +#endif +#if CONFIG_NUM_DDR_CONTROLLERS >= 3 + if (!(sdram_cfg & SDRAM_CFG_MEM_EN)) { + ddr = (void __iomem *)CONFIG_SYS_FSL_DDR3_ADDR; + sdram_cfg = in_be32(&ddr->sdram_cfg); + } +#endif + puts(" (DDR"); + switch ((sdram_cfg & SDRAM_CFG_SDRAM_TYPE_MASK) >> + SDRAM_CFG_SDRAM_TYPE_SHIFT) { + case SDRAM_TYPE_DDR1: + puts("1"); + break; + case SDRAM_TYPE_DDR2: + puts("2"); + break; + case SDRAM_TYPE_DDR3: + puts("3"); + break; + default: + puts("?"); + break; + } + + if (sdram_cfg & SDRAM_CFG_32_BE) + puts(", 32-bit"); + else if (sdram_cfg & SDRAM_CFG_16_BE) + puts(", 16-bit"); + else + puts(", 64-bit"); + + /* Calculate CAS latency based on timing cfg values */ + cas_lat = ((in_be32(&ddr->timing_cfg_1) >> 16) & 0xf) + 1; + if ((in_be32(&ddr->timing_cfg_3) >> 12) & 1) + cas_lat += (8 << 1); + printf(", CL=%d", cas_lat >> 1); + if (cas_lat & 0x1) + puts(".5"); + + if (sdram_cfg & SDRAM_CFG_ECC_EN) + puts(", ECC on)"); + else + puts(", ECC off)"); + +#if (CONFIG_NUM_DDR_CONTROLLERS == 3) +#ifdef CONFIG_E6500 + if (*mcintl3r & 0x80000000) { + puts("\n"); + puts(" DDR Controller Interleaving Mode: "); + switch (*mcintl3r & 0x1f) { + case FSL_DDR_3WAY_1KB_INTERLEAVING: + puts("3-way 1KB"); + break; + case FSL_DDR_3WAY_4KB_INTERLEAVING: + puts("3-way 4KB"); + break; + case FSL_DDR_3WAY_8KB_INTERLEAVING: + puts("3-way 8KB"); + break; + default: + puts("3-way UNKNOWN"); + break; + } + } +#endif +#endif +#if (CONFIG_NUM_DDR_CONTROLLERS >= 2) + if (cs0_config & 0x20000000) { + puts("\n"); + puts(" DDR Controller Interleaving Mode: "); + + switch ((cs0_config >> 24) & 0xf) { + case FSL_DDR_CACHE_LINE_INTERLEAVING: + puts("cache line"); + break; + case FSL_DDR_PAGE_INTERLEAVING: + puts("page"); + break; + case FSL_DDR_BANK_INTERLEAVING: + puts("bank"); + break; + case FSL_DDR_SUPERBANK_INTERLEAVING: + puts("super-bank"); + break; + default: + puts("invalid"); + break; + } + } +#endif + + if ((sdram_cfg >> 8) & 0x7f) { + puts("\n"); + puts(" DDR Chip-Select Interleaving Mode: "); + switch(sdram_cfg >> 8 & 0x7f) { + case FSL_DDR_CS0_CS1_CS2_CS3: + puts("CS0+CS1+CS2+CS3"); + break; + case FSL_DDR_CS0_CS1: + puts("CS0+CS1"); + break; + case FSL_DDR_CS2_CS3: + puts("CS2+CS3"); + break; + case FSL_DDR_CS0_CS1_AND_CS2_CS3: + puts("CS0+CS1 and CS2+CS3"); + break; + default: + puts("invalid"); + break; + } + } +} -- cgit v1.1 From 9a17eb5b7e7ba528c278a9677c38d7ae722d93ec Mon Sep 17 00:00:00 2001 From: York Sun Date: Mon, 18 Nov 2013 10:29:32 -0800 Subject: Driver/DDR: combine ccsr_ddr for 83xx, 85xx and 86xx Fix ccsr_ddr structure to avoid using typedef. Combine DDR2 and DDR3 structure for 83xx, 85xx and 86xx. Signed-off-by: York Sun --- drivers/ddr/fsl/ctrl_regs.c | 3 ++- drivers/ddr/fsl/mpc85xx_ddr_gen1.c | 6 ++++-- drivers/ddr/fsl/mpc85xx_ddr_gen2.c | 3 ++- drivers/ddr/fsl/mpc85xx_ddr_gen3.c | 2 +- drivers/ddr/fsl/mpc86xx_ddr.c | 4 ++-- drivers/ddr/fsl/util.c | 4 +++- 6 files changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/ddr/fsl/ctrl_regs.c b/drivers/ddr/fsl/ctrl_regs.c index aed4569c..5f3ea59 100644 --- a/drivers/ddr/fsl/ctrl_regs.c +++ b/drivers/ddr/fsl/ctrl_regs.c @@ -14,13 +14,14 @@ #include #include +#include #include #define _DDR_ADDR CONFIG_SYS_FSL_DDR_ADDR static u32 fsl_ddr_get_version(void) { - ccsr_ddr_t *ddr; + struct ccsr_ddr __iomem *ddr; u32 ver_major_minor_errata; ddr = (void *)_DDR_ADDR; diff --git a/drivers/ddr/fsl/mpc85xx_ddr_gen1.c b/drivers/ddr/fsl/mpc85xx_ddr_gen1.c index ff7d979..8dd4a91 100644 --- a/drivers/ddr/fsl/mpc85xx_ddr_gen1.c +++ b/drivers/ddr/fsl/mpc85xx_ddr_gen1.c @@ -18,7 +18,8 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, unsigned int ctrl_num, int step) { unsigned int i; - volatile ccsr_ddr_t *ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR; + struct ccsr_ddr __iomem *ddr = + (struct ccsr_ddr __iomem *)CONFIG_SYS_FSL_DDR_ADDR; if (ctrl_num != 0) { printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num); @@ -73,7 +74,8 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, void ddr_enable_ecc(unsigned int dram_size) { - volatile ccsr_ddr_t *ddr = (void *)(CONFIG_SYS_FSL_DDR_ADDR); + struct ccsr_ddr __iomem *ddr = + (struct ccsr_ddr __iomem *)(CONFIG_SYS_FSL_DDR_ADDR); dma_meminit(CONFIG_MEM_INIT_VALUE, dram_size); diff --git a/drivers/ddr/fsl/mpc85xx_ddr_gen2.c b/drivers/ddr/fsl/mpc85xx_ddr_gen2.c index c22dea5..988b4a4 100644 --- a/drivers/ddr/fsl/mpc85xx_ddr_gen2.c +++ b/drivers/ddr/fsl/mpc85xx_ddr_gen2.c @@ -19,7 +19,8 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, unsigned int ctrl_num, int step) { unsigned int i; - ccsr_ddr_t *ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR; + struct ccsr_ddr __iomem *ddr = + (struct ccsr_ddr __iomem *)CONFIG_SYS_FSL_DDR_ADDR; #if defined(CONFIG_SYS_FSL_ERRATUM_NMG_DDR120) && defined(CONFIG_MPC85xx) ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); diff --git a/drivers/ddr/fsl/mpc85xx_ddr_gen3.c b/drivers/ddr/fsl/mpc85xx_ddr_gen3.c index 7b4e8ec..9f04133 100644 --- a/drivers/ddr/fsl/mpc85xx_ddr_gen3.c +++ b/drivers/ddr/fsl/mpc85xx_ddr_gen3.c @@ -29,7 +29,7 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, unsigned int ctrl_num, int step) { unsigned int i, bus_width; - volatile ccsr_ddr_t *ddr; + struct ccsr_ddr __iomem *ddr; u32 temp_sdram_cfg; u32 total_gb_size_per_controller; int timeout; diff --git a/drivers/ddr/fsl/mpc86xx_ddr.c b/drivers/ddr/fsl/mpc86xx_ddr.c index caffbaf..4551ed8 100644 --- a/drivers/ddr/fsl/mpc86xx_ddr.c +++ b/drivers/ddr/fsl/mpc86xx_ddr.c @@ -18,7 +18,7 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, unsigned int ctrl_num, int step) { unsigned int i; - volatile ccsr_ddr_t *ddr; + struct ccsr_ddr __iomem *ddr; switch (ctrl_num) { case 0: @@ -58,7 +58,7 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2); out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode); out_be32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2); - out_be32(&ddr->sdram_mode_cntl, regs->ddr_sdram_md_cntl); + out_be32(&ddr->sdram_md_cntl, regs->ddr_sdram_md_cntl); out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval); out_be32(&ddr->sdram_data_init, regs->ddr_data_init); out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl); diff --git a/drivers/ddr/fsl/util.c b/drivers/ddr/fsl/util.c index 45a7bcc..5d6b362 100644 --- a/drivers/ddr/fsl/util.c +++ b/drivers/ddr/fsl/util.c @@ -11,6 +11,7 @@ #include #include +#include #include /* To avoid 64-bit full-divides, we factor this here */ @@ -134,7 +135,8 @@ u32 fsl_ddr_get_intl3r(void) void board_add_ram_info(int use_default) { - ccsr_ddr_t *ddr = (void *)(CONFIG_SYS_FSL_DDR_ADDR); + struct ccsr_ddr __iomem *ddr = + (struct ccsr_ddr __iomem *)(CONFIG_SYS_FSL_DDR_ADDR); #if defined(CONFIG_E6500) && (CONFIG_NUM_DDR_CONTROLLERS == 3) u32 *mcintl3r = (void *) (CONFIG_SYS_IMMR + 0x18004); -- cgit v1.1 From 9ac4ffbde1a5015c9929ee8578d3811b716e2fd3 Mon Sep 17 00:00:00 2001 From: York Sun Date: Mon, 30 Sep 2013 14:20:51 -0700 Subject: Driver/DDR: Add Freescale DDR driver for ARM Make PowerPC specific code conditional so ARM SoCs can reuse this driver. Add DDR3 driver for ARM. Signed-off-by: York Sun --- drivers/ddr/fsl/Makefile | 2 +- drivers/ddr/fsl/arm_ddr_gen3.c | 213 +++++++++++++++++++++++++++++++++++++++++ drivers/ddr/fsl/main.c | 12 ++- drivers/ddr/fsl/util.c | 4 + 4 files changed, 227 insertions(+), 4 deletions(-) create mode 100644 drivers/ddr/fsl/arm_ddr_gen3.c (limited to 'drivers') diff --git a/drivers/ddr/fsl/Makefile b/drivers/ddr/fsl/Makefile index a328b43..265204f 100644 --- a/drivers/ddr/fsl/Makefile +++ b/drivers/ddr/fsl/Makefile @@ -31,4 +31,4 @@ obj-$(CONFIG_SYS_FSL_DDRC_GEN1) += mpc85xx_ddr_gen1.o obj-$(CONFIG_SYS_FSL_DDRC_GEN2) += mpc85xx_ddr_gen2.o obj-$(CONFIG_SYS_FSL_DDRC_GEN3) += mpc85xx_ddr_gen3.o obj-$(CONFIG_SYS_FSL_DDR_86XX) += mpc86xx_ddr.o -obj-$(CONFIG_FSL_DDR_INTERACTIVE) += interactive.o +obj-$(CONFIG_SYS_FSL_DDRC_ARM_GEN3) += arm_ddr_gen3.o diff --git a/drivers/ddr/fsl/arm_ddr_gen3.c b/drivers/ddr/fsl/arm_ddr_gen3.c new file mode 100644 index 0000000..bf11390 --- /dev/null +++ b/drivers/ddr/fsl/arm_ddr_gen3.c @@ -0,0 +1,213 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Derived from mpc85xx_ddr_gen3.c, removed all workarounds + */ + +#include +#include +#include +#include +#include + +#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4) +#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL +#endif + + +/* + * regs has the to-be-set values for DDR controller registers + * ctrl_num is the DDR controller number + * step: 0 goes through the initialization in one pass + * 1 sets registers and returns before enabling controller + * 2 resumes from step 1 and continues to initialize + * Dividing the initialization to two steps to deassert DDR reset signal + * to comply with JEDEC specs for RDIMMs. + */ +void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, + unsigned int ctrl_num, int step) +{ + unsigned int i, bus_width; + struct ccsr_ddr __iomem *ddr; + u32 temp_sdram_cfg; + u32 total_gb_size_per_controller; + int timeout; + + switch (ctrl_num) { + case 0: + ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR; + break; +#if defined(CONFIG_SYS_FSL_DDR2_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 1) + case 1: + ddr = (void *)CONFIG_SYS_FSL_DDR2_ADDR; + break; +#endif +#if defined(CONFIG_SYS_FSL_DDR3_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 2) + case 2: + ddr = (void *)CONFIG_SYS_FSL_DDR3_ADDR; + break; +#endif +#if defined(CONFIG_SYS_FSL_DDR4_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 3) + case 3: + ddr = (void *)CONFIG_SYS_FSL_DDR4_ADDR; + break; +#endif + default: + printf("%s unexpected ctrl_num = %u\n", __func__, ctrl_num); + return; + } + + if (step == 2) + goto step2; + + if (regs->ddr_eor) + out_be32(&ddr->eor, regs->ddr_eor); + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (i == 0) { + out_be32(&ddr->cs0_bnds, regs->cs[i].bnds); + out_be32(&ddr->cs0_config, regs->cs[i].config); + out_be32(&ddr->cs0_config_2, regs->cs[i].config_2); + + } else if (i == 1) { + out_be32(&ddr->cs1_bnds, regs->cs[i].bnds); + out_be32(&ddr->cs1_config, regs->cs[i].config); + out_be32(&ddr->cs1_config_2, regs->cs[i].config_2); + + } else if (i == 2) { + out_be32(&ddr->cs2_bnds, regs->cs[i].bnds); + out_be32(&ddr->cs2_config, regs->cs[i].config); + out_be32(&ddr->cs2_config_2, regs->cs[i].config_2); + + } else if (i == 3) { + out_be32(&ddr->cs3_bnds, regs->cs[i].bnds); + out_be32(&ddr->cs3_config, regs->cs[i].config); + out_be32(&ddr->cs3_config_2, regs->cs[i].config_2); + } + } + + out_be32(&ddr->timing_cfg_3, regs->timing_cfg_3); + out_be32(&ddr->timing_cfg_0, regs->timing_cfg_0); + out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1); + out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2); + out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2); + out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode); + out_be32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2); + out_be32(&ddr->sdram_mode_3, regs->ddr_sdram_mode_3); + out_be32(&ddr->sdram_mode_4, regs->ddr_sdram_mode_4); + out_be32(&ddr->sdram_mode_5, regs->ddr_sdram_mode_5); + out_be32(&ddr->sdram_mode_6, regs->ddr_sdram_mode_6); + out_be32(&ddr->sdram_mode_7, regs->ddr_sdram_mode_7); + out_be32(&ddr->sdram_mode_8, regs->ddr_sdram_mode_8); + out_be32(&ddr->sdram_md_cntl, regs->ddr_sdram_md_cntl); + out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval); + out_be32(&ddr->sdram_data_init, regs->ddr_data_init); + out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl); + out_be32(&ddr->init_addr, regs->ddr_init_addr); + out_be32(&ddr->init_ext_addr, regs->ddr_init_ext_addr); + + out_be32(&ddr->timing_cfg_4, regs->timing_cfg_4); + out_be32(&ddr->timing_cfg_5, regs->timing_cfg_5); + out_be32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl); + out_be32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl); +#ifndef CONFIG_SYS_FSL_DDR_EMU + /* + * Skip these two registers if running on emulator + * because emulator doesn't have skew between bytes. + */ + + if (regs->ddr_wrlvl_cntl_2) + out_be32(&ddr->ddr_wrlvl_cntl_2, regs->ddr_wrlvl_cntl_2); + if (regs->ddr_wrlvl_cntl_3) + out_be32(&ddr->ddr_wrlvl_cntl_3, regs->ddr_wrlvl_cntl_3); +#endif + + out_be32(&ddr->ddr_sr_cntr, regs->ddr_sr_cntr); + out_be32(&ddr->ddr_sdram_rcw_1, regs->ddr_sdram_rcw_1); + out_be32(&ddr->ddr_sdram_rcw_2, regs->ddr_sdram_rcw_2); + out_be32(&ddr->ddr_cdr1, regs->ddr_cdr1); + out_be32(&ddr->ddr_cdr2, regs->ddr_cdr2); + out_be32(&ddr->err_disable, regs->err_disable); + out_be32(&ddr->err_int_en, regs->err_int_en); + for (i = 0; i < 32; i++) { + if (regs->debug[i]) { + debug("Write to debug_%d as %08x\n", i + 1, + regs->debug[i]); + out_be32(&ddr->debug[i], regs->debug[i]); + } + } + + /* + * For RDIMMs, JEDEC spec requires clocks to be stable before reset is + * deasserted. Clocks start when any chip select is enabled and clock + * control register is set. Because all DDR components are connected to + * one reset signal, this needs to be done in two steps. Step 1 is to + * get the clocks started. Step 2 resumes after reset signal is + * deasserted. + */ + if (step == 1) { + udelay(200); + return; + } + +step2: + /* Set, but do not enable the memory */ + temp_sdram_cfg = regs->ddr_sdram_cfg; + temp_sdram_cfg &= ~(SDRAM_CFG_MEM_EN); + out_be32(&ddr->sdram_cfg, temp_sdram_cfg); + + /* + * 500 painful micro-seconds must elapse between + * the DDR clock setup and the DDR config enable. + * DDR2 need 200 us, and DDR3 need 500 us from spec, + * we choose the max, that is 500 us for all of case. + */ + udelay(500); + asm volatile("dsb sy;isb"); + + /* Let the controller go */ + temp_sdram_cfg = in_be32(&ddr->sdram_cfg) & ~SDRAM_CFG_BI; + out_be32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_MEM_EN); + asm volatile("dsb sy;isb"); + + total_gb_size_per_controller = 0; + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + if (!(regs->cs[i].config & 0x80000000)) + continue; + total_gb_size_per_controller += 1 << ( + ((regs->cs[i].config >> 14) & 0x3) + 2 + + ((regs->cs[i].config >> 8) & 0x7) + 12 + + ((regs->cs[i].config >> 0) & 0x7) + 8 + + 3 - ((regs->ddr_sdram_cfg >> 19) & 0x3) - + 26); /* minus 26 (count of 64M) */ + } + if (regs->cs[0].config & 0x20000000) { + /* 2-way interleaving */ + total_gb_size_per_controller <<= 1; + } + /* + * total memory / bus width = transactions needed + * transactions needed / data rate = seconds + * to add plenty of buffer, double the time + * For example, 2GB on 666MT/s 64-bit bus takes about 402ms + * Let's wait for 800ms + */ + bus_width = 3 - ((ddr->sdram_cfg & SDRAM_CFG_DBW_MASK) + >> SDRAM_CFG_DBW_SHIFT); + timeout = ((total_gb_size_per_controller << (6 - bus_width)) * 100 / + (get_ddr_freq(0) >> 20)) << 1; + total_gb_size_per_controller >>= 4; /* shift down to gb size */ + debug("total %d GB\n", total_gb_size_per_controller); + debug("Need to wait up to %d * 10ms\n", timeout); + + /* Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done. */ + while ((in_be32(&ddr->sdram_cfg_2) & SDRAM_CFG2_D_INIT) && + (timeout >= 0)) { + udelay(10000); /* throttle polling rate */ + timeout--; + } + + if (timeout <= 0) + printf("Waiting for D_INIT timeout. Memory may not work.\n"); +} diff --git a/drivers/ddr/fsl/main.c b/drivers/ddr/fsl/main.c index c1cdbdf..b4988e1 100644 --- a/drivers/ddr/fsl/main.c +++ b/drivers/ddr/fsl/main.c @@ -15,16 +15,18 @@ #include #include #include -#include - #include +#ifdef CONFIG_PPC +#include + void fsl_ddr_set_lawbar( const common_timing_params_t *memctl_common_params, unsigned int memctl_interleaved, unsigned int ctrl_num); -void fsl_ddr_set_intl3r(const unsigned int granule_size); +#endif +void fsl_ddr_set_intl3r(const unsigned int granule_size); #if defined(SPD_EEPROM_ADDRESS) || \ defined(SPD_EEPROM_ADDRESS1) || defined(SPD_EEPROM_ADDRESS2) || \ defined(SPD_EEPROM_ADDRESS3) || defined(SPD_EEPROM_ADDRESS4) @@ -549,7 +551,9 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step, phys_size_t fsl_ddr_sdram(void) { unsigned int i; +#ifdef CONFIG_PPC unsigned int law_memctl = LAW_TRGT_IF_DDR_1; +#endif unsigned long long total_memory; fsl_ddr_info_t info; int deassert_reset; @@ -621,6 +625,7 @@ phys_size_t fsl_ddr_sdram(void) } } +#ifdef CONFIG_PPC /* program LAWs */ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { if (info.memctl_opts[i].memctl_interleaving) { @@ -681,6 +686,7 @@ phys_size_t fsl_ddr_sdram(void) law_memctl, i); } } +#endif debug("total_memory by %s = %llu\n", __func__, total_memory); diff --git a/drivers/ddr/fsl/util.c b/drivers/ddr/fsl/util.c index 5d6b362..0658261 100644 --- a/drivers/ddr/fsl/util.c +++ b/drivers/ddr/fsl/util.c @@ -7,7 +7,9 @@ */ #include +#ifdef CONFIG_PPC #include +#endif #include #include @@ -79,6 +81,7 @@ unsigned int mclk_to_picos(unsigned int mclk) return get_memory_clk_period_ps() * mclk; } +#ifdef CONFIG_PPC void __fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params, unsigned int law_memctl, @@ -113,6 +116,7 @@ __attribute__((weak, alias("__fsl_ddr_set_lawbar"))) void fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params, unsigned int memctl_interleaved, unsigned int ctrl_num); +#endif void fsl_ddr_set_intl3r(const unsigned int granule_size) { -- cgit v1.1 From d4263b8adb5bd940c95cbaebaa0da9eaf759bfed Mon Sep 17 00:00:00 2001 From: York Sun Date: Mon, 3 Jun 2013 12:39:06 -0700 Subject: powerpc/mpc8xxx: Extend DDR registers' fields Some DDR registers' fields have expanded to accommodate larger values. These changes are backward compatible. Some fields are removed for newer DDR controllers. Writing to those fields are safely ignored. TIMING_CFG_2 register is fixed. Additive latency is added to RD_TO_PRE automatically. It was a misunderstanding in commit c360ceac. Signed-off-by: York Sun --- drivers/ddr/fsl/ctrl_regs.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/ddr/fsl/ctrl_regs.c b/drivers/ddr/fsl/ctrl_regs.c index 5f3ea59..6bf22cf 100644 --- a/drivers/ddr/fsl/ctrl_regs.c +++ b/drivers/ddr/fsl/ctrl_regs.c @@ -325,10 +325,10 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr, | ((twrt_mclk & 0x3) << 28) /* WRT */ | ((trrt_mclk & 0x3) << 26) /* RRT */ | ((twwt_mclk & 0x3) << 24) /* WWT */ - | ((act_pd_exit_mclk & 0x7) << 20) /* ACT_PD_EXIT */ + | ((act_pd_exit_mclk & 0xf) << 20) /* ACT_PD_EXIT */ | ((pre_pd_exit_mclk & 0xF) << 16) /* PRE_PD_EXIT */ | ((taxpd_mclk & 0xf) << 8) /* ODT_PD_EXIT */ - | ((tmrd_mclk & 0xf) << 0) /* MRS_CYC */ + | ((tmrd_mclk & 0x1f) << 0) /* MRS_CYC */ ); debug("FSLDDR: timing_cfg_0 = 0x%08x\n", ddr->timing_cfg_0); } @@ -338,7 +338,8 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr, static void set_timing_cfg_3(fsl_ddr_cfg_regs_t *ddr, const memctl_options_t *popts, const common_timing_params_t *common_dimm, - unsigned int cas_latency) + unsigned int cas_latency, + unsigned int additive_latency) { /* Extended precharge to activate interval (tRP) */ unsigned int ext_pretoact = 0; @@ -350,6 +351,8 @@ static void set_timing_cfg_3(fsl_ddr_cfg_regs_t *ddr, unsigned int ext_refrec; /* Extended MCAS latency from READ cmd */ unsigned int ext_caslat = 0; + /* Extended additive latency */ + unsigned int ext_add_lat = 0; /* Extended last data to precharge interval (tWR) */ unsigned int ext_wrrec = 0; /* Control Adjust */ @@ -359,6 +362,7 @@ static void set_timing_cfg_3(fsl_ddr_cfg_regs_t *ddr, ext_acttopre = picos_to_mclk(common_dimm->tras_ps) >> 4; ext_acttorw = picos_to_mclk(common_dimm->trcd_ps) >> 4; ext_caslat = (2 * cas_latency - 1) >> 4; + ext_add_lat = additive_latency >> 4; ext_refrec = (picos_to_mclk(common_dimm->trfc_ps) - 8) >> 4; /* ext_wrrec only deals with 16 clock and above, or 14 with OTF */ ext_wrrec = (picos_to_mclk(common_dimm->twr_ps) + @@ -370,6 +374,7 @@ static void set_timing_cfg_3(fsl_ddr_cfg_regs_t *ddr, | ((ext_acttorw & 0x1) << 22) | ((ext_refrec & 0x1F) << 16) | ((ext_caslat & 0x3) << 12) + | ((ext_add_lat & 0x1) << 10) | ((ext_wrrec & 0x1) << 8) | ((cntl_adj & 0x7) << 0) ); @@ -531,8 +536,6 @@ static void set_timing_cfg_2(fsl_ddr_cfg_regs_t *ddr, if (rd_to_pre < 4) rd_to_pre = 4; #endif - if (additive_latency) - rd_to_pre += additive_latency; if (popts->otf_burst_chop_en) rd_to_pre += 2; /* according to UM */ @@ -1592,8 +1595,8 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, if (cs_en) { ddr->cs[i].bnds = (0 - | ((sa & 0xFFF) << 16)/* starting address MSB */ - | ((ea & 0xFFF) << 0) /* ending address MSB */ + | ((sa & 0xffff) << 16) /* starting address */ + | ((ea & 0xffff) << 0) /* ending address */ ); } else { /* setting bnds to 0xffffffff for inactive CS */ @@ -1618,7 +1621,8 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, set_timing_cfg_0(ddr, popts, dimm_params); #endif - set_timing_cfg_3(ddr, popts, common_dimm, cas_latency); + set_timing_cfg_3(ddr, popts, common_dimm, cas_latency, + additive_latency); set_timing_cfg_1(ddr, popts, common_dimm, cas_latency); set_timing_cfg_2(ddr, popts, common_dimm, cas_latency, additive_latency); -- cgit v1.1 From 00ec3fd21170e463e29723976d37f8ea2316f168 Mon Sep 17 00:00:00 2001 From: York Sun Date: Mon, 28 Oct 2013 16:36:02 -0700 Subject: Driver/DDR: Update DDR driver to allow non-zero base address The DRAM base has been zero for Power SoCs. It could be non-zero for ARM SoCs. Use a macro instead of hard-coding to zero. Signed-off-by: York Sun --- drivers/ddr/fsl/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/ddr/fsl/main.c b/drivers/ddr/fsl/main.c index b4988e1..d0cd589 100644 --- a/drivers/ddr/fsl/main.c +++ b/drivers/ddr/fsl/main.c @@ -255,7 +255,7 @@ static unsigned long long __step_assign_addresses(fsl_ddr_info_t *pinfo, debug("dbw_cap_adj[%d]=%d\n", i, dbw_cap_adj[i]); } - current_mem_base = 0ull; + current_mem_base = CONFIG_SYS_DDR_SDRAM_BASE; total_mem = 0; if (pinfo->memctl_opts[0].memctl_interleaving) { rank_density = pinfo->dimm_params[0][0].rank_density >> @@ -535,8 +535,8 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step, } } - total_mem = 1 + (((unsigned long long)max_end << 24ULL) - | 0xFFFFFFULL); + total_mem = 1 + (((unsigned long long)max_end << 24ULL) | + 0xFFFFFFULL) - CONFIG_SYS_DDR_SDRAM_BASE; } return total_mem; -- cgit v1.1 From 0b66513b2706e941b55ffc6ad5aa011e10e87960 Mon Sep 17 00:00:00 2001 From: York Sun Date: Tue, 22 Oct 2013 12:39:02 -0700 Subject: Driver/IFC: Move Freescale IFC driver to a common driver Freescale IFC controller has been used for mpc8xxx. It will be used for ARM-based SoC as well. This patch moves the driver to driver/misc and fix the header file includes. Signed-off-by: York Sun --- drivers/misc/Makefile | 1 + drivers/misc/fsl_ifc.c | 140 ++++++++++++++++++++++++++++++++++++++++ drivers/mtd/nand/fsl_ifc_nand.c | 2 +- drivers/mtd/nand/fsl_ifc_spl.c | 2 +- 4 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 drivers/misc/fsl_ifc.c (limited to 'drivers') diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index d8ff9c6..c77e40a 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -20,3 +20,4 @@ obj-$(CONFIG_NS87308) += ns87308.o obj-$(CONFIG_PDSP188x) += pdsp188x.o obj-$(CONFIG_STATUS_LED) += status_led.o obj-$(CONFIG_TWL4030_LED) += twl4030_led.o +obj-$(CONFIG_FSL_IFC) += fsl_ifc.o diff --git a/drivers/misc/fsl_ifc.c b/drivers/misc/fsl_ifc.c new file mode 100644 index 0000000..507c4de --- /dev/null +++ b/drivers/misc/fsl_ifc.c @@ -0,0 +1,140 @@ +/* + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * Author: Dipen Dudhat + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +void print_ifc_regs(void) +{ + int i, j; + + printf("IFC Controller Registers\n"); + for (i = 0; i < CONFIG_SYS_FSL_IFC_BANK_COUNT; i++) { + printf("CSPR%d:0x%08X\tAMASK%d:0x%08X\tCSOR%d:0x%08X\n", + i, get_ifc_cspr(i), i, get_ifc_amask(i), + i, get_ifc_csor(i)); + for (j = 0; j < 4; j++) + printf("IFC_FTIM%d:0x%08X\n", j, get_ifc_ftim(i, j)); + } +} + +void init_early_memctl_regs(void) +{ +#if defined(CONFIG_SYS_CSPR0) && defined(CONFIG_SYS_CSOR0) + set_ifc_ftim(IFC_CS0, IFC_FTIM0, CONFIG_SYS_CS0_FTIM0); + set_ifc_ftim(IFC_CS0, IFC_FTIM1, CONFIG_SYS_CS0_FTIM1); + set_ifc_ftim(IFC_CS0, IFC_FTIM2, CONFIG_SYS_CS0_FTIM2); + set_ifc_ftim(IFC_CS0, IFC_FTIM3, CONFIG_SYS_CS0_FTIM3); + +#ifndef CONFIG_A003399_NOR_WORKAROUND +#ifdef CONFIG_SYS_CSPR0_EXT + set_ifc_cspr_ext(IFC_CS0, CONFIG_SYS_CSPR0_EXT); +#endif + set_ifc_cspr(IFC_CS0, CONFIG_SYS_CSPR0); + set_ifc_amask(IFC_CS0, CONFIG_SYS_AMASK0); + set_ifc_csor(IFC_CS0, CONFIG_SYS_CSOR0); +#endif +#endif + +#ifdef CONFIG_SYS_CSPR1_EXT + set_ifc_cspr_ext(IFC_CS1, CONFIG_SYS_CSPR1_EXT); +#endif +#if defined(CONFIG_SYS_CSPR1) && defined(CONFIG_SYS_CSOR1) + set_ifc_ftim(IFC_CS1, IFC_FTIM0, CONFIG_SYS_CS1_FTIM0); + set_ifc_ftim(IFC_CS1, IFC_FTIM1, CONFIG_SYS_CS1_FTIM1); + set_ifc_ftim(IFC_CS1, IFC_FTIM2, CONFIG_SYS_CS1_FTIM2); + set_ifc_ftim(IFC_CS1, IFC_FTIM3, CONFIG_SYS_CS1_FTIM3); + + set_ifc_csor(IFC_CS1, CONFIG_SYS_CSOR1); + set_ifc_amask(IFC_CS1, CONFIG_SYS_AMASK1); + set_ifc_cspr(IFC_CS1, CONFIG_SYS_CSPR1); +#endif + +#ifdef CONFIG_SYS_CSPR2_EXT + set_ifc_cspr_ext(IFC_CS2, CONFIG_SYS_CSPR2_EXT); +#endif +#if defined(CONFIG_SYS_CSPR2) && defined(CONFIG_SYS_CSOR2) + set_ifc_ftim(IFC_CS2, IFC_FTIM0, CONFIG_SYS_CS2_FTIM0); + set_ifc_ftim(IFC_CS2, IFC_FTIM1, CONFIG_SYS_CS2_FTIM1); + set_ifc_ftim(IFC_CS2, IFC_FTIM2, CONFIG_SYS_CS2_FTIM2); + set_ifc_ftim(IFC_CS2, IFC_FTIM3, CONFIG_SYS_CS2_FTIM3); + + set_ifc_csor(IFC_CS2, CONFIG_SYS_CSOR2); + set_ifc_amask(IFC_CS2, CONFIG_SYS_AMASK2); + set_ifc_cspr(IFC_CS2, CONFIG_SYS_CSPR2); +#endif + +#ifdef CONFIG_SYS_CSPR3_EXT + set_ifc_cspr_ext(IFC_CS3, CONFIG_SYS_CSPR3_EXT); +#endif +#if defined(CONFIG_SYS_CSPR3) && defined(CONFIG_SYS_CSOR3) + set_ifc_ftim(IFC_CS3, IFC_FTIM0, CONFIG_SYS_CS3_FTIM0); + set_ifc_ftim(IFC_CS3, IFC_FTIM1, CONFIG_SYS_CS3_FTIM1); + set_ifc_ftim(IFC_CS3, IFC_FTIM2, CONFIG_SYS_CS3_FTIM2); + set_ifc_ftim(IFC_CS3, IFC_FTIM3, CONFIG_SYS_CS3_FTIM3); + + set_ifc_cspr(IFC_CS3, CONFIG_SYS_CSPR3); + set_ifc_amask(IFC_CS3, CONFIG_SYS_AMASK3); + set_ifc_csor(IFC_CS3, CONFIG_SYS_CSOR3); +#endif + +#ifdef CONFIG_SYS_CSPR4_EXT + set_ifc_cspr_ext(IFC_CS4, CONFIG_SYS_CSPR4_EXT); +#endif +#if defined(CONFIG_SYS_CSPR4) && defined(CONFIG_SYS_CSOR4) + set_ifc_ftim(IFC_CS4, IFC_FTIM0, CONFIG_SYS_CS4_FTIM0); + set_ifc_ftim(IFC_CS4, IFC_FTIM1, CONFIG_SYS_CS4_FTIM1); + set_ifc_ftim(IFC_CS4, IFC_FTIM2, CONFIG_SYS_CS4_FTIM2); + set_ifc_ftim(IFC_CS4, IFC_FTIM3, CONFIG_SYS_CS4_FTIM3); + + set_ifc_cspr(IFC_CS4, CONFIG_SYS_CSPR4); + set_ifc_amask(IFC_CS4, CONFIG_SYS_AMASK4); + set_ifc_csor(IFC_CS4, CONFIG_SYS_CSOR4); +#endif + +#ifdef CONFIG_SYS_CSPR5_EXT + set_ifc_cspr_ext(IFC_CS5, CONFIG_SYS_CSPR5_EXT); +#endif +#if defined(CONFIG_SYS_CSPR5) && defined(CONFIG_SYS_CSOR5) + set_ifc_ftim(IFC_CS5, IFC_FTIM0, CONFIG_SYS_CS5_FTIM0); + set_ifc_ftim(IFC_CS5, IFC_FTIM1, CONFIG_SYS_CS5_FTIM1); + set_ifc_ftim(IFC_CS5, IFC_FTIM2, CONFIG_SYS_CS5_FTIM2); + set_ifc_ftim(IFC_CS5, IFC_FTIM3, CONFIG_SYS_CS5_FTIM3); + + set_ifc_cspr(IFC_CS5, CONFIG_SYS_CSPR5); + set_ifc_amask(IFC_CS5, CONFIG_SYS_AMASK5); + set_ifc_csor(IFC_CS5, CONFIG_SYS_CSOR5); +#endif + +#ifdef CONFIG_SYS_CSPR6_EXT + set_ifc_cspr_ext(IFC_CS6, CONFIG_SYS_CSPR6_EXT); +#endif +#if defined(CONFIG_SYS_CSPR6) && defined(CONFIG_SYS_CSOR6) + set_ifc_ftim(IFC_CS6, IFC_FTIM0, CONFIG_SYS_CS6_FTIM0); + set_ifc_ftim(IFC_CS6, IFC_FTIM1, CONFIG_SYS_CS6_FTIM1); + set_ifc_ftim(IFC_CS6, IFC_FTIM2, CONFIG_SYS_CS6_FTIM2); + set_ifc_ftim(IFC_CS6, IFC_FTIM3, CONFIG_SYS_CS6_FTIM3); + + set_ifc_cspr(IFC_CS6, CONFIG_SYS_CSPR6); + set_ifc_amask(IFC_CS6, CONFIG_SYS_AMASK6); + set_ifc_csor(IFC_CS6, CONFIG_SYS_CSOR6); +#endif + +#ifdef CONFIG_SYS_CSPR7_EXT + set_ifc_cspr_ext(IFC_CS7, CONFIG_SYS_CSPR7_EXT); +#endif +#if defined(CONFIG_SYS_CSPR7) && defined(CONFIG_SYS_CSOR7) + set_ifc_ftim(IFC_CS7, IFC_FTIM0, CONFIG_SYS_CS7_FTIM0); + set_ifc_ftim(IFC_CS7, IFC_FTIM1, CONFIG_SYS_CS7_FTIM1); + set_ifc_ftim(IFC_CS7, IFC_FTIM2, CONFIG_SYS_CS7_FTIM2); + set_ifc_ftim(IFC_CS7, IFC_FTIM3, CONFIG_SYS_CS7_FTIM3); + + set_ifc_cspr(IFC_CS7, CONFIG_SYS_CSPR7); + set_ifc_amask(IFC_CS7, CONFIG_SYS_AMASK7); + set_ifc_csor(IFC_CS7, CONFIG_SYS_CSOR7); +#endif +} diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 98a09c0..3b845b9 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -17,7 +17,7 @@ #include #include -#include +#include #define FSL_IFC_V1_1_0 0x01010000 #define MAX_BANKS 4 diff --git a/drivers/mtd/nand/fsl_ifc_spl.c b/drivers/mtd/nand/fsl_ifc_spl.c index d462265..3c8278d 100644 --- a/drivers/mtd/nand/fsl_ifc_spl.c +++ b/drivers/mtd/nand/fsl_ifc_spl.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include static inline int is_blank(uchar *addr, int page_size) -- cgit v1.1 From 82a55c1ef87bb6c596b19e83685cc4cbf0344cb3 Mon Sep 17 00:00:00 2001 From: Shengzhou Liu Date: Fri, 22 Nov 2013 17:39:09 +0800 Subject: net/fman: Add support for 10GEC3 and 10GEC4 There are more than two 10GEC in single FMAN in some SoCs(e.g. T2080). This patch adds support for 10GEC3 and 10GEC4. Signed-off-by: Shengzhou Liu --- drivers/net/fm/eth.c | 12 ++++++++++-- drivers/net/fm/fm.h | 2 ++ drivers/net/fm/init.c | 18 ++++++++++++++---- 3 files changed, 26 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fm/eth.c b/drivers/net/fm/eth.c index cb099cd..218a5ed 100644 --- a/drivers/net/fm/eth.c +++ b/drivers/net/fm/eth.c @@ -557,8 +557,16 @@ static int fm_eth_init_mac(struct fm_eth *fm_eth, struct ccsr_fman *reg) num = fm_eth->num; #ifdef CONFIG_SYS_FMAN_V3 - if (fm_eth->type == FM_ETH_10G_E) - num += 8; + if (fm_eth->type == FM_ETH_10G_E) { + /* 10GEC1/10GEC2 use mEMAC9/mEMAC10 + * 10GEC3/10GEC4 use mEMAC1/mEMAC2 + * so it needs to change the num. + */ + if (fm_eth->num >= 2) + num -= 2; + else + num += 8; + } base = ®->memac[num].fm_memac; phyregs = ®->memac[num].fm_memac_mdio; #else diff --git a/drivers/net/fm/fm.h b/drivers/net/fm/fm.h index 3ec49a4..43de114 100644 --- a/drivers/net/fm/fm.h +++ b/drivers/net/fm/fm.h @@ -18,9 +18,11 @@ #define RX_PORT_1G_BASE 0x08 #define MAX_NUM_RX_PORT_1G CONFIG_SYS_NUM_FM1_DTSEC #define RX_PORT_10G_BASE 0x10 +#define RX_PORT_10G_BASE2 0x08 #define TX_PORT_1G_BASE 0x28 #define MAX_NUM_TX_PORT_1G CONFIG_SYS_NUM_FM1_DTSEC #define TX_PORT_10G_BASE 0x30 +#define TX_PORT_10G_BASE2 0x28 #define MIIM_TIMEOUT 0xFFFF struct fm_muram { diff --git a/drivers/net/fm/init.c b/drivers/net/fm/init.c index 35edd7a..cd787f4 100644 --- a/drivers/net/fm/init.c +++ b/drivers/net/fm/init.c @@ -64,6 +64,12 @@ struct fm_eth_info fm_info[] = { #if (CONFIG_SYS_NUM_FM1_10GEC >= 2) FM_TGEC_INFO_INITIALIZER(1, 2), #endif +#if (CONFIG_SYS_NUM_FM1_10GEC >= 3) + FM_TGEC_INFO_INITIALIZER2(1, 3), +#endif +#if (CONFIG_SYS_NUM_FM1_10GEC >= 4) + FM_TGEC_INFO_INITIALIZER2(1, 4), +#endif #if (CONFIG_SYS_NUM_FM2_10GEC >= 1) FM_TGEC_INFO_INITIALIZER(2, 1), #endif @@ -239,10 +245,14 @@ static void ft_fixup_port(void *blob, struct fm_eth_info *info, char *prop) * FM1_10GEC1 is enabled and FM1_DTSEC9 is disabled, ensure that the * dual-role MAC is not disabled, ditto for other dual-role MACs. */ - if (((info->port == FM1_DTSEC9) && (PORT_IS_ENABLED(FM1_10GEC1))) || - ((info->port == FM1_DTSEC10) && (PORT_IS_ENABLED(FM1_10GEC2))) || - ((info->port == FM1_10GEC1) && (PORT_IS_ENABLED(FM1_DTSEC9))) || - ((info->port == FM1_10GEC2) && (PORT_IS_ENABLED(FM1_DTSEC10))) + if (((info->port == FM1_DTSEC9) && (PORT_IS_ENABLED(FM1_10GEC1))) || + ((info->port == FM1_DTSEC10) && (PORT_IS_ENABLED(FM1_10GEC2))) || + ((info->port == FM1_DTSEC1) && (PORT_IS_ENABLED(FM1_10GEC3))) || + ((info->port == FM1_DTSEC2) && (PORT_IS_ENABLED(FM1_10GEC4))) || + ((info->port == FM1_10GEC1) && (PORT_IS_ENABLED(FM1_DTSEC9))) || + ((info->port == FM1_10GEC2) && (PORT_IS_ENABLED(FM1_DTSEC10))) || + ((info->port == FM1_10GEC3) && (PORT_IS_ENABLED(FM1_DTSEC1))) || + ((info->port == FM1_10GEC4) && (PORT_IS_ENABLED(FM1_DTSEC2))) #if (CONFIG_SYS_NUM_FMAN == 2) || ((info->port == FM2_DTSEC9) && (PORT_IS_ENABLED(FM2_10GEC1))) || -- cgit v1.1 From 629d6b32d6b9452b852fe79a195cca5b897fcad3 Mon Sep 17 00:00:00 2001 From: Shengzhou Liu Date: Fri, 22 Nov 2013 17:39:10 +0800 Subject: powerpc/mpc85xx: Add T2080/T2081 SoC support Add support for Freescale T2080/T2081 SoC. T2080 includes the following functions and features: - Four dual-threads 64-bit Power architecture e6500 cores, up to 1.8GHz - 2MB L2 cache and 512KB CoreNet platform cache (CPC) - Hierarchical interconnect fabric - One 32-/64-bit DDR3/3L SDRAM memory controllers with ECC and interleaving - Data Path Acceleration Architecture (DPAA) incorporating acceleration - 16 SerDes lanes up to 10.3125 GHz - 8 mEMACs for network interfaces (four 1Gbps MACs and four 10Gbps/1Gbps MACs) - High-speed peripheral interfaces - Four PCI Express controllers (two PCIe 2.0 and two PCIe 3.0 with SR-IOV) - Two Serial RapidIO 2.0 controllers/ports running at up to 5 GHz - Additional peripheral interfaces - Two serial ATA (SATA 2.0) controllers - Two high-speed USB 2.0 controllers with integrated PHY - Enhanced secure digital host controller (SD/SDHC/SDXC/eMMC) - Enhanced serial peripheral interface (eSPI) - Four I2C controllers - Four 2-pin UARTs or two 4-pin UARTs - Integrated Flash Controller supporting NAND and NOR flash - Three eight-channel DMA engines - Support for hardware virtualization and partitioning enforcement - QorIQ Platform's Trust Architecture 2.0 Differences between T2080 and T2081: Feature T2080 T2081 1G Ethernet numbers: 8 6 10G Ethernet numbers: 4 2 SerDes lanes: 16 8 Serial RapidIO,RMan: 2 no SATA Controller: 2 no Aurora: yes no SoC Package: 896-pins 780-pins Signed-off-by: Shengzhou Liu Acked-by: York Sun --- drivers/net/fm/Makefile | 2 ++ drivers/net/fm/t2080.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 drivers/net/fm/t2080.c (limited to 'drivers') diff --git a/drivers/net/fm/Makefile b/drivers/net/fm/Makefile index d0fd7fc..ee5d768 100644 --- a/drivers/net/fm/Makefile +++ b/drivers/net/fm/Makefile @@ -28,6 +28,8 @@ obj-$(CONFIG_PPC_T1040) += t1040.o obj-$(CONFIG_PPC_T1042) += t1040.o obj-$(CONFIG_PPC_T1020) += t1040.o obj-$(CONFIG_PPC_T1022) += t1040.o +obj-$(CONFIG_PPC_T2080) += t2080.o +obj-$(CONFIG_PPC_T2081) += t2080.o obj-$(CONFIG_PPC_T4240) += t4240.o obj-$(CONFIG_PPC_T4160) += t4240.o obj-$(CONFIG_PPC_B4420) += b4860.o diff --git a/drivers/net/fm/t2080.c b/drivers/net/fm/t2080.c new file mode 100644 index 0000000..b5c1e9f --- /dev/null +++ b/drivers/net/fm/t2080.c @@ -0,0 +1,91 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * Shengzhou Liu + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +u32 port_to_devdisr[] = { + [FM1_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC1_1, + [FM1_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC1_2, + [FM1_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC1_3, + [FM1_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC1_4, + [FM1_DTSEC5] = FSL_CORENET_DEVDISR2_DTSEC1_5, + [FM1_DTSEC6] = FSL_CORENET_DEVDISR2_DTSEC1_6, + [FM1_DTSEC9] = FSL_CORENET_DEVDISR2_DTSEC1_9, + [FM1_DTSEC10] = FSL_CORENET_DEVDISR2_DTSEC1_10, + [FM1_10GEC1] = FSL_CORENET_DEVDISR2_10GEC1_1, + [FM1_10GEC2] = FSL_CORENET_DEVDISR2_10GEC1_2, + [FM1_10GEC3] = FSL_CORENET_DEVDISR2_10GEC1_3, + [FM1_10GEC4] = FSL_CORENET_DEVDISR2_10GEC1_4, +}; + +static int is_device_disabled(enum fm_port port) +{ + ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); + u32 devdisr2 = in_be32(&gur->devdisr2); + + return port_to_devdisr[port] & devdisr2; +} + +void fman_disable_port(enum fm_port port) +{ + ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); + + setbits_be32(&gur->devdisr2, port_to_devdisr[port]); +} + +phy_interface_t fman_port_enet_if(enum fm_port port) +{ + ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); + u32 rcwsr13 = in_be32(&gur->rcwsr[13]); + + if (is_device_disabled(port)) + return PHY_INTERFACE_MODE_NONE; + + if ((port == FM1_10GEC1 || port == FM1_10GEC2 || + port == FM1_10GEC3 || port == FM1_10GEC4) && + ((is_serdes_configured(XAUI_FM1_MAC9)) || + (is_serdes_configured(XFI_FM1_MAC1)) || + (is_serdes_configured(XFI_FM1_MAC2)) || + (is_serdes_configured(XFI_FM1_MAC9)) || + (is_serdes_configured(XFI_FM1_MAC10)))) + return PHY_INTERFACE_MODE_XGMII; + + if ((port == FM1_DTSEC3) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) == + FSL_CORENET_RCWSR13_EC1_DTSEC3_RGMII)) + return PHY_INTERFACE_MODE_RGMII; + + if ((port == FM1_DTSEC4) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC2) == + FSL_CORENET_RCWSR13_EC2_DTSEC4_RGMII)) + return PHY_INTERFACE_MODE_RGMII; + + if ((port == FM1_DTSEC10) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC2) == + FSL_CORENET_RCWSR13_EC2_DTSEC10_RGMII)) + return PHY_INTERFACE_MODE_RGMII; + + switch (port) { + case FM1_DTSEC1: + case FM1_DTSEC2: + case FM1_DTSEC3: + case FM1_DTSEC4: + case FM1_DTSEC5: + case FM1_DTSEC6: + case FM1_DTSEC9: + case FM1_DTSEC10: + if (is_serdes_configured(SGMII_FM1_DTSEC1 + port - FM1_DTSEC1)) + return PHY_INTERFACE_MODE_SGMII; + break; + default: + return PHY_INTERFACE_MODE_NONE; + } + + return PHY_INTERFACE_MODE_NONE; +} -- cgit v1.1 From 2785a4ae76330dab5e792d52fc9c449ac3d1072e Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Tue, 29 Oct 2013 13:11:54 -0700 Subject: serial: zynq: Remove unused #defines Signed-off-by: Soren Brinkmann Signed-off-by: Michal Simek Series-to: trini, uboot --- drivers/serial/serial_zynq.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/serial_zynq.c b/drivers/serial/serial_zynq.c index 050b9c0..ff28f3c 100644 --- a/drivers/serial/serial_zynq.c +++ b/drivers/serial/serial_zynq.c @@ -21,10 +21,6 @@ #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] */ -- cgit v1.1