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
nexedi
linux
Commits
3feb4a3c
Commit
3feb4a3c
authored
Nov 11, 2019
by
Thierry Reding
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-5.5/clk' into for-5.5/memory
parents
54ecb8f7
ed1a2459
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
350 additions
and
52 deletions
+350
-52
drivers/clk/tegra/Makefile
drivers/clk/tegra/Makefile
+2
-0
drivers/clk/tegra/clk-tegra20-emc.c
drivers/clk/tegra/clk-tegra20-emc.c
+293
-0
drivers/clk/tegra/clk-tegra20.c
drivers/clk/tegra/clk-tegra20.c
+14
-41
drivers/clk/tegra/clk-tegra30.c
drivers/clk/tegra/clk-tegra30.c
+27
-11
drivers/clk/tegra/clk.h
drivers/clk/tegra/clk.h
+3
-0
include/linux/clk/tegra.h
include/linux/clk/tegra.h
+11
-0
No files found.
drivers/clk/tegra/Makefile
View file @
3feb4a3c
...
@@ -17,7 +17,9 @@ obj-y += clk-tegra-fixed.o
...
@@ -17,7 +17,9 @@ obj-y += clk-tegra-fixed.o
obj-y
+=
clk-tegra-super-gen4.o
obj-y
+=
clk-tegra-super-gen4.o
obj-$(CONFIG_TEGRA_CLK_EMC)
+=
clk-emc.o
obj-$(CONFIG_TEGRA_CLK_EMC)
+=
clk-emc.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC)
+=
clk-tegra20.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC)
+=
clk-tegra20.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC)
+=
clk-tegra20-emc.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC)
+=
clk-tegra30.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC)
+=
clk-tegra30.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC)
+=
clk-tegra20-emc.o
obj-$(CONFIG_ARCH_TEGRA_114_SOC)
+=
clk-tegra114.o
obj-$(CONFIG_ARCH_TEGRA_114_SOC)
+=
clk-tegra114.o
obj-$(CONFIG_ARCH_TEGRA_124_SOC)
+=
clk-tegra124.o
obj-$(CONFIG_ARCH_TEGRA_124_SOC)
+=
clk-tegra124.o
obj-$(CONFIG_TEGRA_CLK_DFLL)
+=
clk-tegra124-dfll-fcpu.o
obj-$(CONFIG_TEGRA_CLK_DFLL)
+=
clk-tegra124-dfll-fcpu.o
...
...
drivers/clk/tegra/clk-tegra20-emc.c
0 → 100644
View file @
3feb4a3c
// SPDX-License-Identifier: GPL-2.0+
/*
* Based on drivers/clk/tegra/clk-emc.c
* Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
*
* Author: Dmitry Osipenko <digetx@gmail.com>
* Copyright (C) 2019 GRATE-DRIVER project
*/
#define pr_fmt(fmt) "tegra-emc-clk: " fmt
#include <linux/bits.h>
#include <linux/clk-provider.h>
#include <linux/clk/tegra.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include "clk.h"
#define CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK GENMASK(7, 0)
#define CLK_SOURCE_EMC_2X_CLK_SRC_MASK GENMASK(31, 30)
#define CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT 30
#define MC_EMC_SAME_FREQ BIT(16)
#define USE_PLLM_UD BIT(29)
#define EMC_SRC_PLL_M 0
#define EMC_SRC_PLL_C 1
#define EMC_SRC_PLL_P 2
#define EMC_SRC_CLK_M 3
static
const
char
*
const
emc_parent_clk_names
[]
=
{
"pll_m"
,
"pll_c"
,
"pll_p"
,
"clk_m"
,
};
struct
tegra_clk_emc
{
struct
clk_hw
hw
;
void
__iomem
*
reg
;
bool
mc_same_freq
;
bool
want_low_jitter
;
tegra20_clk_emc_round_cb
*
round_cb
;
void
*
cb_arg
;
};
static
inline
struct
tegra_clk_emc
*
to_tegra_clk_emc
(
struct
clk_hw
*
hw
)
{
return
container_of
(
hw
,
struct
tegra_clk_emc
,
hw
);
}
static
unsigned
long
emc_recalc_rate
(
struct
clk_hw
*
hw
,
unsigned
long
parent_rate
)
{
struct
tegra_clk_emc
*
emc
=
to_tegra_clk_emc
(
hw
);
u32
val
,
div
;
val
=
readl_relaxed
(
emc
->
reg
);
div
=
val
&
CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK
;
return
DIV_ROUND_UP
(
parent_rate
*
2
,
div
+
2
);
}
static
u8
emc_get_parent
(
struct
clk_hw
*
hw
)
{
struct
tegra_clk_emc
*
emc
=
to_tegra_clk_emc
(
hw
);
return
readl_relaxed
(
emc
->
reg
)
>>
CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT
;
}
static
int
emc_set_parent
(
struct
clk_hw
*
hw
,
u8
index
)
{
struct
tegra_clk_emc
*
emc
=
to_tegra_clk_emc
(
hw
);
u32
val
,
div
;
val
=
readl_relaxed
(
emc
->
reg
);
val
&=
~
CLK_SOURCE_EMC_2X_CLK_SRC_MASK
;
val
|=
index
<<
CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT
;
div
=
val
&
CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK
;
if
(
index
==
EMC_SRC_PLL_M
&&
div
==
0
&&
emc
->
want_low_jitter
)
val
|=
USE_PLLM_UD
;
else
val
&=
~
USE_PLLM_UD
;
if
(
emc
->
mc_same_freq
)
val
|=
MC_EMC_SAME_FREQ
;
else
val
&=
~
MC_EMC_SAME_FREQ
;
writel_relaxed
(
val
,
emc
->
reg
);
fence_udelay
(
1
,
emc
->
reg
);
return
0
;
}
static
int
emc_set_rate
(
struct
clk_hw
*
hw
,
unsigned
long
rate
,
unsigned
long
parent_rate
)
{
struct
tegra_clk_emc
*
emc
=
to_tegra_clk_emc
(
hw
);
unsigned
int
index
;
u32
val
,
div
;
div
=
div_frac_get
(
rate
,
parent_rate
,
8
,
1
,
0
);
val
=
readl_relaxed
(
emc
->
reg
);
val
&=
~
CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK
;
val
|=
div
;
index
=
val
>>
CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT
;
if
(
index
==
EMC_SRC_PLL_M
&&
div
==
0
&&
emc
->
want_low_jitter
)
val
|=
USE_PLLM_UD
;
else
val
&=
~
USE_PLLM_UD
;
if
(
emc
->
mc_same_freq
)
val
|=
MC_EMC_SAME_FREQ
;
else
val
&=
~
MC_EMC_SAME_FREQ
;
writel_relaxed
(
val
,
emc
->
reg
);
fence_udelay
(
1
,
emc
->
reg
);
return
0
;
}
static
int
emc_set_rate_and_parent
(
struct
clk_hw
*
hw
,
unsigned
long
rate
,
unsigned
long
parent_rate
,
u8
index
)
{
struct
tegra_clk_emc
*
emc
=
to_tegra_clk_emc
(
hw
);
u32
val
,
div
;
div
=
div_frac_get
(
rate
,
parent_rate
,
8
,
1
,
0
);
val
=
readl_relaxed
(
emc
->
reg
);
val
&=
~
CLK_SOURCE_EMC_2X_CLK_SRC_MASK
;
val
|=
index
<<
CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT
;
val
&=
~
CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK
;
val
|=
div
;
if
(
index
==
EMC_SRC_PLL_M
&&
div
==
0
&&
emc
->
want_low_jitter
)
val
|=
USE_PLLM_UD
;
else
val
&=
~
USE_PLLM_UD
;
if
(
emc
->
mc_same_freq
)
val
|=
MC_EMC_SAME_FREQ
;
else
val
&=
~
MC_EMC_SAME_FREQ
;
writel_relaxed
(
val
,
emc
->
reg
);
fence_udelay
(
1
,
emc
->
reg
);
return
0
;
}
static
int
emc_determine_rate
(
struct
clk_hw
*
hw
,
struct
clk_rate_request
*
req
)
{
struct
tegra_clk_emc
*
emc
=
to_tegra_clk_emc
(
hw
);
struct
clk_hw
*
parent_hw
;
unsigned
long
divided_rate
;
unsigned
long
parent_rate
;
unsigned
int
i
;
long
emc_rate
;
int
div
;
emc_rate
=
emc
->
round_cb
(
req
->
rate
,
req
->
min_rate
,
req
->
max_rate
,
emc
->
cb_arg
);
if
(
emc_rate
<
0
)
return
emc_rate
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
emc_parent_clk_names
);
i
++
)
{
parent_hw
=
clk_hw_get_parent_by_index
(
hw
,
i
);
if
(
req
->
best_parent_hw
==
parent_hw
)
parent_rate
=
req
->
best_parent_rate
;
else
parent_rate
=
clk_hw_get_rate
(
parent_hw
);
if
(
emc_rate
>
parent_rate
)
continue
;
div
=
div_frac_get
(
emc_rate
,
parent_rate
,
8
,
1
,
0
);
divided_rate
=
DIV_ROUND_UP
(
parent_rate
*
2
,
div
+
2
);
if
(
divided_rate
!=
emc_rate
)
continue
;
req
->
best_parent_rate
=
parent_rate
;
req
->
best_parent_hw
=
parent_hw
;
req
->
rate
=
emc_rate
;
break
;
}
if
(
i
==
ARRAY_SIZE
(
emc_parent_clk_names
))
{
pr_err_once
(
"can't find parent for rate %lu emc_rate %lu
\n
"
,
req
->
rate
,
emc_rate
);
return
-
EINVAL
;
}
return
0
;
}
static
const
struct
clk_ops
tegra_clk_emc_ops
=
{
.
recalc_rate
=
emc_recalc_rate
,
.
get_parent
=
emc_get_parent
,
.
set_parent
=
emc_set_parent
,
.
set_rate
=
emc_set_rate
,
.
set_rate_and_parent
=
emc_set_rate_and_parent
,
.
determine_rate
=
emc_determine_rate
,
};
void
tegra20_clk_set_emc_round_callback
(
tegra20_clk_emc_round_cb
*
round_cb
,
void
*
cb_arg
)
{
struct
clk
*
clk
=
__clk_lookup
(
"emc"
);
struct
tegra_clk_emc
*
emc
;
struct
clk_hw
*
hw
;
if
(
clk
)
{
hw
=
__clk_get_hw
(
clk
);
emc
=
to_tegra_clk_emc
(
hw
);
emc
->
round_cb
=
round_cb
;
emc
->
cb_arg
=
cb_arg
;
}
}
bool
tegra20_clk_emc_driver_available
(
struct
clk_hw
*
emc_hw
)
{
return
to_tegra_clk_emc
(
emc_hw
)
->
round_cb
!=
NULL
;
}
struct
clk
*
tegra20_clk_register_emc
(
void
__iomem
*
ioaddr
,
bool
low_jitter
)
{
struct
tegra_clk_emc
*
emc
;
struct
clk_init_data
init
;
struct
clk
*
clk
;
emc
=
kzalloc
(
sizeof
(
*
emc
),
GFP_KERNEL
);
if
(
!
emc
)
return
NULL
;
/*
* EMC stands for External Memory Controller.
*
* We don't want EMC clock to be disabled ever by gating its
* parent and whatnot because system is busted immediately in that
* case, hence the clock is marked as critical.
*/
init
.
name
=
"emc"
;
init
.
ops
=
&
tegra_clk_emc_ops
;
init
.
flags
=
CLK_IS_CRITICAL
;
init
.
parent_names
=
emc_parent_clk_names
;
init
.
num_parents
=
ARRAY_SIZE
(
emc_parent_clk_names
);
emc
->
reg
=
ioaddr
;
emc
->
hw
.
init
=
&
init
;
emc
->
want_low_jitter
=
low_jitter
;
clk
=
clk_register
(
NULL
,
&
emc
->
hw
);
if
(
IS_ERR
(
clk
))
{
kfree
(
emc
);
return
NULL
;
}
return
clk
;
}
int
tegra20_clk_prepare_emc_mc_same_freq
(
struct
clk
*
emc_clk
,
bool
same
)
{
struct
tegra_clk_emc
*
emc
;
struct
clk_hw
*
hw
;
if
(
!
emc_clk
)
return
-
EINVAL
;
hw
=
__clk_get_hw
(
emc_clk
);
emc
=
to_tegra_clk_emc
(
hw
);
emc
->
mc_same_freq
=
same
;
return
0
;
}
drivers/clk/tegra/clk-tegra20.c
View file @
3feb4a3c
...
@@ -130,8 +130,6 @@ static struct cpu_clk_suspend_context {
...
@@ -130,8 +130,6 @@ static struct cpu_clk_suspend_context {
static
void
__iomem
*
clk_base
;
static
void
__iomem
*
clk_base
;
static
void
__iomem
*
pmc_base
;
static
void
__iomem
*
pmc_base
;
static
DEFINE_SPINLOCK
(
emc_lock
);
#define TEGRA_INIT_DATA_MUX(_name, _parents, _offset, \
#define TEGRA_INIT_DATA_MUX(_name, _parents, _offset, \
_clk_num, _gate_flags, _clk_id) \
_clk_num, _gate_flags, _clk_id) \
TEGRA_INIT_DATA(_name, NULL, NULL, _parents, _offset, \
TEGRA_INIT_DATA(_name, NULL, NULL, _parents, _offset, \
...
@@ -760,7 +758,6 @@ static const char *pwm_parents[] = { "pll_p", "pll_c", "audio", "clk_m",
...
@@ -760,7 +758,6 @@ static const char *pwm_parents[] = { "pll_p", "pll_c", "audio", "clk_m",
static
const
char
*
mux_pllpcm_clkm
[]
=
{
"pll_p"
,
"pll_c"
,
"pll_m"
,
"clk_m"
};
static
const
char
*
mux_pllpcm_clkm
[]
=
{
"pll_p"
,
"pll_c"
,
"pll_m"
,
"clk_m"
};
static
const
char
*
mux_pllpdc_clkm
[]
=
{
"pll_p"
,
"pll_d_out0"
,
"pll_c"
,
static
const
char
*
mux_pllpdc_clkm
[]
=
{
"pll_p"
,
"pll_d_out0"
,
"pll_c"
,
"clk_m"
};
"clk_m"
};
static
const
char
*
mux_pllmcp_clkm
[]
=
{
"pll_m"
,
"pll_c"
,
"pll_p"
,
"clk_m"
};
static
struct
tegra_periph_init_data
tegra_periph_clk_list
[]
=
{
static
struct
tegra_periph_init_data
tegra_periph_clk_list
[]
=
{
TEGRA_INIT_DATA_MUX
(
"i2s1"
,
i2s1_parents
,
CLK_SOURCE_I2S1
,
11
,
TEGRA_PERIPH_ON_APB
,
TEGRA20_CLK_I2S1
),
TEGRA_INIT_DATA_MUX
(
"i2s1"
,
i2s1_parents
,
CLK_SOURCE_I2S1
,
11
,
TEGRA_PERIPH_ON_APB
,
TEGRA20_CLK_I2S1
),
...
@@ -787,41 +784,6 @@ static struct tegra_periph_init_data tegra_periph_nodiv_clk_list[] = {
...
@@ -787,41 +784,6 @@ static struct tegra_periph_init_data tegra_periph_nodiv_clk_list[] = {
TEGRA_INIT_DATA_NODIV
(
"disp2"
,
mux_pllpdc_clkm
,
CLK_SOURCE_DISP2
,
30
,
2
,
26
,
0
,
TEGRA20_CLK_DISP2
),
TEGRA_INIT_DATA_NODIV
(
"disp2"
,
mux_pllpdc_clkm
,
CLK_SOURCE_DISP2
,
30
,
2
,
26
,
0
,
TEGRA20_CLK_DISP2
),
};
};
static
void
__init
tegra20_emc_clk_init
(
void
)
{
const
u32
use_pllm_ud
=
BIT
(
29
);
struct
clk
*
clk
;
u32
emc_reg
;
clk
=
clk_register_mux
(
NULL
,
"emc_mux"
,
mux_pllmcp_clkm
,
ARRAY_SIZE
(
mux_pllmcp_clkm
),
CLK_SET_RATE_NO_REPARENT
,
clk_base
+
CLK_SOURCE_EMC
,
30
,
2
,
0
,
&
emc_lock
);
clk
=
tegra_clk_register_mc
(
"mc"
,
"emc_mux"
,
clk_base
+
CLK_SOURCE_EMC
,
&
emc_lock
);
clks
[
TEGRA20_CLK_MC
]
=
clk
;
/* un-divided pll_m_out0 is currently unsupported */
emc_reg
=
readl_relaxed
(
clk_base
+
CLK_SOURCE_EMC
);
if
(
emc_reg
&
use_pllm_ud
)
{
pr_err
(
"%s: un-divided PllM_out0 used as clock source
\n
"
,
__func__
);
return
;
}
/*
* Note that 'emc_mux' source and 'emc' rate shouldn't be changed at
* the same time due to a HW bug, this won't happen because we're
* defining 'emc_mux' and 'emc' as distinct clocks.
*/
clk
=
tegra_clk_register_divider
(
"emc"
,
"emc_mux"
,
clk_base
+
CLK_SOURCE_EMC
,
CLK_IS_CRITICAL
,
TEGRA_DIVIDER_INT
,
0
,
8
,
1
,
&
emc_lock
);
clks
[
TEGRA20_CLK_EMC
]
=
clk
;
}
static
void
__init
tegra20_periph_clk_init
(
void
)
static
void
__init
tegra20_periph_clk_init
(
void
)
{
{
struct
tegra_periph_init_data
*
data
;
struct
tegra_periph_init_data
*
data
;
...
@@ -835,7 +797,13 @@ static void __init tegra20_periph_clk_init(void)
...
@@ -835,7 +797,13 @@ static void __init tegra20_periph_clk_init(void)
clks
[
TEGRA20_CLK_AC97
]
=
clk
;
clks
[
TEGRA20_CLK_AC97
]
=
clk
;
/* emc */
/* emc */
tegra20_emc_clk_init
();
clk
=
tegra20_clk_register_emc
(
clk_base
+
CLK_SOURCE_EMC
,
false
);
clks
[
TEGRA20_CLK_EMC
]
=
clk
;
clk
=
tegra_clk_register_mc
(
"mc"
,
"emc"
,
clk_base
+
CLK_SOURCE_EMC
,
NULL
);
clks
[
TEGRA20_CLK_MC
]
=
clk
;
/* dsi */
/* dsi */
clk
=
tegra_clk_register_periph_gate
(
"dsi"
,
"pll_d"
,
0
,
clk_base
,
0
,
clk
=
tegra_clk_register_periph_gate
(
"dsi"
,
"pll_d"
,
0
,
clk_base
,
0
,
...
@@ -1115,6 +1083,8 @@ static struct clk *tegra20_clk_src_onecell_get(struct of_phandle_args *clkspec,
...
@@ -1115,6 +1083,8 @@ static struct clk *tegra20_clk_src_onecell_get(struct of_phandle_args *clkspec,
if
(
IS_ERR
(
clk
))
if
(
IS_ERR
(
clk
))
return
clk
;
return
clk
;
hw
=
__clk_get_hw
(
clk
);
/*
/*
* Tegra20 CDEV1 and CDEV2 clocks are a bit special case, their parent
* Tegra20 CDEV1 and CDEV2 clocks are a bit special case, their parent
* clock is created by the pinctrl driver. It is possible for clk user
* clock is created by the pinctrl driver. It is possible for clk user
...
@@ -1124,13 +1094,16 @@ static struct clk *tegra20_clk_src_onecell_get(struct of_phandle_args *clkspec,
...
@@ -1124,13 +1094,16 @@ static struct clk *tegra20_clk_src_onecell_get(struct of_phandle_args *clkspec,
*/
*/
if
(
clkspec
->
args
[
0
]
==
TEGRA20_CLK_CDEV1
||
if
(
clkspec
->
args
[
0
]
==
TEGRA20_CLK_CDEV1
||
clkspec
->
args
[
0
]
==
TEGRA20_CLK_CDEV2
)
{
clkspec
->
args
[
0
]
==
TEGRA20_CLK_CDEV2
)
{
hw
=
__clk_get_hw
(
clk
);
parent_hw
=
clk_hw_get_parent
(
hw
);
parent_hw
=
clk_hw_get_parent
(
hw
);
if
(
!
parent_hw
)
if
(
!
parent_hw
)
return
ERR_PTR
(
-
EPROBE_DEFER
);
return
ERR_PTR
(
-
EPROBE_DEFER
);
}
}
if
(
clkspec
->
args
[
0
]
==
TEGRA20_CLK_EMC
)
{
if
(
!
tegra20_clk_emc_driver_available
(
hw
))
return
ERR_PTR
(
-
EPROBE_DEFER
);
}
return
clk
;
return
clk
;
}
}
...
...
drivers/clk/tegra/clk-tegra30.c
View file @
3feb4a3c
...
@@ -151,7 +151,6 @@ static unsigned long input_freq;
...
@@ -151,7 +151,6 @@ static unsigned long input_freq;
static
DEFINE_SPINLOCK
(
cml_lock
);
static
DEFINE_SPINLOCK
(
cml_lock
);
static
DEFINE_SPINLOCK
(
pll_d_lock
);
static
DEFINE_SPINLOCK
(
pll_d_lock
);
static
DEFINE_SPINLOCK
(
emc_lock
);
#define TEGRA_INIT_DATA_MUX(_name, _parents, _offset, \
#define TEGRA_INIT_DATA_MUX(_name, _parents, _offset, \
_clk_num, _gate_flags, _clk_id) \
_clk_num, _gate_flags, _clk_id) \
...
@@ -808,7 +807,7 @@ static struct tegra_clk tegra30_clks[tegra_clk_max] __initdata = {
...
@@ -808,7 +807,7 @@ static struct tegra_clk tegra30_clks[tegra_clk_max] __initdata = {
[
tegra_clk_pll_a
]
=
{
.
dt_id
=
TEGRA30_CLK_PLL_A
,
.
present
=
true
},
[
tegra_clk_pll_a
]
=
{
.
dt_id
=
TEGRA30_CLK_PLL_A
,
.
present
=
true
},
[
tegra_clk_pll_a_out0
]
=
{
.
dt_id
=
TEGRA30_CLK_PLL_A_OUT0
,
.
present
=
true
},
[
tegra_clk_pll_a_out0
]
=
{
.
dt_id
=
TEGRA30_CLK_PLL_A_OUT0
,
.
present
=
true
},
[
tegra_clk_cec
]
=
{
.
dt_id
=
TEGRA30_CLK_CEC
,
.
present
=
true
},
[
tegra_clk_cec
]
=
{
.
dt_id
=
TEGRA30_CLK_CEC
,
.
present
=
true
},
[
tegra_clk_emc
]
=
{
.
dt_id
=
TEGRA30_CLK_EMC
,
.
present
=
tru
e
},
[
tegra_clk_emc
]
=
{
.
dt_id
=
TEGRA30_CLK_EMC
,
.
present
=
fals
e
},
};
};
static
const
char
*
pll_e_parents
[]
=
{
"pll_ref"
,
"pll_p"
};
static
const
char
*
pll_e_parents
[]
=
{
"pll_ref"
,
"pll_p"
};
...
@@ -995,7 +994,6 @@ static void __init tegra30_super_clk_init(void)
...
@@ -995,7 +994,6 @@ static void __init tegra30_super_clk_init(void)
static
const
char
*
mux_pllacp_clkm
[]
=
{
"pll_a_out0"
,
"unused"
,
"pll_p"
,
static
const
char
*
mux_pllacp_clkm
[]
=
{
"pll_a_out0"
,
"unused"
,
"pll_p"
,
"clk_m"
};
"clk_m"
};
static
const
char
*
mux_pllpcm_clkm
[]
=
{
"pll_p"
,
"pll_c"
,
"pll_m"
,
"clk_m"
};
static
const
char
*
mux_pllpcm_clkm
[]
=
{
"pll_p"
,
"pll_c"
,
"pll_m"
,
"clk_m"
};
static
const
char
*
mux_pllmcp_clkm
[]
=
{
"pll_m"
,
"pll_c"
,
"pll_p"
,
"clk_m"
};
static
const
char
*
spdif_out_parents
[]
=
{
"pll_a_out0"
,
"spdif_2x"
,
"pll_p"
,
static
const
char
*
spdif_out_parents
[]
=
{
"pll_a_out0"
,
"spdif_2x"
,
"pll_p"
,
"clk_m"
};
"clk_m"
};
static
const
char
*
mux_pllmcpa
[]
=
{
"pll_m"
,
"pll_c"
,
"pll_p"
,
"pll_a_out0"
};
static
const
char
*
mux_pllmcpa
[]
=
{
"pll_m"
,
"pll_c"
,
"pll_p"
,
"pll_a_out0"
};
...
@@ -1044,14 +1042,12 @@ static void __init tegra30_periph_clk_init(void)
...
@@ -1044,14 +1042,12 @@ static void __init tegra30_periph_clk_init(void)
clks
[
TEGRA30_CLK_AFI
]
=
clk
;
clks
[
TEGRA30_CLK_AFI
]
=
clk
;
/* emc */
/* emc */
clk
=
clk_register_mux
(
NULL
,
"emc_mux"
,
mux_pllmcp_clkm
,
clk
=
tegra20_clk_register_emc
(
clk_base
+
CLK_SOURCE_EMC
,
true
);
ARRAY_SIZE
(
mux_pllmcp_clkm
),
CLK_SET_RATE_NO_REPARENT
,
clks
[
TEGRA30_CLK_EMC
]
=
clk
;
clk_base
+
CLK_SOURCE_EMC
,
30
,
2
,
0
,
&
emc_lock
);
clk
=
tegra_clk_register_mc
(
"mc"
,
"emc
_mux
"
,
clk_base
+
CLK_SOURCE_EMC
,
clk
=
tegra_clk_register_mc
(
"mc"
,
"emc"
,
clk_base
+
CLK_SOURCE_EMC
,
&
emc_lock
);
NULL
);
clks
[
TEGRA30_CLK_MC
]
=
clk
;
clks
[
TEGRA30_CLK_MC
]
=
clk
;
/* cml0 */
/* cml0 */
...
@@ -1302,6 +1298,26 @@ static struct tegra_audio_clk_info tegra30_audio_plls[] = {
...
@@ -1302,6 +1298,26 @@ static struct tegra_audio_clk_info tegra30_audio_plls[] = {
{
"pll_a"
,
&
pll_a_params
,
tegra_clk_pll_a
,
"pll_p_out1"
},
{
"pll_a"
,
&
pll_a_params
,
tegra_clk_pll_a
,
"pll_p_out1"
},
};
};
static
struct
clk
*
tegra30_clk_src_onecell_get
(
struct
of_phandle_args
*
clkspec
,
void
*
data
)
{
struct
clk_hw
*
hw
;
struct
clk
*
clk
;
clk
=
of_clk_src_onecell_get
(
clkspec
,
data
);
if
(
IS_ERR
(
clk
))
return
clk
;
hw
=
__clk_get_hw
(
clk
);
if
(
clkspec
->
args
[
0
]
==
TEGRA30_CLK_EMC
)
{
if
(
!
tegra20_clk_emc_driver_available
(
hw
))
return
ERR_PTR
(
-
EPROBE_DEFER
);
}
return
clk
;
}
static
void
__init
tegra30_clock_init
(
struct
device_node
*
np
)
static
void
__init
tegra30_clock_init
(
struct
device_node
*
np
)
{
{
struct
device_node
*
node
;
struct
device_node
*
node
;
...
@@ -1345,7 +1361,7 @@ static void __init tegra30_clock_init(struct device_node *np)
...
@@ -1345,7 +1361,7 @@ static void __init tegra30_clock_init(struct device_node *np)
tegra_init_dup_clks
(
tegra_clk_duplicates
,
clks
,
TEGRA30_CLK_CLK_MAX
);
tegra_init_dup_clks
(
tegra_clk_duplicates
,
clks
,
TEGRA30_CLK_CLK_MAX
);
tegra_add_of_provider
(
np
,
of
_clk_src_onecell_get
);
tegra_add_of_provider
(
np
,
tegra30
_clk_src_onecell_get
);
tegra_register_devclks
(
devclks
,
ARRAY_SIZE
(
devclks
));
tegra_register_devclks
(
devclks
,
ARRAY_SIZE
(
devclks
));
tegra_clk_apply_init_table
=
tegra30_clock_apply_init_table
;
tegra_clk_apply_init_table
=
tegra30_clock_apply_init_table
;
...
...
drivers/clk/tegra/clk.h
View file @
3feb4a3c
...
@@ -838,4 +838,7 @@ int div_frac_get(unsigned long rate, unsigned parent_rate, u8 width,
...
@@ -838,4 +838,7 @@ int div_frac_get(unsigned long rate, unsigned parent_rate, u8 width,
udelay(delay); \
udelay(delay); \
} while (0)
} while (0)
bool
tegra20_clk_emc_driver_available
(
struct
clk_hw
*
emc_hw
);
struct
clk
*
tegra20_clk_register_emc
(
void
__iomem
*
ioaddr
,
bool
low_jitter
);
#endif
/* TEGRA_CLK_H */
#endif
/* TEGRA_CLK_H */
include/linux/clk/tegra.h
View file @
3feb4a3c
...
@@ -119,4 +119,15 @@ extern void tegra210_put_utmipll_in_iddq(void);
...
@@ -119,4 +119,15 @@ extern void tegra210_put_utmipll_in_iddq(void);
extern
void
tegra210_put_utmipll_out_iddq
(
void
);
extern
void
tegra210_put_utmipll_out_iddq
(
void
);
extern
int
tegra210_clk_handle_mbist_war
(
unsigned
int
id
);
extern
int
tegra210_clk_handle_mbist_war
(
unsigned
int
id
);
struct
clk
;
typedef
long
(
tegra20_clk_emc_round_cb
)(
unsigned
long
rate
,
unsigned
long
min_rate
,
unsigned
long
max_rate
,
void
*
arg
);
void
tegra20_clk_set_emc_round_callback
(
tegra20_clk_emc_round_cb
*
round_cb
,
void
*
cb_arg
);
int
tegra20_clk_prepare_emc_mc_same_freq
(
struct
clk
*
emc_clk
,
bool
same
);
#endif
/* __LINUX_CLK_TEGRA_H_ */
#endif
/* __LINUX_CLK_TEGRA_H_ */
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