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
87d7426f
Commit
87d7426f
authored
Jun 01, 2021
by
Thierry Reding
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-5.14/soc' into for-5.14/memory
parents
dd44ca51
30b44e81
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
317 additions
and
5 deletions
+317
-5
drivers/regulator/core.c
drivers/regulator/core.c
+23
-0
drivers/soc/tegra/common.c
drivers/soc/tegra/common.c
+97
-0
drivers/soc/tegra/regulators-tegra20.c
drivers/soc/tegra/regulators-tegra20.c
+74
-1
drivers/soc/tegra/regulators-tegra30.c
drivers/soc/tegra/regulators-tegra30.c
+74
-1
include/linux/regulator/driver.h
include/linux/regulator/driver.h
+1
-0
include/soc/tegra/common.h
include/soc/tegra/common.h
+31
-0
include/soc/tegra/fuse.h
include/soc/tegra/fuse.h
+17
-3
No files found.
drivers/regulator/core.c
View file @
87d7426f
...
...
@@ -4105,6 +4105,29 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
}
EXPORT_SYMBOL_GPL
(
regulator_set_voltage_time_sel
);
int
regulator_sync_voltage_rdev
(
struct
regulator_dev
*
rdev
)
{
int
ret
;
regulator_lock
(
rdev
);
if
(
!
rdev
->
desc
->
ops
->
set_voltage
&&
!
rdev
->
desc
->
ops
->
set_voltage_sel
)
{
ret
=
-
EINVAL
;
goto
out
;
}
/* balance only, if regulator is coupled */
if
(
rdev
->
coupling_desc
.
n_coupled
>
1
)
ret
=
regulator_balance_voltage
(
rdev
,
PM_SUSPEND_ON
);
else
ret
=
-
EOPNOTSUPP
;
out:
regulator_unlock
(
rdev
);
return
ret
;
}
/**
* regulator_sync_voltage - re-apply last regulator output voltage
* @regulator: regulator source
...
...
drivers/soc/tegra/common.c
View file @
87d7426f
...
...
@@ -3,9 +3,16 @@
* Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
*/
#define dev_fmt(fmt) "tegra-soc: " fmt
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/of.h>
#include <linux/pm_opp.h>
#include <soc/tegra/common.h>
#include <soc/tegra/fuse.h>
static
const
struct
of_device_id
tegra_machine_match
[]
=
{
{
.
compatible
=
"nvidia,tegra20"
,
},
...
...
@@ -31,3 +38,93 @@ bool soc_is_tegra(void)
return
match
!=
NULL
;
}
static
int
tegra_core_dev_init_opp_state
(
struct
device
*
dev
)
{
unsigned
long
rate
;
struct
clk
*
clk
;
int
err
;
clk
=
devm_clk_get
(
dev
,
NULL
);
if
(
IS_ERR
(
clk
))
{
dev_err
(
dev
,
"failed to get clk: %pe
\n
"
,
clk
);
return
PTR_ERR
(
clk
);
}
rate
=
clk_get_rate
(
clk
);
if
(
!
rate
)
{
dev_err
(
dev
,
"failed to get clk rate
\n
"
);
return
-
EINVAL
;
}
/* first dummy rate-setting initializes voltage vote */
err
=
dev_pm_opp_set_rate
(
dev
,
rate
);
if
(
err
)
{
dev_err
(
dev
,
"failed to initialize OPP clock: %d
\n
"
,
err
);
return
err
;
}
return
0
;
}
/**
* devm_tegra_core_dev_init_opp_table() - initialize OPP table
* @dev: device for which OPP table is initialized
* @params: pointer to the OPP table configuration
*
* This function will initialize OPP table and sync OPP state of a Tegra SoC
* core device.
*
* Return: 0 on success or errorno.
*/
int
devm_tegra_core_dev_init_opp_table
(
struct
device
*
dev
,
struct
tegra_core_opp_params
*
params
)
{
u32
hw_version
;
int
err
;
err
=
devm_pm_opp_set_clkname
(
dev
,
NULL
);
if
(
err
)
{
dev_err
(
dev
,
"failed to set OPP clk: %d
\n
"
,
err
);
return
err
;
}
/* Tegra114+ doesn't support OPP yet */
if
(
!
of_machine_is_compatible
(
"nvidia,tegra20"
)
&&
!
of_machine_is_compatible
(
"nvidia,tegra30"
))
return
-
ENODEV
;
if
(
of_machine_is_compatible
(
"nvidia,tegra20"
))
hw_version
=
BIT
(
tegra_sku_info
.
soc_process_id
);
else
hw_version
=
BIT
(
tegra_sku_info
.
soc_speedo_id
);
err
=
devm_pm_opp_set_supported_hw
(
dev
,
&
hw_version
,
1
);
if
(
err
)
{
dev_err
(
dev
,
"failed to set OPP supported HW: %d
\n
"
,
err
);
return
err
;
}
/*
* Older device-trees have an empty OPP table, we will get
* -ENODEV from devm_pm_opp_of_add_table() in this case.
*/
err
=
devm_pm_opp_of_add_table
(
dev
);
if
(
err
)
{
if
(
err
==
-
ENODEV
)
dev_err_once
(
dev
,
"OPP table not found, please update device-tree
\n
"
);
else
dev_err
(
dev
,
"failed to add OPP table: %d
\n
"
,
err
);
return
err
;
}
if
(
params
->
init_state
)
{
err
=
tegra_core_dev_init_opp_state
(
dev
);
if
(
err
)
return
err
;
}
return
0
;
}
EXPORT_SYMBOL_GPL
(
devm_tegra_core_dev_init_opp_table
);
drivers/soc/tegra/regulators-tegra20.c
View file @
87d7426f
...
...
@@ -12,6 +12,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/reboot.h>
#include <linux/regulator/coupler.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
...
...
@@ -21,7 +22,10 @@ struct tegra_regulator_coupler {
struct
regulator_dev
*
core_rdev
;
struct
regulator_dev
*
cpu_rdev
;
struct
regulator_dev
*
rtc_rdev
;
int
core_min_uV
;
struct
notifier_block
reboot_notifier
;
int
core_min_uV
,
cpu_min_uV
;
bool
sys_reboot_mode_req
;
bool
sys_reboot_mode
;
};
static
inline
struct
tegra_regulator_coupler
*
...
...
@@ -242,6 +246,10 @@ static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra,
if
(
cpu_uV
<
0
)
return
cpu_uV
;
/* store boot voltage level */
if
(
!
tegra
->
cpu_min_uV
)
tegra
->
cpu_min_uV
=
cpu_uV
;
/*
* CPU's regulator may not have any consumers, hence the voltage
* must not be changed in that case because CPU simply won't
...
...
@@ -250,6 +258,10 @@ static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra,
if
(
!
cpu_min_uV_consumers
)
cpu_min_uV
=
cpu_uV
;
/* restore boot voltage level */
if
(
tegra
->
sys_reboot_mode
)
cpu_min_uV
=
max
(
cpu_min_uV
,
tegra
->
cpu_min_uV
);
if
(
cpu_min_uV
>
cpu_uV
)
{
err
=
tegra20_core_rtc_update
(
tegra
,
core_rdev
,
rtc_rdev
,
cpu_uV
,
cpu_min_uV
);
...
...
@@ -290,6 +302,8 @@ static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler,
return
-
EINVAL
;
}
tegra
->
sys_reboot_mode
=
READ_ONCE
(
tegra
->
sys_reboot_mode_req
);
if
(
rdev
==
cpu_rdev
)
return
tegra20_cpu_voltage_update
(
tegra
,
cpu_rdev
,
core_rdev
,
rtc_rdev
);
...
...
@@ -303,6 +317,51 @@ static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler,
return
-
EPERM
;
}
static
int
tegra20_regulator_prepare_reboot
(
struct
tegra_regulator_coupler
*
tegra
,
bool
sys_reboot_mode
)
{
int
err
;
if
(
!
tegra
->
core_rdev
||
!
tegra
->
rtc_rdev
||
!
tegra
->
cpu_rdev
)
return
0
;
WRITE_ONCE
(
tegra
->
sys_reboot_mode_req
,
true
);
/*
* Some devices use CPU soft-reboot method and in this case we
* should ensure that voltages are sane for the reboot by restoring
* the minimum boot levels.
*/
err
=
regulator_sync_voltage_rdev
(
tegra
->
cpu_rdev
);
if
(
err
)
return
err
;
err
=
regulator_sync_voltage_rdev
(
tegra
->
core_rdev
);
if
(
err
)
return
err
;
WRITE_ONCE
(
tegra
->
sys_reboot_mode_req
,
sys_reboot_mode
);
return
0
;
}
static
int
tegra20_regulator_reboot
(
struct
notifier_block
*
notifier
,
unsigned
long
event
,
void
*
cmd
)
{
struct
tegra_regulator_coupler
*
tegra
;
int
ret
;
if
(
event
!=
SYS_RESTART
)
return
NOTIFY_DONE
;
tegra
=
container_of
(
notifier
,
struct
tegra_regulator_coupler
,
reboot_notifier
);
ret
=
tegra20_regulator_prepare_reboot
(
tegra
,
true
);
return
notifier_from_errno
(
ret
);
}
static
int
tegra20_regulator_attach
(
struct
regulator_coupler
*
coupler
,
struct
regulator_dev
*
rdev
)
{
...
...
@@ -335,6 +394,14 @@ static int tegra20_regulator_detach(struct regulator_coupler *coupler,
{
struct
tegra_regulator_coupler
*
tegra
=
to_tegra_coupler
(
coupler
);
/*
* We don't expect regulators to be decoupled during reboot,
* this may race with the reboot handler and shouldn't ever
* happen in practice.
*/
if
(
WARN_ON_ONCE
(
system_state
>
SYSTEM_RUNNING
))
return
-
EPERM
;
if
(
tegra
->
core_rdev
==
rdev
)
{
tegra
->
core_rdev
=
NULL
;
return
0
;
...
...
@@ -359,13 +426,19 @@ static struct tegra_regulator_coupler tegra20_coupler = {
.
detach_regulator
=
tegra20_regulator_detach
,
.
balance_voltage
=
tegra20_regulator_balance_voltage
,
},
.
reboot_notifier
.
notifier_call
=
tegra20_regulator_reboot
,
};
static
int
__init
tegra_regulator_coupler_init
(
void
)
{
int
err
;
if
(
!
of_machine_is_compatible
(
"nvidia,tegra20"
))
return
0
;
err
=
register_reboot_notifier
(
&
tegra20_coupler
.
reboot_notifier
);
WARN_ON
(
err
);
return
regulator_coupler_register
(
&
tegra20_coupler
.
coupler
);
}
arch_initcall
(
tegra_regulator_coupler_init
);
drivers/soc/tegra/regulators-tegra30.c
View file @
87d7426f
...
...
@@ -12,6 +12,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/reboot.h>
#include <linux/regulator/coupler.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
...
...
@@ -22,7 +23,10 @@ struct tegra_regulator_coupler {
struct
regulator_coupler
coupler
;
struct
regulator_dev
*
core_rdev
;
struct
regulator_dev
*
cpu_rdev
;
int
core_min_uV
;
struct
notifier_block
reboot_notifier
;
int
core_min_uV
,
cpu_min_uV
;
bool
sys_reboot_mode_req
;
bool
sys_reboot_mode
;
};
static
inline
struct
tegra_regulator_coupler
*
...
...
@@ -172,6 +176,10 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra,
if
(
cpu_uV
<
0
)
return
cpu_uV
;
/* store boot voltage level */
if
(
!
tegra
->
cpu_min_uV
)
tegra
->
cpu_min_uV
=
cpu_uV
;
/*
* CPU's regulator may not have any consumers, hence the voltage
* must not be changed in that case because CPU simply won't
...
...
@@ -195,6 +203,10 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra,
if
(
err
)
return
err
;
/* restore boot voltage level */
if
(
tegra
->
sys_reboot_mode
)
cpu_min_uV
=
max
(
cpu_min_uV
,
tegra
->
cpu_min_uV
);
if
(
core_min_limited_uV
>
core_uV
)
{
pr_err
(
"core voltage constraint violated: %d %d %d
\n
"
,
core_uV
,
core_min_limited_uV
,
cpu_uV
);
...
...
@@ -263,9 +275,56 @@ static int tegra30_regulator_balance_voltage(struct regulator_coupler *coupler,
return
-
EINVAL
;
}
tegra
->
sys_reboot_mode
=
READ_ONCE
(
tegra
->
sys_reboot_mode_req
);
return
tegra30_voltage_update
(
tegra
,
cpu_rdev
,
core_rdev
);
}
static
int
tegra30_regulator_prepare_reboot
(
struct
tegra_regulator_coupler
*
tegra
,
bool
sys_reboot_mode
)
{
int
err
;
if
(
!
tegra
->
core_rdev
||
!
tegra
->
cpu_rdev
)
return
0
;
WRITE_ONCE
(
tegra
->
sys_reboot_mode_req
,
true
);
/*
* Some devices use CPU soft-reboot method and in this case we
* should ensure that voltages are sane for the reboot by restoring
* the minimum boot levels.
*/
err
=
regulator_sync_voltage_rdev
(
tegra
->
cpu_rdev
);
if
(
err
)
return
err
;
err
=
regulator_sync_voltage_rdev
(
tegra
->
core_rdev
);
if
(
err
)
return
err
;
WRITE_ONCE
(
tegra
->
sys_reboot_mode_req
,
sys_reboot_mode
);
return
0
;
}
static
int
tegra30_regulator_reboot
(
struct
notifier_block
*
notifier
,
unsigned
long
event
,
void
*
cmd
)
{
struct
tegra_regulator_coupler
*
tegra
;
int
ret
;
if
(
event
!=
SYS_RESTART
)
return
NOTIFY_DONE
;
tegra
=
container_of
(
notifier
,
struct
tegra_regulator_coupler
,
reboot_notifier
);
ret
=
tegra30_regulator_prepare_reboot
(
tegra
,
true
);
return
notifier_from_errno
(
ret
);
}
static
int
tegra30_regulator_attach
(
struct
regulator_coupler
*
coupler
,
struct
regulator_dev
*
rdev
)
{
...
...
@@ -292,6 +351,14 @@ static int tegra30_regulator_detach(struct regulator_coupler *coupler,
{
struct
tegra_regulator_coupler
*
tegra
=
to_tegra_coupler
(
coupler
);
/*
* We don't expect regulators to be decoupled during reboot,
* this may race with the reboot handler and shouldn't ever
* happen in practice.
*/
if
(
WARN_ON_ONCE
(
system_state
>
SYSTEM_RUNNING
))
return
-
EPERM
;
if
(
tegra
->
core_rdev
==
rdev
)
{
tegra
->
core_rdev
=
NULL
;
return
0
;
...
...
@@ -311,13 +378,19 @@ static struct tegra_regulator_coupler tegra30_coupler = {
.
detach_regulator
=
tegra30_regulator_detach
,
.
balance_voltage
=
tegra30_regulator_balance_voltage
,
},
.
reboot_notifier
.
notifier_call
=
tegra30_regulator_reboot
,
};
static
int
__init
tegra_regulator_coupler_init
(
void
)
{
int
err
;
if
(
!
of_machine_is_compatible
(
"nvidia,tegra30"
))
return
0
;
err
=
register_reboot_notifier
(
&
tegra30_coupler
.
reboot_notifier
);
WARN_ON
(
err
);
return
regulator_coupler_register
(
&
tegra30_coupler
.
coupler
);
}
arch_initcall
(
tegra_regulator_coupler_init
);
include/linux/regulator/driver.h
View file @
87d7426f
...
...
@@ -540,6 +540,7 @@ int regulator_set_current_limit_regmap(struct regulator_dev *rdev,
int
regulator_get_current_limit_regmap
(
struct
regulator_dev
*
rdev
);
void
*
regulator_get_init_drvdata
(
struct
regulator_init_data
*
reg_init_data
);
int
regulator_set_ramp_delay_regmap
(
struct
regulator_dev
*
rdev
,
int
ramp_delay
);
int
regulator_sync_voltage_rdev
(
struct
regulator_dev
*
rdev
);
/*
* Helper functions intended to be used by regulator drivers prior registering
...
...
include/soc/tegra/common.h
View file @
87d7426f
...
...
@@ -6,6 +6,37 @@
#ifndef __SOC_TEGRA_COMMON_H__
#define __SOC_TEGRA_COMMON_H__
#include <linux/errno.h>
#include <linux/types.h>
struct
device
;
/**
* Tegra SoC core device OPP table configuration
*
* @init_state: pre-initialize OPP state of a device
*/
struct
tegra_core_opp_params
{
bool
init_state
;
};
#ifdef CONFIG_ARCH_TEGRA
bool
soc_is_tegra
(
void
);
int
devm_tegra_core_dev_init_opp_table
(
struct
device
*
dev
,
struct
tegra_core_opp_params
*
params
);
#else
static
inline
bool
soc_is_tegra
(
void
)
{
return
false
;
}
static
inline
int
devm_tegra_core_dev_init_opp_table
(
struct
device
*
dev
,
struct
tegra_core_opp_params
*
params
)
{
return
-
ENODEV
;
}
#endif
#endif
/* __SOC_TEGRA_COMMON_H__ */
include/soc/tegra/fuse.h
View file @
87d7426f
...
...
@@ -52,14 +52,28 @@ struct tegra_sku_info {
enum
tegra_revision
revision
;
};
#ifdef CONFIG_ARCH_TEGRA
extern
struct
tegra_sku_info
tegra_sku_info
;
u32
tegra_read_straps
(
void
);
u32
tegra_read_ram_code
(
void
);
int
tegra_fuse_readl
(
unsigned
long
offset
,
u32
*
value
);
#ifdef CONFIG_ARCH_TEGRA
extern
struct
tegra_sku_info
tegra_sku_info
;
#else
static
struct
tegra_sku_info
tegra_sku_info
__maybe_unused
;
static
inline
u32
tegra_read_straps
(
void
)
{
return
0
;
}
static
inline
u32
tegra_read_ram_code
(
void
)
{
return
0
;
}
static
inline
int
tegra_fuse_readl
(
unsigned
long
offset
,
u32
*
value
)
{
return
-
ENODEV
;
}
#endif
struct
device
*
tegra_soc_device_register
(
void
);
...
...
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