From 22eb395f6811dbe47815403f15c6d31692f1ac63 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sat, 4 Oct 2014 19:40:07 +0200 Subject: MIPS: malta: fix pci IO resource assignment Does the same thing as the Linux kernel now. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/mips/mach-malta/pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/mach-malta/pci.c b/arch/mips/mach-malta/pci.c index 90351758e0..47c0e228a7 100644 --- a/arch/mips/mach-malta/pci.c +++ b/arch/mips/mach-malta/pci.c @@ -151,7 +151,7 @@ static struct pci_controller gt64120_controller = { static int pcibios_init(void) { - resource_size_t start, end, map, start1, end1, map1, mask, res_end; + resource_size_t start, end, map, start1, end1, map1, mask; /* * Due to a bug in the Galileo system controller, we need @@ -207,7 +207,7 @@ static int pcibios_init(void) BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) && mask != ~((mask & -mask) - 1)); gt64120_io_resource.start = map & mask; - res_end = (map & mask) | ~mask; + gt64120_io_resource.end = (map & mask) | ~mask; gt64120_controller.io_offset = 0; /* Addresses are 36-bit, so do shifts in the destinations. */ gt64120_io_resource.start <<= GT_PCI_DCRM_SHF; -- cgit v1.2.3 From 72d9846fa6a940ae77ff92ac4413a6e28729a8aa Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sat, 4 Oct 2014 19:40:08 +0200 Subject: pci: split out device init To make it reusable and the code more readable. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/pci/pci.c | 137 +++++++++++++++++++++++++++++------------------------- 1 file changed, 74 insertions(+), 63 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index a1b7680254..ef998dc81a 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -12,6 +12,8 @@ static struct pci_controller *hose_head, **hose_tail = &hose_head; LIST_HEAD(pci_root_buses); EXPORT_SYMBOL(pci_root_buses); static u8 bus_index; +static resource_size_t last_mem; +static resource_size_t last_io; static struct pci_bus *pci_alloc_bus(void) { @@ -45,6 +47,10 @@ void register_pci_controller(struct pci_controller *hose) if (hose->set_busno) hose->set_busno(hose, bus->number); + + last_mem = bus->resource[0]->start; + last_io = bus->resource[1]->start; + pci_scan_bus(bus); list_add_tail(&bus->node, &pci_root_buses); @@ -111,27 +117,80 @@ static struct pci_dev *alloc_pci_dev(void) return dev; } +static void setup_device(struct pci_dev *dev, int max_bar) +{ + int bar, size; + u32 mask; + u8 cmd; + + pci_read_config_byte(dev, PCI_COMMAND, &cmd); + pci_write_config_byte(dev, PCI_COMMAND, + cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)); + + for (bar = 0; bar < max_bar; bar++) { + resource_size_t last_addr; + + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, 0xfffffffe); + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, &mask); + + if (mask == 0 || mask == 0xffffffff) { + DBG(" PCI: pbar%d set bad mask\n", bar); + continue; + } + + if (mask & 0x01) { /* IO */ + size = -(mask & 0xfffffffe); + DBG(" PCI: pbar%d: mask=%08x io %d bytes\n", bar, mask, size); + if (last_mem + size > dev->bus->resource[0]->end) { + DBG("BAR does not fit within bus IO res\n"); + return; + } + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, last_io); + dev->resource[bar].flags = IORESOURCE_IO; + last_addr = last_io; + last_io += size; + } else { /* MEM */ + size = -(mask & 0xfffffff0); + DBG(" PCI: pbar%d: mask=%08x memory %d bytes\n", bar, mask, size); + if (last_mem + size > dev->bus->resource[0]->end) { + DBG("BAR does not fit within bus mem res\n"); + return; + } + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, last_mem); + dev->resource[bar].flags = IORESOURCE_MEM; + last_addr = last_mem; + last_mem += size; + + if ((mask & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == + PCI_BASE_ADDRESS_MEM_TYPE_64) { + dev->resource[bar].flags |= IORESOURCE_MEM_64; + pci_write_config_dword(dev, + PCI_BASE_ADDRESS_1 + bar * 4, 0); + } + } + + dev->resource[bar].start = last_addr; + dev->resource[bar].end = last_addr + size - 1; + if (dev->resource[bar].flags & IORESOURCE_MEM_64) + bar++; + } + + pci_write_config_byte(dev, PCI_COMMAND, cmd); + list_add_tail(&dev->bus_list, &dev->bus->devices); + pci_register_device(dev); +} + unsigned int pci_scan_bus(struct pci_bus *bus) { + struct pci_dev *dev; unsigned int devfn, l, max, class; unsigned char cmd, tmp, hdr_type, is_multi = 0; - struct pci_dev *dev; - resource_size_t last_mem; - resource_size_t last_io; - - /* FIXME: use res_start() */ - last_mem = bus->resource[0]->start; - last_io = bus->resource[1]->start; DBG("pci_scan_bus for bus %d\n", bus->number); DBG(" last_io = 0x%08x, last_mem = 0x%08x\n", last_io, last_mem); max = bus->secondary; for (devfn = 0; devfn < 0xff; ++devfn) { - int bar; - u32 old_bar, mask; - int size; - if (PCI_FUNC(devfn) && !is_multi) { /* not a multi-function device */ continue; @@ -169,6 +228,8 @@ unsigned int pci_scan_bus(struct pci_bus *bus) dev->hdr_type = hdr_type; DBG("PCI: class = %08x, hdr_type = %08x\n", class, hdr_type); + DBG("PCI: %02x:%02x [%04x:%04x]\n", bus->number, dev->devfn, + dev->vendor, dev->device); switch (hdr_type & 0x7f) { /* header type */ case PCI_HEADER_TYPE_NORMAL: /* standard header */ @@ -181,6 +242,8 @@ unsigned int pci_scan_bus(struct pci_bus *bus) */ pci_read_config_dword(dev, PCI_ROM_ADDRESS, &l); dev->rom_address = (l == 0xffffffff) ? 0 : l; + + setup_device(dev, 6); break; default: /* unknown header */ bad: @@ -189,62 +252,10 @@ unsigned int pci_scan_bus(struct pci_bus *bus) continue; } - DBG("PCI: %02x:%02x [%04x/%04x]\n", bus->number, dev->devfn, dev->vendor, dev->device); - if (class == PCI_CLASS_BRIDGE_HOST) { DBG("PCI: skip pci host bridge\n"); continue; } - - pci_read_config_byte(dev, PCI_COMMAND, &cmd); - pci_write_config_byte(dev, PCI_COMMAND, - cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)); - - for (bar = 0; bar < 6; bar++) { - resource_size_t last_addr; - - pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, &old_bar); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, 0xfffffffe); - pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, &mask); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, old_bar); - - if (mask == 0 || mask == 0xffffffff) { - DBG(" PCI: pbar%d set bad mask\n", bar); - continue; - } - - if (mask & 0x01) { /* IO */ - size = -(mask & 0xfffffffe); - DBG(" PCI: pbar%d: mask=%08x io %d bytes\n", bar, mask, size); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, last_io); - dev->resource[bar].flags = IORESOURCE_IO; - last_addr = last_io; - last_io += size; - } else { /* MEM */ - size = -(mask & 0xfffffff0); - DBG(" PCI: pbar%d: mask=%08x memory %d bytes\n", bar, mask, size); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, last_mem); - dev->resource[bar].flags = IORESOURCE_MEM; - last_addr = last_mem; - last_mem += size; - - if ((mask & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == - PCI_BASE_ADDRESS_MEM_TYPE_64) { - dev->resource[bar].flags |= IORESOURCE_MEM_64; - pci_write_config_dword(dev, - PCI_BASE_ADDRESS_1 + bar * 4, 0); - } - } - - dev->resource[bar].start = last_addr; - dev->resource[bar].end = last_addr + size - 1; - if (dev->resource[bar].flags & IORESOURCE_MEM_64) - bar++; - } - - pci_write_config_byte(dev, PCI_COMMAND, cmd); - list_add_tail(&dev->bus_list, &bus->devices); - pci_register_device(dev); } /* -- cgit v1.2.3 From 06ac5b551e29c828c87dd51d57799f9ebc8eef33 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sat, 4 Oct 2014 19:40:09 +0200 Subject: pci: add resource enum Makes things way clearer than juggling numbers. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/pci/pci.c | 14 ++++++++------ include/linux/pci.h | 6 ++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index ef998dc81a..e9f0cb53e7 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -41,15 +41,15 @@ void register_pci_controller(struct pci_controller *hose) hose->bus = bus; bus->host = hose; bus->ops = hose->pci_ops; - bus->resource[0] = hose->mem_resource; - bus->resource[1] = hose->io_resource; + bus->resource[PCI_BUS_RESOURCE_MEM] = hose->mem_resource; + bus->resource[PCI_BUS_RESOURCE_IO] = hose->io_resource; bus->number = bus_index++; if (hose->set_busno) hose->set_busno(hose, bus->number); - last_mem = bus->resource[0]->start; - last_io = bus->resource[1]->start; + last_mem = bus->resource[PCI_BUS_RESOURCE_MEM]->start; + last_io = bus->resource[PCI_BUS_RESOURCE_IO]->start; pci_scan_bus(bus); @@ -141,7 +141,8 @@ static void setup_device(struct pci_dev *dev, int max_bar) if (mask & 0x01) { /* IO */ size = -(mask & 0xfffffffe); DBG(" PCI: pbar%d: mask=%08x io %d bytes\n", bar, mask, size); - if (last_mem + size > dev->bus->resource[0]->end) { + if (last_io + size > + dev->bus->resource[PCI_BUS_RESOURCE_IO]->end) { DBG("BAR does not fit within bus IO res\n"); return; } @@ -152,7 +153,8 @@ static void setup_device(struct pci_dev *dev, int max_bar) } else { /* MEM */ size = -(mask & 0xfffffff0); DBG(" PCI: pbar%d: mask=%08x memory %d bytes\n", bar, mask, size); - if (last_mem + size > dev->bus->resource[0]->end) { + if (last_mem + size > + dev->bus->resource[PCI_BUS_RESOURCE_MEM]->end) { DBG("BAR does not fit within bus mem res\n"); return; } diff --git a/include/linux/pci.h b/include/linux/pci.h index 0ec1320b2f..f5ef588171 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -114,6 +114,12 @@ struct pci_dev { }; #define to_pci_dev(dev) container_of(dev, struct pci_dev, dev) +enum { + PCI_BUS_RESOURCE_IO = 0, + PCI_BUS_RESOURCE_MEM = 1, + PCI_BUS_RESOURCE_MEM_PREF = 2, + PCI_BUS_RESOURCE_BUSN = 3, +}; struct pci_bus { struct pci_controller *host; /* associated host controller */ struct list_head node; /* node in list of buses */ -- cgit v1.2.3 From beb6469992229be1e3b495e6c9dd1fca12635b97 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sat, 4 Oct 2014 19:40:10 +0200 Subject: pci: properly populate prefetchable BARs Some host controllers provide a prefetchable memory area and devices will prefer this for some of their BARs. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/pci/pci.c | 59 ++++++++++++++++++++++++++++++++++++++++------------- include/linux/pci.h | 1 + 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e9f0cb53e7..115d8a3c99 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -13,6 +13,7 @@ LIST_HEAD(pci_root_buses); EXPORT_SYMBOL(pci_root_buses); static u8 bus_index; static resource_size_t last_mem; +static resource_size_t last_mem_pref; static resource_size_t last_io; static struct pci_bus *pci_alloc_bus(void) @@ -42,14 +43,27 @@ void register_pci_controller(struct pci_controller *hose) bus->host = hose; bus->ops = hose->pci_ops; bus->resource[PCI_BUS_RESOURCE_MEM] = hose->mem_resource; + bus->resource[PCI_BUS_RESOURCE_MEM_PREF] = hose->mem_pref_resource; bus->resource[PCI_BUS_RESOURCE_IO] = hose->io_resource; bus->number = bus_index++; if (hose->set_busno) hose->set_busno(hose, bus->number); - last_mem = bus->resource[PCI_BUS_RESOURCE_MEM]->start; - last_io = bus->resource[PCI_BUS_RESOURCE_IO]->start; + if (bus->resource[PCI_BUS_RESOURCE_MEM]) + last_mem = bus->resource[PCI_BUS_RESOURCE_MEM]->start; + else + last_mem = 0; + + if (bus->resource[PCI_BUS_RESOURCE_MEM]) + last_mem_pref = bus->resource[PCI_BUS_RESOURCE_MEM_PREF]->start; + else + last_mem_pref = 0; + + if (bus->resource[PCI_BUS_RESOURCE_IO]) + last_io = bus->resource[PCI_BUS_RESOURCE_IO]->start; + else + last_io = 0; pci_scan_bus(bus); @@ -150,31 +164,46 @@ static void setup_device(struct pci_dev *dev, int max_bar) dev->resource[bar].flags = IORESOURCE_IO; last_addr = last_io; last_io += size; - } else { /* MEM */ + } else if ((mask & PCI_BASE_ADDRESS_MEM_PREFETCH) && + last_mem_pref) /* prefetchable MEM */ { size = -(mask & 0xfffffff0); - DBG(" PCI: pbar%d: mask=%08x memory %d bytes\n", bar, mask, size); + DBG(" PCI: pbar%d: mask=%08x P memory %d bytes\n", + bar, mask, size); + if (last_mem_pref + size > + dev->bus->resource[PCI_BUS_RESOURCE_MEM_PREF]->end) { + DBG("BAR does not fit within bus p-mem res\n"); + return; + } + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, last_mem_pref); + dev->resource[bar].flags = IORESOURCE_MEM | + IORESOURCE_PREFETCH; + last_addr = last_mem_pref; + last_mem_pref += size; + } else { /* non-prefetch MEM */ + size = -(mask & 0xfffffff0); + DBG(" PCI: pbar%d: mask=%08x NP memory %d bytes\n", + bar, mask, size); if (last_mem + size > dev->bus->resource[PCI_BUS_RESOURCE_MEM]->end) { - DBG("BAR does not fit within bus mem res\n"); + DBG("BAR does not fit within bus np-mem res\n"); return; } pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, last_mem); dev->resource[bar].flags = IORESOURCE_MEM; last_addr = last_mem; last_mem += size; - - if ((mask & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == - PCI_BASE_ADDRESS_MEM_TYPE_64) { - dev->resource[bar].flags |= IORESOURCE_MEM_64; - pci_write_config_dword(dev, - PCI_BASE_ADDRESS_1 + bar * 4, 0); - } } dev->resource[bar].start = last_addr; dev->resource[bar].end = last_addr + size - 1; - if (dev->resource[bar].flags & IORESOURCE_MEM_64) + + if ((mask & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == + PCI_BASE_ADDRESS_MEM_TYPE_64) { + dev->resource[bar].flags |= IORESOURCE_MEM_64; + pci_write_config_dword(dev, + PCI_BASE_ADDRESS_1 + bar * 4, 0); bar++; + } } pci_write_config_byte(dev, PCI_COMMAND, cmd); @@ -189,7 +218,9 @@ unsigned int pci_scan_bus(struct pci_bus *bus) unsigned char cmd, tmp, hdr_type, is_multi = 0; DBG("pci_scan_bus for bus %d\n", bus->number); - DBG(" last_io = 0x%08x, last_mem = 0x%08x\n", last_io, last_mem); + DBG(" last_io = 0x%08x, last_mem = 0x%08x, last_mem_pref = 0x%08x\n", + last_io, last_mem, last_mem_pref); + max = bus->secondary; for (devfn = 0; devfn < 0xff; ++devfn) { diff --git a/include/linux/pci.h b/include/linux/pci.h index f5ef588171..932acf0d7c 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -162,6 +162,7 @@ struct pci_controller { struct pci_ops *pci_ops; struct resource *mem_resource; + struct resource *mem_pref_resource; unsigned long mem_offset; struct resource *io_resource; unsigned long io_offset; -- cgit v1.2.3 From 687ceb77162df447f909cc587133417723828f9e Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sat, 4 Oct 2014 19:40:11 +0200 Subject: pci: setup bridges and traverse buses behind them Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/pci/pci.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++-- include/linux/pci_regs.h | 28 +++++++++++++++ 2 files changed, 117 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 115d8a3c99..59f942d511 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -211,9 +211,73 @@ static void setup_device(struct pci_dev *dev, int max_bar) pci_register_device(dev); } +static void prescan_setup_bridge(struct pci_dev *dev) +{ + u16 cmdstat; + + pci_read_config_word(dev, PCI_COMMAND, &cmdstat); + + /* Configure bus number registers */ + pci_write_config_byte(dev, PCI_PRIMARY_BUS, dev->bus->number); + pci_write_config_byte(dev, PCI_SECONDARY_BUS, dev->subordinate->number); + pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, 0xff); + + if (last_mem) { + /* Set up memory and I/O filter limits, assume 32-bit I/O space */ + pci_write_config_word(dev, PCI_MEMORY_BASE, + (last_mem & 0xfff00000) >> 16); + cmdstat |= PCI_COMMAND_MEMORY; + } + + if (last_mem_pref) { + /* Set up memory and I/O filter limits, assume 32-bit I/O space */ + pci_write_config_word(dev, PCI_PREF_MEMORY_BASE, + (last_mem_pref & 0xfff00000) >> 16); + cmdstat |= PCI_COMMAND_MEMORY; + } else { + + /* We don't support prefetchable memory for now, so disable */ + pci_write_config_word(dev, PCI_PREF_MEMORY_BASE, 0x1000); + pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT, 0x0); + } + + if (last_io) { + pci_write_config_byte(dev, PCI_IO_BASE, + (last_io & 0x0000f000) >> 8); + pci_write_config_word(dev, PCI_IO_BASE_UPPER16, + (last_io & 0xffff0000) >> 16); + cmdstat |= PCI_COMMAND_IO; + } + + /* Enable memory and I/O accesses, enable bus master */ + pci_write_config_word(dev, PCI_COMMAND, cmdstat | PCI_COMMAND_MASTER); +} + +static void postscan_setup_bridge(struct pci_dev *dev) +{ + /* limit subordinate to last used bus number */ + pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, bus_index - 1); + + if (last_mem) + pci_write_config_word(dev, PCI_MEMORY_LIMIT, + ((last_mem - 1) & 0xfff00000) >> 16); + + if (last_mem_pref) + pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT, + ((last_mem_pref - 1) & 0xfff00000) >> 16); + + if (last_io) { + pci_write_config_byte(dev, PCI_IO_LIMIT, + ((last_io - 1) & 0x0000f000) >> 8); + pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16, + ((last_io - 1) & 0xffff0000) >> 16); + } +} + unsigned int pci_scan_bus(struct pci_bus *bus) { struct pci_dev *dev; + struct pci_bus *child_bus; unsigned int devfn, l, max, class; unsigned char cmd, tmp, hdr_type, is_multi = 0; @@ -264,8 +328,8 @@ unsigned int pci_scan_bus(struct pci_bus *bus) DBG("PCI: %02x:%02x [%04x:%04x]\n", bus->number, dev->devfn, dev->vendor, dev->device); - switch (hdr_type & 0x7f) { /* header type */ - case PCI_HEADER_TYPE_NORMAL: /* standard header */ + switch (hdr_type & 0x7f) { + case PCI_HEADER_TYPE_NORMAL: if (class == PCI_CLASS_BRIDGE_PCI) goto bad; @@ -278,7 +342,28 @@ unsigned int pci_scan_bus(struct pci_bus *bus) setup_device(dev, 6); break; - default: /* unknown header */ + case PCI_HEADER_TYPE_BRIDGE: + setup_device(dev, 2); + + child_bus = pci_alloc_bus(); + /* inherit parent properties */ + child_bus->host = bus->host; + child_bus->ops = bus->host->pci_ops; + child_bus->resource[PCI_BUS_RESOURCE_MEM] = + bus->resource[PCI_BUS_RESOURCE_MEM]; + child_bus->resource[PCI_BUS_RESOURCE_MEM_PREF] = + bus->resource[PCI_BUS_RESOURCE_MEM_PREF]; + child_bus->resource[PCI_BUS_RESOURCE_IO] = + bus->resource[PCI_BUS_RESOURCE_IO]; + child_bus->number = bus_index++; + list_add_tail(&child_bus->node, &bus->children); + dev->subordinate = child_bus; + + prescan_setup_bridge(dev); + pci_scan_bus(child_bus); + postscan_setup_bridge(dev); + break; + default: bad: printk(KERN_ERR "PCI: %02x:%02x [%04x/%04x/%06x] has unknown header type %02x, ignoring.\n", bus->number, dev->devfn, dev->vendor, dev->device, class, hdr_type); @@ -298,6 +383,7 @@ unsigned int pci_scan_bus(struct pci_bus *bus) * * Return how far we've got finding sub-buses. */ + max = bus_index; DBG("PCI: pci_scan_bus returning with max=%02x\n", max); return max; diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index 14a3ed3184..8669fc7393 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -107,4 +107,32 @@ #define PCI_ROM_ADDRESS_ENABLE 0x01 #define PCI_ROM_ADDRESS_MASK (~0x7ffUL) +/* Header type 1 (PCI-to-PCI bridges) */ +#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */ +#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */ +#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */ +#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */ +#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */ +#define PCI_IO_LIMIT 0x1d +#define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */ +#define PCI_IO_RANGE_TYPE_16 0x00 +#define PCI_IO_RANGE_TYPE_32 0x01 +#define PCI_IO_RANGE_MASK (~0x0fUL) /* Standard 4K I/O windows */ +#define PCI_IO_1K_RANGE_MASK (~0x03UL) /* Intel 1K I/O windows */ +#define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */ +#define PCI_MEMORY_BASE 0x20 /* Memory range behind */ +#define PCI_MEMORY_LIMIT 0x22 +#define PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL +#define PCI_MEMORY_RANGE_MASK (~0x0fUL) +#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */ +#define PCI_PREF_MEMORY_LIMIT 0x26 +#define PCI_PREF_RANGE_TYPE_MASK 0x0fUL +#define PCI_PREF_RANGE_TYPE_32 0x00 +#define PCI_PREF_RANGE_TYPE_64 0x01 +#define PCI_PREF_RANGE_MASK (~0x0fUL) +#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */ +#define PCI_PREF_LIMIT_UPPER32 0x2c +#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */ +#define PCI_IO_LIMIT_UPPER16 0x32 + #endif /* LINUX_PCI_REGS_H */ -- cgit v1.2.3 From b8a1bb1dd215770670108fe5b0de0e5e137bf8fd Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sat, 4 Oct 2014 19:40:12 +0200 Subject: pci: defer device registration until after bridge setup Otherwise the drivers for a device may probe before the devices parent bridge is fully configured, which leads to errors when accessing the BARs. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/pci/pci.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 59f942d511..943d0e8ebe 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -208,7 +208,6 @@ static void setup_device(struct pci_dev *dev, int max_bar) pci_write_config_byte(dev, PCI_COMMAND, cmd); list_add_tail(&dev->bus_list, &dev->bus->devices); - pci_register_device(dev); } static void prescan_setup_bridge(struct pci_dev *dev) @@ -362,6 +361,11 @@ unsigned int pci_scan_bus(struct pci_bus *bus) prescan_setup_bridge(dev); pci_scan_bus(child_bus); postscan_setup_bridge(dev); + /* first activate bridge then all devices on it's bus */ + pci_register_device(dev); + list_for_each_entry(dev, &child_bus->devices, bus_list) + if (!dev->subordinate) + pci_register_device(dev); break; default: bad: -- cgit v1.2.3 From 48f88df158cc6dab89230cf92faeb9389a75faf1 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sat, 4 Oct 2014 19:40:13 +0200 Subject: pci: prettyprint device names Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/pci/bus.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 8215ee5638..866ab08067 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -86,7 +86,8 @@ int pci_register_device(struct pci_dev *pdev) struct device_d *dev = &pdev->dev; int ret; - strcpy(dev->name, "pci"); + snprintf(dev->name, MAX_DRIVER_NAME, "pci-%04x:%04x.", + pdev->vendor, pdev->device); dev->bus = &pci_bus; dev->id = DEVICE_ID_DYNAMIC; -- cgit v1.2.3 From 490d4fe4179675a68f604ec9dcc07926c57125eb Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sat, 4 Oct 2014 19:40:14 +0200 Subject: pci: track parent<->child relationship So that PCI devices hang down from bridges and root bridges down from the PCI host controller when calling devinfo. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/pci/pci.c | 4 ++++ include/linux/pci.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 943d0e8ebe..ba9d097230 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -40,6 +40,7 @@ void register_pci_controller(struct pci_controller *hose) bus = pci_alloc_bus(); hose->bus = bus; + bus->parent = hose->parent; bus->host = hose; bus->ops = hose->pci_ops; bus->resource[PCI_BUS_RESOURCE_MEM] = hose->mem_resource; @@ -309,6 +310,7 @@ unsigned int pci_scan_bus(struct pci_bus *bus) dev->devfn = devfn; dev->vendor = l & 0xffff; dev->device = (l >> 16) & 0xffff; + dev->dev.parent = bus->parent; /* non-destructively determine if device can be a master: */ pci_read_config_byte(dev, PCI_COMMAND, &cmd); @@ -354,6 +356,8 @@ unsigned int pci_scan_bus(struct pci_bus *bus) bus->resource[PCI_BUS_RESOURCE_MEM_PREF]; child_bus->resource[PCI_BUS_RESOURCE_IO] = bus->resource[PCI_BUS_RESOURCE_IO]; + + child_bus->parent = &dev->dev; child_bus->number = bus_index++; list_add_tail(&child_bus->node, &bus->children); dev->subordinate = child_bus; diff --git a/include/linux/pci.h b/include/linux/pci.h index 932acf0d7c..3d0e73bf9f 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -122,6 +122,7 @@ enum { }; struct pci_bus { struct pci_controller *host; /* associated host controller */ + struct device_d *parent; struct list_head node; /* node in list of buses */ struct list_head children; /* list of child buses */ struct list_head devices; /* list of devices on this bus */ @@ -158,6 +159,7 @@ extern struct pci_ops *pci_ops; */ struct pci_controller { struct pci_controller *next; + struct device_d *parent; struct pci_bus *bus; struct pci_ops *pci_ops; -- cgit v1.2.3 From 9b93e2aa59a0444d92ba06a48e7e3fa0395f9182 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sat, 4 Oct 2014 19:40:15 +0200 Subject: commands: lspci: go down into subordinate busses This way we also list devices that are behind bridges. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- commands/lspci.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/commands/lspci.c b/commands/lspci.c index fdf02691b5..27edd5d1c2 100644 --- a/commands/lspci.c +++ b/commands/lspci.c @@ -20,10 +20,24 @@ #include #include +static void traverse_bus(struct pci_bus *bus) +{ + struct pci_dev *dev; + + list_for_each_entry(dev, &bus->devices, bus_list) { + printf("%02x:%02x.%1x %04x: %04x:%04x (rev %02x)\n", + dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), (dev->class >> 8) & 0xffff, + dev->vendor, dev->device, dev->revision); + + if (dev->subordinate) + traverse_bus(dev->subordinate); + } +} + static int do_lspci(int argc, char *argv[]) { struct pci_bus *root_bus; - struct pci_dev *dev; if (list_empty(&pci_root_buses)) { printf("No PCI bus detected\n"); @@ -31,14 +45,7 @@ static int do_lspci(int argc, char *argv[]) } list_for_each_entry(root_bus, &pci_root_buses, node) { - list_for_each_entry(dev, &root_bus->devices, bus_list) { - printf("%02x: %04x: %04x:%04x (rev %02x)\n", - dev->devfn, - (dev->class >> 8) & 0xffff, - dev->vendor, - dev->device, - dev->revision); - } + traverse_bus(root_bus); } return 0; -- cgit v1.2.3 From aa2e6ca831f4f02e133de0c5212a2773a62bb1d5 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sat, 4 Oct 2014 19:40:16 +0200 Subject: clk: tegra: add PLLE setup functions Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/mach-tegra/include/mach/tegra30-car.h | 2 + drivers/clk/tegra/clk-pll.c | 116 +++++++++++++++++++++++++ drivers/clk/tegra/clk.h | 6 ++ 3 files changed, 124 insertions(+) diff --git a/arch/arm/mach-tegra/include/mach/tegra30-car.h b/arch/arm/mach-tegra/include/mach/tegra30-car.h index c8f6c9fd54..7fb2238dc9 100644 --- a/arch/arm/mach-tegra/include/mach/tegra30-car.h +++ b/arch/arm/mach-tegra/include/mach/tegra30-car.h @@ -33,3 +33,5 @@ #define CRC_RST_DEV_V_CLR 0x434 #define CRC_CLK_OUT_ENB_V_SET 0x440 + +#define CRC_PLLE_AUX 0x48c diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index c18c67f705..bff5651802 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -17,12 +17,15 @@ */ #include +#include #include #include #include #include #include +#include + #include "clk.h" #define PLL_BASE_BYPASS BIT(31) @@ -393,6 +396,108 @@ const struct clk_ops tegra_clk_pll_ops = { .set_rate = clk_pll_set_rate, }; +static unsigned long clk_plle_recalc_rate(struct clk *hw, + unsigned long parent_rate) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + u32 val = pll_readl_base(pll); + u32 divn = 0, divm = 0, divp = 0; + u64 rate = parent_rate; + + divp = (val >> 16) & 0x3f; + divn = (val >> 8) & (0xff); + divm = (val >> 0) & (0xff); + divm *= divp; + + rate *= divn; + do_div(rate, divm); + return rate; +} + +static int clk_plle_training(struct tegra_clk_pll *pll) +{ + u32 val; + + /* + * PLLE is already disabled, and setup cleared; + * create falling edge on PLLE IDDQ input. + */ + val = readl(TEGRA_PMC_BASE + PMC_SATA_PWRGT); + val |= PMC_SATA_PWRGT_PLLE_IDDQ_VALUE; + writel(val, TEGRA_PMC_BASE + PMC_SATA_PWRGT); + + val = readl(TEGRA_PMC_BASE + PMC_SATA_PWRGT); + val |= PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL; + writel(val, TEGRA_PMC_BASE + PMC_SATA_PWRGT); + + val = readl(TEGRA_PMC_BASE + PMC_SATA_PWRGT); + val &= ~PMC_SATA_PWRGT_PLLE_IDDQ_VALUE; + writel(val, TEGRA_PMC_BASE + PMC_SATA_PWRGT); + + return wait_on_timeout(100 * MSECOND, + (pll_readl_misc(pll) & PLLE_MISC_READY)); +} + +static int clk_plle_enable(struct clk *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long input_rate = clk_get_rate(clk_get_parent(hw)); + struct tegra_clk_pll_freq_table sel; + u32 val; + int err; + + if (_get_table_rate(hw, &sel, pll->fixed_rate, input_rate)) + return -EINVAL; + + clk_pll_disable(hw); + + val = pll_readl_misc(pll); + val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK); + pll_writel_misc(val, pll); + + val = pll_readl_misc(pll); + if (!(val & PLLE_MISC_READY)) { + err = clk_plle_training(pll); + if (err) + return err; + } + + /* configure dividers */ + val = pll_readl_base(pll); + val &= ~(0x3fffff); + val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT); + val |= sel.m << 0; + val |= sel.n << 8; + val |= sel.p << 16; + val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT; + pll_writel_base(val, pll); + + val = pll_readl_misc(pll); + val |= PLLE_MISC_SETUP_VALUE; + val |= PLLE_MISC_LOCK_ENABLE; + pll_writel_misc(val, pll); + + val = readl(pll->clk_base + PLLE_SS_CTRL); + val |= PLLE_SS_DISABLE; + writel(val, pll->clk_base + PLLE_SS_CTRL); + + val = pll_readl_base(pll); + val |= (PLL_BASE_BYPASS | PLL_BASE_ENABLE); + pll_writel_base(val, pll); + + clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->base_reg, + pll->params->lock_bit_idx); + + return 0; +} + +const struct clk_ops tegra_clk_plle_ops = { + .recalc_rate = clk_plle_recalc_rate, + .is_enabled = clk_pll_is_enabled, + .disable = clk_pll_disable, + .enable = clk_plle_enable, +}; + static struct clk *_tegra_clk_register_pll(const char *name, const char *parent_name, void __iomem *clk_base, unsigned long flags, unsigned long fixed_rate, @@ -447,3 +552,14 @@ struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, flags, fixed_rate, pll_params, pll_flags, freq_table, &tegra_clk_pll_ops); } + +struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, + void __iomem *clk_base, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, u8 pll_flags, + struct tegra_clk_pll_freq_table *freq_table) +{ + return _tegra_clk_register_pll(name, parent_name, clk_base, + flags, fixed_rate, pll_params, pll_flags, freq_table, + &tegra_clk_plle_ops); +} diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index d5d0730602..85777a8898 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -101,6 +101,12 @@ struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, struct tegra_clk_pll_params *pll_params, u8 pll_flags, struct tegra_clk_pll_freq_table *freq_table); +struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, + void __iomem *clk_base, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, u8 pll_flags, + struct tegra_clk_pll_freq_table *freq_table); + /* struct tegra_clk_pll_out - PLL output divider */ struct tegra_clk_pll_out { struct clk hw; -- cgit v1.2.3 From 72f493e3e607a43ea856fcb9ca3d73f397228622 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sat, 4 Oct 2014 19:40:17 +0200 Subject: clk: tegra30: add PCIe clocks Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/mach-tegra/include/mach/tegra20-car.h | 2 ++ drivers/clk/tegra/clk-tegra30.c | 31 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/arch/arm/mach-tegra/include/mach/tegra20-car.h b/arch/arm/mach-tegra/include/mach/tegra20-car.h index 161e3d82a1..5a35f21c1f 100644 --- a/arch/arm/mach-tegra/include/mach/tegra20-car.h +++ b/arch/arm/mach-tegra/include/mach/tegra20-car.h @@ -49,6 +49,8 @@ #define CRC_CLK_OUT_ENB_H 0x014 #define CRC_CLK_OUT_ENB_H_DVC (1 << 15) +#define CRC_CLK_OUT_ENB_U 0x018 + #define CRC_CCLK_BURST_POLICY 0x020 #define CRC_CCLK_BURST_POLICY_SYS_STATE_SHIFT 28 #define CRC_CCLK_BURST_POLICY_SYS_STATE_FIQ 8 diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index ed6d73625c..9997ab9666 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -130,6 +130,13 @@ static struct tegra_clk_pll_freq_table pll_u_freq_table[] = { { 0, 0, 0, 0, 0, 0 }, }; +static struct tegra_clk_pll_freq_table pll_e_freq_table[] = { + /* PLLE special case: use cpcon field to store cml divider value */ + { 12000000, 100000000, 150, 1, 18, 11}, + { 216000000, 100000000, 200, 18, 24, 13}, + { 0, 0, 0, 0, 0, 0 }, +}; + /* PLL parameters */ static struct tegra_clk_pll_params pll_c_params = { .input_min = 2000000, @@ -201,6 +208,19 @@ static struct tegra_clk_pll_params pll_u_params = { .lock_delay = 1000, }; +static struct tegra_clk_pll_params pll_e_params = { + .input_min = 12000000, + .input_max = 216000000, + .cf_min = 12000000, + .cf_max = 12000000, + .vco_min = 1200000000, + .vco_max = 2400000000U, + .base_reg = CRC_PLLE_BASE, + .misc_reg = CRC_PLLE_MISC, + .lock_enable_bit_idx = CRC_PLLE_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + static void tegra30_pll_init(void) { /* PLLC */ @@ -251,6 +271,11 @@ static void tegra30_pll_init(void) clks[TEGRA30_CLK_PLL_U] = tegra_clk_register_pll("pll_u", "pll_ref", car_base, 0, 0, &pll_u_params, TEGRA_PLLU | TEGRA_PLL_HAS_CPCON, pll_u_freq_table); + + /* PLLE */ + clks[TEGRA30_CLK_PLL_E] = tegra_clk_register_plle("pll_e", "pll_ref", + car_base, 0, 100000000, &pll_e_params, + TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK, pll_e_freq_table); } static const char *mux_pllpcm_clkm[] = {"pll_p", "pll_c", "pll_m", "clk_m"}; @@ -278,6 +303,12 @@ static void tegra30_periph_init(void) mux_pllpcm_clkm, ARRAY_SIZE(mux_pllpcm_clkm), car_base, CRC_CLK_SOURCE_UARTE, TEGRA30_CLK_UARTE, TEGRA_PERIPH_ON_APB); + clks[TEGRA30_CLK_PCIE] = clk_gate("pcie", "clk_m", + car_base + CRC_CLK_OUT_ENB_U, 6, 0, 0); + clks[TEGRA30_CLK_AFI] = clk_gate("afi", "clk_m", + car_base + CRC_CLK_OUT_ENB_U, 8, 0, 0); + clks[TEGRA30_CLK_CML0] = clk_gate("cml0", "pll_e", + car_base + CRC_PLLE_AUX, 0, 0, 0); /* peripheral clocks with a divider */ clks[TEGRA30_CLK_MSELECT] = tegra_clk_register_periph("mselect", -- cgit v1.2.3 From 4e4d40c1aef77ad7bc24afa6e1eae5366006e8ec Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sat, 4 Oct 2014 19:40:18 +0200 Subject: i2c: tegra: move to fs initcall i2c is needed to enable voltage rails that are later needed by other drivers. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/boards/nvidia-beaver/board.c | 2 +- drivers/i2c/busses/i2c-tegra.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boards/nvidia-beaver/board.c b/arch/arm/boards/nvidia-beaver/board.c index e87594d5b7..e67d2aa973 100644 --- a/arch/arm/boards/nvidia-beaver/board.c +++ b/arch/arm/boards/nvidia-beaver/board.c @@ -35,4 +35,4 @@ static int nvidia_beaver_devices_init(void) return 0; } -device_initcall(nvidia_beaver_devices_init); +fs_initcall(nvidia_beaver_devices_init); diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index c52da18b57..f793cbeabf 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -696,4 +696,4 @@ static struct driver_d tegra_i2c_driver = { .probe = tegra_i2c_probe, .of_compatible = DRV_OF_COMPAT(tegra_i2c_compatible), }; -device_platform_driver(tegra_i2c_driver); +register_driver_macro(fs, platform, tegra_i2c_driver); -- cgit v1.2.3 From 54a60640bbadb40f4179e5ba7f0497c44a42ee41 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sat, 4 Oct 2014 19:40:19 +0200 Subject: ARM: tegra: beaver: enable PEX voltage rail Supply for the PCIe PLL. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/boards/nvidia-beaver/board.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/arm/boards/nvidia-beaver/board.c b/arch/arm/boards/nvidia-beaver/board.c index e67d2aa973..20707d883f 100644 --- a/arch/arm/boards/nvidia-beaver/board.c +++ b/arch/arm/boards/nvidia-beaver/board.c @@ -15,8 +15,10 @@ */ #include -#include +#include +#include #include +#include static int nvidia_beaver_devices_init(void) { @@ -33,6 +35,13 @@ static int nvidia_beaver_devices_init(void) data = 0x65; i2c_write_reg(&client, 0x32, &data, 1); + /* TPS659110: LDO1_REG = 1.05v, ACTIVE to PEX */ + data = 0x15; + i2c_write_reg(&client, 0x30, &data, 1); + + /* enable SYS_3V3_PEXS */ + gpio_direction_output(TEGRA_GPIO(L, 7), 1); + return 0; } fs_initcall(nvidia_beaver_devices_init); -- cgit v1.2.3 From 7a2255b43ea926970eaf3cae693d015c17cfea1c Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sat, 4 Oct 2014 19:40:20 +0200 Subject: tegra: pmc: add powerdomain handling In order to use some devices we first have to power up their power domain. Add support to do this in a generic way. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/mach-tegra/include/mach/tegra-powergate.h | 93 ++++++++++++++ arch/arm/mach-tegra/tegra20-pmc.c | 139 ++++++++++++++++++++- 2 files changed, 229 insertions(+), 3 deletions(-) create mode 100644 arch/arm/mach-tegra/include/mach/tegra-powergate.h diff --git a/arch/arm/mach-tegra/include/mach/tegra-powergate.h b/arch/arm/mach-tegra/include/mach/tegra-powergate.h new file mode 100644 index 0000000000..e32250a7fa --- /dev/null +++ b/arch/arm/mach-tegra/include/mach/tegra-powergate.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2010 Google, Inc + * + * Author: + * Colin Cross + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _MACH_TEGRA_POWERGATE_H_ +#define _MACH_TEGRA_POWERGATE_H_ + +struct clk; +struct reset_control; + +#define TEGRA_POWERGATE_CPU 0 +#define TEGRA_POWERGATE_3D 1 +#define TEGRA_POWERGATE_VENC 2 +#define TEGRA_POWERGATE_PCIE 3 +#define TEGRA_POWERGATE_VDEC 4 +#define TEGRA_POWERGATE_L2 5 +#define TEGRA_POWERGATE_MPE 6 +#define TEGRA_POWERGATE_HEG 7 +#define TEGRA_POWERGATE_SATA 8 +#define TEGRA_POWERGATE_CPU1 9 +#define TEGRA_POWERGATE_CPU2 10 +#define TEGRA_POWERGATE_CPU3 11 +#define TEGRA_POWERGATE_CELP 12 +#define TEGRA_POWERGATE_3D1 13 +#define TEGRA_POWERGATE_CPU0 14 +#define TEGRA_POWERGATE_C0NC 15 +#define TEGRA_POWERGATE_C1NC 16 +#define TEGRA_POWERGATE_SOR 17 +#define TEGRA_POWERGATE_DIS 18 +#define TEGRA_POWERGATE_DISB 19 +#define TEGRA_POWERGATE_XUSBA 20 +#define TEGRA_POWERGATE_XUSBB 21 +#define TEGRA_POWERGATE_XUSBC 22 +#define TEGRA_POWERGATE_VIC 23 +#define TEGRA_POWERGATE_IRAM 24 + +#define TEGRA_POWERGATE_3D0 TEGRA_POWERGATE_3D + +#define TEGRA_IO_RAIL_CSIA 0 +#define TEGRA_IO_RAIL_CSIB 1 +#define TEGRA_IO_RAIL_DSI 2 +#define TEGRA_IO_RAIL_MIPI_BIAS 3 +#define TEGRA_IO_RAIL_PEX_BIAS 4 +#define TEGRA_IO_RAIL_PEX_CLK1 5 +#define TEGRA_IO_RAIL_PEX_CLK2 6 +#define TEGRA_IO_RAIL_USB0 9 +#define TEGRA_IO_RAIL_USB1 10 +#define TEGRA_IO_RAIL_USB2 11 +#define TEGRA_IO_RAIL_USB_BIAS 12 +#define TEGRA_IO_RAIL_NAND 13 +#define TEGRA_IO_RAIL_UART 14 +#define TEGRA_IO_RAIL_BB 15 +#define TEGRA_IO_RAIL_AUDIO 17 +#define TEGRA_IO_RAIL_HSIC 19 +#define TEGRA_IO_RAIL_COMP 22 +#define TEGRA_IO_RAIL_HDMI 28 +#define TEGRA_IO_RAIL_PEX_CNTRL 32 +#define TEGRA_IO_RAIL_SDMMC1 33 +#define TEGRA_IO_RAIL_SDMMC3 34 +#define TEGRA_IO_RAIL_SDMMC4 35 +#define TEGRA_IO_RAIL_CAM 36 +#define TEGRA_IO_RAIL_RES 37 +#define TEGRA_IO_RAIL_HV 38 +#define TEGRA_IO_RAIL_DSIB 39 +#define TEGRA_IO_RAIL_DSIC 40 +#define TEGRA_IO_RAIL_DSID 41 +#define TEGRA_IO_RAIL_CSIE 44 +#define TEGRA_IO_RAIL_LVDS 57 +#define TEGRA_IO_RAIL_SYS_DDC 58 + +int tegra_powergate_is_powered(int id); +int tegra_powergate_power_on(int id); +int tegra_powergate_power_off(int id); +int tegra_powergate_remove_clamping(int id); + +/* Must be called with clk disabled, and returns with clk enabled */ +int tegra_powergate_sequence_power_up(int id, struct clk *clk, + struct reset_control *rst); + +#endif /* _MACH_TEGRA_POWERGATE_H_ */ diff --git a/arch/arm/mach-tegra/tegra20-pmc.c b/arch/arm/mach-tegra/tegra20-pmc.c index d86809432e..4cd01ffc29 100644 --- a/arch/arm/mach-tegra/tegra20-pmc.c +++ b/arch/arm/mach-tegra/tegra20-pmc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Lucas Stach + * Copyright (C) 2013-2014 Lucas Stach * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,15 +19,19 @@ * @brief Device driver for the Tegra 20 power management controller. */ -#include #include +#include #include #include #include - +#include +#include +#include +#include #include static void __iomem *pmc_base; +static int tegra_num_powerdomains; /* main SoC reset trigger */ void __noreturn reset_cpu(ulong addr) @@ -38,6 +42,133 @@ void __noreturn reset_cpu(ulong addr) } EXPORT_SYMBOL(reset_cpu); +static int tegra_powergate_set(int id, bool new_state) +{ + bool status; + + status = readl(pmc_base + PMC_PWRGATE_STATUS) & (1 << id); + + if (status == new_state) { + return 0; + } + + writel(PMC_PWRGATE_TOGGLE_START | id, pmc_base + PMC_PWRGATE_TOGGLE); + + return 0; +} + +int tegra_powergate_power_on(int id) +{ + if (id < 0 || id >= tegra_num_powerdomains) + return -EINVAL; + + return tegra_powergate_set(id, true); +} + +int tegra_powergate_power_off(int id) +{ + if (id < 0 || id >= tegra_num_powerdomains) + return -EINVAL; + + return tegra_powergate_set(id, false); +} +EXPORT_SYMBOL(tegra_powergate_power_off); + +int tegra_powergate_is_powered(int id) +{ + u32 status; + + if (id < 0 || id >= tegra_num_powerdomains) + return -EINVAL; + + status = readl(pmc_base + PMC_PWRGATE_STATUS) & (1 << id); + return !!status; +} + +int tegra_powergate_remove_clamping(int id) +{ + u32 mask; + + if (id < 0 || id >= tegra_num_powerdomains) + return -EINVAL; + + /* + * Tegra 2 has a bug where PCIE and VDE clamping masks are + * swapped relatively to the partition ids + */ + if (id == TEGRA_POWERGATE_VDEC) + mask = (1 << TEGRA_POWERGATE_PCIE); + else if (id == TEGRA_POWERGATE_PCIE) + mask = (1 << TEGRA_POWERGATE_VDEC); + else + mask = (1 << id); + + writel(mask, pmc_base + PMC_REMOVE_CLAMPING_CMD); + + return 0; +} +EXPORT_SYMBOL(tegra_powergate_remove_clamping); + +/* Must be called with clk disabled, and returns with clk enabled */ +int tegra_powergate_sequence_power_up(int id, struct clk *clk, + struct reset_control *rst) +{ + int ret; + + reset_control_assert(rst); + + ret = tegra_powergate_power_on(id); + if (ret) + goto err_power; + + ret = clk_enable(clk); + if (ret) + goto err_clk; + + udelay(10); + + ret = tegra_powergate_remove_clamping(id); + if (ret) + goto err_clamp; + + udelay(10); + reset_control_deassert(rst); + + return 0; + +err_clamp: + clk_disable(clk); +err_clk: + tegra_powergate_power_off(id); +err_power: + return ret; +} +EXPORT_SYMBOL(tegra_powergate_sequence_power_up); + +static int tegra_powergate_init(void) +{ + switch (tegra_get_chiptype()) { + case TEGRA20: + tegra_num_powerdomains = 7; + break; + case TEGRA30: + tegra_num_powerdomains = 14; + break; + case TEGRA114: + tegra_num_powerdomains = 23; + break; + case TEGRA124: + tegra_num_powerdomains = 25; + break; + default: + /* Unknown Tegra variant. Disable powergating */ + tegra_num_powerdomains = 0; + break; + } + + return 0; +} + static int tegra20_pmc_probe(struct device_d *dev) { pmc_base = dev_request_mem_region(dev, 0); @@ -46,6 +177,8 @@ static int tegra20_pmc_probe(struct device_d *dev) return PTR_ERR(pmc_base); } + tegra_powergate_init(); + return 0; } -- cgit v1.2.3 From 2840294a514231baff2a9ab484b6965519d1eeb3 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sat, 4 Oct 2014 19:40:21 +0200 Subject: of: import pci range parser from linux Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/of/Kconfig | 1 + drivers/of/address.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++ include/of_address.h | 57 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+) diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 97a1d933ec..97378ab59f 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -30,6 +30,7 @@ config OF_GPIO config OF_PCI bool depends on PCI + select OF_ADDRESS_PCI help OpenFirmware PCI bus accessors diff --git a/drivers/of/address.c b/drivers/of/address.c index b3cbb15453..8018d78bcb 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -179,6 +179,74 @@ static int of_bus_pci_translate(__be32 *addr, u64 offset, int na) } #endif /* CONFIG_OF_ADDRESS_PCI */ +#ifdef CONFIG_OF_PCI +int of_pci_range_parser_init(struct of_pci_range_parser *parser, + struct device_node *node) +{ + const int na = 3, ns = 2; + int rlen; + + parser->node = node; + parser->pna = of_n_addr_cells(node); + parser->np = parser->pna + na + ns; + + parser->range = of_get_property(node, "ranges", &rlen); + if (parser->range == NULL) + return -ENOENT; + + parser->end = parser->range + rlen / sizeof(__be32); + + return 0; +} +EXPORT_SYMBOL_GPL(of_pci_range_parser_init); + +struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser, + struct of_pci_range *range) +{ + const int na = 3, ns = 2; + + if (!range) + return NULL; + + if (!parser->range || parser->range + parser->np > parser->end) + return NULL; + + range->pci_space = parser->range[0]; + range->flags = of_bus_pci_get_flags(parser->range); + range->pci_addr = of_read_number(parser->range + 1, ns); + range->cpu_addr = of_translate_address(parser->node, + parser->range + na); + range->size = of_read_number(parser->range + parser->pna + na, ns); + + parser->range += parser->np; + + /* Now consume following elements while they are contiguous */ + while (parser->range + parser->np <= parser->end) { + u32 flags, pci_space; + u64 pci_addr, cpu_addr, size; + + pci_space = be32_to_cpup(parser->range); + flags = of_bus_pci_get_flags(parser->range); + pci_addr = of_read_number(parser->range + 1, ns); + cpu_addr = of_translate_address(parser->node, + parser->range + na); + size = of_read_number(parser->range + parser->pna + na, ns); + + if (flags != range->flags) + break; + if (pci_addr != range->pci_addr + range->size || + cpu_addr != range->cpu_addr + range->size) + break; + + range->size += size; + parser->range += parser->np; + } + + return range; +} +EXPORT_SYMBOL_GPL(of_pci_range_parser_one); +#endif /* CONFIG_OF_PCI */ + /* * Array of bus specific translators */ diff --git a/include/of_address.h b/include/of_address.h index 9022ab7ca0..ebf3ec2a24 100644 --- a/include/of_address.h +++ b/include/of_address.h @@ -4,6 +4,38 @@ #include #include +struct of_pci_range_parser { + struct device_node *node; + const __be32 *range; + const __be32 *end; + int np; + int pna; +}; + +struct of_pci_range { + u32 pci_space; + u64 pci_addr; + u64 cpu_addr; + u64 size; + u32 flags; +}; + +#define for_each_of_pci_range(parser, range) \ + for (; of_pci_range_parser_one(parser, range);) + +static inline void of_pci_range_to_resource(struct of_pci_range *range, + struct device_node *np, + struct resource *res) +{ + res->flags = range->flags; + res->start = range->cpu_addr; + res->end = range->cpu_addr + range->size - 1; + res->parent = NULL; + INIT_LIST_HEAD(&res->children); + INIT_LIST_HEAD(&res->sibling); + res->name = np->full_name; +} + #ifndef pci_address_to_pio static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; } #endif @@ -69,4 +101,29 @@ static inline void __iomem *of_iomap(struct device_node *np, int index) #endif /* CONFIG_OFTREE */ +#ifdef CONFIG_OF_PCI + +extern int of_pci_range_parser_init(struct of_pci_range_parser *parser, + struct device_node *node); + +extern struct of_pci_range *of_pci_range_parser_one( + struct of_pci_range_parser *parser, + struct of_pci_range *range); + +#else + +static inline int of_pci_range_parser_init(struct of_pci_range_parser *parser, + struct device_node *node) +{ + return -1; +} + +static inline struct of_pci_range *of_pci_range_parser_one( + struct of_pci_range_parser *parser, + struct of_pci_range *range) +{ + return NULL; +} +#endif /* CONFIG_OF_PCI */ + #endif /* __OF_ADDRESS_H */ -- cgit v1.2.3 From 18ff087fca88e1d418708d96d93c865e955f4c73 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sat, 4 Oct 2014 19:40:22 +0200 Subject: pci: add Tegra host controller driver Only tested on Tegra30 for now. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/pci/Kconfig | 7 + drivers/pci/Makefile | 1 + drivers/pci/pci-tegra.c | 1193 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1201 insertions(+) create mode 100644 drivers/pci/pci-tegra.c diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index d17a151082..0e9308e97b 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -30,6 +30,13 @@ config PCI_MVEBU select OF_PCI select PCI +config PCI_TEGRA + bool "NVDIA Tegra PCIe driver" + depends on ARCH_TEGRA + select OF_ADDRESS_PCI + select OF_PCI + select PCI + endmenu endif diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 442353173c..b93b28abea 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -8,3 +8,4 @@ ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG CPPFLAGS += $(ccflags-y) obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o pci-mvebu-phy.o +obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o diff --git a/drivers/pci/pci-tegra.c b/drivers/pci/pci-tegra.c new file mode 100644 index 0000000000..07bb251621 --- /dev/null +++ b/drivers/pci/pci-tegra.c @@ -0,0 +1,1193 @@ +/* + * Copyright (C) 2014 Lucas Stach + * + * based on code + * Copyright (c) 2010, CompuLab, Ltd. + * Copyright (c) 2008-2009, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* register definitions */ + +#define AFI_AXI_BAR0_SZ 0x00 +#define AFI_AXI_BAR1_SZ 0x04 +#define AFI_AXI_BAR2_SZ 0x08 +#define AFI_AXI_BAR3_SZ 0x0c +#define AFI_AXI_BAR4_SZ 0x10 +#define AFI_AXI_BAR5_SZ 0x14 + +#define AFI_AXI_BAR0_START 0x18 +#define AFI_AXI_BAR1_START 0x1c +#define AFI_AXI_BAR2_START 0x20 +#define AFI_AXI_BAR3_START 0x24 +#define AFI_AXI_BAR4_START 0x28 +#define AFI_AXI_BAR5_START 0x2c + +#define AFI_FPCI_BAR0 0x30 +#define AFI_FPCI_BAR1 0x34 +#define AFI_FPCI_BAR2 0x38 +#define AFI_FPCI_BAR3 0x3c +#define AFI_FPCI_BAR4 0x40 +#define AFI_FPCI_BAR5 0x44 + +#define AFI_CACHE_BAR0_SZ 0x48 +#define AFI_CACHE_BAR0_ST 0x4c +#define AFI_CACHE_BAR1_SZ 0x50 +#define AFI_CACHE_BAR1_ST 0x54 + +#define AFI_MSI_BAR_SZ 0x60 +#define AFI_MSI_FPCI_BAR_ST 0x64 +#define AFI_MSI_AXI_BAR_ST 0x68 + +#define AFI_MSI_VEC0 0x6c +#define AFI_MSI_VEC1 0x70 +#define AFI_MSI_VEC2 0x74 +#define AFI_MSI_VEC3 0x78 +#define AFI_MSI_VEC4 0x7c +#define AFI_MSI_VEC5 0x80 +#define AFI_MSI_VEC6 0x84 +#define AFI_MSI_VEC7 0x88 + +#define AFI_MSI_EN_VEC0 0x8c +#define AFI_MSI_EN_VEC1 0x90 +#define AFI_MSI_EN_VEC2 0x94 +#define AFI_MSI_EN_VEC3 0x98 +#define AFI_MSI_EN_VEC4 0x9c +#define AFI_MSI_EN_VEC5 0xa0 +#define AFI_MSI_EN_VEC6 0xa4 +#define AFI_MSI_EN_VEC7 0xa8 + +#define AFI_CONFIGURATION 0xac +#define AFI_CONFIGURATION_EN_FPCI (1 << 0) + +#define AFI_FPCI_ERROR_MASKS 0xb0 + +#define AFI_INTR_MASK 0xb4 +#define AFI_INTR_MASK_INT_MASK (1 << 0) +#define AFI_INTR_MASK_MSI_MASK (1 << 8) + +#define AFI_INTR_CODE 0xb8 +#define AFI_INTR_CODE_MASK 0xf +#define AFI_INTR_AXI_SLAVE_ERROR 1 +#define AFI_INTR_AXI_DECODE_ERROR 2 +#define AFI_INTR_TARGET_ABORT 3 +#define AFI_INTR_MASTER_ABORT 4 +#define AFI_INTR_INVALID_WRITE 5 +#define AFI_INTR_LEGACY 6 +#define AFI_INTR_FPCI_DECODE_ERROR 7 + +#define AFI_INTR_SIGNATURE 0xbc +#define AFI_UPPER_FPCI_ADDRESS 0xc0 +#define AFI_SM_INTR_ENABLE 0xc4 +#define AFI_SM_INTR_INTA_ASSERT (1 << 0) +#define AFI_SM_INTR_INTB_ASSERT (1 << 1) +#define AFI_SM_INTR_INTC_ASSERT (1 << 2) +#define AFI_SM_INTR_INTD_ASSERT (1 << 3) +#define AFI_SM_INTR_INTA_DEASSERT (1 << 4) +#define AFI_SM_INTR_INTB_DEASSERT (1 << 5) +#define AFI_SM_INTR_INTC_DEASSERT (1 << 6) +#define AFI_SM_INTR_INTD_DEASSERT (1 << 7) + +#define AFI_AFI_INTR_ENABLE 0xc8 +#define AFI_INTR_EN_INI_SLVERR (1 << 0) +#define AFI_INTR_EN_INI_DECERR (1 << 1) +#define AFI_INTR_EN_TGT_SLVERR (1 << 2) +#define AFI_INTR_EN_TGT_DECERR (1 << 3) +#define AFI_INTR_EN_TGT_WRERR (1 << 4) +#define AFI_INTR_EN_DFPCI_DECERR (1 << 5) +#define AFI_INTR_EN_AXI_DECERR (1 << 6) +#define AFI_INTR_EN_FPCI_TIMEOUT (1 << 7) +#define AFI_INTR_EN_PRSNT_SENSE (1 << 8) + +#define AFI_PCIE_CONFIG 0x0f8 +#define AFI_PCIE_CONFIG_PCIE_DISABLE(x) (1 << ((x) + 1)) +#define AFI_PCIE_CONFIG_PCIE_DISABLE_ALL 0xe +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK (0xf << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE (0x0 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420 (0x0 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL (0x1 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222 (0x1 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411 (0x2 << 20) + +#define AFI_FUSE 0x104 +#define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2) + +#define AFI_PEX0_CTRL 0x110 +#define AFI_PEX1_CTRL 0x118 +#define AFI_PEX2_CTRL 0x128 +#define AFI_PEX_CTRL_RST (1 << 0) +#define AFI_PEX_CTRL_CLKREQ_EN (1 << 1) +#define AFI_PEX_CTRL_REFCLK_EN (1 << 3) + +#define AFI_PEXBIAS_CTRL_0 0x168 + +#define RP_VEND_XP 0x00000F00 +#define RP_VEND_XP_DL_UP (1 << 30) + +#define RP_LINK_CONTROL_STATUS 0x00000090 +#define RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE 0x20000000 +#define RP_LINK_CONTROL_STATUS_LINKSTAT_MASK 0x3fff0000 + +#define PADS_CTL_SEL 0x0000009C + +#define PADS_CTL 0x000000A0 +#define PADS_CTL_IDDQ_1L (1 << 0) +#define PADS_CTL_TX_DATA_EN_1L (1 << 6) +#define PADS_CTL_RX_DATA_EN_1L (1 << 10) + +#define PADS_PLL_CTL_TEGRA20 0x000000B8 +#define PADS_PLL_CTL_TEGRA30 0x000000B4 +#define PADS_PLL_CTL_RST_B4SM (1 << 1) +#define PADS_PLL_CTL_LOCKDET (1 << 8) +#define PADS_PLL_CTL_REFCLK_MASK (0x3 << 16) +#define PADS_PLL_CTL_REFCLK_INTERNAL_CML (0 << 16) +#define PADS_PLL_CTL_REFCLK_INTERNAL_CMOS (1 << 16) +#define PADS_PLL_CTL_REFCLK_EXTERNAL (2 << 16) +#define PADS_PLL_CTL_TXCLKREF_MASK (0x1 << 20) +#define PADS_PLL_CTL_TXCLKREF_DIV10 (0 << 20) +#define PADS_PLL_CTL_TXCLKREF_DIV5 (1 << 20) +#define PADS_PLL_CTL_TXCLKREF_BUF_EN (1 << 22) + +#define PADS_REFCLK_CFG0 0x000000C8 +#define PADS_REFCLK_CFG1 0x000000CC + +/* + * Fields in PADS_REFCLK_CFG*. Those registers form an array of 16-bit + * entries, one entry per PCIe port. These field definitions and desired + * values aren't in the TRM, but do come from NVIDIA. + */ +#define PADS_REFCLK_CFG_TERM_SHIFT 2 /* 6:2 */ +#define PADS_REFCLK_CFG_E_TERM_SHIFT 7 +#define PADS_REFCLK_CFG_PREDI_SHIFT 8 /* 11:8 */ +#define PADS_REFCLK_CFG_DRVI_SHIFT 12 /* 15:12 */ + +/* Default value provided by HW engineering is 0xfa5c */ +#define PADS_REFCLK_CFG_VALUE \ + ( \ + (0x17 << PADS_REFCLK_CFG_TERM_SHIFT) | \ + (0 << PADS_REFCLK_CFG_E_TERM_SHIFT) | \ + (0xa << PADS_REFCLK_CFG_PREDI_SHIFT) | \ + (0xf << PADS_REFCLK_CFG_DRVI_SHIFT) \ + ) + +/* used to differentiate between Tegra SoC generations */ +struct tegra_pcie_soc_data { + unsigned int num_ports; + unsigned int msi_base_shift; + u32 pads_pll_ctl; + u32 tx_ref_sel; + bool has_pex_clkreq_en; + bool has_pex_bias_ctrl; + bool has_intr_prsnt_sense; + bool has_avdd_supply; + bool has_cml_clk; +}; + +struct tegra_pcie { + struct device_d *dev; + struct pci_controller pci; + + void __iomem *pads; + void __iomem *afi; + void __iomem *cs; + + struct list_head buses; + + struct resource io; + struct resource mem; + struct resource prefetch; + struct resource busn; + struct resource *cs_res; + + struct clk *pex_clk; + struct clk *afi_clk; + struct clk *pll_e; + struct clk *cml_clk; + + struct reset_control *pex_rst; + struct reset_control *afi_rst; + struct reset_control *pcie_xrst; + + struct list_head ports; + unsigned int num_ports; + u32 xbar_config; + + struct regulator *pex_clk_supply; + struct regulator *vdd_supply; + struct regulator *avdd_supply; + + const struct tegra_pcie_soc_data *soc_data; +}; + +struct tegra_pcie_port { + struct tegra_pcie *pcie; + struct list_head list; + struct resource regs; + void __iomem *base; + unsigned int index; + unsigned int lanes; +}; + +static inline struct tegra_pcie *host_to_pcie(struct pci_controller *host) +{ + return container_of(host, struct tegra_pcie, pci); +} + +static inline void afi_writel(struct tegra_pcie *pcie, u32 value, + unsigned long offset) +{ + writel(value, pcie->afi + offset); +} + +static inline u32 afi_readl(struct tegra_pcie *pcie, unsigned long offset) +{ + return readl(pcie->afi + offset); +} + +static inline void pads_writel(struct tegra_pcie *pcie, u32 value, + unsigned long offset) +{ + writel(value, pcie->pads + offset); +} + +static inline u32 pads_readl(struct tegra_pcie *pcie, unsigned long offset) +{ + return readl(pcie->pads + offset); +} + +static void __iomem *tegra_pcie_conf_address(struct pci_bus *bus, + unsigned int devfn, + int where) +{ + struct tegra_pcie *pcie = host_to_pcie(bus->host); + void __iomem *addr = NULL; + + if (bus->number == 0) { + unsigned int slot = PCI_SLOT(devfn); + struct tegra_pcie_port *port; + + list_for_each_entry(port, &pcie->ports, list) { + if (port->index + 1 == slot) { + addr = (void __force __iomem *) + port->regs.start + (where & ~3); + break; + } + } + } else { + addr = pcie->cs; + + addr += ((where & 0xf00) << 16) | (bus->number << 16) | + (PCI_SLOT(devfn) << 11) | (PCI_FUNC(devfn) << 8) | + (where & 0xfc); + } + + return addr; +} + +static int tegra_pcie_read_conf(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *value) +{ + void __iomem *addr; + + addr = tegra_pcie_conf_address(bus, devfn, where); + if (!addr) { + *value = 0xffffffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + + *value = readl(addr); + + if (size == 1) + *value = (*value >> (8 * (where & 3))) & 0xff; + else if (size == 2) + *value = (*value >> (8 * (where & 3))) & 0xffff; + + return PCIBIOS_SUCCESSFUL; +} + +static int tegra_pcie_write_conf(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 value) +{ + void __iomem *addr; + u32 mask, tmp; + + addr = tegra_pcie_conf_address(bus, devfn, where); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (size == 4) { + writel(value, addr); + return PCIBIOS_SUCCESSFUL; + } + + if (size == 2) + mask = ~(0xffff << ((where & 0x3) * 8)); + else if (size == 1) + mask = ~(0xff << ((where & 0x3) * 8)); + else + return PCIBIOS_BAD_REGISTER_NUMBER; + + tmp = readl(addr) & mask; + tmp |= value << ((where & 0x3) * 8); + writel(tmp, addr); + + return PCIBIOS_SUCCESSFUL; +} + +static int tegra_pcie_res_start(struct pci_bus *bus, resource_size_t res_addr) +{ + return res_addr; +} + +static struct pci_ops tegra_pcie_ops = { + .read = tegra_pcie_read_conf, + .write = tegra_pcie_write_conf, + .res_start = tegra_pcie_res_start, +}; + +static unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port) +{ + unsigned long ret = 0; + + switch (port->index) { + case 0: + ret = AFI_PEX0_CTRL; + break; + + case 1: + ret = AFI_PEX1_CTRL; + break; + + case 2: + ret = AFI_PEX2_CTRL; + break; + } + + return ret; +} + +static void tegra_pcie_port_reset(struct tegra_pcie_port *port) +{ + unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port); + unsigned long value; + + /* pulse reset signal */ + value = afi_readl(port->pcie, ctrl); + value &= ~AFI_PEX_CTRL_RST; + afi_writel(port->pcie, value, ctrl); + + mdelay(1); + + value = afi_readl(port->pcie, ctrl); + value |= AFI_PEX_CTRL_RST; + afi_writel(port->pcie, value, ctrl); +} + +static void tegra_pcie_port_enable(struct tegra_pcie_port *port) +{ + const struct tegra_pcie_soc_data *soc = port->pcie->soc_data; + unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port); + unsigned long value; + + /* enable reference clock */ + value = afi_readl(port->pcie, ctrl); + value |= AFI_PEX_CTRL_REFCLK_EN; + + if (soc->has_pex_clkreq_en) + value |= AFI_PEX_CTRL_CLKREQ_EN; + + afi_writel(port->pcie, value, ctrl); + + tegra_pcie_port_reset(port); +} + +static void tegra_pcie_port_disable(struct tegra_pcie_port *port) +{ + unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port); + unsigned long value; + + /* assert port reset */ + value = afi_readl(port->pcie, ctrl); + value &= ~AFI_PEX_CTRL_RST; + afi_writel(port->pcie, value, ctrl); + + /* disable reference clock */ + value = afi_readl(port->pcie, ctrl); + value &= ~AFI_PEX_CTRL_REFCLK_EN; + afi_writel(port->pcie, value, ctrl); +} + +static void tegra_pcie_port_free(struct tegra_pcie_port *port) +{ + list_del(&port->list); + kfree(port); +} + +#if 0 +static void tegra_pcie_fixup_bridge(struct pci_dev *dev) +{ + u16 reg; + + if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) { + pci_read_config_word(dev, PCI_COMMAND, ®); + reg |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | PCI_COMMAND_SERR); + pci_write_config_word(dev, PCI_COMMAND, reg); + } +} +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_fixup_bridge); + +/* Tegra PCIE root complex wrongly reports device class */ +static void tegra_pcie_fixup_class(struct pci_dev *dev) +{ + dev->class = PCI_CLASS_BRIDGE_PCI << 8; +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf0, tegra_pcie_fixup_class); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_fixup_class); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1c, tegra_pcie_fixup_class); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1d, tegra_pcie_fixup_class); + +/* Tegra PCIE requires relaxed ordering */ +static void tegra_pcie_relax_enable(struct pci_dev *dev) +{ + pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_RELAX_EN); +} +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_relax_enable); +#endif + +/* + * FPCI map is as follows: + * - 0xfdfc000000: I/O space + * - 0xfdfe000000: type 0 configuration space + * - 0xfdff000000: type 1 configuration space + * - 0xfe00000000: type 0 extended configuration space + * - 0xfe10000000: type 1 extended configuration space + */ +static void tegra_pcie_setup_translations(struct tegra_pcie *pcie) +{ + u32 fpci_bar, size, axi_address; + + /* Bar 0: type 1 extended configuration space */ + fpci_bar = 0xfe100000; + size = resource_size(pcie->cs_res); + axi_address = pcie->cs_res->start; + afi_writel(pcie, axi_address, AFI_AXI_BAR0_START); + afi_writel(pcie, size >> 12, AFI_AXI_BAR0_SZ); + afi_writel(pcie, fpci_bar, AFI_FPCI_BAR0); + + /* Bar 1: downstream IO bar */ + fpci_bar = 0xfdfc0000; + size = resource_size(&pcie->io); + axi_address = pcie->io.start; + afi_writel(pcie, axi_address, AFI_AXI_BAR1_START); + afi_writel(pcie, size >> 12, AFI_AXI_BAR1_SZ); + afi_writel(pcie, fpci_bar, AFI_FPCI_BAR1); + + /* Bar 2: prefetchable memory BAR */ + fpci_bar = (((pcie->prefetch.start >> 12) & 0x0fffffff) << 4) | 0x1; + size = resource_size(&pcie->prefetch); + axi_address = pcie->prefetch.start; + afi_writel(pcie, axi_address, AFI_AXI_BAR2_START); + afi_writel(pcie, size >> 12, AFI_AXI_BAR2_SZ); + afi_writel(pcie, fpci_bar, AFI_FPCI_BAR2); + + /* Bar 3: non prefetchable memory BAR */ + fpci_bar = (((pcie->mem.start >> 12) & 0x0fffffff) << 4) | 0x1; + size = resource_size(&pcie->mem); + axi_address = pcie->mem.start; + afi_writel(pcie, axi_address, AFI_AXI_BAR3_START); + afi_writel(pcie, size >> 12, AFI_AXI_BAR3_SZ); + afi_writel(pcie, fpci_bar, AFI_FPCI_BAR3); + + /* NULL out the remaining BARs as they are not used */ + afi_writel(pcie, 0, AFI_AXI_BAR4_START); + afi_writel(pcie, 0, AFI_AXI_BAR4_SZ); + afi_writel(pcie, 0, AFI_FPCI_BAR4); + + afi_writel(pcie, 0, AFI_AXI_BAR5_START); + afi_writel(pcie, 0, AFI_AXI_BAR5_SZ); + afi_writel(pcie, 0, AFI_FPCI_BAR5); + + /* map all upstream transactions as uncached */ + /* FIXME: is 0 ok for BAR0 start ??? */ + afi_writel(pcie, 0, AFI_CACHE_BAR0_ST); + afi_writel(pcie, 0, AFI_CACHE_BAR0_SZ); + afi_writel(pcie, 0, AFI_CACHE_BAR1_ST); + afi_writel(pcie, 0, AFI_CACHE_BAR1_SZ); + + /* MSI translations are setup only when needed */ + afi_writel(pcie, 0, AFI_MSI_FPCI_BAR_ST); + afi_writel(pcie, 0, AFI_MSI_BAR_SZ); + afi_writel(pcie, 0, AFI_MSI_AXI_BAR_ST); + afi_writel(pcie, 0, AFI_MSI_BAR_SZ); +} + +static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) +{ + const struct tegra_pcie_soc_data *soc = pcie->soc_data; + struct tegra_pcie_port *port; + unsigned long value; + + /* power down PCIe slot clock bias pad */ + if (soc->has_pex_bias_ctrl) + afi_writel(pcie, 0, AFI_PEXBIAS_CTRL_0); + + /* configure mode and disable all ports */ + value = afi_readl(pcie, AFI_PCIE_CONFIG); + value &= ~AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK; + value |= AFI_PCIE_CONFIG_PCIE_DISABLE_ALL | pcie->xbar_config; + + list_for_each_entry(port, &pcie->ports, list) + value &= ~AFI_PCIE_CONFIG_PCIE_DISABLE(port->index); + + afi_writel(pcie, value, AFI_PCIE_CONFIG); + + value = afi_readl(pcie, AFI_FUSE); + value |= AFI_FUSE_PCIE_T0_GEN2_DIS; + afi_writel(pcie, value, AFI_FUSE); + + /* initialize internal PHY, enable up to 16 PCIE lanes */ + pads_writel(pcie, 0x0, PADS_CTL_SEL); + + /* override IDDQ to 1 on all 4 lanes */ + value = pads_readl(pcie, PADS_CTL); + value |= PADS_CTL_IDDQ_1L; + pads_writel(pcie, value, PADS_CTL); + + /* + * Set up PHY PLL inputs select PLLE output as refclock, + * set TX ref sel to div10 (not div5). + */ + value = pads_readl(pcie, soc->pads_pll_ctl); + value &= ~(PADS_PLL_CTL_REFCLK_MASK | PADS_PLL_CTL_TXCLKREF_MASK); + value |= PADS_PLL_CTL_REFCLK_INTERNAL_CML | soc->tx_ref_sel; + pads_writel(pcie, value, soc->pads_pll_ctl); + + /* take PLL out of reset */ + value = pads_readl(pcie, soc->pads_pll_ctl); + value |= PADS_PLL_CTL_RST_B4SM; + pads_writel(pcie, value, soc->pads_pll_ctl); + + /* Configure the reference clock driver */ + value = PADS_REFCLK_CFG_VALUE | (PADS_REFCLK_CFG_VALUE << 16); + pads_writel(pcie, value, PADS_REFCLK_CFG0); + if (soc->num_ports > 2) + pads_writel(pcie, PADS_REFCLK_CFG_VALUE, PADS_REFCLK_CFG1); + + /* wait for the PLL to lock */ + if (wait_on_timeout(300 * MSECOND, + (pads_readl(pcie, soc->pads_pll_ctl) & PADS_PLL_CTL_LOCKDET))) { + pr_err("Tegra PCIe error: timeout waiting for PLL\n"); + return -EBUSY; + } + + /* turn off IDDQ override */ + value = pads_readl(pcie, PADS_CTL); + value &= ~PADS_CTL_IDDQ_1L; + pads_writel(pcie, value, PADS_CTL); + + /* enable TX/RX data */ + value = pads_readl(pcie, PADS_CTL); + value |= PADS_CTL_TX_DATA_EN_1L | PADS_CTL_RX_DATA_EN_1L; + pads_writel(pcie, value, PADS_CTL); + + /* take the PCIe interface module out of reset */ + reset_control_deassert(pcie->pcie_xrst); + + /* finally enable PCIe */ + value = afi_readl(pcie, AFI_CONFIGURATION); + value |= AFI_CONFIGURATION_EN_FPCI; + afi_writel(pcie, value, AFI_CONFIGURATION); + + value = AFI_INTR_EN_INI_SLVERR | AFI_INTR_EN_INI_DECERR | + AFI_INTR_EN_TGT_SLVERR | AFI_INTR_EN_TGT_DECERR | + AFI_INTR_EN_TGT_WRERR | AFI_INTR_EN_DFPCI_DECERR; + + if (soc->has_intr_prsnt_sense) + value |= AFI_INTR_EN_PRSNT_SENSE; + + afi_writel(pcie, value, AFI_AFI_INTR_ENABLE); + afi_writel(pcie, 0xffffffff, AFI_SM_INTR_ENABLE); + + /* don't enable MSI for now, only when needed */ + afi_writel(pcie, AFI_INTR_MASK_INT_MASK, AFI_INTR_MASK); + + /* disable all exceptions */ + afi_writel(pcie, 0, AFI_FPCI_ERROR_MASKS); + + return 0; +} + +static void tegra_pcie_power_off(struct tegra_pcie *pcie) +{ + const struct tegra_pcie_soc_data *soc = pcie->soc_data; + int err; + + /* TODO: disable and unprepare clocks? */ + + reset_control_assert(pcie->pcie_xrst); + reset_control_assert(pcie->afi_rst); + reset_control_assert(pcie->pex_rst); + + tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); + + if (soc->has_avdd_supply) { + err = regulator_disable(pcie->avdd_supply); + if (err < 0) + dev_warn(pcie->dev, + "failed to disable AVDD regulator: %d\n", + err); + } + + err = regulator_disable(pcie->pex_clk_supply); + if (err < 0) + dev_warn(pcie->dev, "failed to disable pex-clk regulator: %d\n", + err); + + err = regulator_disable(pcie->vdd_supply); + if (err < 0) + dev_warn(pcie->dev, "failed to disable VDD regulator: %d\n", + err); +} + +static int tegra_pcie_power_on(struct tegra_pcie *pcie) +{ + const struct tegra_pcie_soc_data *soc = pcie->soc_data; + int err; + + reset_control_assert(pcie->pcie_xrst); + reset_control_assert(pcie->afi_rst); + reset_control_assert(pcie->pex_rst); + + tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); + + /* enable regulators */ + err = regulator_enable(pcie->vdd_supply); + if (err < 0) { + dev_err(pcie->dev, "failed to enable VDD regulator: %d\n", err); + return err; + } + + err = regulator_enable(pcie->pex_clk_supply); + if (err < 0) { + dev_err(pcie->dev, "failed to enable pex-clk regulator: %d\n", + err); + return err; + } + + if (soc->has_avdd_supply) { + err = regulator_enable(pcie->avdd_supply); + if (err < 0) { + dev_err(pcie->dev, + "failed to enable AVDD regulator: %d\n", + err); + return err; + } + } + + err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE, + pcie->pex_clk, + pcie->pex_rst); + if (err) { + dev_err(pcie->dev, "powerup sequence failed: %d\n", err); + return err; + } + + reset_control_deassert(pcie->afi_rst); + + err = clk_enable(pcie->afi_clk); + if (err < 0) { + dev_err(pcie->dev, "failed to enable AFI clock: %d\n", err); + return err; + } + + if (soc->has_cml_clk) { + err = clk_enable(pcie->cml_clk); + if (err < 0) { + dev_err(pcie->dev, "failed to enable CML clock: %d\n", + err); + return err; + } + } + + err = clk_enable(pcie->pll_e); + if (err < 0) { + dev_err(pcie->dev, "failed to enable PLLE clock: %d\n", err); + return err; + } + + return 0; +} + +static int tegra_pcie_clocks_get(struct tegra_pcie *pcie) +{ + const struct tegra_pcie_soc_data *soc = pcie->soc_data; + + pcie->pex_clk = clk_get(pcie->dev, "pex"); + if (IS_ERR(pcie->pex_clk)) + return PTR_ERR(pcie->pex_clk); + + pcie->afi_clk = clk_get(pcie->dev, "afi"); + if (IS_ERR(pcie->afi_clk)) + return PTR_ERR(pcie->afi_clk); + + pcie->pll_e = clk_get(pcie->dev, "pll_e"); + if (IS_ERR(pcie->pll_e)) + return PTR_ERR(pcie->pll_e); + + if (soc->has_cml_clk) { + pcie->cml_clk = clk_get(pcie->dev, "cml"); + if (IS_ERR(pcie->cml_clk)) + return PTR_ERR(pcie->cml_clk); + } + + return 0; +} + +static int tegra_pcie_resets_get(struct tegra_pcie *pcie) +{ + pcie->pex_rst = reset_control_get(pcie->dev, "pex"); + if (IS_ERR(pcie->pex_rst)) + return PTR_ERR(pcie->pex_rst); + + pcie->afi_rst = reset_control_get(pcie->dev, "afi"); + if (IS_ERR(pcie->afi_rst)) + return PTR_ERR(pcie->afi_rst); + + pcie->pcie_xrst = reset_control_get(pcie->dev, "pcie_x"); + if (IS_ERR(pcie->pcie_xrst)) + return PTR_ERR(pcie->pcie_xrst); + + return 0; +} + +static int tegra_pcie_get_resources(struct tegra_pcie *pcie) +{ + struct device_d *dev = pcie->dev; + int err; + + err = tegra_pcie_clocks_get(pcie); + if (err) { + dev_err(dev, "failed to get clocks: %d\n", err); + return err; + } + + err = tegra_pcie_resets_get(pcie); + if (err) { + dev_err(dev, "failed to get resets: %d\n", err); + return err; + } + + err = tegra_pcie_power_on(pcie); + if (err) { + dev_err(dev, "failed to power up: %d\n", err); + return err; + } + + pcie->pads = dev_request_mem_region_by_name(dev, "pads"); + if (IS_ERR(pcie->pads)) { + err = PTR_ERR(pcie->pads); + goto poweroff; + } + + pcie->afi = dev_request_mem_region_by_name(dev, "afi"); + if (IS_ERR(pcie->afi)) { + err = PTR_ERR(pcie->afi); + goto poweroff; + } + + pcie->cs_res = dev_get_resource_by_name(dev, IORESOURCE_MEM, "cs"); + pcie->cs = dev_request_mem_region_by_name(dev, "cs"); + if (IS_ERR(pcie->cs)) { + err = PTR_ERR(pcie->cs); + goto poweroff; + } + + return 0; + +poweroff: + tegra_pcie_power_off(pcie); + return err; +} + +static int tegra_pcie_put_resources(struct tegra_pcie *pcie) +{ + tegra_pcie_power_off(pcie); + return 0; +} + +static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes, + u32 *xbar) +{ + struct device_node *np = pcie->dev->device_node; + + if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) { + switch (lanes) { + case 0x00000204: + dev_info(pcie->dev, "4x1, 2x1 configuration\n"); + *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420; + return 0; + + case 0x00020202: + dev_info(pcie->dev, "2x3 configuration\n"); + *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222; + return 0; + + case 0x00010104: + dev_info(pcie->dev, "4x1, 1x2 configuration\n"); + *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411; + return 0; + } + } else if (of_device_is_compatible(np, "nvidia,tegra20-pcie")) { + switch (lanes) { + case 0x00000004: + dev_info(pcie->dev, "single-mode configuration\n"); + *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE; + return 0; + + case 0x00000202: + dev_info(pcie->dev, "dual-mode configuration\n"); + *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL; + return 0; + } + } + + return -EINVAL; +} + +static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) +{ + const struct tegra_pcie_soc_data *soc = pcie->soc_data; + struct device_node *np = pcie->dev->device_node, *port; + struct of_pci_range_parser parser; + struct of_pci_range range; + struct resource *rp_res; + struct resource res; + u32 lanes = 0; + int err; + + if (of_pci_range_parser_init(&parser, np)) { + dev_err(pcie->dev, "missing \"ranges\" property\n"); + return -EINVAL; + } + + pcie->vdd_supply = regulator_get(pcie->dev, "vdd"); + if (IS_ERR(pcie->vdd_supply)) + return PTR_ERR(pcie->vdd_supply); + + pcie->pex_clk_supply = regulator_get(pcie->dev, "pex-clk"); + if (IS_ERR(pcie->pex_clk_supply)) + return PTR_ERR(pcie->pex_clk_supply); + + if (soc->has_avdd_supply) { + pcie->avdd_supply = regulator_get(pcie->dev, "avdd"); + if (IS_ERR(pcie->avdd_supply)) + return PTR_ERR(pcie->avdd_supply); + } + + for_each_of_pci_range(&parser, &range) { + of_pci_range_to_resource(&range, np, &res); + + switch (res.flags & IORESOURCE_TYPE_BITS) { + case IORESOURCE_IO: + memcpy(&pcie->io, &res, sizeof(res)); + pcie->io.name = "I/O"; + break; + + case IORESOURCE_MEM: + if (res.flags & IORESOURCE_PREFETCH) { + memcpy(&pcie->prefetch, &res, sizeof(res)); + pcie->prefetch.name = "PREFETCH"; + } else { + memcpy(&pcie->mem, &res, sizeof(res)); + pcie->mem.name = "MEM"; + } + break; + } + } +#if 0 + err = of_pci_parse_bus_range(np, &pcie->busn); + if (err < 0) { + dev_err(pcie->dev, "failed to parse ranges property: %d\n", + err); + pcie->busn.name = np->name; + pcie->busn.start = 0; + pcie->busn.end = 0xff; + pcie->busn.flags = IORESOURCE_BUS; + } +#endif + /* parse root ports */ + for_each_child_of_node(np, port) { + struct tegra_pcie_port *rp; + unsigned int index; + u32 value; + + err = of_pci_get_devfn(port); + if (err < 0) { + dev_err(pcie->dev, "failed to parse address: %d\n", + err); + return err; + } + + index = PCI_SLOT(err); + + if (index < 1 || index > soc->num_ports) { + dev_err(pcie->dev, "invalid port number: %d\n", index); + return -EINVAL; + } + + index--; + + err = of_property_read_u32(port, "nvidia,num-lanes", &value); + if (err < 0) { + dev_err(pcie->dev, "failed to parse # of lanes: %d\n", + err); + return err; + } + + if (value > 16) { + dev_err(pcie->dev, "invalid # of lanes: %u\n", value); + return -EINVAL; + } + + lanes |= value << (index << 3); + + if (!of_device_is_available(port)) + continue; + + rp = kzalloc(sizeof(*rp), GFP_KERNEL); + if (!rp) + return -ENOMEM; + + err = of_address_to_resource(port, 0, &rp->regs); + if (err < 0) { + dev_err(pcie->dev, "failed to parse address: %d\n", + err); + return err; + } + + /* + * if the port address is inside the NULL page we alias this + * range at +1MB and fix up the resource, otherwise just request + */ + if (!(rp->regs.start & 0xfffff000)) { + rp_res = request_iomem_region(dev_name(pcie->dev), + rp->regs.start + SZ_1M, + rp->regs.end + SZ_1M); + if (!rp_res) + return -ENOMEM; + + map_io_sections(rp->regs.start, + (void *)rp_res->start, SZ_1M); + + rp->regs.start = rp_res->start; + rp->regs.end = rp_res->end; + } else { + rp_res = request_iomem_region(dev_name(pcie->dev), + rp->regs.start, rp->regs.end); + if (!rp_res) + return -ENOMEM; + } + + INIT_LIST_HEAD(&rp->list); + rp->index = index; + rp->lanes = value; + rp->pcie = pcie; + + rp->base = (void __force __iomem *)rp->regs.start; + if (IS_ERR(rp->base)) + return PTR_ERR(rp->base); + + list_add_tail(&rp->list, &pcie->ports); + } + + err = tegra_pcie_get_xbar_config(pcie, lanes, &pcie->xbar_config); + if (err < 0) { + dev_err(pcie->dev, "invalid lane configuration\n"); + return err; + } + + return 0; +} + +/* + * FIXME: If there are no PCIe cards attached, then calling this function + * can result in the increase of the bootup time as there are big timeout + * loops. + */ +#define TEGRA_PCIE_LINKUP_TIMEOUT 200 /* up to 1.2 seconds */ +static bool tegra_pcie_port_check_link(struct tegra_pcie_port *port) +{ + unsigned int timeout; + unsigned int retries = 2; + + do { + timeout = wait_on_timeout(50 * MSECOND, + readl(port->regs.start + RP_VEND_XP) & RP_VEND_XP_DL_UP); + + if (timeout) { + dev_dbg(port->pcie->dev, "link %u down, retrying\n", + port->index); + goto retry; + } + + timeout = wait_on_timeout(200 * MSECOND, + readl(port->regs.start + RP_LINK_CONTROL_STATUS) & + RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE); + + if (!timeout) + return true; + +retry: + tegra_pcie_port_reset(port); + } while (--retries); + + return false; +} + +static int tegra_pcie_enable(struct tegra_pcie *pcie) +{ + struct tegra_pcie_port *port, *tmp; + + list_for_each_entry_safe(port, tmp, &pcie->ports, list) { + dev_dbg(pcie->dev, "probing port %u, using %u lanes\n", + port->index, port->lanes); + + tegra_pcie_port_enable(port); + + if (tegra_pcie_port_check_link(port)) + continue; + + dev_dbg(pcie->dev, "link %u down, ignoring\n", port->index); + + tegra_pcie_port_disable(port); + tegra_pcie_port_free(port); + } + + pcie->pci.parent = pcie->dev; + pcie->pci.pci_ops = &tegra_pcie_ops; + pcie->pci.mem_resource = &pcie->mem; + pcie->pci.mem_pref_resource = &pcie->prefetch; + pcie->pci.io_resource = &pcie->io; + + register_pci_controller(&pcie->pci); + + return 0; +} + +static const struct tegra_pcie_soc_data tegra20_pcie_data = { + .num_ports = 2, + .msi_base_shift = 0, + .pads_pll_ctl = PADS_PLL_CTL_TEGRA20, + .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_DIV10, + .has_pex_clkreq_en = false, + .has_pex_bias_ctrl = false, + .has_intr_prsnt_sense = false, + .has_avdd_supply = false, + .has_cml_clk = false, +}; + +static const struct tegra_pcie_soc_data tegra30_pcie_data = { + .num_ports = 3, + .msi_base_shift = 8, + .pads_pll_ctl = PADS_PLL_CTL_TEGRA30, + .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN, + .has_pex_clkreq_en = true, + .has_pex_bias_ctrl = true, + .has_intr_prsnt_sense = true, + .has_avdd_supply = true, + .has_cml_clk = true, +}; + +static __maybe_unused struct of_device_id tegra_pcie_of_match[] = { + { + .compatible = "nvidia,tegra30-pcie", + .data = (unsigned long)&tegra30_pcie_data + }, { + .compatible = "nvidia,tegra20-pcie", + .data = (unsigned long)&tegra20_pcie_data + }, { + /* sentinel */ + }, +}; + +static int tegra_pcie_probe(struct device_d *dev) +{ + struct tegra_pcie *pcie; + int err; + + pcie = kzalloc(sizeof(*pcie), GFP_KERNEL); + if (!pcie) + return -ENOMEM; + + INIT_LIST_HEAD(&pcie->buses); + INIT_LIST_HEAD(&pcie->ports); + dev_get_drvdata(dev, (unsigned long *)&pcie->soc_data); + pcie->dev = dev; + + err = tegra_pcie_parse_dt(pcie); + if (err < 0) { + printk("parse DT failed\n"); + return err; + } + + err = tegra_pcie_get_resources(pcie); + if (err < 0) { + dev_err(dev, "failed to request resources: %d\n", err); + return err; + } + + err = tegra_pcie_enable_controller(pcie); + if (err) + goto put_resources; + + /* setup the AFI address translations */ + tegra_pcie_setup_translations(pcie); + + err = tegra_pcie_enable(pcie); + if (err < 0) { + dev_err(dev, "failed to enable PCIe ports: %d\n", err); + goto put_resources; + } + + return 0; + +put_resources: + tegra_pcie_put_resources(pcie); + return err; +} + +static struct driver_d tegra_pcie_driver = { + .name = "tegra-pcie", + .of_compatible = DRV_OF_COMPAT(tegra_pcie_of_match), + .probe = tegra_pcie_probe, +}; +device_platform_driver(tegra_pcie_driver); -- cgit v1.2.3 From 7f5a86db039a27b09d4bef779134972efde0cb08 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sat, 4 Oct 2014 19:40:23 +0200 Subject: ARM: tegra: advertise PCI support Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/Kconfig | 1 + arch/arm/configs/tegra_v7_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 3c9b81ab06..2a00e5ef38 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -198,6 +198,7 @@ config ARCH_TEGRA bool "NVIDIA Tegra" select CPU_V7 select HAS_DEBUG_LL + select HW_HAS_PCI select COMMON_CLK select COMMON_CLK_OF_PROVIDER select CLKDEV_LOOKUP diff --git a/arch/arm/configs/tegra_v7_defconfig b/arch/arm/configs/tegra_v7_defconfig index 22f5765a3b..8f01b549df 100644 --- a/arch/arm/configs/tegra_v7_defconfig +++ b/arch/arm/configs/tegra_v7_defconfig @@ -37,6 +37,7 @@ CONFIG_DRIVER_SERIAL_NS16550=y CONFIG_MCI=y CONFIG_MCI_MMC_BOOT_PARTITIONS=y CONFIG_MCI_TEGRA=y +CONFIG_PCI_TEGRA=y CONFIG_FS_EXT4=y CONFIG_FS_FAT=y CONFIG_FS_FAT_LFN=y -- cgit v1.2.3 From b64b24db752d450173bd0b0bc4a45d6fb7222847 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sat, 4 Oct 2014 19:40:24 +0200 Subject: net: add rtl8169 driver This adds the driver for RealTek 8169 and compatible pci attached network chips. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/net/Kconfig | 8 + drivers/net/Makefile | 1 + drivers/net/rtl8169.c | 566 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 575 insertions(+) create mode 100644 drivers/net/rtl8169.c diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index c99fcc8316..24b984462d 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -156,6 +156,14 @@ config DRIVER_NET_RTL8139 This is a driver for the Fast Ethernet PCI network cards based on the RTL 8139 chips. +config DRIVER_NET_RTL8169 + bool "RealTek RTL-8169 PCI Ethernet driver" + depends on PCI + select PHYLIB + help + This is a driver for the Fast Ethernet PCI network cards based on + the RTL 8169 chips. + config DRIVER_NET_SMC911X bool "smc911x ethernet driver" select PHYLIB diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 1b85778f9f..3e66b3135c 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_DRIVER_NET_MPC5200) += fec_mpc5200.o obj-$(CONFIG_DRIVER_NET_NETX) += netx_eth.o obj-$(CONFIG_DRIVER_NET_ORION) += orion-gbe.o obj-$(CONFIG_DRIVER_NET_RTL8139) += rtl8139.o +obj-$(CONFIG_DRIVER_NET_RTL8169) += rtl8169.o obj-$(CONFIG_DRIVER_NET_SMC911X) += smc911x.o obj-$(CONFIG_DRIVER_NET_SMC91111) += smc91111.o obj-$(CONFIG_DRIVER_NET_TAP) += tap.o diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c new file mode 100644 index 0000000000..3ed2e562a4 --- /dev/null +++ b/drivers/net/rtl8169.c @@ -0,0 +1,566 @@ +/* + * Copyright (C) 2014 Lucas Stach + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#define NUM_TX_DESC 1 +#define NUM_RX_DESC 4 +#define PKT_BUF_SIZE 1536 +#define ETH_ZLEN 60 + +struct rtl8169_chip_info { + const char *name; + u8 version; + u32 RxConfigMask; +}; + +#define BD_STAT_OWN 0x80000000 +#define BD_STAT_EOR 0x40000000 +#define BD_STAT_FS 0x20000000 +#define BD_STAT_LS 0x10000000 +#define BD_STAT_RX_RES 0x00200000 +struct bufdesc { + u32 status; + u32 vlan_tag; + u32 buf_addr; + u32 buf_Haddr; +}; + +struct rtl8169_priv { + struct eth_device edev; + void __iomem *base; + struct pci_dev *pci_dev; + int chipset; + + struct bufdesc *tx_desc; + void *tx_buf; + unsigned int cur_tx; + + struct bufdesc *rx_desc; + void *rx_buf; + unsigned int cur_rx; + + struct mii_bus miibus; +}; + +#define MAC0 0x00 +#define MAR0 0x08 +#define TxDescStartAddrLow 0x20 +#define TxDescStartAddrHigh 0x24 +#define TxHDescStartAddrLow 0x28 +#define TxHDescStartAddrHigh 0x2c +#define FLASH 0x30 +#define ERSR 0x36 +#define ChipCmd 0x37 +#define CmdReset 0x10 +#define CmdRxEnb 0x08 +#define CmdTxEnb 0x04 +#define RxBufEmpty 0x01 +#define TxPoll 0x38 +#define IntrMask 0x3c +#define IntrStatus 0x3e +#define SYSErr 0x8000 +#define PCSTimeout 0x4000 +#define SWInt 0x0100 +#define TxDescUnavail 0x80 +#define RxFIFOOver 0x40 +#define RxUnderrun 0x20 +#define RxOverflow 0x10 +#define TxErr 0x08 +#define TxOK 0x04 +#define RxErr 0x02 +#define RxOK 0x01 +#define TxConfig 0x40 +#define TxInterFrameGapShift 24 +#define TxDMAShift 8 +#define RxConfig 0x44 +#define AcceptErr 0x20 +#define AcceptRunt 0x10 +#define AcceptBroadcast 0x08 +#define AcceptMulticast 0x04 +#define AcceptMyPhys 0x02 +#define AcceptAllPhys 0x01 +#define RxCfgFIFOShift 13 +#define RxCfgDMAShift 8 +#define RxMissed 0x4c +#define Cfg9346 0x50 +#define Cfg9346_Lock 0x00 +#define Cfg9346_Unlock 0xc0 +#define Config0 0x51 +#define Config1 0x52 +#define Config2 0x53 +#define Config3 0x54 +#define Config4 0x55 +#define Config5 0x56 +#define MultiIntr 0x5c +#define PHYAR 0x60 +#define TBICSR 0x64 +#define TBI_ANAR 0x68 +#define TBI_LPAR 0x6a +#define PHYstatus 0x6c +#define RxMaxSize 0xda +#define CPlusCmd 0xe0 +#define RxDescStartAddrLow 0xe4 +#define RxDescStartAddrHigh 0xe8 +#define EarlyTxThres 0xec +#define FuncEvent 0xf0 +#define FuncEventMask 0xf4 +#define FuncPresetState 0xf8 +#define FuncForceEvent 0xfc + +/* write MMIO register */ +#define RTL_W8(priv, reg, val) writeb(val, ((char *)(priv->base) + reg)) +#define RTL_W16(priv, reg, val) writew(val, ((char *)(priv->base) + reg)) +#define RTL_W32(priv, reg, val) writel(val, ((char *)(priv->base) + reg)) + +/* read MMIO register */ +#define RTL_R8(priv, reg) readb(((char *)(priv->base) + reg)) +#define RTL_R16(priv, reg) readw(((char *)(priv->base) + reg)) +#define RTL_R32(priv, reg) readl(((char *)(priv->base) + reg)) + +static const u32 rtl8169_rx_config = + (7 << RxCfgFIFOShift) | (6 << RxCfgDMAShift); + +static void rtl8169_chip_reset(struct rtl8169_priv *priv) +{ + int i; + + /* Soft reset the chip. */ + RTL_W8(priv, ChipCmd, CmdReset); + + /* Check that the chip has finished the reset. */ + for (i = 1000; i > 0; i--) { + if ((RTL_R8(priv, ChipCmd) & CmdReset) == 0) + break; + udelay(10); + } +} + +static struct rtl8169_chip_info chip_info[] = { + {"RTL-8169", 0x00, 0xff7e1880}, + {"RTL-8169", 0x04, 0xff7e1880}, + {"RTL-8169", 0x00, 0xff7e1880}, + {"RTL-8169s/8110s", 0x02, 0xff7e1880}, + {"RTL-8169s/8110s", 0x04, 0xff7e1880}, + {"RTL-8169sb/8110sb", 0x10, 0xff7e1880}, + {"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}, +}; + +static void rtl8169_chip_identify(struct rtl8169_priv *priv) +{ + u32 val; + int i; + + val = RTL_R32(priv, TxConfig); + val = ((val & 0x7c000000) + ((val & 0x00800000) << 2)) >> 24; + + for (i = ARRAY_SIZE(chip_info) - 1; i >= 0; i--){ + if (val == chip_info[i].version) { + priv->chipset = i; + dev_dbg(&priv->pci_dev->dev, "found %s chipset\n", + chip_info[i].name); + return; + } + } + + dev_dbg(&priv->pci_dev->dev, + "no matching chip version found, assuming RTL-8169\n"); + priv->chipset = 0; +} + +static int rtl8169_init_dev(struct eth_device *edev) +{ + struct rtl8169_priv *priv = edev->priv; + + rtl8169_chip_reset(priv); + rtl8169_chip_identify(priv); + pci_set_master(priv->pci_dev); + + return 0; +} + +static void __set_rx_mode(struct rtl8169_priv *priv) +{ + u32 mc_filter[2], val; + + /* IFF_ALLMULTI */ + /* Too many to filter perfectly -- accept all multicasts. */ + mc_filter[1] = mc_filter[0] = 0xffffffff; + + val = AcceptBroadcast | AcceptMulticast | AcceptMyPhys | + rtl8169_rx_config | (RTL_R32(priv, RxConfig) & + chip_info[priv->chipset].RxConfigMask); + + RTL_W32(priv, RxConfig, val); + RTL_W32(priv, MAR0 + 0, mc_filter[0]); + RTL_W32(priv, MAR0 + 4, mc_filter[1]); +} + +static void rtl8169_init_ring(struct rtl8169_priv *priv) +{ + int i; + + priv->cur_rx = priv->cur_tx = 0; + + priv->tx_desc = dma_alloc_coherent(NUM_TX_DESC * + sizeof(struct bufdesc)); + priv->tx_buf = malloc(NUM_TX_DESC * PKT_BUF_SIZE); + priv->rx_desc = dma_alloc_coherent(NUM_RX_DESC * + sizeof(struct bufdesc)); + priv->rx_buf = malloc(NUM_RX_DESC * PKT_BUF_SIZE); + + memset(priv->tx_desc, 0, NUM_TX_DESC * sizeof(struct bufdesc)); + memset(priv->rx_desc, 0, NUM_RX_DESC * sizeof(struct bufdesc)); + + for (i = 0; i < NUM_RX_DESC; i++) { + if (i == (NUM_RX_DESC - 1)) + priv->rx_desc[i].status = + BD_STAT_OWN | BD_STAT_EOR | PKT_BUF_SIZE; + else + priv->rx_desc[i].status = + BD_STAT_OWN | PKT_BUF_SIZE; + + priv->rx_desc[i].buf_addr = + virt_to_phys(priv->rx_buf + i * PKT_BUF_SIZE); + } + + dma_flush_range((unsigned long)priv->rx_desc, + (unsigned long)priv->rx_desc + + NUM_RX_DESC * sizeof(struct bufdesc)); +} + +static void rtl8169_hw_start(struct rtl8169_priv *priv) +{ + u32 val; + + RTL_W8(priv, Cfg9346, Cfg9346_Unlock); + + /* RTL-8169sb/8110sb or previous version */ + if (priv->chipset <= 5) + RTL_W8(priv, ChipCmd, CmdTxEnb | CmdRxEnb); + + RTL_W8(priv, EarlyTxThres, 0x3f); + + /* For gigabit rtl8169 */ + RTL_W16(priv, RxMaxSize, 0x800); + + /* Set Rx Config register */ + val = rtl8169_rx_config | (RTL_R32(priv, RxConfig) & + chip_info[priv->chipset].RxConfigMask); + RTL_W32(priv, RxConfig, val); + + /* Set DMA burst size and Interframe Gap Time */ + RTL_W32(priv, TxConfig, (6 << TxDMAShift) | (3 << TxInterFrameGapShift)); + + RTL_W32(priv, TxDescStartAddrLow, virt_to_phys(priv->tx_desc)); + RTL_W32(priv, TxDescStartAddrHigh, 0); + RTL_W32(priv, RxDescStartAddrLow, virt_to_phys(priv->rx_desc)); + RTL_W32(priv, RxDescStartAddrHigh, 0); + + /* RTL-8169sc/8110sc or later version */ + if (priv->chipset > 5) + RTL_W8(priv, ChipCmd, CmdTxEnb | CmdRxEnb); + + RTL_W8(priv, Cfg9346, Cfg9346_Lock); + udelay(10); + + RTL_W32(priv, RxMissed, 0); + + __set_rx_mode(priv); + + /* no early-rx interrupts */ + RTL_W16(priv, MultiIntr, RTL_R16(priv, MultiIntr) & 0xf000); +} + +static int rtl8169_eth_open(struct eth_device *edev) +{ + struct rtl8169_priv *priv = edev->priv; + int ret; + + rtl8169_init_ring(priv); + rtl8169_hw_start(priv); + + ret = phy_device_connect(edev, &priv->miibus, 0, NULL, 0, + PHY_INTERFACE_MODE_NA); + + return ret; +} + +static int rtl8169_phy_write(struct mii_bus *bus, int phy_addr, + int reg, u16 val) +{ + struct rtl8169_priv *priv = bus->priv; + int i; + + if (phy_addr != 0) + return -1; + + RTL_W32(priv, PHYAR, 0x80000000 | (reg & 0xff) << 16 | val); + mdelay(1); + + for (i = 2000; i > 0; i--) { + if (!(RTL_R32(priv, PHYAR) & 0x80000000)) { + return 0; + } else { + udelay(100); + } + } + + return -1; +} + +static int rtl8169_phy_read(struct mii_bus *bus, int phy_addr, int reg) +{ + struct rtl8169_priv *priv = bus->priv; + int i, val = 0xffff; + + RTL_W32(priv, PHYAR, 0x0 | (reg & 0xff) << 16); + mdelay(10); + + if (phy_addr != 0) + return val; + + for (i = 2000; i > 0; i--) { + if (RTL_R32(priv, PHYAR) & 0x80000000) { + val = (int) (RTL_R32(priv, PHYAR) & 0xffff); + break; + } else { + udelay(100); + } + } + return val; +} + +static int rtl8169_eth_send(struct eth_device *edev, void *packet, + int packet_length) +{ + struct rtl8169_priv *priv = edev->priv; + unsigned int entry; + + entry = priv->cur_tx % NUM_TX_DESC; + + if (packet_length < ETH_ZLEN) + memset(priv->tx_buf + entry * PKT_BUF_SIZE, 0, ETH_ZLEN); + memcpy(priv->tx_buf + entry * PKT_BUF_SIZE, packet, packet_length); + dma_flush_range((unsigned long)priv->tx_buf + entry * PKT_BUF_SIZE, + (unsigned long)priv->tx_buf + (entry + 1) * PKT_BUF_SIZE); + + priv->tx_desc[entry].buf_Haddr = 0; + priv->tx_desc[entry].buf_addr = + virt_to_phys(priv->tx_buf + entry * PKT_BUF_SIZE); + + if (entry != (NUM_TX_DESC - 1)) { + priv->tx_desc[entry].status = + BD_STAT_OWN | BD_STAT_FS | BD_STAT_LS | + ((packet_length > ETH_ZLEN) ? packet_length : ETH_ZLEN); + } else { + priv->tx_desc[entry].status = + BD_STAT_OWN | BD_STAT_EOR | BD_STAT_FS | BD_STAT_LS | + ((packet_length > ETH_ZLEN) ? packet_length : ETH_ZLEN); + } + + dma_flush_range((unsigned long)&priv->tx_desc[entry], + (unsigned long)&priv->tx_desc[entry + 1]); + + RTL_W8(priv, TxPoll, 0x40); + do { + dma_inv_range((unsigned long)&priv->tx_desc[entry], + (unsigned long)&priv->tx_desc[entry + 1]); + } while (priv->tx_desc[entry].status & BD_STAT_OWN); + + priv->cur_tx++; + + return 0; +} + +static int rtl8169_eth_rx(struct eth_device *edev) +{ + struct rtl8169_priv *priv = edev->priv; + unsigned int entry, pkt_size = 0; + u8 status; + + entry = priv->cur_rx % NUM_RX_DESC; + + dma_inv_range((unsigned long)&priv->rx_desc[entry], + (unsigned long)&priv->rx_desc[entry + 1]); + + if ((priv->rx_desc[entry].status & BD_STAT_OWN) == 0) { + if (!(priv->rx_desc[entry].status & BD_STAT_RX_RES)) { + pkt_size = (priv->rx_desc[entry].status & 0x1fff) - 4; + + dma_inv_range((unsigned long)priv->rx_buf + + entry * PKT_BUF_SIZE, + (unsigned long)priv->rx_buf + + entry * PKT_BUF_SIZE + pkt_size); + + net_receive(edev, priv->rx_buf + entry * PKT_BUF_SIZE, + pkt_size); + + if (entry == NUM_RX_DESC - 1) + priv->rx_desc[entry].status = BD_STAT_OWN | + BD_STAT_EOR | PKT_BUF_SIZE; + else + priv->rx_desc[entry].status = + BD_STAT_OWN | PKT_BUF_SIZE; + priv->rx_desc[entry].buf_addr = + virt_to_phys(priv->rx_buf + + entry * PKT_BUF_SIZE); + + dma_flush_range((unsigned long)&priv->rx_desc[entry], + (unsigned long)&priv->rx_desc[entry + 1]); + } else { + dev_err(&edev->dev, "rx error\n"); + } + + priv->cur_rx++; + + return pkt_size; + + } else { + status = RTL_R8(priv, IntrStatus); + RTL_W8(priv, IntrStatus, status & ~(TxErr | RxErr | SYSErr)); + udelay(100); /* wait */ + } + + return 0; +} + +static int rtl8169_get_ethaddr(struct eth_device *edev, unsigned char *m) +{ + struct rtl8169_priv *priv = edev->priv; + int i; + + for (i = 0; i < 6; i++) { + m[i] = RTL_R8(priv, MAC0 + i); + } + + return 0; +} + +static int rtl8169_set_ethaddr(struct eth_device *edev, unsigned char *mac_addr) +{ + struct rtl8169_priv *priv = edev->priv; + int i; + + RTL_W8(priv, Cfg9346, Cfg9346_Unlock); + + for (i = 0; i < 6; i++) { + RTL_W8(priv, (MAC0 + i), mac_addr[i]); + RTL_R8(priv, mac_addr[i]); + } + + RTL_W8(priv, Cfg9346, Cfg9346_Lock); + + return 0; +} + +static void rtl8169_eth_halt(struct eth_device *edev) +{ + struct rtl8169_priv *priv = edev->priv; + + /* Stop the chip's Tx and Rx DMA processes. */ + RTL_W8(priv, ChipCmd, 0x00); + + /* Disable interrupts by clearing the interrupt mask. */ + RTL_W16(priv, IntrMask, 0x0000); + RTL_W32(priv, RxMissed, 0); + + pci_clear_master(priv->pci_dev); +} + +static int rtl8169_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct device_d *dev = &pdev->dev; + struct eth_device *edev; + struct rtl8169_priv *priv; + int ret; + + /* enable pci device */ + pci_enable_device(pdev); + + priv = xzalloc(sizeof(struct rtl8169_priv)); + + edev = &priv->edev; + dev->type_data = edev; + edev->priv = priv; + + priv->pci_dev = pdev; + + priv->miibus.read = rtl8169_phy_read; + priv->miibus.write = rtl8169_phy_write; + priv->miibus.priv = priv; + priv->miibus.parent = &edev->dev; + + priv->base = pci_iomap(pdev, pdev->device == 0x8168 ? 2 : 1); + + dev_dbg(dev, "rtl%04x (rev %02x) (base=%p)\n", + pdev->device, pdev->revision, priv->base); + + edev->init = rtl8169_init_dev; + edev->open = rtl8169_eth_open; + edev->send = rtl8169_eth_send; + edev->recv = rtl8169_eth_rx; + edev->get_ethaddr = rtl8169_get_ethaddr; + edev->set_ethaddr = rtl8169_set_ethaddr; + edev->halt = rtl8169_eth_halt; + edev->parent = dev; + ret = eth_register(edev); + if (ret) + goto eth_err; + + ret = mdiobus_register(&priv->miibus); + if (ret) + goto mdio_err; + + return 0; + +mdio_err: + eth_unregister(edev); + +eth_err: + free(priv); + + return ret; +} +static DEFINE_PCI_DEVICE_TABLE(rtl8169_pci_tbl) = { + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), }, + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), }, + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), }, + { /* sentinel */ } +}; + +static struct pci_driver rtl8169_eth_driver = { + .name = "rtl8169_eth", + .id_table = rtl8169_pci_tbl, + .probe = rtl8169_probe, +}; + +static int rtl8169_init(void) +{ + return pci_register_driver(&rtl8169_eth_driver); +} +device_initcall(rtl8169_init); -- cgit v1.2.3 From cdd73aa2f70bfc7443a9279617301ff4e325bfe9 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sat, 4 Oct 2014 19:40:25 +0200 Subject: ARM: tegra: enable network related options in defconfig Now that we have working network support on the Beaver board it makes sense to enable some network options. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/configs/tegra_v7_defconfig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/configs/tegra_v7_defconfig b/arch/arm/configs/tegra_v7_defconfig index 8f01b549df..ead69edff1 100644 --- a/arch/arm/configs/tegra_v7_defconfig +++ b/arch/arm/configs/tegra_v7_defconfig @@ -27,17 +27,24 @@ CONFIG_CMD_RESET=y CONFIG_CMD_EXPORT=y CONFIG_CMD_LOADENV=y CONFIG_CMD_SAVEENV=y +CONFIG_CMD_DHCP=y +CONFIG_CMD_MIITOOL=y +CONFIG_CMD_PING=y CONFIG_CMD_EDIT=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_CLK=y CONFIG_CMD_DETECT=y CONFIG_CMD_GPIO=y CONFIG_CMD_OFTREE=y +CONFIG_NET=y CONFIG_DRIVER_SERIAL_NS16550=y +CONFIG_DRIVER_NET_RTL8169=y CONFIG_MCI=y CONFIG_MCI_MMC_BOOT_PARTITIONS=y CONFIG_MCI_TEGRA=y CONFIG_PCI_TEGRA=y CONFIG_FS_EXT4=y +CONFIG_FS_TFTP=y +CONFIG_FS_NFS=y CONFIG_FS_FAT=y CONFIG_FS_FAT_LFN=y -- cgit v1.2.3 From fd378e779b790c739675ffad8a43da54081c6956 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sun, 2 Nov 2014 21:13:43 +0100 Subject: net: rtl8169: add support for RTL-8168/8111g This is the version of the chip found on Jetson-TK1. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/net/rtl8169.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index 3ed2e562a4..0cd576315b 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -166,6 +166,7 @@ static struct rtl8169_chip_info chip_info[] = { {"RTL-8168b/8111sb", 0x38, 0xff7e1880}, {"RTL-8168d/8111d", 0x28, 0xff7e1880}, {"RTL-8168evl/8111evl", 0x2e, 0xff7e1880}, + {"RTL-8168/8111g", 0x4c, 0xff7e1880,}, {"RTL-8101e", 0x34, 0xff7e1880}, {"RTL-8100e", 0x32, 0xff7e1880}, }; -- cgit v1.2.3 From 7d60a02034bb8816c74d2bbddc0d0981024bed66 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sun, 2 Nov 2014 21:13:44 +0100 Subject: net: rtl8169: clean receive buffer after net handler The processing of the buffer might change some data, which will eventually trigger a cache writeback later on, corrupting data written by the network chip. Clean the cache range to make sure there is no writeback pending. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/net/rtl8169.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index 0cd576315b..5702900e49 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -233,6 +233,8 @@ static void rtl8169_init_ring(struct rtl8169_priv *priv) priv->rx_desc = dma_alloc_coherent(NUM_RX_DESC * sizeof(struct bufdesc)); priv->rx_buf = malloc(NUM_RX_DESC * PKT_BUF_SIZE); + dma_clean_range((unsigned long)priv->rx_buf, + (unsigned long)priv->rx_buf + NUM_RX_DESC * PKT_BUF_SIZE); memset(priv->tx_desc, 0, NUM_TX_DESC * sizeof(struct bufdesc)); memset(priv->rx_desc, 0, NUM_RX_DESC * sizeof(struct bufdesc)); @@ -421,6 +423,15 @@ static int rtl8169_eth_rx(struct eth_device *edev) net_receive(edev, priv->rx_buf + entry * PKT_BUF_SIZE, pkt_size); + /* + * the buffer is going to be reused by HW, make sure to + * clean out any potentially modified data + */ + dma_clean_range((unsigned long)priv->rx_buf + + entry * PKT_BUF_SIZE, + (unsigned long)priv->rx_buf + + entry * PKT_BUF_SIZE + pkt_size); + if (entry == NUM_RX_DESC - 1) priv->rx_desc[entry].status = BD_STAT_OWN | BD_STAT_EOR | PKT_BUF_SIZE; -- cgit v1.2.3 From 7cf0a3ea2bb07bd02dfe22a81d34c8614e72f52c Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sun, 2 Nov 2014 21:13:49 +0100 Subject: tegra: pmc: work around power domain failure Sometimes a power domain didn't properly power up, reading back the command register seems to fix this by flushing the write. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/mach-tegra/tegra20-pmc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-tegra/tegra20-pmc.c b/arch/arm/mach-tegra/tegra20-pmc.c index 4cd01ffc29..dcd2978109 100644 --- a/arch/arm/mach-tegra/tegra20-pmc.c +++ b/arch/arm/mach-tegra/tegra20-pmc.c @@ -53,6 +53,8 @@ static int tegra_powergate_set(int id, bool new_state) } writel(PMC_PWRGATE_TOGGLE_START | id, pmc_base + PMC_PWRGATE_TOGGLE); + /* I don't know exactly why this is needed, seems to flush the write */ + readl(pmc_base + PMC_PWRGATE_TOGGLE); return 0; } -- cgit v1.2.3 From a546e66838ff4c62b91ec401256bfae15d02c53e Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sun, 2 Nov 2014 21:13:50 +0100 Subject: tegra: jetson-tk1: enable 1.05V_RUN Needed for the PCIe PLL amongst other things. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/boards/nvidia-jetson-tk1/Makefile | 2 +- arch/arm/boards/nvidia-jetson-tk1/board.c | 50 ++++++++++++++++++++++++++++++ arch/arm/mach-tegra/Kconfig | 2 ++ 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boards/nvidia-jetson-tk1/board.c diff --git a/arch/arm/boards/nvidia-jetson-tk1/Makefile b/arch/arm/boards/nvidia-jetson-tk1/Makefile index f1e46206f8..16b203f9f3 100644 --- a/arch/arm/boards/nvidia-jetson-tk1/Makefile +++ b/arch/arm/boards/nvidia-jetson-tk1/Makefile @@ -3,5 +3,5 @@ CFLAGS_pbl-entry.o := \ -fno-tree-switch-conversion -fno-jump-tables soc := tegra124 lwl-y += entry.o -#obj-y += board.o +obj-y += board.o extra-y += jetson-tk1-2gb-emmc.bct diff --git a/arch/arm/boards/nvidia-jetson-tk1/board.c b/arch/arm/boards/nvidia-jetson-tk1/board.c new file mode 100644 index 0000000000..c20f56a3bb --- /dev/null +++ b/arch/arm/boards/nvidia-jetson-tk1/board.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014 Lucas Stach + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#define AS3722_SD_VOLTAGE(n) (0x00 + (n)) +#define AS3722_GPIO_CONTROL(n) (0x08 + (n)) +#define AS3722_GPIO_CONTROL_MODE_OUTPUT_VDDH (1 << 0) +#define AS3722_GPIO_SIGNAL_OUT 0x20 +#define AS3722_SD_CONTROL 0x4d + +static int nvidia_jetson_tk1_devices_init(void) +{ + struct i2c_client client; + u8 data; + + if (!of_machine_is_compatible("nvidia,jetson-tk1")) + return 0; + + client.adapter = i2c_get_adapter(4); + client.addr = 0x40; + + /* AS3722: enable SD4 and set voltage to 1.05v */ + i2c_read_reg(&client, AS3722_SD_CONTROL, &data, 1); + data |= 1 << 4; + i2c_write_reg(&client, AS3722_SD_CONTROL, &data, 1); + + data = 0x24; + i2c_write_reg(&client, AS3722_SD_VOLTAGE(4), &data, 1); + + return 0; +} +fs_initcall(nvidia_jetson_tk1_devices_init); diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 2c69406dfc..1bdea8e6a9 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -70,6 +70,8 @@ config MACH_NVIDIA_BEAVER config MACH_NVIDIA_JETSON bool "NVIDIA Jetson TK1" select ARCH_TEGRA_124_SOC + select I2C + select I2C_TEGRA endmenu -- cgit v1.2.3 From e2ac763d0f89d33620d369aa2a210541979d06c5 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sun, 2 Nov 2014 21:13:51 +0100 Subject: clk: tegra124: add PLLE setup functions This adds functions to bring up the new style Tegra114+ PLL_E. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/clk/tegra/clk-pll.c | 173 +++++++++++++++++++++++++++++++++++++++++++- drivers/clk/tegra/clk.h | 7 ++ 2 files changed, 177 insertions(+), 3 deletions(-) diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index bff5651802..e677effba2 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -63,6 +63,7 @@ #define PLLDU_LFCON_SET_DIVN 600 #define PLLE_BASE_DIVCML_SHIFT 24 +#define PLLE_BASE_DIVCML_MASK 0xf #define PLLE_BASE_DIVCML_WIDTH 4 #define PLLE_BASE_DIVP_SHIFT 16 #define PLLE_BASE_DIVP_WIDTH 7 @@ -81,8 +82,45 @@ PLLE_MISC_SETUP_EX_MASK) #define PLLE_MISC_SETUP_VALUE (7 << PLLE_MISC_SETUP_BASE_SHIFT) -#define PLLE_SS_CTRL 0x68 -#define PLLE_SS_DISABLE (7 << 10) +#define XUSBIO_PLL_CFG0 0x51c +#define XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL (1 << 0) +#define XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL (1 << 2) +#define XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET (1 << 6) +#define XUSBIO_PLL_CFG0_SEQ_ENABLE (1 << 24) +#define XUSBIO_PLL_CFG0_SEQ_START_STATE (1 << 25) + +#define PLLE_SS_CTRL 0x68 +#define PLLE_SS_CNTL_BYPASS_SS (7 << 10) +#define PLLE_SS_CNTL_INTERP_RESET (1 << 11) +#define PLLE_SS_CNTL_SSC_BYP (1 << 12) +#define PLLE_SS_CNTL_CENTER (1 << 14) +#define PLLE_SS_CNTL_INVERT (1 << 15) +#define PLLE_SS_MAX_MASK 0x1ff +#define PLLE_SS_MAX_VAL 0x25 +#define PLLE_SS_INC_MASK (0xff << 16) +#define PLLE_SS_INC_VAL (0x1 << 16) +#define PLLE_SS_INCINTRV_MASK (0x3f << 24) +#define PLLE_SS_INCINTRV_VAL (0x20 << 24) +#define PLLE_SS_COEFFICIENTS_MASK \ + (PLLE_SS_MAX_MASK | PLLE_SS_INC_MASK | PLLE_SS_INCINTRV_MASK) +#define PLLE_SS_COEFFICIENTS_VAL \ + (PLLE_SS_MAX_VAL | PLLE_SS_INC_VAL | PLLE_SS_INCINTRV_VAL) + +#define PLLE_MISC_VREG_CTRL_SHIFT 2 +#define PLLE_MISC_VREG_CTRL_MASK (2 << PLLE_MISC_VREG_CTRL_SHIFT) +#define PLLE_MISC_VREG_BG_CTRL_SHIFT 4 +#define PLLE_MISC_VREG_BG_CTRL_MASK (3 << PLLE_MISC_VREG_BG_CTRL_SHIFT) +#define PLLE_MISC_PLLE_PTS (1 << 8) +#define PLLE_MISC_IDDQ_SW_VALUE (1 << 13) +#define PLLE_MISC_IDDQ_SW_CTRL (1 << 14) + +#define PLLE_AUX_PLLP_SEL (1 << 2) +#define PLLE_AUX_USE_LOCKDET (1 << 3) +#define PLLE_AUX_ENABLE_SWCTL (1 << 4) +#define PLLE_AUX_SS_SWCTL (1 << 6) +#define PLLE_AUX_SEQ_ENABLE (1 << 24) +#define PLLE_AUX_SEQ_START_STATE (1 << 25) +#define PLLE_AUX_PLLRE_SEL (1 << 28) #define PMC_SATA_PWRGT 0x1ac #define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE BIT(5) @@ -102,10 +140,19 @@ #define divp_mask(p) (p->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK : \ mask(p->divp_width)) +#define divm_shift(p) (p)->divm_shift +#define divn_shift(p) (p)->divn_shift +#define divp_shift(p) (p)->divp_shift + +#define divm_mask_shifted(p) (divm_mask(p) << divm_shift(p)) +#define divn_mask_shifted(p) (divn_mask(p) << divn_shift(p)) +#define divp_mask_shifted(p) (divp_mask(p) << divp_shift(p)) + #define divm_max(p) (divm_mask(p)) #define divn_max(p) (divn_mask(p)) #define divp_max(p) (1 << (divp_mask(p))) + #define to_clk_pll(_hw) container_of(_hw, struct tegra_clk_pll, hw) static int clk_pll_is_enabled(struct clk *hw) @@ -478,7 +525,7 @@ static int clk_plle_enable(struct clk *hw) pll_writel_misc(val, pll); val = readl(pll->clk_base + PLLE_SS_CTRL); - val |= PLLE_SS_DISABLE; + val |= PLLE_SS_CNTL_BYPASS_SS; writel(val, pll->clk_base + PLLE_SS_CTRL); val = pll_readl_base(pll); @@ -498,6 +545,115 @@ const struct clk_ops tegra_clk_plle_ops = { .enable = clk_plle_enable, }; +static int clk_plle_tegra114_enable(struct clk *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long input_rate = clk_get_rate(clk_get_parent(hw)); + struct tegra_clk_pll_freq_table sel; + u32 val; + int ret; + + if (_get_table_rate(hw, &sel, pll->fixed_rate, input_rate)) + return -EINVAL; + + val = pll_readl_base(pll); + val &= ~BIT(29); /* Disable lock override */ + pll_writel_base(val, pll); + + val = pll_readl(pll->params->aux_reg, pll); + val |= PLLE_AUX_ENABLE_SWCTL; + val &= ~PLLE_AUX_SEQ_ENABLE; + pll_writel(val, pll->params->aux_reg, pll); + udelay(1); + + val = pll_readl_misc(pll); + val |= PLLE_MISC_LOCK_ENABLE; + val |= PLLE_MISC_IDDQ_SW_CTRL; + val &= ~PLLE_MISC_IDDQ_SW_VALUE; + val |= PLLE_MISC_PLLE_PTS; + val |= PLLE_MISC_VREG_BG_CTRL_MASK | PLLE_MISC_VREG_CTRL_MASK; + pll_writel_misc(val, pll); + udelay(5); + + val = pll_readl(PLLE_SS_CTRL, pll); + val |= PLLE_SS_CNTL_BYPASS_SS; + pll_writel(val, PLLE_SS_CTRL, pll); + + val = pll_readl_base(pll); + val &= ~(divp_mask_shifted(pll) | divn_mask_shifted(pll) | + divm_mask_shifted(pll)); + val &= ~(PLLE_BASE_DIVCML_MASK << PLLE_BASE_DIVCML_SHIFT); + val |= sel.m << divm_shift(pll); + val |= sel.n << divn_shift(pll); + val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT; + pll_writel_base(val, pll); + udelay(1); + + clk_pll_enable(hw); + ret = clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->misc_reg, + pll->params->lock_bit_idx); + + if (ret < 0) + return ret; + + val = pll_readl(PLLE_SS_CTRL, pll); + val &= ~(PLLE_SS_CNTL_CENTER | PLLE_SS_CNTL_INVERT); + val &= ~PLLE_SS_COEFFICIENTS_MASK; + val |= PLLE_SS_COEFFICIENTS_VAL; + pll_writel(val, PLLE_SS_CTRL, pll); + val &= ~(PLLE_SS_CNTL_SSC_BYP | PLLE_SS_CNTL_BYPASS_SS); + pll_writel(val, PLLE_SS_CTRL, pll); + udelay(1); + val &= ~PLLE_SS_CNTL_INTERP_RESET; + pll_writel(val, PLLE_SS_CTRL, pll); + udelay(1); + + /* Enable hw control of xusb brick pll */ + val = pll_readl_misc(pll); + val &= ~PLLE_MISC_IDDQ_SW_CTRL; + pll_writel_misc(val, pll); + + val = pll_readl(pll->params->aux_reg, pll); + val |= (PLLE_AUX_USE_LOCKDET | PLLE_AUX_SEQ_START_STATE); + val &= ~(PLLE_AUX_ENABLE_SWCTL | PLLE_AUX_SS_SWCTL); + pll_writel(val, pll->params->aux_reg, pll); + udelay(1); + val |= PLLE_AUX_SEQ_ENABLE; + pll_writel(val, pll->params->aux_reg, pll); + + val = pll_readl(XUSBIO_PLL_CFG0, pll); + val |= (XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET | + XUSBIO_PLL_CFG0_SEQ_START_STATE); + val &= ~(XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL | + XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL); + pll_writel(val, XUSBIO_PLL_CFG0, pll); + udelay(1); + val |= XUSBIO_PLL_CFG0_SEQ_ENABLE; + pll_writel(val, XUSBIO_PLL_CFG0, pll); + + return ret; +} + +static void clk_plle_tegra114_disable(struct clk *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + u32 val; + + clk_pll_disable(hw); + + val = pll_readl_misc(pll); + val |= PLLE_MISC_IDDQ_SW_CTRL | PLLE_MISC_IDDQ_SW_VALUE; + pll_writel_misc(val, pll); + udelay(1); +} + +const struct clk_ops tegra_clk_plle_tegra114_ops = { + .recalc_rate = clk_pll_recalc_rate, + .is_enabled = clk_pll_is_enabled, + .disable = clk_plle_tegra114_disable, + .enable = clk_plle_tegra114_enable, +}; + static struct clk *_tegra_clk_register_pll(const char *name, const char *parent_name, void __iomem *clk_base, unsigned long flags, unsigned long fixed_rate, @@ -563,3 +719,14 @@ struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, flags, fixed_rate, pll_params, pll_flags, freq_table, &tegra_clk_plle_ops); } + +struct clk *tegra_clk_register_plle_tegra114(const char *name, + const char *parent_name, void __iomem *clk_base, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, u8 pll_flags, + struct tegra_clk_pll_freq_table *freq_table) +{ + return _tegra_clk_register_pll(name, parent_name, clk_base, + flags, fixed_rate, pll_params, pll_flags, freq_table, + &tegra_clk_plle_tegra114_ops); +} diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 85777a8898..10d03573fd 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -63,6 +63,7 @@ struct tegra_clk_pll_params { u32 base_reg; u32 misc_reg; + u32 aux_reg; u32 lock_reg; u8 lock_bit_idx; u8 lock_enable_bit_idx; @@ -107,6 +108,12 @@ struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, struct tegra_clk_pll_params *pll_params, u8 pll_flags, struct tegra_clk_pll_freq_table *freq_table); +struct clk *tegra_clk_register_plle_tegra114(const char *name, + const char *parent_name, void __iomem *clk_base, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, u8 pll_flags, + struct tegra_clk_pll_freq_table *freq_table); + /* struct tegra_clk_pll_out - PLL output divider */ struct tegra_clk_pll_out { struct clk hw; -- cgit v1.2.3 From e000cbeb7a8340f6fe3204db4555790697815ce8 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sun, 2 Nov 2014 21:13:52 +0100 Subject: clk: tegra124: add PCIe clocks Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/clk/tegra/clk-tegra124.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index 514b22a784..7426b52aac 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -62,6 +62,15 @@ static struct tegra_clk_pll_freq_table pll_c_freq_table[] = { { 0, 0, 0, 0, 0, 0 }, }; +static struct tegra_clk_pll_freq_table pll_e_freq_table[] = { + /* PLLE special case: use cpcon field to store cml divider value */ + {336000000, 100000000, 100, 21, 16, 11}, + {312000000, 100000000, 200, 26, 24, 13}, + {13000000, 100000000, 200, 1, 26, 13}, + {12000000, 100000000, 200, 1, 24, 13}, + {0, 0, 0, 0, 0, 0}, +}; + static struct tegra_clk_pll_freq_table pll_p_freq_table[] = { {12000000, 408000000, 408, 12, 0, 8}, {13000000, 408000000, 408, 13, 0, 8}, @@ -114,6 +123,21 @@ static struct tegra_clk_pll_params pll_c_params = { .lock_delay = 300, }; +static struct tegra_clk_pll_params pll_e_params = { + .input_min = 12000000, + .input_max = 1000000000, + .cf_min = 12000000, + .cf_max = 75000000, + .vco_min = 1600000000, + .vco_max = 2400000000U, + .base_reg = CRC_PLLE_BASE, + .misc_reg = CRC_PLLE_MISC, + .aux_reg = CRC_PLLE_AUX, + .lock_bit_idx = CRC_PLLE_MISC_LOCK, + .lock_enable_bit_idx = CRC_PLLE_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + static struct tegra_clk_pll_params pll_p_params = { .input_min = 2000000, .input_max = 31000000, @@ -220,6 +244,11 @@ static void tegra124_pll_init(void) clks[TEGRA124_CLK_PLL_U] = tegra_clk_register_pll("pll_u", "pll_ref", car_base, 0, 0, &pll_u_params, TEGRA_PLLU | TEGRA_PLL_HAS_CPCON, pll_u_freq_table); + + /* PLLE */ + clks[TEGRA124_CLK_PLL_E] = tegra_clk_register_plle_tegra114("pll_e", + "pll_ref", car_base, 0, 100000000, &pll_e_params, + TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK, pll_e_freq_table); } static const char *mux_pllpcm_clkm[] = {"pll_p", "pll_c2", "pll_c", "pll_c3", @@ -244,6 +273,12 @@ static void tegra124_periph_init(void) mux_pllpcm_clkm, ARRAY_SIZE(mux_pllpcm_clkm), car_base, CRC_CLK_SOURCE_UARTD, TEGRA124_CLK_UARTD, TEGRA_PERIPH_ON_APB); + clks[TEGRA124_CLK_PCIE] = clk_gate("pcie", "clk_m", + car_base + CRC_CLK_OUT_ENB_U, 6, 0, 0); + clks[TEGRA124_CLK_AFI] = clk_gate("afi", "clk_m", + car_base + CRC_CLK_OUT_ENB_U, 8, 0, 0); + clks[TEGRA124_CLK_CML0] = clk_gate("cml0", "pll_e", + car_base + CRC_PLLE_AUX, 0, 0, 0); /* peripheral clocks with a divider */ clks[TEGRA124_CLK_MSELECT] = tegra_clk_register_periph("mselect", -- cgit v1.2.3 From 9d1fbc5d12824f882a477f331966517dbc2db5b2 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sun, 2 Nov 2014 21:13:53 +0100 Subject: add generic PHY framework This brings in the generix PHY framework from Linux. I tried to strip it down as much as possible while keeping it useful. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/Kconfig | 1 + drivers/Makefile | 1 + drivers/phy/Kconfig | 18 +++ drivers/phy/Makefile | 5 + drivers/phy/phy-core.c | 318 ++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/phy/phy.h | 240 ++++++++++++++++++++++++++++++++++++ 6 files changed, 583 insertions(+) create mode 100644 drivers/phy/Kconfig create mode 100644 drivers/phy/Makefile create mode 100644 drivers/phy/phy-core.c create mode 100644 include/linux/phy/phy.h diff --git a/drivers/Kconfig b/drivers/Kconfig index e126f62c8f..5984ccca2c 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -30,5 +30,6 @@ source "drivers/reset/Kconfig" source "drivers/pci/Kconfig" source "drivers/rtc/Kconfig" source "drivers/firmware/Kconfig" +source "drivers/phy/Kconfig" endmenu diff --git a/drivers/Makefile b/drivers/Makefile index cf42190b7b..7ef5e90d80 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_RESET_CONTROLLER) += reset/ obj-$(CONFIG_PCI) += pci/ obj-y += rtc/ obj-$(CONFIG_FIRMWARE) += firmware/ +obj-$(CONFIG_GENERIC_PHY) += phy/ diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig new file mode 100644 index 0000000000..e9461e1a25 --- /dev/null +++ b/drivers/phy/Kconfig @@ -0,0 +1,18 @@ +# +# PHY +# + +menu "PHY Subsystem" + +config GENERIC_PHY + bool "PHY Core" + help + Generic PHY support. + + This framework is designed to provide a generic interface for PHY + devices present in the kernel. This layer will have the generic + API by which phy drivers can create PHY using the phy framework and + phy users can obtain reference to the PHY. All the users of this + framework should select this config. + +endmenu diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile new file mode 100644 index 0000000000..74514aeaed --- /dev/null +++ b/drivers/phy/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the phy drivers. +# + +obj-$(CONFIG_GENERIC_PHY) += phy-core.o diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c new file mode 100644 index 0000000000..67af14f680 --- /dev/null +++ b/drivers/phy/phy-core.c @@ -0,0 +1,318 @@ +/* + * phy-core.c -- Generic Phy framework. + * + * Copyright (C) 2014 Lucas Stach + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * + * Author: Kishon Vijay Abraham I + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include + +static LIST_HEAD(phy_provider_list); +static int phy_ida; + +/** + * phy_create() - create a new phy + * @dev: device that is creating the new phy + * @node: device node of the phy + * @ops: function pointers for performing phy operations + * @init_data: contains the list of PHY consumers or NULL + * + * Called to create a phy using phy framework. + */ +struct phy *phy_create(struct device_d *dev, struct device_node *node, + const struct phy_ops *ops, + struct phy_init_data *init_data) +{ + int ret; + int id; + struct phy *phy; + + if (WARN_ON(!dev)) + return ERR_PTR(-EINVAL); + + phy = kzalloc(sizeof(*phy), GFP_KERNEL); + if (!phy) + return ERR_PTR(-ENOMEM); + + id = phy_ida++; + + snprintf(phy->dev.name, MAX_DRIVER_NAME, "phy"); + phy->dev.id = id; + phy->dev.parent = dev; + phy->dev.device_node = node ?: dev->device_node; + phy->id = id; + phy->ops = ops; + phy->init_data = init_data; + + ret = register_device(&phy->dev); + if (ret) + goto free_ida; + + return phy; + +free_ida: + phy_ida--; + kfree(phy); + return ERR_PTR(ret); +} + +/** + * __of_phy_provider_register() - create/register phy provider with the framework + * @dev: struct device of the phy provider + * @owner: the module owner containing of_xlate + * @of_xlate: function pointer to obtain phy instance from phy provider + * + * Creates struct phy_provider from dev and of_xlate function pointer. + * This is used in the case of dt boot for finding the phy instance from + * phy provider. + */ +struct phy_provider *__of_phy_provider_register(struct device_d *dev, + struct phy * (*of_xlate)(struct device_d *dev, + struct of_phandle_args *args)) +{ + struct phy_provider *phy_provider; + + phy_provider = kzalloc(sizeof(*phy_provider), GFP_KERNEL); + if (!phy_provider) + return ERR_PTR(-ENOMEM); + + phy_provider->dev = dev; + phy_provider->of_xlate = of_xlate; + + list_add_tail(&phy_provider->list, &phy_provider_list); + + return phy_provider; +} + +/** + * of_phy_provider_unregister() - unregister phy provider from the framework + * @phy_provider: phy provider returned by of_phy_provider_register() + * + * Removes the phy_provider created using of_phy_provider_register(). + */ +void of_phy_provider_unregister(struct phy_provider *phy_provider) +{ + if (IS_ERR(phy_provider)) + return; + + list_del(&phy_provider->list); + kfree(phy_provider); +} + +int phy_init(struct phy *phy) +{ + int ret; + + if (!phy) + return 0; + + if (phy->init_count == 0 && phy->ops->init) { + ret = phy->ops->init(phy); + if (ret < 0) { + dev_err(&phy->dev, "phy init failed --> %d\n", ret); + return ret; + } + } + ++phy->init_count; + + return 0; +} + +int phy_exit(struct phy *phy) +{ + int ret; + + if (!phy) + return 0; + + if (phy->init_count == 1 && phy->ops->exit) { + ret = phy->ops->exit(phy); + if (ret < 0) { + dev_err(&phy->dev, "phy exit failed --> %d\n", ret); + return ret; + } + } + --phy->init_count; + + return 0; +} + +int phy_power_on(struct phy *phy) +{ + int ret; + + if (!phy) + return 0; + + if (phy->pwr) { + ret = regulator_enable(phy->pwr); + if (ret) + return ret; + } + + if (phy->power_count == 0 && phy->ops->power_on) { + ret = phy->ops->power_on(phy); + if (ret < 0) { + dev_err(&phy->dev, "phy poweron failed --> %d\n", ret); + goto out; + } + } else { + ret = 0; /* Override possible ret == -ENOTSUPP */ + } + ++phy->power_count; + + return 0; + +out: + if (phy->pwr) + regulator_disable(phy->pwr); + + return ret; +} + +int phy_power_off(struct phy *phy) +{ + int ret; + + if (!phy) + return 0; + + if (phy->power_count == 1 && phy->ops->power_off) { + ret = phy->ops->power_off(phy); + if (ret < 0) { + dev_err(&phy->dev, "phy poweroff failed --> %d\n", ret); + return ret; + } + } + --phy->power_count; + + if (phy->pwr) + regulator_disable(phy->pwr); + + return 0; +} + +static struct phy_provider *of_phy_provider_lookup(struct device_node *node) +{ + struct phy_provider *phy_provider; + struct device_node *child; + + list_for_each_entry(phy_provider, &phy_provider_list, list) { + if (phy_provider->dev->device_node == node) + return phy_provider; + + for_each_child_of_node(phy_provider->dev->device_node, child) + if (child == node) + return phy_provider; + } + + return ERR_PTR(-ENODEV); +} + +/** + * _of_phy_get() - lookup and obtain a reference to a phy by phandle + * @np: device_node for which to get the phy + * @index: the index of the phy + * + * Returns the phy associated with the given phandle value, + * after getting a refcount to it or -ENODEV if there is no such phy or + * -EPROBE_DEFER if there is a phandle to the phy, but the device is + * not yet loaded. This function uses of_xlate call back function provided + * while registering the phy_provider to find the phy instance. + */ +static struct phy *_of_phy_get(struct device_node *np, int index) +{ + int ret; + struct phy_provider *phy_provider; + struct of_phandle_args args; + + ret = of_parse_phandle_with_args(np, "phys", "#phy-cells", + index, &args); + if (ret) + return ERR_PTR(-ENODEV); + + phy_provider = of_phy_provider_lookup(args.np); + if (IS_ERR(phy_provider)) { + return ERR_PTR(-ENODEV); + } + + return phy_provider->of_xlate(phy_provider->dev, &args); +} + +/** + * of_phy_get() - lookup and obtain a reference to a phy using a device_node. + * @np: device_node for which to get the phy + * @con_id: name of the phy from device's point of view + * + * Returns the phy driver, after getting a refcount to it; or + * -ENODEV if there is no such phy. The caller is responsible for + * calling phy_put() to release that count. + */ +struct phy *of_phy_get(struct device_node *np, const char *con_id) +{ + int index = 0; + + if (con_id) + index = of_property_match_string(np, "phy-names", con_id); + + return _of_phy_get(np, index); +} + +/** + * phy_get() - lookup and obtain a reference to a phy. + * @dev: device that requests this phy + * @string: the phy name as given in the dt data or the name of the controller + * port for non-dt case + * + * Returns the phy driver, after getting a refcount to it; or + * -ENODEV if there is no such phy. The caller is responsible for + * calling phy_put() to release that count. + */ +struct phy *phy_get(struct device_d *dev, const char *string) +{ + int index = 0; + struct phy *phy = ERR_PTR(-ENODEV); + + if (string == NULL) { + dev_warn(dev, "missing string\n"); + return ERR_PTR(-EINVAL); + } + + if (dev->device_node) { + index = of_property_match_string(dev->device_node, "phy-names", + string); + phy = _of_phy_get(dev->device_node, index); + } + + return phy; +} + +/** + * phy_optional_get() - lookup and obtain a reference to an optional phy. + * @dev: device that requests this phy + * @string: the phy name as given in the dt data or the name of the controller + * port for non-dt case + * + * Returns the phy driver, after getting a refcount to it; or + * NULL if there is no such phy. The caller is responsible for + * calling phy_put() to release that count. + */ +struct phy *phy_optional_get(struct device_d *dev, const char *string) +{ + struct phy *phy = phy_get(dev, string); + + if (PTR_ERR(phy) == -ENODEV) + phy = NULL; + + return phy; +} + diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h new file mode 100644 index 0000000000..94f0044036 --- /dev/null +++ b/include/linux/phy/phy.h @@ -0,0 +1,240 @@ +/* + * phy.h -- generic phy header file + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * + * Author: Kishon Vijay Abraham I + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __DRIVERS_PHY_H +#define __DRIVERS_PHY_H + +#include +#include +#include + +struct phy; + +/** + * struct phy_ops - set of function pointers for performing phy operations + * @init: operation to be performed for initializing phy + * @exit: operation to be performed while exiting + * @power_on: powering on the phy + * @power_off: powering off the phy + * @owner: the module owner containing the ops + */ +struct phy_ops { + int (*init)(struct phy *phy); + int (*exit)(struct phy *phy); + int (*power_on)(struct phy *phy); + int (*power_off)(struct phy *phy); +}; + +/** + * struct phy_attrs - represents phy attributes + * @bus_width: Data path width implemented by PHY + */ +struct phy_attrs { + u32 bus_width; +}; + +/** + * struct phy - represents the phy device + * @dev: phy device + * @id: id of the phy device + * @ops: function pointers for performing phy operations + * @init_data: list of PHY consumers (non-dt only) + * @mutex: mutex to protect phy_ops + * @init_count: used to protect when the PHY is used by multiple consumers + * @power_count: used to protect when the PHY is used by multiple consumers + * @phy_attrs: used to specify PHY specific attributes + */ +struct phy { + struct device_d dev; + int id; + const struct phy_ops *ops; + struct phy_init_data *init_data; + int init_count; + int power_count; + struct phy_attrs attrs; + struct regulator *pwr; +}; + +/** + * struct phy_provider - represents the phy provider + * @dev: phy provider device + * @owner: the module owner having of_xlate + * @of_xlate: function pointer to obtain phy instance from phy pointer + * @list: to maintain a linked list of PHY providers + */ +struct phy_provider { + struct device_d *dev; + struct list_head list; + struct phy * (*of_xlate)(struct device_d *dev, + struct of_phandle_args *args); +}; + +/** + * struct phy_consumer - represents the phy consumer + * @dev_name: the device name of the controller that will use this PHY device + * @port: name given to the consumer port + */ +struct phy_consumer { + const char *dev_name; + const char *port; +}; + +/** + * struct phy_init_data - contains the list of PHY consumers + * @num_consumers: number of consumers for this PHY device + * @consumers: list of PHY consumers + */ +struct phy_init_data { + unsigned int num_consumers; + struct phy_consumer *consumers; +}; + +#define PHY_CONSUMER(_dev_name, _port) \ +{ \ + .dev_name = _dev_name, \ + .port = _port, \ +} + +#define to_phy(dev) (container_of((dev), struct phy, dev)) + +#define of_phy_provider_register(dev, xlate) \ + __of_phy_provider_register((dev), (xlate)) + + +static inline void phy_set_drvdata(struct phy *phy, void *data) +{ + phy->dev.priv = data; +} + +static inline void *phy_get_drvdata(struct phy *phy) +{ + return phy->dev.priv; +} + +#if IS_ENABLED(CONFIG_GENERIC_PHY) +int phy_init(struct phy *phy); +int phy_exit(struct phy *phy); +int phy_power_on(struct phy *phy); +int phy_power_off(struct phy *phy); +static inline int phy_get_bus_width(struct phy *phy) +{ + return phy->attrs.bus_width; +} +static inline void phy_set_bus_width(struct phy *phy, int bus_width) +{ + phy->attrs.bus_width = bus_width; +} +struct phy *phy_get(struct device_d *dev, const char *string); +struct phy *phy_optional_get(struct device_d *dev, const char *string); +void phy_put(struct phy *phy); +struct phy *of_phy_get(struct device_node *np, const char *con_id); +struct phy *of_phy_simple_xlate(struct device_d *dev, + struct of_phandle_args *args); +struct phy *phy_create(struct device_d *dev, struct device_node *node, + const struct phy_ops *ops, + struct phy_init_data *init_data); +void phy_destroy(struct phy *phy); +struct phy_provider *__of_phy_provider_register(struct device_d *dev, + struct phy * (*of_xlate)(struct device_d *dev, + struct of_phandle_args *args)); +void of_phy_provider_unregister(struct phy_provider *phy_provider); +#else +static inline int phy_init(struct phy *phy) +{ + if (!phy) + return 0; + return -ENOSYS; +} + +static inline int phy_exit(struct phy *phy) +{ + if (!phy) + return 0; + return -ENOSYS; +} + +static inline int phy_power_on(struct phy *phy) +{ + if (!phy) + return 0; + return -ENOSYS; +} + +static inline int phy_power_off(struct phy *phy) +{ + if (!phy) + return 0; + return -ENOSYS; +} + +static inline int phy_get_bus_width(struct phy *phy) +{ + return -ENOSYS; +} + +static inline void phy_set_bus_width(struct phy *phy, int bus_width) +{ + return; +} + +static inline struct phy *phy_get(struct device_d *dev, const char *string) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct phy *phy_optional_get(struct device_d *dev, + const char *string) +{ + return ERR_PTR(-ENOSYS); +} + +static inline void phy_put(struct phy *phy) +{ +} + +static inline struct phy *of_phy_get(struct device_node *np, const char *con_id) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct phy *of_phy_simple_xlate(struct device_d *dev, + struct of_phandle_args *args) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct phy *phy_create(struct device_d *dev, + struct device_node *node, + const struct phy_ops *ops, + struct phy_init_data *init_data) +{ + return ERR_PTR(-ENOSYS); +} + +static inline void phy_destroy(struct phy *phy) +{ +} + +static inline struct phy_provider *__of_phy_provider_register( + struct device_d *dev, struct phy * (*of_xlate)( + struct device_d *dev, struct of_phandle_args *args)) +{ + return ERR_PTR(-ENOSYS); +} + +static inline void of_phy_provider_unregister(struct phy_provider *phy_provider) +{ +} +#endif + +#endif /* __DRIVERS_PHY_H */ -- cgit v1.2.3 From af7c753f2e65689296ab124b7f6962c2df19e67e Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sun, 2 Nov 2014 21:13:55 +0100 Subject: pci: tegra: add tegra124 support Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/pci/pci-tegra.c | 156 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 134 insertions(+), 22 deletions(-) diff --git a/drivers/pci/pci-tegra.c b/drivers/pci/pci-tegra.c index 07bb251621..f2ade7749d 100644 --- a/drivers/pci/pci-tegra.c +++ b/drivers/pci/pci-tegra.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -133,8 +134,10 @@ #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK (0xf << 20) #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE (0x0 << 20) #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420 (0x0 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1 (0x0 << 20) #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL (0x1 << 20) #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222 (0x1 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1 (0x1 << 20) #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411 (0x2 << 20) #define AFI_FUSE 0x104 @@ -146,12 +149,21 @@ #define AFI_PEX_CTRL_RST (1 << 0) #define AFI_PEX_CTRL_CLKREQ_EN (1 << 1) #define AFI_PEX_CTRL_REFCLK_EN (1 << 3) +#define AFI_PEX_CTRL_OVERRIDE_EN (1 << 4) + +#define AFI_PLLE_CONTROL 0x160 +#define AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL (1 << 9) +#define AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN (1 << 1) #define AFI_PEXBIAS_CTRL_0 0x168 #define RP_VEND_XP 0x00000F00 #define RP_VEND_XP_DL_UP (1 << 30) +#define RP_PRIV_MISC 0x00000FE0 +#define RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xE << 0) +#define RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xF << 0) + #define RP_LINK_CONTROL_STATUS 0x00000090 #define RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE 0x20000000 #define RP_LINK_CONTROL_STATUS_LINKSTAT_MASK 0x3fff0000 @@ -209,6 +221,7 @@ struct tegra_pcie_soc_data { bool has_intr_prsnt_sense; bool has_avdd_supply; bool has_cml_clk; + bool has_gen2; }; struct tegra_pcie { @@ -236,6 +249,8 @@ struct tegra_pcie { struct reset_control *afi_rst; struct reset_control *pcie_xrst; + struct phy *phy; + struct list_head ports; unsigned int num_ports; u32 xbar_config; @@ -424,6 +439,8 @@ static void tegra_pcie_port_enable(struct tegra_pcie_port *port) if (soc->has_pex_clkreq_en) value |= AFI_PEX_CTRL_CLKREQ_EN; + value |= AFI_PEX_CTRL_OVERRIDE_EN; + afi_writel(port->pcie, value, ctrl); tegra_pcie_port_reset(port); @@ -550,29 +567,10 @@ static void tegra_pcie_setup_translations(struct tegra_pcie *pcie) afi_writel(pcie, 0, AFI_MSI_BAR_SZ); } -static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) +static int tegra_pcie_phy_enable(struct tegra_pcie *pcie) { const struct tegra_pcie_soc_data *soc = pcie->soc_data; - struct tegra_pcie_port *port; - unsigned long value; - - /* power down PCIe slot clock bias pad */ - if (soc->has_pex_bias_ctrl) - afi_writel(pcie, 0, AFI_PEXBIAS_CTRL_0); - - /* configure mode and disable all ports */ - value = afi_readl(pcie, AFI_PCIE_CONFIG); - value &= ~AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK; - value |= AFI_PCIE_CONFIG_PCIE_DISABLE_ALL | pcie->xbar_config; - - list_for_each_entry(port, &pcie->ports, list) - value &= ~AFI_PCIE_CONFIG_PCIE_DISABLE(port->index); - - afi_writel(pcie, value, AFI_PCIE_CONFIG); - - value = afi_readl(pcie, AFI_FUSE); - value |= AFI_FUSE_PCIE_T0_GEN2_DIS; - afi_writel(pcie, value, AFI_FUSE); + u32 value; /* initialize internal PHY, enable up to 16 PCIE lanes */ pads_writel(pcie, 0x0, PADS_CTL_SEL); @@ -591,6 +589,13 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) value |= PADS_PLL_CTL_REFCLK_INTERNAL_CML | soc->tx_ref_sel; pads_writel(pcie, value, soc->pads_pll_ctl); + /* reset PLL */ + value = pads_readl(pcie, soc->pads_pll_ctl); + value &= ~PADS_PLL_CTL_RST_B4SM; + pads_writel(pcie, value, soc->pads_pll_ctl); + + udelay(20); + /* take PLL out of reset */ value = pads_readl(pcie, soc->pads_pll_ctl); value |= PADS_PLL_CTL_RST_B4SM; @@ -619,6 +624,53 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) value |= PADS_CTL_TX_DATA_EN_1L | PADS_CTL_RX_DATA_EN_1L; pads_writel(pcie, value, PADS_CTL); + return 0; +} + +static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) +{ + const struct tegra_pcie_soc_data *soc = pcie->soc_data; + struct tegra_pcie_port *port; + unsigned long value; + int err; + + /* enable PLL power down */ + if (pcie->phy) { + value = afi_readl(pcie, AFI_PLLE_CONTROL); + value &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL; + value |= AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN; + afi_writel(pcie, value, AFI_PLLE_CONTROL); + } + + /* power down PCIe slot clock bias pad */ + if (soc->has_pex_bias_ctrl) + afi_writel(pcie, 0, AFI_PEXBIAS_CTRL_0); + + /* configure mode and disable all ports */ + value = afi_readl(pcie, AFI_PCIE_CONFIG); + value &= ~AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK; + value |= AFI_PCIE_CONFIG_PCIE_DISABLE_ALL | pcie->xbar_config; + + list_for_each_entry(port, &pcie->ports, list) + value &= ~AFI_PCIE_CONFIG_PCIE_DISABLE(port->index); + + afi_writel(pcie, value, AFI_PCIE_CONFIG); + + if (soc->has_gen2) { + value = afi_readl(pcie, AFI_FUSE); + value &= ~AFI_FUSE_PCIE_T0_GEN2_DIS; + afi_writel(pcie, value, AFI_FUSE); + } else { + value = afi_readl(pcie, AFI_FUSE); + value |= AFI_FUSE_PCIE_T0_GEN2_DIS; + afi_writel(pcie, value, AFI_FUSE); + } + + if (!pcie->phy) + err = tegra_pcie_phy_enable(pcie); + else + err = phy_power_on(pcie->phy); + /* take the PCIe interface module out of reset */ reset_control_deassert(pcie->pcie_xrst); @@ -653,6 +705,10 @@ static void tegra_pcie_power_off(struct tegra_pcie *pcie) /* TODO: disable and unprepare clocks? */ + err = phy_power_off(pcie->phy); + if (err < 0) + dev_warn(pcie->dev, "failed to power off PHY: %d\n", err); + reset_control_assert(pcie->pcie_xrst); reset_control_assert(pcie->afi_rst); reset_control_assert(pcie->pex_rst); @@ -806,6 +862,19 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie) return err; } + pcie->phy = phy_optional_get(pcie->dev, "pcie"); + if (IS_ERR(pcie->phy)) { + err = PTR_ERR(pcie->phy); + dev_err(dev, "failed to get PHY: %d\n", err); + return err; + } + + err = phy_init(pcie->phy); + if (err < 0) { + dev_err(dev, "failed to initialize PHY: %d\n", err); + return err; + } + err = tegra_pcie_power_on(pcie); if (err) { dev_err(dev, "failed to power up: %d\n", err); @@ -840,7 +909,14 @@ poweroff: static int tegra_pcie_put_resources(struct tegra_pcie *pcie) { + int err; + tegra_pcie_power_off(pcie); + + err = phy_exit(pcie->phy); + if (err < 0) + dev_err(pcie->dev, "failed to teardown PHY: %d\n", err); + return 0; } @@ -849,7 +925,19 @@ static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes, { struct device_node *np = pcie->dev->device_node; - if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) { + if (of_device_is_compatible(np, "nvidia,tegra124-pcie")) { + switch (lanes) { + case 0x0000104: + dev_info(pcie->dev, "4x1, 1x1 configuration\n"); + *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1; + return 0; + + case 0x0000102: + dev_info(pcie->dev, "2x1, 1x1 configuration\n"); + *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1; + return 0; + } + } else if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) { switch (lanes) { case 0x00000204: dev_info(pcie->dev, "4x1, 2x1 configuration\n"); @@ -1048,6 +1136,13 @@ static bool tegra_pcie_port_check_link(struct tegra_pcie_port *port) { unsigned int timeout; unsigned int retries = 2; + u32 value; + + /* override presence detection */ + value = readl(port->base + RP_PRIV_MISC); + value &= ~RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT; + value |= RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT; + writel(value, port->base + RP_PRIV_MISC); do { timeout = wait_on_timeout(50 * MSECOND, @@ -1113,6 +1208,7 @@ static const struct tegra_pcie_soc_data tegra20_pcie_data = { .has_intr_prsnt_sense = false, .has_avdd_supply = false, .has_cml_clk = false, + .has_gen2 = false, }; static const struct tegra_pcie_soc_data tegra30_pcie_data = { @@ -1125,10 +1221,26 @@ static const struct tegra_pcie_soc_data tegra30_pcie_data = { .has_intr_prsnt_sense = true, .has_avdd_supply = true, .has_cml_clk = true, + .has_gen2 = false, +}; + +static const struct tegra_pcie_soc_data tegra124_pcie_data = { + .num_ports = 2, + .msi_base_shift = 8, + .pads_pll_ctl = PADS_PLL_CTL_TEGRA30, + .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN, + .has_pex_clkreq_en = true, + .has_pex_bias_ctrl = true, + .has_intr_prsnt_sense = true, + .has_cml_clk = true, + .has_gen2 = true, }; static __maybe_unused struct of_device_id tegra_pcie_of_match[] = { { + .compatible = "nvidia,tegra124-pcie", + .data = (unsigned long)&tegra124_pcie_data + }, { .compatible = "nvidia,tegra30-pcie", .data = (unsigned long)&tegra30_pcie_data }, { -- cgit v1.2.3 From ab558587f54a7644841e2c4b04b7a10bc82ea182 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 3 Nov 2014 23:52:13 +0100 Subject: tegra: beaver: set hostname in board init Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/boards/nvidia-beaver/board.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/arch/arm/boards/nvidia-beaver/board.c b/arch/arm/boards/nvidia-beaver/board.c index 20707d883f..d270301ab3 100644 --- a/arch/arm/boards/nvidia-beaver/board.c +++ b/arch/arm/boards/nvidia-beaver/board.c @@ -20,7 +20,7 @@ #include #include -static int nvidia_beaver_devices_init(void) +static int nvidia_beaver_fs_init(void) { struct i2c_client client; u8 data; @@ -44,4 +44,15 @@ static int nvidia_beaver_devices_init(void) return 0; } -fs_initcall(nvidia_beaver_devices_init); +fs_initcall(nvidia_beaver_fs_init); + +static int nvidia_beaver_device_init(void) +{ + if (!of_machine_is_compatible("nvidia,beaver")) + return 0; + + barebox_set_hostname("beaver"); + + return 0; +} +device_initcall(nvidia_beaver_device_init); -- cgit v1.2.3 From 7de814ca552dd8cc75638e7dd547119ceae09ea6 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 3 Nov 2014 23:52:14 +0100 Subject: tegra: jetson-tk1: set hostname in board init Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/boards/nvidia-jetson-tk1/board.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/arch/arm/boards/nvidia-jetson-tk1/board.c b/arch/arm/boards/nvidia-jetson-tk1/board.c index c20f56a3bb..564e6a0aa1 100644 --- a/arch/arm/boards/nvidia-jetson-tk1/board.c +++ b/arch/arm/boards/nvidia-jetson-tk1/board.c @@ -26,7 +26,7 @@ #define AS3722_GPIO_SIGNAL_OUT 0x20 #define AS3722_SD_CONTROL 0x4d -static int nvidia_jetson_tk1_devices_init(void) +static int nvidia_jetson_tk1_fs_init(void) { struct i2c_client client; u8 data; @@ -47,4 +47,15 @@ static int nvidia_jetson_tk1_devices_init(void) return 0; } -fs_initcall(nvidia_jetson_tk1_devices_init); +fs_initcall(nvidia_jetson_tk1_fs_init); + +static int nvidia_jetson_tk1_device_init(void) +{ + if (!of_machine_is_compatible("nvidia,jetson-tk1")) + return 0; + + barebox_set_hostname("jetson-tk1"); + + return 0; +} +device_initcall(nvidia_jetson_tk1_device_init); -- cgit v1.2.3 From c425821ef1a9fab91b417fd5fba9f5b375c1573d Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sun, 5 Oct 2014 21:39:42 +0200 Subject: ARM: tegra30: add environment path to Beaver DT Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/dts/tegra30-beaver.dts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm/dts/tegra30-beaver.dts b/arch/arm/dts/tegra30-beaver.dts index 35b4d7e43c..94955f96fe 100644 --- a/arch/arm/dts/tegra30-beaver.dts +++ b/arch/arm/dts/tegra30-beaver.dts @@ -11,6 +11,13 @@ rtc1 = "/rtc@7000e000"; }; + chosen { + environment@0 { + compatible = "barebox,environment"; + device-path = &emmc, "partname:boot1"; + }; + }; + memory { reg = <0x80000000 0x7ff00000>; }; @@ -750,7 +757,7 @@ bus-width = <4>; }; - sdhci@78000600 { + emmc: sdhci@78000600 { status = "okay"; bus-width = <8>; non-removable; -- cgit v1.2.3 From 8355659fcd733793515a8b963c845402566b2645 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sun, 5 Oct 2014 21:39:43 +0200 Subject: ARM: tegra124: add environment path to Jetson-TK1 DT Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/dts/tegra124-jetson-tk1.dts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm/dts/tegra124-jetson-tk1.dts b/arch/arm/dts/tegra124-jetson-tk1.dts index 16082c0bda..32e41f9074 100644 --- a/arch/arm/dts/tegra124-jetson-tk1.dts +++ b/arch/arm/dts/tegra124-jetson-tk1.dts @@ -12,6 +12,13 @@ rtc1 = "/rtc@0,7000e000"; }; + chosen { + environment@0 { + compatible = "barebox,environment"; + device-path = &emmc, "partname:boot1"; + }; + }; + memory { reg = <0x0 0x80000000 0x0 0x80000000>; }; @@ -1630,7 +1637,7 @@ }; /* eMMC */ - sdhci@0,700b0600 { + emmc: sdhci@0,700b0600 { status = "okay"; bus-width = <8>; non-removable; -- cgit v1.2.3 From f63a42a9991164fd938ec2f37f0ed1d1caf9ef32 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 20 Oct 2014 20:15:29 +0200 Subject: reset_source: add thermal reset Some SoCs are able to detect if they got reset in response to an overtemperature event. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- common/reset_source.c | 1 + include/reset_source.h | 1 + 2 files changed, 2 insertions(+) diff --git a/common/reset_source.c b/common/reset_source.c index 6026af1967..946670b182 100644 --- a/common/reset_source.c +++ b/common/reset_source.c @@ -25,6 +25,7 @@ static const char * const reset_src_names[] = { [RESET_WDG] = "WDG", [RESET_WKE] = "WKE", [RESET_JTAG] = "JTAG", + [RESET_THERM] = "THERM", }; static enum reset_src_type reset_source; diff --git a/include/reset_source.h b/include/reset_source.h index bff7f97850..6620228722 100644 --- a/include/reset_source.h +++ b/include/reset_source.h @@ -20,6 +20,7 @@ enum reset_src_type { RESET_WDG, /* watchdog */ RESET_WKE, /* wake-up (some SoCs can handle this) */ RESET_JTAG, /* JTAG reset */ + RESET_THERM, /* SoC shut down because of overtemperature */ }; #ifdef CONFIG_RESET_SOURCE -- cgit v1.2.3 From 1834169f13cccb1784172aa1ccb85d89f006c254 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 20 Oct 2014 20:15:30 +0200 Subject: tegra: pmc: add support for reset src detection Also activate in defconfig. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/configs/tegra_v7_defconfig | 1 + arch/arm/mach-tegra/include/mach/tegra20-pmc.h | 9 ++++++++ arch/arm/mach-tegra/tegra20-pmc.c | 32 ++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/arch/arm/configs/tegra_v7_defconfig b/arch/arm/configs/tegra_v7_defconfig index ead69edff1..1402bd6d01 100644 --- a/arch/arm/configs/tegra_v7_defconfig +++ b/arch/arm/configs/tegra_v7_defconfig @@ -16,6 +16,7 @@ CONFIG_AUTO_COMPLETE=y CONFIG_MENU=y CONFIG_BLSPEC=y CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y +CONFIG_RESET_SOURCE=y CONFIG_LONGHELP=y CONFIG_CMD_IOMEM=y CONFIG_CMD_MEMINFO=y diff --git a/arch/arm/mach-tegra/include/mach/tegra20-pmc.h b/arch/arm/mach-tegra/include/mach/tegra20-pmc.h index 30ac06508c..c379544755 100644 --- a/arch/arm/mach-tegra/include/mach/tegra20-pmc.h +++ b/arch/arm/mach-tegra/include/mach/tegra20-pmc.h @@ -71,3 +71,12 @@ #define PMC_PARTID_C0NC 15 #define PMC_SCRATCH(i) (0x050 + 0x4*i) + +#define PMC_RST_STATUS 0x1b4 +#define PMC_RST_STATUS_RST_SRC_SHIFT 0 +#define PMC_RST_STATUS_RST_SRC_MASK (0x7 << PMC_RST_STATUS_RST_SRC_SHIFT) +#define PMC_RST_STATUS_RST_SRC_POR 0 +#define PMC_RST_STATUS_RST_SRC_WATCHDOG 1 +#define PMC_RST_STATUS_RST_SRC_SENSOR 2 +#define PMC_RST_STATUS_RST_SRC_SW_MAIN 3 +#define PMC_RST_STATUS_RST_SRC_LP0 4 diff --git a/arch/arm/mach-tegra/tegra20-pmc.c b/arch/arm/mach-tegra/tegra20-pmc.c index dcd2978109..eaa5ac73ff 100644 --- a/arch/arm/mach-tegra/tegra20-pmc.c +++ b/arch/arm/mach-tegra/tegra20-pmc.c @@ -28,6 +28,8 @@ #include #include #include +#include + #include static void __iomem *pmc_base; @@ -171,6 +173,33 @@ static int tegra_powergate_init(void) return 0; } +static void tegra20_pmc_detect_reset_cause(void) +{ + u32 reg = readl(pmc_base + PMC_RST_STATUS); + + switch ((reg & PMC_RST_STATUS_RST_SRC_MASK) >> + PMC_RST_STATUS_RST_SRC_SHIFT) { + case PMC_RST_STATUS_RST_SRC_POR: + reset_source_set(RESET_POR); + break; + case PMC_RST_STATUS_RST_SRC_WATCHDOG: + reset_source_set(RESET_WDG); + break; + case PMC_RST_STATUS_RST_SRC_LP0: + reset_source_set(RESET_WKE); + break; + case PMC_RST_STATUS_RST_SRC_SW_MAIN: + reset_source_set(RESET_RST); + break; + case PMC_RST_STATUS_RST_SRC_SENSOR: + reset_source_set(RESET_THERM); + break; + default: + reset_source_set(RESET_UKWN); + break; + } +} + static int tegra20_pmc_probe(struct device_d *dev) { pmc_base = dev_request_mem_region(dev, 0); @@ -181,6 +210,9 @@ static int tegra20_pmc_probe(struct device_d *dev) tegra_powergate_init(); + if (IS_ENABLED(CONFIG_RESET_SOURCE)) + tegra20_pmc_detect_reset_cause(); + return 0; } -- cgit v1.2.3 From aa8bd30851e9a09480afde2b98b24b8c1736292e Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sun, 2 Nov 2014 21:13:45 +0100 Subject: tegra: defconfig: enable barebox OF drivers We use them to configure the environment location so it's a good idea to have them available by default. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/configs/tegra_v7_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/tegra_v7_defconfig b/arch/arm/configs/tegra_v7_defconfig index 1402bd6d01..47e594ba68 100644 --- a/arch/arm/configs/tegra_v7_defconfig +++ b/arch/arm/configs/tegra_v7_defconfig @@ -38,6 +38,7 @@ CONFIG_CMD_DETECT=y CONFIG_CMD_GPIO=y CONFIG_CMD_OFTREE=y CONFIG_NET=y +CONFIG_OF_BAREBOX_DRIVERS=y CONFIG_DRIVER_SERIAL_NS16550=y CONFIG_DRIVER_NET_RTL8169=y CONFIG_MCI=y -- cgit v1.2.3 From 8b2456a4cbd9d9dfb94aa2d59e36e353a2b31fcb Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sun, 2 Nov 2014 21:13:46 +0100 Subject: pinctrl: tegra: try to select "boot" state New DTs call the initial pinctrl state "boot" in order to avoid Linux reconfiguring the pinctrl by default. The bootloader should explicitly set this state. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/pinctrl/pinctrl-tegra20.c | 8 ++++++-- drivers/pinctrl/pinctrl-tegra30.c | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/pinctrl/pinctrl-tegra20.c b/drivers/pinctrl/pinctrl-tegra20.c index 3c11be6f55..be9d8a996d 100644 --- a/drivers/pinctrl/pinctrl-tegra20.c +++ b/drivers/pinctrl/pinctrl-tegra20.c @@ -320,10 +320,14 @@ static int pinctrl_tegra20_probe(struct device_d *dev) ctrl->pinctrl.ops = &pinctrl_tegra20_ops; ret = pinctrl_register(&ctrl->pinctrl); - if (ret) + if (ret) { free(ctrl); + return ret; + } + + of_pinctrl_select_state(dev->device_node, "boot"); - return ret; + return 0; } static __maybe_unused struct of_device_id pinctrl_tegra20_dt_ids[] = { diff --git a/drivers/pinctrl/pinctrl-tegra30.c b/drivers/pinctrl/pinctrl-tegra30.c index 82772187d5..aac67605cf 100644 --- a/drivers/pinctrl/pinctrl-tegra30.c +++ b/drivers/pinctrl/pinctrl-tegra30.c @@ -897,10 +897,14 @@ static int pinctrl_tegra30_probe(struct device_d *dev) ctrl->pinctrl.ops = &pinctrl_tegra30_ops; ret = pinctrl_register(&ctrl->pinctrl); - if (ret) + if (ret) { free(ctrl); + return ret; + } + + of_pinctrl_select_state(dev->device_node, "boot"); - return ret; + return 0; } static __maybe_unused struct of_device_id pinctrl_tegra30_dt_ids[] = { -- cgit v1.2.3 From c3b08ad1c611d0632a6515806dfdb20f7c27cdf1 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sun, 2 Nov 2014 21:13:47 +0100 Subject: arm: dts: jetson-tk1: switch to upstream DT Almost everything is upstream now, so no need to keep our private copy of the DT. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/dts/tegra124-jetson-tk1.dts | 1823 +--------------------------------- 1 file changed, 1 insertion(+), 1822 deletions(-) diff --git a/arch/arm/dts/tegra124-jetson-tk1.dts b/arch/arm/dts/tegra124-jetson-tk1.dts index 32e41f9074..d2933bdc4f 100644 --- a/arch/arm/dts/tegra124-jetson-tk1.dts +++ b/arch/arm/dts/tegra124-jetson-tk1.dts @@ -1,17 +1,6 @@ -/dts-v1/; - -#include -#include "tegra124.dtsi" +#include / { - model = "NVIDIA Tegra124 Jetson TK1"; - compatible = "nvidia,jetson-tk1", "nvidia,tegra124"; - - aliases { - rtc0 = "/i2c@0,7000d000/pmic@40"; - rtc1 = "/rtc@0,7000e000"; - }; - chosen { environment@0 { compatible = "barebox,environment"; @@ -19,1817 +8,7 @@ }; }; - memory { - reg = <0x0 0x80000000 0x0 0x80000000>; - }; - - host1x@0,50000000 { - hdmi@0,54280000 { - status = "okay"; - - hdmi-supply = <&vdd_5v0_hdmi>; - pll-supply = <&vdd_hdmi_pll>; - vdd-supply = <&vdd_3v3_hdmi>; - - nvidia,ddc-i2c-bus = <&hdmi_ddc>; - nvidia,hpd-gpio = - <&gpio TEGRA_GPIO(N, 7) GPIO_ACTIVE_HIGH>; - }; - }; - - pinmux: pinmux@0,70000868 { - pinctrl-names = "default"; - pinctrl-0 = <&state_default>; - - state_default: pinmux { - clk_32k_out_pa0 { - nvidia,pins = "clk_32k_out_pa0"; - nvidia,function = "soc"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - uart3_cts_n_pa1 { - nvidia,pins = "uart3_cts_n_pa1"; - nvidia,function = "uartc"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - dap2_fs_pa2 { - nvidia,pins = "dap2_fs_pa2"; - nvidia,function = "i2s1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - dap2_sclk_pa3 { - nvidia,pins = "dap2_sclk_pa3"; - nvidia,function = "i2s1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - dap2_din_pa4 { - nvidia,pins = "dap2_din_pa4"; - nvidia,function = "i2s1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - dap2_dout_pa5 { - nvidia,pins = "dap2_dout_pa5"; - nvidia,function = "i2s1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc3_clk_pa6 { - nvidia,pins = "sdmmc3_clk_pa6"; - nvidia,function = "sdmmc3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc3_cmd_pa7 { - nvidia,pins = "sdmmc3_cmd_pa7"; - nvidia,function = "sdmmc3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pb0 { - nvidia,pins = "pb0"; - nvidia,function = "uartd"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pb1 { - nvidia,pins = "pb1"; - nvidia,function = "uartd"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc3_dat3_pb4 { - nvidia,pins = "sdmmc3_dat3_pb4"; - nvidia,function = "sdmmc3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc3_dat2_pb5 { - nvidia,pins = "sdmmc3_dat2_pb5"; - nvidia,function = "sdmmc3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc3_dat1_pb6 { - nvidia,pins = "sdmmc3_dat1_pb6"; - nvidia,function = "sdmmc3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc3_dat0_pb7 { - nvidia,pins = "sdmmc3_dat0_pb7"; - nvidia,function = "sdmmc3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - uart3_rts_n_pc0 { - nvidia,pins = "uart3_rts_n_pc0"; - nvidia,function = "uartc"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - uart2_txd_pc2 { - nvidia,pins = "uart2_txd_pc2"; - nvidia,function = "irda"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - uart2_rxd_pc3 { - nvidia,pins = "uart2_rxd_pc3"; - nvidia,function = "irda"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - gen1_i2c_scl_pc4 { - nvidia,pins = "gen1_i2c_scl_pc4"; - nvidia,function = "i2c1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - nvidia,open-drain = ; - }; - gen1_i2c_sda_pc5 { - nvidia,pins = "gen1_i2c_sda_pc5"; - nvidia,function = "i2c1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - nvidia,open-drain = ; - }; - pc7 { - nvidia,pins = "pc7"; - nvidia,function = "rsvd1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pg0 { - nvidia,pins = "pg0"; - nvidia,function = "rsvd1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pg1 { - nvidia,pins = "pg1"; - nvidia,function = "rsvd1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pg2 { - nvidia,pins = "pg2"; - nvidia,function = "rsvd1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pg3 { - nvidia,pins = "pg3"; - nvidia,function = "rsvd1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pg4 { - nvidia,pins = "pg4"; - nvidia,function = "spi4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pg5 { - nvidia,pins = "pg5"; - nvidia,function = "spi4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pg6 { - nvidia,pins = "pg6"; - nvidia,function = "spi4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pg7 { - nvidia,pins = "pg7"; - nvidia,function = "spi4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - ph0 { - nvidia,pins = "ph0"; - nvidia,function = "gmi"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - ph1 { - nvidia,pins = "ph1"; - nvidia,function = "pwm1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - ph2 { - nvidia,pins = "ph2"; - nvidia,function = "gmi"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - ph3 { - nvidia,pins = "ph3"; - nvidia,function = "gmi"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - ph4 { - nvidia,pins = "ph4"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - ph5 { - nvidia,pins = "ph5"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - ph6 { - nvidia,pins = "ph6"; - nvidia,function = "gmi"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - ph7 { - nvidia,pins = "ph7"; - nvidia,function = "gmi"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pi0 { - nvidia,pins = "pi0"; - nvidia,function = "rsvd1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pi1 { - nvidia,pins = "pi1"; - nvidia,function = "rsvd1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pi2 { - nvidia,pins = "pi2"; - nvidia,function = "rsvd4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pi3 { - nvidia,pins = "pi3"; - nvidia,function = "spi4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pi4 { - nvidia,pins = "pi4"; - nvidia,function = "gmi"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pi5 { - nvidia,pins = "pi5"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pi6 { - nvidia,pins = "pi6"; - nvidia,function = "rsvd1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pi7 { - nvidia,pins = "pi7"; - nvidia,function = "rsvd1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pj0 { - nvidia,pins = "pj0"; - nvidia,function = "rsvd1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pj2 { - nvidia,pins = "pj2"; - nvidia,function = "rsvd1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - uart2_cts_n_pj5 { - nvidia,pins = "uart2_cts_n_pj5"; - nvidia,function = "uartb"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - uart2_rts_n_pj6 { - nvidia,pins = "uart2_rts_n_pj6"; - nvidia,function = "uartb"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pj7 { - nvidia,pins = "pj7"; - nvidia,function = "uartd"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pk0 { - nvidia,pins = "pk0"; - nvidia,function = "soc"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pk1 { - nvidia,pins = "pk1"; - nvidia,function = "rsvd4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pk2 { - nvidia,pins = "pk2"; - nvidia,function = "rsvd1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pk3 { - nvidia,pins = "pk3"; - nvidia,function = "gmi"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pk4 { - nvidia,pins = "pk4"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - spdif_out_pk5 { - nvidia,pins = "spdif_out_pk5"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - spdif_in_pk6 { - nvidia,pins = "spdif_in_pk6"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pk7 { - nvidia,pins = "pk7"; - nvidia,function = "uartd"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - dap1_fs_pn0 { - nvidia,pins = "dap1_fs_pn0"; - nvidia,function = "i2s0"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - dap1_din_pn1 { - nvidia,pins = "dap1_din_pn1"; - nvidia,function = "i2s0"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - dap1_dout_pn2 { - nvidia,pins = "dap1_dout_pn2"; - nvidia,function = "sata"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - dap1_sclk_pn3 { - nvidia,pins = "dap1_sclk_pn3"; - nvidia,function = "i2s0"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - usb_vbus_en0_pn4 { - nvidia,pins = "usb_vbus_en0_pn4"; - nvidia,function = "usb"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - nvidia,open-drain = ; - }; - usb_vbus_en1_pn5 { - nvidia,pins = "usb_vbus_en1_pn5"; - nvidia,function = "usb"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - nvidia,open-drain = ; - }; - hdmi_int_pn7 { - nvidia,pins = "hdmi_int_pn7"; - nvidia,function = "rsvd1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - nvidia,rcv-sel = ; - }; - ulpi_data7_po0 { - nvidia,pins = "ulpi_data7_po0"; - nvidia,function = "ulpi"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - ulpi_data0_po1 { - nvidia,pins = "ulpi_data0_po1"; - nvidia,function = "ulpi"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - ulpi_data1_po2 { - nvidia,pins = "ulpi_data1_po2"; - nvidia,function = "ulpi"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - ulpi_data2_po3 { - nvidia,pins = "ulpi_data2_po3"; - nvidia,function = "ulpi"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - ulpi_data3_po4 { - nvidia,pins = "ulpi_data3_po4"; - nvidia,function = "ulpi"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - ulpi_data4_po5 { - nvidia,pins = "ulpi_data4_po5"; - nvidia,function = "ulpi"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - ulpi_data5_po6 { - nvidia,pins = "ulpi_data5_po6"; - nvidia,function = "ulpi"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - ulpi_data6_po7 { - nvidia,pins = "ulpi_data6_po7"; - nvidia,function = "ulpi"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - dap3_fs_pp0 { - nvidia,pins = "dap3_fs_pp0"; - nvidia,function = "i2s2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - dap3_din_pp1 { - nvidia,pins = "dap3_din_pp1"; - nvidia,function = "i2s2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - dap3_dout_pp2 { - nvidia,pins = "dap3_dout_pp2"; - nvidia,function = "rsvd4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - dap3_sclk_pp3 { - nvidia,pins = "dap3_sclk_pp3"; - nvidia,function = "rsvd3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - dap4_fs_pp4 { - nvidia,pins = "dap4_fs_pp4"; - nvidia,function = "i2s3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - dap4_din_pp5 { - nvidia,pins = "dap4_din_pp5"; - nvidia,function = "i2s3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - dap4_dout_pp6 { - nvidia,pins = "dap4_dout_pp6"; - nvidia,function = "i2s3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - dap4_sclk_pp7 { - nvidia,pins = "dap4_sclk_pp7"; - nvidia,function = "i2s3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_col0_pq0 { - nvidia,pins = "kb_col0_pq0"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_col1_pq1 { - nvidia,pins = "kb_col1_pq1"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_col2_pq2 { - nvidia,pins = "kb_col2_pq2"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_col3_pq3 { - nvidia,pins = "kb_col3_pq3"; - nvidia,function = "kbc"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_col4_pq4 { - nvidia,pins = "kb_col4_pq4"; - nvidia,function = "sdmmc3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_col5_pq5 { - nvidia,pins = "kb_col5_pq5"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_col6_pq6 { - nvidia,pins = "kb_col6_pq6"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_col7_pq7 { - nvidia,pins = "kb_col7_pq7"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_row0_pr0 { - nvidia,pins = "kb_row0_pr0"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_row1_pr1 { - nvidia,pins = "kb_row1_pr1"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_row2_pr2 { - nvidia,pins = "kb_row2_pr2"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_row3_pr3 { - nvidia,pins = "kb_row3_pr3"; - nvidia,function = "sys"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_row4_pr4 { - nvidia,pins = "kb_row4_pr4"; - nvidia,function = "rsvd3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_row5_pr5 { - nvidia,pins = "kb_row5_pr5"; - nvidia,function = "rsvd3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_row6_pr6 { - nvidia,pins = "kb_row6_pr6"; - nvidia,function = "displaya_alt"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_row7_pr7 { - nvidia,pins = "kb_row7_pr7"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_row8_ps0 { - nvidia,pins = "kb_row8_ps0"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_row9_ps1 { - nvidia,pins = "kb_row9_ps1"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_row10_ps2 { - nvidia,pins = "kb_row10_ps2"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_row11_ps3 { - nvidia,pins = "kb_row11_ps3"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_row12_ps4 { - nvidia,pins = "kb_row12_ps4"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_row13_ps5 { - nvidia,pins = "kb_row13_ps5"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_row14_ps6 { - nvidia,pins = "kb_row14_ps6"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_row15_ps7 { - nvidia,pins = "kb_row15_ps7"; - nvidia,function = "soc"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_row16_pt0 { - nvidia,pins = "kb_row16_pt0"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - kb_row17_pt1 { - nvidia,pins = "kb_row17_pt1"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - gen2_i2c_scl_pt5 { - nvidia,pins = "gen2_i2c_scl_pt5"; - nvidia,function = "i2c2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - nvidia,open-drain = ; - }; - gen2_i2c_sda_pt6 { - nvidia,pins = "gen2_i2c_sda_pt6"; - nvidia,function = "i2c2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - nvidia,open-drain = ; - }; - sdmmc4_cmd_pt7 { - nvidia,pins = "sdmmc4_cmd_pt7"; - nvidia,function = "sdmmc4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pu0 { - nvidia,pins = "pu0"; - nvidia,function = "rsvd4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pu1 { - nvidia,pins = "pu1"; - nvidia,function = "rsvd1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pu2 { - nvidia,pins = "pu2"; - nvidia,function = "rsvd1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pu3 { - nvidia,pins = "pu3"; - nvidia,function = "gmi"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pu4 { - nvidia,pins = "pu4"; - nvidia,function = "gmi"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pu5 { - nvidia,pins = "pu5"; - nvidia,function = "gmi"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pu6 { - nvidia,pins = "pu6"; - nvidia,function = "rsvd3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pv0 { - nvidia,pins = "pv0"; - nvidia,function = "rsvd1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pv1 { - nvidia,pins = "pv1"; - nvidia,function = "rsvd1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc3_cd_n_pv2 { - nvidia,pins = "sdmmc3_cd_n_pv2"; - nvidia,function = "sdmmc3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc1_wp_n_pv3 { - nvidia,pins = "sdmmc1_wp_n_pv3"; - nvidia,function = "sdmmc1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - ddc_scl_pv4 { - nvidia,pins = "ddc_scl_pv4"; - nvidia,function = "i2c4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - nvidia,rcv-sel = ; - }; - ddc_sda_pv5 { - nvidia,pins = "ddc_sda_pv5"; - nvidia,function = "i2c4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - nvidia,rcv-sel = ; - }; - gpio_w2_aud_pw2 { - nvidia,pins = "gpio_w2_aud_pw2"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - gpio_w3_aud_pw3 { - nvidia,pins = "gpio_w3_aud_pw3"; - nvidia,function = "spi6"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - dap_mclk1_pw4 { - nvidia,pins = "dap_mclk1_pw4"; - nvidia,function = "extperiph1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - clk2_out_pw5 { - nvidia,pins = "clk2_out_pw5"; - nvidia,function = "extperiph2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - uart3_txd_pw6 { - nvidia,pins = "uart3_txd_pw6"; - nvidia,function = "uartc"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - uart3_rxd_pw7 { - nvidia,pins = "uart3_rxd_pw7"; - nvidia,function = "uartc"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - dvfs_pwm_px0 { - nvidia,pins = "dvfs_pwm_px0"; - nvidia,function = "cldvfs"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - gpio_x1_aud_px1 { - nvidia,pins = "gpio_x1_aud_px1"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - dvfs_clk_px2 { - nvidia,pins = "dvfs_clk_px2"; - nvidia,function = "cldvfs"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - gpio_x3_aud_px3 { - nvidia,pins = "gpio_x3_aud_px3"; - nvidia,function = "rsvd4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - gpio_x4_aud_px4 { - nvidia,pins = "gpio_x4_aud_px4"; - nvidia,function = "gmi"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - gpio_x5_aud_px5 { - nvidia,pins = "gpio_x5_aud_px5"; - nvidia,function = "rsvd4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - gpio_x6_aud_px6 { - nvidia,pins = "gpio_x6_aud_px6"; - nvidia,function = "gmi"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - gpio_x7_aud_px7 { - nvidia,pins = "gpio_x7_aud_px7"; - nvidia,function = "rsvd1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - ulpi_clk_py0 { - nvidia,pins = "ulpi_clk_py0"; - nvidia,function = "spi1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - ulpi_dir_py1 { - nvidia,pins = "ulpi_dir_py1"; - nvidia,function = "spi1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - ulpi_nxt_py2 { - nvidia,pins = "ulpi_nxt_py2"; - nvidia,function = "spi1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - ulpi_stp_py3 { - nvidia,pins = "ulpi_stp_py3"; - nvidia,function = "spi1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc1_dat3_py4 { - nvidia,pins = "sdmmc1_dat3_py4"; - nvidia,function = "sdmmc1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc1_dat2_py5 { - nvidia,pins = "sdmmc1_dat2_py5"; - nvidia,function = "sdmmc1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc1_dat1_py6 { - nvidia,pins = "sdmmc1_dat1_py6"; - nvidia,function = "sdmmc1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc1_dat0_py7 { - nvidia,pins = "sdmmc1_dat0_py7"; - nvidia,function = "sdmmc1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc1_clk_pz0 { - nvidia,pins = "sdmmc1_clk_pz0"; - nvidia,function = "sdmmc1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc1_cmd_pz1 { - nvidia,pins = "sdmmc1_cmd_pz1"; - nvidia,function = "sdmmc1"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pwr_i2c_scl_pz6 { - nvidia,pins = "pwr_i2c_scl_pz6"; - nvidia,function = "i2cpwr"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - nvidia,open-drain = ; - }; - pwr_i2c_sda_pz7 { - nvidia,pins = "pwr_i2c_sda_pz7"; - nvidia,function = "i2cpwr"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - nvidia,open-drain = ; - }; - sdmmc4_dat0_paa0 { - nvidia,pins = "sdmmc4_dat0_paa0"; - nvidia,function = "sdmmc4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc4_dat1_paa1 { - nvidia,pins = "sdmmc4_dat1_paa1"; - nvidia,function = "sdmmc4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc4_dat2_paa2 { - nvidia,pins = "sdmmc4_dat2_paa2"; - nvidia,function = "sdmmc4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc4_dat3_paa3 { - nvidia,pins = "sdmmc4_dat3_paa3"; - nvidia,function = "sdmmc4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc4_dat4_paa4 { - nvidia,pins = "sdmmc4_dat4_paa4"; - nvidia,function = "sdmmc4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc4_dat5_paa5 { - nvidia,pins = "sdmmc4_dat5_paa5"; - nvidia,function = "sdmmc4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc4_dat6_paa6 { - nvidia,pins = "sdmmc4_dat6_paa6"; - nvidia,function = "sdmmc4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc4_dat7_paa7 { - nvidia,pins = "sdmmc4_dat7_paa7"; - nvidia,function = "sdmmc4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pbb0 { - nvidia,pins = "pbb0"; - nvidia,function = "vimclk2_alt"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - cam_i2c_scl_pbb1 { - nvidia,pins = "cam_i2c_scl_pbb1"; - nvidia,function = "i2c3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - nvidia,open-drain = ; - }; - cam_i2c_sda_pbb2 { - nvidia,pins = "cam_i2c_sda_pbb2"; - nvidia,function = "i2c3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - nvidia,open-drain = ; - }; - pbb3 { - nvidia,pins = "pbb3"; - nvidia,function = "vgp3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pbb4 { - nvidia,pins = "pbb4"; - nvidia,function = "vgp4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pbb5 { - nvidia,pins = "pbb5"; - nvidia,function = "rsvd3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pbb6 { - nvidia,pins = "pbb6"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pbb7 { - nvidia,pins = "pbb7"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - cam_mclk_pcc0 { - nvidia,pins = "cam_mclk_pcc0"; - nvidia,function = "vi_alt3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pcc1 { - nvidia,pins = "pcc1"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pcc2 { - nvidia,pins = "pcc2"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc4_clk_pcc4 { - nvidia,pins = "sdmmc4_clk_pcc4"; - nvidia,function = "sdmmc4"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - clk2_req_pcc5 { - nvidia,pins = "clk2_req_pcc5"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - clk3_out_pee0 { - nvidia,pins = "clk3_out_pee0"; - nvidia,function = "extperiph3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - clk3_req_pee1 { - nvidia,pins = "clk3_req_pee1"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - dap_mclk1_req_pee2 { - nvidia,pins = "dap_mclk1_req_pee2"; - nvidia,function = "sata"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - hdmi_cec_pee3 { - nvidia,pins = "hdmi_cec_pee3"; - nvidia,function = "cec"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - nvidia,open-drain = ; - }; - sdmmc3_clk_lb_out_pee4 { - nvidia,pins = "sdmmc3_clk_lb_out_pee4"; - nvidia,function = "sdmmc3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - sdmmc3_clk_lb_in_pee5 { - nvidia,pins = "sdmmc3_clk_lb_in_pee5"; - nvidia,function = "sdmmc3"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - dp_hpd_pff0 { - nvidia,pins = "dp_hpd_pff0"; - nvidia,function = "dp"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - usb_vbus_en2_pff1 { - nvidia,pins = "usb_vbus_en2_pff1"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - nvidia,open-drain = ; - }; - pff2 { - nvidia,pins = "pff2"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - nvidia,open-drain = ; - }; - core_pwr_req { - nvidia,pins = "core_pwr_req"; - nvidia,function = "pwron"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - cpu_pwr_req { - nvidia,pins = "cpu_pwr_req"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - pwr_int_n { - nvidia,pins = "pwr_int_n"; - nvidia,function = "pmi"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - reset_out_n { - nvidia,pins = "reset_out_n"; - nvidia,function = "reset_out_n"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - owr { - nvidia,pins = "owr"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - nvidia,rcv-sel = ; - }; - clk_32k_in { - nvidia,pins = "clk_32k_in"; - nvidia,function = "rsvd2"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - jtag_rtck { - nvidia,pins = "jtag_rtck"; - nvidia,function = "rtck"; - nvidia,pull = ; - nvidia,tristate = ; - nvidia,enable-input = ; - }; - }; - }; - - /* DB9 serial port */ - serial@0,70006300 { - status = "okay"; - }; - - /* Expansion GEN1_I2C_*, mini-PCIe I2C, on-board components */ - i2c@0,7000c000 { - status = "okay"; - clock-frequency = <100000>; - - rt5639: audio-codec@1c { - compatible = "realtek,rt5639"; - reg = <0x1c>; - interrupt-parent = <&gpio>; - interrupts = ; - realtek,ldo1-en-gpios = - <&gpio TEGRA_GPIO(R, 2) GPIO_ACTIVE_HIGH>; - }; - - temperature-sensor@4c { - compatible = "ti,tmp451"; - reg = <0x4c>; - interrupt-parent = <&gpio>; - interrupts = ; - }; - - eeprom@56 { - compatible = "atmel,24c02"; - reg = <0x56>; - pagesize = <8>; - }; - }; - - /* Expansion GEN2_I2C_* */ - i2c@0,7000c400 { - status = "okay"; - clock-frequency = <100000>; - }; - - /* Expansion CAM_I2C_* */ - i2c@0,7000c500 { - status = "okay"; - clock-frequency = <100000>; - }; - - /* HDMI DDC */ - hdmi_ddc: i2c@0,7000c700 { - status = "okay"; - clock-frequency = <100000>; - }; - - /* Expansion PWR_I2C_*, on-board components */ - i2c@0,7000d000 { - status = "okay"; - clock-frequency = <400000>; - - pmic: pmic@40 { - compatible = "ams,as3722"; - reg = <0x40>; - interrupts = <0 86 IRQ_TYPE_LEVEL_HIGH>; - - ams,system-power-controller; - - #interrupt-cells = <2>; - interrupt-controller; - - gpio-controller; - #gpio-cells = <2>; - - pinctrl-names = "default"; - pinctrl-0 = <&as3722_default>; - - as3722_default: pinmux { - gpio0 { - pins = "gpio0"; - function = "gpio"; - bias-pull-down; - }; - - gpio1_2_4_7 { - pins = "gpio1", "gpio2", "gpio4", "gpio7"; - function = "gpio"; - bias-pull-up; - }; - - gpio3_5_6 { - pins = "gpio3", "gpio5", "gpio6"; - bias-high-impedance; - }; - }; - - regulators { - vsup-sd2-supply = <&vdd_5v0_sys>; - vsup-sd3-supply = <&vdd_5v0_sys>; - vsup-sd4-supply = <&vdd_5v0_sys>; - vsup-sd5-supply = <&vdd_5v0_sys>; - vin-ldo0-supply = <&vdd_1v35_lp0>; - vin-ldo1-6-supply = <&vdd_3v3_run>; - vin-ldo2-5-7-supply = <&vddio_1v8>; - vin-ldo3-4-supply = <&vdd_3v3_sys>; - vin-ldo9-10-supply = <&vdd_5v0_sys>; - vin-ldo11-supply = <&vdd_3v3_run>; - - sd0 { - regulator-name = "+VDD_CPU_AP"; - regulator-min-microvolt = <700000>; - regulator-max-microvolt = <1400000>; - regulator-min-microamp = <3500000>; - regulator-max-microamp = <3500000>; - regulator-always-on; - regulator-boot-on; - ams,external-control = <2>; - }; - - sd1 { - regulator-name = "+VDD_CORE"; - regulator-min-microvolt = <700000>; - regulator-max-microvolt = <1350000>; - regulator-min-microamp = <2500000>; - regulator-max-microamp = <2500000>; - regulator-always-on; - regulator-boot-on; - ams,external-control = <1>; - }; - - vdd_1v35_lp0: sd2 { - regulator-name = "+1.35V_LP0(sd2)"; - regulator-min-microvolt = <1350000>; - regulator-max-microvolt = <1350000>; - regulator-always-on; - regulator-boot-on; - }; - - sd3 { - regulator-name = "+1.35V_LP0(sd3)"; - regulator-min-microvolt = <1350000>; - regulator-max-microvolt = <1350000>; - regulator-always-on; - regulator-boot-on; - }; - - vdd_1v05_run: sd4 { - regulator-name = "+1.05V_RUN"; - regulator-min-microvolt = <1050000>; - regulator-max-microvolt = <1050000>; - }; - - vddio_1v8: sd5 { - regulator-name = "+1.8V_VDDIO"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-boot-on; - regulator-always-on; - }; - - sd6 { - regulator-name = "+VDD_GPU_AP"; - regulator-min-microvolt = <650000>; - regulator-max-microvolt = <1200000>; - regulator-min-microamp = <3500000>; - regulator-max-microamp = <3500000>; - regulator-boot-on; - regulator-always-on; - }; - - ldo0 { - regulator-name = "+1.05V_RUN_AVDD"; - regulator-min-microvolt = <1050000>; - regulator-max-microvolt = <1050000>; - regulator-boot-on; - regulator-always-on; - ams,external-control = <1>; - }; - - ldo1 { - regulator-name = "+1.8V_RUN_CAM"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - }; - - ldo2 { - regulator-name = "+1.2V_GEN_AVDD"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - regulator-boot-on; - regulator-always-on; - }; - - ldo3 { - regulator-name = "+1.05V_LP0_VDD_RTC"; - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1000000>; - regulator-boot-on; - regulator-always-on; - ams,enable-tracking; - }; - - ldo4 { - regulator-name = "+2.8V_RUN_CAM"; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <2800000>; - }; - - ldo5 { - regulator-name = "+1.2V_RUN_CAM_FRONT"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - }; - - vddio_sdmmc3: ldo6 { - regulator-name = "+VDDIO_SDMMC3"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3300000>; - }; - - ldo7 { - regulator-name = "+1.05V_RUN_CAM_REAR"; - regulator-min-microvolt = <1050000>; - regulator-max-microvolt = <1050000>; - }; - - ldo9 { - regulator-name = "+3.3V_RUN_TOUCH"; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <2800000>; - }; - - ldo10 { - regulator-name = "+2.8V_RUN_CAM_AF"; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <2800000>; - }; - - ldo11 { - regulator-name = "+1.8V_RUN_VPP_FUSE"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - }; - }; - }; - }; - - /* Expansion TS_SPI_* */ - spi@0,7000d400 { - status = "okay"; - }; - - /* Internal SPI */ - spi@0,7000da00 { - status = "okay"; - spi-max-frequency = <25000000>; - spi-flash@0 { - compatible = "winbond,w25q32dw"; - reg = <0>; - spi-max-frequency = <20000000>; - }; - }; - - pmc@0,7000e400 { - nvidia,invert-interrupt; - nvidia,suspend-mode = <1>; - nvidia,cpu-pwr-good-time = <500>; - nvidia,cpu-pwr-off-time = <300>; - nvidia,core-pwr-good-time = <641 3845>; - nvidia,core-pwr-off-time = <61036>; - nvidia,core-power-req-active-high; - nvidia,sys-clock-req-active-high; - }; - - /* SD card */ - sdhci@0,700b0400 { - status = "okay"; - cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_LOW>; - power-gpios = <&gpio TEGRA_GPIO(R, 0) GPIO_ACTIVE_HIGH>; - wp-gpios = <&gpio TEGRA_GPIO(Q, 4) GPIO_ACTIVE_HIGH>; - bus-width = <4>; - vqmmc-supply = <&vddio_sdmmc3>; - }; - /* eMMC */ emmc: sdhci@0,700b0600 { - status = "okay"; - bus-width = <8>; - non-removable; - }; - - ahub@0,70300000 { - i2s@0,70301100 { - status = "okay"; - }; - }; - - /* mini-PCIe USB */ - usb@0,7d004000 { - status = "okay"; - }; - - usb-phy@0,7d004000 { - status = "okay"; - }; - - /* USB A connector */ - usb@0,7d008000 { - status = "okay"; - }; - - usb-phy@0,7d008000 { - status = "okay"; - vbus-supply = <&vdd_usb3_vbus>; - }; - - clocks { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <0>; - - clk32k_in: clock@0 { - compatible = "fixed-clock"; - reg = <0>; - #clock-cells = <0>; - clock-frequency = <32768>; - }; - }; - - gpio-keys { - compatible = "gpio-keys"; - - power { - label = "Power"; - gpios = <&gpio TEGRA_GPIO(Q, 0) GPIO_ACTIVE_LOW>; - linux,code = ; - debounce-interval = <10>; - gpio-key,wakeup; - }; - }; - - regulators { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <0>; - - vdd_mux: regulator@0 { - compatible = "regulator-fixed"; - reg = <0>; - regulator-name = "+VDD_MUX"; - regulator-min-microvolt = <12000000>; - regulator-max-microvolt = <12000000>; - regulator-always-on; - regulator-boot-on; - }; - - vdd_5v0_sys: regulator@1 { - compatible = "regulator-fixed"; - reg = <1>; - regulator-name = "+5V_SYS"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - regulator-always-on; - regulator-boot-on; - vin-supply = <&vdd_mux>; - }; - - vdd_3v3_sys: regulator@2 { - compatible = "regulator-fixed"; - reg = <2>; - regulator-name = "+3.3V_SYS"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - regulator-boot-on; - vin-supply = <&vdd_mux>; - }; - - vdd_3v3_run: regulator@3 { - compatible = "regulator-fixed"; - reg = <3>; - regulator-name = "+3.3V_RUN"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - regulator-boot-on; - gpio = <&pmic 1 GPIO_ACTIVE_HIGH>; - enable-active-high; - vin-supply = <&vdd_3v3_sys>; - }; - - vdd_3v3_hdmi: regulator@4 { - compatible = "regulator-fixed"; - reg = <4>; - regulator-name = "+3.3V_AVDD_HDMI_AP_GATED"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - vin-supply = <&vdd_3v3_run>; - }; - - vdd_usb1_vbus: regulator@7 { - compatible = "regulator-fixed"; - reg = <7>; - regulator-name = "+USB0_VBUS_SW"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - gpio = <&gpio TEGRA_GPIO(N, 4) GPIO_ACTIVE_HIGH>; - enable-active-high; - gpio-open-drain; - vin-supply = <&vdd_5v0_sys>; - }; - - vdd_usb3_vbus: regulator@8 { - compatible = "regulator-fixed"; - reg = <8>; - regulator-name = "+5V_USB_HS"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - gpio = <&gpio TEGRA_GPIO(N, 5) GPIO_ACTIVE_HIGH>; - enable-active-high; - gpio-open-drain; - vin-supply = <&vdd_5v0_sys>; - }; - - vdd_3v3_lp0: regulator@10 { - compatible = "regulator-fixed"; - reg = <10>; - regulator-name = "+3.3V_LP0"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - regulator-boot-on; - gpio = <&pmic 2 GPIO_ACTIVE_HIGH>; - enable-active-high; - vin-supply = <&vdd_3v3_sys>; - }; - - vdd_hdmi_pll: regulator@11 { - compatible = "regulator-fixed"; - reg = <11>; - regulator-name = "+1.05V_RUN_AVDD_HDMI_PLL"; - regulator-min-microvolt = <1050000>; - regulator-max-microvolt = <1050000>; - gpio = <&gpio TEGRA_GPIO(H, 7) GPIO_ACTIVE_LOW>; - vin-supply = <&vdd_1v05_run>; - }; - - vdd_5v0_hdmi: regulator@12 { - compatible = "regulator-fixed"; - reg = <12>; - regulator-name = "+5V_HDMI_CON"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - gpio = <&gpio TEGRA_GPIO(K, 6) GPIO_ACTIVE_HIGH>; - enable-active-high; - vin-supply = <&vdd_5v0_sys>; - }; - }; - - sound { - compatible = "nvidia,tegra-audio-rt5640-jetson-tk1", - "nvidia,tegra-audio-rt5640"; - nvidia,model = "NVIDIA Tegra Jetson TK1"; - - nvidia,audio-routing = - "Headphones", "HPOR", - "Headphones", "HPOL", - "Mic Jack", "MICBIAS1", - "IN2P", "Mic Jack"; - - nvidia,i2s-controller = <&tegra_i2s1>; - nvidia,audio-codec = <&rt5639>; - - nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(R, 7) GPIO_ACTIVE_LOW>; - - clocks = <&tegra_car TEGRA124_CLK_PLL_A>, - <&tegra_car TEGRA124_CLK_PLL_A_OUT0>, - <&tegra_car TEGRA124_CLK_EXTERN1>; - clock-names = "pll_a", "pll_a_out0", "mclk"; }; }; -- cgit v1.2.3 From 3e41e7561a1b3636140214d92401c10e15962d22 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sun, 2 Nov 2014 21:13:48 +0100 Subject: clk: tegra: slow down MSELECT to 102MHz Don't know where I got the 204MHZ previously, but 102MHz is the official supported maximum. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/clk/tegra/clk-tegra124.c | 2 +- drivers/clk/tegra/clk-tegra30.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index 7426b52aac..d597a239b9 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -321,7 +321,7 @@ static struct tegra_clk_init_table init_table[] = { {TEGRA124_CLK_PLL_P_OUT2, TEGRA124_CLK_CLK_MAX, 48000000, 1}, {TEGRA124_CLK_PLL_P_OUT3, TEGRA124_CLK_CLK_MAX, 102000000, 1}, {TEGRA124_CLK_PLL_P_OUT4, TEGRA124_CLK_CLK_MAX, 204000000, 1}, - {TEGRA124_CLK_MSELECT, TEGRA124_CLK_PLL_P, 204000000, 1}, + {TEGRA124_CLK_MSELECT, TEGRA124_CLK_PLL_P, 102000000, 1}, {TEGRA124_CLK_UARTA, TEGRA124_CLK_PLL_P, 0, 1}, {TEGRA124_CLK_UARTB, TEGRA124_CLK_PLL_P, 0, 1}, {TEGRA124_CLK_UARTC, TEGRA124_CLK_PLL_P, 0, 1}, diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index 9997ab9666..7210053e96 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -351,7 +351,7 @@ static struct tegra_clk_init_table init_table[] = { {TEGRA30_CLK_PLL_P_OUT2, TEGRA30_CLK_CLK_MAX, 48000000, 1}, {TEGRA30_CLK_PLL_P_OUT3, TEGRA30_CLK_CLK_MAX, 102000000, 1}, {TEGRA30_CLK_PLL_P_OUT4, TEGRA30_CLK_CLK_MAX, 204000000, 1}, - {TEGRA30_CLK_MSELECT, TEGRA30_CLK_PLL_P, 204000000, 1}, + {TEGRA30_CLK_MSELECT, TEGRA30_CLK_PLL_P, 102000000, 1}, {TEGRA30_CLK_UARTA, TEGRA30_CLK_PLL_P, 0, 1}, {TEGRA30_CLK_UARTB, TEGRA30_CLK_PLL_P, 0, 1}, {TEGRA30_CLK_UARTC, TEGRA30_CLK_PLL_P, 0, 1}, -- cgit v1.2.3 From d712ce182499f06aafff5ee4af7b83cde209da9e Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Sun, 2 Nov 2014 21:13:54 +0100 Subject: pinctrl: tegra: add XUSB pad controller This is a combined pincontrol/PHY driver for the SerDes lanes on Tegra K1. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/pinctrl/Kconfig | 8 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-tegra-xusb.c | 519 +++++++++++++++++++++++++++++++++++ 3 files changed, 528 insertions(+) create mode 100644 drivers/pinctrl/pinctrl-tegra-xusb.c diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 770fb2d414..4cbc167cd0 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -60,6 +60,14 @@ config PINCTRL_TEGRA30 help The pinmux controller found on the Tegra 30+ line of SoCs. +config PINCTRL_TEGRA_XUSB + bool + default y if ARCH_TEGRA_124_SOC + select GENERIC_PHY + help + The pinmux controller found on the Tegra 124 line of SoCs used for + the SerDes lanes. + source drivers/pinctrl/mvebu/Kconfig endif diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 3ea8649efb..724e6d7d06 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -7,5 +7,6 @@ obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o +obj-$(CONFIG_PINCTRL_TEGRA_XUSB) += pinctrl-tegra-xusb.o obj-$(CONFIG_ARCH_MVEBU) += mvebu/ diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c new file mode 100644 index 0000000000..05cdecbabf --- /dev/null +++ b/drivers/pinctrl/pinctrl-tegra-xusb.c @@ -0,0 +1,519 @@ +/* + * Copyright (C) 2014 Lucas Stach + * + * Partly based on code + * Copyright (C) 2014, NVIDIA CORPORATION. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define XUSB_PADCTL_ELPG_PROGRAM 0x01c +#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26) +#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25) +#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24) + +#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040 +#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19) +#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK (0xf << 12) +#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST (1 << 1) + +#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2 0x044 +#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN (1 << 6) +#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5) +#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4) + +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138 +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27) +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24) +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD (1 << 3) +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST (1 << 1) +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ (1 << 0) + +#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1 0x148 +#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1) +#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0) + +struct tegra_xusb_padctl_soc { + const struct tegra_xusb_padctl_lane *lanes; + unsigned int num_lanes; +}; + +struct tegra_xusb_padctl_lane { + const char *name; + + unsigned int offset; + unsigned int shift; + unsigned int mask; + unsigned int iddq; + + const char **funcs; + unsigned int num_funcs; +}; + +struct tegra_xusb_padctl { + struct device_d *dev; + void __iomem *regs; + struct reset_control *rst; + + const struct tegra_xusb_padctl_soc *soc; + struct pinctrl_device pinctrl; + + struct phy_provider *provider; + struct phy *phys[2]; + + unsigned int enable; +}; + +static inline void padctl_writel(struct tegra_xusb_padctl *padctl, u32 value, + unsigned long offset) +{ + writel(value, padctl->regs + offset); +} + +static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl, + unsigned long offset) +{ + return readl(padctl->regs + offset); +} + +static int tegra_xusb_padctl_enable(struct tegra_xusb_padctl *padctl) +{ + u32 value; + + if (padctl->enable++ > 0) + return 0; + + value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); + value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN; + padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); + + udelay(100); + + value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); + value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY; + padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); + + udelay(100); + + value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); + value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN; + padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); + + return 0; +} + +static int tegra_xusb_padctl_disable(struct tegra_xusb_padctl *padctl) +{ + u32 value; + + if (WARN_ON(padctl->enable == 0)) + return 0; + + if (--padctl->enable > 0) + return 0; + + value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); + value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN; + padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); + + udelay(100); + + value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); + value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY; + padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); + + udelay(100); + + value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); + value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN; + padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); + + return 0; +} + +static int tegra_xusb_phy_init(struct phy *phy) +{ + struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); + + return tegra_xusb_padctl_enable(padctl); +} + +static int tegra_xusb_phy_exit(struct phy *phy) +{ + struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); + + return tegra_xusb_padctl_disable(padctl); +} + +static int pcie_phy_power_on(struct phy *phy) +{ + struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); + int err; + u32 value; + + value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); + value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK; + padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); + + value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL2); + value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN | + XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN | + XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL; + padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL2); + + value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); + value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST; + padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); + + err = wait_on_timeout(50 * MSECOND, + padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1) & + XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET); + + return err; +} + +static int pcie_phy_power_off(struct phy *phy) +{ + struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); + u32 value; + + value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); + value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST; + padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); + + return 0; +} + +static const struct phy_ops pcie_phy_ops = { + + .init = tegra_xusb_phy_init, + .exit = tegra_xusb_phy_exit, + .power_on = pcie_phy_power_on, + .power_off = pcie_phy_power_off, +}; + +static int sata_phy_power_on(struct phy *phy) +{ + struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); + int err; + u32 value; + + value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); + value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD; + value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ; + padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); + + value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); + value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD; + value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ; + padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); + + value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); + value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE; + padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); + + value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); + value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST; + padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); + + err = wait_on_timeout(50 * MSECOND, + padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1) & + XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET); + + return err; +} + +static int sata_phy_power_off(struct phy *phy) +{ + struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); + u32 value; + + value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); + value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST; + padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); + + value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); + value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE; + padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); + + value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); + value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD; + value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ; + padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); + + value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); + value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD; + value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ; + padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); + + return 0; +} + +static const struct phy_ops sata_phy_ops = { + + .init = tegra_xusb_phy_init, + .exit = tegra_xusb_phy_exit, + .power_on = sata_phy_power_on, + .power_off = sata_phy_power_off, +}; + +static struct phy *tegra_xusb_padctl_xlate(struct device_d *dev, + struct of_phandle_args *args) +{ + struct tegra_xusb_padctl *padctl = dev->priv; + unsigned int index = args->args[0]; + + if (args->args_count <= 0) + return ERR_PTR(-EINVAL); + + if (index >= ARRAY_SIZE(padctl->phys)) + return ERR_PTR(-EINVAL); + + return padctl->phys[index]; +} + +static int pinctrl_tegra_xusb_set_state(struct pinctrl_device *pdev, + struct device_node *np) +{ + struct tegra_xusb_padctl *padctl = + container_of(pdev, struct tegra_xusb_padctl, pinctrl); + struct device_node *childnode; + int iddq = -1, i, j, k; + const char *lanes, *func = NULL; + const struct tegra_xusb_padctl_lane *lane = NULL; + u32 val; + + /* + * At first look if the node we are pointed at has children, + * which we may want to visit. + */ + list_for_each_entry(childnode, &np->children, parent_list) + pinctrl_tegra_xusb_set_state(pdev, childnode); + + /* read relevant state from devicetree */ + of_property_read_string(np, "nvidia,function", &func); + of_property_read_u32_array(np, "nvidia,iddq", &iddq, 1); + + /* iterate over all lanes referenced in the dt node */ + for (i = 0; ; i++) { + if (of_property_read_string_index(np, "nvidia,lanes", i, &lanes)) + break; + + for (j = 0; j < padctl->soc->num_lanes; j++) { + if (!strcmp(lanes, padctl->soc->lanes[j].name)) { + lane = &padctl->soc->lanes[j]; + break; + } + } + /* if no matching lane is found */ + if (j == padctl->soc->num_lanes) { + /* nothing matching found, warn and bail out */ + dev_warn(padctl->pinctrl.dev, + "invalid lane %s referenced in node %s\n", + lanes, np->name); + continue; + } + + if (func) { + for (k = 0; k < lane->num_funcs; k++) { + if (!strcmp(func, lane->funcs[k])) + break; + } + if (k < lane->num_funcs) { + val = padctl_readl(padctl, lane->offset); + val &= ~(lane->mask << lane->shift); + val |= k << lane->shift; + padctl_writel(padctl, val, lane->offset); + } else { + dev_warn(padctl->pinctrl.dev, + "invalid function %s for lane %s in node %s\n", + func, lane->name, np->name); + } + } + + if (iddq >= 0) { + if (lane->iddq) { + val = padctl_readl(padctl, lane->offset); + if (iddq) + val &= ~BIT(lane->iddq); + else + val |= BIT(lane->iddq); + padctl_writel(padctl, val, lane->offset); + } else { + dev_warn(padctl->pinctrl.dev, + "invalid iddq setting for lane %s in node %s\n", + lane->name, np->name); + } + } + } + + return 0; +} + +static struct pinctrl_ops pinctrl_tegra_xusb_ops = { + .set_state = pinctrl_tegra_xusb_set_state, +}; + +static int pinctrl_tegra_xusb_probe(struct device_d *dev) +{ + struct tegra_xusb_padctl *padctl; + struct phy *phy; + int err; + + padctl = xzalloc(sizeof(*padctl)); + + dev->priv = padctl; + padctl->dev = dev; + + dev_get_drvdata(dev, (unsigned long *)&padctl->soc); + + padctl->regs = dev_request_mem_region(dev, 0); + if (IS_ERR(padctl->regs)) { + dev_err(dev, "Could not get iomem region\n"); + return PTR_ERR(padctl->regs); + } + + padctl->rst = reset_control_get(dev, NULL); + if (IS_ERR(padctl->rst)) + return PTR_ERR(padctl->rst); + + err = reset_control_deassert(padctl->rst); + if (err < 0) + return err; + + padctl->pinctrl.dev = dev; + padctl->pinctrl.ops = &pinctrl_tegra_xusb_ops; + + err = pinctrl_register(&padctl->pinctrl); + if (err) { + dev_err(dev, "failed to register pincontrol\n"); + err = -ENODEV; + goto reset; + } + + phy = phy_create(dev, NULL, &pcie_phy_ops, NULL); + if (IS_ERR(phy)) { + err = PTR_ERR(phy); + goto unregister; + } + + padctl->phys[TEGRA_XUSB_PADCTL_PCIE] = phy; + phy_set_drvdata(phy, padctl); + + phy = phy_create(dev, NULL, &sata_phy_ops, NULL); + if (IS_ERR(phy)) { + err = PTR_ERR(phy); + goto unregister; + } + + padctl->phys[TEGRA_XUSB_PADCTL_SATA] = phy; + phy_set_drvdata(phy, padctl); + + padctl->provider = of_phy_provider_register(dev, tegra_xusb_padctl_xlate); + if (IS_ERR(padctl->provider)) { + err = PTR_ERR(padctl->provider); + dev_err(dev, "failed to register PHYs: %d\n", err); + goto unregister; + } + + return 0; + +unregister: + pinctrl_unregister(&padctl->pinctrl); +reset: + reset_control_assert(padctl->rst); + return err; +} + +static const char *tegra124_otg_functions[] = { + "snps", + "xusb", + "uart", + "rsvd", +}; + +static const char *tegra124_usb_functions[] = { + "snps", + "xusb", +}; + +static const char *tegra124_pci_functions[] = { + "pcie", + "usb3", + "sata", + "rsvd", +}; + +#define TEGRA124_LANE(_name, _offs, _shift, _mask, _iddq, _funcs, _num) \ + { \ + .name = _name, \ + .offset = _offs, \ + .shift = _shift, \ + .mask = _mask, \ + .iddq = _iddq, \ + .num_funcs = _num, \ + .funcs = tegra124_##_funcs##_functions, \ + } + +static const struct tegra_xusb_padctl_lane tegra124_lanes[] = { + TEGRA124_LANE("otg-0", 0x004, 0, 0x3, 0, otg, 4), + TEGRA124_LANE("otg-1", 0x004, 2, 0x3, 0, otg, 4), + TEGRA124_LANE("otg-2", 0x004, 4, 0x3, 0, otg, 4), + TEGRA124_LANE("ulpi-0", 0x004, 12, 0x1, 0, usb, 2), + TEGRA124_LANE("hsic-0", 0x004, 14, 0x1, 0, usb, 2), + TEGRA124_LANE("hsic-1", 0x004, 15, 0x1, 0, usb, 2), + TEGRA124_LANE("pcie-0", 0x134, 16, 0x3, 1, pci, 4), + TEGRA124_LANE("pcie-1", 0x134, 18, 0x3, 2, pci, 4), + TEGRA124_LANE("pcie-2", 0x134, 20, 0x3, 3, pci, 4), + TEGRA124_LANE("pcie-3", 0x134, 22, 0x3, 4, pci, 4), + TEGRA124_LANE("pcie-4", 0x134, 24, 0x3, 5, pci, 4), + TEGRA124_LANE("sata-0", 0x134, 26, 0x3, 6, pci, 4), +}; + +static const struct tegra_xusb_padctl_soc tegra124_soc = { + .num_lanes = ARRAY_SIZE(tegra124_lanes), + .lanes = tegra124_lanes, +}; + +static __maybe_unused struct of_device_id pinctrl_tegra_xusb_dt_ids[] = { + { + .compatible = "nvidia,tegra124-xusb-padctl", + .data = (unsigned long)&tegra124_soc, + }, { + /* sentinel */ + } +}; + +static struct driver_d pinctrl_tegra_xusb_driver = { + .name = "pinctrl-tegra-xusb", + .probe = pinctrl_tegra_xusb_probe, + .of_compatible = DRV_OF_COMPAT(pinctrl_tegra_xusb_dt_ids), +}; + +static int pinctrl_tegra_xusb_init(void) +{ + return platform_driver_register(&pinctrl_tegra_xusb_driver); +} +postcore_initcall(pinctrl_tegra_xusb_init); -- cgit v1.2.3 From aafa2b84fe7beca94490ca512cf6ca257a66dec2 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 3 Nov 2014 23:52:15 +0100 Subject: tegra: colibri-t20: set hostname in board init Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/boards/toradex-colibri-t20/Makefile | 1 + arch/arm/boards/toradex-colibri-t20/board.c | 29 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 arch/arm/boards/toradex-colibri-t20/board.c diff --git a/arch/arm/boards/toradex-colibri-t20/Makefile b/arch/arm/boards/toradex-colibri-t20/Makefile index 1f767328fa..d0347f2382 100644 --- a/arch/arm/boards/toradex-colibri-t20/Makefile +++ b/arch/arm/boards/toradex-colibri-t20/Makefile @@ -3,6 +3,7 @@ CFLAGS_pbl-entry.o := \ -fno-tree-switch-conversion -fno-jump-tables soc := tegra20 lwl-y += entry.o +obj-y += board.o extra-y += colibri-t20_256_hsmmc.bct colibri-t20_256_v11_nand.bct \ colibri-t20_256_v12_nand.bct colibri-t20_512_hsmmc.bct \ colibri-t20_512_v11_nand.bct colibri-t20_512_v12_nand.bct \ No newline at end of file diff --git a/arch/arm/boards/toradex-colibri-t20/board.c b/arch/arm/boards/toradex-colibri-t20/board.c new file mode 100644 index 0000000000..706198105c --- /dev/null +++ b/arch/arm/boards/toradex-colibri-t20/board.c @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2014 Lucas Stach + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +static int toradex_colibri_t20_device_init(void) +{ + if (!of_machine_is_compatible("toradex,colibri_t20-512")) + return 0; + + barebox_set_hostname("colibri-t20"); + + return 0; +} +device_initcall(toradex_colibri_t20_device_init); -- cgit v1.2.3 From de9b7c85803180e23a503624de1faf7f6dcae691 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 3 Nov 2014 23:52:16 +0100 Subject: tegra: beaver: switch to upstream Tegra30 dtsi It's the same as our version, so no need to carry it around any longer. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/dts/tegra30-beaver.dts | 2 +- arch/arm/dts/tegra30.dtsi | 892 ---------------------------------------- 2 files changed, 1 insertion(+), 893 deletions(-) delete mode 100644 arch/arm/dts/tegra30.dtsi diff --git a/arch/arm/dts/tegra30-beaver.dts b/arch/arm/dts/tegra30-beaver.dts index 94955f96fe..d2809bb0dd 100644 --- a/arch/arm/dts/tegra30-beaver.dts +++ b/arch/arm/dts/tegra30-beaver.dts @@ -1,6 +1,6 @@ /dts-v1/; -#include "tegra30.dtsi" +#include / { model = "NVIDIA Tegra30 Beaver evaluation board"; diff --git a/arch/arm/dts/tegra30.dtsi b/arch/arm/dts/tegra30.dtsi deleted file mode 100644 index 19a84e933f..0000000000 --- a/arch/arm/dts/tegra30.dtsi +++ /dev/null @@ -1,892 +0,0 @@ -#include -#include -#include -#include - -#include "skeleton.dtsi" - -/ { - compatible = "nvidia,tegra30"; - interrupt-parent = <&intc>; - - aliases { - serial0 = &uarta; - serial1 = &uartb; - serial2 = &uartc; - serial3 = &uartd; - serial4 = &uarte; - }; - - pcie-controller@00003000 { - compatible = "nvidia,tegra30-pcie"; - device_type = "pci"; - reg = <0x00003000 0x00000800 /* PADS registers */ - 0x00003800 0x00000200 /* AFI registers */ - 0x10000000 0x10000000>; /* configuration space */ - reg-names = "pads", "afi", "cs"; - interrupts = ; /* MSI interrupt */ - interrupt-names = "intr", "msi"; - - bus-range = <0x00 0xff>; - #address-cells = <3>; - #size-cells = <2>; - - ranges = <0x82000000 0 0x00000000 0x00000000 0 0x00001000 /* port 0 configuration space */ - 0x82000000 0 0x00001000 0x00001000 0 0x00001000 /* port 1 configuration space */ - 0x82000000 0 0x00004000 0x00004000 0 0x00001000 /* port 2 configuration space */ - 0x81000000 0 0 0x02000000 0 0x00010000 /* downstream I/O */ - 0x82000000 0 0x20000000 0x20000000 0 0x08000000 /* non-prefetchable memory */ - 0xc2000000 0 0x28000000 0x28000000 0 0x18000000>; /* prefetchable memory */ - - clocks = <&tegra_car TEGRA30_CLK_PCIE>, - <&tegra_car TEGRA30_CLK_AFI>, - <&tegra_car TEGRA30_CLK_PLL_E>, - <&tegra_car TEGRA30_CLK_CML0>; - clock-names = "pex", "afi", "pll_e", "cml"; - resets = <&tegra_car 70>, - <&tegra_car 72>, - <&tegra_car 74>; - reset-names = "pex", "afi", "pcie_x"; - status = "disabled"; - - pci@1,0 { - device_type = "pci"; - assigned-addresses = <0x82000800 0 0x00000000 0 0x1000>; - reg = <0x000800 0 0 0 0>; - status = "disabled"; - - #address-cells = <3>; - #size-cells = <2>; - ranges; - - nvidia,num-lanes = <2>; - }; - - pci@2,0 { - device_type = "pci"; - assigned-addresses = <0x82001000 0 0x00001000 0 0x1000>; - reg = <0x001000 0 0 0 0>; - status = "disabled"; - - #address-cells = <3>; - #size-cells = <2>; - ranges; - - nvidia,num-lanes = <2>; - }; - - pci@3,0 { - device_type = "pci"; - assigned-addresses = <0x82001800 0 0x00004000 0 0x1000>; - reg = <0x001800 0 0 0 0>; - status = "disabled"; - - #address-cells = <3>; - #size-cells = <2>; - ranges; - - nvidia,num-lanes = <2>; - }; - }; - - host1x@50000000 { - compatible = "nvidia,tegra30-host1x", "simple-bus"; - reg = <0x50000000 0x00024000>; - interrupts = , /* syncpt */ - ; /* general */ - clocks = <&tegra_car TEGRA30_CLK_HOST1X>; - resets = <&tegra_car 28>; - reset-names = "host1x"; - - #address-cells = <1>; - #size-cells = <1>; - - ranges = <0x54000000 0x54000000 0x04000000>; - - mpe@54040000 { - compatible = "nvidia,tegra30-mpe"; - reg = <0x54040000 0x00040000>; - interrupts = ; - clocks = <&tegra_car TEGRA30_CLK_MPE>; - resets = <&tegra_car 60>; - reset-names = "mpe"; - }; - - vi@54080000 { - compatible = "nvidia,tegra30-vi"; - reg = <0x54080000 0x00040000>; - interrupts = ; - clocks = <&tegra_car TEGRA30_CLK_VI>; - resets = <&tegra_car 20>; - reset-names = "vi"; - }; - - epp@540c0000 { - compatible = "nvidia,tegra30-epp"; - reg = <0x540c0000 0x00040000>; - interrupts = ; - clocks = <&tegra_car TEGRA30_CLK_EPP>; - resets = <&tegra_car 19>; - reset-names = "epp"; - }; - - isp@54100000 { - compatible = "nvidia,tegra30-isp"; - reg = <0x54100000 0x00040000>; - interrupts = ; - clocks = <&tegra_car TEGRA30_CLK_ISP>; - resets = <&tegra_car 23>; - reset-names = "isp"; - }; - - gr2d@54140000 { - compatible = "nvidia,tegra30-gr2d"; - reg = <0x54140000 0x00040000>; - interrupts = ; - resets = <&tegra_car 21>; - reset-names = "2d"; - clocks = <&tegra_car TEGRA30_CLK_GR2D>; - }; - - gr3d@54180000 { - compatible = "nvidia,tegra30-gr3d"; - reg = <0x54180000 0x00040000>; - clocks = <&tegra_car TEGRA30_CLK_GR3D - &tegra_car TEGRA30_CLK_GR3D2>; - clock-names = "3d", "3d2"; - resets = <&tegra_car 24>, - <&tegra_car 98>; - reset-names = "3d", "3d2"; - }; - - dc@54200000 { - compatible = "nvidia,tegra30-dc", "nvidia,tegra20-dc"; - reg = <0x54200000 0x00040000>; - interrupts = ; - clocks = <&tegra_car TEGRA30_CLK_DISP1>, - <&tegra_car TEGRA30_CLK_PLL_P>; - clock-names = "dc", "parent"; - resets = <&tegra_car 27>; - reset-names = "dc"; - - nvidia,head = <0>; - - rgb { - status = "disabled"; - }; - }; - - dc@54240000 { - compatible = "nvidia,tegra30-dc"; - reg = <0x54240000 0x00040000>; - interrupts = ; - clocks = <&tegra_car TEGRA30_CLK_DISP2>, - <&tegra_car TEGRA30_CLK_PLL_P>; - clock-names = "dc", "parent"; - resets = <&tegra_car 26>; - reset-names = "dc"; - - nvidia,head = <1>; - - rgb { - status = "disabled"; - }; - }; - - hdmi@54280000 { - compatible = "nvidia,tegra30-hdmi"; - reg = <0x54280000 0x00040000>; - interrupts = ; - clocks = <&tegra_car TEGRA30_CLK_HDMI>, - <&tegra_car TEGRA30_CLK_PLL_D2_OUT0>; - clock-names = "hdmi", "parent"; - resets = <&tegra_car 51>; - reset-names = "hdmi"; - status = "disabled"; - }; - - tvo@542c0000 { - compatible = "nvidia,tegra30-tvo"; - reg = <0x542c0000 0x00040000>; - interrupts = ; - clocks = <&tegra_car TEGRA30_CLK_TVO>; - status = "disabled"; - }; - - dsi@54300000 { - compatible = "nvidia,tegra30-dsi"; - reg = <0x54300000 0x00040000>; - clocks = <&tegra_car TEGRA30_CLK_DSIA>; - resets = <&tegra_car 48>; - reset-names = "dsi"; - status = "disabled"; - }; - }; - - timer@50004600 { - compatible = "arm,cortex-a9-twd-timer"; - reg = <0x50040600 0x20>; - interrupts = ; - clocks = <&tegra_car TEGRA30_CLK_TWD>; - }; - - intc: interrupt-controller@50041000 { - compatible = "arm,cortex-a9-gic"; - reg = <0x50041000 0x1000 - 0x50040100 0x0100>; - interrupt-controller; - #interrupt-cells = <3>; - }; - - cache-controller@50043000 { - compatible = "arm,pl310-cache"; - reg = <0x50043000 0x1000>; - arm,data-latency = <6 6 2>; - arm,tag-latency = <5 5 2>; - cache-unified; - cache-level = <2>; - }; - - timer@60005000 { - compatible = "nvidia,tegra30-timer", "nvidia,tegra20-timer"; - reg = <0x60005000 0x400>; - interrupts = , - , - , - , - , - ; - clocks = <&tegra_car TEGRA30_CLK_TIMER>; - }; - - tegra_car: clock@60006000 { - compatible = "nvidia,tegra30-car"; - reg = <0x60006000 0x1000>; - #clock-cells = <1>; - #reset-cells = <1>; - }; - - apbdma: dma@6000a000 { - compatible = "nvidia,tegra30-apbdma", "nvidia,tegra20-apbdma"; - reg = <0x6000a000 0x1400>; - interrupts = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; - clocks = <&tegra_car TEGRA30_CLK_APBDMA>; - resets = <&tegra_car 34>; - reset-names = "dma"; - #dma-cells = <1>; - }; - - ahb: ahb@6000c004 { - compatible = "nvidia,tegra30-ahb"; - reg = <0x6000c004 0x14c>; /* AHB Arbitration + Gizmo Controller */ - }; - - gpio: gpio@6000d000 { - compatible = "nvidia,tegra30-gpio"; - reg = <0x6000d000 0x1000>; - interrupts = , - , - , - , - , - , - , - ; - #gpio-cells = <2>; - gpio-controller; - #interrupt-cells = <2>; - interrupt-controller; - }; - - pinmux: pinmux@70000868 { - compatible = "nvidia,tegra30-pinmux"; - reg = <0x70000868 0xd4 /* Pad control registers */ - 0x70003000 0x3e4>; /* Mux registers */ - }; - - /* - * There are two serial driver i.e. 8250 based simple serial - * driver and APB DMA based serial driver for higher baudrate - * and performace. To enable the 8250 based driver, the compatible - * is "nvidia,tegra30-uart", "nvidia,tegra20-uart" and to enable - * the APB DMA based serial driver, the comptible is - * "nvidia,tegra30-hsuart", "nvidia,tegra20-hsuart". - */ - uarta: serial@70006000 { - compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart"; - reg = <0x70006000 0x40>; - reg-shift = <2>; - interrupts = ; - clocks = <&tegra_car TEGRA30_CLK_UARTA>; - resets = <&tegra_car 6>; - reset-names = "serial"; - dmas = <&apbdma 8>, <&apbdma 8>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - uartb: serial@70006040 { - compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart"; - reg = <0x70006040 0x40>; - reg-shift = <2>; - interrupts = ; - clocks = <&tegra_car TEGRA30_CLK_UARTB>; - resets = <&tegra_car 7>; - reset-names = "serial"; - dmas = <&apbdma 9>, <&apbdma 9>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - uartc: serial@70006200 { - compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart"; - reg = <0x70006200 0x100>; - reg-shift = <2>; - interrupts = ; - clocks = <&tegra_car TEGRA30_CLK_UARTC>; - resets = <&tegra_car 55>; - reset-names = "serial"; - dmas = <&apbdma 10>, <&apbdma 10>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - uartd: serial@70006300 { - compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart"; - reg = <0x70006300 0x100>; - reg-shift = <2>; - interrupts = ; - clocks = <&tegra_car TEGRA30_CLK_UARTD>; - resets = <&tegra_car 65>; - reset-names = "serial"; - dmas = <&apbdma 19>, <&apbdma 19>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - uarte: serial@70006400 { - compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart"; - reg = <0x70006400 0x100>; - reg-shift = <2>; - interrupts = ; - clocks = <&tegra_car TEGRA30_CLK_UARTE>; - resets = <&tegra_car 66>; - reset-names = "serial"; - dmas = <&apbdma 20>, <&apbdma 20>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - pwm: pwm@7000a000 { - compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm"; - reg = <0x7000a000 0x100>; - #pwm-cells = <2>; - clocks = <&tegra_car TEGRA30_CLK_PWM>; - resets = <&tegra_car 17>; - reset-names = "pwm"; - status = "disabled"; - }; - - rtc@7000e000 { - compatible = "nvidia,tegra30-rtc", "nvidia,tegra20-rtc"; - reg = <0x7000e000 0x100>; - interrupts = ; - clocks = <&tegra_car TEGRA30_CLK_RTC>; - }; - - i2c@7000c000 { - compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; - reg = <0x7000c000 0x100>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&tegra_car TEGRA30_CLK_I2C1>, - <&tegra_car TEGRA30_CLK_PLL_P_OUT3>; - clock-names = "div-clk", "fast-clk"; - resets = <&tegra_car 12>; - reset-names = "i2c"; - dmas = <&apbdma 21>, <&apbdma 21>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - i2c@7000c400 { - compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; - reg = <0x7000c400 0x100>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&tegra_car TEGRA30_CLK_I2C2>, - <&tegra_car TEGRA30_CLK_PLL_P_OUT3>; - clock-names = "div-clk", "fast-clk"; - resets = <&tegra_car 54>; - reset-names = "i2c"; - dmas = <&apbdma 22>, <&apbdma 22>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - i2c@7000c500 { - compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; - reg = <0x7000c500 0x100>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&tegra_car TEGRA30_CLK_I2C3>, - <&tegra_car TEGRA30_CLK_PLL_P_OUT3>; - clock-names = "div-clk", "fast-clk"; - resets = <&tegra_car 67>; - reset-names = "i2c"; - dmas = <&apbdma 23>, <&apbdma 23>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - i2c@7000c700 { - compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; - reg = <0x7000c700 0x100>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&tegra_car TEGRA30_CLK_I2C4>, - <&tegra_car TEGRA30_CLK_PLL_P_OUT3>; - resets = <&tegra_car 103>; - reset-names = "i2c"; - clock-names = "div-clk", "fast-clk"; - dmas = <&apbdma 26>, <&apbdma 26>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - i2c@7000d000 { - compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; - reg = <0x7000d000 0x100>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&tegra_car TEGRA30_CLK_I2C5>, - <&tegra_car TEGRA30_CLK_PLL_P_OUT3>; - clock-names = "div-clk", "fast-clk"; - resets = <&tegra_car 47>; - reset-names = "i2c"; - dmas = <&apbdma 24>, <&apbdma 24>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - spi@7000d400 { - compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink"; - reg = <0x7000d400 0x200>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&tegra_car TEGRA30_CLK_SBC1>; - resets = <&tegra_car 41>; - reset-names = "spi"; - dmas = <&apbdma 15>, <&apbdma 15>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - spi@7000d600 { - compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink"; - reg = <0x7000d600 0x200>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&tegra_car TEGRA30_CLK_SBC2>; - resets = <&tegra_car 44>; - reset-names = "spi"; - dmas = <&apbdma 16>, <&apbdma 16>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - spi@7000d800 { - compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink"; - reg = <0x7000d800 0x200>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&tegra_car TEGRA30_CLK_SBC3>; - resets = <&tegra_car 46>; - reset-names = "spi"; - dmas = <&apbdma 17>, <&apbdma 17>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - spi@7000da00 { - compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink"; - reg = <0x7000da00 0x200>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&tegra_car TEGRA30_CLK_SBC4>; - resets = <&tegra_car 68>; - reset-names = "spi"; - dmas = <&apbdma 18>, <&apbdma 18>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - spi@7000dc00 { - compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink"; - reg = <0x7000dc00 0x200>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&tegra_car TEGRA30_CLK_SBC5>; - resets = <&tegra_car 104>; - reset-names = "spi"; - dmas = <&apbdma 27>, <&apbdma 27>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - spi@7000de00 { - compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink"; - reg = <0x7000de00 0x200>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&tegra_car TEGRA30_CLK_SBC6>; - resets = <&tegra_car 106>; - reset-names = "spi"; - dmas = <&apbdma 28>, <&apbdma 28>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - kbc@7000e200 { - compatible = "nvidia,tegra30-kbc", "nvidia,tegra20-kbc"; - reg = <0x7000e200 0x100>; - interrupts = ; - clocks = <&tegra_car TEGRA30_CLK_KBC>; - resets = <&tegra_car 36>; - reset-names = "kbc"; - status = "disabled"; - }; - - pmc@7000e400 { - compatible = "nvidia,tegra30-pmc"; - reg = <0x7000e400 0x400>; - clocks = <&tegra_car TEGRA30_CLK_PCLK>, <&clk32k_in>; - clock-names = "pclk", "clk32k_in"; - }; - - memory-controller@7000f000 { - compatible = "nvidia,tegra30-mc"; - reg = <0x7000f000 0x010 - 0x7000f03c 0x1b4 - 0x7000f200 0x028 - 0x7000f284 0x17c>; - interrupts = ; - }; - - iommu@7000f010 { - compatible = "nvidia,tegra30-smmu"; - reg = <0x7000f010 0x02c - 0x7000f1f0 0x010 - 0x7000f228 0x05c>; - nvidia,#asids = <4>; /* # of ASIDs */ - dma-window = <0 0x40000000>; /* IOVA start & length */ - nvidia,ahb = <&ahb>; - }; - - ahub@70080000 { - compatible = "nvidia,tegra30-ahub"; - reg = <0x70080000 0x200 - 0x70080200 0x100>; - interrupts = ; - clocks = <&tegra_car TEGRA30_CLK_D_AUDIO>, - <&tegra_car TEGRA30_CLK_APBIF>; - clock-names = "d_audio", "apbif"; - resets = <&tegra_car 106>, /* d_audio */ - <&tegra_car 107>, /* apbif */ - <&tegra_car 30>, /* i2s0 */ - <&tegra_car 11>, /* i2s1 */ - <&tegra_car 18>, /* i2s2 */ - <&tegra_car 101>, /* i2s3 */ - <&tegra_car 102>, /* i2s4 */ - <&tegra_car 108>, /* dam0 */ - <&tegra_car 109>, /* dam1 */ - <&tegra_car 110>, /* dam2 */ - <&tegra_car 10>; /* spdif */ - reset-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2", - "i2s3", "i2s4", "dam0", "dam1", "dam2", - "spdif"; - dmas = <&apbdma 1>, <&apbdma 1>, - <&apbdma 2>, <&apbdma 2>, - <&apbdma 3>, <&apbdma 3>, - <&apbdma 4>, <&apbdma 4>; - dma-names = "rx0", "tx0", "rx1", "tx1", "rx2", "tx2", - "rx3", "tx3"; - ranges; - #address-cells = <1>; - #size-cells = <1>; - - tegra_i2s0: i2s@70080300 { - compatible = "nvidia,tegra30-i2s"; - reg = <0x70080300 0x100>; - nvidia,ahub-cif-ids = <4 4>; - clocks = <&tegra_car TEGRA30_CLK_I2S0>; - resets = <&tegra_car 30>; - reset-names = "i2s"; - status = "disabled"; - }; - - tegra_i2s1: i2s@70080400 { - compatible = "nvidia,tegra30-i2s"; - reg = <0x70080400 0x100>; - nvidia,ahub-cif-ids = <5 5>; - clocks = <&tegra_car TEGRA30_CLK_I2S1>; - resets = <&tegra_car 11>; - reset-names = "i2s"; - status = "disabled"; - }; - - tegra_i2s2: i2s@70080500 { - compatible = "nvidia,tegra30-i2s"; - reg = <0x70080500 0x100>; - nvidia,ahub-cif-ids = <6 6>; - clocks = <&tegra_car TEGRA30_CLK_I2S2>; - resets = <&tegra_car 18>; - reset-names = "i2s"; - status = "disabled"; - }; - - tegra_i2s3: i2s@70080600 { - compatible = "nvidia,tegra30-i2s"; - reg = <0x70080600 0x100>; - nvidia,ahub-cif-ids = <7 7>; - clocks = <&tegra_car TEGRA30_CLK_I2S3>; - resets = <&tegra_car 101>; - reset-names = "i2s"; - status = "disabled"; - }; - - tegra_i2s4: i2s@70080700 { - compatible = "nvidia,tegra30-i2s"; - reg = <0x70080700 0x100>; - nvidia,ahub-cif-ids = <8 8>; - clocks = <&tegra_car TEGRA30_CLK_I2S4>; - resets = <&tegra_car 102>; - reset-names = "i2s"; - status = "disabled"; - }; - }; - - sdhci@78000000 { - compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci"; - reg = <0x78000000 0x200>; - interrupts = ; - clocks = <&tegra_car TEGRA30_CLK_SDMMC1>; - resets = <&tegra_car 14>; - reset-names = "sdhci"; - status = "disabled"; - }; - - sdhci@78000200 { - compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci"; - reg = <0x78000200 0x200>; - interrupts = ; - clocks = <&tegra_car TEGRA30_CLK_SDMMC2>; - resets = <&tegra_car 9>; - reset-names = "sdhci"; - status = "disabled"; - }; - - sdhci@78000400 { - compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci"; - reg = <0x78000400 0x200>; - interrupts = ; - clocks = <&tegra_car TEGRA30_CLK_SDMMC3>; - resets = <&tegra_car 69>; - reset-names = "sdhci"; - status = "disabled"; - }; - - sdhci@78000600 { - compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci"; - reg = <0x78000600 0x200>; - interrupts = ; - clocks = <&tegra_car TEGRA30_CLK_SDMMC4>; - resets = <&tegra_car 15>; - reset-names = "sdhci"; - status = "disabled"; - }; - - usb@7d000000 { - compatible = "nvidia,tegra30-ehci", "usb-ehci"; - reg = <0x7d000000 0x4000>; - interrupts = ; - phy_type = "utmi"; - clocks = <&tegra_car TEGRA30_CLK_USBD>; - resets = <&tegra_car 22>; - reset-names = "usb"; - nvidia,needs-double-reset; - nvidia,phy = <&phy1>; - status = "disabled"; - }; - - phy1: usb-phy@7d000000 { - compatible = "nvidia,tegra30-usb-phy"; - reg = <0x7d000000 0x4000 0x7d000000 0x4000>; - phy_type = "utmi"; - clocks = <&tegra_car TEGRA30_CLK_USBD>, - <&tegra_car TEGRA30_CLK_PLL_U>, - <&tegra_car TEGRA30_CLK_USBD>; - clock-names = "reg", "pll_u", "utmi-pads"; - nvidia,hssync-start-delay = <9>; - nvidia,idle-wait-delay = <17>; - nvidia,elastic-limit = <16>; - nvidia,term-range-adj = <6>; - nvidia,xcvr-setup = <51>; - nvidia.xcvr-setup-use-fuses; - nvidia,xcvr-lsfslew = <1>; - nvidia,xcvr-lsrslew = <1>; - nvidia,xcvr-hsslew = <32>; - nvidia,hssquelch-level = <2>; - nvidia,hsdiscon-level = <5>; - status = "disabled"; - }; - - usb@7d004000 { - compatible = "nvidia,tegra30-ehci", "usb-ehci"; - reg = <0x7d004000 0x4000>; - interrupts = ; - phy_type = "utmi"; - clocks = <&tegra_car TEGRA30_CLK_USB2>; - resets = <&tegra_car 58>; - reset-names = "usb"; - nvidia,phy = <&phy2>; - status = "disabled"; - }; - - phy2: usb-phy@7d004000 { - compatible = "nvidia,tegra30-usb-phy"; - reg = <0x7d004000 0x4000 0x7d000000 0x4000>; - phy_type = "utmi"; - clocks = <&tegra_car TEGRA30_CLK_USB2>, - <&tegra_car TEGRA30_CLK_PLL_U>, - <&tegra_car TEGRA30_CLK_USBD>; - clock-names = "reg", "pll_u", "utmi-pads"; - nvidia,hssync-start-delay = <9>; - nvidia,idle-wait-delay = <17>; - nvidia,elastic-limit = <16>; - nvidia,term-range-adj = <6>; - nvidia,xcvr-setup = <51>; - nvidia.xcvr-setup-use-fuses; - nvidia,xcvr-lsfslew = <2>; - nvidia,xcvr-lsrslew = <2>; - nvidia,xcvr-hsslew = <32>; - nvidia,hssquelch-level = <2>; - nvidia,hsdiscon-level = <5>; - status = "disabled"; - }; - - usb@7d008000 { - compatible = "nvidia,tegra30-ehci", "usb-ehci"; - reg = <0x7d008000 0x4000>; - interrupts = ; - phy_type = "utmi"; - clocks = <&tegra_car TEGRA30_CLK_USB3>; - resets = <&tegra_car 59>; - reset-names = "usb"; - nvidia,phy = <&phy3>; - status = "disabled"; - }; - - phy3: usb-phy@7d008000 { - compatible = "nvidia,tegra30-usb-phy"; - reg = <0x7d008000 0x4000 0x7d000000 0x4000>; - phy_type = "utmi"; - clocks = <&tegra_car TEGRA30_CLK_USB3>, - <&tegra_car TEGRA30_CLK_PLL_U>, - <&tegra_car TEGRA30_CLK_USBD>; - clock-names = "reg", "pll_u", "utmi-pads"; - nvidia,hssync-start-delay = <0>; - nvidia,idle-wait-delay = <17>; - nvidia,elastic-limit = <16>; - nvidia,term-range-adj = <6>; - nvidia,xcvr-setup = <51>; - nvidia.xcvr-setup-use-fuses; - nvidia,xcvr-lsfslew = <2>; - nvidia,xcvr-lsrslew = <2>; - nvidia,xcvr-hsslew = <32>; - nvidia,hssquelch-level = <2>; - nvidia,hsdiscon-level = <5>; - status = "disabled"; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - device_type = "cpu"; - compatible = "arm,cortex-a9"; - reg = <0>; - }; - - cpu@1 { - device_type = "cpu"; - compatible = "arm,cortex-a9"; - reg = <1>; - }; - - cpu@2 { - device_type = "cpu"; - compatible = "arm,cortex-a9"; - reg = <2>; - }; - - cpu@3 { - device_type = "cpu"; - compatible = "arm,cortex-a9"; - reg = <3>; - }; - }; - - pmu { - compatible = "arm,cortex-a9-pmu"; - interrupts = , - , - , - ; - }; -}; -- cgit v1.2.3 From ffe054136c10f810229c05179b24f1c72bf42cb1 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 3 Nov 2014 23:52:17 +0100 Subject: tegra: beaver: add stdout-path Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/dts/tegra30-beaver.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/dts/tegra30-beaver.dts b/arch/arm/dts/tegra30-beaver.dts index d2809bb0dd..5879353fc6 100644 --- a/arch/arm/dts/tegra30-beaver.dts +++ b/arch/arm/dts/tegra30-beaver.dts @@ -12,6 +12,8 @@ }; chosen { + stdout-path = &uarta; + environment@0 { compatible = "barebox,environment"; device-path = &emmc, "partname:boot1"; -- cgit v1.2.3 From c6dcef4d119d2a6a295d368d3f4fd34dd3a2fb90 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 3 Nov 2014 23:52:18 +0100 Subject: tegra: colibri-t20: add stdout-path Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/dts/tegra20-colibri-iris.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/dts/tegra20-colibri-iris.dts b/arch/arm/dts/tegra20-colibri-iris.dts index adfa917824..9c615816ca 100644 --- a/arch/arm/dts/tegra20-colibri-iris.dts +++ b/arch/arm/dts/tegra20-colibri-iris.dts @@ -6,6 +6,10 @@ model = "Toradex Colibri T20 on Iris"; compatible = "toradex,iris", "toradex,colibri_t20", "nvidia,tegra20"; + chosen { + stdout-path = &uarta; + }; + host1x@50000000 { hdmi@54280000 { status = "okay"; -- cgit v1.2.3 From 93c5c841ad7b22d8a0f9ae624ef689a1a62886d8 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 3 Nov 2014 23:52:19 +0100 Subject: tegra: tegra124: add serial alias nodes They are missing in the upstream DT. Add them locally for now. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/dts/tegra124.dtsi | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm/dts/tegra124.dtsi b/arch/arm/dts/tegra124.dtsi index 7d0fafa862..c795811c57 100644 --- a/arch/arm/dts/tegra124.dtsi +++ b/arch/arm/dts/tegra124.dtsi @@ -1 +1,8 @@ -#include +/ { + aliases { + serial0 = "/serial@0,70006000/"; + serial1 = "/serial@0,70006040/"; + serial2 = "/serial@0,70006200/"; + serial3 = "/serial@0,70006300/"; + }; +}; -- cgit v1.2.3 From d086b3298b9bb0da9b8aa9f0f5850dc46f4ea3c8 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 3 Nov 2014 23:52:20 +0100 Subject: tegra: jetson-tk1: add stdout-path Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/dts/tegra124-jetson-tk1.dts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/dts/tegra124-jetson-tk1.dts b/arch/arm/dts/tegra124-jetson-tk1.dts index d2933bdc4f..26f405ca3d 100644 --- a/arch/arm/dts/tegra124-jetson-tk1.dts +++ b/arch/arm/dts/tegra124-jetson-tk1.dts @@ -1,7 +1,10 @@ #include +#include "tegra124.dtsi" / { chosen { + stdout-path = "/serial@0,70006300/"; + environment@0 { compatible = "barebox,environment"; device-path = &emmc, "partname:boot1"; -- cgit v1.2.3 From 2c779cbe9700c4a70d2f846127390b217e75146e Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 3 Nov 2014 23:52:21 +0100 Subject: serial: ns16550: enable clock if available Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/serial/serial_ns16550.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c index 4ca74446b3..f281f3fc92 100644 --- a/drivers/serial/serial_ns16550.c +++ b/drivers/serial/serial_ns16550.c @@ -418,6 +418,7 @@ static int ns16550_probe(struct device_d *dev) ret = PTR_ERR(priv->clk); goto err; } + clk_enable(priv->clk); priv->plat.clock = clk_get_rate(priv->clk); } -- cgit v1.2.3 From b5ac88e8f6e5e8307d9e9c09eaf331e44bafbef1 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 3 Nov 2014 23:52:22 +0100 Subject: serial: ns16550: add Tegra support Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/serial/serial_ns16550.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c index f281f3fc92..38d2f79fc8 100644 --- a/drivers/serial/serial_ns16550.c +++ b/drivers/serial/serial_ns16550.c @@ -311,6 +311,11 @@ static __maybe_unused struct ns16550_drvdata jz_drvdata = { .init_port = ns16550_jz_init_port, }; +static __maybe_unused struct ns16550_drvdata tegra_drvdata = { + .init_port = ns16550_serial_init_port, + .linux_console_name = "ttyS", +}; + static int ns16550_init_iomem(struct device_d *dev, struct ns16550_priv *priv) { struct resource *res; @@ -480,6 +485,12 @@ static struct of_device_id ns16550_serial_dt_ids[] = { .data = (unsigned long)&omap_drvdata, }, #endif +#if IS_ENABLED(CONFIG_ARCH_TEGRA) + { + .compatible = "nvidia,tegra20-uart", + .data = (unsigned long)&tegra_drvdata, + }, +#endif #if IS_ENABLED(CONFIG_MACH_MIPS_XBURST) { .compatible = "ingenic,jz4740-uart", -- cgit v1.2.3 From 566c1630c3164e4e790ca1bfce462034a2639947 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 3 Nov 2014 23:52:23 +0100 Subject: tegra: remove custom UART setup The config option doesn't make any sense anymore when building a multiimage barebox. With a proper DT built into the image we don't need the ODMdata mechanism to find the debug UART anymore. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- arch/arm/mach-tegra/Kconfig | 33 --------------------- arch/arm/mach-tegra/include/mach/lowlevel.h | 45 ----------------------------- arch/arm/mach-tegra/tegra20.c | 41 -------------------------- 3 files changed, 119 deletions(-) diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 1bdea8e6a9..160732fbef 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -7,39 +7,6 @@ config ARCH_TEXT_BASE config BOARDINFO default "" -choice - prompt "Tegra debug UART" - help - This is the first serial console that gets activated by barebox. - Normally each board vendor should program a valid debug UART into - the ODMdata section of the boot configuration table, so it's a - reasonably good bet to use that. - If you know your ODMdata is broken, or you don't wish to activate - any serial console at all you can override the default here. - -config TEGRA_UART_ODMDATA - bool "ODMdata defined UART" - -config TEGRA_UART_A - bool "UART A" - -config TEGRA_UART_B - bool "UART B" - -config TEGRA_UART_C - bool "UART C" - -config TEGRA_UART_D - bool "UART D" - -config TEGRA_UART_E - bool "UART E" - -config TEGRA_UART_NONE - bool "None" - -endchoice - # --------------------------------------------------------- config ARCH_TEGRA_2x_SOC diff --git a/arch/arm/mach-tegra/include/mach/lowlevel.h b/arch/arm/mach-tegra/include/mach/lowlevel.h index c65be0b7ba..3e7e41b990 100644 --- a/arch/arm/mach-tegra/include/mach/lowlevel.h +++ b/arch/arm/mach-tegra/include/mach/lowlevel.h @@ -176,37 +176,6 @@ uint32_t tegra30_get_ramsize(void) } } -static long uart_id_to_base[] = { - TEGRA_UARTA_BASE, - TEGRA_UARTB_BASE, - TEGRA_UARTC_BASE, - TEGRA_UARTD_BASE, - TEGRA_UARTE_BASE, -}; - -static __always_inline -long tegra20_get_debuguart_base(void) -{ - u32 odmdata; - int id; - - odmdata = tegra_get_odmdata(); - - /* - * Get type, we accept both "2" and "3", as they both demark a UART, - * depending on the board type. - */ - if (!(((odmdata & T20_ODMDATA_UARTTYPE_MASK) >> - T20_ODMDATA_UARTTYPE_SHIFT) & 0x2)) - return 0; - - id = (odmdata & T20_ODMDATA_UARTID_MASK) >> T20_ODMDATA_UARTID_SHIFT; - if (id > ARRAY_SIZE(uart_id_to_base)) - return 0; - - return uart_id_to_base[id]; -} - #define CRC_OSC_CTRL 0x050 #define CRC_OSC_CTRL_OSC_FREQ_SHIFT 30 #define CRC_OSC_CTRL_OSC_FREQ_MASK (0x3 << CRC_OSC_CTRL_OSC_FREQ_SHIFT) @@ -231,20 +200,6 @@ int tegra_get_osc_clock(void) } } -static __always_inline -int tegra_get_pllp_rate(void) -{ - switch (tegra_get_chiptype()) { - case TEGRA20: - return 216000000; - case TEGRA30: - case TEGRA124: - return 408000000; - default: - return 0; - } -} - #define TIMER_CNTR_1US 0x00 #define TIMER_USEC_CFG 0x04 diff --git a/arch/arm/mach-tegra/tegra20.c b/arch/arm/mach-tegra/tegra20.c index dcc55aefaa..8d1cd5b2fb 100644 --- a/arch/arm/mach-tegra/tegra20.c +++ b/arch/arm/mach-tegra/tegra20.c @@ -22,47 +22,6 @@ #include #include -static struct NS16550_plat debug_uart = { - .shift = 2, -}; - -static int tegra_add_debug_console(void) -{ - unsigned long base = 0; - - if (!of_machine_is_compatible("nvidia,tegra20") && - !of_machine_is_compatible("nvidia,tegra30") && - !of_machine_is_compatible("nvidia,tegra124")) - return 0; - - /* figure out which UART to use */ - if (IS_ENABLED(CONFIG_TEGRA_UART_NONE)) - return 0; - if (IS_ENABLED(CONFIG_TEGRA_UART_ODMDATA)) - base = tegra20_get_debuguart_base(); - if (IS_ENABLED(CONFIG_TEGRA_UART_A)) - base = TEGRA_UARTA_BASE; - if (IS_ENABLED(CONFIG_TEGRA_UART_B)) - base = TEGRA_UARTB_BASE; - if (IS_ENABLED(CONFIG_TEGRA_UART_C)) - base = TEGRA_UARTC_BASE; - if (IS_ENABLED(CONFIG_TEGRA_UART_D)) - base = TEGRA_UARTD_BASE; - if (IS_ENABLED(CONFIG_TEGRA_UART_E)) - base = TEGRA_UARTE_BASE; - - if (!base) - return -ENODEV; - - debug_uart.clock = tegra_get_pllp_rate(); - - add_ns16550_device(DEVICE_ID_DYNAMIC, base, 8 << debug_uart.shift, - IORESOURCE_MEM | IORESOURCE_MEM_8BIT, &debug_uart); - - return 0; -} -console_initcall(tegra_add_debug_console); - static int tegra20_mem_init(void) { if (!of_machine_is_compatible("nvidia,tegra20")) -- cgit v1.2.3 From c202b7c8d9e66082853ac1b131ddcedf53e9ca99 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 3 Nov 2014 23:52:24 +0100 Subject: clk: tegra: don't enable UART clocks by default Now that we are registering a proper driver for the UARTs we no longer need to enable the clocks unconditionally. Signed-off-by: Lucas Stach Signed-off-by: Sascha Hauer --- drivers/clk/tegra/clk-tegra124.c | 8 ++++---- drivers/clk/tegra/clk-tegra20.c | 10 +++++----- drivers/clk/tegra/clk-tegra30.c | 10 +++++----- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index d597a239b9..7a2f7c081f 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -322,10 +322,10 @@ static struct tegra_clk_init_table init_table[] = { {TEGRA124_CLK_PLL_P_OUT3, TEGRA124_CLK_CLK_MAX, 102000000, 1}, {TEGRA124_CLK_PLL_P_OUT4, TEGRA124_CLK_CLK_MAX, 204000000, 1}, {TEGRA124_CLK_MSELECT, TEGRA124_CLK_PLL_P, 102000000, 1}, - {TEGRA124_CLK_UARTA, TEGRA124_CLK_PLL_P, 0, 1}, - {TEGRA124_CLK_UARTB, TEGRA124_CLK_PLL_P, 0, 1}, - {TEGRA124_CLK_UARTC, TEGRA124_CLK_PLL_P, 0, 1}, - {TEGRA124_CLK_UARTD, TEGRA124_CLK_PLL_P, 0, 1}, + {TEGRA124_CLK_UARTA, TEGRA124_CLK_PLL_P, 0, 0}, + {TEGRA124_CLK_UARTB, TEGRA124_CLK_PLL_P, 0, 0}, + {TEGRA124_CLK_UARTC, TEGRA124_CLK_PLL_P, 0, 0}, + {TEGRA124_CLK_UARTD, TEGRA124_CLK_PLL_P, 0, 0}, {TEGRA124_CLK_SDMMC1, TEGRA124_CLK_PLL_P, 48000000, 0}, {TEGRA124_CLK_SDMMC2, TEGRA124_CLK_PLL_P, 48000000, 0}, {TEGRA124_CLK_SDMMC3, TEGRA124_CLK_PLL_P, 48000000, 0}, diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index 5b4365d492..2ff42d8bdb 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -324,11 +324,11 @@ static struct tegra_clk_init_table init_table[] = { {TEGRA20_CLK_PLL_P_OUT4, TEGRA20_CLK_CLK_MAX, 24000000, 1}, {TEGRA20_CLK_PLL_C, TEGRA20_CLK_CLK_MAX, 600000000, 1}, {TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 120000000, 1}, - {TEGRA20_CLK_UARTA, TEGRA20_CLK_PLL_P, 0, 1}, - {TEGRA20_CLK_UARTB, TEGRA20_CLK_PLL_P, 0, 1}, - {TEGRA20_CLK_UARTC, TEGRA20_CLK_PLL_P, 0, 1}, - {TEGRA20_CLK_UARTD, TEGRA20_CLK_PLL_P, 0, 1}, - {TEGRA20_CLK_UARTE, TEGRA20_CLK_PLL_P, 0, 1}, + {TEGRA20_CLK_UARTA, TEGRA20_CLK_PLL_P, 0, 0}, + {TEGRA20_CLK_UARTB, TEGRA20_CLK_PLL_P, 0, 0}, + {TEGRA20_CLK_UARTC, TEGRA20_CLK_PLL_P, 0, 0}, + {TEGRA20_CLK_UARTD, TEGRA20_CLK_PLL_P, 0, 0}, + {TEGRA20_CLK_UARTE, TEGRA20_CLK_PLL_P, 0, 0}, {TEGRA20_CLK_SDMMC1, TEGRA20_CLK_PLL_P, 48000000, 0}, {TEGRA20_CLK_SDMMC2, TEGRA20_CLK_PLL_P, 48000000, 0}, {TEGRA20_CLK_SDMMC3, TEGRA20_CLK_PLL_P, 48000000, 0}, diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index 7210053e96..46fd6dddea 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -352,11 +352,11 @@ static struct tegra_clk_init_table init_table[] = { {TEGRA30_CLK_PLL_P_OUT3, TEGRA30_CLK_CLK_MAX, 102000000, 1}, {TEGRA30_CLK_PLL_P_OUT4, TEGRA30_CLK_CLK_MAX, 204000000, 1}, {TEGRA30_CLK_MSELECT, TEGRA30_CLK_PLL_P, 102000000, 1}, - {TEGRA30_CLK_UARTA, TEGRA30_CLK_PLL_P, 0, 1}, - {TEGRA30_CLK_UARTB, TEGRA30_CLK_PLL_P, 0, 1}, - {TEGRA30_CLK_UARTC, TEGRA30_CLK_PLL_P, 0, 1}, - {TEGRA30_CLK_UARTD, TEGRA30_CLK_PLL_P, 0, 1}, - {TEGRA30_CLK_UARTE, TEGRA30_CLK_PLL_P, 0, 1}, + {TEGRA30_CLK_UARTA, TEGRA30_CLK_PLL_P, 0, 0}, + {TEGRA30_CLK_UARTB, TEGRA30_CLK_PLL_P, 0, 0}, + {TEGRA30_CLK_UARTC, TEGRA30_CLK_PLL_P, 0, 0}, + {TEGRA30_CLK_UARTD, TEGRA30_CLK_PLL_P, 0, 0}, + {TEGRA30_CLK_UARTE, TEGRA30_CLK_PLL_P, 0, 0}, {TEGRA30_CLK_SDMMC1, TEGRA30_CLK_PLL_P, 48000000, 0}, {TEGRA30_CLK_SDMMC2, TEGRA30_CLK_PLL_P, 48000000, 0}, {TEGRA30_CLK_SDMMC3, TEGRA30_CLK_PLL_P, 48000000, 0}, -- cgit v1.2.3