提交 e61467e9 编写于 作者: L Linus Torvalds

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
......@@ -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;
}
num = BITS_PER_LONG - 1;
return 63 - lz;
#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));
#if defined(CONFIG_64BIT) && defined(CONFIG_CPU_MIPS64)
static inline int fls64(__u64 word)
{
__asm__("dclz %0, %1" : "=r" (word) : "r" (word));
return 32 - x;
}
return 64 - word;
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;
}
#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)
......
/*
* 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 */
/*
* 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 = &current_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 @@ static void emulate_load_store_insn(struct pt_regs *regs,
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;
}
......
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)
......
/*
* 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);
/*
* 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--;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册