mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-28 11:49:32 +00:00
ARM: tegra: Common Clock Framework rework
Tegra already supports the common clock framework, but had issues: 1) The clock driver was located in arch/arm/mach-tegra/ rather than drivers/clk/. 2) A single "Tegra clock" type was implemented, rather than separate clock types for PLL, mux, divider, ... type in HW. 3) Clock lookups by device drivers were still driven by device name and connection ID, rather than through device tree. This pull request solves all three issues. This required some DT changes to add clocks properties, and driver changes to request clocks more "correctly". Finally, this rework allows all AUXDATA to be removed from Tegra board files, and various duplicate clock lookup entries to be removed from the driver. This pull request is based on the previous pull request, with tag tegra-for-3.9-cleanup. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJRCYtBAAoJEMzrak5tbycxKb8P/0cXt2X7mPfoApWV96bI2c9h VE1wZYREcq0Au3hiNuMmPp1Nwous2zvrXRKXMvLoQi42KwpvZlFjlyn8+xACKmxO okSJ+aXETzlGh85l5RlnFJMgq181Kn0nDhN5Iwy0FUEJ8/oqdS8fEz5mwQlHflX1 CLaquDVr/edr8LffvsFlxtSmeYNvZ2jYkSgroWeDhVR5Np1/LUCyh5y3edjVl/es B0/keuZ2fnYZnEfqLTpBEARYDBimymuu8gIoHK5nvtz3d/GGu92sVeda4LuHt8eH 1N+f41ceDR2JG/MIJbLr6PGYmCkAGSM/5Vcfa33G+A7GQT0EVb8jLozGCdrCjaEG OM33pN5wtv1M9gTLR9swITBWhbTpRWaHnXeZQF7ttaV8dvr/fuOzWBw47k8Jw0FJ zjGta66kwW7WkT3HDNoM2RRzm9dlJr1xdHOzAaVJnX3VHtHcIvYzDi90Xv9Nn46D E/qIpExmL4rMrb2+4MxT9CdbfzdBSmsnlRFoWZTIM1NPxA/97i7oAyYVAJ34LCNx xWqwimhXK14LzGffpSHm9CSz8DHNbehDZRMQD0jGYMn61PFtDB+E/oEq5AEqneuC KDht3Qdx/mPzJQPE8WV3d5FxeXfXDjj203x/i6x8TOdH8Bt4aoK9ajvPYBpA+2aE 4fPJIobLHGYN/F+GF1VJ =s9hz -----END PGP SIGNATURE----- Merge tag 'tegra-for-3.9-soc-ccf' of git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-tegra into next/soc From Stephen Warren: ARM: tegra: Common Clock Framework rework Tegra already supports the common clock framework, but had issues: 1) The clock driver was located in arch/arm/mach-tegra/ rather than drivers/clk/. 2) A single "Tegra clock" type was implemented, rather than separate clock types for PLL, mux, divider, ... type in HW. 3) Clock lookups by device drivers were still driven by device name and connection ID, rather than through device tree. This pull request solves all three issues. This required some DT changes to add clocks properties, and driver changes to request clocks more "correctly". Finally, this rework allows all AUXDATA to be removed from Tegra board files, and various duplicate clock lookup entries to be removed from the driver. This pull request is based on the previous pull request, with tag tegra-for-3.9-cleanup. * tag 'tegra-for-3.9-soc-ccf' of git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-tegra: (31 commits) clk: tegra30: remove unused TEGRA_CLK_DUPLICATE()s clk: tegra20: remove unused TEGRA_CLK_DUPLICATE()s ARM: tegra30: remove auxdata ARM: tegra20: remove auxdata ASoC: tegra: remove auxdata staging: nvec: remove use of clk_get_sys ARM: tegra: paz00: add clock information to DT ARM: tegra: add clock properties to Tegra30 DT ARM: tegra: add clock properties to Tegra20 DT spi: tegra: do not use clock name to get clock ARM: tegra: remove legacy clock code ARM: tegra: migrate to new clock code clk: tegra: add clock support for Tegra30 clk: tegra: add clock support for Tegra20 clk: tegra: add Tegra specific clocks ARM: tegra: define Tegra30 CAR binding ARM: tegra: define Tegra20 CAR binding ARM: tegra: move tegra_cpu_car.h to linux/clk/tegra.h ARM: tegra: add function to read chipid ARM: tegra: fix compile error when disable CPU_IDLE ... Signed-off-by: Olof Johansson <olof@lixom.net> Conflicts: arch/arm/mach-tegra/board-dt-tegra20.c arch/arm/mach-tegra/board-dt-tegra30.c arch/arm/mach-tegra/common.c arch/arm/mach-tegra/platsmp.c drivers/clocksource/Makefile
This commit is contained in:
commit
bda6f8e6cd
67 changed files with 6426 additions and 7651 deletions
205
Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt
Normal file
205
Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt
Normal file
|
@ -0,0 +1,205 @@
|
|||
NVIDIA Tegra20 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,tegra20-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 96 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 95 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 96 and
|
||||
above.
|
||||
|
||||
0 cpu
|
||||
1 unassigned
|
||||
2 unassigned
|
||||
3 ac97
|
||||
4 rtc
|
||||
5 tmr
|
||||
6 uart1
|
||||
7 unassigned (register bit affects uart2 and vfir)
|
||||
8 gpio
|
||||
9 sdmmc2
|
||||
10 unassigned (register bit affects spdif_in and spdif_out)
|
||||
11 i2s1
|
||||
12 i2c1
|
||||
13 ndflash
|
||||
14 sdmmc1
|
||||
15 sdmmc4
|
||||
16 twc
|
||||
17 pwm
|
||||
18 i2s2
|
||||
19 epp
|
||||
20 unassigned (register bit affects vi and vi_sensor)
|
||||
21 2d
|
||||
22 usbd
|
||||
23 isp
|
||||
24 3d
|
||||
25 ide
|
||||
26 disp2
|
||||
27 disp1
|
||||
28 host1x
|
||||
29 vcp
|
||||
30 unassigned
|
||||
31 cache2
|
||||
|
||||
32 mem
|
||||
33 ahbdma
|
||||
34 apbdma
|
||||
35 unassigned
|
||||
36 kbc
|
||||
37 stat_mon
|
||||
38 pmc
|
||||
39 fuse
|
||||
40 kfuse
|
||||
41 sbc1
|
||||
42 snor
|
||||
43 spi1
|
||||
44 sbc2
|
||||
45 xio
|
||||
46 sbc3
|
||||
47 dvc
|
||||
48 dsi
|
||||
49 unassigned (register bit affects tvo and cve)
|
||||
50 mipi
|
||||
51 hdmi
|
||||
52 csi
|
||||
53 tvdac
|
||||
54 i2c2
|
||||
55 uart3
|
||||
56 unassigned
|
||||
57 emc
|
||||
58 usb2
|
||||
59 usb3
|
||||
60 mpe
|
||||
61 vde
|
||||
62 bsea
|
||||
63 bsev
|
||||
|
||||
64 speedo
|
||||
65 uart4
|
||||
66 uart5
|
||||
67 i2c3
|
||||
68 sbc4
|
||||
69 sdmmc3
|
||||
70 pcie
|
||||
71 owr
|
||||
72 afi
|
||||
73 csite
|
||||
74 unassigned
|
||||
75 avpucq
|
||||
76 la
|
||||
77 unassigned
|
||||
78 unassigned
|
||||
79 unassigned
|
||||
80 unassigned
|
||||
81 unassigned
|
||||
82 unassigned
|
||||
83 unassigned
|
||||
84 irama
|
||||
85 iramb
|
||||
86 iramc
|
||||
87 iramd
|
||||
88 cram2
|
||||
89 audio_2x a/k/a audio_2x_sync_clk
|
||||
90 clk_d
|
||||
91 unassigned
|
||||
92 sus
|
||||
93 cdev1
|
||||
94 cdev2
|
||||
95 unassigned
|
||||
|
||||
96 uart2
|
||||
97 vfir
|
||||
98 spdif_in
|
||||
99 spdif_out
|
||||
100 vi
|
||||
101 vi_sensor
|
||||
102 tvo
|
||||
103 cve
|
||||
104 osc
|
||||
105 clk_32k a/k/a clk_s
|
||||
106 clk_m
|
||||
107 sclk
|
||||
108 cclk
|
||||
109 hclk
|
||||
110 pclk
|
||||
111 blink
|
||||
112 pll_a
|
||||
113 pll_a_out0
|
||||
114 pll_c
|
||||
115 pll_c_out1
|
||||
116 pll_d
|
||||
117 pll_d_out0
|
||||
118 pll_e
|
||||
119 pll_m
|
||||
120 pll_m_out1
|
||||
121 pll_p
|
||||
122 pll_p_out1
|
||||
123 pll_p_out2
|
||||
124 pll_p_out3
|
||||
125 pll_p_out4
|
||||
126 pll_s
|
||||
127 pll_u
|
||||
128 pll_x
|
||||
129 cop a/k/a avp
|
||||
130 audio a/k/a audio_sync_clk
|
||||
131 pll_ref
|
||||
132 twd
|
||||
|
||||
Example SoC include file:
|
||||
|
||||
/ {
|
||||
tegra_car: clock {
|
||||
compatible = "nvidia,tegra20-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>;
|
||||
};
|
||||
};
|
262
Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt
Normal file
262
Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt
Normal file
|
@ -0,0 +1,262 @@
|
|||
NVIDIA Tegra30 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,tegra30-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 130 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 cpu
|
||||
1 unassigned
|
||||
2 unassigned
|
||||
3 unassigned
|
||||
4 rtc
|
||||
5 timer
|
||||
6 uarta
|
||||
7 unassigned (register bit affects uartb and vfir)
|
||||
8 gpio
|
||||
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 cop_cache
|
||||
|
||||
32 mc
|
||||
33 ahbdma
|
||||
34 apbdma
|
||||
35 unassigned
|
||||
36 kbc
|
||||
37 statmon
|
||||
38 pmc
|
||||
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 (register bit affects cve and tvo)
|
||||
50 mipi
|
||||
51 hdmi
|
||||
52 csi
|
||||
53 tvdac
|
||||
54 i2c2
|
||||
55 uartc
|
||||
56 unassigned
|
||||
57 emc
|
||||
58 usb2
|
||||
59 usb3
|
||||
60 mpe
|
||||
61 vde
|
||||
62 bsea
|
||||
63 bsev
|
||||
|
||||
64 speedo
|
||||
65 uartd
|
||||
66 uarte
|
||||
67 i2c3
|
||||
68 sbc4
|
||||
69 sdmmc3
|
||||
70 pcie
|
||||
71 owr
|
||||
72 afi
|
||||
73 csite
|
||||
74 pciex
|
||||
75 avpucq
|
||||
76 la
|
||||
77 unassigned
|
||||
78 unassigned
|
||||
79 dtv
|
||||
80 ndspeed
|
||||
81 i2cslow
|
||||
82 dsib
|
||||
83 unassigned
|
||||
84 irama
|
||||
85 iramb
|
||||
86 iramc
|
||||
87 iramd
|
||||
88 cram2
|
||||
89 unassigned
|
||||
90 audio_2x a/k/a audio_2x_sync_clk
|
||||
91 unassigned
|
||||
92 csus
|
||||
93 cdev2
|
||||
94 cdev1
|
||||
95 unassigned
|
||||
|
||||
96 cpu_g
|
||||
97 cpu_lp
|
||||
98 3d2
|
||||
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 atomics
|
||||
113 audio0_2x
|
||||
114 audio1_2x
|
||||
115 audio2_2x
|
||||
116 audio3_2x
|
||||
117 audio4_2x
|
||||
118 audio5_2x
|
||||
119 actmon
|
||||
120 extern1
|
||||
121 extern2
|
||||
122 extern3
|
||||
123 sata_oob
|
||||
124 sata
|
||||
125 hda
|
||||
127 se
|
||||
128 hda2hdmi
|
||||
129 sata_cold
|
||||
|
||||
160 uartb
|
||||
161 vfir
|
||||
162 spdif_in
|
||||
163 spdif_out
|
||||
164 vi
|
||||
165 vi_sensor
|
||||
166 fuse
|
||||
167 fuse_burn
|
||||
168 cve
|
||||
169 tvo
|
||||
|
||||
170 clk_32k
|
||||
171 clk_m
|
||||
172 clk_m_div2
|
||||
173 clk_m_div4
|
||||
174 pll_ref
|
||||
175 pll_c
|
||||
176 pll_c_out1
|
||||
177 pll_m
|
||||
178 pll_m_out1
|
||||
179 pll_p
|
||||
180 pll_p_out1
|
||||
181 pll_p_out2
|
||||
182 pll_p_out3
|
||||
183 pll_p_out4
|
||||
184 pll_a
|
||||
185 pll_a_out0
|
||||
186 pll_d
|
||||
187 pll_d_out0
|
||||
188 pll_d2
|
||||
189 pll_d2_out0
|
||||
190 pll_u
|
||||
191 pll_x
|
||||
192 pll_x_out0
|
||||
193 pll_e
|
||||
194 spdif_in_sync
|
||||
195 i2s0_sync
|
||||
196 i2s1_sync
|
||||
197 i2s2_sync
|
||||
198 i2s3_sync
|
||||
199 i2s4_sync
|
||||
200 vimclk
|
||||
201 audio0
|
||||
202 audio1
|
||||
203 audio2
|
||||
204 audio3
|
||||
205 audio4
|
||||
206 audio5
|
||||
207 clk_out_1 (extern1)
|
||||
208 clk_out_2 (extern2)
|
||||
209 clk_out_3 (extern3)
|
||||
210 sclk
|
||||
211 blink
|
||||
212 cclk_g
|
||||
213 cclk_lp
|
||||
214 twd
|
||||
215 cml0
|
||||
216 cml1
|
||||
217 hclk
|
||||
218 pclk
|
||||
|
||||
Example SoC include file:
|
||||
|
||||
/ {
|
||||
tegra_car: clock {
|
||||
compatible = "nvidia,tegra30-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>;
|
||||
};
|
||||
};
|
|
@ -643,6 +643,7 @@ config ARCH_TEGRA
|
|||
select ARCH_HAS_CPUFREQ
|
||||
select CLKDEV_LOOKUP
|
||||
select CLKSRC_MMIO
|
||||
select CLKSRC_OF
|
||||
select COMMON_CLK
|
||||
select GENERIC_CLOCKEVENTS
|
||||
select GENERIC_GPIO
|
||||
|
|
|
@ -266,6 +266,8 @@ nvec {
|
|||
clock-frequency = <80000>;
|
||||
request-gpios = <&gpio 170 0>; /* gpio PV2 */
|
||||
slave-addr = <138>;
|
||||
clocks = <&tegra_car 67>, <&tegra_car 124>;
|
||||
clock-names = "div-clk", "fast-clk";
|
||||
};
|
||||
|
||||
i2c@7000d000 {
|
||||
|
|
|
@ -9,6 +9,7 @@ host1x {
|
|||
reg = <0x50000000 0x00024000>;
|
||||
interrupts = <0 65 0x04 /* mpcore syncpt */
|
||||
0 67 0x04>; /* mpcore general */
|
||||
clocks = <&tegra_car 28>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
@ -19,41 +20,49 @@ mpe {
|
|||
compatible = "nvidia,tegra20-mpe";
|
||||
reg = <0x54040000 0x00040000>;
|
||||
interrupts = <0 68 0x04>;
|
||||
clocks = <&tegra_car 60>;
|
||||
};
|
||||
|
||||
vi {
|
||||
compatible = "nvidia,tegra20-vi";
|
||||
reg = <0x54080000 0x00040000>;
|
||||
interrupts = <0 69 0x04>;
|
||||
clocks = <&tegra_car 100>;
|
||||
};
|
||||
|
||||
epp {
|
||||
compatible = "nvidia,tegra20-epp";
|
||||
reg = <0x540c0000 0x00040000>;
|
||||
interrupts = <0 70 0x04>;
|
||||
clocks = <&tegra_car 19>;
|
||||
};
|
||||
|
||||
isp {
|
||||
compatible = "nvidia,tegra20-isp";
|
||||
reg = <0x54100000 0x00040000>;
|
||||
interrupts = <0 71 0x04>;
|
||||
clocks = <&tegra_car 23>;
|
||||
};
|
||||
|
||||
gr2d {
|
||||
compatible = "nvidia,tegra20-gr2d";
|
||||
reg = <0x54140000 0x00040000>;
|
||||
interrupts = <0 72 0x04>;
|
||||
clocks = <&tegra_car 21>;
|
||||
};
|
||||
|
||||
gr3d {
|
||||
compatible = "nvidia,tegra20-gr3d";
|
||||
reg = <0x54180000 0x00040000>;
|
||||
clocks = <&tegra_car 24>;
|
||||
};
|
||||
|
||||
dc@54200000 {
|
||||
compatible = "nvidia,tegra20-dc";
|
||||
reg = <0x54200000 0x00040000>;
|
||||
interrupts = <0 73 0x04>;
|
||||
clocks = <&tegra_car 27>, <&tegra_car 121>;
|
||||
clock-names = "disp1", "parent";
|
||||
|
||||
rgb {
|
||||
status = "disabled";
|
||||
|
@ -64,6 +73,8 @@ dc@54240000 {
|
|||
compatible = "nvidia,tegra20-dc";
|
||||
reg = <0x54240000 0x00040000>;
|
||||
interrupts = <0 74 0x04>;
|
||||
clocks = <&tegra_car 26>, <&tegra_car 121>;
|
||||
clock-names = "disp2", "parent";
|
||||
|
||||
rgb {
|
||||
status = "disabled";
|
||||
|
@ -74,6 +85,8 @@ hdmi {
|
|||
compatible = "nvidia,tegra20-hdmi";
|
||||
reg = <0x54280000 0x00040000>;
|
||||
interrupts = <0 75 0x04>;
|
||||
clocks = <&tegra_car 51>, <&tegra_car 117>;
|
||||
clock-names = "hdmi", "parent";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -81,12 +94,14 @@ tvo {
|
|||
compatible = "nvidia,tegra20-tvo";
|
||||
reg = <0x542c0000 0x00040000>;
|
||||
interrupts = <0 76 0x04>;
|
||||
clocks = <&tegra_car 102>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
dsi {
|
||||
compatible = "nvidia,tegra20-dsi";
|
||||
reg = <0x54300000 0x00040000>;
|
||||
clocks = <&tegra_car 48>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
@ -123,6 +138,12 @@ timer@60005000 {
|
|||
0 42 0x04>;
|
||||
};
|
||||
|
||||
tegra_car: clock {
|
||||
compatible = "nvidia,tegra20-car";
|
||||
reg = <0x60006000 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
apbdma: dma {
|
||||
compatible = "nvidia,tegra20-apbdma";
|
||||
reg = <0x6000a000 0x1200>;
|
||||
|
@ -142,6 +163,7 @@ apbdma: dma {
|
|||
0 117 0x04
|
||||
0 118 0x04
|
||||
0 119 0x04>;
|
||||
clocks = <&tegra_car 34>;
|
||||
};
|
||||
|
||||
ahb {
|
||||
|
@ -183,6 +205,7 @@ tegra_i2s1: i2s@70002800 {
|
|||
reg = <0x70002800 0x200>;
|
||||
interrupts = <0 13 0x04>;
|
||||
nvidia,dma-request-selector = <&apbdma 2>;
|
||||
clocks = <&tegra_car 11>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -191,6 +214,7 @@ tegra_i2s2: i2s@70002a00 {
|
|||
reg = <0x70002a00 0x200>;
|
||||
interrupts = <0 3 0x04>;
|
||||
nvidia,dma-request-selector = <&apbdma 1>;
|
||||
clocks = <&tegra_car 18>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -199,6 +223,7 @@ serial@70006000 {
|
|||
reg = <0x70006000 0x40>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <0 36 0x04>;
|
||||
clocks = <&tegra_car 6>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -207,6 +232,7 @@ serial@70006040 {
|
|||
reg = <0x70006040 0x40>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <0 37 0x04>;
|
||||
clocks = <&tegra_car 96>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -215,6 +241,7 @@ serial@70006200 {
|
|||
reg = <0x70006200 0x100>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <0 46 0x04>;
|
||||
clocks = <&tegra_car 55>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -223,6 +250,7 @@ serial@70006300 {
|
|||
reg = <0x70006300 0x100>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <0 90 0x04>;
|
||||
clocks = <&tegra_car 65>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -231,6 +259,7 @@ serial@70006400 {
|
|||
reg = <0x70006400 0x100>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <0 91 0x04>;
|
||||
clocks = <&tegra_car 66>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -238,6 +267,7 @@ pwm: pwm {
|
|||
compatible = "nvidia,tegra20-pwm";
|
||||
reg = <0x7000a000 0x100>;
|
||||
#pwm-cells = <2>;
|
||||
clocks = <&tegra_car 17>;
|
||||
};
|
||||
|
||||
rtc {
|
||||
|
@ -252,6 +282,8 @@ i2c@7000c000 {
|
|||
interrupts = <0 38 0x04>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car 12>, <&tegra_car 124>;
|
||||
clock-names = "div-clk", "fast-clk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -262,6 +294,7 @@ spi@7000c380 {
|
|||
nvidia,dma-request-selector = <&apbdma 11>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car 43>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -271,6 +304,8 @@ i2c@7000c400 {
|
|||
interrupts = <0 84 0x04>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car 54>, <&tegra_car 124>;
|
||||
clock-names = "div-clk", "fast-clk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -280,6 +315,8 @@ i2c@7000c500 {
|
|||
interrupts = <0 92 0x04>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car 67>, <&tegra_car 124>;
|
||||
clock-names = "div-clk", "fast-clk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -289,6 +326,8 @@ i2c@7000d000 {
|
|||
interrupts = <0 53 0x04>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car 47>, <&tegra_car 124>;
|
||||
clock-names = "div-clk", "fast-clk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -299,6 +338,7 @@ spi@7000d400 {
|
|||
nvidia,dma-request-selector = <&apbdma 15>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car 41>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -309,6 +349,7 @@ spi@7000d600 {
|
|||
nvidia,dma-request-selector = <&apbdma 16>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car 44>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -319,6 +360,7 @@ spi@7000d800 {
|
|||
nvidia,dma-request-selector = <&apbdma 17>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car 46>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -329,6 +371,7 @@ spi@7000da00 {
|
|||
nvidia,dma-request-selector = <&apbdma 18>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car 68>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -363,6 +406,7 @@ usb@c5000000 {
|
|||
interrupts = <0 20 0x04>;
|
||||
phy_type = "utmi";
|
||||
nvidia,has-legacy-mode;
|
||||
clocks = <&tegra_car 22>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -371,6 +415,7 @@ usb@c5004000 {
|
|||
reg = <0xc5004000 0x4000>;
|
||||
interrupts = <0 21 0x04>;
|
||||
phy_type = "ulpi";
|
||||
clocks = <&tegra_car 58>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -379,6 +424,7 @@ usb@c5008000 {
|
|||
reg = <0xc5008000 0x4000>;
|
||||
interrupts = <0 97 0x04>;
|
||||
phy_type = "utmi";
|
||||
clocks = <&tegra_car 59>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -386,6 +432,7 @@ sdhci@c8000000 {
|
|||
compatible = "nvidia,tegra20-sdhci";
|
||||
reg = <0xc8000000 0x200>;
|
||||
interrupts = <0 14 0x04>;
|
||||
clocks = <&tegra_car 14>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -393,6 +440,7 @@ sdhci@c8000200 {
|
|||
compatible = "nvidia,tegra20-sdhci";
|
||||
reg = <0xc8000200 0x200>;
|
||||
interrupts = <0 15 0x04>;
|
||||
clocks = <&tegra_car 9>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -400,6 +448,7 @@ sdhci@c8000400 {
|
|||
compatible = "nvidia,tegra20-sdhci";
|
||||
reg = <0xc8000400 0x200>;
|
||||
interrupts = <0 19 0x04>;
|
||||
clocks = <&tegra_car 69>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -407,6 +456,7 @@ sdhci@c8000600 {
|
|||
compatible = "nvidia,tegra20-sdhci";
|
||||
reg = <0xc8000600 0x200>;
|
||||
interrupts = <0 31 0x04>;
|
||||
clocks = <&tegra_car 15>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ host1x {
|
|||
reg = <0x50000000 0x00024000>;
|
||||
interrupts = <0 65 0x04 /* mpcore syncpt */
|
||||
0 67 0x04>; /* mpcore general */
|
||||
clocks = <&tegra_car 28>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
@ -19,41 +20,50 @@ mpe {
|
|||
compatible = "nvidia,tegra30-mpe";
|
||||
reg = <0x54040000 0x00040000>;
|
||||
interrupts = <0 68 0x04>;
|
||||
clocks = <&tegra_car 60>;
|
||||
};
|
||||
|
||||
vi {
|
||||
compatible = "nvidia,tegra30-vi";
|
||||
reg = <0x54080000 0x00040000>;
|
||||
interrupts = <0 69 0x04>;
|
||||
clocks = <&tegra_car 164>;
|
||||
};
|
||||
|
||||
epp {
|
||||
compatible = "nvidia,tegra30-epp";
|
||||
reg = <0x540c0000 0x00040000>;
|
||||
interrupts = <0 70 0x04>;
|
||||
clocks = <&tegra_car 19>;
|
||||
};
|
||||
|
||||
isp {
|
||||
compatible = "nvidia,tegra30-isp";
|
||||
reg = <0x54100000 0x00040000>;
|
||||
interrupts = <0 71 0x04>;
|
||||
clocks = <&tegra_car 23>;
|
||||
};
|
||||
|
||||
gr2d {
|
||||
compatible = "nvidia,tegra30-gr2d";
|
||||
reg = <0x54140000 0x00040000>;
|
||||
interrupts = <0 72 0x04>;
|
||||
clocks = <&tegra_car 21>;
|
||||
};
|
||||
|
||||
gr3d {
|
||||
compatible = "nvidia,tegra30-gr3d";
|
||||
reg = <0x54180000 0x00040000>;
|
||||
clocks = <&tegra_car 24 &tegra_car 98>;
|
||||
clock-names = "3d", "3d2";
|
||||
};
|
||||
|
||||
dc@54200000 {
|
||||
compatible = "nvidia,tegra30-dc";
|
||||
reg = <0x54200000 0x00040000>;
|
||||
interrupts = <0 73 0x04>;
|
||||
clocks = <&tegra_car 27>, <&tegra_car 179>;
|
||||
clock-names = "disp1", "parent";
|
||||
|
||||
rgb {
|
||||
status = "disabled";
|
||||
|
@ -64,6 +74,8 @@ dc@54240000 {
|
|||
compatible = "nvidia,tegra30-dc";
|
||||
reg = <0x54240000 0x00040000>;
|
||||
interrupts = <0 74 0x04>;
|
||||
clocks = <&tegra_car 26>, <&tegra_car 179>;
|
||||
clock-names = "disp2", "parent";
|
||||
|
||||
rgb {
|
||||
status = "disabled";
|
||||
|
@ -74,6 +86,8 @@ hdmi {
|
|||
compatible = "nvidia,tegra30-hdmi";
|
||||
reg = <0x54280000 0x00040000>;
|
||||
interrupts = <0 75 0x04>;
|
||||
clocks = <&tegra_car 51>, <&tegra_car 189>;
|
||||
clock-names = "hdmi", "parent";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -81,12 +95,14 @@ tvo {
|
|||
compatible = "nvidia,tegra30-tvo";
|
||||
reg = <0x542c0000 0x00040000>;
|
||||
interrupts = <0 76 0x04>;
|
||||
clocks = <&tegra_car 169>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
dsi {
|
||||
compatible = "nvidia,tegra30-dsi";
|
||||
reg = <0x54300000 0x00040000>;
|
||||
clocks = <&tegra_car 48>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
@ -125,6 +141,12 @@ timer@60005000 {
|
|||
0 122 0x04>;
|
||||
};
|
||||
|
||||
tegra_car: clock {
|
||||
compatible = "nvidia,tegra30-car";
|
||||
reg = <0x60006000 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
apbdma: dma {
|
||||
compatible = "nvidia,tegra30-apbdma", "nvidia,tegra20-apbdma";
|
||||
reg = <0x6000a000 0x1400>;
|
||||
|
@ -160,6 +182,7 @@ apbdma: dma {
|
|||
0 141 0x04
|
||||
0 142 0x04
|
||||
0 143 0x04>;
|
||||
clocks = <&tegra_car 34>;
|
||||
};
|
||||
|
||||
ahb: ahb {
|
||||
|
@ -195,6 +218,7 @@ serial@70006000 {
|
|||
reg = <0x70006000 0x40>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <0 36 0x04>;
|
||||
clocks = <&tegra_car 6>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -203,6 +227,7 @@ serial@70006040 {
|
|||
reg = <0x70006040 0x40>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <0 37 0x04>;
|
||||
clocks = <&tegra_car 160>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -211,6 +236,7 @@ serial@70006200 {
|
|||
reg = <0x70006200 0x100>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <0 46 0x04>;
|
||||
clocks = <&tegra_car 55>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -219,6 +245,7 @@ serial@70006300 {
|
|||
reg = <0x70006300 0x100>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <0 90 0x04>;
|
||||
clocks = <&tegra_car 65>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -227,6 +254,7 @@ serial@70006400 {
|
|||
reg = <0x70006400 0x100>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <0 91 0x04>;
|
||||
clocks = <&tegra_car 66>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -234,6 +262,7 @@ pwm: pwm {
|
|||
compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm";
|
||||
reg = <0x7000a000 0x100>;
|
||||
#pwm-cells = <2>;
|
||||
clocks = <&tegra_car 17>;
|
||||
};
|
||||
|
||||
rtc {
|
||||
|
@ -248,6 +277,8 @@ i2c@7000c000 {
|
|||
interrupts = <0 38 0x04>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car 12>, <&tegra_car 182>;
|
||||
clock-names = "div-clk", "fast-clk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -257,6 +288,8 @@ i2c@7000c400 {
|
|||
interrupts = <0 84 0x04>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car 54>, <&tegra_car 182>;
|
||||
clock-names = "div-clk", "fast-clk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -266,6 +299,8 @@ i2c@7000c500 {
|
|||
interrupts = <0 92 0x04>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car 67>, <&tegra_car 182>;
|
||||
clock-names = "div-clk", "fast-clk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -275,6 +310,8 @@ i2c@7000c700 {
|
|||
interrupts = <0 120 0x04>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car 103>, <&tegra_car 182>;
|
||||
clock-names = "div-clk", "fast-clk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -284,6 +321,8 @@ i2c@7000d000 {
|
|||
interrupts = <0 53 0x04>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car 47>, <&tegra_car 182>;
|
||||
clock-names = "div-clk", "fast-clk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -294,6 +333,7 @@ spi@7000d400 {
|
|||
nvidia,dma-request-selector = <&apbdma 15>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car 41>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -304,6 +344,7 @@ spi@7000d600 {
|
|||
nvidia,dma-request-selector = <&apbdma 16>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car 44>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -314,6 +355,7 @@ spi@7000d800 {
|
|||
nvidia,dma-request-selector = <&apbdma 17>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car 46>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -324,6 +366,7 @@ spi@7000da00 {
|
|||
nvidia,dma-request-selector = <&apbdma 18>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car 68>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -334,6 +377,7 @@ spi@7000dc00 {
|
|||
nvidia,dma-request-selector = <&apbdma 27>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car 104>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -344,6 +388,7 @@ spi@7000de00 {
|
|||
nvidia,dma-request-selector = <&apbdma 28>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car 105>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -377,7 +422,13 @@ ahub {
|
|||
0x70080200 0x100>;
|
||||
interrupts = <0 103 0x04>;
|
||||
nvidia,dma-request-selector = <&apbdma 1>;
|
||||
|
||||
clocks = <&tegra_car 106>, <&tegra_car 107>, <&tegra_car 30>,
|
||||
<&tegra_car 11>, <&tegra_car 18>, <&tegra_car 101>,
|
||||
<&tegra_car 102>, <&tegra_car 108>, <&tegra_car 109>,
|
||||
<&tegra_car 110>, <&tegra_car 162>;
|
||||
clock-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2",
|
||||
"i2s3", "i2s4", "dam0", "dam1", "dam2",
|
||||
"spdif_in";
|
||||
ranges;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
@ -386,6 +437,7 @@ tegra_i2s0: i2s@70080300 {
|
|||
compatible = "nvidia,tegra30-i2s";
|
||||
reg = <0x70080300 0x100>;
|
||||
nvidia,ahub-cif-ids = <4 4>;
|
||||
clocks = <&tegra_car 30>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -393,6 +445,7 @@ tegra_i2s1: i2s@70080400 {
|
|||
compatible = "nvidia,tegra30-i2s";
|
||||
reg = <0x70080400 0x100>;
|
||||
nvidia,ahub-cif-ids = <5 5>;
|
||||
clocks = <&tegra_car 11>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -400,6 +453,7 @@ tegra_i2s2: i2s@70080500 {
|
|||
compatible = "nvidia,tegra30-i2s";
|
||||
reg = <0x70080500 0x100>;
|
||||
nvidia,ahub-cif-ids = <6 6>;
|
||||
clocks = <&tegra_car 18>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -407,6 +461,7 @@ tegra_i2s3: i2s@70080600 {
|
|||
compatible = "nvidia,tegra30-i2s";
|
||||
reg = <0x70080600 0x100>;
|
||||
nvidia,ahub-cif-ids = <7 7>;
|
||||
clocks = <&tegra_car 101>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -414,6 +469,7 @@ tegra_i2s4: i2s@70080700 {
|
|||
compatible = "nvidia,tegra30-i2s";
|
||||
reg = <0x70080700 0x100>;
|
||||
nvidia,ahub-cif-ids = <8 8>;
|
||||
clocks = <&tegra_car 102>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
@ -422,6 +478,7 @@ sdhci@78000000 {
|
|||
compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
|
||||
reg = <0x78000000 0x200>;
|
||||
interrupts = <0 14 0x04>;
|
||||
clocks = <&tegra_car 14>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -429,6 +486,7 @@ sdhci@78000200 {
|
|||
compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
|
||||
reg = <0x78000200 0x200>;
|
||||
interrupts = <0 15 0x04>;
|
||||
clocks = <&tegra_car 9>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -436,6 +494,7 @@ sdhci@78000400 {
|
|||
compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
|
||||
reg = <0x78000400 0x200>;
|
||||
interrupts = <0 19 0x04>;
|
||||
clocks = <&tegra_car 69>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -443,6 +502,7 @@ sdhci@78000600 {
|
|||
compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
|
||||
reg = <0x78000600 0x200>;
|
||||
interrupts = <0 31 0x04>;
|
||||
clocks = <&tegra_car 15>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -6,9 +6,9 @@ config ARCH_TEGRA_2x_SOC
|
|||
bool "Enable support for Tegra20 family"
|
||||
select ARCH_REQUIRE_GPIOLIB
|
||||
select ARM_ERRATA_720789
|
||||
select ARM_ERRATA_742230
|
||||
select ARM_ERRATA_742230 if SMP
|
||||
select ARM_ERRATA_751472
|
||||
select ARM_ERRATA_754327
|
||||
select ARM_ERRATA_754327 if SMP
|
||||
select ARM_ERRATA_764369 if SMP
|
||||
select ARM_GIC
|
||||
select CPU_FREQ_TABLE if CPU_FREQ
|
||||
|
|
|
@ -1,33 +1,28 @@
|
|||
obj-y += common.o
|
||||
obj-y += io.o
|
||||
obj-y += irq.o
|
||||
obj-y += clock.o
|
||||
obj-y += timer.o
|
||||
obj-y += fuse.o
|
||||
obj-y += pmc.o
|
||||
obj-y += flowctrl.o
|
||||
obj-y += powergate.o
|
||||
obj-y += apbio.o
|
||||
obj-y += pm.o
|
||||
obj-y += reset.o
|
||||
obj-y += reset-handler.o
|
||||
obj-y += sleep.o
|
||||
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
|
||||
obj-$(CONFIG_CPU_IDLE) += sleep.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks_data.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_speedo.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-tegra20.o
|
||||
ifeq ($(CONFIG_CPU_IDLE),y)
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += cpuidle-tegra20.o
|
||||
endif
|
||||
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks_data.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_speedo.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += sleep-tegra30.o
|
||||
ifeq ($(CONFIG_CPU_IDLE),y)
|
||||
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += cpuidle-tegra30.o
|
||||
endif
|
||||
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
|
||||
obj-$(CONFIG_SMP) += reset.o
|
||||
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
|
||||
obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o
|
||||
obj-$(CONFIG_TEGRA_PCI) += pcie.o
|
||||
|
|
|
@ -38,7 +38,7 @@ static void tegra_apb_writel_direct(u32 value, unsigned long offset);
|
|||
static struct dma_chan *tegra_apb_dma_chan;
|
||||
static struct dma_slave_config dma_sconfig;
|
||||
|
||||
bool tegra_apb_dma_init(void)
|
||||
static bool tegra_apb_dma_init(void)
|
||||
{
|
||||
dma_cap_mask_t mask;
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
@ -39,99 +40,45 @@
|
|||
#include <asm/setup.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "clock.h"
|
||||
#include "common.h"
|
||||
#include "iomap.h"
|
||||
|
||||
struct tegra_ehci_platform_data tegra_ehci1_pdata = {
|
||||
static struct tegra_ehci_platform_data tegra_ehci1_pdata = {
|
||||
.operating_mode = TEGRA_USB_OTG,
|
||||
.power_down_on_bus_suspend = 1,
|
||||
.vbus_gpio = -1,
|
||||
};
|
||||
|
||||
struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config = {
|
||||
static struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config = {
|
||||
.reset_gpio = -1,
|
||||
.clk = "cdev2",
|
||||
};
|
||||
|
||||
struct tegra_ehci_platform_data tegra_ehci2_pdata = {
|
||||
static struct tegra_ehci_platform_data tegra_ehci2_pdata = {
|
||||
.phy_config = &tegra_ehci2_ulpi_phy_config,
|
||||
.operating_mode = TEGRA_USB_HOST,
|
||||
.power_down_on_bus_suspend = 1,
|
||||
.vbus_gpio = -1,
|
||||
};
|
||||
|
||||
struct tegra_ehci_platform_data tegra_ehci3_pdata = {
|
||||
static struct tegra_ehci_platform_data tegra_ehci3_pdata = {
|
||||
.operating_mode = TEGRA_USB_HOST,
|
||||
.power_down_on_bus_suspend = 1,
|
||||
.vbus_gpio = -1,
|
||||
};
|
||||
|
||||
struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC1_BASE, "sdhci-tegra.0", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC2_BASE, "sdhci-tegra.1", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC3_BASE, "sdhci-tegra.2", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC4_BASE, "sdhci-tegra.3", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C_BASE, "tegra-i2c.0", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C2_BASE, "tegra-i2c.1", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C3_BASE, "tegra-i2c.2", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-i2c-dvc", TEGRA_DVC_BASE, "tegra-i2c.3", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra20-i2s.0", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S2_BASE, "tegra20-i2s.1", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-das", TEGRA_APB_MISC_DAS_BASE, "tegra20-das", NULL),
|
||||
static struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB_BASE, "tegra-ehci.0",
|
||||
&tegra_ehci1_pdata),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB2_BASE, "tegra-ehci.1",
|
||||
&tegra_ehci2_pdata),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB3_BASE, "tegra-ehci.2",
|
||||
&tegra_ehci3_pdata),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-apbdma", TEGRA_APB_DMA_BASE, "tegra-apbdma", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-sflash", 0x7000c380, "spi", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000D400, "spi_tegra.0", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000D600, "spi_tegra.1", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000D800, "spi_tegra.2", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000DA00, "spi_tegra.3", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-host1x", 0x50000000, "host1x", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-dc", 0x54200000, "tegradc.0", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-dc", 0x54240000, "tegradc.1", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-hdmi", 0x54280000, "hdmi", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-dsi", 0x54300000, "dsi", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-tvo", 0x542c0000, "tvo", NULL),
|
||||
{}
|
||||
};
|
||||
|
||||
static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = {
|
||||
/* name parent rate enabled */
|
||||
{ "uarta", "pll_p", 216000000, true },
|
||||
{ "uartd", "pll_p", 216000000, true },
|
||||
{ "usbd", "clk_m", 12000000, false },
|
||||
{ "usb2", "clk_m", 12000000, false },
|
||||
{ "usb3", "clk_m", 12000000, false },
|
||||
{ "pll_a", "pll_p_out1", 56448000, true },
|
||||
{ "pll_a_out0", "pll_a", 11289600, true },
|
||||
{ "cdev1", NULL, 0, true },
|
||||
{ "blink", "clk_32k", 32768, true },
|
||||
{ "i2s1", "pll_a_out0", 11289600, false},
|
||||
{ "i2s2", "pll_a_out0", 11289600, false},
|
||||
{ "sdmmc1", "pll_p", 48000000, false},
|
||||
{ "sdmmc3", "pll_p", 48000000, false},
|
||||
{ "sdmmc4", "pll_p", 48000000, false},
|
||||
{ "spi", "pll_p", 20000000, false },
|
||||
{ "sbc1", "pll_p", 100000000, false },
|
||||
{ "sbc2", "pll_p", 100000000, false },
|
||||
{ "sbc3", "pll_p", 100000000, false },
|
||||
{ "sbc4", "pll_p", 100000000, false },
|
||||
{ "host1x", "pll_c", 150000000, false },
|
||||
{ "disp1", "pll_p", 600000000, false },
|
||||
{ "disp2", "pll_p", 600000000, false },
|
||||
{ NULL, NULL, 0, 0},
|
||||
};
|
||||
|
||||
static void __init tegra_dt_init(void)
|
||||
{
|
||||
tegra_clk_init_from_table(tegra_dt_clk_init_table);
|
||||
|
||||
/*
|
||||
* Finished with the static registrations now; fill in the missing
|
||||
* devices
|
||||
|
@ -200,7 +147,7 @@ DT_MACHINE_START(TEGRA_DT, "nVidia Tegra20 (Flattened Device Tree)")
|
|||
.smp = smp_ops(tegra_smp_ops),
|
||||
.init_early = tegra20_init_early,
|
||||
.init_irq = tegra_dt_init_irq,
|
||||
.init_time = tegra_init_timer,
|
||||
.init_time = clocksource_of_init,
|
||||
.init_machine = tegra_dt_init,
|
||||
.init_late = tegra_dt_init_late,
|
||||
.restart = tegra_assert_system_reset,
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
|
@ -33,72 +34,12 @@
|
|||
#include <asm/mach/arch.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "clock.h"
|
||||
#include "common.h"
|
||||
#include "iomap.h"
|
||||
|
||||
struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = {
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000000, "sdhci-tegra.0", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000200, "sdhci-tegra.1", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000400, "sdhci-tegra.2", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000600, "sdhci-tegra.3", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C000, "tegra-i2c.0", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C400, "tegra-i2c.1", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C500, "tegra-i2c.2", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C700, "tegra-i2c.3", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000D000, "tegra-i2c.4", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra30-ahub", 0x70080000, "tegra30-ahub", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra30-apbdma", 0x6000a000, "tegra-apbdma", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra30-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000D400, "spi_tegra.0", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000D600, "spi_tegra.1", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000D800, "spi_tegra.2", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000DA00, "spi_tegra.3", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000DC00, "spi_tegra.4", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000DE00, "spi_tegra.5", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra30-host1x", 0x50000000, "host1x", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra30-dc", 0x54200000, "tegradc.0", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra30-dc", 0x54240000, "tegradc.1", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra30-hdmi", 0x54280000, "hdmi", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra30-dsi", 0x54300000, "dsi", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra30-tvo", 0x542c0000, "tvo", NULL),
|
||||
{}
|
||||
};
|
||||
|
||||
static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = {
|
||||
/* name parent rate enabled */
|
||||
{ "uarta", "pll_p", 408000000, true },
|
||||
{ "pll_a", "pll_p_out1", 564480000, true },
|
||||
{ "pll_a_out0", "pll_a", 11289600, true },
|
||||
{ "extern1", "pll_a_out0", 0, true },
|
||||
{ "clk_out_1", "extern1", 0, true },
|
||||
{ "blink", "clk_32k", 32768, true },
|
||||
{ "i2s0", "pll_a_out0", 11289600, false},
|
||||
{ "i2s1", "pll_a_out0", 11289600, false},
|
||||
{ "i2s2", "pll_a_out0", 11289600, false},
|
||||
{ "i2s3", "pll_a_out0", 11289600, false},
|
||||
{ "i2s4", "pll_a_out0", 11289600, false},
|
||||
{ "sdmmc1", "pll_p", 48000000, false},
|
||||
{ "sdmmc3", "pll_p", 48000000, false},
|
||||
{ "sdmmc4", "pll_p", 48000000, false},
|
||||
{ "sbc1", "pll_p", 100000000, false},
|
||||
{ "sbc2", "pll_p", 100000000, false},
|
||||
{ "sbc3", "pll_p", 100000000, false},
|
||||
{ "sbc4", "pll_p", 100000000, false},
|
||||
{ "sbc5", "pll_p", 100000000, false},
|
||||
{ "sbc6", "pll_p", 100000000, false},
|
||||
{ "host1x", "pll_c", 150000000, false},
|
||||
{ "disp1", "pll_p", 600000000, false},
|
||||
{ "disp2", "pll_p", 600000000, false},
|
||||
{ NULL, NULL, 0, 0},
|
||||
};
|
||||
|
||||
static void __init tegra30_dt_init(void)
|
||||
{
|
||||
tegra_clk_init_from_table(tegra_dt_clk_init_table);
|
||||
|
||||
of_platform_populate(NULL, of_default_bus_match_table,
|
||||
tegra30_auxdata_lookup, NULL);
|
||||
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
|
||||
}
|
||||
|
||||
static const char *tegra30_dt_board_compat[] = {
|
||||
|
@ -111,7 +52,7 @@ DT_MACHINE_START(TEGRA30_DT, "NVIDIA Tegra30 (Flattened Device Tree)")
|
|||
.map_io = tegra_map_common_io,
|
||||
.init_early = tegra30_init_early,
|
||||
.init_irq = tegra_dt_init_irq,
|
||||
.init_time = tegra_init_timer,
|
||||
.init_time = clocksource_of_init,
|
||||
.init_machine = tegra30_dt_init,
|
||||
.init_late = tegra_init_late,
|
||||
.restart = tegra_assert_system_reset,
|
||||
|
|
|
@ -55,5 +55,4 @@ static inline int harmony_pcie_init(void) { return 0; }
|
|||
|
||||
void __init tegra_paz00_wifikill_init(void);
|
||||
|
||||
extern void tegra_init_timer(void);
|
||||
#endif
|
||||
|
|
|
@ -1,166 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
* Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Colin Cross <ccross@google.com>
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "clock.h"
|
||||
#include "tegra_cpu_car.h"
|
||||
|
||||
/* Global data of Tegra CPU CAR ops */
|
||||
struct tegra_cpu_car_ops *tegra_cpu_car_ops;
|
||||
|
||||
/*
|
||||
* Locking:
|
||||
*
|
||||
* An additional mutex, clock_list_lock, is used to protect the list of all
|
||||
* clocks.
|
||||
*
|
||||
*/
|
||||
static DEFINE_MUTEX(clock_list_lock);
|
||||
static LIST_HEAD(clocks);
|
||||
|
||||
void tegra_clk_add(struct clk *clk)
|
||||
{
|
||||
struct clk_tegra *c = to_clk_tegra(__clk_get_hw(clk));
|
||||
|
||||
mutex_lock(&clock_list_lock);
|
||||
list_add(&c->node, &clocks);
|
||||
mutex_unlock(&clock_list_lock);
|
||||
}
|
||||
|
||||
struct clk *tegra_get_clock_by_name(const char *name)
|
||||
{
|
||||
struct clk_tegra *c;
|
||||
struct clk *ret = NULL;
|
||||
mutex_lock(&clock_list_lock);
|
||||
list_for_each_entry(c, &clocks, node) {
|
||||
if (strcmp(__clk_get_name(c->hw.clk), name) == 0) {
|
||||
ret = c->hw.clk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&clock_list_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table)
|
||||
{
|
||||
struct clk *c;
|
||||
struct clk *p;
|
||||
struct clk *parent;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
c = tegra_get_clock_by_name(table->name);
|
||||
|
||||
if (!c) {
|
||||
pr_warn("Unable to initialize clock %s\n",
|
||||
table->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
parent = clk_get_parent(c);
|
||||
|
||||
if (table->parent) {
|
||||
p = tegra_get_clock_by_name(table->parent);
|
||||
if (!p) {
|
||||
pr_warn("Unable to find parent %s of clock %s\n",
|
||||
table->parent, table->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (parent != p) {
|
||||
ret = clk_set_parent(c, p);
|
||||
if (ret) {
|
||||
pr_warn("Unable to set parent %s of clock %s: %d\n",
|
||||
table->parent, table->name, ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (table->rate && table->rate != clk_get_rate(c)) {
|
||||
ret = clk_set_rate(c, table->rate);
|
||||
if (ret) {
|
||||
pr_warn("Unable to set clock %s to rate %lu: %d\n",
|
||||
table->name, table->rate, ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (table->enabled) {
|
||||
ret = clk_prepare_enable(c);
|
||||
if (ret) {
|
||||
pr_warn("Unable to enable clock %s: %d\n",
|
||||
table->name, ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tegra_clk_init_from_table(struct tegra_clk_init_table *table)
|
||||
{
|
||||
for (; table->name; table++)
|
||||
tegra_clk_init_one_from_table(table);
|
||||
}
|
||||
|
||||
void tegra_periph_reset_deassert(struct clk *c)
|
||||
{
|
||||
struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c));
|
||||
BUG_ON(!clk->reset);
|
||||
clk->reset(__clk_get_hw(c), false);
|
||||
}
|
||||
EXPORT_SYMBOL(tegra_periph_reset_deassert);
|
||||
|
||||
void tegra_periph_reset_assert(struct clk *c)
|
||||
{
|
||||
struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c));
|
||||
BUG_ON(!clk->reset);
|
||||
clk->reset(__clk_get_hw(c), true);
|
||||
}
|
||||
EXPORT_SYMBOL(tegra_periph_reset_assert);
|
||||
|
||||
/* Several extended clock configuration bits (e.g., clock routing, clock
|
||||
* phase control) are included in PLL and peripheral clock source
|
||||
* registers. */
|
||||
int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
|
||||
{
|
||||
int ret = 0;
|
||||
struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c));
|
||||
|
||||
if (!clk->clk_cfg_ex) {
|
||||
ret = -ENOSYS;
|
||||
goto out;
|
||||
}
|
||||
ret = clk->clk_cfg_ex(__clk_get_hw(c), p, setting);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
|
@ -1,153 +0,0 @@
|
|||
/*
|
||||
* arch/arm/mach-tegra/include/mach/clock.h
|
||||
*
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
* Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Colin Cross <ccross@google.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MACH_TEGRA_CLOCK_H
|
||||
#define __MACH_TEGRA_CLOCK_H
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#include <mach/clk.h>
|
||||
|
||||
#define DIV_BUS (1 << 0)
|
||||
#define DIV_U71 (1 << 1)
|
||||
#define DIV_U71_FIXED (1 << 2)
|
||||
#define DIV_2 (1 << 3)
|
||||
#define DIV_U16 (1 << 4)
|
||||
#define PLL_FIXED (1 << 5)
|
||||
#define PLL_HAS_CPCON (1 << 6)
|
||||
#define MUX (1 << 7)
|
||||
#define PLLD (1 << 8)
|
||||
#define PERIPH_NO_RESET (1 << 9)
|
||||
#define PERIPH_NO_ENB (1 << 10)
|
||||
#define PERIPH_EMC_ENB (1 << 11)
|
||||
#define PERIPH_MANUAL_RESET (1 << 12)
|
||||
#define PLL_ALT_MISC_REG (1 << 13)
|
||||
#define PLLU (1 << 14)
|
||||
#define PLLX (1 << 15)
|
||||
#define MUX_PWM (1 << 16)
|
||||
#define MUX8 (1 << 17)
|
||||
#define DIV_U71_UART (1 << 18)
|
||||
#define MUX_CLK_OUT (1 << 19)
|
||||
#define PLLM (1 << 20)
|
||||
#define DIV_U71_INT (1 << 21)
|
||||
#define DIV_U71_IDLE (1 << 22)
|
||||
#define ENABLE_ON_INIT (1 << 28)
|
||||
#define PERIPH_ON_APB (1 << 29)
|
||||
|
||||
struct clk_tegra;
|
||||
#define to_clk_tegra(_hw) container_of(_hw, struct clk_tegra, hw)
|
||||
|
||||
struct clk_mux_sel {
|
||||
struct clk *input;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
struct clk_pll_freq_table {
|
||||
unsigned long input_rate;
|
||||
unsigned long output_rate;
|
||||
u16 n;
|
||||
u16 m;
|
||||
u8 p;
|
||||
u8 cpcon;
|
||||
};
|
||||
|
||||
enum clk_state {
|
||||
UNINITIALIZED = 0,
|
||||
ON,
|
||||
OFF,
|
||||
};
|
||||
|
||||
struct clk_tegra {
|
||||
/* node for master clocks list */
|
||||
struct list_head node; /* node for list of all clocks */
|
||||
struct clk_lookup lookup;
|
||||
struct clk_hw hw;
|
||||
|
||||
bool set;
|
||||
unsigned long fixed_rate;
|
||||
unsigned long max_rate;
|
||||
unsigned long min_rate;
|
||||
u32 flags;
|
||||
const char *name;
|
||||
|
||||
enum clk_state state;
|
||||
u32 div;
|
||||
u32 mul;
|
||||
|
||||
u32 reg;
|
||||
u32 reg_shift;
|
||||
|
||||
struct list_head shared_bus_list;
|
||||
|
||||
union {
|
||||
struct {
|
||||
unsigned int clk_num;
|
||||
} periph;
|
||||
struct {
|
||||
unsigned long input_min;
|
||||
unsigned long input_max;
|
||||
unsigned long cf_min;
|
||||
unsigned long cf_max;
|
||||
unsigned long vco_min;
|
||||
unsigned long vco_max;
|
||||
const struct clk_pll_freq_table *freq_table;
|
||||
int lock_delay;
|
||||
unsigned long fixed_rate;
|
||||
} pll;
|
||||
struct {
|
||||
u32 sel;
|
||||
u32 reg_mask;
|
||||
} mux;
|
||||
struct {
|
||||
struct clk *main;
|
||||
struct clk *backup;
|
||||
} cpu;
|
||||
struct {
|
||||
struct list_head node;
|
||||
bool enabled;
|
||||
unsigned long rate;
|
||||
} shared_bus_user;
|
||||
} u;
|
||||
|
||||
void (*reset)(struct clk_hw *, bool);
|
||||
int (*clk_cfg_ex)(struct clk_hw *, enum tegra_clk_ex_param, u32);
|
||||
};
|
||||
|
||||
struct clk_duplicate {
|
||||
const char *name;
|
||||
struct clk_lookup lookup;
|
||||
};
|
||||
|
||||
struct tegra_clk_init_table {
|
||||
const char *name;
|
||||
const char *parent;
|
||||
unsigned long rate;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
void tegra_clk_add(struct clk *c);
|
||||
void tegra2_init_clocks(void);
|
||||
void tegra30_init_clocks(void);
|
||||
struct clk *tegra_get_clock_by_name(const char *name);
|
||||
void tegra_clk_init_from_table(struct tegra_clk_init_table *table);
|
||||
|
||||
#endif
|
|
@ -22,13 +22,13 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
|
||||
#include <asm/hardware/cache-l2x0.h>
|
||||
|
||||
#include <mach/powergate.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "clock.h"
|
||||
#include "common.h"
|
||||
#include "fuse.h"
|
||||
#include "iomap.h"
|
||||
|
@ -36,6 +36,7 @@
|
|||
#include "apbio.h"
|
||||
#include "sleep.h"
|
||||
#include "pm.h"
|
||||
#include "reset.h"
|
||||
|
||||
/*
|
||||
* Storage for debug-macro.S's state.
|
||||
|
@ -58,6 +59,7 @@ u32 tegra_uart_config[4] = {
|
|||
#ifdef CONFIG_OF
|
||||
void __init tegra_dt_init_irq(void)
|
||||
{
|
||||
tegra_clocks_init();
|
||||
tegra_init_irq();
|
||||
irqchip_init();
|
||||
}
|
||||
|
@ -73,43 +75,6 @@ void tegra_assert_system_reset(char mode, const char *cmd)
|
|||
writel_relaxed(reg, reset);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||
static __initdata struct tegra_clk_init_table tegra20_clk_init_table[] = {
|
||||
/* name parent rate enabled */
|
||||
{ "clk_m", NULL, 0, true },
|
||||
{ "pll_p", "clk_m", 216000000, true },
|
||||
{ "pll_p_out1", "pll_p", 28800000, true },
|
||||
{ "pll_p_out2", "pll_p", 48000000, true },
|
||||
{ "pll_p_out3", "pll_p", 72000000, true },
|
||||
{ "pll_p_out4", "pll_p", 24000000, true },
|
||||
{ "pll_c", "clk_m", 600000000, true },
|
||||
{ "pll_c_out1", "pll_c", 120000000, true },
|
||||
{ "sclk", "pll_c_out1", 120000000, true },
|
||||
{ "hclk", "sclk", 120000000, true },
|
||||
{ "pclk", "hclk", 60000000, true },
|
||||
{ "csite", NULL, 0, true },
|
||||
{ "emc", NULL, 0, true },
|
||||
{ "cpu", NULL, 0, true },
|
||||
{ NULL, NULL, 0, 0},
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
|
||||
static __initdata struct tegra_clk_init_table tegra30_clk_init_table[] = {
|
||||
/* name parent rate enabled */
|
||||
{ "clk_m", NULL, 0, true },
|
||||
{ "pll_p", "pll_ref", 408000000, true },
|
||||
{ "pll_p_out1", "pll_p", 9600000, true },
|
||||
{ "pll_p_out4", "pll_p", 102000000, true },
|
||||
{ "sclk", "pll_p_out4", 102000000, true },
|
||||
{ "hclk", "sclk", 102000000, true },
|
||||
{ "pclk", "hclk", 51000000, true },
|
||||
{ "csite", NULL, 0, true },
|
||||
{ NULL, NULL, 0, 0},
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
static void __init tegra_init_cache(void)
|
||||
{
|
||||
#ifdef CONFIG_CACHE_L2X0
|
||||
|
@ -131,10 +96,9 @@ static void __init tegra_init_cache(void)
|
|||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||
void __init tegra20_init_early(void)
|
||||
{
|
||||
tegra_cpu_reset_handler_init();
|
||||
tegra_apb_io_init();
|
||||
tegra_init_fuse();
|
||||
tegra2_init_clocks();
|
||||
tegra_clk_init_from_table(tegra20_clk_init_table);
|
||||
tegra_init_cache();
|
||||
tegra_pmc_init();
|
||||
tegra_powergate_init();
|
||||
|
@ -144,10 +108,9 @@ void __init tegra20_init_early(void)
|
|||
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
|
||||
void __init tegra30_init_early(void)
|
||||
{
|
||||
tegra_cpu_reset_handler_init();
|
||||
tegra_apb_io_init();
|
||||
tegra_init_fuse();
|
||||
tegra30_init_clocks();
|
||||
tegra_clk_init_from_table(tegra30_clk_init_table);
|
||||
tegra_init_cache();
|
||||
tegra_pmc_init();
|
||||
tegra_powergate_init();
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
extern struct smp_operations tegra_smp_ops;
|
||||
|
||||
extern int tegra_cpu_kill(unsigned int cpu);
|
||||
extern void tegra_cpu_die(unsigned int cpu);
|
||||
extern int tegra_cpu_disable(unsigned int cpu);
|
||||
|
|
|
@ -214,24 +214,6 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)
|
|||
if (policy->cpu >= NUM_CPUS)
|
||||
return -EINVAL;
|
||||
|
||||
cpu_clk = clk_get_sys(NULL, "cpu");
|
||||
if (IS_ERR(cpu_clk))
|
||||
return PTR_ERR(cpu_clk);
|
||||
|
||||
pll_x_clk = clk_get_sys(NULL, "pll_x");
|
||||
if (IS_ERR(pll_x_clk))
|
||||
return PTR_ERR(pll_x_clk);
|
||||
|
||||
pll_p_clk = clk_get_sys(NULL, "pll_p");
|
||||
if (IS_ERR(pll_p_clk))
|
||||
return PTR_ERR(pll_p_clk);
|
||||
|
||||
emc_clk = clk_get_sys("cpu", "emc");
|
||||
if (IS_ERR(emc_clk)) {
|
||||
clk_put(cpu_clk);
|
||||
return PTR_ERR(emc_clk);
|
||||
}
|
||||
|
||||
clk_prepare_enable(emc_clk);
|
||||
clk_prepare_enable(cpu_clk);
|
||||
|
||||
|
@ -256,8 +238,6 @@ static int tegra_cpu_exit(struct cpufreq_policy *policy)
|
|||
{
|
||||
cpufreq_frequency_table_cpuinfo(policy, freq_table);
|
||||
clk_disable_unprepare(emc_clk);
|
||||
clk_put(emc_clk);
|
||||
clk_put(cpu_clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -278,12 +258,32 @@ static struct cpufreq_driver tegra_cpufreq_driver = {
|
|||
|
||||
static int __init tegra_cpufreq_init(void)
|
||||
{
|
||||
cpu_clk = clk_get_sys(NULL, "cpu");
|
||||
if (IS_ERR(cpu_clk))
|
||||
return PTR_ERR(cpu_clk);
|
||||
|
||||
pll_x_clk = clk_get_sys(NULL, "pll_x");
|
||||
if (IS_ERR(pll_x_clk))
|
||||
return PTR_ERR(pll_x_clk);
|
||||
|
||||
pll_p_clk = clk_get_sys(NULL, "pll_p_cclk");
|
||||
if (IS_ERR(pll_p_clk))
|
||||
return PTR_ERR(pll_p_clk);
|
||||
|
||||
emc_clk = clk_get_sys("cpu", "emc");
|
||||
if (IS_ERR(emc_clk)) {
|
||||
clk_put(cpu_clk);
|
||||
return PTR_ERR(emc_clk);
|
||||
}
|
||||
|
||||
return cpufreq_register_driver(&tegra_cpufreq_driver);
|
||||
}
|
||||
|
||||
static void __exit tegra_cpufreq_exit(void)
|
||||
{
|
||||
cpufreq_unregister_driver(&tegra_cpufreq_driver);
|
||||
clk_put(emc_clk);
|
||||
clk_put(cpu_clk);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/cpuidle.h>
|
||||
#include <linux/cpu_pm.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
|
||||
#include <asm/cpuidle.h>
|
||||
#include <asm/proc-fns.h>
|
||||
|
@ -32,7 +33,6 @@
|
|||
|
||||
#include "pm.h"
|
||||
#include "sleep.h"
|
||||
#include "tegra_cpu_car.h"
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int tegra30_idle_lp2(struct cpuidle_device *dev,
|
||||
|
@ -121,9 +121,9 @@ static inline bool tegra30_cpu_core_power_down(struct cpuidle_device *dev,
|
|||
}
|
||||
#endif
|
||||
|
||||
static int __cpuinit tegra30_idle_lp2(struct cpuidle_device *dev,
|
||||
struct cpuidle_driver *drv,
|
||||
int index)
|
||||
static int tegra30_idle_lp2(struct cpuidle_device *dev,
|
||||
struct cpuidle_driver *drv,
|
||||
int index)
|
||||
{
|
||||
u32 cpu = is_smp() ? cpu_logical_map(dev->cpu) : dev->cpu;
|
||||
bool entered_lp2 = false;
|
||||
|
|
|
@ -26,14 +26,14 @@
|
|||
#include "flowctrl.h"
|
||||
#include "iomap.h"
|
||||
|
||||
u8 flowctrl_offset_halt_cpu[] = {
|
||||
static u8 flowctrl_offset_halt_cpu[] = {
|
||||
FLOW_CTRL_HALT_CPU0_EVENTS,
|
||||
FLOW_CTRL_HALT_CPU1_EVENTS,
|
||||
FLOW_CTRL_HALT_CPU1_EVENTS + 8,
|
||||
FLOW_CTRL_HALT_CPU1_EVENTS + 16,
|
||||
};
|
||||
|
||||
u8 flowctrl_offset_cpu_csr[] = {
|
||||
static u8 flowctrl_offset_cpu_csr[] = {
|
||||
FLOW_CTRL_CPU0_CSR,
|
||||
FLOW_CTRL_CPU1_CSR,
|
||||
FLOW_CTRL_CPU1_CSR + 8,
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/tegra-soc.h>
|
||||
|
||||
#include "fuse.h"
|
||||
#include "iomap.h"
|
||||
|
@ -105,6 +106,11 @@ static void tegra_get_process_id(void)
|
|||
tegra_core_process_id = (reg >> 12) & 3;
|
||||
}
|
||||
|
||||
u32 tegra_read_chipid(void)
|
||||
{
|
||||
return readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804);
|
||||
}
|
||||
|
||||
void tegra_init_fuse(void)
|
||||
{
|
||||
u32 id;
|
||||
|
@ -119,7 +125,7 @@ void tegra_init_fuse(void)
|
|||
reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT);
|
||||
tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT;
|
||||
|
||||
id = readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804);
|
||||
id = tegra_read_chipid();
|
||||
tegra_chip_id = (id >> 8) & 0xff;
|
||||
|
||||
switch (tegra_chip_id) {
|
||||
|
|
|
@ -1,22 +1,9 @@
|
|||
#include <linux/linkage.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/cache.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/hardware/cache-l2x0.h>
|
||||
|
||||
#include "flowctrl.h"
|
||||
#include "iomap.h"
|
||||
#include "reset.h"
|
||||
#include "sleep.h"
|
||||
|
||||
#define APB_MISC_GP_HIDREV 0x804
|
||||
#define PMC_SCRATCH41 0x140
|
||||
|
||||
#define RESET_DATA(x) ((TEGRA_RESET_##x)*4)
|
||||
|
||||
.section ".text.head", "ax"
|
||||
__CPUINIT
|
||||
|
||||
/*
|
||||
* Tegra specific entry point for secondary CPUs.
|
||||
|
@ -61,7 +48,6 @@ ENTRY(v7_invalidate_l1)
|
|||
mov pc, lr
|
||||
ENDPROC(v7_invalidate_l1)
|
||||
|
||||
|
||||
ENTRY(tegra_secondary_startup)
|
||||
bl v7_invalidate_l1
|
||||
/* Enable coresight */
|
||||
|
@ -69,210 +55,3 @@ ENTRY(tegra_secondary_startup)
|
|||
mcr p14, 0, r0, c7, c12, 6
|
||||
b secondary_startup
|
||||
ENDPROC(tegra_secondary_startup)
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/*
|
||||
* tegra_resume
|
||||
*
|
||||
* CPU boot vector when restarting the a CPU following
|
||||
* an LP2 transition. Also branched to by LP0 and LP1 resume after
|
||||
* re-enabling sdram.
|
||||
*/
|
||||
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?
|
||||
bne cpu_resume @ no
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_3x_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)
|
||||
beq 1f @ Yes
|
||||
/* Clear the flow controller flags for this CPU. */
|
||||
mov32 r2, TEGRA_FLOW_CTRL_BASE + FLOW_CTRL_CPU0_CSR @ CPU0 CSR
|
||||
ldr r1, [r2]
|
||||
/* Clear event & intr flag */
|
||||
orr r1, r1, \
|
||||
#FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
|
||||
movw r0, #0x0FFD @ enable, cluster_switch, immed, & bitmaps
|
||||
bic r1, r1, r0
|
||||
str r1, [r2]
|
||||
1:
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HAVE_ARM_SCU
|
||||
/* enable SCU */
|
||||
mov32 r0, TEGRA_ARM_PERIF_BASE
|
||||
ldr r1, [r0]
|
||||
orr r1, r1, #1
|
||||
str r1, [r0]
|
||||
#endif
|
||||
|
||||
/* L2 cache resume & re-enable */
|
||||
l2_cache_resume r0, r1, r2, l2x0_saved_regs_addr
|
||||
|
||||
b cpu_resume
|
||||
ENDPROC(tegra_resume)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CACHE_L2X0
|
||||
.globl l2x0_saved_regs_addr
|
||||
l2x0_saved_regs_addr:
|
||||
.long 0
|
||||
#endif
|
||||
|
||||
.align L1_CACHE_SHIFT
|
||||
ENTRY(__tegra_cpu_reset_handler_start)
|
||||
|
||||
/*
|
||||
* __tegra_cpu_reset_handler:
|
||||
*
|
||||
* Common handler for all CPU reset events.
|
||||
*
|
||||
* Register usage within the reset handler:
|
||||
*
|
||||
* R7 = CPU present (to the OS) mask
|
||||
* R8 = CPU in LP1 state mask
|
||||
* R9 = CPU in LP2 state mask
|
||||
* R10 = CPU number
|
||||
* R11 = CPU mask
|
||||
* R12 = pointer to reset handler data
|
||||
*
|
||||
* NOTE: This code is copied to IRAM. All code and data accesses
|
||||
* must be position-independent.
|
||||
*/
|
||||
|
||||
.align L1_CACHE_SHIFT
|
||||
ENTRY(__tegra_cpu_reset_handler)
|
||||
|
||||
cpsid aif, 0x13 @ SVC mode, interrupts disabled
|
||||
mrc p15, 0, r10, c0, c0, 5 @ MPIDR
|
||||
and r10, r10, #0x3 @ R10 = CPU number
|
||||
mov r11, #1
|
||||
mov r11, r11, lsl r10 @ R11 = CPU mask
|
||||
adr r12, __tegra_cpu_reset_handler_data
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* Does the OS know about this CPU? */
|
||||
ldr r7, [r12, #RESET_DATA(MASK_PRESENT)]
|
||||
tst r7, r11 @ if !present
|
||||
bleq __die @ CPU not present (to OS)
|
||||
#endif
|
||||
|
||||
#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)
|
||||
bne 1f
|
||||
/* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
|
||||
mov32 r6, TEGRA_PMC_BASE
|
||||
mov r0, #0
|
||||
cmp r10, #0
|
||||
strne r0, [r6, #PMC_SCRATCH41]
|
||||
1:
|
||||
#endif
|
||||
|
||||
/* Waking up from LP2? */
|
||||
ldr r9, [r12, #RESET_DATA(MASK_LP2)]
|
||||
tst r9, r11 @ if in_lp2
|
||||
beq __is_not_lp2
|
||||
ldr lr, [r12, #RESET_DATA(STARTUP_LP2)]
|
||||
cmp lr, #0
|
||||
bleq __die @ no LP2 startup handler
|
||||
bx lr
|
||||
|
||||
__is_not_lp2:
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/*
|
||||
* Can only be secondary boot (initial or hotplug) but CPU 0
|
||||
* cannot be here.
|
||||
*/
|
||||
cmp r10, #0
|
||||
bleq __die @ CPU0 cannot be here
|
||||
ldr lr, [r12, #RESET_DATA(STARTUP_SECONDARY)]
|
||||
cmp lr, #0
|
||||
bleq __die @ no secondary startup handler
|
||||
bx lr
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We don't know why the CPU reset. Just kill it.
|
||||
* The LR register will contain the address we died at + 4.
|
||||
*/
|
||||
|
||||
__die:
|
||||
sub lr, lr, #4
|
||||
mov32 r7, TEGRA_PMC_BASE
|
||||
str lr, [r7, #PMC_SCRATCH41]
|
||||
|
||||
mov32 r7, TEGRA_CLK_RESET_BASE
|
||||
|
||||
/* 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)
|
||||
bne 1f
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||
mov32 r0, 0x1111
|
||||
mov r1, r0, lsl r10
|
||||
str r1, [r7, #0x340] @ CLK_RST_CPU_CMPLX_SET
|
||||
#endif
|
||||
1:
|
||||
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
|
||||
mov32 r6, TEGRA_FLOW_CTRL_BASE
|
||||
|
||||
cmp r10, #0
|
||||
moveq r1, #FLOW_CTRL_HALT_CPU0_EVENTS
|
||||
moveq r2, #FLOW_CTRL_CPU0_CSR
|
||||
movne r1, r10, lsl #3
|
||||
addne r2, r1, #(FLOW_CTRL_CPU1_CSR-8)
|
||||
addne r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8)
|
||||
|
||||
/* Clear CPU "event" and "interrupt" flags and power gate
|
||||
it when halting but not before it is in the "WFI" state. */
|
||||
ldr r0, [r6, +r2]
|
||||
orr r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
|
||||
orr r0, r0, #FLOW_CTRL_CSR_ENABLE
|
||||
str r0, [r6, +r2]
|
||||
|
||||
/* Unconditionally halt this CPU */
|
||||
mov r0, #FLOW_CTRL_WAITEVENT
|
||||
str r0, [r6, +r1]
|
||||
ldr r0, [r6, +r1] @ memory barrier
|
||||
|
||||
dsb
|
||||
isb
|
||||
wfi @ CPU should be power gated here
|
||||
|
||||
/* If the CPU didn't power gate above just kill it's clock. */
|
||||
|
||||
mov r0, r11, lsl #8
|
||||
str r0, [r7, #348] @ CLK_CPU_CMPLX_SET
|
||||
#endif
|
||||
|
||||
/* If the CPU still isn't dead, just spin here. */
|
||||
b .
|
||||
ENDPROC(__tegra_cpu_reset_handler)
|
||||
|
||||
.align L1_CACHE_SHIFT
|
||||
.type __tegra_cpu_reset_handler_data, %object
|
||||
.globl __tegra_cpu_reset_handler_data
|
||||
__tegra_cpu_reset_handler_data:
|
||||
.rept TEGRA_RESET_DATA_SIZE
|
||||
.long 0
|
||||
.endr
|
||||
.align L1_CACHE_SHIFT
|
||||
|
||||
ENTRY(__tegra_cpu_reset_handler_end)
|
||||
|
|
|
@ -10,15 +10,26 @@
|
|||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/smp_plat.h>
|
||||
|
||||
#include "sleep.h"
|
||||
#include "tegra_cpu_car.h"
|
||||
|
||||
static void (*tegra_hotplug_shutdown)(void);
|
||||
|
||||
int tegra_cpu_kill(unsigned cpu)
|
||||
{
|
||||
cpu = cpu_logical_map(cpu);
|
||||
|
||||
/* Clock gate the CPU */
|
||||
tegra_wait_cpu_in_reset(cpu);
|
||||
tegra_disable_cpu_clock(cpu);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* platform-specific code to shutdown a CPU
|
||||
*
|
||||
|
@ -26,18 +37,12 @@ static void (*tegra_hotplug_shutdown)(void);
|
|||
*/
|
||||
void __ref tegra_cpu_die(unsigned int cpu)
|
||||
{
|
||||
cpu = cpu_logical_map(cpu);
|
||||
|
||||
/* Flush the L1 data cache. */
|
||||
flush_cache_all();
|
||||
/* Clean L1 data cache */
|
||||
tegra_disable_clean_inv_dcache();
|
||||
|
||||
/* Shut down the current CPU. */
|
||||
tegra_hotplug_shutdown();
|
||||
|
||||
/* Clock gate the CPU */
|
||||
tegra_wait_cpu_in_reset(cpu);
|
||||
tegra_disable_cpu_clock(cpu);
|
||||
|
||||
/* Should never return here. */
|
||||
BUG();
|
||||
}
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* arch/arm/mach-tegra/include/mach/clk.h
|
||||
*
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
*
|
||||
* Author:
|
||||
* Erik Gilling <konkers@google.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MACH_CLK_H
|
||||
#define __MACH_CLK_H
|
||||
|
||||
struct clk;
|
||||
|
||||
enum tegra_clk_ex_param {
|
||||
TEGRA_CLK_VI_INP_SEL,
|
||||
TEGRA_CLK_DTV_INVERT,
|
||||
TEGRA_CLK_NAND_PAD_DIV2_ENB,
|
||||
TEGRA_CLK_PLLD_CSI_OUT_ENB,
|
||||
TEGRA_CLK_PLLD_DSI_OUT_ENB,
|
||||
TEGRA_CLK_PLLD_MIPI_MUX_SEL,
|
||||
};
|
||||
|
||||
void tegra_periph_reset_deassert(struct clk *c);
|
||||
void tegra_periph_reset_assert(struct clk *c);
|
||||
|
||||
#ifndef CONFIG_COMMON_CLK
|
||||
unsigned long clk_get_rate_all_locked(struct clk *c);
|
||||
#endif
|
||||
|
||||
void tegra2_sdmmc_tap_delay(struct clk *c, int delay);
|
||||
int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting);
|
||||
|
||||
#endif
|
|
@ -33,11 +33,11 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
|
||||
#include <asm/sizes.h>
|
||||
#include <asm/mach/pci.h>
|
||||
|
||||
#include <mach/clk.h>
|
||||
#include <mach/powergate.h>
|
||||
|
||||
#include "board.h"
|
||||
|
|
|
@ -19,23 +19,25 @@
|
|||
#include <linux/smp.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irqchip/arm-gic.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/smp_scu.h>
|
||||
#include <asm/smp_plat.h>
|
||||
|
||||
#include <mach/powergate.h>
|
||||
|
||||
#include "fuse.h"
|
||||
#include "flowctrl.h"
|
||||
#include "reset.h"
|
||||
#include "tegra_cpu_car.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "iomap.h"
|
||||
|
||||
extern void tegra_secondary_startup(void);
|
||||
|
||||
static cpumask_t tegra_cpu_init_mask;
|
||||
static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE);
|
||||
|
||||
#define EVP_CPU_RESET_VECTOR \
|
||||
|
@ -50,6 +52,7 @@ static void __cpuinit tegra_secondary_init(unsigned int cpu)
|
|||
*/
|
||||
gic_secondary_init(0);
|
||||
|
||||
cpumask_set_cpu(cpu, &tegra_cpu_init_mask);
|
||||
}
|
||||
|
||||
static int tegra20_power_up_cpu(unsigned int cpu)
|
||||
|
@ -72,14 +75,42 @@ static int tegra30_power_up_cpu(unsigned int cpu)
|
|||
if (pwrgateid < 0)
|
||||
return pwrgateid;
|
||||
|
||||
/* If this is the first boot, toggle powergates directly. */
|
||||
/*
|
||||
* The power up sequence of cold boot CPU and warm boot CPU
|
||||
* was different.
|
||||
*
|
||||
* For warm boot CPU that was resumed from CPU hotplug, the
|
||||
* power will be resumed automatically after un-halting the
|
||||
* flow controller of the warm boot CPU. We need to wait for
|
||||
* the confirmaiton that the CPU is powered then removing
|
||||
* 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()
|
||||
* 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))
|
||||
goto remove_clamps;
|
||||
udelay(10);
|
||||
} while (time_before(jiffies, timeout));
|
||||
}
|
||||
|
||||
/*
|
||||
* The power status of the cold boot CPU is power gated as
|
||||
* default. To power up the cold boot CPU, the power should
|
||||
* be un-gated by un-toggling the power gate register
|
||||
* manually.
|
||||
*/
|
||||
if (!tegra_powergate_is_powered(pwrgateid)) {
|
||||
ret = tegra_powergate_power_on(pwrgateid);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Wait for the power to come up. */
|
||||
timeout = jiffies + 10*HZ;
|
||||
timeout = jiffies + msecs_to_jiffies(100);
|
||||
while (tegra_powergate_is_powered(pwrgateid)) {
|
||||
if (time_after(jiffies, timeout))
|
||||
return -ETIMEDOUT;
|
||||
|
@ -87,6 +118,7 @@ static int tegra30_power_up_cpu(unsigned int cpu)
|
|||
}
|
||||
}
|
||||
|
||||
remove_clamps:
|
||||
/* CPU partition is powered. Enable the CPU clock. */
|
||||
tegra_enable_cpu_clock(cpu);
|
||||
udelay(10);
|
||||
|
@ -105,6 +137,8 @@ static int __cpuinit tegra_boot_secondary(unsigned int cpu, struct task_struct *
|
|||
{
|
||||
int status;
|
||||
|
||||
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
|
||||
|
@ -163,7 +197,9 @@ static void __init tegra_smp_init_cpus(void)
|
|||
|
||||
static void __init tegra_smp_prepare_cpus(unsigned int max_cpus)
|
||||
{
|
||||
tegra_cpu_reset_handler_init();
|
||||
/* Always mark the boot CPU (CPU0) as initialized. */
|
||||
cpumask_set_cpu(0, &tegra_cpu_init_mask);
|
||||
|
||||
scu_enable(scu_base);
|
||||
}
|
||||
|
||||
|
@ -173,6 +209,7 @@ struct smp_operations tegra_smp_ops __initdata = {
|
|||
.smp_secondary_init = tegra_secondary_init,
|
||||
.smp_boot_secondary = tegra_boot_secondary,
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
.cpu_kill = tegra_cpu_kill,
|
||||
.cpu_die = tegra_cpu_die,
|
||||
.cpu_disable = tegra_cpu_disable,
|
||||
#endif
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/cpu_pm.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
|
||||
#include <asm/smp_plat.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
@ -36,7 +37,6 @@
|
|||
#include "reset.h"
|
||||
#include "flowctrl.h"
|
||||
#include "sleep.h"
|
||||
#include "tegra_cpu_car.h"
|
||||
|
||||
#define TEGRA_POWER_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */
|
||||
|
||||
|
@ -148,7 +148,7 @@ static void suspend_cpu_complex(void)
|
|||
save_cpu_arch_register();
|
||||
}
|
||||
|
||||
void __cpuinit tegra_clear_cpu_in_lp2(int phy_cpu_id)
|
||||
void tegra_clear_cpu_in_lp2(int phy_cpu_id)
|
||||
{
|
||||
u32 *cpu_in_lp2 = tegra_cpu_lp2_mask;
|
||||
|
||||
|
@ -160,7 +160,7 @@ void __cpuinit tegra_clear_cpu_in_lp2(int phy_cpu_id)
|
|||
spin_unlock(&tegra_lp2_lock);
|
||||
}
|
||||
|
||||
bool __cpuinit tegra_set_cpu_in_lp2(int phy_cpu_id)
|
||||
bool tegra_set_cpu_in_lp2(int phy_cpu_id)
|
||||
{
|
||||
bool last_cpu = false;
|
||||
cpumask_t *cpu_lp2_mask = tegra_cpu_lp2_mask;
|
||||
|
|
|
@ -26,8 +26,8 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
|
||||
#include <mach/clk.h>
|
||||
#include <mach/powergate.h>
|
||||
|
||||
#include "fuse.h"
|
||||
|
|
239
arch/arm/mach-tegra/reset-handler.S
Normal file
239
arch/arm/mach-tegra/reset-handler.S
Normal file
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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/linkage.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/cache.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/hardware/cache-l2x0.h>
|
||||
|
||||
#include "flowctrl.h"
|
||||
#include "iomap.h"
|
||||
#include "reset.h"
|
||||
#include "sleep.h"
|
||||
|
||||
#define APB_MISC_GP_HIDREV 0x804
|
||||
#define PMC_SCRATCH41 0x140
|
||||
|
||||
#define RESET_DATA(x) ((TEGRA_RESET_##x)*4)
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/*
|
||||
* tegra_resume
|
||||
*
|
||||
* CPU boot vector when restarting the a CPU following
|
||||
* an LP2 transition. Also branched to by LP0 and LP1 resume after
|
||||
* re-enabling sdram.
|
||||
*/
|
||||
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?
|
||||
bne cpu_resume @ no
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_3x_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)
|
||||
beq 1f @ Yes
|
||||
/* Clear the flow controller flags for this CPU. */
|
||||
mov32 r2, TEGRA_FLOW_CTRL_BASE + FLOW_CTRL_CPU0_CSR @ CPU0 CSR
|
||||
ldr r1, [r2]
|
||||
/* Clear event & intr flag */
|
||||
orr r1, r1, \
|
||||
#FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
|
||||
movw r0, #0x0FFD @ enable, cluster_switch, immed, & bitmaps
|
||||
bic r1, r1, r0
|
||||
str r1, [r2]
|
||||
1:
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HAVE_ARM_SCU
|
||||
/* enable SCU */
|
||||
mov32 r0, TEGRA_ARM_PERIF_BASE
|
||||
ldr r1, [r0]
|
||||
orr r1, r1, #1
|
||||
str r1, [r0]
|
||||
#endif
|
||||
|
||||
/* L2 cache resume & re-enable */
|
||||
l2_cache_resume r0, r1, r2, l2x0_saved_regs_addr
|
||||
|
||||
b cpu_resume
|
||||
ENDPROC(tegra_resume)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CACHE_L2X0
|
||||
.globl l2x0_saved_regs_addr
|
||||
l2x0_saved_regs_addr:
|
||||
.long 0
|
||||
#endif
|
||||
|
||||
.align L1_CACHE_SHIFT
|
||||
ENTRY(__tegra_cpu_reset_handler_start)
|
||||
|
||||
/*
|
||||
* __tegra_cpu_reset_handler:
|
||||
*
|
||||
* Common handler for all CPU reset events.
|
||||
*
|
||||
* Register usage within the reset handler:
|
||||
*
|
||||
* R7 = CPU present (to the OS) mask
|
||||
* R8 = CPU in LP1 state mask
|
||||
* R9 = CPU in LP2 state mask
|
||||
* R10 = CPU number
|
||||
* R11 = CPU mask
|
||||
* R12 = pointer to reset handler data
|
||||
*
|
||||
* NOTE: This code is copied to IRAM. All code and data accesses
|
||||
* must be position-independent.
|
||||
*/
|
||||
|
||||
.align L1_CACHE_SHIFT
|
||||
ENTRY(__tegra_cpu_reset_handler)
|
||||
|
||||
cpsid aif, 0x13 @ SVC mode, interrupts disabled
|
||||
mrc p15, 0, r10, c0, c0, 5 @ MPIDR
|
||||
and r10, r10, #0x3 @ R10 = CPU number
|
||||
mov r11, #1
|
||||
mov r11, r11, lsl r10 @ R11 = CPU mask
|
||||
adr r12, __tegra_cpu_reset_handler_data
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* Does the OS know about this CPU? */
|
||||
ldr r7, [r12, #RESET_DATA(MASK_PRESENT)]
|
||||
tst r7, r11 @ if !present
|
||||
bleq __die @ CPU not present (to OS)
|
||||
#endif
|
||||
|
||||
#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)
|
||||
bne 1f
|
||||
/* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
|
||||
mov32 r6, TEGRA_PMC_BASE
|
||||
mov r0, #0
|
||||
cmp r10, #0
|
||||
strne r0, [r6, #PMC_SCRATCH41]
|
||||
1:
|
||||
#endif
|
||||
|
||||
/* Waking up from LP2? */
|
||||
ldr r9, [r12, #RESET_DATA(MASK_LP2)]
|
||||
tst r9, r11 @ if in_lp2
|
||||
beq __is_not_lp2
|
||||
ldr lr, [r12, #RESET_DATA(STARTUP_LP2)]
|
||||
cmp lr, #0
|
||||
bleq __die @ no LP2 startup handler
|
||||
bx lr
|
||||
|
||||
__is_not_lp2:
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/*
|
||||
* Can only be secondary boot (initial or hotplug) but CPU 0
|
||||
* cannot be here.
|
||||
*/
|
||||
cmp r10, #0
|
||||
bleq __die @ CPU0 cannot be here
|
||||
ldr lr, [r12, #RESET_DATA(STARTUP_SECONDARY)]
|
||||
cmp lr, #0
|
||||
bleq __die @ no secondary startup handler
|
||||
bx lr
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We don't know why the CPU reset. Just kill it.
|
||||
* The LR register will contain the address we died at + 4.
|
||||
*/
|
||||
|
||||
__die:
|
||||
sub lr, lr, #4
|
||||
mov32 r7, TEGRA_PMC_BASE
|
||||
str lr, [r7, #PMC_SCRATCH41]
|
||||
|
||||
mov32 r7, TEGRA_CLK_RESET_BASE
|
||||
|
||||
/* 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)
|
||||
bne 1f
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||
mov32 r0, 0x1111
|
||||
mov r1, r0, lsl r10
|
||||
str r1, [r7, #0x340] @ CLK_RST_CPU_CMPLX_SET
|
||||
#endif
|
||||
1:
|
||||
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
|
||||
mov32 r6, TEGRA_FLOW_CTRL_BASE
|
||||
|
||||
cmp r10, #0
|
||||
moveq r1, #FLOW_CTRL_HALT_CPU0_EVENTS
|
||||
moveq r2, #FLOW_CTRL_CPU0_CSR
|
||||
movne r1, r10, lsl #3
|
||||
addne r2, r1, #(FLOW_CTRL_CPU1_CSR-8)
|
||||
addne r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8)
|
||||
|
||||
/* Clear CPU "event" and "interrupt" flags and power gate
|
||||
it when halting but not before it is in the "WFI" state. */
|
||||
ldr r0, [r6, +r2]
|
||||
orr r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
|
||||
orr r0, r0, #FLOW_CTRL_CSR_ENABLE
|
||||
str r0, [r6, +r2]
|
||||
|
||||
/* Unconditionally halt this CPU */
|
||||
mov r0, #FLOW_CTRL_WAITEVENT
|
||||
str r0, [r6, +r1]
|
||||
ldr r0, [r6, +r1] @ memory barrier
|
||||
|
||||
dsb
|
||||
isb
|
||||
wfi @ CPU should be power gated here
|
||||
|
||||
/* If the CPU didn't power gate above just kill it's clock. */
|
||||
|
||||
mov r0, r11, lsl #8
|
||||
str r0, [r7, #348] @ CLK_CPU_CMPLX_SET
|
||||
#endif
|
||||
|
||||
/* If the CPU still isn't dead, just spin here. */
|
||||
b .
|
||||
ENDPROC(__tegra_cpu_reset_handler)
|
||||
|
||||
.align L1_CACHE_SHIFT
|
||||
.type __tegra_cpu_reset_handler_data, %object
|
||||
.globl __tegra_cpu_reset_handler_data
|
||||
__tegra_cpu_reset_handler_data:
|
||||
.rept TEGRA_RESET_DATA_SIZE
|
||||
.long 0
|
||||
.endr
|
||||
.align L1_CACHE_SHIFT
|
||||
|
||||
ENTRY(__tegra_cpu_reset_handler_end)
|
|
@ -75,7 +75,7 @@ void __init tegra_cpu_reset_handler_init(void)
|
|||
|
||||
#ifdef CONFIG_SMP
|
||||
__tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_PRESENT] =
|
||||
*((u32 *)cpu_present_mask);
|
||||
*((u32 *)cpu_possible_mask);
|
||||
__tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_SECONDARY] =
|
||||
virt_to_phys((void *)tegra_secondary_startup);
|
||||
#endif
|
||||
|
|
|
@ -33,9 +33,6 @@
|
|||
* should never return
|
||||
*/
|
||||
ENTRY(tegra20_hotplug_shutdown)
|
||||
/* Turn off SMP coherency */
|
||||
exit_smp r4, r5
|
||||
|
||||
/* Put this CPU down */
|
||||
cpu_id r0
|
||||
bl tegra20_cpu_shutdown
|
||||
|
|
|
@ -32,9 +32,6 @@
|
|||
* Should never return.
|
||||
*/
|
||||
ENTRY(tegra30_hotplug_shutdown)
|
||||
/* Turn off SMP coherency */
|
||||
exit_smp r4, r5
|
||||
|
||||
/* Powergate this CPU */
|
||||
mov r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN
|
||||
bl tegra30_cpu_shutdown
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#include "flowctrl.h"
|
||||
#include "sleep.h"
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
|
||||
/*
|
||||
* tegra_disable_clean_inv_dcache
|
||||
*
|
||||
|
@ -60,7 +60,9 @@ ENTRY(tegra_disable_clean_inv_dcache)
|
|||
|
||||
ldmfd sp!, {r0, r4-r5, r7, r9-r11, pc}
|
||||
ENDPROC(tegra_disable_clean_inv_dcache)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/*
|
||||
* tegra_sleep_cpu_finish(unsigned long v2p)
|
||||
*
|
||||
|
|
|
@ -106,6 +106,7 @@
|
|||
#else
|
||||
void tegra_resume(void);
|
||||
int tegra_sleep_cpu_finish(unsigned long);
|
||||
void tegra_disable_clean_inv_dcache(void);
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
void tegra20_hotplug_init(void);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __MACH_TEGRA20_CLOCK_H
|
||||
#define __MACH_TEGRA20_CLOCK_H
|
||||
|
||||
extern struct clk_ops tegra_clk_32k_ops;
|
||||
extern struct clk_ops tegra_pll_ops;
|
||||
extern struct clk_ops tegra_clk_m_ops;
|
||||
extern struct clk_ops tegra_pll_div_ops;
|
||||
extern struct clk_ops tegra_pllx_ops;
|
||||
extern struct clk_ops tegra_plle_ops;
|
||||
extern struct clk_ops tegra_clk_double_ops;
|
||||
extern struct clk_ops tegra_cdev_clk_ops;
|
||||
extern struct clk_ops tegra_audio_sync_clk_ops;
|
||||
extern struct clk_ops tegra_super_ops;
|
||||
extern struct clk_ops tegra_cpu_ops;
|
||||
extern struct clk_ops tegra_twd_ops;
|
||||
extern struct clk_ops tegra_cop_ops;
|
||||
extern struct clk_ops tegra_bus_ops;
|
||||
extern struct clk_ops tegra_blink_clk_ops;
|
||||
extern struct clk_ops tegra_emc_clk_ops;
|
||||
extern struct clk_ops tegra_periph_clk_ops;
|
||||
extern struct clk_ops tegra_clk_shared_bus_ops;
|
||||
|
||||
void tegra2_periph_clk_reset(struct clk_hw *hw, bool assert);
|
||||
void tegra2_cop_clk_reset(struct clk_hw *hw, bool assert);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __MACH_TEGRA30_CLOCK_H
|
||||
#define __MACH_TEGRA30_CLOCK_H
|
||||
|
||||
extern struct clk_ops tegra30_clk_32k_ops;
|
||||
extern struct clk_ops tegra30_clk_m_ops;
|
||||
extern struct clk_ops tegra_clk_m_div_ops;
|
||||
extern struct clk_ops tegra_pll_ref_ops;
|
||||
extern struct clk_ops tegra30_pll_ops;
|
||||
extern struct clk_ops tegra30_pll_div_ops;
|
||||
extern struct clk_ops tegra_plld_ops;
|
||||
extern struct clk_ops tegra30_plle_ops;
|
||||
extern struct clk_ops tegra_cml_clk_ops;
|
||||
extern struct clk_ops tegra_pciex_clk_ops;
|
||||
extern struct clk_ops tegra_sync_source_ops;
|
||||
extern struct clk_ops tegra30_audio_sync_clk_ops;
|
||||
extern struct clk_ops tegra30_clk_double_ops;
|
||||
extern struct clk_ops tegra_clk_out_ops;
|
||||
extern struct clk_ops tegra30_super_ops;
|
||||
extern struct clk_ops tegra30_blink_clk_ops;
|
||||
extern struct clk_ops tegra30_twd_ops;
|
||||
extern struct clk_ops tegra30_bus_ops;
|
||||
extern struct clk_ops tegra30_periph_clk_ops;
|
||||
extern struct clk_ops tegra30_dsib_clk_ops;
|
||||
extern struct clk_ops tegra_nand_clk_ops;
|
||||
extern struct clk_ops tegra_vi_clk_ops;
|
||||
extern struct clk_ops tegra_dtv_clk_ops;
|
||||
extern struct clk_ops tegra_clk_shared_bus_ops;
|
||||
|
||||
int tegra30_plld_clk_cfg_ex(struct clk_hw *hw,
|
||||
enum tegra_clk_ex_param p, u32 setting);
|
||||
void tegra30_periph_clk_reset(struct clk_hw *hw, bool assert);
|
||||
int tegra30_vi_clk_cfg_ex(struct clk_hw *hw,
|
||||
enum tegra_clk_ex_param p, u32 setting);
|
||||
int tegra30_nand_clk_cfg_ex(struct clk_hw *hw,
|
||||
enum tegra_clk_ex_param p, u32 setting);
|
||||
int tegra30_dtv_clk_cfg_ex(struct clk_hw *hw,
|
||||
enum tegra_clk_ex_param p, u32 setting);
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -22,6 +22,7 @@ obj-$(CONFIG_ARCH_U8500) += ux500/
|
|||
obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
|
||||
obj-$(CONFIG_ARCH_SUNXI) += clk-sunxi.o
|
||||
obj-$(CONFIG_ARCH_ZYNQ) += clk-zynq.o
|
||||
obj-$(CONFIG_ARCH_TEGRA) += tegra/
|
||||
|
||||
# Chip specific
|
||||
obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
|
||||
|
|
11
drivers/clk/tegra/Makefile
Normal file
11
drivers/clk/tegra/Makefile
Normal file
|
@ -0,0 +1,11 @@
|
|||
obj-y += clk.o
|
||||
obj-y += clk-audio-sync.o
|
||||
obj-y += clk-divider.o
|
||||
obj-y += clk-periph.o
|
||||
obj-y += clk-periph-gate.o
|
||||
obj-y += clk-pll.o
|
||||
obj-y += clk-pll-out.o
|
||||
obj-y += clk-super.o
|
||||
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o
|
87
drivers/clk/tegra/clk-audio-sync.c
Normal file
87
drivers/clk/tegra/clk-audio-sync.c
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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-provider.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
static unsigned long clk_sync_source_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct tegra_clk_sync_source *sync = to_clk_sync_source(hw);
|
||||
|
||||
return sync->rate;
|
||||
}
|
||||
|
||||
static long clk_sync_source_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
struct tegra_clk_sync_source *sync = to_clk_sync_source(hw);
|
||||
|
||||
if (rate > sync->max_rate)
|
||||
return -EINVAL;
|
||||
else
|
||||
return rate;
|
||||
}
|
||||
|
||||
static int clk_sync_source_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct tegra_clk_sync_source *sync = to_clk_sync_source(hw);
|
||||
|
||||
sync->rate = rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct clk_ops tegra_clk_sync_source_ops = {
|
||||
.round_rate = clk_sync_source_round_rate,
|
||||
.set_rate = clk_sync_source_set_rate,
|
||||
.recalc_rate = clk_sync_source_recalc_rate,
|
||||
};
|
||||
|
||||
struct clk *tegra_clk_register_sync_source(const char *name,
|
||||
unsigned long rate, unsigned long max_rate)
|
||||
{
|
||||
struct tegra_clk_sync_source *sync;
|
||||
struct clk_init_data init;
|
||||
struct clk *clk;
|
||||
|
||||
sync = kzalloc(sizeof(*sync), GFP_KERNEL);
|
||||
if (!sync) {
|
||||
pr_err("%s: could not allocate sync source clk\n", __func__);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
sync->rate = rate;
|
||||
sync->max_rate = max_rate;
|
||||
|
||||
init.ops = &tegra_clk_sync_source_ops;
|
||||
init.name = name;
|
||||
init.flags = CLK_IS_ROOT;
|
||||
init.parent_names = NULL;
|
||||
init.num_parents = 0;
|
||||
|
||||
/* Data in .init is copied by clk_register(), so stack variable OK */
|
||||
sync->hw.init = &init;
|
||||
|
||||
clk = clk_register(NULL, &sync->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(sync);
|
||||
|
||||
return clk;
|
||||
}
|
187
drivers/clk/tegra/clk-divider.c
Normal file
187
drivers/clk/tegra/clk-divider.c
Normal file
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
#define pll_out_override(p) (BIT((p->shift - 6)))
|
||||
#define div_mask(d) ((1 << (d->width)) - 1)
|
||||
#define get_mul(d) (1 << d->frac_width)
|
||||
#define get_max_div(d) div_mask(d)
|
||||
|
||||
#define PERIPH_CLK_UART_DIV_ENB BIT(24)
|
||||
|
||||
static int get_div(struct tegra_clk_frac_div *divider, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
s64 divider_ux1 = parent_rate;
|
||||
u8 flags = divider->flags;
|
||||
int mul;
|
||||
|
||||
if (!rate)
|
||||
return 0;
|
||||
|
||||
mul = get_mul(divider);
|
||||
|
||||
if (!(flags & TEGRA_DIVIDER_INT))
|
||||
divider_ux1 *= mul;
|
||||
|
||||
if (flags & TEGRA_DIVIDER_ROUND_UP)
|
||||
divider_ux1 += rate - 1;
|
||||
|
||||
do_div(divider_ux1, rate);
|
||||
|
||||
if (flags & TEGRA_DIVIDER_INT)
|
||||
divider_ux1 *= mul;
|
||||
|
||||
divider_ux1 -= mul;
|
||||
|
||||
if (divider_ux1 < 0)
|
||||
return 0;
|
||||
|
||||
if (divider_ux1 > get_max_div(divider))
|
||||
return -EINVAL;
|
||||
|
||||
return divider_ux1;
|
||||
}
|
||||
|
||||
static unsigned long clk_frac_div_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct tegra_clk_frac_div *divider = to_clk_frac_div(hw);
|
||||
u32 reg;
|
||||
int div, mul;
|
||||
u64 rate = parent_rate;
|
||||
|
||||
reg = readl_relaxed(divider->reg) >> divider->shift;
|
||||
div = reg & div_mask(divider);
|
||||
|
||||
mul = get_mul(divider);
|
||||
div += mul;
|
||||
|
||||
rate *= mul;
|
||||
rate += div - 1;
|
||||
do_div(rate, div);
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static long clk_frac_div_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
struct tegra_clk_frac_div *divider = to_clk_frac_div(hw);
|
||||
int div, mul;
|
||||
unsigned long output_rate = *prate;
|
||||
|
||||
if (!rate)
|
||||
return output_rate;
|
||||
|
||||
div = get_div(divider, rate, output_rate);
|
||||
if (div < 0)
|
||||
return *prate;
|
||||
|
||||
mul = get_mul(divider);
|
||||
|
||||
return DIV_ROUND_UP(output_rate * mul, div + mul);
|
||||
}
|
||||
|
||||
static int clk_frac_div_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct tegra_clk_frac_div *divider = to_clk_frac_div(hw);
|
||||
int div;
|
||||
unsigned long flags = 0;
|
||||
u32 val;
|
||||
|
||||
div = get_div(divider, rate, parent_rate);
|
||||
if (div < 0)
|
||||
return div;
|
||||
|
||||
if (divider->lock)
|
||||
spin_lock_irqsave(divider->lock, flags);
|
||||
|
||||
val = readl_relaxed(divider->reg);
|
||||
val &= ~(div_mask(divider) << divider->shift);
|
||||
val |= div << divider->shift;
|
||||
|
||||
if (divider->flags & TEGRA_DIVIDER_UART) {
|
||||
if (div)
|
||||
val |= PERIPH_CLK_UART_DIV_ENB;
|
||||
else
|
||||
val &= ~PERIPH_CLK_UART_DIV_ENB;
|
||||
}
|
||||
|
||||
if (divider->flags & TEGRA_DIVIDER_FIXED)
|
||||
val |= pll_out_override(divider);
|
||||
|
||||
writel_relaxed(val, divider->reg);
|
||||
|
||||
if (divider->lock)
|
||||
spin_unlock_irqrestore(divider->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct clk_ops tegra_clk_frac_div_ops = {
|
||||
.recalc_rate = clk_frac_div_recalc_rate,
|
||||
.set_rate = clk_frac_div_set_rate,
|
||||
.round_rate = clk_frac_div_round_rate,
|
||||
};
|
||||
|
||||
struct clk *tegra_clk_register_divider(const char *name,
|
||||
const char *parent_name, void __iomem *reg,
|
||||
unsigned long flags, u8 clk_divider_flags, u8 shift, u8 width,
|
||||
u8 frac_width, spinlock_t *lock)
|
||||
{
|
||||
struct tegra_clk_frac_div *divider;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
divider = kzalloc(sizeof(*divider), GFP_KERNEL);
|
||||
if (!divider) {
|
||||
pr_err("%s: could not allocate fractional divider clk\n",
|
||||
__func__);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
init.name = name;
|
||||
init.ops = &tegra_clk_frac_div_ops;
|
||||
init.flags = flags;
|
||||
init.parent_names = parent_name ? &parent_name : NULL;
|
||||
init.num_parents = parent_name ? 1 : 0;
|
||||
|
||||
divider->reg = reg;
|
||||
divider->shift = shift;
|
||||
divider->width = width;
|
||||
divider->frac_width = frac_width;
|
||||
divider->lock = lock;
|
||||
divider->flags = clk_divider_flags;
|
||||
|
||||
/* Data in .init is copied by clk_register(), so stack variable OK */
|
||||
divider->hw.init = &init;
|
||||
|
||||
clk = clk_register(NULL, ÷r->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(divider);
|
||||
|
||||
return clk;
|
||||
}
|
179
drivers/clk/tegra/clk-periph-gate.c
Normal file
179
drivers/clk/tegra/clk-periph-gate.c
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/tegra-soc.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
static DEFINE_SPINLOCK(periph_ref_lock);
|
||||
|
||||
/* Macros to assist peripheral gate clock */
|
||||
#define read_enb(gate) \
|
||||
readl_relaxed(gate->clk_base + (gate->regs->enb_reg))
|
||||
#define write_enb_set(val, gate) \
|
||||
writel_relaxed(val, gate->clk_base + (gate->regs->enb_set_reg))
|
||||
#define write_enb_clr(val, gate) \
|
||||
writel_relaxed(val, gate->clk_base + (gate->regs->enb_clr_reg))
|
||||
|
||||
#define read_rst(gate) \
|
||||
readl_relaxed(gate->clk_base + (gate->regs->rst_reg))
|
||||
#define write_rst_set(val, gate) \
|
||||
writel_relaxed(val, gate->clk_base + (gate->regs->rst_set_reg))
|
||||
#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))
|
||||
|
||||
/* Peripheral gate clock ops */
|
||||
static int clk_periph_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
|
||||
int state = 1;
|
||||
|
||||
if (!(read_enb(gate) & periph_clk_to_bit(gate)))
|
||||
state = 0;
|
||||
|
||||
if (!(gate->flags & TEGRA_PERIPH_NO_RESET))
|
||||
if (read_rst(gate) & periph_clk_to_bit(gate))
|
||||
state = 0;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static int clk_periph_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
|
||||
unsigned long flags = 0;
|
||||
|
||||
spin_lock_irqsave(&periph_ref_lock, flags);
|
||||
|
||||
gate->enable_refcnt[gate->clk_num]++;
|
||||
if (gate->enable_refcnt[gate->clk_num] > 1) {
|
||||
spin_unlock_irqrestore(&periph_ref_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
write_enb_set(periph_clk_to_bit(gate), gate);
|
||||
udelay(2);
|
||||
|
||||
if (!(gate->flags & TEGRA_PERIPH_NO_RESET) &&
|
||||
!(gate->flags & TEGRA_PERIPH_MANUAL_RESET)) {
|
||||
if (read_rst(gate) & periph_clk_to_bit(gate)) {
|
||||
udelay(5); /* reset propogation delay */
|
||||
write_rst_clr(periph_clk_to_bit(gate), gate);
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&periph_ref_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_periph_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
|
||||
unsigned long flags = 0;
|
||||
|
||||
spin_lock_irqsave(&periph_ref_lock, flags);
|
||||
|
||||
gate->enable_refcnt[gate->clk_num]--;
|
||||
if (gate->enable_refcnt[gate->clk_num] > 0) {
|
||||
spin_unlock_irqrestore(&periph_ref_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If peripheral is in the APB bus then read the APB bus to
|
||||
* flush the write operation in apb bus. This will avoid the
|
||||
* peripheral access after disabling clock
|
||||
*/
|
||||
if (gate->flags & TEGRA_PERIPH_ON_APB)
|
||||
tegra_read_chipid();
|
||||
|
||||
write_enb_clr(periph_clk_to_bit(gate), gate);
|
||||
|
||||
spin_unlock_irqrestore(&periph_ref_lock, flags);
|
||||
}
|
||||
|
||||
void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert)
|
||||
{
|
||||
if (gate->flags & TEGRA_PERIPH_NO_RESET)
|
||||
return;
|
||||
|
||||
if (assert) {
|
||||
/*
|
||||
* If peripheral is in the APB bus then read the APB bus to
|
||||
* flush the write operation in apb bus. This will avoid the
|
||||
* peripheral access after disabling clock
|
||||
*/
|
||||
if (gate->flags & TEGRA_PERIPH_ON_APB)
|
||||
tegra_read_chipid();
|
||||
|
||||
write_rst_set(periph_clk_to_bit(gate), gate);
|
||||
} else {
|
||||
write_rst_clr(periph_clk_to_bit(gate), gate);
|
||||
}
|
||||
}
|
||||
|
||||
const struct clk_ops tegra_clk_periph_gate_ops = {
|
||||
.is_enabled = clk_periph_is_enabled,
|
||||
.enable = clk_periph_enable,
|
||||
.disable = clk_periph_disable,
|
||||
};
|
||||
|
||||
struct clk *tegra_clk_register_periph_gate(const char *name,
|
||||
const char *parent_name, u8 gate_flags, void __iomem *clk_base,
|
||||
unsigned long flags, int clk_num,
|
||||
struct tegra_clk_periph_regs *pregs, int *enable_refcnt)
|
||||
{
|
||||
struct tegra_clk_periph_gate *gate;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
|
||||
if (!gate) {
|
||||
pr_err("%s: could not allocate periph gate clk\n", __func__);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
init.name = name;
|
||||
init.flags = flags;
|
||||
init.parent_names = parent_name ? &parent_name : NULL;
|
||||
init.num_parents = parent_name ? 1 : 0;
|
||||
init.ops = &tegra_clk_periph_gate_ops;
|
||||
|
||||
gate->magic = TEGRA_CLK_PERIPH_GATE_MAGIC;
|
||||
gate->clk_base = clk_base;
|
||||
gate->clk_num = clk_num;
|
||||
gate->flags = gate_flags;
|
||||
gate->enable_refcnt = enable_refcnt;
|
||||
gate->regs = pregs;
|
||||
|
||||
/* Data in .init is copied by clk_register(), so stack variable OK */
|
||||
gate->hw.init = &init;
|
||||
|
||||
clk = clk_register(NULL, &gate->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(gate);
|
||||
|
||||
return clk;
|
||||
}
|
218
drivers/clk/tegra/clk-periph.c
Normal file
218
drivers/clk/tegra/clk-periph.c
Normal file
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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/slab.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
static u8 clk_periph_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct tegra_clk_periph *periph = to_clk_periph(hw);
|
||||
const struct clk_ops *mux_ops = periph->mux_ops;
|
||||
struct clk_hw *mux_hw = &periph->mux.hw;
|
||||
|
||||
mux_hw->clk = hw->clk;
|
||||
|
||||
return mux_ops->get_parent(mux_hw);
|
||||
}
|
||||
|
||||
static int clk_periph_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct tegra_clk_periph *periph = to_clk_periph(hw);
|
||||
const struct clk_ops *mux_ops = periph->mux_ops;
|
||||
struct clk_hw *mux_hw = &periph->mux.hw;
|
||||
|
||||
mux_hw->clk = hw->clk;
|
||||
|
||||
return mux_ops->set_parent(mux_hw, index);
|
||||
}
|
||||
|
||||
static unsigned long clk_periph_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct tegra_clk_periph *periph = to_clk_periph(hw);
|
||||
const struct clk_ops *div_ops = periph->div_ops;
|
||||
struct clk_hw *div_hw = &periph->divider.hw;
|
||||
|
||||
div_hw->clk = hw->clk;
|
||||
|
||||
return div_ops->recalc_rate(div_hw, parent_rate);
|
||||
}
|
||||
|
||||
static long clk_periph_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
struct tegra_clk_periph *periph = to_clk_periph(hw);
|
||||
const struct clk_ops *div_ops = periph->div_ops;
|
||||
struct clk_hw *div_hw = &periph->divider.hw;
|
||||
|
||||
div_hw->clk = hw->clk;
|
||||
|
||||
return div_ops->round_rate(div_hw, rate, prate);
|
||||
}
|
||||
|
||||
static int clk_periph_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct tegra_clk_periph *periph = to_clk_periph(hw);
|
||||
const struct clk_ops *div_ops = periph->div_ops;
|
||||
struct clk_hw *div_hw = &periph->divider.hw;
|
||||
|
||||
div_hw->clk = hw->clk;
|
||||
|
||||
return div_ops->set_rate(div_hw, rate, parent_rate);
|
||||
}
|
||||
|
||||
static int clk_periph_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct tegra_clk_periph *periph = to_clk_periph(hw);
|
||||
const struct clk_ops *gate_ops = periph->gate_ops;
|
||||
struct clk_hw *gate_hw = &periph->gate.hw;
|
||||
|
||||
gate_hw->clk = hw->clk;
|
||||
|
||||
return gate_ops->is_enabled(gate_hw);
|
||||
}
|
||||
|
||||
static int clk_periph_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct tegra_clk_periph *periph = to_clk_periph(hw);
|
||||
const struct clk_ops *gate_ops = periph->gate_ops;
|
||||
struct clk_hw *gate_hw = &periph->gate.hw;
|
||||
|
||||
gate_hw->clk = hw->clk;
|
||||
|
||||
return gate_ops->enable(gate_hw);
|
||||
}
|
||||
|
||||
static void clk_periph_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct tegra_clk_periph *periph = to_clk_periph(hw);
|
||||
const struct clk_ops *gate_ops = periph->gate_ops;
|
||||
struct clk_hw *gate_hw = &periph->gate.hw;
|
||||
|
||||
gate_ops->disable(gate_hw);
|
||||
}
|
||||
|
||||
void tegra_periph_reset_deassert(struct clk *c)
|
||||
{
|
||||
struct clk_hw *hw = __clk_get_hw(c);
|
||||
struct tegra_clk_periph *periph = to_clk_periph(hw);
|
||||
struct tegra_clk_periph_gate *gate;
|
||||
|
||||
if (periph->magic != TEGRA_CLK_PERIPH_MAGIC) {
|
||||
gate = to_clk_periph_gate(hw);
|
||||
if (gate->magic != TEGRA_CLK_PERIPH_GATE_MAGIC) {
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
gate = &periph->gate;
|
||||
}
|
||||
|
||||
tegra_periph_reset(gate, 0);
|
||||
}
|
||||
|
||||
void tegra_periph_reset_assert(struct clk *c)
|
||||
{
|
||||
struct clk_hw *hw = __clk_get_hw(c);
|
||||
struct tegra_clk_periph *periph = to_clk_periph(hw);
|
||||
struct tegra_clk_periph_gate *gate;
|
||||
|
||||
if (periph->magic != TEGRA_CLK_PERIPH_MAGIC) {
|
||||
gate = to_clk_periph_gate(hw);
|
||||
if (gate->magic != TEGRA_CLK_PERIPH_GATE_MAGIC) {
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
gate = &periph->gate;
|
||||
}
|
||||
|
||||
tegra_periph_reset(gate, 1);
|
||||
}
|
||||
|
||||
const struct clk_ops tegra_clk_periph_ops = {
|
||||
.get_parent = clk_periph_get_parent,
|
||||
.set_parent = clk_periph_set_parent,
|
||||
.recalc_rate = clk_periph_recalc_rate,
|
||||
.round_rate = clk_periph_round_rate,
|
||||
.set_rate = clk_periph_set_rate,
|
||||
.is_enabled = clk_periph_is_enabled,
|
||||
.enable = clk_periph_enable,
|
||||
.disable = clk_periph_disable,
|
||||
};
|
||||
|
||||
const struct clk_ops tegra_clk_periph_nodiv_ops = {
|
||||
.get_parent = clk_periph_get_parent,
|
||||
.set_parent = clk_periph_set_parent,
|
||||
.is_enabled = clk_periph_is_enabled,
|
||||
.enable = clk_periph_enable,
|
||||
.disable = clk_periph_disable,
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
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.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
|
||||
/* Data in .init is copied by clk_register(), so stack variable OK */
|
||||
periph->hw.init = &init;
|
||||
periph->magic = TEGRA_CLK_PERIPH_MAGIC;
|
||||
periph->mux.reg = clk_base + offset;
|
||||
periph->divider.reg = div ? (clk_base + offset) : NULL;
|
||||
periph->gate.clk_base = clk_base;
|
||||
|
||||
clk = clk_register(NULL, &periph->hw);
|
||||
if (IS_ERR(clk))
|
||||
return clk;
|
||||
|
||||
periph->mux.hw.clk = clk;
|
||||
periph->divider.hw.clk = div ? clk : NULL;
|
||||
periph->gate.hw.clk = clk;
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return _tegra_clk_register_periph(name, parent_names, num_parents,
|
||||
periph, clk_base, offset, true);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return _tegra_clk_register_periph(name, parent_names, num_parents,
|
||||
periph, clk_base, offset, false);
|
||||
}
|
123
drivers/clk/tegra/clk-pll-out.c
Normal file
123
drivers/clk/tegra/clk-pll-out.c
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
#define pll_out_enb(p) (BIT(p->enb_bit_idx))
|
||||
#define pll_out_rst(p) (BIT(p->rst_bit_idx))
|
||||
|
||||
static int clk_pll_out_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
|
||||
u32 val = readl_relaxed(pll_out->reg);
|
||||
int state;
|
||||
|
||||
state = (val & pll_out_enb(pll_out)) ? 1 : 0;
|
||||
if (!(val & (pll_out_rst(pll_out))))
|
||||
state = 0;
|
||||
return state;
|
||||
}
|
||||
|
||||
static int clk_pll_out_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
|
||||
unsigned long flags = 0;
|
||||
u32 val;
|
||||
|
||||
if (pll_out->lock)
|
||||
spin_lock_irqsave(pll_out->lock, flags);
|
||||
|
||||
val = readl_relaxed(pll_out->reg);
|
||||
|
||||
val |= (pll_out_enb(pll_out) | pll_out_rst(pll_out));
|
||||
|
||||
writel_relaxed(val, pll_out->reg);
|
||||
udelay(2);
|
||||
|
||||
if (pll_out->lock)
|
||||
spin_unlock_irqrestore(pll_out->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_pll_out_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
|
||||
unsigned long flags = 0;
|
||||
u32 val;
|
||||
|
||||
if (pll_out->lock)
|
||||
spin_lock_irqsave(pll_out->lock, flags);
|
||||
|
||||
val = readl_relaxed(pll_out->reg);
|
||||
|
||||
val &= ~(pll_out_enb(pll_out) | pll_out_rst(pll_out));
|
||||
|
||||
writel_relaxed(val, pll_out->reg);
|
||||
udelay(2);
|
||||
|
||||
if (pll_out->lock)
|
||||
spin_unlock_irqrestore(pll_out->lock, flags);
|
||||
}
|
||||
|
||||
const struct clk_ops tegra_clk_pll_out_ops = {
|
||||
.is_enabled = clk_pll_out_is_enabled,
|
||||
.enable = clk_pll_out_enable,
|
||||
.disable = clk_pll_out_disable,
|
||||
};
|
||||
|
||||
struct clk *tegra_clk_register_pll_out(const char *name,
|
||||
const char *parent_name, void __iomem *reg, u8 enb_bit_idx,
|
||||
u8 rst_bit_idx, unsigned long flags, u8 pll_out_flags,
|
||||
spinlock_t *lock)
|
||||
{
|
||||
struct tegra_clk_pll_out *pll_out;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
pll_out = kzalloc(sizeof(*pll_out), GFP_KERNEL);
|
||||
if (!pll_out)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = &tegra_clk_pll_out_ops;
|
||||
init.parent_names = (parent_name ? &parent_name : NULL);
|
||||
init.num_parents = (parent_name ? 1 : 0);
|
||||
init.flags = flags;
|
||||
|
||||
pll_out->reg = reg;
|
||||
pll_out->enb_bit_idx = enb_bit_idx;
|
||||
pll_out->rst_bit_idx = rst_bit_idx;
|
||||
pll_out->flags = pll_out_flags;
|
||||
pll_out->lock = lock;
|
||||
|
||||
/* Data in .init is copied by clk_register(), so stack variable OK */
|
||||
pll_out->hw.init = &init;
|
||||
|
||||
clk = clk_register(NULL, &pll_out->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(pll_out);
|
||||
|
||||
return clk;
|
||||
}
|
648
drivers/clk/tegra/clk-pll.c
Normal file
648
drivers/clk/tegra/clk-pll.c
Normal file
|
@ -0,0 +1,648 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
#define PLL_BASE_BYPASS BIT(31)
|
||||
#define PLL_BASE_ENABLE BIT(30)
|
||||
#define PLL_BASE_REF_ENABLE BIT(29)
|
||||
#define PLL_BASE_OVERRIDE BIT(28)
|
||||
|
||||
#define PLL_BASE_DIVP_SHIFT 20
|
||||
#define PLL_BASE_DIVP_WIDTH 3
|
||||
#define PLL_BASE_DIVN_SHIFT 8
|
||||
#define PLL_BASE_DIVN_WIDTH 10
|
||||
#define PLL_BASE_DIVM_SHIFT 0
|
||||
#define PLL_BASE_DIVM_WIDTH 5
|
||||
#define PLLU_POST_DIVP_MASK 0x1
|
||||
|
||||
#define PLL_MISC_DCCON_SHIFT 20
|
||||
#define PLL_MISC_CPCON_SHIFT 8
|
||||
#define PLL_MISC_CPCON_WIDTH 4
|
||||
#define PLL_MISC_CPCON_MASK ((1 << PLL_MISC_CPCON_WIDTH) - 1)
|
||||
#define PLL_MISC_LFCON_SHIFT 4
|
||||
#define PLL_MISC_LFCON_WIDTH 4
|
||||
#define PLL_MISC_LFCON_MASK ((1 << PLL_MISC_LFCON_WIDTH) - 1)
|
||||
#define PLL_MISC_VCOCON_SHIFT 0
|
||||
#define PLL_MISC_VCOCON_WIDTH 4
|
||||
#define PLL_MISC_VCOCON_MASK ((1 << PLL_MISC_VCOCON_WIDTH) - 1)
|
||||
|
||||
#define OUT_OF_TABLE_CPCON 8
|
||||
|
||||
#define PMC_PLLP_WB0_OVERRIDE 0xf8
|
||||
#define PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE BIT(12)
|
||||
#define PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE BIT(11)
|
||||
|
||||
#define PLL_POST_LOCK_DELAY 50
|
||||
|
||||
#define PLLDU_LFCON_SET_DIVN 600
|
||||
|
||||
#define PLLE_BASE_DIVCML_SHIFT 24
|
||||
#define PLLE_BASE_DIVCML_WIDTH 4
|
||||
#define PLLE_BASE_DIVP_SHIFT 16
|
||||
#define PLLE_BASE_DIVP_WIDTH 7
|
||||
#define PLLE_BASE_DIVN_SHIFT 8
|
||||
#define PLLE_BASE_DIVN_WIDTH 8
|
||||
#define PLLE_BASE_DIVM_SHIFT 0
|
||||
#define PLLE_BASE_DIVM_WIDTH 8
|
||||
|
||||
#define PLLE_MISC_SETUP_BASE_SHIFT 16
|
||||
#define PLLE_MISC_SETUP_BASE_MASK (0xffff << PLLE_MISC_SETUP_BASE_SHIFT)
|
||||
#define PLLE_MISC_LOCK_ENABLE BIT(9)
|
||||
#define PLLE_MISC_READY BIT(15)
|
||||
#define PLLE_MISC_SETUP_EX_SHIFT 2
|
||||
#define PLLE_MISC_SETUP_EX_MASK (3 << PLLE_MISC_SETUP_EX_SHIFT)
|
||||
#define PLLE_MISC_SETUP_MASK (PLLE_MISC_SETUP_BASE_MASK | \
|
||||
PLLE_MISC_SETUP_EX_MASK)
|
||||
#define PLLE_MISC_SETUP_VALUE (7 << PLLE_MISC_SETUP_BASE_SHIFT)
|
||||
|
||||
#define PLLE_SS_CTRL 0x68
|
||||
#define PLLE_SS_DISABLE (7 << 10)
|
||||
|
||||
#define PMC_SATA_PWRGT 0x1ac
|
||||
#define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE BIT(5)
|
||||
#define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL BIT(4)
|
||||
|
||||
#define pll_readl(offset, p) readl_relaxed(p->clk_base + offset)
|
||||
#define pll_readl_base(p) pll_readl(p->params->base_reg, p)
|
||||
#define pll_readl_misc(p) pll_readl(p->params->misc_reg, p)
|
||||
|
||||
#define pll_writel(val, offset, p) writel_relaxed(val, p->clk_base + offset)
|
||||
#define pll_writel_base(val, p) pll_writel(val, p->params->base_reg, p)
|
||||
#define pll_writel_misc(val, p) pll_writel(val, p->params->misc_reg, p)
|
||||
|
||||
#define mask(w) ((1 << (w)) - 1)
|
||||
#define divm_mask(p) mask(p->divm_width)
|
||||
#define divn_mask(p) mask(p->divn_width)
|
||||
#define divp_mask(p) (p->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK : \
|
||||
mask(p->divp_width))
|
||||
|
||||
#define divm_max(p) (divm_mask(p))
|
||||
#define divn_max(p) (divn_mask(p))
|
||||
#define divp_max(p) (1 << (divp_mask(p)))
|
||||
|
||||
static void clk_pll_enable_lock(struct tegra_clk_pll *pll)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (!(pll->flags & TEGRA_PLL_USE_LOCK))
|
||||
return;
|
||||
|
||||
val = pll_readl_misc(pll);
|
||||
val |= BIT(pll->params->lock_enable_bit_idx);
|
||||
pll_writel_misc(val, pll);
|
||||
}
|
||||
|
||||
static int clk_pll_wait_for_lock(struct tegra_clk_pll *pll,
|
||||
void __iomem *lock_addr, u32 lock_bit_idx)
|
||||
{
|
||||
int i;
|
||||
u32 val;
|
||||
|
||||
if (!(pll->flags & TEGRA_PLL_USE_LOCK)) {
|
||||
udelay(pll->params->lock_delay);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < pll->params->lock_delay; i++) {
|
||||
val = readl_relaxed(lock_addr);
|
||||
if (val & BIT(lock_bit_idx)) {
|
||||
udelay(PLL_POST_LOCK_DELAY);
|
||||
return 0;
|
||||
}
|
||||
udelay(2); /* timeout = 2 * lock time */
|
||||
}
|
||||
|
||||
pr_err("%s: Timed out waiting for pll %s lock\n", __func__,
|
||||
__clk_get_name(pll->hw.clk));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int clk_pll_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct tegra_clk_pll *pll = to_clk_pll(hw);
|
||||
u32 val;
|
||||
|
||||
if (pll->flags & TEGRA_PLLM) {
|
||||
val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE);
|
||||
if (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)
|
||||
return val & PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE ? 1 : 0;
|
||||
}
|
||||
|
||||
val = pll_readl_base(pll);
|
||||
|
||||
return val & PLL_BASE_ENABLE ? 1 : 0;
|
||||
}
|
||||
|
||||
static int _clk_pll_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct tegra_clk_pll *pll = to_clk_pll(hw);
|
||||
u32 val;
|
||||
|
||||
clk_pll_enable_lock(pll);
|
||||
|
||||
val = pll_readl_base(pll);
|
||||
val &= ~PLL_BASE_BYPASS;
|
||||
val |= PLL_BASE_ENABLE;
|
||||
pll_writel_base(val, pll);
|
||||
|
||||
if (pll->flags & TEGRA_PLLM) {
|
||||
val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE);
|
||||
val |= PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
|
||||
writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE);
|
||||
}
|
||||
|
||||
clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->base_reg,
|
||||
pll->params->lock_bit_idx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _clk_pll_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct tegra_clk_pll *pll = to_clk_pll(hw);
|
||||
u32 val;
|
||||
|
||||
val = pll_readl_base(pll);
|
||||
val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
|
||||
pll_writel_base(val, pll);
|
||||
|
||||
if (pll->flags & TEGRA_PLLM) {
|
||||
val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE);
|
||||
val &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
|
||||
writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE);
|
||||
}
|
||||
}
|
||||
|
||||
static int clk_pll_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct tegra_clk_pll *pll = to_clk_pll(hw);
|
||||
unsigned long flags = 0;
|
||||
int ret;
|
||||
|
||||
if (pll->lock)
|
||||
spin_lock_irqsave(pll->lock, flags);
|
||||
|
||||
ret = _clk_pll_enable(hw);
|
||||
|
||||
if (pll->lock)
|
||||
spin_unlock_irqrestore(pll->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void clk_pll_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct tegra_clk_pll *pll = to_clk_pll(hw);
|
||||
unsigned long flags = 0;
|
||||
|
||||
if (pll->lock)
|
||||
spin_lock_irqsave(pll->lock, flags);
|
||||
|
||||
_clk_pll_disable(hw);
|
||||
|
||||
if (pll->lock)
|
||||
spin_unlock_irqrestore(pll->lock, flags);
|
||||
}
|
||||
|
||||
static int _get_table_rate(struct clk_hw *hw,
|
||||
struct tegra_clk_pll_freq_table *cfg,
|
||||
unsigned long rate, unsigned long parent_rate)
|
||||
{
|
||||
struct tegra_clk_pll *pll = to_clk_pll(hw);
|
||||
struct tegra_clk_pll_freq_table *sel;
|
||||
|
||||
for (sel = pll->freq_table; sel->input_rate != 0; sel++)
|
||||
if (sel->input_rate == parent_rate &&
|
||||
sel->output_rate == rate)
|
||||
break;
|
||||
|
||||
if (sel->input_rate == 0)
|
||||
return -EINVAL;
|
||||
|
||||
BUG_ON(sel->p < 1);
|
||||
|
||||
cfg->input_rate = sel->input_rate;
|
||||
cfg->output_rate = sel->output_rate;
|
||||
cfg->m = sel->m;
|
||||
cfg->n = sel->n;
|
||||
cfg->p = sel->p;
|
||||
cfg->cpcon = sel->cpcon;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
|
||||
unsigned long rate, unsigned long parent_rate)
|
||||
{
|
||||
struct tegra_clk_pll *pll = to_clk_pll(hw);
|
||||
unsigned long cfreq;
|
||||
u32 p_div = 0;
|
||||
|
||||
switch (parent_rate) {
|
||||
case 12000000:
|
||||
case 26000000:
|
||||
cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000;
|
||||
break;
|
||||
case 13000000:
|
||||
cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000;
|
||||
break;
|
||||
case 16800000:
|
||||
case 19200000:
|
||||
cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000;
|
||||
break;
|
||||
case 9600000:
|
||||
case 28800000:
|
||||
/*
|
||||
* PLL_P_OUT1 rate is not listed in PLLA table
|
||||
*/
|
||||
cfreq = parent_rate/(parent_rate/1000000);
|
||||
break;
|
||||
default:
|
||||
pr_err("%s Unexpected reference rate %lu\n",
|
||||
__func__, parent_rate);
|
||||
BUG();
|
||||
}
|
||||
|
||||
/* Raise VCO to guarantee 0.5% accuracy */
|
||||
for (cfg->output_rate = rate; cfg->output_rate < 200 * cfreq;
|
||||
cfg->output_rate <<= 1)
|
||||
p_div++;
|
||||
|
||||
cfg->p = 1 << p_div;
|
||||
cfg->m = parent_rate / cfreq;
|
||||
cfg->n = cfg->output_rate / cfreq;
|
||||
cfg->cpcon = OUT_OF_TABLE_CPCON;
|
||||
|
||||
if (cfg->m > divm_max(pll) || cfg->n > divn_max(pll) ||
|
||||
cfg->p > divp_max(pll) || cfg->output_rate > pll->params->vco_max) {
|
||||
pr_err("%s: Failed to set %s rate %lu\n",
|
||||
__func__, __clk_get_name(hw->clk), rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
|
||||
unsigned long rate)
|
||||
{
|
||||
struct tegra_clk_pll *pll = to_clk_pll(hw);
|
||||
unsigned long flags = 0;
|
||||
u32 divp, val, old_base;
|
||||
int state;
|
||||
|
||||
divp = __ffs(cfg->p);
|
||||
|
||||
if (pll->flags & TEGRA_PLLU)
|
||||
divp ^= 1;
|
||||
|
||||
if (pll->lock)
|
||||
spin_lock_irqsave(pll->lock, flags);
|
||||
|
||||
old_base = val = pll_readl_base(pll);
|
||||
val &= ~((divm_mask(pll) << pll->divm_shift) |
|
||||
(divn_mask(pll) << pll->divn_shift) |
|
||||
(divp_mask(pll) << pll->divp_shift));
|
||||
val |= ((cfg->m << pll->divm_shift) |
|
||||
(cfg->n << pll->divn_shift) |
|
||||
(divp << pll->divp_shift));
|
||||
if (val == old_base) {
|
||||
if (pll->lock)
|
||||
spin_unlock_irqrestore(pll->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
state = clk_pll_is_enabled(hw);
|
||||
|
||||
if (state) {
|
||||
_clk_pll_disable(hw);
|
||||
val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
|
||||
}
|
||||
pll_writel_base(val, pll);
|
||||
|
||||
if (pll->flags & TEGRA_PLL_HAS_CPCON) {
|
||||
val = pll_readl_misc(pll);
|
||||
val &= ~(PLL_MISC_CPCON_MASK << PLL_MISC_CPCON_SHIFT);
|
||||
val |= cfg->cpcon << PLL_MISC_CPCON_SHIFT;
|
||||
if (pll->flags & TEGRA_PLL_SET_LFCON) {
|
||||
val &= ~(PLL_MISC_LFCON_MASK << PLL_MISC_LFCON_SHIFT);
|
||||
if (cfg->n >= PLLDU_LFCON_SET_DIVN)
|
||||
val |= 0x1 << PLL_MISC_LFCON_SHIFT;
|
||||
} else if (pll->flags & TEGRA_PLL_SET_DCCON) {
|
||||
val &= ~(0x1 << PLL_MISC_DCCON_SHIFT);
|
||||
if (rate >= (pll->params->vco_max >> 1))
|
||||
val |= 0x1 << PLL_MISC_DCCON_SHIFT;
|
||||
}
|
||||
pll_writel_misc(val, pll);
|
||||
}
|
||||
|
||||
if (pll->lock)
|
||||
spin_unlock_irqrestore(pll->lock, flags);
|
||||
|
||||
if (state)
|
||||
clk_pll_enable(hw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct tegra_clk_pll *pll = to_clk_pll(hw);
|
||||
struct tegra_clk_pll_freq_table cfg;
|
||||
|
||||
if (pll->flags & TEGRA_PLL_FIXED) {
|
||||
if (rate != pll->fixed_rate) {
|
||||
pr_err("%s: Can not change %s fixed rate %lu to %lu\n",
|
||||
__func__, __clk_get_name(hw->clk),
|
||||
pll->fixed_rate, rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_get_table_rate(hw, &cfg, rate, parent_rate) &&
|
||||
_calc_rate(hw, &cfg, rate, parent_rate))
|
||||
return -EINVAL;
|
||||
|
||||
return _program_pll(hw, &cfg, rate);
|
||||
}
|
||||
|
||||
static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
struct tegra_clk_pll *pll = to_clk_pll(hw);
|
||||
struct tegra_clk_pll_freq_table cfg;
|
||||
u64 output_rate = *prate;
|
||||
|
||||
if (pll->flags & TEGRA_PLL_FIXED)
|
||||
return pll->fixed_rate;
|
||||
|
||||
/* PLLM is used for memory; we do not change rate */
|
||||
if (pll->flags & TEGRA_PLLM)
|
||||
return __clk_get_rate(hw->clk);
|
||||
|
||||
if (_get_table_rate(hw, &cfg, rate, *prate) &&
|
||||
_calc_rate(hw, &cfg, rate, *prate))
|
||||
return -EINVAL;
|
||||
|
||||
output_rate *= cfg.n;
|
||||
do_div(output_rate, cfg.m * cfg.p);
|
||||
|
||||
return output_rate;
|
||||
}
|
||||
|
||||
static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct tegra_clk_pll *pll = to_clk_pll(hw);
|
||||
u32 val = pll_readl_base(pll);
|
||||
u32 divn = 0, divm = 0, divp = 0;
|
||||
u64 rate = parent_rate;
|
||||
|
||||
if (val & PLL_BASE_BYPASS)
|
||||
return parent_rate;
|
||||
|
||||
if ((pll->flags & TEGRA_PLL_FIXED) && !(val & PLL_BASE_OVERRIDE)) {
|
||||
struct tegra_clk_pll_freq_table sel;
|
||||
if (_get_table_rate(hw, &sel, pll->fixed_rate, parent_rate)) {
|
||||
pr_err("Clock %s has unknown fixed frequency\n",
|
||||
__clk_get_name(hw->clk));
|
||||
BUG();
|
||||
}
|
||||
return pll->fixed_rate;
|
||||
}
|
||||
|
||||
divp = (val >> pll->divp_shift) & (divp_mask(pll));
|
||||
if (pll->flags & TEGRA_PLLU)
|
||||
divp ^= 1;
|
||||
|
||||
divn = (val >> pll->divn_shift) & (divn_mask(pll));
|
||||
divm = (val >> pll->divm_shift) & (divm_mask(pll));
|
||||
divm *= (1 << divp);
|
||||
|
||||
rate *= divn;
|
||||
do_div(rate, divm);
|
||||
return rate;
|
||||
}
|
||||
|
||||
static int clk_plle_training(struct tegra_clk_pll *pll)
|
||||
{
|
||||
u32 val;
|
||||
unsigned long timeout;
|
||||
|
||||
if (!pll->pmc)
|
||||
return -ENOSYS;
|
||||
|
||||
/*
|
||||
* PLLE is already disabled, and setup cleared;
|
||||
* create falling edge on PLLE IDDQ input.
|
||||
*/
|
||||
val = readl(pll->pmc + PMC_SATA_PWRGT);
|
||||
val |= PMC_SATA_PWRGT_PLLE_IDDQ_VALUE;
|
||||
writel(val, pll->pmc + PMC_SATA_PWRGT);
|
||||
|
||||
val = readl(pll->pmc + PMC_SATA_PWRGT);
|
||||
val |= PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL;
|
||||
writel(val, pll->pmc + PMC_SATA_PWRGT);
|
||||
|
||||
val = readl(pll->pmc + PMC_SATA_PWRGT);
|
||||
val &= ~PMC_SATA_PWRGT_PLLE_IDDQ_VALUE;
|
||||
writel(val, pll->pmc + PMC_SATA_PWRGT);
|
||||
|
||||
val = pll_readl_misc(pll);
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(100);
|
||||
while (1) {
|
||||
val = pll_readl_misc(pll);
|
||||
if (val & PLLE_MISC_READY)
|
||||
break;
|
||||
if (time_after(jiffies, timeout)) {
|
||||
pr_err("%s: timeout waiting for PLLE\n", __func__);
|
||||
return -EBUSY;
|
||||
}
|
||||
udelay(300);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_plle_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct tegra_clk_pll *pll = to_clk_pll(hw);
|
||||
unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk));
|
||||
struct tegra_clk_pll_freq_table sel;
|
||||
u32 val;
|
||||
int err;
|
||||
|
||||
if (_get_table_rate(hw, &sel, pll->fixed_rate, input_rate))
|
||||
return -EINVAL;
|
||||
|
||||
clk_pll_disable(hw);
|
||||
|
||||
val = pll_readl_misc(pll);
|
||||
val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK);
|
||||
pll_writel_misc(val, pll);
|
||||
|
||||
val = pll_readl_misc(pll);
|
||||
if (!(val & PLLE_MISC_READY)) {
|
||||
err = clk_plle_training(pll);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (pll->flags & TEGRA_PLLE_CONFIGURE) {
|
||||
/* configure dividers */
|
||||
val = pll_readl_base(pll);
|
||||
val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll));
|
||||
val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT);
|
||||
val |= sel.m << pll->divm_shift;
|
||||
val |= sel.n << pll->divn_shift;
|
||||
val |= sel.p << pll->divp_shift;
|
||||
val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT;
|
||||
pll_writel_base(val, pll);
|
||||
}
|
||||
|
||||
val = pll_readl_misc(pll);
|
||||
val |= PLLE_MISC_SETUP_VALUE;
|
||||
val |= PLLE_MISC_LOCK_ENABLE;
|
||||
pll_writel_misc(val, pll);
|
||||
|
||||
val = readl(pll->clk_base + PLLE_SS_CTRL);
|
||||
val |= PLLE_SS_DISABLE;
|
||||
writel(val, pll->clk_base + PLLE_SS_CTRL);
|
||||
|
||||
val |= pll_readl_base(pll);
|
||||
val |= (PLL_BASE_BYPASS | PLL_BASE_ENABLE);
|
||||
pll_writel_base(val, pll);
|
||||
|
||||
clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->misc_reg,
|
||||
pll->params->lock_bit_idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long clk_plle_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct tegra_clk_pll *pll = to_clk_pll(hw);
|
||||
u32 val = pll_readl_base(pll);
|
||||
u32 divn = 0, divm = 0, divp = 0;
|
||||
u64 rate = parent_rate;
|
||||
|
||||
divp = (val >> pll->divp_shift) & (divp_mask(pll));
|
||||
divn = (val >> pll->divn_shift) & (divn_mask(pll));
|
||||
divm = (val >> pll->divm_shift) & (divm_mask(pll));
|
||||
divm *= divp;
|
||||
|
||||
rate *= divn;
|
||||
do_div(rate, divm);
|
||||
return rate;
|
||||
}
|
||||
|
||||
const struct clk_ops tegra_clk_pll_ops = {
|
||||
.is_enabled = clk_pll_is_enabled,
|
||||
.enable = clk_pll_enable,
|
||||
.disable = clk_pll_disable,
|
||||
.recalc_rate = clk_pll_recalc_rate,
|
||||
.round_rate = clk_pll_round_rate,
|
||||
.set_rate = clk_pll_set_rate,
|
||||
};
|
||||
|
||||
const struct clk_ops tegra_clk_plle_ops = {
|
||||
.recalc_rate = clk_plle_recalc_rate,
|
||||
.is_enabled = clk_pll_is_enabled,
|
||||
.disable = clk_pll_disable,
|
||||
.enable = clk_plle_enable,
|
||||
};
|
||||
|
||||
static 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_freq_table *freq_table, spinlock_t *lock,
|
||||
const struct clk_ops *ops)
|
||||
{
|
||||
struct tegra_clk_pll *pll;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
|
||||
if (!pll)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = ops;
|
||||
init.flags = flags;
|
||||
init.parent_names = (parent_name ? &parent_name : NULL);
|
||||
init.num_parents = (parent_name ? 1 : 0);
|
||||
|
||||
pll->clk_base = clk_base;
|
||||
pll->pmc = pmc;
|
||||
|
||||
pll->freq_table = freq_table;
|
||||
pll->params = pll_params;
|
||||
pll->fixed_rate = fixed_rate;
|
||||
pll->flags = pll_flags;
|
||||
pll->lock = lock;
|
||||
|
||||
pll->divp_shift = PLL_BASE_DIVP_SHIFT;
|
||||
pll->divp_width = PLL_BASE_DIVP_WIDTH;
|
||||
pll->divn_shift = PLL_BASE_DIVN_SHIFT;
|
||||
pll->divn_width = PLL_BASE_DIVN_WIDTH;
|
||||
pll->divm_shift = PLL_BASE_DIVM_SHIFT;
|
||||
pll->divm_width = PLL_BASE_DIVM_WIDTH;
|
||||
|
||||
/* Data in .init is copied by clk_register(), so stack variable OK */
|
||||
pll->hw.init = &init;
|
||||
|
||||
clk = clk_register(NULL, &pll->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(pll);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
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_freq_table *freq_table, spinlock_t *lock)
|
||||
{
|
||||
return _tegra_clk_register_pll(name, parent_name, clk_base, pmc,
|
||||
flags, fixed_rate, pll_params, pll_flags, freq_table,
|
||||
lock, &tegra_clk_pll_ops);
|
||||
}
|
||||
|
||||
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_freq_table *freq_table, spinlock_t *lock)
|
||||
{
|
||||
return _tegra_clk_register_pll(name, parent_name, clk_base, pmc,
|
||||
flags, fixed_rate, pll_params, pll_flags, freq_table,
|
||||
lock, &tegra_clk_plle_ops);
|
||||
}
|
154
drivers/clk/tegra/clk-super.c
Normal file
154
drivers/clk/tegra/clk-super.c
Normal file
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
#define SUPER_STATE_IDLE 0
|
||||
#define SUPER_STATE_RUN 1
|
||||
#define SUPER_STATE_IRQ 2
|
||||
#define SUPER_STATE_FIQ 3
|
||||
|
||||
#define SUPER_STATE_SHIFT 28
|
||||
#define SUPER_STATE_MASK ((BIT(SUPER_STATE_IDLE) | BIT(SUPER_STATE_RUN) | \
|
||||
BIT(SUPER_STATE_IRQ) | BIT(SUPER_STATE_FIQ)) \
|
||||
<< SUPER_STATE_SHIFT)
|
||||
|
||||
#define SUPER_LP_DIV2_BYPASS (1 << 16)
|
||||
|
||||
#define super_state(s) (BIT(s) << SUPER_STATE_SHIFT)
|
||||
#define super_state_to_src_shift(m, s) ((m->width * s))
|
||||
#define super_state_to_src_mask(m) (((1 << m->width) - 1))
|
||||
|
||||
static u8 clk_super_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
|
||||
u32 val, state;
|
||||
u8 source, shift;
|
||||
|
||||
val = readl_relaxed(mux->reg);
|
||||
|
||||
state = val & SUPER_STATE_MASK;
|
||||
|
||||
BUG_ON((state != super_state(SUPER_STATE_RUN)) &&
|
||||
(state != super_state(SUPER_STATE_IDLE)));
|
||||
shift = (state == super_state(SUPER_STATE_IDLE)) ?
|
||||
super_state_to_src_shift(mux, SUPER_STATE_IDLE) :
|
||||
super_state_to_src_shift(mux, SUPER_STATE_RUN);
|
||||
|
||||
source = (val >> shift) & super_state_to_src_mask(mux);
|
||||
|
||||
/*
|
||||
* If LP_DIV2_BYPASS is not set and PLLX is current parent then
|
||||
* PLLX/2 is the input source to CCLKLP.
|
||||
*/
|
||||
if ((mux->flags & TEGRA_DIVIDER_2) && !(val & SUPER_LP_DIV2_BYPASS) &&
|
||||
(source == mux->pllx_index))
|
||||
source = mux->div2_index;
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
static int clk_super_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
|
||||
u32 val, state;
|
||||
u8 parent_index, shift;
|
||||
|
||||
val = readl_relaxed(mux->reg);
|
||||
state = val & SUPER_STATE_MASK;
|
||||
BUG_ON((state != super_state(SUPER_STATE_RUN)) &&
|
||||
(state != super_state(SUPER_STATE_IDLE)));
|
||||
shift = (state == super_state(SUPER_STATE_IDLE)) ?
|
||||
super_state_to_src_shift(mux, SUPER_STATE_IDLE) :
|
||||
super_state_to_src_shift(mux, SUPER_STATE_RUN);
|
||||
|
||||
/*
|
||||
* For LP mode super-clock switch between PLLX direct
|
||||
* and divided-by-2 outputs is allowed only when other
|
||||
* than PLLX clock source is current parent.
|
||||
*/
|
||||
if ((mux->flags & TEGRA_DIVIDER_2) && ((index == mux->div2_index) ||
|
||||
(index == mux->pllx_index))) {
|
||||
parent_index = clk_super_get_parent(hw);
|
||||
if ((parent_index == mux->div2_index) ||
|
||||
(parent_index == mux->pllx_index))
|
||||
return -EINVAL;
|
||||
|
||||
val ^= SUPER_LP_DIV2_BYPASS;
|
||||
writel_relaxed(val, mux->reg);
|
||||
udelay(2);
|
||||
|
||||
if (index == mux->div2_index)
|
||||
index = mux->pllx_index;
|
||||
}
|
||||
val &= ~((super_state_to_src_mask(mux)) << shift);
|
||||
val |= (index & (super_state_to_src_mask(mux))) << shift;
|
||||
|
||||
writel_relaxed(val, mux->reg);
|
||||
udelay(2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct clk_ops tegra_clk_super_ops = {
|
||||
.get_parent = clk_super_get_parent,
|
||||
.set_parent = clk_super_set_parent,
|
||||
};
|
||||
|
||||
struct clk *tegra_clk_register_super_mux(const char *name,
|
||||
const char **parent_names, u8 num_parents,
|
||||
unsigned long flags, void __iomem *reg, u8 clk_super_flags,
|
||||
u8 width, u8 pllx_index, u8 div2_index, spinlock_t *lock)
|
||||
{
|
||||
struct tegra_clk_super_mux *super;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
super = kzalloc(sizeof(*super), GFP_KERNEL);
|
||||
if (!super) {
|
||||
pr_err("%s: could not allocate super clk\n", __func__);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
init.name = name;
|
||||
init.ops = &tegra_clk_super_ops;
|
||||
init.flags = flags;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
|
||||
super->reg = reg;
|
||||
super->pllx_index = pllx_index;
|
||||
super->div2_index = div2_index;
|
||||
super->lock = lock;
|
||||
super->width = width;
|
||||
super->flags = clk_super_flags;
|
||||
|
||||
/* Data in .init is copied by clk_register(), so stack variable OK */
|
||||
super->hw.init = &init;
|
||||
|
||||
clk = clk_register(NULL, &super->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(super);
|
||||
|
||||
return clk;
|
||||
}
|
1256
drivers/clk/tegra/clk-tegra20.c
Normal file
1256
drivers/clk/tegra/clk-tegra20.c
Normal file
File diff suppressed because it is too large
Load diff
1987
drivers/clk/tegra/clk-tegra30.c
Normal file
1987
drivers/clk/tegra/clk-tegra30.c
Normal file
File diff suppressed because it is too large
Load diff
85
drivers/clk/tegra/clk.c
Normal file
85
drivers/clk/tegra/clk.c
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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/of.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
/* Global data of Tegra CPU CAR ops */
|
||||
struct tegra_cpu_car_ops *tegra_cpu_car_ops;
|
||||
|
||||
void __init tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list,
|
||||
struct clk *clks[], int clk_max)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
for (; dup_list->clk_id < clk_max; dup_list++) {
|
||||
clk = clks[dup_list->clk_id];
|
||||
dup_list->lookup.clk = clk;
|
||||
clkdev_add(&dup_list->lookup);
|
||||
}
|
||||
}
|
||||
|
||||
void __init tegra_init_from_table(struct tegra_clk_init_table *tbl,
|
||||
struct clk *clks[], int clk_max)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
for (; tbl->clk_id < clk_max; tbl++) {
|
||||
clk = clks[tbl->clk_id];
|
||||
if (IS_ERR_OR_NULL(clk))
|
||||
return;
|
||||
|
||||
if (tbl->parent_id < clk_max) {
|
||||
struct clk *parent = clks[tbl->parent_id];
|
||||
if (clk_set_parent(clk, parent)) {
|
||||
pr_err("%s: Failed to set parent %s of %s\n",
|
||||
__func__, __clk_get_name(parent),
|
||||
__clk_get_name(clk));
|
||||
WARN_ON(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (tbl->rate)
|
||||
if (clk_set_rate(clk, tbl->rate)) {
|
||||
pr_err("%s: Failed to set rate %lu of %s\n",
|
||||
__func__, tbl->rate,
|
||||
__clk_get_name(clk));
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
if (tbl->state)
|
||||
if (clk_prepare_enable(clk)) {
|
||||
pr_err("%s: Failed to enable %s\n", __func__,
|
||||
__clk_get_name(clk));
|
||||
WARN_ON(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 },
|
||||
{ }
|
||||
};
|
||||
|
||||
void __init tegra_clocks_init(void)
|
||||
{
|
||||
of_clk_init(tegra_dt_clk_match);
|
||||
}
|
502
drivers/clk/tegra/clk.h
Normal file
502
drivers/clk/tegra/clk.h
Normal file
|
@ -0,0 +1,502 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __TEGRA_CLK_H
|
||||
#define __TEGRA_CLK_H
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
|
||||
/**
|
||||
* struct tegra_clk_sync_source - external clock source from codec
|
||||
*
|
||||
* @hw: handle between common and hardware-specific interfaces
|
||||
* @rate: input frequency from source
|
||||
* @max_rate: max rate allowed
|
||||
*/
|
||||
struct tegra_clk_sync_source {
|
||||
struct clk_hw hw;
|
||||
unsigned long rate;
|
||||
unsigned long max_rate;
|
||||
};
|
||||
|
||||
#define to_clk_sync_source(_hw) \
|
||||
container_of(_hw, struct tegra_clk_sync_source, hw)
|
||||
|
||||
extern const struct clk_ops tegra_clk_sync_source_ops;
|
||||
struct clk *tegra_clk_register_sync_source(const char *name,
|
||||
unsigned long fixed_rate, unsigned long max_rate);
|
||||
|
||||
/**
|
||||
* struct tegra_clk_frac_div - fractional divider clock
|
||||
*
|
||||
* @hw: handle between common and hardware-specific interfaces
|
||||
* @reg: register containing divider
|
||||
* @flags: hardware-specific flags
|
||||
* @shift: shift to the divider bit field
|
||||
* @width: width of the divider bit field
|
||||
* @frac_width: width of the fractional bit field
|
||||
* @lock: register lock
|
||||
*
|
||||
* Flags:
|
||||
* TEGRA_DIVIDER_ROUND_UP - This flags indicates to round up the divider value.
|
||||
* TEGRA_DIVIDER_FIXED - Fixed rate PLL dividers has addition override bit, this
|
||||
* flag indicates that this divider is for fixed rate PLL.
|
||||
* TEGRA_DIVIDER_INT - Some modules can not cope with the duty cycle when
|
||||
* fraction bit is set. This flags indicates to calculate divider for which
|
||||
* fracton bit will be zero.
|
||||
* TEGRA_DIVIDER_UART - UART module divider has additional enable bit which is
|
||||
* set when divider value is not 0. This flags indicates that the divider
|
||||
* is for UART module.
|
||||
*/
|
||||
struct tegra_clk_frac_div {
|
||||
struct clk_hw hw;
|
||||
void __iomem *reg;
|
||||
u8 flags;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
u8 frac_width;
|
||||
spinlock_t *lock;
|
||||
};
|
||||
|
||||
#define to_clk_frac_div(_hw) container_of(_hw, struct tegra_clk_frac_div, hw)
|
||||
|
||||
#define TEGRA_DIVIDER_ROUND_UP BIT(0)
|
||||
#define TEGRA_DIVIDER_FIXED BIT(1)
|
||||
#define TEGRA_DIVIDER_INT BIT(2)
|
||||
#define TEGRA_DIVIDER_UART BIT(3)
|
||||
|
||||
extern const struct clk_ops tegra_clk_frac_div_ops;
|
||||
struct clk *tegra_clk_register_divider(const char *name,
|
||||
const char *parent_name, void __iomem *reg,
|
||||
unsigned long flags, u8 clk_divider_flags, u8 shift, u8 width,
|
||||
u8 frac_width, spinlock_t *lock);
|
||||
|
||||
/*
|
||||
* Tegra PLL:
|
||||
*
|
||||
* In general, there are 3 requirements for each PLL
|
||||
* that SW needs to be comply with.
|
||||
* (1) Input frequency range (REF).
|
||||
* (2) Comparison frequency range (CF). CF = REF/DIVM.
|
||||
* (3) VCO frequency range (VCO). VCO = CF * DIVN.
|
||||
*
|
||||
* The final PLL output frequency (FO) = VCO >> DIVP.
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct tegra_clk_pll_freq_table - PLL frequecy table
|
||||
*
|
||||
* @input_rate: input rate from source
|
||||
* @output_rate: output rate from PLL for the input rate
|
||||
* @n: feedback divider
|
||||
* @m: input divider
|
||||
* @p: post divider
|
||||
* @cpcon: charge pump current
|
||||
*/
|
||||
struct tegra_clk_pll_freq_table {
|
||||
unsigned long input_rate;
|
||||
unsigned long output_rate;
|
||||
u16 n;
|
||||
u16 m;
|
||||
u8 p;
|
||||
u8 cpcon;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct clk_pll_params - PLL parameters
|
||||
*
|
||||
* @input_min: Minimum input frequency
|
||||
* @input_max: Maximum input frequency
|
||||
* @cf_min: Minimum comparison frequency
|
||||
* @cf_max: Maximum comparison frequency
|
||||
* @vco_min: Minimum VCO frequency
|
||||
* @vco_max: Maximum VCO frequency
|
||||
* @base_reg: PLL base reg offset
|
||||
* @misc_reg: PLL misc reg offset
|
||||
* @lock_reg: PLL lock reg offset
|
||||
* @lock_bit_idx: Bit index for PLL lock status
|
||||
* @lock_enable_bit_idx: Bit index to enable PLL lock
|
||||
* @lock_delay: Delay in us if PLL lock is not used
|
||||
*/
|
||||
struct tegra_clk_pll_params {
|
||||
unsigned long input_min;
|
||||
unsigned long input_max;
|
||||
unsigned long cf_min;
|
||||
unsigned long cf_max;
|
||||
unsigned long vco_min;
|
||||
unsigned long vco_max;
|
||||
|
||||
u32 base_reg;
|
||||
u32 misc_reg;
|
||||
u32 lock_reg;
|
||||
u32 lock_bit_idx;
|
||||
u32 lock_enable_bit_idx;
|
||||
int lock_delay;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tegra_clk_pll - Tegra PLL clock
|
||||
*
|
||||
* @hw: handle between common and hardware-specifix interfaces
|
||||
* @clk_base: address of CAR controller
|
||||
* @pmc: address of PMC, required to read override bits
|
||||
* @freq_table: array of frequencies supported by PLL
|
||||
* @params: PLL parameters
|
||||
* @flags: PLL flags
|
||||
* @fixed_rate: PLL rate if it is fixed
|
||||
* @lock: register lock
|
||||
* @divn_shift: shift to the feedback divider bit field
|
||||
* @divn_width: width of the feedback divider bit field
|
||||
* @divm_shift: shift to the input divider bit field
|
||||
* @divm_width: width of the input divider bit field
|
||||
* @divp_shift: shift to the post divider bit field
|
||||
* @divp_width: width of the post divider bit field
|
||||
*
|
||||
* Flags:
|
||||
* TEGRA_PLL_USE_LOCK - This flag indicated to use lock bits for
|
||||
* PLL locking. If not set it will use lock_delay value to wait.
|
||||
* TEGRA_PLL_HAS_CPCON - This flag indicates that CPCON value needs
|
||||
* to be programmed to change output frequency of the PLL.
|
||||
* TEGRA_PLL_SET_LFCON - This flag indicates that LFCON value needs
|
||||
* to be programmed to change output frequency of the PLL.
|
||||
* TEGRA_PLL_SET_DCCON - This flag indicates that DCCON value needs
|
||||
* to be programmed to change output frequency of the PLL.
|
||||
* TEGRA_PLLU - PLLU has inverted post divider. This flags indicated
|
||||
* that it is PLLU and invert post divider value.
|
||||
* TEGRA_PLLM - PLLM has additional override settings in PMC. This
|
||||
* flag indicates that it is PLLM and use override settings.
|
||||
* TEGRA_PLL_FIXED - We are not supposed to change output frequency
|
||||
* of some plls.
|
||||
* TEGRA_PLLE_CONFIGURE - Configure PLLE when enabling.
|
||||
*/
|
||||
struct tegra_clk_pll {
|
||||
struct clk_hw hw;
|
||||
void __iomem *clk_base;
|
||||
void __iomem *pmc;
|
||||
u8 flags;
|
||||
unsigned long fixed_rate;
|
||||
spinlock_t *lock;
|
||||
u8 divn_shift;
|
||||
u8 divn_width;
|
||||
u8 divm_shift;
|
||||
u8 divm_width;
|
||||
u8 divp_shift;
|
||||
u8 divp_width;
|
||||
struct tegra_clk_pll_freq_table *freq_table;
|
||||
struct tegra_clk_pll_params *params;
|
||||
};
|
||||
|
||||
#define to_clk_pll(_hw) container_of(_hw, struct tegra_clk_pll, hw)
|
||||
|
||||
#define TEGRA_PLL_USE_LOCK BIT(0)
|
||||
#define TEGRA_PLL_HAS_CPCON BIT(1)
|
||||
#define TEGRA_PLL_SET_LFCON BIT(2)
|
||||
#define TEGRA_PLL_SET_DCCON BIT(3)
|
||||
#define TEGRA_PLLU BIT(4)
|
||||
#define TEGRA_PLLM BIT(5)
|
||||
#define TEGRA_PLL_FIXED BIT(6)
|
||||
#define TEGRA_PLLE_CONFIGURE BIT(7)
|
||||
|
||||
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_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_freq_table *freq_table, spinlock_t *lock);
|
||||
|
||||
/**
|
||||
* struct tegra_clk_pll_out - PLL divider down clock
|
||||
*
|
||||
* @hw: handle between common and hardware-specific interfaces
|
||||
* @reg: register containing the PLL divider
|
||||
* @enb_bit_idx: bit to enable/disable PLL divider
|
||||
* @rst_bit_idx: bit to reset PLL divider
|
||||
* @lock: register lock
|
||||
* @flags: hardware-specific flags
|
||||
*/
|
||||
struct tegra_clk_pll_out {
|
||||
struct clk_hw hw;
|
||||
void __iomem *reg;
|
||||
u8 enb_bit_idx;
|
||||
u8 rst_bit_idx;
|
||||
spinlock_t *lock;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
#define to_clk_pll_out(_hw) container_of(_hw, struct tegra_clk_pll_out, hw)
|
||||
|
||||
extern const struct clk_ops tegra_clk_pll_out_ops;
|
||||
struct clk *tegra_clk_register_pll_out(const char *name,
|
||||
const char *parent_name, void __iomem *reg, u8 enb_bit_idx,
|
||||
u8 rst_bit_idx, unsigned long flags, u8 pll_div_flags,
|
||||
spinlock_t *lock);
|
||||
|
||||
/**
|
||||
* struct tegra_clk_periph_regs - Registers controlling peripheral clock
|
||||
*
|
||||
* @enb_reg: read the enable status
|
||||
* @enb_set_reg: write 1 to enable clock
|
||||
* @enb_clr_reg: write 1 to disable clock
|
||||
* @rst_reg: read the reset status
|
||||
* @rst_set_reg: write 1 to assert the reset of peripheral
|
||||
* @rst_clr_reg: write 1 to deassert the reset of peripheral
|
||||
*/
|
||||
struct tegra_clk_periph_regs {
|
||||
u32 enb_reg;
|
||||
u32 enb_set_reg;
|
||||
u32 enb_clr_reg;
|
||||
u32 rst_reg;
|
||||
u32 rst_set_reg;
|
||||
u32 rst_clr_reg;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tegra_clk_periph_gate - peripheral gate clock
|
||||
*
|
||||
* @magic: magic number to validate type
|
||||
* @hw: handle between common and hardware-specific interfaces
|
||||
* @clk_base: address of CAR controller
|
||||
* @regs: Registers to control the peripheral
|
||||
* @flags: hardware-specific flags
|
||||
* @clk_num: Clock number
|
||||
* @enable_refcnt: array to maintain reference count of the clock
|
||||
*
|
||||
* Flags:
|
||||
* TEGRA_PERIPH_NO_RESET - This flag indicates that reset is not allowed
|
||||
* for this module.
|
||||
* TEGRA_PERIPH_MANUAL_RESET - This flag indicates not to reset module
|
||||
* after clock enable and driver for the module is responsible for
|
||||
* doing reset.
|
||||
* 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.
|
||||
*/
|
||||
struct tegra_clk_periph_gate {
|
||||
u32 magic;
|
||||
struct clk_hw hw;
|
||||
void __iomem *clk_base;
|
||||
u8 flags;
|
||||
int clk_num;
|
||||
int *enable_refcnt;
|
||||
struct tegra_clk_periph_regs *regs;
|
||||
};
|
||||
|
||||
#define to_clk_periph_gate(_hw) \
|
||||
container_of(_hw, struct tegra_clk_periph_gate, hw)
|
||||
|
||||
#define TEGRA_CLK_PERIPH_GATE_MAGIC 0x17760309
|
||||
|
||||
#define TEGRA_PERIPH_NO_RESET BIT(0)
|
||||
#define TEGRA_PERIPH_MANUAL_RESET BIT(1)
|
||||
#define TEGRA_PERIPH_ON_APB BIT(2)
|
||||
|
||||
void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert);
|
||||
extern const struct clk_ops tegra_clk_periph_gate_ops;
|
||||
struct clk *tegra_clk_register_periph_gate(const char *name,
|
||||
const char *parent_name, u8 gate_flags, void __iomem *clk_base,
|
||||
unsigned long flags, int clk_num,
|
||||
struct tegra_clk_periph_regs *pregs, int *enable_refcnt);
|
||||
|
||||
/**
|
||||
* struct clk-periph - peripheral clock
|
||||
*
|
||||
* @magic: magic number to validate type
|
||||
* @hw: handle between common and hardware-specific interfaces
|
||||
* @mux: mux clock
|
||||
* @divider: divider clock
|
||||
* @gate: gate clock
|
||||
* @mux_ops: mux clock ops
|
||||
* @div_ops: divider clock ops
|
||||
* @gate_ops: gate clock ops
|
||||
*/
|
||||
struct tegra_clk_periph {
|
||||
u32 magic;
|
||||
struct clk_hw hw;
|
||||
struct clk_mux mux;
|
||||
struct tegra_clk_frac_div divider;
|
||||
struct tegra_clk_periph_gate gate;
|
||||
|
||||
const struct clk_ops *mux_ops;
|
||||
const struct clk_ops *div_ops;
|
||||
const struct clk_ops *gate_ops;
|
||||
};
|
||||
|
||||
#define to_clk_periph(_hw) container_of(_hw, struct tegra_clk_periph, hw)
|
||||
|
||||
#define TEGRA_CLK_PERIPH_MAGIC 0x18221223
|
||||
|
||||
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);
|
||||
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, \
|
||||
_div_shift, _div_width, _div_frac_width, \
|
||||
_div_flags, _clk_num, _enb_refcnt, _regs, \
|
||||
_gate_flags) \
|
||||
{ \
|
||||
.mux = { \
|
||||
.flags = _mux_flags, \
|
||||
.shift = _mux_shift, \
|
||||
.width = _mux_width, \
|
||||
}, \
|
||||
.divider = { \
|
||||
.flags = _div_flags, \
|
||||
.shift = _div_shift, \
|
||||
.width = _div_width, \
|
||||
.frac_width = _div_frac_width, \
|
||||
}, \
|
||||
.gate = { \
|
||||
.flags = _gate_flags, \
|
||||
.clk_num = _clk_num, \
|
||||
.enable_refcnt = _enb_refcnt, \
|
||||
.regs = _regs, \
|
||||
}, \
|
||||
.mux_ops = &clk_mux_ops, \
|
||||
.div_ops = &tegra_clk_frac_div_ops, \
|
||||
.gate_ops = &tegra_clk_periph_gate_ops, \
|
||||
}
|
||||
|
||||
struct tegra_periph_init_data {
|
||||
const char *name;
|
||||
int clk_id;
|
||||
const char **parent_names;
|
||||
int num_parents;
|
||||
struct tegra_clk_periph periph;
|
||||
u32 offset;
|
||||
const char *con_id;
|
||||
const char *dev_id;
|
||||
};
|
||||
|
||||
#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) \
|
||||
{ \
|
||||
.name = _name, \
|
||||
.clk_id = _clk_id, \
|
||||
.parent_names = _parent_names, \
|
||||
.num_parents = ARRAY_SIZE(_parent_names), \
|
||||
.periph = TEGRA_CLK_PERIPH(_mux_shift, _mux_width, \
|
||||
_mux_flags, _div_shift, \
|
||||
_div_width, _div_frac_width, \
|
||||
_div_flags, _clk_num, \
|
||||
_enb_refcnt, _regs, \
|
||||
_gate_flags), \
|
||||
.offset = _offset, \
|
||||
.con_id = _con_id, \
|
||||
.dev_id = _dev_id, \
|
||||
}
|
||||
|
||||
/**
|
||||
* struct clk_super_mux - super clock
|
||||
*
|
||||
* @hw: handle between common and hardware-specific interfaces
|
||||
* @reg: register controlling multiplexer
|
||||
* @width: width of the multiplexer bit field
|
||||
* @flags: hardware-specific flags
|
||||
* @div2_index: bit controlling divide-by-2
|
||||
* @pllx_index: PLLX index in the parent list
|
||||
* @lock: register lock
|
||||
*
|
||||
* Flags:
|
||||
* TEGRA_DIVIDER_2 - LP cluster has additional divider. This flag indicates
|
||||
* that this is LP cluster clock.
|
||||
*/
|
||||
struct tegra_clk_super_mux {
|
||||
struct clk_hw hw;
|
||||
void __iomem *reg;
|
||||
u8 width;
|
||||
u8 flags;
|
||||
u8 div2_index;
|
||||
u8 pllx_index;
|
||||
spinlock_t *lock;
|
||||
};
|
||||
|
||||
#define to_clk_super_mux(_hw) container_of(_hw, struct tegra_clk_super_mux, hw)
|
||||
|
||||
#define TEGRA_DIVIDER_2 BIT(0)
|
||||
|
||||
extern const struct clk_ops tegra_clk_super_ops;
|
||||
struct clk *tegra_clk_register_super_mux(const char *name,
|
||||
const char **parent_names, u8 num_parents,
|
||||
unsigned long flags, void __iomem *reg, u8 clk_super_flags,
|
||||
u8 width, u8 pllx_index, u8 div2_index, spinlock_t *lock);
|
||||
|
||||
/**
|
||||
* struct clk_init_tabel - clock initialization table
|
||||
* @clk_id: clock id as mentioned in device tree bindings
|
||||
* @parent_id: parent clock id as mentioned in device tree bindings
|
||||
* @rate: rate to set
|
||||
* @state: enable/disable
|
||||
*/
|
||||
struct tegra_clk_init_table {
|
||||
unsigned int clk_id;
|
||||
unsigned int parent_id;
|
||||
unsigned long rate;
|
||||
int state;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct clk_duplicate - duplicate clocks
|
||||
* @clk_id: clock id as mentioned in device tree bindings
|
||||
* @lookup: duplicate lookup entry for the clock
|
||||
*/
|
||||
struct tegra_clk_duplicate {
|
||||
int clk_id;
|
||||
struct clk_lookup lookup;
|
||||
};
|
||||
|
||||
#define TEGRA_CLK_DUPLICATE(_clk_id, _dev, _con) \
|
||||
{ \
|
||||
.clk_id = _clk_id, \
|
||||
.lookup = { \
|
||||
.dev_id = _dev, \
|
||||
.con_id = _con, \
|
||||
}, \
|
||||
}
|
||||
|
||||
void tegra_init_from_table(struct tegra_clk_init_table *tbl,
|
||||
struct clk *clks[], int clk_max);
|
||||
|
||||
void tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list,
|
||||
struct clk *clks[], int clk_max);
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||
void tegra20_clock_init(struct device_node *np);
|
||||
#else
|
||||
static inline void tegra20_clock_init(struct device_node *np) {}
|
||||
#endif /* CONFIG_ARCH_TEGRA_2x_SOC */
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
|
||||
void tegra30_clock_init(struct device_node *np);
|
||||
#else
|
||||
static inline void tegra30_clock_init(struct device_node *np) {}
|
||||
#endif /* CONFIG_ARCH_TEGRA_3x_SOC */
|
||||
|
||||
#endif /* TEGRA_CLK_H */
|
|
@ -17,6 +17,7 @@ obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
|
|||
obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o
|
||||
obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o
|
||||
obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o
|
||||
obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o
|
||||
obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o
|
||||
|
||||
obj-$(CONFIG_CLKSRC_ARM_GENERIC) += arm_generic.o
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
/*
|
||||
* arch/arch/mach-tegra/timer.c
|
||||
*
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
*
|
||||
* Author:
|
||||
|
@ -33,8 +31,6 @@
|
|||
#include <asm/smp_twd.h>
|
||||
#include <asm/sched_clock.h>
|
||||
|
||||
#include "board.h"
|
||||
|
||||
#define RTC_SECONDS 0x08
|
||||
#define RTC_SHADOW_SECONDS 0x0c
|
||||
#define RTC_MILLISECONDS 0x10
|
||||
|
@ -168,7 +164,7 @@ static const struct of_device_id rtc_match[] __initconst = {
|
|||
{}
|
||||
};
|
||||
|
||||
void __init tegra_init_timer(void)
|
||||
static void __init tegra20_init_timer(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
struct clk *clk;
|
||||
|
@ -183,7 +179,7 @@ void __init tegra_init_timer(void)
|
|||
|
||||
timer_reg_base = of_iomap(np, 0);
|
||||
if (!timer_reg_base) {
|
||||
pr_err("Can't map timer registers");
|
||||
pr_err("Can't map timer registers\n");
|
||||
BUG();
|
||||
}
|
||||
|
||||
|
@ -268,6 +264,7 @@ void __init tegra_init_timer(void)
|
|||
#endif
|
||||
register_persistent_clock(NULL, tegra_read_persistent_clock);
|
||||
}
|
||||
CLOCKSOURCE_OF_DECLARE(tegra20, "nvidia,tegra20-timer", tegra20_init_timer);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static u32 usec_config;
|
|
@ -31,8 +31,8 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
|
||||
#include <mach/clk.h>
|
||||
#include "dmaengine.h"
|
||||
|
||||
#define TEGRA_APBDMA_GENERAL 0x0
|
||||
|
|
|
@ -12,8 +12,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <mach/clk.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
|
||||
#include "drm.h"
|
||||
#include "dc.h"
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#include <mach/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <asm/dma-iommu.h>
|
||||
|
||||
|
|
|
@ -14,8 +14,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <mach/clk.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
|
||||
#include "hdmi.h"
|
||||
#include "drm.h"
|
||||
|
|
|
@ -29,11 +29,10 @@
|
|||
#include <linux/of_i2c.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <mach/clk.h>
|
||||
|
||||
#define TEGRA_I2C_TIMEOUT (msecs_to_jiffies(1000))
|
||||
#define BYTES_PER_FIFO_WORD 4
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input/tegra_kbc.h>
|
||||
#include <mach/clk.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
|
||||
#define KBC_MAX_DEBOUNCE_CNT 0x3ffu
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#include <linux/of_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/spi-tegra.h>
|
||||
#include <mach/clk.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
|
||||
#define SPI_COMMAND 0x000
|
||||
#define SPI_GO BIT(30)
|
||||
|
@ -525,7 +525,7 @@ static int tegra_sflash_probe(struct platform_device *pdev)
|
|||
goto exit_free_master;
|
||||
}
|
||||
|
||||
tsd->clk = devm_clk_get(&pdev->dev, "spi");
|
||||
tsd->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(tsd->clk)) {
|
||||
dev_err(&pdev->dev, "can not get clock\n");
|
||||
ret = PTR_ERR(tsd->clk);
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#include <linux/of_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/spi-tegra.h>
|
||||
#include <mach/clk.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
|
||||
#define SLINK_COMMAND 0x000
|
||||
#define SLINK_BIT_LENGTH(x) (((x) & 0x1f) << 0)
|
||||
|
@ -1191,7 +1191,7 @@ static int tegra_slink_probe(struct platform_device *pdev)
|
|||
goto exit_free_master;
|
||||
}
|
||||
|
||||
tspi->clk = devm_clk_get(&pdev->dev, "slink");
|
||||
tspi->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(tspi->clk)) {
|
||||
dev_err(&pdev->dev, "can not get clock\n");
|
||||
ret = PTR_ERR(tspi->clk);
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
ToDo list (incomplete, unordered)
|
||||
- add compile as module support
|
||||
- fix clk usage
|
||||
should not be using clk_get_sys(), but clk_get(&pdev->dev, conn)
|
||||
where conn is either NULL if the device only has one clock, or
|
||||
the device specific name if it has multiple clocks.
|
||||
- move half of the nvec init stuff to i2c-tegra.c
|
||||
- move event handling to nvec_events
|
||||
- finish suspend/resume support
|
||||
|
|
|
@ -37,8 +37,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <mach/clk.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
|
||||
#include "nvec.h"
|
||||
|
||||
|
@ -771,7 +770,7 @@ static int tegra_nvec_probe(struct platform_device *pdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
i2c_clk = clk_get_sys("tegra-i2c.2", "div-clk");
|
||||
i2c_clk = clk_get(&pdev->dev, "div-clk");
|
||||
if (IS_ERR(i2c_clk)) {
|
||||
dev_err(nvec->dev, "failed to get controller clock\n");
|
||||
return -ENODEV;
|
||||
|
|
|
@ -14,8 +14,10 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __MACH_TEGRA_CPU_CAR_H
|
||||
#define __MACH_TEGRA_CPU_CAR_H
|
||||
#ifndef __LINUX_CLK_TEGRA_H_
|
||||
#define __LINUX_CLK_TEGRA_H_
|
||||
|
||||
#include <linux/clk.h>
|
||||
|
||||
/*
|
||||
* Tegra CPU clock and reset control ops
|
||||
|
@ -118,7 +120,8 @@ static inline void tegra_cpu_clock_resume(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
void tegra20_cpu_car_ops_init(void);
|
||||
void tegra30_cpu_car_ops_init(void);
|
||||
void tegra_periph_reset_deassert(struct clk *c);
|
||||
void tegra_periph_reset_assert(struct clk *c);
|
||||
void tegra_clocks_init(void);
|
||||
|
||||
#endif /* __MACH_TEGRA_CPU_CAR_H */
|
||||
#endif /* __LINUX_CLK_TEGRA_H_ */
|
22
include/linux/tegra-soc.h
Normal file
22
include/linux/tegra-soc.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_TEGRA_SOC_H_
|
||||
#define __LINUX_TEGRA_SOC_H_
|
||||
|
||||
u32 tegra_read_chipid(void);
|
||||
|
||||
#endif /* __LINUX_TEGRA_SOC_H_ */
|
|
@ -25,7 +25,7 @@
|
|||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <mach/clk.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
#include <sound/soc.h>
|
||||
#include "tegra30_ahub.h"
|
||||
|
||||
|
@ -299,15 +299,6 @@ static const char * const configlink_clocks[] = {
|
|||
"spdif_in",
|
||||
};
|
||||
|
||||
struct of_dev_auxdata ahub_auxdata[] = {
|
||||
OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080300, "tegra30-i2s.0", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080400, "tegra30-i2s.1", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080500, "tegra30-i2s.2", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080600, "tegra30-i2s.3", NULL),
|
||||
OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080700, "tegra30-i2s.4", NULL),
|
||||
{}
|
||||
};
|
||||
|
||||
#define LAST_REG(name) \
|
||||
(TEGRA30_AHUB_##name + \
|
||||
(TEGRA30_AHUB_##name##_STRIDE * TEGRA30_AHUB_##name##_COUNT) - 4)
|
||||
|
@ -451,7 +442,7 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
|
|||
* Ensure that here.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(configlink_clocks); i++) {
|
||||
clk = clk_get_sys(NULL, configlink_clocks[i]);
|
||||
clk = clk_get(&pdev->dev, configlink_clocks[i]);
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(&pdev->dev, "Can't get clock %s\n",
|
||||
configlink_clocks[i]);
|
||||
|
@ -569,8 +560,7 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
|
|||
goto err_pm_disable;
|
||||
}
|
||||
|
||||
of_platform_populate(pdev->dev.of_node, NULL, ahub_auxdata,
|
||||
&pdev->dev);
|
||||
of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
Loading…
Reference in a new issue