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

Merge tag 'scpi-updates-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into next/drivers

SCPI updates and fixes for v4.8

1. Adds support for device power state management using generic power
domains and runtime PM

2. Other minor/miscellaneous fixes to the driver

* tag 'scpi-updates-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux:
firmware: scpi: add device power domain support using genpd
Documentation: add DT bindings for ARM SCPI power domains
firmware: arm_scpi: add support for device power state management
firmware: arm_scpi: make it depend on MAILBOX instead of ARM_MHU
firmware: arm_scpi: mark scpi_get_sensor_value as static
firmware: arm_scpi: remove dvfs_get packed structure

Signed-off-by: Olof Johansson <olof@lixom.net>

+245 -9
+34
Documentation/devicetree/bindings/arm/arm,scpi.txt
··· 87 87 implementation for the IDs to use. For Juno 88 88 R0 and Juno R1 refer to [3]. 89 89 90 + Power domain bindings for the power domains based on SCPI Message Protocol 91 + ------------------------------------------------------------ 92 + 93 + This binding uses the generic power domain binding[4]. 94 + 95 + PM domain providers 96 + =================== 97 + 98 + Required properties: 99 + - #power-domain-cells : Should be 1. Contains the device or the power 100 + domain ID value used by SCPI commands. 101 + - num-domains: Total number of power domains provided by SCPI. This is 102 + needed as the SCPI message protocol lacks a mechanism to 103 + query this information at runtime. 104 + 105 + PM domain consumers 106 + =================== 107 + 108 + Required properties: 109 + - power-domains : A phandle and PM domain specifier as defined by bindings of 110 + the power controller specified by phandle. 111 + 90 112 [0] http://infocenter.arm.com/help/topic/com.arm.doc.dui0922b/index.html 91 113 [1] Documentation/devicetree/bindings/clock/clock-bindings.txt 92 114 [2] Documentation/devicetree/bindings/thermal/thermal.txt 93 115 [3] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0922b/apas03s22.html 116 + [4] Documentation/devicetree/bindings/power/power_domain.txt 94 117 95 118 Example: 96 119 ··· 167 144 compatible = "arm,scpi-sensors"; 168 145 #thermal-sensor-cells = <1>; 169 146 }; 147 + 148 + scpi_devpd: scpi-power-domains { 149 + compatible = "arm,scpi-power-domains"; 150 + num-domains = <2>; 151 + #power-domain-cells = <1>; 152 + }; 170 153 }; 171 154 172 155 cpu@0 { ··· 185 156 ... 186 157 reg = <0 0x7ff60000 0 0x1000>; 187 158 clocks = <&scpi_clk 4>; 159 + power-domains = <&scpi_devpd 1>; 188 160 }; 189 161 190 162 thermal-zones { ··· 216 186 temperature sensor provided by SCP firmware to setup a thermal 217 187 zone. The ID "3" is the sensor identifier for the temperature sensor 218 188 as used by the firmware. 189 + 190 + The num-domains property in scpi-power-domains domain specifies that 191 + SCPI provides 2 power domains. The hdlcd node uses the power domain with 192 + domain ID 1.
+11 -1
drivers/firmware/Kconfig
··· 10 10 11 11 config ARM_SCPI_PROTOCOL 12 12 tristate "ARM System Control and Power Interface (SCPI) Message Protocol" 13 - depends on ARM_MHU 13 + depends on MAILBOX 14 14 help 15 15 System Control and Power Interface (SCPI) Message Protocol is 16 16 defined for the purpose of communication between the Application ··· 26 26 27 27 This protocol library provides interface for all the client drivers 28 28 making use of the features offered by the SCP. 29 + 30 + config ARM_SCPI_POWER_DOMAIN 31 + tristate "SCPI power domain driver" 32 + depends on ARM_SCPI_PROTOCOL || COMPILE_TEST 33 + default y 34 + select PM_GENERIC_DOMAINS if PM 35 + select PM_GENERIC_DOMAINS_OF if PM 36 + help 37 + This enables support for the SCPI power domains which can be 38 + enabled or disabled via the SCP firmware 29 39 30 40 config EDD 31 41 tristate "BIOS Enhanced Disk Drive calls determine boot disk"
+1
drivers/firmware/Makefile
··· 3 3 # 4 4 obj-$(CONFIG_ARM_PSCI_FW) += psci.o 5 5 obj-$(CONFIG_ARM_SCPI_PROTOCOL) += arm_scpi.o 6 + obj-$(CONFIG_ARM_SCPI_POWER_DOMAIN) += scpi_pm_domain.o 6 7 obj-$(CONFIG_DMI) += dmi_scan.o 7 8 obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o 8 9 obj-$(CONFIG_EDD) += edd.o
+34 -8
drivers/firmware/arm_scpi.c
··· 210 210 } opps[MAX_DVFS_OPPS]; 211 211 } __packed; 212 212 213 - struct dvfs_get { 214 - u8 index; 215 - } __packed; 216 - 217 213 struct dvfs_set { 218 214 u8 domain; 219 215 u8 index; ··· 229 233 struct sensor_value { 230 234 __le32 lo_val; 231 235 __le32 hi_val; 236 + } __packed; 237 + 238 + struct dev_pstate_set { 239 + u16 dev_id; 240 + u8 pstate; 232 241 } __packed; 233 242 234 243 static struct scpi_drvinfo *scpi_info; ··· 432 431 static int scpi_dvfs_get_idx(u8 domain) 433 432 { 434 433 int ret; 435 - struct dvfs_get dvfs; 434 + u8 dvfs_idx; 436 435 437 436 ret = scpi_send_message(SCPI_CMD_GET_DVFS, &domain, sizeof(domain), 438 - &dvfs, sizeof(dvfs)); 439 - return ret ? ret : dvfs.index; 437 + &dvfs_idx, sizeof(dvfs_idx)); 438 + return ret ? ret : dvfs_idx; 440 439 } 441 440 442 441 static int scpi_dvfs_set_idx(u8 domain, u8 index) ··· 527 526 return ret; 528 527 } 529 528 530 - int scpi_sensor_get_value(u16 sensor, u64 *val) 529 + static int scpi_sensor_get_value(u16 sensor, u64 *val) 531 530 { 532 531 __le16 id = cpu_to_le16(sensor); 533 532 struct sensor_value buf; ··· 542 541 return ret; 543 542 } 544 543 544 + static int scpi_device_get_power_state(u16 dev_id) 545 + { 546 + int ret; 547 + u8 pstate; 548 + __le16 id = cpu_to_le16(dev_id); 549 + 550 + ret = scpi_send_message(SCPI_CMD_GET_DEVICE_PWR_STATE, &id, 551 + sizeof(id), &pstate, sizeof(pstate)); 552 + return ret ? ret : pstate; 553 + } 554 + 555 + static int scpi_device_set_power_state(u16 dev_id, u8 pstate) 556 + { 557 + int stat; 558 + struct dev_pstate_set dev_set = { 559 + .dev_id = cpu_to_le16(dev_id), 560 + .pstate = pstate, 561 + }; 562 + 563 + return scpi_send_message(SCPI_CMD_SET_DEVICE_PWR_STATE, &dev_set, 564 + sizeof(dev_set), &stat, sizeof(stat)); 565 + } 566 + 545 567 static struct scpi_ops scpi_ops = { 546 568 .get_version = scpi_get_version, 547 569 .clk_get_range = scpi_clk_get_range, ··· 576 552 .sensor_get_capability = scpi_sensor_get_capability, 577 553 .sensor_get_info = scpi_sensor_get_info, 578 554 .sensor_get_value = scpi_sensor_get_value, 555 + .device_get_power_state = scpi_device_get_power_state, 556 + .device_set_power_state = scpi_device_set_power_state, 579 557 }; 580 558 581 559 struct scpi_ops *get_scpi_ops(void)
+163
drivers/firmware/scpi_pm_domain.c
··· 1 + /* 2 + * SCPI Generic power domain support. 3 + * 4 + * Copyright (C) 2016 ARM Ltd. 5 + * 6 + * This program is free software; you can redistribute it and/or modify it 7 + * under the terms and conditions of the GNU General Public License, 8 + * version 2, as published by the Free Software Foundation. 9 + * 10 + * This program is distributed in the hope it will be useful, but WITHOUT 11 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 + * more details. 14 + * 15 + * You should have received a copy of the GNU General Public License along 16 + * with this program. If not, see <http://www.gnu.org/licenses/>. 17 + */ 18 + 19 + #include <linux/err.h> 20 + #include <linux/io.h> 21 + #include <linux/module.h> 22 + #include <linux/of_platform.h> 23 + #include <linux/pm_domain.h> 24 + #include <linux/scpi_protocol.h> 25 + 26 + struct scpi_pm_domain { 27 + struct generic_pm_domain genpd; 28 + struct scpi_ops *ops; 29 + u32 domain; 30 + char name[30]; 31 + }; 32 + 33 + /* 34 + * These device power state values are not well-defined in the specification. 35 + * In case, different implementations use different values, we can make these 36 + * specific to compatibles rather than getting these values from device tree. 37 + */ 38 + enum scpi_power_domain_state { 39 + SCPI_PD_STATE_ON = 0, 40 + SCPI_PD_STATE_OFF = 3, 41 + }; 42 + 43 + #define to_scpi_pd(gpd) container_of(gpd, struct scpi_pm_domain, genpd) 44 + 45 + static int scpi_pd_power(struct scpi_pm_domain *pd, bool power_on) 46 + { 47 + int ret; 48 + enum scpi_power_domain_state state; 49 + 50 + if (power_on) 51 + state = SCPI_PD_STATE_ON; 52 + else 53 + state = SCPI_PD_STATE_OFF; 54 + 55 + ret = pd->ops->device_set_power_state(pd->domain, state); 56 + if (ret) 57 + return ret; 58 + 59 + return !(state == pd->ops->device_get_power_state(pd->domain)); 60 + } 61 + 62 + static int scpi_pd_power_on(struct generic_pm_domain *domain) 63 + { 64 + struct scpi_pm_domain *pd = to_scpi_pd(domain); 65 + 66 + return scpi_pd_power(pd, true); 67 + } 68 + 69 + static int scpi_pd_power_off(struct generic_pm_domain *domain) 70 + { 71 + struct scpi_pm_domain *pd = to_scpi_pd(domain); 72 + 73 + return scpi_pd_power(pd, false); 74 + } 75 + 76 + static int scpi_pm_domain_probe(struct platform_device *pdev) 77 + { 78 + struct device *dev = &pdev->dev; 79 + struct device_node *np = dev->of_node; 80 + struct scpi_pm_domain *scpi_pd; 81 + struct genpd_onecell_data *scpi_pd_data; 82 + struct generic_pm_domain **domains; 83 + struct scpi_ops *scpi_ops; 84 + int ret, num_domains, i; 85 + 86 + scpi_ops = get_scpi_ops(); 87 + if (!scpi_ops) 88 + return -EPROBE_DEFER; 89 + 90 + if (!np) { 91 + dev_err(dev, "device tree node not found\n"); 92 + return -ENODEV; 93 + } 94 + 95 + if (!scpi_ops->device_set_power_state || 96 + !scpi_ops->device_get_power_state) { 97 + dev_err(dev, "power domains not supported in the firmware\n"); 98 + return -ENODEV; 99 + } 100 + 101 + ret = of_property_read_u32(np, "num-domains", &num_domains); 102 + if (ret) { 103 + dev_err(dev, "number of domains not found\n"); 104 + return -EINVAL; 105 + } 106 + 107 + scpi_pd = devm_kcalloc(dev, num_domains, sizeof(*scpi_pd), GFP_KERNEL); 108 + if (!scpi_pd) 109 + return -ENOMEM; 110 + 111 + scpi_pd_data = devm_kzalloc(dev, sizeof(*scpi_pd_data), GFP_KERNEL); 112 + if (!scpi_pd_data) 113 + return -ENOMEM; 114 + 115 + domains = devm_kcalloc(dev, num_domains, sizeof(*domains), GFP_KERNEL); 116 + if (!domains) 117 + return -ENOMEM; 118 + 119 + for (i = 0; i < num_domains; i++, scpi_pd++) { 120 + domains[i] = &scpi_pd->genpd; 121 + 122 + scpi_pd->domain = i; 123 + scpi_pd->ops = scpi_ops; 124 + sprintf(scpi_pd->name, "%s.%d", np->name, i); 125 + scpi_pd->genpd.name = scpi_pd->name; 126 + scpi_pd->genpd.power_off = scpi_pd_power_off; 127 + scpi_pd->genpd.power_on = scpi_pd_power_on; 128 + 129 + /* 130 + * Treat all power domains as off at boot. 131 + * 132 + * The SCP firmware itself may have switched on some domains, 133 + * but for reference counting purpose, keep it this way. 134 + */ 135 + pm_genpd_init(&scpi_pd->genpd, NULL, true); 136 + } 137 + 138 + scpi_pd_data->domains = domains; 139 + scpi_pd_data->num_domains = num_domains; 140 + 141 + of_genpd_add_provider_onecell(np, scpi_pd_data); 142 + 143 + return 0; 144 + } 145 + 146 + static const struct of_device_id scpi_power_domain_ids[] = { 147 + { .compatible = "arm,scpi-power-domains", }, 148 + { /* sentinel */ } 149 + }; 150 + MODULE_DEVICE_TABLE(of, scpi_power_domain_ids); 151 + 152 + static struct platform_driver scpi_power_domain_driver = { 153 + .driver = { 154 + .name = "scpi_power_domain", 155 + .of_match_table = scpi_power_domain_ids, 156 + }, 157 + .probe = scpi_pm_domain_probe, 158 + }; 159 + module_platform_driver(scpi_power_domain_driver); 160 + 161 + MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>"); 162 + MODULE_DESCRIPTION("ARM SCPI power domain driver"); 163 + MODULE_LICENSE("GPL v2");
+2
include/linux/scpi_protocol.h
··· 70 70 int (*sensor_get_capability)(u16 *sensors); 71 71 int (*sensor_get_info)(u16 sensor_id, struct scpi_sensor_info *); 72 72 int (*sensor_get_value)(u16, u64 *); 73 + int (*device_get_power_state)(u16); 74 + int (*device_set_power_state)(u16, u8); 73 75 }; 74 76 75 77 #if IS_REACHABLE(CONFIG_ARM_SCPI_PROTOCOL)