linux/arch/m68k/mac/via.c
<<
>>
Prefs
   1/*
   2 *      6522 Versatile Interface Adapter (VIA)
   3 *
   4 *      There are two of these on the Mac II. Some IRQs are vectored
   5 *      via them as are assorted bits and bobs - eg RTC, ADB.
   6 *
   7 * CSA: Motorola seems to have removed documentation on the 6522 from
   8 * their web site; try
   9 *     http://nerini.drf.com/vectrex/other/text/chips/6522/
  10 *     http://www.zymurgy.net/classic/vic20/vicdet1.htm
  11 * and
  12 *     http://193.23.168.87/mikro_laborversuche/via_iobaustein/via6522_1.html
  13 * for info.  A full-text web search on 6522 AND VIA will probably also
  14 * net some usefulness. <cananian@alumni.princeton.edu> 20apr1999
  15 *
  16 * Additional data is here (the SY6522 was used in the Mac II etc):
  17 *     http://www.6502.org/documents/datasheets/synertek/synertek_sy6522.pdf
  18 *     http://www.6502.org/documents/datasheets/synertek/synertek_sy6522_programming_reference.pdf
  19 *
  20 * PRAM/RTC access algorithms are from the NetBSD RTC toolkit version 1.08b
  21 * by Erik Vogan and adapted to Linux by Joshua M. Thompson (funaho@jurai.org)
  22 *
  23 */
  24
  25#include <linux/types.h>
  26#include <linux/kernel.h>
  27#include <linux/mm.h>
  28#include <linux/delay.h>
  29#include <linux/init.h>
  30#include <linux/module.h>
  31#include <linux/irq.h>
  32
  33#include <asm/bootinfo.h>
  34#include <asm/macintosh.h>
  35#include <asm/macints.h>
  36#include <asm/mac_via.h>
  37#include <asm/mac_psc.h>
  38#include <asm/mac_oss.h>
  39
  40volatile __u8 *via1, *via2;
  41int rbv_present;
  42int via_alt_mapping;
  43EXPORT_SYMBOL(via_alt_mapping);
  44static __u8 rbv_clear;
  45
  46/*
  47 * Globals for accessing the VIA chip registers without having to
  48 * check if we're hitting a real VIA or an RBV. Normally you could
  49 * just hit the combined register (ie, vIER|rIER) but that seems to
  50 * break on AV Macs...probably because they actually decode more than
  51 * eight address bits. Why can't Apple engineers at least be
  52 * _consistently_ lazy?                          - 1999-05-21 (jmt)
  53 */
  54
  55static int gIER,gIFR,gBufA,gBufB;
  56
  57/*
  58 * Timer defs.
  59 */
  60
  61#define TICK_SIZE               10000
  62#define MAC_CLOCK_TICK          (783300/HZ)             /* ticks per HZ */
  63#define MAC_CLOCK_LOW           (MAC_CLOCK_TICK&0xFF)
  64#define MAC_CLOCK_HIGH          (MAC_CLOCK_TICK>>8)
  65
  66
  67/*
  68 * On Macs with a genuine VIA chip there is no way to mask an individual slot
  69 * interrupt. This limitation also seems to apply to VIA clone logic cores in
  70 * Quadra-like ASICs. (RBV and OSS machines don't have this limitation.)
  71 *
  72 * We used to fake it by configuring the relevent VIA pin as an output
  73 * (to mask the interrupt) or input (to unmask). That scheme did not work on
  74 * (at least) the Quadra 700. A NuBus card's /NMRQ signal is an open-collector
  75 * circuit (see Designing Cards and Drivers for Macintosh II and Macintosh SE,
  76 * p. 10-11 etc) but VIA outputs are not (see datasheet).
  77 *
  78 * Driving these outputs high must cause the VIA to source current and the
  79 * card to sink current when it asserts /NMRQ. Current will flow but the pin
  80 * voltage is uncertain and so the /NMRQ condition may still cause a transition
  81 * at the VIA2 CA1 input (which explains the lost interrupts). A side effect
  82 * is that a disabled slot IRQ can never be tested as pending or not.
  83 *
  84 * Driving these outputs low doesn't work either. All the slot /NMRQ lines are
  85 * (active low) OR'd together to generate the CA1 (aka "SLOTS") interrupt (see
  86 * The Guide To Macintosh Family Hardware, 2nd edition p. 167). If we drive a
  87 * disabled /NMRQ line low, the falling edge immediately triggers a CA1
  88 * interrupt and all slot interrupts after that will generate no transition
  89 * and therefore no interrupt, even after being re-enabled.
  90 *
  91 * So we make the VIA port A I/O lines inputs and use nubus_disabled to keep
  92 * track of their states. When any slot IRQ becomes disabled we mask the CA1
  93 * umbrella interrupt. Only when all slot IRQs become enabled do we unmask
  94 * the CA1 interrupt. It must remain enabled even when cards have no interrupt
  95 * handler registered. Drivers must therefore disable a slot interrupt at the
  96 * device before they call free_irq (like shared and autovector interrupts).
  97 *
  98 * There is also a related problem when MacOS is used to boot Linux. A network
  99 * card brought up by a MacOS driver may raise an interrupt while Linux boots.
 100 * This can be fatal since it can't be handled until the right driver loads
 101 * (if such a driver exists at all). Apparently related to this hardware
 102 * limitation, "Designing Cards and Drivers", p. 9-8, says that a slot
 103 * interrupt with no driver would crash MacOS (the book was written before
 104 * the appearance of Macs with RBV or OSS).
 105 */
 106
 107static u8 nubus_disabled;
 108
 109void via_debug_dump(void);
 110
 111/*
 112 * Initialize the VIAs
 113 *
 114 * First we figure out where they actually _are_ as well as what type of
 115 * VIA we have for VIA2 (it could be a real VIA or an RBV or even an OSS.)
 116 * Then we pretty much clear them out and disable all IRQ sources.
 117 *
 118 * Note: the OSS is actually "detected" here and not in oss_init(). It just
 119 *       seems more logical to do it here since via_init() needs to know
 120 *       these things anyways.
 121 */
 122
 123void __init via_init(void)
 124{
 125        switch(macintosh_config->via_type) {
 126
 127                /* IIci, IIsi, IIvx, IIvi (P6xx), LC series */
 128
 129                case MAC_VIA_IICI:
 130                        via1 = (void *) VIA1_BASE;
 131                        if (macintosh_config->ident == MAC_MODEL_IIFX) {
 132                                via2 = NULL;
 133                                rbv_present = 0;
 134                                oss_present = 1;
 135                        } else {
 136                                via2 = (void *) RBV_BASE;
 137                                rbv_present = 1;
 138                                oss_present = 0;
 139                        }
 140                        if (macintosh_config->ident == MAC_MODEL_LCIII) {
 141                                rbv_clear = 0x00;
 142                        } else {
 143                                /* on most RBVs (& unlike the VIAs), you   */
 144                                /* need to set bit 7 when you write to IFR */
 145                                /* in order for your clear to occur.       */
 146                                rbv_clear = 0x80;
 147                        }
 148                        gIER = rIER;
 149                        gIFR = rIFR;
 150                        gBufA = rSIFR;
 151                        gBufB = rBufB;
 152                        break;
 153
 154                /* Quadra and early MacIIs agree on the VIA locations */
 155
 156                case MAC_VIA_QUADRA:
 157                case MAC_VIA_II:
 158                        via1 = (void *) VIA1_BASE;
 159                        via2 = (void *) VIA2_BASE;
 160                        rbv_present = 0;
 161                        oss_present = 0;
 162                        rbv_clear = 0x00;
 163                        gIER = vIER;
 164                        gIFR = vIFR;
 165                        gBufA = vBufA;
 166                        gBufB = vBufB;
 167                        break;
 168                default:
 169                        panic("UNKNOWN VIA TYPE");
 170        }
 171
 172        printk(KERN_INFO "VIA1 at %p is a 6522 or clone\n", via1);
 173
 174        printk(KERN_INFO "VIA2 at %p is ", via2);
 175        if (rbv_present) {
 176                printk("an RBV\n");
 177        } else if (oss_present) {
 178                printk("an OSS\n");
 179        } else {
 180                printk("a 6522 or clone\n");
 181        }
 182
 183#ifdef DEBUG_VIA
 184        via_debug_dump();
 185#endif
 186
 187        /*
 188         * Shut down all IRQ sources, reset the timers, and
 189         * kill the timer latch on VIA1.
 190         */
 191
 192        via1[vIER] = 0x7F;
 193        via1[vIFR] = 0x7F;
 194        via1[vT1LL] = 0;
 195        via1[vT1LH] = 0;
 196        via1[vT1CL] = 0;
 197        via1[vT1CH] = 0;
 198        via1[vT2CL] = 0;
 199        via1[vT2CH] = 0;
 200        via1[vACR] &= ~0xC0; /* setup T1 timer with no PB7 output */
 201        via1[vACR] &= ~0x03; /* disable port A & B latches */
 202
 203        /*
 204         * SE/30: disable video IRQ
 205         * XXX: testing for SE/30 VBL
 206         */
 207
 208        if (macintosh_config->ident == MAC_MODEL_SE30) {
 209                via1[vDirB] |= 0x40;
 210                via1[vBufB] |= 0x40;
 211        }
 212
 213        /*
 214         * Set the RTC bits to a known state: all lines to outputs and
 215         * RTC disabled (yes that's 0 to enable and 1 to disable).
 216         */
 217
 218        via1[vDirB] |= (VIA1B_vRTCEnb | VIA1B_vRTCClk | VIA1B_vRTCData);
 219        via1[vBufB] |= (VIA1B_vRTCEnb | VIA1B_vRTCClk);
 220
 221        /* Everything below this point is VIA2/RBV only... */
 222
 223        if (oss_present)
 224                return;
 225
 226        if ((macintosh_config->via_type == MAC_VIA_QUADRA) &&
 227            (macintosh_config->adb_type != MAC_ADB_PB1) &&
 228            (macintosh_config->adb_type != MAC_ADB_PB2) &&
 229            (macintosh_config->ident    != MAC_MODEL_C660) &&
 230            (macintosh_config->ident    != MAC_MODEL_Q840)) {
 231                via_alt_mapping = 1;
 232                via1[vDirB] |= 0x40;
 233                via1[vBufB] &= ~0x40;
 234        } else {
 235                via_alt_mapping = 0;
 236        }
 237
 238        /*
 239         * Now initialize VIA2. For RBV we just kill all interrupts;
 240         * for a regular VIA we also reset the timers and stuff.
 241         */
 242
 243        via2[gIER] = 0x7F;
 244        via2[gIFR] = 0x7F | rbv_clear;
 245        if (!rbv_present) {
 246                via2[vT1LL] = 0;
 247                via2[vT1LH] = 0;
 248                via2[vT1CL] = 0;
 249                via2[vT1CH] = 0;
 250                via2[vT2CL] = 0;
 251                via2[vT2CH] = 0;
 252                via2[vACR] &= ~0xC0; /* setup T1 timer with no PB7 output */
 253                via2[vACR] &= ~0x03; /* disable port A & B latches */
 254        }
 255
 256        /* Everything below this point is VIA2 only... */
 257
 258        if (rbv_present)
 259                return;
 260
 261        /*
 262         * Set vPCR for control line interrupts.
 263         *
 264         * CA1 (SLOTS IRQ), CB1 (ASC IRQ): negative edge trigger.
 265         *
 266         * Macs with ESP SCSI have a negative edge triggered SCSI interrupt.
 267         * Testing reveals that PowerBooks do too. However, the SE/30
 268         * schematic diagram shows an active high NCR5380 IRQ line.
 269         */
 270
 271        pr_debug("VIA2 vPCR is 0x%02X\n", via2[vPCR]);
 272        if (macintosh_config->via_type == MAC_VIA_II) {
 273                /* CA2 (SCSI DRQ), CB2 (SCSI IRQ): indep. input, pos. edge */
 274                via2[vPCR] = 0x66;
 275        } else {
 276                /* CA2 (SCSI DRQ), CB2 (SCSI IRQ): indep. input, neg. edge */
 277                via2[vPCR] = 0x22;
 278        }
 279}
 280
 281/*
 282 * Start the 100 Hz clock
 283 */
 284
 285void __init via_init_clock(irq_handler_t func)
 286{
 287        via1[vACR] |= 0x40;
 288        via1[vT1LL] = MAC_CLOCK_LOW;
 289        via1[vT1LH] = MAC_CLOCK_HIGH;
 290        via1[vT1CL] = MAC_CLOCK_LOW;
 291        via1[vT1CH] = MAC_CLOCK_HIGH;
 292
 293        if (request_irq(IRQ_MAC_TIMER_1, func, 0, "timer", func))
 294                pr_err("Couldn't register %s interrupt\n", "timer");
 295}
 296
 297/*
 298 * Debugging dump, used in various places to see what's going on.
 299 */
 300
 301void via_debug_dump(void)
 302{
 303        printk(KERN_DEBUG "VIA1: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
 304                (uint) via1[vDirA], (uint) via1[vDirB], (uint) via1[vACR]);
 305        printk(KERN_DEBUG "         PCR = 0x%02X  IFR = 0x%02X IER = 0x%02X\n",
 306                (uint) via1[vPCR], (uint) via1[vIFR], (uint) via1[vIER]);
 307        if (oss_present) {
 308                printk(KERN_DEBUG "VIA2: <OSS>\n");
 309        } else if (rbv_present) {
 310                printk(KERN_DEBUG "VIA2:  IFR = 0x%02X  IER = 0x%02X\n",
 311                        (uint) via2[rIFR], (uint) via2[rIER]);
 312                printk(KERN_DEBUG "      SIFR = 0x%02X SIER = 0x%02X\n",
 313                        (uint) via2[rSIFR], (uint) via2[rSIER]);
 314        } else {
 315                printk(KERN_DEBUG "VIA2: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
 316                        (uint) via2[vDirA], (uint) via2[vDirB],
 317                        (uint) via2[vACR]);
 318                printk(KERN_DEBUG "         PCR = 0x%02X  IFR = 0x%02X IER = 0x%02X\n",
 319                        (uint) via2[vPCR],
 320                        (uint) via2[vIFR], (uint) via2[vIER]);
 321        }
 322}
 323
 324/*
 325 * This is always executed with interrupts disabled.
 326 *
 327 * TBI: get time offset between scheduling timer ticks
 328 */
 329
 330u32 mac_gettimeoffset(void)
 331{
 332        unsigned long ticks, offset = 0;
 333
 334        /* read VIA1 timer 2 current value */
 335        ticks = via1[vT1CL] | (via1[vT1CH] << 8);
 336        /* The probability of underflow is less than 2% */
 337        if (ticks > MAC_CLOCK_TICK - MAC_CLOCK_TICK / 50)
 338                /* Check for pending timer interrupt in VIA1 IFR */
 339                if (via1[vIFR] & 0x40) offset = TICK_SIZE;
 340
 341        ticks = MAC_CLOCK_TICK - ticks;
 342        ticks = ticks * 10000L / MAC_CLOCK_TICK;
 343
 344        return (ticks + offset) * 1000;
 345}
 346
 347/*
 348 * Flush the L2 cache on Macs that have it by flipping
 349 * the system into 24-bit mode for an instant.
 350 */
 351
 352void via_flush_cache(void)
 353{
 354        via2[gBufB] &= ~VIA2B_vMode32;
 355        via2[gBufB] |= VIA2B_vMode32;
 356}
 357
 358/*
 359 * Return the status of the L2 cache on a IIci
 360 */
 361
 362int via_get_cache_disable(void)
 363{
 364        /* Safeguard against being called accidentally */
 365        if (!via2) {
 366                printk(KERN_ERR "via_get_cache_disable called on a non-VIA machine!\n");
 367                return 1;
 368        }
 369
 370        return (int) via2[gBufB] & VIA2B_vCDis;
 371}
 372
 373/*
 374 * Initialize VIA2 for Nubus access
 375 */
 376
 377void __init via_nubus_init(void)
 378{
 379        /* unlock nubus transactions */
 380
 381        if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
 382            (macintosh_config->adb_type != MAC_ADB_PB2)) {
 383                /* set the line to be an output on non-RBV machines */
 384                if (!rbv_present)
 385                        via2[vDirB] |= 0x02;
 386
 387                /* this seems to be an ADB bit on PMU machines */
 388                /* according to MkLinux.  -- jmt               */
 389                via2[gBufB] |= 0x02;
 390        }
 391
 392        /*
 393         * Disable the slot interrupts. On some hardware that's not possible.
 394         * On some hardware it's unclear what all of these I/O lines do.
 395         */
 396
 397        switch (macintosh_config->via_type) {
 398        case MAC_VIA_II:
 399        case MAC_VIA_QUADRA:
 400                pr_debug("VIA2 vDirA is 0x%02X\n", via2[vDirA]);
 401                break;
 402        case MAC_VIA_IICI:
 403                /* RBV. Disable all the slot interrupts. SIER works like IER. */
 404                via2[rSIER] = 0x7F;
 405                break;
 406        }
 407}
 408
 409void via_nubus_irq_startup(int irq)
 410{
 411        int irq_idx = IRQ_IDX(irq);
 412
 413        switch (macintosh_config->via_type) {
 414        case MAC_VIA_II:
 415        case MAC_VIA_QUADRA:
 416                /* Make the port A line an input. Probably redundant. */
 417                if (macintosh_config->via_type == MAC_VIA_II) {
 418                        /* The top two bits are RAM size outputs. */
 419                        via2[vDirA] &= 0xC0 | ~(1 << irq_idx);
 420                } else {
 421                        /* Allow NuBus slots 9 through F. */
 422                        via2[vDirA] &= 0x80 | ~(1 << irq_idx);
 423                }
 424                /* fall through */
 425        case MAC_VIA_IICI:
 426                via_irq_enable(irq);
 427                break;
 428        }
 429}
 430
 431void via_nubus_irq_shutdown(int irq)
 432{
 433        switch (macintosh_config->via_type) {
 434        case MAC_VIA_II:
 435        case MAC_VIA_QUADRA:
 436                /* Ensure that the umbrella CA1 interrupt remains enabled. */
 437                via_irq_enable(irq);
 438                break;
 439        case MAC_VIA_IICI:
 440                via_irq_disable(irq);
 441                break;
 442        }
 443}
 444
 445/*
 446 * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's
 447 * via6522.c :-), disable/pending masks added.
 448 */
 449
 450void via1_irq(unsigned int irq, struct irq_desc *desc)
 451{
 452        int irq_num;
 453        unsigned char irq_bit, events;
 454
 455        events = via1[vIFR] & via1[vIER] & 0x7F;
 456        if (!events)
 457                return;
 458
 459        irq_num = VIA1_SOURCE_BASE;
 460        irq_bit = 1;
 461        do {
 462                if (events & irq_bit) {
 463                        via1[vIFR] = irq_bit;
 464                        generic_handle_irq(irq_num);
 465                }
 466                ++irq_num;
 467                irq_bit <<= 1;
 468        } while (events >= irq_bit);
 469}
 470
 471static void via2_irq(unsigned int irq, struct irq_desc *desc)
 472{
 473        int irq_num;
 474        unsigned char irq_bit, events;
 475
 476        events = via2[gIFR] & via2[gIER] & 0x7F;
 477        if (!events)
 478                return;
 479
 480        irq_num = VIA2_SOURCE_BASE;
 481        irq_bit = 1;
 482        do {
 483                if (events & irq_bit) {
 484                        via2[gIFR] = irq_bit | rbv_clear;
 485                        generic_handle_irq(irq_num);
 486                }
 487                ++irq_num;
 488                irq_bit <<= 1;
 489        } while (events >= irq_bit);
 490}
 491
 492/*
 493 * Dispatch Nubus interrupts. We are called as a secondary dispatch by the
 494 * VIA2 dispatcher as a fast interrupt handler.
 495 */
 496
 497void via_nubus_irq(unsigned int irq, struct irq_desc *desc)
 498{
 499        int slot_irq;
 500        unsigned char slot_bit, events;
 501
 502        events = ~via2[gBufA] & 0x7F;
 503        if (rbv_present)
 504                events &= via2[rSIER];
 505        else
 506                events &= ~via2[vDirA];
 507        if (!events)
 508                return;
 509
 510        do {
 511                slot_irq = IRQ_NUBUS_F;
 512                slot_bit = 0x40;
 513                do {
 514                        if (events & slot_bit) {
 515                                events &= ~slot_bit;
 516                                generic_handle_irq(slot_irq);
 517                        }
 518                        --slot_irq;
 519                        slot_bit >>= 1;
 520                } while (events);
 521
 522                /* clear the CA1 interrupt and make certain there's no more. */
 523                via2[gIFR] = 0x02 | rbv_clear;
 524                events = ~via2[gBufA] & 0x7F;
 525                if (rbv_present)
 526                        events &= via2[rSIER];
 527                else
 528                        events &= ~via2[vDirA];
 529        } while (events);
 530}
 531
 532/*
 533 * Register the interrupt dispatchers for VIA or RBV machines only.
 534 */
 535
 536void __init via_register_interrupts(void)
 537{
 538        if (via_alt_mapping) {
 539                /* software interrupt */
 540                irq_set_chained_handler(IRQ_AUTO_1, via1_irq);
 541                /* via1 interrupt */
 542                irq_set_chained_handler(IRQ_AUTO_6, via1_irq);
 543        } else {
 544                irq_set_chained_handler(IRQ_AUTO_1, via1_irq);
 545        }
 546        irq_set_chained_handler(IRQ_AUTO_2, via2_irq);
 547        irq_set_chained_handler(IRQ_MAC_NUBUS, via_nubus_irq);
 548}
 549
 550void via_irq_enable(int irq) {
 551        int irq_src     = IRQ_SRC(irq);
 552        int irq_idx     = IRQ_IDX(irq);
 553
 554#ifdef DEBUG_IRQUSE
 555        printk(KERN_DEBUG "via_irq_enable(%d)\n", irq);
 556#endif
 557
 558        if (irq_src == 1) {
 559                via1[vIER] = IER_SET_BIT(irq_idx);
 560        } else if (irq_src == 2) {
 561                if (irq != IRQ_MAC_NUBUS || nubus_disabled == 0)
 562                        via2[gIER] = IER_SET_BIT(irq_idx);
 563        } else if (irq_src == 7) {
 564                switch (macintosh_config->via_type) {
 565                case MAC_VIA_II:
 566                case MAC_VIA_QUADRA:
 567                        nubus_disabled &= ~(1 << irq_idx);
 568                        /* Enable the CA1 interrupt when no slot is disabled. */
 569                        if (!nubus_disabled)
 570                                via2[gIER] = IER_SET_BIT(1);
 571                        break;
 572                case MAC_VIA_IICI:
 573                        /* On RBV, enable the slot interrupt.
 574                         * SIER works like IER.
 575                         */
 576                        via2[rSIER] = IER_SET_BIT(irq_idx);
 577                        break;
 578                }
 579        }
 580}
 581
 582void via_irq_disable(int irq) {
 583        int irq_src     = IRQ_SRC(irq);
 584        int irq_idx     = IRQ_IDX(irq);
 585
 586#ifdef DEBUG_IRQUSE
 587        printk(KERN_DEBUG "via_irq_disable(%d)\n", irq);
 588#endif
 589
 590        if (irq_src == 1) {
 591                via1[vIER] = IER_CLR_BIT(irq_idx);
 592        } else if (irq_src == 2) {
 593                via2[gIER] = IER_CLR_BIT(irq_idx);
 594        } else if (irq_src == 7) {
 595                switch (macintosh_config->via_type) {
 596                case MAC_VIA_II:
 597                case MAC_VIA_QUADRA:
 598                        nubus_disabled |= 1 << irq_idx;
 599                        if (nubus_disabled)
 600                                via2[gIER] = IER_CLR_BIT(1);
 601                        break;
 602                case MAC_VIA_IICI:
 603                        via2[rSIER] = IER_CLR_BIT(irq_idx);
 604                        break;
 605                }
 606        }
 607}
 608
 609void via1_set_head(int head)
 610{
 611        if (head == 0)
 612                via1[vBufA] &= ~VIA1A_vHeadSel;
 613        else
 614                via1[vBufA] |= VIA1A_vHeadSel;
 615}
 616EXPORT_SYMBOL(via1_set_head);
 617
 618int via2_scsi_drq_pending(void)
 619{
 620        return via2[gIFR] & (1 << IRQ_IDX(IRQ_MAC_SCSIDRQ));
 621}
 622EXPORT_SYMBOL(via2_scsi_drq_pending);
 623