linux/arch/mips/sni/rm200.c
<<
>>
Prefs
   1/*
   2 * RM200 specific code
   3 *
   4 * This file is subject to the terms and conditions of the GNU General Public
   5 * License.  See the file "COPYING" in the main directory of this archive
   6 * for more details.
   7 *
   8 * Copyright (C) 2006,2007 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
   9 *
  10 * i8259 parts ripped out of arch/mips/kernel/i8259.c
  11 */
  12
  13#include <linux/delay.h>
  14#include <linux/init.h>
  15#include <linux/interrupt.h>
  16#include <linux/platform_device.h>
  17#include <linux/serial_8250.h>
  18#include <linux/io.h>
  19
  20#include <asm/sni.h>
  21#include <asm/time.h>
  22#include <asm/irq_cpu.h>
  23
  24#define RM200_I8259A_IRQ_BASE 32
  25
  26#define MEMPORT(_base,_irq)                             \
  27        {                                               \
  28                .mapbase        = _base,                \
  29                .irq            = _irq,                 \
  30                .uartclk        = 1843200,              \
  31                .iotype         = UPIO_MEM,             \
  32                .flags          = UPF_BOOT_AUTOCONF|UPF_IOREMAP, \
  33        }
  34
  35static struct plat_serial8250_port rm200_data[] = {
  36        MEMPORT(0x160003f8, RM200_I8259A_IRQ_BASE + 4),
  37        MEMPORT(0x160002f8, RM200_I8259A_IRQ_BASE + 3),
  38        { },
  39};
  40
  41static struct platform_device rm200_serial8250_device = {
  42        .name                   = "serial8250",
  43        .id                     = PLAT8250_DEV_PLATFORM,
  44        .dev                    = {
  45                .platform_data  = rm200_data,
  46        },
  47};
  48
  49static struct resource rm200_ds1216_rsrc[] = {
  50        {
  51                .start = 0x1cd41ffc,
  52                .end   = 0x1cd41fff,
  53                .flags = IORESOURCE_MEM
  54        }
  55};
  56
  57static struct platform_device rm200_ds1216_device = {
  58        .name           = "rtc-ds1216",
  59        .num_resources  = ARRAY_SIZE(rm200_ds1216_rsrc),
  60        .resource       = rm200_ds1216_rsrc
  61};
  62
  63static struct resource snirm_82596_rm200_rsrc[] = {
  64        {
  65                .start = 0x18000000,
  66                .end   = 0x180fffff,
  67                .flags = IORESOURCE_MEM
  68        },
  69        {
  70                .start = 0x1b000000,
  71                .end   = 0x1b000004,
  72                .flags = IORESOURCE_MEM
  73        },
  74        {
  75                .start = 0x1ff00000,
  76                .end   = 0x1ff00020,
  77                .flags = IORESOURCE_MEM
  78        },
  79        {
  80                .start = 27,
  81                .end   = 27,
  82                .flags = IORESOURCE_IRQ
  83        },
  84        {
  85                .flags = 0x00
  86        }
  87};
  88
  89static struct platform_device snirm_82596_rm200_pdev = {
  90        .name           = "snirm_82596",
  91        .num_resources  = ARRAY_SIZE(snirm_82596_rm200_rsrc),
  92        .resource       = snirm_82596_rm200_rsrc
  93};
  94
  95static struct resource snirm_53c710_rm200_rsrc[] = {
  96        {
  97                .start = 0x19000000,
  98                .end   = 0x190fffff,
  99                .flags = IORESOURCE_MEM
 100        },
 101        {
 102                .start = 26,
 103                .end   = 26,
 104                .flags = IORESOURCE_IRQ
 105        }
 106};
 107
 108static struct platform_device snirm_53c710_rm200_pdev = {
 109        .name           = "snirm_53c710",
 110        .num_resources  = ARRAY_SIZE(snirm_53c710_rm200_rsrc),
 111        .resource       = snirm_53c710_rm200_rsrc
 112};
 113
 114static int __init snirm_setup_devinit(void)
 115{
 116        if (sni_brd_type == SNI_BRD_RM200) {
 117                platform_device_register(&rm200_serial8250_device);
 118                platform_device_register(&rm200_ds1216_device);
 119                platform_device_register(&snirm_82596_rm200_pdev);
 120                platform_device_register(&snirm_53c710_rm200_pdev);
 121                sni_eisa_root_init();
 122        }
 123        return 0;
 124}
 125
 126device_initcall(snirm_setup_devinit);
 127
 128/*
 129 * RM200 has an ISA and an EISA bus. The iSA bus is only used
 130 * for onboard devices and also has twi i8259 PICs. Since these
 131 * PICs are no accessible via inb/outb the following code uses
 132 * readb/writeb to access them
 133 */
 134
 135DEFINE_SPINLOCK(sni_rm200_i8259A_lock);
 136#define PIC_CMD    0x00
 137#define PIC_IMR    0x01
 138#define PIC_ISR    PIC_CMD
 139#define PIC_POLL   PIC_ISR
 140#define PIC_OCW3   PIC_ISR
 141
 142/* i8259A PIC related value */
 143#define PIC_CASCADE_IR          2
 144#define MASTER_ICW4_DEFAULT     0x01
 145#define SLAVE_ICW4_DEFAULT      0x01
 146
 147/*
 148 * This contains the irq mask for both 8259A irq controllers,
 149 */
 150static unsigned int rm200_cached_irq_mask = 0xffff;
 151static __iomem u8 *rm200_pic_master;
 152static __iomem u8 *rm200_pic_slave;
 153
 154#define cached_master_mask      (rm200_cached_irq_mask)
 155#define cached_slave_mask       (rm200_cached_irq_mask >> 8)
 156
 157static void sni_rm200_disable_8259A_irq(unsigned int irq)
 158{
 159        unsigned int mask;
 160        unsigned long flags;
 161
 162        irq -= RM200_I8259A_IRQ_BASE;
 163        mask = 1 << irq;
 164        spin_lock_irqsave(&sni_rm200_i8259A_lock, flags);
 165        rm200_cached_irq_mask |= mask;
 166        if (irq & 8)
 167                writeb(cached_slave_mask, rm200_pic_slave + PIC_IMR);
 168        else
 169                writeb(cached_master_mask, rm200_pic_master + PIC_IMR);
 170        spin_unlock_irqrestore(&sni_rm200_i8259A_lock, flags);
 171}
 172
 173static void sni_rm200_enable_8259A_irq(unsigned int irq)
 174{
 175        unsigned int mask;
 176        unsigned long flags;
 177
 178        irq -= RM200_I8259A_IRQ_BASE;
 179        mask = ~(1 << irq);
 180        spin_lock_irqsave(&sni_rm200_i8259A_lock, flags);
 181        rm200_cached_irq_mask &= mask;
 182        if (irq & 8)
 183                writeb(cached_slave_mask, rm200_pic_slave + PIC_IMR);
 184        else
 185                writeb(cached_master_mask, rm200_pic_master + PIC_IMR);
 186        spin_unlock_irqrestore(&sni_rm200_i8259A_lock, flags);
 187}
 188
 189static inline int sni_rm200_i8259A_irq_real(unsigned int irq)
 190{
 191        int value;
 192        int irqmask = 1 << irq;
 193
 194        if (irq < 8) {
 195                writeb(0x0B, rm200_pic_master + PIC_CMD);
 196                value = readb(rm200_pic_master + PIC_CMD) & irqmask;
 197                writeb(0x0A, rm200_pic_master + PIC_CMD);
 198                return value;
 199        }
 200        writeb(0x0B, rm200_pic_slave + PIC_CMD); /* ISR register */
 201        value = readb(rm200_pic_slave + PIC_CMD) & (irqmask >> 8);
 202        writeb(0x0A, rm200_pic_slave + PIC_CMD);
 203        return value;
 204}
 205
 206/*
 207 * Careful! The 8259A is a fragile beast, it pretty
 208 * much _has_ to be done exactly like this (mask it
 209 * first, _then_ send the EOI, and the order of EOI
 210 * to the two 8259s is important!
 211 */
 212void sni_rm200_mask_and_ack_8259A(unsigned int irq)
 213{
 214        unsigned int irqmask;
 215        unsigned long flags;
 216
 217        irq -= RM200_I8259A_IRQ_BASE;
 218        irqmask = 1 << irq;
 219        spin_lock_irqsave(&sni_rm200_i8259A_lock, flags);
 220        /*
 221         * Lightweight spurious IRQ detection. We do not want
 222         * to overdo spurious IRQ handling - it's usually a sign
 223         * of hardware problems, so we only do the checks we can
 224         * do without slowing down good hardware unnecessarily.
 225         *
 226         * Note that IRQ7 and IRQ15 (the two spurious IRQs
 227         * usually resulting from the 8259A-1|2 PICs) occur
 228         * even if the IRQ is masked in the 8259A. Thus we
 229         * can check spurious 8259A IRQs without doing the
 230         * quite slow i8259A_irq_real() call for every IRQ.
 231         * This does not cover 100% of spurious interrupts,
 232         * but should be enough to warn the user that there
 233         * is something bad going on ...
 234         */
 235        if (rm200_cached_irq_mask & irqmask)
 236                goto spurious_8259A_irq;
 237        rm200_cached_irq_mask |= irqmask;
 238
 239handle_real_irq:
 240        if (irq & 8) {
 241                readb(rm200_pic_slave + PIC_IMR);
 242                writeb(cached_slave_mask, rm200_pic_slave + PIC_IMR);
 243                writeb(0x60+(irq & 7), rm200_pic_slave + PIC_CMD);
 244                writeb(0x60+PIC_CASCADE_IR, rm200_pic_master + PIC_CMD);
 245        } else {
 246                readb(rm200_pic_master + PIC_IMR);
 247                writeb(cached_master_mask, rm200_pic_master + PIC_IMR);
 248                writeb(0x60+irq, rm200_pic_master + PIC_CMD);
 249        }
 250        spin_unlock_irqrestore(&sni_rm200_i8259A_lock, flags);
 251        return;
 252
 253spurious_8259A_irq:
 254        /*
 255         * this is the slow path - should happen rarely.
 256         */
 257        if (sni_rm200_i8259A_irq_real(irq))
 258                /*
 259                 * oops, the IRQ _is_ in service according to the
 260                 * 8259A - not spurious, go handle it.
 261                 */
 262                goto handle_real_irq;
 263
 264        {
 265                static int spurious_irq_mask;
 266                /*
 267                 * At this point we can be sure the IRQ is spurious,
 268                 * lets ACK and report it. [once per IRQ]
 269                 */
 270                if (!(spurious_irq_mask & irqmask)) {
 271                        printk(KERN_DEBUG
 272                               "spurious RM200 8259A interrupt: IRQ%d.\n", irq);
 273                        spurious_irq_mask |= irqmask;
 274                }
 275                atomic_inc(&irq_err_count);
 276                /*
 277                 * Theoretically we do not have to handle this IRQ,
 278                 * but in Linux this does not cause problems and is
 279                 * simpler for us.
 280                 */
 281                goto handle_real_irq;
 282        }
 283}
 284
 285static struct irq_chip sni_rm200_i8259A_chip = {
 286        .name           = "RM200-XT-PIC",
 287        .mask           = sni_rm200_disable_8259A_irq,
 288        .unmask         = sni_rm200_enable_8259A_irq,
 289        .mask_ack       = sni_rm200_mask_and_ack_8259A,
 290};
 291
 292/*
 293 * Do the traditional i8259 interrupt polling thing.  This is for the few
 294 * cases where no better interrupt acknowledge method is available and we
 295 * absolutely must touch the i8259.
 296 */
 297static inline int sni_rm200_i8259_irq(void)
 298{
 299        int irq;
 300
 301        spin_lock(&sni_rm200_i8259A_lock);
 302
 303        /* Perform an interrupt acknowledge cycle on controller 1. */
 304        writeb(0x0C, rm200_pic_master + PIC_CMD);       /* prepare for poll */
 305        irq = readb(rm200_pic_master + PIC_CMD) & 7;
 306        if (irq == PIC_CASCADE_IR) {
 307                /*
 308                 * Interrupt is cascaded so perform interrupt
 309                 * acknowledge on controller 2.
 310                 */
 311                writeb(0x0C, rm200_pic_slave + PIC_CMD); /* prepare for poll */
 312                irq = (readb(rm200_pic_slave + PIC_CMD) & 7) + 8;
 313        }
 314
 315        if (unlikely(irq == 7)) {
 316                /*
 317                 * This may be a spurious interrupt.
 318                 *
 319                 * Read the interrupt status register (ISR). If the most
 320                 * significant bit is not set then there is no valid
 321                 * interrupt.
 322                 */
 323                writeb(0x0B, rm200_pic_master + PIC_ISR); /* ISR register */
 324                if (~readb(rm200_pic_master + PIC_ISR) & 0x80)
 325                        irq = -1;
 326        }
 327
 328        spin_unlock(&sni_rm200_i8259A_lock);
 329
 330        return likely(irq >= 0) ? irq + RM200_I8259A_IRQ_BASE : irq;
 331}
 332
 333void sni_rm200_init_8259A(void)
 334{
 335        unsigned long flags;
 336
 337        spin_lock_irqsave(&sni_rm200_i8259A_lock, flags);
 338
 339        writeb(0xff, rm200_pic_master + PIC_IMR);
 340        writeb(0xff, rm200_pic_slave + PIC_IMR);
 341
 342        writeb(0x11, rm200_pic_master + PIC_CMD);
 343        writeb(0, rm200_pic_master + PIC_IMR);
 344        writeb(1U << PIC_CASCADE_IR, rm200_pic_master + PIC_IMR);
 345        writeb(MASTER_ICW4_DEFAULT, rm200_pic_master + PIC_IMR);
 346        writeb(0x11, rm200_pic_slave + PIC_CMD);
 347        writeb(8, rm200_pic_slave + PIC_IMR);
 348        writeb(PIC_CASCADE_IR, rm200_pic_slave + PIC_IMR);
 349        writeb(SLAVE_ICW4_DEFAULT, rm200_pic_slave + PIC_IMR);
 350        udelay(100);            /* wait for 8259A to initialize */
 351
 352        writeb(cached_master_mask, rm200_pic_master + PIC_IMR);
 353        writeb(cached_slave_mask, rm200_pic_slave + PIC_IMR);
 354
 355        spin_unlock_irqrestore(&sni_rm200_i8259A_lock, flags);
 356}
 357
 358/*
 359 * IRQ2 is cascade interrupt to second interrupt controller
 360 */
 361static struct irqaction sni_rm200_irq2 = {
 362        .handler = no_action,
 363        .name = "cascade",
 364};
 365
 366static struct resource sni_rm200_pic1_resource = {
 367        .name = "onboard ISA pic1",
 368        .start = 0x16000020,
 369        .end = 0x16000023,
 370        .flags = IORESOURCE_BUSY
 371};
 372
 373static struct resource sni_rm200_pic2_resource = {
 374        .name = "onboard ISA pic2",
 375        .start = 0x160000a0,
 376        .end = 0x160000a3,
 377        .flags = IORESOURCE_BUSY
 378};
 379
 380/* ISA irq handler */
 381static irqreturn_t sni_rm200_i8259A_irq_handler(int dummy, void *p)
 382{
 383        int irq;
 384
 385        irq = sni_rm200_i8259_irq();
 386        if (unlikely(irq < 0))
 387                return IRQ_NONE;
 388
 389        do_IRQ(irq);
 390        return IRQ_HANDLED;
 391}
 392
 393struct irqaction sni_rm200_i8259A_irq = {
 394        .handler = sni_rm200_i8259A_irq_handler,
 395        .name = "onboard ISA",
 396        .flags = IRQF_SHARED
 397};
 398
 399void __init sni_rm200_i8259_irqs(void)
 400{
 401        int i;
 402
 403        rm200_pic_master = ioremap_nocache(0x16000020, 4);
 404        if (!rm200_pic_master)
 405                return;
 406        rm200_pic_slave = ioremap_nocache(0x160000a0, 4);
 407        if (!rm200_pic_master) {
 408                iounmap(rm200_pic_master);
 409                return;
 410        }
 411
 412        insert_resource(&iomem_resource, &sni_rm200_pic1_resource);
 413        insert_resource(&iomem_resource, &sni_rm200_pic2_resource);
 414
 415        sni_rm200_init_8259A();
 416
 417        for (i = RM200_I8259A_IRQ_BASE; i < RM200_I8259A_IRQ_BASE + 16; i++)
 418                set_irq_chip_and_handler(i, &sni_rm200_i8259A_chip,
 419                                         handle_level_irq);
 420
 421        setup_irq(RM200_I8259A_IRQ_BASE + PIC_CASCADE_IR, &sni_rm200_irq2);
 422}
 423
 424
 425#define SNI_RM200_INT_STAT_REG  CKSEG1ADDR(0xbc000000)
 426#define SNI_RM200_INT_ENA_REG   CKSEG1ADDR(0xbc080000)
 427
 428#define SNI_RM200_INT_START  24
 429#define SNI_RM200_INT_END    28
 430
 431static void enable_rm200_irq(unsigned int irq)
 432{
 433        unsigned int mask = 1 << (irq - SNI_RM200_INT_START);
 434
 435        *(volatile u8 *)SNI_RM200_INT_ENA_REG &= ~mask;
 436}
 437
 438void disable_rm200_irq(unsigned int irq)
 439{
 440        unsigned int mask = 1 << (irq - SNI_RM200_INT_START);
 441
 442        *(volatile u8 *)SNI_RM200_INT_ENA_REG |= mask;
 443}
 444
 445void end_rm200_irq(unsigned int irq)
 446{
 447        if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
 448                enable_rm200_irq(irq);
 449}
 450
 451static struct irq_chip rm200_irq_type = {
 452        .typename = "RM200",
 453        .ack = disable_rm200_irq,
 454        .mask = disable_rm200_irq,
 455        .mask_ack = disable_rm200_irq,
 456        .unmask = enable_rm200_irq,
 457        .end = end_rm200_irq,
 458};
 459
 460static void sni_rm200_hwint(void)
 461{
 462        u32 pending = read_c0_cause() & read_c0_status();
 463        u8 mask;
 464        u8 stat;
 465        int irq;
 466
 467        if (pending & C_IRQ5)
 468                do_IRQ(MIPS_CPU_IRQ_BASE + 7);
 469        else if (pending & C_IRQ0) {
 470                clear_c0_status(IE_IRQ0);
 471                mask = *(volatile u8 *)SNI_RM200_INT_ENA_REG ^ 0x1f;
 472                stat = *(volatile u8 *)SNI_RM200_INT_STAT_REG ^ 0x14;
 473                irq = ffs(stat & mask & 0x1f);
 474
 475                if (likely(irq > 0))
 476                        do_IRQ(irq + SNI_RM200_INT_START - 1);
 477                set_c0_status(IE_IRQ0);
 478        }
 479}
 480
 481void __init sni_rm200_irq_init(void)
 482{
 483        int i;
 484
 485        * (volatile u8 *)SNI_RM200_INT_ENA_REG = 0x1f;
 486
 487        sni_rm200_i8259_irqs();
 488        mips_cpu_irq_init();
 489        /* Actually we've got more interrupts to handle ...  */
 490        for (i = SNI_RM200_INT_START; i <= SNI_RM200_INT_END; i++)
 491                set_irq_chip_and_handler(i, &rm200_irq_type, handle_level_irq);
 492        sni_hwint = sni_rm200_hwint;
 493        change_c0_status(ST0_IM, IE_IRQ0);
 494        setup_irq(SNI_RM200_INT_START + 0, &sni_rm200_i8259A_irq);
 495        setup_irq(SNI_RM200_INT_START + 1, &sni_isa_irq);
 496}
 497
 498void __init sni_rm200_init(void)
 499{
 500}
 501
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.