linux/arch/sparc/kernel/prom_irqtrans.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/kernel.h>
   3#include <linux/string.h>
   4#include <linux/init.h>
   5#include <linux/of.h>
   6#include <linux/of_platform.h>
   7
   8#include <asm/oplib.h>
   9#include <asm/prom.h>
  10#include <asm/irq.h>
  11#include <asm/upa.h>
  12
  13#include "prom.h"
  14
  15#ifdef CONFIG_PCI
  16/* PSYCHO interrupt mapping support. */
  17#define PSYCHO_IMAP_A_SLOT0     0x0c00UL
  18#define PSYCHO_IMAP_B_SLOT0     0x0c20UL
  19static unsigned long psycho_pcislot_imap_offset(unsigned long ino)
  20{
  21        unsigned int bus =  (ino & 0x10) >> 4;
  22        unsigned int slot = (ino & 0x0c) >> 2;
  23
  24        if (bus == 0)
  25                return PSYCHO_IMAP_A_SLOT0 + (slot * 8);
  26        else
  27                return PSYCHO_IMAP_B_SLOT0 + (slot * 8);
  28}
  29
  30#define PSYCHO_OBIO_IMAP_BASE   0x1000UL
  31
  32#define PSYCHO_ONBOARD_IRQ_BASE         0x20
  33#define psycho_onboard_imap_offset(__ino) \
  34        (PSYCHO_OBIO_IMAP_BASE + (((__ino) & 0x1f) << 3))
  35
  36#define PSYCHO_ICLR_A_SLOT0     0x1400UL
  37#define PSYCHO_ICLR_SCSI        0x1800UL
  38
  39#define psycho_iclr_offset(ino)                                       \
  40        ((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) :  \
  41                        (PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3)))
  42
  43static unsigned int psycho_irq_build(struct device_node *dp,
  44                                     unsigned int ino,
  45                                     void *_data)
  46{
  47        unsigned long controller_regs = (unsigned long) _data;
  48        unsigned long imap, iclr;
  49        unsigned long imap_off, iclr_off;
  50        int inofixup = 0;
  51
  52        ino &= 0x3f;
  53        if (ino < PSYCHO_ONBOARD_IRQ_BASE) {
  54                /* PCI slot */
  55                imap_off = psycho_pcislot_imap_offset(ino);
  56        } else {
  57                /* Onboard device */
  58                imap_off = psycho_onboard_imap_offset(ino);
  59        }
  60
  61        /* Now build the IRQ bucket. */
  62        imap = controller_regs + imap_off;
  63
  64        iclr_off = psycho_iclr_offset(ino);
  65        iclr = controller_regs + iclr_off;
  66
  67        if ((ino & 0x20) == 0)
  68                inofixup = ino & 0x03;
  69
  70        return build_irq(inofixup, iclr, imap);
  71}
  72
  73static void __init psycho_irq_trans_init(struct device_node *dp)
  74{
  75        const struct linux_prom64_registers *regs;
  76
  77        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
  78        dp->irq_trans->irq_build = psycho_irq_build;
  79
  80        regs = of_get_property(dp, "reg", NULL);
  81        dp->irq_trans->data = (void *) regs[2].phys_addr;
  82}
  83
  84#define sabre_read(__reg) \
  85({      u64 __ret; \
  86        __asm__ __volatile__("ldxa [%1] %2, %0" \
  87                             : "=r" (__ret) \
  88                             : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
  89                             : "memory"); \
  90        __ret; \
  91})
  92
  93struct sabre_irq_data {
  94        unsigned long controller_regs;
  95        unsigned int pci_first_busno;
  96};
  97#define SABRE_CONFIGSPACE       0x001000000UL
  98#define SABRE_WRSYNC            0x1c20UL
  99
 100#define SABRE_CONFIG_BASE(CONFIG_SPACE) \
 101        (CONFIG_SPACE | (1UL << 24))
 102#define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG)    \
 103        (((unsigned long)(BUS)   << 16) |       \
 104         ((unsigned long)(DEVFN) << 8)  |       \
 105         ((unsigned long)(REG)))
 106
 107/* When a device lives behind a bridge deeper in the PCI bus topology
 108 * than APB, a special sequence must run to make sure all pending DMA
 109 * transfers at the time of IRQ delivery are visible in the coherency
 110 * domain by the cpu.  This sequence is to perform a read on the far
 111 * side of the non-APB bridge, then perform a read of Sabre's DMA
 112 * write-sync register.
 113 */
 114static void sabre_wsync_handler(unsigned int ino, void *_arg1, void *_arg2)
 115{
 116        unsigned int phys_hi = (unsigned int) (unsigned long) _arg1;
 117        struct sabre_irq_data *irq_data = _arg2;
 118        unsigned long controller_regs = irq_data->controller_regs;
 119        unsigned long sync_reg = controller_regs + SABRE_WRSYNC;
 120        unsigned long config_space = controller_regs + SABRE_CONFIGSPACE;
 121        unsigned int bus, devfn;
 122        u16 _unused;
 123
 124        config_space = SABRE_CONFIG_BASE(config_space);
 125
 126        bus = (phys_hi >> 16) & 0xff;
 127        devfn = (phys_hi >> 8) & 0xff;
 128
 129        config_space |= SABRE_CONFIG_ENCODE(bus, devfn, 0x00);
 130
 131        __asm__ __volatile__("membar #Sync\n\t"
 132                             "lduha [%1] %2, %0\n\t"
 133                             "membar #Sync"
 134                             : "=r" (_unused)
 135                             : "r" ((u16 *) config_space),
 136                               "i" (ASI_PHYS_BYPASS_EC_E_L)
 137                             : "memory");
 138
 139        sabre_read(sync_reg);
 140}
 141
 142#define SABRE_IMAP_A_SLOT0      0x0c00UL
 143#define SABRE_IMAP_B_SLOT0      0x0c20UL
 144#define SABRE_ICLR_A_SLOT0      0x1400UL
 145#define SABRE_ICLR_B_SLOT0      0x1480UL
 146#define SABRE_ICLR_SCSI         0x1800UL
 147#define SABRE_ICLR_ETH          0x1808UL
 148#define SABRE_ICLR_BPP          0x1810UL
 149#define SABRE_ICLR_AU_REC       0x1818UL
 150#define SABRE_ICLR_AU_PLAY      0x1820UL
 151#define SABRE_ICLR_PFAIL        0x1828UL
 152#define SABRE_ICLR_KMS          0x1830UL
 153#define SABRE_ICLR_FLPY         0x1838UL
 154#define SABRE_ICLR_SHW          0x1840UL
 155#define SABRE_ICLR_KBD          0x1848UL
 156#define SABRE_ICLR_MS           0x1850UL
 157#define SABRE_ICLR_SER          0x1858UL
 158#define SABRE_ICLR_UE           0x1870UL
 159#define SABRE_ICLR_CE           0x1878UL
 160#define SABRE_ICLR_PCIERR       0x1880UL
 161
 162static unsigned long sabre_pcislot_imap_offset(unsigned long ino)
 163{
 164        unsigned int bus =  (ino & 0x10) >> 4;
 165        unsigned int slot = (ino & 0x0c) >> 2;
 166
 167        if (bus == 0)
 168                return SABRE_IMAP_A_SLOT0 + (slot * 8);
 169        else
 170                return SABRE_IMAP_B_SLOT0 + (slot * 8);
 171}
 172
 173#define SABRE_OBIO_IMAP_BASE    0x1000UL
 174#define SABRE_ONBOARD_IRQ_BASE  0x20
 175#define sabre_onboard_imap_offset(__ino) \
 176        (SABRE_OBIO_IMAP_BASE + (((__ino) & 0x1f) << 3))
 177
 178#define sabre_iclr_offset(ino)                                        \
 179        ((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) :  \
 180                        (SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3)))
 181
 182static int sabre_device_needs_wsync(struct device_node *dp)
 183{
 184        struct device_node *parent = dp->parent;
 185        const char *parent_model, *parent_compat;
 186
 187        /* This traversal up towards the root is meant to
 188         * handle two cases:
 189         *
 190         * 1) non-PCI bus sitting under PCI, such as 'ebus'
 191         * 2) the PCI controller interrupts themselves, which
 192         *    will use the sabre_irq_build but do not need
 193         *    the DMA synchronization handling
 194         */
 195        while (parent) {
 196                if (!strcmp(parent->type, "pci"))
 197                        break;
 198                parent = parent->parent;
 199        }
 200
 201        if (!parent)
 202                return 0;
 203
 204        parent_model = of_get_property(parent,
 205                                       "model", NULL);
 206        if (parent_model &&
 207            (!strcmp(parent_model, "SUNW,sabre") ||
 208             !strcmp(parent_model, "SUNW,simba")))
 209                return 0;
 210
 211        parent_compat = of_get_property(parent,
 212                                        "compatible", NULL);
 213        if (parent_compat &&
 214            (!strcmp(parent_compat, "pci108e,a000") ||
 215             !strcmp(parent_compat, "pci108e,a001")))
 216                return 0;
 217
 218        return 1;
 219}
 220
 221static unsigned int sabre_irq_build(struct device_node *dp,
 222                                    unsigned int ino,
 223                                    void *_data)
 224{
 225        struct sabre_irq_data *irq_data = _data;
 226        unsigned long controller_regs = irq_data->controller_regs;
 227        const struct linux_prom_pci_registers *regs;
 228        unsigned long imap, iclr;
 229        unsigned long imap_off, iclr_off;
 230        int inofixup = 0;
 231        int irq;
 232
 233        ino &= 0x3f;
 234        if (ino < SABRE_ONBOARD_IRQ_BASE) {
 235                /* PCI slot */
 236                imap_off = sabre_pcislot_imap_offset(ino);
 237        } else {
 238                /* onboard device */
 239                imap_off = sabre_onboard_imap_offset(ino);
 240        }
 241
 242        /* Now build the IRQ bucket. */
 243        imap = controller_regs + imap_off;
 244
 245        iclr_off = sabre_iclr_offset(ino);
 246        iclr = controller_regs + iclr_off;
 247
 248        if ((ino & 0x20) == 0)
 249                inofixup = ino & 0x03;
 250
 251        irq = build_irq(inofixup, iclr, imap);
 252
 253        /* If the parent device is a PCI<->PCI bridge other than
 254         * APB, we have to install a pre-handler to ensure that
 255         * all pending DMA is drained before the interrupt handler
 256         * is run.
 257         */
 258        regs = of_get_property(dp, "reg", NULL);
 259        if (regs && sabre_device_needs_wsync(dp)) {
 260                irq_install_pre_handler(irq,
 261                                        sabre_wsync_handler,
 262                                        (void *) (long) regs->phys_hi,
 263                                        (void *) irq_data);
 264        }
 265
 266        return irq;
 267}
 268
 269static void __init sabre_irq_trans_init(struct device_node *dp)
 270{
 271        const struct linux_prom64_registers *regs;
 272        struct sabre_irq_data *irq_data;
 273        const u32 *busrange;
 274
 275        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
 276        dp->irq_trans->irq_build = sabre_irq_build;
 277
 278        irq_data = prom_early_alloc(sizeof(struct sabre_irq_data));
 279
 280        regs = of_get_property(dp, "reg", NULL);
 281        irq_data->controller_regs = regs[0].phys_addr;
 282
 283        busrange = of_get_property(dp, "bus-range", NULL);
 284        irq_data->pci_first_busno = busrange[0];
 285
 286        dp->irq_trans->data = irq_data;
 287}
 288
 289/* SCHIZO interrupt mapping support.  Unlike Psycho, for this controller the
 290 * imap/iclr registers are per-PBM.
 291 */
 292#define SCHIZO_IMAP_BASE        0x1000UL
 293#define SCHIZO_ICLR_BASE        0x1400UL
 294
 295static unsigned long schizo_imap_offset(unsigned long ino)
 296{
 297        return SCHIZO_IMAP_BASE + (ino * 8UL);
 298}
 299
 300static unsigned long schizo_iclr_offset(unsigned long ino)
 301{
 302        return SCHIZO_ICLR_BASE + (ino * 8UL);
 303}
 304
 305static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs,
 306                                        unsigned int ino)
 307{
 308
 309        return pbm_regs + schizo_iclr_offset(ino);
 310}
 311
 312static unsigned long schizo_ino_to_imap(unsigned long pbm_regs,
 313                                        unsigned int ino)
 314{
 315        return pbm_regs + schizo_imap_offset(ino);
 316}
 317
 318#define schizo_read(__reg) \
 319({      u64 __ret; \
 320        __asm__ __volatile__("ldxa [%1] %2, %0" \
 321                             : "=r" (__ret) \
 322                             : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
 323                             : "memory"); \
 324        __ret; \
 325})
 326#define schizo_write(__reg, __val) \
 327        __asm__ __volatile__("stxa %0, [%1] %2" \
 328                             : /* no outputs */ \
 329                             : "r" (__val), "r" (__reg), \
 330                               "i" (ASI_PHYS_BYPASS_EC_E) \
 331                             : "memory")
 332
 333static void tomatillo_wsync_handler(unsigned int ino, void *_arg1, void *_arg2)
 334{
 335        unsigned long sync_reg = (unsigned long) _arg2;
 336        u64 mask = 1UL << (ino & IMAP_INO);
 337        u64 val;
 338        int limit;
 339
 340        schizo_write(sync_reg, mask);
 341
 342        limit = 100000;
 343        val = 0;
 344        while (--limit) {
 345                val = schizo_read(sync_reg);
 346                if (!(val & mask))
 347                        break;
 348        }
 349        if (limit <= 0) {
 350                printk("tomatillo_wsync_handler: DMA won't sync [%llx:%llx]\n",
 351                       val, mask);
 352        }
 353
 354        if (_arg1) {
 355                static unsigned char cacheline[64]
 356                        __attribute__ ((aligned (64)));
 357
 358                __asm__ __volatile__("rd %%fprs, %0\n\t"
 359                                     "or %0, %4, %1\n\t"
 360                                     "wr %1, 0x0, %%fprs\n\t"
 361                                     "stda %%f0, [%5] %6\n\t"
 362                                     "wr %0, 0x0, %%fprs\n\t"
 363                                     "membar #Sync"
 364                                     : "=&r" (mask), "=&r" (val)
 365                                     : "0" (mask), "1" (val),
 366                                     "i" (FPRS_FEF), "r" (&cacheline[0]),
 367                                     "i" (ASI_BLK_COMMIT_P));
 368        }
 369}
 370
 371struct schizo_irq_data {
 372        unsigned long pbm_regs;
 373        unsigned long sync_reg;
 374        u32 portid;
 375        int chip_version;
 376};
 377
 378static unsigned int schizo_irq_build(struct device_node *dp,
 379                                     unsigned int ino,
 380                                     void *_data)
 381{
 382        struct schizo_irq_data *irq_data = _data;
 383        unsigned long pbm_regs = irq_data->pbm_regs;
 384        unsigned long imap, iclr;
 385        int ign_fixup;
 386        int irq;
 387        int is_tomatillo;
 388
 389        ino &= 0x3f;
 390
 391        /* Now build the IRQ bucket. */
 392        imap = schizo_ino_to_imap(pbm_regs, ino);
 393        iclr = schizo_ino_to_iclr(pbm_regs, ino);
 394
 395        /* On Schizo, no inofixup occurs.  This is because each
 396         * INO has it's own IMAP register.  On Psycho and Sabre
 397         * there is only one IMAP register for each PCI slot even
 398         * though four different INOs can be generated by each
 399         * PCI slot.
 400         *
 401         * But, for JBUS variants (essentially, Tomatillo), we have
 402         * to fixup the lowest bit of the interrupt group number.
 403         */
 404        ign_fixup = 0;
 405
 406        is_tomatillo = (irq_data->sync_reg != 0UL);
 407
 408        if (is_tomatillo) {
 409                if (irq_data->portid & 1)
 410                        ign_fixup = (1 << 6);
 411        }
 412
 413        irq = build_irq(ign_fixup, iclr, imap);
 414
 415        if (is_tomatillo) {
 416                irq_install_pre_handler(irq,
 417                                        tomatillo_wsync_handler,
 418                                        ((irq_data->chip_version <= 4) ?
 419                                         (void *) 1 : (void *) 0),
 420                                        (void *) irq_data->sync_reg);
 421        }
 422
 423        return irq;
 424}
 425
 426static void __init __schizo_irq_trans_init(struct device_node *dp,
 427                                           int is_tomatillo)
 428{
 429        const struct linux_prom64_registers *regs;
 430        struct schizo_irq_data *irq_data;
 431
 432        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
 433        dp->irq_trans->irq_build = schizo_irq_build;
 434
 435        irq_data = prom_early_alloc(sizeof(struct schizo_irq_data));
 436
 437        regs = of_get_property(dp, "reg", NULL);
 438        dp->irq_trans->data = irq_data;
 439
 440        irq_data->pbm_regs = regs[0].phys_addr;
 441        if (is_tomatillo)
 442                irq_data->sync_reg = regs[3].phys_addr + 0x1a18UL;
 443        else
 444                irq_data->sync_reg = 0UL;
 445        irq_data->portid = of_getintprop_default(dp, "portid", 0);
 446        irq_data->chip_version = of_getintprop_default(dp, "version#", 0);
 447}
 448
 449static void __init schizo_irq_trans_init(struct device_node *dp)
 450{
 451        __schizo_irq_trans_init(dp, 0);
 452}
 453
 454static void __init tomatillo_irq_trans_init(struct device_node *dp)
 455{
 456        __schizo_irq_trans_init(dp, 1);
 457}
 458
 459static unsigned int pci_sun4v_irq_build(struct device_node *dp,
 460                                        unsigned int devino,
 461                                        void *_data)
 462{
 463        u32 devhandle = (u32) (unsigned long) _data;
 464
 465        return sun4v_build_irq(devhandle, devino);
 466}
 467
 468static void __init pci_sun4v_irq_trans_init(struct device_node *dp)
 469{
 470        const struct linux_prom64_registers *regs;
 471
 472        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
 473        dp->irq_trans->irq_build = pci_sun4v_irq_build;
 474
 475        regs = of_get_property(dp, "reg", NULL);
 476        dp->irq_trans->data = (void *) (unsigned long)
 477                ((regs->phys_addr >> 32UL) & 0x0fffffff);
 478}
 479
 480struct fire_irq_data {
 481        unsigned long pbm_regs;
 482        u32 portid;
 483};
 484
 485#define FIRE_IMAP_BASE  0x001000
 486#define FIRE_ICLR_BASE  0x001400
 487
 488static unsigned long fire_imap_offset(unsigned long ino)
 489{
 490        return FIRE_IMAP_BASE + (ino * 8UL);
 491}
 492
 493static unsigned long fire_iclr_offset(unsigned long ino)
 494{
 495        return FIRE_ICLR_BASE + (ino * 8UL);
 496}
 497
 498static unsigned long fire_ino_to_iclr(unsigned long pbm_regs,
 499                                            unsigned int ino)
 500{
 501        return pbm_regs + fire_iclr_offset(ino);
 502}
 503
 504static unsigned long fire_ino_to_imap(unsigned long pbm_regs,
 505                                            unsigned int ino)
 506{
 507        return pbm_regs + fire_imap_offset(ino);
 508}
 509
 510static unsigned int fire_irq_build(struct device_node *dp,
 511                                         unsigned int ino,
 512                                         void *_data)
 513{
 514        struct fire_irq_data *irq_data = _data;
 515        unsigned long pbm_regs = irq_data->pbm_regs;
 516        unsigned long imap, iclr;
 517        unsigned long int_ctrlr;
 518
 519        ino &= 0x3f;
 520
 521        /* Now build the IRQ bucket. */
 522        imap = fire_ino_to_imap(pbm_regs, ino);
 523        iclr = fire_ino_to_iclr(pbm_regs, ino);
 524
 525        /* Set the interrupt controller number.  */
 526        int_ctrlr = 1 << 6;
 527        upa_writeq(int_ctrlr, imap);
 528
 529        /* The interrupt map registers do not have an INO field
 530         * like other chips do.  They return zero in the INO
 531         * field, and the interrupt controller number is controlled
 532         * in bits 6 to 9.  So in order for build_irq() to get
 533         * the INO right we pass it in as part of the fixup
 534         * which will get added to the map register zero value
 535         * read by build_irq().
 536         */
 537        ino |= (irq_data->portid << 6);
 538        ino -= int_ctrlr;
 539        return build_irq(ino, iclr, imap);
 540}
 541
 542static void __init fire_irq_trans_init(struct device_node *dp)
 543{
 544        const struct linux_prom64_registers *regs;
 545        struct fire_irq_data *irq_data;
 546
 547        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
 548        dp->irq_trans->irq_build = fire_irq_build;
 549
 550        irq_data = prom_early_alloc(sizeof(struct fire_irq_data));
 551
 552        regs = of_get_property(dp, "reg", NULL);
 553        dp->irq_trans->data = irq_data;
 554
 555        irq_data->pbm_regs = regs[0].phys_addr;
 556        irq_data->portid = of_getintprop_default(dp, "portid", 0);
 557}
 558#endif /* CONFIG_PCI */
 559
 560#ifdef CONFIG_SBUS
 561/* INO number to IMAP register offset for SYSIO external IRQ's.
 562 * This should conform to both Sunfire/Wildfire server and Fusion
 563 * desktop designs.
 564 */
 565#define SYSIO_IMAP_SLOT0        0x2c00UL
 566#define SYSIO_IMAP_SLOT1        0x2c08UL
 567#define SYSIO_IMAP_SLOT2        0x2c10UL
 568#define SYSIO_IMAP_SLOT3        0x2c18UL
 569#define SYSIO_IMAP_SCSI         0x3000UL
 570#define SYSIO_IMAP_ETH          0x3008UL
 571#define SYSIO_IMAP_BPP          0x3010UL
 572#define SYSIO_IMAP_AUDIO        0x3018UL
 573#define SYSIO_IMAP_PFAIL        0x3020UL
 574#define SYSIO_IMAP_KMS          0x3028UL
 575#define SYSIO_IMAP_FLPY         0x3030UL
 576#define SYSIO_IMAP_SHW          0x3038UL
 577#define SYSIO_IMAP_KBD          0x3040UL
 578#define SYSIO_IMAP_MS           0x3048UL
 579#define SYSIO_IMAP_SER          0x3050UL
 580#define SYSIO_IMAP_TIM0         0x3060UL
 581#define SYSIO_IMAP_TIM1         0x3068UL
 582#define SYSIO_IMAP_UE           0x3070UL
 583#define SYSIO_IMAP_CE           0x3078UL
 584#define SYSIO_IMAP_SBERR        0x3080UL
 585#define SYSIO_IMAP_PMGMT        0x3088UL
 586#define SYSIO_IMAP_GFX          0x3090UL
 587#define SYSIO_IMAP_EUPA         0x3098UL
 588
 589#define bogon     ((unsigned long) -1)
 590static unsigned long sysio_irq_offsets[] = {
 591        /* SBUS Slot 0 --> 3, level 1 --> 7 */
 592        SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0,
 593        SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0,
 594        SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1,
 595        SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1,
 596        SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2,
 597        SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2,
 598        SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3,
 599        SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3,
 600
 601        /* Onboard devices (not relevant/used on SunFire). */
 602        SYSIO_IMAP_SCSI,
 603        SYSIO_IMAP_ETH,
 604        SYSIO_IMAP_BPP,
 605        bogon,
 606        SYSIO_IMAP_AUDIO,
 607        SYSIO_IMAP_PFAIL,
 608        bogon,
 609        bogon,
 610        SYSIO_IMAP_KMS,
 611        SYSIO_IMAP_FLPY,
 612        SYSIO_IMAP_SHW,
 613        SYSIO_IMAP_KBD,
 614        SYSIO_IMAP_MS,
 615        SYSIO_IMAP_SER,
 616        bogon,
 617        bogon,
 618        SYSIO_IMAP_TIM0,
 619        SYSIO_IMAP_TIM1,
 620        bogon,
 621        bogon,
 622        SYSIO_IMAP_UE,
 623        SYSIO_IMAP_CE,
 624        SYSIO_IMAP_SBERR,
 625        SYSIO_IMAP_PMGMT,
 626        SYSIO_IMAP_GFX,
 627        SYSIO_IMAP_EUPA,
 628};
 629
 630#undef bogon
 631
 632#define NUM_SYSIO_OFFSETS ARRAY_SIZE(sysio_irq_offsets)
 633
 634/* Convert Interrupt Mapping register pointer to associated
 635 * Interrupt Clear register pointer, SYSIO specific version.
 636 */
 637#define SYSIO_ICLR_UNUSED0      0x3400UL
 638#define SYSIO_ICLR_SLOT0        0x3408UL
 639#define SYSIO_ICLR_SLOT1        0x3448UL
 640#define SYSIO_ICLR_SLOT2        0x3488UL
 641#define SYSIO_ICLR_SLOT3        0x34c8UL
 642static unsigned long sysio_imap_to_iclr(unsigned long imap)
 643{
 644        unsigned long diff = SYSIO_ICLR_UNUSED0 - SYSIO_IMAP_SLOT0;
 645        return imap + diff;
 646}
 647
 648static unsigned int sbus_of_build_irq(struct device_node *dp,
 649                                      unsigned int ino,
 650                                      void *_data)
 651{
 652        unsigned long reg_base = (unsigned long) _data;
 653        const struct linux_prom_registers *regs;
 654        unsigned long imap, iclr;
 655        int sbus_slot = 0;
 656        int sbus_level = 0;
 657
 658        ino &= 0x3f;
 659
 660        regs = of_get_property(dp, "reg", NULL);
 661        if (regs)
 662                sbus_slot = regs->which_io;
 663
 664        if (ino < 0x20)
 665                ino += (sbus_slot * 8);
 666
 667        imap = sysio_irq_offsets[ino];
 668        if (imap == ((unsigned long)-1)) {
 669                prom_printf("get_irq_translations: Bad SYSIO INO[%x]\n",
 670                            ino);
 671                prom_halt();
 672        }
 673        imap += reg_base;
 674
 675        /* SYSIO inconsistency.  For external SLOTS, we have to select
 676         * the right ICLR register based upon the lower SBUS irq level
 677         * bits.
 678         */
 679        if (ino >= 0x20) {
 680                iclr = sysio_imap_to_iclr(imap);
 681        } else {
 682                sbus_level = ino & 0x7;
 683
 684                switch(sbus_slot) {
 685                case 0:
 686                        iclr = reg_base + SYSIO_ICLR_SLOT0;
 687                        break;
 688                case 1:
 689                        iclr = reg_base + SYSIO_ICLR_SLOT1;
 690                        break;
 691                case 2:
 692                        iclr = reg_base + SYSIO_ICLR_SLOT2;
 693                        break;
 694                default:
 695                case 3:
 696                        iclr = reg_base + SYSIO_ICLR_SLOT3;
 697                        break;
 698                }
 699
 700                iclr += ((unsigned long)sbus_level - 1UL) * 8UL;
 701        }
 702        return build_irq(sbus_level, iclr, imap);
 703}
 704
 705static void __init sbus_irq_trans_init(struct device_node *dp)
 706{
 707        const struct linux_prom64_registers *regs;
 708
 709        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
 710        dp->irq_trans->irq_build = sbus_of_build_irq;
 711
 712        regs = of_get_property(dp, "reg", NULL);
 713        dp->irq_trans->data = (void *) (unsigned long) regs->phys_addr;
 714}
 715#endif /* CONFIG_SBUS */
 716
 717
 718static unsigned int central_build_irq(struct device_node *dp,
 719                                      unsigned int ino,
 720                                      void *_data)
 721{
 722        struct device_node *central_dp = _data;
 723        struct platform_device *central_op = of_find_device_by_node(central_dp);
 724        struct resource *res;
 725        unsigned long imap, iclr;
 726        u32 tmp;
 727
 728        if (!strcmp(dp->name, "eeprom")) {
 729                res = &central_op->resource[5];
 730        } else if (!strcmp(dp->name, "zs")) {
 731                res = &central_op->resource[4];
 732        } else if (!strcmp(dp->name, "clock-board")) {
 733                res = &central_op->resource[3];
 734        } else {
 735                return ino;
 736        }
 737
 738        imap = res->start + 0x00UL;
 739        iclr = res->start + 0x10UL;
 740
 741        /* Set the INO state to idle, and disable.  */
 742        upa_writel(0, iclr);
 743        upa_readl(iclr);
 744
 745        tmp = upa_readl(imap);
 746        tmp &= ~0x80000000;
 747        upa_writel(tmp, imap);
 748
 749        return build_irq(0, iclr, imap);
 750}
 751
 752static void __init central_irq_trans_init(struct device_node *dp)
 753{
 754        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
 755        dp->irq_trans->irq_build = central_build_irq;
 756
 757        dp->irq_trans->data = dp;
 758}
 759
 760struct irq_trans {
 761        const char *name;
 762        void (*init)(struct device_node *);
 763};
 764
 765#ifdef CONFIG_PCI
 766static struct irq_trans __initdata pci_irq_trans_table[] = {
 767        { "SUNW,sabre", sabre_irq_trans_init },
 768        { "pci108e,a000", sabre_irq_trans_init },
 769        { "pci108e,a001", sabre_irq_trans_init },
 770        { "SUNW,psycho", psycho_irq_trans_init },
 771        { "pci108e,8000", psycho_irq_trans_init },
 772        { "SUNW,schizo", schizo_irq_trans_init },
 773        { "pci108e,8001", schizo_irq_trans_init },
 774        { "SUNW,schizo+", schizo_irq_trans_init },
 775        { "pci108e,8002", schizo_irq_trans_init },
 776        { "SUNW,tomatillo", tomatillo_irq_trans_init },
 777        { "pci108e,a801", tomatillo_irq_trans_init },
 778        { "SUNW,sun4v-pci", pci_sun4v_irq_trans_init },
 779        { "pciex108e,80f0", fire_irq_trans_init },
 780};
 781#endif
 782
 783static unsigned int sun4v_vdev_irq_build(struct device_node *dp,
 784                                         unsigned int devino,
 785                                         void *_data)
 786{
 787        u32 devhandle = (u32) (unsigned long) _data;
 788
 789        return sun4v_build_irq(devhandle, devino);
 790}
 791
 792static void __init sun4v_vdev_irq_trans_init(struct device_node *dp)
 793{
 794        const struct linux_prom64_registers *regs;
 795
 796        dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
 797        dp->irq_trans->irq_build = sun4v_vdev_irq_build;
 798
 799        regs = of_get_property(dp, "reg", NULL);
 800        dp->irq_trans->data = (void *) (unsigned long)
 801                ((regs->phys_addr >> 32UL) & 0x0fffffff);
 802}
 803
 804void __init irq_trans_init(struct device_node *dp)
 805{
 806#ifdef CONFIG_PCI
 807        const char *model;
 808        int i;
 809#endif
 810
 811#ifdef CONFIG_PCI
 812        model = of_get_property(dp, "model", NULL);
 813        if (!model)
 814                model = of_get_property(dp, "compatible", NULL);
 815        if (model) {
 816                for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) {
 817                        struct irq_trans *t = &pci_irq_trans_table[i];
 818
 819                        if (!strcmp(model, t->name)) {
 820                                t->init(dp);
 821                                return;
 822                        }
 823                }
 824        }
 825#endif
 826#ifdef CONFIG_SBUS
 827        if (!strcmp(dp->name, "sbus") ||
 828            !strcmp(dp->name, "sbi")) {
 829                sbus_irq_trans_init(dp);
 830                return;
 831        }
 832#endif
 833        if (!strcmp(dp->name, "fhc") &&
 834            !strcmp(dp->parent->name, "central")) {
 835                central_irq_trans_init(dp);
 836                return;
 837        }
 838        if (!strcmp(dp->name, "virtual-devices") ||
 839            !strcmp(dp->name, "niu")) {
 840                sun4v_vdev_irq_trans_init(dp);
 841                return;
 842        }
 843}
 844