SoC driver updates for 6.2

There are few major updates in the SoC specific drivers, mainly the usual
 reworks and support for variants of the existing SoC.  While this remains
 Arm centric for the most part, the branch now also contains updates to
 risc-v and loongarch specific code in drivers/soc/.
 
 Notable changes include:
 
  - Support for the newly added Qualcomm Snapdragon variants
    (MSM8956, MSM8976, SM6115, SM4250, SM8150, SA8155 and SM8550) in the
    soc ID, rpmh, rpm, spm and powerdomain drivers.
 
  - Documentation for the somewhat controversial qcom,board-id
    properties that are required for booting a number of machines
 
  - A new SoC identification driver for the loongson-2 (loongarch)
    platform
 
  - memory controller updates for stm32, tegra, and renesas.
 
  - a new DT binding to better describe LPDDR2/3/4/5 chips in
    the memory controller subsystem
 
  - Updates for Tegra specific drivers across multiple subsystems,
    improving support for newer SoCs and better identification
 
  - Minor fixes for Broadcom, Freescale, Apple, Renesas, Sifive,
    TI, Mediatek and Marvell SoC drivers
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmOSAZ8ACgkQmmx57+YA
 GNmoDw/9Hdz2rx6TtdjA2eMKFt97bK0EgrQADT1d4lPQzXzZzFDC9ZxL0bwZRujZ
 b8Q6WrMMgcRiWmzmRlxQWMWEdBU8Y0OzeYlo4lbyCSOV+UA2OA/eu6rm0chapBgM
 1/lkquYLUUcB31wg+NmADoKy5Ejxj9SL1Va36Nvng4YpHDrYHKt4gPyCr/EV+KRO
 Q8JpH7vEzQ0P5CGUzeri2UlYWDdF1GXmObqQGF8pq9s6Qz4ACe63r+eJFXAQFiXK
 xewRK7PuvqmQWLVaEnN8dAcSna5P4aIGKOVjQyZjCCp6qTvfm4d2hxTl4dt9gVtt
 vbQPiPQ5ORRzeMmW6wHxSIdy2QCa9CKQDXuMRoOWHfGMrAZQaxruISpcmHYv9Ug+
 nSfedIEtxtmpGK2SZ1Mvndkezbb0o5QXZF4+kxqpiE/EaxVWmxiecmrUqyvJ5RVv
 RuaZeMQpeOaWElnxb2P/T5uLuoHGhDdZ98HXICuCWPAitvA2rRK4Rv3dqTeclPLa
 HR9gVYgZK3CSj+e9xbe5uczIc664bscRl9unghtB3UWkGTiLt2rroX4T2pTU/2xf
 YvzDHC+f42NEkXUzcs4cZ87R8iY2hr0LmePY5/lqF9k6qx0Rc3syNc7q4N4EBxGC
 2y5dDpKXfFL6fEV4YNeGpNcrwmCwnNppcePjmNvgrdtqmUUB/mY=
 =heNV
 -----END PGP SIGNATURE-----

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

Pull ARM SoC driver updates from Arnd Bergmann:
 "There are few major updates in the SoC specific drivers, mainly the
  usual reworks and support for variants of the existing SoC. While this
  remains Arm centric for the most part, the branch now also contains
  updates to risc-v and loongarch specific code in drivers/soc/.

  Notable changes include:

   - Support for the newly added Qualcomm Snapdragon variants (MSM8956,
     MSM8976, SM6115, SM4250, SM8150, SA8155 and SM8550) in the soc ID,
     rpmh, rpm, spm and powerdomain drivers.

   - Documentation for the somewhat controversial qcom,board-id
     properties that are required for booting a number of machines

   - A new SoC identification driver for the loongson-2 (loongarch)
     platform

   - memory controller updates for stm32, tegra, and renesas.

   - a new DT binding to better describe LPDDR2/3/4/5 chips in the
     memory controller subsystem

   - Updates for Tegra specific drivers across multiple subsystems,
     improving support for newer SoCs and better identification

   - Minor fixes for Broadcom, Freescale, Apple, Renesas, Sifive, TI,
     Mediatek and Marvell SoC drivers"

* tag 'soc-drivers-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (137 commits)
  soc: qcom: socinfo: Add SM6115 / SM4250 SoC IDs to the soc_id table
  dt-bindings: arm: qcom,ids: Add SoC IDs for SM6115 / SM4250 and variants
  soc: qcom: socinfo: Add SM8150 and SA8155 SoC IDs to the soc_id table
  dt-bindings: arm: qcom,ids: Add SoC IDs for SM8150 and SA8155
  dt-bindings: soc: qcom: apr: document generic qcom,apr compatible
  soc: qcom: Select REMAP_MMIO for ICC_BWMON driver
  soc: qcom: Select REMAP_MMIO for LLCC driver
  soc: qcom: rpmpd: Add SM4250 support
  dt-bindings: power: rpmpd: Add SM4250 support
  dt-bindings: soc: qcom: aoss: Add compatible for SM8550
  soc: qcom: llcc: Add configuration data for SM8550
  dt-bindings: arm: msm: Add LLCC compatible for SM8550
  soc: qcom: llcc: Add v4.1 HW version support
  soc: qcom: socinfo: Add SM8550 ID
  soc: qcom: rpmh-rsc: Avoid unnecessary checks on irq-done response
  soc: qcom: rpmh-rsc: Add support for RSC v3 register offsets
  soc: qcom: rpmhpd: Add SM8550 power domains
  dt-bindings: power: rpmpd: Add SM8550 to rpmpd binding
  soc: qcom: socinfo: Add MSM8956/76 SoC IDs to the soc_id table
  dt-bindings: arm: qcom,ids: Add SoC IDs for MSM8956 and MSM8976
  ...
This commit is contained in:
Linus Torvalds 2022-12-12 10:17:08 -08:00
commit 8e17b16a2c
118 changed files with 6541 additions and 1877 deletions

View file

@ -32,14 +32,26 @@ properties:
- mediatek,mt8183-mmsys
- mediatek,mt8186-mmsys
- mediatek,mt8192-mmsys
- mediatek,mt8195-mmsys
- mediatek,mt8365-mmsys
- const: syscon
- description: vdosys0 and vdosys1 are 2 display HW pipelines,
so mt8195 binding should be deprecated.
deprecated: true
items:
- const: mediatek,mt8195-mmsys
- const: syscon
- items:
- const: mediatek,mt7623-mmsys
- const: mediatek,mt2701-mmsys
- const: syscon
- items:
- const: mediatek,mt8195-vdosys0
- const: mediatek,mt8195-mmsys
- const: syscon
reg:
maxItems: 1

View file

@ -31,6 +31,7 @@ properties:
- qcom,sm8250-llcc
- qcom,sm8350-llcc
- qcom,sm8450-llcc
- qcom,sm8550-llcc
reg:
items:

View file

@ -739,6 +739,126 @@ properties:
- sony,pdx223
- const: qcom,sm8450
# Board compatibles go above
qcom,msm-id:
$ref: /schemas/types.yaml#/definitions/uint32-matrix
minItems: 1
maxItems: 8
items:
items:
- description: |
MSM chipset ID - an exact match value consisting of two bitfields::
- bits 0-15 - The unique MSM chipset ID
- bits 16-31 - Reserved; should be 0
- description: |
Hardware revision ID - a chipset specific 32-bit ID representing
the version of the chipset. It is best a match value - the
bootloader will look for the closest possible match.
deprecated: true
description:
The MSM chipset and hardware revision used Qualcomm bootloaders. It
can optionally be an array of these to indicate multiple hardware that
use the same device tree. It is expected that the bootloader will use
this information at boot-up to decide which device tree to use when given
multiple device trees, some of which may not be compatible with the
actual hardware. It is the bootloader's responsibility to pass the
correct device tree to the kernel.
The property is deprecated.
qcom,board-id:
$ref: /schemas/types.yaml#/definitions/uint32-matrix
minItems: 1
maxItems: 8
oneOf:
- items:
- items:
- description: |
Board ID consisting of three bitfields::
- bits 31-24 - Unused
- bits 23-16 - Platform Version Major
- bits 15-8 - Platform Version Minor
- bits 7-0 - Platform Type
Platform Type field is an exact match value. The
Platform Major/Minor field is a best match. The bootloader will
look for the closest possible match.
- description: |
Subtype ID unique to a Platform Type/Chipset ID. For a given
Platform Type, there will typically only be a single board and the
subtype_id will be 0. However in some cases board variants may
need to be distinguished by different subtype_id values.
- items:
# OnePlus uses a variant of board-id with four elements:
- items:
- const: 8
- const: 0
- description: OnePlus board ID
- description: OnePlus subtype ID
deprecated: true
description:
The board type and revision information. It can optionally be an array
of these to indicate multiple boards that use the same device tree. It
is expected that the bootloader will use this information at boot-up to
decide which device tree to use when given multiple device trees, some of
which may not be compatible with the actual hardware. It is the
bootloader's responsibility to pass the correct device tree to the
kernel
The property is deprecated.
allOf:
# Explicit allow-list for older SoCs. The legacy properties are not allowed
# on newer SoCs.
- if:
properties:
compatible:
contains:
enum:
- qcom,apq8026
- qcom,apq8094
- qcom,apq8096
- qcom,msm8992
- qcom,msm8994
- qcom,msm8996
- qcom,msm8998
- qcom,sdm630
- qcom,sdm632
- qcom,sdm845
- qcom,sdx55
- qcom,sdx65
- qcom,sm6125
- qcom,sm6350
- qcom,sm7225
- qcom,sm8150
- qcom,sm8250
then:
properties:
qcom,board-id: true
qcom,msm-id: true
else:
properties:
qcom,board-id: false
qcom,msm-id: false
- if:
properties:
compatible:
contains:
enum:
- oneplus,cheeseburger
- oneplus,dumpling
- oneplus,enchilada
- oneplus,fajita
then:
properties:
qcom,board-id:
items:
minItems: 4
else:
properties:
qcom,board-id:
items:
maxItems: 2
additionalProperties: true
...

View file

@ -41,12 +41,14 @@ properties:
- qcom,scm-sc7180
- qcom,scm-sc7280
- qcom,scm-sc8280xp
- qcom,scm-sdm670
- qcom,scm-sdm845
- qcom,scm-sdx55
- qcom,scm-sdx65
- qcom,scm-sm6115
- qcom,scm-sm6125
- qcom,scm-sm6350
- qcom,scm-sm6375
- qcom,scm-sm8150
- qcom,scm-sm8250
- qcom,scm-sm8350
@ -88,6 +90,7 @@ allOf:
- qcom,scm-apq8064
- qcom,scm-msm8660
- qcom,scm-msm8960
- qcom,scm-sm6375
then:
properties:
clock-names:

View file

@ -0,0 +1,38 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwinfo/loongson,ls2k-chipid.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Loongson-2 SoC ChipID
maintainers:
- Yinbo Zhu <zhuyinbo@loongson.cn>
description: |
Loongson-2 SoC contains many groups of global utilities register
blocks, of which the ChipID group registers record SoC version,
feature, vendor and id information.
properties:
compatible:
const: loongson,ls2k-chipid
reg:
maxItems: 1
little-endian: true
required:
- compatible
- reg
additionalProperties: false
examples:
- |
chipid: chipid@1fe00000 {
compatible = "loongson,ls2k-chipid";
reg = <0x1fe00000 0x3ffc>;
little-endian;
};

View file

@ -1,26 +1,31 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/memory-controllers/arm,pl353-smc.yaml#
$id: http://devicetree.org/schemas/memory-controllers/arm,pl35x-smc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ARM PL353 Static Memory Controller (SMC) device-tree bindings
title: Arm PL35x Series Static Memory Controller (SMC)
maintainers:
- Miquel Raynal <miquel.raynal@bootlin.com>
- Naga Sureshkumar Relli <naga.sureshkumar.relli@xilinx.com>
description:
The PL353 Static Memory Controller is a bus where you can connect two kinds
description: |
The PL35x Static Memory Controller is a bus where you can connect two kinds
of memory interfaces, which are NAND and memory mapped interfaces (such as
SRAM or NOR).
SRAM or NOR) depending on the specific configuration.
The TRM is available here:
https://documentation-service.arm.com/static/5e8e2524fd977155116a58aa
# We need a select here so we don't match all nodes with 'arm,primecell'
select:
properties:
compatible:
contains:
const: arm,pl353-smc-r2p1
enum:
- arm,pl353-smc-r2p1
- arm,pl354
required:
- compatible
@ -30,7 +35,9 @@ properties:
compatible:
items:
- const: arm,pl353-smc-r2p1
- enum:
- arm,pl353-smc-r2p1
- arm,pl354
- const: arm,primecell
"#address-cells":
@ -46,30 +53,25 @@ properties:
The three chip select regions are defined in 'ranges'.
clocks:
items:
- description: clock for the memory device bus
- description: main clock of the SMC
minItems: 1
maxItems: 2
clock-names:
items:
- const: memclk
- const: apb_pclk
minItems: 1
maxItems: 2
ranges:
minItems: 1
description: |
Memory bus areas for interacting with the devices. Reflects
the memory layout with four integer values following:
<cs-number> 0 <offset> <size>
items:
- description: NAND bank 0
- description: NOR/SRAM bank 0
- description: NOR/SRAM bank 1
maxItems: 8
interrupts: true
interrupts:
minItems: 1
items:
- description: Combined or Memory interface 0 IRQ
- description: Memory interface 1 IRQ
patternProperties:
"@[0-3],[a-f0-9]+$":
"@[0-7],[a-f0-9]+$":
type: object
description: |
The child device node represents the controller connected to the SMC
@ -87,7 +89,7 @@ patternProperties:
- description: |
Chip-select ID, as in the parent range property.
minimum: 0
maximum: 2
maximum: 7
- description: |
Offset of the memory region requested by the device.
- description: |
@ -102,12 +104,36 @@ required:
- reg
- clock-names
- clocks
- "#address-cells"
- "#size-cells"
- ranges
additionalProperties: false
allOf:
- if:
properties:
compatible:
contains:
const: arm,pl354
then:
properties:
clocks:
# According to TRM, really should be 3 clocks
maxItems: 1
clock-names:
const: apb_pclk
else:
properties:
clocks:
items:
- description: clock for the memory device bus
- description: main clock of the SMC
clock-names:
items:
- const: memclk
- const: apb_pclk
examples:
- |
smcc: memory-controller@e000e000 {

View file

@ -0,0 +1,146 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/memory-controllers/ddr/jedec,lpddr-channel.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: LPDDR channel with chip/rank topology description
description:
An LPDDR channel is a completely independent set of LPDDR pins (DQ, CA, CS,
CK, etc.) that connect one or more LPDDR chips to a host system. The main
purpose of this node is to overall LPDDR topology of the system, including the
amount of individual LPDDR chips and the ranks per chip.
maintainers:
- Julius Werner <jwerner@chromium.org>
properties:
compatible:
enum:
- jedec,lpddr2-channel
- jedec,lpddr3-channel
- jedec,lpddr4-channel
- jedec,lpddr5-channel
io-width:
description:
The number of DQ pins in the channel. If this number is different
from (a multiple of) the io-width of the LPDDR chip, that means that
multiple instances of that type of chip are wired in parallel on this
channel (with the channel's DQ pins split up between the different
chips, and the CA, CS, etc. pins of the different chips all shorted
together). This means that the total physical memory controlled by a
channel is equal to the sum of the densities of each rank on the
connected LPDDR chip, times the io-width of the channel divided by
the io-width of the LPDDR chip.
enum:
- 8
- 16
- 32
- 64
- 128
"#address-cells":
const: 1
"#size-cells":
const: 0
patternProperties:
"^rank@[0-9]+$":
type: object
description:
Each physical LPDDR chip may have one or more ranks. Ranks are
internal but fully independent sub-units of the chip. Each LPDDR bus
transaction on the channel targets exactly one rank, based on the
state of the CS pins. Different ranks may have different densities and
timing requirements.
required:
- reg
allOf:
- if:
properties:
compatible:
contains:
const: jedec,lpddr2-channel
then:
patternProperties:
"^rank@[0-9]+$":
$ref: /schemas/memory-controllers/ddr/jedec,lpddr2.yaml#
- if:
properties:
compatible:
contains:
const: jedec,lpddr3-channel
then:
patternProperties:
"^rank@[0-9]+$":
$ref: /schemas/memory-controllers/ddr/jedec,lpddr3.yaml#
- if:
properties:
compatible:
contains:
const: jedec,lpddr4-channel
then:
patternProperties:
"^rank@[0-9]+$":
$ref: /schemas/memory-controllers/ddr/jedec,lpddr4.yaml#
- if:
properties:
compatible:
contains:
const: jedec,lpddr5-channel
then:
patternProperties:
"^rank@[0-9]+$":
$ref: /schemas/memory-controllers/ddr/jedec,lpddr5.yaml#
required:
- compatible
- io-width
- "#address-cells"
- "#size-cells"
additionalProperties: false
examples:
- |
lpddr-channel0 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "jedec,lpddr3-channel";
io-width = <32>;
rank@0 {
compatible = "lpddr3-ff,0100", "jedec,lpddr3";
reg = <0>;
density = <8192>;
io-width = <16>;
revision-id = <1 0>;
};
};
lpddr-channel1 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "jedec,lpddr4-channel";
io-width = <32>;
rank@0 {
compatible = "lpddr4-05,0301", "jedec,lpddr4";
reg = <0>;
density = <4096>;
io-width = <32>;
revision-id = <3 1>;
};
rank@1 {
compatible = "lpddr4-05,0301", "jedec,lpddr4";
reg = <1>;
density = <2048>;
io-width = <32>;
revision-id = <3 1>;
};
};

View file

@ -0,0 +1,74 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/memory-controllers/ddr/jedec,lpddr-props.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Common properties for LPDDR types
description:
Different LPDDR types generally use the same properties and only differ in the
range of legal values for each. This file defines the common parts that can be
reused for each type. Nodes using this schema should generally be nested under
an LPDDR channel node.
maintainers:
- Krzysztof Kozlowski <krzk@kernel.org>
properties:
compatible:
description:
Compatible strings can be either explicit vendor names and part numbers
(e.g. elpida,ECB240ABACN), or generated strings of the form
lpddrX-YY,ZZZZ where X is the LPDDR version, YY is the manufacturer ID
(from MR5) and ZZZZ is the revision ID (from MR6 and MR7). Both IDs are
formatted in lower case hexadecimal representation with leading zeroes.
The latter form can be useful when LPDDR nodes are created at runtime by
boot firmware that doesn't have access to static part number information.
reg:
description:
The rank number of this LPDDR rank when used as a subnode to an LPDDR
channel.
minimum: 0
maximum: 3
revision-id:
$ref: /schemas/types.yaml#/definitions/uint32-array
description:
Revision IDs read from Mode Register 6 and 7. One byte per uint32 cell (i.e. <MR6 MR7>).
maxItems: 2
items:
minimum: 0
maximum: 255
density:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Density in megabits of SDRAM chip. Decoded from Mode Register 8.
enum:
- 64
- 128
- 256
- 512
- 1024
- 2048
- 3072
- 4096
- 6144
- 8192
- 12288
- 16384
- 24576
- 32768
io-width:
$ref: /schemas/types.yaml#/definitions/uint32
description:
IO bus width in bits of SDRAM chip. Decoded from Mode Register 8.
enum:
- 8
- 16
- 32
additionalProperties: true

View file

@ -9,6 +9,9 @@ title: LPDDR2 SDRAM compliant to JEDEC JESD209-2
maintainers:
- Krzysztof Kozlowski <krzk@kernel.org>
allOf:
- $ref: jedec,lpddr-props.yaml#
properties:
compatible:
oneOf:
@ -17,13 +20,15 @@ properties:
- elpida,ECB240ABACN
- elpida,B8132B2PB-6D-F
- enum:
- jedec,lpddr2-nvm
- jedec,lpddr2-s2
- jedec,lpddr2-s4
- items:
- enum:
- jedec,lpddr2-s2
- items:
- pattern: "^lpddr2-[0-9a-f]{2},[0-9a-f]{4}$"
- enum:
- jedec,lpddr2-nvm
- jedec,lpddr2-s2
- jedec,lpddr2-s4
revision-id1:
$ref: /schemas/types.yaml#/definitions/uint32
@ -41,41 +46,6 @@ properties:
Property is deprecated, use revision-id instead.
deprecated: true
revision-id:
$ref: /schemas/types.yaml#/definitions/uint32-array
description: |
Revision IDs read from Mode Register 6 and 7. One byte per uint32 cell (i.e. <MR6 MR7>).
minItems: 2
maxItems: 2
items:
minimum: 0
maximum: 255
density:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
Density in megabits of SDRAM chip. Obtained from device datasheet.
enum:
- 64
- 128
- 256
- 512
- 1024
- 2048
- 4096
- 8192
- 16384
- 32768
io-width:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
IO bus width in bits of SDRAM chip. Obtained from device datasheet.
enum:
- 32
- 16
- 8
tRRD-min-tck:
$ref: /schemas/types.yaml#/definitions/uint32
maximum: 16
@ -168,7 +138,7 @@ required:
- density
- io-width
additionalProperties: false
unevaluatedProperties: false
examples:
- |

View file

@ -9,35 +9,24 @@ title: LPDDR3 SDRAM compliant to JEDEC JESD209-3
maintainers:
- Krzysztof Kozlowski <krzk@kernel.org>
allOf:
- $ref: jedec,lpddr-props.yaml#
properties:
compatible:
items:
- enum:
- samsung,K3QF2F20DB
- const: jedec,lpddr3
oneOf:
- items:
- enum:
- samsung,K3QF2F20DB
- const: jedec,lpddr3
- items:
- pattern: "^lpddr3-[0-9a-f]{2},[0-9a-f]{4}$"
- const: jedec,lpddr3
'#address-cells':
const: 1
deprecated: true
density:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
Density in megabits of SDRAM chip.
enum:
- 4096
- 8192
- 16384
- 32768
io-width:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
IO bus width in bits of SDRAM chip.
enum:
- 32
- 16
manufacturer-id:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
@ -45,15 +34,6 @@ properties:
deprecated, manufacturer should be derived from the compatible.
deprecated: true
revision-id:
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 2
maxItems: 2
items:
maximum: 255
description: |
Revision value of SDRAM chip read from Mode Registers 6 and 7.
'#size-cells':
const: 0
deprecated: true
@ -206,7 +186,7 @@ required:
- density
- io-width
additionalProperties: false
unevaluatedProperties: false
examples:
- |

View file

@ -0,0 +1,35 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/memory-controllers/ddr/jedec,lpddr4.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: LPDDR4 SDRAM compliant to JEDEC JESD209-4
maintainers:
- Krzysztof Kozlowski <krzk@kernel.org>
allOf:
- $ref: jedec,lpddr-props.yaml#
properties:
compatible:
items:
- pattern: "^lpddr4-[0-9a-f]{2},[0-9a-f]{4}$"
- const: jedec,lpddr4
required:
- compatible
- density
- io-width
unevaluatedProperties: false
examples:
- |
lpddr {
compatible = "lpddr4-ff,0100", "jedec,lpddr4";
density = <8192>;
io-width = <16>;
revision-id = <1 0>;
};

View file

@ -0,0 +1,46 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/memory-controllers/ddr/jedec,lpddr5.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: LPDDR5 SDRAM compliant to JEDEC JESD209-5
maintainers:
- Krzysztof Kozlowski <krzk@kernel.org>
allOf:
- $ref: jedec,lpddr-props.yaml#
properties:
compatible:
items:
- pattern: "^lpddr5-[0-9a-f]{2},[0-9a-f]{4}$"
- const: jedec,lpddr5
serial-id:
$ref: /schemas/types.yaml#/definitions/uint32-array
description:
Serial IDs read from Mode Registers 47 through 54. One byte per uint32
cell (i.e. <MR47 MR48 MR49 MR50 MR51 MR52 MR53 MR54>).
maxItems: 8
items:
minimum: 0
maximum: 255
required:
- compatible
- density
- io-width
unevaluatedProperties: false
examples:
- |
lpddr {
compatible = "lpddr5-01,0200", "jedec,lpddr5";
density = <8192>;
io-width = <8>;
revision-id = <2 0>;
serial-id = <3 1 0 0 0 0 0 0>;
};

View file

@ -0,0 +1,38 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/memory-controllers/mc-peripheral-props.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Peripheral-specific properties for a Memory Controller bus.
description:
Many Memory Controllers need to add properties to peripheral devices.
They could be common properties like reg or they could be controller
specific like delay in clock or data lines, etc. These properties need
to be defined in the peripheral node because they are per-peripheral
and there can be multiple peripherals attached to a controller. All
those properties are listed here. The controller specific properties
should go in their own separate schema that should be referenced
from here.
maintainers:
- Marek Vasut <marex@denx.de>
properties:
reg:
description: Bank number, base address and size of the device.
bank-width:
$ref: /schemas/types.yaml#/definitions/uint32
description: Bank width of the device, in bytes.
enum: [1, 2, 4]
required:
- reg
# The controller specific properties go here.
allOf:
- $ref: st,stm32-fmc2-ebi-props.yaml#
additionalProperties: true

View file

@ -42,6 +42,11 @@ properties:
- renesas,r8a779a0-rpc-if # R-Car V3U
- const: renesas,rcar-gen3-rpc-if # a generic R-Car gen3 or RZ/G2{E,H,M,N} device
- items:
- enum:
- renesas,r8a779g0-rpc-if # R-Car V4H
- const: renesas,rcar-gen4-rpc-if # a generic R-Car gen4 device
- items:
- enum:
- renesas,r9a07g043-rpc-if # RZ/G2UL

View file

@ -0,0 +1,144 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/memory-controllers/st,stm32-fmc2-ebi-props.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Peripheral properties for ST FMC2 Controller
maintainers:
- Christophe Kerello <christophe.kerello@foss.st.com>
- Marek Vasut <marex@denx.de>
properties:
st,fmc2-ebi-cs-transaction-type:
description: |
Select one of the transactions type supported
0: Asynchronous mode 1 SRAM/FRAM.
1: Asynchronous mode 1 PSRAM.
2: Asynchronous mode A SRAM/FRAM.
3: Asynchronous mode A PSRAM.
4: Asynchronous mode 2 NOR.
5: Asynchronous mode B NOR.
6: Asynchronous mode C NOR.
7: Asynchronous mode D NOR.
8: Synchronous read synchronous write PSRAM.
9: Synchronous read asynchronous write PSRAM.
10: Synchronous read synchronous write NOR.
11: Synchronous read asynchronous write NOR.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 11
st,fmc2-ebi-cs-cclk-enable:
description: Continuous clock enable (first bank must be configured
in synchronous mode). The FMC_CLK is generated continuously
during asynchronous and synchronous access. By default, the
FMC_CLK is only generated during synchronous access.
$ref: /schemas/types.yaml#/definitions/flag
st,fmc2-ebi-cs-mux-enable:
description: Address/Data multiplexed on databus (valid only with
NOR and PSRAM transactions type). By default, Address/Data
are not multiplexed.
$ref: /schemas/types.yaml#/definitions/flag
st,fmc2-ebi-cs-buswidth:
description: Data bus width
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 8, 16 ]
default: 16
st,fmc2-ebi-cs-waitpol-high:
description: Wait signal polarity (NWAIT signal active high).
By default, NWAIT is active low.
$ref: /schemas/types.yaml#/definitions/flag
st,fmc2-ebi-cs-waitcfg-enable:
description: The NWAIT signal indicates wheither the data from the
device are valid or if a wait state must be inserted when accessing
the device in synchronous mode. By default, the NWAIT signal is
active one data cycle before wait state.
$ref: /schemas/types.yaml#/definitions/flag
st,fmc2-ebi-cs-wait-enable:
description: The NWAIT signal is enabled (its level is taken into
account after the programmed latency period to insert wait states
if asserted). By default, the NWAIT signal is disabled.
$ref: /schemas/types.yaml#/definitions/flag
st,fmc2-ebi-cs-asyncwait-enable:
description: The NWAIT signal is taken into account during asynchronous
transactions. By default, the NWAIT signal is not taken into account
during asynchronous transactions.
$ref: /schemas/types.yaml#/definitions/flag
st,fmc2-ebi-cs-cpsize:
description: CRAM page size. The controller splits the burst access
when the memory page is reached. By default, no burst split when
crossing page boundary.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 0, 128, 256, 512, 1024 ]
default: 0
st,fmc2-ebi-cs-byte-lane-setup-ns:
description: This property configures the byte lane setup timing
defined in nanoseconds from NBLx low to Chip Select NEx low.
st,fmc2-ebi-cs-address-setup-ns:
description: This property defines the duration of the address setup
phase in nanoseconds used for asynchronous read/write transactions.
st,fmc2-ebi-cs-address-hold-ns:
description: This property defines the duration of the address hold
phase in nanoseconds used for asynchronous multiplexed read/write
transactions.
st,fmc2-ebi-cs-data-setup-ns:
description: This property defines the duration of the data setup phase
in nanoseconds used for asynchronous read/write transactions.
st,fmc2-ebi-cs-bus-turnaround-ns:
description: This property defines the delay in nanoseconds between the
end of current read/write transaction and the next transaction.
st,fmc2-ebi-cs-data-hold-ns:
description: This property defines the duration of the data hold phase
in nanoseconds used for asynchronous read/write transactions.
st,fmc2-ebi-cs-clk-period-ns:
description: This property defines the FMC_CLK output signal period in
nanoseconds.
st,fmc2-ebi-cs-data-latency-ns:
description: This property defines the data latency before reading or
writing the first data in nanoseconds.
st,fmc2-ebi-cs-write-address-setup-ns:
description: This property defines the duration of the address setup
phase in nanoseconds used for asynchronous write transactions.
st,fmc2-ebi-cs-write-address-hold-ns:
description: This property defines the duration of the address hold
phase in nanoseconds used for asynchronous multiplexed write
transactions.
st,fmc2-ebi-cs-write-data-setup-ns:
description: This property defines the duration of the data setup
phase in nanoseconds used for asynchronous write transactions.
st,fmc2-ebi-cs-write-bus-turnaround-ns:
description: This property defines the delay between the end of current
write transaction and the next transaction in nanoseconds.
st,fmc2-ebi-cs-write-data-hold-ns:
description: This property defines the duration of the data hold phase
in nanoseconds used for asynchronous write transactions.
st,fmc2-ebi-cs-max-low-pulse-ns:
description: This property defines the maximum chip select low pulse
duration in nanoseconds for synchronous transactions. When this timing
reaches 0, the controller splits the current access, toggles NE to
allow device refresh and restarts a new access.
additionalProperties: true

View file

@ -48,143 +48,7 @@ properties:
patternProperties:
"^.*@[0-4],[a-f0-9]+$":
type: object
properties:
reg:
description: Bank number, base address and size of the device.
st,fmc2-ebi-cs-transaction-type:
description: |
Select one of the transactions type supported
0: Asynchronous mode 1 SRAM/FRAM.
1: Asynchronous mode 1 PSRAM.
2: Asynchronous mode A SRAM/FRAM.
3: Asynchronous mode A PSRAM.
4: Asynchronous mode 2 NOR.
5: Asynchronous mode B NOR.
6: Asynchronous mode C NOR.
7: Asynchronous mode D NOR.
8: Synchronous read synchronous write PSRAM.
9: Synchronous read asynchronous write PSRAM.
10: Synchronous read synchronous write NOR.
11: Synchronous read asynchronous write NOR.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 11
st,fmc2-ebi-cs-cclk-enable:
description: Continuous clock enable (first bank must be configured
in synchronous mode). The FMC_CLK is generated continuously
during asynchronous and synchronous access. By default, the
FMC_CLK is only generated during synchronous access.
$ref: /schemas/types.yaml#/definitions/flag
st,fmc2-ebi-cs-mux-enable:
description: Address/Data multiplexed on databus (valid only with
NOR and PSRAM transactions type). By default, Address/Data
are not multiplexed.
$ref: /schemas/types.yaml#/definitions/flag
st,fmc2-ebi-cs-buswidth:
description: Data bus width
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 8, 16 ]
default: 16
st,fmc2-ebi-cs-waitpol-high:
description: Wait signal polarity (NWAIT signal active high).
By default, NWAIT is active low.
$ref: /schemas/types.yaml#/definitions/flag
st,fmc2-ebi-cs-waitcfg-enable:
description: The NWAIT signal indicates wheither the data from the
device are valid or if a wait state must be inserted when accessing
the device in synchronous mode. By default, the NWAIT signal is
active one data cycle before wait state.
$ref: /schemas/types.yaml#/definitions/flag
st,fmc2-ebi-cs-wait-enable:
description: The NWAIT signal is enabled (its level is taken into
account after the programmed latency period to insert wait states
if asserted). By default, the NWAIT signal is disabled.
$ref: /schemas/types.yaml#/definitions/flag
st,fmc2-ebi-cs-asyncwait-enable:
description: The NWAIT signal is taken into account during asynchronous
transactions. By default, the NWAIT signal is not taken into account
during asynchronous transactions.
$ref: /schemas/types.yaml#/definitions/flag
st,fmc2-ebi-cs-cpsize:
description: CRAM page size. The controller splits the burst access
when the memory page is reached. By default, no burst split when
crossing page boundary.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 0, 128, 256, 512, 1024 ]
default: 0
st,fmc2-ebi-cs-byte-lane-setup-ns:
description: This property configures the byte lane setup timing
defined in nanoseconds from NBLx low to Chip Select NEx low.
st,fmc2-ebi-cs-address-setup-ns:
description: This property defines the duration of the address setup
phase in nanoseconds used for asynchronous read/write transactions.
st,fmc2-ebi-cs-address-hold-ns:
description: This property defines the duration of the address hold
phase in nanoseconds used for asynchronous multiplexed read/write
transactions.
st,fmc2-ebi-cs-data-setup-ns:
description: This property defines the duration of the data setup phase
in nanoseconds used for asynchronous read/write transactions.
st,fmc2-ebi-cs-bus-turnaround-ns:
description: This property defines the delay in nanoseconds between the
end of current read/write transaction and the next transaction.
st,fmc2-ebi-cs-data-hold-ns:
description: This property defines the duration of the data hold phase
in nanoseconds used for asynchronous read/write transactions.
st,fmc2-ebi-cs-clk-period-ns:
description: This property defines the FMC_CLK output signal period in
nanoseconds.
st,fmc2-ebi-cs-data-latency-ns:
description: This property defines the data latency before reading or
writing the first data in nanoseconds.
st,fmc2_ebi-cs-write-address-setup-ns:
description: This property defines the duration of the address setup
phase in nanoseconds used for asynchronous write transactions.
st,fmc2-ebi-cs-write-address-hold-ns:
description: This property defines the duration of the address hold
phase in nanoseconds used for asynchronous multiplexed write
transactions.
st,fmc2-ebi-cs-write-data-setup-ns:
description: This property defines the duration of the data setup
phase in nanoseconds used for asynchronous write transactions.
st,fmc2-ebi-cs-write-bus-turnaround-ns:
description: This property defines the delay between the end of current
write transaction and the next transaction in nanoseconds.
st,fmc2-ebi-cs-write-data-hold-ns:
description: This property defines the duration of the data hold phase
in nanoseconds used for asynchronous write transactions.
st,fmc2-ebi-cs-max-low-pulse-ns:
description: This property defines the maximum chip select low pulse
duration in nanoseconds for synchronous transactions. When this timing
reaches 0, the controller splits the current access, toggles NE to
allow device refresh and restarts a new access.
required:
- reg
$ref: mc-peripheral-props.yaml#
required:
- "#address-cells"

View file

@ -230,6 +230,13 @@ properties:
Wait-pin used by client. Must be less than "gpmc,num-waitpins".
$ref: /schemas/types.yaml#/definitions/uint32
ti,wait-pin-polarity:
description: |
Set the desired polarity for the selected wait pin.
0 for active low, 1 for active high.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1]
gpmc,wait-on-read:
description: Enables wait monitoring on reads.
type: boolean

View file

@ -44,6 +44,7 @@ required:
allOf:
- $ref: ethernet-controller.yaml#
- $ref: /schemas/memory-controllers/mc-peripheral-props.yaml#
- if:
properties:
compatible:

View file

@ -28,15 +28,18 @@ properties:
- qcom,msm8998-rpmpd
- qcom,qcm2290-rpmpd
- qcom,qcs404-rpmpd
- qcom,qdu1000-rpmhpd
- qcom,sa8540p-rpmhpd
- qcom,sdm660-rpmpd
- qcom,sc7180-rpmhpd
- qcom,sc7280-rpmhpd
- qcom,sc8180x-rpmhpd
- qcom,sc8280xp-rpmhpd
- qcom,sdm670-rpmhpd
- qcom,sdm845-rpmhpd
- qcom,sdx55-rpmhpd
- qcom,sdx65-rpmhpd
- qcom,sm4250-rpmpd
- qcom,sm6115-rpmpd
- qcom,sm6125-rpmpd
- qcom,sm6350-rpmhpd
@ -45,6 +48,7 @@ properties:
- qcom,sm8250-rpmhpd
- qcom,sm8350-rpmhpd
- qcom,sm8450-rpmhpd
- qcom,sm8550-rpmhpd
'#power-domain-cells':
const: 1

View file

@ -30,6 +30,7 @@ Required properties in pwrap device node.
"mediatek,mt8186-pwrap" for MT8186 SoCs
"mediatek,mt8188-pwrap", "mediatek,mt8195-pwrap" for MT8188 SoCs
"mediatek,mt8195-pwrap" for MT8195 SoCs
"mediatek,mt8365-pwrap" for MT8365 SoCs
"mediatek,mt8516-pwrap" for MT8516 SoCs
- interrupts: IRQ for pwrap in SOC
- reg-names: "pwrap" is required; "pwrap-bridge" is optional.
@ -39,6 +40,8 @@ Required properties in pwrap device node.
- clock-names: Must include the following entries:
"spi": SPI bus clock
"wrap": Main module clock
"sys": Optional system module clock
"tmr": Optional timer module clock
- clocks: Must contain an entry for each entry in clock-names.
Optional properities:

View file

@ -28,12 +28,14 @@ properties:
- qcom,sc7180-aoss-qmp
- qcom,sc7280-aoss-qmp
- qcom,sc8180x-aoss-qmp
- qcom,sc8280xp-aoss-qmp
- qcom,sdm845-aoss-qmp
- qcom,sm6350-aoss-qmp
- qcom,sm8150-aoss-qmp
- qcom,sm8250-aoss-qmp
- qcom,sm8350-aoss-qmp
- qcom,sm8450-aoss-qmp
- qcom,sm8550-aoss-qmp
- const: qcom,aoss-qmp
reg:

View file

@ -17,6 +17,7 @@ description: |
properties:
compatible:
enum:
- qcom,apr
- qcom,apr-v2
- qcom,gpr

View file

@ -99,6 +99,9 @@ properties:
- const: drv-2
- const: drv-3
power-domains:
maxItems: 1
bcm-voter:
$ref: /schemas/interconnect/qcom,bcm-voter.yaml#
@ -151,6 +154,7 @@ examples:
<SLEEP_TCS 3>,
<WAKE_TCS 3>,
<CONTROL_TCS 1>;
power-domains = <&CLUSTER_PD>;
};
- |
@ -197,6 +201,7 @@ examples:
<SLEEP_TCS 3>,
<WAKE_TCS 3>,
<CONTROL_TCS 0>;
power-domains = <&CLUSTER_PD>;
clock-controller {
compatible = "qcom,sm8350-rpmh-clk";

View file

@ -4,7 +4,7 @@
$id: "http://devicetree.org/schemas/soc/qcom/qcom,smd-rpm.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Qualcomm Resource Power Manager (RPM) over SMD
title: Qualcomm Resource Power Manager (RPM) over SMD/GLINK
description: |
This driver is used to interface with the Resource Power Manager (RPM) found
@ -12,9 +12,9 @@ description: |
to vote for state of the system resources, such as clocks, regulators and bus
frequencies.
The SMD information for the RPM edge should be filled out. See qcom,smd.yaml
for the required edge properties. All SMD related properties will reside
within the RPM node itself.
The SMD or GLINK information for the RPM edge should be filled out. See
qcom,smd.yaml for the required edge properties. All SMD/GLINK related
properties will reside within the RPM node itself.
The RPM exposes resources to its subnodes. The rpm_requests node must be
present and this subnode may contain children that designate regulator
@ -45,6 +45,7 @@ properties:
- qcom,rpm-sdm660
- qcom,rpm-sm6115
- qcom,rpm-sm6125
- qcom,rpm-sm6375
- qcom,rpm-qcm2290
- qcom,rpm-qcs404
@ -55,12 +56,23 @@ properties:
power-controller:
$ref: /schemas/power/qcom,rpmpd.yaml#
qcom,glink-channels:
$ref: /schemas/types.yaml#/definitions/string-array
description: Channel name used for the RPM communication
items:
- const: rpm_requests
qcom,smd-channels:
$ref: /schemas/types.yaml#/definitions/string-array
description: Channel name used for the RPM communication
items:
- const: rpm_requests
patternProperties:
"^regulators(-[01])?$":
$ref: /schemas/regulator/qcom,smd-rpm-regulator.yaml#
unevaluatedProperties: false
if:
properties:
compatible:
@ -69,10 +81,18 @@ if:
- qcom,rpm-apq8084
- qcom,rpm-msm8916
- qcom,rpm-msm8974
- qcom,rpm-msm8976
- qcom,rpm-msm8953
then:
properties:
qcom,glink-channels: false
required:
- qcom,smd-channels
else:
properties:
qcom,smd-channels: false
required:
- qcom,glink-channels
required:
- compatible

View file

@ -60,7 +60,7 @@ properties:
Two identifiers of the inbound and outbound smem items used for this edge.
patternProperties:
"^master-kernel|slave-kernel|ipa-ap-to-modem|ipa-modem-to-ap$":
"^master-kernel|slave-kernel|ipa-ap-to-modem|ipa-modem-to-ap|wlan-ap-to-wpss|wlan-wpss-to-ap$":
type: object
description:
Each SMP2P pair contain a set of inbound and outbound entries, these are

View file

@ -24,8 +24,11 @@ properties:
- qcom,msm8998-silver-saw2-v4.1-l2
- qcom,msm8909-saw2-v3.0-cpu
- qcom,msm8916-saw2-v3.0-cpu
- qcom,msm8939-saw2-v3.0-cpu
- qcom,msm8226-saw2-v2.1-cpu
- qcom,msm8974-saw2-v2.1-cpu
- qcom,msm8976-gold-saw2-v2.3-l2
- qcom,msm8976-silver-saw2-v2.3-l2
- qcom,apq8084-saw2-v2.1-cpu
- qcom,apq8064-saw2-v1.1-cpu
- const: qcom,saw2

View file

@ -1695,7 +1695,7 @@ M: Miquel Raynal <miquel.raynal@bootlin.com>
M: Naga Sureshkumar Relli <nagasure@xilinx.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/memory-controllers/arm,pl353-smc.yaml
F: Documentation/devicetree/bindings/memory-controllers/arm,pl35x-smc.yaml
F: drivers/memory/pl353-smc.c
ARM PRIMECELL CLCD PL110 DRIVER
@ -12020,6 +12020,13 @@ F: drivers/*/*loongarch*
F: Documentation/loongarch/
F: Documentation/translations/zh_CN/loongarch/
LOONGSON-2 SOC SERIES GUTS DRIVER
M: Yinbo Zhu <zhuyinbo@loongson.cn>
L: loongarch@lists.linux.dev
S: Maintained
F: Documentation/devicetree/bindings/hwinfo/loongson,ls2k-chipid.yaml
F: drivers/soc/loongson/loongson2_guts.c
LSILOGIC MPT FUSION DRIVERS (FC/SAS/SPI)
M: Sathya Prakash <sathya.prakash@broadcom.com>
M: Sreekanth Reddy <sreekanth.reddy@broadcom.com>

View file

@ -43,18 +43,21 @@
static void __iomem *mmp_timer_base = TIMERS_VIRT_BASE;
/*
* FIXME: the timer needs some delay to stablize the counter capture
* Read the timer through the CVWR register. Delay is required after requesting
* a read. The CR register cannot be directly read due to metastability issues
* documented in the PXA168 software manual.
*/
static inline uint32_t timer_read(void)
{
int delay = 100;
uint32_t val;
int delay = 3;
__raw_writel(1, mmp_timer_base + TMR_CVWR(1));
while (delay--)
cpu_relax();
val = __raw_readl(mmp_timer_base + TMR_CVWR(1));
return __raw_readl(mmp_timer_base + TMR_CVWR(1));
return val;
}
static u64 notrace mmp_read_sched_clock(void)

View file

@ -494,6 +494,31 @@ void dev_pm_genpd_set_next_wakeup(struct device *dev, ktime_t next)
}
EXPORT_SYMBOL_GPL(dev_pm_genpd_set_next_wakeup);
/**
* dev_pm_genpd_get_next_hrtimer - Return the next_hrtimer for the genpd
* @dev: A device that is attached to the genpd.
*
* This routine should typically be called for a device, at the point of when a
* GENPD_NOTIFY_PRE_OFF notification has been sent for it.
*
* Returns the aggregated value of the genpd's next hrtimer or KTIME_MAX if no
* valid value have been set.
*/
ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev)
{
struct generic_pm_domain *genpd;
genpd = dev_to_genpd_safe(dev);
if (!genpd)
return KTIME_MAX;
if (genpd->gd)
return genpd->gd->next_hrtimer;
return KTIME_MAX;
}
EXPORT_SYMBOL_GPL(dev_pm_genpd_get_next_hrtimer);
static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
{
unsigned int state_idx = genpd->state_idx;
@ -1994,6 +2019,7 @@ static int genpd_alloc_data(struct generic_pm_domain *genpd)
gd->max_off_time_ns = -1;
gd->max_off_time_changed = true;
gd->next_wakeup = KTIME_MAX;
gd->next_hrtimer = KTIME_MAX;
}
/* Use only one "off" state if there were no states declared */

View file

@ -375,6 +375,9 @@ static bool cpu_power_down_ok(struct dev_pm_domain *pd)
if (idle_duration_ns <= 0)
return false;
/* Store the next domain_wakeup to allow consumers to use it. */
genpd->gd->next_hrtimer = domain_wakeup;
/*
* Find the deepest idle state that has its residency value satisfied
* and by also taking into account the power off latency for the state.

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016-2020 NVIDIA Corporation
* Copyright (C) 2016-2022 NVIDIA Corporation
*/
#include <linux/clk-provider.h>
@ -310,6 +310,23 @@ static const struct clk_ops tegra_bpmp_clk_mux_rate_ops = {
.set_rate = tegra_bpmp_clk_set_rate,
};
static const struct clk_ops tegra_bpmp_clk_mux_read_only_ops = {
.get_parent = tegra_bpmp_clk_get_parent,
.recalc_rate = tegra_bpmp_clk_recalc_rate,
};
static const struct clk_ops tegra_bpmp_clk_read_only_ops = {
.recalc_rate = tegra_bpmp_clk_recalc_rate,
};
static const struct clk_ops tegra_bpmp_clk_gate_mux_read_only_ops = {
.prepare = tegra_bpmp_clk_prepare,
.unprepare = tegra_bpmp_clk_unprepare,
.is_prepared = tegra_bpmp_clk_is_prepared,
.recalc_rate = tegra_bpmp_clk_recalc_rate,
.get_parent = tegra_bpmp_clk_get_parent,
};
static int tegra_bpmp_clk_get_max_id(struct tegra_bpmp *bpmp)
{
struct cmd_clk_get_max_clk_id_response response;
@ -510,8 +527,22 @@ tegra_bpmp_clk_register(struct tegra_bpmp *bpmp,
memset(&init, 0, sizeof(init));
init.name = info->name;
clk->hw.init = &init;
if (info->flags & TEGRA_BPMP_CLK_HAS_MUX) {
if (info->flags & BPMP_CLK_STATE_CHANGE_DENIED) {
if ((info->flags & BPMP_CLK_RATE_PARENT_CHANGE_DENIED) == 0) {
dev_WARN(bpmp->dev,
"Firmware bug! Inconsistent permission bits for clock %s. State and parent/rate changes disabled.",
init.name);
}
if (info->flags & TEGRA_BPMP_CLK_HAS_MUX)
init.ops = &tegra_bpmp_clk_mux_read_only_ops;
else
init.ops = &tegra_bpmp_clk_read_only_ops;
} else if (info->flags & BPMP_CLK_RATE_PARENT_CHANGE_DENIED) {
if (info->flags & TEGRA_BPMP_CLK_HAS_MUX)
init.ops = &tegra_bpmp_clk_gate_mux_read_only_ops;
else
init.ops = &tegra_bpmp_clk_gate_ops;
} else if (info->flags & TEGRA_BPMP_CLK_HAS_MUX) {
if (info->flags & TEGRA_BPMP_CLK_HAS_SET_RATE)
init.ops = &tegra_bpmp_clk_mux_rate_ops;
else

View file

@ -110,6 +110,24 @@ static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_siz
return 0;
}
int bcm47xx_nvram_init_from_iomem(void __iomem *nvram_start, size_t res_size)
{
if (nvram_len) {
pr_warn("nvram already initialized\n");
return -EEXIST;
}
if (!bcm47xx_nvram_is_valid(nvram_start)) {
pr_err("No valid NVRAM found\n");
return -ENOENT;
}
bcm47xx_nvram_copy(nvram_start, res_size);
return 0;
}
EXPORT_SYMBOL_GPL(bcm47xx_nvram_init_from_iomem);
/*
* On bcm47xx we need access to the NVRAM very early, so we can't use mtd
* subsystem to access flash. We can't even use platform device / driver to

View file

@ -108,6 +108,7 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
/* CONN SS */
{ "usb", IMX_SC_R_USB_0, 2, true, 0 },
{ "usb0phy", IMX_SC_R_USB_0_PHY, 1, false, 0 },
{ "usb1phy", IMX_SC_R_USB_1_PHY, 1, false, 0},
{ "usb2", IMX_SC_R_USB_2, 1, false, 0 },
{ "usb2phy", IMX_SC_R_USB_2_PHY, 1, false, 0 },
{ "sdhc", IMX_SC_R_SDHC_0, 3, true, 0 },

View file

@ -268,12 +268,9 @@ static int rpi_firmware_probe(struct platform_device *pdev)
fw->cl.tx_block = true;
fw->chan = mbox_request_channel(&fw->cl, 0);
if (IS_ERR(fw->chan)) {
int ret = PTR_ERR(fw->chan);
if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to get mbox channel: %d\n", ret);
return ret;
}
if (IS_ERR(fw->chan))
return dev_err_probe(dev, PTR_ERR(fw->chan),
"Failed to get mbox channel\n");
init_completion(&fw->c);
kref_init(&fw->consumers);

View file

@ -14,6 +14,7 @@ config TEGRA_IVC
config TEGRA_BPMP
bool "Tegra BPMP driver"
depends on ARCH_TEGRA && TEGRA_HSP_MBOX && TEGRA_IVC
depends on !CPU_BIG_ENDIAN
help
BPMP (Boot and Power Management Processor) is designed to off-loading
the PM functions which include clock/DVFS/thermal/power from the CPU.

View file

@ -48,13 +48,9 @@ static int seqbuf_read(struct seqbuf *seqbuf, void *buf, size_t nbyte)
return seqbuf_status(seqbuf);
}
static int seqbuf_read_u32(struct seqbuf *seqbuf, uint32_t *v)
static int seqbuf_read_u32(struct seqbuf *seqbuf, u32 *v)
{
int err;
err = seqbuf_read(seqbuf, v, 4);
*v = le32_to_cpu(*v);
return err;
return seqbuf_read(seqbuf, v, 4);
}
static int seqbuf_read_str(struct seqbuf *seqbuf, const char **str)
@ -109,10 +105,10 @@ static const char *get_filename(struct tegra_bpmp *bpmp,
}
static int mrq_debug_open(struct tegra_bpmp *bpmp, const char *name,
uint32_t *fd, uint32_t *len, bool write)
u32 *fd, u32 *len, bool write)
{
struct mrq_debug_request req = {
.cmd = cpu_to_le32(write ? CMD_DEBUG_OPEN_WO : CMD_DEBUG_OPEN_RO),
.cmd = write ? CMD_DEBUG_OPEN_WO : CMD_DEBUG_OPEN_RO,
};
struct mrq_debug_response resp;
struct tegra_bpmp_message msg = {
@ -147,10 +143,10 @@ static int mrq_debug_open(struct tegra_bpmp *bpmp, const char *name,
return 0;
}
static int mrq_debug_close(struct tegra_bpmp *bpmp, uint32_t fd)
static int mrq_debug_close(struct tegra_bpmp *bpmp, u32 fd)
{
struct mrq_debug_request req = {
.cmd = cpu_to_le32(CMD_DEBUG_CLOSE),
.cmd = CMD_DEBUG_CLOSE,
.frd = {
.fd = fd,
},
@ -179,10 +175,10 @@ static int mrq_debug_close(struct tegra_bpmp *bpmp, uint32_t fd)
}
static int mrq_debug_read(struct tegra_bpmp *bpmp, const char *name,
char *data, size_t sz_data, uint32_t *nbytes)
char *data, size_t sz_data, u32 *nbytes)
{
struct mrq_debug_request req = {
.cmd = cpu_to_le32(CMD_DEBUG_READ),
.cmd = CMD_DEBUG_READ,
};
struct mrq_debug_response resp;
struct tegra_bpmp_message msg = {
@ -196,7 +192,7 @@ static int mrq_debug_read(struct tegra_bpmp *bpmp, const char *name,
.size = sizeof(resp),
},
};
uint32_t fd = 0, len = 0;
u32 fd = 0, len = 0;
int remaining, err;
mutex_lock(&bpmp_debug_lock);
@ -245,7 +241,7 @@ static int mrq_debug_write(struct tegra_bpmp *bpmp, const char *name,
uint8_t *data, size_t sz_data)
{
struct mrq_debug_request req = {
.cmd = cpu_to_le32(CMD_DEBUG_WRITE)
.cmd = CMD_DEBUG_WRITE
};
struct mrq_debug_response resp;
struct tegra_bpmp_message msg = {
@ -259,7 +255,7 @@ static int mrq_debug_write(struct tegra_bpmp *bpmp, const char *name,
.size = sizeof(resp),
},
};
uint32_t fd = 0, len = 0;
u32 fd = 0, len = 0;
size_t remaining;
int err;
@ -308,7 +304,7 @@ static int bpmp_debug_show(struct seq_file *m, void *p)
char fnamebuf[256];
const char *filename;
struct mrq_debug_request req = {
.cmd = cpu_to_le32(CMD_DEBUG_READ),
.cmd = CMD_DEBUG_READ,
};
struct mrq_debug_response resp;
struct tegra_bpmp_message msg = {
@ -322,7 +318,7 @@ static int bpmp_debug_show(struct seq_file *m, void *p)
.size = sizeof(resp),
},
};
uint32_t fd = 0, len = 0;
u32 fd = 0, len = 0;
int remaining, err;
filename = get_filename(bpmp, file, fnamebuf, sizeof(fnamebuf));
@ -406,8 +402,8 @@ static int bpmp_populate_debugfs_inband(struct tegra_bpmp *bpmp,
{
const size_t pathlen = SZ_256;
const size_t bufsize = SZ_16K;
uint32_t dsize, attrs = 0;
struct dentry *dentry;
u32 dsize, attrs = 0;
struct seqbuf seqbuf;
char *buf, *pathbuf;
const char *name;
@ -487,12 +483,12 @@ static int mrq_debugfs_read(struct tegra_bpmp *bpmp,
size_t *nbytes)
{
struct mrq_debugfs_request req = {
.cmd = cpu_to_le32(CMD_DEBUGFS_READ),
.cmd = CMD_DEBUGFS_READ,
.fop = {
.fnameaddr = cpu_to_le32((uint32_t)name),
.fnamelen = cpu_to_le32((uint32_t)sz_name),
.dataaddr = cpu_to_le32((uint32_t)data),
.datalen = cpu_to_le32((uint32_t)sz_data),
.fnameaddr = (u32)name,
.fnamelen = (u32)sz_name,
.dataaddr = (u32)data,
.datalen = (u32)sz_data,
},
};
struct mrq_debugfs_response resp;
@ -525,12 +521,12 @@ static int mrq_debugfs_write(struct tegra_bpmp *bpmp,
dma_addr_t data, size_t sz_data)
{
const struct mrq_debugfs_request req = {
.cmd = cpu_to_le32(CMD_DEBUGFS_WRITE),
.cmd = CMD_DEBUGFS_WRITE,
.fop = {
.fnameaddr = cpu_to_le32((uint32_t)name),
.fnamelen = cpu_to_le32((uint32_t)sz_name),
.dataaddr = cpu_to_le32((uint32_t)data),
.datalen = cpu_to_le32((uint32_t)sz_data),
.fnameaddr = (u32)name,
.fnamelen = (u32)sz_name,
.dataaddr = (u32)data,
.datalen = (u32)sz_data,
},
};
struct tegra_bpmp_message msg = {
@ -548,10 +544,10 @@ static int mrq_debugfs_dumpdir(struct tegra_bpmp *bpmp, dma_addr_t addr,
size_t size, size_t *nbytes)
{
const struct mrq_debugfs_request req = {
.cmd = cpu_to_le32(CMD_DEBUGFS_DUMPDIR),
.cmd = CMD_DEBUGFS_DUMPDIR,
.dumpdir = {
.dataaddr = cpu_to_le32((uint32_t)addr),
.datalen = cpu_to_le32((uint32_t)size),
.dataaddr = (u32)addr,
.datalen = (u32)size,
},
};
struct mrq_debugfs_response resp;
@ -688,10 +684,10 @@ static const struct file_operations debugfs_fops = {
};
static int bpmp_populate_dir(struct tegra_bpmp *bpmp, struct seqbuf *seqbuf,
struct dentry *parent, uint32_t depth)
struct dentry *parent, u32 depth)
{
int err;
uint32_t d, t;
u32 d, t;
const char *name;
struct dentry *dentry;

View file

@ -18,8 +18,8 @@ struct tegra186_bpmp {
struct {
struct gen_pool *pool;
void __iomem *virt;
dma_addr_t phys;
void *virt;
} tx, rx;
struct {
@ -40,31 +40,27 @@ mbox_client_to_bpmp(struct mbox_client *client)
static bool tegra186_bpmp_is_message_ready(struct tegra_bpmp_channel *channel)
{
void *frame;
int err;
frame = tegra_ivc_read_get_next_frame(channel->ivc);
if (IS_ERR(frame)) {
channel->ib = NULL;
err = tegra_ivc_read_get_next_frame(channel->ivc, &channel->ib);
if (err) {
iosys_map_clear(&channel->ib);
return false;
}
channel->ib = frame;
return true;
}
static bool tegra186_bpmp_is_channel_free(struct tegra_bpmp_channel *channel)
{
void *frame;
int err;
frame = tegra_ivc_write_get_next_frame(channel->ivc);
if (IS_ERR(frame)) {
channel->ob = NULL;
err = tegra_ivc_write_get_next_frame(channel->ivc, &channel->ob);
if (err) {
iosys_map_clear(&channel->ob);
return false;
}
channel->ob = frame;
return true;
}
@ -109,6 +105,7 @@ static int tegra186_bpmp_channel_init(struct tegra_bpmp_channel *channel,
{
struct tegra186_bpmp *priv = bpmp->priv;
size_t message_size, queue_size;
struct iosys_map rx, tx;
unsigned int offset;
int err;
@ -121,10 +118,11 @@ static int tegra186_bpmp_channel_init(struct tegra_bpmp_channel *channel,
queue_size = tegra_ivc_total_queue_size(message_size);
offset = queue_size * index;
err = tegra_ivc_init(channel->ivc, NULL,
priv->rx.virt + offset, priv->rx.phys + offset,
priv->tx.virt + offset, priv->tx.phys + offset,
1, message_size, tegra186_bpmp_ivc_notify,
iosys_map_set_vaddr_iomem(&rx, priv->rx.virt + offset);
iosys_map_set_vaddr_iomem(&tx, priv->tx.virt + offset);
err = tegra_ivc_init(channel->ivc, NULL, &rx, priv->rx.phys + offset, &tx,
priv->tx.phys + offset, 1, message_size, tegra186_bpmp_ivc_notify,
bpmp);
if (err < 0) {
dev_err(bpmp->dev, "failed to setup IVC for channel %u: %d\n",
@ -179,7 +177,7 @@ static int tegra186_bpmp_init(struct tegra_bpmp *bpmp)
return -EPROBE_DEFER;
}
priv->tx.virt = gen_pool_dma_alloc(priv->tx.pool, 4096, &priv->tx.phys);
priv->tx.virt = (void __iomem *)gen_pool_dma_alloc(priv->tx.pool, 4096, &priv->tx.phys);
if (!priv->tx.virt) {
dev_err(bpmp->dev, "failed to allocate from TX pool\n");
return -ENOMEM;
@ -192,7 +190,7 @@ static int tegra186_bpmp_init(struct tegra_bpmp *bpmp)
goto free_tx;
}
priv->rx.virt = gen_pool_dma_alloc(priv->rx.pool, 4096, &priv->rx.phys);
priv->rx.virt = (void __iomem *)gen_pool_dma_alloc(priv->rx.pool, 4096, &priv->rx.phys);
if (!priv->rx.virt) {
dev_err(bpmp->dev, "failed to allocate from RX pool\n");
err = -ENOMEM;

View file

@ -137,8 +137,8 @@ static int tegra210_bpmp_channel_init(struct tegra_bpmp_channel *channel,
unsigned int index)
{
struct tegra210_bpmp *priv = bpmp->priv;
void __iomem *p;
u32 address;
void *p;
/* Retrieve channel base address from BPMP */
writel(index << TRIGGER_ID_SHIFT | TRIGGER_CMD_GET,
@ -149,8 +149,9 @@ static int tegra210_bpmp_channel_init(struct tegra_bpmp_channel *channel,
if (!p)
return -ENOMEM;
channel->ib = p;
channel->ob = p;
iosys_map_set_vaddr_iomem(&channel->ib, p);
iosys_map_set_vaddr_iomem(&channel->ob, p);
channel->index = index;
init_completion(&channel->completion);
channel->bpmp = bpmp;
@ -199,10 +200,8 @@ static int tegra210_bpmp_init(struct tegra_bpmp *bpmp)
}
err = platform_get_irq_byname(pdev, "tx");
if (err < 0) {
dev_err(&pdev->dev, "failed to get TX IRQ: %d\n", err);
if (err < 0)
return err;
}
priv->tx_irq_data = irq_get_irq_data(err);
if (!priv->tx_irq_data) {
@ -211,10 +210,8 @@ static int tegra210_bpmp_init(struct tegra_bpmp *bpmp)
}
err = platform_get_irq_byname(pdev, "rx");
if (err < 0) {
dev_err(&pdev->dev, "failed to get rx IRQ: %d\n", err);
if (err < 0)
return err;
}
err = devm_request_irq(&pdev->dev, err, rx_irq,
IRQF_NO_SUSPEND, dev_name(&pdev->dev), bpmp);

View file

@ -201,13 +201,13 @@ static ssize_t __tegra_bpmp_channel_read(struct tegra_bpmp_channel *channel,
int err;
if (data && size > 0)
memcpy_fromio(data, channel->ib->data, size);
tegra_bpmp_mb_read(data, &channel->ib, size);
err = tegra_bpmp_ack_response(channel);
if (err < 0)
return err;
*ret = channel->ib->code;
*ret = tegra_bpmp_mb_read_field(&channel->ib, code);
return 0;
}
@ -241,11 +241,11 @@ static ssize_t __tegra_bpmp_channel_write(struct tegra_bpmp_channel *channel,
unsigned int mrq, unsigned long flags,
const void *data, size_t size)
{
channel->ob->code = mrq;
channel->ob->flags = flags;
tegra_bpmp_mb_write_field(&channel->ob, code, mrq);
tegra_bpmp_mb_write_field(&channel->ob, flags, flags);
if (data && size > 0)
memcpy_toio(channel->ob->data, data, size);
tegra_bpmp_mb_write(&channel->ob, data, size);
return tegra_bpmp_post_request(channel);
}
@ -400,7 +400,7 @@ static struct tegra_bpmp_mrq *tegra_bpmp_find_mrq(struct tegra_bpmp *bpmp,
void tegra_bpmp_mrq_return(struct tegra_bpmp_channel *channel, int code,
const void *data, size_t size)
{
unsigned long flags = channel->ib->flags;
unsigned long flags = tegra_bpmp_mb_read_field(&channel->ib, flags);
struct tegra_bpmp *bpmp = channel->bpmp;
int err;
@ -417,10 +417,10 @@ void tegra_bpmp_mrq_return(struct tegra_bpmp_channel *channel, int code,
if (WARN_ON(!tegra_bpmp_is_response_channel_free(channel)))
return;
channel->ob->code = code;
tegra_bpmp_mb_write_field(&channel->ob, code, code);
if (data && size > 0)
memcpy_toio(channel->ob->data, data, size);
tegra_bpmp_mb_write(&channel->ob, data, size);
err = tegra_bpmp_post_response(channel);
if (WARN_ON(err < 0))
@ -502,7 +502,7 @@ EXPORT_SYMBOL_GPL(tegra_bpmp_free_mrq);
bool tegra_bpmp_mrq_is_supported(struct tegra_bpmp *bpmp, unsigned int mrq)
{
struct mrq_query_abi_request req = { .mrq = cpu_to_le32(mrq) };
struct mrq_query_abi_request req = { .mrq = mrq };
struct mrq_query_abi_response resp;
struct tegra_bpmp_message msg = {
.mrq = MRQ_QUERY_ABI,
@ -529,13 +529,13 @@ static void tegra_bpmp_mrq_handle_ping(unsigned int mrq,
struct tegra_bpmp_channel *channel,
void *data)
{
struct mrq_ping_request *request;
struct mrq_ping_request request;
struct mrq_ping_response response;
request = (struct mrq_ping_request *)channel->ib->data;
tegra_bpmp_mb_read(&request, &channel->ib, sizeof(request));
memset(&response, 0, sizeof(response));
response.reply = request->challenge << 1;
response.reply = request.challenge << 1;
tegra_bpmp_mrq_return(channel, 0, &response, sizeof(response));
}
@ -648,7 +648,7 @@ static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag,
static void tegra_bpmp_channel_signal(struct tegra_bpmp_channel *channel)
{
unsigned long flags = channel->ob->flags;
unsigned long flags = tegra_bpmp_mb_read_field(&channel->ob, flags);
if ((flags & MSG_RING) == 0)
return;
@ -666,8 +666,11 @@ void tegra_bpmp_handle_rx(struct tegra_bpmp *bpmp)
count = bpmp->soc->channels.thread.count;
busy = bpmp->threaded.busy;
if (tegra_bpmp_is_request_ready(channel))
tegra_bpmp_handle_mrq(bpmp, channel->ib->code, channel);
if (tegra_bpmp_is_request_ready(channel)) {
unsigned int mrq = tegra_bpmp_mb_read_field(&channel->ib, code);
tegra_bpmp_handle_mrq(bpmp, mrq, channel);
}
spin_lock(&bpmp->lock);

View file

@ -68,6 +68,12 @@ struct tegra_ivc_header {
} rx;
};
#define tegra_ivc_header_read_field(hdr, field) \
iosys_map_rd_field(hdr, 0, struct tegra_ivc_header, field)
#define tegra_ivc_header_write_field(hdr, field, value) \
iosys_map_wr_field(hdr, 0, struct tegra_ivc_header, field, value)
static inline void tegra_ivc_invalidate(struct tegra_ivc *ivc, dma_addr_t phys)
{
if (!ivc->peer)
@ -86,16 +92,15 @@ static inline void tegra_ivc_flush(struct tegra_ivc *ivc, dma_addr_t phys)
DMA_TO_DEVICE);
}
static inline bool tegra_ivc_empty(struct tegra_ivc *ivc,
struct tegra_ivc_header *header)
static inline bool tegra_ivc_empty(struct tegra_ivc *ivc, struct iosys_map *map)
{
/*
* This function performs multiple checks on the same values with
* security implications, so create snapshots with READ_ONCE() to
* ensure that these checks use the same values.
*/
u32 tx = READ_ONCE(header->tx.count);
u32 rx = READ_ONCE(header->rx.count);
u32 tx = tegra_ivc_header_read_field(map, tx.count);
u32 rx = tegra_ivc_header_read_field(map, rx.count);
/*
* Perform an over-full check to prevent denial of service attacks
@ -113,11 +118,10 @@ static inline bool tegra_ivc_empty(struct tegra_ivc *ivc,
return tx == rx;
}
static inline bool tegra_ivc_full(struct tegra_ivc *ivc,
struct tegra_ivc_header *header)
static inline bool tegra_ivc_full(struct tegra_ivc *ivc, struct iosys_map *map)
{
u32 tx = READ_ONCE(header->tx.count);
u32 rx = READ_ONCE(header->rx.count);
u32 tx = tegra_ivc_header_read_field(map, tx.count);
u32 rx = tegra_ivc_header_read_field(map, rx.count);
/*
* Invalid cases where the counters indicate that the queue is over
@ -126,11 +130,10 @@ static inline bool tegra_ivc_full(struct tegra_ivc *ivc,
return tx - rx >= ivc->num_frames;
}
static inline u32 tegra_ivc_available(struct tegra_ivc *ivc,
struct tegra_ivc_header *header)
static inline u32 tegra_ivc_available(struct tegra_ivc *ivc, struct iosys_map *map)
{
u32 tx = READ_ONCE(header->tx.count);
u32 rx = READ_ONCE(header->rx.count);
u32 tx = tegra_ivc_header_read_field(map, tx.count);
u32 rx = tegra_ivc_header_read_field(map, rx.count);
/*
* This function isn't expected to be used in scenarios where an
@ -143,8 +146,9 @@ static inline u32 tegra_ivc_available(struct tegra_ivc *ivc,
static inline void tegra_ivc_advance_tx(struct tegra_ivc *ivc)
{
WRITE_ONCE(ivc->tx.channel->tx.count,
READ_ONCE(ivc->tx.channel->tx.count) + 1);
unsigned int count = tegra_ivc_header_read_field(&ivc->tx.map, tx.count);
tegra_ivc_header_write_field(&ivc->tx.map, tx.count, count + 1);
if (ivc->tx.position == ivc->num_frames - 1)
ivc->tx.position = 0;
@ -154,8 +158,9 @@ static inline void tegra_ivc_advance_tx(struct tegra_ivc *ivc)
static inline void tegra_ivc_advance_rx(struct tegra_ivc *ivc)
{
WRITE_ONCE(ivc->rx.channel->rx.count,
READ_ONCE(ivc->rx.channel->rx.count) + 1);
unsigned int count = tegra_ivc_header_read_field(&ivc->rx.map, rx.count);
tegra_ivc_header_write_field(&ivc->rx.map, rx.count, count + 1);
if (ivc->rx.position == ivc->num_frames - 1)
ivc->rx.position = 0;
@ -166,6 +171,7 @@ static inline void tegra_ivc_advance_rx(struct tegra_ivc *ivc)
static inline int tegra_ivc_check_read(struct tegra_ivc *ivc)
{
unsigned int offset = offsetof(struct tegra_ivc_header, tx.count);
unsigned int state;
/*
* tx.channel->state is set locally, so it is not synchronized with
@ -175,7 +181,8 @@ static inline int tegra_ivc_check_read(struct tegra_ivc *ivc)
* asynchronous transition of rx.channel->state to
* TEGRA_IVC_STATE_ACK is not allowed.
*/
if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED)
state = tegra_ivc_header_read_field(&ivc->tx.map, tx.state);
if (state != TEGRA_IVC_STATE_ESTABLISHED)
return -ECONNRESET;
/*
@ -185,12 +192,12 @@ static inline int tegra_ivc_check_read(struct tegra_ivc *ivc)
* Synchronization is only necessary when these pointers indicate
* empty or full.
*/
if (!tegra_ivc_empty(ivc, ivc->rx.channel))
if (!tegra_ivc_empty(ivc, &ivc->rx.map))
return 0;
tegra_ivc_invalidate(ivc, ivc->rx.phys + offset);
if (tegra_ivc_empty(ivc, ivc->rx.channel))
if (tegra_ivc_empty(ivc, &ivc->rx.map))
return -ENOSPC;
return 0;
@ -199,29 +206,34 @@ static inline int tegra_ivc_check_read(struct tegra_ivc *ivc)
static inline int tegra_ivc_check_write(struct tegra_ivc *ivc)
{
unsigned int offset = offsetof(struct tegra_ivc_header, rx.count);
unsigned int state;
if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED)
state = tegra_ivc_header_read_field(&ivc->tx.map, tx.state);
if (state != TEGRA_IVC_STATE_ESTABLISHED)
return -ECONNRESET;
if (!tegra_ivc_full(ivc, ivc->tx.channel))
if (!tegra_ivc_full(ivc, &ivc->tx.map))
return 0;
tegra_ivc_invalidate(ivc, ivc->tx.phys + offset);
if (tegra_ivc_full(ivc, ivc->tx.channel))
if (tegra_ivc_full(ivc, &ivc->tx.map))
return -ENOSPC;
return 0;
}
static void *tegra_ivc_frame_virt(struct tegra_ivc *ivc,
struct tegra_ivc_header *header,
unsigned int frame)
static int tegra_ivc_frame_virt(struct tegra_ivc *ivc, const struct iosys_map *header,
unsigned int frame, struct iosys_map *map)
{
if (WARN_ON(frame >= ivc->num_frames))
return ERR_PTR(-EINVAL);
size_t offset = sizeof(struct tegra_ivc_header) + ivc->frame_size * frame;
return (void *)(header + 1) + ivc->frame_size * frame;
if (WARN_ON(frame >= ivc->num_frames))
return -EINVAL;
*map = IOSYS_MAP_INIT_OFFSET(header, offset);
return 0;
}
static inline dma_addr_t tegra_ivc_frame_phys(struct tegra_ivc *ivc,
@ -264,16 +276,16 @@ static inline void tegra_ivc_flush_frame(struct tegra_ivc *ivc,
}
/* directly peek at the next frame rx'ed */
void *tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc)
int tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc, struct iosys_map *map)
{
int err;
if (WARN_ON(ivc == NULL))
return ERR_PTR(-EINVAL);
return -EINVAL;
err = tegra_ivc_check_read(ivc);
if (err < 0)
return ERR_PTR(err);
return err;
/*
* Order observation of ivc->rx.position potentially indicating new
@ -284,7 +296,7 @@ void *tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc)
tegra_ivc_invalidate_frame(ivc, ivc->rx.phys, ivc->rx.position, 0,
ivc->frame_size);
return tegra_ivc_frame_virt(ivc, ivc->rx.channel, ivc->rx.position);
return tegra_ivc_frame_virt(ivc, &ivc->rx.map, ivc->rx.position, map);
}
EXPORT_SYMBOL(tegra_ivc_read_get_next_frame);
@ -320,7 +332,7 @@ int tegra_ivc_read_advance(struct tegra_ivc *ivc)
*/
tegra_ivc_invalidate(ivc, ivc->rx.phys + tx);
if (tegra_ivc_available(ivc, ivc->rx.channel) == ivc->num_frames - 1)
if (tegra_ivc_available(ivc, &ivc->rx.map) == ivc->num_frames - 1)
ivc->notify(ivc, ivc->notify_data);
return 0;
@ -328,15 +340,15 @@ int tegra_ivc_read_advance(struct tegra_ivc *ivc)
EXPORT_SYMBOL(tegra_ivc_read_advance);
/* directly poke at the next frame to be tx'ed */
void *tegra_ivc_write_get_next_frame(struct tegra_ivc *ivc)
int tegra_ivc_write_get_next_frame(struct tegra_ivc *ivc, struct iosys_map *map)
{
int err;
err = tegra_ivc_check_write(ivc);
if (err < 0)
return ERR_PTR(err);
return err;
return tegra_ivc_frame_virt(ivc, ivc->tx.channel, ivc->tx.position);
return tegra_ivc_frame_virt(ivc, &ivc->tx.map, ivc->tx.position, map);
}
EXPORT_SYMBOL(tegra_ivc_write_get_next_frame);
@ -376,7 +388,7 @@ int tegra_ivc_write_advance(struct tegra_ivc *ivc)
*/
tegra_ivc_invalidate(ivc, ivc->tx.phys + rx);
if (tegra_ivc_available(ivc, ivc->tx.channel) == 1)
if (tegra_ivc_available(ivc, &ivc->tx.map) == 1)
ivc->notify(ivc, ivc->notify_data);
return 0;
@ -387,7 +399,7 @@ void tegra_ivc_reset(struct tegra_ivc *ivc)
{
unsigned int offset = offsetof(struct tegra_ivc_header, tx.count);
ivc->tx.channel->tx.state = TEGRA_IVC_STATE_SYNC;
tegra_ivc_header_write_field(&ivc->tx.map, tx.state, TEGRA_IVC_STATE_SYNC);
tegra_ivc_flush(ivc, ivc->tx.phys + offset);
ivc->notify(ivc, ivc->notify_data);
}
@ -416,13 +428,14 @@ EXPORT_SYMBOL(tegra_ivc_reset);
int tegra_ivc_notified(struct tegra_ivc *ivc)
{
unsigned int offset = offsetof(struct tegra_ivc_header, tx.count);
enum tegra_ivc_state state;
enum tegra_ivc_state rx_state, tx_state;
/* Copy the receiver's state out of shared memory. */
tegra_ivc_invalidate(ivc, ivc->rx.phys + offset);
state = READ_ONCE(ivc->rx.channel->tx.state);
rx_state = tegra_ivc_header_read_field(&ivc->rx.map, tx.state);
tx_state = tegra_ivc_header_read_field(&ivc->tx.map, tx.state);
if (state == TEGRA_IVC_STATE_SYNC) {
if (rx_state == TEGRA_IVC_STATE_SYNC) {
offset = offsetof(struct tegra_ivc_header, tx.count);
/*
@ -436,8 +449,8 @@ int tegra_ivc_notified(struct tegra_ivc *ivc)
* state and won't make progress until we change our state,
* so the counters are not in use at this time.
*/
ivc->tx.channel->tx.count = 0;
ivc->rx.channel->rx.count = 0;
tegra_ivc_header_write_field(&ivc->tx.map, tx.count, 0);
tegra_ivc_header_write_field(&ivc->rx.map, rx.count, 0);
ivc->tx.position = 0;
ivc->rx.position = 0;
@ -452,7 +465,7 @@ int tegra_ivc_notified(struct tegra_ivc *ivc)
* Move to ACK state. We have just cleared our counters, so it
* is now safe for the remote end to start using these values.
*/
ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ACK;
tegra_ivc_header_write_field(&ivc->tx.map, tx.state, TEGRA_IVC_STATE_ACK);
tegra_ivc_flush(ivc, ivc->tx.phys + offset);
/*
@ -460,8 +473,8 @@ int tegra_ivc_notified(struct tegra_ivc *ivc)
*/
ivc->notify(ivc, ivc->notify_data);
} else if (ivc->tx.channel->tx.state == TEGRA_IVC_STATE_SYNC &&
state == TEGRA_IVC_STATE_ACK) {
} else if (tx_state == TEGRA_IVC_STATE_SYNC &&
rx_state == TEGRA_IVC_STATE_ACK) {
offset = offsetof(struct tegra_ivc_header, tx.count);
/*
@ -475,8 +488,8 @@ int tegra_ivc_notified(struct tegra_ivc *ivc)
* state and won't make progress until we change our state,
* so the counters are not in use at this time.
*/
ivc->tx.channel->tx.count = 0;
ivc->rx.channel->rx.count = 0;
tegra_ivc_header_write_field(&ivc->tx.map, tx.count, 0);
tegra_ivc_header_write_field(&ivc->rx.map, rx.count, 0);
ivc->tx.position = 0;
ivc->rx.position = 0;
@ -492,7 +505,7 @@ int tegra_ivc_notified(struct tegra_ivc *ivc)
* already cleared its counters, so it is safe to start
* writing/reading on this channel.
*/
ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ESTABLISHED;
tegra_ivc_header_write_field(&ivc->tx.map, tx.state, TEGRA_IVC_STATE_ESTABLISHED);
tegra_ivc_flush(ivc, ivc->tx.phys + offset);
/*
@ -500,7 +513,7 @@ int tegra_ivc_notified(struct tegra_ivc *ivc)
*/
ivc->notify(ivc, ivc->notify_data);
} else if (ivc->tx.channel->tx.state == TEGRA_IVC_STATE_ACK) {
} else if (tx_state == TEGRA_IVC_STATE_ACK) {
offset = offsetof(struct tegra_ivc_header, tx.count);
/*
@ -516,7 +529,7 @@ int tegra_ivc_notified(struct tegra_ivc *ivc)
* cleared its counters, so it is safe to start writing/reading
* on this channel.
*/
ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ESTABLISHED;
tegra_ivc_header_write_field(&ivc->tx.map, tx.state, TEGRA_IVC_STATE_ESTABLISHED);
tegra_ivc_flush(ivc, ivc->tx.phys + offset);
/*
@ -533,7 +546,7 @@ int tegra_ivc_notified(struct tegra_ivc *ivc)
*/
}
if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED)
if (tx_state != TEGRA_IVC_STATE_ESTABLISHED)
return -EAGAIN;
return 0;
@ -609,8 +622,29 @@ static int tegra_ivc_check_params(unsigned long rx, unsigned long tx,
return 0;
}
int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx,
dma_addr_t rx_phys, void *tx, dma_addr_t tx_phys,
static inline void iosys_map_copy(struct iosys_map *dst, const struct iosys_map *src)
{
*dst = *src;
}
static inline unsigned long iosys_map_get_address(const struct iosys_map *map)
{
if (map->is_iomem)
return (unsigned long)map->vaddr_iomem;
return (unsigned long)map->vaddr;
}
static inline void *iosys_map_get_vaddr(const struct iosys_map *map)
{
if (WARN_ON(map->is_iomem))
return NULL;
return map->vaddr;
}
int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, const struct iosys_map *rx,
dma_addr_t rx_phys, const struct iosys_map *tx, dma_addr_t tx_phys,
unsigned int num_frames, size_t frame_size,
void (*notify)(struct tegra_ivc *ivc, void *data),
void *data)
@ -628,7 +662,7 @@ int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx,
if (frame_size > INT_MAX)
return -E2BIG;
err = tegra_ivc_check_params((unsigned long)rx, (unsigned long)tx,
err = tegra_ivc_check_params(iosys_map_get_address(rx), iosys_map_get_address(tx),
num_frames, frame_size);
if (err < 0)
return err;
@ -636,12 +670,12 @@ int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx,
queue_size = tegra_ivc_total_queue_size(num_frames * frame_size);
if (peer) {
ivc->rx.phys = dma_map_single(peer, rx, queue_size,
ivc->rx.phys = dma_map_single(peer, iosys_map_get_vaddr(rx), queue_size,
DMA_BIDIRECTIONAL);
if (dma_mapping_error(peer, ivc->rx.phys))
return -ENOMEM;
ivc->tx.phys = dma_map_single(peer, tx, queue_size,
ivc->tx.phys = dma_map_single(peer, iosys_map_get_vaddr(tx), queue_size,
DMA_BIDIRECTIONAL);
if (dma_mapping_error(peer, ivc->tx.phys)) {
dma_unmap_single(peer, ivc->rx.phys, queue_size,
@ -653,8 +687,8 @@ int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx,
ivc->tx.phys = tx_phys;
}
ivc->rx.channel = rx;
ivc->tx.channel = tx;
iosys_map_copy(&ivc->rx.map, rx);
iosys_map_copy(&ivc->tx.map, tx);
ivc->peer = peer;
ivc->notify = notify;
ivc->notify_data = data;

View file

@ -429,15 +429,14 @@ static inline int ti_sci_do_xfer(struct ti_sci_info *info,
* during noirq phase, so we must manually poll the completion.
*/
ret = read_poll_timeout_atomic(try_wait_for_completion, done_state,
true, 1,
done_state, 1,
info->desc->max_rx_timeout_ms * 1000,
false, &xfer->done);
}
if (ret == -ETIMEDOUT || !done_state) {
if (ret == -ETIMEDOUT)
dev_err(dev, "Mbox timedout in resp(caller: %pS)\n",
(void *)_RET_IP_);
}
/*
* NOTE: we might prefer not to need the mailbox ticker to manage the
@ -3096,7 +3095,7 @@ u16 ti_sci_get_free_resource(struct ti_sci_resource *res)
free_bit = find_first_zero_bit(desc->res_map, res_count);
if (free_bit != res_count) {
set_bit(free_bit, desc->res_map);
__set_bit(free_bit, desc->res_map);
raw_spin_unlock_irqrestore(&res->lock, flags);
if (desc->num && free_bit < desc->num)
@ -3127,10 +3126,10 @@ void ti_sci_release_resource(struct ti_sci_resource *res, u16 id)
if (desc->num && desc->start <= id &&
(desc->start + desc->num) > id)
clear_bit(id - desc->start, desc->res_map);
__clear_bit(id - desc->start, desc->res_map);
else if (desc->num_sec && desc->start_sec <= id &&
(desc->start_sec + desc->num_sec) > id)
clear_bit(id - desc->start_sec, desc->res_map);
__clear_bit(id - desc->start_sec, desc->res_map);
}
raw_spin_unlock_irqrestore(&res->lock, flags);
}
@ -3201,9 +3200,8 @@ devm_ti_sci_get_resource_sets(const struct ti_sci_handle *handle,
valid_set = true;
res_count = res->desc[i].num + res->desc[i].num_sec;
res->desc[i].res_map =
devm_kzalloc(dev, BITS_TO_LONGS(res_count) *
sizeof(*res->desc[i].res_map), GFP_KERNEL);
res->desc[i].res_map = devm_bitmap_zalloc(dev, res_count,
GFP_KERNEL);
if (!res->desc[i].res_map)
return ERR_PTR(-ENOMEM);
}
@ -3400,13 +3398,11 @@ static int ti_sci_probe(struct platform_device *pdev)
if (!minfo->xfer_block)
return -ENOMEM;
minfo->xfer_alloc_table = devm_kcalloc(dev,
BITS_TO_LONGS(desc->max_msgs),
sizeof(unsigned long),
GFP_KERNEL);
minfo->xfer_alloc_table = devm_bitmap_zalloc(dev,
desc->max_msgs,
GFP_KERNEL);
if (!minfo->xfer_alloc_table)
return -ENOMEM;
bitmap_zero(minfo->xfer_alloc_table, desc->max_msgs);
/* Pre-initialize the buffer pointer to pre-allocated buffers */
for (i = 0, xfer = minfo->xfer_block; i < desc->max_msgs; i++, xfer++) {

View file

@ -134,6 +134,7 @@
#define GPMC_CONFIG_DEV_SIZE 0x00000002
#define GPMC_CONFIG_DEV_TYPE 0x00000003
#define GPMC_CONFIG_WAITPINPOLARITY(pin) (BIT(pin) << 8)
#define GPMC_CONFIG1_WRAPBURST_SUPP (1 << 31)
#define GPMC_CONFIG1_READMULTIPLE_SUPP (1 << 30)
#define GPMC_CONFIG1_READTYPE_ASYNC (0 << 29)
@ -229,6 +230,12 @@ struct omap3_gpmc_regs {
struct gpmc_cs_config cs_context[GPMC_CS_NUM];
};
struct gpmc_waitpin {
u32 pin;
u32 polarity;
struct gpio_desc *desc;
};
struct gpmc_device {
struct device *dev;
int irq;
@ -236,6 +243,7 @@ struct gpmc_device {
struct gpio_chip gpio_chip;
struct notifier_block nb;
struct omap3_gpmc_regs context;
struct gpmc_waitpin *waitpins;
int nirqs;
unsigned int is_suspended:1;
struct resource *data;
@ -1035,6 +1043,62 @@ void gpmc_cs_free(int cs)
}
EXPORT_SYMBOL(gpmc_cs_free);
static bool gpmc_is_valid_waitpin(u32 waitpin)
{
return waitpin < gpmc_nr_waitpins;
}
static int gpmc_alloc_waitpin(struct gpmc_device *gpmc,
struct gpmc_settings *p)
{
int ret;
struct gpmc_waitpin *waitpin;
struct gpio_desc *waitpin_desc;
if (!gpmc_is_valid_waitpin(p->wait_pin))
return -EINVAL;
waitpin = &gpmc->waitpins[p->wait_pin];
if (!waitpin->desc) {
/* Reserve the GPIO for wait pin usage.
* GPIO polarity doesn't matter here. Wait pin polarity
* is set in GPMC_CONFIG register.
*/
waitpin_desc = gpiochip_request_own_desc(&gpmc->gpio_chip,
p->wait_pin, "WAITPIN",
GPIO_ACTIVE_HIGH,
GPIOD_IN);
ret = PTR_ERR(waitpin_desc);
if (IS_ERR(waitpin_desc) && ret != -EBUSY)
return ret;
/* New wait pin */
waitpin->desc = waitpin_desc;
waitpin->pin = p->wait_pin;
waitpin->polarity = p->wait_pin_polarity;
} else {
/* Shared wait pin */
if (p->wait_pin_polarity != waitpin->polarity ||
p->wait_pin != waitpin->pin) {
dev_err(gpmc->dev,
"shared-wait-pin: invalid configuration\n");
return -EINVAL;
}
dev_info(gpmc->dev, "shared wait-pin: %d\n", waitpin->pin);
}
return 0;
}
static void gpmc_free_waitpin(struct gpmc_device *gpmc,
int wait_pin)
{
if (gpmc_is_valid_waitpin(wait_pin))
gpiochip_free_own_desc(gpmc->waitpins[wait_pin].desc);
}
/**
* gpmc_configure - write request to configure gpmc
* @cmd: command type
@ -1886,6 +1950,17 @@ int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, config1);
if (p->wait_pin_polarity != GPMC_WAITPINPOLARITY_INVALID) {
config1 = gpmc_read_reg(GPMC_CONFIG);
if (p->wait_pin_polarity == GPMC_WAITPINPOLARITY_ACTIVE_LOW)
config1 &= ~GPMC_CONFIG_WAITPINPOLARITY(p->wait_pin);
else if (p->wait_pin_polarity == GPMC_WAITPINPOLARITY_ACTIVE_HIGH)
config1 |= GPMC_CONFIG_WAITPINPOLARITY(p->wait_pin);
gpmc_write_reg(GPMC_CONFIG, config1);
}
return 0;
}
@ -1975,7 +2050,25 @@ void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p)
__func__);
}
p->wait_pin = GPMC_WAITPIN_INVALID;
p->wait_pin_polarity = GPMC_WAITPINPOLARITY_INVALID;
if (!of_property_read_u32(np, "gpmc,wait-pin", &p->wait_pin)) {
if (!gpmc_is_valid_waitpin(p->wait_pin)) {
pr_err("%s: Invalid wait-pin (%d)\n", __func__, p->wait_pin);
p->wait_pin = GPMC_WAITPIN_INVALID;
}
if (!of_property_read_u32(np, "ti,wait-pin-polarity",
&p->wait_pin_polarity)) {
if (p->wait_pin_polarity != GPMC_WAITPINPOLARITY_ACTIVE_HIGH &&
p->wait_pin_polarity != GPMC_WAITPINPOLARITY_ACTIVE_LOW) {
pr_err("%s: Invalid wait-pin-polarity (%d)\n",
__func__, p->wait_pin_polarity);
p->wait_pin_polarity = GPMC_WAITPINPOLARITY_INVALID;
}
}
p->wait_on_read = of_property_read_bool(np,
"gpmc,wait-on-read");
p->wait_on_write = of_property_read_bool(np,
@ -2080,7 +2173,6 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
const char *name;
int ret, cs;
u32 val;
struct gpio_desc *waitpin_desc = NULL;
struct gpmc_device *gpmc = platform_get_drvdata(pdev);
if (of_property_read_u32(child, "reg", &cs) < 0) {
@ -2208,17 +2300,9 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
/* Reserve wait pin if it is required and valid */
if (gpmc_s.wait_on_read || gpmc_s.wait_on_write) {
unsigned int wait_pin = gpmc_s.wait_pin;
waitpin_desc = gpiochip_request_own_desc(&gpmc->gpio_chip,
wait_pin, "WAITPIN",
GPIO_ACTIVE_HIGH,
GPIOD_IN);
if (IS_ERR(waitpin_desc)) {
dev_err(&pdev->dev, "invalid wait-pin: %d\n", wait_pin);
ret = PTR_ERR(waitpin_desc);
ret = gpmc_alloc_waitpin(gpmc, &gpmc_s);
if (ret < 0)
goto err;
}
}
gpmc_cs_show_timings(cs, "before gpmc_cs_program_settings");
@ -2260,7 +2344,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
ret = -ENODEV;
err_cs:
gpiochip_free_own_desc(waitpin_desc);
gpmc_free_waitpin(gpmc, gpmc_s.wait_pin);
err:
gpmc_cs_free(cs);
@ -2489,7 +2573,7 @@ static int omap_gpmc_context_notifier(struct notifier_block *nb,
static int gpmc_probe(struct platform_device *pdev)
{
int rc;
int rc, i;
u32 l;
struct resource *res;
struct gpmc_device *gpmc;
@ -2545,6 +2629,15 @@ static int gpmc_probe(struct platform_device *pdev)
gpmc_nr_waitpins = GPMC_NR_WAITPINS;
}
gpmc->waitpins = devm_kzalloc(&pdev->dev,
gpmc_nr_waitpins * sizeof(struct gpmc_waitpin),
GFP_KERNEL);
if (!gpmc->waitpins)
return -ENOMEM;
for (i = 0; i < gpmc_nr_waitpins; i++)
gpmc->waitpins[i].pin = GPMC_WAITPIN_INVALID;
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
@ -2598,9 +2691,12 @@ static int gpmc_probe(struct platform_device *pdev)
static int gpmc_remove(struct platform_device *pdev)
{
int i;
struct gpmc_device *gpmc = platform_get_drvdata(pdev);
cpu_pm_unregister_notifier(&gpmc->nb);
for (i = 0; i < gpmc_nr_waitpins; i++)
gpmc_free_waitpin(gpmc, i);
gpmc_free_irq(gpmc);
gpmc_mem_exit();
pm_runtime_put_sync(&pdev->dev);

View file

@ -136,7 +136,8 @@
#define RPCIF_PHYCNT_DDRCAL BIT(19)
#define RPCIF_PHYCNT_HS BIT(18)
#define RPCIF_PHYCNT_CKSEL(v) (((v) & 0x3) << 16) /* valid only for RZ/G2L */
#define RPCIF_PHYCNT_STRTIM(v) (((v) & 0x7) << 15) /* valid for R-Car and RZ/G2{E,H,M,N} */
#define RPCIF_PHYCNT_STRTIM(v) (((v) & 0x7) << 15 | ((v) & 0x8) << 24) /* valid for R-Car and RZ/G2{E,H,M,N} */
#define RPCIF_PHYCNT_WBUF2 BIT(4)
#define RPCIF_PHYCNT_WBUF BIT(2)
#define RPCIF_PHYCNT_PHYMEM(v) (((v) & 0x3) << 0)
@ -317,9 +318,15 @@ int rpcif_hw_init(struct rpcif *rpc, bool hyperflash)
regmap_update_bits(rpc->regmap, RPCIF_PHYCNT, RPCIF_PHYCNT_PHYMEM_MASK,
RPCIF_PHYCNT_PHYMEM(hyperflash ? 3 : 0));
/* DMA Transfer is not supported */
regmap_update_bits(rpc->regmap, RPCIF_PHYCNT, RPCIF_PHYCNT_HS, 0);
if (rpc->type == RPCIF_RCAR_GEN3)
regmap_update_bits(rpc->regmap, RPCIF_PHYCNT,
RPCIF_PHYCNT_STRTIM(7), RPCIF_PHYCNT_STRTIM(7));
else if (rpc->type == RPCIF_RCAR_GEN4)
regmap_update_bits(rpc->regmap, RPCIF_PHYCNT,
RPCIF_PHYCNT_STRTIM(15), RPCIF_PHYCNT_STRTIM(15));
regmap_update_bits(rpc->regmap, RPCIF_PHYOFFSET1, RPCIF_PHYOFFSET1_DDRTMG(3),
RPCIF_PHYOFFSET1_DDRTMG(3));
@ -330,17 +337,17 @@ int rpcif_hw_init(struct rpcif *rpc, bool hyperflash)
regmap_update_bits(rpc->regmap, RPCIF_PHYINT,
RPCIF_PHYINT_WPVAL, 0);
if (rpc->type == RPCIF_RCAR_GEN3)
regmap_update_bits(rpc->regmap, RPCIF_CMNCR,
RPCIF_CMNCR_MOIIO(3) | RPCIF_CMNCR_BSZ(3),
RPCIF_CMNCR_MOIIO(3) |
RPCIF_CMNCR_BSZ(hyperflash ? 1 : 0));
else
if (rpc->type == RPCIF_RZ_G2L)
regmap_update_bits(rpc->regmap, RPCIF_CMNCR,
RPCIF_CMNCR_MOIIO(3) | RPCIF_CMNCR_IOFV(3) |
RPCIF_CMNCR_BSZ(3),
RPCIF_CMNCR_MOIIO(1) | RPCIF_CMNCR_IOFV(2) |
RPCIF_CMNCR_BSZ(hyperflash ? 1 : 0));
else
regmap_update_bits(rpc->regmap, RPCIF_CMNCR,
RPCIF_CMNCR_MOIIO(3) | RPCIF_CMNCR_BSZ(3),
RPCIF_CMNCR_MOIIO(3) |
RPCIF_CMNCR_BSZ(hyperflash ? 1 : 0));
/* Set RCF after BSZ update */
regmap_write(rpc->regmap, RPCIF_DRCR, RPCIF_DRCR_RCF);
@ -715,6 +722,7 @@ static int rpcif_remove(struct platform_device *pdev)
static const struct of_device_id rpcif_of_match[] = {
{ .compatible = "renesas,rcar-gen3-rpc-if", .data = (void *)RPCIF_RCAR_GEN3 },
{ .compatible = "renesas,rcar-gen4-rpc-if", .data = (void *)RPCIF_RCAR_GEN4 },
{ .compatible = "renesas,rzg2l-rpc-if", .data = (void *)RPCIF_RZ_G2L },
{},
};

View file

@ -84,20 +84,7 @@ static int tegra186_emc_debug_available_rates_show(struct seq_file *s,
return 0;
}
static int tegra186_emc_debug_available_rates_open(struct inode *inode,
struct file *file)
{
return single_open(file, tegra186_emc_debug_available_rates_show,
inode->i_private);
}
static const struct file_operations tegra186_emc_debug_available_rates_fops = {
.open = tegra186_emc_debug_available_rates_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_SHOW_ATTRIBUTE(tegra186_emc_debug_available_rates);
static int tegra186_emc_debug_min_rate_get(void *data, u64 *rate)
{

View file

@ -841,20 +841,7 @@ static int tegra_emc_debug_available_rates_show(struct seq_file *s, void *data)
return 0;
}
static int tegra_emc_debug_available_rates_open(struct inode *inode,
struct file *file)
{
return single_open(file, tegra_emc_debug_available_rates_show,
inode->i_private);
}
static const struct file_operations tegra_emc_debug_available_rates_fops = {
.open = tegra_emc_debug_available_rates_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_SHOW_ATTRIBUTE(tegra_emc_debug_available_rates);
static int tegra_emc_debug_min_rate_get(void *data, u64 *rate)
{

View file

@ -1621,20 +1621,7 @@ static int tegra210_emc_debug_available_rates_show(struct seq_file *s,
return 0;
}
static int tegra210_emc_debug_available_rates_open(struct inode *inode,
struct file *file)
{
return single_open(file, tegra210_emc_debug_available_rates_show,
inode->i_private);
}
static const struct file_operations tegra210_emc_debug_available_rates_fops = {
.open = tegra210_emc_debug_available_rates_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_SHOW_ATTRIBUTE(tegra210_emc_debug_available_rates);
static int tegra210_emc_debug_min_rate_get(void *data, u64 *rate)
{

View file

@ -170,6 +170,166 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
.security = 0x504,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0RDA,
.name = "dla0rda",
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
.override = 0x5f0,
.security = 0x5f4,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0FALRDB,
.name = "dla0falrdb",
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
.override = 0x5f8,
.security = 0x5fc,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0WRA,
.name = "dla0wra",
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
.override = 0x600,
.security = 0x604,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0RDB,
.name = "dla0rdb",
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
.override = 0x160,
.security = 0x164,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0RDA1,
.name = "dla0rda1",
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
.override = 0x748,
.security = 0x74c,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0FALWRB,
.name = "dla0falwrb",
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
.override = 0x608,
.security = 0x60c,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0RDB1,
.name = "dla0rdb1",
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
.override = 0x168,
.security = 0x16c,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0WRB,
.name = "dla0wrb",
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
.override = 0x170,
.security = 0x174,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1RDA,
.name = "dla0rda",
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
.override = 0x610,
.security = 0x614,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1FALRDB,
.name = "dla0falrdb",
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
.override = 0x618,
.security = 0x61c,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1WRA,
.name = "dla0wra",
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
.override = 0x620,
.security = 0x624,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1RDB,
.name = "dla0rdb",
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
.override = 0x178,
.security = 0x17c,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1RDA1,
.name = "dla0rda1",
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
.override = 0x750,
.security = 0x754,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1FALWRB,
.name = "dla0falwrb",
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
.override = 0x628,
.security = 0x62c,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1RDB1,
.name = "dla0rdb1",
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
.override = 0x370,
.security = 0x374,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1WRB,
.name = "dla0wrb",
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
.override = 0x378,
.security = 0x37c,
},
},
},
};

View file

@ -1359,20 +1359,7 @@ static int tegra_emc_debug_available_rates_show(struct seq_file *s, void *data)
return 0;
}
static int tegra_emc_debug_available_rates_open(struct inode *inode,
struct file *file)
{
return single_open(file, tegra_emc_debug_available_rates_show,
inode->i_private);
}
static const struct file_operations tegra_emc_debug_available_rates_fops = {
.open = tegra_emc_debug_available_rates_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_SHOW_ATTRIBUTE(tegra_emc_debug_available_rates);
static int tegra_emc_debug_min_rate_get(void *data, u64 *rate)
{

View file

@ -3,6 +3,7 @@
* Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
*/
#include <linux/bcm47xx_nvram.h>
#include <linux/io.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
@ -136,6 +137,8 @@ static int brcm_nvram_probe(struct platform_device *pdev)
if (err)
return err;
bcm47xx_nvram_init_from_iomem(priv->base, resource_size(res));
config.dev = dev;
config.cells = priv->cells;
config.ncells = priv->ncells;

View file

@ -13,6 +13,7 @@ source "drivers/soc/fujitsu/Kconfig"
source "drivers/soc/imx/Kconfig"
source "drivers/soc/ixp4xx/Kconfig"
source "drivers/soc/litex/Kconfig"
source "drivers/soc/loongson/Kconfig"
source "drivers/soc/mediatek/Kconfig"
source "drivers/soc/microchip/Kconfig"
source "drivers/soc/pxa/Kconfig"

View file

@ -18,6 +18,7 @@ obj-y += imx/
obj-y += ixp4xx/
obj-$(CONFIG_SOC_XWAY) += lantiq/
obj-$(CONFIG_LITEX_SOC_CONTROLLER) += litex/
obj-y += loongson/
obj-y += mediatek/
obj-y += microchip/
obj-y += pxa/

View file

@ -926,8 +926,10 @@ int apple_rtkit_wake(struct apple_rtkit *rtk)
}
EXPORT_SYMBOL_GPL(apple_rtkit_wake);
static void apple_rtkit_free(struct apple_rtkit *rtk)
static void apple_rtkit_free(void *data)
{
struct apple_rtkit *rtk = data;
mbox_free_channel(rtk->mbox_chan);
destroy_workqueue(rtk->wq);
@ -950,8 +952,7 @@ struct apple_rtkit *devm_apple_rtkit_init(struct device *dev, void *cookie,
if (IS_ERR(rtk))
return rtk;
ret = devm_add_action_or_reset(dev, (void (*)(void *))apple_rtkit_free,
rtk);
ret = devm_add_action_or_reset(dev, apple_rtkit_free, rtk);
if (ret)
return ERR_PTR(ret);

View file

@ -164,6 +164,11 @@ static int apple_sart_probe(struct platform_device *pdev)
return 0;
}
static void apple_sart_put_device(void *dev)
{
put_device(dev);
}
struct apple_sart *devm_apple_sart_get(struct device *dev)
{
struct device_node *sart_node;
@ -187,7 +192,7 @@ struct apple_sart *devm_apple_sart_get(struct device *dev)
return ERR_PTR(-EPROBE_DEFER);
}
ret = devm_add_action_or_reset(dev, (void (*)(void *))put_device,
ret = devm_add_action_or_reset(dev, apple_sart_put_device,
&sart_pdev->dev);
if (ret)
return ERR_PTR(ret);

View file

@ -13,10 +13,9 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_gpio.h> /* for of_mm_gpio_chip */
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
/* FIXME: needed for gpio_to_chip() get rid of this */
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/export.h>
#include <soc/fsl/qe/qe.h>
@ -25,9 +24,6 @@ struct qe_gpio_chip {
struct of_mm_gpio_chip mm_gc;
spinlock_t lock;
unsigned long pin_flags[QE_PIO_PINS];
#define QE_PIN_REQUESTED 0
/* shadowed data register to clear/set bits safely */
u32 cpdata;
@ -149,62 +145,65 @@ struct qe_pin {
/**
* qe_pin_request - Request a QE pin
* @np: device node to get a pin from
* @index: index of a pin in the device tree
* @dev: device to get the pin from
* @index: index of the pin in the device tree
* Context: non-atomic
*
* This function return qe_pin so that you could use it with the rest of
* the QE Pin Multiplexing API.
*/
struct qe_pin *qe_pin_request(struct device_node *np, int index)
struct qe_pin *qe_pin_request(struct device *dev, int index)
{
struct qe_pin *qe_pin;
struct gpio_chip *gc;
struct qe_gpio_chip *qe_gc;
struct gpio_desc *gpiod;
int gpio_num;
int err;
unsigned long flags;
qe_pin = kzalloc(sizeof(*qe_pin), GFP_KERNEL);
if (!qe_pin) {
pr_debug("%s: can't allocate memory\n", __func__);
dev_dbg(dev, "%s: can't allocate memory\n", __func__);
return ERR_PTR(-ENOMEM);
}
err = of_get_gpio(np, index);
if (err < 0)
/*
* Request gpio as nonexclusive as it was likely reserved by the
* caller, and we are not planning on controlling it, we only need
* the descriptor to the to the gpio chip structure.
*/
gpiod = gpiod_get_index(dev, NULL, index,
GPIOD_ASIS | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
err = PTR_ERR_OR_ZERO(gpiod);
if (err)
goto err0;
gc = gpio_to_chip(err);
gc = gpiod_to_chip(gpiod);
gpio_num = desc_to_gpio(gpiod);
/* We no longer need this descriptor */
gpiod_put(gpiod);
if (WARN_ON(!gc)) {
err = -ENODEV;
goto err0;
}
qe_pin->controller = gpiochip_get_data(gc);
/*
* FIXME: this gets the local offset on the gpio_chip so that the driver
* can manipulate pin control settings through its custom API. The real
* solution is to create a real pin control driver for this.
*/
qe_pin->num = gpio_num - gc->base;
if (!of_device_is_compatible(gc->of_node, "fsl,mpc8323-qe-pario-bank")) {
pr_debug("%s: tried to get a non-qe pin\n", __func__);
dev_dbg(dev, "%s: tried to get a non-qe pin\n", __func__);
err = -EINVAL;
goto err0;
}
qe_gc = gpiochip_get_data(gc);
spin_lock_irqsave(&qe_gc->lock, flags);
err -= gc->base;
if (test_and_set_bit(QE_PIN_REQUESTED, &qe_gc->pin_flags[err]) == 0) {
qe_pin->controller = qe_gc;
qe_pin->num = err;
err = 0;
} else {
err = -EBUSY;
}
spin_unlock_irqrestore(&qe_gc->lock, flags);
if (!err)
return qe_pin;
return qe_pin;
err0:
kfree(qe_pin);
pr_debug("%s failed with status %d\n", __func__, err);
dev_dbg(dev, "%s failed with status %d\n", __func__, err);
return ERR_PTR(err);
}
EXPORT_SYMBOL(qe_pin_request);
@ -219,14 +218,6 @@ EXPORT_SYMBOL(qe_pin_request);
*/
void qe_pin_free(struct qe_pin *qe_pin)
{
struct qe_gpio_chip *qe_gc = qe_pin->controller;
unsigned long flags;
const int pin = qe_pin->num;
spin_lock_irqsave(&qe_gc->lock, flags);
test_and_clear_bit(QE_PIN_REQUESTED, &qe_gc->pin_flags[pin]);
spin_unlock_irqrestore(&qe_gc->lock, flags);
kfree(qe_pin);
}
EXPORT_SYMBOL(qe_pin_free);

View file

@ -755,6 +755,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
[IMX8MM_POWER_DOMAIN_OTG1] = {
.genpd = {
.name = "usb-otg1",
.flags = GENPD_FLAG_ACTIVE_WAKEUP,
},
.bits = {
.pxx = IMX8MM_OTG1_SW_Pxx_REQ,
@ -766,6 +767,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
[IMX8MM_POWER_DOMAIN_OTG2] = {
.genpd = {
.name = "usb-otg2",
.flags = GENPD_FLAG_ACTIVE_WAKEUP,
},
.bits = {
.pxx = IMX8MM_OTG2_SW_Pxx_REQ,
@ -1232,6 +1234,7 @@ static const struct imx_pgc_domain imx8mn_pgc_domains[] = {
[IMX8MN_POWER_DOMAIN_OTG1] = {
.genpd = {
.name = "usb-otg1",
.flags = GENPD_FLAG_ACTIVE_WAKEUP,
},
.bits = {
.pxx = IMX8MN_OTG1_SW_Pxx_REQ,

View file

@ -210,9 +210,14 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
return -ENOMEM;
bc->bus_power_dev = genpd_dev_pm_attach_by_name(dev, "bus");
if (IS_ERR(bc->bus_power_dev))
return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev),
"failed to attach power domain \"bus\"\n");
if (IS_ERR(bc->bus_power_dev)) {
if (PTR_ERR(bc->bus_power_dev) == -ENODEV)
return dev_err_probe(dev, -EPROBE_DEFER,
"failed to attach power domain \"bus\"\n");
else
return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev),
"failed to attach power domain \"bus\"\n");
}
for (i = 0; i < bc_data->num_domains; i++) {
const struct imx8m_blk_ctrl_domain_data *data = &bc_data->domains[i];

View file

@ -0,0 +1,18 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Loongson-2 series SoC drivers
#
config LOONGSON2_GUTS
tristate "Loongson-2 SoC Global UtiliTieS (GUTS) register block"
depends on LOONGARCH || COMPILE_TEST
select SOC_BUS
help
The global utilities block controls PCIE device enabling, alternate
function selection for multiplexed signals, consistency of HDA, USB
and PCIE, configuration of memory controller, rtc controller, lio
controller, and clock control. This patch adds a driver to manage
and access global utilities block for LoongArch architecture Loongson-2
SoCs. Initially only reading SVR and registering soc device are
supported. Other guts accesses, such as reading firmware configuration
by default, should eventually be added into this driver as well.

View file

@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Makefile for the Linux Kernel SoC Loongson-2 specific device drivers
#
obj-$(CONFIG_LOONGSON2_GUTS) += loongson2_guts.o

View file

@ -0,0 +1,192 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Author: Yinbo Zhu <zhuyinbo@loongson.cn>
* Copyright (C) 2022-2023 Loongson Technology Corporation Limited
*/
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of_fdt.h>
#include <linux/sys_soc.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
static struct soc_device_attribute soc_dev_attr;
static struct soc_device *soc_dev;
/*
* Global Utility Registers.
*
* Not all registers defined in this structure are available on all chips, so
* you are expected to know whether a given register actually exists on your
* chip before you access it.
*
* Also, some registers are similar on different chips but have slightly
* different names. In these cases, one name is chosen to avoid extraneous
* #ifdefs.
*/
struct scfg_guts {
u32 svr; /* Version Register */
u8 res0[4];
u16 feature; /* Feature Register */
u32 vendor; /* Vendor Register */
u8 res1[6];
u32 id;
u8 res2[0x3ff8 - 0x18];
u32 chip;
};
static struct guts {
struct scfg_guts __iomem *regs;
bool little_endian;
} *guts;
struct loongson2_soc_die_attr {
char *die;
u32 svr;
u32 mask;
};
/* SoC die attribute definition for Loongson-2 platform */
static const struct loongson2_soc_die_attr loongson2_soc_die[] = {
/*
* LoongArch-based SoCs Loongson-2 Series
*/
/* Die: 2k1000, SoC: 2k1000 */
{ .die = "2K1000",
.svr = 0x00000013,
.mask = 0x000000ff,
},
{ },
};
static const struct loongson2_soc_die_attr *loongson2_soc_die_match(
u32 svr, const struct loongson2_soc_die_attr *matches)
{
while (matches->svr) {
if (matches->svr == (svr & matches->mask))
return matches;
matches++;
};
return NULL;
}
static u32 loongson2_guts_get_svr(void)
{
u32 svr = 0;
if (!guts || !guts->regs)
return svr;
if (guts->little_endian)
svr = ioread32(&guts->regs->svr);
else
svr = ioread32be(&guts->regs->svr);
return svr;
}
static int loongson2_guts_probe(struct platform_device *pdev)
{
struct device_node *root, *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct resource *res;
const struct loongson2_soc_die_attr *soc_die;
const char *machine;
u32 svr;
/* Initialize guts */
guts = devm_kzalloc(dev, sizeof(*guts), GFP_KERNEL);
if (!guts)
return -ENOMEM;
guts->little_endian = of_property_read_bool(np, "little-endian");
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
guts->regs = ioremap(res->start, res->end - res->start + 1);
if (IS_ERR(guts->regs))
return PTR_ERR(guts->regs);
/* Register soc device */
root = of_find_node_by_path("/");
if (of_property_read_string(root, "model", &machine))
of_property_read_string_index(root, "compatible", 0, &machine);
of_node_put(root);
if (machine)
soc_dev_attr.machine = devm_kstrdup(dev, machine, GFP_KERNEL);
svr = loongson2_guts_get_svr();
soc_die = loongson2_soc_die_match(svr, loongson2_soc_die);
if (soc_die) {
soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL,
"Loongson %s", soc_die->die);
} else {
soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL, "Loongson");
}
if (!soc_dev_attr.family)
return -ENOMEM;
soc_dev_attr.soc_id = devm_kasprintf(dev, GFP_KERNEL,
"svr:0x%08x", svr);
if (!soc_dev_attr.soc_id)
return -ENOMEM;
soc_dev_attr.revision = devm_kasprintf(dev, GFP_KERNEL, "%d.%d",
(svr >> 4) & 0xf, svr & 0xf);
if (!soc_dev_attr.revision)
return -ENOMEM;
soc_dev = soc_device_register(&soc_dev_attr);
if (IS_ERR(soc_dev))
return PTR_ERR(soc_dev);
pr_info("Machine: %s\n", soc_dev_attr.machine);
pr_info("SoC family: %s\n", soc_dev_attr.family);
pr_info("SoC ID: %s, Revision: %s\n",
soc_dev_attr.soc_id, soc_dev_attr.revision);
return 0;
}
static int loongson2_guts_remove(struct platform_device *dev)
{
soc_device_unregister(soc_dev);
return 0;
}
/*
* Table for matching compatible strings, for device tree
* guts node, for Loongson-2 SoCs.
*/
static const struct of_device_id loongson2_guts_of_match[] = {
{ .compatible = "loongson,ls2k-chipid", },
{}
};
MODULE_DEVICE_TABLE(of, loongson2_guts_of_match);
static struct platform_driver loongson2_guts_driver = {
.driver = {
.name = "loongson2-guts",
.of_match_table = loongson2_guts_of_match,
},
.probe = loongson2_guts_probe,
.remove = loongson2_guts_remove,
};
static int __init loongson2_guts_init(void)
{
return platform_driver_register(&loongson2_guts_driver);
}
core_initcall(loongson2_guts_init);
static void __exit loongson2_guts_exit(void)
{
platform_driver_unregister(&loongson2_guts_driver);
}
module_exit(loongson2_guts_exit);
MODULE_DESCRIPTION("Loongson2 GUTS driver");
MODULE_LICENSE("GPL");

View file

@ -5,9 +5,11 @@
/* 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_DPI_FORMAT_MASK GENMASK(1, 0)
#define MT8186_DPI_RGB888_SDR_CON 0
#define MT8186_DPI_RGB888_DDR_CON 1
#define MT8186_DPI_RGB565_SDR_CON 2
#define MT8186_DPI_RGB565_DDR_CON 3
#define MT8186_MMSYS_OVL_CON 0xF04
#define MT8186_MMSYS_OVL0_CON_MASK 0x3

View file

@ -26,61 +26,26 @@ static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = {
.num_routes = ARRAY_SIZE(mmsys_default_routing_table),
};
static const struct mtk_mmsys_match_data mt2701_mmsys_match_data = {
.num_drv_data = 1,
.drv_data = {
&mt2701_mmsys_driver_data,
},
};
static const struct mtk_mmsys_driver_data mt2712_mmsys_driver_data = {
.clk_driver = "clk-mt2712-mm",
.routes = mmsys_default_routing_table,
.num_routes = ARRAY_SIZE(mmsys_default_routing_table),
};
static const struct mtk_mmsys_match_data mt2712_mmsys_match_data = {
.num_drv_data = 1,
.drv_data = {
&mt2712_mmsys_driver_data,
},
};
static const struct mtk_mmsys_driver_data mt6779_mmsys_driver_data = {
.clk_driver = "clk-mt6779-mm",
};
static const struct mtk_mmsys_match_data mt6779_mmsys_match_data = {
.num_drv_data = 1,
.drv_data = {
&mt6779_mmsys_driver_data,
},
};
static const struct mtk_mmsys_driver_data mt6797_mmsys_driver_data = {
.clk_driver = "clk-mt6797-mm",
};
static const struct mtk_mmsys_match_data mt6797_mmsys_match_data = {
.num_drv_data = 1,
.drv_data = {
&mt6797_mmsys_driver_data,
},
};
static const struct mtk_mmsys_driver_data mt8167_mmsys_driver_data = {
.clk_driver = "clk-mt8167-mm",
.routes = mt8167_mmsys_routing_table,
.num_routes = ARRAY_SIZE(mt8167_mmsys_routing_table),
};
static const struct mtk_mmsys_match_data mt8167_mmsys_match_data = {
.num_drv_data = 1,
.drv_data = {
&mt8167_mmsys_driver_data,
},
};
static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = {
.clk_driver = "clk-mt8173-mm",
.routes = mmsys_default_routing_table,
@ -88,13 +53,6 @@ static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = {
.sw0_rst_offset = MT8183_MMSYS_SW0_RST_B,
};
static const struct mtk_mmsys_match_data mt8173_mmsys_match_data = {
.num_drv_data = 1,
.drv_data = {
&mt8173_mmsys_driver_data,
},
};
static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = {
.clk_driver = "clk-mt8183-mm",
.routes = mmsys_mt8183_routing_table,
@ -102,13 +60,6 @@ static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = {
.sw0_rst_offset = MT8183_MMSYS_SW0_RST_B,
};
static const struct mtk_mmsys_match_data mt8183_mmsys_match_data = {
.num_drv_data = 1,
.drv_data = {
&mt8183_mmsys_driver_data,
},
};
static const struct mtk_mmsys_driver_data mt8186_mmsys_driver_data = {
.clk_driver = "clk-mt8186-mm",
.routes = mmsys_mt8186_routing_table,
@ -116,13 +67,6 @@ static const struct mtk_mmsys_driver_data mt8186_mmsys_driver_data = {
.sw0_rst_offset = MT8186_MMSYS_SW0_RST_B,
};
static const struct mtk_mmsys_match_data mt8186_mmsys_match_data = {
.num_drv_data = 1,
.drv_data = {
&mt8186_mmsys_driver_data,
},
};
static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = {
.clk_driver = "clk-mt8192-mm",
.routes = mmsys_mt8192_routing_table,
@ -130,66 +74,25 @@ static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = {
.sw0_rst_offset = MT8186_MMSYS_SW0_RST_B,
};
static const struct mtk_mmsys_match_data mt8192_mmsys_match_data = {
.num_drv_data = 1,
.drv_data = {
&mt8192_mmsys_driver_data,
},
};
static const struct mtk_mmsys_driver_data mt8195_vdosys0_driver_data = {
.io_start = 0x1c01a000,
.clk_driver = "clk-mt8195-vdo0",
.routes = mmsys_mt8195_routing_table,
.num_routes = ARRAY_SIZE(mmsys_mt8195_routing_table),
};
static const struct mtk_mmsys_driver_data mt8195_vdosys1_driver_data = {
.io_start = 0x1c100000,
.clk_driver = "clk-mt8195-vdo1",
};
static const struct mtk_mmsys_match_data mt8195_mmsys_match_data = {
.num_drv_data = 2,
.drv_data = {
&mt8195_vdosys0_driver_data,
&mt8195_vdosys1_driver_data,
},
};
static const struct mtk_mmsys_driver_data mt8365_mmsys_driver_data = {
.clk_driver = "clk-mt8365-mm",
.routes = mt8365_mmsys_routing_table,
.num_routes = ARRAY_SIZE(mt8365_mmsys_routing_table),
};
static const struct mtk_mmsys_match_data mt8365_mmsys_match_data = {
.num_drv_data = 1,
.drv_data = {
&mt8365_mmsys_driver_data,
},
};
struct mtk_mmsys {
void __iomem *regs;
const struct mtk_mmsys_driver_data *data;
spinlock_t lock; /* protects mmsys_sw_rst_b reg */
struct reset_controller_dev rcdev;
phys_addr_t io_start;
};
static int mtk_mmsys_find_match_drvdata(struct mtk_mmsys *mmsys,
const struct mtk_mmsys_match_data *match)
{
int i;
for (i = 0; i < match->num_drv_data; i++)
if (mmsys->io_start == match->drv_data[i]->io_start)
return i;
return -EINVAL;
}
void mtk_mmsys_ddp_connect(struct device *dev,
enum mtk_ddp_comp_id cur,
enum mtk_ddp_comp_id next)
@ -238,12 +141,27 @@ static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32 offset, u32 mask,
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);
struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
switch (val) {
case MTK_DPI_RGB888_SDR_CON:
mtk_mmsys_update_bits(mmsys, MT8186_MMSYS_DPI_OUTPUT_FORMAT,
MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB888_SDR_CON);
break;
case MTK_DPI_RGB565_SDR_CON:
mtk_mmsys_update_bits(mmsys, MT8186_MMSYS_DPI_OUTPUT_FORMAT,
MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB565_SDR_CON);
break;
case MTK_DPI_RGB565_DDR_CON:
mtk_mmsys_update_bits(mmsys, MT8186_MMSYS_DPI_OUTPUT_FORMAT,
MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB565_DDR_CON);
break;
case MTK_DPI_RGB888_DDR_CON:
default:
mtk_mmsys_update_bits(mmsys, MT8186_MMSYS_DPI_OUTPUT_FORMAT,
MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB888_DDR_CON);
break;
}
}
EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_dpi_fmt_config);
@ -304,9 +222,7 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct platform_device *clks;
struct platform_device *drm;
const struct mtk_mmsys_match_data *match_data;
struct mtk_mmsys *mmsys;
struct resource *res;
int ret;
mmsys = devm_kzalloc(dev, sizeof(*mmsys), GFP_KERNEL);
@ -332,27 +248,7 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
return ret;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "Couldn't get mmsys resource\n");
return -EINVAL;
}
mmsys->io_start = res->start;
match_data = of_device_get_match_data(dev);
if (match_data->num_drv_data > 1) {
/* This SoC has multiple mmsys channels */
ret = mtk_mmsys_find_match_drvdata(mmsys, match_data);
if (ret < 0) {
dev_err(dev, "Couldn't get match driver data\n");
return ret;
}
mmsys->data = match_data->drv_data[ret];
} else {
dev_dbg(dev, "Using single mmsys channel\n");
mmsys->data = match_data->drv_data[0];
}
mmsys->data = of_device_get_match_data(&pdev->dev);
platform_set_drvdata(pdev, mmsys);
clks = platform_device_register_data(&pdev->dev, mmsys->data->clk_driver,
@ -373,47 +269,51 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
static const struct of_device_id of_match_mtk_mmsys[] = {
{
.compatible = "mediatek,mt2701-mmsys",
.data = &mt2701_mmsys_match_data,
.data = &mt2701_mmsys_driver_data,
},
{
.compatible = "mediatek,mt2712-mmsys",
.data = &mt2712_mmsys_match_data,
.data = &mt2712_mmsys_driver_data,
},
{
.compatible = "mediatek,mt6779-mmsys",
.data = &mt6779_mmsys_match_data,
.data = &mt6779_mmsys_driver_data,
},
{
.compatible = "mediatek,mt6797-mmsys",
.data = &mt6797_mmsys_match_data,
.data = &mt6797_mmsys_driver_data,
},
{
.compatible = "mediatek,mt8167-mmsys",
.data = &mt8167_mmsys_match_data,
.data = &mt8167_mmsys_driver_data,
},
{
.compatible = "mediatek,mt8173-mmsys",
.data = &mt8173_mmsys_match_data,
.data = &mt8173_mmsys_driver_data,
},
{
.compatible = "mediatek,mt8183-mmsys",
.data = &mt8183_mmsys_match_data,
.data = &mt8183_mmsys_driver_data,
},
{
.compatible = "mediatek,mt8186-mmsys",
.data = &mt8186_mmsys_match_data,
.data = &mt8186_mmsys_driver_data,
},
{
.compatible = "mediatek,mt8192-mmsys",
.data = &mt8192_mmsys_match_data,
.data = &mt8192_mmsys_driver_data,
},
{ /* deprecated compatible */
.compatible = "mediatek,mt8195-mmsys",
.data = &mt8195_vdosys0_driver_data,
},
{
.compatible = "mediatek,mt8195-mmsys",
.data = &mt8195_mmsys_match_data,
.compatible = "mediatek,mt8195-vdosys0",
.data = &mt8195_vdosys0_driver_data,
},
{
.compatible = "mediatek,mt8365-mmsys",
.data = &mt8365_mmsys_match_data,
.data = &mt8365_mmsys_driver_data,
},
{ }
};

View file

@ -87,18 +87,12 @@ struct mtk_mmsys_routes {
};
struct mtk_mmsys_driver_data {
const resource_size_t io_start;
const char *clk_driver;
const struct mtk_mmsys_routes *routes;
const unsigned int num_routes;
const u16 sw0_rst_offset;
};
struct mtk_mmsys_match_data {
unsigned short num_drv_data;
const struct mtk_mmsys_driver_data *drv_data[];
};
/*
* Routes in mt8173, mt2701, mt2712 are different. That means
* in the same register address, it controls different input/output

View file

@ -983,6 +983,68 @@ static int mt8195_regs[] = {
[PWRAP_WACS2_RDATA] = 0x8A8,
};
static int mt8365_regs[] = {
[PWRAP_MUX_SEL] = 0x0,
[PWRAP_WRAP_EN] = 0x4,
[PWRAP_DIO_EN] = 0x8,
[PWRAP_CSHEXT_WRITE] = 0x24,
[PWRAP_CSHEXT_READ] = 0x28,
[PWRAP_STAUPD_PRD] = 0x3c,
[PWRAP_STAUPD_GRPEN] = 0x40,
[PWRAP_STAUPD_MAN_TRIG] = 0x58,
[PWRAP_STAUPD_STA] = 0x5c,
[PWRAP_WRAP_STA] = 0x60,
[PWRAP_HARB_INIT] = 0x64,
[PWRAP_HARB_HPRIO] = 0x68,
[PWRAP_HIPRIO_ARB_EN] = 0x6c,
[PWRAP_HARB_STA0] = 0x70,
[PWRAP_HARB_STA1] = 0x74,
[PWRAP_MAN_EN] = 0x7c,
[PWRAP_MAN_CMD] = 0x80,
[PWRAP_MAN_RDATA] = 0x84,
[PWRAP_MAN_VLDCLR] = 0x88,
[PWRAP_WACS0_EN] = 0x8c,
[PWRAP_INIT_DONE0] = 0x90,
[PWRAP_WACS0_CMD] = 0xc00,
[PWRAP_WACS0_RDATA] = 0xc04,
[PWRAP_WACS0_VLDCLR] = 0xc08,
[PWRAP_WACS1_EN] = 0x94,
[PWRAP_INIT_DONE1] = 0x98,
[PWRAP_WACS2_EN] = 0x9c,
[PWRAP_INIT_DONE2] = 0xa0,
[PWRAP_WACS2_CMD] = 0xc20,
[PWRAP_WACS2_RDATA] = 0xc24,
[PWRAP_WACS2_VLDCLR] = 0xc28,
[PWRAP_INT_EN] = 0xb4,
[PWRAP_INT_FLG_RAW] = 0xb8,
[PWRAP_INT_FLG] = 0xbc,
[PWRAP_INT_CLR] = 0xc0,
[PWRAP_SIG_ADR] = 0xd4,
[PWRAP_SIG_MODE] = 0xd8,
[PWRAP_SIG_VALUE] = 0xdc,
[PWRAP_SIG_ERRVAL] = 0xe0,
[PWRAP_CRC_EN] = 0xe4,
[PWRAP_TIMER_EN] = 0xe8,
[PWRAP_TIMER_STA] = 0xec,
[PWRAP_WDT_UNIT] = 0xf0,
[PWRAP_WDT_SRC_EN] = 0xf4,
[PWRAP_WDT_FLG] = 0xfc,
[PWRAP_DEBUG_INT_SEL] = 0x104,
[PWRAP_CIPHER_KEY_SEL] = 0x1c4,
[PWRAP_CIPHER_IV_SEL] = 0x1c8,
[PWRAP_CIPHER_RDY] = 0x1d0,
[PWRAP_CIPHER_MODE] = 0x1d4,
[PWRAP_CIPHER_SWRST] = 0x1d8,
[PWRAP_DCM_EN] = 0x1dc,
[PWRAP_DCM_DBC_PRD] = 0x1e0,
[PWRAP_EINT_STA0_ADR] = 0x44,
[PWRAP_EINT_STA1_ADR] = 0x48,
[PWRAP_INT1_EN] = 0xc4,
[PWRAP_INT1_FLG] = 0xcc,
[PWRAP_INT1_CLR] = 0xd0,
[PWRAP_WDT_SRC_EN_1] = 0xf8,
};
static int mt8516_regs[] = {
[PWRAP_MUX_SEL] = 0x0,
[PWRAP_WRAP_EN] = 0x4,
@ -1139,6 +1201,7 @@ enum pwrap_type {
PWRAP_MT8183,
PWRAP_MT8186,
PWRAP_MT8195,
PWRAP_MT8365,
PWRAP_MT8516,
};
@ -1171,6 +1234,8 @@ struct pmic_wrapper {
const struct pwrap_slv_type *slave;
struct clk *clk_spi;
struct clk *clk_wrap;
struct clk *clk_sys;
struct clk *clk_tmr;
struct reset_control *rstc;
struct reset_control *rstc_bridge;
@ -1596,6 +1661,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
case PWRAP_MT6797:
case PWRAP_MT8173:
case PWRAP_MT8186:
case PWRAP_MT8365:
case PWRAP_MT8516:
pwrap_writel(wrp, 1, PWRAP_CIPHER_EN);
break;
@ -2104,6 +2170,19 @@ static struct pmic_wrapper_type pwrap_mt8195 = {
.init_soc_specific = NULL,
};
static const struct pmic_wrapper_type pwrap_mt8365 = {
.regs = mt8365_regs,
.type = PWRAP_MT8365,
.arb_en_all = 0x3ffff,
.int_en_all = 0x7f1fffff,
.int1_en_all = 0x0,
.spi_w = PWRAP_MAN_CMD_SPI_WRITE,
.wdt_src = PWRAP_WDT_SRC_MASK_ALL,
.caps = PWRAP_CAP_INT1_EN | PWRAP_CAP_WDT_SRC1,
.init_reg_clock = pwrap_common_init_reg_clock,
.init_soc_specific = NULL,
};
static struct pmic_wrapper_type pwrap_mt8516 = {
.regs = mt8516_regs,
.type = PWRAP_MT8516,
@ -2141,6 +2220,7 @@ static const struct of_device_id of_pwrap_match_tbl[] = {
{ .compatible = "mediatek,mt8183-pwrap", .data = &pwrap_mt8183 },
{ .compatible = "mediatek,mt8186-pwrap", .data = &pwrap_mt8186 },
{ .compatible = "mediatek,mt8195-pwrap", .data = &pwrap_mt8195 },
{ .compatible = "mediatek,mt8365-pwrap", .data = &pwrap_mt8365 },
{ .compatible = "mediatek,mt8516-pwrap", .data = &pwrap_mt8516 },
{ /* sentinel */ }
};
@ -2214,6 +2294,20 @@ static int pwrap_probe(struct platform_device *pdev)
return PTR_ERR(wrp->clk_wrap);
}
wrp->clk_sys = devm_clk_get_optional(wrp->dev, "sys");
if (IS_ERR(wrp->clk_sys)) {
return dev_err_probe(wrp->dev, PTR_ERR(wrp->clk_sys),
"failed to get clock: %pe\n",
wrp->clk_sys);
}
wrp->clk_tmr = devm_clk_get_optional(wrp->dev, "tmr");
if (IS_ERR(wrp->clk_tmr)) {
return dev_err_probe(wrp->dev, PTR_ERR(wrp->clk_tmr),
"failed to get clock: %pe\n",
wrp->clk_tmr);
}
ret = clk_prepare_enable(wrp->clk_spi);
if (ret)
return ret;
@ -2222,6 +2316,14 @@ static int pwrap_probe(struct platform_device *pdev)
if (ret)
goto err_out1;
ret = clk_prepare_enable(wrp->clk_sys);
if (ret)
goto err_out2;
ret = clk_prepare_enable(wrp->clk_tmr);
if (ret)
goto err_out3;
/* Enable internal dynamic clock */
if (HAS_CAP(wrp->master->caps, PWRAP_CAP_DCM)) {
pwrap_writel(wrp, 1, PWRAP_DCM_EN);
@ -2236,7 +2338,7 @@ static int pwrap_probe(struct platform_device *pdev)
ret = pwrap_init(wrp);
if (ret) {
dev_dbg(wrp->dev, "init failed with %d\n", ret);
goto err_out2;
goto err_out4;
}
}
@ -2250,7 +2352,7 @@ static int pwrap_probe(struct platform_device *pdev)
if (!(pwrap_readl(wrp, PWRAP_WACS2_RDATA) & mask_done)) {
dev_dbg(wrp->dev, "initialization isn't finished\n");
ret = -ENODEV;
goto err_out2;
goto err_out4;
}
/* Initialize watchdog, may not be done by the bootloader */
@ -2288,7 +2390,7 @@ static int pwrap_probe(struct platform_device *pdev)
IRQF_TRIGGER_HIGH,
"mt-pmic-pwrap", wrp);
if (ret)
goto err_out2;
goto err_out4;
wrp->regmap = devm_regmap_init(wrp->dev, NULL, wrp, wrp->slave->regops->regmap);
if (IS_ERR(wrp->regmap)) {
@ -2300,11 +2402,15 @@ static int pwrap_probe(struct platform_device *pdev)
if (ret) {
dev_dbg(wrp->dev, "failed to create child devices at %pOF\n",
np);
goto err_out2;
goto err_out4;
}
return 0;
err_out4:
clk_disable_unprepare(wrp->clk_tmr);
err_out3:
clk_disable_unprepare(wrp->clk_sys);
err_out2:
clk_disable_unprepare(wrp->clk_wrap);
err_out1:

View file

@ -146,10 +146,8 @@ static int pxa_ssp_probe(struct platform_device *pdev)
}
ssp->irq = platform_get_irq(pdev, 0);
if (ssp->irq < 0) {
dev_err(dev, "no IRQ resource defined\n");
if (ssp->irq < 0)
return -ENODEV;
}
if (dev->of_node) {
const struct of_device_id *id =

View file

@ -63,6 +63,7 @@ config QCOM_GSBI
config QCOM_LLCC
tristate "Qualcomm Technologies, Inc. LLCC driver"
depends on ARCH_QCOM || COMPILE_TEST
select REGMAP_MMIO
help
Qualcomm Technologies, Inc. platform specific
Last Level Cache Controller(LLCC) driver for platforms such as,
@ -236,6 +237,7 @@ config QCOM_ICC_BWMON
tristate "QCOM Interconnect Bandwidth Monitor driver"
depends on ARCH_QCOM || COMPILE_TEST
select PM_OPP
select REGMAP_MMIO
help
Sets up driver monitoring bandwidth on various interconnects and
based on that voting for interconnect bandwidth, adjusting their

View file

@ -454,11 +454,19 @@ static int apr_add_device(struct device *dev, struct device_node *np,
adev->dev.driver = NULL;
spin_lock(&apr->svcs_lock);
idr_alloc(&apr->svcs_idr, svc, svc_id, svc_id + 1, GFP_ATOMIC);
ret = idr_alloc(&apr->svcs_idr, svc, svc_id, svc_id + 1, GFP_ATOMIC);
spin_unlock(&apr->svcs_lock);
if (ret < 0) {
dev_err(dev, "idr_alloc failed: %d\n", ret);
goto out;
}
of_property_read_string_index(np, "qcom,protection-domain",
1, &adev->service_path);
ret = of_property_read_string_index(np, "qcom,protection-domain",
1, &adev->service_path);
if (ret < 0) {
dev_err(dev, "Failed to read second value of qcom,protection-domain\n");
goto out;
}
dev_info(dev, "Adding APR/GPR dev: %s\n", dev_name(&adev->dev));
@ -468,6 +476,7 @@ static int apr_add_device(struct device *dev, struct device_node *np,
put_device(&adev->dev);
}
out:
return ret;
}

View file

@ -338,6 +338,8 @@ static int cmd_db_dev_probe(struct platform_device *pdev)
debugfs_create_file("cmd-db", 0400, NULL, NULL, &cmd_db_debugfs_ops);
device_set_pm_not_required(&pdev->dev);
return 0;
}

View file

@ -21,6 +21,8 @@
#define ACTIVATE BIT(0)
#define DEACTIVATE BIT(1)
#define ACT_CLEAR BIT(0)
#define ACT_COMPLETE BIT(4)
#define ACT_CTRL_OPCODE_ACTIVATE BIT(0)
#define ACT_CTRL_OPCODE_DEACTIVATE BIT(1)
#define ACT_CTRL_ACT_TRIG BIT(0)
@ -41,19 +43,30 @@
#define MAX_CAP_TO_BYTES(n) (n * SZ_1K)
#define LLCC_TRP_ACT_CTRLn(n) (n * SZ_4K)
#define LLCC_TRP_ACT_CLEARn(n) (8 + n * SZ_4K)
#define LLCC_TRP_STATUSn(n) (4 + n * SZ_4K)
#define LLCC_TRP_ATTR0_CFGn(n) (0x21000 + SZ_8 * n)
#define LLCC_TRP_ATTR1_CFGn(n) (0x21004 + SZ_8 * n)
#define LLCC_TRP_ATTR2_CFGn(n) (0x21100 + SZ_8 * n)
#define LLCC_TRP_SCID_DIS_CAP_ALLOC 0x21f00
#define LLCC_TRP_PCB_ACT 0x21f04
#define LLCC_TRP_ALGO_CFG1 0x21f0c
#define LLCC_TRP_ALGO_CFG2 0x21f10
#define LLCC_TRP_ALGO_CFG3 0x21f14
#define LLCC_TRP_ALGO_CFG4 0x21f18
#define LLCC_TRP_ALGO_CFG5 0x21f1c
#define LLCC_TRP_WRSC_EN 0x21f20
#define LLCC_TRP_ALGO_CFG6 0x21f24
#define LLCC_TRP_ALGO_CFG7 0x21f28
#define LLCC_TRP_WRSC_CACHEABLE_EN 0x21f2c
#define LLCC_TRP_ALGO_CFG8 0x21f30
#define BANK_OFFSET_STRIDE 0x80000
#define LLCC_VERSION_2_0_0_0 0x02000000
#define LLCC_VERSION_2_1_0_0 0x02010000
#define LLCC_VERSION_4_1_0_0 0x04010000
/**
* struct llcc_slice_config - Data associated with the llcc slice
@ -97,6 +110,14 @@ struct llcc_slice_config {
bool activate_on_init;
bool write_scid_en;
bool write_scid_cacheable_en;
bool stale_en;
bool stale_cap_en;
bool mru_uncap_en;
bool mru_rollover;
bool alloc_oneway_en;
bool ovcap_en;
bool ovcap_prio;
bool vict_prio;
};
struct qcom_llcc_config {
@ -297,6 +318,38 @@ 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 struct llcc_slice_config sm8550_data[] = {
{LLCC_CPUSS, 1, 5120, 1, 0, 0xFFFFFF, 0x0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_VIDSC0, 2, 512, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_AUDIO, 6, 1024, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_MDMHPGRW, 25, 1024, 4, 0, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_MODHW, 26, 1024, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_CMPT, 10, 4096, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_GPUHTW, 11, 512, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_GPU, 9, 3096, 1, 0, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_MMUHWT, 18, 768, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_DISP, 16, 6144, 1, 1, 0xFFFFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_MDMPNG, 27, 1024, 0, 1, 0xF00000, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_AUDHW, 22, 1024, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_CVP, 8, 256, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_MODPE, 29, 64, 1, 1, 0xF00000, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, },
{LLCC_WRCACHE, 31, 512, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_CAMEXP0, 4, 256, 4, 1, 0xF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_CPUHWT, 5, 512, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_CAMEXP1, 7, 3200, 3, 1, 0xFFFFF0, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_CMPTHCP, 17, 256, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_LCPDARE, 30, 128, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, },
{LLCC_AENPU, 3, 3072, 1, 1, 0xFE01FF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_ISLAND1, 12, 1792, 7, 1, 0xFE00, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_ISLAND4, 15, 256, 7, 1, 0x10000, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_CAMEXP2, 19, 3200, 3, 1, 0xFFFFF0, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_CAMEXP3, 20, 3200, 2, 1, 0xFFFFF0, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_CAMEXP4, 21, 3200, 2, 1, 0xFFFFF0, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_DISP_WB, 23, 1024, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_DISP_1, 24, 6144, 1, 1, 0xFFFFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{LLCC_VIDVSP, 28, 256, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
};
static const struct llcc_edac_reg_offset llcc_v1_edac_reg_offset = {
.trp_ecc_error_status0 = 0x20344,
.trp_ecc_error_status1 = 0x20348,
@ -443,6 +496,14 @@ static const struct qcom_llcc_config sm8450_cfg = {
.edac_reg_offset = &llcc_v2_1_edac_reg_offset,
};
static const struct qcom_llcc_config sm8550_cfg = {
.sct_data = sm8550_data,
.size = ARRAY_SIZE(sm8550_data),
.need_llcc_cfg = true,
.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;
/**
@ -497,6 +558,7 @@ static int llcc_update_act_ctrl(u32 sid,
u32 act_ctrl_reg_val, u32 status)
{
u32 act_ctrl_reg;
u32 act_clear_reg;
u32 status_reg;
u32 slice_status;
int ret;
@ -505,6 +567,7 @@ static int llcc_update_act_ctrl(u32 sid,
return PTR_ERR(drv_data);
act_ctrl_reg = LLCC_TRP_ACT_CTRLn(sid);
act_clear_reg = LLCC_TRP_ACT_CLEARn(sid);
status_reg = LLCC_TRP_STATUSn(sid);
/* Set the ACTIVE trigger */
@ -521,9 +584,22 @@ static int llcc_update_act_ctrl(u32 sid,
if (ret)
return ret;
if (drv_data->version >= LLCC_VERSION_4_1_0_0) {
ret = regmap_read_poll_timeout(drv_data->bcast_regmap, status_reg,
slice_status, (slice_status & ACT_COMPLETE),
0, LLCC_STATUS_READ_DELAY);
if (ret)
return ret;
}
ret = regmap_read_poll_timeout(drv_data->bcast_regmap, status_reg,
slice_status, !(slice_status & status),
0, LLCC_STATUS_READ_DELAY);
if (drv_data->version >= LLCC_VERSION_4_1_0_0)
ret = regmap_write(drv_data->bcast_regmap, act_clear_reg,
ACT_CLEAR);
return ret;
}
@ -636,8 +712,10 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
const struct qcom_llcc_config *cfg)
{
int ret;
u32 attr2_cfg;
u32 attr1_cfg;
u32 attr0_cfg;
u32 attr2_val;
u32 attr1_val;
u32 attr0_val;
u32 max_cap_cacheline;
@ -667,8 +745,14 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
if (ret)
return ret;
attr0_val = config->res_ways & ATTR0_RES_WAYS_MASK;
attr0_val |= config->bonus_ways << ATTR0_BONUS_WAYS_SHIFT;
if (drv_data->version >= LLCC_VERSION_4_1_0_0) {
attr2_cfg = LLCC_TRP_ATTR2_CFGn(config->slice_id);
attr0_val = config->res_ways;
attr2_val = config->bonus_ways;
} else {
attr0_val = config->res_ways & ATTR0_RES_WAYS_MASK;
attr0_val |= config->bonus_ways << ATTR0_BONUS_WAYS_SHIFT;
}
attr0_cfg = LLCC_TRP_ATTR0_CFGn(config->slice_id);
@ -676,6 +760,12 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
if (ret)
return ret;
if (drv_data->version >= LLCC_VERSION_4_1_0_0) {
ret = regmap_write(drv_data->bcast_regmap, attr2_cfg, attr2_val);
if (ret)
return ret;
}
if (cfg->need_llcc_cfg) {
u32 disable_cap_alloc, retain_pc;
@ -685,11 +775,13 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
if (ret)
return ret;
retain_pc = config->retain_on_pc << config->slice_id;
ret = regmap_write(drv_data->bcast_regmap,
LLCC_TRP_PCB_ACT, retain_pc);
if (ret)
return ret;
if (drv_data->version < LLCC_VERSION_4_1_0_0) {
retain_pc = config->retain_on_pc << config->slice_id;
ret = regmap_write(drv_data->bcast_regmap,
LLCC_TRP_PCB_ACT, retain_pc);
if (ret)
return ret;
}
}
if (drv_data->version >= LLCC_VERSION_2_0_0_0) {
@ -712,6 +804,65 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
return ret;
}
if (drv_data->version >= LLCC_VERSION_4_1_0_0) {
u32 stale_en;
u32 stale_cap_en;
u32 mru_uncap_en;
u32 mru_rollover;
u32 alloc_oneway_en;
u32 ovcap_en;
u32 ovcap_prio;
u32 vict_prio;
stale_en = config->stale_en << config->slice_id;
ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG1,
BIT(config->slice_id), stale_en);
if (ret)
return ret;
stale_cap_en = config->stale_cap_en << config->slice_id;
ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG2,
BIT(config->slice_id), stale_cap_en);
if (ret)
return ret;
mru_uncap_en = config->mru_uncap_en << config->slice_id;
ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG3,
BIT(config->slice_id), mru_uncap_en);
if (ret)
return ret;
mru_rollover = config->mru_rollover << config->slice_id;
ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG4,
BIT(config->slice_id), mru_rollover);
if (ret)
return ret;
alloc_oneway_en = config->alloc_oneway_en << config->slice_id;
ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG5,
BIT(config->slice_id), alloc_oneway_en);
if (ret)
return ret;
ovcap_en = config->ovcap_en << config->slice_id;
ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG6,
BIT(config->slice_id), ovcap_en);
if (ret)
return ret;
ovcap_prio = config->ovcap_prio << config->slice_id;
ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG7,
BIT(config->slice_id), ovcap_prio);
if (ret)
return ret;
vict_prio = config->vict_prio << config->slice_id;
ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG8,
BIT(config->slice_id), vict_prio);
if (ret)
return ret;
}
if (config->activate_on_init) {
desc.slice_id = config->slice_id;
ret = llcc_slice_activate(&desc);
@ -849,7 +1000,7 @@ static int qcom_llcc_probe(struct platform_device *pdev)
if (ret)
goto err;
drv_data->ecc_irq = platform_get_irq(pdev, 0);
drv_data->ecc_irq = platform_get_irq_optional(pdev, 0);
if (drv_data->ecc_irq >= 0) {
llcc_edac = platform_device_register_data(&pdev->dev,
"qcom_llcc_edac", -1, drv_data,
@ -875,6 +1026,7 @@ static const struct of_device_id qcom_llcc_of_match[] = {
{ .compatible = "qcom,sm8250-llcc", .data = &sm8250_cfg },
{ .compatible = "qcom,sm8350-llcc", .data = &sm8350_cfg },
{ .compatible = "qcom,sm8450-llcc", .data = &sm8450_cfg },
{ .compatible = "qcom,sm8550-llcc", .data = &sm8550_cfg },
{ }
};
MODULE_DEVICE_TABLE(of, qcom_llcc_of_match);

View file

@ -28,7 +28,7 @@ struct servreg_location_entry {
u32 instance;
};
static struct qmi_elem_info servreg_location_entry_ei[] = {
static const struct qmi_elem_info servreg_location_entry_ei[] = {
{
.data_type = QMI_STRING,
.elem_len = SERVREG_NAME_LENGTH + 1,
@ -74,7 +74,7 @@ struct servreg_get_domain_list_req {
u32 domain_offset;
};
static struct qmi_elem_info servreg_get_domain_list_req_ei[] = {
static const struct qmi_elem_info servreg_get_domain_list_req_ei[] = {
{
.data_type = QMI_STRING,
.elem_len = SERVREG_NAME_LENGTH + 1,
@ -116,7 +116,7 @@ struct servreg_get_domain_list_resp {
struct servreg_location_entry domain_list[SERVREG_DOMAIN_LIST_LENGTH];
};
static struct qmi_elem_info servreg_get_domain_list_resp_ei[] = {
static const struct qmi_elem_info servreg_get_domain_list_resp_ei[] = {
{
.data_type = QMI_STRUCT,
.elem_len = 1,
@ -199,7 +199,7 @@ struct servreg_register_listener_req {
char service_path[SERVREG_NAME_LENGTH + 1];
};
static struct qmi_elem_info servreg_register_listener_req_ei[] = {
static const struct qmi_elem_info servreg_register_listener_req_ei[] = {
{
.data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = 1,
@ -227,7 +227,7 @@ struct servreg_register_listener_resp {
enum servreg_service_state curr_state;
};
static struct qmi_elem_info servreg_register_listener_resp_ei[] = {
static const struct qmi_elem_info servreg_register_listener_resp_ei[] = {
{
.data_type = QMI_STRUCT,
.elem_len = 1,
@ -263,7 +263,7 @@ struct servreg_restart_pd_req {
char service_path[SERVREG_NAME_LENGTH + 1];
};
static struct qmi_elem_info servreg_restart_pd_req_ei[] = {
static const struct qmi_elem_info servreg_restart_pd_req_ei[] = {
{
.data_type = QMI_STRING,
.elem_len = SERVREG_NAME_LENGTH + 1,
@ -280,7 +280,7 @@ struct servreg_restart_pd_resp {
struct qmi_response_type_v01 resp;
};
static struct qmi_elem_info servreg_restart_pd_resp_ei[] = {
static const struct qmi_elem_info servreg_restart_pd_resp_ei[] = {
{
.data_type = QMI_STRUCT,
.elem_len = 1,
@ -300,7 +300,7 @@ struct servreg_state_updated_ind {
u16 transaction_id;
};
static struct qmi_elem_info servreg_state_updated_ind_ei[] = {
static const struct qmi_elem_info servreg_state_updated_ind_ei[] = {
{
.data_type = QMI_SIGNED_4_BYTE_ENUM,
.elem_len = 1,
@ -336,7 +336,7 @@ struct servreg_set_ack_req {
u16 transaction_id;
};
static struct qmi_elem_info servreg_set_ack_req_ei[] = {
static const struct qmi_elem_info servreg_set_ack_req_ei[] = {
{
.data_type = QMI_STRING,
.elem_len = SERVREG_NAME_LENGTH + 1,
@ -362,7 +362,7 @@ struct servreg_set_ack_resp {
struct qmi_response_type_v01 resp;
};
static struct qmi_elem_info servreg_set_ack_resp_ei[] = {
static const struct qmi_elem_info servreg_set_ack_resp_ei[] = {
{
.data_type = QMI_STRUCT,
.elem_len = 1,

View file

@ -217,6 +217,8 @@ static int qcom_stats_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, root);
device_set_pm_not_required(&pdev->dev);
return 0;
}

View file

@ -59,7 +59,6 @@ struct tcs_group {
* @cmd: the payload that will be part of the @msg
* @completion: triggered when request is done
* @dev: the device making the request
* @err: err return from the controller
* @needs_free: check to free dynamically allocated request object
*/
struct rpmh_request {
@ -67,7 +66,6 @@ struct rpmh_request {
struct tcs_cmd cmd[MAX_RPMH_PAYLOAD];
struct completion *completion;
const struct device *dev;
int err;
bool needs_free;
};
@ -86,18 +84,25 @@ struct rpmh_ctrlr {
struct list_head batch_cache;
};
struct rsc_ver {
u32 major;
u32 minor;
};
/**
* struct rsc_drv: the Direct Resource Voter (DRV) of the
* Resource State Coordinator controller (RSC)
*
* @name: Controller identifier.
* @base: Start address of the DRV registers in this controller.
* @tcs_base: Start address of the TCS registers in this controller.
* @id: Instance id in the controller (Direct Resource Voter).
* @num_tcs: Number of TCSes in this DRV.
* @rsc_pm: CPU PM notifier for controller.
* Used when solver mode is not present.
* @cpus_in_pm: Number of CPUs not in idle power collapse.
* Used when solver mode is not present.
* Used when solver mode and "power-domains" is not present.
* @genpd_nb: PM Domain notifier for cluster genpd notifications.
* @tcs: TCS groups.
* @tcs_in_use: S/W state of the TCS; only set for ACTIVE_ONLY
* transfers, but might show a sleep/wake TCS in use if
@ -110,27 +115,34 @@ struct rpmh_ctrlr {
* @tcs_wait: Wait queue used to wait for @tcs_in_use to free up a
* slot
* @client: Handle to the DRV's client.
* @dev: RSC device.
*/
struct rsc_drv {
const char *name;
void __iomem *base;
void __iomem *tcs_base;
int id;
int num_tcs;
struct notifier_block rsc_pm;
struct notifier_block genpd_nb;
atomic_t cpus_in_pm;
struct tcs_group tcs[TCS_TYPE_NR];
DECLARE_BITMAP(tcs_in_use, MAX_TCS_NR);
spinlock_t lock;
wait_queue_head_t tcs_wait;
struct rpmh_ctrlr client;
struct device *dev;
struct rsc_ver ver;
u32 *regs;
};
int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg);
int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv,
const struct tcs_request *msg);
void rpmh_rsc_invalidate(struct rsc_drv *drv);
void rpmh_rsc_write_next_wakeup(struct rsc_drv *drv);
void rpmh_tx_done(const struct tcs_request *msg, int r);
void rpmh_tx_done(const struct tcs_request *msg);
int rpmh_flush(struct rpmh_ctrlr *ctrlr);
#endif /* __RPM_INTERNAL_H__ */

View file

@ -12,16 +12,21 @@
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/ktime.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
#include <clocksource/arm_arch_timer.h>
#include <soc/qcom/cmd-db.h>
#include <soc/qcom/tcs.h>
#include <dt-bindings/soc/qcom,rpmh-rsc.h>
@ -31,49 +36,50 @@
#define CREATE_TRACE_POINTS
#include "trace-rpmh.h"
#define RSC_DRV_TCS_OFFSET 672
#define RSC_DRV_CMD_OFFSET 20
#define RSC_DRV_ID 0
#define MAJOR_VER_MASK 0xFF
#define MAJOR_VER_SHIFT 16
#define MINOR_VER_MASK 0xFF
#define MINOR_VER_SHIFT 8
enum {
RSC_DRV_TCS_OFFSET,
RSC_DRV_CMD_OFFSET,
DRV_SOLVER_CONFIG,
DRV_PRNT_CHLD_CONFIG,
RSC_DRV_IRQ_ENABLE,
RSC_DRV_IRQ_STATUS,
RSC_DRV_IRQ_CLEAR,
RSC_DRV_CMD_WAIT_FOR_CMPL,
RSC_DRV_CONTROL,
RSC_DRV_STATUS,
RSC_DRV_CMD_ENABLE,
RSC_DRV_CMD_MSGID,
RSC_DRV_CMD_ADDR,
RSC_DRV_CMD_DATA,
RSC_DRV_CMD_STATUS,
RSC_DRV_CMD_RESP_DATA,
};
/* DRV HW Solver Configuration Information Register */
#define DRV_SOLVER_CONFIG 0x04
#define DRV_HW_SOLVER_MASK 1
#define DRV_HW_SOLVER_SHIFT 24
/* DRV TCS Configuration Information Register */
#define DRV_PRNT_CHLD_CONFIG 0x0C
#define DRV_NUM_TCS_MASK 0x3F
#define DRV_NUM_TCS_SHIFT 6
#define DRV_NCPT_MASK 0x1F
#define DRV_NCPT_SHIFT 27
/* Offsets for common TCS Registers, one bit per TCS */
#define RSC_DRV_IRQ_ENABLE 0x00
#define RSC_DRV_IRQ_STATUS 0x04
#define RSC_DRV_IRQ_CLEAR 0x08 /* w/o; write 1 to clear */
/*
* Offsets for per TCS Registers.
*
* TCSes start at 0x10 from tcs_base and are stored one after another.
* Multiply tcs_id by RSC_DRV_TCS_OFFSET to find a given TCS and add one
* of the below to find a register.
*/
#define RSC_DRV_CMD_WAIT_FOR_CMPL 0x10 /* 1 bit per command */
#define RSC_DRV_CONTROL 0x14
#define RSC_DRV_STATUS 0x18 /* zero if tcs is busy */
#define RSC_DRV_CMD_ENABLE 0x1C /* 1 bit per command */
/*
* Offsets for per command in a TCS.
*
* Commands (up to 16) start at 0x30 in a TCS; multiply command index
* by RSC_DRV_CMD_OFFSET and add one of the below to find a register.
*/
#define RSC_DRV_CMD_MSGID 0x30
#define RSC_DRV_CMD_ADDR 0x34
#define RSC_DRV_CMD_DATA 0x38
#define RSC_DRV_CMD_STATUS 0x3C
#define RSC_DRV_CMD_RESP_DATA 0x40
/* Offsets for CONTROL TCS Registers */
#define RSC_DRV_CTL_TCS_DATA_HI 0x38
#define RSC_DRV_CTL_TCS_DATA_HI_MASK 0xFFFFFF
#define RSC_DRV_CTL_TCS_DATA_HI_VALID BIT(31)
#define RSC_DRV_CTL_TCS_DATA_LO 0x40
#define RSC_DRV_CTL_TCS_DATA_LO_MASK 0xFFFFFFFF
#define RSC_DRV_CTL_TCS_DATA_SIZE 32
#define TCS_AMC_MODE_ENABLE BIT(16)
#define TCS_AMC_MODE_TRIGGER BIT(24)
@ -139,16 +145,62 @@
* +---------------------------------------------------+
*/
#define USECS_TO_CYCLES(time_usecs) \
xloops_to_cycles((time_usecs) * 0x10C7UL)
static inline unsigned long xloops_to_cycles(u64 xloops)
{
return (xloops * loops_per_jiffy * HZ) >> 32;
}
static u32 rpmh_rsc_reg_offset_ver_2_7[] = {
[RSC_DRV_TCS_OFFSET] = 672,
[RSC_DRV_CMD_OFFSET] = 20,
[DRV_SOLVER_CONFIG] = 0x04,
[DRV_PRNT_CHLD_CONFIG] = 0x0C,
[RSC_DRV_IRQ_ENABLE] = 0x00,
[RSC_DRV_IRQ_STATUS] = 0x04,
[RSC_DRV_IRQ_CLEAR] = 0x08,
[RSC_DRV_CMD_WAIT_FOR_CMPL] = 0x10,
[RSC_DRV_CONTROL] = 0x14,
[RSC_DRV_STATUS] = 0x18,
[RSC_DRV_CMD_ENABLE] = 0x1C,
[RSC_DRV_CMD_MSGID] = 0x30,
[RSC_DRV_CMD_ADDR] = 0x34,
[RSC_DRV_CMD_DATA] = 0x38,
[RSC_DRV_CMD_STATUS] = 0x3C,
[RSC_DRV_CMD_RESP_DATA] = 0x40,
};
static u32 rpmh_rsc_reg_offset_ver_3_0[] = {
[RSC_DRV_TCS_OFFSET] = 672,
[RSC_DRV_CMD_OFFSET] = 24,
[DRV_SOLVER_CONFIG] = 0x04,
[DRV_PRNT_CHLD_CONFIG] = 0x0C,
[RSC_DRV_IRQ_ENABLE] = 0x00,
[RSC_DRV_IRQ_STATUS] = 0x04,
[RSC_DRV_IRQ_CLEAR] = 0x08,
[RSC_DRV_CMD_WAIT_FOR_CMPL] = 0x20,
[RSC_DRV_CONTROL] = 0x24,
[RSC_DRV_STATUS] = 0x28,
[RSC_DRV_CMD_ENABLE] = 0x2C,
[RSC_DRV_CMD_MSGID] = 0x34,
[RSC_DRV_CMD_ADDR] = 0x38,
[RSC_DRV_CMD_DATA] = 0x3C,
[RSC_DRV_CMD_STATUS] = 0x40,
[RSC_DRV_CMD_RESP_DATA] = 0x44,
};
static inline void __iomem *
tcs_reg_addr(const struct rsc_drv *drv, int reg, int tcs_id)
{
return drv->tcs_base + RSC_DRV_TCS_OFFSET * tcs_id + reg;
return drv->tcs_base + drv->regs[RSC_DRV_TCS_OFFSET] * tcs_id + reg;
}
static inline void __iomem *
tcs_cmd_addr(const struct rsc_drv *drv, int reg, int tcs_id, int cmd_id)
{
return tcs_reg_addr(drv, reg, tcs_id) + RSC_DRV_CMD_OFFSET * cmd_id;
return tcs_reg_addr(drv, reg, tcs_id) + drv->regs[RSC_DRV_CMD_OFFSET] * cmd_id;
}
static u32 read_tcs_cmd(const struct rsc_drv *drv, int reg, int tcs_id,
@ -216,7 +268,7 @@ static void tcs_invalidate(struct rsc_drv *drv, int type)
return;
for (m = tcs->offset; m < tcs->offset + tcs->num_tcs; m++)
write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, m, 0);
write_tcs_reg_sync(drv, drv->regs[RSC_DRV_CMD_ENABLE], m, 0);
bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
}
@ -330,24 +382,25 @@ static const struct tcs_request *get_req_from_tcs(struct rsc_drv *drv,
static void __tcs_set_trigger(struct rsc_drv *drv, int tcs_id, bool trigger)
{
u32 enable;
u32 reg = drv->regs[RSC_DRV_CONTROL];
/*
* HW req: Clear the DRV_CONTROL and enable TCS again
* While clearing ensure that the AMC mode trigger is cleared
* and then the mode enable is cleared.
*/
enable = read_tcs_reg(drv, RSC_DRV_CONTROL, tcs_id);
enable = read_tcs_reg(drv, reg, tcs_id);
enable &= ~TCS_AMC_MODE_TRIGGER;
write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
write_tcs_reg_sync(drv, reg, tcs_id, enable);
enable &= ~TCS_AMC_MODE_ENABLE;
write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
write_tcs_reg_sync(drv, reg, tcs_id, enable);
if (trigger) {
/* Enable the AMC mode on the TCS and then trigger the TCS */
enable = TCS_AMC_MODE_ENABLE;
write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
write_tcs_reg_sync(drv, reg, tcs_id, enable);
enable |= TCS_AMC_MODE_TRIGGER;
write_tcs_reg(drv, RSC_DRV_CONTROL, tcs_id, enable);
write_tcs_reg(drv, reg, tcs_id, enable);
}
}
@ -363,13 +416,14 @@ static void __tcs_set_trigger(struct rsc_drv *drv, int tcs_id, bool trigger)
static void enable_tcs_irq(struct rsc_drv *drv, int tcs_id, bool enable)
{
u32 data;
u32 reg = drv->regs[RSC_DRV_IRQ_ENABLE];
data = readl_relaxed(drv->tcs_base + RSC_DRV_IRQ_ENABLE);
data = readl_relaxed(drv->tcs_base + reg);
if (enable)
data |= BIT(tcs_id);
else
data &= ~BIT(tcs_id);
writel_relaxed(data, drv->tcs_base + RSC_DRV_IRQ_ENABLE);
writel_relaxed(data, drv->tcs_base + reg);
}
/**
@ -385,34 +439,18 @@ static void enable_tcs_irq(struct rsc_drv *drv, int tcs_id, bool enable)
static irqreturn_t tcs_tx_done(int irq, void *p)
{
struct rsc_drv *drv = p;
int i, j, err = 0;
int i;
unsigned long irq_status;
const struct tcs_request *req;
struct tcs_cmd *cmd;
irq_status = readl_relaxed(drv->tcs_base + RSC_DRV_IRQ_STATUS);
irq_status = readl_relaxed(drv->tcs_base + drv->regs[RSC_DRV_IRQ_STATUS]);
for_each_set_bit(i, &irq_status, BITS_PER_TYPE(u32)) {
req = get_req_from_tcs(drv, i);
if (WARN_ON(!req))
goto skip;
err = 0;
for (j = 0; j < req->num_cmds; j++) {
u32 sts;
cmd = &req->cmds[j];
sts = read_tcs_cmd(drv, RSC_DRV_CMD_STATUS, i, j);
if (!(sts & CMD_STATUS_ISSUED) ||
((req->wait_for_compl || cmd->wait) &&
!(sts & CMD_STATUS_COMPL))) {
pr_err("Incomplete request: %s: addr=%#x data=%#x",
drv->name, cmd->addr, cmd->data);
err = -EIO;
}
}
trace_rpmh_tx_done(drv, i, req, err);
trace_rpmh_tx_done(drv, i, req);
/*
* If wake tcs was re-purposed for sending active
@ -423,8 +461,8 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
__tcs_set_trigger(drv, i, false);
skip:
/* Reclaim the TCS */
write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i, 0);
writel_relaxed(BIT(i), drv->tcs_base + RSC_DRV_IRQ_CLEAR);
write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], i, 0);
writel_relaxed(BIT(i), drv->tcs_base + drv->regs[RSC_DRV_IRQ_CLEAR]);
spin_lock(&drv->lock);
clear_bit(i, drv->tcs_in_use);
/*
@ -437,7 +475,7 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
spin_unlock(&drv->lock);
wake_up(&drv->tcs_wait);
if (req)
rpmh_tx_done(req, err);
rpmh_tx_done(req);
}
return IRQ_HANDLED;
@ -475,14 +513,14 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id,
*/
msgid |= cmd->wait ? CMD_MSGID_RESP_REQ : 0;
write_tcs_cmd(drv, RSC_DRV_CMD_MSGID, tcs_id, j, msgid);
write_tcs_cmd(drv, RSC_DRV_CMD_ADDR, tcs_id, j, cmd->addr);
write_tcs_cmd(drv, RSC_DRV_CMD_DATA, tcs_id, j, cmd->data);
write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_MSGID], tcs_id, j, msgid);
write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], tcs_id, j, cmd->addr);
write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_DATA], tcs_id, j, cmd->data);
trace_rpmh_send_msg(drv, tcs_id, j, msgid, cmd);
}
cmd_enable |= read_tcs_reg(drv, RSC_DRV_CMD_ENABLE, tcs_id);
write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, tcs_id, cmd_enable);
cmd_enable |= read_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id);
write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, cmd_enable);
}
/**
@ -514,10 +552,10 @@ static int check_for_req_inflight(struct rsc_drv *drv, struct tcs_group *tcs,
int i = tcs->offset;
for_each_set_bit_from(i, drv->tcs_in_use, tcs->offset + tcs->num_tcs) {
curr_enabled = read_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i);
curr_enabled = read_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], i);
for_each_set_bit(j, &curr_enabled, MAX_CMDS_PER_TCS) {
addr = read_tcs_cmd(drv, RSC_DRV_CMD_ADDR, i, j);
addr = read_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], i, j);
for (k = 0; k < msg->num_cmds; k++) {
if (addr == msg->cmds[k].addr)
return -EBUSY;
@ -628,7 +666,7 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
* repurposed TCS to avoid triggering them. tcs->slots will be
* cleaned from rpmh_flush() by invoking rpmh_rsc_invalidate()
*/
write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, tcs_id, 0);
write_tcs_reg_sync(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, 0);
enable_tcs_irq(drv, tcs_id, true);
}
spin_unlock_irqrestore(&drv->lock, flags);
@ -753,6 +791,48 @@ static bool rpmh_rsc_ctrlr_is_busy(struct rsc_drv *drv)
return set < max;
}
/**
* rpmh_rsc_write_next_wakeup() - Write next wakeup in CONTROL_TCS.
* @drv: The controller
*
* Writes maximum wakeup cycles when called from suspend.
* Writes earliest hrtimer wakeup when called from idle.
*/
void rpmh_rsc_write_next_wakeup(struct rsc_drv *drv)
{
ktime_t now, wakeup;
u64 wakeup_us, wakeup_cycles = ~0;
u32 lo, hi;
if (!drv->tcs[CONTROL_TCS].num_tcs || !drv->genpd_nb.notifier_call)
return;
/* Set highest time when system (timekeeping) is suspended */
if (system_state == SYSTEM_SUSPEND)
goto exit;
/* Find the earliest hrtimer wakeup from online cpus */
wakeup = dev_pm_genpd_get_next_hrtimer(drv->dev);
/* Find the relative wakeup in kernel time scale */
now = ktime_get();
wakeup = ktime_sub(wakeup, now);
wakeup_us = ktime_to_us(wakeup);
/* Convert the wakeup to arch timer scale */
wakeup_cycles = USECS_TO_CYCLES(wakeup_us);
wakeup_cycles += arch_timer_read_counter();
exit:
lo = wakeup_cycles & RSC_DRV_CTL_TCS_DATA_LO_MASK;
hi = wakeup_cycles >> RSC_DRV_CTL_TCS_DATA_SIZE;
hi &= RSC_DRV_CTL_TCS_DATA_HI_MASK;
hi |= RSC_DRV_CTL_TCS_DATA_HI_VALID;
writel_relaxed(lo, drv->base + RSC_DRV_CTL_TCS_DATA_LO);
writel_relaxed(hi, drv->base + RSC_DRV_CTL_TCS_DATA_HI);
}
/**
* rpmh_rsc_cpu_pm_callback() - Check if any of the AMCs are busy.
* @nfb: Pointer to the notifier block in struct rsc_drv.
@ -834,8 +914,51 @@ static int rpmh_rsc_cpu_pm_callback(struct notifier_block *nfb,
return ret;
}
static int rpmh_probe_tcs_config(struct platform_device *pdev,
struct rsc_drv *drv, void __iomem *base)
/**
* rpmh_rsc_pd_callback() - Check if any of the AMCs are busy.
* @nfb: Pointer to the genpd notifier block in struct rsc_drv.
* @action: GENPD_NOTIFY_PRE_OFF, GENPD_NOTIFY_OFF, GENPD_NOTIFY_PRE_ON or GENPD_NOTIFY_ON.
* @v: Unused
*
* This function is given to dev_pm_genpd_add_notifier() so we can be informed
* about when cluster-pd is going down. When cluster go down we know no more active
* transfers will be started so we write sleep/wake sets. This function gets
* called from cpuidle code paths and also at system suspend time.
*
* If AMCs are not busy then writes cached sleep and wake messages to TCSes.
* The firmware then takes care of triggering them when entering deepest low power modes.
*
* Return:
* * NOTIFY_OK - success
* * NOTIFY_BAD - failure
*/
static int rpmh_rsc_pd_callback(struct notifier_block *nfb,
unsigned long action, void *v)
{
struct rsc_drv *drv = container_of(nfb, struct rsc_drv, genpd_nb);
/* We don't need to lock as genpd on/off are serialized */
if ((action == GENPD_NOTIFY_PRE_OFF) &&
(rpmh_rsc_ctrlr_is_busy(drv) || rpmh_flush(&drv->client)))
return NOTIFY_BAD;
return NOTIFY_OK;
}
static int rpmh_rsc_pd_attach(struct rsc_drv *drv, struct device *dev)
{
int ret;
pm_runtime_enable(dev);
drv->genpd_nb.notifier_call = rpmh_rsc_pd_callback;
ret = dev_pm_genpd_add_notifier(dev, &drv->genpd_nb);
if (ret)
pm_runtime_disable(dev);
return ret;
}
static int rpmh_probe_tcs_config(struct platform_device *pdev, struct rsc_drv *drv)
{
struct tcs_type_config {
u32 type;
@ -849,9 +972,9 @@ static int rpmh_probe_tcs_config(struct platform_device *pdev,
ret = of_property_read_u32(dn, "qcom,tcs-offset", &offset);
if (ret)
return ret;
drv->tcs_base = base + offset;
drv->tcs_base = drv->base + offset;
config = readl_relaxed(base + DRV_PRNT_CHLD_CONFIG);
config = readl_relaxed(drv->base + drv->regs[DRV_PRNT_CHLD_CONFIG]);
max_tcs = config;
max_tcs &= DRV_NUM_TCS_MASK << (DRV_NUM_TCS_SHIFT * drv->id);
@ -913,7 +1036,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
char drv_id[10] = {0};
int ret, irq;
u32 solver_config;
void __iomem *base;
u32 rsc_id;
/*
* Even though RPMh doesn't directly use cmd-db, all of its children
@ -940,11 +1063,22 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
drv->name = dev_name(&pdev->dev);
snprintf(drv_id, ARRAY_SIZE(drv_id), "drv-%d", drv->id);
base = devm_platform_ioremap_resource_byname(pdev, drv_id);
if (IS_ERR(base))
return PTR_ERR(base);
drv->base = devm_platform_ioremap_resource_byname(pdev, drv_id);
if (IS_ERR(drv->base))
return PTR_ERR(drv->base);
ret = rpmh_probe_tcs_config(pdev, drv, base);
rsc_id = readl_relaxed(drv->base + RSC_DRV_ID);
drv->ver.major = rsc_id & (MAJOR_VER_MASK << MAJOR_VER_SHIFT);
drv->ver.major >>= MAJOR_VER_SHIFT;
drv->ver.minor = rsc_id & (MINOR_VER_MASK << MINOR_VER_SHIFT);
drv->ver.minor >>= MINOR_VER_SHIFT;
if (drv->ver.major == 3 && drv->ver.minor == 0)
drv->regs = rpmh_rsc_reg_offset_ver_3_0;
else
drv->regs = rpmh_rsc_reg_offset_ver_2_7;
ret = rpmh_probe_tcs_config(pdev, drv);
if (ret)
return ret;
@ -963,29 +1097,42 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
return ret;
/*
* CPU PM notification are not required for controllers that support
* CPU PM/genpd notification are not required for controllers that support
* 'HW solver' mode where they can be in autonomous mode executing low
* power mode to power down.
*/
solver_config = readl_relaxed(base + DRV_SOLVER_CONFIG);
solver_config = readl_relaxed(drv->base + drv->regs[DRV_SOLVER_CONFIG]);
solver_config &= DRV_HW_SOLVER_MASK << DRV_HW_SOLVER_SHIFT;
solver_config = solver_config >> DRV_HW_SOLVER_SHIFT;
if (!solver_config) {
drv->rsc_pm.notifier_call = rpmh_rsc_cpu_pm_callback;
cpu_pm_register_notifier(&drv->rsc_pm);
if (pdev->dev.pm_domain) {
ret = rpmh_rsc_pd_attach(drv, &pdev->dev);
if (ret)
return ret;
} else {
drv->rsc_pm.notifier_call = rpmh_rsc_cpu_pm_callback;
cpu_pm_register_notifier(&drv->rsc_pm);
}
}
/* Enable the active TCS to send requests immediately */
writel_relaxed(drv->tcs[ACTIVE_TCS].mask,
drv->tcs_base + RSC_DRV_IRQ_ENABLE);
drv->tcs_base + drv->regs[RSC_DRV_IRQ_ENABLE]);
spin_lock_init(&drv->client.cache_lock);
INIT_LIST_HEAD(&drv->client.cache);
INIT_LIST_HEAD(&drv->client.batch_cache);
dev_set_drvdata(&pdev->dev, drv);
drv->dev = &pdev->dev;
return devm_of_platform_populate(&pdev->dev);
ret = devm_of_platform_populate(&pdev->dev);
if (ret && pdev->dev.pm_domain) {
dev_pm_genpd_remove_notifier(&pdev->dev);
pm_runtime_disable(&pdev->dev);
}
return ret;
}
static const struct of_device_id rpmh_drv_match[] = {

View file

@ -76,19 +76,13 @@ static struct rpmh_ctrlr *get_rpmh_ctrlr(const struct device *dev)
return &drv->client;
}
void rpmh_tx_done(const struct tcs_request *msg, int r)
void rpmh_tx_done(const struct tcs_request *msg)
{
struct rpmh_request *rpm_msg = container_of(msg, struct rpmh_request,
msg);
struct completion *compl = rpm_msg->completion;
bool free = rpm_msg->needs_free;
rpm_msg->err = r;
if (r)
dev_err(rpm_msg->dev, "RPMH TX fail in msg addr=%#x, err=%d\n",
rpm_msg->msg.cmds[0].addr, r);
if (!compl)
goto exit;
@ -194,7 +188,7 @@ static int __rpmh_write(const struct device *dev, enum rpmh_state state,
} else {
/* Clean up our call by spoofing tx_done */
ret = 0;
rpmh_tx_done(&rpm_msg->msg, ret);
rpmh_tx_done(&rpm_msg->msg);
}
return ret;
@ -450,7 +444,7 @@ int rpmh_flush(struct rpmh_ctrlr *ctrlr)
if (!ctrlr->dirty) {
pr_debug("Skipping flush, TCS has latest data.\n");
goto exit;
goto write_next_wakeup;
}
/* Invalidate the TCSes first to avoid stale data */
@ -479,6 +473,8 @@ int rpmh_flush(struct rpmh_ctrlr *ctrlr)
ctrlr->dirty = false;
write_next_wakeup:
rpmh_rsc_write_next_wakeup(ctrlr_to_drv(ctrlr));
exit:
spin_unlock(&ctrlr->cache_lock);
return ret;

View file

@ -39,6 +39,7 @@
* @res_name: Resource name used for cmd-db lookup
* @addr: Resource address as looped up using resource name from
* cmd-db
* @state_synced: Indicator that sync_state has been invoked for the rpmhpd resource
*/
struct rpmhpd {
struct device *dev;
@ -54,6 +55,7 @@ struct rpmhpd {
bool enabled;
const char *res_name;
u32 addr;
bool state_synced;
};
struct rpmhpd_desc {
@ -210,6 +212,23 @@ static const struct rpmhpd_desc sa8540p_desc = {
.num_pds = ARRAY_SIZE(sa8540p_rpmhpds),
};
/* SDM670 RPMH powerdomains */
static struct rpmhpd *sdm670_rpmhpds[] = {
[SDM670_CX] = &cx_w_mx_parent,
[SDM670_CX_AO] = &cx_ao_w_mx_parent,
[SDM670_GFX] = &gfx,
[SDM670_LCX] = &lcx,
[SDM670_LMX] = &lmx,
[SDM670_MSS] = &mss,
[SDM670_MX] = &mx,
[SDM670_MX_AO] = &mx_ao,
};
static const struct rpmhpd_desc sdm670_desc = {
.rpmhpds = sdm670_rpmhpds,
.num_pds = ARRAY_SIZE(sdm670_rpmhpds),
};
/* SDM845 RPMH powerdomains */
static struct rpmhpd *sdm845_rpmhpds[] = {
[SDM845_CX] = &cx_w_mx_parent,
@ -353,6 +372,42 @@ static const struct rpmhpd_desc sm8450_desc = {
.num_pds = ARRAY_SIZE(sm8450_rpmhpds),
};
/* SM8550 RPMH powerdomains */
static struct rpmhpd *sm8550_rpmhpds[] = {
[SM8550_CX] = &cx,
[SM8550_CX_AO] = &cx_ao,
[SM8550_EBI] = &ebi,
[SM8550_GFX] = &gfx,
[SM8550_LCX] = &lcx,
[SM8550_LMX] = &lmx,
[SM8550_MMCX] = &mmcx_w_cx_parent,
[SM8550_MMCX_AO] = &mmcx_ao_w_cx_parent,
[SM8550_MSS] = &mss,
[SM8550_MX] = &mx,
[SM8550_MX_AO] = &mx_ao,
[SM8550_MXC] = &mxc,
[SM8550_MXC_AO] = &mxc_ao,
[SM8550_NSP] = &nsp,
};
static const struct rpmhpd_desc sm8550_desc = {
.rpmhpds = sm8550_rpmhpds,
.num_pds = ARRAY_SIZE(sm8550_rpmhpds),
};
/* QDU1000/QRU1000 RPMH powerdomains */
static struct rpmhpd *qdu1000_rpmhpds[] = {
[QDU1000_CX] = &cx,
[QDU1000_EBI] = &ebi,
[QDU1000_MSS] = &mss,
[QDU1000_MX] = &mx,
};
static const struct rpmhpd_desc qdu1000_desc = {
.rpmhpds = qdu1000_rpmhpds,
.num_pds = ARRAY_SIZE(qdu1000_rpmhpds),
};
/* SC7180 RPMH powerdomains */
static struct rpmhpd *sc7180_rpmhpds[] = {
[SC7180_CX] = &cx_w_mx_parent,
@ -430,11 +485,13 @@ static const struct rpmhpd_desc sc8280xp_desc = {
};
static const struct of_device_id rpmhpd_match_table[] = {
{ .compatible = "qcom,qdu1000-rpmhpd", .data = &qdu1000_desc },
{ .compatible = "qcom,sa8540p-rpmhpd", .data = &sa8540p_desc },
{ .compatible = "qcom,sc7180-rpmhpd", .data = &sc7180_desc },
{ .compatible = "qcom,sc7280-rpmhpd", .data = &sc7280_desc },
{ .compatible = "qcom,sc8180x-rpmhpd", .data = &sc8180x_desc },
{ .compatible = "qcom,sc8280xp-rpmhpd", .data = &sc8280xp_desc },
{ .compatible = "qcom,sdm670-rpmhpd", .data = &sdm670_desc },
{ .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc },
{ .compatible = "qcom,sdx55-rpmhpd", .data = &sdx55_desc},
{ .compatible = "qcom,sdx65-rpmhpd", .data = &sdx65_desc},
@ -443,6 +500,7 @@ static const struct of_device_id rpmhpd_match_table[] = {
{ .compatible = "qcom,sm8250-rpmhpd", .data = &sm8250_desc },
{ .compatible = "qcom,sm8350-rpmhpd", .data = &sm8350_desc },
{ .compatible = "qcom,sm8450-rpmhpd", .data = &sm8450_desc },
{ .compatible = "qcom,sm8550-rpmhpd", .data = &sm8550_desc },
{ }
};
MODULE_DEVICE_TABLE(of, rpmhpd_match_table);
@ -493,7 +551,13 @@ static int rpmhpd_aggregate_corner(struct rpmhpd *pd, unsigned int corner)
unsigned int this_active_corner = 0, this_sleep_corner = 0;
unsigned int peer_active_corner = 0, peer_sleep_corner = 0;
to_active_sleep(pd, corner, &this_active_corner, &this_sleep_corner);
if (pd->state_synced) {
to_active_sleep(pd, corner, &this_active_corner, &this_sleep_corner);
} else {
/* Clamp to highest corner if sync_state hasn't happened */
this_active_corner = pd->level_count - 1;
this_sleep_corner = pd->level_count - 1;
}
if (peer && peer->enabled)
to_active_sleep(peer, peer->corner, &peer_active_corner,
@ -708,11 +772,40 @@ static int rpmhpd_probe(struct platform_device *pdev)
return of_genpd_add_provider_onecell(pdev->dev.of_node, data);
}
static void rpmhpd_sync_state(struct device *dev)
{
const struct rpmhpd_desc *desc = of_device_get_match_data(dev);
struct rpmhpd **rpmhpds = desc->rpmhpds;
unsigned int corner;
struct rpmhpd *pd;
unsigned int i;
int ret;
mutex_lock(&rpmhpd_lock);
for (i = 0; i < desc->num_pds; i++) {
pd = rpmhpds[i];
if (!pd)
continue;
pd->state_synced = true;
if (pd->enabled)
corner = max(pd->corner, pd->enable_corner);
else
corner = 0;
ret = rpmhpd_aggregate_corner(pd, corner);
if (ret)
dev_err(dev, "failed to sync %s\n", pd->res_name);
}
mutex_unlock(&rpmhpd_lock);
}
static struct platform_driver rpmhpd_driver = {
.driver = {
.name = "qcom-rpmhpd",
.of_match_table = rpmhpd_match_table,
.suppress_bind_attrs = true,
.sync_state = rpmhpd_sync_state,
},
.probe = rpmhpd_probe,
};

View file

@ -471,6 +471,23 @@ static const struct rpmpd_desc qcm2290_desc = {
.max_state = RPM_SMD_LEVEL_TURBO_NO_CPR,
};
static struct rpmpd *sm4250_rpmpds[] = {
[SM4250_VDDCX] = &sm6115_vddcx,
[SM4250_VDDCX_AO] = &sm6115_vddcx_ao,
[SM4250_VDDCX_VFL] = &sm6115_vddcx_vfl,
[SM4250_VDDMX] = &sm6115_vddmx,
[SM4250_VDDMX_AO] = &sm6115_vddmx_ao,
[SM4250_VDDMX_VFL] = &sm6115_vddmx_vfl,
[SM4250_VDD_LPI_CX] = &sm6115_vdd_lpi_cx,
[SM4250_VDD_LPI_MX] = &sm6115_vdd_lpi_mx,
};
static const struct rpmpd_desc sm4250_desc = {
.rpmpds = sm4250_rpmpds,
.num_pds = ARRAY_SIZE(sm4250_rpmpds),
.max_state = RPM_SMD_LEVEL_TURBO_NO_CPR,
};
static const struct of_device_id rpmpd_match_table[] = {
{ .compatible = "qcom,mdm9607-rpmpd", .data = &mdm9607_desc },
{ .compatible = "qcom,msm8226-rpmpd", .data = &msm8226_desc },
@ -485,6 +502,7 @@ static const struct of_device_id rpmpd_match_table[] = {
{ .compatible = "qcom,qcm2290-rpmpd", .data = &qcm2290_desc },
{ .compatible = "qcom,qcs404-rpmpd", .data = &qcs404_desc },
{ .compatible = "qcom,sdm660-rpmpd", .data = &sdm660_desc },
{ .compatible = "qcom,sm4250-rpmpd", .data = &sm4250_desc },
{ .compatible = "qcom,sm6115-rpmpd", .data = &sm6115_desc },
{ .compatible = "qcom,sm6125-rpmpd", .data = &sm6125_desc },
{ .compatible = "qcom,sm6375-rpmpd", .data = &sm6375_desc },

View file

@ -75,7 +75,7 @@ struct qcom_rpm_message {
__le32 length;
union {
__le32 msg_id;
u8 message[0];
DECLARE_FLEX_ARRAY(u8, message);
};
};
@ -246,6 +246,7 @@ static const struct of_device_id qcom_smd_rpm_of_match[] = {
{ .compatible = "qcom,rpm-sdm660" },
{ .compatible = "qcom,rpm-sm6115" },
{ .compatible = "qcom,rpm-sm6125" },
{ .compatible = "qcom,rpm-sm6375" },
{ .compatible = "qcom,rpm-qcm2290" },
{ .compatible = "qcom,rpm-qcs404" },
{}

View file

@ -422,7 +422,7 @@ static int qcom_smp2p_outbound_entry(struct qcom_smp2p *smp2p,
char buf[SMP2P_MAX_ENTRY_NAME] = {};
/* Allocate an entry from the smem item */
strlcpy(buf, entry->name, SMP2P_MAX_ENTRY_NAME);
strscpy(buf, entry->name, SMP2P_MAX_ENTRY_NAME);
memcpy(out->entries[out->valid_entries].name, buf, SMP2P_MAX_ENTRY_NAME);
/* Make the logical entry reference the physical value */

View file

@ -12,11 +12,14 @@
#include <linux/slab.h>
#include <linux/soc/qcom/smem.h>
#include <linux/string.h>
#include <linux/stringify.h>
#include <linux/sys_soc.h>
#include <linux/types.h>
#include <asm/unaligned.h>
#include <dt-bindings/arm/qcom,ids.h>
/*
* SoC version type with major number in the upper 16 bits and minor
* number in the lower 16 bits.
@ -25,6 +28,10 @@
#define SOCINFO_MINOR(ver) ((ver) & 0xffff)
#define SOCINFO_VERSION(maj, min) ((((maj) & 0xffff) << 16)|((min) & 0xffff))
/* Helper macros to create soc_id table */
#define qcom_board_id(id) QCOM_ID_ ## id, __stringify(id)
#define qcom_board_id_named(id, name) QCOM_ID_ ## id, (name)
#define SMEM_SOCINFO_BUILD_ID_LENGTH 32
#define SMEM_SOCINFO_CHIP_ID_LENGTH 32
@ -207,135 +214,150 @@ struct soc_id {
};
static const struct soc_id soc_id[] = {
{ 87, "MSM8960" },
{ 109, "APQ8064" },
{ 122, "MSM8660A" },
{ 123, "MSM8260A" },
{ 124, "APQ8060A" },
{ 126, "MSM8974" },
{ 130, "MPQ8064" },
{ 138, "MSM8960AB" },
{ 139, "APQ8060AB" },
{ 140, "MSM8260AB" },
{ 141, "MSM8660AB" },
{ 145, "MSM8626" },
{ 147, "MSM8610" },
{ 153, "APQ8064AB" },
{ 158, "MSM8226" },
{ 159, "MSM8526" },
{ 161, "MSM8110" },
{ 162, "MSM8210" },
{ 163, "MSM8810" },
{ 164, "MSM8212" },
{ 165, "MSM8612" },
{ 166, "MSM8112" },
{ 168, "MSM8225Q" },
{ 169, "MSM8625Q" },
{ 170, "MSM8125Q" },
{ 172, "APQ8064AA" },
{ 178, "APQ8084" },
{ 184, "APQ8074" },
{ 185, "MSM8274" },
{ 186, "MSM8674" },
{ 194, "MSM8974PRO-AC" },
{ 198, "MSM8126" },
{ 199, "APQ8026" },
{ 200, "MSM8926" },
{ 205, "MSM8326" },
{ 206, "MSM8916" },
{ 207, "MSM8994" },
{ 208, "APQ8074PRO-AA" },
{ 209, "APQ8074PRO-AB" },
{ 210, "APQ8074PRO-AC" },
{ 211, "MSM8274PRO-AA" },
{ 212, "MSM8274PRO-AB" },
{ 213, "MSM8274PRO-AC" },
{ 214, "MSM8674PRO-AA" },
{ 215, "MSM8674PRO-AB" },
{ 216, "MSM8674PRO-AC" },
{ 217, "MSM8974PRO-AA" },
{ 218, "MSM8974PRO-AB" },
{ 219, "APQ8028" },
{ 220, "MSM8128" },
{ 221, "MSM8228" },
{ 222, "MSM8528" },
{ 223, "MSM8628" },
{ 224, "MSM8928" },
{ 225, "MSM8510" },
{ 226, "MSM8512" },
{ 233, "MSM8936" },
{ 239, "MSM8939" },
{ 240, "APQ8036" },
{ 241, "APQ8039" },
{ 246, "MSM8996" },
{ 247, "APQ8016" },
{ 248, "MSM8216" },
{ 249, "MSM8116" },
{ 250, "MSM8616" },
{ 251, "MSM8992" },
{ 253, "APQ8094" },
{ 290, "MDM9607" },
{ 291, "APQ8096" },
{ 292, "MSM8998" },
{ 293, "MSM8953" },
{ 296, "MDM8207" },
{ 297, "MDM9207" },
{ 298, "MDM9307" },
{ 299, "MDM9628" },
{ 304, "APQ8053" },
{ 305, "MSM8996SG" },
{ 310, "MSM8996AU" },
{ 311, "APQ8096AU" },
{ 312, "APQ8096SG" },
{ 317, "SDM660" },
{ 318, "SDM630" },
{ 319, "APQ8098" },
{ 321, "SDM845" },
{ 322, "MDM9206" },
{ 323, "IPQ8074" },
{ 324, "SDA660" },
{ 325, "SDM658" },
{ 326, "SDA658" },
{ 327, "SDA630" },
{ 338, "SDM450" },
{ 341, "SDA845" },
{ 342, "IPQ8072" },
{ 343, "IPQ8076" },
{ 344, "IPQ8078" },
{ 345, "SDM636" },
{ 346, "SDA636" },
{ 349, "SDM632" },
{ 350, "SDA632" },
{ 351, "SDA450" },
{ 356, "SM8250" },
{ 375, "IPQ8070" },
{ 376, "IPQ8071" },
{ 389, "IPQ8072A" },
{ 390, "IPQ8074A" },
{ 391, "IPQ8076A" },
{ 392, "IPQ8078A" },
{ 394, "SM6125" },
{ 395, "IPQ8070A" },
{ 396, "IPQ8071A" },
{ 402, "IPQ6018" },
{ 403, "IPQ6028" },
{ 421, "IPQ6000" },
{ 422, "IPQ6010" },
{ 425, "SC7180" },
{ 434, "SM6350" },
{ 439, "SM8350" },
{ 449, "SC8280XP" },
{ 453, "IPQ6005" },
{ 455, "QRB5165" },
{ 457, "SM8450" },
{ 459, "SM7225" },
{ 460, "SA8295P" },
{ 461, "SA8540P" },
{ 480, "SM8450" },
{ 482, "SM8450" },
{ 487, "SC7280" },
{ 495, "SC7180P" },
{ 507, "SM6375" },
{ qcom_board_id(MSM8960) },
{ qcom_board_id(APQ8064) },
{ qcom_board_id(MSM8660A) },
{ qcom_board_id(MSM8260A) },
{ qcom_board_id(APQ8060A) },
{ qcom_board_id(MSM8974) },
{ qcom_board_id(MPQ8064) },
{ qcom_board_id(MSM8960AB) },
{ qcom_board_id(APQ8060AB) },
{ qcom_board_id(MSM8260AB) },
{ qcom_board_id(MSM8660AB) },
{ qcom_board_id(MSM8626) },
{ qcom_board_id(MSM8610) },
{ qcom_board_id(APQ8064AB) },
{ qcom_board_id(MSM8226) },
{ qcom_board_id(MSM8526) },
{ qcom_board_id(MSM8110) },
{ qcom_board_id(MSM8210) },
{ qcom_board_id(MSM8810) },
{ qcom_board_id(MSM8212) },
{ qcom_board_id(MSM8612) },
{ qcom_board_id(MSM8112) },
{ qcom_board_id(MSM8225Q) },
{ qcom_board_id(MSM8625Q) },
{ qcom_board_id(MSM8125Q) },
{ qcom_board_id(APQ8064AA) },
{ qcom_board_id(APQ8084) },
{ qcom_board_id(APQ8074) },
{ qcom_board_id(MSM8274) },
{ qcom_board_id(MSM8674) },
{ qcom_board_id_named(MSM8974PRO_AC, "MSM8974PRO-AC") },
{ qcom_board_id(MSM8126) },
{ qcom_board_id(APQ8026) },
{ qcom_board_id(MSM8926) },
{ qcom_board_id(MSM8326) },
{ qcom_board_id(MSM8916) },
{ qcom_board_id(MSM8956) },
{ qcom_board_id(MSM8976) },
{ qcom_board_id(MSM8994) },
{ qcom_board_id_named(APQ8074PRO_AA, "APQ8074PRO-AA") },
{ qcom_board_id_named(APQ8074PRO_AB, "APQ8074PRO-AB") },
{ qcom_board_id_named(APQ8074PRO_AC, "APQ8074PRO-AC") },
{ qcom_board_id_named(MSM8274PRO_AA, "MSM8274PRO-AA") },
{ qcom_board_id_named(MSM8274PRO_AB, "MSM8274PRO-AB") },
{ qcom_board_id_named(MSM8274PRO_AC, "MSM8274PRO-AC") },
{ qcom_board_id_named(MSM8674PRO_AA, "MSM8674PRO-AA") },
{ qcom_board_id_named(MSM8674PRO_AB, "MSM8674PRO-AB") },
{ qcom_board_id_named(MSM8674PRO_AC, "MSM8674PRO-AC") },
{ qcom_board_id_named(MSM8974PRO_AA, "MSM8974PRO-AA") },
{ qcom_board_id_named(MSM8974PRO_AB, "MSM8974PRO-AB") },
{ qcom_board_id(APQ8028) },
{ qcom_board_id(MSM8128) },
{ qcom_board_id(MSM8228) },
{ qcom_board_id(MSM8528) },
{ qcom_board_id(MSM8628) },
{ qcom_board_id(MSM8928) },
{ qcom_board_id(MSM8510) },
{ qcom_board_id(MSM8512) },
{ qcom_board_id(MSM8936) },
{ qcom_board_id(MSM8939) },
{ qcom_board_id(APQ8036) },
{ qcom_board_id(APQ8039) },
{ qcom_board_id(MSM8996) },
{ qcom_board_id(APQ8016) },
{ qcom_board_id(MSM8216) },
{ qcom_board_id(MSM8116) },
{ qcom_board_id(MSM8616) },
{ qcom_board_id(MSM8992) },
{ qcom_board_id(APQ8094) },
{ qcom_board_id(MDM9607) },
{ qcom_board_id(APQ8096) },
{ qcom_board_id(MSM8998) },
{ qcom_board_id(MSM8953) },
{ qcom_board_id(MDM8207) },
{ qcom_board_id(MDM9207) },
{ qcom_board_id(MDM9307) },
{ qcom_board_id(MDM9628) },
{ qcom_board_id(APQ8053) },
{ qcom_board_id(MSM8996SG) },
{ qcom_board_id(MSM8996AU) },
{ qcom_board_id(APQ8096AU) },
{ qcom_board_id(APQ8096SG) },
{ qcom_board_id(SDM660) },
{ qcom_board_id(SDM630) },
{ qcom_board_id(APQ8098) },
{ qcom_board_id(SDM845) },
{ qcom_board_id(MDM9206) },
{ qcom_board_id(IPQ8074) },
{ qcom_board_id(SDA660) },
{ qcom_board_id(SDM658) },
{ qcom_board_id(SDA658) },
{ qcom_board_id(SDA630) },
{ qcom_board_id(SDM450) },
{ qcom_board_id(SM8150) },
{ qcom_board_id(SDA845) },
{ qcom_board_id(IPQ8072) },
{ qcom_board_id(IPQ8076) },
{ qcom_board_id(IPQ8078) },
{ qcom_board_id(SDM636) },
{ qcom_board_id(SDA636) },
{ qcom_board_id(SDM632) },
{ qcom_board_id(SDA632) },
{ qcom_board_id(SDA450) },
{ qcom_board_id(SM8250) },
{ qcom_board_id(SA8155) },
{ qcom_board_id(IPQ8070) },
{ qcom_board_id(IPQ8071) },
{ qcom_board_id(IPQ8072A) },
{ qcom_board_id(IPQ8074A) },
{ qcom_board_id(IPQ8076A) },
{ qcom_board_id(IPQ8078A) },
{ qcom_board_id(SM6125) },
{ qcom_board_id(IPQ8070A) },
{ qcom_board_id(IPQ8071A) },
{ qcom_board_id(IPQ6018) },
{ qcom_board_id(IPQ6028) },
{ qcom_board_id(SM4250) },
{ qcom_board_id(IPQ6000) },
{ qcom_board_id(IPQ6010) },
{ qcom_board_id(SC7180) },
{ qcom_board_id(SM6350) },
{ qcom_board_id(SM8350) },
{ qcom_board_id(SM6115) },
{ qcom_board_id(SC8280XP) },
{ qcom_board_id(IPQ6005) },
{ qcom_board_id(QRB5165) },
{ qcom_board_id(SM8450) },
{ qcom_board_id(SM8550) },
{ qcom_board_id(SM7225) },
{ qcom_board_id(SA8295P) },
{ qcom_board_id(SA8540P) },
{ qcom_board_id(QCM4290) },
{ qcom_board_id(QCS4290) },
{ qcom_board_id_named(SM8450_2, "SM8450") },
{ qcom_board_id_named(SM8450_3, "SM8450") },
{ qcom_board_id(SC7280) },
{ qcom_board_id(SC7180P) },
{ qcom_board_id(SM6375) },
{ qcom_board_id(QRU1000) },
{ qcom_board_id(QDU1000) },
{ qcom_board_id(QDU1010) },
{ qcom_board_id(QRU1032) },
{ qcom_board_id(QRU1052) },
{ qcom_board_id(QRU1062) },
};
static const char *socinfo_machine(struct device *dev, unsigned int id)

View file

@ -98,6 +98,46 @@ static const struct spm_reg_data spm_reg_8916_cpu = {
.start_index[PM_SLEEP_MODE_SPC] = 5,
};
static const struct spm_reg_data spm_reg_8939_cpu = {
.reg_offset = spm_reg_offset_v3_0,
.spm_cfg = 0x1,
.spm_dly = 0x3C102800,
.seq = { 0x60, 0x03, 0x60, 0x0B, 0x0F, 0x20, 0x50, 0x1B, 0x10, 0x80,
0x30, 0x90, 0x5B, 0x60, 0x50, 0x03, 0x60, 0x76, 0x76, 0x0B,
0x50, 0x1B, 0x94, 0x5B, 0x80, 0x10, 0x26, 0x30, 0x50, 0x0F },
.start_index[PM_SLEEP_MODE_STBY] = 0,
.start_index[PM_SLEEP_MODE_SPC] = 5,
};
static const u16 spm_reg_offset_v2_3[SPM_REG_NR] = {
[SPM_REG_CFG] = 0x08,
[SPM_REG_SPM_CTL] = 0x30,
[SPM_REG_DLY] = 0x34,
[SPM_REG_PMIC_DATA_0] = 0x40,
[SPM_REG_PMIC_DATA_1] = 0x44,
};
/* SPM register data for 8976 */
static const struct spm_reg_data spm_reg_8976_gold_l2 = {
.reg_offset = spm_reg_offset_v2_3,
.spm_cfg = 0x14,
.spm_dly = 0x3c11840a,
.pmic_data[0] = 0x03030080,
.pmic_data[1] = 0x00030000,
.start_index[PM_SLEEP_MODE_STBY] = 0,
.start_index[PM_SLEEP_MODE_SPC] = 3,
};
static const struct spm_reg_data spm_reg_8976_silver_l2 = {
.reg_offset = spm_reg_offset_v2_3,
.spm_cfg = 0x14,
.spm_dly = 0x3c102800,
.pmic_data[0] = 0x03030080,
.pmic_data[1] = 0x00030000,
.start_index[PM_SLEEP_MODE_STBY] = 0,
.start_index[PM_SLEEP_MODE_SPC] = 2,
};
static const u16 spm_reg_offset_v2_1[SPM_REG_NR] = {
[SPM_REG_CFG] = 0x08,
[SPM_REG_SPM_CTL] = 0x30,
@ -211,8 +251,14 @@ static const struct of_device_id spm_match_table[] = {
.data = &spm_reg_8909_cpu },
{ .compatible = "qcom,msm8916-saw2-v3.0-cpu",
.data = &spm_reg_8916_cpu },
{ .compatible = "qcom,msm8939-saw2-v3.0-cpu",
.data = &spm_reg_8939_cpu },
{ .compatible = "qcom,msm8974-saw2-v2.1-cpu",
.data = &spm_reg_8974_8084_cpu },
{ .compatible = "qcom,msm8976-gold-saw2-v2.3-l2",
.data = &spm_reg_8976_gold_l2 },
{ .compatible = "qcom,msm8976-silver-saw2-v2.3-l2",
.data = &spm_reg_8976_silver_l2 },
{ .compatible = "qcom,msm8998-gold-saw2-v4.1-l2",
.data = &spm_reg_8998_gold_l2 },
{ .compatible = "qcom,msm8998-silver-saw2-v4.1-l2",

View file

@ -14,16 +14,15 @@
TRACE_EVENT(rpmh_tx_done,
TP_PROTO(struct rsc_drv *d, int m, const struct tcs_request *r, int e),
TP_PROTO(struct rsc_drv *d, int m, const struct tcs_request *r),
TP_ARGS(d, m, r, e),
TP_ARGS(d, m, r),
TP_STRUCT__entry(
__string(name, d->name)
__field(int, m)
__field(u32, addr)
__field(u32, data)
__field(int, err)
),
TP_fast_assign(
@ -31,12 +30,10 @@ TRACE_EVENT(rpmh_tx_done,
__entry->m = m;
__entry->addr = r->cmds[0].addr;
__entry->data = r->cmds[0].data;
__entry->err = e;
),
TP_printk("%s: ack: tcs-m: %d addr: %#x data: %#x errno: %d",
__get_str(name), __entry->m, __entry->addr, __entry->data,
__entry->err)
TP_printk("%s: ack: tcs-m: %d addr: %#x data: %#x",
__get_str(name), __entry->m, __entry->addr, __entry->data)
);
TRACE_EVENT(rpmh_send_msg,

View file

@ -76,6 +76,10 @@ static const struct renesas_family fam_rzv2l __initconst __maybe_unused = {
.name = "RZ/V2L",
};
static const struct renesas_family fam_rzv2m __initconst __maybe_unused = {
.name = "RZ/V2M",
};
static const struct renesas_family fam_shmobile __initconst __maybe_unused = {
.name = "SH-Mobile",
.reg = 0xe600101c, /* CCCR (Common Chip Code Register) */
@ -171,6 +175,10 @@ static const struct renesas_soc soc_rz_v2l __initconst __maybe_unused = {
.id = 0x8447447,
};
static const struct renesas_soc soc_rz_v2m __initconst __maybe_unused = {
.family = &fam_rzv2m,
};
static const struct renesas_soc soc_rcar_m1a __initconst __maybe_unused = {
.family = &fam_rcar_gen1,
};
@ -380,6 +388,9 @@ static const struct of_device_id renesas_socs[] __initconst = {
#if defined(CONFIG_ARCH_R9A07G054)
{ .compatible = "renesas,r9a07g054", .data = &soc_rz_v2l },
#endif
#if defined(CONFIG_ARCH_R9A09G011)
{ .compatible = "renesas,r9a09g011", .data = &soc_rz_v2m },
#endif
#ifdef CONFIG_ARCH_SH73A0
{ .compatible = "renesas,sh73a0", .data = &soc_shmobile_ag5 },
#endif
@ -405,6 +416,11 @@ static const struct renesas_id id_rzg2l __initconst = {
.mask = 0xfffffff,
};
static const struct renesas_id id_rzv2m __initconst = {
.offset = 0x104,
.mask = 0xff,
};
static const struct renesas_id id_prr __initconst = {
.offset = 0,
.mask = 0xff00,
@ -415,6 +431,7 @@ static const struct of_device_id renesas_ids[] __initconst = {
{ .compatible = "renesas,r9a07g043-sysc", .data = &id_rzg2l },
{ .compatible = "renesas,r9a07g044-sysc", .data = &id_rzg2l },
{ .compatible = "renesas,r9a07g054-sysc", .data = &id_rzg2l },
{ .compatible = "renesas,r9a09g011-sys", .data = &id_rzv2m },
{ .compatible = "renesas,prr", .data = &id_prr },
{ /* sentinel */ }
};
@ -485,6 +502,11 @@ static int __init renesas_soc_init(void)
soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%u",
eshi);
rev_prefix = "Rev ";
} else if (id == &id_rzv2m) {
eshi = ((product >> 4) & 0x0f);
eslo = product & 0xf;
soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%u.%u",
eshi, eslo);
}
if (soc->id &&

View file

@ -215,20 +215,27 @@ static int __init sifive_ccache_init(void)
if (!np)
return -ENODEV;
if (of_address_to_resource(np, 0, &res))
return -ENODEV;
if (of_address_to_resource(np, 0, &res)) {
rc = -ENODEV;
goto err_node_put;
}
ccache_base = ioremap(res.start, resource_size(&res));
if (!ccache_base)
return -ENOMEM;
if (!ccache_base) {
rc = -ENOMEM;
goto err_node_put;
}
if (of_property_read_u32(np, "cache-level", &level))
return -ENOENT;
if (of_property_read_u32(np, "cache-level", &level)) {
rc = -ENOENT;
goto err_unmap;
}
intr_num = of_property_count_u32_elems(np, "interrupts");
if (!intr_num) {
pr_err("No interrupts property\n");
return -ENODEV;
rc = -ENODEV;
goto err_unmap;
}
for (i = 0; i < intr_num; i++) {
@ -237,9 +244,10 @@ static int __init sifive_ccache_init(void)
NULL);
if (rc) {
pr_err("Could not request IRQ %d\n", g_irq[i]);
return rc;
goto err_free_irq;
}
}
of_node_put(np);
ccache_config_read();
@ -250,6 +258,15 @@ static int __init sifive_ccache_init(void)
setup_sifive_debug();
#endif
return 0;
err_free_irq:
while (--i >= 0)
free_irq(g_irq[i], NULL);
err_unmap:
iounmap(ccache_base);
err_node_put:
of_node_put(np);
return rc;
}
device_initcall(sifive_ccache_init);

View file

@ -143,6 +143,7 @@ config SOC_TEGRA_FLOWCTRL
config SOC_TEGRA_PMC
bool
select GENERIC_PINCONF
select IRQ_DOMAIN_HIERARCHY
select PM_OPP
select PM_GENERIC_DOMAINS
select REGMAP

View file

@ -72,18 +72,7 @@ static int tegra_cbb_err_show(struct seq_file *file, void *data)
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
};
DEFINE_SHOW_ATTRIBUTE(tegra_cbb_err);
static int tegra_cbb_err_debugfs_init(struct tegra_cbb *cbb)
{

View file

@ -102,8 +102,6 @@
#define CLUSTER_NOC_VQC GENMASK(17, 16)
#define CLUSTER_NOC_MSTR_ID GENMASK(21, 18)
#define USRBITS_MSTR_ID GENMASK(21, 18)
#define CBB_ERR_OPC GENMASK(4, 1)
#define CBB_ERR_ERRCODE GENMASK(10, 8)
#define CBB_ERR_LEN1 GENMASK(27, 16)
@ -2038,15 +2036,17 @@ static irqreturn_t tegra194_cbb_err_isr(int irq, void *data)
smp_processor_id(), priv->noc->name, priv->res->start,
irq);
mstr_id = FIELD_GET(USRBITS_MSTR_ID, priv->errlog5) - 1;
is_fatal = print_errlog(NULL, priv, status);
/*
* If illegal request is from CCPLEX(0x1)
* initiator then call BUG() to crash system.
* If illegal request is from CCPLEX(0x1) initiator
* and error is fatal then call BUG() to crash system.
*/
if ((mstr_id == 0x1) && priv->noc->erd_mask_inband_err)
is_inband_err = 1;
if (priv->noc->erd_mask_inband_err) {
mstr_id = FIELD_GET(CBB_NOC_MSTR_ID, priv->errlog5);
if (mstr_id == 0x1)
is_inband_err = 1;
}
}
}
@ -2226,10 +2226,8 @@ static int tegra194_cbb_get_bridges(struct tegra194_cbb *cbb, struct device_node
cbb->bridges[i].base = devm_ioremap_resource(cbb->base.dev,
&cbb->bridges[i].res);
if (IS_ERR(cbb->bridges[i].base)) {
dev_err(cbb->base.dev, "failed to map AXI2APB range\n");
if (IS_ERR(cbb->bridges[i].base))
return PTR_ERR(cbb->bridges[i].base);
}
}
}

View file

@ -72,6 +72,11 @@
#define REQ_SOCKET_ID GENMASK(27, 24)
#define CCPLEX_MSTRID 0x1
#define FIREWALL_APERTURE_SZ 0x10000
/* Write firewall check enable */
#define WEN 0x20000
enum tegra234_cbb_fabric_ids {
CBB_FAB_ID,
SCE_FAB_ID,
@ -92,11 +97,15 @@ struct tegra234_slave_lookup {
struct tegra234_cbb_fabric {
const char *name;
phys_addr_t off_mask_erd;
bool erd_mask_inband_err;
phys_addr_t firewall_base;
unsigned int firewall_ctl;
unsigned int firewall_wr_ctl;
const char * const *master_id;
unsigned int notifier_offset;
const struct tegra_cbb_error *errors;
const int max_errors;
const struct tegra234_slave_lookup *slave_map;
const int max_slaves;
};
struct tegra234_cbb {
@ -128,6 +137,44 @@ static inline struct tegra234_cbb *to_tegra234_cbb(struct tegra_cbb *cbb)
static LIST_HEAD(cbb_list);
static DEFINE_SPINLOCK(cbb_lock);
static bool
tegra234_cbb_write_access_allowed(struct platform_device *pdev, struct tegra234_cbb *cbb)
{
u32 val;
if (!cbb->fabric->firewall_base ||
!cbb->fabric->firewall_ctl ||
!cbb->fabric->firewall_wr_ctl) {
dev_info(&pdev->dev, "SoC data missing for firewall\n");
return false;
}
if ((cbb->fabric->firewall_ctl > FIREWALL_APERTURE_SZ) ||
(cbb->fabric->firewall_wr_ctl > FIREWALL_APERTURE_SZ)) {
dev_err(&pdev->dev, "wrong firewall offset value\n");
return false;
}
val = readl(cbb->regs + cbb->fabric->firewall_base + cbb->fabric->firewall_ctl);
/*
* If the firewall check feature for allowing or blocking the
* write accesses through the firewall of a fabric is disabled
* then CCPLEX can write to the registers of that fabric.
*/
if (!(val & WEN))
return true;
/*
* If the firewall check is enabled then check whether CCPLEX
* has write access to the fabric's error notifier registers
*/
val = readl(cbb->regs + cbb->fabric->firewall_base + cbb->fabric->firewall_wr_ctl);
if (val & (BIT(CCPLEX_MSTRID)))
return true;
return false;
}
static void tegra234_cbb_fault_enable(struct tegra_cbb *cbb)
{
struct tegra234_cbb *priv = to_tegra234_cbb(cbb);
@ -271,6 +318,12 @@ static void tegra234_cbb_print_error(struct seq_file *file, struct tegra234_cbb
tegra_cbb_print_err(file, "\t Multiple type of errors reported\n");
while (status) {
if (type >= cbb->fabric->max_errors) {
tegra_cbb_print_err(file, "\t Wrong type index:%u, status:%u\n",
type, status);
return;
}
if (status & 0x1)
tegra_cbb_print_err(file, "\t Error Code\t\t: %s\n",
cbb->fabric->errors[type].code);
@ -282,6 +335,12 @@ static void tegra234_cbb_print_error(struct seq_file *file, struct tegra234_cbb
type = 0;
while (overflow) {
if (type >= cbb->fabric->max_errors) {
tegra_cbb_print_err(file, "\t Wrong type index:%u, overflow:%u\n",
type, overflow);
return;
}
if (overflow & 0x1)
tegra_cbb_print_err(file, "\t Overflow\t\t: Multiple %s\n",
cbb->fabric->errors[type].code);
@ -334,8 +393,11 @@ static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb)
access_type = FIELD_GET(FAB_EM_EL_ACCESSTYPE, cbb->mn_attr0);
tegra_cbb_print_err(file, "\n");
tegra_cbb_print_err(file, "\t Error Code\t\t: %s\n",
cbb->fabric->errors[cbb->type].code);
if (cbb->type < cbb->fabric->max_errors)
tegra_cbb_print_err(file, "\t Error Code\t\t: %s\n",
cbb->fabric->errors[cbb->type].code);
else
tegra_cbb_print_err(file, "\t Wrong type index:%u\n", cbb->type);
tegra_cbb_print_err(file, "\t MASTER_ID\t\t: %s\n", cbb->fabric->master_id[mstr_id]);
tegra_cbb_print_err(file, "\t Address\t\t: %#llx\n", cbb->access);
@ -374,6 +436,11 @@ static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb)
if ((fab_id == PSC_FAB_ID) || (fab_id == FSI_FAB_ID))
return;
if (slave_id >= cbb->fabric->max_slaves) {
tegra_cbb_print_err(file, "\t Invalid slave_id:%d\n", slave_id);
return;
}
if (!strcmp(cbb->fabric->errors[cbb->type].code, "TIMEOUT_ERR")) {
tegra234_lookup_slave_timeout(file, cbb, slave_id, fab_id);
return;
@ -517,7 +584,7 @@ static irqreturn_t tegra234_cbb_isr(int irq, void *data)
u32 status = tegra_cbb_get_status(cbb);
if (status && (irq == priv->sec_irq)) {
tegra_cbb_print_err(NULL, "CPU:%d, Error: %s@%llx, irq=%d\n",
tegra_cbb_print_err(NULL, "CPU:%d, Error: %s@0x%llx, irq=%d\n",
smp_processor_id(), priv->fabric->name,
priv->res->start, irq);
@ -525,14 +592,14 @@ static irqreturn_t tegra234_cbb_isr(int irq, void *data)
if (err)
goto unlock;
mstr_id = FIELD_GET(USRBITS_MSTR_ID, priv->mn_user_bits);
/*
* If illegal request is from CCPLEX(id:0x1) master then call BUG() to
* crash system.
* If illegal request is from CCPLEX(id:0x1) master then call WARN()
*/
if ((mstr_id == 0x1) && priv->fabric->off_mask_erd)
is_inband_err = 1;
if (priv->fabric->off_mask_erd) {
mstr_id = FIELD_GET(USRBITS_MSTR_ID, priv->mn_user_bits);
if (mstr_id == CCPLEX_MSTRID)
is_inband_err = 1;
}
}
}
@ -640,8 +707,13 @@ static const struct tegra234_cbb_fabric tegra234_aon_fabric = {
.name = "aon-fabric",
.master_id = tegra234_master_id,
.slave_map = tegra234_aon_slave_map,
.max_slaves = ARRAY_SIZE(tegra234_aon_slave_map),
.errors = tegra234_cbb_errors,
.max_errors = ARRAY_SIZE(tegra234_cbb_errors),
.notifier_offset = 0x17000,
.firewall_base = 0x30000,
.firewall_ctl = 0x8d0,
.firewall_wr_ctl = 0x8c8,
};
static const struct tegra234_slave_lookup tegra234_bpmp_slave_map[] = {
@ -656,8 +728,13 @@ static const struct tegra234_cbb_fabric tegra234_bpmp_fabric = {
.name = "bpmp-fabric",
.master_id = tegra234_master_id,
.slave_map = tegra234_bpmp_slave_map,
.max_slaves = ARRAY_SIZE(tegra234_bpmp_slave_map),
.errors = tegra234_cbb_errors,
.max_errors = ARRAY_SIZE(tegra234_cbb_errors),
.notifier_offset = 0x19000,
.firewall_base = 0x30000,
.firewall_ctl = 0x8f0,
.firewall_wr_ctl = 0x8e8,
};
static const struct tegra234_slave_lookup tegra234_cbb_slave_map[] = {
@ -728,55 +805,62 @@ static const struct tegra234_cbb_fabric tegra234_cbb_fabric = {
.name = "cbb-fabric",
.master_id = tegra234_master_id,
.slave_map = tegra234_cbb_slave_map,
.max_slaves = ARRAY_SIZE(tegra234_cbb_slave_map),
.errors = tegra234_cbb_errors,
.max_errors = ARRAY_SIZE(tegra234_cbb_errors),
.notifier_offset = 0x60000,
.off_mask_erd = 0x3a004
.off_mask_erd = 0x3a004,
.firewall_base = 0x10000,
.firewall_ctl = 0x23f0,
.firewall_wr_ctl = 0x23e8,
};
static const struct tegra234_slave_lookup tegra234_dce_slave_map[] = {
static const struct tegra234_slave_lookup tegra234_common_slave_map[] = {
{ "AXI2APB", 0x00000 },
{ "AST0", 0x15000 },
{ "AST1", 0x16000 },
{ "CBB", 0x17000 },
{ "RSVD", 0x00000 },
{ "CPU", 0x18000 },
};
static const struct tegra234_cbb_fabric tegra234_dce_fabric = {
.name = "dce-fabric",
.master_id = tegra234_master_id,
.slave_map = tegra234_dce_slave_map,
.slave_map = tegra234_common_slave_map,
.max_slaves = ARRAY_SIZE(tegra234_common_slave_map),
.errors = tegra234_cbb_errors,
.max_errors = ARRAY_SIZE(tegra234_cbb_errors),
.notifier_offset = 0x19000,
};
static const struct tegra234_slave_lookup tegra234_rce_slave_map[] = {
{ "AXI2APB", 0x00000 },
{ "AST0", 0x15000 },
{ "AST1", 0x16000 },
{ "CPU", 0x18000 },
.firewall_base = 0x30000,
.firewall_ctl = 0x290,
.firewall_wr_ctl = 0x288,
};
static const struct tegra234_cbb_fabric tegra234_rce_fabric = {
.name = "rce-fabric",
.master_id = tegra234_master_id,
.slave_map = tegra234_rce_slave_map,
.slave_map = tegra234_common_slave_map,
.max_slaves = ARRAY_SIZE(tegra234_common_slave_map),
.errors = tegra234_cbb_errors,
.max_errors = ARRAY_SIZE(tegra234_cbb_errors),
.notifier_offset = 0x19000,
};
static const struct tegra234_slave_lookup tegra234_sce_slave_map[] = {
{ "AXI2APB", 0x00000 },
{ "AST0", 0x15000 },
{ "AST1", 0x16000 },
{ "CBB", 0x17000 },
{ "CPU", 0x18000 },
.firewall_base = 0x30000,
.firewall_ctl = 0x290,
.firewall_wr_ctl = 0x288,
};
static const struct tegra234_cbb_fabric tegra234_sce_fabric = {
.name = "sce-fabric",
.master_id = tegra234_master_id,
.slave_map = tegra234_sce_slave_map,
.slave_map = tegra234_common_slave_map,
.max_slaves = ARRAY_SIZE(tegra234_common_slave_map),
.errors = tegra234_cbb_errors,
.max_errors = ARRAY_SIZE(tegra234_cbb_errors),
.notifier_offset = 0x19000,
.firewall_base = 0x30000,
.firewall_ctl = 0x290,
.firewall_wr_ctl = 0x288,
};
static const char * const tegra241_master_id[] = {
@ -889,7 +973,7 @@ static const struct tegra_cbb_error tegra241_cbb_errors[] = {
};
static const struct tegra234_slave_lookup tegra241_cbb_slave_map[] = {
{ "CCPLEX", 0x50000 },
{ "RSVD", 0x00000 },
{ "PCIE_C8", 0x51000 },
{ "PCIE_C9", 0x52000 },
{ "RSVD", 0x00000 },
@ -942,20 +1026,30 @@ static const struct tegra234_slave_lookup tegra241_cbb_slave_map[] = {
{ "PCIE_C3", 0x58000 },
{ "PCIE_C0", 0x59000 },
{ "PCIE_C1", 0x5a000 },
{ "CCPLEX", 0x50000 },
{ "AXI2APB_29", 0x85000 },
{ "AXI2APB_30", 0x86000 },
{ "CBB_CENTRAL", 0x00000 },
{ "AXI2APB_31", 0x8E000 },
{ "AXI2APB_32", 0x8F000 },
};
static const struct tegra234_cbb_fabric tegra241_cbb_fabric = {
.name = "cbb-fabric",
.master_id = tegra241_master_id,
.slave_map = tegra241_cbb_slave_map,
.max_slaves = ARRAY_SIZE(tegra241_cbb_slave_map),
.errors = tegra241_cbb_errors,
.max_errors = ARRAY_SIZE(tegra241_cbb_errors),
.notifier_offset = 0x60000,
.off_mask_erd = 0x40004,
.firewall_base = 0x20000,
.firewall_ctl = 0x2370,
.firewall_wr_ctl = 0x2368,
};
static const struct tegra234_slave_lookup tegra241_bpmp_slave_map[] = {
{ "RSVD", 0x00000 },
{ "RSVD", 0x00000 },
{ "RSVD", 0x00000 },
{ "CBB", 0x15000 },
@ -969,8 +1063,13 @@ static const struct tegra234_cbb_fabric tegra241_bpmp_fabric = {
.name = "bpmp-fabric",
.master_id = tegra241_master_id,
.slave_map = tegra241_bpmp_slave_map,
.max_slaves = ARRAY_SIZE(tegra241_bpmp_slave_map),
.errors = tegra241_cbb_errors,
.max_errors = ARRAY_SIZE(tegra241_cbb_errors),
.notifier_offset = 0x19000,
.firewall_base = 0x30000,
.firewall_ctl = 0x8f0,
.firewall_wr_ctl = 0x8e8,
};
static const struct of_device_id tegra234_cbb_dt_ids[] = {
@ -1055,6 +1154,15 @@ static int tegra234_cbb_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, cbb);
/*
* Don't enable error reporting for a Fabric if write to it's registers
* is blocked by CBB firewall.
*/
if (!tegra234_cbb_write_access_allowed(pdev, cbb)) {
dev_info(&pdev->dev, "error reporting not enabled due to firewall\n");
return 0;
}
spin_lock_irqsave(&cbb_lock, flags);
list_add(&cbb->base.node, &cbb_list);
spin_unlock_irqrestore(&cbb_lock, flags);

View file

@ -35,6 +35,19 @@ static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
[TEGRA_REVISION_A04] = "A04",
};
static const char *tegra_platform_name[TEGRA_PLATFORM_MAX] = {
[TEGRA_PLATFORM_SILICON] = "Silicon",
[TEGRA_PLATFORM_QT] = "QT",
[TEGRA_PLATFORM_SYSTEM_FPGA] = "System FPGA",
[TEGRA_PLATFORM_UNIT_FPGA] = "Unit FPGA",
[TEGRA_PLATFORM_ASIM_QT] = "Asim QT",
[TEGRA_PLATFORM_ASIM_LINSIM] = "Asim Linsim",
[TEGRA_PLATFORM_DSIM_ASIM_LINSIM] = "Dsim Asim Linsim",
[TEGRA_PLATFORM_VERIFICATION_SIMULATION] = "Verification Simulation",
[TEGRA_PLATFORM_VDK] = "VDK",
[TEGRA_PLATFORM_VSP] = "VSP",
};
static const struct of_device_id car_match[] __initconst = {
{ .compatible = "nvidia,tegra20-car", },
{ .compatible = "nvidia,tegra30-car", },
@ -94,112 +107,6 @@ static int tegra_fuse_read(void *priv, unsigned int offset, void *value,
return 0;
}
static const struct nvmem_cell_info tegra_fuse_cells[] = {
{
.name = "tsensor-cpu1",
.offset = 0x084,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-cpu2",
.offset = 0x088,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-cpu0",
.offset = 0x098,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "xusb-pad-calibration",
.offset = 0x0f0,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-cpu3",
.offset = 0x12c,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "sata-calibration",
.offset = 0x124,
.bytes = 1,
.bit_offset = 0,
.nbits = 2,
}, {
.name = "tsensor-gpu",
.offset = 0x154,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-mem0",
.offset = 0x158,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-mem1",
.offset = 0x15c,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-pllx",
.offset = 0x160,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-common",
.offset = 0x180,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "gpu-gcplex-config-fuse",
.offset = 0x1c8,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-realignment",
.offset = 0x1fc,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "gpu-calibration",
.offset = 0x204,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "xusb-pad-calibration-ext",
.offset = 0x250,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "gpu-pdi0",
.offset = 0x300,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "gpu-pdi1",
.offset = 0x304,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
},
};
static void tegra_fuse_restore(void *base)
{
fuse->base = (void __iomem *)base;
@ -253,8 +160,10 @@ static int tegra_fuse_probe(struct platform_device *pdev)
nvmem.name = "fuse";
nvmem.id = -1;
nvmem.owner = THIS_MODULE;
nvmem.cells = tegra_fuse_cells;
nvmem.ncells = ARRAY_SIZE(tegra_fuse_cells);
nvmem.cells = fuse->soc->cells;
nvmem.ncells = fuse->soc->num_cells;
nvmem.keepout = fuse->soc->keepouts;
nvmem.nkeepout = fuse->soc->num_keepouts;
nvmem.type = NVMEM_TYPE_OTP;
nvmem.read_only = true;
nvmem.root_only = true;
@ -474,8 +383,13 @@ struct device * __init tegra_soc_device_register(void)
return NULL;
attr->family = kasprintf(GFP_KERNEL, "Tegra");
attr->revision = kasprintf(GFP_KERNEL, "%s",
tegra_revision_name[tegra_sku_info.revision]);
if (tegra_is_silicon())
attr->revision = kasprintf(GFP_KERNEL, "%s %s",
tegra_platform_name[tegra_sku_info.platform],
tegra_revision_name[tegra_sku_info.revision]);
else
attr->revision = kasprintf(GFP_KERNEL, "%s",
tegra_platform_name[tegra_sku_info.platform]);
attr->soc_id = kasprintf(GFP_KERNEL, "%u", tegra_get_chip_id());
attr->custom_attr_group = fuse->soc->soc_attr_group;

View file

@ -9,6 +9,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/nvmem-consumer.h>
#include <linux/nvmem-provider.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
@ -133,6 +134,82 @@ const struct tegra_fuse_soc tegra114_fuse_soc = {
#endif
#if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)
static const struct nvmem_cell_info tegra124_fuse_cells[] = {
{
.name = "tsensor-cpu1",
.offset = 0x084,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-cpu2",
.offset = 0x088,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-cpu0",
.offset = 0x098,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "xusb-pad-calibration",
.offset = 0x0f0,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-cpu3",
.offset = 0x12c,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "sata-calibration",
.offset = 0x124,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-gpu",
.offset = 0x154,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-mem0",
.offset = 0x158,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-mem1",
.offset = 0x15c,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-pllx",
.offset = 0x160,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-common",
.offset = 0x180,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-realignment",
.offset = 0x1fc,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
},
};
static const struct nvmem_cell_lookup tegra124_fuse_lookups[] = {
{
.nvmem_name = "fuse",
@ -209,12 +286,96 @@ const struct tegra_fuse_soc tegra124_fuse_soc = {
.info = &tegra124_fuse_info,
.lookups = tegra124_fuse_lookups,
.num_lookups = ARRAY_SIZE(tegra124_fuse_lookups),
.cells = tegra124_fuse_cells,
.num_cells = ARRAY_SIZE(tegra124_fuse_cells),
.soc_attr_group = &tegra_soc_attr_group,
.clk_suspend_on = true,
};
#endif
#if defined(CONFIG_ARCH_TEGRA_210_SOC)
static const struct nvmem_cell_info tegra210_fuse_cells[] = {
{
.name = "tsensor-cpu1",
.offset = 0x084,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-cpu2",
.offset = 0x088,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-cpu0",
.offset = 0x098,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "xusb-pad-calibration",
.offset = 0x0f0,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-cpu3",
.offset = 0x12c,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "sata-calibration",
.offset = 0x124,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-gpu",
.offset = 0x154,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-mem0",
.offset = 0x158,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-mem1",
.offset = 0x15c,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-pllx",
.offset = 0x160,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "tsensor-common",
.offset = 0x180,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "gpu-calibration",
.offset = 0x204,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "xusb-pad-calibration-ext",
.offset = 0x250,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
},
};
static const struct nvmem_cell_lookup tegra210_fuse_lookups[] = {
{
.nvmem_name = "fuse",
@ -295,6 +456,8 @@ const struct tegra_fuse_soc tegra210_fuse_soc = {
.speedo_init = tegra210_init_speedo_data,
.info = &tegra210_fuse_info,
.lookups = tegra210_fuse_lookups,
.cells = tegra210_fuse_cells,
.num_cells = ARRAY_SIZE(tegra210_fuse_cells),
.num_lookups = ARRAY_SIZE(tegra210_fuse_lookups),
.soc_attr_group = &tegra_soc_attr_group,
.clk_suspend_on = false,
@ -302,6 +465,22 @@ const struct tegra_fuse_soc tegra210_fuse_soc = {
#endif
#if defined(CONFIG_ARCH_TEGRA_186_SOC)
static const struct nvmem_cell_info tegra186_fuse_cells[] = {
{
.name = "xusb-pad-calibration",
.offset = 0x0f0,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "xusb-pad-calibration-ext",
.offset = 0x250,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
},
};
static const struct nvmem_cell_lookup tegra186_fuse_lookups[] = {
{
.nvmem_name = "fuse",
@ -316,9 +495,17 @@ static const struct nvmem_cell_lookup tegra186_fuse_lookups[] = {
},
};
static const struct nvmem_keepout tegra186_fuse_keepouts[] = {
{ .start = 0x01c, .end = 0x0f0 },
{ .start = 0x138, .end = 0x198 },
{ .start = 0x1d8, .end = 0x250 },
{ .start = 0x280, .end = 0x290 },
{ .start = 0x340, .end = 0x344 }
};
static const struct tegra_fuse_info tegra186_fuse_info = {
.read = tegra30_fuse_read,
.size = 0x300,
.size = 0x478,
.spare = 0x280,
};
@ -327,12 +514,50 @@ const struct tegra_fuse_soc tegra186_fuse_soc = {
.info = &tegra186_fuse_info,
.lookups = tegra186_fuse_lookups,
.num_lookups = ARRAY_SIZE(tegra186_fuse_lookups),
.cells = tegra186_fuse_cells,
.num_cells = ARRAY_SIZE(tegra186_fuse_cells),
.keepouts = tegra186_fuse_keepouts,
.num_keepouts = ARRAY_SIZE(tegra186_fuse_keepouts),
.soc_attr_group = &tegra_soc_attr_group,
.clk_suspend_on = false,
};
#endif
#if defined(CONFIG_ARCH_TEGRA_194_SOC)
static const struct nvmem_cell_info tegra194_fuse_cells[] = {
{
.name = "xusb-pad-calibration",
.offset = 0x0f0,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "gpu-gcplex-config-fuse",
.offset = 0x1c8,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "xusb-pad-calibration-ext",
.offset = 0x250,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "gpu-pdi0",
.offset = 0x300,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "gpu-pdi1",
.offset = 0x304,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
},
};
static const struct nvmem_cell_lookup tegra194_fuse_lookups[] = {
{
.nvmem_name = "fuse",
@ -362,9 +587,18 @@ static const struct nvmem_cell_lookup tegra194_fuse_lookups[] = {
},
};
static const struct nvmem_keepout tegra194_fuse_keepouts[] = {
{ .start = 0x01c, .end = 0x0b8 },
{ .start = 0x12c, .end = 0x198 },
{ .start = 0x1a0, .end = 0x1bc },
{ .start = 0x1d8, .end = 0x250 },
{ .start = 0x270, .end = 0x290 },
{ .start = 0x310, .end = 0x45c }
};
static const struct tegra_fuse_info tegra194_fuse_info = {
.read = tegra30_fuse_read,
.size = 0x300,
.size = 0x650,
.spare = 0x280,
};
@ -373,12 +607,32 @@ const struct tegra_fuse_soc tegra194_fuse_soc = {
.info = &tegra194_fuse_info,
.lookups = tegra194_fuse_lookups,
.num_lookups = ARRAY_SIZE(tegra194_fuse_lookups),
.cells = tegra194_fuse_cells,
.num_cells = ARRAY_SIZE(tegra194_fuse_cells),
.keepouts = tegra194_fuse_keepouts,
.num_keepouts = ARRAY_SIZE(tegra194_fuse_keepouts),
.soc_attr_group = &tegra194_soc_attr_group,
.clk_suspend_on = false,
};
#endif
#if defined(CONFIG_ARCH_TEGRA_234_SOC)
static const struct nvmem_cell_info tegra234_fuse_cells[] = {
{
.name = "xusb-pad-calibration",
.offset = 0x0f0,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
}, {
.name = "xusb-pad-calibration-ext",
.offset = 0x250,
.bytes = 4,
.bit_offset = 0,
.nbits = 32,
},
};
static const struct nvmem_cell_lookup tegra234_fuse_lookups[] = {
{
.nvmem_name = "fuse",
@ -393,9 +647,23 @@ static const struct nvmem_cell_lookup tegra234_fuse_lookups[] = {
},
};
static const struct nvmem_keepout tegra234_fuse_keepouts[] = {
{ .start = 0x01c, .end = 0x0c8 },
{ .start = 0x12c, .end = 0x184 },
{ .start = 0x190, .end = 0x198 },
{ .start = 0x1a0, .end = 0x204 },
{ .start = 0x21c, .end = 0x250 },
{ .start = 0x25c, .end = 0x2f0 },
{ .start = 0x310, .end = 0x3d8 },
{ .start = 0x400, .end = 0x4f0 },
{ .start = 0x4f8, .end = 0x7e8 },
{ .start = 0x8d0, .end = 0x8d8 },
{ .start = 0xacc, .end = 0xf00 }
};
static const struct tegra_fuse_info tegra234_fuse_info = {
.read = tegra30_fuse_read,
.size = 0x300,
.size = 0x98c,
.spare = 0x280,
};
@ -404,6 +672,10 @@ const struct tegra_fuse_soc tegra234_fuse_soc = {
.info = &tegra234_fuse_info,
.lookups = tegra234_fuse_lookups,
.num_lookups = ARRAY_SIZE(tegra234_fuse_lookups),
.cells = tegra234_fuse_cells,
.num_cells = ARRAY_SIZE(tegra234_fuse_cells),
.keepouts = tegra234_fuse_keepouts,
.num_keepouts = ARRAY_SIZE(tegra234_fuse_keepouts),
.soc_attr_group = &tegra194_soc_attr_group,
.clk_suspend_on = false,
};

View file

@ -32,6 +32,10 @@ struct tegra_fuse_soc {
const struct nvmem_cell_lookup *lookups;
unsigned int num_lookups;
const struct nvmem_cell_info *cells;
unsigned int num_cells;
const struct nvmem_keepout *keepouts;
unsigned int num_keepouts;
const struct attribute_group *soc_attr_group;

View file

@ -156,6 +156,7 @@ void __init tegra_init_revision(void)
}
tegra_sku_info.sku_id = tegra_fuse_read_early(FUSE_SKU_INFO);
tegra_sku_info.platform = tegra_get_platform();
}
void __init tegra_init_apbmisc(void)

File diff suppressed because it is too large Load diff

View file

@ -63,7 +63,7 @@ config TI_SCI_PM_DOMAINS
rootfs may be available.
config TI_K3_RINGACC
bool "K3 Ring accelerator Sub System"
tristate "K3 Ring accelerator Sub System"
depends on ARCH_K3 || COMPILE_TEST
depends on TI_SCI_INTA_IRQCHIP
help

View file

@ -7,7 +7,7 @@
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
@ -336,6 +336,9 @@ struct k3_ring *k3_ringacc_request_ring(struct k3_ringacc *ringacc,
mutex_lock(&ringacc->req_lock);
if (!try_module_get(ringacc->dev->driver->owner))
goto err_module_get;
if (id == K3_RINGACC_RING_ID_ANY) {
/* Request for any general purpose ring */
struct ti_sci_resource_desc *gp_rings =
@ -380,6 +383,9 @@ struct k3_ring *k3_ringacc_request_ring(struct k3_ringacc *ringacc,
return &ringacc->rings[id];
error:
module_put(ringacc->dev->driver->owner);
err_module_get:
mutex_unlock(&ringacc->req_lock);
return NULL;
}
@ -616,6 +622,8 @@ int k3_ringacc_ring_free(struct k3_ring *ring)
no_init:
clear_bit(ring->ring_id, ringacc->rings_inuse);
module_put(ringacc->dev->driver->owner);
out:
mutex_unlock(&ringacc->req_lock);
return 0;
@ -1450,6 +1458,7 @@ static const struct of_device_id k3_ringacc_of_match[] = {
{ .compatible = "ti,am654-navss-ringacc", .data = &k3_ringacc_data, },
{},
};
MODULE_DEVICE_TABLE(of, k3_ringacc_of_match);
struct k3_ringacc *k3_ringacc_dmarings_init(struct platform_device *pdev,
struct k3_ringacc_init_data *data)
@ -1544,12 +1553,27 @@ static int k3_ringacc_probe(struct platform_device *pdev)
return 0;
}
static int k3_ringacc_remove(struct platform_device *pdev)
{
struct k3_ringacc *ringacc = dev_get_drvdata(&pdev->dev);
mutex_lock(&k3_ringacc_list_lock);
list_del(&ringacc->list);
mutex_unlock(&k3_ringacc_list_lock);
return 0;
}
static struct platform_driver k3_ringacc_driver = {
.probe = k3_ringacc_probe,
.remove = k3_ringacc_remove,
.driver = {
.name = "k3-ringacc",
.of_match_table = k3_ringacc_of_match,
.suppress_bind_attrs = true,
},
};
builtin_platform_driver(k3_ringacc_driver);
module_platform_driver(k3_ringacc_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("TI Ringacc driver for K3 SOCs");
MODULE_AUTHOR("Grygorii Strashko <grygorii.strashko@ti.com>");

View file

@ -43,6 +43,7 @@ static const struct k3_soc_id {
{ 0xBB38, "AM64X" },
{ 0xBB75, "J721S2"},
{ 0xBB7E, "AM62X" },
{ 0xBB8D, "AM62AX" },
};
static int

View file

@ -67,7 +67,7 @@ static DEFINE_MUTEX(knav_dev_lock);
* Newest followed by older ones. Search is done from start of the array
* until a firmware file is found.
*/
const char *knav_acc_firmwares[] = {"ks2_qmss_pdsp_acc48.bin"};
static const char * const knav_acc_firmwares[] = {"ks2_qmss_pdsp_acc48.bin"};
static bool device_ready;
bool knav_qmss_device_ready(void)
@ -1785,6 +1785,7 @@ static int knav_queue_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
ret = pm_runtime_resume_and_get(&pdev->dev);
if (ret < 0) {
pm_runtime_disable(&pdev->dev);
dev_err(dev, "Failed to enable QMSS\n");
return ret;
}

View file

@ -932,6 +932,7 @@ static int omap_sr_probe(struct platform_device *pdev)
err_debugfs:
debugfs_remove_recursive(sr_info->dbg_dir);
err_list_del:
pm_runtime_disable(&pdev->dev);
list_del(&sr_info->node);
clk_unprepare(sr_info->fck);

View file

@ -188,7 +188,7 @@ void optee_remove_common(struct optee *optee)
static int smc_abi_rc;
static int ffa_abi_rc;
static int optee_core_init(void)
static int __init optee_core_init(void)
{
/*
* The kernel may have crashed at the same time that all available
@ -210,7 +210,7 @@ static int optee_core_init(void)
}
module_init(optee_core_init);
static void optee_core_exit(void)
static void __exit optee_core_exit(void)
{
if (!smc_abi_rc)
optee_smc_abi_unregister();

View file

@ -106,21 +106,22 @@ static void tz_device_update_work_fn(struct work_struct *work)
static void bpmp_mrq_thermal(unsigned int mrq, struct tegra_bpmp_channel *ch,
void *data)
{
struct mrq_thermal_bpmp_to_host_request *req;
struct mrq_thermal_bpmp_to_host_request req;
struct tegra_bpmp_thermal *tegra = data;
size_t offset;
int i;
req = (struct mrq_thermal_bpmp_to_host_request *)ch->ib->data;
offset = offsetof(struct tegra_bpmp_mb_data, data);
iosys_map_memcpy_from(&req, &ch->ib, offset, sizeof(req));
if (req->type != CMD_THERMAL_HOST_TRIP_REACHED) {
dev_err(tegra->dev, "%s: invalid request type: %d\n",
__func__, req->type);
if (req.type != CMD_THERMAL_HOST_TRIP_REACHED) {
dev_err(tegra->dev, "%s: invalid request type: %d\n", __func__, req.type);
tegra_bpmp_mrq_return(ch, -EINVAL, NULL, 0);
return;
}
for (i = 0; i < tegra->num_zones; ++i) {
if (tegra->zones[i]->idx != req->host_trip_reached.zone)
if (tegra->zones[i]->idx != req.host_trip_reached.zone)
continue;
schedule_work(&tegra->zones[i]->tz_device_update_work);
@ -129,7 +130,7 @@ static void bpmp_mrq_thermal(unsigned int mrq, struct tegra_bpmp_channel *ch,
}
dev_err(tegra->dev, "%s: invalid thermal zone: %d\n", __func__,
req->host_trip_reached.zone);
req.host_trip_reached.zone);
tegra_bpmp_mrq_return(ch, -EINVAL, NULL, 0);
}

View file

@ -651,7 +651,7 @@ static int of_fhci_probe(struct platform_device *ofdev)
}
for (j = 0; j < NUM_PINS; j++) {
fhci->pins[j] = qe_pin_request(node, j);
fhci->pins[j] = qe_pin_request(dev, j);
if (IS_ERR(fhci->pins[j])) {
ret = PTR_ERR(fhci->pins[j]);
dev_err(dev, "can't get pin %d: %d\n", j, ret);

View file

@ -0,0 +1,170 @@
/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
/*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Linaro Ltd
* Author: Krzysztof Kozlowski <krzk@kernel.org> based on previous work of Kumar Gala.
*/
#ifndef _DT_BINDINGS_ARM_QCOM_IDS_H
#define _DT_BINDINGS_ARM_QCOM_IDS_H
/*
* The MSM chipset and hardware revision used by Qualcomm bootloaders, DTS for
* older chipsets (qcom,msm-id) and in socinfo driver:
*/
#define QCOM_ID_MSM8960 87
#define QCOM_ID_APQ8064 109
#define QCOM_ID_MSM8660A 122
#define QCOM_ID_MSM8260A 123
#define QCOM_ID_APQ8060A 124
#define QCOM_ID_MSM8974 126
#define QCOM_ID_MPQ8064 130
#define QCOM_ID_MSM8960AB 138
#define QCOM_ID_APQ8060AB 139
#define QCOM_ID_MSM8260AB 140
#define QCOM_ID_MSM8660AB 141
#define QCOM_ID_MSM8626 145
#define QCOM_ID_MSM8610 147
#define QCOM_ID_APQ8064AB 153
#define QCOM_ID_MSM8226 158
#define QCOM_ID_MSM8526 159
#define QCOM_ID_MSM8110 161
#define QCOM_ID_MSM8210 162
#define QCOM_ID_MSM8810 163
#define QCOM_ID_MSM8212 164
#define QCOM_ID_MSM8612 165
#define QCOM_ID_MSM8112 166
#define QCOM_ID_MSM8225Q 168
#define QCOM_ID_MSM8625Q 169
#define QCOM_ID_MSM8125Q 170
#define QCOM_ID_APQ8064AA 172
#define QCOM_ID_APQ8084 178
#define QCOM_ID_APQ8074 184
#define QCOM_ID_MSM8274 185
#define QCOM_ID_MSM8674 186
#define QCOM_ID_MSM8974PRO_AC 194
#define QCOM_ID_MSM8126 198
#define QCOM_ID_APQ8026 199
#define QCOM_ID_MSM8926 200
#define QCOM_ID_MSM8326 205
#define QCOM_ID_MSM8916 206
#define QCOM_ID_MSM8994 207
#define QCOM_ID_APQ8074PRO_AA 208
#define QCOM_ID_APQ8074PRO_AB 209
#define QCOM_ID_APQ8074PRO_AC 210
#define QCOM_ID_MSM8274PRO_AA 211
#define QCOM_ID_MSM8274PRO_AB 212
#define QCOM_ID_MSM8274PRO_AC 213
#define QCOM_ID_MSM8674PRO_AA 214
#define QCOM_ID_MSM8674PRO_AB 215
#define QCOM_ID_MSM8674PRO_AC 216
#define QCOM_ID_MSM8974PRO_AA 217
#define QCOM_ID_MSM8974PRO_AB 218
#define QCOM_ID_APQ8028 219
#define QCOM_ID_MSM8128 220
#define QCOM_ID_MSM8228 221
#define QCOM_ID_MSM8528 222
#define QCOM_ID_MSM8628 223
#define QCOM_ID_MSM8928 224
#define QCOM_ID_MSM8510 225
#define QCOM_ID_MSM8512 226
#define QCOM_ID_MSM8936 233
#define QCOM_ID_MSM8939 239
#define QCOM_ID_APQ8036 240
#define QCOM_ID_APQ8039 241
#define QCOM_ID_MSM8996 246
#define QCOM_ID_APQ8016 247
#define QCOM_ID_MSM8216 248
#define QCOM_ID_MSM8116 249
#define QCOM_ID_MSM8616 250
#define QCOM_ID_MSM8992 251
#define QCOM_ID_APQ8094 253
#define QCOM_ID_MSM8956 266
#define QCOM_ID_MSM8976 278
#define QCOM_ID_MDM9607 290
#define QCOM_ID_APQ8096 291
#define QCOM_ID_MSM8998 292
#define QCOM_ID_MSM8953 293
#define QCOM_ID_MDM8207 296
#define QCOM_ID_MDM9207 297
#define QCOM_ID_MDM9307 298
#define QCOM_ID_MDM9628 299
#define QCOM_ID_APQ8053 304
#define QCOM_ID_MSM8996SG 305
#define QCOM_ID_MSM8996AU 310
#define QCOM_ID_APQ8096AU 311
#define QCOM_ID_APQ8096SG 312
#define QCOM_ID_SDM660 317
#define QCOM_ID_SDM630 318
#define QCOM_ID_APQ8098 319
#define QCOM_ID_SDM845 321
#define QCOM_ID_MDM9206 322
#define QCOM_ID_IPQ8074 323
#define QCOM_ID_SDA660 324
#define QCOM_ID_SDM658 325
#define QCOM_ID_SDA658 326
#define QCOM_ID_SDA630 327
#define QCOM_ID_SDM450 338
#define QCOM_ID_SM8150 339
#define QCOM_ID_SDA845 341
#define QCOM_ID_IPQ8072 342
#define QCOM_ID_IPQ8076 343
#define QCOM_ID_IPQ8078 344
#define QCOM_ID_SDM636 345
#define QCOM_ID_SDA636 346
#define QCOM_ID_SDM632 349
#define QCOM_ID_SDA632 350
#define QCOM_ID_SDA450 351
#define QCOM_ID_SM8250 356
#define QCOM_ID_SA8155 362
#define QCOM_ID_IPQ8070 375
#define QCOM_ID_IPQ8071 376
#define QCOM_ID_IPQ8072A 389
#define QCOM_ID_IPQ8074A 390
#define QCOM_ID_IPQ8076A 391
#define QCOM_ID_IPQ8078A 392
#define QCOM_ID_SM6125 394
#define QCOM_ID_IPQ8070A 395
#define QCOM_ID_IPQ8071A 396
#define QCOM_ID_IPQ6018 402
#define QCOM_ID_IPQ6028 403
#define QCOM_ID_SM4250 417
#define QCOM_ID_IPQ6000 421
#define QCOM_ID_IPQ6010 422
#define QCOM_ID_SC7180 425
#define QCOM_ID_SM6350 434
#define QCOM_ID_SM8350 439
#define QCOM_ID_SM6115 444
#define QCOM_ID_SC8280XP 449
#define QCOM_ID_IPQ6005 453
#define QCOM_ID_QRB5165 455
#define QCOM_ID_SM8450 457
#define QCOM_ID_SM7225 459
#define QCOM_ID_SA8295P 460
#define QCOM_ID_SA8540P 461
#define QCOM_ID_QCM4290 469
#define QCOM_ID_QCS4290 470
#define QCOM_ID_SM8450_2 480
#define QCOM_ID_SM8450_3 482
#define QCOM_ID_SC7280 487
#define QCOM_ID_SC7180P 495
#define QCOM_ID_SM6375 507
#define QCOM_ID_SM8550 519
#define QCOM_ID_QRU1000 539
#define QCOM_ID_QDU1000 545
#define QCOM_ID_QDU1010 587
#define QCOM_ID_QRU1032 588
#define QCOM_ID_QRU1052 589
#define QCOM_ID_QRU1062 590
/*
* The board type and revision information, used by Qualcomm bootloaders and
* DTS for older chipsets (qcom,board-id):
*/
#define QCOM_BOARD_ID(a, major, minor) \
(((major & 0xff) << 16) | ((minor & 0xff) << 8) | QCOM_BOARD_ID_##a)
#define QCOM_BOARD_ID_MTP 8
#define QCOM_BOARD_ID_DRAGONBOARD 10
#define QCOM_BOARD_ID_SBC 24
#endif /* _DT_BINDINGS_ARM_QCOM_IDS_H */

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