Merge branch 'tegra/clk' into next/dt2
This is a dependency for the tegra/dt branch. Conflicts: drivers/clocksource/tegra20_timer.c Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
Коммит
f8da810cbb
|
@ -0,0 +1,56 @@
|
|||
Frequently asked questions about the sunxi clock system
|
||||
=======================================================
|
||||
|
||||
This document contains useful bits of information that people tend to ask
|
||||
about the sunxi clock system, as well as accompanying ASCII art when adequate.
|
||||
|
||||
Q: Why is the main 24MHz oscillator gatable? Wouldn't that break the
|
||||
system?
|
||||
|
||||
A: The 24MHz oscillator allows gating to save power. Indeed, if gated
|
||||
carelessly the system would stop functioning, but with the right
|
||||
steps, one can gate it and keep the system running. Consider this
|
||||
simplified suspend example:
|
||||
|
||||
While the system is operational, you would see something like
|
||||
|
||||
24MHz 32kHz
|
||||
|
|
||||
PLL1
|
||||
\
|
||||
\_ CPU Mux
|
||||
|
|
||||
[CPU]
|
||||
|
||||
When you are about to suspend, you switch the CPU Mux to the 32kHz
|
||||
oscillator:
|
||||
|
||||
24Mhz 32kHz
|
||||
| |
|
||||
PLL1 |
|
||||
/
|
||||
CPU Mux _/
|
||||
|
|
||||
[CPU]
|
||||
|
||||
Finally you can gate the main oscillator
|
||||
|
||||
32kHz
|
||||
|
|
||||
|
|
||||
/
|
||||
CPU Mux _/
|
||||
|
|
||||
[CPU]
|
||||
|
||||
Q: Were can I learn more about the sunxi clocks?
|
||||
|
||||
A: The linux-sunxi wiki contains a page documenting the clock registers,
|
||||
you can find it at
|
||||
|
||||
http://linux-sunxi.org/A10/CCM
|
||||
|
||||
The authoritative source for information at this time is the ccmu driver
|
||||
released by Allwinner, you can find it at
|
||||
|
||||
https://github.com/linux-sunxi/linux-sunxi/tree/sunxi-3.0/arch/arm/mach-sun4i/clock/ccmu
|
|
@ -174,9 +174,9 @@ int clk_foo_enable(struct clk_hw *hw)
|
|||
};
|
||||
|
||||
Below is a matrix detailing which clk_ops are mandatory based upon the
|
||||
hardware capbilities of that clock. A cell marked as "y" means
|
||||
hardware capabilities of that clock. A cell marked as "y" means
|
||||
mandatory, a cell marked as "n" implies that either including that
|
||||
callback is invalid or otherwise uneccesary. Empty cells are either
|
||||
callback is invalid or otherwise unnecessary. Empty cells are either
|
||||
optional or must be evaluated on a case-by-case basis.
|
||||
|
||||
clock hardware characteristics
|
||||
|
|
|
@ -1,19 +1,84 @@
|
|||
NVIDIA Tegra Power Management Controller (PMC)
|
||||
|
||||
Properties:
|
||||
The PMC block interacts with an external Power Management Unit. The PMC
|
||||
mostly controls the entry and exit of the system from different sleep
|
||||
modes. It provides power-gating controllers for SoC and CPU power-islands.
|
||||
|
||||
Required properties:
|
||||
- name : Should be pmc
|
||||
- compatible : Should contain "nvidia,tegra<chip>-pmc".
|
||||
- reg : Offset and length of the register set for the device
|
||||
- clocks : Must contain an entry for each entry in clock-names.
|
||||
- clock-names : Must include the following entries:
|
||||
"pclk" (The Tegra clock of that name),
|
||||
"clk32k_in" (The 32KHz clock input to Tegra).
|
||||
|
||||
Optional properties:
|
||||
- nvidia,invert-interrupt : If present, inverts the PMU interrupt signal.
|
||||
The PMU is an external Power Management Unit, whose interrupt output
|
||||
signal is fed into the PMC. This signal is optionally inverted, and then
|
||||
fed into the ARM GIC. The PMC is not involved in the detection or
|
||||
handling of this interrupt signal, merely its inversion.
|
||||
- nvidia,suspend-mode : The suspend mode that the platform should use.
|
||||
Valid values are 0, 1 and 2:
|
||||
0 (LP0): CPU + Core voltage off and DRAM in self-refresh
|
||||
1 (LP1): CPU voltage off and DRAM in self-refresh
|
||||
2 (LP2): CPU voltage off
|
||||
- nvidia,core-power-req-active-high : Boolean, core power request active-high
|
||||
- nvidia,sys-clock-req-active-high : Boolean, system clock request active-high
|
||||
- nvidia,combined-power-req : Boolean, combined power request for CPU & Core
|
||||
- nvidia,cpu-pwr-good-en : Boolean, CPU power good signal (from PMIC to PMC)
|
||||
is enabled.
|
||||
|
||||
Required properties when nvidia,suspend-mode is specified:
|
||||
- nvidia,cpu-pwr-good-time : CPU power good time in uS.
|
||||
- nvidia,cpu-pwr-off-time : CPU power off time in uS.
|
||||
- nvidia,core-pwr-good-time : <Oscillator-stable-time Power-stable-time>
|
||||
Core power good time in uS.
|
||||
- nvidia,core-pwr-off-time : Core power off time in uS.
|
||||
|
||||
Required properties when nvidia,suspend-mode=<0>:
|
||||
- nvidia,lp0-vec : <start length> Starting address and length of LP0 vector
|
||||
The LP0 vector contains the warm boot code that is executed by AVP when
|
||||
resuming from the LP0 state. The AVP (Audio-Video Processor) is an ARM7
|
||||
processor and always being the first boot processor when chip is power on
|
||||
or resume from deep sleep mode. When the system is resumed from the deep
|
||||
sleep mode, the warm boot code will restore some PLLs, clocks and then
|
||||
bring up CPU0 for resuming the system.
|
||||
|
||||
Example:
|
||||
|
||||
/ SoC dts including file
|
||||
pmc@7000f400 {
|
||||
compatible = "nvidia,tegra20-pmc";
|
||||
reg = <0x7000e400 0x400>;
|
||||
clocks = <&tegra_car 110>, <&clk32k_in>;
|
||||
clock-names = "pclk", "clk32k_in";
|
||||
nvidia,invert-interrupt;
|
||||
nvidia,suspend-mode = <1>;
|
||||
nvidia,cpu-pwr-good-time = <2000>;
|
||||
nvidia,cpu-pwr-off-time = <100>;
|
||||
nvidia,core-pwr-good-time = <3845 3845>;
|
||||
nvidia,core-pwr-off-time = <458>;
|
||||
nvidia,core-power-req-active-high;
|
||||
nvidia,sys-clock-req-active-high;
|
||||
nvidia,lp0-vec = <0xbdffd000 0x2000>;
|
||||
};
|
||||
|
||||
/ Tegra board dts file
|
||||
{
|
||||
...
|
||||
clocks {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
clk32k_in: clock {
|
||||
compatible = "fixed-clock";
|
||||
reg=<0>;
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <32768>;
|
||||
};
|
||||
};
|
||||
...
|
||||
};
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
Binding for the axi-clkgen clock generator
|
||||
|
||||
This binding uses the common clock binding[1].
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
||||
Required properties:
|
||||
- compatible : shall be "adi,axi-clkgen".
|
||||
- #clock-cells : from common clock binding; Should always be set to 0.
|
||||
- reg : Address and length of the axi-clkgen register set.
|
||||
- clocks : Phandle and clock specifier for the parent clock.
|
||||
|
||||
Optional properties:
|
||||
- clock-output-names : From common clock binding.
|
||||
|
||||
Example:
|
||||
clock@0xff000000 {
|
||||
compatible = "adi,axi-clkgen";
|
||||
#clock-cells = <0>;
|
||||
reg = <0xff000000 0x1000>;
|
||||
clocks = <&osc 1>;
|
||||
};
|
|
@ -0,0 +1,303 @@
|
|||
NVIDIA Tegra114 Clock And Reset Controller
|
||||
|
||||
This binding uses the common clock binding:
|
||||
Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
||||
The CAR (Clock And Reset) Controller on Tegra is the HW module responsible
|
||||
for muxing and gating Tegra's clocks, and setting their rates.
|
||||
|
||||
Required properties :
|
||||
- compatible : Should be "nvidia,tegra114-car"
|
||||
- reg : Should contain CAR registers location and length
|
||||
- clocks : Should contain phandle and clock specifiers for two clocks:
|
||||
the 32 KHz "32k_in", and the board-specific oscillator "osc".
|
||||
- #clock-cells : Should be 1.
|
||||
In clock consumers, this cell represents the clock ID exposed by the CAR.
|
||||
|
||||
The first 160 clocks are numbered to match the bits in the CAR's CLK_OUT_ENB
|
||||
registers. These IDs often match those in the CAR's RST_DEVICES registers,
|
||||
but not in all cases. Some bits in CLK_OUT_ENB affect multiple clocks. In
|
||||
this case, those clocks are assigned IDs above 160 in order to highlight
|
||||
this issue. Implementations that interpret these clock IDs as bit values
|
||||
within the CLK_OUT_ENB or RST_DEVICES registers should be careful to
|
||||
explicitly handle these special cases.
|
||||
|
||||
The balance of the clocks controlled by the CAR are assigned IDs of 160 and
|
||||
above.
|
||||
|
||||
0 unassigned
|
||||
1 unassigned
|
||||
2 unassigned
|
||||
3 unassigned
|
||||
4 rtc
|
||||
5 timer
|
||||
6 uarta
|
||||
7 unassigned (register bit affects uartb and vfir)
|
||||
8 unassigned
|
||||
9 sdmmc2
|
||||
10 unassigned (register bit affects spdif_in and spdif_out)
|
||||
11 i2s1
|
||||
12 i2c1
|
||||
13 ndflash
|
||||
14 sdmmc1
|
||||
15 sdmmc4
|
||||
16 unassigned
|
||||
17 pwm
|
||||
18 i2s2
|
||||
19 epp
|
||||
20 unassigned (register bit affects vi and vi_sensor)
|
||||
21 2d
|
||||
22 usbd
|
||||
23 isp
|
||||
24 3d
|
||||
25 unassigned
|
||||
26 disp2
|
||||
27 disp1
|
||||
28 host1x
|
||||
29 vcp
|
||||
30 i2s0
|
||||
31 unassigned
|
||||
|
||||
32 unassigned
|
||||
33 unassigned
|
||||
34 apbdma
|
||||
35 unassigned
|
||||
36 kbc
|
||||
37 unassigned
|
||||
38 unassigned
|
||||
39 unassigned (register bit affects fuse and fuse_burn)
|
||||
40 kfuse
|
||||
41 sbc1
|
||||
42 nor
|
||||
43 unassigned
|
||||
44 sbc2
|
||||
45 unassigned
|
||||
46 sbc3
|
||||
47 i2c5
|
||||
48 dsia
|
||||
49 unassigned
|
||||
50 mipi
|
||||
51 hdmi
|
||||
52 csi
|
||||
53 unassigned
|
||||
54 i2c2
|
||||
55 uartc
|
||||
56 mipi-cal
|
||||
57 emc
|
||||
58 usb2
|
||||
59 usb3
|
||||
60 msenc
|
||||
61 vde
|
||||
62 bsea
|
||||
63 bsev
|
||||
|
||||
64 unassigned
|
||||
65 uartd
|
||||
66 unassigned
|
||||
67 i2c3
|
||||
68 sbc4
|
||||
69 sdmmc3
|
||||
70 unassigned
|
||||
71 owr
|
||||
72 afi
|
||||
73 csite
|
||||
74 unassigned
|
||||
75 unassigned
|
||||
76 la
|
||||
77 trace
|
||||
78 soc_therm
|
||||
79 dtv
|
||||
80 ndspeed
|
||||
81 i2cslow
|
||||
82 dsib
|
||||
83 tsec
|
||||
84 unassigned
|
||||
85 unassigned
|
||||
86 unassigned
|
||||
87 unassigned
|
||||
88 unassigned
|
||||
89 xusb_host
|
||||
90 unassigned
|
||||
91 msenc
|
||||
92 csus
|
||||
93 unassigned
|
||||
94 unassigned
|
||||
95 unassigned (bit affects xusb_dev and xusb_dev_src)
|
||||
|
||||
96 unassigned
|
||||
97 unassigned
|
||||
98 unassigned
|
||||
99 mselect
|
||||
100 tsensor
|
||||
101 i2s3
|
||||
102 i2s4
|
||||
103 i2c4
|
||||
104 sbc5
|
||||
105 sbc6
|
||||
106 d_audio
|
||||
107 apbif
|
||||
108 dam0
|
||||
109 dam1
|
||||
110 dam2
|
||||
111 hda2codec_2x
|
||||
112 unassigned
|
||||
113 audio0_2x
|
||||
114 audio1_2x
|
||||
115 audio2_2x
|
||||
116 audio3_2x
|
||||
117 audio4_2x
|
||||
118 spdif_2x
|
||||
119 actmon
|
||||
120 extern1
|
||||
121 extern2
|
||||
122 extern3
|
||||
123 unassigned
|
||||
124 unassigned
|
||||
125 hda
|
||||
126 unassigned
|
||||
127 se
|
||||
|
||||
128 hda2hdmi
|
||||
129 unassigned
|
||||
130 unassigned
|
||||
131 unassigned
|
||||
132 unassigned
|
||||
133 unassigned
|
||||
134 unassigned
|
||||
135 unassigned
|
||||
136 unassigned
|
||||
137 unassigned
|
||||
138 unassigned
|
||||
139 unassigned
|
||||
140 unassigned
|
||||
141 unassigned
|
||||
142 unassigned
|
||||
143 unassigned (bit affects xusb_falcon_src, xusb_fs_src,
|
||||
xusb_host_src and xusb_ss_src)
|
||||
144 cilab
|
||||
145 cilcd
|
||||
146 cile
|
||||
147 dsialp
|
||||
148 dsiblp
|
||||
149 unassigned
|
||||
150 dds
|
||||
151 unassigned
|
||||
152 dp2
|
||||
153 amx
|
||||
154 adx
|
||||
155 unassigned (bit affects dfll_ref and dfll_soc)
|
||||
156 xusb_ss
|
||||
|
||||
192 uartb
|
||||
193 vfir
|
||||
194 spdif_in
|
||||
195 spdif_out
|
||||
196 vi
|
||||
197 vi_sensor
|
||||
198 fuse
|
||||
199 fuse_burn
|
||||
200 clk_32k
|
||||
201 clk_m
|
||||
202 clk_m_div2
|
||||
203 clk_m_div4
|
||||
204 pll_ref
|
||||
205 pll_c
|
||||
206 pll_c_out1
|
||||
207 pll_c2
|
||||
208 pll_c3
|
||||
209 pll_m
|
||||
210 pll_m_out1
|
||||
211 pll_p
|
||||
212 pll_p_out1
|
||||
213 pll_p_out2
|
||||
214 pll_p_out3
|
||||
215 pll_p_out4
|
||||
216 pll_a
|
||||
217 pll_a_out0
|
||||
218 pll_d
|
||||
219 pll_d_out0
|
||||
220 pll_d2
|
||||
221 pll_d2_out0
|
||||
222 pll_u
|
||||
223 pll_u_480M
|
||||
224 pll_u_60M
|
||||
225 pll_u_48M
|
||||
226 pll_u_12M
|
||||
227 pll_x
|
||||
228 pll_x_out0
|
||||
229 pll_re_vco
|
||||
230 pll_re_out
|
||||
231 pll_e_out0
|
||||
232 spdif_in_sync
|
||||
233 i2s0_sync
|
||||
234 i2s1_sync
|
||||
235 i2s2_sync
|
||||
236 i2s3_sync
|
||||
237 i2s4_sync
|
||||
238 vimclk_sync
|
||||
239 audio0
|
||||
240 audio1
|
||||
241 audio2
|
||||
242 audio3
|
||||
243 audio4
|
||||
244 spdif
|
||||
245 clk_out_1
|
||||
246 clk_out_2
|
||||
247 clk_out_3
|
||||
248 blink
|
||||
252 xusb_host_src
|
||||
253 xusb_falcon_src
|
||||
254 xusb_fs_src
|
||||
255 xusb_ss_src
|
||||
256 xusb_dev_src
|
||||
257 xusb_dev
|
||||
258 xusb_hs_src
|
||||
259 sclk
|
||||
260 hclk
|
||||
261 pclk
|
||||
262 cclk_g
|
||||
263 cclk_lp
|
||||
264 dfll_ref
|
||||
265 dfll_soc
|
||||
|
||||
Example SoC include file:
|
||||
|
||||
/ {
|
||||
tegra_car: clock {
|
||||
compatible = "nvidia,tegra114-car";
|
||||
reg = <0x60006000 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
usb@c5004000 {
|
||||
clocks = <&tegra_car 58>; /* usb2 */
|
||||
};
|
||||
};
|
||||
|
||||
Example board file:
|
||||
|
||||
/ {
|
||||
clocks {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
osc: clock@0 {
|
||||
compatible = "fixed-clock";
|
||||
reg = <0>;
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <12000000>;
|
||||
};
|
||||
|
||||
clk_32k: clock@1 {
|
||||
compatible = "fixed-clock";
|
||||
reg = <1>;
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <32768>;
|
||||
};
|
||||
};
|
||||
|
||||
&tegra_car {
|
||||
clocks = <&clk_32k> <&osc>;
|
||||
};
|
||||
};
|
|
@ -120,8 +120,8 @@ Required properties :
|
|||
90 clk_d
|
||||
91 unassigned
|
||||
92 sus
|
||||
93 cdev1
|
||||
94 cdev2
|
||||
93 cdev2
|
||||
94 cdev1
|
||||
95 unassigned
|
||||
|
||||
96 uart2
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
Device Tree Clock bindings for arch-sunxi
|
||||
|
||||
This binding uses the common clock binding[1].
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
||||
Required properties:
|
||||
- compatible : shall be one of the following:
|
||||
"allwinner,sun4i-osc-clk" - for a gatable oscillator
|
||||
"allwinner,sun4i-pll1-clk" - for the main PLL clock
|
||||
"allwinner,sun4i-cpu-clk" - for the CPU multiplexer clock
|
||||
"allwinner,sun4i-axi-clk" - for the AXI clock
|
||||
"allwinner,sun4i-ahb-clk" - for the AHB clock
|
||||
"allwinner,sun4i-apb0-clk" - for the APB0 clock
|
||||
"allwinner,sun4i-apb1-clk" - for the APB1 clock
|
||||
"allwinner,sun4i-apb1-mux-clk" - for the APB1 clock muxing
|
||||
|
||||
Required properties for all clocks:
|
||||
- reg : shall be the control register address for the clock.
|
||||
- clocks : shall be the input parent clock(s) phandle for the clock
|
||||
- #clock-cells : from common clock binding; shall be set to 0.
|
||||
|
||||
For example:
|
||||
|
||||
osc24M: osc24M@01c20050 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-osc-clk";
|
||||
reg = <0x01c20050 0x4>;
|
||||
clocks = <&osc24M_fixed>;
|
||||
};
|
||||
|
||||
pll1: pll1@01c20000 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-pll1-clk";
|
||||
reg = <0x01c20000 0x4>;
|
||||
clocks = <&osc24M>;
|
||||
};
|
||||
|
||||
cpu: cpu@01c20054 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-cpu-clk";
|
||||
reg = <0x01c20054 0x4>;
|
||||
clocks = <&osc32k>, <&osc24M>, <&pll1>;
|
||||
};
|
|
@ -675,6 +675,7 @@ config ARCH_TEGRA
|
|||
select HAVE_CLK
|
||||
select HAVE_SMP
|
||||
select MIGHT_HAVE_CACHE_L2X0
|
||||
select SOC_BUS
|
||||
select SPARSE_IRQ
|
||||
select USE_OF
|
||||
help
|
||||
|
|
|
@ -12,10 +12,22 @@
|
|||
|
||||
serial@70006300 {
|
||||
status = "okay";
|
||||
clock-frequency = <408000000>;
|
||||
};
|
||||
|
||||
pmc {
|
||||
nvidia,invert-interrupt;
|
||||
};
|
||||
|
||||
clocks {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
clk32k_in: clock {
|
||||
compatible = "fixed-clock";
|
||||
reg=<0>;
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <32768>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -12,10 +12,22 @@
|
|||
|
||||
serial@70006300 {
|
||||
status = "okay";
|
||||
clock-frequency = <408000000>;
|
||||
};
|
||||
|
||||
pmc {
|
||||
nvidia,invert-interrupt;
|
||||
};
|
||||
|
||||
clocks {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
clk32k_in: clock {
|
||||
compatible = "fixed-clock";
|
||||
reg=<0>;
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <32768>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -24,10 +24,11 @@
|
|||
0 42 0x04
|
||||
0 121 0x04
|
||||
0 122 0x04>;
|
||||
clocks = <&tegra_car 5>;
|
||||
};
|
||||
|
||||
tegra_car: clock {
|
||||
compatible = "nvidia,tegra114-car, nvidia,tegra30-car";
|
||||
compatible = "nvidia,tegra114-car";
|
||||
reg = <0x60006000 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
@ -66,6 +67,7 @@
|
|||
reg-shift = <2>;
|
||||
interrupts = <0 36 0x04>;
|
||||
status = "disabled";
|
||||
clocks = <&tegra_car 6>;
|
||||
};
|
||||
|
||||
serial@70006040 {
|
||||
|
@ -74,6 +76,7 @@
|
|||
reg-shift = <2>;
|
||||
interrupts = <0 37 0x04>;
|
||||
status = "disabled";
|
||||
clocks = <&tegra_car 192>;
|
||||
};
|
||||
|
||||
serial@70006200 {
|
||||
|
@ -82,6 +85,7 @@
|
|||
reg-shift = <2>;
|
||||
interrupts = <0 46 0x04>;
|
||||
status = "disabled";
|
||||
clocks = <&tegra_car 55>;
|
||||
};
|
||||
|
||||
serial@70006300 {
|
||||
|
@ -90,17 +94,21 @@
|
|||
reg-shift = <2>;
|
||||
interrupts = <0 90 0x04>;
|
||||
status = "disabled";
|
||||
clocks = <&tegra_car 65>;
|
||||
};
|
||||
|
||||
rtc {
|
||||
compatible = "nvidia,tegra114-rtc", "nvidia,tegra20-rtc";
|
||||
reg = <0x7000e000 0x100>;
|
||||
interrupts = <0 2 0x04>;
|
||||
clocks = <&tegra_car 4>;
|
||||
};
|
||||
|
||||
pmc {
|
||||
compatible = "nvidia,tegra114-pmc", "nvidia,tegra30-pmc";
|
||||
compatible = "nvidia,tegra114-pmc";
|
||||
reg = <0x7000e400 0x400>;
|
||||
clocks = <&tegra_car 261>, <&clk32k_in>;
|
||||
clock-names = "pclk", "clk32k_in";
|
||||
};
|
||||
|
||||
iommu {
|
||||
|
|
|
@ -444,7 +444,20 @@
|
|||
};
|
||||
|
||||
sdhci@c8000600 {
|
||||
cd-gpios = <&gpio 23 0>; /* gpio PC7 */
|
||||
cd-gpios = <&gpio 23 1>; /* gpio PC7 */
|
||||
};
|
||||
|
||||
clocks {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
clk32k_in: clock {
|
||||
compatible = "fixed-clock";
|
||||
reg=<0>;
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <32768>;
|
||||
};
|
||||
};
|
||||
|
||||
sound {
|
||||
|
|
|
@ -437,7 +437,7 @@
|
|||
|
||||
sdhci@c8000200 {
|
||||
status = "okay";
|
||||
cd-gpios = <&gpio 69 0>; /* gpio PI5 */
|
||||
cd-gpios = <&gpio 69 1>; /* gpio PI5 */
|
||||
wp-gpios = <&gpio 57 0>; /* gpio PH1 */
|
||||
power-gpios = <&gpio 155 0>; /* gpio PT3 */
|
||||
bus-width = <4>;
|
||||
|
@ -445,12 +445,25 @@
|
|||
|
||||
sdhci@c8000600 {
|
||||
status = "okay";
|
||||
cd-gpios = <&gpio 58 0>; /* gpio PH2 */
|
||||
cd-gpios = <&gpio 58 1>; /* gpio PH2 */
|
||||
wp-gpios = <&gpio 59 0>; /* gpio PH3 */
|
||||
power-gpios = <&gpio 70 0>; /* gpio PI6 */
|
||||
bus-width = <8>;
|
||||
};
|
||||
|
||||
clocks {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
clk32k_in: clock {
|
||||
compatible = "fixed-clock";
|
||||
reg=<0>;
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <32768>;
|
||||
};
|
||||
};
|
||||
|
||||
kbc {
|
||||
status = "okay";
|
||||
nvidia,debounce-delay-ms = <2>;
|
||||
|
|
|
@ -436,7 +436,7 @@
|
|||
|
||||
sdhci@c8000000 {
|
||||
status = "okay";
|
||||
cd-gpios = <&gpio 173 0>; /* gpio PV5 */
|
||||
cd-gpios = <&gpio 173 1>; /* gpio PV5 */
|
||||
wp-gpios = <&gpio 57 0>; /* gpio PH1 */
|
||||
power-gpios = <&gpio 169 0>; /* gpio PV1 */
|
||||
bus-width = <4>;
|
||||
|
@ -447,6 +447,19 @@
|
|||
bus-width = <8>;
|
||||
};
|
||||
|
||||
clocks {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
clk32k_in: clock {
|
||||
compatible = "fixed-clock";
|
||||
reg=<0>;
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <32768>;
|
||||
};
|
||||
};
|
||||
|
||||
gpio-keys {
|
||||
compatible = "gpio-keys";
|
||||
|
||||
|
|
|
@ -584,7 +584,7 @@
|
|||
|
||||
sdhci@c8000400 {
|
||||
status = "okay";
|
||||
cd-gpios = <&gpio 69 0>; /* gpio PI5 */
|
||||
cd-gpios = <&gpio 69 1>; /* gpio PI5 */
|
||||
wp-gpios = <&gpio 57 0>; /* gpio PH1 */
|
||||
power-gpios = <&gpio 70 0>; /* gpio PI6 */
|
||||
bus-width = <4>;
|
||||
|
@ -595,6 +595,19 @@
|
|||
bus-width = <8>;
|
||||
};
|
||||
|
||||
clocks {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
clk32k_in: clock {
|
||||
compatible = "fixed-clock";
|
||||
reg=<0>;
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <32768>;
|
||||
};
|
||||
};
|
||||
|
||||
gpio-keys {
|
||||
compatible = "gpio-keys";
|
||||
|
||||
|
|
|
@ -465,12 +465,25 @@
|
|||
};
|
||||
|
||||
sdhci@c8000600 {
|
||||
cd-gpios = <&gpio 58 0>; /* gpio PH2 */
|
||||
cd-gpios = <&gpio 58 1>; /* gpio PH2 */
|
||||
wp-gpios = <&gpio 59 0>; /* gpio PH3 */
|
||||
bus-width = <4>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
clocks {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
clk32k_in: clock {
|
||||
compatible = "fixed-clock";
|
||||
reg=<0>;
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <32768>;
|
||||
};
|
||||
};
|
||||
|
||||
regulators {
|
||||
compatible = "simple-bus";
|
||||
|
||||
|
|
|
@ -325,11 +325,24 @@
|
|||
|
||||
sdhci@c8000600 {
|
||||
status = "okay";
|
||||
cd-gpios = <&gpio 121 0>; /* gpio PP1 */
|
||||
cd-gpios = <&gpio 121 1>; /* gpio PP1 */
|
||||
wp-gpios = <&gpio 122 0>; /* gpio PP2 */
|
||||
bus-width = <4>;
|
||||
};
|
||||
|
||||
clocks {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
clk32k_in: clock {
|
||||
compatible = "fixed-clock";
|
||||
reg=<0>;
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <32768>;
|
||||
};
|
||||
};
|
||||
|
||||
poweroff {
|
||||
compatible = "gpio-poweroff";
|
||||
gpios = <&gpio 191 1>; /* gpio PX7, active low */
|
||||
|
|
|
@ -520,7 +520,7 @@
|
|||
|
||||
sdhci@c8000400 {
|
||||
status = "okay";
|
||||
cd-gpios = <&gpio 69 0>; /* gpio PI5 */
|
||||
cd-gpios = <&gpio 69 1>; /* gpio PI5 */
|
||||
wp-gpios = <&gpio 57 0>; /* gpio PH1 */
|
||||
power-gpios = <&gpio 70 0>; /* gpio PI6 */
|
||||
bus-width = <4>;
|
||||
|
@ -531,6 +531,19 @@
|
|||
bus-width = <8>;
|
||||
};
|
||||
|
||||
clocks {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
clk32k_in: clock {
|
||||
compatible = "fixed-clock";
|
||||
reg=<0>;
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <32768>;
|
||||
};
|
||||
};
|
||||
|
||||
regulators {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
|
|
|
@ -510,6 +510,7 @@
|
|||
|
||||
sdhci@c8000400 {
|
||||
status = "okay";
|
||||
cd-gpios = <&gpio 69 1>; /* gpio PI5 */
|
||||
wp-gpios = <&gpio 173 0>; /* gpio PV5 */
|
||||
bus-width = <8>;
|
||||
};
|
||||
|
@ -519,6 +520,19 @@
|
|||
bus-width = <8>;
|
||||
};
|
||||
|
||||
clocks {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
clk32k_in: clock {
|
||||
compatible = "fixed-clock";
|
||||
reg=<0>;
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <32768>;
|
||||
};
|
||||
};
|
||||
|
||||
kbc {
|
||||
status = "okay";
|
||||
nvidia,debounce-delay-ms = <20>;
|
||||
|
|
|
@ -145,6 +145,7 @@
|
|||
0 1 0x04
|
||||
0 41 0x04
|
||||
0 42 0x04>;
|
||||
clocks = <&tegra_car 5>;
|
||||
};
|
||||
|
||||
tegra_car: clock {
|
||||
|
@ -304,6 +305,7 @@
|
|||
compatible = "nvidia,tegra20-rtc";
|
||||
reg = <0x7000e000 0x100>;
|
||||
interrupts = <0 2 0x04>;
|
||||
clocks = <&tegra_car 4>;
|
||||
};
|
||||
|
||||
i2c@7000c000 {
|
||||
|
@ -416,6 +418,8 @@
|
|||
pmc {
|
||||
compatible = "nvidia,tegra20-pmc";
|
||||
reg = <0x7000e400 0x400>;
|
||||
clocks = <&tegra_car 110>, <&clk32k_in>;
|
||||
clock-names = "pclk", "clk32k_in";
|
||||
};
|
||||
|
||||
memory-controller@7000f000 {
|
||||
|
|
|
@ -257,7 +257,7 @@
|
|||
|
||||
sdhci@78000000 {
|
||||
status = "okay";
|
||||
cd-gpios = <&gpio 69 0>; /* gpio PI5 */
|
||||
cd-gpios = <&gpio 69 1>; /* gpio PI5 */
|
||||
wp-gpios = <&gpio 155 0>; /* gpio PT3 */
|
||||
power-gpios = <&gpio 31 0>; /* gpio PD7 */
|
||||
bus-width = <4>;
|
||||
|
@ -268,6 +268,19 @@
|
|||
bus-width = <8>;
|
||||
};
|
||||
|
||||
clocks {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
clk32k_in: clock {
|
||||
compatible = "fixed-clock";
|
||||
reg=<0>;
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <32768>;
|
||||
};
|
||||
};
|
||||
|
||||
regulators {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
|
|
|
@ -311,7 +311,7 @@
|
|||
|
||||
sdhci@78000000 {
|
||||
status = "okay";
|
||||
cd-gpios = <&gpio 69 0>; /* gpio PI5 */
|
||||
cd-gpios = <&gpio 69 1>; /* gpio PI5 */
|
||||
wp-gpios = <&gpio 155 0>; /* gpio PT3 */
|
||||
power-gpios = <&gpio 31 0>; /* gpio PD7 */
|
||||
bus-width = <4>;
|
||||
|
@ -322,6 +322,19 @@
|
|||
bus-width = <8>;
|
||||
};
|
||||
|
||||
clocks {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
clk32k_in: clock {
|
||||
compatible = "fixed-clock";
|
||||
reg=<0>;
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <32768>;
|
||||
};
|
||||
};
|
||||
|
||||
regulators {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
|
|
|
@ -148,6 +148,7 @@
|
|||
0 42 0x04
|
||||
0 121 0x04
|
||||
0 122 0x04>;
|
||||
clocks = <&tegra_car 5>;
|
||||
};
|
||||
|
||||
tegra_car: clock {
|
||||
|
@ -291,6 +292,7 @@
|
|||
compatible = "nvidia,tegra30-rtc", "nvidia,tegra20-rtc";
|
||||
reg = <0x7000e000 0x100>;
|
||||
interrupts = <0 2 0x04>;
|
||||
clocks = <&tegra_car 4>;
|
||||
};
|
||||
|
||||
i2c@7000c000 {
|
||||
|
@ -423,8 +425,10 @@
|
|||
};
|
||||
|
||||
pmc {
|
||||
compatible = "nvidia,tegra20-pmc", "nvidia,tegra30-pmc";
|
||||
compatible = "nvidia,tegra30-pmc";
|
||||
reg = <0x7000e400 0x400>;
|
||||
clocks = <&tegra_car 218>, <&clk32k_in>;
|
||||
clock-names = "pclk", "clk32k_in";
|
||||
};
|
||||
|
||||
memory-controller {
|
||||
|
|
|
@ -169,7 +169,7 @@ struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
|
|||
|
||||
busy->mux.reg = reg;
|
||||
busy->mux.shift = shift;
|
||||
busy->mux.width = width;
|
||||
busy->mux.mask = BIT(width) - 1;
|
||||
busy->mux.lock = &imx_ccm_lock;
|
||||
busy->mux_ops = &clk_mux_ops;
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ obj-y += pm.o
|
|||
obj-y += reset.o
|
||||
obj-y += reset-handler.o
|
||||
obj-y += sleep.o
|
||||
obj-y += tegra.o
|
||||
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_speedo.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o
|
||||
|
@ -27,9 +28,7 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
|
|||
obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o
|
||||
obj-$(CONFIG_TEGRA_PCI) += pcie.o
|
||||
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += board-dt-tegra20.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += board-dt-tegra30.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_114_SOC) += board-dt-tegra114.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114_speedo.o
|
||||
ifeq ($(CONFIG_CPU_IDLE),y)
|
||||
obj-$(CONFIG_ARCH_TEGRA_114_SOC) += cpuidle-tegra114.o
|
||||
endif
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* NVIDIA Tegra114 device tree board support
|
||||
*
|
||||
* Copyright (C) 2013 NVIDIA Corporation
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/clocksource.h>
|
||||
|
||||
#include <asm/mach/arch.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "common.h"
|
||||
|
||||
static void __init tegra114_dt_init(void)
|
||||
{
|
||||
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
|
||||
}
|
||||
|
||||
static const char * const tegra114_dt_board_compat[] = {
|
||||
"nvidia,tegra114",
|
||||
NULL,
|
||||
};
|
||||
|
||||
DT_MACHINE_START(TEGRA114_DT, "NVIDIA Tegra114 (Flattened Device Tree)")
|
||||
.smp = smp_ops(tegra_smp_ops),
|
||||
.map_io = tegra_map_common_io,
|
||||
.init_early = tegra114_init_early,
|
||||
.init_irq = tegra_dt_init_irq,
|
||||
.init_time = clocksource_of_init,
|
||||
.init_machine = tegra114_dt_init,
|
||||
.init_late = tegra_init_late,
|
||||
.restart = tegra_assert_system_reset,
|
||||
.dt_compat = tegra114_dt_board_compat,
|
||||
MACHINE_END
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
* arch/arm/mach-tegra/board-dt-tegra30.c
|
||||
*
|
||||
* NVIDIA Tegra30 device tree board support
|
||||
*
|
||||
* Copyright (C) 2011 NVIDIA Corporation
|
||||
*
|
||||
* Derived from:
|
||||
*
|
||||
* arch/arm/mach-tegra/board-dt-tegra20.c
|
||||
*
|
||||
* Copyright (C) 2010 Secret Lab Technologies, Ltd.
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#include <asm/mach/arch.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "common.h"
|
||||
#include "iomap.h"
|
||||
|
||||
static void __init tegra30_dt_init(void)
|
||||
{
|
||||
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
|
||||
}
|
||||
|
||||
static const char *tegra30_dt_board_compat[] = {
|
||||
"nvidia,tegra30",
|
||||
NULL
|
||||
};
|
||||
|
||||
DT_MACHINE_START(TEGRA30_DT, "NVIDIA Tegra30 (Flattened Device Tree)")
|
||||
.smp = smp_ops(tegra_smp_ops),
|
||||
.map_io = tegra_map_common_io,
|
||||
.init_early = tegra30_init_early,
|
||||
.init_irq = tegra_dt_init_irq,
|
||||
.init_time = clocksource_of_init,
|
||||
.init_machine = tegra30_dt_init,
|
||||
.init_late = tegra_init_late,
|
||||
.restart = tegra_assert_system_reset,
|
||||
.dt_compat = tegra30_dt_board_compat,
|
||||
MACHINE_END
|
|
@ -62,7 +62,11 @@ int __init harmony_pcie_init(void)
|
|||
goto err_reg;
|
||||
}
|
||||
|
||||
regulator_enable(regulator);
|
||||
err = regulator_enable(regulator);
|
||||
if (err) {
|
||||
pr_err("%s: regulator_enable failed: %d\n", __func__, err);
|
||||
goto err_en;
|
||||
}
|
||||
|
||||
err = tegra_pcie_init(true, true);
|
||||
if (err) {
|
||||
|
@ -74,6 +78,7 @@ int __init harmony_pcie_init(void)
|
|||
|
||||
err_pcie:
|
||||
regulator_disable(regulator);
|
||||
err_en:
|
||||
regulator_put(regulator);
|
||||
err_reg:
|
||||
gpio_free(en_vdd_1v05);
|
||||
|
|
|
@ -26,9 +26,7 @@
|
|||
|
||||
void tegra_assert_system_reset(char mode, const char *cmd);
|
||||
|
||||
void __init tegra20_init_early(void);
|
||||
void __init tegra30_init_early(void);
|
||||
void __init tegra114_init_early(void);
|
||||
void __init tegra_init_early(void);
|
||||
void __init tegra_map_common_io(void);
|
||||
void __init tegra_init_irq(void);
|
||||
void __init tegra_dt_init_irq(void);
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "common.h"
|
||||
#include "fuse.h"
|
||||
#include "iomap.h"
|
||||
#include "irq.h"
|
||||
#include "pmc.h"
|
||||
#include "apbio.h"
|
||||
#include "sleep.h"
|
||||
|
@ -61,8 +62,10 @@ u32 tegra_uart_config[4] = {
|
|||
void __init tegra_dt_init_irq(void)
|
||||
{
|
||||
tegra_clocks_init();
|
||||
tegra_pmc_init();
|
||||
tegra_init_irq();
|
||||
irqchip_init();
|
||||
tegra_legacy_irq_syscore_init();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -94,40 +97,18 @@ static void __init tegra_init_cache(void)
|
|||
|
||||
}
|
||||
|
||||
static void __init tegra_init_early(void)
|
||||
void __init tegra_init_early(void)
|
||||
{
|
||||
tegra_cpu_reset_handler_init();
|
||||
tegra_apb_io_init();
|
||||
tegra_init_fuse();
|
||||
tegra_init_cache();
|
||||
tegra_pmc_init();
|
||||
tegra_powergate_init();
|
||||
tegra_hotplug_init();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||
void __init tegra20_init_early(void)
|
||||
{
|
||||
tegra_init_early();
|
||||
tegra20_hotplug_init();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
|
||||
void __init tegra30_init_early(void)
|
||||
{
|
||||
tegra_init_early();
|
||||
tegra30_hotplug_init();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_114_SOC
|
||||
void __init tegra114_init_early(void)
|
||||
{
|
||||
tegra_init_early();
|
||||
}
|
||||
#endif
|
||||
|
||||
void __init tegra_init_late(void)
|
||||
{
|
||||
tegra_init_suspend();
|
||||
tegra_powergate_debugfs_init();
|
||||
}
|
||||
|
|
|
@ -130,10 +130,6 @@ static bool tegra20_cpu_cluster_power_down(struct cpuidle_device *dev,
|
|||
struct cpuidle_driver *drv,
|
||||
int index)
|
||||
{
|
||||
struct cpuidle_state *state = &drv->states[index];
|
||||
u32 cpu_on_time = state->exit_latency;
|
||||
u32 cpu_off_time = state->target_residency - state->exit_latency;
|
||||
|
||||
while (tegra20_cpu_is_resettable_soon())
|
||||
cpu_relax();
|
||||
|
||||
|
@ -142,7 +138,7 @@ static bool tegra20_cpu_cluster_power_down(struct cpuidle_device *dev,
|
|||
|
||||
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
|
||||
|
||||
tegra_idle_lp2_last(cpu_on_time, cpu_off_time);
|
||||
tegra_idle_lp2_last();
|
||||
|
||||
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
|
||||
|
||||
|
|
|
@ -72,10 +72,6 @@ static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev,
|
|||
struct cpuidle_driver *drv,
|
||||
int index)
|
||||
{
|
||||
struct cpuidle_state *state = &drv->states[index];
|
||||
u32 cpu_on_time = state->exit_latency;
|
||||
u32 cpu_off_time = state->target_residency - state->exit_latency;
|
||||
|
||||
/* All CPUs entering LP2 is not working.
|
||||
* Don't let CPU0 enter LP2 when any secondary CPU is online.
|
||||
*/
|
||||
|
@ -86,7 +82,7 @@ static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev,
|
|||
|
||||
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
|
||||
|
||||
tegra_idle_lp2_last(cpu_on_time, cpu_off_time);
|
||||
tegra_idle_lp2_last();
|
||||
|
||||
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
|
||||
|
||||
|
@ -102,12 +98,8 @@ static bool tegra30_cpu_core_power_down(struct cpuidle_device *dev,
|
|||
|
||||
smp_wmb();
|
||||
|
||||
save_cpu_arch_register();
|
||||
|
||||
cpu_suspend(0, tegra30_sleep_cpu_secondary_finish);
|
||||
|
||||
restore_cpu_arch_register();
|
||||
|
||||
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
|
||||
|
||||
return true;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* arch/arm/mach-tegra/fuse.c
|
||||
*
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Colin Cross <ccross@android.com>
|
||||
|
@ -137,6 +138,9 @@ void tegra_init_fuse(void)
|
|||
tegra_fuse_spare_bit = TEGRA30_FUSE_SPARE_BIT;
|
||||
tegra_init_speedo_data = &tegra30_init_speedo_data;
|
||||
break;
|
||||
case TEGRA114:
|
||||
tegra_init_speedo_data = &tegra114_init_speedo_data;
|
||||
break;
|
||||
default:
|
||||
pr_warn("Tegra: unknown chip id %d\n", tegra_chip_id);
|
||||
tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Colin Cross <ccross@android.com>
|
||||
|
@ -66,4 +67,10 @@ void tegra30_init_speedo_data(void);
|
|||
static inline void tegra30_init_speedo_data(void) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_114_SOC
|
||||
void tegra114_init_speedo_data(void);
|
||||
#else
|
||||
static inline void tegra114_init_speedo_data(void) {}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,8 +7,5 @@
|
|||
|
||||
ENTRY(tegra_secondary_startup)
|
||||
bl v7_invalidate_l1
|
||||
/* Enable coresight */
|
||||
mov32 r0, 0xC5ACCE55
|
||||
mcr p14, 0, r0, c7, c12, 6
|
||||
b secondary_startup
|
||||
ENDPROC(tegra_secondary_startup)
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (C) 2002 ARM Ltd.
|
||||
* All Rights Reserved
|
||||
* Copyright (c) 2010, 2012 NVIDIA Corporation. All rights reserved.
|
||||
* Copyright (c) 2010, 2012-2013, NVIDIA Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -15,6 +14,7 @@
|
|||
#include <asm/cacheflush.h>
|
||||
#include <asm/smp_plat.h>
|
||||
|
||||
#include "fuse.h"
|
||||
#include "sleep.h"
|
||||
|
||||
static void (*tegra_hotplug_shutdown)(void);
|
||||
|
@ -56,18 +56,13 @@ int tegra_cpu_disable(unsigned int cpu)
|
|||
return cpu == 0 ? -EPERM : 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||
extern void tegra20_hotplug_shutdown(void);
|
||||
void __init tegra20_hotplug_init(void)
|
||||
void __init tegra_hotplug_init(void)
|
||||
{
|
||||
tegra_hotplug_shutdown = tegra20_hotplug_shutdown;
|
||||
}
|
||||
#endif
|
||||
if (!IS_ENABLED(CONFIG_HOTPLUG_CPU))
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
|
||||
extern void tegra30_hotplug_shutdown(void);
|
||||
void __init tegra30_hotplug_init(void)
|
||||
{
|
||||
tegra_hotplug_shutdown = tegra30_hotplug_shutdown;
|
||||
if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_chip_id == TEGRA20)
|
||||
tegra_hotplug_shutdown = tegra20_hotplug_shutdown;
|
||||
if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_chip_id == TEGRA30)
|
||||
tegra_hotplug_shutdown = tegra30_hotplug_shutdown;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* Author:
|
||||
* Colin Cross <ccross@android.com>
|
||||
*
|
||||
* Copyright (C) 2010, NVIDIA Corporation
|
||||
* Copyright (C) 2010,2013, NVIDIA Corporation
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
|
@ -23,6 +23,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/irqchip/arm-gic.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "iomap.h"
|
||||
|
@ -43,6 +44,7 @@
|
|||
#define ICTLR_COP_IEP_CLASS 0x3c
|
||||
|
||||
#define FIRST_LEGACY_IRQ 32
|
||||
#define TEGRA_MAX_NUM_ICTLRS 5
|
||||
|
||||
#define SGI_MASK 0xFFFF
|
||||
|
||||
|
@ -56,6 +58,15 @@ static void __iomem *ictlr_reg_base[] = {
|
|||
IO_ADDRESS(TEGRA_QUINARY_ICTLR_BASE),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static u32 cop_ier[TEGRA_MAX_NUM_ICTLRS];
|
||||
static u32 cop_iep[TEGRA_MAX_NUM_ICTLRS];
|
||||
static u32 cpu_ier[TEGRA_MAX_NUM_ICTLRS];
|
||||
static u32 cpu_iep[TEGRA_MAX_NUM_ICTLRS];
|
||||
|
||||
static u32 ictlr_wake_mask[TEGRA_MAX_NUM_ICTLRS];
|
||||
#endif
|
||||
|
||||
bool tegra_pending_sgi(void)
|
||||
{
|
||||
u32 pending_set;
|
||||
|
@ -125,6 +136,87 @@ static int tegra_retrigger(struct irq_data *d)
|
|||
return 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int tegra_set_wake(struct irq_data *d, unsigned int enable)
|
||||
{
|
||||
u32 irq = d->irq;
|
||||
u32 index, mask;
|
||||
|
||||
if (irq < FIRST_LEGACY_IRQ ||
|
||||
irq >= FIRST_LEGACY_IRQ + num_ictlrs * 32)
|
||||
return -EINVAL;
|
||||
|
||||
index = ((irq - FIRST_LEGACY_IRQ) / 32);
|
||||
mask = BIT((irq - FIRST_LEGACY_IRQ) % 32);
|
||||
if (enable)
|
||||
ictlr_wake_mask[index] |= mask;
|
||||
else
|
||||
ictlr_wake_mask[index] &= ~mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_legacy_irq_suspend(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
local_irq_save(flags);
|
||||
for (i = 0; i < num_ictlrs; i++) {
|
||||
void __iomem *ictlr = ictlr_reg_base[i];
|
||||
/* Save interrupt state */
|
||||
cpu_ier[i] = readl_relaxed(ictlr + ICTLR_CPU_IER);
|
||||
cpu_iep[i] = readl_relaxed(ictlr + ICTLR_CPU_IEP_CLASS);
|
||||
cop_ier[i] = readl_relaxed(ictlr + ICTLR_COP_IER);
|
||||
cop_iep[i] = readl_relaxed(ictlr + ICTLR_COP_IEP_CLASS);
|
||||
|
||||
/* Disable COP interrupts */
|
||||
writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
|
||||
|
||||
/* Disable CPU interrupts */
|
||||
writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR);
|
||||
|
||||
/* Enable the wakeup sources of ictlr */
|
||||
writel_relaxed(ictlr_wake_mask[i], ictlr + ICTLR_CPU_IER_SET);
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_legacy_irq_resume(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
local_irq_save(flags);
|
||||
for (i = 0; i < num_ictlrs; i++) {
|
||||
void __iomem *ictlr = ictlr_reg_base[i];
|
||||
writel_relaxed(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS);
|
||||
writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR);
|
||||
writel_relaxed(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET);
|
||||
writel_relaxed(cop_iep[i], ictlr + ICTLR_COP_IEP_CLASS);
|
||||
writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
|
||||
writel_relaxed(cop_ier[i], ictlr + ICTLR_COP_IER_SET);
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static struct syscore_ops tegra_legacy_irq_syscore_ops = {
|
||||
.suspend = tegra_legacy_irq_suspend,
|
||||
.resume = tegra_legacy_irq_resume,
|
||||
};
|
||||
|
||||
int tegra_legacy_irq_syscore_init(void)
|
||||
{
|
||||
register_syscore_ops(&tegra_legacy_irq_syscore_ops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define tegra_set_wake NULL
|
||||
#endif
|
||||
|
||||
void __init tegra_init_irq(void)
|
||||
{
|
||||
int i;
|
||||
|
@ -150,6 +242,8 @@ void __init tegra_init_irq(void)
|
|||
gic_arch_extn.irq_mask = tegra_mask;
|
||||
gic_arch_extn.irq_unmask = tegra_unmask;
|
||||
gic_arch_extn.irq_retrigger = tegra_retrigger;
|
||||
gic_arch_extn.irq_set_wake = tegra_set_wake;
|
||||
gic_arch_extn.flags = IRQCHIP_MASK_ON_SUSPEND;
|
||||
|
||||
/*
|
||||
* Check if there is a devicetree present, since the GIC will be
|
||||
|
|
|
@ -19,4 +19,10 @@
|
|||
|
||||
bool tegra_pending_sgi(void);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
int tegra_legacy_irq_syscore_init(void);
|
||||
#else
|
||||
static inline int tegra_legacy_irq_syscore_init(void) { return 0; }
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,22 +26,16 @@
|
|||
#include <asm/smp_scu.h>
|
||||
#include <asm/smp_plat.h>
|
||||
|
||||
#include <mach/powergate.h>
|
||||
|
||||
#include "fuse.h"
|
||||
#include "flowctrl.h"
|
||||
#include "reset.h"
|
||||
#include "pmc.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "iomap.h"
|
||||
|
||||
extern void tegra_secondary_startup(void);
|
||||
|
||||
static cpumask_t tegra_cpu_init_mask;
|
||||
|
||||
#define EVP_CPU_RESET_VECTOR \
|
||||
(IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100)
|
||||
|
||||
static void __cpuinit tegra_secondary_init(unsigned int cpu)
|
||||
{
|
||||
/*
|
||||
|
@ -54,25 +48,43 @@ static void __cpuinit tegra_secondary_init(unsigned int cpu)
|
|||
cpumask_set_cpu(cpu, &tegra_cpu_init_mask);
|
||||
}
|
||||
|
||||
static int tegra20_power_up_cpu(unsigned int cpu)
|
||||
|
||||
static int tegra20_boot_secondary(unsigned int cpu, struct task_struct *idle)
|
||||
{
|
||||
/* Enable the CPU clock. */
|
||||
cpu = cpu_logical_map(cpu);
|
||||
|
||||
/*
|
||||
* Force the CPU into reset. The CPU must remain in reset when
|
||||
* the flow controller state is cleared (which will cause the
|
||||
* flow controller to stop driving reset if the CPU has been
|
||||
* power-gated via the flow controller). This will have no
|
||||
* effect on first boot of the CPU since it should already be
|
||||
* in reset.
|
||||
*/
|
||||
tegra_put_cpu_in_reset(cpu);
|
||||
|
||||
/*
|
||||
* Unhalt the CPU. If the flow controller was used to
|
||||
* power-gate the CPU this will cause the flow controller to
|
||||
* stop driving reset. The CPU will remain in reset because the
|
||||
* clock and reset block is now driving reset.
|
||||
*/
|
||||
flowctrl_write_cpu_halt(cpu, 0);
|
||||
|
||||
tegra_enable_cpu_clock(cpu);
|
||||
|
||||
/* Clear flow controller CSR. */
|
||||
flowctrl_write_cpu_csr(cpu, 0);
|
||||
|
||||
flowctrl_write_cpu_csr(cpu, 0); /* Clear flow controller CSR. */
|
||||
tegra_cpu_out_of_reset(cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra30_power_up_cpu(unsigned int cpu)
|
||||
static int tegra30_boot_secondary(unsigned int cpu, struct task_struct *idle)
|
||||
{
|
||||
int ret, pwrgateid;
|
||||
int ret;
|
||||
unsigned long timeout;
|
||||
|
||||
pwrgateid = tegra_cpu_powergate_id(cpu);
|
||||
if (pwrgateid < 0)
|
||||
return pwrgateid;
|
||||
cpu = cpu_logical_map(cpu);
|
||||
tegra_put_cpu_in_reset(cpu);
|
||||
flowctrl_write_cpu_halt(cpu, 0);
|
||||
|
||||
/*
|
||||
* The power up sequence of cold boot CPU and warm boot CPU
|
||||
|
@ -85,13 +97,13 @@ static int tegra30_power_up_cpu(unsigned int cpu)
|
|||
* the IO clamps.
|
||||
* For cold boot CPU, do not wait. After the cold boot CPU be
|
||||
* booted, it will run to tegra_secondary_init() and set
|
||||
* tegra_cpu_init_mask which influences what tegra30_power_up_cpu()
|
||||
* tegra_cpu_init_mask which influences what tegra30_boot_secondary()
|
||||
* next time around.
|
||||
*/
|
||||
if (cpumask_test_cpu(cpu, &tegra_cpu_init_mask)) {
|
||||
timeout = jiffies + msecs_to_jiffies(50);
|
||||
do {
|
||||
if (!tegra_powergate_is_powered(pwrgateid))
|
||||
if (tegra_pmc_cpu_is_powered(cpu))
|
||||
goto remove_clamps;
|
||||
udelay(10);
|
||||
} while (time_before(jiffies, timeout));
|
||||
|
@ -103,14 +115,14 @@ static int tegra30_power_up_cpu(unsigned int cpu)
|
|||
* be un-gated by un-toggling the power gate register
|
||||
* manually.
|
||||
*/
|
||||
if (!tegra_powergate_is_powered(pwrgateid)) {
|
||||
ret = tegra_powergate_power_on(pwrgateid);
|
||||
if (!tegra_pmc_cpu_is_powered(cpu)) {
|
||||
ret = tegra_pmc_cpu_power_on(cpu);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Wait for the power to come up. */
|
||||
timeout = jiffies + msecs_to_jiffies(100);
|
||||
while (tegra_powergate_is_powered(pwrgateid)) {
|
||||
while (tegra_pmc_cpu_is_powered(cpu)) {
|
||||
if (time_after(jiffies, timeout))
|
||||
return -ETIMEDOUT;
|
||||
udelay(10);
|
||||
|
@ -123,57 +135,34 @@ remove_clamps:
|
|||
udelay(10);
|
||||
|
||||
/* Remove I/O clamps. */
|
||||
ret = tegra_powergate_remove_clamping(pwrgateid);
|
||||
ret = tegra_pmc_cpu_remove_clamping(cpu);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
udelay(10);
|
||||
|
||||
/* Clear flow controller CSR. */
|
||||
flowctrl_write_cpu_csr(cpu, 0);
|
||||
|
||||
flowctrl_write_cpu_csr(cpu, 0); /* Clear flow controller CSR. */
|
||||
tegra_cpu_out_of_reset(cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __cpuinit tegra_boot_secondary(unsigned int cpu, struct task_struct *idle)
|
||||
static int tegra114_boot_secondary(unsigned int cpu, struct task_struct *idle)
|
||||
{
|
||||
int status;
|
||||
|
||||
cpu = cpu_logical_map(cpu);
|
||||
return tegra_pmc_cpu_power_on(cpu);
|
||||
}
|
||||
|
||||
/*
|
||||
* Force the CPU into reset. The CPU must remain in reset when the
|
||||
* flow controller state is cleared (which will cause the flow
|
||||
* controller to stop driving reset if the CPU has been power-gated
|
||||
* via the flow controller). This will have no effect on first boot
|
||||
* of the CPU since it should already be in reset.
|
||||
*/
|
||||
tegra_put_cpu_in_reset(cpu);
|
||||
static int __cpuinit tegra_boot_secondary(unsigned int cpu,
|
||||
struct task_struct *idle)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_chip_id == TEGRA20)
|
||||
return tegra20_boot_secondary(cpu, idle);
|
||||
if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_chip_id == TEGRA30)
|
||||
return tegra30_boot_secondary(cpu, idle);
|
||||
if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_chip_id == TEGRA114)
|
||||
return tegra114_boot_secondary(cpu, idle);
|
||||
|
||||
/*
|
||||
* Unhalt the CPU. If the flow controller was used to power-gate the
|
||||
* CPU this will cause the flow controller to stop driving reset.
|
||||
* The CPU will remain in reset because the clock and reset block
|
||||
* is now driving reset.
|
||||
*/
|
||||
flowctrl_write_cpu_halt(cpu, 0);
|
||||
|
||||
switch (tegra_chip_id) {
|
||||
case TEGRA20:
|
||||
status = tegra20_power_up_cpu(cpu);
|
||||
break;
|
||||
case TEGRA30:
|
||||
status = tegra30_power_up_cpu(cpu);
|
||||
break;
|
||||
default:
|
||||
status = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (status)
|
||||
goto done;
|
||||
|
||||
/* Take the CPU out of reset. */
|
||||
tegra_cpu_out_of_reset(cpu);
|
||||
done:
|
||||
return status;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void __init tegra_smp_prepare_cpus(unsigned int max_cpus)
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include <linux/cpumask.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/cpu_pm.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
|
||||
|
@ -37,67 +37,14 @@
|
|||
#include "reset.h"
|
||||
#include "flowctrl.h"
|
||||
#include "fuse.h"
|
||||
#include "pmc.h"
|
||||
#include "sleep.h"
|
||||
|
||||
#define TEGRA_POWER_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */
|
||||
|
||||
#define PMC_CTRL 0x0
|
||||
#define PMC_CPUPWRGOOD_TIMER 0xc8
|
||||
#define PMC_CPUPWROFF_TIMER 0xcc
|
||||
#include "pmc.h"
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static unsigned int g_diag_reg;
|
||||
static DEFINE_SPINLOCK(tegra_lp2_lock);
|
||||
static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
|
||||
static struct clk *tegra_pclk;
|
||||
void (*tegra_tear_down_cpu)(void);
|
||||
|
||||
void save_cpu_arch_register(void)
|
||||
{
|
||||
/* read diagnostic register */
|
||||
asm("mrc p15, 0, %0, c15, c0, 1" : "=r"(g_diag_reg) : : "cc");
|
||||
return;
|
||||
}
|
||||
|
||||
void restore_cpu_arch_register(void)
|
||||
{
|
||||
/* write diagnostic register */
|
||||
asm("mcr p15, 0, %0, c15, c0, 1" : : "r"(g_diag_reg) : "cc");
|
||||
return;
|
||||
}
|
||||
|
||||
static void set_power_timers(unsigned long us_on, unsigned long us_off)
|
||||
{
|
||||
unsigned long long ticks;
|
||||
unsigned long long pclk;
|
||||
unsigned long rate;
|
||||
static unsigned long tegra_last_pclk;
|
||||
|
||||
if (tegra_pclk == NULL) {
|
||||
tegra_pclk = clk_get_sys(NULL, "pclk");
|
||||
WARN_ON(IS_ERR(tegra_pclk));
|
||||
}
|
||||
|
||||
rate = clk_get_rate(tegra_pclk);
|
||||
|
||||
if (WARN_ON_ONCE(rate <= 0))
|
||||
pclk = 100000000;
|
||||
else
|
||||
pclk = rate;
|
||||
|
||||
if ((rate != tegra_last_pclk)) {
|
||||
ticks = (us_on * pclk) + 999999ull;
|
||||
do_div(ticks, 1000000);
|
||||
writel((unsigned long)ticks, pmc + PMC_CPUPWRGOOD_TIMER);
|
||||
|
||||
ticks = (us_off * pclk) + 999999ull;
|
||||
do_div(ticks, 1000000);
|
||||
writel((unsigned long)ticks, pmc + PMC_CPUPWROFF_TIMER);
|
||||
wmb();
|
||||
}
|
||||
tegra_last_pclk = pclk;
|
||||
}
|
||||
|
||||
/*
|
||||
* restore_cpu_complex
|
||||
*
|
||||
|
@ -119,8 +66,6 @@ static void restore_cpu_complex(void)
|
|||
tegra_cpu_clock_resume();
|
||||
|
||||
flowctrl_cpu_suspend_exit(cpu);
|
||||
|
||||
restore_cpu_arch_register();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -145,8 +90,6 @@ static void suspend_cpu_complex(void)
|
|||
tegra_cpu_clock_suspend();
|
||||
|
||||
flowctrl_cpu_suspend_enter(cpu);
|
||||
|
||||
save_cpu_arch_register();
|
||||
}
|
||||
|
||||
void tegra_clear_cpu_in_lp2(int phy_cpu_id)
|
||||
|
@ -197,16 +140,9 @@ static int tegra_sleep_cpu(unsigned long v2p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void tegra_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time)
|
||||
void tegra_idle_lp2_last(void)
|
||||
{
|
||||
u32 mode;
|
||||
|
||||
/* Only the last cpu down does the final suspend steps */
|
||||
mode = readl(pmc + PMC_CTRL);
|
||||
mode |= TEGRA_POWER_CPU_PWRREQ_OE;
|
||||
writel(mode, pmc + PMC_CTRL);
|
||||
|
||||
set_power_timers(cpu_on_time, cpu_off_time);
|
||||
tegra_pmc_pm_set(TEGRA_SUSPEND_LP2);
|
||||
|
||||
cpu_cluster_pm_enter();
|
||||
suspend_cpu_complex();
|
||||
|
@ -216,4 +152,81 @@ void tegra_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time)
|
|||
restore_cpu_complex();
|
||||
cpu_cluster_pm_exit();
|
||||
}
|
||||
|
||||
enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
|
||||
enum tegra_suspend_mode mode)
|
||||
{
|
||||
/* Tegra114 didn't support any suspending mode yet. */
|
||||
if (tegra_chip_id == TEGRA114)
|
||||
return TEGRA_SUSPEND_NONE;
|
||||
|
||||
/*
|
||||
* The Tegra devices only support suspending to LP2 currently.
|
||||
*/
|
||||
if (mode > TEGRA_SUSPEND_LP2)
|
||||
return TEGRA_SUSPEND_LP2;
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
static const char *lp_state[TEGRA_MAX_SUSPEND_MODE] = {
|
||||
[TEGRA_SUSPEND_NONE] = "none",
|
||||
[TEGRA_SUSPEND_LP2] = "LP2",
|
||||
[TEGRA_SUSPEND_LP1] = "LP1",
|
||||
[TEGRA_SUSPEND_LP0] = "LP0",
|
||||
};
|
||||
|
||||
static int __cpuinit tegra_suspend_enter(suspend_state_t state)
|
||||
{
|
||||
enum tegra_suspend_mode mode = tegra_pmc_get_suspend_mode();
|
||||
|
||||
if (WARN_ON(mode < TEGRA_SUSPEND_NONE ||
|
||||
mode >= TEGRA_MAX_SUSPEND_MODE))
|
||||
return -EINVAL;
|
||||
|
||||
pr_info("Entering suspend state %s\n", lp_state[mode]);
|
||||
|
||||
tegra_pmc_pm_set(mode);
|
||||
|
||||
local_fiq_disable();
|
||||
|
||||
suspend_cpu_complex();
|
||||
switch (mode) {
|
||||
case TEGRA_SUSPEND_LP2:
|
||||
tegra_set_cpu_in_lp2(0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
|
||||
|
||||
switch (mode) {
|
||||
case TEGRA_SUSPEND_LP2:
|
||||
tegra_clear_cpu_in_lp2(0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
restore_cpu_complex();
|
||||
|
||||
local_fiq_enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_suspend_ops tegra_suspend_ops = {
|
||||
.valid = suspend_valid_only_mem,
|
||||
.enter = tegra_suspend_enter,
|
||||
};
|
||||
|
||||
void __init tegra_init_suspend(void)
|
||||
{
|
||||
if (tegra_pmc_get_suspend_mode() == TEGRA_SUSPEND_NONE)
|
||||
return;
|
||||
|
||||
tegra_pmc_suspend_init();
|
||||
|
||||
suspend_set_ops(&tegra_suspend_ops);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#ifndef _MACH_TEGRA_PM_H_
|
||||
#define _MACH_TEGRA_PM_H_
|
||||
|
||||
#include "pmc.h"
|
||||
|
||||
extern unsigned long l2x0_saved_regs_addr;
|
||||
|
||||
void save_cpu_arch_register(void);
|
||||
|
@ -29,7 +31,20 @@ void restore_cpu_arch_register(void);
|
|||
void tegra_clear_cpu_in_lp2(int phy_cpu_id);
|
||||
bool tegra_set_cpu_in_lp2(int phy_cpu_id);
|
||||
|
||||
void tegra_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time);
|
||||
void tegra_idle_lp2_last(void);
|
||||
extern void (*tegra_tear_down_cpu)(void);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
|
||||
enum tegra_suspend_mode mode);
|
||||
void tegra_init_suspend(void);
|
||||
#else
|
||||
enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
|
||||
enum tegra_suspend_mode mode)
|
||||
{
|
||||
return TEGRA_SUSPEND_NONE;
|
||||
}
|
||||
static inline void tegra_init_suspend(void) {}
|
||||
#endif
|
||||
|
||||
#endif /* _MACH_TEGRA_PM_H_ */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (C) 2012,2013 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
@ -16,59 +16,313 @@
|
|||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
|
||||
#include "iomap.h"
|
||||
#include "fuse.h"
|
||||
#include "pm.h"
|
||||
#include "pmc.h"
|
||||
#include "sleep.h"
|
||||
|
||||
#define PMC_CTRL 0x0
|
||||
#define PMC_CTRL_INTR_LOW (1 << 17)
|
||||
#define TEGRA_POWER_EFFECT_LP0 (1 << 14) /* LP0 when CPU pwr gated */
|
||||
#define TEGRA_POWER_CPU_PWRREQ_POLARITY (1 << 15) /* CPU pwr req polarity */
|
||||
#define TEGRA_POWER_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */
|
||||
|
||||
#define PMC_CTRL 0x0
|
||||
#define PMC_CTRL_INTR_LOW (1 << 17)
|
||||
#define PMC_PWRGATE_TOGGLE 0x30
|
||||
#define PMC_PWRGATE_TOGGLE_START (1 << 8)
|
||||
#define PMC_REMOVE_CLAMPING 0x34
|
||||
#define PMC_PWRGATE_STATUS 0x38
|
||||
|
||||
#define PMC_CPUPWRGOOD_TIMER 0xc8
|
||||
#define PMC_CPUPWROFF_TIMER 0xcc
|
||||
|
||||
#define TEGRA_POWERGATE_PCIE 3
|
||||
#define TEGRA_POWERGATE_VDEC 4
|
||||
#define TEGRA_POWERGATE_CPU1 9
|
||||
#define TEGRA_POWERGATE_CPU2 10
|
||||
#define TEGRA_POWERGATE_CPU3 11
|
||||
|
||||
static u8 tegra_cpu_domains[] = {
|
||||
0xFF, /* not available for CPU0 */
|
||||
TEGRA_POWERGATE_CPU1,
|
||||
TEGRA_POWERGATE_CPU2,
|
||||
TEGRA_POWERGATE_CPU3,
|
||||
};
|
||||
static DEFINE_SPINLOCK(tegra_powergate_lock);
|
||||
|
||||
static void __iomem *tegra_pmc_base;
|
||||
static bool tegra_pmc_invert_interrupt;
|
||||
static struct clk *tegra_pclk;
|
||||
|
||||
struct pmc_pm_data {
|
||||
u32 cpu_good_time; /* CPU power good time in uS */
|
||||
u32 cpu_off_time; /* CPU power off time in uS */
|
||||
u32 core_osc_time; /* Core power good osc time in uS */
|
||||
u32 core_pmu_time; /* Core power good pmu time in uS */
|
||||
u32 core_off_time; /* Core power off time in uS */
|
||||
bool corereq_high; /* Core power request active-high */
|
||||
bool sysclkreq_high; /* System clock request active-high */
|
||||
bool combined_req; /* Combined pwr req for CPU & Core */
|
||||
bool cpu_pwr_good_en; /* CPU power good signal is enabled */
|
||||
u32 lp0_vec_phy_addr; /* The phy addr of LP0 warm boot code */
|
||||
u32 lp0_vec_size; /* The size of LP0 warm boot code */
|
||||
enum tegra_suspend_mode suspend_mode;
|
||||
};
|
||||
static struct pmc_pm_data pmc_pm_data;
|
||||
|
||||
static inline u32 tegra_pmc_readl(u32 reg)
|
||||
{
|
||||
return readl(IO_ADDRESS(TEGRA_PMC_BASE + reg));
|
||||
return readl(tegra_pmc_base + reg);
|
||||
}
|
||||
|
||||
static inline void tegra_pmc_writel(u32 val, u32 reg)
|
||||
{
|
||||
writel(val, IO_ADDRESS(TEGRA_PMC_BASE + reg));
|
||||
writel(val, tegra_pmc_base + reg);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int tegra_pmc_get_cpu_powerdomain_id(int cpuid)
|
||||
{
|
||||
if (cpuid <= 0 || cpuid >= num_possible_cpus())
|
||||
return -EINVAL;
|
||||
return tegra_cpu_domains[cpuid];
|
||||
}
|
||||
|
||||
static bool tegra_pmc_powergate_is_powered(int id)
|
||||
{
|
||||
return (tegra_pmc_readl(PMC_PWRGATE_STATUS) >> id) & 1;
|
||||
}
|
||||
|
||||
static int tegra_pmc_powergate_set(int id, bool new_state)
|
||||
{
|
||||
bool old_state;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&tegra_powergate_lock, flags);
|
||||
|
||||
old_state = tegra_pmc_powergate_is_powered(id);
|
||||
WARN_ON(old_state == new_state);
|
||||
|
||||
tegra_pmc_writel(PMC_PWRGATE_TOGGLE_START | id, PMC_PWRGATE_TOGGLE);
|
||||
|
||||
spin_unlock_irqrestore(&tegra_powergate_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_pmc_powergate_remove_clamping(int id)
|
||||
{
|
||||
u32 mask;
|
||||
|
||||
/*
|
||||
* Tegra has a bug where PCIE and VDE clamping masks are
|
||||
* swapped relatively to the partition ids.
|
||||
*/
|
||||
if (id == TEGRA_POWERGATE_VDEC)
|
||||
mask = (1 << TEGRA_POWERGATE_PCIE);
|
||||
else if (id == TEGRA_POWERGATE_PCIE)
|
||||
mask = (1 << TEGRA_POWERGATE_VDEC);
|
||||
else
|
||||
mask = (1 << id);
|
||||
|
||||
tegra_pmc_writel(mask, PMC_REMOVE_CLAMPING);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool tegra_pmc_cpu_is_powered(int cpuid)
|
||||
{
|
||||
int id;
|
||||
|
||||
id = tegra_pmc_get_cpu_powerdomain_id(cpuid);
|
||||
if (id < 0)
|
||||
return false;
|
||||
return tegra_pmc_powergate_is_powered(id);
|
||||
}
|
||||
|
||||
int tegra_pmc_cpu_power_on(int cpuid)
|
||||
{
|
||||
int id;
|
||||
|
||||
id = tegra_pmc_get_cpu_powerdomain_id(cpuid);
|
||||
if (id < 0)
|
||||
return id;
|
||||
return tegra_pmc_powergate_set(id, true);
|
||||
}
|
||||
|
||||
int tegra_pmc_cpu_remove_clamping(int cpuid)
|
||||
{
|
||||
int id;
|
||||
|
||||
id = tegra_pmc_get_cpu_powerdomain_id(cpuid);
|
||||
if (id < 0)
|
||||
return id;
|
||||
return tegra_pmc_powergate_remove_clamping(id);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static void set_power_timers(u32 us_on, u32 us_off, unsigned long rate)
|
||||
{
|
||||
unsigned long long ticks;
|
||||
unsigned long long pclk;
|
||||
static unsigned long tegra_last_pclk;
|
||||
|
||||
if (WARN_ON_ONCE(rate <= 0))
|
||||
pclk = 100000000;
|
||||
else
|
||||
pclk = rate;
|
||||
|
||||
if ((rate != tegra_last_pclk)) {
|
||||
ticks = (us_on * pclk) + 999999ull;
|
||||
do_div(ticks, 1000000);
|
||||
tegra_pmc_writel((unsigned long)ticks, PMC_CPUPWRGOOD_TIMER);
|
||||
|
||||
ticks = (us_off * pclk) + 999999ull;
|
||||
do_div(ticks, 1000000);
|
||||
tegra_pmc_writel((unsigned long)ticks, PMC_CPUPWROFF_TIMER);
|
||||
wmb();
|
||||
}
|
||||
tegra_last_pclk = pclk;
|
||||
}
|
||||
|
||||
enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void)
|
||||
{
|
||||
return pmc_pm_data.suspend_mode;
|
||||
}
|
||||
|
||||
void tegra_pmc_pm_set(enum tegra_suspend_mode mode)
|
||||
{
|
||||
u32 reg;
|
||||
unsigned long rate = 0;
|
||||
|
||||
reg = tegra_pmc_readl(PMC_CTRL);
|
||||
reg |= TEGRA_POWER_CPU_PWRREQ_OE;
|
||||
reg &= ~TEGRA_POWER_EFFECT_LP0;
|
||||
|
||||
switch (mode) {
|
||||
case TEGRA_SUSPEND_LP2:
|
||||
rate = clk_get_rate(tegra_pclk);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
set_power_timers(pmc_pm_data.cpu_good_time, pmc_pm_data.cpu_off_time,
|
||||
rate);
|
||||
|
||||
tegra_pmc_writel(reg, PMC_CTRL);
|
||||
}
|
||||
|
||||
void tegra_pmc_suspend_init(void)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
/* Always enable CPU power request */
|
||||
reg = tegra_pmc_readl(PMC_CTRL);
|
||||
reg |= TEGRA_POWER_CPU_PWRREQ_OE;
|
||||
tegra_pmc_writel(reg, PMC_CTRL);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct of_device_id matches[] __initconst = {
|
||||
{ .compatible = "nvidia,tegra114-pmc" },
|
||||
{ .compatible = "nvidia,tegra30-pmc" },
|
||||
{ .compatible = "nvidia,tegra20-pmc" },
|
||||
{ }
|
||||
};
|
||||
#endif
|
||||
|
||||
static void tegra_pmc_parse_dt(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
u32 prop;
|
||||
enum tegra_suspend_mode suspend_mode;
|
||||
u32 core_good_time[2] = {0, 0};
|
||||
u32 lp0_vec[2] = {0, 0};
|
||||
|
||||
np = of_find_matching_node(NULL, matches);
|
||||
BUG_ON(!np);
|
||||
|
||||
tegra_pmc_base = of_iomap(np, 0);
|
||||
|
||||
tegra_pmc_invert_interrupt = of_property_read_bool(np,
|
||||
"nvidia,invert-interrupt");
|
||||
tegra_pclk = of_clk_get_by_name(np, "pclk");
|
||||
WARN_ON(IS_ERR(tegra_pclk));
|
||||
|
||||
/* Grabbing the power management configurations */
|
||||
if (of_property_read_u32(np, "nvidia,suspend-mode", &prop)) {
|
||||
suspend_mode = TEGRA_SUSPEND_NONE;
|
||||
} else {
|
||||
switch (prop) {
|
||||
case 0:
|
||||
suspend_mode = TEGRA_SUSPEND_LP0;
|
||||
break;
|
||||
case 1:
|
||||
suspend_mode = TEGRA_SUSPEND_LP1;
|
||||
break;
|
||||
case 2:
|
||||
suspend_mode = TEGRA_SUSPEND_LP2;
|
||||
break;
|
||||
default:
|
||||
suspend_mode = TEGRA_SUSPEND_NONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
suspend_mode = tegra_pm_validate_suspend_mode(suspend_mode);
|
||||
|
||||
if (of_property_read_u32(np, "nvidia,cpu-pwr-good-time", &prop))
|
||||
suspend_mode = TEGRA_SUSPEND_NONE;
|
||||
pmc_pm_data.cpu_good_time = prop;
|
||||
|
||||
if (of_property_read_u32(np, "nvidia,cpu-pwr-off-time", &prop))
|
||||
suspend_mode = TEGRA_SUSPEND_NONE;
|
||||
pmc_pm_data.cpu_off_time = prop;
|
||||
|
||||
if (of_property_read_u32_array(np, "nvidia,core-pwr-good-time",
|
||||
core_good_time, ARRAY_SIZE(core_good_time)))
|
||||
suspend_mode = TEGRA_SUSPEND_NONE;
|
||||
pmc_pm_data.core_osc_time = core_good_time[0];
|
||||
pmc_pm_data.core_pmu_time = core_good_time[1];
|
||||
|
||||
if (of_property_read_u32(np, "nvidia,core-pwr-off-time",
|
||||
&prop))
|
||||
suspend_mode = TEGRA_SUSPEND_NONE;
|
||||
pmc_pm_data.core_off_time = prop;
|
||||
|
||||
pmc_pm_data.corereq_high = of_property_read_bool(np,
|
||||
"nvidia,core-power-req-active-high");
|
||||
|
||||
pmc_pm_data.sysclkreq_high = of_property_read_bool(np,
|
||||
"nvidia,sys-clock-req-active-high");
|
||||
|
||||
pmc_pm_data.combined_req = of_property_read_bool(np,
|
||||
"nvidia,combined-power-req");
|
||||
|
||||
pmc_pm_data.cpu_pwr_good_en = of_property_read_bool(np,
|
||||
"nvidia,cpu-pwr-good-en");
|
||||
|
||||
if (of_property_read_u32_array(np, "nvidia,lp0-vec", lp0_vec,
|
||||
ARRAY_SIZE(lp0_vec)))
|
||||
if (suspend_mode == TEGRA_SUSPEND_LP0)
|
||||
suspend_mode = TEGRA_SUSPEND_LP1;
|
||||
|
||||
pmc_pm_data.lp0_vec_phy_addr = lp0_vec[0];
|
||||
pmc_pm_data.lp0_vec_size = lp0_vec[1];
|
||||
|
||||
pmc_pm_data.suspend_mode = suspend_mode;
|
||||
}
|
||||
|
||||
void __init tegra_pmc_init(void)
|
||||
{
|
||||
/*
|
||||
* For now, Harmony is the only board that uses the PMC, and it wants
|
||||
* the signal inverted. Seaboard would too if it used the PMC.
|
||||
* Hopefully by the time other boards want to use the PMC, everything
|
||||
* will be device-tree, or they also want it inverted.
|
||||
*/
|
||||
bool invert_interrupt = true;
|
||||
u32 val;
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
if (of_have_populated_dt()) {
|
||||
struct device_node *np;
|
||||
|
||||
invert_interrupt = false;
|
||||
|
||||
np = of_find_matching_node(NULL, matches);
|
||||
if (np) {
|
||||
if (of_find_property(np, "nvidia,invert-interrupt",
|
||||
NULL))
|
||||
invert_interrupt = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
tegra_pmc_parse_dt();
|
||||
|
||||
val = tegra_pmc_readl(PMC_CTRL);
|
||||
if (invert_interrupt)
|
||||
if (tegra_pmc_invert_interrupt)
|
||||
val |= PMC_CTRL_INTR_LOW;
|
||||
else
|
||||
val &= ~PMC_CTRL_INTR_LOW;
|
||||
|
|
|
@ -18,6 +18,24 @@
|
|||
#ifndef __MACH_TEGRA_PMC_H
|
||||
#define __MACH_TEGRA_PMC_H
|
||||
|
||||
enum tegra_suspend_mode {
|
||||
TEGRA_SUSPEND_NONE = 0,
|
||||
TEGRA_SUSPEND_LP2, /* CPU voltage off */
|
||||
TEGRA_SUSPEND_LP1, /* CPU voltage off, DRAM self-refresh */
|
||||
TEGRA_SUSPEND_LP0, /* CPU + core voltage off, DRAM self-refresh */
|
||||
TEGRA_MAX_SUSPEND_MODE,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void);
|
||||
void tegra_pmc_pm_set(enum tegra_suspend_mode mode);
|
||||
void tegra_pmc_suspend_init(void);
|
||||
#endif
|
||||
|
||||
bool tegra_pmc_cpu_is_powered(int cpuid);
|
||||
int tegra_pmc_cpu_power_on(int cpuid);
|
||||
int tegra_pmc_cpu_remove_clamping(int cpuid);
|
||||
|
||||
void tegra_pmc_init(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -41,9 +41,6 @@
|
|||
*/
|
||||
ENTRY(tegra_resume)
|
||||
bl v7_invalidate_l1
|
||||
/* Enable coresight */
|
||||
mov32 r0, 0xC5ACCE55
|
||||
mcr p14, 0, r0, c7, c12, 6
|
||||
|
||||
cpu_id r0
|
||||
cmp r0, #0 @ CPU0?
|
||||
|
@ -99,6 +96,8 @@ ENTRY(__tegra_cpu_reset_handler_start)
|
|||
*
|
||||
* Register usage within the reset handler:
|
||||
*
|
||||
* Others: scratch
|
||||
* R6 = SoC ID << 8
|
||||
* R7 = CPU present (to the OS) mask
|
||||
* R8 = CPU in LP1 state mask
|
||||
* R9 = CPU in LP2 state mask
|
||||
|
@ -114,6 +113,40 @@ ENTRY(__tegra_cpu_reset_handler_start)
|
|||
ENTRY(__tegra_cpu_reset_handler)
|
||||
|
||||
cpsid aif, 0x13 @ SVC mode, interrupts disabled
|
||||
|
||||
mov32 r6, TEGRA_APB_MISC_BASE
|
||||
ldr r6, [r6, #APB_MISC_GP_HIDREV]
|
||||
and r6, r6, #0xff00
|
||||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||
t20_check:
|
||||
cmp r6, #(0x20 << 8)
|
||||
bne after_t20_check
|
||||
t20_errata:
|
||||
# Tegra20 is a Cortex-A9 r1p1
|
||||
mrc p15, 0, r0, c1, c0, 0 @ read system control register
|
||||
orr r0, r0, #1 << 14 @ erratum 716044
|
||||
mcr p15, 0, r0, c1, c0, 0 @ write system control register
|
||||
mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register
|
||||
orr r0, r0, #1 << 4 @ erratum 742230
|
||||
orr r0, r0, #1 << 11 @ erratum 751472
|
||||
mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register
|
||||
b after_errata
|
||||
after_t20_check:
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
|
||||
t30_check:
|
||||
cmp r6, #(0x30 << 8)
|
||||
bne after_t30_check
|
||||
t30_errata:
|
||||
# Tegra30 is a Cortex-A9 r2p9
|
||||
mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register
|
||||
orr r0, r0, #1 << 6 @ erratum 743622
|
||||
orr r0, r0, #1 << 11 @ erratum 751472
|
||||
mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register
|
||||
b after_errata
|
||||
after_t30_check:
|
||||
#endif
|
||||
after_errata:
|
||||
mrc p15, 0, r10, c0, c0, 5 @ MPIDR
|
||||
and r10, r10, #0x3 @ R10 = CPU number
|
||||
mov r11, #1
|
||||
|
@ -129,16 +162,13 @@ ENTRY(__tegra_cpu_reset_handler)
|
|||
|
||||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||
/* Are we on Tegra20? */
|
||||
mov32 r6, TEGRA_APB_MISC_BASE
|
||||
ldr r0, [r6, #APB_MISC_GP_HIDREV]
|
||||
and r0, r0, #0xff00
|
||||
cmp r0, #(0x20 << 8)
|
||||
cmp r6, #(0x20 << 8)
|
||||
bne 1f
|
||||
/* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
|
||||
mov32 r6, TEGRA_PMC_BASE
|
||||
mov32 r5, TEGRA_PMC_BASE
|
||||
mov r0, #0
|
||||
cmp r10, #0
|
||||
strne r0, [r6, #PMC_SCRATCH41]
|
||||
strne r0, [r5, #PMC_SCRATCH41]
|
||||
1:
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
|
||||
* Copyright (c) 2010-2013, NVIDIA Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
@ -124,11 +124,11 @@ int tegra_sleep_cpu_finish(unsigned long);
|
|||
void tegra_disable_clean_inv_dcache(void);
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
void tegra20_hotplug_init(void);
|
||||
void tegra30_hotplug_init(void);
|
||||
void tegra20_hotplug_shutdown(void);
|
||||
void tegra30_hotplug_shutdown(void);
|
||||
void tegra_hotplug_init(void);
|
||||
#else
|
||||
static inline void tegra20_hotplug_init(void) {}
|
||||
static inline void tegra30_hotplug_init(void) {}
|
||||
static inline void tegra_hotplug_init(void) {}
|
||||
#endif
|
||||
|
||||
void tegra20_cpu_shutdown(int cpu);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* nVidia Tegra device tree board support
|
||||
* NVIDIA Tegra SoC device tree board support
|
||||
*
|
||||
* Copyright (C) 2011, 2013, NVIDIA Corporation
|
||||
* Copyright (C) 2010 Secret Lab Technologies, Ltd.
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
*
|
||||
|
@ -32,7 +33,10 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-tegra.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sys_soc.h>
|
||||
#include <linux/usb/tegra_usb_phy.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
|
@ -41,6 +45,7 @@
|
|||
|
||||
#include "board.h"
|
||||
#include "common.h"
|
||||
#include "fuse.h"
|
||||
#include "iomap.h"
|
||||
|
||||
static struct tegra_ehci_platform_data tegra_ehci1_pdata = {
|
||||
|
@ -79,12 +84,38 @@ static struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
|
|||
|
||||
static void __init tegra_dt_init(void)
|
||||
{
|
||||
struct soc_device_attribute *soc_dev_attr;
|
||||
struct soc_device *soc_dev;
|
||||
struct device *parent = NULL;
|
||||
|
||||
tegra_clocks_apply_init_table();
|
||||
|
||||
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
|
||||
if (!soc_dev_attr)
|
||||
goto out;
|
||||
|
||||
soc_dev_attr->family = kasprintf(GFP_KERNEL, "Tegra");
|
||||
soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d", tegra_revision);
|
||||
soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%d", tegra_chip_id);
|
||||
|
||||
soc_dev = soc_device_register(soc_dev_attr);
|
||||
if (IS_ERR(soc_dev)) {
|
||||
kfree(soc_dev_attr->family);
|
||||
kfree(soc_dev_attr->revision);
|
||||
kfree(soc_dev_attr->soc_id);
|
||||
kfree(soc_dev_attr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
parent = soc_device_to_device(soc_dev);
|
||||
|
||||
/*
|
||||
* Finished with the static registrations now; fill in the missing
|
||||
* devices
|
||||
*/
|
||||
out:
|
||||
of_platform_populate(NULL, of_default_bus_match_table,
|
||||
tegra20_auxdata_lookup, NULL);
|
||||
tegra20_auxdata_lookup, parent);
|
||||
}
|
||||
|
||||
static void __init trimslice_init(void)
|
||||
|
@ -111,7 +142,8 @@ static void __init harmony_init(void)
|
|||
|
||||
static void __init paz00_init(void)
|
||||
{
|
||||
tegra_paz00_wifikill_init();
|
||||
if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC))
|
||||
tegra_paz00_wifikill_init();
|
||||
}
|
||||
|
||||
static struct {
|
||||
|
@ -137,19 +169,21 @@ static void __init tegra_dt_init_late(void)
|
|||
}
|
||||
}
|
||||
|
||||
static const char *tegra20_dt_board_compat[] = {
|
||||
static const char * const tegra_dt_board_compat[] = {
|
||||
"nvidia,tegra114",
|
||||
"nvidia,tegra30",
|
||||
"nvidia,tegra20",
|
||||
NULL
|
||||
};
|
||||
|
||||
DT_MACHINE_START(TEGRA_DT, "nVidia Tegra20 (Flattened Device Tree)")
|
||||
DT_MACHINE_START(TEGRA_DT, "NVIDIA Tegra SoC (Flattened Device Tree)")
|
||||
.map_io = tegra_map_common_io,
|
||||
.smp = smp_ops(tegra_smp_ops),
|
||||
.init_early = tegra20_init_early,
|
||||
.init_early = tegra_init_early,
|
||||
.init_irq = tegra_dt_init_irq,
|
||||
.init_time = clocksource_of_init,
|
||||
.init_machine = tegra_dt_init,
|
||||
.init_late = tegra_dt_init_late,
|
||||
.restart = tegra_assert_system_reset,
|
||||
.dt_compat = tegra20_dt_board_compat,
|
||||
.dt_compat = tegra_dt_board_compat,
|
||||
MACHINE_END
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/bug.h>
|
||||
|
||||
#include "fuse.h"
|
||||
|
||||
#define CORE_PROCESS_CORNERS_NUM 2
|
||||
#define CPU_PROCESS_CORNERS_NUM 2
|
||||
|
||||
enum {
|
||||
THRESHOLD_INDEX_0,
|
||||
THRESHOLD_INDEX_1,
|
||||
THRESHOLD_INDEX_COUNT,
|
||||
};
|
||||
|
||||
static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
|
||||
{1123, UINT_MAX},
|
||||
{0, UINT_MAX},
|
||||
};
|
||||
|
||||
static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
|
||||
{1695, UINT_MAX},
|
||||
{0, UINT_MAX},
|
||||
};
|
||||
|
||||
static void rev_sku_to_speedo_ids(int rev, int sku, int *threshold)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
switch (sku) {
|
||||
case 0x00:
|
||||
case 0x10:
|
||||
case 0x05:
|
||||
case 0x06:
|
||||
tegra_cpu_speedo_id = 1;
|
||||
tegra_soc_speedo_id = 0;
|
||||
*threshold = THRESHOLD_INDEX_0;
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
case 0x04:
|
||||
tegra_cpu_speedo_id = 2;
|
||||
tegra_soc_speedo_id = 1;
|
||||
*threshold = THRESHOLD_INDEX_1;
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_err("Tegra114 Unknown SKU %d\n", sku);
|
||||
tegra_cpu_speedo_id = 0;
|
||||
tegra_soc_speedo_id = 0;
|
||||
*threshold = THRESHOLD_INDEX_0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rev == TEGRA_REVISION_A01) {
|
||||
tmp = tegra_fuse_readl(0x270) << 1;
|
||||
tmp |= tegra_fuse_readl(0x26c);
|
||||
if (!tmp)
|
||||
tegra_cpu_speedo_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void tegra114_init_speedo_data(void)
|
||||
{
|
||||
u32 cpu_speedo_val;
|
||||
u32 core_speedo_val;
|
||||
int threshold;
|
||||
int i;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
|
||||
THRESHOLD_INDEX_COUNT);
|
||||
BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) !=
|
||||
THRESHOLD_INDEX_COUNT);
|
||||
|
||||
rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id, &threshold);
|
||||
|
||||
cpu_speedo_val = tegra_fuse_readl(0x12c) + 1024;
|
||||
core_speedo_val = tegra_fuse_readl(0x134);
|
||||
|
||||
for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++)
|
||||
if (cpu_speedo_val < cpu_process_speedos[threshold][i])
|
||||
break;
|
||||
tegra_cpu_process_id = i;
|
||||
|
||||
for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++)
|
||||
if (core_speedo_val < core_process_speedos[threshold][i])
|
||||
break;
|
||||
tegra_core_process_id = i;
|
||||
}
|
|
@ -63,6 +63,14 @@ config CLK_TWL6040
|
|||
McPDM. McPDM module is using the external bit clock on the McPDM bus
|
||||
as functional clock.
|
||||
|
||||
config COMMON_CLK_AXI_CLKGEN
|
||||
tristate "AXI clkgen driver"
|
||||
depends on ARCH_ZYNQ || MICROBLAZE
|
||||
help
|
||||
---help---
|
||||
Support for the Analog Devices axi-clkgen pcore clock generator for Xilinx
|
||||
FPGAs. It is commonly used in Analog Devices' reference designs.
|
||||
|
||||
endmenu
|
||||
|
||||
source "drivers/clk/mvebu/Kconfig"
|
||||
|
|
|
@ -7,6 +7,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o
|
|||
obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-gate.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-mux.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-composite.o
|
||||
|
||||
# SoCs specific
|
||||
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
|
||||
|
@ -23,6 +24,7 @@ ifeq ($(CONFIG_COMMON_CLK), y)
|
|||
obj-$(CONFIG_ARCH_MMP) += mmp/
|
||||
endif
|
||||
obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o
|
||||
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
|
||||
obj-$(CONFIG_ARCH_U8500) += ux500/
|
||||
obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
|
||||
obj-$(CONFIG_ARCH_ZYNQ) += clk-zynq.o
|
||||
|
@ -31,6 +33,7 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra/
|
|||
obj-$(CONFIG_X86) += x86/
|
||||
|
||||
# Chip specific
|
||||
obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
|
||||
obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
|
||||
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
|
||||
obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
|
||||
|
|
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
* AXI clkgen driver
|
||||
*
|
||||
* Copyright 2012-2013 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#define AXI_CLKGEN_REG_UPDATE_ENABLE 0x04
|
||||
#define AXI_CLKGEN_REG_CLK_OUT1 0x08
|
||||
#define AXI_CLKGEN_REG_CLK_OUT2 0x0c
|
||||
#define AXI_CLKGEN_REG_CLK_DIV 0x10
|
||||
#define AXI_CLKGEN_REG_CLK_FB1 0x14
|
||||
#define AXI_CLKGEN_REG_CLK_FB2 0x18
|
||||
#define AXI_CLKGEN_REG_LOCK1 0x1c
|
||||
#define AXI_CLKGEN_REG_LOCK2 0x20
|
||||
#define AXI_CLKGEN_REG_LOCK3 0x24
|
||||
#define AXI_CLKGEN_REG_FILTER1 0x28
|
||||
#define AXI_CLKGEN_REG_FILTER2 0x2c
|
||||
|
||||
struct axi_clkgen {
|
||||
void __iomem *base;
|
||||
struct clk_hw clk_hw;
|
||||
};
|
||||
|
||||
static uint32_t axi_clkgen_lookup_filter(unsigned int m)
|
||||
{
|
||||
switch (m) {
|
||||
case 0:
|
||||
return 0x01001990;
|
||||
case 1:
|
||||
return 0x01001190;
|
||||
case 2:
|
||||
return 0x01009890;
|
||||
case 3:
|
||||
return 0x01001890;
|
||||
case 4:
|
||||
return 0x01008890;
|
||||
case 5 ... 8:
|
||||
return 0x01009090;
|
||||
case 9 ... 11:
|
||||
return 0x01000890;
|
||||
case 12:
|
||||
return 0x08009090;
|
||||
case 13 ... 22:
|
||||
return 0x01001090;
|
||||
case 23 ... 36:
|
||||
return 0x01008090;
|
||||
case 37 ... 46:
|
||||
return 0x08001090;
|
||||
default:
|
||||
return 0x08008090;
|
||||
}
|
||||
}
|
||||
|
||||
static const uint32_t axi_clkgen_lock_table[] = {
|
||||
0x060603e8, 0x060603e8, 0x080803e8, 0x0b0b03e8,
|
||||
0x0e0e03e8, 0x111103e8, 0x131303e8, 0x161603e8,
|
||||
0x191903e8, 0x1c1c03e8, 0x1f1f0384, 0x1f1f0339,
|
||||
0x1f1f02ee, 0x1f1f02bc, 0x1f1f028a, 0x1f1f0271,
|
||||
0x1f1f023f, 0x1f1f0226, 0x1f1f020d, 0x1f1f01f4,
|
||||
0x1f1f01db, 0x1f1f01c2, 0x1f1f01a9, 0x1f1f0190,
|
||||
0x1f1f0190, 0x1f1f0177, 0x1f1f015e, 0x1f1f015e,
|
||||
0x1f1f0145, 0x1f1f0145, 0x1f1f012c, 0x1f1f012c,
|
||||
0x1f1f012c, 0x1f1f0113, 0x1f1f0113, 0x1f1f0113,
|
||||
};
|
||||
|
||||
static uint32_t axi_clkgen_lookup_lock(unsigned int m)
|
||||
{
|
||||
if (m < ARRAY_SIZE(axi_clkgen_lock_table))
|
||||
return axi_clkgen_lock_table[m];
|
||||
return 0x1f1f00fa;
|
||||
}
|
||||
|
||||
static const unsigned int fpfd_min = 10000;
|
||||
static const unsigned int fpfd_max = 300000;
|
||||
static const unsigned int fvco_min = 600000;
|
||||
static const unsigned int fvco_max = 1200000;
|
||||
|
||||
static void axi_clkgen_calc_params(unsigned long fin, unsigned long fout,
|
||||
unsigned int *best_d, unsigned int *best_m, unsigned int *best_dout)
|
||||
{
|
||||
unsigned long d, d_min, d_max, _d_min, _d_max;
|
||||
unsigned long m, m_min, m_max;
|
||||
unsigned long f, dout, best_f, fvco;
|
||||
|
||||
fin /= 1000;
|
||||
fout /= 1000;
|
||||
|
||||
best_f = ULONG_MAX;
|
||||
*best_d = 0;
|
||||
*best_m = 0;
|
||||
*best_dout = 0;
|
||||
|
||||
d_min = max_t(unsigned long, DIV_ROUND_UP(fin, fpfd_max), 1);
|
||||
d_max = min_t(unsigned long, fin / fpfd_min, 80);
|
||||
|
||||
m_min = max_t(unsigned long, DIV_ROUND_UP(fvco_min, fin) * d_min, 1);
|
||||
m_max = min_t(unsigned long, fvco_max * d_max / fin, 64);
|
||||
|
||||
for (m = m_min; m <= m_max; m++) {
|
||||
_d_min = max(d_min, DIV_ROUND_UP(fin * m, fvco_max));
|
||||
_d_max = min(d_max, fin * m / fvco_min);
|
||||
|
||||
for (d = _d_min; d <= _d_max; d++) {
|
||||
fvco = fin * m / d;
|
||||
|
||||
dout = DIV_ROUND_CLOSEST(fvco, fout);
|
||||
dout = clamp_t(unsigned long, dout, 1, 128);
|
||||
f = fvco / dout;
|
||||
if (abs(f - fout) < abs(best_f - fout)) {
|
||||
best_f = f;
|
||||
*best_d = d;
|
||||
*best_m = m;
|
||||
*best_dout = dout;
|
||||
if (best_f == fout)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void axi_clkgen_calc_clk_params(unsigned int divider, unsigned int *low,
|
||||
unsigned int *high, unsigned int *edge, unsigned int *nocount)
|
||||
{
|
||||
if (divider == 1)
|
||||
*nocount = 1;
|
||||
else
|
||||
*nocount = 0;
|
||||
|
||||
*high = divider / 2;
|
||||
*edge = divider % 2;
|
||||
*low = divider - *high;
|
||||
}
|
||||
|
||||
static void axi_clkgen_write(struct axi_clkgen *axi_clkgen,
|
||||
unsigned int reg, unsigned int val)
|
||||
{
|
||||
writel(val, axi_clkgen->base + reg);
|
||||
}
|
||||
|
||||
static void axi_clkgen_read(struct axi_clkgen *axi_clkgen,
|
||||
unsigned int reg, unsigned int *val)
|
||||
{
|
||||
*val = readl(axi_clkgen->base + reg);
|
||||
}
|
||||
|
||||
static struct axi_clkgen *clk_hw_to_axi_clkgen(struct clk_hw *clk_hw)
|
||||
{
|
||||
return container_of(clk_hw, struct axi_clkgen, clk_hw);
|
||||
}
|
||||
|
||||
static int axi_clkgen_set_rate(struct clk_hw *clk_hw,
|
||||
unsigned long rate, unsigned long parent_rate)
|
||||
{
|
||||
struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
|
||||
unsigned int d, m, dout;
|
||||
unsigned int nocount;
|
||||
unsigned int high;
|
||||
unsigned int edge;
|
||||
unsigned int low;
|
||||
uint32_t filter;
|
||||
uint32_t lock;
|
||||
|
||||
if (parent_rate == 0 || rate == 0)
|
||||
return -EINVAL;
|
||||
|
||||
axi_clkgen_calc_params(parent_rate, rate, &d, &m, &dout);
|
||||
|
||||
if (d == 0 || dout == 0 || m == 0)
|
||||
return -EINVAL;
|
||||
|
||||
filter = axi_clkgen_lookup_filter(m - 1);
|
||||
lock = axi_clkgen_lookup_lock(m - 1);
|
||||
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_UPDATE_ENABLE, 0);
|
||||
|
||||
axi_clkgen_calc_clk_params(dout, &low, &high, &edge, &nocount);
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_OUT1,
|
||||
(high << 6) | low);
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_OUT2,
|
||||
(edge << 7) | (nocount << 6));
|
||||
|
||||
axi_clkgen_calc_clk_params(d, &low, &high, &edge, &nocount);
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_DIV,
|
||||
(edge << 13) | (nocount << 12) | (high << 6) | low);
|
||||
|
||||
axi_clkgen_calc_clk_params(m, &low, &high, &edge, &nocount);
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_FB1,
|
||||
(high << 6) | low);
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_FB2,
|
||||
(edge << 7) | (nocount << 6));
|
||||
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_LOCK1, lock & 0x3ff);
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_LOCK2,
|
||||
(((lock >> 16) & 0x1f) << 10) | 0x1);
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_LOCK3,
|
||||
(((lock >> 24) & 0x1f) << 10) | 0x3e9);
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_FILTER1, filter >> 16);
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_FILTER2, filter);
|
||||
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_UPDATE_ENABLE, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long axi_clkgen_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
unsigned int d, m, dout;
|
||||
|
||||
axi_clkgen_calc_params(*parent_rate, rate, &d, &m, &dout);
|
||||
|
||||
if (d == 0 || dout == 0 || m == 0)
|
||||
return -EINVAL;
|
||||
|
||||
return *parent_rate / d * m / dout;
|
||||
}
|
||||
|
||||
static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
|
||||
unsigned int d, m, dout;
|
||||
unsigned int reg;
|
||||
unsigned long long tmp;
|
||||
|
||||
axi_clkgen_read(axi_clkgen, AXI_CLKGEN_REG_CLK_OUT1, ®);
|
||||
dout = (reg & 0x3f) + ((reg >> 6) & 0x3f);
|
||||
axi_clkgen_read(axi_clkgen, AXI_CLKGEN_REG_CLK_DIV, ®);
|
||||
d = (reg & 0x3f) + ((reg >> 6) & 0x3f);
|
||||
axi_clkgen_read(axi_clkgen, AXI_CLKGEN_REG_CLK_FB1, ®);
|
||||
m = (reg & 0x3f) + ((reg >> 6) & 0x3f);
|
||||
|
||||
if (d == 0 || dout == 0)
|
||||
return 0;
|
||||
|
||||
tmp = (unsigned long long)(parent_rate / d) * m;
|
||||
do_div(tmp, dout);
|
||||
|
||||
if (tmp > ULONG_MAX)
|
||||
return ULONG_MAX;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static const struct clk_ops axi_clkgen_ops = {
|
||||
.recalc_rate = axi_clkgen_recalc_rate,
|
||||
.round_rate = axi_clkgen_round_rate,
|
||||
.set_rate = axi_clkgen_set_rate,
|
||||
};
|
||||
|
||||
static int axi_clkgen_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct axi_clkgen *axi_clkgen;
|
||||
struct clk_init_data init;
|
||||
const char *parent_name;
|
||||
const char *clk_name;
|
||||
struct resource *mem;
|
||||
struct clk *clk;
|
||||
|
||||
axi_clkgen = devm_kzalloc(&pdev->dev, sizeof(*axi_clkgen), GFP_KERNEL);
|
||||
if (!axi_clkgen)
|
||||
return -ENOMEM;
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
axi_clkgen->base = devm_ioremap_resource(&pdev->dev, mem);
|
||||
if (IS_ERR(axi_clkgen->base))
|
||||
return PTR_ERR(axi_clkgen->base);
|
||||
|
||||
parent_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
|
||||
if (!parent_name)
|
||||
return -EINVAL;
|
||||
|
||||
clk_name = pdev->dev.of_node->name;
|
||||
of_property_read_string(pdev->dev.of_node, "clock-output-names",
|
||||
&clk_name);
|
||||
|
||||
init.name = clk_name;
|
||||
init.ops = &axi_clkgen_ops;
|
||||
init.flags = 0;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
|
||||
axi_clkgen->clk_hw.init = &init;
|
||||
clk = devm_clk_register(&pdev->dev, &axi_clkgen->clk_hw);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
return of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get,
|
||||
clk);
|
||||
}
|
||||
|
||||
static int axi_clkgen_remove(struct platform_device *pdev)
|
||||
{
|
||||
of_clk_del_provider(pdev->dev.of_node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id axi_clkgen_ids[] = {
|
||||
{ .compatible = "adi,axi-clkgen-1.00.a" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, axi_clkgen_ids);
|
||||
|
||||
static struct platform_driver axi_clkgen_driver = {
|
||||
.driver = {
|
||||
.name = "adi-axi-clkgen",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = axi_clkgen_ids,
|
||||
},
|
||||
.probe = axi_clkgen_probe,
|
||||
.remove = axi_clkgen_remove,
|
||||
};
|
||||
module_platform_driver(axi_clkgen_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("Driver for the Analog Devices' AXI clkgen pcore clock generator");
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Copyright (c) 2013 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw)
|
||||
|
||||
static u8 clk_composite_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_composite *composite = to_clk_composite(hw);
|
||||
const struct clk_ops *mux_ops = composite->mux_ops;
|
||||
struct clk_hw *mux_hw = composite->mux_hw;
|
||||
|
||||
mux_hw->clk = hw->clk;
|
||||
|
||||
return mux_ops->get_parent(mux_hw);
|
||||
}
|
||||
|
||||
static int clk_composite_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct clk_composite *composite = to_clk_composite(hw);
|
||||
const struct clk_ops *mux_ops = composite->mux_ops;
|
||||
struct clk_hw *mux_hw = composite->mux_hw;
|
||||
|
||||
mux_hw->clk = hw->clk;
|
||||
|
||||
return mux_ops->set_parent(mux_hw, index);
|
||||
}
|
||||
|
||||
static unsigned long clk_composite_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_composite *composite = to_clk_composite(hw);
|
||||
const struct clk_ops *div_ops = composite->div_ops;
|
||||
struct clk_hw *div_hw = composite->div_hw;
|
||||
|
||||
div_hw->clk = hw->clk;
|
||||
|
||||
return div_ops->recalc_rate(div_hw, parent_rate);
|
||||
}
|
||||
|
||||
static long clk_composite_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
struct clk_composite *composite = to_clk_composite(hw);
|
||||
const struct clk_ops *div_ops = composite->div_ops;
|
||||
struct clk_hw *div_hw = composite->div_hw;
|
||||
|
||||
div_hw->clk = hw->clk;
|
||||
|
||||
return div_ops->round_rate(div_hw, rate, prate);
|
||||
}
|
||||
|
||||
static int clk_composite_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_composite *composite = to_clk_composite(hw);
|
||||
const struct clk_ops *div_ops = composite->div_ops;
|
||||
struct clk_hw *div_hw = composite->div_hw;
|
||||
|
||||
div_hw->clk = hw->clk;
|
||||
|
||||
return div_ops->set_rate(div_hw, rate, parent_rate);
|
||||
}
|
||||
|
||||
static int clk_composite_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_composite *composite = to_clk_composite(hw);
|
||||
const struct clk_ops *gate_ops = composite->gate_ops;
|
||||
struct clk_hw *gate_hw = composite->gate_hw;
|
||||
|
||||
gate_hw->clk = hw->clk;
|
||||
|
||||
return gate_ops->is_enabled(gate_hw);
|
||||
}
|
||||
|
||||
static int clk_composite_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_composite *composite = to_clk_composite(hw);
|
||||
const struct clk_ops *gate_ops = composite->gate_ops;
|
||||
struct clk_hw *gate_hw = composite->gate_hw;
|
||||
|
||||
gate_hw->clk = hw->clk;
|
||||
|
||||
return gate_ops->enable(gate_hw);
|
||||
}
|
||||
|
||||
static void clk_composite_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_composite *composite = to_clk_composite(hw);
|
||||
const struct clk_ops *gate_ops = composite->gate_ops;
|
||||
struct clk_hw *gate_hw = composite->gate_hw;
|
||||
|
||||
gate_hw->clk = hw->clk;
|
||||
|
||||
gate_ops->disable(gate_hw);
|
||||
}
|
||||
|
||||
struct clk *clk_register_composite(struct device *dev, const char *name,
|
||||
const char **parent_names, int num_parents,
|
||||
struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
|
||||
struct clk_hw *div_hw, const struct clk_ops *div_ops,
|
||||
struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
struct clk_composite *composite;
|
||||
struct clk_ops *clk_composite_ops;
|
||||
|
||||
composite = kzalloc(sizeof(*composite), GFP_KERNEL);
|
||||
if (!composite) {
|
||||
pr_err("%s: could not allocate composite clk\n", __func__);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
init.name = name;
|
||||
init.flags = flags | CLK_IS_BASIC;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
|
||||
clk_composite_ops = &composite->ops;
|
||||
|
||||
if (mux_hw && mux_ops) {
|
||||
if (!mux_ops->get_parent || !mux_ops->set_parent) {
|
||||
clk = ERR_PTR(-EINVAL);
|
||||
goto err;
|
||||
}
|
||||
|
||||
composite->mux_hw = mux_hw;
|
||||
composite->mux_ops = mux_ops;
|
||||
clk_composite_ops->get_parent = clk_composite_get_parent;
|
||||
clk_composite_ops->set_parent = clk_composite_set_parent;
|
||||
}
|
||||
|
||||
if (div_hw && div_ops) {
|
||||
if (!div_ops->recalc_rate || !div_ops->round_rate ||
|
||||
!div_ops->set_rate) {
|
||||
clk = ERR_PTR(-EINVAL);
|
||||
goto err;
|
||||
}
|
||||
|
||||
composite->div_hw = div_hw;
|
||||
composite->div_ops = div_ops;
|
||||
clk_composite_ops->recalc_rate = clk_composite_recalc_rate;
|
||||
clk_composite_ops->round_rate = clk_composite_round_rate;
|
||||
clk_composite_ops->set_rate = clk_composite_set_rate;
|
||||
}
|
||||
|
||||
if (gate_hw && gate_ops) {
|
||||
if (!gate_ops->is_enabled || !gate_ops->enable ||
|
||||
!gate_ops->disable) {
|
||||
clk = ERR_PTR(-EINVAL);
|
||||
goto err;
|
||||
}
|
||||
|
||||
composite->gate_hw = gate_hw;
|
||||
composite->gate_ops = gate_ops;
|
||||
clk_composite_ops->is_enabled = clk_composite_is_enabled;
|
||||
clk_composite_ops->enable = clk_composite_enable;
|
||||
clk_composite_ops->disable = clk_composite_disable;
|
||||
}
|
||||
|
||||
init.ops = clk_composite_ops;
|
||||
composite->hw.init = &init;
|
||||
|
||||
clk = clk_register(dev, &composite->hw);
|
||||
if (IS_ERR(clk))
|
||||
goto err;
|
||||
|
||||
if (composite->mux_hw)
|
||||
composite->mux_hw->clk = clk;
|
||||
|
||||
if (composite->div_hw)
|
||||
composite->div_hw->clk = clk;
|
||||
|
||||
if (composite->gate_hw)
|
||||
composite->gate_hw->clk = clk;
|
||||
|
||||
return clk;
|
||||
|
||||
err:
|
||||
kfree(composite);
|
||||
return clk;
|
||||
}
|
|
@ -32,6 +32,7 @@
|
|||
static u8 clk_mux_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_mux *mux = to_clk_mux(hw);
|
||||
int num_parents = __clk_get_num_parents(hw->clk);
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
|
@ -42,7 +43,16 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
|
|||
* val = 0x4 really means "bit 2, index starts at bit 0"
|
||||
*/
|
||||
val = readl(mux->reg) >> mux->shift;
|
||||
val &= (1 << mux->width) - 1;
|
||||
val &= mux->mask;
|
||||
|
||||
if (mux->table) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_parents; i++)
|
||||
if (mux->table[i] == val)
|
||||
return i;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (val && (mux->flags & CLK_MUX_INDEX_BIT))
|
||||
val = ffs(val) - 1;
|
||||
|
@ -50,7 +60,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
|
|||
if (val && (mux->flags & CLK_MUX_INDEX_ONE))
|
||||
val--;
|
||||
|
||||
if (val >= __clk_get_num_parents(hw->clk))
|
||||
if (val >= num_parents)
|
||||
return -EINVAL;
|
||||
|
||||
return val;
|
||||
|
@ -62,17 +72,22 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
|
|||
u32 val;
|
||||
unsigned long flags = 0;
|
||||
|
||||
if (mux->flags & CLK_MUX_INDEX_BIT)
|
||||
index = (1 << ffs(index));
|
||||
if (mux->table)
|
||||
index = mux->table[index];
|
||||
|
||||
if (mux->flags & CLK_MUX_INDEX_ONE)
|
||||
index++;
|
||||
else {
|
||||
if (mux->flags & CLK_MUX_INDEX_BIT)
|
||||
index = (1 << ffs(index));
|
||||
|
||||
if (mux->flags & CLK_MUX_INDEX_ONE)
|
||||
index++;
|
||||
}
|
||||
|
||||
if (mux->lock)
|
||||
spin_lock_irqsave(mux->lock, flags);
|
||||
|
||||
val = readl(mux->reg);
|
||||
val &= ~(((1 << mux->width) - 1) << mux->shift);
|
||||
val &= ~(mux->mask << mux->shift);
|
||||
val |= index << mux->shift;
|
||||
writel(val, mux->reg);
|
||||
|
||||
|
@ -88,10 +103,10 @@ const struct clk_ops clk_mux_ops = {
|
|||
};
|
||||
EXPORT_SYMBOL_GPL(clk_mux_ops);
|
||||
|
||||
struct clk *clk_register_mux(struct device *dev, const char *name,
|
||||
struct clk *clk_register_mux_table(struct device *dev, const char *name,
|
||||
const char **parent_names, u8 num_parents, unsigned long flags,
|
||||
void __iomem *reg, u8 shift, u8 width,
|
||||
u8 clk_mux_flags, spinlock_t *lock)
|
||||
void __iomem *reg, u8 shift, u32 mask,
|
||||
u8 clk_mux_flags, u32 *table, spinlock_t *lock)
|
||||
{
|
||||
struct clk_mux *mux;
|
||||
struct clk *clk;
|
||||
|
@ -113,9 +128,10 @@ struct clk *clk_register_mux(struct device *dev, const char *name,
|
|||
/* struct clk_mux assignments */
|
||||
mux->reg = reg;
|
||||
mux->shift = shift;
|
||||
mux->width = width;
|
||||
mux->mask = mask;
|
||||
mux->flags = clk_mux_flags;
|
||||
mux->lock = lock;
|
||||
mux->table = table;
|
||||
mux->hw.init = &init;
|
||||
|
||||
clk = clk_register(dev, &mux->hw);
|
||||
|
@ -125,3 +141,15 @@ struct clk *clk_register_mux(struct device *dev, const char *name,
|
|||
|
||||
return clk;
|
||||
}
|
||||
|
||||
struct clk *clk_register_mux(struct device *dev, const char *name,
|
||||
const char **parent_names, u8 num_parents, unsigned long flags,
|
||||
void __iomem *reg, u8 shift, u8 width,
|
||||
u8 clk_mux_flags, spinlock_t *lock)
|
||||
{
|
||||
u32 mask = BIT(width) - 1;
|
||||
|
||||
return clk_register_mux_table(dev, name, parent_names, num_parents,
|
||||
flags, reg, shift, mask, clk_mux_flags,
|
||||
NULL, lock);
|
||||
}
|
||||
|
|
|
@ -1113,7 +1113,7 @@ void __init sirfsoc_of_clk_init(void)
|
|||
|
||||
for (i = pll1; i < maxclk; i++) {
|
||||
prima2_clks[i] = clk_register(NULL, prima2_clk_hw_array[i]);
|
||||
BUG_ON(!prima2_clks[i]);
|
||||
BUG_ON(IS_ERR(prima2_clks[i]));
|
||||
}
|
||||
clk_register_clkdev(prima2_clks[cpu], NULL, "cpu");
|
||||
clk_register_clkdev(prima2_clks[io], NULL, "io");
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk/zynq.h>
|
||||
|
||||
static void __iomem *slcr_base;
|
||||
|
||||
|
|
|
@ -19,14 +19,77 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
static DEFINE_SPINLOCK(enable_lock);
|
||||
static DEFINE_MUTEX(prepare_lock);
|
||||
|
||||
static struct task_struct *prepare_owner;
|
||||
static struct task_struct *enable_owner;
|
||||
|
||||
static int prepare_refcnt;
|
||||
static int enable_refcnt;
|
||||
|
||||
static HLIST_HEAD(clk_root_list);
|
||||
static HLIST_HEAD(clk_orphan_list);
|
||||
static LIST_HEAD(clk_notifier_list);
|
||||
|
||||
/*** locking ***/
|
||||
static void clk_prepare_lock(void)
|
||||
{
|
||||
if (!mutex_trylock(&prepare_lock)) {
|
||||
if (prepare_owner == current) {
|
||||
prepare_refcnt++;
|
||||
return;
|
||||
}
|
||||
mutex_lock(&prepare_lock);
|
||||
}
|
||||
WARN_ON_ONCE(prepare_owner != NULL);
|
||||
WARN_ON_ONCE(prepare_refcnt != 0);
|
||||
prepare_owner = current;
|
||||
prepare_refcnt = 1;
|
||||
}
|
||||
|
||||
static void clk_prepare_unlock(void)
|
||||
{
|
||||
WARN_ON_ONCE(prepare_owner != current);
|
||||
WARN_ON_ONCE(prepare_refcnt == 0);
|
||||
|
||||
if (--prepare_refcnt)
|
||||
return;
|
||||
prepare_owner = NULL;
|
||||
mutex_unlock(&prepare_lock);
|
||||
}
|
||||
|
||||
static unsigned long clk_enable_lock(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!spin_trylock_irqsave(&enable_lock, flags)) {
|
||||
if (enable_owner == current) {
|
||||
enable_refcnt++;
|
||||
return flags;
|
||||
}
|
||||
spin_lock_irqsave(&enable_lock, flags);
|
||||
}
|
||||
WARN_ON_ONCE(enable_owner != NULL);
|
||||
WARN_ON_ONCE(enable_refcnt != 0);
|
||||
enable_owner = current;
|
||||
enable_refcnt = 1;
|
||||
return flags;
|
||||
}
|
||||
|
||||
static void clk_enable_unlock(unsigned long flags)
|
||||
{
|
||||
WARN_ON_ONCE(enable_owner != current);
|
||||
WARN_ON_ONCE(enable_refcnt == 0);
|
||||
|
||||
if (--enable_refcnt)
|
||||
return;
|
||||
enable_owner = NULL;
|
||||
spin_unlock_irqrestore(&enable_lock, flags);
|
||||
}
|
||||
|
||||
/*** debugfs support ***/
|
||||
|
||||
#ifdef CONFIG_COMMON_CLK_DEBUG
|
||||
|
@ -69,7 +132,7 @@ static int clk_summary_show(struct seq_file *s, void *data)
|
|||
seq_printf(s, " clock enable_cnt prepare_cnt rate\n");
|
||||
seq_printf(s, "---------------------------------------------------------------------\n");
|
||||
|
||||
mutex_lock(&prepare_lock);
|
||||
clk_prepare_lock();
|
||||
|
||||
hlist_for_each_entry(c, &clk_root_list, child_node)
|
||||
clk_summary_show_subtree(s, c, 0);
|
||||
|
@ -77,7 +140,7 @@ static int clk_summary_show(struct seq_file *s, void *data)
|
|||
hlist_for_each_entry(c, &clk_orphan_list, child_node)
|
||||
clk_summary_show_subtree(s, c, 0);
|
||||
|
||||
mutex_unlock(&prepare_lock);
|
||||
clk_prepare_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -130,7 +193,7 @@ static int clk_dump(struct seq_file *s, void *data)
|
|||
|
||||
seq_printf(s, "{");
|
||||
|
||||
mutex_lock(&prepare_lock);
|
||||
clk_prepare_lock();
|
||||
|
||||
hlist_for_each_entry(c, &clk_root_list, child_node) {
|
||||
if (!first_node)
|
||||
|
@ -144,7 +207,7 @@ static int clk_dump(struct seq_file *s, void *data)
|
|||
clk_dump_subtree(s, c, 0);
|
||||
}
|
||||
|
||||
mutex_unlock(&prepare_lock);
|
||||
clk_prepare_unlock();
|
||||
|
||||
seq_printf(s, "}");
|
||||
return 0;
|
||||
|
@ -316,7 +379,7 @@ static int __init clk_debug_init(void)
|
|||
if (!orphandir)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&prepare_lock);
|
||||
clk_prepare_lock();
|
||||
|
||||
hlist_for_each_entry(clk, &clk_root_list, child_node)
|
||||
clk_debug_create_subtree(clk, rootdir);
|
||||
|
@ -326,7 +389,7 @@ static int __init clk_debug_init(void)
|
|||
|
||||
inited = 1;
|
||||
|
||||
mutex_unlock(&prepare_lock);
|
||||
clk_prepare_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -335,6 +398,31 @@ late_initcall(clk_debug_init);
|
|||
static inline int clk_debug_register(struct clk *clk) { return 0; }
|
||||
#endif
|
||||
|
||||
/* caller must hold prepare_lock */
|
||||
static void clk_unprepare_unused_subtree(struct clk *clk)
|
||||
{
|
||||
struct clk *child;
|
||||
|
||||
if (!clk)
|
||||
return;
|
||||
|
||||
hlist_for_each_entry(child, &clk->children, child_node)
|
||||
clk_unprepare_unused_subtree(child);
|
||||
|
||||
if (clk->prepare_count)
|
||||
return;
|
||||
|
||||
if (clk->flags & CLK_IGNORE_UNUSED)
|
||||
return;
|
||||
|
||||
if (__clk_is_prepared(clk)) {
|
||||
if (clk->ops->unprepare_unused)
|
||||
clk->ops->unprepare_unused(clk->hw);
|
||||
else if (clk->ops->unprepare)
|
||||
clk->ops->unprepare(clk->hw);
|
||||
}
|
||||
}
|
||||
|
||||
/* caller must hold prepare_lock */
|
||||
static void clk_disable_unused_subtree(struct clk *clk)
|
||||
{
|
||||
|
@ -347,7 +435,7 @@ static void clk_disable_unused_subtree(struct clk *clk)
|
|||
hlist_for_each_entry(child, &clk->children, child_node)
|
||||
clk_disable_unused_subtree(child);
|
||||
|
||||
spin_lock_irqsave(&enable_lock, flags);
|
||||
flags = clk_enable_lock();
|
||||
|
||||
if (clk->enable_count)
|
||||
goto unlock_out;
|
||||
|
@ -368,7 +456,7 @@ static void clk_disable_unused_subtree(struct clk *clk)
|
|||
}
|
||||
|
||||
unlock_out:
|
||||
spin_unlock_irqrestore(&enable_lock, flags);
|
||||
clk_enable_unlock(flags);
|
||||
|
||||
out:
|
||||
return;
|
||||
|
@ -378,7 +466,7 @@ static int clk_disable_unused(void)
|
|||
{
|
||||
struct clk *clk;
|
||||
|
||||
mutex_lock(&prepare_lock);
|
||||
clk_prepare_lock();
|
||||
|
||||
hlist_for_each_entry(clk, &clk_root_list, child_node)
|
||||
clk_disable_unused_subtree(clk);
|
||||
|
@ -386,7 +474,13 @@ static int clk_disable_unused(void)
|
|||
hlist_for_each_entry(clk, &clk_orphan_list, child_node)
|
||||
clk_disable_unused_subtree(clk);
|
||||
|
||||
mutex_unlock(&prepare_lock);
|
||||
hlist_for_each_entry(clk, &clk_root_list, child_node)
|
||||
clk_unprepare_unused_subtree(clk);
|
||||
|
||||
hlist_for_each_entry(clk, &clk_orphan_list, child_node)
|
||||
clk_unprepare_unused_subtree(clk);
|
||||
|
||||
clk_prepare_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -451,6 +545,27 @@ unsigned long __clk_get_flags(struct clk *clk)
|
|||
return !clk ? 0 : clk->flags;
|
||||
}
|
||||
|
||||
bool __clk_is_prepared(struct clk *clk)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!clk)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* .is_prepared is optional for clocks that can prepare
|
||||
* fall back to software usage counter if it is missing
|
||||
*/
|
||||
if (!clk->ops->is_prepared) {
|
||||
ret = clk->prepare_count ? 1 : 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = clk->ops->is_prepared(clk->hw);
|
||||
out:
|
||||
return !!ret;
|
||||
}
|
||||
|
||||
bool __clk_is_enabled(struct clk *clk)
|
||||
{
|
||||
int ret;
|
||||
|
@ -548,9 +663,9 @@ void __clk_unprepare(struct clk *clk)
|
|||
*/
|
||||
void clk_unprepare(struct clk *clk)
|
||||
{
|
||||
mutex_lock(&prepare_lock);
|
||||
clk_prepare_lock();
|
||||
__clk_unprepare(clk);
|
||||
mutex_unlock(&prepare_lock);
|
||||
clk_prepare_unlock();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_unprepare);
|
||||
|
||||
|
@ -596,9 +711,9 @@ int clk_prepare(struct clk *clk)
|
|||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&prepare_lock);
|
||||
clk_prepare_lock();
|
||||
ret = __clk_prepare(clk);
|
||||
mutex_unlock(&prepare_lock);
|
||||
clk_prepare_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -640,9 +755,9 @@ void clk_disable(struct clk *clk)
|
|||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&enable_lock, flags);
|
||||
flags = clk_enable_lock();
|
||||
__clk_disable(clk);
|
||||
spin_unlock_irqrestore(&enable_lock, flags);
|
||||
clk_enable_unlock(flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_disable);
|
||||
|
||||
|
@ -693,9 +808,9 @@ int clk_enable(struct clk *clk)
|
|||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&enable_lock, flags);
|
||||
flags = clk_enable_lock();
|
||||
ret = __clk_enable(clk);
|
||||
spin_unlock_irqrestore(&enable_lock, flags);
|
||||
clk_enable_unlock(flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -740,9 +855,9 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
|
|||
{
|
||||
unsigned long ret;
|
||||
|
||||
mutex_lock(&prepare_lock);
|
||||
clk_prepare_lock();
|
||||
ret = __clk_round_rate(clk, rate);
|
||||
mutex_unlock(&prepare_lock);
|
||||
clk_prepare_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -837,13 +952,13 @@ unsigned long clk_get_rate(struct clk *clk)
|
|||
{
|
||||
unsigned long rate;
|
||||
|
||||
mutex_lock(&prepare_lock);
|
||||
clk_prepare_lock();
|
||||
|
||||
if (clk && (clk->flags & CLK_GET_RATE_NOCACHE))
|
||||
__clk_recalc_rates(clk, 0);
|
||||
|
||||
rate = __clk_get_rate(clk);
|
||||
mutex_unlock(&prepare_lock);
|
||||
clk_prepare_unlock();
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
@ -974,7 +1089,7 @@ static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long even
|
|||
int ret = NOTIFY_DONE;
|
||||
|
||||
if (clk->rate == clk->new_rate)
|
||||
return 0;
|
||||
return NULL;
|
||||
|
||||
if (clk->notifier_count) {
|
||||
ret = __clk_notify(clk, event, clk->rate, clk->new_rate);
|
||||
|
@ -1048,7 +1163,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
|
|||
int ret = 0;
|
||||
|
||||
/* prevent racing with updates to the clock topology */
|
||||
mutex_lock(&prepare_lock);
|
||||
clk_prepare_lock();
|
||||
|
||||
/* bail early if nothing to do */
|
||||
if (rate == clk->rate)
|
||||
|
@ -1080,7 +1195,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
|
|||
clk_change_rate(top);
|
||||
|
||||
out:
|
||||
mutex_unlock(&prepare_lock);
|
||||
clk_prepare_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1096,9 +1211,9 @@ struct clk *clk_get_parent(struct clk *clk)
|
|||
{
|
||||
struct clk *parent;
|
||||
|
||||
mutex_lock(&prepare_lock);
|
||||
clk_prepare_lock();
|
||||
parent = __clk_get_parent(clk);
|
||||
mutex_unlock(&prepare_lock);
|
||||
clk_prepare_unlock();
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
@ -1242,19 +1357,19 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent)
|
|||
__clk_prepare(parent);
|
||||
|
||||
/* FIXME replace with clk_is_enabled(clk) someday */
|
||||
spin_lock_irqsave(&enable_lock, flags);
|
||||
flags = clk_enable_lock();
|
||||
if (clk->enable_count)
|
||||
__clk_enable(parent);
|
||||
spin_unlock_irqrestore(&enable_lock, flags);
|
||||
clk_enable_unlock(flags);
|
||||
|
||||
/* change clock input source */
|
||||
ret = clk->ops->set_parent(clk->hw, i);
|
||||
|
||||
/* clean up old prepare and enable */
|
||||
spin_lock_irqsave(&enable_lock, flags);
|
||||
flags = clk_enable_lock();
|
||||
if (clk->enable_count)
|
||||
__clk_disable(old_parent);
|
||||
spin_unlock_irqrestore(&enable_lock, flags);
|
||||
clk_enable_unlock(flags);
|
||||
|
||||
if (clk->prepare_count)
|
||||
__clk_unprepare(old_parent);
|
||||
|
@ -1286,7 +1401,7 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
|
|||
return -ENOSYS;
|
||||
|
||||
/* prevent racing with updates to the clock topology */
|
||||
mutex_lock(&prepare_lock);
|
||||
clk_prepare_lock();
|
||||
|
||||
if (clk->parent == parent)
|
||||
goto out;
|
||||
|
@ -1315,7 +1430,7 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
|
|||
__clk_reparent(clk, parent);
|
||||
|
||||
out:
|
||||
mutex_unlock(&prepare_lock);
|
||||
clk_prepare_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1338,7 +1453,7 @@ int __clk_init(struct device *dev, struct clk *clk)
|
|||
if (!clk)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&prepare_lock);
|
||||
clk_prepare_lock();
|
||||
|
||||
/* check to see if a clock with this name is already registered */
|
||||
if (__clk_lookup(clk->name)) {
|
||||
|
@ -1462,7 +1577,7 @@ int __clk_init(struct device *dev, struct clk *clk)
|
|||
clk_debug_register(clk);
|
||||
|
||||
out:
|
||||
mutex_unlock(&prepare_lock);
|
||||
clk_prepare_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1696,7 +1811,7 @@ int clk_notifier_register(struct clk *clk, struct notifier_block *nb)
|
|||
if (!clk || !nb)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&prepare_lock);
|
||||
clk_prepare_lock();
|
||||
|
||||
/* search the list of notifiers for this clk */
|
||||
list_for_each_entry(cn, &clk_notifier_list, node)
|
||||
|
@ -1720,7 +1835,7 @@ int clk_notifier_register(struct clk *clk, struct notifier_block *nb)
|
|||
clk->notifier_count++;
|
||||
|
||||
out:
|
||||
mutex_unlock(&prepare_lock);
|
||||
clk_prepare_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1745,7 +1860,7 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
|
|||
if (!clk || !nb)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&prepare_lock);
|
||||
clk_prepare_lock();
|
||||
|
||||
list_for_each_entry(cn, &clk_notifier_list, node)
|
||||
if (cn->clk == clk)
|
||||
|
@ -1766,7 +1881,7 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
|
|||
ret = -ENOENT;
|
||||
}
|
||||
|
||||
mutex_unlock(&prepare_lock);
|
||||
clk_prepare_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include "clk.h"
|
||||
|
||||
DEFINE_SPINLOCK(mxs_lock);
|
||||
|
||||
|
|
|
@ -960,47 +960,47 @@ void __init spear1340_clk_init(void)
|
|||
SPEAR1340_SPDIF_IN_CLK_ENB, 0, &_lock);
|
||||
clk_register_clkdev(clk, NULL, "d0100000.spdif-in");
|
||||
|
||||
clk = clk_register_gate(NULL, "acp_clk", "acp_mclk", 0,
|
||||
clk = clk_register_gate(NULL, "acp_clk", "ahb_clk", 0,
|
||||
SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_ACP_CLK_ENB, 0,
|
||||
&_lock);
|
||||
clk_register_clkdev(clk, NULL, "acp_clk");
|
||||
|
||||
clk = clk_register_gate(NULL, "plgpio_clk", "plgpio_mclk", 0,
|
||||
clk = clk_register_gate(NULL, "plgpio_clk", "ahb_clk", 0,
|
||||
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_PLGPIO_CLK_ENB, 0,
|
||||
&_lock);
|
||||
clk_register_clkdev(clk, NULL, "e2800000.gpio");
|
||||
|
||||
clk = clk_register_gate(NULL, "video_dec_clk", "video_dec_mclk", 0,
|
||||
clk = clk_register_gate(NULL, "video_dec_clk", "ahb_clk", 0,
|
||||
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_VIDEO_DEC_CLK_ENB,
|
||||
0, &_lock);
|
||||
clk_register_clkdev(clk, NULL, "video_dec");
|
||||
|
||||
clk = clk_register_gate(NULL, "video_enc_clk", "video_enc_mclk", 0,
|
||||
clk = clk_register_gate(NULL, "video_enc_clk", "ahb_clk", 0,
|
||||
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_VIDEO_ENC_CLK_ENB,
|
||||
0, &_lock);
|
||||
clk_register_clkdev(clk, NULL, "video_enc");
|
||||
|
||||
clk = clk_register_gate(NULL, "video_in_clk", "video_in_mclk", 0,
|
||||
clk = clk_register_gate(NULL, "video_in_clk", "ahb_clk", 0,
|
||||
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_VIDEO_IN_CLK_ENB, 0,
|
||||
&_lock);
|
||||
clk_register_clkdev(clk, NULL, "spear_vip");
|
||||
|
||||
clk = clk_register_gate(NULL, "cam0_clk", "cam0_mclk", 0,
|
||||
clk = clk_register_gate(NULL, "cam0_clk", "ahb_clk", 0,
|
||||
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM0_CLK_ENB, 0,
|
||||
&_lock);
|
||||
clk_register_clkdev(clk, NULL, "d0200000.cam0");
|
||||
|
||||
clk = clk_register_gate(NULL, "cam1_clk", "cam1_mclk", 0,
|
||||
clk = clk_register_gate(NULL, "cam1_clk", "ahb_clk", 0,
|
||||
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM1_CLK_ENB, 0,
|
||||
&_lock);
|
||||
clk_register_clkdev(clk, NULL, "d0300000.cam1");
|
||||
|
||||
clk = clk_register_gate(NULL, "cam2_clk", "cam2_mclk", 0,
|
||||
clk = clk_register_gate(NULL, "cam2_clk", "ahb_clk", 0,
|
||||
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM2_CLK_ENB, 0,
|
||||
&_lock);
|
||||
clk_register_clkdev(clk, NULL, "d0400000.cam2");
|
||||
|
||||
clk = clk_register_gate(NULL, "cam3_clk", "cam3_mclk", 0,
|
||||
clk = clk_register_gate(NULL, "cam3_clk", "ahb_clk", 0,
|
||||
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM3_CLK_ENB, 0,
|
||||
&_lock);
|
||||
clk_register_clkdev(clk, NULL, "d0500000.cam3");
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#
|
||||
# Makefile for sunxi specific clk
|
||||
#
|
||||
|
||||
obj-y += clk-sunxi.o clk-factors.o
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Copyright (C) 2013 Emilio López <emilio@elopez.com.ar>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Adjustable factor-based clock implementation
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "clk-factors.h"
|
||||
|
||||
/*
|
||||
* DOC: basic adjustable factor-based clock that cannot gate
|
||||
*
|
||||
* Traits of this clock:
|
||||
* prepare - clk_prepare only ensures that parents are prepared
|
||||
* enable - clk_enable only ensures that parents are enabled
|
||||
* rate - rate is adjustable.
|
||||
* clk->rate = (parent->rate * N * (K + 1) >> P) / (M + 1)
|
||||
* parent - fixed parent. No clk_set_parent support
|
||||
*/
|
||||
|
||||
struct clk_factors {
|
||||
struct clk_hw hw;
|
||||
void __iomem *reg;
|
||||
struct clk_factors_config *config;
|
||||
void (*get_factors) (u32 *rate, u32 parent, u8 *n, u8 *k, u8 *m, u8 *p);
|
||||
spinlock_t *lock;
|
||||
};
|
||||
|
||||
#define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw)
|
||||
|
||||
#define SETMASK(len, pos) (((-1U) >> (31-len)) << (pos))
|
||||
#define CLRMASK(len, pos) (~(SETMASK(len, pos)))
|
||||
#define FACTOR_GET(bit, len, reg) (((reg) & SETMASK(len, bit)) >> (bit))
|
||||
|
||||
#define FACTOR_SET(bit, len, reg, val) \
|
||||
(((reg) & CLRMASK(len, bit)) | (val << (bit)))
|
||||
|
||||
static unsigned long clk_factors_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u8 n = 1, k = 0, p = 0, m = 0;
|
||||
u32 reg;
|
||||
unsigned long rate;
|
||||
struct clk_factors *factors = to_clk_factors(hw);
|
||||
struct clk_factors_config *config = factors->config;
|
||||
|
||||
/* Fetch the register value */
|
||||
reg = readl(factors->reg);
|
||||
|
||||
/* Get each individual factor if applicable */
|
||||
if (config->nwidth != SUNXI_FACTORS_NOT_APPLICABLE)
|
||||
n = FACTOR_GET(config->nshift, config->nwidth, reg);
|
||||
if (config->kwidth != SUNXI_FACTORS_NOT_APPLICABLE)
|
||||
k = FACTOR_GET(config->kshift, config->kwidth, reg);
|
||||
if (config->mwidth != SUNXI_FACTORS_NOT_APPLICABLE)
|
||||
m = FACTOR_GET(config->mshift, config->mwidth, reg);
|
||||
if (config->pwidth != SUNXI_FACTORS_NOT_APPLICABLE)
|
||||
p = FACTOR_GET(config->pshift, config->pwidth, reg);
|
||||
|
||||
/* Calculate the rate */
|
||||
rate = (parent_rate * n * (k + 1) >> p) / (m + 1);
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct clk_factors *factors = to_clk_factors(hw);
|
||||
factors->get_factors((u32 *)&rate, (u32)*parent_rate,
|
||||
NULL, NULL, NULL, NULL);
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u8 n, k, m, p;
|
||||
u32 reg;
|
||||
struct clk_factors *factors = to_clk_factors(hw);
|
||||
struct clk_factors_config *config = factors->config;
|
||||
unsigned long flags = 0;
|
||||
|
||||
factors->get_factors((u32 *)&rate, (u32)parent_rate, &n, &k, &m, &p);
|
||||
|
||||
if (factors->lock)
|
||||
spin_lock_irqsave(factors->lock, flags);
|
||||
|
||||
/* Fetch the register value */
|
||||
reg = readl(factors->reg);
|
||||
|
||||
/* Set up the new factors - macros do not do anything if width is 0 */
|
||||
reg = FACTOR_SET(config->nshift, config->nwidth, reg, n);
|
||||
reg = FACTOR_SET(config->kshift, config->kwidth, reg, k);
|
||||
reg = FACTOR_SET(config->mshift, config->mwidth, reg, m);
|
||||
reg = FACTOR_SET(config->pshift, config->pwidth, reg, p);
|
||||
|
||||
/* Apply them now */
|
||||
writel(reg, factors->reg);
|
||||
|
||||
/* delay 500us so pll stabilizes */
|
||||
__delay((rate >> 20) * 500 / 2);
|
||||
|
||||
if (factors->lock)
|
||||
spin_unlock_irqrestore(factors->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_factors_ops = {
|
||||
.recalc_rate = clk_factors_recalc_rate,
|
||||
.round_rate = clk_factors_round_rate,
|
||||
.set_rate = clk_factors_set_rate,
|
||||
};
|
||||
|
||||
/**
|
||||
* clk_register_factors - register a factors clock with
|
||||
* the clock framework
|
||||
* @dev: device registering this clock
|
||||
* @name: name of this clock
|
||||
* @parent_name: name of clock's parent
|
||||
* @flags: framework-specific flags
|
||||
* @reg: register address to adjust factors
|
||||
* @config: shift and width of factors n, k, m and p
|
||||
* @get_factors: function to calculate the factors for a given frequency
|
||||
* @lock: shared register lock for this clock
|
||||
*/
|
||||
struct clk *clk_register_factors(struct device *dev, const char *name,
|
||||
const char *parent_name,
|
||||
unsigned long flags, void __iomem *reg,
|
||||
struct clk_factors_config *config,
|
||||
void (*get_factors)(u32 *rate, u32 parent,
|
||||
u8 *n, u8 *k, u8 *m, u8 *p),
|
||||
spinlock_t *lock)
|
||||
{
|
||||
struct clk_factors *factors;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
/* allocate the factors */
|
||||
factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL);
|
||||
if (!factors) {
|
||||
pr_err("%s: could not allocate factors clk\n", __func__);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_factors_ops;
|
||||
init.flags = flags;
|
||||
init.parent_names = (parent_name ? &parent_name : NULL);
|
||||
init.num_parents = (parent_name ? 1 : 0);
|
||||
|
||||
/* struct clk_factors assignments */
|
||||
factors->reg = reg;
|
||||
factors->config = config;
|
||||
factors->lock = lock;
|
||||
factors->hw.init = &init;
|
||||
factors->get_factors = get_factors;
|
||||
|
||||
/* register the clock */
|
||||
clk = clk_register(dev, &factors->hw);
|
||||
|
||||
if (IS_ERR(clk))
|
||||
kfree(factors);
|
||||
|
||||
return clk;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef __MACH_SUNXI_CLK_FACTORS_H
|
||||
#define __MACH_SUNXI_CLK_FACTORS_H
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
|
||||
#define SUNXI_FACTORS_NOT_APPLICABLE (0)
|
||||
|
||||
struct clk_factors_config {
|
||||
u8 nshift;
|
||||
u8 nwidth;
|
||||
u8 kshift;
|
||||
u8 kwidth;
|
||||
u8 mshift;
|
||||
u8 mwidth;
|
||||
u8 pshift;
|
||||
u8 pwidth;
|
||||
};
|
||||
|
||||
struct clk *clk_register_factors(struct device *dev, const char *name,
|
||||
const char *parent_name,
|
||||
unsigned long flags, void __iomem *reg,
|
||||
struct clk_factors_config *config,
|
||||
void (*get_factors) (u32 *rate, u32 parent_rate,
|
||||
u8 *n, u8 *k, u8 *m, u8 *p),
|
||||
spinlock_t *lock);
|
||||
#endif
|
|
@ -0,0 +1,362 @@
|
|||
/*
|
||||
* Copyright 2013 Emilio López
|
||||
*
|
||||
* Emilio López <emilio@elopez.com.ar>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk/sunxi.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
|
||||
#include "clk-factors.h"
|
||||
|
||||
static DEFINE_SPINLOCK(clk_lock);
|
||||
|
||||
/**
|
||||
* sunxi_osc_clk_setup() - Setup function for gatable oscillator
|
||||
*/
|
||||
|
||||
#define SUNXI_OSC24M_GATE 0
|
||||
|
||||
static void __init sunxi_osc_clk_setup(struct device_node *node)
|
||||
{
|
||||
struct clk *clk;
|
||||
const char *clk_name = node->name;
|
||||
const char *parent;
|
||||
void *reg;
|
||||
|
||||
reg = of_iomap(node, 0);
|
||||
|
||||
parent = of_clk_get_parent_name(node, 0);
|
||||
|
||||
clk = clk_register_gate(NULL, clk_name, parent, CLK_IGNORE_UNUSED,
|
||||
reg, SUNXI_OSC24M_GATE, 0, &clk_lock);
|
||||
|
||||
if (clk) {
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
clk_register_clkdev(clk, clk_name, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* sunxi_get_pll1_factors() - calculates n, k, m, p factors for PLL1
|
||||
* PLL1 rate is calculated as follows
|
||||
* rate = (parent_rate * n * (k + 1) >> p) / (m + 1);
|
||||
* parent_rate is always 24Mhz
|
||||
*/
|
||||
|
||||
static void sunxi_get_pll1_factors(u32 *freq, u32 parent_rate,
|
||||
u8 *n, u8 *k, u8 *m, u8 *p)
|
||||
{
|
||||
u8 div;
|
||||
|
||||
/* Normalize value to a 6M multiple */
|
||||
div = *freq / 6000000;
|
||||
*freq = 6000000 * div;
|
||||
|
||||
/* we were called to round the frequency, we can now return */
|
||||
if (n == NULL)
|
||||
return;
|
||||
|
||||
/* m is always zero for pll1 */
|
||||
*m = 0;
|
||||
|
||||
/* k is 1 only on these cases */
|
||||
if (*freq >= 768000000 || *freq == 42000000 || *freq == 54000000)
|
||||
*k = 1;
|
||||
else
|
||||
*k = 0;
|
||||
|
||||
/* p will be 3 for divs under 10 */
|
||||
if (div < 10)
|
||||
*p = 3;
|
||||
|
||||
/* p will be 2 for divs between 10 - 20 and odd divs under 32 */
|
||||
else if (div < 20 || (div < 32 && (div & 1)))
|
||||
*p = 2;
|
||||
|
||||
/* p will be 1 for even divs under 32, divs under 40 and odd pairs
|
||||
* of divs between 40-62 */
|
||||
else if (div < 40 || (div < 64 && (div & 2)))
|
||||
*p = 1;
|
||||
|
||||
/* any other entries have p = 0 */
|
||||
else
|
||||
*p = 0;
|
||||
|
||||
/* calculate a suitable n based on k and p */
|
||||
div <<= *p;
|
||||
div /= (*k + 1);
|
||||
*n = div / 4;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* sunxi_get_apb1_factors() - calculates m, p factors for APB1
|
||||
* APB1 rate is calculated as follows
|
||||
* rate = (parent_rate >> p) / (m + 1);
|
||||
*/
|
||||
|
||||
static void sunxi_get_apb1_factors(u32 *freq, u32 parent_rate,
|
||||
u8 *n, u8 *k, u8 *m, u8 *p)
|
||||
{
|
||||
u8 calcm, calcp;
|
||||
|
||||
if (parent_rate < *freq)
|
||||
*freq = parent_rate;
|
||||
|
||||
parent_rate = (parent_rate + (*freq - 1)) / *freq;
|
||||
|
||||
/* Invalid rate! */
|
||||
if (parent_rate > 32)
|
||||
return;
|
||||
|
||||
if (parent_rate <= 4)
|
||||
calcp = 0;
|
||||
else if (parent_rate <= 8)
|
||||
calcp = 1;
|
||||
else if (parent_rate <= 16)
|
||||
calcp = 2;
|
||||
else
|
||||
calcp = 3;
|
||||
|
||||
calcm = (parent_rate >> calcp) - 1;
|
||||
|
||||
*freq = (parent_rate >> calcp) / (calcm + 1);
|
||||
|
||||
/* we were called to round the frequency, we can now return */
|
||||
if (n == NULL)
|
||||
return;
|
||||
|
||||
*m = calcm;
|
||||
*p = calcp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* sunxi_factors_clk_setup() - Setup function for factor clocks
|
||||
*/
|
||||
|
||||
struct factors_data {
|
||||
struct clk_factors_config *table;
|
||||
void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p);
|
||||
};
|
||||
|
||||
static struct clk_factors_config pll1_config = {
|
||||
.nshift = 8,
|
||||
.nwidth = 5,
|
||||
.kshift = 4,
|
||||
.kwidth = 2,
|
||||
.mshift = 0,
|
||||
.mwidth = 2,
|
||||
.pshift = 16,
|
||||
.pwidth = 2,
|
||||
};
|
||||
|
||||
static struct clk_factors_config apb1_config = {
|
||||
.mshift = 0,
|
||||
.mwidth = 5,
|
||||
.pshift = 16,
|
||||
.pwidth = 2,
|
||||
};
|
||||
|
||||
static const __initconst struct factors_data pll1_data = {
|
||||
.table = &pll1_config,
|
||||
.getter = sunxi_get_pll1_factors,
|
||||
};
|
||||
|
||||
static const __initconst struct factors_data apb1_data = {
|
||||
.table = &apb1_config,
|
||||
.getter = sunxi_get_apb1_factors,
|
||||
};
|
||||
|
||||
static void __init sunxi_factors_clk_setup(struct device_node *node,
|
||||
struct factors_data *data)
|
||||
{
|
||||
struct clk *clk;
|
||||
const char *clk_name = node->name;
|
||||
const char *parent;
|
||||
void *reg;
|
||||
|
||||
reg = of_iomap(node, 0);
|
||||
|
||||
parent = of_clk_get_parent_name(node, 0);
|
||||
|
||||
clk = clk_register_factors(NULL, clk_name, parent, CLK_IGNORE_UNUSED,
|
||||
reg, data->table, data->getter, &clk_lock);
|
||||
|
||||
if (clk) {
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
clk_register_clkdev(clk, clk_name, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* sunxi_mux_clk_setup() - Setup function for muxes
|
||||
*/
|
||||
|
||||
#define SUNXI_MUX_GATE_WIDTH 2
|
||||
|
||||
struct mux_data {
|
||||
u8 shift;
|
||||
};
|
||||
|
||||
static const __initconst struct mux_data cpu_data = {
|
||||
.shift = 16,
|
||||
};
|
||||
|
||||
static const __initconst struct mux_data apb1_mux_data = {
|
||||
.shift = 24,
|
||||
};
|
||||
|
||||
static void __init sunxi_mux_clk_setup(struct device_node *node,
|
||||
struct mux_data *data)
|
||||
{
|
||||
struct clk *clk;
|
||||
const char *clk_name = node->name;
|
||||
const char **parents = kmalloc(sizeof(char *) * 5, GFP_KERNEL);
|
||||
void *reg;
|
||||
int i = 0;
|
||||
|
||||
reg = of_iomap(node, 0);
|
||||
|
||||
while (i < 5 && (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
|
||||
i++;
|
||||
|
||||
clk = clk_register_mux(NULL, clk_name, parents, i, 0, reg,
|
||||
data->shift, SUNXI_MUX_GATE_WIDTH,
|
||||
0, &clk_lock);
|
||||
|
||||
if (clk) {
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
clk_register_clkdev(clk, clk_name, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* sunxi_divider_clk_setup() - Setup function for simple divider clocks
|
||||
*/
|
||||
|
||||
#define SUNXI_DIVISOR_WIDTH 2
|
||||
|
||||
struct div_data {
|
||||
u8 shift;
|
||||
u8 pow;
|
||||
};
|
||||
|
||||
static const __initconst struct div_data axi_data = {
|
||||
.shift = 0,
|
||||
.pow = 0,
|
||||
};
|
||||
|
||||
static const __initconst struct div_data ahb_data = {
|
||||
.shift = 4,
|
||||
.pow = 1,
|
||||
};
|
||||
|
||||
static const __initconst struct div_data apb0_data = {
|
||||
.shift = 8,
|
||||
.pow = 1,
|
||||
};
|
||||
|
||||
static void __init sunxi_divider_clk_setup(struct device_node *node,
|
||||
struct div_data *data)
|
||||
{
|
||||
struct clk *clk;
|
||||
const char *clk_name = node->name;
|
||||
const char *clk_parent;
|
||||
void *reg;
|
||||
|
||||
reg = of_iomap(node, 0);
|
||||
|
||||
clk_parent = of_clk_get_parent_name(node, 0);
|
||||
|
||||
clk = clk_register_divider(NULL, clk_name, clk_parent, 0,
|
||||
reg, data->shift, SUNXI_DIVISOR_WIDTH,
|
||||
data->pow ? CLK_DIVIDER_POWER_OF_TWO : 0,
|
||||
&clk_lock);
|
||||
if (clk) {
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
clk_register_clkdev(clk, clk_name, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Matches for of_clk_init */
|
||||
static const __initconst struct of_device_id clk_match[] = {
|
||||
{.compatible = "fixed-clock", .data = of_fixed_clk_setup,},
|
||||
{.compatible = "allwinner,sun4i-osc-clk", .data = sunxi_osc_clk_setup,},
|
||||
{}
|
||||
};
|
||||
|
||||
/* Matches for factors clocks */
|
||||
static const __initconst struct of_device_id clk_factors_match[] = {
|
||||
{.compatible = "allwinner,sun4i-pll1-clk", .data = &pll1_data,},
|
||||
{.compatible = "allwinner,sun4i-apb1-clk", .data = &apb1_data,},
|
||||
{}
|
||||
};
|
||||
|
||||
/* Matches for divider clocks */
|
||||
static const __initconst struct of_device_id clk_div_match[] = {
|
||||
{.compatible = "allwinner,sun4i-axi-clk", .data = &axi_data,},
|
||||
{.compatible = "allwinner,sun4i-ahb-clk", .data = &ahb_data,},
|
||||
{.compatible = "allwinner,sun4i-apb0-clk", .data = &apb0_data,},
|
||||
{}
|
||||
};
|
||||
|
||||
/* Matches for mux clocks */
|
||||
static const __initconst struct of_device_id clk_mux_match[] = {
|
||||
{.compatible = "allwinner,sun4i-cpu-clk", .data = &cpu_data,},
|
||||
{.compatible = "allwinner,sun4i-apb1-mux-clk", .data = &apb1_mux_data,},
|
||||
{}
|
||||
};
|
||||
|
||||
static void __init of_sunxi_table_clock_setup(const struct of_device_id *clk_match,
|
||||
void *function)
|
||||
{
|
||||
struct device_node *np;
|
||||
const struct div_data *data;
|
||||
const struct of_device_id *match;
|
||||
void (*setup_function)(struct device_node *, const void *) = function;
|
||||
|
||||
for_each_matching_node(np, clk_match) {
|
||||
match = of_match_node(clk_match, np);
|
||||
data = match->data;
|
||||
setup_function(np, data);
|
||||
}
|
||||
}
|
||||
|
||||
void __init sunxi_init_clocks(void)
|
||||
{
|
||||
/* Register all the simple sunxi clocks on DT */
|
||||
of_clk_init(clk_match);
|
||||
|
||||
/* Register factor clocks */
|
||||
of_sunxi_table_clock_setup(clk_factors_match, sunxi_factors_clk_setup);
|
||||
|
||||
/* Register divider clocks */
|
||||
of_sunxi_table_clock_setup(clk_div_match, sunxi_divider_clk_setup);
|
||||
|
||||
/* Register mux clocks */
|
||||
of_sunxi_table_clock_setup(clk_mux_match, sunxi_mux_clk_setup);
|
||||
}
|
|
@ -9,3 +9,4 @@ obj-y += clk-super.o
|
|||
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_114_SOC) += clk-tegra114.o
|
||||
|
|
|
@ -41,7 +41,9 @@ static DEFINE_SPINLOCK(periph_ref_lock);
|
|||
#define write_rst_clr(val, gate) \
|
||||
writel_relaxed(val, gate->clk_base + (gate->regs->rst_clr_reg))
|
||||
|
||||
#define periph_clk_to_bit(periph) (1 << (gate->clk_num % 32))
|
||||
#define periph_clk_to_bit(gate) (1 << (gate->clk_num % 32))
|
||||
|
||||
#define LVL2_CLK_GATE_OVRE 0x554
|
||||
|
||||
/* Peripheral gate clock ops */
|
||||
static int clk_periph_is_enabled(struct clk_hw *hw)
|
||||
|
@ -83,6 +85,13 @@ static int clk_periph_enable(struct clk_hw *hw)
|
|||
}
|
||||
}
|
||||
|
||||
if (gate->flags & TEGRA_PERIPH_WAR_1005168) {
|
||||
writel_relaxed(0, gate->clk_base + LVL2_CLK_GATE_OVRE);
|
||||
writel_relaxed(BIT(22), gate->clk_base + LVL2_CLK_GATE_OVRE);
|
||||
udelay(1);
|
||||
writel_relaxed(0, gate->clk_base + LVL2_CLK_GATE_OVRE);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&periph_ref_lock, flags);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
|
@ -128,6 +129,7 @@ void tegra_periph_reset_deassert(struct clk *c)
|
|||
|
||||
tegra_periph_reset(gate, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(tegra_periph_reset_deassert);
|
||||
|
||||
void tegra_periph_reset_assert(struct clk *c)
|
||||
{
|
||||
|
@ -147,6 +149,7 @@ void tegra_periph_reset_assert(struct clk *c)
|
|||
|
||||
tegra_periph_reset(gate, 1);
|
||||
}
|
||||
EXPORT_SYMBOL(tegra_periph_reset_assert);
|
||||
|
||||
const struct clk_ops tegra_clk_periph_ops = {
|
||||
.get_parent = clk_periph_get_parent,
|
||||
|
@ -170,14 +173,15 @@ const struct clk_ops tegra_clk_periph_nodiv_ops = {
|
|||
static struct clk *_tegra_clk_register_periph(const char *name,
|
||||
const char **parent_names, int num_parents,
|
||||
struct tegra_clk_periph *periph,
|
||||
void __iomem *clk_base, u32 offset, bool div)
|
||||
void __iomem *clk_base, u32 offset, bool div,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
init.name = name;
|
||||
init.ops = div ? &tegra_clk_periph_ops : &tegra_clk_periph_nodiv_ops;
|
||||
init.flags = div ? 0 : CLK_SET_RATE_PARENT;
|
||||
init.flags = flags;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
|
||||
|
@ -202,10 +206,10 @@ static struct clk *_tegra_clk_register_periph(const char *name,
|
|||
struct clk *tegra_clk_register_periph(const char *name,
|
||||
const char **parent_names, int num_parents,
|
||||
struct tegra_clk_periph *periph, void __iomem *clk_base,
|
||||
u32 offset)
|
||||
u32 offset, unsigned long flags)
|
||||
{
|
||||
return _tegra_clk_register_periph(name, parent_names, num_parents,
|
||||
periph, clk_base, offset, true);
|
||||
periph, clk_base, offset, true, flags);
|
||||
}
|
||||
|
||||
struct clk *tegra_clk_register_periph_nodiv(const char *name,
|
||||
|
@ -214,5 +218,5 @@ struct clk *tegra_clk_register_periph_nodiv(const char *name,
|
|||
u32 offset)
|
||||
{
|
||||
return _tegra_clk_register_periph(name, parent_names, num_parents,
|
||||
periph, clk_base, offset, false);
|
||||
periph, clk_base, offset, false, CLK_SET_RATE_PARENT);
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -86,8 +86,8 @@
|
|||
#define PLLE_BASE 0xe8
|
||||
#define PLLE_MISC 0xec
|
||||
|
||||
#define PLL_BASE_LOCK 27
|
||||
#define PLLE_MISC_LOCK 11
|
||||
#define PLL_BASE_LOCK BIT(27)
|
||||
#define PLLE_MISC_LOCK BIT(11)
|
||||
|
||||
#define PLL_MISC_LOCK_ENABLE 18
|
||||
#define PLLDU_MISC_LOCK_ENABLE 22
|
||||
|
@ -236,7 +236,7 @@ enum tegra20_clk {
|
|||
dvc, dsi, mipi = 50, hdmi, csi, tvdac, i2c2, uartc, emc = 57, usb2,
|
||||
usb3, mpe, vde, bsea, bsev, speedo, uartd, uarte, i2c3, sbc4, sdmmc3,
|
||||
pex, owr, afi, csite, pcie_xclk, avpucq = 75, la, irama = 84, iramb,
|
||||
iramc, iramd, cram2, audio_2x, clk_d, csus = 92, cdev1, cdev2,
|
||||
iramc, iramd, cram2, audio_2x, clk_d, csus = 92, cdev2, cdev1,
|
||||
uartb = 96, vfir, spdif_in, spdif_out, vi, vi_sensor, tvo, cve,
|
||||
osc, clk_32k, clk_m, sclk, cclk, hclk, pclk, blink, pll_a, pll_a_out0,
|
||||
pll_c, pll_c_out1, pll_d, pll_d_out0, pll_e, pll_m, pll_m_out1,
|
||||
|
@ -248,125 +248,125 @@ static struct clk *clks[clk_max];
|
|||
static struct clk_onecell_data clk_data;
|
||||
|
||||
static struct tegra_clk_pll_freq_table pll_c_freq_table[] = {
|
||||
{ 12000000, 600000000, 600, 12, 1, 8 },
|
||||
{ 13000000, 600000000, 600, 13, 1, 8 },
|
||||
{ 19200000, 600000000, 500, 16, 1, 6 },
|
||||
{ 26000000, 600000000, 600, 26, 1, 8 },
|
||||
{ 12000000, 600000000, 600, 12, 0, 8 },
|
||||
{ 13000000, 600000000, 600, 13, 0, 8 },
|
||||
{ 19200000, 600000000, 500, 16, 0, 6 },
|
||||
{ 26000000, 600000000, 600, 26, 0, 8 },
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
static struct tegra_clk_pll_freq_table pll_m_freq_table[] = {
|
||||
{ 12000000, 666000000, 666, 12, 1, 8},
|
||||
{ 13000000, 666000000, 666, 13, 1, 8},
|
||||
{ 19200000, 666000000, 555, 16, 1, 8},
|
||||
{ 26000000, 666000000, 666, 26, 1, 8},
|
||||
{ 12000000, 600000000, 600, 12, 1, 8},
|
||||
{ 13000000, 600000000, 600, 13, 1, 8},
|
||||
{ 19200000, 600000000, 375, 12, 1, 6},
|
||||
{ 26000000, 600000000, 600, 26, 1, 8},
|
||||
{ 12000000, 666000000, 666, 12, 0, 8},
|
||||
{ 13000000, 666000000, 666, 13, 0, 8},
|
||||
{ 19200000, 666000000, 555, 16, 0, 8},
|
||||
{ 26000000, 666000000, 666, 26, 0, 8},
|
||||
{ 12000000, 600000000, 600, 12, 0, 8},
|
||||
{ 13000000, 600000000, 600, 13, 0, 8},
|
||||
{ 19200000, 600000000, 375, 12, 0, 6},
|
||||
{ 26000000, 600000000, 600, 26, 0, 8},
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
|
||||
{ 12000000, 216000000, 432, 12, 2, 8},
|
||||
{ 13000000, 216000000, 432, 13, 2, 8},
|
||||
{ 19200000, 216000000, 90, 4, 2, 1},
|
||||
{ 26000000, 216000000, 432, 26, 2, 8},
|
||||
{ 12000000, 432000000, 432, 12, 1, 8},
|
||||
{ 13000000, 432000000, 432, 13, 1, 8},
|
||||
{ 19200000, 432000000, 90, 4, 1, 1},
|
||||
{ 26000000, 432000000, 432, 26, 1, 8},
|
||||
{ 12000000, 216000000, 432, 12, 1, 8},
|
||||
{ 13000000, 216000000, 432, 13, 1, 8},
|
||||
{ 19200000, 216000000, 90, 4, 1, 1},
|
||||
{ 26000000, 216000000, 432, 26, 1, 8},
|
||||
{ 12000000, 432000000, 432, 12, 0, 8},
|
||||
{ 13000000, 432000000, 432, 13, 0, 8},
|
||||
{ 19200000, 432000000, 90, 4, 0, 1},
|
||||
{ 26000000, 432000000, 432, 26, 0, 8},
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
|
||||
{ 28800000, 56448000, 49, 25, 1, 1},
|
||||
{ 28800000, 73728000, 64, 25, 1, 1},
|
||||
{ 28800000, 24000000, 5, 6, 1, 1},
|
||||
{ 28800000, 56448000, 49, 25, 0, 1},
|
||||
{ 28800000, 73728000, 64, 25, 0, 1},
|
||||
{ 28800000, 24000000, 5, 6, 0, 1},
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
|
||||
{ 12000000, 216000000, 216, 12, 1, 4},
|
||||
{ 13000000, 216000000, 216, 13, 1, 4},
|
||||
{ 19200000, 216000000, 135, 12, 1, 3},
|
||||
{ 26000000, 216000000, 216, 26, 1, 4},
|
||||
{ 12000000, 216000000, 216, 12, 0, 4},
|
||||
{ 13000000, 216000000, 216, 13, 0, 4},
|
||||
{ 19200000, 216000000, 135, 12, 0, 3},
|
||||
{ 26000000, 216000000, 216, 26, 0, 4},
|
||||
|
||||
{ 12000000, 594000000, 594, 12, 1, 8},
|
||||
{ 13000000, 594000000, 594, 13, 1, 8},
|
||||
{ 19200000, 594000000, 495, 16, 1, 8},
|
||||
{ 26000000, 594000000, 594, 26, 1, 8},
|
||||
{ 12000000, 594000000, 594, 12, 0, 8},
|
||||
{ 13000000, 594000000, 594, 13, 0, 8},
|
||||
{ 19200000, 594000000, 495, 16, 0, 8},
|
||||
{ 26000000, 594000000, 594, 26, 0, 8},
|
||||
|
||||
{ 12000000, 1000000000, 1000, 12, 1, 12},
|
||||
{ 13000000, 1000000000, 1000, 13, 1, 12},
|
||||
{ 19200000, 1000000000, 625, 12, 1, 8},
|
||||
{ 26000000, 1000000000, 1000, 26, 1, 12},
|
||||
{ 12000000, 1000000000, 1000, 12, 0, 12},
|
||||
{ 13000000, 1000000000, 1000, 13, 0, 12},
|
||||
{ 19200000, 1000000000, 625, 12, 0, 8},
|
||||
{ 26000000, 1000000000, 1000, 26, 0, 12},
|
||||
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
|
||||
{ 12000000, 480000000, 960, 12, 2, 0},
|
||||
{ 13000000, 480000000, 960, 13, 2, 0},
|
||||
{ 19200000, 480000000, 200, 4, 2, 0},
|
||||
{ 26000000, 480000000, 960, 26, 2, 0},
|
||||
{ 12000000, 480000000, 960, 12, 0, 0},
|
||||
{ 13000000, 480000000, 960, 13, 0, 0},
|
||||
{ 19200000, 480000000, 200, 4, 0, 0},
|
||||
{ 26000000, 480000000, 960, 26, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
|
||||
/* 1 GHz */
|
||||
{ 12000000, 1000000000, 1000, 12, 1, 12},
|
||||
{ 13000000, 1000000000, 1000, 13, 1, 12},
|
||||
{ 19200000, 1000000000, 625, 12, 1, 8},
|
||||
{ 26000000, 1000000000, 1000, 26, 1, 12},
|
||||
{ 12000000, 1000000000, 1000, 12, 0, 12},
|
||||
{ 13000000, 1000000000, 1000, 13, 0, 12},
|
||||
{ 19200000, 1000000000, 625, 12, 0, 8},
|
||||
{ 26000000, 1000000000, 1000, 26, 0, 12},
|
||||
|
||||
/* 912 MHz */
|
||||
{ 12000000, 912000000, 912, 12, 1, 12},
|
||||
{ 13000000, 912000000, 912, 13, 1, 12},
|
||||
{ 19200000, 912000000, 760, 16, 1, 8},
|
||||
{ 26000000, 912000000, 912, 26, 1, 12},
|
||||
{ 12000000, 912000000, 912, 12, 0, 12},
|
||||
{ 13000000, 912000000, 912, 13, 0, 12},
|
||||
{ 19200000, 912000000, 760, 16, 0, 8},
|
||||
{ 26000000, 912000000, 912, 26, 0, 12},
|
||||
|
||||
/* 816 MHz */
|
||||
{ 12000000, 816000000, 816, 12, 1, 12},
|
||||
{ 13000000, 816000000, 816, 13, 1, 12},
|
||||
{ 19200000, 816000000, 680, 16, 1, 8},
|
||||
{ 26000000, 816000000, 816, 26, 1, 12},
|
||||
{ 12000000, 816000000, 816, 12, 0, 12},
|
||||
{ 13000000, 816000000, 816, 13, 0, 12},
|
||||
{ 19200000, 816000000, 680, 16, 0, 8},
|
||||
{ 26000000, 816000000, 816, 26, 0, 12},
|
||||
|
||||
/* 760 MHz */
|
||||
{ 12000000, 760000000, 760, 12, 1, 12},
|
||||
{ 13000000, 760000000, 760, 13, 1, 12},
|
||||
{ 19200000, 760000000, 950, 24, 1, 8},
|
||||
{ 26000000, 760000000, 760, 26, 1, 12},
|
||||
{ 12000000, 760000000, 760, 12, 0, 12},
|
||||
{ 13000000, 760000000, 760, 13, 0, 12},
|
||||
{ 19200000, 760000000, 950, 24, 0, 8},
|
||||
{ 26000000, 760000000, 760, 26, 0, 12},
|
||||
|
||||
/* 750 MHz */
|
||||
{ 12000000, 750000000, 750, 12, 1, 12},
|
||||
{ 13000000, 750000000, 750, 13, 1, 12},
|
||||
{ 19200000, 750000000, 625, 16, 1, 8},
|
||||
{ 26000000, 750000000, 750, 26, 1, 12},
|
||||
{ 12000000, 750000000, 750, 12, 0, 12},
|
||||
{ 13000000, 750000000, 750, 13, 0, 12},
|
||||
{ 19200000, 750000000, 625, 16, 0, 8},
|
||||
{ 26000000, 750000000, 750, 26, 0, 12},
|
||||
|
||||
/* 608 MHz */
|
||||
{ 12000000, 608000000, 608, 12, 1, 12},
|
||||
{ 13000000, 608000000, 608, 13, 1, 12},
|
||||
{ 19200000, 608000000, 380, 12, 1, 8},
|
||||
{ 26000000, 608000000, 608, 26, 1, 12},
|
||||
{ 12000000, 608000000, 608, 12, 0, 12},
|
||||
{ 13000000, 608000000, 608, 13, 0, 12},
|
||||
{ 19200000, 608000000, 380, 12, 0, 8},
|
||||
{ 26000000, 608000000, 608, 26, 0, 12},
|
||||
|
||||
/* 456 MHz */
|
||||
{ 12000000, 456000000, 456, 12, 1, 12},
|
||||
{ 13000000, 456000000, 456, 13, 1, 12},
|
||||
{ 19200000, 456000000, 380, 16, 1, 8},
|
||||
{ 26000000, 456000000, 456, 26, 1, 12},
|
||||
{ 12000000, 456000000, 456, 12, 0, 12},
|
||||
{ 13000000, 456000000, 456, 13, 0, 12},
|
||||
{ 19200000, 456000000, 380, 16, 0, 8},
|
||||
{ 26000000, 456000000, 456, 26, 0, 12},
|
||||
|
||||
/* 312 MHz */
|
||||
{ 12000000, 312000000, 312, 12, 1, 12},
|
||||
{ 13000000, 312000000, 312, 13, 1, 12},
|
||||
{ 19200000, 312000000, 260, 16, 1, 8},
|
||||
{ 26000000, 312000000, 312, 26, 1, 12},
|
||||
{ 12000000, 312000000, 312, 12, 0, 12},
|
||||
{ 13000000, 312000000, 312, 13, 0, 12},
|
||||
{ 19200000, 312000000, 260, 16, 0, 8},
|
||||
{ 26000000, 312000000, 312, 26, 0, 12},
|
||||
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
|
||||
{ 12000000, 100000000, 200, 24, 1, 0 },
|
||||
{ 12000000, 100000000, 200, 24, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
|
@ -380,7 +380,7 @@ static struct tegra_clk_pll_params pll_c_params = {
|
|||
.vco_max = 1400000000,
|
||||
.base_reg = PLLC_BASE,
|
||||
.misc_reg = PLLC_MISC,
|
||||
.lock_bit_idx = PLL_BASE_LOCK,
|
||||
.lock_mask = PLL_BASE_LOCK,
|
||||
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
|
||||
.lock_delay = 300,
|
||||
};
|
||||
|
@ -394,7 +394,7 @@ static struct tegra_clk_pll_params pll_m_params = {
|
|||
.vco_max = 1200000000,
|
||||
.base_reg = PLLM_BASE,
|
||||
.misc_reg = PLLM_MISC,
|
||||
.lock_bit_idx = PLL_BASE_LOCK,
|
||||
.lock_mask = PLL_BASE_LOCK,
|
||||
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
|
||||
.lock_delay = 300,
|
||||
};
|
||||
|
@ -408,7 +408,7 @@ static struct tegra_clk_pll_params pll_p_params = {
|
|||
.vco_max = 1400000000,
|
||||
.base_reg = PLLP_BASE,
|
||||
.misc_reg = PLLP_MISC,
|
||||
.lock_bit_idx = PLL_BASE_LOCK,
|
||||
.lock_mask = PLL_BASE_LOCK,
|
||||
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
|
||||
.lock_delay = 300,
|
||||
};
|
||||
|
@ -422,7 +422,7 @@ static struct tegra_clk_pll_params pll_a_params = {
|
|||
.vco_max = 1400000000,
|
||||
.base_reg = PLLA_BASE,
|
||||
.misc_reg = PLLA_MISC,
|
||||
.lock_bit_idx = PLL_BASE_LOCK,
|
||||
.lock_mask = PLL_BASE_LOCK,
|
||||
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
|
||||
.lock_delay = 300,
|
||||
};
|
||||
|
@ -436,11 +436,17 @@ static struct tegra_clk_pll_params pll_d_params = {
|
|||
.vco_max = 1000000000,
|
||||
.base_reg = PLLD_BASE,
|
||||
.misc_reg = PLLD_MISC,
|
||||
.lock_bit_idx = PLL_BASE_LOCK,
|
||||
.lock_mask = PLL_BASE_LOCK,
|
||||
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
|
||||
.lock_delay = 1000,
|
||||
};
|
||||
|
||||
static struct pdiv_map pllu_p[] = {
|
||||
{ .pdiv = 1, .hw_val = 1 },
|
||||
{ .pdiv = 2, .hw_val = 0 },
|
||||
{ .pdiv = 0, .hw_val = 0 },
|
||||
};
|
||||
|
||||
static struct tegra_clk_pll_params pll_u_params = {
|
||||
.input_min = 2000000,
|
||||
.input_max = 40000000,
|
||||
|
@ -450,9 +456,10 @@ static struct tegra_clk_pll_params pll_u_params = {
|
|||
.vco_max = 960000000,
|
||||
.base_reg = PLLU_BASE,
|
||||
.misc_reg = PLLU_MISC,
|
||||
.lock_bit_idx = PLL_BASE_LOCK,
|
||||
.lock_mask = PLL_BASE_LOCK,
|
||||
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
|
||||
.lock_delay = 1000,
|
||||
.pdiv_tohw = pllu_p,
|
||||
};
|
||||
|
||||
static struct tegra_clk_pll_params pll_x_params = {
|
||||
|
@ -464,7 +471,7 @@ static struct tegra_clk_pll_params pll_x_params = {
|
|||
.vco_max = 1200000000,
|
||||
.base_reg = PLLX_BASE,
|
||||
.misc_reg = PLLX_MISC,
|
||||
.lock_bit_idx = PLL_BASE_LOCK,
|
||||
.lock_mask = PLL_BASE_LOCK,
|
||||
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
|
||||
.lock_delay = 300,
|
||||
};
|
||||
|
@ -478,7 +485,7 @@ static struct tegra_clk_pll_params pll_e_params = {
|
|||
.vco_max = 0,
|
||||
.base_reg = PLLE_BASE,
|
||||
.misc_reg = PLLE_MISC,
|
||||
.lock_bit_idx = PLLE_MISC_LOCK,
|
||||
.lock_mask = PLLE_MISC_LOCK,
|
||||
.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
|
||||
.lock_delay = 0,
|
||||
};
|
||||
|
@ -711,8 +718,8 @@ static void tegra20_pll_init(void)
|
|||
}
|
||||
|
||||
static const char *cclk_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m",
|
||||
"pll_p_cclk", "pll_p_out4_cclk",
|
||||
"pll_p_out3_cclk", "clk_d", "pll_x" };
|
||||
"pll_p", "pll_p_out4",
|
||||
"pll_p_out3", "clk_d", "pll_x" };
|
||||
static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4",
|
||||
"pll_p_out3", "pll_p_out2", "clk_d",
|
||||
"clk_32k", "pll_m_out1" };
|
||||
|
@ -721,38 +728,6 @@ static void tegra20_super_clk_init(void)
|
|||
{
|
||||
struct clk *clk;
|
||||
|
||||
/*
|
||||
* DIV_U71 dividers for CCLK, these dividers are used only
|
||||
* if parent clock is fixed rate.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Clock input to cclk divided from pll_p using
|
||||
* U71 divider of cclk.
|
||||
*/
|
||||
clk = tegra_clk_register_divider("pll_p_cclk", "pll_p",
|
||||
clk_base + SUPER_CCLK_DIVIDER, 0,
|
||||
TEGRA_DIVIDER_INT, 16, 8, 1, NULL);
|
||||
clk_register_clkdev(clk, "pll_p_cclk", NULL);
|
||||
|
||||
/*
|
||||
* Clock input to cclk divided from pll_p_out3 using
|
||||
* U71 divider of cclk.
|
||||
*/
|
||||
clk = tegra_clk_register_divider("pll_p_out3_cclk", "pll_p_out3",
|
||||
clk_base + SUPER_CCLK_DIVIDER, 0,
|
||||
TEGRA_DIVIDER_INT, 16, 8, 1, NULL);
|
||||
clk_register_clkdev(clk, "pll_p_out3_cclk", NULL);
|
||||
|
||||
/*
|
||||
* Clock input to cclk divided from pll_p_out4 using
|
||||
* U71 divider of cclk.
|
||||
*/
|
||||
clk = tegra_clk_register_divider("pll_p_out4_cclk", "pll_p_out4",
|
||||
clk_base + SUPER_CCLK_DIVIDER, 0,
|
||||
TEGRA_DIVIDER_INT, 16, 8, 1, NULL);
|
||||
clk_register_clkdev(clk, "pll_p_out4_cclk", NULL);
|
||||
|
||||
/* CCLK */
|
||||
clk = tegra_clk_register_super_mux("cclk", cclk_parents,
|
||||
ARRAY_SIZE(cclk_parents), CLK_SET_RATE_PARENT,
|
||||
|
@ -1044,7 +1019,7 @@ static void __init tegra20_periph_clk_init(void)
|
|||
data = &tegra_periph_clk_list[i];
|
||||
clk = tegra_clk_register_periph(data->name, data->parent_names,
|
||||
data->num_parents, &data->periph,
|
||||
clk_base, data->offset);
|
||||
clk_base, data->offset, data->flags);
|
||||
clk_register_clkdev(clk, data->con_id, data->dev_id);
|
||||
clks[data->clk_id] = clk;
|
||||
}
|
||||
|
@ -1279,9 +1254,16 @@ static __initdata struct tegra_clk_init_table init_table[] = {
|
|||
{host1x, pll_c, 150000000, 0},
|
||||
{disp1, pll_p, 600000000, 0},
|
||||
{disp2, pll_p, 600000000, 0},
|
||||
{gr2d, pll_c, 300000000, 0},
|
||||
{gr3d, pll_c, 300000000, 0},
|
||||
{clk_max, clk_max, 0, 0}, /* This MUST be the last entry */
|
||||
};
|
||||
|
||||
static void __init tegra20_clock_apply_init_table(void)
|
||||
{
|
||||
tegra_init_from_table(init_table, clks, clk_max);
|
||||
}
|
||||
|
||||
/*
|
||||
* Some clocks may be used by different drivers depending on the board
|
||||
* configuration. List those here to register them twice in the clock lookup
|
||||
|
@ -1348,7 +1330,7 @@ void __init tegra20_clock_init(struct device_node *np)
|
|||
clk_data.clk_num = ARRAY_SIZE(clks);
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
||||
|
||||
tegra_init_from_table(init_table, clks, clk_max);
|
||||
tegra_clk_apply_init_table = tegra20_clock_apply_init_table;
|
||||
|
||||
tegra_cpu_car_ops = &tegra20_cpu_car_ops;
|
||||
}
|
||||
|
|
|
@ -116,8 +116,8 @@
|
|||
#define PLLDU_MISC_LOCK_ENABLE 22
|
||||
#define PLLE_MISC_LOCK_ENABLE 9
|
||||
|
||||
#define PLL_BASE_LOCK 27
|
||||
#define PLLE_MISC_LOCK 11
|
||||
#define PLL_BASE_LOCK BIT(27)
|
||||
#define PLLE_MISC_LOCK BIT(11)
|
||||
|
||||
#define PLLE_AUX 0x48c
|
||||
#define PLLC_OUT 0x84
|
||||
|
@ -330,7 +330,7 @@ enum tegra30_clk {
|
|||
usb3, mpe, vde, bsea, bsev, speedo, uartd, uarte, i2c3, sbc4, sdmmc3,
|
||||
pcie, owr, afi, csite, pciex, avpucq, la, dtv = 79, ndspeed, i2cslow,
|
||||
dsib, irama = 84, iramb, iramc, iramd, cram2, audio_2x = 90, csus = 92,
|
||||
cdev1, cdev2, cpu_g = 96, cpu_lp, gr3d2, mselect, tsensor, i2s3, i2s4,
|
||||
cdev2, cdev1, cpu_g = 96, cpu_lp, gr3d2, mselect, tsensor, i2s3, i2s4,
|
||||
i2c4, sbc5, sbc6, d_audio, apbif, dam0, dam1, dam2, hda2codec_2x,
|
||||
atomics, audio0_2x, audio1_2x, audio2_2x, audio3_2x, audio4_2x,
|
||||
spdif_2x, actmon, extern1, extern2, extern3, sata_oob, sata, hda,
|
||||
|
@ -374,164 +374,170 @@ static const struct utmi_clk_param utmi_parameters[] = {
|
|||
};
|
||||
|
||||
static struct tegra_clk_pll_freq_table pll_c_freq_table[] = {
|
||||
{ 12000000, 1040000000, 520, 6, 1, 8},
|
||||
{ 13000000, 1040000000, 480, 6, 1, 8},
|
||||
{ 16800000, 1040000000, 495, 8, 1, 8}, /* actual: 1039.5 MHz */
|
||||
{ 19200000, 1040000000, 325, 6, 1, 6},
|
||||
{ 26000000, 1040000000, 520, 13, 1, 8},
|
||||
{ 12000000, 1040000000, 520, 6, 0, 8},
|
||||
{ 13000000, 1040000000, 480, 6, 0, 8},
|
||||
{ 16800000, 1040000000, 495, 8, 0, 8}, /* actual: 1039.5 MHz */
|
||||
{ 19200000, 1040000000, 325, 6, 0, 6},
|
||||
{ 26000000, 1040000000, 520, 13, 0, 8},
|
||||
|
||||
{ 12000000, 832000000, 416, 6, 1, 8},
|
||||
{ 13000000, 832000000, 832, 13, 1, 8},
|
||||
{ 16800000, 832000000, 396, 8, 1, 8}, /* actual: 831.6 MHz */
|
||||
{ 19200000, 832000000, 260, 6, 1, 8},
|
||||
{ 26000000, 832000000, 416, 13, 1, 8},
|
||||
{ 12000000, 832000000, 416, 6, 0, 8},
|
||||
{ 13000000, 832000000, 832, 13, 0, 8},
|
||||
{ 16800000, 832000000, 396, 8, 0, 8}, /* actual: 831.6 MHz */
|
||||
{ 19200000, 832000000, 260, 6, 0, 8},
|
||||
{ 26000000, 832000000, 416, 13, 0, 8},
|
||||
|
||||
{ 12000000, 624000000, 624, 12, 1, 8},
|
||||
{ 13000000, 624000000, 624, 13, 1, 8},
|
||||
{ 16800000, 600000000, 520, 14, 1, 8},
|
||||
{ 19200000, 624000000, 520, 16, 1, 8},
|
||||
{ 26000000, 624000000, 624, 26, 1, 8},
|
||||
{ 12000000, 624000000, 624, 12, 0, 8},
|
||||
{ 13000000, 624000000, 624, 13, 0, 8},
|
||||
{ 16800000, 600000000, 520, 14, 0, 8},
|
||||
{ 19200000, 624000000, 520, 16, 0, 8},
|
||||
{ 26000000, 624000000, 624, 26, 0, 8},
|
||||
|
||||
{ 12000000, 600000000, 600, 12, 1, 8},
|
||||
{ 13000000, 600000000, 600, 13, 1, 8},
|
||||
{ 16800000, 600000000, 500, 14, 1, 8},
|
||||
{ 19200000, 600000000, 375, 12, 1, 6},
|
||||
{ 26000000, 600000000, 600, 26, 1, 8},
|
||||
{ 12000000, 600000000, 600, 12, 0, 8},
|
||||
{ 13000000, 600000000, 600, 13, 0, 8},
|
||||
{ 16800000, 600000000, 500, 14, 0, 8},
|
||||
{ 19200000, 600000000, 375, 12, 0, 6},
|
||||
{ 26000000, 600000000, 600, 26, 0, 8},
|
||||
|
||||
{ 12000000, 520000000, 520, 12, 1, 8},
|
||||
{ 13000000, 520000000, 520, 13, 1, 8},
|
||||
{ 16800000, 520000000, 495, 16, 1, 8}, /* actual: 519.75 MHz */
|
||||
{ 19200000, 520000000, 325, 12, 1, 6},
|
||||
{ 26000000, 520000000, 520, 26, 1, 8},
|
||||
{ 12000000, 520000000, 520, 12, 0, 8},
|
||||
{ 13000000, 520000000, 520, 13, 0, 8},
|
||||
{ 16800000, 520000000, 495, 16, 0, 8}, /* actual: 519.75 MHz */
|
||||
{ 19200000, 520000000, 325, 12, 0, 6},
|
||||
{ 26000000, 520000000, 520, 26, 0, 8},
|
||||
|
||||
{ 12000000, 416000000, 416, 12, 1, 8},
|
||||
{ 13000000, 416000000, 416, 13, 1, 8},
|
||||
{ 16800000, 416000000, 396, 16, 1, 8}, /* actual: 415.8 MHz */
|
||||
{ 19200000, 416000000, 260, 12, 1, 6},
|
||||
{ 26000000, 416000000, 416, 26, 1, 8},
|
||||
{ 12000000, 416000000, 416, 12, 0, 8},
|
||||
{ 13000000, 416000000, 416, 13, 0, 8},
|
||||
{ 16800000, 416000000, 396, 16, 0, 8}, /* actual: 415.8 MHz */
|
||||
{ 19200000, 416000000, 260, 12, 0, 6},
|
||||
{ 26000000, 416000000, 416, 26, 0, 8},
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
static struct tegra_clk_pll_freq_table pll_m_freq_table[] = {
|
||||
{ 12000000, 666000000, 666, 12, 1, 8},
|
||||
{ 13000000, 666000000, 666, 13, 1, 8},
|
||||
{ 16800000, 666000000, 555, 14, 1, 8},
|
||||
{ 19200000, 666000000, 555, 16, 1, 8},
|
||||
{ 26000000, 666000000, 666, 26, 1, 8},
|
||||
{ 12000000, 600000000, 600, 12, 1, 8},
|
||||
{ 13000000, 600000000, 600, 13, 1, 8},
|
||||
{ 16800000, 600000000, 500, 14, 1, 8},
|
||||
{ 19200000, 600000000, 375, 12, 1, 6},
|
||||
{ 26000000, 600000000, 600, 26, 1, 8},
|
||||
{ 12000000, 666000000, 666, 12, 0, 8},
|
||||
{ 13000000, 666000000, 666, 13, 0, 8},
|
||||
{ 16800000, 666000000, 555, 14, 0, 8},
|
||||
{ 19200000, 666000000, 555, 16, 0, 8},
|
||||
{ 26000000, 666000000, 666, 26, 0, 8},
|
||||
{ 12000000, 600000000, 600, 12, 0, 8},
|
||||
{ 13000000, 600000000, 600, 13, 0, 8},
|
||||
{ 16800000, 600000000, 500, 14, 0, 8},
|
||||
{ 19200000, 600000000, 375, 12, 0, 6},
|
||||
{ 26000000, 600000000, 600, 26, 0, 8},
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
|
||||
{ 12000000, 216000000, 432, 12, 2, 8},
|
||||
{ 13000000, 216000000, 432, 13, 2, 8},
|
||||
{ 16800000, 216000000, 360, 14, 2, 8},
|
||||
{ 19200000, 216000000, 360, 16, 2, 8},
|
||||
{ 26000000, 216000000, 432, 26, 2, 8},
|
||||
{ 12000000, 216000000, 432, 12, 1, 8},
|
||||
{ 13000000, 216000000, 432, 13, 1, 8},
|
||||
{ 16800000, 216000000, 360, 14, 1, 8},
|
||||
{ 19200000, 216000000, 360, 16, 1, 8},
|
||||
{ 26000000, 216000000, 432, 26, 1, 8},
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
|
||||
{ 9600000, 564480000, 294, 5, 1, 4},
|
||||
{ 9600000, 552960000, 288, 5, 1, 4},
|
||||
{ 9600000, 24000000, 5, 2, 1, 1},
|
||||
{ 9600000, 564480000, 294, 5, 0, 4},
|
||||
{ 9600000, 552960000, 288, 5, 0, 4},
|
||||
{ 9600000, 24000000, 5, 2, 0, 1},
|
||||
|
||||
{ 28800000, 56448000, 49, 25, 1, 1},
|
||||
{ 28800000, 73728000, 64, 25, 1, 1},
|
||||
{ 28800000, 24000000, 5, 6, 1, 1},
|
||||
{ 28800000, 56448000, 49, 25, 0, 1},
|
||||
{ 28800000, 73728000, 64, 25, 0, 1},
|
||||
{ 28800000, 24000000, 5, 6, 0, 1},
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
|
||||
{ 12000000, 216000000, 216, 12, 1, 4},
|
||||
{ 13000000, 216000000, 216, 13, 1, 4},
|
||||
{ 16800000, 216000000, 180, 14, 1, 4},
|
||||
{ 19200000, 216000000, 180, 16, 1, 4},
|
||||
{ 26000000, 216000000, 216, 26, 1, 4},
|
||||
{ 12000000, 216000000, 216, 12, 0, 4},
|
||||
{ 13000000, 216000000, 216, 13, 0, 4},
|
||||
{ 16800000, 216000000, 180, 14, 0, 4},
|
||||
{ 19200000, 216000000, 180, 16, 0, 4},
|
||||
{ 26000000, 216000000, 216, 26, 0, 4},
|
||||
|
||||
{ 12000000, 594000000, 594, 12, 1, 8},
|
||||
{ 13000000, 594000000, 594, 13, 1, 8},
|
||||
{ 16800000, 594000000, 495, 14, 1, 8},
|
||||
{ 19200000, 594000000, 495, 16, 1, 8},
|
||||
{ 26000000, 594000000, 594, 26, 1, 8},
|
||||
{ 12000000, 594000000, 594, 12, 0, 8},
|
||||
{ 13000000, 594000000, 594, 13, 0, 8},
|
||||
{ 16800000, 594000000, 495, 14, 0, 8},
|
||||
{ 19200000, 594000000, 495, 16, 0, 8},
|
||||
{ 26000000, 594000000, 594, 26, 0, 8},
|
||||
|
||||
{ 12000000, 1000000000, 1000, 12, 1, 12},
|
||||
{ 13000000, 1000000000, 1000, 13, 1, 12},
|
||||
{ 19200000, 1000000000, 625, 12, 1, 8},
|
||||
{ 26000000, 1000000000, 1000, 26, 1, 12},
|
||||
{ 12000000, 1000000000, 1000, 12, 0, 12},
|
||||
{ 13000000, 1000000000, 1000, 13, 0, 12},
|
||||
{ 19200000, 1000000000, 625, 12, 0, 8},
|
||||
{ 26000000, 1000000000, 1000, 26, 0, 12},
|
||||
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
static struct pdiv_map pllu_p[] = {
|
||||
{ .pdiv = 1, .hw_val = 1 },
|
||||
{ .pdiv = 2, .hw_val = 0 },
|
||||
{ .pdiv = 0, .hw_val = 0 },
|
||||
};
|
||||
|
||||
static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
|
||||
{ 12000000, 480000000, 960, 12, 2, 12},
|
||||
{ 13000000, 480000000, 960, 13, 2, 12},
|
||||
{ 16800000, 480000000, 400, 7, 2, 5},
|
||||
{ 19200000, 480000000, 200, 4, 2, 3},
|
||||
{ 26000000, 480000000, 960, 26, 2, 12},
|
||||
{ 12000000, 480000000, 960, 12, 0, 12},
|
||||
{ 13000000, 480000000, 960, 13, 0, 12},
|
||||
{ 16800000, 480000000, 400, 7, 0, 5},
|
||||
{ 19200000, 480000000, 200, 4, 0, 3},
|
||||
{ 26000000, 480000000, 960, 26, 0, 12},
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
|
||||
/* 1.7 GHz */
|
||||
{ 12000000, 1700000000, 850, 6, 1, 8},
|
||||
{ 13000000, 1700000000, 915, 7, 1, 8}, /* actual: 1699.2 MHz */
|
||||
{ 16800000, 1700000000, 708, 7, 1, 8}, /* actual: 1699.2 MHz */
|
||||
{ 19200000, 1700000000, 885, 10, 1, 8}, /* actual: 1699.2 MHz */
|
||||
{ 26000000, 1700000000, 850, 13, 1, 8},
|
||||
{ 12000000, 1700000000, 850, 6, 0, 8},
|
||||
{ 13000000, 1700000000, 915, 7, 0, 8}, /* actual: 1699.2 MHz */
|
||||
{ 16800000, 1700000000, 708, 7, 0, 8}, /* actual: 1699.2 MHz */
|
||||
{ 19200000, 1700000000, 885, 10, 0, 8}, /* actual: 1699.2 MHz */
|
||||
{ 26000000, 1700000000, 850, 13, 0, 8},
|
||||
|
||||
/* 1.6 GHz */
|
||||
{ 12000000, 1600000000, 800, 6, 1, 8},
|
||||
{ 13000000, 1600000000, 738, 6, 1, 8}, /* actual: 1599.0 MHz */
|
||||
{ 16800000, 1600000000, 857, 9, 1, 8}, /* actual: 1599.7 MHz */
|
||||
{ 19200000, 1600000000, 500, 6, 1, 8},
|
||||
{ 26000000, 1600000000, 800, 13, 1, 8},
|
||||
{ 12000000, 1600000000, 800, 6, 0, 8},
|
||||
{ 13000000, 1600000000, 738, 6, 0, 8}, /* actual: 1599.0 MHz */
|
||||
{ 16800000, 1600000000, 857, 9, 0, 8}, /* actual: 1599.7 MHz */
|
||||
{ 19200000, 1600000000, 500, 6, 0, 8},
|
||||
{ 26000000, 1600000000, 800, 13, 0, 8},
|
||||
|
||||
/* 1.5 GHz */
|
||||
{ 12000000, 1500000000, 750, 6, 1, 8},
|
||||
{ 13000000, 1500000000, 923, 8, 1, 8}, /* actual: 1499.8 MHz */
|
||||
{ 16800000, 1500000000, 625, 7, 1, 8},
|
||||
{ 19200000, 1500000000, 625, 8, 1, 8},
|
||||
{ 26000000, 1500000000, 750, 13, 1, 8},
|
||||
{ 12000000, 1500000000, 750, 6, 0, 8},
|
||||
{ 13000000, 1500000000, 923, 8, 0, 8}, /* actual: 1499.8 MHz */
|
||||
{ 16800000, 1500000000, 625, 7, 0, 8},
|
||||
{ 19200000, 1500000000, 625, 8, 0, 8},
|
||||
{ 26000000, 1500000000, 750, 13, 0, 8},
|
||||
|
||||
/* 1.4 GHz */
|
||||
{ 12000000, 1400000000, 700, 6, 1, 8},
|
||||
{ 13000000, 1400000000, 969, 9, 1, 8}, /* actual: 1399.7 MHz */
|
||||
{ 16800000, 1400000000, 1000, 12, 1, 8},
|
||||
{ 19200000, 1400000000, 875, 12, 1, 8},
|
||||
{ 26000000, 1400000000, 700, 13, 1, 8},
|
||||
{ 12000000, 1400000000, 700, 6, 0, 8},
|
||||
{ 13000000, 1400000000, 969, 9, 0, 8}, /* actual: 1399.7 MHz */
|
||||
{ 16800000, 1400000000, 1000, 12, 0, 8},
|
||||
{ 19200000, 1400000000, 875, 12, 0, 8},
|
||||
{ 26000000, 1400000000, 700, 13, 0, 8},
|
||||
|
||||
/* 1.3 GHz */
|
||||
{ 12000000, 1300000000, 975, 9, 1, 8},
|
||||
{ 13000000, 1300000000, 1000, 10, 1, 8},
|
||||
{ 16800000, 1300000000, 928, 12, 1, 8}, /* actual: 1299.2 MHz */
|
||||
{ 19200000, 1300000000, 812, 12, 1, 8}, /* actual: 1299.2 MHz */
|
||||
{ 26000000, 1300000000, 650, 13, 1, 8},
|
||||
{ 12000000, 1300000000, 975, 9, 0, 8},
|
||||
{ 13000000, 1300000000, 1000, 10, 0, 8},
|
||||
{ 16800000, 1300000000, 928, 12, 0, 8}, /* actual: 1299.2 MHz */
|
||||
{ 19200000, 1300000000, 812, 12, 0, 8}, /* actual: 1299.2 MHz */
|
||||
{ 26000000, 1300000000, 650, 13, 0, 8},
|
||||
|
||||
/* 1.2 GHz */
|
||||
{ 12000000, 1200000000, 1000, 10, 1, 8},
|
||||
{ 13000000, 1200000000, 923, 10, 1, 8}, /* actual: 1199.9 MHz */
|
||||
{ 16800000, 1200000000, 1000, 14, 1, 8},
|
||||
{ 19200000, 1200000000, 1000, 16, 1, 8},
|
||||
{ 26000000, 1200000000, 600, 13, 1, 8},
|
||||
{ 12000000, 1200000000, 1000, 10, 0, 8},
|
||||
{ 13000000, 1200000000, 923, 10, 0, 8}, /* actual: 1199.9 MHz */
|
||||
{ 16800000, 1200000000, 1000, 14, 0, 8},
|
||||
{ 19200000, 1200000000, 1000, 16, 0, 8},
|
||||
{ 26000000, 1200000000, 600, 13, 0, 8},
|
||||
|
||||
/* 1.1 GHz */
|
||||
{ 12000000, 1100000000, 825, 9, 1, 8},
|
||||
{ 13000000, 1100000000, 846, 10, 1, 8}, /* actual: 1099.8 MHz */
|
||||
{ 16800000, 1100000000, 982, 15, 1, 8}, /* actual: 1099.8 MHz */
|
||||
{ 19200000, 1100000000, 859, 15, 1, 8}, /* actual: 1099.5 MHz */
|
||||
{ 26000000, 1100000000, 550, 13, 1, 8},
|
||||
{ 12000000, 1100000000, 825, 9, 0, 8},
|
||||
{ 13000000, 1100000000, 846, 10, 0, 8}, /* actual: 1099.8 MHz */
|
||||
{ 16800000, 1100000000, 982, 15, 0, 8}, /* actual: 1099.8 MHz */
|
||||
{ 19200000, 1100000000, 859, 15, 0, 8}, /* actual: 1099.5 MHz */
|
||||
{ 26000000, 1100000000, 550, 13, 0, 8},
|
||||
|
||||
/* 1 GHz */
|
||||
{ 12000000, 1000000000, 1000, 12, 1, 8},
|
||||
{ 13000000, 1000000000, 1000, 13, 1, 8},
|
||||
{ 16800000, 1000000000, 833, 14, 1, 8}, /* actual: 999.6 MHz */
|
||||
{ 19200000, 1000000000, 625, 12, 1, 8},
|
||||
{ 26000000, 1000000000, 1000, 26, 1, 8},
|
||||
{ 12000000, 1000000000, 1000, 12, 0, 8},
|
||||
{ 13000000, 1000000000, 1000, 13, 0, 8},
|
||||
{ 16800000, 1000000000, 833, 14, 0, 8}, /* actual: 999.6 MHz */
|
||||
{ 19200000, 1000000000, 625, 12, 0, 8},
|
||||
{ 26000000, 1000000000, 1000, 26, 0, 8},
|
||||
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
@ -553,7 +559,7 @@ static struct tegra_clk_pll_params pll_c_params = {
|
|||
.vco_max = 1400000000,
|
||||
.base_reg = PLLC_BASE,
|
||||
.misc_reg = PLLC_MISC,
|
||||
.lock_bit_idx = PLL_BASE_LOCK,
|
||||
.lock_mask = PLL_BASE_LOCK,
|
||||
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
|
||||
.lock_delay = 300,
|
||||
};
|
||||
|
@ -567,7 +573,7 @@ static struct tegra_clk_pll_params pll_m_params = {
|
|||
.vco_max = 1200000000,
|
||||
.base_reg = PLLM_BASE,
|
||||
.misc_reg = PLLM_MISC,
|
||||
.lock_bit_idx = PLL_BASE_LOCK,
|
||||
.lock_mask = PLL_BASE_LOCK,
|
||||
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
|
||||
.lock_delay = 300,
|
||||
};
|
||||
|
@ -581,7 +587,7 @@ static struct tegra_clk_pll_params pll_p_params = {
|
|||
.vco_max = 1400000000,
|
||||
.base_reg = PLLP_BASE,
|
||||
.misc_reg = PLLP_MISC,
|
||||
.lock_bit_idx = PLL_BASE_LOCK,
|
||||
.lock_mask = PLL_BASE_LOCK,
|
||||
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
|
||||
.lock_delay = 300,
|
||||
};
|
||||
|
@ -595,7 +601,7 @@ static struct tegra_clk_pll_params pll_a_params = {
|
|||
.vco_max = 1400000000,
|
||||
.base_reg = PLLA_BASE,
|
||||
.misc_reg = PLLA_MISC,
|
||||
.lock_bit_idx = PLL_BASE_LOCK,
|
||||
.lock_mask = PLL_BASE_LOCK,
|
||||
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
|
||||
.lock_delay = 300,
|
||||
};
|
||||
|
@ -609,7 +615,7 @@ static struct tegra_clk_pll_params pll_d_params = {
|
|||
.vco_max = 1000000000,
|
||||
.base_reg = PLLD_BASE,
|
||||
.misc_reg = PLLD_MISC,
|
||||
.lock_bit_idx = PLL_BASE_LOCK,
|
||||
.lock_mask = PLL_BASE_LOCK,
|
||||
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
|
||||
.lock_delay = 1000,
|
||||
};
|
||||
|
@ -623,7 +629,7 @@ static struct tegra_clk_pll_params pll_d2_params = {
|
|||
.vco_max = 1000000000,
|
||||
.base_reg = PLLD2_BASE,
|
||||
.misc_reg = PLLD2_MISC,
|
||||
.lock_bit_idx = PLL_BASE_LOCK,
|
||||
.lock_mask = PLL_BASE_LOCK,
|
||||
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
|
||||
.lock_delay = 1000,
|
||||
};
|
||||
|
@ -637,9 +643,10 @@ static struct tegra_clk_pll_params pll_u_params = {
|
|||
.vco_max = 960000000,
|
||||
.base_reg = PLLU_BASE,
|
||||
.misc_reg = PLLU_MISC,
|
||||
.lock_bit_idx = PLL_BASE_LOCK,
|
||||
.lock_mask = PLL_BASE_LOCK,
|
||||
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
|
||||
.lock_delay = 1000,
|
||||
.pdiv_tohw = pllu_p,
|
||||
};
|
||||
|
||||
static struct tegra_clk_pll_params pll_x_params = {
|
||||
|
@ -651,7 +658,7 @@ static struct tegra_clk_pll_params pll_x_params = {
|
|||
.vco_max = 1700000000,
|
||||
.base_reg = PLLX_BASE,
|
||||
.misc_reg = PLLX_MISC,
|
||||
.lock_bit_idx = PLL_BASE_LOCK,
|
||||
.lock_mask = PLL_BASE_LOCK,
|
||||
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
|
||||
.lock_delay = 300,
|
||||
};
|
||||
|
@ -665,7 +672,7 @@ static struct tegra_clk_pll_params pll_e_params = {
|
|||
.vco_max = 2400000000U,
|
||||
.base_reg = PLLE_BASE,
|
||||
.misc_reg = PLLE_MISC,
|
||||
.lock_bit_idx = PLLE_MISC_LOCK,
|
||||
.lock_mask = PLLE_MISC_LOCK,
|
||||
.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
|
||||
.lock_delay = 300,
|
||||
};
|
||||
|
@ -1661,7 +1668,7 @@ static void __init tegra30_periph_clk_init(void)
|
|||
data = &tegra_periph_clk_list[i];
|
||||
clk = tegra_clk_register_periph(data->name, data->parent_names,
|
||||
data->num_parents, &data->periph,
|
||||
clk_base, data->offset);
|
||||
clk_base, data->offset, data->flags);
|
||||
clk_register_clkdev(clk, data->con_id, data->dev_id);
|
||||
clks[data->clk_id] = clk;
|
||||
}
|
||||
|
@ -1911,9 +1918,16 @@ static __initdata struct tegra_clk_init_table init_table[] = {
|
|||
{disp1, pll_p, 600000000, 0},
|
||||
{disp2, pll_p, 600000000, 0},
|
||||
{twd, clk_max, 0, 1},
|
||||
{gr2d, pll_c, 300000000, 0},
|
||||
{gr3d, pll_c, 300000000, 0},
|
||||
{clk_max, clk_max, 0, 0}, /* This MUST be the last entry. */
|
||||
};
|
||||
|
||||
static void __init tegra30_clock_apply_init_table(void)
|
||||
{
|
||||
tegra_init_from_table(init_table, clks, clk_max);
|
||||
}
|
||||
|
||||
/*
|
||||
* Some clocks may be used by different drivers depending on the board
|
||||
* configuration. List those here to register them twice in the clock lookup
|
||||
|
@ -1987,7 +2001,7 @@ void __init tegra30_clock_init(struct device_node *np)
|
|||
clk_data.clk_num = ARRAY_SIZE(clks);
|
||||
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
||||
|
||||
tegra_init_from_table(init_table, clks, clk_max);
|
||||
tegra_clk_apply_init_table = tegra30_clock_apply_init_table;
|
||||
|
||||
tegra_cpu_car_ops = &tegra30_cpu_car_ops;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
#include "clk.h"
|
||||
|
||||
/* Global data of Tegra CPU CAR ops */
|
||||
struct tegra_cpu_car_ops *tegra_cpu_car_ops;
|
||||
static struct tegra_cpu_car_ops dummy_car_ops;
|
||||
struct tegra_cpu_car_ops *tegra_cpu_car_ops = &dummy_car_ops;
|
||||
|
||||
void __init tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list,
|
||||
struct clk *clks[], int clk_max)
|
||||
|
@ -76,6 +77,7 @@ void __init tegra_init_from_table(struct tegra_clk_init_table *tbl,
|
|||
static const struct of_device_id tegra_dt_clk_match[] = {
|
||||
{ .compatible = "nvidia,tegra20-car", .data = tegra20_clock_init },
|
||||
{ .compatible = "nvidia,tegra30-car", .data = tegra30_clock_init },
|
||||
{ .compatible = "nvidia,tegra114-car", .data = tegra114_clock_init },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -83,3 +85,13 @@ void __init tegra_clocks_init(void)
|
|||
{
|
||||
of_clk_init(tegra_dt_clk_match);
|
||||
}
|
||||
|
||||
tegra_clk_apply_init_table_func tegra_clk_apply_init_table;
|
||||
|
||||
void __init tegra_clocks_apply_init_table(void)
|
||||
{
|
||||
if (!tegra_clk_apply_init_table)
|
||||
return;
|
||||
|
||||
tegra_clk_apply_init_table();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
@ -116,6 +116,17 @@ struct tegra_clk_pll_freq_table {
|
|||
u8 cpcon;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct pdiv_map - map post divider to hw value
|
||||
*
|
||||
* @pdiv: post divider
|
||||
* @hw_val: value to be written to the PLL hw
|
||||
*/
|
||||
struct pdiv_map {
|
||||
u8 pdiv;
|
||||
u8 hw_val;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct clk_pll_params - PLL parameters
|
||||
*
|
||||
|
@ -143,9 +154,18 @@ struct tegra_clk_pll_params {
|
|||
u32 base_reg;
|
||||
u32 misc_reg;
|
||||
u32 lock_reg;
|
||||
u32 lock_bit_idx;
|
||||
u32 lock_mask;
|
||||
u32 lock_enable_bit_idx;
|
||||
u32 iddq_reg;
|
||||
u32 iddq_bit_idx;
|
||||
u32 aux_reg;
|
||||
u32 dyn_ramp_reg;
|
||||
u32 ext_misc_reg[3];
|
||||
int stepa_shift;
|
||||
int stepb_shift;
|
||||
int lock_delay;
|
||||
int max_p;
|
||||
struct pdiv_map *pdiv_tohw;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -182,12 +202,16 @@ struct tegra_clk_pll_params {
|
|||
* TEGRA_PLL_FIXED - We are not supposed to change output frequency
|
||||
* of some plls.
|
||||
* TEGRA_PLLE_CONFIGURE - Configure PLLE when enabling.
|
||||
* TEGRA_PLL_LOCK_MISC - Lock bit is in the misc register instead of the
|
||||
* base register.
|
||||
* TEGRA_PLL_BYPASS - PLL has bypass bit
|
||||
* TEGRA_PLL_HAS_LOCK_ENABLE - PLL has bit to enable lock monitoring
|
||||
*/
|
||||
struct tegra_clk_pll {
|
||||
struct clk_hw hw;
|
||||
void __iomem *clk_base;
|
||||
void __iomem *pmc;
|
||||
u8 flags;
|
||||
u32 flags;
|
||||
unsigned long fixed_rate;
|
||||
spinlock_t *lock;
|
||||
u8 divn_shift;
|
||||
|
@ -210,20 +234,64 @@ struct tegra_clk_pll {
|
|||
#define TEGRA_PLLM BIT(5)
|
||||
#define TEGRA_PLL_FIXED BIT(6)
|
||||
#define TEGRA_PLLE_CONFIGURE BIT(7)
|
||||
#define TEGRA_PLL_LOCK_MISC BIT(8)
|
||||
#define TEGRA_PLL_BYPASS BIT(9)
|
||||
#define TEGRA_PLL_HAS_LOCK_ENABLE BIT(10)
|
||||
|
||||
extern const struct clk_ops tegra_clk_pll_ops;
|
||||
extern const struct clk_ops tegra_clk_plle_ops;
|
||||
struct clk *tegra_clk_register_pll(const char *name, const char *parent_name,
|
||||
void __iomem *clk_base, void __iomem *pmc,
|
||||
unsigned long flags, unsigned long fixed_rate,
|
||||
struct tegra_clk_pll_params *pll_params, u8 pll_flags,
|
||||
struct tegra_clk_pll_params *pll_params, u32 pll_flags,
|
||||
struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock);
|
||||
|
||||
struct clk *tegra_clk_register_plle(const char *name, const char *parent_name,
|
||||
void __iomem *clk_base, void __iomem *pmc,
|
||||
unsigned long flags, unsigned long fixed_rate,
|
||||
struct tegra_clk_pll_params *pll_params, u8 pll_flags,
|
||||
struct tegra_clk_pll_params *pll_params, u32 pll_flags,
|
||||
struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock);
|
||||
|
||||
struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name,
|
||||
void __iomem *clk_base, void __iomem *pmc,
|
||||
unsigned long flags, unsigned long fixed_rate,
|
||||
struct tegra_clk_pll_params *pll_params,
|
||||
u32 pll_flags,
|
||||
struct tegra_clk_pll_freq_table *freq_table,
|
||||
spinlock_t *lock);
|
||||
|
||||
struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name,
|
||||
void __iomem *clk_base, void __iomem *pmc,
|
||||
unsigned long flags, unsigned long fixed_rate,
|
||||
struct tegra_clk_pll_params *pll_params,
|
||||
u32 pll_flags,
|
||||
struct tegra_clk_pll_freq_table *freq_table,
|
||||
spinlock_t *lock);
|
||||
|
||||
struct clk *tegra_clk_register_pllc(const char *name, const char *parent_name,
|
||||
void __iomem *clk_base, void __iomem *pmc,
|
||||
unsigned long flags, unsigned long fixed_rate,
|
||||
struct tegra_clk_pll_params *pll_params,
|
||||
u32 pll_flags,
|
||||
struct tegra_clk_pll_freq_table *freq_table,
|
||||
spinlock_t *lock);
|
||||
|
||||
struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name,
|
||||
void __iomem *clk_base, void __iomem *pmc,
|
||||
unsigned long flags, unsigned long fixed_rate,
|
||||
struct tegra_clk_pll_params *pll_params,
|
||||
u32 pll_flags,
|
||||
struct tegra_clk_pll_freq_table *freq_table,
|
||||
spinlock_t *lock, unsigned long parent_rate);
|
||||
|
||||
struct clk *tegra_clk_register_plle_tegra114(const char *name,
|
||||
const char *parent_name,
|
||||
void __iomem *clk_base, unsigned long flags,
|
||||
unsigned long fixed_rate,
|
||||
struct tegra_clk_pll_params *pll_params,
|
||||
struct tegra_clk_pll_freq_table *freq_table,
|
||||
spinlock_t *lock);
|
||||
|
||||
/**
|
||||
* struct tegra_clk_pll_out - PLL divider down clock
|
||||
*
|
||||
|
@ -290,6 +358,7 @@ struct tegra_clk_periph_regs {
|
|||
* TEGRA_PERIPH_ON_APB - If peripheral is in the APB bus then read the
|
||||
* bus to flush the write operation in apb bus. This flag indicates
|
||||
* that this peripheral is in apb bus.
|
||||
* TEGRA_PERIPH_WAR_1005168 - Apply workaround for Tegra114 MSENC bug
|
||||
*/
|
||||
struct tegra_clk_periph_gate {
|
||||
u32 magic;
|
||||
|
@ -309,6 +378,7 @@ struct tegra_clk_periph_gate {
|
|||
#define TEGRA_PERIPH_NO_RESET BIT(0)
|
||||
#define TEGRA_PERIPH_MANUAL_RESET BIT(1)
|
||||
#define TEGRA_PERIPH_ON_APB BIT(2)
|
||||
#define TEGRA_PERIPH_WAR_1005168 BIT(3)
|
||||
|
||||
void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert);
|
||||
extern const struct clk_ops tegra_clk_periph_gate_ops;
|
||||
|
@ -349,21 +419,22 @@ extern const struct clk_ops tegra_clk_periph_ops;
|
|||
struct clk *tegra_clk_register_periph(const char *name,
|
||||
const char **parent_names, int num_parents,
|
||||
struct tegra_clk_periph *periph, void __iomem *clk_base,
|
||||
u32 offset);
|
||||
u32 offset, unsigned long flags);
|
||||
struct clk *tegra_clk_register_periph_nodiv(const char *name,
|
||||
const char **parent_names, int num_parents,
|
||||
struct tegra_clk_periph *periph, void __iomem *clk_base,
|
||||
u32 offset);
|
||||
|
||||
#define TEGRA_CLK_PERIPH(_mux_shift, _mux_width, _mux_flags, \
|
||||
#define TEGRA_CLK_PERIPH(_mux_shift, _mux_mask, _mux_flags, \
|
||||
_div_shift, _div_width, _div_frac_width, \
|
||||
_div_flags, _clk_num, _enb_refcnt, _regs, \
|
||||
_gate_flags) \
|
||||
_gate_flags, _table) \
|
||||
{ \
|
||||
.mux = { \
|
||||
.flags = _mux_flags, \
|
||||
.shift = _mux_shift, \
|
||||
.width = _mux_width, \
|
||||
.mask = _mux_mask, \
|
||||
.table = _table, \
|
||||
}, \
|
||||
.divider = { \
|
||||
.flags = _div_flags, \
|
||||
|
@ -391,28 +462,41 @@ struct tegra_periph_init_data {
|
|||
u32 offset;
|
||||
const char *con_id;
|
||||
const char *dev_id;
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
#define TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parent_names, _offset, \
|
||||
_mux_shift, _mux_width, _mux_flags, _div_shift, \
|
||||
#define TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parent_names, _offset,\
|
||||
_mux_shift, _mux_mask, _mux_flags, _div_shift, \
|
||||
_div_width, _div_frac_width, _div_flags, _regs, \
|
||||
_clk_num, _enb_refcnt, _gate_flags, _clk_id) \
|
||||
_clk_num, _enb_refcnt, _gate_flags, _clk_id, _table,\
|
||||
_flags) \
|
||||
{ \
|
||||
.name = _name, \
|
||||
.clk_id = _clk_id, \
|
||||
.parent_names = _parent_names, \
|
||||
.num_parents = ARRAY_SIZE(_parent_names), \
|
||||
.periph = TEGRA_CLK_PERIPH(_mux_shift, _mux_width, \
|
||||
.periph = TEGRA_CLK_PERIPH(_mux_shift, _mux_mask, \
|
||||
_mux_flags, _div_shift, \
|
||||
_div_width, _div_frac_width, \
|
||||
_div_flags, _clk_num, \
|
||||
_enb_refcnt, _regs, \
|
||||
_gate_flags), \
|
||||
_gate_flags, _table), \
|
||||
.offset = _offset, \
|
||||
.con_id = _con_id, \
|
||||
.dev_id = _dev_id, \
|
||||
.flags = _flags \
|
||||
}
|
||||
|
||||
#define TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parent_names, _offset,\
|
||||
_mux_shift, _mux_width, _mux_flags, _div_shift, \
|
||||
_div_width, _div_frac_width, _div_flags, _regs, \
|
||||
_clk_num, _enb_refcnt, _gate_flags, _clk_id) \
|
||||
TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parent_names, _offset,\
|
||||
_mux_shift, BIT(_mux_width) - 1, _mux_flags, \
|
||||
_div_shift, _div_width, _div_frac_width, _div_flags, \
|
||||
_regs, _clk_num, _enb_refcnt, _gate_flags, _clk_id,\
|
||||
NULL, 0)
|
||||
|
||||
/**
|
||||
* struct clk_super_mux - super clock
|
||||
*
|
||||
|
@ -499,4 +583,13 @@ void tegra30_clock_init(struct device_node *np);
|
|||
static inline void tegra30_clock_init(struct device_node *np) {}
|
||||
#endif /* CONFIG_ARCH_TEGRA_3x_SOC */
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_114_SOC
|
||||
void tegra114_clock_init(struct device_node *np);
|
||||
#else
|
||||
static inline void tegra114_clock_init(struct device_node *np) {}
|
||||
#endif /* CONFIG_ARCH_TEGRA114_SOC */
|
||||
|
||||
typedef void (*tegra_clk_apply_init_table_func)(void);
|
||||
extern tegra_clk_apply_init_table_func tegra_clk_apply_init_table;
|
||||
|
||||
#endif /* TEGRA_CLK_H */
|
||||
|
|
|
@ -20,15 +20,23 @@
|
|||
struct clk_prcmu {
|
||||
struct clk_hw hw;
|
||||
u8 cg_sel;
|
||||
int is_prepared;
|
||||
int is_enabled;
|
||||
int opp_requested;
|
||||
};
|
||||
|
||||
/* PRCMU clock operations. */
|
||||
|
||||
static int clk_prcmu_prepare(struct clk_hw *hw)
|
||||
{
|
||||
int ret;
|
||||
struct clk_prcmu *clk = to_clk_prcmu(hw);
|
||||
return prcmu_request_clock(clk->cg_sel, true);
|
||||
|
||||
ret = prcmu_request_clock(clk->cg_sel, true);
|
||||
if (!ret)
|
||||
clk->is_prepared = 1;
|
||||
|
||||
return ret;;
|
||||
}
|
||||
|
||||
static void clk_prcmu_unprepare(struct clk_hw *hw)
|
||||
|
@ -36,7 +44,15 @@ static void clk_prcmu_unprepare(struct clk_hw *hw)
|
|||
struct clk_prcmu *clk = to_clk_prcmu(hw);
|
||||
if (prcmu_request_clock(clk->cg_sel, false))
|
||||
pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
|
||||
hw->init->name);
|
||||
__clk_get_name(hw->clk));
|
||||
else
|
||||
clk->is_prepared = 0;
|
||||
}
|
||||
|
||||
static int clk_prcmu_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_prcmu *clk = to_clk_prcmu(hw);
|
||||
return clk->is_prepared;
|
||||
}
|
||||
|
||||
static int clk_prcmu_enable(struct clk_hw *hw)
|
||||
|
@ -79,58 +95,52 @@ static int clk_prcmu_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
return prcmu_set_clock_rate(clk->cg_sel, rate);
|
||||
}
|
||||
|
||||
static int request_ape_opp100(bool enable)
|
||||
{
|
||||
static int reqs;
|
||||
int err = 0;
|
||||
|
||||
if (enable) {
|
||||
if (!reqs)
|
||||
err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP,
|
||||
"clock", 100);
|
||||
if (!err)
|
||||
reqs++;
|
||||
} else {
|
||||
reqs--;
|
||||
if (!reqs)
|
||||
prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
|
||||
"clock");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int clk_prcmu_opp_prepare(struct clk_hw *hw)
|
||||
{
|
||||
int err;
|
||||
struct clk_prcmu *clk = to_clk_prcmu(hw);
|
||||
|
||||
err = request_ape_opp100(true);
|
||||
if (err) {
|
||||
pr_err("clk_prcmu: %s failed to request APE OPP100 for %s.\n",
|
||||
__func__, hw->init->name);
|
||||
return err;
|
||||
if (!clk->opp_requested) {
|
||||
err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP,
|
||||
(char *)__clk_get_name(hw->clk),
|
||||
100);
|
||||
if (err) {
|
||||
pr_err("clk_prcmu: %s fail req APE OPP for %s.\n",
|
||||
__func__, __clk_get_name(hw->clk));
|
||||
return err;
|
||||
}
|
||||
clk->opp_requested = 1;
|
||||
}
|
||||
|
||||
err = prcmu_request_clock(clk->cg_sel, true);
|
||||
if (err)
|
||||
request_ape_opp100(false);
|
||||
if (err) {
|
||||
prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
|
||||
(char *)__clk_get_name(hw->clk));
|
||||
clk->opp_requested = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
clk->is_prepared = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_prcmu_opp_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_prcmu *clk = to_clk_prcmu(hw);
|
||||
|
||||
if (prcmu_request_clock(clk->cg_sel, false))
|
||||
goto out_error;
|
||||
if (request_ape_opp100(false))
|
||||
goto out_error;
|
||||
return;
|
||||
if (prcmu_request_clock(clk->cg_sel, false)) {
|
||||
pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
|
||||
__clk_get_name(hw->clk));
|
||||
return;
|
||||
}
|
||||
|
||||
out_error:
|
||||
pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
|
||||
hw->init->name);
|
||||
if (clk->opp_requested) {
|
||||
prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
|
||||
(char *)__clk_get_name(hw->clk));
|
||||
clk->opp_requested = 0;
|
||||
}
|
||||
|
||||
clk->is_prepared = 0;
|
||||
}
|
||||
|
||||
static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw)
|
||||
|
@ -138,38 +148,49 @@ static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw)
|
|||
int err;
|
||||
struct clk_prcmu *clk = to_clk_prcmu(hw);
|
||||
|
||||
err = prcmu_request_ape_opp_100_voltage(true);
|
||||
if (err) {
|
||||
pr_err("clk_prcmu: %s failed to request APE OPP VOLT for %s.\n",
|
||||
__func__, hw->init->name);
|
||||
return err;
|
||||
if (!clk->opp_requested) {
|
||||
err = prcmu_request_ape_opp_100_voltage(true);
|
||||
if (err) {
|
||||
pr_err("clk_prcmu: %s fail req APE OPP VOLT for %s.\n",
|
||||
__func__, __clk_get_name(hw->clk));
|
||||
return err;
|
||||
}
|
||||
clk->opp_requested = 1;
|
||||
}
|
||||
|
||||
err = prcmu_request_clock(clk->cg_sel, true);
|
||||
if (err)
|
||||
if (err) {
|
||||
prcmu_request_ape_opp_100_voltage(false);
|
||||
clk->opp_requested = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
clk->is_prepared = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_prcmu_opp_volt_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_prcmu *clk = to_clk_prcmu(hw);
|
||||
|
||||
if (prcmu_request_clock(clk->cg_sel, false))
|
||||
goto out_error;
|
||||
if (prcmu_request_ape_opp_100_voltage(false))
|
||||
goto out_error;
|
||||
return;
|
||||
if (prcmu_request_clock(clk->cg_sel, false)) {
|
||||
pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
|
||||
__clk_get_name(hw->clk));
|
||||
return;
|
||||
}
|
||||
|
||||
out_error:
|
||||
pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
|
||||
hw->init->name);
|
||||
if (clk->opp_requested) {
|
||||
prcmu_request_ape_opp_100_voltage(false);
|
||||
clk->opp_requested = 0;
|
||||
}
|
||||
|
||||
clk->is_prepared = 0;
|
||||
}
|
||||
|
||||
static struct clk_ops clk_prcmu_scalable_ops = {
|
||||
.prepare = clk_prcmu_prepare,
|
||||
.unprepare = clk_prcmu_unprepare,
|
||||
.is_prepared = clk_prcmu_is_prepared,
|
||||
.enable = clk_prcmu_enable,
|
||||
.disable = clk_prcmu_disable,
|
||||
.is_enabled = clk_prcmu_is_enabled,
|
||||
|
@ -181,6 +202,7 @@ static struct clk_ops clk_prcmu_scalable_ops = {
|
|||
static struct clk_ops clk_prcmu_gate_ops = {
|
||||
.prepare = clk_prcmu_prepare,
|
||||
.unprepare = clk_prcmu_unprepare,
|
||||
.is_prepared = clk_prcmu_is_prepared,
|
||||
.enable = clk_prcmu_enable,
|
||||
.disable = clk_prcmu_disable,
|
||||
.is_enabled = clk_prcmu_is_enabled,
|
||||
|
@ -202,6 +224,7 @@ static struct clk_ops clk_prcmu_rate_ops = {
|
|||
static struct clk_ops clk_prcmu_opp_gate_ops = {
|
||||
.prepare = clk_prcmu_opp_prepare,
|
||||
.unprepare = clk_prcmu_opp_unprepare,
|
||||
.is_prepared = clk_prcmu_is_prepared,
|
||||
.enable = clk_prcmu_enable,
|
||||
.disable = clk_prcmu_disable,
|
||||
.is_enabled = clk_prcmu_is_enabled,
|
||||
|
@ -211,6 +234,7 @@ static struct clk_ops clk_prcmu_opp_gate_ops = {
|
|||
static struct clk_ops clk_prcmu_opp_volt_scalable_ops = {
|
||||
.prepare = clk_prcmu_opp_volt_prepare,
|
||||
.unprepare = clk_prcmu_opp_volt_unprepare,
|
||||
.is_prepared = clk_prcmu_is_prepared,
|
||||
.enable = clk_prcmu_enable,
|
||||
.disable = clk_prcmu_disable,
|
||||
.is_enabled = clk_prcmu_is_enabled,
|
||||
|
@ -242,7 +266,9 @@ static struct clk *clk_reg_prcmu(const char *name,
|
|||
}
|
||||
|
||||
clk->cg_sel = cg_sel;
|
||||
clk->is_prepared = 1;
|
||||
clk->is_enabled = 1;
|
||||
clk->opp_requested = 0;
|
||||
/* "rate" can be used for changing the initial frequency */
|
||||
if (rate)
|
||||
prcmu_set_clock_rate(cg_sel, rate);
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/sunxi_timer.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk/sunxi.h>
|
||||
|
||||
#define TIMER_CTL_REG 0x00
|
||||
#define TIMER_CTL_ENABLE (1 << 0)
|
||||
|
@ -123,7 +123,7 @@ void __init sunxi_timer_init(void)
|
|||
if (irq <= 0)
|
||||
panic("Can't parse IRQ");
|
||||
|
||||
of_clk_init(NULL);
|
||||
sunxi_init_clocks();
|
||||
|
||||
clk = of_clk_get(node, 0);
|
||||
if (IS_ERR(clk))
|
||||
|
|
|
@ -172,7 +172,7 @@ static void __init tegra20_init_timer(struct device_node *np)
|
|||
BUG();
|
||||
}
|
||||
|
||||
clk = clk_get_sys("timer", NULL);
|
||||
clk = of_clk_get(np, 0);
|
||||
if (IS_ERR(clk)) {
|
||||
pr_warn("Unable to get timer clock. Assuming 12Mhz input clock.\n");
|
||||
rate = 12000000;
|
||||
|
@ -235,7 +235,7 @@ static void __init tegra20_init_rtc(struct device_node *np)
|
|||
* rtc registers are used by read_persistent_clock, keep the rtc clock
|
||||
* enabled
|
||||
*/
|
||||
clk = clk_get_sys("rtc-tegra", NULL);
|
||||
clk = of_clk_get(np, 0);
|
||||
if (IS_ERR(clk))
|
||||
pr_warn("Unable to get rtc-tegra clock\n");
|
||||
else
|
||||
|
|
|
@ -72,6 +72,7 @@ struct tegra_gpio_bank {
|
|||
u32 oe[4];
|
||||
u32 int_enb[4];
|
||||
u32 int_lvl[4];
|
||||
u32 wake_enb[4];
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -333,15 +334,31 @@ static int tegra_gpio_suspend(struct device *dev)
|
|||
bank->oe[p] = tegra_gpio_readl(GPIO_OE(gpio));
|
||||
bank->int_enb[p] = tegra_gpio_readl(GPIO_INT_ENB(gpio));
|
||||
bank->int_lvl[p] = tegra_gpio_readl(GPIO_INT_LVL(gpio));
|
||||
|
||||
/* Enable gpio irq for wake up source */
|
||||
tegra_gpio_writel(bank->wake_enb[p],
|
||||
GPIO_INT_ENB(gpio));
|
||||
}
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_gpio_wake_enable(struct irq_data *d, unsigned int enable)
|
||||
static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
|
||||
{
|
||||
struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
|
||||
int gpio = d->hwirq;
|
||||
u32 port, bit, mask;
|
||||
|
||||
port = GPIO_PORT(gpio);
|
||||
bit = GPIO_BIT(gpio);
|
||||
mask = BIT(bit);
|
||||
|
||||
if (enable)
|
||||
bank->wake_enb[port] |= mask;
|
||||
else
|
||||
bank->wake_enb[port] &= ~mask;
|
||||
|
||||
return irq_set_irq_wake(bank->irq, enable);
|
||||
}
|
||||
#endif
|
||||
|
@ -353,7 +370,7 @@ static struct irq_chip tegra_gpio_irq_chip = {
|
|||
.irq_unmask = tegra_gpio_irq_unmask,
|
||||
.irq_set_type = tegra_gpio_irq_set_type,
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.irq_set_wake = tegra_gpio_wake_enable,
|
||||
.irq_set_wake = tegra_gpio_irq_set_wake,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -152,7 +152,7 @@ struct clk {
|
|||
}, \
|
||||
.reg = _reg, \
|
||||
.shift = _shift, \
|
||||
.width = _width, \
|
||||
.mask = BIT(_width) - 1, \
|
||||
.flags = _mux_flags, \
|
||||
.lock = _lock, \
|
||||
}; \
|
||||
|
|
|
@ -45,6 +45,14 @@ struct clk_hw;
|
|||
* undo any work done in the @prepare callback. Called with
|
||||
* prepare_lock held.
|
||||
*
|
||||
* @is_prepared: Queries the hardware to determine if the clock is prepared.
|
||||
* This function is allowed to sleep. Optional, if this op is not
|
||||
* set then the prepare count will be used.
|
||||
*
|
||||
* @unprepare_unused: Unprepare the clock atomically. Only called from
|
||||
* clk_disable_unused for prepare clocks with special needs.
|
||||
* Called with prepare mutex held. This function may sleep.
|
||||
*
|
||||
* @enable: Enable the clock atomically. This must not return until the
|
||||
* clock is generating a valid clock signal, usable by consumer
|
||||
* devices. Called with enable_lock held. This function must not
|
||||
|
@ -108,6 +116,8 @@ struct clk_hw;
|
|||
struct clk_ops {
|
||||
int (*prepare)(struct clk_hw *hw);
|
||||
void (*unprepare)(struct clk_hw *hw);
|
||||
int (*is_prepared)(struct clk_hw *hw);
|
||||
void (*unprepare_unused)(struct clk_hw *hw);
|
||||
int (*enable)(struct clk_hw *hw);
|
||||
void (*disable)(struct clk_hw *hw);
|
||||
int (*is_enabled)(struct clk_hw *hw);
|
||||
|
@ -287,8 +297,9 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
|
|||
struct clk_mux {
|
||||
struct clk_hw hw;
|
||||
void __iomem *reg;
|
||||
u32 *table;
|
||||
u32 mask;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
u8 flags;
|
||||
spinlock_t *lock;
|
||||
};
|
||||
|
@ -297,11 +308,17 @@ struct clk_mux {
|
|||
#define CLK_MUX_INDEX_BIT BIT(1)
|
||||
|
||||
extern const struct clk_ops clk_mux_ops;
|
||||
|
||||
struct clk *clk_register_mux(struct device *dev, const char *name,
|
||||
const char **parent_names, u8 num_parents, unsigned long flags,
|
||||
void __iomem *reg, u8 shift, u8 width,
|
||||
u8 clk_mux_flags, spinlock_t *lock);
|
||||
|
||||
struct clk *clk_register_mux_table(struct device *dev, const char *name,
|
||||
const char **parent_names, u8 num_parents, unsigned long flags,
|
||||
void __iomem *reg, u8 shift, u32 mask,
|
||||
u8 clk_mux_flags, u32 *table, spinlock_t *lock);
|
||||
|
||||
/**
|
||||
* struct clk_fixed_factor - fixed multiplier and divider clock
|
||||
*
|
||||
|
@ -325,6 +342,37 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
|
|||
const char *parent_name, unsigned long flags,
|
||||
unsigned int mult, unsigned int div);
|
||||
|
||||
/***
|
||||
* struct clk_composite - aggregate clock of mux, divider and gate clocks
|
||||
*
|
||||
* @hw: handle between common and hardware-specific interfaces
|
||||
* @mux_hw: handle between composite and hardware-specifix mux clock
|
||||
* @div_hw: handle between composite and hardware-specifix divider clock
|
||||
* @gate_hw: handle between composite and hardware-specifix gate clock
|
||||
* @mux_ops: clock ops for mux
|
||||
* @div_ops: clock ops for divider
|
||||
* @gate_ops: clock ops for gate
|
||||
*/
|
||||
struct clk_composite {
|
||||
struct clk_hw hw;
|
||||
struct clk_ops ops;
|
||||
|
||||
struct clk_hw *mux_hw;
|
||||
struct clk_hw *div_hw;
|
||||
struct clk_hw *gate_hw;
|
||||
|
||||
const struct clk_ops *mux_ops;
|
||||
const struct clk_ops *div_ops;
|
||||
const struct clk_ops *gate_ops;
|
||||
};
|
||||
|
||||
struct clk *clk_register_composite(struct device *dev, const char *name,
|
||||
const char **parent_names, int num_parents,
|
||||
struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
|
||||
struct clk_hw *div_hw, const struct clk_ops *div_ops,
|
||||
struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
|
||||
unsigned long flags);
|
||||
|
||||
/**
|
||||
* clk_register - allocate a new clock, register it and return an opaque cookie
|
||||
* @dev: device that is registering this clock
|
||||
|
@ -351,6 +399,7 @@ unsigned int __clk_get_enable_count(struct clk *clk);
|
|||
unsigned int __clk_get_prepare_count(struct clk *clk);
|
||||
unsigned long __clk_get_rate(struct clk *clk);
|
||||
unsigned long __clk_get_flags(struct clk *clk);
|
||||
bool __clk_is_prepared(struct clk *clk);
|
||||
bool __clk_is_enabled(struct clk *clk);
|
||||
struct clk *__clk_lookup(const char *name);
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright 2012 Maxime Ripard
|
||||
*
|
||||
* Maxime Ripard <maxime.ripard@free-electrons.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_CLK_SUNXI_H_
|
||||
#define __LINUX_CLK_SUNXI_H_
|
||||
|
||||
void __init sunxi_init_clocks(void);
|
||||
|
||||
#endif
|
|
@ -123,5 +123,6 @@ static inline void tegra_cpu_clock_resume(void)
|
|||
void tegra_periph_reset_deassert(struct clk *c);
|
||||
void tegra_periph_reset_assert(struct clk *c);
|
||||
void tegra_clocks_init(void);
|
||||
void tegra_clocks_apply_init_table(void);
|
||||
|
||||
#endif /* __LINUX_CLK_TEGRA_H_ */
|
||||
|
|
Загрузка…
Ссылка в новой задаче