Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
8ba706a9
Commit
8ba706a9
authored
Mar 01, 2006
by
David S. Miller
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[SPARC64]: Add mini-RTC driver for Starfire and SUN4V.
Signed-off-by:
David S. Miller
<
davem@davemloft.net
>
parent
b830ab66
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
279 additions
and
0 deletions
+279
-0
arch/sparc64/kernel/time.c
arch/sparc64/kernel/time.c
+279
-0
No files found.
arch/sparc64/kernel/time.c
View file @
8ba706a9
...
...
@@ -30,6 +30,8 @@
#include <linux/cpufreq.h>
#include <linux/percpu.h>
#include <linux/profile.h>
#include <linux/miscdevice.h>
#include <linux/rtc.h>
#include <asm/oplib.h>
#include <asm/mostek.h>
...
...
@@ -45,6 +47,7 @@
#include <asm/smp.h>
#include <asm/sections.h>
#include <asm/cpudata.h>
#include <asm/uaccess.h>
DEFINE_SPINLOCK
(
mostek_lock
);
DEFINE_SPINLOCK
(
rtc_lock
);
...
...
@@ -702,6 +705,14 @@ static u32 starfire_get_time(void)
return
unix_tod
;
}
static
int
starfire_set_time
(
u32
val
)
{
/* Do nothing, time is set using the service processor
* console on this platform.
*/
return
0
;
}
static
u32
hypervisor_get_time
(
void
)
{
register
unsigned
long
func
asm
(
"%o5"
);
...
...
@@ -731,6 +742,33 @@ static u32 hypervisor_get_time(void)
return
0
;
}
static
int
hypervisor_set_time
(
u32
secs
)
{
register
unsigned
long
func
asm
(
"%o5"
);
register
unsigned
long
arg0
asm
(
"%o0"
);
int
retries
=
10000
;
retry:
func
=
HV_FAST_TOD_SET
;
arg0
=
secs
;
__asm__
__volatile__
(
"ta %4"
:
"=&r"
(
func
),
"=&r"
(
arg0
)
:
"0"
(
func
),
"1"
(
arg0
),
"i"
(
HV_FAST_TRAP
));
if
(
arg0
==
HV_EOK
)
return
0
;
if
(
arg0
==
HV_EWOULDBLOCK
)
{
if
(
--
retries
>
0
)
{
udelay
(
100
);
goto
retry
;
}
printk
(
KERN_WARNING
"SUN4V: tod_set() timed out.
\n
"
);
return
-
EAGAIN
;
}
printk
(
KERN_WARNING
"SUN4V: tod_set() not supported.
\n
"
);
return
-
EOPNOTSUPP
;
}
void
__init
clock_probe
(
void
)
{
struct
linux_prom_registers
clk_reg
[
2
];
...
...
@@ -1221,3 +1259,244 @@ static int set_rtc_mmss(unsigned long nowtime)
return
retval
;
}
}
#define RTC_IS_OPEN 0x01
/* means /dev/rtc is in use */
static
unsigned
char
mini_rtc_status
;
/* bitmapped status byte. */
/* months start at 0 now */
static
unsigned
char
days_in_mo
[]
=
{
31
,
28
,
31
,
30
,
31
,
30
,
31
,
31
,
30
,
31
,
30
,
31
};
#define FEBRUARY 2
#define STARTOFTIME 1970
#define SECDAY 86400L
#define SECYR (SECDAY * 365)
#define leapyear(year) ((year) % 4 == 0 && \
((year) % 100 != 0 || (year) % 400 == 0))
#define days_in_year(a) (leapyear(a) ? 366 : 365)
#define days_in_month(a) (month_days[(a) - 1])
static
int
month_days
[
12
]
=
{
31
,
28
,
31
,
30
,
31
,
30
,
31
,
31
,
30
,
31
,
30
,
31
};
/*
* This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
*/
static
void
GregorianDay
(
struct
rtc_time
*
tm
)
{
int
leapsToDate
;
int
lastYear
;
int
day
;
int
MonthOffset
[]
=
{
0
,
31
,
59
,
90
,
120
,
151
,
181
,
212
,
243
,
273
,
304
,
334
};
lastYear
=
tm
->
tm_year
-
1
;
/*
* Number of leap corrections to apply up to end of last year
*/
leapsToDate
=
lastYear
/
4
-
lastYear
/
100
+
lastYear
/
400
;
/*
* This year is a leap year if it is divisible by 4 except when it is
* divisible by 100 unless it is divisible by 400
*
* e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 was
*/
day
=
tm
->
tm_mon
>
2
&&
leapyear
(
tm
->
tm_year
);
day
+=
lastYear
*
365
+
leapsToDate
+
MonthOffset
[
tm
->
tm_mon
-
1
]
+
tm
->
tm_mday
;
tm
->
tm_wday
=
day
%
7
;
}
static
void
to_tm
(
int
tim
,
struct
rtc_time
*
tm
)
{
register
int
i
;
register
long
hms
,
day
;
day
=
tim
/
SECDAY
;
hms
=
tim
%
SECDAY
;
/* Hours, minutes, seconds are easy */
tm
->
tm_hour
=
hms
/
3600
;
tm
->
tm_min
=
(
hms
%
3600
)
/
60
;
tm
->
tm_sec
=
(
hms
%
3600
)
%
60
;
/* Number of years in days */
for
(
i
=
STARTOFTIME
;
day
>=
days_in_year
(
i
);
i
++
)
day
-=
days_in_year
(
i
);
tm
->
tm_year
=
i
;
/* Number of months in days left */
if
(
leapyear
(
tm
->
tm_year
))
days_in_month
(
FEBRUARY
)
=
29
;
for
(
i
=
1
;
day
>=
days_in_month
(
i
);
i
++
)
day
-=
days_in_month
(
i
);
days_in_month
(
FEBRUARY
)
=
28
;
tm
->
tm_mon
=
i
;
/* Days are what is left over (+1) from all that. */
tm
->
tm_mday
=
day
+
1
;
/*
* Determine the day of week
*/
GregorianDay
(
tm
);
}
/* Both Starfire and SUN4V give us seconds since Jan 1st, 1970,
* aka Unix time. So we have to convert to/from rtc_time.
*/
static
inline
void
mini_get_rtc_time
(
struct
rtc_time
*
time
)
{
unsigned
long
flags
;
u32
seconds
;
spin_lock_irqsave
(
&
rtc_lock
,
flags
);
seconds
=
0
;
if
(
this_is_starfire
)
seconds
=
starfire_get_time
();
else
if
(
tlb_type
==
hypervisor
)
seconds
=
hypervisor_get_time
();
spin_unlock_irqrestore
(
&
rtc_lock
,
flags
);
to_tm
(
seconds
,
time
);
}
static
inline
int
mini_set_rtc_time
(
struct
rtc_time
*
time
)
{
u32
seconds
=
mktime
(
time
->
tm_year
+
1900
,
time
->
tm_mon
+
1
,
time
->
tm_mday
,
time
->
tm_hour
,
time
->
tm_min
,
time
->
tm_sec
);
unsigned
long
flags
;
int
err
;
spin_lock_irqsave
(
&
rtc_lock
,
flags
);
err
=
-
ENODEV
;
if
(
this_is_starfire
)
err
=
starfire_set_time
(
seconds
);
else
if
(
tlb_type
==
hypervisor
)
err
=
hypervisor_set_time
(
seconds
);
spin_unlock_irqrestore
(
&
rtc_lock
,
flags
);
return
err
;
}
static
int
mini_rtc_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
struct
rtc_time
wtime
;
void
__user
*
argp
=
(
void
__user
*
)
arg
;
switch
(
cmd
)
{
case
RTC_PLL_GET
:
return
-
EINVAL
;
case
RTC_PLL_SET
:
return
-
EINVAL
;
case
RTC_UIE_OFF
:
/* disable ints from RTC updates. */
return
0
;
case
RTC_UIE_ON
:
/* enable ints for RTC updates. */
return
-
EINVAL
;
case
RTC_RD_TIME
:
/* Read the time/date from RTC */
/* this doesn't get week-day, who cares */
memset
(
&
wtime
,
0
,
sizeof
(
wtime
));
mini_get_rtc_time
(
&
wtime
);
return
copy_to_user
(
argp
,
&
wtime
,
sizeof
(
wtime
))
?
-
EFAULT
:
0
;
case
RTC_SET_TIME
:
/* Set the RTC */
{
int
year
;
unsigned
char
leap_yr
;
if
(
!
capable
(
CAP_SYS_TIME
))
return
-
EACCES
;
if
(
copy_from_user
(
&
wtime
,
argp
,
sizeof
(
wtime
)))
return
-
EFAULT
;
year
=
wtime
.
tm_year
+
1900
;
leap_yr
=
((
!
(
year
%
4
)
&&
(
year
%
100
))
||
!
(
year
%
400
));
if
((
wtime
.
tm_mon
<
0
||
wtime
.
tm_mon
>
11
)
||
(
wtime
.
tm_mday
<
1
))
return
-
EINVAL
;
if
(
wtime
.
tm_mday
<
0
||
wtime
.
tm_mday
>
(
days_in_mo
[
wtime
.
tm_mon
]
+
((
wtime
.
tm_mon
==
1
)
&&
leap_yr
)))
return
-
EINVAL
;
if
(
wtime
.
tm_hour
<
0
||
wtime
.
tm_hour
>=
24
||
wtime
.
tm_min
<
0
||
wtime
.
tm_min
>=
60
||
wtime
.
tm_sec
<
0
||
wtime
.
tm_sec
>=
60
)
return
-
EINVAL
;
return
mini_set_rtc_time
(
&
wtime
);
}
}
return
-
EINVAL
;
}
static
int
mini_rtc_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
mini_rtc_status
&
RTC_IS_OPEN
)
return
-
EBUSY
;
mini_rtc_status
|=
RTC_IS_OPEN
;
return
0
;
}
static
int
mini_rtc_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
mini_rtc_status
&=
~
RTC_IS_OPEN
;
return
0
;
}
static
struct
file_operations
mini_rtc_fops
=
{
.
owner
=
THIS_MODULE
,
.
ioctl
=
mini_rtc_ioctl
,
.
open
=
mini_rtc_open
,
.
release
=
mini_rtc_release
,
};
static
struct
miscdevice
rtc_mini_dev
=
{
.
minor
=
RTC_MINOR
,
.
name
=
"rtc"
,
.
fops
=
&
mini_rtc_fops
,
};
static
int
__init
rtc_mini_init
(
void
)
{
int
retval
;
if
(
tlb_type
!=
hypervisor
&&
!
this_is_starfire
)
return
-
ENODEV
;
printk
(
KERN_INFO
"Mini RTC Driver
\n
"
);
retval
=
misc_register
(
&
rtc_mini_dev
);
if
(
retval
<
0
)
return
retval
;
return
0
;
}
static
void
__exit
rtc_mini_exit
(
void
)
{
misc_deregister
(
&
rtc_mini_dev
);
}
module_init
(
rtc_mini_init
);
module_exit
(
rtc_mini_exit
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment