Char/Misc driver changes for 5.6-rc1
Here is the big char/misc/whatever driver changes for 5.6-rc1 Included in here are loads of things from a variety of different driver subsystems: - soundwire updates - binder updates - nvmem updates - firmware drivers updates - extcon driver updates - various misc driver updates - fpga driver updates - interconnect subsystem and driver updates - bus driver updates - uio driver updates - mei driver updates - w1 driver cleanups - various other small driver updates All of these have been in linux-next for a while with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXjFKeQ8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ynjVACgg6JWfOyPCnz3GfRD1vQZyUl+Hg0An1H+Eh08 +LQk5Qpb3vVwBpCp6qR3 =MB+D -----END PGP SIGNATURE----- Merge tag 'char-misc-5.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc Pull char/misc driver updates from Greg KH: "Here is the big char/misc/whatever driver changes for 5.6-rc1 Included in here are loads of things from a variety of different driver subsystems: - soundwire updates - binder updates - nvmem updates - firmware drivers updates - extcon driver updates - various misc driver updates - fpga driver updates - interconnect subsystem and driver updates - bus driver updates - uio driver updates - mei driver updates - w1 driver cleanups - various other small driver updates All of these have been in linux-next for a while with no reported issues" * tag 'char-misc-5.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (86 commits) mei: me: add jasper point DID char: hpet: Use flexible-array member binder: fix log spam for existing debugfs file creation. mei: me: add comet point (lake) H device ids nvmem: add QTI SDAM driver dt-bindings: nvmem: add binding for QTI SPMI SDAM dt-bindings: imx-ocotp: Add i.MX8MP compatible dt-bindings: soundwire: fix example soundwire: cadence: fix kernel-doc parameter descriptions soundwire: intel: report slave_ids for each link to SOF driver siox: Use the correct style for SPDX License Identifier w1: omap-hdq: Simplify driver with PM runtime autosuspend firmware: stratix10-svc: Remove unneeded semicolon firmware: google: Probe for a GSMI handler in firmware firmware: google: Unregister driver_info on failure and exit in gsmi firmware: google: Release devices before unregistering the bus slimbus: qcom: add missed clk_disable_unprepare in remove slimbus: Use the correct style for SPDX License Identifier slimbus: qcom-ngd-ctrl: Use dma_request_chan() instead dma_request_slave_channel() dt-bindings: SLIMBus: add slim devices optional properties ...
This commit is contained in:
commit
701a9c8092
|
@ -0,0 +1,77 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/interconnect/qcom,msm8916.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Qualcomm MSM8916 Network-On-Chip interconnect
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Georgi Djakov <georgi.djakov@linaro.org>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
The Qualcomm MSM8916 interconnect providers support adjusting the
|
||||||
|
bandwidth requirements between the various NoC fabrics.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- qcom,msm8916-bimc
|
||||||
|
- qcom,msm8916-pcnoc
|
||||||
|
- qcom,msm8916-snoc
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
'#interconnect-cells':
|
||||||
|
const: 1
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
items:
|
||||||
|
- const: bus
|
||||||
|
- const: bus_a
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
items:
|
||||||
|
- description: Bus Clock
|
||||||
|
- description: Bus A Clock
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- '#interconnect-cells'
|
||||||
|
- clock-names
|
||||||
|
- clocks
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/clock/qcom,rpmcc.h>
|
||||||
|
|
||||||
|
bimc: interconnect@400000 {
|
||||||
|
compatible = "qcom,msm8916-bimc";
|
||||||
|
reg = <0x00400000 0x62000>;
|
||||||
|
#interconnect-cells = <1>;
|
||||||
|
clock-names = "bus", "bus_a";
|
||||||
|
clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
|
||||||
|
<&rpmcc RPM_SMD_BIMC_A_CLK>;
|
||||||
|
};
|
||||||
|
|
||||||
|
pcnoc: interconnect@500000 {
|
||||||
|
compatible = "qcom,msm8916-pcnoc";
|
||||||
|
reg = <0x00500000 0x11000>;
|
||||||
|
#interconnect-cells = <1>;
|
||||||
|
clock-names = "bus", "bus_a";
|
||||||
|
clocks = <&rpmcc RPM_SMD_PCNOC_CLK>,
|
||||||
|
<&rpmcc RPM_SMD_PCNOC_A_CLK>;
|
||||||
|
};
|
||||||
|
|
||||||
|
snoc: interconnect@580000 {
|
||||||
|
compatible = "qcom,msm8916-snoc";
|
||||||
|
reg = <0x00580000 0x14000>;
|
||||||
|
#interconnect-cells = <1>;
|
||||||
|
clock-names = "bus", "bus_a";
|
||||||
|
clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
|
||||||
|
<&rpmcc RPM_SMD_SNOC_A_CLK>;
|
||||||
|
};
|
|
@ -2,7 +2,7 @@ Freescale i.MX6 On-Chip OTP Controller (OCOTP) device tree bindings
|
||||||
|
|
||||||
This binding represents the on-chip eFuse OTP controller found on
|
This binding represents the on-chip eFuse OTP controller found on
|
||||||
i.MX6Q/D, i.MX6DL/S, i.MX6SL, i.MX6SX, i.MX6UL, i.MX6ULL/ULZ, i.MX6SLL,
|
i.MX6Q/D, i.MX6DL/S, i.MX6SL, i.MX6SX, i.MX6UL, i.MX6ULL/ULZ, i.MX6SLL,
|
||||||
i.MX7D/S, i.MX7ULP, i.MX8MQ, i.MX8MM and i.MX8MN SoCs.
|
i.MX7D/S, i.MX7ULP, i.MX8MQ, i.MX8MM, i.MX8MN and i.MX8MP SoCs.
|
||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
- compatible: should be one of
|
- compatible: should be one of
|
||||||
|
@ -17,6 +17,7 @@ Required properties:
|
||||||
"fsl,imx8mq-ocotp" (i.MX8MQ),
|
"fsl,imx8mq-ocotp" (i.MX8MQ),
|
||||||
"fsl,imx8mm-ocotp" (i.MX8MM),
|
"fsl,imx8mm-ocotp" (i.MX8MM),
|
||||||
"fsl,imx8mn-ocotp" (i.MX8MN),
|
"fsl,imx8mn-ocotp" (i.MX8MN),
|
||||||
|
"fsl,imx8mp-ocotp" (i.MX8MP),
|
||||||
followed by "syscon".
|
followed by "syscon".
|
||||||
- #address-cells : Should be 1
|
- #address-cells : Should be 1
|
||||||
- #size-cells : Should be 1
|
- #size-cells : Should be 1
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/nvmem/qcom,spmi-sdam.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Qualcomm Technologies, Inc. SPMI SDAM DT bindings
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Shyam Kumar Thella <sthella@codeaurora.org>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
The SDAM provides scratch register space for the PMIC clients. This
|
||||||
|
memory can be used by software to store information or communicate
|
||||||
|
to/from the PBUS.
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: "nvmem.yaml#"
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- qcom,spmi-sdam
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
"#address-cells":
|
||||||
|
const: 1
|
||||||
|
|
||||||
|
"#size-cells":
|
||||||
|
const: 1
|
||||||
|
|
||||||
|
ranges: true
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- ranges
|
||||||
|
|
||||||
|
patternProperties:
|
||||||
|
"^.*@[0-9a-f]+$":
|
||||||
|
type: object
|
||||||
|
|
||||||
|
properties:
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
description:
|
||||||
|
Offset and size in bytes within the storage device.
|
||||||
|
|
||||||
|
bits:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||||
|
maxItems: 1
|
||||||
|
items:
|
||||||
|
items:
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 7
|
||||||
|
description:
|
||||||
|
Offset in bit within the address range specified by reg.
|
||||||
|
- minimum: 1
|
||||||
|
description:
|
||||||
|
Size in bit within the address range specified by reg.
|
||||||
|
|
||||||
|
required:
|
||||||
|
- reg
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
sdam_1: nvram@b000 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
compatible = "qcom,spmi-sdam";
|
||||||
|
reg = <0xb000 0x100>;
|
||||||
|
ranges = <0 0xb000 0x100>;
|
||||||
|
|
||||||
|
/* Data cells */
|
||||||
|
restart_reason: restart@50 {
|
||||||
|
reg = <0x50 0x1>;
|
||||||
|
bits = <6 2>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
...
|
|
@ -32,6 +32,10 @@ Required property for SLIMbus child node if it is present:
|
||||||
Product Code, shall be in lower case hexadecimal with leading
|
Product Code, shall be in lower case hexadecimal with leading
|
||||||
zeroes suppressed
|
zeroes suppressed
|
||||||
|
|
||||||
|
Optional property for SLIMbus child node if it is present:
|
||||||
|
- slim-ifc-dev - Should be phandle to SLIMBus Interface device.
|
||||||
|
Required for devices which deal with streams.
|
||||||
|
|
||||||
SLIMbus example for Qualcomm's slimbus manager component:
|
SLIMbus example for Qualcomm's slimbus manager component:
|
||||||
|
|
||||||
slim@28080000 {
|
slim@28080000 {
|
||||||
|
@ -43,8 +47,14 @@ SLIMbus example for Qualcomm's slimbus manager component:
|
||||||
#address-cells = <2>;
|
#address-cells = <2>;
|
||||||
#size-cell = <0>;
|
#size-cell = <0>;
|
||||||
|
|
||||||
|
codec_ifd: ifd@0,0{
|
||||||
|
compatible = "slim217,60";
|
||||||
|
reg = <0 0>;
|
||||||
|
};
|
||||||
|
|
||||||
codec: wcd9310@1,0{
|
codec: wcd9310@1,0{
|
||||||
compatible = "slim217,60";
|
compatible = "slim217,60";
|
||||||
reg = <1 0>;
|
reg = <1 0>;
|
||||||
|
slim-ifc-dev = <&codec_ifd>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
Qualcomm SoundWire Controller Bindings
|
||||||
|
|
||||||
|
|
||||||
|
This binding describes the Qualcomm SoundWire Controller along with its
|
||||||
|
board specific bus parameters.
|
||||||
|
|
||||||
|
- compatible:
|
||||||
|
Usage: required
|
||||||
|
Value type: <stringlist>
|
||||||
|
Definition: must be "qcom,soundwire-v<MAJOR>.<MINOR>.<STEP>",
|
||||||
|
Example:
|
||||||
|
"qcom,soundwire-v1.3.0"
|
||||||
|
"qcom,soundwire-v1.5.0"
|
||||||
|
"qcom,soundwire-v1.6.0"
|
||||||
|
- reg:
|
||||||
|
Usage: required
|
||||||
|
Value type: <prop-encoded-array>
|
||||||
|
Definition: the base address and size of SoundWire controller
|
||||||
|
address space.
|
||||||
|
|
||||||
|
- interrupts:
|
||||||
|
Usage: required
|
||||||
|
Value type: <prop-encoded-array>
|
||||||
|
Definition: should specify the SoundWire Controller IRQ
|
||||||
|
|
||||||
|
- clock-names:
|
||||||
|
Usage: required
|
||||||
|
Value type: <stringlist>
|
||||||
|
Definition: should be "iface" for SoundWire Controller interface clock
|
||||||
|
|
||||||
|
- clocks:
|
||||||
|
Usage: required
|
||||||
|
Value type: <prop-encoded-array>
|
||||||
|
Definition: should specify the SoundWire Controller interface clock
|
||||||
|
|
||||||
|
- #sound-dai-cells:
|
||||||
|
Usage: required
|
||||||
|
Value type: <u32>
|
||||||
|
Definition: must be 1 for digital audio interfaces on the controller.
|
||||||
|
|
||||||
|
- qcom,dout-ports:
|
||||||
|
Usage: required
|
||||||
|
Value type: <u32>
|
||||||
|
Definition: must be count of data out ports
|
||||||
|
|
||||||
|
- qcom,din-ports:
|
||||||
|
Usage: required
|
||||||
|
Value type: <u32>
|
||||||
|
Definition: must be count of data in ports
|
||||||
|
|
||||||
|
- qcom,ports-offset1:
|
||||||
|
Usage: required
|
||||||
|
Value type: <prop-encoded-array>
|
||||||
|
Definition: should specify payload transport window offset1 of each
|
||||||
|
data port. Out ports followed by In ports.
|
||||||
|
More info in MIPI Alliance SoundWire 1.0 Specifications.
|
||||||
|
|
||||||
|
- qcom,ports-offset2:
|
||||||
|
Usage: required
|
||||||
|
Value type: <prop-encoded-array>
|
||||||
|
Definition: should specify payload transport window offset2 of each
|
||||||
|
data port. Out ports followed by In ports.
|
||||||
|
More info in MIPI Alliance SoundWire 1.0 Specifications.
|
||||||
|
|
||||||
|
- qcom,ports-sinterval-low:
|
||||||
|
Usage: required
|
||||||
|
Value type: <prop-encoded-array>
|
||||||
|
Definition: should be sample interval low of each data port.
|
||||||
|
Out ports followed by In ports. Used for Sample Interval
|
||||||
|
calculation.
|
||||||
|
More info in MIPI Alliance SoundWire 1.0 Specifications.
|
||||||
|
|
||||||
|
- qcom,ports-word-length:
|
||||||
|
Usage: optional
|
||||||
|
Value type: <prop-encoded-array>
|
||||||
|
Definition: should be size of payload channel sample.
|
||||||
|
More info in MIPI Alliance SoundWire 1.0 Specifications.
|
||||||
|
|
||||||
|
- qcom,ports-block-pack-mode:
|
||||||
|
Usage: optional
|
||||||
|
Value type: <prop-encoded-array>
|
||||||
|
Definition: should be 0 or 1 to indicate the block packing mode.
|
||||||
|
0 to indicate Blocks are per Channel
|
||||||
|
1 to indicate Blocks are per Port.
|
||||||
|
Out ports followed by In ports.
|
||||||
|
More info in MIPI Alliance SoundWire 1.0 Specifications.
|
||||||
|
|
||||||
|
- qcom,ports-block-group-count:
|
||||||
|
Usage: optional
|
||||||
|
Value type: <prop-encoded-array>
|
||||||
|
Definition: should be in range 1 to 4 to indicate how many sample
|
||||||
|
intervals are combined into a payload.
|
||||||
|
Out ports followed by In ports.
|
||||||
|
More info in MIPI Alliance SoundWire 1.0 Specifications.
|
||||||
|
|
||||||
|
- qcom,ports-lane-control:
|
||||||
|
Usage: optional
|
||||||
|
Value type: <prop-encoded-array>
|
||||||
|
Definition: should be in range 0 to 7 to identify which data lane
|
||||||
|
the data port uses.
|
||||||
|
Out ports followed by In ports.
|
||||||
|
More info in MIPI Alliance SoundWire 1.0 Specifications.
|
||||||
|
|
||||||
|
- qcom,ports-hstart:
|
||||||
|
Usage: optional
|
||||||
|
Value type: <prop-encoded-array>
|
||||||
|
Definition: should be number identifying lowerst numbered coloum in
|
||||||
|
SoundWire Frame, i.e. left edge of the Transport sub-frame
|
||||||
|
for each port. Values between 0 and 15 are valid.
|
||||||
|
Out ports followed by In ports.
|
||||||
|
More info in MIPI Alliance SoundWire 1.0 Specifications.
|
||||||
|
|
||||||
|
- qcom,ports-hstop:
|
||||||
|
Usage: optional
|
||||||
|
Value type: <prop-encoded-array>
|
||||||
|
Definition: should be number identifying highest numbered coloum in
|
||||||
|
SoundWire Frame, i.e. the right edge of the Transport
|
||||||
|
sub-frame for each port. Values between 0 and 15 are valid.
|
||||||
|
Out ports followed by In ports.
|
||||||
|
More info in MIPI Alliance SoundWire 1.0 Specifications.
|
||||||
|
|
||||||
|
- qcom,dports-type:
|
||||||
|
Usage: optional
|
||||||
|
Value type: <prop-encoded-array>
|
||||||
|
Definition: should be one of the following types
|
||||||
|
0 for reduced port
|
||||||
|
1 for simple ports
|
||||||
|
2 for full port
|
||||||
|
Out ports followed by In ports.
|
||||||
|
More info in MIPI Alliance SoundWire 1.0 Specifications.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
More Information on detail of encoding of these fields can be
|
||||||
|
found in MIPI Alliance SoundWire 1.0 Specifications.
|
||||||
|
|
||||||
|
= SoundWire devices
|
||||||
|
Each subnode of the bus represents SoundWire device attached to it.
|
||||||
|
The properties of these nodes are defined by the individual bindings.
|
||||||
|
|
||||||
|
= EXAMPLE
|
||||||
|
The following example represents a SoundWire controller on DB845c board
|
||||||
|
which has controller integrated inside WCD934x codec on SDM845 SoC.
|
||||||
|
|
||||||
|
soundwire: soundwire@c85 {
|
||||||
|
compatible = "qcom,soundwire-v1.3.0";
|
||||||
|
reg = <0xc85 0x20>;
|
||||||
|
interrupts = <20 IRQ_TYPE_EDGE_RISING>;
|
||||||
|
clocks = <&wcc>;
|
||||||
|
clock-names = "iface";
|
||||||
|
#sound-dai-cells = <1>;
|
||||||
|
qcom,dports-type = <0>;
|
||||||
|
qcom,dout-ports = <6>;
|
||||||
|
qcom,din-ports = <2>;
|
||||||
|
qcom,ports-sinterval-low = /bits/ 8 <0x07 0x1F 0x3F 0x7 0x1F 0x3F 0x0F 0x0F>;
|
||||||
|
qcom,ports-offset1 = /bits/ 8 <0x01 0x02 0x0C 0x6 0x12 0x0D 0x07 0x0A >;
|
||||||
|
qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x1F 0x00 0x00 0x1F 0x00 0x00>;
|
||||||
|
|
||||||
|
/* Left Speaker */
|
||||||
|
left{
|
||||||
|
....
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Right Speaker */
|
||||||
|
right{
|
||||||
|
....
|
||||||
|
};
|
||||||
|
};
|
|
@ -69,6 +69,7 @@ examples:
|
||||||
reg = <0 1>;
|
reg = <0 1>;
|
||||||
powerdown-gpios = <&wcdpinctrl 2 0>;
|
powerdown-gpios = <&wcdpinctrl 2 0>;
|
||||||
#thermal-sensor-cells = <0>;
|
#thermal-sensor-cells = <0>;
|
||||||
|
#sound-dai-cells = <0>;
|
||||||
};
|
};
|
||||||
|
|
||||||
speaker@0,2 {
|
speaker@0,2 {
|
||||||
|
@ -76,6 +77,7 @@ examples:
|
||||||
reg = <0 2>;
|
reg = <0 2>;
|
||||||
powerdown-gpios = <&wcdpinctrl 2 0>;
|
powerdown-gpios = <&wcdpinctrl 2 0>;
|
||||||
#thermal-sensor-cells = <0>;
|
#thermal-sensor-cells = <0>;
|
||||||
|
#sound-dai-cells = <0>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -91,3 +91,25 @@ Interconnect consumers are the clients which use the interconnect APIs to
|
||||||
get paths between endpoints and set their bandwidth/latency/QoS requirements
|
get paths between endpoints and set their bandwidth/latency/QoS requirements
|
||||||
for these interconnect paths. These interfaces are not currently
|
for these interconnect paths. These interfaces are not currently
|
||||||
documented.
|
documented.
|
||||||
|
|
||||||
|
Interconnect debugfs interfaces
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
Like several other subsystems interconnect will create some files for debugging
|
||||||
|
and introspection. Files in debugfs are not considered ABI so application
|
||||||
|
software shouldn't rely on format details change between kernel versions.
|
||||||
|
|
||||||
|
``/sys/kernel/debug/interconnect/interconnect_summary``:
|
||||||
|
|
||||||
|
Show all interconnect nodes in the system with their aggregated bandwidth
|
||||||
|
request. Indented under each node show bandwidth requests from each device.
|
||||||
|
|
||||||
|
``/sys/kernel/debug/interconnect/interconnect_graph``:
|
||||||
|
|
||||||
|
Show the interconnect graph in the graphviz dot format. It shows all
|
||||||
|
interconnect nodes and links in the system and groups together nodes from the
|
||||||
|
same provider as subgraphs. The format is human-readable and can also be piped
|
||||||
|
through dot to generate diagrams in many graphical formats::
|
||||||
|
|
||||||
|
$ cat /sys/kernel/debug/interconnect/interconnect_graph | \
|
||||||
|
dot -Tsvg > interconnect_graph.svg
|
||||||
|
|
|
@ -5199,10 +5199,11 @@ err_bad_arg:
|
||||||
|
|
||||||
static int binder_open(struct inode *nodp, struct file *filp)
|
static int binder_open(struct inode *nodp, struct file *filp)
|
||||||
{
|
{
|
||||||
struct binder_proc *proc;
|
struct binder_proc *proc, *itr;
|
||||||
struct binder_device *binder_dev;
|
struct binder_device *binder_dev;
|
||||||
struct binderfs_info *info;
|
struct binderfs_info *info;
|
||||||
struct dentry *binder_binderfs_dir_entry_proc = NULL;
|
struct dentry *binder_binderfs_dir_entry_proc = NULL;
|
||||||
|
bool existing_pid = false;
|
||||||
|
|
||||||
binder_debug(BINDER_DEBUG_OPEN_CLOSE, "%s: %d:%d\n", __func__,
|
binder_debug(BINDER_DEBUG_OPEN_CLOSE, "%s: %d:%d\n", __func__,
|
||||||
current->group_leader->pid, current->pid);
|
current->group_leader->pid, current->pid);
|
||||||
|
@ -5235,19 +5236,24 @@ static int binder_open(struct inode *nodp, struct file *filp)
|
||||||
filp->private_data = proc;
|
filp->private_data = proc;
|
||||||
|
|
||||||
mutex_lock(&binder_procs_lock);
|
mutex_lock(&binder_procs_lock);
|
||||||
|
hlist_for_each_entry(itr, &binder_procs, proc_node) {
|
||||||
|
if (itr->pid == proc->pid) {
|
||||||
|
existing_pid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
hlist_add_head(&proc->proc_node, &binder_procs);
|
hlist_add_head(&proc->proc_node, &binder_procs);
|
||||||
mutex_unlock(&binder_procs_lock);
|
mutex_unlock(&binder_procs_lock);
|
||||||
|
|
||||||
if (binder_debugfs_dir_entry_proc) {
|
if (binder_debugfs_dir_entry_proc && !existing_pid) {
|
||||||
char strbuf[11];
|
char strbuf[11];
|
||||||
|
|
||||||
snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
|
snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
|
||||||
/*
|
/*
|
||||||
* proc debug entries are shared between contexts, so
|
* proc debug entries are shared between contexts.
|
||||||
* this will fail if the process tries to open the driver
|
* Only create for the first PID to avoid debugfs log spamming
|
||||||
* again with a different context. The priting code will
|
* The printing code will anyway print all contexts for a given
|
||||||
* anyway print all contexts that a given PID has, so this
|
* PID so this is not a problem.
|
||||||
* is not a problem.
|
|
||||||
*/
|
*/
|
||||||
proc->debugfs_entry = debugfs_create_file(strbuf, 0444,
|
proc->debugfs_entry = debugfs_create_file(strbuf, 0444,
|
||||||
binder_debugfs_dir_entry_proc,
|
binder_debugfs_dir_entry_proc,
|
||||||
|
@ -5255,19 +5261,16 @@ static int binder_open(struct inode *nodp, struct file *filp)
|
||||||
&proc_fops);
|
&proc_fops);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (binder_binderfs_dir_entry_proc) {
|
if (binder_binderfs_dir_entry_proc && !existing_pid) {
|
||||||
char strbuf[11];
|
char strbuf[11];
|
||||||
struct dentry *binderfs_entry;
|
struct dentry *binderfs_entry;
|
||||||
|
|
||||||
snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
|
snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
|
||||||
/*
|
/*
|
||||||
* Similar to debugfs, the process specific log file is shared
|
* Similar to debugfs, the process specific log file is shared
|
||||||
* between contexts. If the file has already been created for a
|
* between contexts. Only create for the first PID.
|
||||||
* process, the following binderfs_create_file() call will
|
* This is ok since same as debugfs, the log file will contain
|
||||||
* fail with error code EEXIST if another context of the same
|
* information on all contexts of a given PID.
|
||||||
* process invoked binder_open(). This is ok since same as
|
|
||||||
* debugfs, the log file will contain information on all
|
|
||||||
* contexts of a given PID.
|
|
||||||
*/
|
*/
|
||||||
binderfs_entry = binderfs_create_file(binder_binderfs_dir_entry_proc,
|
binderfs_entry = binderfs_create_file(binder_binderfs_dir_entry_proc,
|
||||||
strbuf, &proc_fops, (void *)(unsigned long)proc->pid);
|
strbuf, &proc_fops, (void *)(unsigned long)proc->pid);
|
||||||
|
@ -5277,10 +5280,8 @@ static int binder_open(struct inode *nodp, struct file *filp)
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = PTR_ERR(binderfs_entry);
|
error = PTR_ERR(binderfs_entry);
|
||||||
if (error != -EEXIST) {
|
pr_warn("Unable to create file %s in binderfs (error %d)\n",
|
||||||
pr_warn("Unable to create file %s in binderfs (error %d)\n",
|
strbuf, error);
|
||||||
strbuf, error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -715,9 +715,9 @@ EXPORT_SYMBOL_GPL(fsl_mc_device_remove);
|
||||||
struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev)
|
struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev)
|
||||||
{
|
{
|
||||||
struct fsl_mc_device *mc_bus_dev, *endpoint;
|
struct fsl_mc_device *mc_bus_dev, *endpoint;
|
||||||
struct fsl_mc_obj_desc endpoint_desc = { 0 };
|
struct fsl_mc_obj_desc endpoint_desc = {{ 0 }};
|
||||||
struct dprc_endpoint endpoint1 = { 0 };
|
struct dprc_endpoint endpoint1 = {{ 0 }};
|
||||||
struct dprc_endpoint endpoint2 = { 0 };
|
struct dprc_endpoint endpoint2 = {{ 0 }};
|
||||||
int state, err;
|
int state, err;
|
||||||
|
|
||||||
mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent);
|
mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent);
|
||||||
|
|
|
@ -110,7 +110,7 @@ struct hpets {
|
||||||
unsigned long hp_delta;
|
unsigned long hp_delta;
|
||||||
unsigned int hp_ntimer;
|
unsigned int hp_ntimer;
|
||||||
unsigned int hp_which;
|
unsigned int hp_which;
|
||||||
struct hpet_dev hp_dev[1];
|
struct hpet_dev hp_dev[];
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct hpets *hpets;
|
static struct hpets *hpets;
|
||||||
|
|
|
@ -77,8 +77,6 @@ struct arizona_extcon_info {
|
||||||
const struct arizona_micd_range *micd_ranges;
|
const struct arizona_micd_range *micd_ranges;
|
||||||
int num_micd_ranges;
|
int num_micd_ranges;
|
||||||
|
|
||||||
int micd_timeout;
|
|
||||||
|
|
||||||
bool micd_reva;
|
bool micd_reva;
|
||||||
bool micd_clamp;
|
bool micd_clamp;
|
||||||
|
|
||||||
|
@ -310,9 +308,13 @@ static void arizona_start_mic(struct arizona_extcon_info *info)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->micd_reva) {
|
if (info->micd_reva) {
|
||||||
regmap_write(arizona->regmap, 0x80, 0x3);
|
const struct reg_sequence reva[] = {
|
||||||
regmap_write(arizona->regmap, 0x294, 0);
|
{ 0x80, 0x3 },
|
||||||
regmap_write(arizona->regmap, 0x80, 0x0);
|
{ 0x294, 0x0 },
|
||||||
|
{ 0x80, 0x0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
regmap_multi_reg_write(arizona->regmap, reva, ARRAY_SIZE(reva));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->detecting && arizona->pdata.micd_software_compare)
|
if (info->detecting && arizona->pdata.micd_software_compare)
|
||||||
|
@ -361,9 +363,13 @@ static void arizona_stop_mic(struct arizona_extcon_info *info)
|
||||||
snd_soc_dapm_sync(dapm);
|
snd_soc_dapm_sync(dapm);
|
||||||
|
|
||||||
if (info->micd_reva) {
|
if (info->micd_reva) {
|
||||||
regmap_write(arizona->regmap, 0x80, 0x3);
|
const struct reg_sequence reva[] = {
|
||||||
regmap_write(arizona->regmap, 0x294, 2);
|
{ 0x80, 0x3 },
|
||||||
regmap_write(arizona->regmap, 0x80, 0x0);
|
{ 0x294, 0x2 },
|
||||||
|
{ 0x80, 0x0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
regmap_multi_reg_write(arizona->regmap, reva, ARRAY_SIZE(reva));
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = regulator_allow_bypass(info->micvdd, true);
|
ret = regulator_allow_bypass(info->micvdd, true);
|
||||||
|
@ -527,67 +533,65 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
|
||||||
struct arizona *arizona = info->arizona;
|
struct arizona *arizona = info->arizona;
|
||||||
int id_gpio = arizona->pdata.hpdet_id_gpio;
|
int id_gpio = arizona->pdata.hpdet_id_gpio;
|
||||||
|
|
||||||
|
if (!arizona->pdata.hpdet_acc_id)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we're using HPDET for accessory identification we need
|
* If we're using HPDET for accessory identification we need
|
||||||
* to take multiple measurements, step through them in sequence.
|
* to take multiple measurements, step through them in sequence.
|
||||||
*/
|
*/
|
||||||
if (arizona->pdata.hpdet_acc_id) {
|
info->hpdet_res[info->num_hpdet_res++] = *reading;
|
||||||
info->hpdet_res[info->num_hpdet_res++] = *reading;
|
|
||||||
|
|
||||||
/* Only check the mic directly if we didn't already ID it */
|
/* Only check the mic directly if we didn't already ID it */
|
||||||
if (id_gpio && info->num_hpdet_res == 1) {
|
if (id_gpio && info->num_hpdet_res == 1) {
|
||||||
dev_dbg(arizona->dev, "Measuring mic\n");
|
dev_dbg(arizona->dev, "Measuring mic\n");
|
||||||
|
|
||||||
regmap_update_bits(arizona->regmap,
|
|
||||||
ARIZONA_ACCESSORY_DETECT_MODE_1,
|
|
||||||
ARIZONA_ACCDET_MODE_MASK |
|
|
||||||
ARIZONA_ACCDET_SRC,
|
|
||||||
ARIZONA_ACCDET_MODE_HPR |
|
|
||||||
info->micd_modes[0].src);
|
|
||||||
|
|
||||||
gpio_set_value_cansleep(id_gpio, 1);
|
|
||||||
|
|
||||||
regmap_update_bits(arizona->regmap,
|
|
||||||
ARIZONA_HEADPHONE_DETECT_1,
|
|
||||||
ARIZONA_HP_POLL, ARIZONA_HP_POLL);
|
|
||||||
return -EAGAIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* OK, got both. Now, compare... */
|
|
||||||
dev_dbg(arizona->dev, "HPDET measured %d %d\n",
|
|
||||||
info->hpdet_res[0], info->hpdet_res[1]);
|
|
||||||
|
|
||||||
/* Take the headphone impedance for the main report */
|
|
||||||
*reading = info->hpdet_res[0];
|
|
||||||
|
|
||||||
/* Sometimes we get false readings due to slow insert */
|
|
||||||
if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
|
|
||||||
dev_dbg(arizona->dev, "Retrying high impedance\n");
|
|
||||||
info->num_hpdet_res = 0;
|
|
||||||
info->hpdet_retried = true;
|
|
||||||
arizona_start_hpdet_acc_id(info);
|
|
||||||
pm_runtime_put(info->dev);
|
|
||||||
return -EAGAIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If we measure the mic as high impedance
|
|
||||||
*/
|
|
||||||
if (!id_gpio || info->hpdet_res[1] > 50) {
|
|
||||||
dev_dbg(arizona->dev, "Detected mic\n");
|
|
||||||
*mic = true;
|
|
||||||
info->detecting = true;
|
|
||||||
} else {
|
|
||||||
dev_dbg(arizona->dev, "Detected headphone\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure everything is reset back to the real polarity */
|
|
||||||
regmap_update_bits(arizona->regmap,
|
regmap_update_bits(arizona->regmap,
|
||||||
ARIZONA_ACCESSORY_DETECT_MODE_1,
|
ARIZONA_ACCESSORY_DETECT_MODE_1,
|
||||||
|
ARIZONA_ACCDET_MODE_MASK |
|
||||||
ARIZONA_ACCDET_SRC,
|
ARIZONA_ACCDET_SRC,
|
||||||
|
ARIZONA_ACCDET_MODE_HPR |
|
||||||
info->micd_modes[0].src);
|
info->micd_modes[0].src);
|
||||||
|
|
||||||
|
gpio_set_value_cansleep(id_gpio, 1);
|
||||||
|
|
||||||
|
regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
|
||||||
|
ARIZONA_HP_POLL, ARIZONA_HP_POLL);
|
||||||
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* OK, got both. Now, compare... */
|
||||||
|
dev_dbg(arizona->dev, "HPDET measured %d %d\n",
|
||||||
|
info->hpdet_res[0], info->hpdet_res[1]);
|
||||||
|
|
||||||
|
/* Take the headphone impedance for the main report */
|
||||||
|
*reading = info->hpdet_res[0];
|
||||||
|
|
||||||
|
/* Sometimes we get false readings due to slow insert */
|
||||||
|
if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
|
||||||
|
dev_dbg(arizona->dev, "Retrying high impedance\n");
|
||||||
|
info->num_hpdet_res = 0;
|
||||||
|
info->hpdet_retried = true;
|
||||||
|
arizona_start_hpdet_acc_id(info);
|
||||||
|
pm_runtime_put(info->dev);
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we measure the mic as high impedance
|
||||||
|
*/
|
||||||
|
if (!id_gpio || info->hpdet_res[1] > 50) {
|
||||||
|
dev_dbg(arizona->dev, "Detected mic\n");
|
||||||
|
*mic = true;
|
||||||
|
info->detecting = true;
|
||||||
|
} else {
|
||||||
|
dev_dbg(arizona->dev, "Detected headphone\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure everything is reset back to the real polarity */
|
||||||
|
regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
|
||||||
|
ARIZONA_ACCDET_SRC, info->micd_modes[0].src);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -662,11 +666,6 @@ done:
|
||||||
if (id_gpio)
|
if (id_gpio)
|
||||||
gpio_set_value_cansleep(id_gpio, 0);
|
gpio_set_value_cansleep(id_gpio, 0);
|
||||||
|
|
||||||
/* Revert back to MICDET mode */
|
|
||||||
regmap_update_bits(arizona->regmap,
|
|
||||||
ARIZONA_ACCESSORY_DETECT_MODE_1,
|
|
||||||
ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
|
|
||||||
|
|
||||||
/* If we have a mic then reenable MICDET */
|
/* If we have a mic then reenable MICDET */
|
||||||
if (mic || info->mic)
|
if (mic || info->mic)
|
||||||
arizona_start_mic(info);
|
arizona_start_mic(info);
|
||||||
|
@ -699,8 +698,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info)
|
||||||
|
|
||||||
info->hpdet_active = true;
|
info->hpdet_active = true;
|
||||||
|
|
||||||
if (info->mic)
|
arizona_stop_mic(info);
|
||||||
arizona_stop_mic(info);
|
|
||||||
|
|
||||||
arizona_extcon_hp_clamp(info, true);
|
arizona_extcon_hp_clamp(info, true);
|
||||||
|
|
||||||
|
@ -724,8 +722,8 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
|
arizona_extcon_hp_clamp(info, false);
|
||||||
ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
|
pm_runtime_put_autosuspend(info->dev);
|
||||||
|
|
||||||
/* Just report headphone */
|
/* Just report headphone */
|
||||||
ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
|
ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
|
||||||
|
@ -781,9 +779,6 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
|
|
||||||
ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
|
|
||||||
|
|
||||||
/* Just report headphone */
|
/* Just report headphone */
|
||||||
ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
|
ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
|
@ -806,75 +801,58 @@ static void arizona_micd_timeout_work(struct work_struct *work)
|
||||||
|
|
||||||
arizona_identify_headphone(info);
|
arizona_identify_headphone(info);
|
||||||
|
|
||||||
arizona_stop_mic(info);
|
|
||||||
|
|
||||||
mutex_unlock(&info->lock);
|
mutex_unlock(&info->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arizona_micd_detect(struct work_struct *work)
|
static int arizona_micd_adc_read(struct arizona_extcon_info *info)
|
||||||
{
|
{
|
||||||
struct arizona_extcon_info *info = container_of(work,
|
|
||||||
struct arizona_extcon_info,
|
|
||||||
micd_detect_work.work);
|
|
||||||
struct arizona *arizona = info->arizona;
|
struct arizona *arizona = info->arizona;
|
||||||
unsigned int val = 0, lvl;
|
unsigned int val;
|
||||||
int ret, i, key;
|
int ret;
|
||||||
|
|
||||||
cancel_delayed_work_sync(&info->micd_timeout_work);
|
/* Must disable MICD before we read the ADCVAL */
|
||||||
|
regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
|
||||||
|
ARIZONA_MICD_ENA, 0);
|
||||||
|
|
||||||
mutex_lock(&info->lock);
|
ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val);
|
||||||
|
if (ret != 0) {
|
||||||
/* If the cable was removed while measuring ignore the result */
|
dev_err(arizona->dev,
|
||||||
ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
|
"Failed to read MICDET_ADCVAL: %d\n", ret);
|
||||||
if (ret < 0) {
|
return ret;
|
||||||
dev_err(arizona->dev, "Failed to check cable state: %d\n",
|
|
||||||
ret);
|
|
||||||
mutex_unlock(&info->lock);
|
|
||||||
return;
|
|
||||||
} else if (!ret) {
|
|
||||||
dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
|
|
||||||
mutex_unlock(&info->lock);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->detecting && arizona->pdata.micd_software_compare) {
|
dev_dbg(arizona->dev, "MICDET_ADCVAL: %x\n", val);
|
||||||
/* Must disable MICD before we read the ADCVAL */
|
|
||||||
regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
|
|
||||||
ARIZONA_MICD_ENA, 0);
|
|
||||||
ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val);
|
|
||||||
if (ret != 0) {
|
|
||||||
dev_err(arizona->dev,
|
|
||||||
"Failed to read MICDET_ADCVAL: %d\n",
|
|
||||||
ret);
|
|
||||||
mutex_unlock(&info->lock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_dbg(arizona->dev, "MICDET_ADCVAL: %x\n", val);
|
val &= ARIZONA_MICDET_ADCVAL_MASK;
|
||||||
|
if (val < ARRAY_SIZE(arizona_micd_levels))
|
||||||
|
val = arizona_micd_levels[val];
|
||||||
|
else
|
||||||
|
val = INT_MAX;
|
||||||
|
|
||||||
val &= ARIZONA_MICDET_ADCVAL_MASK;
|
if (val <= QUICK_HEADPHONE_MAX_OHM)
|
||||||
if (val < ARRAY_SIZE(arizona_micd_levels))
|
val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_0;
|
||||||
val = arizona_micd_levels[val];
|
else if (val <= MICROPHONE_MIN_OHM)
|
||||||
else
|
val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_1;
|
||||||
val = INT_MAX;
|
else if (val <= MICROPHONE_MAX_OHM)
|
||||||
|
val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_8;
|
||||||
|
else
|
||||||
|
val = ARIZONA_MICD_LVL_8;
|
||||||
|
|
||||||
if (val <= QUICK_HEADPHONE_MAX_OHM)
|
return val;
|
||||||
val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_0;
|
}
|
||||||
else if (val <= MICROPHONE_MIN_OHM)
|
|
||||||
val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_1;
|
static int arizona_micd_read(struct arizona_extcon_info *info)
|
||||||
else if (val <= MICROPHONE_MAX_OHM)
|
{
|
||||||
val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_8;
|
struct arizona *arizona = info->arizona;
|
||||||
else
|
unsigned int val = 0;
|
||||||
val = ARIZONA_MICD_LVL_8;
|
int ret, i;
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
|
for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
|
||||||
ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
|
ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
dev_err(arizona->dev,
|
dev_err(arizona->dev,
|
||||||
"Failed to read MICDET: %d\n", ret);
|
"Failed to read MICDET: %d\n", ret);
|
||||||
mutex_unlock(&info->lock);
|
return ret;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(arizona->dev, "MICDET: %x\n", val);
|
dev_dbg(arizona->dev, "MICDET: %x\n", val);
|
||||||
|
@ -882,29 +860,44 @@ static void arizona_micd_detect(struct work_struct *work)
|
||||||
if (!(val & ARIZONA_MICD_VALID)) {
|
if (!(val & ARIZONA_MICD_VALID)) {
|
||||||
dev_warn(arizona->dev,
|
dev_warn(arizona->dev,
|
||||||
"Microphone detection state invalid\n");
|
"Microphone detection state invalid\n");
|
||||||
mutex_unlock(&info->lock);
|
return -EINVAL;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
|
if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
|
||||||
dev_err(arizona->dev, "Failed to get valid MICDET value\n");
|
dev_err(arizona->dev, "Failed to get valid MICDET value\n");
|
||||||
mutex_unlock(&info->lock);
|
return -EINVAL;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int arizona_micdet_reading(void *priv)
|
||||||
|
{
|
||||||
|
struct arizona_extcon_info *info = priv;
|
||||||
|
struct arizona *arizona = info->arizona;
|
||||||
|
int ret, val;
|
||||||
|
|
||||||
|
if (info->detecting && arizona->pdata.micd_software_compare)
|
||||||
|
ret = arizona_micd_adc_read(info);
|
||||||
|
else
|
||||||
|
ret = arizona_micd_read(info);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
val = ret;
|
||||||
|
|
||||||
/* Due to jack detect this should never happen */
|
/* Due to jack detect this should never happen */
|
||||||
if (!(val & ARIZONA_MICD_STS)) {
|
if (!(val & ARIZONA_MICD_STS)) {
|
||||||
dev_warn(arizona->dev, "Detected open circuit\n");
|
dev_warn(arizona->dev, "Detected open circuit\n");
|
||||||
info->mic = false;
|
info->mic = false;
|
||||||
arizona_stop_mic(info);
|
|
||||||
info->detecting = false;
|
info->detecting = false;
|
||||||
arizona_identify_headphone(info);
|
arizona_identify_headphone(info);
|
||||||
goto handled;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we got a high impedence we should have a headset, report it. */
|
/* If we got a high impedence we should have a headset, report it. */
|
||||||
if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
|
if (val & ARIZONA_MICD_LVL_8) {
|
||||||
info->mic = true;
|
info->mic = true;
|
||||||
info->detecting = false;
|
info->detecting = false;
|
||||||
|
|
||||||
|
@ -923,7 +916,7 @@ static void arizona_micd_detect(struct work_struct *work)
|
||||||
ret);
|
ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
goto handled;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we detected a lower impedence during initial startup
|
/* If we detected a lower impedence during initial startup
|
||||||
|
@ -932,15 +925,13 @@ static void arizona_micd_detect(struct work_struct *work)
|
||||||
* plain headphones. If both polarities report a low
|
* plain headphones. If both polarities report a low
|
||||||
* impedence then give up and report headphones.
|
* impedence then give up and report headphones.
|
||||||
*/
|
*/
|
||||||
if (info->detecting && (val & MICD_LVL_1_TO_7)) {
|
if (val & MICD_LVL_1_TO_7) {
|
||||||
if (info->jack_flips >= info->micd_num_modes * 10) {
|
if (info->jack_flips >= info->micd_num_modes * 10) {
|
||||||
dev_dbg(arizona->dev, "Detected HP/line\n");
|
dev_dbg(arizona->dev, "Detected HP/line\n");
|
||||||
|
|
||||||
info->detecting = false;
|
info->detecting = false;
|
||||||
|
|
||||||
arizona_identify_headphone(info);
|
arizona_identify_headphone(info);
|
||||||
|
|
||||||
arizona_stop_mic(info);
|
|
||||||
} else {
|
} else {
|
||||||
info->micd_mode++;
|
info->micd_mode++;
|
||||||
if (info->micd_mode == info->micd_num_modes)
|
if (info->micd_mode == info->micd_num_modes)
|
||||||
|
@ -948,11 +939,43 @@ static void arizona_micd_detect(struct work_struct *work)
|
||||||
arizona_extcon_set_mode(info, info->micd_mode);
|
arizona_extcon_set_mode(info, info->micd_mode);
|
||||||
|
|
||||||
info->jack_flips++;
|
info->jack_flips++;
|
||||||
|
|
||||||
|
if (arizona->pdata.micd_software_compare)
|
||||||
|
regmap_update_bits(arizona->regmap,
|
||||||
|
ARIZONA_MIC_DETECT_1,
|
||||||
|
ARIZONA_MICD_ENA,
|
||||||
|
ARIZONA_MICD_ENA);
|
||||||
|
|
||||||
|
queue_delayed_work(system_power_efficient_wq,
|
||||||
|
&info->micd_timeout_work,
|
||||||
|
msecs_to_jiffies(arizona->pdata.micd_timeout));
|
||||||
}
|
}
|
||||||
|
|
||||||
goto handled;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we're still detecting and we detect a short then we've
|
||||||
|
* got a headphone.
|
||||||
|
*/
|
||||||
|
dev_dbg(arizona->dev, "Headphone detected\n");
|
||||||
|
info->detecting = false;
|
||||||
|
|
||||||
|
arizona_identify_headphone(info);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int arizona_button_reading(void *priv)
|
||||||
|
{
|
||||||
|
struct arizona_extcon_info *info = priv;
|
||||||
|
struct arizona *arizona = info->arizona;
|
||||||
|
int val, key, lvl, i;
|
||||||
|
|
||||||
|
val = arizona_micd_read(info);
|
||||||
|
if (val < 0)
|
||||||
|
return val;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we're still detecting and we detect a short then we've
|
* If we're still detecting and we detect a short then we've
|
||||||
* got a headphone. Otherwise it's a button press.
|
* got a headphone. Otherwise it's a button press.
|
||||||
|
@ -968,20 +991,13 @@ static void arizona_micd_detect(struct work_struct *work)
|
||||||
input_report_key(info->input,
|
input_report_key(info->input,
|
||||||
info->micd_ranges[i].key, 0);
|
info->micd_ranges[i].key, 0);
|
||||||
|
|
||||||
WARN_ON(!lvl);
|
|
||||||
WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
|
|
||||||
if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
|
if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
|
||||||
key = info->micd_ranges[ffs(lvl) - 1].key;
|
key = info->micd_ranges[ffs(lvl) - 1].key;
|
||||||
input_report_key(info->input, key, 1);
|
input_report_key(info->input, key, 1);
|
||||||
input_sync(info->input);
|
input_sync(info->input);
|
||||||
|
} else {
|
||||||
|
dev_err(arizona->dev, "Button out of range\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (info->detecting) {
|
|
||||||
dev_dbg(arizona->dev, "Headphone detected\n");
|
|
||||||
info->detecting = false;
|
|
||||||
arizona_stop_mic(info);
|
|
||||||
|
|
||||||
arizona_identify_headphone(info);
|
|
||||||
} else {
|
} else {
|
||||||
dev_warn(arizona->dev, "Button with no mic: %x\n",
|
dev_warn(arizona->dev, "Button with no mic: %x\n",
|
||||||
val);
|
val);
|
||||||
|
@ -995,19 +1011,39 @@ static void arizona_micd_detect(struct work_struct *work)
|
||||||
arizona_extcon_pulse_micbias(info);
|
arizona_extcon_pulse_micbias(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
handled:
|
return 0;
|
||||||
if (info->detecting) {
|
}
|
||||||
if (arizona->pdata.micd_software_compare)
|
|
||||||
regmap_update_bits(arizona->regmap,
|
|
||||||
ARIZONA_MIC_DETECT_1,
|
|
||||||
ARIZONA_MICD_ENA,
|
|
||||||
ARIZONA_MICD_ENA);
|
|
||||||
|
|
||||||
queue_delayed_work(system_power_efficient_wq,
|
static void arizona_micd_detect(struct work_struct *work)
|
||||||
&info->micd_timeout_work,
|
{
|
||||||
msecs_to_jiffies(info->micd_timeout));
|
struct arizona_extcon_info *info = container_of(work,
|
||||||
|
struct arizona_extcon_info,
|
||||||
|
micd_detect_work.work);
|
||||||
|
struct arizona *arizona = info->arizona;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
cancel_delayed_work_sync(&info->micd_timeout_work);
|
||||||
|
|
||||||
|
mutex_lock(&info->lock);
|
||||||
|
|
||||||
|
/* If the cable was removed while measuring ignore the result */
|
||||||
|
ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(arizona->dev, "Failed to check cable state: %d\n",
|
||||||
|
ret);
|
||||||
|
mutex_unlock(&info->lock);
|
||||||
|
return;
|
||||||
|
} else if (!ret) {
|
||||||
|
dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
|
||||||
|
mutex_unlock(&info->lock);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (info->detecting)
|
||||||
|
arizona_micdet_reading(info);
|
||||||
|
else
|
||||||
|
arizona_button_reading(info);
|
||||||
|
|
||||||
pm_runtime_mark_last_busy(info->dev);
|
pm_runtime_mark_last_busy(info->dev);
|
||||||
mutex_unlock(&info->lock);
|
mutex_unlock(&info->lock);
|
||||||
}
|
}
|
||||||
|
@ -1125,7 +1161,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
|
||||||
msecs_to_jiffies(HPDET_DEBOUNCE));
|
msecs_to_jiffies(HPDET_DEBOUNCE));
|
||||||
|
|
||||||
if (cancelled_mic) {
|
if (cancelled_mic) {
|
||||||
int micd_timeout = info->micd_timeout;
|
int micd_timeout = arizona->pdata.micd_timeout;
|
||||||
|
|
||||||
queue_delayed_work(system_power_efficient_wq,
|
queue_delayed_work(system_power_efficient_wq,
|
||||||
&info->micd_timeout_work,
|
&info->micd_timeout_work,
|
||||||
|
@ -1145,11 +1181,11 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
|
||||||
dev_err(arizona->dev, "Mechanical report failed: %d\n",
|
dev_err(arizona->dev, "Mechanical report failed: %d\n",
|
||||||
ret);
|
ret);
|
||||||
|
|
||||||
if (!arizona->pdata.hpdet_acc_id) {
|
info->detecting = true;
|
||||||
info->detecting = true;
|
info->mic = false;
|
||||||
info->mic = false;
|
info->jack_flips = 0;
|
||||||
info->jack_flips = 0;
|
|
||||||
|
|
||||||
|
if (!arizona->pdata.hpdet_acc_id) {
|
||||||
arizona_start_mic(info);
|
arizona_start_mic(info);
|
||||||
} else {
|
} else {
|
||||||
queue_delayed_work(system_power_efficient_wq,
|
queue_delayed_work(system_power_efficient_wq,
|
||||||
|
@ -1202,11 +1238,6 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
|
||||||
ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
|
ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arizona->pdata.micd_timeout)
|
|
||||||
info->micd_timeout = arizona->pdata.micd_timeout;
|
|
||||||
else
|
|
||||||
info->micd_timeout = DEFAULT_MICD_TIMEOUT;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
/* Clear trig_sts to make sure DCVDD is not forced up */
|
/* Clear trig_sts to make sure DCVDD is not forced up */
|
||||||
regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
|
regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
|
||||||
|
@ -1435,6 +1466,9 @@ static int arizona_extcon_probe(struct platform_device *pdev)
|
||||||
info->input->name = "Headset";
|
info->input->name = "Headset";
|
||||||
info->input->phys = "arizona/extcon";
|
info->input->phys = "arizona/extcon";
|
||||||
|
|
||||||
|
if (!pdata->micd_timeout)
|
||||||
|
pdata->micd_timeout = DEFAULT_MICD_TIMEOUT;
|
||||||
|
|
||||||
if (pdata->num_micd_configs) {
|
if (pdata->num_micd_configs) {
|
||||||
info->micd_modes = pdata->micd_configs;
|
info->micd_modes = pdata->micd_configs;
|
||||||
info->micd_num_modes = pdata->num_micd_configs;
|
info->micd_num_modes = pdata->num_micd_configs;
|
||||||
|
|
|
@ -249,7 +249,7 @@ static int sm5502_muic_set_path(struct sm5502_muic_info *info,
|
||||||
dev_err(info->dev, "Unknown DM_CON/DP_CON switch type (%d)\n",
|
dev_err(info->dev, "Unknown DM_CON/DP_CON switch type (%d)\n",
|
||||||
con_sw);
|
con_sw);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
};
|
}
|
||||||
|
|
||||||
switch (vbus_sw) {
|
switch (vbus_sw) {
|
||||||
case VBUSIN_SWITCH_OPEN:
|
case VBUSIN_SWITCH_OPEN:
|
||||||
|
@ -268,7 +268,7 @@ static int sm5502_muic_set_path(struct sm5502_muic_info *info,
|
||||||
default:
|
default:
|
||||||
dev_err(info->dev, "Unknown VBUS switch type (%d)\n", vbus_sw);
|
dev_err(info->dev, "Unknown VBUS switch type (%d)\n", vbus_sw);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
};
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -357,13 +357,13 @@ static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info)
|
||||||
"cannot identify the cable type: adc(0x%x)\n",
|
"cannot identify the cable type: adc(0x%x)\n",
|
||||||
adc);
|
adc);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
};
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(info->dev,
|
dev_err(info->dev,
|
||||||
"failed to identify the cable type: adc(0x%x)\n", adc);
|
"failed to identify the cable type: adc(0x%x)\n", adc);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
};
|
}
|
||||||
|
|
||||||
return cable_type;
|
return cable_type;
|
||||||
}
|
}
|
||||||
|
@ -405,7 +405,7 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info,
|
||||||
dev_dbg(info->dev,
|
dev_dbg(info->dev,
|
||||||
"cannot handle this cable_type (0x%x)\n", cable_type);
|
"cannot handle this cable_type (0x%x)\n", cable_type);
|
||||||
return 0;
|
return 0;
|
||||||
};
|
}
|
||||||
|
|
||||||
/* Change internal hardware path(DM_CON/DP_CON, VBUSIN) */
|
/* Change internal hardware path(DM_CON/DP_CON, VBUSIN) */
|
||||||
ret = sm5502_muic_set_path(info, con_sw, vbus_sw, attached);
|
ret = sm5502_muic_set_path(info, con_sw, vbus_sw, attached);
|
||||||
|
|
|
@ -163,8 +163,15 @@ static int coreboot_table_probe(struct platform_device *pdev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __cb_dev_unregister(struct device *dev, void *dummy)
|
||||||
|
{
|
||||||
|
device_unregister(dev);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int coreboot_table_remove(struct platform_device *pdev)
|
static int coreboot_table_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
bus_for_each_dev(&coreboot_bus_type, NULL, NULL, __cb_dev_unregister);
|
||||||
bus_unregister(&coreboot_bus_type);
|
bus_unregister(&coreboot_bus_type);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,7 @@
|
||||||
#define GSMI_CMD_LOG_S0IX_RESUME 0x0b
|
#define GSMI_CMD_LOG_S0IX_RESUME 0x0b
|
||||||
#define GSMI_CMD_CLEAR_CONFIG 0x20
|
#define GSMI_CMD_CLEAR_CONFIG 0x20
|
||||||
#define GSMI_CMD_HANDSHAKE_TYPE 0xC1
|
#define GSMI_CMD_HANDSHAKE_TYPE 0xC1
|
||||||
|
#define GSMI_CMD_RESERVED 0xff
|
||||||
|
|
||||||
/* Magic entry type for kernel events */
|
/* Magic entry type for kernel events */
|
||||||
#define GSMI_LOG_ENTRY_TYPE_KERNEL 0xDEAD
|
#define GSMI_LOG_ENTRY_TYPE_KERNEL 0xDEAD
|
||||||
|
@ -746,6 +747,7 @@ MODULE_DEVICE_TABLE(dmi, gsmi_dmi_table);
|
||||||
static __init int gsmi_system_valid(void)
|
static __init int gsmi_system_valid(void)
|
||||||
{
|
{
|
||||||
u32 hash;
|
u32 hash;
|
||||||
|
u16 cmd, result;
|
||||||
|
|
||||||
if (!dmi_check_system(gsmi_dmi_table))
|
if (!dmi_check_system(gsmi_dmi_table))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
@ -780,6 +782,23 @@ static __init int gsmi_system_valid(void)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Test the smihandler with a bogus command. If it leaves the
|
||||||
|
* calling argument in %ax untouched, there is no handler for
|
||||||
|
* GSMI commands.
|
||||||
|
*/
|
||||||
|
cmd = GSMI_CALLBACK | GSMI_CMD_RESERVED << 8;
|
||||||
|
asm volatile (
|
||||||
|
"outb %%al, %%dx\n\t"
|
||||||
|
: "=a" (result)
|
||||||
|
: "0" (cmd),
|
||||||
|
"d" (acpi_gbl_FADT.smi_command)
|
||||||
|
: "memory", "cc"
|
||||||
|
);
|
||||||
|
if (cmd == result) {
|
||||||
|
pr_info("gsmi: no gsmi handler in firmware\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
/* Found */
|
/* Found */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1016,6 +1035,9 @@ out_err:
|
||||||
dma_pool_destroy(gsmi_dev.dma_pool);
|
dma_pool_destroy(gsmi_dev.dma_pool);
|
||||||
platform_device_unregister(gsmi_dev.pdev);
|
platform_device_unregister(gsmi_dev.pdev);
|
||||||
pr_info("gsmi: failed to load: %d\n", ret);
|
pr_info("gsmi: failed to load: %d\n", ret);
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
platform_driver_unregister(&gsmi_driver_info);
|
||||||
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1037,6 +1059,9 @@ static void __exit gsmi_exit(void)
|
||||||
gsmi_buf_free(gsmi_dev.name_buf);
|
gsmi_buf_free(gsmi_dev.name_buf);
|
||||||
dma_pool_destroy(gsmi_dev.dma_pool);
|
dma_pool_destroy(gsmi_dev.dma_pool);
|
||||||
platform_device_unregister(gsmi_dev.pdev);
|
platform_device_unregister(gsmi_dev.pdev);
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
platform_driver_unregister(&gsmi_driver_info);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(gsmi_init);
|
module_init(gsmi_init);
|
||||||
|
|
|
@ -268,7 +268,7 @@ static void svc_thread_cmd_config_status(struct stratix10_svc_controller *ctrl,
|
||||||
*/
|
*/
|
||||||
msleep(1000);
|
msleep(1000);
|
||||||
count_in_sec--;
|
count_in_sec--;
|
||||||
};
|
}
|
||||||
|
|
||||||
if (res.a0 == INTEL_SIP_SMC_STATUS_OK && count_in_sec)
|
if (res.a0 == INTEL_SIP_SMC_STATUS_OK && count_in_sec)
|
||||||
cb_data->status = BIT(SVC_STATUS_RECONFIG_COMPLETED);
|
cb_data->status = BIT(SVC_STATUS_RECONFIG_COMPLETED);
|
||||||
|
@ -512,7 +512,7 @@ static int svc_normal_to_secure_thread(void *data)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
kfree(cbdata);
|
kfree(cbdata);
|
||||||
kfree(pdata);
|
kfree(pdata);
|
||||||
|
|
|
@ -813,10 +813,8 @@ static int afu_dev_init(struct platform_device *pdev)
|
||||||
static int afu_dev_destroy(struct platform_device *pdev)
|
static int afu_dev_destroy(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||||
struct dfl_afu *afu;
|
|
||||||
|
|
||||||
mutex_lock(&pdata->lock);
|
mutex_lock(&pdata->lock);
|
||||||
afu = dfl_fpga_pdata_get_private(pdata);
|
|
||||||
afu_mmio_region_destroy(pdata);
|
afu_mmio_region_destroy(pdata);
|
||||||
afu_dma_region_destroy(pdata);
|
afu_dma_region_destroy(pdata);
|
||||||
dfl_fpga_pdata_set_private(pdata, NULL);
|
dfl_fpga_pdata_set_private(pdata, NULL);
|
||||||
|
|
|
@ -675,10 +675,8 @@ static int fme_dev_init(struct platform_device *pdev)
|
||||||
static void fme_dev_destroy(struct platform_device *pdev)
|
static void fme_dev_destroy(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||||
struct dfl_fme *fme;
|
|
||||||
|
|
||||||
mutex_lock(&pdata->lock);
|
mutex_lock(&pdata->lock);
|
||||||
fme = dfl_fpga_pdata_get_private(pdata);
|
|
||||||
dfl_fpga_pdata_set_private(pdata, NULL);
|
dfl_fpga_pdata_set_private(pdata, NULL);
|
||||||
mutex_unlock(&pdata->lock);
|
mutex_unlock(&pdata->lock);
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,10 +119,8 @@ static int ts73xx_fpga_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
priv->io_base = devm_ioremap_resource(kdev, res);
|
priv->io_base = devm_ioremap_resource(kdev, res);
|
||||||
if (IS_ERR(priv->io_base)) {
|
if (IS_ERR(priv->io_base))
|
||||||
dev_err(kdev, "unable to remap registers\n");
|
|
||||||
return PTR_ERR(priv->io_base);
|
return PTR_ERR(priv->io_base);
|
||||||
}
|
|
||||||
|
|
||||||
mgr = devm_fpga_mgr_create(kdev, "TS-73xx FPGA Manager",
|
mgr = devm_fpga_mgr_create(kdev, "TS-73xx FPGA Manager",
|
||||||
&ts73xx_fpga_ops, priv);
|
&ts73xx_fpga_ops, priv);
|
||||||
|
|
|
@ -101,7 +101,8 @@ static int xlnx_pr_decoupler_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
priv->clk = devm_clk_get(&pdev->dev, "aclk");
|
priv->clk = devm_clk_get(&pdev->dev, "aclk");
|
||||||
if (IS_ERR(priv->clk)) {
|
if (IS_ERR(priv->clk)) {
|
||||||
dev_err(&pdev->dev, "input clock not found\n");
|
if (PTR_ERR(priv->clk) != -EPROBE_DEFER)
|
||||||
|
dev_err(&pdev->dev, "input clock not found\n");
|
||||||
return PTR_ERR(priv->clk);
|
return PTR_ERR(priv->clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
CFLAGS_core.o := -I$(src)
|
||||||
icc-core-objs := core.o
|
icc-core-objs := core.o
|
||||||
|
|
||||||
obj-$(CONFIG_INTERCONNECT) += icc-core.o
|
obj-$(CONFIG_INTERCONNECT) += icc-core.o
|
||||||
|
|
|
@ -19,45 +19,22 @@
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/overflow.h>
|
#include <linux/overflow.h>
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#define CREATE_TRACE_POINTS
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
static DEFINE_IDR(icc_idr);
|
static DEFINE_IDR(icc_idr);
|
||||||
static LIST_HEAD(icc_providers);
|
static LIST_HEAD(icc_providers);
|
||||||
static DEFINE_MUTEX(icc_lock);
|
static DEFINE_MUTEX(icc_lock);
|
||||||
static struct dentry *icc_debugfs_dir;
|
static struct dentry *icc_debugfs_dir;
|
||||||
|
|
||||||
/**
|
|
||||||
* struct icc_req - constraints that are attached to each node
|
|
||||||
* @req_node: entry in list of requests for the particular @node
|
|
||||||
* @node: the interconnect node to which this constraint applies
|
|
||||||
* @dev: reference to the device that sets the constraints
|
|
||||||
* @tag: path tag (optional)
|
|
||||||
* @avg_bw: an integer describing the average bandwidth in kBps
|
|
||||||
* @peak_bw: an integer describing the peak bandwidth in kBps
|
|
||||||
*/
|
|
||||||
struct icc_req {
|
|
||||||
struct hlist_node req_node;
|
|
||||||
struct icc_node *node;
|
|
||||||
struct device *dev;
|
|
||||||
u32 tag;
|
|
||||||
u32 avg_bw;
|
|
||||||
u32 peak_bw;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* struct icc_path - interconnect path structure
|
|
||||||
* @num_nodes: number of hops (nodes)
|
|
||||||
* @reqs: array of the requests applicable to this path of nodes
|
|
||||||
*/
|
|
||||||
struct icc_path {
|
|
||||||
size_t num_nodes;
|
|
||||||
struct icc_req reqs[];
|
|
||||||
};
|
|
||||||
|
|
||||||
static void icc_summary_show_one(struct seq_file *s, struct icc_node *n)
|
static void icc_summary_show_one(struct seq_file *s, struct icc_node *n)
|
||||||
{
|
{
|
||||||
if (!n)
|
if (!n)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
seq_printf(s, "%-30s %12u %12u\n",
|
seq_printf(s, "%-42s %12u %12u\n",
|
||||||
n->name, n->avg_bw, n->peak_bw);
|
n->name, n->avg_bw, n->peak_bw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,8 +42,8 @@ static int icc_summary_show(struct seq_file *s, void *data)
|
||||||
{
|
{
|
||||||
struct icc_provider *provider;
|
struct icc_provider *provider;
|
||||||
|
|
||||||
seq_puts(s, " node avg peak\n");
|
seq_puts(s, " node tag avg peak\n");
|
||||||
seq_puts(s, "--------------------------------------------------------\n");
|
seq_puts(s, "--------------------------------------------------------------------\n");
|
||||||
|
|
||||||
mutex_lock(&icc_lock);
|
mutex_lock(&icc_lock);
|
||||||
|
|
||||||
|
@ -81,8 +58,8 @@ static int icc_summary_show(struct seq_file *s, void *data)
|
||||||
if (!r->dev)
|
if (!r->dev)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
seq_printf(s, " %-26s %12u %12u\n",
|
seq_printf(s, " %-27s %12u %12u %12u\n",
|
||||||
dev_name(r->dev), r->avg_bw,
|
dev_name(r->dev), r->tag, r->avg_bw,
|
||||||
r->peak_bw);
|
r->peak_bw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,6 +71,70 @@ static int icc_summary_show(struct seq_file *s, void *data)
|
||||||
}
|
}
|
||||||
DEFINE_SHOW_ATTRIBUTE(icc_summary);
|
DEFINE_SHOW_ATTRIBUTE(icc_summary);
|
||||||
|
|
||||||
|
static void icc_graph_show_link(struct seq_file *s, int level,
|
||||||
|
struct icc_node *n, struct icc_node *m)
|
||||||
|
{
|
||||||
|
seq_printf(s, "%s\"%d:%s\" -> \"%d:%s\"\n",
|
||||||
|
level == 2 ? "\t\t" : "\t",
|
||||||
|
n->id, n->name, m->id, m->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void icc_graph_show_node(struct seq_file *s, struct icc_node *n)
|
||||||
|
{
|
||||||
|
seq_printf(s, "\t\t\"%d:%s\" [label=\"%d:%s",
|
||||||
|
n->id, n->name, n->id, n->name);
|
||||||
|
seq_printf(s, "\n\t\t\t|avg_bw=%ukBps", n->avg_bw);
|
||||||
|
seq_printf(s, "\n\t\t\t|peak_bw=%ukBps", n->peak_bw);
|
||||||
|
seq_puts(s, "\"]\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int icc_graph_show(struct seq_file *s, void *data)
|
||||||
|
{
|
||||||
|
struct icc_provider *provider;
|
||||||
|
struct icc_node *n;
|
||||||
|
int cluster_index = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
seq_puts(s, "digraph {\n\trankdir = LR\n\tnode [shape = record]\n");
|
||||||
|
mutex_lock(&icc_lock);
|
||||||
|
|
||||||
|
/* draw providers as cluster subgraphs */
|
||||||
|
cluster_index = 0;
|
||||||
|
list_for_each_entry(provider, &icc_providers, provider_list) {
|
||||||
|
seq_printf(s, "\tsubgraph cluster_%d {\n", ++cluster_index);
|
||||||
|
if (provider->dev)
|
||||||
|
seq_printf(s, "\t\tlabel = \"%s\"\n",
|
||||||
|
dev_name(provider->dev));
|
||||||
|
|
||||||
|
/* draw nodes */
|
||||||
|
list_for_each_entry(n, &provider->nodes, node_list)
|
||||||
|
icc_graph_show_node(s, n);
|
||||||
|
|
||||||
|
/* draw internal links */
|
||||||
|
list_for_each_entry(n, &provider->nodes, node_list)
|
||||||
|
for (i = 0; i < n->num_links; ++i)
|
||||||
|
if (n->provider == n->links[i]->provider)
|
||||||
|
icc_graph_show_link(s, 2, n,
|
||||||
|
n->links[i]);
|
||||||
|
|
||||||
|
seq_puts(s, "\t}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* draw external links */
|
||||||
|
list_for_each_entry(provider, &icc_providers, provider_list)
|
||||||
|
list_for_each_entry(n, &provider->nodes, node_list)
|
||||||
|
for (i = 0; i < n->num_links; ++i)
|
||||||
|
if (n->provider != n->links[i]->provider)
|
||||||
|
icc_graph_show_link(s, 1, n,
|
||||||
|
n->links[i]);
|
||||||
|
|
||||||
|
mutex_unlock(&icc_lock);
|
||||||
|
seq_puts(s, "}");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DEFINE_SHOW_ATTRIBUTE(icc_graph);
|
||||||
|
|
||||||
static struct icc_node *node_find(const int id)
|
static struct icc_node *node_find(const int id)
|
||||||
{
|
{
|
||||||
return idr_find(&icc_idr, id);
|
return idr_find(&icc_idr, id);
|
||||||
|
@ -244,6 +285,16 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int icc_std_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
|
||||||
|
u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
|
||||||
|
{
|
||||||
|
*agg_avg += avg_bw;
|
||||||
|
*agg_peak = max(*agg_peak, peak_bw);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(icc_std_aggregate);
|
||||||
|
|
||||||
/* of_icc_xlate_onecell() - Translate function using a single index.
|
/* of_icc_xlate_onecell() - Translate function using a single index.
|
||||||
* @spec: OF phandle args to map into an interconnect node.
|
* @spec: OF phandle args to map into an interconnect node.
|
||||||
* @data: private data (pointer to struct icc_onecell_data)
|
* @data: private data (pointer to struct icc_onecell_data)
|
||||||
|
@ -382,9 +433,17 @@ struct icc_path *of_icc_get(struct device *dev, const char *name)
|
||||||
|
|
||||||
mutex_lock(&icc_lock);
|
mutex_lock(&icc_lock);
|
||||||
path = path_find(dev, src_node, dst_node);
|
path = path_find(dev, src_node, dst_node);
|
||||||
if (IS_ERR(path))
|
|
||||||
dev_err(dev, "%s: invalid path=%ld\n", __func__, PTR_ERR(path));
|
|
||||||
mutex_unlock(&icc_lock);
|
mutex_unlock(&icc_lock);
|
||||||
|
if (IS_ERR(path)) {
|
||||||
|
dev_err(dev, "%s: invalid path=%ld\n", __func__, PTR_ERR(path));
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name)
|
||||||
|
path->name = kstrdup_const(name, GFP_KERNEL);
|
||||||
|
else
|
||||||
|
path->name = kasprintf(GFP_KERNEL, "%s-%s",
|
||||||
|
src_node->name, dst_node->name);
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
@ -436,9 +495,12 @@ int icc_set_bw(struct icc_path *path, u32 avg_bw, u32 peak_bw)
|
||||||
size_t i;
|
size_t i;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!path || !path->num_nodes)
|
if (!path)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (WARN_ON(IS_ERR(path) || !path->num_nodes))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&icc_lock);
|
mutex_lock(&icc_lock);
|
||||||
|
|
||||||
old_avg = path->reqs[0].avg_bw;
|
old_avg = path->reqs[0].avg_bw;
|
||||||
|
@ -453,6 +515,8 @@ int icc_set_bw(struct icc_path *path, u32 avg_bw, u32 peak_bw)
|
||||||
|
|
||||||
/* aggregate requests for this node */
|
/* aggregate requests for this node */
|
||||||
aggregate_requests(node);
|
aggregate_requests(node);
|
||||||
|
|
||||||
|
trace_icc_set_bw(path, node, i, avg_bw, peak_bw);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = apply_constraints(path);
|
ret = apply_constraints(path);
|
||||||
|
@ -471,6 +535,8 @@ int icc_set_bw(struct icc_path *path, u32 avg_bw, u32 peak_bw)
|
||||||
|
|
||||||
mutex_unlock(&icc_lock);
|
mutex_unlock(&icc_lock);
|
||||||
|
|
||||||
|
trace_icc_set_bw_end(path, ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(icc_set_bw);
|
EXPORT_SYMBOL_GPL(icc_set_bw);
|
||||||
|
@ -507,9 +573,12 @@ struct icc_path *icc_get(struct device *dev, const int src_id, const int dst_id)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
path = path_find(dev, src, dst);
|
path = path_find(dev, src, dst);
|
||||||
if (IS_ERR(path))
|
if (IS_ERR(path)) {
|
||||||
dev_err(dev, "%s: invalid path=%ld\n", __func__, PTR_ERR(path));
|
dev_err(dev, "%s: invalid path=%ld\n", __func__, PTR_ERR(path));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
path->name = kasprintf(GFP_KERNEL, "%s-%s", src->name, dst->name);
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&icc_lock);
|
mutex_unlock(&icc_lock);
|
||||||
return path;
|
return path;
|
||||||
|
@ -545,6 +614,7 @@ void icc_put(struct icc_path *path)
|
||||||
}
|
}
|
||||||
mutex_unlock(&icc_lock);
|
mutex_unlock(&icc_lock);
|
||||||
|
|
||||||
|
kfree_const(path->name);
|
||||||
kfree(path);
|
kfree(path);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(icc_put);
|
EXPORT_SYMBOL_GPL(icc_put);
|
||||||
|
@ -742,6 +812,28 @@ void icc_node_del(struct icc_node *node)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(icc_node_del);
|
EXPORT_SYMBOL_GPL(icc_node_del);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* icc_nodes_remove() - remove all previously added nodes from provider
|
||||||
|
* @provider: the interconnect provider we are removing nodes from
|
||||||
|
*
|
||||||
|
* Return: 0 on success, or an error code otherwise
|
||||||
|
*/
|
||||||
|
int icc_nodes_remove(struct icc_provider *provider)
|
||||||
|
{
|
||||||
|
struct icc_node *n, *tmp;
|
||||||
|
|
||||||
|
if (WARN_ON(IS_ERR_OR_NULL(provider)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
list_for_each_entry_safe_reverse(n, tmp, &provider->nodes, node_list) {
|
||||||
|
icc_node_del(n);
|
||||||
|
icc_node_destroy(n->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(icc_nodes_remove);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* icc_provider_add() - add a new interconnect provider
|
* icc_provider_add() - add a new interconnect provider
|
||||||
* @provider: the interconnect provider that will be added into topology
|
* @provider: the interconnect provider that will be added into topology
|
||||||
|
@ -802,6 +894,8 @@ static int __init icc_init(void)
|
||||||
icc_debugfs_dir = debugfs_create_dir("interconnect", NULL);
|
icc_debugfs_dir = debugfs_create_dir("interconnect", NULL);
|
||||||
debugfs_create_file("interconnect_summary", 0444,
|
debugfs_create_file("interconnect_summary", 0444,
|
||||||
icc_debugfs_dir, NULL, &icc_summary_fops);
|
icc_debugfs_dir, NULL, &icc_summary_fops);
|
||||||
|
debugfs_create_file("interconnect_graph", 0444,
|
||||||
|
icc_debugfs_dir, NULL, &icc_graph_fops);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Interconnect framework internal structs
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019, Linaro Ltd.
|
||||||
|
* Author: Georgi Djakov <georgi.djakov@linaro.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DRIVERS_INTERCONNECT_INTERNAL_H
|
||||||
|
#define __DRIVERS_INTERCONNECT_INTERNAL_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct icc_req - constraints that are attached to each node
|
||||||
|
* @req_node: entry in list of requests for the particular @node
|
||||||
|
* @node: the interconnect node to which this constraint applies
|
||||||
|
* @dev: reference to the device that sets the constraints
|
||||||
|
* @tag: path tag (optional)
|
||||||
|
* @avg_bw: an integer describing the average bandwidth in kBps
|
||||||
|
* @peak_bw: an integer describing the peak bandwidth in kBps
|
||||||
|
*/
|
||||||
|
struct icc_req {
|
||||||
|
struct hlist_node req_node;
|
||||||
|
struct icc_node *node;
|
||||||
|
struct device *dev;
|
||||||
|
u32 tag;
|
||||||
|
u32 avg_bw;
|
||||||
|
u32 peak_bw;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct icc_path - interconnect path structure
|
||||||
|
* @name: a string name of the path (useful for ftrace)
|
||||||
|
* @num_nodes: number of hops (nodes)
|
||||||
|
* @reqs: array of the requests applicable to this path of nodes
|
||||||
|
*/
|
||||||
|
struct icc_path {
|
||||||
|
const char *name;
|
||||||
|
size_t num_nodes;
|
||||||
|
struct icc_req reqs[];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -5,6 +5,15 @@ config INTERCONNECT_QCOM
|
||||||
help
|
help
|
||||||
Support for Qualcomm's Network-on-Chip interconnect hardware.
|
Support for Qualcomm's Network-on-Chip interconnect hardware.
|
||||||
|
|
||||||
|
config INTERCONNECT_QCOM_MSM8916
|
||||||
|
tristate "Qualcomm MSM8916 interconnect driver"
|
||||||
|
depends on INTERCONNECT_QCOM
|
||||||
|
depends on QCOM_SMD_RPM
|
||||||
|
select INTERCONNECT_QCOM_SMD_RPM
|
||||||
|
help
|
||||||
|
This is a driver for the Qualcomm Network-on-Chip on msm8916-based
|
||||||
|
platforms.
|
||||||
|
|
||||||
config INTERCONNECT_QCOM_MSM8974
|
config INTERCONNECT_QCOM_MSM8974
|
||||||
tristate "Qualcomm MSM8974 interconnect driver"
|
tristate "Qualcomm MSM8974 interconnect driver"
|
||||||
depends on INTERCONNECT_QCOM
|
depends on INTERCONNECT_QCOM
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
qnoc-msm8916-objs := msm8916.o
|
||||||
qnoc-msm8974-objs := msm8974.o
|
qnoc-msm8974-objs := msm8974.o
|
||||||
qnoc-qcs404-objs := qcs404.o
|
qnoc-qcs404-objs := qcs404.o
|
||||||
qnoc-sdm845-objs := sdm845.o
|
qnoc-sdm845-objs := sdm845.o
|
||||||
icc-smd-rpm-objs := smd-rpm.o
|
icc-smd-rpm-objs := smd-rpm.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8916) += qnoc-msm8916.o
|
||||||
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8974) += qnoc-msm8974.o
|
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8974) += qnoc-msm8974.o
|
||||||
obj-$(CONFIG_INTERCONNECT_QCOM_QCS404) += qnoc-qcs404.o
|
obj-$(CONFIG_INTERCONNECT_QCOM_QCS404) += qnoc-qcs404.o
|
||||||
obj-$(CONFIG_INTERCONNECT_QCOM_SDM845) += qnoc-sdm845.o
|
obj-$(CONFIG_INTERCONNECT_QCOM_SDM845) += qnoc-sdm845.o
|
||||||
|
|
|
@ -0,0 +1,554 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018-2020 Linaro Ltd
|
||||||
|
* Author: Georgi Djakov <georgi.djakov@linaro.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/interconnect-provider.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
|
||||||
|
#include <dt-bindings/interconnect/qcom,msm8916.h>
|
||||||
|
|
||||||
|
#include "smd-rpm.h"
|
||||||
|
|
||||||
|
#define RPM_BUS_MASTER_REQ 0x73616d62
|
||||||
|
#define RPM_BUS_SLAVE_REQ 0x766c7362
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MSM8916_BIMC_SNOC_MAS = 1,
|
||||||
|
MSM8916_BIMC_SNOC_SLV,
|
||||||
|
MSM8916_MASTER_AMPSS_M0,
|
||||||
|
MSM8916_MASTER_LPASS,
|
||||||
|
MSM8916_MASTER_BLSP_1,
|
||||||
|
MSM8916_MASTER_DEHR,
|
||||||
|
MSM8916_MASTER_GRAPHICS_3D,
|
||||||
|
MSM8916_MASTER_JPEG,
|
||||||
|
MSM8916_MASTER_MDP_PORT0,
|
||||||
|
MSM8916_MASTER_CRYPTO_CORE0,
|
||||||
|
MSM8916_MASTER_SDCC_1,
|
||||||
|
MSM8916_MASTER_SDCC_2,
|
||||||
|
MSM8916_MASTER_QDSS_BAM,
|
||||||
|
MSM8916_MASTER_QDSS_ETR,
|
||||||
|
MSM8916_MASTER_SNOC_CFG,
|
||||||
|
MSM8916_MASTER_SPDM,
|
||||||
|
MSM8916_MASTER_TCU0,
|
||||||
|
MSM8916_MASTER_TCU1,
|
||||||
|
MSM8916_MASTER_USB_HS,
|
||||||
|
MSM8916_MASTER_VFE,
|
||||||
|
MSM8916_MASTER_VIDEO_P0,
|
||||||
|
MSM8916_SNOC_MM_INT_0,
|
||||||
|
MSM8916_SNOC_MM_INT_1,
|
||||||
|
MSM8916_SNOC_MM_INT_2,
|
||||||
|
MSM8916_SNOC_MM_INT_BIMC,
|
||||||
|
MSM8916_PNOC_INT_0,
|
||||||
|
MSM8916_PNOC_INT_1,
|
||||||
|
MSM8916_PNOC_MAS_0,
|
||||||
|
MSM8916_PNOC_MAS_1,
|
||||||
|
MSM8916_PNOC_SLV_0,
|
||||||
|
MSM8916_PNOC_SLV_1,
|
||||||
|
MSM8916_PNOC_SLV_2,
|
||||||
|
MSM8916_PNOC_SLV_3,
|
||||||
|
MSM8916_PNOC_SLV_4,
|
||||||
|
MSM8916_PNOC_SLV_8,
|
||||||
|
MSM8916_PNOC_SLV_9,
|
||||||
|
MSM8916_PNOC_SNOC_MAS,
|
||||||
|
MSM8916_PNOC_SNOC_SLV,
|
||||||
|
MSM8916_SNOC_QDSS_INT,
|
||||||
|
MSM8916_SLAVE_AMPSS_L2,
|
||||||
|
MSM8916_SLAVE_APSS,
|
||||||
|
MSM8916_SLAVE_LPASS,
|
||||||
|
MSM8916_SLAVE_BIMC_CFG,
|
||||||
|
MSM8916_SLAVE_BLSP_1,
|
||||||
|
MSM8916_SLAVE_BOOT_ROM,
|
||||||
|
MSM8916_SLAVE_CAMERA_CFG,
|
||||||
|
MSM8916_SLAVE_CATS_128,
|
||||||
|
MSM8916_SLAVE_OCMEM_64,
|
||||||
|
MSM8916_SLAVE_CLK_CTL,
|
||||||
|
MSM8916_SLAVE_CRYPTO_0_CFG,
|
||||||
|
MSM8916_SLAVE_DEHR_CFG,
|
||||||
|
MSM8916_SLAVE_DISPLAY_CFG,
|
||||||
|
MSM8916_SLAVE_EBI_CH0,
|
||||||
|
MSM8916_SLAVE_GRAPHICS_3D_CFG,
|
||||||
|
MSM8916_SLAVE_IMEM_CFG,
|
||||||
|
MSM8916_SLAVE_IMEM,
|
||||||
|
MSM8916_SLAVE_MPM,
|
||||||
|
MSM8916_SLAVE_MSG_RAM,
|
||||||
|
MSM8916_SLAVE_MSS,
|
||||||
|
MSM8916_SLAVE_PDM,
|
||||||
|
MSM8916_SLAVE_PMIC_ARB,
|
||||||
|
MSM8916_SLAVE_PNOC_CFG,
|
||||||
|
MSM8916_SLAVE_PRNG,
|
||||||
|
MSM8916_SLAVE_QDSS_CFG,
|
||||||
|
MSM8916_SLAVE_QDSS_STM,
|
||||||
|
MSM8916_SLAVE_RBCPR_CFG,
|
||||||
|
MSM8916_SLAVE_SDCC_1,
|
||||||
|
MSM8916_SLAVE_SDCC_2,
|
||||||
|
MSM8916_SLAVE_SECURITY,
|
||||||
|
MSM8916_SLAVE_SNOC_CFG,
|
||||||
|
MSM8916_SLAVE_SPDM,
|
||||||
|
MSM8916_SLAVE_SRVC_SNOC,
|
||||||
|
MSM8916_SLAVE_TCSR,
|
||||||
|
MSM8916_SLAVE_TLMM,
|
||||||
|
MSM8916_SLAVE_USB_HS,
|
||||||
|
MSM8916_SLAVE_VENUS_CFG,
|
||||||
|
MSM8916_SNOC_BIMC_0_MAS,
|
||||||
|
MSM8916_SNOC_BIMC_0_SLV,
|
||||||
|
MSM8916_SNOC_BIMC_1_MAS,
|
||||||
|
MSM8916_SNOC_BIMC_1_SLV,
|
||||||
|
MSM8916_SNOC_INT_0,
|
||||||
|
MSM8916_SNOC_INT_1,
|
||||||
|
MSM8916_SNOC_INT_BIMC,
|
||||||
|
MSM8916_SNOC_PNOC_MAS,
|
||||||
|
MSM8916_SNOC_PNOC_SLV,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define to_msm8916_provider(_provider) \
|
||||||
|
container_of(_provider, struct msm8916_icc_provider, provider)
|
||||||
|
|
||||||
|
static const struct clk_bulk_data msm8916_bus_clocks[] = {
|
||||||
|
{ .id = "bus" },
|
||||||
|
{ .id = "bus_a" },
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct msm8916_icc_provider - Qualcomm specific interconnect provider
|
||||||
|
* @provider: generic interconnect provider
|
||||||
|
* @bus_clks: the clk_bulk_data table of bus clocks
|
||||||
|
* @num_clks: the total number of clk_bulk_data entries
|
||||||
|
*/
|
||||||
|
struct msm8916_icc_provider {
|
||||||
|
struct icc_provider provider;
|
||||||
|
struct clk_bulk_data *bus_clks;
|
||||||
|
int num_clks;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MSM8916_MAX_LINKS 8
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct msm8916_icc_node - Qualcomm specific interconnect nodes
|
||||||
|
* @name: the node name used in debugfs
|
||||||
|
* @id: a unique node identifier
|
||||||
|
* @links: an array of nodes where we can go next while traversing
|
||||||
|
* @num_links: the total number of @links
|
||||||
|
* @buswidth: width of the interconnect between a node and the bus (bytes)
|
||||||
|
* @mas_rpm_id: RPM ID for devices that are bus masters
|
||||||
|
* @slv_rpm_id: RPM ID for devices that are bus slaves
|
||||||
|
* @rate: current bus clock rate in Hz
|
||||||
|
*/
|
||||||
|
struct msm8916_icc_node {
|
||||||
|
unsigned char *name;
|
||||||
|
u16 id;
|
||||||
|
u16 links[MSM8916_MAX_LINKS];
|
||||||
|
u16 num_links;
|
||||||
|
u16 buswidth;
|
||||||
|
int mas_rpm_id;
|
||||||
|
int slv_rpm_id;
|
||||||
|
u64 rate;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct msm8916_icc_desc {
|
||||||
|
struct msm8916_icc_node **nodes;
|
||||||
|
size_t num_nodes;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DEFINE_QNODE(_name, _id, _buswidth, _mas_rpm_id, _slv_rpm_id, \
|
||||||
|
...) \
|
||||||
|
static struct msm8916_icc_node _name = { \
|
||||||
|
.name = #_name, \
|
||||||
|
.id = _id, \
|
||||||
|
.buswidth = _buswidth, \
|
||||||
|
.mas_rpm_id = _mas_rpm_id, \
|
||||||
|
.slv_rpm_id = _slv_rpm_id, \
|
||||||
|
.num_links = ARRAY_SIZE(((int[]){ __VA_ARGS__ })), \
|
||||||
|
.links = { __VA_ARGS__ }, \
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_QNODE(bimc_snoc_mas, MSM8916_BIMC_SNOC_MAS, 8, -1, -1, MSM8916_BIMC_SNOC_SLV);
|
||||||
|
DEFINE_QNODE(bimc_snoc_slv, MSM8916_BIMC_SNOC_SLV, 8, -1, -1, MSM8916_SNOC_INT_0, MSM8916_SNOC_INT_1);
|
||||||
|
DEFINE_QNODE(mas_apss, MSM8916_MASTER_AMPSS_M0, 8, -1, -1, MSM8916_SLAVE_EBI_CH0, MSM8916_BIMC_SNOC_MAS, MSM8916_SLAVE_AMPSS_L2);
|
||||||
|
DEFINE_QNODE(mas_audio, MSM8916_MASTER_LPASS, 4, -1, -1, MSM8916_PNOC_MAS_0);
|
||||||
|
DEFINE_QNODE(mas_blsp_1, MSM8916_MASTER_BLSP_1, 4, -1, -1, MSM8916_PNOC_MAS_1);
|
||||||
|
DEFINE_QNODE(mas_dehr, MSM8916_MASTER_DEHR, 4, -1, -1, MSM8916_PNOC_MAS_0);
|
||||||
|
DEFINE_QNODE(mas_gfx, MSM8916_MASTER_GRAPHICS_3D, 8, -1, -1, MSM8916_SLAVE_EBI_CH0, MSM8916_BIMC_SNOC_MAS, MSM8916_SLAVE_AMPSS_L2);
|
||||||
|
DEFINE_QNODE(mas_jpeg, MSM8916_MASTER_JPEG, 16, -1, -1, MSM8916_SNOC_MM_INT_0, MSM8916_SNOC_MM_INT_2);
|
||||||
|
DEFINE_QNODE(mas_mdp, MSM8916_MASTER_MDP_PORT0, 16, -1, -1, MSM8916_SNOC_MM_INT_0, MSM8916_SNOC_MM_INT_2);
|
||||||
|
DEFINE_QNODE(mas_pcnoc_crypto_0, MSM8916_MASTER_CRYPTO_CORE0, 8, -1, -1, MSM8916_PNOC_INT_1);
|
||||||
|
DEFINE_QNODE(mas_pcnoc_sdcc_1, MSM8916_MASTER_SDCC_1, 8, -1, -1, MSM8916_PNOC_INT_1);
|
||||||
|
DEFINE_QNODE(mas_pcnoc_sdcc_2, MSM8916_MASTER_SDCC_2, 8, -1, -1, MSM8916_PNOC_INT_1);
|
||||||
|
DEFINE_QNODE(mas_qdss_bam, MSM8916_MASTER_QDSS_BAM, 8, -1, -1, MSM8916_SNOC_QDSS_INT);
|
||||||
|
DEFINE_QNODE(mas_qdss_etr, MSM8916_MASTER_QDSS_ETR, 8, -1, -1, MSM8916_SNOC_QDSS_INT);
|
||||||
|
DEFINE_QNODE(mas_snoc_cfg, MSM8916_MASTER_SNOC_CFG, 4, 20, -1, MSM8916_SNOC_QDSS_INT);
|
||||||
|
DEFINE_QNODE(mas_spdm, MSM8916_MASTER_SPDM, 4, -1, -1, MSM8916_PNOC_MAS_0);
|
||||||
|
DEFINE_QNODE(mas_tcu0, MSM8916_MASTER_TCU0, 8, -1, -1, MSM8916_SLAVE_EBI_CH0, MSM8916_BIMC_SNOC_MAS, MSM8916_SLAVE_AMPSS_L2);
|
||||||
|
DEFINE_QNODE(mas_tcu1, MSM8916_MASTER_TCU1, 8, -1, -1, MSM8916_SLAVE_EBI_CH0, MSM8916_BIMC_SNOC_MAS, MSM8916_SLAVE_AMPSS_L2);
|
||||||
|
DEFINE_QNODE(mas_usb_hs, MSM8916_MASTER_USB_HS, 4, -1, -1, MSM8916_PNOC_MAS_1);
|
||||||
|
DEFINE_QNODE(mas_vfe, MSM8916_MASTER_VFE, 16, -1, -1, MSM8916_SNOC_MM_INT_1, MSM8916_SNOC_MM_INT_2);
|
||||||
|
DEFINE_QNODE(mas_video, MSM8916_MASTER_VIDEO_P0, 16, -1, -1, MSM8916_SNOC_MM_INT_0, MSM8916_SNOC_MM_INT_2);
|
||||||
|
DEFINE_QNODE(mm_int_0, MSM8916_SNOC_MM_INT_0, 16, -1, -1, MSM8916_SNOC_MM_INT_BIMC);
|
||||||
|
DEFINE_QNODE(mm_int_1, MSM8916_SNOC_MM_INT_1, 16, -1, -1, MSM8916_SNOC_MM_INT_BIMC);
|
||||||
|
DEFINE_QNODE(mm_int_2, MSM8916_SNOC_MM_INT_2, 16, -1, -1, MSM8916_SNOC_INT_0);
|
||||||
|
DEFINE_QNODE(mm_int_bimc, MSM8916_SNOC_MM_INT_BIMC, 16, -1, -1, MSM8916_SNOC_BIMC_1_MAS);
|
||||||
|
DEFINE_QNODE(pcnoc_int_0, MSM8916_PNOC_INT_0, 8, -1, -1, MSM8916_PNOC_SNOC_MAS, MSM8916_PNOC_SLV_0, MSM8916_PNOC_SLV_1, MSM8916_PNOC_SLV_2, MSM8916_PNOC_SLV_3, MSM8916_PNOC_SLV_4, MSM8916_PNOC_SLV_8, MSM8916_PNOC_SLV_9);
|
||||||
|
DEFINE_QNODE(pcnoc_int_1, MSM8916_PNOC_INT_1, 8, -1, -1, MSM8916_PNOC_SNOC_MAS);
|
||||||
|
DEFINE_QNODE(pcnoc_m_0, MSM8916_PNOC_MAS_0, 8, -1, -1, MSM8916_PNOC_INT_0);
|
||||||
|
DEFINE_QNODE(pcnoc_m_1, MSM8916_PNOC_MAS_1, 8, -1, -1, MSM8916_PNOC_SNOC_MAS);
|
||||||
|
DEFINE_QNODE(pcnoc_s_0, MSM8916_PNOC_SLV_0, 8, -1, -1, MSM8916_SLAVE_CLK_CTL, MSM8916_SLAVE_TLMM, MSM8916_SLAVE_TCSR, MSM8916_SLAVE_SECURITY, MSM8916_SLAVE_MSS);
|
||||||
|
DEFINE_QNODE(pcnoc_s_1, MSM8916_PNOC_SLV_1, 8, -1, -1, MSM8916_SLAVE_IMEM_CFG, MSM8916_SLAVE_CRYPTO_0_CFG, MSM8916_SLAVE_MSG_RAM, MSM8916_SLAVE_PDM, MSM8916_SLAVE_PRNG);
|
||||||
|
DEFINE_QNODE(pcnoc_s_2, MSM8916_PNOC_SLV_2, 8, -1, -1, MSM8916_SLAVE_SPDM, MSM8916_SLAVE_BOOT_ROM, MSM8916_SLAVE_BIMC_CFG, MSM8916_SLAVE_PNOC_CFG, MSM8916_SLAVE_PMIC_ARB);
|
||||||
|
DEFINE_QNODE(pcnoc_s_3, MSM8916_PNOC_SLV_3, 8, -1, -1, MSM8916_SLAVE_MPM, MSM8916_SLAVE_SNOC_CFG, MSM8916_SLAVE_RBCPR_CFG, MSM8916_SLAVE_QDSS_CFG, MSM8916_SLAVE_DEHR_CFG);
|
||||||
|
DEFINE_QNODE(pcnoc_s_4, MSM8916_PNOC_SLV_4, 8, -1, -1, MSM8916_SLAVE_VENUS_CFG, MSM8916_SLAVE_CAMERA_CFG, MSM8916_SLAVE_DISPLAY_CFG);
|
||||||
|
DEFINE_QNODE(pcnoc_s_8, MSM8916_PNOC_SLV_8, 8, -1, -1, MSM8916_SLAVE_USB_HS, MSM8916_SLAVE_SDCC_1, MSM8916_SLAVE_BLSP_1);
|
||||||
|
DEFINE_QNODE(pcnoc_s_9, MSM8916_PNOC_SLV_9, 8, -1, -1, MSM8916_SLAVE_SDCC_2, MSM8916_SLAVE_LPASS, MSM8916_SLAVE_GRAPHICS_3D_CFG);
|
||||||
|
DEFINE_QNODE(pcnoc_snoc_mas, MSM8916_PNOC_SNOC_MAS, 8, 29, -1, MSM8916_PNOC_SNOC_SLV);
|
||||||
|
DEFINE_QNODE(pcnoc_snoc_slv, MSM8916_PNOC_SNOC_SLV, 8, -1, 45, MSM8916_SNOC_INT_0, MSM8916_SNOC_INT_BIMC, MSM8916_SNOC_INT_1);
|
||||||
|
DEFINE_QNODE(qdss_int, MSM8916_SNOC_QDSS_INT, 8, -1, -1, MSM8916_SNOC_INT_0, MSM8916_SNOC_INT_BIMC);
|
||||||
|
DEFINE_QNODE(slv_apps_l2, MSM8916_SLAVE_AMPSS_L2, 8, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_apss, MSM8916_SLAVE_APSS, 4, -1, 20, 0);
|
||||||
|
DEFINE_QNODE(slv_audio, MSM8916_SLAVE_LPASS, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_bimc_cfg, MSM8916_SLAVE_BIMC_CFG, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_blsp_1, MSM8916_SLAVE_BLSP_1, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_boot_rom, MSM8916_SLAVE_BOOT_ROM, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_camera_cfg, MSM8916_SLAVE_CAMERA_CFG, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_cats_0, MSM8916_SLAVE_CATS_128, 16, -1, 106, 0);
|
||||||
|
DEFINE_QNODE(slv_cats_1, MSM8916_SLAVE_OCMEM_64, 8, -1, 107, 0);
|
||||||
|
DEFINE_QNODE(slv_clk_ctl, MSM8916_SLAVE_CLK_CTL, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_crypto_0_cfg, MSM8916_SLAVE_CRYPTO_0_CFG, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_dehr_cfg, MSM8916_SLAVE_DEHR_CFG, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_display_cfg, MSM8916_SLAVE_DISPLAY_CFG, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_ebi_ch0, MSM8916_SLAVE_EBI_CH0, 8, -1, 0, 0);
|
||||||
|
DEFINE_QNODE(slv_gfx_cfg, MSM8916_SLAVE_GRAPHICS_3D_CFG, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_imem_cfg, MSM8916_SLAVE_IMEM_CFG, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_imem, MSM8916_SLAVE_IMEM, 8, -1, 26, 0);
|
||||||
|
DEFINE_QNODE(slv_mpm, MSM8916_SLAVE_MPM, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_msg_ram, MSM8916_SLAVE_MSG_RAM, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_mss, MSM8916_SLAVE_MSS, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_pdm, MSM8916_SLAVE_PDM, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_pmic_arb, MSM8916_SLAVE_PMIC_ARB, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_pcnoc_cfg, MSM8916_SLAVE_PNOC_CFG, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_prng, MSM8916_SLAVE_PRNG, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_qdss_cfg, MSM8916_SLAVE_QDSS_CFG, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_qdss_stm, MSM8916_SLAVE_QDSS_STM, 4, -1, 30, 0);
|
||||||
|
DEFINE_QNODE(slv_rbcpr_cfg, MSM8916_SLAVE_RBCPR_CFG, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_sdcc_1, MSM8916_SLAVE_SDCC_1, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_sdcc_2, MSM8916_SLAVE_SDCC_2, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_security, MSM8916_SLAVE_SECURITY, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_snoc_cfg, MSM8916_SLAVE_SNOC_CFG, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_spdm, MSM8916_SLAVE_SPDM, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_srvc_snoc, MSM8916_SLAVE_SRVC_SNOC, 8, -1, 29, 0);
|
||||||
|
DEFINE_QNODE(slv_tcsr, MSM8916_SLAVE_TCSR, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_tlmm, MSM8916_SLAVE_TLMM, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_usb_hs, MSM8916_SLAVE_USB_HS, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(slv_venus_cfg, MSM8916_SLAVE_VENUS_CFG, 4, -1, -1, 0);
|
||||||
|
DEFINE_QNODE(snoc_bimc_0_mas, MSM8916_SNOC_BIMC_0_MAS, 8, 3, -1, MSM8916_SNOC_BIMC_0_SLV);
|
||||||
|
DEFINE_QNODE(snoc_bimc_0_slv, MSM8916_SNOC_BIMC_0_SLV, 8, -1, 24, MSM8916_SLAVE_EBI_CH0);
|
||||||
|
DEFINE_QNODE(snoc_bimc_1_mas, MSM8916_SNOC_BIMC_1_MAS, 16, -1, -1, MSM8916_SNOC_BIMC_1_SLV);
|
||||||
|
DEFINE_QNODE(snoc_bimc_1_slv, MSM8916_SNOC_BIMC_1_SLV, 8, -1, -1, MSM8916_SLAVE_EBI_CH0);
|
||||||
|
DEFINE_QNODE(snoc_int_0, MSM8916_SNOC_INT_0, 8, 99, 130, MSM8916_SLAVE_QDSS_STM, MSM8916_SLAVE_IMEM, MSM8916_SNOC_PNOC_MAS);
|
||||||
|
DEFINE_QNODE(snoc_int_1, MSM8916_SNOC_INT_1, 8, 100, 131, MSM8916_SLAVE_APSS, MSM8916_SLAVE_CATS_128, MSM8916_SLAVE_OCMEM_64);
|
||||||
|
DEFINE_QNODE(snoc_int_bimc, MSM8916_SNOC_INT_BIMC, 8, 101, 132, MSM8916_SNOC_BIMC_0_MAS);
|
||||||
|
DEFINE_QNODE(snoc_pcnoc_mas, MSM8916_SNOC_PNOC_MAS, 8, -1, -1, MSM8916_SNOC_PNOC_SLV);
|
||||||
|
DEFINE_QNODE(snoc_pcnoc_slv, MSM8916_SNOC_PNOC_SLV, 8, -1, -1, MSM8916_PNOC_INT_0);
|
||||||
|
|
||||||
|
static struct msm8916_icc_node *msm8916_snoc_nodes[] = {
|
||||||
|
[BIMC_SNOC_SLV] = &bimc_snoc_slv,
|
||||||
|
[MASTER_JPEG] = &mas_jpeg,
|
||||||
|
[MASTER_MDP_PORT0] = &mas_mdp,
|
||||||
|
[MASTER_QDSS_BAM] = &mas_qdss_bam,
|
||||||
|
[MASTER_QDSS_ETR] = &mas_qdss_etr,
|
||||||
|
[MASTER_SNOC_CFG] = &mas_snoc_cfg,
|
||||||
|
[MASTER_VFE] = &mas_vfe,
|
||||||
|
[MASTER_VIDEO_P0] = &mas_video,
|
||||||
|
[SNOC_MM_INT_0] = &mm_int_0,
|
||||||
|
[SNOC_MM_INT_1] = &mm_int_1,
|
||||||
|
[SNOC_MM_INT_2] = &mm_int_2,
|
||||||
|
[SNOC_MM_INT_BIMC] = &mm_int_bimc,
|
||||||
|
[PCNOC_SNOC_SLV] = &pcnoc_snoc_slv,
|
||||||
|
[SLAVE_APSS] = &slv_apss,
|
||||||
|
[SLAVE_CATS_128] = &slv_cats_0,
|
||||||
|
[SLAVE_OCMEM_64] = &slv_cats_1,
|
||||||
|
[SLAVE_IMEM] = &slv_imem,
|
||||||
|
[SLAVE_QDSS_STM] = &slv_qdss_stm,
|
||||||
|
[SLAVE_SRVC_SNOC] = &slv_srvc_snoc,
|
||||||
|
[SNOC_BIMC_0_MAS] = &snoc_bimc_0_mas,
|
||||||
|
[SNOC_BIMC_1_MAS] = &snoc_bimc_1_mas,
|
||||||
|
[SNOC_INT_0] = &snoc_int_0,
|
||||||
|
[SNOC_INT_1] = &snoc_int_1,
|
||||||
|
[SNOC_INT_BIMC] = &snoc_int_bimc,
|
||||||
|
[SNOC_PCNOC_MAS] = &snoc_pcnoc_mas,
|
||||||
|
[SNOC_QDSS_INT] = &qdss_int,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct msm8916_icc_desc msm8916_snoc = {
|
||||||
|
.nodes = msm8916_snoc_nodes,
|
||||||
|
.num_nodes = ARRAY_SIZE(msm8916_snoc_nodes),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct msm8916_icc_node *msm8916_bimc_nodes[] = {
|
||||||
|
[BIMC_SNOC_MAS] = &bimc_snoc_mas,
|
||||||
|
[MASTER_AMPSS_M0] = &mas_apss,
|
||||||
|
[MASTER_GRAPHICS_3D] = &mas_gfx,
|
||||||
|
[MASTER_TCU0] = &mas_tcu0,
|
||||||
|
[MASTER_TCU1] = &mas_tcu1,
|
||||||
|
[SLAVE_AMPSS_L2] = &slv_apps_l2,
|
||||||
|
[SLAVE_EBI_CH0] = &slv_ebi_ch0,
|
||||||
|
[SNOC_BIMC_0_SLV] = &snoc_bimc_0_slv,
|
||||||
|
[SNOC_BIMC_1_SLV] = &snoc_bimc_1_slv,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct msm8916_icc_desc msm8916_bimc = {
|
||||||
|
.nodes = msm8916_bimc_nodes,
|
||||||
|
.num_nodes = ARRAY_SIZE(msm8916_bimc_nodes),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct msm8916_icc_node *msm8916_pcnoc_nodes[] = {
|
||||||
|
[MASTER_BLSP_1] = &mas_blsp_1,
|
||||||
|
[MASTER_DEHR] = &mas_dehr,
|
||||||
|
[MASTER_LPASS] = &mas_audio,
|
||||||
|
[MASTER_CRYPTO_CORE0] = &mas_pcnoc_crypto_0,
|
||||||
|
[MASTER_SDCC_1] = &mas_pcnoc_sdcc_1,
|
||||||
|
[MASTER_SDCC_2] = &mas_pcnoc_sdcc_2,
|
||||||
|
[MASTER_SPDM] = &mas_spdm,
|
||||||
|
[MASTER_USB_HS] = &mas_usb_hs,
|
||||||
|
[PCNOC_INT_0] = &pcnoc_int_0,
|
||||||
|
[PCNOC_INT_1] = &pcnoc_int_1,
|
||||||
|
[PCNOC_MAS_0] = &pcnoc_m_0,
|
||||||
|
[PCNOC_MAS_1] = &pcnoc_m_1,
|
||||||
|
[PCNOC_SLV_0] = &pcnoc_s_0,
|
||||||
|
[PCNOC_SLV_1] = &pcnoc_s_1,
|
||||||
|
[PCNOC_SLV_2] = &pcnoc_s_2,
|
||||||
|
[PCNOC_SLV_3] = &pcnoc_s_3,
|
||||||
|
[PCNOC_SLV_4] = &pcnoc_s_4,
|
||||||
|
[PCNOC_SLV_8] = &pcnoc_s_8,
|
||||||
|
[PCNOC_SLV_9] = &pcnoc_s_9,
|
||||||
|
[PCNOC_SNOC_MAS] = &pcnoc_snoc_mas,
|
||||||
|
[SLAVE_BIMC_CFG] = &slv_bimc_cfg,
|
||||||
|
[SLAVE_BLSP_1] = &slv_blsp_1,
|
||||||
|
[SLAVE_BOOT_ROM] = &slv_boot_rom,
|
||||||
|
[SLAVE_CAMERA_CFG] = &slv_camera_cfg,
|
||||||
|
[SLAVE_CLK_CTL] = &slv_clk_ctl,
|
||||||
|
[SLAVE_CRYPTO_0_CFG] = &slv_crypto_0_cfg,
|
||||||
|
[SLAVE_DEHR_CFG] = &slv_dehr_cfg,
|
||||||
|
[SLAVE_DISPLAY_CFG] = &slv_display_cfg,
|
||||||
|
[SLAVE_GRAPHICS_3D_CFG] = &slv_gfx_cfg,
|
||||||
|
[SLAVE_IMEM_CFG] = &slv_imem_cfg,
|
||||||
|
[SLAVE_LPASS] = &slv_audio,
|
||||||
|
[SLAVE_MPM] = &slv_mpm,
|
||||||
|
[SLAVE_MSG_RAM] = &slv_msg_ram,
|
||||||
|
[SLAVE_MSS] = &slv_mss,
|
||||||
|
[SLAVE_PDM] = &slv_pdm,
|
||||||
|
[SLAVE_PMIC_ARB] = &slv_pmic_arb,
|
||||||
|
[SLAVE_PCNOC_CFG] = &slv_pcnoc_cfg,
|
||||||
|
[SLAVE_PRNG] = &slv_prng,
|
||||||
|
[SLAVE_QDSS_CFG] = &slv_qdss_cfg,
|
||||||
|
[SLAVE_RBCPR_CFG] = &slv_rbcpr_cfg,
|
||||||
|
[SLAVE_SDCC_1] = &slv_sdcc_1,
|
||||||
|
[SLAVE_SDCC_2] = &slv_sdcc_2,
|
||||||
|
[SLAVE_SECURITY] = &slv_security,
|
||||||
|
[SLAVE_SNOC_CFG] = &slv_snoc_cfg,
|
||||||
|
[SLAVE_SPDM] = &slv_spdm,
|
||||||
|
[SLAVE_TCSR] = &slv_tcsr,
|
||||||
|
[SLAVE_TLMM] = &slv_tlmm,
|
||||||
|
[SLAVE_USB_HS] = &slv_usb_hs,
|
||||||
|
[SLAVE_VENUS_CFG] = &slv_venus_cfg,
|
||||||
|
[SNOC_PCNOC_SLV] = &snoc_pcnoc_slv,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct msm8916_icc_desc msm8916_pcnoc = {
|
||||||
|
.nodes = msm8916_pcnoc_nodes,
|
||||||
|
.num_nodes = ARRAY_SIZE(msm8916_pcnoc_nodes),
|
||||||
|
};
|
||||||
|
|
||||||
|
static int msm8916_icc_set(struct icc_node *src, struct icc_node *dst)
|
||||||
|
{
|
||||||
|
struct msm8916_icc_provider *qp;
|
||||||
|
struct msm8916_icc_node *qn;
|
||||||
|
u64 sum_bw, max_peak_bw, rate;
|
||||||
|
u32 agg_avg = 0, agg_peak = 0;
|
||||||
|
struct icc_provider *provider;
|
||||||
|
struct icc_node *n;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
qn = src->data;
|
||||||
|
provider = src->provider;
|
||||||
|
qp = to_msm8916_provider(provider);
|
||||||
|
|
||||||
|
list_for_each_entry(n, &provider->nodes, node_list)
|
||||||
|
provider->aggregate(n, 0, n->avg_bw, n->peak_bw,
|
||||||
|
&agg_avg, &agg_peak);
|
||||||
|
|
||||||
|
sum_bw = icc_units_to_bps(agg_avg);
|
||||||
|
max_peak_bw = icc_units_to_bps(agg_peak);
|
||||||
|
|
||||||
|
/* send bandwidth request message to the RPM processor */
|
||||||
|
if (qn->mas_rpm_id != -1) {
|
||||||
|
ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
|
||||||
|
RPM_BUS_MASTER_REQ,
|
||||||
|
qn->mas_rpm_id,
|
||||||
|
sum_bw);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("qcom_icc_rpm_smd_send mas %d error %d\n",
|
||||||
|
qn->mas_rpm_id, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qn->slv_rpm_id != -1) {
|
||||||
|
ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
|
||||||
|
RPM_BUS_SLAVE_REQ,
|
||||||
|
qn->slv_rpm_id,
|
||||||
|
sum_bw);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("qcom_icc_rpm_smd_send slv error %d\n",
|
||||||
|
ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rate = max(sum_bw, max_peak_bw);
|
||||||
|
|
||||||
|
do_div(rate, qn->buswidth);
|
||||||
|
|
||||||
|
if (qn->rate == rate)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < qp->num_clks; i++) {
|
||||||
|
ret = clk_set_rate(qp->bus_clks[i].clk, rate);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s clk_set_rate error: %d\n",
|
||||||
|
qp->bus_clks[i].id, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qn->rate = rate;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int msm8916_qnoc_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
const struct msm8916_icc_desc *desc;
|
||||||
|
struct msm8916_icc_node **qnodes;
|
||||||
|
struct msm8916_icc_provider *qp;
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct icc_onecell_data *data;
|
||||||
|
struct icc_provider *provider;
|
||||||
|
struct icc_node *node;
|
||||||
|
size_t num_nodes, i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* wait for the RPM proxy */
|
||||||
|
if (!qcom_icc_rpm_smd_available())
|
||||||
|
return -EPROBE_DEFER;
|
||||||
|
|
||||||
|
desc = of_device_get_match_data(dev);
|
||||||
|
if (!desc)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
qnodes = desc->nodes;
|
||||||
|
num_nodes = desc->num_nodes;
|
||||||
|
|
||||||
|
qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL);
|
||||||
|
if (!qp)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!data)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
qp->bus_clks = devm_kmemdup(dev, msm8916_bus_clocks,
|
||||||
|
sizeof(msm8916_bus_clocks), GFP_KERNEL);
|
||||||
|
if (!qp->bus_clks)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
qp->num_clks = ARRAY_SIZE(msm8916_bus_clocks);
|
||||||
|
ret = devm_clk_bulk_get(dev, qp->num_clks, qp->bus_clks);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = clk_bulk_prepare_enable(qp->num_clks, qp->bus_clks);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
provider = &qp->provider;
|
||||||
|
INIT_LIST_HEAD(&provider->nodes);
|
||||||
|
provider->dev = dev;
|
||||||
|
provider->set = msm8916_icc_set;
|
||||||
|
provider->aggregate = icc_std_aggregate;
|
||||||
|
provider->xlate = of_icc_xlate_onecell;
|
||||||
|
provider->data = data;
|
||||||
|
|
||||||
|
ret = icc_provider_add(provider);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "error adding interconnect provider: %d\n", ret);
|
||||||
|
clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < num_nodes; i++) {
|
||||||
|
size_t j;
|
||||||
|
|
||||||
|
node = icc_node_create(qnodes[i]->id);
|
||||||
|
if (IS_ERR(node)) {
|
||||||
|
ret = PTR_ERR(node);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->name = qnodes[i]->name;
|
||||||
|
node->data = qnodes[i];
|
||||||
|
icc_node_add(node, provider);
|
||||||
|
|
||||||
|
for (j = 0; j < qnodes[i]->num_links; j++)
|
||||||
|
icc_link_create(node, qnodes[i]->links[j]);
|
||||||
|
|
||||||
|
data->nodes[i] = node;
|
||||||
|
}
|
||||||
|
data->num_nodes = num_nodes;
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, qp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
icc_nodes_remove(provider);
|
||||||
|
icc_provider_del(provider);
|
||||||
|
clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int msm8916_qnoc_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct msm8916_icc_provider *qp = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
icc_nodes_remove(&qp->provider);
|
||||||
|
clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
|
||||||
|
return icc_provider_del(&qp->provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id msm8916_noc_of_match[] = {
|
||||||
|
{ .compatible = "qcom,msm8916-bimc", .data = &msm8916_bimc },
|
||||||
|
{ .compatible = "qcom,msm8916-pcnoc", .data = &msm8916_pcnoc },
|
||||||
|
{ .compatible = "qcom,msm8916-snoc", .data = &msm8916_snoc },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, msm8916_noc_of_match);
|
||||||
|
|
||||||
|
static struct platform_driver msm8916_noc_driver = {
|
||||||
|
.probe = msm8916_qnoc_probe,
|
||||||
|
.remove = msm8916_qnoc_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "qnoc-msm8916",
|
||||||
|
.of_match_table = msm8916_noc_of_match,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(msm8916_noc_driver);
|
||||||
|
MODULE_AUTHOR("Georgi Djakov <georgi.djakov@linaro.org>");
|
||||||
|
MODULE_DESCRIPTION("Qualcomm MSM8916 NoC driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
|
@ -550,15 +550,6 @@ static struct msm8974_icc_desc msm8974_snoc = {
|
||||||
.num_nodes = ARRAY_SIZE(msm8974_snoc_nodes),
|
.num_nodes = ARRAY_SIZE(msm8974_snoc_nodes),
|
||||||
};
|
};
|
||||||
|
|
||||||
static int msm8974_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
|
|
||||||
u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
|
|
||||||
{
|
|
||||||
*agg_avg += avg_bw;
|
|
||||||
*agg_peak = max(*agg_peak, peak_bw);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void msm8974_icc_rpm_smd_send(struct device *dev, int rsc_type,
|
static void msm8974_icc_rpm_smd_send(struct device *dev, int rsc_type,
|
||||||
char *name, int id, u64 val)
|
char *name, int id, u64 val)
|
||||||
{
|
{
|
||||||
|
@ -603,8 +594,8 @@ static int msm8974_icc_set(struct icc_node *src, struct icc_node *dst)
|
||||||
qp = to_msm8974_icc_provider(provider);
|
qp = to_msm8974_icc_provider(provider);
|
||||||
|
|
||||||
list_for_each_entry(n, &provider->nodes, node_list)
|
list_for_each_entry(n, &provider->nodes, node_list)
|
||||||
msm8974_icc_aggregate(n, 0, n->avg_bw, n->peak_bw,
|
provider->aggregate(n, 0, n->avg_bw, n->peak_bw,
|
||||||
&agg_avg, &agg_peak);
|
&agg_avg, &agg_peak);
|
||||||
|
|
||||||
sum_bw = icc_units_to_bps(agg_avg);
|
sum_bw = icc_units_to_bps(agg_avg);
|
||||||
max_peak_bw = icc_units_to_bps(agg_peak);
|
max_peak_bw = icc_units_to_bps(agg_peak);
|
||||||
|
@ -652,7 +643,7 @@ static int msm8974_icc_probe(struct platform_device *pdev)
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct icc_onecell_data *data;
|
struct icc_onecell_data *data;
|
||||||
struct icc_provider *provider;
|
struct icc_provider *provider;
|
||||||
struct icc_node *node, *tmp;
|
struct icc_node *node;
|
||||||
size_t num_nodes, i;
|
size_t num_nodes, i;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -694,7 +685,7 @@ static int msm8974_icc_probe(struct platform_device *pdev)
|
||||||
INIT_LIST_HEAD(&provider->nodes);
|
INIT_LIST_HEAD(&provider->nodes);
|
||||||
provider->dev = dev;
|
provider->dev = dev;
|
||||||
provider->set = msm8974_icc_set;
|
provider->set = msm8974_icc_set;
|
||||||
provider->aggregate = msm8974_icc_aggregate;
|
provider->aggregate = icc_std_aggregate;
|
||||||
provider->xlate = of_icc_xlate_onecell;
|
provider->xlate = of_icc_xlate_onecell;
|
||||||
provider->data = data;
|
provider->data = data;
|
||||||
|
|
||||||
|
@ -732,10 +723,7 @@ static int msm8974_icc_probe(struct platform_device *pdev)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_del_icc:
|
err_del_icc:
|
||||||
list_for_each_entry_safe(node, tmp, &provider->nodes, node_list) {
|
icc_nodes_remove(provider);
|
||||||
icc_node_del(node);
|
|
||||||
icc_node_destroy(node->id);
|
|
||||||
}
|
|
||||||
icc_provider_del(provider);
|
icc_provider_del(provider);
|
||||||
|
|
||||||
err_disable_clks:
|
err_disable_clks:
|
||||||
|
@ -747,16 +735,10 @@ err_disable_clks:
|
||||||
static int msm8974_icc_remove(struct platform_device *pdev)
|
static int msm8974_icc_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct msm8974_icc_provider *qp = platform_get_drvdata(pdev);
|
struct msm8974_icc_provider *qp = platform_get_drvdata(pdev);
|
||||||
struct icc_provider *provider = &qp->provider;
|
|
||||||
struct icc_node *n, *tmp;
|
|
||||||
|
|
||||||
list_for_each_entry_safe(n, tmp, &provider->nodes, node_list) {
|
icc_nodes_remove(&qp->provider);
|
||||||
icc_node_del(n);
|
|
||||||
icc_node_destroy(n->id);
|
|
||||||
}
|
|
||||||
clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
|
clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
|
||||||
|
return icc_provider_del(&qp->provider);
|
||||||
return icc_provider_del(provider);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id msm8974_noc_of_match[] = {
|
static const struct of_device_id msm8974_noc_of_match[] = {
|
||||||
|
|
|
@ -327,15 +327,6 @@ static struct qcom_icc_desc qcs404_snoc = {
|
||||||
.num_nodes = ARRAY_SIZE(qcs404_snoc_nodes),
|
.num_nodes = ARRAY_SIZE(qcs404_snoc_nodes),
|
||||||
};
|
};
|
||||||
|
|
||||||
static int qcom_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
|
|
||||||
u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
|
|
||||||
{
|
|
||||||
*agg_avg += avg_bw;
|
|
||||||
*agg_peak = max(*agg_peak, peak_bw);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
|
static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
|
||||||
{
|
{
|
||||||
struct qcom_icc_provider *qp;
|
struct qcom_icc_provider *qp;
|
||||||
|
@ -354,8 +345,8 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
|
||||||
qp = to_qcom_provider(provider);
|
qp = to_qcom_provider(provider);
|
||||||
|
|
||||||
list_for_each_entry(n, &provider->nodes, node_list)
|
list_for_each_entry(n, &provider->nodes, node_list)
|
||||||
qcom_icc_aggregate(n, 0, n->avg_bw, n->peak_bw,
|
provider->aggregate(n, 0, n->avg_bw, n->peak_bw,
|
||||||
&agg_avg, &agg_peak);
|
&agg_avg, &agg_peak);
|
||||||
|
|
||||||
sum_bw = icc_units_to_bps(agg_avg);
|
sum_bw = icc_units_to_bps(agg_avg);
|
||||||
max_peak_bw = icc_units_to_bps(agg_peak);
|
max_peak_bw = icc_units_to_bps(agg_peak);
|
||||||
|
@ -414,7 +405,7 @@ static int qnoc_probe(struct platform_device *pdev)
|
||||||
struct icc_provider *provider;
|
struct icc_provider *provider;
|
||||||
struct qcom_icc_node **qnodes;
|
struct qcom_icc_node **qnodes;
|
||||||
struct qcom_icc_provider *qp;
|
struct qcom_icc_provider *qp;
|
||||||
struct icc_node *node, *tmp;
|
struct icc_node *node;
|
||||||
size_t num_nodes, i;
|
size_t num_nodes, i;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -456,7 +447,7 @@ static int qnoc_probe(struct platform_device *pdev)
|
||||||
INIT_LIST_HEAD(&provider->nodes);
|
INIT_LIST_HEAD(&provider->nodes);
|
||||||
provider->dev = dev;
|
provider->dev = dev;
|
||||||
provider->set = qcom_icc_set;
|
provider->set = qcom_icc_set;
|
||||||
provider->aggregate = qcom_icc_aggregate;
|
provider->aggregate = icc_std_aggregate;
|
||||||
provider->xlate = of_icc_xlate_onecell;
|
provider->xlate = of_icc_xlate_onecell;
|
||||||
provider->data = data;
|
provider->data = data;
|
||||||
|
|
||||||
|
@ -494,10 +485,7 @@ static int qnoc_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
err:
|
err:
|
||||||
list_for_each_entry_safe(node, tmp, &provider->nodes, node_list) {
|
icc_nodes_remove(provider);
|
||||||
icc_node_del(node);
|
|
||||||
icc_node_destroy(node->id);
|
|
||||||
}
|
|
||||||
clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
|
clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
|
||||||
icc_provider_del(provider);
|
icc_provider_del(provider);
|
||||||
|
|
||||||
|
@ -507,16 +495,10 @@ err:
|
||||||
static int qnoc_remove(struct platform_device *pdev)
|
static int qnoc_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
|
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
|
||||||
struct icc_provider *provider = &qp->provider;
|
|
||||||
struct icc_node *n, *tmp;
|
|
||||||
|
|
||||||
list_for_each_entry_safe(n, tmp, &provider->nodes, node_list) {
|
icc_nodes_remove(&qp->provider);
|
||||||
icc_node_del(n);
|
|
||||||
icc_node_destroy(n->id);
|
|
||||||
}
|
|
||||||
clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
|
clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
|
||||||
|
return icc_provider_del(&qp->provider);
|
||||||
return icc_provider_del(provider);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id qcs404_noc_of_match[] = {
|
static const struct of_device_id qcs404_noc_of_match[] = {
|
||||||
|
|
|
@ -855,11 +855,7 @@ static int qnoc_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
err:
|
err:
|
||||||
list_for_each_entry(node, &provider->nodes, node_list) {
|
icc_nodes_remove(provider);
|
||||||
icc_node_del(node);
|
|
||||||
icc_node_destroy(node->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
icc_provider_del(provider);
|
icc_provider_del(provider);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -867,15 +863,9 @@ err:
|
||||||
static int qnoc_remove(struct platform_device *pdev)
|
static int qnoc_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
|
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
|
||||||
struct icc_provider *provider = &qp->provider;
|
|
||||||
struct icc_node *n, *tmp;
|
|
||||||
|
|
||||||
list_for_each_entry_safe(n, tmp, &provider->nodes, node_list) {
|
icc_nodes_remove(&qp->provider);
|
||||||
icc_node_del(n);
|
return icc_provider_del(&qp->provider);
|
||||||
icc_node_destroy(n->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return icc_provider_del(provider);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id qnoc_of_match[] = {
|
static const struct of_device_id qnoc_of_match[] = {
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Interconnect framework tracepoints
|
||||||
|
* Copyright (c) 2019, Linaro Ltd.
|
||||||
|
* Author: Georgi Djakov <georgi.djakov@linaro.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef TRACE_SYSTEM
|
||||||
|
#define TRACE_SYSTEM interconnect
|
||||||
|
|
||||||
|
#if !defined(_TRACE_INTERCONNECT_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||||
|
#define _TRACE_INTERCONNECT_H
|
||||||
|
|
||||||
|
#include <linux/interconnect.h>
|
||||||
|
#include <linux/tracepoint.h>
|
||||||
|
|
||||||
|
TRACE_EVENT(icc_set_bw,
|
||||||
|
|
||||||
|
TP_PROTO(struct icc_path *p, struct icc_node *n, int i,
|
||||||
|
u32 avg_bw, u32 peak_bw),
|
||||||
|
|
||||||
|
TP_ARGS(p, n, i, avg_bw, peak_bw),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__string(path_name, p->name)
|
||||||
|
__string(dev, dev_name(p->reqs[i].dev))
|
||||||
|
__string(node_name, n->name)
|
||||||
|
__field(u32, avg_bw)
|
||||||
|
__field(u32, peak_bw)
|
||||||
|
__field(u32, node_avg_bw)
|
||||||
|
__field(u32, node_peak_bw)
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__assign_str(path_name, p->name);
|
||||||
|
__assign_str(dev, dev_name(p->reqs[i].dev));
|
||||||
|
__assign_str(node_name, n->name);
|
||||||
|
__entry->avg_bw = avg_bw;
|
||||||
|
__entry->peak_bw = peak_bw;
|
||||||
|
__entry->node_avg_bw = n->avg_bw;
|
||||||
|
__entry->node_peak_bw = n->peak_bw;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk("path=%s dev=%s node=%s avg_bw=%u peak_bw=%u agg_avg=%u agg_peak=%u",
|
||||||
|
__get_str(path_name),
|
||||||
|
__get_str(dev),
|
||||||
|
__get_str(node_name),
|
||||||
|
__entry->avg_bw,
|
||||||
|
__entry->peak_bw,
|
||||||
|
__entry->node_avg_bw,
|
||||||
|
__entry->node_peak_bw)
|
||||||
|
);
|
||||||
|
|
||||||
|
TRACE_EVENT(icc_set_bw_end,
|
||||||
|
|
||||||
|
TP_PROTO(struct icc_path *p, int ret),
|
||||||
|
|
||||||
|
TP_ARGS(p, ret),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__string(path_name, p->name)
|
||||||
|
__string(dev, dev_name(p->reqs[0].dev))
|
||||||
|
__field(int, ret)
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__assign_str(path_name, p->name);
|
||||||
|
__assign_str(dev, dev_name(p->reqs[0].dev));
|
||||||
|
__entry->ret = ret;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk("path=%s dev=%s ret=%d",
|
||||||
|
__get_str(path_name),
|
||||||
|
__get_str(dev),
|
||||||
|
__entry->ret)
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif /* _TRACE_INTERCONNECT_H */
|
||||||
|
|
||||||
|
/* This part must be outside protection */
|
||||||
|
|
||||||
|
#undef TRACE_INCLUDE_PATH
|
||||||
|
#define TRACE_INCLUDE_PATH .
|
||||||
|
|
||||||
|
#undef TRACE_INCLUDE_FILE
|
||||||
|
#define TRACE_INCLUDE_FILE trace
|
||||||
|
|
||||||
|
#include <trace/define_trace.h>
|
|
@ -38,12 +38,18 @@ static const struct alcor_dev_cfg au6621_cfg = {
|
||||||
.dma = 1,
|
.dma = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct alcor_dev_cfg au6625_cfg = {
|
||||||
|
.dma = 0,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct pci_device_id pci_ids[] = {
|
static const struct pci_device_id pci_ids[] = {
|
||||||
{ PCI_DEVICE(PCI_ID_ALCOR_MICRO, PCI_ID_AU6601),
|
{ PCI_DEVICE(PCI_ID_ALCOR_MICRO, PCI_ID_AU6601),
|
||||||
.driver_data = (kernel_ulong_t)&alcor_cfg },
|
.driver_data = (kernel_ulong_t)&alcor_cfg },
|
||||||
{ PCI_DEVICE(PCI_ID_ALCOR_MICRO, PCI_ID_AU6621),
|
{ PCI_DEVICE(PCI_ID_ALCOR_MICRO, PCI_ID_AU6621),
|
||||||
.driver_data = (kernel_ulong_t)&au6621_cfg },
|
.driver_data = (kernel_ulong_t)&au6621_cfg },
|
||||||
{ },
|
{ PCI_DEVICE(PCI_ID_ALCOR_MICRO, PCI_ID_AU6625),
|
||||||
|
.driver_data = (kernel_ulong_t)&au6625_cfg },
|
||||||
|
{},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(pci, pci_ids);
|
MODULE_DEVICE_TABLE(pci, pci_ids);
|
||||||
|
|
||||||
|
|
|
@ -628,7 +628,8 @@ int rts5261_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
|
||||||
u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk)
|
u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk)
|
||||||
{
|
{
|
||||||
int err, clk;
|
int err, clk;
|
||||||
u8 n, clk_divider, mcu_cnt, div;
|
u16 n;
|
||||||
|
u8 clk_divider, mcu_cnt, div;
|
||||||
static const u8 depth[] = {
|
static const u8 depth[] = {
|
||||||
[RTSX_SSC_DEPTH_4M] = RTS5261_SSC_DEPTH_4M,
|
[RTSX_SSC_DEPTH_4M] = RTS5261_SSC_DEPTH_4M,
|
||||||
[RTSX_SSC_DEPTH_2M] = RTS5261_SSC_DEPTH_2M,
|
[RTSX_SSC_DEPTH_2M] = RTS5261_SSC_DEPTH_2M,
|
||||||
|
@ -661,13 +662,13 @@ int rts5261_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (pcr->ops->conv_clk_and_div_n)
|
if (pcr->ops->conv_clk_and_div_n)
|
||||||
n = (u8)pcr->ops->conv_clk_and_div_n(clk, CLK_TO_DIV_N);
|
n = pcr->ops->conv_clk_and_div_n(clk, CLK_TO_DIV_N);
|
||||||
else
|
else
|
||||||
n = (u8)(clk - 4);
|
n = clk - 4;
|
||||||
if ((clk <= 4) || (n > 396))
|
if ((clk <= 4) || (n > 396))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
mcu_cnt = (u8)(125/clk + 3);
|
mcu_cnt = 125/clk + 3;
|
||||||
if (mcu_cnt > 15)
|
if (mcu_cnt > 15)
|
||||||
mcu_cnt = 15;
|
mcu_cnt = 15;
|
||||||
|
|
||||||
|
@ -676,7 +677,7 @@ int rts5261_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
|
||||||
if (pcr->ops->conv_clk_and_div_n) {
|
if (pcr->ops->conv_clk_and_div_n) {
|
||||||
int dbl_clk = pcr->ops->conv_clk_and_div_n(n,
|
int dbl_clk = pcr->ops->conv_clk_and_div_n(n,
|
||||||
DIV_N_TO_CLK) * 2;
|
DIV_N_TO_CLK) * 2;
|
||||||
n = (u8)pcr->ops->conv_clk_and_div_n(dbl_clk,
|
n = pcr->ops->conv_clk_and_div_n(dbl_clk,
|
||||||
CLK_TO_DIV_N);
|
CLK_TO_DIV_N);
|
||||||
} else {
|
} else {
|
||||||
n = (n + 4) * 2 - 4;
|
n = (n + 4) * 2 - 4;
|
||||||
|
|
|
@ -352,7 +352,7 @@ void cxl_context_free(struct cxl_context *ctx)
|
||||||
void cxl_context_mm_count_get(struct cxl_context *ctx)
|
void cxl_context_mm_count_get(struct cxl_context *ctx)
|
||||||
{
|
{
|
||||||
if (ctx->mm)
|
if (ctx->mm)
|
||||||
atomic_inc(&ctx->mm->mm_count);
|
mmgrab(ctx->mm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cxl_context_mm_count_put(struct cxl_context *ctx)
|
void cxl_context_mm_count_put(struct cxl_context *ctx)
|
||||||
|
|
|
@ -1084,7 +1084,7 @@ static int setup_ddcb_queue(struct genwqe_dev *cd, struct ddcb_queue *queue)
|
||||||
queue->ddcb_daddr);
|
queue->ddcb_daddr);
|
||||||
queue->ddcb_vaddr = NULL;
|
queue->ddcb_vaddr = NULL;
|
||||||
queue->ddcb_daddr = 0ull;
|
queue->ddcb_daddr = 0ull;
|
||||||
return -ENODEV;
|
return rc;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1179,7 +1179,7 @@ static irqreturn_t genwqe_vf_isr(int irq, void *dev_id)
|
||||||
*/
|
*/
|
||||||
static int genwqe_card_thread(void *data)
|
static int genwqe_card_thread(void *data)
|
||||||
{
|
{
|
||||||
int should_stop = 0, rc = 0;
|
int should_stop = 0;
|
||||||
struct genwqe_dev *cd = (struct genwqe_dev *)data;
|
struct genwqe_dev *cd = (struct genwqe_dev *)data;
|
||||||
|
|
||||||
while (!kthread_should_stop()) {
|
while (!kthread_should_stop()) {
|
||||||
|
@ -1187,12 +1187,12 @@ static int genwqe_card_thread(void *data)
|
||||||
genwqe_check_ddcb_queue(cd, &cd->queue);
|
genwqe_check_ddcb_queue(cd, &cd->queue);
|
||||||
|
|
||||||
if (GENWQE_POLLING_ENABLED) {
|
if (GENWQE_POLLING_ENABLED) {
|
||||||
rc = wait_event_interruptible_timeout(
|
wait_event_interruptible_timeout(
|
||||||
cd->queue_waitq,
|
cd->queue_waitq,
|
||||||
genwqe_ddcbs_in_flight(cd) ||
|
genwqe_ddcbs_in_flight(cd) ||
|
||||||
(should_stop = kthread_should_stop()), 1);
|
(should_stop = kthread_should_stop()), 1);
|
||||||
} else {
|
} else {
|
||||||
rc = wait_event_interruptible_timeout(
|
wait_event_interruptible_timeout(
|
||||||
cd->queue_waitq,
|
cd->queue_waitq,
|
||||||
genwqe_next_ddcb_ready(cd) ||
|
genwqe_next_ddcb_ready(cd) ||
|
||||||
(should_stop = kthread_should_stop()), HZ);
|
(should_stop = kthread_should_stop()), HZ);
|
||||||
|
|
|
@ -173,6 +173,7 @@ static int isl29020_probe(struct i2c_client *client,
|
||||||
|
|
||||||
static int isl29020_remove(struct i2c_client *client)
|
static int isl29020_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
|
pm_runtime_disable(&client->dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &m_als_gr);
|
sysfs_remove_group(&client->dev.kobj, &m_als_gr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -765,7 +765,7 @@ static ssize_t uuid_show(struct device *dev, struct device_attribute *a,
|
||||||
struct mei_cl_device *cldev = to_mei_cl_device(dev);
|
struct mei_cl_device *cldev = to_mei_cl_device(dev);
|
||||||
const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
|
const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%pUl", uuid);
|
return sprintf(buf, "%pUl", uuid);
|
||||||
}
|
}
|
||||||
static DEVICE_ATTR_RO(uuid);
|
static DEVICE_ATTR_RO(uuid);
|
||||||
|
|
||||||
|
@ -775,7 +775,7 @@ static ssize_t version_show(struct device *dev, struct device_attribute *a,
|
||||||
struct mei_cl_device *cldev = to_mei_cl_device(dev);
|
struct mei_cl_device *cldev = to_mei_cl_device(dev);
|
||||||
u8 version = mei_me_cl_ver(cldev->me_cl);
|
u8 version = mei_me_cl_ver(cldev->me_cl);
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%02X", version);
|
return sprintf(buf, "%02X", version);
|
||||||
}
|
}
|
||||||
static DEVICE_ATTR_RO(version);
|
static DEVICE_ATTR_RO(version);
|
||||||
|
|
||||||
|
@ -797,7 +797,7 @@ static ssize_t max_conn_show(struct device *dev, struct device_attribute *a,
|
||||||
struct mei_cl_device *cldev = to_mei_cl_device(dev);
|
struct mei_cl_device *cldev = to_mei_cl_device(dev);
|
||||||
u8 maxconn = mei_me_cl_max_conn(cldev->me_cl);
|
u8 maxconn = mei_me_cl_max_conn(cldev->me_cl);
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%d", maxconn);
|
return sprintf(buf, "%d", maxconn);
|
||||||
}
|
}
|
||||||
static DEVICE_ATTR_RO(max_conn);
|
static DEVICE_ATTR_RO(max_conn);
|
||||||
|
|
||||||
|
@ -807,7 +807,7 @@ static ssize_t fixed_show(struct device *dev, struct device_attribute *a,
|
||||||
struct mei_cl_device *cldev = to_mei_cl_device(dev);
|
struct mei_cl_device *cldev = to_mei_cl_device(dev);
|
||||||
u8 fixed = mei_me_cl_fixed(cldev->me_cl);
|
u8 fixed = mei_me_cl_fixed(cldev->me_cl);
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%d", fixed);
|
return sprintf(buf, "%d", fixed);
|
||||||
}
|
}
|
||||||
static DEVICE_ATTR_RO(fixed);
|
static DEVICE_ATTR_RO(fixed);
|
||||||
|
|
||||||
|
@ -817,7 +817,7 @@ static ssize_t max_len_show(struct device *dev, struct device_attribute *a,
|
||||||
struct mei_cl_device *cldev = to_mei_cl_device(dev);
|
struct mei_cl_device *cldev = to_mei_cl_device(dev);
|
||||||
u32 maxlen = mei_me_cl_max_len(cldev->me_cl);
|
u32 maxlen = mei_me_cl_max_len(cldev->me_cl);
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%u", maxlen);
|
return sprintf(buf, "%u", maxlen);
|
||||||
}
|
}
|
||||||
static DEVICE_ATTR_RO(max_len);
|
static DEVICE_ATTR_RO(max_len);
|
||||||
|
|
||||||
|
|
|
@ -757,11 +757,38 @@ static const struct component_master_ops mei_component_master_ops = {
|
||||||
.unbind = mei_component_master_unbind,
|
.unbind = mei_component_master_unbind,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mei_hdcp_component_match - compare function for matching mei hdcp.
|
||||||
|
*
|
||||||
|
* The function checks if the driver is i915, the subcomponent is HDCP
|
||||||
|
* and the grand parent of hdcp and the parent of i915 are the same
|
||||||
|
* PCH device.
|
||||||
|
*
|
||||||
|
* @dev: master device
|
||||||
|
* @subcomponent: subcomponent to match (I915_COMPONENT_HDCP)
|
||||||
|
* @data: compare data (mei hdcp device)
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* * 1 - if components match
|
||||||
|
* * 0 - otherwise
|
||||||
|
*/
|
||||||
static int mei_hdcp_component_match(struct device *dev, int subcomponent,
|
static int mei_hdcp_component_match(struct device *dev, int subcomponent,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
return !strcmp(dev->driver->name, "i915") &&
|
struct device *base = data;
|
||||||
subcomponent == I915_COMPONENT_HDCP;
|
|
||||||
|
if (strcmp(dev->driver->name, "i915") ||
|
||||||
|
subcomponent != I915_COMPONENT_HDCP)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
base = base->parent;
|
||||||
|
if (!base)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
base = base->parent;
|
||||||
|
dev = dev->parent;
|
||||||
|
|
||||||
|
return (base && dev && dev == base);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mei_hdcp_probe(struct mei_cl_device *cldev,
|
static int mei_hdcp_probe(struct mei_cl_device *cldev,
|
||||||
|
@ -785,7 +812,7 @@ static int mei_hdcp_probe(struct mei_cl_device *cldev,
|
||||||
|
|
||||||
master_match = NULL;
|
master_match = NULL;
|
||||||
component_match_add_typed(&cldev->dev, &master_match,
|
component_match_add_typed(&cldev->dev, &master_match,
|
||||||
mei_hdcp_component_match, comp_master);
|
mei_hdcp_component_match, &cldev->dev);
|
||||||
if (IS_ERR_OR_NULL(master_match)) {
|
if (IS_ERR_OR_NULL(master_match)) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err_exit;
|
goto err_exit;
|
||||||
|
|
|
@ -81,10 +81,16 @@
|
||||||
|
|
||||||
#define MEI_DEV_ID_CMP_LP 0x02e0 /* Comet Point LP */
|
#define MEI_DEV_ID_CMP_LP 0x02e0 /* Comet Point LP */
|
||||||
#define MEI_DEV_ID_CMP_LP_3 0x02e4 /* Comet Point LP 3 (iTouch) */
|
#define MEI_DEV_ID_CMP_LP_3 0x02e4 /* Comet Point LP 3 (iTouch) */
|
||||||
|
|
||||||
#define MEI_DEV_ID_CMP_V 0xA3BA /* Comet Point Lake V */
|
#define MEI_DEV_ID_CMP_V 0xA3BA /* Comet Point Lake V */
|
||||||
|
|
||||||
|
#define MEI_DEV_ID_CMP_H 0x06e0 /* Comet Lake H */
|
||||||
|
#define MEI_DEV_ID_CMP_H_3 0x06e4 /* Comet Lake H 3 (iTouch) */
|
||||||
|
|
||||||
#define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */
|
#define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */
|
||||||
|
|
||||||
|
#define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */
|
||||||
|
|
||||||
#define MEI_DEV_ID_TGP_LP 0xA0E0 /* Tiger Lake Point LP */
|
#define MEI_DEV_ID_TGP_LP 0xA0E0 /* Tiger Lake Point LP */
|
||||||
|
|
||||||
#define MEI_DEV_ID_MCC 0x4B70 /* Mule Creek Canyon (EHL) */
|
#define MEI_DEV_ID_MCC 0x4B70 /* Mule Creek Canyon (EHL) */
|
||||||
|
|
|
@ -99,11 +99,15 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
|
||||||
{MEI_PCI_DEVICE(MEI_DEV_ID_CMP_LP, MEI_ME_PCH12_CFG)},
|
{MEI_PCI_DEVICE(MEI_DEV_ID_CMP_LP, MEI_ME_PCH12_CFG)},
|
||||||
{MEI_PCI_DEVICE(MEI_DEV_ID_CMP_LP_3, MEI_ME_PCH8_CFG)},
|
{MEI_PCI_DEVICE(MEI_DEV_ID_CMP_LP_3, MEI_ME_PCH8_CFG)},
|
||||||
{MEI_PCI_DEVICE(MEI_DEV_ID_CMP_V, MEI_ME_PCH12_CFG)},
|
{MEI_PCI_DEVICE(MEI_DEV_ID_CMP_V, MEI_ME_PCH12_CFG)},
|
||||||
|
{MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H, MEI_ME_PCH12_CFG)},
|
||||||
|
{MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_CFG)},
|
||||||
|
|
||||||
{MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)},
|
{MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)},
|
||||||
|
|
||||||
{MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)},
|
{MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)},
|
||||||
|
|
||||||
|
{MEI_PCI_DEVICE(MEI_DEV_ID_JSP_N, MEI_ME_PCH15_CFG)},
|
||||||
|
|
||||||
{MEI_PCI_DEVICE(MEI_DEV_ID_MCC, MEI_ME_PCH15_CFG)},
|
{MEI_PCI_DEVICE(MEI_DEV_ID_MCC, MEI_ME_PCH15_CFG)},
|
||||||
{MEI_PCI_DEVICE(MEI_DEV_ID_MCC_4, MEI_ME_PCH8_CFG)},
|
{MEI_PCI_DEVICE(MEI_DEV_ID_MCC_4, MEI_ME_PCH8_CFG)},
|
||||||
|
|
||||||
|
|
|
@ -65,9 +65,6 @@ void __init mic_create_card_debug_dir(struct mic_driver *mdrv)
|
||||||
*/
|
*/
|
||||||
void mic_delete_card_debug_dir(struct mic_driver *mdrv)
|
void mic_delete_card_debug_dir(struct mic_driver *mdrv)
|
||||||
{
|
{
|
||||||
if (!mdrv->dbg_dir)
|
|
||||||
return;
|
|
||||||
|
|
||||||
debugfs_remove_recursive(mdrv->dbg_dir);
|
debugfs_remove_recursive(mdrv->dbg_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -102,9 +102,6 @@ void cosm_create_debug_dir(struct cosm_device *cdev)
|
||||||
|
|
||||||
void cosm_delete_debug_dir(struct cosm_device *cdev)
|
void cosm_delete_debug_dir(struct cosm_device *cdev)
|
||||||
{
|
{
|
||||||
if (!cdev->dbg_dir)
|
|
||||||
return;
|
|
||||||
|
|
||||||
debugfs_remove_recursive(cdev->dbg_dir);
|
debugfs_remove_recursive(cdev->dbg_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -129,9 +129,6 @@ void mic_create_debug_dir(struct mic_device *mdev)
|
||||||
*/
|
*/
|
||||||
void mic_delete_debug_dir(struct mic_device *mdev)
|
void mic_delete_debug_dir(struct mic_device *mdev)
|
||||||
{
|
{
|
||||||
if (!mdev->dbg_dir)
|
|
||||||
return;
|
|
||||||
|
|
||||||
debugfs_remove_recursive(mdev->dbg_dir);
|
debugfs_remove_recursive(mdev->dbg_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -792,7 +792,7 @@ static int pti_pci_probe(struct pci_dev *pdev,
|
||||||
const struct pci_device_id *ent)
|
const struct pci_device_id *ent)
|
||||||
{
|
{
|
||||||
unsigned int a;
|
unsigned int a;
|
||||||
int retval = -EINVAL;
|
int retval;
|
||||||
int pci_bar = 1;
|
int pci_bar = 1;
|
||||||
|
|
||||||
dev_dbg(&pdev->dev, "%s %s(%d): PTI PCI ID %04x:%04x\n", __FILE__,
|
dev_dbg(&pdev->dev, "%s %s(%d): PTI PCI ID %04x:%04x\n", __FILE__,
|
||||||
|
@ -910,7 +910,7 @@ static struct pci_driver pti_pci_driver = {
|
||||||
*/
|
*/
|
||||||
static int __init pti_init(void)
|
static int __init pti_init(void)
|
||||||
{
|
{
|
||||||
int retval = -EINVAL;
|
int retval;
|
||||||
|
|
||||||
/* First register module as tty device */
|
/* First register module as tty device */
|
||||||
|
|
||||||
|
|
|
@ -10,16 +10,16 @@
|
||||||
|
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/kexec.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
#include <uapi/misc/pvpanic.h>
|
||||||
|
|
||||||
static void __iomem *base;
|
static void __iomem *base;
|
||||||
|
|
||||||
#define PVPANIC_PANICKED (1 << 0)
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Hu Tao <hutao@cn.fujitsu.com>");
|
MODULE_AUTHOR("Hu Tao <hutao@cn.fujitsu.com>");
|
||||||
MODULE_DESCRIPTION("pvpanic device driver");
|
MODULE_DESCRIPTION("pvpanic device driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
@ -34,7 +34,13 @@ static int
|
||||||
pvpanic_panic_notify(struct notifier_block *nb, unsigned long code,
|
pvpanic_panic_notify(struct notifier_block *nb, unsigned long code,
|
||||||
void *unused)
|
void *unused)
|
||||||
{
|
{
|
||||||
pvpanic_send_event(PVPANIC_PANICKED);
|
unsigned int event = PVPANIC_PANICKED;
|
||||||
|
|
||||||
|
if (kexec_crash_loaded())
|
||||||
|
event = PVPANIC_CRASH_LOADED;
|
||||||
|
|
||||||
|
pvpanic_send_event(event);
|
||||||
|
|
||||||
return NOTIFY_DONE;
|
return NOTIFY_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,7 @@ void *sram_exec_copy(struct gen_pool *pool, void *dst, void *src,
|
||||||
unsigned long base;
|
unsigned long base;
|
||||||
int pages;
|
int pages;
|
||||||
void *dst_cpy;
|
void *dst_cpy;
|
||||||
|
int ret;
|
||||||
|
|
||||||
mutex_lock(&exec_pool_list_mutex);
|
mutex_lock(&exec_pool_list_mutex);
|
||||||
list_for_each_entry(p, &exec_pool_list, list) {
|
list_for_each_entry(p, &exec_pool_list, list) {
|
||||||
|
@ -104,16 +105,28 @@ void *sram_exec_copy(struct gen_pool *pool, void *dst, void *src,
|
||||||
|
|
||||||
mutex_lock(&part->lock);
|
mutex_lock(&part->lock);
|
||||||
|
|
||||||
set_memory_nx((unsigned long)base, pages);
|
ret = set_memory_nx((unsigned long)base, pages);
|
||||||
set_memory_rw((unsigned long)base, pages);
|
if (ret)
|
||||||
|
goto error_out;
|
||||||
|
ret = set_memory_rw((unsigned long)base, pages);
|
||||||
|
if (ret)
|
||||||
|
goto error_out;
|
||||||
|
|
||||||
dst_cpy = fncpy(dst, src, size);
|
dst_cpy = fncpy(dst, src, size);
|
||||||
|
|
||||||
set_memory_ro((unsigned long)base, pages);
|
ret = set_memory_ro((unsigned long)base, pages);
|
||||||
set_memory_x((unsigned long)base, pages);
|
if (ret)
|
||||||
|
goto error_out;
|
||||||
|
ret = set_memory_x((unsigned long)base, pages);
|
||||||
|
if (ret)
|
||||||
|
goto error_out;
|
||||||
|
|
||||||
mutex_unlock(&part->lock);
|
mutex_unlock(&part->lock);
|
||||||
|
|
||||||
return dst_cpy;
|
return dst_cpy;
|
||||||
|
|
||||||
|
error_out:
|
||||||
|
mutex_unlock(&part->lock);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(sram_exec_copy);
|
EXPORT_SYMBOL_GPL(sram_exec_copy);
|
||||||
|
|
|
@ -736,8 +736,8 @@ static int st_tty_open(struct tty_struct *tty)
|
||||||
|
|
||||||
static void st_tty_close(struct tty_struct *tty)
|
static void st_tty_close(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
unsigned char i = ST_MAX_CHANNELS;
|
unsigned char i;
|
||||||
unsigned long flags = 0;
|
unsigned long flags;
|
||||||
struct st_data_s *st_gdata = tty->disc_data;
|
struct st_data_s *st_gdata = tty->disc_data;
|
||||||
|
|
||||||
pr_info("%s ", __func__);
|
pr_info("%s ", __func__);
|
||||||
|
|
|
@ -148,16 +148,14 @@ static int tsl2550_calculate_lux(u8 ch0, u8 ch1)
|
||||||
u16 c0 = count_lut[ch0];
|
u16 c0 = count_lut[ch0];
|
||||||
u16 c1 = count_lut[ch1];
|
u16 c1 = count_lut[ch1];
|
||||||
|
|
||||||
/*
|
|
||||||
* Calculate ratio.
|
|
||||||
* Note: the "128" is a scaling factor
|
|
||||||
*/
|
|
||||||
u8 r = 128;
|
|
||||||
|
|
||||||
/* Avoid division by 0 and count 1 cannot be greater than count 0 */
|
/* Avoid division by 0 and count 1 cannot be greater than count 0 */
|
||||||
if (c1 <= c0)
|
if (c1 <= c0)
|
||||||
if (c0) {
|
if (c0) {
|
||||||
r = c1 * 128 / c0;
|
/*
|
||||||
|
* Calculate ratio.
|
||||||
|
* Note: the "128" is a scaling factor
|
||||||
|
*/
|
||||||
|
u8 r = c1 * 128 / c0;
|
||||||
|
|
||||||
/* Calculate LUX */
|
/* Calculate LUX */
|
||||||
lux = ((c0 - c1) * ratio_lut[r]) / 256;
|
lux = ((c0 - c1) * ratio_lut[r]) / 256;
|
||||||
|
|
|
@ -733,7 +733,7 @@ static int xsdfec_set_order(struct xsdfec_dev *xsdfec, void __user *arg)
|
||||||
enum xsdfec_order order;
|
enum xsdfec_order order;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = get_user(order, (enum xsdfec_order *)arg);
|
err = get_user(order, (enum xsdfec_order __user *)arg);
|
||||||
if (err)
|
if (err)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
|
@ -1025,25 +1025,25 @@ static long xsdfec_dev_compat_ioctl(struct file *file, unsigned int cmd,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static unsigned int xsdfec_poll(struct file *file, poll_table *wait)
|
static __poll_t xsdfec_poll(struct file *file, poll_table *wait)
|
||||||
{
|
{
|
||||||
unsigned int mask = 0;
|
__poll_t mask = 0;
|
||||||
struct xsdfec_dev *xsdfec;
|
struct xsdfec_dev *xsdfec;
|
||||||
|
|
||||||
xsdfec = container_of(file->private_data, struct xsdfec_dev, miscdev);
|
xsdfec = container_of(file->private_data, struct xsdfec_dev, miscdev);
|
||||||
|
|
||||||
if (!xsdfec)
|
if (!xsdfec)
|
||||||
return POLLNVAL | POLLHUP;
|
return EPOLLNVAL | EPOLLHUP;
|
||||||
|
|
||||||
poll_wait(file, &xsdfec->waitq, wait);
|
poll_wait(file, &xsdfec->waitq, wait);
|
||||||
|
|
||||||
/* XSDFEC ISR detected an error */
|
/* XSDFEC ISR detected an error */
|
||||||
spin_lock_irqsave(&xsdfec->error_data_lock, xsdfec->flags);
|
spin_lock_irqsave(&xsdfec->error_data_lock, xsdfec->flags);
|
||||||
if (xsdfec->state_updated)
|
if (xsdfec->state_updated)
|
||||||
mask |= POLLIN | POLLPRI;
|
mask |= EPOLLIN | EPOLLPRI;
|
||||||
|
|
||||||
if (xsdfec->stats_updated)
|
if (xsdfec->stats_updated)
|
||||||
mask |= POLLIN | POLLRDNORM;
|
mask |= EPOLLIN | EPOLLRDNORM;
|
||||||
spin_unlock_irqrestore(&xsdfec->error_data_lock, xsdfec->flags);
|
spin_unlock_irqrestore(&xsdfec->error_data_lock, xsdfec->flags);
|
||||||
|
|
||||||
return mask;
|
return mask;
|
||||||
|
|
|
@ -109,6 +109,14 @@ config QCOM_QFPROM
|
||||||
This driver can also be built as a module. If so, the module
|
This driver can also be built as a module. If so, the module
|
||||||
will be called nvmem_qfprom.
|
will be called nvmem_qfprom.
|
||||||
|
|
||||||
|
config NVMEM_SPMI_SDAM
|
||||||
|
tristate "SPMI SDAM Support"
|
||||||
|
depends on SPMI
|
||||||
|
help
|
||||||
|
This driver supports the Shared Direct Access Memory Module on
|
||||||
|
Qualcomm Technologies, Inc. PMICs. It provides the clients
|
||||||
|
an interface to read/write to the SDAM module's shared memory.
|
||||||
|
|
||||||
config ROCKCHIP_EFUSE
|
config ROCKCHIP_EFUSE
|
||||||
tristate "Rockchip eFuse Support"
|
tristate "Rockchip eFuse Support"
|
||||||
depends on ARCH_ROCKCHIP || COMPILE_TEST
|
depends on ARCH_ROCKCHIP || COMPILE_TEST
|
||||||
|
|
|
@ -28,6 +28,8 @@ obj-$(CONFIG_MTK_EFUSE) += nvmem_mtk-efuse.o
|
||||||
nvmem_mtk-efuse-y := mtk-efuse.o
|
nvmem_mtk-efuse-y := mtk-efuse.o
|
||||||
obj-$(CONFIG_QCOM_QFPROM) += nvmem_qfprom.o
|
obj-$(CONFIG_QCOM_QFPROM) += nvmem_qfprom.o
|
||||||
nvmem_qfprom-y := qfprom.o
|
nvmem_qfprom-y := qfprom.o
|
||||||
|
obj-$(CONFIG_NVMEM_SPMI_SDAM) += nvmem_qcom-spmi-sdam.o
|
||||||
|
nvmem_qcom-spmi-sdam-y += qcom-spmi-sdam.o
|
||||||
obj-$(CONFIG_ROCKCHIP_EFUSE) += nvmem_rockchip_efuse.o
|
obj-$(CONFIG_ROCKCHIP_EFUSE) += nvmem_rockchip_efuse.o
|
||||||
nvmem_rockchip_efuse-y := rockchip-efuse.o
|
nvmem_rockchip_efuse-y := rockchip-efuse.o
|
||||||
obj-$(CONFIG_ROCKCHIP_OTP) += nvmem-rockchip-otp.o
|
obj-$(CONFIG_ROCKCHIP_OTP) += nvmem-rockchip-otp.o
|
||||||
|
|
|
@ -83,7 +83,7 @@ static void nvmem_cell_drop(struct nvmem_cell *cell)
|
||||||
list_del(&cell->node);
|
list_del(&cell->node);
|
||||||
mutex_unlock(&nvmem_mutex);
|
mutex_unlock(&nvmem_mutex);
|
||||||
of_node_put(cell->np);
|
of_node_put(cell->np);
|
||||||
kfree(cell->name);
|
kfree_const(cell->name);
|
||||||
kfree(cell);
|
kfree(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +110,9 @@ static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem,
|
||||||
cell->nvmem = nvmem;
|
cell->nvmem = nvmem;
|
||||||
cell->offset = info->offset;
|
cell->offset = info->offset;
|
||||||
cell->bytes = info->bytes;
|
cell->bytes = info->bytes;
|
||||||
cell->name = info->name;
|
cell->name = kstrdup_const(info->name, GFP_KERNEL);
|
||||||
|
if (!cell->name)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
cell->bit_offset = info->bit_offset;
|
cell->bit_offset = info->bit_offset;
|
||||||
cell->nbits = info->nbits;
|
cell->nbits = info->nbits;
|
||||||
|
@ -300,7 +302,7 @@ static int nvmem_add_cells_from_of(struct nvmem_device *nvmem)
|
||||||
dev_err(dev, "cell %s unaligned to nvmem stride %d\n",
|
dev_err(dev, "cell %s unaligned to nvmem stride %d\n",
|
||||||
cell->name, nvmem->stride);
|
cell->name, nvmem->stride);
|
||||||
/* Cells already added will be freed later. */
|
/* Cells already added will be freed later. */
|
||||||
kfree(cell->name);
|
kfree_const(cell->name);
|
||||||
kfree(cell);
|
kfree(cell);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,7 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#define IMX_SIP_OTP 0xC200000A
|
#define IMX_SIP_OTP_WRITE 0xc200000B
|
||||||
#define IMX_SIP_OTP_WRITE 0x2
|
|
||||||
|
|
||||||
enum ocotp_devtype {
|
enum ocotp_devtype {
|
||||||
IMX8QXP,
|
IMX8QXP,
|
||||||
|
@ -139,8 +138,8 @@ static int imx_scu_ocotp_read(void *context, unsigned int offset,
|
||||||
void *p;
|
void *p;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
|
||||||
index = offset >> 2;
|
index = offset;
|
||||||
num_bytes = round_up((offset % 4) + bytes, 4);
|
num_bytes = round_up(bytes, 4);
|
||||||
count = num_bytes >> 2;
|
count = num_bytes >> 2;
|
||||||
|
|
||||||
if (count > (priv->data->nregs - index))
|
if (count > (priv->data->nregs - index))
|
||||||
|
@ -169,7 +168,7 @@ static int imx_scu_ocotp_read(void *context, unsigned int offset,
|
||||||
buf++;
|
buf++;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(val, (u8 *)p + offset % 4, bytes);
|
memcpy(val, (u8 *)p, bytes);
|
||||||
|
|
||||||
mutex_unlock(&scu_ocotp_mutex);
|
mutex_unlock(&scu_ocotp_mutex);
|
||||||
|
|
||||||
|
@ -189,10 +188,10 @@ static int imx_scu_ocotp_write(void *context, unsigned int offset,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* allow only writing one complete OTP word at a time */
|
/* allow only writing one complete OTP word at a time */
|
||||||
if ((bytes != 4) || (offset % 4))
|
if (bytes != 4)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
index = offset >> 2;
|
index = offset;
|
||||||
|
|
||||||
if (in_hole(context, index))
|
if (in_hole(context, index))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -212,8 +211,7 @@ static int imx_scu_ocotp_write(void *context, unsigned int offset,
|
||||||
|
|
||||||
mutex_lock(&scu_ocotp_mutex);
|
mutex_lock(&scu_ocotp_mutex);
|
||||||
|
|
||||||
arm_smccc_smc(IMX_SIP_OTP, IMX_SIP_OTP_WRITE, index, *buf,
|
arm_smccc_smc(IMX_SIP_OTP_WRITE, index, *buf, 0, 0, 0, 0, 0, &res);
|
||||||
0, 0, 0, 0, &res);
|
|
||||||
|
|
||||||
mutex_unlock(&scu_ocotp_mutex);
|
mutex_unlock(&scu_ocotp_mutex);
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,14 @@
|
||||||
#define IMX_OCOTP_BM_CTRL_ERROR 0x00000200
|
#define IMX_OCOTP_BM_CTRL_ERROR 0x00000200
|
||||||
#define IMX_OCOTP_BM_CTRL_REL_SHADOWS 0x00000400
|
#define IMX_OCOTP_BM_CTRL_REL_SHADOWS 0x00000400
|
||||||
|
|
||||||
|
#define IMX_OCOTP_BM_CTRL_DEFAULT \
|
||||||
|
{ \
|
||||||
|
.bm_addr = IMX_OCOTP_BM_CTRL_ADDR, \
|
||||||
|
.bm_busy = IMX_OCOTP_BM_CTRL_BUSY, \
|
||||||
|
.bm_error = IMX_OCOTP_BM_CTRL_ERROR, \
|
||||||
|
.bm_rel_shadows = IMX_OCOTP_BM_CTRL_REL_SHADOWS,\
|
||||||
|
}
|
||||||
|
|
||||||
#define TIMING_STROBE_PROG_US 10 /* Min time to blow a fuse */
|
#define TIMING_STROBE_PROG_US 10 /* Min time to blow a fuse */
|
||||||
#define TIMING_STROBE_READ_NS 37 /* Min time before read */
|
#define TIMING_STROBE_READ_NS 37 /* Min time before read */
|
||||||
#define TIMING_RELAX_NS 17
|
#define TIMING_RELAX_NS 17
|
||||||
|
@ -62,18 +70,31 @@ struct ocotp_priv {
|
||||||
struct nvmem_config *config;
|
struct nvmem_config *config;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ocotp_ctrl_reg {
|
||||||
|
u32 bm_addr;
|
||||||
|
u32 bm_busy;
|
||||||
|
u32 bm_error;
|
||||||
|
u32 bm_rel_shadows;
|
||||||
|
};
|
||||||
|
|
||||||
struct ocotp_params {
|
struct ocotp_params {
|
||||||
unsigned int nregs;
|
unsigned int nregs;
|
||||||
unsigned int bank_address_words;
|
unsigned int bank_address_words;
|
||||||
void (*set_timing)(struct ocotp_priv *priv);
|
void (*set_timing)(struct ocotp_priv *priv);
|
||||||
|
struct ocotp_ctrl_reg ctrl;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int imx_ocotp_wait_for_busy(void __iomem *base, u32 flags)
|
static int imx_ocotp_wait_for_busy(struct ocotp_priv *priv, u32 flags)
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
u32 c, mask;
|
u32 c, mask;
|
||||||
|
u32 bm_ctrl_busy, bm_ctrl_error;
|
||||||
|
void __iomem *base = priv->base;
|
||||||
|
|
||||||
mask = IMX_OCOTP_BM_CTRL_BUSY | IMX_OCOTP_BM_CTRL_ERROR | flags;
|
bm_ctrl_busy = priv->params->ctrl.bm_busy;
|
||||||
|
bm_ctrl_error = priv->params->ctrl.bm_error;
|
||||||
|
|
||||||
|
mask = bm_ctrl_busy | bm_ctrl_error | flags;
|
||||||
|
|
||||||
for (count = 10000; count >= 0; count--) {
|
for (count = 10000; count >= 0; count--) {
|
||||||
c = readl(base + IMX_OCOTP_ADDR_CTRL);
|
c = readl(base + IMX_OCOTP_ADDR_CTRL);
|
||||||
|
@ -97,7 +118,7 @@ static int imx_ocotp_wait_for_busy(void __iomem *base, u32 flags)
|
||||||
* - A read is performed to from a fuse word which has been read
|
* - A read is performed to from a fuse word which has been read
|
||||||
* locked.
|
* locked.
|
||||||
*/
|
*/
|
||||||
if (c & IMX_OCOTP_BM_CTRL_ERROR)
|
if (c & bm_ctrl_error)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
@ -105,15 +126,18 @@ static int imx_ocotp_wait_for_busy(void __iomem *base, u32 flags)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void imx_ocotp_clr_err_if_set(void __iomem *base)
|
static void imx_ocotp_clr_err_if_set(struct ocotp_priv *priv)
|
||||||
{
|
{
|
||||||
u32 c;
|
u32 c, bm_ctrl_error;
|
||||||
|
void __iomem *base = priv->base;
|
||||||
|
|
||||||
|
bm_ctrl_error = priv->params->ctrl.bm_error;
|
||||||
|
|
||||||
c = readl(base + IMX_OCOTP_ADDR_CTRL);
|
c = readl(base + IMX_OCOTP_ADDR_CTRL);
|
||||||
if (!(c & IMX_OCOTP_BM_CTRL_ERROR))
|
if (!(c & bm_ctrl_error))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
writel(IMX_OCOTP_BM_CTRL_ERROR, base + IMX_OCOTP_ADDR_CTRL_CLR);
|
writel(bm_ctrl_error, base + IMX_OCOTP_ADDR_CTRL_CLR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int imx_ocotp_read(void *context, unsigned int offset,
|
static int imx_ocotp_read(void *context, unsigned int offset,
|
||||||
|
@ -140,7 +164,7 @@ static int imx_ocotp_read(void *context, unsigned int offset,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = imx_ocotp_wait_for_busy(priv->base, 0);
|
ret = imx_ocotp_wait_for_busy(priv, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(priv->dev, "timeout during read setup\n");
|
dev_err(priv->dev, "timeout during read setup\n");
|
||||||
goto read_end;
|
goto read_end;
|
||||||
|
@ -157,7 +181,7 @@ static int imx_ocotp_read(void *context, unsigned int offset,
|
||||||
* issued
|
* issued
|
||||||
*/
|
*/
|
||||||
if (*(buf - 1) == IMX_OCOTP_READ_LOCKED_VAL)
|
if (*(buf - 1) == IMX_OCOTP_READ_LOCKED_VAL)
|
||||||
imx_ocotp_clr_err_if_set(priv->base);
|
imx_ocotp_clr_err_if_set(priv);
|
||||||
}
|
}
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
|
@ -274,7 +298,7 @@ static int imx_ocotp_write(void *context, unsigned int offset, void *val,
|
||||||
* write or reload must be completed before a write access can be
|
* write or reload must be completed before a write access can be
|
||||||
* requested.
|
* requested.
|
||||||
*/
|
*/
|
||||||
ret = imx_ocotp_wait_for_busy(priv->base, 0);
|
ret = imx_ocotp_wait_for_busy(priv, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(priv->dev, "timeout during timing setup\n");
|
dev_err(priv->dev, "timeout during timing setup\n");
|
||||||
goto write_end;
|
goto write_end;
|
||||||
|
@ -306,8 +330,8 @@ static int imx_ocotp_write(void *context, unsigned int offset, void *val,
|
||||||
}
|
}
|
||||||
|
|
||||||
ctrl = readl(priv->base + IMX_OCOTP_ADDR_CTRL);
|
ctrl = readl(priv->base + IMX_OCOTP_ADDR_CTRL);
|
||||||
ctrl &= ~IMX_OCOTP_BM_CTRL_ADDR;
|
ctrl &= ~priv->params->ctrl.bm_addr;
|
||||||
ctrl |= waddr & IMX_OCOTP_BM_CTRL_ADDR;
|
ctrl |= waddr & priv->params->ctrl.bm_addr;
|
||||||
ctrl |= IMX_OCOTP_WR_UNLOCK;
|
ctrl |= IMX_OCOTP_WR_UNLOCK;
|
||||||
|
|
||||||
writel(ctrl, priv->base + IMX_OCOTP_ADDR_CTRL);
|
writel(ctrl, priv->base + IMX_OCOTP_ADDR_CTRL);
|
||||||
|
@ -374,11 +398,11 @@ static int imx_ocotp_write(void *context, unsigned int offset, void *val,
|
||||||
* be set. It must be cleared by software before any new write access
|
* be set. It must be cleared by software before any new write access
|
||||||
* can be issued.
|
* can be issued.
|
||||||
*/
|
*/
|
||||||
ret = imx_ocotp_wait_for_busy(priv->base, 0);
|
ret = imx_ocotp_wait_for_busy(priv, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (ret == -EPERM) {
|
if (ret == -EPERM) {
|
||||||
dev_err(priv->dev, "failed write to locked region");
|
dev_err(priv->dev, "failed write to locked region");
|
||||||
imx_ocotp_clr_err_if_set(priv->base);
|
imx_ocotp_clr_err_if_set(priv);
|
||||||
} else {
|
} else {
|
||||||
dev_err(priv->dev, "timeout during data write\n");
|
dev_err(priv->dev, "timeout during data write\n");
|
||||||
}
|
}
|
||||||
|
@ -394,10 +418,10 @@ static int imx_ocotp_write(void *context, unsigned int offset, void *val,
|
||||||
udelay(2);
|
udelay(2);
|
||||||
|
|
||||||
/* reload all shadow registers */
|
/* reload all shadow registers */
|
||||||
writel(IMX_OCOTP_BM_CTRL_REL_SHADOWS,
|
writel(priv->params->ctrl.bm_rel_shadows,
|
||||||
priv->base + IMX_OCOTP_ADDR_CTRL_SET);
|
priv->base + IMX_OCOTP_ADDR_CTRL_SET);
|
||||||
ret = imx_ocotp_wait_for_busy(priv->base,
|
ret = imx_ocotp_wait_for_busy(priv,
|
||||||
IMX_OCOTP_BM_CTRL_REL_SHADOWS);
|
priv->params->ctrl.bm_rel_shadows);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(priv->dev, "timeout during shadow register reload\n");
|
dev_err(priv->dev, "timeout during shadow register reload\n");
|
||||||
goto write_end;
|
goto write_end;
|
||||||
|
@ -424,65 +448,76 @@ static const struct ocotp_params imx6q_params = {
|
||||||
.nregs = 128,
|
.nregs = 128,
|
||||||
.bank_address_words = 0,
|
.bank_address_words = 0,
|
||||||
.set_timing = imx_ocotp_set_imx6_timing,
|
.set_timing = imx_ocotp_set_imx6_timing,
|
||||||
|
.ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct ocotp_params imx6sl_params = {
|
static const struct ocotp_params imx6sl_params = {
|
||||||
.nregs = 64,
|
.nregs = 64,
|
||||||
.bank_address_words = 0,
|
.bank_address_words = 0,
|
||||||
.set_timing = imx_ocotp_set_imx6_timing,
|
.set_timing = imx_ocotp_set_imx6_timing,
|
||||||
|
.ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct ocotp_params imx6sll_params = {
|
static const struct ocotp_params imx6sll_params = {
|
||||||
.nregs = 128,
|
.nregs = 128,
|
||||||
.bank_address_words = 0,
|
.bank_address_words = 0,
|
||||||
.set_timing = imx_ocotp_set_imx6_timing,
|
.set_timing = imx_ocotp_set_imx6_timing,
|
||||||
|
.ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct ocotp_params imx6sx_params = {
|
static const struct ocotp_params imx6sx_params = {
|
||||||
.nregs = 128,
|
.nregs = 128,
|
||||||
.bank_address_words = 0,
|
.bank_address_words = 0,
|
||||||
.set_timing = imx_ocotp_set_imx6_timing,
|
.set_timing = imx_ocotp_set_imx6_timing,
|
||||||
|
.ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct ocotp_params imx6ul_params = {
|
static const struct ocotp_params imx6ul_params = {
|
||||||
.nregs = 128,
|
.nregs = 128,
|
||||||
.bank_address_words = 0,
|
.bank_address_words = 0,
|
||||||
.set_timing = imx_ocotp_set_imx6_timing,
|
.set_timing = imx_ocotp_set_imx6_timing,
|
||||||
|
.ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct ocotp_params imx6ull_params = {
|
static const struct ocotp_params imx6ull_params = {
|
||||||
.nregs = 64,
|
.nregs = 64,
|
||||||
.bank_address_words = 0,
|
.bank_address_words = 0,
|
||||||
.set_timing = imx_ocotp_set_imx6_timing,
|
.set_timing = imx_ocotp_set_imx6_timing,
|
||||||
|
.ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct ocotp_params imx7d_params = {
|
static const struct ocotp_params imx7d_params = {
|
||||||
.nregs = 64,
|
.nregs = 64,
|
||||||
.bank_address_words = 4,
|
.bank_address_words = 4,
|
||||||
.set_timing = imx_ocotp_set_imx7_timing,
|
.set_timing = imx_ocotp_set_imx7_timing,
|
||||||
|
.ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct ocotp_params imx7ulp_params = {
|
static const struct ocotp_params imx7ulp_params = {
|
||||||
.nregs = 256,
|
.nregs = 256,
|
||||||
.bank_address_words = 0,
|
.bank_address_words = 0,
|
||||||
|
.ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct ocotp_params imx8mq_params = {
|
static const struct ocotp_params imx8mq_params = {
|
||||||
.nregs = 256,
|
.nregs = 256,
|
||||||
.bank_address_words = 0,
|
.bank_address_words = 0,
|
||||||
.set_timing = imx_ocotp_set_imx6_timing,
|
.set_timing = imx_ocotp_set_imx6_timing,
|
||||||
|
.ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct ocotp_params imx8mm_params = {
|
static const struct ocotp_params imx8mm_params = {
|
||||||
.nregs = 256,
|
.nregs = 256,
|
||||||
.bank_address_words = 0,
|
.bank_address_words = 0,
|
||||||
.set_timing = imx_ocotp_set_imx6_timing,
|
.set_timing = imx_ocotp_set_imx6_timing,
|
||||||
|
.ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct ocotp_params imx8mn_params = {
|
static const struct ocotp_params imx8mn_params = {
|
||||||
.nregs = 256,
|
.nregs = 256,
|
||||||
.bank_address_words = 0,
|
.bank_address_words = 0,
|
||||||
.set_timing = imx_ocotp_set_imx6_timing,
|
.set_timing = imx_ocotp_set_imx6_timing,
|
||||||
|
.ctrl = IMX_OCOTP_BM_CTRL_DEFAULT,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id imx_ocotp_dt_ids[] = {
|
static const struct of_device_id imx_ocotp_dt_ids[] = {
|
||||||
|
@ -521,17 +556,17 @@ static int imx_ocotp_probe(struct platform_device *pdev)
|
||||||
if (IS_ERR(priv->clk))
|
if (IS_ERR(priv->clk))
|
||||||
return PTR_ERR(priv->clk);
|
return PTR_ERR(priv->clk);
|
||||||
|
|
||||||
clk_prepare_enable(priv->clk);
|
|
||||||
imx_ocotp_clr_err_if_set(priv->base);
|
|
||||||
clk_disable_unprepare(priv->clk);
|
|
||||||
|
|
||||||
priv->params = of_device_get_match_data(&pdev->dev);
|
priv->params = of_device_get_match_data(&pdev->dev);
|
||||||
imx_ocotp_nvmem_config.size = 4 * priv->params->nregs;
|
imx_ocotp_nvmem_config.size = 4 * priv->params->nregs;
|
||||||
imx_ocotp_nvmem_config.dev = dev;
|
imx_ocotp_nvmem_config.dev = dev;
|
||||||
imx_ocotp_nvmem_config.priv = priv;
|
imx_ocotp_nvmem_config.priv = priv;
|
||||||
priv->config = &imx_ocotp_nvmem_config;
|
priv->config = &imx_ocotp_nvmem_config;
|
||||||
nvmem = devm_nvmem_register(dev, &imx_ocotp_nvmem_config);
|
|
||||||
|
|
||||||
|
clk_prepare_enable(priv->clk);
|
||||||
|
imx_ocotp_clr_err_if_set(priv);
|
||||||
|
clk_disable_unprepare(priv->clk);
|
||||||
|
|
||||||
|
nvmem = devm_nvmem_register(dev, &imx_ocotp_nvmem_config);
|
||||||
|
|
||||||
return PTR_ERR_OR_ZERO(nvmem);
|
return PTR_ERR_OR_ZERO(nvmem);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 The Linux Foundation. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
|
#include <linux/nvmem-provider.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
|
||||||
|
#define SDAM_MEM_START 0x40
|
||||||
|
#define REGISTER_MAP_ID 0x40
|
||||||
|
#define REGISTER_MAP_VERSION 0x41
|
||||||
|
#define SDAM_SIZE 0x44
|
||||||
|
#define SDAM_PBS_TRIG_SET 0xE5
|
||||||
|
#define SDAM_PBS_TRIG_CLR 0xE6
|
||||||
|
|
||||||
|
struct sdam_chip {
|
||||||
|
struct platform_device *pdev;
|
||||||
|
struct regmap *regmap;
|
||||||
|
struct nvmem_config sdam_config;
|
||||||
|
unsigned int base;
|
||||||
|
unsigned int size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* read only register offsets */
|
||||||
|
static const u8 sdam_ro_map[] = {
|
||||||
|
REGISTER_MAP_ID,
|
||||||
|
REGISTER_MAP_VERSION,
|
||||||
|
SDAM_SIZE
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool sdam_is_valid(struct sdam_chip *sdam, unsigned int offset,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
unsigned int sdam_mem_end = SDAM_MEM_START + sdam->size - 1;
|
||||||
|
|
||||||
|
if (!len)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (offset >= SDAM_MEM_START && offset <= sdam_mem_end
|
||||||
|
&& (offset + len - 1) <= sdam_mem_end)
|
||||||
|
return true;
|
||||||
|
else if ((offset == SDAM_PBS_TRIG_SET || offset == SDAM_PBS_TRIG_CLR)
|
||||||
|
&& (len == 1))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool sdam_is_ro(unsigned int offset, size_t len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(sdam_ro_map); i++)
|
||||||
|
if (offset <= sdam_ro_map[i] && (offset + len) > sdam_ro_map[i])
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdam_read(void *priv, unsigned int offset, void *val,
|
||||||
|
size_t bytes)
|
||||||
|
{
|
||||||
|
struct sdam_chip *sdam = priv;
|
||||||
|
struct device *dev = &sdam->pdev->dev;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!sdam_is_valid(sdam, offset, bytes)) {
|
||||||
|
dev_err(dev, "Invalid SDAM offset %#x len=%zd\n",
|
||||||
|
offset, bytes);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = regmap_bulk_read(sdam->regmap, sdam->base + offset, val, bytes);
|
||||||
|
if (rc < 0)
|
||||||
|
dev_err(dev, "Failed to read SDAM offset %#x len=%zd, rc=%d\n",
|
||||||
|
offset, bytes, rc);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdam_write(void *priv, unsigned int offset, void *val,
|
||||||
|
size_t bytes)
|
||||||
|
{
|
||||||
|
struct sdam_chip *sdam = priv;
|
||||||
|
struct device *dev = &sdam->pdev->dev;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!sdam_is_valid(sdam, offset, bytes)) {
|
||||||
|
dev_err(dev, "Invalid SDAM offset %#x len=%zd\n",
|
||||||
|
offset, bytes);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sdam_is_ro(offset, bytes)) {
|
||||||
|
dev_err(dev, "Invalid write offset %#x len=%zd\n",
|
||||||
|
offset, bytes);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = regmap_bulk_write(sdam->regmap, sdam->base + offset, val, bytes);
|
||||||
|
if (rc < 0)
|
||||||
|
dev_err(dev, "Failed to write SDAM offset %#x len=%zd, rc=%d\n",
|
||||||
|
offset, bytes, rc);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdam_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct sdam_chip *sdam;
|
||||||
|
struct nvmem_device *nvmem;
|
||||||
|
unsigned int val;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
sdam = devm_kzalloc(&pdev->dev, sizeof(*sdam), GFP_KERNEL);
|
||||||
|
if (!sdam)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
sdam->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||||
|
if (!sdam->regmap) {
|
||||||
|
dev_err(&pdev->dev, "Failed to get regmap handle\n");
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = of_property_read_u32(pdev->dev.of_node, "reg", &sdam->base);
|
||||||
|
if (rc < 0) {
|
||||||
|
dev_err(&pdev->dev, "Failed to get SDAM base, rc=%d\n", rc);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = regmap_read(sdam->regmap, sdam->base + SDAM_SIZE, &val);
|
||||||
|
if (rc < 0) {
|
||||||
|
dev_err(&pdev->dev, "Failed to read SDAM_SIZE rc=%d\n", rc);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
sdam->size = val * 32;
|
||||||
|
|
||||||
|
sdam->sdam_config.dev = &pdev->dev;
|
||||||
|
sdam->sdam_config.name = "spmi_sdam";
|
||||||
|
sdam->sdam_config.id = pdev->id;
|
||||||
|
sdam->sdam_config.owner = THIS_MODULE,
|
||||||
|
sdam->sdam_config.stride = 1;
|
||||||
|
sdam->sdam_config.word_size = 1;
|
||||||
|
sdam->sdam_config.reg_read = sdam_read;
|
||||||
|
sdam->sdam_config.reg_write = sdam_write;
|
||||||
|
sdam->sdam_config.priv = sdam;
|
||||||
|
|
||||||
|
nvmem = devm_nvmem_register(&pdev->dev, &sdam->sdam_config);
|
||||||
|
if (IS_ERR(nvmem)) {
|
||||||
|
dev_err(&pdev->dev,
|
||||||
|
"Failed to register SDAM nvmem device rc=%ld\n",
|
||||||
|
PTR_ERR(nvmem));
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
dev_dbg(&pdev->dev,
|
||||||
|
"SDAM base=%#x size=%u registered successfully\n",
|
||||||
|
sdam->base, sdam->size);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id sdam_match_table[] = {
|
||||||
|
{ .compatible = "qcom,spmi-sdam" },
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_driver sdam_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "qcom,spmi-sdam",
|
||||||
|
.of_match_table = sdam_match_table,
|
||||||
|
},
|
||||||
|
.probe = sdam_probe,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init sdam_init(void)
|
||||||
|
{
|
||||||
|
return platform_driver_register(&sdam_driver);
|
||||||
|
}
|
||||||
|
subsys_initcall(sdam_init);
|
||||||
|
|
||||||
|
static void __exit sdam_exit(void)
|
||||||
|
{
|
||||||
|
return platform_driver_unregister(&sdam_driver);
|
||||||
|
}
|
||||||
|
module_exit(sdam_exit);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("QCOM SPMI SDAM driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015-2017 Pengutronix, Uwe Kleine-König <kernel@pengutronix.de>
|
* Copyright (C) 2015-2017 Pengutronix, Uwe Kleine-König <kernel@pengutronix.de>
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -641,6 +641,8 @@ static int qcom_slim_remove(struct platform_device *pdev)
|
||||||
|
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
slim_unregister_controller(&ctrl->ctrl);
|
slim_unregister_controller(&ctrl->ctrl);
|
||||||
|
clk_disable_unprepare(ctrl->rclk);
|
||||||
|
clk_disable_unprepare(ctrl->hclk);
|
||||||
destroy_workqueue(ctrl->rxwq);
|
destroy_workqueue(ctrl->rxwq);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -666,10 +666,12 @@ static int qcom_slim_ngd_init_rx_msgq(struct qcom_slim_ngd_ctrl *ctrl)
|
||||||
struct device *dev = ctrl->dev;
|
struct device *dev = ctrl->dev;
|
||||||
int ret, size;
|
int ret, size;
|
||||||
|
|
||||||
ctrl->dma_rx_channel = dma_request_slave_channel(dev, "rx");
|
ctrl->dma_rx_channel = dma_request_chan(dev, "rx");
|
||||||
if (!ctrl->dma_rx_channel) {
|
if (IS_ERR(ctrl->dma_rx_channel)) {
|
||||||
dev_err(dev, "Failed to request dma channels");
|
dev_err(dev, "Failed to request RX dma channel");
|
||||||
return -EINVAL;
|
ret = PTR_ERR(ctrl->dma_rx_channel);
|
||||||
|
ctrl->dma_rx_channel = NULL;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = QCOM_SLIM_NGD_DESC_NUM * SLIM_MSGQ_BUF_LEN;
|
size = QCOM_SLIM_NGD_DESC_NUM * SLIM_MSGQ_BUF_LEN;
|
||||||
|
@ -703,10 +705,12 @@ static int qcom_slim_ngd_init_tx_msgq(struct qcom_slim_ngd_ctrl *ctrl)
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
ctrl->dma_tx_channel = dma_request_slave_channel(dev, "tx");
|
ctrl->dma_tx_channel = dma_request_chan(dev, "tx");
|
||||||
if (!ctrl->dma_tx_channel) {
|
if (IS_ERR(ctrl->dma_tx_channel)) {
|
||||||
dev_err(dev, "Failed to request dma channels");
|
dev_err(dev, "Failed to request TX dma channel");
|
||||||
return -EINVAL;
|
ret = PTR_ERR(ctrl->dma_tx_channel);
|
||||||
|
ctrl->dma_tx_channel = NULL;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = ((QCOM_SLIM_NGD_DESC_NUM + 1) * SLIM_MSGQ_BUF_LEN);
|
size = ((QCOM_SLIM_NGD_DESC_NUM + 1) * SLIM_MSGQ_BUF_LEN);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011-2017, The Linux Foundation
|
* Copyright (c) 2011-2017, The Linux Foundation
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -31,4 +31,13 @@ config SOUNDWIRE_INTEL
|
||||||
enable this config option to get the SoundWire support for that
|
enable this config option to get the SoundWire support for that
|
||||||
device.
|
device.
|
||||||
|
|
||||||
|
config SOUNDWIRE_QCOM
|
||||||
|
tristate "Qualcomm SoundWire Master driver"
|
||||||
|
depends on SLIMBUS
|
||||||
|
depends on SND_SOC
|
||||||
|
help
|
||||||
|
SoundWire Qualcomm Master driver.
|
||||||
|
If you have an Qualcomm platform which has a SoundWire Master then
|
||||||
|
enable this config option to get the SoundWire support for that
|
||||||
|
device
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -21,3 +21,7 @@ obj-$(CONFIG_SOUNDWIRE_INTEL) += soundwire-intel.o
|
||||||
|
|
||||||
soundwire-intel-init-objs := intel_init.o
|
soundwire-intel-init-objs := intel_init.o
|
||||||
obj-$(CONFIG_SOUNDWIRE_INTEL) += soundwire-intel-init.o
|
obj-$(CONFIG_SOUNDWIRE_INTEL) += soundwire-intel-init.o
|
||||||
|
|
||||||
|
#Qualcomm driver
|
||||||
|
soundwire-qcom-objs := qcom.o
|
||||||
|
obj-$(CONFIG_SOUNDWIRE_QCOM) += soundwire-qcom.o
|
||||||
|
|
|
@ -456,26 +456,35 @@ err:
|
||||||
static int sdw_assign_device_num(struct sdw_slave *slave)
|
static int sdw_assign_device_num(struct sdw_slave *slave)
|
||||||
{
|
{
|
||||||
int ret, dev_num;
|
int ret, dev_num;
|
||||||
|
bool new_device = false;
|
||||||
|
|
||||||
/* check first if device number is assigned, if so reuse that */
|
/* check first if device number is assigned, if so reuse that */
|
||||||
if (!slave->dev_num) {
|
if (!slave->dev_num) {
|
||||||
mutex_lock(&slave->bus->bus_lock);
|
if (!slave->dev_num_sticky) {
|
||||||
dev_num = sdw_get_device_num(slave);
|
mutex_lock(&slave->bus->bus_lock);
|
||||||
mutex_unlock(&slave->bus->bus_lock);
|
dev_num = sdw_get_device_num(slave);
|
||||||
if (dev_num < 0) {
|
mutex_unlock(&slave->bus->bus_lock);
|
||||||
dev_err(slave->bus->dev, "Get dev_num failed: %d\n",
|
if (dev_num < 0) {
|
||||||
dev_num);
|
dev_err(slave->bus->dev, "Get dev_num failed: %d\n",
|
||||||
return dev_num;
|
dev_num);
|
||||||
|
return dev_num;
|
||||||
|
}
|
||||||
|
slave->dev_num = dev_num;
|
||||||
|
slave->dev_num_sticky = dev_num;
|
||||||
|
new_device = true;
|
||||||
|
} else {
|
||||||
|
slave->dev_num = slave->dev_num_sticky;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
if (!new_device)
|
||||||
dev_info(slave->bus->dev,
|
dev_info(slave->bus->dev,
|
||||||
"Slave already registered dev_num:%d\n",
|
"Slave already registered, reusing dev_num:%d\n",
|
||||||
slave->dev_num);
|
slave->dev_num);
|
||||||
|
|
||||||
/* Clear the slave->dev_num to transfer message on device 0 */
|
/* Clear the slave->dev_num to transfer message on device 0 */
|
||||||
dev_num = slave->dev_num;
|
dev_num = slave->dev_num;
|
||||||
slave->dev_num = 0;
|
slave->dev_num = 0;
|
||||||
}
|
|
||||||
|
|
||||||
ret = sdw_write(slave, SDW_SCP_DEVNUMBER, dev_num);
|
ret = sdw_write(slave, SDW_SCP_DEVNUMBER, dev_num);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -485,7 +494,7 @@ static int sdw_assign_device_num(struct sdw_slave *slave)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* After xfer of msg, restore dev_num */
|
/* After xfer of msg, restore dev_num */
|
||||||
slave->dev_num = dev_num;
|
slave->dev_num = slave->dev_num_sticky;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -979,6 +988,24 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
|
||||||
struct sdw_slave *slave;
|
struct sdw_slave *slave;
|
||||||
int i, ret = 0;
|
int i, ret = 0;
|
||||||
|
|
||||||
|
/* first check if any Slaves fell off the bus */
|
||||||
|
for (i = 1; i <= SDW_MAX_DEVICES; i++) {
|
||||||
|
mutex_lock(&bus->bus_lock);
|
||||||
|
if (test_bit(i, bus->assigned) == false) {
|
||||||
|
mutex_unlock(&bus->bus_lock);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
mutex_unlock(&bus->bus_lock);
|
||||||
|
|
||||||
|
slave = sdw_get_slave(bus, i);
|
||||||
|
if (!slave)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (status[i] == SDW_SLAVE_UNATTACHED &&
|
||||||
|
slave->status != SDW_SLAVE_UNATTACHED)
|
||||||
|
sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED);
|
||||||
|
}
|
||||||
|
|
||||||
if (status[0] == SDW_SLAVE_ATTACHED) {
|
if (status[0] == SDW_SLAVE_ATTACHED) {
|
||||||
dev_dbg(bus->dev, "Slave attached, programming device number\n");
|
dev_dbg(bus->dev, "Slave attached, programming device number\n");
|
||||||
ret = sdw_program_device_num(bus);
|
ret = sdw_program_device_num(bus);
|
||||||
|
|
|
@ -74,6 +74,7 @@ MODULE_PARM_DESC(cdns_mcp_int_mask, "Cadence MCP IntMask");
|
||||||
#define CDNS_MCP_INTMASK 0x48
|
#define CDNS_MCP_INTMASK 0x48
|
||||||
|
|
||||||
#define CDNS_MCP_INT_IRQ BIT(31)
|
#define CDNS_MCP_INT_IRQ BIT(31)
|
||||||
|
#define CDNS_MCP_INT_RESERVED1 GENMASK(30, 17)
|
||||||
#define CDNS_MCP_INT_WAKEUP BIT(16)
|
#define CDNS_MCP_INT_WAKEUP BIT(16)
|
||||||
#define CDNS_MCP_INT_SLAVE_RSVD BIT(15)
|
#define CDNS_MCP_INT_SLAVE_RSVD BIT(15)
|
||||||
#define CDNS_MCP_INT_SLAVE_ALERT BIT(14)
|
#define CDNS_MCP_INT_SLAVE_ALERT BIT(14)
|
||||||
|
@ -85,10 +86,12 @@ MODULE_PARM_DESC(cdns_mcp_int_mask, "Cadence MCP IntMask");
|
||||||
#define CDNS_MCP_INT_DATA_CLASH BIT(9)
|
#define CDNS_MCP_INT_DATA_CLASH BIT(9)
|
||||||
#define CDNS_MCP_INT_PARITY BIT(8)
|
#define CDNS_MCP_INT_PARITY BIT(8)
|
||||||
#define CDNS_MCP_INT_CMD_ERR BIT(7)
|
#define CDNS_MCP_INT_CMD_ERR BIT(7)
|
||||||
|
#define CDNS_MCP_INT_RESERVED2 GENMASK(6, 4)
|
||||||
#define CDNS_MCP_INT_RX_NE BIT(3)
|
#define CDNS_MCP_INT_RX_NE BIT(3)
|
||||||
#define CDNS_MCP_INT_RX_WL BIT(2)
|
#define CDNS_MCP_INT_RX_WL BIT(2)
|
||||||
#define CDNS_MCP_INT_TXE BIT(1)
|
#define CDNS_MCP_INT_TXE BIT(1)
|
||||||
#define CDNS_MCP_INT_TXF BIT(0)
|
#define CDNS_MCP_INT_TXF BIT(0)
|
||||||
|
#define CDNS_MCP_INT_RESERVED (CDNS_MCP_INT_RESERVED1 | CDNS_MCP_INT_RESERVED2)
|
||||||
|
|
||||||
#define CDNS_MCP_INTSET 0x4C
|
#define CDNS_MCP_INTSET 0x4C
|
||||||
|
|
||||||
|
@ -444,7 +447,8 @@ _cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd,
|
||||||
time = wait_for_completion_timeout(&cdns->tx_complete,
|
time = wait_for_completion_timeout(&cdns->tx_complete,
|
||||||
msecs_to_jiffies(CDNS_TX_TIMEOUT));
|
msecs_to_jiffies(CDNS_TX_TIMEOUT));
|
||||||
if (!time) {
|
if (!time) {
|
||||||
dev_err(cdns->dev, "IO transfer timed out\n");
|
dev_err(cdns->dev, "IO transfer timed out, cmd %d device %d addr %x len %d\n",
|
||||||
|
cmd, msg->dev_num, msg->addr, msg->len);
|
||||||
msg->len = 0;
|
msg->len = 0;
|
||||||
return SDW_CMD_TIMEOUT;
|
return SDW_CMD_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
@ -672,13 +676,36 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns,
|
||||||
|
|
||||||
/* first check if Slave reported multiple status */
|
/* first check if Slave reported multiple status */
|
||||||
if (set_status > 1) {
|
if (set_status > 1) {
|
||||||
|
u32 val;
|
||||||
|
|
||||||
dev_warn_ratelimited(cdns->dev,
|
dev_warn_ratelimited(cdns->dev,
|
||||||
"Slave reported multiple Status: %d\n",
|
"Slave %d reported multiple Status: %d\n",
|
||||||
mask);
|
i, mask);
|
||||||
/*
|
|
||||||
* TODO: we need to reread the status here by
|
/* check latest status extracted from PING commands */
|
||||||
* issuing a PING cmd
|
val = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);
|
||||||
*/
|
val >>= (i * 2);
|
||||||
|
|
||||||
|
switch (val & 0x3) {
|
||||||
|
case 0:
|
||||||
|
status[i] = SDW_SLAVE_UNATTACHED;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
status[i] = SDW_SLAVE_ATTACHED;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
status[i] = SDW_SLAVE_ALERT;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
default:
|
||||||
|
status[i] = SDW_SLAVE_RESERVED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_warn_ratelimited(cdns->dev,
|
||||||
|
"Slave %d status updated to %d\n",
|
||||||
|
i, status[i]);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -705,6 +732,10 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id)
|
||||||
|
|
||||||
int_status = cdns_readl(cdns, CDNS_MCP_INTSTAT);
|
int_status = cdns_readl(cdns, CDNS_MCP_INTSTAT);
|
||||||
|
|
||||||
|
/* check for reserved values read as zero */
|
||||||
|
if (int_status & CDNS_MCP_INT_RESERVED)
|
||||||
|
return IRQ_NONE;
|
||||||
|
|
||||||
if (!(int_status & CDNS_MCP_INT_IRQ))
|
if (!(int_status & CDNS_MCP_INT_IRQ))
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
|
||||||
|
@ -812,8 +843,9 @@ int sdw_cdns_exit_reset(struct sdw_cdns *cdns)
|
||||||
EXPORT_SYMBOL(sdw_cdns_exit_reset);
|
EXPORT_SYMBOL(sdw_cdns_exit_reset);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config
|
* sdw_cdns_enable_interrupt() - Enable SDW interrupts
|
||||||
* @cdns: Cadence instance
|
* @cdns: Cadence instance
|
||||||
|
* @state: True if we are trying to enable interrupt.
|
||||||
*/
|
*/
|
||||||
int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state)
|
int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state)
|
||||||
{
|
{
|
||||||
|
@ -849,12 +881,21 @@ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state)
|
||||||
mask = interrupt_mask;
|
mask = interrupt_mask;
|
||||||
|
|
||||||
update_masks:
|
update_masks:
|
||||||
|
/* clear slave interrupt status before enabling interrupt */
|
||||||
|
if (state) {
|
||||||
|
u32 slave_state;
|
||||||
|
|
||||||
|
slave_state = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT0);
|
||||||
|
cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT0, slave_state);
|
||||||
|
slave_state = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT1);
|
||||||
|
cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT1, slave_state);
|
||||||
|
}
|
||||||
|
|
||||||
cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK0, slave_intmask0);
|
cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK0, slave_intmask0);
|
||||||
cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1, slave_intmask1);
|
cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1, slave_intmask1);
|
||||||
cdns_writel(cdns, CDNS_MCP_INTMASK, mask);
|
cdns_writel(cdns, CDNS_MCP_INTMASK, mask);
|
||||||
|
|
||||||
/* commit changes */
|
return 0;
|
||||||
return cdns_update_config(cdns);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sdw_cdns_enable_interrupt);
|
EXPORT_SYMBOL(sdw_cdns_enable_interrupt);
|
||||||
|
|
||||||
|
@ -948,8 +989,6 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
|
||||||
ret = cdns_allocate_pdi(cdns, &stream->out,
|
ret = cdns_allocate_pdi(cdns, &stream->out,
|
||||||
stream->num_out, offset);
|
stream->num_out, offset);
|
||||||
|
|
||||||
offset += stream->num_out;
|
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -1224,8 +1263,10 @@ EXPORT_SYMBOL(cdns_set_sdw_stream);
|
||||||
* cdns_find_pdi() - Find a free PDI
|
* cdns_find_pdi() - Find a free PDI
|
||||||
*
|
*
|
||||||
* @cdns: Cadence instance
|
* @cdns: Cadence instance
|
||||||
|
* @offset: Starting offset
|
||||||
* @num: Number of PDIs
|
* @num: Number of PDIs
|
||||||
* @pdi: PDI instances
|
* @pdi: PDI instances
|
||||||
|
* @dai_id: DAI id
|
||||||
*
|
*
|
||||||
* Find a PDI for a given PDI array. The PDI num and dai_id are
|
* Find a PDI for a given PDI array. The PDI num and dai_id are
|
||||||
* expected to match, return NULL otherwise.
|
* expected to match, return NULL otherwise.
|
||||||
|
@ -1277,6 +1318,7 @@ EXPORT_SYMBOL(sdw_cdns_config_stream);
|
||||||
* @stream: Stream to be allocated
|
* @stream: Stream to be allocated
|
||||||
* @ch: Channel count
|
* @ch: Channel count
|
||||||
* @dir: Data direction
|
* @dir: Data direction
|
||||||
|
* @dai_id: DAI id
|
||||||
*/
|
*/
|
||||||
struct sdw_cdns_pdi *sdw_cdns_alloc_pdi(struct sdw_cdns *cdns,
|
struct sdw_cdns_pdi *sdw_cdns_alloc_pdi(struct sdw_cdns *cdns,
|
||||||
struct sdw_cdns_streams *stream,
|
struct sdw_cdns_streams *stream,
|
||||||
|
|
|
@ -880,6 +880,9 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus)
|
||||||
"intel-sdw-ip-clock",
|
"intel-sdw-ip-clock",
|
||||||
&prop->mclk_freq);
|
&prop->mclk_freq);
|
||||||
|
|
||||||
|
/* the values reported by BIOS are the 2x clock, not the bus clock */
|
||||||
|
prop->mclk_freq /= 2;
|
||||||
|
|
||||||
fwnode_property_read_u32(link,
|
fwnode_property_read_u32(link,
|
||||||
"intel-quirk-mask",
|
"intel-quirk-mask",
|
||||||
&quirk_mask);
|
&quirk_mask);
|
||||||
|
|
|
@ -0,0 +1,861 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
// Copyright (c) 2019, Linaro Limited
|
||||||
|
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/completion.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_irq.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/slimbus.h>
|
||||||
|
#include <linux/soundwire/sdw.h>
|
||||||
|
#include <linux/soundwire/sdw_registers.h>
|
||||||
|
#include <sound/pcm_params.h>
|
||||||
|
#include <sound/soc.h>
|
||||||
|
#include "bus.h"
|
||||||
|
|
||||||
|
#define SWRM_COMP_HW_VERSION 0x00
|
||||||
|
#define SWRM_COMP_CFG_ADDR 0x04
|
||||||
|
#define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK BIT(1)
|
||||||
|
#define SWRM_COMP_CFG_ENABLE_MSK BIT(0)
|
||||||
|
#define SWRM_COMP_PARAMS 0x100
|
||||||
|
#define SWRM_COMP_PARAMS_DOUT_PORTS_MASK GENMASK(4, 0)
|
||||||
|
#define SWRM_COMP_PARAMS_DIN_PORTS_MASK GENMASK(9, 5)
|
||||||
|
#define SWRM_INTERRUPT_STATUS 0x200
|
||||||
|
#define SWRM_INTERRUPT_STATUS_RMSK GENMASK(16, 0)
|
||||||
|
#define SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED BIT(1)
|
||||||
|
#define SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS BIT(2)
|
||||||
|
#define SWRM_INTERRUPT_STATUS_CMD_ERROR BIT(7)
|
||||||
|
#define SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED BIT(10)
|
||||||
|
#define SWRM_INTERRUPT_MASK_ADDR 0x204
|
||||||
|
#define SWRM_INTERRUPT_CLEAR 0x208
|
||||||
|
#define SWRM_CMD_FIFO_WR_CMD 0x300
|
||||||
|
#define SWRM_CMD_FIFO_RD_CMD 0x304
|
||||||
|
#define SWRM_CMD_FIFO_CMD 0x308
|
||||||
|
#define SWRM_CMD_FIFO_STATUS 0x30C
|
||||||
|
#define SWRM_CMD_FIFO_CFG_ADDR 0x314
|
||||||
|
#define SWRM_RD_WR_CMD_RETRIES 0x7
|
||||||
|
#define SWRM_CMD_FIFO_RD_FIFO_ADDR 0x318
|
||||||
|
#define SWRM_ENUMERATOR_CFG_ADDR 0x500
|
||||||
|
#define SWRM_MCP_FRAME_CTRL_BANK_ADDR(m) (0x101C + 0x40 * (m))
|
||||||
|
#define SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT 3
|
||||||
|
#define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK GENMASK(2, 0)
|
||||||
|
#define SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK GENMASK(7, 3)
|
||||||
|
#define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT 0
|
||||||
|
#define SWRM_MCP_CFG_ADDR 0x1048
|
||||||
|
#define SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK GENMASK(21, 17)
|
||||||
|
#define SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_SHFT 0x11
|
||||||
|
#define SWRM_DEF_CMD_NO_PINGS 0x1f
|
||||||
|
#define SWRM_MCP_STATUS 0x104C
|
||||||
|
#define SWRM_MCP_STATUS_BANK_NUM_MASK BIT(0)
|
||||||
|
#define SWRM_MCP_SLV_STATUS 0x1090
|
||||||
|
#define SWRM_MCP_SLV_STATUS_MASK GENMASK(1, 0)
|
||||||
|
#define SWRM_DP_PORT_CTRL_BANK(n, m) (0x1124 + 0x100 * (n - 1) + 0x40 * m)
|
||||||
|
#define SWRM_DP_PORT_CTRL_EN_CHAN_SHFT 0x18
|
||||||
|
#define SWRM_DP_PORT_CTRL_OFFSET2_SHFT 0x10
|
||||||
|
#define SWRM_DP_PORT_CTRL_OFFSET1_SHFT 0x08
|
||||||
|
#define SWRM_AHB_BRIDGE_WR_DATA_0 0xc85
|
||||||
|
#define SWRM_AHB_BRIDGE_WR_ADDR_0 0xc89
|
||||||
|
#define SWRM_AHB_BRIDGE_RD_ADDR_0 0xc8d
|
||||||
|
#define SWRM_AHB_BRIDGE_RD_DATA_0 0xc91
|
||||||
|
|
||||||
|
#define SWRM_REG_VAL_PACK(data, dev, id, reg) \
|
||||||
|
((reg) | ((id) << 16) | ((dev) << 20) | ((data) << 24))
|
||||||
|
|
||||||
|
#define SWRM_MAX_ROW_VAL 0 /* Rows = 48 */
|
||||||
|
#define SWRM_DEFAULT_ROWS 48
|
||||||
|
#define SWRM_MIN_COL_VAL 0 /* Cols = 2 */
|
||||||
|
#define SWRM_DEFAULT_COL 16
|
||||||
|
#define SWRM_MAX_COL_VAL 7
|
||||||
|
#define SWRM_SPECIAL_CMD_ID 0xF
|
||||||
|
#define MAX_FREQ_NUM 1
|
||||||
|
#define TIMEOUT_MS (2 * HZ)
|
||||||
|
#define QCOM_SWRM_MAX_RD_LEN 0xf
|
||||||
|
#define QCOM_SDW_MAX_PORTS 14
|
||||||
|
#define DEFAULT_CLK_FREQ 9600000
|
||||||
|
#define SWRM_MAX_DAIS 0xF
|
||||||
|
|
||||||
|
struct qcom_swrm_port_config {
|
||||||
|
u8 si;
|
||||||
|
u8 off1;
|
||||||
|
u8 off2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct qcom_swrm_ctrl {
|
||||||
|
struct sdw_bus bus;
|
||||||
|
struct device *dev;
|
||||||
|
struct regmap *regmap;
|
||||||
|
struct completion *comp;
|
||||||
|
struct work_struct slave_work;
|
||||||
|
/* read/write lock */
|
||||||
|
spinlock_t comp_lock;
|
||||||
|
/* Port alloc/free lock */
|
||||||
|
struct mutex port_lock;
|
||||||
|
struct clk *hclk;
|
||||||
|
u8 wr_cmd_id;
|
||||||
|
u8 rd_cmd_id;
|
||||||
|
int irq;
|
||||||
|
unsigned int version;
|
||||||
|
int num_din_ports;
|
||||||
|
int num_dout_ports;
|
||||||
|
unsigned long dout_port_mask;
|
||||||
|
unsigned long din_port_mask;
|
||||||
|
struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS];
|
||||||
|
struct sdw_stream_runtime *sruntime[SWRM_MAX_DAIS];
|
||||||
|
enum sdw_slave_status status[SDW_MAX_DEVICES];
|
||||||
|
int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val);
|
||||||
|
int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val);
|
||||||
|
};
|
||||||
|
|
||||||
|
#define to_qcom_sdw(b) container_of(b, struct qcom_swrm_ctrl, bus)
|
||||||
|
|
||||||
|
static int qcom_swrm_abh_reg_read(struct qcom_swrm_ctrl *ctrl, int reg,
|
||||||
|
u32 *val)
|
||||||
|
{
|
||||||
|
struct regmap *wcd_regmap = ctrl->regmap;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* pg register + offset */
|
||||||
|
ret = regmap_bulk_write(wcd_regmap, SWRM_AHB_BRIDGE_RD_ADDR_0,
|
||||||
|
(u8 *)®, 4);
|
||||||
|
if (ret < 0)
|
||||||
|
return SDW_CMD_FAIL;
|
||||||
|
|
||||||
|
ret = regmap_bulk_read(wcd_regmap, SWRM_AHB_BRIDGE_RD_DATA_0,
|
||||||
|
val, 4);
|
||||||
|
if (ret < 0)
|
||||||
|
return SDW_CMD_FAIL;
|
||||||
|
|
||||||
|
return SDW_CMD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_swrm_ahb_reg_write(struct qcom_swrm_ctrl *ctrl,
|
||||||
|
int reg, int val)
|
||||||
|
{
|
||||||
|
struct regmap *wcd_regmap = ctrl->regmap;
|
||||||
|
int ret;
|
||||||
|
/* pg register + offset */
|
||||||
|
ret = regmap_bulk_write(wcd_regmap, SWRM_AHB_BRIDGE_WR_DATA_0,
|
||||||
|
(u8 *)&val, 4);
|
||||||
|
if (ret)
|
||||||
|
return SDW_CMD_FAIL;
|
||||||
|
|
||||||
|
/* write address register */
|
||||||
|
ret = regmap_bulk_write(wcd_regmap, SWRM_AHB_BRIDGE_WR_ADDR_0,
|
||||||
|
(u8 *)®, 4);
|
||||||
|
if (ret)
|
||||||
|
return SDW_CMD_FAIL;
|
||||||
|
|
||||||
|
return SDW_CMD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *ctrl, u8 cmd_data,
|
||||||
|
u8 dev_addr, u16 reg_addr)
|
||||||
|
{
|
||||||
|
DECLARE_COMPLETION_ONSTACK(comp);
|
||||||
|
unsigned long flags;
|
||||||
|
u32 val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&ctrl->comp_lock, flags);
|
||||||
|
ctrl->comp = ∁
|
||||||
|
spin_unlock_irqrestore(&ctrl->comp_lock, flags);
|
||||||
|
val = SWRM_REG_VAL_PACK(cmd_data, dev_addr,
|
||||||
|
SWRM_SPECIAL_CMD_ID, reg_addr);
|
||||||
|
ret = ctrl->reg_write(ctrl, SWRM_CMD_FIFO_WR_CMD, val);
|
||||||
|
if (ret)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
ret = wait_for_completion_timeout(ctrl->comp,
|
||||||
|
msecs_to_jiffies(TIMEOUT_MS));
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
ret = SDW_CMD_IGNORED;
|
||||||
|
else
|
||||||
|
ret = SDW_CMD_OK;
|
||||||
|
err:
|
||||||
|
spin_lock_irqsave(&ctrl->comp_lock, flags);
|
||||||
|
ctrl->comp = NULL;
|
||||||
|
spin_unlock_irqrestore(&ctrl->comp_lock, flags);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_swrm_cmd_fifo_rd_cmd(struct qcom_swrm_ctrl *ctrl,
|
||||||
|
u8 dev_addr, u16 reg_addr,
|
||||||
|
u32 len, u8 *rval)
|
||||||
|
{
|
||||||
|
int i, ret;
|
||||||
|
u32 val;
|
||||||
|
DECLARE_COMPLETION_ONSTACK(comp);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&ctrl->comp_lock, flags);
|
||||||
|
ctrl->comp = ∁
|
||||||
|
spin_unlock_irqrestore(&ctrl->comp_lock, flags);
|
||||||
|
|
||||||
|
val = SWRM_REG_VAL_PACK(len, dev_addr, SWRM_SPECIAL_CMD_ID, reg_addr);
|
||||||
|
ret = ctrl->reg_write(ctrl, SWRM_CMD_FIFO_RD_CMD, val);
|
||||||
|
if (ret)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
ret = wait_for_completion_timeout(ctrl->comp,
|
||||||
|
msecs_to_jiffies(TIMEOUT_MS));
|
||||||
|
|
||||||
|
if (!ret) {
|
||||||
|
ret = SDW_CMD_IGNORED;
|
||||||
|
goto err;
|
||||||
|
} else {
|
||||||
|
ret = SDW_CMD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
ctrl->reg_read(ctrl, SWRM_CMD_FIFO_RD_FIFO_ADDR, &val);
|
||||||
|
rval[i] = val & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
err:
|
||||||
|
spin_lock_irqsave(&ctrl->comp_lock, flags);
|
||||||
|
ctrl->comp = NULL;
|
||||||
|
spin_unlock_irqrestore(&ctrl->comp_lock, flags);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val);
|
||||||
|
|
||||||
|
for (i = 0; i < SDW_MAX_DEVICES; i++) {
|
||||||
|
u32 s;
|
||||||
|
|
||||||
|
s = (val >> (i * 2));
|
||||||
|
s &= SWRM_MCP_SLV_STATUS_MASK;
|
||||||
|
ctrl->status[i] = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct qcom_swrm_ctrl *ctrl = dev_id;
|
||||||
|
u32 sts, value;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
ctrl->reg_read(ctrl, SWRM_INTERRUPT_STATUS, &sts);
|
||||||
|
|
||||||
|
if (sts & SWRM_INTERRUPT_STATUS_CMD_ERROR) {
|
||||||
|
ctrl->reg_read(ctrl, SWRM_CMD_FIFO_STATUS, &value);
|
||||||
|
dev_err_ratelimited(ctrl->dev,
|
||||||
|
"CMD error, fifo status 0x%x\n",
|
||||||
|
value);
|
||||||
|
ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CMD, 0x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sts & SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED) ||
|
||||||
|
sts & SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS)
|
||||||
|
schedule_work(&ctrl->slave_work);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clear the interrupt before complete() is called, as complete can
|
||||||
|
* schedule new read/writes which require interrupts, clearing the
|
||||||
|
* interrupt would avoid missing interrupts in such cases.
|
||||||
|
*/
|
||||||
|
ctrl->reg_write(ctrl, SWRM_INTERRUPT_CLEAR, sts);
|
||||||
|
|
||||||
|
if (sts & SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED) {
|
||||||
|
spin_lock_irqsave(&ctrl->comp_lock, flags);
|
||||||
|
if (ctrl->comp)
|
||||||
|
complete(ctrl->comp);
|
||||||
|
spin_unlock_irqrestore(&ctrl->comp_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
/* Clear Rows and Cols */
|
||||||
|
val = (SWRM_MAX_ROW_VAL << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT |
|
||||||
|
SWRM_MIN_COL_VAL << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT);
|
||||||
|
|
||||||
|
ctrl->reg_write(ctrl, SWRM_MCP_FRAME_CTRL_BANK_ADDR(0), val);
|
||||||
|
|
||||||
|
/* Disable Auto enumeration */
|
||||||
|
ctrl->reg_write(ctrl, SWRM_ENUMERATOR_CFG_ADDR, 0);
|
||||||
|
|
||||||
|
/* Mask soundwire interrupts */
|
||||||
|
ctrl->reg_write(ctrl, SWRM_INTERRUPT_MASK_ADDR,
|
||||||
|
SWRM_INTERRUPT_STATUS_RMSK);
|
||||||
|
|
||||||
|
/* Configure No pings */
|
||||||
|
ctrl->reg_read(ctrl, SWRM_MCP_CFG_ADDR, &val);
|
||||||
|
val &= ~SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK;
|
||||||
|
val |= (SWRM_DEF_CMD_NO_PINGS <<
|
||||||
|
SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_SHFT);
|
||||||
|
ctrl->reg_write(ctrl, SWRM_MCP_CFG_ADDR, val);
|
||||||
|
|
||||||
|
/* Configure number of retries of a read/write cmd */
|
||||||
|
ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR, SWRM_RD_WR_CMD_RETRIES);
|
||||||
|
|
||||||
|
/* Set IRQ to PULSE */
|
||||||
|
ctrl->reg_write(ctrl, SWRM_COMP_CFG_ADDR,
|
||||||
|
SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK |
|
||||||
|
SWRM_COMP_CFG_ENABLE_MSK);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum sdw_command_response qcom_swrm_xfer_msg(struct sdw_bus *bus,
|
||||||
|
struct sdw_msg *msg)
|
||||||
|
{
|
||||||
|
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
|
||||||
|
int ret, i, len;
|
||||||
|
|
||||||
|
if (msg->flags == SDW_MSG_FLAG_READ) {
|
||||||
|
for (i = 0; i < msg->len;) {
|
||||||
|
if ((msg->len - i) < QCOM_SWRM_MAX_RD_LEN)
|
||||||
|
len = msg->len - i;
|
||||||
|
else
|
||||||
|
len = QCOM_SWRM_MAX_RD_LEN;
|
||||||
|
|
||||||
|
ret = qcom_swrm_cmd_fifo_rd_cmd(ctrl, msg->dev_num,
|
||||||
|
msg->addr + i, len,
|
||||||
|
&msg->buf[i]);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
i = i + len;
|
||||||
|
}
|
||||||
|
} else if (msg->flags == SDW_MSG_FLAG_WRITE) {
|
||||||
|
for (i = 0; i < msg->len; i++) {
|
||||||
|
ret = qcom_swrm_cmd_fifo_wr_cmd(ctrl, msg->buf[i],
|
||||||
|
msg->dev_num,
|
||||||
|
msg->addr + i);
|
||||||
|
if (ret)
|
||||||
|
return SDW_CMD_IGNORED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SDW_CMD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_swrm_pre_bank_switch(struct sdw_bus *bus)
|
||||||
|
{
|
||||||
|
u32 reg = SWRM_MCP_FRAME_CTRL_BANK_ADDR(bus->params.next_bank);
|
||||||
|
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
ctrl->reg_read(ctrl, reg, &val);
|
||||||
|
|
||||||
|
val &= ~SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK;
|
||||||
|
val &= ~SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK;
|
||||||
|
|
||||||
|
val |= (SWRM_MAX_ROW_VAL << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT |
|
||||||
|
SWRM_MAX_COL_VAL << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT);
|
||||||
|
|
||||||
|
return ctrl->reg_write(ctrl, reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_swrm_port_params(struct sdw_bus *bus,
|
||||||
|
struct sdw_port_params *p_params,
|
||||||
|
unsigned int bank)
|
||||||
|
{
|
||||||
|
/* TBD */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_swrm_transport_params(struct sdw_bus *bus,
|
||||||
|
struct sdw_transport_params *params,
|
||||||
|
enum sdw_reg_bank bank)
|
||||||
|
{
|
||||||
|
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
|
||||||
|
u32 value;
|
||||||
|
|
||||||
|
value = params->offset1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT;
|
||||||
|
value |= params->offset2 << SWRM_DP_PORT_CTRL_OFFSET2_SHFT;
|
||||||
|
value |= params->sample_interval - 1;
|
||||||
|
|
||||||
|
return ctrl->reg_write(ctrl,
|
||||||
|
SWRM_DP_PORT_CTRL_BANK((params->port_num), bank),
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_swrm_port_enable(struct sdw_bus *bus,
|
||||||
|
struct sdw_enable_ch *enable_ch,
|
||||||
|
unsigned int bank)
|
||||||
|
{
|
||||||
|
u32 reg = SWRM_DP_PORT_CTRL_BANK(enable_ch->port_num, bank);
|
||||||
|
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
ctrl->reg_read(ctrl, reg, &val);
|
||||||
|
|
||||||
|
if (enable_ch->enable)
|
||||||
|
val |= (enable_ch->ch_mask << SWRM_DP_PORT_CTRL_EN_CHAN_SHFT);
|
||||||
|
else
|
||||||
|
val &= ~(0xff << SWRM_DP_PORT_CTRL_EN_CHAN_SHFT);
|
||||||
|
|
||||||
|
return ctrl->reg_write(ctrl, reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sdw_master_port_ops qcom_swrm_port_ops = {
|
||||||
|
.dpn_set_port_params = qcom_swrm_port_params,
|
||||||
|
.dpn_set_port_transport_params = qcom_swrm_transport_params,
|
||||||
|
.dpn_port_enable_ch = qcom_swrm_port_enable,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct sdw_master_ops qcom_swrm_ops = {
|
||||||
|
.xfer_msg = qcom_swrm_xfer_msg,
|
||||||
|
.pre_bank_switch = qcom_swrm_pre_bank_switch,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int qcom_swrm_compute_params(struct sdw_bus *bus)
|
||||||
|
{
|
||||||
|
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
|
||||||
|
struct sdw_master_runtime *m_rt;
|
||||||
|
struct sdw_slave_runtime *s_rt;
|
||||||
|
struct sdw_port_runtime *p_rt;
|
||||||
|
struct qcom_swrm_port_config *pcfg;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
|
||||||
|
list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
|
||||||
|
pcfg = &ctrl->pconfig[p_rt->num - 1];
|
||||||
|
p_rt->transport_params.port_num = p_rt->num;
|
||||||
|
p_rt->transport_params.sample_interval = pcfg->si + 1;
|
||||||
|
p_rt->transport_params.offset1 = pcfg->off1;
|
||||||
|
p_rt->transport_params.offset2 = pcfg->off2;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
|
||||||
|
list_for_each_entry(p_rt, &s_rt->port_list, port_node) {
|
||||||
|
pcfg = &ctrl->pconfig[i];
|
||||||
|
p_rt->transport_params.port_num = p_rt->num;
|
||||||
|
p_rt->transport_params.sample_interval =
|
||||||
|
pcfg->si + 1;
|
||||||
|
p_rt->transport_params.offset1 = pcfg->off1;
|
||||||
|
p_rt->transport_params.offset2 = pcfg->off2;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 qcom_swrm_freq_tbl[MAX_FREQ_NUM] = {
|
||||||
|
DEFAULT_CLK_FREQ,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void qcom_swrm_slave_wq(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct qcom_swrm_ctrl *ctrl =
|
||||||
|
container_of(work, struct qcom_swrm_ctrl, slave_work);
|
||||||
|
|
||||||
|
qcom_swrm_get_device_status(ctrl);
|
||||||
|
sdw_handle_slave_status(&ctrl->bus, ctrl->status);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void qcom_swrm_stream_free_ports(struct qcom_swrm_ctrl *ctrl,
|
||||||
|
struct sdw_stream_runtime *stream)
|
||||||
|
{
|
||||||
|
struct sdw_master_runtime *m_rt;
|
||||||
|
struct sdw_port_runtime *p_rt;
|
||||||
|
unsigned long *port_mask;
|
||||||
|
|
||||||
|
mutex_lock(&ctrl->port_lock);
|
||||||
|
|
||||||
|
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
|
||||||
|
if (m_rt->direction == SDW_DATA_DIR_RX)
|
||||||
|
port_mask = &ctrl->dout_port_mask;
|
||||||
|
else
|
||||||
|
port_mask = &ctrl->din_port_mask;
|
||||||
|
|
||||||
|
list_for_each_entry(p_rt, &m_rt->port_list, port_node)
|
||||||
|
clear_bit(p_rt->num - 1, port_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&ctrl->port_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl,
|
||||||
|
struct sdw_stream_runtime *stream,
|
||||||
|
struct snd_pcm_hw_params *params,
|
||||||
|
int direction)
|
||||||
|
{
|
||||||
|
struct sdw_port_config pconfig[QCOM_SDW_MAX_PORTS];
|
||||||
|
struct sdw_stream_config sconfig;
|
||||||
|
struct sdw_master_runtime *m_rt;
|
||||||
|
struct sdw_slave_runtime *s_rt;
|
||||||
|
struct sdw_port_runtime *p_rt;
|
||||||
|
unsigned long *port_mask;
|
||||||
|
int i, maxport, pn, nports = 0, ret = 0;
|
||||||
|
|
||||||
|
mutex_lock(&ctrl->port_lock);
|
||||||
|
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
|
||||||
|
if (m_rt->direction == SDW_DATA_DIR_RX) {
|
||||||
|
maxport = ctrl->num_dout_ports;
|
||||||
|
port_mask = &ctrl->dout_port_mask;
|
||||||
|
} else {
|
||||||
|
maxport = ctrl->num_din_ports;
|
||||||
|
port_mask = &ctrl->din_port_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
|
||||||
|
list_for_each_entry(p_rt, &s_rt->port_list, port_node) {
|
||||||
|
/* Port numbers start from 1 - 14*/
|
||||||
|
pn = find_first_zero_bit(port_mask, maxport);
|
||||||
|
if (pn > (maxport - 1)) {
|
||||||
|
dev_err(ctrl->dev, "All ports busy\n");
|
||||||
|
ret = -EBUSY;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
set_bit(pn, port_mask);
|
||||||
|
pconfig[nports].num = pn + 1;
|
||||||
|
pconfig[nports].ch_mask = p_rt->ch_mask;
|
||||||
|
nports++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (direction == SNDRV_PCM_STREAM_CAPTURE)
|
||||||
|
sconfig.direction = SDW_DATA_DIR_TX;
|
||||||
|
else
|
||||||
|
sconfig.direction = SDW_DATA_DIR_RX;
|
||||||
|
|
||||||
|
/* hw parameters wil be ignored as we only support PDM */
|
||||||
|
sconfig.ch_count = 1;
|
||||||
|
sconfig.frame_rate = params_rate(params);
|
||||||
|
sconfig.type = stream->type;
|
||||||
|
sconfig.bps = 1;
|
||||||
|
sdw_stream_add_master(&ctrl->bus, &sconfig, pconfig,
|
||||||
|
nports, stream);
|
||||||
|
err:
|
||||||
|
if (ret) {
|
||||||
|
for (i = 0; i < nports; i++)
|
||||||
|
clear_bit(pconfig[i].num - 1, port_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&ctrl->port_lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_swrm_hw_params(struct snd_pcm_substream *substream,
|
||||||
|
struct snd_pcm_hw_params *params,
|
||||||
|
struct snd_soc_dai *dai)
|
||||||
|
{
|
||||||
|
struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev);
|
||||||
|
struct sdw_stream_runtime *sruntime = ctrl->sruntime[dai->id];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = qcom_swrm_stream_alloc_ports(ctrl, sruntime, params,
|
||||||
|
substream->stream);
|
||||||
|
if (ret)
|
||||||
|
qcom_swrm_stream_free_ports(ctrl, sruntime);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_swrm_hw_free(struct snd_pcm_substream *substream,
|
||||||
|
struct snd_soc_dai *dai)
|
||||||
|
{
|
||||||
|
struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev);
|
||||||
|
struct sdw_stream_runtime *sruntime = ctrl->sruntime[dai->id];
|
||||||
|
|
||||||
|
qcom_swrm_stream_free_ports(ctrl, sruntime);
|
||||||
|
sdw_stream_remove_master(&ctrl->bus, sruntime);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_swrm_set_sdw_stream(struct snd_soc_dai *dai,
|
||||||
|
void *stream, int direction)
|
||||||
|
{
|
||||||
|
struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev);
|
||||||
|
|
||||||
|
ctrl->sruntime[dai->id] = stream;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_swrm_startup(struct snd_pcm_substream *substream,
|
||||||
|
struct snd_soc_dai *dai)
|
||||||
|
{
|
||||||
|
struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev);
|
||||||
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||||
|
struct sdw_stream_runtime *sruntime;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
sruntime = sdw_alloc_stream(dai->name);
|
||||||
|
if (!sruntime)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ctrl->sruntime[dai->id] = sruntime;
|
||||||
|
|
||||||
|
for (i = 0; i < rtd->num_codecs; i++) {
|
||||||
|
ret = snd_soc_dai_set_sdw_stream(rtd->codec_dais[i], sruntime,
|
||||||
|
substream->stream);
|
||||||
|
if (ret < 0 && ret != -ENOTSUPP) {
|
||||||
|
dev_err(dai->dev, "Failed to set sdw stream on %s",
|
||||||
|
rtd->codec_dais[i]->name);
|
||||||
|
sdw_release_stream(sruntime);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qcom_swrm_shutdown(struct snd_pcm_substream *substream,
|
||||||
|
struct snd_soc_dai *dai)
|
||||||
|
{
|
||||||
|
struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev);
|
||||||
|
|
||||||
|
sdw_release_stream(ctrl->sruntime[dai->id]);
|
||||||
|
ctrl->sruntime[dai->id] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct snd_soc_dai_ops qcom_swrm_pdm_dai_ops = {
|
||||||
|
.hw_params = qcom_swrm_hw_params,
|
||||||
|
.hw_free = qcom_swrm_hw_free,
|
||||||
|
.startup = qcom_swrm_startup,
|
||||||
|
.shutdown = qcom_swrm_shutdown,
|
||||||
|
.set_sdw_stream = qcom_swrm_set_sdw_stream,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct snd_soc_component_driver qcom_swrm_dai_component = {
|
||||||
|
.name = "soundwire",
|
||||||
|
};
|
||||||
|
|
||||||
|
static int qcom_swrm_register_dais(struct qcom_swrm_ctrl *ctrl)
|
||||||
|
{
|
||||||
|
int num_dais = ctrl->num_dout_ports + ctrl->num_din_ports;
|
||||||
|
struct snd_soc_dai_driver *dais;
|
||||||
|
struct snd_soc_pcm_stream *stream;
|
||||||
|
struct device *dev = ctrl->dev;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* PDM dais are only tested for now */
|
||||||
|
dais = devm_kcalloc(dev, num_dais, sizeof(*dais), GFP_KERNEL);
|
||||||
|
if (!dais)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
for (i = 0; i < num_dais; i++) {
|
||||||
|
dais[i].name = devm_kasprintf(dev, GFP_KERNEL, "SDW Pin%d", i);
|
||||||
|
if (!dais[i].name)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (i < ctrl->num_dout_ports)
|
||||||
|
stream = &dais[i].playback;
|
||||||
|
else
|
||||||
|
stream = &dais[i].capture;
|
||||||
|
|
||||||
|
stream->channels_min = 1;
|
||||||
|
stream->channels_max = 1;
|
||||||
|
stream->rates = SNDRV_PCM_RATE_48000;
|
||||||
|
stream->formats = SNDRV_PCM_FMTBIT_S16_LE;
|
||||||
|
|
||||||
|
dais[i].ops = &qcom_swrm_pdm_dai_ops;
|
||||||
|
dais[i].id = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return devm_snd_soc_register_component(ctrl->dev,
|
||||||
|
&qcom_swrm_dai_component,
|
||||||
|
dais, num_dais);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl)
|
||||||
|
{
|
||||||
|
struct device_node *np = ctrl->dev->of_node;
|
||||||
|
u8 off1[QCOM_SDW_MAX_PORTS];
|
||||||
|
u8 off2[QCOM_SDW_MAX_PORTS];
|
||||||
|
u8 si[QCOM_SDW_MAX_PORTS];
|
||||||
|
int i, ret, nports, val;
|
||||||
|
|
||||||
|
ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val);
|
||||||
|
|
||||||
|
ctrl->num_dout_ports = val & SWRM_COMP_PARAMS_DOUT_PORTS_MASK;
|
||||||
|
ctrl->num_din_ports = (val & SWRM_COMP_PARAMS_DIN_PORTS_MASK) >> 5;
|
||||||
|
|
||||||
|
ret = of_property_read_u32(np, "qcom,din-ports", &val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (val > ctrl->num_din_ports)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
ctrl->num_din_ports = val;
|
||||||
|
|
||||||
|
ret = of_property_read_u32(np, "qcom,dout-ports", &val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (val > ctrl->num_dout_ports)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
ctrl->num_dout_ports = val;
|
||||||
|
|
||||||
|
nports = ctrl->num_dout_ports + ctrl->num_din_ports;
|
||||||
|
|
||||||
|
ret = of_property_read_u8_array(np, "qcom,ports-offset1",
|
||||||
|
off1, nports);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = of_property_read_u8_array(np, "qcom,ports-offset2",
|
||||||
|
off2, nports);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = of_property_read_u8_array(np, "qcom,ports-sinterval-low",
|
||||||
|
si, nports);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
for (i = 0; i < nports; i++) {
|
||||||
|
ctrl->pconfig[i].si = si[i];
|
||||||
|
ctrl->pconfig[i].off1 = off1[i];
|
||||||
|
ctrl->pconfig[i].off2 = off2[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_swrm_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct sdw_master_prop *prop;
|
||||||
|
struct sdw_bus_params *params;
|
||||||
|
struct qcom_swrm_ctrl *ctrl;
|
||||||
|
int ret;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
|
||||||
|
if (!ctrl)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (dev->parent->bus == &slimbus_bus) {
|
||||||
|
ctrl->reg_read = qcom_swrm_abh_reg_read;
|
||||||
|
ctrl->reg_write = qcom_swrm_ahb_reg_write;
|
||||||
|
ctrl->regmap = dev_get_regmap(dev->parent, NULL);
|
||||||
|
if (!ctrl->regmap)
|
||||||
|
return -EINVAL;
|
||||||
|
} else {
|
||||||
|
/* Only WCD based SoundWire controller is supported */
|
||||||
|
return -ENOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrl->irq = of_irq_get(dev->of_node, 0);
|
||||||
|
if (ctrl->irq < 0)
|
||||||
|
return ctrl->irq;
|
||||||
|
|
||||||
|
ctrl->hclk = devm_clk_get(dev, "iface");
|
||||||
|
if (IS_ERR(ctrl->hclk))
|
||||||
|
return PTR_ERR(ctrl->hclk);
|
||||||
|
|
||||||
|
clk_prepare_enable(ctrl->hclk);
|
||||||
|
|
||||||
|
ctrl->dev = dev;
|
||||||
|
dev_set_drvdata(&pdev->dev, ctrl);
|
||||||
|
spin_lock_init(&ctrl->comp_lock);
|
||||||
|
mutex_init(&ctrl->port_lock);
|
||||||
|
INIT_WORK(&ctrl->slave_work, qcom_swrm_slave_wq);
|
||||||
|
|
||||||
|
ctrl->bus.dev = dev;
|
||||||
|
ctrl->bus.ops = &qcom_swrm_ops;
|
||||||
|
ctrl->bus.port_ops = &qcom_swrm_port_ops;
|
||||||
|
ctrl->bus.compute_params = &qcom_swrm_compute_params;
|
||||||
|
|
||||||
|
ret = qcom_swrm_get_port_config(ctrl);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
params = &ctrl->bus.params;
|
||||||
|
params->max_dr_freq = DEFAULT_CLK_FREQ;
|
||||||
|
params->curr_dr_freq = DEFAULT_CLK_FREQ;
|
||||||
|
params->col = SWRM_DEFAULT_COL;
|
||||||
|
params->row = SWRM_DEFAULT_ROWS;
|
||||||
|
ctrl->reg_read(ctrl, SWRM_MCP_STATUS, &val);
|
||||||
|
params->curr_bank = val & SWRM_MCP_STATUS_BANK_NUM_MASK;
|
||||||
|
params->next_bank = !params->curr_bank;
|
||||||
|
|
||||||
|
prop = &ctrl->bus.prop;
|
||||||
|
prop->max_clk_freq = DEFAULT_CLK_FREQ;
|
||||||
|
prop->num_clk_gears = 0;
|
||||||
|
prop->num_clk_freq = MAX_FREQ_NUM;
|
||||||
|
prop->clk_freq = &qcom_swrm_freq_tbl[0];
|
||||||
|
prop->default_col = SWRM_DEFAULT_COL;
|
||||||
|
prop->default_row = SWRM_DEFAULT_ROWS;
|
||||||
|
|
||||||
|
ctrl->reg_read(ctrl, SWRM_COMP_HW_VERSION, &ctrl->version);
|
||||||
|
|
||||||
|
ret = devm_request_threaded_irq(dev, ctrl->irq, NULL,
|
||||||
|
qcom_swrm_irq_handler,
|
||||||
|
IRQF_TRIGGER_RISING,
|
||||||
|
"soundwire", ctrl);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Failed to request soundwire irq\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sdw_add_bus_master(&ctrl->bus);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Failed to register Soundwire controller (%d)\n",
|
||||||
|
ret);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
qcom_swrm_init(ctrl);
|
||||||
|
ret = qcom_swrm_register_dais(ctrl);
|
||||||
|
if (ret)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
dev_info(dev, "Qualcomm Soundwire controller v%x.%x.%x Registered\n",
|
||||||
|
(ctrl->version >> 24) & 0xff, (ctrl->version >> 16) & 0xff,
|
||||||
|
ctrl->version & 0xffff);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
err:
|
||||||
|
clk_disable_unprepare(ctrl->hclk);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_swrm_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
|
sdw_delete_bus_master(&ctrl->bus);
|
||||||
|
clk_disable_unprepare(ctrl->hclk);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id qcom_swrm_of_match[] = {
|
||||||
|
{ .compatible = "qcom,soundwire-v1.3.0", },
|
||||||
|
{/* sentinel */},
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_DEVICE_TABLE(of, qcom_swrm_of_match);
|
||||||
|
|
||||||
|
static struct platform_driver qcom_swrm_driver = {
|
||||||
|
.probe = &qcom_swrm_probe,
|
||||||
|
.remove = &qcom_swrm_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "qcom-soundwire",
|
||||||
|
.of_match_table = qcom_swrm_of_match,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
module_platform_driver(qcom_swrm_driver);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("Qualcomm soundwire driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
|
@ -1554,8 +1554,6 @@ int sdw_prepare_stream(struct sdw_stream_runtime *stream)
|
||||||
sdw_acquire_bus_lock(stream);
|
sdw_acquire_bus_lock(stream);
|
||||||
|
|
||||||
ret = _sdw_prepare_stream(stream);
|
ret = _sdw_prepare_stream(stream);
|
||||||
if (ret < 0)
|
|
||||||
pr_err("Prepare for stream:%s failed: %d\n", stream->name, ret);
|
|
||||||
|
|
||||||
sdw_release_bus_lock(stream);
|
sdw_release_bus_lock(stream);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1622,8 +1620,6 @@ int sdw_enable_stream(struct sdw_stream_runtime *stream)
|
||||||
sdw_acquire_bus_lock(stream);
|
sdw_acquire_bus_lock(stream);
|
||||||
|
|
||||||
ret = _sdw_enable_stream(stream);
|
ret = _sdw_enable_stream(stream);
|
||||||
if (ret < 0)
|
|
||||||
pr_err("Enable for stream:%s failed: %d\n", stream->name, ret);
|
|
||||||
|
|
||||||
sdw_release_bus_lock(stream);
|
sdw_release_bus_lock(stream);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1698,8 +1694,6 @@ int sdw_disable_stream(struct sdw_stream_runtime *stream)
|
||||||
sdw_acquire_bus_lock(stream);
|
sdw_acquire_bus_lock(stream);
|
||||||
|
|
||||||
ret = _sdw_disable_stream(stream);
|
ret = _sdw_disable_stream(stream);
|
||||||
if (ret < 0)
|
|
||||||
pr_err("Disable for stream:%s failed: %d\n", stream->name, ret);
|
|
||||||
|
|
||||||
sdw_release_bus_lock(stream);
|
sdw_release_bus_lock(stream);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1756,8 +1750,6 @@ int sdw_deprepare_stream(struct sdw_stream_runtime *stream)
|
||||||
|
|
||||||
sdw_acquire_bus_lock(stream);
|
sdw_acquire_bus_lock(stream);
|
||||||
ret = _sdw_deprepare_stream(stream);
|
ret = _sdw_deprepare_stream(stream);
|
||||||
if (ret < 0)
|
|
||||||
pr_err("De-prepare for stream:%d failed: %d\n", ret, ret);
|
|
||||||
|
|
||||||
sdw_release_bus_lock(stream);
|
sdw_release_bus_lock(stream);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -132,11 +132,13 @@ static int uio_dmem_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on)
|
||||||
if (irq_on) {
|
if (irq_on) {
|
||||||
if (test_and_clear_bit(0, &priv->flags))
|
if (test_and_clear_bit(0, &priv->flags))
|
||||||
enable_irq(dev_info->irq);
|
enable_irq(dev_info->irq);
|
||||||
|
spin_unlock_irqrestore(&priv->lock, flags);
|
||||||
} else {
|
} else {
|
||||||
if (!test_and_set_bit(0, &priv->flags))
|
if (!test_and_set_bit(0, &priv->flags)) {
|
||||||
|
spin_unlock_irqrestore(&priv->lock, flags);
|
||||||
disable_irq(dev_info->irq);
|
disable_irq(dev_info->irq);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&priv->lock, flags);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,6 +156,8 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev)
|
||||||
uioinfo->irq = ret;
|
uioinfo->irq = ret;
|
||||||
if (ret == -ENXIO && pdev->dev.of_node)
|
if (ret == -ENXIO && pdev->dev.of_node)
|
||||||
uioinfo->irq = UIO_IRQ_NONE;
|
uioinfo->irq = UIO_IRQ_NONE;
|
||||||
|
else if (ret == -EPROBE_DEFER)
|
||||||
|
return ret;
|
||||||
else if (ret < 0) {
|
else if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "failed to get IRQ\n");
|
dev_err(&pdev->dev, "failed to get IRQ\n");
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -1210,14 +1210,17 @@ static void setup_crash_devices_work_queue(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct controlvm_message local_crash_bus_msg;
|
struct controlvm_message local_crash_bus_msg;
|
||||||
struct controlvm_message local_crash_dev_msg;
|
struct controlvm_message local_crash_dev_msg;
|
||||||
struct controlvm_message msg;
|
struct controlvm_message msg = {
|
||||||
|
.hdr.id = CONTROLVM_CHIPSET_INIT,
|
||||||
|
.cmd.init_chipset = {
|
||||||
|
.bus_count = 23,
|
||||||
|
.switch_count = 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
u32 local_crash_msg_offset;
|
u32 local_crash_msg_offset;
|
||||||
u16 local_crash_msg_count;
|
u16 local_crash_msg_count;
|
||||||
|
|
||||||
/* send init chipset msg */
|
/* send init chipset msg */
|
||||||
msg.hdr.id = CONTROLVM_CHIPSET_INIT;
|
|
||||||
msg.cmd.init_chipset.bus_count = 23;
|
|
||||||
msg.cmd.init_chipset.switch_count = 0;
|
|
||||||
chipset_init(&msg);
|
chipset_init(&msg);
|
||||||
/* get saved message count */
|
/* get saved message count */
|
||||||
if (visorchannel_read(chipset_dev->controlvm_channel,
|
if (visorchannel_read(chipset_dev->controlvm_channel,
|
||||||
|
|
|
@ -414,8 +414,9 @@ static void fake_lm_check(struct fake_driver *bridge, unsigned long long addr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 fake_vmeread8(struct fake_driver *bridge, unsigned long long addr,
|
static noinline_for_stack u8 fake_vmeread8(struct fake_driver *bridge,
|
||||||
u32 aspace, u32 cycle)
|
unsigned long long addr,
|
||||||
|
u32 aspace, u32 cycle)
|
||||||
{
|
{
|
||||||
u8 retval = 0xff;
|
u8 retval = 0xff;
|
||||||
int i;
|
int i;
|
||||||
|
@ -446,8 +447,9 @@ static u8 fake_vmeread8(struct fake_driver *bridge, unsigned long long addr,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u16 fake_vmeread16(struct fake_driver *bridge, unsigned long long addr,
|
static noinline_for_stack u16 fake_vmeread16(struct fake_driver *bridge,
|
||||||
u32 aspace, u32 cycle)
|
unsigned long long addr,
|
||||||
|
u32 aspace, u32 cycle)
|
||||||
{
|
{
|
||||||
u16 retval = 0xffff;
|
u16 retval = 0xffff;
|
||||||
int i;
|
int i;
|
||||||
|
@ -478,8 +480,9 @@ static u16 fake_vmeread16(struct fake_driver *bridge, unsigned long long addr,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 fake_vmeread32(struct fake_driver *bridge, unsigned long long addr,
|
static noinline_for_stack u32 fake_vmeread32(struct fake_driver *bridge,
|
||||||
u32 aspace, u32 cycle)
|
unsigned long long addr,
|
||||||
|
u32 aspace, u32 cycle)
|
||||||
{
|
{
|
||||||
u32 retval = 0xffffffff;
|
u32 retval = 0xffffffff;
|
||||||
int i;
|
int i;
|
||||||
|
@ -609,8 +612,9 @@ out:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fake_vmewrite8(struct fake_driver *bridge, u8 *buf,
|
static noinline_for_stack void fake_vmewrite8(struct fake_driver *bridge,
|
||||||
unsigned long long addr, u32 aspace, u32 cycle)
|
u8 *buf, unsigned long long addr,
|
||||||
|
u32 aspace, u32 cycle)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned long long start, end, offset;
|
unsigned long long start, end, offset;
|
||||||
|
@ -639,8 +643,9 @@ static void fake_vmewrite8(struct fake_driver *bridge, u8 *buf,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fake_vmewrite16(struct fake_driver *bridge, u16 *buf,
|
static noinline_for_stack void fake_vmewrite16(struct fake_driver *bridge,
|
||||||
unsigned long long addr, u32 aspace, u32 cycle)
|
u16 *buf, unsigned long long addr,
|
||||||
|
u32 aspace, u32 cycle)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned long long start, end, offset;
|
unsigned long long start, end, offset;
|
||||||
|
@ -669,8 +674,9 @@ static void fake_vmewrite16(struct fake_driver *bridge, u16 *buf,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fake_vmewrite32(struct fake_driver *bridge, u32 *buf,
|
static noinline_for_stack void fake_vmewrite32(struct fake_driver *bridge,
|
||||||
unsigned long long addr, u32 aspace, u32 cycle)
|
u32 *buf, unsigned long long addr,
|
||||||
|
u32 aspace, u32 cycle)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned long long start, end, offset;
|
unsigned long long start, end, offset;
|
||||||
|
|
|
@ -38,12 +38,6 @@
|
||||||
#define OMAP_HDQ_INT_STATUS_TXCOMPLETE BIT(2)
|
#define OMAP_HDQ_INT_STATUS_TXCOMPLETE BIT(2)
|
||||||
#define OMAP_HDQ_INT_STATUS_RXCOMPLETE BIT(1)
|
#define OMAP_HDQ_INT_STATUS_RXCOMPLETE BIT(1)
|
||||||
#define OMAP_HDQ_INT_STATUS_TIMEOUT BIT(0)
|
#define OMAP_HDQ_INT_STATUS_TIMEOUT BIT(0)
|
||||||
#define OMAP_HDQ_SYSCONFIG 0x14
|
|
||||||
#define OMAP_HDQ_SYSCONFIG_SOFTRESET BIT(1)
|
|
||||||
#define OMAP_HDQ_SYSCONFIG_AUTOIDLE BIT(0)
|
|
||||||
#define OMAP_HDQ_SYSCONFIG_NOIDLE 0x0
|
|
||||||
#define OMAP_HDQ_SYSSTATUS 0x18
|
|
||||||
#define OMAP_HDQ_SYSSTATUS_RESETDONE BIT(0)
|
|
||||||
|
|
||||||
#define OMAP_HDQ_FLAG_CLEAR 0
|
#define OMAP_HDQ_FLAG_CLEAR 0
|
||||||
#define OMAP_HDQ_FLAG_SET 1
|
#define OMAP_HDQ_FLAG_SET 1
|
||||||
|
@ -62,17 +56,9 @@ struct hdq_data {
|
||||||
void __iomem *hdq_base;
|
void __iomem *hdq_base;
|
||||||
/* lock status update */
|
/* lock status update */
|
||||||
struct mutex hdq_mutex;
|
struct mutex hdq_mutex;
|
||||||
int hdq_usecount;
|
|
||||||
u8 hdq_irqstatus;
|
u8 hdq_irqstatus;
|
||||||
/* device lock */
|
/* device lock */
|
||||||
spinlock_t hdq_spinlock;
|
spinlock_t hdq_spinlock;
|
||||||
/*
|
|
||||||
* Used to control the call to omap_hdq_get and omap_hdq_put.
|
|
||||||
* HDQ Protocol: Write the CMD|REG_address first, followed by
|
|
||||||
* the data wrire or read.
|
|
||||||
*/
|
|
||||||
int init_trans;
|
|
||||||
int rrw;
|
|
||||||
/* mode: 0-HDQ 1-W1 */
|
/* mode: 0-HDQ 1-W1 */
|
||||||
int mode;
|
int mode;
|
||||||
|
|
||||||
|
@ -99,15 +85,6 @@ static inline u8 hdq_reg_merge(struct hdq_data *hdq_data, u32 offset,
|
||||||
return new_val;
|
return new_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hdq_disable_interrupt(struct hdq_data *hdq_data, u32 offset,
|
|
||||||
u32 mask)
|
|
||||||
{
|
|
||||||
u32 ie;
|
|
||||||
|
|
||||||
ie = readl(hdq_data->hdq_base + offset);
|
|
||||||
writel(ie & mask, hdq_data->hdq_base + offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wait for one or more bits in flag change.
|
* Wait for one or more bits in flag change.
|
||||||
* HDQ_FLAG_SET: wait until any bit in the flag is set.
|
* HDQ_FLAG_SET: wait until any bit in the flag is set.
|
||||||
|
@ -142,22 +119,24 @@ static int hdq_wait_for_flag(struct hdq_data *hdq_data, u32 offset,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Clear saved irqstatus after using an interrupt */
|
||||||
|
static void hdq_reset_irqstatus(struct hdq_data *hdq_data)
|
||||||
|
{
|
||||||
|
unsigned long irqflags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
|
||||||
|
hdq_data->hdq_irqstatus = 0;
|
||||||
|
spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
|
||||||
|
}
|
||||||
|
|
||||||
/* write out a byte and fill *status with HDQ_INT_STATUS */
|
/* write out a byte and fill *status with HDQ_INT_STATUS */
|
||||||
static int hdq_write_byte(struct hdq_data *hdq_data, u8 val, u8 *status)
|
static int hdq_write_byte(struct hdq_data *hdq_data, u8 val, u8 *status)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
u8 tmp_status;
|
u8 tmp_status;
|
||||||
unsigned long irqflags;
|
|
||||||
|
|
||||||
*status = 0;
|
*status = 0;
|
||||||
|
|
||||||
spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
|
|
||||||
/* clear interrupt flags via a dummy read */
|
|
||||||
hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
|
|
||||||
/* ISR loads it with new INT_STATUS */
|
|
||||||
hdq_data->hdq_irqstatus = 0;
|
|
||||||
spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
|
|
||||||
|
|
||||||
hdq_reg_out(hdq_data, OMAP_HDQ_TX_DATA, val);
|
hdq_reg_out(hdq_data, OMAP_HDQ_TX_DATA, val);
|
||||||
|
|
||||||
/* set the GO bit */
|
/* set the GO bit */
|
||||||
|
@ -191,6 +170,7 @@ static int hdq_write_byte(struct hdq_data *hdq_data, u8 val, u8 *status)
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
hdq_reset_irqstatus(hdq_data);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,47 +217,11 @@ static void omap_w1_search_bus(void *_hdq, struct w1_master *master_dev,
|
||||||
slave_found(master_dev, id);
|
slave_found(master_dev, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _omap_hdq_reset(struct hdq_data *hdq_data)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
u8 tmp_status;
|
|
||||||
|
|
||||||
hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG,
|
|
||||||
OMAP_HDQ_SYSCONFIG_SOFTRESET);
|
|
||||||
/*
|
|
||||||
* Select HDQ/1W mode & enable clocks.
|
|
||||||
* It is observed that INT flags can't be cleared via a read and GO/INIT
|
|
||||||
* won't return to zero if interrupt is disabled. So we always enable
|
|
||||||
* interrupt.
|
|
||||||
*/
|
|
||||||
hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS,
|
|
||||||
OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
|
|
||||||
OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK);
|
|
||||||
|
|
||||||
/* wait for reset to complete */
|
|
||||||
ret = hdq_wait_for_flag(hdq_data, OMAP_HDQ_SYSSTATUS,
|
|
||||||
OMAP_HDQ_SYSSTATUS_RESETDONE, OMAP_HDQ_FLAG_SET, &tmp_status);
|
|
||||||
if (ret)
|
|
||||||
dev_dbg(hdq_data->dev, "timeout waiting HDQ reset, %x",
|
|
||||||
tmp_status);
|
|
||||||
else {
|
|
||||||
hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS,
|
|
||||||
OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
|
|
||||||
OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK |
|
|
||||||
hdq_data->mode);
|
|
||||||
hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG,
|
|
||||||
OMAP_HDQ_SYSCONFIG_AUTOIDLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Issue break pulse to the device */
|
/* Issue break pulse to the device */
|
||||||
static int omap_hdq_break(struct hdq_data *hdq_data)
|
static int omap_hdq_break(struct hdq_data *hdq_data)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u8 tmp_status;
|
u8 tmp_status;
|
||||||
unsigned long irqflags;
|
|
||||||
|
|
||||||
ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
|
ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -286,13 +230,6 @@ static int omap_hdq_break(struct hdq_data *hdq_data)
|
||||||
goto rtn;
|
goto rtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
|
|
||||||
/* clear interrupt flags via a dummy read */
|
|
||||||
hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
|
|
||||||
/* ISR loads it with new INT_STATUS */
|
|
||||||
hdq_data->hdq_irqstatus = 0;
|
|
||||||
spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
|
|
||||||
|
|
||||||
/* set the INIT and GO bit */
|
/* set the INIT and GO bit */
|
||||||
hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS,
|
hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS,
|
||||||
OMAP_HDQ_CTRL_STATUS_INITIALIZATION | OMAP_HDQ_CTRL_STATUS_GO,
|
OMAP_HDQ_CTRL_STATUS_INITIALIZATION | OMAP_HDQ_CTRL_STATUS_GO,
|
||||||
|
@ -341,6 +278,7 @@ static int omap_hdq_break(struct hdq_data *hdq_data)
|
||||||
" return to zero, %x", tmp_status);
|
" return to zero, %x", tmp_status);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
hdq_reset_irqstatus(hdq_data);
|
||||||
mutex_unlock(&hdq_data->hdq_mutex);
|
mutex_unlock(&hdq_data->hdq_mutex);
|
||||||
rtn:
|
rtn:
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -357,7 +295,7 @@ static int hdq_read_byte(struct hdq_data *hdq_data, u8 *val)
|
||||||
goto rtn;
|
goto rtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hdq_data->hdq_usecount) {
|
if (pm_runtime_suspended(hdq_data->dev)) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -388,86 +326,13 @@ static int hdq_read_byte(struct hdq_data *hdq_data, u8 *val)
|
||||||
/* the data is ready. Read it in! */
|
/* the data is ready. Read it in! */
|
||||||
*val = hdq_reg_in(hdq_data, OMAP_HDQ_RX_DATA);
|
*val = hdq_reg_in(hdq_data, OMAP_HDQ_RX_DATA);
|
||||||
out:
|
out:
|
||||||
|
hdq_reset_irqstatus(hdq_data);
|
||||||
mutex_unlock(&hdq_data->hdq_mutex);
|
mutex_unlock(&hdq_data->hdq_mutex);
|
||||||
rtn:
|
rtn:
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable clocks and set the controller to HDQ/1W mode */
|
|
||||||
static int omap_hdq_get(struct hdq_data *hdq_data)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
|
|
||||||
if (ret < 0) {
|
|
||||||
ret = -EINTR;
|
|
||||||
goto rtn;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OMAP_HDQ_MAX_USER == hdq_data->hdq_usecount) {
|
|
||||||
dev_dbg(hdq_data->dev, "attempt to exceed the max use count");
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto out;
|
|
||||||
} else {
|
|
||||||
hdq_data->hdq_usecount++;
|
|
||||||
try_module_get(THIS_MODULE);
|
|
||||||
if (1 == hdq_data->hdq_usecount) {
|
|
||||||
|
|
||||||
pm_runtime_get_sync(hdq_data->dev);
|
|
||||||
|
|
||||||
/* make sure HDQ/1W is out of reset */
|
|
||||||
if (!(hdq_reg_in(hdq_data, OMAP_HDQ_SYSSTATUS) &
|
|
||||||
OMAP_HDQ_SYSSTATUS_RESETDONE)) {
|
|
||||||
ret = _omap_hdq_reset(hdq_data);
|
|
||||||
if (ret)
|
|
||||||
/* back up the count */
|
|
||||||
hdq_data->hdq_usecount--;
|
|
||||||
} else {
|
|
||||||
/* select HDQ/1W mode & enable clocks */
|
|
||||||
hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS,
|
|
||||||
OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
|
|
||||||
OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK |
|
|
||||||
hdq_data->mode);
|
|
||||||
hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG,
|
|
||||||
OMAP_HDQ_SYSCONFIG_NOIDLE);
|
|
||||||
hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
mutex_unlock(&hdq_data->hdq_mutex);
|
|
||||||
rtn:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Disable clocks to the module */
|
|
||||||
static int omap_hdq_put(struct hdq_data *hdq_data)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
|
|
||||||
if (ret < 0)
|
|
||||||
return -EINTR;
|
|
||||||
|
|
||||||
hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG,
|
|
||||||
OMAP_HDQ_SYSCONFIG_AUTOIDLE);
|
|
||||||
if (0 == hdq_data->hdq_usecount) {
|
|
||||||
dev_dbg(hdq_data->dev, "attempt to decrement use count"
|
|
||||||
" when it is zero");
|
|
||||||
ret = -EINVAL;
|
|
||||||
} else {
|
|
||||||
hdq_data->hdq_usecount--;
|
|
||||||
module_put(THIS_MODULE);
|
|
||||||
if (0 == hdq_data->hdq_usecount)
|
|
||||||
pm_runtime_put_sync(hdq_data->dev);
|
|
||||||
}
|
|
||||||
mutex_unlock(&hdq_data->hdq_mutex);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* W1 triplet callback function - used for searching ROM addresses.
|
* W1 triplet callback function - used for searching ROM addresses.
|
||||||
* Registered only when controller is in 1-wire mode.
|
* Registered only when controller is in 1-wire mode.
|
||||||
|
@ -482,7 +347,12 @@ static u8 omap_w1_triplet(void *_hdq, u8 bdir)
|
||||||
OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK;
|
OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK;
|
||||||
u8 mask = ctrl | OMAP_HDQ_CTRL_STATUS_DIR;
|
u8 mask = ctrl | OMAP_HDQ_CTRL_STATUS_DIR;
|
||||||
|
|
||||||
omap_hdq_get(_hdq);
|
err = pm_runtime_get_sync(hdq_data->dev);
|
||||||
|
if (err < 0) {
|
||||||
|
pm_runtime_put_noidle(hdq_data->dev);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
err = mutex_lock_interruptible(&hdq_data->hdq_mutex);
|
err = mutex_lock_interruptible(&hdq_data->hdq_mutex);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
@ -490,7 +360,6 @@ static u8 omap_w1_triplet(void *_hdq, u8 bdir)
|
||||||
goto rtn;
|
goto rtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
hdq_data->hdq_irqstatus = 0;
|
|
||||||
/* read id_bit */
|
/* read id_bit */
|
||||||
hdq_reg_merge(_hdq, OMAP_HDQ_CTRL_STATUS,
|
hdq_reg_merge(_hdq, OMAP_HDQ_CTRL_STATUS,
|
||||||
ctrl | OMAP_HDQ_CTRL_STATUS_DIR, mask);
|
ctrl | OMAP_HDQ_CTRL_STATUS_DIR, mask);
|
||||||
|
@ -504,7 +373,9 @@ static u8 omap_w1_triplet(void *_hdq, u8 bdir)
|
||||||
}
|
}
|
||||||
id_bit = (hdq_reg_in(_hdq, OMAP_HDQ_RX_DATA) & 0x01);
|
id_bit = (hdq_reg_in(_hdq, OMAP_HDQ_RX_DATA) & 0x01);
|
||||||
|
|
||||||
hdq_data->hdq_irqstatus = 0;
|
/* Must clear irqstatus for another RXCOMPLETE interrupt */
|
||||||
|
hdq_reset_irqstatus(hdq_data);
|
||||||
|
|
||||||
/* read comp_bit */
|
/* read comp_bit */
|
||||||
hdq_reg_merge(_hdq, OMAP_HDQ_CTRL_STATUS,
|
hdq_reg_merge(_hdq, OMAP_HDQ_CTRL_STATUS,
|
||||||
ctrl | OMAP_HDQ_CTRL_STATUS_DIR, mask);
|
ctrl | OMAP_HDQ_CTRL_STATUS_DIR, mask);
|
||||||
|
@ -547,18 +418,33 @@ static u8 omap_w1_triplet(void *_hdq, u8 bdir)
|
||||||
OMAP_HDQ_CTRL_STATUS_SINGLE);
|
OMAP_HDQ_CTRL_STATUS_SINGLE);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
hdq_reset_irqstatus(hdq_data);
|
||||||
mutex_unlock(&hdq_data->hdq_mutex);
|
mutex_unlock(&hdq_data->hdq_mutex);
|
||||||
rtn:
|
rtn:
|
||||||
omap_hdq_put(_hdq);
|
pm_runtime_mark_last_busy(hdq_data->dev);
|
||||||
|
pm_runtime_put_autosuspend(hdq_data->dev);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reset callback */
|
/* reset callback */
|
||||||
static u8 omap_w1_reset_bus(void *_hdq)
|
static u8 omap_w1_reset_bus(void *_hdq)
|
||||||
{
|
{
|
||||||
omap_hdq_get(_hdq);
|
struct hdq_data *hdq_data = _hdq;
|
||||||
omap_hdq_break(_hdq);
|
int err;
|
||||||
omap_hdq_put(_hdq);
|
|
||||||
|
err = pm_runtime_get_sync(hdq_data->dev);
|
||||||
|
if (err < 0) {
|
||||||
|
pm_runtime_put_noidle(hdq_data->dev);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
omap_hdq_break(hdq_data);
|
||||||
|
|
||||||
|
pm_runtime_mark_last_busy(hdq_data->dev);
|
||||||
|
pm_runtime_put_autosuspend(hdq_data->dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -569,37 +455,19 @@ static u8 omap_w1_read_byte(void *_hdq)
|
||||||
u8 val = 0;
|
u8 val = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* First write to initialize the transfer */
|
ret = pm_runtime_get_sync(hdq_data->dev);
|
||||||
if (hdq_data->init_trans == 0)
|
if (ret < 0) {
|
||||||
omap_hdq_get(hdq_data);
|
pm_runtime_put_noidle(hdq_data->dev);
|
||||||
|
|
||||||
ret = hdq_read_byte(hdq_data, &val);
|
|
||||||
if (ret) {
|
|
||||||
ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
|
|
||||||
return -EINTR;
|
|
||||||
}
|
|
||||||
hdq_data->init_trans = 0;
|
|
||||||
mutex_unlock(&hdq_data->hdq_mutex);
|
|
||||||
omap_hdq_put(hdq_data);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
hdq_disable_interrupt(hdq_data, OMAP_HDQ_CTRL_STATUS,
|
ret = hdq_read_byte(hdq_data, &val);
|
||||||
~OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK);
|
if (ret)
|
||||||
|
ret = -1;
|
||||||
|
|
||||||
/* Write followed by a read, release the module */
|
pm_runtime_mark_last_busy(hdq_data->dev);
|
||||||
if (hdq_data->init_trans) {
|
pm_runtime_put_autosuspend(hdq_data->dev);
|
||||||
ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
|
|
||||||
return -EINTR;
|
|
||||||
}
|
|
||||||
hdq_data->init_trans = 0;
|
|
||||||
mutex_unlock(&hdq_data->hdq_mutex);
|
|
||||||
omap_hdq_put(hdq_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
@ -611,9 +479,12 @@ static void omap_w1_write_byte(void *_hdq, u8 byte)
|
||||||
int ret;
|
int ret;
|
||||||
u8 status;
|
u8 status;
|
||||||
|
|
||||||
/* First write to initialize the transfer */
|
ret = pm_runtime_get_sync(hdq_data->dev);
|
||||||
if (hdq_data->init_trans == 0)
|
if (ret < 0) {
|
||||||
omap_hdq_get(hdq_data);
|
pm_runtime_put_noidle(hdq_data->dev);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need to reset the slave before
|
* We need to reset the slave before
|
||||||
|
@ -623,31 +494,15 @@ static void omap_w1_write_byte(void *_hdq, u8 byte)
|
||||||
if (byte == W1_SKIP_ROM)
|
if (byte == W1_SKIP_ROM)
|
||||||
omap_hdq_break(hdq_data);
|
omap_hdq_break(hdq_data);
|
||||||
|
|
||||||
ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
hdq_data->init_trans++;
|
|
||||||
mutex_unlock(&hdq_data->hdq_mutex);
|
|
||||||
|
|
||||||
ret = hdq_write_byte(hdq_data, byte, &status);
|
ret = hdq_write_byte(hdq_data, byte, &status);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_dbg(hdq_data->dev, "TX failure:Ctrl status %x\n", status);
|
dev_dbg(hdq_data->dev, "TX failure:Ctrl status %x\n", status);
|
||||||
return;
|
goto out_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Second write, data transferred. Release the module */
|
out_err:
|
||||||
if (hdq_data->init_trans > 1) {
|
pm_runtime_mark_last_busy(hdq_data->dev);
|
||||||
omap_hdq_put(hdq_data);
|
pm_runtime_put_autosuspend(hdq_data->dev);
|
||||||
ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
hdq_data->init_trans = 0;
|
|
||||||
mutex_unlock(&hdq_data->hdq_mutex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct w1_bus_master omap_w1_master = {
|
static struct w1_bus_master omap_w1_master = {
|
||||||
|
@ -656,6 +511,35 @@ static struct w1_bus_master omap_w1_master = {
|
||||||
.reset_bus = omap_w1_reset_bus,
|
.reset_bus = omap_w1_reset_bus,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int __maybe_unused omap_hdq_runtime_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct hdq_data *hdq_data = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
hdq_reg_out(hdq_data, 0, hdq_data->mode);
|
||||||
|
hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused omap_hdq_runtime_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct hdq_data *hdq_data = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
/* select HDQ/1W mode & enable clocks */
|
||||||
|
hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS,
|
||||||
|
OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
|
||||||
|
OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK |
|
||||||
|
hdq_data->mode);
|
||||||
|
hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dev_pm_ops omap_hdq_pm_ops = {
|
||||||
|
SET_RUNTIME_PM_OPS(omap_hdq_runtime_suspend,
|
||||||
|
omap_hdq_runtime_resume, NULL)
|
||||||
|
};
|
||||||
|
|
||||||
static int omap_hdq_probe(struct platform_device *pdev)
|
static int omap_hdq_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
|
@ -677,21 +561,25 @@ static int omap_hdq_probe(struct platform_device *pdev)
|
||||||
if (IS_ERR(hdq_data->hdq_base))
|
if (IS_ERR(hdq_data->hdq_base))
|
||||||
return PTR_ERR(hdq_data->hdq_base);
|
return PTR_ERR(hdq_data->hdq_base);
|
||||||
|
|
||||||
hdq_data->hdq_usecount = 0;
|
|
||||||
hdq_data->rrw = 0;
|
|
||||||
mutex_init(&hdq_data->hdq_mutex);
|
mutex_init(&hdq_data->hdq_mutex);
|
||||||
|
|
||||||
pm_runtime_enable(&pdev->dev);
|
ret = of_property_read_string(pdev->dev.of_node, "ti,mode", &mode);
|
||||||
ret = pm_runtime_get_sync(&pdev->dev);
|
if (ret < 0 || !strcmp(mode, "hdq")) {
|
||||||
if (ret < 0) {
|
hdq_data->mode = 0;
|
||||||
dev_dbg(&pdev->dev, "pm_runtime_get_sync failed\n");
|
omap_w1_master.search = omap_w1_search_bus;
|
||||||
goto err_w1;
|
} else {
|
||||||
|
hdq_data->mode = 1;
|
||||||
|
omap_w1_master.triplet = omap_w1_triplet;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = _omap_hdq_reset(hdq_data);
|
pm_runtime_enable(&pdev->dev);
|
||||||
if (ret) {
|
pm_runtime_use_autosuspend(&pdev->dev);
|
||||||
dev_dbg(&pdev->dev, "reset failed\n");
|
pm_runtime_set_autosuspend_delay(&pdev->dev, 300);
|
||||||
goto err_irq;
|
ret = pm_runtime_get_sync(&pdev->dev);
|
||||||
|
if (ret < 0) {
|
||||||
|
pm_runtime_put_noidle(&pdev->dev);
|
||||||
|
dev_dbg(&pdev->dev, "pm_runtime_get_sync failed\n");
|
||||||
|
goto err_w1;
|
||||||
}
|
}
|
||||||
|
|
||||||
rev = hdq_reg_in(hdq_data, OMAP_HDQ_REVISION);
|
rev = hdq_reg_in(hdq_data, OMAP_HDQ_REVISION);
|
||||||
|
@ -715,16 +603,8 @@ static int omap_hdq_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
omap_hdq_break(hdq_data);
|
omap_hdq_break(hdq_data);
|
||||||
|
|
||||||
pm_runtime_put_sync(&pdev->dev);
|
pm_runtime_mark_last_busy(&pdev->dev);
|
||||||
|
pm_runtime_put_autosuspend(&pdev->dev);
|
||||||
ret = of_property_read_string(pdev->dev.of_node, "ti,mode", &mode);
|
|
||||||
if (ret < 0 || !strcmp(mode, "hdq")) {
|
|
||||||
hdq_data->mode = 0;
|
|
||||||
omap_w1_master.search = omap_w1_search_bus;
|
|
||||||
} else {
|
|
||||||
hdq_data->mode = 1;
|
|
||||||
omap_w1_master.triplet = omap_w1_triplet;
|
|
||||||
}
|
|
||||||
|
|
||||||
omap_w1_master.data = hdq_data;
|
omap_w1_master.data = hdq_data;
|
||||||
|
|
||||||
|
@ -739,6 +619,7 @@ static int omap_hdq_probe(struct platform_device *pdev)
|
||||||
err_irq:
|
err_irq:
|
||||||
pm_runtime_put_sync(&pdev->dev);
|
pm_runtime_put_sync(&pdev->dev);
|
||||||
err_w1:
|
err_w1:
|
||||||
|
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -746,23 +627,19 @@ err_w1:
|
||||||
|
|
||||||
static int omap_hdq_remove(struct platform_device *pdev)
|
static int omap_hdq_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct hdq_data *hdq_data = platform_get_drvdata(pdev);
|
int active;
|
||||||
|
|
||||||
mutex_lock(&hdq_data->hdq_mutex);
|
active = pm_runtime_get_sync(&pdev->dev);
|
||||||
|
if (active < 0)
|
||||||
if (hdq_data->hdq_usecount) {
|
pm_runtime_put_noidle(&pdev->dev);
|
||||||
dev_dbg(&pdev->dev, "removed when use count is not zero\n");
|
|
||||||
mutex_unlock(&hdq_data->hdq_mutex);
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&hdq_data->hdq_mutex);
|
|
||||||
|
|
||||||
/* remove module dependency */
|
|
||||||
pm_runtime_disable(&pdev->dev);
|
|
||||||
|
|
||||||
w1_remove_master_device(&omap_w1_master);
|
w1_remove_master_device(&omap_w1_master);
|
||||||
|
|
||||||
|
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||||
|
if (active >= 0)
|
||||||
|
pm_runtime_put_sync(&pdev->dev);
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -779,6 +656,7 @@ static struct platform_driver omap_hdq_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "omap_hdq",
|
.name = "omap_hdq",
|
||||||
.of_match_table = omap_hdq_dt_ids,
|
.of_match_table = omap_hdq_dt_ids,
|
||||||
|
.pm = &omap_hdq_pm_ops,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
module_platform_driver(omap_hdq_driver);
|
module_platform_driver(omap_hdq_driver);
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Qualcomm interconnect IDs
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019, Linaro Ltd.
|
||||||
|
* Author: Georgi Djakov <georgi.djakov@linaro.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_MSM8916_H
|
||||||
|
#define __DT_BINDINGS_INTERCONNECT_QCOM_MSM8916_H
|
||||||
|
|
||||||
|
#define BIMC_SNOC_SLV 0
|
||||||
|
#define MASTER_JPEG 1
|
||||||
|
#define MASTER_MDP_PORT0 2
|
||||||
|
#define MASTER_QDSS_BAM 3
|
||||||
|
#define MASTER_QDSS_ETR 4
|
||||||
|
#define MASTER_SNOC_CFG 5
|
||||||
|
#define MASTER_VFE 6
|
||||||
|
#define MASTER_VIDEO_P0 7
|
||||||
|
#define SNOC_MM_INT_0 8
|
||||||
|
#define SNOC_MM_INT_1 9
|
||||||
|
#define SNOC_MM_INT_2 10
|
||||||
|
#define SNOC_MM_INT_BIMC 11
|
||||||
|
#define PCNOC_SNOC_SLV 12
|
||||||
|
#define SLAVE_APSS 13
|
||||||
|
#define SLAVE_CATS_128 14
|
||||||
|
#define SLAVE_OCMEM_64 15
|
||||||
|
#define SLAVE_IMEM 16
|
||||||
|
#define SLAVE_QDSS_STM 17
|
||||||
|
#define SLAVE_SRVC_SNOC 18
|
||||||
|
#define SNOC_BIMC_0_MAS 19
|
||||||
|
#define SNOC_BIMC_1_MAS 20
|
||||||
|
#define SNOC_INT_0 21
|
||||||
|
#define SNOC_INT_1 22
|
||||||
|
#define SNOC_INT_BIMC 23
|
||||||
|
#define SNOC_PCNOC_MAS 24
|
||||||
|
#define SNOC_QDSS_INT 25
|
||||||
|
|
||||||
|
#define BIMC_SNOC_MAS 0
|
||||||
|
#define MASTER_AMPSS_M0 1
|
||||||
|
#define MASTER_GRAPHICS_3D 2
|
||||||
|
#define MASTER_TCU0 3
|
||||||
|
#define MASTER_TCU1 4
|
||||||
|
#define SLAVE_AMPSS_L2 5
|
||||||
|
#define SLAVE_EBI_CH0 6
|
||||||
|
#define SNOC_BIMC_0_SLV 7
|
||||||
|
#define SNOC_BIMC_1_SLV 8
|
||||||
|
|
||||||
|
#define MASTER_BLSP_1 0
|
||||||
|
#define MASTER_DEHR 1
|
||||||
|
#define MASTER_LPASS 2
|
||||||
|
#define MASTER_CRYPTO_CORE0 3
|
||||||
|
#define MASTER_SDCC_1 4
|
||||||
|
#define MASTER_SDCC_2 5
|
||||||
|
#define MASTER_SPDM 6
|
||||||
|
#define MASTER_USB_HS 7
|
||||||
|
#define PCNOC_INT_0 8
|
||||||
|
#define PCNOC_INT_1 9
|
||||||
|
#define PCNOC_MAS_0 10
|
||||||
|
#define PCNOC_MAS_1 11
|
||||||
|
#define PCNOC_SLV_0 12
|
||||||
|
#define PCNOC_SLV_1 13
|
||||||
|
#define PCNOC_SLV_2 14
|
||||||
|
#define PCNOC_SLV_3 15
|
||||||
|
#define PCNOC_SLV_4 16
|
||||||
|
#define PCNOC_SLV_8 17
|
||||||
|
#define PCNOC_SLV_9 18
|
||||||
|
#define PCNOC_SNOC_MAS 19
|
||||||
|
#define SLAVE_BIMC_CFG 20
|
||||||
|
#define SLAVE_BLSP_1 21
|
||||||
|
#define SLAVE_BOOT_ROM 22
|
||||||
|
#define SLAVE_CAMERA_CFG 23
|
||||||
|
#define SLAVE_CLK_CTL 24
|
||||||
|
#define SLAVE_CRYPTO_0_CFG 25
|
||||||
|
#define SLAVE_DEHR_CFG 26
|
||||||
|
#define SLAVE_DISPLAY_CFG 27
|
||||||
|
#define SLAVE_GRAPHICS_3D_CFG 28
|
||||||
|
#define SLAVE_IMEM_CFG 29
|
||||||
|
#define SLAVE_LPASS 30
|
||||||
|
#define SLAVE_MPM 31
|
||||||
|
#define SLAVE_MSG_RAM 32
|
||||||
|
#define SLAVE_MSS 33
|
||||||
|
#define SLAVE_PDM 34
|
||||||
|
#define SLAVE_PMIC_ARB 35
|
||||||
|
#define SLAVE_PCNOC_CFG 36
|
||||||
|
#define SLAVE_PRNG 37
|
||||||
|
#define SLAVE_QDSS_CFG 38
|
||||||
|
#define SLAVE_RBCPR_CFG 39
|
||||||
|
#define SLAVE_SDCC_1 40
|
||||||
|
#define SLAVE_SDCC_2 41
|
||||||
|
#define SLAVE_SECURITY 42
|
||||||
|
#define SLAVE_SNOC_CFG 43
|
||||||
|
#define SLAVE_SPDM 44
|
||||||
|
#define SLAVE_TCSR 45
|
||||||
|
#define SLAVE_TLMM 46
|
||||||
|
#define SLAVE_USB_HS 47
|
||||||
|
#define SLAVE_VENUS_CFG 48
|
||||||
|
#define SNOC_PCNOC_SLV 49
|
||||||
|
|
||||||
|
#endif
|
|
@ -17,6 +17,7 @@
|
||||||
#define PCI_ID_ALCOR_MICRO 0x1AEA
|
#define PCI_ID_ALCOR_MICRO 0x1AEA
|
||||||
#define PCI_ID_AU6601 0x6601
|
#define PCI_ID_AU6601 0x6601
|
||||||
#define PCI_ID_AU6621 0x6621
|
#define PCI_ID_AU6621 0x6621
|
||||||
|
#define PCI_ID_AU6625 0x6625
|
||||||
|
|
||||||
#define MHZ_TO_HZ(freq) ((freq) * 1000 * 1000)
|
#define MHZ_TO_HZ(freq) ((freq) * 1000 * 1000)
|
||||||
|
|
||||||
|
|
|
@ -170,7 +170,7 @@ struct extcon_dev;
|
||||||
* Following APIs get the connected state of each external connector.
|
* Following APIs get the connected state of each external connector.
|
||||||
* The 'id' argument indicates the defined external connector.
|
* The 'id' argument indicates the defined external connector.
|
||||||
*/
|
*/
|
||||||
extern int extcon_get_state(struct extcon_dev *edev, unsigned int id);
|
int extcon_get_state(struct extcon_dev *edev, unsigned int id);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Following APIs get the property of each external connector.
|
* Following APIs get the property of each external connector.
|
||||||
|
@ -181,10 +181,10 @@ extern int extcon_get_state(struct extcon_dev *edev, unsigned int id);
|
||||||
* for each external connector. They are used to get the capability of the
|
* for each external connector. They are used to get the capability of the
|
||||||
* property of each external connector based on the id and property.
|
* property of each external connector based on the id and property.
|
||||||
*/
|
*/
|
||||||
extern int extcon_get_property(struct extcon_dev *edev, unsigned int id,
|
int extcon_get_property(struct extcon_dev *edev, unsigned int id,
|
||||||
unsigned int prop,
|
unsigned int prop,
|
||||||
union extcon_property_value *prop_val);
|
union extcon_property_value *prop_val);
|
||||||
extern int extcon_get_property_capability(struct extcon_dev *edev,
|
int extcon_get_property_capability(struct extcon_dev *edev,
|
||||||
unsigned int id, unsigned int prop);
|
unsigned int id, unsigned int prop);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -196,38 +196,38 @@ extern int extcon_get_property_capability(struct extcon_dev *edev,
|
||||||
* extcon_register_notifier_all(*edev, *nb) : Register a notifier block
|
* extcon_register_notifier_all(*edev, *nb) : Register a notifier block
|
||||||
* for all supported external connectors of the extcon.
|
* for all supported external connectors of the extcon.
|
||||||
*/
|
*/
|
||||||
extern int extcon_register_notifier(struct extcon_dev *edev, unsigned int id,
|
int extcon_register_notifier(struct extcon_dev *edev, unsigned int id,
|
||||||
struct notifier_block *nb);
|
struct notifier_block *nb);
|
||||||
extern int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id,
|
int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id,
|
||||||
struct notifier_block *nb);
|
struct notifier_block *nb);
|
||||||
extern int devm_extcon_register_notifier(struct device *dev,
|
int devm_extcon_register_notifier(struct device *dev,
|
||||||
struct extcon_dev *edev, unsigned int id,
|
struct extcon_dev *edev, unsigned int id,
|
||||||
struct notifier_block *nb);
|
struct notifier_block *nb);
|
||||||
extern void devm_extcon_unregister_notifier(struct device *dev,
|
void devm_extcon_unregister_notifier(struct device *dev,
|
||||||
struct extcon_dev *edev, unsigned int id,
|
struct extcon_dev *edev, unsigned int id,
|
||||||
struct notifier_block *nb);
|
struct notifier_block *nb);
|
||||||
|
|
||||||
extern int extcon_register_notifier_all(struct extcon_dev *edev,
|
int extcon_register_notifier_all(struct extcon_dev *edev,
|
||||||
struct notifier_block *nb);
|
struct notifier_block *nb);
|
||||||
extern int extcon_unregister_notifier_all(struct extcon_dev *edev,
|
int extcon_unregister_notifier_all(struct extcon_dev *edev,
|
||||||
struct notifier_block *nb);
|
struct notifier_block *nb);
|
||||||
extern int devm_extcon_register_notifier_all(struct device *dev,
|
int devm_extcon_register_notifier_all(struct device *dev,
|
||||||
struct extcon_dev *edev,
|
struct extcon_dev *edev,
|
||||||
struct notifier_block *nb);
|
struct notifier_block *nb);
|
||||||
extern void devm_extcon_unregister_notifier_all(struct device *dev,
|
void devm_extcon_unregister_notifier_all(struct device *dev,
|
||||||
struct extcon_dev *edev,
|
struct extcon_dev *edev,
|
||||||
struct notifier_block *nb);
|
struct notifier_block *nb);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Following APIs get the extcon_dev from devicetree or by through extcon name.
|
* Following APIs get the extcon_dev from devicetree or by through extcon name.
|
||||||
*/
|
*/
|
||||||
extern struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name);
|
struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name);
|
||||||
extern struct extcon_dev *extcon_find_edev_by_node(struct device_node *node);
|
struct extcon_dev *extcon_find_edev_by_node(struct device_node *node);
|
||||||
extern struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev,
|
struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev,
|
||||||
int index);
|
int index);
|
||||||
|
|
||||||
/* Following API get the name of extcon device. */
|
/* Following API get the name of extcon device. */
|
||||||
extern const char *extcon_get_edev_name(struct extcon_dev *edev);
|
const char *extcon_get_edev_name(struct extcon_dev *edev);
|
||||||
|
|
||||||
#else /* CONFIG_EXTCON */
|
#else /* CONFIG_EXTCON */
|
||||||
static inline int extcon_get_state(struct extcon_dev *edev, unsigned int id)
|
static inline int extcon_get_state(struct extcon_dev *edev, unsigned int id)
|
||||||
|
|
|
@ -92,17 +92,26 @@ struct icc_node {
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_INTERCONNECT)
|
#if IS_ENABLED(CONFIG_INTERCONNECT)
|
||||||
|
|
||||||
|
int icc_std_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
|
||||||
|
u32 peak_bw, u32 *agg_avg, u32 *agg_peak);
|
||||||
struct icc_node *icc_node_create(int id);
|
struct icc_node *icc_node_create(int id);
|
||||||
void icc_node_destroy(int id);
|
void icc_node_destroy(int id);
|
||||||
int icc_link_create(struct icc_node *node, const int dst_id);
|
int icc_link_create(struct icc_node *node, const int dst_id);
|
||||||
int icc_link_destroy(struct icc_node *src, struct icc_node *dst);
|
int icc_link_destroy(struct icc_node *src, struct icc_node *dst);
|
||||||
void icc_node_add(struct icc_node *node, struct icc_provider *provider);
|
void icc_node_add(struct icc_node *node, struct icc_provider *provider);
|
||||||
void icc_node_del(struct icc_node *node);
|
void icc_node_del(struct icc_node *node);
|
||||||
|
int icc_nodes_remove(struct icc_provider *provider);
|
||||||
int icc_provider_add(struct icc_provider *provider);
|
int icc_provider_add(struct icc_provider *provider);
|
||||||
int icc_provider_del(struct icc_provider *provider);
|
int icc_provider_del(struct icc_provider *provider);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
static inline int icc_std_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
|
||||||
|
u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
|
||||||
|
{
|
||||||
|
return -ENOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
static inline struct icc_node *icc_node_create(int id)
|
static inline struct icc_node *icc_node_create(int id)
|
||||||
{
|
{
|
||||||
return ERR_PTR(-ENOTSUPP);
|
return ERR_PTR(-ENOTSUPP);
|
||||||
|
@ -130,6 +139,11 @@ void icc_node_del(struct icc_node *node)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int icc_nodes_remove(struct icc_provider *provider)
|
||||||
|
{
|
||||||
|
return -ENOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int icc_provider_add(struct icc_provider *provider)
|
static inline int icc_provider_add(struct icc_provider *provider)
|
||||||
{
|
{
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
|
|
|
@ -546,7 +546,8 @@ struct sdw_slave_ops {
|
||||||
* @debugfs: Slave debugfs
|
* @debugfs: Slave debugfs
|
||||||
* @node: node for bus list
|
* @node: node for bus list
|
||||||
* @port_ready: Port ready completion flag for each Slave port
|
* @port_ready: Port ready completion flag for each Slave port
|
||||||
* @dev_num: Device Number assigned by Bus
|
* @dev_num: Current Device Number, values can be 0 or dev_num_sticky
|
||||||
|
* @dev_num_sticky: one-time static Device Number assigned by Bus
|
||||||
* @probed: boolean tracking driver state
|
* @probed: boolean tracking driver state
|
||||||
* @probe_complete: completion utility to control potential races
|
* @probe_complete: completion utility to control potential races
|
||||||
* on startup between driver probe/initialization and SoundWire
|
* on startup between driver probe/initialization and SoundWire
|
||||||
|
@ -575,6 +576,7 @@ struct sdw_slave {
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
struct completion *port_ready;
|
struct completion *port_ready;
|
||||||
u16 dev_num;
|
u16 dev_num;
|
||||||
|
u16 dev_num_sticky;
|
||||||
bool probed;
|
bool probed;
|
||||||
struct completion probe_complete;
|
struct completion probe_complete;
|
||||||
struct completion enumeration_complete;
|
struct completion enumeration_complete;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#define __SDW_INTEL_H
|
#define __SDW_INTEL_H
|
||||||
|
|
||||||
#include <linux/irqreturn.h>
|
#include <linux/irqreturn.h>
|
||||||
|
#include <linux/soundwire/sdw.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct sdw_intel_stream_params_data: configuration passed during
|
* struct sdw_intel_stream_params_data: configuration passed during
|
||||||
|
@ -93,6 +94,11 @@ struct sdw_intel_link_res;
|
||||||
*/
|
*/
|
||||||
#define SDW_INTEL_CLK_STOP_BUS_RESET BIT(3)
|
#define SDW_INTEL_CLK_STOP_BUS_RESET BIT(3)
|
||||||
|
|
||||||
|
struct sdw_intel_slave_id {
|
||||||
|
int link_id;
|
||||||
|
struct sdw_slave_id id;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct sdw_intel_ctx - context allocated by the controller
|
* struct sdw_intel_ctx - context allocated by the controller
|
||||||
* driver probe
|
* driver probe
|
||||||
|
@ -101,9 +107,12 @@ struct sdw_intel_link_res;
|
||||||
* hardware capabilities after all power dependencies are settled.
|
* hardware capabilities after all power dependencies are settled.
|
||||||
* @link_mask: bit-wise mask listing SoundWire links reported by the
|
* @link_mask: bit-wise mask listing SoundWire links reported by the
|
||||||
* Controller
|
* Controller
|
||||||
|
* @num_slaves: total number of devices exposed across all enabled links
|
||||||
* @handle: ACPI parent handle
|
* @handle: ACPI parent handle
|
||||||
* @links: information for each link (controller-specific and kept
|
* @links: information for each link (controller-specific and kept
|
||||||
* opaque here)
|
* opaque here)
|
||||||
|
* @ids: array of slave_id, representing Slaves exposed across all enabled
|
||||||
|
* links
|
||||||
* @link_list: list to handle interrupts across all links
|
* @link_list: list to handle interrupts across all links
|
||||||
* @shim_lock: mutex to handle concurrent rmw access to shared SHIM registers.
|
* @shim_lock: mutex to handle concurrent rmw access to shared SHIM registers.
|
||||||
*/
|
*/
|
||||||
|
@ -111,8 +120,10 @@ struct sdw_intel_ctx {
|
||||||
int count;
|
int count;
|
||||||
void __iomem *mmio_base;
|
void __iomem *mmio_base;
|
||||||
u32 link_mask;
|
u32 link_mask;
|
||||||
|
int num_slaves;
|
||||||
acpi_handle handle;
|
acpi_handle handle;
|
||||||
struct sdw_intel_link_res *links;
|
struct sdw_intel_link_res *links;
|
||||||
|
struct sdw_intel_slave_id *ids;
|
||||||
struct list_head link_list;
|
struct list_head link_list;
|
||||||
struct mutex shim_lock; /* lock for access to shared SHIM registers */
|
struct mutex shim_lock; /* lock for access to shared SHIM registers */
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||||
|
|
||||||
|
#ifndef __PVPANIC_H__
|
||||||
|
#define __PVPANIC_H__
|
||||||
|
|
||||||
|
#define PVPANIC_PANICKED (1 << 0)
|
||||||
|
#define PVPANIC_CRASH_LOADED (1 << 1)
|
||||||
|
|
||||||
|
#endif /* __PVPANIC_H__ */
|
Loading…
Reference in New Issue