18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *	6522 Versatile Interface Adapter (VIA)
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *	There are two of these on the Mac II. Some IRQs are vectored
68c2ecf20Sopenharmony_ci *	via them as are assorted bits and bobs - eg RTC, ADB.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * CSA: Motorola seems to have removed documentation on the 6522 from
98c2ecf20Sopenharmony_ci * their web site; try
108c2ecf20Sopenharmony_ci *     http://nerini.drf.com/vectrex/other/text/chips/6522/
118c2ecf20Sopenharmony_ci *     http://www.zymurgy.net/classic/vic20/vicdet1.htm
128c2ecf20Sopenharmony_ci * and
138c2ecf20Sopenharmony_ci *     http://193.23.168.87/mikro_laborversuche/via_iobaustein/via6522_1.html
148c2ecf20Sopenharmony_ci * for info.  A full-text web search on 6522 AND VIA will probably also
158c2ecf20Sopenharmony_ci * net some usefulness. <cananian@alumni.princeton.edu> 20apr1999
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci * Additional data is here (the SY6522 was used in the Mac II etc):
188c2ecf20Sopenharmony_ci *     http://www.6502.org/documents/datasheets/synertek/synertek_sy6522.pdf
198c2ecf20Sopenharmony_ci *     http://www.6502.org/documents/datasheets/synertek/synertek_sy6522_programming_reference.pdf
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * PRAM/RTC access algorithms are from the NetBSD RTC toolkit version 1.08b
228c2ecf20Sopenharmony_ci * by Erik Vogan and adapted to Linux by Joshua M. Thompson (funaho@jurai.org)
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include <linux/clocksource.h>
278c2ecf20Sopenharmony_ci#include <linux/types.h>
288c2ecf20Sopenharmony_ci#include <linux/kernel.h>
298c2ecf20Sopenharmony_ci#include <linux/mm.h>
308c2ecf20Sopenharmony_ci#include <linux/delay.h>
318c2ecf20Sopenharmony_ci#include <linux/init.h>
328c2ecf20Sopenharmony_ci#include <linux/module.h>
338c2ecf20Sopenharmony_ci#include <linux/irq.h>
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include <asm/macintosh.h>
368c2ecf20Sopenharmony_ci#include <asm/macints.h>
378c2ecf20Sopenharmony_ci#include <asm/mac_via.h>
388c2ecf20Sopenharmony_ci#include <asm/mac_psc.h>
398c2ecf20Sopenharmony_ci#include <asm/mac_oss.h>
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_civolatile __u8 *via1, *via2;
428c2ecf20Sopenharmony_ciint rbv_present;
438c2ecf20Sopenharmony_ciint via_alt_mapping;
448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(via_alt_mapping);
458c2ecf20Sopenharmony_cistatic __u8 rbv_clear;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci/*
488c2ecf20Sopenharmony_ci * Globals for accessing the VIA chip registers without having to
498c2ecf20Sopenharmony_ci * check if we're hitting a real VIA or an RBV. Normally you could
508c2ecf20Sopenharmony_ci * just hit the combined register (ie, vIER|rIER) but that seems to
518c2ecf20Sopenharmony_ci * break on AV Macs...probably because they actually decode more than
528c2ecf20Sopenharmony_ci * eight address bits. Why can't Apple engineers at least be
538c2ecf20Sopenharmony_ci * _consistently_ lazy?                          - 1999-05-21 (jmt)
548c2ecf20Sopenharmony_ci */
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic int gIER,gIFR,gBufA,gBufB;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/*
598c2ecf20Sopenharmony_ci * On Macs with a genuine VIA chip there is no way to mask an individual slot
608c2ecf20Sopenharmony_ci * interrupt. This limitation also seems to apply to VIA clone logic cores in
618c2ecf20Sopenharmony_ci * Quadra-like ASICs. (RBV and OSS machines don't have this limitation.)
628c2ecf20Sopenharmony_ci *
638c2ecf20Sopenharmony_ci * We used to fake it by configuring the relevant VIA pin as an output
648c2ecf20Sopenharmony_ci * (to mask the interrupt) or input (to unmask). That scheme did not work on
658c2ecf20Sopenharmony_ci * (at least) the Quadra 700. A NuBus card's /NMRQ signal is an open-collector
668c2ecf20Sopenharmony_ci * circuit (see Designing Cards and Drivers for Macintosh II and Macintosh SE,
678c2ecf20Sopenharmony_ci * p. 10-11 etc) but VIA outputs are not (see datasheet).
688c2ecf20Sopenharmony_ci *
698c2ecf20Sopenharmony_ci * Driving these outputs high must cause the VIA to source current and the
708c2ecf20Sopenharmony_ci * card to sink current when it asserts /NMRQ. Current will flow but the pin
718c2ecf20Sopenharmony_ci * voltage is uncertain and so the /NMRQ condition may still cause a transition
728c2ecf20Sopenharmony_ci * at the VIA2 CA1 input (which explains the lost interrupts). A side effect
738c2ecf20Sopenharmony_ci * is that a disabled slot IRQ can never be tested as pending or not.
748c2ecf20Sopenharmony_ci *
758c2ecf20Sopenharmony_ci * Driving these outputs low doesn't work either. All the slot /NMRQ lines are
768c2ecf20Sopenharmony_ci * (active low) OR'd together to generate the CA1 (aka "SLOTS") interrupt (see
778c2ecf20Sopenharmony_ci * The Guide To Macintosh Family Hardware, 2nd edition p. 167). If we drive a
788c2ecf20Sopenharmony_ci * disabled /NMRQ line low, the falling edge immediately triggers a CA1
798c2ecf20Sopenharmony_ci * interrupt and all slot interrupts after that will generate no transition
808c2ecf20Sopenharmony_ci * and therefore no interrupt, even after being re-enabled.
818c2ecf20Sopenharmony_ci *
828c2ecf20Sopenharmony_ci * So we make the VIA port A I/O lines inputs and use nubus_disabled to keep
838c2ecf20Sopenharmony_ci * track of their states. When any slot IRQ becomes disabled we mask the CA1
848c2ecf20Sopenharmony_ci * umbrella interrupt. Only when all slot IRQs become enabled do we unmask
858c2ecf20Sopenharmony_ci * the CA1 interrupt. It must remain enabled even when cards have no interrupt
868c2ecf20Sopenharmony_ci * handler registered. Drivers must therefore disable a slot interrupt at the
878c2ecf20Sopenharmony_ci * device before they call free_irq (like shared and autovector interrupts).
888c2ecf20Sopenharmony_ci *
898c2ecf20Sopenharmony_ci * There is also a related problem when MacOS is used to boot Linux. A network
908c2ecf20Sopenharmony_ci * card brought up by a MacOS driver may raise an interrupt while Linux boots.
918c2ecf20Sopenharmony_ci * This can be fatal since it can't be handled until the right driver loads
928c2ecf20Sopenharmony_ci * (if such a driver exists at all). Apparently related to this hardware
938c2ecf20Sopenharmony_ci * limitation, "Designing Cards and Drivers", p. 9-8, says that a slot
948c2ecf20Sopenharmony_ci * interrupt with no driver would crash MacOS (the book was written before
958c2ecf20Sopenharmony_ci * the appearance of Macs with RBV or OSS).
968c2ecf20Sopenharmony_ci */
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic u8 nubus_disabled;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_civoid via_debug_dump(void);
1018c2ecf20Sopenharmony_cistatic void via_nubus_init(void);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci/*
1048c2ecf20Sopenharmony_ci * Initialize the VIAs
1058c2ecf20Sopenharmony_ci *
1068c2ecf20Sopenharmony_ci * First we figure out where they actually _are_ as well as what type of
1078c2ecf20Sopenharmony_ci * VIA we have for VIA2 (it could be a real VIA or an RBV or even an OSS.)
1088c2ecf20Sopenharmony_ci * Then we pretty much clear them out and disable all IRQ sources.
1098c2ecf20Sopenharmony_ci */
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_civoid __init via_init(void)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	via1 = (void *)VIA1_BASE;
1148c2ecf20Sopenharmony_ci	pr_debug("VIA1 detected at %p\n", via1);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	if (oss_present) {
1178c2ecf20Sopenharmony_ci		via2 = NULL;
1188c2ecf20Sopenharmony_ci		rbv_present = 0;
1198c2ecf20Sopenharmony_ci	} else {
1208c2ecf20Sopenharmony_ci		switch (macintosh_config->via_type) {
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci		/* IIci, IIsi, IIvx, IIvi (P6xx), LC series */
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci		case MAC_VIA_IICI:
1258c2ecf20Sopenharmony_ci			via2 = (void *)RBV_BASE;
1268c2ecf20Sopenharmony_ci			pr_debug("VIA2 (RBV) detected at %p\n", via2);
1278c2ecf20Sopenharmony_ci			rbv_present = 1;
1288c2ecf20Sopenharmony_ci			if (macintosh_config->ident == MAC_MODEL_LCIII) {
1298c2ecf20Sopenharmony_ci				rbv_clear = 0x00;
1308c2ecf20Sopenharmony_ci			} else {
1318c2ecf20Sopenharmony_ci				/* on most RBVs (& unlike the VIAs), you   */
1328c2ecf20Sopenharmony_ci				/* need to set bit 7 when you write to IFR */
1338c2ecf20Sopenharmony_ci				/* in order for your clear to occur.       */
1348c2ecf20Sopenharmony_ci				rbv_clear = 0x80;
1358c2ecf20Sopenharmony_ci			}
1368c2ecf20Sopenharmony_ci			gIER = rIER;
1378c2ecf20Sopenharmony_ci			gIFR = rIFR;
1388c2ecf20Sopenharmony_ci			gBufA = rSIFR;
1398c2ecf20Sopenharmony_ci			gBufB = rBufB;
1408c2ecf20Sopenharmony_ci			break;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci		/* Quadra and early MacIIs agree on the VIA locations */
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci		case MAC_VIA_QUADRA:
1458c2ecf20Sopenharmony_ci		case MAC_VIA_II:
1468c2ecf20Sopenharmony_ci			via2 = (void *) VIA2_BASE;
1478c2ecf20Sopenharmony_ci			pr_debug("VIA2 detected at %p\n", via2);
1488c2ecf20Sopenharmony_ci			rbv_present = 0;
1498c2ecf20Sopenharmony_ci			rbv_clear = 0x00;
1508c2ecf20Sopenharmony_ci			gIER = vIER;
1518c2ecf20Sopenharmony_ci			gIFR = vIFR;
1528c2ecf20Sopenharmony_ci			gBufA = vBufA;
1538c2ecf20Sopenharmony_ci			gBufB = vBufB;
1548c2ecf20Sopenharmony_ci			break;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci		default:
1578c2ecf20Sopenharmony_ci			panic("UNKNOWN VIA TYPE");
1588c2ecf20Sopenharmony_ci		}
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci#ifdef DEBUG_VIA
1628c2ecf20Sopenharmony_ci	via_debug_dump();
1638c2ecf20Sopenharmony_ci#endif
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	/*
1668c2ecf20Sopenharmony_ci	 * Shut down all IRQ sources, reset the timers, and
1678c2ecf20Sopenharmony_ci	 * kill the timer latch on VIA1.
1688c2ecf20Sopenharmony_ci	 */
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	via1[vIER] = 0x7F;
1718c2ecf20Sopenharmony_ci	via1[vIFR] = 0x7F;
1728c2ecf20Sopenharmony_ci	via1[vT1LL] = 0;
1738c2ecf20Sopenharmony_ci	via1[vT1LH] = 0;
1748c2ecf20Sopenharmony_ci	via1[vT1CL] = 0;
1758c2ecf20Sopenharmony_ci	via1[vT1CH] = 0;
1768c2ecf20Sopenharmony_ci	via1[vT2CL] = 0;
1778c2ecf20Sopenharmony_ci	via1[vT2CH] = 0;
1788c2ecf20Sopenharmony_ci	via1[vACR] &= ~0xC0; /* setup T1 timer with no PB7 output */
1798c2ecf20Sopenharmony_ci	via1[vACR] &= ~0x03; /* disable port A & B latches */
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	/*
1828c2ecf20Sopenharmony_ci	 * SE/30: disable video IRQ
1838c2ecf20Sopenharmony_ci	 */
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (macintosh_config->ident == MAC_MODEL_SE30) {
1868c2ecf20Sopenharmony_ci		via1[vDirB] |= 0x40;
1878c2ecf20Sopenharmony_ci		via1[vBufB] |= 0x40;
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	switch (macintosh_config->adb_type) {
1918c2ecf20Sopenharmony_ci	case MAC_ADB_IOP:
1928c2ecf20Sopenharmony_ci	case MAC_ADB_II:
1938c2ecf20Sopenharmony_ci	case MAC_ADB_PB1:
1948c2ecf20Sopenharmony_ci		/*
1958c2ecf20Sopenharmony_ci		 * Set the RTC bits to a known state: all lines to outputs and
1968c2ecf20Sopenharmony_ci		 * RTC disabled (yes that's 0 to enable and 1 to disable).
1978c2ecf20Sopenharmony_ci		 */
1988c2ecf20Sopenharmony_ci		via1[vDirB] |= VIA1B_vRTCEnb | VIA1B_vRTCClk | VIA1B_vRTCData;
1998c2ecf20Sopenharmony_ci		via1[vBufB] |= VIA1B_vRTCEnb | VIA1B_vRTCClk;
2008c2ecf20Sopenharmony_ci		break;
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	/* Everything below this point is VIA2/RBV only... */
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	if (oss_present)
2068c2ecf20Sopenharmony_ci		return;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	if ((macintosh_config->via_type == MAC_VIA_QUADRA) &&
2098c2ecf20Sopenharmony_ci	    (macintosh_config->adb_type != MAC_ADB_PB1) &&
2108c2ecf20Sopenharmony_ci	    (macintosh_config->adb_type != MAC_ADB_PB2) &&
2118c2ecf20Sopenharmony_ci	    (macintosh_config->ident    != MAC_MODEL_C660) &&
2128c2ecf20Sopenharmony_ci	    (macintosh_config->ident    != MAC_MODEL_Q840)) {
2138c2ecf20Sopenharmony_ci		via_alt_mapping = 1;
2148c2ecf20Sopenharmony_ci		via1[vDirB] |= 0x40;
2158c2ecf20Sopenharmony_ci		via1[vBufB] &= ~0x40;
2168c2ecf20Sopenharmony_ci	} else {
2178c2ecf20Sopenharmony_ci		via_alt_mapping = 0;
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	/*
2218c2ecf20Sopenharmony_ci	 * Now initialize VIA2. For RBV we just kill all interrupts;
2228c2ecf20Sopenharmony_ci	 * for a regular VIA we also reset the timers and stuff.
2238c2ecf20Sopenharmony_ci	 */
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	via2[gIER] = 0x7F;
2268c2ecf20Sopenharmony_ci	via2[gIFR] = 0x7F | rbv_clear;
2278c2ecf20Sopenharmony_ci	if (!rbv_present) {
2288c2ecf20Sopenharmony_ci		via2[vT1LL] = 0;
2298c2ecf20Sopenharmony_ci		via2[vT1LH] = 0;
2308c2ecf20Sopenharmony_ci		via2[vT1CL] = 0;
2318c2ecf20Sopenharmony_ci		via2[vT1CH] = 0;
2328c2ecf20Sopenharmony_ci		via2[vT2CL] = 0;
2338c2ecf20Sopenharmony_ci		via2[vT2CH] = 0;
2348c2ecf20Sopenharmony_ci		via2[vACR] &= ~0xC0; /* setup T1 timer with no PB7 output */
2358c2ecf20Sopenharmony_ci		via2[vACR] &= ~0x03; /* disable port A & B latches */
2368c2ecf20Sopenharmony_ci	}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	via_nubus_init();
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	/* Everything below this point is VIA2 only... */
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	if (rbv_present)
2438c2ecf20Sopenharmony_ci		return;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	/*
2468c2ecf20Sopenharmony_ci	 * Set vPCR for control line interrupts.
2478c2ecf20Sopenharmony_ci	 *
2488c2ecf20Sopenharmony_ci	 * CA1 (SLOTS IRQ), CB1 (ASC IRQ): negative edge trigger.
2498c2ecf20Sopenharmony_ci	 *
2508c2ecf20Sopenharmony_ci	 * Macs with ESP SCSI have a negative edge triggered SCSI interrupt.
2518c2ecf20Sopenharmony_ci	 * Testing reveals that PowerBooks do too. However, the SE/30
2528c2ecf20Sopenharmony_ci	 * schematic diagram shows an active high NCR5380 IRQ line.
2538c2ecf20Sopenharmony_ci	 */
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	pr_debug("VIA2 vPCR is 0x%02X\n", via2[vPCR]);
2568c2ecf20Sopenharmony_ci	if (macintosh_config->via_type == MAC_VIA_II) {
2578c2ecf20Sopenharmony_ci		/* CA2 (SCSI DRQ), CB2 (SCSI IRQ): indep. input, pos. edge */
2588c2ecf20Sopenharmony_ci		via2[vPCR] = 0x66;
2598c2ecf20Sopenharmony_ci	} else {
2608c2ecf20Sopenharmony_ci		/* CA2 (SCSI DRQ), CB2 (SCSI IRQ): indep. input, neg. edge */
2618c2ecf20Sopenharmony_ci		via2[vPCR] = 0x22;
2628c2ecf20Sopenharmony_ci	}
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci/*
2668c2ecf20Sopenharmony_ci * Debugging dump, used in various places to see what's going on.
2678c2ecf20Sopenharmony_ci */
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_civoid via_debug_dump(void)
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "VIA1: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
2728c2ecf20Sopenharmony_ci		(uint) via1[vDirA], (uint) via1[vDirB], (uint) via1[vACR]);
2738c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "         PCR = 0x%02X  IFR = 0x%02X IER = 0x%02X\n",
2748c2ecf20Sopenharmony_ci		(uint) via1[vPCR], (uint) via1[vIFR], (uint) via1[vIER]);
2758c2ecf20Sopenharmony_ci	if (!via2)
2768c2ecf20Sopenharmony_ci		return;
2778c2ecf20Sopenharmony_ci	if (rbv_present) {
2788c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "VIA2:  IFR = 0x%02X  IER = 0x%02X\n",
2798c2ecf20Sopenharmony_ci			(uint) via2[rIFR], (uint) via2[rIER]);
2808c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "      SIFR = 0x%02X SIER = 0x%02X\n",
2818c2ecf20Sopenharmony_ci			(uint) via2[rSIFR], (uint) via2[rSIER]);
2828c2ecf20Sopenharmony_ci	} else {
2838c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "VIA2: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
2848c2ecf20Sopenharmony_ci			(uint) via2[vDirA], (uint) via2[vDirB],
2858c2ecf20Sopenharmony_ci			(uint) via2[vACR]);
2868c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "         PCR = 0x%02X  IFR = 0x%02X IER = 0x%02X\n",
2878c2ecf20Sopenharmony_ci			(uint) via2[vPCR],
2888c2ecf20Sopenharmony_ci			(uint) via2[vIFR], (uint) via2[vIER]);
2898c2ecf20Sopenharmony_ci	}
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci/*
2938c2ecf20Sopenharmony_ci * Flush the L2 cache on Macs that have it by flipping
2948c2ecf20Sopenharmony_ci * the system into 24-bit mode for an instant.
2958c2ecf20Sopenharmony_ci */
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_civoid via_l2_flush(int writeback)
2988c2ecf20Sopenharmony_ci{
2998c2ecf20Sopenharmony_ci	unsigned long flags;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	local_irq_save(flags);
3028c2ecf20Sopenharmony_ci	via2[gBufB] &= ~VIA2B_vMode32;
3038c2ecf20Sopenharmony_ci	via2[gBufB] |= VIA2B_vMode32;
3048c2ecf20Sopenharmony_ci	local_irq_restore(flags);
3058c2ecf20Sopenharmony_ci}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci/*
3088c2ecf20Sopenharmony_ci * Return the status of the L2 cache on a IIci
3098c2ecf20Sopenharmony_ci */
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ciint via_get_cache_disable(void)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	/* Safeguard against being called accidentally */
3148c2ecf20Sopenharmony_ci	if (!via2) {
3158c2ecf20Sopenharmony_ci		printk(KERN_ERR "via_get_cache_disable called on a non-VIA machine!\n");
3168c2ecf20Sopenharmony_ci		return 1;
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	return (int) via2[gBufB] & VIA2B_vCDis;
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci/*
3238c2ecf20Sopenharmony_ci * Initialize VIA2 for Nubus access
3248c2ecf20Sopenharmony_ci */
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_cistatic void __init via_nubus_init(void)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	/* unlock nubus transactions */
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
3318c2ecf20Sopenharmony_ci	    (macintosh_config->adb_type != MAC_ADB_PB2)) {
3328c2ecf20Sopenharmony_ci		/* set the line to be an output on non-RBV machines */
3338c2ecf20Sopenharmony_ci		if (!rbv_present)
3348c2ecf20Sopenharmony_ci			via2[vDirB] |= 0x02;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci		/* this seems to be an ADB bit on PMU machines */
3378c2ecf20Sopenharmony_ci		/* according to MkLinux.  -- jmt               */
3388c2ecf20Sopenharmony_ci		via2[gBufB] |= 0x02;
3398c2ecf20Sopenharmony_ci	}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	/*
3428c2ecf20Sopenharmony_ci	 * Disable the slot interrupts. On some hardware that's not possible.
3438c2ecf20Sopenharmony_ci	 * On some hardware it's unclear what all of these I/O lines do.
3448c2ecf20Sopenharmony_ci	 */
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	switch (macintosh_config->via_type) {
3478c2ecf20Sopenharmony_ci	case MAC_VIA_II:
3488c2ecf20Sopenharmony_ci	case MAC_VIA_QUADRA:
3498c2ecf20Sopenharmony_ci		pr_debug("VIA2 vDirA is 0x%02X\n", via2[vDirA]);
3508c2ecf20Sopenharmony_ci		break;
3518c2ecf20Sopenharmony_ci	case MAC_VIA_IICI:
3528c2ecf20Sopenharmony_ci		/* RBV. Disable all the slot interrupts. SIER works like IER. */
3538c2ecf20Sopenharmony_ci		via2[rSIER] = 0x7F;
3548c2ecf20Sopenharmony_ci		break;
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_civoid via_nubus_irq_startup(int irq)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci	int irq_idx = IRQ_IDX(irq);
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	switch (macintosh_config->via_type) {
3638c2ecf20Sopenharmony_ci	case MAC_VIA_II:
3648c2ecf20Sopenharmony_ci	case MAC_VIA_QUADRA:
3658c2ecf20Sopenharmony_ci		/* Make the port A line an input. Probably redundant. */
3668c2ecf20Sopenharmony_ci		if (macintosh_config->via_type == MAC_VIA_II) {
3678c2ecf20Sopenharmony_ci			/* The top two bits are RAM size outputs. */
3688c2ecf20Sopenharmony_ci			via2[vDirA] &= 0xC0 | ~(1 << irq_idx);
3698c2ecf20Sopenharmony_ci		} else {
3708c2ecf20Sopenharmony_ci			/* Allow NuBus slots 9 through F. */
3718c2ecf20Sopenharmony_ci			via2[vDirA] &= 0x80 | ~(1 << irq_idx);
3728c2ecf20Sopenharmony_ci		}
3738c2ecf20Sopenharmony_ci		fallthrough;
3748c2ecf20Sopenharmony_ci	case MAC_VIA_IICI:
3758c2ecf20Sopenharmony_ci		via_irq_enable(irq);
3768c2ecf20Sopenharmony_ci		break;
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_civoid via_nubus_irq_shutdown(int irq)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	switch (macintosh_config->via_type) {
3838c2ecf20Sopenharmony_ci	case MAC_VIA_II:
3848c2ecf20Sopenharmony_ci	case MAC_VIA_QUADRA:
3858c2ecf20Sopenharmony_ci		/* Ensure that the umbrella CA1 interrupt remains enabled. */
3868c2ecf20Sopenharmony_ci		via_irq_enable(irq);
3878c2ecf20Sopenharmony_ci		break;
3888c2ecf20Sopenharmony_ci	case MAC_VIA_IICI:
3898c2ecf20Sopenharmony_ci		via_irq_disable(irq);
3908c2ecf20Sopenharmony_ci		break;
3918c2ecf20Sopenharmony_ci	}
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci/*
3958c2ecf20Sopenharmony_ci * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's
3968c2ecf20Sopenharmony_ci * via6522.c :-), disable/pending masks added.
3978c2ecf20Sopenharmony_ci */
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci#define VIA_TIMER_1_INT BIT(6)
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_civoid via1_irq(struct irq_desc *desc)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	int irq_num;
4048c2ecf20Sopenharmony_ci	unsigned char irq_bit, events;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	events = via1[vIFR] & via1[vIER] & 0x7F;
4078c2ecf20Sopenharmony_ci	if (!events)
4088c2ecf20Sopenharmony_ci		return;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	irq_num = IRQ_MAC_TIMER_1;
4118c2ecf20Sopenharmony_ci	irq_bit = VIA_TIMER_1_INT;
4128c2ecf20Sopenharmony_ci	if (events & irq_bit) {
4138c2ecf20Sopenharmony_ci		unsigned long flags;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci		local_irq_save(flags);
4168c2ecf20Sopenharmony_ci		via1[vIFR] = irq_bit;
4178c2ecf20Sopenharmony_ci		generic_handle_irq(irq_num);
4188c2ecf20Sopenharmony_ci		local_irq_restore(flags);
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci		events &= ~irq_bit;
4218c2ecf20Sopenharmony_ci		if (!events)
4228c2ecf20Sopenharmony_ci			return;
4238c2ecf20Sopenharmony_ci	}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	irq_num = VIA1_SOURCE_BASE;
4268c2ecf20Sopenharmony_ci	irq_bit = 1;
4278c2ecf20Sopenharmony_ci	do {
4288c2ecf20Sopenharmony_ci		if (events & irq_bit) {
4298c2ecf20Sopenharmony_ci			via1[vIFR] = irq_bit;
4308c2ecf20Sopenharmony_ci			generic_handle_irq(irq_num);
4318c2ecf20Sopenharmony_ci		}
4328c2ecf20Sopenharmony_ci		++irq_num;
4338c2ecf20Sopenharmony_ci		irq_bit <<= 1;
4348c2ecf20Sopenharmony_ci	} while (events >= irq_bit);
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_cistatic void via2_irq(struct irq_desc *desc)
4388c2ecf20Sopenharmony_ci{
4398c2ecf20Sopenharmony_ci	int irq_num;
4408c2ecf20Sopenharmony_ci	unsigned char irq_bit, events;
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	events = via2[gIFR] & via2[gIER] & 0x7F;
4438c2ecf20Sopenharmony_ci	if (!events)
4448c2ecf20Sopenharmony_ci		return;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	irq_num = VIA2_SOURCE_BASE;
4478c2ecf20Sopenharmony_ci	irq_bit = 1;
4488c2ecf20Sopenharmony_ci	do {
4498c2ecf20Sopenharmony_ci		if (events & irq_bit) {
4508c2ecf20Sopenharmony_ci			via2[gIFR] = irq_bit | rbv_clear;
4518c2ecf20Sopenharmony_ci			generic_handle_irq(irq_num);
4528c2ecf20Sopenharmony_ci		}
4538c2ecf20Sopenharmony_ci		++irq_num;
4548c2ecf20Sopenharmony_ci		irq_bit <<= 1;
4558c2ecf20Sopenharmony_ci	} while (events >= irq_bit);
4568c2ecf20Sopenharmony_ci}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci/*
4598c2ecf20Sopenharmony_ci * Dispatch Nubus interrupts. We are called as a secondary dispatch by the
4608c2ecf20Sopenharmony_ci * VIA2 dispatcher as a fast interrupt handler.
4618c2ecf20Sopenharmony_ci */
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_cistatic void via_nubus_irq(struct irq_desc *desc)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	int slot_irq;
4668c2ecf20Sopenharmony_ci	unsigned char slot_bit, events;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	events = ~via2[gBufA] & 0x7F;
4698c2ecf20Sopenharmony_ci	if (rbv_present)
4708c2ecf20Sopenharmony_ci		events &= via2[rSIER];
4718c2ecf20Sopenharmony_ci	else
4728c2ecf20Sopenharmony_ci		events &= ~via2[vDirA];
4738c2ecf20Sopenharmony_ci	if (!events)
4748c2ecf20Sopenharmony_ci		return;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	do {
4778c2ecf20Sopenharmony_ci		slot_irq = IRQ_NUBUS_F;
4788c2ecf20Sopenharmony_ci		slot_bit = 0x40;
4798c2ecf20Sopenharmony_ci		do {
4808c2ecf20Sopenharmony_ci			if (events & slot_bit) {
4818c2ecf20Sopenharmony_ci				events &= ~slot_bit;
4828c2ecf20Sopenharmony_ci				generic_handle_irq(slot_irq);
4838c2ecf20Sopenharmony_ci			}
4848c2ecf20Sopenharmony_ci			--slot_irq;
4858c2ecf20Sopenharmony_ci			slot_bit >>= 1;
4868c2ecf20Sopenharmony_ci		} while (events);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci 		/* clear the CA1 interrupt and make certain there's no more. */
4898c2ecf20Sopenharmony_ci		via2[gIFR] = 0x02 | rbv_clear;
4908c2ecf20Sopenharmony_ci		events = ~via2[gBufA] & 0x7F;
4918c2ecf20Sopenharmony_ci		if (rbv_present)
4928c2ecf20Sopenharmony_ci			events &= via2[rSIER];
4938c2ecf20Sopenharmony_ci		else
4948c2ecf20Sopenharmony_ci			events &= ~via2[vDirA];
4958c2ecf20Sopenharmony_ci	} while (events);
4968c2ecf20Sopenharmony_ci}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci/*
4998c2ecf20Sopenharmony_ci * Register the interrupt dispatchers for VIA or RBV machines only.
5008c2ecf20Sopenharmony_ci */
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_civoid __init via_register_interrupts(void)
5038c2ecf20Sopenharmony_ci{
5048c2ecf20Sopenharmony_ci	if (via_alt_mapping) {
5058c2ecf20Sopenharmony_ci		/* software interrupt */
5068c2ecf20Sopenharmony_ci		irq_set_chained_handler(IRQ_AUTO_1, via1_irq);
5078c2ecf20Sopenharmony_ci		/* via1 interrupt */
5088c2ecf20Sopenharmony_ci		irq_set_chained_handler(IRQ_AUTO_6, via1_irq);
5098c2ecf20Sopenharmony_ci	} else {
5108c2ecf20Sopenharmony_ci		irq_set_chained_handler(IRQ_AUTO_1, via1_irq);
5118c2ecf20Sopenharmony_ci	}
5128c2ecf20Sopenharmony_ci	irq_set_chained_handler(IRQ_AUTO_2, via2_irq);
5138c2ecf20Sopenharmony_ci	irq_set_chained_handler(IRQ_MAC_NUBUS, via_nubus_irq);
5148c2ecf20Sopenharmony_ci}
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_civoid via_irq_enable(int irq) {
5178c2ecf20Sopenharmony_ci	int irq_src	= IRQ_SRC(irq);
5188c2ecf20Sopenharmony_ci	int irq_idx	= IRQ_IDX(irq);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	if (irq_src == 1) {
5218c2ecf20Sopenharmony_ci		via1[vIER] = IER_SET_BIT(irq_idx);
5228c2ecf20Sopenharmony_ci	} else if (irq_src == 2) {
5238c2ecf20Sopenharmony_ci		if (irq != IRQ_MAC_NUBUS || nubus_disabled == 0)
5248c2ecf20Sopenharmony_ci			via2[gIER] = IER_SET_BIT(irq_idx);
5258c2ecf20Sopenharmony_ci	} else if (irq_src == 7) {
5268c2ecf20Sopenharmony_ci		switch (macintosh_config->via_type) {
5278c2ecf20Sopenharmony_ci		case MAC_VIA_II:
5288c2ecf20Sopenharmony_ci		case MAC_VIA_QUADRA:
5298c2ecf20Sopenharmony_ci			nubus_disabled &= ~(1 << irq_idx);
5308c2ecf20Sopenharmony_ci			/* Enable the CA1 interrupt when no slot is disabled. */
5318c2ecf20Sopenharmony_ci			if (!nubus_disabled)
5328c2ecf20Sopenharmony_ci				via2[gIER] = IER_SET_BIT(1);
5338c2ecf20Sopenharmony_ci			break;
5348c2ecf20Sopenharmony_ci		case MAC_VIA_IICI:
5358c2ecf20Sopenharmony_ci			/* On RBV, enable the slot interrupt.
5368c2ecf20Sopenharmony_ci			 * SIER works like IER.
5378c2ecf20Sopenharmony_ci			 */
5388c2ecf20Sopenharmony_ci			via2[rSIER] = IER_SET_BIT(irq_idx);
5398c2ecf20Sopenharmony_ci			break;
5408c2ecf20Sopenharmony_ci		}
5418c2ecf20Sopenharmony_ci	}
5428c2ecf20Sopenharmony_ci}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_civoid via_irq_disable(int irq) {
5458c2ecf20Sopenharmony_ci	int irq_src	= IRQ_SRC(irq);
5468c2ecf20Sopenharmony_ci	int irq_idx	= IRQ_IDX(irq);
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	if (irq_src == 1) {
5498c2ecf20Sopenharmony_ci		via1[vIER] = IER_CLR_BIT(irq_idx);
5508c2ecf20Sopenharmony_ci	} else if (irq_src == 2) {
5518c2ecf20Sopenharmony_ci		via2[gIER] = IER_CLR_BIT(irq_idx);
5528c2ecf20Sopenharmony_ci	} else if (irq_src == 7) {
5538c2ecf20Sopenharmony_ci		switch (macintosh_config->via_type) {
5548c2ecf20Sopenharmony_ci		case MAC_VIA_II:
5558c2ecf20Sopenharmony_ci		case MAC_VIA_QUADRA:
5568c2ecf20Sopenharmony_ci			nubus_disabled |= 1 << irq_idx;
5578c2ecf20Sopenharmony_ci			if (nubus_disabled)
5588c2ecf20Sopenharmony_ci				via2[gIER] = IER_CLR_BIT(1);
5598c2ecf20Sopenharmony_ci			break;
5608c2ecf20Sopenharmony_ci		case MAC_VIA_IICI:
5618c2ecf20Sopenharmony_ci			via2[rSIER] = IER_CLR_BIT(irq_idx);
5628c2ecf20Sopenharmony_ci			break;
5638c2ecf20Sopenharmony_ci		}
5648c2ecf20Sopenharmony_ci	}
5658c2ecf20Sopenharmony_ci}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_civoid via1_set_head(int head)
5688c2ecf20Sopenharmony_ci{
5698c2ecf20Sopenharmony_ci	if (head == 0)
5708c2ecf20Sopenharmony_ci		via1[vBufA] &= ~VIA1A_vHeadSel;
5718c2ecf20Sopenharmony_ci	else
5728c2ecf20Sopenharmony_ci		via1[vBufA] |= VIA1A_vHeadSel;
5738c2ecf20Sopenharmony_ci}
5748c2ecf20Sopenharmony_ciEXPORT_SYMBOL(via1_set_head);
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ciint via2_scsi_drq_pending(void)
5778c2ecf20Sopenharmony_ci{
5788c2ecf20Sopenharmony_ci	return via2[gIFR] & (1 << IRQ_IDX(IRQ_MAC_SCSIDRQ));
5798c2ecf20Sopenharmony_ci}
5808c2ecf20Sopenharmony_ciEXPORT_SYMBOL(via2_scsi_drq_pending);
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci/* timer and clock source */
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci#define VIA_CLOCK_FREQ     783360                /* VIA "phase 2" clock in Hz */
5858c2ecf20Sopenharmony_ci#define VIA_TIMER_CYCLES   (VIA_CLOCK_FREQ / HZ) /* clock cycles per jiffy */
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci#define VIA_TC             (VIA_TIMER_CYCLES - 2) /* including 0 and -1 */
5888c2ecf20Sopenharmony_ci#define VIA_TC_LOW         (VIA_TC & 0xFF)
5898c2ecf20Sopenharmony_ci#define VIA_TC_HIGH        (VIA_TC >> 8)
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_cistatic u64 mac_read_clk(struct clocksource *cs);
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_cistatic struct clocksource mac_clk = {
5948c2ecf20Sopenharmony_ci	.name   = "via1",
5958c2ecf20Sopenharmony_ci	.rating = 250,
5968c2ecf20Sopenharmony_ci	.read   = mac_read_clk,
5978c2ecf20Sopenharmony_ci	.mask   = CLOCKSOURCE_MASK(32),
5988c2ecf20Sopenharmony_ci	.flags  = CLOCK_SOURCE_IS_CONTINUOUS,
5998c2ecf20Sopenharmony_ci};
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_cistatic u32 clk_total, clk_offset;
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_cistatic irqreturn_t via_timer_handler(int irq, void *dev_id)
6048c2ecf20Sopenharmony_ci{
6058c2ecf20Sopenharmony_ci	irq_handler_t timer_routine = dev_id;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	clk_total += VIA_TIMER_CYCLES;
6088c2ecf20Sopenharmony_ci	clk_offset = 0;
6098c2ecf20Sopenharmony_ci	timer_routine(0, NULL);
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
6128c2ecf20Sopenharmony_ci}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_civoid __init via_init_clock(irq_handler_t timer_routine)
6158c2ecf20Sopenharmony_ci{
6168c2ecf20Sopenharmony_ci	if (request_irq(IRQ_MAC_TIMER_1, via_timer_handler, IRQF_TIMER, "timer",
6178c2ecf20Sopenharmony_ci			timer_routine)) {
6188c2ecf20Sopenharmony_ci		pr_err("Couldn't register %s interrupt\n", "timer");
6198c2ecf20Sopenharmony_ci		return;
6208c2ecf20Sopenharmony_ci	}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	via1[vT1LL] = VIA_TC_LOW;
6238c2ecf20Sopenharmony_ci	via1[vT1LH] = VIA_TC_HIGH;
6248c2ecf20Sopenharmony_ci	via1[vT1CL] = VIA_TC_LOW;
6258c2ecf20Sopenharmony_ci	via1[vT1CH] = VIA_TC_HIGH;
6268c2ecf20Sopenharmony_ci	via1[vACR] |= 0x40;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	clocksource_register_hz(&mac_clk, VIA_CLOCK_FREQ);
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_cistatic u64 mac_read_clk(struct clocksource *cs)
6328c2ecf20Sopenharmony_ci{
6338c2ecf20Sopenharmony_ci	unsigned long flags;
6348c2ecf20Sopenharmony_ci	u8 count_high;
6358c2ecf20Sopenharmony_ci	u16 count;
6368c2ecf20Sopenharmony_ci	u32 ticks;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	/*
6398c2ecf20Sopenharmony_ci	 * Timer counter wrap-around is detected with the timer interrupt flag
6408c2ecf20Sopenharmony_ci	 * but reading the counter low byte (vT1CL) would reset the flag.
6418c2ecf20Sopenharmony_ci	 * Also, accessing both counter registers is essentially a data race.
6428c2ecf20Sopenharmony_ci	 * These problems are avoided by ignoring the low byte. Clock accuracy
6438c2ecf20Sopenharmony_ci	 * is 256 times worse (error can reach 0.327 ms) but CPU overhead is
6448c2ecf20Sopenharmony_ci	 * reduced by avoiding slow VIA register accesses.
6458c2ecf20Sopenharmony_ci	 */
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	local_irq_save(flags);
6488c2ecf20Sopenharmony_ci	count_high = via1[vT1CH];
6498c2ecf20Sopenharmony_ci	if (count_high == 0xFF)
6508c2ecf20Sopenharmony_ci		count_high = 0;
6518c2ecf20Sopenharmony_ci	if (count_high > 0 && (via1[vIFR] & VIA_TIMER_1_INT))
6528c2ecf20Sopenharmony_ci		clk_offset = VIA_TIMER_CYCLES;
6538c2ecf20Sopenharmony_ci	count = count_high << 8;
6548c2ecf20Sopenharmony_ci	ticks = VIA_TIMER_CYCLES - count;
6558c2ecf20Sopenharmony_ci	ticks += clk_offset + clk_total;
6568c2ecf20Sopenharmony_ci	local_irq_restore(flags);
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	return ticks;
6598c2ecf20Sopenharmony_ci}
660