mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
ARM: SoC-related driver updates
Various driver updates for platforms. A bulk of this is smaller fixes or cleanups, but some of the new material this time around is: - Support for Nvidia Tegra234 SoC - Ring accelerator support for TI AM65x - PRUSS driver for TI platforms - Renesas support for R-Car V3U SoC - Reset support for Cortex-M4 processor on i.MX8MQ There are also new socinfo entries for a handful of different SoCs and platforms. -----BEGIN PGP SIGNATURE----- iQJDBAABCgAtFiEElf+HevZ4QCAJmMQ+jBrnPN6EHHcFAl+TUboPHG9sb2ZAbGl4 b20ubmV0AAoJEIwa5zzehBx3T4YP/R5pjF2C1gt8FrCaG4IfhIY1VHWelfPcB5qB RC7Pn4MCRCEY+10YPXA70oS6KBaC+gtZ4bPeInzfLXh1ynFJJb+XtAIxoRhnkEw+ /R979wNcIls9JqkvnHWFx29Y008W2ZNcXVNKH7O2Gxy+eKzDcTMsoH/zj8xWrV5b +eBllTzGU4RArYRJdcwOBQwMO6L2pzADHZ7hGMAY//8fo+qrxg8b9EINsH1UHCa8 gQdWdVlmv6GeLB6RYLRBCWxpW4jOLDqEAvyDV84QQmYHvzD9tqJExNR0hfGTs4TU TZWK7LWSNqF0ujQUbFh9Ikcx6DypU1gvE7LKhCDrf4D7HLRX5v4BjGH+xtVtjsyD xzh4WEoa3qCNu1mxQjKG8Y6U7bB9cRI2TPVxbbmI4ZuF0njvybecwwOZUBQl4aD4 5x+Df3pO/E5ECLOBeTnLgvw20fcjHv4HP8l63B6ADb31FUiZrJXItvayY5qXWe+P HSgUykmVA4nd4PnLsSj9seyWqOTIqUZ3U3TsmfxIQh2Otie01okwuHb1J7ErO/u0 W148SgSwVbnkPxjbBHKGgC2r+Q/AjSDGRBYL0ThIVFUztxTBBwhj3FIvMnyyxTIj yFBY14KQ8FcNUs8DrbPCaAx/RDCB02IHdvvIlyTmU3RBq7UhJVIglpLzzo2ed9F2 5u/aVH3y =tfPb -----END PGP SIGNATURE----- Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc Pull ARM SoC-related driver updates from Olof Johansson: "Various driver updates for platforms. A bulk of this is smaller fixes or cleanups, but some of the new material this time around is: - Support for Nvidia Tegra234 SoC - Ring accelerator support for TI AM65x - PRUSS driver for TI platforms - Renesas support for R-Car V3U SoC - Reset support for Cortex-M4 processor on i.MX8MQ There are also new socinfo entries for a handful of different SoCs and platforms" * tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (131 commits) drm/mediatek: reduce clear event soc: mediatek: cmdq: add clear option in cmdq_pkt_wfe api soc: mediatek: cmdq: add jump function soc: mediatek: cmdq: add write_s_mask value function soc: mediatek: cmdq: add write_s value function soc: mediatek: cmdq: add read_s function soc: mediatek: cmdq: add write_s_mask function soc: mediatek: cmdq: add write_s function soc: mediatek: cmdq: add address shift in jump soc: mediatek: mtk-infracfg: Fix kerneldoc soc: amlogic: pm-domains: use always-on flag reset: sti: reset-syscfg: fix struct description warnings reset: imx7: add the cm4 reset for i.MX8MQ dt-bindings: reset: imx8mq: add m4 reset reset: Fix and extend kerneldoc reset: reset-zynqmp: Added support for Versal platform dt-bindings: reset: Updated binding for Versal reset driver reset: imx7: Support module build soc: fsl: qe: Remove unnessesary check in ucc_set_tdm_rxtx_clk soc: fsl: qman: convert to use be32_add_cpu() ...
This commit is contained in:
commit
2e368dd2bb
@ -10,7 +10,8 @@ Required properties:
|
||||
"brcm,bcm7038-gisb-arb" for 130nm chips
|
||||
- reg: specifies the base physical address and size of the registers
|
||||
- interrupts: specifies the two interrupts (timeout and TEA) to be used from
|
||||
the parent interrupt controller
|
||||
the parent interrupt controller. A third optional interrupt may be specified
|
||||
for breakpoints.
|
||||
|
||||
Optional properties:
|
||||
|
||||
|
@ -5,7 +5,7 @@ The hardware block diagram please check bindings/iommu/mediatek,iommu.txt
|
||||
Mediatek SMI have two generations of HW architecture, here is the list
|
||||
which generation the SoCs use:
|
||||
generation 1: mt2701 and mt7623.
|
||||
generation 2: mt2712, mt6779, mt8173 and mt8183.
|
||||
generation 2: mt2712, mt6779, mt8167, mt8173 and mt8183.
|
||||
|
||||
There's slight differences between the two SMI, for generation 2, the
|
||||
register which control the iommu port is at each larb's register base. But
|
||||
@ -20,6 +20,7 @@ Required properties:
|
||||
"mediatek,mt2712-smi-common"
|
||||
"mediatek,mt6779-smi-common"
|
||||
"mediatek,mt7623-smi-common", "mediatek,mt2701-smi-common"
|
||||
"mediatek,mt8167-smi-common"
|
||||
"mediatek,mt8173-smi-common"
|
||||
"mediatek,mt8183-smi-common"
|
||||
- reg : the register and size of the SMI block.
|
||||
|
@ -8,6 +8,7 @@ Required properties:
|
||||
"mediatek,mt2712-smi-larb"
|
||||
"mediatek,mt6779-smi-larb"
|
||||
"mediatek,mt7623-smi-larb", "mediatek,mt2701-smi-larb"
|
||||
"mediatek,mt8167-smi-larb"
|
||||
"mediatek,mt8173-smi-larb"
|
||||
"mediatek,mt8183-smi-larb"
|
||||
- reg : the register and size of this local arbiter.
|
||||
@ -22,7 +23,7 @@ Required properties:
|
||||
- "gals": the clock for GALS(Global Async Local Sync).
|
||||
Here is the list which has this GALS: mt8183.
|
||||
|
||||
Required property for mt2701, mt2712, mt6779 and mt7623:
|
||||
Required property for mt2701, mt2712, mt6779, mt7623 and mt8167:
|
||||
- mediatek,larb-id :the hardware id of this larb.
|
||||
|
||||
Example:
|
||||
|
@ -27,6 +27,7 @@ properties:
|
||||
- amlogic,meson8b-pwrc
|
||||
- amlogic,meson8m2-pwrc
|
||||
- amlogic,meson-gxbb-pwrc
|
||||
- amlogic,meson-axg-pwrc
|
||||
- amlogic,meson-g12a-pwrc
|
||||
- amlogic,meson-sm1-pwrc
|
||||
|
||||
@ -42,11 +43,11 @@ properties:
|
||||
- const: vapb
|
||||
|
||||
resets:
|
||||
minItems: 11
|
||||
minItems: 5
|
||||
maxItems: 12
|
||||
|
||||
reset-names:
|
||||
minItems: 11
|
||||
minItems: 5
|
||||
maxItems: 12
|
||||
|
||||
"#power-domain-cells":
|
||||
@ -107,6 +108,24 @@ allOf:
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- amlogic,meson-axg-pwrc
|
||||
then:
|
||||
properties:
|
||||
reset-names:
|
||||
items:
|
||||
- const: viu
|
||||
- const: venc
|
||||
- const: vcbus
|
||||
- const: vencl
|
||||
- const: vid_lock
|
||||
required:
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -0,0 +1,44 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/power/brcm,bcm63xx-power.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: BCM63xx power domain driver
|
||||
|
||||
maintainers:
|
||||
- Álvaro Fernández Rojas <noltari@gmail.com>
|
||||
|
||||
description: |
|
||||
BCM6318, BCM6328, BCM6362 and BCM63268 SoCs have a power domain controller
|
||||
to enable/disable certain components in order to save power.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- brcm,bcm6318-power-controller
|
||||
- brcm,bcm6328-power-controller
|
||||
- brcm,bcm6362-power-controller
|
||||
- brcm,bcm63268-power-controller
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#power-domain-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#power-domain-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
periph_pwr: power-controller@10001848 {
|
||||
compatible = "brcm,bcm6328-power-controller";
|
||||
reg = <0x10001848 0x4>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
@ -1,7 +1,7 @@
|
||||
--------------------------------------------------------------------------
|
||||
= Zynq UltraScale+ MPSoC reset driver binding =
|
||||
= Zynq UltraScale+ MPSoC and Versal reset driver binding =
|
||||
--------------------------------------------------------------------------
|
||||
The Zynq UltraScale+ MPSoC has several different resets.
|
||||
The Zynq UltraScale+ MPSoC and Versal has several different resets.
|
||||
|
||||
See Chapter 36 of the Zynq UltraScale+ MPSoC TRM (UG) for more information
|
||||
about zynqmp resets.
|
||||
@ -10,7 +10,8 @@ Please also refer to reset.txt in this directory for common reset
|
||||
controller binding usage.
|
||||
|
||||
Required Properties:
|
||||
- compatible: "xlnx,zynqmp-reset"
|
||||
- compatible: "xlnx,zynqmp-reset" for Zynq UltraScale+ MPSoC platform
|
||||
"xlnx,versal-reset" for Versal platform
|
||||
- #reset-cells: Specifies the number of cells needed to encode reset
|
||||
line, should be 1
|
||||
|
||||
@ -37,8 +38,10 @@ Device nodes that need access to reset lines should
|
||||
specify them as a reset phandle in their corresponding node as
|
||||
specified in reset.txt.
|
||||
|
||||
For list of all valid reset indicies see
|
||||
For list of all valid reset indices for Zynq UltraScale+ MPSoC see
|
||||
<dt-bindings/reset/xlnx-zynqmp-resets.h>
|
||||
For list of all valid reset indices for Versal see
|
||||
<dt-bindings/reset/xlnx-versal-resets.h>
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -62,11 +62,6 @@ properties:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: TI-SCI device id of the ring accelerator
|
||||
|
||||
ti,dma-ring-reset-quirk:
|
||||
$ref: /schemas/types.yaml#definitions/flag
|
||||
description: |
|
||||
enable ringacc/udma ring state interoperability issue software w/a
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@ -94,7 +89,6 @@ examples:
|
||||
reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target";
|
||||
ti,num-rings = <818>;
|
||||
ti,sci-rm-range-gp-rings = <0x2>; /* GP ring range */
|
||||
ti,dma-ring-reset-quirk;
|
||||
ti,sci = <&dmsc>;
|
||||
ti,sci-dev-id = <187>;
|
||||
msi-parent = <&inta_main_udmass>;
|
||||
|
439
Documentation/devicetree/bindings/soc/ti/ti,pruss.yaml
Normal file
439
Documentation/devicetree/bindings/soc/ti/ti,pruss.yaml
Normal file
@ -0,0 +1,439 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/soc/ti/ti,pruss.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: |+
|
||||
TI Programmable Real-Time Unit and Industrial Communication Subsystem
|
||||
|
||||
maintainers:
|
||||
- Suman Anna <s-anna@ti.com>
|
||||
|
||||
description: |+
|
||||
|
||||
The Programmable Real-Time Unit and Industrial Communication Subsystem
|
||||
(PRU-ICSS a.k.a. PRUSS) is present on various TI SoCs such as AM335x, AM437x,
|
||||
Keystone 66AK2G, OMAP-L138/DA850 etc. A PRUSS consists of dual 32-bit RISC
|
||||
cores (Programmable Real-Time Units, or PRUs), shared RAM, data and
|
||||
instruction RAMs, some internal peripheral modules to facilitate industrial
|
||||
communication, and an interrupt controller.
|
||||
|
||||
The programmable nature of the PRUs provide flexibility to implement custom
|
||||
peripheral interfaces, fast real-time responses, or specialized data handling.
|
||||
The common peripheral modules include the following,
|
||||
- an Ethernet MII_RT module with two MII ports
|
||||
- an MDIO port to control external Ethernet PHYs
|
||||
- an Industrial Ethernet Peripheral (IEP) to manage/generate Industrial
|
||||
Ethernet functions
|
||||
- an Enhanced Capture Module (eCAP)
|
||||
- an Industrial Ethernet Timer with 7/9 capture and 16 compare events
|
||||
- a 16550-compatible UART to support PROFIBUS
|
||||
- Enhanced GPIO with async capture and serial support
|
||||
|
||||
A PRU-ICSS subsystem can have up to three shared data memories. A PRU core
|
||||
acts on a primary Data RAM (there are usually 2 Data RAMs) at its address
|
||||
0x0, but also has access to a secondary Data RAM (primary to the other PRU
|
||||
core) at its address 0x2000. A shared Data RAM, if present, can be accessed
|
||||
by both the PRU cores. The Interrupt Controller (INTC) and a CFG module are
|
||||
common to both the PRU cores. Each PRU core also has a private instruction
|
||||
RAM, and specific register spaces for Control and Debug functionalities.
|
||||
|
||||
Various sub-modules within a PRU-ICSS subsystem are represented as individual
|
||||
nodes and are defined using a parent-child hierarchy depending on their
|
||||
integration within the IP and the SoC. These nodes are described in the
|
||||
following sections.
|
||||
|
||||
|
||||
PRU-ICSS Node
|
||||
==============
|
||||
Each PRU-ICSS instance is represented as its own node with the individual PRU
|
||||
processor cores, the memories node, an INTC node and an MDIO node represented
|
||||
as child nodes within this PRUSS node. This node shall be a child of the
|
||||
corresponding interconnect bus nodes or target-module nodes.
|
||||
|
||||
See ../../mfd/syscon.yaml for generic SysCon binding details.
|
||||
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^(pruss|icssg)@[0-9a-f]+$"
|
||||
|
||||
compatible:
|
||||
enum:
|
||||
- ti,am3356-pruss # for AM335x SoC family
|
||||
- ti,am4376-pruss0 # for AM437x SoC family and PRUSS unit 0
|
||||
- ti,am4376-pruss1 # for AM437x SoC family and PRUSS unit 1
|
||||
- ti,am5728-pruss # for AM57xx SoC family
|
||||
- ti,k2g-pruss # for 66AK2G SoC family
|
||||
- ti,am654-icssg # for K3 AM65x SoC family
|
||||
- ti,j721e-icssg # for K3 J721E SoC family
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 1
|
||||
|
||||
ranges:
|
||||
maxItems: 1
|
||||
|
||||
power-domains:
|
||||
description: |
|
||||
This property is as per sci-pm-domain.txt.
|
||||
|
||||
patternProperties:
|
||||
|
||||
memories@[a-f0-9]+$:
|
||||
description: |
|
||||
The various Data RAMs within a single PRU-ICSS unit are represented as a
|
||||
single node with the name 'memories'.
|
||||
|
||||
type: object
|
||||
|
||||
properties:
|
||||
reg:
|
||||
minItems: 2 # On AM437x one of two PRUSS units don't contain Shared RAM.
|
||||
maxItems: 3
|
||||
items:
|
||||
- description: Address and size of the Data RAM0.
|
||||
- description: Address and size of the Data RAM1.
|
||||
- description: |
|
||||
Address and size of the Shared Data RAM. Note that on AM437x one
|
||||
of two PRUSS units don't contain Shared RAM, while the second one
|
||||
has it.
|
||||
|
||||
reg-names:
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
items:
|
||||
- const: dram0
|
||||
- const: dram1
|
||||
- const: shrdram2
|
||||
|
||||
required:
|
||||
- reg
|
||||
- reg-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
cfg@[a-f0-9]+$:
|
||||
description: |
|
||||
PRU-ICSS configuration space. CFG sub-module represented as a SysCon.
|
||||
|
||||
type: object
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: ti,pruss-cfg
|
||||
- const: syscon
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
ranges:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
type: object
|
||||
|
||||
properties:
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
patternProperties:
|
||||
coreclk-mux@[a-f0-9]+$:
|
||||
description: |
|
||||
This is applicable only for ICSSG (K3 SoCs). The ICSSG modules
|
||||
core clock can be set to one of the 2 sources: ICSSG_CORE_CLK or
|
||||
ICSSG_ICLK. This node models this clock mux and should have the
|
||||
name "coreclk-mux".
|
||||
|
||||
type: object
|
||||
|
||||
properties:
|
||||
'#clock-cells':
|
||||
const: 0
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: ICSSG_CORE Clock
|
||||
- description: ICSSG_ICLK Clock
|
||||
|
||||
assigned-clocks:
|
||||
maxItems: 1
|
||||
|
||||
assigned-clock-parents:
|
||||
maxItems: 1
|
||||
description: |
|
||||
Standard assigned-clocks-parents definition used for selecting
|
||||
mux parent (one of the mux input).
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
iepclk-mux@[a-f0-9]+$:
|
||||
description: |
|
||||
The IEP module can get its clock from 2 sources: ICSSG_IEP_CLK or
|
||||
CORE_CLK (OCP_CLK in older SoCs). This node models this clock
|
||||
mux and should have the name "iepclk-mux".
|
||||
|
||||
type: object
|
||||
|
||||
properties:
|
||||
'#clock-cells':
|
||||
const: 0
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: ICSSG_IEP Clock
|
||||
- description: Core Clock (OCP Clock in older SoCs)
|
||||
|
||||
assigned-clocks:
|
||||
maxItems: 1
|
||||
|
||||
assigned-clock-parents:
|
||||
maxItems: 1
|
||||
description: |
|
||||
Standard assigned-clocks-parents definition used for selecting
|
||||
mux parent (one of the mux input).
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
iep@[a-f0-9]+$:
|
||||
description: |
|
||||
Industrial Ethernet Peripheral to manage/generate Industrial Ethernet
|
||||
functions such as time stamping. Each PRUSS has either 1 IEP (on AM335x,
|
||||
AM437x, AM57xx & 66AK2G SoCs) or 2 IEPs (on K3 AM65x & J721E SoCs ). IEP
|
||||
is used for creating PTP clocks and generating PPS signals.
|
||||
|
||||
type: object
|
||||
|
||||
mii-rt@[a-f0-9]+$:
|
||||
description: |
|
||||
Real-Time Ethernet to support multiple industrial communication protocols.
|
||||
MII-RT sub-module represented as a SysCon.
|
||||
|
||||
type: object
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: ti,pruss-mii
|
||||
- const: syscon
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
mii-g-rt@[a-f0-9]+$:
|
||||
description: |
|
||||
The Real-time Media Independent Interface to support multiple industrial
|
||||
communication protocols (G stands for Gigabit). MII-G-RT sub-module
|
||||
represented as a SysCon.
|
||||
|
||||
type: object
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: ti,pruss-mii-g
|
||||
- const: syscon
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
interrupt-controller@[a-f0-9]+$:
|
||||
description: |
|
||||
PRUSS INTC Node. Each PRUSS has a single interrupt controller instance
|
||||
that is common to all the PRU cores. This should be represented as an
|
||||
interrupt-controller node.
|
||||
|
||||
type: object
|
||||
|
||||
mdio@[a-f0-9]+$:
|
||||
description: |
|
||||
MDIO Node. Each PRUSS has an MDIO module that can be used to control
|
||||
external PHYs. The MDIO module used within the PRU-ICSS is an instance of
|
||||
the MDIO Controller used in TI Davinci SoCs.
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/net/ti,davinci-mdio.yaml#
|
||||
|
||||
type: object
|
||||
|
||||
"^(pru|rtu|txpru)@[0-9a-f]+$":
|
||||
description: |
|
||||
PRU Node. Each PRUSS has dual PRU cores, each represented as a RemoteProc
|
||||
device through a PRU child node each. Each node can optionally be rendered
|
||||
inactive by using the standard DT string property, "status". The ICSSG IP
|
||||
present on K3 SoCs have additional auxiliary PRU cores with slightly
|
||||
different IP integration.
|
||||
|
||||
type: object
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- ranges
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
# Due to inability of correctly verifying sub-nodes with an @address through
|
||||
# the "required" list, the required sub-nodes below are commented out for now.
|
||||
|
||||
#required:
|
||||
# - memories
|
||||
# - interrupt-controller
|
||||
# - pru
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- ti,k2g-pruss
|
||||
- ti,am654-icssg
|
||||
- ti,j721e-icssg
|
||||
then:
|
||||
required:
|
||||
- power-domains
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
||||
/* Example 1 AM33xx PRU-ICSS */
|
||||
pruss: pruss@0 {
|
||||
compatible = "ti,am3356-pruss";
|
||||
reg = <0x0 0x80000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
|
||||
pruss_mem: memories@0 {
|
||||
reg = <0x0 0x2000>,
|
||||
<0x2000 0x2000>,
|
||||
<0x10000 0x3000>;
|
||||
reg-names = "dram0", "dram1", "shrdram2";
|
||||
};
|
||||
|
||||
pruss_cfg: cfg@26000 {
|
||||
compatible = "ti,pruss-cfg", "syscon";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
reg = <0x26000 0x2000>;
|
||||
ranges = <0x00 0x26000 0x2000>;
|
||||
|
||||
clocks {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
pruss_iepclk_mux: iepclk-mux@30 {
|
||||
reg = <0x30>;
|
||||
#clock-cells = <0>;
|
||||
clocks = <&l3_gclk>, /* icss_iep */
|
||||
<&pruss_ocp_gclk>; /* icss_ocp */
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
pruss_mii_rt: mii-rt@32000 {
|
||||
compatible = "ti,pruss-mii", "syscon";
|
||||
reg = <0x32000 0x58>;
|
||||
};
|
||||
|
||||
pruss_mdio: mdio@32400 {
|
||||
compatible = "ti,davinci_mdio";
|
||||
reg = <0x32400 0x90>;
|
||||
clocks = <&dpll_core_m4_ck>;
|
||||
clock-names = "fck";
|
||||
bus_freq = <1000000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
- |
|
||||
|
||||
/* Example 2 AM43xx PRU-ICSS with PRUSS1 node */
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
pruss1: pruss@0 {
|
||||
compatible = "ti,am4376-pruss1";
|
||||
reg = <0x0 0x40000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
|
||||
pruss1_mem: memories@0 {
|
||||
reg = <0x0 0x2000>,
|
||||
<0x2000 0x2000>,
|
||||
<0x10000 0x8000>;
|
||||
reg-names = "dram0", "dram1", "shrdram2";
|
||||
};
|
||||
|
||||
pruss1_cfg: cfg@26000 {
|
||||
compatible = "ti,pruss-cfg", "syscon";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
reg = <0x26000 0x2000>;
|
||||
ranges = <0x00 0x26000 0x2000>;
|
||||
|
||||
clocks {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
pruss1_iepclk_mux: iepclk-mux@30 {
|
||||
reg = <0x30>;
|
||||
#clock-cells = <0>;
|
||||
clocks = <&sysclk_div>, /* icss_iep */
|
||||
<&pruss_ocp_gclk>; /* icss_ocp */
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
pruss1_mii_rt: mii-rt@32000 {
|
||||
compatible = "ti,pruss-mii", "syscon";
|
||||
reg = <0x32000 0x58>;
|
||||
};
|
||||
|
||||
pruss1_mdio: mdio@32400 {
|
||||
compatible = "ti,davinci_mdio";
|
||||
reg = <0x32400 0x90>;
|
||||
clocks = <&dpll_core_m4_ck>;
|
||||
clock-names = "fck";
|
||||
bus_freq = <1000000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -3482,6 +3482,7 @@ F: arch/mips/bmips/*
|
||||
F: arch/mips/boot/dts/brcm/bcm*.dts*
|
||||
F: arch/mips/include/asm/mach-bmips/*
|
||||
F: arch/mips/kernel/*bmips*
|
||||
F: drivers/soc/bcm/bcm63xx
|
||||
F: drivers/irqchip/irq-bcm63*
|
||||
F: drivers/irqchip/irq-bcm7*
|
||||
F: drivers/irqchip/irq-brcmstb*
|
||||
|
@ -117,6 +117,12 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
periph_pwr: power-controller@1000184c {
|
||||
compatible = "brcm,bcm6328-power-controller";
|
||||
reg = <0x1000184c 0x4>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
|
||||
ehci: usb@10002500 {
|
||||
compatible = "brcm,bcm63268-ehci", "generic-ehci";
|
||||
reg = <0x10002500 0x100>;
|
||||
|
@ -110,6 +110,12 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
periph_pwr: power-controller@10001848 {
|
||||
compatible = "brcm,bcm6328-power-controller";
|
||||
reg = <0x10001848 0x4>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
|
||||
ehci: usb@10002500 {
|
||||
compatible = "brcm,bcm6328-ehci", "generic-ehci";
|
||||
reg = <0x10002500 0x100>;
|
||||
|
@ -108,6 +108,12 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
periph_pwr: power-controller@10001848 {
|
||||
compatible = "brcm,bcm6362-power-controller";
|
||||
reg = <0x10001848 0x4>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
|
||||
leds0: led-controller@10001900 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
@ -30,8 +30,22 @@
|
||||
#define ARB_ERR_CAP_STATUS_WRITE (1 << 1)
|
||||
#define ARB_ERR_CAP_STATUS_VALID (1 << 0)
|
||||
|
||||
#define ARB_BP_CAP_CLEAR (1 << 0)
|
||||
#define ARB_BP_CAP_STATUS_PROT_SHIFT 14
|
||||
#define ARB_BP_CAP_STATUS_TYPE (1 << 13)
|
||||
#define ARB_BP_CAP_STATUS_RSP_SHIFT 10
|
||||
#define ARB_BP_CAP_STATUS_MASK GENMASK(1, 0)
|
||||
#define ARB_BP_CAP_STATUS_BS_SHIFT 2
|
||||
#define ARB_BP_CAP_STATUS_WRITE (1 << 1)
|
||||
#define ARB_BP_CAP_STATUS_VALID (1 << 0)
|
||||
|
||||
enum {
|
||||
ARB_TIMER,
|
||||
ARB_BP_CAP_CLR,
|
||||
ARB_BP_CAP_HI_ADDR,
|
||||
ARB_BP_CAP_ADDR,
|
||||
ARB_BP_CAP_STATUS,
|
||||
ARB_BP_CAP_MASTER,
|
||||
ARB_ERR_CAP_CLR,
|
||||
ARB_ERR_CAP_HI_ADDR,
|
||||
ARB_ERR_CAP_ADDR,
|
||||
@ -41,6 +55,11 @@ enum {
|
||||
|
||||
static const int gisb_offsets_bcm7038[] = {
|
||||
[ARB_TIMER] = 0x00c,
|
||||
[ARB_BP_CAP_CLR] = 0x014,
|
||||
[ARB_BP_CAP_HI_ADDR] = -1,
|
||||
[ARB_BP_CAP_ADDR] = 0x0b8,
|
||||
[ARB_BP_CAP_STATUS] = 0x0c0,
|
||||
[ARB_BP_CAP_MASTER] = -1,
|
||||
[ARB_ERR_CAP_CLR] = 0x0c4,
|
||||
[ARB_ERR_CAP_HI_ADDR] = -1,
|
||||
[ARB_ERR_CAP_ADDR] = 0x0c8,
|
||||
@ -50,6 +69,11 @@ static const int gisb_offsets_bcm7038[] = {
|
||||
|
||||
static const int gisb_offsets_bcm7278[] = {
|
||||
[ARB_TIMER] = 0x008,
|
||||
[ARB_BP_CAP_CLR] = 0x01c,
|
||||
[ARB_BP_CAP_HI_ADDR] = -1,
|
||||
[ARB_BP_CAP_ADDR] = 0x220,
|
||||
[ARB_BP_CAP_STATUS] = 0x230,
|
||||
[ARB_BP_CAP_MASTER] = 0x234,
|
||||
[ARB_ERR_CAP_CLR] = 0x7f8,
|
||||
[ARB_ERR_CAP_HI_ADDR] = -1,
|
||||
[ARB_ERR_CAP_ADDR] = 0x7e0,
|
||||
@ -59,6 +83,11 @@ static const int gisb_offsets_bcm7278[] = {
|
||||
|
||||
static const int gisb_offsets_bcm7400[] = {
|
||||
[ARB_TIMER] = 0x00c,
|
||||
[ARB_BP_CAP_CLR] = 0x014,
|
||||
[ARB_BP_CAP_HI_ADDR] = -1,
|
||||
[ARB_BP_CAP_ADDR] = 0x0b8,
|
||||
[ARB_BP_CAP_STATUS] = 0x0c0,
|
||||
[ARB_BP_CAP_MASTER] = 0x0c4,
|
||||
[ARB_ERR_CAP_CLR] = 0x0c8,
|
||||
[ARB_ERR_CAP_HI_ADDR] = -1,
|
||||
[ARB_ERR_CAP_ADDR] = 0x0cc,
|
||||
@ -68,6 +97,11 @@ static const int gisb_offsets_bcm7400[] = {
|
||||
|
||||
static const int gisb_offsets_bcm7435[] = {
|
||||
[ARB_TIMER] = 0x00c,
|
||||
[ARB_BP_CAP_CLR] = 0x014,
|
||||
[ARB_BP_CAP_HI_ADDR] = -1,
|
||||
[ARB_BP_CAP_ADDR] = 0x158,
|
||||
[ARB_BP_CAP_STATUS] = 0x160,
|
||||
[ARB_BP_CAP_MASTER] = 0x164,
|
||||
[ARB_ERR_CAP_CLR] = 0x168,
|
||||
[ARB_ERR_CAP_HI_ADDR] = -1,
|
||||
[ARB_ERR_CAP_ADDR] = 0x16c,
|
||||
@ -77,6 +111,11 @@ static const int gisb_offsets_bcm7435[] = {
|
||||
|
||||
static const int gisb_offsets_bcm7445[] = {
|
||||
[ARB_TIMER] = 0x008,
|
||||
[ARB_BP_CAP_CLR] = 0x010,
|
||||
[ARB_BP_CAP_HI_ADDR] = -1,
|
||||
[ARB_BP_CAP_ADDR] = 0x1d8,
|
||||
[ARB_BP_CAP_STATUS] = 0x1e0,
|
||||
[ARB_BP_CAP_MASTER] = 0x1e4,
|
||||
[ARB_ERR_CAP_CLR] = 0x7e4,
|
||||
[ARB_ERR_CAP_HI_ADDR] = 0x7e8,
|
||||
[ARB_ERR_CAP_ADDR] = 0x7ec,
|
||||
@ -125,6 +164,16 @@ static u64 gisb_read_address(struct brcmstb_gisb_arb_device *gdev)
|
||||
return value;
|
||||
}
|
||||
|
||||
static u64 gisb_read_bp_address(struct brcmstb_gisb_arb_device *gdev)
|
||||
{
|
||||
u64 value;
|
||||
|
||||
value = gisb_read(gdev, ARB_BP_CAP_ADDR);
|
||||
value |= (u64)gisb_read(gdev, ARB_BP_CAP_HI_ADDR) << 32;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg)
|
||||
{
|
||||
int offset = gdev->gisb_offsets[reg];
|
||||
@ -210,8 +259,8 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev,
|
||||
m_name = m_fmt;
|
||||
}
|
||||
|
||||
pr_crit("%s: %s at 0x%llx [%c %s], core: %s\n",
|
||||
__func__, reason, arb_addr,
|
||||
pr_crit("GISB: %s at 0x%llx [%c %s], core: %s\n",
|
||||
reason, arb_addr,
|
||||
cap_status & ARB_ERR_CAP_STATUS_WRITE ? 'W' : 'R',
|
||||
cap_status & ARB_ERR_CAP_STATUS_TIMEOUT ? "timeout" : "",
|
||||
m_name);
|
||||
@ -259,6 +308,41 @@ static irqreturn_t brcmstb_gisb_tea_handler(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t brcmstb_gisb_bp_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct brcmstb_gisb_arb_device *gdev = dev_id;
|
||||
const char *m_name;
|
||||
u32 bp_status;
|
||||
u64 arb_addr;
|
||||
u32 master;
|
||||
char m_fmt[11];
|
||||
|
||||
bp_status = gisb_read(gdev, ARB_BP_CAP_STATUS);
|
||||
|
||||
/* Invalid captured address, bail out */
|
||||
if (!(bp_status & ARB_BP_CAP_STATUS_VALID))
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/* Read the address and master */
|
||||
arb_addr = gisb_read_bp_address(gdev);
|
||||
master = gisb_read(gdev, ARB_BP_CAP_MASTER);
|
||||
|
||||
m_name = brcmstb_gisb_master_to_str(gdev, master);
|
||||
if (!m_name) {
|
||||
snprintf(m_fmt, sizeof(m_fmt), "0x%08x", master);
|
||||
m_name = m_fmt;
|
||||
}
|
||||
|
||||
pr_crit("GISB: breakpoint at 0x%llx [%c], core: %s\n",
|
||||
arb_addr, bp_status & ARB_BP_CAP_STATUS_WRITE ? 'W' : 'R',
|
||||
m_name);
|
||||
|
||||
/* clear the GISB error */
|
||||
gisb_write(gdev, ARB_ERR_CAP_CLEAR, ARB_ERR_CAP_CLR);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dump out gisb errors on die or panic.
|
||||
*/
|
||||
@ -317,13 +401,14 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
|
||||
struct brcmstb_gisb_arb_device *gdev;
|
||||
const struct of_device_id *of_id;
|
||||
struct resource *r;
|
||||
int err, timeout_irq, tea_irq;
|
||||
int err, timeout_irq, tea_irq, bp_irq;
|
||||
unsigned int num_masters, j = 0;
|
||||
int i, first, last;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
timeout_irq = platform_get_irq(pdev, 0);
|
||||
tea_irq = platform_get_irq(pdev, 1);
|
||||
bp_irq = platform_get_irq(pdev, 2);
|
||||
|
||||
gdev = devm_kzalloc(&pdev->dev, sizeof(*gdev), GFP_KERNEL);
|
||||
if (!gdev)
|
||||
@ -356,6 +441,15 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Interrupt is optional */
|
||||
if (bp_irq > 0) {
|
||||
err = devm_request_irq(&pdev->dev, bp_irq,
|
||||
brcmstb_gisb_bp_handler, 0, pdev->name,
|
||||
gdev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* If we do not have a valid mask, assume all masters are enabled */
|
||||
if (of_property_read_u32(dn, "brcm,gisb-arb-master-mask",
|
||||
&gdev->valid_mask))
|
||||
|
@ -29,7 +29,7 @@ static const struct scmi_handle *handle;
|
||||
static unsigned int scmi_cpufreq_get_rate(unsigned int cpu)
|
||||
{
|
||||
struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
|
||||
struct scmi_perf_ops *perf_ops = handle->perf_ops;
|
||||
const struct scmi_perf_ops *perf_ops = handle->perf_ops;
|
||||
struct scmi_data *priv = policy->driver_data;
|
||||
unsigned long rate;
|
||||
int ret;
|
||||
@ -49,7 +49,7 @@ static int
|
||||
scmi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
{
|
||||
struct scmi_data *priv = policy->driver_data;
|
||||
struct scmi_perf_ops *perf_ops = handle->perf_ops;
|
||||
const struct scmi_perf_ops *perf_ops = handle->perf_ops;
|
||||
u64 freq = policy->freq_table[index].frequency;
|
||||
|
||||
return perf_ops->freq_set(handle, priv->domain_id, freq * 1000, false);
|
||||
@ -59,7 +59,7 @@ static unsigned int scmi_cpufreq_fast_switch(struct cpufreq_policy *policy,
|
||||
unsigned int target_freq)
|
||||
{
|
||||
struct scmi_data *priv = policy->driver_data;
|
||||
struct scmi_perf_ops *perf_ops = handle->perf_ops;
|
||||
const struct scmi_perf_ops *perf_ops = handle->perf_ops;
|
||||
|
||||
if (!perf_ops->freq_set(handle, priv->domain_id,
|
||||
target_freq * 1000, true))
|
||||
|
@ -573,8 +573,8 @@ static int k3_udma_glue_cfg_rx_flow(struct k3_udma_glue_rx_channel *rx_chn,
|
||||
|
||||
/* request and cfg rings */
|
||||
ret = k3_ringacc_request_rings_pair(rx_chn->common.ringacc,
|
||||
flow_cfg->ring_rxq_id,
|
||||
flow_cfg->ring_rxfdq0_id,
|
||||
flow_cfg->ring_rxq_id,
|
||||
&flow->ringrxfdq,
|
||||
&flow->ringrx);
|
||||
if (ret) {
|
||||
|
@ -7,7 +7,7 @@
|
||||
menu "Firmware Drivers"
|
||||
|
||||
config ARM_SCMI_PROTOCOL
|
||||
bool "ARM System Control and Management Interface (SCMI) Message Protocol"
|
||||
tristate "ARM System Control and Management Interface (SCMI) Message Protocol"
|
||||
depends on ARM || ARM64 || COMPILE_TEST
|
||||
depends on MAILBOX
|
||||
help
|
||||
|
@ -22,7 +22,7 @@ obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
|
||||
obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o
|
||||
obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o
|
||||
|
||||
obj-$(CONFIG_ARM_SCMI_PROTOCOL) += arm_scmi/
|
||||
obj-y += arm_scmi/
|
||||
obj-y += broadcom/
|
||||
obj-y += meson/
|
||||
obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
|
||||
|
@ -1,9 +1,11 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-y = scmi-bus.o scmi-driver.o scmi-protocols.o scmi-transport.o
|
||||
scmi-bus-y = bus.o
|
||||
scmi-driver-y = driver.o notify.o
|
||||
scmi-transport-y = shmem.o
|
||||
scmi-transport-$(CONFIG_MAILBOX) += mailbox.o
|
||||
scmi-transport-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smc.o
|
||||
scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o
|
||||
scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o system.o
|
||||
scmi-module-objs := $(scmi-bus-y) $(scmi-driver-y) $(scmi-protocols-y) \
|
||||
$(scmi-transport-y)
|
||||
obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o
|
||||
obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o
|
||||
|
@ -230,7 +230,7 @@ static void scmi_devices_unregister(void)
|
||||
bus_for_each_dev(&scmi_bus_type, NULL, NULL, __scmi_devices_unregister);
|
||||
}
|
||||
|
||||
static int __init scmi_bus_init(void)
|
||||
int __init scmi_bus_init(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
@ -240,12 +240,10 @@ static int __init scmi_bus_init(void)
|
||||
|
||||
return retval;
|
||||
}
|
||||
subsys_initcall(scmi_bus_init);
|
||||
|
||||
static void __exit scmi_bus_exit(void)
|
||||
void __exit scmi_bus_exit(void)
|
||||
{
|
||||
scmi_devices_unregister();
|
||||
bus_unregister(&scmi_bus_type);
|
||||
ida_destroy(&scmi_bus_id);
|
||||
}
|
||||
module_exit(scmi_bus_exit);
|
||||
|
@ -318,7 +318,7 @@ scmi_clock_info_get(const struct scmi_handle *handle, u32 clk_id)
|
||||
return clk;
|
||||
}
|
||||
|
||||
static struct scmi_clk_ops clk_ops = {
|
||||
static const struct scmi_clk_ops clk_ops = {
|
||||
.count_get = scmi_clock_count_get,
|
||||
.info_get = scmi_clock_info_get,
|
||||
.rate_get = scmi_clock_rate_get,
|
||||
@ -364,9 +364,4 @@ static int scmi_clock_protocol_init(struct scmi_handle *handle)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init scmi_clock_init(void)
|
||||
{
|
||||
return scmi_protocol_register(SCMI_PROTOCOL_CLOCK,
|
||||
&scmi_clock_protocol_init);
|
||||
}
|
||||
subsys_initcall(scmi_clock_init);
|
||||
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_CLOCK, clock)
|
||||
|
@ -156,6 +156,30 @@ void scmi_setup_protocol_implemented(const struct scmi_handle *handle,
|
||||
|
||||
int scmi_base_protocol_init(struct scmi_handle *h);
|
||||
|
||||
int __init scmi_bus_init(void);
|
||||
void __exit scmi_bus_exit(void);
|
||||
|
||||
#define DECLARE_SCMI_REGISTER_UNREGISTER(func) \
|
||||
int __init scmi_##func##_register(void); \
|
||||
void __exit scmi_##func##_unregister(void)
|
||||
DECLARE_SCMI_REGISTER_UNREGISTER(clock);
|
||||
DECLARE_SCMI_REGISTER_UNREGISTER(perf);
|
||||
DECLARE_SCMI_REGISTER_UNREGISTER(power);
|
||||
DECLARE_SCMI_REGISTER_UNREGISTER(reset);
|
||||
DECLARE_SCMI_REGISTER_UNREGISTER(sensors);
|
||||
DECLARE_SCMI_REGISTER_UNREGISTER(system);
|
||||
|
||||
#define DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(id, name) \
|
||||
int __init scmi_##name##_register(void) \
|
||||
{ \
|
||||
return scmi_protocol_register((id), &scmi_##name##_protocol_init); \
|
||||
} \
|
||||
\
|
||||
void __exit scmi_##name##_unregister(void) \
|
||||
{ \
|
||||
scmi_protocol_unregister((id)); \
|
||||
}
|
||||
|
||||
/* SCMI Transport */
|
||||
/**
|
||||
* struct scmi_chan_info - Structure representing a SCMI channel information
|
||||
@ -210,7 +234,7 @@ struct scmi_transport_ops {
|
||||
* @max_msg_size: Maximum size of data per message that can be handled.
|
||||
*/
|
||||
struct scmi_desc {
|
||||
struct scmi_transport_ops *ops;
|
||||
const struct scmi_transport_ops *ops;
|
||||
int max_rx_timeout_ms;
|
||||
int max_msg;
|
||||
int max_msg_size;
|
||||
|
@ -730,6 +730,7 @@ struct scmi_prot_devnames {
|
||||
|
||||
static struct scmi_prot_devnames devnames[] = {
|
||||
{ SCMI_PROTOCOL_POWER, { "genpd" },},
|
||||
{ SCMI_PROTOCOL_SYSTEM, { "syspower" },},
|
||||
{ SCMI_PROTOCOL_PERF, { "cpufreq" },},
|
||||
{ SCMI_PROTOCOL_CLOCK, { "clocks" },},
|
||||
{ SCMI_PROTOCOL_SENSOR, { "hwmon" },},
|
||||
@ -928,7 +929,35 @@ static struct platform_driver scmi_driver = {
|
||||
.remove = scmi_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(scmi_driver);
|
||||
static int __init scmi_driver_init(void)
|
||||
{
|
||||
scmi_bus_init();
|
||||
|
||||
scmi_clock_register();
|
||||
scmi_perf_register();
|
||||
scmi_power_register();
|
||||
scmi_reset_register();
|
||||
scmi_sensors_register();
|
||||
scmi_system_register();
|
||||
|
||||
return platform_driver_register(&scmi_driver);
|
||||
}
|
||||
subsys_initcall(scmi_driver_init);
|
||||
|
||||
static void __exit scmi_driver_exit(void)
|
||||
{
|
||||
scmi_bus_exit();
|
||||
|
||||
scmi_clock_unregister();
|
||||
scmi_perf_unregister();
|
||||
scmi_power_unregister();
|
||||
scmi_reset_unregister();
|
||||
scmi_sensors_unregister();
|
||||
scmi_system_unregister();
|
||||
|
||||
platform_driver_unregister(&scmi_driver);
|
||||
}
|
||||
module_exit(scmi_driver_exit);
|
||||
|
||||
MODULE_ALIAS("platform: arm-scmi");
|
||||
MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
|
||||
|
@ -110,7 +110,7 @@ static int mailbox_chan_free(int id, void *p, void *data)
|
||||
struct scmi_chan_info *cinfo = p;
|
||||
struct scmi_mailbox *smbox = cinfo->transport_info;
|
||||
|
||||
if (!IS_ERR(smbox->chan)) {
|
||||
if (smbox && !IS_ERR(smbox->chan)) {
|
||||
mbox_free_channel(smbox->chan);
|
||||
cinfo->transport_info = NULL;
|
||||
smbox->chan = NULL;
|
||||
@ -181,7 +181,7 @@ mailbox_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer)
|
||||
return shmem_poll_done(smbox->shmem, xfer);
|
||||
}
|
||||
|
||||
static struct scmi_transport_ops scmi_mailbox_ops = {
|
||||
static const struct scmi_transport_ops scmi_mailbox_ops = {
|
||||
.chan_available = mailbox_chan_available,
|
||||
.chan_setup = mailbox_chan_setup,
|
||||
.chan_free = mailbox_chan_free,
|
||||
|
@ -1421,7 +1421,7 @@ static void scmi_protocols_late_init(struct work_struct *work)
|
||||
* notify_ops are attached to the handle so that can be accessed
|
||||
* directly from an scmi_driver to register its own notifiers.
|
||||
*/
|
||||
static struct scmi_notify_ops notify_ops = {
|
||||
static const struct scmi_notify_ops notify_ops = {
|
||||
.register_event_notifier = scmi_register_notifier,
|
||||
.unregister_event_notifier = scmi_unregister_notifier,
|
||||
};
|
||||
|
@ -748,7 +748,7 @@ static bool scmi_fast_switch_possible(const struct scmi_handle *handle,
|
||||
return dom->fc_info && dom->fc_info->level_set_addr;
|
||||
}
|
||||
|
||||
static struct scmi_perf_ops perf_ops = {
|
||||
static const struct scmi_perf_ops perf_ops = {
|
||||
.limits_set = scmi_perf_limits_set,
|
||||
.limits_get = scmi_perf_limits_get,
|
||||
.level_set = scmi_perf_level_set,
|
||||
@ -890,9 +890,4 @@ static int scmi_perf_protocol_init(struct scmi_handle *handle)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init scmi_perf_init(void)
|
||||
{
|
||||
return scmi_protocol_register(SCMI_PROTOCOL_PERF,
|
||||
&scmi_perf_protocol_init);
|
||||
}
|
||||
subsys_initcall(scmi_perf_init);
|
||||
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_PERF, perf)
|
||||
|
@ -184,7 +184,7 @@ static char *scmi_power_name_get(const struct scmi_handle *handle, u32 domain)
|
||||
return dom->name;
|
||||
}
|
||||
|
||||
static struct scmi_power_ops power_ops = {
|
||||
static const struct scmi_power_ops power_ops = {
|
||||
.num_domains_get = scmi_power_num_domains_get,
|
||||
.name_get = scmi_power_name_get,
|
||||
.state_set = scmi_power_state_set,
|
||||
@ -301,9 +301,4 @@ static int scmi_power_protocol_init(struct scmi_handle *handle)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init scmi_power_init(void)
|
||||
{
|
||||
return scmi_protocol_register(SCMI_PROTOCOL_POWER,
|
||||
&scmi_power_protocol_init);
|
||||
}
|
||||
subsys_initcall(scmi_power_init);
|
||||
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_POWER, power)
|
||||
|
@ -194,7 +194,7 @@ scmi_reset_domain_deassert(const struct scmi_handle *handle, u32 domain)
|
||||
return scmi_domain_reset(handle, domain, 0, ARCH_COLD_RESET);
|
||||
}
|
||||
|
||||
static struct scmi_reset_ops reset_ops = {
|
||||
static const struct scmi_reset_ops reset_ops = {
|
||||
.num_domains_get = scmi_reset_num_domains_get,
|
||||
.name_get = scmi_reset_name_get,
|
||||
.latency_get = scmi_reset_latency_get,
|
||||
@ -313,9 +313,4 @@ static int scmi_reset_protocol_init(struct scmi_handle *handle)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init scmi_reset_init(void)
|
||||
{
|
||||
return scmi_protocol_register(SCMI_PROTOCOL_RESET,
|
||||
&scmi_reset_protocol_init);
|
||||
}
|
||||
subsys_initcall(scmi_reset_init);
|
||||
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_RESET, reset)
|
||||
|
@ -275,7 +275,7 @@ static int scmi_sensor_count_get(const struct scmi_handle *handle)
|
||||
return si->num_sensors;
|
||||
}
|
||||
|
||||
static struct scmi_sensor_ops sensor_ops = {
|
||||
static const struct scmi_sensor_ops sensor_ops = {
|
||||
.count_get = scmi_sensor_count_get,
|
||||
.info_get = scmi_sensor_info_get,
|
||||
.trip_point_config = scmi_sensor_trip_point_config,
|
||||
@ -365,9 +365,4 @@ static int scmi_sensors_protocol_init(struct scmi_handle *handle)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init scmi_sensors_init(void)
|
||||
{
|
||||
return scmi_protocol_register(SCMI_PROTOCOL_SENSOR,
|
||||
&scmi_sensors_protocol_init);
|
||||
}
|
||||
subsys_initcall(scmi_sensors_init);
|
||||
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_SENSOR, sensors)
|
||||
|
@ -137,7 +137,7 @@ smc_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer)
|
||||
return shmem_poll_done(scmi_info->shmem, xfer);
|
||||
}
|
||||
|
||||
static struct scmi_transport_ops scmi_smc_ops = {
|
||||
static const struct scmi_transport_ops scmi_smc_ops = {
|
||||
.chan_available = smc_chan_available,
|
||||
.chan_setup = smc_chan_setup,
|
||||
.chan_free = smc_chan_free,
|
||||
|
131
drivers/firmware/arm_scmi/system.c
Normal file
131
drivers/firmware/arm_scmi/system.c
Normal file
@ -0,0 +1,131 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* System Control and Management Interface (SCMI) System Power Protocol
|
||||
*
|
||||
* Copyright (C) 2020 ARM Ltd.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "SCMI Notifications SYSTEM - " fmt
|
||||
|
||||
#include <linux/scmi_protocol.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "notify.h"
|
||||
|
||||
#define SCMI_SYSTEM_NUM_SOURCES 1
|
||||
|
||||
enum scmi_system_protocol_cmd {
|
||||
SYSTEM_POWER_STATE_NOTIFY = 0x5,
|
||||
};
|
||||
|
||||
struct scmi_system_power_state_notify {
|
||||
__le32 notify_enable;
|
||||
};
|
||||
|
||||
struct scmi_system_power_state_notifier_payld {
|
||||
__le32 agent_id;
|
||||
__le32 flags;
|
||||
__le32 system_state;
|
||||
};
|
||||
|
||||
struct scmi_system_info {
|
||||
u32 version;
|
||||
};
|
||||
|
||||
static int scmi_system_request_notify(const struct scmi_handle *handle,
|
||||
bool enable)
|
||||
{
|
||||
int ret;
|
||||
struct scmi_xfer *t;
|
||||
struct scmi_system_power_state_notify *notify;
|
||||
|
||||
ret = scmi_xfer_get_init(handle, SYSTEM_POWER_STATE_NOTIFY,
|
||||
SCMI_PROTOCOL_SYSTEM, sizeof(*notify), 0, &t);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
notify = t->tx.buf;
|
||||
notify->notify_enable = enable ? cpu_to_le32(BIT(0)) : 0;
|
||||
|
||||
ret = scmi_do_xfer(handle, t);
|
||||
|
||||
scmi_xfer_put(handle, t);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int scmi_system_set_notify_enabled(const struct scmi_handle *handle,
|
||||
u8 evt_id, u32 src_id, bool enable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = scmi_system_request_notify(handle, enable);
|
||||
if (ret)
|
||||
pr_debug("FAIL_ENABLE - evt[%X] - ret:%d\n", evt_id, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *scmi_system_fill_custom_report(const struct scmi_handle *handle,
|
||||
u8 evt_id, ktime_t timestamp,
|
||||
const void *payld, size_t payld_sz,
|
||||
void *report, u32 *src_id)
|
||||
{
|
||||
const struct scmi_system_power_state_notifier_payld *p = payld;
|
||||
struct scmi_system_power_state_notifier_report *r = report;
|
||||
|
||||
if (evt_id != SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER ||
|
||||
sizeof(*p) != payld_sz)
|
||||
return NULL;
|
||||
|
||||
r->timestamp = timestamp;
|
||||
r->agent_id = le32_to_cpu(p->agent_id);
|
||||
r->flags = le32_to_cpu(p->flags);
|
||||
r->system_state = le32_to_cpu(p->system_state);
|
||||
*src_id = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static const struct scmi_event system_events[] = {
|
||||
{
|
||||
.id = SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER,
|
||||
.max_payld_sz =
|
||||
sizeof(struct scmi_system_power_state_notifier_payld),
|
||||
.max_report_sz =
|
||||
sizeof(struct scmi_system_power_state_notifier_report),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct scmi_event_ops system_event_ops = {
|
||||
.set_notify_enabled = scmi_system_set_notify_enabled,
|
||||
.fill_custom_report = scmi_system_fill_custom_report,
|
||||
};
|
||||
|
||||
static int scmi_system_protocol_init(struct scmi_handle *handle)
|
||||
{
|
||||
u32 version;
|
||||
struct scmi_system_info *pinfo;
|
||||
|
||||
scmi_version_get(handle, SCMI_PROTOCOL_SYSTEM, &version);
|
||||
|
||||
dev_dbg(handle->dev, "System Power Version %d.%d\n",
|
||||
PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
|
||||
|
||||
pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL);
|
||||
if (!pinfo)
|
||||
return -ENOMEM;
|
||||
|
||||
scmi_register_protocol_events(handle,
|
||||
SCMI_PROTOCOL_SYSTEM, SCMI_PROTO_QUEUE_SZ,
|
||||
&system_event_ops,
|
||||
system_events,
|
||||
ARRAY_SIZE(system_events),
|
||||
SCMI_SYSTEM_NUM_SOURCES);
|
||||
|
||||
pinfo->version = version;
|
||||
handle->system_priv = pinfo;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_SYSTEM, system)
|
@ -46,6 +46,7 @@
|
||||
|
||||
#include <dt-bindings/firmware/imx/rsrc.h>
|
||||
#include <linux/firmware/imx/sci.h>
|
||||
#include <linux/firmware/imx/svc/rm.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
@ -256,6 +257,9 @@ imx_scu_add_pm_domain(struct device *dev, int idx,
|
||||
struct imx_sc_pm_domain *sc_pd;
|
||||
int ret;
|
||||
|
||||
if (!imx_sc_rm_is_resource_owned(pm_ipc_handle, pd_ranges->rsrc + idx))
|
||||
return NULL;
|
||||
|
||||
sc_pd = devm_kzalloc(dev, sizeof(*sc_pd), GFP_KERNEL);
|
||||
if (!sc_pd)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
@ -24,8 +24,10 @@ enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void)
|
||||
|
||||
return smccc_conduit;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arm_smccc_1_1_get_conduit);
|
||||
|
||||
u32 arm_smccc_get_version(void)
|
||||
{
|
||||
return smccc_version;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arm_smccc_get_version);
|
||||
|
@ -856,7 +856,8 @@ static const struct tegra_bpmp_soc tegra210_soc = {
|
||||
|
||||
static const struct of_device_id tegra_bpmp_match[] = {
|
||||
#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \
|
||||
IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
|
||||
IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
|
||||
IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
|
||||
{ .compatible = "nvidia,tegra186-bpmp", .data = &tegra186_soc },
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
|
||||
|
@ -1106,7 +1106,8 @@ static int ti_sci_cmd_get_clock(const struct ti_sci_handle *handle, u32 dev_id,
|
||||
static int ti_sci_cmd_idle_clock(const struct ti_sci_handle *handle,
|
||||
u32 dev_id, u32 clk_id)
|
||||
{
|
||||
return ti_sci_set_clock_state(handle, dev_id, clk_id, 0,
|
||||
return ti_sci_set_clock_state(handle, dev_id, clk_id,
|
||||
MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE,
|
||||
MSG_CLOCK_SW_STATE_UNREQ);
|
||||
}
|
||||
|
||||
@ -1125,7 +1126,8 @@ static int ti_sci_cmd_idle_clock(const struct ti_sci_handle *handle,
|
||||
static int ti_sci_cmd_put_clock(const struct ti_sci_handle *handle,
|
||||
u32 dev_id, u32 clk_id)
|
||||
{
|
||||
return ti_sci_set_clock_state(handle, dev_id, clk_id, 0,
|
||||
return ti_sci_set_clock_state(handle, dev_id, clk_id,
|
||||
MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE,
|
||||
MSG_CLOCK_SW_STATE_AUTO);
|
||||
}
|
||||
|
||||
|
@ -481,7 +481,7 @@ static void mtk_drm_crtc_hw_config(struct mtk_drm_crtc *mtk_crtc)
|
||||
mbox_flush(mtk_crtc->cmdq_client->chan, 2000);
|
||||
cmdq_handle = cmdq_pkt_create(mtk_crtc->cmdq_client, PAGE_SIZE);
|
||||
cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event);
|
||||
cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event);
|
||||
cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event, false);
|
||||
mtk_crtc_ddp_config(crtc, cmdq_handle);
|
||||
cmdq_pkt_finalize(cmdq_handle);
|
||||
cmdq_pkt_flush_async(cmdq_handle, ddp_cmdq_cb, cmdq_handle);
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include <linux/pm.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <soc/tegra/fuse.h>
|
||||
|
||||
#include <dt-bindings/mailbox/tegra186-hsp.h>
|
||||
|
||||
#include "mailbox.h"
|
||||
@ -322,7 +324,12 @@ static int tegra_hsp_doorbell_startup(struct mbox_chan *chan)
|
||||
if (!ccplex)
|
||||
return -ENODEV;
|
||||
|
||||
if (!tegra_hsp_doorbell_can_ring(db))
|
||||
/*
|
||||
* On simulation platforms the BPMP hasn't had a chance yet to mark
|
||||
* the doorbell as ringable by the CCPLEX, so we want to skip extra
|
||||
* checks here.
|
||||
*/
|
||||
if (tegra_is_silicon() && !tegra_hsp_doorbell_can_ring(db))
|
||||
return -ENODEV;
|
||||
|
||||
spin_lock_irqsave(&hsp->lock, flags);
|
||||
|
@ -32,8 +32,9 @@ config ARM_PL172_MPMC
|
||||
|
||||
config ATMEL_SDRAMC
|
||||
bool "Atmel (Multi-port DDR-)SDRAM Controller"
|
||||
default y
|
||||
depends on ARCH_AT91 && OF
|
||||
default y if ARCH_AT91
|
||||
depends on ARCH_AT91 || COMPILE_TEST
|
||||
depends on OF
|
||||
help
|
||||
This driver is for Atmel SDRAM Controller or Atmel Multi-port
|
||||
DDR-SDRAM Controller available on Atmel AT91SAM9 and SAMA5 SoCs.
|
||||
@ -42,8 +43,9 @@ config ATMEL_SDRAMC
|
||||
|
||||
config ATMEL_EBI
|
||||
bool "Atmel EBI driver"
|
||||
default y
|
||||
depends on ARCH_AT91 && OF
|
||||
default y if ARCH_AT91
|
||||
depends on ARCH_AT91 || COMPILE_TEST
|
||||
depends on OF
|
||||
select MFD_SYSCON
|
||||
select MFD_ATMEL_SMC
|
||||
help
|
||||
@ -52,6 +54,18 @@ config ATMEL_EBI
|
||||
tree is used. This bus supports NANDs, external ethernet controller,
|
||||
SRAMs, ATA devices, etc.
|
||||
|
||||
config BRCMSTB_DPFE
|
||||
bool "Broadcom STB DPFE driver" if COMPILE_TEST
|
||||
default y if ARCH_BRCMSTB
|
||||
depends on ARCH_BRCMSTB || COMPILE_TEST
|
||||
help
|
||||
This driver provides access to the DPFE interface of Broadcom
|
||||
STB SoCs. The firmware running on the DCPU inside the DDR PHY can
|
||||
provide current information about the system's RAM, for instance
|
||||
the DRAM refresh rate. This can be used as an indirect indicator
|
||||
for the DRAM's temperature. Slower refresh rate means cooler RAM,
|
||||
higher refresh rate means hotter RAM.
|
||||
|
||||
config BT1_L2_CTL
|
||||
bool "Baikal-T1 CM2 L2-RAM Cache Control Block"
|
||||
depends on MIPS_BAIKAL_T1 || COMPILE_TEST
|
||||
@ -65,7 +79,8 @@ config BT1_L2_CTL
|
||||
|
||||
config TI_AEMIF
|
||||
tristate "Texas Instruments AEMIF driver"
|
||||
depends on (ARCH_DAVINCI || ARCH_KEYSTONE) && OF
|
||||
depends on ARCH_DAVINCI || ARCH_KEYSTONE || COMPILE_TEST
|
||||
depends on OF
|
||||
help
|
||||
This driver is for the AEMIF module available in Texas Instruments
|
||||
SoCs. AEMIF stands for Asynchronous External Memory Interface and
|
||||
@ -76,7 +91,7 @@ config TI_AEMIF
|
||||
|
||||
config TI_EMIF
|
||||
tristate "Texas Instruments EMIF driver"
|
||||
depends on ARCH_OMAP2PLUS
|
||||
depends on ARCH_OMAP2PLUS || COMPILE_TEST
|
||||
select DDR
|
||||
help
|
||||
This driver is for the EMIF module available in Texas Instruments
|
||||
@ -88,7 +103,8 @@ config TI_EMIF
|
||||
temperature changes
|
||||
|
||||
config OMAP_GPMC
|
||||
bool
|
||||
bool "Texas Instruments OMAP SoC GPMC driver" if COMPILE_TEST
|
||||
depends on OF_ADDRESS
|
||||
select GPIOLIB
|
||||
help
|
||||
This driver is for the General Purpose Memory Controller (GPMC)
|
||||
@ -112,7 +128,8 @@ config OMAP_GPMC_DEBUG
|
||||
|
||||
config TI_EMIF_SRAM
|
||||
tristate "Texas Instruments EMIF SRAM driver"
|
||||
depends on (SOC_AM33XX || SOC_AM43XX) && SRAM
|
||||
depends on SOC_AM33XX || SOC_AM43XX || (ARM && COMPILE_TEST)
|
||||
depends on SRAM
|
||||
help
|
||||
This driver is for the EMIF module available on Texas Instruments
|
||||
AM33XX and AM43XX SoCs and is required for PM. Certain parts of
|
||||
@ -122,8 +139,9 @@ config TI_EMIF_SRAM
|
||||
|
||||
config MVEBU_DEVBUS
|
||||
bool "Marvell EBU Device Bus Controller"
|
||||
default y
|
||||
depends on PLAT_ORION && OF
|
||||
default y if PLAT_ORION
|
||||
depends on PLAT_ORION || COMPILE_TEST
|
||||
depends on OF
|
||||
help
|
||||
This driver is for the Device Bus controller available in some
|
||||
Marvell EBU SoCs such as Discovery (mv78xx0), Orion (88f5xxx) and
|
||||
@ -132,7 +150,7 @@ config MVEBU_DEVBUS
|
||||
|
||||
config FSL_CORENET_CF
|
||||
tristate "Freescale CoreNet Error Reporting"
|
||||
depends on FSL_SOC_BOOKE
|
||||
depends on FSL_SOC_BOOKE || COMPILE_TEST
|
||||
help
|
||||
Say Y for reporting of errors from the Freescale CoreNet
|
||||
Coherency Fabric. Errors reported include accesses to
|
||||
@ -141,7 +159,7 @@ config FSL_CORENET_CF
|
||||
represents a coherency violation.
|
||||
|
||||
config FSL_IFC
|
||||
bool
|
||||
bool "Freescale IFC driver" if COMPILE_TEST
|
||||
depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A || COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
|
||||
@ -155,7 +173,7 @@ config JZ4780_NEMC
|
||||
memory devices such as NAND and SRAM.
|
||||
|
||||
config MTK_SMI
|
||||
bool
|
||||
bool "Mediatek SoC Memory Controller driver" if COMPILE_TEST
|
||||
depends on ARCH_MEDIATEK || COMPILE_TEST
|
||||
help
|
||||
This driver is for the Memory Controller module in MediaTek SoCs,
|
||||
@ -164,7 +182,7 @@ config MTK_SMI
|
||||
|
||||
config DA8XX_DDRCTL
|
||||
bool "Texas Instruments da8xx DDR2/mDDR driver"
|
||||
depends on ARCH_DAVINCI_DA8XX
|
||||
depends on ARCH_DAVINCI_DA8XX || COMPILE_TEST
|
||||
help
|
||||
This driver is for the DDR2/mDDR Memory Controller present on
|
||||
Texas Instruments da8xx SoCs. It's used to tweak various memory
|
||||
@ -172,16 +190,16 @@ config DA8XX_DDRCTL
|
||||
|
||||
config PL353_SMC
|
||||
tristate "ARM PL35X Static Memory Controller(SMC) driver"
|
||||
default y
|
||||
default y if ARM
|
||||
depends on ARM
|
||||
depends on ARM_AMBA
|
||||
depends on ARM_AMBA || COMPILE_TEST
|
||||
help
|
||||
This driver is for the ARM PL351/PL353 Static Memory
|
||||
Controller(SMC) module.
|
||||
|
||||
config RENESAS_RPCIF
|
||||
tristate "Renesas RPC-IF driver"
|
||||
depends on ARCH_RENESAS
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
This supports Renesas R-Car Gen3 RPC-IF which provides either SPI
|
||||
|
@ -10,7 +10,7 @@ endif
|
||||
obj-$(CONFIG_ARM_PL172_MPMC) += pl172.o
|
||||
obj-$(CONFIG_ATMEL_SDRAMC) += atmel-sdramc.o
|
||||
obj-$(CONFIG_ATMEL_EBI) += atmel-ebi.o
|
||||
obj-$(CONFIG_ARCH_BRCMSTB) += brcmstb_dpfe.o
|
||||
obj-$(CONFIG_BRCMSTB_DPFE) += brcmstb_dpfe.o
|
||||
obj-$(CONFIG_BT1_L2_CTL) += bt1-l2-ctl.o
|
||||
obj-$(CONFIG_TI_AEMIF) += ti-aemif.o
|
||||
obj-$(CONFIG_TI_EMIF) += emif.o
|
||||
|
@ -188,11 +188,6 @@ struct brcmstb_dpfe_priv {
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
static const char * const error_text[] = {
|
||||
"Success", "Header code incorrect", "Unknown command or argument",
|
||||
"Incorrect checksum", "Malformed command", "Timed out",
|
||||
};
|
||||
|
||||
/*
|
||||
* Forward declaration of our sysfs attribute functions, so we can declare the
|
||||
* attribute data structures early.
|
||||
@ -307,6 +302,20 @@ static const struct dpfe_api dpfe_api_v3 = {
|
||||
},
|
||||
};
|
||||
|
||||
static const char *get_error_text(unsigned int i)
|
||||
{
|
||||
static const char * const error_text[] = {
|
||||
"Success", "Header code incorrect",
|
||||
"Unknown command or argument", "Incorrect checksum",
|
||||
"Malformed command", "Timed out", "Unknown error",
|
||||
};
|
||||
|
||||
if (unlikely(i >= ARRAY_SIZE(error_text)))
|
||||
i = ARRAY_SIZE(error_text) - 1;
|
||||
|
||||
return error_text[i];
|
||||
}
|
||||
|
||||
static bool is_dcpu_enabled(struct brcmstb_dpfe_priv *priv)
|
||||
{
|
||||
u32 val;
|
||||
@ -445,7 +454,7 @@ static int __send_command(struct brcmstb_dpfe_priv *priv, unsigned int cmd,
|
||||
}
|
||||
if (resp != 0) {
|
||||
mutex_unlock(&priv->lock);
|
||||
return -ETIMEDOUT;
|
||||
return -ffs(DCPU_RET_ERR_TIMEDOUT);
|
||||
}
|
||||
|
||||
/* Compute checksum over the message */
|
||||
@ -647,8 +656,10 @@ static int brcmstb_dpfe_download_firmware(struct brcmstb_dpfe_priv *priv)
|
||||
return (ret == -ENOENT) ? -EPROBE_DEFER : ret;
|
||||
|
||||
ret = __verify_firmware(&init, fw);
|
||||
if (ret)
|
||||
return -EFAULT;
|
||||
if (ret) {
|
||||
ret = -EFAULT;
|
||||
goto release_fw;
|
||||
}
|
||||
|
||||
__disable_dcpu(priv);
|
||||
|
||||
@ -667,18 +678,20 @@ static int brcmstb_dpfe_download_firmware(struct brcmstb_dpfe_priv *priv)
|
||||
|
||||
ret = __write_firmware(priv->dmem, dmem, dmem_size, is_big_endian);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto release_fw;
|
||||
ret = __write_firmware(priv->imem, imem, imem_size, is_big_endian);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto release_fw;
|
||||
|
||||
ret = __verify_fw_checksum(&init, priv, header, init.chksum);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto release_fw;
|
||||
|
||||
__enable_dcpu(priv);
|
||||
|
||||
return 0;
|
||||
release_fw:
|
||||
release_firmware(fw);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t generic_show(unsigned int command, u32 response[],
|
||||
@ -691,7 +704,7 @@ static ssize_t generic_show(unsigned int command, u32 response[],
|
||||
|
||||
ret = __send_command(priv, command, response);
|
||||
if (ret < 0)
|
||||
return sprintf(buf, "ERROR: %s\n", error_text[-ret]);
|
||||
return sprintf(buf, "ERROR: %s\n", get_error_text(-ret));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -888,11 +901,8 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
ret = brcmstb_dpfe_download_firmware(priv);
|
||||
if (ret) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "Couldn't download firmware -- %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Couldn't download firmware\n");
|
||||
|
||||
ret = sysfs_create_groups(&pdev->dev.kobj, priv->dpfe_api->sysfs_attrs);
|
||||
if (!ret)
|
||||
|
@ -131,16 +131,7 @@ static int emif_regdump_show(struct seq_file *s, void *unused)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emif_regdump_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, emif_regdump_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations emif_regdump_fops = {
|
||||
.open = emif_regdump_open,
|
||||
.read = seq_read,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(emif_regdump);
|
||||
|
||||
static int emif_mr4_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
@ -150,48 +141,16 @@ static int emif_mr4_show(struct seq_file *s, void *unused)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emif_mr4_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, emif_mr4_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations emif_mr4_fops = {
|
||||
.open = emif_mr4_open,
|
||||
.read = seq_read,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(emif_mr4);
|
||||
|
||||
static int __init_or_module emif_debugfs_init(struct emif_data *emif)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
int ret;
|
||||
|
||||
dentry = debugfs_create_dir(dev_name(emif->dev), NULL);
|
||||
if (!dentry) {
|
||||
ret = -ENOMEM;
|
||||
goto err0;
|
||||
}
|
||||
emif->debugfs_root = dentry;
|
||||
|
||||
dentry = debugfs_create_file("regcache_dump", S_IRUGO,
|
||||
emif->debugfs_root, emif, &emif_regdump_fops);
|
||||
if (!dentry) {
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
dentry = debugfs_create_file("mr4", S_IRUGO,
|
||||
emif->debugfs_root, emif, &emif_mr4_fops);
|
||||
if (!dentry) {
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
emif->debugfs_root = debugfs_create_dir(dev_name(emif->dev), NULL);
|
||||
debugfs_create_file("regcache_dump", S_IRUGO, emif->debugfs_root, emif,
|
||||
&emif_regdump_fops);
|
||||
debugfs_create_file("mr4", S_IRUGO, emif->debugfs_root, emif,
|
||||
&emif_mr4_fops);
|
||||
return 0;
|
||||
err1:
|
||||
debugfs_remove_recursive(emif->debugfs_root);
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit emif_debugfs_exit(struct emif_data *emif)
|
||||
|
@ -211,10 +211,8 @@ static int ccf_probe(struct platform_device *pdev)
|
||||
dev_set_drvdata(&pdev->dev, ccf);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (!irq) {
|
||||
dev_err(&pdev->dev, "%s: no irq\n", __func__);
|
||||
return -ENXIO;
|
||||
}
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, irq, ccf_irq, 0, pdev->name, ccf);
|
||||
if (ret) {
|
||||
|
@ -19,6 +19,9 @@
|
||||
/* mt8173 */
|
||||
#define SMI_LARB_MMU_EN 0xf00
|
||||
|
||||
/* mt8167 */
|
||||
#define MT8167_SMI_LARB_MMU_EN 0xfc0
|
||||
|
||||
/* mt2701 */
|
||||
#define REG_SMI_SECUR_CON_BASE 0x5c0
|
||||
|
||||
@ -179,6 +182,13 @@ static void mtk_smi_larb_config_port_mt8173(struct device *dev)
|
||||
writel(*larb->mmu, larb->base + SMI_LARB_MMU_EN);
|
||||
}
|
||||
|
||||
static void mtk_smi_larb_config_port_mt8167(struct device *dev)
|
||||
{
|
||||
struct mtk_smi_larb *larb = dev_get_drvdata(dev);
|
||||
|
||||
writel(*larb->mmu, larb->base + MT8167_SMI_LARB_MMU_EN);
|
||||
}
|
||||
|
||||
static void mtk_smi_larb_config_port_gen1(struct device *dev)
|
||||
{
|
||||
struct mtk_smi_larb *larb = dev_get_drvdata(dev);
|
||||
@ -226,6 +236,11 @@ static const struct mtk_smi_larb_gen mtk_smi_larb_mt8173 = {
|
||||
.config_port = mtk_smi_larb_config_port_mt8173,
|
||||
};
|
||||
|
||||
static const struct mtk_smi_larb_gen mtk_smi_larb_mt8167 = {
|
||||
/* mt8167 do not need the port in larb */
|
||||
.config_port = mtk_smi_larb_config_port_mt8167,
|
||||
};
|
||||
|
||||
static const struct mtk_smi_larb_gen mtk_smi_larb_mt2701 = {
|
||||
.port_in_larb = {
|
||||
LARB0_PORT_OFFSET, LARB1_PORT_OFFSET,
|
||||
@ -254,6 +269,10 @@ static const struct mtk_smi_larb_gen mtk_smi_larb_mt8183 = {
|
||||
};
|
||||
|
||||
static const struct of_device_id mtk_smi_larb_of_ids[] = {
|
||||
{
|
||||
.compatible = "mediatek,mt8167-smi-larb",
|
||||
.data = &mtk_smi_larb_mt8167
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt8173-smi-larb",
|
||||
.data = &mtk_smi_larb_mt8173
|
||||
@ -418,6 +437,10 @@ static const struct of_device_id mtk_smi_common_of_ids[] = {
|
||||
.compatible = "mediatek,mt8173-smi-common",
|
||||
.data = &mtk_smi_common_gen2,
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt8167-smi-common",
|
||||
.data = &mtk_smi_common_gen2,
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt2701-smi-common",
|
||||
.data = &mtk_smi_common_gen1,
|
||||
|
@ -33,8 +33,6 @@
|
||||
|
||||
#include <linux/platform_data/mtd-nand-omap2.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#define DEVICE_NAME "omap-gpmc"
|
||||
|
||||
/* GPMC register offsets */
|
||||
@ -245,7 +243,6 @@ static DEFINE_SPINLOCK(gpmc_mem_lock);
|
||||
/* Define chip-selects as reserved by default until probe completes */
|
||||
static unsigned int gpmc_cs_num = GPMC_CS_NUM;
|
||||
static unsigned int gpmc_nr_waitpins;
|
||||
static resource_size_t phys_base, mem_size;
|
||||
static unsigned int gpmc_capability;
|
||||
static void __iomem *gpmc_base;
|
||||
|
||||
@ -634,14 +631,6 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, int max
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define GPMC_SET_ONE_CD_MAX(reg, st, end, max, field, cd) \
|
||||
if (set_gpmc_timing_reg(cs, (reg), (st), (end), (max), \
|
||||
t->field, (cd), #field) < 0) \
|
||||
return -1
|
||||
|
||||
#define GPMC_SET_ONE(reg, st, end, field) \
|
||||
GPMC_SET_ONE_CD_MAX(reg, st, end, 0, field, GPMC_CD_FCLK)
|
||||
|
||||
/**
|
||||
* gpmc_calc_waitmonitoring_divider - calculate proper GPMCFCLKDIVIDER based on WAITMONITORINGTIME
|
||||
* WAITMONITORINGTIME will be _at least_ as long as desired, i.e.
|
||||
@ -700,12 +689,12 @@ int gpmc_calc_divider(unsigned int sync_clk)
|
||||
int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t,
|
||||
const struct gpmc_settings *s)
|
||||
{
|
||||
int div;
|
||||
int div, ret;
|
||||
u32 l;
|
||||
|
||||
div = gpmc_calc_divider(t->sync_clk);
|
||||
if (div < 0)
|
||||
return div;
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* See if we need to change the divider for waitmonitoringtime.
|
||||
@ -729,57 +718,114 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t,
|
||||
__func__,
|
||||
t->wait_monitoring
|
||||
);
|
||||
return -1;
|
||||
return -ENXIO;
|
||||
}
|
||||
}
|
||||
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG2, 0, 3, cs_on);
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG2, 8, 12, cs_rd_off);
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG2, 16, 20, cs_wr_off);
|
||||
ret = 0;
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG2, 0, 3, 0, t->cs_on,
|
||||
GPMC_CD_FCLK, "cs_on");
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG2, 8, 12, 0, t->cs_rd_off,
|
||||
GPMC_CD_FCLK, "cs_rd_off");
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG2, 16, 20, 0, t->cs_wr_off,
|
||||
GPMC_CD_FCLK, "cs_wr_off");
|
||||
if (ret)
|
||||
return -ENXIO;
|
||||
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 0, 3, 0, t->adv_on,
|
||||
GPMC_CD_FCLK, "adv_on");
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 8, 12, 0, t->adv_rd_off,
|
||||
GPMC_CD_FCLK, "adv_rd_off");
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 16, 20, 0, t->adv_wr_off,
|
||||
GPMC_CD_FCLK, "adv_wr_off");
|
||||
if (ret)
|
||||
return -ENXIO;
|
||||
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG3, 0, 3, adv_on);
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG3, 8, 12, adv_rd_off);
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG3, 16, 20, adv_wr_off);
|
||||
if (gpmc_capability & GPMC_HAS_MUX_AAD) {
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG3, 4, 6, adv_aad_mux_on);
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG3, 24, 26, adv_aad_mux_rd_off);
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG3, 28, 30, adv_aad_mux_wr_off);
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 4, 6, 0,
|
||||
t->adv_aad_mux_on, GPMC_CD_FCLK,
|
||||
"adv_aad_mux_on");
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 24, 26, 0,
|
||||
t->adv_aad_mux_rd_off, GPMC_CD_FCLK,
|
||||
"adv_aad_mux_rd_off");
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 28, 30, 0,
|
||||
t->adv_aad_mux_wr_off, GPMC_CD_FCLK,
|
||||
"adv_aad_mux_wr_off");
|
||||
if (ret)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG4, 0, 3, oe_on);
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG4, 8, 12, oe_off);
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 0, 3, 0, t->oe_on,
|
||||
GPMC_CD_FCLK, "oe_on");
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 8, 12, 0, t->oe_off,
|
||||
GPMC_CD_FCLK, "oe_off");
|
||||
if (gpmc_capability & GPMC_HAS_MUX_AAD) {
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG4, 4, 6, oe_aad_mux_on);
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG4, 13, 15, oe_aad_mux_off);
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 4, 6, 0,
|
||||
t->oe_aad_mux_on, GPMC_CD_FCLK,
|
||||
"oe_aad_mux_on");
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 13, 15, 0,
|
||||
t->oe_aad_mux_off, GPMC_CD_FCLK,
|
||||
"oe_aad_mux_off");
|
||||
}
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG4, 16, 19, we_on);
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG4, 24, 28, we_off);
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 16, 19, 0, t->we_on,
|
||||
GPMC_CD_FCLK, "we_on");
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 24, 28, 0, t->we_off,
|
||||
GPMC_CD_FCLK, "we_off");
|
||||
if (ret)
|
||||
return -ENXIO;
|
||||
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG5, 0, 4, rd_cycle);
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG5, 8, 12, wr_cycle);
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG5, 16, 20, access);
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG5, 0, 4, 0, t->rd_cycle,
|
||||
GPMC_CD_FCLK, "rd_cycle");
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG5, 8, 12, 0, t->wr_cycle,
|
||||
GPMC_CD_FCLK, "wr_cycle");
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG5, 16, 20, 0, t->access,
|
||||
GPMC_CD_FCLK, "access");
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG5, 24, 27, 0,
|
||||
t->page_burst_access, GPMC_CD_FCLK,
|
||||
"page_burst_access");
|
||||
if (ret)
|
||||
return -ENXIO;
|
||||
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG5, 24, 27, page_burst_access);
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG6, 0, 3, 0,
|
||||
t->bus_turnaround, GPMC_CD_FCLK,
|
||||
"bus_turnaround");
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG6, 8, 11, 0,
|
||||
t->cycle2cycle_delay, GPMC_CD_FCLK,
|
||||
"cycle2cycle_delay");
|
||||
if (ret)
|
||||
return -ENXIO;
|
||||
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG6, 0, 3, bus_turnaround);
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG6, 8, 11, cycle2cycle_delay);
|
||||
|
||||
if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG6, 16, 19, wr_data_mux_bus);
|
||||
if (gpmc_capability & GPMC_HAS_WR_ACCESS)
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access);
|
||||
if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS) {
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG6, 16, 19, 0,
|
||||
t->wr_data_mux_bus, GPMC_CD_FCLK,
|
||||
"wr_data_mux_bus");
|
||||
if (ret)
|
||||
return -ENXIO;
|
||||
}
|
||||
if (gpmc_capability & GPMC_HAS_WR_ACCESS) {
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG6, 24, 28, 0,
|
||||
t->wr_access, GPMC_CD_FCLK,
|
||||
"wr_access");
|
||||
if (ret)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
|
||||
l &= ~0x03;
|
||||
l |= (div - 1);
|
||||
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
|
||||
|
||||
GPMC_SET_ONE_CD_MAX(GPMC_CS_CONFIG1, 18, 19,
|
||||
GPMC_CONFIG1_WAITMONITORINGTIME_MAX,
|
||||
wait_monitoring, GPMC_CD_CLK);
|
||||
GPMC_SET_ONE_CD_MAX(GPMC_CS_CONFIG1, 25, 26,
|
||||
GPMC_CONFIG1_CLKACTIVATIONTIME_MAX,
|
||||
clk_activation, GPMC_CD_FCLK);
|
||||
ret = 0;
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG1, 18, 19,
|
||||
GPMC_CONFIG1_WAITMONITORINGTIME_MAX,
|
||||
t->wait_monitoring, GPMC_CD_CLK,
|
||||
"wait_monitoring");
|
||||
ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG1, 25, 26,
|
||||
GPMC_CONFIG1_CLKACTIVATIONTIME_MAX,
|
||||
t->clk_activation, GPMC_CD_FCLK,
|
||||
"clk_activation");
|
||||
if (ret)
|
||||
return -ENXIO;
|
||||
|
||||
#ifdef CONFIG_OMAP_GPMC_DEBUG
|
||||
pr_info("GPMC CS%d CLK period is %lu ns (div %d)\n",
|
||||
@ -870,20 +916,6 @@ static bool gpmc_cs_reserved(int cs)
|
||||
return gpmc->flags & GPMC_CS_RESERVED;
|
||||
}
|
||||
|
||||
static void gpmc_cs_set_name(int cs, const char *name)
|
||||
{
|
||||
struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
|
||||
|
||||
gpmc->name = name;
|
||||
}
|
||||
|
||||
static const char *gpmc_cs_get_name(int cs)
|
||||
{
|
||||
struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
|
||||
|
||||
return gpmc->name;
|
||||
}
|
||||
|
||||
static unsigned long gpmc_mem_align(unsigned long size)
|
||||
{
|
||||
int order;
|
||||
@ -929,56 +961,13 @@ static int gpmc_cs_delete_mem(int cs)
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* gpmc_cs_remap - remaps a chip-select physical base address
|
||||
* @cs: chip-select to remap
|
||||
* @base: physical base address to re-map chip-select to
|
||||
*
|
||||
* Re-maps a chip-select to a new physical base address specified by
|
||||
* "base". Returns 0 on success and appropriate negative error code
|
||||
* on failure.
|
||||
*/
|
||||
static int gpmc_cs_remap(int cs, u32 base)
|
||||
{
|
||||
int ret;
|
||||
u32 old_base, size;
|
||||
|
||||
if (cs > gpmc_cs_num) {
|
||||
pr_err("%s: requested chip-select is disabled\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure we ignore any device offsets from the GPMC partition
|
||||
* allocated for the chip select and that the new base confirms
|
||||
* to the GPMC 16MB minimum granularity.
|
||||
*/
|
||||
base &= ~(SZ_16M - 1);
|
||||
|
||||
gpmc_cs_get_memconf(cs, &old_base, &size);
|
||||
if (base == old_base)
|
||||
return 0;
|
||||
|
||||
ret = gpmc_cs_delete_mem(cs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = gpmc_cs_insert_mem(cs, base, size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = gpmc_cs_set_memconf(cs, base, size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
|
||||
{
|
||||
struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
|
||||
struct resource *res = &gpmc->mem;
|
||||
int r = -1;
|
||||
|
||||
if (cs > gpmc_cs_num) {
|
||||
if (cs >= gpmc_cs_num) {
|
||||
pr_err("%s: requested chip-select is disabled\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
@ -1025,8 +1014,7 @@ void gpmc_cs_free(int cs)
|
||||
|
||||
spin_lock(&gpmc_mem_lock);
|
||||
if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) {
|
||||
printk(KERN_ERR "Trying to free non-reserved GPMC CS%d\n", cs);
|
||||
BUG();
|
||||
WARN(1, "Trying to free non-reserved GPMC CS%d\n", cs);
|
||||
spin_unlock(&gpmc_mem_lock);
|
||||
return;
|
||||
}
|
||||
@ -1896,6 +1884,63 @@ static const struct of_device_id gpmc_dt_ids[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
static void gpmc_cs_set_name(int cs, const char *name)
|
||||
{
|
||||
struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
|
||||
|
||||
gpmc->name = name;
|
||||
}
|
||||
|
||||
static const char *gpmc_cs_get_name(int cs)
|
||||
{
|
||||
struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
|
||||
|
||||
return gpmc->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* gpmc_cs_remap - remaps a chip-select physical base address
|
||||
* @cs: chip-select to remap
|
||||
* @base: physical base address to re-map chip-select to
|
||||
*
|
||||
* Re-maps a chip-select to a new physical base address specified by
|
||||
* "base". Returns 0 on success and appropriate negative error code
|
||||
* on failure.
|
||||
*/
|
||||
static int gpmc_cs_remap(int cs, u32 base)
|
||||
{
|
||||
int ret;
|
||||
u32 old_base, size;
|
||||
|
||||
if (cs >= gpmc_cs_num) {
|
||||
pr_err("%s: requested chip-select is disabled\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure we ignore any device offsets from the GPMC partition
|
||||
* allocated for the chip select and that the new base confirms
|
||||
* to the GPMC 16MB minimum granularity.
|
||||
*/
|
||||
base &= ~(SZ_16M - 1);
|
||||
|
||||
gpmc_cs_get_memconf(cs, &old_base, &size);
|
||||
if (base == old_base)
|
||||
return 0;
|
||||
|
||||
ret = gpmc_cs_delete_mem(cs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = gpmc_cs_insert_mem(cs, base, size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = gpmc_cs_set_memconf(cs, base, size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* gpmc_read_settings_dt - read gpmc settings from device-tree
|
||||
* @np: pointer to device-tree node for a gpmc child device
|
||||
@ -2265,6 +2310,10 @@ static void gpmc_probe_dt_children(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
#else
|
||||
void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p)
|
||||
{
|
||||
memset(p, 0, sizeof(*p));
|
||||
}
|
||||
static int gpmc_probe_dt(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
@ -2347,12 +2396,9 @@ static int gpmc_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, gpmc);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (res == NULL)
|
||||
if (!res)
|
||||
return -ENOENT;
|
||||
|
||||
phys_base = res->start;
|
||||
mem_size = resource_size(res);
|
||||
|
||||
gpmc_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(gpmc_base))
|
||||
return PTR_ERR(gpmc_base);
|
||||
|
@ -199,10 +199,8 @@ int rpcif_sw_init(struct rpcif *rpc, struct device *dev)
|
||||
rpc->dirmap = NULL;
|
||||
|
||||
rpc->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
|
||||
if (IS_ERR(rpc->rstc))
|
||||
return PTR_ERR(rpc->rstc);
|
||||
|
||||
return 0;
|
||||
return PTR_ERR_OR_ZERO(rpc->rstc);
|
||||
}
|
||||
EXPORT_SYMBOL(rpcif_sw_init);
|
||||
|
||||
|
@ -98,6 +98,8 @@ MODULE_PARM_DESC(irqmode, "Enable IRQ mode (0=off [default], 1=on)");
|
||||
|
||||
/**
|
||||
* struct dmc_opp_table - Operating level desciption
|
||||
* @freq_hz: target frequency in Hz
|
||||
* @volt_uv: target voltage in uV
|
||||
*
|
||||
* Covers frequency and voltage settings of the DMC operating mode.
|
||||
*/
|
||||
@ -108,6 +110,41 @@ struct dmc_opp_table {
|
||||
|
||||
/**
|
||||
* struct exynos5_dmc - main structure describing DMC device
|
||||
* @dev: DMC device
|
||||
* @df: devfreq device structure returned by devfreq framework
|
||||
* @gov_data: configuration of devfreq governor
|
||||
* @base_drexi0: DREX0 registers mapping
|
||||
* @base_drexi1: DREX1 registers mapping
|
||||
* @clk_regmap: regmap for clock controller registers
|
||||
* @lock: protects curr_rate and frequency/voltage setting section
|
||||
* @curr_rate: current frequency
|
||||
* @curr_volt: current voltage
|
||||
* @opp: OPP table
|
||||
* @opp_count: number of 'opp' elements
|
||||
* @timings_arr_size: number of 'timings' elements
|
||||
* @timing_row: values for timing row register, for each OPP
|
||||
* @timing_data: values for timing data register, for each OPP
|
||||
* @timing_power: balues for timing power register, for each OPP
|
||||
* @timings: DDR memory timings, from device tree
|
||||
* @min_tck: DDR memory minimum timing values, from device tree
|
||||
* @bypass_timing_row: value for timing row register for bypass timings
|
||||
* @bypass_timing_data: value for timing data register for bypass timings
|
||||
* @bypass_timing_power: value for timing power register for bypass
|
||||
* timings
|
||||
* @vdd_mif: Memory interface regulator
|
||||
* @fout_spll: clock: SPLL
|
||||
* @fout_bpll: clock: BPLL
|
||||
* @mout_spll: clock: mux SPLL
|
||||
* @mout_bpll: clock: mux BPLL
|
||||
* @mout_mclk_cdrex: clock: mux mclk_cdrex
|
||||
* @mout_mx_mspll_ccore: clock: mux mx_mspll_ccore
|
||||
* @counter: devfreq events
|
||||
* @num_counters: number of 'counter' elements
|
||||
* @last_overflow_ts: time (in ns) of last overflow of each DREX
|
||||
* @load: utilization in percents
|
||||
* @total: total time between devfreq events
|
||||
* @in_irq_mode: whether running in interrupt mode (true)
|
||||
* or polling (false)
|
||||
*
|
||||
* The main structure for the Dynamic Memory Controller which covers clocks,
|
||||
* memory regions, HW information, parameters and current operating mode.
|
||||
@ -119,12 +156,11 @@ struct exynos5_dmc {
|
||||
void __iomem *base_drexi0;
|
||||
void __iomem *base_drexi1;
|
||||
struct regmap *clk_regmap;
|
||||
/* Protects curr_rate and frequency/voltage setting section */
|
||||
struct mutex lock;
|
||||
unsigned long curr_rate;
|
||||
unsigned long curr_volt;
|
||||
unsigned long bypass_rate;
|
||||
struct dmc_opp_table *opp;
|
||||
struct dmc_opp_table opp_bypass;
|
||||
int opp_count;
|
||||
u32 timings_arr_size;
|
||||
u32 *timing_row;
|
||||
@ -142,8 +178,6 @@ struct exynos5_dmc {
|
||||
struct clk *mout_bpll;
|
||||
struct clk *mout_mclk_cdrex;
|
||||
struct clk *mout_mx_mspll_ccore;
|
||||
struct clk *mx_mspll_ccore_phy;
|
||||
struct clk *mout_mx_mspll_ccore_phy;
|
||||
struct devfreq_event_dev **counter;
|
||||
int num_counters;
|
||||
u64 last_overflow_ts[2];
|
||||
@ -169,7 +203,7 @@ struct timing_reg {
|
||||
unsigned int val;
|
||||
};
|
||||
|
||||
static const struct timing_reg timing_row[] = {
|
||||
static const struct timing_reg timing_row_reg_fields[] = {
|
||||
TIMING_FIELD("tRFC", 24, 31),
|
||||
TIMING_FIELD("tRRD", 20, 23),
|
||||
TIMING_FIELD("tRP", 16, 19),
|
||||
@ -178,7 +212,7 @@ static const struct timing_reg timing_row[] = {
|
||||
TIMING_FIELD("tRAS", 0, 5),
|
||||
};
|
||||
|
||||
static const struct timing_reg timing_data[] = {
|
||||
static const struct timing_reg timing_data_reg_fields[] = {
|
||||
TIMING_FIELD("tWTR", 28, 31),
|
||||
TIMING_FIELD("tWR", 24, 27),
|
||||
TIMING_FIELD("tRTP", 20, 23),
|
||||
@ -189,7 +223,7 @@ static const struct timing_reg timing_data[] = {
|
||||
TIMING_FIELD("RL", 0, 3),
|
||||
};
|
||||
|
||||
static const struct timing_reg timing_power[] = {
|
||||
static const struct timing_reg timing_power_reg_fields[] = {
|
||||
TIMING_FIELD("tFAW", 26, 31),
|
||||
TIMING_FIELD("tXSR", 16, 25),
|
||||
TIMING_FIELD("tXP", 8, 15),
|
||||
@ -197,8 +231,9 @@ static const struct timing_reg timing_power[] = {
|
||||
TIMING_FIELD("tMRD", 0, 3),
|
||||
};
|
||||
|
||||
#define TIMING_COUNT (ARRAY_SIZE(timing_row) + ARRAY_SIZE(timing_data) + \
|
||||
ARRAY_SIZE(timing_power))
|
||||
#define TIMING_COUNT (ARRAY_SIZE(timing_row_reg_fields) + \
|
||||
ARRAY_SIZE(timing_data_reg_fields) + \
|
||||
ARRAY_SIZE(timing_power_reg_fields))
|
||||
|
||||
static int exynos5_counters_set_event(struct exynos5_dmc *dmc)
|
||||
{
|
||||
@ -346,7 +381,6 @@ err_opp:
|
||||
/**
|
||||
* exynos5_set_bypass_dram_timings() - Low-level changes of the DRAM timings
|
||||
* @dmc: device for which the new settings is going to be applied
|
||||
* @param: DRAM parameters which passes timing data
|
||||
*
|
||||
* Low-level function for changing timings for DRAM memory clocking from
|
||||
* 'bypass' clock source (fixed frequency @400MHz).
|
||||
@ -453,9 +487,6 @@ static int exynos5_dmc_align_bypass_voltage(struct exynos5_dmc *dmc,
|
||||
unsigned long target_volt)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long bypass_volt = dmc->opp_bypass.volt_uv;
|
||||
|
||||
target_volt = max(bypass_volt, target_volt);
|
||||
|
||||
if (dmc->curr_volt >= target_volt)
|
||||
return 0;
|
||||
@ -617,6 +648,7 @@ disable_clocks:
|
||||
* requested
|
||||
* @target_volt: returned voltage which corresponds to the returned
|
||||
* frequency
|
||||
* @flags: devfreq flags provided for this frequency change request
|
||||
*
|
||||
* Function gets requested frequency and checks OPP framework for needed
|
||||
* frequency and voltage. It populates the values 'target_rate' and
|
||||
@ -908,7 +940,10 @@ static int exynos5_dmc_get_status(struct device *dev,
|
||||
int ret;
|
||||
|
||||
if (dmc->in_irq_mode) {
|
||||
mutex_lock(&dmc->lock);
|
||||
stat->current_frequency = dmc->curr_rate;
|
||||
mutex_unlock(&dmc->lock);
|
||||
|
||||
stat->busy_time = dmc->load;
|
||||
stat->total_time = dmc->total;
|
||||
} else {
|
||||
@ -950,7 +985,7 @@ static int exynos5_dmc_get_cur_freq(struct device *dev, unsigned long *freq)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* exynos5_dmc_df_profile - Devfreq governor's profile structure
|
||||
*
|
||||
* It provides to the devfreq framework needed functions and polling period.
|
||||
@ -993,7 +1028,9 @@ exynos5_dmc_align_init_freq(struct exynos5_dmc *dmc,
|
||||
/**
|
||||
* create_timings_aligned() - Create register values and align with standard
|
||||
* @dmc: device for which the frequency is going to be set
|
||||
* @idx: speed bin in the OPP table
|
||||
* @reg_timing_row: array to fill with values for timing row register
|
||||
* @reg_timing_data: array to fill with values for timing data register
|
||||
* @reg_timing_power: array to fill with values for timing power register
|
||||
* @clk_period_ps: the period of the clock, known as tCK
|
||||
*
|
||||
* The function calculates timings and creates a register value ready for
|
||||
@ -1018,117 +1055,117 @@ static int create_timings_aligned(struct exynos5_dmc *dmc, u32 *reg_timing_row,
|
||||
val = dmc->timings->tRFC / clk_period_ps;
|
||||
val += dmc->timings->tRFC % clk_period_ps ? 1 : 0;
|
||||
val = max(val, dmc->min_tck->tRFC);
|
||||
reg = &timing_row[0];
|
||||
reg = &timing_row_reg_fields[0];
|
||||
*reg_timing_row |= TIMING_VAL2REG(reg, val);
|
||||
|
||||
val = dmc->timings->tRRD / clk_period_ps;
|
||||
val += dmc->timings->tRRD % clk_period_ps ? 1 : 0;
|
||||
val = max(val, dmc->min_tck->tRRD);
|
||||
reg = &timing_row[1];
|
||||
reg = &timing_row_reg_fields[1];
|
||||
*reg_timing_row |= TIMING_VAL2REG(reg, val);
|
||||
|
||||
val = dmc->timings->tRPab / clk_period_ps;
|
||||
val += dmc->timings->tRPab % clk_period_ps ? 1 : 0;
|
||||
val = max(val, dmc->min_tck->tRPab);
|
||||
reg = &timing_row[2];
|
||||
reg = &timing_row_reg_fields[2];
|
||||
*reg_timing_row |= TIMING_VAL2REG(reg, val);
|
||||
|
||||
val = dmc->timings->tRCD / clk_period_ps;
|
||||
val += dmc->timings->tRCD % clk_period_ps ? 1 : 0;
|
||||
val = max(val, dmc->min_tck->tRCD);
|
||||
reg = &timing_row[3];
|
||||
reg = &timing_row_reg_fields[3];
|
||||
*reg_timing_row |= TIMING_VAL2REG(reg, val);
|
||||
|
||||
val = dmc->timings->tRC / clk_period_ps;
|
||||
val += dmc->timings->tRC % clk_period_ps ? 1 : 0;
|
||||
val = max(val, dmc->min_tck->tRC);
|
||||
reg = &timing_row[4];
|
||||
reg = &timing_row_reg_fields[4];
|
||||
*reg_timing_row |= TIMING_VAL2REG(reg, val);
|
||||
|
||||
val = dmc->timings->tRAS / clk_period_ps;
|
||||
val += dmc->timings->tRAS % clk_period_ps ? 1 : 0;
|
||||
val = max(val, dmc->min_tck->tRAS);
|
||||
reg = &timing_row[5];
|
||||
reg = &timing_row_reg_fields[5];
|
||||
*reg_timing_row |= TIMING_VAL2REG(reg, val);
|
||||
|
||||
/* data related timings */
|
||||
val = dmc->timings->tWTR / clk_period_ps;
|
||||
val += dmc->timings->tWTR % clk_period_ps ? 1 : 0;
|
||||
val = max(val, dmc->min_tck->tWTR);
|
||||
reg = &timing_data[0];
|
||||
reg = &timing_data_reg_fields[0];
|
||||
*reg_timing_data |= TIMING_VAL2REG(reg, val);
|
||||
|
||||
val = dmc->timings->tWR / clk_period_ps;
|
||||
val += dmc->timings->tWR % clk_period_ps ? 1 : 0;
|
||||
val = max(val, dmc->min_tck->tWR);
|
||||
reg = &timing_data[1];
|
||||
reg = &timing_data_reg_fields[1];
|
||||
*reg_timing_data |= TIMING_VAL2REG(reg, val);
|
||||
|
||||
val = dmc->timings->tRTP / clk_period_ps;
|
||||
val += dmc->timings->tRTP % clk_period_ps ? 1 : 0;
|
||||
val = max(val, dmc->min_tck->tRTP);
|
||||
reg = &timing_data[2];
|
||||
reg = &timing_data_reg_fields[2];
|
||||
*reg_timing_data |= TIMING_VAL2REG(reg, val);
|
||||
|
||||
val = dmc->timings->tW2W_C2C / clk_period_ps;
|
||||
val += dmc->timings->tW2W_C2C % clk_period_ps ? 1 : 0;
|
||||
val = max(val, dmc->min_tck->tW2W_C2C);
|
||||
reg = &timing_data[3];
|
||||
reg = &timing_data_reg_fields[3];
|
||||
*reg_timing_data |= TIMING_VAL2REG(reg, val);
|
||||
|
||||
val = dmc->timings->tR2R_C2C / clk_period_ps;
|
||||
val += dmc->timings->tR2R_C2C % clk_period_ps ? 1 : 0;
|
||||
val = max(val, dmc->min_tck->tR2R_C2C);
|
||||
reg = &timing_data[4];
|
||||
reg = &timing_data_reg_fields[4];
|
||||
*reg_timing_data |= TIMING_VAL2REG(reg, val);
|
||||
|
||||
val = dmc->timings->tWL / clk_period_ps;
|
||||
val += dmc->timings->tWL % clk_period_ps ? 1 : 0;
|
||||
val = max(val, dmc->min_tck->tWL);
|
||||
reg = &timing_data[5];
|
||||
reg = &timing_data_reg_fields[5];
|
||||
*reg_timing_data |= TIMING_VAL2REG(reg, val);
|
||||
|
||||
val = dmc->timings->tDQSCK / clk_period_ps;
|
||||
val += dmc->timings->tDQSCK % clk_period_ps ? 1 : 0;
|
||||
val = max(val, dmc->min_tck->tDQSCK);
|
||||
reg = &timing_data[6];
|
||||
reg = &timing_data_reg_fields[6];
|
||||
*reg_timing_data |= TIMING_VAL2REG(reg, val);
|
||||
|
||||
val = dmc->timings->tRL / clk_period_ps;
|
||||
val += dmc->timings->tRL % clk_period_ps ? 1 : 0;
|
||||
val = max(val, dmc->min_tck->tRL);
|
||||
reg = &timing_data[7];
|
||||
reg = &timing_data_reg_fields[7];
|
||||
*reg_timing_data |= TIMING_VAL2REG(reg, val);
|
||||
|
||||
/* power related timings */
|
||||
val = dmc->timings->tFAW / clk_period_ps;
|
||||
val += dmc->timings->tFAW % clk_period_ps ? 1 : 0;
|
||||
val = max(val, dmc->min_tck->tFAW);
|
||||
reg = &timing_power[0];
|
||||
reg = &timing_power_reg_fields[0];
|
||||
*reg_timing_power |= TIMING_VAL2REG(reg, val);
|
||||
|
||||
val = dmc->timings->tXSR / clk_period_ps;
|
||||
val += dmc->timings->tXSR % clk_period_ps ? 1 : 0;
|
||||
val = max(val, dmc->min_tck->tXSR);
|
||||
reg = &timing_power[1];
|
||||
reg = &timing_power_reg_fields[1];
|
||||
*reg_timing_power |= TIMING_VAL2REG(reg, val);
|
||||
|
||||
val = dmc->timings->tXP / clk_period_ps;
|
||||
val += dmc->timings->tXP % clk_period_ps ? 1 : 0;
|
||||
val = max(val, dmc->min_tck->tXP);
|
||||
reg = &timing_power[2];
|
||||
reg = &timing_power_reg_fields[2];
|
||||
*reg_timing_power |= TIMING_VAL2REG(reg, val);
|
||||
|
||||
val = dmc->timings->tCKE / clk_period_ps;
|
||||
val += dmc->timings->tCKE % clk_period_ps ? 1 : 0;
|
||||
val = max(val, dmc->min_tck->tCKE);
|
||||
reg = &timing_power[3];
|
||||
reg = &timing_power_reg_fields[3];
|
||||
*reg_timing_power |= TIMING_VAL2REG(reg, val);
|
||||
|
||||
val = dmc->timings->tMRD / clk_period_ps;
|
||||
val += dmc->timings->tMRD % clk_period_ps ? 1 : 0;
|
||||
val = max(val, dmc->min_tck->tMRD);
|
||||
reg = &timing_power[4];
|
||||
reg = &timing_power_reg_fields[4];
|
||||
*reg_timing_power |= TIMING_VAL2REG(reg, val);
|
||||
|
||||
return 0;
|
||||
@ -1263,8 +1300,6 @@ static int exynos5_dmc_init_clks(struct exynos5_dmc *dmc)
|
||||
|
||||
clk_set_parent(dmc->mout_mx_mspll_ccore, dmc->mout_spll);
|
||||
|
||||
dmc->bypass_rate = clk_get_rate(dmc->mout_mx_mspll_ccore);
|
||||
|
||||
clk_prepare_enable(dmc->fout_bpll);
|
||||
clk_prepare_enable(dmc->mout_bpll);
|
||||
|
||||
@ -1332,7 +1367,6 @@ static int exynos5_performance_counters_init(struct exynos5_dmc *dmc)
|
||||
/**
|
||||
* exynos5_dmc_set_pause_on_switching() - Controls a pause feature in DMC
|
||||
* @dmc: device which is used for changing this feature
|
||||
* @set: a boolean state passing enable/disable request
|
||||
*
|
||||
* There is a need of pausing DREX DMC when divider or MUX in clock tree
|
||||
* changes its configuration. In such situation access to the memory is blocked
|
||||
|
@ -1060,19 +1060,7 @@ static int tegra_emc_debug_available_rates_show(struct seq_file *s,
|
||||
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)
|
||||
{
|
||||
|
@ -957,7 +957,6 @@ static const struct tegra_smmu_swgroup tegra124_swgroups[] = {
|
||||
static const unsigned int tegra124_group_drm[] = {
|
||||
TEGRA_SWGROUP_DC,
|
||||
TEGRA_SWGROUP_DCB,
|
||||
TEGRA_SWGROUP_GPU,
|
||||
TEGRA_SWGROUP_VIC,
|
||||
};
|
||||
|
||||
|
@ -172,14 +172,8 @@ static int tegra186_emc_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
emc->bpmp = tegra_bpmp_get(&pdev->dev);
|
||||
if (IS_ERR(emc->bpmp)) {
|
||||
err = PTR_ERR(emc->bpmp);
|
||||
|
||||
if (err != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "failed to get BPMP: %d\n", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
if (IS_ERR(emc->bpmp))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(emc->bpmp), "failed to get BPMP\n");
|
||||
|
||||
emc->clk = devm_clk_get(&pdev->dev, "emc");
|
||||
if (IS_ERR(emc->clk)) {
|
||||
|
@ -501,7 +501,6 @@ static u32 tegra210_emc_r21021_periodic_compensation(struct tegra210_emc *emc)
|
||||
emc_cfg_o = emc_readl(emc, EMC_CFG);
|
||||
emc_cfg = emc_cfg_o & ~(EMC_CFG_DYN_SELF_REF |
|
||||
EMC_CFG_DRAM_ACPD |
|
||||
EMC_CFG_DRAM_CLKSTOP_PD |
|
||||
EMC_CFG_DRAM_CLKSTOP_PD);
|
||||
|
||||
|
||||
@ -1044,7 +1043,7 @@ static void tegra210_emc_r21021_set_clock(struct tegra210_emc *emc, u32 clksrc)
|
||||
!opt_cc_short_zcal && opt_short_zcal) {
|
||||
value = (value & ~(EMC_ZCAL_WAIT_CNT_ZCAL_WAIT_CNT_MASK <<
|
||||
EMC_ZCAL_WAIT_CNT_ZCAL_WAIT_CNT_SHIFT)) |
|
||||
((zq_wait_long & EMC_ZCAL_WAIT_CNT_ZCAL_WAIT_CNT_MASK) <<
|
||||
((zq_wait_long & EMC_ZCAL_WAIT_CNT_ZCAL_WAIT_CNT_MASK) <<
|
||||
EMC_MRS_WAIT_CNT_SHORT_WAIT_SHIFT);
|
||||
} else if (offset == EMC_ZCAL_INTERVAL && opt_zcal_en_cc) {
|
||||
value = 0; /* EMC_ZCAL_INTERVAL reset value. */
|
||||
|
@ -842,7 +842,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = {
|
||||
},
|
||||
.la = {
|
||||
.reg = 0x3dc,
|
||||
.shift = 0,
|
||||
.shift = 16,
|
||||
.mask = 0xff,
|
||||
.def = 0x80,
|
||||
},
|
||||
|
@ -65,9 +65,10 @@ config RESET_HSDK
|
||||
This enables the reset controller driver for HSDK board.
|
||||
|
||||
config RESET_IMX7
|
||||
bool "i.MX7/8 Reset Driver" if COMPILE_TEST
|
||||
tristate "i.MX7/8 Reset Driver"
|
||||
depends on HAS_IOMEM
|
||||
default SOC_IMX7D || (ARM64 && ARCH_MXC)
|
||||
depends on SOC_IMX7D || (ARM64 && ARCH_MXC) || COMPILE_TEST
|
||||
default y if SOC_IMX7D
|
||||
select MFD_SYSCON
|
||||
help
|
||||
This enables the reset controller driver for i.MX7 SoCs.
|
||||
|
@ -32,7 +32,8 @@ static LIST_HEAD(reset_lookup_list);
|
||||
* @refcnt: Number of gets of this reset_control
|
||||
* @acquired: Only one reset_control may be acquired for a given rcdev and id.
|
||||
* @shared: Is this a shared (1), or an exclusive (0) reset_control?
|
||||
* @deassert_cnt: Number of times this reset line has been deasserted
|
||||
* @array: Is this an array of reset controls (1)?
|
||||
* @deassert_count: Number of times this reset line has been deasserted
|
||||
* @triggered_count: Number of times this reset line has been reset. Currently
|
||||
* only used for shared resets, which means that the value
|
||||
* will be either 0 or 1.
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
@ -178,6 +178,9 @@ static const struct imx7_src_signal imx8mq_src_signals[IMX8MQ_RESET_NUM] = {
|
||||
[IMX8MQ_RESET_A53_SOC_DBG_RESET] = { SRC_A53RCR0, BIT(20) },
|
||||
[IMX8MQ_RESET_A53_L2RESET] = { SRC_A53RCR0, BIT(21) },
|
||||
[IMX8MQ_RESET_SW_NON_SCLR_M4C_RST] = { SRC_M4RCR, BIT(0) },
|
||||
[IMX8MQ_RESET_SW_M4C_RST] = { SRC_M4RCR, BIT(1) },
|
||||
[IMX8MQ_RESET_SW_M4P_RST] = { SRC_M4RCR, BIT(2) },
|
||||
[IMX8MQ_RESET_M4_ENABLE] = { SRC_M4RCR, BIT(3) },
|
||||
[IMX8MQ_RESET_OTG1_PHY_RESET] = { SRC_USBOPHY1_RCR, BIT(0) },
|
||||
[IMX8MQ_RESET_OTG2_PHY_RESET] = { SRC_USBOPHY2_RCR, BIT(0) },
|
||||
[IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N] = { SRC_MIPIPHY_RCR, BIT(1) },
|
||||
@ -238,6 +241,7 @@ static int imx8mq_reset_set(struct reset_controller_dev *rcdev,
|
||||
case IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N:
|
||||
case IMX8MQ_RESET_MIPI_DSI_RESET_N:
|
||||
case IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N:
|
||||
case IMX8MQ_RESET_M4_ENABLE:
|
||||
value = assert ? 0 : bit;
|
||||
break;
|
||||
}
|
||||
@ -386,6 +390,7 @@ static const struct of_device_id imx7_reset_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx8mp-src", .data = &variant_imx8mp },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imx7_reset_dt_ids);
|
||||
|
||||
static struct platform_driver imx7_reset_driver = {
|
||||
.probe = imx7_reset_probe,
|
||||
@ -394,4 +399,8 @@ static struct platform_driver imx7_reset_driver = {
|
||||
.of_match_table = imx7_reset_dt_ids,
|
||||
},
|
||||
};
|
||||
builtin_platform_driver(imx7_reset_driver);
|
||||
module_platform_driver(imx7_reset_driver);
|
||||
|
||||
MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
|
||||
MODULE_DESCRIPTION("NXP i.MX7 reset driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -9,12 +9,20 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/firmware/xlnx-zynqmp.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#define ZYNQMP_NR_RESETS (ZYNQMP_PM_RESET_END - ZYNQMP_PM_RESET_START)
|
||||
#define ZYNQMP_RESET_ID ZYNQMP_PM_RESET_START
|
||||
#define VERSAL_NR_RESETS 95
|
||||
|
||||
struct zynqmp_reset_soc_data {
|
||||
u32 reset_id;
|
||||
u32 num_resets;
|
||||
};
|
||||
|
||||
struct zynqmp_reset_data {
|
||||
struct reset_controller_dev rcdev;
|
||||
const struct zynqmp_reset_soc_data *data;
|
||||
};
|
||||
|
||||
static inline struct zynqmp_reset_data *
|
||||
@ -26,23 +34,28 @@ to_zynqmp_reset_data(struct reset_controller_dev *rcdev)
|
||||
static int zynqmp_reset_assert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
return zynqmp_pm_reset_assert(ZYNQMP_RESET_ID + id,
|
||||
struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
|
||||
|
||||
return zynqmp_pm_reset_assert(priv->data->reset_id + id,
|
||||
PM_RESET_ACTION_ASSERT);
|
||||
}
|
||||
|
||||
static int zynqmp_reset_deassert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
return zynqmp_pm_reset_assert(ZYNQMP_RESET_ID + id,
|
||||
struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
|
||||
|
||||
return zynqmp_pm_reset_assert(priv->data->reset_id + id,
|
||||
PM_RESET_ACTION_RELEASE);
|
||||
}
|
||||
|
||||
static int zynqmp_reset_status(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
|
||||
int val, err;
|
||||
|
||||
err = zynqmp_pm_reset_get_status(ZYNQMP_RESET_ID + id, &val);
|
||||
err = zynqmp_pm_reset_get_status(priv->data->reset_id + id, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -52,10 +65,28 @@ static int zynqmp_reset_status(struct reset_controller_dev *rcdev,
|
||||
static int zynqmp_reset_reset(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
return zynqmp_pm_reset_assert(ZYNQMP_RESET_ID + id,
|
||||
struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
|
||||
|
||||
return zynqmp_pm_reset_assert(priv->data->reset_id + id,
|
||||
PM_RESET_ACTION_PULSE);
|
||||
}
|
||||
|
||||
static int zynqmp_reset_of_xlate(struct reset_controller_dev *rcdev,
|
||||
const struct of_phandle_args *reset_spec)
|
||||
{
|
||||
return reset_spec->args[0];
|
||||
}
|
||||
|
||||
static const struct zynqmp_reset_soc_data zynqmp_reset_data = {
|
||||
.reset_id = ZYNQMP_RESET_ID,
|
||||
.num_resets = ZYNQMP_NR_RESETS,
|
||||
};
|
||||
|
||||
static const struct zynqmp_reset_soc_data versal_reset_data = {
|
||||
.reset_id = 0,
|
||||
.num_resets = VERSAL_NR_RESETS,
|
||||
};
|
||||
|
||||
static const struct reset_control_ops zynqmp_reset_ops = {
|
||||
.reset = zynqmp_reset_reset,
|
||||
.assert = zynqmp_reset_assert,
|
||||
@ -71,18 +102,25 @@ static int zynqmp_reset_probe(struct platform_device *pdev)
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->data = of_device_get_match_data(&pdev->dev);
|
||||
if (!priv->data)
|
||||
return -EINVAL;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
priv->rcdev.ops = &zynqmp_reset_ops;
|
||||
priv->rcdev.owner = THIS_MODULE;
|
||||
priv->rcdev.of_node = pdev->dev.of_node;
|
||||
priv->rcdev.nr_resets = ZYNQMP_NR_RESETS;
|
||||
priv->rcdev.nr_resets = priv->data->num_resets;
|
||||
priv->rcdev.of_reset_n_cells = 1;
|
||||
priv->rcdev.of_xlate = zynqmp_reset_of_xlate;
|
||||
|
||||
return devm_reset_controller_register(&pdev->dev, &priv->rcdev);
|
||||
}
|
||||
|
||||
static const struct of_device_id zynqmp_reset_dt_ids[] = {
|
||||
{ .compatible = "xlnx,zynqmp-reset", },
|
||||
{ .compatible = "xlnx,zynqmp-reset", .data = &zynqmp_reset_data, },
|
||||
{ .compatible = "xlnx,versal-reset", .data = &versal_reset_data, },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include "reset-syscfg.h"
|
||||
|
||||
/**
|
||||
* Reset channel regmap configuration
|
||||
* struct syscfg_reset_channel - Reset channel regmap configuration
|
||||
*
|
||||
* @reset: regmap field for the channel's reset bit.
|
||||
* @ack: regmap field for the channel's ack bit (optional).
|
||||
@ -28,8 +28,9 @@ struct syscfg_reset_channel {
|
||||
};
|
||||
|
||||
/**
|
||||
* A reset controller which groups together a set of related reset bits, which
|
||||
* may be located in different system configuration registers.
|
||||
* struct syscfg_reset_controller - A reset controller which groups together
|
||||
* a set of related reset bits, which may be located in different system
|
||||
* configuration registers.
|
||||
*
|
||||
* @rst: base reset controller structure.
|
||||
* @active_low: are the resets in this controller active low, i.e. clearing
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/reset.h>
|
||||
#include <linux/clk.h>
|
||||
#include <dt-bindings/power/meson8-power.h>
|
||||
#include <dt-bindings/power/meson-axg-power.h>
|
||||
#include <dt-bindings/power/meson-g12a-power.h>
|
||||
#include <dt-bindings/power/meson-gxbb-power.h>
|
||||
#include <dt-bindings/power/meson-sm1-power.h>
|
||||
@ -134,6 +135,11 @@ static struct meson_ee_pwrc_top_domain sm1_pwrc_ge2d = SM1_EE_PD(19);
|
||||
{ __reg, BIT(14) }, \
|
||||
{ __reg, BIT(15) }
|
||||
|
||||
static struct meson_ee_pwrc_mem_domain axg_pwrc_mem_vpu[] = {
|
||||
VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
|
||||
VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
|
||||
};
|
||||
|
||||
static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_vpu[] = {
|
||||
VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
|
||||
VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
|
||||
@ -190,6 +196,10 @@ static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_ge2d[] = {
|
||||
{ HHI_MEM_PD_REG0, GENMASK(25, 18) },
|
||||
};
|
||||
|
||||
static struct meson_ee_pwrc_mem_domain axg_pwrc_mem_audio[] = {
|
||||
{ HHI_MEM_PD_REG0, GENMASK(5, 4) },
|
||||
};
|
||||
|
||||
static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = {
|
||||
{ HHI_MEM_PD_REG0, GENMASK(5, 4) },
|
||||
{ HHI_AUDIO_MEM_PD_REG0, GENMASK(1, 0) },
|
||||
@ -231,6 +241,13 @@ static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = {
|
||||
|
||||
static bool pwrc_ee_get_power(struct meson_ee_pwrc_domain *pwrc_domain);
|
||||
|
||||
static struct meson_ee_pwrc_domain_desc axg_pwrc_domains[] = {
|
||||
[PWRC_AXG_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, axg_pwrc_mem_vpu,
|
||||
pwrc_ee_get_power, 5, 2),
|
||||
[PWRC_AXG_ETHERNET_MEM_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),
|
||||
[PWRC_AXG_AUDIO_ID] = MEM_PD("AUDIO", axg_pwrc_mem_audio),
|
||||
};
|
||||
|
||||
static struct meson_ee_pwrc_domain_desc g12a_pwrc_domains[] = {
|
||||
[PWRC_G12A_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, g12a_pwrc_mem_vpu,
|
||||
pwrc_ee_get_power, 11, 2),
|
||||
@ -433,8 +450,8 @@ static int meson_ee_pwrc_init_domain(struct platform_device *pdev,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pm_genpd_init(&dom->base, &pm_domain_always_on_gov,
|
||||
false);
|
||||
dom->base.flags = GENPD_FLAG_ALWAYS_ON;
|
||||
ret = pm_genpd_init(&dom->base, NULL, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
@ -529,6 +546,11 @@ static struct meson_ee_pwrc_domain_data meson_ee_g12a_pwrc_data = {
|
||||
.domains = g12a_pwrc_domains,
|
||||
};
|
||||
|
||||
static struct meson_ee_pwrc_domain_data meson_ee_axg_pwrc_data = {
|
||||
.count = ARRAY_SIZE(axg_pwrc_domains),
|
||||
.domains = axg_pwrc_domains,
|
||||
};
|
||||
|
||||
static struct meson_ee_pwrc_domain_data meson_ee_gxbb_pwrc_data = {
|
||||
.count = ARRAY_SIZE(gxbb_pwrc_domains),
|
||||
.domains = gxbb_pwrc_domains,
|
||||
@ -562,6 +584,10 @@ static const struct of_device_id meson_ee_pwrc_match_table[] = {
|
||||
.compatible = "amlogic,meson8m2-pwrc",
|
||||
.data = &meson_ee_m8b_pwrc_data,
|
||||
},
|
||||
{
|
||||
.compatible = "amlogic,meson-axg-pwrc",
|
||||
.data = &meson_ee_axg_pwrc_data,
|
||||
},
|
||||
{
|
||||
.compatible = "amlogic,meson-gxbb-pwrc",
|
||||
.data = &meson_ee_gxbb_pwrc_data,
|
||||
|
@ -339,8 +339,8 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
pm_genpd_init(&vpu_pd->genpd, &pm_domain_always_on_gov,
|
||||
powered_off);
|
||||
vpu_pd->genpd.flags = GENPD_FLAG_ALWAYS_ON;
|
||||
pm_genpd_init(&vpu_pd->genpd, NULL, powered_off);
|
||||
|
||||
return of_genpd_add_provider_simple(pdev->dev.of_node,
|
||||
&vpu_pd->genpd);
|
||||
|
@ -22,6 +22,15 @@ config RASPBERRYPI_POWER
|
||||
This enables support for the RPi power domains which can be enabled
|
||||
or disabled via the RPi firmware.
|
||||
|
||||
config SOC_BCM63XX
|
||||
bool "Broadcom 63xx SoC drivers"
|
||||
depends on BMIPS_GENERIC || COMPILE_TEST
|
||||
help
|
||||
Enables drivers for the Broadcom 63xx series of chips.
|
||||
Drivers can be enabled individually within this menu.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config SOC_BRCMSTB
|
||||
bool "Broadcom STB SoC drivers"
|
||||
depends on ARM || ARM64 || BMIPS_GENERIC || COMPILE_TEST
|
||||
@ -33,6 +42,7 @@ config SOC_BRCMSTB
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
source "drivers/soc/bcm/bcm63xx/Kconfig"
|
||||
source "drivers/soc/bcm/brcmstb/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
@ -1,4 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-$(CONFIG_BCM2835_POWER) += bcm2835-power.o
|
||||
obj-$(CONFIG_RASPBERRYPI_POWER) += raspberrypi-power.o
|
||||
obj-$(CONFIG_SOC_BCM63XX) += bcm63xx/
|
||||
obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/
|
||||
|
12
drivers/soc/bcm/bcm63xx/Kconfig
Normal file
12
drivers/soc/bcm/bcm63xx/Kconfig
Normal file
@ -0,0 +1,12 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
if SOC_BCM63XX
|
||||
|
||||
config BCM63XX_POWER
|
||||
bool "BCM63xx power domain driver"
|
||||
depends on BMIPS_GENERIC || (COMPILE_TEST && OF)
|
||||
select PM_GENERIC_DOMAINS if PM
|
||||
help
|
||||
This enables support for the BCM63xx power domains controller on
|
||||
BCM6318, BCM6328, BCM6362 and BCM63268 SoCs.
|
||||
|
||||
endif # SOC_BCM63XX
|
2
drivers/soc/bcm/bcm63xx/Makefile
Normal file
2
drivers/soc/bcm/bcm63xx/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-$(CONFIG_BCM63XX_POWER) += bcm63xx-power.o
|
378
drivers/soc/bcm/bcm63xx/bcm63xx-power.c
Normal file
378
drivers/soc/bcm/bcm63xx/bcm63xx-power.c
Normal file
@ -0,0 +1,378 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* BCM63xx Power Domain Controller Driver
|
||||
*
|
||||
* Copyright (C) 2020 Álvaro Fernández Rojas <noltari@gmail.com>
|
||||
*/
|
||||
|
||||
#include <dt-bindings/soc/bcm6318-pm.h>
|
||||
#include <dt-bindings/soc/bcm6328-pm.h>
|
||||
#include <dt-bindings/soc/bcm6362-pm.h>
|
||||
#include <dt-bindings/soc/bcm63268-pm.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
struct bcm63xx_power_dev {
|
||||
struct generic_pm_domain genpd;
|
||||
struct bcm63xx_power *power;
|
||||
uint32_t mask;
|
||||
};
|
||||
|
||||
struct bcm63xx_power {
|
||||
void __iomem *base;
|
||||
spinlock_t lock;
|
||||
struct bcm63xx_power_dev *dev;
|
||||
struct genpd_onecell_data genpd_data;
|
||||
struct generic_pm_domain **genpd;
|
||||
};
|
||||
|
||||
struct bcm63xx_power_data {
|
||||
const char * const name;
|
||||
uint8_t bit;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
static int bcm63xx_power_get_state(struct bcm63xx_power_dev *pmd, bool *is_on)
|
||||
{
|
||||
struct bcm63xx_power *power = pmd->power;
|
||||
|
||||
if (!pmd->mask) {
|
||||
*is_on = false;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*is_on = !(__raw_readl(power->base) & pmd->mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm63xx_power_set_state(struct bcm63xx_power_dev *pmd, bool on)
|
||||
{
|
||||
struct bcm63xx_power *power = pmd->power;
|
||||
unsigned long flags;
|
||||
uint32_t val;
|
||||
|
||||
if (!pmd->mask)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&power->lock, flags);
|
||||
val = __raw_readl(power->base);
|
||||
if (on)
|
||||
val &= ~pmd->mask;
|
||||
else
|
||||
val |= pmd->mask;
|
||||
__raw_writel(val, power->base);
|
||||
spin_unlock_irqrestore(&power->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm63xx_power_on(struct generic_pm_domain *genpd)
|
||||
{
|
||||
struct bcm63xx_power_dev *pmd = container_of(genpd,
|
||||
struct bcm63xx_power_dev, genpd);
|
||||
|
||||
return bcm63xx_power_set_state(pmd, true);
|
||||
}
|
||||
|
||||
static int bcm63xx_power_off(struct generic_pm_domain *genpd)
|
||||
{
|
||||
struct bcm63xx_power_dev *pmd = container_of(genpd,
|
||||
struct bcm63xx_power_dev, genpd);
|
||||
|
||||
return bcm63xx_power_set_state(pmd, false);
|
||||
}
|
||||
|
||||
static int bcm63xx_power_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct resource *res;
|
||||
const struct bcm63xx_power_data *entry, *table;
|
||||
struct bcm63xx_power *power;
|
||||
unsigned int ndom;
|
||||
uint8_t max_bit = 0;
|
||||
int ret;
|
||||
|
||||
power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
|
||||
if (!power)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
power->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(power->base))
|
||||
return PTR_ERR(power->base);
|
||||
|
||||
table = of_device_get_match_data(dev);
|
||||
if (!table)
|
||||
return -EINVAL;
|
||||
|
||||
power->genpd_data.num_domains = 0;
|
||||
ndom = 0;
|
||||
for (entry = table; entry->name; entry++) {
|
||||
max_bit = max(max_bit, entry->bit);
|
||||
ndom++;
|
||||
}
|
||||
|
||||
if (!ndom)
|
||||
return -ENODEV;
|
||||
|
||||
power->genpd_data.num_domains = max_bit + 1;
|
||||
|
||||
power->dev = devm_kcalloc(dev, power->genpd_data.num_domains,
|
||||
sizeof(struct bcm63xx_power_dev),
|
||||
GFP_KERNEL);
|
||||
if (!power->dev)
|
||||
return -ENOMEM;
|
||||
|
||||
power->genpd = devm_kcalloc(dev, power->genpd_data.num_domains,
|
||||
sizeof(struct generic_pm_domain *),
|
||||
GFP_KERNEL);
|
||||
if (!power->genpd)
|
||||
return -ENOMEM;
|
||||
|
||||
power->genpd_data.domains = power->genpd;
|
||||
|
||||
ndom = 0;
|
||||
for (entry = table; entry->name; entry++) {
|
||||
struct bcm63xx_power_dev *pmd = &power->dev[ndom];
|
||||
bool is_on;
|
||||
|
||||
pmd->power = power;
|
||||
pmd->mask = BIT(entry->bit);
|
||||
pmd->genpd.name = entry->name;
|
||||
pmd->genpd.flags = entry->flags;
|
||||
|
||||
ret = bcm63xx_power_get_state(pmd, &is_on);
|
||||
if (ret)
|
||||
dev_warn(dev, "unable to get current state for %s\n",
|
||||
pmd->genpd.name);
|
||||
|
||||
pmd->genpd.power_on = bcm63xx_power_on;
|
||||
pmd->genpd.power_off = bcm63xx_power_off;
|
||||
|
||||
pm_genpd_init(&pmd->genpd, NULL, !is_on);
|
||||
power->genpd[entry->bit] = &pmd->genpd;
|
||||
|
||||
ndom++;
|
||||
}
|
||||
|
||||
spin_lock_init(&power->lock);
|
||||
|
||||
ret = of_genpd_add_provider_onecell(np, &power->genpd_data);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register genpd driver: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(dev, "registered %u power domains\n", ndom);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct bcm63xx_power_data bcm6318_power_domains[] = {
|
||||
{
|
||||
.name = "pcie",
|
||||
.bit = BCM6318_POWER_DOMAIN_PCIE,
|
||||
}, {
|
||||
.name = "usb",
|
||||
.bit = BCM6318_POWER_DOMAIN_USB,
|
||||
}, {
|
||||
.name = "ephy0",
|
||||
.bit = BCM6318_POWER_DOMAIN_EPHY0,
|
||||
}, {
|
||||
.name = "ephy1",
|
||||
.bit = BCM6318_POWER_DOMAIN_EPHY1,
|
||||
}, {
|
||||
.name = "ephy2",
|
||||
.bit = BCM6318_POWER_DOMAIN_EPHY2,
|
||||
}, {
|
||||
.name = "ephy3",
|
||||
.bit = BCM6318_POWER_DOMAIN_EPHY3,
|
||||
}, {
|
||||
.name = "ldo2p5",
|
||||
.bit = BCM6318_POWER_DOMAIN_LDO2P5,
|
||||
.flags = GENPD_FLAG_ALWAYS_ON,
|
||||
}, {
|
||||
.name = "ldo2p9",
|
||||
.bit = BCM6318_POWER_DOMAIN_LDO2P9,
|
||||
.flags = GENPD_FLAG_ALWAYS_ON,
|
||||
}, {
|
||||
.name = "sw1p0",
|
||||
.bit = BCM6318_POWER_DOMAIN_SW1P0,
|
||||
.flags = GENPD_FLAG_ALWAYS_ON,
|
||||
}, {
|
||||
.name = "pad",
|
||||
.bit = BCM6318_POWER_DOMAIN_PAD,
|
||||
.flags = GENPD_FLAG_ALWAYS_ON,
|
||||
}, {
|
||||
/* sentinel */
|
||||
},
|
||||
};
|
||||
|
||||
static const struct bcm63xx_power_data bcm6328_power_domains[] = {
|
||||
{
|
||||
.name = "adsl2-mips",
|
||||
.bit = BCM6328_POWER_DOMAIN_ADSL2_MIPS,
|
||||
}, {
|
||||
.name = "adsl2-phy",
|
||||
.bit = BCM6328_POWER_DOMAIN_ADSL2_PHY,
|
||||
}, {
|
||||
.name = "adsl2-afe",
|
||||
.bit = BCM6328_POWER_DOMAIN_ADSL2_AFE,
|
||||
}, {
|
||||
.name = "sar",
|
||||
.bit = BCM6328_POWER_DOMAIN_SAR,
|
||||
}, {
|
||||
.name = "pcm",
|
||||
.bit = BCM6328_POWER_DOMAIN_PCM,
|
||||
}, {
|
||||
.name = "usbd",
|
||||
.bit = BCM6328_POWER_DOMAIN_USBD,
|
||||
}, {
|
||||
.name = "usbh",
|
||||
.bit = BCM6328_POWER_DOMAIN_USBH,
|
||||
}, {
|
||||
.name = "pcie",
|
||||
.bit = BCM6328_POWER_DOMAIN_PCIE,
|
||||
}, {
|
||||
.name = "robosw",
|
||||
.bit = BCM6328_POWER_DOMAIN_ROBOSW,
|
||||
}, {
|
||||
.name = "ephy",
|
||||
.bit = BCM6328_POWER_DOMAIN_EPHY,
|
||||
}, {
|
||||
/* sentinel */
|
||||
},
|
||||
};
|
||||
|
||||
static const struct bcm63xx_power_data bcm6362_power_domains[] = {
|
||||
{
|
||||
.name = "sar",
|
||||
.bit = BCM6362_POWER_DOMAIN_SAR,
|
||||
}, {
|
||||
.name = "ipsec",
|
||||
.bit = BCM6362_POWER_DOMAIN_IPSEC,
|
||||
}, {
|
||||
.name = "mips",
|
||||
.bit = BCM6362_POWER_DOMAIN_MIPS,
|
||||
.flags = GENPD_FLAG_ALWAYS_ON,
|
||||
}, {
|
||||
.name = "dect",
|
||||
.bit = BCM6362_POWER_DOMAIN_DECT,
|
||||
}, {
|
||||
.name = "usbh",
|
||||
.bit = BCM6362_POWER_DOMAIN_USBH,
|
||||
}, {
|
||||
.name = "usbd",
|
||||
.bit = BCM6362_POWER_DOMAIN_USBD,
|
||||
}, {
|
||||
.name = "robosw",
|
||||
.bit = BCM6362_POWER_DOMAIN_ROBOSW,
|
||||
}, {
|
||||
.name = "pcm",
|
||||
.bit = BCM6362_POWER_DOMAIN_PCM,
|
||||
}, {
|
||||
.name = "periph",
|
||||
.bit = BCM6362_POWER_DOMAIN_PERIPH,
|
||||
.flags = GENPD_FLAG_ALWAYS_ON,
|
||||
}, {
|
||||
.name = "adsl-phy",
|
||||
.bit = BCM6362_POWER_DOMAIN_ADSL_PHY,
|
||||
}, {
|
||||
.name = "gmii-pads",
|
||||
.bit = BCM6362_POWER_DOMAIN_GMII_PADS,
|
||||
}, {
|
||||
.name = "fap",
|
||||
.bit = BCM6362_POWER_DOMAIN_FAP,
|
||||
}, {
|
||||
.name = "pcie",
|
||||
.bit = BCM6362_POWER_DOMAIN_PCIE,
|
||||
}, {
|
||||
.name = "wlan-pads",
|
||||
.bit = BCM6362_POWER_DOMAIN_WLAN_PADS,
|
||||
}, {
|
||||
/* sentinel */
|
||||
},
|
||||
};
|
||||
|
||||
static const struct bcm63xx_power_data bcm63268_power_domains[] = {
|
||||
{
|
||||
.name = "sar",
|
||||
.bit = BCM63268_POWER_DOMAIN_SAR,
|
||||
}, {
|
||||
.name = "ipsec",
|
||||
.bit = BCM63268_POWER_DOMAIN_IPSEC,
|
||||
}, {
|
||||
.name = "mips",
|
||||
.bit = BCM63268_POWER_DOMAIN_MIPS,
|
||||
.flags = GENPD_FLAG_ALWAYS_ON,
|
||||
}, {
|
||||
.name = "dect",
|
||||
.bit = BCM63268_POWER_DOMAIN_DECT,
|
||||
}, {
|
||||
.name = "usbh",
|
||||
.bit = BCM63268_POWER_DOMAIN_USBH,
|
||||
}, {
|
||||
.name = "usbd",
|
||||
.bit = BCM63268_POWER_DOMAIN_USBD,
|
||||
}, {
|
||||
.name = "robosw",
|
||||
.bit = BCM63268_POWER_DOMAIN_ROBOSW,
|
||||
}, {
|
||||
.name = "pcm",
|
||||
.bit = BCM63268_POWER_DOMAIN_PCM,
|
||||
}, {
|
||||
.name = "periph",
|
||||
.bit = BCM63268_POWER_DOMAIN_PERIPH,
|
||||
.flags = GENPD_FLAG_ALWAYS_ON,
|
||||
}, {
|
||||
.name = "vdsl-phy",
|
||||
.bit = BCM63268_POWER_DOMAIN_VDSL_PHY,
|
||||
}, {
|
||||
.name = "vdsl-mips",
|
||||
.bit = BCM63268_POWER_DOMAIN_VDSL_MIPS,
|
||||
}, {
|
||||
.name = "fap",
|
||||
.bit = BCM63268_POWER_DOMAIN_FAP,
|
||||
}, {
|
||||
.name = "pcie",
|
||||
.bit = BCM63268_POWER_DOMAIN_PCIE,
|
||||
}, {
|
||||
.name = "wlan-pads",
|
||||
.bit = BCM63268_POWER_DOMAIN_WLAN_PADS,
|
||||
}, {
|
||||
/* sentinel */
|
||||
},
|
||||
};
|
||||
|
||||
static const struct of_device_id bcm63xx_power_of_match[] = {
|
||||
{
|
||||
.compatible = "brcm,bcm6318-power-controller",
|
||||
.data = &bcm6318_power_domains,
|
||||
}, {
|
||||
.compatible = "brcm,bcm6328-power-controller",
|
||||
.data = &bcm6328_power_domains,
|
||||
}, {
|
||||
.compatible = "brcm,bcm6362-power-controller",
|
||||
.data = &bcm6362_power_domains,
|
||||
}, {
|
||||
.compatible = "brcm,bcm63268-power-controller",
|
||||
.data = &bcm63268_power_domains,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
|
||||
static struct platform_driver bcm63xx_power_driver = {
|
||||
.driver = {
|
||||
.name = "bcm63xx-power-controller",
|
||||
.of_match_table = bcm63xx_power_of_match,
|
||||
},
|
||||
.probe = bcm63xx_power_probe,
|
||||
};
|
||||
builtin_platform_driver(bcm63xx_power_driver);
|
@ -13,6 +13,22 @@
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <linux/soc/brcmstb/brcmstb.h>
|
||||
|
||||
#define RACENPREF_MASK 0x3
|
||||
#define RACPREFINST_SHIFT 0
|
||||
#define RACENINST_SHIFT 2
|
||||
#define RACPREFDATA_SHIFT 4
|
||||
#define RACENDATA_SHIFT 6
|
||||
#define RAC_CPU_SHIFT 8
|
||||
#define RACCFG_MASK 0xff
|
||||
#define DPREF_LINE_2_SHIFT 24
|
||||
#define DPREF_LINE_2_MASK 0xff
|
||||
|
||||
/* Bitmask to enable instruction and data prefetching with a 256-bytes stride */
|
||||
#define RAC_DATA_INST_EN_MASK (1 << RACPREFINST_SHIFT | \
|
||||
RACENPREF_MASK << RACENINST_SHIFT | \
|
||||
1 << RACPREFDATA_SHIFT | \
|
||||
RACENPREF_MASK << RACENDATA_SHIFT)
|
||||
|
||||
#define CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK 0x70000000
|
||||
#define CPU_CREDIT_REG_MCPx_READ_CRED_MASK 0xf
|
||||
#define CPU_CREDIT_REG_MCPx_WRITE_CRED_MASK 0xf
|
||||
@ -31,11 +47,21 @@ static void __iomem *cpubiuctrl_base;
|
||||
static bool mcp_wr_pairing_en;
|
||||
static const int *cpubiuctrl_regs;
|
||||
|
||||
enum cpubiuctrl_regs {
|
||||
CPU_CREDIT_REG = 0,
|
||||
CPU_MCP_FLOW_REG,
|
||||
CPU_WRITEBACK_CTRL_REG,
|
||||
RAC_CONFIG0_REG,
|
||||
RAC_CONFIG1_REG,
|
||||
NUM_CPU_BIUCTRL_REGS,
|
||||
};
|
||||
|
||||
static inline u32 cbc_readl(int reg)
|
||||
{
|
||||
int offset = cpubiuctrl_regs[reg];
|
||||
|
||||
if (offset == -1)
|
||||
if (offset == -1 ||
|
||||
(IS_ENABLED(CONFIG_CACHE_B15_RAC) && reg >= RAC_CONFIG0_REG))
|
||||
return (u32)-1;
|
||||
|
||||
return readl_relaxed(cpubiuctrl_base + offset);
|
||||
@ -45,22 +71,19 @@ static inline void cbc_writel(u32 val, int reg)
|
||||
{
|
||||
int offset = cpubiuctrl_regs[reg];
|
||||
|
||||
if (offset == -1)
|
||||
if (offset == -1 ||
|
||||
(IS_ENABLED(CONFIG_CACHE_B15_RAC) && reg >= RAC_CONFIG0_REG))
|
||||
return;
|
||||
|
||||
writel(val, cpubiuctrl_base + offset);
|
||||
}
|
||||
|
||||
enum cpubiuctrl_regs {
|
||||
CPU_CREDIT_REG = 0,
|
||||
CPU_MCP_FLOW_REG,
|
||||
CPU_WRITEBACK_CTRL_REG
|
||||
};
|
||||
|
||||
static const int b15_cpubiuctrl_regs[] = {
|
||||
[CPU_CREDIT_REG] = 0x184,
|
||||
[CPU_MCP_FLOW_REG] = -1,
|
||||
[CPU_WRITEBACK_CTRL_REG] = -1,
|
||||
[RAC_CONFIG0_REG] = -1,
|
||||
[RAC_CONFIG1_REG] = -1,
|
||||
};
|
||||
|
||||
/* Odd cases, e.g: 7260A0 */
|
||||
@ -68,22 +91,26 @@ static const int b53_cpubiuctrl_no_wb_regs[] = {
|
||||
[CPU_CREDIT_REG] = 0x0b0,
|
||||
[CPU_MCP_FLOW_REG] = 0x0b4,
|
||||
[CPU_WRITEBACK_CTRL_REG] = -1,
|
||||
[RAC_CONFIG0_REG] = 0x78,
|
||||
[RAC_CONFIG1_REG] = 0x7c,
|
||||
};
|
||||
|
||||
static const int b53_cpubiuctrl_regs[] = {
|
||||
[CPU_CREDIT_REG] = 0x0b0,
|
||||
[CPU_MCP_FLOW_REG] = 0x0b4,
|
||||
[CPU_WRITEBACK_CTRL_REG] = 0x22c,
|
||||
[RAC_CONFIG0_REG] = 0x78,
|
||||
[RAC_CONFIG1_REG] = 0x7c,
|
||||
};
|
||||
|
||||
static const int a72_cpubiuctrl_regs[] = {
|
||||
[CPU_CREDIT_REG] = 0x18,
|
||||
[CPU_MCP_FLOW_REG] = 0x1c,
|
||||
[CPU_WRITEBACK_CTRL_REG] = 0x20,
|
||||
[RAC_CONFIG0_REG] = 0x08,
|
||||
[RAC_CONFIG1_REG] = 0x0c,
|
||||
};
|
||||
|
||||
#define NUM_CPU_BIUCTRL_REGS 3
|
||||
|
||||
static int __init mcp_write_pairing_set(void)
|
||||
{
|
||||
u32 creds = 0;
|
||||
@ -110,6 +137,8 @@ static int __init mcp_write_pairing_set(void)
|
||||
static const u32 a72_b53_mach_compat[] = {
|
||||
0x7211,
|
||||
0x7216,
|
||||
0x72164,
|
||||
0x72165,
|
||||
0x7255,
|
||||
0x7260,
|
||||
0x7268,
|
||||
@ -117,6 +146,61 @@ static const u32 a72_b53_mach_compat[] = {
|
||||
0x7278,
|
||||
};
|
||||
|
||||
/* The read-ahead cache present in the Brahma-B53 CPU is a special piece of
|
||||
* hardware after the integrated L2 cache of the B53 CPU complex whose purpose
|
||||
* is to prefetch instruction and/or data with a line size of either 64 bytes
|
||||
* or 256 bytes. The rationale is that the data-bus of the CPU interface is
|
||||
* optimized for 256-byte transactions, and enabling the read-ahead cache
|
||||
* provides a significant performance boost (typically twice the performance
|
||||
* for a memcpy benchmark application).
|
||||
*
|
||||
* The read-ahead cache is transparent for Virtual Address cache maintenance
|
||||
* operations: IC IVAU, DC IVAC, DC CVAC, DC CVAU and DC CIVAC. So no special
|
||||
* handling is needed for the DMA API above and beyond what is included in the
|
||||
* arm64 implementation.
|
||||
*
|
||||
* In addition, since the Point of Unification is typically between L1 and L2
|
||||
* for the Brahma-B53 processor no special read-ahead cache handling is needed
|
||||
* for the IC IALLU and IC IALLUIS cache maintenance operations.
|
||||
*
|
||||
* However, it is not possible to specify the cache level (L3) for the cache
|
||||
* maintenance instructions operating by set/way to operate on the read-ahead
|
||||
* cache. The read-ahead cache will maintain coherency when inner cache lines
|
||||
* are cleaned by set/way, but if it is necessary to invalidate inner cache
|
||||
* lines by set/way to maintain coherency with system masters operating on
|
||||
* shared memory that does not have hardware support for coherency, then it
|
||||
* will also be necessary to explicitly invalidate the read-ahead cache.
|
||||
*/
|
||||
static void __init a72_b53_rac_enable_all(struct device_node *np)
|
||||
{
|
||||
unsigned int cpu;
|
||||
u32 enable = 0, pref_dist, shift;
|
||||
|
||||
if (IS_ENABLED(CONFIG_CACHE_B15_RAC))
|
||||
return;
|
||||
|
||||
if (WARN(num_possible_cpus() > 4, "RAC only supports 4 CPUs\n"))
|
||||
return;
|
||||
|
||||
pref_dist = cbc_readl(RAC_CONFIG1_REG);
|
||||
for_each_possible_cpu(cpu) {
|
||||
shift = cpu * RAC_CPU_SHIFT + RACPREFDATA_SHIFT;
|
||||
enable |= RAC_DATA_INST_EN_MASK << (cpu * RAC_CPU_SHIFT);
|
||||
if (cpubiuctrl_regs == a72_cpubiuctrl_regs) {
|
||||
enable &= ~(RACENPREF_MASK << shift);
|
||||
enable |= 3 << shift;
|
||||
pref_dist |= 1 << (cpu + DPREF_LINE_2_SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
cbc_writel(enable, RAC_CONFIG0_REG);
|
||||
cbc_writel(pref_dist, RAC_CONFIG1_REG);
|
||||
|
||||
pr_info("%pOF: Broadcom %s read-ahead cache\n",
|
||||
np, cpubiuctrl_regs == a72_cpubiuctrl_regs ?
|
||||
"Cortex-A72" : "Brahma-B53");
|
||||
}
|
||||
|
||||
static void __init mcp_a72_b53_set(void)
|
||||
{
|
||||
unsigned int i;
|
||||
@ -262,6 +346,7 @@ static int __init brcmstb_biuctrl_init(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
a72_b53_rac_enable_all(np);
|
||||
mcp_a72_b53_set();
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
register_syscore_ops(&brcmstb_cpu_credit_syscore_ops);
|
||||
|
@ -647,7 +647,6 @@ int qbman_swp_enqueue_multiple_direct(struct qbman_swp *s,
|
||||
const uint32_t *cl = (uint32_t *)d;
|
||||
uint32_t eqcr_ci, eqcr_pi, half_mask, full_mask;
|
||||
int i, num_enqueued = 0;
|
||||
uint64_t addr_cena;
|
||||
|
||||
spin_lock(&s->access_spinlock);
|
||||
half_mask = (s->eqcr.pi_ci_mask>>1);
|
||||
@ -701,7 +700,6 @@ int qbman_swp_enqueue_multiple_direct(struct qbman_swp *s,
|
||||
|
||||
/* Flush all the cacheline without load/store in between */
|
||||
eqcr_pi = s->eqcr.pi;
|
||||
addr_cena = (size_t)s->addr_cena;
|
||||
for (i = 0; i < num_enqueued; i++)
|
||||
eqcr_pi++;
|
||||
s->eqcr.pi = eqcr_pi & full_mask;
|
||||
|
@ -660,7 +660,7 @@ int bm_shutdown_pool(u32 bpid)
|
||||
}
|
||||
done:
|
||||
put_affine_portal();
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
struct gen_pool *bm_bpalloc;
|
||||
|
@ -86,7 +86,7 @@ static void fd_inc(struct qm_fd *fd)
|
||||
len--;
|
||||
qm_fd_set_param(fd, fmt, off, len);
|
||||
|
||||
fd->cmd = cpu_to_be32(be32_to_cpu(fd->cmd) + 1);
|
||||
be32_add_cpu(&fd->cmd, 1);
|
||||
}
|
||||
|
||||
/* The only part of the 'fd' we can't memcmp() is the ppid */
|
||||
|
@ -523,7 +523,7 @@ int ucc_set_tdm_rxtx_clk(u32 tdm_num, enum qe_clock clock,
|
||||
|
||||
qe_mux_reg = &qe_immr->qmx;
|
||||
|
||||
if (tdm_num > 7 || tdm_num < 0)
|
||||
if (tdm_num > 7)
|
||||
return -EINVAL;
|
||||
|
||||
/* The communications direction must be RX or TX */
|
||||
|
@ -487,22 +487,17 @@ static int imx_pgc_domain_probe(struct platform_device *pdev)
|
||||
|
||||
domain->regulator = devm_regulator_get_optional(domain->dev, "power");
|
||||
if (IS_ERR(domain->regulator)) {
|
||||
if (PTR_ERR(domain->regulator) != -ENODEV) {
|
||||
if (PTR_ERR(domain->regulator) != -EPROBE_DEFER)
|
||||
dev_err(domain->dev, "Failed to get domain's regulator\n");
|
||||
return PTR_ERR(domain->regulator);
|
||||
}
|
||||
if (PTR_ERR(domain->regulator) != -ENODEV)
|
||||
return dev_err_probe(domain->dev, PTR_ERR(domain->regulator),
|
||||
"Failed to get domain's regulator\n");
|
||||
} else if (domain->voltage) {
|
||||
regulator_set_voltage(domain->regulator,
|
||||
domain->voltage, domain->voltage);
|
||||
}
|
||||
|
||||
ret = imx_pgc_get_clocks(domain);
|
||||
if (ret) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(domain->dev, "Failed to get domain's clocks\n");
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(domain->dev, ret, "Failed to get domain's clocks\n");
|
||||
|
||||
ret = pm_genpd_init(&domain->genpd, NULL, true);
|
||||
if (ret) {
|
||||
|
@ -13,11 +13,16 @@
|
||||
#define CMDQ_POLL_ENABLE_MASK BIT(0)
|
||||
#define CMDQ_EOC_IRQ_EN BIT(0)
|
||||
#define CMDQ_REG_TYPE 1
|
||||
#define CMDQ_JUMP_RELATIVE 1
|
||||
|
||||
struct cmdq_instruction {
|
||||
union {
|
||||
u32 value;
|
||||
u32 mask;
|
||||
struct {
|
||||
u16 arg_c;
|
||||
u16 src_reg;
|
||||
};
|
||||
};
|
||||
union {
|
||||
u16 offset;
|
||||
@ -223,15 +228,104 @@ int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
|
||||
}
|
||||
EXPORT_SYMBOL(cmdq_pkt_write_mask);
|
||||
|
||||
int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event)
|
||||
int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, u16 addr_low,
|
||||
u16 reg_idx)
|
||||
{
|
||||
struct cmdq_instruction inst = {};
|
||||
|
||||
inst.op = CMDQ_CODE_READ_S;
|
||||
inst.dst_t = CMDQ_REG_TYPE;
|
||||
inst.sop = high_addr_reg_idx;
|
||||
inst.reg_dst = reg_idx;
|
||||
inst.src_reg = addr_low;
|
||||
|
||||
return cmdq_pkt_append_command(pkt, inst);
|
||||
}
|
||||
EXPORT_SYMBOL(cmdq_pkt_read_s);
|
||||
|
||||
int cmdq_pkt_write_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx,
|
||||
u16 addr_low, u16 src_reg_idx)
|
||||
{
|
||||
struct cmdq_instruction inst = {};
|
||||
|
||||
inst.op = CMDQ_CODE_WRITE_S;
|
||||
inst.src_t = CMDQ_REG_TYPE;
|
||||
inst.sop = high_addr_reg_idx;
|
||||
inst.offset = addr_low;
|
||||
inst.src_reg = src_reg_idx;
|
||||
|
||||
return cmdq_pkt_append_command(pkt, inst);
|
||||
}
|
||||
EXPORT_SYMBOL(cmdq_pkt_write_s);
|
||||
|
||||
int cmdq_pkt_write_s_mask(struct cmdq_pkt *pkt, u16 high_addr_reg_idx,
|
||||
u16 addr_low, u16 src_reg_idx, u32 mask)
|
||||
{
|
||||
struct cmdq_instruction inst = {};
|
||||
int err;
|
||||
|
||||
inst.op = CMDQ_CODE_MASK;
|
||||
inst.mask = ~mask;
|
||||
err = cmdq_pkt_append_command(pkt, inst);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
inst.mask = 0;
|
||||
inst.op = CMDQ_CODE_WRITE_S_MASK;
|
||||
inst.src_t = CMDQ_REG_TYPE;
|
||||
inst.sop = high_addr_reg_idx;
|
||||
inst.offset = addr_low;
|
||||
inst.src_reg = src_reg_idx;
|
||||
|
||||
return cmdq_pkt_append_command(pkt, inst);
|
||||
}
|
||||
EXPORT_SYMBOL(cmdq_pkt_write_s_mask);
|
||||
|
||||
int cmdq_pkt_write_s_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx,
|
||||
u16 addr_low, u32 value)
|
||||
{
|
||||
struct cmdq_instruction inst = {};
|
||||
|
||||
inst.op = CMDQ_CODE_WRITE_S;
|
||||
inst.sop = high_addr_reg_idx;
|
||||
inst.offset = addr_low;
|
||||
inst.value = value;
|
||||
|
||||
return cmdq_pkt_append_command(pkt, inst);
|
||||
}
|
||||
EXPORT_SYMBOL(cmdq_pkt_write_s_value);
|
||||
|
||||
int cmdq_pkt_write_s_mask_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx,
|
||||
u16 addr_low, u32 value, u32 mask)
|
||||
{
|
||||
struct cmdq_instruction inst = {};
|
||||
int err;
|
||||
|
||||
inst.op = CMDQ_CODE_MASK;
|
||||
inst.mask = ~mask;
|
||||
err = cmdq_pkt_append_command(pkt, inst);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
inst.op = CMDQ_CODE_WRITE_S_MASK;
|
||||
inst.sop = high_addr_reg_idx;
|
||||
inst.offset = addr_low;
|
||||
inst.value = value;
|
||||
|
||||
return cmdq_pkt_append_command(pkt, inst);
|
||||
}
|
||||
EXPORT_SYMBOL(cmdq_pkt_write_s_mask_value);
|
||||
|
||||
int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event, bool clear)
|
||||
{
|
||||
struct cmdq_instruction inst = { {0} };
|
||||
u32 clear_option = clear ? CMDQ_WFE_UPDATE : 0;
|
||||
|
||||
if (event >= CMDQ_MAX_EVENT)
|
||||
return -EINVAL;
|
||||
|
||||
inst.op = CMDQ_CODE_WFE;
|
||||
inst.value = CMDQ_WFE_OPTION;
|
||||
inst.value = CMDQ_WFE_OPTION | clear_option;
|
||||
inst.event = event;
|
||||
|
||||
return cmdq_pkt_append_command(pkt, inst);
|
||||
@ -315,6 +409,18 @@ int cmdq_pkt_assign(struct cmdq_pkt *pkt, u16 reg_idx, u32 value)
|
||||
}
|
||||
EXPORT_SYMBOL(cmdq_pkt_assign);
|
||||
|
||||
int cmdq_pkt_jump(struct cmdq_pkt *pkt, dma_addr_t addr)
|
||||
{
|
||||
struct cmdq_instruction inst = {};
|
||||
|
||||
inst.op = CMDQ_CODE_JUMP;
|
||||
inst.offset = CMDQ_JUMP_RELATIVE;
|
||||
inst.value = addr >>
|
||||
cmdq_get_shift_pa(((struct cmdq_client *)pkt->cl)->chan);
|
||||
return cmdq_pkt_append_command(pkt, inst);
|
||||
}
|
||||
EXPORT_SYMBOL(cmdq_pkt_jump);
|
||||
|
||||
int cmdq_pkt_finalize(struct cmdq_pkt *pkt)
|
||||
{
|
||||
struct cmdq_instruction inst = { {0} };
|
||||
@ -329,7 +435,8 @@ int cmdq_pkt_finalize(struct cmdq_pkt *pkt)
|
||||
|
||||
/* JUMP to end */
|
||||
inst.op = CMDQ_CODE_JUMP;
|
||||
inst.value = CMDQ_JUMP_PASS;
|
||||
inst.value = CMDQ_JUMP_PASS >>
|
||||
cmdq_get_shift_pa(((struct cmdq_client *)pkt->cl)->chan);
|
||||
err = cmdq_pkt_append_command(pkt, inst);
|
||||
|
||||
return err;
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
/**
|
||||
* mtk_infracfg_set_bus_protection - enable bus protection
|
||||
* @regmap: The infracfg regmap
|
||||
* @infracfg: The infracfg regmap
|
||||
* @mask: The mask containing the protection bits to be enabled.
|
||||
* @reg_update: The boolean flag determines to set the protection bits
|
||||
* by regmap_update_bits with enable register(PROTECTEN) or
|
||||
@ -50,7 +50,7 @@ int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask,
|
||||
|
||||
/**
|
||||
* mtk_infracfg_clear_bus_protection - disable bus protection
|
||||
* @regmap: The infracfg regmap
|
||||
* @infracfg: The infracfg regmap
|
||||
* @mask: The mask containing the protection bits to be disabled.
|
||||
* @reg_update: The boolean flag determines to clear the protection bits
|
||||
* by regmap_update_bits with enable register(PROTECTEN) or
|
||||
|
@ -328,7 +328,7 @@ static int of_apr_add_pd_lookups(struct device *dev)
|
||||
|
||||
pds = pdr_add_lookup(apr->pdr, service_name, service_path);
|
||||
if (IS_ERR(pds) && PTR_ERR(pds) != -EALREADY) {
|
||||
dev_err(dev, "pdr add lookup failed: %d\n", ret);
|
||||
dev_err(dev, "pdr add lookup failed: %ld\n", PTR_ERR(pds));
|
||||
return PTR_ERR(pds);
|
||||
}
|
||||
}
|
||||
|
@ -387,7 +387,6 @@ static int qcom_llcc_remove(struct platform_device *pdev)
|
||||
static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev,
|
||||
const char *name)
|
||||
{
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
struct regmap_config llcc_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
@ -396,11 +395,7 @@ static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev,
|
||||
.fast_io = true,
|
||||
};
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
|
||||
if (!res)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
base = devm_platform_ioremap_resource_byname(pdev, name);
|
||||
if (IS_ERR(base))
|
||||
return ERR_CAST(base);
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#define __RPM_INTERNAL_H__
|
||||
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/wait.h>
|
||||
#include <soc/qcom/tcs.h>
|
||||
|
||||
#define TCS_TYPE_NR 4
|
||||
@ -106,6 +107,8 @@ struct rpmh_ctrlr {
|
||||
* @lock: Synchronize state of the controller. If RPMH's cache
|
||||
* lock will also be held, the order is: drv->lock then
|
||||
* cache_lock.
|
||||
* @tcs_wait: Wait queue used to wait for @tcs_in_use to free up a
|
||||
* slot
|
||||
* @client: Handle to the DRV's client.
|
||||
*/
|
||||
struct rsc_drv {
|
||||
@ -118,6 +121,7 @@ struct rsc_drv {
|
||||
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;
|
||||
};
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include <soc/qcom/cmd-db.h>
|
||||
#include <soc/qcom/tcs.h>
|
||||
@ -453,6 +454,7 @@ skip:
|
||||
if (!drv->tcs[ACTIVE_TCS].num_tcs)
|
||||
enable_tcs_irq(drv, i, false);
|
||||
spin_unlock(&drv->lock);
|
||||
wake_up(&drv->tcs_wait);
|
||||
if (req)
|
||||
rpmh_tx_done(req, err);
|
||||
}
|
||||
@ -571,43 +573,74 @@ static int find_free_tcs(struct tcs_group *tcs)
|
||||
}
|
||||
|
||||
/**
|
||||
* tcs_write() - Store messages into a TCS right now, or return -EBUSY.
|
||||
* claim_tcs_for_req() - Claim a tcs in the given tcs_group; only for active.
|
||||
* @drv: The controller.
|
||||
* @tcs: The tcs_group used for ACTIVE_ONLY transfers.
|
||||
* @msg: The data to be sent.
|
||||
*
|
||||
* Grabs a TCS for ACTIVE_ONLY transfers and writes the messages to it.
|
||||
* Claims a tcs in the given tcs_group while making sure that no existing cmd
|
||||
* is in flight that would conflict with the one in @msg.
|
||||
*
|
||||
* If there are no free TCSes for ACTIVE_ONLY transfers or if a command for
|
||||
* the same address is already transferring returns -EBUSY which means the
|
||||
* client should retry shortly.
|
||||
* Context: Must be called with the drv->lock held since that protects
|
||||
* tcs_in_use.
|
||||
*
|
||||
* Return: 0 on success, -EBUSY if client should retry, or an error.
|
||||
* Client should have interrupts enabled for a bit before retrying.
|
||||
* Return: The id of the claimed tcs or -EBUSY if a matching msg is in flight
|
||||
* or the tcs_group is full.
|
||||
*/
|
||||
static int tcs_write(struct rsc_drv *drv, const struct tcs_request *msg)
|
||||
static int claim_tcs_for_req(struct rsc_drv *drv, struct tcs_group *tcs,
|
||||
const struct tcs_request *msg)
|
||||
{
|
||||
struct tcs_group *tcs;
|
||||
int tcs_id;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
tcs = get_tcs_for_msg(drv, msg);
|
||||
if (IS_ERR(tcs))
|
||||
return PTR_ERR(tcs);
|
||||
|
||||
spin_lock_irqsave(&drv->lock, flags);
|
||||
/*
|
||||
* The h/w does not like if we send a request to the same address,
|
||||
* when one is already in-flight or being processed.
|
||||
*/
|
||||
ret = check_for_req_inflight(drv, tcs, msg);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
return ret;
|
||||
|
||||
ret = find_free_tcs(tcs);
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
tcs_id = ret;
|
||||
return find_free_tcs(tcs);
|
||||
}
|
||||
|
||||
/**
|
||||
* rpmh_rsc_send_data() - Write / trigger active-only message.
|
||||
* @drv: The controller.
|
||||
* @msg: The data to be sent.
|
||||
*
|
||||
* NOTES:
|
||||
* - This is only used for "ACTIVE_ONLY" since the limitations of this
|
||||
* function don't make sense for sleep/wake cases.
|
||||
* - To do the transfer, we will grab a whole TCS for ourselves--we don't
|
||||
* try to share. If there are none available we'll wait indefinitely
|
||||
* for a free one.
|
||||
* - This function will not wait for the commands to be finished, only for
|
||||
* data to be programmed into the RPMh. See rpmh_tx_done() which will
|
||||
* be called when the transfer is fully complete.
|
||||
* - This function must be called with interrupts enabled. If the hardware
|
||||
* is busy doing someone else's transfer we need that transfer to fully
|
||||
* finish so that we can have the hardware, and to fully finish it needs
|
||||
* the interrupt handler to run. If the interrupts is set to run on the
|
||||
* active CPU this can never happen if interrupts are disabled.
|
||||
*
|
||||
* Return: 0 on success, -EINVAL on error.
|
||||
*/
|
||||
int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
|
||||
{
|
||||
struct tcs_group *tcs;
|
||||
int tcs_id;
|
||||
unsigned long flags;
|
||||
|
||||
tcs = get_tcs_for_msg(drv, msg);
|
||||
if (IS_ERR(tcs))
|
||||
return PTR_ERR(tcs);
|
||||
|
||||
spin_lock_irqsave(&drv->lock, flags);
|
||||
|
||||
/* Wait forever for a free tcs. It better be there eventually! */
|
||||
wait_event_lock_irq(drv->tcs_wait,
|
||||
(tcs_id = claim_tcs_for_req(drv, tcs, msg)) >= 0,
|
||||
drv->lock);
|
||||
|
||||
tcs->req[tcs_id - tcs->offset] = msg;
|
||||
set_bit(tcs_id, drv->tcs_in_use);
|
||||
@ -635,47 +668,6 @@ static int tcs_write(struct rsc_drv *drv, const struct tcs_request *msg)
|
||||
__tcs_set_trigger(drv, tcs_id, true);
|
||||
|
||||
return 0;
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&drv->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* rpmh_rsc_send_data() - Write / trigger active-only message.
|
||||
* @drv: The controller.
|
||||
* @msg: The data to be sent.
|
||||
*
|
||||
* NOTES:
|
||||
* - This is only used for "ACTIVE_ONLY" since the limitations of this
|
||||
* function don't make sense for sleep/wake cases.
|
||||
* - To do the transfer, we will grab a whole TCS for ourselves--we don't
|
||||
* try to share. If there are none available we'll wait indefinitely
|
||||
* for a free one.
|
||||
* - This function will not wait for the commands to be finished, only for
|
||||
* data to be programmed into the RPMh. See rpmh_tx_done() which will
|
||||
* be called when the transfer is fully complete.
|
||||
* - This function must be called with interrupts enabled. If the hardware
|
||||
* is busy doing someone else's transfer we need that transfer to fully
|
||||
* finish so that we can have the hardware, and to fully finish it needs
|
||||
* the interrupt handler to run. If the interrupts is set to run on the
|
||||
* active CPU this can never happen if interrupts are disabled.
|
||||
*
|
||||
* Return: 0 on success, -EINVAL on error.
|
||||
*/
|
||||
int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
do {
|
||||
ret = tcs_write(drv, msg);
|
||||
if (ret == -EBUSY) {
|
||||
pr_info_ratelimited("TCS Busy, retrying RPMH message send: addr=%#x\n",
|
||||
msg->cmds[0].addr);
|
||||
udelay(10);
|
||||
}
|
||||
} while (ret == -EBUSY);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -983,6 +975,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
|
||||
spin_lock_init(&drv->lock);
|
||||
init_waitqueue_head(&drv->tcs_wait);
|
||||
bitmap_zero(drv->tcs_in_use, MAX_TCS_NR);
|
||||
|
||||
irq = platform_get_irq(pdev, drv->id);
|
||||
|
@ -194,6 +194,7 @@ static const struct soc_id soc_id[] = {
|
||||
{ 186, "MSM8674" },
|
||||
{ 194, "MSM8974PRO" },
|
||||
{ 206, "MSM8916" },
|
||||
{ 207, "MSM8994" },
|
||||
{ 208, "APQ8074-AA" },
|
||||
{ 209, "APQ8074-AB" },
|
||||
{ 210, "APQ8074PRO" },
|
||||
@ -214,6 +215,8 @@ static const struct soc_id soc_id[] = {
|
||||
{ 248, "MSM8216" },
|
||||
{ 249, "MSM8116" },
|
||||
{ 250, "MSM8616" },
|
||||
{ 251, "MSM8992" },
|
||||
{ 253, "APQ8094" },
|
||||
{ 291, "APQ8096" },
|
||||
{ 305, "MSM8996SG" },
|
||||
{ 310, "MSM8996AU" },
|
||||
@ -223,6 +226,8 @@ static const struct soc_id soc_id[] = {
|
||||
{ 321, "SDM845" },
|
||||
{ 341, "SDA845" },
|
||||
{ 356, "SM8250" },
|
||||
{ 402, "IPQ6018" },
|
||||
{ 425, "SC7180" },
|
||||
};
|
||||
|
||||
static const char *socinfo_machine(struct device *dev, unsigned int id)
|
||||
|
@ -1,5 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
config SOC_RENESAS
|
||||
menuconfig SOC_RENESAS
|
||||
bool "Renesas SoC driver support" if COMPILE_TEST && !ARCH_RENESAS
|
||||
default y if ARCH_RENESAS
|
||||
select SOC_BUS
|
||||
@ -49,78 +49,18 @@ if ARM && ARCH_RENESAS
|
||||
#comment "Renesas ARM SoCs System Type"
|
||||
|
||||
config ARCH_EMEV2
|
||||
bool "Emma Mobile EV2"
|
||||
bool "ARM32 Platform support for Emma Mobile EV2"
|
||||
select HAVE_ARM_SCU if SMP
|
||||
select SYS_SUPPORTS_EM_STI
|
||||
|
||||
config ARCH_R7S72100
|
||||
bool "RZ/A1H (R7S72100)"
|
||||
select ARM_ERRATA_754322
|
||||
select PM
|
||||
select PM_GENERIC_DOMAINS
|
||||
select RENESAS_OSTM
|
||||
select RENESAS_RZA1_IRQC
|
||||
select SYS_SUPPORTS_SH_MTU2
|
||||
|
||||
config ARCH_R7S9210
|
||||
bool "RZ/A2 (R7S9210)"
|
||||
select PM
|
||||
select PM_GENERIC_DOMAINS
|
||||
select RENESAS_OSTM
|
||||
select RENESAS_RZA1_IRQC
|
||||
|
||||
config ARCH_R8A73A4
|
||||
bool "R-Mobile APE6 (R8A73A40)"
|
||||
select ARCH_RMOBILE
|
||||
select ARM_ERRATA_798181 if SMP
|
||||
select ARM_ERRATA_814220
|
||||
select HAVE_ARM_ARCH_TIMER
|
||||
select RENESAS_IRQC
|
||||
|
||||
config ARCH_R8A7740
|
||||
bool "R-Mobile A1 (R8A77400)"
|
||||
select ARCH_RMOBILE
|
||||
select ARM_ERRATA_754322
|
||||
select RENESAS_INTC_IRQPIN
|
||||
|
||||
config ARCH_R8A7742
|
||||
bool "RZ/G1H (R8A77420)"
|
||||
select ARCH_RCAR_GEN2
|
||||
select ARM_ERRATA_798181 if SMP
|
||||
select ARM_ERRATA_814220
|
||||
select SYSC_R8A7742
|
||||
|
||||
config ARCH_R8A7743
|
||||
bool "RZ/G1M (R8A77430)"
|
||||
select ARCH_RCAR_GEN2
|
||||
select ARM_ERRATA_798181 if SMP
|
||||
select SYSC_R8A7743
|
||||
|
||||
config ARCH_R8A7744
|
||||
bool "RZ/G1N (R8A77440)"
|
||||
select ARCH_RCAR_GEN2
|
||||
select ARM_ERRATA_798181 if SMP
|
||||
select SYSC_R8A7743
|
||||
|
||||
config ARCH_R8A7745
|
||||
bool "RZ/G1E (R8A77450)"
|
||||
config ARCH_R8A7794
|
||||
bool "ARM32 Platform support for R-Car E2"
|
||||
select ARCH_RCAR_GEN2
|
||||
select ARM_ERRATA_814220
|
||||
select SYSC_R8A7745
|
||||
|
||||
config ARCH_R8A77470
|
||||
bool "RZ/G1C (R8A77470)"
|
||||
select ARCH_RCAR_GEN2
|
||||
select ARM_ERRATA_814220
|
||||
select SYSC_R8A77470
|
||||
|
||||
config ARCH_R8A7778
|
||||
bool "R-Car M1A (R8A77781)"
|
||||
select ARCH_RCAR_GEN1
|
||||
select ARM_ERRATA_754322
|
||||
select SYSC_R8A7794
|
||||
|
||||
config ARCH_R8A7779
|
||||
bool "R-Car H1 (R8A77790)"
|
||||
bool "ARM32 Platform support for R-Car H1"
|
||||
select ARCH_RCAR_GEN1
|
||||
select ARM_ERRATA_754322
|
||||
select ARM_GLOBAL_TIMER
|
||||
@ -129,46 +69,106 @@ config ARCH_R8A7779
|
||||
select SYSC_R8A7779
|
||||
|
||||
config ARCH_R8A7790
|
||||
bool "R-Car H2 (R8A77900)"
|
||||
bool "ARM32 Platform support for R-Car H2"
|
||||
select ARCH_RCAR_GEN2
|
||||
select ARM_ERRATA_798181 if SMP
|
||||
select ARM_ERRATA_814220
|
||||
select I2C
|
||||
select SYSC_R8A7790
|
||||
|
||||
config ARCH_R8A7778
|
||||
bool "ARM32 Platform support for R-Car M1A"
|
||||
select ARCH_RCAR_GEN1
|
||||
select ARM_ERRATA_754322
|
||||
|
||||
config ARCH_R8A7793
|
||||
bool "ARM32 Platform support for R-Car M2-N"
|
||||
select ARCH_RCAR_GEN2
|
||||
select ARM_ERRATA_798181 if SMP
|
||||
select I2C
|
||||
select SYSC_R8A7791
|
||||
|
||||
config ARCH_R8A7791
|
||||
bool "R-Car M2-W (R8A77910)"
|
||||
bool "ARM32 Platform support for R-Car M2-W"
|
||||
select ARCH_RCAR_GEN2
|
||||
select ARM_ERRATA_798181 if SMP
|
||||
select I2C
|
||||
select SYSC_R8A7791
|
||||
|
||||
config ARCH_R8A7792
|
||||
bool "R-Car V2H (R8A77920)"
|
||||
bool "ARM32 Platform support for R-Car V2H"
|
||||
select ARCH_RCAR_GEN2
|
||||
select ARM_ERRATA_798181 if SMP
|
||||
select SYSC_R8A7792
|
||||
|
||||
config ARCH_R8A7793
|
||||
bool "R-Car M2-N (R8A7793)"
|
||||
select ARCH_RCAR_GEN2
|
||||
select ARM_ERRATA_798181 if SMP
|
||||
select I2C
|
||||
select SYSC_R8A7791
|
||||
config ARCH_R8A7740
|
||||
bool "ARM32 Platform support for R-Mobile A1"
|
||||
select ARCH_RMOBILE
|
||||
select ARM_ERRATA_754322
|
||||
select RENESAS_INTC_IRQPIN
|
||||
|
||||
config ARCH_R8A7794
|
||||
bool "R-Car E2 (R8A77940)"
|
||||
config ARCH_R8A73A4
|
||||
bool "ARM32 Platform support for R-Mobile APE6"
|
||||
select ARCH_RMOBILE
|
||||
select ARM_ERRATA_798181 if SMP
|
||||
select ARM_ERRATA_814220
|
||||
select HAVE_ARM_ARCH_TIMER
|
||||
select RENESAS_IRQC
|
||||
|
||||
config ARCH_R7S72100
|
||||
bool "ARM32 Platform support for RZ/A1H"
|
||||
select ARM_ERRATA_754322
|
||||
select PM
|
||||
select PM_GENERIC_DOMAINS
|
||||
select RENESAS_OSTM
|
||||
select RENESAS_RZA1_IRQC
|
||||
select SYS_SUPPORTS_SH_MTU2
|
||||
|
||||
config ARCH_R7S9210
|
||||
bool "ARM32 Platform support for RZ/A2"
|
||||
select PM
|
||||
select PM_GENERIC_DOMAINS
|
||||
select RENESAS_OSTM
|
||||
select RENESAS_RZA1_IRQC
|
||||
|
||||
config ARCH_R8A77470
|
||||
bool "ARM32 Platform support for RZ/G1C"
|
||||
select ARCH_RCAR_GEN2
|
||||
select ARM_ERRATA_814220
|
||||
select SYSC_R8A7794
|
||||
select SYSC_R8A77470
|
||||
|
||||
config ARCH_R8A7745
|
||||
bool "ARM32 Platform support for RZ/G1E"
|
||||
select ARCH_RCAR_GEN2
|
||||
select ARM_ERRATA_814220
|
||||
select SYSC_R8A7745
|
||||
|
||||
config ARCH_R8A7742
|
||||
bool "ARM32 Platform support for RZ/G1H"
|
||||
select ARCH_RCAR_GEN2
|
||||
select ARM_ERRATA_798181 if SMP
|
||||
select ARM_ERRATA_814220
|
||||
select SYSC_R8A7742
|
||||
|
||||
config ARCH_R8A7743
|
||||
bool "ARM32 Platform support for RZ/G1M"
|
||||
select ARCH_RCAR_GEN2
|
||||
select ARM_ERRATA_798181 if SMP
|
||||
select SYSC_R8A7743
|
||||
|
||||
config ARCH_R8A7744
|
||||
bool "ARM32 Platform support for RZ/G1N"
|
||||
select ARCH_RCAR_GEN2
|
||||
select ARM_ERRATA_798181 if SMP
|
||||
select SYSC_R8A7743
|
||||
|
||||
config ARCH_R9A06G032
|
||||
bool "RZ/N1D (R9A06G032)"
|
||||
bool "ARM32 Platform support for RZ/N1D"
|
||||
select ARCH_RZN1
|
||||
select ARM_ERRATA_814220
|
||||
|
||||
config ARCH_SH73A0
|
||||
bool "SH-Mobile AG5 (R8A73A00)"
|
||||
bool "ARM32 Platform support for SH-Mobile AG5"
|
||||
select ARCH_RMOBILE
|
||||
select ARM_ERRATA_754322
|
||||
select ARM_GLOBAL_TIMER
|
||||
@ -180,193 +180,201 @@ endif # ARM
|
||||
|
||||
if ARM64
|
||||
|
||||
config ARCH_R8A774A1
|
||||
bool "Renesas RZ/G2M SoC Platform"
|
||||
config ARCH_R8A77995
|
||||
bool "ARM64 Platform support for R-Car D3"
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A774A1
|
||||
select SYSC_R8A77995
|
||||
help
|
||||
This enables support for the Renesas RZ/G2M SoC.
|
||||
This enables support for the Renesas R-Car D3 SoC.
|
||||
|
||||
config ARCH_R8A774B1
|
||||
bool "Renesas RZ/G2N SoC Platform"
|
||||
config ARCH_R8A77990
|
||||
bool "ARM64 Platform support for R-Car E3"
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A774B1
|
||||
select SYSC_R8A77990
|
||||
help
|
||||
This enables support for the Renesas RZ/G2N SoC.
|
||||
|
||||
config ARCH_R8A774C0
|
||||
bool "Renesas RZ/G2E SoC Platform"
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A774C0
|
||||
help
|
||||
This enables support for the Renesas RZ/G2E SoC.
|
||||
|
||||
config ARCH_R8A774E1
|
||||
bool "Renesas RZ/G2H SoC Platform"
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A774E1
|
||||
help
|
||||
This enables support for the Renesas RZ/G2H SoC.
|
||||
This enables support for the Renesas R-Car E3 SoC.
|
||||
|
||||
config ARCH_R8A77950
|
||||
bool "Renesas R-Car H3 ES1.x SoC Platform"
|
||||
bool "ARM64 Platform support for R-Car H3 ES1.x"
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A7795
|
||||
help
|
||||
This enables support for the Renesas R-Car H3 SoC (revision 1.x).
|
||||
|
||||
config ARCH_R8A77951
|
||||
bool "Renesas R-Car H3 ES2.0+ SoC Platform"
|
||||
bool "ARM64 Platform support for R-Car H3 ES2.0+"
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A7795
|
||||
help
|
||||
This enables support for the Renesas R-Car H3 SoC (revisions 2.0 and
|
||||
later).
|
||||
|
||||
config ARCH_R8A77965
|
||||
bool "ARM64 Platform support for R-Car M3-N"
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A77965
|
||||
help
|
||||
This enables support for the Renesas R-Car M3-N SoC.
|
||||
|
||||
config ARCH_R8A77960
|
||||
bool "Renesas R-Car M3-W SoC Platform"
|
||||
bool "ARM64 Platform support for R-Car M3-W"
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A77960
|
||||
help
|
||||
This enables support for the Renesas R-Car M3-W SoC.
|
||||
|
||||
config ARCH_R8A77961
|
||||
bool "Renesas R-Car M3-W+ SoC Platform"
|
||||
bool "ARM64 Platform support for R-Car M3-W+"
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A77961
|
||||
help
|
||||
This enables support for the Renesas R-Car M3-W+ SoC.
|
||||
|
||||
config ARCH_R8A77965
|
||||
bool "Renesas R-Car M3-N SoC Platform"
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A77965
|
||||
help
|
||||
This enables support for the Renesas R-Car M3-N SoC.
|
||||
|
||||
config ARCH_R8A77970
|
||||
bool "Renesas R-Car V3M SoC Platform"
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A77970
|
||||
help
|
||||
This enables support for the Renesas R-Car V3M SoC.
|
||||
|
||||
config ARCH_R8A77980
|
||||
bool "Renesas R-Car V3H SoC Platform"
|
||||
bool "ARM64 Platform support for R-Car V3H"
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A77980
|
||||
help
|
||||
This enables support for the Renesas R-Car V3H SoC.
|
||||
|
||||
config ARCH_R8A77990
|
||||
bool "Renesas R-Car E3 SoC Platform"
|
||||
config ARCH_R8A77970
|
||||
bool "ARM64 Platform support for R-Car V3M"
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A77990
|
||||
select SYSC_R8A77970
|
||||
help
|
||||
This enables support for the Renesas R-Car E3 SoC.
|
||||
This enables support for the Renesas R-Car V3M SoC.
|
||||
|
||||
config ARCH_R8A77995
|
||||
bool "Renesas R-Car D3 SoC Platform"
|
||||
config ARCH_R8A779A0
|
||||
bool "ARM64 Platform support for R-Car V3U"
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A77995
|
||||
select SYSC_R8A779A0
|
||||
help
|
||||
This enables support for the Renesas R-Car D3 SoC.
|
||||
This enables support for the Renesas R-Car V3U SoC.
|
||||
|
||||
config ARCH_R8A774C0
|
||||
bool "ARM64 Platform support for RZ/G2E"
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A774C0
|
||||
help
|
||||
This enables support for the Renesas RZ/G2E SoC.
|
||||
|
||||
config ARCH_R8A774E1
|
||||
bool "ARM64 Platform support for RZ/G2H"
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A774E1
|
||||
help
|
||||
This enables support for the Renesas RZ/G2H SoC.
|
||||
|
||||
config ARCH_R8A774A1
|
||||
bool "ARM64 Platform support for RZ/G2M"
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A774A1
|
||||
help
|
||||
This enables support for the Renesas RZ/G2M SoC.
|
||||
|
||||
config ARCH_R8A774B1
|
||||
bool "ARM64 Platform support for RZ/G2N"
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A774B1
|
||||
help
|
||||
This enables support for the Renesas RZ/G2N SoC.
|
||||
|
||||
endif # ARM64
|
||||
|
||||
# SoC
|
||||
config SYSC_R8A7742
|
||||
bool "RZ/G1H System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
config RST_RCAR
|
||||
bool "Reset Controller support for R-Car" if COMPILE_TEST
|
||||
|
||||
config SYSC_R8A7743
|
||||
bool "RZ/G1M System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
config SYSC_RCAR
|
||||
bool "System Controller support for R-Car" if COMPILE_TEST
|
||||
|
||||
config SYSC_R8A7745
|
||||
bool "RZ/G1E System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A77470
|
||||
bool "RZ/G1C System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A774A1
|
||||
bool "RZ/G2M System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A774B1
|
||||
bool "RZ/G2N System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A774C0
|
||||
bool "RZ/G2E System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A774E1
|
||||
bool "RZ/G2H System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A7779
|
||||
bool "R-Car H1 System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A7790
|
||||
bool "R-Car H2 System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A7791
|
||||
bool "R-Car M2-W/N System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A7792
|
||||
bool "R-Car V2H System Controller support" if COMPILE_TEST
|
||||
config SYSC_R8A77995
|
||||
bool "System Controller support for R-Car D3" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A7794
|
||||
bool "R-Car E2 System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A7795
|
||||
bool "R-Car H3 System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A77960
|
||||
bool "R-Car M3-W System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A77961
|
||||
bool "R-Car M3-W+ System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A77965
|
||||
bool "R-Car M3-N System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A77970
|
||||
bool "R-Car V3M System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A77980
|
||||
bool "R-Car V3H System Controller support" if COMPILE_TEST
|
||||
bool "System Controller support for R-Car E2" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A77990
|
||||
bool "R-Car E3 System Controller support" if COMPILE_TEST
|
||||
bool "System Controller support for R-Car E3" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A77995
|
||||
bool "R-Car D3 System Controller support" if COMPILE_TEST
|
||||
config SYSC_R8A7779
|
||||
bool "System Controller support for R-Car H1" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
# Family
|
||||
config RST_RCAR
|
||||
bool "R-Car Reset Controller support" if COMPILE_TEST
|
||||
config SYSC_R8A7790
|
||||
bool "System Controller support for R-Car H2" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_RCAR
|
||||
bool "R-Car System Controller support" if COMPILE_TEST
|
||||
config SYSC_R8A7795
|
||||
bool "System Controller support for R-Car H3" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A7791
|
||||
bool "System Controller support for R-Car M2-W/N" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A77965
|
||||
bool "System Controller support for R-Car M3-N" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A77960
|
||||
bool "System Controller support for R-Car M3-W" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A77961
|
||||
bool "System Controller support for R-Car M3-W+" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A7792
|
||||
bool "System Controller support for R-Car V2H" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A77980
|
||||
bool "System Controller support for R-Car V3H" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A77970
|
||||
bool "System Controller support for R-Car V3M" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A779A0
|
||||
bool "System Controller support for R-Car V3U" if COMPILE_TEST
|
||||
|
||||
config SYSC_RMOBILE
|
||||
bool "R-Mobile System Controller support" if COMPILE_TEST
|
||||
bool "System Controller support for R-Mobile" if COMPILE_TEST
|
||||
|
||||
config SYSC_R8A77470
|
||||
bool "System Controller support for RZ/G1C" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A7745
|
||||
bool "System Controller support for RZ/G1E" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A7742
|
||||
bool "System Controller support for RZ/G1H" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A7743
|
||||
bool "System Controller support for RZ/G1M" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A774C0
|
||||
bool "System Controller support for RZ/G2E" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A774E1
|
||||
bool "System Controller support for RZ/G2H" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A774A1
|
||||
bool "System Controller support for RZ/G2M" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A774B1
|
||||
bool "System Controller support for RZ/G2N" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
endif # SOC_RENESAS
|
||||
|
@ -24,6 +24,7 @@ obj-$(CONFIG_SYSC_R8A77970) += r8a77970-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A77980) += r8a77980-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A77990) += r8a77990-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A77995) += r8a77995-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A779A0) += r8a779a0-sysc.o
|
||||
ifdef CONFIG_SMP
|
||||
obj-$(CONFIG_ARCH_R9A06G032) += r9a06g032-smp.o
|
||||
endif
|
||||
|
448
drivers/soc/renesas/r8a779a0-sysc.c
Normal file
448
drivers/soc/renesas/r8a779a0-sysc.c
Normal file
@ -0,0 +1,448 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Renesas R-Car V3U System Controller
|
||||
*
|
||||
* Copyright (C) 2020 Renesas Electronics Corp.
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/clk/renesas.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <dt-bindings/power/r8a779a0-sysc.h>
|
||||
|
||||
/*
|
||||
* Power Domain flags
|
||||
*/
|
||||
#define PD_CPU BIT(0) /* Area contains main CPU core */
|
||||
#define PD_SCU BIT(1) /* Area contains SCU and L2 cache */
|
||||
#define PD_NO_CR BIT(2) /* Area lacks PWR{ON,OFF}CR registers */
|
||||
|
||||
#define PD_CPU_NOCR PD_CPU | PD_NO_CR /* CPU area lacks CR */
|
||||
#define PD_ALWAYS_ON PD_NO_CR /* Always-on area */
|
||||
|
||||
/*
|
||||
* Description of a Power Area
|
||||
*/
|
||||
struct r8a779a0_sysc_area {
|
||||
const char *name;
|
||||
u8 pdr; /* PDRn */
|
||||
int parent; /* -1 if none */
|
||||
unsigned int flags; /* See PD_* */
|
||||
};
|
||||
|
||||
/*
|
||||
* SoC-specific Power Area Description
|
||||
*/
|
||||
struct r8a779a0_sysc_info {
|
||||
const struct r8a779a0_sysc_area *areas;
|
||||
unsigned int num_areas;
|
||||
};
|
||||
|
||||
static struct r8a779a0_sysc_area r8a779a0_areas[] __initdata = {
|
||||
{ "always-on", R8A779A0_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
|
||||
{ "a3e0", R8A779A0_PD_A3E0, R8A779A0_PD_ALWAYS_ON, PD_SCU },
|
||||
{ "a3e1", R8A779A0_PD_A3E1, R8A779A0_PD_ALWAYS_ON, PD_SCU },
|
||||
{ "a2e0d0", R8A779A0_PD_A2E0D0, R8A779A0_PD_A3E0, PD_SCU },
|
||||
{ "a2e0d1", R8A779A0_PD_A2E0D1, R8A779A0_PD_A3E0, PD_SCU },
|
||||
{ "a2e1d0", R8A779A0_PD_A2E1D0, R8A779A0_PD_A3E1, PD_SCU },
|
||||
{ "a2e1d1", R8A779A0_PD_A2E1D1, R8A779A0_PD_A3E1, PD_SCU },
|
||||
{ "a1e0d0c0", R8A779A0_PD_A1E0D0C0, R8A779A0_PD_A2E0D0, PD_CPU_NOCR },
|
||||
{ "a1e0d0c1", R8A779A0_PD_A1E0D0C1, R8A779A0_PD_A2E0D0, PD_CPU_NOCR },
|
||||
{ "a1e0d1c0", R8A779A0_PD_A1E0D1C0, R8A779A0_PD_A2E0D1, PD_CPU_NOCR },
|
||||
{ "a1e0d1c1", R8A779A0_PD_A1E0D1C1, R8A779A0_PD_A2E0D1, PD_CPU_NOCR },
|
||||
{ "a1e1d0c0", R8A779A0_PD_A1E1D0C0, R8A779A0_PD_A2E1D0, PD_CPU_NOCR },
|
||||
{ "a1e1d0c1", R8A779A0_PD_A1E1D0C1, R8A779A0_PD_A2E1D0, PD_CPU_NOCR },
|
||||
{ "a1e1d1c0", R8A779A0_PD_A1E1D1C0, R8A779A0_PD_A2E1D1, PD_CPU_NOCR },
|
||||
{ "a1e1d1c1", R8A779A0_PD_A1E1D1C1, R8A779A0_PD_A2E1D1, PD_CPU_NOCR },
|
||||
{ "3dg-a", R8A779A0_PD_3DG_A, R8A779A0_PD_ALWAYS_ON },
|
||||
{ "3dg-b", R8A779A0_PD_3DG_B, R8A779A0_PD_3DG_A },
|
||||
{ "a3vip0", R8A779A0_PD_A3VIP0, R8A779A0_PD_ALWAYS_ON },
|
||||
{ "a3vip1", R8A779A0_PD_A3VIP1, R8A779A0_PD_ALWAYS_ON },
|
||||
{ "a3vip3", R8A779A0_PD_A3VIP3, R8A779A0_PD_ALWAYS_ON },
|
||||
{ "a3vip2", R8A779A0_PD_A3VIP2, R8A779A0_PD_ALWAYS_ON },
|
||||
{ "a3isp01", R8A779A0_PD_A3ISP01, R8A779A0_PD_ALWAYS_ON },
|
||||
{ "a3isp23", R8A779A0_PD_A3ISP23, R8A779A0_PD_ALWAYS_ON },
|
||||
{ "a3ir", R8A779A0_PD_A3IR, R8A779A0_PD_ALWAYS_ON },
|
||||
{ "a2cn0", R8A779A0_PD_A2CN0, R8A779A0_PD_A3IR },
|
||||
{ "a2imp01", R8A779A0_PD_A2IMP01, R8A779A0_PD_A3IR },
|
||||
{ "a2dp0", R8A779A0_PD_A2DP0, R8A779A0_PD_A3IR },
|
||||
{ "a2cv0", R8A779A0_PD_A2CV0, R8A779A0_PD_A3IR },
|
||||
{ "a2cv1", R8A779A0_PD_A2CV1, R8A779A0_PD_A3IR },
|
||||
{ "a2cv4", R8A779A0_PD_A2CV4, R8A779A0_PD_A3IR },
|
||||
{ "a2cv6", R8A779A0_PD_A2CV6, R8A779A0_PD_A3IR },
|
||||
{ "a2cn2", R8A779A0_PD_A2CN2, R8A779A0_PD_A3IR },
|
||||
{ "a2imp23", R8A779A0_PD_A2IMP23, R8A779A0_PD_A3IR },
|
||||
{ "a2dp1", R8A779A0_PD_A2DP0, R8A779A0_PD_A3IR },
|
||||
{ "a2cv2", R8A779A0_PD_A2CV0, R8A779A0_PD_A3IR },
|
||||
{ "a2cv3", R8A779A0_PD_A2CV1, R8A779A0_PD_A3IR },
|
||||
{ "a2cv5", R8A779A0_PD_A2CV4, R8A779A0_PD_A3IR },
|
||||
{ "a2cv7", R8A779A0_PD_A2CV6, R8A779A0_PD_A3IR },
|
||||
{ "a2cn1", R8A779A0_PD_A2CN1, R8A779A0_PD_A3IR },
|
||||
{ "a1cnn0", R8A779A0_PD_A1CNN0, R8A779A0_PD_A2CN0 },
|
||||
{ "a1cnn2", R8A779A0_PD_A1CNN2, R8A779A0_PD_A2CN2 },
|
||||
{ "a1dsp0", R8A779A0_PD_A1DSP0, R8A779A0_PD_A2CN2 },
|
||||
{ "a1cnn1", R8A779A0_PD_A1CNN1, R8A779A0_PD_A2CN1 },
|
||||
{ "a1dsp1", R8A779A0_PD_A1DSP1, R8A779A0_PD_A2CN1 },
|
||||
};
|
||||
|
||||
static const struct r8a779a0_sysc_info r8a779a0_sysc_info __initconst = {
|
||||
.areas = r8a779a0_areas,
|
||||
.num_areas = ARRAY_SIZE(r8a779a0_areas),
|
||||
};
|
||||
|
||||
/* SYSC Common */
|
||||
#define SYSCSR 0x000 /* SYSC Status Register */
|
||||
#define SYSCPONSR(x) (0x800 + ((x) * 0x4)) /* Power-ON Status Register 0 */
|
||||
#define SYSCPOFFSR(x) (0x808 + ((x) * 0x4)) /* Power-OFF Status Register */
|
||||
#define SYSCISCR(x) (0x810 + ((x) * 0x4)) /* Interrupt Status/Clear Register */
|
||||
#define SYSCIER(x) (0x820 + ((x) * 0x4)) /* Interrupt Enable Register */
|
||||
#define SYSCIMR(x) (0x830 + ((x) * 0x4)) /* Interrupt Mask Register */
|
||||
|
||||
/* Power Domain Registers */
|
||||
#define PDRSR(n) (0x1000 + ((n) * 0x40))
|
||||
#define PDRONCR(n) (0x1004 + ((n) * 0x40))
|
||||
#define PDROFFCR(n) (0x1008 + ((n) * 0x40))
|
||||
#define PDRESR(n) (0x100C + ((n) * 0x40))
|
||||
|
||||
/* PWRON/PWROFF */
|
||||
#define PWRON_PWROFF BIT(0) /* Power-ON/OFF request */
|
||||
|
||||
/* PDRESR */
|
||||
#define PDRESR_ERR BIT(0)
|
||||
|
||||
/* PDRSR */
|
||||
#define PDRSR_OFF BIT(0) /* Power-OFF state */
|
||||
#define PDRSR_ON BIT(4) /* Power-ON state */
|
||||
#define PDRSR_OFF_STATE BIT(8) /* Processing Power-OFF sequence */
|
||||
#define PDRSR_ON_STATE BIT(12) /* Processing Power-ON sequence */
|
||||
|
||||
#define SYSCSR_BUSY GENMASK(1, 0) /* All bit sets is not busy */
|
||||
|
||||
#define SYSCSR_TIMEOUT 10000
|
||||
#define SYSCSR_DELAY_US 10
|
||||
|
||||
#define PDRESR_RETRIES 1000
|
||||
#define PDRESR_DELAY_US 10
|
||||
|
||||
#define SYSCISR_TIMEOUT 10000
|
||||
#define SYSCISR_DELAY_US 10
|
||||
|
||||
#define NUM_DOMAINS_EACH_REG BITS_PER_TYPE(u32)
|
||||
|
||||
static void __iomem *r8a779a0_sysc_base;
|
||||
static DEFINE_SPINLOCK(r8a779a0_sysc_lock); /* SMP CPUs + I/O devices */
|
||||
|
||||
static int r8a779a0_sysc_pwr_on_off(u8 pdr, bool on)
|
||||
{
|
||||
unsigned int reg_offs;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
if (on)
|
||||
reg_offs = PDRONCR(pdr);
|
||||
else
|
||||
reg_offs = PDROFFCR(pdr);
|
||||
|
||||
/* Wait until SYSC is ready to accept a power request */
|
||||
ret = readl_poll_timeout_atomic(r8a779a0_sysc_base + SYSCSR, val,
|
||||
(val & SYSCSR_BUSY) == SYSCSR_BUSY,
|
||||
SYSCSR_DELAY_US, SYSCSR_TIMEOUT);
|
||||
if (ret < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
/* Submit power shutoff or power resume request */
|
||||
iowrite32(PWRON_PWROFF, r8a779a0_sysc_base + reg_offs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clear_irq_flags(unsigned int reg_idx, unsigned int isr_mask)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
iowrite32(isr_mask, r8a779a0_sysc_base + SYSCISCR(reg_idx));
|
||||
|
||||
ret = readl_poll_timeout_atomic(r8a779a0_sysc_base + SYSCISCR(reg_idx),
|
||||
val, !(val & isr_mask),
|
||||
SYSCISR_DELAY_US, SYSCISR_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
pr_err("\n %s : Can not clear IRQ flags in SYSCISCR", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int r8a779a0_sysc_power(u8 pdr, bool on)
|
||||
{
|
||||
unsigned int isr_mask;
|
||||
unsigned int reg_idx, bit_idx;
|
||||
unsigned int status;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
u32 val;
|
||||
int k;
|
||||
|
||||
spin_lock_irqsave(&r8a779a0_sysc_lock, flags);
|
||||
|
||||
reg_idx = pdr / NUM_DOMAINS_EACH_REG;
|
||||
bit_idx = pdr % NUM_DOMAINS_EACH_REG;
|
||||
|
||||
isr_mask = BIT(bit_idx);
|
||||
|
||||
/*
|
||||
* The interrupt source needs to be enabled, but masked, to prevent the
|
||||
* CPU from receiving it.
|
||||
*/
|
||||
iowrite32(ioread32(r8a779a0_sysc_base + SYSCIER(reg_idx)) | isr_mask,
|
||||
r8a779a0_sysc_base + SYSCIER(reg_idx));
|
||||
iowrite32(ioread32(r8a779a0_sysc_base + SYSCIMR(reg_idx)) | isr_mask,
|
||||
r8a779a0_sysc_base + SYSCIMR(reg_idx));
|
||||
|
||||
ret = clear_irq_flags(reg_idx, isr_mask);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* Submit power shutoff or resume request until it was accepted */
|
||||
for (k = 0; k < PDRESR_RETRIES; k++) {
|
||||
ret = r8a779a0_sysc_pwr_on_off(pdr, on);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
status = ioread32(r8a779a0_sysc_base + PDRESR(pdr));
|
||||
if (!(status & PDRESR_ERR))
|
||||
break;
|
||||
|
||||
udelay(PDRESR_DELAY_US);
|
||||
}
|
||||
|
||||
if (k == PDRESR_RETRIES) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Wait until the power shutoff or resume request has completed * */
|
||||
ret = readl_poll_timeout_atomic(r8a779a0_sysc_base + SYSCISCR(reg_idx),
|
||||
val, (val & isr_mask),
|
||||
SYSCISR_DELAY_US, SYSCISR_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Clear interrupt flags */
|
||||
ret = clear_irq_flags(reg_idx, isr_mask);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&r8a779a0_sysc_lock, flags);
|
||||
|
||||
pr_debug("sysc power %s domain %d: %08x -> %d\n", on ? "on" : "off",
|
||||
pdr, ioread32(r8a779a0_sysc_base + SYSCISCR(reg_idx)), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool r8a779a0_sysc_power_is_off(u8 pdr)
|
||||
{
|
||||
unsigned int st;
|
||||
|
||||
st = ioread32(r8a779a0_sysc_base + PDRSR(pdr));
|
||||
|
||||
if (st & PDRSR_OFF)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct r8a779a0_sysc_pd {
|
||||
struct generic_pm_domain genpd;
|
||||
u8 pdr;
|
||||
unsigned int flags;
|
||||
char name[];
|
||||
};
|
||||
|
||||
static inline struct r8a779a0_sysc_pd *to_r8a779a0_pd(struct generic_pm_domain *d)
|
||||
{
|
||||
return container_of(d, struct r8a779a0_sysc_pd, genpd);
|
||||
}
|
||||
|
||||
static int r8a779a0_sysc_pd_power_off(struct generic_pm_domain *genpd)
|
||||
{
|
||||
struct r8a779a0_sysc_pd *pd = to_r8a779a0_pd(genpd);
|
||||
|
||||
pr_debug("%s: %s\n", __func__, genpd->name);
|
||||
return r8a779a0_sysc_power(pd->pdr, false);
|
||||
}
|
||||
|
||||
static int r8a779a0_sysc_pd_power_on(struct generic_pm_domain *genpd)
|
||||
{
|
||||
struct r8a779a0_sysc_pd *pd = to_r8a779a0_pd(genpd);
|
||||
|
||||
pr_debug("%s: %s\n", __func__, genpd->name);
|
||||
return r8a779a0_sysc_power(pd->pdr, true);
|
||||
}
|
||||
|
||||
static int __init r8a779a0_sysc_pd_setup(struct r8a779a0_sysc_pd *pd)
|
||||
{
|
||||
struct generic_pm_domain *genpd = &pd->genpd;
|
||||
const char *name = pd->genpd.name;
|
||||
int error;
|
||||
|
||||
if (pd->flags & PD_CPU) {
|
||||
/*
|
||||
* This domain contains a CPU core and therefore it should
|
||||
* only be turned off if the CPU is not in use.
|
||||
*/
|
||||
pr_debug("PM domain %s contains %s\n", name, "CPU");
|
||||
genpd->flags |= GENPD_FLAG_ALWAYS_ON;
|
||||
} else if (pd->flags & PD_SCU) {
|
||||
/*
|
||||
* This domain contains an SCU and cache-controller, and
|
||||
* therefore it should only be turned off if the CPU cores are
|
||||
* not in use.
|
||||
*/
|
||||
pr_debug("PM domain %s contains %s\n", name, "SCU");
|
||||
genpd->flags |= GENPD_FLAG_ALWAYS_ON;
|
||||
} else if (pd->flags & PD_NO_CR) {
|
||||
/*
|
||||
* This domain cannot be turned off.
|
||||
*/
|
||||
genpd->flags |= GENPD_FLAG_ALWAYS_ON;
|
||||
}
|
||||
|
||||
if (!(pd->flags & (PD_CPU | PD_SCU))) {
|
||||
/* Enable Clock Domain for I/O devices */
|
||||
genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
|
||||
genpd->attach_dev = cpg_mssr_attach_dev;
|
||||
genpd->detach_dev = cpg_mssr_detach_dev;
|
||||
}
|
||||
|
||||
genpd->power_off = r8a779a0_sysc_pd_power_off;
|
||||
genpd->power_on = r8a779a0_sysc_pd_power_on;
|
||||
|
||||
if (pd->flags & (PD_CPU | PD_NO_CR)) {
|
||||
/* Skip CPUs (handled by SMP code) and areas without control */
|
||||
pr_debug("%s: Not touching %s\n", __func__, genpd->name);
|
||||
goto finalize;
|
||||
}
|
||||
|
||||
if (!r8a779a0_sysc_power_is_off(pd->pdr)) {
|
||||
pr_debug("%s: %s is already powered\n", __func__, genpd->name);
|
||||
goto finalize;
|
||||
}
|
||||
|
||||
r8a779a0_sysc_power(pd->pdr, true);
|
||||
|
||||
finalize:
|
||||
error = pm_genpd_init(genpd, &simple_qos_governor, false);
|
||||
if (error)
|
||||
pr_err("Failed to init PM domain %s: %d\n", name, error);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static const struct of_device_id r8a779a0_sysc_matches[] __initconst = {
|
||||
{ .compatible = "renesas,r8a779a0-sysc", .data = &r8a779a0_sysc_info },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
struct r8a779a0_pm_domains {
|
||||
struct genpd_onecell_data onecell_data;
|
||||
struct generic_pm_domain *domains[R8A779A0_PD_ALWAYS_ON + 1];
|
||||
};
|
||||
|
||||
static struct genpd_onecell_data *r8a779a0_sysc_onecell_data;
|
||||
|
||||
static int __init r8a779a0_sysc_pd_init(void)
|
||||
{
|
||||
const struct r8a779a0_sysc_info *info;
|
||||
const struct of_device_id *match;
|
||||
struct r8a779a0_pm_domains *domains;
|
||||
struct device_node *np;
|
||||
void __iomem *base;
|
||||
unsigned int i;
|
||||
int error;
|
||||
|
||||
np = of_find_matching_node_and_match(NULL, r8a779a0_sysc_matches, &match);
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
info = match->data;
|
||||
|
||||
base = of_iomap(np, 0);
|
||||
if (!base) {
|
||||
pr_warn("%pOF: Cannot map regs\n", np);
|
||||
error = -ENOMEM;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
r8a779a0_sysc_base = base;
|
||||
|
||||
domains = kzalloc(sizeof(*domains), GFP_KERNEL);
|
||||
if (!domains) {
|
||||
error = -ENOMEM;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
domains->onecell_data.domains = domains->domains;
|
||||
domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains);
|
||||
r8a779a0_sysc_onecell_data = &domains->onecell_data;
|
||||
|
||||
for (i = 0; i < info->num_areas; i++) {
|
||||
const struct r8a779a0_sysc_area *area = &info->areas[i];
|
||||
struct r8a779a0_sysc_pd *pd;
|
||||
|
||||
if (!area->name) {
|
||||
/* Skip NULLified area */
|
||||
continue;
|
||||
}
|
||||
|
||||
pd = kzalloc(sizeof(*pd) + strlen(area->name) + 1, GFP_KERNEL);
|
||||
if (!pd) {
|
||||
error = -ENOMEM;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
strcpy(pd->name, area->name);
|
||||
pd->genpd.name = pd->name;
|
||||
pd->pdr = area->pdr;
|
||||
pd->flags = area->flags;
|
||||
|
||||
error = r8a779a0_sysc_pd_setup(pd);
|
||||
if (error)
|
||||
goto out_put;
|
||||
|
||||
domains->domains[area->pdr] = &pd->genpd;
|
||||
|
||||
if (area->parent < 0)
|
||||
continue;
|
||||
|
||||
error = pm_genpd_add_subdomain(domains->domains[area->parent],
|
||||
&pd->genpd);
|
||||
if (error) {
|
||||
pr_warn("Failed to add PM subdomain %s to parent %u\n",
|
||||
area->name, area->parent);
|
||||
goto out_put;
|
||||
}
|
||||
}
|
||||
|
||||
error = of_genpd_add_provider_onecell(np, &domains->onecell_data);
|
||||
|
||||
out_put:
|
||||
of_node_put(np);
|
||||
return error;
|
||||
}
|
||||
early_initcall(r8a779a0_sysc_pd_init);
|
@ -37,6 +37,10 @@ static const struct rst_config rcar_rst_gen3 __initconst = {
|
||||
.modemr = 0x60,
|
||||
};
|
||||
|
||||
static const struct rst_config rcar_rst_r8a779a0 __initconst = {
|
||||
.modemr = 0x00, /* MODEMR0 and it has CPG related bits */
|
||||
};
|
||||
|
||||
static const struct of_device_id rcar_rst_matches[] __initconst = {
|
||||
/* RZ/G1 is handled like R-Car Gen2 */
|
||||
{ .compatible = "renesas,r8a7742-rst", .data = &rcar_rst_gen2 },
|
||||
@ -67,6 +71,8 @@ static const struct of_device_id rcar_rst_matches[] __initconst = {
|
||||
{ .compatible = "renesas,r8a77980-rst", .data = &rcar_rst_gen3 },
|
||||
{ .compatible = "renesas,r8a77990-rst", .data = &rcar_rst_gen3 },
|
||||
{ .compatible = "renesas,r8a77995-rst", .data = &rcar_rst_gen3 },
|
||||
/* R-Car V3U */
|
||||
{ .compatible = "renesas,r8a779a0-rst", .data = &rcar_rst_r8a779a0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
|
@ -200,6 +200,11 @@ static const struct renesas_soc soc_rcar_d3 __initconst __maybe_unused = {
|
||||
.id = 0x58,
|
||||
};
|
||||
|
||||
static const struct renesas_soc soc_rcar_v3u __initconst __maybe_unused = {
|
||||
.family = &fam_rcar_gen3,
|
||||
.id = 0x59,
|
||||
};
|
||||
|
||||
static const struct renesas_soc soc_shmobile_ag5 __initconst __maybe_unused = {
|
||||
.family = &fam_shmobile,
|
||||
.id = 0x37,
|
||||
@ -291,6 +296,9 @@ static const struct of_device_id renesas_socs[] __initconst = {
|
||||
#ifdef CONFIG_ARCH_R8A77995
|
||||
{ .compatible = "renesas,r8a77995", .data = &soc_rcar_d3 },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_R8A779A0
|
||||
{ .compatible = "renesas,r8a779a0", .data = &soc_rcar_v3u },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_SH73A0
|
||||
{ .compatible = "renesas,sh73a0", .data = &soc_shmobile_ag5 },
|
||||
#endif
|
||||
|
@ -194,7 +194,7 @@ static const struct sunxi_sram_data *sunxi_sram_of_parse(struct device_node *nod
|
||||
if (!data) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
};
|
||||
}
|
||||
|
||||
for (func = data->func; func->func; func++) {
|
||||
if (val == func->val) {
|
||||
|
@ -49,6 +49,9 @@ static struct tegra_fuse *fuse = &(struct tegra_fuse) {
|
||||
};
|
||||
|
||||
static const struct of_device_id tegra_fuse_match[] = {
|
||||
#ifdef CONFIG_ARCH_TEGRA_234_SOC
|
||||
{ .compatible = "nvidia,tegra234-efuse", .data = &tegra234_fuse_soc },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_TEGRA_194_SOC
|
||||
{ .compatible = "nvidia,tegra194-efuse", .data = &tegra194_fuse_soc },
|
||||
#endif
|
||||
@ -326,7 +329,8 @@ const struct attribute_group tegra_soc_attr_group = {
|
||||
.attrs = tegra_soc_attr,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_194_SOC
|
||||
#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
|
||||
IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
|
||||
static ssize_t platform_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
@ -336,7 +340,7 @@ static ssize_t platform_show(struct device *dev, struct device_attribute *attr,
|
||||
* platform type is silicon and all other non-zero values indicate
|
||||
* the type of simulation platform is being used.
|
||||
*/
|
||||
return sprintf(buf, "%d\n", (tegra_read_chipid() >> 20) & 0xf);
|
||||
return sprintf(buf, "%d\n", tegra_get_platform());
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(platform);
|
||||
|
@ -356,3 +356,33 @@ const struct tegra_fuse_soc tegra194_fuse_soc = {
|
||||
.soc_attr_group = &tegra194_soc_attr_group,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ARCH_TEGRA_234_SOC)
|
||||
static const struct nvmem_cell_lookup tegra234_fuse_lookups[] = {
|
||||
{
|
||||
.nvmem_name = "fuse",
|
||||
.cell_name = "xusb-pad-calibration",
|
||||
.dev_id = "3520000.padctl",
|
||||
.con_id = "calibration",
|
||||
}, {
|
||||
.nvmem_name = "fuse",
|
||||
.cell_name = "xusb-pad-calibration-ext",
|
||||
.dev_id = "3520000.padctl",
|
||||
.con_id = "calibration-ext",
|
||||
},
|
||||
};
|
||||
|
||||
static const struct tegra_fuse_info tegra234_fuse_info = {
|
||||
.read = tegra30_fuse_read,
|
||||
.size = 0x300,
|
||||
.spare = 0x280,
|
||||
};
|
||||
|
||||
const struct tegra_fuse_soc tegra234_fuse_soc = {
|
||||
.init = tegra30_fuse_init,
|
||||
.info = &tegra234_fuse_info,
|
||||
.lookups = tegra234_fuse_lookups,
|
||||
.num_lookups = ARRAY_SIZE(tegra234_fuse_lookups),
|
||||
.soc_attr_group = &tegra194_soc_attr_group,
|
||||
};
|
||||
#endif
|
||||
|
@ -115,9 +115,17 @@ extern const struct tegra_fuse_soc tegra210_fuse_soc;
|
||||
extern const struct tegra_fuse_soc tegra186_fuse_soc;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_194_SOC
|
||||
extern const struct tegra_fuse_soc tegra194_fuse_soc;
|
||||
#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
|
||||
IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
|
||||
extern const struct attribute_group tegra194_soc_attr_group;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_194_SOC
|
||||
extern const struct tegra_fuse_soc tegra194_fuse_soc;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_234_SOC
|
||||
extern const struct tegra_fuse_soc tegra234_fuse_soc;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -47,6 +47,31 @@ u8 tegra_get_minor_rev(void)
|
||||
return (tegra_read_chipid() >> 16) & 0xf;
|
||||
}
|
||||
|
||||
u8 tegra_get_platform(void)
|
||||
{
|
||||
return (tegra_read_chipid() >> 20) & 0xf;
|
||||
}
|
||||
|
||||
bool tegra_is_silicon(void)
|
||||
{
|
||||
switch (tegra_get_chip_id()) {
|
||||
case TEGRA194:
|
||||
case TEGRA234:
|
||||
if (tegra_get_platform() == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Chips prior to Tegra194 have a different way of determining whether
|
||||
* they are silicon or not. Since we never supported simulation on the
|
||||
* older Tegra chips, don't bother extracting the information and just
|
||||
* report that we're running on silicon.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 tegra_read_straps(void)
|
||||
{
|
||||
WARN(!chipid, "Tegra ABP MISC not yet available\n");
|
||||
@ -70,6 +95,7 @@ static const struct of_device_id apbmisc_match[] __initconst = {
|
||||
{ .compatible = "nvidia,tegra20-apbmisc", },
|
||||
{ .compatible = "nvidia,tegra186-misc", },
|
||||
{ .compatible = "nvidia,tegra194-misc", },
|
||||
{ .compatible = "nvidia,tegra234-misc", },
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -336,45 +336,6 @@ struct tegra_pmc_soc {
|
||||
bool has_blink_output;
|
||||
};
|
||||
|
||||
static const char * const tegra186_reset_sources[] = {
|
||||
"SYS_RESET",
|
||||
"AOWDT",
|
||||
"MCCPLEXWDT",
|
||||
"BPMPWDT",
|
||||
"SCEWDT",
|
||||
"SPEWDT",
|
||||
"APEWDT",
|
||||
"BCCPLEXWDT",
|
||||
"SENSOR",
|
||||
"AOTAG",
|
||||
"VFSENSOR",
|
||||
"SWREST",
|
||||
"SC7",
|
||||
"HSM",
|
||||
"CORESIGHT"
|
||||
};
|
||||
|
||||
static const char * const tegra186_reset_levels[] = {
|
||||
"L0", "L1", "L2", "WARM"
|
||||
};
|
||||
|
||||
static const char * const tegra30_reset_sources[] = {
|
||||
"POWER_ON_RESET",
|
||||
"WATCHDOG",
|
||||
"SENSOR",
|
||||
"SW_MAIN",
|
||||
"LP0"
|
||||
};
|
||||
|
||||
static const char * const tegra210_reset_sources[] = {
|
||||
"POWER_ON_RESET",
|
||||
"WATCHDOG",
|
||||
"SENSOR",
|
||||
"SW_MAIN",
|
||||
"LP0",
|
||||
"AOTAG"
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tegra_pmc - NVIDIA Tegra PMC
|
||||
* @dev: pointer to PMC device structure
|
||||
@ -2771,6 +2732,14 @@ static const u8 tegra30_cpu_powergates[] = {
|
||||
TEGRA_POWERGATE_CPU3,
|
||||
};
|
||||
|
||||
static const char * const tegra30_reset_sources[] = {
|
||||
"POWER_ON_RESET",
|
||||
"WATCHDOG",
|
||||
"SENSOR",
|
||||
"SW_MAIN",
|
||||
"LP0"
|
||||
};
|
||||
|
||||
static const struct tegra_pmc_soc tegra30_pmc_soc = {
|
||||
.num_powergates = ARRAY_SIZE(tegra30_powergates),
|
||||
.powergates = tegra30_powergates,
|
||||
@ -3048,6 +3017,15 @@ static const struct pinctrl_pin_desc tegra210_pin_descs[] = {
|
||||
TEGRA210_IO_PAD_TABLE(TEGRA_IO_PIN_DESC)
|
||||
};
|
||||
|
||||
static const char * const tegra210_reset_sources[] = {
|
||||
"POWER_ON_RESET",
|
||||
"WATCHDOG",
|
||||
"SENSOR",
|
||||
"SW_MAIN",
|
||||
"LP0",
|
||||
"AOTAG"
|
||||
};
|
||||
|
||||
static const struct tegra_wake_event tegra210_wake_events[] = {
|
||||
TEGRA_WAKE_IRQ("rtc", 16, 2),
|
||||
TEGRA_WAKE_IRQ("pmu", 51, 86),
|
||||
@ -3180,6 +3158,28 @@ static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
|
||||
iounmap(wake);
|
||||
}
|
||||
|
||||
static const char * const tegra186_reset_sources[] = {
|
||||
"SYS_RESET",
|
||||
"AOWDT",
|
||||
"MCCPLEXWDT",
|
||||
"BPMPWDT",
|
||||
"SCEWDT",
|
||||
"SPEWDT",
|
||||
"APEWDT",
|
||||
"BCCPLEXWDT",
|
||||
"SENSOR",
|
||||
"AOTAG",
|
||||
"VFSENSOR",
|
||||
"SWREST",
|
||||
"SC7",
|
||||
"HSM",
|
||||
"CORESIGHT"
|
||||
};
|
||||
|
||||
static const char * const tegra186_reset_levels[] = {
|
||||
"L0", "L1", "L2", "WARM"
|
||||
};
|
||||
|
||||
static const struct tegra_wake_event tegra186_wake_events[] = {
|
||||
TEGRA_WAKE_IRQ("pmu", 24, 209),
|
||||
TEGRA_WAKE_GPIO("power", 29, 1, TEGRA186_AON_GPIO(FF, 0)),
|
||||
@ -3349,7 +3349,75 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = {
|
||||
.has_blink_output = false,
|
||||
};
|
||||
|
||||
static const struct tegra_pmc_regs tegra234_pmc_regs = {
|
||||
.scratch0 = 0x2000,
|
||||
.dpd_req = 0,
|
||||
.dpd_status = 0,
|
||||
.dpd2_req = 0,
|
||||
.dpd2_status = 0,
|
||||
.rst_status = 0x70,
|
||||
.rst_source_shift = 0x2,
|
||||
.rst_source_mask = 0xfc,
|
||||
.rst_level_shift = 0x0,
|
||||
.rst_level_mask = 0x3,
|
||||
};
|
||||
|
||||
static const char * const tegra234_reset_sources[] = {
|
||||
"SYS_RESET_N",
|
||||
"AOWDT",
|
||||
"BCCPLEXWDT",
|
||||
"BPMPWDT",
|
||||
"SCEWDT",
|
||||
"SPEWDT",
|
||||
"APEWDT",
|
||||
"LCCPLEXWDT",
|
||||
"SENSOR",
|
||||
"AOTAG",
|
||||
"VFSENSOR",
|
||||
"MAINSWRST",
|
||||
"SC7",
|
||||
"HSM",
|
||||
"CSITE",
|
||||
"RCEWDT",
|
||||
"PVA0WDT",
|
||||
"PVA1WDT",
|
||||
"L1A_ASYNC",
|
||||
"BPMPBOOT",
|
||||
"FUSECRC",
|
||||
};
|
||||
|
||||
static const struct tegra_pmc_soc tegra234_pmc_soc = {
|
||||
.num_powergates = 0,
|
||||
.powergates = NULL,
|
||||
.num_cpu_powergates = 0,
|
||||
.cpu_powergates = NULL,
|
||||
.has_tsense_reset = false,
|
||||
.has_gpu_clamps = false,
|
||||
.needs_mbist_war = false,
|
||||
.has_impl_33v_pwr = true,
|
||||
.maybe_tz_only = false,
|
||||
.num_io_pads = 0,
|
||||
.io_pads = NULL,
|
||||
.num_pin_descs = 0,
|
||||
.pin_descs = NULL,
|
||||
.regs = &tegra234_pmc_regs,
|
||||
.init = NULL,
|
||||
.setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
|
||||
.irq_set_wake = tegra186_pmc_irq_set_wake,
|
||||
.irq_set_type = tegra186_pmc_irq_set_type,
|
||||
.reset_sources = tegra234_reset_sources,
|
||||
.num_reset_sources = ARRAY_SIZE(tegra234_reset_sources),
|
||||
.reset_levels = tegra186_reset_levels,
|
||||
.num_reset_levels = ARRAY_SIZE(tegra186_reset_levels),
|
||||
.num_wake_events = 0,
|
||||
.wake_events = NULL,
|
||||
.pmc_clks_data = NULL,
|
||||
.num_pmc_clks = 0,
|
||||
.has_blink_output = false,
|
||||
};
|
||||
|
||||
static const struct of_device_id tegra_pmc_match[] = {
|
||||
{ .compatible = "nvidia,tegra234-pmc", .data = &tegra234_pmc_soc },
|
||||
{ .compatible = "nvidia,tegra194-pmc", .data = &tegra194_pmc_soc },
|
||||
{ .compatible = "nvidia,tegra186-pmc", .data = &tegra186_pmc_soc },
|
||||
{ .compatible = "nvidia,tegra210-pmc", .data = &tegra210_pmc_soc },
|
||||
|
@ -101,6 +101,17 @@ config TI_K3_SOCINFO
|
||||
platforms to provide information about the SoC family and
|
||||
variant to user space.
|
||||
|
||||
config TI_PRUSS
|
||||
tristate "TI PRU-ICSS Subsystem Platform drivers"
|
||||
depends on SOC_AM33XX || SOC_AM43XX || SOC_DRA7XX || ARCH_KEYSTONE || ARCH_K3
|
||||
select MFD_SYSCON
|
||||
help
|
||||
TI PRU-ICSS Subsystem platform specific support.
|
||||
|
||||
Say Y or M here to support the Programmable Realtime Unit (PRU)
|
||||
processors on various TI SoCs. It's safe to say N here if you're
|
||||
not interested in the PRU or if you are unsure.
|
||||
|
||||
endif # SOC_TI
|
||||
|
||||
config TI_SCI_INTA_MSI_DOMAIN
|
||||
|
@ -12,4 +12,5 @@ obj-$(CONFIG_TI_SCI_PM_DOMAINS) += ti_sci_pm_domains.o
|
||||
obj-$(CONFIG_TI_SCI_INTA_MSI_DOMAIN) += ti_sci_inta_msi.o
|
||||
obj-$(CONFIG_TI_K3_RINGACC) += k3-ringacc.o
|
||||
obj-$(CONFIG_TI_K3_SOCINFO) += k3-socinfo.o
|
||||
obj-$(CONFIG_TI_PRUSS) += pruss.o
|
||||
obj-$(CONFIG_POWER_AVS_OMAP) += smartreflex.o
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/sys_soc.h>
|
||||
#include <linux/soc/ti/k3-ringacc.h>
|
||||
#include <linux/soc/ti/ti_sci_protocol.h>
|
||||
#include <linux/soc/ti/ti_sci_inta_msi.h>
|
||||
@ -208,6 +209,15 @@ struct k3_ringacc {
|
||||
const struct k3_ringacc_ops *ops;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct k3_ringacc - Rings accelerator SoC data
|
||||
*
|
||||
* @dma_ring_reset_quirk: DMA reset w/a enable
|
||||
*/
|
||||
struct k3_ringacc_soc_data {
|
||||
unsigned dma_ring_reset_quirk:1;
|
||||
};
|
||||
|
||||
static long k3_ringacc_ring_get_fifo_pos(struct k3_ring *ring)
|
||||
{
|
||||
return K3_RINGACC_FIFO_WINDOW_SIZE_BYTES -
|
||||
@ -1051,9 +1061,6 @@ static int k3_ringacc_probe_dt(struct k3_ringacc *ringacc)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ringacc->dma_ring_reset_quirk =
|
||||
of_property_read_bool(node, "ti,dma-ring-reset-quirk");
|
||||
|
||||
ringacc->tisci = ti_sci_get_by_phandle(node, "ti,sci");
|
||||
if (IS_ERR(ringacc->tisci)) {
|
||||
ret = PTR_ERR(ringacc->tisci);
|
||||
@ -1084,9 +1091,22 @@ static int k3_ringacc_probe_dt(struct k3_ringacc *ringacc)
|
||||
ringacc->rm_gp_range);
|
||||
}
|
||||
|
||||
static const struct k3_ringacc_soc_data k3_ringacc_soc_data_sr1 = {
|
||||
.dma_ring_reset_quirk = 1,
|
||||
};
|
||||
|
||||
static const struct soc_device_attribute k3_ringacc_socinfo[] = {
|
||||
{ .family = "AM65X",
|
||||
.revision = "SR1.0",
|
||||
.data = &k3_ringacc_soc_data_sr1
|
||||
},
|
||||
{/* sentinel */}
|
||||
};
|
||||
|
||||
static int k3_ringacc_init(struct platform_device *pdev,
|
||||
struct k3_ringacc *ringacc)
|
||||
{
|
||||
const struct soc_device_attribute *soc;
|
||||
void __iomem *base_fifo, *base_rt;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
@ -1103,6 +1123,13 @@ static int k3_ringacc_init(struct platform_device *pdev,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
soc = soc_device_match(k3_ringacc_socinfo);
|
||||
if (soc && soc->data) {
|
||||
const struct k3_ringacc_soc_data *soc_data = soc->data;
|
||||
|
||||
ringacc->dma_ring_reset_quirk = soc_data->dma_ring_reset_quirk;
|
||||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rt");
|
||||
base_rt = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(base_rt))
|
||||
|
@ -39,6 +39,7 @@ static const struct k3_soc_id {
|
||||
} k3_soc_ids[] = {
|
||||
{ 0xBB5A, "AM65X" },
|
||||
{ 0xBB64, "J721E" },
|
||||
{ 0xBB6D, "J7200" },
|
||||
};
|
||||
|
||||
static int
|
||||
|
@ -355,7 +355,7 @@ static void dma_debug_show_devices(struct seq_file *s,
|
||||
}
|
||||
}
|
||||
|
||||
static int dma_debug_show(struct seq_file *s, void *v)
|
||||
static int knav_dma_debug_show(struct seq_file *s, void *v)
|
||||
{
|
||||
struct knav_dma_device *dma;
|
||||
|
||||
@ -370,17 +370,7 @@ static int dma_debug_show(struct seq_file *s, void *v)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int knav_dma_debug_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, dma_debug_show, NULL);
|
||||
}
|
||||
|
||||
static const struct file_operations knav_dma_debug_ops = {
|
||||
.open = knav_dma_debug_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(knav_dma_debug);
|
||||
|
||||
static int of_channel_match_helper(struct device_node *np, const char *name,
|
||||
const char **dma_instance)
|
||||
@ -778,7 +768,7 @@ static int knav_dma_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
debugfs_create_file("knav_dma", S_IFREG | S_IRUGO, NULL, NULL,
|
||||
&knav_dma_debug_ops);
|
||||
&knav_dma_debug_fops);
|
||||
|
||||
device_ready = true;
|
||||
return ret;
|
||||
|
@ -478,17 +478,7 @@ static int knav_queue_debug_show(struct seq_file *s, void *v)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int knav_queue_debug_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, knav_queue_debug_show, NULL);
|
||||
}
|
||||
|
||||
static const struct file_operations knav_queue_debug_ops = {
|
||||
.open = knav_queue_debug_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(knav_queue_debug);
|
||||
|
||||
static inline int knav_queue_pdsp_wait(u32 * __iomem addr, unsigned timeout,
|
||||
u32 flags)
|
||||
@ -1878,7 +1868,7 @@ static int knav_queue_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
debugfs_create_file("qmss", S_IFREG | S_IRUGO, NULL, NULL,
|
||||
&knav_queue_debug_ops);
|
||||
&knav_queue_debug_fops);
|
||||
device_ready = true;
|
||||
return 0;
|
||||
|
||||
|
354
drivers/soc/ti/pruss.c
Normal file
354
drivers/soc/ti/pruss.c
Normal file
@ -0,0 +1,354 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* PRU-ICSS platform driver for various TI SoCs
|
||||
*
|
||||
* Copyright (C) 2014-2020 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* Author(s):
|
||||
* Suman Anna <s-anna@ti.com>
|
||||
* Andrew F. Davis <afd@ti.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pruss_driver.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/**
|
||||
* struct pruss_private_data - PRUSS driver private data
|
||||
* @has_no_sharedram: flag to indicate the absence of PRUSS Shared Data RAM
|
||||
* @has_core_mux_clock: flag to indicate the presence of PRUSS core clock
|
||||
*/
|
||||
struct pruss_private_data {
|
||||
bool has_no_sharedram;
|
||||
bool has_core_mux_clock;
|
||||
};
|
||||
|
||||
static void pruss_of_free_clk_provider(void *data)
|
||||
{
|
||||
struct device_node *clk_mux_np = data;
|
||||
|
||||
of_clk_del_provider(clk_mux_np);
|
||||
of_node_put(clk_mux_np);
|
||||
}
|
||||
|
||||
static int pruss_clk_mux_setup(struct pruss *pruss, struct clk *clk_mux,
|
||||
char *mux_name, struct device_node *clks_np)
|
||||
{
|
||||
struct device_node *clk_mux_np;
|
||||
struct device *dev = pruss->dev;
|
||||
char *clk_mux_name;
|
||||
unsigned int num_parents;
|
||||
const char **parent_names;
|
||||
void __iomem *reg;
|
||||
u32 reg_offset;
|
||||
int ret;
|
||||
|
||||
clk_mux_np = of_get_child_by_name(clks_np, mux_name);
|
||||
if (!clk_mux_np) {
|
||||
dev_err(dev, "%pOF is missing its '%s' node\n", clks_np,
|
||||
mux_name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
num_parents = of_clk_get_parent_count(clk_mux_np);
|
||||
if (num_parents < 1) {
|
||||
dev_err(dev, "mux-clock %pOF must have parents\n", clk_mux_np);
|
||||
ret = -EINVAL;
|
||||
goto put_clk_mux_np;
|
||||
}
|
||||
|
||||
parent_names = devm_kcalloc(dev, sizeof(*parent_names), num_parents,
|
||||
GFP_KERNEL);
|
||||
if (!parent_names) {
|
||||
ret = -ENOMEM;
|
||||
goto put_clk_mux_np;
|
||||
}
|
||||
|
||||
of_clk_parent_fill(clk_mux_np, parent_names, num_parents);
|
||||
|
||||
clk_mux_name = devm_kasprintf(dev, GFP_KERNEL, "%s.%pOFn",
|
||||
dev_name(dev), clk_mux_np);
|
||||
if (!clk_mux_name) {
|
||||
ret = -ENOMEM;
|
||||
goto put_clk_mux_np;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(clk_mux_np, "reg", ®_offset);
|
||||
if (ret)
|
||||
goto put_clk_mux_np;
|
||||
|
||||
reg = pruss->cfg_base + reg_offset;
|
||||
|
||||
clk_mux = clk_register_mux(NULL, clk_mux_name, parent_names,
|
||||
num_parents, 0, reg, 0, 1, 0, NULL);
|
||||
if (IS_ERR(clk_mux)) {
|
||||
ret = PTR_ERR(clk_mux);
|
||||
goto put_clk_mux_np;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(dev, (void(*)(void *))clk_unregister_mux,
|
||||
clk_mux);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add clkmux unregister action %d", ret);
|
||||
goto put_clk_mux_np;
|
||||
}
|
||||
|
||||
ret = of_clk_add_provider(clk_mux_np, of_clk_src_simple_get, clk_mux);
|
||||
if (ret)
|
||||
goto put_clk_mux_np;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, pruss_of_free_clk_provider,
|
||||
clk_mux_np);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add clkmux free action %d", ret);
|
||||
goto put_clk_mux_np;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
put_clk_mux_np:
|
||||
of_node_put(clk_mux_np);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pruss_clk_init(struct pruss *pruss, struct device_node *cfg_node)
|
||||
{
|
||||
const struct pruss_private_data *data;
|
||||
struct device_node *clks_np;
|
||||
struct device *dev = pruss->dev;
|
||||
int ret = 0;
|
||||
|
||||
data = of_device_get_match_data(dev);
|
||||
if (IS_ERR(data))
|
||||
return -ENODEV;
|
||||
|
||||
clks_np = of_get_child_by_name(cfg_node, "clocks");
|
||||
if (!clks_np) {
|
||||
dev_err(dev, "%pOF is missing its 'clocks' node\n", clks_np);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (data && data->has_core_mux_clock) {
|
||||
ret = pruss_clk_mux_setup(pruss, pruss->core_clk_mux,
|
||||
"coreclk-mux", clks_np);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to setup coreclk-mux\n");
|
||||
goto put_clks_node;
|
||||
}
|
||||
}
|
||||
|
||||
ret = pruss_clk_mux_setup(pruss, pruss->iep_clk_mux, "iepclk-mux",
|
||||
clks_np);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to setup iepclk-mux\n");
|
||||
goto put_clks_node;
|
||||
}
|
||||
|
||||
put_clks_node:
|
||||
of_node_put(clks_np);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct regmap_config regmap_conf = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
};
|
||||
|
||||
static int pruss_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev_of_node(dev);
|
||||
struct device_node *child;
|
||||
struct pruss *pruss;
|
||||
struct resource res;
|
||||
int ret, i, index;
|
||||
const struct pruss_private_data *data;
|
||||
const char *mem_names[PRUSS_MEM_MAX] = { "dram0", "dram1", "shrdram2" };
|
||||
|
||||
data = of_device_get_match_data(&pdev->dev);
|
||||
if (IS_ERR(data)) {
|
||||
dev_err(dev, "missing private data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to set the DMA coherent mask");
|
||||
return ret;
|
||||
}
|
||||
|
||||
pruss = devm_kzalloc(dev, sizeof(*pruss), GFP_KERNEL);
|
||||
if (!pruss)
|
||||
return -ENOMEM;
|
||||
|
||||
pruss->dev = dev;
|
||||
|
||||
child = of_get_child_by_name(np, "memories");
|
||||
if (!child) {
|
||||
dev_err(dev, "%pOF is missing its 'memories' node\n", child);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
for (i = 0; i < PRUSS_MEM_MAX; i++) {
|
||||
/*
|
||||
* On AM437x one of two PRUSS units don't contain Shared RAM,
|
||||
* skip it
|
||||
*/
|
||||
if (data && data->has_no_sharedram && i == PRUSS_MEM_SHRD_RAM2)
|
||||
continue;
|
||||
|
||||
index = of_property_match_string(child, "reg-names",
|
||||
mem_names[i]);
|
||||
if (index < 0) {
|
||||
of_node_put(child);
|
||||
return index;
|
||||
}
|
||||
|
||||
if (of_address_to_resource(child, index, &res)) {
|
||||
of_node_put(child);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pruss->mem_regions[i].va = devm_ioremap(dev, res.start,
|
||||
resource_size(&res));
|
||||
if (!pruss->mem_regions[i].va) {
|
||||
dev_err(dev, "failed to parse and map memory resource %d %s\n",
|
||||
i, mem_names[i]);
|
||||
of_node_put(child);
|
||||
return -ENOMEM;
|
||||
}
|
||||
pruss->mem_regions[i].pa = res.start;
|
||||
pruss->mem_regions[i].size = resource_size(&res);
|
||||
|
||||
dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %pK\n",
|
||||
mem_names[i], &pruss->mem_regions[i].pa,
|
||||
pruss->mem_regions[i].size, pruss->mem_regions[i].va);
|
||||
}
|
||||
of_node_put(child);
|
||||
|
||||
platform_set_drvdata(pdev, pruss);
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "couldn't enable module\n");
|
||||
pm_runtime_put_noidle(dev);
|
||||
goto rpm_disable;
|
||||
}
|
||||
|
||||
child = of_get_child_by_name(np, "cfg");
|
||||
if (!child) {
|
||||
dev_err(dev, "%pOF is missing its 'cfg' node\n", child);
|
||||
ret = -ENODEV;
|
||||
goto rpm_put;
|
||||
}
|
||||
|
||||
if (of_address_to_resource(child, 0, &res)) {
|
||||
ret = -ENOMEM;
|
||||
goto node_put;
|
||||
}
|
||||
|
||||
pruss->cfg_base = devm_ioremap(dev, res.start, resource_size(&res));
|
||||
if (!pruss->cfg_base) {
|
||||
ret = -ENOMEM;
|
||||
goto node_put;
|
||||
}
|
||||
|
||||
regmap_conf.name = kasprintf(GFP_KERNEL, "%pOFn@%llx", child,
|
||||
(u64)res.start);
|
||||
regmap_conf.max_register = resource_size(&res) - 4;
|
||||
|
||||
pruss->cfg_regmap = devm_regmap_init_mmio(dev, pruss->cfg_base,
|
||||
®map_conf);
|
||||
kfree(regmap_conf.name);
|
||||
if (IS_ERR(pruss->cfg_regmap)) {
|
||||
dev_err(dev, "regmap_init_mmio failed for cfg, ret = %ld\n",
|
||||
PTR_ERR(pruss->cfg_regmap));
|
||||
ret = PTR_ERR(pruss->cfg_regmap);
|
||||
goto node_put;
|
||||
}
|
||||
|
||||
ret = pruss_clk_init(pruss, child);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to setup coreclk-mux\n");
|
||||
goto node_put;
|
||||
}
|
||||
|
||||
ret = devm_of_platform_populate(dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register child devices\n");
|
||||
goto node_put;
|
||||
}
|
||||
|
||||
of_node_put(child);
|
||||
|
||||
return 0;
|
||||
|
||||
node_put:
|
||||
of_node_put(child);
|
||||
rpm_put:
|
||||
pm_runtime_put_sync(dev);
|
||||
rpm_disable:
|
||||
pm_runtime_disable(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pruss_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
devm_of_platform_depopulate(dev);
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* instance-specific driver private data */
|
||||
static const struct pruss_private_data am437x_pruss1_data = {
|
||||
.has_no_sharedram = false,
|
||||
};
|
||||
|
||||
static const struct pruss_private_data am437x_pruss0_data = {
|
||||
.has_no_sharedram = true,
|
||||
};
|
||||
|
||||
static const struct pruss_private_data am65x_j721e_pruss_data = {
|
||||
.has_core_mux_clock = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id pruss_of_match[] = {
|
||||
{ .compatible = "ti,am3356-pruss" },
|
||||
{ .compatible = "ti,am4376-pruss0", .data = &am437x_pruss0_data, },
|
||||
{ .compatible = "ti,am4376-pruss1", .data = &am437x_pruss1_data, },
|
||||
{ .compatible = "ti,am5728-pruss" },
|
||||
{ .compatible = "ti,k2g-pruss" },
|
||||
{ .compatible = "ti,am654-icssg", .data = &am65x_j721e_pruss_data, },
|
||||
{ .compatible = "ti,j721e-icssg", .data = &am65x_j721e_pruss_data, },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pruss_of_match);
|
||||
|
||||
static struct platform_driver pruss_driver = {
|
||||
.driver = {
|
||||
.name = "pruss",
|
||||
.of_match_table = pruss_of_match,
|
||||
},
|
||||
.probe = pruss_probe,
|
||||
.remove = pruss_remove,
|
||||
};
|
||||
module_platform_driver(pruss_driver);
|
||||
|
||||
MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
|
||||
MODULE_DESCRIPTION("PRU-ICSS Subsystem Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
@ -18,150 +17,95 @@
|
||||
#include <dt-bindings/soc/ti,sci_pm_domain.h>
|
||||
|
||||
/**
|
||||
* struct ti_sci_genpd_dev_data: holds data needed for every device attached
|
||||
* to this genpd
|
||||
* @idx: index of the device that identifies it with the system
|
||||
* control processor.
|
||||
* @exclusive: Permissions for exclusive request or shared request of the
|
||||
* device.
|
||||
* struct ti_sci_genpd_provider: holds common TI SCI genpd provider data
|
||||
* @ti_sci: handle to TI SCI protocol driver that provides ops to
|
||||
* communicate with system control processor.
|
||||
* @dev: pointer to dev for the driver for devm allocs
|
||||
* @pd_list: list of all the power domains on the device
|
||||
* @data: onecell data for genpd core
|
||||
*/
|
||||
struct ti_sci_genpd_dev_data {
|
||||
int idx;
|
||||
u8 exclusive;
|
||||
struct ti_sci_genpd_provider {
|
||||
const struct ti_sci_handle *ti_sci;
|
||||
struct device *dev;
|
||||
struct list_head pd_list;
|
||||
struct genpd_onecell_data data;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ti_sci_pm_domain: TI specific data needed for power domain
|
||||
* @ti_sci: handle to TI SCI protocol driver that provides ops to
|
||||
* communicate with system control processor.
|
||||
* @dev: pointer to dev for the driver for devm allocs
|
||||
* @idx: index of the device that identifies it with the system
|
||||
* control processor.
|
||||
* @exclusive: Permissions for exclusive request or shared request of the
|
||||
* device.
|
||||
* @pd: generic_pm_domain for use with the genpd framework
|
||||
* @node: link for the genpd list
|
||||
* @parent: link to the parent TI SCI genpd provider
|
||||
*/
|
||||
struct ti_sci_pm_domain {
|
||||
const struct ti_sci_handle *ti_sci;
|
||||
struct device *dev;
|
||||
int idx;
|
||||
u8 exclusive;
|
||||
struct generic_pm_domain pd;
|
||||
struct list_head node;
|
||||
struct ti_sci_genpd_provider *parent;
|
||||
};
|
||||
|
||||
#define genpd_to_ti_sci_pd(gpd) container_of(gpd, struct ti_sci_pm_domain, pd)
|
||||
|
||||
/**
|
||||
* ti_sci_dev_id(): get prepopulated ti_sci id from struct dev
|
||||
* @dev: pointer to device associated with this genpd
|
||||
*
|
||||
* Returns device_id stored from ti,sci_id property
|
||||
/*
|
||||
* ti_sci_pd_power_off(): genpd power down hook
|
||||
* @domain: pointer to the powerdomain to power off
|
||||
*/
|
||||
static int ti_sci_dev_id(struct device *dev)
|
||||
static int ti_sci_pd_power_off(struct generic_pm_domain *domain)
|
||||
{
|
||||
struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev);
|
||||
struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data;
|
||||
struct ti_sci_pm_domain *pd = genpd_to_ti_sci_pd(domain);
|
||||
const struct ti_sci_handle *ti_sci = pd->parent->ti_sci;
|
||||
|
||||
return sci_dev_data->idx;
|
||||
return ti_sci->ops.dev_ops.put_device(ti_sci, pd->idx);
|
||||
}
|
||||
|
||||
static u8 is_ti_sci_dev_exclusive(struct device *dev)
|
||||
{
|
||||
struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev);
|
||||
struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data;
|
||||
|
||||
return sci_dev_data->exclusive;
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_dev_to_sci_handle(): get pointer to ti_sci_handle
|
||||
* @dev: pointer to device associated with this genpd
|
||||
*
|
||||
* Returns ti_sci_handle to be used to communicate with system
|
||||
* control processor.
|
||||
/*
|
||||
* ti_sci_pd_power_on(): genpd power up hook
|
||||
* @domain: pointer to the powerdomain to power on
|
||||
*/
|
||||
static const struct ti_sci_handle *ti_sci_dev_to_sci_handle(struct device *dev)
|
||||
static int ti_sci_pd_power_on(struct generic_pm_domain *domain)
|
||||
{
|
||||
struct generic_pm_domain *pd = pd_to_genpd(dev->pm_domain);
|
||||
struct ti_sci_pm_domain *ti_sci_genpd = genpd_to_ti_sci_pd(pd);
|
||||
struct ti_sci_pm_domain *pd = genpd_to_ti_sci_pd(domain);
|
||||
const struct ti_sci_handle *ti_sci = pd->parent->ti_sci;
|
||||
|
||||
return ti_sci_genpd->ti_sci;
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_dev_start(): genpd device start hook called to turn device on
|
||||
* @dev: pointer to device associated with this genpd to be powered on
|
||||
*/
|
||||
static int ti_sci_dev_start(struct device *dev)
|
||||
{
|
||||
const struct ti_sci_handle *ti_sci = ti_sci_dev_to_sci_handle(dev);
|
||||
int idx = ti_sci_dev_id(dev);
|
||||
|
||||
if (is_ti_sci_dev_exclusive(dev))
|
||||
return ti_sci->ops.dev_ops.get_device_exclusive(ti_sci, idx);
|
||||
if (pd->exclusive)
|
||||
return ti_sci->ops.dev_ops.get_device_exclusive(ti_sci,
|
||||
pd->idx);
|
||||
else
|
||||
return ti_sci->ops.dev_ops.get_device(ti_sci, idx);
|
||||
return ti_sci->ops.dev_ops.get_device(ti_sci, pd->idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_dev_stop(): genpd device stop hook called to turn device off
|
||||
* @dev: pointer to device associated with this genpd to be powered off
|
||||
/*
|
||||
* ti_sci_pd_xlate(): translation service for TI SCI genpds
|
||||
* @genpdspec: DT identification data for the genpd
|
||||
* @data: genpd core data for all the powerdomains on the device
|
||||
*/
|
||||
static int ti_sci_dev_stop(struct device *dev)
|
||||
static struct generic_pm_domain *ti_sci_pd_xlate(
|
||||
struct of_phandle_args *genpdspec,
|
||||
void *data)
|
||||
{
|
||||
const struct ti_sci_handle *ti_sci = ti_sci_dev_to_sci_handle(dev);
|
||||
int idx = ti_sci_dev_id(dev);
|
||||
struct genpd_onecell_data *genpd_data = data;
|
||||
unsigned int idx = genpdspec->args[0];
|
||||
|
||||
return ti_sci->ops.dev_ops.put_device(ti_sci, idx);
|
||||
}
|
||||
if (genpdspec->args_count < 2)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
static int ti_sci_pd_attach_dev(struct generic_pm_domain *domain,
|
||||
struct device *dev)
|
||||
{
|
||||
struct device_node *np = dev->of_node;
|
||||
struct of_phandle_args pd_args;
|
||||
struct ti_sci_pm_domain *ti_sci_genpd = genpd_to_ti_sci_pd(domain);
|
||||
const struct ti_sci_handle *ti_sci = ti_sci_genpd->ti_sci;
|
||||
struct ti_sci_genpd_dev_data *sci_dev_data;
|
||||
struct generic_pm_domain_data *genpd_data;
|
||||
int idx, ret = 0;
|
||||
if (idx >= genpd_data->num_domains) {
|
||||
pr_err("%s: invalid domain index %u\n", __func__, idx);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
ret = of_parse_phandle_with_args(np, "power-domains",
|
||||
"#power-domain-cells", 0, &pd_args);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (!genpd_data->domains[idx])
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
if (pd_args.args_count != 1 && pd_args.args_count != 2)
|
||||
return -EINVAL;
|
||||
genpd_to_ti_sci_pd(genpd_data->domains[idx])->exclusive =
|
||||
genpdspec->args[1];
|
||||
|
||||
idx = pd_args.args[0];
|
||||
|
||||
/*
|
||||
* Check the validity of the requested idx, if the index is not valid
|
||||
* the PMMC will return a NAK here and we will not allocate it.
|
||||
*/
|
||||
ret = ti_sci->ops.dev_ops.is_valid(ti_sci, idx);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
sci_dev_data = kzalloc(sizeof(*sci_dev_data), GFP_KERNEL);
|
||||
if (!sci_dev_data)
|
||||
return -ENOMEM;
|
||||
|
||||
sci_dev_data->idx = idx;
|
||||
/* Enable the exclusive permissions by default */
|
||||
sci_dev_data->exclusive = TI_SCI_PD_EXCLUSIVE;
|
||||
if (pd_args.args_count == 2)
|
||||
sci_dev_data->exclusive = pd_args.args[1] & 0x1;
|
||||
|
||||
genpd_data = dev_gpd_data(dev);
|
||||
genpd_data->data = sci_dev_data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ti_sci_pd_detach_dev(struct generic_pm_domain *domain,
|
||||
struct device *dev)
|
||||
{
|
||||
struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev);
|
||||
struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data;
|
||||
|
||||
kfree(sci_dev_data);
|
||||
genpd_data->data = NULL;
|
||||
return genpd_data->domains[idx];
|
||||
}
|
||||
|
||||
static const struct of_device_id ti_sci_pm_domain_matches[] = {
|
||||
@ -173,33 +117,80 @@ MODULE_DEVICE_TABLE(of, ti_sci_pm_domain_matches);
|
||||
static int ti_sci_pm_domain_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct ti_sci_pm_domain *ti_sci_pd;
|
||||
struct ti_sci_genpd_provider *pd_provider;
|
||||
struct ti_sci_pm_domain *pd;
|
||||
struct device_node *np = NULL;
|
||||
struct of_phandle_args args;
|
||||
int ret;
|
||||
u32 max_id = 0;
|
||||
int index;
|
||||
|
||||
ti_sci_pd = devm_kzalloc(dev, sizeof(*ti_sci_pd), GFP_KERNEL);
|
||||
if (!ti_sci_pd)
|
||||
pd_provider = devm_kzalloc(dev, sizeof(*pd_provider), GFP_KERNEL);
|
||||
if (!pd_provider)
|
||||
return -ENOMEM;
|
||||
|
||||
ti_sci_pd->ti_sci = devm_ti_sci_get_handle(dev);
|
||||
if (IS_ERR(ti_sci_pd->ti_sci))
|
||||
return PTR_ERR(ti_sci_pd->ti_sci);
|
||||
pd_provider->ti_sci = devm_ti_sci_get_handle(dev);
|
||||
if (IS_ERR(pd_provider->ti_sci))
|
||||
return PTR_ERR(pd_provider->ti_sci);
|
||||
|
||||
ti_sci_pd->dev = dev;
|
||||
pd_provider->dev = dev;
|
||||
|
||||
ti_sci_pd->pd.name = "ti_sci_pd";
|
||||
INIT_LIST_HEAD(&pd_provider->pd_list);
|
||||
|
||||
ti_sci_pd->pd.attach_dev = ti_sci_pd_attach_dev;
|
||||
ti_sci_pd->pd.detach_dev = ti_sci_pd_detach_dev;
|
||||
/* Find highest device ID used for power domains */
|
||||
while (1) {
|
||||
np = of_find_node_with_property(np, "power-domains");
|
||||
if (!np)
|
||||
break;
|
||||
|
||||
ti_sci_pd->pd.dev_ops.start = ti_sci_dev_start;
|
||||
ti_sci_pd->pd.dev_ops.stop = ti_sci_dev_stop;
|
||||
index = 0;
|
||||
|
||||
pm_genpd_init(&ti_sci_pd->pd, NULL, true);
|
||||
while (1) {
|
||||
ret = of_parse_phandle_with_args(np, "power-domains",
|
||||
"#power-domain-cells",
|
||||
index, &args);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
ret = of_genpd_add_provider_simple(np, &ti_sci_pd->pd);
|
||||
if (args.args_count >= 1 && args.np == dev->of_node) {
|
||||
if (args.args[0] > max_id)
|
||||
max_id = args.args[0];
|
||||
|
||||
return ret;
|
||||
pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
|
||||
if (!pd)
|
||||
return -ENOMEM;
|
||||
|
||||
pd->pd.name = devm_kasprintf(dev, GFP_KERNEL,
|
||||
"pd:%d",
|
||||
args.args[0]);
|
||||
if (!pd->pd.name)
|
||||
return -ENOMEM;
|
||||
|
||||
pd->pd.power_off = ti_sci_pd_power_off;
|
||||
pd->pd.power_on = ti_sci_pd_power_on;
|
||||
pd->idx = args.args[0];
|
||||
pd->parent = pd_provider;
|
||||
|
||||
pm_genpd_init(&pd->pd, NULL, true);
|
||||
|
||||
list_add(&pd->node, &pd_provider->pd_list);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
pd_provider->data.domains =
|
||||
devm_kcalloc(dev, max_id + 1,
|
||||
sizeof(*pd_provider->data.domains),
|
||||
GFP_KERNEL);
|
||||
|
||||
pd_provider->data.num_domains = max_id + 1;
|
||||
pd_provider->data.xlate = ti_sci_pd_xlate;
|
||||
|
||||
list_for_each_entry(pd, &pd_provider->pd_list, node)
|
||||
pd_provider->data.domains[pd->idx] = &pd->pd;
|
||||
|
||||
return of_genpd_add_provider_onecell(dev->of_node, &pd_provider->data);
|
||||
}
|
||||
|
||||
static struct platform_driver ti_sci_pm_domains_driver = {
|
||||
|
@ -216,6 +216,8 @@ static void optee_get_version(struct tee_device *teedev,
|
||||
|
||||
if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
|
||||
v.gen_caps |= TEE_GEN_CAP_REG_MEM;
|
||||
if (optee->sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL)
|
||||
v.gen_caps |= TEE_GEN_CAP_MEMREF_NULL;
|
||||
*vers = v;
|
||||
}
|
||||
|
||||
@ -262,6 +264,11 @@ static int optee_open(struct tee_context *ctx)
|
||||
mutex_init(&ctxdata->mutex);
|
||||
INIT_LIST_HEAD(&ctxdata->sess_list);
|
||||
|
||||
if (optee->sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL)
|
||||
ctx->cap_memref_null = true;
|
||||
else
|
||||
ctx->cap_memref_null = false;
|
||||
|
||||
ctx->data = ctxdata;
|
||||
return 0;
|
||||
}
|
||||
|
@ -419,4 +419,25 @@ struct optee_msg_arg {
|
||||
*/
|
||||
#define OPTEE_MSG_RPC_CMD_SHM_FREE 7
|
||||
|
||||
/*
|
||||
* Access a device on an i2c bus
|
||||
*
|
||||
* [in] param[0].u.value.a mode: RD(0), WR(1)
|
||||
* [in] param[0].u.value.b i2c adapter
|
||||
* [in] param[0].u.value.c i2c chip
|
||||
*
|
||||
* [in] param[1].u.value.a i2c control flags
|
||||
*
|
||||
* [in/out] memref[2] buffer to exchange the transfer data
|
||||
* with the secure world
|
||||
*
|
||||
* [out] param[3].u.value.a bytes transferred by the driver
|
||||
*/
|
||||
#define OPTEE_MSG_RPC_CMD_I2C_TRANSFER 21
|
||||
/* I2C master transfer modes */
|
||||
#define OPTEE_MSG_RPC_CMD_I2C_TRANSFER_RD 0
|
||||
#define OPTEE_MSG_RPC_CMD_I2C_TRANSFER_WR 1
|
||||
/* I2C master control flags */
|
||||
#define OPTEE_MSG_RPC_CMD_I2C_FLAGS_TEN_BIT BIT(0)
|
||||
|
||||
#endif /* _OPTEE_MSG_H */
|
||||
|
@ -17,6 +17,7 @@
|
||||
/* Some Global Platform error codes used in this driver */
|
||||
#define TEEC_SUCCESS 0x00000000
|
||||
#define TEEC_ERROR_BAD_PARAMETERS 0xFFFF0006
|
||||
#define TEEC_ERROR_NOT_SUPPORTED 0xFFFF000A
|
||||
#define TEEC_ERROR_COMMUNICATION 0xFFFF000E
|
||||
#define TEEC_ERROR_OUT_OF_MEMORY 0xFFFF000C
|
||||
#define TEEC_ERROR_SHORT_BUFFER 0xFFFF0010
|
||||
|
@ -215,6 +215,9 @@ struct optee_smc_get_shm_config_result {
|
||||
*/
|
||||
#define OPTEE_SMC_SEC_CAP_DYNAMIC_SHM BIT(2)
|
||||
|
||||
/* Secure world supports Shared Memory with a NULL buffer reference */
|
||||
#define OPTEE_SMC_SEC_CAP_MEMREF_NULL BIT(4)
|
||||
|
||||
#define OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES 9
|
||||
#define OPTEE_SMC_EXCHANGE_CAPABILITIES \
|
||||
OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES)
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/tee_drv.h>
|
||||
#include "optee_private.h"
|
||||
@ -49,6 +50,97 @@ bad:
|
||||
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
|
||||
#if IS_REACHABLE(CONFIG_I2C)
|
||||
static void handle_rpc_func_cmd_i2c_transfer(struct tee_context *ctx,
|
||||
struct optee_msg_arg *arg)
|
||||
{
|
||||
struct i2c_client client = { 0 };
|
||||
struct tee_param *params;
|
||||
size_t i;
|
||||
int ret = -EOPNOTSUPP;
|
||||
u8 attr[] = {
|
||||
TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
|
||||
TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
|
||||
TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT,
|
||||
TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT,
|
||||
};
|
||||
|
||||
if (arg->num_params != ARRAY_SIZE(attr)) {
|
||||
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
|
||||
return;
|
||||
}
|
||||
|
||||
params = kmalloc_array(arg->num_params, sizeof(struct tee_param),
|
||||
GFP_KERNEL);
|
||||
if (!params) {
|
||||
arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
|
||||
return;
|
||||
}
|
||||
|
||||
if (optee_from_msg_param(params, arg->num_params, arg->params))
|
||||
goto bad;
|
||||
|
||||
for (i = 0; i < arg->num_params; i++) {
|
||||
if (params[i].attr != attr[i])
|
||||
goto bad;
|
||||
}
|
||||
|
||||
client.adapter = i2c_get_adapter(params[0].u.value.b);
|
||||
if (!client.adapter)
|
||||
goto bad;
|
||||
|
||||
if (params[1].u.value.a & OPTEE_MSG_RPC_CMD_I2C_FLAGS_TEN_BIT) {
|
||||
if (!i2c_check_functionality(client.adapter,
|
||||
I2C_FUNC_10BIT_ADDR)) {
|
||||
i2c_put_adapter(client.adapter);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
client.flags = I2C_CLIENT_TEN;
|
||||
}
|
||||
|
||||
client.addr = params[0].u.value.c;
|
||||
snprintf(client.name, I2C_NAME_SIZE, "i2c%d", client.adapter->nr);
|
||||
|
||||
switch (params[0].u.value.a) {
|
||||
case OPTEE_MSG_RPC_CMD_I2C_TRANSFER_RD:
|
||||
ret = i2c_master_recv(&client, params[2].u.memref.shm->kaddr,
|
||||
params[2].u.memref.size);
|
||||
break;
|
||||
case OPTEE_MSG_RPC_CMD_I2C_TRANSFER_WR:
|
||||
ret = i2c_master_send(&client, params[2].u.memref.shm->kaddr,
|
||||
params[2].u.memref.size);
|
||||
break;
|
||||
default:
|
||||
i2c_put_adapter(client.adapter);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
arg->ret = TEEC_ERROR_COMMUNICATION;
|
||||
} else {
|
||||
params[3].u.value.a = ret;
|
||||
if (optee_to_msg_param(arg->params, arg->num_params, params))
|
||||
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
|
||||
else
|
||||
arg->ret = TEEC_SUCCESS;
|
||||
}
|
||||
|
||||
i2c_put_adapter(client.adapter);
|
||||
kfree(params);
|
||||
return;
|
||||
bad:
|
||||
kfree(params);
|
||||
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
#else
|
||||
static void handle_rpc_func_cmd_i2c_transfer(struct tee_context *ctx,
|
||||
struct optee_msg_arg *arg)
|
||||
{
|
||||
arg->ret = TEEC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct wq_entry *wq_entry_get(struct optee_wait_queue *wq, u32 key)
|
||||
{
|
||||
struct wq_entry *w;
|
||||
@ -382,6 +474,9 @@ static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee,
|
||||
case OPTEE_MSG_RPC_CMD_SHM_FREE:
|
||||
handle_rpc_func_cmd_shm_free(ctx, arg);
|
||||
break;
|
||||
case OPTEE_MSG_RPC_CMD_I2C_TRANSFER:
|
||||
handle_rpc_func_cmd_i2c_transfer(ctx, arg);
|
||||
break;
|
||||
default:
|
||||
handle_rpc_supp_cmd(ctx, arg);
|
||||
}
|
||||
|
@ -383,25 +383,38 @@ static int params_from_user(struct tee_context *ctx, struct tee_param *params,
|
||||
case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
|
||||
case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
|
||||
/*
|
||||
* If we fail to get a pointer to a shared memory
|
||||
* object (and increase the ref count) from an
|
||||
* identifier we return an error. All pointers that
|
||||
* has been added in params have an increased ref
|
||||
* count. It's the callers responibility to do
|
||||
* tee_shm_put() on all resolved pointers.
|
||||
* If a NULL pointer is passed to a TA in the TEE,
|
||||
* the ip.c IOCTL parameters is set to TEE_MEMREF_NULL
|
||||
* indicating a NULL memory reference.
|
||||
*/
|
||||
shm = tee_shm_get_from_id(ctx, ip.c);
|
||||
if (IS_ERR(shm))
|
||||
return PTR_ERR(shm);
|
||||
if (ip.c != TEE_MEMREF_NULL) {
|
||||
/*
|
||||
* If we fail to get a pointer to a shared
|
||||
* memory object (and increase the ref count)
|
||||
* from an identifier we return an error. All
|
||||
* pointers that has been added in params have
|
||||
* an increased ref count. It's the callers
|
||||
* responibility to do tee_shm_put() on all
|
||||
* resolved pointers.
|
||||
*/
|
||||
shm = tee_shm_get_from_id(ctx, ip.c);
|
||||
if (IS_ERR(shm))
|
||||
return PTR_ERR(shm);
|
||||
|
||||
/*
|
||||
* Ensure offset + size does not overflow offset
|
||||
* and does not overflow the size of the referred
|
||||
* shared memory object.
|
||||
*/
|
||||
if ((ip.a + ip.b) < ip.a ||
|
||||
(ip.a + ip.b) > shm->size) {
|
||||
tee_shm_put(shm);
|
||||
/*
|
||||
* Ensure offset + size does not overflow
|
||||
* offset and does not overflow the size of
|
||||
* the referred shared memory object.
|
||||
*/
|
||||
if ((ip.a + ip.b) < ip.a ||
|
||||
(ip.a + ip.b) > shm->size) {
|
||||
tee_shm_put(shm);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (ctx->cap_memref_null) {
|
||||
/* Pass NULL pointer to OP-TEE */
|
||||
shm = NULL;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -917,7 +930,6 @@ struct tee_device *tee_device_alloc(const struct tee_desc *teedesc,
|
||||
|
||||
cdev_init(&teedev->cdev, &tee_fops);
|
||||
teedev->cdev.owner = teedesc->owner;
|
||||
teedev->cdev.kobj.parent = &teedev->dev.kobj;
|
||||
|
||||
dev_set_drvdata(&teedev->dev, driver_data);
|
||||
device_initialize(&teedev->dev);
|
||||
@ -963,9 +975,7 @@ static struct attribute *tee_dev_attrs[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group tee_dev_group = {
|
||||
.attrs = tee_dev_attrs,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(tee_dev);
|
||||
|
||||
/**
|
||||
* tee_device_register() - Registers a TEE device
|
||||
@ -985,39 +995,19 @@ int tee_device_register(struct tee_device *teedev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = cdev_add(&teedev->cdev, teedev->dev.devt, 1);
|
||||
teedev->dev.groups = tee_dev_groups;
|
||||
|
||||
rc = cdev_device_add(&teedev->cdev, &teedev->dev);
|
||||
if (rc) {
|
||||
dev_err(&teedev->dev,
|
||||
"unable to cdev_add() %s, major %d, minor %d, err=%d\n",
|
||||
"unable to cdev_device_add() %s, major %d, minor %d, err=%d\n",
|
||||
teedev->name, MAJOR(teedev->dev.devt),
|
||||
MINOR(teedev->dev.devt), rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = device_add(&teedev->dev);
|
||||
if (rc) {
|
||||
dev_err(&teedev->dev,
|
||||
"unable to device_add() %s, major %d, minor %d, err=%d\n",
|
||||
teedev->name, MAJOR(teedev->dev.devt),
|
||||
MINOR(teedev->dev.devt), rc);
|
||||
goto err_device_add;
|
||||
}
|
||||
|
||||
rc = sysfs_create_group(&teedev->dev.kobj, &tee_dev_group);
|
||||
if (rc) {
|
||||
dev_err(&teedev->dev,
|
||||
"failed to create sysfs attributes, err=%d\n", rc);
|
||||
goto err_sysfs_create_group;
|
||||
}
|
||||
|
||||
teedev->flags |= TEE_DEVICE_FLAG_REGISTERED;
|
||||
return 0;
|
||||
|
||||
err_sysfs_create_group:
|
||||
device_del(&teedev->dev);
|
||||
err_device_add:
|
||||
cdev_del(&teedev->cdev);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tee_device_register);
|
||||
|
||||
@ -1060,11 +1050,8 @@ void tee_device_unregister(struct tee_device *teedev)
|
||||
if (!teedev)
|
||||
return;
|
||||
|
||||
if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) {
|
||||
sysfs_remove_group(&teedev->dev.kobj, &tee_dev_group);
|
||||
cdev_del(&teedev->cdev);
|
||||
device_del(&teedev->dev);
|
||||
}
|
||||
if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED)
|
||||
cdev_device_del(&teedev->cdev, &teedev->dev);
|
||||
|
||||
tee_device_put(teedev);
|
||||
wait_for_completion(&teedev->c_no_users);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user