提交 866147b8 编写于 作者: L Linus Torvalds

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

Pull ARM SoC driver updates from Arnd Bergmann:
 "These are updates for drivers that are tied to a particular SoC,
  including the correspondig device tree bindings:

   - A couple of reset controller changes for unisoc, uniphier, renesas
     and zte platforms

   - memory controller driver fixes for omap and tegra

   - Rockchip io domain driver updates

   - Lots of updates for qualcomm platforms, mostly touching their
     firmware and power management drivers

   - Tegra FUSE and firmware driver updateѕ

   - Support for virtio transports in the SCMI firmware framework

   - cleanup of ixp4xx drivers, towards enabling multiplatform support
     and bringing it up to date with modern platforms

   - Minor updates for keystone, mediatek, omap, renesas"

* tag 'drivers-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (96 commits)
  reset: simple: remove ZTE details in Kconfig help
  soc: rockchip: io-domain: Remove unneeded semicolon
  soc: rockchip: io-domain: add rk3568 support
  dt-bindings: power: add rk3568-pmu-io-domain support
  bus: ixp4xx: return on error in ixp4xx_exp_probe()
  soc: renesas: Prefer memcpy() over strcpy()
  firmware: tegra: Stop using seq_get_buf()
  soc/tegra: fuse: Enable fuse clock on suspend for Tegra124
  soc/tegra: fuse: Add runtime PM support
  soc/tegra: fuse: Clear fuse->clk on driver probe failure
  soc/tegra: pmc: Prevent racing with cpuilde driver
  soc/tegra: bpmp: Remove unused including <linux/version.h>
  dt-bindings: soc: ti: pruss: Add dma-coherent property
  soc: ti: Remove pm_runtime_irq_safe() usage for smartreflex
  soc: ti: pruss: Enable support for ICSSG subsystems on K3 AM64x SoCs
  dt-bindings: soc: ti: pruss: Update bindings for K3 AM64x SoCs
  firmware: arm_scmi: Use WARN_ON() to check configured transports
  firmware: arm_scmi: Fix boolconv.cocci warnings
  soc: mediatek: mmsys: Fix missing UFOE component in mt8173 table routing
  soc: mediatek: mmsys: add MT8365 support
  ...
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/ata/intel,ixp4xx-compact-flash.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Intel IXP4xx CompactFlash Card Controller
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
description: |
The IXP4xx network processors have a CompactFlash interface that presents
a CompactFlash card to the system as a true IDE (parallel ATA) device. The
device is always connected to the expansion bus of the IXP4xx SoCs using one
or two chip select areas and address translating logic on the board. The
node must be placed inside a chip select node on the IXP4xx expansion bus.
properties:
compatible:
const: intel,ixp4xx-compact-flash
reg:
items:
- description: Command interface registers
- description: Control interface registers
interrupts:
maxItems: 1
required:
- compatible
- reg
- interrupts
allOf:
- $ref: pata-common.yaml#
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
bus@c4000000 {
compatible = "intel,ixp43x-expansion-bus-controller", "syscon";
reg = <0xc4000000 0x1000>;
native-endian;
#address-cells = <2>;
#size-cells = <1>;
ranges = <0 0x0 0x50000000 0x01000000>, <1 0x0 0x51000000 0x01000000>;
dma-ranges = <0 0x0 0x50000000 0x01000000>, <1 0x0 0x51000000 0x01000000>;
ide@1,0 {
compatible = "intel,ixp4xx-compact-flash";
reg = <1 0x00000000 0x1000>, <1 0x00040000 0x1000>;
interrupt-parent = <&gpio0>;
interrupts = <12 IRQ_TYPE_EDGE_RISING>;
};
};
...
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/bus/intel,ixp4xx-expansion-bus-controller.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Intel IXP4xx Expansion Bus Controller
description: |
The IXP4xx expansion bus controller handles access to devices on the
memory-mapped expansion bus on the Intel IXP4xx family of system on chips,
including IXP42x, IXP43x, IXP45x and IXP46x.
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
properties:
$nodename:
pattern: '^bus@[0-9a-f]+$'
compatible:
items:
- enum:
- intel,ixp42x-expansion-bus-controller
- intel,ixp43x-expansion-bus-controller
- intel,ixp45x-expansion-bus-controller
- intel,ixp46x-expansion-bus-controller
- const: syscon
reg:
description: Control registers for the expansion bus, these are not
inside the memory range handled by the expansion bus.
maxItems: 1
native-endian:
$ref: /schemas/types.yaml#/definitions/flag
description: The IXP4xx has a peculiar MMIO access scheme, as it changes
the access pattern for words (swizzling) on the bus depending on whether
the SoC is running in big-endian or little-endian mode. Thus the
registers must always be accessed using native endianness.
"#address-cells":
description: |
The first cell is the chip select number.
The second cell is the address offset within the bank.
const: 2
"#size-cells":
const: 1
ranges: true
dma-ranges: true
patternProperties:
"^.*@[0-7],[0-9a-f]+$":
description: Devices attached to chip selects are represented as
subnodes.
type: object
properties:
intel,ixp4xx-eb-t1:
description: Address timing, extend address phase with n cycles.
$ref: /schemas/types.yaml#/definitions/uint32
maximum: 3
intel,ixp4xx-eb-t2:
description: Setup chip select timing, extend setup phase with n cycles.
$ref: /schemas/types.yaml#/definitions/uint32
maximum: 3
intel,ixp4xx-eb-t3:
description: Strobe timing, extend strobe phase with n cycles.
$ref: /schemas/types.yaml#/definitions/uint32
maximum: 15
intel,ixp4xx-eb-t4:
description: Hold timing, extend hold phase with n cycles.
$ref: /schemas/types.yaml#/definitions/uint32
maximum: 3
intel,ixp4xx-eb-t5:
description: Recovery timing, extend recovery phase with n cycles.
$ref: /schemas/types.yaml#/definitions/uint32
maximum: 15
intel,ixp4xx-eb-cycle-type:
description: The type of cycles to use on the expansion bus for this
chip select. 0 = Intel cycles, 1 = Motorola cycles, 2 = HPI cycles.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2]
intel,ixp4xx-eb-byte-access-on-halfword:
description: Allow byte read access on half word devices.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1]
intel,ixp4xx-eb-hpi-hrdy-pol-high:
description: Set HPI HRDY polarity to active high when using HPI.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1]
intel,ixp4xx-eb-mux-address-and-data:
description: Multiplex address and data on the data bus.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1]
intel,ixp4xx-eb-ahb-split-transfers:
description: Enable AHB split transfers.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1]
intel,ixp4xx-eb-write-enable:
description: Enable write cycles.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1]
intel,ixp4xx-eb-byte-access:
description: Expansion bus uses only 8 bits. The default is to use
16 bits.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1]
required:
- compatible
- reg
- native-endian
- "#address-cells"
- "#size-cells"
- ranges
- dma-ranges
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
bus@50000000 {
compatible = "intel,ixp42x-expansion-bus-controller", "syscon";
reg = <0xc4000000 0x28>;
native-endian;
#address-cells = <2>;
#size-cells = <1>;
ranges = <0 0x0 0x50000000 0x01000000>,
<1 0x0 0x51000000 0x01000000>;
dma-ranges = <0 0x0 0x50000000 0x01000000>,
<1 0x0 0x51000000 0x01000000>;
flash@0,0 {
compatible = "intel,ixp4xx-flash", "cfi-flash";
bank-width = <2>;
reg = <0 0x00000000 0x1000000>;
intel,ixp4xx-eb-t3 = <3>;
intel,ixp4xx-eb-cycle-type = <0>;
intel,ixp4xx-eb-byte-access-on-halfword = <1>;
intel,ixp4xx-eb-write-enable = <1>;
intel,ixp4xx-eb-byte-access = <0>;
};
serial@1,0 {
compatible = "exar,xr16l2551", "ns8250";
reg = <1 0x00000000 0x10>;
interrupt-parent = <&gpio0>;
interrupts = <4 IRQ_TYPE_LEVEL_LOW>;
clock-frequency = <1843200>;
intel,ixp4xx-eb-t3 = <3>;
intel,ixp4xx-eb-cycle-type = <1>;
intel,ixp4xx-eb-write-enable = <1>;
intel,ixp4xx-eb-byte-access = <1>;
};
};
......@@ -9,6 +9,7 @@ Required properties:
"fsl,imx53-sdma"
"fsl,imx6q-sdma"
"fsl,imx7d-sdma"
"fsl,imx6ul-sdma"
"fsl,imx8mq-sdma"
"fsl,imx8mm-sdma"
"fsl,imx8mn-sdma"
......
......@@ -34,6 +34,10 @@ properties:
- description: SCMI compliant firmware with ARM SMC/HVC transport
items:
- const: arm,scmi-smc
- description: SCMI compliant firmware with SCMI Virtio transport.
The virtio transport only supports a single device.
items:
- const: arm,scmi-virtio
interrupts:
description:
......@@ -172,6 +176,7 @@ patternProperties:
Each sub-node represents a protocol supported. If the platform
supports a dedicated communication channel for a particular protocol,
then the corresponding transport properties must be present.
The virtio transport does not support a dedicated communication channel.
properties:
reg:
......@@ -195,7 +200,6 @@ patternProperties:
required:
- compatible
- shmem
if:
properties:
......@@ -209,6 +213,7 @@ then:
required:
- mboxes
- shmem
else:
if:
......@@ -219,6 +224,7 @@ else:
then:
required:
- arm,smc-id
- shmem
examples:
- |
......
......@@ -30,6 +30,7 @@ properties:
- qcom,sc8180x-rpmhpd
- qcom,sdm845-rpmhpd
- qcom,sdx55-rpmhpd
- qcom,sm6115-rpmpd
- qcom,sm8150-rpmhpd
- qcom,sm8250-rpmhpd
- qcom,sm8350-rpmhpd
......
Rockchip SRAM for IO Voltage Domains:
-------------------------------------
IO domain voltages on some Rockchip SoCs are variable but need to be
kept in sync between the regulators and the SoC using a special
register.
A specific example using rk3288:
- If the regulator hooked up to a pin like SDMMC0_VDD is 3.3V then
bit 7 of GRF_IO_VSEL needs to be 0. If the regulator hooked up to
that same pin is 1.8V then bit 7 of GRF_IO_VSEL needs to be 1.
Said another way, this driver simply handles keeping bits in the SoC's
general register file (GRF) in sync with the actual value of a voltage
hooked up to the pins.
Note that this driver specifically doesn't include:
- any logic for deciding what voltage we should set regulators to
- any logic for deciding whether regulators (or internal SoC blocks)
should have power or not have power
If there were some other software that had the smarts of making
decisions about regulators, it would work in conjunction with this
driver. When that other software adjusted a regulator's voltage then
this driver would handle telling the SoC about it. A good example is
vqmmc for SD. In that case the dw_mmc driver simply is told about a
regulator. It changes the regulator between 3.3V and 1.8V at the
right time. This driver notices the change and makes sure that the
SoC is on the same page.
Required properties:
- compatible: should be one of:
- "rockchip,px30-io-voltage-domain" for px30
- "rockchip,px30-pmu-io-voltage-domain" for px30 pmu-domains
- "rockchip,rk3188-io-voltage-domain" for rk3188
- "rockchip,rk3228-io-voltage-domain" for rk3228
- "rockchip,rk3288-io-voltage-domain" for rk3288
- "rockchip,rk3328-io-voltage-domain" for rk3328
- "rockchip,rk3368-io-voltage-domain" for rk3368
- "rockchip,rk3368-pmu-io-voltage-domain" for rk3368 pmu-domains
- "rockchip,rk3399-io-voltage-domain" for rk3399
- "rockchip,rk3399-pmu-io-voltage-domain" for rk3399 pmu-domains
- "rockchip,rv1108-io-voltage-domain" for rv1108
- "rockchip,rv1108-pmu-io-voltage-domain" for rv1108 pmu-domains
Deprecated properties:
- rockchip,grf: phandle to the syscon managing the "general register files"
Systems should move the io-domains to a sub-node of the grf simple-mfd.
You specify supplies using the standard regulator bindings by including
a phandle the relevant regulator. All specified supplies must be able
to report their voltage. The IO Voltage Domain for any non-specified
supplies will be not be touched.
Possible supplies for PX30:
- vccio6-supply: The supply connected to VCCIO6.
- vccio1-supply: The supply connected to VCCIO1.
- vccio2-supply: The supply connected to VCCIO2.
- vccio3-supply: The supply connected to VCCIO3.
- vccio4-supply: The supply connected to VCCIO4.
- vccio5-supply: The supply connected to VCCIO5.
- vccio-oscgpi-supply: The supply connected to VCCIO_OSCGPI.
Possible supplies for PX30 pmu-domains:
- pmuio1-supply: The supply connected to PMUIO1.
- pmuio2-supply: The supply connected to PMUIO2.
Possible supplies for rk3188:
- ap0-supply: The supply connected to AP0_VCC.
- ap1-supply: The supply connected to AP1_VCC.
- cif-supply: The supply connected to CIF_VCC.
- flash-supply: The supply connected to FLASH_VCC.
- lcdc0-supply: The supply connected to LCD0_VCC.
- lcdc1-supply: The supply connected to LCD1_VCC.
- vccio0-supply: The supply connected to VCCIO0.
- vccio1-supply: The supply connected to VCCIO1.
Sometimes also labeled VCCIO1 and VCCIO2.
Possible supplies for rk3228:
- vccio1-supply: The supply connected to VCCIO1.
- vccio2-supply: The supply connected to VCCIO2.
- vccio3-supply: The supply connected to VCCIO3.
- vccio4-supply: The supply connected to VCCIO4.
Possible supplies for rk3288:
- audio-supply: The supply connected to APIO4_VDD.
- bb-supply: The supply connected to APIO5_VDD.
- dvp-supply: The supply connected to DVPIO_VDD.
- flash0-supply: The supply connected to FLASH0_VDD. Typically for eMMC
- flash1-supply: The supply connected to FLASH1_VDD. Also known as SDIO1.
- gpio30-supply: The supply connected to APIO1_VDD.
- gpio1830 The supply connected to APIO2_VDD.
- lcdc-supply: The supply connected to LCDC_VDD.
- sdcard-supply: The supply connected to SDMMC0_VDD.
- wifi-supply: The supply connected to APIO3_VDD. Also known as SDIO0.
Possible supplies for rk3368:
- audio-supply: The supply connected to APIO3_VDD.
- dvp-supply: The supply connected to DVPIO_VDD.
- flash0-supply: The supply connected to FLASH0_VDD. Typically for eMMC
- gpio30-supply: The supply connected to APIO1_VDD.
- gpio1830 The supply connected to APIO4_VDD.
- sdcard-supply: The supply connected to SDMMC0_VDD.
- wifi-supply: The supply connected to APIO2_VDD. Also known as SDIO0.
Possible supplies for rk3368 pmu-domains:
- pmu-supply: The supply connected to PMUIO_VDD.
- vop-supply: The supply connected to LCDC_VDD.
Possible supplies for rk3399:
- bt656-supply: The supply connected to APIO2_VDD.
- audio-supply: The supply connected to APIO5_VDD.
- sdmmc-supply: The supply connected to SDMMC0_VDD.
- gpio1830 The supply connected to APIO4_VDD.
Possible supplies for rk3399 pmu-domains:
- pmu1830-supply:The supply connected to PMUIO2_VDD.
Example:
io-domains {
compatible = "rockchip,rk3288-io-voltage-domain";
rockchip,grf = <&grf>;
audio-supply = <&vcc18_codec>;
bb-supply = <&vcc33_io>;
dvp-supply = <&vcc_18>;
flash0-supply = <&vcc18_flashio>;
gpio1830-supply = <&vcc33_io>;
gpio30-supply = <&vcc33_pmuio>;
lcdc-supply = <&vcc33_lcd>;
sdcard-supply = <&vccio_sd>;
wifi-supply = <&vcc18_wl>;
};
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/power/rockchip-io-domain.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Rockchip SRAM for IO Voltage Domains
maintainers:
- Heiko Stuebner <heiko@sntech.de>
description: |
IO domain voltages on some Rockchip SoCs are variable but need to be
kept in sync between the regulators and the SoC using a special
register.
A specific example using rk3288
If the regulator hooked up to a pin like SDMMC0_VDD is 3.3V then
bit 7 of GRF_IO_VSEL needs to be 0. If the regulator hooked up to
that same pin is 1.8V then bit 7 of GRF_IO_VSEL needs to be 1.
Said another way, this driver simply handles keeping bits in the SoCs
General Register File (GRF) in sync with the actual value of a voltage
hooked up to the pins.
Note that this driver specifically does not include
any logic for deciding what voltage we should set regulators to
any logic for deciding whether regulators (or internal SoC blocks)
should have power or not have power
If there were some other software that had the smarts of making
decisions about regulators, it would work in conjunction with this
driver. When that other software adjusted a regulators voltage then
this driver would handle telling the SoC about it. A good example is
vqmmc for SD. In that case the dw_mmc driver simply is told about a
regulator. It changes the regulator between 3.3V and 1.8V at the
right time. This driver notices the change and makes sure that the
SoC is on the same page.
You specify supplies using the standard regulator bindings by including
a phandle the relevant regulator. All specified supplies must be able
to report their voltage. The IO Voltage Domain for any non-specified
supplies will be not be touched.
properties:
compatible:
enum:
- rockchip,px30-io-voltage-domain
- rockchip,px30-pmu-io-voltage-domain
- rockchip,rk3188-io-voltage-domain
- rockchip,rk3228-io-voltage-domain
- rockchip,rk3288-io-voltage-domain
- rockchip,rk3328-io-voltage-domain
- rockchip,rk3368-io-voltage-domain
- rockchip,rk3368-pmu-io-voltage-domain
- rockchip,rk3399-io-voltage-domain
- rockchip,rk3399-pmu-io-voltage-domain
- rockchip,rk3568-pmu-io-voltage-domain
- rockchip,rv1108-io-voltage-domain
- rockchip,rv1108-pmu-io-voltage-domain
required:
- compatible
unevaluatedProperties: false
allOf:
- $ref: "#/$defs/px30"
- $ref: "#/$defs/px30-pmu"
- $ref: "#/$defs/rk3188"
- $ref: "#/$defs/rk3228"
- $ref: "#/$defs/rk3288"
- $ref: "#/$defs/rk3328"
- $ref: "#/$defs/rk3368"
- $ref: "#/$defs/rk3368-pmu"
- $ref: "#/$defs/rk3399"
- $ref: "#/$defs/rk3399-pmu"
- $ref: "#/$defs/rk3568-pmu"
- $ref: "#/$defs/rv1108"
- $ref: "#/$defs/rv1108-pmu"
$defs:
px30:
if:
properties:
compatible:
contains:
const: rockchip,px30-io-voltage-domain
then:
properties:
vccio1-supply:
description: The supply connected to VCCIO1.
vccio2-supply:
description: The supply connected to VCCIO2.
vccio3-supply:
description: The supply connected to VCCIO3.
vccio4-supply:
description: The supply connected to VCCIO4.
vccio5-supply:
description: The supply connected to VCCIO5.
vccio6-supply:
description: The supply connected to VCCIO6.
vccio-oscgpi-supply:
description: The supply connected to VCCIO_OSCGPI.
px30-pmu:
if:
properties:
compatible:
contains:
const: rockchip,px30-pmu-io-voltage-domain
then:
properties:
pmuio1-supply:
description: The supply connected to PMUIO1.
pmuio2-supply:
description: The supply connected to PMUIO2.
rk3188:
if:
properties:
compatible:
contains:
const: rockchip,rk3188-io-voltage-domain
then:
properties:
ap0-supply:
description: The supply connected to AP0_VCC.
ap1-supply:
description: The supply connected to AP1_VCC.
cif-supply:
description: The supply connected to CIF_VCC.
flash-supply:
description: The supply connected to FLASH_VCC.
lcdc0-supply:
description: The supply connected to LCD0_VCC.
lcdc1-supply:
description: The supply connected to LCD1_VCC.
vccio0-supply:
description: The supply connected to VCCIO0.
vccio1-supply:
description: The supply connected to VCCIO1. Also labeled as VCCIO2.
rk3228:
if:
properties:
compatible:
contains:
const: rockchip,rk3228-io-voltage-domain
then:
properties:
vccio1-supply:
description: The supply connected to VCCIO1.
vccio2-supply:
description: The supply connected to VCCIO2.
vccio3-supply:
description: The supply connected to VCCIO3.
vccio4-supply:
description: The supply connected to VCCIO4.
rk3288:
if:
properties:
compatible:
contains:
const: rockchip,rk3288-io-voltage-domain
then:
properties:
audio-supply:
description: The supply connected to APIO4_VDD.
bb-supply:
description: The supply connected to APIO5_VDD.
dvp-supply:
description: The supply connected to DVPIO_VDD.
flash0-supply:
description: The supply connected to FLASH0_VDD. Typically for eMMC.
flash1-supply:
description: The supply connected to FLASH1_VDD. Also known as SDIO1.
gpio30-supply:
description: The supply connected to APIO1_VDD.
gpio1830-supply:
description: The supply connected to APIO2_VDD.
lcdc-supply:
description: The supply connected to LCDC_VDD.
sdcard-supply:
description: The supply connected to SDMMC0_VDD.
wifi-supply:
description: The supply connected to APIO3_VDD. Also known as SDIO0.
rk3328:
if:
properties:
compatible:
contains:
const: rockchip,rk3328-io-voltage-domain
then:
properties:
vccio1-supply:
description: The supply connected to VCCIO1.
vccio2-supply:
description: The supply connected to VCCIO2.
vccio3-supply:
description: The supply connected to VCCIO3.
vccio4-supply:
description: The supply connected to VCCIO4.
vccio5-supply:
description: The supply connected to VCCIO5.
vccio6-supply:
description: The supply connected to VCCIO6.
pmuio-supply:
description: The supply connected to VCCIO_PMU.
rk3368:
if:
properties:
compatible:
contains:
const: rockchip,rk3368-io-voltage-domain
then:
properties:
audio-supply:
description: The supply connected to APIO3_VDD.
dvp-supply:
description: The supply connected to DVPIO_VDD.
flash0-supply:
description: The supply connected to FLASH0_VDD. Typically for eMMC.
gpio30-supply:
description: The supply connected to APIO1_VDD.
gpio1830-supply:
description: The supply connected to APIO4_VDD.
sdcard-supply:
description: The supply connected to SDMMC0_VDD.
wifi-supply:
description: The supply connected to APIO2_VDD. Also known as SDIO0.
rk3368-pmu:
if:
properties:
compatible:
contains:
const: rockchip,rk3368-pmu-io-voltage-domain
then:
properties:
pmu-supply:
description: The supply connected to PMUIO_VDD.
vop-supply:
description: The supply connected to LCDC_VDD.
rk3399:
if:
properties:
compatible:
contains:
const: rockchip,rk3399-io-voltage-domain
then:
properties:
audio-supply:
description: The supply connected to APIO5_VDD.
bt656-supply:
description: The supply connected to APIO2_VDD.
gpio1830-supply:
description: The supply connected to APIO4_VDD.
sdmmc-supply:
description: The supply connected to SDMMC0_VDD.
rk3399-pmu:
if:
properties:
compatible:
contains:
const: rockchip,rk3399-pmu-io-voltage-domain
then:
properties:
pmu1830-supply:
description: The supply connected to PMUIO2_VDD.
rk3568-pmu:
if:
properties:
compatible:
contains:
const: rockchip,rk3568-pmu-io-voltage-domain
then:
properties:
pmuio1-supply:
description: The supply connected to PMUIO1.
pmuio2-supply:
description: The supply connected to PMUIO2.
vccio1-supply:
description: The supply connected to VCCIO1.
vccio2-supply:
description: The supply connected to VCCIO2.
vccio3-supply:
description: The supply connected to VCCIO3.
vccio4-supply:
description: The supply connected to VCCIO4.
vccio5-supply:
description: The supply connected to VCCIO5.
vccio6-supply:
description: The supply connected to VCCIO6.
vccio7-supply:
description: The supply connected to VCCIO7.
rv1108:
if:
properties:
compatible:
contains:
const: rockchip,rv1108-io-voltage-domain
then:
properties:
vccio1-supply:
description: The supply connected to APIO1_VDD.
vccio2-supply:
description: The supply connected to APIO2_VDD.
vccio3-supply:
description: The supply connected to APIO3_VDD.
vccio5-supply:
description: The supply connected to APIO5_VDD.
vccio6-supply:
description: The supply connected to APIO6_VDD.
rv1108-pmu:
if:
properties:
compatible:
contains:
const: rockchip,rv1108-pmu-io-voltage-domain
then:
properties:
pmu-supply:
description: The supply connected to PMUIO_VDD.
examples:
- |
io-domains {
compatible = "rockchip,rk3288-io-voltage-domain";
audio-supply = <&vcc18_codec>;
bb-supply = <&vcc33_io>;
dvp-supply = <&vcc_18>;
flash0-supply = <&vcc18_flashio>;
gpio1830-supply = <&vcc33_io>;
gpio30-supply = <&vcc33_pmuio>;
lcdc-supply = <&vcc33_lcd>;
sdcard-supply = <&vccio_sd>;
wifi-supply = <&vcc18_wl>;
};
......@@ -21,6 +21,11 @@ properties:
- const: "qcom,sc7180-aoss-cc"
- const: "qcom,sdm845-aoss-cc"
- description: on SC7280 SoCs the following compatibles must be specified
items:
- const: "qcom,sc7280-aoss-cc"
- const: "qcom,sdm845-aoss-cc"
- description: on SDM845 SoCs the following compatibles must be specified
items:
- const: "qcom,sdm845-aoss-cc"
......
......@@ -21,6 +21,10 @@ properties:
- const: "qcom,sc7180-pdc-global"
- const: "qcom,sdm845-pdc-global"
- description: on SC7280 SoCs the following compatibles must be specified
items:
- const: "qcom,sc7280-pdc-global"
- description: on SDM845 SoCs the following compatibles must be specified
items:
- const: "qcom,sdm845-pdc-global"
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/reset/renesas,rzg2l-usbphy-ctrl.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas RZ/G2L USBPHY Control
maintainers:
- Biju Das <biju.das.jz@bp.renesas.com>
description:
The RZ/G2L USBPHY Control mainly controls reset and power down of the
USB/PHY.
properties:
compatible:
items:
- enum:
- renesas,r9a07g044-usbphy-ctrl # RZ/G2{L,LC}
- const: renesas,rzg2l-usbphy-ctrl
reg:
maxItems: 1
clocks:
maxItems: 1
resets:
maxItems: 1
power-domains:
maxItems: 1
'#reset-cells':
const: 1
description: |
The phandle's argument in the reset specifier is the PHY reset associated
with the USB port.
0 = Port 1 Phy reset
1 = Port 2 Phy reset
required:
- compatible
- reg
- clocks
- resets
- power-domains
- '#reset-cells'
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/r9a07g044-cpg.h>
phyrst: usbphy-ctrl@11c40000 {
compatible = "renesas,r9a07g044-usbphy-ctrl",
"renesas,rzg2l-usbphy-ctrl";
reg = <0x11c40000 0x10000>;
clocks = <&cpg CPG_MOD R9A07G044_USB_PCLK>;
resets = <&cpg R9A07G044_USB_PRESETN>;
power-domains = <&cpg>;
#reset-cells = <1>;
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/reset/socionext,uniphier-glue-reset.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Socionext UniPhier peripheral core reset in glue layer
description: |
Some peripheral core reset belongs to its own glue layer. Before using
this core reset, it is necessary to control the clocks and resets to
enable this layer. These clocks and resets should be described in each
property.
maintainers:
- Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
properties:
compatible:
enum:
- socionext,uniphier-pro4-usb3-reset
- socionext,uniphier-pro5-usb3-reset
- socionext,uniphier-pxs2-usb3-reset
- socionext,uniphier-ld20-usb3-reset
- socionext,uniphier-pxs3-usb3-reset
- socionext,uniphier-pro4-ahci-reset
- socionext,uniphier-pxs2-ahci-reset
- socionext,uniphier-pxs3-ahci-reset
reg:
maxItems: 1
"#reset-cells":
const: 1
clocks:
minItems: 1
maxItems: 2
clock-names:
oneOf:
- items: # for Pro4, Pro5
- const: gio
- const: link
- items: # for others
- const: link
resets:
minItems: 1
maxItems: 2
reset-names:
oneOf:
- items: # for Pro4, Pro5
- const: gio
- const: link
- items: # for others
- const: link
additionalProperties: false
required:
- compatible
- reg
- "#reset-cells"
- clocks
- clock-names
- resets
- reset-names
examples:
- |
usb-glue@65b00000 {
compatible = "simple-mfd";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0x65b00000 0x400>;
usb_rst: reset@0 {
compatible = "socionext,uniphier-ld20-usb3-reset";
reg = <0x0 0x4>;
#reset-cells = <1>;
clock-names = "link";
clocks = <&sys_clk 14>;
reset-names = "link";
resets = <&sys_rst 14>;
};
};
UniPhier glue reset controller
Peripheral core reset in glue layer
-----------------------------------
Some peripheral core reset belongs to its own glue layer. Before using
this core reset, it is necessary to control the clocks and resets to enable
this layer. These clocks and resets should be described in each property.
Required properties:
- compatible: Should be
"socionext,uniphier-pro4-usb3-reset" - for Pro4 SoC USB3
"socionext,uniphier-pro5-usb3-reset" - for Pro5 SoC USB3
"socionext,uniphier-pxs2-usb3-reset" - for PXs2 SoC USB3
"socionext,uniphier-ld20-usb3-reset" - for LD20 SoC USB3
"socionext,uniphier-pxs3-usb3-reset" - for PXs3 SoC USB3
"socionext,uniphier-pro4-ahci-reset" - for Pro4 SoC AHCI
"socionext,uniphier-pxs2-ahci-reset" - for PXs2 SoC AHCI
"socionext,uniphier-pxs3-ahci-reset" - for PXs3 SoC AHCI
- #reset-cells: Should be 1.
- reg: Specifies offset and length of the register set for the device.
- clocks: A list of phandles to the clock gate for the glue layer.
According to the clock-names, appropriate clocks are required.
- clock-names: Should contain
"gio", "link" - for Pro4 and Pro5 SoCs
"link" - for others
- resets: A list of phandles to the reset control for the glue layer.
According to the reset-names, appropriate resets are required.
- reset-names: Should contain
"gio", "link" - for Pro4 and Pro5 SoCs
"link" - for others
Example:
usb-glue@65b00000 {
compatible = "socionext,uniphier-ld20-dwc3-glue",
"simple-mfd";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0x65b00000 0x400>;
usb_rst: reset@0 {
compatible = "socionext,uniphier-ld20-usb3-reset";
reg = <0x0 0x4>;
#reset-cells = <1>;
clock-names = "link";
clocks = <&sys_clk 14>;
reset-names = "link";
resets = <&sys_rst 14>;
};
regulator {
...
};
phy {
...
};
...
};
Qualcomm Always-On Subsystem side channel binding
This binding describes the hardware component responsible for side channel
requests to the always-on subsystem (AOSS), used for certain power management
requests that is not handled by the standard RPMh interface. Each client in the
SoC has it's own block of message RAM and IRQ for communication with the AOSS.
The protocol used to communicate in the message RAM is known as Qualcomm
Messaging Protocol (QMP)
The AOSS side channel exposes control over a set of resources, used to control
a set of debug related clocks and to affect the low power state of resources
related to the secondary subsystems. These resources are exposed as a set of
power-domains.
- compatible:
Usage: required
Value type: <string>
Definition: must be one of:
"qcom,sc7180-aoss-qmp"
"qcom,sc7280-aoss-qmp"
"qcom,sdm845-aoss-qmp"
"qcom,sm8150-aoss-qmp"
"qcom,sm8250-aoss-qmp"
"qcom,sm8350-aoss-qmp"
- reg:
Usage: required
Value type: <prop-encoded-array>
Definition: the base address and size of the message RAM for this
client's communication with the AOSS
- interrupts:
Usage: required
Value type: <prop-encoded-array>
Definition: should specify the AOSS message IRQ for this client
- mboxes:
Usage: required
Value type: <prop-encoded-array>
Definition: reference to the mailbox representing the outgoing doorbell
in APCS for this client, as described in mailbox/mailbox.txt
- #clock-cells:
Usage: optional
Value type: <u32>
Definition: must be 0
The single clock represents the QDSS clock.
- #power-domain-cells:
Usage: optional
Value type: <u32>
Definition: must be 1
The provided power-domains are:
CDSP state (0), LPASS state (1), modem state (2), SLPI
state (3), SPSS state (4) and Venus state (5).
= SUBNODES
The AOSS side channel also provides the controls for three cooling devices,
these are expressed as subnodes of the QMP node. The name of the node is used
to identify the resource and must therefor be "cx", "mx" or "ebi".
- #cooling-cells:
Usage: optional
Value type: <u32>
Definition: must be 2
= EXAMPLE
The following example represents the AOSS side-channel message RAM and the
mechanism exposing the power-domains, as found in SDM845.
aoss_qmp: qmp@c300000 {
compatible = "qcom,sdm845-aoss-qmp";
reg = <0x0c300000 0x100000>;
interrupts = <GIC_SPI 389 IRQ_TYPE_EDGE_RISING>;
mboxes = <&apss_shared 0>;
#power-domain-cells = <1>;
cx_cdev: cx {
#cooling-cells = <2>;
};
mx_cdev: mx {
#cooling-cells = <2>;
};
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/soc/qcom/qcom,aoss-qmp.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Always-On Subsystem side channel binding
maintainers:
- Bjorn Andersson <bjorn.andersson@linaro.org>
description:
This binding describes the hardware component responsible for side channel
requests to the always-on subsystem (AOSS), used for certain power management
requests that is not handled by the standard RPMh interface. Each client in the
SoC has it's own block of message RAM and IRQ for communication with the AOSS.
The protocol used to communicate in the message RAM is known as Qualcomm
Messaging Protocol (QMP)
The AOSS side channel exposes control over a set of resources, used to control
a set of debug related clocks and to affect the low power state of resources
related to the secondary subsystems. These resources are exposed as a set of
power-domains.
properties:
compatible:
items:
- enum:
- qcom,sc7180-aoss-qmp
- qcom,sc7280-aoss-qmp
- qcom,sc8180x-aoss-qmp
- qcom,sdm845-aoss-qmp
- qcom,sm8150-aoss-qmp
- qcom,sm8250-aoss-qmp
- qcom,sm8350-aoss-qmp
- const: qcom,aoss-qmp
reg:
maxItems: 1
description:
The base address and size of the message RAM for this client's
communication with the AOSS
interrupts:
maxItems: 1
description:
Should specify the AOSS message IRQ for this client
mboxes:
maxItems: 1
description:
Reference to the mailbox representing the outgoing doorbell in APCS for
this client, as described in mailbox/mailbox.txt
"#clock-cells":
const: 0
description:
The single clock represents the QDSS clock.
"#power-domain-cells":
const: 1
description: |
The provided power-domains are:
CDSP state (0), LPASS state (1), modem state (2), SLPI
state (3), SPSS state (4) and Venus state (5).
required:
- compatible
- reg
- interrupts
- mboxes
- "#clock-cells"
additionalProperties: false
patternProperties:
"^(cx|mx|ebi)$":
type: object
description:
The AOSS side channel also provides the controls for three cooling devices,
these are expressed as subnodes of the QMP node. The name of the node is
used to identify the resource and must therefor be "cx", "mx" or "ebi".
properties:
"#cooling-cells":
const: 2
required:
- "#cooling-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
aoss_qmp: qmp@c300000 {
compatible = "qcom,sdm845-aoss-qmp", "qcom,aoss-qmp";
reg = <0x0c300000 0x100000>;
interrupts = <GIC_SPI 389 IRQ_TYPE_EDGE_RISING>;
mboxes = <&apss_shared 0>;
#clock-cells = <0>;
#power-domain-cells = <1>;
cx_cdev: cx {
#cooling-cells = <2>;
};
mx_cdev: mx {
#cooling-cells = <2>;
};
};
...
......@@ -51,6 +51,9 @@ properties:
interconnect-names:
const: qup-core
iommus:
maxItems: 1
required:
- compatible
- reg
......
......@@ -39,6 +39,7 @@ properties:
- qcom,rpm-msm8996
- qcom,rpm-msm8998
- qcom,rpm-sdm660
- qcom,rpm-sm6115
- qcom,rpm-sm6125
- qcom,rpm-qcs404
......
......@@ -15,7 +15,6 @@ properties:
- items:
- enum:
- rockchip,rk3288-sgrf
- rockchip,rv1108-pmugrf
- rockchip,rv1108-usbgrf
- const: syscon
- items:
......@@ -41,6 +40,7 @@ properties:
- rockchip,rk3568-grf
- rockchip,rk3568-pmugrf
- rockchip,rv1108-grf
- rockchip,rv1108-pmugrf
- const: syscon
- const: simple-mfd
......@@ -198,21 +198,28 @@ allOf:
compatible:
contains:
enum:
- rockchip,px30-pmugrf
- rockchip,px30-grf
- rockchip,px30-pmugrf
- rockchip,rk3188-grf
- rockchip,rk3228-grf
- rockchip,rk3288-grf
- rockchip,rk3328-grf
- rockchip,rk3368-pmugrf
- rockchip,rk3368-grf
- rockchip,rk3399-pmugrf
- rockchip,rk3368-pmugrf
- rockchip,rk3399-grf
- rockchip,rk3399-pmugrf
- rockchip,rk3568-pmugrf
- rockchip,rv1108-grf
- rockchip,rv1108-pmugrf
then:
properties:
io-domains:
description:
Documentation/devicetree/bindings/power/rockchip-io-domain.txt
type: object
$ref: "/schemas/power/rockchip-io-domain.yaml#"
unevaluatedProperties: false
examples:
- |
......
......@@ -68,6 +68,7 @@ properties:
- ti,k2g-pruss # for 66AK2G SoC family
- ti,am654-icssg # for K3 AM65x SoC family
- ti,j721e-icssg # for K3 J721E SoC family
- ti,am642-icssg # for K3 AM64x SoC family
reg:
maxItems: 1
......@@ -84,6 +85,8 @@ properties:
dma-ranges:
maxItems: 1
dma-coherent: true
power-domains:
description: |
This property is as per sci-pm-domain.txt.
......@@ -231,8 +234,8 @@ patternProperties:
description: |
Industrial Ethernet Peripheral to manage/generate Industrial Ethernet
functions such as time stamping. Each PRUSS has either 1 IEP (on AM335x,
AM437x, AM57xx & 66AK2G SoCs) or 2 IEPs (on K3 AM65x & J721E SoCs ). IEP
is used for creating PTP clocks and generating PPS signals.
AM437x, AM57xx & 66AK2G SoCs) or 2 IEPs (on K3 AM65x, J721E & AM64x SoCs).
IEP is used for creating PTP clocks and generating PPS signals.
type: object
......@@ -323,17 +326,29 @@ additionalProperties: false
# - interrupt-controller
# - pru
if:
properties:
compatible:
contains:
enum:
- ti,k2g-pruss
- ti,am654-icssg
- ti,j721e-icssg
then:
required:
- power-domains
allOf:
- if:
properties:
compatible:
contains:
enum:
- ti,k2g-pruss
- ti,am654-icssg
- ti,j721e-icssg
- ti,am642-icssg
then:
required:
- power-domains
- if:
properties:
compatible:
contains:
enum:
- ti,k2g-pruss
then:
required:
- dma-coherent
examples:
- |
......
......@@ -1501,7 +1501,7 @@ M: Miquel Raynal <miquel.raynal@bootlin.com@bootlin.com>
M: Naga Sureshkumar Relli <nagasure@xilinx.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/mtd/arm,pl353-smc.yaml
F: Documentation/devicetree/bindings/memory-controllers/arm,pl353-smc.yaml
F: drivers/memory/pl353-smc.c
ARM PRIMECELL CLCD PL110 DRIVER
......@@ -2023,10 +2023,12 @@ M: Krzysztof Halasa <khalasa@piap.pl>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/arm/intel-ixp4xx.yaml
F: Documentation/devicetree/bindings/bus/intel,ixp4xx-expansion-bus-controller.yaml
F: Documentation/devicetree/bindings/gpio/intel,ixp4xx-gpio.txt
F: Documentation/devicetree/bindings/interrupt-controller/intel,ixp4xx-interrupt.yaml
F: Documentation/devicetree/bindings/timer/intel,ixp4xx-timer.yaml
F: arch/arm/mach-ixp4xx/
F: drivers/bus/intel-ixp4xx-eb.c
F: drivers/clocksource/timer-ixp4xx.c
F: drivers/crypto/ixp4xx_crypto.c
F: drivers/gpio/gpio-ixp4xx.c
......@@ -18077,6 +18079,7 @@ F: drivers/regulator/scmi-regulator.c
F: drivers/reset/reset-scmi.c
F: include/linux/sc[mp]i_protocol.h
F: include/trace/events/scmi.h
F: include/uapi/linux/virtio_scmi.h
SYSTEM RESET/SHUTDOWN DRIVERS
M: Sebastian Reichel <sre@kernel.org>
......
......@@ -177,7 +177,7 @@
clocks = <&clks IMX6Q_CLK_ECSPI5>,
<&clks IMX6Q_CLK_ECSPI5>;
clock-names = "ipg", "per";
dmas = <&sdma 11 8 1>, <&sdma 12 8 2>;
dmas = <&sdma 11 7 1>, <&sdma 12 7 2>;
dma-names = "rx", "tx";
status = "disabled";
};
......
......@@ -334,7 +334,7 @@
clocks = <&clks IMX6QDL_CLK_ECSPI1>,
<&clks IMX6QDL_CLK_ECSPI1>;
clock-names = "ipg", "per";
dmas = <&sdma 3 8 1>, <&sdma 4 8 2>;
dmas = <&sdma 3 7 1>, <&sdma 4 7 2>;
dma-names = "rx", "tx";
status = "disabled";
};
......@@ -348,7 +348,7 @@
clocks = <&clks IMX6QDL_CLK_ECSPI2>,
<&clks IMX6QDL_CLK_ECSPI2>;
clock-names = "ipg", "per";
dmas = <&sdma 5 8 1>, <&sdma 6 8 2>;
dmas = <&sdma 5 7 1>, <&sdma 6 7 2>;
dma-names = "rx", "tx";
status = "disabled";
};
......@@ -362,7 +362,7 @@
clocks = <&clks IMX6QDL_CLK_ECSPI3>,
<&clks IMX6QDL_CLK_ECSPI3>;
clock-names = "ipg", "per";
dmas = <&sdma 7 8 1>, <&sdma 8 8 2>;
dmas = <&sdma 7 7 1>, <&sdma 8 7 2>;
dma-names = "rx", "tx";
status = "disabled";
};
......@@ -376,7 +376,7 @@
clocks = <&clks IMX6QDL_CLK_ECSPI4>,
<&clks IMX6QDL_CLK_ECSPI4>;
clock-names = "ipg", "per";
dmas = <&sdma 9 8 1>, <&sdma 10 8 2>;
dmas = <&sdma 9 7 1>, <&sdma 10 7 2>;
dma-names = "rx", "tx";
status = "disabled";
};
......
......@@ -26,7 +26,6 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/omap-gpmc.h>
#include <trace/events/power.h>
......@@ -81,8 +80,6 @@ static void omap3_core_save_context(void)
/* Save the Interrupt controller context */
omap_intc_save_context();
/* Save the GPMC context */
omap3_gpmc_save_context();
/* Save the system control module context, padconf already save above*/
omap3_control_save_context();
}
......@@ -91,8 +88,6 @@ static void omap3_core_restore_context(void)
{
/* Restore the control module context, padconf restored by h/w */
omap3_control_restore_context();
/* Restore the GPMC context */
omap3_gpmc_restore_context();
/* Restore the interrupt controller context */
omap_intc_restore_context();
}
......
......@@ -403,7 +403,7 @@ static const struct platform_suspend_ops tegra_suspend_ops = {
.enter = tegra_suspend_enter,
};
void __init tegra_init_suspend(void)
void tegra_pm_init_suspend(void)
{
enum tegra_suspend_mode mode = tegra_pmc_get_suspend_mode();
......
......@@ -25,10 +25,4 @@ void tegra30_sleep_core_init(void);
extern void (*tegra_tear_down_cpu)(void);
#ifdef CONFIG_PM_SLEEP
void tegra_init_suspend(void);
#else
static inline void tegra_init_suspend(void) {}
#endif
#endif /* _MACH_TEGRA_PM_H_ */
......@@ -84,8 +84,6 @@ static void __init tegra_dt_init(void)
static void __init tegra_dt_init_late(void)
{
tegra_init_suspend();
if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) &&
of_machine_is_compatible("compal,paz00"))
tegra_paz00_wifikill_init();
......
......@@ -13,45 +13,134 @@
*/
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/libata.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/platform_data/pata_ixp4xx_cf.h>
#include <linux/regmap.h>
#include <scsi/scsi_host.h>
#define DRV_NAME "pata_ixp4xx_cf"
#define DRV_VERSION "0.2"
#define DRV_VERSION "1.0"
static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error)
struct ixp4xx_pata {
struct ata_host *host;
struct regmap *rmap;
u32 cmd_csreg;
void __iomem *cmd;
void __iomem *ctl;
};
#define IXP4XX_EXP_TIMING_STRIDE 0x04
/* The timings for the chipselect is in bits 29..16 */
#define IXP4XX_EXP_T1_T5_MASK GENMASK(29, 16)
#define IXP4XX_EXP_PIO_0_8 0x0a470000
#define IXP4XX_EXP_PIO_1_8 0x06430000
#define IXP4XX_EXP_PIO_2_8 0x02410000
#define IXP4XX_EXP_PIO_3_8 0x00820000
#define IXP4XX_EXP_PIO_4_8 0x00400000
#define IXP4XX_EXP_PIO_0_16 0x29640000
#define IXP4XX_EXP_PIO_1_16 0x05030000
#define IXP4XX_EXP_PIO_2_16 0x00b20000
#define IXP4XX_EXP_PIO_3_16 0x00820000
#define IXP4XX_EXP_PIO_4_16 0x00400000
#define IXP4XX_EXP_BW_MASK (BIT(6)|BIT(0))
#define IXP4XX_EXP_BYTE_RD16 BIT(6) /* Byte reads on half-word devices */
#define IXP4XX_EXP_BYTE_EN BIT(0) /* Use 8bit data bus if set */
static void ixp4xx_set_8bit_timing(struct ixp4xx_pata *ixpp, u8 pio_mode)
{
switch (pio_mode) {
case XFER_PIO_0:
regmap_update_bits(ixpp->rmap, ixpp->cmd_csreg,
IXP4XX_EXP_T1_T5_MASK, IXP4XX_EXP_PIO_0_8);
break;
case XFER_PIO_1:
regmap_update_bits(ixpp->rmap, ixpp->cmd_csreg,
IXP4XX_EXP_T1_T5_MASK, IXP4XX_EXP_PIO_1_8);
break;
case XFER_PIO_2:
regmap_update_bits(ixpp->rmap, ixpp->cmd_csreg,
IXP4XX_EXP_T1_T5_MASK, IXP4XX_EXP_PIO_2_8);
break;
case XFER_PIO_3:
regmap_update_bits(ixpp->rmap, ixpp->cmd_csreg,
IXP4XX_EXP_T1_T5_MASK, IXP4XX_EXP_PIO_3_8);
break;
case XFER_PIO_4:
regmap_update_bits(ixpp->rmap, ixpp->cmd_csreg,
IXP4XX_EXP_T1_T5_MASK, IXP4XX_EXP_PIO_4_8);
break;
default:
break;
}
regmap_update_bits(ixpp->rmap, ixpp->cmd_csreg,
IXP4XX_EXP_BW_MASK, IXP4XX_EXP_BYTE_RD16|IXP4XX_EXP_BYTE_EN);
}
static void ixp4xx_set_16bit_timing(struct ixp4xx_pata *ixpp, u8 pio_mode)
{
struct ata_device *dev;
ata_for_each_dev(dev, link, ENABLED) {
ata_dev_info(dev, "configured for PIO0\n");
dev->pio_mode = XFER_PIO_0;
dev->xfer_mode = XFER_PIO_0;
dev->xfer_shift = ATA_SHIFT_PIO;
dev->flags |= ATA_DFLAG_PIO;
switch (pio_mode){
case XFER_PIO_0:
regmap_update_bits(ixpp->rmap, ixpp->cmd_csreg,
IXP4XX_EXP_T1_T5_MASK, IXP4XX_EXP_PIO_0_16);
break;
case XFER_PIO_1:
regmap_update_bits(ixpp->rmap, ixpp->cmd_csreg,
IXP4XX_EXP_T1_T5_MASK, IXP4XX_EXP_PIO_1_16);
break;
case XFER_PIO_2:
regmap_update_bits(ixpp->rmap, ixpp->cmd_csreg,
IXP4XX_EXP_T1_T5_MASK, IXP4XX_EXP_PIO_2_16);
break;
case XFER_PIO_3:
regmap_update_bits(ixpp->rmap, ixpp->cmd_csreg,
IXP4XX_EXP_T1_T5_MASK, IXP4XX_EXP_PIO_3_16);
break;
case XFER_PIO_4:
regmap_update_bits(ixpp->rmap, ixpp->cmd_csreg,
IXP4XX_EXP_T1_T5_MASK, IXP4XX_EXP_PIO_4_16);
break;
default:
break;
}
return 0;
regmap_update_bits(ixpp->rmap, ixpp->cmd_csreg,
IXP4XX_EXP_BW_MASK, IXP4XX_EXP_BYTE_RD16);
}
/* This sets up the timing on the chipselect CMD accordingly */
static void ixp4xx_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
struct ixp4xx_pata *ixpp = ap->host->private_data;
ata_dev_printk(adev, KERN_INFO, "configured for PIO%d 8bit\n",
adev->pio_mode - XFER_PIO_0);
ixp4xx_set_8bit_timing(ixpp, adev->pio_mode);
}
static unsigned int ixp4xx_mmio_data_xfer(struct ata_queued_cmd *qc,
unsigned char *buf, unsigned int buflen, int rw)
unsigned char *buf, unsigned int buflen, int rw)
{
unsigned int i;
unsigned int words = buflen >> 1;
u16 *buf16 = (u16 *) buf;
struct ata_device *adev = qc->dev;
struct ata_port *ap = qc->dev->link->ap;
void __iomem *mmio = ap->ioaddr.data_addr;
struct ixp4xx_pata_data *data = dev_get_platdata(ap->host->dev);
struct ixp4xx_pata *ixpp = ap->host->private_data;
unsigned long flags;
ata_dev_printk(adev, KERN_DEBUG, "%s %d bytes\n", (rw == READ) ? "READ" : "WRITE",
buflen);
spin_lock_irqsave(ap->lock, flags);
/* set the expansion bus in 16bit mode and restore
* 8 bit mode after the transaction.
*/
*data->cs0_cfg &= ~(0x01);
udelay(100);
ixp4xx_set_16bit_timing(ixpp, adev->pio_mode);
udelay(5);
/* Transfer multiple of 2 bytes */
if (rw == READ)
......@@ -76,8 +165,10 @@ static unsigned int ixp4xx_mmio_data_xfer(struct ata_queued_cmd *qc,
words++;
}
udelay(100);
*data->cs0_cfg |= 0x01;
ixp4xx_set_8bit_timing(ixpp, adev->pio_mode);
udelay(5);
spin_unlock_irqrestore(ap->lock, flags);
return words << 1;
}
......@@ -90,79 +181,98 @@ static struct ata_port_operations ixp4xx_port_ops = {
.inherits = &ata_sff_port_ops,
.sff_data_xfer = ixp4xx_mmio_data_xfer,
.cable_detect = ata_cable_40wire,
.set_mode = ixp4xx_set_mode,
.set_piomode = ixp4xx_set_piomode,
};
static struct ata_port_info ixp4xx_port_info = {
.flags = ATA_FLAG_NO_ATAPI,
.pio_mask = ATA_PIO4,
.port_ops = &ixp4xx_port_ops,
};
static void ixp4xx_setup_port(struct ata_port *ap,
struct ixp4xx_pata_data *data,
unsigned long raw_cs0, unsigned long raw_cs1)
struct ixp4xx_pata *ixpp,
unsigned long raw_cmd, unsigned long raw_ctl)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
unsigned long raw_cmd = raw_cs0;
unsigned long raw_ctl = raw_cs1 + 0x06;
ioaddr->cmd_addr = data->cs0;
ioaddr->altstatus_addr = data->cs1 + 0x06;
ioaddr->ctl_addr = data->cs1 + 0x06;
raw_ctl += 0x06;
ioaddr->cmd_addr = ixpp->cmd;
ioaddr->altstatus_addr = ixpp->ctl + 0x06;
ioaddr->ctl_addr = ixpp->ctl + 0x06;
ata_sff_std_ports(ioaddr);
#ifndef __ARMEB__
/* adjust the addresses to handle the address swizzling of the
* ixp4xx in little endian mode.
*/
*(unsigned long *)&ioaddr->data_addr ^= 0x02;
*(unsigned long *)&ioaddr->cmd_addr ^= 0x03;
*(unsigned long *)&ioaddr->altstatus_addr ^= 0x03;
*(unsigned long *)&ioaddr->ctl_addr ^= 0x03;
*(unsigned long *)&ioaddr->error_addr ^= 0x03;
*(unsigned long *)&ioaddr->feature_addr ^= 0x03;
*(unsigned long *)&ioaddr->nsect_addr ^= 0x03;
*(unsigned long *)&ioaddr->lbal_addr ^= 0x03;
*(unsigned long *)&ioaddr->lbam_addr ^= 0x03;
*(unsigned long *)&ioaddr->lbah_addr ^= 0x03;
*(unsigned long *)&ioaddr->device_addr ^= 0x03;
*(unsigned long *)&ioaddr->status_addr ^= 0x03;
*(unsigned long *)&ioaddr->command_addr ^= 0x03;
raw_cmd ^= 0x03;
raw_ctl ^= 0x03;
#endif
if (!IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) {
/* adjust the addresses to handle the address swizzling of the
* ixp4xx in little endian mode.
*/
*(unsigned long *)&ioaddr->data_addr ^= 0x02;
*(unsigned long *)&ioaddr->cmd_addr ^= 0x03;
*(unsigned long *)&ioaddr->altstatus_addr ^= 0x03;
*(unsigned long *)&ioaddr->ctl_addr ^= 0x03;
*(unsigned long *)&ioaddr->error_addr ^= 0x03;
*(unsigned long *)&ioaddr->feature_addr ^= 0x03;
*(unsigned long *)&ioaddr->nsect_addr ^= 0x03;
*(unsigned long *)&ioaddr->lbal_addr ^= 0x03;
*(unsigned long *)&ioaddr->lbam_addr ^= 0x03;
*(unsigned long *)&ioaddr->lbah_addr ^= 0x03;
*(unsigned long *)&ioaddr->device_addr ^= 0x03;
*(unsigned long *)&ioaddr->status_addr ^= 0x03;
*(unsigned long *)&ioaddr->command_addr ^= 0x03;
raw_cmd ^= 0x03;
raw_ctl ^= 0x03;
}
ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", raw_cmd, raw_ctl);
}
static int ixp4xx_pata_probe(struct platform_device *pdev)
{
struct resource *cs0, *cs1;
struct ata_host *host;
struct ata_port *ap;
struct ixp4xx_pata_data *data = dev_get_platdata(&pdev->dev);
struct resource *cmd, *ctl;
struct ata_port_info pi = ixp4xx_port_info;
const struct ata_port_info *ppi[] = { &pi, NULL };
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct ixp4xx_pata *ixpp;
u32 csindex;
int ret;
int irq;
cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
cmd = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ctl = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!cs0 || !cs1)
if (!cmd || !ctl)
return -EINVAL;
/* allocate host */
host = ata_host_alloc(&pdev->dev, 1);
if (!host)
ixpp = devm_kzalloc(dev, sizeof(*ixpp), GFP_KERNEL);
if (!ixpp)
return -ENOMEM;
/* acquire resources and fill host */
ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
ixpp->rmap = syscon_node_to_regmap(np->parent);
if (IS_ERR(ixpp->rmap))
return dev_err_probe(dev, PTR_ERR(ixpp->rmap), "no regmap\n");
/* Inspect our address to figure out what chipselect the CMD is on */
ret = of_property_read_u32_index(np, "reg", 0, &csindex);
if (ret)
return ret;
return dev_err_probe(dev, ret, "can't inspect CMD address\n");
dev_info(dev, "using CS%d for PIO timing configuration\n", csindex);
ixpp->cmd_csreg = csindex * IXP4XX_EXP_TIMING_STRIDE;
data->cs0 = devm_ioremap(&pdev->dev, cs0->start, 0x1000);
data->cs1 = devm_ioremap(&pdev->dev, cs1->start, 0x1000);
ixpp->host = ata_host_alloc_pinfo(dev, ppi, 1);
if (!ixpp->host)
return -ENOMEM;
ixpp->host->private_data = ixpp;
if (!data->cs0 || !data->cs1)
ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
if (ret)
return ret;
ixpp->cmd = devm_ioremap_resource(dev, cmd);
ixpp->ctl = devm_ioremap_resource(dev, ctl);
if (IS_ERR(ixpp->cmd) || IS_ERR(ixpp->ctl))
return -ENOMEM;
irq = platform_get_irq(pdev, 0);
......@@ -173,27 +283,23 @@ static int ixp4xx_pata_probe(struct platform_device *pdev)
else
return -EINVAL;
/* Setup expansion bus chip selects */
*data->cs0_cfg = data->cs0_bits;
*data->cs1_cfg = data->cs1_bits;
ap = host->ports[0];
ap->ops = &ixp4xx_port_ops;
ap->pio_mask = ATA_PIO4;
ap->flags |= ATA_FLAG_NO_ATAPI;
/* Just one port to set up */
ixp4xx_setup_port(ixpp->host->ports[0], ixpp, cmd->start, ctl->start);
ixp4xx_setup_port(ap, data, cs0->start, cs1->start);
ata_print_version_once(dev, DRV_VERSION);
ata_print_version_once(&pdev->dev, DRV_VERSION);
/* activate host */
return ata_host_activate(host, irq, ata_sff_interrupt, 0, &ixp4xx_sht);
return ata_host_activate(ixpp->host, irq, ata_sff_interrupt, 0, &ixp4xx_sht);
}
static const struct of_device_id ixp4xx_pata_of_match[] = {
{ .compatible = "intel,ixp4xx-compact-flash", },
{ },
};
static struct platform_driver ixp4xx_pata_platform_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = ixp4xx_pata_of_match,
},
.probe = ixp4xx_pata_probe,
.remove = ata_platform_remove_one,
......
......@@ -95,6 +95,17 @@ config IMX_WEIM
The WEIM(Wireless External Interface Module) works like a bus.
You can attach many different devices on it, such as NOR, onenand.
config INTEL_IXP4XX_EB
bool "Intel IXP4xx expansion bus interface driver"
depends on HAS_IOMEM
depends on ARCH_IXP4XX || COMPILE_TEST
default ARCH_IXP4XX
select MFD_SYSCON
help
Driver for the Intel IXP4xx expansion bus interface. The driver is
needed to set up various chip select configuration parameters before
devices on the expansion bus can be discovered.
config MIPS_CDMM
bool "MIPS Common Device Memory Map (CDMM) Driver"
depends on CPU_MIPSR2 || CPU_MIPSR5
......
......@@ -16,6 +16,7 @@ obj-$(CONFIG_FSL_MC_BUS) += fsl-mc/
obj-$(CONFIG_BT1_APB) += bt1-apb.o
obj-$(CONFIG_BT1_AXI) += bt1-axi.o
obj-$(CONFIG_IMX_WEIM) += imx-weim.o
obj-$(CONFIG_INTEL_IXP4XX_EB) += intel-ixp4xx-eb.o
obj-$(CONFIG_MIPS_CDMM) += mips_cdmm.o
obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel IXP4xx Expansion Bus Controller
* Copyright (C) 2021 Linaro Ltd.
*
* Author: Linus Walleij <linus.walleij@linaro.org>
*/
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/log2.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#define IXP4XX_EXP_NUM_CS 8
#define IXP4XX_EXP_TIMING_CS0 0x00
#define IXP4XX_EXP_TIMING_CS1 0x04
#define IXP4XX_EXP_TIMING_CS2 0x08
#define IXP4XX_EXP_TIMING_CS3 0x0c
#define IXP4XX_EXP_TIMING_CS4 0x10
#define IXP4XX_EXP_TIMING_CS5 0x14
#define IXP4XX_EXP_TIMING_CS6 0x18
#define IXP4XX_EXP_TIMING_CS7 0x1c
/* Bits inside each CS timing register */
#define IXP4XX_EXP_TIMING_STRIDE 0x04
#define IXP4XX_EXP_CS_EN BIT(31)
#define IXP456_EXP_PAR_EN BIT(30) /* Only on IXP45x and IXP46x */
#define IXP4XX_EXP_T1_MASK GENMASK(28, 27)
#define IXP4XX_EXP_T1_SHIFT 28
#define IXP4XX_EXP_T2_MASK GENMASK(27, 26)
#define IXP4XX_EXP_T2_SHIFT 26
#define IXP4XX_EXP_T3_MASK GENMASK(25, 22)
#define IXP4XX_EXP_T3_SHIFT 22
#define IXP4XX_EXP_T4_MASK GENMASK(21, 20)
#define IXP4XX_EXP_T4_SHIFT 20
#define IXP4XX_EXP_T5_MASK GENMASK(19, 16)
#define IXP4XX_EXP_T5_SHIFT 16
#define IXP4XX_EXP_CYC_TYPE_MASK GENMASK(15, 14)
#define IXP4XX_EXP_CYC_TYPE_SHIFT 14
#define IXP4XX_EXP_SIZE_MASK GENMASK(13, 10)
#define IXP4XX_EXP_SIZE_SHIFT 10
#define IXP4XX_EXP_CNFG_0 BIT(9) /* Always zero */
#define IXP43X_EXP_SYNC_INTEL BIT(8) /* Only on IXP43x */
#define IXP43X_EXP_EXP_CHIP BIT(7) /* Only on IXP43x */
#define IXP4XX_EXP_BYTE_RD16 BIT(6)
#define IXP4XX_EXP_HRDY_POL BIT(5) /* Only on IXP42x */
#define IXP4XX_EXP_MUX_EN BIT(4)
#define IXP4XX_EXP_SPLT_EN BIT(3)
#define IXP4XX_EXP_WORD BIT(2) /* Always zero */
#define IXP4XX_EXP_WR_EN BIT(1)
#define IXP4XX_EXP_BYTE_EN BIT(0)
#define IXP42X_RESERVED (BIT(30)|IXP4XX_EXP_CNFG_0|BIT(8)|BIT(7)|IXP4XX_EXP_WORD)
#define IXP43X_RESERVED (BIT(30)|IXP4XX_EXP_CNFG_0|BIT(5)|IXP4XX_EXP_WORD)
#define IXP4XX_EXP_CNFG0 0x20
#define IXP4XX_EXP_CNFG0_MEM_MAP BIT(31)
#define IXP4XX_EXP_CNFG1 0x24
#define IXP4XX_EXP_BOOT_BASE 0x00000000
#define IXP4XX_EXP_NORMAL_BASE 0x50000000
#define IXP4XX_EXP_STRIDE 0x01000000
/* Fuses on the IXP43x */
#define IXP43X_EXP_UNIT_FUSE_RESET 0x28
#define IXP43x_EXP_FUSE_SPEED_MASK GENMASK(23, 22)
/* Number of device tree values in "reg" */
#define IXP4XX_OF_REG_SIZE 3
struct ixp4xx_eb {
struct device *dev;
struct regmap *rmap;
u32 bus_base;
bool is_42x;
bool is_43x;
};
struct ixp4xx_exp_tim_prop {
const char *prop;
u32 max;
u32 mask;
u16 shift;
};
static const struct ixp4xx_exp_tim_prop ixp4xx_exp_tim_props[] = {
{
.prop = "intel,ixp4xx-eb-t1",
.max = 3,
.mask = IXP4XX_EXP_T1_MASK,
.shift = IXP4XX_EXP_T1_SHIFT,
},
{
.prop = "intel,ixp4xx-eb-t2",
.max = 3,
.mask = IXP4XX_EXP_T2_MASK,
.shift = IXP4XX_EXP_T2_SHIFT,
},
{
.prop = "intel,ixp4xx-eb-t3",
.max = 15,
.mask = IXP4XX_EXP_T3_MASK,
.shift = IXP4XX_EXP_T3_SHIFT,
},
{
.prop = "intel,ixp4xx-eb-t4",
.max = 3,
.mask = IXP4XX_EXP_T4_MASK,
.shift = IXP4XX_EXP_T4_SHIFT,
},
{
.prop = "intel,ixp4xx-eb-t5",
.max = 15,
.mask = IXP4XX_EXP_T5_MASK,
.shift = IXP4XX_EXP_T5_SHIFT,
},
{
.prop = "intel,ixp4xx-eb-byte-access-on-halfword",
.max = 1,
.mask = IXP4XX_EXP_BYTE_RD16,
},
{
.prop = "intel,ixp4xx-eb-hpi-hrdy-pol-high",
.max = 1,
.mask = IXP4XX_EXP_HRDY_POL,
},
{
.prop = "intel,ixp4xx-eb-mux-address-and-data",
.max = 1,
.mask = IXP4XX_EXP_MUX_EN,
},
{
.prop = "intel,ixp4xx-eb-ahb-split-transfers",
.max = 1,
.mask = IXP4XX_EXP_SPLT_EN,
},
{
.prop = "intel,ixp4xx-eb-write-enable",
.max = 1,
.mask = IXP4XX_EXP_WR_EN,
},
{
.prop = "intel,ixp4xx-eb-byte-access",
.max = 1,
.mask = IXP4XX_EXP_BYTE_EN,
},
};
static void ixp4xx_exp_setup_chipselect(struct ixp4xx_eb *eb,
struct device_node *np,
u32 cs_index,
u32 cs_size)
{
u32 cs_cfg;
u32 val;
u32 cur_cssize;
u32 cs_order;
int ret;
int i;
if (eb->is_42x && (cs_index > 7)) {
dev_err(eb->dev,
"invalid chipselect %u, we only support 0-7\n",
cs_index);
return;
}
if (eb->is_43x && (cs_index > 3)) {
dev_err(eb->dev,
"invalid chipselect %u, we only support 0-3\n",
cs_index);
return;
}
/* Several chip selects can be joined into one device */
if (cs_size > IXP4XX_EXP_STRIDE)
cur_cssize = IXP4XX_EXP_STRIDE;
else
cur_cssize = cs_size;
/*
* The following will read/modify/write the configuration for one
* chipselect, attempting to leave the boot defaults in place unless
* something is explicitly defined.
*/
regmap_read(eb->rmap, IXP4XX_EXP_TIMING_CS0 +
IXP4XX_EXP_TIMING_STRIDE * cs_index, &cs_cfg);
dev_info(eb->dev, "CS%d at %#08x, size %#08x, config before: %#08x\n",
cs_index, eb->bus_base + IXP4XX_EXP_STRIDE * cs_index,
cur_cssize, cs_cfg);
/* Size set-up first align to 2^9 .. 2^24 */
cur_cssize = roundup_pow_of_two(cur_cssize);
if (cur_cssize < 512)
cur_cssize = 512;
cs_order = ilog2(cur_cssize);
if (cs_order < 9 || cs_order > 24) {
dev_err(eb->dev, "illegal size order %d\n", cs_order);
return;
}
dev_dbg(eb->dev, "CS%d size order: %d\n", cs_index, cs_order);
cs_cfg &= ~(IXP4XX_EXP_SIZE_MASK);
cs_cfg |= ((cs_order - 9) << IXP4XX_EXP_SIZE_SHIFT);
for (i = 0; i < ARRAY_SIZE(ixp4xx_exp_tim_props); i++) {
const struct ixp4xx_exp_tim_prop *ip = &ixp4xx_exp_tim_props[i];
/* All are regular u32 values */
ret = of_property_read_u32(np, ip->prop, &val);
if (ret)
continue;
/* Handle bools (single bits) first */
if (ip->max == 1) {
if (val)
cs_cfg |= ip->mask;
else
cs_cfg &= ~ip->mask;
dev_info(eb->dev, "CS%d %s %s\n", cs_index,
val ? "enabled" : "disabled",
ip->prop);
continue;
}
if (val > ip->max) {
dev_err(eb->dev,
"CS%d too high value for %s: %u, capped at %u\n",
cs_index, ip->prop, val, ip->max);
val = ip->max;
}
/* This assumes max value fills all the assigned bits (and it does) */
cs_cfg &= ~ip->mask;
cs_cfg |= (val << ip->shift);
dev_info(eb->dev, "CS%d set %s to %u\n", cs_index, ip->prop, val);
}
ret = of_property_read_u32(np, "intel,ixp4xx-eb-cycle-type", &val);
if (!ret) {
if (val > 3) {
dev_err(eb->dev, "illegal cycle type %d\n", val);
return;
}
dev_info(eb->dev, "CS%d set cycle type %d\n", cs_index, val);
cs_cfg &= ~IXP4XX_EXP_CYC_TYPE_MASK;
cs_cfg |= val << IXP4XX_EXP_CYC_TYPE_SHIFT;
}
if (eb->is_42x)
cs_cfg &= ~IXP42X_RESERVED;
if (eb->is_43x) {
cs_cfg &= ~IXP43X_RESERVED;
/*
* This bit for Intel strata flash is currently unused, but let's
* report it if we find one.
*/
if (cs_cfg & IXP43X_EXP_SYNC_INTEL)
dev_info(eb->dev, "claims to be Intel strata flash\n");
}
cs_cfg |= IXP4XX_EXP_CS_EN;
regmap_write(eb->rmap,
IXP4XX_EXP_TIMING_CS0 + IXP4XX_EXP_TIMING_STRIDE * cs_index,
cs_cfg);
dev_info(eb->dev, "CS%d wrote %#08x into CS config\n", cs_index, cs_cfg);
/*
* If several chip selects are joined together into one big
* device area, we call ourselves recursively for each successive
* chip select. For a 32MB flash chip this results in two calls
* for example.
*/
if (cs_size > IXP4XX_EXP_STRIDE)
ixp4xx_exp_setup_chipselect(eb, np,
cs_index + 1,
cs_size - IXP4XX_EXP_STRIDE);
}
static void ixp4xx_exp_setup_child(struct ixp4xx_eb *eb,
struct device_node *np)
{
u32 cs_sizes[IXP4XX_EXP_NUM_CS];
int num_regs;
u32 csindex;
u32 cssize;
int ret;
int i;
num_regs = of_property_count_elems_of_size(np, "reg", IXP4XX_OF_REG_SIZE);
if (num_regs <= 0)
return;
dev_dbg(eb->dev, "child %s has %d register sets\n",
of_node_full_name(np), num_regs);
for (csindex = 0; csindex < IXP4XX_EXP_NUM_CS; csindex++)
cs_sizes[csindex] = 0;
for (i = 0; i < num_regs; i++) {
u32 rbase, rsize;
ret = of_property_read_u32_index(np, "reg",
i * IXP4XX_OF_REG_SIZE, &csindex);
if (ret)
break;
ret = of_property_read_u32_index(np, "reg",
i * IXP4XX_OF_REG_SIZE + 1, &rbase);
if (ret)
break;
ret = of_property_read_u32_index(np, "reg",
i * IXP4XX_OF_REG_SIZE + 2, &rsize);
if (ret)
break;
if (csindex >= IXP4XX_EXP_NUM_CS) {
dev_err(eb->dev, "illegal CS %d\n", csindex);
continue;
}
/*
* The memory window always starts from CS base so we need to add
* the start and size to get to the size from the start of the CS
* base. For example if CS0 is at 0x50000000 and the reg is
* <0 0xe40000 0x40000> the size is e80000.
*
* Roof this if we have several regs setting the same CS.
*/
cssize = rbase + rsize;
dev_dbg(eb->dev, "CS%d size %#08x\n", csindex, cssize);
if (cs_sizes[csindex] < cssize)
cs_sizes[csindex] = cssize;
}
for (csindex = 0; csindex < IXP4XX_EXP_NUM_CS; csindex++) {
cssize = cs_sizes[csindex];
if (!cssize)
continue;
/* Just this one, so set it up and return */
ixp4xx_exp_setup_chipselect(eb, np, csindex, cssize);
}
}
static int ixp4xx_exp_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct ixp4xx_eb *eb;
struct device_node *child;
bool have_children = false;
u32 val;
int ret;
eb = devm_kzalloc(dev, sizeof(*eb), GFP_KERNEL);
if (!eb)
return -ENOMEM;
eb->dev = dev;
eb->is_42x = of_device_is_compatible(np, "intel,ixp42x-expansion-bus-controller");
eb->is_43x = of_device_is_compatible(np, "intel,ixp43x-expansion-bus-controller");
eb->rmap = syscon_node_to_regmap(np);
if (IS_ERR(eb->rmap))
return dev_err_probe(dev, PTR_ERR(eb->rmap), "no regmap\n");
/* We check that the regmap work only on first read */
ret = regmap_read(eb->rmap, IXP4XX_EXP_CNFG0, &val);
if (ret)
return dev_err_probe(dev, ret, "cannot read regmap\n");
if (val & IXP4XX_EXP_CNFG0_MEM_MAP)
eb->bus_base = IXP4XX_EXP_BOOT_BASE;
else
eb->bus_base = IXP4XX_EXP_NORMAL_BASE;
dev_info(dev, "expansion bus at %08x\n", eb->bus_base);
if (eb->is_43x) {
/* Check some fuses */
regmap_read(eb->rmap, IXP43X_EXP_UNIT_FUSE_RESET, &val);
switch (FIELD_GET(IXP43x_EXP_FUSE_SPEED_MASK, val)) {
case 0:
dev_info(dev, "IXP43x at 533 MHz\n");
break;
case 1:
dev_info(dev, "IXP43x at 400 MHz\n");
break;
case 2:
dev_info(dev, "IXP43x at 667 MHz\n");
break;
default:
dev_info(dev, "IXP43x unknown speed\n");
break;
}
}
/* Walk over the child nodes and see what chipselects we use */
for_each_available_child_of_node(np, child) {
ixp4xx_exp_setup_child(eb, child);
/* We have at least one child */
have_children = true;
}
if (have_children)
return of_platform_default_populate(np, NULL, dev);
return 0;
}
static const struct of_device_id ixp4xx_exp_of_match[] = {
{ .compatible = "intel,ixp42x-expansion-bus-controller", },
{ .compatible = "intel,ixp43x-expansion-bus-controller", },
{ .compatible = "intel,ixp45x-expansion-bus-controller", },
{ .compatible = "intel,ixp46x-expansion-bus-controller", },
{ }
};
static struct platform_driver ixp4xx_exp_driver = {
.probe = ixp4xx_exp_probe,
.driver = {
.name = "intel-extbus",
.of_match_table = ixp4xx_exp_of_match,
},
};
module_platform_driver(ixp4xx_exp_driver);
MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
MODULE_DESCRIPTION("Intel IXP4xx external bus driver");
MODULE_LICENSE("GPL");
......@@ -855,7 +855,7 @@ static int sysc_check_registers(struct sysc *ddata)
}
/**
* syc_ioremap - ioremap register space for the interconnect target module
* sysc_ioremap - ioremap register space for the interconnect target module
* @ddata: device driver data
*
* Note that the interconnect target module registers can be anywhere
......@@ -1446,10 +1446,6 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_OPT_CLKS_IN_RESET),
SYSC_QUIRK("sham", 0, 0x100, 0x110, 0x114, 0x40000c03, 0xffffffff,
SYSC_QUIRK_LEGACY_IDLE),
SYSC_QUIRK("smartreflex", 0, -ENODEV, 0x24, -ENODEV, 0x00000000, 0xffffffff,
SYSC_QUIRK_LEGACY_IDLE),
SYSC_QUIRK("smartreflex", 0, -ENODEV, 0x38, -ENODEV, 0x00000000, 0xffffffff,
SYSC_QUIRK_LEGACY_IDLE),
SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000046, 0xffffffff,
SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE),
SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff,
......@@ -1501,6 +1497,8 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
SYSC_MODULE_QUIRK_SGX),
SYSC_QUIRK("lcdc", 0, 0, 0x54, -ENODEV, 0x4f201000, 0xffffffff,
SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
SYSC_QUIRK("mcasp", 0, 0, 0x4, -ENODEV, 0x44306302, 0xffffffff,
SYSC_QUIRK_SWSUP_SIDLE),
SYSC_QUIRK("rtc", 0, 0x74, 0x78, -ENODEV, 0x4eb01908, 0xffff00f0,
SYSC_MODULE_QUIRK_RTC_UNLOCK),
SYSC_QUIRK("tptc", 0, 0, 0x10, -ENODEV, 0x40006c00, 0xffffefff,
......@@ -1557,7 +1555,6 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
SYSC_QUIRK("hsi", 0, 0, 0x10, 0x14, 0x50043101, 0xffffffff, 0),
SYSC_QUIRK("iss", 0, 0, 0x10, -ENODEV, 0x40000101, 0xffffffff, 0),
SYSC_QUIRK("keypad", 0x4a31c000, 0, 0x10, 0x14, 0x00000020, 0xffffffff, 0),
SYSC_QUIRK("mcasp", 0, 0, 0x4, -ENODEV, 0x44306302, 0xffffffff, 0),
SYSC_QUIRK("mcasp", 0, 0, 0x4, -ENODEV, 0x44307b02, 0xffffffff, 0),
SYSC_QUIRK("mcbsp", 0, -ENODEV, 0x8c, -ENODEV, 0, 0, 0),
SYSC_QUIRK("mcspi", 0, 0, 0x10, -ENODEV, 0x40300a0b, 0xffff00ff, 0),
......@@ -1585,6 +1582,8 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
SYSC_QUIRK("sdma", 0, 0, 0x2c, 0x28, 0x00010900, 0xffffffff, 0),
SYSC_QUIRK("slimbus", 0, 0, 0x10, -ENODEV, 0x40000902, 0xffffffff, 0),
SYSC_QUIRK("slimbus", 0, 0, 0x10, -ENODEV, 0x40002903, 0xffffffff, 0),
SYSC_QUIRK("smartreflex", 0, -ENODEV, 0x24, -ENODEV, 0x00000000, 0xffffffff, 0),
SYSC_QUIRK("smartreflex", 0, -ENODEV, 0x38, -ENODEV, 0x00000000, 0xffffffff, 0),
SYSC_QUIRK("spinlock", 0, 0, 0x10, -ENODEV, 0x50020000, 0xffffffff, 0),
SYSC_QUIRK("rng", 0, 0x1fe0, 0x1fe4, -ENODEV, 0x00000020, 0xffffffff, 0),
SYSC_QUIRK("timer", 0, 0, 0x10, 0x14, 0x00000013, 0xffffffff, 0),
......@@ -3115,9 +3114,8 @@ static int sysc_probe(struct platform_device *pdev)
goto unprepare;
pm_runtime_enable(ddata->dev);
error = pm_runtime_get_sync(ddata->dev);
error = pm_runtime_resume_and_get(ddata->dev);
if (error < 0) {
pm_runtime_put_noidle(ddata->dev);
pm_runtime_disable(ddata->dev);
goto unprepare;
}
......@@ -3175,9 +3173,8 @@ static int sysc_remove(struct platform_device *pdev)
cancel_delayed_work_sync(&ddata->idle_work);
error = pm_runtime_get_sync(ddata->dev);
error = pm_runtime_resume_and_get(ddata->dev);
if (error < 0) {
pm_runtime_put_noidle(ddata->dev);
pm_runtime_disable(ddata->dev);
goto unprepare;
}
......
......@@ -18,6 +18,7 @@
#include <linux/delay.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
/* Goes away with OF conversion */
#include <linux/platform_data/timer-ixp4xx.h>
......@@ -29,9 +30,6 @@
#define IXP4XX_OSRT1_OFFSET 0x08 /* Timer 1 Reload */
#define IXP4XX_OST2_OFFSET 0x0C /* Timer 2 Timestamp */
#define IXP4XX_OSRT2_OFFSET 0x10 /* Timer 2 Reload */
#define IXP4XX_OSWT_OFFSET 0x14 /* Watchdog Timer */
#define IXP4XX_OSWE_OFFSET 0x18 /* Watchdog Enable */
#define IXP4XX_OSWK_OFFSET 0x1C /* Watchdog Key */
#define IXP4XX_OSST_OFFSET 0x20 /* Timer Status */
/*
......@@ -45,17 +43,10 @@
#define IXP4XX_OSST_TIMER_1_PEND 0x00000001
#define IXP4XX_OSST_TIMER_2_PEND 0x00000002
#define IXP4XX_OSST_TIMER_TS_PEND 0x00000004
#define IXP4XX_OSST_TIMER_WDOG_PEND 0x00000008
#define IXP4XX_OSST_TIMER_WARM_RESET 0x00000010
#define IXP4XX_WDT_KEY 0x0000482E
#define IXP4XX_WDT_RESET_ENABLE 0x00000001
#define IXP4XX_WDT_IRQ_ENABLE 0x00000002
#define IXP4XX_WDT_COUNT_ENABLE 0x00000004
/* Remaining registers are for the watchdog and defined in the watchdog driver */
struct ixp4xx_timer {
void __iomem *base;
unsigned int tick_rate;
u32 latch;
struct clock_event_device clkevt;
#ifdef CONFIG_ARM
......@@ -181,7 +172,6 @@ static __init int ixp4xx_timer_register(void __iomem *base,
if (!tmr)
return -ENOMEM;
tmr->base = base;
tmr->tick_rate = timer_freq;
/*
* The timer register doesn't allow to specify the two least
......@@ -239,6 +229,40 @@ static __init int ixp4xx_timer_register(void __iomem *base,
return 0;
}
static struct platform_device ixp4xx_watchdog_device = {
.name = "ixp4xx-watchdog",
.id = -1,
};
/*
* This probe gets called after the timer is already up and running. The main
* function on this platform is to spawn the watchdog device as a child.
*/
static int ixp4xx_timer_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
/* Pass the base address as platform data and nothing else */
ixp4xx_watchdog_device.dev.platform_data = local_ixp4xx_timer->base;
ixp4xx_watchdog_device.dev.parent = dev;
return platform_device_register(&ixp4xx_watchdog_device);
}
static const struct of_device_id ixp4xx_timer_dt_id[] = {
{ .compatible = "intel,ixp4xx-timer", },
{ /* sentinel */ },
};
static struct platform_driver ixp4xx_timer_driver = {
.probe = ixp4xx_timer_probe,
.driver = {
.name = "ixp4xx-timer",
.of_match_table = ixp4xx_timer_dt_id,
.suppress_bind_attrs = true,
},
};
builtin_platform_driver(ixp4xx_timer_driver);
/**
* ixp4xx_timer_setup() - Timer setup function to be called from boardfiles
* @timerbase: physical base of timer block
......
......@@ -198,12 +198,12 @@ struct sdma_script_start_addrs {
s32 per_2_firi_addr;
s32 mcu_2_firi_addr;
s32 uart_2_per_addr;
s32 uart_2_mcu_addr;
s32 uart_2_mcu_ram_addr;
s32 per_2_app_addr;
s32 mcu_2_app_addr;
s32 per_2_per_addr;
s32 uartsh_2_per_addr;
s32 uartsh_2_mcu_addr;
s32 uartsh_2_mcu_ram_addr;
s32 per_2_shp_addr;
s32 mcu_2_shp_addr;
s32 ata_2_mcu_addr;
......@@ -230,6 +230,10 @@ struct sdma_script_start_addrs {
s32 zcanfd_2_mcu_addr;
s32 zqspi_2_mcu_addr;
s32 mcu_2_ecspi_addr;
s32 mcu_2_sai_addr;
s32 sai_2_mcu_addr;
s32 uart_2_mcu_addr;
s32 uartsh_2_mcu_addr;
/* End of v3 array */
s32 mcu_2_zqspi_addr;
/* End of v4 array */
......@@ -433,9 +437,10 @@ struct sdma_channel {
unsigned long watermark_level;
u32 shp_addr, per_addr;
enum dma_status status;
bool context_loaded;
struct imx_dma_data data;
struct work_struct terminate_worker;
struct list_head terminated;
bool is_ram_script;
};
#define IMX_DMA_SG_LOOP BIT(0)
......@@ -476,6 +481,13 @@ struct sdma_driver_data {
int num_events;
struct sdma_script_start_addrs *script_addrs;
bool check_ratio;
/*
* ecspi ERR009165 fixed should be done in sdma script
* and it has been fixed in soc from i.mx6ul.
* please get more information from the below link:
* https://www.nxp.com/docs/en/errata/IMX6DQCE.pdf
*/
bool ecspi_fixed;
};
struct sdma_engine {
......@@ -499,6 +511,7 @@ struct sdma_engine {
struct sdma_buffer_descriptor *bd0;
/* clock ratio for AHB:SDMA core. 1:1 is 1, 2:1 is 0*/
bool clk_ratio;
bool fw_loaded;
};
static int sdma_config_write(struct dma_chan *chan,
......@@ -595,6 +608,13 @@ static struct sdma_driver_data sdma_imx6q = {
.script_addrs = &sdma_script_imx6q,
};
static struct sdma_driver_data sdma_imx6ul = {
.chnenbl0 = SDMA_CHNENBL0_IMX35,
.num_events = 48,
.script_addrs = &sdma_script_imx6q,
.ecspi_fixed = true,
};
static struct sdma_script_start_addrs sdma_script_imx7d = {
.ap_2_ap_addr = 644,
.uart_2_mcu_addr = 819,
......@@ -628,6 +648,7 @@ static const struct of_device_id sdma_dt_ids[] = {
{ .compatible = "fsl,imx31-sdma", .data = &sdma_imx31, },
{ .compatible = "fsl,imx25-sdma", .data = &sdma_imx25, },
{ .compatible = "fsl,imx7d-sdma", .data = &sdma_imx7d, },
{ .compatible = "fsl,imx6ul-sdma", .data = &sdma_imx6ul, },
{ .compatible = "fsl,imx8mq-sdma", .data = &sdma_imx8mq, },
{ /* sentinel */ }
};
......@@ -919,6 +940,7 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
sdmac->pc_to_device = 0;
sdmac->device_to_device = 0;
sdmac->pc_to_pc = 0;
sdmac->is_ram_script = false;
switch (peripheral_type) {
case IMX_DMATYPE_MEMORY:
......@@ -945,6 +967,17 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
emi_2_per = sdma->script_addrs->mcu_2_ata_addr;
break;
case IMX_DMATYPE_CSPI:
per_2_emi = sdma->script_addrs->app_2_mcu_addr;
/* Use rom script mcu_2_app if ERR009165 fixed */
if (sdmac->sdma->drvdata->ecspi_fixed) {
emi_2_per = sdma->script_addrs->mcu_2_app_addr;
} else {
emi_2_per = sdma->script_addrs->mcu_2_ecspi_addr;
sdmac->is_ram_script = true;
}
break;
case IMX_DMATYPE_EXT:
case IMX_DMATYPE_SSI:
case IMX_DMATYPE_SAI:
......@@ -954,6 +987,7 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
case IMX_DMATYPE_SSI_DUAL:
per_2_emi = sdma->script_addrs->ssish_2_mcu_addr;
emi_2_per = sdma->script_addrs->mcu_2_ssish_addr;
sdmac->is_ram_script = true;
break;
case IMX_DMATYPE_SSI_SP:
case IMX_DMATYPE_MMC:
......@@ -968,6 +1002,7 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
per_2_emi = sdma->script_addrs->asrc_2_mcu_addr;
emi_2_per = sdma->script_addrs->asrc_2_mcu_addr;
per_2_per = sdma->script_addrs->per_2_per_addr;
sdmac->is_ram_script = true;
break;
case IMX_DMATYPE_ASRC_SP:
per_2_emi = sdma->script_addrs->shp_2_mcu_addr;
......@@ -1008,9 +1043,6 @@ static int sdma_load_context(struct sdma_channel *sdmac)
int ret;
unsigned long flags;
if (sdmac->context_loaded)
return 0;
if (sdmac->direction == DMA_DEV_TO_MEM)
load_address = sdmac->pc_from_device;
else if (sdmac->direction == DMA_DEV_TO_DEV)
......@@ -1053,8 +1085,6 @@ static int sdma_load_context(struct sdma_channel *sdmac)
spin_unlock_irqrestore(&sdma->channel_0_lock, flags);
sdmac->context_loaded = true;
return ret;
}
......@@ -1078,9 +1108,6 @@ static void sdma_channel_terminate_work(struct work_struct *work)
{
struct sdma_channel *sdmac = container_of(work, struct sdma_channel,
terminate_worker);
unsigned long flags;
LIST_HEAD(head);
/*
* According to NXP R&D team a delay of one BD SDMA cost time
* (maximum is 1ms) should be added after disable of the channel
......@@ -1089,11 +1116,7 @@ static void sdma_channel_terminate_work(struct work_struct *work)
*/
usleep_range(1000, 2000);
spin_lock_irqsave(&sdmac->vc.lock, flags);
vchan_get_all_descriptors(&sdmac->vc, &head);
spin_unlock_irqrestore(&sdmac->vc.lock, flags);
vchan_dma_desc_free_list(&sdmac->vc, &head);
sdmac->context_loaded = false;
vchan_dma_desc_free_list(&sdmac->vc, &sdmac->terminated);
}
static int sdma_terminate_all(struct dma_chan *chan)
......@@ -1107,6 +1130,13 @@ static int sdma_terminate_all(struct dma_chan *chan)
if (sdmac->desc) {
vchan_terminate_vdesc(&sdmac->desc->vd);
/*
* move out current descriptor into terminated list so that
* it could be free in sdma_channel_terminate_work alone
* later without potential involving next descriptor raised
* up before the last descriptor terminated.
*/
vchan_get_all_descriptors(&sdmac->vc, &sdmac->terminated);
sdmac->desc = NULL;
schedule_work(&sdmac->terminate_worker);
}
......@@ -1168,7 +1198,6 @@ static void sdma_set_watermarklevel_for_p2p(struct sdma_channel *sdmac)
static int sdma_config_channel(struct dma_chan *chan)
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
int ret;
sdma_disable_channel(chan);
......@@ -1208,9 +1237,7 @@ static int sdma_config_channel(struct dma_chan *chan)
sdmac->watermark_level = 0; /* FIXME: M3_BASE_ADDRESS */
}
ret = sdma_load_context(sdmac);
return ret;
return 0;
}
static int sdma_set_channel_priority(struct sdma_channel *sdmac,
......@@ -1361,7 +1388,6 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
sdmac->event_id0 = 0;
sdmac->event_id1 = 0;
sdmac->context_loaded = false;
sdma_set_channel_priority(sdmac, 0);
......@@ -1374,6 +1400,11 @@ static struct sdma_desc *sdma_transfer_init(struct sdma_channel *sdmac,
{
struct sdma_desc *desc;
if (!sdmac->sdma->fw_loaded && sdmac->is_ram_script) {
dev_warn_once(sdmac->sdma->dev, "sdma firmware not ready!\n");
goto err_out;
}
desc = kzalloc((sizeof(*desc)), GFP_NOWAIT);
if (!desc)
goto err_out;
......@@ -1722,8 +1753,8 @@ static void sdma_issue_pending(struct dma_chan *chan)
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2 38
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3 41
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V4 42
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3 45
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V4 46
static void sdma_add_scripts(struct sdma_engine *sdma,
const struct sdma_script_start_addrs *addr)
......@@ -1747,6 +1778,19 @@ static void sdma_add_scripts(struct sdma_engine *sdma,
for (i = 0; i < sdma->script_number; i++)
if (addr_arr[i] > 0)
saddr_arr[i] = addr_arr[i];
/*
* get uart_2_mcu_addr/uartsh_2_mcu_addr rom script specially because
* they are now replaced by uart_2_mcu_ram_addr/uartsh_2_mcu_ram_addr
* to be compatible with legacy freescale/nxp sdma firmware, and they
* are located in the bottom part of sdma_script_start_addrs which are
* beyond the SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1.
*/
if (addr->uart_2_mcu_addr)
sdma->script_addrs->uart_2_mcu_addr = addr->uart_2_mcu_addr;
if (addr->uartsh_2_mcu_addr)
sdma->script_addrs->uartsh_2_mcu_addr = addr->uartsh_2_mcu_addr;
}
static void sdma_load_firmware(const struct firmware *fw, void *context)
......@@ -1803,6 +1847,8 @@ static void sdma_load_firmware(const struct firmware *fw, void *context)
sdma_add_scripts(sdma, addr);
sdma->fw_loaded = true;
dev_info(sdma->dev, "loaded firmware %d.%d\n",
header->version_major,
header->version_minor);
......@@ -2086,6 +2132,7 @@ static int sdma_probe(struct platform_device *pdev)
sdmac->channel = i;
sdmac->vc.desc_free = sdma_desc_free;
INIT_LIST_HEAD(&sdmac->terminated);
INIT_WORK(&sdmac->terminate_worker,
sdma_channel_terminate_work);
/*
......
......@@ -6,39 +6,7 @@
menu "Firmware Drivers"
config ARM_SCMI_PROTOCOL
tristate "ARM System Control and Management Interface (SCMI) Message Protocol"
depends on ARM || ARM64 || COMPILE_TEST
depends on MAILBOX || HAVE_ARM_SMCCC_DISCOVERY
help
ARM System Control and Management Interface (SCMI) protocol is a
set of operating system-independent software interfaces that are
used in system management. SCMI is extensible and currently provides
interfaces for: Discovery and self-description of the interfaces
it supports, Power domain management which is the ability to place
a given device or domain into the various power-saving states that
it supports, Performance management which is the ability to control
the performance of a domain that is composed of compute engines
such as application processors and other accelerators, Clock
management which is the ability to set and inquire rates on platform
managed clocks and Sensor management which is the ability to read
sensor data, and be notified of sensor value.
This protocol library provides interface for all the client drivers
making use of the features offered by the SCMI.
config ARM_SCMI_POWER_DOMAIN
tristate "SCMI power domain driver"
depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
default y
select PM_GENERIC_DOMAINS if PM
help
This enables support for the SCMI power domains which can be
enabled or disabled via the SCP firmware
This driver can also be built as a module. If so, the module
will be called scmi_pm_domain. Note this may needed early in boot
before rootfs may be available.
source "drivers/firmware/arm_scmi/Kconfig"
config ARM_SCPI_PROTOCOL
tristate "ARM System Control and Power Interface (SCPI) Message Protocol"
......@@ -235,7 +203,7 @@ config INTEL_STRATIX10_RSU
Say Y here if you want Intel RSU support.
config QCOM_SCM
bool
tristate "Qcom SCM driver"
depends on ARM || ARM64
depends on HAVE_ARM_SMCCC
select RESET_CONTROLLER
......
......@@ -17,7 +17,8 @@ obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o
obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o
obj-$(CONFIG_QCOM_SCM) += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
obj-$(CONFIG_QCOM_SCM) += qcom-scm.o
qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
obj-$(CONFIG_SYSFB) += sysfb.o
obj-$(CONFIG_SYSFB_SIMPLEFB) += sysfb_simplefb.o
obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
......
# SPDX-License-Identifier: GPL-2.0-only
menu "ARM System Control and Management Interface Protocol"
config ARM_SCMI_PROTOCOL
tristate "ARM System Control and Management Interface (SCMI) Message Protocol"
depends on ARM || ARM64 || COMPILE_TEST
help
ARM System Control and Management Interface (SCMI) protocol is a
set of operating system-independent software interfaces that are
used in system management. SCMI is extensible and currently provides
interfaces for: Discovery and self-description of the interfaces
it supports, Power domain management which is the ability to place
a given device or domain into the various power-saving states that
it supports, Performance management which is the ability to control
the performance of a domain that is composed of compute engines
such as application processors and other accelerators, Clock
management which is the ability to set and inquire rates on platform
managed clocks and Sensor management which is the ability to read
sensor data, and be notified of sensor value.
This protocol library provides interface for all the client drivers
making use of the features offered by the SCMI.
if ARM_SCMI_PROTOCOL
config ARM_SCMI_HAVE_TRANSPORT
bool
help
This declares whether at least one SCMI transport has been configured.
Used to trigger a build bug when trying to build SCMI without any
configured transport.
config ARM_SCMI_HAVE_SHMEM
bool
help
This declares whether a shared memory based transport for SCMI is
available.
config ARM_SCMI_HAVE_MSG
bool
help
This declares whether a message passing based transport for SCMI is
available.
config ARM_SCMI_TRANSPORT_MAILBOX
bool "SCMI transport based on Mailbox"
depends on MAILBOX
select ARM_SCMI_HAVE_TRANSPORT
select ARM_SCMI_HAVE_SHMEM
default y
help
Enable mailbox based transport for SCMI.
If you want the ARM SCMI PROTOCOL stack to include support for a
transport based on mailboxes, answer Y.
config ARM_SCMI_TRANSPORT_SMC
bool "SCMI transport based on SMC"
depends on HAVE_ARM_SMCCC_DISCOVERY
select ARM_SCMI_HAVE_TRANSPORT
select ARM_SCMI_HAVE_SHMEM
default y
help
Enable SMC based transport for SCMI.
If you want the ARM SCMI PROTOCOL stack to include support for a
transport based on SMC, answer Y.
config ARM_SCMI_TRANSPORT_VIRTIO
bool "SCMI transport based on VirtIO"
depends on VIRTIO
select ARM_SCMI_HAVE_TRANSPORT
select ARM_SCMI_HAVE_MSG
help
This enables the virtio based transport for SCMI.
If you want the ARM SCMI PROTOCOL stack to include support for a
transport based on VirtIO, answer Y.
endif #ARM_SCMI_PROTOCOL
config ARM_SCMI_POWER_DOMAIN
tristate "SCMI power domain driver"
depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
default y
select PM_GENERIC_DOMAINS if PM
help
This enables support for the SCMI power domains which can be
enabled or disabled via the SCP firmware
This driver can also be built as a module. If so, the module
will be called scmi_pm_domain. Note this may needed early in boot
before rootfs may be available.
endmenu
# SPDX-License-Identifier: GPL-2.0-only
scmi-bus-y = bus.o
scmi-driver-y = driver.o notify.o
scmi-transport-y = shmem.o
scmi-transport-$(CONFIG_MAILBOX) += mailbox.o
scmi-transport-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smc.o
scmi-transport-$(CONFIG_ARM_SCMI_HAVE_SHMEM) = shmem.o
scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_MAILBOX) += mailbox.o
scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_SMC) += smc.o
scmi-transport-$(CONFIG_ARM_SCMI_HAVE_MSG) += msg.o
scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO) += virtio.o
scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o system.o voltage.o
scmi-module-objs := $(scmi-bus-y) $(scmi-driver-y) $(scmi-protocols-y) \
$(scmi-transport-y)
......
......@@ -14,8 +14,12 @@
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/hashtable.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/refcount.h>
#include <linux/scmi_protocol.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <asm/unaligned.h>
......@@ -65,11 +69,22 @@ struct scmi_msg_resp_prot_version {
#define MSG_XTRACT_TOKEN(hdr) FIELD_GET(MSG_TOKEN_ID_MASK, (hdr))
#define MSG_TOKEN_MAX (MSG_XTRACT_TOKEN(MSG_TOKEN_ID_MASK) + 1)
/*
* Size of @pending_xfers hashtable included in @scmi_xfers_info; ideally, in
* order to minimize space and collisions, this should equal max_msg, i.e. the
* maximum number of in-flight messages on a specific platform, but such value
* is only available at runtime while kernel hashtables are statically sized:
* pick instead as a fixed static size the maximum number of entries that can
* fit the whole table into one 4k page.
*/
#define SCMI_PENDING_XFERS_HT_ORDER_SZ 9
/**
* struct scmi_msg_hdr - Message(Tx/Rx) header
*
* @id: The identifier of the message being sent
* @protocol_id: The identifier of the protocol used to send @id message
* @type: The SCMI type for this message
* @seq: The token to identify the message. When a message returns, the
* platform returns the whole message header unmodified including the
* token
......@@ -80,6 +95,7 @@ struct scmi_msg_resp_prot_version {
struct scmi_msg_hdr {
u8 id;
u8 protocol_id;
u8 type;
u16 seq;
u32 status;
bool poll_completion;
......@@ -89,13 +105,14 @@ struct scmi_msg_hdr {
* pack_scmi_header() - packs and returns 32-bit header
*
* @hdr: pointer to header containing all the information on message id,
* protocol id and sequence id.
* protocol id, sequence id and type.
*
* Return: 32-bit packed message header to be sent to the platform.
*/
static inline u32 pack_scmi_header(struct scmi_msg_hdr *hdr)
{
return FIELD_PREP(MSG_ID_MASK, hdr->id) |
FIELD_PREP(MSG_TYPE_MASK, hdr->type) |
FIELD_PREP(MSG_TOKEN_ID_MASK, hdr->seq) |
FIELD_PREP(MSG_PROTOCOL_ID_MASK, hdr->protocol_id);
}
......@@ -110,6 +127,7 @@ static inline void unpack_scmi_header(u32 msg_hdr, struct scmi_msg_hdr *hdr)
{
hdr->id = MSG_XTRACT_ID(msg_hdr);
hdr->protocol_id = MSG_XTRACT_PROT_ID(msg_hdr);
hdr->type = MSG_XTRACT_TYPE(msg_hdr);
}
/**
......@@ -134,6 +152,27 @@ struct scmi_msg {
* buffer for the rx path as we use for the tx path.
* @done: command message transmit completion event
* @async_done: pointer to delayed response message received event completion
* @pending: True for xfers added to @pending_xfers hashtable
* @node: An hlist_node reference used to store this xfer, alternatively, on
* the free list @free_xfers or in the @pending_xfers hashtable
* @users: A refcount to track the active users for this xfer.
* This is meant to protect against the possibility that, when a command
* transaction times out concurrently with the reception of a valid
* response message, the xfer could be finally put on the TX path, and
* so vanish, while on the RX path scmi_rx_callback() is still
* processing it: in such a case this refcounting will ensure that, even
* though the timed-out transaction will anyway cause the command
* request to be reported as failed by time-out, the underlying xfer
* cannot be discarded and possibly reused until the last one user on
* the RX path has released it.
* @busy: An atomic flag to ensure exclusive write access to this xfer
* @state: The current state of this transfer, with states transitions deemed
* valid being:
* - SCMI_XFER_SENT_OK -> SCMI_XFER_RESP_OK [ -> SCMI_XFER_DRESP_OK ]
* - SCMI_XFER_SENT_OK -> SCMI_XFER_DRESP_OK
* (Missing synchronous response is assumed OK and ignored)
* @lock: A spinlock to protect state and busy fields.
* @priv: A pointer for transport private usage.
*/
struct scmi_xfer {
int transfer_id;
......@@ -142,8 +181,36 @@ struct scmi_xfer {
struct scmi_msg rx;
struct completion done;
struct completion *async_done;
bool pending;
struct hlist_node node;
refcount_t users;
#define SCMI_XFER_FREE 0
#define SCMI_XFER_BUSY 1
atomic_t busy;
#define SCMI_XFER_SENT_OK 0
#define SCMI_XFER_RESP_OK 1
#define SCMI_XFER_DRESP_OK 2
int state;
/* A lock to protect state and busy fields */
spinlock_t lock;
void *priv;
};
/*
* An helper macro to lookup an xfer from the @pending_xfers hashtable
* using the message sequence number token as a key.
*/
#define XFER_FIND(__ht, __k) \
({ \
typeof(__k) k_ = __k; \
struct scmi_xfer *xfer_ = NULL; \
\
hash_for_each_possible((__ht), xfer_, node, k_) \
if (xfer_->hdr.seq == k_) \
break; \
xfer_; \
})
struct scmi_xfer_ops;
/**
......@@ -283,9 +350,13 @@ struct scmi_chan_info {
/**
* struct scmi_transport_ops - Structure representing a SCMI transport ops
*
* @link_supplier: Optional callback to add link to a supplier device
* @chan_available: Callback to check if channel is available or not
* @chan_setup: Callback to allocate and setup a channel
* @chan_free: Callback to free a channel
* @get_max_msg: Optional callback to provide max_msg dynamically
* Returns the maximum number of messages for the channel type
* (tx or rx) that can be pending simultaneously in the system
* @send_message: Callback to send a message
* @mark_txdone: Callback to mark tx as done
* @fetch_response: Callback to fetch response
......@@ -294,10 +365,12 @@ struct scmi_chan_info {
* @poll_done: Callback to poll transfer status
*/
struct scmi_transport_ops {
int (*link_supplier)(struct device *dev);
bool (*chan_available)(struct device *dev, int idx);
int (*chan_setup)(struct scmi_chan_info *cinfo, struct device *dev,
bool tx);
int (*chan_free)(int id, void *p, void *data);
unsigned int (*get_max_msg)(struct scmi_chan_info *base_cinfo);
int (*send_message)(struct scmi_chan_info *cinfo,
struct scmi_xfer *xfer);
void (*mark_txdone)(struct scmi_chan_info *cinfo, int ret);
......@@ -317,25 +390,39 @@ struct scmi_device *scmi_child_dev_find(struct device *parent,
/**
* struct scmi_desc - Description of SoC integration
*
* @transport_init: An optional function that a transport can provide to
* initialize some transport-specific setup during SCMI core
* initialization, so ahead of SCMI core probing.
* @transport_exit: An optional function that a transport can provide to
* de-initialize some transport-specific setup during SCMI core
* de-initialization, so after SCMI core removal.
* @ops: Pointer to the transport specific ops structure
* @max_rx_timeout_ms: Timeout for communication with SoC (in Milliseconds)
* @max_msg: Maximum number of messages that can be pending
* simultaneously in the system
* @max_msg: Maximum number of messages for a channel type (tx or rx) that can
* be pending simultaneously in the system. May be overridden by the
* get_max_msg op.
* @max_msg_size: Maximum size of data per message that can be handled.
*/
struct scmi_desc {
int (*transport_init)(void);
void (*transport_exit)(void);
const struct scmi_transport_ops *ops;
int max_rx_timeout_ms;
int max_msg;
int max_msg_size;
};
#ifdef CONFIG_ARM_SCMI_TRANSPORT_MAILBOX
extern const struct scmi_desc scmi_mailbox_desc;
#ifdef CONFIG_HAVE_ARM_SMCCC_DISCOVERY
#endif
#ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC
extern const struct scmi_desc scmi_smc_desc;
#endif
#ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO
extern const struct scmi_desc scmi_virtio_desc;
#endif
void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr);
void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, void *priv);
void scmi_free_channel(struct scmi_chan_info *cinfo, struct idr *idr, int id);
/* shmem related declarations */
......@@ -352,8 +439,22 @@ void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem);
bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem,
struct scmi_xfer *xfer);
/* declarations for message passing transports */
struct scmi_msg_payld;
/* Maximum overhead of message w.r.t. struct scmi_desc.max_msg_size */
#define SCMI_MSG_MAX_PROT_OVERHEAD (2 * sizeof(__le32))
size_t msg_response_size(struct scmi_xfer *xfer);
size_t msg_command_size(struct scmi_xfer *xfer);
void msg_tx_prepare(struct scmi_msg_payld *msg, struct scmi_xfer *xfer);
u32 msg_read_header(struct scmi_msg_payld *msg);
void msg_fetch_response(struct scmi_msg_payld *msg, size_t len,
struct scmi_xfer *xfer);
void msg_fetch_notification(struct scmi_msg_payld *msg, size_t len,
size_t max_len, struct scmi_xfer *xfer);
void scmi_notification_instance_data_set(const struct scmi_handle *handle,
void *priv);
void *scmi_notification_instance_data_get(const struct scmi_handle *handle);
#endif /* _SCMI_COMMON_H */
此差异已折叠。
......@@ -43,7 +43,7 @@ static void rx_callback(struct mbox_client *cl, void *m)
{
struct scmi_mailbox *smbox = client_to_scmi_mailbox(cl);
scmi_rx_callback(smbox->cinfo, shmem_read_header(smbox->shmem));
scmi_rx_callback(smbox->cinfo, shmem_read_header(smbox->shmem), NULL);
}
static bool mailbox_chan_available(struct device *dev, int idx)
......
// SPDX-License-Identifier: GPL-2.0
/*
* For transports using message passing.
*
* Derived from shm.c.
*
* Copyright (C) 2019-2021 ARM Ltd.
* Copyright (C) 2020-2021 OpenSynergy GmbH
*/
#include <linux/types.h>
#include "common.h"
/*
* struct scmi_msg_payld - Transport SDU layout
*
* The SCMI specification requires all parameters, message headers, return
* arguments or any protocol data to be expressed in little endian format only.
*/
struct scmi_msg_payld {
__le32 msg_header;
__le32 msg_payload[];
};
/**
* msg_command_size() - Actual size of transport SDU for command.
*
* @xfer: message which core has prepared for sending
*
* Return: transport SDU size.
*/
size_t msg_command_size(struct scmi_xfer *xfer)
{
return sizeof(struct scmi_msg_payld) + xfer->tx.len;
}
/**
* msg_response_size() - Maximum size of transport SDU for response.
*
* @xfer: message which core has prepared for sending
*
* Return: transport SDU size.
*/
size_t msg_response_size(struct scmi_xfer *xfer)
{
return sizeof(struct scmi_msg_payld) + sizeof(__le32) + xfer->rx.len;
}
/**
* msg_tx_prepare() - Set up transport SDU for command.
*
* @msg: transport SDU for command
* @xfer: message which is being sent
*/
void msg_tx_prepare(struct scmi_msg_payld *msg, struct scmi_xfer *xfer)
{
msg->msg_header = cpu_to_le32(pack_scmi_header(&xfer->hdr));
if (xfer->tx.buf)
memcpy(msg->msg_payload, xfer->tx.buf, xfer->tx.len);
}
/**
* msg_read_header() - Read SCMI header from transport SDU.
*
* @msg: transport SDU
*
* Return: SCMI header
*/
u32 msg_read_header(struct scmi_msg_payld *msg)
{
return le32_to_cpu(msg->msg_header);
}
/**
* msg_fetch_response() - Fetch response SCMI payload from transport SDU.
*
* @msg: transport SDU with response
* @len: transport SDU size
* @xfer: message being responded to
*/
void msg_fetch_response(struct scmi_msg_payld *msg, size_t len,
struct scmi_xfer *xfer)
{
size_t prefix_len = sizeof(*msg) + sizeof(msg->msg_payload[0]);
xfer->hdr.status = le32_to_cpu(msg->msg_payload[0]);
xfer->rx.len = min_t(size_t, xfer->rx.len,
len >= prefix_len ? len - prefix_len : 0);
/* Take a copy to the rx buffer.. */
memcpy(xfer->rx.buf, &msg->msg_payload[1], xfer->rx.len);
}
/**
* msg_fetch_notification() - Fetch notification payload from transport SDU.
*
* @msg: transport SDU with notification
* @len: transport SDU size
* @max_len: maximum SCMI payload size to fetch
* @xfer: notification message
*/
void msg_fetch_notification(struct scmi_msg_payld *msg, size_t len,
size_t max_len, struct scmi_xfer *xfer)
{
xfer->rx.len = min_t(size_t, max_len,
len >= sizeof(*msg) ? len - sizeof(*msg) : 0);
/* Take a copy to the rx buffer.. */
memcpy(xfer->rx.buf, msg->msg_payload, xfer->rx.len);
}
......@@ -154,7 +154,8 @@ static int smc_send_message(struct scmi_chan_info *cinfo,
if (scmi_info->irq)
wait_for_completion(&scmi_info->tx_complete);
scmi_rx_callback(scmi_info->cinfo, shmem_read_header(scmi_info->shmem));
scmi_rx_callback(scmi_info->cinfo,
shmem_read_header(scmi_info->shmem), NULL);
mutex_unlock(&scmi_info->shmem_lock);
......
// SPDX-License-Identifier: GPL-2.0
/*
* Virtio Transport driver for Arm System Control and Management Interface
* (SCMI).
*
* Copyright (C) 2020-2021 OpenSynergy.
* Copyright (C) 2021 ARM Ltd.
*/
/**
* DOC: Theory of Operation
*
* The scmi-virtio transport implements a driver for the virtio SCMI device.
*
* There is one Tx channel (virtio cmdq, A2P channel) and at most one Rx
* channel (virtio eventq, P2A channel). Each channel is implemented through a
* virtqueue. Access to each virtqueue is protected by spinlocks.
*/
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/virtio.h>
#include <linux/virtio_config.h>
#include <uapi/linux/virtio_ids.h>
#include <uapi/linux/virtio_scmi.h>
#include "common.h"
#define VIRTIO_SCMI_MAX_MSG_SIZE 128 /* Value may be increased. */
#define VIRTIO_SCMI_MAX_PDU_SIZE \
(VIRTIO_SCMI_MAX_MSG_SIZE + SCMI_MSG_MAX_PROT_OVERHEAD)
#define DESCRIPTORS_PER_TX_MSG 2
/**
* struct scmi_vio_channel - Transport channel information
*
* @vqueue: Associated virtqueue
* @cinfo: SCMI Tx or Rx channel
* @free_list: List of unused scmi_vio_msg, maintained for Tx channels only
* @is_rx: Whether channel is an Rx channel
* @ready: Whether transport user is ready to hear about channel
* @max_msg: Maximum number of pending messages for this channel.
* @lock: Protects access to all members except ready.
* @ready_lock: Protects access to ready. If required, it must be taken before
* lock.
*/
struct scmi_vio_channel {
struct virtqueue *vqueue;
struct scmi_chan_info *cinfo;
struct list_head free_list;
bool is_rx;
bool ready;
unsigned int max_msg;
/* lock to protect access to all members except ready. */
spinlock_t lock;
/* lock to rotects access to ready flag. */
spinlock_t ready_lock;
};
/**
* struct scmi_vio_msg - Transport PDU information
*
* @request: SDU used for commands
* @input: SDU used for (delayed) responses and notifications
* @list: List which scmi_vio_msg may be part of
* @rx_len: Input SDU size in bytes, once input has been received
*/
struct scmi_vio_msg {
struct scmi_msg_payld *request;
struct scmi_msg_payld *input;
struct list_head list;
unsigned int rx_len;
};
/* Only one SCMI VirtIO device can possibly exist */
static struct virtio_device *scmi_vdev;
static bool scmi_vio_have_vq_rx(struct virtio_device *vdev)
{
return virtio_has_feature(vdev, VIRTIO_SCMI_F_P2A_CHANNELS);
}
static int scmi_vio_feed_vq_rx(struct scmi_vio_channel *vioch,
struct scmi_vio_msg *msg)
{
struct scatterlist sg_in;
int rc;
unsigned long flags;
sg_init_one(&sg_in, msg->input, VIRTIO_SCMI_MAX_PDU_SIZE);
spin_lock_irqsave(&vioch->lock, flags);
rc = virtqueue_add_inbuf(vioch->vqueue, &sg_in, 1, msg, GFP_ATOMIC);
if (rc)
dev_err_once(vioch->cinfo->dev,
"failed to add to virtqueue (%d)\n", rc);
else
virtqueue_kick(vioch->vqueue);
spin_unlock_irqrestore(&vioch->lock, flags);
return rc;
}
static void scmi_finalize_message(struct scmi_vio_channel *vioch,
struct scmi_vio_msg *msg)
{
if (vioch->is_rx) {
scmi_vio_feed_vq_rx(vioch, msg);
} else {
unsigned long flags;
spin_lock_irqsave(&vioch->lock, flags);
list_add(&msg->list, &vioch->free_list);
spin_unlock_irqrestore(&vioch->lock, flags);
}
}
static void scmi_vio_complete_cb(struct virtqueue *vqueue)
{
unsigned long ready_flags;
unsigned long flags;
unsigned int length;
struct scmi_vio_channel *vioch;
struct scmi_vio_msg *msg;
bool cb_enabled = true;
if (WARN_ON_ONCE(!vqueue->vdev->priv))
return;
vioch = &((struct scmi_vio_channel *)vqueue->vdev->priv)[vqueue->index];
for (;;) {
spin_lock_irqsave(&vioch->ready_lock, ready_flags);
if (!vioch->ready) {
if (!cb_enabled)
(void)virtqueue_enable_cb(vqueue);
goto unlock_ready_out;
}
spin_lock_irqsave(&vioch->lock, flags);
if (cb_enabled) {
virtqueue_disable_cb(vqueue);
cb_enabled = false;
}
msg = virtqueue_get_buf(vqueue, &length);
if (!msg) {
if (virtqueue_enable_cb(vqueue))
goto unlock_out;
cb_enabled = true;
}
spin_unlock_irqrestore(&vioch->lock, flags);
if (msg) {
msg->rx_len = length;
scmi_rx_callback(vioch->cinfo,
msg_read_header(msg->input), msg);
scmi_finalize_message(vioch, msg);
}
spin_unlock_irqrestore(&vioch->ready_lock, ready_flags);
}
unlock_out:
spin_unlock_irqrestore(&vioch->lock, flags);
unlock_ready_out:
spin_unlock_irqrestore(&vioch->ready_lock, ready_flags);
}
static const char *const scmi_vio_vqueue_names[] = { "tx", "rx" };
static vq_callback_t *scmi_vio_complete_callbacks[] = {
scmi_vio_complete_cb,
scmi_vio_complete_cb
};
static unsigned int virtio_get_max_msg(struct scmi_chan_info *base_cinfo)
{
struct scmi_vio_channel *vioch = base_cinfo->transport_info;
return vioch->max_msg;
}
static int virtio_link_supplier(struct device *dev)
{
if (!scmi_vdev) {
dev_notice_once(dev,
"Deferring probe after not finding a bound scmi-virtio device\n");
return -EPROBE_DEFER;
}
if (!device_link_add(dev, &scmi_vdev->dev,
DL_FLAG_AUTOREMOVE_CONSUMER)) {
dev_err(dev, "Adding link to supplier virtio device failed\n");
return -ECANCELED;
}
return 0;
}
static bool virtio_chan_available(struct device *dev, int idx)
{
struct scmi_vio_channel *channels, *vioch = NULL;
if (WARN_ON_ONCE(!scmi_vdev))
return false;
channels = (struct scmi_vio_channel *)scmi_vdev->priv;
switch (idx) {
case VIRTIO_SCMI_VQ_TX:
vioch = &channels[VIRTIO_SCMI_VQ_TX];
break;
case VIRTIO_SCMI_VQ_RX:
if (scmi_vio_have_vq_rx(scmi_vdev))
vioch = &channels[VIRTIO_SCMI_VQ_RX];
break;
default:
return false;
}
return vioch && !vioch->cinfo;
}
static int virtio_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
bool tx)
{
unsigned long flags;
struct scmi_vio_channel *vioch;
int index = tx ? VIRTIO_SCMI_VQ_TX : VIRTIO_SCMI_VQ_RX;
int i;
if (!scmi_vdev)
return -EPROBE_DEFER;
vioch = &((struct scmi_vio_channel *)scmi_vdev->priv)[index];
for (i = 0; i < vioch->max_msg; i++) {
struct scmi_vio_msg *msg;
msg = devm_kzalloc(cinfo->dev, sizeof(*msg), GFP_KERNEL);
if (!msg)
return -ENOMEM;
if (tx) {
msg->request = devm_kzalloc(cinfo->dev,
VIRTIO_SCMI_MAX_PDU_SIZE,
GFP_KERNEL);
if (!msg->request)
return -ENOMEM;
}
msg->input = devm_kzalloc(cinfo->dev, VIRTIO_SCMI_MAX_PDU_SIZE,
GFP_KERNEL);
if (!msg->input)
return -ENOMEM;
if (tx) {
spin_lock_irqsave(&vioch->lock, flags);
list_add_tail(&msg->list, &vioch->free_list);
spin_unlock_irqrestore(&vioch->lock, flags);
} else {
scmi_vio_feed_vq_rx(vioch, msg);
}
}
spin_lock_irqsave(&vioch->lock, flags);
cinfo->transport_info = vioch;
/* Indirectly setting channel not available any more */
vioch->cinfo = cinfo;
spin_unlock_irqrestore(&vioch->lock, flags);
spin_lock_irqsave(&vioch->ready_lock, flags);
vioch->ready = true;
spin_unlock_irqrestore(&vioch->ready_lock, flags);
return 0;
}
static int virtio_chan_free(int id, void *p, void *data)
{
unsigned long flags;
struct scmi_chan_info *cinfo = p;
struct scmi_vio_channel *vioch = cinfo->transport_info;
spin_lock_irqsave(&vioch->ready_lock, flags);
vioch->ready = false;
spin_unlock_irqrestore(&vioch->ready_lock, flags);
scmi_free_channel(cinfo, data, id);
spin_lock_irqsave(&vioch->lock, flags);
vioch->cinfo = NULL;
spin_unlock_irqrestore(&vioch->lock, flags);
return 0;
}
static int virtio_send_message(struct scmi_chan_info *cinfo,
struct scmi_xfer *xfer)
{
struct scmi_vio_channel *vioch = cinfo->transport_info;
struct scatterlist sg_out;
struct scatterlist sg_in;
struct scatterlist *sgs[DESCRIPTORS_PER_TX_MSG] = { &sg_out, &sg_in };
unsigned long flags;
int rc;
struct scmi_vio_msg *msg;
spin_lock_irqsave(&vioch->lock, flags);
if (list_empty(&vioch->free_list)) {
spin_unlock_irqrestore(&vioch->lock, flags);
return -EBUSY;
}
msg = list_first_entry(&vioch->free_list, typeof(*msg), list);
list_del(&msg->list);
msg_tx_prepare(msg->request, xfer);
sg_init_one(&sg_out, msg->request, msg_command_size(xfer));
sg_init_one(&sg_in, msg->input, msg_response_size(xfer));
rc = virtqueue_add_sgs(vioch->vqueue, sgs, 1, 1, msg, GFP_ATOMIC);
if (rc) {
list_add(&msg->list, &vioch->free_list);
dev_err_once(vioch->cinfo->dev,
"%s() failed to add to virtqueue (%d)\n", __func__,
rc);
} else {
virtqueue_kick(vioch->vqueue);
}
spin_unlock_irqrestore(&vioch->lock, flags);
return rc;
}
static void virtio_fetch_response(struct scmi_chan_info *cinfo,
struct scmi_xfer *xfer)
{
struct scmi_vio_msg *msg = xfer->priv;
if (msg) {
msg_fetch_response(msg->input, msg->rx_len, xfer);
xfer->priv = NULL;
}
}
static void virtio_fetch_notification(struct scmi_chan_info *cinfo,
size_t max_len, struct scmi_xfer *xfer)
{
struct scmi_vio_msg *msg = xfer->priv;
if (msg) {
msg_fetch_notification(msg->input, msg->rx_len, max_len, xfer);
xfer->priv = NULL;
}
}
static const struct scmi_transport_ops scmi_virtio_ops = {
.link_supplier = virtio_link_supplier,
.chan_available = virtio_chan_available,
.chan_setup = virtio_chan_setup,
.chan_free = virtio_chan_free,
.get_max_msg = virtio_get_max_msg,
.send_message = virtio_send_message,
.fetch_response = virtio_fetch_response,
.fetch_notification = virtio_fetch_notification,
};
static int scmi_vio_probe(struct virtio_device *vdev)
{
struct device *dev = &vdev->dev;
struct scmi_vio_channel *channels;
bool have_vq_rx;
int vq_cnt;
int i;
int ret;
struct virtqueue *vqs[VIRTIO_SCMI_VQ_MAX_CNT];
/* Only one SCMI VirtiO device allowed */
if (scmi_vdev)
return -EINVAL;
have_vq_rx = scmi_vio_have_vq_rx(vdev);
vq_cnt = have_vq_rx ? VIRTIO_SCMI_VQ_MAX_CNT : 1;
channels = devm_kcalloc(dev, vq_cnt, sizeof(*channels), GFP_KERNEL);
if (!channels)
return -ENOMEM;
if (have_vq_rx)
channels[VIRTIO_SCMI_VQ_RX].is_rx = true;
ret = virtio_find_vqs(vdev, vq_cnt, vqs, scmi_vio_complete_callbacks,
scmi_vio_vqueue_names, NULL);
if (ret) {
dev_err(dev, "Failed to get %d virtqueue(s)\n", vq_cnt);
return ret;
}
for (i = 0; i < vq_cnt; i++) {
unsigned int sz;
spin_lock_init(&channels[i].lock);
spin_lock_init(&channels[i].ready_lock);
INIT_LIST_HEAD(&channels[i].free_list);
channels[i].vqueue = vqs[i];
sz = virtqueue_get_vring_size(channels[i].vqueue);
/* Tx messages need multiple descriptors. */
if (!channels[i].is_rx)
sz /= DESCRIPTORS_PER_TX_MSG;
if (sz > MSG_TOKEN_MAX) {
dev_info_once(dev,
"%s virtqueue could hold %d messages. Only %ld allowed to be pending.\n",
channels[i].is_rx ? "rx" : "tx",
sz, MSG_TOKEN_MAX);
sz = MSG_TOKEN_MAX;
}
channels[i].max_msg = sz;
}
vdev->priv = channels;
scmi_vdev = vdev;
return 0;
}
static void scmi_vio_remove(struct virtio_device *vdev)
{
vdev->config->reset(vdev);
vdev->config->del_vqs(vdev);
scmi_vdev = NULL;
}
static int scmi_vio_validate(struct virtio_device *vdev)
{
if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
dev_err(&vdev->dev,
"device does not comply with spec version 1.x\n");
return -EINVAL;
}
return 0;
}
static unsigned int features[] = {
VIRTIO_SCMI_F_P2A_CHANNELS,
};
static const struct virtio_device_id id_table[] = {
{ VIRTIO_ID_SCMI, VIRTIO_DEV_ANY_ID },
{ 0 }
};
static struct virtio_driver virtio_scmi_driver = {
.driver.name = "scmi-virtio",
.driver.owner = THIS_MODULE,
.feature_table = features,
.feature_table_size = ARRAY_SIZE(features),
.id_table = id_table,
.probe = scmi_vio_probe,
.remove = scmi_vio_remove,
.validate = scmi_vio_validate,
};
static int __init virtio_scmi_init(void)
{
return register_virtio_driver(&virtio_scmi_driver);
}
static void __exit virtio_scmi_exit(void)
{
unregister_virtio_driver(&virtio_scmi_driver);
}
const struct scmi_desc scmi_virtio_desc = {
.transport_init = virtio_scmi_init,
.transport_exit = virtio_scmi_exit,
.ops = &scmi_virtio_ops,
.max_rx_timeout_ms = 60000, /* for non-realtime virtio devices */
.max_msg = 0, /* overridden by virtio_get_max_msg() */
.max_msg_size = VIRTIO_SCMI_MAX_MSG_SIZE,
};
......@@ -71,7 +71,7 @@ static struct qcom_scm_wb_entry qcom_scm_wb[] = {
{ .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 },
};
static const char *qcom_scm_convention_names[] = {
static const char * const qcom_scm_convention_names[] = {
[SMC_CONVENTION_UNKNOWN] = "unknown",
[SMC_CONVENTION_ARM_32] = "smc arm 32",
[SMC_CONVENTION_ARM_64] = "smc arm 64",
......@@ -331,7 +331,7 @@ int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
.owner = ARM_SMCCC_OWNER_SIP,
};
if (!cpus || (cpus && cpumask_empty(cpus)))
if (!cpus || cpumask_empty(cpus))
return -EINVAL;
for_each_cpu(cpu, cpus) {
......@@ -1299,6 +1299,7 @@ static const struct of_device_id qcom_scm_dt_match[] = {
{ .compatible = "qcom,scm" },
{}
};
MODULE_DEVICE_TABLE(of, qcom_scm_dt_match);
static struct platform_driver qcom_scm_driver = {
.driver = {
......@@ -1315,3 +1316,6 @@ static int __init qcom_scm_init(void)
return platform_driver_register(&qcom_scm_driver);
}
subsys_initcall(qcom_scm_init);
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. SCM driver");
MODULE_LICENSE("GPL v2");
......@@ -296,25 +296,61 @@ static int bpmp_debug_show(struct seq_file *m, void *p)
struct file *file = m->private;
struct inode *inode = file_inode(file);
struct tegra_bpmp *bpmp = inode->i_private;
char *databuf = NULL;
char fnamebuf[256];
const char *filename;
uint32_t nbytes = 0;
size_t len;
int err;
len = seq_get_buf(m, &databuf);
if (!databuf)
return -ENOMEM;
struct mrq_debug_request req = {
.cmd = cpu_to_le32(CMD_DEBUG_READ),
};
struct mrq_debug_response resp;
struct tegra_bpmp_message msg = {
.mrq = MRQ_DEBUG,
.tx = {
.data = &req,
.size = sizeof(req),
},
.rx = {
.data = &resp,
.size = sizeof(resp),
},
};
uint32_t fd = 0, len = 0;
int remaining, err;
filename = get_filename(bpmp, file, fnamebuf, sizeof(fnamebuf));
if (!filename)
return -ENOENT;
err = mrq_debug_read(bpmp, filename, databuf, len, &nbytes);
if (!err)
seq_commit(m, nbytes);
mutex_lock(&bpmp_debug_lock);
err = mrq_debug_open(bpmp, filename, &fd, &len, 0);
if (err)
goto out;
req.frd.fd = fd;
remaining = len;
while (remaining > 0) {
err = tegra_bpmp_transfer(bpmp, &msg);
if (err < 0) {
goto close;
} else if (msg.rx.ret < 0) {
err = -EINVAL;
goto close;
}
if (resp.frd.readlen > remaining) {
pr_err("%s: read data length invalid\n", __func__);
err = -EINVAL;
goto close;
}
seq_write(m, resp.frd.data, resp.frd.readlen);
remaining -= resp.frd.readlen;
}
close:
err = mrq_debug_close(bpmp, fd);
out:
mutex_unlock(&bpmp_debug_lock);
return err;
}
......
......@@ -253,6 +253,7 @@ config SPAPR_TCE_IOMMU
config ARM_SMMU
tristate "ARM Ltd. System MMU (SMMU) Support"
depends on ARM64 || ARM || (COMPILE_TEST && !GENERIC_ATOMIC64)
depends on QCOM_SCM || !QCOM_SCM #if QCOM_SCM=m this can't be =y
select IOMMU_API
select IOMMU_IO_PGTABLE_LPAE
select ARM_DMA_USE_IOMMU if ARM
......@@ -382,6 +383,7 @@ config QCOM_IOMMU
# Note: iommu drivers cannot (yet?) be built as modules
bool "Qualcomm IOMMU Support"
depends on ARCH_QCOM || (COMPILE_TEST && !GENERIC_ATOMIC64)
depends on QCOM_SCM=y
select IOMMU_API
select IOMMU_IO_PGTABLE_LPAE
select ARM_DMA_USE_IOMMU
......
......@@ -9,6 +9,7 @@
* Copyright (C) 2009 Texas Instruments
* Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
*/
#include <linux/cpu_pm.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/init.h>
......@@ -232,7 +233,10 @@ struct gpmc_device {
int irq;
struct irq_chip irq_chip;
struct gpio_chip gpio_chip;
struct notifier_block nb;
struct omap3_gpmc_regs context;
int nirqs;
unsigned int is_suspended:1;
};
static struct irq_domain *gpmc_irq_domain;
......@@ -2384,6 +2388,106 @@ static int gpmc_gpio_init(struct gpmc_device *gpmc)
return 0;
}
static void omap3_gpmc_save_context(struct gpmc_device *gpmc)
{
struct omap3_gpmc_regs *gpmc_context;
int i;
if (!gpmc || !gpmc_base)
return;
gpmc_context = &gpmc->context;
gpmc_context->sysconfig = gpmc_read_reg(GPMC_SYSCONFIG);
gpmc_context->irqenable = gpmc_read_reg(GPMC_IRQENABLE);
gpmc_context->timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
gpmc_context->config = gpmc_read_reg(GPMC_CONFIG);
gpmc_context->prefetch_config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
gpmc_context->prefetch_config2 = gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
gpmc_context->prefetch_control = gpmc_read_reg(GPMC_PREFETCH_CONTROL);
for (i = 0; i < gpmc_cs_num; i++) {
gpmc_context->cs_context[i].is_valid = gpmc_cs_mem_enabled(i);
if (gpmc_context->cs_context[i].is_valid) {
gpmc_context->cs_context[i].config1 =
gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
gpmc_context->cs_context[i].config2 =
gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
gpmc_context->cs_context[i].config3 =
gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
gpmc_context->cs_context[i].config4 =
gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
gpmc_context->cs_context[i].config5 =
gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
gpmc_context->cs_context[i].config6 =
gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
gpmc_context->cs_context[i].config7 =
gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
}
}
}
static void omap3_gpmc_restore_context(struct gpmc_device *gpmc)
{
struct omap3_gpmc_regs *gpmc_context;
int i;
if (!gpmc || !gpmc_base)
return;
gpmc_context = &gpmc->context;
gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context->sysconfig);
gpmc_write_reg(GPMC_IRQENABLE, gpmc_context->irqenable);
gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context->timeout_ctrl);
gpmc_write_reg(GPMC_CONFIG, gpmc_context->config);
gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context->prefetch_config1);
gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context->prefetch_config2);
gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context->prefetch_control);
for (i = 0; i < gpmc_cs_num; i++) {
if (gpmc_context->cs_context[i].is_valid) {
gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
gpmc_context->cs_context[i].config1);
gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
gpmc_context->cs_context[i].config2);
gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
gpmc_context->cs_context[i].config3);
gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
gpmc_context->cs_context[i].config4);
gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
gpmc_context->cs_context[i].config5);
gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
gpmc_context->cs_context[i].config6);
gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
gpmc_context->cs_context[i].config7);
} else {
gpmc_cs_write_reg(i, GPMC_CS_CONFIG7, 0);
}
}
}
static int omap_gpmc_context_notifier(struct notifier_block *nb,
unsigned long cmd, void *v)
{
struct gpmc_device *gpmc;
gpmc = container_of(nb, struct gpmc_device, nb);
if (gpmc->is_suspended || pm_runtime_suspended(gpmc->dev))
return NOTIFY_OK;
switch (cmd) {
case CPU_CLUSTER_PM_ENTER:
omap3_gpmc_save_context(gpmc);
break;
case CPU_CLUSTER_PM_ENTER_FAILED: /* No need to restore context */
break;
case CPU_CLUSTER_PM_EXIT:
omap3_gpmc_restore_context(gpmc);
break;
}
return NOTIFY_OK;
}
static int gpmc_probe(struct platform_device *pdev)
{
int rc;
......@@ -2472,6 +2576,9 @@ static int gpmc_probe(struct platform_device *pdev)
gpmc_probe_dt_children(pdev);
gpmc->nb.notifier_call = omap_gpmc_context_notifier;
cpu_pm_register_notifier(&gpmc->nb);
return 0;
gpio_init_failed:
......@@ -2486,6 +2593,7 @@ static int gpmc_remove(struct platform_device *pdev)
{
struct gpmc_device *gpmc = platform_get_drvdata(pdev);
cpu_pm_unregister_notifier(&gpmc->nb);
gpmc_free_irq(gpmc);
gpmc_mem_exit();
pm_runtime_put_sync(&pdev->dev);
......@@ -2497,15 +2605,23 @@ static int gpmc_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int gpmc_suspend(struct device *dev)
{
omap3_gpmc_save_context();
struct gpmc_device *gpmc = dev_get_drvdata(dev);
omap3_gpmc_save_context(gpmc);
pm_runtime_put_sync(dev);
gpmc->is_suspended = 1;
return 0;
}
static int gpmc_resume(struct device *dev)
{
struct gpmc_device *gpmc = dev_get_drvdata(dev);
pm_runtime_get_sync(dev);
omap3_gpmc_restore_context();
omap3_gpmc_restore_context(gpmc);
gpmc->is_suspended = 0;
return 0;
}
#endif
......@@ -2527,74 +2643,3 @@ static __init int gpmc_init(void)
return platform_driver_register(&gpmc_driver);
}
postcore_initcall(gpmc_init);
static struct omap3_gpmc_regs gpmc_context;
void omap3_gpmc_save_context(void)
{
int i;
if (!gpmc_base)
return;
gpmc_context.sysconfig = gpmc_read_reg(GPMC_SYSCONFIG);
gpmc_context.irqenable = gpmc_read_reg(GPMC_IRQENABLE);
gpmc_context.timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
gpmc_context.config = gpmc_read_reg(GPMC_CONFIG);
gpmc_context.prefetch_config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
gpmc_context.prefetch_config2 = gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
gpmc_context.prefetch_control = gpmc_read_reg(GPMC_PREFETCH_CONTROL);
for (i = 0; i < gpmc_cs_num; i++) {
gpmc_context.cs_context[i].is_valid = gpmc_cs_mem_enabled(i);
if (gpmc_context.cs_context[i].is_valid) {
gpmc_context.cs_context[i].config1 =
gpmc_cs_read_reg(i, GPMC_CS_CONFIG1);
gpmc_context.cs_context[i].config2 =
gpmc_cs_read_reg(i, GPMC_CS_CONFIG2);
gpmc_context.cs_context[i].config3 =
gpmc_cs_read_reg(i, GPMC_CS_CONFIG3);
gpmc_context.cs_context[i].config4 =
gpmc_cs_read_reg(i, GPMC_CS_CONFIG4);
gpmc_context.cs_context[i].config5 =
gpmc_cs_read_reg(i, GPMC_CS_CONFIG5);
gpmc_context.cs_context[i].config6 =
gpmc_cs_read_reg(i, GPMC_CS_CONFIG6);
gpmc_context.cs_context[i].config7 =
gpmc_cs_read_reg(i, GPMC_CS_CONFIG7);
}
}
}
void omap3_gpmc_restore_context(void)
{
int i;
if (!gpmc_base)
return;
gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
gpmc_write_reg(GPMC_CONFIG, gpmc_context.config);
gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
for (i = 0; i < gpmc_cs_num; i++) {
if (gpmc_context.cs_context[i].is_valid) {
gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
gpmc_context.cs_context[i].config1);
gpmc_cs_write_reg(i, GPMC_CS_CONFIG2,
gpmc_context.cs_context[i].config2);
gpmc_cs_write_reg(i, GPMC_CS_CONFIG3,
gpmc_context.cs_context[i].config3);
gpmc_cs_write_reg(i, GPMC_CS_CONFIG4,
gpmc_context.cs_context[i].config4);
gpmc_cs_write_reg(i, GPMC_CS_CONFIG5,
gpmc_context.cs_context[i].config5);
gpmc_cs_write_reg(i, GPMC_CS_CONFIG6,
gpmc_context.cs_context[i].config6);
gpmc_cs_write_reg(i, GPMC_CS_CONFIG7,
gpmc_context.cs_context[i].config7);
}
}
}
......@@ -71,6 +71,7 @@ static int tegra186_mc_resume(struct tegra_mc *mc)
return 0;
}
#if IS_ENABLED(CONFIG_IOMMU_API)
static void tegra186_mc_client_sid_override(struct tegra_mc *mc,
const struct tegra_mc_client *client,
unsigned int sid)
......@@ -108,6 +109,7 @@ static void tegra186_mc_client_sid_override(struct tegra_mc *mc,
writel(sid, mc->regs + client->regs.sid.override);
}
}
#endif
static int tegra186_mc_probe_device(struct tegra_mc *mc, struct device *dev)
{
......
......@@ -44,6 +44,7 @@ config ATH10K_SNOC
tristate "Qualcomm ath10k SNOC support"
depends on ATH10K
depends on ARCH_QCOM || COMPILE_TEST
depends on QCOM_SCM || !QCOM_SCM #if QCOM_SCM=m this can't be =y
select QCOM_QMI_HELPERS
help
This module adds support for integrated WCN3990 chip connected
......
......@@ -181,6 +181,13 @@ config RESET_RASPBERRYPI
interfacing with RPi4's co-processor and model these firmware
initialization routines as reset lines.
config RESET_RZG2L_USBPHY_CTRL
tristate "Renesas RZ/G2L USBPHY control driver"
depends on ARCH_R9A07G044 || COMPILE_TEST
help
Support for USBPHY Control found on RZ/G2L family. It mainly
controls reset and power down of the USB/PHY.
config RESET_SCMI
tristate "Reset driver controlled via ARM SCMI interface"
depends on ARM_SCMI_PROTOCOL || COMPILE_TEST
......@@ -207,7 +214,6 @@ config RESET_SIMPLE
- Realtek SoCs
- RCC reset controller in STM32 MCUs
- Allwinner SoCs
- ZTE's zx2967 family
- SiFive FU740 SoCs
config RESET_SOCFPGA
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册