Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
K
KED Linux Kernel Fork
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Model registry
Analyze
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
KED Software Projects
Miscellaneous
KED Linux Kernel Fork
Commits
8ba706a9
Commit
8ba706a9
authored
19 years ago
by
David S. Miller
Browse files
Options
Downloads
Patches
Plain Diff
[SPARC64]: Add mini-RTC driver for Starfire and SUN4V.
Signed-off-by:
David S. Miller
<
davem@davemloft.net
>
parent
b830ab66
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
arch/sparc64/kernel/time.c
+279
-0
279 additions, 0 deletions
arch/sparc64/kernel/time.c
with
279 additions
and
0 deletions
arch/sparc64/kernel/time.c
+
279
−
0
View file @
8ba706a9
...
@@ -30,6 +30,8 @@
...
@@ -30,6 +30,8 @@
#include
<linux/cpufreq.h>
#include
<linux/cpufreq.h>
#include
<linux/percpu.h>
#include
<linux/percpu.h>
#include
<linux/profile.h>
#include
<linux/profile.h>
#include
<linux/miscdevice.h>
#include
<linux/rtc.h>
#include
<asm/oplib.h>
#include
<asm/oplib.h>
#include
<asm/mostek.h>
#include
<asm/mostek.h>
...
@@ -45,6 +47,7 @@
...
@@ -45,6 +47,7 @@
#include
<asm/smp.h>
#include
<asm/smp.h>
#include
<asm/sections.h>
#include
<asm/sections.h>
#include
<asm/cpudata.h>
#include
<asm/cpudata.h>
#include
<asm/uaccess.h>
DEFINE_SPINLOCK
(
mostek_lock
);
DEFINE_SPINLOCK
(
mostek_lock
);
DEFINE_SPINLOCK
(
rtc_lock
);
DEFINE_SPINLOCK
(
rtc_lock
);
...
@@ -702,6 +705,14 @@ static u32 starfire_get_time(void)
...
@@ -702,6 +705,14 @@ static u32 starfire_get_time(void)
return
unix_tod
;
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
)
static
u32
hypervisor_get_time
(
void
)
{
{
register
unsigned
long
func
asm
(
"%o5"
);
register
unsigned
long
func
asm
(
"%o5"
);
...
@@ -731,6 +742,33 @@ static u32 hypervisor_get_time(void)
...
@@ -731,6 +742,33 @@ static u32 hypervisor_get_time(void)
return
0
;
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
)
void
__init
clock_probe
(
void
)
{
{
struct
linux_prom_registers
clk_reg
[
2
];
struct
linux_prom_registers
clk_reg
[
2
];
...
@@ -1221,3 +1259,244 @@ static int set_rtc_mmss(unsigned long nowtime)
...
@@ -1221,3 +1259,244 @@ static int set_rtc_mmss(unsigned long nowtime)
return
retval
;
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
);
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment