mirror of
https://github.com/torvalds/linux.git
synced 2025-04-09 14:45:27 +00:00
pmdomain core:
- Add dev_pm_genpd_rpm_always_on() to support more fine-grained PM pmdomain providers: - arm: Remove redundant state verification for the SCMI PM domain - bcm: Add system-wakeup support for bcm2835 via GENPD_FLAG_ACTIVE_WAKEUP - rockchip: Add support for regulators - rockchip: Use SMC call to properly inform firmware - sunxi: Add V853 ppu support - thead: Add support for RISC-V TH1520 power-domains firmware: - Add support for the AON firmware protocol for RISC-V THEAD cpuidle-psci: - Update section in MAINTAINERS for cpuidle-psci - Add trace support for PSCI domain-idlestates -----BEGIN PGP SIGNATURE----- iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAmfimQ8XHHVsZi5oYW5z c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjCmp5A//QuqG0PiwrDyR/qOgOaYXHLe3 lYohfHtLyKVO0qAxhhiRbUZQrK4yitkRUJoXHcJuIqqXXjiM3tKu5Vp5loqVpqZi Q8nj6gEIUA1FQjY0h8VTS+NWXA5xbsqgayzw2U6BAfKHQwsvcMXn/hT5v8d0Q2WG UVNb+Xz25q6qzZPbhR/wfJ8kvFkGjV1GtIG3PPwA+C31jFjdcZhU+Rlwtgu+WDZE yofA/pkw5jdDkODTyysYhHKpZlnX+V1yUqs2xym27M2xmbCDpsn9IM45omuFCdnh 7dyKtG55XLd9wpAtO2DVvUWW0bhtr/zfDpWvDQdevQLjwrIdw5wdg53SE3NpNR7/ cCWLM7OFaTJDuuK/upuT75ZKaFqEu5QV9+Na5skQhL0Tl4V9A0nNRPLQXJItGZWv XNfV9OxljYK8c+5fEEEB+pBymZ2LeRvw2+P3DIMSgYNwdZMudmNRWsQe2SjbC4jI G9XzpXw6YaIUNmI8fGGZ4U4CqMg0bOjY7zlQL2VMTe3+JJGdpCRmONT8EV/LH3PQ 2V4dSjwoWH0lmQLo2trNDuIWj6AdGNObSL3LXSKPo6ORXg24dWdI9Dbc7PpPvOb0 CZ9AV3SezfmkSyODI5G5ULUeH1hy4h6jn9py2SoVRS3SQyznh0HZj9kBlyuVgfmL mArHaUCmVHPKhAvLc1g= =Wihe -----END PGP SIGNATURE----- Merge tag 'pmdomain-v6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm Pull pmdomain updates from Ulf Hansson: "pmdomain core: - Add dev_pm_genpd_rpm_always_on() to support more fine-grained PM pmdomain providers: - arm: Remove redundant state verification for the SCMI PM domain - bcm: Add system-wakeup support for bcm2835 via GENPD_FLAG_ACTIVE_WAKEUP - rockchip: Add support for regulators - rockchip: Use SMC call to properly inform firmware - sunxi: Add V853 ppu support - thead: Add support for RISC-V TH1520 power-domains firmware: - Add support for the AON firmware protocol for RISC-V THEAD cpuidle-psci: - Update section in MAINTAINERS for cpuidle-psci - Add trace support for PSCI domain-idlestates" * tag 'pmdomain-v6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm: (29 commits) firmware: thead: add CONFIG_MAILBOX dependency firmware: thead,th1520-aon: Fix use after free in th1520_aon_init() pmdomain: arm: scmi_pm_domain: Remove redundant state verification pmdomain: thead: fix TH1520_AON_PROTOCOL dependency pmdomain: thead: Add power-domain driver for TH1520 dt-bindings: power: Add TH1520 SoC power domains firmware: thead: Add AON firmware protocol driver dt-bindings: firmware: thead,th1520: Add support for firmware node pmdomain: rockchip: add regulator dependency pmdomain: rockchip: add regulator support pmdomain: rockchip: fix rockchip_pd_power error handling pmdomain: rockchip: reduce indentation in rockchip_pd_power pmdomain: rockchip: forward rockchip_do_pmu_set_power_domain errors pmdomain: rockchip: cleanup mutex handling in rockchip_pd_power dt-bindings: power: rockchip: add regulator support pmdomain: rockchip: Fix build error pmdomain: imx: gpcv2: use proper helper for property detection MAINTAINERS: Update section for cpuidle-psci pmdomain: rockchip: Check if SMC could be handled by TA cpuidle: psci: Add trace for PSCI domain idle ...
This commit is contained in:
commit
2a2274e90a
Documentation/devicetree/bindings
MAINTAINERSdrivers
cpuidle
firmware
pmdomain
include
dt-bindings/power
linux
soc/rockchip
trace/events
@ -0,0 +1,53 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/firmware/thead,th1520-aon.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: T-HEAD TH1520 AON (Always-On) Firmware
|
||||
|
||||
description: |
|
||||
The Always-On (AON) subsystem in the TH1520 SoC is responsible for managing
|
||||
low-power states, system wakeup events, and power management tasks. It is
|
||||
designed to operate independently in a dedicated power domain, allowing it to
|
||||
remain functional even during the SoC's deep sleep states.
|
||||
|
||||
At the heart of the AON subsystem is the E902, a low-power core that executes
|
||||
firmware responsible for coordinating tasks such as power domain control,
|
||||
clock management, and system wakeup signaling. Communication between the main
|
||||
SoC and the AON subsystem is handled through a mailbox interface, which
|
||||
enables message-based interactions with the AON firmware.
|
||||
|
||||
maintainers:
|
||||
- Michal Wilczynski <m.wilczynski@samsung.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: thead,th1520-aon
|
||||
|
||||
mboxes:
|
||||
maxItems: 1
|
||||
|
||||
mbox-names:
|
||||
items:
|
||||
- const: aon
|
||||
|
||||
"#power-domain-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- mboxes
|
||||
- mbox-names
|
||||
- "#power-domain-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
aon: aon {
|
||||
compatible = "thead,th1520-aon";
|
||||
mboxes = <&mbox_910t 1>;
|
||||
mbox-names = "aon";
|
||||
#power-domain-cells = <1>;
|
||||
};
|
@ -17,6 +17,7 @@ properties:
|
||||
compatible:
|
||||
enum:
|
||||
- allwinner,sun20i-d1-ppu
|
||||
- allwinner,sun8i-v853-ppu
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -132,6 +132,9 @@ $defs:
|
||||
A number of phandles to clocks that need to be enabled
|
||||
while power domain switches state.
|
||||
|
||||
domain-supply:
|
||||
description: domain regulator supply.
|
||||
|
||||
pm_qos:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
items:
|
||||
|
@ -6103,9 +6103,11 @@ F: include/linux/platform_data/cpuidle-exynos.h
|
||||
CPUIDLE DRIVER - ARM PSCI
|
||||
M: Lorenzo Pieralisi <lpieralisi@kernel.org>
|
||||
M: Sudeep Holla <sudeep.holla@arm.com>
|
||||
M: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
L: linux-pm@vger.kernel.org
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Supported
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm.git
|
||||
F: drivers/cpuidle/cpuidle-psci.c
|
||||
|
||||
CPUIDLE DRIVER - ARM PSCI PM DOMAIN
|
||||
@ -20510,15 +20512,20 @@ L: linux-riscv@lists.infradead.org
|
||||
S: Maintained
|
||||
T: git https://github.com/pdp7/linux.git
|
||||
F: Documentation/devicetree/bindings/clock/thead,th1520-clk-ap.yaml
|
||||
F: Documentation/devicetree/bindings/firmware/thead,th1520-aon.yaml
|
||||
F: Documentation/devicetree/bindings/mailbox/thead,th1520-mbox.yaml
|
||||
F: Documentation/devicetree/bindings/net/thead,th1520-gmac.yaml
|
||||
F: Documentation/devicetree/bindings/pinctrl/thead,th1520-pinctrl.yaml
|
||||
F: arch/riscv/boot/dts/thead/
|
||||
F: drivers/clk/thead/clk-th1520-ap.c
|
||||
F: drivers/firmware/thead,th1520-aon.c
|
||||
F: drivers/mailbox/mailbox-th1520.c
|
||||
F: drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c
|
||||
F: drivers/pinctrl/pinctrl-th1520.c
|
||||
F: drivers/pmdomain/thead/
|
||||
F: include/dt-bindings/clock/thead,th1520-clk-ap.h
|
||||
F: include/dt-bindings/power/thead,th1520-power.h
|
||||
F: include/linux/firmware/thead/thead,th1520-aon.h
|
||||
|
||||
RNBD BLOCK DRIVERS
|
||||
M: Md. Haris Iqbal <haris.iqbal@ionos.com>
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
#include <asm/cpuidle.h>
|
||||
#include <trace/events/power.h>
|
||||
|
||||
#include "cpuidle-psci.h"
|
||||
#include "dt_idle_states.h"
|
||||
@ -74,7 +75,9 @@ static __cpuidle int __psci_enter_domain_idle_state(struct cpuidle_device *dev,
|
||||
if (!state)
|
||||
state = states[idx];
|
||||
|
||||
trace_psci_domain_idle_enter(dev->cpu, state, s2idle);
|
||||
ret = psci_cpu_suspend_enter(state) ? -1 : idx;
|
||||
trace_psci_domain_idle_exit(dev->cpu, state, s2idle);
|
||||
|
||||
if (s2idle)
|
||||
dev_pm_genpd_resume(pd_dev);
|
||||
|
@ -212,6 +212,16 @@ config SYSFB_SIMPLEFB
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config TH1520_AON_PROTOCOL
|
||||
tristate "Always-On firmware protocol"
|
||||
depends on ARCH_THEAD || COMPILE_TEST
|
||||
depends on MAILBOX
|
||||
help
|
||||
Power, clock, and resource management capabilities on the TH1520 SoC are
|
||||
managed by the E902 core. Firmware running on this core communicates with
|
||||
the kernel through the Always-On protocol, using hardware mailbox as a medium.
|
||||
Say yes if you need such capabilities.
|
||||
|
||||
config TI_SCI_PROTOCOL
|
||||
tristate "TI System Control Interface (TISCI) Message Protocol"
|
||||
depends on TI_MESSAGE_MANAGER
|
||||
|
@ -18,6 +18,7 @@ obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
|
||||
obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o
|
||||
obj-$(CONFIG_SYSFB) += sysfb.o
|
||||
obj-$(CONFIG_SYSFB_SIMPLEFB) += sysfb_simplefb.o
|
||||
obj-$(CONFIG_TH1520_AON_PROTOCOL) += thead,th1520-aon.o
|
||||
obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
|
||||
obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o
|
||||
obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o
|
||||
|
250
drivers/firmware/thead,th1520-aon.c
Normal file
250
drivers/firmware/thead,th1520-aon.c
Normal file
@ -0,0 +1,250 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2021 Alibaba Group Holding Limited.
|
||||
* Copyright (c) 2024 Samsung Electronics Co., Ltd.
|
||||
* Author: Michal Wilczynski <m.wilczynski@samsung.com>
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/firmware/thead/thead,th1520-aon.h>
|
||||
#include <linux/mailbox_client.h>
|
||||
#include <linux/mailbox_controller.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define MAX_RX_TIMEOUT (msecs_to_jiffies(3000))
|
||||
#define MAX_TX_TIMEOUT 500
|
||||
|
||||
struct th1520_aon_chan {
|
||||
struct mbox_chan *ch;
|
||||
struct th1520_aon_rpc_ack_common ack_msg;
|
||||
struct mbox_client cl;
|
||||
struct completion done;
|
||||
|
||||
/* make sure only one RPC is performed at a time */
|
||||
struct mutex transaction_lock;
|
||||
};
|
||||
|
||||
struct th1520_aon_msg_req_set_resource_power_mode {
|
||||
struct th1520_aon_rpc_msg_hdr hdr;
|
||||
u16 resource;
|
||||
u16 mode;
|
||||
u16 reserved[10];
|
||||
} __packed __aligned(1);
|
||||
|
||||
/*
|
||||
* This type is used to indicate error response for most functions.
|
||||
*/
|
||||
enum th1520_aon_error_codes {
|
||||
LIGHT_AON_ERR_NONE = 0, /* Success */
|
||||
LIGHT_AON_ERR_VERSION = 1, /* Incompatible API version */
|
||||
LIGHT_AON_ERR_CONFIG = 2, /* Configuration error */
|
||||
LIGHT_AON_ERR_PARM = 3, /* Bad parameter */
|
||||
LIGHT_AON_ERR_NOACCESS = 4, /* Permission error (no access) */
|
||||
LIGHT_AON_ERR_LOCKED = 5, /* Permission error (locked) */
|
||||
LIGHT_AON_ERR_UNAVAILABLE = 6, /* Unavailable (out of resources) */
|
||||
LIGHT_AON_ERR_NOTFOUND = 7, /* Not found */
|
||||
LIGHT_AON_ERR_NOPOWER = 8, /* No power */
|
||||
LIGHT_AON_ERR_IPC = 9, /* Generic IPC error */
|
||||
LIGHT_AON_ERR_BUSY = 10, /* Resource is currently busy/active */
|
||||
LIGHT_AON_ERR_FAIL = 11, /* General I/O failure */
|
||||
LIGHT_AON_ERR_LAST
|
||||
};
|
||||
|
||||
static int th1520_aon_linux_errmap[LIGHT_AON_ERR_LAST] = {
|
||||
0, /* LIGHT_AON_ERR_NONE */
|
||||
-EINVAL, /* LIGHT_AON_ERR_VERSION */
|
||||
-EINVAL, /* LIGHT_AON_ERR_CONFIG */
|
||||
-EINVAL, /* LIGHT_AON_ERR_PARM */
|
||||
-EACCES, /* LIGHT_AON_ERR_NOACCESS */
|
||||
-EACCES, /* LIGHT_AON_ERR_LOCKED */
|
||||
-ERANGE, /* LIGHT_AON_ERR_UNAVAILABLE */
|
||||
-EEXIST, /* LIGHT_AON_ERR_NOTFOUND */
|
||||
-EPERM, /* LIGHT_AON_ERR_NOPOWER */
|
||||
-EPIPE, /* LIGHT_AON_ERR_IPC */
|
||||
-EBUSY, /* LIGHT_AON_ERR_BUSY */
|
||||
-EIO, /* LIGHT_AON_ERR_FAIL */
|
||||
};
|
||||
|
||||
static inline int th1520_aon_to_linux_errno(int errno)
|
||||
{
|
||||
if (errno >= LIGHT_AON_ERR_NONE && errno < LIGHT_AON_ERR_LAST)
|
||||
return th1520_aon_linux_errmap[errno];
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static void th1520_aon_rx_callback(struct mbox_client *c, void *rx_msg)
|
||||
{
|
||||
struct th1520_aon_chan *aon_chan =
|
||||
container_of(c, struct th1520_aon_chan, cl);
|
||||
struct th1520_aon_rpc_msg_hdr *hdr =
|
||||
(struct th1520_aon_rpc_msg_hdr *)rx_msg;
|
||||
u8 recv_size = sizeof(struct th1520_aon_rpc_msg_hdr) + hdr->size;
|
||||
|
||||
if (recv_size != sizeof(struct th1520_aon_rpc_ack_common)) {
|
||||
dev_err(c->dev, "Invalid ack size, not completing\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&aon_chan->ack_msg, rx_msg, recv_size);
|
||||
complete(&aon_chan->done);
|
||||
}
|
||||
|
||||
/**
|
||||
* th1520_aon_call_rpc() - Send an RPC request to the TH1520 AON subsystem
|
||||
* @aon_chan: Pointer to the AON channel structure
|
||||
* @msg: Pointer to the message (RPC payload) that will be sent
|
||||
*
|
||||
* This function sends an RPC message to the TH1520 AON subsystem via mailbox.
|
||||
* It takes the provided @msg buffer, formats it with version and service flags,
|
||||
* then blocks until the RPC completes or times out. The completion is signaled
|
||||
* by the `aon_chan->done` completion, which is waited upon for a duration
|
||||
* defined by `MAX_RX_TIMEOUT`.
|
||||
*
|
||||
* Return:
|
||||
* * 0 on success
|
||||
* * -ETIMEDOUT if the RPC call times out
|
||||
* * A negative error code if the mailbox send fails or if AON responds with
|
||||
* a non-zero error code (converted via th1520_aon_to_linux_errno()).
|
||||
*/
|
||||
int th1520_aon_call_rpc(struct th1520_aon_chan *aon_chan, void *msg)
|
||||
{
|
||||
struct th1520_aon_rpc_msg_hdr *hdr = msg;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&aon_chan->transaction_lock);
|
||||
reinit_completion(&aon_chan->done);
|
||||
|
||||
RPC_SET_VER(hdr, TH1520_AON_RPC_VERSION);
|
||||
RPC_SET_SVC_ID(hdr, hdr->svc);
|
||||
RPC_SET_SVC_FLAG_MSG_TYPE(hdr, RPC_SVC_MSG_TYPE_DATA);
|
||||
RPC_SET_SVC_FLAG_ACK_TYPE(hdr, RPC_SVC_MSG_NEED_ACK);
|
||||
|
||||
ret = mbox_send_message(aon_chan->ch, msg);
|
||||
if (ret < 0) {
|
||||
dev_err(aon_chan->cl.dev, "RPC send msg failed: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!wait_for_completion_timeout(&aon_chan->done, MAX_RX_TIMEOUT)) {
|
||||
dev_err(aon_chan->cl.dev, "RPC send msg timeout\n");
|
||||
mutex_unlock(&aon_chan->transaction_lock);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
ret = aon_chan->ack_msg.err_code;
|
||||
|
||||
out:
|
||||
mutex_unlock(&aon_chan->transaction_lock);
|
||||
|
||||
return th1520_aon_to_linux_errno(ret);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(th1520_aon_call_rpc);
|
||||
|
||||
/**
|
||||
* th1520_aon_power_update() - Change power state of a resource via TH1520 AON
|
||||
* @aon_chan: Pointer to the AON channel structure
|
||||
* @rsrc: Resource ID whose power state needs to be updated
|
||||
* @power_on: Boolean indicating whether the resource should be powered on (true)
|
||||
* or powered off (false)
|
||||
*
|
||||
* This function requests the TH1520 AON subsystem to set the power mode of the
|
||||
* given resource (@rsrc) to either on or off. It constructs the message in
|
||||
* `struct th1520_aon_msg_req_set_resource_power_mode` and then invokes
|
||||
* th1520_aon_call_rpc() to make the request. If the AON call fails, an error
|
||||
* message is logged along with the specific return code.
|
||||
*
|
||||
* Return:
|
||||
* * 0 on success
|
||||
* * A negative error code in case of failures (propagated from
|
||||
* th1520_aon_call_rpc()).
|
||||
*/
|
||||
int th1520_aon_power_update(struct th1520_aon_chan *aon_chan, u16 rsrc,
|
||||
bool power_on)
|
||||
{
|
||||
struct th1520_aon_msg_req_set_resource_power_mode msg = {};
|
||||
struct th1520_aon_rpc_msg_hdr *hdr = &msg.hdr;
|
||||
int ret;
|
||||
|
||||
hdr->svc = TH1520_AON_RPC_SVC_PM;
|
||||
hdr->func = TH1520_AON_PM_FUNC_SET_RESOURCE_POWER_MODE;
|
||||
hdr->size = TH1520_AON_RPC_MSG_NUM;
|
||||
|
||||
RPC_SET_BE16(&msg.resource, 0, rsrc);
|
||||
RPC_SET_BE16(&msg.resource, 2,
|
||||
(power_on ? TH1520_AON_PM_PW_MODE_ON :
|
||||
TH1520_AON_PM_PW_MODE_OFF));
|
||||
|
||||
ret = th1520_aon_call_rpc(aon_chan, &msg);
|
||||
if (ret)
|
||||
dev_err(aon_chan->cl.dev, "failed to power %s resource %d ret %d\n",
|
||||
power_on ? "up" : "off", rsrc, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(th1520_aon_power_update);
|
||||
|
||||
/**
|
||||
* th1520_aon_init() - Initialize TH1520 AON firmware protocol interface
|
||||
* @dev: Device pointer for the AON subsystem
|
||||
*
|
||||
* This function initializes the TH1520 AON firmware protocol interface by:
|
||||
* - Allocating and initializing the AON channel structure
|
||||
* - Setting up the mailbox client
|
||||
* - Requesting the AON mailbox channel
|
||||
* - Initializing synchronization primitives
|
||||
*
|
||||
* Return:
|
||||
* * Valid pointer to th1520_aon_chan structure on success
|
||||
* * ERR_PTR(-ENOMEM) if memory allocation fails
|
||||
* * ERR_PTR() with other negative error codes from mailbox operations
|
||||
*/
|
||||
struct th1520_aon_chan *th1520_aon_init(struct device *dev)
|
||||
{
|
||||
struct th1520_aon_chan *aon_chan;
|
||||
struct mbox_client *cl;
|
||||
int ret;
|
||||
|
||||
aon_chan = kzalloc(sizeof(*aon_chan), GFP_KERNEL);
|
||||
if (!aon_chan)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
cl = &aon_chan->cl;
|
||||
cl->dev = dev;
|
||||
cl->tx_block = true;
|
||||
cl->tx_tout = MAX_TX_TIMEOUT;
|
||||
cl->rx_callback = th1520_aon_rx_callback;
|
||||
|
||||
aon_chan->ch = mbox_request_channel_byname(cl, "aon");
|
||||
if (IS_ERR(aon_chan->ch)) {
|
||||
dev_err(dev, "Failed to request aon mbox chan\n");
|
||||
ret = PTR_ERR(aon_chan->ch);
|
||||
kfree(aon_chan);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
mutex_init(&aon_chan->transaction_lock);
|
||||
init_completion(&aon_chan->done);
|
||||
|
||||
return aon_chan;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(th1520_aon_init);
|
||||
|
||||
/**
|
||||
* th1520_aon_deinit() - Clean up TH1520 AON firmware protocol interface
|
||||
* @aon_chan: Pointer to the AON channel structure to clean up
|
||||
*
|
||||
* This function cleans up resources allocated by th1520_aon_init():
|
||||
* - Frees the mailbox channel
|
||||
* - Frees the AON channel
|
||||
*/
|
||||
void th1520_aon_deinit(struct th1520_aon_chan *aon_chan)
|
||||
{
|
||||
mbox_free_channel(aon_chan->ch);
|
||||
kfree(aon_chan);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(th1520_aon_deinit);
|
||||
|
||||
MODULE_AUTHOR("Michal Wilczynski <m.wilczynski@samsung.com>");
|
||||
MODULE_DESCRIPTION("T-HEAD TH1520 Always-On firmware protocol library");
|
||||
MODULE_LICENSE("GPL");
|
@ -16,6 +16,7 @@ source "drivers/pmdomain/st/Kconfig"
|
||||
source "drivers/pmdomain/starfive/Kconfig"
|
||||
source "drivers/pmdomain/sunxi/Kconfig"
|
||||
source "drivers/pmdomain/tegra/Kconfig"
|
||||
source "drivers/pmdomain/thead/Kconfig"
|
||||
source "drivers/pmdomain/ti/Kconfig"
|
||||
source "drivers/pmdomain/xilinx/Kconfig"
|
||||
|
||||
|
@ -14,6 +14,7 @@ obj-y += st/
|
||||
obj-y += starfive/
|
||||
obj-y += sunxi/
|
||||
obj-y += tegra/
|
||||
obj-y += thead/
|
||||
obj-y += ti/
|
||||
obj-y += xilinx/
|
||||
obj-y += core.o governor.o
|
||||
|
@ -24,8 +24,7 @@ struct scmi_pm_domain {
|
||||
|
||||
static int scmi_pd_power(struct generic_pm_domain *domain, bool power_on)
|
||||
{
|
||||
int ret;
|
||||
u32 state, ret_state;
|
||||
u32 state;
|
||||
struct scmi_pm_domain *pd = to_scmi_pd(domain);
|
||||
|
||||
if (power_on)
|
||||
@ -33,13 +32,7 @@ static int scmi_pd_power(struct generic_pm_domain *domain, bool power_on)
|
||||
else
|
||||
state = SCMI_POWER_STATE_GENERIC_OFF;
|
||||
|
||||
ret = power_ops->state_set(pd->ph, pd->domain, state);
|
||||
if (!ret)
|
||||
ret = power_ops->state_get(pd->ph, pd->domain, &ret_state);
|
||||
if (!ret && state != ret_state)
|
||||
return -EIO;
|
||||
|
||||
return ret;
|
||||
return power_ops->state_set(pd->ph, pd->domain, state);
|
||||
}
|
||||
|
||||
static int scmi_pd_power_on(struct generic_pm_domain *domain)
|
||||
|
@ -520,6 +520,7 @@ bcm2835_init_power_domain(struct bcm2835_power *power,
|
||||
}
|
||||
|
||||
dom->base.name = name;
|
||||
dom->base.flags = GENPD_FLAG_ACTIVE_WAKEUP;
|
||||
dom->base.power_on = bcm2835_power_pd_power_on;
|
||||
dom->base.power_off = bcm2835_power_pd_power_off;
|
||||
|
||||
|
@ -697,6 +697,37 @@ bool dev_pm_genpd_get_hwmode(struct device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_genpd_get_hwmode);
|
||||
|
||||
/**
|
||||
* dev_pm_genpd_rpm_always_on() - Control if the PM domain can be powered off.
|
||||
*
|
||||
* @dev: Device for which the PM domain may need to stay on for.
|
||||
* @on: Value to set or unset for the condition.
|
||||
*
|
||||
* For some usecases a consumer driver requires its device to remain power-on
|
||||
* from the PM domain perspective during runtime. This function allows the
|
||||
* behaviour to be dynamically controlled for a device attached to a genpd.
|
||||
*
|
||||
* It is assumed that the users guarantee that the genpd wouldn't be detached
|
||||
* while this routine is getting called.
|
||||
*
|
||||
* Return: Returns 0 on success and negative error values on failures.
|
||||
*/
|
||||
int dev_pm_genpd_rpm_always_on(struct device *dev, bool on)
|
||||
{
|
||||
struct generic_pm_domain *genpd;
|
||||
|
||||
genpd = dev_to_genpd_safe(dev);
|
||||
if (!genpd)
|
||||
return -ENODEV;
|
||||
|
||||
genpd_lock(genpd);
|
||||
dev_gpd_data(dev)->rpm_always_on = on;
|
||||
genpd_unlock(genpd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_genpd_rpm_always_on);
|
||||
|
||||
static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
|
||||
{
|
||||
unsigned int state_idx = genpd->state_idx;
|
||||
@ -868,6 +899,10 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
|
||||
if (!pm_runtime_suspended(pdd->dev) ||
|
||||
irq_safe_dev_in_sleep_domain(pdd->dev, genpd))
|
||||
not_suspended++;
|
||||
|
||||
/* The device may need its PM domain to stay powered on. */
|
||||
if (to_gpd_data(pdd)->rpm_always_on)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (not_suspended > 1 || (not_suspended == 1 && !one_dev_on))
|
||||
|
@ -1361,7 +1361,7 @@ static int imx_pgc_domain_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_LOCKDEP) &&
|
||||
of_property_read_bool(domain->dev->of_node, "power-domains"))
|
||||
of_property_present(domain->dev->of_node, "power-domains"))
|
||||
lockdep_set_subclass(&domain->genpd.mlock, 1);
|
||||
|
||||
ret = of_genpd_add_provider_simple(domain->dev->of_node,
|
||||
|
@ -434,8 +434,6 @@ static int __init rcar_sysc_pd_init(void)
|
||||
}
|
||||
|
||||
error = of_genpd_add_provider_onecell(np, &domains->onecell_data);
|
||||
if (!error)
|
||||
fwnode_dev_initialized(of_fwnode_handle(np), true);
|
||||
|
||||
out_put:
|
||||
of_node_put(np);
|
||||
|
@ -4,6 +4,8 @@ if ARCH_ROCKCHIP || COMPILE_TEST
|
||||
config ROCKCHIP_PM_DOMAINS
|
||||
bool "Rockchip generic power domain"
|
||||
depends on PM
|
||||
depends on HAVE_ARM_SMCCC_DISCOVERY
|
||||
depends on REGULATOR
|
||||
select PM_GENERIC_DOMAINS
|
||||
help
|
||||
Say y here to enable power domain support.
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Copyright (c) 2015 ROCKCHIP, Co. Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/err.h>
|
||||
@ -18,8 +19,10 @@
|
||||
#include <linux/of_clk.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <soc/rockchip/pm_domains.h>
|
||||
#include <soc/rockchip/rockchip_sip.h>
|
||||
#include <dt-bindings/power/px30-power.h>
|
||||
#include <dt-bindings/power/rockchip,rv1126-power.h>
|
||||
#include <dt-bindings/power/rk3036-power.h>
|
||||
@ -44,6 +47,7 @@ struct rockchip_domain_info {
|
||||
int idle_mask;
|
||||
int ack_mask;
|
||||
bool active_wakeup;
|
||||
bool need_regulator;
|
||||
int pwr_w_mask;
|
||||
int req_w_mask;
|
||||
int clk_ungate_mask;
|
||||
@ -92,6 +96,8 @@ struct rockchip_pm_domain {
|
||||
u32 *qos_save_regs[MAX_QOS_REGS_NUM];
|
||||
int num_clks;
|
||||
struct clk_bulk_data *clks;
|
||||
struct device_node *node;
|
||||
struct regulator *supply;
|
||||
};
|
||||
|
||||
struct rockchip_pmu {
|
||||
@ -129,7 +135,7 @@ struct rockchip_pmu {
|
||||
.active_wakeup = wakeup, \
|
||||
}
|
||||
|
||||
#define DOMAIN_M_O_R(_name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, ack, wakeup) \
|
||||
#define DOMAIN_M_O_R(_name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, ack, wakeup, regulator) \
|
||||
{ \
|
||||
.name = _name, \
|
||||
.pwr_offset = p_offset, \
|
||||
@ -145,6 +151,7 @@ struct rockchip_pmu {
|
||||
.idle_mask = (idle), \
|
||||
.ack_mask = (ack), \
|
||||
.active_wakeup = wakeup, \
|
||||
.need_regulator = regulator, \
|
||||
}
|
||||
|
||||
#define DOMAIN_M_O_R_G(_name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, ack, g_mask, wakeup) \
|
||||
@ -303,8 +310,8 @@ void rockchip_pmu_unblock(void)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_pmu_unblock);
|
||||
|
||||
#define DOMAIN_RK3588(name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, wakeup) \
|
||||
DOMAIN_M_O_R(name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, idle, wakeup)
|
||||
#define DOMAIN_RK3588(name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, wakeup, regulator) \
|
||||
DOMAIN_M_O_R(name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, idle, wakeup, regulator)
|
||||
|
||||
static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd)
|
||||
{
|
||||
@ -533,16 +540,18 @@ error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
|
||||
bool on)
|
||||
static int rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
|
||||
bool on)
|
||||
{
|
||||
struct rockchip_pmu *pmu = pd->pmu;
|
||||
struct generic_pm_domain *genpd = &pd->genpd;
|
||||
u32 pd_pwr_offset = pd->info->pwr_offset;
|
||||
bool is_on, is_mem_on = false;
|
||||
struct arm_smccc_res res;
|
||||
int ret;
|
||||
|
||||
if (pd->info->pwr_mask == 0)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (on && pd->info->mem_status_mask)
|
||||
is_mem_on = rockchip_pmu_domain_is_mem_on(pd);
|
||||
@ -557,16 +566,28 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
|
||||
|
||||
wmb();
|
||||
|
||||
if (is_mem_on && rockchip_pmu_domain_mem_reset(pd))
|
||||
return;
|
||||
|
||||
if (readx_poll_timeout_atomic(rockchip_pmu_domain_is_on, pd, is_on,
|
||||
is_on == on, 0, 10000)) {
|
||||
dev_err(pmu->dev,
|
||||
"failed to set domain '%s', val=%d\n",
|
||||
genpd->name, is_on);
|
||||
return;
|
||||
if (is_mem_on) {
|
||||
ret = rockchip_pmu_domain_mem_reset(pd);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_on, pd, is_on,
|
||||
is_on == on, 0, 10000);
|
||||
if (ret) {
|
||||
dev_err(pmu->dev, "failed to set domain '%s' %s, val=%d\n",
|
||||
genpd->name, on ? "on" : "off", is_on);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Inform firmware to keep this pd on or off */
|
||||
if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_NONE)
|
||||
arm_smccc_smc(ROCKCHIP_SIP_SUSPEND_MODE, ROCKCHIP_SLEEP_PD_CONFIG,
|
||||
pmu->info->pwr_offset + pd_pwr_offset,
|
||||
pd->info->pwr_mask, on, 0, 0, 0, &res);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
|
||||
@ -574,54 +595,99 @@ static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
|
||||
struct rockchip_pmu *pmu = pd->pmu;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&pmu->mutex);
|
||||
guard(mutex)(&pmu->mutex);
|
||||
|
||||
if (rockchip_pmu_domain_is_on(pd) != power_on) {
|
||||
ret = clk_bulk_enable(pd->num_clks, pd->clks);
|
||||
if (ret < 0) {
|
||||
dev_err(pmu->dev, "failed to enable clocks\n");
|
||||
mutex_unlock(&pmu->mutex);
|
||||
return ret;
|
||||
}
|
||||
if (rockchip_pmu_domain_is_on(pd) == power_on)
|
||||
return 0;
|
||||
|
||||
rockchip_pmu_ungate_clk(pd, true);
|
||||
|
||||
if (!power_on) {
|
||||
rockchip_pmu_save_qos(pd);
|
||||
|
||||
/* if powering down, idle request to NIU first */
|
||||
rockchip_pmu_set_idle_request(pd, true);
|
||||
}
|
||||
|
||||
rockchip_do_pmu_set_power_domain(pd, power_on);
|
||||
|
||||
if (power_on) {
|
||||
/* if powering up, leave idle mode */
|
||||
rockchip_pmu_set_idle_request(pd, false);
|
||||
|
||||
rockchip_pmu_restore_qos(pd);
|
||||
}
|
||||
|
||||
rockchip_pmu_ungate_clk(pd, false);
|
||||
clk_bulk_disable(pd->num_clks, pd->clks);
|
||||
ret = clk_bulk_enable(pd->num_clks, pd->clks);
|
||||
if (ret < 0) {
|
||||
dev_err(pmu->dev, "failed to enable clocks\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_unlock(&pmu->mutex);
|
||||
return 0;
|
||||
rockchip_pmu_ungate_clk(pd, true);
|
||||
|
||||
if (!power_on) {
|
||||
rockchip_pmu_save_qos(pd);
|
||||
|
||||
/* if powering down, idle request to NIU first */
|
||||
ret = rockchip_pmu_set_idle_request(pd, true);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = rockchip_do_pmu_set_power_domain(pd, power_on);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (power_on) {
|
||||
/* if powering up, leave idle mode */
|
||||
ret = rockchip_pmu_set_idle_request(pd, false);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
rockchip_pmu_restore_qos(pd);
|
||||
}
|
||||
|
||||
out:
|
||||
rockchip_pmu_ungate_clk(pd, false);
|
||||
clk_bulk_disable(pd->num_clks, pd->clks);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rockchip_pd_regulator_disable(struct rockchip_pm_domain *pd)
|
||||
{
|
||||
return IS_ERR_OR_NULL(pd->supply) ? 0 : regulator_disable(pd->supply);
|
||||
}
|
||||
|
||||
static int rockchip_pd_regulator_enable(struct rockchip_pm_domain *pd)
|
||||
{
|
||||
struct rockchip_pmu *pmu = pd->pmu;
|
||||
|
||||
if (!pd->info->need_regulator)
|
||||
return 0;
|
||||
|
||||
if (IS_ERR_OR_NULL(pd->supply)) {
|
||||
pd->supply = devm_of_regulator_get(pmu->dev, pd->node, "domain");
|
||||
|
||||
if (IS_ERR(pd->supply))
|
||||
return PTR_ERR(pd->supply);
|
||||
}
|
||||
|
||||
return regulator_enable(pd->supply);
|
||||
}
|
||||
|
||||
static int rockchip_pd_power_on(struct generic_pm_domain *domain)
|
||||
{
|
||||
struct rockchip_pm_domain *pd = to_rockchip_pd(domain);
|
||||
int ret;
|
||||
|
||||
return rockchip_pd_power(pd, true);
|
||||
ret = rockchip_pd_regulator_enable(pd);
|
||||
if (ret) {
|
||||
dev_err(pd->pmu->dev, "Failed to enable supply: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = rockchip_pd_power(pd, true);
|
||||
if (ret)
|
||||
rockchip_pd_regulator_disable(pd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rockchip_pd_power_off(struct generic_pm_domain *domain)
|
||||
{
|
||||
struct rockchip_pm_domain *pd = to_rockchip_pd(domain);
|
||||
int ret;
|
||||
|
||||
return rockchip_pd_power(pd, false);
|
||||
ret = rockchip_pd_power(pd, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rockchip_pd_regulator_disable(pd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rockchip_pd_attach_dev(struct generic_pm_domain *genpd,
|
||||
@ -702,6 +768,7 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
|
||||
|
||||
pd->info = pd_info;
|
||||
pd->pmu = pmu;
|
||||
pd->node = node;
|
||||
|
||||
pd->num_clks = of_clk_get_parent_count(node);
|
||||
if (pd->num_clks > 0) {
|
||||
@ -1165,35 +1232,35 @@ static const struct rockchip_domain_info rk3576_pm_domains[] = {
|
||||
};
|
||||
|
||||
static const struct rockchip_domain_info rk3588_pm_domains[] = {
|
||||
[RK3588_PD_GPU] = DOMAIN_RK3588("gpu", 0x0, BIT(0), 0, 0x0, 0, BIT(1), 0x0, BIT(0), BIT(0), false),
|
||||
[RK3588_PD_NPU] = DOMAIN_RK3588("npu", 0x0, BIT(1), BIT(1), 0x0, 0, 0, 0x0, 0, 0, false),
|
||||
[RK3588_PD_VCODEC] = DOMAIN_RK3588("vcodec", 0x0, BIT(2), BIT(2), 0x0, 0, 0, 0x0, 0, 0, false),
|
||||
[RK3588_PD_NPUTOP] = DOMAIN_RK3588("nputop", 0x0, BIT(3), 0, 0x0, BIT(11), BIT(2), 0x0, BIT(1), BIT(1), false),
|
||||
[RK3588_PD_NPU1] = DOMAIN_RK3588("npu1", 0x0, BIT(4), 0, 0x0, BIT(12), BIT(3), 0x0, BIT(2), BIT(2), false),
|
||||
[RK3588_PD_NPU2] = DOMAIN_RK3588("npu2", 0x0, BIT(5), 0, 0x0, BIT(13), BIT(4), 0x0, BIT(3), BIT(3), false),
|
||||
[RK3588_PD_VENC0] = DOMAIN_RK3588("venc0", 0x0, BIT(6), 0, 0x0, BIT(14), BIT(5), 0x0, BIT(4), BIT(4), false),
|
||||
[RK3588_PD_VENC1] = DOMAIN_RK3588("venc1", 0x0, BIT(7), 0, 0x0, BIT(15), BIT(6), 0x0, BIT(5), BIT(5), false),
|
||||
[RK3588_PD_RKVDEC0] = DOMAIN_RK3588("rkvdec0", 0x0, BIT(8), 0, 0x0, BIT(16), BIT(7), 0x0, BIT(6), BIT(6), false),
|
||||
[RK3588_PD_RKVDEC1] = DOMAIN_RK3588("rkvdec1", 0x0, BIT(9), 0, 0x0, BIT(17), BIT(8), 0x0, BIT(7), BIT(7), false),
|
||||
[RK3588_PD_VDPU] = DOMAIN_RK3588("vdpu", 0x0, BIT(10), 0, 0x0, BIT(18), BIT(9), 0x0, BIT(8), BIT(8), false),
|
||||
[RK3588_PD_RGA30] = DOMAIN_RK3588("rga30", 0x0, BIT(11), 0, 0x0, BIT(19), BIT(10), 0x0, 0, 0, false),
|
||||
[RK3588_PD_AV1] = DOMAIN_RK3588("av1", 0x0, BIT(12), 0, 0x0, BIT(20), BIT(11), 0x0, BIT(9), BIT(9), false),
|
||||
[RK3588_PD_VI] = DOMAIN_RK3588("vi", 0x0, BIT(13), 0, 0x0, BIT(21), BIT(12), 0x0, BIT(10), BIT(10), false),
|
||||
[RK3588_PD_FEC] = DOMAIN_RK3588("fec", 0x0, BIT(14), 0, 0x0, BIT(22), BIT(13), 0x0, 0, 0, false),
|
||||
[RK3588_PD_ISP1] = DOMAIN_RK3588("isp1", 0x0, BIT(15), 0, 0x0, BIT(23), BIT(14), 0x0, BIT(11), BIT(11), false),
|
||||
[RK3588_PD_RGA31] = DOMAIN_RK3588("rga31", 0x4, BIT(0), 0, 0x0, BIT(24), BIT(15), 0x0, BIT(12), BIT(12), false),
|
||||
[RK3588_PD_VOP] = DOMAIN_RK3588("vop", 0x4, BIT(1), 0, 0x0, BIT(25), BIT(16), 0x0, BIT(13) | BIT(14), BIT(13) | BIT(14), false),
|
||||
[RK3588_PD_VO0] = DOMAIN_RK3588("vo0", 0x4, BIT(2), 0, 0x0, BIT(26), BIT(17), 0x0, BIT(15), BIT(15), false),
|
||||
[RK3588_PD_VO1] = DOMAIN_RK3588("vo1", 0x4, BIT(3), 0, 0x0, BIT(27), BIT(18), 0x4, BIT(0), BIT(16), false),
|
||||
[RK3588_PD_AUDIO] = DOMAIN_RK3588("audio", 0x4, BIT(4), 0, 0x0, BIT(28), BIT(19), 0x4, BIT(1), BIT(17), false),
|
||||
[RK3588_PD_PHP] = DOMAIN_RK3588("php", 0x4, BIT(5), 0, 0x0, BIT(29), BIT(20), 0x4, BIT(5), BIT(21), false),
|
||||
[RK3588_PD_GMAC] = DOMAIN_RK3588("gmac", 0x4, BIT(6), 0, 0x0, BIT(30), BIT(21), 0x0, 0, 0, false),
|
||||
[RK3588_PD_PCIE] = DOMAIN_RK3588("pcie", 0x4, BIT(7), 0, 0x0, BIT(31), BIT(22), 0x0, 0, 0, true),
|
||||
[RK3588_PD_NVM] = DOMAIN_RK3588("nvm", 0x4, BIT(8), BIT(24), 0x4, 0, 0, 0x4, BIT(2), BIT(18), false),
|
||||
[RK3588_PD_NVM0] = DOMAIN_RK3588("nvm0", 0x4, BIT(9), 0, 0x4, BIT(1), BIT(23), 0x0, 0, 0, false),
|
||||
[RK3588_PD_SDIO] = DOMAIN_RK3588("sdio", 0x4, BIT(10), 0, 0x4, BIT(2), BIT(24), 0x4, BIT(3), BIT(19), false),
|
||||
[RK3588_PD_USB] = DOMAIN_RK3588("usb", 0x4, BIT(11), 0, 0x4, BIT(3), BIT(25), 0x4, BIT(4), BIT(20), true),
|
||||
[RK3588_PD_SDMMC] = DOMAIN_RK3588("sdmmc", 0x4, BIT(13), 0, 0x4, BIT(5), BIT(26), 0x0, 0, 0, false),
|
||||
[RK3588_PD_GPU] = DOMAIN_RK3588("gpu", 0x0, BIT(0), 0, 0x0, 0, BIT(1), 0x0, BIT(0), BIT(0), false, true),
|
||||
[RK3588_PD_NPU] = DOMAIN_RK3588("npu", 0x0, BIT(1), BIT(1), 0x0, 0, 0, 0x0, 0, 0, false, true),
|
||||
[RK3588_PD_VCODEC] = DOMAIN_RK3588("vcodec", 0x0, BIT(2), BIT(2), 0x0, 0, 0, 0x0, 0, 0, false, false),
|
||||
[RK3588_PD_NPUTOP] = DOMAIN_RK3588("nputop", 0x0, BIT(3), 0, 0x0, BIT(11), BIT(2), 0x0, BIT(1), BIT(1), false, false),
|
||||
[RK3588_PD_NPU1] = DOMAIN_RK3588("npu1", 0x0, BIT(4), 0, 0x0, BIT(12), BIT(3), 0x0, BIT(2), BIT(2), false, false),
|
||||
[RK3588_PD_NPU2] = DOMAIN_RK3588("npu2", 0x0, BIT(5), 0, 0x0, BIT(13), BIT(4), 0x0, BIT(3), BIT(3), false, false),
|
||||
[RK3588_PD_VENC0] = DOMAIN_RK3588("venc0", 0x0, BIT(6), 0, 0x0, BIT(14), BIT(5), 0x0, BIT(4), BIT(4), false, false),
|
||||
[RK3588_PD_VENC1] = DOMAIN_RK3588("venc1", 0x0, BIT(7), 0, 0x0, BIT(15), BIT(6), 0x0, BIT(5), BIT(5), false, false),
|
||||
[RK3588_PD_RKVDEC0] = DOMAIN_RK3588("rkvdec0", 0x0, BIT(8), 0, 0x0, BIT(16), BIT(7), 0x0, BIT(6), BIT(6), false, false),
|
||||
[RK3588_PD_RKVDEC1] = DOMAIN_RK3588("rkvdec1", 0x0, BIT(9), 0, 0x0, BIT(17), BIT(8), 0x0, BIT(7), BIT(7), false, false),
|
||||
[RK3588_PD_VDPU] = DOMAIN_RK3588("vdpu", 0x0, BIT(10), 0, 0x0, BIT(18), BIT(9), 0x0, BIT(8), BIT(8), false, false),
|
||||
[RK3588_PD_RGA30] = DOMAIN_RK3588("rga30", 0x0, BIT(11), 0, 0x0, BIT(19), BIT(10), 0x0, 0, 0, false, false),
|
||||
[RK3588_PD_AV1] = DOMAIN_RK3588("av1", 0x0, BIT(12), 0, 0x0, BIT(20), BIT(11), 0x0, BIT(9), BIT(9), false, false),
|
||||
[RK3588_PD_VI] = DOMAIN_RK3588("vi", 0x0, BIT(13), 0, 0x0, BIT(21), BIT(12), 0x0, BIT(10), BIT(10), false, false),
|
||||
[RK3588_PD_FEC] = DOMAIN_RK3588("fec", 0x0, BIT(14), 0, 0x0, BIT(22), BIT(13), 0x0, 0, 0, false, false),
|
||||
[RK3588_PD_ISP1] = DOMAIN_RK3588("isp1", 0x0, BIT(15), 0, 0x0, BIT(23), BIT(14), 0x0, BIT(11), BIT(11), false, false),
|
||||
[RK3588_PD_RGA31] = DOMAIN_RK3588("rga31", 0x4, BIT(0), 0, 0x0, BIT(24), BIT(15), 0x0, BIT(12), BIT(12), false, false),
|
||||
[RK3588_PD_VOP] = DOMAIN_RK3588("vop", 0x4, BIT(1), 0, 0x0, BIT(25), BIT(16), 0x0, BIT(13) | BIT(14), BIT(13) | BIT(14), false, false),
|
||||
[RK3588_PD_VO0] = DOMAIN_RK3588("vo0", 0x4, BIT(2), 0, 0x0, BIT(26), BIT(17), 0x0, BIT(15), BIT(15), false, false),
|
||||
[RK3588_PD_VO1] = DOMAIN_RK3588("vo1", 0x4, BIT(3), 0, 0x0, BIT(27), BIT(18), 0x4, BIT(0), BIT(16), false, false),
|
||||
[RK3588_PD_AUDIO] = DOMAIN_RK3588("audio", 0x4, BIT(4), 0, 0x0, BIT(28), BIT(19), 0x4, BIT(1), BIT(17), false, false),
|
||||
[RK3588_PD_PHP] = DOMAIN_RK3588("php", 0x4, BIT(5), 0, 0x0, BIT(29), BIT(20), 0x4, BIT(5), BIT(21), false, false),
|
||||
[RK3588_PD_GMAC] = DOMAIN_RK3588("gmac", 0x4, BIT(6), 0, 0x0, BIT(30), BIT(21), 0x0, 0, 0, false, false),
|
||||
[RK3588_PD_PCIE] = DOMAIN_RK3588("pcie", 0x4, BIT(7), 0, 0x0, BIT(31), BIT(22), 0x0, 0, 0, true, false),
|
||||
[RK3588_PD_NVM] = DOMAIN_RK3588("nvm", 0x4, BIT(8), BIT(24), 0x4, 0, 0, 0x4, BIT(2), BIT(18), false, false),
|
||||
[RK3588_PD_NVM0] = DOMAIN_RK3588("nvm0", 0x4, BIT(9), 0, 0x4, BIT(1), BIT(23), 0x0, 0, 0, false, false),
|
||||
[RK3588_PD_SDIO] = DOMAIN_RK3588("sdio", 0x4, BIT(10), 0, 0x4, BIT(2), BIT(24), 0x4, BIT(3), BIT(19), false, false),
|
||||
[RK3588_PD_USB] = DOMAIN_RK3588("usb", 0x4, BIT(11), 0, 0x4, BIT(3), BIT(25), 0x4, BIT(4), BIT(20), true, false),
|
||||
[RK3588_PD_SDMMC] = DOMAIN_RK3588("sdmmc", 0x4, BIT(13), 0, 0x4, BIT(5), BIT(26), 0x0, 0, 0, false, false),
|
||||
};
|
||||
|
||||
static const struct rockchip_pmu_info px30_pmu = {
|
||||
|
@ -182,11 +182,26 @@ static const struct sun20i_ppu_desc sun20i_d1_ppu_desc = {
|
||||
.num_domains = ARRAY_SIZE(sun20i_d1_ppu_pd_names),
|
||||
};
|
||||
|
||||
static const char *const sun8i_v853_ppu_pd_names[] = {
|
||||
"RISCV",
|
||||
"NPU",
|
||||
"VE",
|
||||
};
|
||||
|
||||
static const struct sun20i_ppu_desc sun8i_v853_ppu_desc = {
|
||||
.names = sun8i_v853_ppu_pd_names,
|
||||
.num_domains = ARRAY_SIZE(sun8i_v853_ppu_pd_names),
|
||||
};
|
||||
|
||||
static const struct of_device_id sun20i_ppu_of_match[] = {
|
||||
{
|
||||
.compatible = "allwinner,sun20i-d1-ppu",
|
||||
.data = &sun20i_d1_ppu_desc,
|
||||
},
|
||||
{
|
||||
.compatible = "allwinner,sun8i-v853-ppu",
|
||||
.data = &sun8i_v853_ppu_desc,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sun20i_ppu_of_match);
|
||||
|
12
drivers/pmdomain/thead/Kconfig
Normal file
12
drivers/pmdomain/thead/Kconfig
Normal file
@ -0,0 +1,12 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
config TH1520_PM_DOMAINS
|
||||
tristate "Support TH1520 Power Domains"
|
||||
depends on TH1520_AON_PROTOCOL
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
This driver enables power domain management for the T-HEAD
|
||||
TH-1520 SoC. On this SoC there are number of power domains,
|
||||
which can be managed independently. For example GPU, NPU,
|
||||
and DPU reside in their own power domains which can be
|
||||
turned on/off.
|
2
drivers/pmdomain/thead/Makefile
Normal file
2
drivers/pmdomain/thead/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-$(CONFIG_TH1520_PM_DOMAINS) += th1520-pm-domains.o
|
218
drivers/pmdomain/thead/th1520-pm-domains.c
Normal file
218
drivers/pmdomain/thead/th1520-pm-domains.c
Normal file
@ -0,0 +1,218 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2021 Alibaba Group Holding Limited.
|
||||
* Copyright (c) 2024 Samsung Electronics Co., Ltd.
|
||||
* Author: Michal Wilczynski <m.wilczynski@samsung.com>
|
||||
*/
|
||||
|
||||
#include <linux/firmware/thead/thead,th1520-aon.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
|
||||
#include <dt-bindings/power/thead,th1520-power.h>
|
||||
|
||||
struct th1520_power_domain {
|
||||
struct th1520_aon_chan *aon_chan;
|
||||
struct generic_pm_domain genpd;
|
||||
u32 rsrc;
|
||||
};
|
||||
|
||||
struct th1520_power_info {
|
||||
const char *name;
|
||||
u32 rsrc;
|
||||
bool disabled;
|
||||
};
|
||||
|
||||
/*
|
||||
* The AUDIO power domain is marked as disabled to prevent the driver from
|
||||
* managing its power state. Direct AON firmware calls to control this power
|
||||
* island trigger a firmware bug causing system instability. Until this
|
||||
* firmware issue is resolved, the AUDIO power domain must remain disabled
|
||||
* to avoid crashes.
|
||||
*/
|
||||
static const struct th1520_power_info th1520_pd_ranges[] = {
|
||||
[TH1520_AUDIO_PD] = {"audio", TH1520_AON_AUDIO_PD, true },
|
||||
[TH1520_VDEC_PD] = { "vdec", TH1520_AON_VDEC_PD, false },
|
||||
[TH1520_NPU_PD] = { "npu", TH1520_AON_NPU_PD, false },
|
||||
[TH1520_VENC_PD] = { "venc", TH1520_AON_VENC_PD, false },
|
||||
[TH1520_GPU_PD] = { "gpu", TH1520_AON_GPU_PD, false },
|
||||
[TH1520_DSP0_PD] = { "dsp0", TH1520_AON_DSP0_PD, false },
|
||||
[TH1520_DSP1_PD] = { "dsp1", TH1520_AON_DSP1_PD, false }
|
||||
};
|
||||
|
||||
static inline struct th1520_power_domain *
|
||||
to_th1520_power_domain(struct generic_pm_domain *genpd)
|
||||
{
|
||||
return container_of(genpd, struct th1520_power_domain, genpd);
|
||||
}
|
||||
|
||||
static int th1520_pd_power_on(struct generic_pm_domain *domain)
|
||||
{
|
||||
struct th1520_power_domain *pd = to_th1520_power_domain(domain);
|
||||
|
||||
return th1520_aon_power_update(pd->aon_chan, pd->rsrc, true);
|
||||
}
|
||||
|
||||
static int th1520_pd_power_off(struct generic_pm_domain *domain)
|
||||
{
|
||||
struct th1520_power_domain *pd = to_th1520_power_domain(domain);
|
||||
|
||||
return th1520_aon_power_update(pd->aon_chan, pd->rsrc, false);
|
||||
}
|
||||
|
||||
static struct generic_pm_domain *th1520_pd_xlate(const struct of_phandle_args *spec,
|
||||
void *data)
|
||||
{
|
||||
struct generic_pm_domain *domain = ERR_PTR(-ENOENT);
|
||||
struct genpd_onecell_data *pd_data = data;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(th1520_pd_ranges); i++) {
|
||||
struct th1520_power_domain *pd;
|
||||
|
||||
if (th1520_pd_ranges[i].disabled)
|
||||
continue;
|
||||
|
||||
pd = to_th1520_power_domain(pd_data->domains[i]);
|
||||
if (pd->rsrc == spec->args[0]) {
|
||||
domain = &pd->genpd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return domain;
|
||||
}
|
||||
|
||||
static struct th1520_power_domain *
|
||||
th1520_add_pm_domain(struct device *dev, const struct th1520_power_info *pi)
|
||||
{
|
||||
struct th1520_power_domain *pd;
|
||||
int ret;
|
||||
|
||||
pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
|
||||
if (!pd)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pd->rsrc = pi->rsrc;
|
||||
pd->genpd.power_on = th1520_pd_power_on;
|
||||
pd->genpd.power_off = th1520_pd_power_off;
|
||||
pd->genpd.name = pi->name;
|
||||
|
||||
ret = pm_genpd_init(&pd->genpd, NULL, true);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return pd;
|
||||
}
|
||||
|
||||
static void th1520_pd_init_all_off(struct generic_pm_domain **domains,
|
||||
struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(th1520_pd_ranges); i++) {
|
||||
struct th1520_power_domain *pd;
|
||||
|
||||
if (th1520_pd_ranges[i].disabled)
|
||||
continue;
|
||||
|
||||
pd = to_th1520_power_domain(domains[i]);
|
||||
|
||||
ret = th1520_aon_power_update(pd->aon_chan, pd->rsrc, false);
|
||||
if (ret)
|
||||
dev_err(dev,
|
||||
"Failed to initially power down power domain %s\n",
|
||||
pd->genpd.name);
|
||||
}
|
||||
}
|
||||
|
||||
static int th1520_pd_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct generic_pm_domain **domains;
|
||||
struct genpd_onecell_data *pd_data;
|
||||
struct th1520_aon_chan *aon_chan;
|
||||
struct device *dev = &pdev->dev;
|
||||
int i, ret;
|
||||
|
||||
aon_chan = th1520_aon_init(dev);
|
||||
if (IS_ERR(aon_chan))
|
||||
return dev_err_probe(dev, PTR_ERR(aon_chan),
|
||||
"Failed to get AON channel\n");
|
||||
|
||||
domains = devm_kcalloc(dev, ARRAY_SIZE(th1520_pd_ranges),
|
||||
sizeof(*domains), GFP_KERNEL);
|
||||
if (!domains) {
|
||||
ret = -ENOMEM;
|
||||
goto err_clean_aon;
|
||||
}
|
||||
|
||||
pd_data = devm_kzalloc(dev, sizeof(*pd_data), GFP_KERNEL);
|
||||
if (!pd_data) {
|
||||
ret = -ENOMEM;
|
||||
goto err_clean_aon;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(th1520_pd_ranges); i++) {
|
||||
struct th1520_power_domain *pd;
|
||||
|
||||
if (th1520_pd_ranges[i].disabled)
|
||||
continue;
|
||||
|
||||
pd = th1520_add_pm_domain(dev, &th1520_pd_ranges[i]);
|
||||
if (IS_ERR(pd)) {
|
||||
ret = PTR_ERR(pd);
|
||||
goto err_clean_genpd;
|
||||
}
|
||||
|
||||
pd->aon_chan = aon_chan;
|
||||
domains[i] = &pd->genpd;
|
||||
dev_dbg(dev, "added power domain %s\n", pd->genpd.name);
|
||||
}
|
||||
|
||||
pd_data->domains = domains;
|
||||
pd_data->num_domains = ARRAY_SIZE(th1520_pd_ranges);
|
||||
pd_data->xlate = th1520_pd_xlate;
|
||||
|
||||
/*
|
||||
* Initialize all power domains to off to ensure they start in a
|
||||
* low-power state. This allows device drivers to manage power
|
||||
* domains by turning them on or off as needed.
|
||||
*/
|
||||
th1520_pd_init_all_off(domains, dev);
|
||||
|
||||
ret = of_genpd_add_provider_onecell(dev->of_node, pd_data);
|
||||
if (ret)
|
||||
goto err_clean_genpd;
|
||||
|
||||
return 0;
|
||||
|
||||
err_clean_genpd:
|
||||
for (i--; i >= 0; i--)
|
||||
pm_genpd_remove(domains[i]);
|
||||
err_clean_aon:
|
||||
th1520_aon_deinit(aon_chan);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id th1520_pd_match[] = {
|
||||
{ .compatible = "thead,th1520-aon" },
|
||||
{ /* Sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, th1520_pd_match);
|
||||
|
||||
static struct platform_driver th1520_pd_driver = {
|
||||
.driver = {
|
||||
.name = "th1520-pd",
|
||||
.of_match_table = th1520_pd_match,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.probe = th1520_pd_probe,
|
||||
};
|
||||
module_platform_driver(th1520_pd_driver);
|
||||
|
||||
MODULE_AUTHOR("Michal Wilczynski <m.wilczynski@samsung.com>");
|
||||
MODULE_DESCRIPTION("T-HEAD TH1520 SoC power domain controller");
|
||||
MODULE_LICENSE("GPL");
|
@ -613,7 +613,7 @@ static int omap_prm_domain_attach_clock(struct device *dev,
|
||||
if (!of_device_is_compatible(np, "simple-pm-bus"))
|
||||
return 0;
|
||||
|
||||
if (!of_property_read_bool(np, "clocks"))
|
||||
if (!of_property_present(np, "clocks"))
|
||||
return 0;
|
||||
|
||||
error = pm_clk_create(dev);
|
||||
|
10
include/dt-bindings/power/allwinner,sun8i-v853-ppu.h
Normal file
10
include/dt-bindings/power/allwinner,sun8i-v853-ppu.h
Normal file
@ -0,0 +1,10 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
|
||||
|
||||
#ifndef _DT_BINDINGS_POWER_SUN8I_V853_PPU_H_
|
||||
#define _DT_BINDINGS_POWER_SUN8I_V853_PPU_H_
|
||||
|
||||
#define PD_RISCV 0
|
||||
#define PD_NPU 1
|
||||
#define PD_VE 2
|
||||
|
||||
#endif
|
@ -65,7 +65,7 @@
|
||||
#define SM6350_MSS 4
|
||||
#define SM6350_MX 5
|
||||
|
||||
/* SM6350 Power Domain Indexes */
|
||||
/* SM6375 Power Domain Indexes */
|
||||
#define SM6375_VDDCX 0
|
||||
#define SM6375_VDDCX_AO 1
|
||||
#define SM6375_VDDCX_VFL 2
|
||||
|
19
include/dt-bindings/power/thead,th1520-power.h
Normal file
19
include/dt-bindings/power/thead,th1520-power.h
Normal file
@ -0,0 +1,19 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
|
||||
/*
|
||||
* Copyright (C) 2022 Alibaba Group Holding Limited.
|
||||
* Copyright (c) 2024 Samsung Electronics Co., Ltd.
|
||||
* Author: Michal Wilczynski <m.wilczynski@samsung.com>
|
||||
*/
|
||||
|
||||
#ifndef __DT_BINDINGS_POWER_TH1520_H
|
||||
#define __DT_BINDINGS_POWER_TH1520_H
|
||||
|
||||
#define TH1520_AUDIO_PD 0
|
||||
#define TH1520_VDEC_PD 1
|
||||
#define TH1520_NPU_PD 2
|
||||
#define TH1520_VENC_PD 3
|
||||
#define TH1520_GPU_PD 4
|
||||
#define TH1520_DSP0_PD 5
|
||||
#define TH1520_DSP1_PD 6
|
||||
|
||||
#endif
|
200
include/linux/firmware/thead/thead,th1520-aon.h
Normal file
200
include/linux/firmware/thead/thead,th1520-aon.h
Normal file
@ -0,0 +1,200 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2021 Alibaba Group Holding Limited.
|
||||
*/
|
||||
|
||||
#ifndef _THEAD_AON_H
|
||||
#define _THEAD_AON_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define AON_RPC_MSG_MAGIC (0xef)
|
||||
#define TH1520_AON_RPC_VERSION 2
|
||||
#define TH1520_AON_RPC_MSG_NUM 7
|
||||
|
||||
struct th1520_aon_chan;
|
||||
|
||||
enum th1520_aon_rpc_svc {
|
||||
TH1520_AON_RPC_SVC_UNKNOWN = 0,
|
||||
TH1520_AON_RPC_SVC_PM = 1,
|
||||
TH1520_AON_RPC_SVC_MISC = 2,
|
||||
TH1520_AON_RPC_SVC_AVFS = 3,
|
||||
TH1520_AON_RPC_SVC_SYS = 4,
|
||||
TH1520_AON_RPC_SVC_WDG = 5,
|
||||
TH1520_AON_RPC_SVC_LPM = 6,
|
||||
TH1520_AON_RPC_SVC_MAX = 0x3F,
|
||||
};
|
||||
|
||||
enum th1520_aon_misc_func {
|
||||
TH1520_AON_MISC_FUNC_UNKNOWN = 0,
|
||||
TH1520_AON_MISC_FUNC_SET_CONTROL = 1,
|
||||
TH1520_AON_MISC_FUNC_GET_CONTROL = 2,
|
||||
TH1520_AON_MISC_FUNC_REGDUMP_CFG = 3,
|
||||
};
|
||||
|
||||
enum th1520_aon_wdg_func {
|
||||
TH1520_AON_WDG_FUNC_UNKNOWN = 0,
|
||||
TH1520_AON_WDG_FUNC_START = 1,
|
||||
TH1520_AON_WDG_FUNC_STOP = 2,
|
||||
TH1520_AON_WDG_FUNC_PING = 3,
|
||||
TH1520_AON_WDG_FUNC_TIMEOUTSET = 4,
|
||||
TH1520_AON_WDG_FUNC_RESTART = 5,
|
||||
TH1520_AON_WDG_FUNC_GET_STATE = 6,
|
||||
TH1520_AON_WDG_FUNC_POWER_OFF = 7,
|
||||
TH1520_AON_WDG_FUNC_AON_WDT_ON = 8,
|
||||
TH1520_AON_WDG_FUNC_AON_WDT_OFF = 9,
|
||||
};
|
||||
|
||||
enum th1520_aon_sys_func {
|
||||
TH1520_AON_SYS_FUNC_UNKNOWN = 0,
|
||||
TH1520_AON_SYS_FUNC_AON_RESERVE_MEM = 1,
|
||||
};
|
||||
|
||||
enum th1520_aon_lpm_func {
|
||||
TH1520_AON_LPM_FUNC_UNKNOWN = 0,
|
||||
TH1520_AON_LPM_FUNC_REQUIRE_STR = 1,
|
||||
TH1520_AON_LPM_FUNC_RESUME_STR = 2,
|
||||
TH1520_AON_LPM_FUNC_REQUIRE_STD = 3,
|
||||
TH1520_AON_LPM_FUNC_CPUHP = 4,
|
||||
TH1520_AON_LPM_FUNC_REGDUMP_CFG = 5,
|
||||
};
|
||||
|
||||
enum th1520_aon_pm_func {
|
||||
TH1520_AON_PM_FUNC_UNKNOWN = 0,
|
||||
TH1520_AON_PM_FUNC_SET_RESOURCE_REGULATOR = 1,
|
||||
TH1520_AON_PM_FUNC_GET_RESOURCE_REGULATOR = 2,
|
||||
TH1520_AON_PM_FUNC_SET_RESOURCE_POWER_MODE = 3,
|
||||
TH1520_AON_PM_FUNC_PWR_SET = 4,
|
||||
TH1520_AON_PM_FUNC_PWR_GET = 5,
|
||||
TH1520_AON_PM_FUNC_CHECK_FAULT = 6,
|
||||
TH1520_AON_PM_FUNC_GET_TEMPERATURE = 7,
|
||||
};
|
||||
|
||||
struct th1520_aon_rpc_msg_hdr {
|
||||
u8 ver; /* version of msg hdr */
|
||||
u8 size; /* msg size ,uinit in bytes,the size includes rpc msg header self */
|
||||
u8 svc; /* rpc main service id */
|
||||
u8 func; /* rpc sub func id of specific service, sent by caller */
|
||||
} __packed __aligned(1);
|
||||
|
||||
struct th1520_aon_rpc_ack_common {
|
||||
struct th1520_aon_rpc_msg_hdr hdr;
|
||||
u8 err_code;
|
||||
} __packed __aligned(1);
|
||||
|
||||
#define RPC_SVC_MSG_TYPE_DATA 0
|
||||
#define RPC_SVC_MSG_TYPE_ACK 1
|
||||
#define RPC_SVC_MSG_NEED_ACK 0
|
||||
#define RPC_SVC_MSG_NO_NEED_ACK 1
|
||||
|
||||
#define RPC_GET_VER(MESG) ((MESG)->ver)
|
||||
#define RPC_SET_VER(MESG, VER) ((MESG)->ver = (VER))
|
||||
#define RPC_GET_SVC_ID(MESG) ((MESG)->svc & 0x3F)
|
||||
#define RPC_SET_SVC_ID(MESG, ID) ((MESG)->svc |= 0x3F & (ID))
|
||||
#define RPC_GET_SVC_FLAG_MSG_TYPE(MESG) (((MESG)->svc & 0x80) >> 7)
|
||||
#define RPC_SET_SVC_FLAG_MSG_TYPE(MESG, TYPE) ((MESG)->svc |= (TYPE) << 7)
|
||||
#define RPC_GET_SVC_FLAG_ACK_TYPE(MESG) (((MESG)->svc & 0x40) >> 6)
|
||||
#define RPC_SET_SVC_FLAG_ACK_TYPE(MESG, ACK) ((MESG)->svc |= (ACK) << 6)
|
||||
|
||||
#define RPC_SET_BE64(MESG, OFFSET, SET_DATA) \
|
||||
do { \
|
||||
u8 *data = (u8 *)(MESG); \
|
||||
u64 _offset = (OFFSET); \
|
||||
u64 _set_data = (SET_DATA); \
|
||||
data[_offset + 7] = _set_data & 0xFF; \
|
||||
data[_offset + 6] = (_set_data & 0xFF00) >> 8; \
|
||||
data[_offset + 5] = (_set_data & 0xFF0000) >> 16; \
|
||||
data[_offset + 4] = (_set_data & 0xFF000000) >> 24; \
|
||||
data[_offset + 3] = (_set_data & 0xFF00000000) >> 32; \
|
||||
data[_offset + 2] = (_set_data & 0xFF0000000000) >> 40; \
|
||||
data[_offset + 1] = (_set_data & 0xFF000000000000) >> 48; \
|
||||
data[_offset + 0] = (_set_data & 0xFF00000000000000) >> 56; \
|
||||
} while (0)
|
||||
|
||||
#define RPC_SET_BE32(MESG, OFFSET, SET_DATA) \
|
||||
do { \
|
||||
u8 *data = (u8 *)(MESG); \
|
||||
u64 _offset = (OFFSET); \
|
||||
u64 _set_data = (SET_DATA); \
|
||||
data[_offset + 3] = (_set_data) & 0xFF; \
|
||||
data[_offset + 2] = (_set_data & 0xFF00) >> 8; \
|
||||
data[_offset + 1] = (_set_data & 0xFF0000) >> 16; \
|
||||
data[_offset + 0] = (_set_data & 0xFF000000) >> 24; \
|
||||
} while (0)
|
||||
|
||||
#define RPC_SET_BE16(MESG, OFFSET, SET_DATA) \
|
||||
do { \
|
||||
u8 *data = (u8 *)(MESG); \
|
||||
u64 _offset = (OFFSET); \
|
||||
u64 _set_data = (SET_DATA); \
|
||||
data[_offset + 1] = (_set_data) & 0xFF; \
|
||||
data[_offset + 0] = (_set_data & 0xFF00) >> 8; \
|
||||
} while (0)
|
||||
|
||||
#define RPC_SET_U8(MESG, OFFSET, SET_DATA) \
|
||||
do { \
|
||||
u8 *data = (u8 *)(MESG); \
|
||||
data[OFFSET] = (SET_DATA) & 0xFF; \
|
||||
} while (0)
|
||||
|
||||
#define RPC_GET_BE64(MESG, OFFSET, PTR) \
|
||||
do { \
|
||||
u8 *data = (u8 *)(MESG); \
|
||||
u64 _offset = (OFFSET); \
|
||||
*(u32 *)(PTR) = \
|
||||
(data[_offset + 7] | data[_offset + 6] << 8 | \
|
||||
data[_offset + 5] << 16 | data[_offset + 4] << 24 | \
|
||||
data[_offset + 3] << 32 | data[_offset + 2] << 40 | \
|
||||
data[_offset + 1] << 48 | data[_offset + 0] << 56); \
|
||||
} while (0)
|
||||
|
||||
#define RPC_GET_BE32(MESG, OFFSET, PTR) \
|
||||
do { \
|
||||
u8 *data = (u8 *)(MESG); \
|
||||
u64 _offset = (OFFSET); \
|
||||
*(u32 *)(PTR) = \
|
||||
(data[_offset + 3] | data[_offset + 2] << 8 | \
|
||||
data[_offset + 1] << 16 | data[_offset + 0] << 24); \
|
||||
} while (0)
|
||||
|
||||
#define RPC_GET_BE16(MESG, OFFSET, PTR) \
|
||||
do { \
|
||||
u8 *data = (u8 *)(MESG); \
|
||||
u64 _offset = (OFFSET); \
|
||||
*(u16 *)(PTR) = (data[_offset + 1] | data[_offset + 0] << 8); \
|
||||
} while (0)
|
||||
|
||||
#define RPC_GET_U8(MESG, OFFSET, PTR) \
|
||||
do { \
|
||||
u8 *data = (u8 *)(MESG); \
|
||||
*(u8 *)(PTR) = (data[OFFSET]); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Defines for SC PM Power Mode
|
||||
*/
|
||||
#define TH1520_AON_PM_PW_MODE_OFF 0 /* Power off */
|
||||
#define TH1520_AON_PM_PW_MODE_STBY 1 /* Power in standby */
|
||||
#define TH1520_AON_PM_PW_MODE_LP 2 /* Power in low-power */
|
||||
#define TH1520_AON_PM_PW_MODE_ON 3 /* Power on */
|
||||
|
||||
/*
|
||||
* Defines for AON power islands
|
||||
*/
|
||||
#define TH1520_AON_AUDIO_PD 0
|
||||
#define TH1520_AON_VDEC_PD 1
|
||||
#define TH1520_AON_NPU_PD 2
|
||||
#define TH1520_AON_VENC_PD 3
|
||||
#define TH1520_AON_GPU_PD 4
|
||||
#define TH1520_AON_DSP0_PD 5
|
||||
#define TH1520_AON_DSP1_PD 6
|
||||
|
||||
struct th1520_aon_chan *th1520_aon_init(struct device *dev);
|
||||
void th1520_aon_deinit(struct th1520_aon_chan *aon_chan);
|
||||
|
||||
int th1520_aon_call_rpc(struct th1520_aon_chan *aon_chan, void *msg);
|
||||
int th1520_aon_power_update(struct th1520_aon_chan *aon_chan, u16 rsrc,
|
||||
bool power_on);
|
||||
|
||||
#endif /* _THEAD_AON_H */
|
@ -261,6 +261,7 @@ struct generic_pm_domain_data {
|
||||
unsigned int rpm_pstate;
|
||||
unsigned int opp_token;
|
||||
bool hw_mode;
|
||||
bool rpm_always_on;
|
||||
void *data;
|
||||
};
|
||||
|
||||
@ -293,6 +294,7 @@ ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev);
|
||||
void dev_pm_genpd_synced_poweroff(struct device *dev);
|
||||
int dev_pm_genpd_set_hwmode(struct device *dev, bool enable);
|
||||
bool dev_pm_genpd_get_hwmode(struct device *dev);
|
||||
int dev_pm_genpd_rpm_always_on(struct device *dev, bool on);
|
||||
|
||||
extern struct dev_power_governor simple_qos_governor;
|
||||
extern struct dev_power_governor pm_domain_always_on_gov;
|
||||
@ -376,6 +378,11 @@ static inline bool dev_pm_genpd_get_hwmode(struct device *dev)
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int dev_pm_genpd_rpm_always_on(struct device *dev, bool on)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#define simple_qos_governor (*(struct dev_power_governor *)(NULL))
|
||||
#define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL))
|
||||
#endif
|
||||
|
@ -6,6 +6,9 @@
|
||||
#ifndef __SOC_ROCKCHIP_SIP_H
|
||||
#define __SOC_ROCKCHIP_SIP_H
|
||||
|
||||
#define ROCKCHIP_SIP_SUSPEND_MODE 0x82000003
|
||||
#define ROCKCHIP_SLEEP_PD_CONFIG 0xff
|
||||
|
||||
#define ROCKCHIP_SIP_DRAM_FREQ 0x82000008
|
||||
#define ROCKCHIP_SIP_CONFIG_DRAM_INIT 0x00
|
||||
#define ROCKCHIP_SIP_CONFIG_DRAM_SET_RATE 0x01
|
||||
|
@ -62,6 +62,43 @@ TRACE_EVENT(cpu_idle_miss,
|
||||
(unsigned long)__entry->state, (__entry->below)?"below":"above")
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(psci_domain_idle,
|
||||
|
||||
TP_PROTO(unsigned int cpu_id, unsigned int state, bool s2idle),
|
||||
|
||||
TP_ARGS(cpu_id, state, s2idle),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, cpu_id)
|
||||
__field(u32, state)
|
||||
__field(bool, s2idle)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->cpu_id = cpu_id;
|
||||
__entry->state = state;
|
||||
__entry->s2idle = s2idle;
|
||||
),
|
||||
|
||||
TP_printk("cpu_id=%lu state=0x%lx is_s2idle=%s",
|
||||
(unsigned long)__entry->cpu_id, (unsigned long)__entry->state,
|
||||
(__entry->s2idle)?"yes":"no")
|
||||
);
|
||||
|
||||
DEFINE_EVENT(psci_domain_idle, psci_domain_idle_enter,
|
||||
|
||||
TP_PROTO(unsigned int cpu_id, unsigned int state, bool s2idle),
|
||||
|
||||
TP_ARGS(cpu_id, state, s2idle)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(psci_domain_idle, psci_domain_idle_exit,
|
||||
|
||||
TP_PROTO(unsigned int cpu_id, unsigned int state, bool s2idle),
|
||||
|
||||
TP_ARGS(cpu_id, state, s2idle)
|
||||
);
|
||||
|
||||
TRACE_EVENT(powernv_throttle,
|
||||
|
||||
TP_PROTO(int chip_id, const char *reason, int pmax),
|
||||
|
Loading…
x
Reference in New Issue
Block a user