Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci-2.6.23
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci-2.6.23
Commits
da9f0ac2
Commit
da9f0ac2
authored
Jul 20, 2007
by
Paul Mundt
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'clkfwk'
parents
bd5f0d1c
cb5ec75b
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
113 additions
and
135 deletions
+113
-135
arch/sh/Kconfig
arch/sh/Kconfig
+1
-1
arch/sh/kernel/cpu/clock.c
arch/sh/kernel/cpu/clock.c
+16
-0
arch/sh/kernel/cpu/sh4a/clock-sh7722.c
arch/sh/kernel/cpu/sh4a/clock-sh7722.c
+15
-0
arch/sh/kernel/cpufreq.c
arch/sh/kernel/cpufreq.c
+80
-134
include/asm-sh/clock.h
include/asm-sh/clock.h
+1
-0
No files found.
arch/sh/Kconfig
View file @
da9f0ac2
...
...
@@ -475,7 +475,7 @@ source "drivers/cpufreq/Kconfig"
config SH_CPU_FREQ
tristate "SuperH CPU Frequency driver"
depends on CPU_FREQ
&& CPU_SH4 && BROKEN
depends on CPU_FREQ
select CPU_FREQ_TABLE
help
This adds the cpufreq driver for SuperH. At present, only
...
...
arch/sh/kernel/cpu/clock.c
View file @
da9f0ac2
...
...
@@ -229,6 +229,22 @@ void clk_recalc_rate(struct clk *clk)
}
EXPORT_SYMBOL_GPL
(
clk_recalc_rate
);
long
clk_round_rate
(
struct
clk
*
clk
,
unsigned
long
rate
)
{
if
(
likely
(
clk
->
ops
&&
clk
->
ops
->
round_rate
))
{
unsigned
long
flags
,
rounded
;
spin_lock_irqsave
(
&
clock_lock
,
flags
);
rounded
=
clk
->
ops
->
round_rate
(
clk
,
rate
);
spin_unlock_irqrestore
(
&
clock_lock
,
flags
);
return
rounded
;
}
return
clk_get_rate
(
clk
);
}
EXPORT_SYMBOL_GPL
(
clk_round_rate
);
/*
* Returns a clock. Note that we first try to use device id on the bus
* and clock name. If this fails, we try to use clock name only.
...
...
arch/sh/kernel/cpu/sh4a/clock-sh7722.c
View file @
da9f0ac2
...
...
@@ -387,9 +387,24 @@ out_err:
return
err
;
}
static
long
sh7722_frqcr_round_rate
(
struct
clk
*
clk
,
unsigned
long
rate
)
{
unsigned
long
parent_rate
=
clk
->
parent
->
rate
;
int
div
;
/* look for multiplier/divisor pair */
div
=
sh7722_find_divisors
(
parent_rate
,
rate
);
if
(
div
<
0
)
return
clk
->
rate
;
/* calculate new value of clock rate */
return
parent_rate
*
2
/
div
;
}
static
struct
clk_ops
sh7722_frqcr_clk_ops
=
{
.
recalc
=
sh7722_frqcr_recalc
,
.
set_rate
=
sh7722_frqcr_set_rate
,
.
round_rate
=
sh7722_frqcr_round_rate
,
};
/*
...
...
arch/sh/kernel/cpufreq.c
View file @
da9f0ac2
...
...
@@ -3,89 +3,51 @@
*
* cpufreq driver for the SuperH processors.
*
* Copyright (C) 2002
, 2003, 2004, 2005
Paul Mundt
* Copyright (C) 2002
- 2007
Paul Mundt
* Copyright (C) 2002 M. R. Brown
*
* 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.
* Clock framework bits from arch/avr32/mach-at32ap/cpufreq.c
*
* Copyright (C) 2004-2007 Atmel Corporation
*
* 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.
*/
#include <linux/types.h>
#include <linux/cpufreq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/
delay
.h>
#include <linux/
err
.h>
#include <linux/cpumask.h>
#include <linux/smp.h>
#include <linux/sched.h>
/* set_cpus_allowed() */
#include <linux/io.h>
#include <linux/clk.h>
#include <asm/processor.h>
#include <asm/watchdog.h>
#include <asm/freq.h>
#include <asm/io.h>
/*
* For SuperH, each policy change requires that we change the IFC, BFC, and
* PFC at the same time. Here we define sane values that won't trash the
* system.
*
* Note the max set is computed at runtime, we use the divisors that we booted
* with to setup our maximum operating frequencies.
*/
struct
clock_set
{
unsigned
int
ifc
;
unsigned
int
bfc
;
unsigned
int
pfc
;
}
clock_sets
[]
=
{
#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH2)
{
0
,
0
,
0
},
/* not implemented yet */
#elif defined(CONFIG_CPU_SH4)
{
4
,
8
,
8
},
/* min - IFC: 1/4, BFC: 1/8, PFC: 1/8 */
{
1
,
2
,
2
},
/* max - IFC: 1, BFC: 1/2, PFC: 1/2 */
#endif
};
#define MIN_CLOCK_SET 0
#define MAX_CLOCK_SET (ARRAY_SIZE(clock_sets) - 1)
/*
* For the time being, we only support two frequencies, which in turn are
* aimed at the POWERSAVE and PERFORMANCE policies, which in turn are derived
* directly from the respective min/max clock sets. Technically we could
* support a wider range of frequencies, but these vary far too much for each
* CPU subtype (and we'd have to construct a frequency table for each subtype).
*
* Maybe something to implement in the future..
*/
#define SH_FREQ_MAX 0
#define SH_FREQ_MIN 1
#include <asm/clock.h>
static
struct
cpufreq_frequency_table
sh_freqs
[]
=
{
{
SH_FREQ_MAX
,
0
},
{
SH_FREQ_MIN
,
0
},
{
0
,
CPUFREQ_TABLE_END
},
};
static
struct
clk
*
cpuclk
;
static
void
sh_cpufreq_update_clocks
(
unsigned
int
set
)
static
unsigned
int
sh_cpufreq_get
(
unsigned
int
cpu
)
{
current_cpu_data
.
cpu_clock
=
current_cpu_data
.
master_clock
/
clock_sets
[
set
].
ifc
;
current_cpu_data
.
bus_clock
=
current_cpu_data
.
master_clock
/
clock_sets
[
set
].
bfc
;
current_cpu_data
.
module_clock
=
current_cpu_data
.
master_clock
/
clock_sets
[
set
].
pfc
;
current_cpu_data
.
loops_per_jiffy
=
loops_per_jiffy
;
return
(
clk_get_rate
(
cpuclk
)
+
500
)
/
1000
;
}
/* XXX: This needs to be split out per CPU and CPU subtype. */
/*
* Here we notify other drivers of the proposed change and the final change.
*/
static
int
sh_cpufreq_setstate
(
unsigned
int
cpu
,
unsigned
int
set
)
static
int
sh_cpufreq_target
(
struct
cpufreq_policy
*
policy
,
unsigned
int
target_freq
,
unsigned
int
relation
)
{
unsigned
short
frqcr
=
ctrl_inw
(
FRQCR
)
;
unsigned
int
cpu
=
policy
->
cpu
;
cpumask_t
cpus_allowed
;
struct
cpufreq_freqs
freqs
;
long
freq
;
if
(
!
cpu_online
(
cpu
))
return
-
ENODEV
;
...
...
@@ -95,125 +57,109 @@ static int sh_cpufreq_setstate(unsigned int cpu, unsigned int set)
BUG_ON
(
smp_processor_id
()
!=
cpu
);
freqs
.
cpu
=
cpu
;
freqs
.
old
=
current_cpu_data
.
cpu_clock
/
1000
;
freqs
.
new
=
(
current_cpu_data
.
master_clock
/
clock_sets
[
set
].
ifc
)
/
1000
;
/* Convert target_freq from kHz to Hz */
freq
=
clk_round_rate
(
cpuclk
,
target_freq
*
1000
);
cpufreq_notify_transition
(
&
freqs
,
CPUFREQ_PRECHANGE
);
#if defined(CONFIG_CPU_SH3)
frqcr
|=
(
newstate
&
0x4000
)
<<
14
;
frqcr
|=
(
newstate
&
0x000c
)
<<
2
;
#elif defined(CONFIG_CPU_SH4)
/*
* FRQCR.PLL2EN is 1, we need to allow the PLL to stabilize by
* initializing the WDT.
*/
if
(
frqcr
&
(
1
<<
9
))
{
__u8
csr
;
/*
* Set the overflow period to the highest available,
* in this case a 1/4096 division ratio yields a 5.25ms
* overflow period. See asm-sh/watchdog.h for more
* information and a range of other divisors.
*/
csr
=
sh_wdt_read_csr
();
csr
|=
WTCSR_CKS_4096
;
sh_wdt_write_csr
(
csr
);
sh_wdt_write_cnt
(
0
);
}
frqcr
&=
0x0e00
;
/* Clear ifc, bfc, pfc */
frqcr
|=
get_ifc_value
(
clock_sets
[
set
].
ifc
)
<<
6
;
frqcr
|=
get_bfc_value
(
clock_sets
[
set
].
bfc
)
<<
3
;
frqcr
|=
get_pfc_value
(
clock_sets
[
set
].
pfc
);
#endif
ctrl_outw
(
frqcr
,
FRQCR
);
sh_cpufreq_update_clocks
(
set
);
if
(
freq
<
(
policy
->
min
*
1000
)
||
freq
>
(
policy
->
max
*
1000
))
return
-
EINVAL
;
pr_debug
(
"cpufreq: requested frequency %u Hz
\n
"
,
target_freq
*
1000
);
freqs
.
cpu
=
cpu
;
freqs
.
old
=
sh_cpufreq_get
(
cpu
);
freqs
.
new
=
(
freq
+
500
)
/
1000
;
freqs
.
flags
=
0
;
cpufreq_notify_transition
(
&
freqs
,
CPUFREQ_PRECHANGE
);
set_cpus_allowed
(
current
,
cpus_allowed
);
clk_set_rate
(
cpuclk
,
freq
);
cpufreq_notify_transition
(
&
freqs
,
CPUFREQ_POSTCHANGE
);
pr_debug
(
"cpufreq: set frequency %lu Hz
\n
"
,
freq
);
return
0
;
}
static
int
sh_cpufreq_cpu_init
(
struct
cpufreq_policy
*
policy
)
{
unsigned
int
min_freq
,
max_freq
;
unsigned
int
ifc
,
bfc
,
pfc
;
printk
(
KERN_INFO
"cpufreq: SuperH CPU frequency driver.
\n
"
);
if
(
!
cpu_online
(
policy
->
cpu
))
return
-
ENODEV
;
/* Update our maximum clock set */
get_current_frequency_divisors
(
&
ifc
,
&
bfc
,
&
pfc
);
clock_sets
[
MAX_CLOCK_SET
].
ifc
=
ifc
;
clock_sets
[
MAX_CLOCK_SET
].
bfc
=
bfc
;
clock_sets
[
MAX_CLOCK_SET
].
pfc
=
pfc
;
/* Convert from Hz to kHz */
max_freq
=
current_cpu_data
.
cpu_clock
/
1000
;
min_freq
=
(
current_cpu_data
.
master_clock
/
clock_sets
[
MIN_CLOCK_SET
].
ifc
)
/
1000
;
sh_freqs
[
SH_FREQ_MAX
].
frequency
=
max_freq
;
sh_freqs
[
SH_FREQ_MIN
].
frequency
=
min_freq
;
cpuclk
=
clk_get
(
NULL
,
"cpu_clk"
);
if
(
IS_ERR
(
cpuclk
))
{
printk
(
KERN_ERR
"cpufreq: couldn't get CPU clk
\n
"
);
return
PTR_ERR
(
cpuclk
);
}
/* cpuinfo and default policy values */
policy
->
governor
=
CPUFREQ_DEFAULT_GOVERNOR
;
policy
->
cpuinfo
.
min_freq
=
(
clk_round_rate
(
cpuclk
,
1
)
+
500
)
/
1000
;
policy
->
cpuinfo
.
max_freq
=
(
clk_round_rate
(
cpuclk
,
~
0UL
)
+
500
)
/
1000
;
policy
->
cpuinfo
.
transition_latency
=
CPUFREQ_ETERNAL
;
policy
->
cur
=
max_freq
;
return
cpufreq_frequency_table_cpuinfo
(
policy
,
&
sh_freqs
[
0
]);
}
policy
->
governor
=
CPUFREQ_DEFAULT_GOVERNOR
;
policy
->
cur
=
sh_cpufreq_get
(
policy
->
cpu
);
policy
->
min
=
policy
->
cpuinfo
.
min_freq
;
policy
->
max
=
policy
->
cpuinfo
.
max_freq
;
static
int
sh_cpufreq_verify
(
struct
cpufreq_policy
*
policy
)
{
return
cpufreq_frequency_table_verify
(
policy
,
&
sh_freqs
[
0
]);
}
static
int
sh_cpufreq_target
(
struct
cpufreq_policy
*
policy
,
unsigned
int
target_freq
,
unsigned
int
relation
)
{
unsigned
int
set
,
idx
=
0
;
/*
* Catch the cases where the clock framework hasn't been wired up
* properly to support scaling.
*/
if
(
unlikely
(
policy
->
min
==
policy
->
max
))
{
printk
(
KERN_ERR
"cpufreq: clock framework rate rounding "
"not supported on this CPU.
\n
"
);
if
(
cpufreq_frequency_table_target
(
policy
,
&
sh_freqs
[
0
],
target_freq
,
relation
,
&
idx
))
clk_put
(
cpuclk
);
return
-
EINVAL
;
}
set
=
(
idx
==
SH_FREQ_MIN
)
?
MIN_CLOCK_SET
:
MAX_CLOCK_SET
;
printk
(
KERN_INFO
"cpufreq: Frequencies - Minimum %u.%03u MHz, "
"Maximum %u.%03u MHz.
\n
"
,
policy
->
min
/
1000
,
policy
->
min
%
1000
,
policy
->
max
/
1000
,
policy
->
max
%
1000
);
sh_cpufreq_setstate
(
policy
->
cpu
,
set
);
return
0
;
}
static
int
sh_cpufreq_verify
(
struct
cpufreq_policy
*
policy
)
{
cpufreq_verify_within_limits
(
policy
,
policy
->
cpuinfo
.
min_freq
,
policy
->
cpuinfo
.
max_freq
);
return
0
;
}
static
int
sh_cpufreq_exit
(
struct
cpufreq_policy
*
policy
)
{
clk_put
(
cpuclk
);
return
0
;
}
static
struct
cpufreq_driver
sh_cpufreq_driver
=
{
.
owner
=
THIS_MODULE
,
.
name
=
"
SH cpufreq
"
,
.
name
=
"
sh
"
,
.
init
=
sh_cpufreq_cpu_init
,
.
verify
=
sh_cpufreq_verify
,
.
target
=
sh_cpufreq_target
,
.
get
=
sh_cpufreq_get
,
.
exit
=
sh_cpufreq_exit
,
};
static
int
__init
sh_cpufreq_init
(
void
)
static
int
__init
sh_cpufreq_
module_
init
(
void
)
{
if
(
!
current_cpu_data
.
cpu_clock
)
return
-
EINVAL
;
if
(
cpufreq_register_driver
(
&
sh_cpufreq_driver
))
return
-
EINVAL
;
return
0
;
return
cpufreq_register_driver
(
&
sh_cpufreq_driver
);
}
static
void
__exit
sh_cpufreq_exit
(
void
)
static
void
__exit
sh_cpufreq_
module_
exit
(
void
)
{
cpufreq_unregister_driver
(
&
sh_cpufreq_driver
);
}
module_init
(
sh_cpufreq_init
);
module_exit
(
sh_cpufreq_exit
);
module_init
(
sh_cpufreq_
module_
init
);
module_exit
(
sh_cpufreq_
module_
exit
);
MODULE_AUTHOR
(
"Paul Mundt <lethal@linux-sh.org>"
);
MODULE_DESCRIPTION
(
"cpufreq driver for SuperH"
);
MODULE_LICENSE
(
"GPL"
);
include/asm-sh/clock.h
View file @
da9f0ac2
...
...
@@ -14,6 +14,7 @@ struct clk_ops {
void
(
*
disable
)(
struct
clk
*
clk
);
void
(
*
recalc
)(
struct
clk
*
clk
);
int
(
*
set_rate
)(
struct
clk
*
clk
,
unsigned
long
rate
,
int
algo_id
);
long
(
*
round_rate
)(
struct
clk
*
clk
,
unsigned
long
rate
);
};
struct
clk
{
...
...
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