mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-22 12:14:01 +08:00
ARM: soc: TI driver updates for v5.10
Consist of: - Add Ring accelerator support for AM65x - Add TI PRUSS platform driver and enable it on available platforms - Extend PRUSS driver for CORECLK_MUX/IEPCLK_MUX support - UDMA rx ring pair fix - Add socinfo entry for J7200 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIbBAABAgAGBQJfaBQeAAoJEHJsHOdBp5c/K1oP+Or/n3/TMOGoAKQL+2m2hhH+ c6fVzGOWEI4AkToGiE9n/EyDvh7BAvPG+j0f7SxTPUEmgbweJ2Lc6NNx+c+dssRA g6zQVzHphtGLla3u5NDOI8vQ66vw6hMY48zSRwbUuE+ee4VbUjmwTYgDN42rawQs N1Iq+KN2FzzYmT3lnJp0jDqZjKicCJ6GjYWZVlEJ6i6Yn7Rq2F1m4ilLoGejN15x bEr5IItF3kmLAuCbjgDzanSYv5ni20iGfVniNynQcTqsjzRQnJqpY2+XgWhV/nZo tT45m6AU/D7l/fbDNXecQ9X4AxLuL+JUb1nM0DcIWWPUDJauAMLzC5+IX5gg/f79 FUoUWpyxNVUuis3ZLAhzhe8uVZEcpD5Pwp7LCKr7QbBu84eCol3cUGCIvdvaAaQM 9eDBORUhkd8XdMtHDhPqpvYxUeKmlqSLHabWmEtdGVRvzJElrxF6AyUDD7ToDHiv x9wuC+bZi63gL1xukinGtTUic9vaytGrUeElslhTUGo8upZKc2XahTE0ce8e8ij5 9Vtnr7a8vQR0AanRa0yDx40IBC9w8wlnfFSNnVbQ2SOhE8YiuT0H8p2unWA6Oz4K tB+vUk+rGAZ5fnhbpSQRKWoTUbiKqU7S+lQ8gUFVzOsDy9DzoD9L+jmw1xEFUIjd 4cqaaQ9WbnBytGFmxgw= =s8sI -----END PGP SIGNATURE----- Merge tag 'drivers_soc_for_5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone into arm/drivers ARM: soc: TI driver updates for v5.10 Consist of: - Add Ring accelerator support for AM65x - Add TI PRUSS platform driver and enable it on available platforms - Extend PRUSS driver for CORECLK_MUX/IEPCLK_MUX support - UDMA rx ring pair fix - Add socinfo entry for J7200 * tag 'drivers_soc_for_5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone: Add missing '#' to fix schema errors: soc: ti: Convert to DEFINE_SHOW_ATTRIBUTE dmaengine: ti: k3-udma-glue: Fix parameters for rx ring pair request soc: ti: k3-socinfo: Add entry for J7200 soc: ti: pruss: support CORECLK_MUX and IEPCLK_MUX dt-bindings: soc: ti: Update TI PRUSS bindings regarding clock-muxes firmware: ti_sci: allow frequency change for disabled clocks by default soc: ti: ti_sci_pm_domains: switch to use multiple genpds instead of one soc: ti: pruss: Enable support for ICSSG subsystems on K3 J721E SoCs soc: ti: pruss: Enable support for ICSSG subsystems on K3 AM65x SoCs soc: ti: pruss: Add support for PRU-ICSS subsystems on 66AK2G SoC soc: ti: pruss: Add support for PRU-ICSS subsystems on AM57xx SoCs soc: ti: pruss: Add support for PRU-ICSSs on AM437x SoCs soc: ti: pruss: Add a platform driver for PRUSS in TI SoCs dt-bindings: soc: ti: Add TI PRUSS bindings bindings: soc: ti: soc: ringacc: remove ti,dma-ring-reset-quirk soc: ti: k3: ringacc: add am65x sr2.0 support Link: https://lore.kernel.org/r/1600656828-29267-1-git-send-email-santosh.shilimkar@oracle.com Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
commit
aa78dd167e
@ -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>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -579,8 +579,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) {
|
||||
|
@ -1124,7 +1124,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);
|
||||
}
|
||||
|
||||
@ -1143,7 +1144,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);
|
||||
}
|
||||
|
||||
|
@ -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,3 +12,4 @@ 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
|
||||
|
@ -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 = {
|
||||
|
54
include/linux/pruss_driver.h
Normal file
54
include/linux/pruss_driver.h
Normal file
@ -0,0 +1,54 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* PRU-ICSS sub-system specific definitions
|
||||
*
|
||||
* Copyright (C) 2014-2020 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* Suman Anna <s-anna@ti.com>
|
||||
*/
|
||||
|
||||
#ifndef _PRUSS_DRIVER_H_
|
||||
#define _PRUSS_DRIVER_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
* enum pruss_mem - PRUSS memory range identifiers
|
||||
*/
|
||||
enum pruss_mem {
|
||||
PRUSS_MEM_DRAM0 = 0,
|
||||
PRUSS_MEM_DRAM1,
|
||||
PRUSS_MEM_SHRD_RAM2,
|
||||
PRUSS_MEM_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct pruss_mem_region - PRUSS memory region structure
|
||||
* @va: kernel virtual address of the PRUSS memory region
|
||||
* @pa: physical (bus) address of the PRUSS memory region
|
||||
* @size: size of the PRUSS memory region
|
||||
*/
|
||||
struct pruss_mem_region {
|
||||
void __iomem *va;
|
||||
phys_addr_t pa;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct pruss - PRUSS parent structure
|
||||
* @dev: pruss device pointer
|
||||
* @cfg_base: base iomap for CFG region
|
||||
* @cfg_regmap: regmap for config region
|
||||
* @mem_regions: data for each of the PRUSS memory regions
|
||||
* @core_clk_mux: clk handle for PRUSS CORE_CLK_MUX
|
||||
* @iep_clk_mux: clk handle for PRUSS IEP_CLK_MUX
|
||||
*/
|
||||
struct pruss {
|
||||
struct device *dev;
|
||||
void __iomem *cfg_base;
|
||||
struct regmap *cfg_regmap;
|
||||
struct pruss_mem_region mem_regions[PRUSS_MEM_MAX];
|
||||
struct clk *core_clk_mux;
|
||||
struct clk *iep_clk_mux;
|
||||
};
|
||||
|
||||
#endif /* _PRUSS_DRIVER_H_ */
|
Loading…
Reference in New Issue
Block a user