mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 21:21:41 +00:00
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:
commit
ff6862c23d
15
Documentation/ABI/testing/sysfs-platform-brcmstb-memc
Normal file
15
Documentation/ABI/testing/sysfs-platform-brcmstb-memc
Normal 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.
|
@ -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:
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
@ -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";
|
||||
};
|
||||
};
|
148
Documentation/devicetree/bindings/firmware/qcom,scm.yaml
Normal file
148
Documentation/devicetree/bindings/firmware/qcom,scm.yaml
Normal 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";
|
||||
};
|
||||
};
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
@ -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>;
|
||||
};
|
@ -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>;
|
||||
};
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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";
|
||||
};
|
||||
...
|
@ -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>;
|
||||
};
|
||||
};
|
@ -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>;
|
||||
};
|
||||
...
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -27,25 +27,22 @@ properties:
|
||||
const: 1
|
||||
|
||||
power-domains:
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
|
||||
power-domain-names:
|
||||
items:
|
||||
- const: bus
|
||||
- const: g1
|
||||
- const: g2
|
||||
- const: h1
|
||||
maxItems: 4
|
||||
|
||||
clocks:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: g1
|
||||
- const: g2
|
||||
- const: h1
|
||||
maxItems: 3
|
||||
|
||||
interconnects:
|
||||
maxItems: 3
|
||||
|
||||
interconnect-names:
|
||||
maxItems: 3
|
||||
|
||||
required:
|
||||
- compatible
|
||||
@ -55,6 +52,97 @@ required:
|
||||
- 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
|
||||
- const: g1
|
||||
- const: g2
|
||||
- const: h1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: G1 decoder clk
|
||||
- description: G2 decoder clk
|
||||
- description: H1 encoder clk
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: g1
|
||||
- const: g2
|
||||
- const: h1
|
||||
|
||||
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
|
||||
|
||||
examples:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>;
|
||||
};
|
96
Documentation/devicetree/bindings/soc/imx/fsl,imx93-src.yaml
Normal file
96
Documentation/devicetree/bindings/soc/imx/fsl,imx93-src.yaml
Normal 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>;
|
||||
};
|
||||
};
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
15
MAINTAINERS
15
MAINTAINERS
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,28 +503,45 @@ static int hisi_lpc_acpi_add_child(struct acpi_device *child, void *data)
|
||||
/* ipmi */
|
||||
{
|
||||
.hid = "IPI0001",
|
||||
.name = "hisi-lpc-ipmi",
|
||||
.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",
|
||||
.name = "serial8250",
|
||||
.pdata = (struct plat_serial8250_port []) {
|
||||
.pdevinfo = (struct platform_device_info []) {
|
||||
{
|
||||
.iobase = res->start,
|
||||
.uartclk = 1843200,
|
||||
.iotype = UPIO_PORT,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.parent = hostdev,
|
||||
.fwnode = acpi_fwnode_handle(child),
|
||||
.name = "serial8250",
|
||||
.id = PLATFORM_DEVID_AUTO,
|
||||
.res = res,
|
||||
.num_res = num_res,
|
||||
.data = (struct plat_serial8250_port []) {
|
||||
{
|
||||
.iobase = res->start,
|
||||
.uartclk = 1843200,
|
||||
.iotype = UPIO_PORT,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
},
|
||||
{}
|
||||
},
|
||||
.size_data = 2 * sizeof(struct plat_serial8250_port),
|
||||
},
|
||||
{}
|
||||
},
|
||||
.pdata_size = 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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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_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_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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
301
drivers/memory/brcmstb_memc.c
Normal file
301
drivers/memory/brcmstb_memc.c
Normal 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");
|
@ -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;
|
||||
}
|
||||
|
@ -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},
|
||||
|
@ -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++;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
}
|
||||
|
@ -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");
|
||||
|
436
drivers/soc/imx/imx93-blk-ctrl.c
Normal file
436
drivers/soc/imx/imx93-blk-ctrl.c
Normal 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, ®map_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
164
drivers/soc/imx/imx93-pd.c
Normal 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");
|
33
drivers/soc/imx/imx93-src.c
Normal file
33
drivers/soc/imx/imx93-src.c
Normal 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");
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
static unsigned int bwmon_kbps_to_count(struct icc_bwmon *bwmon,
|
||||
unsigned int kbps)
|
||||
{
|
||||
return kbps / BWMON_COUNT_UNIT_KB;
|
||||
return kbps / bwmon->data->count_unit_kb;
|
||||
}
|
||||
|
||||
static void bwmon_set_threshold(struct icc_bwmon *bwmon, unsigned int reg,
|
||||
unsigned int kbps)
|
||||
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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
u32 type)
|
||||
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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 */ },
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
const struct sunxi_sramc_variant *variant = dev_get_drvdata(dev);
|
||||
|
||||
variant = of_device_get_match_data(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;
|
||||
|
||||
if (reg < SUNXI_SRAM_EMAC_CLOCK_REG)
|
||||
return false;
|
||||
if (reg > SUNXI_SRAM_EMAC_CLOCK_REG + variant->num_emac_clocks * 4)
|
||||
return false;
|
||||
|
||||
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,
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
9
drivers/soc/tegra/cbb/Makefile
Normal file
9
drivers/soc/tegra/cbb/Makefile
Normal 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
|
190
drivers/soc/tegra/cbb/tegra-cbb.c
Normal file
190
drivers/soc/tegra/cbb/tegra-cbb.c
Normal 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;
|
||||
}
|
2364
drivers/soc/tegra/cbb/tegra194-cbb.c
Normal file
2364
drivers/soc/tegra/cbb/tegra194-cbb.c
Normal file
File diff suppressed because it is too large
Load Diff
1113
drivers/soc/tegra/cbb/tegra234-cbb.c
Normal file
1113
drivers/soc/tegra/cbb/tegra234-cbb.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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])
|
||||
@ -2274,7 +2293,7 @@ static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
|
||||
/* GPIO hierarchies stop at the PMC level */
|
||||
if (!err && domain->parent)
|
||||
err = irq_domain_disconnect_hierarchy(domain->parent,
|
||||
err = irq_domain_disconnect_hierarchy(domain->parent,
|
||||
virq);
|
||||
break;
|
||||
}
|
||||
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user