/* * Offset between Unix time (1970-based) and Mac time (1904-based). Cuda and PMU * times wrap in 2040. If we need to handle later times, the read_time functions * need to be changed to interpret wrapped times as post-2040.
*/
/* * Execute a VIA PRAM/RTC command. For read commands * data should point to a one-byte buffer for the * resulting data. For write commands it should point * to the data byte to for the command. * * This function disables all interrupts while running.
*/
staticvoid via_rtc_command(int command, __u8 *data)
{ unsignedlong flags; int is_read;
local_irq_save(flags);
/* The least significant bits must be 0b01 according to Inside Mac */
command = (command & ~3) | 1;
/* Enable the RTC and make sure the strobe line is high */
/* * Return the current time in seconds since January 1, 1904. * * This only works on machines with the VIA-based PRAM/RTC, which * is basically any machine with Mac II-style ADB.
*/
static time64_t via_read_time(void)
{ union {
__u8 cdata[4];
__u32 idata;
} result, last_result; int count = 1;
if (result.idata == last_result.idata) return (time64_t)result.idata - RTC_OFFSET;
if (++count > 10) break;
last_result.idata = result.idata;
}
pr_err("%s: failed to read a stable value; got 0x%08x then 0x%08x\n",
__func__, last_result.idata, result.idata);
return 0;
}
/* * Set the current time to a number of seconds since January 1, 1904. * * This only works on machines with the VIA-based PRAM/RTC, which * is basically any machine with Mac II-style ADB.
*/
staticvoid via_shutdown(void)
{ if (rbv_present) {
via2[rBufB] &= ~0x04;
} else { /* Direction of vDirB is output */
via2[vDirB] |= 0x04; /* Send a value of 0 on that line */
via2[vBufB] &= ~0x04;
mdelay(1000);
}
}
if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN) < 0) return;
/* Avoid infinite polling loop when PSU is not under Cuda control */ switch (macintosh_config->ident) { case MAC_MODEL_C660: case MAC_MODEL_Q605: case MAC_MODEL_Q605_ACC: case MAC_MODEL_P475: case MAC_MODEL_P475F: return;
}
while (!req.complete)
cuda_poll();
} #endif/* CONFIG_ADB_CUDA */
/* *------------------------------------------------------------------- * Below this point are the generic routines; they'll dispatch to the * correct routine for the hardware on which we're running. *-------------------------------------------------------------------
*/
#if IS_ENABLED(CONFIG_NVRAM) unsignedchar mac_pram_read_byte(int addr)
{ switch (macintosh_config->adb_type) { case MAC_ADB_IOP: case MAC_ADB_II: case MAC_ADB_PB1: return via_pram_read_byte(addr); #ifdef CONFIG_ADB_CUDA case MAC_ADB_EGRET: case MAC_ADB_CUDA: return cuda_pram_read_byte(addr); #endif #ifdef CONFIG_ADB_PMU case MAC_ADB_PB2: return pmu_pram_read_byte(addr); #endif default: return 0xFF;
}
}
void mac_pram_write_byte(unsignedchar val, int addr)
{ switch (macintosh_config->adb_type) { case MAC_ADB_IOP: case MAC_ADB_II: case MAC_ADB_PB1:
via_pram_write_byte(val, addr); break; #ifdef CONFIG_ADB_CUDA case MAC_ADB_EGRET: case MAC_ADB_CUDA:
cuda_pram_write_byte(val, addr); break; #endif #ifdef CONFIG_ADB_PMU case MAC_ADB_PB2:
pmu_pram_write_byte(val, addr); break; #endif default: break;
}
}
pr_crit("It is now safe to turn off your Macintosh.\n");
local_irq_disable(); while(1);
}
void mac_reset(void)
{ #ifdef CONFIG_ADB_CUDA if (macintosh_config->adb_type == MAC_ADB_EGRET ||
macintosh_config->adb_type == MAC_ADB_CUDA) {
cuda_restart();
} else #endif #ifdef CONFIG_ADB_PMU if (macintosh_config->adb_type == MAC_ADB_PB2) {
pmu_restart();
} else #endif if (CPU_IS_030) { /* 030-specific reset routine. The idea is general, but the * specific registers to reset are '030-specific. Until I * have a non-030 machine, I can't test anything else. * -- C. Scott Ananian <cananian@alumni.princeton.edu>
*/
unsignedlong rombase = 0x40000000;
/* make a 1-to-1 mapping, using the transparent tran. reg. */ unsignedlong virt = (unsignedlong) mac_reset; unsignedlong phys = virt_to_phys(mac_reset); unsignedlong addr = (phys&0xFF000000)|0x8777; unsignedlong offset = phys-virt;
local_irq_disable(); /* lets not screw this up, ok? */
__asm__ __volatile__(".chip 68030\n\t" "pmove %0,%/tt0\n\t" ".chip 68k"
: : "m" (addr)); /* Now jump to physical address so we can disable MMU */
__asm__ __volatile__( ".chip 68030\n\t" "lea %/pc@(1f),%/a0\n\t" "addl %0,%/a0\n\t"/* fixup target address and stack ptr */ "addl %0,%/sp\n\t" "pflusha\n\t" "jmp %/a0@\n\t"/* jump into physical memory */ "0:.long 0\n\t"/* a constant zero. */ /* OK. Now reset everything and jump to reset vector. */ "1:\n\t" "lea %/pc@(0b),%/a0\n\t" "pmove %/a0@, %/tc\n\t"/* disable mmu */ "pmove %/a0@, %/tt0\n\t"/* disable tt0 */ "pmove %/a0@, %/tt1\n\t"/* disable tt1 */ "movel #0, %/a0\n\t" "movec %/a0, %/vbr\n\t"/* clear vector base register */ "movec %/a0, %/cacr\n\t"/* disable caches */ "movel #0x0808,%/a0\n\t" "movec %/a0, %/cacr\n\t"/* flush i&d caches */ "movew #0x2700,%/sr\n\t"/* set up status register */ "movel %1@(0x0),%/a0\n\t"/* load interrupt stack pointer */ "movec %/a0, %/isp\n\t" "movel %1@(0x4),%/a0\n\t"/* load reset vector */ "reset\n\t"/* reset external devices */ "jmp %/a0@\n\t"/* jump to the reset vector */ ".chip 68k"
: : "r" (offset), "a" (rombase) : "a0");
} else { /* need ROMBASE in booter */ /* indeed, plus need to MAP THE ROM !! */
if (mac_bi_data.rombase == 0)
mac_bi_data.rombase = 0x40800000;
/* works on some */
rom_reset = (void *)(mac_bi_data.rombase + 0xa);
local_irq_disable();
rom_reset();
}
/* should never get here */
pr_crit("Restart failed. Please restart manually.\n");
local_irq_disable(); while(1);
}
/* * This function translates seconds since 1970 into a proper date. * * Algorithm cribbed from glibc2.1, __offtime(). * * This is roughly same as rtc_time64_to_tm(), which we should probably * use here, but it's only available when CONFIG_RTC_LIB is enabled.
*/ #define SECS_PER_MINUTE (60) #define SECS_PER_HOUR (SECS_PER_MINUTE * 60) #define SECS_PER_DAY (SECS_PER_HOUR * 24)
staticvoid unmktime(time64_t time, long offset, int *yearp, int *monp, int *dayp, int *hourp, int *minp, int *secp)
{ /* How many days come before each month (0-12). */ staticconstunsignedshortint __mon_yday[2][13] =
{ /* Normal years. */
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, /* Leap years. */
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
}; int days, rem, y, wday; constunsignedshortint *ip;
days = div_u64_rem(time, SECS_PER_DAY, &rem);
rem += offset; while (rem < 0) {
rem += SECS_PER_DAY;
--days;
} while (rem >= SECS_PER_DAY) {
rem -= SECS_PER_DAY;
++days;
}
*hourp = rem / SECS_PER_HOUR;
rem %= SECS_PER_HOUR;
*minp = rem / SECS_PER_MINUTE;
*secp = rem % SECS_PER_MINUTE; /* January 1, 1970 was a Thursday. */
wday = (4 + days) % 7; /* Day in the week. Not currently used */ if (wday < 0) wday += 7;
y = 1970;
while (days < 0 || days >= (__isleap (y) ? 366 : 365))
{ /* Guess a corrected year, assuming 365 days per year. */ longint yg = y + days / 365 - (days % 365 < 0);
/* Adjust DAYS and Y to match the guessed year. */
days -= (yg - y) * 365 +
LEAPS_THRU_END_OF(yg - 1) - LEAPS_THRU_END_OF(y - 1);
y = yg;
}
*yearp = y - 1900;
ip = __mon_yday[__isleap(y)]; for (y = 11; days < (longint) ip[y]; --y) continue;
days -= ip[y];
*monp = y;
*dayp = days + 1; /* day in the month */ return;
}
/* * Read/write the hardware clock.
*/
int mac_hwclk(int op, struct rtc_time *t)
{
time64_t now;
if (!op) { /* read */ switch (macintosh_config->adb_type) { case MAC_ADB_IOP: case MAC_ADB_II: case MAC_ADB_PB1:
now = via_read_time(); break; #ifdef CONFIG_ADB_CUDA case MAC_ADB_EGRET: case MAC_ADB_CUDA:
now = cuda_get_time(); break; #endif #ifdef CONFIG_ADB_PMU case MAC_ADB_PB2:
now = pmu_get_time(); break; #endif default:
now = 0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.