Unverified Commit bee7fbc3 authored by Palmer Dabbelt's avatar Palmer Dabbelt
Browse files

RISC-V CPU Idle Support

This series adds RISC-V CPU Idle support using SBI HSM suspend function.
The RISC-V SBI CPU idle driver added by this series is highly inspired
from the ARM PSCI CPU idle driver.

Special thanks Sandeep Tripathy for providing early feeback on SBI HSM
support in all above projects (RISC-V SBI specification, OpenSBI, and
Linux RISC-V).

* palmer/riscv-idle:
  RISC-V: Enable RISC-V SBI CPU Idle driver for QEMU virt machine
  dt-bindings: Add common bindings for ARM and RISC-V idle states
  cpuidle: Add RISC-V SBI CPU idle driver
  cpuidle: Factor-out power domain related code from PSCI domain driver
  RISC-V: Add SBI HSM suspend related defines
  RISC-V: Add arch functions for non-retentive suspend entry/exit
  RISC-V: Rename relocate() and make it global
  RISC-V: Enable CPU_IDLE drivers
parents fdecfea0 c5179ef1
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -81,4 +81,4 @@ Example:
		};
	};

[1]. Documentation/devicetree/bindings/arm/idle-states.yaml
[1]. Documentation/devicetree/bindings/cpu/idle-states.yaml
+1 −1
Original line number Diff line number Diff line
@@ -101,7 +101,7 @@ properties:
      bindings in [1]) must specify this property.

      [1] Kernel documentation - ARM idle states bindings
        Documentation/devicetree/bindings/arm/idle-states.yaml
        Documentation/devicetree/bindings/cpu/idle-states.yaml

patternProperties:
  "^power-domain-":
+211 −17
Original line number Diff line number Diff line
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/arm/idle-states.yaml#
$id: http://devicetree.org/schemas/cpu/idle-states.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: ARM idle states binding description
title: Idle states binding description

maintainers:
  - Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
  - Anup Patel <anup@brainfault.org>

description: |+
  ==========================================
  1 - Introduction
  ==========================================

  ARM systems contain HW capable of managing power consumption dynamically,
  where cores can be put in different low-power states (ranging from simple wfi
  to power gating) according to OS PM policies. The CPU states representing the
  range of dynamic idle states that a processor can enter at run-time, can be
  specified through device tree bindings representing the parameters required to
  enter/exit specific idle states on a given processor.
  ARM and RISC-V systems contain HW capable of managing power consumption
  dynamically, where cores can be put in different low-power states (ranging
  from simple wfi to power gating) according to OS PM policies. The CPU states
  representing the range of dynamic idle states that a processor can enter at
  run-time, can be specified through device tree bindings representing the
  parameters required to enter/exit specific idle states on a given processor.

  ==========================================
  2 - ARM idle states
  ==========================================

  According to the Server Base System Architecture document (SBSA, [3]), the
  power states an ARM CPU can be put into are identified by the following list:
@@ -43,8 +48,23 @@ description: |+
  The device tree binding definition for ARM idle states is the subject of this
  document.

  ==========================================
  3 - RISC-V idle states
  ==========================================

  On RISC-V systems, the HARTs (or CPUs) [6] can be put in platform specific
  suspend (or idle) states (ranging from simple WFI, power gating, etc). The
  RISC-V SBI v0.3 (or higher) [7] hart state management extension provides a
  standard mechanism for OS to request HART state transitions.

  The platform specific suspend (or idle) states of a hart can be either
  retentive or non-rententive in nature. A retentive suspend state will
  preserve HART registers and CSR values for all privilege modes whereas
  a non-retentive suspend state will not preserve HART registers and CSR
  values.

  ===========================================
  2 - idle-states definitions
  4 - idle-states definitions
  ===========================================

  Idle states are characterized for a specific system through a set of
@@ -211,10 +231,10 @@ description: |+
  properties specification that is the subject of the following sections.

  ===========================================
  3 - idle-states node
  5 - idle-states node
  ===========================================

  ARM processor idle states are defined within the idle-states node, which is
  The processor idle states are defined within the idle-states node, which is
  a direct child of the cpus node [1] and provides a container where the
  processor idle states, defined as device tree nodes, are listed.

@@ -223,7 +243,7 @@ description: |+
  just supports idle_standby, an idle-states node is not required.

  ===========================================
  4 - References
  6 - References
  ===========================================

  [1] ARM Linux Kernel documentation - CPUs bindings
@@ -238,9 +258,15 @@ description: |+
  [4] ARM Architecture Reference Manuals
      http://infocenter.arm.com/help/index.jsp

  [6] ARM Linux Kernel documentation - Booting AArch64 Linux
  [5] ARM Linux Kernel documentation - Booting AArch64 Linux
      Documentation/arm64/booting.rst

  [6] RISC-V Linux Kernel documentation - CPUs bindings
      Documentation/devicetree/bindings/riscv/cpus.yaml

  [7] RISC-V Supervisor Binary Interface (SBI)
      http://github.com/riscv/riscv-sbi-doc/riscv-sbi.adoc

properties:
  $nodename:
    const: idle-states
@@ -253,7 +279,7 @@ properties:
      On ARM 32-bit systems this property is optional

      This assumes that the "enable-method" property is set to "psci" in the cpu
      node[6] that is responsible for setting up CPU idle management in the OS
      node[5] that is responsible for setting up CPU idle management in the OS
      implementation.
    const: psci

@@ -265,8 +291,8 @@ patternProperties:
      as follows.

      The idle state entered by executing the wfi instruction (idle_standby
      SBSA,[3][4]) is considered standard on all ARM platforms and therefore
      must not be listed.
      SBSA,[3][4]) is considered standard on all ARM and RISC-V platforms and
      therefore must not be listed.

      In addition to the properties listed above, a state node may require
      additional properties specific to the entry-method defined in the
@@ -275,7 +301,27 @@ patternProperties:

    properties:
      compatible:
        const: arm,idle-state
        enum:
          - arm,idle-state
          - riscv,idle-state

      arm,psci-suspend-param:
        $ref: /schemas/types.yaml#/definitions/uint32
        description: |
          power_state parameter to pass to the ARM PSCI suspend call.

          Device tree nodes that require usage of PSCI CPU_SUSPEND function
          (i.e. idle states node with entry-method property is set to "psci")
          must specify this property.

      riscv,sbi-suspend-param:
        $ref: /schemas/types.yaml#/definitions/uint32
        description: |
          suspend_type parameter to pass to the RISC-V SBI HSM suspend call.

          This property is required in idle state nodes of device tree meant
          for RISC-V systems. For more details on the suspend_type parameter
          refer the SBI specifiation v0.3 (or higher) [7].

      local-timer-stop:
        description:
@@ -317,6 +363,8 @@ patternProperties:
        description:
          A string used as a descriptive name for the idle state.

    additionalProperties: false

    required:
      - compatible
      - entry-latency-us
@@ -658,4 +706,150 @@ examples:
        };
    };

  - |
    // Example 3 (RISC-V 64-bit, 4-cpu systems, two clusters):

    cpus {
        #size-cells = <0>;
        #address-cells = <1>;

        cpu@0 {
            device_type = "cpu";
            compatible = "riscv";
            reg = <0x0>;
            riscv,isa = "rv64imafdc";
            mmu-type = "riscv,sv48";
            cpu-idle-states = <&CPU_RET_0_0 &CPU_NONRET_0_0
                            &CLUSTER_RET_0 &CLUSTER_NONRET_0>;

            cpu_intc0: interrupt-controller {
                #interrupt-cells = <1>;
                compatible = "riscv,cpu-intc";
                interrupt-controller;
            };
        };

        cpu@1 {
            device_type = "cpu";
            compatible = "riscv";
            reg = <0x1>;
            riscv,isa = "rv64imafdc";
            mmu-type = "riscv,sv48";
            cpu-idle-states = <&CPU_RET_0_0 &CPU_NONRET_0_0
                            &CLUSTER_RET_0 &CLUSTER_NONRET_0>;

            cpu_intc1: interrupt-controller {
                #interrupt-cells = <1>;
                compatible = "riscv,cpu-intc";
                interrupt-controller;
            };
        };

        cpu@10 {
            device_type = "cpu";
            compatible = "riscv";
            reg = <0x10>;
            riscv,isa = "rv64imafdc";
            mmu-type = "riscv,sv48";
            cpu-idle-states = <&CPU_RET_1_0 &CPU_NONRET_1_0
                            &CLUSTER_RET_1 &CLUSTER_NONRET_1>;

            cpu_intc10: interrupt-controller {
                #interrupt-cells = <1>;
                compatible = "riscv,cpu-intc";
                interrupt-controller;
            };
        };

        cpu@11 {
            device_type = "cpu";
            compatible = "riscv";
            reg = <0x11>;
            riscv,isa = "rv64imafdc";
            mmu-type = "riscv,sv48";
            cpu-idle-states = <&CPU_RET_1_0 &CPU_NONRET_1_0
                            &CLUSTER_RET_1 &CLUSTER_NONRET_1>;

            cpu_intc11: interrupt-controller {
                #interrupt-cells = <1>;
                compatible = "riscv,cpu-intc";
                interrupt-controller;
            };
        };

        idle-states {
            CPU_RET_0_0: cpu-retentive-0-0 {
                compatible = "riscv,idle-state";
                riscv,sbi-suspend-param = <0x10000000>;
                entry-latency-us = <20>;
                exit-latency-us = <40>;
                min-residency-us = <80>;
            };

            CPU_NONRET_0_0: cpu-nonretentive-0-0 {
                compatible = "riscv,idle-state";
                riscv,sbi-suspend-param = <0x90000000>;
                entry-latency-us = <250>;
                exit-latency-us = <500>;
                min-residency-us = <950>;
            };

            CLUSTER_RET_0: cluster-retentive-0 {
                compatible = "riscv,idle-state";
                riscv,sbi-suspend-param = <0x11000000>;
                local-timer-stop;
                entry-latency-us = <50>;
                exit-latency-us = <100>;
                min-residency-us = <250>;
                wakeup-latency-us = <130>;
            };

            CLUSTER_NONRET_0: cluster-nonretentive-0 {
                compatible = "riscv,idle-state";
                riscv,sbi-suspend-param = <0x91000000>;
                local-timer-stop;
                entry-latency-us = <600>;
                exit-latency-us = <1100>;
                min-residency-us = <2700>;
                wakeup-latency-us = <1500>;
            };

            CPU_RET_1_0: cpu-retentive-1-0 {
                compatible = "riscv,idle-state";
                riscv,sbi-suspend-param = <0x10000010>;
                entry-latency-us = <20>;
                exit-latency-us = <40>;
                min-residency-us = <80>;
            };

            CPU_NONRET_1_0: cpu-nonretentive-1-0 {
                compatible = "riscv,idle-state";
                riscv,sbi-suspend-param = <0x90000010>;
                entry-latency-us = <250>;
                exit-latency-us = <500>;
                min-residency-us = <950>;
            };

            CLUSTER_RET_1: cluster-retentive-1 {
                compatible = "riscv,idle-state";
                riscv,sbi-suspend-param = <0x11000010>;
                local-timer-stop;
                entry-latency-us = <50>;
                exit-latency-us = <100>;
                min-residency-us = <250>;
                wakeup-latency-us = <130>;
            };

            CLUSTER_NONRET_1: cluster-nonretentive-1 {
                compatible = "riscv,idle-state";
                riscv,sbi-suspend-param = <0x91000010>;
                local-timer-stop;
                entry-latency-us = <600>;
                exit-latency-us = <1100>;
                min-residency-us = <2700>;
                wakeup-latency-us = <1500>;
            };
        };
    };

...
+6 −0
Original line number Diff line number Diff line
@@ -99,6 +99,12 @@ properties:
      - compatible
      - interrupt-controller

  cpu-idle-states:
    $ref: '/schemas/types.yaml#/definitions/phandle-array'
    description: |
      List of phandles to idle state nodes supported
      by this hart (see ./idle-states.yaml).

required:
  - riscv,isa
  - interrupt-controller
+14 −0
Original line number Diff line number Diff line
@@ -5069,6 +5069,20 @@ S: Supported
F:	drivers/cpuidle/cpuidle-psci.h
F:	drivers/cpuidle/cpuidle-psci-domain.c
CPUIDLE DRIVER - DT IDLE PM DOMAIN
M:	Ulf Hansson <ulf.hansson@linaro.org>
L:	linux-pm@vger.kernel.org
S:	Supported
F:	drivers/cpuidle/dt_idle_genpd.c
F:	drivers/cpuidle/dt_idle_genpd.h
CPUIDLE DRIVER - RISC-V SBI
M:	Anup Patel <anup@brainfault.org>
L:	linux-pm@vger.kernel.org
L:	linux-riscv@lists.infradead.org
S:	Maintained
F:	drivers/cpuidle/cpuidle-riscv-sbi.c
CRAMFS FILESYSTEM
M:	Nicolas Pitre <nico@fluxnic.net>
S:	Maintained
Loading