Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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
...

+1039 -90
+53
Documentation/devicetree/bindings/firmware/thead,th1520-aon.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/firmware/thead,th1520-aon.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: T-HEAD TH1520 AON (Always-On) Firmware 8 + 9 + description: | 10 + The Always-On (AON) subsystem in the TH1520 SoC is responsible for managing 11 + low-power states, system wakeup events, and power management tasks. It is 12 + designed to operate independently in a dedicated power domain, allowing it to 13 + remain functional even during the SoC's deep sleep states. 14 + 15 + At the heart of the AON subsystem is the E902, a low-power core that executes 16 + firmware responsible for coordinating tasks such as power domain control, 17 + clock management, and system wakeup signaling. Communication between the main 18 + SoC and the AON subsystem is handled through a mailbox interface, which 19 + enables message-based interactions with the AON firmware. 20 + 21 + maintainers: 22 + - Michal Wilczynski <m.wilczynski@samsung.com> 23 + 24 + properties: 25 + compatible: 26 + const: thead,th1520-aon 27 + 28 + mboxes: 29 + maxItems: 1 30 + 31 + mbox-names: 32 + items: 33 + - const: aon 34 + 35 + "#power-domain-cells": 36 + const: 1 37 + 38 + required: 39 + - compatible 40 + - mboxes 41 + - mbox-names 42 + - "#power-domain-cells" 43 + 44 + additionalProperties: false 45 + 46 + examples: 47 + - | 48 + aon: aon { 49 + compatible = "thead,th1520-aon"; 50 + mboxes = <&mbox_910t 1>; 51 + mbox-names = "aon"; 52 + #power-domain-cells = <1>; 53 + };
+1
Documentation/devicetree/bindings/power/allwinner,sun20i-d1-ppu.yaml
··· 17 17 compatible: 18 18 enum: 19 19 - allwinner,sun20i-d1-ppu 20 + - allwinner,sun8i-v853-ppu 20 21 21 22 reg: 22 23 maxItems: 1
+3
Documentation/devicetree/bindings/power/rockchip,power-controller.yaml
··· 132 132 A number of phandles to clocks that need to be enabled 133 133 while power domain switches state. 134 134 135 + domain-supply: 136 + description: domain regulator supply. 137 + 135 138 pm_qos: 136 139 $ref: /schemas/types.yaml#/definitions/phandle-array 137 140 items:
+7
MAINTAINERS
··· 6103 6103 CPUIDLE DRIVER - ARM PSCI 6104 6104 M: Lorenzo Pieralisi <lpieralisi@kernel.org> 6105 6105 M: Sudeep Holla <sudeep.holla@arm.com> 6106 + M: Ulf Hansson <ulf.hansson@linaro.org> 6106 6107 L: linux-pm@vger.kernel.org 6107 6108 L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) 6108 6109 S: Supported 6110 + T: git git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm.git 6109 6111 F: drivers/cpuidle/cpuidle-psci.c 6110 6112 6111 6113 CPUIDLE DRIVER - ARM PSCI PM DOMAIN ··· 20512 20510 S: Maintained 20513 20511 T: git https://github.com/pdp7/linux.git 20514 20512 F: Documentation/devicetree/bindings/clock/thead,th1520-clk-ap.yaml 20513 + F: Documentation/devicetree/bindings/firmware/thead,th1520-aon.yaml 20515 20514 F: Documentation/devicetree/bindings/mailbox/thead,th1520-mbox.yaml 20516 20515 F: Documentation/devicetree/bindings/net/thead,th1520-gmac.yaml 20517 20516 F: Documentation/devicetree/bindings/pinctrl/thead,th1520-pinctrl.yaml 20518 20517 F: arch/riscv/boot/dts/thead/ 20519 20518 F: drivers/clk/thead/clk-th1520-ap.c 20519 + F: drivers/firmware/thead,th1520-aon.c 20520 20520 F: drivers/mailbox/mailbox-th1520.c 20521 20521 F: drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c 20522 20522 F: drivers/pinctrl/pinctrl-th1520.c 20523 + F: drivers/pmdomain/thead/ 20523 20524 F: include/dt-bindings/clock/thead,th1520-clk-ap.h 20525 + F: include/dt-bindings/power/thead,th1520-power.h 20526 + F: include/linux/firmware/thead/thead,th1520-aon.h 20524 20527 20525 20528 RNBD BLOCK DRIVERS 20526 20529 M: Md. Haris Iqbal <haris.iqbal@ionos.com>
+3
drivers/cpuidle/cpuidle-psci.c
··· 25 25 #include <linux/syscore_ops.h> 26 26 27 27 #include <asm/cpuidle.h> 28 + #include <trace/events/power.h> 28 29 29 30 #include "cpuidle-psci.h" 30 31 #include "dt_idle_states.h" ··· 75 74 if (!state) 76 75 state = states[idx]; 77 76 77 + trace_psci_domain_idle_enter(dev->cpu, state, s2idle); 78 78 ret = psci_cpu_suspend_enter(state) ? -1 : idx; 79 + trace_psci_domain_idle_exit(dev->cpu, state, s2idle); 79 80 80 81 if (s2idle) 81 82 dev_pm_genpd_resume(pd_dev);
+10
drivers/firmware/Kconfig
··· 212 212 213 213 If unsure, say Y. 214 214 215 + config TH1520_AON_PROTOCOL 216 + tristate "Always-On firmware protocol" 217 + depends on ARCH_THEAD || COMPILE_TEST 218 + depends on MAILBOX 219 + help 220 + Power, clock, and resource management capabilities on the TH1520 SoC are 221 + managed by the E902 core. Firmware running on this core communicates with 222 + the kernel through the Always-On protocol, using hardware mailbox as a medium. 223 + Say yes if you need such capabilities. 224 + 215 225 config TI_SCI_PROTOCOL 216 226 tristate "TI System Control Interface (TISCI) Message Protocol" 217 227 depends on TI_MESSAGE_MANAGER
+1
drivers/firmware/Makefile
··· 18 18 obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o 19 19 obj-$(CONFIG_SYSFB) += sysfb.o 20 20 obj-$(CONFIG_SYSFB_SIMPLEFB) += sysfb_simplefb.o 21 + obj-$(CONFIG_TH1520_AON_PROTOCOL) += thead,th1520-aon.o 21 22 obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o 22 23 obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o 23 24 obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o
+250
drivers/firmware/thead,th1520-aon.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2021 Alibaba Group Holding Limited. 4 + * Copyright (c) 2024 Samsung Electronics Co., Ltd. 5 + * Author: Michal Wilczynski <m.wilczynski@samsung.com> 6 + */ 7 + 8 + #include <linux/device.h> 9 + #include <linux/firmware/thead/thead,th1520-aon.h> 10 + #include <linux/mailbox_client.h> 11 + #include <linux/mailbox_controller.h> 12 + #include <linux/slab.h> 13 + 14 + #define MAX_RX_TIMEOUT (msecs_to_jiffies(3000)) 15 + #define MAX_TX_TIMEOUT 500 16 + 17 + struct th1520_aon_chan { 18 + struct mbox_chan *ch; 19 + struct th1520_aon_rpc_ack_common ack_msg; 20 + struct mbox_client cl; 21 + struct completion done; 22 + 23 + /* make sure only one RPC is performed at a time */ 24 + struct mutex transaction_lock; 25 + }; 26 + 27 + struct th1520_aon_msg_req_set_resource_power_mode { 28 + struct th1520_aon_rpc_msg_hdr hdr; 29 + u16 resource; 30 + u16 mode; 31 + u16 reserved[10]; 32 + } __packed __aligned(1); 33 + 34 + /* 35 + * This type is used to indicate error response for most functions. 36 + */ 37 + enum th1520_aon_error_codes { 38 + LIGHT_AON_ERR_NONE = 0, /* Success */ 39 + LIGHT_AON_ERR_VERSION = 1, /* Incompatible API version */ 40 + LIGHT_AON_ERR_CONFIG = 2, /* Configuration error */ 41 + LIGHT_AON_ERR_PARM = 3, /* Bad parameter */ 42 + LIGHT_AON_ERR_NOACCESS = 4, /* Permission error (no access) */ 43 + LIGHT_AON_ERR_LOCKED = 5, /* Permission error (locked) */ 44 + LIGHT_AON_ERR_UNAVAILABLE = 6, /* Unavailable (out of resources) */ 45 + LIGHT_AON_ERR_NOTFOUND = 7, /* Not found */ 46 + LIGHT_AON_ERR_NOPOWER = 8, /* No power */ 47 + LIGHT_AON_ERR_IPC = 9, /* Generic IPC error */ 48 + LIGHT_AON_ERR_BUSY = 10, /* Resource is currently busy/active */ 49 + LIGHT_AON_ERR_FAIL = 11, /* General I/O failure */ 50 + LIGHT_AON_ERR_LAST 51 + }; 52 + 53 + static int th1520_aon_linux_errmap[LIGHT_AON_ERR_LAST] = { 54 + 0, /* LIGHT_AON_ERR_NONE */ 55 + -EINVAL, /* LIGHT_AON_ERR_VERSION */ 56 + -EINVAL, /* LIGHT_AON_ERR_CONFIG */ 57 + -EINVAL, /* LIGHT_AON_ERR_PARM */ 58 + -EACCES, /* LIGHT_AON_ERR_NOACCESS */ 59 + -EACCES, /* LIGHT_AON_ERR_LOCKED */ 60 + -ERANGE, /* LIGHT_AON_ERR_UNAVAILABLE */ 61 + -EEXIST, /* LIGHT_AON_ERR_NOTFOUND */ 62 + -EPERM, /* LIGHT_AON_ERR_NOPOWER */ 63 + -EPIPE, /* LIGHT_AON_ERR_IPC */ 64 + -EBUSY, /* LIGHT_AON_ERR_BUSY */ 65 + -EIO, /* LIGHT_AON_ERR_FAIL */ 66 + }; 67 + 68 + static inline int th1520_aon_to_linux_errno(int errno) 69 + { 70 + if (errno >= LIGHT_AON_ERR_NONE && errno < LIGHT_AON_ERR_LAST) 71 + return th1520_aon_linux_errmap[errno]; 72 + 73 + return -EIO; 74 + } 75 + 76 + static void th1520_aon_rx_callback(struct mbox_client *c, void *rx_msg) 77 + { 78 + struct th1520_aon_chan *aon_chan = 79 + container_of(c, struct th1520_aon_chan, cl); 80 + struct th1520_aon_rpc_msg_hdr *hdr = 81 + (struct th1520_aon_rpc_msg_hdr *)rx_msg; 82 + u8 recv_size = sizeof(struct th1520_aon_rpc_msg_hdr) + hdr->size; 83 + 84 + if (recv_size != sizeof(struct th1520_aon_rpc_ack_common)) { 85 + dev_err(c->dev, "Invalid ack size, not completing\n"); 86 + return; 87 + } 88 + 89 + memcpy(&aon_chan->ack_msg, rx_msg, recv_size); 90 + complete(&aon_chan->done); 91 + } 92 + 93 + /** 94 + * th1520_aon_call_rpc() - Send an RPC request to the TH1520 AON subsystem 95 + * @aon_chan: Pointer to the AON channel structure 96 + * @msg: Pointer to the message (RPC payload) that will be sent 97 + * 98 + * This function sends an RPC message to the TH1520 AON subsystem via mailbox. 99 + * It takes the provided @msg buffer, formats it with version and service flags, 100 + * then blocks until the RPC completes or times out. The completion is signaled 101 + * by the `aon_chan->done` completion, which is waited upon for a duration 102 + * defined by `MAX_RX_TIMEOUT`. 103 + * 104 + * Return: 105 + * * 0 on success 106 + * * -ETIMEDOUT if the RPC call times out 107 + * * A negative error code if the mailbox send fails or if AON responds with 108 + * a non-zero error code (converted via th1520_aon_to_linux_errno()). 109 + */ 110 + int th1520_aon_call_rpc(struct th1520_aon_chan *aon_chan, void *msg) 111 + { 112 + struct th1520_aon_rpc_msg_hdr *hdr = msg; 113 + int ret; 114 + 115 + mutex_lock(&aon_chan->transaction_lock); 116 + reinit_completion(&aon_chan->done); 117 + 118 + RPC_SET_VER(hdr, TH1520_AON_RPC_VERSION); 119 + RPC_SET_SVC_ID(hdr, hdr->svc); 120 + RPC_SET_SVC_FLAG_MSG_TYPE(hdr, RPC_SVC_MSG_TYPE_DATA); 121 + RPC_SET_SVC_FLAG_ACK_TYPE(hdr, RPC_SVC_MSG_NEED_ACK); 122 + 123 + ret = mbox_send_message(aon_chan->ch, msg); 124 + if (ret < 0) { 125 + dev_err(aon_chan->cl.dev, "RPC send msg failed: %d\n", ret); 126 + goto out; 127 + } 128 + 129 + if (!wait_for_completion_timeout(&aon_chan->done, MAX_RX_TIMEOUT)) { 130 + dev_err(aon_chan->cl.dev, "RPC send msg timeout\n"); 131 + mutex_unlock(&aon_chan->transaction_lock); 132 + return -ETIMEDOUT; 133 + } 134 + 135 + ret = aon_chan->ack_msg.err_code; 136 + 137 + out: 138 + mutex_unlock(&aon_chan->transaction_lock); 139 + 140 + return th1520_aon_to_linux_errno(ret); 141 + } 142 + EXPORT_SYMBOL_GPL(th1520_aon_call_rpc); 143 + 144 + /** 145 + * th1520_aon_power_update() - Change power state of a resource via TH1520 AON 146 + * @aon_chan: Pointer to the AON channel structure 147 + * @rsrc: Resource ID whose power state needs to be updated 148 + * @power_on: Boolean indicating whether the resource should be powered on (true) 149 + * or powered off (false) 150 + * 151 + * This function requests the TH1520 AON subsystem to set the power mode of the 152 + * given resource (@rsrc) to either on or off. It constructs the message in 153 + * `struct th1520_aon_msg_req_set_resource_power_mode` and then invokes 154 + * th1520_aon_call_rpc() to make the request. If the AON call fails, an error 155 + * message is logged along with the specific return code. 156 + * 157 + * Return: 158 + * * 0 on success 159 + * * A negative error code in case of failures (propagated from 160 + * th1520_aon_call_rpc()). 161 + */ 162 + int th1520_aon_power_update(struct th1520_aon_chan *aon_chan, u16 rsrc, 163 + bool power_on) 164 + { 165 + struct th1520_aon_msg_req_set_resource_power_mode msg = {}; 166 + struct th1520_aon_rpc_msg_hdr *hdr = &msg.hdr; 167 + int ret; 168 + 169 + hdr->svc = TH1520_AON_RPC_SVC_PM; 170 + hdr->func = TH1520_AON_PM_FUNC_SET_RESOURCE_POWER_MODE; 171 + hdr->size = TH1520_AON_RPC_MSG_NUM; 172 + 173 + RPC_SET_BE16(&msg.resource, 0, rsrc); 174 + RPC_SET_BE16(&msg.resource, 2, 175 + (power_on ? TH1520_AON_PM_PW_MODE_ON : 176 + TH1520_AON_PM_PW_MODE_OFF)); 177 + 178 + ret = th1520_aon_call_rpc(aon_chan, &msg); 179 + if (ret) 180 + dev_err(aon_chan->cl.dev, "failed to power %s resource %d ret %d\n", 181 + power_on ? "up" : "off", rsrc, ret); 182 + 183 + return ret; 184 + } 185 + EXPORT_SYMBOL_GPL(th1520_aon_power_update); 186 + 187 + /** 188 + * th1520_aon_init() - Initialize TH1520 AON firmware protocol interface 189 + * @dev: Device pointer for the AON subsystem 190 + * 191 + * This function initializes the TH1520 AON firmware protocol interface by: 192 + * - Allocating and initializing the AON channel structure 193 + * - Setting up the mailbox client 194 + * - Requesting the AON mailbox channel 195 + * - Initializing synchronization primitives 196 + * 197 + * Return: 198 + * * Valid pointer to th1520_aon_chan structure on success 199 + * * ERR_PTR(-ENOMEM) if memory allocation fails 200 + * * ERR_PTR() with other negative error codes from mailbox operations 201 + */ 202 + struct th1520_aon_chan *th1520_aon_init(struct device *dev) 203 + { 204 + struct th1520_aon_chan *aon_chan; 205 + struct mbox_client *cl; 206 + int ret; 207 + 208 + aon_chan = kzalloc(sizeof(*aon_chan), GFP_KERNEL); 209 + if (!aon_chan) 210 + return ERR_PTR(-ENOMEM); 211 + 212 + cl = &aon_chan->cl; 213 + cl->dev = dev; 214 + cl->tx_block = true; 215 + cl->tx_tout = MAX_TX_TIMEOUT; 216 + cl->rx_callback = th1520_aon_rx_callback; 217 + 218 + aon_chan->ch = mbox_request_channel_byname(cl, "aon"); 219 + if (IS_ERR(aon_chan->ch)) { 220 + dev_err(dev, "Failed to request aon mbox chan\n"); 221 + ret = PTR_ERR(aon_chan->ch); 222 + kfree(aon_chan); 223 + return ERR_PTR(ret); 224 + } 225 + 226 + mutex_init(&aon_chan->transaction_lock); 227 + init_completion(&aon_chan->done); 228 + 229 + return aon_chan; 230 + } 231 + EXPORT_SYMBOL_GPL(th1520_aon_init); 232 + 233 + /** 234 + * th1520_aon_deinit() - Clean up TH1520 AON firmware protocol interface 235 + * @aon_chan: Pointer to the AON channel structure to clean up 236 + * 237 + * This function cleans up resources allocated by th1520_aon_init(): 238 + * - Frees the mailbox channel 239 + * - Frees the AON channel 240 + */ 241 + void th1520_aon_deinit(struct th1520_aon_chan *aon_chan) 242 + { 243 + mbox_free_channel(aon_chan->ch); 244 + kfree(aon_chan); 245 + } 246 + EXPORT_SYMBOL_GPL(th1520_aon_deinit); 247 + 248 + MODULE_AUTHOR("Michal Wilczynski <m.wilczynski@samsung.com>"); 249 + MODULE_DESCRIPTION("T-HEAD TH1520 Always-On firmware protocol library"); 250 + MODULE_LICENSE("GPL");
+1
drivers/pmdomain/Kconfig
··· 16 16 source "drivers/pmdomain/starfive/Kconfig" 17 17 source "drivers/pmdomain/sunxi/Kconfig" 18 18 source "drivers/pmdomain/tegra/Kconfig" 19 + source "drivers/pmdomain/thead/Kconfig" 19 20 source "drivers/pmdomain/ti/Kconfig" 20 21 source "drivers/pmdomain/xilinx/Kconfig" 21 22
+1
drivers/pmdomain/Makefile
··· 14 14 obj-y += starfive/ 15 15 obj-y += sunxi/ 16 16 obj-y += tegra/ 17 + obj-y += thead/ 17 18 obj-y += ti/ 18 19 obj-y += xilinx/ 19 20 obj-y += core.o governor.o
+2 -9
drivers/pmdomain/arm/scmi_pm_domain.c
··· 24 24 25 25 static int scmi_pd_power(struct generic_pm_domain *domain, bool power_on) 26 26 { 27 - int ret; 28 - u32 state, ret_state; 27 + u32 state; 29 28 struct scmi_pm_domain *pd = to_scmi_pd(domain); 30 29 31 30 if (power_on) ··· 32 33 else 33 34 state = SCMI_POWER_STATE_GENERIC_OFF; 34 35 35 - ret = power_ops->state_set(pd->ph, pd->domain, state); 36 - if (!ret) 37 - ret = power_ops->state_get(pd->ph, pd->domain, &ret_state); 38 - if (!ret && state != ret_state) 39 - return -EIO; 40 - 41 - return ret; 36 + return power_ops->state_set(pd->ph, pd->domain, state); 42 37 } 43 38 44 39 static int scmi_pd_power_on(struct generic_pm_domain *domain)
+1
drivers/pmdomain/bcm/bcm2835-power.c
··· 520 520 } 521 521 522 522 dom->base.name = name; 523 + dom->base.flags = GENPD_FLAG_ACTIVE_WAKEUP; 523 524 dom->base.power_on = bcm2835_power_pd_power_on; 524 525 dom->base.power_off = bcm2835_power_pd_power_off; 525 526
+35
drivers/pmdomain/core.c
··· 697 697 } 698 698 EXPORT_SYMBOL_GPL(dev_pm_genpd_get_hwmode); 699 699 700 + /** 701 + * dev_pm_genpd_rpm_always_on() - Control if the PM domain can be powered off. 702 + * 703 + * @dev: Device for which the PM domain may need to stay on for. 704 + * @on: Value to set or unset for the condition. 705 + * 706 + * For some usecases a consumer driver requires its device to remain power-on 707 + * from the PM domain perspective during runtime. This function allows the 708 + * behaviour to be dynamically controlled for a device attached to a genpd. 709 + * 710 + * It is assumed that the users guarantee that the genpd wouldn't be detached 711 + * while this routine is getting called. 712 + * 713 + * Return: Returns 0 on success and negative error values on failures. 714 + */ 715 + int dev_pm_genpd_rpm_always_on(struct device *dev, bool on) 716 + { 717 + struct generic_pm_domain *genpd; 718 + 719 + genpd = dev_to_genpd_safe(dev); 720 + if (!genpd) 721 + return -ENODEV; 722 + 723 + genpd_lock(genpd); 724 + dev_gpd_data(dev)->rpm_always_on = on; 725 + genpd_unlock(genpd); 726 + 727 + return 0; 728 + } 729 + EXPORT_SYMBOL_GPL(dev_pm_genpd_rpm_always_on); 730 + 700 731 static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed) 701 732 { 702 733 unsigned int state_idx = genpd->state_idx; ··· 899 868 if (!pm_runtime_suspended(pdd->dev) || 900 869 irq_safe_dev_in_sleep_domain(pdd->dev, genpd)) 901 870 not_suspended++; 871 + 872 + /* The device may need its PM domain to stay powered on. */ 873 + if (to_gpd_data(pdd)->rpm_always_on) 874 + return -EBUSY; 902 875 } 903 876 904 877 if (not_suspended > 1 || (not_suspended == 1 && !one_dev_on))
+1 -1
drivers/pmdomain/imx/gpcv2.c
··· 1361 1361 } 1362 1362 1363 1363 if (IS_ENABLED(CONFIG_LOCKDEP) && 1364 - of_property_read_bool(domain->dev->of_node, "power-domains")) 1364 + of_property_present(domain->dev->of_node, "power-domains")) 1365 1365 lockdep_set_subclass(&domain->genpd.mlock, 1); 1366 1366 1367 1367 ret = of_genpd_add_provider_simple(domain->dev->of_node,
-2
drivers/pmdomain/renesas/rcar-sysc.c
··· 434 434 } 435 435 436 436 error = of_genpd_add_provider_onecell(np, &domains->onecell_data); 437 - if (!error) 438 - fwnode_dev_initialized(of_fwnode_handle(np), true); 439 437 440 438 out_put: 441 439 of_node_put(np);
+2
drivers/pmdomain/rockchip/Kconfig
··· 4 4 config ROCKCHIP_PM_DOMAINS 5 5 bool "Rockchip generic power domain" 6 6 depends on PM 7 + depends on HAVE_ARM_SMCCC_DISCOVERY 8 + depends on REGULATOR 7 9 select PM_GENERIC_DOMAINS 8 10 help 9 11 Say y here to enable power domain support.
+143 -76
drivers/pmdomain/rockchip/pm-domains.c
··· 5 5 * Copyright (c) 2015 ROCKCHIP, Co. Ltd. 6 6 */ 7 7 8 + #include <linux/arm-smccc.h> 8 9 #include <linux/io.h> 9 10 #include <linux/iopoll.h> 10 11 #include <linux/err.h> ··· 19 18 #include <linux/of_clk.h> 20 19 #include <linux/clk.h> 21 20 #include <linux/regmap.h> 21 + #include <linux/regulator/consumer.h> 22 22 #include <linux/mfd/syscon.h> 23 23 #include <soc/rockchip/pm_domains.h> 24 + #include <soc/rockchip/rockchip_sip.h> 24 25 #include <dt-bindings/power/px30-power.h> 25 26 #include <dt-bindings/power/rockchip,rv1126-power.h> 26 27 #include <dt-bindings/power/rk3036-power.h> ··· 47 44 int idle_mask; 48 45 int ack_mask; 49 46 bool active_wakeup; 47 + bool need_regulator; 50 48 int pwr_w_mask; 51 49 int req_w_mask; 52 50 int clk_ungate_mask; ··· 96 92 u32 *qos_save_regs[MAX_QOS_REGS_NUM]; 97 93 int num_clks; 98 94 struct clk_bulk_data *clks; 95 + struct device_node *node; 96 + struct regulator *supply; 99 97 }; 100 98 101 99 struct rockchip_pmu { ··· 135 129 .active_wakeup = wakeup, \ 136 130 } 137 131 138 - #define DOMAIN_M_O_R(_name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, ack, wakeup) \ 132 + #define DOMAIN_M_O_R(_name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, ack, wakeup, regulator) \ 139 133 { \ 140 134 .name = _name, \ 141 135 .pwr_offset = p_offset, \ ··· 151 145 .idle_mask = (idle), \ 152 146 .ack_mask = (ack), \ 153 147 .active_wakeup = wakeup, \ 148 + .need_regulator = regulator, \ 154 149 } 155 150 156 151 #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) \ ··· 310 303 } 311 304 EXPORT_SYMBOL_GPL(rockchip_pmu_unblock); 312 305 313 - #define DOMAIN_RK3588(name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, wakeup) \ 314 - DOMAIN_M_O_R(name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, idle, wakeup) 306 + #define DOMAIN_RK3588(name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, wakeup, regulator) \ 307 + DOMAIN_M_O_R(name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, idle, wakeup, regulator) 315 308 316 309 static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd) 317 310 { ··· 540 533 return ret; 541 534 } 542 535 543 - static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd, 544 - bool on) 536 + static int rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd, 537 + bool on) 545 538 { 546 539 struct rockchip_pmu *pmu = pd->pmu; 547 540 struct generic_pm_domain *genpd = &pd->genpd; 548 541 u32 pd_pwr_offset = pd->info->pwr_offset; 549 542 bool is_on, is_mem_on = false; 543 + struct arm_smccc_res res; 544 + int ret; 550 545 551 546 if (pd->info->pwr_mask == 0) 552 - return; 547 + return 0; 553 548 554 549 if (on && pd->info->mem_status_mask) 555 550 is_mem_on = rockchip_pmu_domain_is_mem_on(pd); ··· 566 557 567 558 wmb(); 568 559 569 - if (is_mem_on && rockchip_pmu_domain_mem_reset(pd)) 570 - return; 571 - 572 - if (readx_poll_timeout_atomic(rockchip_pmu_domain_is_on, pd, is_on, 573 - is_on == on, 0, 10000)) { 574 - dev_err(pmu->dev, 575 - "failed to set domain '%s', val=%d\n", 576 - genpd->name, is_on); 577 - return; 560 + if (is_mem_on) { 561 + ret = rockchip_pmu_domain_mem_reset(pd); 562 + if (ret) 563 + return ret; 578 564 } 565 + 566 + 567 + ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_on, pd, is_on, 568 + is_on == on, 0, 10000); 569 + if (ret) { 570 + dev_err(pmu->dev, "failed to set domain '%s' %s, val=%d\n", 571 + genpd->name, on ? "on" : "off", is_on); 572 + return ret; 573 + } 574 + 575 + /* Inform firmware to keep this pd on or off */ 576 + if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_NONE) 577 + arm_smccc_smc(ROCKCHIP_SIP_SUSPEND_MODE, ROCKCHIP_SLEEP_PD_CONFIG, 578 + pmu->info->pwr_offset + pd_pwr_offset, 579 + pd->info->pwr_mask, on, 0, 0, 0, &res); 580 + 581 + return 0; 579 582 } 580 583 581 584 static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on) ··· 595 574 struct rockchip_pmu *pmu = pd->pmu; 596 575 int ret; 597 576 598 - mutex_lock(&pmu->mutex); 577 + guard(mutex)(&pmu->mutex); 599 578 600 - if (rockchip_pmu_domain_is_on(pd) != power_on) { 601 - ret = clk_bulk_enable(pd->num_clks, pd->clks); 602 - if (ret < 0) { 603 - dev_err(pmu->dev, "failed to enable clocks\n"); 604 - mutex_unlock(&pmu->mutex); 605 - return ret; 606 - } 579 + if (rockchip_pmu_domain_is_on(pd) == power_on) 580 + return 0; 607 581 608 - rockchip_pmu_ungate_clk(pd, true); 609 - 610 - if (!power_on) { 611 - rockchip_pmu_save_qos(pd); 612 - 613 - /* if powering down, idle request to NIU first */ 614 - rockchip_pmu_set_idle_request(pd, true); 615 - } 616 - 617 - rockchip_do_pmu_set_power_domain(pd, power_on); 618 - 619 - if (power_on) { 620 - /* if powering up, leave idle mode */ 621 - rockchip_pmu_set_idle_request(pd, false); 622 - 623 - rockchip_pmu_restore_qos(pd); 624 - } 625 - 626 - rockchip_pmu_ungate_clk(pd, false); 627 - clk_bulk_disable(pd->num_clks, pd->clks); 582 + ret = clk_bulk_enable(pd->num_clks, pd->clks); 583 + if (ret < 0) { 584 + dev_err(pmu->dev, "failed to enable clocks\n"); 585 + return ret; 628 586 } 629 587 630 - mutex_unlock(&pmu->mutex); 631 - return 0; 588 + rockchip_pmu_ungate_clk(pd, true); 589 + 590 + if (!power_on) { 591 + rockchip_pmu_save_qos(pd); 592 + 593 + /* if powering down, idle request to NIU first */ 594 + ret = rockchip_pmu_set_idle_request(pd, true); 595 + if (ret < 0) 596 + goto out; 597 + } 598 + 599 + ret = rockchip_do_pmu_set_power_domain(pd, power_on); 600 + if (ret < 0) 601 + goto out; 602 + 603 + if (power_on) { 604 + /* if powering up, leave idle mode */ 605 + ret = rockchip_pmu_set_idle_request(pd, false); 606 + if (ret < 0) 607 + goto out; 608 + 609 + rockchip_pmu_restore_qos(pd); 610 + } 611 + 612 + out: 613 + rockchip_pmu_ungate_clk(pd, false); 614 + clk_bulk_disable(pd->num_clks, pd->clks); 615 + 616 + return ret; 617 + } 618 + 619 + static int rockchip_pd_regulator_disable(struct rockchip_pm_domain *pd) 620 + { 621 + return IS_ERR_OR_NULL(pd->supply) ? 0 : regulator_disable(pd->supply); 622 + } 623 + 624 + static int rockchip_pd_regulator_enable(struct rockchip_pm_domain *pd) 625 + { 626 + struct rockchip_pmu *pmu = pd->pmu; 627 + 628 + if (!pd->info->need_regulator) 629 + return 0; 630 + 631 + if (IS_ERR_OR_NULL(pd->supply)) { 632 + pd->supply = devm_of_regulator_get(pmu->dev, pd->node, "domain"); 633 + 634 + if (IS_ERR(pd->supply)) 635 + return PTR_ERR(pd->supply); 636 + } 637 + 638 + return regulator_enable(pd->supply); 632 639 } 633 640 634 641 static int rockchip_pd_power_on(struct generic_pm_domain *domain) 635 642 { 636 643 struct rockchip_pm_domain *pd = to_rockchip_pd(domain); 644 + int ret; 637 645 638 - return rockchip_pd_power(pd, true); 646 + ret = rockchip_pd_regulator_enable(pd); 647 + if (ret) { 648 + dev_err(pd->pmu->dev, "Failed to enable supply: %d\n", ret); 649 + return ret; 650 + } 651 + 652 + ret = rockchip_pd_power(pd, true); 653 + if (ret) 654 + rockchip_pd_regulator_disable(pd); 655 + 656 + return ret; 639 657 } 640 658 641 659 static int rockchip_pd_power_off(struct generic_pm_domain *domain) 642 660 { 643 661 struct rockchip_pm_domain *pd = to_rockchip_pd(domain); 662 + int ret; 644 663 645 - return rockchip_pd_power(pd, false); 664 + ret = rockchip_pd_power(pd, false); 665 + if (ret) 666 + return ret; 667 + 668 + rockchip_pd_regulator_disable(pd); 669 + return ret; 646 670 } 647 671 648 672 static int rockchip_pd_attach_dev(struct generic_pm_domain *genpd, ··· 768 702 769 703 pd->info = pd_info; 770 704 pd->pmu = pmu; 705 + pd->node = node; 771 706 772 707 pd->num_clks = of_clk_get_parent_count(node); 773 708 if (pd->num_clks > 0) { ··· 1232 1165 }; 1233 1166 1234 1167 static const struct rockchip_domain_info rk3588_pm_domains[] = { 1235 - [RK3588_PD_GPU] = DOMAIN_RK3588("gpu", 0x0, BIT(0), 0, 0x0, 0, BIT(1), 0x0, BIT(0), BIT(0), false), 1236 - [RK3588_PD_NPU] = DOMAIN_RK3588("npu", 0x0, BIT(1), BIT(1), 0x0, 0, 0, 0x0, 0, 0, false), 1237 - [RK3588_PD_VCODEC] = DOMAIN_RK3588("vcodec", 0x0, BIT(2), BIT(2), 0x0, 0, 0, 0x0, 0, 0, false), 1238 - [RK3588_PD_NPUTOP] = DOMAIN_RK3588("nputop", 0x0, BIT(3), 0, 0x0, BIT(11), BIT(2), 0x0, BIT(1), BIT(1), false), 1239 - [RK3588_PD_NPU1] = DOMAIN_RK3588("npu1", 0x0, BIT(4), 0, 0x0, BIT(12), BIT(3), 0x0, BIT(2), BIT(2), false), 1240 - [RK3588_PD_NPU2] = DOMAIN_RK3588("npu2", 0x0, BIT(5), 0, 0x0, BIT(13), BIT(4), 0x0, BIT(3), BIT(3), false), 1241 - [RK3588_PD_VENC0] = DOMAIN_RK3588("venc0", 0x0, BIT(6), 0, 0x0, BIT(14), BIT(5), 0x0, BIT(4), BIT(4), false), 1242 - [RK3588_PD_VENC1] = DOMAIN_RK3588("venc1", 0x0, BIT(7), 0, 0x0, BIT(15), BIT(6), 0x0, BIT(5), BIT(5), false), 1243 - [RK3588_PD_RKVDEC0] = DOMAIN_RK3588("rkvdec0", 0x0, BIT(8), 0, 0x0, BIT(16), BIT(7), 0x0, BIT(6), BIT(6), false), 1244 - [RK3588_PD_RKVDEC1] = DOMAIN_RK3588("rkvdec1", 0x0, BIT(9), 0, 0x0, BIT(17), BIT(8), 0x0, BIT(7), BIT(7), false), 1245 - [RK3588_PD_VDPU] = DOMAIN_RK3588("vdpu", 0x0, BIT(10), 0, 0x0, BIT(18), BIT(9), 0x0, BIT(8), BIT(8), false), 1246 - [RK3588_PD_RGA30] = DOMAIN_RK3588("rga30", 0x0, BIT(11), 0, 0x0, BIT(19), BIT(10), 0x0, 0, 0, false), 1247 - [RK3588_PD_AV1] = DOMAIN_RK3588("av1", 0x0, BIT(12), 0, 0x0, BIT(20), BIT(11), 0x0, BIT(9), BIT(9), false), 1248 - [RK3588_PD_VI] = DOMAIN_RK3588("vi", 0x0, BIT(13), 0, 0x0, BIT(21), BIT(12), 0x0, BIT(10), BIT(10), false), 1249 - [RK3588_PD_FEC] = DOMAIN_RK3588("fec", 0x0, BIT(14), 0, 0x0, BIT(22), BIT(13), 0x0, 0, 0, false), 1250 - [RK3588_PD_ISP1] = DOMAIN_RK3588("isp1", 0x0, BIT(15), 0, 0x0, BIT(23), BIT(14), 0x0, BIT(11), BIT(11), false), 1251 - [RK3588_PD_RGA31] = DOMAIN_RK3588("rga31", 0x4, BIT(0), 0, 0x0, BIT(24), BIT(15), 0x0, BIT(12), BIT(12), false), 1252 - [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), 1253 - [RK3588_PD_VO0] = DOMAIN_RK3588("vo0", 0x4, BIT(2), 0, 0x0, BIT(26), BIT(17), 0x0, BIT(15), BIT(15), false), 1254 - [RK3588_PD_VO1] = DOMAIN_RK3588("vo1", 0x4, BIT(3), 0, 0x0, BIT(27), BIT(18), 0x4, BIT(0), BIT(16), false), 1255 - [RK3588_PD_AUDIO] = DOMAIN_RK3588("audio", 0x4, BIT(4), 0, 0x0, BIT(28), BIT(19), 0x4, BIT(1), BIT(17), false), 1256 - [RK3588_PD_PHP] = DOMAIN_RK3588("php", 0x4, BIT(5), 0, 0x0, BIT(29), BIT(20), 0x4, BIT(5), BIT(21), false), 1257 - [RK3588_PD_GMAC] = DOMAIN_RK3588("gmac", 0x4, BIT(6), 0, 0x0, BIT(30), BIT(21), 0x0, 0, 0, false), 1258 - [RK3588_PD_PCIE] = DOMAIN_RK3588("pcie", 0x4, BIT(7), 0, 0x0, BIT(31), BIT(22), 0x0, 0, 0, true), 1259 - [RK3588_PD_NVM] = DOMAIN_RK3588("nvm", 0x4, BIT(8), BIT(24), 0x4, 0, 0, 0x4, BIT(2), BIT(18), false), 1260 - [RK3588_PD_NVM0] = DOMAIN_RK3588("nvm0", 0x4, BIT(9), 0, 0x4, BIT(1), BIT(23), 0x0, 0, 0, false), 1261 - [RK3588_PD_SDIO] = DOMAIN_RK3588("sdio", 0x4, BIT(10), 0, 0x4, BIT(2), BIT(24), 0x4, BIT(3), BIT(19), false), 1262 - [RK3588_PD_USB] = DOMAIN_RK3588("usb", 0x4, BIT(11), 0, 0x4, BIT(3), BIT(25), 0x4, BIT(4), BIT(20), true), 1263 - [RK3588_PD_SDMMC] = DOMAIN_RK3588("sdmmc", 0x4, BIT(13), 0, 0x4, BIT(5), BIT(26), 0x0, 0, 0, false), 1168 + [RK3588_PD_GPU] = DOMAIN_RK3588("gpu", 0x0, BIT(0), 0, 0x0, 0, BIT(1), 0x0, BIT(0), BIT(0), false, true), 1169 + [RK3588_PD_NPU] = DOMAIN_RK3588("npu", 0x0, BIT(1), BIT(1), 0x0, 0, 0, 0x0, 0, 0, false, true), 1170 + [RK3588_PD_VCODEC] = DOMAIN_RK3588("vcodec", 0x0, BIT(2), BIT(2), 0x0, 0, 0, 0x0, 0, 0, false, false), 1171 + [RK3588_PD_NPUTOP] = DOMAIN_RK3588("nputop", 0x0, BIT(3), 0, 0x0, BIT(11), BIT(2), 0x0, BIT(1), BIT(1), false, false), 1172 + [RK3588_PD_NPU1] = DOMAIN_RK3588("npu1", 0x0, BIT(4), 0, 0x0, BIT(12), BIT(3), 0x0, BIT(2), BIT(2), false, false), 1173 + [RK3588_PD_NPU2] = DOMAIN_RK3588("npu2", 0x0, BIT(5), 0, 0x0, BIT(13), BIT(4), 0x0, BIT(3), BIT(3), false, false), 1174 + [RK3588_PD_VENC0] = DOMAIN_RK3588("venc0", 0x0, BIT(6), 0, 0x0, BIT(14), BIT(5), 0x0, BIT(4), BIT(4), false, false), 1175 + [RK3588_PD_VENC1] = DOMAIN_RK3588("venc1", 0x0, BIT(7), 0, 0x0, BIT(15), BIT(6), 0x0, BIT(5), BIT(5), false, false), 1176 + [RK3588_PD_RKVDEC0] = DOMAIN_RK3588("rkvdec0", 0x0, BIT(8), 0, 0x0, BIT(16), BIT(7), 0x0, BIT(6), BIT(6), false, false), 1177 + [RK3588_PD_RKVDEC1] = DOMAIN_RK3588("rkvdec1", 0x0, BIT(9), 0, 0x0, BIT(17), BIT(8), 0x0, BIT(7), BIT(7), false, false), 1178 + [RK3588_PD_VDPU] = DOMAIN_RK3588("vdpu", 0x0, BIT(10), 0, 0x0, BIT(18), BIT(9), 0x0, BIT(8), BIT(8), false, false), 1179 + [RK3588_PD_RGA30] = DOMAIN_RK3588("rga30", 0x0, BIT(11), 0, 0x0, BIT(19), BIT(10), 0x0, 0, 0, false, false), 1180 + [RK3588_PD_AV1] = DOMAIN_RK3588("av1", 0x0, BIT(12), 0, 0x0, BIT(20), BIT(11), 0x0, BIT(9), BIT(9), false, false), 1181 + [RK3588_PD_VI] = DOMAIN_RK3588("vi", 0x0, BIT(13), 0, 0x0, BIT(21), BIT(12), 0x0, BIT(10), BIT(10), false, false), 1182 + [RK3588_PD_FEC] = DOMAIN_RK3588("fec", 0x0, BIT(14), 0, 0x0, BIT(22), BIT(13), 0x0, 0, 0, false, false), 1183 + [RK3588_PD_ISP1] = DOMAIN_RK3588("isp1", 0x0, BIT(15), 0, 0x0, BIT(23), BIT(14), 0x0, BIT(11), BIT(11), false, false), 1184 + [RK3588_PD_RGA31] = DOMAIN_RK3588("rga31", 0x4, BIT(0), 0, 0x0, BIT(24), BIT(15), 0x0, BIT(12), BIT(12), false, false), 1185 + [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), 1186 + [RK3588_PD_VO0] = DOMAIN_RK3588("vo0", 0x4, BIT(2), 0, 0x0, BIT(26), BIT(17), 0x0, BIT(15), BIT(15), false, false), 1187 + [RK3588_PD_VO1] = DOMAIN_RK3588("vo1", 0x4, BIT(3), 0, 0x0, BIT(27), BIT(18), 0x4, BIT(0), BIT(16), false, false), 1188 + [RK3588_PD_AUDIO] = DOMAIN_RK3588("audio", 0x4, BIT(4), 0, 0x0, BIT(28), BIT(19), 0x4, BIT(1), BIT(17), false, false), 1189 + [RK3588_PD_PHP] = DOMAIN_RK3588("php", 0x4, BIT(5), 0, 0x0, BIT(29), BIT(20), 0x4, BIT(5), BIT(21), false, false), 1190 + [RK3588_PD_GMAC] = DOMAIN_RK3588("gmac", 0x4, BIT(6), 0, 0x0, BIT(30), BIT(21), 0x0, 0, 0, false, false), 1191 + [RK3588_PD_PCIE] = DOMAIN_RK3588("pcie", 0x4, BIT(7), 0, 0x0, BIT(31), BIT(22), 0x0, 0, 0, true, false), 1192 + [RK3588_PD_NVM] = DOMAIN_RK3588("nvm", 0x4, BIT(8), BIT(24), 0x4, 0, 0, 0x4, BIT(2), BIT(18), false, false), 1193 + [RK3588_PD_NVM0] = DOMAIN_RK3588("nvm0", 0x4, BIT(9), 0, 0x4, BIT(1), BIT(23), 0x0, 0, 0, false, false), 1194 + [RK3588_PD_SDIO] = DOMAIN_RK3588("sdio", 0x4, BIT(10), 0, 0x4, BIT(2), BIT(24), 0x4, BIT(3), BIT(19), false, false), 1195 + [RK3588_PD_USB] = DOMAIN_RK3588("usb", 0x4, BIT(11), 0, 0x4, BIT(3), BIT(25), 0x4, BIT(4), BIT(20), true, false), 1196 + [RK3588_PD_SDMMC] = DOMAIN_RK3588("sdmmc", 0x4, BIT(13), 0, 0x4, BIT(5), BIT(26), 0x0, 0, 0, false, false), 1264 1197 }; 1265 1198 1266 1199 static const struct rockchip_pmu_info px30_pmu = {
+15
drivers/pmdomain/sunxi/sun20i-ppu.c
··· 182 182 .num_domains = ARRAY_SIZE(sun20i_d1_ppu_pd_names), 183 183 }; 184 184 185 + static const char *const sun8i_v853_ppu_pd_names[] = { 186 + "RISCV", 187 + "NPU", 188 + "VE", 189 + }; 190 + 191 + static const struct sun20i_ppu_desc sun8i_v853_ppu_desc = { 192 + .names = sun8i_v853_ppu_pd_names, 193 + .num_domains = ARRAY_SIZE(sun8i_v853_ppu_pd_names), 194 + }; 195 + 185 196 static const struct of_device_id sun20i_ppu_of_match[] = { 186 197 { 187 198 .compatible = "allwinner,sun20i-d1-ppu", 188 199 .data = &sun20i_d1_ppu_desc, 200 + }, 201 + { 202 + .compatible = "allwinner,sun8i-v853-ppu", 203 + .data = &sun8i_v853_ppu_desc, 189 204 }, 190 205 { } 191 206 };
+12
drivers/pmdomain/thead/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + 3 + config TH1520_PM_DOMAINS 4 + tristate "Support TH1520 Power Domains" 5 + depends on TH1520_AON_PROTOCOL 6 + select REGMAP_MMIO 7 + help 8 + This driver enables power domain management for the T-HEAD 9 + TH-1520 SoC. On this SoC there are number of power domains, 10 + which can be managed independently. For example GPU, NPU, 11 + and DPU reside in their own power domains which can be 12 + turned on/off.
+2
drivers/pmdomain/thead/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + obj-$(CONFIG_TH1520_PM_DOMAINS) += th1520-pm-domains.o
+218
drivers/pmdomain/thead/th1520-pm-domains.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2021 Alibaba Group Holding Limited. 4 + * Copyright (c) 2024 Samsung Electronics Co., Ltd. 5 + * Author: Michal Wilczynski <m.wilczynski@samsung.com> 6 + */ 7 + 8 + #include <linux/firmware/thead/thead,th1520-aon.h> 9 + #include <linux/slab.h> 10 + #include <linux/platform_device.h> 11 + #include <linux/pm_domain.h> 12 + 13 + #include <dt-bindings/power/thead,th1520-power.h> 14 + 15 + struct th1520_power_domain { 16 + struct th1520_aon_chan *aon_chan; 17 + struct generic_pm_domain genpd; 18 + u32 rsrc; 19 + }; 20 + 21 + struct th1520_power_info { 22 + const char *name; 23 + u32 rsrc; 24 + bool disabled; 25 + }; 26 + 27 + /* 28 + * The AUDIO power domain is marked as disabled to prevent the driver from 29 + * managing its power state. Direct AON firmware calls to control this power 30 + * island trigger a firmware bug causing system instability. Until this 31 + * firmware issue is resolved, the AUDIO power domain must remain disabled 32 + * to avoid crashes. 33 + */ 34 + static const struct th1520_power_info th1520_pd_ranges[] = { 35 + [TH1520_AUDIO_PD] = {"audio", TH1520_AON_AUDIO_PD, true }, 36 + [TH1520_VDEC_PD] = { "vdec", TH1520_AON_VDEC_PD, false }, 37 + [TH1520_NPU_PD] = { "npu", TH1520_AON_NPU_PD, false }, 38 + [TH1520_VENC_PD] = { "venc", TH1520_AON_VENC_PD, false }, 39 + [TH1520_GPU_PD] = { "gpu", TH1520_AON_GPU_PD, false }, 40 + [TH1520_DSP0_PD] = { "dsp0", TH1520_AON_DSP0_PD, false }, 41 + [TH1520_DSP1_PD] = { "dsp1", TH1520_AON_DSP1_PD, false } 42 + }; 43 + 44 + static inline struct th1520_power_domain * 45 + to_th1520_power_domain(struct generic_pm_domain *genpd) 46 + { 47 + return container_of(genpd, struct th1520_power_domain, genpd); 48 + } 49 + 50 + static int th1520_pd_power_on(struct generic_pm_domain *domain) 51 + { 52 + struct th1520_power_domain *pd = to_th1520_power_domain(domain); 53 + 54 + return th1520_aon_power_update(pd->aon_chan, pd->rsrc, true); 55 + } 56 + 57 + static int th1520_pd_power_off(struct generic_pm_domain *domain) 58 + { 59 + struct th1520_power_domain *pd = to_th1520_power_domain(domain); 60 + 61 + return th1520_aon_power_update(pd->aon_chan, pd->rsrc, false); 62 + } 63 + 64 + static struct generic_pm_domain *th1520_pd_xlate(const struct of_phandle_args *spec, 65 + void *data) 66 + { 67 + struct generic_pm_domain *domain = ERR_PTR(-ENOENT); 68 + struct genpd_onecell_data *pd_data = data; 69 + unsigned int i; 70 + 71 + for (i = 0; i < ARRAY_SIZE(th1520_pd_ranges); i++) { 72 + struct th1520_power_domain *pd; 73 + 74 + if (th1520_pd_ranges[i].disabled) 75 + continue; 76 + 77 + pd = to_th1520_power_domain(pd_data->domains[i]); 78 + if (pd->rsrc == spec->args[0]) { 79 + domain = &pd->genpd; 80 + break; 81 + } 82 + } 83 + 84 + return domain; 85 + } 86 + 87 + static struct th1520_power_domain * 88 + th1520_add_pm_domain(struct device *dev, const struct th1520_power_info *pi) 89 + { 90 + struct th1520_power_domain *pd; 91 + int ret; 92 + 93 + pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); 94 + if (!pd) 95 + return ERR_PTR(-ENOMEM); 96 + 97 + pd->rsrc = pi->rsrc; 98 + pd->genpd.power_on = th1520_pd_power_on; 99 + pd->genpd.power_off = th1520_pd_power_off; 100 + pd->genpd.name = pi->name; 101 + 102 + ret = pm_genpd_init(&pd->genpd, NULL, true); 103 + if (ret) 104 + return ERR_PTR(ret); 105 + 106 + return pd; 107 + } 108 + 109 + static void th1520_pd_init_all_off(struct generic_pm_domain **domains, 110 + struct device *dev) 111 + { 112 + int ret; 113 + int i; 114 + 115 + for (i = 0; i < ARRAY_SIZE(th1520_pd_ranges); i++) { 116 + struct th1520_power_domain *pd; 117 + 118 + if (th1520_pd_ranges[i].disabled) 119 + continue; 120 + 121 + pd = to_th1520_power_domain(domains[i]); 122 + 123 + ret = th1520_aon_power_update(pd->aon_chan, pd->rsrc, false); 124 + if (ret) 125 + dev_err(dev, 126 + "Failed to initially power down power domain %s\n", 127 + pd->genpd.name); 128 + } 129 + } 130 + 131 + static int th1520_pd_probe(struct platform_device *pdev) 132 + { 133 + struct generic_pm_domain **domains; 134 + struct genpd_onecell_data *pd_data; 135 + struct th1520_aon_chan *aon_chan; 136 + struct device *dev = &pdev->dev; 137 + int i, ret; 138 + 139 + aon_chan = th1520_aon_init(dev); 140 + if (IS_ERR(aon_chan)) 141 + return dev_err_probe(dev, PTR_ERR(aon_chan), 142 + "Failed to get AON channel\n"); 143 + 144 + domains = devm_kcalloc(dev, ARRAY_SIZE(th1520_pd_ranges), 145 + sizeof(*domains), GFP_KERNEL); 146 + if (!domains) { 147 + ret = -ENOMEM; 148 + goto err_clean_aon; 149 + } 150 + 151 + pd_data = devm_kzalloc(dev, sizeof(*pd_data), GFP_KERNEL); 152 + if (!pd_data) { 153 + ret = -ENOMEM; 154 + goto err_clean_aon; 155 + } 156 + 157 + for (i = 0; i < ARRAY_SIZE(th1520_pd_ranges); i++) { 158 + struct th1520_power_domain *pd; 159 + 160 + if (th1520_pd_ranges[i].disabled) 161 + continue; 162 + 163 + pd = th1520_add_pm_domain(dev, &th1520_pd_ranges[i]); 164 + if (IS_ERR(pd)) { 165 + ret = PTR_ERR(pd); 166 + goto err_clean_genpd; 167 + } 168 + 169 + pd->aon_chan = aon_chan; 170 + domains[i] = &pd->genpd; 171 + dev_dbg(dev, "added power domain %s\n", pd->genpd.name); 172 + } 173 + 174 + pd_data->domains = domains; 175 + pd_data->num_domains = ARRAY_SIZE(th1520_pd_ranges); 176 + pd_data->xlate = th1520_pd_xlate; 177 + 178 + /* 179 + * Initialize all power domains to off to ensure they start in a 180 + * low-power state. This allows device drivers to manage power 181 + * domains by turning them on or off as needed. 182 + */ 183 + th1520_pd_init_all_off(domains, dev); 184 + 185 + ret = of_genpd_add_provider_onecell(dev->of_node, pd_data); 186 + if (ret) 187 + goto err_clean_genpd; 188 + 189 + return 0; 190 + 191 + err_clean_genpd: 192 + for (i--; i >= 0; i--) 193 + pm_genpd_remove(domains[i]); 194 + err_clean_aon: 195 + th1520_aon_deinit(aon_chan); 196 + 197 + return ret; 198 + } 199 + 200 + static const struct of_device_id th1520_pd_match[] = { 201 + { .compatible = "thead,th1520-aon" }, 202 + { /* Sentinel */ } 203 + }; 204 + MODULE_DEVICE_TABLE(of, th1520_pd_match); 205 + 206 + static struct platform_driver th1520_pd_driver = { 207 + .driver = { 208 + .name = "th1520-pd", 209 + .of_match_table = th1520_pd_match, 210 + .suppress_bind_attrs = true, 211 + }, 212 + .probe = th1520_pd_probe, 213 + }; 214 + module_platform_driver(th1520_pd_driver); 215 + 216 + MODULE_AUTHOR("Michal Wilczynski <m.wilczynski@samsung.com>"); 217 + MODULE_DESCRIPTION("T-HEAD TH1520 SoC power domain controller"); 218 + MODULE_LICENSE("GPL");
+1 -1
drivers/pmdomain/ti/omap_prm.c
··· 613 613 if (!of_device_is_compatible(np, "simple-pm-bus")) 614 614 return 0; 615 615 616 - if (!of_property_read_bool(np, "clocks")) 616 + if (!of_property_present(np, "clocks")) 617 617 return 0; 618 618 619 619 error = pm_clk_create(dev);
+10
include/dt-bindings/power/allwinner,sun8i-v853-ppu.h
··· 1 + /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 + 3 + #ifndef _DT_BINDINGS_POWER_SUN8I_V853_PPU_H_ 4 + #define _DT_BINDINGS_POWER_SUN8I_V853_PPU_H_ 5 + 6 + #define PD_RISCV 0 7 + #define PD_NPU 1 8 + #define PD_VE 2 9 + 10 + #endif
+1 -1
include/dt-bindings/power/qcom-rpmpd.h
··· 65 65 #define SM6350_MSS 4 66 66 #define SM6350_MX 5 67 67 68 - /* SM6350 Power Domain Indexes */ 68 + /* SM6375 Power Domain Indexes */ 69 69 #define SM6375_VDDCX 0 70 70 #define SM6375_VDDCX_AO 1 71 71 #define SM6375_VDDCX_VFL 2
+19
include/dt-bindings/power/thead,th1520-power.h
··· 1 + /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 + /* 3 + * Copyright (C) 2022 Alibaba Group Holding Limited. 4 + * Copyright (c) 2024 Samsung Electronics Co., Ltd. 5 + * Author: Michal Wilczynski <m.wilczynski@samsung.com> 6 + */ 7 + 8 + #ifndef __DT_BINDINGS_POWER_TH1520_H 9 + #define __DT_BINDINGS_POWER_TH1520_H 10 + 11 + #define TH1520_AUDIO_PD 0 12 + #define TH1520_VDEC_PD 1 13 + #define TH1520_NPU_PD 2 14 + #define TH1520_VENC_PD 3 15 + #define TH1520_GPU_PD 4 16 + #define TH1520_DSP0_PD 5 17 + #define TH1520_DSP1_PD 6 18 + 19 + #endif
+200
include/linux/firmware/thead/thead,th1520-aon.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2021 Alibaba Group Holding Limited. 4 + */ 5 + 6 + #ifndef _THEAD_AON_H 7 + #define _THEAD_AON_H 8 + 9 + #include <linux/device.h> 10 + #include <linux/types.h> 11 + 12 + #define AON_RPC_MSG_MAGIC (0xef) 13 + #define TH1520_AON_RPC_VERSION 2 14 + #define TH1520_AON_RPC_MSG_NUM 7 15 + 16 + struct th1520_aon_chan; 17 + 18 + enum th1520_aon_rpc_svc { 19 + TH1520_AON_RPC_SVC_UNKNOWN = 0, 20 + TH1520_AON_RPC_SVC_PM = 1, 21 + TH1520_AON_RPC_SVC_MISC = 2, 22 + TH1520_AON_RPC_SVC_AVFS = 3, 23 + TH1520_AON_RPC_SVC_SYS = 4, 24 + TH1520_AON_RPC_SVC_WDG = 5, 25 + TH1520_AON_RPC_SVC_LPM = 6, 26 + TH1520_AON_RPC_SVC_MAX = 0x3F, 27 + }; 28 + 29 + enum th1520_aon_misc_func { 30 + TH1520_AON_MISC_FUNC_UNKNOWN = 0, 31 + TH1520_AON_MISC_FUNC_SET_CONTROL = 1, 32 + TH1520_AON_MISC_FUNC_GET_CONTROL = 2, 33 + TH1520_AON_MISC_FUNC_REGDUMP_CFG = 3, 34 + }; 35 + 36 + enum th1520_aon_wdg_func { 37 + TH1520_AON_WDG_FUNC_UNKNOWN = 0, 38 + TH1520_AON_WDG_FUNC_START = 1, 39 + TH1520_AON_WDG_FUNC_STOP = 2, 40 + TH1520_AON_WDG_FUNC_PING = 3, 41 + TH1520_AON_WDG_FUNC_TIMEOUTSET = 4, 42 + TH1520_AON_WDG_FUNC_RESTART = 5, 43 + TH1520_AON_WDG_FUNC_GET_STATE = 6, 44 + TH1520_AON_WDG_FUNC_POWER_OFF = 7, 45 + TH1520_AON_WDG_FUNC_AON_WDT_ON = 8, 46 + TH1520_AON_WDG_FUNC_AON_WDT_OFF = 9, 47 + }; 48 + 49 + enum th1520_aon_sys_func { 50 + TH1520_AON_SYS_FUNC_UNKNOWN = 0, 51 + TH1520_AON_SYS_FUNC_AON_RESERVE_MEM = 1, 52 + }; 53 + 54 + enum th1520_aon_lpm_func { 55 + TH1520_AON_LPM_FUNC_UNKNOWN = 0, 56 + TH1520_AON_LPM_FUNC_REQUIRE_STR = 1, 57 + TH1520_AON_LPM_FUNC_RESUME_STR = 2, 58 + TH1520_AON_LPM_FUNC_REQUIRE_STD = 3, 59 + TH1520_AON_LPM_FUNC_CPUHP = 4, 60 + TH1520_AON_LPM_FUNC_REGDUMP_CFG = 5, 61 + }; 62 + 63 + enum th1520_aon_pm_func { 64 + TH1520_AON_PM_FUNC_UNKNOWN = 0, 65 + TH1520_AON_PM_FUNC_SET_RESOURCE_REGULATOR = 1, 66 + TH1520_AON_PM_FUNC_GET_RESOURCE_REGULATOR = 2, 67 + TH1520_AON_PM_FUNC_SET_RESOURCE_POWER_MODE = 3, 68 + TH1520_AON_PM_FUNC_PWR_SET = 4, 69 + TH1520_AON_PM_FUNC_PWR_GET = 5, 70 + TH1520_AON_PM_FUNC_CHECK_FAULT = 6, 71 + TH1520_AON_PM_FUNC_GET_TEMPERATURE = 7, 72 + }; 73 + 74 + struct th1520_aon_rpc_msg_hdr { 75 + u8 ver; /* version of msg hdr */ 76 + u8 size; /* msg size ,uinit in bytes,the size includes rpc msg header self */ 77 + u8 svc; /* rpc main service id */ 78 + u8 func; /* rpc sub func id of specific service, sent by caller */ 79 + } __packed __aligned(1); 80 + 81 + struct th1520_aon_rpc_ack_common { 82 + struct th1520_aon_rpc_msg_hdr hdr; 83 + u8 err_code; 84 + } __packed __aligned(1); 85 + 86 + #define RPC_SVC_MSG_TYPE_DATA 0 87 + #define RPC_SVC_MSG_TYPE_ACK 1 88 + #define RPC_SVC_MSG_NEED_ACK 0 89 + #define RPC_SVC_MSG_NO_NEED_ACK 1 90 + 91 + #define RPC_GET_VER(MESG) ((MESG)->ver) 92 + #define RPC_SET_VER(MESG, VER) ((MESG)->ver = (VER)) 93 + #define RPC_GET_SVC_ID(MESG) ((MESG)->svc & 0x3F) 94 + #define RPC_SET_SVC_ID(MESG, ID) ((MESG)->svc |= 0x3F & (ID)) 95 + #define RPC_GET_SVC_FLAG_MSG_TYPE(MESG) (((MESG)->svc & 0x80) >> 7) 96 + #define RPC_SET_SVC_FLAG_MSG_TYPE(MESG, TYPE) ((MESG)->svc |= (TYPE) << 7) 97 + #define RPC_GET_SVC_FLAG_ACK_TYPE(MESG) (((MESG)->svc & 0x40) >> 6) 98 + #define RPC_SET_SVC_FLAG_ACK_TYPE(MESG, ACK) ((MESG)->svc |= (ACK) << 6) 99 + 100 + #define RPC_SET_BE64(MESG, OFFSET, SET_DATA) \ 101 + do { \ 102 + u8 *data = (u8 *)(MESG); \ 103 + u64 _offset = (OFFSET); \ 104 + u64 _set_data = (SET_DATA); \ 105 + data[_offset + 7] = _set_data & 0xFF; \ 106 + data[_offset + 6] = (_set_data & 0xFF00) >> 8; \ 107 + data[_offset + 5] = (_set_data & 0xFF0000) >> 16; \ 108 + data[_offset + 4] = (_set_data & 0xFF000000) >> 24; \ 109 + data[_offset + 3] = (_set_data & 0xFF00000000) >> 32; \ 110 + data[_offset + 2] = (_set_data & 0xFF0000000000) >> 40; \ 111 + data[_offset + 1] = (_set_data & 0xFF000000000000) >> 48; \ 112 + data[_offset + 0] = (_set_data & 0xFF00000000000000) >> 56; \ 113 + } while (0) 114 + 115 + #define RPC_SET_BE32(MESG, OFFSET, SET_DATA) \ 116 + do { \ 117 + u8 *data = (u8 *)(MESG); \ 118 + u64 _offset = (OFFSET); \ 119 + u64 _set_data = (SET_DATA); \ 120 + data[_offset + 3] = (_set_data) & 0xFF; \ 121 + data[_offset + 2] = (_set_data & 0xFF00) >> 8; \ 122 + data[_offset + 1] = (_set_data & 0xFF0000) >> 16; \ 123 + data[_offset + 0] = (_set_data & 0xFF000000) >> 24; \ 124 + } while (0) 125 + 126 + #define RPC_SET_BE16(MESG, OFFSET, SET_DATA) \ 127 + do { \ 128 + u8 *data = (u8 *)(MESG); \ 129 + u64 _offset = (OFFSET); \ 130 + u64 _set_data = (SET_DATA); \ 131 + data[_offset + 1] = (_set_data) & 0xFF; \ 132 + data[_offset + 0] = (_set_data & 0xFF00) >> 8; \ 133 + } while (0) 134 + 135 + #define RPC_SET_U8(MESG, OFFSET, SET_DATA) \ 136 + do { \ 137 + u8 *data = (u8 *)(MESG); \ 138 + data[OFFSET] = (SET_DATA) & 0xFF; \ 139 + } while (0) 140 + 141 + #define RPC_GET_BE64(MESG, OFFSET, PTR) \ 142 + do { \ 143 + u8 *data = (u8 *)(MESG); \ 144 + u64 _offset = (OFFSET); \ 145 + *(u32 *)(PTR) = \ 146 + (data[_offset + 7] | data[_offset + 6] << 8 | \ 147 + data[_offset + 5] << 16 | data[_offset + 4] << 24 | \ 148 + data[_offset + 3] << 32 | data[_offset + 2] << 40 | \ 149 + data[_offset + 1] << 48 | data[_offset + 0] << 56); \ 150 + } while (0) 151 + 152 + #define RPC_GET_BE32(MESG, OFFSET, PTR) \ 153 + do { \ 154 + u8 *data = (u8 *)(MESG); \ 155 + u64 _offset = (OFFSET); \ 156 + *(u32 *)(PTR) = \ 157 + (data[_offset + 3] | data[_offset + 2] << 8 | \ 158 + data[_offset + 1] << 16 | data[_offset + 0] << 24); \ 159 + } while (0) 160 + 161 + #define RPC_GET_BE16(MESG, OFFSET, PTR) \ 162 + do { \ 163 + u8 *data = (u8 *)(MESG); \ 164 + u64 _offset = (OFFSET); \ 165 + *(u16 *)(PTR) = (data[_offset + 1] | data[_offset + 0] << 8); \ 166 + } while (0) 167 + 168 + #define RPC_GET_U8(MESG, OFFSET, PTR) \ 169 + do { \ 170 + u8 *data = (u8 *)(MESG); \ 171 + *(u8 *)(PTR) = (data[OFFSET]); \ 172 + } while (0) 173 + 174 + /* 175 + * Defines for SC PM Power Mode 176 + */ 177 + #define TH1520_AON_PM_PW_MODE_OFF 0 /* Power off */ 178 + #define TH1520_AON_PM_PW_MODE_STBY 1 /* Power in standby */ 179 + #define TH1520_AON_PM_PW_MODE_LP 2 /* Power in low-power */ 180 + #define TH1520_AON_PM_PW_MODE_ON 3 /* Power on */ 181 + 182 + /* 183 + * Defines for AON power islands 184 + */ 185 + #define TH1520_AON_AUDIO_PD 0 186 + #define TH1520_AON_VDEC_PD 1 187 + #define TH1520_AON_NPU_PD 2 188 + #define TH1520_AON_VENC_PD 3 189 + #define TH1520_AON_GPU_PD 4 190 + #define TH1520_AON_DSP0_PD 5 191 + #define TH1520_AON_DSP1_PD 6 192 + 193 + struct th1520_aon_chan *th1520_aon_init(struct device *dev); 194 + void th1520_aon_deinit(struct th1520_aon_chan *aon_chan); 195 + 196 + int th1520_aon_call_rpc(struct th1520_aon_chan *aon_chan, void *msg); 197 + int th1520_aon_power_update(struct th1520_aon_chan *aon_chan, u16 rsrc, 198 + bool power_on); 199 + 200 + #endif /* _THEAD_AON_H */
+7
include/linux/pm_domain.h
··· 261 261 unsigned int rpm_pstate; 262 262 unsigned int opp_token; 263 263 bool hw_mode; 264 + bool rpm_always_on; 264 265 void *data; 265 266 }; 266 267 ··· 294 293 void dev_pm_genpd_synced_poweroff(struct device *dev); 295 294 int dev_pm_genpd_set_hwmode(struct device *dev, bool enable); 296 295 bool dev_pm_genpd_get_hwmode(struct device *dev); 296 + int dev_pm_genpd_rpm_always_on(struct device *dev, bool on); 297 297 298 298 extern struct dev_power_governor simple_qos_governor; 299 299 extern struct dev_power_governor pm_domain_always_on_gov; ··· 376 374 static inline bool dev_pm_genpd_get_hwmode(struct device *dev) 377 375 { 378 376 return false; 377 + } 378 + 379 + static inline int dev_pm_genpd_rpm_always_on(struct device *dev, bool on) 380 + { 381 + return -EOPNOTSUPP; 379 382 } 380 383 381 384 #define simple_qos_governor (*(struct dev_power_governor *)(NULL))
+3
include/soc/rockchip/rockchip_sip.h
··· 6 6 #ifndef __SOC_ROCKCHIP_SIP_H 7 7 #define __SOC_ROCKCHIP_SIP_H 8 8 9 + #define ROCKCHIP_SIP_SUSPEND_MODE 0x82000003 10 + #define ROCKCHIP_SLEEP_PD_CONFIG 0xff 11 + 9 12 #define ROCKCHIP_SIP_DRAM_FREQ 0x82000008 10 13 #define ROCKCHIP_SIP_CONFIG_DRAM_INIT 0x00 11 14 #define ROCKCHIP_SIP_CONFIG_DRAM_SET_RATE 0x01
+37
include/trace/events/power.h
··· 62 62 (unsigned long)__entry->state, (__entry->below)?"below":"above") 63 63 ); 64 64 65 + DECLARE_EVENT_CLASS(psci_domain_idle, 66 + 67 + TP_PROTO(unsigned int cpu_id, unsigned int state, bool s2idle), 68 + 69 + TP_ARGS(cpu_id, state, s2idle), 70 + 71 + TP_STRUCT__entry( 72 + __field(u32, cpu_id) 73 + __field(u32, state) 74 + __field(bool, s2idle) 75 + ), 76 + 77 + TP_fast_assign( 78 + __entry->cpu_id = cpu_id; 79 + __entry->state = state; 80 + __entry->s2idle = s2idle; 81 + ), 82 + 83 + TP_printk("cpu_id=%lu state=0x%lx is_s2idle=%s", 84 + (unsigned long)__entry->cpu_id, (unsigned long)__entry->state, 85 + (__entry->s2idle)?"yes":"no") 86 + ); 87 + 88 + DEFINE_EVENT(psci_domain_idle, psci_domain_idle_enter, 89 + 90 + TP_PROTO(unsigned int cpu_id, unsigned int state, bool s2idle), 91 + 92 + TP_ARGS(cpu_id, state, s2idle) 93 + ); 94 + 95 + DEFINE_EVENT(psci_domain_idle, psci_domain_idle_exit, 96 + 97 + TP_PROTO(unsigned int cpu_id, unsigned int state, bool s2idle), 98 + 99 + TP_ARGS(cpu_id, state, s2idle) 100 + ); 101 + 65 102 TRACE_EVENT(powernv_throttle, 66 103 67 104 TP_PROTO(int chip_id, const char *reason, int pmax),