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
d5a4dfc3
Commit
d5a4dfc3
authored
Aug 25, 2022
by
Hans de Goede
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'platform-drivers-x86-amd-pmf' into pdx86-base
parents
568035b0
ea522b80
Changes
10
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
1488 additions
and
0 deletions
+1488
-0
MAINTAINERS
MAINTAINERS
+6
-0
drivers/platform/x86/amd/Kconfig
drivers/platform/x86/amd/Kconfig
+2
-0
drivers/platform/x86/amd/Makefile
drivers/platform/x86/amd/Makefile
+1
-0
drivers/platform/x86/amd/pmf/Kconfig
drivers/platform/x86/amd/pmf/Kconfig
+16
-0
drivers/platform/x86/amd/pmf/Makefile
drivers/platform/x86/amd/pmf/Makefile
+9
-0
drivers/platform/x86/amd/pmf/acpi.c
drivers/platform/x86/amd/pmf/acpi.c
+288
-0
drivers/platform/x86/amd/pmf/auto-mode.c
drivers/platform/x86/amd/pmf/auto-mode.c
+305
-0
drivers/platform/x86/amd/pmf/core.c
drivers/platform/x86/amd/pmf/core.c
+388
-0
drivers/platform/x86/amd/pmf/pmf.h
drivers/platform/x86/amd/pmf/pmf.h
+327
-0
drivers/platform/x86/amd/pmf/sps.c
drivers/platform/x86/amd/pmf/sps.c
+146
-0
No files found.
MAINTAINERS
View file @
d5a4dfc3
...
...
@@ -1022,6 +1022,12 @@ L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/amd/pmc.c
AMD PMF DRIVER
M: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/amd/pmf/
AMD HSMP DRIVER
M: Naveen Krishna Chatradhi <naveenkrishna.chatradhi@amd.com>
R: Carlos Bilbao <carlos.bilbao@amd.com>
...
...
drivers/platform/x86/amd/Kconfig
View file @
d5a4dfc3
...
...
@@ -3,6 +3,8 @@
# AMD x86 Platform Specific Drivers
#
source "drivers/platform/x86/amd/pmf/Kconfig"
config AMD_PMC
tristate "AMD SoC PMC driver"
depends on ACPI && PCI && RTC_CLASS
...
...
drivers/platform/x86/amd/Makefile
View file @
d5a4dfc3
...
...
@@ -8,3 +8,4 @@ amd-pmc-y := pmc.o
obj-$(CONFIG_AMD_PMC)
+=
amd-pmc.o
amd_hsmp-y
:=
hsmp.o
obj-$(CONFIG_AMD_HSMP)
+=
amd_hsmp.o
obj-$(CONFIG_AMD_PMF)
+=
pmf/
drivers/platform/x86/amd/pmf/Kconfig
0 → 100644
View file @
d5a4dfc3
# SPDX-License-Identifier: GPL-2.0-only
#
# AMD PMF Driver
#
config AMD_PMF
tristate "AMD Platform Management Framework"
depends on ACPI && PCI
select ACPI_PLATFORM_PROFILE
help
This driver provides support for the AMD Platform Management Framework.
The goal is to enhance end user experience by making AMD PCs smarter,
quiter, power efficient by adapting to user behavior and environment.
To compile this driver as a module, choose M here: the module will
be called amd_pmf.
drivers/platform/x86/amd/pmf/Makefile
0 → 100644
View file @
d5a4dfc3
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for linux/drivers/platform/x86/amd/pmf
# AMD Platform Management Framework
#
obj-$(CONFIG_AMD_PMF)
+=
amd-pmf.o
amd-pmf-objs
:=
core.o acpi.o sps.o
\
auto-mode.o
drivers/platform/x86/amd/pmf/acpi.c
0 → 100644
View file @
d5a4dfc3
// SPDX-License-Identifier: GPL-2.0
/*
* AMD Platform Management Framework Driver
*
* Copyright (c) 2022, Advanced Micro Devices, Inc.
* All Rights Reserved.
*
* Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
*/
#include <linux/acpi.h>
#include "pmf.h"
#define APMF_CQL_NOTIFICATION 2
#define APMF_AMT_NOTIFICATION 3
static
union
acpi_object
*
apmf_if_call
(
struct
amd_pmf_dev
*
pdev
,
int
fn
,
struct
acpi_buffer
*
param
)
{
struct
acpi_buffer
buffer
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
acpi_handle
ahandle
=
ACPI_HANDLE
(
pdev
->
dev
);
struct
acpi_object_list
apmf_if_arg_list
;
union
acpi_object
apmf_if_args
[
2
];
acpi_status
status
;
apmf_if_arg_list
.
count
=
2
;
apmf_if_arg_list
.
pointer
=
&
apmf_if_args
[
0
];
apmf_if_args
[
0
].
type
=
ACPI_TYPE_INTEGER
;
apmf_if_args
[
0
].
integer
.
value
=
fn
;
if
(
param
)
{
apmf_if_args
[
1
].
type
=
ACPI_TYPE_BUFFER
;
apmf_if_args
[
1
].
buffer
.
length
=
param
->
length
;
apmf_if_args
[
1
].
buffer
.
pointer
=
param
->
pointer
;
}
else
{
apmf_if_args
[
1
].
type
=
ACPI_TYPE_INTEGER
;
apmf_if_args
[
1
].
integer
.
value
=
0
;
}
status
=
acpi_evaluate_object
(
ahandle
,
"APMF"
,
&
apmf_if_arg_list
,
&
buffer
);
if
(
ACPI_FAILURE
(
status
))
{
dev_err
(
pdev
->
dev
,
"APMF method:%d call failed
\n
"
,
fn
);
kfree
(
buffer
.
pointer
);
return
NULL
;
}
return
buffer
.
pointer
;
}
static
int
apmf_if_call_store_buffer
(
struct
amd_pmf_dev
*
pdev
,
int
fn
,
void
*
dest
,
size_t
out_sz
)
{
union
acpi_object
*
info
;
size_t
size
;
int
err
=
0
;
info
=
apmf_if_call
(
pdev
,
fn
,
NULL
);
if
(
!
info
)
return
-
EIO
;
if
(
info
->
type
!=
ACPI_TYPE_BUFFER
)
{
dev_err
(
pdev
->
dev
,
"object is not a buffer
\n
"
);
err
=
-
EINVAL
;
goto
out
;
}
if
(
info
->
buffer
.
length
<
2
)
{
dev_err
(
pdev
->
dev
,
"buffer too small
\n
"
);
err
=
-
EINVAL
;
goto
out
;
}
size
=
*
(
u16
*
)
info
->
buffer
.
pointer
;
if
(
info
->
buffer
.
length
<
size
)
{
dev_err
(
pdev
->
dev
,
"buffer smaller then headersize %u < %zu
\n
"
,
info
->
buffer
.
length
,
size
);
err
=
-
EINVAL
;
goto
out
;
}
if
(
size
<
out_sz
)
{
dev_err
(
pdev
->
dev
,
"buffer too small %zu
\n
"
,
size
);
err
=
-
EINVAL
;
goto
out
;
}
memcpy
(
dest
,
info
->
buffer
.
pointer
,
out_sz
);
out:
kfree
(
info
);
return
err
;
}
int
is_apmf_func_supported
(
struct
amd_pmf_dev
*
pdev
,
unsigned
long
index
)
{
/* If bit-n is set, that indicates function n+1 is supported */
return
!!
(
pdev
->
supported_func
&
BIT
(
index
-
1
));
}
int
apmf_get_static_slider_granular
(
struct
amd_pmf_dev
*
pdev
,
struct
apmf_static_slider_granular_output
*
data
)
{
if
(
!
is_apmf_func_supported
(
pdev
,
APMF_FUNC_STATIC_SLIDER_GRANULAR
))
return
-
EINVAL
;
return
apmf_if_call_store_buffer
(
pdev
,
APMF_FUNC_STATIC_SLIDER_GRANULAR
,
data
,
sizeof
(
*
data
));
}
static
void
apmf_sbios_heartbeat_notify
(
struct
work_struct
*
work
)
{
struct
amd_pmf_dev
*
dev
=
container_of
(
work
,
struct
amd_pmf_dev
,
heart_beat
.
work
);
union
acpi_object
*
info
;
dev_dbg
(
dev
->
dev
,
"Sending heartbeat to SBIOS
\n
"
);
info
=
apmf_if_call
(
dev
,
APMF_FUNC_SBIOS_HEARTBEAT
,
NULL
);
if
(
!
info
)
goto
out
;
schedule_delayed_work
(
&
dev
->
heart_beat
,
msecs_to_jiffies
(
dev
->
hb_interval
*
1000
));
out:
kfree
(
info
);
}
int
apmf_update_fan_idx
(
struct
amd_pmf_dev
*
pdev
,
bool
manual
,
u32
idx
)
{
union
acpi_object
*
info
;
struct
apmf_fan_idx
args
;
struct
acpi_buffer
params
;
int
err
=
0
;
args
.
size
=
sizeof
(
args
);
args
.
fan_ctl_mode
=
manual
;
args
.
fan_ctl_idx
=
idx
;
params
.
length
=
sizeof
(
args
);
params
.
pointer
=
(
void
*
)
&
args
;
info
=
apmf_if_call
(
pdev
,
APMF_FUNC_SET_FAN_IDX
,
&
params
);
if
(
!
info
)
{
err
=
-
EIO
;
goto
out
;
}
out:
kfree
(
info
);
return
err
;
}
int
apmf_get_auto_mode_def
(
struct
amd_pmf_dev
*
pdev
,
struct
apmf_auto_mode
*
data
)
{
return
apmf_if_call_store_buffer
(
pdev
,
APMF_FUNC_AUTO_MODE
,
data
,
sizeof
(
*
data
));
}
int
apmf_get_sbios_requests
(
struct
amd_pmf_dev
*
pdev
,
struct
apmf_sbios_req
*
req
)
{
return
apmf_if_call_store_buffer
(
pdev
,
APMF_FUNC_SBIOS_REQUESTS
,
req
,
sizeof
(
*
req
));
}
static
void
apmf_event_handler
(
acpi_handle
handle
,
u32
event
,
void
*
data
)
{
struct
amd_pmf_dev
*
pmf_dev
=
data
;
struct
apmf_sbios_req
req
;
int
ret
;
mutex_lock
(
&
pmf_dev
->
update_mutex
);
ret
=
apmf_get_sbios_requests
(
pmf_dev
,
&
req
);
if
(
ret
)
{
dev_err
(
pmf_dev
->
dev
,
"Failed to get SBIOS requests:%d
\n
"
,
ret
);
goto
out
;
}
if
(
req
.
pending_req
&
BIT
(
APMF_AMT_NOTIFICATION
))
{
dev_dbg
(
pmf_dev
->
dev
,
"AMT is supported and notifications %s
\n
"
,
req
.
amt_event
?
"Enabled"
:
"Disabled"
);
pmf_dev
->
amt_enabled
=
!!
req
.
amt_event
;
if
(
pmf_dev
->
amt_enabled
)
amd_pmf_handle_amt
(
pmf_dev
);
else
amd_pmf_reset_amt
(
pmf_dev
);
}
if
(
req
.
pending_req
&
BIT
(
APMF_CQL_NOTIFICATION
))
{
dev_dbg
(
pmf_dev
->
dev
,
"CQL is supported and notifications %s
\n
"
,
req
.
cql_event
?
"Enabled"
:
"Disabled"
);
/* update the target mode information */
if
(
pmf_dev
->
amt_enabled
)
amd_pmf_update_2_cql
(
pmf_dev
,
req
.
cql_event
);
}
out:
mutex_unlock
(
&
pmf_dev
->
update_mutex
);
}
static
int
apmf_if_verify_interface
(
struct
amd_pmf_dev
*
pdev
)
{
struct
apmf_verify_interface
output
;
int
err
;
err
=
apmf_if_call_store_buffer
(
pdev
,
APMF_FUNC_VERIFY_INTERFACE
,
&
output
,
sizeof
(
output
));
if
(
err
)
return
err
;
pdev
->
supported_func
=
output
.
supported_functions
;
dev_dbg
(
pdev
->
dev
,
"supported functions:0x%x notifications:0x%x
\n
"
,
output
.
supported_functions
,
output
.
notification_mask
);
return
0
;
}
static
int
apmf_get_system_params
(
struct
amd_pmf_dev
*
dev
)
{
struct
apmf_system_params
params
;
int
err
;
if
(
!
is_apmf_func_supported
(
dev
,
APMF_FUNC_GET_SYS_PARAMS
))
return
-
EINVAL
;
err
=
apmf_if_call_store_buffer
(
dev
,
APMF_FUNC_GET_SYS_PARAMS
,
&
params
,
sizeof
(
params
));
if
(
err
)
return
err
;
dev_dbg
(
dev
->
dev
,
"system params mask:0x%x flags:0x%x cmd_code:0x%x heartbeat:%d
\n
"
,
params
.
valid_mask
,
params
.
flags
,
params
.
command_code
,
params
.
heartbeat_int
);
params
.
flags
=
params
.
flags
&
params
.
valid_mask
;
dev
->
hb_interval
=
params
.
heartbeat_int
;
return
0
;
}
void
apmf_acpi_deinit
(
struct
amd_pmf_dev
*
pmf_dev
)
{
acpi_handle
ahandle
=
ACPI_HANDLE
(
pmf_dev
->
dev
);
if
(
pmf_dev
->
hb_interval
)
cancel_delayed_work_sync
(
&
pmf_dev
->
heart_beat
);
if
(
is_apmf_func_supported
(
pmf_dev
,
APMF_FUNC_AUTO_MODE
)
&&
is_apmf_func_supported
(
pmf_dev
,
APMF_FUNC_SBIOS_REQUESTS
))
acpi_remove_notify_handler
(
ahandle
,
ACPI_ALL_NOTIFY
,
apmf_event_handler
);
}
int
apmf_acpi_init
(
struct
amd_pmf_dev
*
pmf_dev
)
{
acpi_handle
ahandle
=
ACPI_HANDLE
(
pmf_dev
->
dev
);
acpi_status
status
;
int
ret
;
ret
=
apmf_if_verify_interface
(
pmf_dev
);
if
(
ret
)
{
dev_err
(
pmf_dev
->
dev
,
"APMF verify interface failed :%d
\n
"
,
ret
);
goto
out
;
}
ret
=
apmf_get_system_params
(
pmf_dev
);
if
(
ret
)
{
dev_err
(
pmf_dev
->
dev
,
"APMF apmf_get_system_params failed :%d
\n
"
,
ret
);
goto
out
;
}
if
(
pmf_dev
->
hb_interval
)
{
/* send heartbeats only if the interval is not zero */
INIT_DELAYED_WORK
(
&
pmf_dev
->
heart_beat
,
apmf_sbios_heartbeat_notify
);
schedule_delayed_work
(
&
pmf_dev
->
heart_beat
,
0
);
}
/* Install the APMF Notify handler */
if
(
is_apmf_func_supported
(
pmf_dev
,
APMF_FUNC_AUTO_MODE
)
&&
is_apmf_func_supported
(
pmf_dev
,
APMF_FUNC_SBIOS_REQUESTS
))
{
status
=
acpi_install_notify_handler
(
ahandle
,
ACPI_ALL_NOTIFY
,
apmf_event_handler
,
pmf_dev
);
if
(
ACPI_FAILURE
(
status
))
{
dev_err
(
pmf_dev
->
dev
,
"failed to install notify handler
\n
"
);
return
-
ENODEV
;
}
/* Call the handler once manually to catch up with possibly missed notifies. */
apmf_event_handler
(
ahandle
,
0
,
pmf_dev
);
}
out:
return
ret
;
}
drivers/platform/x86/amd/pmf/auto-mode.c
0 → 100644
View file @
d5a4dfc3
This diff is collapsed.
Click to expand it.
drivers/platform/x86/amd/pmf/core.c
0 → 100644
View file @
d5a4dfc3
This diff is collapsed.
Click to expand it.
drivers/platform/x86/amd/pmf/pmf.h
0 → 100644
View file @
d5a4dfc3
/* SPDX-License-Identifier: GPL-2.0 */
/*
* AMD Platform Management Framework Driver
*
* Copyright (c) 2022, Advanced Micro Devices, Inc.
* All Rights Reserved.
*
* Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
*/
#ifndef PMF_H
#define PMF_H
#include <linux/acpi.h>
#include <linux/platform_profile.h>
/* APMF Functions */
#define APMF_FUNC_VERIFY_INTERFACE 0
#define APMF_FUNC_GET_SYS_PARAMS 1
#define APMF_FUNC_SBIOS_REQUESTS 2
#define APMF_FUNC_SBIOS_HEARTBEAT 4
#define APMF_FUNC_AUTO_MODE 5
#define APMF_FUNC_SET_FAN_IDX 7
#define APMF_FUNC_STATIC_SLIDER_GRANULAR 9
/* Message Definitions */
#define SET_SPL 0x03
/* SPL: Sustained Power Limit */
#define SET_SPPT 0x05
/* SPPT: Slow Package Power Tracking */
#define SET_FPPT 0x07
/* FPPT: Fast Package Power Tracking */
#define GET_SPL 0x0B
#define GET_SPPT 0x0D
#define GET_FPPT 0x0F
#define SET_DRAM_ADDR_HIGH 0x14
#define SET_DRAM_ADDR_LOW 0x15
#define SET_TRANSFER_TABLE 0x16
#define SET_STT_MIN_LIMIT 0x18
/* STT: Skin Temperature Tracking */
#define SET_STT_LIMIT_APU 0x19
#define SET_STT_LIMIT_HS2 0x1A
#define SET_SPPT_APU_ONLY 0x1D
#define GET_SPPT_APU_ONLY 0x1E
#define GET_STT_MIN_LIMIT 0x1F
#define GET_STT_LIMIT_APU 0x20
#define GET_STT_LIMIT_HS2 0x21
/* Fan Index for Auto Mode */
#define FAN_INDEX_AUTO 0xFFFFFFFF
#define ARG_NONE 0
#define AVG_SAMPLE_SIZE 3
/* AMD PMF BIOS interfaces */
struct
apmf_verify_interface
{
u16
size
;
u16
version
;
u32
notification_mask
;
u32
supported_functions
;
}
__packed
;
struct
apmf_system_params
{
u16
size
;
u32
valid_mask
;
u32
flags
;
u8
command_code
;
u32
heartbeat_int
;
}
__packed
;
struct
apmf_sbios_req
{
u16
size
;
u32
pending_req
;
u8
rsd
;
u8
cql_event
;
u8
amt_event
;
u32
fppt
;
u32
sppt
;
u32
fppt_apu_only
;
u32
spl
;
u32
stt_min_limit
;
u8
skin_temp_apu
;
u8
skin_temp_hs2
;
}
__packed
;
struct
apmf_fan_idx
{
u16
size
;
u8
fan_ctl_mode
;
u32
fan_ctl_idx
;
}
__packed
;
struct
smu_pmf_metrics
{
u16
gfxclk_freq
;
/* in MHz */
u16
socclk_freq
;
/* in MHz */
u16
vclk_freq
;
/* in MHz */
u16
dclk_freq
;
/* in MHz */
u16
memclk_freq
;
/* in MHz */
u16
spare
;
u16
gfx_activity
;
/* in Centi */
u16
uvd_activity
;
/* in Centi */
u16
voltage
[
2
];
/* in mV */
u16
currents
[
2
];
/* in mA */
u16
power
[
2
];
/* in mW */
u16
core_freq
[
8
];
/* in MHz */
u16
core_power
[
8
];
/* in mW */
u16
core_temp
[
8
];
/* in centi-Celsius */
u16
l3_freq
;
/* in MHz */
u16
l3_temp
;
/* in centi-Celsius */
u16
gfx_temp
;
/* in centi-Celsius */
u16
soc_temp
;
/* in centi-Celsius */
u16
throttler_status
;
u16
current_socketpower
;
/* in mW */
u16
stapm_orig_limit
;
/* in W */
u16
stapm_cur_limit
;
/* in W */
u32
apu_power
;
/* in mW */
u32
dgpu_power
;
/* in mW */
u16
vdd_tdc_val
;
/* in mA */
u16
soc_tdc_val
;
/* in mA */
u16
vdd_edc_val
;
/* in mA */
u16
soc_edcv_al
;
/* in mA */
u16
infra_cpu_maxfreq
;
/* in MHz */
u16
infra_gfx_maxfreq
;
/* in MHz */
u16
skin_temp
;
/* in centi-Celsius */
u16
device_state
;
}
__packed
;
enum
amd_stt_skin_temp
{
STT_TEMP_APU
,
STT_TEMP_HS2
,
STT_TEMP_COUNT
,
};
enum
amd_slider_op
{
SLIDER_OP_GET
,
SLIDER_OP_SET
,
};
enum
power_source
{
POWER_SOURCE_AC
,
POWER_SOURCE_DC
,
POWER_SOURCE_MAX
,
};
enum
power_modes
{
POWER_MODE_PERFORMANCE
,
POWER_MODE_BALANCED_POWER
,
POWER_MODE_POWER_SAVER
,
POWER_MODE_MAX
,
};
struct
amd_pmf_dev
{
void
__iomem
*
regbase
;
void
__iomem
*
smu_virt_addr
;
void
*
buf
;
u32
base_addr
;
u32
cpu_id
;
struct
device
*
dev
;
struct
mutex
lock
;
/* protects the PMF interface */
u32
supported_func
;
enum
platform_profile_option
current_profile
;
struct
platform_profile_handler
pprof
;
struct
dentry
*
dbgfs_dir
;
int
hb_interval
;
/* SBIOS heartbeat interval */
struct
delayed_work
heart_beat
;
struct
smu_pmf_metrics
m_table
;
struct
delayed_work
work_buffer
;
ktime_t
start_time
;
int
socket_power_history
[
AVG_SAMPLE_SIZE
];
int
socket_power_history_idx
;
bool
amt_enabled
;
struct
mutex
update_mutex
;
/* protects race between ACPI handler and metrics thread */
};
struct
apmf_sps_prop_granular
{
u32
fppt
;
u32
sppt
;
u32
sppt_apu_only
;
u32
spl
;
u32
stt_min
;
u8
stt_skin_temp
[
STT_TEMP_COUNT
];
u32
fan_id
;
}
__packed
;
/* Static Slider */
struct
apmf_static_slider_granular_output
{
u16
size
;
struct
apmf_sps_prop_granular
prop
[
POWER_SOURCE_MAX
*
POWER_MODE_MAX
];
}
__packed
;
struct
amd_pmf_static_slider_granular
{
u16
size
;
struct
apmf_sps_prop_granular
prop
[
POWER_SOURCE_MAX
][
POWER_MODE_MAX
];
};
struct
fan_table_control
{
bool
manual
;
unsigned
long
fan_id
;
};
struct
power_table_control
{
u32
spl
;
u32
sppt
;
u32
fppt
;
u32
sppt_apu_only
;
u32
stt_min
;
u32
stt_skin_temp
[
STT_TEMP_COUNT
];
u32
reserved
[
16
];
};
/* Auto Mode Layer */
enum
auto_mode_transition_priority
{
AUTO_TRANSITION_TO_PERFORMANCE
,
/* Any other mode to Performance Mode */
AUTO_TRANSITION_FROM_QUIET_TO_BALANCE
,
/* Quiet Mode to Balance Mode */
AUTO_TRANSITION_TO_QUIET
,
/* Any other mode to Quiet Mode */
AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE
,
/* Performance Mode to Balance Mode */
AUTO_TRANSITION_MAX
,
};
enum
auto_mode_mode
{
AUTO_QUIET
,
AUTO_BALANCE
,
AUTO_PERFORMANCE_ON_LAP
,
AUTO_PERFORMANCE
,
AUTO_MODE_MAX
,
};
struct
auto_mode_trans_params
{
u32
time_constant
;
/* minimum time required to switch to next mode */
u32
power_delta
;
/* delta power to shift mode */
u32
power_threshold
;
u32
timer
;
/* elapsed time. if timer > TimeThreshold, it will move to next mode */
u32
applied
;
enum
auto_mode_mode
target_mode
;
u32
shifting_up
;
};
struct
auto_mode_mode_settings
{
struct
power_table_control
power_control
;
struct
fan_table_control
fan_control
;
u32
power_floor
;
};
struct
auto_mode_mode_config
{
struct
auto_mode_trans_params
transition
[
AUTO_TRANSITION_MAX
];
struct
auto_mode_mode_settings
mode_set
[
AUTO_MODE_MAX
];
enum
auto_mode_mode
current_mode
;
};
struct
apmf_auto_mode
{
u16
size
;
/* time constant */
u32
balanced_to_perf
;
u32
perf_to_balanced
;
u32
quiet_to_balanced
;
u32
balanced_to_quiet
;
/* power floor */
u32
pfloor_perf
;
u32
pfloor_balanced
;
u32
pfloor_quiet
;
/* Power delta for mode change */
u32
pd_balanced_to_perf
;
u32
pd_perf_to_balanced
;
u32
pd_quiet_to_balanced
;
u32
pd_balanced_to_quiet
;
/* skin temperature limits */
u8
stt_apu_perf_on_lap
;
/* CQL ON */
u8
stt_hs2_perf_on_lap
;
/* CQL ON */
u8
stt_apu_perf
;
u8
stt_hs2_perf
;
u8
stt_apu_balanced
;
u8
stt_hs2_balanced
;
u8
stt_apu_quiet
;
u8
stt_hs2_quiet
;
u32
stt_min_limit_perf_on_lap
;
/* CQL ON */
u32
stt_min_limit_perf
;
u32
stt_min_limit_balanced
;
u32
stt_min_limit_quiet
;
/* SPL based */
u32
fppt_perf_on_lap
;
/* CQL ON */
u32
sppt_perf_on_lap
;
/* CQL ON */
u32
spl_perf_on_lap
;
/* CQL ON */
u32
sppt_apu_only_perf_on_lap
;
/* CQL ON */
u32
fppt_perf
;
u32
sppt_perf
;
u32
spl_perf
;
u32
sppt_apu_only_perf
;
u32
fppt_balanced
;
u32
sppt_balanced
;
u32
spl_balanced
;
u32
sppt_apu_only_balanced
;
u32
fppt_quiet
;
u32
sppt_quiet
;
u32
spl_quiet
;
u32
sppt_apu_only_quiet
;
/* Fan ID */
u32
fan_id_perf
;
u32
fan_id_balanced
;
u32
fan_id_quiet
;
}
__packed
;
/* Core Layer */
int
apmf_acpi_init
(
struct
amd_pmf_dev
*
pmf_dev
);
void
apmf_acpi_deinit
(
struct
amd_pmf_dev
*
pmf_dev
);
int
is_apmf_func_supported
(
struct
amd_pmf_dev
*
pdev
,
unsigned
long
index
);
int
amd_pmf_send_cmd
(
struct
amd_pmf_dev
*
dev
,
u8
message
,
bool
get
,
u32
arg
,
u32
*
data
);
int
amd_pmf_init_metrics_table
(
struct
amd_pmf_dev
*
dev
);
int
amd_pmf_get_power_source
(
void
);
/* SPS Layer */
int
amd_pmf_get_pprof_modes
(
struct
amd_pmf_dev
*
pmf
);
void
amd_pmf_update_slider
(
struct
amd_pmf_dev
*
dev
,
bool
op
,
int
idx
,
struct
amd_pmf_static_slider_granular
*
table
);
int
amd_pmf_init_sps
(
struct
amd_pmf_dev
*
dev
);
void
amd_pmf_deinit_sps
(
struct
amd_pmf_dev
*
dev
);
int
apmf_get_static_slider_granular
(
struct
amd_pmf_dev
*
pdev
,
struct
apmf_static_slider_granular_output
*
output
);
int
apmf_update_fan_idx
(
struct
amd_pmf_dev
*
pdev
,
bool
manual
,
u32
idx
);
/* Auto Mode Layer */
int
apmf_get_auto_mode_def
(
struct
amd_pmf_dev
*
pdev
,
struct
apmf_auto_mode
*
data
);
void
amd_pmf_init_auto_mode
(
struct
amd_pmf_dev
*
dev
);
void
amd_pmf_deinit_auto_mode
(
struct
amd_pmf_dev
*
dev
);
void
amd_pmf_trans_automode
(
struct
amd_pmf_dev
*
dev
,
int
socket_power
,
ktime_t
time_elapsed_ms
);
int
apmf_get_sbios_requests
(
struct
amd_pmf_dev
*
pdev
,
struct
apmf_sbios_req
*
req
);
void
amd_pmf_update_2_cql
(
struct
amd_pmf_dev
*
dev
,
bool
is_cql_event
);
int
amd_pmf_reset_amt
(
struct
amd_pmf_dev
*
dev
);
void
amd_pmf_handle_amt
(
struct
amd_pmf_dev
*
dev
);
#endif
/* PMF_H */
drivers/platform/x86/amd/pmf/sps.c
0 → 100644
View file @
d5a4dfc3
// SPDX-License-Identifier: GPL-2.0
/*
* AMD Platform Management Framework (PMF) Driver
*
* Copyright (c) 2022, Advanced Micro Devices, Inc.
* All Rights Reserved.
*
* Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
*/
#include "pmf.h"
static
struct
amd_pmf_static_slider_granular
config_store
;
static
void
amd_pmf_load_defaults_sps
(
struct
amd_pmf_dev
*
dev
)
{
struct
apmf_static_slider_granular_output
output
;
int
i
,
j
,
idx
=
0
;
memset
(
&
config_store
,
0
,
sizeof
(
config_store
));
apmf_get_static_slider_granular
(
dev
,
&
output
);
for
(
i
=
0
;
i
<
POWER_SOURCE_MAX
;
i
++
)
{
for
(
j
=
0
;
j
<
POWER_MODE_MAX
;
j
++
)
{
config_store
.
prop
[
i
][
j
].
spl
=
output
.
prop
[
idx
].
spl
;
config_store
.
prop
[
i
][
j
].
sppt
=
output
.
prop
[
idx
].
sppt
;
config_store
.
prop
[
i
][
j
].
sppt_apu_only
=
output
.
prop
[
idx
].
sppt_apu_only
;
config_store
.
prop
[
i
][
j
].
fppt
=
output
.
prop
[
idx
].
fppt
;
config_store
.
prop
[
i
][
j
].
stt_min
=
output
.
prop
[
idx
].
stt_min
;
config_store
.
prop
[
i
][
j
].
stt_skin_temp
[
STT_TEMP_APU
]
=
output
.
prop
[
idx
].
stt_skin_temp
[
STT_TEMP_APU
];
config_store
.
prop
[
i
][
j
].
stt_skin_temp
[
STT_TEMP_HS2
]
=
output
.
prop
[
idx
].
stt_skin_temp
[
STT_TEMP_HS2
];
config_store
.
prop
[
i
][
j
].
fan_id
=
output
.
prop
[
idx
].
fan_id
;
idx
++
;
}
}
}
void
amd_pmf_update_slider
(
struct
amd_pmf_dev
*
dev
,
bool
op
,
int
idx
,
struct
amd_pmf_static_slider_granular
*
table
)
{
int
src
=
amd_pmf_get_power_source
();
if
(
op
==
SLIDER_OP_SET
)
{
amd_pmf_send_cmd
(
dev
,
SET_SPL
,
false
,
config_store
.
prop
[
src
][
idx
].
spl
,
NULL
);
amd_pmf_send_cmd
(
dev
,
SET_FPPT
,
false
,
config_store
.
prop
[
src
][
idx
].
fppt
,
NULL
);
amd_pmf_send_cmd
(
dev
,
SET_SPPT
,
false
,
config_store
.
prop
[
src
][
idx
].
sppt
,
NULL
);
amd_pmf_send_cmd
(
dev
,
SET_SPPT_APU_ONLY
,
false
,
config_store
.
prop
[
src
][
idx
].
sppt_apu_only
,
NULL
);
amd_pmf_send_cmd
(
dev
,
SET_STT_MIN_LIMIT
,
false
,
config_store
.
prop
[
src
][
idx
].
stt_min
,
NULL
);
amd_pmf_send_cmd
(
dev
,
SET_STT_LIMIT_APU
,
false
,
config_store
.
prop
[
src
][
idx
].
stt_skin_temp
[
STT_TEMP_APU
],
NULL
);
amd_pmf_send_cmd
(
dev
,
SET_STT_LIMIT_HS2
,
false
,
config_store
.
prop
[
src
][
idx
].
stt_skin_temp
[
STT_TEMP_HS2
],
NULL
);
}
else
if
(
op
==
SLIDER_OP_GET
)
{
amd_pmf_send_cmd
(
dev
,
GET_SPL
,
true
,
ARG_NONE
,
&
table
->
prop
[
src
][
idx
].
spl
);
amd_pmf_send_cmd
(
dev
,
GET_FPPT
,
true
,
ARG_NONE
,
&
table
->
prop
[
src
][
idx
].
fppt
);
amd_pmf_send_cmd
(
dev
,
GET_SPPT
,
true
,
ARG_NONE
,
&
table
->
prop
[
src
][
idx
].
sppt
);
amd_pmf_send_cmd
(
dev
,
GET_SPPT_APU_ONLY
,
true
,
ARG_NONE
,
&
table
->
prop
[
src
][
idx
].
sppt_apu_only
);
amd_pmf_send_cmd
(
dev
,
GET_STT_MIN_LIMIT
,
true
,
ARG_NONE
,
&
table
->
prop
[
src
][
idx
].
stt_min
);
amd_pmf_send_cmd
(
dev
,
GET_STT_LIMIT_APU
,
true
,
ARG_NONE
,
(
u32
*
)
&
table
->
prop
[
src
][
idx
].
stt_skin_temp
[
STT_TEMP_APU
]);
amd_pmf_send_cmd
(
dev
,
GET_STT_LIMIT_HS2
,
true
,
ARG_NONE
,
(
u32
*
)
&
table
->
prop
[
src
][
idx
].
stt_skin_temp
[
STT_TEMP_HS2
]);
}
}
static
int
amd_pmf_profile_get
(
struct
platform_profile_handler
*
pprof
,
enum
platform_profile_option
*
profile
)
{
struct
amd_pmf_dev
*
pmf
=
container_of
(
pprof
,
struct
amd_pmf_dev
,
pprof
);
*
profile
=
pmf
->
current_profile
;
return
0
;
}
int
amd_pmf_get_pprof_modes
(
struct
amd_pmf_dev
*
pmf
)
{
int
mode
;
switch
(
pmf
->
current_profile
)
{
case
PLATFORM_PROFILE_PERFORMANCE
:
mode
=
POWER_MODE_PERFORMANCE
;
break
;
case
PLATFORM_PROFILE_BALANCED
:
mode
=
POWER_MODE_BALANCED_POWER
;
break
;
case
PLATFORM_PROFILE_LOW_POWER
:
mode
=
POWER_MODE_POWER_SAVER
;
break
;
default:
dev_err
(
pmf
->
dev
,
"Unknown Platform Profile.
\n
"
);
return
-
EOPNOTSUPP
;
}
return
mode
;
}
static
int
amd_pmf_profile_set
(
struct
platform_profile_handler
*
pprof
,
enum
platform_profile_option
profile
)
{
struct
amd_pmf_dev
*
pmf
=
container_of
(
pprof
,
struct
amd_pmf_dev
,
pprof
);
int
mode
;
pmf
->
current_profile
=
profile
;
mode
=
amd_pmf_get_pprof_modes
(
pmf
);
if
(
mode
<
0
)
return
mode
;
amd_pmf_update_slider
(
pmf
,
SLIDER_OP_SET
,
mode
,
NULL
);
return
0
;
}
int
amd_pmf_init_sps
(
struct
amd_pmf_dev
*
dev
)
{
int
err
;
dev
->
current_profile
=
PLATFORM_PROFILE_BALANCED
;
amd_pmf_load_defaults_sps
(
dev
);
dev
->
pprof
.
profile_get
=
amd_pmf_profile_get
;
dev
->
pprof
.
profile_set
=
amd_pmf_profile_set
;
/* Setup supported modes */
set_bit
(
PLATFORM_PROFILE_LOW_POWER
,
dev
->
pprof
.
choices
);
set_bit
(
PLATFORM_PROFILE_BALANCED
,
dev
->
pprof
.
choices
);
set_bit
(
PLATFORM_PROFILE_PERFORMANCE
,
dev
->
pprof
.
choices
);
/* Create platform_profile structure and register */
err
=
platform_profile_register
(
&
dev
->
pprof
);
if
(
err
)
dev_err
(
dev
->
dev
,
"Failed to register SPS support, this is most likely an SBIOS bug: %d
\n
"
,
err
);
return
err
;
}
void
amd_pmf_deinit_sps
(
struct
amd_pmf_dev
*
dev
)
{
platform_profile_remove
();
}
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