Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
1ad105fc
Commit
1ad105fc
authored
Mar 26, 2012
by
Stephen Warren
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote branch 'remotes/korg_olof_tegra/for-3.4/soc' into for-3.4/fixes-for-io-cleanup
parents
2bc856c4
e186ad74
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
3456 additions
and
13 deletions
+3456
-13
arch/arm/mach-tegra/Makefile
arch/arm/mach-tegra/Makefile
+3
-0
arch/arm/mach-tegra/board-dt-tegra30.c
arch/arm/mach-tegra/board-dt-tegra30.c
+23
-1
arch/arm/mach-tegra/clock.c
arch/arm/mach-tegra/clock.c
+22
-0
arch/arm/mach-tegra/clock.h
arch/arm/mach-tegra/clock.h
+15
-0
arch/arm/mach-tegra/common.c
arch/arm/mach-tegra/common.c
+1
-0
arch/arm/mach-tegra/cpuidle.c
arch/arm/mach-tegra/cpuidle.c
+107
-0
arch/arm/mach-tegra/flowctrl.h
arch/arm/mach-tegra/flowctrl.h
+37
-0
arch/arm/mach-tegra/include/mach/clk.h
arch/arm/mach-tegra/include/mach/clk.h
+10
-0
arch/arm/mach-tegra/include/mach/iomap.h
arch/arm/mach-tegra/include/mach/iomap.h
+3
-0
arch/arm/mach-tegra/include/mach/irqs.h
arch/arm/mach-tegra/include/mach/irqs.h
+4
-3
arch/arm/mach-tegra/irq.c
arch/arm/mach-tegra/irq.c
+16
-4
arch/arm/mach-tegra/sleep.S
arch/arm/mach-tegra/sleep.S
+91
-0
arch/arm/mach-tegra/tegra2_clocks.c
arch/arm/mach-tegra/tegra2_clocks.c
+25
-5
arch/arm/mach-tegra/tegra30_clocks.c
arch/arm/mach-tegra/tegra30_clocks.c
+3099
-0
No files found.
arch/arm/mach-tegra/Makefile
View file @
1ad105fc
...
...
@@ -7,12 +7,15 @@ obj-y += clock.o
obj-y
+=
timer.o
obj-y
+=
pinmux.o
obj-y
+=
fuse.o
obj-$(CONFIG_CPU_IDLE)
+=
cpuidle.o
obj-$(CONFIG_CPU_IDLE)
+=
sleep.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC)
+=
powergate.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC)
+=
tegra2_clocks.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC)
+=
tegra2_emc.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC)
+=
pinmux-tegra20-tables.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC)
+=
pinmux-tegra30-tables.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC)
+=
board-dt-tegra30.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC)
+=
tegra30_clocks.o
obj-$(CONFIG_SMP)
+=
platsmp.o localtimer.o headsmp.o
obj-$(CONFIG_HOTPLUG_CPU)
+=
hotplug.o
obj-$(CONFIG_TEGRA_SYSTEM_DMA)
+=
dma.o
...
...
arch/arm/mach-tegra/board-dt-tegra30.c
View file @
1ad105fc
...
...
@@ -34,16 +34,38 @@
#include <asm/hardware/gic.h>
#include "board.h"
#include "clock.h"
static
struct
of_device_id
tegra_dt_match_table
[]
__initdata
=
{
{
.
compatible
=
"simple-bus"
,
},
{}
};
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
),
{}
};
static
__initdata
struct
tegra_clk_init_table
tegra_dt_clk_init_table
[]
=
{
/* name parent rate enabled */
{
"uartd"
,
"pll_p"
,
408000000
,
true
},
{
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
,
tegra_dt_match_table
,
NULL
,
NULL
);
tegra30_auxdata_lookup
,
NULL
);
}
static
const
char
*
tegra30_dt_board_compat
[]
=
{
...
...
arch/arm/mach-tegra/clock.c
View file @
1ad105fc
...
...
@@ -399,6 +399,28 @@ void tegra_periph_reset_assert(struct clk *c)
}
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
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
c
->
spinlock
,
flags
);
if
(
!
c
->
ops
||
!
c
->
ops
->
clk_cfg_ex
)
{
ret
=
-
ENOSYS
;
goto
out
;
}
ret
=
c
->
ops
->
clk_cfg_ex
(
c
,
p
,
setting
);
out:
spin_unlock_irqrestore
(
&
c
->
spinlock
,
flags
);
return
ret
;
}
#ifdef CONFIG_DEBUG_FS
static
int
__clk_lock_all_spinlocks
(
void
)
...
...
arch/arm/mach-tegra/clock.h
View file @
1ad105fc
...
...
@@ -24,6 +24,8 @@
#include <linux/list.h>
#include <linux/spinlock.h>
#include <mach/clk.h>
#define DIV_BUS (1 << 0)
#define DIV_U71 (1 << 1)
#define DIV_U71_FIXED (1 << 2)
...
...
@@ -39,7 +41,16 @@
#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
;
...
...
@@ -65,6 +76,8 @@ struct clk_ops {
int
(
*
set_rate
)(
struct
clk
*
,
unsigned
long
);
long
(
*
round_rate
)(
struct
clk
*
,
unsigned
long
);
void
(
*
reset
)(
struct
clk
*
,
bool
);
int
(
*
clk_cfg_ex
)(
struct
clk
*
,
enum
tegra_clk_ex_param
,
u32
);
};
enum
clk_state
{
...
...
@@ -114,6 +127,7 @@ struct clk {
unsigned
long
vco_max
;
const
struct
clk_pll_freq_table
*
freq_table
;
int
lock_delay
;
unsigned
long
fixed_rate
;
}
pll
;
struct
{
u32
sel
;
...
...
@@ -146,6 +160,7 @@ struct tegra_clk_init_table {
};
void
tegra2_init_clocks
(
void
);
void
tegra30_init_clocks
(
void
);
void
clk_init
(
struct
clk
*
clk
);
struct
clk
*
tegra_get_clock_by_name
(
const
char
*
name
);
int
clk_reparent
(
struct
clk
*
c
,
struct
clk
*
parent
);
...
...
arch/arm/mach-tegra/common.c
View file @
1ad105fc
...
...
@@ -106,6 +106,7 @@ void __init tegra20_init_early(void)
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
void
__init
tegra30_init_early
(
void
)
{
tegra30_init_clocks
();
tegra_init_cache
(
0x441
,
0x551
);
}
#endif
arch/arm/mach-tegra/cpuidle.c
0 → 100644
View file @
1ad105fc
/*
* arch/arm/mach-tegra/cpuidle.c
*
* CPU idle driver for Tegra CPUs
*
* Copyright (c) 2010-2012, NVIDIA Corporation.
* Copyright (c) 2011 Google, Inc.
* Author: Colin Cross <ccross@android.com>
* Gary King <gking@nvidia.com>
*
* Rework for 3.3 by Peter De Schrijver <pdeschrijver@nvidia.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/cpu.h>
#include <linux/cpuidle.h>
#include <linux/hrtimer.h>
#include <mach/iomap.h>
extern
void
tegra_cpu_wfi
(
void
);
static
int
tegra_idle_enter_lp3
(
struct
cpuidle_device
*
dev
,
struct
cpuidle_driver
*
drv
,
int
index
);
struct
cpuidle_driver
tegra_idle_driver
=
{
.
name
=
"tegra_idle"
,
.
owner
=
THIS_MODULE
,
.
state_count
=
1
,
.
states
=
{
[
0
]
=
{
.
enter
=
tegra_idle_enter_lp3
,
.
exit_latency
=
10
,
.
target_residency
=
10
,
.
power_usage
=
600
,
.
flags
=
CPUIDLE_FLAG_TIME_VALID
,
.
name
=
"LP3"
,
.
desc
=
"CPU flow-controlled"
,
},
},
};
static
DEFINE_PER_CPU
(
struct
cpuidle_device
,
tegra_idle_device
);
static
int
tegra_idle_enter_lp3
(
struct
cpuidle_device
*
dev
,
struct
cpuidle_driver
*
drv
,
int
index
)
{
ktime_t
enter
,
exit
;
s64
us
;
local_irq_disable
();
local_fiq_disable
();
enter
=
ktime_get
();
tegra_cpu_wfi
();
exit
=
ktime_sub
(
ktime_get
(),
enter
);
us
=
ktime_to_us
(
exit
);
local_fiq_enable
();
local_irq_enable
();
dev
->
last_residency
=
us
;
return
index
;
}
static
int
__init
tegra_cpuidle_init
(
void
)
{
int
ret
;
unsigned
int
cpu
;
struct
cpuidle_device
*
dev
;
struct
cpuidle_driver
*
drv
=
&
tegra_idle_driver
;
ret
=
cpuidle_register_driver
(
&
tegra_idle_driver
);
if
(
ret
)
{
pr_err
(
"CPUidle driver registration failed
\n
"
);
return
ret
;
}
for_each_possible_cpu
(
cpu
)
{
dev
=
&
per_cpu
(
tegra_idle_device
,
cpu
);
dev
->
cpu
=
cpu
;
dev
->
state_count
=
drv
->
state_count
;
ret
=
cpuidle_register_device
(
dev
);
if
(
ret
)
{
pr_err
(
"CPU%u: CPUidle device registration failed
\n
"
,
cpu
);
return
ret
;
}
}
return
0
;
}
device_initcall
(
tegra_cpuidle_init
);
arch/arm/mach-tegra/flowctrl.h
0 → 100644
View file @
1ad105fc
/*
* arch/arm/mach-tegra/flowctrl.h
*
* functions and macros to control the flowcontroller
*
* Copyright (c) 2010-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 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.
*
* 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_TEGRA_FLOWCTRL_H
#define __MACH_TEGRA_FLOWCTRL_H
#define FLOW_CTRL_HALT_CPU0_EVENTS 0x0
#define FLOW_CTRL_WAITEVENT (2 << 29)
#define FLOW_CTRL_WAIT_FOR_INTERRUPT (4 << 29)
#define FLOW_CTRL_JTAG_RESUME (1 << 28)
#define FLOW_CTRL_HALT_CPU_IRQ (1 << 10)
#define FLOW_CTRL_HALT_CPU_FIQ (1 << 8)
#define FLOW_CTRL_CPU0_CSR 0x8
#define FLOW_CTRL_CSR_INTR_FLAG (1 << 15)
#define FLOW_CTRL_CSR_EVENT_FLAG (1 << 14)
#define FLOW_CTRL_CSR_ENABLE (1 << 0)
#define FLOW_CTRL_HALT_CPU1_EVENTS 0x14
#define FLOW_CTRL_CPU1_CSR 0x18
#endif
arch/arm/mach-tegra/include/mach/clk.h
View file @
1ad105fc
...
...
@@ -22,10 +22,20 @@
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
);
unsigned
long
clk_get_rate_all_locked
(
struct
clk
*
c
);
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
arch/arm/mach-tegra/include/mach/iomap.h
View file @
1ad105fc
...
...
@@ -74,6 +74,9 @@
#define TEGRA_QUATERNARY_ICTLR_BASE 0x60004300
#define TEGRA_QUATERNARY_ICTLR_SIZE SZ_64
#define TEGRA_QUINARY_ICTLR_BASE 0x60004400
#define TEGRA_QUINARY_ICTLR_SIZE SZ_64
#define TEGRA_TMR1_BASE 0x60005000
#define TEGRA_TMR1_SIZE SZ_8
...
...
arch/arm/mach-tegra/include/mach/irqs.h
View file @
1ad105fc
...
...
@@ -165,11 +165,12 @@
#define INT_QUAD_RES_30 (INT_QUAD_BASE + 30)
#define INT_QUAD_RES_31 (INT_QUAD_BASE + 31)
#define INT_MAIN_NR (INT_QUAD_BASE + 32 - INT_PRI_BASE)
/* Tegra30 has 5 banks of 32 IRQs */
#define INT_MAIN_NR (32 * 5)
#define INT_GPIO_BASE (INT_PRI_BASE + INT_MAIN_NR)
#define INT_GPIO_NR (28 * 8)
/* Tegra30 has 8 banks of 32 GPIOs */
#define INT_GPIO_NR (32 * 8)
#define TEGRA_NR_IRQS (INT_GPIO_BASE + INT_GPIO_NR)
...
...
arch/arm/mach-tegra/irq.c
View file @
1ad105fc
...
...
@@ -44,14 +44,16 @@
#define ICTLR_COP_IER_CLR 0x38
#define ICTLR_COP_IEP_CLASS 0x3c
#define NUM_ICTLRS 4
#define FIRST_LEGACY_IRQ 32
static
int
num_ictlrs
;
static
void
__iomem
*
ictlr_reg_base
[]
=
{
IO_ADDRESS
(
TEGRA_PRIMARY_ICTLR_BASE
),
IO_ADDRESS
(
TEGRA_SECONDARY_ICTLR_BASE
),
IO_ADDRESS
(
TEGRA_TERTIARY_ICTLR_BASE
),
IO_ADDRESS
(
TEGRA_QUATERNARY_ICTLR_BASE
),
IO_ADDRESS
(
TEGRA_QUINARY_ICTLR_BASE
),
};
static
inline
void
tegra_irq_write_mask
(
unsigned
int
irq
,
unsigned
long
reg
)
...
...
@@ -60,7 +62,7 @@ static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg)
u32
mask
;
BUG_ON
(
irq
<
FIRST_LEGACY_IRQ
||
irq
>=
FIRST_LEGACY_IRQ
+
NUM_ICTLRS
*
32
);
irq
>=
FIRST_LEGACY_IRQ
+
num_ictlrs
*
32
);
base
=
ictlr_reg_base
[(
irq
-
FIRST_LEGACY_IRQ
)
/
32
];
mask
=
BIT
((
irq
-
FIRST_LEGACY_IRQ
)
%
32
);
...
...
@@ -113,8 +115,18 @@ static int tegra_retrigger(struct irq_data *d)
void
__init
tegra_init_irq
(
void
)
{
int
i
;
void
__iomem
*
distbase
;
distbase
=
IO_ADDRESS
(
TEGRA_ARM_INT_DIST_BASE
);
num_ictlrs
=
readl_relaxed
(
distbase
+
GIC_DIST_CTR
)
&
0x1f
;
if
(
num_ictlrs
>
ARRAY_SIZE
(
ictlr_reg_base
))
{
WARN
(
1
,
"Too many (%d) interrupt controllers found. Maximum is %d."
,
num_ictlrs
,
ARRAY_SIZE
(
ictlr_reg_base
));
num_ictlrs
=
ARRAY_SIZE
(
ictlr_reg_base
);
}
for
(
i
=
0
;
i
<
NUM_ICTLRS
;
i
++
)
{
for
(
i
=
0
;
i
<
num_ictlrs
;
i
++
)
{
void
__iomem
*
ictlr
=
ictlr_reg_base
[
i
];
writel
(
~
0
,
ictlr
+
ICTLR_CPU_IER_CLR
);
writel
(
0
,
ictlr
+
ICTLR_CPU_IEP_CLASS
);
...
...
@@ -131,6 +143,6 @@ void __init tegra_init_irq(void)
* initialized elsewhere under DT.
*/
if
(
!
of_have_populated_dt
())
gic_init
(
0
,
29
,
IO_ADDRESS
(
TEGRA_ARM_INT_DIST_BASE
)
,
gic_init
(
0
,
29
,
distbase
,
IO_ADDRESS
(
TEGRA_ARM_PERIF_BASE
+
0x100
));
}
arch/arm/mach-tegra/sleep.S
0 → 100644
View file @
1ad105fc
/*
*
arch
/
arm
/
mach
-
tegra
/
sleep
.
S
*
*
Copyright
(
c
)
2010
-
2011
,
NVIDIA
Corporation
.
*
Copyright
(
c
)
2011
,
Google
,
Inc
.
*
*
Author
:
Colin
Cross
<
ccross
@
android
.
com
>
*
Gary
King
<
gking
@
nvidia
.
com
>
*
*
This
program
is
free
software
; you can redistribute it and/or modify
*
it
under
the
terms
of
the
GNU
General
Public
License
as
published
by
*
the
Free
Software
Foundation
; either version 2 of the License, or
*
(
at
your
option
)
any
later
version
.
*
*
This
program
is
distributed
in
the
hope
that
it
will
be
useful
,
but
WITHOUT
*
ANY
WARRANTY
; without even the implied warranty of MERCHANTABILITY or
*
FITNESS
FOR
A
PARTICULAR
PURPOSE
.
See
the
GNU
General
Public
License
for
*
more
details
.
*
*
You
should
have
received
a
copy
of
the
GNU
General
Public
License
along
*
with
this
program
; if not, write to the Free Software Foundation, Inc.,
*
51
Franklin
Street
,
Fifth
Floor
,
Boston
,
MA
02110
-
1301
,
USA
.
*/
#include <linux/linkage.h>
#include <mach/io.h>
#include <mach/iomap.h>
#include "flowctrl.h"
#define TEGRA_FLOW_CTRL_VIRT (TEGRA_FLOW_CTRL_BASE - IO_PPSB_PHYS \
+
IO_PPSB_VIRT
)
/*
returns
the
offset
of
the
flow
controller
halt
register
for
a
cpu
*/
.
macro
cpu_to_halt_reg
rd
,
rcpu
cmp
\
rcpu
,
#
0
subne
\
rd
,
\
rcpu
,
#
1
movne
\
rd
,
\
rd
,
lsl
#
3
addne
\
rd
,
\
rd
,
#
0x14
moveq
\
rd
,
#
0
.
endm
/*
returns
the
offset
of
the
flow
controller
csr
register
for
a
cpu
*/
.
macro
cpu_to_csr_reg
rd
,
rcpu
cmp
\
rcpu
,
#
0
subne
\
rd
,
\
rcpu
,
#
1
movne
\
rd
,
\
rd
,
lsl
#
3
addne
\
rd
,
\
rd
,
#
0x18
moveq
\
rd
,
#
8
.
endm
/*
returns
the
ID
of
the
current
processor
*/
.
macro
cpu_id
,
rd
mrc
p15
,
0
,
\
rd
,
c0
,
c0
,
5
and
\
rd
,
\
rd
,
#
0xF
.
endm
/*
loads
a
32
-
bit
value
into
a
register
without
a
data
access
*/
.
macro
mov32
,
reg
,
val
movw
\
reg
,
#
:
lower16
:\
val
movt
\
reg
,
#
:
upper16
:\
val
.
endm
/*
*
tegra_cpu_wfi
*
*
puts
current
CPU
in
clock
-
gated
wfi
using
the
flow
controller
*
*
corrupts
r0
-
r3
*
must
be
called
with
MMU
on
*/
ENTRY
(
tegra_cpu_wfi
)
cpu_id
r0
cpu_to_halt_reg
r1
,
r0
cpu_to_csr_reg
r2
,
r0
mov32
r0
,
TEGRA_FLOW_CTRL_VIRT
mov
r3
,
#
FLOW_CTRL_CSR_INTR_FLAG
|
FLOW_CTRL_CSR_EVENT_FLAG
str
r3
,
[
r0
,
r2
]
@
clear
event
&
interrupt
status
mov
r3
,
#
FLOW_CTRL_WAIT_FOR_INTERRUPT
|
FLOW_CTRL_JTAG_RESUME
str
r3
,
[
r0
,
r1
]
@
put
flow
controller
in
wait
irq
mode
dsb
wfi
mov
r3
,
#
0
str
r3
,
[
r0
,
r1
]
@
clear
flow
controller
halt
status
mov
r3
,
#
FLOW_CTRL_CSR_INTR_FLAG
|
FLOW_CTRL_CSR_EVENT_FLAG
str
r3
,
[
r0
,
r2
]
@
clear
event
&
interrupt
status
dsb
mov
pc
,
lr
ENDPROC
(
tegra_cpu_wfi
)
arch/arm/mach-tegra/tegra2_clocks.c
View file @
1ad105fc
...
...
@@ -1143,15 +1143,35 @@ static void tegra2_emc_clk_init(struct clk *c)
static
long
tegra2_emc_clk_round_rate
(
struct
clk
*
c
,
unsigned
long
rate
)
{
long
new_rate
=
rate
;
long
emc_rate
;
long
clk_rate
;
new_rate
=
tegra_emc_round_rate
(
new_rate
);
if
(
new_rate
<
0
)
/*
* The slowest entry in the EMC clock table that is at least as
* fast as rate.
*/
emc_rate
=
tegra_emc_round_rate
(
rate
);
if
(
emc_rate
<
0
)
return
c
->
max_rate
;
BUG_ON
(
new_rate
!=
tegra2_periph_clk_round_rate
(
c
,
new_rate
));
/*
* The fastest rate the PLL will generate that is at most the
* requested rate.
*/
clk_rate
=
tegra2_periph_clk_round_rate
(
c
,
emc_rate
);
/*
* If this fails, and emc_rate > clk_rate, it's because the maximum
* rate in the EMC tables is larger than the maximum rate of the EMC
* clock. The EMC clock's max rate is the rate it was running when the
* kernel booted. Such a mismatch is probably due to using the wrong
* BCT, i.e. using a Tegra20 BCT with an EMC table written for Tegra25.
*/
WARN_ONCE
(
emc_rate
!=
clk_rate
,
"emc_rate %ld != clk_rate %ld"
,
emc_rate
,
clk_rate
);
return
new
_rate
;
return
emc
_rate
;
}
static
int
tegra2_emc_clk_set_rate
(
struct
clk
*
c
,
unsigned
long
rate
)
...
...
arch/arm/mach-tegra/tegra30_clocks.c
0 → 100644
View file @
1ad105fc
/*
* arch/arm/mach-tegra/tegra30_clocks.c
*
* Copyright (c) 2010-2011 NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <linux/syscore_ops.h>
#include <asm/clkdev.h>
#include <mach/iomap.h>
#include "clock.h"
#include "fuse.h"
#define USE_PLL_LOCK_BITS 0
#define RST_DEVICES_L 0x004
#define RST_DEVICES_H 0x008
#define RST_DEVICES_U 0x00C
#define RST_DEVICES_V 0x358
#define RST_DEVICES_W 0x35C
#define RST_DEVICES_SET_L 0x300
#define RST_DEVICES_CLR_L 0x304
#define RST_DEVICES_SET_V 0x430
#define RST_DEVICES_CLR_V 0x434
#define RST_DEVICES_NUM 5
#define CLK_OUT_ENB_L 0x010
#define CLK_OUT_ENB_H 0x014
#define CLK_OUT_ENB_U 0x018
#define CLK_OUT_ENB_V 0x360
#define CLK_OUT_ENB_W 0x364
#define CLK_OUT_ENB_SET_L 0x320
#define CLK_OUT_ENB_CLR_L 0x324
#define CLK_OUT_ENB_SET_V 0x440
#define CLK_OUT_ENB_CLR_V 0x444
#define CLK_OUT_ENB_NUM 5
#define RST_DEVICES_V_SWR_CPULP_RST_DIS (0x1 << 1)
#define CLK_OUT_ENB_V_CLK_ENB_CPULP_EN (0x1 << 1)
#define PERIPH_CLK_TO_BIT(c) (1 << (c->u.periph.clk_num % 32))
#define PERIPH_CLK_TO_RST_REG(c) \
periph_clk_to_reg((c), RST_DEVICES_L, RST_DEVICES_V, 4)
#define PERIPH_CLK_TO_RST_SET_REG(c) \
periph_clk_to_reg((c), RST_DEVICES_SET_L, RST_DEVICES_SET_V, 8)
#define PERIPH_CLK_TO_RST_CLR_REG(c) \
periph_clk_to_reg((c), RST_DEVICES_CLR_L, RST_DEVICES_CLR_V, 8)
#define PERIPH_CLK_TO_ENB_REG(c) \
periph_clk_to_reg((c), CLK_OUT_ENB_L, CLK_OUT_ENB_V, 4)
#define PERIPH_CLK_TO_ENB_SET_REG(c) \
periph_clk_to_reg((c), CLK_OUT_ENB_SET_L, CLK_OUT_ENB_SET_V, 8)
#define PERIPH_CLK_TO_ENB_CLR_REG(c) \
periph_clk_to_reg((c), CLK_OUT_ENB_CLR_L, CLK_OUT_ENB_CLR_V, 8)
#define CLK_MASK_ARM 0x44
#define MISC_CLK_ENB 0x48
#define OSC_CTRL 0x50
#define OSC_CTRL_OSC_FREQ_MASK (0xF<<28)
#define OSC_CTRL_OSC_FREQ_13MHZ (0x0<<28)
#define OSC_CTRL_OSC_FREQ_19_2MHZ (0x4<<28)
#define OSC_CTRL_OSC_FREQ_12MHZ (0x8<<28)
#define OSC_CTRL_OSC_FREQ_26MHZ (0xC<<28)
#define OSC_CTRL_OSC_FREQ_16_8MHZ (0x1<<28)
#define OSC_CTRL_OSC_FREQ_38_4MHZ (0x5<<28)
#define OSC_CTRL_OSC_FREQ_48MHZ (0x9<<28)
#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK)
#define OSC_CTRL_PLL_REF_DIV_MASK (3<<26)
#define OSC_CTRL_PLL_REF_DIV_1 (0<<26)
#define OSC_CTRL_PLL_REF_DIV_2 (1<<26)
#define OSC_CTRL_PLL_REF_DIV_4 (2<<26)
#define OSC_FREQ_DET 0x58
#define OSC_FREQ_DET_TRIG (1<<31)
#define OSC_FREQ_DET_STATUS 0x5C
#define OSC_FREQ_DET_BUSY (1<<31)
#define OSC_FREQ_DET_CNT_MASK 0xFFFF
#define PERIPH_CLK_SOURCE_I2S1 0x100
#define PERIPH_CLK_SOURCE_EMC 0x19c
#define PERIPH_CLK_SOURCE_OSC 0x1fc
#define PERIPH_CLK_SOURCE_NUM1 \
((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4)
#define PERIPH_CLK_SOURCE_G3D2 0x3b0
#define PERIPH_CLK_SOURCE_SE 0x42c
#define PERIPH_CLK_SOURCE_NUM2 \
((PERIPH_CLK_SOURCE_SE - PERIPH_CLK_SOURCE_G3D2) / 4 + 1)
#define AUDIO_DLY_CLK 0x49c
#define AUDIO_SYNC_CLK_SPDIF 0x4b4
#define PERIPH_CLK_SOURCE_NUM3 \
((AUDIO_SYNC_CLK_SPDIF - AUDIO_DLY_CLK) / 4 + 1)
#define PERIPH_CLK_SOURCE_NUM (PERIPH_CLK_SOURCE_NUM1 + \
PERIPH_CLK_SOURCE_NUM2 + \
PERIPH_CLK_SOURCE_NUM3)
#define CPU_SOFTRST_CTRL 0x380
#define PERIPH_CLK_SOURCE_DIVU71_MASK 0xFF
#define PERIPH_CLK_SOURCE_DIVU16_MASK 0xFFFF
#define PERIPH_CLK_SOURCE_DIV_SHIFT 0
#define PERIPH_CLK_SOURCE_DIVIDLE_SHIFT 8
#define PERIPH_CLK_SOURCE_DIVIDLE_VAL 50
#define PERIPH_CLK_UART_DIV_ENB (1<<24)
#define PERIPH_CLK_VI_SEL_EX_SHIFT 24
#define PERIPH_CLK_VI_SEL_EX_MASK (0x3<<PERIPH_CLK_VI_SEL_EX_SHIFT)
#define PERIPH_CLK_NAND_DIV_EX_ENB (1<<8)
#define PERIPH_CLK_DTV_POLARITY_INV (1<<25)
#define AUDIO_SYNC_SOURCE_MASK 0x0F
#define AUDIO_SYNC_DISABLE_BIT 0x10
#define AUDIO_SYNC_TAP_NIBBLE_SHIFT(c) ((c->reg_shift - 24) * 4)
#define PLL_BASE 0x0
#define PLL_BASE_BYPASS (1<<31)
#define PLL_BASE_ENABLE (1<<30)
#define PLL_BASE_REF_ENABLE (1<<29)
#define PLL_BASE_OVERRIDE (1<<28)
#define PLL_BASE_LOCK (1<<27)
#define PLL_BASE_DIVP_MASK (0x7<<20)
#define PLL_BASE_DIVP_SHIFT 20
#define PLL_BASE_DIVN_MASK (0x3FF<<8)
#define PLL_BASE_DIVN_SHIFT 8
#define PLL_BASE_DIVM_MASK (0x1F)
#define PLL_BASE_DIVM_SHIFT 0
#define PLL_OUT_RATIO_MASK (0xFF<<8)
#define PLL_OUT_RATIO_SHIFT 8
#define PLL_OUT_OVERRIDE (1<<2)
#define PLL_OUT_CLKEN (1<<1)
#define PLL_OUT_RESET_DISABLE (1<<0)
#define PLL_MISC(c) \
(((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc)
#define PLL_MISC_LOCK_ENABLE(c) \
(((c)->flags & (PLLU | PLLD)) ? (1<<22) : (1<<18))
#define PLL_MISC_DCCON_SHIFT 20
#define PLL_MISC_CPCON_SHIFT 8
#define PLL_MISC_CPCON_MASK (0xF<<PLL_MISC_CPCON_SHIFT)
#define PLL_MISC_LFCON_SHIFT 4
#define PLL_MISC_LFCON_MASK (0xF<<PLL_MISC_LFCON_SHIFT)
#define PLL_MISC_VCOCON_SHIFT 0
#define PLL_MISC_VCOCON_MASK (0xF<<PLL_MISC_VCOCON_SHIFT)
#define PLLD_MISC_CLKENABLE (1<<30)
#define PLLU_BASE_POST_DIV (1<<20)
#define PLLD_BASE_DSIB_MUX_SHIFT 25
#define PLLD_BASE_DSIB_MUX_MASK (1<<PLLD_BASE_DSIB_MUX_SHIFT)
#define PLLD_BASE_CSI_CLKENABLE (1<<26)
#define PLLD_MISC_DSI_CLKENABLE (1<<30)
#define PLLD_MISC_DIV_RST (1<<23)
#define PLLD_MISC_DCCON_SHIFT 12
#define PLLDU_LFCON_SET_DIVN 600
/* FIXME: OUT_OF_TABLE_CPCON per pll */
#define OUT_OF_TABLE_CPCON 0x8
#define SUPER_CLK_MUX 0x00
#define SUPER_STATE_SHIFT 28
#define SUPER_STATE_MASK (0xF << SUPER_STATE_SHIFT)
#define SUPER_STATE_STANDBY (0x0 << SUPER_STATE_SHIFT)
#define SUPER_STATE_IDLE (0x1 << SUPER_STATE_SHIFT)
#define SUPER_STATE_RUN (0x2 << SUPER_STATE_SHIFT)
#define SUPER_STATE_IRQ (0x3 << SUPER_STATE_SHIFT)
#define SUPER_STATE_FIQ (0x4 << SUPER_STATE_SHIFT)
#define SUPER_LP_DIV2_BYPASS (0x1 << 16)
#define SUPER_SOURCE_MASK 0xF
#define SUPER_FIQ_SOURCE_SHIFT 12
#define SUPER_IRQ_SOURCE_SHIFT 8
#define SUPER_RUN_SOURCE_SHIFT 4
#define SUPER_IDLE_SOURCE_SHIFT 0
#define SUPER_CLK_DIVIDER 0x04
#define SUPER_CLOCK_DIV_U71_SHIFT 16
#define SUPER_CLOCK_DIV_U71_MASK (0xff << SUPER_CLOCK_DIV_U71_SHIFT)
/* guarantees safe cpu backup */
#define SUPER_CLOCK_DIV_U71_MIN 0x2
#define BUS_CLK_DISABLE (1<<3)
#define BUS_CLK_DIV_MASK 0x3
#define PMC_CTRL 0x0
#define PMC_CTRL_BLINK_ENB (1 << 7)
#define PMC_DPD_PADS_ORIDE 0x1c
#define PMC_DPD_PADS_ORIDE_BLINK_ENB (1 << 20)
#define PMC_BLINK_TIMER_DATA_ON_SHIFT 0
#define PMC_BLINK_TIMER_DATA_ON_MASK 0x7fff
#define PMC_BLINK_TIMER_ENB (1 << 15)
#define PMC_BLINK_TIMER_DATA_OFF_SHIFT 16
#define PMC_BLINK_TIMER_DATA_OFF_MASK 0xffff
#define PMC_PLLP_WB0_OVERRIDE 0xf8
#define PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE (1 << 12)
#define UTMIP_PLL_CFG2 0x488
#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xfff) << 6)
#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18)
#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN (1 << 0)
#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN (1 << 2)
#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN (1 << 4)
#define UTMIP_PLL_CFG1 0x484
#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN (1 << 14)
#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN (1 << 12)
#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN (1 << 16)
#define PLLE_BASE_CML_ENABLE (1<<31)
#define PLLE_BASE_ENABLE (1<<30)
#define PLLE_BASE_DIVCML_SHIFT 24
#define PLLE_BASE_DIVCML_MASK (0xf<<PLLE_BASE_DIVCML_SHIFT)
#define PLLE_BASE_DIVP_SHIFT 16
#define PLLE_BASE_DIVP_MASK (0x3f<<PLLE_BASE_DIVP_SHIFT)
#define PLLE_BASE_DIVN_SHIFT 8
#define PLLE_BASE_DIVN_MASK (0xFF<<PLLE_BASE_DIVN_SHIFT)
#define PLLE_BASE_DIVM_SHIFT 0
#define PLLE_BASE_DIVM_MASK (0xFF<<PLLE_BASE_DIVM_SHIFT)
#define PLLE_BASE_DIV_MASK \
(PLLE_BASE_DIVCML_MASK | PLLE_BASE_DIVP_MASK | \
PLLE_BASE_DIVN_MASK | PLLE_BASE_DIVM_MASK)
#define PLLE_BASE_DIV(m, n, p, cml) \
(((cml)<<PLLE_BASE_DIVCML_SHIFT) | ((p)<<PLLE_BASE_DIVP_SHIFT) | \
((n)<<PLLE_BASE_DIVN_SHIFT) | ((m)<<PLLE_BASE_DIVM_SHIFT))
#define PLLE_MISC_SETUP_BASE_SHIFT 16
#define PLLE_MISC_SETUP_BASE_MASK (0xFFFF<<PLLE_MISC_SETUP_BASE_SHIFT)
#define PLLE_MISC_READY (1<<15)
#define PLLE_MISC_LOCK (1<<11)
#define PLLE_MISC_LOCK_ENABLE (1<<9)
#define PLLE_MISC_SETUP_EX_SHIFT 2
#define PLLE_MISC_SETUP_EX_MASK (0x3<<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 \
((0x7<<PLLE_MISC_SETUP_BASE_SHIFT) | (0x0<<PLLE_MISC_SETUP_EX_SHIFT))
#define PLLE_SS_CTRL 0x68
#define PLLE_SS_INCINTRV_SHIFT 24
#define PLLE_SS_INCINTRV_MASK (0x3f<<PLLE_SS_INCINTRV_SHIFT)
#define PLLE_SS_INC_SHIFT 16
#define PLLE_SS_INC_MASK (0xff<<PLLE_SS_INC_SHIFT)
#define PLLE_SS_MAX_SHIFT 0
#define PLLE_SS_MAX_MASK (0x1ff<<PLLE_SS_MAX_SHIFT)
#define PLLE_SS_COEFFICIENTS_MASK \
(PLLE_SS_INCINTRV_MASK | PLLE_SS_INC_MASK | PLLE_SS_MAX_MASK)
#define PLLE_SS_COEFFICIENTS_12MHZ \
((0x18<<PLLE_SS_INCINTRV_SHIFT) | (0x1<<PLLE_SS_INC_SHIFT) | \
(0x24<<PLLE_SS_MAX_SHIFT))
#define PLLE_SS_DISABLE ((1<<12) | (1<<11) | (1<<10))
#define PLLE_AUX 0x48c
#define PLLE_AUX_PLLP_SEL (1<<2)
#define PLLE_AUX_CML_SATA_ENABLE (1<<1)
#define PLLE_AUX_CML_PCIE_ENABLE (1<<0)
#define PMC_SATA_PWRGT 0x1ac
#define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE (1<<5)
#define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL (1<<4)
#define ROUND_DIVIDER_UP 0
#define ROUND_DIVIDER_DOWN 1
/* FIXME: recommended safety delay after lock is detected */
#define PLL_POST_LOCK_DELAY 100
/**
* Structure defining the fields for USB UTMI clocks Parameters.
*/
struct
utmi_clk_param
{
/* Oscillator Frequency in KHz */
u32
osc_frequency
;
/* UTMIP PLL Enable Delay Count */
u8
enable_delay_count
;
/* UTMIP PLL Stable count */
u8
stable_count
;
/* UTMIP PLL Active delay count */
u8
active_delay_count
;
/* UTMIP PLL Xtal frequency count */
u8
xtal_freq_count
;
};
static
const
struct
utmi_clk_param
utmi_parameters
[]
=
{
{
.
osc_frequency
=
13000000
,
.
enable_delay_count
=
0x02
,
.
stable_count
=
0x33
,
.
active_delay_count
=
0x05
,
.
xtal_freq_count
=
0x7F
},
{
.
osc_frequency
=
19200000
,
.
enable_delay_count
=
0x03
,
.
stable_count
=
0x4B
,
.
active_delay_count
=
0x06
,
.
xtal_freq_count
=
0xBB
},
{
.
osc_frequency
=
12000000
,
.
enable_delay_count
=
0x02
,
.
stable_count
=
0x2F
,
.
active_delay_count
=
0x04
,
.
xtal_freq_count
=
0x76
},
{
.
osc_frequency
=
26000000
,
.
enable_delay_count
=
0x04
,
.
stable_count
=
0x66
,
.
active_delay_count
=
0x09
,
.
xtal_freq_count
=
0xFE
},
{
.
osc_frequency
=
16800000
,
.
enable_delay_count
=
0x03
,
.
stable_count
=
0x41
,
.
active_delay_count
=
0x0A
,
.
xtal_freq_count
=
0xA4
},
};
static
void
__iomem
*
reg_clk_base
=
IO_ADDRESS
(
TEGRA_CLK_RESET_BASE
);
static
void
__iomem
*
reg_pmc_base
=
IO_ADDRESS
(
TEGRA_PMC_BASE
);
static
void
__iomem
*
misc_gp_hidrev_base
=
IO_ADDRESS
(
TEGRA_APB_MISC_BASE
);
#define MISC_GP_HIDREV 0x804
/*
* Some peripheral clocks share an enable bit, so refcount the enable bits
* in registers CLK_ENABLE_L, ... CLK_ENABLE_W
*/
static
int
tegra_periph_clk_enable_refcount
[
CLK_OUT_ENB_NUM
*
32
];
#define clk_writel(value, reg) \
__raw_writel(value, (u32)reg_clk_base + (reg))
#define clk_readl(reg) \
__raw_readl((u32)reg_clk_base + (reg))
#define pmc_writel(value, reg) \
__raw_writel(value, (u32)reg_pmc_base + (reg))
#define pmc_readl(reg) \
__raw_readl((u32)reg_pmc_base + (reg))
#define chipid_readl() \
__raw_readl((u32)misc_gp_hidrev_base + MISC_GP_HIDREV)
#define clk_writel_delay(value, reg) \
do { \
__raw_writel((value), (u32)reg_clk_base + (reg)); \
udelay(2); \
} while (0)
static
inline
int
clk_set_div
(
struct
clk
*
c
,
u32
n
)
{
return
clk_set_rate
(
c
,
(
clk_get_rate
(
c
->
parent
)
+
n
-
1
)
/
n
);
}
static
inline
u32
periph_clk_to_reg
(
struct
clk
*
c
,
u32
reg_L
,
u32
reg_V
,
int
offs
)
{
u32
reg
=
c
->
u
.
periph
.
clk_num
/
32
;
BUG_ON
(
reg
>=
RST_DEVICES_NUM
);
if
(
reg
<
3
)
reg
=
reg_L
+
(
reg
*
offs
);
else
reg
=
reg_V
+
((
reg
-
3
)
*
offs
);
return
reg
;
}
static
unsigned
long
clk_measure_input_freq
(
void
)
{
u32
clock_autodetect
;
clk_writel
(
OSC_FREQ_DET_TRIG
|
1
,
OSC_FREQ_DET
);
do
{}
while
(
clk_readl
(
OSC_FREQ_DET_STATUS
)
&
OSC_FREQ_DET_BUSY
);
clock_autodetect
=
clk_readl
(
OSC_FREQ_DET_STATUS
);
if
(
clock_autodetect
>=
732
-
3
&&
clock_autodetect
<=
732
+
3
)
{
return
12000000
;
}
else
if
(
clock_autodetect
>=
794
-
3
&&
clock_autodetect
<=
794
+
3
)
{
return
13000000
;
}
else
if
(
clock_autodetect
>=
1172
-
3
&&
clock_autodetect
<=
1172
+
3
)
{
return
19200000
;
}
else
if
(
clock_autodetect
>=
1587
-
3
&&
clock_autodetect
<=
1587
+
3
)
{
return
26000000
;
}
else
if
(
clock_autodetect
>=
1025
-
3
&&
clock_autodetect
<=
1025
+
3
)
{
return
16800000
;
}
else
if
(
clock_autodetect
>=
2344
-
3
&&
clock_autodetect
<=
2344
+
3
)
{
return
38400000
;
}
else
if
(
clock_autodetect
>=
2928
-
3
&&
clock_autodetect
<=
2928
+
3
)
{
return
48000000
;
}
else
{
pr_err
(
"%s: Unexpected clock autodetect value %d"
,
__func__
,
clock_autodetect
);
BUG
();
return
0
;
}
}
static
int
clk_div71_get_divider
(
unsigned
long
parent_rate
,
unsigned
long
rate
,
u32
flags
,
u32
round_mode
)
{
s64
divider_u71
=
parent_rate
;
if
(
!
rate
)
return
-
EINVAL
;
if
(
!
(
flags
&
DIV_U71_INT
))
divider_u71
*=
2
;
if
(
round_mode
==
ROUND_DIVIDER_UP
)
divider_u71
+=
rate
-
1
;
do_div
(
divider_u71
,
rate
);
if
(
flags
&
DIV_U71_INT
)
divider_u71
*=
2
;
if
(
divider_u71
-
2
<
0
)
return
0
;
if
(
divider_u71
-
2
>
255
)
return
-
EINVAL
;
return
divider_u71
-
2
;
}
static
int
clk_div16_get_divider
(
unsigned
long
parent_rate
,
unsigned
long
rate
)
{
s64
divider_u16
;
divider_u16
=
parent_rate
;
if
(
!
rate
)
return
-
EINVAL
;
divider_u16
+=
rate
-
1
;
do_div
(
divider_u16
,
rate
);
if
(
divider_u16
-
1
<
0
)
return
0
;
if
(
divider_u16
-
1
>
0xFFFF
)
return
-
EINVAL
;
return
divider_u16
-
1
;
}
/* clk_m functions */
static
unsigned
long
tegra30_clk_m_autodetect_rate
(
struct
clk
*
c
)
{
u32
osc_ctrl
=
clk_readl
(
OSC_CTRL
);
u32
auto_clock_control
=
osc_ctrl
&
~
OSC_CTRL_OSC_FREQ_MASK
;
u32
pll_ref_div
=
osc_ctrl
&
OSC_CTRL_PLL_REF_DIV_MASK
;
c
->
rate
=
clk_measure_input_freq
();
switch
(
c
->
rate
)
{
case
12000000
:
auto_clock_control
|=
OSC_CTRL_OSC_FREQ_12MHZ
;
BUG_ON
(
pll_ref_div
!=
OSC_CTRL_PLL_REF_DIV_1
);
break
;
case
13000000
:
auto_clock_control
|=
OSC_CTRL_OSC_FREQ_13MHZ
;
BUG_ON
(
pll_ref_div
!=
OSC_CTRL_PLL_REF_DIV_1
);
break
;
case
19200000
:
auto_clock_control
|=
OSC_CTRL_OSC_FREQ_19_2MHZ
;
BUG_ON
(
pll_ref_div
!=
OSC_CTRL_PLL_REF_DIV_1
);
break
;
case
26000000
:
auto_clock_control
|=
OSC_CTRL_OSC_FREQ_26MHZ
;
BUG_ON
(
pll_ref_div
!=
OSC_CTRL_PLL_REF_DIV_1
);
break
;
case
16800000
:
auto_clock_control
|=
OSC_CTRL_OSC_FREQ_16_8MHZ
;
BUG_ON
(
pll_ref_div
!=
OSC_CTRL_PLL_REF_DIV_1
);
break
;
case
38400000
:
auto_clock_control
|=
OSC_CTRL_OSC_FREQ_38_4MHZ
;
BUG_ON
(
pll_ref_div
!=
OSC_CTRL_PLL_REF_DIV_2
);
break
;
case
48000000
:
auto_clock_control
|=
OSC_CTRL_OSC_FREQ_48MHZ
;
BUG_ON
(
pll_ref_div
!=
OSC_CTRL_PLL_REF_DIV_4
);
break
;
default:
pr_err
(
"%s: Unexpected clock rate %ld"
,
__func__
,
c
->
rate
);
BUG
();
}
clk_writel
(
auto_clock_control
,
OSC_CTRL
);
return
c
->
rate
;
}
static
void
tegra30_clk_m_init
(
struct
clk
*
c
)
{
pr_debug
(
"%s on clock %s
\n
"
,
__func__
,
c
->
name
);
tegra30_clk_m_autodetect_rate
(
c
);
}
static
int
tegra30_clk_m_enable
(
struct
clk
*
c
)
{
pr_debug
(
"%s on clock %s
\n
"
,
__func__
,
c
->
name
);
return
0
;
}
static
void
tegra30_clk_m_disable
(
struct
clk
*
c
)
{
pr_debug
(
"%s on clock %s
\n
"
,
__func__
,
c
->
name
);
WARN
(
1
,
"Attempting to disable main SoC clock
\n
"
);
}
static
struct
clk_ops
tegra_clk_m_ops
=
{
.
init
=
tegra30_clk_m_init
,
.
enable
=
tegra30_clk_m_enable
,
.
disable
=
tegra30_clk_m_disable
,
};
static
struct
clk_ops
tegra_clk_m_div_ops
=
{
.
enable
=
tegra30_clk_m_enable
,
};
/* PLL reference divider functions */
static
void
tegra30_pll_ref_init
(
struct
clk
*
c
)
{
u32
pll_ref_div
=
clk_readl
(
OSC_CTRL
)
&
OSC_CTRL_PLL_REF_DIV_MASK
;
pr_debug
(
"%s on clock %s
\n
"
,
__func__
,
c
->
name
);
switch
(
pll_ref_div
)
{
case
OSC_CTRL_PLL_REF_DIV_1
:
c
->
div
=
1
;
break
;
case
OSC_CTRL_PLL_REF_DIV_2
:
c
->
div
=
2
;
break
;
case
OSC_CTRL_PLL_REF_DIV_4
:
c
->
div
=
4
;
break
;
default:
pr_err
(
"%s: Invalid pll ref divider %d"
,
__func__
,
pll_ref_div
);
BUG
();
}
c
->
mul
=
1
;
c
->
state
=
ON
;
}
static
struct
clk_ops
tegra_pll_ref_ops
=
{
.
init
=
tegra30_pll_ref_init
,
.
enable
=
tegra30_clk_m_enable
,
.
disable
=
tegra30_clk_m_disable
,
};
/* super clock functions */
/* "super clocks" on tegra30 have two-stage muxes, fractional 7.1 divider and
* clock skipping super divider. We will ignore the clock skipping divider,
* since we can't lower the voltage when using the clock skip, but we can if
* we lower the PLL frequency. We will use 7.1 divider for CPU super-clock
* only when its parent is a fixed rate PLL, since we can't change PLL rate
* in this case.
*/
static
void
tegra30_super_clk_init
(
struct
clk
*
c
)
{
u32
val
;
int
source
;
int
shift
;
const
struct
clk_mux_sel
*
sel
;
val
=
clk_readl
(
c
->
reg
+
SUPER_CLK_MUX
);
c
->
state
=
ON
;
BUG_ON
(((
val
&
SUPER_STATE_MASK
)
!=
SUPER_STATE_RUN
)
&&
((
val
&
SUPER_STATE_MASK
)
!=
SUPER_STATE_IDLE
));
shift
=
((
val
&
SUPER_STATE_MASK
)
==
SUPER_STATE_IDLE
)
?
SUPER_IDLE_SOURCE_SHIFT
:
SUPER_RUN_SOURCE_SHIFT
;
source
=
(
val
>>
shift
)
&
SUPER_SOURCE_MASK
;
if
(
c
->
flags
&
DIV_2
)
source
|=
val
&
SUPER_LP_DIV2_BYPASS
;
for
(
sel
=
c
->
inputs
;
sel
->
input
!=
NULL
;
sel
++
)
{
if
(
sel
->
value
==
source
)
break
;
}
BUG_ON
(
sel
->
input
==
NULL
);
c
->
parent
=
sel
->
input
;
if
(
c
->
flags
&
DIV_U71
)
{
/* Init safe 7.1 divider value (does not affect PLLX path) */
clk_writel
(
SUPER_CLOCK_DIV_U71_MIN
<<
SUPER_CLOCK_DIV_U71_SHIFT
,
c
->
reg
+
SUPER_CLK_DIVIDER
);
c
->
mul
=
2
;
c
->
div
=
2
;
if
(
!
(
c
->
parent
->
flags
&
PLLX
))
c
->
div
+=
SUPER_CLOCK_DIV_U71_MIN
;
}
else
clk_writel
(
0
,
c
->
reg
+
SUPER_CLK_DIVIDER
);
}
static
int
tegra30_super_clk_enable
(
struct
clk
*
c
)
{
return
0
;
}
static
void
tegra30_super_clk_disable
(
struct
clk
*
c
)
{
/* since tegra 3 has 2 CPU super clocks - low power lp-mode clock and
geared up g-mode super clock - mode switch may request to disable
either of them; accept request with no affect on h/w */
}
static
int
tegra30_super_clk_set_parent
(
struct
clk
*
c
,
struct
clk
*
p
)
{
u32
val
;
const
struct
clk_mux_sel
*
sel
;
int
shift
;
val
=
clk_readl
(
c
->
reg
+
SUPER_CLK_MUX
);
BUG_ON
(((
val
&
SUPER_STATE_MASK
)
!=
SUPER_STATE_RUN
)
&&
((
val
&
SUPER_STATE_MASK
)
!=
SUPER_STATE_IDLE
));
shift
=
((
val
&
SUPER_STATE_MASK
)
==
SUPER_STATE_IDLE
)
?
SUPER_IDLE_SOURCE_SHIFT
:
SUPER_RUN_SOURCE_SHIFT
;
for
(
sel
=
c
->
inputs
;
sel
->
input
!=
NULL
;
sel
++
)
{
if
(
sel
->
input
==
p
)
{
/* 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
((
c
->
flags
&
DIV_2
)
&&
(
p
->
flags
&
PLLX
)
&&
((
sel
->
value
^
val
)
&
SUPER_LP_DIV2_BYPASS
))
{
if
(
c
->
parent
->
flags
&
PLLX
)
return
-
EINVAL
;
val
^=
SUPER_LP_DIV2_BYPASS
;
clk_writel_delay
(
val
,
c
->
reg
);
}
val
&=
~
(
SUPER_SOURCE_MASK
<<
shift
);
val
|=
(
sel
->
value
&
SUPER_SOURCE_MASK
)
<<
shift
;
/* 7.1 divider for CPU super-clock does not affect
PLLX path */
if
(
c
->
flags
&
DIV_U71
)
{
u32
div
=
0
;
if
(
!
(
p
->
flags
&
PLLX
))
{
div
=
clk_readl
(
c
->
reg
+
SUPER_CLK_DIVIDER
);
div
&=
SUPER_CLOCK_DIV_U71_MASK
;
div
>>=
SUPER_CLOCK_DIV_U71_SHIFT
;
}
c
->
div
=
div
+
2
;
c
->
mul
=
2
;
}
if
(
c
->
refcnt
)
clk_enable
(
p
);
clk_writel_delay
(
val
,
c
->
reg
);
if
(
c
->
refcnt
&&
c
->
parent
)
clk_disable
(
c
->
parent
);
clk_reparent
(
c
,
p
);
return
0
;
}
}
return
-
EINVAL
;
}
/*
* Do not use super clocks "skippers", since dividing using a clock skipper
* does not allow the voltage to be scaled down. Instead adjust the rate of
* the parent clock. This requires that the parent of a super clock have no
* other children, otherwise the rate will change underneath the other
* children. Special case: if fixed rate PLL is CPU super clock parent the
* rate of this PLL can't be changed, and it has many other children. In
* this case use 7.1 fractional divider to adjust the super clock rate.
*/
static
int
tegra30_super_clk_set_rate
(
struct
clk
*
c
,
unsigned
long
rate
)
{
if
((
c
->
flags
&
DIV_U71
)
&&
(
c
->
parent
->
flags
&
PLL_FIXED
))
{
int
div
=
clk_div71_get_divider
(
c
->
parent
->
u
.
pll
.
fixed_rate
,
rate
,
c
->
flags
,
ROUND_DIVIDER_DOWN
);
div
=
max
(
div
,
SUPER_CLOCK_DIV_U71_MIN
);
clk_writel
(
div
<<
SUPER_CLOCK_DIV_U71_SHIFT
,
c
->
reg
+
SUPER_CLK_DIVIDER
);
c
->
div
=
div
+
2
;
c
->
mul
=
2
;
return
0
;
}
return
clk_set_rate
(
c
->
parent
,
rate
);
}
static
struct
clk_ops
tegra_super_ops
=
{
.
init
=
tegra30_super_clk_init
,
.
enable
=
tegra30_super_clk_enable
,
.
disable
=
tegra30_super_clk_disable
,
.
set_parent
=
tegra30_super_clk_set_parent
,
.
set_rate
=
tegra30_super_clk_set_rate
,
};
static
int
tegra30_twd_clk_set_rate
(
struct
clk
*
c
,
unsigned
long
rate
)
{
/* The input value 'rate' is the clock rate of the CPU complex. */
c
->
rate
=
(
rate
*
c
->
mul
)
/
c
->
div
;
return
0
;
}
static
struct
clk_ops
tegra30_twd_ops
=
{
.
set_rate
=
tegra30_twd_clk_set_rate
,
};
/* Blink output functions */
static
void
tegra30_blink_clk_init
(
struct
clk
*
c
)
{
u32
val
;
val
=
pmc_readl
(
PMC_CTRL
);
c
->
state
=
(
val
&
PMC_CTRL_BLINK_ENB
)
?
ON
:
OFF
;
c
->
mul
=
1
;
val
=
pmc_readl
(
c
->
reg
);
if
(
val
&
PMC_BLINK_TIMER_ENB
)
{
unsigned
int
on_off
;
on_off
=
(
val
>>
PMC_BLINK_TIMER_DATA_ON_SHIFT
)
&
PMC_BLINK_TIMER_DATA_ON_MASK
;
val
>>=
PMC_BLINK_TIMER_DATA_OFF_SHIFT
;
val
&=
PMC_BLINK_TIMER_DATA_OFF_MASK
;
on_off
+=
val
;
/* each tick in the blink timer is 4 32KHz clocks */
c
->
div
=
on_off
*
4
;
}
else
{
c
->
div
=
1
;
}
}
static
int
tegra30_blink_clk_enable
(
struct
clk
*
c
)
{
u32
val
;
val
=
pmc_readl
(
PMC_DPD_PADS_ORIDE
);
pmc_writel
(
val
|
PMC_DPD_PADS_ORIDE_BLINK_ENB
,
PMC_DPD_PADS_ORIDE
);
val
=
pmc_readl
(
PMC_CTRL
);
pmc_writel
(
val
|
PMC_CTRL_BLINK_ENB
,
PMC_CTRL
);
return
0
;
}
static
void
tegra30_blink_clk_disable
(
struct
clk
*
c
)
{
u32
val
;
val
=
pmc_readl
(
PMC_CTRL
);
pmc_writel
(
val
&
~
PMC_CTRL_BLINK_ENB
,
PMC_CTRL
);
val
=
pmc_readl
(
PMC_DPD_PADS_ORIDE
);
pmc_writel
(
val
&
~
PMC_DPD_PADS_ORIDE_BLINK_ENB
,
PMC_DPD_PADS_ORIDE
);
}
static
int
tegra30_blink_clk_set_rate
(
struct
clk
*
c
,
unsigned
long
rate
)
{
unsigned
long
parent_rate
=
clk_get_rate
(
c
->
parent
);
if
(
rate
>=
parent_rate
)
{
c
->
div
=
1
;
pmc_writel
(
0
,
c
->
reg
);
}
else
{
unsigned
int
on_off
;
u32
val
;
on_off
=
DIV_ROUND_UP
(
parent_rate
/
8
,
rate
);
c
->
div
=
on_off
*
8
;
val
=
(
on_off
&
PMC_BLINK_TIMER_DATA_ON_MASK
)
<<
PMC_BLINK_TIMER_DATA_ON_SHIFT
;
on_off
&=
PMC_BLINK_TIMER_DATA_OFF_MASK
;
on_off
<<=
PMC_BLINK_TIMER_DATA_OFF_SHIFT
;
val
|=
on_off
;
val
|=
PMC_BLINK_TIMER_ENB
;
pmc_writel
(
val
,
c
->
reg
);
}
return
0
;
}
static
struct
clk_ops
tegra_blink_clk_ops
=
{
.
init
=
&
tegra30_blink_clk_init
,
.
enable
=
&
tegra30_blink_clk_enable
,
.
disable
=
&
tegra30_blink_clk_disable
,
.
set_rate
=
&
tegra30_blink_clk_set_rate
,
};
/* PLL Functions */
static
int
tegra30_pll_clk_wait_for_lock
(
struct
clk
*
c
,
u32
lock_reg
,
u32
lock_bit
)
{
#if USE_PLL_LOCK_BITS
int
i
;
for
(
i
=
0
;
i
<
c
->
u
.
pll
.
lock_delay
;
i
++
)
{
if
(
clk_readl
(
lock_reg
)
&
lock_bit
)
{
udelay
(
PLL_POST_LOCK_DELAY
);
return
0
;
}
udelay
(
2
);
/* timeout = 2 * lock time */
}
pr_err
(
"Timed out waiting for lock bit on pll %s"
,
c
->
name
);
return
-
1
;
#endif
udelay
(
c
->
u
.
pll
.
lock_delay
);
return
0
;
}
static
void
tegra30_utmi_param_configure
(
struct
clk
*
c
)
{
u32
reg
;
int
i
;
unsigned
long
main_rate
=
clk_get_rate
(
c
->
parent
->
parent
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
utmi_parameters
);
i
++
)
{
if
(
main_rate
==
utmi_parameters
[
i
].
osc_frequency
)
break
;
}
if
(
i
>=
ARRAY_SIZE
(
utmi_parameters
))
{
pr_err
(
"%s: Unexpected main rate %lu
\n
"
,
__func__
,
main_rate
);
return
;
}
reg
=
clk_readl
(
UTMIP_PLL_CFG2
);
/* Program UTMIP PLL stable and active counts */
/* [FIXME] arclk_rst.h says WRONG! This should be 1ms -> 0x50 Check! */
reg
&=
~
UTMIP_PLL_CFG2_STABLE_COUNT
(
~
0
);
reg
|=
UTMIP_PLL_CFG2_STABLE_COUNT
(
utmi_parameters
[
i
].
stable_count
);
reg
&=
~
UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT
(
~
0
);
reg
|=
UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT
(
utmi_parameters
[
i
].
active_delay_count
);
/* Remove power downs from UTMIP PLL control bits */
reg
&=
~
UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN
;
reg
&=
~
UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN
;
reg
&=
~
UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN
;
clk_writel
(
reg
,
UTMIP_PLL_CFG2
);
/* Program UTMIP PLL delay and oscillator frequency counts */
reg
=
clk_readl
(
UTMIP_PLL_CFG1
);
reg
&=
~
UTMIP_PLL_CFG1_ENABLE_DLY_COUNT
(
~
0
);
reg
|=
UTMIP_PLL_CFG1_ENABLE_DLY_COUNT
(
utmi_parameters
[
i
].
enable_delay_count
);
reg
&=
~
UTMIP_PLL_CFG1_XTAL_FREQ_COUNT
(
~
0
);
reg
|=
UTMIP_PLL_CFG1_XTAL_FREQ_COUNT
(
utmi_parameters
[
i
].
xtal_freq_count
);
/* Remove power downs from UTMIP PLL control bits */
reg
&=
~
UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN
;
reg
&=
~
UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN
;
reg
&=
~
UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN
;
clk_writel
(
reg
,
UTMIP_PLL_CFG1
);
}
static
void
tegra30_pll_clk_init
(
struct
clk
*
c
)
{
u32
val
=
clk_readl
(
c
->
reg
+
PLL_BASE
);
c
->
state
=
(
val
&
PLL_BASE_ENABLE
)
?
ON
:
OFF
;
if
(
c
->
flags
&
PLL_FIXED
&&
!
(
val
&
PLL_BASE_OVERRIDE
))
{
const
struct
clk_pll_freq_table
*
sel
;
unsigned
long
input_rate
=
clk_get_rate
(
c
->
parent
);
for
(
sel
=
c
->
u
.
pll
.
freq_table
;
sel
->
input_rate
!=
0
;
sel
++
)
{
if
(
sel
->
input_rate
==
input_rate
&&
sel
->
output_rate
==
c
->
u
.
pll
.
fixed_rate
)
{
c
->
mul
=
sel
->
n
;
c
->
div
=
sel
->
m
*
sel
->
p
;
return
;
}
}
pr_err
(
"Clock %s has unknown fixed frequency
\n
"
,
c
->
name
);
BUG
();
}
else
if
(
val
&
PLL_BASE_BYPASS
)
{
c
->
mul
=
1
;
c
->
div
=
1
;
}
else
{
c
->
mul
=
(
val
&
PLL_BASE_DIVN_MASK
)
>>
PLL_BASE_DIVN_SHIFT
;
c
->
div
=
(
val
&
PLL_BASE_DIVM_MASK
)
>>
PLL_BASE_DIVM_SHIFT
;
if
(
c
->
flags
&
PLLU
)
c
->
div
*=
(
val
&
PLLU_BASE_POST_DIV
)
?
1
:
2
;
else
c
->
div
*=
(
0x1
<<
((
val
&
PLL_BASE_DIVP_MASK
)
>>
PLL_BASE_DIVP_SHIFT
));
if
(
c
->
flags
&
PLL_FIXED
)
{
unsigned
long
rate
=
clk_get_rate_locked
(
c
);
BUG_ON
(
rate
!=
c
->
u
.
pll
.
fixed_rate
);
}
}
if
(
c
->
flags
&
PLLU
)
tegra30_utmi_param_configure
(
c
);
}
static
int
tegra30_pll_clk_enable
(
struct
clk
*
c
)
{
u32
val
;
pr_debug
(
"%s on clock %s
\n
"
,
__func__
,
c
->
name
);
#if USE_PLL_LOCK_BITS
val
=
clk_readl
(
c
->
reg
+
PLL_MISC
(
c
));
val
|=
PLL_MISC_LOCK_ENABLE
(
c
);
clk_writel
(
val
,
c
->
reg
+
PLL_MISC
(
c
));
#endif
val
=
clk_readl
(
c
->
reg
+
PLL_BASE
);
val
&=
~
PLL_BASE_BYPASS
;
val
|=
PLL_BASE_ENABLE
;
clk_writel
(
val
,
c
->
reg
+
PLL_BASE
);
if
(
c
->
flags
&
PLLM
)
{
val
=
pmc_readl
(
PMC_PLLP_WB0_OVERRIDE
);
val
|=
PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE
;
pmc_writel
(
val
,
PMC_PLLP_WB0_OVERRIDE
);
}
tegra30_pll_clk_wait_for_lock
(
c
,
c
->
reg
+
PLL_BASE
,
PLL_BASE_LOCK
);
return
0
;
}
static
void
tegra30_pll_clk_disable
(
struct
clk
*
c
)
{
u32
val
;
pr_debug
(
"%s on clock %s
\n
"
,
__func__
,
c
->
name
);
val
=
clk_readl
(
c
->
reg
);
val
&=
~
(
PLL_BASE_BYPASS
|
PLL_BASE_ENABLE
);
clk_writel
(
val
,
c
->
reg
);
if
(
c
->
flags
&
PLLM
)
{
val
=
pmc_readl
(
PMC_PLLP_WB0_OVERRIDE
);
val
&=
~
PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE
;
pmc_writel
(
val
,
PMC_PLLP_WB0_OVERRIDE
);
}
}
static
int
tegra30_pll_clk_set_rate
(
struct
clk
*
c
,
unsigned
long
rate
)
{
u32
val
,
p_div
,
old_base
;
unsigned
long
input_rate
;
const
struct
clk_pll_freq_table
*
sel
;
struct
clk_pll_freq_table
cfg
;
pr_debug
(
"%s: %s %lu
\n
"
,
__func__
,
c
->
name
,
rate
);
if
(
c
->
flags
&
PLL_FIXED
)
{
int
ret
=
0
;
if
(
rate
!=
c
->
u
.
pll
.
fixed_rate
)
{
pr_err
(
"%s: Can not change %s fixed rate %lu to %lu
\n
"
,
__func__
,
c
->
name
,
c
->
u
.
pll
.
fixed_rate
,
rate
);
ret
=
-
EINVAL
;
}
return
ret
;
}
if
(
c
->
flags
&
PLLM
)
{
if
(
rate
!=
clk_get_rate_locked
(
c
))
{
pr_err
(
"%s: Can not change memory %s rate in flight
\n
"
,
__func__
,
c
->
name
);
return
-
EINVAL
;
}
return
0
;
}
p_div
=
0
;
input_rate
=
clk_get_rate
(
c
->
parent
);
/* Check if the target rate is tabulated */
for
(
sel
=
c
->
u
.
pll
.
freq_table
;
sel
->
input_rate
!=
0
;
sel
++
)
{
if
(
sel
->
input_rate
==
input_rate
&&
sel
->
output_rate
==
rate
)
{
if
(
c
->
flags
&
PLLU
)
{
BUG_ON
(
sel
->
p
<
1
||
sel
->
p
>
2
);
if
(
sel
->
p
==
1
)
p_div
=
PLLU_BASE_POST_DIV
;
}
else
{
BUG_ON
(
sel
->
p
<
1
);
for
(
val
=
sel
->
p
;
val
>
1
;
val
>>=
1
)
p_div
++
;
p_div
<<=
PLL_BASE_DIVP_SHIFT
;
}
break
;
}
}
/* Configure out-of-table rate */
if
(
sel
->
input_rate
==
0
)
{
unsigned
long
cfreq
;
BUG_ON
(
c
->
flags
&
PLLU
);
sel
=
&
cfg
;
switch
(
input_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
;
default:
pr_err
(
"%s: Unexpected reference rate %lu
\n
"
,
__func__
,
input_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
=
0x1
<<
p_div
;
cfg
.
m
=
input_rate
/
cfreq
;
cfg
.
n
=
cfg
.
output_rate
/
cfreq
;
cfg
.
cpcon
=
OUT_OF_TABLE_CPCON
;
if
((
cfg
.
m
>
(
PLL_BASE_DIVM_MASK
>>
PLL_BASE_DIVM_SHIFT
))
||
(
cfg
.
n
>
(
PLL_BASE_DIVN_MASK
>>
PLL_BASE_DIVN_SHIFT
))
||
(
p_div
>
(
PLL_BASE_DIVP_MASK
>>
PLL_BASE_DIVP_SHIFT
))
||
(
cfg
.
output_rate
>
c
->
u
.
pll
.
vco_max
))
{
pr_err
(
"%s: Failed to set %s out-of-table rate %lu
\n
"
,
__func__
,
c
->
name
,
rate
);
return
-
EINVAL
;
}
p_div
<<=
PLL_BASE_DIVP_SHIFT
;
}
c
->
mul
=
sel
->
n
;
c
->
div
=
sel
->
m
*
sel
->
p
;
old_base
=
val
=
clk_readl
(
c
->
reg
+
PLL_BASE
);
val
&=
~
(
PLL_BASE_DIVM_MASK
|
PLL_BASE_DIVN_MASK
|
((
c
->
flags
&
PLLU
)
?
PLLU_BASE_POST_DIV
:
PLL_BASE_DIVP_MASK
));
val
|=
(
sel
->
m
<<
PLL_BASE_DIVM_SHIFT
)
|
(
sel
->
n
<<
PLL_BASE_DIVN_SHIFT
)
|
p_div
;
if
(
val
==
old_base
)
return
0
;
if
(
c
->
state
==
ON
)
{
tegra30_pll_clk_disable
(
c
);
val
&=
~
(
PLL_BASE_BYPASS
|
PLL_BASE_ENABLE
);
}
clk_writel
(
val
,
c
->
reg
+
PLL_BASE
);
if
(
c
->
flags
&
PLL_HAS_CPCON
)
{
val
=
clk_readl
(
c
->
reg
+
PLL_MISC
(
c
));
val
&=
~
PLL_MISC_CPCON_MASK
;
val
|=
sel
->
cpcon
<<
PLL_MISC_CPCON_SHIFT
;
if
(
c
->
flags
&
(
PLLU
|
PLLD
))
{
val
&=
~
PLL_MISC_LFCON_MASK
;
if
(
sel
->
n
>=
PLLDU_LFCON_SET_DIVN
)
val
|=
0x1
<<
PLL_MISC_LFCON_SHIFT
;
}
else
if
(
c
->
flags
&
(
PLLX
|
PLLM
))
{
val
&=
~
(
0x1
<<
PLL_MISC_DCCON_SHIFT
);
if
(
rate
>=
(
c
->
u
.
pll
.
vco_max
>>
1
))
val
|=
0x1
<<
PLL_MISC_DCCON_SHIFT
;
}
clk_writel
(
val
,
c
->
reg
+
PLL_MISC
(
c
));
}
if
(
c
->
state
==
ON
)
tegra30_pll_clk_enable
(
c
);
return
0
;
}
static
struct
clk_ops
tegra_pll_ops
=
{
.
init
=
tegra30_pll_clk_init
,
.
enable
=
tegra30_pll_clk_enable
,
.
disable
=
tegra30_pll_clk_disable
,
.
set_rate
=
tegra30_pll_clk_set_rate
,
};
static
int
tegra30_plld_clk_cfg_ex
(
struct
clk
*
c
,
enum
tegra_clk_ex_param
p
,
u32
setting
)
{
u32
val
,
mask
,
reg
;
switch
(
p
)
{
case
TEGRA_CLK_PLLD_CSI_OUT_ENB
:
mask
=
PLLD_BASE_CSI_CLKENABLE
;
reg
=
c
->
reg
+
PLL_BASE
;
break
;
case
TEGRA_CLK_PLLD_DSI_OUT_ENB
:
mask
=
PLLD_MISC_DSI_CLKENABLE
;
reg
=
c
->
reg
+
PLL_MISC
(
c
);
break
;
case
TEGRA_CLK_PLLD_MIPI_MUX_SEL
:
if
(
!
(
c
->
flags
&
PLL_ALT_MISC_REG
))
{
mask
=
PLLD_BASE_DSIB_MUX_MASK
;
reg
=
c
->
reg
+
PLL_BASE
;
break
;
}
/* fall through - error since PLLD2 does not have MUX_SEL control */
default:
return
-
EINVAL
;
}
val
=
clk_readl
(
reg
);
if
(
setting
)
val
|=
mask
;
else
val
&=
~
mask
;
clk_writel
(
val
,
reg
);
return
0
;
}
static
struct
clk_ops
tegra_plld_ops
=
{
.
init
=
tegra30_pll_clk_init
,
.
enable
=
tegra30_pll_clk_enable
,
.
disable
=
tegra30_pll_clk_disable
,
.
set_rate
=
tegra30_pll_clk_set_rate
,
.
clk_cfg_ex
=
tegra30_plld_clk_cfg_ex
,
};
static
void
tegra30_plle_clk_init
(
struct
clk
*
c
)
{
u32
val
;
val
=
clk_readl
(
PLLE_AUX
);
c
->
parent
=
(
val
&
PLLE_AUX_PLLP_SEL
)
?
tegra_get_clock_by_name
(
"pll_p"
)
:
tegra_get_clock_by_name
(
"pll_ref"
);
val
=
clk_readl
(
c
->
reg
+
PLL_BASE
);
c
->
state
=
(
val
&
PLLE_BASE_ENABLE
)
?
ON
:
OFF
;
c
->
mul
=
(
val
&
PLLE_BASE_DIVN_MASK
)
>>
PLLE_BASE_DIVN_SHIFT
;
c
->
div
=
(
val
&
PLLE_BASE_DIVM_MASK
)
>>
PLLE_BASE_DIVM_SHIFT
;
c
->
div
*=
(
val
&
PLLE_BASE_DIVP_MASK
)
>>
PLLE_BASE_DIVP_SHIFT
;
}
static
void
tegra30_plle_clk_disable
(
struct
clk
*
c
)
{
u32
val
;
pr_debug
(
"%s on clock %s
\n
"
,
__func__
,
c
->
name
);
val
=
clk_readl
(
c
->
reg
+
PLL_BASE
);
val
&=
~
(
PLLE_BASE_CML_ENABLE
|
PLLE_BASE_ENABLE
);
clk_writel
(
val
,
c
->
reg
+
PLL_BASE
);
}
static
void
tegra30_plle_training
(
struct
clk
*
c
)
{
u32
val
;
/* PLLE is already disabled, and setup cleared;
* create falling edge on PLLE IDDQ input */
val
=
pmc_readl
(
PMC_SATA_PWRGT
);
val
|=
PMC_SATA_PWRGT_PLLE_IDDQ_VALUE
;
pmc_writel
(
val
,
PMC_SATA_PWRGT
);
val
=
pmc_readl
(
PMC_SATA_PWRGT
);
val
|=
PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL
;
pmc_writel
(
val
,
PMC_SATA_PWRGT
);
val
=
pmc_readl
(
PMC_SATA_PWRGT
);
val
&=
~
PMC_SATA_PWRGT_PLLE_IDDQ_VALUE
;
pmc_writel
(
val
,
PMC_SATA_PWRGT
);
do
{
val
=
clk_readl
(
c
->
reg
+
PLL_MISC
(
c
));
}
while
(
!
(
val
&
PLLE_MISC_READY
));
}
static
int
tegra30_plle_configure
(
struct
clk
*
c
,
bool
force_training
)
{
u32
val
;
const
struct
clk_pll_freq_table
*
sel
;
unsigned
long
rate
=
c
->
u
.
pll
.
fixed_rate
;
unsigned
long
input_rate
=
clk_get_rate
(
c
->
parent
);
for
(
sel
=
c
->
u
.
pll
.
freq_table
;
sel
->
input_rate
!=
0
;
sel
++
)
{
if
(
sel
->
input_rate
==
input_rate
&&
sel
->
output_rate
==
rate
)
break
;
}
if
(
sel
->
input_rate
==
0
)
return
-
ENOSYS
;
/* disable PLLE, clear setup fiels */
tegra30_plle_clk_disable
(
c
);
val
=
clk_readl
(
c
->
reg
+
PLL_MISC
(
c
));
val
&=
~
(
PLLE_MISC_LOCK_ENABLE
|
PLLE_MISC_SETUP_MASK
);
clk_writel
(
val
,
c
->
reg
+
PLL_MISC
(
c
));
/* training */
val
=
clk_readl
(
c
->
reg
+
PLL_MISC
(
c
));
if
(
force_training
||
(
!
(
val
&
PLLE_MISC_READY
)))
tegra30_plle_training
(
c
);
/* configure dividers, setup, disable SS */
val
=
clk_readl
(
c
->
reg
+
PLL_BASE
);
val
&=
~
PLLE_BASE_DIV_MASK
;
val
|=
PLLE_BASE_DIV
(
sel
->
m
,
sel
->
n
,
sel
->
p
,
sel
->
cpcon
);
clk_writel
(
val
,
c
->
reg
+
PLL_BASE
);
c
->
mul
=
sel
->
n
;
c
->
div
=
sel
->
m
*
sel
->
p
;
val
=
clk_readl
(
c
->
reg
+
PLL_MISC
(
c
));
val
|=
PLLE_MISC_SETUP_VALUE
;
val
|=
PLLE_MISC_LOCK_ENABLE
;
clk_writel
(
val
,
c
->
reg
+
PLL_MISC
(
c
));
val
=
clk_readl
(
PLLE_SS_CTRL
);
val
|=
PLLE_SS_DISABLE
;
clk_writel
(
val
,
PLLE_SS_CTRL
);
/* enable and lock PLLE*/
val
=
clk_readl
(
c
->
reg
+
PLL_BASE
);
val
|=
(
PLLE_BASE_CML_ENABLE
|
PLLE_BASE_ENABLE
);
clk_writel
(
val
,
c
->
reg
+
PLL_BASE
);
tegra30_pll_clk_wait_for_lock
(
c
,
c
->
reg
+
PLL_MISC
(
c
),
PLLE_MISC_LOCK
);
return
0
;
}
static
int
tegra30_plle_clk_enable
(
struct
clk
*
c
)
{
pr_debug
(
"%s on clock %s
\n
"
,
__func__
,
c
->
name
);
return
tegra30_plle_configure
(
c
,
!
c
->
set
);
}
static
struct
clk_ops
tegra_plle_ops
=
{
.
init
=
tegra30_plle_clk_init
,
.
enable
=
tegra30_plle_clk_enable
,
.
disable
=
tegra30_plle_clk_disable
,
};
/* Clock divider ops */
static
void
tegra30_pll_div_clk_init
(
struct
clk
*
c
)
{
if
(
c
->
flags
&
DIV_U71
)
{
u32
divu71
;
u32
val
=
clk_readl
(
c
->
reg
);
val
>>=
c
->
reg_shift
;
c
->
state
=
(
val
&
PLL_OUT_CLKEN
)
?
ON
:
OFF
;
if
(
!
(
val
&
PLL_OUT_RESET_DISABLE
))
c
->
state
=
OFF
;
divu71
=
(
val
&
PLL_OUT_RATIO_MASK
)
>>
PLL_OUT_RATIO_SHIFT
;
c
->
div
=
(
divu71
+
2
);
c
->
mul
=
2
;
}
else
if
(
c
->
flags
&
DIV_2
)
{
c
->
state
=
ON
;
if
(
c
->
flags
&
(
PLLD
|
PLLX
))
{
c
->
div
=
2
;
c
->
mul
=
1
;
}
else
BUG
();
}
else
{
c
->
state
=
ON
;
c
->
div
=
1
;
c
->
mul
=
1
;
}
}
static
int
tegra30_pll_div_clk_enable
(
struct
clk
*
c
)
{
u32
val
;
u32
new_val
;
pr_debug
(
"%s: %s
\n
"
,
__func__
,
c
->
name
);
if
(
c
->
flags
&
DIV_U71
)
{
val
=
clk_readl
(
c
->
reg
);
new_val
=
val
>>
c
->
reg_shift
;
new_val
&=
0xFFFF
;
new_val
|=
PLL_OUT_CLKEN
|
PLL_OUT_RESET_DISABLE
;
val
&=
~
(
0xFFFF
<<
c
->
reg_shift
);
val
|=
new_val
<<
c
->
reg_shift
;
clk_writel_delay
(
val
,
c
->
reg
);
return
0
;
}
else
if
(
c
->
flags
&
DIV_2
)
{
return
0
;
}
return
-
EINVAL
;
}
static
void
tegra30_pll_div_clk_disable
(
struct
clk
*
c
)
{
u32
val
;
u32
new_val
;
pr_debug
(
"%s: %s
\n
"
,
__func__
,
c
->
name
);
if
(
c
->
flags
&
DIV_U71
)
{
val
=
clk_readl
(
c
->
reg
);
new_val
=
val
>>
c
->
reg_shift
;
new_val
&=
0xFFFF
;
new_val
&=
~
(
PLL_OUT_CLKEN
|
PLL_OUT_RESET_DISABLE
);
val
&=
~
(
0xFFFF
<<
c
->
reg_shift
);
val
|=
new_val
<<
c
->
reg_shift
;
clk_writel_delay
(
val
,
c
->
reg
);
}
}
static
int
tegra30_pll_div_clk_set_rate
(
struct
clk
*
c
,
unsigned
long
rate
)
{
u32
val
;
u32
new_val
;
int
divider_u71
;
unsigned
long
parent_rate
=
clk_get_rate
(
c
->
parent
);
pr_debug
(
"%s: %s %lu
\n
"
,
__func__
,
c
->
name
,
rate
);
if
(
c
->
flags
&
DIV_U71
)
{
divider_u71
=
clk_div71_get_divider
(
parent_rate
,
rate
,
c
->
flags
,
ROUND_DIVIDER_UP
);
if
(
divider_u71
>=
0
)
{
val
=
clk_readl
(
c
->
reg
);
new_val
=
val
>>
c
->
reg_shift
;
new_val
&=
0xFFFF
;
if
(
c
->
flags
&
DIV_U71_FIXED
)
new_val
|=
PLL_OUT_OVERRIDE
;
new_val
&=
~
PLL_OUT_RATIO_MASK
;
new_val
|=
divider_u71
<<
PLL_OUT_RATIO_SHIFT
;
val
&=
~
(
0xFFFF
<<
c
->
reg_shift
);
val
|=
new_val
<<
c
->
reg_shift
;
clk_writel_delay
(
val
,
c
->
reg
);
c
->
div
=
divider_u71
+
2
;
c
->
mul
=
2
;
return
0
;
}
}
else
if
(
c
->
flags
&
DIV_2
)
return
clk_set_rate
(
c
->
parent
,
rate
*
2
);
return
-
EINVAL
;
}
static
long
tegra30_pll_div_clk_round_rate
(
struct
clk
*
c
,
unsigned
long
rate
)
{
int
divider
;
unsigned
long
parent_rate
=
clk_get_rate
(
c
->
parent
);
pr_debug
(
"%s: %s %lu
\n
"
,
__func__
,
c
->
name
,
rate
);
if
(
c
->
flags
&
DIV_U71
)
{
divider
=
clk_div71_get_divider
(
parent_rate
,
rate
,
c
->
flags
,
ROUND_DIVIDER_UP
);
if
(
divider
<
0
)
return
divider
;
return
DIV_ROUND_UP
(
parent_rate
*
2
,
divider
+
2
);
}
else
if
(
c
->
flags
&
DIV_2
)
/* no rounding - fixed DIV_2 dividers pass rate to parent PLL */
return
rate
;
return
-
EINVAL
;
}
static
struct
clk_ops
tegra_pll_div_ops
=
{
.
init
=
tegra30_pll_div_clk_init
,
.
enable
=
tegra30_pll_div_clk_enable
,
.
disable
=
tegra30_pll_div_clk_disable
,
.
set_rate
=
tegra30_pll_div_clk_set_rate
,
.
round_rate
=
tegra30_pll_div_clk_round_rate
,
};
/* Periph clk ops */
static
inline
u32
periph_clk_source_mask
(
struct
clk
*
c
)
{
if
(
c
->
flags
&
MUX8
)
return
7
<<
29
;
else
if
(
c
->
flags
&
MUX_PWM
)
return
3
<<
28
;
else
if
(
c
->
flags
&
MUX_CLK_OUT
)
return
3
<<
(
c
->
u
.
periph
.
clk_num
+
4
);
else
if
(
c
->
flags
&
PLLD
)
return
PLLD_BASE_DSIB_MUX_MASK
;
else
return
3
<<
30
;
}
static
inline
u32
periph_clk_source_shift
(
struct
clk
*
c
)
{
if
(
c
->
flags
&
MUX8
)
return
29
;
else
if
(
c
->
flags
&
MUX_PWM
)
return
28
;
else
if
(
c
->
flags
&
MUX_CLK_OUT
)
return
c
->
u
.
periph
.
clk_num
+
4
;
else
if
(
c
->
flags
&
PLLD
)
return
PLLD_BASE_DSIB_MUX_SHIFT
;
else
return
30
;
}
static
void
tegra30_periph_clk_init
(
struct
clk
*
c
)
{
u32
val
=
clk_readl
(
c
->
reg
);
const
struct
clk_mux_sel
*
mux
=
0
;
const
struct
clk_mux_sel
*
sel
;
if
(
c
->
flags
&
MUX
)
{
for
(
sel
=
c
->
inputs
;
sel
->
input
!=
NULL
;
sel
++
)
{
if
(((
val
&
periph_clk_source_mask
(
c
))
>>
periph_clk_source_shift
(
c
))
==
sel
->
value
)
mux
=
sel
;
}
BUG_ON
(
!
mux
);
c
->
parent
=
mux
->
input
;
}
else
{
c
->
parent
=
c
->
inputs
[
0
].
input
;
}
if
(
c
->
flags
&
DIV_U71
)
{
u32
divu71
=
val
&
PERIPH_CLK_SOURCE_DIVU71_MASK
;
if
((
c
->
flags
&
DIV_U71_UART
)
&&
(
!
(
val
&
PERIPH_CLK_UART_DIV_ENB
)))
{
divu71
=
0
;
}
if
(
c
->
flags
&
DIV_U71_IDLE
)
{
val
&=
~
(
PERIPH_CLK_SOURCE_DIVU71_MASK
<<
PERIPH_CLK_SOURCE_DIVIDLE_SHIFT
);
val
|=
(
PERIPH_CLK_SOURCE_DIVIDLE_VAL
<<
PERIPH_CLK_SOURCE_DIVIDLE_SHIFT
);
clk_writel
(
val
,
c
->
reg
);
}
c
->
div
=
divu71
+
2
;
c
->
mul
=
2
;
}
else
if
(
c
->
flags
&
DIV_U16
)
{
u32
divu16
=
val
&
PERIPH_CLK_SOURCE_DIVU16_MASK
;
c
->
div
=
divu16
+
1
;
c
->
mul
=
1
;
}
else
{
c
->
div
=
1
;
c
->
mul
=
1
;
}
c
->
state
=
ON
;
if
(
!
(
clk_readl
(
PERIPH_CLK_TO_ENB_REG
(
c
))
&
PERIPH_CLK_TO_BIT
(
c
)))
c
->
state
=
OFF
;
if
(
!
(
c
->
flags
&
PERIPH_NO_RESET
))
if
(
clk_readl
(
PERIPH_CLK_TO_RST_REG
(
c
))
&
PERIPH_CLK_TO_BIT
(
c
))
c
->
state
=
OFF
;
}
static
int
tegra30_periph_clk_enable
(
struct
clk
*
c
)
{
pr_debug
(
"%s on clock %s
\n
"
,
__func__
,
c
->
name
);
tegra_periph_clk_enable_refcount
[
c
->
u
.
periph
.
clk_num
]
++
;
if
(
tegra_periph_clk_enable_refcount
[
c
->
u
.
periph
.
clk_num
]
>
1
)
return
0
;
clk_writel_delay
(
PERIPH_CLK_TO_BIT
(
c
),
PERIPH_CLK_TO_ENB_SET_REG
(
c
));
if
(
!
(
c
->
flags
&
PERIPH_NO_RESET
)
&&
!
(
c
->
flags
&
PERIPH_MANUAL_RESET
))
{
if
(
clk_readl
(
PERIPH_CLK_TO_RST_REG
(
c
))
&
PERIPH_CLK_TO_BIT
(
c
))
{
udelay
(
5
);
/* reset propagation delay */
clk_writel
(
PERIPH_CLK_TO_BIT
(
c
),
PERIPH_CLK_TO_RST_CLR_REG
(
c
));
}
}
return
0
;
}
static
void
tegra30_periph_clk_disable
(
struct
clk
*
c
)
{
unsigned
long
val
;
pr_debug
(
"%s on clock %s
\n
"
,
__func__
,
c
->
name
);
if
(
c
->
refcnt
)
tegra_periph_clk_enable_refcount
[
c
->
u
.
periph
.
clk_num
]
--
;
if
(
tegra_periph_clk_enable_refcount
[
c
->
u
.
periph
.
clk_num
]
==
0
)
{
/* 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
(
c
->
flags
&
PERIPH_ON_APB
)
val
=
chipid_readl
();
clk_writel_delay
(
PERIPH_CLK_TO_BIT
(
c
),
PERIPH_CLK_TO_ENB_CLR_REG
(
c
));
}
}
static
void
tegra30_periph_clk_reset
(
struct
clk
*
c
,
bool
assert
)
{
unsigned
long
val
;
pr_debug
(
"%s %s on clock %s
\n
"
,
__func__
,
assert
?
"assert"
:
"deassert"
,
c
->
name
);
if
(
!
(
c
->
flags
&
PERIPH_NO_RESET
))
{
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
(
c
->
flags
&
PERIPH_ON_APB
)
val
=
chipid_readl
();
clk_writel
(
PERIPH_CLK_TO_BIT
(
c
),
PERIPH_CLK_TO_RST_SET_REG
(
c
));
}
else
clk_writel
(
PERIPH_CLK_TO_BIT
(
c
),
PERIPH_CLK_TO_RST_CLR_REG
(
c
));
}
}
static
int
tegra30_periph_clk_set_parent
(
struct
clk
*
c
,
struct
clk
*
p
)
{
u32
val
;
const
struct
clk_mux_sel
*
sel
;
pr_debug
(
"%s: %s %s
\n
"
,
__func__
,
c
->
name
,
p
->
name
);
if
(
!
(
c
->
flags
&
MUX
))
return
(
p
==
c
->
parent
)
?
0
:
(
-
EINVAL
);
for
(
sel
=
c
->
inputs
;
sel
->
input
!=
NULL
;
sel
++
)
{
if
(
sel
->
input
==
p
)
{
val
=
clk_readl
(
c
->
reg
);
val
&=
~
periph_clk_source_mask
(
c
);
val
|=
(
sel
->
value
<<
periph_clk_source_shift
(
c
));
if
(
c
->
refcnt
)
clk_enable
(
p
);
clk_writel_delay
(
val
,
c
->
reg
);
if
(
c
->
refcnt
&&
c
->
parent
)
clk_disable
(
c
->
parent
);
clk_reparent
(
c
,
p
);
return
0
;
}
}
return
-
EINVAL
;
}
static
int
tegra30_periph_clk_set_rate
(
struct
clk
*
c
,
unsigned
long
rate
)
{
u32
val
;
int
divider
;
unsigned
long
parent_rate
=
clk_get_rate
(
c
->
parent
);
if
(
c
->
flags
&
DIV_U71
)
{
divider
=
clk_div71_get_divider
(
parent_rate
,
rate
,
c
->
flags
,
ROUND_DIVIDER_UP
);
if
(
divider
>=
0
)
{
val
=
clk_readl
(
c
->
reg
);
val
&=
~
PERIPH_CLK_SOURCE_DIVU71_MASK
;
val
|=
divider
;
if
(
c
->
flags
&
DIV_U71_UART
)
{
if
(
divider
)
val
|=
PERIPH_CLK_UART_DIV_ENB
;
else
val
&=
~
PERIPH_CLK_UART_DIV_ENB
;
}
clk_writel_delay
(
val
,
c
->
reg
);
c
->
div
=
divider
+
2
;
c
->
mul
=
2
;
return
0
;
}
}
else
if
(
c
->
flags
&
DIV_U16
)
{
divider
=
clk_div16_get_divider
(
parent_rate
,
rate
);
if
(
divider
>=
0
)
{
val
=
clk_readl
(
c
->
reg
);
val
&=
~
PERIPH_CLK_SOURCE_DIVU16_MASK
;
val
|=
divider
;
clk_writel_delay
(
val
,
c
->
reg
);
c
->
div
=
divider
+
1
;
c
->
mul
=
1
;
return
0
;
}
}
else
if
(
parent_rate
<=
rate
)
{
c
->
div
=
1
;
c
->
mul
=
1
;
return
0
;
}
return
-
EINVAL
;
}
static
long
tegra30_periph_clk_round_rate
(
struct
clk
*
c
,
unsigned
long
rate
)
{
int
divider
;
unsigned
long
parent_rate
=
clk_get_rate
(
c
->
parent
);
pr_debug
(
"%s: %s %lu
\n
"
,
__func__
,
c
->
name
,
rate
);
if
(
c
->
flags
&
DIV_U71
)
{
divider
=
clk_div71_get_divider
(
parent_rate
,
rate
,
c
->
flags
,
ROUND_DIVIDER_UP
);
if
(
divider
<
0
)
return
divider
;
return
DIV_ROUND_UP
(
parent_rate
*
2
,
divider
+
2
);
}
else
if
(
c
->
flags
&
DIV_U16
)
{
divider
=
clk_div16_get_divider
(
parent_rate
,
rate
);
if
(
divider
<
0
)
return
divider
;
return
DIV_ROUND_UP
(
parent_rate
,
divider
+
1
);
}
return
-
EINVAL
;
}
static
struct
clk_ops
tegra_periph_clk_ops
=
{
.
init
=
&
tegra30_periph_clk_init
,
.
enable
=
&
tegra30_periph_clk_enable
,
.
disable
=
&
tegra30_periph_clk_disable
,
.
set_parent
=
&
tegra30_periph_clk_set_parent
,
.
set_rate
=
&
tegra30_periph_clk_set_rate
,
.
round_rate
=
&
tegra30_periph_clk_round_rate
,
.
reset
=
&
tegra30_periph_clk_reset
,
};
/* Periph extended clock configuration ops */
static
int
tegra30_vi_clk_cfg_ex
(
struct
clk
*
c
,
enum
tegra_clk_ex_param
p
,
u32
setting
)
{
if
(
p
==
TEGRA_CLK_VI_INP_SEL
)
{
u32
val
=
clk_readl
(
c
->
reg
);
val
&=
~
PERIPH_CLK_VI_SEL_EX_MASK
;
val
|=
(
setting
<<
PERIPH_CLK_VI_SEL_EX_SHIFT
)
&
PERIPH_CLK_VI_SEL_EX_MASK
;
clk_writel
(
val
,
c
->
reg
);
return
0
;
}
return
-
EINVAL
;
}
static
struct
clk_ops
tegra_vi_clk_ops
=
{
.
init
=
&
tegra30_periph_clk_init
,
.
enable
=
&
tegra30_periph_clk_enable
,
.
disable
=
&
tegra30_periph_clk_disable
,
.
set_parent
=
&
tegra30_periph_clk_set_parent
,
.
set_rate
=
&
tegra30_periph_clk_set_rate
,
.
round_rate
=
&
tegra30_periph_clk_round_rate
,
.
clk_cfg_ex
=
&
tegra30_vi_clk_cfg_ex
,
.
reset
=
&
tegra30_periph_clk_reset
,
};
static
int
tegra30_nand_clk_cfg_ex
(
struct
clk
*
c
,
enum
tegra_clk_ex_param
p
,
u32
setting
)
{
if
(
p
==
TEGRA_CLK_NAND_PAD_DIV2_ENB
)
{
u32
val
=
clk_readl
(
c
->
reg
);
if
(
setting
)
val
|=
PERIPH_CLK_NAND_DIV_EX_ENB
;
else
val
&=
~
PERIPH_CLK_NAND_DIV_EX_ENB
;
clk_writel
(
val
,
c
->
reg
);
return
0
;
}
return
-
EINVAL
;
}
static
struct
clk_ops
tegra_nand_clk_ops
=
{
.
init
=
&
tegra30_periph_clk_init
,
.
enable
=
&
tegra30_periph_clk_enable
,
.
disable
=
&
tegra30_periph_clk_disable
,
.
set_parent
=
&
tegra30_periph_clk_set_parent
,
.
set_rate
=
&
tegra30_periph_clk_set_rate
,
.
round_rate
=
&
tegra30_periph_clk_round_rate
,
.
clk_cfg_ex
=
&
tegra30_nand_clk_cfg_ex
,
.
reset
=
&
tegra30_periph_clk_reset
,
};
static
int
tegra30_dtv_clk_cfg_ex
(
struct
clk
*
c
,
enum
tegra_clk_ex_param
p
,
u32
setting
)
{
if
(
p
==
TEGRA_CLK_DTV_INVERT
)
{
u32
val
=
clk_readl
(
c
->
reg
);
if
(
setting
)
val
|=
PERIPH_CLK_DTV_POLARITY_INV
;
else
val
&=
~
PERIPH_CLK_DTV_POLARITY_INV
;
clk_writel
(
val
,
c
->
reg
);
return
0
;
}
return
-
EINVAL
;
}
static
struct
clk_ops
tegra_dtv_clk_ops
=
{
.
init
=
&
tegra30_periph_clk_init
,
.
enable
=
&
tegra30_periph_clk_enable
,
.
disable
=
&
tegra30_periph_clk_disable
,
.
set_parent
=
&
tegra30_periph_clk_set_parent
,
.
set_rate
=
&
tegra30_periph_clk_set_rate
,
.
round_rate
=
&
tegra30_periph_clk_round_rate
,
.
clk_cfg_ex
=
&
tegra30_dtv_clk_cfg_ex
,
.
reset
=
&
tegra30_periph_clk_reset
,
};
static
int
tegra30_dsib_clk_set_parent
(
struct
clk
*
c
,
struct
clk
*
p
)
{
const
struct
clk_mux_sel
*
sel
;
struct
clk
*
d
=
tegra_get_clock_by_name
(
"pll_d"
);
pr_debug
(
"%s: %s %s
\n
"
,
__func__
,
c
->
name
,
p
->
name
);
for
(
sel
=
c
->
inputs
;
sel
->
input
!=
NULL
;
sel
++
)
{
if
(
sel
->
input
==
p
)
{
if
(
c
->
refcnt
)
clk_enable
(
p
);
/* The DSIB parent selection bit is in PLLD base
register - can not do direct r-m-w, must be
protected by PLLD lock */
tegra_clk_cfg_ex
(
d
,
TEGRA_CLK_PLLD_MIPI_MUX_SEL
,
sel
->
value
);
if
(
c
->
refcnt
&&
c
->
parent
)
clk_disable
(
c
->
parent
);
clk_reparent
(
c
,
p
);
return
0
;
}
}
return
-
EINVAL
;
}
static
struct
clk_ops
tegra_dsib_clk_ops
=
{
.
init
=
&
tegra30_periph_clk_init
,
.
enable
=
&
tegra30_periph_clk_enable
,
.
disable
=
&
tegra30_periph_clk_disable
,
.
set_parent
=
&
tegra30_dsib_clk_set_parent
,
.
set_rate
=
&
tegra30_periph_clk_set_rate
,
.
round_rate
=
&
tegra30_periph_clk_round_rate
,
.
reset
=
&
tegra30_periph_clk_reset
,
};
/* pciex clock support only reset function */
static
struct
clk_ops
tegra_pciex_clk_ops
=
{
.
reset
=
tegra30_periph_clk_reset
,
};
/* Output clock ops */
static
DEFINE_SPINLOCK
(
clk_out_lock
);
static
void
tegra30_clk_out_init
(
struct
clk
*
c
)
{
const
struct
clk_mux_sel
*
mux
=
0
;
const
struct
clk_mux_sel
*
sel
;
u32
val
=
pmc_readl
(
c
->
reg
);
c
->
state
=
(
val
&
(
0x1
<<
c
->
u
.
periph
.
clk_num
))
?
ON
:
OFF
;
c
->
mul
=
1
;
c
->
div
=
1
;
for
(
sel
=
c
->
inputs
;
sel
->
input
!=
NULL
;
sel
++
)
{
if
(((
val
&
periph_clk_source_mask
(
c
))
>>
periph_clk_source_shift
(
c
))
==
sel
->
value
)
mux
=
sel
;
}
BUG_ON
(
!
mux
);
c
->
parent
=
mux
->
input
;
}
static
int
tegra30_clk_out_enable
(
struct
clk
*
c
)
{
u32
val
;
unsigned
long
flags
;
pr_debug
(
"%s on clock %s
\n
"
,
__func__
,
c
->
name
);
spin_lock_irqsave
(
&
clk_out_lock
,
flags
);
val
=
pmc_readl
(
c
->
reg
);
val
|=
(
0x1
<<
c
->
u
.
periph
.
clk_num
);
pmc_writel
(
val
,
c
->
reg
);
spin_unlock_irqrestore
(
&
clk_out_lock
,
flags
);
return
0
;
}
static
void
tegra30_clk_out_disable
(
struct
clk
*
c
)
{
u32
val
;
unsigned
long
flags
;
pr_debug
(
"%s on clock %s
\n
"
,
__func__
,
c
->
name
);
spin_lock_irqsave
(
&
clk_out_lock
,
flags
);
val
=
pmc_readl
(
c
->
reg
);
val
&=
~
(
0x1
<<
c
->
u
.
periph
.
clk_num
);
pmc_writel
(
val
,
c
->
reg
);
spin_unlock_irqrestore
(
&
clk_out_lock
,
flags
);
}
static
int
tegra30_clk_out_set_parent
(
struct
clk
*
c
,
struct
clk
*
p
)
{
u32
val
;
unsigned
long
flags
;
const
struct
clk_mux_sel
*
sel
;
pr_debug
(
"%s: %s %s
\n
"
,
__func__
,
c
->
name
,
p
->
name
);
for
(
sel
=
c
->
inputs
;
sel
->
input
!=
NULL
;
sel
++
)
{
if
(
sel
->
input
==
p
)
{
if
(
c
->
refcnt
)
clk_enable
(
p
);
spin_lock_irqsave
(
&
clk_out_lock
,
flags
);
val
=
pmc_readl
(
c
->
reg
);
val
&=
~
periph_clk_source_mask
(
c
);
val
|=
(
sel
->
value
<<
periph_clk_source_shift
(
c
));
pmc_writel
(
val
,
c
->
reg
);
spin_unlock_irqrestore
(
&
clk_out_lock
,
flags
);
if
(
c
->
refcnt
&&
c
->
parent
)
clk_disable
(
c
->
parent
);
clk_reparent
(
c
,
p
);
return
0
;
}
}
return
-
EINVAL
;
}
static
struct
clk_ops
tegra_clk_out_ops
=
{
.
init
=
&
tegra30_clk_out_init
,
.
enable
=
&
tegra30_clk_out_enable
,
.
disable
=
&
tegra30_clk_out_disable
,
.
set_parent
=
&
tegra30_clk_out_set_parent
,
};
/* Clock doubler ops */
static
void
tegra30_clk_double_init
(
struct
clk
*
c
)
{
u32
val
=
clk_readl
(
c
->
reg
);
c
->
mul
=
val
&
(
0x1
<<
c
->
reg_shift
)
?
1
:
2
;
c
->
div
=
1
;
c
->
state
=
ON
;
if
(
!
(
clk_readl
(
PERIPH_CLK_TO_ENB_REG
(
c
))
&
PERIPH_CLK_TO_BIT
(
c
)))
c
->
state
=
OFF
;
};
static
int
tegra30_clk_double_set_rate
(
struct
clk
*
c
,
unsigned
long
rate
)
{
u32
val
;
unsigned
long
parent_rate
=
clk_get_rate
(
c
->
parent
);
if
(
rate
==
parent_rate
)
{
val
=
clk_readl
(
c
->
reg
)
|
(
0x1
<<
c
->
reg_shift
);
clk_writel
(
val
,
c
->
reg
);
c
->
mul
=
1
;
c
->
div
=
1
;
return
0
;
}
else
if
(
rate
==
2
*
parent_rate
)
{
val
=
clk_readl
(
c
->
reg
)
&
(
~
(
0x1
<<
c
->
reg_shift
));
clk_writel
(
val
,
c
->
reg
);
c
->
mul
=
2
;
c
->
div
=
1
;
return
0
;
}
return
-
EINVAL
;
}
static
struct
clk_ops
tegra_clk_double_ops
=
{
.
init
=
&
tegra30_clk_double_init
,
.
enable
=
&
tegra30_periph_clk_enable
,
.
disable
=
&
tegra30_periph_clk_disable
,
.
set_rate
=
&
tegra30_clk_double_set_rate
,
};
/* Audio sync clock ops */
static
int
tegra30_sync_source_set_rate
(
struct
clk
*
c
,
unsigned
long
rate
)
{
c
->
rate
=
rate
;
return
0
;
}
static
struct
clk_ops
tegra_sync_source_ops
=
{
.
set_rate
=
&
tegra30_sync_source_set_rate
,
};
static
void
tegra30_audio_sync_clk_init
(
struct
clk
*
c
)
{
int
source
;
const
struct
clk_mux_sel
*
sel
;
u32
val
=
clk_readl
(
c
->
reg
);
c
->
state
=
(
val
&
AUDIO_SYNC_DISABLE_BIT
)
?
OFF
:
ON
;
source
=
val
&
AUDIO_SYNC_SOURCE_MASK
;
for
(
sel
=
c
->
inputs
;
sel
->
input
!=
NULL
;
sel
++
)
if
(
sel
->
value
==
source
)
break
;
BUG_ON
(
sel
->
input
==
NULL
);
c
->
parent
=
sel
->
input
;
}
static
int
tegra30_audio_sync_clk_enable
(
struct
clk
*
c
)
{
u32
val
=
clk_readl
(
c
->
reg
);
clk_writel
((
val
&
(
~
AUDIO_SYNC_DISABLE_BIT
)),
c
->
reg
);
return
0
;
}
static
void
tegra30_audio_sync_clk_disable
(
struct
clk
*
c
)
{
u32
val
=
clk_readl
(
c
->
reg
);
clk_writel
((
val
|
AUDIO_SYNC_DISABLE_BIT
),
c
->
reg
);
}
static
int
tegra30_audio_sync_clk_set_parent
(
struct
clk
*
c
,
struct
clk
*
p
)
{
u32
val
;
const
struct
clk_mux_sel
*
sel
;
for
(
sel
=
c
->
inputs
;
sel
->
input
!=
NULL
;
sel
++
)
{
if
(
sel
->
input
==
p
)
{
val
=
clk_readl
(
c
->
reg
);
val
&=
~
AUDIO_SYNC_SOURCE_MASK
;
val
|=
sel
->
value
;
if
(
c
->
refcnt
)
clk_enable
(
p
);
clk_writel
(
val
,
c
->
reg
);
if
(
c
->
refcnt
&&
c
->
parent
)
clk_disable
(
c
->
parent
);
clk_reparent
(
c
,
p
);
return
0
;
}
}
return
-
EINVAL
;
}
static
struct
clk_ops
tegra_audio_sync_clk_ops
=
{
.
init
=
tegra30_audio_sync_clk_init
,
.
enable
=
tegra30_audio_sync_clk_enable
,
.
disable
=
tegra30_audio_sync_clk_disable
,
.
set_parent
=
tegra30_audio_sync_clk_set_parent
,
};
/* cml0 (pcie), and cml1 (sata) clock ops */
static
void
tegra30_cml_clk_init
(
struct
clk
*
c
)
{
u32
val
=
clk_readl
(
c
->
reg
);
c
->
state
=
val
&
(
0x1
<<
c
->
u
.
periph
.
clk_num
)
?
ON
:
OFF
;
}
static
int
tegra30_cml_clk_enable
(
struct
clk
*
c
)
{
u32
val
=
clk_readl
(
c
->
reg
);
val
|=
(
0x1
<<
c
->
u
.
periph
.
clk_num
);
clk_writel
(
val
,
c
->
reg
);
return
0
;
}
static
void
tegra30_cml_clk_disable
(
struct
clk
*
c
)
{
u32
val
=
clk_readl
(
c
->
reg
);
val
&=
~
(
0x1
<<
c
->
u
.
periph
.
clk_num
);
clk_writel
(
val
,
c
->
reg
);
}
static
struct
clk_ops
tegra_cml_clk_ops
=
{
.
init
=
&
tegra30_cml_clk_init
,
.
enable
=
&
tegra30_cml_clk_enable
,
.
disable
=
&
tegra30_cml_clk_disable
,
};
/* Clock definitions */
static
struct
clk
tegra_clk_32k
=
{
.
name
=
"clk_32k"
,
.
rate
=
32768
,
.
ops
=
NULL
,
.
max_rate
=
32768
,
};
static
struct
clk
tegra_clk_m
=
{
.
name
=
"clk_m"
,
.
flags
=
ENABLE_ON_INIT
,
.
ops
=
&
tegra_clk_m_ops
,
.
reg
=
0x1fc
,
.
reg_shift
=
28
,
.
max_rate
=
48000000
,
};
static
struct
clk
tegra_clk_m_div2
=
{
.
name
=
"clk_m_div2"
,
.
ops
=
&
tegra_clk_m_div_ops
,
.
parent
=
&
tegra_clk_m
,
.
mul
=
1
,
.
div
=
2
,
.
state
=
ON
,
.
max_rate
=
24000000
,
};
static
struct
clk
tegra_clk_m_div4
=
{
.
name
=
"clk_m_div4"
,
.
ops
=
&
tegra_clk_m_div_ops
,
.
parent
=
&
tegra_clk_m
,
.
mul
=
1
,
.
div
=
4
,
.
state
=
ON
,
.
max_rate
=
12000000
,
};
static
struct
clk
tegra_pll_ref
=
{
.
name
=
"pll_ref"
,
.
flags
=
ENABLE_ON_INIT
,
.
ops
=
&
tegra_pll_ref_ops
,
.
parent
=
&
tegra_clk_m
,
.
max_rate
=
26000000
,
};
static
struct
clk_pll_freq_table
tegra_pll_c_freq_table
[]
=
{
{
12000000
,
1040000000
,
520
,
6
,
1
,
8
},
{
13000000
,
1040000000
,
480
,
6
,
1
,
8
},
{
16800000
,
1040000000
,
495
,
8
,
1
,
8
},
/* actual: 1039.5 MHz */
{
19200000
,
1040000000
,
325
,
6
,
1
,
6
},
{
26000000
,
1040000000
,
520
,
13
,
1
,
8
},
{
12000000
,
832000000
,
416
,
6
,
1
,
8
},
{
13000000
,
832000000
,
832
,
13
,
1
,
8
},
{
16800000
,
832000000
,
396
,
8
,
1
,
8
},
/* actual: 831.6 MHz */
{
19200000
,
832000000
,
260
,
6
,
1
,
8
},
{
26000000
,
832000000
,
416
,
13
,
1
,
8
},
{
12000000
,
624000000
,
624
,
12
,
1
,
8
},
{
13000000
,
624000000
,
624
,
13
,
1
,
8
},
{
16800000
,
600000000
,
520
,
14
,
1
,
8
},
{
19200000
,
624000000
,
520
,
16
,
1
,
8
},
{
26000000
,
624000000
,
624
,
26
,
1
,
8
},
{
12000000
,
600000000
,
600
,
12
,
1
,
8
},
{
13000000
,
600000000
,
600
,
13
,
1
,
8
},
{
16800000
,
600000000
,
500
,
14
,
1
,
8
},
{
19200000
,
600000000
,
375
,
12
,
1
,
6
},
{
26000000
,
600000000
,
600
,
26
,
1
,
8
},
{
12000000
,
520000000
,
520
,
12
,
1
,
8
},
{
13000000
,
520000000
,
520
,
13
,
1
,
8
},
{
16800000
,
520000000
,
495
,
16
,
1
,
8
},
/* actual: 519.75 MHz */
{
19200000
,
520000000
,
325
,
12
,
1
,
6
},
{
26000000
,
520000000
,
520
,
26
,
1
,
8
},
{
12000000
,
416000000
,
416
,
12
,
1
,
8
},
{
13000000
,
416000000
,
416
,
13
,
1
,
8
},
{
16800000
,
416000000
,
396
,
16
,
1
,
8
},
/* actual: 415.8 MHz */
{
19200000
,
416000000
,
260
,
12
,
1
,
6
},
{
26000000
,
416000000
,
416
,
26
,
1
,
8
},
{
0
,
0
,
0
,
0
,
0
,
0
},
};
static
struct
clk
tegra_pll_c
=
{
.
name
=
"pll_c"
,
.
flags
=
PLL_HAS_CPCON
,
.
ops
=
&
tegra_pll_ops
,
.
reg
=
0x80
,
.
parent
=
&
tegra_pll_ref
,
.
max_rate
=
1400000000
,
.
u
.
pll
=
{
.
input_min
=
2000000
,
.
input_max
=
31000000
,
.
cf_min
=
1000000
,
.
cf_max
=
6000000
,
.
vco_min
=
20000000
,
.
vco_max
=
1400000000
,
.
freq_table
=
tegra_pll_c_freq_table
,
.
lock_delay
=
300
,
},
};
static
struct
clk
tegra_pll_c_out1
=
{
.
name
=
"pll_c_out1"
,
.
ops
=
&
tegra_pll_div_ops
,
.
flags
=
DIV_U71
,
.
parent
=
&
tegra_pll_c
,
.
reg
=
0x84
,
.
reg_shift
=
0
,
.
max_rate
=
700000000
,
};
static
struct
clk_pll_freq_table
tegra_pll_m_freq_table
[]
=
{
{
12000000
,
666000000
,
666
,
12
,
1
,
8
},
{
13000000
,
666000000
,
666
,
13
,
1
,
8
},
{
16800000
,
666000000
,
555
,
14
,
1
,
8
},
{
19200000
,
666000000
,
555
,
16
,
1
,
8
},
{
26000000
,
666000000
,
666
,
26
,
1
,
8
},
{
12000000
,
600000000
,
600
,
12
,
1
,
8
},
{
13000000
,
600000000
,
600
,
13
,
1
,
8
},
{
16800000
,
600000000
,
500
,
14
,
1
,
8
},
{
19200000
,
600000000
,
375
,
12
,
1
,
6
},
{
26000000
,
600000000
,
600
,
26
,
1
,
8
},
{
0
,
0
,
0
,
0
,
0
,
0
},
};
static
struct
clk
tegra_pll_m
=
{
.
name
=
"pll_m"
,
.
flags
=
PLL_HAS_CPCON
|
PLLM
,
.
ops
=
&
tegra_pll_ops
,
.
reg
=
0x90
,
.
parent
=
&
tegra_pll_ref
,
.
max_rate
=
800000000
,
.
u
.
pll
=
{
.
input_min
=
2000000
,
.
input_max
=
31000000
,
.
cf_min
=
1000000
,
.
cf_max
=
6000000
,
.
vco_min
=
20000000
,
.
vco_max
=
1200000000
,
.
freq_table
=
tegra_pll_m_freq_table
,
.
lock_delay
=
300
,
},
};
static
struct
clk
tegra_pll_m_out1
=
{
.
name
=
"pll_m_out1"
,
.
ops
=
&
tegra_pll_div_ops
,
.
flags
=
DIV_U71
,
.
parent
=
&
tegra_pll_m
,
.
reg
=
0x94
,
.
reg_shift
=
0
,
.
max_rate
=
600000000
,
};
static
struct
clk_pll_freq_table
tegra_pll_p_freq_table
[]
=
{
{
12000000
,
216000000
,
432
,
12
,
2
,
8
},
{
13000000
,
216000000
,
432
,
13
,
2
,
8
},
{
16800000
,
216000000
,
360
,
14
,
2
,
8
},
{
19200000
,
216000000
,
360
,
16
,
2
,
8
},
{
26000000
,
216000000
,
432
,
26
,
2
,
8
},
{
0
,
0
,
0
,
0
,
0
,
0
},
};
static
struct
clk
tegra_pll_p
=
{
.
name
=
"pll_p"
,
.
flags
=
ENABLE_ON_INIT
|
PLL_FIXED
|
PLL_HAS_CPCON
,
.
ops
=
&
tegra_pll_ops
,
.
reg
=
0xa0
,
.
parent
=
&
tegra_pll_ref
,
.
max_rate
=
432000000
,
.
u
.
pll
=
{
.
input_min
=
2000000
,
.
input_max
=
31000000
,
.
cf_min
=
1000000
,
.
cf_max
=
6000000
,
.
vco_min
=
20000000
,
.
vco_max
=
1400000000
,
.
freq_table
=
tegra_pll_p_freq_table
,
.
lock_delay
=
300
,
.
fixed_rate
=
408000000
,
},
};
static
struct
clk
tegra_pll_p_out1
=
{
.
name
=
"pll_p_out1"
,
.
ops
=
&
tegra_pll_div_ops
,
.
flags
=
ENABLE_ON_INIT
|
DIV_U71
|
DIV_U71_FIXED
,
.
parent
=
&
tegra_pll_p
,
.
reg
=
0xa4
,
.
reg_shift
=
0
,
.
max_rate
=
432000000
,
};
static
struct
clk
tegra_pll_p_out2
=
{
.
name
=
"pll_p_out2"
,
.
ops
=
&
tegra_pll_div_ops
,
.
flags
=
ENABLE_ON_INIT
|
DIV_U71
|
DIV_U71_FIXED
,
.
parent
=
&
tegra_pll_p
,
.
reg
=
0xa4
,
.
reg_shift
=
16
,
.
max_rate
=
432000000
,
};
static
struct
clk
tegra_pll_p_out3
=
{
.
name
=
"pll_p_out3"
,
.
ops
=
&
tegra_pll_div_ops
,
.
flags
=
ENABLE_ON_INIT
|
DIV_U71
|
DIV_U71_FIXED
,
.
parent
=
&
tegra_pll_p
,
.
reg
=
0xa8
,
.
reg_shift
=
0
,
.
max_rate
=
432000000
,
};
static
struct
clk
tegra_pll_p_out4
=
{
.
name
=
"pll_p_out4"
,
.
ops
=
&
tegra_pll_div_ops
,
.
flags
=
ENABLE_ON_INIT
|
DIV_U71
|
DIV_U71_FIXED
,
.
parent
=
&
tegra_pll_p
,
.
reg
=
0xa8
,
.
reg_shift
=
16
,
.
max_rate
=
432000000
,
};
static
struct
clk_pll_freq_table
tegra_pll_a_freq_table
[]
=
{
{
9600000
,
564480000
,
294
,
5
,
1
,
4
},
{
9600000
,
552960000
,
288
,
5
,
1
,
4
},
{
9600000
,
24000000
,
5
,
2
,
1
,
1
},
{
28800000
,
56448000
,
49
,
25
,
1
,
1
},
{
28800000
,
73728000
,
64
,
25
,
1
,
1
},
{
28800000
,
24000000
,
5
,
6
,
1
,
1
},
{
0
,
0
,
0
,
0
,
0
,
0
},
};
static
struct
clk
tegra_pll_a
=
{
.
name
=
"pll_a"
,
.
flags
=
PLL_HAS_CPCON
,
.
ops
=
&
tegra_pll_ops
,
.
reg
=
0xb0
,
.
parent
=
&
tegra_pll_p_out1
,
.
max_rate
=
700000000
,
.
u
.
pll
=
{
.
input_min
=
2000000
,
.
input_max
=
31000000
,
.
cf_min
=
1000000
,
.
cf_max
=
6000000
,
.
vco_min
=
20000000
,
.
vco_max
=
1400000000
,
.
freq_table
=
tegra_pll_a_freq_table
,
.
lock_delay
=
300
,
},
};
static
struct
clk
tegra_pll_a_out0
=
{
.
name
=
"pll_a_out0"
,
.
ops
=
&
tegra_pll_div_ops
,
.
flags
=
DIV_U71
,
.
parent
=
&
tegra_pll_a
,
.
reg
=
0xb4
,
.
reg_shift
=
0
,
.
max_rate
=
100000000
,
};
static
struct
clk_pll_freq_table
tegra_pll_d_freq_table
[]
=
{
{
12000000
,
216000000
,
216
,
12
,
1
,
4
},
{
13000000
,
216000000
,
216
,
13
,
1
,
4
},
{
16800000
,
216000000
,
180
,
14
,
1
,
4
},
{
19200000
,
216000000
,
180
,
16
,
1
,
4
},
{
26000000
,
216000000
,
216
,
26
,
1
,
4
},
{
12000000
,
594000000
,
594
,
12
,
1
,
8
},
{
13000000
,
594000000
,
594
,
13
,
1
,
8
},
{
16800000
,
594000000
,
495
,
14
,
1
,
8
},
{
19200000
,
594000000
,
495
,
16
,
1
,
8
},
{
26000000
,
594000000
,
594
,
26
,
1
,
8
},
{
12000000
,
1000000000
,
1000
,
12
,
1
,
12
},
{
13000000
,
1000000000
,
1000
,
13
,
1
,
12
},
{
19200000
,
1000000000
,
625
,
12
,
1
,
8
},
{
26000000
,
1000000000
,
1000
,
26
,
1
,
12
},
{
0
,
0
,
0
,
0
,
0
,
0
},
};
static
struct
clk
tegra_pll_d
=
{
.
name
=
"pll_d"
,
.
flags
=
PLL_HAS_CPCON
|
PLLD
,
.
ops
=
&
tegra_plld_ops
,
.
reg
=
0xd0
,
.
parent
=
&
tegra_pll_ref
,
.
max_rate
=
1000000000
,
.
u
.
pll
=
{
.
input_min
=
2000000
,
.
input_max
=
40000000
,
.
cf_min
=
1000000
,
.
cf_max
=
6000000
,
.
vco_min
=
40000000
,
.
vco_max
=
1000000000
,
.
freq_table
=
tegra_pll_d_freq_table
,
.
lock_delay
=
1000
,
},
};
static
struct
clk
tegra_pll_d_out0
=
{
.
name
=
"pll_d_out0"
,
.
ops
=
&
tegra_pll_div_ops
,
.
flags
=
DIV_2
|
PLLD
,
.
parent
=
&
tegra_pll_d
,
.
max_rate
=
500000000
,
};
static
struct
clk
tegra_pll_d2
=
{
.
name
=
"pll_d2"
,
.
flags
=
PLL_HAS_CPCON
|
PLL_ALT_MISC_REG
|
PLLD
,
.
ops
=
&
tegra_plld_ops
,
.
reg
=
0x4b8
,
.
parent
=
&
tegra_pll_ref
,
.
max_rate
=
1000000000
,
.
u
.
pll
=
{
.
input_min
=
2000000
,
.
input_max
=
40000000
,
.
cf_min
=
1000000
,
.
cf_max
=
6000000
,
.
vco_min
=
40000000
,
.
vco_max
=
1000000000
,
.
freq_table
=
tegra_pll_d_freq_table
,
.
lock_delay
=
1000
,
},
};
static
struct
clk
tegra_pll_d2_out0
=
{
.
name
=
"pll_d2_out0"
,
.
ops
=
&
tegra_pll_div_ops
,
.
flags
=
DIV_2
|
PLLD
,
.
parent
=
&
tegra_pll_d2
,
.
max_rate
=
500000000
,
};
static
struct
clk_pll_freq_table
tegra_pll_u_freq_table
[]
=
{
{
12000000
,
480000000
,
960
,
12
,
2
,
12
},
{
13000000
,
480000000
,
960
,
13
,
2
,
12
},
{
16800000
,
480000000
,
400
,
7
,
2
,
5
},
{
19200000
,
480000000
,
200
,
4
,
2
,
3
},
{
26000000
,
480000000
,
960
,
26
,
2
,
12
},
{
0
,
0
,
0
,
0
,
0
,
0
},
};
static
struct
clk
tegra_pll_u
=
{
.
name
=
"pll_u"
,
.
flags
=
PLL_HAS_CPCON
|
PLLU
,
.
ops
=
&
tegra_pll_ops
,
.
reg
=
0xc0
,
.
parent
=
&
tegra_pll_ref
,
.
max_rate
=
480000000
,
.
u
.
pll
=
{
.
input_min
=
2000000
,
.
input_max
=
40000000
,
.
cf_min
=
1000000
,
.
cf_max
=
6000000
,
.
vco_min
=
480000000
,
.
vco_max
=
960000000
,
.
freq_table
=
tegra_pll_u_freq_table
,
.
lock_delay
=
1000
,
},
};
static
struct
clk_pll_freq_table
tegra_pll_x_freq_table
[]
=
{
/* 1.7 GHz */
{
12000000
,
1700000000
,
850
,
6
,
1
,
8
},
{
13000000
,
1700000000
,
915
,
7
,
1
,
8
},
/* actual: 1699.2 MHz */
{
16800000
,
1700000000
,
708
,
7
,
1
,
8
},
/* actual: 1699.2 MHz */
{
19200000
,
1700000000
,
885
,
10
,
1
,
8
},
/* actual: 1699.2 MHz */
{
26000000
,
1700000000
,
850
,
13
,
1
,
8
},
/* 1.6 GHz */
{
12000000
,
1600000000
,
800
,
6
,
1
,
8
},
{
13000000
,
1600000000
,
738
,
6
,
1
,
8
},
/* actual: 1599.0 MHz */
{
16800000
,
1600000000
,
857
,
9
,
1
,
8
},
/* actual: 1599.7 MHz */
{
19200000
,
1600000000
,
500
,
6
,
1
,
8
},
{
26000000
,
1600000000
,
800
,
13
,
1
,
8
},
/* 1.5 GHz */
{
12000000
,
1500000000
,
750
,
6
,
1
,
8
},
{
13000000
,
1500000000
,
923
,
8
,
1
,
8
},
/* actual: 1499.8 MHz */
{
16800000
,
1500000000
,
625
,
7
,
1
,
8
},
{
19200000
,
1500000000
,
625
,
8
,
1
,
8
},
{
26000000
,
1500000000
,
750
,
13
,
1
,
8
},
/* 1.4 GHz */
{
12000000
,
1400000000
,
700
,
6
,
1
,
8
},
{
13000000
,
1400000000
,
969
,
9
,
1
,
8
},
/* actual: 1399.7 MHz */
{
16800000
,
1400000000
,
1000
,
12
,
1
,
8
},
{
19200000
,
1400000000
,
875
,
12
,
1
,
8
},
{
26000000
,
1400000000
,
700
,
13
,
1
,
8
},
/* 1.3 GHz */
{
12000000
,
1300000000
,
975
,
9
,
1
,
8
},
{
13000000
,
1300000000
,
1000
,
10
,
1
,
8
},
{
16800000
,
1300000000
,
928
,
12
,
1
,
8
},
/* actual: 1299.2 MHz */
{
19200000
,
1300000000
,
812
,
12
,
1
,
8
},
/* actual: 1299.2 MHz */
{
26000000
,
1300000000
,
650
,
13
,
1
,
8
},
/* 1.2 GHz */
{
12000000
,
1200000000
,
1000
,
10
,
1
,
8
},
{
13000000
,
1200000000
,
923
,
10
,
1
,
8
},
/* actual: 1199.9 MHz */
{
16800000
,
1200000000
,
1000
,
14
,
1
,
8
},
{
19200000
,
1200000000
,
1000
,
16
,
1
,
8
},
{
26000000
,
1200000000
,
600
,
13
,
1
,
8
},
/* 1.1 GHz */
{
12000000
,
1100000000
,
825
,
9
,
1
,
8
},
{
13000000
,
1100000000
,
846
,
10
,
1
,
8
},
/* actual: 1099.8 MHz */
{
16800000
,
1100000000
,
982
,
15
,
1
,
8
},
/* actual: 1099.8 MHz */
{
19200000
,
1100000000
,
859
,
15
,
1
,
8
},
/* actual: 1099.5 MHz */
{
26000000
,
1100000000
,
550
,
13
,
1
,
8
},
/* 1 GHz */
{
12000000
,
1000000000
,
1000
,
12
,
1
,
8
},
{
13000000
,
1000000000
,
1000
,
13
,
1
,
8
},
{
16800000
,
1000000000
,
833
,
14
,
1
,
8
},
/* actual: 999.6 MHz */
{
19200000
,
1000000000
,
625
,
12
,
1
,
8
},
{
26000000
,
1000000000
,
1000
,
26
,
1
,
8
},
{
0
,
0
,
0
,
0
,
0
,
0
},
};
static
struct
clk
tegra_pll_x
=
{
.
name
=
"pll_x"
,
.
flags
=
PLL_HAS_CPCON
|
PLL_ALT_MISC_REG
|
PLLX
,
.
ops
=
&
tegra_pll_ops
,
.
reg
=
0xe0
,
.
parent
=
&
tegra_pll_ref
,
.
max_rate
=
1700000000
,
.
u
.
pll
=
{
.
input_min
=
2000000
,
.
input_max
=
31000000
,
.
cf_min
=
1000000
,
.
cf_max
=
6000000
,
.
vco_min
=
20000000
,
.
vco_max
=
1700000000
,
.
freq_table
=
tegra_pll_x_freq_table
,
.
lock_delay
=
300
,
},
};
static
struct
clk
tegra_pll_x_out0
=
{
.
name
=
"pll_x_out0"
,
.
ops
=
&
tegra_pll_div_ops
,
.
flags
=
DIV_2
|
PLLX
,
.
parent
=
&
tegra_pll_x
,
.
max_rate
=
850000000
,
};
static
struct
clk_pll_freq_table
tegra_pll_e_freq_table
[]
=
{
/* PLLE special case: use cpcon field to store cml divider value */
{
12000000
,
100000000
,
150
,
1
,
18
,
11
},
{
216000000
,
100000000
,
200
,
18
,
24
,
13
},
{
0
,
0
,
0
,
0
,
0
,
0
},
};
static
struct
clk
tegra_pll_e
=
{
.
name
=
"pll_e"
,
.
flags
=
PLL_ALT_MISC_REG
,
.
ops
=
&
tegra_plle_ops
,
.
reg
=
0xe8
,
.
max_rate
=
100000000
,
.
u
.
pll
=
{
.
input_min
=
12000000
,
.
input_max
=
216000000
,
.
cf_min
=
12000000
,
.
cf_max
=
12000000
,
.
vco_min
=
1200000000
,
.
vco_max
=
2400000000U
,
.
freq_table
=
tegra_pll_e_freq_table
,
.
lock_delay
=
300
,
.
fixed_rate
=
100000000
,
},
};
static
struct
clk
tegra_cml0_clk
=
{
.
name
=
"cml0"
,
.
parent
=
&
tegra_pll_e
,
.
ops
=
&
tegra_cml_clk_ops
,
.
reg
=
PLLE_AUX
,
.
max_rate
=
100000000
,
.
u
.
periph
=
{
.
clk_num
=
0
,
},
};
static
struct
clk
tegra_cml1_clk
=
{
.
name
=
"cml1"
,
.
parent
=
&
tegra_pll_e
,
.
ops
=
&
tegra_cml_clk_ops
,
.
reg
=
PLLE_AUX
,
.
max_rate
=
100000000
,
.
u
.
periph
=
{
.
clk_num
=
1
,
},
};
static
struct
clk
tegra_pciex_clk
=
{
.
name
=
"pciex"
,
.
parent
=
&
tegra_pll_e
,
.
ops
=
&
tegra_pciex_clk_ops
,
.
max_rate
=
100000000
,
.
u
.
periph
=
{
.
clk_num
=
74
,
},
};
/* Audio sync clocks */
#define SYNC_SOURCE(_id) \
{ \
.name = #_id "_sync", \
.rate = 24000000, \
.max_rate = 24000000, \
.ops = &tegra_sync_source_ops \
}
static
struct
clk
tegra_sync_source_list
[]
=
{
SYNC_SOURCE
(
spdif_in
),
SYNC_SOURCE
(
i2s0
),
SYNC_SOURCE
(
i2s1
),
SYNC_SOURCE
(
i2s2
),
SYNC_SOURCE
(
i2s3
),
SYNC_SOURCE
(
i2s4
),
SYNC_SOURCE
(
vimclk
),
};
static
struct
clk_mux_sel
mux_audio_sync_clk
[]
=
{
{
.
input
=
&
tegra_sync_source_list
[
0
],
.
value
=
0
},
{
.
input
=
&
tegra_sync_source_list
[
1
],
.
value
=
1
},
{
.
input
=
&
tegra_sync_source_list
[
2
],
.
value
=
2
},
{
.
input
=
&
tegra_sync_source_list
[
3
],
.
value
=
3
},
{
.
input
=
&
tegra_sync_source_list
[
4
],
.
value
=
4
},
{
.
input
=
&
tegra_sync_source_list
[
5
],
.
value
=
5
},
{
.
input
=
&
tegra_pll_a_out0
,
.
value
=
6
},
{
.
input
=
&
tegra_sync_source_list
[
6
],
.
value
=
7
},
{
0
,
0
}
};
#define AUDIO_SYNC_CLK(_id, _index) \
{ \
.name = #_id, \
.inputs = mux_audio_sync_clk, \
.reg = 0x4A0 + (_index) * 4, \
.max_rate = 24000000, \
.ops = &tegra_audio_sync_clk_ops \
}
static
struct
clk
tegra_clk_audio_list
[]
=
{
AUDIO_SYNC_CLK
(
audio0
,
0
),
AUDIO_SYNC_CLK
(
audio1
,
1
),
AUDIO_SYNC_CLK
(
audio2
,
2
),
AUDIO_SYNC_CLK
(
audio3
,
3
),
AUDIO_SYNC_CLK
(
audio4
,
4
),
AUDIO_SYNC_CLK
(
audio
,
5
),
/* SPDIF */
};
#define AUDIO_SYNC_2X_CLK(_id, _index) \
{ \
.name = #_id "_2x", \
.flags = PERIPH_NO_RESET, \
.max_rate = 48000000, \
.ops = &tegra_clk_double_ops, \
.reg = 0x49C, \
.reg_shift = 24 + (_index), \
.parent = &tegra_clk_audio_list[(_index)], \
.u.periph = { \
.clk_num = 113 + (_index), \
}, \
}
static
struct
clk
tegra_clk_audio_2x_list
[]
=
{
AUDIO_SYNC_2X_CLK
(
audio0
,
0
),
AUDIO_SYNC_2X_CLK
(
audio1
,
1
),
AUDIO_SYNC_2X_CLK
(
audio2
,
2
),
AUDIO_SYNC_2X_CLK
(
audio3
,
3
),
AUDIO_SYNC_2X_CLK
(
audio4
,
4
),
AUDIO_SYNC_2X_CLK
(
audio
,
5
),
/* SPDIF */
};
#define MUX_I2S_SPDIF(_id, _index) \
static struct clk_mux_sel mux_pllaout0_##_id##_2x_pllp_clkm[] = { \
{.input = &tegra_pll_a_out0, .value = 0}, \
{.input = &tegra_clk_audio_2x_list[(_index)], .value = 1}, \
{.input = &tegra_pll_p, .value = 2}, \
{.input = &tegra_clk_m, .value = 3}, \
{ 0, 0}, \
}
MUX_I2S_SPDIF
(
audio0
,
0
);
MUX_I2S_SPDIF
(
audio1
,
1
);
MUX_I2S_SPDIF
(
audio2
,
2
);
MUX_I2S_SPDIF
(
audio3
,
3
);
MUX_I2S_SPDIF
(
audio4
,
4
);
MUX_I2S_SPDIF
(
audio
,
5
);
/* SPDIF */
/* External clock outputs (through PMC) */
#define MUX_EXTERN_OUT(_id) \
static struct clk_mux_sel mux_clkm_clkm2_clkm4_extern##_id[] = { \
{.input = &tegra_clk_m, .value = 0}, \
{.input = &tegra_clk_m_div2, .value = 1}, \
{.input = &tegra_clk_m_div4, .value = 2}, \
{.input = NULL, .value = 3},
/* placeholder */
\
{ 0, 0}, \
}
MUX_EXTERN_OUT
(
1
);
MUX_EXTERN_OUT
(
2
);
MUX_EXTERN_OUT
(
3
);
static
struct
clk_mux_sel
*
mux_extern_out_list
[]
=
{
mux_clkm_clkm2_clkm4_extern1
,
mux_clkm_clkm2_clkm4_extern2
,
mux_clkm_clkm2_clkm4_extern3
,
};
#define CLK_OUT_CLK(_id) \
{ \
.name = "clk_out_" #_id, \
.lookup = { \
.dev_id = "clk_out_" #_id, \
.con_id = "extern" #_id, \
}, \
.ops = &tegra_clk_out_ops, \
.reg = 0x1a8, \
.inputs = mux_clkm_clkm2_clkm4_extern##_id, \
.flags = MUX_CLK_OUT, \
.max_rate = 216000000, \
.u.periph = { \
.clk_num = (_id - 1) * 8 + 2, \
}, \
}
static
struct
clk
tegra_clk_out_list
[]
=
{
CLK_OUT_CLK
(
1
),
CLK_OUT_CLK
(
2
),
CLK_OUT_CLK
(
3
),
};
/* called after peripheral external clocks are initialized */
static
void
init_clk_out_mux
(
void
)
{
int
i
;
struct
clk
*
c
;
/* output clock con_id is the name of peripheral
external clock connected to input 3 of the output mux */
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
tegra_clk_out_list
);
i
++
)
{
c
=
tegra_get_clock_by_name
(
tegra_clk_out_list
[
i
].
lookup
.
con_id
);
if
(
!
c
)
pr_err
(
"%s: could not find clk %s
\n
"
,
__func__
,
tegra_clk_out_list
[
i
].
lookup
.
con_id
);
mux_extern_out_list
[
i
][
3
].
input
=
c
;
}
}
/* Peripheral muxes */
static
struct
clk_mux_sel
mux_sclk
[]
=
{
{
.
input
=
&
tegra_clk_m
,
.
value
=
0
},
{
.
input
=
&
tegra_pll_c_out1
,
.
value
=
1
},
{
.
input
=
&
tegra_pll_p_out4
,
.
value
=
2
},
{
.
input
=
&
tegra_pll_p_out3
,
.
value
=
3
},
{
.
input
=
&
tegra_pll_p_out2
,
.
value
=
4
},
/* { .input = &tegra_clk_d, .value = 5}, - no use on tegra30 */
{
.
input
=
&
tegra_clk_32k
,
.
value
=
6
},
{
.
input
=
&
tegra_pll_m_out1
,
.
value
=
7
},
{
0
,
0
},
};
static
struct
clk
tegra_clk_sclk
=
{
.
name
=
"sclk"
,
.
inputs
=
mux_sclk
,
.
reg
=
0x28
,
.
ops
=
&
tegra_super_ops
,
.
max_rate
=
334000000
,
.
min_rate
=
40000000
,
};
static
struct
clk
tegra_clk_blink
=
{
.
name
=
"blink"
,
.
parent
=
&
tegra_clk_32k
,
.
reg
=
0x40
,
.
ops
=
&
tegra_blink_clk_ops
,
.
max_rate
=
32768
,
};
static
struct
clk_mux_sel
mux_pllm_pllc_pllp_plla
[]
=
{
{
.
input
=
&
tegra_pll_m
,
.
value
=
0
},
{
.
input
=
&
tegra_pll_c
,
.
value
=
1
},
{
.
input
=
&
tegra_pll_p
,
.
value
=
2
},
{
.
input
=
&
tegra_pll_a_out0
,
.
value
=
3
},
{
0
,
0
},
};
static
struct
clk_mux_sel
mux_pllp_pllc_pllm_clkm
[]
=
{
{
.
input
=
&
tegra_pll_p
,
.
value
=
0
},
{
.
input
=
&
tegra_pll_c
,
.
value
=
1
},
{
.
input
=
&
tegra_pll_m
,
.
value
=
2
},
{
.
input
=
&
tegra_clk_m
,
.
value
=
3
},
{
0
,
0
},
};
static
struct
clk_mux_sel
mux_pllp_clkm
[]
=
{
{
.
input
=
&
tegra_pll_p
,
.
value
=
0
},
{
.
input
=
&
tegra_clk_m
,
.
value
=
3
},
{
0
,
0
},
};
static
struct
clk_mux_sel
mux_pllp_plld_pllc_clkm
[]
=
{
{.
input
=
&
tegra_pll_p
,
.
value
=
0
},
{.
input
=
&
tegra_pll_d_out0
,
.
value
=
1
},
{.
input
=
&
tegra_pll_c
,
.
value
=
2
},
{.
input
=
&
tegra_clk_m
,
.
value
=
3
},
{
0
,
0
},
};
static
struct
clk_mux_sel
mux_pllp_pllm_plld_plla_pllc_plld2_clkm
[]
=
{
{.
input
=
&
tegra_pll_p
,
.
value
=
0
},
{.
input
=
&
tegra_pll_m
,
.
value
=
1
},
{.
input
=
&
tegra_pll_d_out0
,
.
value
=
2
},
{.
input
=
&
tegra_pll_a_out0
,
.
value
=
3
},
{.
input
=
&
tegra_pll_c
,
.
value
=
4
},
{.
input
=
&
tegra_pll_d2_out0
,
.
value
=
5
},
{.
input
=
&
tegra_clk_m
,
.
value
=
6
},
{
0
,
0
},
};
static
struct
clk_mux_sel
mux_plla_pllc_pllp_clkm
[]
=
{
{
.
input
=
&
tegra_pll_a_out0
,
.
value
=
0
},
/* { .input = &tegra_pll_c, .value = 1}, no use on tegra30 */
{
.
input
=
&
tegra_pll_p
,
.
value
=
2
},
{
.
input
=
&
tegra_clk_m
,
.
value
=
3
},
{
0
,
0
},
};
static
struct
clk_mux_sel
mux_pllp_pllc_clk32_clkm
[]
=
{
{.
input
=
&
tegra_pll_p
,
.
value
=
0
},
{.
input
=
&
tegra_pll_c
,
.
value
=
1
},
{.
input
=
&
tegra_clk_32k
,
.
value
=
2
},
{.
input
=
&
tegra_clk_m
,
.
value
=
3
},
{
0
,
0
},
};
static
struct
clk_mux_sel
mux_pllp_pllc_clkm_clk32
[]
=
{
{.
input
=
&
tegra_pll_p
,
.
value
=
0
},
{.
input
=
&
tegra_pll_c
,
.
value
=
1
},
{.
input
=
&
tegra_clk_m
,
.
value
=
2
},
{.
input
=
&
tegra_clk_32k
,
.
value
=
3
},
{
0
,
0
},
};
static
struct
clk_mux_sel
mux_pllp_pllc_pllm
[]
=
{
{.
input
=
&
tegra_pll_p
,
.
value
=
0
},
{.
input
=
&
tegra_pll_c
,
.
value
=
1
},
{.
input
=
&
tegra_pll_m
,
.
value
=
2
},
{
0
,
0
},
};
static
struct
clk_mux_sel
mux_clk_m
[]
=
{
{
.
input
=
&
tegra_clk_m
,
.
value
=
0
},
{
0
,
0
},
};
static
struct
clk_mux_sel
mux_pllp_out3
[]
=
{
{
.
input
=
&
tegra_pll_p_out3
,
.
value
=
0
},
{
0
,
0
},
};
static
struct
clk_mux_sel
mux_plld_out0
[]
=
{
{
.
input
=
&
tegra_pll_d_out0
,
.
value
=
0
},
{
0
,
0
},
};
static
struct
clk_mux_sel
mux_plld_out0_plld2_out0
[]
=
{
{
.
input
=
&
tegra_pll_d_out0
,
.
value
=
0
},
{
.
input
=
&
tegra_pll_d2_out0
,
.
value
=
1
},
{
0
,
0
},
};
static
struct
clk_mux_sel
mux_clk_32k
[]
=
{
{
.
input
=
&
tegra_clk_32k
,
.
value
=
0
},
{
0
,
0
},
};
static
struct
clk_mux_sel
mux_plla_clk32_pllp_clkm_plle
[]
=
{
{
.
input
=
&
tegra_pll_a_out0
,
.
value
=
0
},
{
.
input
=
&
tegra_clk_32k
,
.
value
=
1
},
{
.
input
=
&
tegra_pll_p
,
.
value
=
2
},
{
.
input
=
&
tegra_clk_m
,
.
value
=
3
},
{
.
input
=
&
tegra_pll_e
,
.
value
=
4
},
{
0
,
0
},
};
static
struct
clk_mux_sel
mux_cclk_g
[]
=
{
{
.
input
=
&
tegra_clk_m
,
.
value
=
0
},
{
.
input
=
&
tegra_pll_c
,
.
value
=
1
},
{
.
input
=
&
tegra_clk_32k
,
.
value
=
2
},
{
.
input
=
&
tegra_pll_m
,
.
value
=
3
},
{
.
input
=
&
tegra_pll_p
,
.
value
=
4
},
{
.
input
=
&
tegra_pll_p_out4
,
.
value
=
5
},
{
.
input
=
&
tegra_pll_p_out3
,
.
value
=
6
},
{
.
input
=
&
tegra_pll_x
,
.
value
=
8
},
{
0
,
0
},
};
static
struct
clk
tegra_clk_cclk_g
=
{
.
name
=
"cclk_g"
,
.
flags
=
DIV_U71
|
DIV_U71_INT
,
.
inputs
=
mux_cclk_g
,
.
reg
=
0x368
,
.
ops
=
&
tegra_super_ops
,
.
max_rate
=
1700000000
,
};
static
struct
clk
tegra30_clk_twd
=
{
.
parent
=
&
tegra_clk_cclk_g
,
.
name
=
"twd"
,
.
ops
=
&
tegra30_twd_ops
,
.
max_rate
=
1400000000
,
/* Same as tegra_clk_cpu_cmplx.max_rate */
.
mul
=
1
,
.
div
=
2
,
};
#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \
{ \
.name = _name, \
.lookup = { \
.dev_id = _dev, \
.con_id = _con, \
}, \
.ops = &tegra_periph_clk_ops, \
.reg = _reg, \
.inputs = _inputs, \
.flags = _flags, \
.max_rate = _max, \
.u.periph = { \
.clk_num = _clk_num, \
}, \
}
#define PERIPH_CLK_EX(_name, _dev, _con, _clk_num, _reg, _max, _inputs, \
_flags, _ops) \
{ \
.name = _name, \
.lookup = { \
.dev_id = _dev, \
.con_id = _con, \
}, \
.ops = _ops, \
.reg = _reg, \
.inputs = _inputs, \
.flags = _flags, \
.max_rate = _max, \
.u.periph = { \
.clk_num = _clk_num, \
}, \
}
#define SHARED_CLK(_name, _dev, _con, _parent, _id, _div, _mode)\
{ \
.name = _name, \
.lookup = { \
.dev_id = _dev, \
.con_id = _con, \
}, \
.ops = &tegra_clk_shared_bus_ops, \
.parent = _parent, \
.u.shared_bus_user = { \
.client_id = _id, \
.client_div = _div, \
.mode = _mode, \
}, \
}
struct
clk
tegra_list_clks
[]
=
{
PERIPH_CLK
(
"apbdma"
,
"tegra-dma"
,
NULL
,
34
,
0
,
26000000
,
mux_clk_m
,
0
),
PERIPH_CLK
(
"rtc"
,
"rtc-tegra"
,
NULL
,
4
,
0
,
32768
,
mux_clk_32k
,
PERIPH_NO_RESET
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"kbc"
,
"tegra-kbc"
,
NULL
,
36
,
0
,
32768
,
mux_clk_32k
,
PERIPH_NO_RESET
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"timer"
,
"timer"
,
NULL
,
5
,
0
,
26000000
,
mux_clk_m
,
0
),
PERIPH_CLK
(
"kfuse"
,
"kfuse-tegra"
,
NULL
,
40
,
0
,
26000000
,
mux_clk_m
,
0
),
PERIPH_CLK
(
"fuse"
,
"fuse-tegra"
,
"fuse"
,
39
,
0
,
26000000
,
mux_clk_m
,
PERIPH_ON_APB
),
PERIPH_CLK
(
"fuse_burn"
,
"fuse-tegra"
,
"fuse_burn"
,
39
,
0
,
26000000
,
mux_clk_m
,
PERIPH_ON_APB
),
PERIPH_CLK
(
"apbif"
,
"tegra30-ahub"
,
"apbif"
,
107
,
0
,
26000000
,
mux_clk_m
,
0
),
PERIPH_CLK
(
"i2s0"
,
"tegra30-i2s.0"
,
NULL
,
30
,
0x1d8
,
26000000
,
mux_pllaout0_audio0_2x_pllp_clkm
,
MUX
|
DIV_U71
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"i2s1"
,
"tegra30-i2s.1"
,
NULL
,
11
,
0x100
,
26000000
,
mux_pllaout0_audio1_2x_pllp_clkm
,
MUX
|
DIV_U71
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"i2s2"
,
"tegra30-i2s.2"
,
NULL
,
18
,
0x104
,
26000000
,
mux_pllaout0_audio2_2x_pllp_clkm
,
MUX
|
DIV_U71
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"i2s3"
,
"tegra30-i2s.3"
,
NULL
,
101
,
0x3bc
,
26000000
,
mux_pllaout0_audio3_2x_pllp_clkm
,
MUX
|
DIV_U71
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"i2s4"
,
"tegra30-i2s.4"
,
NULL
,
102
,
0x3c0
,
26000000
,
mux_pllaout0_audio4_2x_pllp_clkm
,
MUX
|
DIV_U71
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"spdif_out"
,
"tegra30-spdif"
,
"spdif_out"
,
10
,
0x108
,
100000000
,
mux_pllaout0_audio_2x_pllp_clkm
,
MUX
|
DIV_U71
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"spdif_in"
,
"tegra30-spdif"
,
"spdif_in"
,
10
,
0x10c
,
100000000
,
mux_pllp_pllc_pllm
,
MUX
|
DIV_U71
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"pwm"
,
"pwm"
,
NULL
,
17
,
0x110
,
432000000
,
mux_pllp_pllc_clk32_clkm
,
MUX
|
MUX_PWM
|
DIV_U71
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"d_audio"
,
"tegra30-ahub"
,
"d_audio"
,
106
,
0x3d0
,
48000000
,
mux_plla_pllc_pllp_clkm
,
MUX
|
DIV_U71
),
PERIPH_CLK
(
"dam0"
,
"tegra30-dam.0"
,
NULL
,
108
,
0x3d8
,
48000000
,
mux_plla_pllc_pllp_clkm
,
MUX
|
DIV_U71
),
PERIPH_CLK
(
"dam1"
,
"tegra30-dam.1"
,
NULL
,
109
,
0x3dc
,
48000000
,
mux_plla_pllc_pllp_clkm
,
MUX
|
DIV_U71
),
PERIPH_CLK
(
"dam2"
,
"tegra30-dam.2"
,
NULL
,
110
,
0x3e0
,
48000000
,
mux_plla_pllc_pllp_clkm
,
MUX
|
DIV_U71
),
PERIPH_CLK
(
"hda"
,
"tegra30-hda"
,
"hda"
,
125
,
0x428
,
108000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
),
PERIPH_CLK
(
"hda2codec_2x"
,
"tegra30-hda"
,
"hda2codec"
,
111
,
0x3e4
,
48000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
),
PERIPH_CLK
(
"hda2hdmi"
,
"tegra30-hda"
,
"hda2hdmi"
,
128
,
0
,
48000000
,
mux_clk_m
,
0
),
PERIPH_CLK
(
"sbc1"
,
"spi_tegra.0"
,
NULL
,
41
,
0x134
,
160000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"sbc2"
,
"spi_tegra.1"
,
NULL
,
44
,
0x118
,
160000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"sbc3"
,
"spi_tegra.2"
,
NULL
,
46
,
0x11c
,
160000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"sbc4"
,
"spi_tegra.3"
,
NULL
,
68
,
0x1b4
,
160000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"sbc5"
,
"spi_tegra.4"
,
NULL
,
104
,
0x3c8
,
160000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"sbc6"
,
"spi_tegra.5"
,
NULL
,
105
,
0x3cc
,
160000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"sata_oob"
,
"tegra_sata_oob"
,
NULL
,
123
,
0x420
,
216000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
),
PERIPH_CLK
(
"sata"
,
"tegra_sata"
,
NULL
,
124
,
0x424
,
216000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
),
PERIPH_CLK
(
"sata_cold"
,
"tegra_sata_cold"
,
NULL
,
129
,
0
,
48000000
,
mux_clk_m
,
0
),
PERIPH_CLK_EX
(
"ndflash"
,
"tegra_nand"
,
NULL
,
13
,
0x160
,
240000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
,
&
tegra_nand_clk_ops
),
PERIPH_CLK
(
"ndspeed"
,
"tegra_nand_speed"
,
NULL
,
80
,
0x3f8
,
240000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
),
PERIPH_CLK
(
"vfir"
,
"vfir"
,
NULL
,
7
,
0x168
,
72000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"sdmmc1"
,
"sdhci-tegra.0"
,
NULL
,
14
,
0x150
,
208000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
),
/* scales with voltage */
PERIPH_CLK
(
"sdmmc2"
,
"sdhci-tegra.1"
,
NULL
,
9
,
0x154
,
104000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
),
/* scales with voltage */
PERIPH_CLK
(
"sdmmc3"
,
"sdhci-tegra.2"
,
NULL
,
69
,
0x1bc
,
208000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
),
/* scales with voltage */
PERIPH_CLK
(
"sdmmc4"
,
"sdhci-tegra.3"
,
NULL
,
15
,
0x164
,
104000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
),
/* scales with voltage */
PERIPH_CLK
(
"vcp"
,
"tegra-avp"
,
"vcp"
,
29
,
0
,
250000000
,
mux_clk_m
,
0
),
PERIPH_CLK
(
"bsea"
,
"tegra-avp"
,
"bsea"
,
62
,
0
,
250000000
,
mux_clk_m
,
0
),
PERIPH_CLK
(
"bsev"
,
"tegra-aes"
,
"bsev"
,
63
,
0
,
250000000
,
mux_clk_m
,
0
),
PERIPH_CLK
(
"vde"
,
"vde"
,
NULL
,
61
,
0x1c8
,
520000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
|
DIV_U71_INT
),
PERIPH_CLK
(
"csite"
,
"csite"
,
NULL
,
73
,
0x1d4
,
144000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
),
/* max rate ??? */
PERIPH_CLK
(
"la"
,
"la"
,
NULL
,
76
,
0x1f8
,
26000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
),
PERIPH_CLK
(
"owr"
,
"tegra_w1"
,
NULL
,
71
,
0x1cc
,
26000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"nor"
,
"nor"
,
NULL
,
42
,
0x1d0
,
127000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
),
/* requires min voltage */
PERIPH_CLK
(
"mipi"
,
"mipi"
,
NULL
,
50
,
0x174
,
60000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
|
PERIPH_ON_APB
),
/* scales with voltage */
PERIPH_CLK
(
"i2c1"
,
"tegra-i2c.0"
,
NULL
,
12
,
0x124
,
26000000
,
mux_pllp_clkm
,
MUX
|
DIV_U16
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"i2c2"
,
"tegra-i2c.1"
,
NULL
,
54
,
0x198
,
26000000
,
mux_pllp_clkm
,
MUX
|
DIV_U16
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"i2c3"
,
"tegra-i2c.2"
,
NULL
,
67
,
0x1b8
,
26000000
,
mux_pllp_clkm
,
MUX
|
DIV_U16
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"i2c4"
,
"tegra-i2c.3"
,
NULL
,
103
,
0x3c4
,
26000000
,
mux_pllp_clkm
,
MUX
|
DIV_U16
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"i2c5"
,
"tegra-i2c.4"
,
NULL
,
47
,
0x128
,
26000000
,
mux_pllp_clkm
,
MUX
|
DIV_U16
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"uarta"
,
"tegra_uart.0"
,
NULL
,
6
,
0x178
,
800000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
|
DIV_U71_UART
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"uartb"
,
"tegra_uart.1"
,
NULL
,
7
,
0x17c
,
800000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
|
DIV_U71_UART
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"uartc"
,
"tegra_uart.2"
,
NULL
,
55
,
0x1a0
,
800000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
|
DIV_U71_UART
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"uartd"
,
"tegra_uart.3"
,
NULL
,
65
,
0x1c0
,
800000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
|
DIV_U71_UART
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"uarte"
,
"tegra_uart.4"
,
NULL
,
66
,
0x1c4
,
800000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
|
DIV_U71_UART
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"uarta_dbg"
,
"serial8250.0"
,
"uarta"
,
6
,
0x178
,
800000000
,
mux_pllp_clkm
,
MUX
|
DIV_U71
|
DIV_U71_UART
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"uartb_dbg"
,
"serial8250.0"
,
"uartb"
,
7
,
0x17c
,
800000000
,
mux_pllp_clkm
,
MUX
|
DIV_U71
|
DIV_U71_UART
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"uartc_dbg"
,
"serial8250.0"
,
"uartc"
,
55
,
0x1a0
,
800000000
,
mux_pllp_clkm
,
MUX
|
DIV_U71
|
DIV_U71_UART
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"uartd_dbg"
,
"serial8250.0"
,
"uartd"
,
65
,
0x1c0
,
800000000
,
mux_pllp_clkm
,
MUX
|
DIV_U71
|
DIV_U71_UART
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"uarte_dbg"
,
"serial8250.0"
,
"uarte"
,
66
,
0x1c4
,
800000000
,
mux_pllp_clkm
,
MUX
|
DIV_U71
|
DIV_U71_UART
|
PERIPH_ON_APB
),
PERIPH_CLK_EX
(
"vi"
,
"tegra_camera"
,
"vi"
,
20
,
0x148
,
425000000
,
mux_pllm_pllc_pllp_plla
,
MUX
|
DIV_U71
|
DIV_U71_INT
,
&
tegra_vi_clk_ops
),
PERIPH_CLK
(
"3d"
,
"3d"
,
NULL
,
24
,
0x158
,
520000000
,
mux_pllm_pllc_pllp_plla
,
MUX
|
DIV_U71
|
DIV_U71_INT
|
DIV_U71_IDLE
|
PERIPH_MANUAL_RESET
),
PERIPH_CLK
(
"3d2"
,
"3d2"
,
NULL
,
98
,
0x3b0
,
520000000
,
mux_pllm_pllc_pllp_plla
,
MUX
|
DIV_U71
|
DIV_U71_INT
|
DIV_U71_IDLE
|
PERIPH_MANUAL_RESET
),
PERIPH_CLK
(
"2d"
,
"2d"
,
NULL
,
21
,
0x15c
,
520000000
,
mux_pllm_pllc_pllp_plla
,
MUX
|
DIV_U71
|
DIV_U71_INT
|
DIV_U71_IDLE
),
PERIPH_CLK
(
"vi_sensor"
,
"tegra_camera"
,
"vi_sensor"
,
20
,
0x1a8
,
150000000
,
mux_pllm_pllc_pllp_plla
,
MUX
|
DIV_U71
|
PERIPH_NO_RESET
),
PERIPH_CLK
(
"epp"
,
"epp"
,
NULL
,
19
,
0x16c
,
520000000
,
mux_pllm_pllc_pllp_plla
,
MUX
|
DIV_U71
|
DIV_U71_INT
),
PERIPH_CLK
(
"mpe"
,
"mpe"
,
NULL
,
60
,
0x170
,
520000000
,
mux_pllm_pllc_pllp_plla
,
MUX
|
DIV_U71
|
DIV_U71_INT
),
PERIPH_CLK
(
"host1x"
,
"host1x"
,
NULL
,
28
,
0x180
,
260000000
,
mux_pllm_pllc_pllp_plla
,
MUX
|
DIV_U71
|
DIV_U71_INT
),
PERIPH_CLK
(
"cve"
,
"cve"
,
NULL
,
49
,
0x140
,
250000000
,
mux_pllp_plld_pllc_clkm
,
MUX
|
DIV_U71
),
/* requires min voltage */
PERIPH_CLK
(
"tvo"
,
"tvo"
,
NULL
,
49
,
0x188
,
250000000
,
mux_pllp_plld_pllc_clkm
,
MUX
|
DIV_U71
),
/* requires min voltage */
PERIPH_CLK_EX
(
"dtv"
,
"dtv"
,
NULL
,
79
,
0x1dc
,
250000000
,
mux_clk_m
,
0
,
&
tegra_dtv_clk_ops
),
PERIPH_CLK
(
"hdmi"
,
"hdmi"
,
NULL
,
51
,
0x18c
,
148500000
,
mux_pllp_pllm_plld_plla_pllc_plld2_clkm
,
MUX
|
MUX8
|
DIV_U71
),
PERIPH_CLK
(
"tvdac"
,
"tvdac"
,
NULL
,
53
,
0x194
,
220000000
,
mux_pllp_plld_pllc_clkm
,
MUX
|
DIV_U71
),
/* requires min voltage */
PERIPH_CLK
(
"disp1"
,
"tegradc.0"
,
NULL
,
27
,
0x138
,
600000000
,
mux_pllp_pllm_plld_plla_pllc_plld2_clkm
,
MUX
|
MUX8
),
PERIPH_CLK
(
"disp2"
,
"tegradc.1"
,
NULL
,
26
,
0x13c
,
600000000
,
mux_pllp_pllm_plld_plla_pllc_plld2_clkm
,
MUX
|
MUX8
),
PERIPH_CLK
(
"usbd"
,
"fsl-tegra-udc"
,
NULL
,
22
,
0
,
480000000
,
mux_clk_m
,
0
),
/* requires min voltage */
PERIPH_CLK
(
"usb2"
,
"tegra-ehci.1"
,
NULL
,
58
,
0
,
480000000
,
mux_clk_m
,
0
),
/* requires min voltage */
PERIPH_CLK
(
"usb3"
,
"tegra-ehci.2"
,
NULL
,
59
,
0
,
480000000
,
mux_clk_m
,
0
),
/* requires min voltage */
PERIPH_CLK
(
"dsia"
,
"tegradc.0"
,
"dsia"
,
48
,
0
,
500000000
,
mux_plld_out0
,
0
),
PERIPH_CLK_EX
(
"dsib"
,
"tegradc.1"
,
"dsib"
,
82
,
0xd0
,
500000000
,
mux_plld_out0_plld2_out0
,
MUX
|
PLLD
,
&
tegra_dsib_clk_ops
),
PERIPH_CLK
(
"csi"
,
"tegra_camera"
,
"csi"
,
52
,
0
,
102000000
,
mux_pllp_out3
,
0
),
PERIPH_CLK
(
"isp"
,
"tegra_camera"
,
"isp"
,
23
,
0
,
150000000
,
mux_clk_m
,
0
),
/* same frequency as VI */
PERIPH_CLK
(
"csus"
,
"tegra_camera"
,
"csus"
,
92
,
0
,
150000000
,
mux_clk_m
,
PERIPH_NO_RESET
),
PERIPH_CLK
(
"tsensor"
,
"tegra-tsensor"
,
NULL
,
100
,
0x3b8
,
216000000
,
mux_pllp_pllc_clkm_clk32
,
MUX
|
DIV_U71
),
PERIPH_CLK
(
"actmon"
,
"actmon"
,
NULL
,
119
,
0x3e8
,
216000000
,
mux_pllp_pllc_clk32_clkm
,
MUX
|
DIV_U71
),
PERIPH_CLK
(
"extern1"
,
"extern1"
,
NULL
,
120
,
0x3ec
,
216000000
,
mux_plla_clk32_pllp_clkm_plle
,
MUX
|
MUX8
|
DIV_U71
),
PERIPH_CLK
(
"extern2"
,
"extern2"
,
NULL
,
121
,
0x3f0
,
216000000
,
mux_plla_clk32_pllp_clkm_plle
,
MUX
|
MUX8
|
DIV_U71
),
PERIPH_CLK
(
"extern3"
,
"extern3"
,
NULL
,
122
,
0x3f4
,
216000000
,
mux_plla_clk32_pllp_clkm_plle
,
MUX
|
MUX8
|
DIV_U71
),
PERIPH_CLK
(
"i2cslow"
,
"i2cslow"
,
NULL
,
81
,
0x3fc
,
26000000
,
mux_pllp_pllc_clk32_clkm
,
MUX
|
DIV_U71
|
PERIPH_ON_APB
),
PERIPH_CLK
(
"pcie"
,
"tegra-pcie"
,
"pcie"
,
70
,
0
,
250000000
,
mux_clk_m
,
0
),
PERIPH_CLK
(
"afi"
,
"tegra-pcie"
,
"afi"
,
72
,
0
,
250000000
,
mux_clk_m
,
0
),
PERIPH_CLK
(
"se"
,
"se"
,
NULL
,
127
,
0x42c
,
520000000
,
mux_pllp_pllc_pllm_clkm
,
MUX
|
DIV_U71
|
DIV_U71_INT
),
};
#define CLK_DUPLICATE(_name, _dev, _con) \
{ \
.name = _name, \
.lookup = { \
.dev_id = _dev, \
.con_id = _con, \
}, \
}
/* Some clocks may be used by different drivers depending on the board
* configuration. List those here to register them twice in the clock lookup
* table under two names.
*/
struct
clk_duplicate
tegra_clk_duplicates
[]
=
{
CLK_DUPLICATE
(
"usbd"
,
"utmip-pad"
,
NULL
),
CLK_DUPLICATE
(
"usbd"
,
"tegra-ehci.0"
,
NULL
),
CLK_DUPLICATE
(
"usbd"
,
"tegra-otg"
,
NULL
),
CLK_DUPLICATE
(
"hdmi"
,
"tegradc.0"
,
"hdmi"
),
CLK_DUPLICATE
(
"hdmi"
,
"tegradc.1"
,
"hdmi"
),
CLK_DUPLICATE
(
"dsib"
,
"tegradc.0"
,
"dsib"
),
CLK_DUPLICATE
(
"dsia"
,
"tegradc.1"
,
"dsia"
),
CLK_DUPLICATE
(
"pwm"
,
"tegra_pwm.0"
,
NULL
),
CLK_DUPLICATE
(
"pwm"
,
"tegra_pwm.1"
,
NULL
),
CLK_DUPLICATE
(
"pwm"
,
"tegra_pwm.2"
,
NULL
),
CLK_DUPLICATE
(
"pwm"
,
"tegra_pwm.3"
,
NULL
),
CLK_DUPLICATE
(
"bsev"
,
"tegra-avp"
,
"bsev"
),
CLK_DUPLICATE
(
"bsev"
,
"nvavp"
,
"bsev"
),
CLK_DUPLICATE
(
"vde"
,
"tegra-aes"
,
"vde"
),
CLK_DUPLICATE
(
"bsea"
,
"tegra-aes"
,
"bsea"
),
CLK_DUPLICATE
(
"bsea"
,
"nvavp"
,
"bsea"
),
CLK_DUPLICATE
(
"cml1"
,
"tegra_sata_cml"
,
NULL
),
CLK_DUPLICATE
(
"cml0"
,
"tegra_pcie"
,
"cml"
),
CLK_DUPLICATE
(
"pciex"
,
"tegra_pcie"
,
"pciex"
),
CLK_DUPLICATE
(
"i2c1"
,
"tegra-i2c-slave.0"
,
NULL
),
CLK_DUPLICATE
(
"i2c2"
,
"tegra-i2c-slave.1"
,
NULL
),
CLK_DUPLICATE
(
"i2c3"
,
"tegra-i2c-slave.2"
,
NULL
),
CLK_DUPLICATE
(
"i2c4"
,
"tegra-i2c-slave.3"
,
NULL
),
CLK_DUPLICATE
(
"i2c5"
,
"tegra-i2c-slave.4"
,
NULL
),
CLK_DUPLICATE
(
"sbc1"
,
"spi_slave_tegra.0"
,
NULL
),
CLK_DUPLICATE
(
"sbc2"
,
"spi_slave_tegra.1"
,
NULL
),
CLK_DUPLICATE
(
"sbc3"
,
"spi_slave_tegra.2"
,
NULL
),
CLK_DUPLICATE
(
"sbc4"
,
"spi_slave_tegra.3"
,
NULL
),
CLK_DUPLICATE
(
"sbc5"
,
"spi_slave_tegra.4"
,
NULL
),
CLK_DUPLICATE
(
"sbc6"
,
"spi_slave_tegra.5"
,
NULL
),
CLK_DUPLICATE
(
"twd"
,
"smp_twd"
,
NULL
),
CLK_DUPLICATE
(
"vcp"
,
"nvavp"
,
"vcp"
),
};
struct
clk
*
tegra_ptr_clks
[]
=
{
&
tegra_clk_32k
,
&
tegra_clk_m
,
&
tegra_clk_m_div2
,
&
tegra_clk_m_div4
,
&
tegra_pll_ref
,
&
tegra_pll_m
,
&
tegra_pll_m_out1
,
&
tegra_pll_c
,
&
tegra_pll_c_out1
,
&
tegra_pll_p
,
&
tegra_pll_p_out1
,
&
tegra_pll_p_out2
,
&
tegra_pll_p_out3
,
&
tegra_pll_p_out4
,
&
tegra_pll_a
,
&
tegra_pll_a_out0
,
&
tegra_pll_d
,
&
tegra_pll_d_out0
,
&
tegra_pll_d2
,
&
tegra_pll_d2_out0
,
&
tegra_pll_u
,
&
tegra_pll_x
,
&
tegra_pll_x_out0
,
&
tegra_pll_e
,
&
tegra_clk_cclk_g
,
&
tegra_cml0_clk
,
&
tegra_cml1_clk
,
&
tegra_pciex_clk
,
&
tegra_clk_sclk
,
&
tegra_clk_blink
,
&
tegra30_clk_twd
,
};
static
void
tegra30_init_one_clock
(
struct
clk
*
c
)
{
clk_init
(
c
);
INIT_LIST_HEAD
(
&
c
->
shared_bus_list
);
if
(
!
c
->
lookup
.
dev_id
&&
!
c
->
lookup
.
con_id
)
c
->
lookup
.
con_id
=
c
->
name
;
c
->
lookup
.
clk
=
c
;
clkdev_add
(
&
c
->
lookup
);
}
void
__init
tegra30_init_clocks
(
void
)
{
int
i
;
struct
clk
*
c
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
tegra_ptr_clks
);
i
++
)
tegra30_init_one_clock
(
tegra_ptr_clks
[
i
]);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
tegra_list_clks
);
i
++
)
tegra30_init_one_clock
(
&
tegra_list_clks
[
i
]);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
tegra_clk_duplicates
);
i
++
)
{
c
=
tegra_get_clock_by_name
(
tegra_clk_duplicates
[
i
].
name
);
if
(
!
c
)
{
pr_err
(
"%s: Unknown duplicate clock %s
\n
"
,
__func__
,
tegra_clk_duplicates
[
i
].
name
);
continue
;
}
tegra_clk_duplicates
[
i
].
lookup
.
clk
=
c
;
clkdev_add
(
&
tegra_clk_duplicates
[
i
].
lookup
);
}
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
tegra_sync_source_list
);
i
++
)
tegra30_init_one_clock
(
&
tegra_sync_source_list
[
i
]);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
tegra_clk_audio_list
);
i
++
)
tegra30_init_one_clock
(
&
tegra_clk_audio_list
[
i
]);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
tegra_clk_audio_2x_list
);
i
++
)
tegra30_init_one_clock
(
&
tegra_clk_audio_2x_list
[
i
]);
init_clk_out_mux
();
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
tegra_clk_out_list
);
i
++
)
tegra30_init_one_clock
(
&
tegra_clk_out_list
[
i
]);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment