1a88b5ba8SSam Ravnborg /* 2a88b5ba8SSam Ravnborg * Procedures for creating, accessing and interpreting the device tree. 3a88b5ba8SSam Ravnborg * 4a88b5ba8SSam Ravnborg * Paul Mackerras August 1996. 5a88b5ba8SSam Ravnborg * Copyright (C) 1996-2005 Paul Mackerras. 6a88b5ba8SSam Ravnborg * 7a88b5ba8SSam Ravnborg * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. 8a88b5ba8SSam Ravnborg * {engebret|bergner}@us.ibm.com 9a88b5ba8SSam Ravnborg * 10a88b5ba8SSam Ravnborg * Adapted for sparc64 by David S. Miller davem@davemloft.net 11a88b5ba8SSam Ravnborg * 12a88b5ba8SSam Ravnborg * This program is free software; you can redistribute it and/or 13a88b5ba8SSam Ravnborg * modify it under the terms of the GNU General Public License 14a88b5ba8SSam Ravnborg * as published by the Free Software Foundation; either version 15a88b5ba8SSam Ravnborg * 2 of the License, or (at your option) any later version. 16a88b5ba8SSam Ravnborg */ 17a88b5ba8SSam Ravnborg 18a88b5ba8SSam Ravnborg #include <linux/kernel.h> 19a88b5ba8SSam Ravnborg #include <linux/types.h> 20a88b5ba8SSam Ravnborg #include <linux/string.h> 21a88b5ba8SSam Ravnborg #include <linux/mm.h> 22a88b5ba8SSam Ravnborg #include <linux/module.h> 23a88b5ba8SSam Ravnborg #include <linux/lmb.h> 24a88b5ba8SSam Ravnborg #include <linux/of_device.h> 25a88b5ba8SSam Ravnborg 26a88b5ba8SSam Ravnborg #include <asm/prom.h> 27a88b5ba8SSam Ravnborg #include <asm/oplib.h> 28a88b5ba8SSam Ravnborg #include <asm/irq.h> 29a88b5ba8SSam Ravnborg #include <asm/asi.h> 30a88b5ba8SSam Ravnborg #include <asm/upa.h> 31a88b5ba8SSam Ravnborg #include <asm/smp.h> 32a88b5ba8SSam Ravnborg 33657f201dSDavid S. Miller #include "prom.h" 34a88b5ba8SSam Ravnborg 35a88b5ba8SSam Ravnborg static unsigned int prom_early_allocated __initdata; 36a88b5ba8SSam Ravnborg 37efeac2f8SDavid S. Miller void * __init prom_early_alloc(unsigned long size) 38a88b5ba8SSam Ravnborg { 39a88b5ba8SSam Ravnborg unsigned long paddr = lmb_alloc(size, SMP_CACHE_BYTES); 40a88b5ba8SSam Ravnborg void *ret; 41a88b5ba8SSam Ravnborg 42a88b5ba8SSam Ravnborg if (!paddr) { 43a88b5ba8SSam Ravnborg prom_printf("prom_early_alloc(%lu) failed\n"); 44a88b5ba8SSam Ravnborg prom_halt(); 45a88b5ba8SSam Ravnborg } 46a88b5ba8SSam Ravnborg 47a88b5ba8SSam Ravnborg ret = __va(paddr); 48a88b5ba8SSam Ravnborg memset(ret, 0, size); 49a88b5ba8SSam Ravnborg prom_early_allocated += size; 50a88b5ba8SSam Ravnborg 51a88b5ba8SSam Ravnborg return ret; 52a88b5ba8SSam Ravnborg } 53a88b5ba8SSam Ravnborg 54a88b5ba8SSam Ravnborg #ifdef CONFIG_PCI 55a88b5ba8SSam Ravnborg /* PSYCHO interrupt mapping support. */ 56a88b5ba8SSam Ravnborg #define PSYCHO_IMAP_A_SLOT0 0x0c00UL 57a88b5ba8SSam Ravnborg #define PSYCHO_IMAP_B_SLOT0 0x0c20UL 58a88b5ba8SSam Ravnborg static unsigned long psycho_pcislot_imap_offset(unsigned long ino) 59a88b5ba8SSam Ravnborg { 60a88b5ba8SSam Ravnborg unsigned int bus = (ino & 0x10) >> 4; 61a88b5ba8SSam Ravnborg unsigned int slot = (ino & 0x0c) >> 2; 62a88b5ba8SSam Ravnborg 63a88b5ba8SSam Ravnborg if (bus == 0) 64a88b5ba8SSam Ravnborg return PSYCHO_IMAP_A_SLOT0 + (slot * 8); 65a88b5ba8SSam Ravnborg else 66a88b5ba8SSam Ravnborg return PSYCHO_IMAP_B_SLOT0 + (slot * 8); 67a88b5ba8SSam Ravnborg } 68a88b5ba8SSam Ravnborg 69a88b5ba8SSam Ravnborg #define PSYCHO_OBIO_IMAP_BASE 0x1000UL 70a88b5ba8SSam Ravnborg 71a88b5ba8SSam Ravnborg #define PSYCHO_ONBOARD_IRQ_BASE 0x20 72a88b5ba8SSam Ravnborg #define psycho_onboard_imap_offset(__ino) \ 73a88b5ba8SSam Ravnborg (PSYCHO_OBIO_IMAP_BASE + (((__ino) & 0x1f) << 3)) 74a88b5ba8SSam Ravnborg 75a88b5ba8SSam Ravnborg #define PSYCHO_ICLR_A_SLOT0 0x1400UL 76a88b5ba8SSam Ravnborg #define PSYCHO_ICLR_SCSI 0x1800UL 77a88b5ba8SSam Ravnborg 78a88b5ba8SSam Ravnborg #define psycho_iclr_offset(ino) \ 79a88b5ba8SSam Ravnborg ((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ 80a88b5ba8SSam Ravnborg (PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) 81a88b5ba8SSam Ravnborg 82a88b5ba8SSam Ravnborg static unsigned int psycho_irq_build(struct device_node *dp, 83a88b5ba8SSam Ravnborg unsigned int ino, 84a88b5ba8SSam Ravnborg void *_data) 85a88b5ba8SSam Ravnborg { 86a88b5ba8SSam Ravnborg unsigned long controller_regs = (unsigned long) _data; 87a88b5ba8SSam Ravnborg unsigned long imap, iclr; 88a88b5ba8SSam Ravnborg unsigned long imap_off, iclr_off; 89a88b5ba8SSam Ravnborg int inofixup = 0; 90a88b5ba8SSam Ravnborg 91a88b5ba8SSam Ravnborg ino &= 0x3f; 92a88b5ba8SSam Ravnborg if (ino < PSYCHO_ONBOARD_IRQ_BASE) { 93a88b5ba8SSam Ravnborg /* PCI slot */ 94a88b5ba8SSam Ravnborg imap_off = psycho_pcislot_imap_offset(ino); 95a88b5ba8SSam Ravnborg } else { 96a88b5ba8SSam Ravnborg /* Onboard device */ 97a88b5ba8SSam Ravnborg imap_off = psycho_onboard_imap_offset(ino); 98a88b5ba8SSam Ravnborg } 99a88b5ba8SSam Ravnborg 100a88b5ba8SSam Ravnborg /* Now build the IRQ bucket. */ 101a88b5ba8SSam Ravnborg imap = controller_regs + imap_off; 102a88b5ba8SSam Ravnborg 103a88b5ba8SSam Ravnborg iclr_off = psycho_iclr_offset(ino); 104a88b5ba8SSam Ravnborg iclr = controller_regs + iclr_off; 105a88b5ba8SSam Ravnborg 106a88b5ba8SSam Ravnborg if ((ino & 0x20) == 0) 107a88b5ba8SSam Ravnborg inofixup = ino & 0x03; 108a88b5ba8SSam Ravnborg 109a88b5ba8SSam Ravnborg return build_irq(inofixup, iclr, imap); 110a88b5ba8SSam Ravnborg } 111a88b5ba8SSam Ravnborg 112a88b5ba8SSam Ravnborg static void __init psycho_irq_trans_init(struct device_node *dp) 113a88b5ba8SSam Ravnborg { 114a88b5ba8SSam Ravnborg const struct linux_prom64_registers *regs; 115a88b5ba8SSam Ravnborg 116a88b5ba8SSam Ravnborg dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); 117a88b5ba8SSam Ravnborg dp->irq_trans->irq_build = psycho_irq_build; 118a88b5ba8SSam Ravnborg 119a88b5ba8SSam Ravnborg regs = of_get_property(dp, "reg", NULL); 120a88b5ba8SSam Ravnborg dp->irq_trans->data = (void *) regs[2].phys_addr; 121a88b5ba8SSam Ravnborg } 122a88b5ba8SSam Ravnborg 123a88b5ba8SSam Ravnborg #define sabre_read(__reg) \ 124a88b5ba8SSam Ravnborg ({ u64 __ret; \ 125a88b5ba8SSam Ravnborg __asm__ __volatile__("ldxa [%1] %2, %0" \ 126a88b5ba8SSam Ravnborg : "=r" (__ret) \ 127a88b5ba8SSam Ravnborg : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ 128a88b5ba8SSam Ravnborg : "memory"); \ 129a88b5ba8SSam Ravnborg __ret; \ 130a88b5ba8SSam Ravnborg }) 131a88b5ba8SSam Ravnborg 132a88b5ba8SSam Ravnborg struct sabre_irq_data { 133a88b5ba8SSam Ravnborg unsigned long controller_regs; 134a88b5ba8SSam Ravnborg unsigned int pci_first_busno; 135a88b5ba8SSam Ravnborg }; 136a88b5ba8SSam Ravnborg #define SABRE_CONFIGSPACE 0x001000000UL 137a88b5ba8SSam Ravnborg #define SABRE_WRSYNC 0x1c20UL 138a88b5ba8SSam Ravnborg 139a88b5ba8SSam Ravnborg #define SABRE_CONFIG_BASE(CONFIG_SPACE) \ 140a88b5ba8SSam Ravnborg (CONFIG_SPACE | (1UL << 24)) 141a88b5ba8SSam Ravnborg #define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG) \ 142a88b5ba8SSam Ravnborg (((unsigned long)(BUS) << 16) | \ 143a88b5ba8SSam Ravnborg ((unsigned long)(DEVFN) << 8) | \ 144a88b5ba8SSam Ravnborg ((unsigned long)(REG))) 145a88b5ba8SSam Ravnborg 146a88b5ba8SSam Ravnborg /* When a device lives behind a bridge deeper in the PCI bus topology 147a88b5ba8SSam Ravnborg * than APB, a special sequence must run to make sure all pending DMA 148a88b5ba8SSam Ravnborg * transfers at the time of IRQ delivery are visible in the coherency 149a88b5ba8SSam Ravnborg * domain by the cpu. This sequence is to perform a read on the far 150a88b5ba8SSam Ravnborg * side of the non-APB bridge, then perform a read of Sabre's DMA 151a88b5ba8SSam Ravnborg * write-sync register. 152a88b5ba8SSam Ravnborg */ 153a88b5ba8SSam Ravnborg static void sabre_wsync_handler(unsigned int ino, void *_arg1, void *_arg2) 154a88b5ba8SSam Ravnborg { 155a88b5ba8SSam Ravnborg unsigned int phys_hi = (unsigned int) (unsigned long) _arg1; 156a88b5ba8SSam Ravnborg struct sabre_irq_data *irq_data = _arg2; 157a88b5ba8SSam Ravnborg unsigned long controller_regs = irq_data->controller_regs; 158a88b5ba8SSam Ravnborg unsigned long sync_reg = controller_regs + SABRE_WRSYNC; 159a88b5ba8SSam Ravnborg unsigned long config_space = controller_regs + SABRE_CONFIGSPACE; 160a88b5ba8SSam Ravnborg unsigned int bus, devfn; 161a88b5ba8SSam Ravnborg u16 _unused; 162a88b5ba8SSam Ravnborg 163a88b5ba8SSam Ravnborg config_space = SABRE_CONFIG_BASE(config_space); 164a88b5ba8SSam Ravnborg 165a88b5ba8SSam Ravnborg bus = (phys_hi >> 16) & 0xff; 166a88b5ba8SSam Ravnborg devfn = (phys_hi >> 8) & 0xff; 167a88b5ba8SSam Ravnborg 168a88b5ba8SSam Ravnborg config_space |= SABRE_CONFIG_ENCODE(bus, devfn, 0x00); 169a88b5ba8SSam Ravnborg 170a88b5ba8SSam Ravnborg __asm__ __volatile__("membar #Sync\n\t" 171a88b5ba8SSam Ravnborg "lduha [%1] %2, %0\n\t" 172a88b5ba8SSam Ravnborg "membar #Sync" 173a88b5ba8SSam Ravnborg : "=r" (_unused) 174a88b5ba8SSam Ravnborg : "r" ((u16 *) config_space), 175a88b5ba8SSam Ravnborg "i" (ASI_PHYS_BYPASS_EC_E_L) 176a88b5ba8SSam Ravnborg : "memory"); 177a88b5ba8SSam Ravnborg 178a88b5ba8SSam Ravnborg sabre_read(sync_reg); 179a88b5ba8SSam Ravnborg } 180a88b5ba8SSam Ravnborg 181a88b5ba8SSam Ravnborg #define SABRE_IMAP_A_SLOT0 0x0c00UL 182a88b5ba8SSam Ravnborg #define SABRE_IMAP_B_SLOT0 0x0c20UL 183a88b5ba8SSam Ravnborg #define SABRE_ICLR_A_SLOT0 0x1400UL 184a88b5ba8SSam Ravnborg #define SABRE_ICLR_B_SLOT0 0x1480UL 185a88b5ba8SSam Ravnborg #define SABRE_ICLR_SCSI 0x1800UL 186a88b5ba8SSam Ravnborg #define SABRE_ICLR_ETH 0x1808UL 187a88b5ba8SSam Ravnborg #define SABRE_ICLR_BPP 0x1810UL 188a88b5ba8SSam Ravnborg #define SABRE_ICLR_AU_REC 0x1818UL 189a88b5ba8SSam Ravnborg #define SABRE_ICLR_AU_PLAY 0x1820UL 190a88b5ba8SSam Ravnborg #define SABRE_ICLR_PFAIL 0x1828UL 191a88b5ba8SSam Ravnborg #define SABRE_ICLR_KMS 0x1830UL 192a88b5ba8SSam Ravnborg #define SABRE_ICLR_FLPY 0x1838UL 193a88b5ba8SSam Ravnborg #define SABRE_ICLR_SHW 0x1840UL 194a88b5ba8SSam Ravnborg #define SABRE_ICLR_KBD 0x1848UL 195a88b5ba8SSam Ravnborg #define SABRE_ICLR_MS 0x1850UL 196a88b5ba8SSam Ravnborg #define SABRE_ICLR_SER 0x1858UL 197a88b5ba8SSam Ravnborg #define SABRE_ICLR_UE 0x1870UL 198a88b5ba8SSam Ravnborg #define SABRE_ICLR_CE 0x1878UL 199a88b5ba8SSam Ravnborg #define SABRE_ICLR_PCIERR 0x1880UL 200a88b5ba8SSam Ravnborg 201a88b5ba8SSam Ravnborg static unsigned long sabre_pcislot_imap_offset(unsigned long ino) 202a88b5ba8SSam Ravnborg { 203a88b5ba8SSam Ravnborg unsigned int bus = (ino & 0x10) >> 4; 204a88b5ba8SSam Ravnborg unsigned int slot = (ino & 0x0c) >> 2; 205a88b5ba8SSam Ravnborg 206a88b5ba8SSam Ravnborg if (bus == 0) 207a88b5ba8SSam Ravnborg return SABRE_IMAP_A_SLOT0 + (slot * 8); 208a88b5ba8SSam Ravnborg else 209a88b5ba8SSam Ravnborg return SABRE_IMAP_B_SLOT0 + (slot * 8); 210a88b5ba8SSam Ravnborg } 211a88b5ba8SSam Ravnborg 212a88b5ba8SSam Ravnborg #define SABRE_OBIO_IMAP_BASE 0x1000UL 213a88b5ba8SSam Ravnborg #define SABRE_ONBOARD_IRQ_BASE 0x20 214a88b5ba8SSam Ravnborg #define sabre_onboard_imap_offset(__ino) \ 215a88b5ba8SSam Ravnborg (SABRE_OBIO_IMAP_BASE + (((__ino) & 0x1f) << 3)) 216a88b5ba8SSam Ravnborg 217a88b5ba8SSam Ravnborg #define sabre_iclr_offset(ino) \ 218a88b5ba8SSam Ravnborg ((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ 219a88b5ba8SSam Ravnborg (SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) 220a88b5ba8SSam Ravnborg 221a88b5ba8SSam Ravnborg static int sabre_device_needs_wsync(struct device_node *dp) 222a88b5ba8SSam Ravnborg { 223a88b5ba8SSam Ravnborg struct device_node *parent = dp->parent; 224a88b5ba8SSam Ravnborg const char *parent_model, *parent_compat; 225a88b5ba8SSam Ravnborg 226a88b5ba8SSam Ravnborg /* This traversal up towards the root is meant to 227a88b5ba8SSam Ravnborg * handle two cases: 228a88b5ba8SSam Ravnborg * 229a88b5ba8SSam Ravnborg * 1) non-PCI bus sitting under PCI, such as 'ebus' 230a88b5ba8SSam Ravnborg * 2) the PCI controller interrupts themselves, which 231a88b5ba8SSam Ravnborg * will use the sabre_irq_build but do not need 232a88b5ba8SSam Ravnborg * the DMA synchronization handling 233a88b5ba8SSam Ravnborg */ 234a88b5ba8SSam Ravnborg while (parent) { 235a88b5ba8SSam Ravnborg if (!strcmp(parent->type, "pci")) 236a88b5ba8SSam Ravnborg break; 237a88b5ba8SSam Ravnborg parent = parent->parent; 238a88b5ba8SSam Ravnborg } 239a88b5ba8SSam Ravnborg 240a88b5ba8SSam Ravnborg if (!parent) 241a88b5ba8SSam Ravnborg return 0; 242a88b5ba8SSam Ravnborg 243a88b5ba8SSam Ravnborg parent_model = of_get_property(parent, 244a88b5ba8SSam Ravnborg "model", NULL); 245a88b5ba8SSam Ravnborg if (parent_model && 246a88b5ba8SSam Ravnborg (!strcmp(parent_model, "SUNW,sabre") || 247a88b5ba8SSam Ravnborg !strcmp(parent_model, "SUNW,simba"))) 248a88b5ba8SSam Ravnborg return 0; 249a88b5ba8SSam Ravnborg 250a88b5ba8SSam Ravnborg parent_compat = of_get_property(parent, 251a88b5ba8SSam Ravnborg "compatible", NULL); 252a88b5ba8SSam Ravnborg if (parent_compat && 253a88b5ba8SSam Ravnborg (!strcmp(parent_compat, "pci108e,a000") || 254a88b5ba8SSam Ravnborg !strcmp(parent_compat, "pci108e,a001"))) 255a88b5ba8SSam Ravnborg return 0; 256a88b5ba8SSam Ravnborg 257a88b5ba8SSam Ravnborg return 1; 258a88b5ba8SSam Ravnborg } 259a88b5ba8SSam Ravnborg 260a88b5ba8SSam Ravnborg static unsigned int sabre_irq_build(struct device_node *dp, 261a88b5ba8SSam Ravnborg unsigned int ino, 262a88b5ba8SSam Ravnborg void *_data) 263a88b5ba8SSam Ravnborg { 264a88b5ba8SSam Ravnborg struct sabre_irq_data *irq_data = _data; 265a88b5ba8SSam Ravnborg unsigned long controller_regs = irq_data->controller_regs; 266a88b5ba8SSam Ravnborg const struct linux_prom_pci_registers *regs; 267a88b5ba8SSam Ravnborg unsigned long imap, iclr; 268a88b5ba8SSam Ravnborg unsigned long imap_off, iclr_off; 269a88b5ba8SSam Ravnborg int inofixup = 0; 270a88b5ba8SSam Ravnborg int virt_irq; 271a88b5ba8SSam Ravnborg 272a88b5ba8SSam Ravnborg ino &= 0x3f; 273a88b5ba8SSam Ravnborg if (ino < SABRE_ONBOARD_IRQ_BASE) { 274a88b5ba8SSam Ravnborg /* PCI slot */ 275a88b5ba8SSam Ravnborg imap_off = sabre_pcislot_imap_offset(ino); 276a88b5ba8SSam Ravnborg } else { 277a88b5ba8SSam Ravnborg /* onboard device */ 278a88b5ba8SSam Ravnborg imap_off = sabre_onboard_imap_offset(ino); 279a88b5ba8SSam Ravnborg } 280a88b5ba8SSam Ravnborg 281a88b5ba8SSam Ravnborg /* Now build the IRQ bucket. */ 282a88b5ba8SSam Ravnborg imap = controller_regs + imap_off; 283a88b5ba8SSam Ravnborg 284a88b5ba8SSam Ravnborg iclr_off = sabre_iclr_offset(ino); 285a88b5ba8SSam Ravnborg iclr = controller_regs + iclr_off; 286a88b5ba8SSam Ravnborg 287a88b5ba8SSam Ravnborg if ((ino & 0x20) == 0) 288a88b5ba8SSam Ravnborg inofixup = ino & 0x03; 289a88b5ba8SSam Ravnborg 290a88b5ba8SSam Ravnborg virt_irq = build_irq(inofixup, iclr, imap); 291a88b5ba8SSam Ravnborg 292a88b5ba8SSam Ravnborg /* If the parent device is a PCI<->PCI bridge other than 293a88b5ba8SSam Ravnborg * APB, we have to install a pre-handler to ensure that 294a88b5ba8SSam Ravnborg * all pending DMA is drained before the interrupt handler 295a88b5ba8SSam Ravnborg * is run. 296a88b5ba8SSam Ravnborg */ 297a88b5ba8SSam Ravnborg regs = of_get_property(dp, "reg", NULL); 298a88b5ba8SSam Ravnborg if (regs && sabre_device_needs_wsync(dp)) { 299a88b5ba8SSam Ravnborg irq_install_pre_handler(virt_irq, 300a88b5ba8SSam Ravnborg sabre_wsync_handler, 301a88b5ba8SSam Ravnborg (void *) (long) regs->phys_hi, 302a88b5ba8SSam Ravnborg (void *) irq_data); 303a88b5ba8SSam Ravnborg } 304a88b5ba8SSam Ravnborg 305a88b5ba8SSam Ravnborg return virt_irq; 306a88b5ba8SSam Ravnborg } 307a88b5ba8SSam Ravnborg 308a88b5ba8SSam Ravnborg static void __init sabre_irq_trans_init(struct device_node *dp) 309a88b5ba8SSam Ravnborg { 310a88b5ba8SSam Ravnborg const struct linux_prom64_registers *regs; 311a88b5ba8SSam Ravnborg struct sabre_irq_data *irq_data; 312a88b5ba8SSam Ravnborg const u32 *busrange; 313a88b5ba8SSam Ravnborg 314a88b5ba8SSam Ravnborg dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); 315a88b5ba8SSam Ravnborg dp->irq_trans->irq_build = sabre_irq_build; 316a88b5ba8SSam Ravnborg 317a88b5ba8SSam Ravnborg irq_data = prom_early_alloc(sizeof(struct sabre_irq_data)); 318a88b5ba8SSam Ravnborg 319a88b5ba8SSam Ravnborg regs = of_get_property(dp, "reg", NULL); 320a88b5ba8SSam Ravnborg irq_data->controller_regs = regs[0].phys_addr; 321a88b5ba8SSam Ravnborg 322a88b5ba8SSam Ravnborg busrange = of_get_property(dp, "bus-range", NULL); 323a88b5ba8SSam Ravnborg irq_data->pci_first_busno = busrange[0]; 324a88b5ba8SSam Ravnborg 325a88b5ba8SSam Ravnborg dp->irq_trans->data = irq_data; 326a88b5ba8SSam Ravnborg } 327a88b5ba8SSam Ravnborg 328a88b5ba8SSam Ravnborg /* SCHIZO interrupt mapping support. Unlike Psycho, for this controller the 329a88b5ba8SSam Ravnborg * imap/iclr registers are per-PBM. 330a88b5ba8SSam Ravnborg */ 331a88b5ba8SSam Ravnborg #define SCHIZO_IMAP_BASE 0x1000UL 332a88b5ba8SSam Ravnborg #define SCHIZO_ICLR_BASE 0x1400UL 333a88b5ba8SSam Ravnborg 334a88b5ba8SSam Ravnborg static unsigned long schizo_imap_offset(unsigned long ino) 335a88b5ba8SSam Ravnborg { 336a88b5ba8SSam Ravnborg return SCHIZO_IMAP_BASE + (ino * 8UL); 337a88b5ba8SSam Ravnborg } 338a88b5ba8SSam Ravnborg 339a88b5ba8SSam Ravnborg static unsigned long schizo_iclr_offset(unsigned long ino) 340a88b5ba8SSam Ravnborg { 341a88b5ba8SSam Ravnborg return SCHIZO_ICLR_BASE + (ino * 8UL); 342a88b5ba8SSam Ravnborg } 343a88b5ba8SSam Ravnborg 344a88b5ba8SSam Ravnborg static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs, 345a88b5ba8SSam Ravnborg unsigned int ino) 346a88b5ba8SSam Ravnborg { 347a88b5ba8SSam Ravnborg 348a88b5ba8SSam Ravnborg return pbm_regs + schizo_iclr_offset(ino); 349a88b5ba8SSam Ravnborg } 350a88b5ba8SSam Ravnborg 351a88b5ba8SSam Ravnborg static unsigned long schizo_ino_to_imap(unsigned long pbm_regs, 352a88b5ba8SSam Ravnborg unsigned int ino) 353a88b5ba8SSam Ravnborg { 354a88b5ba8SSam Ravnborg return pbm_regs + schizo_imap_offset(ino); 355a88b5ba8SSam Ravnborg } 356a88b5ba8SSam Ravnborg 357a88b5ba8SSam Ravnborg #define schizo_read(__reg) \ 358a88b5ba8SSam Ravnborg ({ u64 __ret; \ 359a88b5ba8SSam Ravnborg __asm__ __volatile__("ldxa [%1] %2, %0" \ 360a88b5ba8SSam Ravnborg : "=r" (__ret) \ 361a88b5ba8SSam Ravnborg : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ 362a88b5ba8SSam Ravnborg : "memory"); \ 363a88b5ba8SSam Ravnborg __ret; \ 364a88b5ba8SSam Ravnborg }) 365a88b5ba8SSam Ravnborg #define schizo_write(__reg, __val) \ 366a88b5ba8SSam Ravnborg __asm__ __volatile__("stxa %0, [%1] %2" \ 367a88b5ba8SSam Ravnborg : /* no outputs */ \ 368a88b5ba8SSam Ravnborg : "r" (__val), "r" (__reg), \ 369a88b5ba8SSam Ravnborg "i" (ASI_PHYS_BYPASS_EC_E) \ 370a88b5ba8SSam Ravnborg : "memory") 371a88b5ba8SSam Ravnborg 372a88b5ba8SSam Ravnborg static void tomatillo_wsync_handler(unsigned int ino, void *_arg1, void *_arg2) 373a88b5ba8SSam Ravnborg { 374a88b5ba8SSam Ravnborg unsigned long sync_reg = (unsigned long) _arg2; 375a88b5ba8SSam Ravnborg u64 mask = 1UL << (ino & IMAP_INO); 376a88b5ba8SSam Ravnborg u64 val; 377a88b5ba8SSam Ravnborg int limit; 378a88b5ba8SSam Ravnborg 379a88b5ba8SSam Ravnborg schizo_write(sync_reg, mask); 380a88b5ba8SSam Ravnborg 381a88b5ba8SSam Ravnborg limit = 100000; 382a88b5ba8SSam Ravnborg val = 0; 383a88b5ba8SSam Ravnborg while (--limit) { 384a88b5ba8SSam Ravnborg val = schizo_read(sync_reg); 385a88b5ba8SSam Ravnborg if (!(val & mask)) 386a88b5ba8SSam Ravnborg break; 387a88b5ba8SSam Ravnborg } 388a88b5ba8SSam Ravnborg if (limit <= 0) { 389a88b5ba8SSam Ravnborg printk("tomatillo_wsync_handler: DMA won't sync [%lx:%lx]\n", 390a88b5ba8SSam Ravnborg val, mask); 391a88b5ba8SSam Ravnborg } 392a88b5ba8SSam Ravnborg 393a88b5ba8SSam Ravnborg if (_arg1) { 394a88b5ba8SSam Ravnborg static unsigned char cacheline[64] 395a88b5ba8SSam Ravnborg __attribute__ ((aligned (64))); 396a88b5ba8SSam Ravnborg 397a88b5ba8SSam Ravnborg __asm__ __volatile__("rd %%fprs, %0\n\t" 398a88b5ba8SSam Ravnborg "or %0, %4, %1\n\t" 399a88b5ba8SSam Ravnborg "wr %1, 0x0, %%fprs\n\t" 400a88b5ba8SSam Ravnborg "stda %%f0, [%5] %6\n\t" 401a88b5ba8SSam Ravnborg "wr %0, 0x0, %%fprs\n\t" 402a88b5ba8SSam Ravnborg "membar #Sync" 403a88b5ba8SSam Ravnborg : "=&r" (mask), "=&r" (val) 404a88b5ba8SSam Ravnborg : "0" (mask), "1" (val), 405a88b5ba8SSam Ravnborg "i" (FPRS_FEF), "r" (&cacheline[0]), 406a88b5ba8SSam Ravnborg "i" (ASI_BLK_COMMIT_P)); 407a88b5ba8SSam Ravnborg } 408a88b5ba8SSam Ravnborg } 409a88b5ba8SSam Ravnborg 410a88b5ba8SSam Ravnborg struct schizo_irq_data { 411a88b5ba8SSam Ravnborg unsigned long pbm_regs; 412a88b5ba8SSam Ravnborg unsigned long sync_reg; 413a88b5ba8SSam Ravnborg u32 portid; 414a88b5ba8SSam Ravnborg int chip_version; 415a88b5ba8SSam Ravnborg }; 416a88b5ba8SSam Ravnborg 417a88b5ba8SSam Ravnborg static unsigned int schizo_irq_build(struct device_node *dp, 418a88b5ba8SSam Ravnborg unsigned int ino, 419a88b5ba8SSam Ravnborg void *_data) 420a88b5ba8SSam Ravnborg { 421a88b5ba8SSam Ravnborg struct schizo_irq_data *irq_data = _data; 422a88b5ba8SSam Ravnborg unsigned long pbm_regs = irq_data->pbm_regs; 423a88b5ba8SSam Ravnborg unsigned long imap, iclr; 424a88b5ba8SSam Ravnborg int ign_fixup; 425a88b5ba8SSam Ravnborg int virt_irq; 426a88b5ba8SSam Ravnborg int is_tomatillo; 427a88b5ba8SSam Ravnborg 428a88b5ba8SSam Ravnborg ino &= 0x3f; 429a88b5ba8SSam Ravnborg 430a88b5ba8SSam Ravnborg /* Now build the IRQ bucket. */ 431a88b5ba8SSam Ravnborg imap = schizo_ino_to_imap(pbm_regs, ino); 432a88b5ba8SSam Ravnborg iclr = schizo_ino_to_iclr(pbm_regs, ino); 433a88b5ba8SSam Ravnborg 434a88b5ba8SSam Ravnborg /* On Schizo, no inofixup occurs. This is because each 435a88b5ba8SSam Ravnborg * INO has it's own IMAP register. On Psycho and Sabre 436a88b5ba8SSam Ravnborg * there is only one IMAP register for each PCI slot even 437a88b5ba8SSam Ravnborg * though four different INOs can be generated by each 438a88b5ba8SSam Ravnborg * PCI slot. 439a88b5ba8SSam Ravnborg * 440a88b5ba8SSam Ravnborg * But, for JBUS variants (essentially, Tomatillo), we have 441a88b5ba8SSam Ravnborg * to fixup the lowest bit of the interrupt group number. 442a88b5ba8SSam Ravnborg */ 443a88b5ba8SSam Ravnborg ign_fixup = 0; 444a88b5ba8SSam Ravnborg 445a88b5ba8SSam Ravnborg is_tomatillo = (irq_data->sync_reg != 0UL); 446a88b5ba8SSam Ravnborg 447a88b5ba8SSam Ravnborg if (is_tomatillo) { 448a88b5ba8SSam Ravnborg if (irq_data->portid & 1) 449a88b5ba8SSam Ravnborg ign_fixup = (1 << 6); 450a88b5ba8SSam Ravnborg } 451a88b5ba8SSam Ravnborg 452a88b5ba8SSam Ravnborg virt_irq = build_irq(ign_fixup, iclr, imap); 453a88b5ba8SSam Ravnborg 454a88b5ba8SSam Ravnborg if (is_tomatillo) { 455a88b5ba8SSam Ravnborg irq_install_pre_handler(virt_irq, 456a88b5ba8SSam Ravnborg tomatillo_wsync_handler, 457a88b5ba8SSam Ravnborg ((irq_data->chip_version <= 4) ? 458a88b5ba8SSam Ravnborg (void *) 1 : (void *) 0), 459a88b5ba8SSam Ravnborg (void *) irq_data->sync_reg); 460a88b5ba8SSam Ravnborg } 461a88b5ba8SSam Ravnborg 462a88b5ba8SSam Ravnborg return virt_irq; 463a88b5ba8SSam Ravnborg } 464a88b5ba8SSam Ravnborg 465a88b5ba8SSam Ravnborg static void __init __schizo_irq_trans_init(struct device_node *dp, 466a88b5ba8SSam Ravnborg int is_tomatillo) 467a88b5ba8SSam Ravnborg { 468a88b5ba8SSam Ravnborg const struct linux_prom64_registers *regs; 469a88b5ba8SSam Ravnborg struct schizo_irq_data *irq_data; 470a88b5ba8SSam Ravnborg 471a88b5ba8SSam Ravnborg dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); 472a88b5ba8SSam Ravnborg dp->irq_trans->irq_build = schizo_irq_build; 473a88b5ba8SSam Ravnborg 474a88b5ba8SSam Ravnborg irq_data = prom_early_alloc(sizeof(struct schizo_irq_data)); 475a88b5ba8SSam Ravnborg 476a88b5ba8SSam Ravnborg regs = of_get_property(dp, "reg", NULL); 477a88b5ba8SSam Ravnborg dp->irq_trans->data = irq_data; 478a88b5ba8SSam Ravnborg 479a88b5ba8SSam Ravnborg irq_data->pbm_regs = regs[0].phys_addr; 480a88b5ba8SSam Ravnborg if (is_tomatillo) 481a88b5ba8SSam Ravnborg irq_data->sync_reg = regs[3].phys_addr + 0x1a18UL; 482a88b5ba8SSam Ravnborg else 483a88b5ba8SSam Ravnborg irq_data->sync_reg = 0UL; 484a88b5ba8SSam Ravnborg irq_data->portid = of_getintprop_default(dp, "portid", 0); 485a88b5ba8SSam Ravnborg irq_data->chip_version = of_getintprop_default(dp, "version#", 0); 486a88b5ba8SSam Ravnborg } 487a88b5ba8SSam Ravnborg 488a88b5ba8SSam Ravnborg static void __init schizo_irq_trans_init(struct device_node *dp) 489a88b5ba8SSam Ravnborg { 490a88b5ba8SSam Ravnborg __schizo_irq_trans_init(dp, 0); 491a88b5ba8SSam Ravnborg } 492a88b5ba8SSam Ravnborg 493a88b5ba8SSam Ravnborg static void __init tomatillo_irq_trans_init(struct device_node *dp) 494a88b5ba8SSam Ravnborg { 495a88b5ba8SSam Ravnborg __schizo_irq_trans_init(dp, 1); 496a88b5ba8SSam Ravnborg } 497a88b5ba8SSam Ravnborg 498a88b5ba8SSam Ravnborg static unsigned int pci_sun4v_irq_build(struct device_node *dp, 499a88b5ba8SSam Ravnborg unsigned int devino, 500a88b5ba8SSam Ravnborg void *_data) 501a88b5ba8SSam Ravnborg { 502a88b5ba8SSam Ravnborg u32 devhandle = (u32) (unsigned long) _data; 503a88b5ba8SSam Ravnborg 504a88b5ba8SSam Ravnborg return sun4v_build_irq(devhandle, devino); 505a88b5ba8SSam Ravnborg } 506a88b5ba8SSam Ravnborg 507a88b5ba8SSam Ravnborg static void __init pci_sun4v_irq_trans_init(struct device_node *dp) 508a88b5ba8SSam Ravnborg { 509a88b5ba8SSam Ravnborg const struct linux_prom64_registers *regs; 510a88b5ba8SSam Ravnborg 511a88b5ba8SSam Ravnborg dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); 512a88b5ba8SSam Ravnborg dp->irq_trans->irq_build = pci_sun4v_irq_build; 513a88b5ba8SSam Ravnborg 514a88b5ba8SSam Ravnborg regs = of_get_property(dp, "reg", NULL); 515a88b5ba8SSam Ravnborg dp->irq_trans->data = (void *) (unsigned long) 516a88b5ba8SSam Ravnborg ((regs->phys_addr >> 32UL) & 0x0fffffff); 517a88b5ba8SSam Ravnborg } 518a88b5ba8SSam Ravnborg 519a88b5ba8SSam Ravnborg struct fire_irq_data { 520a88b5ba8SSam Ravnborg unsigned long pbm_regs; 521a88b5ba8SSam Ravnborg u32 portid; 522a88b5ba8SSam Ravnborg }; 523a88b5ba8SSam Ravnborg 524a88b5ba8SSam Ravnborg #define FIRE_IMAP_BASE 0x001000 525a88b5ba8SSam Ravnborg #define FIRE_ICLR_BASE 0x001400 526a88b5ba8SSam Ravnborg 527a88b5ba8SSam Ravnborg static unsigned long fire_imap_offset(unsigned long ino) 528a88b5ba8SSam Ravnborg { 529a88b5ba8SSam Ravnborg return FIRE_IMAP_BASE + (ino * 8UL); 530a88b5ba8SSam Ravnborg } 531a88b5ba8SSam Ravnborg 532a88b5ba8SSam Ravnborg static unsigned long fire_iclr_offset(unsigned long ino) 533a88b5ba8SSam Ravnborg { 534a88b5ba8SSam Ravnborg return FIRE_ICLR_BASE + (ino * 8UL); 535a88b5ba8SSam Ravnborg } 536a88b5ba8SSam Ravnborg 537a88b5ba8SSam Ravnborg static unsigned long fire_ino_to_iclr(unsigned long pbm_regs, 538a88b5ba8SSam Ravnborg unsigned int ino) 539a88b5ba8SSam Ravnborg { 540a88b5ba8SSam Ravnborg return pbm_regs + fire_iclr_offset(ino); 541a88b5ba8SSam Ravnborg } 542a88b5ba8SSam Ravnborg 543a88b5ba8SSam Ravnborg static unsigned long fire_ino_to_imap(unsigned long pbm_regs, 544a88b5ba8SSam Ravnborg unsigned int ino) 545a88b5ba8SSam Ravnborg { 546a88b5ba8SSam Ravnborg return pbm_regs + fire_imap_offset(ino); 547a88b5ba8SSam Ravnborg } 548a88b5ba8SSam Ravnborg 549a88b5ba8SSam Ravnborg static unsigned int fire_irq_build(struct device_node *dp, 550a88b5ba8SSam Ravnborg unsigned int ino, 551a88b5ba8SSam Ravnborg void *_data) 552a88b5ba8SSam Ravnborg { 553a88b5ba8SSam Ravnborg struct fire_irq_data *irq_data = _data; 554a88b5ba8SSam Ravnborg unsigned long pbm_regs = irq_data->pbm_regs; 555a88b5ba8SSam Ravnborg unsigned long imap, iclr; 556a88b5ba8SSam Ravnborg unsigned long int_ctrlr; 557a88b5ba8SSam Ravnborg 558a88b5ba8SSam Ravnborg ino &= 0x3f; 559a88b5ba8SSam Ravnborg 560a88b5ba8SSam Ravnborg /* Now build the IRQ bucket. */ 561a88b5ba8SSam Ravnborg imap = fire_ino_to_imap(pbm_regs, ino); 562a88b5ba8SSam Ravnborg iclr = fire_ino_to_iclr(pbm_regs, ino); 563a88b5ba8SSam Ravnborg 564a88b5ba8SSam Ravnborg /* Set the interrupt controller number. */ 565a88b5ba8SSam Ravnborg int_ctrlr = 1 << 6; 566a88b5ba8SSam Ravnborg upa_writeq(int_ctrlr, imap); 567a88b5ba8SSam Ravnborg 568a88b5ba8SSam Ravnborg /* The interrupt map registers do not have an INO field 569a88b5ba8SSam Ravnborg * like other chips do. They return zero in the INO 570a88b5ba8SSam Ravnborg * field, and the interrupt controller number is controlled 571a88b5ba8SSam Ravnborg * in bits 6 to 9. So in order for build_irq() to get 572a88b5ba8SSam Ravnborg * the INO right we pass it in as part of the fixup 573a88b5ba8SSam Ravnborg * which will get added to the map register zero value 574a88b5ba8SSam Ravnborg * read by build_irq(). 575a88b5ba8SSam Ravnborg */ 576a88b5ba8SSam Ravnborg ino |= (irq_data->portid << 6); 577a88b5ba8SSam Ravnborg ino -= int_ctrlr; 578a88b5ba8SSam Ravnborg return build_irq(ino, iclr, imap); 579a88b5ba8SSam Ravnborg } 580a88b5ba8SSam Ravnborg 581a88b5ba8SSam Ravnborg static void __init fire_irq_trans_init(struct device_node *dp) 582a88b5ba8SSam Ravnborg { 583a88b5ba8SSam Ravnborg const struct linux_prom64_registers *regs; 584a88b5ba8SSam Ravnborg struct fire_irq_data *irq_data; 585a88b5ba8SSam Ravnborg 586a88b5ba8SSam Ravnborg dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); 587a88b5ba8SSam Ravnborg dp->irq_trans->irq_build = fire_irq_build; 588a88b5ba8SSam Ravnborg 589a88b5ba8SSam Ravnborg irq_data = prom_early_alloc(sizeof(struct fire_irq_data)); 590a88b5ba8SSam Ravnborg 591a88b5ba8SSam Ravnborg regs = of_get_property(dp, "reg", NULL); 592a88b5ba8SSam Ravnborg dp->irq_trans->data = irq_data; 593a88b5ba8SSam Ravnborg 594a88b5ba8SSam Ravnborg irq_data->pbm_regs = regs[0].phys_addr; 595a88b5ba8SSam Ravnborg irq_data->portid = of_getintprop_default(dp, "portid", 0); 596a88b5ba8SSam Ravnborg } 597a88b5ba8SSam Ravnborg #endif /* CONFIG_PCI */ 598a88b5ba8SSam Ravnborg 599a88b5ba8SSam Ravnborg #ifdef CONFIG_SBUS 600a88b5ba8SSam Ravnborg /* INO number to IMAP register offset for SYSIO external IRQ's. 601a88b5ba8SSam Ravnborg * This should conform to both Sunfire/Wildfire server and Fusion 602a88b5ba8SSam Ravnborg * desktop designs. 603a88b5ba8SSam Ravnborg */ 604a88b5ba8SSam Ravnborg #define SYSIO_IMAP_SLOT0 0x2c00UL 605a88b5ba8SSam Ravnborg #define SYSIO_IMAP_SLOT1 0x2c08UL 606a88b5ba8SSam Ravnborg #define SYSIO_IMAP_SLOT2 0x2c10UL 607a88b5ba8SSam Ravnborg #define SYSIO_IMAP_SLOT3 0x2c18UL 608a88b5ba8SSam Ravnborg #define SYSIO_IMAP_SCSI 0x3000UL 609a88b5ba8SSam Ravnborg #define SYSIO_IMAP_ETH 0x3008UL 610a88b5ba8SSam Ravnborg #define SYSIO_IMAP_BPP 0x3010UL 611a88b5ba8SSam Ravnborg #define SYSIO_IMAP_AUDIO 0x3018UL 612a88b5ba8SSam Ravnborg #define SYSIO_IMAP_PFAIL 0x3020UL 613a88b5ba8SSam Ravnborg #define SYSIO_IMAP_KMS 0x3028UL 614a88b5ba8SSam Ravnborg #define SYSIO_IMAP_FLPY 0x3030UL 615a88b5ba8SSam Ravnborg #define SYSIO_IMAP_SHW 0x3038UL 616a88b5ba8SSam Ravnborg #define SYSIO_IMAP_KBD 0x3040UL 617a88b5ba8SSam Ravnborg #define SYSIO_IMAP_MS 0x3048UL 618a88b5ba8SSam Ravnborg #define SYSIO_IMAP_SER 0x3050UL 619a88b5ba8SSam Ravnborg #define SYSIO_IMAP_TIM0 0x3060UL 620a88b5ba8SSam Ravnborg #define SYSIO_IMAP_TIM1 0x3068UL 621a88b5ba8SSam Ravnborg #define SYSIO_IMAP_UE 0x3070UL 622a88b5ba8SSam Ravnborg #define SYSIO_IMAP_CE 0x3078UL 623a88b5ba8SSam Ravnborg #define SYSIO_IMAP_SBERR 0x3080UL 624a88b5ba8SSam Ravnborg #define SYSIO_IMAP_PMGMT 0x3088UL 625a88b5ba8SSam Ravnborg #define SYSIO_IMAP_GFX 0x3090UL 626a88b5ba8SSam Ravnborg #define SYSIO_IMAP_EUPA 0x3098UL 627a88b5ba8SSam Ravnborg 628a88b5ba8SSam Ravnborg #define bogon ((unsigned long) -1) 629a88b5ba8SSam Ravnborg static unsigned long sysio_irq_offsets[] = { 630a88b5ba8SSam Ravnborg /* SBUS Slot 0 --> 3, level 1 --> 7 */ 631a88b5ba8SSam Ravnborg SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, 632a88b5ba8SSam Ravnborg SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, 633a88b5ba8SSam Ravnborg SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, 634a88b5ba8SSam Ravnborg SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, 635a88b5ba8SSam Ravnborg SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, 636a88b5ba8SSam Ravnborg SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, 637a88b5ba8SSam Ravnborg SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, 638a88b5ba8SSam Ravnborg SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, 639a88b5ba8SSam Ravnborg 640a88b5ba8SSam Ravnborg /* Onboard devices (not relevant/used on SunFire). */ 641a88b5ba8SSam Ravnborg SYSIO_IMAP_SCSI, 642a88b5ba8SSam Ravnborg SYSIO_IMAP_ETH, 643a88b5ba8SSam Ravnborg SYSIO_IMAP_BPP, 644a88b5ba8SSam Ravnborg bogon, 645a88b5ba8SSam Ravnborg SYSIO_IMAP_AUDIO, 646a88b5ba8SSam Ravnborg SYSIO_IMAP_PFAIL, 647a88b5ba8SSam Ravnborg bogon, 648a88b5ba8SSam Ravnborg bogon, 649a88b5ba8SSam Ravnborg SYSIO_IMAP_KMS, 650a88b5ba8SSam Ravnborg SYSIO_IMAP_FLPY, 651a88b5ba8SSam Ravnborg SYSIO_IMAP_SHW, 652a88b5ba8SSam Ravnborg SYSIO_IMAP_KBD, 653a88b5ba8SSam Ravnborg SYSIO_IMAP_MS, 654a88b5ba8SSam Ravnborg SYSIO_IMAP_SER, 655a88b5ba8SSam Ravnborg bogon, 656a88b5ba8SSam Ravnborg bogon, 657a88b5ba8SSam Ravnborg SYSIO_IMAP_TIM0, 658a88b5ba8SSam Ravnborg SYSIO_IMAP_TIM1, 659a88b5ba8SSam Ravnborg bogon, 660a88b5ba8SSam Ravnborg bogon, 661a88b5ba8SSam Ravnborg SYSIO_IMAP_UE, 662a88b5ba8SSam Ravnborg SYSIO_IMAP_CE, 663a88b5ba8SSam Ravnborg SYSIO_IMAP_SBERR, 664a88b5ba8SSam Ravnborg SYSIO_IMAP_PMGMT, 665a88b5ba8SSam Ravnborg SYSIO_IMAP_GFX, 666a88b5ba8SSam Ravnborg SYSIO_IMAP_EUPA, 667a88b5ba8SSam Ravnborg }; 668a88b5ba8SSam Ravnborg 669a88b5ba8SSam Ravnborg #undef bogon 670a88b5ba8SSam Ravnborg 671a88b5ba8SSam Ravnborg #define NUM_SYSIO_OFFSETS ARRAY_SIZE(sysio_irq_offsets) 672a88b5ba8SSam Ravnborg 673a88b5ba8SSam Ravnborg /* Convert Interrupt Mapping register pointer to associated 674a88b5ba8SSam Ravnborg * Interrupt Clear register pointer, SYSIO specific version. 675a88b5ba8SSam Ravnborg */ 676a88b5ba8SSam Ravnborg #define SYSIO_ICLR_UNUSED0 0x3400UL 677a88b5ba8SSam Ravnborg #define SYSIO_ICLR_SLOT0 0x3408UL 678a88b5ba8SSam Ravnborg #define SYSIO_ICLR_SLOT1 0x3448UL 679a88b5ba8SSam Ravnborg #define SYSIO_ICLR_SLOT2 0x3488UL 680a88b5ba8SSam Ravnborg #define SYSIO_ICLR_SLOT3 0x34c8UL 681a88b5ba8SSam Ravnborg static unsigned long sysio_imap_to_iclr(unsigned long imap) 682a88b5ba8SSam Ravnborg { 683a88b5ba8SSam Ravnborg unsigned long diff = SYSIO_ICLR_UNUSED0 - SYSIO_IMAP_SLOT0; 684a88b5ba8SSam Ravnborg return imap + diff; 685a88b5ba8SSam Ravnborg } 686a88b5ba8SSam Ravnborg 687a88b5ba8SSam Ravnborg static unsigned int sbus_of_build_irq(struct device_node *dp, 688a88b5ba8SSam Ravnborg unsigned int ino, 689a88b5ba8SSam Ravnborg void *_data) 690a88b5ba8SSam Ravnborg { 691a88b5ba8SSam Ravnborg unsigned long reg_base = (unsigned long) _data; 692a88b5ba8SSam Ravnborg const struct linux_prom_registers *regs; 693a88b5ba8SSam Ravnborg unsigned long imap, iclr; 694a88b5ba8SSam Ravnborg int sbus_slot = 0; 695a88b5ba8SSam Ravnborg int sbus_level = 0; 696a88b5ba8SSam Ravnborg 697a88b5ba8SSam Ravnborg ino &= 0x3f; 698a88b5ba8SSam Ravnborg 699a88b5ba8SSam Ravnborg regs = of_get_property(dp, "reg", NULL); 700a88b5ba8SSam Ravnborg if (regs) 701a88b5ba8SSam Ravnborg sbus_slot = regs->which_io; 702a88b5ba8SSam Ravnborg 703a88b5ba8SSam Ravnborg if (ino < 0x20) 704a88b5ba8SSam Ravnborg ino += (sbus_slot * 8); 705a88b5ba8SSam Ravnborg 706a88b5ba8SSam Ravnborg imap = sysio_irq_offsets[ino]; 707a88b5ba8SSam Ravnborg if (imap == ((unsigned long)-1)) { 708a88b5ba8SSam Ravnborg prom_printf("get_irq_translations: Bad SYSIO INO[%x]\n", 709a88b5ba8SSam Ravnborg ino); 710a88b5ba8SSam Ravnborg prom_halt(); 711a88b5ba8SSam Ravnborg } 712a88b5ba8SSam Ravnborg imap += reg_base; 713a88b5ba8SSam Ravnborg 714a88b5ba8SSam Ravnborg /* SYSIO inconsistency. For external SLOTS, we have to select 715a88b5ba8SSam Ravnborg * the right ICLR register based upon the lower SBUS irq level 716a88b5ba8SSam Ravnborg * bits. 717a88b5ba8SSam Ravnborg */ 718a88b5ba8SSam Ravnborg if (ino >= 0x20) { 719a88b5ba8SSam Ravnborg iclr = sysio_imap_to_iclr(imap); 720a88b5ba8SSam Ravnborg } else { 721a88b5ba8SSam Ravnborg sbus_level = ino & 0x7; 722a88b5ba8SSam Ravnborg 723a88b5ba8SSam Ravnborg switch(sbus_slot) { 724a88b5ba8SSam Ravnborg case 0: 725a88b5ba8SSam Ravnborg iclr = reg_base + SYSIO_ICLR_SLOT0; 726a88b5ba8SSam Ravnborg break; 727a88b5ba8SSam Ravnborg case 1: 728a88b5ba8SSam Ravnborg iclr = reg_base + SYSIO_ICLR_SLOT1; 729a88b5ba8SSam Ravnborg break; 730a88b5ba8SSam Ravnborg case 2: 731a88b5ba8SSam Ravnborg iclr = reg_base + SYSIO_ICLR_SLOT2; 732a88b5ba8SSam Ravnborg break; 733a88b5ba8SSam Ravnborg default: 734a88b5ba8SSam Ravnborg case 3: 735a88b5ba8SSam Ravnborg iclr = reg_base + SYSIO_ICLR_SLOT3; 736a88b5ba8SSam Ravnborg break; 737a88b5ba8SSam Ravnborg }; 738a88b5ba8SSam Ravnborg 739a88b5ba8SSam Ravnborg iclr += ((unsigned long)sbus_level - 1UL) * 8UL; 740a88b5ba8SSam Ravnborg } 741a88b5ba8SSam Ravnborg return build_irq(sbus_level, iclr, imap); 742a88b5ba8SSam Ravnborg } 743a88b5ba8SSam Ravnborg 744a88b5ba8SSam Ravnborg static void __init sbus_irq_trans_init(struct device_node *dp) 745a88b5ba8SSam Ravnborg { 746a88b5ba8SSam Ravnborg const struct linux_prom64_registers *regs; 747a88b5ba8SSam Ravnborg 748a88b5ba8SSam Ravnborg dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); 749a88b5ba8SSam Ravnborg dp->irq_trans->irq_build = sbus_of_build_irq; 750a88b5ba8SSam Ravnborg 751a88b5ba8SSam Ravnborg regs = of_get_property(dp, "reg", NULL); 752a88b5ba8SSam Ravnborg dp->irq_trans->data = (void *) (unsigned long) regs->phys_addr; 753a88b5ba8SSam Ravnborg } 754a88b5ba8SSam Ravnborg #endif /* CONFIG_SBUS */ 755a88b5ba8SSam Ravnborg 756a88b5ba8SSam Ravnborg 757a88b5ba8SSam Ravnborg static unsigned int central_build_irq(struct device_node *dp, 758a88b5ba8SSam Ravnborg unsigned int ino, 759a88b5ba8SSam Ravnborg void *_data) 760a88b5ba8SSam Ravnborg { 761a88b5ba8SSam Ravnborg struct device_node *central_dp = _data; 762a88b5ba8SSam Ravnborg struct of_device *central_op = of_find_device_by_node(central_dp); 763a88b5ba8SSam Ravnborg struct resource *res; 764a88b5ba8SSam Ravnborg unsigned long imap, iclr; 765a88b5ba8SSam Ravnborg u32 tmp; 766a88b5ba8SSam Ravnborg 767a88b5ba8SSam Ravnborg if (!strcmp(dp->name, "eeprom")) { 768a88b5ba8SSam Ravnborg res = ¢ral_op->resource[5]; 769a88b5ba8SSam Ravnborg } else if (!strcmp(dp->name, "zs")) { 770a88b5ba8SSam Ravnborg res = ¢ral_op->resource[4]; 771a88b5ba8SSam Ravnborg } else if (!strcmp(dp->name, "clock-board")) { 772a88b5ba8SSam Ravnborg res = ¢ral_op->resource[3]; 773a88b5ba8SSam Ravnborg } else { 774a88b5ba8SSam Ravnborg return ino; 775a88b5ba8SSam Ravnborg } 776a88b5ba8SSam Ravnborg 777a88b5ba8SSam Ravnborg imap = res->start + 0x00UL; 778a88b5ba8SSam Ravnborg iclr = res->start + 0x10UL; 779a88b5ba8SSam Ravnborg 780a88b5ba8SSam Ravnborg /* Set the INO state to idle, and disable. */ 781a88b5ba8SSam Ravnborg upa_writel(0, iclr); 782a88b5ba8SSam Ravnborg upa_readl(iclr); 783a88b5ba8SSam Ravnborg 784a88b5ba8SSam Ravnborg tmp = upa_readl(imap); 785a88b5ba8SSam Ravnborg tmp &= ~0x80000000; 786a88b5ba8SSam Ravnborg upa_writel(tmp, imap); 787a88b5ba8SSam Ravnborg 788a88b5ba8SSam Ravnborg return build_irq(0, iclr, imap); 789a88b5ba8SSam Ravnborg } 790a88b5ba8SSam Ravnborg 791a88b5ba8SSam Ravnborg static void __init central_irq_trans_init(struct device_node *dp) 792a88b5ba8SSam Ravnborg { 793a88b5ba8SSam Ravnborg dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); 794a88b5ba8SSam Ravnborg dp->irq_trans->irq_build = central_build_irq; 795a88b5ba8SSam Ravnborg 796a88b5ba8SSam Ravnborg dp->irq_trans->data = dp; 797a88b5ba8SSam Ravnborg } 798a88b5ba8SSam Ravnborg 799a88b5ba8SSam Ravnborg struct irq_trans { 800a88b5ba8SSam Ravnborg const char *name; 801a88b5ba8SSam Ravnborg void (*init)(struct device_node *); 802a88b5ba8SSam Ravnborg }; 803a88b5ba8SSam Ravnborg 804a88b5ba8SSam Ravnborg #ifdef CONFIG_PCI 805a88b5ba8SSam Ravnborg static struct irq_trans __initdata pci_irq_trans_table[] = { 806a88b5ba8SSam Ravnborg { "SUNW,sabre", sabre_irq_trans_init }, 807a88b5ba8SSam Ravnborg { "pci108e,a000", sabre_irq_trans_init }, 808a88b5ba8SSam Ravnborg { "pci108e,a001", sabre_irq_trans_init }, 809a88b5ba8SSam Ravnborg { "SUNW,psycho", psycho_irq_trans_init }, 810a88b5ba8SSam Ravnborg { "pci108e,8000", psycho_irq_trans_init }, 811a88b5ba8SSam Ravnborg { "SUNW,schizo", schizo_irq_trans_init }, 812a88b5ba8SSam Ravnborg { "pci108e,8001", schizo_irq_trans_init }, 813a88b5ba8SSam Ravnborg { "SUNW,schizo+", schizo_irq_trans_init }, 814a88b5ba8SSam Ravnborg { "pci108e,8002", schizo_irq_trans_init }, 815a88b5ba8SSam Ravnborg { "SUNW,tomatillo", tomatillo_irq_trans_init }, 816a88b5ba8SSam Ravnborg { "pci108e,a801", tomatillo_irq_trans_init }, 817a88b5ba8SSam Ravnborg { "SUNW,sun4v-pci", pci_sun4v_irq_trans_init }, 818a88b5ba8SSam Ravnborg { "pciex108e,80f0", fire_irq_trans_init }, 819a88b5ba8SSam Ravnborg }; 820a88b5ba8SSam Ravnborg #endif 821a88b5ba8SSam Ravnborg 822a88b5ba8SSam Ravnborg static unsigned int sun4v_vdev_irq_build(struct device_node *dp, 823a88b5ba8SSam Ravnborg unsigned int devino, 824a88b5ba8SSam Ravnborg void *_data) 825a88b5ba8SSam Ravnborg { 826a88b5ba8SSam Ravnborg u32 devhandle = (u32) (unsigned long) _data; 827a88b5ba8SSam Ravnborg 828a88b5ba8SSam Ravnborg return sun4v_build_irq(devhandle, devino); 829a88b5ba8SSam Ravnborg } 830a88b5ba8SSam Ravnborg 831a88b5ba8SSam Ravnborg static void __init sun4v_vdev_irq_trans_init(struct device_node *dp) 832a88b5ba8SSam Ravnborg { 833a88b5ba8SSam Ravnborg const struct linux_prom64_registers *regs; 834a88b5ba8SSam Ravnborg 835a88b5ba8SSam Ravnborg dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); 836a88b5ba8SSam Ravnborg dp->irq_trans->irq_build = sun4v_vdev_irq_build; 837a88b5ba8SSam Ravnborg 838a88b5ba8SSam Ravnborg regs = of_get_property(dp, "reg", NULL); 839a88b5ba8SSam Ravnborg dp->irq_trans->data = (void *) (unsigned long) 840a88b5ba8SSam Ravnborg ((regs->phys_addr >> 32UL) & 0x0fffffff); 841a88b5ba8SSam Ravnborg } 842a88b5ba8SSam Ravnborg 843a88b5ba8SSam Ravnborg static void __init irq_trans_init(struct device_node *dp) 844a88b5ba8SSam Ravnborg { 845a88b5ba8SSam Ravnborg #ifdef CONFIG_PCI 846a88b5ba8SSam Ravnborg const char *model; 847a88b5ba8SSam Ravnborg int i; 848a88b5ba8SSam Ravnborg #endif 849a88b5ba8SSam Ravnborg 850a88b5ba8SSam Ravnborg #ifdef CONFIG_PCI 851a88b5ba8SSam Ravnborg model = of_get_property(dp, "model", NULL); 852a88b5ba8SSam Ravnborg if (!model) 853a88b5ba8SSam Ravnborg model = of_get_property(dp, "compatible", NULL); 854a88b5ba8SSam Ravnborg if (model) { 855a88b5ba8SSam Ravnborg for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) { 856a88b5ba8SSam Ravnborg struct irq_trans *t = &pci_irq_trans_table[i]; 857a88b5ba8SSam Ravnborg 858a88b5ba8SSam Ravnborg if (!strcmp(model, t->name)) { 859a88b5ba8SSam Ravnborg t->init(dp); 860a88b5ba8SSam Ravnborg return; 861a88b5ba8SSam Ravnborg } 862a88b5ba8SSam Ravnborg } 863a88b5ba8SSam Ravnborg } 864a88b5ba8SSam Ravnborg #endif 865a88b5ba8SSam Ravnborg #ifdef CONFIG_SBUS 866a88b5ba8SSam Ravnborg if (!strcmp(dp->name, "sbus") || 867a88b5ba8SSam Ravnborg !strcmp(dp->name, "sbi")) { 868a88b5ba8SSam Ravnborg sbus_irq_trans_init(dp); 869a88b5ba8SSam Ravnborg return; 870a88b5ba8SSam Ravnborg } 871a88b5ba8SSam Ravnborg #endif 872a88b5ba8SSam Ravnborg if (!strcmp(dp->name, "fhc") && 873a88b5ba8SSam Ravnborg !strcmp(dp->parent->name, "central")) { 874a88b5ba8SSam Ravnborg central_irq_trans_init(dp); 875a88b5ba8SSam Ravnborg return; 876a88b5ba8SSam Ravnborg } 877a88b5ba8SSam Ravnborg if (!strcmp(dp->name, "virtual-devices") || 878a88b5ba8SSam Ravnborg !strcmp(dp->name, "niu")) { 879a88b5ba8SSam Ravnborg sun4v_vdev_irq_trans_init(dp); 880a88b5ba8SSam Ravnborg return; 881a88b5ba8SSam Ravnborg } 882a88b5ba8SSam Ravnborg } 883a88b5ba8SSam Ravnborg 884a88b5ba8SSam Ravnborg static int is_root_node(const struct device_node *dp) 885a88b5ba8SSam Ravnborg { 886a88b5ba8SSam Ravnborg if (!dp) 887a88b5ba8SSam Ravnborg return 0; 888a88b5ba8SSam Ravnborg 889a88b5ba8SSam Ravnborg return (dp->parent == NULL); 890a88b5ba8SSam Ravnborg } 891a88b5ba8SSam Ravnborg 892a88b5ba8SSam Ravnborg /* The following routines deal with the black magic of fully naming a 893a88b5ba8SSam Ravnborg * node. 894a88b5ba8SSam Ravnborg * 895a88b5ba8SSam Ravnborg * Certain well known named nodes are just the simple name string. 896a88b5ba8SSam Ravnborg * 897a88b5ba8SSam Ravnborg * Actual devices have an address specifier appended to the base name 898a88b5ba8SSam Ravnborg * string, like this "foo@addr". The "addr" can be in any number of 899a88b5ba8SSam Ravnborg * formats, and the platform plus the type of the node determine the 900a88b5ba8SSam Ravnborg * format and how it is constructed. 901a88b5ba8SSam Ravnborg * 902a88b5ba8SSam Ravnborg * For children of the ROOT node, the naming convention is fixed and 903a88b5ba8SSam Ravnborg * determined by whether this is a sun4u or sun4v system. 904a88b5ba8SSam Ravnborg * 905a88b5ba8SSam Ravnborg * For children of other nodes, it is bus type specific. So 906a88b5ba8SSam Ravnborg * we walk up the tree until we discover a "device_type" property 907a88b5ba8SSam Ravnborg * we recognize and we go from there. 908a88b5ba8SSam Ravnborg * 909a88b5ba8SSam Ravnborg * As an example, the boot device on my workstation has a full path: 910a88b5ba8SSam Ravnborg * 911a88b5ba8SSam Ravnborg * /pci@1e,600000/ide@d/disk@0,0:c 912a88b5ba8SSam Ravnborg */ 913a88b5ba8SSam Ravnborg static void __init sun4v_path_component(struct device_node *dp, char *tmp_buf) 914a88b5ba8SSam Ravnborg { 915a88b5ba8SSam Ravnborg struct linux_prom64_registers *regs; 916a88b5ba8SSam Ravnborg struct property *rprop; 917a88b5ba8SSam Ravnborg u32 high_bits, low_bits, type; 918a88b5ba8SSam Ravnborg 919a88b5ba8SSam Ravnborg rprop = of_find_property(dp, "reg", NULL); 920a88b5ba8SSam Ravnborg if (!rprop) 921a88b5ba8SSam Ravnborg return; 922a88b5ba8SSam Ravnborg 923a88b5ba8SSam Ravnborg regs = rprop->value; 924a88b5ba8SSam Ravnborg if (!is_root_node(dp->parent)) { 925a88b5ba8SSam Ravnborg sprintf(tmp_buf, "%s@%x,%x", 926a88b5ba8SSam Ravnborg dp->name, 927a88b5ba8SSam Ravnborg (unsigned int) (regs->phys_addr >> 32UL), 928a88b5ba8SSam Ravnborg (unsigned int) (regs->phys_addr & 0xffffffffUL)); 929a88b5ba8SSam Ravnborg return; 930a88b5ba8SSam Ravnborg } 931a88b5ba8SSam Ravnborg 932a88b5ba8SSam Ravnborg type = regs->phys_addr >> 60UL; 933a88b5ba8SSam Ravnborg high_bits = (regs->phys_addr >> 32UL) & 0x0fffffffUL; 934a88b5ba8SSam Ravnborg low_bits = (regs->phys_addr & 0xffffffffUL); 935a88b5ba8SSam Ravnborg 936a88b5ba8SSam Ravnborg if (type == 0 || type == 8) { 937a88b5ba8SSam Ravnborg const char *prefix = (type == 0) ? "m" : "i"; 938a88b5ba8SSam Ravnborg 939a88b5ba8SSam Ravnborg if (low_bits) 940a88b5ba8SSam Ravnborg sprintf(tmp_buf, "%s@%s%x,%x", 941a88b5ba8SSam Ravnborg dp->name, prefix, 942a88b5ba8SSam Ravnborg high_bits, low_bits); 943a88b5ba8SSam Ravnborg else 944a88b5ba8SSam Ravnborg sprintf(tmp_buf, "%s@%s%x", 945a88b5ba8SSam Ravnborg dp->name, 946a88b5ba8SSam Ravnborg prefix, 947a88b5ba8SSam Ravnborg high_bits); 948a88b5ba8SSam Ravnborg } else if (type == 12) { 949a88b5ba8SSam Ravnborg sprintf(tmp_buf, "%s@%x", 950a88b5ba8SSam Ravnborg dp->name, high_bits); 951a88b5ba8SSam Ravnborg } 952a88b5ba8SSam Ravnborg } 953a88b5ba8SSam Ravnborg 954a88b5ba8SSam Ravnborg static void __init sun4u_path_component(struct device_node *dp, char *tmp_buf) 955a88b5ba8SSam Ravnborg { 956a88b5ba8SSam Ravnborg struct linux_prom64_registers *regs; 957a88b5ba8SSam Ravnborg struct property *prop; 958a88b5ba8SSam Ravnborg 959a88b5ba8SSam Ravnborg prop = of_find_property(dp, "reg", NULL); 960a88b5ba8SSam Ravnborg if (!prop) 961a88b5ba8SSam Ravnborg return; 962a88b5ba8SSam Ravnborg 963a88b5ba8SSam Ravnborg regs = prop->value; 964a88b5ba8SSam Ravnborg if (!is_root_node(dp->parent)) { 965a88b5ba8SSam Ravnborg sprintf(tmp_buf, "%s@%x,%x", 966a88b5ba8SSam Ravnborg dp->name, 967a88b5ba8SSam Ravnborg (unsigned int) (regs->phys_addr >> 32UL), 968a88b5ba8SSam Ravnborg (unsigned int) (regs->phys_addr & 0xffffffffUL)); 969a88b5ba8SSam Ravnborg return; 970a88b5ba8SSam Ravnborg } 971a88b5ba8SSam Ravnborg 972a88b5ba8SSam Ravnborg prop = of_find_property(dp, "upa-portid", NULL); 973a88b5ba8SSam Ravnborg if (!prop) 974a88b5ba8SSam Ravnborg prop = of_find_property(dp, "portid", NULL); 975a88b5ba8SSam Ravnborg if (prop) { 976a88b5ba8SSam Ravnborg unsigned long mask = 0xffffffffUL; 977a88b5ba8SSam Ravnborg 978a88b5ba8SSam Ravnborg if (tlb_type >= cheetah) 979a88b5ba8SSam Ravnborg mask = 0x7fffff; 980a88b5ba8SSam Ravnborg 981a88b5ba8SSam Ravnborg sprintf(tmp_buf, "%s@%x,%x", 982a88b5ba8SSam Ravnborg dp->name, 983a88b5ba8SSam Ravnborg *(u32 *)prop->value, 984a88b5ba8SSam Ravnborg (unsigned int) (regs->phys_addr & mask)); 985a88b5ba8SSam Ravnborg } 986a88b5ba8SSam Ravnborg } 987a88b5ba8SSam Ravnborg 988a88b5ba8SSam Ravnborg /* "name@slot,offset" */ 989a88b5ba8SSam Ravnborg static void __init sbus_path_component(struct device_node *dp, char *tmp_buf) 990a88b5ba8SSam Ravnborg { 991a88b5ba8SSam Ravnborg struct linux_prom_registers *regs; 992a88b5ba8SSam Ravnborg struct property *prop; 993a88b5ba8SSam Ravnborg 994a88b5ba8SSam Ravnborg prop = of_find_property(dp, "reg", NULL); 995a88b5ba8SSam Ravnborg if (!prop) 996a88b5ba8SSam Ravnborg return; 997a88b5ba8SSam Ravnborg 998a88b5ba8SSam Ravnborg regs = prop->value; 999a88b5ba8SSam Ravnborg sprintf(tmp_buf, "%s@%x,%x", 1000a88b5ba8SSam Ravnborg dp->name, 1001a88b5ba8SSam Ravnborg regs->which_io, 1002a88b5ba8SSam Ravnborg regs->phys_addr); 1003a88b5ba8SSam Ravnborg } 1004a88b5ba8SSam Ravnborg 1005a88b5ba8SSam Ravnborg /* "name@devnum[,func]" */ 1006a88b5ba8SSam Ravnborg static void __init pci_path_component(struct device_node *dp, char *tmp_buf) 1007a88b5ba8SSam Ravnborg { 1008a88b5ba8SSam Ravnborg struct linux_prom_pci_registers *regs; 1009a88b5ba8SSam Ravnborg struct property *prop; 1010a88b5ba8SSam Ravnborg unsigned int devfn; 1011a88b5ba8SSam Ravnborg 1012a88b5ba8SSam Ravnborg prop = of_find_property(dp, "reg", NULL); 1013a88b5ba8SSam Ravnborg if (!prop) 1014a88b5ba8SSam Ravnborg return; 1015a88b5ba8SSam Ravnborg 1016a88b5ba8SSam Ravnborg regs = prop->value; 1017a88b5ba8SSam Ravnborg devfn = (regs->phys_hi >> 8) & 0xff; 1018a88b5ba8SSam Ravnborg if (devfn & 0x07) { 1019a88b5ba8SSam Ravnborg sprintf(tmp_buf, "%s@%x,%x", 1020a88b5ba8SSam Ravnborg dp->name, 1021a88b5ba8SSam Ravnborg devfn >> 3, 1022a88b5ba8SSam Ravnborg devfn & 0x07); 1023a88b5ba8SSam Ravnborg } else { 1024a88b5ba8SSam Ravnborg sprintf(tmp_buf, "%s@%x", 1025a88b5ba8SSam Ravnborg dp->name, 1026a88b5ba8SSam Ravnborg devfn >> 3); 1027a88b5ba8SSam Ravnborg } 1028a88b5ba8SSam Ravnborg } 1029a88b5ba8SSam Ravnborg 1030a88b5ba8SSam Ravnborg /* "name@UPA_PORTID,offset" */ 1031a88b5ba8SSam Ravnborg static void __init upa_path_component(struct device_node *dp, char *tmp_buf) 1032a88b5ba8SSam Ravnborg { 1033a88b5ba8SSam Ravnborg struct linux_prom64_registers *regs; 1034a88b5ba8SSam Ravnborg struct property *prop; 1035a88b5ba8SSam Ravnborg 1036a88b5ba8SSam Ravnborg prop = of_find_property(dp, "reg", NULL); 1037a88b5ba8SSam Ravnborg if (!prop) 1038a88b5ba8SSam Ravnborg return; 1039a88b5ba8SSam Ravnborg 1040a88b5ba8SSam Ravnborg regs = prop->value; 1041a88b5ba8SSam Ravnborg 1042a88b5ba8SSam Ravnborg prop = of_find_property(dp, "upa-portid", NULL); 1043a88b5ba8SSam Ravnborg if (!prop) 1044a88b5ba8SSam Ravnborg return; 1045a88b5ba8SSam Ravnborg 1046a88b5ba8SSam Ravnborg sprintf(tmp_buf, "%s@%x,%x", 1047a88b5ba8SSam Ravnborg dp->name, 1048a88b5ba8SSam Ravnborg *(u32 *) prop->value, 1049a88b5ba8SSam Ravnborg (unsigned int) (regs->phys_addr & 0xffffffffUL)); 1050a88b5ba8SSam Ravnborg } 1051a88b5ba8SSam Ravnborg 1052a88b5ba8SSam Ravnborg /* "name@reg" */ 1053a88b5ba8SSam Ravnborg static void __init vdev_path_component(struct device_node *dp, char *tmp_buf) 1054a88b5ba8SSam Ravnborg { 1055a88b5ba8SSam Ravnborg struct property *prop; 1056a88b5ba8SSam Ravnborg u32 *regs; 1057a88b5ba8SSam Ravnborg 1058a88b5ba8SSam Ravnborg prop = of_find_property(dp, "reg", NULL); 1059a88b5ba8SSam Ravnborg if (!prop) 1060a88b5ba8SSam Ravnborg return; 1061a88b5ba8SSam Ravnborg 1062a88b5ba8SSam Ravnborg regs = prop->value; 1063a88b5ba8SSam Ravnborg 1064a88b5ba8SSam Ravnborg sprintf(tmp_buf, "%s@%x", dp->name, *regs); 1065a88b5ba8SSam Ravnborg } 1066a88b5ba8SSam Ravnborg 1067a88b5ba8SSam Ravnborg /* "name@addrhi,addrlo" */ 1068a88b5ba8SSam Ravnborg static void __init ebus_path_component(struct device_node *dp, char *tmp_buf) 1069a88b5ba8SSam Ravnborg { 1070a88b5ba8SSam Ravnborg struct linux_prom64_registers *regs; 1071a88b5ba8SSam Ravnborg struct property *prop; 1072a88b5ba8SSam Ravnborg 1073a88b5ba8SSam Ravnborg prop = of_find_property(dp, "reg", NULL); 1074a88b5ba8SSam Ravnborg if (!prop) 1075a88b5ba8SSam Ravnborg return; 1076a88b5ba8SSam Ravnborg 1077a88b5ba8SSam Ravnborg regs = prop->value; 1078a88b5ba8SSam Ravnborg 1079a88b5ba8SSam Ravnborg sprintf(tmp_buf, "%s@%x,%x", 1080a88b5ba8SSam Ravnborg dp->name, 1081a88b5ba8SSam Ravnborg (unsigned int) (regs->phys_addr >> 32UL), 1082a88b5ba8SSam Ravnborg (unsigned int) (regs->phys_addr & 0xffffffffUL)); 1083a88b5ba8SSam Ravnborg } 1084a88b5ba8SSam Ravnborg 1085a88b5ba8SSam Ravnborg /* "name@bus,addr" */ 1086a88b5ba8SSam Ravnborg static void __init i2c_path_component(struct device_node *dp, char *tmp_buf) 1087a88b5ba8SSam Ravnborg { 1088a88b5ba8SSam Ravnborg struct property *prop; 1089a88b5ba8SSam Ravnborg u32 *regs; 1090a88b5ba8SSam Ravnborg 1091a88b5ba8SSam Ravnborg prop = of_find_property(dp, "reg", NULL); 1092a88b5ba8SSam Ravnborg if (!prop) 1093a88b5ba8SSam Ravnborg return; 1094a88b5ba8SSam Ravnborg 1095a88b5ba8SSam Ravnborg regs = prop->value; 1096a88b5ba8SSam Ravnborg 1097a88b5ba8SSam Ravnborg /* This actually isn't right... should look at the #address-cells 1098a88b5ba8SSam Ravnborg * property of the i2c bus node etc. etc. 1099a88b5ba8SSam Ravnborg */ 1100a88b5ba8SSam Ravnborg sprintf(tmp_buf, "%s@%x,%x", 1101a88b5ba8SSam Ravnborg dp->name, regs[0], regs[1]); 1102a88b5ba8SSam Ravnborg } 1103a88b5ba8SSam Ravnborg 1104a88b5ba8SSam Ravnborg /* "name@reg0[,reg1]" */ 1105a88b5ba8SSam Ravnborg static void __init usb_path_component(struct device_node *dp, char *tmp_buf) 1106a88b5ba8SSam Ravnborg { 1107a88b5ba8SSam Ravnborg struct property *prop; 1108a88b5ba8SSam Ravnborg u32 *regs; 1109a88b5ba8SSam Ravnborg 1110a88b5ba8SSam Ravnborg prop = of_find_property(dp, "reg", NULL); 1111a88b5ba8SSam Ravnborg if (!prop) 1112a88b5ba8SSam Ravnborg return; 1113a88b5ba8SSam Ravnborg 1114a88b5ba8SSam Ravnborg regs = prop->value; 1115a88b5ba8SSam Ravnborg 1116a88b5ba8SSam Ravnborg if (prop->length == sizeof(u32) || regs[1] == 1) { 1117a88b5ba8SSam Ravnborg sprintf(tmp_buf, "%s@%x", 1118a88b5ba8SSam Ravnborg dp->name, regs[0]); 1119a88b5ba8SSam Ravnborg } else { 1120a88b5ba8SSam Ravnborg sprintf(tmp_buf, "%s@%x,%x", 1121a88b5ba8SSam Ravnborg dp->name, regs[0], regs[1]); 1122a88b5ba8SSam Ravnborg } 1123a88b5ba8SSam Ravnborg } 1124a88b5ba8SSam Ravnborg 1125a88b5ba8SSam Ravnborg /* "name@reg0reg1[,reg2reg3]" */ 1126a88b5ba8SSam Ravnborg static void __init ieee1394_path_component(struct device_node *dp, char *tmp_buf) 1127a88b5ba8SSam Ravnborg { 1128a88b5ba8SSam Ravnborg struct property *prop; 1129a88b5ba8SSam Ravnborg u32 *regs; 1130a88b5ba8SSam Ravnborg 1131a88b5ba8SSam Ravnborg prop = of_find_property(dp, "reg", NULL); 1132a88b5ba8SSam Ravnborg if (!prop) 1133a88b5ba8SSam Ravnborg return; 1134a88b5ba8SSam Ravnborg 1135a88b5ba8SSam Ravnborg regs = prop->value; 1136a88b5ba8SSam Ravnborg 1137a88b5ba8SSam Ravnborg if (regs[2] || regs[3]) { 1138a88b5ba8SSam Ravnborg sprintf(tmp_buf, "%s@%08x%08x,%04x%08x", 1139a88b5ba8SSam Ravnborg dp->name, regs[0], regs[1], regs[2], regs[3]); 1140a88b5ba8SSam Ravnborg } else { 1141a88b5ba8SSam Ravnborg sprintf(tmp_buf, "%s@%08x%08x", 1142a88b5ba8SSam Ravnborg dp->name, regs[0], regs[1]); 1143a88b5ba8SSam Ravnborg } 1144a88b5ba8SSam Ravnborg } 1145a88b5ba8SSam Ravnborg 1146a88b5ba8SSam Ravnborg static void __init __build_path_component(struct device_node *dp, char *tmp_buf) 1147a88b5ba8SSam Ravnborg { 1148a88b5ba8SSam Ravnborg struct device_node *parent = dp->parent; 1149a88b5ba8SSam Ravnborg 1150a88b5ba8SSam Ravnborg if (parent != NULL) { 1151a88b5ba8SSam Ravnborg if (!strcmp(parent->type, "pci") || 1152a88b5ba8SSam Ravnborg !strcmp(parent->type, "pciex")) { 1153a88b5ba8SSam Ravnborg pci_path_component(dp, tmp_buf); 1154a88b5ba8SSam Ravnborg return; 1155a88b5ba8SSam Ravnborg } 1156a88b5ba8SSam Ravnborg if (!strcmp(parent->type, "sbus")) { 1157a88b5ba8SSam Ravnborg sbus_path_component(dp, tmp_buf); 1158a88b5ba8SSam Ravnborg return; 1159a88b5ba8SSam Ravnborg } 1160a88b5ba8SSam Ravnborg if (!strcmp(parent->type, "upa")) { 1161a88b5ba8SSam Ravnborg upa_path_component(dp, tmp_buf); 1162a88b5ba8SSam Ravnborg return; 1163a88b5ba8SSam Ravnborg } 1164a88b5ba8SSam Ravnborg if (!strcmp(parent->type, "ebus")) { 1165a88b5ba8SSam Ravnborg ebus_path_component(dp, tmp_buf); 1166a88b5ba8SSam Ravnborg return; 1167a88b5ba8SSam Ravnborg } 1168a88b5ba8SSam Ravnborg if (!strcmp(parent->name, "usb") || 1169a88b5ba8SSam Ravnborg !strcmp(parent->name, "hub")) { 1170a88b5ba8SSam Ravnborg usb_path_component(dp, tmp_buf); 1171a88b5ba8SSam Ravnborg return; 1172a88b5ba8SSam Ravnborg } 1173a88b5ba8SSam Ravnborg if (!strcmp(parent->type, "i2c")) { 1174a88b5ba8SSam Ravnborg i2c_path_component(dp, tmp_buf); 1175a88b5ba8SSam Ravnborg return; 1176a88b5ba8SSam Ravnborg } 1177a88b5ba8SSam Ravnborg if (!strcmp(parent->type, "firewire")) { 1178a88b5ba8SSam Ravnborg ieee1394_path_component(dp, tmp_buf); 1179a88b5ba8SSam Ravnborg return; 1180a88b5ba8SSam Ravnborg } 1181a88b5ba8SSam Ravnborg if (!strcmp(parent->type, "virtual-devices")) { 1182a88b5ba8SSam Ravnborg vdev_path_component(dp, tmp_buf); 1183a88b5ba8SSam Ravnborg return; 1184a88b5ba8SSam Ravnborg } 1185a88b5ba8SSam Ravnborg /* "isa" is handled with platform naming */ 1186a88b5ba8SSam Ravnborg } 1187a88b5ba8SSam Ravnborg 1188a88b5ba8SSam Ravnborg /* Use platform naming convention. */ 1189a88b5ba8SSam Ravnborg if (tlb_type == hypervisor) { 1190a88b5ba8SSam Ravnborg sun4v_path_component(dp, tmp_buf); 1191a88b5ba8SSam Ravnborg return; 1192a88b5ba8SSam Ravnborg } else { 1193a88b5ba8SSam Ravnborg sun4u_path_component(dp, tmp_buf); 1194a88b5ba8SSam Ravnborg } 1195a88b5ba8SSam Ravnborg } 1196a88b5ba8SSam Ravnborg 1197a88b5ba8SSam Ravnborg static char * __init build_path_component(struct device_node *dp) 1198a88b5ba8SSam Ravnborg { 1199a88b5ba8SSam Ravnborg char tmp_buf[64], *n; 1200a88b5ba8SSam Ravnborg 1201a88b5ba8SSam Ravnborg tmp_buf[0] = '\0'; 1202a88b5ba8SSam Ravnborg __build_path_component(dp, tmp_buf); 1203a88b5ba8SSam Ravnborg if (tmp_buf[0] == '\0') 1204a88b5ba8SSam Ravnborg strcpy(tmp_buf, dp->name); 1205a88b5ba8SSam Ravnborg 1206a88b5ba8SSam Ravnborg n = prom_early_alloc(strlen(tmp_buf) + 1); 1207a88b5ba8SSam Ravnborg strcpy(n, tmp_buf); 1208a88b5ba8SSam Ravnborg 1209a88b5ba8SSam Ravnborg return n; 1210a88b5ba8SSam Ravnborg } 1211a88b5ba8SSam Ravnborg 1212a88b5ba8SSam Ravnborg static char * __init build_full_name(struct device_node *dp) 1213a88b5ba8SSam Ravnborg { 1214a88b5ba8SSam Ravnborg int len, ourlen, plen; 1215a88b5ba8SSam Ravnborg char *n; 1216a88b5ba8SSam Ravnborg 1217a88b5ba8SSam Ravnborg plen = strlen(dp->parent->full_name); 1218a88b5ba8SSam Ravnborg ourlen = strlen(dp->path_component_name); 1219a88b5ba8SSam Ravnborg len = ourlen + plen + 2; 1220a88b5ba8SSam Ravnborg 1221a88b5ba8SSam Ravnborg n = prom_early_alloc(len); 1222a88b5ba8SSam Ravnborg strcpy(n, dp->parent->full_name); 1223a88b5ba8SSam Ravnborg if (!is_root_node(dp->parent)) { 1224a88b5ba8SSam Ravnborg strcpy(n + plen, "/"); 1225a88b5ba8SSam Ravnborg plen++; 1226a88b5ba8SSam Ravnborg } 1227a88b5ba8SSam Ravnborg strcpy(n + plen, dp->path_component_name); 1228a88b5ba8SSam Ravnborg 1229a88b5ba8SSam Ravnborg return n; 1230a88b5ba8SSam Ravnborg } 1231a88b5ba8SSam Ravnborg 1232a88b5ba8SSam Ravnborg static unsigned int unique_id; 1233a88b5ba8SSam Ravnborg 1234a88b5ba8SSam Ravnborg static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, void *special_val, int special_len) 1235a88b5ba8SSam Ravnborg { 1236a88b5ba8SSam Ravnborg static struct property *tmp = NULL; 1237a88b5ba8SSam Ravnborg struct property *p; 1238a88b5ba8SSam Ravnborg 1239a88b5ba8SSam Ravnborg if (tmp) { 1240a88b5ba8SSam Ravnborg p = tmp; 1241a88b5ba8SSam Ravnborg memset(p, 0, sizeof(*p) + 32); 1242a88b5ba8SSam Ravnborg tmp = NULL; 1243a88b5ba8SSam Ravnborg } else { 1244a88b5ba8SSam Ravnborg p = prom_early_alloc(sizeof(struct property) + 32); 1245a88b5ba8SSam Ravnborg p->unique_id = unique_id++; 1246a88b5ba8SSam Ravnborg } 1247a88b5ba8SSam Ravnborg 1248a88b5ba8SSam Ravnborg p->name = (char *) (p + 1); 1249a88b5ba8SSam Ravnborg if (special_name) { 1250a88b5ba8SSam Ravnborg strcpy(p->name, special_name); 1251a88b5ba8SSam Ravnborg p->length = special_len; 1252a88b5ba8SSam Ravnborg p->value = prom_early_alloc(special_len); 1253a88b5ba8SSam Ravnborg memcpy(p->value, special_val, special_len); 1254a88b5ba8SSam Ravnborg } else { 1255a88b5ba8SSam Ravnborg if (prev == NULL) { 1256a88b5ba8SSam Ravnborg prom_firstprop(node, p->name); 1257a88b5ba8SSam Ravnborg } else { 1258a88b5ba8SSam Ravnborg prom_nextprop(node, prev, p->name); 1259a88b5ba8SSam Ravnborg } 1260a88b5ba8SSam Ravnborg if (strlen(p->name) == 0) { 1261a88b5ba8SSam Ravnborg tmp = p; 1262a88b5ba8SSam Ravnborg return NULL; 1263a88b5ba8SSam Ravnborg } 1264a88b5ba8SSam Ravnborg p->length = prom_getproplen(node, p->name); 1265a88b5ba8SSam Ravnborg if (p->length <= 0) { 1266a88b5ba8SSam Ravnborg p->length = 0; 1267a88b5ba8SSam Ravnborg } else { 1268a88b5ba8SSam Ravnborg p->value = prom_early_alloc(p->length + 1); 1269a88b5ba8SSam Ravnborg prom_getproperty(node, p->name, p->value, p->length); 1270a88b5ba8SSam Ravnborg ((unsigned char *)p->value)[p->length] = '\0'; 1271a88b5ba8SSam Ravnborg } 1272a88b5ba8SSam Ravnborg } 1273a88b5ba8SSam Ravnborg return p; 1274a88b5ba8SSam Ravnborg } 1275a88b5ba8SSam Ravnborg 1276a88b5ba8SSam Ravnborg static struct property * __init build_prop_list(phandle node) 1277a88b5ba8SSam Ravnborg { 1278a88b5ba8SSam Ravnborg struct property *head, *tail; 1279a88b5ba8SSam Ravnborg 1280a88b5ba8SSam Ravnborg head = tail = build_one_prop(node, NULL, 1281a88b5ba8SSam Ravnborg ".node", &node, sizeof(node)); 1282a88b5ba8SSam Ravnborg 1283a88b5ba8SSam Ravnborg tail->next = build_one_prop(node, NULL, NULL, NULL, 0); 1284a88b5ba8SSam Ravnborg tail = tail->next; 1285a88b5ba8SSam Ravnborg while(tail) { 1286a88b5ba8SSam Ravnborg tail->next = build_one_prop(node, tail->name, 1287a88b5ba8SSam Ravnborg NULL, NULL, 0); 1288a88b5ba8SSam Ravnborg tail = tail->next; 1289a88b5ba8SSam Ravnborg } 1290a88b5ba8SSam Ravnborg 1291a88b5ba8SSam Ravnborg return head; 1292a88b5ba8SSam Ravnborg } 1293a88b5ba8SSam Ravnborg 1294a88b5ba8SSam Ravnborg static char * __init get_one_property(phandle node, const char *name) 1295a88b5ba8SSam Ravnborg { 1296a88b5ba8SSam Ravnborg char *buf = "<NULL>"; 1297a88b5ba8SSam Ravnborg int len; 1298a88b5ba8SSam Ravnborg 1299a88b5ba8SSam Ravnborg len = prom_getproplen(node, name); 1300a88b5ba8SSam Ravnborg if (len > 0) { 1301a88b5ba8SSam Ravnborg buf = prom_early_alloc(len); 1302a88b5ba8SSam Ravnborg prom_getproperty(node, name, buf, len); 1303a88b5ba8SSam Ravnborg } 1304a88b5ba8SSam Ravnborg 1305a88b5ba8SSam Ravnborg return buf; 1306a88b5ba8SSam Ravnborg } 1307a88b5ba8SSam Ravnborg 1308a88b5ba8SSam Ravnborg static struct device_node * __init create_node(phandle node, struct device_node *parent) 1309a88b5ba8SSam Ravnborg { 1310a88b5ba8SSam Ravnborg struct device_node *dp; 1311a88b5ba8SSam Ravnborg 1312a88b5ba8SSam Ravnborg if (!node) 1313a88b5ba8SSam Ravnborg return NULL; 1314a88b5ba8SSam Ravnborg 1315a88b5ba8SSam Ravnborg dp = prom_early_alloc(sizeof(*dp)); 1316a88b5ba8SSam Ravnborg dp->unique_id = unique_id++; 1317a88b5ba8SSam Ravnborg dp->parent = parent; 1318a88b5ba8SSam Ravnborg 1319a88b5ba8SSam Ravnborg kref_init(&dp->kref); 1320a88b5ba8SSam Ravnborg 1321a88b5ba8SSam Ravnborg dp->name = get_one_property(node, "name"); 1322a88b5ba8SSam Ravnborg dp->type = get_one_property(node, "device_type"); 1323a88b5ba8SSam Ravnborg dp->node = node; 1324a88b5ba8SSam Ravnborg 1325a88b5ba8SSam Ravnborg dp->properties = build_prop_list(node); 1326a88b5ba8SSam Ravnborg 1327a88b5ba8SSam Ravnborg irq_trans_init(dp); 1328a88b5ba8SSam Ravnborg 1329a88b5ba8SSam Ravnborg return dp; 1330a88b5ba8SSam Ravnborg } 1331a88b5ba8SSam Ravnborg 1332a88b5ba8SSam Ravnborg static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp) 1333a88b5ba8SSam Ravnborg { 1334a88b5ba8SSam Ravnborg struct device_node *ret = NULL, *prev_sibling = NULL; 1335a88b5ba8SSam Ravnborg struct device_node *dp; 1336a88b5ba8SSam Ravnborg 1337a88b5ba8SSam Ravnborg while (1) { 1338a88b5ba8SSam Ravnborg dp = create_node(node, parent); 1339a88b5ba8SSam Ravnborg if (!dp) 1340a88b5ba8SSam Ravnborg break; 1341a88b5ba8SSam Ravnborg 1342a88b5ba8SSam Ravnborg if (prev_sibling) 1343a88b5ba8SSam Ravnborg prev_sibling->sibling = dp; 1344a88b5ba8SSam Ravnborg 1345a88b5ba8SSam Ravnborg if (!ret) 1346a88b5ba8SSam Ravnborg ret = dp; 1347a88b5ba8SSam Ravnborg prev_sibling = dp; 1348a88b5ba8SSam Ravnborg 1349a88b5ba8SSam Ravnborg *(*nextp) = dp; 1350a88b5ba8SSam Ravnborg *nextp = &dp->allnext; 1351a88b5ba8SSam Ravnborg 1352a88b5ba8SSam Ravnborg dp->path_component_name = build_path_component(dp); 1353a88b5ba8SSam Ravnborg dp->full_name = build_full_name(dp); 1354a88b5ba8SSam Ravnborg 1355a88b5ba8SSam Ravnborg dp->child = build_tree(dp, prom_getchild(node), nextp); 1356a88b5ba8SSam Ravnborg 1357a88b5ba8SSam Ravnborg node = prom_getsibling(node); 1358a88b5ba8SSam Ravnborg } 1359a88b5ba8SSam Ravnborg 1360a88b5ba8SSam Ravnborg return ret; 1361a88b5ba8SSam Ravnborg } 1362a88b5ba8SSam Ravnborg 1363a88b5ba8SSam Ravnborg static const char *get_mid_prop(void) 1364a88b5ba8SSam Ravnborg { 1365a88b5ba8SSam Ravnborg return (tlb_type == spitfire ? "upa-portid" : "portid"); 1366a88b5ba8SSam Ravnborg } 1367a88b5ba8SSam Ravnborg 1368a88b5ba8SSam Ravnborg struct device_node *of_find_node_by_cpuid(int cpuid) 1369a88b5ba8SSam Ravnborg { 1370a88b5ba8SSam Ravnborg struct device_node *dp; 1371a88b5ba8SSam Ravnborg const char *mid_prop = get_mid_prop(); 1372a88b5ba8SSam Ravnborg 1373a88b5ba8SSam Ravnborg for_each_node_by_type(dp, "cpu") { 1374a88b5ba8SSam Ravnborg int id = of_getintprop_default(dp, mid_prop, -1); 1375a88b5ba8SSam Ravnborg const char *this_mid_prop = mid_prop; 1376a88b5ba8SSam Ravnborg 1377a88b5ba8SSam Ravnborg if (id < 0) { 1378a88b5ba8SSam Ravnborg this_mid_prop = "cpuid"; 1379a88b5ba8SSam Ravnborg id = of_getintprop_default(dp, this_mid_prop, -1); 1380a88b5ba8SSam Ravnborg } 1381a88b5ba8SSam Ravnborg 1382a88b5ba8SSam Ravnborg if (id < 0) { 1383a88b5ba8SSam Ravnborg prom_printf("OF: Serious problem, cpu lacks " 1384a88b5ba8SSam Ravnborg "%s property", this_mid_prop); 1385a88b5ba8SSam Ravnborg prom_halt(); 1386a88b5ba8SSam Ravnborg } 1387a88b5ba8SSam Ravnborg if (cpuid == id) 1388a88b5ba8SSam Ravnborg return dp; 1389a88b5ba8SSam Ravnborg } 1390a88b5ba8SSam Ravnborg return NULL; 1391a88b5ba8SSam Ravnborg } 1392a88b5ba8SSam Ravnborg 1393a88b5ba8SSam Ravnborg static void __init of_fill_in_cpu_data(void) 1394a88b5ba8SSam Ravnborg { 1395a88b5ba8SSam Ravnborg struct device_node *dp; 1396a88b5ba8SSam Ravnborg const char *mid_prop = get_mid_prop(); 1397a88b5ba8SSam Ravnborg 1398a88b5ba8SSam Ravnborg ncpus_probed = 0; 1399a88b5ba8SSam Ravnborg for_each_node_by_type(dp, "cpu") { 1400a88b5ba8SSam Ravnborg int cpuid = of_getintprop_default(dp, mid_prop, -1); 1401a88b5ba8SSam Ravnborg const char *this_mid_prop = mid_prop; 1402a88b5ba8SSam Ravnborg struct device_node *portid_parent; 1403a88b5ba8SSam Ravnborg int portid = -1; 1404a88b5ba8SSam Ravnborg 1405a88b5ba8SSam Ravnborg portid_parent = NULL; 1406a88b5ba8SSam Ravnborg if (cpuid < 0) { 1407a88b5ba8SSam Ravnborg this_mid_prop = "cpuid"; 1408a88b5ba8SSam Ravnborg cpuid = of_getintprop_default(dp, this_mid_prop, -1); 1409a88b5ba8SSam Ravnborg if (cpuid >= 0) { 1410a88b5ba8SSam Ravnborg int limit = 2; 1411a88b5ba8SSam Ravnborg 1412a88b5ba8SSam Ravnborg portid_parent = dp; 1413a88b5ba8SSam Ravnborg while (limit--) { 1414a88b5ba8SSam Ravnborg portid_parent = portid_parent->parent; 1415a88b5ba8SSam Ravnborg if (!portid_parent) 1416a88b5ba8SSam Ravnborg break; 1417a88b5ba8SSam Ravnborg portid = of_getintprop_default(portid_parent, 1418a88b5ba8SSam Ravnborg "portid", -1); 1419a88b5ba8SSam Ravnborg if (portid >= 0) 1420a88b5ba8SSam Ravnborg break; 1421a88b5ba8SSam Ravnborg } 1422a88b5ba8SSam Ravnborg } 1423a88b5ba8SSam Ravnborg } 1424a88b5ba8SSam Ravnborg 1425a88b5ba8SSam Ravnborg if (cpuid < 0) { 1426a88b5ba8SSam Ravnborg prom_printf("OF: Serious problem, cpu lacks " 1427a88b5ba8SSam Ravnborg "%s property", this_mid_prop); 1428a88b5ba8SSam Ravnborg prom_halt(); 1429a88b5ba8SSam Ravnborg } 1430a88b5ba8SSam Ravnborg 1431a88b5ba8SSam Ravnborg ncpus_probed++; 1432a88b5ba8SSam Ravnborg 1433a88b5ba8SSam Ravnborg #ifdef CONFIG_SMP 1434a88b5ba8SSam Ravnborg if (cpuid >= NR_CPUS) { 1435a88b5ba8SSam Ravnborg printk(KERN_WARNING "Ignoring CPU %d which is " 1436a88b5ba8SSam Ravnborg ">= NR_CPUS (%d)\n", 1437a88b5ba8SSam Ravnborg cpuid, NR_CPUS); 1438a88b5ba8SSam Ravnborg continue; 1439a88b5ba8SSam Ravnborg } 1440a88b5ba8SSam Ravnborg #else 1441a88b5ba8SSam Ravnborg /* On uniprocessor we only want the values for the 1442a88b5ba8SSam Ravnborg * real physical cpu the kernel booted onto, however 1443a88b5ba8SSam Ravnborg * cpu_data() only has one entry at index 0. 1444a88b5ba8SSam Ravnborg */ 1445a88b5ba8SSam Ravnborg if (cpuid != real_hard_smp_processor_id()) 1446a88b5ba8SSam Ravnborg continue; 1447a88b5ba8SSam Ravnborg cpuid = 0; 1448a88b5ba8SSam Ravnborg #endif 1449a88b5ba8SSam Ravnborg 1450a88b5ba8SSam Ravnborg cpu_data(cpuid).clock_tick = 1451a88b5ba8SSam Ravnborg of_getintprop_default(dp, "clock-frequency", 0); 1452a88b5ba8SSam Ravnborg 1453a88b5ba8SSam Ravnborg if (portid_parent) { 1454a88b5ba8SSam Ravnborg cpu_data(cpuid).dcache_size = 1455a88b5ba8SSam Ravnborg of_getintprop_default(dp, "l1-dcache-size", 1456a88b5ba8SSam Ravnborg 16 * 1024); 1457a88b5ba8SSam Ravnborg cpu_data(cpuid).dcache_line_size = 1458a88b5ba8SSam Ravnborg of_getintprop_default(dp, "l1-dcache-line-size", 1459a88b5ba8SSam Ravnborg 32); 1460a88b5ba8SSam Ravnborg cpu_data(cpuid).icache_size = 1461a88b5ba8SSam Ravnborg of_getintprop_default(dp, "l1-icache-size", 1462a88b5ba8SSam Ravnborg 8 * 1024); 1463a88b5ba8SSam Ravnborg cpu_data(cpuid).icache_line_size = 1464a88b5ba8SSam Ravnborg of_getintprop_default(dp, "l1-icache-line-size", 1465a88b5ba8SSam Ravnborg 32); 1466a88b5ba8SSam Ravnborg cpu_data(cpuid).ecache_size = 1467a88b5ba8SSam Ravnborg of_getintprop_default(dp, "l2-cache-size", 0); 1468a88b5ba8SSam Ravnborg cpu_data(cpuid).ecache_line_size = 1469a88b5ba8SSam Ravnborg of_getintprop_default(dp, "l2-cache-line-size", 0); 1470a88b5ba8SSam Ravnborg if (!cpu_data(cpuid).ecache_size || 1471a88b5ba8SSam Ravnborg !cpu_data(cpuid).ecache_line_size) { 1472a88b5ba8SSam Ravnborg cpu_data(cpuid).ecache_size = 1473a88b5ba8SSam Ravnborg of_getintprop_default(portid_parent, 1474a88b5ba8SSam Ravnborg "l2-cache-size", 1475a88b5ba8SSam Ravnborg (4 * 1024 * 1024)); 1476a88b5ba8SSam Ravnborg cpu_data(cpuid).ecache_line_size = 1477a88b5ba8SSam Ravnborg of_getintprop_default(portid_parent, 1478a88b5ba8SSam Ravnborg "l2-cache-line-size", 64); 1479a88b5ba8SSam Ravnborg } 1480a88b5ba8SSam Ravnborg 1481a88b5ba8SSam Ravnborg cpu_data(cpuid).core_id = portid + 1; 1482a88b5ba8SSam Ravnborg cpu_data(cpuid).proc_id = portid; 1483a88b5ba8SSam Ravnborg #ifdef CONFIG_SMP 1484a88b5ba8SSam Ravnborg sparc64_multi_core = 1; 1485a88b5ba8SSam Ravnborg #endif 1486a88b5ba8SSam Ravnborg } else { 1487a88b5ba8SSam Ravnborg cpu_data(cpuid).dcache_size = 1488a88b5ba8SSam Ravnborg of_getintprop_default(dp, "dcache-size", 16 * 1024); 1489a88b5ba8SSam Ravnborg cpu_data(cpuid).dcache_line_size = 1490a88b5ba8SSam Ravnborg of_getintprop_default(dp, "dcache-line-size", 32); 1491a88b5ba8SSam Ravnborg 1492a88b5ba8SSam Ravnborg cpu_data(cpuid).icache_size = 1493a88b5ba8SSam Ravnborg of_getintprop_default(dp, "icache-size", 16 * 1024); 1494a88b5ba8SSam Ravnborg cpu_data(cpuid).icache_line_size = 1495a88b5ba8SSam Ravnborg of_getintprop_default(dp, "icache-line-size", 32); 1496a88b5ba8SSam Ravnborg 1497a88b5ba8SSam Ravnborg cpu_data(cpuid).ecache_size = 1498a88b5ba8SSam Ravnborg of_getintprop_default(dp, "ecache-size", 1499a88b5ba8SSam Ravnborg (4 * 1024 * 1024)); 1500a88b5ba8SSam Ravnborg cpu_data(cpuid).ecache_line_size = 1501a88b5ba8SSam Ravnborg of_getintprop_default(dp, "ecache-line-size", 64); 1502a88b5ba8SSam Ravnborg 1503a88b5ba8SSam Ravnborg cpu_data(cpuid).core_id = 0; 1504a88b5ba8SSam Ravnborg cpu_data(cpuid).proc_id = -1; 1505a88b5ba8SSam Ravnborg } 1506a88b5ba8SSam Ravnborg 1507a88b5ba8SSam Ravnborg #ifdef CONFIG_SMP 1508a88b5ba8SSam Ravnborg cpu_set(cpuid, cpu_present_map); 1509a88b5ba8SSam Ravnborg cpu_set(cpuid, cpu_possible_map); 1510a88b5ba8SSam Ravnborg #endif 1511a88b5ba8SSam Ravnborg } 1512a88b5ba8SSam Ravnborg 1513a88b5ba8SSam Ravnborg smp_fill_in_sib_core_maps(); 1514a88b5ba8SSam Ravnborg } 1515a88b5ba8SSam Ravnborg 1516a88b5ba8SSam Ravnborg struct device_node *of_console_device; 1517a88b5ba8SSam Ravnborg EXPORT_SYMBOL(of_console_device); 1518a88b5ba8SSam Ravnborg 1519a88b5ba8SSam Ravnborg char *of_console_path; 1520a88b5ba8SSam Ravnborg EXPORT_SYMBOL(of_console_path); 1521a88b5ba8SSam Ravnborg 1522a88b5ba8SSam Ravnborg char *of_console_options; 1523a88b5ba8SSam Ravnborg EXPORT_SYMBOL(of_console_options); 1524a88b5ba8SSam Ravnborg 1525a88b5ba8SSam Ravnborg static void __init of_console_init(void) 1526a88b5ba8SSam Ravnborg { 1527a88b5ba8SSam Ravnborg char *msg = "OF stdout device is: %s\n"; 1528a88b5ba8SSam Ravnborg struct device_node *dp; 1529a88b5ba8SSam Ravnborg const char *type; 1530a88b5ba8SSam Ravnborg phandle node; 1531a88b5ba8SSam Ravnborg 1532a88b5ba8SSam Ravnborg of_console_path = prom_early_alloc(256); 1533a88b5ba8SSam Ravnborg if (prom_ihandle2path(prom_stdout, of_console_path, 256) < 0) { 1534a88b5ba8SSam Ravnborg prom_printf("Cannot obtain path of stdout.\n"); 1535a88b5ba8SSam Ravnborg prom_halt(); 1536a88b5ba8SSam Ravnborg } 1537a88b5ba8SSam Ravnborg of_console_options = strrchr(of_console_path, ':'); 1538a88b5ba8SSam Ravnborg if (of_console_options) { 1539a88b5ba8SSam Ravnborg of_console_options++; 1540a88b5ba8SSam Ravnborg if (*of_console_options == '\0') 1541a88b5ba8SSam Ravnborg of_console_options = NULL; 1542a88b5ba8SSam Ravnborg } 1543a88b5ba8SSam Ravnborg 1544a88b5ba8SSam Ravnborg node = prom_inst2pkg(prom_stdout); 1545a88b5ba8SSam Ravnborg if (!node) { 1546a88b5ba8SSam Ravnborg prom_printf("Cannot resolve stdout node from " 1547a88b5ba8SSam Ravnborg "instance %08x.\n", prom_stdout); 1548a88b5ba8SSam Ravnborg prom_halt(); 1549a88b5ba8SSam Ravnborg } 1550a88b5ba8SSam Ravnborg 1551a88b5ba8SSam Ravnborg dp = of_find_node_by_phandle(node); 1552a88b5ba8SSam Ravnborg type = of_get_property(dp, "device_type", NULL); 1553a88b5ba8SSam Ravnborg if (!type) { 1554a88b5ba8SSam Ravnborg prom_printf("Console stdout lacks device_type property.\n"); 1555a88b5ba8SSam Ravnborg prom_halt(); 1556a88b5ba8SSam Ravnborg } 1557a88b5ba8SSam Ravnborg 1558a88b5ba8SSam Ravnborg if (strcmp(type, "display") && strcmp(type, "serial")) { 1559a88b5ba8SSam Ravnborg prom_printf("Console device_type is neither display " 1560a88b5ba8SSam Ravnborg "nor serial.\n"); 1561a88b5ba8SSam Ravnborg prom_halt(); 1562a88b5ba8SSam Ravnborg } 1563a88b5ba8SSam Ravnborg 1564a88b5ba8SSam Ravnborg of_console_device = dp; 1565a88b5ba8SSam Ravnborg 1566a88b5ba8SSam Ravnborg printk(msg, of_console_path); 1567a88b5ba8SSam Ravnborg } 1568a88b5ba8SSam Ravnborg 1569a88b5ba8SSam Ravnborg void __init prom_build_devicetree(void) 1570a88b5ba8SSam Ravnborg { 1571a88b5ba8SSam Ravnborg struct device_node **nextp; 1572a88b5ba8SSam Ravnborg 1573a88b5ba8SSam Ravnborg allnodes = create_node(prom_root_node, NULL); 1574a88b5ba8SSam Ravnborg allnodes->path_component_name = ""; 1575a88b5ba8SSam Ravnborg allnodes->full_name = "/"; 1576a88b5ba8SSam Ravnborg 1577a88b5ba8SSam Ravnborg nextp = &allnodes->allnext; 1578a88b5ba8SSam Ravnborg allnodes->child = build_tree(allnodes, 1579a88b5ba8SSam Ravnborg prom_getchild(allnodes->node), 1580a88b5ba8SSam Ravnborg &nextp); 1581a88b5ba8SSam Ravnborg of_console_init(); 1582a88b5ba8SSam Ravnborg 1583a88b5ba8SSam Ravnborg printk("PROM: Built device tree with %u bytes of memory.\n", 1584a88b5ba8SSam Ravnborg prom_early_allocated); 1585a88b5ba8SSam Ravnborg 1586a88b5ba8SSam Ravnborg if (tlb_type != hypervisor) 1587a88b5ba8SSam Ravnborg of_fill_in_cpu_data(); 1588a88b5ba8SSam Ravnborg } 1589