ARM: driver updates for 6.1

The drivers branch for 6.1 is a bit larger than for most releases.  Most
 of the changes come from SoC maintainers for the drivers/soc subsystem:
 
  - A new driver for error handling on the NVIDIA Tegra
    'control backbone' bus.
 
  - A new driver for Qualcomm LLCC/DDR bandwidth measurement
 
  - New Rockchip rv1126 and rk3588 power domain drivers
 
  - DT binding updates for memory controllers, older Rockchip
    SoCs, various Mediatek devices, Qualcomm SCM firmware
 
  - Minor updates to Hisilicon LPC bus, the Allwinner SRAM
    driver, the Apple rtkit firmware driver, Tegra firmware
 
  - Minor updates for SoC drivers (Samsung, Mediatek, Renesas,
    Tegra, Qualcomm, Broadcom, NXP, ...)
 
 There are also some separate subsystem with downstream maintainers that
 merge updates this way:
 
  - Various updates and new drivers in the memory controller
    subsystem for Mediatek and Broadcom SoCs
 
  - Small set of changes in preparation to add support for FF-A
    v1.1 specification later, in the Arm FF-A firmware subsystem
 
  - debugfs support in the PSCI firmware subsystem
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmM+j54ACgkQmmx57+YA
 GNkK1Q//fSzCHUPNTrZKJi8mRtp/32Nrpav3eorMZWltKnYbYQyhqH/LCuSZJfe/
 rmGYFxsH6DHEgfHqqyzm6PNC0S4Hle6KiB5xnqXrTgqciPuSg4Fa9OMQgkbiQF6x
 uB2KR+TouQA3MssQh6NW4wy5XAkEqudZCSnEyOTJTmdpepZd/1Eu2Rhn8kx5AYQN
 pzYNGURRoirgYbO9vHMssCcpqyGNdR9SWXcOkROyd65L4LCHQ9JRh4etg7fSXP5j
 abWtTHSOwD8MTXOENOiNw/vyCfBX7wUoJkY2v8OUo3G/20qbOXKWPWi056gyDjVQ
 kJdlnnK4APtiluyBg2alEEZmJOd1iCaVP2j84EO1N4FEek2UGd/lMNOtAOJa+wbh
 eiE6KC5gswe+99//PdY4gB+7dRM3I0gU7FDMl9G5A4DPMEE/0bMKLKk1jR5vyYXl
 6QpN2N0OlU7d16MJiP9RvWf2/xJrcQrLQcy8FKvFVWClJ9wMvBXozKrvXgji9l3I
 ZTW+EViQiyWmj6KbFlDZkYT+Q6YosxaogJUNrZeIaAwmwJj1oTa+M6jYRnFU6uha
 XxG5TrybC9JQ/BpYCTYEqb16LOYALwEm7NWmylWASUCCZclC1u35qmmVEhDyBcS9
 98ePumkAwrcjmW0TZsiYXOCQWNOITuvU/Ku2t/+6Mhg+Xl44zX4=
 =WX9J
 -----END PGP SIGNATURE-----

Merge tag 'arm-drivers-6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc

Pull ARM driver updates from Arnd Bergmann:
 "The drivers branch for 6.1 is a bit larger than for most releases.

  Most of the changes come from SoC maintainers for the drivers/soc
  subsystem:

   - A new driver for error handling on the NVIDIA Tegra 'control
     backbone' bus.

   - A new driver for Qualcomm LLCC/DDR bandwidth measurement

   - New Rockchip rv1126 and rk3588 power domain drivers

   - DT binding updates for memory controllers, older Rockchip SoCs,
     various Mediatek devices, Qualcomm SCM firmware

   - Minor updates to Hisilicon LPC bus, the Allwinner SRAM driver, the
     Apple rtkit firmware driver, Tegra firmware

   - Minor updates for SoC drivers (Samsung, Mediatek, Renesas, Tegra,
     Qualcomm, Broadcom, NXP, ...)

  There are also some separate subsystem with downstream maintainers
  that merge updates this way:

   - Various updates and new drivers in the memory controller subsystem
     for Mediatek and Broadcom SoCs

   - Small set of changes in preparation to add support for FF-A v1.1
     specification later, in the Arm FF-A firmware subsystem

   - debugfs support in the PSCI firmware subsystem"

* tag 'arm-drivers-6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (149 commits)
  ARM: remove check for CONFIG_DEBUG_LL_SER3
  firmware/psci: Add debugfs support to ease debugging
  firmware/psci: Print a warning if PSCI doesn't accept PC mode
  dt-bindings: memory: snps,dw-umctl2-ddrc: Extend schema with IRQs/resets/clocks props
  dt-bindings: memory: snps,dw-umctl2-ddrc: Replace opencoded numbers with macros
  dt-bindings: memory: snps,dw-umctl2-ddrc: Use more descriptive device name
  dt-bindings: memory: synopsys,ddrc-ecc: Detach Zynq DDRC controller support
  soc: sunxi: sram: Add support for the D1 system control
  soc: sunxi: sram: Export the LDO control register
  soc: sunxi: sram: Save a pointer to the OF match data
  soc: sunxi: sram: Return void from the release function
  soc: apple: rtkit: Add apple_rtkit_poll
  soc: imx: add i.MX93 media blk ctrl driver
  soc: imx: add i.MX93 SRC power domain driver
  soc: imx: imx8m-blk-ctrl: Use genpd_xlate_onecell
  soc: imx: imx8mp-blk-ctrl: handle PCIe PHY resets
  soc: imx: imx8m-blk-ctrl: add i.MX8MP VPU blk ctrl
  soc: imx: add i.MX8MP HDMI blk ctrl HDCP/HRV_MWR
  soc: imx: add icc paths for i.MX8MP hsio/hdmi blk ctrl
  soc: imx: add icc paths for i.MX8MP media blk ctrl
  ...
This commit is contained in:
Linus Torvalds 2022-10-06 11:04:57 -07:00
commit ff6862c23d
121 changed files with 7566 additions and 885 deletions

View File

@ -0,0 +1,15 @@
What: /sys/bus/platform/devices/*/srpd
Date: July 2022
KernelVersion: 5.21
Contact: Florian Fainelli <f.fainelli@gmail.com>
Description:
Self Refresh Power Down (SRPD) inactivity timeout counted in
internal DDR controller clock cycles. Possible values range
from 0 (disable inactivity timeout) to 65535 (0xffff).
What: /sys/bus/platform/devices/*/frequency
Date: July 2022
KernelVersion: 5.21
Contact: Florian Fainelli <f.fainelli@gmail.com>
Description:
DDR PHY frequency in Hz.

View File

@ -187,15 +187,8 @@ Required properties:
Sequencer DRAM parameters and control registers. Used for Self-Refresh
Power-Down (SRPD), among other things.
Required properties:
- compatible : should contain one of these
"brcm,brcmstb-memc-ddr-rev-b.2.1"
"brcm,brcmstb-memc-ddr-rev-b.2.2"
"brcm,brcmstb-memc-ddr-rev-b.2.3"
"brcm,brcmstb-memc-ddr-rev-b.3.0"
"brcm,brcmstb-memc-ddr-rev-b.3.1"
"brcm,brcmstb-memc-ddr"
- reg : the MEMC DDR register range
See Documentation/devicetree/bindings/memory-controllers/brcm,brcmstb-memc-ddr.yaml for a
full list of supported compatible strings and properties.
Example:

View File

@ -554,8 +554,7 @@ properties:
- engicam,imx6ul-isiot # Engicam Is.IoT MX6UL eMMC/NAND Starter kit
- fsl,imx6ul-14x14-evk # i.MX6 UltraLite 14x14 EVK Board
- karo,imx6ul-tx6ul # Ka-Ro electronics TXUL-0010 Module
- kontron,imx6ul-n6310-som # Kontron N6310 SOM
- kontron,imx6ul-n6311-som # Kontron N6311 SOM
- kontron,sl-imx6ul # Kontron SL i.MX6UL SoM
- prt,prti6g # Protonic PRTI6G Board
- technexion,imx6ul-pico-dwarf # TechNexion i.MX6UL Pico-Dwarf
- technexion,imx6ul-pico-hobbit # TechNexion i.MX6UL Pico-Hobbit
@ -591,23 +590,17 @@ properties:
- const: phytec,imx6ul-pcl063 # PHYTEC phyCORE-i.MX 6UL
- const: fsl,imx6ul
- description: Kontron N6310 S Board
- description: Kontron BL i.MX6UL (N631X S) Board
items:
- const: kontron,imx6ul-n6310-s
- const: kontron,imx6ul-n6310-som
- const: kontron,bl-imx6ul # Kontron BL i.MX6UL Carrier Board
- const: kontron,sl-imx6ul # Kontron SL i.MX6UL SoM
- const: fsl,imx6ul
- description: Kontron N6311 S Board
- description: Kontron BL i.MX6UL 43 (N631X S 43) Board
items:
- const: kontron,imx6ul-n6311-s
- const: kontron,imx6ul-n6311-som
- const: fsl,imx6ul
- description: Kontron N6310 S 43 Board
items:
- const: kontron,imx6ul-n6310-s-43
- const: kontron,imx6ul-n6310-s
- const: kontron,imx6ul-n6310-som
- const: kontron,bl-imx6ul-43 # Kontron BL i.MX6UL Carrier Board with 4.3" Display
- const: kontron,bl-imx6ul # Kontron BL i.MX6UL Carrier Board
- const: kontron,sl-imx6ul # Kontron SL i.MX6UL SoM
- const: fsl,imx6ul
- description: TQ-Systems TQMa6UL1 SoM on MBa6ULx board
@ -637,7 +630,7 @@ properties:
- enum:
- fsl,imx6ull-14x14-evk # i.MX6 UltraLiteLite 14x14 EVK Board
- joz,jozacp # JOZ Access Point
- kontron,imx6ull-n6411-som # Kontron N6411 SOM
- kontron,sl-imx6ull # Kontron SL i.MX6ULL SoM
- myir,imx6ull-mys-6ulx-eval # MYiR Tech iMX6ULL Evaluation Board
- toradex,colibri-imx6ull # Colibri iMX6ULL Modules
- toradex,colibri-imx6ull-emmc # Colibri iMX6ULL 1GB (eMMC) Module
@ -698,10 +691,10 @@ properties:
- const: toradex,colibri-imx6ull-wifi # Colibri iMX6ULL Wi-Fi / BT Module
- const: fsl,imx6ull
- description: Kontron N6411 S Board
- description: Kontron BL i.MX6ULL (N6411 S) Board
items:
- const: kontron,imx6ull-n6411-s
- const: kontron,imx6ull-n6411-som
- const: kontron,bl-imx6ull # Kontron BL i.MX6ULL Carrier Board
- const: kontron,sl-imx6ull # Kontron SL i.MX6ULL SoM
- const: fsl,imx6ull
- description: TQ Systems TQMa6ULLx SoM on MBa6ULx board
@ -825,13 +818,15 @@ properties:
- emtrion,emcon-mx8mm-avari # emCON-MX8MM SoM on Avari Base
- fsl,imx8mm-ddr4-evk # i.MX8MM DDR4 EVK Board
- fsl,imx8mm-evk # i.MX8MM EVK Board
- gateworks,imx8mm-gw7904
- gw,imx8mm-gw71xx-0x # i.MX8MM Gateworks Development Kit
- gw,imx8mm-gw72xx-0x # i.MX8MM Gateworks Development Kit
- gw,imx8mm-gw73xx-0x # i.MX8MM Gateworks Development Kit
- gw,imx8mm-gw7901 # i.MX8MM Gateworks Board
- gw,imx8mm-gw7902 # i.MX8MM Gateworks Board
- gw,imx8mm-gw7903 # i.MX8MM Gateworks Board
- kontron,imx8mm-n801x-som # i.MX8MM Kontron SL (N801X) SOM
- kontron,imx8mm-sl # i.MX8MM Kontron SL (N801X) SOM
- kontron,imx8mm-osm-s # i.MX8MM Kontron OSM-S (N802X) SOM
- menlo,mx8menlo # i.MX8MM Menlo board with Verdin SoM
- toradex,verdin-imx8mm # Verdin iMX8M Mini Modules
- toradex,verdin-imx8mm-nonwifi # Verdin iMX8M Mini Modules without Wi-Fi / BT
@ -850,8 +845,14 @@ properties:
- description: Kontron BL i.MX8MM (N801X S) Board
items:
- const: kontron,imx8mm-n801x-s
- const: kontron,imx8mm-n801x-som
- const: kontron,imx8mm-bl
- const: kontron,imx8mm-sl
- const: fsl,imx8mm
- description: Kontron BL i.MX8MM OSM-S (N802X S) Board
items:
- const: kontron,imx8mm-bl-osm-s
- const: kontron,imx8mm-osm-s
- const: fsl,imx8mm
- description: Toradex Boards with Verdin iMX8M Mini Modules
@ -936,6 +937,13 @@ properties:
- toradex,verdin-imx8mp-wifi # Verdin iMX8M Plus Wi-Fi / BT Modules
- const: fsl,imx8mp
- description: Avnet (MSC Branded) Boards with SM2S i.MX8M Plus Modules
items:
- const: avnet,sm2s-imx8mp-14N0600E-ep1 # SM2S-IMX8PLUS-14N0600E on SM2-MB-EP1 Carrier Board
- const: avnet,sm2s-imx8mp-14N0600E # 14N0600E variant of SM2S-IMX8PLUS SoM
- const: avnet,sm2s-imx8mp # SM2S-IMX8PLUS SoM
- const: fsl,imx8mp
- description: Engicam i.Core MX8M Plus SoM based boards
items:
- enum:
@ -1034,6 +1042,12 @@ properties:
- toradex,colibri-imx8x # Colibri iMX8X Modules
- const: fsl,imx8qxp
- description: i.MX8DXL based Boards
items:
- enum:
- fsl,imx8dxl-evk # i.MX8DXL EVK Board
- const: fsl,imx8dxl
- description: i.MX8QXP Boards with Toradex Coilbri iMX8X Modules
items:
- enum:

View File

@ -21,10 +21,12 @@ select:
enum:
- rockchip,px30-pmu
- rockchip,rk3066-pmu
- rockchip,rk3128-pmu
- rockchip,rk3288-pmu
- rockchip,rk3368-pmu
- rockchip,rk3399-pmu
- rockchip,rk3568-pmu
- rockchip,rk3588-pmu
required:
- compatible
@ -35,10 +37,12 @@ properties:
- enum:
- rockchip,px30-pmu
- rockchip,rk3066-pmu
- rockchip,rk3128-pmu
- rockchip,rk3288-pmu
- rockchip,rk3368-pmu
- rockchip,rk3399-pmu
- rockchip,rk3568-pmu
- rockchip,rk3588-pmu
- const: syscon
- const: simple-mfd

View File

@ -1,61 +0,0 @@
QCOM Secure Channel Manager (SCM)
Qualcomm processors include an interface to communicate to the secure firmware.
This interface allows for clients to request different types of actions. These
can include CPU power up/down, HDCP requests, loading of firmware, and other
assorted actions.
Required properties:
- compatible: must contain one of the following:
* "qcom,scm-apq8064"
* "qcom,scm-apq8084"
* "qcom,scm-ipq4019"
* "qcom,scm-ipq806x"
* "qcom,scm-ipq8074"
* "qcom,scm-mdm9607"
* "qcom,scm-msm8226"
* "qcom,scm-msm8660"
* "qcom,scm-msm8916"
* "qcom,scm-msm8953"
* "qcom,scm-msm8960"
* "qcom,scm-msm8974"
* "qcom,scm-msm8976"
* "qcom,scm-msm8994"
* "qcom,scm-msm8996"
* "qcom,scm-msm8998"
* "qcom,scm-qcs404"
* "qcom,scm-sc7180"
* "qcom,scm-sc7280"
* "qcom,scm-sm6125"
* "qcom,scm-sdm845"
* "qcom,scm-sdx55"
* "qcom,scm-sdx65"
* "qcom,scm-sm6350"
* "qcom,scm-sm8150"
* "qcom,scm-sm8250"
* "qcom,scm-sm8350"
* "qcom,scm-sm8450"
and:
* "qcom,scm"
- clocks: Specifies clocks needed by the SCM interface, if any:
* core clock required for "qcom,scm-apq8064", "qcom,scm-msm8660" and
"qcom,scm-msm8960"
* core, iface and bus clocks required for "qcom,scm-apq8084",
"qcom,scm-msm8916", "qcom,scm-msm8953", "qcom,scm-msm8974" and "qcom,scm-msm8976"
- clock-names: Must contain "core" for the core clock, "iface" for the interface
clock and "bus" for the bus clock per the requirements of the compatible.
- qcom,dload-mode: phandle to the TCSR hardware block and offset of the
download mode control register (optional)
- interconnects: Specifies the bandwidth requirements of the SCM interface (optional)
Example for MSM8916:
firmware {
scm {
compatible = "qcom,msm8916", "qcom,scm";
clocks = <&gcc GCC_CRYPTO_CLK> ,
<&gcc GCC_CRYPTO_AXI_CLK>,
<&gcc GCC_CRYPTO_AHB_CLK>;
clock-names = "core", "bus", "iface";
};
};

View File

@ -0,0 +1,148 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/firmware/qcom,scm.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: QCOM Secure Channel Manager (SCM)
description: |
Qualcomm processors include an interface to communicate to the secure firmware.
This interface allows for clients to request different types of actions.
These can include CPU power up/down, HDCP requests, loading of firmware,
and other assorted actions.
maintainers:
- Bjorn Andersson <bjorn.andersson@linaro.org>
- Robert Marko <robimarko@gmail.com>
- Guru Das Srinagesh <quic_gurus@quicinc.com>
properties:
compatible:
items:
- enum:
- qcom,scm-apq8064
- qcom,scm-apq8084
- qcom,scm-ipq4019
- qcom,scm-ipq6018
- qcom,scm-ipq806x
- qcom,scm-ipq8074
- qcom,scm-mdm9607
- qcom,scm-msm8226
- qcom,scm-msm8660
- qcom,scm-msm8916
- qcom,scm-msm8953
- qcom,scm-msm8960
- qcom,scm-msm8974
- qcom,scm-msm8976
- qcom,scm-msm8994
- qcom,scm-msm8996
- qcom,scm-msm8998
- qcom,scm-sc7180
- qcom,scm-sc7280
- qcom,scm-sc8280xp
- qcom,scm-sdm845
- qcom,scm-sdx55
- qcom,scm-sdx65
- qcom,scm-sm6115
- qcom,scm-sm6125
- qcom,scm-sm6350
- qcom,scm-sm8150
- qcom,scm-sm8250
- qcom,scm-sm8350
- qcom,scm-sm8450
- qcom,scm-qcs404
- const: qcom,scm
clocks:
minItems: 1
maxItems: 3
clock-names:
minItems: 1
maxItems: 3
interconnects:
maxItems: 1
interconnect-names:
maxItems: 1
'#reset-cells':
const: 1
qcom,dload-mode:
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
- items:
- description: phandle to TCSR hardware block
- description: offset of the download mode control register
description: TCSR hardware block
allOf:
- if:
properties:
compatible:
contains:
enum:
- qcom,scm-apq8064
- qcom,scm-msm8660
- qcom,scm-msm8960
then:
properties:
clock-names:
items:
- const: core
clocks:
maxItems: 1
required:
- clocks
- clock-names
- if:
properties:
compatible:
contains:
enum:
- qcom,scm-apq8084
- qcom,scm-mdm9607
- qcom,scm-msm8916
- qcom,scm-msm8953
- qcom,scm-msm8974
- qcom,scm-msm8976
then:
properties:
clock-names:
items:
- const: core
- const: bus
- const: iface
clocks:
minItems: 3
maxItems: 3
required:
- clocks
- clock-names
required:
- compatible
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,gcc-msm8916.h>
firmware {
scm {
compatible = "qcom,scm-msm8916", "qcom,scm";
clocks = <&gcc GCC_CRYPTO_CLK>,
<&gcc GCC_CRYPTO_AXI_CLK>,
<&gcc GCC_CRYPTO_AHB_CLK>;
clock-names = "core", "bus", "iface";
};
};

View File

@ -24,9 +24,12 @@ properties:
oneOf:
- items:
- enum:
- qcom,sc7280-bwmon
- qcom,sdm845-bwmon
- const: qcom,msm8998-bwmon
- const: qcom,msm8998-bwmon # BWMON v4
- const: qcom,sc7280-llcc-bwmon # BWMON v5
- const: qcom,sdm845-llcc-bwmon # BWMON v5
interconnects:
maxItems: 1

View File

@ -1,38 +0,0 @@
* Samsung Exynos5 G-Scaler device
G-Scaler is used for scaling and color space conversion on Exynos5 SoCs.
Required properties:
- compatible: should be one of
"samsung,exynos5250-gsc"
"samsung,exynos5420-gsc"
"samsung,exynos5433-gsc"
"samsung,exynos5-gsc" (deprecated)
- reg: should contain G-Scaler physical address location and length.
- interrupts: should contain G-Scaler interrupt number
Optional properties:
- samsung,sysreg: handle to syscon used to control the system registers to
set writeback input and destination
Example:
gsc_0: gsc@13e00000 {
compatible = "samsung,exynos5250-gsc";
reg = <0x13e00000 0x1000>;
interrupts = <0 85 0>;
};
Aliases:
Each G-Scaler node should have a numbered alias in the aliases node,
in the form of gscN, N = 0...3. G-Scaler driver uses these aliases
to retrieve the device IDs using "of_alias_get_id()" call.
Example:
aliases {
gsc0 =&gsc_0;
gsc1 =&gsc_1;
gsc2 =&gsc_2;
gsc3 =&gsc_3;
};

View File

@ -0,0 +1,109 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/samsung,exynos5250-gsc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung Exynos SoC G-Scaler
maintainers:
- Inki Dae <inki.dae@samsung.com>
- Krzysztof Kozlowski <krzk@kernel.org>
- Seung-Woo Kim <sw0312.kim@samsung.com
description:
G-Scaler is used for scaling and color space conversion on Samsung Exynos
SoCs.
Each G-Scaler node should have a numbered alias in the aliases node, in the
form of gscN, N = 0...3.
properties:
compatible:
oneOf:
- items:
- enum:
- samsung,exynos5250-gsc
- samsung,exynos5420-gsc
- const: samsung,exynos5-gsc
- enum:
- samsung,exynos5433-gsc
- const: samsung,exynos5-gsc
deprecated: True
clocks:
minItems: 1
maxItems: 5
clock-names:
minItems: 1
maxItems: 5
interrupts:
maxItems: 1
iommus:
maxItems: 1
power-domains:
maxItems: 1
reg:
maxItems: 1
samsung,sysreg:
$ref: /schemas/types.yaml#/definitions/phandle
description:
Syscon used to control the system registers to set writeback input and destination.
required:
- compatible
- clocks
- clock-names
- interrupts
- reg
allOf:
- if:
properties:
compatible:
contains:
enum:
- samsung,exynos5-gsc
- samsung,exynos5250-gsc
- samsung,exynos5420-gsc
then:
properties:
clocks:
maxItems: 1
clock-names:
items:
- const: gscl
else:
properties:
clocks:
minItems: 5
clock-names:
items:
- const: pclk
- const: aclk
- const: aclk_xiu
- const: aclk_gsclbend
- const: gsd
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/exynos5250.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
video-scaler@13e00000 {
compatible = "samsung,exynos5250-gsc", "samsung,exynos5-gsc";
reg = <0x13e00000 0x1000>;
interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
power-domains = <&pd_gsc>;
clocks = <&clock CLK_GSCL0>;
clock-names = "gscl";
iommus = <&sysmmu_gsc0>;
};

View File

@ -0,0 +1,52 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/memory-controllers/brcm,brcmstb-memc-ddr.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Memory controller (MEMC) for Broadcom STB
maintainers:
- Florian Fainelli <f.fainelli@gmail.com>
properties:
compatible:
items:
- enum:
- brcm,brcmstb-memc-ddr-rev-b.1.x
- brcm,brcmstb-memc-ddr-rev-b.2.0
- brcm,brcmstb-memc-ddr-rev-b.2.1
- brcm,brcmstb-memc-ddr-rev-b.2.2
- brcm,brcmstb-memc-ddr-rev-b.2.3
- brcm,brcmstb-memc-ddr-rev-b.2.5
- brcm,brcmstb-memc-ddr-rev-b.2.6
- brcm,brcmstb-memc-ddr-rev-b.2.7
- brcm,brcmstb-memc-ddr-rev-b.2.8
- brcm,brcmstb-memc-ddr-rev-b.3.0
- brcm,brcmstb-memc-ddr-rev-b.3.1
- brcm,brcmstb-memc-ddr-rev-c.1.0
- brcm,brcmstb-memc-ddr-rev-c.1.1
- brcm,brcmstb-memc-ddr-rev-c.1.2
- brcm,brcmstb-memc-ddr-rev-c.1.3
- brcm,brcmstb-memc-ddr-rev-c.1.4
- const: brcm,brcmstb-memc-ddr
reg:
maxItems: 1
clock-frequency:
description: DDR PHY frequency in Hz
required:
- compatible
- reg
additionalProperties: false
examples:
- |
memory-controller@9902000 {
compatible = "brcm,brcmstb-memc-ddr-rev-c.1.1", "brcm,brcmstb-memc-ddr";
reg = <0x9902000 0x600>;
clock-frequency = <2133000000>;
};

View File

@ -16,7 +16,7 @@ description: |
MediaTek SMI have two generations of HW architecture, here is the list
which generation the SoCs use:
generation 1: mt2701 and mt7623.
generation 2: mt2712, mt6779, mt8167, mt8173, mt8183, mt8186, mt8192 and mt8195.
generation 2: mt2712, mt6779, mt8167, mt8173, mt8183, mt8186, mt8188, mt8192 and mt8195.
There's slight differences between the two SMI, for generation 2, the
register which control the iommu port is at each larb's register base. But
@ -37,6 +37,8 @@ properties:
- mediatek,mt8173-smi-common
- mediatek,mt8183-smi-common
- mediatek,mt8186-smi-common
- mediatek,mt8188-smi-common-vdo
- mediatek,mt8188-smi-common-vpp
- mediatek,mt8192-smi-common
- mediatek,mt8195-smi-common-vdo
- mediatek,mt8195-smi-common-vpp
@ -144,7 +146,16 @@ allOf:
- const: gals0
- const: gals1
else: # for gen2 HW that don't have gals
- if: # for gen2 HW that don't have gals
properties:
compatible:
enum:
- mediatek,mt2712-smi-common
- mediatek,mt6795-smi-common
- mediatek,mt8167-smi-common
- mediatek,mt8173-smi-common
then:
properties:
clocks:
minItems: 2

View File

@ -25,6 +25,7 @@ properties:
- mediatek,mt8173-smi-larb
- mediatek,mt8183-smi-larb
- mediatek,mt8186-smi-larb
- mediatek,mt8188-smi-larb
- mediatek,mt8192-smi-larb
- mediatek,mt8195-smi-larb
@ -78,6 +79,7 @@ allOf:
enum:
- mediatek,mt8183-smi-larb
- mediatek,mt8186-smi-larb
- mediatek,mt8188-smi-larb
- mediatek,mt8195-smi-larb
then:
@ -111,6 +113,7 @@ allOf:
- mediatek,mt2712-smi-larb
- mediatek,mt6779-smi-larb
- mediatek,mt8186-smi-larb
- mediatek,mt8188-smi-larb
- mediatek,mt8192-smi-larb
- mediatek,mt8195-smi-larb

View File

@ -0,0 +1,118 @@
# SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2
---
$id: http://devicetree.org/schemas/memory-controllers/snps,dw-umctl2-ddrc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Synopsys DesignWare Universal Multi-Protocol Memory Controller
maintainers:
- Krzysztof Kozlowski <krzk@kernel.org>
- Manish Narani <manish.narani@xilinx.com>
- Michal Simek <michal.simek@xilinx.com>
description: |
Synopsys DesignWare Enhanced uMCTL2 DDR Memory Controller is capable of
working with the memory devices supporting up to (LP)DDR4 protocol. It can
be equipped with SEC/DEC ECC feature if DRAM data bus width is either
16-bits or 32-bits or 64-bits wide.
For instance the ZynqMP DDR controller is based on the DW uMCTL2 v2.40a
controller. It has an optional SEC/DEC ECC support in 64- and 32-bits
bus width configurations.
properties:
compatible:
oneOf:
- deprecated: true
description: Synopsys DW uMCTL2 DDR controller v3.80a
const: snps,ddrc-3.80a
- description: Synopsys DW uMCTL2 DDR controller
const: snps,dw-umctl2-ddrc
- description: Xilinx ZynqMP DDR controller v2.40a
const: xlnx,zynqmp-ddrc-2.40a
interrupts:
description:
DW uMCTL2 DDRC IP-core provides individual IRQ signal for each event":"
ECC Corrected Error, ECC Uncorrected Error, ECC Address Protection,
Scrubber-Done signal, DFI Parity/CRC Error. Some platforms may have the
signals merged before they reach the IRQ controller or have some of them
absent in case if the corresponding feature is unavailable/disabled.
minItems: 1
maxItems: 5
interrupt-names:
minItems: 1
maxItems: 5
oneOf:
- description: Common ECC CE/UE/Scrubber/DFI Errors IRQ
items:
- const: ecc
- description: Individual ECC CE/UE/Scrubber/DFI Errors IRQs
items:
enum: [ ecc_ce, ecc_ue, ecc_ap, ecc_sbr, dfi_e ]
reg:
maxItems: 1
clocks:
description:
A standard set of the clock sources contains CSRs bus clock, AXI-ports
reference clock, DDRC core clock, Scrubber standalone clock
(synchronous to the DDRC clock).
minItems: 1
maxItems: 4
clock-names:
minItems: 1
maxItems: 4
items:
enum: [ pclk, aclk, core, sbr ]
resets:
description:
Each clock domain can have separate reset signal.
minItems: 1
maxItems: 4
reset-names:
minItems: 1
maxItems: 4
items:
enum: [ prst, arst, core, sbr ]
required:
- compatible
- reg
- interrupts
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
memory-controller@fd070000 {
compatible = "xlnx,zynqmp-ddrc-2.40a";
reg = <0xfd070000 0x30000>;
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "ecc";
};
- |
#include <dt-bindings/interrupt-controller/irq.h>
memory-controller@3d400000 {
compatible = "snps,dw-umctl2-ddrc";
reg = <0x3d400000 0x400000>;
interrupts = <147 IRQ_TYPE_LEVEL_HIGH>, <148 IRQ_TYPE_LEVEL_HIGH>,
<149 IRQ_TYPE_LEVEL_HIGH>, <150 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "ecc_ce", "ecc_ue", "ecc_sbr", "dfi_e";
clocks = <&pclk>, <&aclk>, <&core_clk>, <&sbr_clk>;
clock-names = "pclk", "aclk", "core", "sbr";
};
...

View File

@ -1,76 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2
---
$id: http://devicetree.org/schemas/memory-controllers/synopsys,ddrc-ecc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Synopsys IntelliDDR Multi Protocol memory controller
maintainers:
- Krzysztof Kozlowski <krzk@kernel.org>
- Manish Narani <manish.narani@xilinx.com>
- Michal Simek <michal.simek@xilinx.com>
description: |
The ZynqMP DDR ECC controller has an optional ECC support in 64-bit and
32-bit bus width configurations.
The Zynq DDR ECC controller has an optional ECC support in half-bus width
(16-bit) configuration.
These both ECC controllers correct single bit ECC errors and detect double bit
ECC errors.
properties:
compatible:
enum:
- snps,ddrc-3.80a
- xlnx,zynq-ddrc-a05
- xlnx,zynqmp-ddrc-2.40a
interrupts:
maxItems: 1
reg:
maxItems: 1
required:
- compatible
- reg
allOf:
- if:
properties:
compatible:
contains:
enum:
- snps,ddrc-3.80a
- xlnx,zynqmp-ddrc-2.40a
then:
required:
- interrupts
else:
properties:
interrupts: false
additionalProperties: false
examples:
- |
memory-controller@f8006000 {
compatible = "xlnx,zynq-ddrc-a05";
reg = <0xf8006000 0x1000>;
};
- |
axi {
#address-cells = <2>;
#size-cells = <2>;
memory-controller@fd070000 {
compatible = "xlnx,zynqmp-ddrc-2.40a";
reg = <0x0 0xfd070000 0x0 0x30000>;
interrupt-parent = <&gic>;
interrupts = <0 112 4>;
};
};

View File

@ -0,0 +1,38 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/memory-controllers/xlnx,zynq-ddrc-a05.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Zynq A05 DDR Memory Controller
maintainers:
- Krzysztof Kozlowski <krzk@kernel.org>
- Manish Narani <manish.narani@xilinx.com>
- Michal Simek <michal.simek@xilinx.com>
description:
The Zynq DDR ECC controller has an optional ECC support in half-bus width
(16-bit) configuration. It is cappable of correcting single bit ECC errors
and detecting double bit ECC errors.
properties:
compatible:
const: xlnx,zynq-ddrc-a05
reg:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
memory-controller@f8006000 {
compatible = "xlnx,zynq-ddrc-a05";
reg = <0xf8006000 0x1000>;
};
...

View File

@ -40,6 +40,8 @@ properties:
- allwinner,sun50i-a64-system-controller
- brcm,cru-clkset
- freecom,fsg-cs2-system-controller
- fsl,imx93-aonmix-ns-syscfg
- fsl,imx93-wakeupmix-syscfg
- hisilicon,dsa-subctrl
- hisilicon,hi6220-sramctrl
- hisilicon,pcie-sas-subctrl

View File

@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Mediatek Power Domains Controller
maintainers:
- Weiyi Lu <weiyi.lu@mediatek.com>
- MandyJH Liu <mandyjh.liu@mediatek.com>
- Matthias Brugger <mbrugger@suse.com>
description: |
@ -19,7 +19,7 @@ description: |
properties:
$nodename:
const: power-controller
pattern: '^power-controller(@[0-9a-f]+)?$'
compatible:
enum:
@ -42,6 +42,23 @@ properties:
patternProperties:
"^power-domain@[0-9a-f]+$":
$ref: "#/$defs/power-domain-node"
patternProperties:
"^power-domain@[0-9a-f]+$":
$ref: "#/$defs/power-domain-node"
patternProperties:
"^power-domain@[0-9a-f]+$":
$ref: "#/$defs/power-domain-node"
patternProperties:
"^power-domain@[0-9a-f]+$":
$ref: "#/$defs/power-domain-node"
unevaluatedProperties: false
unevaluatedProperties: false
unevaluatedProperties: false
unevaluatedProperties: false
$defs:
power-domain-node:
type: object
description: |
Represents the power domains within the power controller node as documented
@ -100,123 +117,9 @@ patternProperties:
$ref: /schemas/types.yaml#/definitions/phandle
description: phandle to the device containing the SMI register range.
patternProperties:
"^power-domain@[0-9a-f]+$":
type: object
description: |
Represents a power domain child within a power domain parent node.
properties:
'#power-domain-cells':
description:
Must be 0 for nodes representing a single PM domain and 1 for nodes
providing multiple PM domains.
'#address-cells':
const: 1
'#size-cells':
const: 0
reg:
maxItems: 1
clocks:
description: |
A number of phandles to clocks that need to be enabled during domain
power-up sequencing.
clock-names:
description: |
List of names of clocks, in order to match the power-up sequencing
for each power domain we need to group the clocks by name. BASIC
clocks need to be enabled before enabling the corresponding power
domain, and should not have a '-' in their name (i.e mm, mfg, venc).
SUSBYS clocks need to be enabled before releasing the bus protection,
and should contain a '-' in their name (i.e mm-0, isp-0, cam-0).
In order to follow properly the power-up sequencing, the clocks must
be specified by order, adding first the BASIC clocks followed by the
SUSBSYS clocks.
domain-supply:
description: domain regulator supply.
mediatek,infracfg:
$ref: /schemas/types.yaml#/definitions/phandle
description: phandle to the device containing the INFRACFG register range.
mediatek,smi:
$ref: /schemas/types.yaml#/definitions/phandle
description: phandle to the device containing the SMI register range.
patternProperties:
"^power-domain@[0-9a-f]+$":
type: object
description: |
Represents a power domain child within a power domain parent node.
properties:
'#power-domain-cells':
description:
Must be 0 for nodes representing a single PM domain and 1 for nodes
providing multiple PM domains.
'#address-cells':
const: 1
'#size-cells':
const: 0
reg:
maxItems: 1
clocks:
description: |
A number of phandles to clocks that need to be enabled during domain
power-up sequencing.
clock-names:
description: |
List of names of clocks, in order to match the power-up sequencing
for each power domain we need to group the clocks by name. BASIC
clocks need to be enabled before enabling the corresponding power
domain, and should not have a '-' in their name (i.e mm, mfg, venc).
SUSBYS clocks need to be enabled before releasing the bus protection,
and should contain a '-' in their name (i.e mm-0, isp-0, cam-0).
In order to follow properly the power-up sequencing, the clocks must
be specified by order, adding first the BASIC clocks followed by the
SUSBSYS clocks.
domain-supply:
description: domain regulator supply.
mediatek,infracfg:
$ref: /schemas/types.yaml#/definitions/phandle
description: phandle to the device containing the INFRACFG register range.
mediatek,smi:
$ref: /schemas/types.yaml#/definitions/phandle
description: phandle to the device containing the SMI register range.
required:
- reg
additionalProperties: false
required:
- reg
additionalProperties: false
required:
- reg
additionalProperties: false
required:
- compatible

View File

@ -40,6 +40,7 @@ properties:
- qcom,sm6115-rpmpd
- qcom,sm6125-rpmpd
- qcom,sm6350-rpmhpd
- qcom,sm6375-rpmpd
- qcom,sm8150-rpmhpd
- qcom,sm8250-rpmhpd
- qcom,sm8350-rpmhpd

View File

@ -41,6 +41,8 @@ properties:
- rockchip,rk3368-power-controller
- rockchip,rk3399-power-controller
- rockchip,rk3568-power-controller
- rockchip,rk3588-power-controller
- rockchip,rv1126-power-controller
"#power-domain-cells":
const: 1
@ -119,6 +121,8 @@ $defs:
"include/dt-bindings/power/rk3368-power.h"
"include/dt-bindings/power/rk3399-power.h"
"include/dt-bindings/power/rk3568-power.h"
"include/dt-bindings/power/rk3588-power.h"
"include/dt-bindings/power/rockchip,rv1126-power.h"
clocks:
minItems: 1

View File

@ -58,6 +58,7 @@ properties:
- rockchip,rk3568-pmu-io-voltage-domain
- rockchip,rv1108-io-voltage-domain
- rockchip,rv1108-pmu-io-voltage-domain
- rockchip,rv1126-pmu-io-voltage-domain
required:
- compatible
@ -78,6 +79,7 @@ allOf:
- $ref: "#/$defs/rk3568-pmu"
- $ref: "#/$defs/rv1108"
- $ref: "#/$defs/rv1108-pmu"
- $ref: "#/$defs/rv1126-pmu"
$defs:
px30:
@ -344,6 +346,34 @@ $defs:
pmu-supply:
description: The supply connected to PMUIO_VDD.
rv1126-pmu:
if:
properties:
compatible:
contains:
const: rockchip,rv1126-pmu-io-voltage-domain
then:
properties:
vccio1-supply:
description: The supply connected to VCCIO1.
vccio2-supply:
description: The supply connected to VCCIO2.
vccio3-supply:
description: The supply connected to VCCIO3.
vccio4-supply:
description: The supply connected to VCCIO4.
vccio5-supply:
description: The supply connected to VCCIO5.
vccio6-supply:
description: The supply connected to VCCIO6.
vccio7-supply:
description: The supply connected to VCCIO7.
pmuio0-supply:
description: The supply connected to PMUIO0.
pmuio1-supply:
description: The supply connected to PMUIO1.
examples:
- |
io-domains {

View File

@ -27,9 +27,46 @@ properties:
const: 1
power-domains:
minItems: 4
maxItems: 4
power-domain-names:
maxItems: 4
clocks:
maxItems: 3
clock-names:
maxItems: 3
interconnects:
maxItems: 3
interconnect-names:
maxItems: 3
required:
- compatible
- reg
- power-domains
- power-domain-names
- clocks
- clock-names
allOf:
- if:
properties:
compatible:
contains:
const: fsl,imx8mm-vpu-blk-ctrl
then:
properties:
power-domains:
items:
- description: bus power domain
- description: G1 decoder power domain
- description: G2 decoder power domain
- description: H1 encoder power domain
power-domain-names:
items:
- const: bus
@ -38,8 +75,10 @@ properties:
- const: h1
clocks:
minItems: 3
maxItems: 3
items:
- description: G1 decoder clk
- description: G2 decoder clk
- description: H1 encoder clk
clock-names:
items:
@ -47,13 +86,62 @@ properties:
- const: g2
- const: h1
required:
- compatible
- reg
- power-domains
- power-domain-names
- clocks
- clock-names
interconnects:
items:
- description: G1 decoder interconnect
- description: G2 decoder interconnect
- description: H1 encoder power domain
interconnect-names:
items:
- const: g1
- const: g2
- const: h1
- if:
properties:
compatible:
contains:
const: fsl,imx8mp-vpu-blk-ctrl
then:
properties:
power-domains:
items:
- description: bus power domain
- description: G1 decoder power domain
- description: G2 decoder power domain
- description: VC8000E encoder power domain
power-domain-names:
items:
- const: bus
- const: g1
- const: g2
- const: vc8000e
clocks:
items:
- description: G1 decoder clk
- description: G2 decoder clk
- description: VC8000E encoder clk
clock-names:
items:
- const: g1
- const: g2
- const: vc8000e
interconnects:
items:
- description: G1 decoder interconnect
- description: G2 decoder interconnect
- description: VC8000E encoder interconnect
interconnect-names:
items:
- const: g1
- const: g2
- const: vc8000e
additionalProperties: false

View File

@ -52,6 +52,15 @@ properties:
- const: ref_266m
- const: ref_24m
interconnects:
maxItems: 3
interconnect-names:
items:
- const: hrv
- const: lcdif-hdmi
- const: hdcp
required:
- compatible
- reg

View File

@ -48,6 +48,16 @@ properties:
- const: usb
- const: pcie
interconnects:
maxItems: 4
interconnect-names:
items:
- const: noc-pcie
- const: usb1
- const: usb2
- const: pcie
required:
- compatible
- reg

View File

@ -64,6 +64,20 @@ properties:
- const: isp
- const: phy
interconnects:
maxItems: 8
interconnect-names:
items:
- const: lcdif-rd
- const: lcdif-wr
- const: isi0
- const: isi1
- const: isi2
- const: isp0
- const: isp1
- const: dwe
required:
- compatible
- reg

View File

@ -0,0 +1,80 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/soc/imx/fsl,imx93-media-blk-ctrl.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP i.MX93 Media blk-ctrl
maintainers:
- Peng Fan <peng.fan@nxp.com>
description:
The i.MX93 MEDIAMIX domain contains control and status registers known
as MEDIAMIX Block Control (MEDIAMIX BLK_CTRL). These registers include
clocking, reset, and miscellaneous top-level controls for peripherals
within the MEDIAMIX domain
properties:
compatible:
items:
- const: fsl,imx93-media-blk-ctrl
- const: syscon
reg:
maxItems: 1
'#power-domain-cells':
const: 1
power-domains:
maxItems: 1
clocks:
maxItems: 10
clock-names:
items:
- const: apb
- const: axi
- const: nic
- const: disp
- const: cam
- const: pxp
- const: lcdif
- const: isi
- const: csi
- const: dsi
required:
- compatible
- reg
- power-domains
- clocks
- clock-names
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/imx93-clock.h>
#include <dt-bindings/power/fsl,imx93-power.h>
media_blk_ctrl: system-controller@4ac10000 {
compatible = "fsl,imx93-media-blk-ctrl", "syscon";
reg = <0x4ac10000 0x10000>;
power-domains = <&mediamix>;
clocks = <&clk IMX93_CLK_MEDIA_APB>,
<&clk IMX93_CLK_MEDIA_AXI>,
<&clk IMX93_CLK_NIC_MEDIA_GATE>,
<&clk IMX93_CLK_MEDIA_DISP_PIX>,
<&clk IMX93_CLK_CAM_PIX>,
<&clk IMX93_CLK_PXP_GATE>,
<&clk IMX93_CLK_LCDIF_GATE>,
<&clk IMX93_CLK_ISI_GATE>,
<&clk IMX93_CLK_MIPI_CSI_GATE>,
<&clk IMX93_CLK_MIPI_DSI_GATE>;
clock-names = "apb", "axi", "nic", "disp", "cam",
"pxp", "lcdif", "isi", "csi", "dsi";
#power-domain-cells = <1>;
};

View File

@ -0,0 +1,96 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/soc/imx/fsl,imx93-src.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP i.MX93 System Reset Controller
maintainers:
- Peng Fan <peng.fan@nxp.com>
description: |
The System Reset Controller (SRC) is responsible for the generation of
all the system reset signals and boot argument latching.
Its main functions are as follows,
- Deals with all global system reset sources from other modules,
and generates global system reset.
- Responsible for power gating of MIXs (Slices) and their memory
low power control.
properties:
compatible:
items:
- const: fsl,imx93-src
- const: syscon
reg:
maxItems: 1
ranges: true
'#address-cells':
const: 1
'#size-cells':
const: 1
patternProperties:
"power-domain@[0-9a-f]+$":
type: object
properties:
compatible:
items:
- const: fsl,imx93-src-slice
'#power-domain-cells':
const: 0
reg:
items:
- description: mix slice register region
- description: mem slice register region
clocks:
description: |
A number of phandles to clocks that need to be enabled
during domain power-up sequencing to ensure reset
propagation into devices located inside this power domain.
minItems: 1
maxItems: 5
required:
- compatible
- '#power-domain-cells'
- reg
required:
- compatible
- reg
- ranges
- '#address-cells'
- '#size-cells'
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/imx93-clock.h>
system-controller@44460000 {
compatible = "fsl,imx93-src", "syscon";
reg = <0x44460000 0x10000>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
mediamix: power-domain@0 {
compatible = "fsl,imx93-src-slice";
reg = <0x44462400 0x400>, <0x44465800 0x400>;
#power-domain-cells = <0>;
clocks = <&clk IMX93_CLK_MEDIA_AXI>,
<&clk IMX93_CLK_MEDIA_APB>;
};
};

View File

@ -26,10 +26,12 @@ properties:
enum:
- mediatek,mt2701-disp-mutex
- mediatek,mt2712-disp-mutex
- mediatek,mt6795-disp-mutex
- mediatek,mt8167-disp-mutex
- mediatek,mt8173-disp-mutex
- mediatek,mt8183-disp-mutex
- mediatek,mt8186-disp-mutex
- mediatek,mt8186-mdp3-mutex
- mediatek,mt8192-disp-mutex
- mediatek,mt8195-disp-mutex

View File

@ -28,6 +28,7 @@ Required properties in pwrap device node.
"mediatek,mt8173-pwrap" for MT8173 SoCs
"mediatek,mt8183-pwrap" for MT8183 SoCs
"mediatek,mt8186-pwrap" for MT8186 SoCs
"mediatek,mt8188-pwrap", "mediatek,mt8195-pwrap" for MT8188 SoCs
"mediatek,mt8195-pwrap" for MT8195 SoCs
"mediatek,mt8516-pwrap" for MT8516 SoCs
- interrupts: IRQ for pwrap in SOC

View File

@ -20,6 +20,7 @@ properties:
compatible:
enum:
- qcom,rpmh-stats
- qcom,sdm845-rpmh-stats
- qcom,rpm-stats
# For older RPM firmware versions with fixed offset for the sleep stats
- qcom,apq8084-rpm-stats

View File

@ -16,9 +16,12 @@ properties:
- enum:
- rockchip,rk3288-sgrf
- rockchip,rk3566-pipe-grf
- rockchip,rk3568-pcie3-phy-grf
- rockchip,rk3568-pipe-grf
- rockchip,rk3568-pipe-phy-grf
- rockchip,rk3568-usb2phy-grf
- rockchip,rk3588-pcie3-phy-grf
- rockchip,rk3588-pcie3-pipe-grf
- rockchip,rv1108-usbgrf
- const: syscon
- items:
@ -28,6 +31,7 @@ properties:
- rockchip,px30-usb2phy-grf
- rockchip,rk3036-grf
- rockchip,rk3066-grf
- rockchip,rk3128-grf
- rockchip,rk3188-grf
- rockchip,rk3228-grf
- rockchip,rk3288-grf
@ -45,6 +49,8 @@ properties:
- rockchip,rk3568-pmugrf
- rockchip,rv1108-grf
- rockchip,rv1108-pmugrf
- rockchip,rv1126-grf
- rockchip,rv1126-pmugrf
- const: syscon
- const: simple-mfd
@ -178,6 +184,7 @@ allOf:
contains:
enum:
- rockchip,px30-usb2phy-grf
- rockchip,rk3128-grf
- rockchip,rk3228-grf
- rockchip,rk3308-usb2phy-grf
- rockchip,rk3328-usb2phy-grf

View File

@ -3125,6 +3125,8 @@ W: http://wiki.xilinx.com
T: git https://github.com/Xilinx/linux-xlnx.git
F: Documentation/devicetree/bindings/i2c/cdns,i2c-r1p10.yaml
F: Documentation/devicetree/bindings/i2c/xlnx,xps-iic-2.00.a.yaml
F: Documentation/devicetree/bindings/memory-controllers/snps,dw-umctl2-ddrc.yaml
F: Documentation/devicetree/bindings/memory-controllers/xlnx,zynq-ddrc-a05.yaml
F: Documentation/devicetree/bindings/spi/xlnx,zynq-qspi.yaml
F: arch/arm/mach-zynq/
F: drivers/clocksource/timer-cadence-ttc.c
@ -5407,8 +5409,8 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
F: drivers/cpuidle/cpuidle-big_little.c
CPUIDLE DRIVER - ARM EXYNOS
M: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
M: Daniel Lezcano <daniel.lezcano@linaro.org>
R: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
M: Kukjin Kim <kgene@kernel.org>
L: linux-pm@vger.kernel.org
L: linux-samsung-soc@vger.kernel.org
@ -12441,7 +12443,6 @@ F: drivers/power/supply/max77976_charger.c
MAXIM MUIC CHARGER DRIVERS FOR EXYNOS BASED BOARDS
M: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
M: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
L: linux-pm@vger.kernel.org
S: Supported
B: mailto:linux-samsung-soc@vger.kernel.org
@ -12453,7 +12454,6 @@ F: drivers/power/supply/max77693_charger.c
MAXIM PMIC AND MUIC DRIVERS FOR EXYNOS BASED BOARDS
M: Chanwoo Choi <cw00.choi@samsung.com>
M: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
M: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
L: linux-kernel@vger.kernel.org
S: Supported
B: mailto:linux-samsung-soc@vger.kernel.org
@ -16587,14 +16587,6 @@ T: git git://linuxtv.org/media_tree.git
F: drivers/media/usb/pwc/*
F: include/trace/events/pwc.h
PWM FAN DRIVER
M: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
L: linux-hwmon@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/hwmon/pwm-fan.txt
F: Documentation/hwmon/pwm-fan.rst
F: drivers/hwmon/pwm-fan.c
PWM IR Transmitter
M: Sean Young <sean@mess.org>
L: linux-media@vger.kernel.org
@ -18055,7 +18047,6 @@ F: drivers/platform/x86/samsung-laptop.c
SAMSUNG MULTIFUNCTION PMIC DEVICE DRIVERS
M: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
M: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
L: linux-kernel@vger.kernel.org
L: linux-samsung-soc@vger.kernel.org
S: Supported

View File

@ -67,11 +67,7 @@
#if defined(CONFIG_ARCH_SA1100)
.macro loadsp, rb, tmp1, tmp2
mov \rb, #0x80000000 @ physical base address
#ifdef CONFIG_DEBUG_LL_SER3
add \rb, \rb, #0x00050000 @ Ser3
#else
add \rb, \rb, #0x00010000 @ Ser1
#endif
.endm
#else
.macro loadsp, rb, tmp1, tmp2

View File

@ -85,7 +85,7 @@ static int wait_lpc_idle(void __iomem *mbase, unsigned int waitcnt)
ndelay(LPC_NSEC_PERWAIT);
} while (--waitcnt);
return -ETIME;
return -ETIMEDOUT;
}
/*
@ -347,7 +347,7 @@ static int hisi_lpc_acpi_xlat_io_res(struct acpi_device *adev,
unsigned long sys_port;
resource_size_t len = resource_size(res);
sys_port = logic_pio_trans_hwaddr(&host->fwnode, res->start, len);
sys_port = logic_pio_trans_hwaddr(acpi_fwnode_handle(host), res->start, len);
if (sys_port == ~0UL)
return -EFAULT;
@ -472,9 +472,7 @@ static int hisi_lpc_acpi_clear_enumerated(struct acpi_device *adev, void *not_us
struct hisi_lpc_acpi_cell {
const char *hid;
const char *name;
void *pdata;
size_t pdata_size;
const struct platform_device_info *pdevinfo;
};
static void hisi_lpc_acpi_remove(struct device *hostdev)
@ -505,13 +503,29 @@ static int hisi_lpc_acpi_add_child(struct acpi_device *child, void *data)
/* ipmi */
{
.hid = "IPI0001",
.pdevinfo = (struct platform_device_info []) {
{
.parent = hostdev,
.fwnode = acpi_fwnode_handle(child),
.name = "hisi-lpc-ipmi",
.id = PLATFORM_DEVID_AUTO,
.res = res,
.num_res = num_res,
},
},
},
/* 8250-compatible uart */
{
.hid = "HISI1031",
.pdevinfo = (struct platform_device_info []) {
{
.parent = hostdev,
.fwnode = acpi_fwnode_handle(child),
.name = "serial8250",
.pdata = (struct plat_serial8250_port []) {
.id = PLATFORM_DEVID_AUTO,
.res = res,
.num_res = num_res,
.data = (struct plat_serial8250_port []) {
{
.iobase = res->start,
.uartclk = 1843200,
@ -520,13 +534,14 @@ static int hisi_lpc_acpi_add_child(struct acpi_device *child, void *data)
},
{}
},
.pdata_size = 2 *
sizeof(struct plat_serial8250_port),
.size_data = 2 * sizeof(struct plat_serial8250_port),
},
},
},
{}
};
for (; cell && cell->name; cell++) {
for (; cell && cell->hid; cell++) {
if (!strcmp(cell->hid, hid)) {
found = true;
break;
@ -540,31 +555,12 @@ static int hisi_lpc_acpi_add_child(struct acpi_device *child, void *data)
return 0;
}
pdev = platform_device_alloc(cell->name, PLATFORM_DEVID_AUTO);
if (!pdev)
return -ENOMEM;
pdev->dev.parent = hostdev;
ACPI_COMPANION_SET(&pdev->dev, child);
ret = platform_device_add_resources(pdev, res, num_res);
if (ret)
goto fail;
ret = platform_device_add_data(pdev, cell->pdata, cell->pdata_size);
if (ret)
goto fail;
ret = platform_device_add(pdev);
if (ret)
goto fail;
pdev = platform_device_register_full(cell->pdevinfo);
if (IS_ERR(pdev))
return PTR_ERR(pdev);
acpi_device_set_enumerated(child);
return 0;
fail:
platform_device_put(pdev);
return ret;
}
/*
@ -589,11 +585,6 @@ static int hisi_lpc_acpi_probe(struct device *hostdev)
return ret;
}
static const struct acpi_device_id hisi_lpc_acpi_match[] = {
{"HISI0191"},
{}
};
#else
static int hisi_lpc_acpi_probe(struct device *dev)
{
@ -615,11 +606,9 @@ static void hisi_lpc_acpi_remove(struct device *hostdev)
static int hisi_lpc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct acpi_device *acpi_device = ACPI_COMPANION(dev);
struct logic_pio_hwaddr *range;
struct hisi_lpc_dev *lpcdev;
resource_size_t io_end;
struct resource *res;
int ret;
lpcdev = devm_kzalloc(dev, sizeof(*lpcdev), GFP_KERNEL);
@ -628,8 +617,7 @@ static int hisi_lpc_probe(struct platform_device *pdev)
spin_lock_init(&lpcdev->cycle_lock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
lpcdev->membase = devm_ioremap_resource(dev, res);
lpcdev->membase = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(lpcdev->membase))
return PTR_ERR(lpcdev->membase);
@ -637,7 +625,7 @@ static int hisi_lpc_probe(struct platform_device *pdev)
if (!range)
return -ENOMEM;
range->fwnode = dev->fwnode;
range->fwnode = dev_fwnode(dev);
range->flags = LOGIC_PIO_INDIRECT;
range->size = PIO_INDIRECT_SIZE;
range->hostdata = lpcdev;
@ -651,7 +639,7 @@ static int hisi_lpc_probe(struct platform_device *pdev)
}
/* register the LPC host PIO resources */
if (acpi_device)
if (is_acpi_device_node(range->fwnode))
ret = hisi_lpc_acpi_probe(dev);
else
ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
@ -672,11 +660,10 @@ static int hisi_lpc_probe(struct platform_device *pdev)
static int hisi_lpc_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct acpi_device *acpi_device = ACPI_COMPANION(dev);
struct hisi_lpc_dev *lpcdev = dev_get_drvdata(dev);
struct logic_pio_hwaddr *range = lpcdev->io_host;
if (acpi_device)
if (is_acpi_device_node(range->fwnode))
hisi_lpc_acpi_remove(dev);
else
of_platform_depopulate(dev);
@ -692,11 +679,16 @@ static const struct of_device_id hisi_lpc_of_match[] = {
{}
};
static const struct acpi_device_id hisi_lpc_acpi_match[] = {
{"HISI0191"},
{}
};
static struct platform_driver hisi_lpc_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = hisi_lpc_of_match,
.acpi_match_table = ACPI_PTR(hisi_lpc_acpi_match),
.acpi_match_table = hisi_lpc_acpi_match,
},
.probe = hisi_lpc_probe,
.remove = hisi_lpc_remove,

View File

@ -124,10 +124,8 @@ static bool psci_pd_try_set_osi_mode(void)
return false;
ret = psci_set_osi_mode(true);
if (ret) {
pr_warn("failed to enable OSI mode: %d\n", ret);
if (ret)
return false;
}
return true;
}

View File

@ -167,7 +167,8 @@ bool ffa_device_is_valid(struct ffa_device *ffa_dev)
return valid;
}
struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id)
struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id,
const struct ffa_ops *ops)
{
int ret;
struct device *dev;
@ -183,6 +184,7 @@ struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id)
dev_set_name(&ffa_dev->dev, "arm-ffa-%04x", vm_id);
ffa_dev->vm_id = vm_id;
ffa_dev->ops = ops;
uuid_copy(&ffa_dev->uuid, uuid);
ret = device_register(&ffa_dev->dev);

View File

@ -163,6 +163,7 @@ struct ffa_drv_info {
struct mutex tx_lock; /* lock to protect Tx buffer */
void *rx_buffer;
void *tx_buffer;
bool mem_ops_native;
};
static struct ffa_drv_info *drv_info;
@ -263,18 +264,24 @@ static int ffa_rxtx_unmap(u16 vm_id)
return 0;
}
#define PARTITION_INFO_GET_RETURN_COUNT_ONLY BIT(0)
/* buffer must be sizeof(struct ffa_partition_info) * num_partitions */
static int
__ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
struct ffa_partition_info *buffer, int num_partitions)
{
int count;
int idx, count, flags = 0, sz, buf_sz;
ffa_value_t partition_info;
if (!buffer || !num_partitions) /* Just get the count for now */
flags = PARTITION_INFO_GET_RETURN_COUNT_ONLY;
mutex_lock(&drv_info->rx_lock);
invoke_ffa_fn((ffa_value_t){
.a0 = FFA_PARTITION_INFO_GET,
.a1 = uuid0, .a2 = uuid1, .a3 = uuid2, .a4 = uuid3,
.a5 = flags,
}, &partition_info);
if (partition_info.a0 == FFA_ERROR) {
@ -284,8 +291,19 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
count = partition_info.a2;
if (drv_info->version > FFA_VERSION_1_0) {
buf_sz = sz = partition_info.a3;
if (sz > sizeof(*buffer))
buf_sz = sizeof(*buffer);
} else {
/* FFA_VERSION_1_0 lacks size in the response */
buf_sz = sz = 8;
}
if (buffer && count <= num_partitions)
memcpy(buffer, drv_info->rx_buffer, sizeof(*buffer) * count);
for (idx = 0; idx < count; idx++)
memcpy(buffer + idx, drv_info->rx_buffer + idx * sz,
buf_sz);
ffa_rx_release();
@ -571,6 +589,39 @@ static int ffa_memory_reclaim(u64 g_handle, u32 flags)
return 0;
}
static int ffa_features(u32 func_feat_id, u32 input_props,
u32 *if_props_1, u32 *if_props_2)
{
ffa_value_t id;
if (!ARM_SMCCC_IS_FAST_CALL(func_feat_id) && input_props) {
pr_err("%s: Invalid Parameters: %x, %x", __func__,
func_feat_id, input_props);
return ffa_to_linux_errno(FFA_RET_INVALID_PARAMETERS);
}
invoke_ffa_fn((ffa_value_t){
.a0 = FFA_FEATURES, .a1 = func_feat_id, .a2 = input_props,
}, &id);
if (id.a0 == FFA_ERROR)
return ffa_to_linux_errno((int)id.a2);
if (if_props_1)
*if_props_1 = id.a2;
if (if_props_2)
*if_props_2 = id.a3;
return 0;
}
static void ffa_set_up_mem_ops_native_flag(void)
{
if (!ffa_features(FFA_FN_NATIVE(MEM_LEND), 0, NULL, NULL) ||
!ffa_features(FFA_FN_NATIVE(MEM_SHARE), 0, NULL, NULL))
drv_info->mem_ops_native = true;
}
static u32 ffa_api_version_get(void)
{
return drv_info->version;
@ -597,11 +648,19 @@ static int ffa_partition_info_get(const char *uuid_str,
return 0;
}
static void ffa_mode_32bit_set(struct ffa_device *dev)
static void _ffa_mode_32bit_set(struct ffa_device *dev)
{
dev->mode_32bit = true;
}
static void ffa_mode_32bit_set(struct ffa_device *dev)
{
if (drv_info->version > FFA_VERSION_1_0)
return;
_ffa_mode_32bit_set(dev);
}
static int ffa_sync_send_receive(struct ffa_device *dev,
struct ffa_send_direct_data *data)
{
@ -609,17 +668,15 @@ static int ffa_sync_send_receive(struct ffa_device *dev,
dev->mode_32bit, data);
}
static int
ffa_memory_share(struct ffa_device *dev, struct ffa_mem_ops_args *args)
static int ffa_memory_share(struct ffa_mem_ops_args *args)
{
if (dev->mode_32bit)
return ffa_memory_ops(FFA_MEM_SHARE, args);
if (drv_info->mem_ops_native)
return ffa_memory_ops(FFA_FN_NATIVE(MEM_SHARE), args);
return ffa_memory_ops(FFA_MEM_SHARE, args);
}
static int
ffa_memory_lend(struct ffa_device *dev, struct ffa_mem_ops_args *args)
static int ffa_memory_lend(struct ffa_mem_ops_args *args)
{
/* Note that upon a successful MEM_LEND request the caller
* must ensure that the memory region specified is not accessed
@ -628,36 +685,47 @@ ffa_memory_lend(struct ffa_device *dev, struct ffa_mem_ops_args *args)
* however on systems without a hypervisor the responsibility
* falls to the calling kernel driver to prevent access.
*/
if (dev->mode_32bit)
return ffa_memory_ops(FFA_MEM_LEND, args);
if (drv_info->mem_ops_native)
return ffa_memory_ops(FFA_FN_NATIVE(MEM_LEND), args);
return ffa_memory_ops(FFA_MEM_LEND, args);
}
static const struct ffa_dev_ops ffa_ops = {
static const struct ffa_info_ops ffa_drv_info_ops = {
.api_version_get = ffa_api_version_get,
.partition_info_get = ffa_partition_info_get,
};
static const struct ffa_msg_ops ffa_drv_msg_ops = {
.mode_32bit_set = ffa_mode_32bit_set,
.sync_send_receive = ffa_sync_send_receive,
};
static const struct ffa_mem_ops ffa_drv_mem_ops = {
.memory_reclaim = ffa_memory_reclaim,
.memory_share = ffa_memory_share,
.memory_lend = ffa_memory_lend,
};
const struct ffa_dev_ops *ffa_dev_ops_get(struct ffa_device *dev)
{
if (ffa_device_is_valid(dev))
return &ffa_ops;
return NULL;
}
EXPORT_SYMBOL_GPL(ffa_dev_ops_get);
static const struct ffa_ops ffa_drv_ops = {
.info_ops = &ffa_drv_info_ops,
.msg_ops = &ffa_drv_msg_ops,
.mem_ops = &ffa_drv_mem_ops,
};
void ffa_device_match_uuid(struct ffa_device *ffa_dev, const uuid_t *uuid)
{
int count, idx;
struct ffa_partition_info *pbuf, *tpbuf;
/*
* FF-A v1.1 provides UUID for each partition as part of the discovery
* API, the discovered UUID must be populated in the device's UUID and
* there is no need to copy the same from the driver table.
*/
if (drv_info->version > FFA_VERSION_1_0)
return;
count = ffa_partition_probe(uuid, &pbuf);
if (count <= 0)
return;
@ -671,6 +739,7 @@ void ffa_device_match_uuid(struct ffa_device *ffa_dev, const uuid_t *uuid)
static void ffa_setup_partitions(void)
{
int count, idx;
uuid_t uuid;
struct ffa_device *ffa_dev;
struct ffa_partition_info *pbuf, *tpbuf;
@ -681,19 +750,24 @@ static void ffa_setup_partitions(void)
}
for (idx = 0, tpbuf = pbuf; idx < count; idx++, tpbuf++) {
/* Note that the &uuid_null parameter will require
import_uuid(&uuid, (u8 *)tpbuf->uuid);
/* Note that if the UUID will be uuid_null, that will require
* ffa_device_match() to find the UUID of this partition id
* with help of ffa_device_match_uuid(). Once the FF-A spec
* is updated to provide correct UUID here for each partition
* as part of the discovery API, we need to pass the
* discovered UUID here instead.
* with help of ffa_device_match_uuid(). FF-A v1.1 and above
* provides UUID here for each partition as part of the
* discovery API and the same is passed.
*/
ffa_dev = ffa_device_register(&uuid_null, tpbuf->id);
ffa_dev = ffa_device_register(&uuid, tpbuf->id, &ffa_drv_ops);
if (!ffa_dev) {
pr_err("%s: failed to register partition ID 0x%x\n",
__func__, tpbuf->id);
continue;
}
if (drv_info->version > FFA_VERSION_1_0 &&
!(tpbuf->properties & FFA_PARTITION_AARCH64_EXEC))
_ffa_mode_32bit_set(ffa_dev);
}
kfree(pbuf);
}
@ -751,6 +825,8 @@ static int __init ffa_init(void)
ffa_setup_partitions();
ffa_set_up_mem_ops_native_flag();
return 0;
free_pages:
if (drv_info->tx_buffer)

View File

@ -9,6 +9,7 @@
#include <linux/acpi.h>
#include <linux/arm-smccc.h>
#include <linux/cpuidle.h>
#include <linux/debugfs.h>
#include <linux/errno.h>
#include <linux/linkage.h>
#include <linux/of.h>
@ -163,6 +164,8 @@ int psci_set_osi_mode(bool enable)
PSCI_1_0_SUSPEND_MODE_PC;
err = invoke_psci_fn(PSCI_1_0_FN_SET_SUSPEND_MODE, suspend_mode, 0, 0);
if (err < 0)
pr_warn("failed to set %s mode: %d\n", enable ? "OSI" : "PC", err);
return psci_to_linux_errno(err);
}
@ -324,12 +327,125 @@ static void psci_sys_poweroff(void)
invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
}
static int __init psci_features(u32 psci_func_id)
static int psci_features(u32 psci_func_id)
{
return invoke_psci_fn(PSCI_1_0_FN_PSCI_FEATURES,
psci_func_id, 0, 0);
}
#ifdef CONFIG_DEBUG_FS
#define PSCI_ID(ver, _name) \
{ .fn = PSCI_##ver##_FN_##_name, .name = #_name, }
#define PSCI_ID_NATIVE(ver, _name) \
{ .fn = PSCI_FN_NATIVE(ver, _name), .name = #_name, }
/* A table of all optional functions */
static const struct {
u32 fn;
const char *name;
} psci_fn_ids[] = {
PSCI_ID_NATIVE(0_2, MIGRATE),
PSCI_ID(0_2, MIGRATE_INFO_TYPE),
PSCI_ID_NATIVE(0_2, MIGRATE_INFO_UP_CPU),
PSCI_ID(1_0, CPU_FREEZE),
PSCI_ID_NATIVE(1_0, CPU_DEFAULT_SUSPEND),
PSCI_ID_NATIVE(1_0, NODE_HW_STATE),
PSCI_ID_NATIVE(1_0, SYSTEM_SUSPEND),
PSCI_ID(1_0, SET_SUSPEND_MODE),
PSCI_ID_NATIVE(1_0, STAT_RESIDENCY),
PSCI_ID_NATIVE(1_0, STAT_COUNT),
PSCI_ID_NATIVE(1_1, SYSTEM_RESET2),
PSCI_ID(1_1, MEM_PROTECT),
PSCI_ID_NATIVE(1_1, MEM_PROTECT_CHECK_RANGE),
};
static int psci_debugfs_read(struct seq_file *s, void *data)
{
int feature, type, i;
u32 ver;
ver = psci_ops.get_version();
seq_printf(s, "PSCIv%d.%d\n",
PSCI_VERSION_MAJOR(ver),
PSCI_VERSION_MINOR(ver));
/* PSCI_FEATURES is available only starting from 1.0 */
if (PSCI_VERSION_MAJOR(ver) < 1)
return 0;
feature = psci_features(ARM_SMCCC_VERSION_FUNC_ID);
if (feature != PSCI_RET_NOT_SUPPORTED) {
ver = invoke_psci_fn(ARM_SMCCC_VERSION_FUNC_ID, 0, 0, 0);
seq_printf(s, "SMC Calling Convention v%d.%d\n",
PSCI_VERSION_MAJOR(ver),
PSCI_VERSION_MINOR(ver));
} else {
seq_puts(s, "SMC Calling Convention v1.0 is assumed\n");
}
feature = psci_features(PSCI_FN_NATIVE(0_2, CPU_SUSPEND));
if (feature < 0) {
seq_printf(s, "PSCI_FEATURES(CPU_SUSPEND) error (%d)\n", feature);
} else {
seq_printf(s, "OSI is %ssupported\n",
(feature & BIT(0)) ? "" : "not ");
seq_printf(s, "%s StateID format is used\n",
(feature & BIT(1)) ? "Extended" : "Original");
}
type = psci_ops.migrate_info_type();
if (type == PSCI_0_2_TOS_UP_MIGRATE ||
type == PSCI_0_2_TOS_UP_NO_MIGRATE) {
unsigned long cpuid;
seq_printf(s, "Trusted OS %smigrate capable\n",
type == PSCI_0_2_TOS_UP_NO_MIGRATE ? "not " : "");
cpuid = psci_migrate_info_up_cpu();
seq_printf(s, "Trusted OS resident on physical CPU 0x%lx (#%d)\n",
cpuid, resident_cpu);
} else if (type == PSCI_0_2_TOS_MP) {
seq_puts(s, "Trusted OS migration not required\n");
} else {
if (type != PSCI_RET_NOT_SUPPORTED)
seq_printf(s, "MIGRATE_INFO_TYPE returned unknown type (%d)\n", type);
}
for (i = 0; i < ARRAY_SIZE(psci_fn_ids); i++) {
feature = psci_features(psci_fn_ids[i].fn);
if (feature == PSCI_RET_NOT_SUPPORTED)
continue;
if (feature < 0)
seq_printf(s, "PSCI_FEATURES(%s) error (%d)\n",
psci_fn_ids[i].name, feature);
else
seq_printf(s, "%s is supported\n", psci_fn_ids[i].name);
}
return 0;
}
static int psci_debugfs_open(struct inode *inode, struct file *f)
{
return single_open(f, psci_debugfs_read, NULL);
}
static const struct file_operations psci_debugfs_ops = {
.owner = THIS_MODULE,
.open = psci_debugfs_open,
.release = single_release,
.read = seq_read,
.llseek = seq_lseek
};
static int __init psci_debugfs_init(void)
{
return PTR_ERR_OR_ZERO(debugfs_create_file("psci", 0444, NULL, NULL,
&psci_debugfs_ops));
}
late_initcall(psci_debugfs_init)
#endif
#ifdef CONFIG_CPU_IDLE
static int psci_suspend_finisher(unsigned long state)
{

View File

@ -129,8 +129,6 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
#define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x03
#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x02
extern void __qcom_scm_init(void);
/* common error codes */
#define QCOM_SCM_V2_EBUSY -12
#define QCOM_SCM_ENOMEM -5

View File

@ -377,18 +377,11 @@ static ssize_t bpmp_debug_store(struct file *file, const char __user *buf,
if (!filename)
return -ENOENT;
databuf = kmalloc(count, GFP_KERNEL);
if (!databuf)
return -ENOMEM;
if (copy_from_user(databuf, buf, count)) {
err = -EFAULT;
goto free_ret;
}
databuf = memdup_user(buf, count);
if (IS_ERR(databuf))
return PTR_ERR(databuf);
err = mrq_debug_write(bpmp, filename, databuf, count);
free_ret:
kfree(databuf);
return err ?: count;

View File

@ -488,8 +488,8 @@ config I2C_BCM_KONA
config I2C_BRCMSTB
tristate "BRCM Settop/DSL I2C controller"
depends on ARCH_BCM2835 || ARCH_BCM4908 || ARCH_BCMBCA || \
ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST
depends on ARCH_BCM2835 || ARCH_BCMBCA || ARCH_BRCMSTB || \
BMIPS_GENERIC || COMPILE_TEST
default y
help
If you say yes to this option, support will be included for the

View File

@ -66,6 +66,15 @@ config BRCMSTB_DPFE
for the DRAM's temperature. Slower refresh rate means cooler RAM,
higher refresh rate means hotter RAM.
config BRCMSTB_MEMC
tristate "Broadcom STB MEMC driver"
default ARCH_BRCMSTB
depends on ARCH_BRCMSTB || COMPILE_TEST
help
This driver provides a way to configure the Broadcom STB memory
controller and specifically control the Self Refresh Power Down
(SRPD) inactivity timeout.
config BT1_L2_CTL
bool "Baikal-T1 CM2 L2-RAM Cache Control Block"
depends on MIPS_BAIKAL_T1 || COMPILE_TEST

View File

@ -11,6 +11,7 @@ obj-$(CONFIG_ARM_PL172_MPMC) += pl172.o
obj-$(CONFIG_ATMEL_SDRAMC) += atmel-sdramc.o
obj-$(CONFIG_ATMEL_EBI) += atmel-ebi.o
obj-$(CONFIG_BRCMSTB_DPFE) += brcmstb_dpfe.o
obj-$(CONFIG_BRCMSTB_MEMC) += brcmstb_memc.o
obj-$(CONFIG_BT1_L2_CTL) += bt1-l2-ctl.o
obj-$(CONFIG_TI_AEMIF) += ti-aemif.o
obj-$(CONFIG_TI_EMIF) += emif.o

View File

@ -0,0 +1,301 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* DDR Self-Refresh Power Down (SRPD) support for Broadcom STB SoCs
*
*/
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#define REG_MEMC_CNTRLR_CONFIG 0x00
#define CNTRLR_CONFIG_LPDDR4_SHIFT 5
#define CNTRLR_CONFIG_MASK 0xf
#define REG_MEMC_SRPD_CFG_21 0x20
#define REG_MEMC_SRPD_CFG_20 0x34
#define REG_MEMC_SRPD_CFG_1x 0x3c
#define INACT_COUNT_SHIFT 0
#define INACT_COUNT_MASK 0xffff
#define SRPD_EN_SHIFT 16
struct brcmstb_memc_data {
u32 srpd_offset;
};
struct brcmstb_memc {
struct device *dev;
void __iomem *ddr_ctrl;
unsigned int timeout_cycles;
u32 frequency;
u32 srpd_offset;
};
static int brcmstb_memc_uses_lpddr4(struct brcmstb_memc *memc)
{
void __iomem *config = memc->ddr_ctrl + REG_MEMC_CNTRLR_CONFIG;
u32 reg;
reg = readl_relaxed(config) & CNTRLR_CONFIG_MASK;
return reg == CNTRLR_CONFIG_LPDDR4_SHIFT;
}
static int brcmstb_memc_srpd_config(struct brcmstb_memc *memc,
unsigned int cycles)
{
void __iomem *cfg = memc->ddr_ctrl + memc->srpd_offset;
u32 val;
/* Max timeout supported in HW */
if (cycles > INACT_COUNT_MASK)
return -EINVAL;
memc->timeout_cycles = cycles;
val = (cycles << INACT_COUNT_SHIFT) & INACT_COUNT_MASK;
if (cycles)
val |= BIT(SRPD_EN_SHIFT);
writel_relaxed(val, cfg);
/* Ensure the write is committed to the controller */
(void)readl_relaxed(cfg);
return 0;
}
static ssize_t frequency_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct brcmstb_memc *memc = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", memc->frequency);
}
static ssize_t srpd_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct brcmstb_memc *memc = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", memc->timeout_cycles);
}
static ssize_t srpd_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct brcmstb_memc *memc = dev_get_drvdata(dev);
unsigned int val;
int ret;
/*
* Cannot change the inactivity timeout on LPDDR4 chips because the
* dynamic tuning process will also get affected by the inactivity
* timeout, thus making it non functional.
*/
if (brcmstb_memc_uses_lpddr4(memc))
return -EOPNOTSUPP;
ret = kstrtouint(buf, 10, &val);
if (ret < 0)
return ret;
ret = brcmstb_memc_srpd_config(memc, val);
if (ret)
return ret;
return count;
}
static DEVICE_ATTR_RO(frequency);
static DEVICE_ATTR_RW(srpd);
static struct attribute *dev_attrs[] = {
&dev_attr_frequency.attr,
&dev_attr_srpd.attr,
NULL,
};
static struct attribute_group dev_attr_group = {
.attrs = dev_attrs,
};
static const struct of_device_id brcmstb_memc_of_match[];
static int brcmstb_memc_probe(struct platform_device *pdev)
{
const struct brcmstb_memc_data *memc_data;
const struct of_device_id *of_id;
struct device *dev = &pdev->dev;
struct brcmstb_memc *memc;
int ret;
memc = devm_kzalloc(dev, sizeof(*memc), GFP_KERNEL);
if (!memc)
return -ENOMEM;
dev_set_drvdata(dev, memc);
of_id = of_match_device(brcmstb_memc_of_match, dev);
memc_data = of_id->data;
memc->srpd_offset = memc_data->srpd_offset;
memc->ddr_ctrl = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(memc->ddr_ctrl))
return PTR_ERR(memc->ddr_ctrl);
of_property_read_u32(pdev->dev.of_node, "clock-frequency",
&memc->frequency);
ret = sysfs_create_group(&dev->kobj, &dev_attr_group);
if (ret)
return ret;
return 0;
}
static int brcmstb_memc_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
sysfs_remove_group(&dev->kobj, &dev_attr_group);
return 0;
}
enum brcmstb_memc_hwtype {
BRCMSTB_MEMC_V21,
BRCMSTB_MEMC_V20,
BRCMSTB_MEMC_V1X,
};
static const struct brcmstb_memc_data brcmstb_memc_versions[] = {
{ .srpd_offset = REG_MEMC_SRPD_CFG_21 },
{ .srpd_offset = REG_MEMC_SRPD_CFG_20 },
{ .srpd_offset = REG_MEMC_SRPD_CFG_1x },
};
static const struct of_device_id brcmstb_memc_of_match[] = {
{
.compatible = "brcm,brcmstb-memc-ddr-rev-b.1.x",
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V1X]
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.0",
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V20]
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.1",
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.2",
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.3",
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.5",
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.6",
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.7",
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.8",
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-b.3.0",
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-b.3.1",
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-c.1.0",
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-c.1.1",
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-c.1.2",
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-c.1.3",
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-c.1.4",
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21]
},
/* default to the original offset */
{
.compatible = "brcm,brcmstb-memc-ddr",
.data = &brcmstb_memc_versions[BRCMSTB_MEMC_V1X]
},
{}
};
static int brcmstb_memc_suspend(struct device *dev)
{
struct brcmstb_memc *memc = dev_get_drvdata(dev);
void __iomem *cfg = memc->ddr_ctrl + memc->srpd_offset;
u32 val;
if (memc->timeout_cycles == 0)
return 0;
/*
* Disable SRPD prior to suspending the system since that can
* cause issues with other memory clients managed by the ARM
* trusted firmware to access memory.
*/
val = readl_relaxed(cfg);
val &= ~BIT(SRPD_EN_SHIFT);
writel_relaxed(val, cfg);
/* Ensure the write is committed to the controller */
(void)readl_relaxed(cfg);
return 0;
}
static int brcmstb_memc_resume(struct device *dev)
{
struct brcmstb_memc *memc = dev_get_drvdata(dev);
if (memc->timeout_cycles == 0)
return 0;
return brcmstb_memc_srpd_config(memc, memc->timeout_cycles);
}
static DEFINE_SIMPLE_DEV_PM_OPS(brcmstb_memc_pm_ops, brcmstb_memc_suspend,
brcmstb_memc_resume);
static struct platform_driver brcmstb_memc_driver = {
.probe = brcmstb_memc_probe,
.remove = brcmstb_memc_remove,
.driver = {
.name = "brcmstb_memc",
.of_match_table = brcmstb_memc_of_match,
.pm = pm_ptr(&brcmstb_memc_pm_ops),
},
};
module_platform_driver(brcmstb_memc_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Broadcom");
MODULE_DESCRIPTION("DDR SRPD driver for Broadcom STB chips");

View File

@ -24,11 +24,24 @@
#define EMIF_STAT_CLEAR_BUSY_SFT 16
#define EMIF_CTRL 0x10
#define EMIF_CTRL_CLEAR_EN_SFT 0
#define EMIF_CTRL_CLEAR_EN_MSK GENMASK_ULL(3, 0)
#define EMIF_CTRL_CLEAR_EN_MSK GENMASK_ULL(7, 0)
#define EMIF_POLL_INVL 10000 /* us */
#define EMIF_POLL_TIMEOUT 5000000 /* us */
/*
* The Capability Register replaces the Control Register (at the same
* offset) for EMIF feature revisions > 0. The bitmask that indicates
* the presence of memory channels exists in both the Capability Register
* and Control Register definitions. These can be thought of as a C union.
* The Capability Register definitions are used to check for the existence
* of a memory channel, and the Control Register definitions are used for
* managing the memory-clear functionality in revision 0.
*/
#define EMIF_CAPABILITY_BASE 0x10
#define EMIF_CAPABILITY_CHN_MSK_V0 GENMASK_ULL(3, 0)
#define EMIF_CAPABILITY_CHN_MSK GENMASK_ULL(7, 0)
struct dfl_emif {
struct device *dev;
void __iomem *base;
@ -106,16 +119,30 @@ emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 0);
emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 1);
emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 2);
emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 3);
emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 4);
emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 5);
emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 6);
emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 7);
emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 0);
emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 1);
emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 2);
emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 3);
emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 4);
emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 5);
emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 6);
emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 7);
emif_clear_attr(0);
emif_clear_attr(1);
emif_clear_attr(2);
emif_clear_attr(3);
emif_clear_attr(4);
emif_clear_attr(5);
emif_clear_attr(6);
emif_clear_attr(7);
static struct attribute *dfl_emif_attrs[] = {
&emif_attr_inf0_init_done.attr.attr,
@ -134,6 +161,22 @@ static struct attribute *dfl_emif_attrs[] = {
&emif_attr_inf3_cal_fail.attr.attr,
&emif_attr_inf3_clear.attr.attr,
&emif_attr_inf4_init_done.attr.attr,
&emif_attr_inf4_cal_fail.attr.attr,
&emif_attr_inf4_clear.attr.attr,
&emif_attr_inf5_init_done.attr.attr,
&emif_attr_inf5_cal_fail.attr.attr,
&emif_attr_inf5_clear.attr.attr,
&emif_attr_inf6_init_done.attr.attr,
&emif_attr_inf6_cal_fail.attr.attr,
&emif_attr_inf6_clear.attr.attr,
&emif_attr_inf7_init_done.attr.attr,
&emif_attr_inf7_cal_fail.attr.attr,
&emif_attr_inf7_clear.attr.attr,
NULL,
};
@ -143,15 +186,24 @@ static umode_t dfl_emif_visible(struct kobject *kobj,
struct dfl_emif *de = dev_get_drvdata(kobj_to_dev(kobj));
struct emif_attr *eattr = container_of(attr, struct emif_attr,
attr.attr);
struct dfl_device *ddev = to_dfl_dev(de->dev);
u64 val;
/*
* This device supports upto 4 memory interfaces, but not all
* This device supports up to 8 memory interfaces, but not all
* interfaces are used on different platforms. The read out value of
* CLEAN_EN field (which is a bitmap) could tell how many interfaces
* are available.
* CAPABILITY_CHN_MSK field (which is a bitmap) indicates which
* interfaces are available.
*/
val = FIELD_GET(EMIF_CTRL_CLEAR_EN_MSK, readq(de->base + EMIF_CTRL));
if (ddev->revision > 0 && strstr(attr->name, "_clear"))
return 0;
if (ddev->revision == 0)
val = FIELD_GET(EMIF_CAPABILITY_CHN_MSK_V0,
readq(de->base + EMIF_CAPABILITY_BASE));
else
val = FIELD_GET(EMIF_CAPABILITY_CHN_MSK,
readq(de->base + EMIF_CAPABILITY_BASE));
return (val & BIT_ULL(eattr->index)) ? attr->mode : 0;
}

View File

@ -3,6 +3,7 @@
* Copyright (c) 2015-2016 MediaTek Inc.
* Author: Yong Wu <yong.wu@mediatek.com>
*/
#include <linux/arm-smccc.h>
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/device.h>
@ -14,6 +15,7 @@
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/soc/mediatek/mtk_sip_svc.h>
#include <soc/mediatek/smi.h>
#include <dt-bindings/memory/mt2701-larb-port.h>
#include <dt-bindings/memory/mtk-memory-port.h>
@ -89,6 +91,7 @@
#define MTK_SMI_FLAG_THRT_UPDATE BIT(0)
#define MTK_SMI_FLAG_SW_FLAG BIT(1)
#define MTK_SMI_FLAG_SLEEP_CTL BIT(2)
#define MTK_SMI_FLAG_CFG_PORT_SEC_CTL BIT(3)
#define MTK_SMI_CAPS(flags, _x) (!!((flags) & (_x)))
struct mtk_smi_reg_pair {
@ -127,7 +130,7 @@ struct mtk_smi_common_plat {
struct mtk_smi_larb_gen {
int port_in_larb[MTK_LARB_NR_MAX + 1];
void (*config_port)(struct device *dev);
int (*config_port)(struct device *dev);
unsigned int larb_direct_to_common_mask;
unsigned int flags_general;
const u8 (*ostd)[SMI_LARB_PORT_NR_MAX];
@ -185,7 +188,7 @@ static const struct component_ops mtk_smi_larb_component_ops = {
.unbind = mtk_smi_larb_unbind,
};
static void mtk_smi_larb_config_port_gen1(struct device *dev)
static int mtk_smi_larb_config_port_gen1(struct device *dev)
{
struct mtk_smi_larb *larb = dev_get_drvdata(dev);
const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen;
@ -214,31 +217,35 @@ static void mtk_smi_larb_config_port_gen1(struct device *dev)
common->smi_ao_base
+ REG_SMI_SECUR_CON_ADDR(m4u_port_id));
}
return 0;
}
static void mtk_smi_larb_config_port_mt8167(struct device *dev)
static int mtk_smi_larb_config_port_mt8167(struct device *dev)
{
struct mtk_smi_larb *larb = dev_get_drvdata(dev);
writel(*larb->mmu, larb->base + MT8167_SMI_LARB_MMU_EN);
return 0;
}
static void mtk_smi_larb_config_port_mt8173(struct device *dev)
static int mtk_smi_larb_config_port_mt8173(struct device *dev)
{
struct mtk_smi_larb *larb = dev_get_drvdata(dev);
writel(*larb->mmu, larb->base + MT8173_SMI_LARB_MMU_EN);
return 0;
}
static void mtk_smi_larb_config_port_gen2_general(struct device *dev)
static int mtk_smi_larb_config_port_gen2_general(struct device *dev)
{
struct mtk_smi_larb *larb = dev_get_drvdata(dev);
u32 reg, flags_general = larb->larb_gen->flags_general;
const u8 *larbostd = larb->larb_gen->ostd ? larb->larb_gen->ostd[larb->larbid] : NULL;
struct arm_smccc_res res;
int i;
if (BIT(larb->larbid) & larb->larb_gen->larb_direct_to_common_mask)
return;
return 0;
if (MTK_SMI_CAPS(flags_general, MTK_SMI_FLAG_THRT_UPDATE)) {
reg = readl_relaxed(larb->base + SMI_LARB_CMD_THRT_CON);
@ -253,14 +260,78 @@ static void mtk_smi_larb_config_port_gen2_general(struct device *dev)
for (i = 0; i < SMI_LARB_PORT_NR_MAX && larbostd && !!larbostd[i]; i++)
writel_relaxed(larbostd[i], larb->base + SMI_LARB_OSTDL_PORTx(i));
/*
* When mmu_en bits are in security world, the bank_sel still is in the
* LARB_NONSEC_CON below. And the mmu_en bits of LARB_NONSEC_CON have no
* effect in this case.
*/
if (MTK_SMI_CAPS(flags_general, MTK_SMI_FLAG_CFG_PORT_SEC_CTL)) {
arm_smccc_smc(MTK_SIP_KERNEL_IOMMU_CONTROL, IOMMU_ATF_CMD_CONFIG_SMI_LARB,
larb->larbid, *larb->mmu, 0, 0, 0, 0, &res);
if (res.a0 != 0) {
dev_err(dev, "Enable iommu fail, ret %ld\n", res.a0);
return -EINVAL;
}
}
for_each_set_bit(i, (unsigned long *)larb->mmu, 32) {
reg = readl_relaxed(larb->base + SMI_LARB_NONSEC_CON(i));
reg |= F_MMU_EN;
reg |= BANK_SEL(larb->bank[i]);
writel(reg, larb->base + SMI_LARB_NONSEC_CON(i));
}
return 0;
}
static const u8 mtk_smi_larb_mt8188_ostd[][SMI_LARB_PORT_NR_MAX] = {
[0] = {0x02, 0x18, 0x22, 0x22, 0x01, 0x02, 0x0a,},
[1] = {0x12, 0x02, 0x14, 0x14, 0x01, 0x18, 0x0a,},
[2] = {0x12, 0x12, 0x12, 0x12, 0x0a,},
[3] = {0x12, 0x12, 0x12, 0x12, 0x28, 0x28, 0x0a,},
[4] = {0x06, 0x01, 0x17, 0x06, 0x0a, 0x07, 0x07,},
[5] = {0x02, 0x01, 0x04, 0x02, 0x06, 0x01, 0x06, 0x0a,},
[6] = {0x06, 0x01, 0x06, 0x0a,},
[7] = {0x0c, 0x0c, 0x12,},
[8] = {0x0c, 0x01, 0x0a, 0x05, 0x02, 0x03, 0x01, 0x01, 0x14, 0x14,
0x0a, 0x14, 0x1e, 0x01, 0x0c, 0x0a, 0x05, 0x02, 0x02, 0x05,
0x03, 0x01, 0x1e, 0x01, 0x05,},
[9] = {0x1e, 0x01, 0x0a, 0x0a, 0x01, 0x01, 0x03, 0x1e, 0x1e, 0x10,
0x07, 0x01, 0x0a, 0x06, 0x03, 0x03, 0x0e, 0x01, 0x04, 0x28,},
[10] = {0x03, 0x20, 0x01, 0x20, 0x01, 0x01, 0x14, 0x0a, 0x0a, 0x0c,
0x0a, 0x05, 0x02, 0x03, 0x02, 0x14, 0x0a, 0x0a, 0x14, 0x14,
0x14, 0x01, 0x01, 0x14, 0x1e, 0x01, 0x05, 0x03, 0x02, 0x28,},
[11] = {0x03, 0x20, 0x01, 0x20, 0x01, 0x01, 0x14, 0x0a, 0x0a, 0x0c,
0x0a, 0x05, 0x02, 0x03, 0x02, 0x14, 0x0a, 0x0a, 0x14, 0x14,
0x14, 0x01, 0x01, 0x14, 0x1e, 0x01, 0x05, 0x03, 0x02, 0x28,},
[12] = {0x03, 0x20, 0x01, 0x20, 0x01, 0x01, 0x14, 0x0a, 0x0a, 0x0c,
0x0a, 0x05, 0x02, 0x03, 0x02, 0x14, 0x0a, 0x0a, 0x14, 0x14,
0x14, 0x01, 0x01, 0x14, 0x1e, 0x01, 0x05, 0x03, 0x02, 0x28,},
[13] = {0x07, 0x02, 0x04, 0x02, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x07, 0x02, 0x04, 0x02, 0x05, 0x05,},
[14] = {0x02, 0x02, 0x0c, 0x0c, 0x0c, 0x0c, 0x01, 0x01, 0x02, 0x02,
0x02, 0x02, 0x0c, 0x0c, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x01, 0x01,},
[15] = {0x0c, 0x0c, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x0c, 0x0c,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02,
0x0c, 0x01, 0x01,},
[16] = {0x28, 0x28, 0x03, 0x01, 0x01, 0x03, 0x14, 0x14, 0x0a, 0x0d,
0x03, 0x05, 0x0e, 0x01, 0x01, 0x05, 0x06, 0x0d, 0x01,},
[17] = {0x28, 0x02, 0x02, 0x12, 0x02, 0x12, 0x10, 0x02, 0x02, 0x0a,
0x12, 0x02, 0x02, 0x0a, 0x16, 0x02, 0x04,},
[18] = {0x28, 0x02, 0x02, 0x12, 0x02, 0x12, 0x10, 0x02, 0x02, 0x0a,
0x12, 0x02, 0x02, 0x0a, 0x16, 0x02, 0x04,},
[19] = {0x1a, 0x0e, 0x0a, 0x0a, 0x0c, 0x0e, 0x10,},
[20] = {0x1a, 0x0e, 0x0a, 0x0a, 0x0c, 0x0e, 0x10,},
[21] = {0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x01,
0x01, 0x01, 0x04, 0x0a, 0x06, 0x01, 0x01, 0x01, 0x0a, 0x06,
0x01, 0x01, 0x05, 0x03, 0x03, 0x04, 0x01,},
[22] = {0x28, 0x19, 0x0c, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04,
0x01,},
[23] = {0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x18, 0x01, 0x01,},
[24] = {0x12, 0x06, 0x12, 0x06,},
[25] = {0x01},
};
static const u8 mtk_smi_larb_mt8195_ostd[][SMI_LARB_PORT_NR_MAX] = {
[0] = {0x0a, 0xc, 0x22, 0x22, 0x01, 0x0a,}, /* larb0 */
[1] = {0x0a, 0xc, 0x22, 0x22, 0x01, 0x0a,}, /* larb1 */
@ -347,6 +418,13 @@ static const struct mtk_smi_larb_gen mtk_smi_larb_mt8186 = {
.flags_general = MTK_SMI_FLAG_SLEEP_CTL,
};
static const struct mtk_smi_larb_gen mtk_smi_larb_mt8188 = {
.config_port = mtk_smi_larb_config_port_gen2_general,
.flags_general = MTK_SMI_FLAG_THRT_UPDATE | MTK_SMI_FLAG_SW_FLAG |
MTK_SMI_FLAG_SLEEP_CTL | MTK_SMI_FLAG_CFG_PORT_SEC_CTL,
.ostd = mtk_smi_larb_mt8188_ostd,
};
static const struct mtk_smi_larb_gen mtk_smi_larb_mt8192 = {
.config_port = mtk_smi_larb_config_port_gen2_general,
};
@ -367,6 +445,7 @@ static const struct of_device_id mtk_smi_larb_of_ids[] = {
{.compatible = "mediatek,mt8173-smi-larb", .data = &mtk_smi_larb_mt8173},
{.compatible = "mediatek,mt8183-smi-larb", .data = &mtk_smi_larb_mt8183},
{.compatible = "mediatek,mt8186-smi-larb", .data = &mtk_smi_larb_mt8186},
{.compatible = "mediatek,mt8188-smi-larb", .data = &mtk_smi_larb_mt8188},
{.compatible = "mediatek,mt8192-smi-larb", .data = &mtk_smi_larb_mt8192},
{.compatible = "mediatek,mt8195-smi-larb", .data = &mtk_smi_larb_mt8195},
{}
@ -511,9 +590,7 @@ static int __maybe_unused mtk_smi_larb_resume(struct device *dev)
mtk_smi_larb_sleep_ctrl_disable(larb);
/* Configure the basic setting for this larb */
larb_gen->config_port(dev);
return 0;
return larb_gen->config_port(dev);
}
static int __maybe_unused mtk_smi_larb_suspend(struct device *dev)
@ -597,6 +674,18 @@ static const struct mtk_smi_common_plat mtk_smi_common_mt8186 = {
.bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(4) | F_MMU1_LARB(7),
};
static const struct mtk_smi_common_plat mtk_smi_common_mt8188_vdo = {
.type = MTK_SMI_GEN2,
.bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(5) | F_MMU1_LARB(7),
.init = mtk_smi_common_mt8195_init,
};
static const struct mtk_smi_common_plat mtk_smi_common_mt8188_vpp = {
.type = MTK_SMI_GEN2,
.bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(7),
.init = mtk_smi_common_mt8195_init,
};
static const struct mtk_smi_common_plat mtk_smi_common_mt8192 = {
.type = MTK_SMI_GEN2,
.has_gals = true,
@ -633,6 +722,8 @@ static const struct of_device_id mtk_smi_common_of_ids[] = {
{.compatible = "mediatek,mt8173-smi-common", .data = &mtk_smi_common_gen2},
{.compatible = "mediatek,mt8183-smi-common", .data = &mtk_smi_common_mt8183},
{.compatible = "mediatek,mt8186-smi-common", .data = &mtk_smi_common_mt8186},
{.compatible = "mediatek,mt8188-smi-common-vdo", .data = &mtk_smi_common_mt8188_vdo},
{.compatible = "mediatek,mt8188-smi-common-vpp", .data = &mtk_smi_common_mt8188_vpp},
{.compatible = "mediatek,mt8192-smi-common", .data = &mtk_smi_common_mt8192},
{.compatible = "mediatek,mt8195-smi-common-vdo", .data = &mtk_smi_common_mt8195_vdo},
{.compatible = "mediatek,mt8195-smi-common-vpp", .data = &mtk_smi_common_mt8195_vpp},

View File

@ -134,6 +134,7 @@ const struct lpddr2_timings *of_get_ddr_timings(struct device_node *np_ddr,
for_each_child_of_node(np_ddr, np_tim) {
if (of_device_is_compatible(np_tim, tim_compat)) {
if (of_do_get_timings(np_tim, &timings[i])) {
of_node_put(np_tim);
devm_kfree(dev, timings);
goto default_timings;
}
@ -284,6 +285,7 @@ const struct lpddr3_timings
if (of_device_is_compatible(np_tim, tim_compat)) {
if (of_lpddr3_do_get_timings(np_tim, &timings[i])) {
devm_kfree(dev, timings);
of_node_put(np_tim);
goto default_timings;
}
i++;

View File

@ -122,6 +122,7 @@ static int pl353_smc_probe(struct amba_device *adev, const struct amba_id *id)
}
of_platform_device_create(child, NULL, &adev->dev);
of_node_put(child);
return 0;

View File

@ -69,8 +69,8 @@ config MTD_OF_PARTS
config MTD_OF_PARTS_BCM4908
bool "BCM4908 partitioning support"
depends on MTD_OF_PARTS && (ARCH_BCM4908 || COMPILE_TEST)
default ARCH_BCM4908
depends on MTD_OF_PARTS && (ARCH_BCMBCA || COMPILE_TEST)
default ARCH_BCMBCA
help
This provides partitions parser for BCM4908 family devices
that can have multiple "firmware" partitions. It takes care of
@ -78,7 +78,7 @@ config MTD_OF_PARTS_BCM4908
config MTD_OF_PARTS_LINKSYS_NS
bool "Linksys Northstar partitioning support"
depends on MTD_OF_PARTS && (ARCH_BCM_5301X || ARCH_BCM4908 || COMPILE_TEST)
depends on MTD_OF_PARTS && (ARCH_BCM_5301X || ARCH_BCMBCA || COMPILE_TEST)
default ARCH_BCM_5301X
help
This provides partitions parser for Linksys devices based on Broadcom

View File

@ -53,8 +53,8 @@ config B44_PCI
config BCM4908_ENET
tristate "Broadcom BCM4908 internal mac support"
depends on ARCH_BCM4908 || COMPILE_TEST
default y if ARCH_BCM4908
depends on ARCH_BCMBCA || COMPILE_TEST
default y if ARCH_BCMBCA
help
This driver supports Ethernet controller integrated into Broadcom
BCM4908 family SoCs.

View File

@ -274,7 +274,7 @@ config VMD
config PCIE_BRCMSTB
tristate "Broadcom Brcmstb PCIe host controller"
depends on ARCH_BRCMSTB || ARCH_BCM2835 || ARCH_BCM4908 || \
depends on ARCH_BRCMSTB || ARCH_BCM2835 || ARCH_BCMBCA || \
BMIPS_GENERIC || COMPILE_TEST
depends on OF
depends on PCI_MSI_IRQ_DOMAIN

View File

@ -93,11 +93,11 @@ config PHY_BRCM_SATA
config PHY_BRCM_USB
tristate "Broadcom STB USB PHY driver"
depends on ARCH_BCM4908 || ARCH_BRCMSTB || COMPILE_TEST
depends on ARCH_BCMBCA || ARCH_BRCMSTB || COMPILE_TEST
depends on OF
select GENERIC_PHY
select SOC_BRCMSTB if ARCH_BRCMSTB
default ARCH_BCM4908 || ARCH_BRCMSTB
default ARCH_BCMBCA || ARCH_BRCMSTB
help
Enable this to support the Broadcom STB USB PHY.
This driver is required by the USB XHCI, EHCI and OHCI

View File

@ -31,13 +31,13 @@ config PINCTRL_BCM2835
config PINCTRL_BCM4908
tristate "Broadcom BCM4908 pinmux driver"
depends on OF && (ARCH_BCM4908 || COMPILE_TEST)
depends on OF && (ARCH_BCMBCA || COMPILE_TEST)
select PINMUX
select PINCONF
select GENERIC_PINCONF
select GENERIC_PINCTRL_GROUPS
select GENERIC_PINMUX_FUNCTIONS
default ARCH_BCM4908
default ARCH_BCMBCA
help
Driver for BCM4908 family SoCs with integrated pin controller.

View File

@ -201,7 +201,7 @@ config RESET_SCMI
config RESET_SIMPLE
bool "Simple Reset Controller Driver" if COMPILE_TEST || EXPERT
default ARCH_ASPEED || ARCH_BCM4908 || ARCH_BITMAIN || ARCH_REALTEK || ARCH_STM32 || (ARCH_INTEL_SOCFPGA && ARM64) || ARCH_SUNXI || ARC
default ARCH_ASPEED || ARCH_BCMBCA || ARCH_BITMAIN || ARCH_REALTEK || ARCH_STM32 || (ARCH_INTEL_SOCFPGA && ARM64) || ARCH_SUNXI || ARC
depends on HAS_IOMEM
help
This enables a simple reset controller driver for reset lines that

View File

@ -469,6 +469,7 @@ static int meson_ee_pwrc_probe(struct platform_device *pdev)
{
const struct meson_ee_pwrc_domain_data *match;
struct regmap *regmap_ao, *regmap_hhi;
struct device_node *parent_np;
struct meson_ee_pwrc *pwrc;
int i, ret;
@ -495,7 +496,9 @@ static int meson_ee_pwrc_probe(struct platform_device *pdev)
pwrc->xlate.num_domains = match->count;
regmap_hhi = syscon_node_to_regmap(of_get_parent(pdev->dev.of_node));
parent_np = of_get_parent(pdev->dev.of_node);
regmap_hhi = syscon_node_to_regmap(parent_np);
of_node_put(parent_np);
if (IS_ERR(regmap_hhi)) {
dev_err(&pdev->dev, "failed to get HHI regmap\n");
return PTR_ERR(regmap_hhi);

View File

@ -273,6 +273,7 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
const struct meson_gx_pwrc_vpu *vpu_pd_match;
struct regmap *regmap_ao, *regmap_hhi;
struct meson_gx_pwrc_vpu *vpu_pd;
struct device_node *parent_np;
struct reset_control *rstc;
struct clk *vpu_clk;
struct clk *vapb_clk;
@ -291,7 +292,9 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
memcpy(vpu_pd, vpu_pd_match, sizeof(*vpu_pd));
regmap_ao = syscon_node_to_regmap(of_get_parent(pdev->dev.of_node));
parent_np = of_get_parent(pdev->dev.of_node);
regmap_ao = syscon_node_to_regmap(parent_np);
of_node_put(parent_np);
if (IS_ERR(regmap_ao)) {
dev_err(&pdev->dev, "failed to get regmap\n");
return PTR_ERR(regmap_ao);

View File

@ -660,6 +660,12 @@ int apple_rtkit_send_message_wait(struct apple_rtkit *rtk, u8 ep, u64 message,
}
EXPORT_SYMBOL_GPL(apple_rtkit_send_message_wait);
int apple_rtkit_poll(struct apple_rtkit *rtk)
{
return mbox_client_peek_data(rtk->mbox_chan);
}
EXPORT_SYMBOL_GPL(apple_rtkit_poll);
int apple_rtkit_start_ep(struct apple_rtkit *rtk, u8 endpoint)
{
u64 msg;

View File

@ -13,8 +13,8 @@ endif # SOC_BCM63XX
config BCM_PMB
bool "Broadcom PMB (Power Management Bus) driver"
depends on ARCH_BCM4908 || (COMPILE_TEST && OF)
default ARCH_BCM4908
depends on ARCH_BCMBCA || (COMPILE_TEST && OF)
default ARCH_BCMBCA
select PM_GENERIC_DOMAINS if PM
help
This enables support for the Broadcom's PMB (Power Management Bus) that

View File

@ -25,7 +25,6 @@
#include <linux/kernel.h>
#include <linux/memblock.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/panic_notifier.h>
@ -664,7 +663,20 @@ static void __iomem *brcmstb_ioremap_match(const struct of_device_id *matches,
return of_io_request_and_map(dn, index, dn->full_name);
}
/*
* The AON is a small domain in the SoC that can retain its state across
* various system wide sleep states and specific reset conditions; the
* AON DATA RAM is a small RAM of a few words (< 1KB) which can store
* persistent information across such events.
*
* The purpose of the below panic notifier is to help with notifying
* the bootloader that a panic occurred and so that it should try its
* best to preserve the DRAM contents holding that buffer for recovery
* by the kernel as opposed to wiping out DRAM clean again.
*
* Reference: comment from Florian Fainelli, at
* https://lore.kernel.org/lkml/781cafb0-8d06-8b56-907a-5175c2da196a@gmail.com
*/
static int brcmstb_pm_panic_notify(struct notifier_block *nb,
unsigned long action, void *data)
{

View File

@ -20,4 +20,12 @@ config SOC_IMX8M
support, it will provide the SoC info like SoC family,
ID and revision etc.
config SOC_IMX9
tristate "i.MX9 SoC family support"
depends on ARCH_MXC || COMPILE_TEST
default ARCH_MXC && ARM64
select SOC_BUS
help
If you say yes here, you get support for the NXP i.MX9 family
endmenu

View File

@ -7,3 +7,5 @@ obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o
obj-$(CONFIG_SOC_IMX8M) += soc-imx8m.o
obj-$(CONFIG_SOC_IMX8M) += imx8m-blk-ctrl.o
obj-$(CONFIG_SOC_IMX8M) += imx8mp-blk-ctrl.o
obj-$(CONFIG_SOC_IMX9) += imx93-src.o imx93-pd.o
obj-$(CONFIG_SOC_IMX9) += imx93-blk-ctrl.o

View File

@ -5,6 +5,7 @@
*/
#include <linux/device.h>
#include <linux/interconnect.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
@ -37,6 +38,8 @@ struct imx8m_blk_ctrl_domain_data {
const char *name;
const char * const *clk_names;
int num_clks;
const char * const *path_names;
int num_paths;
const char *gpc_name;
u32 rst_mask;
u32 clk_mask;
@ -52,13 +55,16 @@ struct imx8m_blk_ctrl_domain_data {
};
#define DOMAIN_MAX_CLKS 4
#define DOMAIN_MAX_PATHS 4
struct imx8m_blk_ctrl_domain {
struct generic_pm_domain genpd;
const struct imx8m_blk_ctrl_domain_data *data;
struct clk_bulk_data clks[DOMAIN_MAX_CLKS];
struct icc_bulk_data paths[DOMAIN_MAX_PATHS];
struct device *power_dev;
struct imx8m_blk_ctrl *bc;
int num_paths;
};
struct imx8m_blk_ctrl_data {
@ -117,6 +123,10 @@ static int imx8m_blk_ctrl_power_on(struct generic_pm_domain *genpd)
if (data->mipi_phy_rst_mask)
regmap_set_bits(bc->regmap, BLK_MIPI_RESET_DIV, data->mipi_phy_rst_mask);
ret = icc_bulk_set_bw(domain->num_paths, domain->paths);
if (ret)
dev_err(bc->dev, "failed to set icc bw\n");
/* disable upstream clocks */
clk_bulk_disable_unprepare(data->num_clks, domain->clks);
@ -152,19 +162,6 @@ static int imx8m_blk_ctrl_power_off(struct generic_pm_domain *genpd)
return 0;
}
static struct generic_pm_domain *
imx8m_blk_ctrl_xlate(struct of_phandle_args *args, void *data)
{
struct genpd_onecell_data *onecell_data = data;
unsigned int index = args->args[0];
if (args->args_count != 1 ||
index >= onecell_data->num_domains)
return ERR_PTR(-EINVAL);
return onecell_data->domains[index];
}
static struct lock_class_key blk_ctrl_genpd_lock_class;
static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
@ -206,7 +203,6 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
return -ENOMEM;
bc->onecell_data.num_domains = bc_data->num_domains;
bc->onecell_data.xlate = imx8m_blk_ctrl_xlate;
bc->onecell_data.domains =
devm_kcalloc(dev, bc_data->num_domains,
sizeof(struct generic_pm_domain *), GFP_KERNEL);
@ -224,10 +220,29 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
int j;
domain->data = data;
domain->num_paths = data->num_paths;
for (j = 0; j < data->num_clks; j++)
domain->clks[j].id = data->clk_names[j];
for (j = 0; j < data->num_paths; j++) {
domain->paths[j].name = data->path_names[j];
/* Fake value for now, just let ICC could configure NoC mode/priority */
domain->paths[j].avg_bw = 1;
domain->paths[j].peak_bw = 1;
}
ret = devm_of_icc_bulk_get(dev, data->num_paths, domain->paths);
if (ret) {
if (ret != -EPROBE_DEFER) {
dev_warn_once(dev, "Could not get interconnect paths, NoC will stay unconfigured!\n");
domain->num_paths = 0;
} else {
dev_err_probe(dev, ret, "failed to get noc entries\n");
goto cleanup_pds;
}
}
ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
if (ret) {
dev_err_probe(dev, ret, "failed to get clock\n");
@ -454,6 +469,46 @@ static const struct imx8m_blk_ctrl_data imx8mm_vpu_blk_ctl_dev_data = {
.num_domains = ARRAY_SIZE(imx8mm_vpu_blk_ctl_domain_data),
};
static const struct imx8m_blk_ctrl_domain_data imx8mp_vpu_blk_ctl_domain_data[] = {
[IMX8MP_VPUBLK_PD_G1] = {
.name = "vpublk-g1",
.clk_names = (const char *[]){ "g1", },
.num_clks = 1,
.gpc_name = "g1",
.rst_mask = BIT(1),
.clk_mask = BIT(1),
.path_names = (const char *[]){"g1"},
.num_paths = 1,
},
[IMX8MP_VPUBLK_PD_G2] = {
.name = "vpublk-g2",
.clk_names = (const char *[]){ "g2", },
.num_clks = 1,
.gpc_name = "g2",
.rst_mask = BIT(0),
.clk_mask = BIT(0),
.path_names = (const char *[]){"g2"},
.num_paths = 1,
},
[IMX8MP_VPUBLK_PD_VC8000E] = {
.name = "vpublk-vc8000e",
.clk_names = (const char *[]){ "vc8000e", },
.num_clks = 1,
.gpc_name = "vc8000e",
.rst_mask = BIT(2),
.clk_mask = BIT(2),
.path_names = (const char *[]){"vc8000e"},
.num_paths = 1,
},
};
static const struct imx8m_blk_ctrl_data imx8mp_vpu_blk_ctl_dev_data = {
.max_reg = 0x18,
.power_notifier_fn = imx8mm_vpu_power_notifier,
.domains = imx8mp_vpu_blk_ctl_domain_data,
.num_domains = ARRAY_SIZE(imx8mp_vpu_blk_ctl_domain_data),
};
static int imx8mm_disp_power_notifier(struct notifier_block *nb,
unsigned long action, void *data)
{
@ -649,6 +704,8 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_media_blk_ctl_domain_data[
.gpc_name = "lcdif1",
.rst_mask = BIT(4) | BIT(5) | BIT(23),
.clk_mask = BIT(4) | BIT(5) | BIT(23),
.path_names = (const char *[]){"lcdif-rd", "lcdif-wr"},
.num_paths = 2,
},
[IMX8MP_MEDIABLK_PD_ISI] = {
.name = "mediablk-isi",
@ -657,6 +714,8 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_media_blk_ctl_domain_data[
.gpc_name = "isi",
.rst_mask = BIT(6) | BIT(7),
.clk_mask = BIT(6) | BIT(7),
.path_names = (const char *[]){"isi0", "isi1", "isi2"},
.num_paths = 3,
},
[IMX8MP_MEDIABLK_PD_MIPI_CSI2_2] = {
.name = "mediablk-mipi-csi2-2",
@ -674,6 +733,8 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_media_blk_ctl_domain_data[
.gpc_name = "lcdif2",
.rst_mask = BIT(11) | BIT(12) | BIT(24),
.clk_mask = BIT(11) | BIT(12) | BIT(24),
.path_names = (const char *[]){"lcdif-rd", "lcdif-wr"},
.num_paths = 2,
},
[IMX8MP_MEDIABLK_PD_ISP] = {
.name = "mediablk-isp",
@ -682,6 +743,8 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_media_blk_ctl_domain_data[
.gpc_name = "isp",
.rst_mask = BIT(16) | BIT(17) | BIT(18),
.clk_mask = BIT(16) | BIT(17) | BIT(18),
.path_names = (const char *[]){"isp0", "isp1"},
.num_paths = 2,
},
[IMX8MP_MEDIABLK_PD_DWE] = {
.name = "mediablk-dwe",
@ -690,6 +753,8 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_media_blk_ctl_domain_data[
.gpc_name = "dwe",
.rst_mask = BIT(19) | BIT(20) | BIT(21),
.clk_mask = BIT(19) | BIT(20) | BIT(21),
.path_names = (const char *[]){"dwe"},
.num_paths = 1,
},
[IMX8MP_MEDIABLK_PD_MIPI_DSI_2] = {
.name = "mediablk-mipi-dsi-2",
@ -787,6 +852,9 @@ static const struct of_device_id imx8m_blk_ctrl_of_match[] = {
}, {
.compatible = "fsl,imx8mq-vpu-blk-ctrl",
.data = &imx8mq_vpu_blk_ctl_dev_data
}, {
.compatible = "fsl,imx8mp-vpu-blk-ctrl",
.data = &imx8mp_vpu_blk_ctl_dev_data
}, {
/* Sentinel */
}

View File

@ -6,6 +6,7 @@
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/interconnect.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
@ -18,6 +19,8 @@
#define GPR_REG0 0x0
#define PCIE_CLOCK_MODULE_EN BIT(0)
#define USB_CLOCK_MODULE_EN BIT(1)
#define PCIE_PHY_APB_RST BIT(4)
#define PCIE_PHY_INIT_RST BIT(5)
struct imx8mp_blk_ctrl_domain;
@ -36,17 +39,22 @@ struct imx8mp_blk_ctrl_domain_data {
const char *name;
const char * const *clk_names;
int num_clks;
const char * const *path_names;
int num_paths;
const char *gpc_name;
};
#define DOMAIN_MAX_CLKS 2
#define DOMAIN_MAX_PATHS 3
struct imx8mp_blk_ctrl_domain {
struct generic_pm_domain genpd;
const struct imx8mp_blk_ctrl_domain_data *data;
struct clk_bulk_data clks[DOMAIN_MAX_CLKS];
struct icc_bulk_data paths[DOMAIN_MAX_PATHS];
struct device *power_dev;
struct imx8mp_blk_ctrl *bc;
int num_paths;
int id;
};
@ -75,6 +83,10 @@ static void imx8mp_hsio_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
case IMX8MP_HSIOBLK_PD_PCIE:
regmap_set_bits(bc->regmap, GPR_REG0, PCIE_CLOCK_MODULE_EN);
break;
case IMX8MP_HSIOBLK_PD_PCIE_PHY:
regmap_set_bits(bc->regmap, GPR_REG0,
PCIE_PHY_APB_RST | PCIE_PHY_INIT_RST);
break;
default:
break;
}
@ -90,6 +102,10 @@ static void imx8mp_hsio_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc,
case IMX8MP_HSIOBLK_PD_PCIE:
regmap_clear_bits(bc->regmap, GPR_REG0, PCIE_CLOCK_MODULE_EN);
break;
case IMX8MP_HSIOBLK_PD_PCIE_PHY:
regmap_clear_bits(bc->regmap, GPR_REG0,
PCIE_PHY_APB_RST | PCIE_PHY_INIT_RST);
break;
default:
break;
}
@ -144,6 +160,8 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hsio_domain_data[] = {
.clk_names = (const char *[]){ "usb" },
.num_clks = 1,
.gpc_name = "usb",
.path_names = (const char *[]){"usb1", "usb2"},
.num_paths = 2,
},
[IMX8MP_HSIOBLK_PD_USB_PHY1] = {
.name = "hsioblk-usb-phy1",
@ -158,6 +176,8 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hsio_domain_data[] = {
.clk_names = (const char *[]){ "pcie" },
.num_clks = 1,
.gpc_name = "pcie",
.path_names = (const char *[]){"noc-pcie", "pcie"},
.num_paths = 2,
},
[IMX8MP_HSIOBLK_PD_PCIE_PHY] = {
.name = "hsioblk-pcie-phy",
@ -225,6 +245,13 @@ static void imx8mp_hdmi_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12));
regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3));
break;
case IMX8MP_HDMIBLK_PD_HDCP:
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(11));
break;
case IMX8MP_HDMIBLK_PD_HRV:
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(3) | BIT(4) | BIT(5));
regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(15));
break;
default:
break;
}
@ -273,6 +300,13 @@ static void imx8mp_hdmi_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc,
regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12));
regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24));
break;
case IMX8MP_HDMIBLK_PD_HDCP:
regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(11));
break;
case IMX8MP_HDMIBLK_PD_HRV:
regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(15));
regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(3) | BIT(4) | BIT(5));
break;
default:
break;
}
@ -322,6 +356,8 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = {
.clk_names = (const char *[]){ "axi", "apb" },
.num_clks = 2,
.gpc_name = "lcdif",
.path_names = (const char *[]){"lcdif-hdmi"},
.num_paths = 1,
},
[IMX8MP_HDMIBLK_PD_PAI] = {
.name = "hdmiblk-pai",
@ -353,6 +389,22 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = {
.num_clks = 2,
.gpc_name = "hdmi-tx-phy",
},
[IMX8MP_HDMIBLK_PD_HRV] = {
.name = "hdmiblk-hrv",
.clk_names = (const char *[]){ "axi", "apb" },
.num_clks = 2,
.gpc_name = "hrv",
.path_names = (const char *[]){"hrv"},
.num_paths = 1,
},
[IMX8MP_HDMIBLK_PD_HDCP] = {
.name = "hdmiblk-hdcp",
.clk_names = (const char *[]){ "axi", "apb" },
.num_clks = 2,
.gpc_name = "hdcp",
.path_names = (const char *[]){"hdcp"},
.num_paths = 1,
},
};
static const struct imx8mp_blk_ctrl_data imx8mp_hdmi_blk_ctl_dev_data = {
@ -395,6 +447,10 @@ static int imx8mp_blk_ctrl_power_on(struct generic_pm_domain *genpd)
goto clk_disable;
}
ret = icc_bulk_set_bw(domain->num_paths, domain->paths);
if (ret)
dev_err(bc->dev, "failed to set icc bw\n");
clk_bulk_disable_unprepare(data->num_clks, domain->clks);
return 0;
@ -434,19 +490,6 @@ static int imx8mp_blk_ctrl_power_off(struct generic_pm_domain *genpd)
return 0;
}
static struct generic_pm_domain *
imx8m_blk_ctrl_xlate(struct of_phandle_args *args, void *data)
{
struct genpd_onecell_data *onecell_data = data;
unsigned int index = args->args[0];
if (args->args_count != 1 ||
index >= onecell_data->num_domains)
return ERR_PTR(-EINVAL);
return onecell_data->domains[index];
}
static struct lock_class_key blk_ctrl_genpd_lock_class;
static int imx8mp_blk_ctrl_probe(struct platform_device *pdev)
@ -489,7 +532,6 @@ static int imx8mp_blk_ctrl_probe(struct platform_device *pdev)
return -ENOMEM;
bc->onecell_data.num_domains = num_domains;
bc->onecell_data.xlate = imx8m_blk_ctrl_xlate;
bc->onecell_data.domains =
devm_kcalloc(dev, num_domains,
sizeof(struct generic_pm_domain *), GFP_KERNEL);
@ -510,10 +552,29 @@ static int imx8mp_blk_ctrl_probe(struct platform_device *pdev)
int j;
domain->data = data;
domain->num_paths = data->num_paths;
for (j = 0; j < data->num_clks; j++)
domain->clks[j].id = data->clk_names[j];
for (j = 0; j < data->num_paths; j++) {
domain->paths[j].name = data->path_names[j];
/* Fake value for now, just let ICC could configure NoC mode/priority */
domain->paths[j].avg_bw = 1;
domain->paths[j].peak_bw = 1;
}
ret = devm_of_icc_bulk_get(dev, data->num_paths, domain->paths);
if (ret) {
if (ret != -EPROBE_DEFER) {
dev_warn_once(dev, "Could not get interconnect paths, NoC will stay unconfigured!\n");
domain->num_paths = 0;
} else {
dev_err_probe(dev, ret, "failed to get noc entries\n");
goto cleanup_pds;
}
}
ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
if (ret) {
dev_err_probe(dev, ret, "failed to get clock\n");

View File

@ -0,0 +1,436 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2022 NXP, Peng Fan <peng.fan@nxp.com>
*/
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/sizes.h>
#include <dt-bindings/power/fsl,imx93-power.h>
#define BLK_SFT_RSTN 0x0
#define BLK_CLK_EN 0x4
#define BLK_MAX_CLKS 4
#define DOMAIN_MAX_CLKS 4
#define LCDIF_QOS_REG 0xC
#define LCDIF_DEFAULT_QOS_OFF 12
#define LCDIF_CFG_QOS_OFF 8
#define PXP_QOS_REG 0x10
#define PXP_R_DEFAULT_QOS_OFF 28
#define PXP_R_CFG_QOS_OFF 24
#define PXP_W_DEFAULT_QOS_OFF 20
#define PXP_W_CFG_QOS_OFF 16
#define ISI_CACHE_REG 0x14
#define ISI_QOS_REG 0x1C
#define ISI_V_DEFAULT_QOS_OFF 28
#define ISI_V_CFG_QOS_OFF 24
#define ISI_U_DEFAULT_QOS_OFF 20
#define ISI_U_CFG_QOS_OFF 16
#define ISI_Y_R_DEFAULT_QOS_OFF 12
#define ISI_Y_R_CFG_QOS_OFF 8
#define ISI_Y_W_DEFAULT_QOS_OFF 4
#define ISI_Y_W_CFG_QOS_OFF 0
#define PRIO_MASK 0xF
#define PRIO(X) (X)
struct imx93_blk_ctrl_domain;
struct imx93_blk_ctrl {
struct device *dev;
struct regmap *regmap;
int num_clks;
struct clk_bulk_data clks[BLK_MAX_CLKS];
struct imx93_blk_ctrl_domain *domains;
struct genpd_onecell_data onecell_data;
};
#define DOMAIN_MAX_QOS 4
struct imx93_blk_ctrl_qos {
u32 reg;
u32 cfg_off;
u32 default_prio;
u32 cfg_prio;
};
struct imx93_blk_ctrl_domain_data {
const char *name;
const char * const *clk_names;
int num_clks;
u32 rst_mask;
u32 clk_mask;
int num_qos;
struct imx93_blk_ctrl_qos qos[DOMAIN_MAX_QOS];
};
struct imx93_blk_ctrl_domain {
struct generic_pm_domain genpd;
const struct imx93_blk_ctrl_domain_data *data;
struct clk_bulk_data clks[DOMAIN_MAX_CLKS];
struct imx93_blk_ctrl *bc;
};
struct imx93_blk_ctrl_data {
const struct imx93_blk_ctrl_domain_data *domains;
int num_domains;
const char * const *clk_names;
int num_clks;
const struct regmap_access_table *reg_access_table;
};
static inline struct imx93_blk_ctrl_domain *
to_imx93_blk_ctrl_domain(struct generic_pm_domain *genpd)
{
return container_of(genpd, struct imx93_blk_ctrl_domain, genpd);
}
static int imx93_blk_ctrl_set_qos(struct imx93_blk_ctrl_domain *domain)
{
const struct imx93_blk_ctrl_domain_data *data = domain->data;
struct imx93_blk_ctrl *bc = domain->bc;
const struct imx93_blk_ctrl_qos *qos;
u32 val, mask;
int i;
for (i = 0; i < data->num_qos; i++) {
qos = &data->qos[i];
mask = PRIO_MASK << qos->cfg_off;
mask |= PRIO_MASK << (qos->cfg_off + 4);
val = qos->cfg_prio << qos->cfg_off;
val |= qos->default_prio << (qos->cfg_off + 4);
regmap_write_bits(bc->regmap, qos->reg, mask, val);
dev_dbg(bc->dev, "data->qos[i].reg 0x%x 0x%x\n", qos->reg, val);
}
return 0;
}
static int imx93_blk_ctrl_power_on(struct generic_pm_domain *genpd)
{
struct imx93_blk_ctrl_domain *domain = to_imx93_blk_ctrl_domain(genpd);
const struct imx93_blk_ctrl_domain_data *data = domain->data;
struct imx93_blk_ctrl *bc = domain->bc;
int ret;
ret = clk_bulk_prepare_enable(bc->num_clks, bc->clks);
if (ret) {
dev_err(bc->dev, "failed to enable bus clocks\n");
return ret;
}
ret = clk_bulk_prepare_enable(data->num_clks, domain->clks);
if (ret) {
clk_bulk_disable_unprepare(bc->num_clks, bc->clks);
dev_err(bc->dev, "failed to enable clocks\n");
return ret;
}
ret = pm_runtime_get_sync(bc->dev);
if (ret < 0) {
pm_runtime_put_noidle(bc->dev);
dev_err(bc->dev, "failed to power up domain\n");
goto disable_clk;
}
/* ungate clk */
regmap_clear_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
/* release reset */
regmap_set_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask);
dev_dbg(bc->dev, "pd_on: name: %s\n", genpd->name);
return imx93_blk_ctrl_set_qos(domain);
disable_clk:
clk_bulk_disable_unprepare(data->num_clks, domain->clks);
clk_bulk_disable_unprepare(bc->num_clks, bc->clks);
return ret;
}
static int imx93_blk_ctrl_power_off(struct generic_pm_domain *genpd)
{
struct imx93_blk_ctrl_domain *domain = to_imx93_blk_ctrl_domain(genpd);
const struct imx93_blk_ctrl_domain_data *data = domain->data;
struct imx93_blk_ctrl *bc = domain->bc;
dev_dbg(bc->dev, "pd_off: name: %s\n", genpd->name);
regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask);
regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
pm_runtime_put(bc->dev);
clk_bulk_disable_unprepare(data->num_clks, domain->clks);
clk_bulk_disable_unprepare(bc->num_clks, bc->clks);
return 0;
}
static int imx93_blk_ctrl_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct imx93_blk_ctrl_data *bc_data = of_device_get_match_data(dev);
struct imx93_blk_ctrl *bc;
void __iomem *base;
int i, ret;
struct regmap_config regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.rd_table = bc_data->reg_access_table,
.wr_table = bc_data->reg_access_table,
.max_register = SZ_4K,
};
bc = devm_kzalloc(dev, sizeof(*bc), GFP_KERNEL);
if (!bc)
return -ENOMEM;
bc->dev = dev;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
bc->regmap = devm_regmap_init_mmio(dev, base, &regmap_config);
if (IS_ERR(bc->regmap))
return dev_err_probe(dev, PTR_ERR(bc->regmap),
"failed to init regmap\n");
bc->domains = devm_kcalloc(dev, bc_data->num_domains,
sizeof(struct imx93_blk_ctrl_domain),
GFP_KERNEL);
if (!bc->domains)
return -ENOMEM;
bc->onecell_data.num_domains = bc_data->num_domains;
bc->onecell_data.domains =
devm_kcalloc(dev, bc_data->num_domains,
sizeof(struct generic_pm_domain *), GFP_KERNEL);
if (!bc->onecell_data.domains)
return -ENOMEM;
for (i = 0; i < bc_data->num_clks; i++)
bc->clks[i].id = bc_data->clk_names[i];
bc->num_clks = bc_data->num_clks;
ret = devm_clk_bulk_get(dev, bc->num_clks, bc->clks);
if (ret) {
dev_err_probe(dev, ret, "failed to get bus clock\n");
return ret;
}
for (i = 0; i < bc_data->num_domains; i++) {
const struct imx93_blk_ctrl_domain_data *data = &bc_data->domains[i];
struct imx93_blk_ctrl_domain *domain = &bc->domains[i];
int j;
domain->data = data;
for (j = 0; j < data->num_clks; j++)
domain->clks[j].id = data->clk_names[j];
ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
if (ret) {
dev_err_probe(dev, ret, "failed to get clock\n");
goto cleanup_pds;
}
domain->genpd.name = data->name;
domain->genpd.power_on = imx93_blk_ctrl_power_on;
domain->genpd.power_off = imx93_blk_ctrl_power_off;
domain->bc = bc;
ret = pm_genpd_init(&domain->genpd, NULL, true);
if (ret) {
dev_err_probe(dev, ret, "failed to init power domain\n");
goto cleanup_pds;
}
bc->onecell_data.domains[i] = &domain->genpd;
}
pm_runtime_enable(dev);
ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data);
if (ret) {
dev_err_probe(dev, ret, "failed to add power domain provider\n");
goto cleanup_pds;
}
dev_set_drvdata(dev, bc);
return 0;
cleanup_pds:
for (i--; i >= 0; i--)
pm_genpd_remove(&bc->domains[i].genpd);
return ret;
}
static int imx93_blk_ctrl_remove(struct platform_device *pdev)
{
struct imx93_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
int i;
of_genpd_del_provider(pdev->dev.of_node);
for (i = 0; bc->onecell_data.num_domains; i++) {
struct imx93_blk_ctrl_domain *domain = &bc->domains[i];
pm_genpd_remove(&domain->genpd);
}
return 0;
}
static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] = {
[IMX93_MEDIABLK_PD_MIPI_DSI] = {
.name = "mediablk-mipi-dsi",
.clk_names = (const char *[]){ "dsi" },
.num_clks = 1,
.rst_mask = BIT(11) | BIT(12),
.clk_mask = BIT(11) | BIT(12),
},
[IMX93_MEDIABLK_PD_MIPI_CSI] = {
.name = "mediablk-mipi-csi",
.clk_names = (const char *[]){ "cam", "csi" },
.num_clks = 2,
.rst_mask = BIT(9) | BIT(10),
.clk_mask = BIT(9) | BIT(10),
},
[IMX93_MEDIABLK_PD_PXP] = {
.name = "mediablk-pxp",
.clk_names = (const char *[]){ "pxp" },
.num_clks = 1,
.rst_mask = BIT(7) | BIT(8),
.clk_mask = BIT(7) | BIT(8),
.num_qos = 2,
.qos = {
{
.reg = PXP_QOS_REG,
.cfg_off = PXP_R_CFG_QOS_OFF,
.default_prio = PRIO(3),
.cfg_prio = PRIO(6),
}, {
.reg = PXP_QOS_REG,
.cfg_off = PXP_W_CFG_QOS_OFF,
.default_prio = PRIO(3),
.cfg_prio = PRIO(6),
}
}
},
[IMX93_MEDIABLK_PD_LCDIF] = {
.name = "mediablk-lcdif",
.clk_names = (const char *[]){ "disp", "lcdif" },
.num_clks = 2,
.rst_mask = BIT(4) | BIT(5) | BIT(6),
.clk_mask = BIT(4) | BIT(5) | BIT(6),
.num_qos = 1,
.qos = {
{
.reg = LCDIF_QOS_REG,
.cfg_off = LCDIF_CFG_QOS_OFF,
.default_prio = PRIO(3),
.cfg_prio = PRIO(7),
}
}
},
[IMX93_MEDIABLK_PD_ISI] = {
.name = "mediablk-isi",
.clk_names = (const char *[]){ "isi" },
.num_clks = 1,
.rst_mask = BIT(2) | BIT(3),
.clk_mask = BIT(2) | BIT(3),
.num_qos = 4,
.qos = {
{
.reg = ISI_QOS_REG,
.cfg_off = ISI_Y_W_CFG_QOS_OFF,
.default_prio = PRIO(3),
.cfg_prio = PRIO(7),
}, {
.reg = ISI_QOS_REG,
.cfg_off = ISI_Y_R_CFG_QOS_OFF,
.default_prio = PRIO(3),
.cfg_prio = PRIO(7),
}, {
.reg = ISI_QOS_REG,
.cfg_off = ISI_U_CFG_QOS_OFF,
.default_prio = PRIO(3),
.cfg_prio = PRIO(7),
}, {
.reg = ISI_QOS_REG,
.cfg_off = ISI_V_CFG_QOS_OFF,
.default_prio = PRIO(3),
.cfg_prio = PRIO(7),
}
}
},
};
static const struct regmap_range imx93_media_blk_ctl_yes_ranges[] = {
regmap_reg_range(BLK_SFT_RSTN, BLK_CLK_EN),
regmap_reg_range(LCDIF_QOS_REG, ISI_CACHE_REG),
regmap_reg_range(ISI_QOS_REG, ISI_QOS_REG),
};
static const struct regmap_access_table imx93_media_blk_ctl_access_table = {
.yes_ranges = imx93_media_blk_ctl_yes_ranges,
.n_yes_ranges = ARRAY_SIZE(imx93_media_blk_ctl_yes_ranges),
};
static const struct imx93_blk_ctrl_data imx93_media_blk_ctl_dev_data = {
.domains = imx93_media_blk_ctl_domain_data,
.num_domains = ARRAY_SIZE(imx93_media_blk_ctl_domain_data),
.clk_names = (const char *[]){ "axi", "apb", "nic", },
.num_clks = 3,
.reg_access_table = &imx93_media_blk_ctl_access_table,
};
static const struct of_device_id imx93_blk_ctrl_of_match[] = {
{
.compatible = "fsl,imx93-media-blk-ctrl",
.data = &imx93_media_blk_ctl_dev_data
}, {
/* Sentinel */
}
};
MODULE_DEVICE_TABLE(of, imx93_blk_ctrl_of_match);
static struct platform_driver imx93_blk_ctrl_driver = {
.probe = imx93_blk_ctrl_probe,
.remove = imx93_blk_ctrl_remove,
.driver = {
.name = "imx93-blk-ctrl",
.of_match_table = imx93_blk_ctrl_of_match,
},
};
module_platform_driver(imx93_blk_ctrl_driver);
MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
MODULE_DESCRIPTION("i.MX93 BLK CTRL driver");
MODULE_LICENSE("GPL");

164
drivers/soc/imx/imx93-pd.c Normal file
View File

@ -0,0 +1,164 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2022 NXP
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/of_device.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#define MIX_SLICE_SW_CTRL_OFF 0x20
#define SLICE_SW_CTRL_PSW_CTRL_OFF_MASK BIT(4)
#define SLICE_SW_CTRL_PDN_SOFT_MASK BIT(31)
#define MIX_FUNC_STAT_OFF 0xB4
#define FUNC_STAT_PSW_STAT_MASK BIT(0)
#define FUNC_STAT_RST_STAT_MASK BIT(2)
#define FUNC_STAT_ISO_STAT_MASK BIT(4)
struct imx93_power_domain {
struct generic_pm_domain genpd;
struct device *dev;
void __iomem *addr;
struct clk_bulk_data *clks;
int num_clks;
bool init_off;
};
#define to_imx93_pd(_genpd) container_of(_genpd, struct imx93_power_domain, genpd)
static int imx93_pd_on(struct generic_pm_domain *genpd)
{
struct imx93_power_domain *domain = to_imx93_pd(genpd);
void __iomem *addr = domain->addr;
u32 val;
int ret;
ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks);
if (ret) {
dev_err(domain->dev, "failed to enable clocks for domain: %s\n", genpd->name);
return ret;
}
val = readl(addr + MIX_SLICE_SW_CTRL_OFF);
val &= ~SLICE_SW_CTRL_PDN_SOFT_MASK;
writel(val, addr + MIX_SLICE_SW_CTRL_OFF);
ret = readl_poll_timeout(addr + MIX_FUNC_STAT_OFF, val,
!(val & FUNC_STAT_ISO_STAT_MASK), 1, 10000);
if (ret) {
dev_err(domain->dev, "pd_on timeout: name: %s, stat: %x\n", genpd->name, val);
return ret;
}
return 0;
}
static int imx93_pd_off(struct generic_pm_domain *genpd)
{
struct imx93_power_domain *domain = to_imx93_pd(genpd);
void __iomem *addr = domain->addr;
int ret;
u32 val;
/* Power off MIX */
val = readl(addr + MIX_SLICE_SW_CTRL_OFF);
val |= SLICE_SW_CTRL_PDN_SOFT_MASK;
writel(val, addr + MIX_SLICE_SW_CTRL_OFF);
ret = readl_poll_timeout(addr + MIX_FUNC_STAT_OFF, val,
val & FUNC_STAT_PSW_STAT_MASK, 1, 1000);
if (ret) {
dev_err(domain->dev, "pd_off timeout: name: %s, stat: %x\n", genpd->name, val);
return ret;
}
clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
return 0;
};
static int imx93_pd_remove(struct platform_device *pdev)
{
struct imx93_power_domain *domain = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
if (!domain->init_off)
clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
of_genpd_del_provider(np);
pm_genpd_remove(&domain->genpd);
return 0;
}
static int imx93_pd_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct imx93_power_domain *domain;
int ret;
domain = devm_kzalloc(dev, sizeof(*domain), GFP_KERNEL);
if (!domain)
return -ENOMEM;
domain->addr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(domain->addr))
return PTR_ERR(domain->addr);
domain->num_clks = devm_clk_bulk_get_all(dev, &domain->clks);
if (domain->num_clks < 0)
return dev_err_probe(dev, domain->num_clks, "Failed to get domain's clocks\n");
domain->genpd.name = dev_name(dev);
domain->genpd.power_off = imx93_pd_off;
domain->genpd.power_on = imx93_pd_on;
domain->dev = dev;
domain->init_off = readl(domain->addr + MIX_FUNC_STAT_OFF) & FUNC_STAT_ISO_STAT_MASK;
/* Just to sync the status of hardware */
if (!domain->init_off) {
ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks);
if (ret) {
dev_err(domain->dev, "failed to enable clocks for domain: %s\n",
domain->genpd.name);
return ret;
}
}
ret = pm_genpd_init(&domain->genpd, NULL, domain->init_off);
if (ret)
return ret;
platform_set_drvdata(pdev, domain);
return of_genpd_add_provider_simple(np, &domain->genpd);
}
static const struct of_device_id imx93_pd_ids[] = {
{ .compatible = "fsl,imx93-src-slice" },
{ }
};
MODULE_DEVICE_TABLE(of, imx93_pd_ids);
static struct platform_driver imx93_power_domain_driver = {
.driver = {
.name = "imx93_power_domain",
.owner = THIS_MODULE,
.of_match_table = imx93_pd_ids,
},
.probe = imx93_pd_probe,
.remove = imx93_pd_remove,
};
module_platform_driver(imx93_power_domain_driver);
MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
MODULE_DESCRIPTION("NXP i.MX93 power domain driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,33 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2022 NXP
*/
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
static int imx93_src_probe(struct platform_device *pdev)
{
return devm_of_platform_populate(&pdev->dev);
}
static const struct of_device_id imx93_src_ids[] = {
{ .compatible = "fsl,imx93-src" },
{ }
};
MODULE_DEVICE_TABLE(of, imx93_src_ids);
static struct platform_driver imx93_src_driver = {
.driver = {
.name = "imx93_src",
.owner = THIS_MODULE,
.of_match_table = imx93_src_ids,
},
.probe = imx93_src_probe,
};
module_platform_driver(imx93_src_driver);
MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
MODULE_DESCRIPTION("NXP i.MX93 src driver");
MODULE_LICENSE("GPL");

View File

@ -37,6 +37,7 @@ config MTK_INFRACFG
config MTK_PMIC_WRAP
tristate "MediaTek PMIC Wrapper Support"
depends on RESET_CONTROLLER
depends on OF
select REGMAP
help
Say yes here to add support for MediaTek PMIC Wrapper found
@ -46,6 +47,7 @@ config MTK_PMIC_WRAP
config MTK_SCPSYS
bool "MediaTek SCPSYS Support"
default ARCH_MEDIATEK
depends on OF
select REGMAP
select MTK_INFRACFG
select PM_GENERIC_DOMAINS if PM

View File

@ -3,6 +3,12 @@
#ifndef __SOC_MEDIATEK_MT8186_MMSYS_H
#define __SOC_MEDIATEK_MT8186_MMSYS_H
/* Values for DPI configuration in MMSYS address space */
#define MT8186_MMSYS_DPI_OUTPUT_FORMAT 0x400
#define DPI_FORMAT_MASK 0x1
#define DPI_RGB888_DDR_CON BIT(0)
#define DPI_RGB565_SDR_CON BIT(1)
#define MT8186_MMSYS_OVL_CON 0xF04
#define MT8186_MMSYS_OVL0_CON_MASK 0x3
#define MT8186_MMSYS_OVL0_2L_CON_MASK 0xC

View File

@ -227,6 +227,26 @@ void mtk_mmsys_ddp_disconnect(struct device *dev,
}
EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_disconnect);
static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32 offset, u32 mask, u32 val)
{
u32 tmp;
tmp = readl_relaxed(mmsys->regs + offset);
tmp = (tmp & ~mask) | val;
writel_relaxed(tmp, mmsys->regs + offset);
}
void mtk_mmsys_ddp_dpi_fmt_config(struct device *dev, u32 val)
{
if (val)
mtk_mmsys_update_bits(dev_get_drvdata(dev), MT8186_MMSYS_DPI_OUTPUT_FORMAT,
DPI_RGB888_DDR_CON, DPI_FORMAT_MASK);
else
mtk_mmsys_update_bits(dev_get_drvdata(dev), MT8186_MMSYS_DPI_OUTPUT_FORMAT,
DPI_RGB565_SDR_CON, DPI_FORMAT_MASK);
}
EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_dpi_fmt_config);
static int mtk_mmsys_reset_update(struct reset_controller_dev *rcdev, unsigned long id,
bool assert)
{

View File

@ -91,6 +91,15 @@
#define MT8183_MUTEX_MOD_MDP_AAL0 23
#define MT8183_MUTEX_MOD_MDP_CCORR0 24
#define MT8186_MUTEX_MOD_MDP_RDMA0 0
#define MT8186_MUTEX_MOD_MDP_AAL0 2
#define MT8186_MUTEX_MOD_MDP_HDR0 4
#define MT8186_MUTEX_MOD_MDP_RSZ0 5
#define MT8186_MUTEX_MOD_MDP_RSZ1 6
#define MT8186_MUTEX_MOD_MDP_WROT0 7
#define MT8186_MUTEX_MOD_MDP_TDSHP0 9
#define MT8186_MUTEX_MOD_MDP_COLOR0 14
#define MT8173_MUTEX_MOD_DISP_OVL0 11
#define MT8173_MUTEX_MOD_DISP_OVL1 12
#define MT8173_MUTEX_MOD_DISP_RDMA0 13
@ -324,6 +333,17 @@ static const unsigned int mt8186_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_RDMA1] = MT8186_MUTEX_MOD_DISP_RDMA1,
};
static const unsigned int mt8186_mdp_mutex_table_mod[MUTEX_MOD_IDX_MAX] = {
[MUTEX_MOD_IDX_MDP_RDMA0] = MT8186_MUTEX_MOD_MDP_RDMA0,
[MUTEX_MOD_IDX_MDP_RSZ0] = MT8186_MUTEX_MOD_MDP_RSZ0,
[MUTEX_MOD_IDX_MDP_RSZ1] = MT8186_MUTEX_MOD_MDP_RSZ1,
[MUTEX_MOD_IDX_MDP_TDSHP0] = MT8186_MUTEX_MOD_MDP_TDSHP0,
[MUTEX_MOD_IDX_MDP_WROT0] = MT8186_MUTEX_MOD_MDP_WROT0,
[MUTEX_MOD_IDX_MDP_HDR0] = MT8186_MUTEX_MOD_MDP_HDR0,
[MUTEX_MOD_IDX_MDP_AAL0] = MT8186_MUTEX_MOD_MDP_AAL0,
[MUTEX_MOD_IDX_MDP_COLOR0] = MT8186_MUTEX_MOD_MDP_COLOR0,
};
static const unsigned int mt8192_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_AAL0] = MT8192_MUTEX_MOD_DISP_AAL0,
[DDP_COMPONENT_CCORR] = MT8192_MUTEX_MOD_DISP_CCORR0,
@ -380,6 +400,13 @@ static const unsigned int mt2712_mutex_sof[DDP_MUTEX_SOF_MAX] = {
[MUTEX_SOF_DSI3] = MUTEX_SOF_DSI3,
};
static const unsigned int mt6795_mutex_sof[DDP_MUTEX_SOF_MAX] = {
[MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
[MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0,
[MUTEX_SOF_DSI1] = MUTEX_SOF_DSI1,
[MUTEX_SOF_DPI0] = MUTEX_SOF_DPI0,
};
static const unsigned int mt8167_mutex_sof[DDP_MUTEX_SOF_MAX] = {
[MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
[MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0,
@ -434,6 +461,13 @@ static const struct mtk_mutex_data mt2712_mutex_driver_data = {
.mutex_sof_reg = MT2701_MUTEX0_SOF0,
};
static const struct mtk_mutex_data mt6795_mutex_driver_data = {
.mutex_mod = mt8173_mutex_mod,
.mutex_sof = mt6795_mutex_sof,
.mutex_mod_reg = MT2701_MUTEX0_MOD0,
.mutex_sof_reg = MT2701_MUTEX0_SOF0,
};
static const struct mtk_mutex_data mt8167_mutex_driver_data = {
.mutex_mod = mt8167_mutex_mod,
.mutex_sof = mt8167_mutex_sof,
@ -458,6 +492,12 @@ static const struct mtk_mutex_data mt8183_mutex_driver_data = {
.no_clk = true,
};
static const struct mtk_mutex_data mt8186_mdp_mutex_driver_data = {
.mutex_mod_reg = MT8183_MUTEX0_MOD0,
.mutex_sof_reg = MT8183_MUTEX0_SOF0,
.mutex_table_mod = mt8186_mdp_mutex_table_mod,
};
static const struct mtk_mutex_data mt8186_mutex_driver_data = {
.mutex_mod = mt8186_mutex_mod,
.mutex_sof = mt8186_mutex_sof,
@ -802,6 +842,8 @@ static const struct of_device_id mutex_driver_dt_match[] = {
.data = &mt2701_mutex_driver_data},
{ .compatible = "mediatek,mt2712-disp-mutex",
.data = &mt2712_mutex_driver_data},
{ .compatible = "mediatek,mt6795-disp-mutex",
.data = &mt6795_mutex_driver_data},
{ .compatible = "mediatek,mt8167-disp-mutex",
.data = &mt8167_mutex_driver_data},
{ .compatible = "mediatek,mt8173-disp-mutex",
@ -810,6 +852,8 @@ static const struct of_device_id mutex_driver_dt_match[] = {
.data = &mt8183_mutex_driver_data},
{ .compatible = "mediatek,mt8186-disp-mutex",
.data = &mt8186_mutex_driver_data},
{ .compatible = "mediatek,mt8186-mdp3-mutex",
.data = &mt8186_mdp_mutex_driver_data},
{ .compatible = "mediatek,mt8192-disp-mutex",
.data = &mt8192_mutex_driver_data},
{ .compatible = "mediatek,mt8195-disp-mutex",

View File

@ -393,7 +393,7 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
dev_err_probe(scpsys->dev, ret,
"%pOF: failed to get clk at index %d: %d\n", node, i, ret);
"%pOF: failed to get clk at index %d\n", node, i);
goto err_put_clocks;
}
@ -405,8 +405,8 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
dev_err_probe(scpsys->dev, ret,
"%pOF: failed to get clk at index %d: %d\n", node,
i + clk_ind, ret);
"%pOF: failed to get clk at index %d\n", node,
i + clk_ind);
goto err_put_subsys_clocks;
}

View File

@ -2316,7 +2316,7 @@ err_out1:
static struct platform_driver pwrap_drv = {
.driver = {
.name = "mt-pmic-pwrap",
.of_match_table = of_match_ptr(of_pwrap_match_tbl),
.of_match_table = of_pwrap_match_tbl,
},
.probe = pwrap_probe,
};

View File

@ -1141,7 +1141,7 @@ static struct platform_driver scpsys_drv = {
.name = "mtk-scpsys",
.suppress_bind_attrs = true,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_scpsys_match_tbl),
.of_match_table = of_scpsys_match_tbl,
},
};
builtin_platform_driver(scpsys_drv);

View File

@ -3,6 +3,7 @@
* Copyright (C) 2022 MediaTek Inc.
*/
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/completion.h>
@ -53,22 +54,79 @@
#define SVSB_MON_VOLT_IGNORE BIT(16)
#define SVSB_REMOVE_DVTFIXED_VOLT BIT(24)
/* svs bank register common configuration */
#define SVSB_DET_MAX 0xffff
/* svs bank register fields and common configuration */
#define SVSB_PTPCONFIG_DETMAX GENMASK(15, 0)
#define SVSB_DET_MAX FIELD_PREP(SVSB_PTPCONFIG_DETMAX, 0xffff)
#define SVSB_DET_WINDOW 0xa28
#define SVSB_DTHI 0x1
#define SVSB_DTLO 0xfe
#define SVSB_EN_INIT01 0x1
#define SVSB_EN_INIT02 0x5
#define SVSB_EN_MON 0x2
#define SVSB_EN_OFF 0x0
#define SVSB_INTEN_INIT0x 0x00005f01
#define SVSB_INTEN_MONVOPEN 0x00ff0000
#define SVSB_INTSTS_CLEAN 0x00ffffff
#define SVSB_INTSTS_COMPLETE 0x1
#define SVSB_INTSTS_MONVOP 0x00ff0000
/* DESCHAR */
#define SVSB_DESCHAR_FLD_MDES GENMASK(7, 0)
#define SVSB_DESCHAR_FLD_BDES GENMASK(15, 8)
/* TEMPCHAR */
#define SVSB_TEMPCHAR_FLD_DVT_FIXED GENMASK(7, 0)
#define SVSB_TEMPCHAR_FLD_MTDES GENMASK(15, 8)
#define SVSB_TEMPCHAR_FLD_VCO GENMASK(23, 16)
/* DETCHAR */
#define SVSB_DETCHAR_FLD_DCMDET GENMASK(7, 0)
#define SVSB_DETCHAR_FLD_DCBDET GENMASK(15, 8)
/* SVSEN (PTPEN) */
#define SVSB_PTPEN_INIT01 BIT(0)
#define SVSB_PTPEN_MON BIT(1)
#define SVSB_PTPEN_INIT02 (SVSB_PTPEN_INIT01 | BIT(2))
#define SVSB_PTPEN_OFF 0x0
/* FREQPCTS */
#define SVSB_FREQPCTS_FLD_PCT0_4 GENMASK(7, 0)
#define SVSB_FREQPCTS_FLD_PCT1_5 GENMASK(15, 8)
#define SVSB_FREQPCTS_FLD_PCT2_6 GENMASK(23, 16)
#define SVSB_FREQPCTS_FLD_PCT3_7 GENMASK(31, 24)
/* INTSTS */
#define SVSB_INTSTS_VAL_CLEAN 0x00ffffff
#define SVSB_INTSTS_F0_COMPLETE BIT(0)
#define SVSB_INTSTS_FLD_MONVOP GENMASK(23, 16)
#define SVSB_RUNCONFIG_DEFAULT 0x80000000
/* LIMITVALS */
#define SVSB_LIMITVALS_FLD_DTLO GENMASK(7, 0)
#define SVSB_LIMITVALS_FLD_DTHI GENMASK(15, 8)
#define SVSB_LIMITVALS_FLD_VMIN GENMASK(23, 16)
#define SVSB_LIMITVALS_FLD_VMAX GENMASK(31, 24)
#define SVSB_VAL_DTHI 0x1
#define SVSB_VAL_DTLO 0xfe
/* INTEN */
#define SVSB_INTEN_F0EN BIT(0)
#define SVSB_INTEN_DACK0UPEN BIT(8)
#define SVSB_INTEN_DC0EN BIT(9)
#define SVSB_INTEN_DC1EN BIT(10)
#define SVSB_INTEN_DACK0LOEN BIT(11)
#define SVSB_INTEN_INITPROD_OVF_EN BIT(12)
#define SVSB_INTEN_INITSUM_OVF_EN BIT(14)
#define SVSB_INTEN_MONVOPEN GENMASK(23, 16)
#define SVSB_INTEN_INIT0x (SVSB_INTEN_F0EN | SVSB_INTEN_DACK0UPEN | \
SVSB_INTEN_DC0EN | SVSB_INTEN_DC1EN | \
SVSB_INTEN_DACK0LOEN | \
SVSB_INTEN_INITPROD_OVF_EN | \
SVSB_INTEN_INITSUM_OVF_EN)
/* TSCALCS */
#define SVSB_TSCALCS_FLD_MTS GENMASK(11, 0)
#define SVSB_TSCALCS_FLD_BTS GENMASK(23, 12)
/* INIT2VALS */
#define SVSB_INIT2VALS_FLD_DCVOFFSETIN GENMASK(15, 0)
#define SVSB_INIT2VALS_FLD_AGEVOFFSETIN GENMASK(31, 16)
/* VOPS */
#define SVSB_VOPS_FLD_VOP0_4 GENMASK(7, 0)
#define SVSB_VOPS_FLD_VOP1_5 GENMASK(15, 8)
#define SVSB_VOPS_FLD_VOP2_6 GENMASK(23, 16)
#define SVSB_VOPS_FLD_VOP3_7 GENMASK(31, 24)
/* svs bank related setting */
#define BITS8 8
#define MAX_OPP_ENTRIES 16
@ -262,7 +320,6 @@ static const u32 svs_regs_v2[] = {
* @rst: svs platform reset control
* @efuse_parsing: svs platform efuse parsing function pointer
* @probe: svs platform probe function pointer
* @irqflags: svs platform irq settings flags
* @efuse_max: total number of svs efuse
* @tefuse_max: total number of thermal efuse
* @regs: svs platform registers map
@ -280,7 +337,6 @@ struct svs_platform {
struct reset_control *rst;
bool (*efuse_parsing)(struct svs_platform *svsp);
int (*probe)(struct svs_platform *svsp);
unsigned long irqflags;
size_t efuse_max;
size_t tefuse_max;
const u32 *regs;
@ -294,7 +350,6 @@ struct svs_platform_data {
struct svs_bank *banks;
bool (*efuse_parsing)(struct svs_platform *svsp);
int (*probe)(struct svs_platform *svsp);
unsigned long irqflags;
const u32 *regs;
u32 bank_max;
};
@ -668,8 +723,8 @@ static ssize_t svs_enable_debug_write(struct file *filp,
svsp->pbank = svsb;
svsb->mode_support = SVSB_MODE_ALL_DISABLE;
svs_switch_bank(svsp);
svs_writel_relaxed(svsp, SVSB_EN_OFF, SVSEN);
svs_writel_relaxed(svsp, SVSB_INTSTS_CLEAN, INTSTS);
svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN);
svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS);
spin_unlock_irqrestore(&svs_lock, flags);
svsb->phase = SVSB_PHASE_ERROR;
@ -830,7 +885,7 @@ static void svs_get_bank_volts_v3(struct svs_platform *svsp)
} else if (svsb->type == SVSB_LOW) {
/* volt[turn_pt] + volt[j] ~ volt[opp_count - 1] */
j = svsb->opp_count - 7;
svsb->volt[turn_pt] = vop30 & GENMASK(7, 0);
svsb->volt[turn_pt] = FIELD_GET(SVSB_VOPS_FLD_VOP0_4, vop30);
shift_byte++;
for (i = j; i < svsb->opp_count; i++) {
b_sft = BITS8 * (shift_byte % REG_BYTES);
@ -852,7 +907,7 @@ static void svs_get_bank_volts_v3(struct svs_platform *svsp)
if (svsb->type == SVSB_HIGH) {
/* volt[0] + volt[j] ~ volt[turn_pt - 1] */
j = turn_pt - 7;
svsb->volt[0] = vop30 & GENMASK(7, 0);
svsb->volt[0] = FIELD_GET(SVSB_VOPS_FLD_VOP0_4, vop30);
shift_byte++;
for (i = j; i < turn_pt; i++) {
b_sft = BITS8 * (shift_byte % REG_BYTES);
@ -983,16 +1038,16 @@ static void svs_get_bank_volts_v2(struct svs_platform *svsp)
u32 temp, i;
temp = svs_readl_relaxed(svsp, VOP74);
svsb->volt[14] = (temp >> 24) & GENMASK(7, 0);
svsb->volt[12] = (temp >> 16) & GENMASK(7, 0);
svsb->volt[10] = (temp >> 8) & GENMASK(7, 0);
svsb->volt[8] = (temp & GENMASK(7, 0));
svsb->volt[14] = FIELD_GET(SVSB_VOPS_FLD_VOP3_7, temp);
svsb->volt[12] = FIELD_GET(SVSB_VOPS_FLD_VOP2_6, temp);
svsb->volt[10] = FIELD_GET(SVSB_VOPS_FLD_VOP1_5, temp);
svsb->volt[8] = FIELD_GET(SVSB_VOPS_FLD_VOP0_4, temp);
temp = svs_readl_relaxed(svsp, VOP30);
svsb->volt[6] = (temp >> 24) & GENMASK(7, 0);
svsb->volt[4] = (temp >> 16) & GENMASK(7, 0);
svsb->volt[2] = (temp >> 8) & GENMASK(7, 0);
svsb->volt[0] = (temp & GENMASK(7, 0));
svsb->volt[6] = FIELD_GET(SVSB_VOPS_FLD_VOP3_7, temp);
svsb->volt[4] = FIELD_GET(SVSB_VOPS_FLD_VOP2_6, temp);
svsb->volt[2] = FIELD_GET(SVSB_VOPS_FLD_VOP1_5, temp);
svsb->volt[0] = FIELD_GET(SVSB_VOPS_FLD_VOP0_4, temp);
for (i = 0; i <= 12; i += 2)
svsb->volt[i + 1] = interpolate(svsb->freq_pct[i],
@ -1014,20 +1069,20 @@ static void svs_get_bank_volts_v2(struct svs_platform *svsp)
static void svs_set_bank_freq_pct_v2(struct svs_platform *svsp)
{
struct svs_bank *svsb = svsp->pbank;
u32 freqpct74_val, freqpct30_val;
svs_writel_relaxed(svsp,
(svsb->freq_pct[14] << 24) |
(svsb->freq_pct[12] << 16) |
(svsb->freq_pct[10] << 8) |
svsb->freq_pct[8],
FREQPCT74);
freqpct74_val = FIELD_PREP(SVSB_FREQPCTS_FLD_PCT0_4, svsb->freq_pct[8]) |
FIELD_PREP(SVSB_FREQPCTS_FLD_PCT1_5, svsb->freq_pct[10]) |
FIELD_PREP(SVSB_FREQPCTS_FLD_PCT2_6, svsb->freq_pct[12]) |
FIELD_PREP(SVSB_FREQPCTS_FLD_PCT3_7, svsb->freq_pct[14]);
svs_writel_relaxed(svsp,
(svsb->freq_pct[6] << 24) |
(svsb->freq_pct[4] << 16) |
(svsb->freq_pct[2] << 8) |
svsb->freq_pct[0],
FREQPCT30);
freqpct30_val = FIELD_PREP(SVSB_FREQPCTS_FLD_PCT0_4, svsb->freq_pct[0]) |
FIELD_PREP(SVSB_FREQPCTS_FLD_PCT1_5, svsb->freq_pct[2]) |
FIELD_PREP(SVSB_FREQPCTS_FLD_PCT2_6, svsb->freq_pct[4]) |
FIELD_PREP(SVSB_FREQPCTS_FLD_PCT3_7, svsb->freq_pct[6]);
svs_writel_relaxed(svsp, freqpct74_val, FREQPCT74);
svs_writel_relaxed(svsp, freqpct30_val, FREQPCT30);
}
static void svs_set_bank_phase(struct svs_platform *svsp,
@ -1038,13 +1093,17 @@ static void svs_set_bank_phase(struct svs_platform *svsp,
svs_switch_bank(svsp);
des_char = (svsb->bdes << 8) | svsb->mdes;
des_char = FIELD_PREP(SVSB_DESCHAR_FLD_BDES, svsb->bdes) |
FIELD_PREP(SVSB_DESCHAR_FLD_MDES, svsb->mdes);
svs_writel_relaxed(svsp, des_char, DESCHAR);
temp_char = (svsb->vco << 16) | (svsb->mtdes << 8) | svsb->dvt_fixed;
temp_char = FIELD_PREP(SVSB_TEMPCHAR_FLD_VCO, svsb->vco) |
FIELD_PREP(SVSB_TEMPCHAR_FLD_MTDES, svsb->mtdes) |
FIELD_PREP(SVSB_TEMPCHAR_FLD_DVT_FIXED, svsb->dvt_fixed);
svs_writel_relaxed(svsp, temp_char, TEMPCHAR);
det_char = (svsb->dcbdet << 8) | svsb->dcmdet;
det_char = FIELD_PREP(SVSB_DETCHAR_FLD_DCBDET, svsb->dcbdet) |
FIELD_PREP(SVSB_DETCHAR_FLD_DCMDET, svsb->dcmdet);
svs_writel_relaxed(svsp, det_char, DETCHAR);
svs_writel_relaxed(svsp, svsb->dc_config, DCCONFIG);
@ -1053,33 +1112,37 @@ static void svs_set_bank_phase(struct svs_platform *svsp,
svsb->set_freq_pct(svsp);
limit_vals = (svsb->vmax << 24) | (svsb->vmin << 16) |
(SVSB_DTHI << 8) | SVSB_DTLO;
limit_vals = FIELD_PREP(SVSB_LIMITVALS_FLD_DTLO, SVSB_VAL_DTLO) |
FIELD_PREP(SVSB_LIMITVALS_FLD_DTHI, SVSB_VAL_DTHI) |
FIELD_PREP(SVSB_LIMITVALS_FLD_VMIN, svsb->vmin) |
FIELD_PREP(SVSB_LIMITVALS_FLD_VMAX, svsb->vmax);
svs_writel_relaxed(svsp, limit_vals, LIMITVALS);
svs_writel_relaxed(svsp, SVSB_DET_WINDOW, DETWINDOW);
svs_writel_relaxed(svsp, SVSB_DET_MAX, CONFIG);
svs_writel_relaxed(svsp, svsb->chk_shift, CHKSHIFT);
svs_writel_relaxed(svsp, svsb->ctl0, CTL0);
svs_writel_relaxed(svsp, SVSB_INTSTS_CLEAN, INTSTS);
svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS);
switch (target_phase) {
case SVSB_PHASE_INIT01:
svs_writel_relaxed(svsp, svsb->vboot, VBOOT);
svs_writel_relaxed(svsp, SVSB_INTEN_INIT0x, INTEN);
svs_writel_relaxed(svsp, SVSB_EN_INIT01, SVSEN);
svs_writel_relaxed(svsp, SVSB_PTPEN_INIT01, SVSEN);
break;
case SVSB_PHASE_INIT02:
init2vals = FIELD_PREP(SVSB_INIT2VALS_FLD_AGEVOFFSETIN, svsb->age_voffset_in) |
FIELD_PREP(SVSB_INIT2VALS_FLD_DCVOFFSETIN, svsb->dc_voffset_in);
svs_writel_relaxed(svsp, SVSB_INTEN_INIT0x, INTEN);
init2vals = (svsb->age_voffset_in << 16) | svsb->dc_voffset_in;
svs_writel_relaxed(svsp, init2vals, INIT2VALS);
svs_writel_relaxed(svsp, SVSB_EN_INIT02, SVSEN);
svs_writel_relaxed(svsp, SVSB_PTPEN_INIT02, SVSEN);
break;
case SVSB_PHASE_MON:
ts_calcs = (svsb->bts << 12) | svsb->mts;
ts_calcs = FIELD_PREP(SVSB_TSCALCS_FLD_BTS, svsb->bts) |
FIELD_PREP(SVSB_TSCALCS_FLD_MTS, svsb->mts);
svs_writel_relaxed(svsp, ts_calcs, TSCALCS);
svs_writel_relaxed(svsp, SVSB_INTEN_MONVOPEN, INTEN);
svs_writel_relaxed(svsp, SVSB_EN_MON, SVSEN);
svs_writel_relaxed(svsp, SVSB_PTPEN_MON, SVSEN);
break;
default:
dev_err(svsb->dev, "requested unknown target phase: %u\n",
@ -1115,8 +1178,8 @@ static inline void svs_error_isr_handler(struct svs_platform *svsp)
svs_save_bank_register_data(svsp, SVSB_PHASE_ERROR);
svsb->phase = SVSB_PHASE_ERROR;
svs_writel_relaxed(svsp, SVSB_EN_OFF, SVSEN);
svs_writel_relaxed(svsp, SVSB_INTSTS_CLEAN, INTSTS);
svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN);
svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS);
}
static inline void svs_init01_isr_handler(struct svs_platform *svsp)
@ -1141,8 +1204,8 @@ static inline void svs_init01_isr_handler(struct svs_platform *svsp)
svsb->age_voffset_in = svs_readl_relaxed(svsp, AGEVALUES) &
GENMASK(15, 0);
svs_writel_relaxed(svsp, SVSB_EN_OFF, SVSEN);
svs_writel_relaxed(svsp, SVSB_INTSTS_COMPLETE, INTSTS);
svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN);
svs_writel_relaxed(svsp, SVSB_INTSTS_F0_COMPLETE, INTSTS);
svsb->core_sel &= ~SVSB_DET_CLK_EN;
}
@ -1160,8 +1223,8 @@ static inline void svs_init02_isr_handler(struct svs_platform *svsp)
svsb->phase = SVSB_PHASE_INIT02;
svsb->get_volts(svsp);
svs_writel_relaxed(svsp, SVSB_EN_OFF, SVSEN);
svs_writel_relaxed(svsp, SVSB_INTSTS_COMPLETE, INTSTS);
svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN);
svs_writel_relaxed(svsp, SVSB_INTSTS_F0_COMPLETE, INTSTS);
}
static inline void svs_mon_mode_isr_handler(struct svs_platform *svsp)
@ -1174,7 +1237,7 @@ static inline void svs_mon_mode_isr_handler(struct svs_platform *svsp)
svsb->get_volts(svsp);
svsb->temp = svs_readl_relaxed(svsp, TEMP) & GENMASK(7, 0);
svs_writel_relaxed(svsp, SVSB_INTSTS_MONVOP, INTSTS);
svs_writel_relaxed(svsp, SVSB_INTSTS_FLD_MONVOP, INTSTS);
}
static irqreturn_t svs_isr(int irq, void *data)
@ -1201,13 +1264,13 @@ static irqreturn_t svs_isr(int irq, void *data)
int_sts = svs_readl_relaxed(svsp, INTSTS);
svs_en = svs_readl_relaxed(svsp, SVSEN);
if (int_sts == SVSB_INTSTS_COMPLETE &&
svs_en == SVSB_EN_INIT01)
if (int_sts == SVSB_INTSTS_F0_COMPLETE &&
svs_en == SVSB_PTPEN_INIT01)
svs_init01_isr_handler(svsp);
else if (int_sts == SVSB_INTSTS_COMPLETE &&
svs_en == SVSB_EN_INIT02)
else if (int_sts == SVSB_INTSTS_F0_COMPLETE &&
svs_en == SVSB_PTPEN_INIT02)
svs_init02_isr_handler(svsp);
else if (int_sts & SVSB_INTSTS_MONVOP)
else if (int_sts & SVSB_INTSTS_FLD_MONVOP)
svs_mon_mode_isr_handler(svsp);
else
svs_error_isr_handler(svsp);
@ -1493,8 +1556,8 @@ static int svs_suspend(struct device *dev)
spin_lock_irqsave(&svs_lock, flags);
svsp->pbank = svsb;
svs_switch_bank(svsp);
svs_writel_relaxed(svsp, SVSB_EN_OFF, SVSEN);
svs_writel_relaxed(svsp, SVSB_INTSTS_CLEAN, INTSTS);
svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN);
svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS);
spin_unlock_irqrestore(&svs_lock, flags);
svsb->phase = SVSB_PHASE_ERROR;
@ -1589,7 +1652,7 @@ static int svs_bank_resource_setup(struct svs_platform *svsp)
dev_set_drvdata(svsb->dev, svsp);
ret = dev_pm_opp_of_add_table(svsb->opp_dev);
ret = devm_pm_opp_of_add_table(svsb->opp_dev);
if (ret) {
dev_err(svsb->dev, "add opp table fail: %d\n", ret);
return ret;
@ -1644,11 +1707,36 @@ static int svs_bank_resource_setup(struct svs_platform *svsp)
return 0;
}
static int svs_thermal_efuse_get_data(struct svs_platform *svsp)
{
struct nvmem_cell *cell;
/* Thermal efuse parsing */
cell = nvmem_cell_get(svsp->dev, "t-calibration-data");
if (IS_ERR_OR_NULL(cell)) {
dev_err(svsp->dev, "no \"t-calibration-data\"? %ld\n", PTR_ERR(cell));
return PTR_ERR(cell);
}
svsp->tefuse = nvmem_cell_read(cell, &svsp->tefuse_max);
if (IS_ERR(svsp->tefuse)) {
dev_err(svsp->dev, "cannot read thermal efuse: %ld\n",
PTR_ERR(svsp->tefuse));
nvmem_cell_put(cell);
return PTR_ERR(svsp->tefuse);
}
svsp->tefuse_max /= sizeof(u32);
nvmem_cell_put(cell);
return 0;
}
static bool svs_mt8192_efuse_parsing(struct svs_platform *svsp)
{
struct svs_bank *svsb;
struct nvmem_cell *cell;
u32 idx, i, vmin, golden_temp;
int ret;
for (i = 0; i < svsp->efuse_max; i++)
if (svsp->efuse[i])
@ -1686,24 +1774,9 @@ static bool svs_mt8192_efuse_parsing(struct svs_platform *svsp)
svsb->vmax += svsb->dvt_fixed;
}
/* Thermal efuse parsing */
cell = nvmem_cell_get(svsp->dev, "t-calibration-data");
if (IS_ERR_OR_NULL(cell)) {
dev_err(svsp->dev, "no \"t-calibration-data\"? %ld\n",
PTR_ERR(cell));
ret = svs_thermal_efuse_get_data(svsp);
if (ret)
return false;
}
svsp->tefuse = nvmem_cell_read(cell, &svsp->tefuse_max);
if (IS_ERR(svsp->tefuse)) {
dev_err(svsp->dev, "cannot read thermal efuse: %ld\n",
PTR_ERR(svsp->tefuse));
nvmem_cell_put(cell);
return false;
}
svsp->tefuse_max /= sizeof(u32);
nvmem_cell_put(cell);
for (i = 0; i < svsp->tefuse_max; i++)
if (svsp->tefuse[i] != 0)
@ -1726,11 +1799,11 @@ static bool svs_mt8192_efuse_parsing(struct svs_platform *svsp)
static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp)
{
struct svs_bank *svsb;
struct nvmem_cell *cell;
int format[6], x_roomt[6], o_vtsmcu[5], o_vtsabb, tb_roomt = 0;
int adc_ge_t, adc_oe_t, ge, oe, gain, degc_cali, adc_cali_en_t;
int o_slope, o_slope_sign, ts_id;
u32 idx, i, ft_pgm, mts, temp0, temp1, temp2;
int ret;
for (i = 0; i < svsp->efuse_max; i++)
if (svsp->efuse[i])
@ -1806,24 +1879,9 @@ static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp)
}
}
/* Get thermal efuse by nvmem */
cell = nvmem_cell_get(svsp->dev, "t-calibration-data");
if (IS_ERR(cell)) {
dev_err(svsp->dev, "no \"t-calibration-data\"? %ld\n",
PTR_ERR(cell));
goto remove_mt8183_svsb_mon_mode;
}
svsp->tefuse = nvmem_cell_read(cell, &svsp->tefuse_max);
if (IS_ERR(svsp->tefuse)) {
dev_err(svsp->dev, "cannot read thermal efuse: %ld\n",
PTR_ERR(svsp->tefuse));
nvmem_cell_put(cell);
goto remove_mt8183_svsb_mon_mode;
}
svsp->tefuse_max /= sizeof(u32);
nvmem_cell_put(cell);
ret = svs_thermal_efuse_get_data(svsp);
if (ret)
return false;
/* Thermal efuse parsing */
adc_ge_t = (svsp->tefuse[1] >> 22) & GENMASK(9, 0);
@ -2244,7 +2302,6 @@ static const struct svs_platform_data svs_mt8192_platform_data = {
.banks = svs_mt8192_banks,
.efuse_parsing = svs_mt8192_efuse_parsing,
.probe = svs_mt8192_platform_probe,
.irqflags = IRQF_TRIGGER_HIGH,
.regs = svs_regs_v2,
.bank_max = ARRAY_SIZE(svs_mt8192_banks),
};
@ -2254,7 +2311,6 @@ static const struct svs_platform_data svs_mt8183_platform_data = {
.banks = svs_mt8183_banks,
.efuse_parsing = svs_mt8183_efuse_parsing,
.probe = svs_mt8183_platform_probe,
.irqflags = IRQF_TRIGGER_LOW,
.regs = svs_regs_v2,
.bank_max = ARRAY_SIZE(svs_mt8183_banks),
};
@ -2292,7 +2348,6 @@ static struct svs_platform *svs_platform_probe(struct platform_device *pdev)
svsp->banks = svsp_data->banks;
svsp->efuse_parsing = svsp_data->efuse_parsing;
svsp->probe = svsp_data->probe;
svsp->irqflags = svsp_data->irqflags;
svsp->regs = svsp_data->regs;
svsp->bank_max = svsp_data->bank_max;
@ -2306,8 +2361,7 @@ static struct svs_platform *svs_platform_probe(struct platform_device *pdev)
static int svs_probe(struct platform_device *pdev)
{
struct svs_platform *svsp;
unsigned int svsp_irq;
int ret;
int svsp_irq, ret;
svsp = svs_platform_probe(pdev);
if (IS_ERR(svsp))
@ -2325,10 +2379,14 @@ static int svs_probe(struct platform_device *pdev)
goto svs_probe_free_resource;
}
svsp_irq = irq_of_parse_and_map(svsp->dev->of_node, 0);
svsp_irq = platform_get_irq(pdev, 0);
if (svsp_irq < 0) {
ret = svsp_irq;
goto svs_probe_free_resource;
}
ret = devm_request_threaded_irq(svsp->dev, svsp_irq, NULL, svs_isr,
svsp->irqflags | IRQF_ONESHOT,
svsp->name, svsp);
IRQF_ONESHOT, svsp->name, svsp);
if (ret) {
dev_err(svsp->dev, "register irq(%d) failed: %d\n",
svsp_irq, ret);
@ -2392,7 +2450,7 @@ static struct platform_driver svs_driver = {
.driver = {
.name = "mtk-svs",
.pm = &svs_pm_ops,
.of_match_table = of_match_ptr(svs_of_match),
.of_match_table = svs_of_match,
},
};

View File

@ -129,7 +129,7 @@ config QCOM_RPMHPD
config QCOM_RPMPD
tristate "Qualcomm RPM Power domain driver"
depends on PM
depends on PM && OF
depends on QCOM_SMD_RPM
select PM_GENERIC_DOMAINS
select PM_GENERIC_DOMAINS_OF

View File

@ -5,6 +5,8 @@
* Author: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>, based on
* previous work of Thara Gopinath and msm-4.9 downstream sources.
*/
#include <linux/err.h>
#include <linux/interconnect.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@ -13,6 +15,7 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/regmap.h>
#include <linux/sizes.h>
/*
@ -31,33 +34,44 @@
/* Internal sampling clock frequency */
#define HW_TIMER_HZ 19200000
#define BWMON_GLOBAL_IRQ_STATUS 0x0
#define BWMON_GLOBAL_IRQ_CLEAR 0x8
#define BWMON_GLOBAL_IRQ_ENABLE 0xc
#define BWMON_GLOBAL_IRQ_ENABLE_ENABLE BIT(0)
#define BWMON_V4_GLOBAL_IRQ_CLEAR 0x008
#define BWMON_V4_GLOBAL_IRQ_ENABLE 0x00c
/*
* All values here and further are matching regmap fields, so without absolute
* register offsets.
*/
#define BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE BIT(0)
#define BWMON_IRQ_STATUS 0x100
#define BWMON_IRQ_STATUS_ZONE_SHIFT 4
#define BWMON_IRQ_CLEAR 0x108
#define BWMON_IRQ_ENABLE 0x10c
#define BWMON_IRQ_ENABLE_ZONE1_SHIFT 5
#define BWMON_IRQ_ENABLE_ZONE2_SHIFT 6
#define BWMON_IRQ_ENABLE_ZONE3_SHIFT 7
#define BWMON_IRQ_ENABLE_MASK (BIT(BWMON_IRQ_ENABLE_ZONE1_SHIFT) | \
BIT(BWMON_IRQ_ENABLE_ZONE3_SHIFT))
#define BWMON_V4_IRQ_STATUS 0x100
#define BWMON_V4_IRQ_CLEAR 0x108
#define BWMON_ENABLE 0x2a0
#define BWMON_V4_IRQ_ENABLE 0x10c
#define BWMON_IRQ_ENABLE_MASK (BIT(1) | BIT(3))
#define BWMON_V5_IRQ_STATUS 0x000
#define BWMON_V5_IRQ_CLEAR 0x008
#define BWMON_V5_IRQ_ENABLE 0x00c
#define BWMON_V4_ENABLE 0x2a0
#define BWMON_V5_ENABLE 0x010
#define BWMON_ENABLE_ENABLE BIT(0)
#define BWMON_CLEAR 0x2a4
#define BWMON_V4_CLEAR 0x2a4
#define BWMON_V5_CLEAR 0x014
#define BWMON_CLEAR_CLEAR BIT(0)
#define BWMON_CLEAR_CLEAR_ALL BIT(1)
#define BWMON_SAMPLE_WINDOW 0x2a8
#define BWMON_THRESHOLD_HIGH 0x2ac
#define BWMON_THRESHOLD_MED 0x2b0
#define BWMON_THRESHOLD_LOW 0x2b4
#define BWMON_V4_SAMPLE_WINDOW 0x2a8
#define BWMON_V5_SAMPLE_WINDOW 0x020
#define BWMON_ZONE_ACTIONS 0x2b8
#define BWMON_V4_THRESHOLD_HIGH 0x2ac
#define BWMON_V4_THRESHOLD_MED 0x2b0
#define BWMON_V4_THRESHOLD_LOW 0x2b4
#define BWMON_V5_THRESHOLD_HIGH 0x024
#define BWMON_V5_THRESHOLD_MED 0x028
#define BWMON_V5_THRESHOLD_LOW 0x02c
#define BWMON_V4_ZONE_ACTIONS 0x2b8
#define BWMON_V5_ZONE_ACTIONS 0x030
/*
* Actions to perform on some zone 'z' when current zone hits the threshold:
* Increment counter of zone 'z'
@ -83,55 +97,244 @@
BWMON_ZONE_ACTIONS_CLEAR(2) | \
BWMON_ZONE_ACTIONS_CLEAR(1) | \
BWMON_ZONE_ACTIONS_CLEAR(0))
/* Value for BWMON_ZONE_ACTIONS */
#define BWMON_ZONE_ACTIONS_DEFAULT (BWMON_ZONE_ACTIONS_ZONE0 | \
BWMON_ZONE_ACTIONS_ZONE1 << 8 | \
BWMON_ZONE_ACTIONS_ZONE2 << 16 | \
BWMON_ZONE_ACTIONS_ZONE3 << 24)
/*
* There is no clear documentation/explanation of BWMON_THRESHOLD_COUNT
* There is no clear documentation/explanation of BWMON_V4_THRESHOLD_COUNT
* register. Based on observations, this is number of times one threshold has to
* be reached, to trigger interrupt in given zone.
*
* 0xff are maximum values meant to ignore the zones 0 and 2.
*/
#define BWMON_THRESHOLD_COUNT 0x2bc
#define BWMON_THRESHOLD_COUNT_ZONE1_SHIFT 8
#define BWMON_THRESHOLD_COUNT_ZONE2_SHIFT 16
#define BWMON_THRESHOLD_COUNT_ZONE3_SHIFT 24
#define BWMON_V4_THRESHOLD_COUNT 0x2bc
#define BWMON_V5_THRESHOLD_COUNT 0x034
#define BWMON_THRESHOLD_COUNT_ZONE0_DEFAULT 0xff
#define BWMON_THRESHOLD_COUNT_ZONE2_DEFAULT 0xff
/* BWMONv4 count registers use count unit of 64 kB */
#define BWMON_COUNT_UNIT_KB 64
#define BWMON_ZONE_COUNT 0x2d8
#define BWMON_ZONE_MAX(zone) (0x2e0 + 4 * (zone))
#define BWMON_V4_ZONE_MAX(zone) (0x2e0 + 4 * (zone))
#define BWMON_V5_ZONE_MAX(zone) (0x044 + 4 * (zone))
/* Quirks for specific BWMON types */
#define BWMON_HAS_GLOBAL_IRQ BIT(0)
#define BWMON_NEEDS_FORCE_CLEAR BIT(1)
enum bwmon_fields {
F_GLOBAL_IRQ_CLEAR,
F_GLOBAL_IRQ_ENABLE,
F_IRQ_STATUS,
F_IRQ_CLEAR,
F_IRQ_ENABLE,
F_ENABLE,
F_CLEAR,
F_SAMPLE_WINDOW,
F_THRESHOLD_HIGH,
F_THRESHOLD_MED,
F_THRESHOLD_LOW,
F_ZONE_ACTIONS_ZONE0,
F_ZONE_ACTIONS_ZONE1,
F_ZONE_ACTIONS_ZONE2,
F_ZONE_ACTIONS_ZONE3,
F_THRESHOLD_COUNT_ZONE0,
F_THRESHOLD_COUNT_ZONE1,
F_THRESHOLD_COUNT_ZONE2,
F_THRESHOLD_COUNT_ZONE3,
F_ZONE0_MAX,
F_ZONE1_MAX,
F_ZONE2_MAX,
F_ZONE3_MAX,
F_NUM_FIELDS
};
struct icc_bwmon_data {
unsigned int sample_ms;
unsigned int count_unit_kb; /* kbytes */
unsigned int default_highbw_kbps;
unsigned int default_medbw_kbps;
unsigned int default_lowbw_kbps;
u8 zone1_thres_count;
u8 zone3_thres_count;
unsigned int quirks;
const struct regmap_config *regmap_cfg;
const struct reg_field *regmap_fields;
};
struct icc_bwmon {
struct device *dev;
void __iomem *base;
const struct icc_bwmon_data *data;
int irq;
unsigned int default_lowbw_kbps;
unsigned int sample_ms;
struct regmap *regmap;
struct regmap_field *regs[F_NUM_FIELDS];
unsigned int max_bw_kbps;
unsigned int min_bw_kbps;
unsigned int target_kbps;
unsigned int current_kbps;
};
static void bwmon_clear_counters(struct icc_bwmon *bwmon)
/* BWMON v4 */
static const struct reg_field msm8998_bwmon_reg_fields[] = {
[F_GLOBAL_IRQ_CLEAR] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_CLEAR, 0, 0),
[F_GLOBAL_IRQ_ENABLE] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_ENABLE, 0, 0),
[F_IRQ_STATUS] = REG_FIELD(BWMON_V4_IRQ_STATUS, 4, 7),
[F_IRQ_CLEAR] = REG_FIELD(BWMON_V4_IRQ_CLEAR, 4, 7),
[F_IRQ_ENABLE] = REG_FIELD(BWMON_V4_IRQ_ENABLE, 4, 7),
/* F_ENABLE covers entire register to disable other features */
[F_ENABLE] = REG_FIELD(BWMON_V4_ENABLE, 0, 31),
[F_CLEAR] = REG_FIELD(BWMON_V4_CLEAR, 0, 1),
[F_SAMPLE_WINDOW] = REG_FIELD(BWMON_V4_SAMPLE_WINDOW, 0, 23),
[F_THRESHOLD_HIGH] = REG_FIELD(BWMON_V4_THRESHOLD_HIGH, 0, 11),
[F_THRESHOLD_MED] = REG_FIELD(BWMON_V4_THRESHOLD_MED, 0, 11),
[F_THRESHOLD_LOW] = REG_FIELD(BWMON_V4_THRESHOLD_LOW, 0, 11),
[F_ZONE_ACTIONS_ZONE0] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 0, 7),
[F_ZONE_ACTIONS_ZONE1] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 8, 15),
[F_ZONE_ACTIONS_ZONE2] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 16, 23),
[F_ZONE_ACTIONS_ZONE3] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 24, 31),
[F_THRESHOLD_COUNT_ZONE0] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 0, 7),
[F_THRESHOLD_COUNT_ZONE1] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 8, 15),
[F_THRESHOLD_COUNT_ZONE2] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 16, 23),
[F_THRESHOLD_COUNT_ZONE3] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 24, 31),
[F_ZONE0_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(0), 0, 11),
[F_ZONE1_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(1), 0, 11),
[F_ZONE2_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(2), 0, 11),
[F_ZONE3_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(3), 0, 11),
};
static const struct regmap_range msm8998_bwmon_reg_noread_ranges[] = {
regmap_reg_range(BWMON_V4_GLOBAL_IRQ_CLEAR, BWMON_V4_GLOBAL_IRQ_CLEAR),
regmap_reg_range(BWMON_V4_IRQ_CLEAR, BWMON_V4_IRQ_CLEAR),
regmap_reg_range(BWMON_V4_CLEAR, BWMON_V4_CLEAR),
};
static const struct regmap_access_table msm8998_bwmon_reg_read_table = {
.no_ranges = msm8998_bwmon_reg_noread_ranges,
.n_no_ranges = ARRAY_SIZE(msm8998_bwmon_reg_noread_ranges),
};
static const struct regmap_range msm8998_bwmon_reg_volatile_ranges[] = {
regmap_reg_range(BWMON_V4_IRQ_STATUS, BWMON_V4_IRQ_STATUS),
regmap_reg_range(BWMON_V4_ZONE_MAX(0), BWMON_V4_ZONE_MAX(3)),
};
static const struct regmap_access_table msm8998_bwmon_reg_volatile_table = {
.yes_ranges = msm8998_bwmon_reg_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(msm8998_bwmon_reg_volatile_ranges),
};
/*
* Fill the cache for non-readable registers only as rest does not really
* matter and can be read from the device.
*/
static const struct reg_default msm8998_bwmon_reg_defaults[] = {
{ BWMON_V4_GLOBAL_IRQ_CLEAR, 0x0 },
{ BWMON_V4_IRQ_CLEAR, 0x0 },
{ BWMON_V4_CLEAR, 0x0 },
};
static const struct regmap_config msm8998_bwmon_regmap_cfg = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
/*
* No concurrent access expected - driver has one interrupt handler,
* regmap is not shared, no driver or user-space API.
*/
.disable_locking = true,
.rd_table = &msm8998_bwmon_reg_read_table,
.volatile_table = &msm8998_bwmon_reg_volatile_table,
.reg_defaults = msm8998_bwmon_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(msm8998_bwmon_reg_defaults),
/*
* Cache is necessary for using regmap fields with non-readable
* registers.
*/
.cache_type = REGCACHE_RBTREE,
};
/* BWMON v5 */
static const struct reg_field sdm845_llcc_bwmon_reg_fields[] = {
[F_GLOBAL_IRQ_CLEAR] = {},
[F_GLOBAL_IRQ_ENABLE] = {},
[F_IRQ_STATUS] = REG_FIELD(BWMON_V5_IRQ_STATUS, 0, 3),
[F_IRQ_CLEAR] = REG_FIELD(BWMON_V5_IRQ_CLEAR, 0, 3),
[F_IRQ_ENABLE] = REG_FIELD(BWMON_V5_IRQ_ENABLE, 0, 3),
/* F_ENABLE covers entire register to disable other features */
[F_ENABLE] = REG_FIELD(BWMON_V5_ENABLE, 0, 31),
[F_CLEAR] = REG_FIELD(BWMON_V5_CLEAR, 0, 1),
[F_SAMPLE_WINDOW] = REG_FIELD(BWMON_V5_SAMPLE_WINDOW, 0, 19),
[F_THRESHOLD_HIGH] = REG_FIELD(BWMON_V5_THRESHOLD_HIGH, 0, 11),
[F_THRESHOLD_MED] = REG_FIELD(BWMON_V5_THRESHOLD_MED, 0, 11),
[F_THRESHOLD_LOW] = REG_FIELD(BWMON_V5_THRESHOLD_LOW, 0, 11),
[F_ZONE_ACTIONS_ZONE0] = REG_FIELD(BWMON_V5_ZONE_ACTIONS, 0, 7),
[F_ZONE_ACTIONS_ZONE1] = REG_FIELD(BWMON_V5_ZONE_ACTIONS, 8, 15),
[F_ZONE_ACTIONS_ZONE2] = REG_FIELD(BWMON_V5_ZONE_ACTIONS, 16, 23),
[F_ZONE_ACTIONS_ZONE3] = REG_FIELD(BWMON_V5_ZONE_ACTIONS, 24, 31),
[F_THRESHOLD_COUNT_ZONE0] = REG_FIELD(BWMON_V5_THRESHOLD_COUNT, 0, 7),
[F_THRESHOLD_COUNT_ZONE1] = REG_FIELD(BWMON_V5_THRESHOLD_COUNT, 8, 15),
[F_THRESHOLD_COUNT_ZONE2] = REG_FIELD(BWMON_V5_THRESHOLD_COUNT, 16, 23),
[F_THRESHOLD_COUNT_ZONE3] = REG_FIELD(BWMON_V5_THRESHOLD_COUNT, 24, 31),
[F_ZONE0_MAX] = REG_FIELD(BWMON_V5_ZONE_MAX(0), 0, 11),
[F_ZONE1_MAX] = REG_FIELD(BWMON_V5_ZONE_MAX(1), 0, 11),
[F_ZONE2_MAX] = REG_FIELD(BWMON_V5_ZONE_MAX(2), 0, 11),
[F_ZONE3_MAX] = REG_FIELD(BWMON_V5_ZONE_MAX(3), 0, 11),
};
static const struct regmap_range sdm845_llcc_bwmon_reg_noread_ranges[] = {
regmap_reg_range(BWMON_V5_IRQ_CLEAR, BWMON_V5_IRQ_CLEAR),
regmap_reg_range(BWMON_V5_CLEAR, BWMON_V5_CLEAR),
};
static const struct regmap_access_table sdm845_llcc_bwmon_reg_read_table = {
.no_ranges = sdm845_llcc_bwmon_reg_noread_ranges,
.n_no_ranges = ARRAY_SIZE(sdm845_llcc_bwmon_reg_noread_ranges),
};
static const struct regmap_range sdm845_llcc_bwmon_reg_volatile_ranges[] = {
regmap_reg_range(BWMON_V5_IRQ_STATUS, BWMON_V5_IRQ_STATUS),
regmap_reg_range(BWMON_V5_ZONE_MAX(0), BWMON_V5_ZONE_MAX(3)),
};
static const struct regmap_access_table sdm845_llcc_bwmon_reg_volatile_table = {
.yes_ranges = sdm845_llcc_bwmon_reg_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(sdm845_llcc_bwmon_reg_volatile_ranges),
};
/*
* Fill the cache for non-readable registers only as rest does not really
* matter and can be read from the device.
*/
static const struct reg_default sdm845_llcc_bwmon_reg_defaults[] = {
{ BWMON_V5_IRQ_CLEAR, 0x0 },
{ BWMON_V5_CLEAR, 0x0 },
};
static const struct regmap_config sdm845_llcc_bwmon_regmap_cfg = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
/*
* No concurrent access expected - driver has one interrupt handler,
* regmap is not shared, no driver or user-space API.
*/
.disable_locking = true,
.rd_table = &sdm845_llcc_bwmon_reg_read_table,
.volatile_table = &sdm845_llcc_bwmon_reg_volatile_table,
.reg_defaults = sdm845_llcc_bwmon_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(sdm845_llcc_bwmon_reg_defaults),
/*
* Cache is necessary for using regmap fields with non-readable
* registers.
*/
.cache_type = REGCACHE_RBTREE,
};
static void bwmon_clear_counters(struct icc_bwmon *bwmon, bool clear_all)
{
unsigned int val = BWMON_CLEAR_CLEAR;
if (clear_all)
val |= BWMON_CLEAR_CLEAR_ALL;
/*
* Clear counters. The order and barriers are
* important. Quoting downstream Qualcomm msm-4.9 tree:
@ -140,7 +343,9 @@ static void bwmon_clear_counters(struct icc_bwmon *bwmon)
* region. So, we need to make sure the counter clear is completed
* before we try to clear the IRQ or do any other counter operations.
*/
writel(BWMON_CLEAR_CLEAR, bwmon->base + BWMON_CLEAR);
regmap_field_force_write(bwmon->regs[F_CLEAR], val);
if (bwmon->data->quirks & BWMON_NEEDS_FORCE_CLEAR)
regmap_field_force_write(bwmon->regs[F_CLEAR], 0);
}
static void bwmon_clear_irq(struct icc_bwmon *bwmon)
@ -161,76 +366,91 @@ static void bwmon_clear_irq(struct icc_bwmon *bwmon)
* clearing here so that local writes don't happen before the
* interrupt is cleared.
*/
writel(BWMON_IRQ_ENABLE_MASK, bwmon->base + BWMON_IRQ_CLEAR);
writel(BIT(0), bwmon->base + BWMON_GLOBAL_IRQ_CLEAR);
regmap_field_force_write(bwmon->regs[F_IRQ_CLEAR], BWMON_IRQ_ENABLE_MASK);
if (bwmon->data->quirks & BWMON_NEEDS_FORCE_CLEAR)
regmap_field_force_write(bwmon->regs[F_IRQ_CLEAR], 0);
if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ)
regmap_field_force_write(bwmon->regs[F_GLOBAL_IRQ_CLEAR],
BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE);
}
static void bwmon_disable(struct icc_bwmon *bwmon)
{
/* Disable interrupts. Strict ordering, see bwmon_clear_irq(). */
writel(0x0, bwmon->base + BWMON_GLOBAL_IRQ_ENABLE);
writel(0x0, bwmon->base + BWMON_IRQ_ENABLE);
if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ)
regmap_field_write(bwmon->regs[F_GLOBAL_IRQ_ENABLE], 0x0);
regmap_field_write(bwmon->regs[F_IRQ_ENABLE], 0x0);
/*
* Disable bwmon. Must happen before bwmon_clear_irq() to avoid spurious
* IRQ.
*/
writel(0x0, bwmon->base + BWMON_ENABLE);
regmap_field_write(bwmon->regs[F_ENABLE], 0x0);
}
static void bwmon_enable(struct icc_bwmon *bwmon, unsigned int irq_enable)
{
/* Enable interrupts */
writel(BWMON_GLOBAL_IRQ_ENABLE_ENABLE,
bwmon->base + BWMON_GLOBAL_IRQ_ENABLE);
writel(irq_enable, bwmon->base + BWMON_IRQ_ENABLE);
if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ)
regmap_field_write(bwmon->regs[F_GLOBAL_IRQ_ENABLE],
BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE);
regmap_field_write(bwmon->regs[F_IRQ_ENABLE], irq_enable);
/* Enable bwmon */
writel(BWMON_ENABLE_ENABLE, bwmon->base + BWMON_ENABLE);
regmap_field_write(bwmon->regs[F_ENABLE], BWMON_ENABLE_ENABLE);
}
static unsigned int bwmon_kbps_to_count(unsigned int kbps)
{
return kbps / BWMON_COUNT_UNIT_KB;
}
static void bwmon_set_threshold(struct icc_bwmon *bwmon, unsigned int reg,
static unsigned int bwmon_kbps_to_count(struct icc_bwmon *bwmon,
unsigned int kbps)
{
return kbps / bwmon->data->count_unit_kb;
}
static void bwmon_set_threshold(struct icc_bwmon *bwmon,
struct regmap_field *reg, unsigned int kbps)
{
unsigned int thres;
thres = mult_frac(bwmon_kbps_to_count(kbps), bwmon->sample_ms,
MSEC_PER_SEC);
writel_relaxed(thres, bwmon->base + reg);
thres = mult_frac(bwmon_kbps_to_count(bwmon, kbps),
bwmon->data->sample_ms, MSEC_PER_SEC);
regmap_field_write(reg, thres);
}
static void bwmon_start(struct icc_bwmon *bwmon,
const struct icc_bwmon_data *data)
static void bwmon_start(struct icc_bwmon *bwmon)
{
unsigned int thres_count;
const struct icc_bwmon_data *data = bwmon->data;
int window;
bwmon_clear_counters(bwmon);
bwmon_clear_counters(bwmon, true);
window = mult_frac(bwmon->sample_ms, HW_TIMER_HZ, MSEC_PER_SEC);
/* Maximum sampling window: 0xfffff */
writel_relaxed(window, bwmon->base + BWMON_SAMPLE_WINDOW);
window = mult_frac(bwmon->data->sample_ms, HW_TIMER_HZ, MSEC_PER_SEC);
/* Maximum sampling window: 0xffffff for v4 and 0xfffff for v5 */
regmap_field_write(bwmon->regs[F_SAMPLE_WINDOW], window);
bwmon_set_threshold(bwmon, BWMON_THRESHOLD_HIGH,
bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_HIGH],
data->default_highbw_kbps);
bwmon_set_threshold(bwmon, BWMON_THRESHOLD_MED,
bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_MED],
data->default_medbw_kbps);
bwmon_set_threshold(bwmon, BWMON_THRESHOLD_LOW,
bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_LOW],
data->default_lowbw_kbps);
thres_count = data->zone3_thres_count << BWMON_THRESHOLD_COUNT_ZONE3_SHIFT |
BWMON_THRESHOLD_COUNT_ZONE2_DEFAULT << BWMON_THRESHOLD_COUNT_ZONE2_SHIFT |
data->zone1_thres_count << BWMON_THRESHOLD_COUNT_ZONE1_SHIFT |
BWMON_THRESHOLD_COUNT_ZONE0_DEFAULT;
writel_relaxed(thres_count, bwmon->base + BWMON_THRESHOLD_COUNT);
writel_relaxed(BWMON_ZONE_ACTIONS_DEFAULT,
bwmon->base + BWMON_ZONE_ACTIONS);
/* Write barriers in bwmon_clear_irq() */
regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE0],
BWMON_THRESHOLD_COUNT_ZONE0_DEFAULT);
regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE1],
data->zone1_thres_count);
regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE2],
BWMON_THRESHOLD_COUNT_ZONE2_DEFAULT);
regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE3],
data->zone3_thres_count);
regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE0],
BWMON_ZONE_ACTIONS_ZONE0);
regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE1],
BWMON_ZONE_ACTIONS_ZONE1);
regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE2],
BWMON_ZONE_ACTIONS_ZONE2);
regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE3],
BWMON_ZONE_ACTIONS_ZONE3);
bwmon_clear_irq(bwmon);
bwmon_enable(bwmon, BWMON_IRQ_ENABLE_MASK);
@ -242,7 +462,9 @@ static irqreturn_t bwmon_intr(int irq, void *dev_id)
unsigned int status, max;
int zone;
status = readl(bwmon->base + BWMON_IRQ_STATUS);
if (regmap_field_read(bwmon->regs[F_IRQ_STATUS], &status))
return IRQ_NONE;
status &= BWMON_IRQ_ENABLE_MASK;
if (!status) {
/*
@ -259,15 +481,18 @@ static irqreturn_t bwmon_intr(int irq, void *dev_id)
bwmon_disable(bwmon);
zone = get_bitmask_order(status >> BWMON_IRQ_STATUS_ZONE_SHIFT) - 1;
zone = get_bitmask_order(status) - 1;
/*
* Zone max bytes count register returns count units within sampling
* window. Downstream kernel for BWMONv4 (called BWMON type 2 in
* downstream) always increments the max bytes count by one.
*/
max = readl(bwmon->base + BWMON_ZONE_MAX(zone)) + 1;
max *= BWMON_COUNT_UNIT_KB;
bwmon->target_kbps = mult_frac(max, MSEC_PER_SEC, bwmon->sample_ms);
if (regmap_field_read(bwmon->regs[F_ZONE0_MAX + zone], &max))
return IRQ_NONE;
max += 1;
max *= bwmon->data->count_unit_kb;
bwmon->target_kbps = mult_frac(max, MSEC_PER_SEC, bwmon->data->sample_ms);
return IRQ_WAKE_THREAD;
}
@ -297,16 +522,17 @@ static irqreturn_t bwmon_intr_thread(int irq, void *dev_id)
up_kbps = bwmon->target_kbps + 1;
if (bwmon->target_kbps >= bwmon->max_bw_kbps)
irq_enable = BIT(BWMON_IRQ_ENABLE_ZONE1_SHIFT);
irq_enable = BIT(1);
else if (bwmon->target_kbps <= bwmon->min_bw_kbps)
irq_enable = BIT(BWMON_IRQ_ENABLE_ZONE3_SHIFT);
irq_enable = BIT(3);
else
irq_enable = BWMON_IRQ_ENABLE_MASK;
bwmon_set_threshold(bwmon, BWMON_THRESHOLD_HIGH, up_kbps);
bwmon_set_threshold(bwmon, BWMON_THRESHOLD_MED, down_kbps);
/* Write barriers in bwmon_clear_counters() */
bwmon_clear_counters(bwmon);
bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_HIGH],
up_kbps);
bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_MED],
down_kbps);
bwmon_clear_counters(bwmon, false);
bwmon_clear_irq(bwmon);
bwmon_enable(bwmon, irq_enable);
@ -324,25 +550,47 @@ out:
return IRQ_HANDLED;
}
static int bwmon_init_regmap(struct platform_device *pdev,
struct icc_bwmon *bwmon)
{
struct device *dev = &pdev->dev;
void __iomem *base;
struct regmap *map;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return dev_err_probe(dev, PTR_ERR(base),
"failed to map bwmon registers\n");
map = devm_regmap_init_mmio(dev, base, bwmon->data->regmap_cfg);
if (IS_ERR(map))
return dev_err_probe(dev, PTR_ERR(map),
"failed to initialize regmap\n");
BUILD_BUG_ON(ARRAY_SIZE(msm8998_bwmon_reg_fields) != F_NUM_FIELDS);
BUILD_BUG_ON(ARRAY_SIZE(sdm845_llcc_bwmon_reg_fields) != F_NUM_FIELDS);
return devm_regmap_field_bulk_alloc(dev, map, bwmon->regs,
bwmon->data->regmap_fields,
F_NUM_FIELDS);
}
static int bwmon_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct dev_pm_opp *opp;
struct icc_bwmon *bwmon;
const struct icc_bwmon_data *data;
int ret;
bwmon = devm_kzalloc(dev, sizeof(*bwmon), GFP_KERNEL);
if (!bwmon)
return -ENOMEM;
data = of_device_get_match_data(dev);
bwmon->data = of_device_get_match_data(dev);
bwmon->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(bwmon->base)) {
dev_err(dev, "failed to map bwmon registers\n");
return PTR_ERR(bwmon->base);
}
ret = bwmon_init_regmap(pdev, bwmon);
if (ret)
return ret;
bwmon->irq = platform_get_irq(pdev, 0);
if (bwmon->irq < 0)
@ -362,8 +610,6 @@ static int bwmon_probe(struct platform_device *pdev)
if (IS_ERR(opp))
return dev_err_probe(dev, ret, "failed to find min peak bandwidth\n");
bwmon->sample_ms = data->sample_ms;
bwmon->default_lowbw_kbps = data->default_lowbw_kbps;
bwmon->dev = dev;
bwmon_disable(bwmon);
@ -374,7 +620,7 @@ static int bwmon_probe(struct platform_device *pdev)
return dev_err_probe(dev, ret, "failed to request IRQ\n");
platform_set_drvdata(pdev, bwmon);
bwmon_start(bwmon, data);
bwmon_start(bwmon);
return 0;
}
@ -388,18 +634,55 @@ static int bwmon_remove(struct platform_device *pdev)
return 0;
}
/* BWMON v4 */
static const struct icc_bwmon_data msm8998_bwmon_data = {
.sample_ms = 4,
.count_unit_kb = 64,
.default_highbw_kbps = 4800 * 1024, /* 4.8 GBps */
.default_medbw_kbps = 512 * 1024, /* 512 MBps */
.default_lowbw_kbps = 0,
.zone1_thres_count = 16,
.zone3_thres_count = 1,
.quirks = BWMON_HAS_GLOBAL_IRQ,
.regmap_fields = msm8998_bwmon_reg_fields,
.regmap_cfg = &msm8998_bwmon_regmap_cfg,
};
static const struct icc_bwmon_data sdm845_llcc_bwmon_data = {
.sample_ms = 4,
.count_unit_kb = 1024,
.default_highbw_kbps = 800 * 1024, /* 800 MBps */
.default_medbw_kbps = 256 * 1024, /* 256 MBps */
.default_lowbw_kbps = 0,
.zone1_thres_count = 16,
.zone3_thres_count = 1,
.regmap_fields = sdm845_llcc_bwmon_reg_fields,
.regmap_cfg = &sdm845_llcc_bwmon_regmap_cfg,
};
static const struct icc_bwmon_data sc7280_llcc_bwmon_data = {
.sample_ms = 4,
.count_unit_kb = 64,
.default_highbw_kbps = 800 * 1024, /* 800 MBps */
.default_medbw_kbps = 256 * 1024, /* 256 MBps */
.default_lowbw_kbps = 0,
.zone1_thres_count = 16,
.zone3_thres_count = 1,
.quirks = BWMON_NEEDS_FORCE_CLEAR,
.regmap_fields = sdm845_llcc_bwmon_reg_fields,
.regmap_cfg = &sdm845_llcc_bwmon_regmap_cfg,
};
static const struct of_device_id bwmon_of_match[] = {
{ .compatible = "qcom,msm8998-bwmon", .data = &msm8998_bwmon_data },
{
.compatible = "qcom,msm8998-bwmon",
.data = &msm8998_bwmon_data
}, {
.compatible = "qcom,sdm845-llcc-bwmon",
.data = &sdm845_llcc_bwmon_data
}, {
.compatible = "qcom,sc7280-llcc-bwmon",
.data = &sc7280_llcc_bwmon_data
},
{}
};
MODULE_DEVICE_TABLE(of, bwmon_of_match);

View File

@ -104,6 +104,7 @@ struct qcom_llcc_config {
int size;
bool need_llcc_cfg;
const u32 *reg_offset;
const struct llcc_edac_reg_offset *edac_reg_offset;
};
enum llcc_reg_offset {
@ -296,12 +297,68 @@ static const struct llcc_slice_config sm8450_data[] = {
{LLCC_AENPU, 8, 2048, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0 },
};
static const u32 llcc_v1_2_reg_offset[] = {
static const struct llcc_edac_reg_offset llcc_v1_edac_reg_offset = {
.trp_ecc_error_status0 = 0x20344,
.trp_ecc_error_status1 = 0x20348,
.trp_ecc_sb_err_syn0 = 0x2304c,
.trp_ecc_db_err_syn0 = 0x20370,
.trp_ecc_error_cntr_clear = 0x20440,
.trp_interrupt_0_status = 0x20480,
.trp_interrupt_0_clear = 0x20484,
.trp_interrupt_0_enable = 0x20488,
/* LLCC Common registers */
.cmn_status0 = 0x3000c,
.cmn_interrupt_0_enable = 0x3001c,
.cmn_interrupt_2_enable = 0x3003c,
/* LLCC DRP registers */
.drp_ecc_error_cfg = 0x40000,
.drp_ecc_error_cntr_clear = 0x40004,
.drp_interrupt_status = 0x41000,
.drp_interrupt_clear = 0x41008,
.drp_interrupt_enable = 0x4100c,
.drp_ecc_error_status0 = 0x42044,
.drp_ecc_error_status1 = 0x42048,
.drp_ecc_sb_err_syn0 = 0x4204c,
.drp_ecc_db_err_syn0 = 0x42070,
};
static const struct llcc_edac_reg_offset llcc_v2_1_edac_reg_offset = {
.trp_ecc_error_status0 = 0x20344,
.trp_ecc_error_status1 = 0x20348,
.trp_ecc_sb_err_syn0 = 0x2034c,
.trp_ecc_db_err_syn0 = 0x20370,
.trp_ecc_error_cntr_clear = 0x20440,
.trp_interrupt_0_status = 0x20480,
.trp_interrupt_0_clear = 0x20484,
.trp_interrupt_0_enable = 0x20488,
/* LLCC Common registers */
.cmn_status0 = 0x3400c,
.cmn_interrupt_0_enable = 0x3401c,
.cmn_interrupt_2_enable = 0x3403c,
/* LLCC DRP registers */
.drp_ecc_error_cfg = 0x50000,
.drp_ecc_error_cntr_clear = 0x50004,
.drp_interrupt_status = 0x50020,
.drp_interrupt_clear = 0x50028,
.drp_interrupt_enable = 0x5002c,
.drp_ecc_error_status0 = 0x520f4,
.drp_ecc_error_status1 = 0x520f8,
.drp_ecc_sb_err_syn0 = 0x520fc,
.drp_ecc_db_err_syn0 = 0x52120,
};
/* LLCC register offset starting from v1.0.0 */
static const u32 llcc_v1_reg_offset[] = {
[LLCC_COMMON_HW_INFO] = 0x00030000,
[LLCC_COMMON_STATUS0] = 0x0003000c,
};
static const u32 llcc_v21_reg_offset[] = {
/* LLCC register offset starting from v2.0.1 */
static const u32 llcc_v2_1_reg_offset[] = {
[LLCC_COMMON_HW_INFO] = 0x00034000,
[LLCC_COMMON_STATUS0] = 0x0003400c,
};
@ -310,70 +367,80 @@ static const struct qcom_llcc_config sc7180_cfg = {
.sct_data = sc7180_data,
.size = ARRAY_SIZE(sc7180_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_2_reg_offset,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
};
static const struct qcom_llcc_config sc7280_cfg = {
.sct_data = sc7280_data,
.size = ARRAY_SIZE(sc7280_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_2_reg_offset,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
};
static const struct qcom_llcc_config sc8180x_cfg = {
.sct_data = sc8180x_data,
.size = ARRAY_SIZE(sc8180x_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_2_reg_offset,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
};
static const struct qcom_llcc_config sc8280xp_cfg = {
.sct_data = sc8280xp_data,
.size = ARRAY_SIZE(sc8280xp_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_2_reg_offset,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
};
static const struct qcom_llcc_config sdm845_cfg = {
.sct_data = sdm845_data,
.size = ARRAY_SIZE(sdm845_data),
.need_llcc_cfg = false,
.reg_offset = llcc_v1_2_reg_offset,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
};
static const struct qcom_llcc_config sm6350_cfg = {
.sct_data = sm6350_data,
.size = ARRAY_SIZE(sm6350_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_2_reg_offset,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
};
static const struct qcom_llcc_config sm8150_cfg = {
.sct_data = sm8150_data,
.size = ARRAY_SIZE(sm8150_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_2_reg_offset,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
};
static const struct qcom_llcc_config sm8250_cfg = {
.sct_data = sm8250_data,
.size = ARRAY_SIZE(sm8250_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_2_reg_offset,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
};
static const struct qcom_llcc_config sm8350_cfg = {
.sct_data = sm8350_data,
.size = ARRAY_SIZE(sm8350_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_2_reg_offset,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
};
static const struct qcom_llcc_config sm8450_cfg = {
.sct_data = sm8450_data,
.size = ARRAY_SIZE(sm8450_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v21_reg_offset,
.reg_offset = llcc_v2_1_reg_offset,
.edac_reg_offset = &llcc_v2_1_edac_reg_offset,
};
static struct llcc_drv_data *drv_data = (void *) -EPROBE_DEFER;
@ -774,6 +841,7 @@ static int qcom_llcc_probe(struct platform_device *pdev)
drv_data->cfg = llcc_cfg;
drv_data->cfg_size = sz;
drv_data->edac_reg_offset = cfg->edac_reg_offset;
mutex_init(&drv_data->lock);
platform_set_drvdata(pdev, drv_data);

View File

@ -246,6 +246,14 @@ static const struct stats_config rpm_data_dba0 = {
.subsystem_stats_in_smem = false,
};
static const struct stats_config rpmh_data_sdm845 = {
.stats_offset = 0x48,
.num_records = 2,
.appended_stats_avail = false,
.dynamic_offset = false,
.subsystem_stats_in_smem = true,
};
static const struct stats_config rpmh_data = {
.stats_offset = 0x48,
.num_records = 3,
@ -261,6 +269,7 @@ static const struct of_device_id qcom_stats_table[] = {
{ .compatible = "qcom,msm8974-rpm-stats", .data = &rpm_data_dba0 },
{ .compatible = "qcom,rpm-stats", .data = &rpm_data },
{ .compatible = "qcom,rpmh-stats", .data = &rpmh_data },
{ .compatible = "qcom,sdm845-rpmh-stats", .data = &rpmh_data_sdm845 },
{ }
};
MODULE_DEVICE_TABLE(of, qcom_stats_table);

View File

@ -57,11 +57,11 @@ do { \
#define TLV_TYPE_SIZE sizeof(u8)
#define OPTIONAL_TLV_TYPE_START 0x10
static int qmi_encode(struct qmi_elem_info *ei_array, void *out_buf,
static int qmi_encode(const struct qmi_elem_info *ei_array, void *out_buf,
const void *in_c_struct, u32 out_buf_len,
int enc_level);
static int qmi_decode(struct qmi_elem_info *ei_array, void *out_c_struct,
static int qmi_decode(const struct qmi_elem_info *ei_array, void *out_c_struct,
const void *in_buf, u32 in_buf_len, int dec_level);
/**
@ -76,10 +76,10 @@ static int qmi_decode(struct qmi_elem_info *ei_array, void *out_c_struct,
*
* Return: struct info of the next element that can be encoded.
*/
static struct qmi_elem_info *skip_to_next_elem(struct qmi_elem_info *ei_array,
int level)
static const struct qmi_elem_info *
skip_to_next_elem(const struct qmi_elem_info *ei_array, int level)
{
struct qmi_elem_info *temp_ei = ei_array;
const struct qmi_elem_info *temp_ei = ei_array;
u8 tlv_type;
if (level > 1) {
@ -101,11 +101,11 @@ static struct qmi_elem_info *skip_to_next_elem(struct qmi_elem_info *ei_array,
*
* Return: Expected minimum length of the QMI message or 0 on error.
*/
static int qmi_calc_min_msg_len(struct qmi_elem_info *ei_array,
static int qmi_calc_min_msg_len(const struct qmi_elem_info *ei_array,
int level)
{
int min_msg_len = 0;
struct qmi_elem_info *temp_ei = ei_array;
const struct qmi_elem_info *temp_ei = ei_array;
if (!ei_array)
return min_msg_len;
@ -194,13 +194,13 @@ static int qmi_encode_basic_elem(void *buf_dst, const void *buf_src,
* Return: The number of bytes of encoded information on success or negative
* errno on error.
*/
static int qmi_encode_struct_elem(struct qmi_elem_info *ei_array,
static int qmi_encode_struct_elem(const struct qmi_elem_info *ei_array,
void *buf_dst, const void *buf_src,
u32 elem_len, u32 out_buf_len,
int enc_level)
{
int i, rc, encoded_bytes = 0;
struct qmi_elem_info *temp_ei = ei_array;
const struct qmi_elem_info *temp_ei = ei_array;
for (i = 0; i < elem_len; i++) {
rc = qmi_encode(temp_ei->ei_array, buf_dst, buf_src,
@ -233,13 +233,13 @@ static int qmi_encode_struct_elem(struct qmi_elem_info *ei_array,
* Return: The number of bytes of encoded information on success or negative
* errno on error.
*/
static int qmi_encode_string_elem(struct qmi_elem_info *ei_array,
static int qmi_encode_string_elem(const struct qmi_elem_info *ei_array,
void *buf_dst, const void *buf_src,
u32 out_buf_len, int enc_level)
{
int rc;
int encoded_bytes = 0;
struct qmi_elem_info *temp_ei = ei_array;
const struct qmi_elem_info *temp_ei = ei_array;
u32 string_len = 0;
u32 string_len_sz = 0;
@ -289,11 +289,11 @@ static int qmi_encode_string_elem(struct qmi_elem_info *ei_array,
* Return: The number of bytes of encoded information on success or negative
* errno on error.
*/
static int qmi_encode(struct qmi_elem_info *ei_array, void *out_buf,
static int qmi_encode(const struct qmi_elem_info *ei_array, void *out_buf,
const void *in_c_struct, u32 out_buf_len,
int enc_level)
{
struct qmi_elem_info *temp_ei = ei_array;
const struct qmi_elem_info *temp_ei = ei_array;
u8 opt_flag_value = 0;
u32 data_len_value = 0, data_len_sz;
u8 *buf_dst = (u8 *)out_buf;
@ -468,13 +468,13 @@ static int qmi_decode_basic_elem(void *buf_dst, const void *buf_src,
* Return: The total size of the decoded data elements on success, negative
* errno on error.
*/
static int qmi_decode_struct_elem(struct qmi_elem_info *ei_array,
static int qmi_decode_struct_elem(const struct qmi_elem_info *ei_array,
void *buf_dst, const void *buf_src,
u32 elem_len, u32 tlv_len,
int dec_level)
{
int i, rc, decoded_bytes = 0;
struct qmi_elem_info *temp_ei = ei_array;
const struct qmi_elem_info *temp_ei = ei_array;
for (i = 0; i < elem_len && decoded_bytes < tlv_len; i++) {
rc = qmi_decode(temp_ei->ei_array, buf_dst, buf_src,
@ -514,7 +514,7 @@ static int qmi_decode_struct_elem(struct qmi_elem_info *ei_array,
* Return: The total size of the decoded data elements on success, negative
* errno on error.
*/
static int qmi_decode_string_elem(struct qmi_elem_info *ei_array,
static int qmi_decode_string_elem(const struct qmi_elem_info *ei_array,
void *buf_dst, const void *buf_src,
u32 tlv_len, int dec_level)
{
@ -522,7 +522,7 @@ static int qmi_decode_string_elem(struct qmi_elem_info *ei_array,
int decoded_bytes = 0;
u32 string_len = 0;
u32 string_len_sz = 0;
struct qmi_elem_info *temp_ei = ei_array;
const struct qmi_elem_info *temp_ei = ei_array;
if (dec_level == 1) {
string_len = tlv_len;
@ -564,10 +564,10 @@ static int qmi_decode_string_elem(struct qmi_elem_info *ei_array,
*
* Return: Pointer to struct info, if found
*/
static struct qmi_elem_info *find_ei(struct qmi_elem_info *ei_array,
static const struct qmi_elem_info *find_ei(const struct qmi_elem_info *ei_array,
u32 type)
{
struct qmi_elem_info *temp_ei = ei_array;
const struct qmi_elem_info *temp_ei = ei_array;
while (temp_ei->data_type != QMI_EOTI) {
if (temp_ei->tlv_type == (u8)type)
@ -590,11 +590,11 @@ static struct qmi_elem_info *find_ei(struct qmi_elem_info *ei_array,
* Return: The number of bytes of decoded information on success, negative
* errno on error.
*/
static int qmi_decode(struct qmi_elem_info *ei_array, void *out_c_struct,
static int qmi_decode(const struct qmi_elem_info *ei_array, void *out_c_struct,
const void *in_buf, u32 in_buf_len,
int dec_level)
{
struct qmi_elem_info *temp_ei = ei_array;
const struct qmi_elem_info *temp_ei = ei_array;
u8 opt_flag_value = 1;
u32 data_len_value = 0, data_len_sz = 0;
u8 *buf_dst = out_c_struct;
@ -713,7 +713,7 @@ static int qmi_decode(struct qmi_elem_info *ei_array, void *out_c_struct,
* Return: Buffer with encoded message, or negative ERR_PTR() on error
*/
void *qmi_encode_message(int type, unsigned int msg_id, size_t *len,
unsigned int txn_id, struct qmi_elem_info *ei,
unsigned int txn_id, const struct qmi_elem_info *ei,
const void *c_struct)
{
struct qmi_header *hdr;
@ -767,7 +767,7 @@ EXPORT_SYMBOL(qmi_encode_message);
* errno on error.
*/
int qmi_decode_message(const void *buf, size_t len,
struct qmi_elem_info *ei, void *c_struct)
const struct qmi_elem_info *ei, void *c_struct)
{
if (!ei)
return -EINVAL;
@ -781,7 +781,7 @@ int qmi_decode_message(const void *buf, size_t len,
EXPORT_SYMBOL(qmi_decode_message);
/* Common header in all QMI responses */
struct qmi_elem_info qmi_response_type_v01_ei[] = {
const struct qmi_elem_info qmi_response_type_v01_ei[] = {
{
.data_type = QMI_SIGNED_2_BYTE_ENUM,
.elem_len = 1,

View File

@ -305,7 +305,7 @@ EXPORT_SYMBOL(qmi_add_server);
* Return: Transaction id on success, negative errno on failure.
*/
int qmi_txn_init(struct qmi_handle *qmi, struct qmi_txn *txn,
struct qmi_elem_info *ei, void *c_struct)
const struct qmi_elem_info *ei, void *c_struct)
{
int ret;
@ -736,7 +736,8 @@ EXPORT_SYMBOL(qmi_handle_release);
static ssize_t qmi_send_message(struct qmi_handle *qmi,
struct sockaddr_qrtr *sq, struct qmi_txn *txn,
int type, int msg_id, size_t len,
struct qmi_elem_info *ei, const void *c_struct)
const struct qmi_elem_info *ei,
const void *c_struct)
{
struct msghdr msghdr = {};
struct kvec iv;
@ -787,7 +788,7 @@ static ssize_t qmi_send_message(struct qmi_handle *qmi,
*/
ssize_t qmi_send_request(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
struct qmi_txn *txn, int msg_id, size_t len,
struct qmi_elem_info *ei, const void *c_struct)
const struct qmi_elem_info *ei, const void *c_struct)
{
return qmi_send_message(qmi, sq, txn, QMI_REQUEST, msg_id, len, ei,
c_struct);
@ -808,7 +809,7 @@ EXPORT_SYMBOL(qmi_send_request);
*/
ssize_t qmi_send_response(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
struct qmi_txn *txn, int msg_id, size_t len,
struct qmi_elem_info *ei, const void *c_struct)
const struct qmi_elem_info *ei, const void *c_struct)
{
return qmi_send_message(qmi, sq, txn, QMI_RESPONSE, msg_id, len, ei,
c_struct);
@ -827,7 +828,8 @@ EXPORT_SYMBOL(qmi_send_response);
* Return: 0 on success, negative errno on failure.
*/
ssize_t qmi_send_indication(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
int msg_id, size_t len, struct qmi_elem_info *ei,
int msg_id, size_t len,
const struct qmi_elem_info *ei,
const void *c_struct)
{
struct qmi_txn txn;

View File

@ -29,6 +29,7 @@
#define RPMPD_RWLM 0x6d6c7772
#define RPMPD_RWSC 0x63737772
#define RPMPD_RWSM 0x6d737772
#define RPMPD_RWGX 0x78677772
/* Operation Keys */
#define KEY_CORNER 0x6e726f63 /* corn */
@ -433,6 +434,26 @@ static const struct rpmpd_desc sm6125_desc = {
.max_state = RPM_SMD_LEVEL_BINNING,
};
DEFINE_RPMPD_PAIR(sm6375, vddgx, vddgx_ao, RWGX, LEVEL, 0);
static struct rpmpd *sm6375_rpmpds[] = {
[SM6375_VDDCX] = &sm6125_vddcx,
[SM6375_VDDCX_AO] = &sm6125_vddcx_ao,
[SM6375_VDDCX_VFL] = &sm6125_vddcx_vfl,
[SM6375_VDDMX] = &sm6125_vddmx,
[SM6375_VDDMX_AO] = &sm6125_vddmx_ao,
[SM6375_VDDMX_VFL] = &sm6125_vddmx_vfl,
[SM6375_VDDGX] = &sm6375_vddgx,
[SM6375_VDDGX_AO] = &sm6375_vddgx_ao,
[SM6375_VDD_LPI_CX] = &sm6115_vdd_lpi_cx,
[SM6375_VDD_LPI_MX] = &sm6115_vdd_lpi_mx,
};
static const struct rpmpd_desc sm6375_desc = {
.rpmpds = sm6375_rpmpds,
.num_pds = ARRAY_SIZE(sm6375_rpmpds),
.max_state = RPM_SMD_LEVEL_TURBO_NO_CPR,
};
static struct rpmpd *qcm2290_rpmpds[] = {
[QCM2290_VDDCX] = &sm6115_vddcx,
[QCM2290_VDDCX_AO] = &sm6115_vddcx_ao,
@ -466,6 +487,7 @@ static const struct of_device_id rpmpd_match_table[] = {
{ .compatible = "qcom,sdm660-rpmpd", .data = &sdm660_desc },
{ .compatible = "qcom,sm6115-rpmpd", .data = &sm6115_desc },
{ .compatible = "qcom,sm6125-rpmpd", .data = &sm6125_desc },
{ .compatible = "qcom,sm6375-rpmpd", .data = &sm6375_desc },
{ }
};
MODULE_DEVICE_TABLE(of, rpmpd_match_table);

View File

@ -136,6 +136,7 @@ static void qcom_smem_state_release(struct kref *ref)
struct qcom_smem_state *state = container_of(ref, struct qcom_smem_state, refcount);
list_del(&state->list);
of_node_put(state->of_node);
kfree(state);
}
@ -205,7 +206,7 @@ struct qcom_smem_state *qcom_smem_state_register(struct device_node *of_node,
kref_init(&state->refcount);
state->of_node = of_node;
state->of_node = of_node_get(of_node);
state->ops = *ops;
state->priv = priv;

View File

@ -526,7 +526,7 @@ static int qcom_smsm_probe(struct platform_device *pdev)
for (id = 0; id < smsm->num_hosts; id++) {
ret = smsm_parse_ipc(smsm, id);
if (ret < 0)
return ret;
goto out_put;
}
/* Acquire the main SMSM state vector */
@ -534,13 +534,14 @@ static int qcom_smsm_probe(struct platform_device *pdev)
smsm->num_entries * sizeof(u32));
if (ret < 0 && ret != -EEXIST) {
dev_err(&pdev->dev, "unable to allocate shared state entry\n");
return ret;
goto out_put;
}
states = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_SMSM_SHARED_STATE, NULL);
if (IS_ERR(states)) {
dev_err(&pdev->dev, "Unable to acquire shared state entry\n");
return PTR_ERR(states);
ret = PTR_ERR(states);
goto out_put;
}
/* Acquire the list of interrupt mask vectors */
@ -548,13 +549,14 @@ static int qcom_smsm_probe(struct platform_device *pdev)
ret = qcom_smem_alloc(QCOM_SMEM_HOST_ANY, SMEM_SMSM_CPU_INTR_MASK, size);
if (ret < 0 && ret != -EEXIST) {
dev_err(&pdev->dev, "unable to allocate smsm interrupt mask\n");
return ret;
goto out_put;
}
intr_mask = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_SMSM_CPU_INTR_MASK, NULL);
if (IS_ERR(intr_mask)) {
dev_err(&pdev->dev, "unable to acquire shared memory interrupt mask\n");
return PTR_ERR(intr_mask);
ret = PTR_ERR(intr_mask);
goto out_put;
}
/* Setup the reference to the local state bits */
@ -565,7 +567,8 @@ static int qcom_smsm_probe(struct platform_device *pdev)
smsm->state = qcom_smem_state_register(local_node, &smsm_state_ops, smsm);
if (IS_ERR(smsm->state)) {
dev_err(smsm->dev, "failed to register qcom_smem_state\n");
return PTR_ERR(smsm->state);
ret = PTR_ERR(smsm->state);
goto out_put;
}
/* Register handlers for remote processor entries of interest. */
@ -595,16 +598,19 @@ static int qcom_smsm_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, smsm);
of_node_put(local_node);
return 0;
unwind_interfaces:
of_node_put(node);
for (id = 0; id < smsm->num_entries; id++)
if (smsm->entries[id].domain)
irq_domain_remove(smsm->entries[id].domain);
qcom_smem_state_unregister(smsm->state);
out_put:
of_node_put(local_node);
return ret;
}

View File

@ -104,6 +104,7 @@ static const char *const pmic_models[] = {
[36] = "PM8009",
[38] = "PM8150C",
[41] = "SMB2351",
[45] = "PM6125",
[47] = "PMK8350",
[48] = "PM8350",
[49] = "PM8350C",
@ -334,6 +335,7 @@ static const struct soc_id soc_id[] = {
{ 482, "SM8450" },
{ 487, "SC7280" },
{ 495, "SC7180P" },
{ 507, "SM6375" },
};
static const char *socinfo_machine(struct device *dev, unsigned int id)

View File

@ -44,6 +44,7 @@ config ARCH_RZG2L
bool
select PM
select PM_GENERIC_DOMAINS
select RENESAS_RZG2L_IRQC
config ARCH_RZN1
bool
@ -332,6 +333,16 @@ config ARCH_R9A09G011
endif # ARM64
if RISCV
config ARCH_R9A07G043
bool "RISC-V Platform support for RZ/Five"
select ARCH_RZG2L
help
This enables support for the Renesas RZ/Five SoC.
endif # RISCV
config RST_RCAR
bool "Reset Controller support for R-Car" if COMPILE_TEST

View File

@ -50,6 +50,10 @@ static const struct renesas_family fam_rza2 __initconst __maybe_unused = {
.name = "RZ/A2",
};
static const struct renesas_family fam_rzfive __initconst __maybe_unused = {
.name = "RZ/Five",
};
static const struct renesas_family fam_rzg1 __initconst __maybe_unused = {
.name = "RZ/G1",
.reg = 0xff000044, /* PRR (Product Register) */
@ -102,6 +106,11 @@ static const struct renesas_soc soc_rmobile_a1 __initconst __maybe_unused = {
.id = 0x40,
};
static const struct renesas_soc soc_rz_five __initconst __maybe_unused = {
.family = &fam_rzfive,
.id = 0x847c447,
};
static const struct renesas_soc soc_rz_g1h __initconst __maybe_unused = {
.family = &fam_rzg1,
.id = 0x45,
@ -320,6 +329,7 @@ static const struct of_device_id renesas_socs[] __initconst = {
{ .compatible = "renesas,r8a779m0", .data = &soc_rcar_h3 },
{ .compatible = "renesas,r8a779m1", .data = &soc_rcar_h3 },
{ .compatible = "renesas,r8a779m8", .data = &soc_rcar_h3 },
{ .compatible = "renesas,r8a779mb", .data = &soc_rcar_h3 },
#endif
#ifdef CONFIG_ARCH_R8A77960
{ .compatible = "renesas,r8a7796", .data = &soc_rcar_m3_w },
@ -358,8 +368,12 @@ static const struct of_device_id renesas_socs[] __initconst = {
{ .compatible = "renesas,r8a779g0", .data = &soc_rcar_v4h },
#endif
#if defined(CONFIG_ARCH_R9A07G043)
#ifdef CONFIG_RISCV
{ .compatible = "renesas,r9a07g043", .data = &soc_rz_five },
#else
{ .compatible = "renesas,r9a07g043", .data = &soc_rz_g2ul },
#endif
#endif
#if defined(CONFIG_ARCH_R9A07G044)
{ .compatible = "renesas,r9a07g044", .data = &soc_rz_g2l },
#endif

View File

@ -491,6 +491,22 @@ static const struct rockchip_iodomain_soc_data soc_data_rv1108_pmu = {
},
};
static const struct rockchip_iodomain_soc_data soc_data_rv1126_pmu = {
.grf_offset = 0x140,
.supply_names = {
NULL,
"vccio1",
"vccio2",
"vccio3",
"vccio4",
"vccio5",
"vccio6",
"vccio7",
"pmuio0",
"pmuio1",
},
};
static const struct of_device_id rockchip_iodomain_match[] = {
{
.compatible = "rockchip,px30-io-voltage-domain",
@ -544,6 +560,10 @@ static const struct of_device_id rockchip_iodomain_match[] = {
.compatible = "rockchip,rv1108-pmu-io-voltage-domain",
.data = &soc_data_rv1108_pmu
},
{
.compatible = "rockchip,rv1126-pmu-io-voltage-domain",
.data = &soc_data_rv1126_pmu
},
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, rockchip_iodomain_match);

View File

@ -19,6 +19,7 @@
#include <linux/mfd/syscon.h>
#include <soc/rockchip/pm_domains.h>
#include <dt-bindings/power/px30-power.h>
#include <dt-bindings/power/rockchip,rv1126-power.h>
#include <dt-bindings/power/rk3036-power.h>
#include <dt-bindings/power/rk3066-power.h>
#include <dt-bindings/power/rk3128-power.h>
@ -30,6 +31,7 @@
#include <dt-bindings/power/rk3368-power.h>
#include <dt-bindings/power/rk3399-power.h>
#include <dt-bindings/power/rk3568-power.h>
#include <dt-bindings/power/rk3588-power.h>
struct rockchip_domain_info {
const char *name;
@ -41,6 +43,9 @@ struct rockchip_domain_info {
bool active_wakeup;
int pwr_w_mask;
int req_w_mask;
int repair_status_mask;
u32 pwr_offset;
u32 req_offset;
};
struct rockchip_pmu_info {
@ -49,6 +54,7 @@ struct rockchip_pmu_info {
u32 req_offset;
u32 idle_offset;
u32 ack_offset;
u32 repair_status_offset;
u32 core_pwrcnt_offset;
u32 gpu_pwrcnt_offset;
@ -113,6 +119,22 @@ struct rockchip_pmu {
.active_wakeup = wakeup, \
}
#define DOMAIN_M_O_R(_name, p_offset, pwr, status, r_status, r_offset, req, idle, ack, wakeup) \
{ \
.name = _name, \
.pwr_offset = p_offset, \
.pwr_w_mask = (pwr) << 16, \
.pwr_mask = (pwr), \
.status_mask = (status), \
.repair_status_mask = (r_status), \
.req_offset = r_offset, \
.req_w_mask = (req) << 16, \
.req_mask = (req), \
.idle_mask = (idle), \
.ack_mask = (ack), \
.active_wakeup = wakeup, \
}
#define DOMAIN_RK3036(_name, req, ack, idle, wakeup) \
{ \
.name = _name, \
@ -126,6 +148,9 @@ struct rockchip_pmu {
#define DOMAIN_PX30(name, pwr, status, req, wakeup) \
DOMAIN_M(name, pwr, status, req, (req) << 16, req, wakeup)
#define DOMAIN_RV1126(name, pwr, req, idle, wakeup) \
DOMAIN_M(name, pwr, pwr, req, idle, idle, wakeup)
#define DOMAIN_RK3288(name, pwr, status, req, wakeup) \
DOMAIN(name, pwr, status, req, req, (req) << 16, wakeup)
@ -244,6 +269,9 @@ void rockchip_pmu_unblock(void)
}
EXPORT_SYMBOL_GPL(rockchip_pmu_unblock);
#define DOMAIN_RK3588(name, p_offset, pwr, status, r_status, r_offset, req, idle, wakeup) \
DOMAIN_M_O_R(name, p_offset, pwr, status, r_status, r_offset, req, idle, idle, wakeup)
static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd)
{
struct rockchip_pmu *pmu = pd->pmu;
@ -268,6 +296,7 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd,
const struct rockchip_domain_info *pd_info = pd->info;
struct generic_pm_domain *genpd = &pd->genpd;
struct rockchip_pmu *pmu = pd->pmu;
u32 pd_req_offset = pd_info->req_offset;
unsigned int target_ack;
unsigned int val;
bool is_idle;
@ -276,11 +305,11 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd,
if (pd_info->req_mask == 0)
return 0;
else if (pd_info->req_w_mask)
regmap_write(pmu->regmap, pmu->info->req_offset,
regmap_write(pmu->regmap, pmu->info->req_offset + pd_req_offset,
idle ? (pd_info->req_mask | pd_info->req_w_mask) :
pd_info->req_w_mask);
else
regmap_update_bits(pmu->regmap, pmu->info->req_offset,
regmap_update_bits(pmu->regmap, pmu->info->req_offset + pd_req_offset,
pd_info->req_mask, idle ? -1U : 0);
wmb();
@ -363,6 +392,12 @@ static bool rockchip_pmu_domain_is_on(struct rockchip_pm_domain *pd)
struct rockchip_pmu *pmu = pd->pmu;
unsigned int val;
if (pd->info->repair_status_mask) {
regmap_read(pmu->regmap, pmu->info->repair_status_offset, &val);
/* 1'b1: power on, 1'b0: power off */
return val & pd->info->repair_status_mask;
}
/* check idle status for idle-only domains */
if (pd->info->status_mask == 0)
return !rockchip_pmu_domain_is_idle(pd);
@ -378,16 +413,17 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
{
struct rockchip_pmu *pmu = pd->pmu;
struct generic_pm_domain *genpd = &pd->genpd;
u32 pd_pwr_offset = pd->info->pwr_offset;
bool is_on;
if (pd->info->pwr_mask == 0)
return;
else if (pd->info->pwr_w_mask)
regmap_write(pmu->regmap, pmu->info->pwr_offset,
regmap_write(pmu->regmap, pmu->info->pwr_offset + pd_pwr_offset,
on ? pd->info->pwr_w_mask :
(pd->info->pwr_mask | pd->info->pwr_w_mask));
else
regmap_update_bits(pmu->regmap, pmu->info->pwr_offset,
regmap_update_bits(pmu->regmap, pmu->info->pwr_offset + pd_pwr_offset,
pd->info->pwr_mask, on ? 0 : -1U);
wmb();
@ -514,6 +550,9 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
node, id);
return -EINVAL;
}
/* RK3588 has domains with two parents (RKVDEC0/RKVDEC1) */
if (pmu->genpd_data.domains[id])
return 0;
pd_info = &pmu->info->domain_info[id];
if (!pd_info) {
@ -595,14 +634,6 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
}
}
error = rockchip_pd_power(pd, true);
if (error) {
dev_err(pmu->dev,
"failed to power on domain '%pOFn': %d\n",
node, error);
goto err_unprepare_clocks;
}
if (pd->info->name)
pd->genpd.name = pd->info->name;
else
@ -614,7 +645,7 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
pd->genpd.flags = GENPD_FLAG_PM_CLK;
if (pd_info->active_wakeup)
pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
pm_genpd_init(&pd->genpd, NULL, false);
pm_genpd_init(&pd->genpd, NULL, !rockchip_pmu_domain_is_on(pd));
pmu->genpd_data.domains[id] = &pd->genpd;
return 0;
@ -855,6 +886,16 @@ static const struct rockchip_domain_info px30_pm_domains[] = {
[PX30_PD_GPU] = DOMAIN_PX30("gpu", BIT(15), BIT(15), BIT(2), false),
};
static const struct rockchip_domain_info rv1126_pm_domains[] = {
[RV1126_PD_VEPU] = DOMAIN_RV1126("vepu", BIT(2), BIT(9), BIT(9), false),
[RV1126_PD_VI] = DOMAIN_RV1126("vi", BIT(4), BIT(6), BIT(6), false),
[RV1126_PD_ISPP] = DOMAIN_RV1126("ispp", BIT(1), BIT(8), BIT(8), false),
[RV1126_PD_VDPU] = DOMAIN_RV1126("vdpu", BIT(3), BIT(10), BIT(10), false),
[RV1126_PD_NVM] = DOMAIN_RV1126("nvm", BIT(7), BIT(11), BIT(11), false),
[RV1126_PD_SDIO] = DOMAIN_RV1126("sdio", BIT(8), BIT(13), BIT(13), false),
[RV1126_PD_USB] = DOMAIN_RV1126("usb", BIT(9), BIT(15), BIT(15), false),
};
static const struct rockchip_domain_info rk3036_pm_domains[] = {
[RK3036_PD_MSCH] = DOMAIN_RK3036("msch", BIT(14), BIT(23), BIT(30), true),
[RK3036_PD_CORE] = DOMAIN_RK3036("core", BIT(13), BIT(17), BIT(24), false),
@ -982,6 +1023,38 @@ static const struct rockchip_domain_info rk3568_pm_domains[] = {
[RK3568_PD_PIPE] = DOMAIN_RK3568("pipe", BIT(8), BIT(11), false),
};
static const struct rockchip_domain_info rk3588_pm_domains[] = {
[RK3588_PD_GPU] = DOMAIN_RK3588("gpu", 0x0, BIT(0), 0, BIT(1), 0x0, BIT(0), BIT(0), false),
[RK3588_PD_NPU] = DOMAIN_RK3588("npu", 0x0, BIT(1), BIT(1), 0, 0x0, 0, 0, false),
[RK3588_PD_VCODEC] = DOMAIN_RK3588("vcodec", 0x0, BIT(2), BIT(2), 0, 0x0, 0, 0, false),
[RK3588_PD_NPUTOP] = DOMAIN_RK3588("nputop", 0x0, BIT(3), 0, BIT(2), 0x0, BIT(1), BIT(1), false),
[RK3588_PD_NPU1] = DOMAIN_RK3588("npu1", 0x0, BIT(4), 0, BIT(3), 0x0, BIT(2), BIT(2), false),
[RK3588_PD_NPU2] = DOMAIN_RK3588("npu2", 0x0, BIT(5), 0, BIT(4), 0x0, BIT(3), BIT(3), false),
[RK3588_PD_VENC0] = DOMAIN_RK3588("venc0", 0x0, BIT(6), 0, BIT(5), 0x0, BIT(4), BIT(4), false),
[RK3588_PD_VENC1] = DOMAIN_RK3588("venc1", 0x0, BIT(7), 0, BIT(6), 0x0, BIT(5), BIT(5), false),
[RK3588_PD_RKVDEC0] = DOMAIN_RK3588("rkvdec0", 0x0, BIT(8), 0, BIT(7), 0x0, BIT(6), BIT(6), false),
[RK3588_PD_RKVDEC1] = DOMAIN_RK3588("rkvdec1", 0x0, BIT(9), 0, BIT(8), 0x0, BIT(7), BIT(7), false),
[RK3588_PD_VDPU] = DOMAIN_RK3588("vdpu", 0x0, BIT(10), 0, BIT(9), 0x0, BIT(8), BIT(8), false),
[RK3588_PD_RGA30] = DOMAIN_RK3588("rga30", 0x0, BIT(11), 0, BIT(10), 0x0, 0, 0, false),
[RK3588_PD_AV1] = DOMAIN_RK3588("av1", 0x0, BIT(12), 0, BIT(11), 0x0, BIT(9), BIT(9), false),
[RK3588_PD_VI] = DOMAIN_RK3588("vi", 0x0, BIT(13), 0, BIT(12), 0x0, BIT(10), BIT(10), false),
[RK3588_PD_FEC] = DOMAIN_RK3588("fec", 0x0, BIT(14), 0, BIT(13), 0x0, 0, 0, false),
[RK3588_PD_ISP1] = DOMAIN_RK3588("isp1", 0x0, BIT(15), 0, BIT(14), 0x0, BIT(11), BIT(11), false),
[RK3588_PD_RGA31] = DOMAIN_RK3588("rga31", 0x4, BIT(0), 0, BIT(15), 0x0, BIT(12), BIT(12), false),
[RK3588_PD_VOP] = DOMAIN_RK3588("vop", 0x4, BIT(1), 0, BIT(16), 0x0, BIT(13) | BIT(14), BIT(13) | BIT(14), false),
[RK3588_PD_VO0] = DOMAIN_RK3588("vo0", 0x4, BIT(2), 0, BIT(17), 0x0, BIT(15), BIT(15), false),
[RK3588_PD_VO1] = DOMAIN_RK3588("vo1", 0x4, BIT(3), 0, BIT(18), 0x4, BIT(0), BIT(16), false),
[RK3588_PD_AUDIO] = DOMAIN_RK3588("audio", 0x4, BIT(4), 0, BIT(19), 0x4, BIT(1), BIT(17), false),
[RK3588_PD_PHP] = DOMAIN_RK3588("php", 0x4, BIT(5), 0, BIT(20), 0x4, BIT(5), BIT(21), false),
[RK3588_PD_GMAC] = DOMAIN_RK3588("gmac", 0x4, BIT(6), 0, BIT(21), 0x0, 0, 0, false),
[RK3588_PD_PCIE] = DOMAIN_RK3588("pcie", 0x4, BIT(7), 0, BIT(22), 0x0, 0, 0, true),
[RK3588_PD_NVM] = DOMAIN_RK3588("nvm", 0x4, BIT(8), BIT(24), 0, 0x4, BIT(2), BIT(18), false),
[RK3588_PD_NVM0] = DOMAIN_RK3588("nvm0", 0x4, BIT(9), 0, BIT(23), 0x0, 0, 0, false),
[RK3588_PD_SDIO] = DOMAIN_RK3588("sdio", 0x4, BIT(10), 0, BIT(24), 0x4, BIT(3), BIT(19), false),
[RK3588_PD_USB] = DOMAIN_RK3588("usb", 0x4, BIT(11), 0, BIT(25), 0x4, BIT(4), BIT(20), true),
[RK3588_PD_SDMMC] = DOMAIN_RK3588("sdmmc", 0x4, BIT(13), 0, BIT(26), 0x0, 0, 0, false),
};
static const struct rockchip_pmu_info px30_pmu = {
.pwr_offset = 0x18,
.status_offset = 0x20,
@ -1128,6 +1201,29 @@ static const struct rockchip_pmu_info rk3568_pmu = {
.domain_info = rk3568_pm_domains,
};
static const struct rockchip_pmu_info rk3588_pmu = {
.pwr_offset = 0x14c,
.status_offset = 0x180,
.req_offset = 0x10c,
.idle_offset = 0x120,
.ack_offset = 0x118,
.repair_status_offset = 0x290,
.num_domains = ARRAY_SIZE(rk3588_pm_domains),
.domain_info = rk3588_pm_domains,
};
static const struct rockchip_pmu_info rv1126_pmu = {
.pwr_offset = 0x110,
.status_offset = 0x108,
.req_offset = 0xc0,
.idle_offset = 0xd8,
.ack_offset = 0xd0,
.num_domains = ARRAY_SIZE(rv1126_pm_domains),
.domain_info = rv1126_pm_domains,
};
static const struct of_device_id rockchip_pm_domain_dt_match[] = {
{
.compatible = "rockchip,px30-power-controller",
@ -1177,6 +1273,14 @@ static const struct of_device_id rockchip_pm_domain_dt_match[] = {
.compatible = "rockchip,rk3568-power-controller",
.data = (void *)&rk3568_pmu,
},
{
.compatible = "rockchip,rk3588-power-controller",
.data = (void *)&rk3588_pmu,
},
{
.compatible = "rockchip,rv1126-power-controller",
.data = (void *)&rv1126_pmu,
},
{ /* sentinel */ },
};

View File

@ -261,30 +261,29 @@ int sunxi_sram_claim(struct device *dev)
}
EXPORT_SYMBOL(sunxi_sram_claim);
int sunxi_sram_release(struct device *dev)
void sunxi_sram_release(struct device *dev)
{
const struct sunxi_sram_data *sram_data;
struct sunxi_sram_desc *sram_desc;
if (!dev || !dev->of_node)
return -EINVAL;
return;
sram_data = sunxi_sram_of_parse(dev->of_node, NULL);
if (IS_ERR(sram_data))
return -EINVAL;
return;
sram_desc = to_sram_desc(sram_data);
spin_lock(&sram_lock);
sram_desc->claimed = false;
spin_unlock(&sram_lock);
return 0;
}
EXPORT_SYMBOL(sunxi_sram_release);
struct sunxi_sramc_variant {
int num_emac_clocks;
bool has_ldo_ctrl;
};
static const struct sunxi_sramc_variant sun4i_a10_sramc_variant = {
@ -295,6 +294,11 @@ static const struct sunxi_sramc_variant sun8i_h3_sramc_variant = {
.num_emac_clocks = 1,
};
static const struct sunxi_sramc_variant sun20i_d1_sramc_variant = {
.num_emac_clocks = 1,
.has_ldo_ctrl = true,
};
static const struct sunxi_sramc_variant sun50i_a64_sramc_variant = {
.num_emac_clocks = 1,
};
@ -304,27 +308,28 @@ static const struct sunxi_sramc_variant sun50i_h616_sramc_variant = {
};
#define SUNXI_SRAM_EMAC_CLOCK_REG 0x30
#define SUNXI_SYS_LDO_CTRL_REG 0x150
static bool sunxi_sram_regmap_accessible_reg(struct device *dev,
unsigned int reg)
{
const struct sunxi_sramc_variant *variant;
variant = of_device_get_match_data(dev);
if (reg < SUNXI_SRAM_EMAC_CLOCK_REG)
return false;
if (reg > SUNXI_SRAM_EMAC_CLOCK_REG + variant->num_emac_clocks * 4)
return false;
const struct sunxi_sramc_variant *variant = dev_get_drvdata(dev);
if (reg >= SUNXI_SRAM_EMAC_CLOCK_REG &&
reg < SUNXI_SRAM_EMAC_CLOCK_REG + variant->num_emac_clocks * 4)
return true;
if (reg == SUNXI_SYS_LDO_CTRL_REG && variant->has_ldo_ctrl)
return true;
return false;
}
static struct regmap_config sunxi_sram_emac_clock_regmap = {
static struct regmap_config sunxi_sram_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
/* last defined register */
.max_register = SUNXI_SRAM_EMAC_CLOCK_REG + 4,
.max_register = SUNXI_SYS_LDO_CTRL_REG,
/* other devices have no business accessing other registers */
.readable_reg = sunxi_sram_regmap_accessible_reg,
.writeable_reg = sunxi_sram_regmap_accessible_reg,
@ -332,9 +337,9 @@ static struct regmap_config sunxi_sram_emac_clock_regmap = {
static int __init sunxi_sram_probe(struct platform_device *pdev)
{
struct regmap *emac_clock;
const struct sunxi_sramc_variant *variant;
struct device *dev = &pdev->dev;
struct regmap *regmap;
sram_dev = &pdev->dev;
@ -342,16 +347,16 @@ static int __init sunxi_sram_probe(struct platform_device *pdev)
if (!variant)
return -EINVAL;
dev_set_drvdata(dev, (struct sunxi_sramc_variant *)variant);
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
if (variant->num_emac_clocks > 0) {
emac_clock = devm_regmap_init_mmio(&pdev->dev, base,
&sunxi_sram_emac_clock_regmap);
if (IS_ERR(emac_clock))
return PTR_ERR(emac_clock);
if (variant->num_emac_clocks || variant->has_ldo_ctrl) {
regmap = devm_regmap_init_mmio(dev, base, &sunxi_sram_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
}
of_platform_populate(dev->of_node, NULL, NULL, dev);
@ -382,6 +387,10 @@ static const struct of_device_id sunxi_sram_dt_match[] = {
.compatible = "allwinner,sun8i-h3-system-control",
.data = &sun8i_h3_sramc_variant,
},
{
.compatible = "allwinner,sun20i-d1-system-control",
.data = &sun20i_d1_sramc_variant,
},
{
.compatible = "allwinner,sun50i-a64-sram-controller",
.data = &sun50i_a64_sramc_variant,

View File

@ -136,7 +136,6 @@ config SOC_TEGRA_FUSE
def_bool y
depends on ARCH_TEGRA
select SOC_BUS
select TEGRA20_APB_DMA if ARCH_TEGRA_2x_SOC
config SOC_TEGRA_FLOWCTRL
bool
@ -162,3 +161,12 @@ config SOC_TEGRA30_VOLTAGE_COUPLER
bool "Voltage scaling support for Tegra30 SoCs"
depends on ARCH_TEGRA_3x_SOC || COMPILE_TEST
depends on REGULATOR
config SOC_TEGRA_CBB
tristate "Tegra driver to handle error from CBB"
depends on ARCH_TEGRA_194_SOC || ARCH_TEGRA_234_SOC
default y
help
Support for handling error from Tegra Control Backbone(CBB).
This driver handles the errors from CBB and prints debug
information about the failed transactions.

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-y += fuse/
obj-y += cbb/
obj-y += common.o
obj-$(CONFIG_SOC_TEGRA_FLOWCTRL) += flowctrl.o

View File

@ -0,0 +1,9 @@
# SPDX-License-Identifier: GPL-2.0
#
# Control Backbone Driver code.
#
ifdef CONFIG_SOC_TEGRA_CBB
obj-y += tegra-cbb.o
obj-$(CONFIG_ARCH_TEGRA_194_SOC) += tegra194-cbb.o
obj-$(CONFIG_ARCH_TEGRA_234_SOC) += tegra234-cbb.o
endif

View File

@ -0,0 +1,190 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2021-2022, NVIDIA CORPORATION. All rights reserved
*/
#include <linux/clk.h>
#include <linux/cpufeature.h>
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/version.h>
#include <soc/tegra/fuse.h>
#include <soc/tegra/tegra-cbb.h>
void tegra_cbb_print_err(struct seq_file *file, const char *fmt, ...)
{
struct va_format vaf;
va_list args;
va_start(args, fmt);
if (file) {
seq_vprintf(file, fmt, args);
} else {
vaf.fmt = fmt;
vaf.va = &args;
pr_crit("%pV", &vaf);
}
va_end(args);
}
void tegra_cbb_print_cache(struct seq_file *file, u32 cache)
{
const char *buff_str, *mod_str, *rd_str, *wr_str;
buff_str = (cache & BIT(0)) ? "Bufferable " : "";
mod_str = (cache & BIT(1)) ? "Modifiable " : "";
rd_str = (cache & BIT(2)) ? "Read-Allocate " : "";
wr_str = (cache & BIT(3)) ? "Write-Allocate" : "";
if (cache == 0x0)
buff_str = "Device Non-Bufferable";
tegra_cbb_print_err(file, "\t Cache\t\t\t: 0x%x -- %s%s%s%s\n",
cache, buff_str, mod_str, rd_str, wr_str);
}
void tegra_cbb_print_prot(struct seq_file *file, u32 prot)
{
const char *data_str, *secure_str, *priv_str;
data_str = (prot & 0x4) ? "Instruction" : "Data";
secure_str = (prot & 0x2) ? "Non-Secure" : "Secure";
priv_str = (prot & 0x1) ? "Privileged" : "Unprivileged";
tegra_cbb_print_err(file, "\t Protection\t\t: 0x%x -- %s, %s, %s Access\n",
prot, priv_str, secure_str, data_str);
}
static int tegra_cbb_err_show(struct seq_file *file, void *data)
{
struct tegra_cbb *cbb = file->private;
return cbb->ops->debugfs_show(cbb, file, data);
}
static int tegra_cbb_err_open(struct inode *inode, struct file *file)
{
return single_open(file, tegra_cbb_err_show, inode->i_private);
}
static const struct file_operations tegra_cbb_err_fops = {
.open = tegra_cbb_err_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release
};
static int tegra_cbb_err_debugfs_init(struct tegra_cbb *cbb)
{
static struct dentry *root;
if (!root) {
root = debugfs_create_file("tegra_cbb_err", 0444, NULL, cbb, &tegra_cbb_err_fops);
if (IS_ERR_OR_NULL(root)) {
pr_err("%s(): could not create debugfs node\n", __func__);
return PTR_ERR(root);
}
}
return 0;
}
void tegra_cbb_stall_enable(struct tegra_cbb *cbb)
{
if (cbb->ops->stall_enable)
cbb->ops->stall_enable(cbb);
}
void tegra_cbb_fault_enable(struct tegra_cbb *cbb)
{
if (cbb->ops->fault_enable)
cbb->ops->fault_enable(cbb);
}
void tegra_cbb_error_clear(struct tegra_cbb *cbb)
{
if (cbb->ops->error_clear)
cbb->ops->error_clear(cbb);
}
u32 tegra_cbb_get_status(struct tegra_cbb *cbb)
{
if (cbb->ops->get_status)
return cbb->ops->get_status(cbb);
return 0;
}
int tegra_cbb_get_irq(struct platform_device *pdev, unsigned int *nonsec_irq,
unsigned int *sec_irq)
{
unsigned int index = 0;
int num_intr = 0, irq;
num_intr = platform_irq_count(pdev);
if (!num_intr)
return -EINVAL;
if (num_intr == 2) {
irq = platform_get_irq(pdev, index);
if (irq <= 0) {
dev_err(&pdev->dev, "failed to get non-secure IRQ: %d\n", irq);
return -ENOENT;
}
*nonsec_irq = irq;
index++;
}
irq = platform_get_irq(pdev, index);
if (irq <= 0) {
dev_err(&pdev->dev, "failed to get secure IRQ: %d\n", irq);
return -ENOENT;
}
*sec_irq = irq;
if (num_intr == 1)
dev_dbg(&pdev->dev, "secure IRQ: %u\n", *sec_irq);
if (num_intr == 2)
dev_dbg(&pdev->dev, "secure IRQ: %u, non-secure IRQ: %u\n", *sec_irq, *nonsec_irq);
return 0;
}
int tegra_cbb_register(struct tegra_cbb *cbb)
{
int ret;
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
ret = tegra_cbb_err_debugfs_init(cbb);
if (ret) {
dev_err(cbb->dev, "failed to create debugfs\n");
return ret;
}
}
/* register interrupt handler for errors due to different initiators */
ret = cbb->ops->interrupt_enable(cbb);
if (ret < 0) {
dev_err(cbb->dev, "Failed to register CBB Interrupt ISR");
return ret;
}
cbb->ops->error_enable(cbb);
dsb(sy);
return 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -568,6 +568,7 @@ static int __init tegra_init_fuse(void)
np = of_find_matching_node(NULL, car_match);
if (np) {
void __iomem *base = of_iomap(np, 0);
of_node_put(np);
if (base) {
tegra_enable_fuse_clk(base);
iounmap(base);

View File

@ -16,12 +16,16 @@
#define FUSE_SKU_INFO 0x10
#define ERD_ERR_CONFIG 0x120c
#define ERD_MASK_INBAND_ERR 0x1
#define PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT 4
#define PMC_STRAPPING_OPT_A_RAM_CODE_MASK_LONG \
(0xf << PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT)
#define PMC_STRAPPING_OPT_A_RAM_CODE_MASK_SHORT \
(0x3 << PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT)
static void __iomem *apbmisc_base;
static bool long_ram_code;
static u32 strapping;
static u32 chipid;
@ -93,6 +97,28 @@ u32 tegra_read_ram_code(void)
}
EXPORT_SYMBOL_GPL(tegra_read_ram_code);
/*
* The function sets ERD(Error Response Disable) bit.
* This allows to mask inband errors and always send an
* OKAY response from CBB to the master which caused error.
*/
int tegra194_miscreg_mask_serror(void)
{
if (!apbmisc_base)
return -EPROBE_DEFER;
if (!of_machine_is_compatible("nvidia,tegra194")) {
WARN(1, "Only supported for Tegra194 devices!\n");
return -EOPNOTSUPP;
}
writel_relaxed(ERD_MASK_INBAND_ERR,
apbmisc_base + ERD_ERR_CONFIG);
return 0;
}
EXPORT_SYMBOL(tegra194_miscreg_mask_serror);
static const struct of_device_id apbmisc_match[] __initconst = {
{ .compatible = "nvidia,tegra20-apbmisc", },
{ .compatible = "nvidia,tegra186-misc", },
@ -134,7 +160,7 @@ void __init tegra_init_revision(void)
void __init tegra_init_apbmisc(void)
{
void __iomem *apbmisc_base, *strapping_base;
void __iomem *strapping_base;
struct resource apbmisc, straps;
struct device_node *np;
@ -182,12 +208,12 @@ void __init tegra_init_apbmisc(void)
*/
if (of_address_to_resource(np, 0, &apbmisc) < 0) {
pr_err("failed to get APBMISC registers\n");
return;
goto put;
}
if (of_address_to_resource(np, 1, &straps) < 0) {
pr_err("failed to get strapping options registers\n");
return;
goto put;
}
}
@ -196,7 +222,6 @@ void __init tegra_init_apbmisc(void)
pr_err("failed to map APBMISC registers\n");
} else {
chipid = readl_relaxed(apbmisc_base + 4);
iounmap(apbmisc_base);
}
strapping_base = ioremap(straps.start, resource_size(&straps));
@ -208,4 +233,7 @@ void __init tegra_init_apbmisc(void)
}
long_ram_code = of_property_read_bool(np, "nvidia,long-ram-code");
put:
of_node_put(np);
}

View File

@ -296,6 +296,17 @@ struct tegra_wake_event {
} gpio;
};
#define TEGRA_WAKE_SIMPLE(_name, _id) \
{ \
.name = _name, \
.id = _id, \
.irq = 0, \
.gpio = { \
.instance = UINT_MAX, \
.pin = UINT_MAX, \
}, \
}
#define TEGRA_WAKE_IRQ(_name, _id, _irq) \
{ \
.name = _name, \
@ -2239,6 +2250,7 @@ static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq,
for (i = 0; i < soc->num_wake_events; i++) {
const struct tegra_wake_event *event = &soc->wake_events[i];
/* IRQ and simple wake events */
if (fwspec->param_count == 2) {
struct irq_fwspec spec;
@ -2251,6 +2263,12 @@ static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq,
if (err < 0)
break;
/* simple hierarchies stop at the PMC level */
if (event->irq == 0) {
err = irq_domain_disconnect_hierarchy(domain->parent, virq);
break;
}
spec.fwnode = &pmc->dev->of_node->fwnode;
spec.param_count = 3;
spec.param[0] = GIC_SPI;
@ -2263,6 +2281,7 @@ static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq,
break;
}
/* GPIO wake events */
if (fwspec->param_count == 3) {
if (event->gpio.instance != fwspec->param[0] ||
event->gpio.pin != fwspec->param[1])
@ -2885,17 +2904,10 @@ static int tegra_pmc_probe(struct platform_device *pdev)
pmc->scratch = base;
}
pmc->clk = devm_clk_get(&pdev->dev, "pclk");
if (IS_ERR(pmc->clk)) {
err = PTR_ERR(pmc->clk);
if (err != -ENOENT) {
dev_err(&pdev->dev, "failed to get pclk: %d\n", err);
return err;
}
pmc->clk = NULL;
}
pmc->clk = devm_clk_get_optional(&pdev->dev, "pclk");
if (IS_ERR(pmc->clk))
return dev_err_probe(&pdev->dev, PTR_ERR(pmc->clk),
"failed to get pclk\n");
/*
* PMC should be last resort for restarting since it soft-resets
@ -3757,6 +3769,13 @@ static const struct tegra_wake_event tegra194_wake_events[] = {
TEGRA_WAKE_IRQ("pmu", 24, 209),
TEGRA_WAKE_GPIO("power", 29, 1, TEGRA194_AON_GPIO(EE, 4)),
TEGRA_WAKE_IRQ("rtc", 73, 10),
TEGRA_WAKE_SIMPLE("usb3-port-0", 76),
TEGRA_WAKE_SIMPLE("usb3-port-1", 77),
TEGRA_WAKE_SIMPLE("usb3-port-2-3", 78),
TEGRA_WAKE_SIMPLE("usb2-port-0", 79),
TEGRA_WAKE_SIMPLE("usb2-port-1", 80),
TEGRA_WAKE_SIMPLE("usb2-port-2", 81),
TEGRA_WAKE_SIMPLE("usb2-port-3", 82),
};
static const struct tegra_pmc_soc tegra194_pmc_soc = {
@ -4025,7 +4044,7 @@ static int __init tegra_pmc_early_init(void)
return -ENXIO;
}
if (np) {
if (of_device_is_available(np)) {
pmc->soc = match->data;
if (pmc->soc->maybe_tz_only)

View File

@ -271,8 +271,8 @@ static int optee_ffa_shm_register(struct tee_context *ctx, struct tee_shm *shm,
unsigned long start)
{
struct optee *optee = tee_get_drvdata(ctx->teedev);
const struct ffa_dev_ops *ffa_ops = optee->ffa.ffa_ops;
struct ffa_device *ffa_dev = optee->ffa.ffa_dev;
const struct ffa_mem_ops *mem_ops = ffa_dev->ops->mem_ops;
struct ffa_mem_region_attributes mem_attr = {
.receiver = ffa_dev->vm_id,
.attrs = FFA_MEM_RW,
@ -294,14 +294,14 @@ static int optee_ffa_shm_register(struct tee_context *ctx, struct tee_shm *shm,
if (rc)
return rc;
args.sg = sgt.sgl;
rc = ffa_ops->memory_share(ffa_dev, &args);
rc = mem_ops->memory_share(&args);
sg_free_table(&sgt);
if (rc)
return rc;
rc = optee_shm_add_ffa_handle(optee, shm, args.g_handle);
if (rc) {
ffa_ops->memory_reclaim(args.g_handle, 0);
mem_ops->memory_reclaim(args.g_handle, 0);
return rc;
}
@ -314,8 +314,9 @@ static int optee_ffa_shm_unregister(struct tee_context *ctx,
struct tee_shm *shm)
{
struct optee *optee = tee_get_drvdata(ctx->teedev);
const struct ffa_dev_ops *ffa_ops = optee->ffa.ffa_ops;
struct ffa_device *ffa_dev = optee->ffa.ffa_dev;
const struct ffa_msg_ops *msg_ops = ffa_dev->ops->msg_ops;
const struct ffa_mem_ops *mem_ops = ffa_dev->ops->mem_ops;
u64 global_handle = shm->sec_world_id;
struct ffa_send_direct_data data = {
.data0 = OPTEE_FFA_UNREGISTER_SHM,
@ -327,11 +328,11 @@ static int optee_ffa_shm_unregister(struct tee_context *ctx,
optee_shm_rem_ffa_handle(optee, global_handle);
shm->sec_world_id = 0;
rc = ffa_ops->sync_send_receive(ffa_dev, &data);
rc = msg_ops->sync_send_receive(ffa_dev, &data);
if (rc)
pr_err("Unregister SHM id 0x%llx rc %d\n", global_handle, rc);
rc = ffa_ops->memory_reclaim(global_handle, 0);
rc = mem_ops->memory_reclaim(global_handle, 0);
if (rc)
pr_err("mem_reclaim: 0x%llx %d", global_handle, rc);
@ -342,7 +343,7 @@ static int optee_ffa_shm_unregister_supp(struct tee_context *ctx,
struct tee_shm *shm)
{
struct optee *optee = tee_get_drvdata(ctx->teedev);
const struct ffa_dev_ops *ffa_ops = optee->ffa.ffa_ops;
const struct ffa_mem_ops *mem_ops;
u64 global_handle = shm->sec_world_id;
int rc;
@ -353,7 +354,8 @@ static int optee_ffa_shm_unregister_supp(struct tee_context *ctx,
*/
optee_shm_rem_ffa_handle(optee, global_handle);
rc = ffa_ops->memory_reclaim(global_handle, 0);
mem_ops = optee->ffa.ffa_dev->ops->mem_ops;
rc = mem_ops->memory_reclaim(global_handle, 0);
if (rc)
pr_err("mem_reclaim: 0x%llx %d", global_handle, rc);
@ -529,8 +531,8 @@ static int optee_ffa_yielding_call(struct tee_context *ctx,
struct optee_msg_arg *rpc_arg)
{
struct optee *optee = tee_get_drvdata(ctx->teedev);
const struct ffa_dev_ops *ffa_ops = optee->ffa.ffa_ops;
struct ffa_device *ffa_dev = optee->ffa.ffa_dev;
const struct ffa_msg_ops *msg_ops = ffa_dev->ops->msg_ops;
struct optee_call_waiter w;
u32 cmd = data->data0;
u32 w4 = data->data1;
@ -541,7 +543,7 @@ static int optee_ffa_yielding_call(struct tee_context *ctx,
/* Initialize waiter */
optee_cq_wait_init(&optee->call_queue, &w);
while (true) {
rc = ffa_ops->sync_send_receive(ffa_dev, data);
rc = msg_ops->sync_send_receive(ffa_dev, data);
if (rc)
goto done;
@ -576,7 +578,7 @@ static int optee_ffa_yielding_call(struct tee_context *ctx,
* OP-TEE has returned with a RPC request.
*
* Note that data->data4 (passed in register w7) is already
* filled in by ffa_ops->sync_send_receive() returning
* filled in by ffa_mem_ops->sync_send_receive() returning
* above.
*/
cond_resched();
@ -652,14 +654,15 @@ static int optee_ffa_do_call_with_arg(struct tee_context *ctx,
*/
static bool optee_ffa_api_is_compatbile(struct ffa_device *ffa_dev,
const struct ffa_dev_ops *ops)
const struct ffa_ops *ops)
{
const struct ffa_msg_ops *msg_ops = ops->msg_ops;
struct ffa_send_direct_data data = { OPTEE_FFA_GET_API_VERSION };
int rc;
ops->mode_32bit_set(ffa_dev);
msg_ops->mode_32bit_set(ffa_dev);
rc = ops->sync_send_receive(ffa_dev, &data);
rc = msg_ops->sync_send_receive(ffa_dev, &data);
if (rc) {
pr_err("Unexpected error %d\n", rc);
return false;
@ -672,7 +675,7 @@ static bool optee_ffa_api_is_compatbile(struct ffa_device *ffa_dev,
}
data = (struct ffa_send_direct_data){ OPTEE_FFA_GET_OS_VERSION };
rc = ops->sync_send_receive(ffa_dev, &data);
rc = msg_ops->sync_send_receive(ffa_dev, &data);
if (rc) {
pr_err("Unexpected error %d\n", rc);
return false;
@ -687,14 +690,14 @@ static bool optee_ffa_api_is_compatbile(struct ffa_device *ffa_dev,
}
static bool optee_ffa_exchange_caps(struct ffa_device *ffa_dev,
const struct ffa_dev_ops *ops,
const struct ffa_ops *ops,
u32 *sec_caps,
unsigned int *rpc_param_count)
{
struct ffa_send_direct_data data = { OPTEE_FFA_EXCHANGE_CAPABILITIES };
int rc;
rc = ops->sync_send_receive(ffa_dev, &data);
rc = ops->msg_ops->sync_send_receive(ffa_dev, &data);
if (rc) {
pr_err("Unexpected error %d", rc);
return false;
@ -783,7 +786,7 @@ static void optee_ffa_remove(struct ffa_device *ffa_dev)
static int optee_ffa_probe(struct ffa_device *ffa_dev)
{
const struct ffa_dev_ops *ffa_ops;
const struct ffa_ops *ffa_ops;
unsigned int rpc_param_count;
struct tee_shm_pool *pool;
struct tee_device *teedev;
@ -793,11 +796,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
u32 sec_caps;
int rc;
ffa_ops = ffa_dev_ops_get(ffa_dev);
if (!ffa_ops) {
pr_warn("failed \"method\" init: ffa\n");
return -ENOENT;
}
ffa_ops = ffa_dev->ops;
if (!optee_ffa_api_is_compatbile(ffa_dev, ffa_ops))
return -EINVAL;
@ -821,7 +820,6 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
optee->ops = &optee_ffa_ops;
optee->ffa.ffa_dev = ffa_dev;
optee->ffa.ffa_ops = ffa_ops;
optee->rpc_param_count = rpc_param_count;
teedev = tee_device_alloc(&optee_ffa_clnt_desc, NULL, optee->pool,

View File

@ -111,7 +111,6 @@ struct optee_smc {
*/
struct optee_ffa {
struct ffa_device *ffa_dev;
const struct ffa_dev_ops *ffa_ops;
/* Serializes access to @global_ids */
struct mutex mutex;
struct rhashtable global_ids;

View File

@ -1083,8 +1083,8 @@ config SERIAL_TIMBERDALE
config SERIAL_BCM63XX
tristate "Broadcom BCM63xx/BCM33xx UART support"
select SERIAL_CORE
depends on ARCH_BCM4908 || ARCH_BCMBCA || BCM63XX || BMIPS_GENERIC || COMPILE_TEST
default ARCH_BCM4908 || ARCH_BCMBCA || BCM63XX || BMIPS_GENERIC
depends on ARCH_BCMBCA || BCM63XX || BMIPS_GENERIC || COMPILE_TEST
default ARCH_BCMBCA || BCM63XX || BMIPS_GENERIC
help
This enables the driver for the onchip UART core found on
the following chipsets:

Some files were not shown because too many files have changed in this diff Show More