forked from Minki/linux
b24413180f
Many source files in the tree are missing licensing information, which makes it harder for compliance tools to determine the correct license. By default all files without license information are under the default license of the kernel, which is GPL version 2. Update the files which contain no license information with the 'GPL-2.0' SPDX license identifier. The SPDX identifier is a legally binding shorthand, which can be used instead of the full boiler plate text. This patch is based on work done by Thomas Gleixner and Kate Stewart and Philippe Ombredanne. How this work was done: Patches were generated and checked against linux-4.14-rc6 for a subset of the use cases: - file had no licensing information it it. - file was a */uapi/* one with no licensing information in it, - file was a */uapi/* one with existing licensing information, Further patches will be generated in subsequent months to fix up cases where non-standard license headers were used, and references to license had to be inferred by heuristics based on keywords. The analysis to determine which SPDX License Identifier to be applied to a file was done in a spreadsheet of side by side results from of the output of two independent scanners (ScanCode & Windriver) producing SPDX tag:value files created by Philippe Ombredanne. Philippe prepared the base worksheet, and did an initial spot review of a few 1000 files. The 4.13 kernel was the starting point of the analysis with 60,537 files assessed. Kate Stewart did a file by file comparison of the scanner results in the spreadsheet to determine which SPDX license identifier(s) to be applied to the file. She confirmed any determination that was not immediately clear with lawyers working with the Linux Foundation. Criteria used to select files for SPDX license identifier tagging was: - Files considered eligible had to be source code files. - Make and config files were included as candidates if they contained >5 lines of source - File already had some variant of a license header in it (even if <5 lines). All documentation files were explicitly excluded. The following heuristics were used to determine which SPDX license identifiers to apply. - when both scanners couldn't find any license traces, file was considered to have no license information in it, and the top level COPYING file license applied. For non */uapi/* files that summary was: SPDX license identifier # files ---------------------------------------------------|------- GPL-2.0 11139 and resulted in the first patch in this series. If that file was a */uapi/* path one, it was "GPL-2.0 WITH Linux-syscall-note" otherwise it was "GPL-2.0". Results of that was: SPDX license identifier # files ---------------------------------------------------|------- GPL-2.0 WITH Linux-syscall-note 930 and resulted in the second patch in this series. - if a file had some form of licensing information in it, and was one of the */uapi/* ones, it was denoted with the Linux-syscall-note if any GPL family license was found in the file or had no licensing in it (per prior point). Results summary: SPDX license identifier # files ---------------------------------------------------|------ GPL-2.0 WITH Linux-syscall-note 270 GPL-2.0+ WITH Linux-syscall-note 169 ((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) 21 ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 17 LGPL-2.1+ WITH Linux-syscall-note 15 GPL-1.0+ WITH Linux-syscall-note 14 ((GPL-2.0+ WITH Linux-syscall-note) OR BSD-3-Clause) 5 LGPL-2.0+ WITH Linux-syscall-note 4 LGPL-2.1 WITH Linux-syscall-note 3 ((GPL-2.0 WITH Linux-syscall-note) OR MIT) 3 ((GPL-2.0 WITH Linux-syscall-note) AND MIT) 1 and that resulted in the third patch in this series. - when the two scanners agreed on the detected license(s), that became the concluded license(s). - when there was disagreement between the two scanners (one detected a license but the other didn't, or they both detected different licenses) a manual inspection of the file occurred. - In most cases a manual inspection of the information in the file resulted in a clear resolution of the license that should apply (and which scanner probably needed to revisit its heuristics). - When it was not immediately clear, the license identifier was confirmed with lawyers working with the Linux Foundation. - If there was any question as to the appropriate license identifier, the file was flagged for further research and to be revisited later in time. In total, over 70 hours of logged manual review was done on the spreadsheet to determine the SPDX license identifiers to apply to the source files by Kate, Philippe, Thomas and, in some cases, confirmation by lawyers working with the Linux Foundation. Kate also obtained a third independent scan of the 4.13 code base from FOSSology, and compared selected files where the other two scanners disagreed against that SPDX file, to see if there was new insights. The Windriver scanner is based on an older version of FOSSology in part, so they are related. Thomas did random spot checks in about 500 files from the spreadsheets for the uapi headers and agreed with SPDX license identifier in the files he inspected. For the non-uapi files Thomas did random spot checks in about 15000 files. In initial set of patches against 4.14-rc6, 3 files were found to have copy/paste license identifier errors, and have been fixed to reflect the correct identifier. Additionally Philippe spent 10 hours this week doing a detailed manual inspection and review of the 12,461 patched files from the initial patch version early this week with: - a full scancode scan run, collecting the matched texts, detected license ids and scores - reviewing anything where there was a license detected (about 500+ files) to ensure that the applied SPDX license was correct - reviewing anything where there was no detection but the patch license was not GPL-2.0 WITH Linux-syscall-note to ensure that the applied SPDX license was correct This produced a worksheet with 20 files needing minor correction. This worksheet was then exported into 3 different .csv files for the different types of files to be modified. These .csv files were then reviewed by Greg. Thomas wrote a script to parse the csv files and add the proper SPDX tag to the file, in the format that the file expected. This script was further refined by Greg based on the output to detect more types of files automatically and to distinguish between header and source .c files (which need different comment types.) Finally Greg ran the script using the .csv files to generate the patches. Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org> Reviewed-by: Philippe Ombredanne <pombredanne@nexb.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
720 lines
16 KiB
C
720 lines
16 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Miscellaneous Mac68K-specific stuff
|
|
*/
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/time.h>
|
|
#include <linux/rtc.h>
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/adb.h>
|
|
#include <linux/cuda.h>
|
|
#include <linux/pmu.h>
|
|
|
|
#include <linux/uaccess.h>
|
|
#include <asm/io.h>
|
|
#include <asm/segment.h>
|
|
#include <asm/setup.h>
|
|
#include <asm/macintosh.h>
|
|
#include <asm/mac_via.h>
|
|
#include <asm/mac_oss.h>
|
|
|
|
#include <asm/machdep.h>
|
|
|
|
/* Offset between Unix time (1970-based) and Mac time (1904-based) */
|
|
|
|
#define RTC_OFFSET 2082844800
|
|
|
|
static void (*rom_reset)(void);
|
|
|
|
#ifdef CONFIG_ADB_CUDA
|
|
static long cuda_read_time(void)
|
|
{
|
|
struct adb_request req;
|
|
long time;
|
|
|
|
if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
|
|
return 0;
|
|
while (!req.complete)
|
|
cuda_poll();
|
|
|
|
time = (req.reply[3] << 24) | (req.reply[4] << 16)
|
|
| (req.reply[5] << 8) | req.reply[6];
|
|
return time - RTC_OFFSET;
|
|
}
|
|
|
|
static void cuda_write_time(long data)
|
|
{
|
|
struct adb_request req;
|
|
data += RTC_OFFSET;
|
|
if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
|
|
(data >> 24) & 0xFF, (data >> 16) & 0xFF,
|
|
(data >> 8) & 0xFF, data & 0xFF) < 0)
|
|
return;
|
|
while (!req.complete)
|
|
cuda_poll();
|
|
}
|
|
|
|
static __u8 cuda_read_pram(int offset)
|
|
{
|
|
struct adb_request req;
|
|
if (cuda_request(&req, NULL, 4, CUDA_PACKET, CUDA_GET_PRAM,
|
|
(offset >> 8) & 0xFF, offset & 0xFF) < 0)
|
|
return 0;
|
|
while (!req.complete)
|
|
cuda_poll();
|
|
return req.reply[3];
|
|
}
|
|
|
|
static void cuda_write_pram(int offset, __u8 data)
|
|
{
|
|
struct adb_request req;
|
|
if (cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_SET_PRAM,
|
|
(offset >> 8) & 0xFF, offset & 0xFF, data) < 0)
|
|
return;
|
|
while (!req.complete)
|
|
cuda_poll();
|
|
}
|
|
#else
|
|
#define cuda_read_time() 0
|
|
#define cuda_write_time(n)
|
|
#define cuda_read_pram NULL
|
|
#define cuda_write_pram NULL
|
|
#endif
|
|
|
|
#ifdef CONFIG_ADB_PMU68K
|
|
static long pmu_read_time(void)
|
|
{
|
|
struct adb_request req;
|
|
long time;
|
|
|
|
if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
|
|
return 0;
|
|
while (!req.complete)
|
|
pmu_poll();
|
|
|
|
time = (req.reply[1] << 24) | (req.reply[2] << 16)
|
|
| (req.reply[3] << 8) | req.reply[4];
|
|
return time - RTC_OFFSET;
|
|
}
|
|
|
|
static void pmu_write_time(long data)
|
|
{
|
|
struct adb_request req;
|
|
data += RTC_OFFSET;
|
|
if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
|
|
(data >> 24) & 0xFF, (data >> 16) & 0xFF,
|
|
(data >> 8) & 0xFF, data & 0xFF) < 0)
|
|
return;
|
|
while (!req.complete)
|
|
pmu_poll();
|
|
}
|
|
|
|
static __u8 pmu_read_pram(int offset)
|
|
{
|
|
struct adb_request req;
|
|
if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM,
|
|
(offset >> 8) & 0xFF, offset & 0xFF) < 0)
|
|
return 0;
|
|
while (!req.complete)
|
|
pmu_poll();
|
|
return req.reply[3];
|
|
}
|
|
|
|
static void pmu_write_pram(int offset, __u8 data)
|
|
{
|
|
struct adb_request req;
|
|
if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM,
|
|
(offset >> 8) & 0xFF, offset & 0xFF, data) < 0)
|
|
return;
|
|
while (!req.complete)
|
|
pmu_poll();
|
|
}
|
|
#else
|
|
#define pmu_read_time() 0
|
|
#define pmu_write_time(n)
|
|
#define pmu_read_pram NULL
|
|
#define pmu_write_pram NULL
|
|
#endif
|
|
|
|
/*
|
|
* VIA PRAM/RTC access routines
|
|
*
|
|
* Must be called with interrupts disabled and
|
|
* the RTC should be enabled.
|
|
*/
|
|
|
|
static __u8 via_pram_readbyte(void)
|
|
{
|
|
int i,reg;
|
|
__u8 data;
|
|
|
|
reg = via1[vBufB] & ~VIA1B_vRTCClk;
|
|
|
|
/* Set the RTC data line to be an input. */
|
|
|
|
via1[vDirB] &= ~VIA1B_vRTCData;
|
|
|
|
/* The bits of the byte come out in MSB order */
|
|
|
|
data = 0;
|
|
for (i = 0 ; i < 8 ; i++) {
|
|
via1[vBufB] = reg;
|
|
via1[vBufB] = reg | VIA1B_vRTCClk;
|
|
data = (data << 1) | (via1[vBufB] & VIA1B_vRTCData);
|
|
}
|
|
|
|
/* Return RTC data line to output state */
|
|
|
|
via1[vDirB] |= VIA1B_vRTCData;
|
|
|
|
return data;
|
|
}
|
|
|
|
static void via_pram_writebyte(__u8 data)
|
|
{
|
|
int i,reg,bit;
|
|
|
|
reg = via1[vBufB] & ~(VIA1B_vRTCClk | VIA1B_vRTCData);
|
|
|
|
/* The bits of the byte go in in MSB order */
|
|
|
|
for (i = 0 ; i < 8 ; i++) {
|
|
bit = data & 0x80? 1 : 0;
|
|
data <<= 1;
|
|
via1[vBufB] = reg | bit;
|
|
via1[vBufB] = reg | bit | VIA1B_vRTCClk;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
static void via_pram_command(int command, __u8 *data)
|
|
{
|
|
unsigned long flags;
|
|
int is_read;
|
|
|
|
local_irq_save(flags);
|
|
|
|
/* Enable the RTC and make sure the strobe line is high */
|
|
|
|
via1[vBufB] = (via1[vBufB] | VIA1B_vRTCClk) & ~VIA1B_vRTCEnb;
|
|
|
|
if (command & 0xFF00) { /* extended (two-byte) command */
|
|
via_pram_writebyte((command & 0xFF00) >> 8);
|
|
via_pram_writebyte(command & 0xFF);
|
|
is_read = command & 0x8000;
|
|
} else { /* one-byte command */
|
|
via_pram_writebyte(command);
|
|
is_read = command & 0x80;
|
|
}
|
|
if (is_read) {
|
|
*data = via_pram_readbyte();
|
|
} else {
|
|
via_pram_writebyte(*data);
|
|
}
|
|
|
|
/* All done, disable the RTC */
|
|
|
|
via1[vBufB] |= VIA1B_vRTCEnb;
|
|
|
|
local_irq_restore(flags);
|
|
}
|
|
|
|
static __u8 via_read_pram(int offset)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static void via_write_pram(int offset, __u8 data)
|
|
{
|
|
}
|
|
|
|
/*
|
|
* 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 long via_read_time(void)
|
|
{
|
|
union {
|
|
__u8 cdata[4];
|
|
long idata;
|
|
} result, last_result;
|
|
int count = 1;
|
|
|
|
via_pram_command(0x81, &last_result.cdata[3]);
|
|
via_pram_command(0x85, &last_result.cdata[2]);
|
|
via_pram_command(0x89, &last_result.cdata[1]);
|
|
via_pram_command(0x8D, &last_result.cdata[0]);
|
|
|
|
/*
|
|
* The NetBSD guys say to loop until you get the same reading
|
|
* twice in a row.
|
|
*/
|
|
|
|
while (1) {
|
|
via_pram_command(0x81, &result.cdata[3]);
|
|
via_pram_command(0x85, &result.cdata[2]);
|
|
via_pram_command(0x89, &result.cdata[1]);
|
|
via_pram_command(0x8D, &result.cdata[0]);
|
|
|
|
if (result.idata == last_result.idata)
|
|
return result.idata - RTC_OFFSET;
|
|
|
|
if (++count > 10)
|
|
break;
|
|
|
|
last_result.idata = result.idata;
|
|
}
|
|
|
|
pr_err("via_read_time: failed to read a stable value; got 0x%08lx then 0x%08lx\n",
|
|
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.
|
|
*/
|
|
|
|
static void via_write_time(long time)
|
|
{
|
|
union {
|
|
__u8 cdata[4];
|
|
long idata;
|
|
} data;
|
|
__u8 temp;
|
|
|
|
/* Clear the write protect bit */
|
|
|
|
temp = 0x55;
|
|
via_pram_command(0x35, &temp);
|
|
|
|
data.idata = time + RTC_OFFSET;
|
|
via_pram_command(0x01, &data.cdata[3]);
|
|
via_pram_command(0x05, &data.cdata[2]);
|
|
via_pram_command(0x09, &data.cdata[1]);
|
|
via_pram_command(0x0D, &data.cdata[0]);
|
|
|
|
/* Set the write protect bit */
|
|
|
|
temp = 0xD5;
|
|
via_pram_command(0x35, &temp);
|
|
}
|
|
|
|
static void 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);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* FIXME: not sure how this is supposed to work exactly...
|
|
*/
|
|
|
|
static void oss_shutdown(void)
|
|
{
|
|
oss->rom_ctrl = OSS_POWEROFF;
|
|
}
|
|
|
|
#ifdef CONFIG_ADB_CUDA
|
|
|
|
static void cuda_restart(void)
|
|
{
|
|
struct adb_request req;
|
|
if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM) < 0)
|
|
return;
|
|
while (!req.complete)
|
|
cuda_poll();
|
|
}
|
|
|
|
static void cuda_shutdown(void)
|
|
{
|
|
struct adb_request req;
|
|
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 */
|
|
|
|
#ifdef CONFIG_ADB_PMU68K
|
|
|
|
void pmu_restart(void)
|
|
{
|
|
struct adb_request req;
|
|
if (pmu_request(&req, NULL,
|
|
2, PMU_SET_INTR_MASK, PMU_INT_ADB|PMU_INT_TICK) < 0)
|
|
return;
|
|
while (!req.complete)
|
|
pmu_poll();
|
|
if (pmu_request(&req, NULL, 1, PMU_RESET) < 0)
|
|
return;
|
|
while (!req.complete)
|
|
pmu_poll();
|
|
}
|
|
|
|
void pmu_shutdown(void)
|
|
{
|
|
struct adb_request req;
|
|
if (pmu_request(&req, NULL,
|
|
2, PMU_SET_INTR_MASK, PMU_INT_ADB|PMU_INT_TICK) < 0)
|
|
return;
|
|
while (!req.complete)
|
|
pmu_poll();
|
|
if (pmu_request(&req, NULL, 5, PMU_SHUTDOWN, 'M', 'A', 'T', 'T') < 0)
|
|
return;
|
|
while (!req.complete)
|
|
pmu_poll();
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
*-------------------------------------------------------------------
|
|
* Below this point are the generic routines; they'll dispatch to the
|
|
* correct routine for the hardware on which we're running.
|
|
*-------------------------------------------------------------------
|
|
*/
|
|
|
|
void mac_pram_read(int offset, __u8 *buffer, int len)
|
|
{
|
|
__u8 (*func)(int);
|
|
int i;
|
|
|
|
switch(macintosh_config->adb_type) {
|
|
case MAC_ADB_PB1:
|
|
case MAC_ADB_PB2:
|
|
func = pmu_read_pram; break;
|
|
case MAC_ADB_EGRET:
|
|
case MAC_ADB_CUDA:
|
|
func = cuda_read_pram; break;
|
|
default:
|
|
func = via_read_pram;
|
|
}
|
|
if (!func)
|
|
return;
|
|
for (i = 0 ; i < len ; i++) {
|
|
buffer[i] = (*func)(offset++);
|
|
}
|
|
}
|
|
|
|
void mac_pram_write(int offset, __u8 *buffer, int len)
|
|
{
|
|
void (*func)(int, __u8);
|
|
int i;
|
|
|
|
switch(macintosh_config->adb_type) {
|
|
case MAC_ADB_PB1:
|
|
case MAC_ADB_PB2:
|
|
func = pmu_write_pram; break;
|
|
case MAC_ADB_EGRET:
|
|
case MAC_ADB_CUDA:
|
|
func = cuda_write_pram; break;
|
|
default:
|
|
func = via_write_pram;
|
|
}
|
|
if (!func)
|
|
return;
|
|
for (i = 0 ; i < len ; i++) {
|
|
(*func)(offset++, buffer[i]);
|
|
}
|
|
}
|
|
|
|
void mac_poweroff(void)
|
|
{
|
|
if (oss_present) {
|
|
oss_shutdown();
|
|
} else if (macintosh_config->adb_type == MAC_ADB_II) {
|
|
via_shutdown();
|
|
#ifdef CONFIG_ADB_CUDA
|
|
} else if (macintosh_config->adb_type == MAC_ADB_EGRET ||
|
|
macintosh_config->adb_type == MAC_ADB_CUDA) {
|
|
cuda_shutdown();
|
|
#endif
|
|
#ifdef CONFIG_ADB_PMU68K
|
|
} else if (macintosh_config->adb_type == MAC_ADB_PB1
|
|
|| macintosh_config->adb_type == MAC_ADB_PB2) {
|
|
pmu_shutdown();
|
|
#endif
|
|
}
|
|
|
|
pr_crit("It is now safe to turn off your Macintosh.\n");
|
|
local_irq_disable();
|
|
while(1);
|
|
}
|
|
|
|
void mac_reset(void)
|
|
{
|
|
if (macintosh_config->adb_type == MAC_ADB_II) {
|
|
unsigned long flags;
|
|
|
|
/* 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);
|
|
|
|
if (macintosh_config->ident == MAC_MODEL_SE30) {
|
|
/*
|
|
* MSch: Machines known to crash on ROM reset ...
|
|
*/
|
|
} else {
|
|
local_irq_save(flags);
|
|
|
|
rom_reset();
|
|
|
|
local_irq_restore(flags);
|
|
}
|
|
#ifdef CONFIG_ADB_CUDA
|
|
} else if (macintosh_config->adb_type == MAC_ADB_EGRET ||
|
|
macintosh_config->adb_type == MAC_ADB_CUDA) {
|
|
cuda_restart();
|
|
#endif
|
|
#ifdef CONFIG_ADB_PMU68K
|
|
} else if (macintosh_config->adb_type == MAC_ADB_PB1
|
|
|| macintosh_config->adb_type == MAC_ADB_PB2) {
|
|
pmu_restart();
|
|
#endif
|
|
} else 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>
|
|
*/
|
|
|
|
unsigned long rombase = 0x40000000;
|
|
|
|
/* make a 1-to-1 mapping, using the transparent tran. reg. */
|
|
unsigned long virt = (unsigned long) mac_reset;
|
|
unsigned long phys = virt_to_phys(mac_reset);
|
|
unsigned long addr = (phys&0xFF000000)|0x8777;
|
|
unsigned long 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");
|
|
}
|
|
|
|
/* 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().
|
|
*/
|
|
#define SECS_PER_MINUTE (60)
|
|
#define SECS_PER_HOUR (SECS_PER_MINUTE * 60)
|
|
#define SECS_PER_DAY (SECS_PER_HOUR * 24)
|
|
|
|
static void unmktime(unsigned long time, long offset,
|
|
int *yearp, int *monp, int *dayp,
|
|
int *hourp, int *minp, int *secp)
|
|
{
|
|
/* How many days come before each month (0-12). */
|
|
static const unsigned short int __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 }
|
|
};
|
|
long int days, rem, y, wday, yday;
|
|
const unsigned short int *ip;
|
|
|
|
days = time / SECS_PER_DAY;
|
|
rem = time % SECS_PER_DAY;
|
|
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;
|
|
|
|
#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
|
|
#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
|
|
#define __isleap(year) \
|
|
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
|
|
|
|
while (days < 0 || days >= (__isleap (y) ? 366 : 365))
|
|
{
|
|
/* Guess a corrected year, assuming 365 days per year. */
|
|
long int 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;
|
|
yday = days; /* day in the year. Not currently used. */
|
|
ip = __mon_yday[__isleap(y)];
|
|
for (y = 11; days < (long int) 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)
|
|
{
|
|
unsigned long now;
|
|
|
|
if (!op) { /* read */
|
|
switch (macintosh_config->adb_type) {
|
|
case MAC_ADB_II:
|
|
case MAC_ADB_IOP:
|
|
now = via_read_time();
|
|
break;
|
|
case MAC_ADB_PB1:
|
|
case MAC_ADB_PB2:
|
|
now = pmu_read_time();
|
|
break;
|
|
case MAC_ADB_EGRET:
|
|
case MAC_ADB_CUDA:
|
|
now = cuda_read_time();
|
|
break;
|
|
default:
|
|
now = 0;
|
|
}
|
|
|
|
t->tm_wday = 0;
|
|
unmktime(now, 0,
|
|
&t->tm_year, &t->tm_mon, &t->tm_mday,
|
|
&t->tm_hour, &t->tm_min, &t->tm_sec);
|
|
pr_debug("%s: read %04d-%02d-%-2d %02d:%02d:%02d\n",
|
|
__func__, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
|
|
t->tm_hour, t->tm_min, t->tm_sec);
|
|
} else { /* write */
|
|
pr_debug("%s: tried to write %04d-%02d-%-2d %02d:%02d:%02d\n",
|
|
__func__, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
|
|
t->tm_hour, t->tm_min, t->tm_sec);
|
|
|
|
now = mktime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
|
|
t->tm_hour, t->tm_min, t->tm_sec);
|
|
|
|
switch (macintosh_config->adb_type) {
|
|
case MAC_ADB_II:
|
|
case MAC_ADB_IOP:
|
|
via_write_time(now);
|
|
break;
|
|
case MAC_ADB_EGRET:
|
|
case MAC_ADB_CUDA:
|
|
cuda_write_time(now);
|
|
break;
|
|
case MAC_ADB_PB1:
|
|
case MAC_ADB_PB2:
|
|
pmu_write_time(now);
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Set minutes/seconds in the hardware clock
|
|
*/
|
|
|
|
int mac_set_clock_mmss (unsigned long nowtime)
|
|
{
|
|
struct rtc_time now;
|
|
|
|
mac_hwclk(0, &now);
|
|
now.tm_sec = nowtime % 60;
|
|
now.tm_min = (nowtime / 60) % 60;
|
|
mac_hwclk(1, &now);
|
|
|
|
return 0;
|
|
}
|