forked from Minki/linux
Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
* 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus: CHAR: Delete old and now unused M48T35 RTC driver for SGI IP27. CHAR: Delete old and now unused DS1286 driver. MIPS: Sort out CPU type to name translation. MIPS: Use the new byteorder headers MIPS: Probe for watch registers on cores of all vendors, not just MTI. MIPS: Switch FPU emulator trap to BREAK instruction. MIPS: SMP: Do not initialize __cpu_number_map/__cpu_logical_map for CPU 0. MIPS: Consider value of c0_ebase when computing value of exception base. MIPS: Clean up MIPSxx-optimized bitop functions MIPS: New feature test macro cpu_has_mips_r MIPS: RBTX4927: Add GPIO-LED support MIPS: TXx9: Fix RBTX4939 ethernet address initialization
This commit is contained in:
commit
e61467e9b6
@ -327,7 +327,6 @@ config SGI_IP22
|
||||
select IP22_CPU_SCACHE
|
||||
select IRQ_CPU
|
||||
select GENERIC_ISA_DMA_SUPPORT_BROKEN
|
||||
select SGI_HAS_DS1286
|
||||
select SGI_HAS_I8042
|
||||
select SGI_HAS_INDYDOG
|
||||
select SGI_HAS_HAL2
|
||||
@ -382,7 +381,6 @@ config SGI_IP28
|
||||
select HW_HAS_EISA
|
||||
select I8253
|
||||
select I8259
|
||||
select SGI_HAS_DS1286
|
||||
select SGI_HAS_I8042
|
||||
select SGI_HAS_INDYDOG
|
||||
select SGI_HAS_HAL2
|
||||
@ -893,9 +891,6 @@ config EMMA2RH
|
||||
config SERIAL_RM9000
|
||||
bool
|
||||
|
||||
config SGI_HAS_DS1286
|
||||
bool
|
||||
|
||||
config SGI_HAS_INDYDOG
|
||||
bool
|
||||
|
||||
|
@ -771,7 +771,6 @@ CONFIG_WATCHDOG=y
|
||||
CONFIG_INDYDOG=m
|
||||
# CONFIG_HW_RANDOM is not set
|
||||
# CONFIG_RTC is not set
|
||||
CONFIG_SGI_DS1286=m
|
||||
# CONFIG_R3964 is not set
|
||||
CONFIG_RAW_DRIVER=m
|
||||
CONFIG_MAX_RAW_DEVS=256
|
||||
|
@ -701,7 +701,6 @@ CONFIG_LEGACY_PTY_COUNT=256
|
||||
# CONFIG_WATCHDOG is not set
|
||||
CONFIG_HW_RANDOM=m
|
||||
# CONFIG_RTC is not set
|
||||
CONFIG_SGI_IP27_RTC=y
|
||||
# CONFIG_R3964 is not set
|
||||
# CONFIG_APPLICOM is not set
|
||||
# CONFIG_DRM is not set
|
||||
|
@ -70,7 +70,6 @@ CONFIG_CPU_BIG_ENDIAN=y
|
||||
CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
|
||||
CONFIG_IRQ_CPU=y
|
||||
CONFIG_SWAP_IO_SPACE=y
|
||||
CONFIG_SGI_HAS_DS1286=y
|
||||
CONFIG_SGI_HAS_INDYDOG=y
|
||||
CONFIG_SGI_HAS_SEEQ=y
|
||||
CONFIG_SGI_HAS_WD93=y
|
||||
@ -585,7 +584,6 @@ CONFIG_LEGACY_PTY_COUNT=256
|
||||
# CONFIG_IPMI_HANDLER is not set
|
||||
# CONFIG_HW_RANDOM is not set
|
||||
# CONFIG_RTC is not set
|
||||
CONFIG_SGI_DS1286=y
|
||||
# CONFIG_DTLK is not set
|
||||
# CONFIG_R3964 is not set
|
||||
# CONFIG_RAW_DRIVER is not set
|
||||
|
@ -558,39 +558,67 @@ static inline void __clear_bit_unlock(unsigned long nr, volatile unsigned long *
|
||||
__clear_bit(nr, addr);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
|
||||
|
||||
/*
|
||||
* Return the bit position (0..63) of the most significant 1 bit in a word
|
||||
* Returns -1 if no 1 bit exists
|
||||
*/
|
||||
static inline unsigned long __fls(unsigned long x)
|
||||
static inline unsigned long __fls(unsigned long word)
|
||||
{
|
||||
int lz;
|
||||
int num;
|
||||
|
||||
if (sizeof(x) == 4) {
|
||||
if (BITS_PER_LONG == 32 &&
|
||||
__builtin_constant_p(cpu_has_mips_r) && cpu_has_mips_r) {
|
||||
__asm__(
|
||||
" .set push \n"
|
||||
" .set mips32 \n"
|
||||
" clz %0, %1 \n"
|
||||
" .set pop \n"
|
||||
: "=r" (lz)
|
||||
: "r" (x));
|
||||
: "=r" (num)
|
||||
: "r" (word));
|
||||
|
||||
return 31 - lz;
|
||||
return 31 - num;
|
||||
}
|
||||
|
||||
BUG_ON(sizeof(x) != 8);
|
||||
if (BITS_PER_LONG == 64 &&
|
||||
__builtin_constant_p(cpu_has_mips64) && cpu_has_mips64) {
|
||||
__asm__(
|
||||
" .set push \n"
|
||||
" .set mips64 \n"
|
||||
" dclz %0, %1 \n"
|
||||
" .set pop \n"
|
||||
: "=r" (num)
|
||||
: "r" (word));
|
||||
|
||||
__asm__(
|
||||
" .set push \n"
|
||||
" .set mips64 \n"
|
||||
" dclz %0, %1 \n"
|
||||
" .set pop \n"
|
||||
: "=r" (lz)
|
||||
: "r" (x));
|
||||
return 63 - num;
|
||||
}
|
||||
|
||||
return 63 - lz;
|
||||
num = BITS_PER_LONG - 1;
|
||||
|
||||
#if BITS_PER_LONG == 64
|
||||
if (!(word & (~0ul << 32))) {
|
||||
num -= 32;
|
||||
word <<= 32;
|
||||
}
|
||||
#endif
|
||||
if (!(word & (~0ul << (BITS_PER_LONG-16)))) {
|
||||
num -= 16;
|
||||
word <<= 16;
|
||||
}
|
||||
if (!(word & (~0ul << (BITS_PER_LONG-8)))) {
|
||||
num -= 8;
|
||||
word <<= 8;
|
||||
}
|
||||
if (!(word & (~0ul << (BITS_PER_LONG-4)))) {
|
||||
num -= 4;
|
||||
word <<= 4;
|
||||
}
|
||||
if (!(word & (~0ul << (BITS_PER_LONG-2)))) {
|
||||
num -= 2;
|
||||
word <<= 2;
|
||||
}
|
||||
if (!(word & (~0ul << (BITS_PER_LONG-1))))
|
||||
num -= 1;
|
||||
return num;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -612,23 +640,43 @@ static inline unsigned long __ffs(unsigned long word)
|
||||
* This is defined the same way as ffs.
|
||||
* Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
|
||||
*/
|
||||
static inline int fls(int word)
|
||||
static inline int fls(int x)
|
||||
{
|
||||
__asm__("clz %0, %1" : "=r" (word) : "r" (word));
|
||||
int r;
|
||||
|
||||
return 32 - word;
|
||||
if (__builtin_constant_p(cpu_has_mips_r) && cpu_has_mips_r) {
|
||||
__asm__("clz %0, %1" : "=r" (x) : "r" (x));
|
||||
|
||||
return 32 - x;
|
||||
}
|
||||
|
||||
r = 32;
|
||||
if (!x)
|
||||
return 0;
|
||||
if (!(x & 0xffff0000u)) {
|
||||
x <<= 16;
|
||||
r -= 16;
|
||||
}
|
||||
if (!(x & 0xff000000u)) {
|
||||
x <<= 8;
|
||||
r -= 8;
|
||||
}
|
||||
if (!(x & 0xf0000000u)) {
|
||||
x <<= 4;
|
||||
r -= 4;
|
||||
}
|
||||
if (!(x & 0xc0000000u)) {
|
||||
x <<= 2;
|
||||
r -= 2;
|
||||
}
|
||||
if (!(x & 0x80000000u)) {
|
||||
x <<= 1;
|
||||
r -= 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_64BIT) && defined(CONFIG_CPU_MIPS64)
|
||||
static inline int fls64(__u64 word)
|
||||
{
|
||||
__asm__("dclz %0, %1" : "=r" (word) : "r" (word));
|
||||
|
||||
return 64 - word;
|
||||
}
|
||||
#else
|
||||
#include <asm-generic/bitops/fls64.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ffs - find first bit set.
|
||||
@ -646,16 +694,6 @@ static inline int ffs(int word)
|
||||
return fls(word & -word);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <asm-generic/bitops/__ffs.h>
|
||||
#include <asm-generic/bitops/__fls.h>
|
||||
#include <asm-generic/bitops/ffs.h>
|
||||
#include <asm-generic/bitops/fls.h>
|
||||
#include <asm-generic/bitops/fls64.h>
|
||||
|
||||
#endif /*defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64) */
|
||||
|
||||
#include <asm-generic/bitops/ffz.h>
|
||||
#include <asm-generic/bitops/find.h>
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#define _BRK_THREADBP 11 /* For threads, user bp (used by debuggers) */
|
||||
#define BRK_BUG 512 /* Used by BUG() */
|
||||
#define BRK_KDB 513 /* Used in KDB_ENTER() */
|
||||
#define BRK_MEMU 514 /* Used by FPU emulator */
|
||||
#define BRK_MULOVF 1023 /* Multiply overflow */
|
||||
|
||||
#endif /* __ASM_BREAK_H */
|
||||
|
@ -11,11 +11,19 @@
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#if defined(__MIPSEB__)
|
||||
# define __BIG_ENDIAN
|
||||
#elif defined(__MIPSEL__)
|
||||
# define __LITTLE_ENDIAN
|
||||
#else
|
||||
# error "MIPS, but neither __MIPSEB__, nor __MIPSEL__???"
|
||||
#endif
|
||||
|
||||
#define __SWAB_64_THRU_32__
|
||||
|
||||
#ifdef CONFIG_CPU_MIPSR2
|
||||
|
||||
static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 x)
|
||||
static inline __attribute_const__ __u16 __arch_swab16(__u16 x)
|
||||
{
|
||||
__asm__(
|
||||
" wsbh %0, %1 \n"
|
||||
@ -24,9 +32,9 @@ static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 x)
|
||||
|
||||
return x;
|
||||
}
|
||||
#define __arch__swab16(x) ___arch__swab16(x)
|
||||
#define __arch_swab16 __arch_swab16
|
||||
|
||||
static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x)
|
||||
static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
|
||||
{
|
||||
__asm__(
|
||||
" wsbh %0, %1 \n"
|
||||
@ -36,11 +44,10 @@ static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x)
|
||||
|
||||
return x;
|
||||
}
|
||||
#define __arch__swab32(x) ___arch__swab32(x)
|
||||
#define __arch_swab32 __arch_swab32
|
||||
|
||||
#ifdef CONFIG_CPU_MIPS64_R2
|
||||
|
||||
static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 x)
|
||||
static inline __attribute_const__ __u64 __arch_swab64(__u64 x)
|
||||
{
|
||||
__asm__(
|
||||
" dsbh %0, %1 \n"
|
||||
@ -51,26 +58,11 @@ static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 x)
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
#define __arch__swab64(x) ___arch__swab64(x)
|
||||
|
||||
#define __arch_swab64 __arch_swab64
|
||||
#endif /* CONFIG_CPU_MIPS64_R2 */
|
||||
|
||||
#endif /* CONFIG_CPU_MIPSR2 */
|
||||
|
||||
#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
|
||||
# define __BYTEORDER_HAS_U64__
|
||||
# define __SWAB_64_THRU_32__
|
||||
#endif
|
||||
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
#if defined(__MIPSEB__)
|
||||
# include <linux/byteorder/big_endian.h>
|
||||
#elif defined(__MIPSEL__)
|
||||
# include <linux/byteorder/little_endian.h>
|
||||
#else
|
||||
# error "MIPS, but neither __MIPSEB__, nor __MIPSEL__???"
|
||||
#endif
|
||||
#include <linux/byteorder.h>
|
||||
|
||||
#endif /* _ASM_BYTEORDER_H */
|
||||
|
@ -141,6 +141,8 @@
|
||||
#define cpu_has_mips64 (cpu_has_mips64r1 | cpu_has_mips64r2)
|
||||
#define cpu_has_mips_r1 (cpu_has_mips32r1 | cpu_has_mips64r1)
|
||||
#define cpu_has_mips_r2 (cpu_has_mips32r2 | cpu_has_mips64r2)
|
||||
#define cpu_has_mips_r (cpu_has_mips32r1 | cpu_has_mips32r2 | \
|
||||
cpu_has_mips64r1 | cpu_has_mips64r2)
|
||||
|
||||
#ifndef cpu_has_dsp
|
||||
#define cpu_has_dsp (cpu_data[0].ases & MIPS_ASE_DSP)
|
||||
|
@ -1,15 +0,0 @@
|
||||
/*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Machine dependent access functions for RTC registers.
|
||||
*
|
||||
* Copyright (C) 2003 Ralf Baechle (ralf@linux-mips.org)
|
||||
*/
|
||||
#ifndef _ASM_DS1286_H
|
||||
#define _ASM_DS1286_H
|
||||
|
||||
#include <ds1286.h>
|
||||
|
||||
#endif /* _ASM_DS1286_H */
|
@ -23,6 +23,9 @@
|
||||
#ifndef _ASM_FPU_EMULATOR_H
|
||||
#define _ASM_FPU_EMULATOR_H
|
||||
|
||||
#include <asm/break.h>
|
||||
#include <asm/inst.h>
|
||||
|
||||
struct mips_fpu_emulator_stats {
|
||||
unsigned int emulated;
|
||||
unsigned int loads;
|
||||
@ -34,4 +37,18 @@ struct mips_fpu_emulator_stats {
|
||||
|
||||
extern struct mips_fpu_emulator_stats fpuemustats;
|
||||
|
||||
extern int mips_dsemul(struct pt_regs *regs, mips_instruction ir,
|
||||
unsigned long cpc);
|
||||
extern int do_dsemulret(struct pt_regs *xcp);
|
||||
|
||||
/*
|
||||
* Instruction inserted following the badinst to further tag the sequence
|
||||
*/
|
||||
#define BD_COOKIE 0x0000bd36 /* tne $0, $0 with baggage */
|
||||
|
||||
/*
|
||||
* Break instruction with special math emu break code set
|
||||
*/
|
||||
#define BREAK_MATH (0x0000000d | (BRK_MEMU << 16))
|
||||
|
||||
#endif /* _ASM_FPU_EMULATOR_H */
|
||||
|
@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Registers for the SGS-Thomson M48T35 Timekeeper RAM chip
|
||||
*/
|
||||
#ifndef _ASM_M48T35_H
|
||||
#define _ASM_M48T35_H
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
extern spinlock_t rtc_lock;
|
||||
|
||||
struct m48t35_rtc {
|
||||
volatile u8 pad[0x7ff8]; /* starts at 0x7ff8 */
|
||||
volatile u8 control;
|
||||
volatile u8 sec;
|
||||
volatile u8 min;
|
||||
volatile u8 hour;
|
||||
volatile u8 day;
|
||||
volatile u8 date;
|
||||
volatile u8 month;
|
||||
volatile u8 year;
|
||||
};
|
||||
|
||||
#define M48T35_RTC_SET 0x80
|
||||
#define M48T35_RTC_STOPPED 0x80
|
||||
#define M48T35_RTC_READ 0x40
|
||||
|
||||
#endif /* _ASM_M48T35_H */
|
@ -286,11 +286,12 @@ static inline int __cpu_has_fpu(void)
|
||||
#define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE \
|
||||
| MIPS_CPU_COUNTER)
|
||||
|
||||
static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
|
||||
{
|
||||
switch (c->processor_id & 0xff00) {
|
||||
case PRID_IMP_R2000:
|
||||
c->cputype = CPU_R2000;
|
||||
__cpu_name[cpu] = "R2000";
|
||||
c->isa_level = MIPS_CPU_ISA_I;
|
||||
c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE |
|
||||
MIPS_CPU_NOFPUEX;
|
||||
@ -299,13 +300,19 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
c->tlbsize = 64;
|
||||
break;
|
||||
case PRID_IMP_R3000:
|
||||
if ((c->processor_id & 0xff) == PRID_REV_R3000A)
|
||||
if (cpu_has_confreg())
|
||||
if ((c->processor_id & 0xff) == PRID_REV_R3000A) {
|
||||
if (cpu_has_confreg()) {
|
||||
c->cputype = CPU_R3081E;
|
||||
else
|
||||
__cpu_name[cpu] = "R3081";
|
||||
} else {
|
||||
c->cputype = CPU_R3000A;
|
||||
else
|
||||
__cpu_name[cpu] = "R3000A";
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
c->cputype = CPU_R3000;
|
||||
__cpu_name[cpu] = "R3000";
|
||||
}
|
||||
c->isa_level = MIPS_CPU_ISA_I;
|
||||
c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE |
|
||||
MIPS_CPU_NOFPUEX;
|
||||
@ -315,15 +322,21 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
break;
|
||||
case PRID_IMP_R4000:
|
||||
if (read_c0_config() & CONF_SC) {
|
||||
if ((c->processor_id & 0xff) >= PRID_REV_R4400)
|
||||
if ((c->processor_id & 0xff) >= PRID_REV_R4400) {
|
||||
c->cputype = CPU_R4400PC;
|
||||
else
|
||||
__cpu_name[cpu] = "R4400PC";
|
||||
} else {
|
||||
c->cputype = CPU_R4000PC;
|
||||
__cpu_name[cpu] = "R4000PC";
|
||||
}
|
||||
} else {
|
||||
if ((c->processor_id & 0xff) >= PRID_REV_R4400)
|
||||
if ((c->processor_id & 0xff) >= PRID_REV_R4400) {
|
||||
c->cputype = CPU_R4400SC;
|
||||
else
|
||||
__cpu_name[cpu] = "R4400SC";
|
||||
} else {
|
||||
c->cputype = CPU_R4000SC;
|
||||
__cpu_name[cpu] = "R4000SC";
|
||||
}
|
||||
}
|
||||
|
||||
c->isa_level = MIPS_CPU_ISA_III;
|
||||
@ -336,25 +349,34 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
switch (c->processor_id & 0xf0) {
|
||||
case PRID_REV_VR4111:
|
||||
c->cputype = CPU_VR4111;
|
||||
__cpu_name[cpu] = "NEC VR4111";
|
||||
break;
|
||||
case PRID_REV_VR4121:
|
||||
c->cputype = CPU_VR4121;
|
||||
__cpu_name[cpu] = "NEC VR4121";
|
||||
break;
|
||||
case PRID_REV_VR4122:
|
||||
if ((c->processor_id & 0xf) < 0x3)
|
||||
if ((c->processor_id & 0xf) < 0x3) {
|
||||
c->cputype = CPU_VR4122;
|
||||
else
|
||||
__cpu_name[cpu] = "NEC VR4122";
|
||||
} else {
|
||||
c->cputype = CPU_VR4181A;
|
||||
__cpu_name[cpu] = "NEC VR4181A";
|
||||
}
|
||||
break;
|
||||
case PRID_REV_VR4130:
|
||||
if ((c->processor_id & 0xf) < 0x4)
|
||||
if ((c->processor_id & 0xf) < 0x4) {
|
||||
c->cputype = CPU_VR4131;
|
||||
else
|
||||
__cpu_name[cpu] = "NEC VR4131";
|
||||
} else {
|
||||
c->cputype = CPU_VR4133;
|
||||
__cpu_name[cpu] = "NEC VR4133";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n");
|
||||
c->cputype = CPU_VR41XX;
|
||||
__cpu_name[cpu] = "NEC Vr41xx";
|
||||
break;
|
||||
}
|
||||
c->isa_level = MIPS_CPU_ISA_III;
|
||||
@ -363,6 +385,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
break;
|
||||
case PRID_IMP_R4300:
|
||||
c->cputype = CPU_R4300;
|
||||
__cpu_name[cpu] = "R4300";
|
||||
c->isa_level = MIPS_CPU_ISA_III;
|
||||
c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
|
||||
MIPS_CPU_LLSC;
|
||||
@ -370,6 +393,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
break;
|
||||
case PRID_IMP_R4600:
|
||||
c->cputype = CPU_R4600;
|
||||
__cpu_name[cpu] = "R4600";
|
||||
c->isa_level = MIPS_CPU_ISA_III;
|
||||
c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
|
||||
MIPS_CPU_LLSC;
|
||||
@ -384,6 +408,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
* it's c0_prid id number with the TX3900.
|
||||
*/
|
||||
c->cputype = CPU_R4650;
|
||||
__cpu_name[cpu] = "R4650";
|
||||
c->isa_level = MIPS_CPU_ISA_III;
|
||||
c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_LLSC;
|
||||
c->tlbsize = 48;
|
||||
@ -395,25 +420,26 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
|
||||
if ((c->processor_id & 0xf0) == (PRID_REV_TX3927 & 0xf0)) {
|
||||
c->cputype = CPU_TX3927;
|
||||
__cpu_name[cpu] = "TX3927";
|
||||
c->tlbsize = 64;
|
||||
} else {
|
||||
switch (c->processor_id & 0xff) {
|
||||
case PRID_REV_TX3912:
|
||||
c->cputype = CPU_TX3912;
|
||||
__cpu_name[cpu] = "TX3912";
|
||||
c->tlbsize = 32;
|
||||
break;
|
||||
case PRID_REV_TX3922:
|
||||
c->cputype = CPU_TX3922;
|
||||
__cpu_name[cpu] = "TX3922";
|
||||
c->tlbsize = 64;
|
||||
break;
|
||||
default:
|
||||
c->cputype = CPU_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PRID_IMP_R4700:
|
||||
c->cputype = CPU_R4700;
|
||||
__cpu_name[cpu] = "R4700";
|
||||
c->isa_level = MIPS_CPU_ISA_III;
|
||||
c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
|
||||
MIPS_CPU_LLSC;
|
||||
@ -421,6 +447,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
break;
|
||||
case PRID_IMP_TX49:
|
||||
c->cputype = CPU_TX49XX;
|
||||
__cpu_name[cpu] = "R49XX";
|
||||
c->isa_level = MIPS_CPU_ISA_III;
|
||||
c->options = R4K_OPTS | MIPS_CPU_LLSC;
|
||||
if (!(c->processor_id & 0x08))
|
||||
@ -429,6 +456,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
break;
|
||||
case PRID_IMP_R5000:
|
||||
c->cputype = CPU_R5000;
|
||||
__cpu_name[cpu] = "R5000";
|
||||
c->isa_level = MIPS_CPU_ISA_IV;
|
||||
c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
|
||||
MIPS_CPU_LLSC;
|
||||
@ -436,6 +464,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
break;
|
||||
case PRID_IMP_R5432:
|
||||
c->cputype = CPU_R5432;
|
||||
__cpu_name[cpu] = "R5432";
|
||||
c->isa_level = MIPS_CPU_ISA_IV;
|
||||
c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
|
||||
MIPS_CPU_WATCH | MIPS_CPU_LLSC;
|
||||
@ -443,6 +472,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
break;
|
||||
case PRID_IMP_R5500:
|
||||
c->cputype = CPU_R5500;
|
||||
__cpu_name[cpu] = "R5500";
|
||||
c->isa_level = MIPS_CPU_ISA_IV;
|
||||
c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
|
||||
MIPS_CPU_WATCH | MIPS_CPU_LLSC;
|
||||
@ -450,6 +480,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
break;
|
||||
case PRID_IMP_NEVADA:
|
||||
c->cputype = CPU_NEVADA;
|
||||
__cpu_name[cpu] = "Nevada";
|
||||
c->isa_level = MIPS_CPU_ISA_IV;
|
||||
c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
|
||||
MIPS_CPU_DIVEC | MIPS_CPU_LLSC;
|
||||
@ -457,6 +488,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
break;
|
||||
case PRID_IMP_R6000:
|
||||
c->cputype = CPU_R6000;
|
||||
__cpu_name[cpu] = "R6000";
|
||||
c->isa_level = MIPS_CPU_ISA_II;
|
||||
c->options = MIPS_CPU_TLB | MIPS_CPU_FPU |
|
||||
MIPS_CPU_LLSC;
|
||||
@ -464,6 +496,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
break;
|
||||
case PRID_IMP_R6000A:
|
||||
c->cputype = CPU_R6000A;
|
||||
__cpu_name[cpu] = "R6000A";
|
||||
c->isa_level = MIPS_CPU_ISA_II;
|
||||
c->options = MIPS_CPU_TLB | MIPS_CPU_FPU |
|
||||
MIPS_CPU_LLSC;
|
||||
@ -471,6 +504,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
break;
|
||||
case PRID_IMP_RM7000:
|
||||
c->cputype = CPU_RM7000;
|
||||
__cpu_name[cpu] = "RM7000";
|
||||
c->isa_level = MIPS_CPU_ISA_IV;
|
||||
c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
|
||||
MIPS_CPU_LLSC;
|
||||
@ -486,6 +520,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
break;
|
||||
case PRID_IMP_RM9000:
|
||||
c->cputype = CPU_RM9000;
|
||||
__cpu_name[cpu] = "RM9000";
|
||||
c->isa_level = MIPS_CPU_ISA_IV;
|
||||
c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
|
||||
MIPS_CPU_LLSC;
|
||||
@ -500,6 +535,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
break;
|
||||
case PRID_IMP_R8000:
|
||||
c->cputype = CPU_R8000;
|
||||
__cpu_name[cpu] = "RM8000";
|
||||
c->isa_level = MIPS_CPU_ISA_IV;
|
||||
c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
|
||||
MIPS_CPU_FPU | MIPS_CPU_32FPR |
|
||||
@ -508,6 +544,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
break;
|
||||
case PRID_IMP_R10000:
|
||||
c->cputype = CPU_R10000;
|
||||
__cpu_name[cpu] = "R10000";
|
||||
c->isa_level = MIPS_CPU_ISA_IV;
|
||||
c->options = MIPS_CPU_TLB | MIPS_CPU_4K_CACHE | MIPS_CPU_4KEX |
|
||||
MIPS_CPU_FPU | MIPS_CPU_32FPR |
|
||||
@ -517,6 +554,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
break;
|
||||
case PRID_IMP_R12000:
|
||||
c->cputype = CPU_R12000;
|
||||
__cpu_name[cpu] = "R12000";
|
||||
c->isa_level = MIPS_CPU_ISA_IV;
|
||||
c->options = MIPS_CPU_TLB | MIPS_CPU_4K_CACHE | MIPS_CPU_4KEX |
|
||||
MIPS_CPU_FPU | MIPS_CPU_32FPR |
|
||||
@ -526,6 +564,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
break;
|
||||
case PRID_IMP_R14000:
|
||||
c->cputype = CPU_R14000;
|
||||
__cpu_name[cpu] = "R14000";
|
||||
c->isa_level = MIPS_CPU_ISA_IV;
|
||||
c->options = MIPS_CPU_TLB | MIPS_CPU_4K_CACHE | MIPS_CPU_4KEX |
|
||||
MIPS_CPU_FPU | MIPS_CPU_32FPR |
|
||||
@ -535,6 +574,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
|
||||
break;
|
||||
case PRID_IMP_LOONGSON2:
|
||||
c->cputype = CPU_LOONGSON2;
|
||||
__cpu_name[cpu] = "ICT Loongson-2";
|
||||
c->isa_level = MIPS_CPU_ISA_III;
|
||||
c->options = R4K_OPTS |
|
||||
MIPS_CPU_FPU | MIPS_CPU_LLSC |
|
||||
@ -652,21 +692,24 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c)
|
||||
|
||||
static void __cpuinit decode_configs(struct cpuinfo_mips *c)
|
||||
{
|
||||
int ok;
|
||||
|
||||
/* MIPS32 or MIPS64 compliant CPU. */
|
||||
c->options = MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER |
|
||||
MIPS_CPU_DIVEC | MIPS_CPU_LLSC | MIPS_CPU_MCHECK;
|
||||
|
||||
c->scache.flags = MIPS_CACHE_NOT_PRESENT;
|
||||
|
||||
/* Read Config registers. */
|
||||
if (!decode_config0(c))
|
||||
return; /* actually worth a panic() */
|
||||
if (!decode_config1(c))
|
||||
return;
|
||||
if (!decode_config2(c))
|
||||
return;
|
||||
if (!decode_config3(c))
|
||||
return;
|
||||
ok = decode_config0(c); /* Read Config registers. */
|
||||
BUG_ON(!ok); /* Arch spec violation! */
|
||||
if (ok)
|
||||
ok = decode_config1(c);
|
||||
if (ok)
|
||||
ok = decode_config2(c);
|
||||
if (ok)
|
||||
ok = decode_config3(c);
|
||||
|
||||
mips_probe_watch_registers(c);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_MIPSR2
|
||||
@ -675,52 +718,62 @@ extern void spram_config(void);
|
||||
static inline void spram_config(void) {}
|
||||
#endif
|
||||
|
||||
static inline void cpu_probe_mips(struct cpuinfo_mips *c)
|
||||
static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
|
||||
{
|
||||
decode_configs(c);
|
||||
mips_probe_watch_registers(c);
|
||||
switch (c->processor_id & 0xff00) {
|
||||
case PRID_IMP_4KC:
|
||||
c->cputype = CPU_4KC;
|
||||
__cpu_name[cpu] = "MIPS 4Kc";
|
||||
break;
|
||||
case PRID_IMP_4KEC:
|
||||
c->cputype = CPU_4KEC;
|
||||
__cpu_name[cpu] = "MIPS 4KEc";
|
||||
break;
|
||||
case PRID_IMP_4KECR2:
|
||||
c->cputype = CPU_4KEC;
|
||||
__cpu_name[cpu] = "MIPS 4KEc";
|
||||
break;
|
||||
case PRID_IMP_4KSC:
|
||||
case PRID_IMP_4KSD:
|
||||
c->cputype = CPU_4KSC;
|
||||
__cpu_name[cpu] = "MIPS 4KSc";
|
||||
break;
|
||||
case PRID_IMP_5KC:
|
||||
c->cputype = CPU_5KC;
|
||||
__cpu_name[cpu] = "MIPS 5Kc";
|
||||
break;
|
||||
case PRID_IMP_20KC:
|
||||
c->cputype = CPU_20KC;
|
||||
__cpu_name[cpu] = "MIPS 20Kc";
|
||||
break;
|
||||
case PRID_IMP_24K:
|
||||
case PRID_IMP_24KE:
|
||||
c->cputype = CPU_24K;
|
||||
__cpu_name[cpu] = "MIPS 24Kc";
|
||||
break;
|
||||
case PRID_IMP_25KF:
|
||||
c->cputype = CPU_25KF;
|
||||
__cpu_name[cpu] = "MIPS 25Kc";
|
||||
break;
|
||||
case PRID_IMP_34K:
|
||||
c->cputype = CPU_34K;
|
||||
__cpu_name[cpu] = "MIPS 34Kc";
|
||||
break;
|
||||
case PRID_IMP_74K:
|
||||
c->cputype = CPU_74K;
|
||||
__cpu_name[cpu] = "MIPS 74Kc";
|
||||
break;
|
||||
case PRID_IMP_1004K:
|
||||
c->cputype = CPU_1004K;
|
||||
__cpu_name[cpu] = "MIPS 1004Kc";
|
||||
break;
|
||||
}
|
||||
|
||||
spram_config();
|
||||
}
|
||||
|
||||
static inline void cpu_probe_alchemy(struct cpuinfo_mips *c)
|
||||
static inline void cpu_probe_alchemy(struct cpuinfo_mips *c, unsigned int cpu)
|
||||
{
|
||||
decode_configs(c);
|
||||
switch (c->processor_id & 0xff00) {
|
||||
@ -729,23 +782,31 @@ static inline void cpu_probe_alchemy(struct cpuinfo_mips *c)
|
||||
switch ((c->processor_id >> 24) & 0xff) {
|
||||
case 0:
|
||||
c->cputype = CPU_AU1000;
|
||||
__cpu_name[cpu] = "Au1000";
|
||||
break;
|
||||
case 1:
|
||||
c->cputype = CPU_AU1500;
|
||||
__cpu_name[cpu] = "Au1500";
|
||||
break;
|
||||
case 2:
|
||||
c->cputype = CPU_AU1100;
|
||||
__cpu_name[cpu] = "Au1100";
|
||||
break;
|
||||
case 3:
|
||||
c->cputype = CPU_AU1550;
|
||||
__cpu_name[cpu] = "Au1550";
|
||||
break;
|
||||
case 4:
|
||||
c->cputype = CPU_AU1200;
|
||||
if (2 == (c->processor_id & 0xff))
|
||||
__cpu_name[cpu] = "Au1200";
|
||||
if ((c->processor_id & 0xff) == 2) {
|
||||
c->cputype = CPU_AU1250;
|
||||
__cpu_name[cpu] = "Au1250";
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
c->cputype = CPU_AU1210;
|
||||
__cpu_name[cpu] = "Au1210";
|
||||
break;
|
||||
default:
|
||||
panic("Unknown Au Core!");
|
||||
@ -755,154 +816,67 @@ static inline void cpu_probe_alchemy(struct cpuinfo_mips *c)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void cpu_probe_sibyte(struct cpuinfo_mips *c)
|
||||
static inline void cpu_probe_sibyte(struct cpuinfo_mips *c, unsigned int cpu)
|
||||
{
|
||||
decode_configs(c);
|
||||
|
||||
switch (c->processor_id & 0xff00) {
|
||||
case PRID_IMP_SB1:
|
||||
c->cputype = CPU_SB1;
|
||||
__cpu_name[cpu] = "SiByte SB1";
|
||||
/* FPU in pass1 is known to have issues. */
|
||||
if ((c->processor_id & 0xff) < 0x02)
|
||||
c->options &= ~(MIPS_CPU_FPU | MIPS_CPU_32FPR);
|
||||
break;
|
||||
case PRID_IMP_SB1A:
|
||||
c->cputype = CPU_SB1A;
|
||||
__cpu_name[cpu] = "SiByte SB1A";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void cpu_probe_sandcraft(struct cpuinfo_mips *c)
|
||||
static inline void cpu_probe_sandcraft(struct cpuinfo_mips *c, unsigned int cpu)
|
||||
{
|
||||
decode_configs(c);
|
||||
switch (c->processor_id & 0xff00) {
|
||||
case PRID_IMP_SR71000:
|
||||
c->cputype = CPU_SR71000;
|
||||
__cpu_name[cpu] = "Sandcraft SR71000";
|
||||
c->scache.ways = 8;
|
||||
c->tlbsize = 64;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void cpu_probe_nxp(struct cpuinfo_mips *c)
|
||||
static inline void cpu_probe_nxp(struct cpuinfo_mips *c, unsigned int cpu)
|
||||
{
|
||||
decode_configs(c);
|
||||
switch (c->processor_id & 0xff00) {
|
||||
case PRID_IMP_PR4450:
|
||||
c->cputype = CPU_PR4450;
|
||||
__cpu_name[cpu] = "Philips PR4450";
|
||||
c->isa_level = MIPS_CPU_ISA_M32R1;
|
||||
break;
|
||||
default:
|
||||
panic("Unknown NXP Core!"); /* REVISIT: die? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline void cpu_probe_broadcom(struct cpuinfo_mips *c)
|
||||
static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
|
||||
{
|
||||
decode_configs(c);
|
||||
switch (c->processor_id & 0xff00) {
|
||||
case PRID_IMP_BCM3302:
|
||||
c->cputype = CPU_BCM3302;
|
||||
__cpu_name[cpu] = "Broadcom BCM3302";
|
||||
break;
|
||||
case PRID_IMP_BCM4710:
|
||||
c->cputype = CPU_BCM4710;
|
||||
break;
|
||||
default:
|
||||
c->cputype = CPU_UNKNOWN;
|
||||
__cpu_name[cpu] = "Broadcom BCM4710";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char *__cpu_name[NR_CPUS];
|
||||
|
||||
/*
|
||||
* Name a CPU
|
||||
*/
|
||||
static __cpuinit const char *cpu_to_name(struct cpuinfo_mips *c)
|
||||
{
|
||||
const char *name = NULL;
|
||||
|
||||
switch (c->cputype) {
|
||||
case CPU_UNKNOWN: name = "unknown"; break;
|
||||
case CPU_R2000: name = "R2000"; break;
|
||||
case CPU_R3000: name = "R3000"; break;
|
||||
case CPU_R3000A: name = "R3000A"; break;
|
||||
case CPU_R3041: name = "R3041"; break;
|
||||
case CPU_R3051: name = "R3051"; break;
|
||||
case CPU_R3052: name = "R3052"; break;
|
||||
case CPU_R3081: name = "R3081"; break;
|
||||
case CPU_R3081E: name = "R3081E"; break;
|
||||
case CPU_R4000PC: name = "R4000PC"; break;
|
||||
case CPU_R4000SC: name = "R4000SC"; break;
|
||||
case CPU_R4000MC: name = "R4000MC"; break;
|
||||
case CPU_R4200: name = "R4200"; break;
|
||||
case CPU_R4400PC: name = "R4400PC"; break;
|
||||
case CPU_R4400SC: name = "R4400SC"; break;
|
||||
case CPU_R4400MC: name = "R4400MC"; break;
|
||||
case CPU_R4600: name = "R4600"; break;
|
||||
case CPU_R6000: name = "R6000"; break;
|
||||
case CPU_R6000A: name = "R6000A"; break;
|
||||
case CPU_R8000: name = "R8000"; break;
|
||||
case CPU_R10000: name = "R10000"; break;
|
||||
case CPU_R12000: name = "R12000"; break;
|
||||
case CPU_R14000: name = "R14000"; break;
|
||||
case CPU_R4300: name = "R4300"; break;
|
||||
case CPU_R4650: name = "R4650"; break;
|
||||
case CPU_R4700: name = "R4700"; break;
|
||||
case CPU_R5000: name = "R5000"; break;
|
||||
case CPU_R5000A: name = "R5000A"; break;
|
||||
case CPU_R4640: name = "R4640"; break;
|
||||
case CPU_NEVADA: name = "Nevada"; break;
|
||||
case CPU_RM7000: name = "RM7000"; break;
|
||||
case CPU_RM9000: name = "RM9000"; break;
|
||||
case CPU_R5432: name = "R5432"; break;
|
||||
case CPU_4KC: name = "MIPS 4Kc"; break;
|
||||
case CPU_5KC: name = "MIPS 5Kc"; break;
|
||||
case CPU_R4310: name = "R4310"; break;
|
||||
case CPU_SB1: name = "SiByte SB1"; break;
|
||||
case CPU_SB1A: name = "SiByte SB1A"; break;
|
||||
case CPU_TX3912: name = "TX3912"; break;
|
||||
case CPU_TX3922: name = "TX3922"; break;
|
||||
case CPU_TX3927: name = "TX3927"; break;
|
||||
case CPU_AU1000: name = "Au1000"; break;
|
||||
case CPU_AU1500: name = "Au1500"; break;
|
||||
case CPU_AU1100: name = "Au1100"; break;
|
||||
case CPU_AU1550: name = "Au1550"; break;
|
||||
case CPU_AU1200: name = "Au1200"; break;
|
||||
case CPU_AU1210: name = "Au1210"; break;
|
||||
case CPU_AU1250: name = "Au1250"; break;
|
||||
case CPU_4KEC: name = "MIPS 4KEc"; break;
|
||||
case CPU_4KSC: name = "MIPS 4KSc"; break;
|
||||
case CPU_VR41XX: name = "NEC Vr41xx"; break;
|
||||
case CPU_R5500: name = "R5500"; break;
|
||||
case CPU_TX49XX: name = "TX49xx"; break;
|
||||
case CPU_20KC: name = "MIPS 20Kc"; break;
|
||||
case CPU_24K: name = "MIPS 24K"; break;
|
||||
case CPU_25KF: name = "MIPS 25Kf"; break;
|
||||
case CPU_34K: name = "MIPS 34K"; break;
|
||||
case CPU_1004K: name = "MIPS 1004K"; break;
|
||||
case CPU_74K: name = "MIPS 74K"; break;
|
||||
case CPU_VR4111: name = "NEC VR4111"; break;
|
||||
case CPU_VR4121: name = "NEC VR4121"; break;
|
||||
case CPU_VR4122: name = "NEC VR4122"; break;
|
||||
case CPU_VR4131: name = "NEC VR4131"; break;
|
||||
case CPU_VR4133: name = "NEC VR4133"; break;
|
||||
case CPU_VR4181: name = "NEC VR4181"; break;
|
||||
case CPU_VR4181A: name = "NEC VR4181A"; break;
|
||||
case CPU_SR71000: name = "Sandcraft SR71000"; break;
|
||||
case CPU_BCM3302: name = "Broadcom BCM3302"; break;
|
||||
case CPU_BCM4710: name = "Broadcom BCM4710"; break;
|
||||
case CPU_PR4450: name = "Philips PR4450"; break;
|
||||
case CPU_LOONGSON2: name = "ICT Loongson-2"; break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
__cpuinit void cpu_probe(void)
|
||||
{
|
||||
struct cpuinfo_mips *c = ¤t_cpu_data;
|
||||
@ -915,30 +889,31 @@ __cpuinit void cpu_probe(void)
|
||||
c->processor_id = read_c0_prid();
|
||||
switch (c->processor_id & 0xff0000) {
|
||||
case PRID_COMP_LEGACY:
|
||||
cpu_probe_legacy(c);
|
||||
cpu_probe_legacy(c, cpu);
|
||||
break;
|
||||
case PRID_COMP_MIPS:
|
||||
cpu_probe_mips(c);
|
||||
cpu_probe_mips(c, cpu);
|
||||
break;
|
||||
case PRID_COMP_ALCHEMY:
|
||||
cpu_probe_alchemy(c);
|
||||
cpu_probe_alchemy(c, cpu);
|
||||
break;
|
||||
case PRID_COMP_SIBYTE:
|
||||
cpu_probe_sibyte(c);
|
||||
cpu_probe_sibyte(c, cpu);
|
||||
break;
|
||||
case PRID_COMP_BROADCOM:
|
||||
cpu_probe_broadcom(c);
|
||||
cpu_probe_broadcom(c, cpu);
|
||||
break;
|
||||
case PRID_COMP_SANDCRAFT:
|
||||
cpu_probe_sandcraft(c);
|
||||
cpu_probe_sandcraft(c, cpu);
|
||||
break;
|
||||
case PRID_COMP_NXP:
|
||||
cpu_probe_nxp(c);
|
||||
cpu_probe_nxp(c, cpu);
|
||||
break;
|
||||
default:
|
||||
c->cputype = CPU_UNKNOWN;
|
||||
}
|
||||
|
||||
BUG_ON(!__cpu_name[cpu]);
|
||||
BUG_ON(c->cputype == CPU_UNKNOWN);
|
||||
|
||||
/*
|
||||
* Platform code can force the cpu type to optimize code
|
||||
* generation. In that case be sure the cpu type is correctly
|
||||
@ -958,8 +933,6 @@ __cpuinit void cpu_probe(void)
|
||||
}
|
||||
}
|
||||
|
||||
__cpu_name[cpu] = cpu_to_name(c);
|
||||
|
||||
if (cpu_has_mips_r2)
|
||||
c->srsets = ((read_c0_srsctl() >> 26) & 0x0f) + 1;
|
||||
else
|
||||
|
@ -195,12 +195,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
|
||||
/* preload SMP state for boot cpu */
|
||||
void __devinit smp_prepare_boot_cpu(void)
|
||||
{
|
||||
/*
|
||||
* This assumes that bootup is always handled by the processor
|
||||
* with the logic and physical number 0.
|
||||
*/
|
||||
__cpu_number_map[0] = 0;
|
||||
__cpu_logical_map[0] = 0;
|
||||
cpu_set(0, phys_cpu_present_map);
|
||||
cpu_set(0, cpu_online_map);
|
||||
cpu_set(0, cpu_callin_map);
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/dsp.h>
|
||||
#include <asm/fpu.h>
|
||||
#include <asm/fpu_emulator.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/mipsmtregs.h>
|
||||
#include <asm/module.h>
|
||||
@ -722,6 +723,21 @@ static void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
|
||||
die_if_kernel("Kernel bug detected", regs);
|
||||
force_sig(SIGTRAP, current);
|
||||
break;
|
||||
case BRK_MEMU:
|
||||
/*
|
||||
* Address errors may be deliberately induced by the FPU
|
||||
* emulator to retake control of the CPU after executing the
|
||||
* instruction in the delay slot of an emulated branch.
|
||||
*
|
||||
* Terminate if exception was recognized as a delay slot return
|
||||
* otherwise handle as normal.
|
||||
*/
|
||||
if (do_dsemulret(regs))
|
||||
return;
|
||||
|
||||
die_if_kernel("Math emu break/trap", regs);
|
||||
force_sig(SIGTRAP, current);
|
||||
break;
|
||||
default:
|
||||
scnprintf(b, sizeof(b), "%s instruction in kernel code", str);
|
||||
die_if_kernel(b, regs);
|
||||
@ -1555,6 +1571,8 @@ void __cpuinit set_uncached_handler(unsigned long offset, void *addr,
|
||||
#ifdef CONFIG_64BIT
|
||||
unsigned long uncached_ebase = TO_UNCAC(ebase);
|
||||
#endif
|
||||
if (cpu_has_mips_r2)
|
||||
ebase += (read_c0_ebase() & 0x3ffff000);
|
||||
|
||||
if (!addr)
|
||||
panic(panic_null_cerr);
|
||||
@ -1588,8 +1606,11 @@ void __init trap_init(void)
|
||||
|
||||
if (cpu_has_veic || cpu_has_vint)
|
||||
ebase = (unsigned long) alloc_bootmem_low_pages(0x200 + VECTORSPACING*64);
|
||||
else
|
||||
else {
|
||||
ebase = CAC_BASE;
|
||||
if (cpu_has_mips_r2)
|
||||
ebase += (read_c0_ebase() & 0x3ffff000);
|
||||
}
|
||||
|
||||
per_cpu_trap_init();
|
||||
|
||||
@ -1697,11 +1718,11 @@ void __init trap_init(void)
|
||||
|
||||
if (cpu_has_vce)
|
||||
/* Special exception: R4[04]00 uses also the divec space. */
|
||||
memcpy((void *)(CAC_BASE + 0x180), &except_vec3_r4000, 0x100);
|
||||
memcpy((void *)(ebase + 0x180), &except_vec3_r4000, 0x100);
|
||||
else if (cpu_has_4kex)
|
||||
memcpy((void *)(CAC_BASE + 0x180), &except_vec3_generic, 0x80);
|
||||
memcpy((void *)(ebase + 0x180), &except_vec3_generic, 0x80);
|
||||
else
|
||||
memcpy((void *)(CAC_BASE + 0x080), &except_vec3_generic, 0x80);
|
||||
memcpy((void *)(ebase + 0x080), &except_vec3_generic, 0x80);
|
||||
|
||||
signal_init();
|
||||
#ifdef CONFIG_MIPS32_COMPAT
|
||||
|
@ -499,21 +499,9 @@ sigill:
|
||||
|
||||
asmlinkage void do_ade(struct pt_regs *regs)
|
||||
{
|
||||
extern int do_dsemulret(struct pt_regs *);
|
||||
unsigned int __user *pc;
|
||||
mm_segment_t seg;
|
||||
|
||||
/*
|
||||
* Address errors may be deliberately induced by the FPU emulator to
|
||||
* retake control of the CPU after executing the instruction in the
|
||||
* delay slot of an emulated branch.
|
||||
*/
|
||||
/* Terminate if exception was recognized as a delay slot return */
|
||||
if (do_dsemulret(regs))
|
||||
return;
|
||||
|
||||
/* Otherwise handle as normal */
|
||||
|
||||
/*
|
||||
* Did we catch a fault trying to load an instruction?
|
||||
* Or are we running in MIPS16 mode?
|
||||
|
@ -48,7 +48,6 @@
|
||||
#include <asm/branch.h>
|
||||
|
||||
#include "ieee754.h"
|
||||
#include "dsemul.h"
|
||||
|
||||
/* Strap kernel emulator for full MIPS IV emulation */
|
||||
|
||||
@ -346,9 +345,6 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx)
|
||||
/* cop control register rd -> gpr[rt] */
|
||||
u32 value;
|
||||
|
||||
if (ir == CP1UNDEF) {
|
||||
return do_dsemulret(xcp);
|
||||
}
|
||||
if (MIPSInst_RD(ir) == FPCREG_CSR) {
|
||||
value = ctx->fcr31;
|
||||
value = (value & ~0x3) | mips_rm[value & 0x3];
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include <asm/fpu_emulator.h>
|
||||
|
||||
#include "ieee754.h"
|
||||
#include "dsemul.h"
|
||||
|
||||
/* Strap kernel emulator for full MIPS IV emulation */
|
||||
|
||||
@ -94,7 +93,7 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc)
|
||||
return SIGBUS;
|
||||
|
||||
err = __put_user(ir, &fr->emul);
|
||||
err |= __put_user((mips_instruction)BADINST, &fr->badinst);
|
||||
err |= __put_user((mips_instruction)BREAK_MATH, &fr->badinst);
|
||||
err |= __put_user((mips_instruction)BD_COOKIE, &fr->cookie);
|
||||
err |= __put_user(cpc, &fr->epc);
|
||||
|
||||
@ -130,13 +129,13 @@ int do_dsemulret(struct pt_regs *xcp)
|
||||
/*
|
||||
* Do some sanity checking on the stackframe:
|
||||
*
|
||||
* - Is the instruction pointed to by the EPC an BADINST?
|
||||
* - Is the instruction pointed to by the EPC an BREAK_MATH?
|
||||
* - Is the following memory word the BD_COOKIE?
|
||||
*/
|
||||
err = __get_user(insn, &fr->badinst);
|
||||
err |= __get_user(cookie, &fr->cookie);
|
||||
|
||||
if (unlikely(err || (insn != BADINST) || (cookie != BD_COOKIE))) {
|
||||
if (unlikely(err || (insn != BREAK_MATH) || (cookie != BD_COOKIE))) {
|
||||
fpuemustats.errors++;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
extern int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc);
|
||||
extern int do_dsemulret(struct pt_regs *xcp);
|
||||
|
||||
/* Instruction which will always cause an address error */
|
||||
#define AdELOAD 0x8c000001 /* lw $0,1($0) */
|
||||
/* Instruction which will plainly cause a CP1 exception when FPU is disabled */
|
||||
#define CP1UNDEF 0x44400001 /* cfc1 $0,$0 undef */
|
||||
|
||||
/* Instruction inserted following the badinst to further tag the sequence */
|
||||
#define BD_COOKIE 0x0000bd36 /* tne $0,$0 with baggage */
|
||||
|
||||
/* Setup which instruction to use for trampoline */
|
||||
#ifdef STANDALONE_EMULATOR
|
||||
#define BADINST CP1UNDEF
|
||||
#else
|
||||
#define BADINST AdELOAD
|
||||
#endif
|
@ -49,6 +49,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/leds.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/reboot.h>
|
||||
#include <asm/txx9/generic.h>
|
||||
@ -210,10 +211,6 @@ static void __init rbtx4927_mem_setup(void)
|
||||
/* TX4927-SIO DTR on (PIO[15]) */
|
||||
gpio_request(15, "sio-dtr");
|
||||
gpio_direction_output(15, 1);
|
||||
gpio_request(0, "led");
|
||||
gpio_direction_output(0, 1);
|
||||
gpio_request(1, "led");
|
||||
gpio_direction_output(1, 1);
|
||||
|
||||
tx4927_sio_init(0, 0);
|
||||
#ifdef CONFIG_SERIAL_TXX9_CONSOLE
|
||||
@ -315,6 +312,25 @@ static void __init rbtx4927_mtd_init(void)
|
||||
tx4927_mtd_init(i);
|
||||
}
|
||||
|
||||
static void __init rbtx4927_gpioled_init(void)
|
||||
{
|
||||
static struct gpio_led leds[] = {
|
||||
{ .name = "gpioled:green:0", .gpio = 0, .active_low = 1, },
|
||||
{ .name = "gpioled:green:1", .gpio = 1, .active_low = 1, },
|
||||
};
|
||||
static struct gpio_led_platform_data pdata = {
|
||||
.num_leds = ARRAY_SIZE(leds),
|
||||
.leds = leds,
|
||||
};
|
||||
struct platform_device *pdev = platform_device_alloc("leds-gpio", 0);
|
||||
|
||||
if (!pdev)
|
||||
return;
|
||||
pdev->dev.platform_data = &pdata;
|
||||
if (platform_device_add(pdev))
|
||||
platform_device_put(pdev);
|
||||
}
|
||||
|
||||
static void __init rbtx4927_device_init(void)
|
||||
{
|
||||
toshiba_rbtx4927_rtc_init();
|
||||
@ -322,6 +338,7 @@ static void __init rbtx4927_device_init(void)
|
||||
tx4927_wdt_init();
|
||||
rbtx4927_mtd_init();
|
||||
txx9_iocled_init(RBTX4927_LED_ADDR - IO_BASE, -1, 3, 1, "green", NULL);
|
||||
rbtx4927_gpioled_init();
|
||||
}
|
||||
|
||||
struct txx9_board_vec rbtx4927_vec __initdata = {
|
||||
|
@ -308,16 +308,22 @@ static void __init rbtx4939_device_init(void)
|
||||
#if defined(CONFIG_TC35815) || defined(CONFIG_TC35815_MODULE)
|
||||
int i, j;
|
||||
unsigned char ethaddr[2][6];
|
||||
u8 bdipsw = readb(rbtx4939_bdipsw_addr) & 0x0f;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
unsigned long area = CKSEG1 + 0x1fff0000 + (i * 0x10);
|
||||
if (readb(rbtx4939_bdipsw_addr) & 8) {
|
||||
if (bdipsw == 0)
|
||||
memcpy(ethaddr[i], (void *)area, 6);
|
||||
else {
|
||||
u16 buf[3];
|
||||
area -= 0x03000000;
|
||||
if (bdipsw & 8)
|
||||
area -= 0x03000000;
|
||||
else
|
||||
area -= 0x01000000;
|
||||
for (j = 0; j < 3; j++)
|
||||
buf[j] = le16_to_cpup((u16 *)(area + j * 2));
|
||||
memcpy(ethaddr[i], buf, 6);
|
||||
} else
|
||||
memcpy(ethaddr[i], (void *)area, 6);
|
||||
}
|
||||
}
|
||||
tx4939_ethaddr_init(ethaddr[0], ethaddr[1]);
|
||||
#endif
|
||||
|
@ -812,28 +812,6 @@ config JS_RTC
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called js-rtc.
|
||||
|
||||
config SGI_DS1286
|
||||
tristate "SGI DS1286 RTC support"
|
||||
depends on SGI_HAS_DS1286
|
||||
help
|
||||
If you say Y here and create a character special file /dev/rtc with
|
||||
major number 10 and minor number 135 using mknod ("man mknod"), you
|
||||
will get access to the real time clock built into your computer.
|
||||
Every SGI has such a clock built in. It reports status information
|
||||
via the file /proc/rtc and its behaviour is set by various ioctls on
|
||||
/dev/rtc.
|
||||
|
||||
config SGI_IP27_RTC
|
||||
bool "SGI M48T35 RTC support"
|
||||
depends on SGI_IP27
|
||||
help
|
||||
If you say Y here and create a character special file /dev/rtc with
|
||||
major number 10 and minor number 135 using mknod ("man mknod"), you
|
||||
will get access to the real time clock built into your computer.
|
||||
Every SGI has such a clock built in. It reports status information
|
||||
via the file /proc/rtc and its behaviour is set by various ioctls on
|
||||
/dev/rtc.
|
||||
|
||||
config GEN_RTC
|
||||
tristate "Generic /dev/rtc emulation"
|
||||
depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH && !AVR32
|
||||
|
@ -74,8 +74,6 @@ obj-$(CONFIG_RTC) += rtc.o
|
||||
obj-$(CONFIG_HPET) += hpet.o
|
||||
obj-$(CONFIG_GEN_RTC) += genrtc.o
|
||||
obj-$(CONFIG_EFI_RTC) += efirtc.o
|
||||
obj-$(CONFIG_SGI_DS1286) += ds1286.o
|
||||
obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
|
||||
obj-$(CONFIG_DS1302) += ds1302.o
|
||||
obj-$(CONFIG_XILINX_HWICAP) += xilinx_hwicap/
|
||||
ifeq ($(CONFIG_GENERIC_NVRAM),y)
|
||||
|
@ -1,585 +0,0 @@
|
||||
/*
|
||||
* DS1286 Real Time Clock interface for Linux
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000 Ralf Baechle
|
||||
*
|
||||
* Based on code written by Paul Gortmaker.
|
||||
*
|
||||
* This driver allows use of the real time clock (built into nearly all
|
||||
* computers) from user space. It exports the /dev/rtc interface supporting
|
||||
* various ioctl() and also the /proc/rtc pseudo-file for status
|
||||
* information.
|
||||
*
|
||||
* The ioctls can be used to set the interrupt behaviour and generation rate
|
||||
* from the RTC via IRQ 8. Then the /dev/rtc interface can be used to make
|
||||
* use of these timer interrupts, be they interval or alarm based.
|
||||
*
|
||||
* The /dev/rtc interface will block on reads until an interrupt has been
|
||||
* received. If a RTC interrupt has already happened, it will output an
|
||||
* unsigned long and then block. The output value contains the interrupt
|
||||
* status in the low byte and the number of interrupts since the last read
|
||||
* in the remaining high bytes. The /dev/rtc interface can also be used with
|
||||
* the select(2) call.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
#include <linux/ds1286.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#define DS1286_VERSION "1.0"
|
||||
|
||||
/*
|
||||
* We sponge a minor off of the misc major. No need slurping
|
||||
* up another valuable major dev number for this. If you add
|
||||
* an ioctl, make sure you don't conflict with SPARC's RTC
|
||||
* ioctls.
|
||||
*/
|
||||
|
||||
static DECLARE_WAIT_QUEUE_HEAD(ds1286_wait);
|
||||
|
||||
static ssize_t ds1286_read(struct file *file, char *buf,
|
||||
size_t count, loff_t *ppos);
|
||||
|
||||
static int ds1286_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
|
||||
static unsigned int ds1286_poll(struct file *file, poll_table *wait);
|
||||
|
||||
static void ds1286_get_alm_time (struct rtc_time *alm_tm);
|
||||
static void ds1286_get_time(struct rtc_time *rtc_tm);
|
||||
static int ds1286_set_time(struct rtc_time *rtc_tm);
|
||||
|
||||
static inline unsigned char ds1286_is_updating(void);
|
||||
|
||||
static DEFINE_SPINLOCK(ds1286_lock);
|
||||
|
||||
static int ds1286_read_proc(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data);
|
||||
|
||||
/*
|
||||
* Bits in rtc_status. (7 bits of room for future expansion)
|
||||
*/
|
||||
|
||||
#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */
|
||||
#define RTC_TIMER_ON 0x02 /* missed irq timer active */
|
||||
|
||||
static unsigned char ds1286_status; /* bitmapped status byte. */
|
||||
|
||||
static unsigned char days_in_mo[] = {
|
||||
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||||
};
|
||||
|
||||
/*
|
||||
* Now all the various file operations that we export.
|
||||
*/
|
||||
|
||||
static ssize_t ds1286_read(struct file *file, char *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int ds1286_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct rtc_time wtime;
|
||||
|
||||
switch (cmd) {
|
||||
case RTC_AIE_OFF: /* Mask alarm int. enab. bit */
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned char val;
|
||||
|
||||
if (!capable(CAP_SYS_TIME))
|
||||
return -EACCES;
|
||||
|
||||
spin_lock_irqsave(&ds1286_lock, flags);
|
||||
val = rtc_read(RTC_CMD);
|
||||
val |= RTC_TDM;
|
||||
rtc_write(val, RTC_CMD);
|
||||
spin_unlock_irqrestore(&ds1286_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
case RTC_AIE_ON: /* Allow alarm interrupts. */
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned char val;
|
||||
|
||||
if (!capable(CAP_SYS_TIME))
|
||||
return -EACCES;
|
||||
|
||||
spin_lock_irqsave(&ds1286_lock, flags);
|
||||
val = rtc_read(RTC_CMD);
|
||||
val &= ~RTC_TDM;
|
||||
rtc_write(val, RTC_CMD);
|
||||
spin_unlock_irqrestore(&ds1286_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
case RTC_WIE_OFF: /* Mask watchdog int. enab. bit */
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned char val;
|
||||
|
||||
if (!capable(CAP_SYS_TIME))
|
||||
return -EACCES;
|
||||
|
||||
spin_lock_irqsave(&ds1286_lock, flags);
|
||||
val = rtc_read(RTC_CMD);
|
||||
val |= RTC_WAM;
|
||||
rtc_write(val, RTC_CMD);
|
||||
spin_unlock_irqrestore(&ds1286_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
case RTC_WIE_ON: /* Allow watchdog interrupts. */
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned char val;
|
||||
|
||||
if (!capable(CAP_SYS_TIME))
|
||||
return -EACCES;
|
||||
|
||||
spin_lock_irqsave(&ds1286_lock, flags);
|
||||
val = rtc_read(RTC_CMD);
|
||||
val &= ~RTC_WAM;
|
||||
rtc_write(val, RTC_CMD);
|
||||
spin_unlock_irqrestore(&ds1286_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
case RTC_ALM_READ: /* Read the present alarm time */
|
||||
{
|
||||
/*
|
||||
* This returns a struct rtc_time. Reading >= 0xc0
|
||||
* means "don't care" or "match all". Only the tm_hour,
|
||||
* tm_min, and tm_sec values are filled in.
|
||||
*/
|
||||
|
||||
memset(&wtime, 0, sizeof(wtime));
|
||||
ds1286_get_alm_time(&wtime);
|
||||
break;
|
||||
}
|
||||
case RTC_ALM_SET: /* Store a time into the alarm */
|
||||
{
|
||||
/*
|
||||
* This expects a struct rtc_time. Writing 0xff means
|
||||
* "don't care" or "match all". Only the tm_hour,
|
||||
* tm_min and tm_sec are used.
|
||||
*/
|
||||
unsigned char hrs, min, sec;
|
||||
struct rtc_time alm_tm;
|
||||
|
||||
if (!capable(CAP_SYS_TIME))
|
||||
return -EACCES;
|
||||
|
||||
if (copy_from_user(&alm_tm, (struct rtc_time*)arg,
|
||||
sizeof(struct rtc_time)))
|
||||
return -EFAULT;
|
||||
|
||||
hrs = alm_tm.tm_hour;
|
||||
min = alm_tm.tm_min;
|
||||
sec = alm_tm.tm_sec;
|
||||
|
||||
if (hrs >= 24)
|
||||
hrs = 0xff;
|
||||
|
||||
if (min >= 60)
|
||||
min = 0xff;
|
||||
|
||||
if (sec != 0)
|
||||
return -EINVAL;
|
||||
|
||||
min = bin2bcd(min);
|
||||
min = bin2bcd(hrs);
|
||||
|
||||
spin_lock(&ds1286_lock);
|
||||
rtc_write(hrs, RTC_HOURS_ALARM);
|
||||
rtc_write(min, RTC_MINUTES_ALARM);
|
||||
spin_unlock(&ds1286_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
case RTC_RD_TIME: /* Read the time/date from RTC */
|
||||
{
|
||||
memset(&wtime, 0, sizeof(wtime));
|
||||
ds1286_get_time(&wtime);
|
||||
break;
|
||||
}
|
||||
case RTC_SET_TIME: /* Set the RTC */
|
||||
{
|
||||
struct rtc_time rtc_tm;
|
||||
|
||||
if (!capable(CAP_SYS_TIME))
|
||||
return -EACCES;
|
||||
|
||||
if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
|
||||
sizeof(struct rtc_time)))
|
||||
return -EFAULT;
|
||||
|
||||
return ds1286_set_time(&rtc_tm);
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We enforce only one user at a time here with the open/close.
|
||||
* Also clear the previous interrupt data on an open, and clean
|
||||
* up things on a close.
|
||||
*/
|
||||
|
||||
static int ds1286_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
lock_kernel();
|
||||
spin_lock_irq(&ds1286_lock);
|
||||
|
||||
if (ds1286_status & RTC_IS_OPEN)
|
||||
goto out_busy;
|
||||
|
||||
ds1286_status |= RTC_IS_OPEN;
|
||||
|
||||
spin_unlock_irq(&ds1286_lock);
|
||||
unlock_kernel();
|
||||
return 0;
|
||||
|
||||
out_busy:
|
||||
spin_lock_irq(&ds1286_lock);
|
||||
unlock_kernel();
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int ds1286_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
ds1286_status &= ~RTC_IS_OPEN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int ds1286_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
poll_wait(file, &ds1286_wait, wait);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The various file operations we support.
|
||||
*/
|
||||
|
||||
static const struct file_operations ds1286_fops = {
|
||||
.llseek = no_llseek,
|
||||
.read = ds1286_read,
|
||||
.poll = ds1286_poll,
|
||||
.ioctl = ds1286_ioctl,
|
||||
.open = ds1286_open,
|
||||
.release = ds1286_release,
|
||||
};
|
||||
|
||||
static struct miscdevice ds1286_dev=
|
||||
{
|
||||
.minor = RTC_MINOR,
|
||||
.name = "rtc",
|
||||
.fops = &ds1286_fops,
|
||||
};
|
||||
|
||||
static int __init ds1286_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk(KERN_INFO "DS1286 Real Time Clock Driver v%s\n", DS1286_VERSION);
|
||||
|
||||
err = misc_register(&ds1286_dev);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (!create_proc_read_entry("driver/rtc", 0, 0, ds1286_read_proc, NULL)) {
|
||||
err = -ENOMEM;
|
||||
|
||||
goto out_deregister;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_deregister:
|
||||
misc_deregister(&ds1286_dev);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit ds1286_exit(void)
|
||||
{
|
||||
remove_proc_entry("driver/rtc", NULL);
|
||||
misc_deregister(&ds1286_dev);
|
||||
}
|
||||
|
||||
static char *days[] = {
|
||||
"***", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
|
||||
};
|
||||
|
||||
/*
|
||||
* Info exported via "/proc/rtc".
|
||||
*/
|
||||
static int ds1286_proc_output(char *buf)
|
||||
{
|
||||
char *p, *s;
|
||||
struct rtc_time tm;
|
||||
unsigned char hundredth, month, cmd, amode;
|
||||
|
||||
p = buf;
|
||||
|
||||
ds1286_get_time(&tm);
|
||||
hundredth = rtc_read(RTC_HUNDREDTH_SECOND);
|
||||
hundredth = bcd2bin(hundredth);
|
||||
|
||||
p += sprintf(p,
|
||||
"rtc_time\t: %02d:%02d:%02d.%02d\n"
|
||||
"rtc_date\t: %04d-%02d-%02d\n",
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec, hundredth,
|
||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
|
||||
|
||||
/*
|
||||
* We implicitly assume 24hr mode here. Alarm values >= 0xc0 will
|
||||
* match any value for that particular field. Values that are
|
||||
* greater than a valid time, but less than 0xc0 shouldn't appear.
|
||||
*/
|
||||
ds1286_get_alm_time(&tm);
|
||||
p += sprintf(p, "alarm\t\t: %s ", days[tm.tm_wday]);
|
||||
if (tm.tm_hour <= 24)
|
||||
p += sprintf(p, "%02d:", tm.tm_hour);
|
||||
else
|
||||
p += sprintf(p, "**:");
|
||||
|
||||
if (tm.tm_min <= 59)
|
||||
p += sprintf(p, "%02d\n", tm.tm_min);
|
||||
else
|
||||
p += sprintf(p, "**\n");
|
||||
|
||||
month = rtc_read(RTC_MONTH);
|
||||
p += sprintf(p,
|
||||
"oscillator\t: %s\n"
|
||||
"square_wave\t: %s\n",
|
||||
(month & RTC_EOSC) ? "disabled" : "enabled",
|
||||
(month & RTC_ESQW) ? "disabled" : "enabled");
|
||||
|
||||
amode = ((rtc_read(RTC_MINUTES_ALARM) & 0x80) >> 5) |
|
||||
((rtc_read(RTC_HOURS_ALARM) & 0x80) >> 6) |
|
||||
((rtc_read(RTC_DAY_ALARM) & 0x80) >> 7);
|
||||
if (amode == 7) s = "each minute";
|
||||
else if (amode == 3) s = "minutes match";
|
||||
else if (amode == 1) s = "hours and minutes match";
|
||||
else if (amode == 0) s = "days, hours and minutes match";
|
||||
else s = "invalid";
|
||||
p += sprintf(p, "alarm_mode\t: %s\n", s);
|
||||
|
||||
cmd = rtc_read(RTC_CMD);
|
||||
p += sprintf(p,
|
||||
"alarm_enable\t: %s\n"
|
||||
"wdog_alarm\t: %s\n"
|
||||
"alarm_mask\t: %s\n"
|
||||
"wdog_alarm_mask\t: %s\n"
|
||||
"interrupt_mode\t: %s\n"
|
||||
"INTB_mode\t: %s_active\n"
|
||||
"interrupt_pins\t: %s\n",
|
||||
(cmd & RTC_TDF) ? "yes" : "no",
|
||||
(cmd & RTC_WAF) ? "yes" : "no",
|
||||
(cmd & RTC_TDM) ? "disabled" : "enabled",
|
||||
(cmd & RTC_WAM) ? "disabled" : "enabled",
|
||||
(cmd & RTC_PU_LVL) ? "pulse" : "level",
|
||||
(cmd & RTC_IBH_LO) ? "low" : "high",
|
||||
(cmd & RTC_IPSW) ? "unswapped" : "swapped");
|
||||
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
static int ds1286_read_proc(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data)
|
||||
{
|
||||
int len = ds1286_proc_output (page);
|
||||
if (len <= off+count) *eof = 1;
|
||||
*start = page + off;
|
||||
len -= off;
|
||||
if (len>count)
|
||||
len = count;
|
||||
if (len<0)
|
||||
len = 0;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if a clock update is in progress
|
||||
*/
|
||||
static inline unsigned char ds1286_is_updating(void)
|
||||
{
|
||||
return rtc_read(RTC_CMD) & RTC_TE;
|
||||
}
|
||||
|
||||
|
||||
static void ds1286_get_time(struct rtc_time *rtc_tm)
|
||||
{
|
||||
unsigned char save_control;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* read RTC once any update in progress is done. The update
|
||||
* can take just over 2ms. We wait 10 to 20ms. There is no need to
|
||||
* to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
|
||||
* If you need to know *exactly* when a second has started, enable
|
||||
* periodic update complete interrupts, (via ioctl) and then
|
||||
* immediately read /dev/rtc which will block until you get the IRQ.
|
||||
* Once the read clears, read the RTC time (again via ioctl). Easy.
|
||||
*/
|
||||
|
||||
if (ds1286_is_updating() != 0)
|
||||
msleep(20);
|
||||
|
||||
/*
|
||||
* Only the values that we read from the RTC are set. We leave
|
||||
* tm_wday, tm_yday and tm_isdst untouched. Even though the
|
||||
* RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
|
||||
* by the RTC when initially set to a non-zero value.
|
||||
*/
|
||||
spin_lock_irqsave(&ds1286_lock, flags);
|
||||
save_control = rtc_read(RTC_CMD);
|
||||
rtc_write((save_control|RTC_TE), RTC_CMD);
|
||||
|
||||
rtc_tm->tm_sec = rtc_read(RTC_SECONDS);
|
||||
rtc_tm->tm_min = rtc_read(RTC_MINUTES);
|
||||
rtc_tm->tm_hour = rtc_read(RTC_HOURS) & 0x3f;
|
||||
rtc_tm->tm_mday = rtc_read(RTC_DATE);
|
||||
rtc_tm->tm_mon = rtc_read(RTC_MONTH) & 0x1f;
|
||||
rtc_tm->tm_year = rtc_read(RTC_YEAR);
|
||||
|
||||
rtc_write(save_control, RTC_CMD);
|
||||
spin_unlock_irqrestore(&ds1286_lock, flags);
|
||||
|
||||
rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
|
||||
rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
|
||||
rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
|
||||
rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
|
||||
rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);
|
||||
rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
|
||||
|
||||
/*
|
||||
* Account for differences between how the RTC uses the values
|
||||
* and how they are defined in a struct rtc_time;
|
||||
*/
|
||||
if (rtc_tm->tm_year < 45)
|
||||
rtc_tm->tm_year += 30;
|
||||
if ((rtc_tm->tm_year += 40) < 70)
|
||||
rtc_tm->tm_year += 100;
|
||||
|
||||
rtc_tm->tm_mon--;
|
||||
}
|
||||
|
||||
static int ds1286_set_time(struct rtc_time *rtc_tm)
|
||||
{
|
||||
unsigned char mon, day, hrs, min, sec, leap_yr;
|
||||
unsigned char save_control;
|
||||
unsigned int yrs;
|
||||
unsigned long flags;
|
||||
|
||||
|
||||
yrs = rtc_tm->tm_year + 1900;
|
||||
mon = rtc_tm->tm_mon + 1; /* tm_mon starts at zero */
|
||||
day = rtc_tm->tm_mday;
|
||||
hrs = rtc_tm->tm_hour;
|
||||
min = rtc_tm->tm_min;
|
||||
sec = rtc_tm->tm_sec;
|
||||
|
||||
if (yrs < 1970)
|
||||
return -EINVAL;
|
||||
|
||||
leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
|
||||
|
||||
if ((mon > 12) || (day == 0))
|
||||
return -EINVAL;
|
||||
|
||||
if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
|
||||
return -EINVAL;
|
||||
|
||||
if ((hrs >= 24) || (min >= 60) || (sec >= 60))
|
||||
return -EINVAL;
|
||||
|
||||
if ((yrs -= 1940) > 255) /* They are unsigned */
|
||||
return -EINVAL;
|
||||
|
||||
if (yrs >= 100)
|
||||
yrs -= 100;
|
||||
|
||||
sec = bin2bcd(sec);
|
||||
min = bin2bcd(min);
|
||||
hrs = bin2bcd(hrs);
|
||||
day = bin2bcd(day);
|
||||
mon = bin2bcd(mon);
|
||||
yrs = bin2bcd(yrs);
|
||||
|
||||
spin_lock_irqsave(&ds1286_lock, flags);
|
||||
save_control = rtc_read(RTC_CMD);
|
||||
rtc_write((save_control|RTC_TE), RTC_CMD);
|
||||
|
||||
rtc_write(yrs, RTC_YEAR);
|
||||
rtc_write(mon, RTC_MONTH);
|
||||
rtc_write(day, RTC_DATE);
|
||||
rtc_write(hrs, RTC_HOURS);
|
||||
rtc_write(min, RTC_MINUTES);
|
||||
rtc_write(sec, RTC_SECONDS);
|
||||
rtc_write(0, RTC_HUNDREDTH_SECOND);
|
||||
|
||||
rtc_write(save_control, RTC_CMD);
|
||||
spin_unlock_irqrestore(&ds1286_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ds1286_get_alm_time(struct rtc_time *alm_tm)
|
||||
{
|
||||
unsigned char cmd;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Only the values that we read from the RTC are set. That
|
||||
* means only tm_wday, tm_hour, tm_min.
|
||||
*/
|
||||
spin_lock_irqsave(&ds1286_lock, flags);
|
||||
alm_tm->tm_min = rtc_read(RTC_MINUTES_ALARM) & 0x7f;
|
||||
alm_tm->tm_hour = rtc_read(RTC_HOURS_ALARM) & 0x1f;
|
||||
alm_tm->tm_wday = rtc_read(RTC_DAY_ALARM) & 0x07;
|
||||
cmd = rtc_read(RTC_CMD);
|
||||
spin_unlock_irqrestore(&ds1286_lock, flags);
|
||||
|
||||
alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
|
||||
alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
|
||||
alm_tm->tm_sec = 0;
|
||||
}
|
||||
|
||||
module_init(ds1286_init);
|
||||
module_exit(ds1286_exit);
|
||||
|
||||
MODULE_AUTHOR("Ralf Baechle");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_MISCDEV(RTC_MINOR);
|
@ -1,329 +0,0 @@
|
||||
/*
|
||||
* Driver for the SGS-Thomson M48T35 Timekeeper RAM chip
|
||||
*
|
||||
* Real Time Clock interface for Linux
|
||||
*
|
||||
* TODO: Implement periodic interrupts.
|
||||
*
|
||||
* Copyright (C) 2000 Silicon Graphics, Inc.
|
||||
* Written by Ulf Carlsson (ulfc@engr.sgi.com)
|
||||
*
|
||||
* Based on code written by Paul Gortmaker.
|
||||
*
|
||||
* This driver allows use of the real time clock (built into
|
||||
* nearly all computers) from user space. It exports the /dev/rtc
|
||||
* interface supporting various ioctl() and also the /proc/rtc
|
||||
* pseudo-file for status information.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#define RTC_VERSION "1.09b"
|
||||
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/proc_fs.h>
|
||||
|
||||
#include <asm/m48t35.h>
|
||||
#include <asm/sn/ioc3.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/sn/klconfig.h>
|
||||
#include <asm/sn/sn0/ip27.h>
|
||||
#include <asm/sn/sn0/hub.h>
|
||||
#include <asm/sn/sn_private.h>
|
||||
|
||||
static long rtc_ioctl(struct file *filp, unsigned int cmd,
|
||||
unsigned long arg);
|
||||
|
||||
static int rtc_read_proc(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data);
|
||||
|
||||
static void get_rtc_time(struct rtc_time *rtc_tm);
|
||||
|
||||
/*
|
||||
* Bits in rtc_status. (6 bits of room for future expansion)
|
||||
*/
|
||||
|
||||
#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */
|
||||
#define RTC_TIMER_ON 0x02 /* missed irq timer active */
|
||||
|
||||
static unsigned char rtc_status; /* bitmapped status byte. */
|
||||
static unsigned long rtc_freq; /* Current periodic IRQ rate */
|
||||
static struct m48t35_rtc *rtc;
|
||||
|
||||
/*
|
||||
* If this driver ever becomes modularised, it will be really nice
|
||||
* to make the epoch retain its value across module reload...
|
||||
*/
|
||||
|
||||
static unsigned long epoch = 1970; /* year corresponding to 0x00 */
|
||||
|
||||
static const unsigned char days_in_mo[] =
|
||||
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
|
||||
static long rtc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
|
||||
struct rtc_time wtime;
|
||||
|
||||
switch (cmd) {
|
||||
case RTC_RD_TIME: /* Read the time/date from RTC */
|
||||
{
|
||||
get_rtc_time(&wtime);
|
||||
break;
|
||||
}
|
||||
case RTC_SET_TIME: /* Set the RTC */
|
||||
{
|
||||
struct rtc_time rtc_tm;
|
||||
unsigned char mon, day, hrs, min, sec, leap_yr;
|
||||
unsigned int yrs;
|
||||
|
||||
if (!capable(CAP_SYS_TIME))
|
||||
return -EACCES;
|
||||
|
||||
if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
|
||||
sizeof(struct rtc_time)))
|
||||
return -EFAULT;
|
||||
|
||||
yrs = rtc_tm.tm_year + 1900;
|
||||
mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */
|
||||
day = rtc_tm.tm_mday;
|
||||
hrs = rtc_tm.tm_hour;
|
||||
min = rtc_tm.tm_min;
|
||||
sec = rtc_tm.tm_sec;
|
||||
|
||||
if (yrs < 1970)
|
||||
return -EINVAL;
|
||||
|
||||
leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
|
||||
|
||||
if ((mon > 12) || (day == 0))
|
||||
return -EINVAL;
|
||||
|
||||
if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
|
||||
return -EINVAL;
|
||||
|
||||
if ((hrs >= 24) || (min >= 60) || (sec >= 60))
|
||||
return -EINVAL;
|
||||
|
||||
if ((yrs -= epoch) > 255) /* They are unsigned */
|
||||
return -EINVAL;
|
||||
|
||||
if (yrs > 169)
|
||||
return -EINVAL;
|
||||
|
||||
if (yrs >= 100)
|
||||
yrs -= 100;
|
||||
|
||||
sec = bin2bcd(sec);
|
||||
min = bin2bcd(min);
|
||||
hrs = bin2bcd(hrs);
|
||||
day = bin2bcd(day);
|
||||
mon = bin2bcd(mon);
|
||||
yrs = bin2bcd(yrs);
|
||||
|
||||
spin_lock_irq(&rtc_lock);
|
||||
rtc->control |= M48T35_RTC_SET;
|
||||
rtc->year = yrs;
|
||||
rtc->month = mon;
|
||||
rtc->date = day;
|
||||
rtc->hour = hrs;
|
||||
rtc->min = min;
|
||||
rtc->sec = sec;
|
||||
rtc->control &= ~M48T35_RTC_SET;
|
||||
spin_unlock_irq(&rtc_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We enforce only one user at a time here with the open/close.
|
||||
* Also clear the previous interrupt data on an open, and clean
|
||||
* up things on a close.
|
||||
*/
|
||||
|
||||
static int rtc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
lock_kernel();
|
||||
spin_lock_irq(&rtc_lock);
|
||||
|
||||
if (rtc_status & RTC_IS_OPEN) {
|
||||
spin_unlock_irq(&rtc_lock);
|
||||
unlock_kernel();
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
rtc_status |= RTC_IS_OPEN;
|
||||
spin_unlock_irq(&rtc_lock);
|
||||
unlock_kernel();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtc_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
/*
|
||||
* Turn off all interrupts once the device is no longer
|
||||
* in use, and clear the data.
|
||||
*/
|
||||
|
||||
spin_lock_irq(&rtc_lock);
|
||||
rtc_status &= ~RTC_IS_OPEN;
|
||||
spin_unlock_irq(&rtc_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The various file operations we support.
|
||||
*/
|
||||
|
||||
static const struct file_operations rtc_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.unlocked_ioctl = rtc_ioctl,
|
||||
.open = rtc_open,
|
||||
.release = rtc_release,
|
||||
};
|
||||
|
||||
static struct miscdevice rtc_dev=
|
||||
{
|
||||
RTC_MINOR,
|
||||
"rtc",
|
||||
&rtc_fops
|
||||
};
|
||||
|
||||
static int __init rtc_init(void)
|
||||
{
|
||||
rtc = (struct m48t35_rtc *)
|
||||
(KL_CONFIG_CH_CONS_INFO(master_nasid)->memory_base + IOC3_BYTEBUS_DEV0);
|
||||
|
||||
printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION);
|
||||
if (misc_register(&rtc_dev)) {
|
||||
printk(KERN_ERR "rtc: cannot register misc device.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!create_proc_read_entry("driver/rtc", 0, NULL, rtc_read_proc, NULL)) {
|
||||
printk(KERN_ERR "rtc: cannot create /proc/rtc.\n");
|
||||
misc_deregister(&rtc_dev);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
rtc_freq = 1024;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit rtc_exit (void)
|
||||
{
|
||||
/* interrupts and timer disabled at this point by rtc_release */
|
||||
|
||||
remove_proc_entry ("rtc", NULL);
|
||||
misc_deregister(&rtc_dev);
|
||||
}
|
||||
|
||||
module_init(rtc_init);
|
||||
module_exit(rtc_exit);
|
||||
|
||||
/*
|
||||
* Info exported via "/proc/rtc".
|
||||
*/
|
||||
|
||||
static int rtc_get_status(char *buf)
|
||||
{
|
||||
char *p;
|
||||
struct rtc_time tm;
|
||||
|
||||
/*
|
||||
* Just emulate the standard /proc/rtc
|
||||
*/
|
||||
|
||||
p = buf;
|
||||
|
||||
get_rtc_time(&tm);
|
||||
|
||||
/*
|
||||
* There is no way to tell if the luser has the RTC set for local
|
||||
* time or for Universal Standard Time (GMT). Probably local though.
|
||||
*/
|
||||
p += sprintf(p,
|
||||
"rtc_time\t: %02d:%02d:%02d\n"
|
||||
"rtc_date\t: %04d-%02d-%02d\n"
|
||||
"rtc_epoch\t: %04lu\n"
|
||||
"24hr\t\t: yes\n",
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec,
|
||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch);
|
||||
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
static int rtc_read_proc(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data)
|
||||
{
|
||||
int len = rtc_get_status(page);
|
||||
if (len <= off+count) *eof = 1;
|
||||
*start = page + off;
|
||||
len -= off;
|
||||
if (len>count) len = count;
|
||||
if (len<0) len = 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
static void get_rtc_time(struct rtc_time *rtc_tm)
|
||||
{
|
||||
/*
|
||||
* Do we need to wait for the last update to finish?
|
||||
*/
|
||||
|
||||
/*
|
||||
* Only the values that we read from the RTC are set. We leave
|
||||
* tm_wday, tm_yday and tm_isdst untouched. Even though the
|
||||
* RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
|
||||
* by the RTC when initially set to a non-zero value.
|
||||
*/
|
||||
spin_lock_irq(&rtc_lock);
|
||||
rtc->control |= M48T35_RTC_READ;
|
||||
rtc_tm->tm_sec = rtc->sec;
|
||||
rtc_tm->tm_min = rtc->min;
|
||||
rtc_tm->tm_hour = rtc->hour;
|
||||
rtc_tm->tm_mday = rtc->date;
|
||||
rtc_tm->tm_mon = rtc->month;
|
||||
rtc_tm->tm_year = rtc->year;
|
||||
rtc->control &= ~M48T35_RTC_READ;
|
||||
spin_unlock_irq(&rtc_lock);
|
||||
|
||||
rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
|
||||
rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
|
||||
rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
|
||||
rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
|
||||
rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);
|
||||
rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
|
||||
|
||||
/*
|
||||
* Account for differences between how the RTC uses the values
|
||||
* and how they are defined in a struct rtc_time;
|
||||
*/
|
||||
if ((rtc_tm->tm_year += (epoch - 1900)) <= 69)
|
||||
rtc_tm->tm_year += 100;
|
||||
|
||||
rtc_tm->tm_mon--;
|
||||
}
|
Loading…
Reference in New Issue
Block a user