forked from Minki/linux
ARM: SoC drivers for v5.11
There are a couple of subsystems maintained by other people that merge their drivers through the SoC tree, those changes include: - The SCMI firmware framework gains support for sensor notifications and for controlling voltage domains. - A large update for the Tegra memory controller driver, integrating it better with the interconnect framework - The memory controller subsystem gains support for Mediatek MT8192 - The reset controller framework gains support for sharing pulsed resets For Soc specific drivers in drivers/soc, the main changes are - The Allwinner/sunxi MBUS gets a rework for the way it handles dma_map_ops and offsets between physical and dma address spaces. - An errata fix plus some cleanups for Freescale Layerscape SoCs - A cleanup for renesas drivers regarding MMIO accesses. - New SoC specific drivers for Mediatek MT8192 and MT8183 power domains - New SoC specific drivers for Aspeed AST2600 LPC bus control and SoC identification. - Core Power Domain support for Qualcomm MSM8916, MSM8939, SDM660 and SDX55. - A rework of the TI AM33xx 'genpd' power domain support to use information from DT instead of platform data - Support for TI AM64x SoCs - Allow building some Amlogic drivers as modules instead of built-in Finally, there are numerous cleanups and smaller bug fixes for Mediatek, Tegra, Samsung, Qualcomm, TI OMAP, Amlogic, Rockchips, Renesas, and Xilinx SoCs. There is a trivial conflict in the cedrus driver, with two branches adding the same CEDRUS_CAPABILITY_H265_DEC flag, and another trivial remove/remove conflict in linux/dma-mapping.h. Signed-off-by: Arnd Bergmann <arnd@arndb.de> -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAl/alSUACgkQmmx57+YA GNm7GRAAlNMVi7F0f4Ixf1bEh+J2QUonYIpZfrdxOLFwISGQ+nstGrFW2He/OeQv KAi027tZLl6Sdzjy809cLDPA4Z2IKwjVWhEbBHybvy1+irPYjnixtLd0x3YvPhjH iadlcjQ3uaGue8PvubK6CVnBEy82A+Pp29n9i4A4wX/8w+BVIhVsxwQWUBF8pFXE 3La2UZYZMVMvVZMrpTOqwCgdmLDCk+RLMVZ1IiRqBEBq5/DVq03uIXgjGEOrq8tl PXC89w7K510Is891mbBdBThQf+pZkU1vwORuknDcEJKWs9ngbEha7ebVgp32kbFl pi8DEK205d106WQgfn0Zxkpbsp8XD058wDILwkhBcteXlBaUEL6btGVLDTUCJZuv /pkH8tL4lNGpThQFbCEXC8oHZBp2xk55P+SW9RRZOoA5tAp+sz7hlf3y3YKdCSxv 4xybeeVOAgjl01WtbEC7CuIkqcKVSQ7njhLhC8r5ASteNywDThqxLT6nd0VegcQc YH3Eu9QRXpvFwQ35zMkTMWa27bMG5d60fp90bWT0R5amXZpxJJot87w8trFCxv74 mE5KvCbefCRNsTt8GOBA/WR7hVaG369g07qOvs7g4LjJEM3Nl2h/A4/zVFef9O0t yq3Nm4YCGfDSAQXzGR2SJ3nxiqbDknzJTAtZPf4BmbaMuPOIJ5k= =BjJf -----END PGP SIGNATURE----- Merge tag 'arm-soc-drivers-5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc Pull ARM SoC driver updates from Arnd Bergmann: "There are a couple of subsystems maintained by other people that merge their drivers through the SoC tree, those changes include: - The SCMI firmware framework gains support for sensor notifications and for controlling voltage domains. - A large update for the Tegra memory controller driver, integrating it better with the interconnect framework - The memory controller subsystem gains support for Mediatek MT8192 - The reset controller framework gains support for sharing pulsed resets For Soc specific drivers in drivers/soc, the main changes are - The Allwinner/sunxi MBUS gets a rework for the way it handles dma_map_ops and offsets between physical and dma address spaces. - An errata fix plus some cleanups for Freescale Layerscape SoCs - A cleanup for renesas drivers regarding MMIO accesses. - New SoC specific drivers for Mediatek MT8192 and MT8183 power domains - New SoC specific drivers for Aspeed AST2600 LPC bus control and SoC identification. - Core Power Domain support for Qualcomm MSM8916, MSM8939, SDM660 and SDX55. - A rework of the TI AM33xx 'genpd' power domain support to use information from DT instead of platform data - Support for TI AM64x SoCs - Allow building some Amlogic drivers as modules instead of built-in Finally, there are numerous cleanups and smaller bug fixes for Mediatek, Tegra, Samsung, Qualcomm, TI OMAP, Amlogic, Rockchips, Renesas, and Xilinx SoCs" * tag 'arm-soc-drivers-5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (222 commits) soc: mediatek: mmsys: Specify HAS_IOMEM dependency for MTK_MMSYS firmware: xilinx: Properly align function parameter firmware: xilinx: Add a blank line after function declaration firmware: xilinx: Remove additional newline firmware: xilinx: Fix kernel-doc warnings firmware: xlnx-zynqmp: fix compilation warning soc: xilinx: vcu: add missing register NUM_CORE soc: xilinx: vcu: use vcu-settings syscon registers dt-bindings: soc: xlnx: extract xlnx, vcu-settings to separate binding soc: xilinx: vcu: drop useless success message clk: samsung: mark PM functions as __maybe_unused soc: samsung: exynos-chipid: initialize later - with arch_initcall soc: samsung: exynos-chipid: order list of SoCs by name memory: jz4780_nemc: Fix potential NULL dereference in jz4780_nemc_probe() memory: ti-emif-sram: only build for ARMv7 memory: tegra30: Support interconnect framework memory: tegra20: Support hardware versioning and clean up OPP table initialization dt-bindings: memory: tegra20-emc: Document opp-supported-hw property soc: rockchip: io-domain: Fix error return code in rockchip_iodomain_probe() reset-controller: ti: force the write operation when assert or deassert ...
This commit is contained in:
commit
48c1c40ab4
@ -2948,7 +2948,7 @@
|
||||
mtdset= [ARM]
|
||||
ARM/S3C2412 JIVE boot control
|
||||
|
||||
See arch/arm/mach-s3c2412/mach-jive.c
|
||||
See arch/arm/mach-s3c/mach-jive.c
|
||||
|
||||
mtouchusb.raw_coordinates=
|
||||
[HW] Make the MicroTouch USB driver use raw coordinates
|
||||
|
@ -29,7 +29,7 @@ GPIOLIB
|
||||
|
||||
The following functions now either have a `s3c_` specific variant
|
||||
or are merged into gpiolib. See the definitions in
|
||||
arch/arm/plat-samsung/include/plat/gpio-cfg.h:
|
||||
arch/arm/mach-s3c/gpio-cfg.h:
|
||||
|
||||
- s3c2410_gpio_setpin() gpio_set_value() or gpio_direction_output()
|
||||
- s3c2410_gpio_getpin() gpio_get_value() or gpio_direction_input()
|
||||
@ -86,7 +86,7 @@ between the calls.
|
||||
Headers
|
||||
-------
|
||||
|
||||
See arch/arm/mach-s3c24xx/include/mach/regs-gpio.h for the list
|
||||
See arch/arm/mach-s3c/regs-gpio-s3c24xx.h for the list
|
||||
of GPIO pins, and the configuration values for them. This
|
||||
is included by using #include <mach/regs-gpio.h>
|
||||
|
||||
|
@ -18,7 +18,7 @@ Introduction
|
||||
versions.
|
||||
|
||||
The S3C2416 and S3C2450 devices are very similar and S3C2450 support is
|
||||
included under the arch/arm/mach-s3c2416 directory. Note, while core
|
||||
included under the arch/arm/mach-s3c directory. Note, while core
|
||||
support for these SoCs is in, work on some of the extra peripherals
|
||||
and extra interrupts is still ongoing.
|
||||
|
||||
@ -37,19 +37,11 @@ Configuration
|
||||
Layout
|
||||
------
|
||||
|
||||
The core support files are located in the platform code contained in
|
||||
arch/arm/plat-s3c24xx with headers in include/asm-arm/plat-s3c24xx.
|
||||
This directory should be kept to items shared between the platform
|
||||
code (arch/arm/plat-s3c24xx) and the arch/arm/mach-s3c24* code.
|
||||
The core support files, register, kernel and paltform data are located in the
|
||||
platform code contained in arch/arm/mach-s3c with headers in
|
||||
arch/arm/mach-s3c/include
|
||||
|
||||
Each cpu has a directory with the support files for it, and the
|
||||
machines that carry the device. For example S3C2410 is contained
|
||||
in arch/arm/mach-s3c2410 and S3C2440 in arch/arm/mach-s3c2440
|
||||
|
||||
Register, kernel and platform data definitions are held in the
|
||||
arch/arm/mach-s3c2410 directory./include/mach
|
||||
|
||||
arch/arm/plat-s3c24xx:
|
||||
arch/arm/mach-s3c:
|
||||
|
||||
Files in here are either common to all the s3c24xx family,
|
||||
or are common to only some of them with names to indicate this
|
||||
@ -134,7 +126,7 @@ Adding New Machines
|
||||
should keep this in mind before altering items outside of their own
|
||||
machine files.
|
||||
|
||||
Machine definitions should be kept in linux/arch/arm/mach-s3c2410,
|
||||
Machine definitions should be kept in arch/arm/mach-s3c,
|
||||
and there are a number of examples that can be looked at.
|
||||
|
||||
Read the kernel patch submission policies as well as the
|
||||
@ -293,7 +285,7 @@ Platform Data
|
||||
}
|
||||
|
||||
Note, since the code is marked as __init, it should not be
|
||||
exported outside arch/arm/mach-s3c2410/, or exported to
|
||||
exported outside arch/arm/mach-s3c/, or exported to
|
||||
modules via EXPORT_SYMBOL() and related functions.
|
||||
|
||||
|
||||
|
@ -36,7 +36,7 @@ Board Support
|
||||
-------------
|
||||
|
||||
The driver attaches to a platform device, which will need to be
|
||||
added by the board specific support file in linux/arch/arm/mach-s3c2410,
|
||||
added by the board specific support file in arch/arm/mach-s3c,
|
||||
such as mach-bast.c or mach-smdk2410.c
|
||||
|
||||
The platform device's platform_data field is only needed if the
|
||||
@ -51,9 +51,9 @@ Board Support
|
||||
Platform Data
|
||||
-------------
|
||||
|
||||
See arch/arm/mach-s3c2410/include/mach/usb-control.h for the
|
||||
See include/linux/platform_data/usb-ohci-s3c2410.h for the
|
||||
descriptions of the platform device data. An implementation
|
||||
can be found in linux/arch/arm/mach-s3c2410/usb-simtec.c .
|
||||
can be found in arch/arm/mach-s3c/simtec-usb.c .
|
||||
|
||||
The `struct s3c2410_hcd_info` contains a pair of functions
|
||||
that get called to enable over-current detection, and to
|
||||
|
@ -37,5 +37,4 @@ implementation to configure pins as necessary.
|
||||
The s3c_gpio_cfgpin() and s3c_gpio_setpull() provide the means for a
|
||||
driver or machine to change gpio configuration.
|
||||
|
||||
See arch/arm/plat-samsung/include/plat/gpio-cfg.h for more information
|
||||
on these functions.
|
||||
See arch/arm/mach-s3c/gpio-cfg.h for more information on these functions.
|
||||
|
@ -23,6 +23,7 @@ properties:
|
||||
enum:
|
||||
- qcom,sc7180-llcc
|
||||
- qcom,sdm845-llcc
|
||||
- qcom,sm8150-llcc
|
||||
|
||||
reg:
|
||||
items:
|
||||
|
@ -18,8 +18,30 @@ clock-names. See ../../clock/clock-bindings.txt for details.
|
||||
../../reset/reset.txt for details.
|
||||
- reset-names: Must include the following entries:
|
||||
- actmon
|
||||
- operating-points-v2: See ../bindings/opp/opp.txt for details.
|
||||
- interconnects: Should contain entries for memory clients sitting on
|
||||
MC->EMC memory interconnect path.
|
||||
- interconnect-names: Should include name of the interconnect path for each
|
||||
interconnect entry. Consult TRM documentation for
|
||||
information about available memory clients, see MEMORY
|
||||
CONTROLLER section.
|
||||
|
||||
For each opp entry in 'operating-points-v2' table:
|
||||
- opp-supported-hw: bitfield indicating SoC speedo ID mask
|
||||
- opp-peak-kBps: peak bandwidth of the memory channel
|
||||
|
||||
Example:
|
||||
dfs_opp_table: opp-table {
|
||||
compatible = "operating-points-v2";
|
||||
|
||||
opp@12750000 {
|
||||
opp-hz = /bits/ 64 <12750000>;
|
||||
opp-supported-hw = <0x000F>;
|
||||
opp-peak-kBps = <51000>;
|
||||
};
|
||||
...
|
||||
};
|
||||
|
||||
actmon@6000c800 {
|
||||
compatible = "nvidia,tegra124-actmon";
|
||||
reg = <0x0 0x6000c800 0x0 0x400>;
|
||||
@ -29,4 +51,7 @@ Example:
|
||||
clock-names = "actmon", "emc";
|
||||
resets = <&tegra_car 119>;
|
||||
reset-names = "actmon";
|
||||
operating-points-v2 = <&dfs_opp_table>;
|
||||
interconnects = <&mc TEGRA124_MC_MPCORER &emc>;
|
||||
interconnect-names = "cpu";
|
||||
};
|
||||
|
@ -20,6 +20,10 @@ Required properties:
|
||||
- reset-names: Must include the following entries:
|
||||
- host1x
|
||||
|
||||
Each host1x client module having to perform DMA through the Memory Controller
|
||||
should have the interconnect endpoints set to the Memory Client and External
|
||||
Memory respectively.
|
||||
|
||||
The host1x top-level node defines a number of children, each representing one
|
||||
of the following host1x client modules:
|
||||
|
||||
@ -36,6 +40,12 @@ of the following host1x client modules:
|
||||
- reset-names: Must include the following entries:
|
||||
- mpe
|
||||
|
||||
Optional properties:
|
||||
- interconnects: Must contain entry for the MPE memory clients.
|
||||
- interconnect-names: Must include name of the interconnect path for each
|
||||
interconnect entry. Consult TRM documentation for information about
|
||||
available memory clients, see MEMORY CONTROLLER section.
|
||||
|
||||
- vi: video input
|
||||
|
||||
Required properties:
|
||||
@ -113,6 +123,12 @@ of the following host1x client modules:
|
||||
Required properties:
|
||||
- remote-endpoint: phandle to vi port 'endpoint' node.
|
||||
|
||||
Optional properties:
|
||||
- interconnects: Must contain entry for the VI memory clients.
|
||||
- interconnect-names: Must include name of the interconnect path for each
|
||||
interconnect entry. Consult TRM documentation for information about
|
||||
available memory clients, see MEMORY CONTROLLER section.
|
||||
|
||||
- epp: encoder pre-processor
|
||||
|
||||
Required properties:
|
||||
@ -126,6 +142,12 @@ of the following host1x client modules:
|
||||
- reset-names: Must include the following entries:
|
||||
- epp
|
||||
|
||||
Optional properties:
|
||||
- interconnects: Must contain entry for the EPP memory clients.
|
||||
- interconnect-names: Must include name of the interconnect path for each
|
||||
interconnect entry. Consult TRM documentation for information about
|
||||
available memory clients, see MEMORY CONTROLLER section.
|
||||
|
||||
- isp: image signal processor
|
||||
|
||||
Required properties:
|
||||
@ -139,6 +161,12 @@ of the following host1x client modules:
|
||||
- reset-names: Must include the following entries:
|
||||
- isp
|
||||
|
||||
Optional properties:
|
||||
- interconnects: Must contain entry for the ISP memory clients.
|
||||
- interconnect-names: Must include name of the interconnect path for each
|
||||
interconnect entry. Consult TRM documentation for information about
|
||||
available memory clients, see MEMORY CONTROLLER section.
|
||||
|
||||
- gr2d: 2D graphics engine
|
||||
|
||||
Required properties:
|
||||
@ -152,6 +180,12 @@ of the following host1x client modules:
|
||||
- reset-names: Must include the following entries:
|
||||
- 2d
|
||||
|
||||
Optional properties:
|
||||
- interconnects: Must contain entry for the GR2D memory clients.
|
||||
- interconnect-names: Must include name of the interconnect path for each
|
||||
interconnect entry. Consult TRM documentation for information about
|
||||
available memory clients, see MEMORY CONTROLLER section.
|
||||
|
||||
- gr3d: 3D graphics engine
|
||||
|
||||
Required properties:
|
||||
@ -170,6 +204,12 @@ of the following host1x client modules:
|
||||
- 3d
|
||||
- 3d2 (Only required on SoCs with two 3D clocks)
|
||||
|
||||
Optional properties:
|
||||
- interconnects: Must contain entry for the GR3D memory clients.
|
||||
- interconnect-names: Must include name of the interconnect path for each
|
||||
interconnect entry. Consult TRM documentation for information about
|
||||
available memory clients, see MEMORY CONTROLLER section.
|
||||
|
||||
- dc: display controller
|
||||
|
||||
Required properties:
|
||||
@ -197,6 +237,10 @@ of the following host1x client modules:
|
||||
- nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
|
||||
- nvidia,edid: supplies a binary EDID blob
|
||||
- nvidia,panel: phandle of a display panel
|
||||
- interconnects: Must contain entry for the DC memory clients.
|
||||
- interconnect-names: Must include name of the interconnect path for each
|
||||
interconnect entry. Consult TRM documentation for information about
|
||||
available memory clients, see MEMORY CONTROLLER section.
|
||||
|
||||
- hdmi: High Definition Multimedia Interface
|
||||
|
||||
@ -345,6 +389,12 @@ of the following host1x client modules:
|
||||
- reset-names: Must include the following entries:
|
||||
- vic
|
||||
|
||||
Optional properties:
|
||||
- interconnects: Must contain entry for the VIC memory clients.
|
||||
- interconnect-names: Must include name of the interconnect path for each
|
||||
interconnect entry. Consult TRM documentation for information about
|
||||
available memory clients, see MEMORY CONTROLLER section.
|
||||
|
||||
Example:
|
||||
|
||||
/ {
|
||||
@ -498,6 +548,15 @@ Example:
|
||||
resets = <&tegra_car 27>;
|
||||
reset-names = "dc";
|
||||
|
||||
interconnects = <&mc TEGRA20_MC_DISPLAY0A &emc>,
|
||||
<&mc TEGRA20_MC_DISPLAY0B &emc>,
|
||||
<&mc TEGRA20_MC_DISPLAY0C &emc>,
|
||||
<&mc TEGRA20_MC_DISPLAYHC &emc>;
|
||||
interconnect-names = "wina",
|
||||
"winb",
|
||||
"winc",
|
||||
"cursor";
|
||||
|
||||
rgb {
|
||||
status = "disabled";
|
||||
};
|
||||
@ -513,6 +572,15 @@ Example:
|
||||
resets = <&tegra_car 26>;
|
||||
reset-names = "dc";
|
||||
|
||||
interconnects = <&mc TEGRA20_MC_DISPLAY0AB &emc>,
|
||||
<&mc TEGRA20_MC_DISPLAY0BB &emc>,
|
||||
<&mc TEGRA20_MC_DISPLAY0CB &emc>,
|
||||
<&mc TEGRA20_MC_DISPLAYHCB &emc>;
|
||||
interconnect-names = "wina",
|
||||
"winb",
|
||||
"winc",
|
||||
"cursor";
|
||||
|
||||
rgb {
|
||||
status = "disabled";
|
||||
};
|
||||
|
@ -1,50 +0,0 @@
|
||||
SMI (Smart Multimedia Interface) Common
|
||||
|
||||
The hardware block diagram please check bindings/iommu/mediatek,iommu.txt
|
||||
|
||||
Mediatek SMI have two generations of HW architecture, here is the list
|
||||
which generation the SoCs use:
|
||||
generation 1: mt2701 and mt7623.
|
||||
generation 2: mt2712, mt6779, mt8167, mt8173 and mt8183.
|
||||
|
||||
There's slight differences between the two SMI, for generation 2, the
|
||||
register which control the iommu port is at each larb's register base. But
|
||||
for generation 1, the register is at smi ao base(smi always on register
|
||||
base). Besides that, the smi async clock should be prepared and enabled for
|
||||
SMI generation 1 to transform the smi clock into emi clock domain, but that is
|
||||
not needed for SMI generation 2.
|
||||
|
||||
Required properties:
|
||||
- compatible : must be one of :
|
||||
"mediatek,mt2701-smi-common"
|
||||
"mediatek,mt2712-smi-common"
|
||||
"mediatek,mt6779-smi-common"
|
||||
"mediatek,mt7623-smi-common", "mediatek,mt2701-smi-common"
|
||||
"mediatek,mt8167-smi-common"
|
||||
"mediatek,mt8173-smi-common"
|
||||
"mediatek,mt8183-smi-common"
|
||||
- reg : the register and size of the SMI block.
|
||||
- power-domains : a phandle to the power domain of this local arbiter.
|
||||
- clocks : Must contain an entry for each entry in clock-names.
|
||||
- clock-names : must contain 3 entries for generation 1 smi HW and 2 entries
|
||||
for generation 2 smi HW as follows:
|
||||
- "apb" : Advanced Peripheral Bus clock, It's the clock for setting
|
||||
the register.
|
||||
- "smi" : It's the clock for transfer data and command.
|
||||
They may be the same if both source clocks are the same.
|
||||
- "async" : asynchronous clock, it help transform the smi clock into the emi
|
||||
clock domain, this clock is only needed by generation 1 smi HW.
|
||||
and these 2 option clocks for generation 2 smi HW:
|
||||
- "gals0": the path0 clock of GALS(Global Async Local Sync).
|
||||
- "gals1": the path1 clock of GALS(Global Async Local Sync).
|
||||
Here is the list which has this GALS: mt6779 and mt8183.
|
||||
|
||||
Example:
|
||||
smi_common: smi@14022000 {
|
||||
compatible = "mediatek,mt8173-smi-common";
|
||||
reg = <0 0x14022000 0 0x1000>;
|
||||
power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
|
||||
clocks = <&mmsys CLK_MM_SMI_COMMON>,
|
||||
<&mmsys CLK_MM_SMI_COMMON>;
|
||||
clock-names = "apb", "smi";
|
||||
};
|
@ -0,0 +1,142 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (c) 2020 MediaTek Inc.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/memory-controllers/mediatek,smi-common.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: SMI (Smart Multimedia Interface) Common
|
||||
|
||||
maintainers:
|
||||
- Yong Wu <yong.wu@mediatek.com>
|
||||
|
||||
description: |
|
||||
The hardware block diagram please check bindings/iommu/mediatek,iommu.yaml
|
||||
|
||||
MediaTek SMI have two generations of HW architecture, here is the list
|
||||
which generation the SoCs use:
|
||||
generation 1: mt2701 and mt7623.
|
||||
generation 2: mt2712, mt6779, mt8167, mt8173, mt8183 and mt8192.
|
||||
|
||||
There's slight differences between the two SMI, for generation 2, the
|
||||
register which control the iommu port is at each larb's register base. But
|
||||
for generation 1, the register is at smi ao base(smi always on register
|
||||
base). Besides that, the smi async clock should be prepared and enabled for
|
||||
SMI generation 1 to transform the smi clock into emi clock domain, but that is
|
||||
not needed for SMI generation 2.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- enum:
|
||||
- mediatek,mt2701-smi-common
|
||||
- mediatek,mt2712-smi-common
|
||||
- mediatek,mt6779-smi-common
|
||||
- mediatek,mt8167-smi-common
|
||||
- mediatek,mt8173-smi-common
|
||||
- mediatek,mt8183-smi-common
|
||||
- mediatek,mt8192-smi-common
|
||||
|
||||
- description: for mt7623
|
||||
items:
|
||||
- const: mediatek,mt7623-smi-common
|
||||
- const: mediatek,mt2701-smi-common
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
description: |
|
||||
apb and smi are mandatory. the async is only for generation 1 smi HW.
|
||||
gals(global async local sync) also is optional, see below.
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
items:
|
||||
- description: apb is Advanced Peripheral Bus clock, It's the clock for
|
||||
setting the register.
|
||||
- description: smi is the clock for transfer data and command.
|
||||
- description: async is asynchronous clock, it help transform the smi
|
||||
clock into the emi clock domain.
|
||||
- description: gals0 is the path0 clock of gals.
|
||||
- description: gals1 is the path1 clock of gals.
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- power-domains
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
allOf:
|
||||
- if: # only for gen1 HW
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- mediatek,mt2701-smi-common
|
||||
then:
|
||||
properties:
|
||||
clock:
|
||||
items:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
clock-names:
|
||||
items:
|
||||
- const: apb
|
||||
- const: smi
|
||||
- const: async
|
||||
|
||||
- if: # for gen2 HW that have gals
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt6779-smi-common
|
||||
- mediatek,mt8183-smi-common
|
||||
- mediatek,mt8192-smi-common
|
||||
|
||||
then:
|
||||
properties:
|
||||
clock:
|
||||
items:
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
clock-names:
|
||||
items:
|
||||
- const: apb
|
||||
- const: smi
|
||||
- const: gals0
|
||||
- const: gals1
|
||||
|
||||
else: # for gen2 HW that don't have gals
|
||||
properties:
|
||||
clock:
|
||||
items:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: apb
|
||||
- const: smi
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |+
|
||||
#include <dt-bindings/clock/mt8173-clk.h>
|
||||
#include <dt-bindings/power/mt8173-power.h>
|
||||
|
||||
smi_common: smi@14022000 {
|
||||
compatible = "mediatek,mt8173-smi-common";
|
||||
reg = <0x14022000 0x1000>;
|
||||
power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
|
||||
clocks = <&mmsys CLK_MM_SMI_COMMON>,
|
||||
<&mmsys CLK_MM_SMI_COMMON>;
|
||||
clock-names = "apb", "smi";
|
||||
};
|
@ -1,50 +0,0 @@
|
||||
SMI (Smart Multimedia Interface) Local Arbiter
|
||||
|
||||
The hardware block diagram please check bindings/iommu/mediatek,iommu.txt
|
||||
|
||||
Required properties:
|
||||
- compatible : must be one of :
|
||||
"mediatek,mt2701-smi-larb"
|
||||
"mediatek,mt2712-smi-larb"
|
||||
"mediatek,mt6779-smi-larb"
|
||||
"mediatek,mt7623-smi-larb", "mediatek,mt2701-smi-larb"
|
||||
"mediatek,mt8167-smi-larb"
|
||||
"mediatek,mt8173-smi-larb"
|
||||
"mediatek,mt8183-smi-larb"
|
||||
- reg : the register and size of this local arbiter.
|
||||
- mediatek,smi : a phandle to the smi_common node.
|
||||
- power-domains : a phandle to the power domain of this local arbiter.
|
||||
- clocks : Must contain an entry for each entry in clock-names.
|
||||
- clock-names: must contain 2 entries, as follows:
|
||||
- "apb" : Advanced Peripheral Bus clock, It's the clock for setting
|
||||
the register.
|
||||
- "smi" : It's the clock for transfer data and command.
|
||||
and this optional clock name:
|
||||
- "gals": the clock for GALS(Global Async Local Sync).
|
||||
Here is the list which has this GALS: mt8183.
|
||||
|
||||
Required property for mt2701, mt2712, mt6779, mt7623 and mt8167:
|
||||
- mediatek,larb-id :the hardware id of this larb.
|
||||
|
||||
Example:
|
||||
larb1: larb@16010000 {
|
||||
compatible = "mediatek,mt8173-smi-larb";
|
||||
reg = <0 0x16010000 0 0x1000>;
|
||||
mediatek,smi = <&smi_common>;
|
||||
power-domains = <&scpsys MT8173_POWER_DOMAIN_VDEC>;
|
||||
clocks = <&vdecsys CLK_VDEC_CKEN>,
|
||||
<&vdecsys CLK_VDEC_LARB_CKEN>;
|
||||
clock-names = "apb", "smi";
|
||||
};
|
||||
|
||||
Example for mt2701:
|
||||
larb0: larb@14010000 {
|
||||
compatible = "mediatek,mt2701-smi-larb";
|
||||
reg = <0 0x14010000 0 0x1000>;
|
||||
mediatek,smi = <&smi_common>;
|
||||
mediatek,larb-id = <0>;
|
||||
clocks = <&mmsys CLK_MM_SMI_LARB0>,
|
||||
<&mmsys CLK_MM_SMI_LARB0>;
|
||||
clock-names = "apb", "smi";
|
||||
power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>;
|
||||
};
|
@ -0,0 +1,132 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (c) 2020 MediaTek Inc.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/memory-controllers/mediatek,smi-larb.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: SMI (Smart Multimedia Interface) Local Arbiter
|
||||
|
||||
maintainers:
|
||||
- Yong Wu <yong.wu@mediatek.com>
|
||||
|
||||
description: |
|
||||
The hardware block diagram please check bindings/iommu/mediatek,iommu.yaml
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- enum:
|
||||
- mediatek,mt2701-smi-larb
|
||||
- mediatek,mt2712-smi-larb
|
||||
- mediatek,mt6779-smi-larb
|
||||
- mediatek,mt8167-smi-larb
|
||||
- mediatek,mt8173-smi-larb
|
||||
- mediatek,mt8183-smi-larb
|
||||
- mediatek,mt8192-smi-larb
|
||||
|
||||
- description: for mt7623
|
||||
items:
|
||||
- const: mediatek,mt7623-smi-larb
|
||||
- const: mediatek,mt2701-smi-larb
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
description: |
|
||||
apb and smi are mandatory. gals(global async local sync) is optional.
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
items:
|
||||
- description: apb is Advanced Peripheral Bus clock, It's the clock for
|
||||
setting the register.
|
||||
- description: smi is the clock for transfer data and command.
|
||||
- description: the clock for gals.
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
mediatek,smi:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
description: a phandle to the smi_common node.
|
||||
|
||||
mediatek,larb-id:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 31
|
||||
description: the hardware id of this larb. It's only required when this
|
||||
hardward id is not consecutive from its M4U point of view.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- power-domains
|
||||
|
||||
allOf:
|
||||
- if: # HW has gals
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt8183-smi-larb
|
||||
|
||||
then:
|
||||
properties:
|
||||
clock:
|
||||
items:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
clock-names:
|
||||
items:
|
||||
- const: apb
|
||||
- const: smi
|
||||
- const: gals
|
||||
|
||||
else:
|
||||
properties:
|
||||
clock:
|
||||
items:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: apb
|
||||
- const: smi
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- mediatek,mt2701-smi-larb
|
||||
- mediatek,mt2712-smi-larb
|
||||
- mediatek,mt6779-smi-larb
|
||||
- mediatek,mt8167-smi-larb
|
||||
- mediatek,mt8192-smi-larb
|
||||
|
||||
then:
|
||||
required:
|
||||
- mediatek,larb-id
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |+
|
||||
#include <dt-bindings/clock/mt8173-clk.h>
|
||||
#include <dt-bindings/power/mt8173-power.h>
|
||||
|
||||
larb1: larb@16010000 {
|
||||
compatible = "mediatek,mt8173-smi-larb";
|
||||
reg = <0x16010000 0x1000>;
|
||||
mediatek,smi = <&smi_common>;
|
||||
power-domains = <&scpsys MT8173_POWER_DOMAIN_VDEC>;
|
||||
clocks = <&vdecsys CLK_VDEC_CKEN>,
|
||||
<&vdecsys CLK_VDEC_LARB_CKEN>;
|
||||
clock-names = "apb", "smi";
|
||||
};
|
@ -29,11 +29,23 @@ properties:
|
||||
items:
|
||||
- const: emc
|
||||
|
||||
"#interconnect-cells":
|
||||
const: 0
|
||||
|
||||
nvidia,memory-controller:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
phandle of the memory controller node
|
||||
|
||||
core-supply:
|
||||
description:
|
||||
Phandle of voltage regulator of the SoC "core" power domain.
|
||||
|
||||
operating-points-v2:
|
||||
description:
|
||||
Should contain freqs and voltages and opp-supported-hw property, which
|
||||
is a bitfield indicating SoC speedo ID mask.
|
||||
|
||||
patternProperties:
|
||||
"^emc-timings-[0-9]+$":
|
||||
type: object
|
||||
@ -327,6 +339,8 @@ required:
|
||||
- clocks
|
||||
- clock-names
|
||||
- nvidia,memory-controller
|
||||
- "#interconnect-cells"
|
||||
- operating-points-v2
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
@ -345,6 +359,7 @@ examples:
|
||||
|
||||
#iommu-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#interconnect-cells = <1>;
|
||||
};
|
||||
|
||||
external-memory-controller@7001b000 {
|
||||
@ -354,6 +369,10 @@ examples:
|
||||
clock-names = "emc";
|
||||
|
||||
nvidia,memory-controller = <&mc>;
|
||||
operating-points-v2 = <&dvfs_opp_table>;
|
||||
core-supply = <&vdd_core>;
|
||||
|
||||
#interconnect-cells = <0>;
|
||||
|
||||
emc-timings-0 {
|
||||
nvidia,ram-code = <3>;
|
||||
|
@ -40,6 +40,9 @@ properties:
|
||||
"#iommu-cells":
|
||||
const: 1
|
||||
|
||||
"#interconnect-cells":
|
||||
const: 1
|
||||
|
||||
patternProperties:
|
||||
"^emc-timings-[0-9]+$":
|
||||
type: object
|
||||
@ -104,6 +107,7 @@ required:
|
||||
- clock-names
|
||||
- "#reset-cells"
|
||||
- "#iommu-cells"
|
||||
- "#interconnect-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
@ -119,6 +123,7 @@ examples:
|
||||
|
||||
#iommu-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#interconnect-cells = <1>;
|
||||
|
||||
emc-timings-3 {
|
||||
nvidia,ram-code = <3>;
|
||||
|
@ -12,18 +12,44 @@ Properties:
|
||||
irrespective of ram-code configuration.
|
||||
- interrupts : Should contain EMC General interrupt.
|
||||
- clocks : Should contain EMC clock.
|
||||
- nvidia,memory-controller : Phandle of the Memory Controller node.
|
||||
- #interconnect-cells : Should be 0.
|
||||
- operating-points-v2: See ../bindings/opp/opp.txt for details.
|
||||
|
||||
For each opp entry in 'operating-points-v2' table:
|
||||
- opp-supported-hw: One bitfield indicating SoC process ID mask
|
||||
|
||||
A bitwise AND is performed against this value and if any bit
|
||||
matches, the OPP gets enabled.
|
||||
|
||||
Optional properties:
|
||||
- core-supply: Phandle of voltage regulator of the SoC "core" power domain.
|
||||
|
||||
Child device nodes describe the memory settings for different configurations and clock rates.
|
||||
|
||||
Example:
|
||||
|
||||
opp_table: opp-table {
|
||||
compatible = "operating-points-v2";
|
||||
|
||||
opp@36000000 {
|
||||
opp-microvolt = <950000 950000 1300000>;
|
||||
opp-hz = /bits/ 64 <36000000>;
|
||||
};
|
||||
...
|
||||
};
|
||||
|
||||
memory-controller@7000f400 {
|
||||
#address-cells = < 1 >;
|
||||
#size-cells = < 0 >;
|
||||
#interconnect-cells = <0>;
|
||||
compatible = "nvidia,tegra20-emc";
|
||||
reg = <0x7000f4000 0x200>;
|
||||
reg = <0x7000f400 0x400>;
|
||||
interrupts = <0 78 0x04>;
|
||||
clocks = <&tegra_car TEGRA20_CLK_EMC>;
|
||||
nvidia,memory-controller = <&mc>;
|
||||
core-supply = <&core_vdd_reg>;
|
||||
operating-points-v2 = <&opp_table>;
|
||||
}
|
||||
|
||||
|
||||
|
@ -16,6 +16,8 @@ Required properties:
|
||||
IOMMU specifier needed to encode an address. GART supports only a single
|
||||
address space that is shared by all devices, therefore no additional
|
||||
information needed for the address encoding.
|
||||
- #interconnect-cells : Should be 1. This cell represents memory client.
|
||||
The assignments may be found in header file <dt-bindings/memory/tegra20-mc.h>.
|
||||
|
||||
Example:
|
||||
mc: memory-controller@7000f000 {
|
||||
@ -27,6 +29,7 @@ Example:
|
||||
interrupts = <GIC_SPI 77 0x04>;
|
||||
#reset-cells = <1>;
|
||||
#iommu-cells = <0>;
|
||||
#interconnect-cells = <1>;
|
||||
};
|
||||
|
||||
video-codec@6001a000 {
|
||||
|
@ -31,11 +31,23 @@ properties:
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
"#interconnect-cells":
|
||||
const: 0
|
||||
|
||||
nvidia,memory-controller:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle of the Memory Controller node.
|
||||
|
||||
core-supply:
|
||||
description:
|
||||
Phandle of voltage regulator of the SoC "core" power domain.
|
||||
|
||||
operating-points-v2:
|
||||
description:
|
||||
Should contain freqs and voltages and opp-supported-hw property, which
|
||||
is a bitfield indicating SoC speedo ID mask.
|
||||
|
||||
patternProperties:
|
||||
"^emc-timings-[0-9]+$":
|
||||
type: object
|
||||
@ -214,6 +226,8 @@ required:
|
||||
- interrupts
|
||||
- clocks
|
||||
- nvidia,memory-controller
|
||||
- "#interconnect-cells"
|
||||
- operating-points-v2
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
@ -226,6 +240,10 @@ examples:
|
||||
clocks = <&tegra_car 57>;
|
||||
|
||||
nvidia,memory-controller = <&mc>;
|
||||
operating-points-v2 = <&dvfs_opp_table>;
|
||||
core-supply = <&vdd_core>;
|
||||
|
||||
#interconnect-cells = <0>;
|
||||
|
||||
emc-timings-1 {
|
||||
nvidia,ram-code = <1>;
|
||||
|
@ -57,6 +57,9 @@ properties:
|
||||
"#iommu-cells":
|
||||
const: 1
|
||||
|
||||
"#interconnect-cells":
|
||||
const: 1
|
||||
|
||||
patternProperties:
|
||||
"^emc-timings-[0-9]+$":
|
||||
type: object
|
||||
@ -120,6 +123,7 @@ required:
|
||||
- clock-names
|
||||
- "#reset-cells"
|
||||
- "#iommu-cells"
|
||||
- "#interconnect-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
@ -135,6 +139,7 @@ examples:
|
||||
|
||||
#iommu-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#interconnect-cells = <1>;
|
||||
|
||||
emc-timings-1 {
|
||||
nvidia,ram-code = <1>;
|
||||
|
@ -46,6 +46,7 @@ Required properties
|
||||
- compatible: One of:
|
||||
"aspeed,ast2400-lpc", "simple-mfd"
|
||||
"aspeed,ast2500-lpc", "simple-mfd"
|
||||
"aspeed,ast2600-lpc", "simple-mfd"
|
||||
|
||||
- reg: contains the physical address and length values of the Aspeed
|
||||
LPC memory region.
|
||||
@ -64,6 +65,7 @@ BMC Node
|
||||
- compatible: One of:
|
||||
"aspeed,ast2400-lpc-bmc"
|
||||
"aspeed,ast2500-lpc-bmc"
|
||||
"aspeed,ast2600-lpc-bmc"
|
||||
|
||||
- reg: contains the physical address and length values of the
|
||||
H8S/2168-compatible LPC controller memory region
|
||||
@ -74,6 +76,7 @@ Host Node
|
||||
- compatible: One of:
|
||||
"aspeed,ast2400-lpc-host", "simple-mfd", "syscon"
|
||||
"aspeed,ast2500-lpc-host", "simple-mfd", "syscon"
|
||||
"aspeed,ast2600-lpc-host", "simple-mfd", "syscon"
|
||||
|
||||
- reg: contains the address and length values of the host-related
|
||||
register space for the Aspeed LPC controller
|
||||
@ -128,6 +131,7 @@ Required properties:
|
||||
- compatible: One of:
|
||||
"aspeed,ast2400-lpc-ctrl";
|
||||
"aspeed,ast2500-lpc-ctrl";
|
||||
"aspeed,ast2600-lpc-ctrl";
|
||||
|
||||
- reg: contains offset/length values of the host interface controller
|
||||
memory regions
|
||||
@ -168,6 +172,7 @@ Required properties:
|
||||
- compatible: One of:
|
||||
"aspeed,ast2400-lhc";
|
||||
"aspeed,ast2500-lhc";
|
||||
"aspeed,ast2600-lhc";
|
||||
|
||||
- reg: contains offset/length values of the LHC memory regions. In the
|
||||
AST2400 and AST2500 there are two regions.
|
||||
@ -187,7 +192,8 @@ state of the LPC bus. Some systems may chose to modify this configuration.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: "aspeed,ast2500-lpc-reset" or
|
||||
- compatible: "aspeed,ast2600-lpc-reset" or
|
||||
"aspeed,ast2500-lpc-reset"
|
||||
"aspeed,ast2400-lpc-reset"
|
||||
- reg: offset and length of the IP in the LHC memory region
|
||||
- #reset-controller indicates the number of reset cells expected
|
||||
|
@ -20,3 +20,29 @@ syscon: syscon@1e6e2000 {
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
Silicon ID
|
||||
-----------------
|
||||
|
||||
Families have unique hardware silicon identifiers within the SoC.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: "aspeed,silicon-id" or:
|
||||
"aspeed,ast2400-silicon-id" or
|
||||
"aspeed,ast2500-silicon-id" or
|
||||
"aspeed,ast2600-silicon-id"
|
||||
|
||||
- reg: offset and length of the silicon id information
|
||||
optionally, a second offset and length describes the unique chip id
|
||||
|
||||
The reg should be the unique silicon id register, and
|
||||
not backwards compatible one in eg. the 2600.
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
silicon-id@7c {
|
||||
compatible = "aspeed,ast2500-silicon-id", "aspeed,silicon-id";
|
||||
reg = <0x7c 0x4 0x150 0x8>;
|
||||
};
|
||||
|
@ -16,12 +16,16 @@ description:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,msm8916-rpmpd
|
||||
- qcom,msm8939-rpmpd
|
||||
- qcom,msm8976-rpmpd
|
||||
- qcom,msm8996-rpmpd
|
||||
- qcom,msm8998-rpmpd
|
||||
- qcom,qcs404-rpmpd
|
||||
- qcom,sdm660-rpmpd
|
||||
- qcom,sc7180-rpmhpd
|
||||
- qcom,sdm845-rpmhpd
|
||||
- qcom,sdx55-rpmhpd
|
||||
- qcom,sm8150-rpmhpd
|
||||
- qcom,sm8250-rpmhpd
|
||||
|
||||
|
58
Documentation/devicetree/bindings/soc/mediatek/devapc.yaml
Normal file
58
Documentation/devicetree/bindings/soc/mediatek/devapc.yaml
Normal file
@ -0,0 +1,58 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
# # Copyright 2020 MediaTek Inc.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/soc/mediatek/devapc.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: MediaTek Device Access Permission Control driver
|
||||
|
||||
description: |
|
||||
MediaTek bus fabric provides TrustZone security support and data
|
||||
protection to prevent slaves from being accessed by unexpected masters.
|
||||
The security violation is logged and sent to the processor for further
|
||||
analysis and countermeasures.
|
||||
|
||||
maintainers:
|
||||
- Neal Liu <neal.liu@mediatek.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt6779-devapc
|
||||
|
||||
reg:
|
||||
description: The base address of devapc register bank
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
description: A single interrupt specifier
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
description: Contains module clock source and clock names
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
description: Names of the clocks list in clocks property
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/mt6779-clk.h>
|
||||
|
||||
devapc: devapc@10207000 {
|
||||
compatible = "mediatek,mt6779-devapc";
|
||||
reg = <0x10207000 0x1000>;
|
||||
interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_LOW>;
|
||||
clocks = <&infracfg_ao CLK_INFRA_DEVICE_APC>;
|
||||
clock-names = "devapc-infra-clock";
|
||||
};
|
@ -0,0 +1,34 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/soc/xilinx/xlnx,vcu-settings.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Xilinx VCU Settings
|
||||
|
||||
maintainers:
|
||||
- Michael Tretter <kernel@pengutronix.de>
|
||||
|
||||
description: |
|
||||
The Xilinx VCU Settings provides information about the configuration of the
|
||||
video codec unit.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: xlnx,vcu-settings
|
||||
- const: syscon
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
examples:
|
||||
- |
|
||||
xlnx_vcu: vcu@a0041000 {
|
||||
compatible = "xlnx,vcu-settings", "syscon";
|
||||
reg = <0x0 0xa0041000 0x0 0x1000>;
|
||||
};
|
@ -12,10 +12,7 @@ Required properties:
|
||||
- compatible: shall be one of:
|
||||
"xlnx,vcu"
|
||||
"xlnx,vcu-logicoreip-1.0"
|
||||
- reg, reg-names: There are two sets of registers need to provide.
|
||||
1. vcu slcr
|
||||
2. Logicore
|
||||
reg-names should contain name for the each register sequence.
|
||||
- reg : The base offset and size of the VCU_PL_SLCR register space.
|
||||
- clocks: phandle for aclk and pll_ref clocksource
|
||||
- clock-names: The identification string, "aclk", is always required for
|
||||
the axi clock. "pll_ref" is required for pll.
|
||||
@ -23,9 +20,7 @@ Example:
|
||||
|
||||
xlnx_vcu: vcu@a0040000 {
|
||||
compatible = "xlnx,vcu-logicoreip-1.0";
|
||||
reg = <0x0 0xa0040000 0x0 0x1000>,
|
||||
<0x0 0xa0041000 0x0 0x1000>;
|
||||
reg-names = "vcu_slcr", "logicore";
|
||||
reg = <0x0 0xa0040000 0x0 0x1000>;
|
||||
clocks = <&si570_1>, <&clkc 71>;
|
||||
clock-names = "pll_ref", "aclk";
|
||||
};
|
||||
|
@ -34,7 +34,7 @@ These resources should be specified in that order, as the ordering of the
|
||||
two address regions is important (the driver expects these to be address
|
||||
and then data).
|
||||
|
||||
An example from arch/arm/mach-s3c2410/mach-bast.c is::
|
||||
An example from arch/arm/mach-s3c/mach-bast.c is::
|
||||
|
||||
static struct resource bast_dm9k_resource[] = {
|
||||
[0] = {
|
||||
|
@ -2074,7 +2074,7 @@ M: Matthias Brugger <matthias.bgg@gmail.com>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
W: https://mtk.bcnfs.org/
|
||||
W: https://mtk.wiki.kernel.org/
|
||||
C: irc://chat.freenode.net/linux-mediatek
|
||||
F: arch/arm/boot/dts/mt6*
|
||||
F: arch/arm/boot/dts/mt7*
|
||||
@ -11429,6 +11429,7 @@ S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl.git
|
||||
F: Documentation/devicetree/bindings/memory-controllers/
|
||||
F: drivers/memory/
|
||||
F: include/dt-bindings/memory/
|
||||
|
||||
MEMORY FREQUENCY SCALING DRIVERS FOR NVIDIA TEGRA
|
||||
M: Dmitry Osipenko <digetx@gmail.com>
|
||||
|
@ -192,6 +192,11 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
silicon-id@7c {
|
||||
compatible = "aspeed,ast2400-silicon-id", "aspeed,silicon-id";
|
||||
reg = <0x7c 0x4>;
|
||||
};
|
||||
|
||||
pinctrl: pinctrl@80 {
|
||||
reg = <0x80 0x18>, <0xa0 0x10>;
|
||||
compatible = "aspeed,ast2400-pinctrl";
|
||||
|
@ -239,6 +239,11 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
silicon-id@7c {
|
||||
compatible = "aspeed,ast2500-silicon-id", "aspeed,silicon-id";
|
||||
reg = <0x7c 0x4 0x150 0x8>;
|
||||
};
|
||||
|
||||
pinctrl: pinctrl@80 {
|
||||
compatible = "aspeed,ast2500-pinctrl";
|
||||
reg = <0x80 0x18>, <0xa0 0x10>;
|
||||
|
@ -317,6 +317,11 @@
|
||||
compatible = "aspeed,ast2600-pinctrl";
|
||||
};
|
||||
|
||||
silicon-id@14 {
|
||||
compatible = "aspeed,ast2600-silicon-id", "aspeed,silicon-id";
|
||||
reg = <0x14 0x4 0x5b0 0x8>;
|
||||
};
|
||||
|
||||
smp-memram@180 {
|
||||
compatible = "aspeed,ast2600-smpmem";
|
||||
reg = <0x180 0x40>;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dma-map-ops.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_address.h>
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dma-map-ops.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
|
@ -627,6 +627,9 @@ static struct clockdomain *_get_clkdm(struct omap_hwmod *oh)
|
||||
{
|
||||
struct clk_hw_omap *clk;
|
||||
|
||||
if (!oh)
|
||||
return NULL;
|
||||
|
||||
if (oh->clkdm) {
|
||||
return oh->clkdm;
|
||||
} else if (oh->_clk) {
|
||||
@ -3677,6 +3680,9 @@ static void __init omap_hwmod_setup_earlycon_flags(void)
|
||||
*/
|
||||
static int __init omap_hwmod_setup_all(void)
|
||||
{
|
||||
if (!inited)
|
||||
return 0;
|
||||
|
||||
_ensure_mpu_hwmod_is_setup(NULL);
|
||||
|
||||
omap_hwmod_for_each(_init, NULL);
|
||||
|
@ -580,6 +580,8 @@ static void pdata_quirks_check(struct pdata_init *quirks)
|
||||
|
||||
void __init pdata_quirks_init(const struct of_device_id *omap_dt_match_table)
|
||||
{
|
||||
struct device_node *np;
|
||||
|
||||
/*
|
||||
* We still need this for omap2420 and omap3 PM to work, others are
|
||||
* using drivers/misc/sram.c already.
|
||||
@ -591,6 +593,15 @@ void __init pdata_quirks_init(const struct of_device_id *omap_dt_match_table)
|
||||
if (of_machine_is_compatible("ti,omap3"))
|
||||
omap3_mcbsp_init();
|
||||
pdata_quirks_check(auxdata_quirks);
|
||||
|
||||
/* Populate always-on PRCM in l4_wkup to probe l4_wkup */
|
||||
np = of_find_node_by_name(NULL, "prcm");
|
||||
if (!np)
|
||||
np = of_find_node_by_name(NULL, "prm");
|
||||
if (np)
|
||||
of_platform_populate(np, omap_dt_match_table,
|
||||
omap_auxdata_lookup, NULL);
|
||||
|
||||
of_platform_populate(NULL, omap_dt_match_table,
|
||||
omap_auxdata_lookup, NULL);
|
||||
pdata_quirks_check(pdata_quirks);
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/async.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dma-map-ops.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/sh_clk.h>
|
||||
|
@ -11,7 +11,8 @@
|
||||
#include <linux/pci_ids.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/dma-direct.h>
|
||||
#include <linux/dma-map-ops.h>
|
||||
#include <linux/swiotlb.h>
|
||||
#include <asm/iommu.h>
|
||||
|
||||
#define STA2X11_SWIOTLB_SIZE (4*1024*1024)
|
||||
|
@ -853,8 +853,12 @@ static int sysc_ioremap(struct sysc *ddata)
|
||||
*/
|
||||
static int sysc_map_and_check_registers(struct sysc *ddata)
|
||||
{
|
||||
struct device_node *np = ddata->dev->of_node;
|
||||
int error;
|
||||
|
||||
if (!of_get_property(np, "reg", NULL))
|
||||
return 0;
|
||||
|
||||
error = sysc_parse_and_check_child_range(ddata);
|
||||
if (error)
|
||||
return error;
|
||||
@ -1222,10 +1226,10 @@ static int __maybe_unused sysc_runtime_suspend(struct device *dev)
|
||||
ddata->enabled = false;
|
||||
|
||||
err_allow_idle:
|
||||
reset_control_assert(ddata->rsts);
|
||||
|
||||
sysc_clkdm_allow_idle(ddata);
|
||||
|
||||
reset_control_assert(ddata->rsts);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -1379,6 +1383,8 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
|
||||
SYSC_QUIRK_CLKDM_NOAUTO),
|
||||
SYSC_QUIRK("dwc3", 0x488c0000, 0, 0x10, -ENODEV, 0x500a0200, 0xffffffff,
|
||||
SYSC_QUIRK_CLKDM_NOAUTO),
|
||||
SYSC_QUIRK("gpmc", 0, 0, 0x10, 0x14, 0x00000060, 0xffffffff,
|
||||
SYSC_QUIRK_GPMC_DEBUG),
|
||||
SYSC_QUIRK("hdmi", 0, 0, 0x10, -ENODEV, 0x50030200, 0xffffffff,
|
||||
SYSC_QUIRK_OPT_CLKS_NEEDED),
|
||||
SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff,
|
||||
@ -1814,6 +1820,14 @@ static void sysc_init_module_quirks(struct sysc *ddata)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OMAP_GPMC_DEBUG
|
||||
if (ddata->cfg.quirks & SYSC_QUIRK_GPMC_DEBUG) {
|
||||
ddata->cfg.quirks |= SYSC_QUIRK_NO_RESET_ON_INIT;
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_I2C) {
|
||||
ddata->pre_reset_quirk = sysc_pre_reset_quirk_i2c;
|
||||
ddata->post_reset_quirk = sysc_post_reset_quirk_i2c;
|
||||
@ -1945,6 +1959,7 @@ static int sysc_reset(struct sysc *ddata)
|
||||
*/
|
||||
static int sysc_init_module(struct sysc *ddata)
|
||||
{
|
||||
bool rstctrl_deasserted = false;
|
||||
int error = 0;
|
||||
|
||||
error = sysc_clockdomain_init(ddata);
|
||||
@ -1969,6 +1984,7 @@ static int sysc_init_module(struct sysc *ddata)
|
||||
error = reset_control_deassert(ddata->rsts);
|
||||
if (error)
|
||||
goto err_main_clocks;
|
||||
rstctrl_deasserted = true;
|
||||
}
|
||||
|
||||
ddata->revision = sysc_read_revision(ddata);
|
||||
@ -1978,13 +1994,13 @@ static int sysc_init_module(struct sysc *ddata)
|
||||
if (ddata->legacy_mode) {
|
||||
error = sysc_legacy_init(ddata);
|
||||
if (error)
|
||||
goto err_reset;
|
||||
goto err_main_clocks;
|
||||
}
|
||||
|
||||
if (!ddata->legacy_mode) {
|
||||
error = sysc_enable_module(ddata->dev);
|
||||
if (error)
|
||||
goto err_reset;
|
||||
goto err_main_clocks;
|
||||
}
|
||||
|
||||
error = sysc_reset(ddata);
|
||||
@ -1994,10 +2010,6 @@ static int sysc_init_module(struct sysc *ddata)
|
||||
if (error && !ddata->legacy_mode)
|
||||
sysc_disable_module(ddata->dev);
|
||||
|
||||
err_reset:
|
||||
if (error && !(ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT))
|
||||
reset_control_assert(ddata->rsts);
|
||||
|
||||
err_main_clocks:
|
||||
if (error)
|
||||
sysc_disable_main_clocks(ddata);
|
||||
@ -2008,6 +2020,10 @@ err_opt_clocks:
|
||||
sysc_clkdm_allow_idle(ddata);
|
||||
}
|
||||
|
||||
if (error && rstctrl_deasserted &&
|
||||
!(ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT))
|
||||
reset_control_assert(ddata->rsts);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -2909,6 +2925,9 @@ static int sysc_probe(struct platform_device *pdev)
|
||||
if (!ddata)
|
||||
return -ENOMEM;
|
||||
|
||||
ddata->offsets[SYSC_REVISION] = -ENODEV;
|
||||
ddata->offsets[SYSC_SYSCONFIG] = -ENODEV;
|
||||
ddata->offsets[SYSC_SYSSTATUS] = -ENODEV;
|
||||
ddata->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
|
||||
@ -2975,9 +2994,6 @@ static int sysc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* Balance use counts as PM runtime should have enabled these all */
|
||||
if (!(ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT))
|
||||
reset_control_assert(ddata->rsts);
|
||||
|
||||
if (!(ddata->cfg.quirks &
|
||||
(SYSC_QUIRK_NO_IDLE | SYSC_QUIRK_NO_IDLE_ON_INIT))) {
|
||||
sysc_disable_main_clocks(ddata);
|
||||
@ -2985,6 +3001,9 @@ static int sysc_probe(struct platform_device *pdev)
|
||||
sysc_clkdm_allow_idle(ddata);
|
||||
}
|
||||
|
||||
if (!(ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT))
|
||||
reset_control_assert(ddata->rsts);
|
||||
|
||||
sysc_show_registers(ddata);
|
||||
|
||||
ddata->dev->type = &sysc_device_type;
|
||||
|
@ -19,6 +19,16 @@ config EXYNOS_AUDSS_CLK_CON
|
||||
on some Exynos SoC variants. Choose M or Y here if you want to
|
||||
use audio devices such as I2S, PCM, etc.
|
||||
|
||||
config EXYNOS_CLKOUT
|
||||
tristate "Samsung Exynos clock output driver"
|
||||
depends on COMMON_CLK_SAMSUNG
|
||||
default y if ARCH_EXYNOS
|
||||
help
|
||||
Support for the clock output (XCLKOUT) present on some of Exynos SoC
|
||||
variants. Usually the XCLKOUT is used to monitor the status of the
|
||||
certains clocks from SoC, but it could also be tied to other devices
|
||||
as an input clock.
|
||||
|
||||
# For S3C24XX platforms, select following symbols:
|
||||
config S3C2410_COMMON_CLK
|
||||
bool "Samsung S3C2410 clock controller support" if COMPILE_TEST
|
||||
|
@ -15,7 +15,7 @@ obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o
|
||||
obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5-subcmu.o
|
||||
obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos5433.o
|
||||
obj-$(CONFIG_EXYNOS_AUDSS_CLK_CON) += clk-exynos-audss.o
|
||||
obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-clkout.o
|
||||
obj-$(CONFIG_EXYNOS_CLKOUT) += clk-exynos-clkout.o
|
||||
obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos7.o
|
||||
obj-$(CONFIG_S3C2410_COMMON_CLK)+= clk-s3c2410.o
|
||||
obj-$(CONFIG_S3C2410_COMMON_DCLK)+= clk-s3c2410-dclk.o
|
||||
|
@ -9,10 +9,13 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
|
||||
#define EXYNOS_CLKOUT_NR_CLKS 1
|
||||
#define EXYNOS_CLKOUT_PARENTS 32
|
||||
@ -28,41 +31,103 @@ struct exynos_clkout {
|
||||
struct clk_mux mux;
|
||||
spinlock_t slock;
|
||||
void __iomem *reg;
|
||||
struct device_node *np;
|
||||
u32 pmu_debug_save;
|
||||
struct clk_hw_onecell_data data;
|
||||
};
|
||||
|
||||
static struct exynos_clkout *clkout;
|
||||
struct exynos_clkout_variant {
|
||||
u32 mux_mask;
|
||||
};
|
||||
|
||||
static int exynos_clkout_suspend(void)
|
||||
static const struct exynos_clkout_variant exynos_clkout_exynos4 = {
|
||||
.mux_mask = EXYNOS4_CLKOUT_MUX_MASK,
|
||||
};
|
||||
|
||||
static const struct exynos_clkout_variant exynos_clkout_exynos5 = {
|
||||
.mux_mask = EXYNOS5_CLKOUT_MUX_MASK,
|
||||
};
|
||||
|
||||
static const struct of_device_id exynos_clkout_ids[] = {
|
||||
{
|
||||
.compatible = "samsung,exynos3250-pmu",
|
||||
.data = &exynos_clkout_exynos4,
|
||||
}, {
|
||||
.compatible = "samsung,exynos4210-pmu",
|
||||
.data = &exynos_clkout_exynos4,
|
||||
}, {
|
||||
.compatible = "samsung,exynos4412-pmu",
|
||||
.data = &exynos_clkout_exynos4,
|
||||
}, {
|
||||
.compatible = "samsung,exynos5250-pmu",
|
||||
.data = &exynos_clkout_exynos5,
|
||||
}, {
|
||||
.compatible = "samsung,exynos5410-pmu",
|
||||
.data = &exynos_clkout_exynos5,
|
||||
}, {
|
||||
.compatible = "samsung,exynos5420-pmu",
|
||||
.data = &exynos_clkout_exynos5,
|
||||
}, {
|
||||
.compatible = "samsung,exynos5433-pmu",
|
||||
.data = &exynos_clkout_exynos5,
|
||||
}, { }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, exynos_clkout_ids);
|
||||
|
||||
/*
|
||||
* Device will be instantiated as child of PMU device without its own
|
||||
* device node. Therefore match compatibles against parent.
|
||||
*/
|
||||
static int exynos_clkout_match_parent_dev(struct device *dev, u32 *mux_mask)
|
||||
{
|
||||
clkout->pmu_debug_save = readl(clkout->reg + EXYNOS_PMU_DEBUG_REG);
|
||||
const struct exynos_clkout_variant *variant;
|
||||
const struct of_device_id *match;
|
||||
|
||||
if (!dev->parent) {
|
||||
dev_err(dev, "not instantiated from MFD\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
match = of_match_device(exynos_clkout_ids, dev->parent);
|
||||
if (!match) {
|
||||
dev_err(dev, "cannot match parent device\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
variant = match->data;
|
||||
|
||||
*mux_mask = variant->mux_mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exynos_clkout_resume(void)
|
||||
{
|
||||
writel(clkout->pmu_debug_save, clkout->reg + EXYNOS_PMU_DEBUG_REG);
|
||||
}
|
||||
|
||||
static struct syscore_ops exynos_clkout_syscore_ops = {
|
||||
.suspend = exynos_clkout_suspend,
|
||||
.resume = exynos_clkout_resume,
|
||||
};
|
||||
|
||||
static void __init exynos_clkout_init(struct device_node *node, u32 mux_mask)
|
||||
static int exynos_clkout_probe(struct platform_device *pdev)
|
||||
{
|
||||
const char *parent_names[EXYNOS_CLKOUT_PARENTS];
|
||||
struct clk *parents[EXYNOS_CLKOUT_PARENTS];
|
||||
int parent_count;
|
||||
int ret;
|
||||
int i;
|
||||
struct exynos_clkout *clkout;
|
||||
int parent_count, ret, i;
|
||||
u32 mux_mask;
|
||||
|
||||
clkout = kzalloc(struct_size(clkout, data.hws, EXYNOS_CLKOUT_NR_CLKS),
|
||||
GFP_KERNEL);
|
||||
clkout = devm_kzalloc(&pdev->dev,
|
||||
struct_size(clkout, data.hws, EXYNOS_CLKOUT_NR_CLKS),
|
||||
GFP_KERNEL);
|
||||
if (!clkout)
|
||||
return;
|
||||
return -ENOMEM;
|
||||
|
||||
ret = exynos_clkout_match_parent_dev(&pdev->dev, &mux_mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clkout->np = pdev->dev.of_node;
|
||||
if (!clkout->np) {
|
||||
/*
|
||||
* pdev->dev.parent was checked by exynos_clkout_match_parent_dev()
|
||||
* so it is not NULL.
|
||||
*/
|
||||
clkout->np = pdev->dev.parent->of_node;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, clkout);
|
||||
|
||||
spin_lock_init(&clkout->slock);
|
||||
|
||||
@ -71,7 +136,7 @@ static void __init exynos_clkout_init(struct device_node *node, u32 mux_mask)
|
||||
char name[] = "clkoutXX";
|
||||
|
||||
snprintf(name, sizeof(name), "clkout%d", i);
|
||||
parents[i] = of_clk_get_by_name(node, name);
|
||||
parents[i] = of_clk_get_by_name(clkout->np, name);
|
||||
if (IS_ERR(parents[i])) {
|
||||
parent_names[i] = "none";
|
||||
continue;
|
||||
@ -82,11 +147,13 @@ static void __init exynos_clkout_init(struct device_node *node, u32 mux_mask)
|
||||
}
|
||||
|
||||
if (!parent_count)
|
||||
goto free_clkout;
|
||||
return -EINVAL;
|
||||
|
||||
clkout->reg = of_iomap(node, 0);
|
||||
if (!clkout->reg)
|
||||
clkout->reg = of_iomap(clkout->np, 0);
|
||||
if (!clkout->reg) {
|
||||
ret = -ENODEV;
|
||||
goto clks_put;
|
||||
}
|
||||
|
||||
clkout->gate.reg = clkout->reg + EXYNOS_PMU_DEBUG_REG;
|
||||
clkout->gate.bit_idx = EXYNOS_CLKOUT_DISABLE_SHIFT;
|
||||
@ -103,17 +170,17 @@ static void __init exynos_clkout_init(struct device_node *node, u32 mux_mask)
|
||||
&clk_mux_ops, NULL, NULL, &clkout->gate.hw,
|
||||
&clk_gate_ops, CLK_SET_RATE_PARENT
|
||||
| CLK_SET_RATE_NO_REPARENT);
|
||||
if (IS_ERR(clkout->data.hws[0]))
|
||||
if (IS_ERR(clkout->data.hws[0])) {
|
||||
ret = PTR_ERR(clkout->data.hws[0]);
|
||||
goto err_unmap;
|
||||
}
|
||||
|
||||
clkout->data.num = EXYNOS_CLKOUT_NR_CLKS;
|
||||
ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, &clkout->data);
|
||||
ret = of_clk_add_hw_provider(clkout->np, of_clk_hw_onecell_get, &clkout->data);
|
||||
if (ret)
|
||||
goto err_clk_unreg;
|
||||
|
||||
register_syscore_ops(&exynos_clkout_syscore_ops);
|
||||
|
||||
return;
|
||||
return 0;
|
||||
|
||||
err_clk_unreg:
|
||||
clk_hw_unregister(clkout->data.hws[0]);
|
||||
@ -123,38 +190,56 @@ clks_put:
|
||||
for (i = 0; i < EXYNOS_CLKOUT_PARENTS; ++i)
|
||||
if (!IS_ERR(parents[i]))
|
||||
clk_put(parents[i]);
|
||||
free_clkout:
|
||||
kfree(clkout);
|
||||
|
||||
pr_err("%s: failed to register clkout clock\n", __func__);
|
||||
dev_err(&pdev->dev, "failed to register clkout clock\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* We use CLK_OF_DECLARE_DRIVER initialization method to avoid setting
|
||||
* the OF_POPULATED flag on the pmu device tree node, so later the
|
||||
* Exynos PMU platform device can be properly probed with PMU driver.
|
||||
*/
|
||||
|
||||
static void __init exynos4_clkout_init(struct device_node *node)
|
||||
static int exynos_clkout_remove(struct platform_device *pdev)
|
||||
{
|
||||
exynos_clkout_init(node, EXYNOS4_CLKOUT_MUX_MASK);
|
||||
}
|
||||
CLK_OF_DECLARE_DRIVER(exynos4210_clkout, "samsung,exynos4210-pmu",
|
||||
exynos4_clkout_init);
|
||||
CLK_OF_DECLARE_DRIVER(exynos4412_clkout, "samsung,exynos4412-pmu",
|
||||
exynos4_clkout_init);
|
||||
CLK_OF_DECLARE_DRIVER(exynos3250_clkout, "samsung,exynos3250-pmu",
|
||||
exynos4_clkout_init);
|
||||
struct exynos_clkout *clkout = platform_get_drvdata(pdev);
|
||||
|
||||
static void __init exynos5_clkout_init(struct device_node *node)
|
||||
{
|
||||
exynos_clkout_init(node, EXYNOS5_CLKOUT_MUX_MASK);
|
||||
of_clk_del_provider(clkout->np);
|
||||
clk_hw_unregister(clkout->data.hws[0]);
|
||||
iounmap(clkout->reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
CLK_OF_DECLARE_DRIVER(exynos5250_clkout, "samsung,exynos5250-pmu",
|
||||
exynos5_clkout_init);
|
||||
CLK_OF_DECLARE_DRIVER(exynos5410_clkout, "samsung,exynos5410-pmu",
|
||||
exynos5_clkout_init);
|
||||
CLK_OF_DECLARE_DRIVER(exynos5420_clkout, "samsung,exynos5420-pmu",
|
||||
exynos5_clkout_init);
|
||||
CLK_OF_DECLARE_DRIVER(exynos5433_clkout, "samsung,exynos5433-pmu",
|
||||
exynos5_clkout_init);
|
||||
|
||||
static int __maybe_unused exynos_clkout_suspend(struct device *dev)
|
||||
{
|
||||
struct exynos_clkout *clkout = dev_get_drvdata(dev);
|
||||
|
||||
clkout->pmu_debug_save = readl(clkout->reg + EXYNOS_PMU_DEBUG_REG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused exynos_clkout_resume(struct device *dev)
|
||||
{
|
||||
struct exynos_clkout *clkout = dev_get_drvdata(dev);
|
||||
|
||||
writel(clkout->pmu_debug_save, clkout->reg + EXYNOS_PMU_DEBUG_REG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(exynos_clkout_pm_ops, exynos_clkout_suspend,
|
||||
exynos_clkout_resume);
|
||||
|
||||
static struct platform_driver exynos_clkout_driver = {
|
||||
.driver = {
|
||||
.name = "exynos-clkout",
|
||||
.of_match_table = exynos_clkout_ids,
|
||||
.pm = &exynos_clkout_pm_ops,
|
||||
},
|
||||
.probe = exynos_clkout_probe,
|
||||
.remove = exynos_clkout_remove,
|
||||
};
|
||||
module_platform_driver(exynos_clkout_driver);
|
||||
|
||||
MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>");
|
||||
MODULE_AUTHOR("Tomasz Figa <tomasz.figa@gmail.com>");
|
||||
MODULE_DESCRIPTION("Samsung Exynos clock output driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -266,6 +266,8 @@ static const char *enable_init_clks[] = {
|
||||
"dpll_ddr_m2_ck",
|
||||
"dpll_mpu_m2_ck",
|
||||
"l3_gclk",
|
||||
/* AM3_L3_L3_MAIN_CLKCTRL, needed during suspend */
|
||||
"l3-clkctrl:00bc:0",
|
||||
"l4hs_gclk",
|
||||
"l4fw_gclk",
|
||||
"l4ls_gclk",
|
||||
|
@ -155,8 +155,7 @@ static int __init bl_idle_driver_init(struct cpuidle_driver *drv, int part_id)
|
||||
|
||||
static const struct of_device_id compatible_machine_match[] = {
|
||||
{ .compatible = "arm,vexpress,v2p-ca15_a7" },
|
||||
{ .compatible = "samsung,exynos5420" },
|
||||
{ .compatible = "samsung,exynos5800" },
|
||||
{ .compatible = "google,peach" },
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -1474,17 +1474,17 @@ int scmi_notification_init(struct scmi_handle *handle)
|
||||
ni->gid = gid;
|
||||
ni->handle = handle;
|
||||
|
||||
ni->registered_protocols = devm_kcalloc(handle->dev, SCMI_MAX_PROTO,
|
||||
sizeof(char *), GFP_KERNEL);
|
||||
if (!ni->registered_protocols)
|
||||
goto err;
|
||||
|
||||
ni->notify_wq = alloc_workqueue(dev_name(handle->dev),
|
||||
WQ_UNBOUND | WQ_FREEZABLE | WQ_SYSFS,
|
||||
0);
|
||||
if (!ni->notify_wq)
|
||||
goto err;
|
||||
|
||||
ni->registered_protocols = devm_kcalloc(handle->dev, SCMI_MAX_PROTO,
|
||||
sizeof(char *), GFP_KERNEL);
|
||||
if (!ni->registered_protocols)
|
||||
goto err;
|
||||
|
||||
mutex_init(&ni->pending_mtx);
|
||||
hash_init(ni->pending_events_handlers);
|
||||
|
||||
|
@ -2,21 +2,30 @@
|
||||
/*
|
||||
* System Control and Management Interface (SCMI) Sensor Protocol
|
||||
*
|
||||
* Copyright (C) 2018 ARM Ltd.
|
||||
* Copyright (C) 2018-2020 ARM Ltd.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "SCMI Notifications SENSOR - " fmt
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/scmi_protocol.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "notify.h"
|
||||
|
||||
#define SCMI_MAX_NUM_SENSOR_AXIS 63
|
||||
#define SCMIv2_SENSOR_PROTOCOL 0x10000
|
||||
|
||||
enum scmi_sensor_protocol_cmd {
|
||||
SENSOR_DESCRIPTION_GET = 0x3,
|
||||
SENSOR_TRIP_POINT_NOTIFY = 0x4,
|
||||
SENSOR_TRIP_POINT_CONFIG = 0x5,
|
||||
SENSOR_READING_GET = 0x6,
|
||||
SENSOR_AXIS_DESCRIPTION_GET = 0x7,
|
||||
SENSOR_LIST_UPDATE_INTERVALS = 0x8,
|
||||
SENSOR_CONFIG_GET = 0x9,
|
||||
SENSOR_CONFIG_SET = 0xA,
|
||||
SENSOR_CONTINUOUS_UPDATE_NOTIFY = 0xB,
|
||||
};
|
||||
|
||||
struct scmi_msg_resp_sensor_attributes {
|
||||
@ -28,29 +37,106 @@ struct scmi_msg_resp_sensor_attributes {
|
||||
__le32 reg_size;
|
||||
};
|
||||
|
||||
/* v3 attributes_low macros */
|
||||
#define SUPPORTS_UPDATE_NOTIFY(x) FIELD_GET(BIT(30), (x))
|
||||
#define SENSOR_TSTAMP_EXP(x) FIELD_GET(GENMASK(14, 10), (x))
|
||||
#define SUPPORTS_TIMESTAMP(x) FIELD_GET(BIT(9), (x))
|
||||
#define SUPPORTS_EXTEND_ATTRS(x) FIELD_GET(BIT(8), (x))
|
||||
|
||||
/* v2 attributes_high macros */
|
||||
#define SENSOR_UPDATE_BASE(x) FIELD_GET(GENMASK(31, 27), (x))
|
||||
#define SENSOR_UPDATE_SCALE(x) FIELD_GET(GENMASK(26, 22), (x))
|
||||
|
||||
/* v3 attributes_high macros */
|
||||
#define SENSOR_AXIS_NUMBER(x) FIELD_GET(GENMASK(21, 16), (x))
|
||||
#define SUPPORTS_AXIS(x) FIELD_GET(BIT(8), (x))
|
||||
|
||||
/* v3 resolution macros */
|
||||
#define SENSOR_RES(x) FIELD_GET(GENMASK(26, 0), (x))
|
||||
#define SENSOR_RES_EXP(x) FIELD_GET(GENMASK(31, 27), (x))
|
||||
|
||||
struct scmi_msg_resp_attrs {
|
||||
__le32 min_range_low;
|
||||
__le32 min_range_high;
|
||||
__le32 max_range_low;
|
||||
__le32 max_range_high;
|
||||
};
|
||||
|
||||
struct scmi_msg_resp_sensor_description {
|
||||
__le16 num_returned;
|
||||
__le16 num_remaining;
|
||||
struct {
|
||||
struct scmi_sensor_descriptor {
|
||||
__le32 id;
|
||||
__le32 attributes_low;
|
||||
#define SUPPORTS_ASYNC_READ(x) ((x) & BIT(31))
|
||||
#define NUM_TRIP_POINTS(x) ((x) & 0xff)
|
||||
/* Common attributes_low macros */
|
||||
#define SUPPORTS_ASYNC_READ(x) FIELD_GET(BIT(31), (x))
|
||||
#define NUM_TRIP_POINTS(x) FIELD_GET(GENMASK(7, 0), (x))
|
||||
__le32 attributes_high;
|
||||
#define SENSOR_TYPE(x) ((x) & 0xff)
|
||||
#define SENSOR_SCALE(x) (((x) >> 11) & 0x1f)
|
||||
#define SENSOR_SCALE_SIGN BIT(4)
|
||||
#define SENSOR_SCALE_EXTEND GENMASK(7, 5)
|
||||
#define SENSOR_UPDATE_SCALE(x) (((x) >> 22) & 0x1f)
|
||||
#define SENSOR_UPDATE_BASE(x) (((x) >> 27) & 0x1f)
|
||||
u8 name[SCMI_MAX_STR_SIZE];
|
||||
} desc[0];
|
||||
/* Common attributes_high macros */
|
||||
#define SENSOR_SCALE(x) FIELD_GET(GENMASK(15, 11), (x))
|
||||
#define SENSOR_SCALE_SIGN BIT(4)
|
||||
#define SENSOR_SCALE_EXTEND GENMASK(31, 5)
|
||||
#define SENSOR_TYPE(x) FIELD_GET(GENMASK(7, 0), (x))
|
||||
u8 name[SCMI_MAX_STR_SIZE];
|
||||
/* only for version > 2.0 */
|
||||
__le32 power;
|
||||
__le32 resolution;
|
||||
struct scmi_msg_resp_attrs scalar_attrs;
|
||||
} desc[];
|
||||
};
|
||||
|
||||
struct scmi_msg_sensor_trip_point_notify {
|
||||
/* Base scmi_sensor_descriptor size excluding extended attrs after name */
|
||||
#define SCMI_MSG_RESP_SENS_DESCR_BASE_SZ 28
|
||||
|
||||
/* Sign extend to a full s32 */
|
||||
#define S32_EXT(v) \
|
||||
({ \
|
||||
int __v = (v); \
|
||||
\
|
||||
if (__v & SENSOR_SCALE_SIGN) \
|
||||
__v |= SENSOR_SCALE_EXTEND; \
|
||||
__v; \
|
||||
})
|
||||
|
||||
struct scmi_msg_sensor_axis_description_get {
|
||||
__le32 id;
|
||||
__le32 axis_desc_index;
|
||||
};
|
||||
|
||||
struct scmi_msg_resp_sensor_axis_description {
|
||||
__le32 num_axis_flags;
|
||||
#define NUM_AXIS_RETURNED(x) FIELD_GET(GENMASK(5, 0), (x))
|
||||
#define NUM_AXIS_REMAINING(x) FIELD_GET(GENMASK(31, 26), (x))
|
||||
struct scmi_axis_descriptor {
|
||||
__le32 id;
|
||||
__le32 attributes_low;
|
||||
__le32 attributes_high;
|
||||
u8 name[SCMI_MAX_STR_SIZE];
|
||||
__le32 resolution;
|
||||
struct scmi_msg_resp_attrs attrs;
|
||||
} desc[];
|
||||
};
|
||||
|
||||
/* Base scmi_axis_descriptor size excluding extended attrs after name */
|
||||
#define SCMI_MSG_RESP_AXIS_DESCR_BASE_SZ 28
|
||||
|
||||
struct scmi_msg_sensor_list_update_intervals {
|
||||
__le32 id;
|
||||
__le32 index;
|
||||
};
|
||||
|
||||
struct scmi_msg_resp_sensor_list_update_intervals {
|
||||
__le32 num_intervals_flags;
|
||||
#define NUM_INTERVALS_RETURNED(x) FIELD_GET(GENMASK(11, 0), (x))
|
||||
#define SEGMENTED_INTVL_FORMAT(x) FIELD_GET(BIT(12), (x))
|
||||
#define NUM_INTERVALS_REMAINING(x) FIELD_GET(GENMASK(31, 16), (x))
|
||||
__le32 intervals[];
|
||||
};
|
||||
|
||||
struct scmi_msg_sensor_request_notify {
|
||||
__le32 id;
|
||||
__le32 event_control;
|
||||
#define SENSOR_TP_NOTIFY_ALL BIT(0)
|
||||
#define SENSOR_NOTIFY_ALL BIT(0)
|
||||
};
|
||||
|
||||
struct scmi_msg_set_sensor_trip_point {
|
||||
@ -66,18 +152,46 @@ struct scmi_msg_set_sensor_trip_point {
|
||||
__le32 value_high;
|
||||
};
|
||||
|
||||
struct scmi_msg_sensor_config_set {
|
||||
__le32 id;
|
||||
__le32 sensor_config;
|
||||
};
|
||||
|
||||
struct scmi_msg_sensor_reading_get {
|
||||
__le32 id;
|
||||
__le32 flags;
|
||||
#define SENSOR_READ_ASYNC BIT(0)
|
||||
};
|
||||
|
||||
struct scmi_resp_sensor_reading_complete {
|
||||
__le32 id;
|
||||
__le64 readings;
|
||||
};
|
||||
|
||||
struct scmi_sensor_reading_resp {
|
||||
__le32 sensor_value_low;
|
||||
__le32 sensor_value_high;
|
||||
__le32 timestamp_low;
|
||||
__le32 timestamp_high;
|
||||
};
|
||||
|
||||
struct scmi_resp_sensor_reading_complete_v3 {
|
||||
__le32 id;
|
||||
struct scmi_sensor_reading_resp readings[];
|
||||
};
|
||||
|
||||
struct scmi_sensor_trip_notify_payld {
|
||||
__le32 agent_id;
|
||||
__le32 sensor_id;
|
||||
__le32 trip_point_desc;
|
||||
};
|
||||
|
||||
struct scmi_sensor_update_notify_payld {
|
||||
__le32 agent_id;
|
||||
__le32 sensor_id;
|
||||
struct scmi_sensor_reading_resp readings[];
|
||||
};
|
||||
|
||||
struct sensors_info {
|
||||
u32 version;
|
||||
int num_sensors;
|
||||
@ -114,6 +228,194 @@ static int scmi_sensor_attributes_get(const struct scmi_handle *handle,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void scmi_parse_range_attrs(struct scmi_range_attrs *out,
|
||||
struct scmi_msg_resp_attrs *in)
|
||||
{
|
||||
out->min_range = get_unaligned_le64((void *)&in->min_range_low);
|
||||
out->max_range = get_unaligned_le64((void *)&in->max_range_low);
|
||||
}
|
||||
|
||||
static int scmi_sensor_update_intervals(const struct scmi_handle *handle,
|
||||
struct scmi_sensor_info *s)
|
||||
{
|
||||
int ret, cnt;
|
||||
u32 desc_index = 0;
|
||||
u16 num_returned, num_remaining;
|
||||
struct scmi_xfer *ti;
|
||||
struct scmi_msg_resp_sensor_list_update_intervals *buf;
|
||||
struct scmi_msg_sensor_list_update_intervals *msg;
|
||||
|
||||
ret = scmi_xfer_get_init(handle, SENSOR_LIST_UPDATE_INTERVALS,
|
||||
SCMI_PROTOCOL_SENSOR, sizeof(*msg), 0, &ti);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
buf = ti->rx.buf;
|
||||
do {
|
||||
u32 flags;
|
||||
|
||||
msg = ti->tx.buf;
|
||||
/* Set the number of sensors to be skipped/already read */
|
||||
msg->id = cpu_to_le32(s->id);
|
||||
msg->index = cpu_to_le32(desc_index);
|
||||
|
||||
ret = scmi_do_xfer(handle, ti);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
flags = le32_to_cpu(buf->num_intervals_flags);
|
||||
num_returned = NUM_INTERVALS_RETURNED(flags);
|
||||
num_remaining = NUM_INTERVALS_REMAINING(flags);
|
||||
|
||||
/*
|
||||
* Max intervals is not declared previously anywhere so we
|
||||
* assume it's returned+remaining.
|
||||
*/
|
||||
if (!s->intervals.count) {
|
||||
s->intervals.segmented = SEGMENTED_INTVL_FORMAT(flags);
|
||||
s->intervals.count = num_returned + num_remaining;
|
||||
/* segmented intervals are reported in one triplet */
|
||||
if (s->intervals.segmented &&
|
||||
(num_remaining || num_returned != 3)) {
|
||||
dev_err(handle->dev,
|
||||
"Sensor ID:%d advertises an invalid segmented interval (%d)\n",
|
||||
s->id, s->intervals.count);
|
||||
s->intervals.segmented = false;
|
||||
s->intervals.count = 0;
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
/* Direct allocation when exceeding pre-allocated */
|
||||
if (s->intervals.count >= SCMI_MAX_PREALLOC_POOL) {
|
||||
s->intervals.desc =
|
||||
devm_kcalloc(handle->dev,
|
||||
s->intervals.count,
|
||||
sizeof(*s->intervals.desc),
|
||||
GFP_KERNEL);
|
||||
if (!s->intervals.desc) {
|
||||
s->intervals.segmented = false;
|
||||
s->intervals.count = 0;
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (desc_index + num_returned > s->intervals.count) {
|
||||
dev_err(handle->dev,
|
||||
"No. of update intervals can't exceed %d\n",
|
||||
s->intervals.count);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
for (cnt = 0; cnt < num_returned; cnt++)
|
||||
s->intervals.desc[desc_index + cnt] =
|
||||
le32_to_cpu(buf->intervals[cnt]);
|
||||
|
||||
desc_index += num_returned;
|
||||
|
||||
scmi_reset_rx_to_maxsz(handle, ti);
|
||||
/*
|
||||
* check for both returned and remaining to avoid infinite
|
||||
* loop due to buggy firmware
|
||||
*/
|
||||
} while (num_returned && num_remaining);
|
||||
|
||||
scmi_xfer_put(handle, ti);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int scmi_sensor_axis_description(const struct scmi_handle *handle,
|
||||
struct scmi_sensor_info *s)
|
||||
{
|
||||
int ret, cnt;
|
||||
u32 desc_index = 0;
|
||||
u16 num_returned, num_remaining;
|
||||
struct scmi_xfer *te;
|
||||
struct scmi_msg_resp_sensor_axis_description *buf;
|
||||
struct scmi_msg_sensor_axis_description_get *msg;
|
||||
|
||||
s->axis = devm_kcalloc(handle->dev, s->num_axis,
|
||||
sizeof(*s->axis), GFP_KERNEL);
|
||||
if (!s->axis)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = scmi_xfer_get_init(handle, SENSOR_AXIS_DESCRIPTION_GET,
|
||||
SCMI_PROTOCOL_SENSOR, sizeof(*msg), 0, &te);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
buf = te->rx.buf;
|
||||
do {
|
||||
u32 flags;
|
||||
struct scmi_axis_descriptor *adesc;
|
||||
|
||||
msg = te->tx.buf;
|
||||
/* Set the number of sensors to be skipped/already read */
|
||||
msg->id = cpu_to_le32(s->id);
|
||||
msg->axis_desc_index = cpu_to_le32(desc_index);
|
||||
|
||||
ret = scmi_do_xfer(handle, te);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
flags = le32_to_cpu(buf->num_axis_flags);
|
||||
num_returned = NUM_AXIS_RETURNED(flags);
|
||||
num_remaining = NUM_AXIS_REMAINING(flags);
|
||||
|
||||
if (desc_index + num_returned > s->num_axis) {
|
||||
dev_err(handle->dev, "No. of axis can't exceed %d\n",
|
||||
s->num_axis);
|
||||
break;
|
||||
}
|
||||
|
||||
adesc = &buf->desc[0];
|
||||
for (cnt = 0; cnt < num_returned; cnt++) {
|
||||
u32 attrh, attrl;
|
||||
struct scmi_sensor_axis_info *a;
|
||||
size_t dsize = SCMI_MSG_RESP_AXIS_DESCR_BASE_SZ;
|
||||
|
||||
attrl = le32_to_cpu(adesc->attributes_low);
|
||||
|
||||
a = &s->axis[desc_index + cnt];
|
||||
|
||||
a->id = le32_to_cpu(adesc->id);
|
||||
a->extended_attrs = SUPPORTS_EXTEND_ATTRS(attrl);
|
||||
|
||||
attrh = le32_to_cpu(adesc->attributes_high);
|
||||
a->scale = S32_EXT(SENSOR_SCALE(attrh));
|
||||
a->type = SENSOR_TYPE(attrh);
|
||||
strlcpy(a->name, adesc->name, SCMI_MAX_STR_SIZE);
|
||||
|
||||
if (a->extended_attrs) {
|
||||
unsigned int ares =
|
||||
le32_to_cpu(adesc->resolution);
|
||||
|
||||
a->resolution = SENSOR_RES(ares);
|
||||
a->exponent =
|
||||
S32_EXT(SENSOR_RES_EXP(ares));
|
||||
dsize += sizeof(adesc->resolution);
|
||||
|
||||
scmi_parse_range_attrs(&a->attrs,
|
||||
&adesc->attrs);
|
||||
dsize += sizeof(adesc->attrs);
|
||||
}
|
||||
|
||||
adesc = (typeof(adesc))((u8 *)adesc + dsize);
|
||||
}
|
||||
|
||||
desc_index += num_returned;
|
||||
|
||||
scmi_reset_rx_to_maxsz(handle, te);
|
||||
/*
|
||||
* check for both returned and remaining to avoid infinite
|
||||
* loop due to buggy firmware
|
||||
*/
|
||||
} while (num_returned && num_remaining);
|
||||
|
||||
scmi_xfer_put(handle, te);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int scmi_sensor_description_get(const struct scmi_handle *handle,
|
||||
struct sensors_info *si)
|
||||
{
|
||||
@ -131,9 +433,10 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle,
|
||||
buf = t->rx.buf;
|
||||
|
||||
do {
|
||||
struct scmi_sensor_descriptor *sdesc;
|
||||
|
||||
/* Set the number of sensors to be skipped/already read */
|
||||
put_unaligned_le32(desc_index, t->tx.buf);
|
||||
|
||||
ret = scmi_do_xfer(handle, t);
|
||||
if (ret)
|
||||
break;
|
||||
@ -147,22 +450,97 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle,
|
||||
break;
|
||||
}
|
||||
|
||||
sdesc = &buf->desc[0];
|
||||
for (cnt = 0; cnt < num_returned; cnt++) {
|
||||
u32 attrh, attrl;
|
||||
struct scmi_sensor_info *s;
|
||||
size_t dsize = SCMI_MSG_RESP_SENS_DESCR_BASE_SZ;
|
||||
|
||||
attrl = le32_to_cpu(buf->desc[cnt].attributes_low);
|
||||
attrh = le32_to_cpu(buf->desc[cnt].attributes_high);
|
||||
s = &si->sensors[desc_index + cnt];
|
||||
s->id = le32_to_cpu(buf->desc[cnt].id);
|
||||
s->type = SENSOR_TYPE(attrh);
|
||||
s->scale = SENSOR_SCALE(attrh);
|
||||
/* Sign extend to a full s8 */
|
||||
if (s->scale & SENSOR_SCALE_SIGN)
|
||||
s->scale |= SENSOR_SCALE_EXTEND;
|
||||
s->id = le32_to_cpu(sdesc->id);
|
||||
|
||||
attrl = le32_to_cpu(sdesc->attributes_low);
|
||||
/* common bitfields parsing */
|
||||
s->async = SUPPORTS_ASYNC_READ(attrl);
|
||||
s->num_trip_points = NUM_TRIP_POINTS(attrl);
|
||||
strlcpy(s->name, buf->desc[cnt].name, SCMI_MAX_STR_SIZE);
|
||||
/**
|
||||
* only SCMIv3.0 specific bitfield below.
|
||||
* Such bitfields are assumed to be zeroed on non
|
||||
* relevant fw versions...assuming fw not buggy !
|
||||
*/
|
||||
s->update = SUPPORTS_UPDATE_NOTIFY(attrl);
|
||||
s->timestamped = SUPPORTS_TIMESTAMP(attrl);
|
||||
if (s->timestamped)
|
||||
s->tstamp_scale =
|
||||
S32_EXT(SENSOR_TSTAMP_EXP(attrl));
|
||||
s->extended_scalar_attrs =
|
||||
SUPPORTS_EXTEND_ATTRS(attrl);
|
||||
|
||||
attrh = le32_to_cpu(sdesc->attributes_high);
|
||||
/* common bitfields parsing */
|
||||
s->scale = S32_EXT(SENSOR_SCALE(attrh));
|
||||
s->type = SENSOR_TYPE(attrh);
|
||||
/* Use pre-allocated pool wherever possible */
|
||||
s->intervals.desc = s->intervals.prealloc_pool;
|
||||
if (si->version == SCMIv2_SENSOR_PROTOCOL) {
|
||||
s->intervals.segmented = false;
|
||||
s->intervals.count = 1;
|
||||
/*
|
||||
* Convert SCMIv2.0 update interval format to
|
||||
* SCMIv3.0 to be used as the common exposed
|
||||
* descriptor, accessible via common macros.
|
||||
*/
|
||||
s->intervals.desc[0] =
|
||||
(SENSOR_UPDATE_BASE(attrh) << 5) |
|
||||
SENSOR_UPDATE_SCALE(attrh);
|
||||
} else {
|
||||
/*
|
||||
* From SCMIv3.0 update intervals are retrieved
|
||||
* via a dedicated (optional) command.
|
||||
* Since the command is optional, on error carry
|
||||
* on without any update interval.
|
||||
*/
|
||||
if (scmi_sensor_update_intervals(handle, s))
|
||||
dev_dbg(handle->dev,
|
||||
"Update Intervals not available for sensor ID:%d\n",
|
||||
s->id);
|
||||
}
|
||||
/**
|
||||
* only > SCMIv2.0 specific bitfield below.
|
||||
* Such bitfields are assumed to be zeroed on non
|
||||
* relevant fw versions...assuming fw not buggy !
|
||||
*/
|
||||
s->num_axis = min_t(unsigned int,
|
||||
SUPPORTS_AXIS(attrh) ?
|
||||
SENSOR_AXIS_NUMBER(attrh) : 0,
|
||||
SCMI_MAX_NUM_SENSOR_AXIS);
|
||||
strlcpy(s->name, sdesc->name, SCMI_MAX_STR_SIZE);
|
||||
|
||||
if (s->extended_scalar_attrs) {
|
||||
s->sensor_power = le32_to_cpu(sdesc->power);
|
||||
dsize += sizeof(sdesc->power);
|
||||
/* Only for sensors reporting scalar values */
|
||||
if (s->num_axis == 0) {
|
||||
unsigned int sres =
|
||||
le32_to_cpu(sdesc->resolution);
|
||||
|
||||
s->resolution = SENSOR_RES(sres);
|
||||
s->exponent =
|
||||
S32_EXT(SENSOR_RES_EXP(sres));
|
||||
dsize += sizeof(sdesc->resolution);
|
||||
|
||||
scmi_parse_range_attrs(&s->scalar_attrs,
|
||||
&sdesc->scalar_attrs);
|
||||
dsize += sizeof(sdesc->scalar_attrs);
|
||||
}
|
||||
}
|
||||
if (s->num_axis > 0) {
|
||||
ret = scmi_sensor_axis_description(handle, s);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
sdesc = (typeof(sdesc))((u8 *)sdesc + dsize);
|
||||
}
|
||||
|
||||
desc_index += num_returned;
|
||||
@ -174,19 +552,21 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle,
|
||||
*/
|
||||
} while (num_returned && num_remaining);
|
||||
|
||||
out:
|
||||
scmi_xfer_put(handle, t);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int scmi_sensor_trip_point_notify(const struct scmi_handle *handle,
|
||||
u32 sensor_id, bool enable)
|
||||
static inline int
|
||||
scmi_sensor_request_notify(const struct scmi_handle *handle, u32 sensor_id,
|
||||
u8 message_id, bool enable)
|
||||
{
|
||||
int ret;
|
||||
u32 evt_cntl = enable ? SENSOR_TP_NOTIFY_ALL : 0;
|
||||
u32 evt_cntl = enable ? SENSOR_NOTIFY_ALL : 0;
|
||||
struct scmi_xfer *t;
|
||||
struct scmi_msg_sensor_trip_point_notify *cfg;
|
||||
struct scmi_msg_sensor_request_notify *cfg;
|
||||
|
||||
ret = scmi_xfer_get_init(handle, SENSOR_TRIP_POINT_NOTIFY,
|
||||
ret = scmi_xfer_get_init(handle, message_id,
|
||||
SCMI_PROTOCOL_SENSOR, sizeof(*cfg), 0, &t);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -201,6 +581,23 @@ static int scmi_sensor_trip_point_notify(const struct scmi_handle *handle,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int scmi_sensor_trip_point_notify(const struct scmi_handle *handle,
|
||||
u32 sensor_id, bool enable)
|
||||
{
|
||||
return scmi_sensor_request_notify(handle, sensor_id,
|
||||
SENSOR_TRIP_POINT_NOTIFY,
|
||||
enable);
|
||||
}
|
||||
|
||||
static int
|
||||
scmi_sensor_continuous_update_notify(const struct scmi_handle *handle,
|
||||
u32 sensor_id, bool enable)
|
||||
{
|
||||
return scmi_sensor_request_notify(handle, sensor_id,
|
||||
SENSOR_CONTINUOUS_UPDATE_NOTIFY,
|
||||
enable);
|
||||
}
|
||||
|
||||
static int
|
||||
scmi_sensor_trip_point_config(const struct scmi_handle *handle, u32 sensor_id,
|
||||
u8 trip_id, u64 trip_value)
|
||||
@ -227,6 +624,75 @@ scmi_sensor_trip_point_config(const struct scmi_handle *handle, u32 sensor_id,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int scmi_sensor_config_get(const struct scmi_handle *handle,
|
||||
u32 sensor_id, u32 *sensor_config)
|
||||
{
|
||||
int ret;
|
||||
struct scmi_xfer *t;
|
||||
|
||||
ret = scmi_xfer_get_init(handle, SENSOR_CONFIG_GET,
|
||||
SCMI_PROTOCOL_SENSOR, sizeof(__le32),
|
||||
sizeof(__le32), &t);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
put_unaligned_le32(cpu_to_le32(sensor_id), t->tx.buf);
|
||||
ret = scmi_do_xfer(handle, t);
|
||||
if (!ret) {
|
||||
struct sensors_info *si = handle->sensor_priv;
|
||||
struct scmi_sensor_info *s = si->sensors + sensor_id;
|
||||
|
||||
*sensor_config = get_unaligned_le64(t->rx.buf);
|
||||
s->sensor_config = *sensor_config;
|
||||
}
|
||||
|
||||
scmi_xfer_put(handle, t);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int scmi_sensor_config_set(const struct scmi_handle *handle,
|
||||
u32 sensor_id, u32 sensor_config)
|
||||
{
|
||||
int ret;
|
||||
struct scmi_xfer *t;
|
||||
struct scmi_msg_sensor_config_set *msg;
|
||||
|
||||
ret = scmi_xfer_get_init(handle, SENSOR_CONFIG_SET,
|
||||
SCMI_PROTOCOL_SENSOR, sizeof(*msg), 0, &t);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
msg = t->tx.buf;
|
||||
msg->id = cpu_to_le32(sensor_id);
|
||||
msg->sensor_config = cpu_to_le32(sensor_config);
|
||||
|
||||
ret = scmi_do_xfer(handle, t);
|
||||
if (!ret) {
|
||||
struct sensors_info *si = handle->sensor_priv;
|
||||
struct scmi_sensor_info *s = si->sensors + sensor_id;
|
||||
|
||||
s->sensor_config = sensor_config;
|
||||
}
|
||||
|
||||
scmi_xfer_put(handle, t);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* scmi_sensor_reading_get - Read scalar sensor value
|
||||
* @handle: Platform handle
|
||||
* @sensor_id: Sensor ID
|
||||
* @value: The 64bit value sensor reading
|
||||
*
|
||||
* This function returns a single 64 bit reading value representing the sensor
|
||||
* value; if the platform SCMI Protocol implementation and the sensor support
|
||||
* multiple axis and timestamped-reads, this just returns the first axis while
|
||||
* dropping the timestamp value.
|
||||
* Use instead the @scmi_sensor_reading_get_timestamped to retrieve the array of
|
||||
* timestamped multi-axis values.
|
||||
*
|
||||
* Return: 0 on Success
|
||||
*/
|
||||
static int scmi_sensor_reading_get(const struct scmi_handle *handle,
|
||||
u32 sensor_id, u64 *value)
|
||||
{
|
||||
@ -237,20 +703,24 @@ static int scmi_sensor_reading_get(const struct scmi_handle *handle,
|
||||
struct scmi_sensor_info *s = si->sensors + sensor_id;
|
||||
|
||||
ret = scmi_xfer_get_init(handle, SENSOR_READING_GET,
|
||||
SCMI_PROTOCOL_SENSOR, sizeof(*sensor),
|
||||
sizeof(u64), &t);
|
||||
SCMI_PROTOCOL_SENSOR, sizeof(*sensor), 0, &t);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sensor = t->tx.buf;
|
||||
sensor->id = cpu_to_le32(sensor_id);
|
||||
|
||||
if (s->async) {
|
||||
sensor->flags = cpu_to_le32(SENSOR_READ_ASYNC);
|
||||
ret = scmi_do_xfer_with_response(handle, t);
|
||||
if (!ret)
|
||||
*value = get_unaligned_le64((void *)
|
||||
((__le32 *)t->rx.buf + 1));
|
||||
if (!ret) {
|
||||
struct scmi_resp_sensor_reading_complete *resp;
|
||||
|
||||
resp = t->rx.buf;
|
||||
if (le32_to_cpu(resp->id) == sensor_id)
|
||||
*value = get_unaligned_le64(&resp->readings);
|
||||
else
|
||||
ret = -EPROTO;
|
||||
}
|
||||
} else {
|
||||
sensor->flags = cpu_to_le32(0);
|
||||
ret = scmi_do_xfer(handle, t);
|
||||
@ -262,6 +732,84 @@ static int scmi_sensor_reading_get(const struct scmi_handle *handle,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void
|
||||
scmi_parse_sensor_readings(struct scmi_sensor_reading *out,
|
||||
const struct scmi_sensor_reading_resp *in)
|
||||
{
|
||||
out->value = get_unaligned_le64((void *)&in->sensor_value_low);
|
||||
out->timestamp = get_unaligned_le64((void *)&in->timestamp_low);
|
||||
}
|
||||
|
||||
/**
|
||||
* scmi_sensor_reading_get_timestamped - Read multiple-axis timestamped values
|
||||
* @handle: Platform handle
|
||||
* @sensor_id: Sensor ID
|
||||
* @count: The length of the provided @readings array
|
||||
* @readings: An array of elements each representing a timestamped per-axis
|
||||
* reading of type @struct scmi_sensor_reading.
|
||||
* Returned readings are ordered as the @axis descriptors array
|
||||
* included in @struct scmi_sensor_info and the max number of
|
||||
* returned elements is min(@count, @num_axis); ideally the provided
|
||||
* array should be of length @count equal to @num_axis.
|
||||
*
|
||||
* Return: 0 on Success
|
||||
*/
|
||||
static int
|
||||
scmi_sensor_reading_get_timestamped(const struct scmi_handle *handle,
|
||||
u32 sensor_id, u8 count,
|
||||
struct scmi_sensor_reading *readings)
|
||||
{
|
||||
int ret;
|
||||
struct scmi_xfer *t;
|
||||
struct scmi_msg_sensor_reading_get *sensor;
|
||||
struct sensors_info *si = handle->sensor_priv;
|
||||
struct scmi_sensor_info *s = si->sensors + sensor_id;
|
||||
|
||||
if (!count || !readings ||
|
||||
(!s->num_axis && count > 1) || (s->num_axis && count > s->num_axis))
|
||||
return -EINVAL;
|
||||
|
||||
ret = scmi_xfer_get_init(handle, SENSOR_READING_GET,
|
||||
SCMI_PROTOCOL_SENSOR, sizeof(*sensor), 0, &t);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sensor = t->tx.buf;
|
||||
sensor->id = cpu_to_le32(sensor_id);
|
||||
if (s->async) {
|
||||
sensor->flags = cpu_to_le32(SENSOR_READ_ASYNC);
|
||||
ret = scmi_do_xfer_with_response(handle, t);
|
||||
if (!ret) {
|
||||
int i;
|
||||
struct scmi_resp_sensor_reading_complete_v3 *resp;
|
||||
|
||||
resp = t->rx.buf;
|
||||
/* Retrieve only the number of requested axis anyway */
|
||||
if (le32_to_cpu(resp->id) == sensor_id)
|
||||
for (i = 0; i < count; i++)
|
||||
scmi_parse_sensor_readings(&readings[i],
|
||||
&resp->readings[i]);
|
||||
else
|
||||
ret = -EPROTO;
|
||||
}
|
||||
} else {
|
||||
sensor->flags = cpu_to_le32(0);
|
||||
ret = scmi_do_xfer(handle, t);
|
||||
if (!ret) {
|
||||
int i;
|
||||
struct scmi_sensor_reading_resp *resp_readings;
|
||||
|
||||
resp_readings = t->rx.buf;
|
||||
for (i = 0; i < count; i++)
|
||||
scmi_parse_sensor_readings(&readings[i],
|
||||
&resp_readings[i]);
|
||||
}
|
||||
}
|
||||
|
||||
scmi_xfer_put(handle, t);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct scmi_sensor_info *
|
||||
scmi_sensor_info_get(const struct scmi_handle *handle, u32 sensor_id)
|
||||
{
|
||||
@ -282,6 +830,9 @@ static const struct scmi_sensor_ops sensor_ops = {
|
||||
.info_get = scmi_sensor_info_get,
|
||||
.trip_point_config = scmi_sensor_trip_point_config,
|
||||
.reading_get = scmi_sensor_reading_get,
|
||||
.reading_get_timestamped = scmi_sensor_reading_get_timestamped,
|
||||
.config_get = scmi_sensor_config_get,
|
||||
.config_set = scmi_sensor_config_set,
|
||||
};
|
||||
|
||||
static int scmi_sensor_set_notify_enabled(const struct scmi_handle *handle,
|
||||
@ -289,7 +840,19 @@ static int scmi_sensor_set_notify_enabled(const struct scmi_handle *handle,
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = scmi_sensor_trip_point_notify(handle, src_id, enable);
|
||||
switch (evt_id) {
|
||||
case SCMI_EVENT_SENSOR_TRIP_POINT_EVENT:
|
||||
ret = scmi_sensor_trip_point_notify(handle, src_id, enable);
|
||||
break;
|
||||
case SCMI_EVENT_SENSOR_UPDATE:
|
||||
ret = scmi_sensor_continuous_update_notify(handle, src_id,
|
||||
enable);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
|
||||
evt_id, src_id, ret);
|
||||
@ -302,20 +865,59 @@ static void *scmi_sensor_fill_custom_report(const struct scmi_handle *handle,
|
||||
const void *payld, size_t payld_sz,
|
||||
void *report, u32 *src_id)
|
||||
{
|
||||
const struct scmi_sensor_trip_notify_payld *p = payld;
|
||||
struct scmi_sensor_trip_point_report *r = report;
|
||||
void *rep = NULL;
|
||||
|
||||
if (evt_id != SCMI_EVENT_SENSOR_TRIP_POINT_EVENT ||
|
||||
sizeof(*p) != payld_sz)
|
||||
return NULL;
|
||||
switch (evt_id) {
|
||||
case SCMI_EVENT_SENSOR_TRIP_POINT_EVENT:
|
||||
{
|
||||
const struct scmi_sensor_trip_notify_payld *p = payld;
|
||||
struct scmi_sensor_trip_point_report *r = report;
|
||||
|
||||
r->timestamp = timestamp;
|
||||
r->agent_id = le32_to_cpu(p->agent_id);
|
||||
r->sensor_id = le32_to_cpu(p->sensor_id);
|
||||
r->trip_point_desc = le32_to_cpu(p->trip_point_desc);
|
||||
*src_id = r->sensor_id;
|
||||
if (sizeof(*p) != payld_sz)
|
||||
break;
|
||||
|
||||
return r;
|
||||
r->timestamp = timestamp;
|
||||
r->agent_id = le32_to_cpu(p->agent_id);
|
||||
r->sensor_id = le32_to_cpu(p->sensor_id);
|
||||
r->trip_point_desc = le32_to_cpu(p->trip_point_desc);
|
||||
*src_id = r->sensor_id;
|
||||
rep = r;
|
||||
break;
|
||||
}
|
||||
case SCMI_EVENT_SENSOR_UPDATE:
|
||||
{
|
||||
int i;
|
||||
struct scmi_sensor_info *s;
|
||||
const struct scmi_sensor_update_notify_payld *p = payld;
|
||||
struct scmi_sensor_update_report *r = report;
|
||||
struct sensors_info *sinfo = handle->sensor_priv;
|
||||
|
||||
/* payld_sz is variable for this event */
|
||||
r->sensor_id = le32_to_cpu(p->sensor_id);
|
||||
if (r->sensor_id >= sinfo->num_sensors)
|
||||
break;
|
||||
r->timestamp = timestamp;
|
||||
r->agent_id = le32_to_cpu(p->agent_id);
|
||||
s = &sinfo->sensors[r->sensor_id];
|
||||
/*
|
||||
* The generated report r (@struct scmi_sensor_update_report)
|
||||
* was pre-allocated to contain up to SCMI_MAX_NUM_SENSOR_AXIS
|
||||
* readings: here it is filled with the effective @num_axis
|
||||
* readings defined for this sensor or 1 for scalar sensors.
|
||||
*/
|
||||
r->readings_count = s->num_axis ?: 1;
|
||||
for (i = 0; i < r->readings_count; i++)
|
||||
scmi_parse_sensor_readings(&r->readings[i],
|
||||
&p->readings[i]);
|
||||
*src_id = r->sensor_id;
|
||||
rep = r;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return rep;
|
||||
}
|
||||
|
||||
static const struct scmi_event sensor_events[] = {
|
||||
@ -324,6 +926,16 @@ static const struct scmi_event sensor_events[] = {
|
||||
.max_payld_sz = sizeof(struct scmi_sensor_trip_notify_payld),
|
||||
.max_report_sz = sizeof(struct scmi_sensor_trip_point_report),
|
||||
},
|
||||
{
|
||||
.id = SCMI_EVENT_SENSOR_UPDATE,
|
||||
.max_payld_sz =
|
||||
sizeof(struct scmi_sensor_update_notify_payld) +
|
||||
SCMI_MAX_NUM_SENSOR_AXIS *
|
||||
sizeof(struct scmi_sensor_reading_resp),
|
||||
.max_report_sz = sizeof(struct scmi_sensor_update_report) +
|
||||
SCMI_MAX_NUM_SENSOR_AXIS *
|
||||
sizeof(struct scmi_sensor_reading),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct scmi_event_ops sensor_event_ops = {
|
||||
@ -334,6 +946,7 @@ static const struct scmi_event_ops sensor_event_ops = {
|
||||
static int scmi_sensors_protocol_init(struct scmi_handle *handle)
|
||||
{
|
||||
u32 version;
|
||||
int ret;
|
||||
struct sensors_info *sinfo;
|
||||
|
||||
scmi_version_get(handle, SCMI_PROTOCOL_SENSOR, &version);
|
||||
@ -344,15 +957,19 @@ static int scmi_sensors_protocol_init(struct scmi_handle *handle)
|
||||
sinfo = devm_kzalloc(handle->dev, sizeof(*sinfo), GFP_KERNEL);
|
||||
if (!sinfo)
|
||||
return -ENOMEM;
|
||||
sinfo->version = version;
|
||||
|
||||
scmi_sensor_attributes_get(handle, sinfo);
|
||||
|
||||
ret = scmi_sensor_attributes_get(handle, sinfo);
|
||||
if (ret)
|
||||
return ret;
|
||||
sinfo->sensors = devm_kcalloc(handle->dev, sinfo->num_sensors,
|
||||
sizeof(*sinfo->sensors), GFP_KERNEL);
|
||||
if (!sinfo->sensors)
|
||||
return -ENOMEM;
|
||||
|
||||
scmi_sensor_description_get(handle, sinfo);
|
||||
ret = scmi_sensor_description_get(handle, sinfo);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
scmi_register_protocol_events(handle,
|
||||
SCMI_PROTOCOL_SENSOR, SCMI_PROTO_QUEUE_SZ,
|
||||
@ -360,9 +977,8 @@ static int scmi_sensors_protocol_init(struct scmi_handle *handle)
|
||||
ARRAY_SIZE(sensor_events),
|
||||
sinfo->num_sensors);
|
||||
|
||||
sinfo->version = version;
|
||||
handle->sensor_ops = &sensor_ops;
|
||||
handle->sensor_priv = sinfo;
|
||||
handle->sensor_ops = &sensor_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -60,22 +60,40 @@ static void imx_dsp_handle_rx(struct mbox_client *c, void *msg)
|
||||
}
|
||||
}
|
||||
|
||||
static int imx_dsp_probe(struct platform_device *pdev)
|
||||
struct mbox_chan *imx_dsp_request_channel(struct imx_dsp_ipc *dsp_ipc, int idx)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct imx_dsp_ipc *dsp_ipc;
|
||||
struct imx_dsp_chan *dsp_chan;
|
||||
|
||||
if (idx >= DSP_MU_CHAN_NUM)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
dsp_chan = &dsp_ipc->chans[idx];
|
||||
dsp_chan->ch = mbox_request_channel_byname(&dsp_chan->cl, dsp_chan->name);
|
||||
return dsp_chan->ch;
|
||||
}
|
||||
EXPORT_SYMBOL(imx_dsp_request_channel);
|
||||
|
||||
void imx_dsp_free_channel(struct imx_dsp_ipc *dsp_ipc, int idx)
|
||||
{
|
||||
struct imx_dsp_chan *dsp_chan;
|
||||
|
||||
if (idx >= DSP_MU_CHAN_NUM)
|
||||
return;
|
||||
|
||||
dsp_chan = &dsp_ipc->chans[idx];
|
||||
mbox_free_channel(dsp_chan->ch);
|
||||
}
|
||||
EXPORT_SYMBOL(imx_dsp_free_channel);
|
||||
|
||||
static int imx_dsp_setup_channels(struct imx_dsp_ipc *dsp_ipc)
|
||||
{
|
||||
struct device *dev = dsp_ipc->dev;
|
||||
struct imx_dsp_chan *dsp_chan;
|
||||
struct mbox_client *cl;
|
||||
char *chan_name;
|
||||
int ret;
|
||||
int i, j;
|
||||
|
||||
device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
|
||||
|
||||
dsp_ipc = devm_kzalloc(dev, sizeof(*dsp_ipc), GFP_KERNEL);
|
||||
if (!dsp_ipc)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < DSP_MU_CHAN_NUM; i++) {
|
||||
if (i < 2)
|
||||
chan_name = kasprintf(GFP_KERNEL, "txdb%d", i);
|
||||
@ -86,6 +104,7 @@ static int imx_dsp_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
dsp_chan = &dsp_ipc->chans[i];
|
||||
dsp_chan->name = chan_name;
|
||||
cl = &dsp_chan->cl;
|
||||
cl->dev = dev;
|
||||
cl->tx_block = false;
|
||||
@ -104,25 +123,41 @@ static int imx_dsp_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
dev_dbg(dev, "request mbox chan %s\n", chan_name);
|
||||
/* chan_name is not used anymore by framework */
|
||||
kfree(chan_name);
|
||||
}
|
||||
|
||||
dsp_ipc->dev = dev;
|
||||
return 0;
|
||||
out:
|
||||
for (j = 0; j < i; j++) {
|
||||
dsp_chan = &dsp_ipc->chans[j];
|
||||
mbox_free_channel(dsp_chan->ch);
|
||||
kfree(dsp_chan->name);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx_dsp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct imx_dsp_ipc *dsp_ipc;
|
||||
int ret;
|
||||
|
||||
device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
|
||||
|
||||
dsp_ipc = devm_kzalloc(dev, sizeof(*dsp_ipc), GFP_KERNEL);
|
||||
if (!dsp_ipc)
|
||||
return -ENOMEM;
|
||||
|
||||
dsp_ipc->dev = dev;
|
||||
dev_set_drvdata(dev, dsp_ipc);
|
||||
|
||||
ret = imx_dsp_setup_channels(dsp_ipc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev_info(dev, "NXP i.MX DSP IPC initialized\n");
|
||||
|
||||
return 0;
|
||||
out:
|
||||
kfree(chan_name);
|
||||
for (j = 0; j < i; j++) {
|
||||
dsp_chan = &dsp_ipc->chans[j];
|
||||
mbox_free_channel(dsp_chan->ch);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx_dsp_remove(struct platform_device *pdev)
|
||||
@ -136,6 +171,7 @@ static int imx_dsp_remove(struct platform_device *pdev)
|
||||
for (i = 0; i < DSP_MU_CHAN_NUM; i++) {
|
||||
dsp_chan = &dsp_ipc->chans[i];
|
||||
mbox_free_channel(dsp_chan->ch);
|
||||
kfree(dsp_chan->name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -160,12 +160,18 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
|
||||
{ "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, false, 0 },
|
||||
{ "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, true, 0 },
|
||||
|
||||
{ "mipi1", IMX_SC_R_MIPI_1, 1, false, 0 },
|
||||
{ "mipi1-pwm0", IMX_SC_R_MIPI_1_PWM_0, 1, false, 0 },
|
||||
{ "mipi1-i2c", IMX_SC_R_MIPI_1_I2C_0, 2, true, 0 },
|
||||
|
||||
/* LVDS SS */
|
||||
{ "lvds0", IMX_SC_R_LVDS_0, 1, false, 0 },
|
||||
{ "lvds1", IMX_SC_R_LVDS_1, 1, false, 0 },
|
||||
|
||||
/* DC SS */
|
||||
{ "dc0", IMX_SC_R_DC_0, 1, false, 0 },
|
||||
{ "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, true, 0 },
|
||||
{ "dc0-video", IMX_SC_R_DC_0_VIDEO0, 2, true, 0 },
|
||||
|
||||
/* CM40 SS */
|
||||
{ "cm40-i2c", IMX_SC_R_M4_0_I2C, 1, false, 0 },
|
||||
@ -180,6 +186,12 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
|
||||
{ "cm41-pid", IMX_SC_R_M4_1_PID0, 5, true, 0},
|
||||
{ "cm41-mu-a1", IMX_SC_R_M4_1_MU_1A, 1, false, 0},
|
||||
{ "cm41-lpuart", IMX_SC_R_M4_1_UART, 1, false, 0},
|
||||
|
||||
/* IMAGE SS */
|
||||
{ "img-jpegdec-mp", IMX_SC_R_MJPEG_DEC_MP, 1, false, 0 },
|
||||
{ "img-jpegdec-s0", IMX_SC_R_MJPEG_DEC_S0, 4, true, 0 },
|
||||
{ "img-jpegenc-mp", IMX_SC_R_MJPEG_ENC_MP, 1, false, 0 },
|
||||
{ "img-jpegenc-s0", IMX_SC_R_MJPEG_ENC_S0, 4, true, 0 },
|
||||
};
|
||||
|
||||
static const struct imx_sc_pd_soc imx8qxp_scu_pd = {
|
||||
|
@ -3,8 +3,9 @@
|
||||
# Amlogic Secure Monitor driver
|
||||
#
|
||||
config MESON_SM
|
||||
bool
|
||||
default ARCH_MESON
|
||||
tristate "Amlogic Secure Monitor driver"
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
default y
|
||||
depends on ARM64_4K_PAGES
|
||||
help
|
||||
Say y here to enable the Amlogic secure monitor driver
|
||||
|
@ -331,3 +331,4 @@ static struct platform_driver meson_sm_driver = {
|
||||
},
|
||||
};
|
||||
module_platform_driver_probe(meson_sm_driver, meson_sm_probe);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -412,16 +412,12 @@ static int bpmp_populate_debugfs_inband(struct tegra_bpmp *bpmp,
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = strlen(ppath) + strlen(name) + 1;
|
||||
len = snprintf(pathbuf, pathlen, "%s%s/", ppath, name);
|
||||
if (len >= pathlen) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
strncpy(pathbuf, ppath, pathlen);
|
||||
strncat(pathbuf, name, strlen(name));
|
||||
strcat(pathbuf, "/");
|
||||
|
||||
err = bpmp_populate_debugfs_inband(bpmp, dentry,
|
||||
pathbuf);
|
||||
if (err < 0)
|
||||
|
@ -1703,14 +1703,14 @@ fail:
|
||||
* @subtype: Resource assignment subtype that is being requested
|
||||
* from the given device.
|
||||
* @s_host: Host processor ID to which the resources are allocated
|
||||
* @range_start: Start index of the resource range
|
||||
* @range_num: Number of resources in the range
|
||||
* @desc: Pointer to ti_sci_resource_desc to be updated with the
|
||||
* resource range start index and number of resources
|
||||
*
|
||||
* Return: 0 if all went fine, else return appropriate error.
|
||||
*/
|
||||
static int ti_sci_get_resource_range(const struct ti_sci_handle *handle,
|
||||
u32 dev_id, u8 subtype, u8 s_host,
|
||||
u16 *range_start, u16 *range_num)
|
||||
struct ti_sci_resource_desc *desc)
|
||||
{
|
||||
struct ti_sci_msg_resp_get_resource_range *resp;
|
||||
struct ti_sci_msg_req_get_resource_range *req;
|
||||
@ -1721,7 +1721,7 @@ static int ti_sci_get_resource_range(const struct ti_sci_handle *handle,
|
||||
|
||||
if (IS_ERR(handle))
|
||||
return PTR_ERR(handle);
|
||||
if (!handle)
|
||||
if (!handle || !desc)
|
||||
return -EINVAL;
|
||||
|
||||
info = handle_to_ti_sci_info(handle);
|
||||
@ -1751,11 +1751,14 @@ static int ti_sci_get_resource_range(const struct ti_sci_handle *handle,
|
||||
|
||||
if (!ti_sci_is_response_ack(resp)) {
|
||||
ret = -ENODEV;
|
||||
} else if (!resp->range_start && !resp->range_num) {
|
||||
} else if (!resp->range_num && !resp->range_num_sec) {
|
||||
/* Neither of the two resource range is valid */
|
||||
ret = -ENODEV;
|
||||
} else {
|
||||
*range_start = resp->range_start;
|
||||
*range_num = resp->range_num;
|
||||
desc->start = resp->range_start;
|
||||
desc->num = resp->range_num;
|
||||
desc->start_sec = resp->range_start_sec;
|
||||
desc->num_sec = resp->range_num_sec;
|
||||
};
|
||||
|
||||
fail:
|
||||
@ -1771,18 +1774,18 @@ fail:
|
||||
* @dev_id: TISCI device ID.
|
||||
* @subtype: Resource assignment subtype that is being requested
|
||||
* from the given device.
|
||||
* @range_start: Start index of the resource range
|
||||
* @range_num: Number of resources in the range
|
||||
* @desc: Pointer to ti_sci_resource_desc to be updated with the
|
||||
* resource range start index and number of resources
|
||||
*
|
||||
* Return: 0 if all went fine, else return appropriate error.
|
||||
*/
|
||||
static int ti_sci_cmd_get_resource_range(const struct ti_sci_handle *handle,
|
||||
u32 dev_id, u8 subtype,
|
||||
u16 *range_start, u16 *range_num)
|
||||
struct ti_sci_resource_desc *desc)
|
||||
{
|
||||
return ti_sci_get_resource_range(handle, dev_id, subtype,
|
||||
TI_SCI_IRQ_SECONDARY_HOST_INVALID,
|
||||
range_start, range_num);
|
||||
desc);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1793,18 +1796,17 @@ static int ti_sci_cmd_get_resource_range(const struct ti_sci_handle *handle,
|
||||
* @subtype: Resource assignment subtype that is being requested
|
||||
* from the given device.
|
||||
* @s_host: Host processor ID to which the resources are allocated
|
||||
* @range_start: Start index of the resource range
|
||||
* @range_num: Number of resources in the range
|
||||
* @desc: Pointer to ti_sci_resource_desc to be updated with the
|
||||
* resource range start index and number of resources
|
||||
*
|
||||
* Return: 0 if all went fine, else return appropriate error.
|
||||
*/
|
||||
static
|
||||
int ti_sci_cmd_get_resource_range_from_shost(const struct ti_sci_handle *handle,
|
||||
u32 dev_id, u8 subtype, u8 s_host,
|
||||
u16 *range_start, u16 *range_num)
|
||||
struct ti_sci_resource_desc *desc)
|
||||
{
|
||||
return ti_sci_get_resource_range(handle, dev_id, subtype, s_host,
|
||||
range_start, range_num);
|
||||
return ti_sci_get_resource_range(handle, dev_id, subtype, s_host, desc);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2047,28 +2049,17 @@ static int ti_sci_cmd_free_event_map(const struct ti_sci_handle *handle,
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_cmd_ring_config() - configure RA ring
|
||||
* @handle: Pointer to TI SCI handle.
|
||||
* @valid_params: Bitfield defining validity of ring configuration
|
||||
* parameters
|
||||
* @nav_id: Device ID of Navigator Subsystem from which the ring is
|
||||
* allocated
|
||||
* @index: Ring index
|
||||
* @addr_lo: The ring base address lo 32 bits
|
||||
* @addr_hi: The ring base address hi 32 bits
|
||||
* @count: Number of ring elements
|
||||
* @mode: The mode of the ring
|
||||
* @size: The ring element size.
|
||||
* @order_id: Specifies the ring's bus order ID
|
||||
* ti_sci_cmd_rm_ring_cfg() - Configure a NAVSS ring
|
||||
* @handle: Pointer to TI SCI handle.
|
||||
* @params: Pointer to ti_sci_msg_rm_ring_cfg ring config structure
|
||||
*
|
||||
* Return: 0 if all went well, else returns appropriate error value.
|
||||
*
|
||||
* See @ti_sci_msg_rm_ring_cfg_req for more info.
|
||||
* See @ti_sci_msg_rm_ring_cfg and @ti_sci_msg_rm_ring_cfg_req for
|
||||
* more info.
|
||||
*/
|
||||
static int ti_sci_cmd_ring_config(const struct ti_sci_handle *handle,
|
||||
u32 valid_params, u16 nav_id, u16 index,
|
||||
u32 addr_lo, u32 addr_hi, u32 count,
|
||||
u8 mode, u8 size, u8 order_id)
|
||||
static int ti_sci_cmd_rm_ring_cfg(const struct ti_sci_handle *handle,
|
||||
const struct ti_sci_msg_rm_ring_cfg *params)
|
||||
{
|
||||
struct ti_sci_msg_rm_ring_cfg_req *req;
|
||||
struct ti_sci_msg_hdr *resp;
|
||||
@ -2092,15 +2083,17 @@ static int ti_sci_cmd_ring_config(const struct ti_sci_handle *handle,
|
||||
return ret;
|
||||
}
|
||||
req = (struct ti_sci_msg_rm_ring_cfg_req *)xfer->xfer_buf;
|
||||
req->valid_params = valid_params;
|
||||
req->nav_id = nav_id;
|
||||
req->index = index;
|
||||
req->addr_lo = addr_lo;
|
||||
req->addr_hi = addr_hi;
|
||||
req->count = count;
|
||||
req->mode = mode;
|
||||
req->size = size;
|
||||
req->order_id = order_id;
|
||||
req->valid_params = params->valid_params;
|
||||
req->nav_id = params->nav_id;
|
||||
req->index = params->index;
|
||||
req->addr_lo = params->addr_lo;
|
||||
req->addr_hi = params->addr_hi;
|
||||
req->count = params->count;
|
||||
req->mode = params->mode;
|
||||
req->size = params->size;
|
||||
req->order_id = params->order_id;
|
||||
req->virtid = params->virtid;
|
||||
req->asel = params->asel;
|
||||
|
||||
ret = ti_sci_do_xfer(info, xfer);
|
||||
if (ret) {
|
||||
@ -2109,90 +2102,11 @@ static int ti_sci_cmd_ring_config(const struct ti_sci_handle *handle,
|
||||
}
|
||||
|
||||
resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf;
|
||||
ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV;
|
||||
ret = ti_sci_is_response_ack(resp) ? 0 : -EINVAL;
|
||||
|
||||
fail:
|
||||
ti_sci_put_one_xfer(&info->minfo, xfer);
|
||||
dev_dbg(dev, "RM_RA:config ring %u ret:%d\n", index, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_cmd_ring_get_config() - get RA ring configuration
|
||||
* @handle: Pointer to TI SCI handle.
|
||||
* @nav_id: Device ID of Navigator Subsystem from which the ring is
|
||||
* allocated
|
||||
* @index: Ring index
|
||||
* @addr_lo: Returns ring's base address lo 32 bits
|
||||
* @addr_hi: Returns ring's base address hi 32 bits
|
||||
* @count: Returns number of ring elements
|
||||
* @mode: Returns mode of the ring
|
||||
* @size: Returns ring element size
|
||||
* @order_id: Returns ring's bus order ID
|
||||
*
|
||||
* Return: 0 if all went well, else returns appropriate error value.
|
||||
*
|
||||
* See @ti_sci_msg_rm_ring_get_cfg_req for more info.
|
||||
*/
|
||||
static int ti_sci_cmd_ring_get_config(const struct ti_sci_handle *handle,
|
||||
u32 nav_id, u32 index, u8 *mode,
|
||||
u32 *addr_lo, u32 *addr_hi,
|
||||
u32 *count, u8 *size, u8 *order_id)
|
||||
{
|
||||
struct ti_sci_msg_rm_ring_get_cfg_resp *resp;
|
||||
struct ti_sci_msg_rm_ring_get_cfg_req *req;
|
||||
struct ti_sci_xfer *xfer;
|
||||
struct ti_sci_info *info;
|
||||
struct device *dev;
|
||||
int ret = 0;
|
||||
|
||||
if (IS_ERR_OR_NULL(handle))
|
||||
return -EINVAL;
|
||||
|
||||
info = handle_to_ti_sci_info(handle);
|
||||
dev = info->dev;
|
||||
|
||||
xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_RM_RING_GET_CFG,
|
||||
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
|
||||
sizeof(*req), sizeof(*resp));
|
||||
if (IS_ERR(xfer)) {
|
||||
ret = PTR_ERR(xfer);
|
||||
dev_err(dev,
|
||||
"RM_RA:Message get config failed(%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
req = (struct ti_sci_msg_rm_ring_get_cfg_req *)xfer->xfer_buf;
|
||||
req->nav_id = nav_id;
|
||||
req->index = index;
|
||||
|
||||
ret = ti_sci_do_xfer(info, xfer);
|
||||
if (ret) {
|
||||
dev_err(dev, "RM_RA:Mbox get config send fail %d\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
resp = (struct ti_sci_msg_rm_ring_get_cfg_resp *)xfer->xfer_buf;
|
||||
|
||||
if (!ti_sci_is_response_ack(resp)) {
|
||||
ret = -ENODEV;
|
||||
} else {
|
||||
if (mode)
|
||||
*mode = resp->mode;
|
||||
if (addr_lo)
|
||||
*addr_lo = resp->addr_lo;
|
||||
if (addr_hi)
|
||||
*addr_hi = resp->addr_hi;
|
||||
if (count)
|
||||
*count = resp->count;
|
||||
if (size)
|
||||
*size = resp->size;
|
||||
if (order_id)
|
||||
*order_id = resp->order_id;
|
||||
};
|
||||
|
||||
fail:
|
||||
ti_sci_put_one_xfer(&info->minfo, xfer);
|
||||
dev_dbg(dev, "RM_RA:get config ring %u ret:%d\n", index, ret);
|
||||
dev_dbg(dev, "RM_RA:config ring %u ret:%d\n", params->index, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2362,6 +2276,8 @@ static int ti_sci_cmd_rm_udmap_tx_ch_cfg(const struct ti_sci_handle *handle,
|
||||
req->fdepth = params->fdepth;
|
||||
req->tx_sched_priority = params->tx_sched_priority;
|
||||
req->tx_burst_size = params->tx_burst_size;
|
||||
req->tx_tdtype = params->tx_tdtype;
|
||||
req->extended_ch_type = params->extended_ch_type;
|
||||
|
||||
ret = ti_sci_do_xfer(info, xfer);
|
||||
if (ret) {
|
||||
@ -2921,8 +2837,7 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
|
||||
iops->free_irq = ti_sci_cmd_free_irq;
|
||||
iops->free_event_map = ti_sci_cmd_free_event_map;
|
||||
|
||||
rops->config = ti_sci_cmd_ring_config;
|
||||
rops->get_config = ti_sci_cmd_ring_get_config;
|
||||
rops->set_cfg = ti_sci_cmd_rm_ring_cfg;
|
||||
|
||||
psilops->pair = ti_sci_cmd_rm_psil_pair;
|
||||
psilops->unpair = ti_sci_cmd_rm_psil_unpair;
|
||||
@ -3157,12 +3072,18 @@ u16 ti_sci_get_free_resource(struct ti_sci_resource *res)
|
||||
|
||||
raw_spin_lock_irqsave(&res->lock, flags);
|
||||
for (set = 0; set < res->sets; set++) {
|
||||
free_bit = find_first_zero_bit(res->desc[set].res_map,
|
||||
res->desc[set].num);
|
||||
if (free_bit != res->desc[set].num) {
|
||||
set_bit(free_bit, res->desc[set].res_map);
|
||||
struct ti_sci_resource_desc *desc = &res->desc[set];
|
||||
int res_count = desc->num + desc->num_sec;
|
||||
|
||||
free_bit = find_first_zero_bit(desc->res_map, res_count);
|
||||
if (free_bit != res_count) {
|
||||
set_bit(free_bit, desc->res_map);
|
||||
raw_spin_unlock_irqrestore(&res->lock, flags);
|
||||
return res->desc[set].start + free_bit;
|
||||
|
||||
if (desc->num && free_bit < desc->num)
|
||||
return desc->start + free_bit;
|
||||
else
|
||||
return desc->start_sec + free_bit;
|
||||
}
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&res->lock, flags);
|
||||
@ -3183,10 +3104,14 @@ void ti_sci_release_resource(struct ti_sci_resource *res, u16 id)
|
||||
|
||||
raw_spin_lock_irqsave(&res->lock, flags);
|
||||
for (set = 0; set < res->sets; set++) {
|
||||
if (res->desc[set].start <= id &&
|
||||
(res->desc[set].num + res->desc[set].start) > id)
|
||||
clear_bit(id - res->desc[set].start,
|
||||
res->desc[set].res_map);
|
||||
struct ti_sci_resource_desc *desc = &res->desc[set];
|
||||
|
||||
if (desc->num && desc->start <= id &&
|
||||
(desc->start + desc->num) > id)
|
||||
clear_bit(id - desc->start, desc->res_map);
|
||||
else if (desc->num_sec && desc->start_sec <= id &&
|
||||
(desc->start_sec + desc->num_sec) > id)
|
||||
clear_bit(id - desc->start_sec, desc->res_map);
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&res->lock, flags);
|
||||
}
|
||||
@ -3203,7 +3128,7 @@ u32 ti_sci_get_num_resources(struct ti_sci_resource *res)
|
||||
u32 set, count = 0;
|
||||
|
||||
for (set = 0; set < res->sets; set++)
|
||||
count += res->desc[set].num;
|
||||
count += res->desc[set].num + res->desc[set].num_sec;
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -3227,7 +3152,7 @@ devm_ti_sci_get_resource_sets(const struct ti_sci_handle *handle,
|
||||
{
|
||||
struct ti_sci_resource *res;
|
||||
bool valid_set = false;
|
||||
int i, ret;
|
||||
int i, ret, res_count;
|
||||
|
||||
res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
|
||||
if (!res)
|
||||
@ -3242,23 +3167,23 @@ devm_ti_sci_get_resource_sets(const struct ti_sci_handle *handle,
|
||||
for (i = 0; i < res->sets; i++) {
|
||||
ret = handle->ops.rm_core_ops.get_range(handle, dev_id,
|
||||
sub_types[i],
|
||||
&res->desc[i].start,
|
||||
&res->desc[i].num);
|
||||
&res->desc[i]);
|
||||
if (ret) {
|
||||
dev_dbg(dev, "dev = %d subtype %d not allocated for this host\n",
|
||||
dev_id, sub_types[i]);
|
||||
res->desc[i].start = 0;
|
||||
res->desc[i].num = 0;
|
||||
memset(&res->desc[i], 0, sizeof(res->desc[i]));
|
||||
continue;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "dev = %d, subtype = %d, start = %d, num = %d\n",
|
||||
dev_dbg(dev, "dev/sub_type: %d/%d, start/num: %d/%d | %d/%d\n",
|
||||
dev_id, sub_types[i], res->desc[i].start,
|
||||
res->desc[i].num);
|
||||
res->desc[i].num, res->desc[i].start_sec,
|
||||
res->desc[i].num_sec);
|
||||
|
||||
valid_set = true;
|
||||
res_count = res->desc[i].num + res->desc[i].num_sec;
|
||||
res->desc[i].res_map =
|
||||
devm_kzalloc(dev, BITS_TO_LONGS(res->desc[i].num) *
|
||||
devm_kzalloc(dev, BITS_TO_LONGS(res_count) *
|
||||
sizeof(*res->desc[i].res_map), GFP_KERNEL);
|
||||
if (!res->desc[i].res_map)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
@ -49,7 +49,6 @@
|
||||
#define TI_SCI_MSG_RM_RING_RECONFIG 0x1102
|
||||
#define TI_SCI_MSG_RM_RING_RESET 0x1103
|
||||
#define TI_SCI_MSG_RM_RING_CFG 0x1110
|
||||
#define TI_SCI_MSG_RM_RING_GET_CFG 0x1111
|
||||
|
||||
/* PSI-L requests */
|
||||
#define TI_SCI_MSG_RM_PSIL_PAIR 0x1280
|
||||
@ -574,8 +573,10 @@ struct ti_sci_msg_req_get_resource_range {
|
||||
/**
|
||||
* struct ti_sci_msg_resp_get_resource_range - Response to resource get range.
|
||||
* @hdr: Generic Header
|
||||
* @range_start: Start index of the resource range.
|
||||
* @range_num: Number of resources in the range.
|
||||
* @range_start: Start index of the first resource range.
|
||||
* @range_num: Number of resources in the first range.
|
||||
* @range_start_sec: Start index of the second resource range.
|
||||
* @range_num_sec: Number of resources in the second range.
|
||||
*
|
||||
* Response to request TI_SCI_MSG_GET_RESOURCE_RANGE.
|
||||
*/
|
||||
@ -583,6 +584,8 @@ struct ti_sci_msg_resp_get_resource_range {
|
||||
struct ti_sci_msg_hdr hdr;
|
||||
u16 range_start;
|
||||
u16 range_num;
|
||||
u16 range_start_sec;
|
||||
u16 range_num_sec;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
@ -656,6 +659,8 @@ struct ti_sci_msg_req_manage_irq {
|
||||
* 3 - Valid bit for @tisci_msg_rm_ring_cfg_req mode
|
||||
* 4 - Valid bit for @tisci_msg_rm_ring_cfg_req size
|
||||
* 5 - Valid bit for @tisci_msg_rm_ring_cfg_req order_id
|
||||
* 6 - Valid bit for @tisci_msg_rm_ring_cfg_req virtid
|
||||
* 7 - Valid bit for @tisci_msg_rm_ring_cfg_req ASEL
|
||||
* @nav_id: Device ID of Navigator Subsystem from which the ring is allocated
|
||||
* @index: ring index to be configured.
|
||||
* @addr_lo: 32 LSBs of ring base address to be programmed into the ring's
|
||||
@ -669,6 +674,9 @@ struct ti_sci_msg_req_manage_irq {
|
||||
* the formula (log2(size_bytes) - 2), where size_bytes cannot be
|
||||
* greater than 256.
|
||||
* @order_id: Specifies the ring's bus order ID.
|
||||
* @virtid: Ring virt ID value
|
||||
* @asel: Ring ASEL (address select) value to be set into the ASEL field of the
|
||||
* ring's RING_BA_HI register.
|
||||
*/
|
||||
struct ti_sci_msg_rm_ring_cfg_req {
|
||||
struct ti_sci_msg_hdr hdr;
|
||||
@ -681,49 +689,8 @@ struct ti_sci_msg_rm_ring_cfg_req {
|
||||
u8 mode;
|
||||
u8 size;
|
||||
u8 order_id;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct ti_sci_msg_rm_ring_get_cfg_req - Get RA ring's configuration
|
||||
*
|
||||
* Gets the configuration of the non-real-time register fields of a ring. The
|
||||
* host, or a supervisor of the host, who owns the ring must be the requesting
|
||||
* host. The values of the non-real-time registers are returned in
|
||||
* @ti_sci_msg_rm_ring_get_cfg_resp.
|
||||
*
|
||||
* @hdr: Generic Header
|
||||
* @nav_id: Device ID of Navigator Subsystem from which the ring is allocated
|
||||
* @index: ring index.
|
||||
*/
|
||||
struct ti_sci_msg_rm_ring_get_cfg_req {
|
||||
struct ti_sci_msg_hdr hdr;
|
||||
u16 nav_id;
|
||||
u16 index;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct ti_sci_msg_rm_ring_get_cfg_resp - Ring get configuration response
|
||||
*
|
||||
* Response received by host processor after RM has handled
|
||||
* @ti_sci_msg_rm_ring_get_cfg_req. The response contains the ring's
|
||||
* non-real-time register values.
|
||||
*
|
||||
* @hdr: Generic Header
|
||||
* @addr_lo: Ring 32 LSBs of base address
|
||||
* @addr_hi: Ring 16 MSBs of base address.
|
||||
* @count: Ring number of elements.
|
||||
* @mode: Ring mode.
|
||||
* @size: encoded Ring element size
|
||||
* @order_id: ing order ID.
|
||||
*/
|
||||
struct ti_sci_msg_rm_ring_get_cfg_resp {
|
||||
struct ti_sci_msg_hdr hdr;
|
||||
u32 addr_lo;
|
||||
u32 addr_hi;
|
||||
u32 count;
|
||||
u8 mode;
|
||||
u8 size;
|
||||
u8 order_id;
|
||||
u16 virtid;
|
||||
u8 asel;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
@ -910,6 +877,8 @@ struct rm_ti_sci_msg_udmap_rx_flow_opt_cfg {
|
||||
* 12 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_credit_count
|
||||
* 13 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::fdepth
|
||||
* 14 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_burst_size
|
||||
* 15 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_tdtype
|
||||
* 16 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::extended_ch_type
|
||||
*
|
||||
* @nav_id: SoC device ID of Navigator Subsystem where tx channel is located
|
||||
*
|
||||
@ -973,6 +942,15 @@ struct rm_ti_sci_msg_udmap_rx_flow_opt_cfg {
|
||||
*
|
||||
* @tx_burst_size: UDMAP transmit channel burst size configuration to be
|
||||
* programmed into the tx_burst_size field of the TCHAN_TCFG register.
|
||||
*
|
||||
* @tx_tdtype: UDMAP transmit channel teardown type configuration to be
|
||||
* programmed into the tdtype field of the TCHAN_TCFG register:
|
||||
* 0 - Return immediately
|
||||
* 1 - Wait for completion message from remote peer
|
||||
*
|
||||
* @extended_ch_type: Valid for BCDMA.
|
||||
* 0 - the channel is split tx channel (tchan)
|
||||
* 1 - the channel is block copy channel (bchan)
|
||||
*/
|
||||
struct ti_sci_msg_rm_udmap_tx_ch_cfg_req {
|
||||
struct ti_sci_msg_hdr hdr;
|
||||
@ -994,6 +972,8 @@ struct ti_sci_msg_rm_udmap_tx_ch_cfg_req {
|
||||
u16 fdepth;
|
||||
u8 tx_sched_priority;
|
||||
u8 tx_burst_size;
|
||||
u8 tx_tdtype;
|
||||
u8 extended_ch_type;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
|
@ -615,13 +615,13 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_get_pll_frac_data);
|
||||
/**
|
||||
* zynqmp_pm_set_sd_tapdelay() - Set tap delay for the SD device
|
||||
*
|
||||
* @node_id Node ID of the device
|
||||
* @type Type of tap delay to set (input/output)
|
||||
* @value Value to set fot the tap delay
|
||||
* @node_id: Node ID of the device
|
||||
* @type: Type of tap delay to set (input/output)
|
||||
* @value: Value to set fot the tap delay
|
||||
*
|
||||
* This function sets input/output tap delay for the SD device.
|
||||
*
|
||||
* @return Returns status, either success or error+reason
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
int zynqmp_pm_set_sd_tapdelay(u32 node_id, u32 type, u32 value)
|
||||
{
|
||||
@ -633,12 +633,12 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_tapdelay);
|
||||
/**
|
||||
* zynqmp_pm_sd_dll_reset() - Reset DLL logic
|
||||
*
|
||||
* @node_id Node ID of the device
|
||||
* @type Reset type
|
||||
* @node_id: Node ID of the device
|
||||
* @type: Reset type
|
||||
*
|
||||
* This function resets DLL logic for the SD device.
|
||||
*
|
||||
* @return Returns status, either success or error+reason
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
int zynqmp_pm_sd_dll_reset(u32 node_id, u32 type)
|
||||
{
|
||||
@ -649,12 +649,12 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_sd_dll_reset);
|
||||
|
||||
/**
|
||||
* zynqmp_pm_write_ggs() - PM API for writing global general storage (ggs)
|
||||
* @index GGS register index
|
||||
* @value Register value to be written
|
||||
* @index: GGS register index
|
||||
* @value: Register value to be written
|
||||
*
|
||||
* This function writes value to GGS register.
|
||||
*
|
||||
* @return Returns status, either success or error+reason
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
int zynqmp_pm_write_ggs(u32 index, u32 value)
|
||||
{
|
||||
@ -665,12 +665,12 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_write_ggs);
|
||||
|
||||
/**
|
||||
* zynqmp_pm_write_ggs() - PM API for reading global general storage (ggs)
|
||||
* @index GGS register index
|
||||
* @value Register value to be written
|
||||
* @index: GGS register index
|
||||
* @value: Register value to be written
|
||||
*
|
||||
* This function returns GGS register value.
|
||||
*
|
||||
* @return Returns status, either success or error+reason
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
int zynqmp_pm_read_ggs(u32 index, u32 *value)
|
||||
{
|
||||
@ -682,12 +682,12 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_read_ggs);
|
||||
/**
|
||||
* zynqmp_pm_write_pggs() - PM API for writing persistent global general
|
||||
* storage (pggs)
|
||||
* @index PGGS register index
|
||||
* @value Register value to be written
|
||||
* @index: PGGS register index
|
||||
* @value: Register value to be written
|
||||
*
|
||||
* This function writes value to PGGS register.
|
||||
*
|
||||
* @return Returns status, either success or error+reason
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
int zynqmp_pm_write_pggs(u32 index, u32 value)
|
||||
{
|
||||
@ -699,12 +699,12 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_write_pggs);
|
||||
/**
|
||||
* zynqmp_pm_write_pggs() - PM API for reading persistent global general
|
||||
* storage (pggs)
|
||||
* @index PGGS register index
|
||||
* @value Register value to be written
|
||||
* @index: PGGS register index
|
||||
* @value: Register value to be written
|
||||
*
|
||||
* This function returns PGGS register value.
|
||||
*
|
||||
* @return Returns status, either success or error+reason
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
int zynqmp_pm_read_pggs(u32 index, u32 *value)
|
||||
{
|
||||
@ -715,12 +715,12 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_read_pggs);
|
||||
|
||||
/**
|
||||
* zynqmp_pm_set_boot_health_status() - PM API for setting healthy boot status
|
||||
* @value Status value to be written
|
||||
* @value: Status value to be written
|
||||
*
|
||||
* This function sets healthy bit value to indicate boot health status
|
||||
* to firmware.
|
||||
*
|
||||
* @return Returns status, either success or error+reason
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
int zynqmp_pm_set_boot_health_status(u32 value)
|
||||
{
|
||||
@ -815,10 +815,10 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_fpga_get_status);
|
||||
* zynqmp_pm_init_finalize() - PM call to inform firmware that the caller
|
||||
* master has initialized its own power management
|
||||
*
|
||||
* Return: Returns status, either success or error+reason
|
||||
*
|
||||
* This API function is to be used for notify the power management controller
|
||||
* about the completed power management initialization.
|
||||
*
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
int zynqmp_pm_init_finalize(void)
|
||||
{
|
||||
|
@ -829,8 +829,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
|
||||
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
|
||||
mtk_crtc->cmdq_client =
|
||||
cmdq_mbox_create(mtk_crtc->mmsys_dev,
|
||||
drm_crtc_index(&mtk_crtc->base),
|
||||
2000);
|
||||
drm_crtc_index(&mtk_crtc->base));
|
||||
if (IS_ERR(mtk_crtc->cmdq_client)) {
|
||||
dev_dbg(dev, "mtk_crtc %d failed to create mailbox client, writing register by CPU now\n",
|
||||
drm_crtc_index(&mtk_crtc->base));
|
||||
|
@ -7,6 +7,7 @@
|
||||
#define MTK_DRM_DDP_COMP_H
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/soc/mediatek/mtk-mmsys.h>
|
||||
|
||||
struct device;
|
||||
struct device_node;
|
||||
@ -35,39 +36,6 @@ enum mtk_ddp_comp_type {
|
||||
MTK_DDP_COMP_TYPE_MAX,
|
||||
};
|
||||
|
||||
enum mtk_ddp_comp_id {
|
||||
DDP_COMPONENT_AAL0,
|
||||
DDP_COMPONENT_AAL1,
|
||||
DDP_COMPONENT_BLS,
|
||||
DDP_COMPONENT_CCORR,
|
||||
DDP_COMPONENT_COLOR0,
|
||||
DDP_COMPONENT_COLOR1,
|
||||
DDP_COMPONENT_DITHER,
|
||||
DDP_COMPONENT_DPI0,
|
||||
DDP_COMPONENT_DPI1,
|
||||
DDP_COMPONENT_DSI0,
|
||||
DDP_COMPONENT_DSI1,
|
||||
DDP_COMPONENT_DSI2,
|
||||
DDP_COMPONENT_DSI3,
|
||||
DDP_COMPONENT_GAMMA,
|
||||
DDP_COMPONENT_OD0,
|
||||
DDP_COMPONENT_OD1,
|
||||
DDP_COMPONENT_OVL0,
|
||||
DDP_COMPONENT_OVL_2L0,
|
||||
DDP_COMPONENT_OVL_2L1,
|
||||
DDP_COMPONENT_OVL1,
|
||||
DDP_COMPONENT_PWM0,
|
||||
DDP_COMPONENT_PWM1,
|
||||
DDP_COMPONENT_PWM2,
|
||||
DDP_COMPONENT_RDMA0,
|
||||
DDP_COMPONENT_RDMA1,
|
||||
DDP_COMPONENT_RDMA2,
|
||||
DDP_COMPONENT_UFOE,
|
||||
DDP_COMPONENT_WDMA0,
|
||||
DDP_COMPONENT_WDMA1,
|
||||
DDP_COMPONENT_ID_MAX,
|
||||
};
|
||||
|
||||
struct mtk_ddp_comp;
|
||||
struct cmdq_pkt;
|
||||
struct mtk_ddp_comp_funcs {
|
||||
|
@ -805,25 +805,6 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
|
||||
ret = of_dma_configure(drm->dev, dev->of_node, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
/*
|
||||
* If we don't have the interconnect property, most likely
|
||||
* because of an old DT, we need to set the DMA offset by hand
|
||||
* on our device since the RAM mapping is at 0 for the DMA bus,
|
||||
* unlike the CPU.
|
||||
*
|
||||
* XXX(hch): this has no business in a driver and needs to move
|
||||
* to the device tree.
|
||||
*
|
||||
* If we have two subsequent calls to dma_direct_set_offset
|
||||
* returns -EINVAL. Unfortunately, this happens when we have two
|
||||
* backends in the system, and will result in the driver
|
||||
* reporting an error while it has been setup properly before.
|
||||
* Ignore EINVAL, but it should really be removed eventually.
|
||||
*/
|
||||
ret = dma_direct_set_offset(drm->dev, PHYS_OFFSET, 0, SZ_4G);
|
||||
if (ret && ret != -EINVAL)
|
||||
return ret;
|
||||
}
|
||||
|
||||
backend->engine.node = dev->of_node;
|
||||
|
@ -30,7 +30,7 @@ static inline u64 __pow10(u8 x)
|
||||
|
||||
static int scmi_hwmon_scale(const struct scmi_sensor_info *sensor, u64 *value)
|
||||
{
|
||||
s8 scale = sensor->scale;
|
||||
int scale = sensor->scale;
|
||||
u64 f;
|
||||
|
||||
switch (sensor->type) {
|
||||
|
@ -167,33 +167,6 @@ static int sun4i_csi_probe(struct platform_device *pdev)
|
||||
if (!csi->traits)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* On Allwinner SoCs, some high memory bandwidth devices do DMA
|
||||
* directly over the memory bus (called MBUS), instead of the
|
||||
* system bus. The memory bus has a different addressing scheme
|
||||
* without the DRAM starting offset.
|
||||
*
|
||||
* In some cases this can be described by an interconnect in
|
||||
* the device tree. In other cases where the hardware is not
|
||||
* fully understood and the interconnect is left out of the
|
||||
* device tree, fall back to a default offset.
|
||||
*/
|
||||
if (of_find_property(csi->dev->of_node, "interconnects", NULL)) {
|
||||
ret = of_dma_configure(csi->dev, csi->dev->of_node, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
/*
|
||||
* XXX(hch): this has no business in a driver and needs to move
|
||||
* to the device tree.
|
||||
*/
|
||||
#ifdef PHYS_PFN_OFFSET
|
||||
ret = dma_direct_set_offset(csi->dev, PHYS_OFFSET, 0, SZ_4G);
|
||||
if (ret)
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
csi->mdev.dev = csi->dev;
|
||||
strscpy(csi->mdev.model, "Allwinner Video Capture Device",
|
||||
sizeof(csi->mdev.model));
|
||||
|
@ -881,14 +881,6 @@ static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* PHYS_OFFSET isn't available on all architectures. In order to
|
||||
* accommodate for COMPILE_TEST, let's define it to something dumb.
|
||||
*/
|
||||
#if defined(CONFIG_COMPILE_TEST) && !defined(PHYS_OFFSET)
|
||||
#define PHYS_OFFSET 0
|
||||
#endif
|
||||
|
||||
static int sun6i_csi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sun6i_csi_dev *sdev;
|
||||
@ -899,15 +891,6 @@ static int sun6i_csi_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
sdev->dev = &pdev->dev;
|
||||
/*
|
||||
* The DMA bus has the memory mapped at 0.
|
||||
*
|
||||
* XXX(hch): this has no business in a driver and needs to move
|
||||
* to the device tree.
|
||||
*/
|
||||
ret = dma_direct_set_offset(sdev->dev, PHYS_OFFSET, 0, SZ_4G);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sun6i_csi_resource_request(sdev, pdev);
|
||||
if (ret)
|
||||
|
@ -825,10 +825,6 @@ static int deinterlace_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = of_dma_configure(dev->dev, dev->dev->of_node, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
dev->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(dev->base))
|
||||
|
@ -128,7 +128,7 @@ config OMAP_GPMC_DEBUG
|
||||
|
||||
config TI_EMIF_SRAM
|
||||
tristate "Texas Instruments EMIF SRAM driver"
|
||||
depends on SOC_AM33XX || SOC_AM43XX || (ARM && COMPILE_TEST)
|
||||
depends on SOC_AM33XX || SOC_AM43XX || (ARM && CPU_V7 && COMPILE_TEST)
|
||||
depends on SRAM
|
||||
help
|
||||
This driver is for the EMIF module available on Texas Instruments
|
||||
@ -191,8 +191,8 @@ config DA8XX_DDRCTL
|
||||
config PL353_SMC
|
||||
tristate "ARM PL35X Static Memory Controller(SMC) driver"
|
||||
default y if ARM
|
||||
depends on ARM
|
||||
depends on ARM_AMBA || COMPILE_TEST
|
||||
depends on ARM || COMPILE_TEST
|
||||
depends on ARM_AMBA
|
||||
help
|
||||
This driver is for the ARM PL351/PL353 Static Memory
|
||||
Controller(SMC) module.
|
||||
|
@ -291,6 +291,8 @@ static int jz4780_nemc_probe(struct platform_device *pdev)
|
||||
nemc->dev = dev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* The driver currently only uses the registers up to offset
|
||||
@ -304,9 +306,9 @@ static int jz4780_nemc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
nemc->base = devm_ioremap(dev, res->start, NEMC_REG_LEN);
|
||||
if (IS_ERR(nemc->base)) {
|
||||
if (!nemc->base) {
|
||||
dev_err(dev, "failed to get I/O memory\n");
|
||||
return PTR_ERR(nemc->base);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
writel(0, nemc->base + NEMC_NFCSR);
|
||||
|
@ -268,6 +268,10 @@ static const struct mtk_smi_larb_gen mtk_smi_larb_mt8183 = {
|
||||
/* IPU0 | IPU1 | CCU */
|
||||
};
|
||||
|
||||
static const struct mtk_smi_larb_gen mtk_smi_larb_mt8192 = {
|
||||
.config_port = mtk_smi_larb_config_port_gen2_general,
|
||||
};
|
||||
|
||||
static const struct of_device_id mtk_smi_larb_of_ids[] = {
|
||||
{
|
||||
.compatible = "mediatek,mt8167-smi-larb",
|
||||
@ -293,6 +297,10 @@ static const struct of_device_id mtk_smi_larb_of_ids[] = {
|
||||
.compatible = "mediatek,mt8183-smi-larb",
|
||||
.data = &mtk_smi_larb_mt8183
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt8192-smi-larb",
|
||||
.data = &mtk_smi_larb_mt8192
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
@ -432,6 +440,13 @@ static const struct mtk_smi_common_plat mtk_smi_common_mt8183 = {
|
||||
F_MMU1_LARB(7),
|
||||
};
|
||||
|
||||
static const struct mtk_smi_common_plat mtk_smi_common_mt8192 = {
|
||||
.gen = MTK_SMI_GEN2,
|
||||
.has_gals = true,
|
||||
.bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(5) |
|
||||
F_MMU1_LARB(6),
|
||||
};
|
||||
|
||||
static const struct of_device_id mtk_smi_common_of_ids[] = {
|
||||
{
|
||||
.compatible = "mediatek,mt8173-smi-common",
|
||||
@ -457,6 +472,10 @@ static const struct of_device_id mtk_smi_common_of_ids[] = {
|
||||
.compatible = "mediatek,mt8183-smi-common",
|
||||
.data = &mtk_smi_common_mt8183,
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt8192-smi-common",
|
||||
.data = &mtk_smi_common_mt8192,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
@ -204,18 +203,6 @@ int rpcif_sw_init(struct rpcif *rpc, struct device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL(rpcif_sw_init);
|
||||
|
||||
void rpcif_enable_rpm(struct rpcif *rpc)
|
||||
{
|
||||
pm_runtime_enable(rpc->dev);
|
||||
}
|
||||
EXPORT_SYMBOL(rpcif_enable_rpm);
|
||||
|
||||
void rpcif_disable_rpm(struct rpcif *rpc)
|
||||
{
|
||||
pm_runtime_put_sync(rpc->dev);
|
||||
}
|
||||
EXPORT_SYMBOL(rpcif_disable_rpm);
|
||||
|
||||
void rpcif_hw_init(struct rpcif *rpc, bool hyperflash)
|
||||
{
|
||||
u32 dummy;
|
||||
@ -508,7 +495,8 @@ exit:
|
||||
return ret;
|
||||
|
||||
err_out:
|
||||
ret = reset_control_reset(rpc->rstc);
|
||||
if (reset_control_reset(rpc->rstc))
|
||||
dev_err(rpc->dev, "Failed to reset HW\n");
|
||||
rpcif_hw_init(rpc, rpc->bus_size == 2);
|
||||
goto exit;
|
||||
}
|
||||
@ -560,9 +548,11 @@ static int rpcif_probe(struct platform_device *pdev)
|
||||
} else if (of_device_is_compatible(flash, "cfi-flash")) {
|
||||
name = "rpc-if-hyperflash";
|
||||
} else {
|
||||
of_node_put(flash);
|
||||
dev_warn(&pdev->dev, "unknown flash type\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
of_node_put(flash);
|
||||
|
||||
vdev = platform_device_alloc(name, pdev->id);
|
||||
if (!vdev)
|
||||
|
@ -3,14 +3,17 @@ config TEGRA_MC
|
||||
bool "NVIDIA Tegra Memory Controller support"
|
||||
default y
|
||||
depends on ARCH_TEGRA
|
||||
select INTERCONNECT
|
||||
help
|
||||
This driver supports the Memory Controller (MC) hardware found on
|
||||
NVIDIA Tegra SoCs.
|
||||
|
||||
config TEGRA20_EMC
|
||||
bool "NVIDIA Tegra20 External Memory Controller driver"
|
||||
tristate "NVIDIA Tegra20 External Memory Controller driver"
|
||||
default y
|
||||
depends on ARCH_TEGRA_2x_SOC
|
||||
depends on TEGRA_MC && ARCH_TEGRA_2x_SOC
|
||||
select DEVFREQ_GOV_SIMPLE_ONDEMAND
|
||||
select PM_DEVFREQ
|
||||
help
|
||||
This driver is for the External Memory Controller (EMC) found on
|
||||
Tegra20 chips. The EMC controls the external DRAM on the board.
|
||||
@ -18,9 +21,10 @@ config TEGRA20_EMC
|
||||
external memory.
|
||||
|
||||
config TEGRA30_EMC
|
||||
bool "NVIDIA Tegra30 External Memory Controller driver"
|
||||
tristate "NVIDIA Tegra30 External Memory Controller driver"
|
||||
default y
|
||||
depends on TEGRA_MC && ARCH_TEGRA_3x_SOC
|
||||
select PM_OPP
|
||||
help
|
||||
This driver is for the External Memory Controller (EMC) found on
|
||||
Tegra30 chips. The EMC controls the external DRAM on the board.
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
@ -42,6 +43,54 @@ static const struct of_device_id tegra_mc_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tegra_mc_of_match);
|
||||
|
||||
static void tegra_mc_devm_action_put_device(void *data)
|
||||
{
|
||||
struct tegra_mc *mc = data;
|
||||
|
||||
put_device(mc->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_tegra_memory_controller_get() - get Tegra Memory Controller handle
|
||||
* @dev: device pointer for the consumer device
|
||||
*
|
||||
* This function will search for the Memory Controller node in a device-tree
|
||||
* and retrieve the Memory Controller handle.
|
||||
*
|
||||
* Return: ERR_PTR() on error or a valid pointer to a struct tegra_mc.
|
||||
*/
|
||||
struct tegra_mc *devm_tegra_memory_controller_get(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct device_node *np;
|
||||
struct tegra_mc *mc;
|
||||
int err;
|
||||
|
||||
np = of_parse_phandle(dev->of_node, "nvidia,memory-controller", 0);
|
||||
if (!np)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
pdev = of_find_device_by_node(np);
|
||||
of_node_put(np);
|
||||
if (!pdev)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
mc = platform_get_drvdata(pdev);
|
||||
if (!mc) {
|
||||
put_device(&pdev->dev);
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
|
||||
err = devm_add_action(dev, tegra_mc_devm_action_put_device, mc);
|
||||
if (err) {
|
||||
put_device(mc->dev);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
return mc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_tegra_memory_controller_get);
|
||||
|
||||
static int tegra_mc_block_dma_common(struct tegra_mc *mc,
|
||||
const struct tegra_mc_reset *rst)
|
||||
{
|
||||
@ -298,6 +347,7 @@ int tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tegra_mc_write_emem_configuration);
|
||||
|
||||
unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc)
|
||||
{
|
||||
@ -309,6 +359,7 @@ unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc)
|
||||
|
||||
return dram_count;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tegra_mc_get_emem_device_count);
|
||||
|
||||
static int load_one_timing(struct tegra_mc *mc,
|
||||
struct tegra_mc_timing *timing,
|
||||
@ -591,6 +642,101 @@ static __maybe_unused irqreturn_t tegra20_mc_irq(int irq, void *data)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Memory Controller (MC) has few Memory Clients that are issuing memory
|
||||
* bandwidth allocation requests to the MC interconnect provider. The MC
|
||||
* provider aggregates the requests and then sends the aggregated request
|
||||
* up to the External Memory Controller (EMC) interconnect provider which
|
||||
* re-configures hardware interface to External Memory (EMEM) in accordance
|
||||
* to the required bandwidth. Each MC interconnect node represents an
|
||||
* individual Memory Client.
|
||||
*
|
||||
* Memory interconnect topology:
|
||||
*
|
||||
* +----+
|
||||
* +--------+ | |
|
||||
* | TEXSRD +--->+ |
|
||||
* +--------+ | |
|
||||
* | | +-----+ +------+
|
||||
* ... | MC +--->+ EMC +--->+ EMEM |
|
||||
* | | +-----+ +------+
|
||||
* +--------+ | |
|
||||
* | DISP.. +--->+ |
|
||||
* +--------+ | |
|
||||
* +----+
|
||||
*/
|
||||
static int tegra_mc_interconnect_setup(struct tegra_mc *mc)
|
||||
{
|
||||
struct icc_node *node;
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
/* older device-trees don't have interconnect properties */
|
||||
if (!device_property_present(mc->dev, "#interconnect-cells") ||
|
||||
!mc->soc->icc_ops)
|
||||
return 0;
|
||||
|
||||
mc->provider.dev = mc->dev;
|
||||
mc->provider.data = &mc->provider;
|
||||
mc->provider.set = mc->soc->icc_ops->set;
|
||||
mc->provider.aggregate = mc->soc->icc_ops->aggregate;
|
||||
mc->provider.xlate_extended = mc->soc->icc_ops->xlate_extended;
|
||||
|
||||
err = icc_provider_add(&mc->provider);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* create Memory Controller node */
|
||||
node = icc_node_create(TEGRA_ICC_MC);
|
||||
if (IS_ERR(node)) {
|
||||
err = PTR_ERR(node);
|
||||
goto del_provider;
|
||||
}
|
||||
|
||||
node->name = "Memory Controller";
|
||||
icc_node_add(node, &mc->provider);
|
||||
|
||||
/* link Memory Controller to External Memory Controller */
|
||||
err = icc_link_create(node, TEGRA_ICC_EMC);
|
||||
if (err)
|
||||
goto remove_nodes;
|
||||
|
||||
for (i = 0; i < mc->soc->num_clients; i++) {
|
||||
/* create MC client node */
|
||||
node = icc_node_create(mc->soc->clients[i].id);
|
||||
if (IS_ERR(node)) {
|
||||
err = PTR_ERR(node);
|
||||
goto remove_nodes;
|
||||
}
|
||||
|
||||
node->name = mc->soc->clients[i].name;
|
||||
icc_node_add(node, &mc->provider);
|
||||
|
||||
/* link Memory Client to Memory Controller */
|
||||
err = icc_link_create(node, TEGRA_ICC_MC);
|
||||
if (err)
|
||||
goto remove_nodes;
|
||||
}
|
||||
|
||||
/*
|
||||
* MC driver is registered too early, so early that generic driver
|
||||
* syncing doesn't work for the MC. But it doesn't really matter
|
||||
* since syncing works for the EMC drivers, hence we can sync the
|
||||
* MC driver by ourselves and then EMC will complete syncing of
|
||||
* the whole ICC state.
|
||||
*/
|
||||
icc_sync_state(mc->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
remove_nodes:
|
||||
icc_nodes_remove(&mc->provider);
|
||||
del_provider:
|
||||
icc_provider_del(&mc->provider);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int tegra_mc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
@ -659,10 +805,8 @@ static int tegra_mc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
mc->irq = platform_get_irq(pdev, 0);
|
||||
if (mc->irq < 0) {
|
||||
dev_err(&pdev->dev, "interrupt not specified\n");
|
||||
if (mc->irq < 0)
|
||||
return mc->irq;
|
||||
}
|
||||
|
||||
WARN(!mc->soc->client_id_mask, "missing client ID mask for this SoC\n");
|
||||
|
||||
@ -681,6 +825,11 @@ static int tegra_mc_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "failed to register reset controller: %d\n",
|
||||
err);
|
||||
|
||||
err = tegra_mc_interconnect_setup(mc);
|
||||
if (err < 0)
|
||||
dev_err(&pdev->dev, "failed to initialize interconnect: %d\n",
|
||||
err);
|
||||
|
||||
if (IS_ENABLED(CONFIG_TEGRA_IOMMU_SMMU) && mc->soc->smmu) {
|
||||
mc->smmu = tegra_smmu_probe(&pdev->dev, mc->soc->smmu, mc);
|
||||
if (IS_ERR(mc->smmu)) {
|
||||
|
@ -78,6 +78,20 @@
|
||||
|
||||
#define MC_TIMING_UPDATE BIT(0)
|
||||
|
||||
static inline u32 tegra_mc_scale_percents(u64 val, unsigned int percents)
|
||||
{
|
||||
val = val * percents;
|
||||
do_div(val, 100);
|
||||
|
||||
return min_t(u64, val, U32_MAX);
|
||||
}
|
||||
|
||||
static inline struct tegra_mc *
|
||||
icc_provider_to_tegra_mc(struct icc_provider *provider)
|
||||
{
|
||||
return container_of(provider, struct tegra_mc, provider);
|
||||
}
|
||||
|
||||
static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset)
|
||||
{
|
||||
return readl_relaxed(mc->regs + offset);
|
||||
@ -115,4 +129,12 @@ extern const struct tegra_mc_soc tegra132_mc_soc;
|
||||
extern const struct tegra_mc_soc tegra210_mc_soc;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These IDs are for internal use of Tegra ICC drivers. The ID numbers are
|
||||
* chosen such that they don't conflict with the device-tree ICC node IDs.
|
||||
*/
|
||||
#define TEGRA_ICC_MC 1000
|
||||
#define TEGRA_ICC_EMC 1001
|
||||
#define TEGRA_ICC_EMEM 1002
|
||||
|
||||
#endif /* MEMORY_TEGRA_MC_H */
|
||||
|
@ -15,6 +15,12 @@ static const struct tegra_mc_client tegra114_mc_clients[] = {
|
||||
.id = 0x00,
|
||||
.name = "ptcr",
|
||||
.swgroup = TEGRA_SWGROUP_PTC,
|
||||
.la = {
|
||||
.reg = 0x34c,
|
||||
.shift = 0,
|
||||
.mask = 0xff,
|
||||
.def = 0x0,
|
||||
},
|
||||
}, {
|
||||
.id = 0x01,
|
||||
.name = "display0a",
|
||||
|
@ -1177,10 +1177,8 @@ static void emc_debugfs_init(struct device *dev, struct tegra_emc *emc)
|
||||
|
||||
static int tegra_emc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct platform_device *mc;
|
||||
struct device_node *np;
|
||||
struct tegra_emc *emc;
|
||||
struct resource *res;
|
||||
u32 ram_code;
|
||||
int err;
|
||||
|
||||
@ -1190,25 +1188,13 @@ static int tegra_emc_probe(struct platform_device *pdev)
|
||||
|
||||
emc->dev = &pdev->dev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
emc->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
emc->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(emc->regs))
|
||||
return PTR_ERR(emc->regs);
|
||||
|
||||
np = of_parse_phandle(pdev->dev.of_node, "nvidia,memory-controller", 0);
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "could not get memory controller\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
mc = of_find_device_by_node(np);
|
||||
of_node_put(np);
|
||||
if (!mc)
|
||||
return -ENOENT;
|
||||
|
||||
emc->mc = platform_get_drvdata(mc);
|
||||
if (!emc->mc)
|
||||
return -EPROBE_DEFER;
|
||||
emc->mc = devm_tegra_memory_controller_get(&pdev->dev);
|
||||
if (IS_ERR(emc->mc))
|
||||
return PTR_ERR(emc->mc);
|
||||
|
||||
ram_code = tegra_read_ram_code();
|
||||
|
||||
|
@ -15,6 +15,12 @@ static const struct tegra_mc_client tegra124_mc_clients[] = {
|
||||
.id = 0x00,
|
||||
.name = "ptcr",
|
||||
.swgroup = TEGRA_SWGROUP_PTC,
|
||||
.la = {
|
||||
.reg = 0x34c,
|
||||
.shift = 0,
|
||||
.mask = 0xff,
|
||||
.def = 0x0,
|
||||
},
|
||||
}, {
|
||||
.id = 0x01,
|
||||
.name = "display0a",
|
||||
|
@ -8,19 +8,27 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/devfreq.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interconnect-provider.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_opp.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sort.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <soc/tegra/common.h>
|
||||
#include <soc/tegra/fuse.h>
|
||||
|
||||
#include "mc.h"
|
||||
|
||||
#define EMC_INTSTATUS 0x000
|
||||
#define EMC_INTMASK 0x004
|
||||
#define EMC_DBG 0x008
|
||||
@ -62,6 +70,11 @@
|
||||
#define EMC_ODT_READ 0x0b4
|
||||
#define EMC_FBIO_CFG5 0x104
|
||||
#define EMC_FBIO_CFG6 0x114
|
||||
#define EMC_STAT_CONTROL 0x160
|
||||
#define EMC_STAT_LLMC_CONTROL 0x178
|
||||
#define EMC_STAT_PWR_CLOCK_LIMIT 0x198
|
||||
#define EMC_STAT_PWR_CLOCKS 0x19c
|
||||
#define EMC_STAT_PWR_COUNT 0x1a0
|
||||
#define EMC_AUTO_CAL_INTERVAL 0x2a8
|
||||
#define EMC_CFG_2 0x2b8
|
||||
#define EMC_CFG_DIG_DLL 0x2bc
|
||||
@ -88,6 +101,12 @@
|
||||
#define EMC_DBG_READ_DQM_CTRL BIT(9)
|
||||
#define EMC_DBG_CFG_PRIORITY BIT(24)
|
||||
|
||||
#define EMC_FBIO_CFG5_DRAM_WIDTH_X16 BIT(4)
|
||||
|
||||
#define EMC_PWR_GATHER_CLEAR (1 << 8)
|
||||
#define EMC_PWR_GATHER_DISABLE (2 << 8)
|
||||
#define EMC_PWR_GATHER_ENABLE (3 << 8)
|
||||
|
||||
static const u16 emc_timing_registers[] = {
|
||||
EMC_RC,
|
||||
EMC_RFC,
|
||||
@ -142,11 +161,26 @@ struct emc_timing {
|
||||
u32 data[ARRAY_SIZE(emc_timing_registers)];
|
||||
};
|
||||
|
||||
enum emc_rate_request_type {
|
||||
EMC_RATE_DEVFREQ,
|
||||
EMC_RATE_DEBUG,
|
||||
EMC_RATE_ICC,
|
||||
EMC_RATE_TYPE_MAX,
|
||||
};
|
||||
|
||||
struct emc_rate_request {
|
||||
unsigned long min_rate;
|
||||
unsigned long max_rate;
|
||||
};
|
||||
|
||||
struct tegra_emc {
|
||||
struct device *dev;
|
||||
struct tegra_mc *mc;
|
||||
struct icc_provider provider;
|
||||
struct notifier_block clk_nb;
|
||||
struct clk *clk;
|
||||
void __iomem *regs;
|
||||
unsigned int dram_bus_width;
|
||||
|
||||
struct emc_timing *timings;
|
||||
unsigned int num_timings;
|
||||
@ -156,6 +190,17 @@ struct tegra_emc {
|
||||
unsigned long min_rate;
|
||||
unsigned long max_rate;
|
||||
} debugfs;
|
||||
|
||||
/*
|
||||
* There are multiple sources in the EMC driver which could request
|
||||
* a min/max clock rate, these rates are contained in this array.
|
||||
*/
|
||||
struct emc_rate_request requested_rate[EMC_RATE_TYPE_MAX];
|
||||
|
||||
/* protect shared rate-change code path */
|
||||
struct mutex rate_lock;
|
||||
|
||||
struct devfreq_simple_ondemand_data ondemand_data;
|
||||
};
|
||||
|
||||
static irqreturn_t tegra_emc_isr(int irq, void *data)
|
||||
@ -383,6 +428,11 @@ tegra_emc_find_node_by_ram_code(struct device *dev)
|
||||
u32 value, ram_code;
|
||||
int err;
|
||||
|
||||
if (of_get_child_count(dev->of_node) == 0) {
|
||||
dev_info(dev, "device-tree doesn't have memory timings\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!of_property_read_bool(dev->of_node, "nvidia,use-ram-code"))
|
||||
return of_node_get(dev->of_node);
|
||||
|
||||
@ -408,7 +458,7 @@ tegra_emc_find_node_by_ram_code(struct device *dev)
|
||||
static int emc_setup_hw(struct tegra_emc *emc)
|
||||
{
|
||||
u32 intmask = EMC_REFRESH_OVERFLOW_INT;
|
||||
u32 emc_cfg, emc_dbg;
|
||||
u32 emc_cfg, emc_dbg, emc_fbio;
|
||||
|
||||
emc_cfg = readl_relaxed(emc->regs + EMC_CFG_2);
|
||||
|
||||
@ -439,6 +489,15 @@ static int emc_setup_hw(struct tegra_emc *emc)
|
||||
emc_dbg &= ~EMC_DBG_FORCE_UPDATE;
|
||||
writel_relaxed(emc_dbg, emc->regs + EMC_DBG);
|
||||
|
||||
emc_fbio = readl_relaxed(emc->regs + EMC_FBIO_CFG5);
|
||||
|
||||
if (emc_fbio & EMC_FBIO_CFG5_DRAM_WIDTH_X16)
|
||||
emc->dram_bus_width = 16;
|
||||
else
|
||||
emc->dram_bus_width = 32;
|
||||
|
||||
dev_info(emc->dev, "%ubit DRAM bus\n", emc->dram_bus_width);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -451,6 +510,9 @@ static long emc_round_rate(unsigned long rate,
|
||||
struct tegra_emc *emc = arg;
|
||||
unsigned int i;
|
||||
|
||||
if (!emc->num_timings)
|
||||
return clk_get_rate(emc->clk);
|
||||
|
||||
min_rate = min(min_rate, emc->timings[emc->num_timings - 1].rate);
|
||||
|
||||
for (i = 0; i < emc->num_timings; i++) {
|
||||
@ -480,6 +542,83 @@ static long emc_round_rate(unsigned long rate,
|
||||
return timing->rate;
|
||||
}
|
||||
|
||||
static void tegra_emc_rate_requests_init(struct tegra_emc *emc)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < EMC_RATE_TYPE_MAX; i++) {
|
||||
emc->requested_rate[i].min_rate = 0;
|
||||
emc->requested_rate[i].max_rate = ULONG_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
static int emc_request_rate(struct tegra_emc *emc,
|
||||
unsigned long new_min_rate,
|
||||
unsigned long new_max_rate,
|
||||
enum emc_rate_request_type type)
|
||||
{
|
||||
struct emc_rate_request *req = emc->requested_rate;
|
||||
unsigned long min_rate = 0, max_rate = ULONG_MAX;
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
/* select minimum and maximum rates among the requested rates */
|
||||
for (i = 0; i < EMC_RATE_TYPE_MAX; i++, req++) {
|
||||
if (i == type) {
|
||||
min_rate = max(new_min_rate, min_rate);
|
||||
max_rate = min(new_max_rate, max_rate);
|
||||
} else {
|
||||
min_rate = max(req->min_rate, min_rate);
|
||||
max_rate = min(req->max_rate, max_rate);
|
||||
}
|
||||
}
|
||||
|
||||
if (min_rate > max_rate) {
|
||||
dev_err_ratelimited(emc->dev, "%s: type %u: out of range: %lu %lu\n",
|
||||
__func__, type, min_rate, max_rate);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/*
|
||||
* EMC rate-changes should go via OPP API because it manages voltage
|
||||
* changes.
|
||||
*/
|
||||
err = dev_pm_opp_set_rate(emc->dev, min_rate);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
emc->requested_rate[type].min_rate = new_min_rate;
|
||||
emc->requested_rate[type].max_rate = new_max_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emc_set_min_rate(struct tegra_emc *emc, unsigned long rate,
|
||||
enum emc_rate_request_type type)
|
||||
{
|
||||
struct emc_rate_request *req = &emc->requested_rate[type];
|
||||
int ret;
|
||||
|
||||
mutex_lock(&emc->rate_lock);
|
||||
ret = emc_request_rate(emc, rate, req->max_rate, type);
|
||||
mutex_unlock(&emc->rate_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int emc_set_max_rate(struct tegra_emc *emc, unsigned long rate,
|
||||
enum emc_rate_request_type type)
|
||||
{
|
||||
struct emc_rate_request *req = &emc->requested_rate[type];
|
||||
int ret;
|
||||
|
||||
mutex_lock(&emc->rate_lock);
|
||||
ret = emc_request_rate(emc, req->min_rate, rate, type);
|
||||
mutex_unlock(&emc->rate_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* debugfs interface
|
||||
*
|
||||
@ -563,7 +702,7 @@ static int tegra_emc_debug_min_rate_set(void *data, u64 rate)
|
||||
if (!tegra_emc_validate_rate(emc, rate))
|
||||
return -EINVAL;
|
||||
|
||||
err = clk_set_min_rate(emc->clk, rate);
|
||||
err = emc_set_min_rate(emc, rate, EMC_RATE_DEBUG);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
@ -593,7 +732,7 @@ static int tegra_emc_debug_max_rate_set(void *data, u64 rate)
|
||||
if (!tegra_emc_validate_rate(emc, rate))
|
||||
return -EINVAL;
|
||||
|
||||
err = clk_set_max_rate(emc->clk, rate);
|
||||
err = emc_set_max_rate(emc, rate, EMC_RATE_DEBUG);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
@ -650,47 +789,330 @@ static void tegra_emc_debugfs_init(struct tegra_emc *emc)
|
||||
emc, &tegra_emc_debug_max_rate_fops);
|
||||
}
|
||||
|
||||
static inline struct tegra_emc *
|
||||
to_tegra_emc_provider(struct icc_provider *provider)
|
||||
{
|
||||
return container_of(provider, struct tegra_emc, provider);
|
||||
}
|
||||
|
||||
static struct icc_node_data *
|
||||
emc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
|
||||
{
|
||||
struct icc_provider *provider = data;
|
||||
struct icc_node_data *ndata;
|
||||
struct icc_node *node;
|
||||
|
||||
/* External Memory is the only possible ICC route */
|
||||
list_for_each_entry(node, &provider->nodes, node_list) {
|
||||
if (node->id != TEGRA_ICC_EMEM)
|
||||
continue;
|
||||
|
||||
ndata = kzalloc(sizeof(*ndata), GFP_KERNEL);
|
||||
if (!ndata)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/*
|
||||
* SRC and DST nodes should have matching TAG in order to have
|
||||
* it set by default for a requested path.
|
||||
*/
|
||||
ndata->tag = TEGRA_MC_ICC_TAG_ISO;
|
||||
ndata->node = node;
|
||||
|
||||
return ndata;
|
||||
}
|
||||
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
|
||||
static int emc_icc_set(struct icc_node *src, struct icc_node *dst)
|
||||
{
|
||||
struct tegra_emc *emc = to_tegra_emc_provider(dst->provider);
|
||||
unsigned long long peak_bw = icc_units_to_bps(dst->peak_bw);
|
||||
unsigned long long avg_bw = icc_units_to_bps(dst->avg_bw);
|
||||
unsigned long long rate = max(avg_bw, peak_bw);
|
||||
unsigned int dram_data_bus_width_bytes;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* Tegra20 EMC runs on x2 clock rate of SDRAM bus because DDR data
|
||||
* is sampled on both clock edges. This means that EMC clock rate
|
||||
* equals to the peak data-rate.
|
||||
*/
|
||||
dram_data_bus_width_bytes = emc->dram_bus_width / 8;
|
||||
do_div(rate, dram_data_bus_width_bytes);
|
||||
rate = min_t(u64, rate, U32_MAX);
|
||||
|
||||
err = emc_set_min_rate(emc, rate, EMC_RATE_ICC);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_emc_interconnect_init(struct tegra_emc *emc)
|
||||
{
|
||||
const struct tegra_mc_soc *soc;
|
||||
struct icc_node *node;
|
||||
int err;
|
||||
|
||||
emc->mc = devm_tegra_memory_controller_get(emc->dev);
|
||||
if (IS_ERR(emc->mc))
|
||||
return PTR_ERR(emc->mc);
|
||||
|
||||
soc = emc->mc->soc;
|
||||
|
||||
emc->provider.dev = emc->dev;
|
||||
emc->provider.set = emc_icc_set;
|
||||
emc->provider.data = &emc->provider;
|
||||
emc->provider.aggregate = soc->icc_ops->aggregate;
|
||||
emc->provider.xlate_extended = emc_of_icc_xlate_extended;
|
||||
|
||||
err = icc_provider_add(&emc->provider);
|
||||
if (err)
|
||||
goto err_msg;
|
||||
|
||||
/* create External Memory Controller node */
|
||||
node = icc_node_create(TEGRA_ICC_EMC);
|
||||
if (IS_ERR(node)) {
|
||||
err = PTR_ERR(node);
|
||||
goto del_provider;
|
||||
}
|
||||
|
||||
node->name = "External Memory Controller";
|
||||
icc_node_add(node, &emc->provider);
|
||||
|
||||
/* link External Memory Controller to External Memory (DRAM) */
|
||||
err = icc_link_create(node, TEGRA_ICC_EMEM);
|
||||
if (err)
|
||||
goto remove_nodes;
|
||||
|
||||
/* create External Memory node */
|
||||
node = icc_node_create(TEGRA_ICC_EMEM);
|
||||
if (IS_ERR(node)) {
|
||||
err = PTR_ERR(node);
|
||||
goto remove_nodes;
|
||||
}
|
||||
|
||||
node->name = "External Memory (DRAM)";
|
||||
icc_node_add(node, &emc->provider);
|
||||
|
||||
return 0;
|
||||
|
||||
remove_nodes:
|
||||
icc_nodes_remove(&emc->provider);
|
||||
del_provider:
|
||||
icc_provider_del(&emc->provider);
|
||||
err_msg:
|
||||
dev_err(emc->dev, "failed to initialize ICC: %d\n", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int tegra_emc_opp_table_init(struct tegra_emc *emc)
|
||||
{
|
||||
u32 hw_version = BIT(tegra_sku_info.soc_process_id);
|
||||
struct opp_table *clk_opp_table, *hw_opp_table;
|
||||
int err;
|
||||
|
||||
clk_opp_table = dev_pm_opp_set_clkname(emc->dev, NULL);
|
||||
err = PTR_ERR_OR_ZERO(clk_opp_table);
|
||||
if (err) {
|
||||
dev_err(emc->dev, "failed to set OPP clk: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
hw_opp_table = dev_pm_opp_set_supported_hw(emc->dev, &hw_version, 1);
|
||||
err = PTR_ERR_OR_ZERO(hw_opp_table);
|
||||
if (err) {
|
||||
dev_err(emc->dev, "failed to set OPP supported HW: %d\n", err);
|
||||
goto put_clk_table;
|
||||
}
|
||||
|
||||
err = dev_pm_opp_of_add_table(emc->dev);
|
||||
if (err) {
|
||||
if (err == -ENODEV)
|
||||
dev_err(emc->dev, "OPP table not found, please update your device tree\n");
|
||||
else
|
||||
dev_err(emc->dev, "failed to add OPP table: %d\n", err);
|
||||
|
||||
goto put_hw_table;
|
||||
}
|
||||
|
||||
dev_info(emc->dev, "OPP HW ver. 0x%x, current clock rate %lu MHz\n",
|
||||
hw_version, clk_get_rate(emc->clk) / 1000000);
|
||||
|
||||
/* first dummy rate-set initializes voltage state */
|
||||
err = dev_pm_opp_set_rate(emc->dev, clk_get_rate(emc->clk));
|
||||
if (err) {
|
||||
dev_err(emc->dev, "failed to initialize OPP clock: %d\n", err);
|
||||
goto remove_table;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
remove_table:
|
||||
dev_pm_opp_of_remove_table(emc->dev);
|
||||
put_hw_table:
|
||||
dev_pm_opp_put_supported_hw(hw_opp_table);
|
||||
put_clk_table:
|
||||
dev_pm_opp_put_clkname(clk_opp_table);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void devm_tegra_emc_unset_callback(void *data)
|
||||
{
|
||||
tegra20_clk_set_emc_round_callback(NULL, NULL);
|
||||
}
|
||||
|
||||
static void devm_tegra_emc_unreg_clk_notifier(void *data)
|
||||
{
|
||||
struct tegra_emc *emc = data;
|
||||
|
||||
clk_notifier_unregister(emc->clk, &emc->clk_nb);
|
||||
}
|
||||
|
||||
static int tegra_emc_init_clk(struct tegra_emc *emc)
|
||||
{
|
||||
int err;
|
||||
|
||||
tegra20_clk_set_emc_round_callback(emc_round_rate, emc);
|
||||
|
||||
err = devm_add_action_or_reset(emc->dev, devm_tegra_emc_unset_callback,
|
||||
NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
emc->clk = devm_clk_get(emc->dev, NULL);
|
||||
if (IS_ERR(emc->clk)) {
|
||||
dev_err(emc->dev, "failed to get EMC clock: %pe\n", emc->clk);
|
||||
return PTR_ERR(emc->clk);
|
||||
}
|
||||
|
||||
err = clk_notifier_register(emc->clk, &emc->clk_nb);
|
||||
if (err) {
|
||||
dev_err(emc->dev, "failed to register clk notifier: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = devm_add_action_or_reset(emc->dev,
|
||||
devm_tegra_emc_unreg_clk_notifier, emc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_emc_devfreq_target(struct device *dev, unsigned long *freq,
|
||||
u32 flags)
|
||||
{
|
||||
struct tegra_emc *emc = dev_get_drvdata(dev);
|
||||
struct dev_pm_opp *opp;
|
||||
unsigned long rate;
|
||||
|
||||
opp = devfreq_recommended_opp(dev, freq, flags);
|
||||
if (IS_ERR(opp)) {
|
||||
dev_err(dev, "failed to find opp for %lu Hz\n", *freq);
|
||||
return PTR_ERR(opp);
|
||||
}
|
||||
|
||||
rate = dev_pm_opp_get_freq(opp);
|
||||
dev_pm_opp_put(opp);
|
||||
|
||||
return emc_set_min_rate(emc, rate, EMC_RATE_DEVFREQ);
|
||||
}
|
||||
|
||||
static int tegra_emc_devfreq_get_dev_status(struct device *dev,
|
||||
struct devfreq_dev_status *stat)
|
||||
{
|
||||
struct tegra_emc *emc = dev_get_drvdata(dev);
|
||||
|
||||
/* freeze counters */
|
||||
writel_relaxed(EMC_PWR_GATHER_DISABLE, emc->regs + EMC_STAT_CONTROL);
|
||||
|
||||
/*
|
||||
* busy_time: number of clocks EMC request was accepted
|
||||
* total_time: number of clocks PWR_GATHER control was set to ENABLE
|
||||
*/
|
||||
stat->busy_time = readl_relaxed(emc->regs + EMC_STAT_PWR_COUNT);
|
||||
stat->total_time = readl_relaxed(emc->regs + EMC_STAT_PWR_CLOCKS);
|
||||
stat->current_frequency = clk_get_rate(emc->clk);
|
||||
|
||||
/* clear counters and restart */
|
||||
writel_relaxed(EMC_PWR_GATHER_CLEAR, emc->regs + EMC_STAT_CONTROL);
|
||||
writel_relaxed(EMC_PWR_GATHER_ENABLE, emc->regs + EMC_STAT_CONTROL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct devfreq_dev_profile tegra_emc_devfreq_profile = {
|
||||
.polling_ms = 30,
|
||||
.target = tegra_emc_devfreq_target,
|
||||
.get_dev_status = tegra_emc_devfreq_get_dev_status,
|
||||
};
|
||||
|
||||
static int tegra_emc_devfreq_init(struct tegra_emc *emc)
|
||||
{
|
||||
struct devfreq *devfreq;
|
||||
|
||||
/*
|
||||
* PWR_COUNT is 1/2 of PWR_CLOCKS at max, and thus, the up-threshold
|
||||
* should be less than 50. Secondly, multiple active memory clients
|
||||
* may cause over 20% of lost clock cycles due to stalls caused by
|
||||
* competing memory accesses. This means that threshold should be
|
||||
* set to a less than 30 in order to have a properly working governor.
|
||||
*/
|
||||
emc->ondemand_data.upthreshold = 20;
|
||||
|
||||
/*
|
||||
* Reset statistic gathers state, select global bandwidth for the
|
||||
* statistics collection mode and set clocks counter saturation
|
||||
* limit to maximum.
|
||||
*/
|
||||
writel_relaxed(0x00000000, emc->regs + EMC_STAT_CONTROL);
|
||||
writel_relaxed(0x00000000, emc->regs + EMC_STAT_LLMC_CONTROL);
|
||||
writel_relaxed(0xffffffff, emc->regs + EMC_STAT_PWR_CLOCK_LIMIT);
|
||||
|
||||
devfreq = devm_devfreq_add_device(emc->dev, &tegra_emc_devfreq_profile,
|
||||
DEVFREQ_GOV_SIMPLE_ONDEMAND,
|
||||
&emc->ondemand_data);
|
||||
if (IS_ERR(devfreq)) {
|
||||
dev_err(emc->dev, "failed to initialize devfreq: %pe", devfreq);
|
||||
return PTR_ERR(devfreq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_emc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np;
|
||||
struct tegra_emc *emc;
|
||||
struct resource *res;
|
||||
int irq, err;
|
||||
|
||||
/* driver has nothing to do in a case of memory timing absence */
|
||||
if (of_get_child_count(pdev->dev.of_node) == 0) {
|
||||
dev_info(&pdev->dev,
|
||||
"EMC device tree node doesn't have memory timings\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "interrupt not specified\n");
|
||||
dev_err(&pdev->dev, "please update your device tree\n");
|
||||
return irq;
|
||||
}
|
||||
|
||||
np = tegra_emc_find_node_by_ram_code(&pdev->dev);
|
||||
if (!np)
|
||||
return -EINVAL;
|
||||
|
||||
emc = devm_kzalloc(&pdev->dev, sizeof(*emc), GFP_KERNEL);
|
||||
if (!emc) {
|
||||
of_node_put(np);
|
||||
if (!emc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mutex_init(&emc->rate_lock);
|
||||
emc->clk_nb.notifier_call = tegra_emc_clk_change_notify;
|
||||
emc->dev = &pdev->dev;
|
||||
|
||||
err = tegra_emc_load_timings_from_dt(emc, np);
|
||||
of_node_put(np);
|
||||
if (err)
|
||||
return err;
|
||||
np = tegra_emc_find_node_by_ram_code(&pdev->dev);
|
||||
if (np) {
|
||||
err = tegra_emc_load_timings_from_dt(emc, np);
|
||||
of_node_put(np);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
emc->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
emc->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(emc->regs))
|
||||
return PTR_ERR(emc->regs);
|
||||
|
||||
@ -701,41 +1123,39 @@ static int tegra_emc_probe(struct platform_device *pdev)
|
||||
err = devm_request_irq(&pdev->dev, irq, tegra_emc_isr, 0,
|
||||
dev_name(&pdev->dev), emc);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", irq, err);
|
||||
dev_err(&pdev->dev, "failed to request IRQ: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
tegra20_clk_set_emc_round_callback(emc_round_rate, emc);
|
||||
err = tegra_emc_init_clk(emc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
emc->clk = devm_clk_get(&pdev->dev, "emc");
|
||||
if (IS_ERR(emc->clk)) {
|
||||
err = PTR_ERR(emc->clk);
|
||||
dev_err(&pdev->dev, "failed to get emc clock: %d\n", err);
|
||||
goto unset_cb;
|
||||
}
|
||||
|
||||
err = clk_notifier_register(emc->clk, &emc->clk_nb);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to register clk notifier: %d\n",
|
||||
err);
|
||||
goto unset_cb;
|
||||
}
|
||||
err = tegra_emc_opp_table_init(emc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
platform_set_drvdata(pdev, emc);
|
||||
tegra_emc_rate_requests_init(emc);
|
||||
tegra_emc_debugfs_init(emc);
|
||||
tegra_emc_interconnect_init(emc);
|
||||
tegra_emc_devfreq_init(emc);
|
||||
|
||||
/*
|
||||
* Don't allow the kernel module to be unloaded. Unloading adds some
|
||||
* extra complexity which doesn't really worth the effort in a case of
|
||||
* this driver.
|
||||
*/
|
||||
try_module_get(THIS_MODULE);
|
||||
|
||||
return 0;
|
||||
|
||||
unset_cb:
|
||||
tegra20_clk_set_emc_round_callback(NULL, NULL);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct of_device_id tegra_emc_of_match[] = {
|
||||
{ .compatible = "nvidia,tegra20-emc", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tegra_emc_of_match);
|
||||
|
||||
static struct platform_driver tegra_emc_driver = {
|
||||
.probe = tegra_emc_probe,
|
||||
@ -743,11 +1163,11 @@ static struct platform_driver tegra_emc_driver = {
|
||||
.name = "tegra20-emc",
|
||||
.of_match_table = tegra_emc_of_match,
|
||||
.suppress_bind_attrs = true,
|
||||
.sync_state = icc_sync_state,
|
||||
},
|
||||
};
|
||||
module_platform_driver(tegra_emc_driver);
|
||||
|
||||
static int __init tegra_emc_init(void)
|
||||
{
|
||||
return platform_driver_register(&tegra_emc_driver);
|
||||
}
|
||||
subsys_initcall(tegra_emc_init);
|
||||
MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>");
|
||||
MODULE_DESCRIPTION("NVIDIA Tegra20 EMC driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -3,6 +3,10 @@
|
||||
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <dt-bindings/memory/tegra20-mc.h>
|
||||
|
||||
#include "mc.h"
|
||||
@ -280,6 +284,78 @@ static const struct tegra_mc_reset_ops tegra20_mc_reset_ops = {
|
||||
.reset_status = tegra20_mc_reset_status,
|
||||
};
|
||||
|
||||
static int tegra20_mc_icc_set(struct icc_node *src, struct icc_node *dst)
|
||||
{
|
||||
/*
|
||||
* It should be possible to tune arbitration knobs here, but the
|
||||
* default values are known to work well on all devices. Hence
|
||||
* nothing to do here so far.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra20_mc_icc_aggreate(struct icc_node *node, u32 tag, u32 avg_bw,
|
||||
u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
|
||||
{
|
||||
/*
|
||||
* ISO clients need to reserve extra bandwidth up-front because
|
||||
* there could be high bandwidth pressure during initial filling
|
||||
* of the client's FIFO buffers. Secondly, we need to take into
|
||||
* account impurities of the memory subsystem.
|
||||
*/
|
||||
if (tag & TEGRA_MC_ICC_TAG_ISO)
|
||||
peak_bw = tegra_mc_scale_percents(peak_bw, 300);
|
||||
|
||||
*agg_avg += avg_bw;
|
||||
*agg_peak = max(*agg_peak, peak_bw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct icc_node_data *
|
||||
tegra20_mc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
|
||||
{
|
||||
struct tegra_mc *mc = icc_provider_to_tegra_mc(data);
|
||||
unsigned int i, idx = spec->args[0];
|
||||
struct icc_node_data *ndata;
|
||||
struct icc_node *node;
|
||||
|
||||
list_for_each_entry(node, &mc->provider.nodes, node_list) {
|
||||
if (node->id != idx)
|
||||
continue;
|
||||
|
||||
ndata = kzalloc(sizeof(*ndata), GFP_KERNEL);
|
||||
if (!ndata)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ndata->node = node;
|
||||
|
||||
/* these clients are isochronous by default */
|
||||
if (strstarts(node->name, "display") ||
|
||||
strstarts(node->name, "vi"))
|
||||
ndata->tag = TEGRA_MC_ICC_TAG_ISO;
|
||||
else
|
||||
ndata->tag = TEGRA_MC_ICC_TAG_DEFAULT;
|
||||
|
||||
return ndata;
|
||||
}
|
||||
|
||||
for (i = 0; i < mc->soc->num_clients; i++) {
|
||||
if (mc->soc->clients[i].id == idx)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
|
||||
dev_err(mc->dev, "invalid ICC client ID %u\n", idx);
|
||||
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
static const struct tegra_mc_icc_ops tegra20_mc_icc_ops = {
|
||||
.xlate_extended = tegra20_mc_of_icc_xlate_extended,
|
||||
.aggregate = tegra20_mc_icc_aggreate,
|
||||
.set = tegra20_mc_icc_set,
|
||||
};
|
||||
|
||||
const struct tegra_mc_soc tegra20_mc_soc = {
|
||||
.clients = tegra20_mc_clients,
|
||||
.num_clients = ARRAY_SIZE(tegra20_mc_clients),
|
||||
@ -290,4 +366,5 @@ const struct tegra_mc_soc tegra20_mc_soc = {
|
||||
.reset_ops = &tegra20_mc_reset_ops,
|
||||
.resets = tegra20_mc_resets,
|
||||
.num_resets = ARRAY_SIZE(tegra20_mc_resets),
|
||||
.icc_ops = &tegra20_mc_icc_ops,
|
||||
};
|
||||
|
@ -1828,7 +1828,6 @@ static int tegra210_emc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct thermal_cooling_device *cd;
|
||||
unsigned long current_rate;
|
||||
struct platform_device *mc;
|
||||
struct tegra210_emc *emc;
|
||||
struct device_node *np;
|
||||
unsigned int i;
|
||||
@ -1846,35 +1845,19 @@ static int tegra210_emc_probe(struct platform_device *pdev)
|
||||
spin_lock_init(&emc->lock);
|
||||
emc->dev = &pdev->dev;
|
||||
|
||||
np = of_parse_phandle(pdev->dev.of_node, "nvidia,memory-controller", 0);
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "could not get memory controller\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
mc = of_find_device_by_node(np);
|
||||
of_node_put(np);
|
||||
if (!mc)
|
||||
return -ENOENT;
|
||||
|
||||
emc->mc = platform_get_drvdata(mc);
|
||||
if (!emc->mc) {
|
||||
put_device(&mc->dev);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
emc->mc = devm_tegra_memory_controller_get(&pdev->dev);
|
||||
if (IS_ERR(emc->mc))
|
||||
return PTR_ERR(emc->mc);
|
||||
|
||||
emc->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(emc->regs)) {
|
||||
err = PTR_ERR(emc->regs);
|
||||
goto put_mc;
|
||||
}
|
||||
if (IS_ERR(emc->regs))
|
||||
return PTR_ERR(emc->regs);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
emc->channel[i] = devm_platform_ioremap_resource(pdev, 1 + i);
|
||||
if (IS_ERR(emc->channel[i])) {
|
||||
err = PTR_ERR(emc->channel[i]);
|
||||
goto put_mc;
|
||||
}
|
||||
if (IS_ERR(emc->channel[i]))
|
||||
return PTR_ERR(emc->channel[i]);
|
||||
|
||||
}
|
||||
|
||||
tegra210_emc_detect(emc);
|
||||
@ -1884,7 +1867,7 @@ static int tegra210_emc_probe(struct platform_device *pdev)
|
||||
err = of_reserved_mem_device_init_by_name(emc->dev, np, "nominal");
|
||||
if (err < 0) {
|
||||
dev_err(emc->dev, "failed to get nominal EMC table: %d\n", err);
|
||||
goto put_mc;
|
||||
return err;
|
||||
}
|
||||
|
||||
err = of_reserved_mem_device_init_by_name(emc->dev, np, "derated");
|
||||
@ -2015,8 +1998,7 @@ detach:
|
||||
tegra210_clk_emc_detach(emc->clk);
|
||||
release:
|
||||
of_reserved_mem_device_release(emc->dev);
|
||||
put_mc:
|
||||
put_device(emc->mc->dev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -2027,7 +2009,6 @@ static int tegra210_emc_remove(struct platform_device *pdev)
|
||||
debugfs_remove_recursive(emc->debugfs.root);
|
||||
tegra210_clk_emc_detach(emc->clk);
|
||||
of_reserved_mem_device_release(emc->dev);
|
||||
put_device(emc->mc->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = {
|
||||
.reg = 0x2e8,
|
||||
.shift = 0,
|
||||
.mask = 0xff,
|
||||
.def = 0xc2,
|
||||
.def = 0x1e,
|
||||
},
|
||||
}, {
|
||||
.id = 0x02,
|
||||
@ -38,7 +38,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = {
|
||||
.reg = 0x2f4,
|
||||
.shift = 0,
|
||||
.mask = 0xff,
|
||||
.def = 0xc6,
|
||||
.def = 0x1e,
|
||||
},
|
||||
}, {
|
||||
.id = 0x03,
|
||||
@ -52,7 +52,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = {
|
||||
.reg = 0x2e8,
|
||||
.shift = 16,
|
||||
.mask = 0xff,
|
||||
.def = 0x50,
|
||||
.def = 0x1e,
|
||||
},
|
||||
}, {
|
||||
.id = 0x04,
|
||||
@ -66,7 +66,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = {
|
||||
.reg = 0x2f4,
|
||||
.shift = 16,
|
||||
.mask = 0xff,
|
||||
.def = 0x50,
|
||||
.def = 0x1e,
|
||||
},
|
||||
}, {
|
||||
.id = 0x05,
|
||||
@ -80,7 +80,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = {
|
||||
.reg = 0x2ec,
|
||||
.shift = 0,
|
||||
.mask = 0xff,
|
||||
.def = 0x50,
|
||||
.def = 0x1e,
|
||||
},
|
||||
}, {
|
||||
.id = 0x06,
|
||||
@ -94,7 +94,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = {
|
||||
.reg = 0x2f8,
|
||||
.shift = 0,
|
||||
.mask = 0xff,
|
||||
.def = 0x50,
|
||||
.def = 0x1e,
|
||||
},
|
||||
}, {
|
||||
.id = 0x0e,
|
||||
@ -108,7 +108,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = {
|
||||
.reg = 0x2e0,
|
||||
.shift = 0,
|
||||
.mask = 0xff,
|
||||
.def = 0x13,
|
||||
.def = 0x2e,
|
||||
},
|
||||
}, {
|
||||
.id = 0x0f,
|
||||
@ -136,7 +136,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = {
|
||||
.reg = 0x2f0,
|
||||
.shift = 0,
|
||||
.mask = 0xff,
|
||||
.def = 0x50,
|
||||
.def = 0x1e,
|
||||
},
|
||||
}, {
|
||||
.id = 0x11,
|
||||
@ -150,7 +150,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = {
|
||||
.reg = 0x2fc,
|
||||
.shift = 0,
|
||||
.mask = 0xff,
|
||||
.def = 0x50,
|
||||
.def = 0x1e,
|
||||
},
|
||||
}, {
|
||||
.id = 0x15,
|
||||
@ -380,7 +380,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = {
|
||||
.reg = 0x350,
|
||||
.shift = 16,
|
||||
.mask = 0xff,
|
||||
.def = 0x65,
|
||||
.def = 0x80,
|
||||
},
|
||||
}, {
|
||||
.id = 0x44,
|
||||
@ -620,7 +620,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = {
|
||||
.reg = 0x2f0,
|
||||
.shift = 16,
|
||||
.mask = 0xff,
|
||||
.def = 0x50,
|
||||
.def = 0x1e,
|
||||
},
|
||||
}, {
|
||||
.id = 0x60,
|
||||
@ -648,7 +648,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = {
|
||||
.reg = 0x3bc,
|
||||
.shift = 0,
|
||||
.mask = 0xff,
|
||||
.def = 0x49,
|
||||
.def = 0x5a,
|
||||
},
|
||||
}, {
|
||||
.id = 0x62,
|
||||
@ -676,7 +676,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = {
|
||||
.reg = 0x3c4,
|
||||
.shift = 0,
|
||||
.mask = 0xff,
|
||||
.def = 0x49,
|
||||
.def = 0x5a,
|
||||
},
|
||||
}, {
|
||||
.id = 0x64,
|
||||
@ -897,7 +897,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = {
|
||||
.bit = 1,
|
||||
},
|
||||
.la = {
|
||||
.reg = 0xb98,
|
||||
.reg = 0x3e0,
|
||||
.shift = 16,
|
||||
.mask = 0xff,
|
||||
.def = 0x80,
|
||||
@ -956,7 +956,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = {
|
||||
.reg = 0x3ec,
|
||||
.shift = 16,
|
||||
.mask = 0xff,
|
||||
.def = 0xff,
|
||||
.def = 0x80,
|
||||
},
|
||||
}, {
|
||||
.id = 0x86,
|
||||
@ -1020,35 +1020,45 @@ static const struct tegra_mc_client tegra210_mc_clients[] = {
|
||||
};
|
||||
|
||||
static const struct tegra_smmu_swgroup tegra210_swgroups[] = {
|
||||
{ .name = "dc", .swgroup = TEGRA_SWGROUP_DC, .reg = 0x240 },
|
||||
{ .name = "dcb", .swgroup = TEGRA_SWGROUP_DCB, .reg = 0x244 },
|
||||
{ .name = "afi", .swgroup = TEGRA_SWGROUP_AFI, .reg = 0x238 },
|
||||
{ .name = "avpc", .swgroup = TEGRA_SWGROUP_AVPC, .reg = 0x23c },
|
||||
{ .name = "hda", .swgroup = TEGRA_SWGROUP_HDA, .reg = 0x254 },
|
||||
{ .name = "dc", .swgroup = TEGRA_SWGROUP_DC, .reg = 0x240 },
|
||||
{ .name = "dcb", .swgroup = TEGRA_SWGROUP_DCB, .reg = 0x244 },
|
||||
{ .name = "hc", .swgroup = TEGRA_SWGROUP_HC, .reg = 0x250 },
|
||||
{ .name = "hda", .swgroup = TEGRA_SWGROUP_HDA, .reg = 0x254 },
|
||||
{ .name = "isp2", .swgroup = TEGRA_SWGROUP_ISP2, .reg = 0x258 },
|
||||
{ .name = "nvenc", .swgroup = TEGRA_SWGROUP_NVENC, .reg = 0x264 },
|
||||
{ .name = "nv", .swgroup = TEGRA_SWGROUP_NV, .reg = 0x268 },
|
||||
{ .name = "nv2", .swgroup = TEGRA_SWGROUP_NV2, .reg = 0x26c },
|
||||
{ .name = "ppcs", .swgroup = TEGRA_SWGROUP_PPCS, .reg = 0x270 },
|
||||
{ .name = "sata", .swgroup = TEGRA_SWGROUP_SATA, .reg = 0x274 },
|
||||
{ .name = "isp2", .swgroup = TEGRA_SWGROUP_ISP2, .reg = 0x258 },
|
||||
{ .name = "vi", .swgroup = TEGRA_SWGROUP_VI, .reg = 0x280 },
|
||||
{ .name = "vic", .swgroup = TEGRA_SWGROUP_VIC, .reg = 0x284 },
|
||||
{ .name = "xusb_host", .swgroup = TEGRA_SWGROUP_XUSB_HOST, .reg = 0x288 },
|
||||
{ .name = "xusb_dev", .swgroup = TEGRA_SWGROUP_XUSB_DEV, .reg = 0x28c },
|
||||
{ .name = "isp2b", .swgroup = TEGRA_SWGROUP_ISP2B, .reg = 0xaa4 },
|
||||
{ .name = "tsec", .swgroup = TEGRA_SWGROUP_TSEC, .reg = 0x294 },
|
||||
{ .name = "a9avp", .swgroup = TEGRA_SWGROUP_A9AVP, .reg = 0x290 },
|
||||
{ .name = "gpu", .swgroup = TEGRA_SWGROUP_GPU, .reg = 0xaac },
|
||||
{ .name = "tsec", .swgroup = TEGRA_SWGROUP_TSEC, .reg = 0x294 },
|
||||
{ .name = "ppcs1", .swgroup = TEGRA_SWGROUP_PPCS1, .reg = 0x298 },
|
||||
{ .name = "dc1", .swgroup = TEGRA_SWGROUP_DC1, .reg = 0xa88 },
|
||||
{ .name = "sdmmc1a", .swgroup = TEGRA_SWGROUP_SDMMC1A, .reg = 0xa94 },
|
||||
{ .name = "sdmmc2a", .swgroup = TEGRA_SWGROUP_SDMMC2A, .reg = 0xa98 },
|
||||
{ .name = "sdmmc3a", .swgroup = TEGRA_SWGROUP_SDMMC3A, .reg = 0xa9c },
|
||||
{ .name = "sdmmc4a", .swgroup = TEGRA_SWGROUP_SDMMC4A, .reg = 0xaa0 },
|
||||
{ .name = "vic", .swgroup = TEGRA_SWGROUP_VIC, .reg = 0x284 },
|
||||
{ .name = "vi", .swgroup = TEGRA_SWGROUP_VI, .reg = 0x280 },
|
||||
{ .name = "isp2b", .swgroup = TEGRA_SWGROUP_ISP2B, .reg = 0xaa4 },
|
||||
{ .name = "gpu", .swgroup = TEGRA_SWGROUP_GPU, .reg = 0xaac },
|
||||
{ .name = "ppcs2", .swgroup = TEGRA_SWGROUP_PPCS2, .reg = 0xab0 },
|
||||
{ .name = "nvdec", .swgroup = TEGRA_SWGROUP_NVDEC, .reg = 0xab4 },
|
||||
{ .name = "ape", .swgroup = TEGRA_SWGROUP_APE, .reg = 0xab8 },
|
||||
{ .name = "nvjpg", .swgroup = TEGRA_SWGROUP_NVJPG, .reg = 0xac0 },
|
||||
{ .name = "se", .swgroup = TEGRA_SWGROUP_SE, .reg = 0xabc },
|
||||
{ .name = "nvjpg", .swgroup = TEGRA_SWGROUP_NVJPG, .reg = 0xac0 },
|
||||
{ .name = "hc1", .swgroup = TEGRA_SWGROUP_HC1, .reg = 0xac4 },
|
||||
{ .name = "se1", .swgroup = TEGRA_SWGROUP_SE1, .reg = 0xac8 },
|
||||
{ .name = "axiap", .swgroup = TEGRA_SWGROUP_AXIAP, .reg = 0xacc },
|
||||
{ .name = "etr", .swgroup = TEGRA_SWGROUP_ETR, .reg = 0xad0 },
|
||||
{ .name = "tsecb", .swgroup = TEGRA_SWGROUP_TSECB, .reg = 0xad4 },
|
||||
{ .name = "tsec1", .swgroup = TEGRA_SWGROUP_TSEC1, .reg = 0xad8 },
|
||||
{ .name = "tsecb1", .swgroup = TEGRA_SWGROUP_TSECB1, .reg = 0xadc },
|
||||
{ .name = "nvdec1", .swgroup = TEGRA_SWGROUP_NVDEC1, .reg = 0xae0 },
|
||||
};
|
||||
|
||||
static const unsigned int tegra210_group_display[] = {
|
||||
|
@ -14,16 +14,21 @@
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interconnect-provider.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_opp.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sort.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <soc/tegra/common.h>
|
||||
#include <soc/tegra/fuse.h>
|
||||
|
||||
#include "mc.h"
|
||||
@ -323,9 +328,21 @@ struct emc_timing {
|
||||
bool emc_cfg_dyn_self_ref;
|
||||
};
|
||||
|
||||
enum emc_rate_request_type {
|
||||
EMC_RATE_DEBUG,
|
||||
EMC_RATE_ICC,
|
||||
EMC_RATE_TYPE_MAX,
|
||||
};
|
||||
|
||||
struct emc_rate_request {
|
||||
unsigned long min_rate;
|
||||
unsigned long max_rate;
|
||||
};
|
||||
|
||||
struct tegra_emc {
|
||||
struct device *dev;
|
||||
struct tegra_mc *mc;
|
||||
struct icc_provider provider;
|
||||
struct notifier_block clk_nb;
|
||||
struct clk *clk;
|
||||
void __iomem *regs;
|
||||
@ -352,6 +369,15 @@ struct tegra_emc {
|
||||
unsigned long min_rate;
|
||||
unsigned long max_rate;
|
||||
} debugfs;
|
||||
|
||||
/*
|
||||
* There are multiple sources in the EMC driver which could request
|
||||
* a min/max clock rate, these rates are contained in this array.
|
||||
*/
|
||||
struct emc_rate_request requested_rate[EMC_RATE_TYPE_MAX];
|
||||
|
||||
/* protect shared rate-change code path */
|
||||
struct mutex rate_lock;
|
||||
};
|
||||
|
||||
static int emc_seq_update_timing(struct tegra_emc *emc)
|
||||
@ -988,6 +1014,11 @@ static struct device_node *emc_find_node_by_ram_code(struct device *dev)
|
||||
u32 value, ram_code;
|
||||
int err;
|
||||
|
||||
if (of_get_child_count(dev->of_node) == 0) {
|
||||
dev_info(dev, "device-tree doesn't have memory timings\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ram_code = tegra_read_ram_code();
|
||||
|
||||
for_each_child_of_node(dev->of_node, np) {
|
||||
@ -1057,6 +1088,9 @@ static long emc_round_rate(unsigned long rate,
|
||||
struct tegra_emc *emc = arg;
|
||||
unsigned int i;
|
||||
|
||||
if (!emc->num_timings)
|
||||
return clk_get_rate(emc->clk);
|
||||
|
||||
min_rate = min(min_rate, emc->timings[emc->num_timings - 1].rate);
|
||||
|
||||
for (i = 0; i < emc->num_timings; i++) {
|
||||
@ -1086,6 +1120,83 @@ static long emc_round_rate(unsigned long rate,
|
||||
return timing->rate;
|
||||
}
|
||||
|
||||
static void tegra_emc_rate_requests_init(struct tegra_emc *emc)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < EMC_RATE_TYPE_MAX; i++) {
|
||||
emc->requested_rate[i].min_rate = 0;
|
||||
emc->requested_rate[i].max_rate = ULONG_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
static int emc_request_rate(struct tegra_emc *emc,
|
||||
unsigned long new_min_rate,
|
||||
unsigned long new_max_rate,
|
||||
enum emc_rate_request_type type)
|
||||
{
|
||||
struct emc_rate_request *req = emc->requested_rate;
|
||||
unsigned long min_rate = 0, max_rate = ULONG_MAX;
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
/* select minimum and maximum rates among the requested rates */
|
||||
for (i = 0; i < EMC_RATE_TYPE_MAX; i++, req++) {
|
||||
if (i == type) {
|
||||
min_rate = max(new_min_rate, min_rate);
|
||||
max_rate = min(new_max_rate, max_rate);
|
||||
} else {
|
||||
min_rate = max(req->min_rate, min_rate);
|
||||
max_rate = min(req->max_rate, max_rate);
|
||||
}
|
||||
}
|
||||
|
||||
if (min_rate > max_rate) {
|
||||
dev_err_ratelimited(emc->dev, "%s: type %u: out of range: %lu %lu\n",
|
||||
__func__, type, min_rate, max_rate);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/*
|
||||
* EMC rate-changes should go via OPP API because it manages voltage
|
||||
* changes.
|
||||
*/
|
||||
err = dev_pm_opp_set_rate(emc->dev, min_rate);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
emc->requested_rate[type].min_rate = new_min_rate;
|
||||
emc->requested_rate[type].max_rate = new_max_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emc_set_min_rate(struct tegra_emc *emc, unsigned long rate,
|
||||
enum emc_rate_request_type type)
|
||||
{
|
||||
struct emc_rate_request *req = &emc->requested_rate[type];
|
||||
int ret;
|
||||
|
||||
mutex_lock(&emc->rate_lock);
|
||||
ret = emc_request_rate(emc, rate, req->max_rate, type);
|
||||
mutex_unlock(&emc->rate_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int emc_set_max_rate(struct tegra_emc *emc, unsigned long rate,
|
||||
enum emc_rate_request_type type)
|
||||
{
|
||||
struct emc_rate_request *req = &emc->requested_rate[type];
|
||||
int ret;
|
||||
|
||||
mutex_lock(&emc->rate_lock);
|
||||
ret = emc_request_rate(emc, req->min_rate, rate, type);
|
||||
mutex_unlock(&emc->rate_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* debugfs interface
|
||||
*
|
||||
@ -1169,7 +1280,7 @@ static int tegra_emc_debug_min_rate_set(void *data, u64 rate)
|
||||
if (!tegra_emc_validate_rate(emc, rate))
|
||||
return -EINVAL;
|
||||
|
||||
err = clk_set_min_rate(emc->clk, rate);
|
||||
err = emc_set_min_rate(emc, rate, EMC_RATE_DEBUG);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
@ -1199,7 +1310,7 @@ static int tegra_emc_debug_max_rate_set(void *data, u64 rate)
|
||||
if (!tegra_emc_validate_rate(emc, rate))
|
||||
return -EINVAL;
|
||||
|
||||
err = clk_set_max_rate(emc->clk, rate);
|
||||
err = emc_set_max_rate(emc, rate, EMC_RATE_DEBUG);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
@ -1256,51 +1367,239 @@ static void tegra_emc_debugfs_init(struct tegra_emc *emc)
|
||||
emc, &tegra_emc_debug_max_rate_fops);
|
||||
}
|
||||
|
||||
static inline struct tegra_emc *
|
||||
to_tegra_emc_provider(struct icc_provider *provider)
|
||||
{
|
||||
return container_of(provider, struct tegra_emc, provider);
|
||||
}
|
||||
|
||||
static struct icc_node_data *
|
||||
emc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
|
||||
{
|
||||
struct icc_provider *provider = data;
|
||||
struct icc_node_data *ndata;
|
||||
struct icc_node *node;
|
||||
|
||||
/* External Memory is the only possible ICC route */
|
||||
list_for_each_entry(node, &provider->nodes, node_list) {
|
||||
if (node->id != TEGRA_ICC_EMEM)
|
||||
continue;
|
||||
|
||||
ndata = kzalloc(sizeof(*ndata), GFP_KERNEL);
|
||||
if (!ndata)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/*
|
||||
* SRC and DST nodes should have matching TAG in order to have
|
||||
* it set by default for a requested path.
|
||||
*/
|
||||
ndata->tag = TEGRA_MC_ICC_TAG_ISO;
|
||||
ndata->node = node;
|
||||
|
||||
return ndata;
|
||||
}
|
||||
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
|
||||
static int emc_icc_set(struct icc_node *src, struct icc_node *dst)
|
||||
{
|
||||
struct tegra_emc *emc = to_tegra_emc_provider(dst->provider);
|
||||
unsigned long long peak_bw = icc_units_to_bps(dst->peak_bw);
|
||||
unsigned long long avg_bw = icc_units_to_bps(dst->avg_bw);
|
||||
unsigned long long rate = max(avg_bw, peak_bw);
|
||||
const unsigned int dram_data_bus_width_bytes = 4;
|
||||
const unsigned int ddr = 2;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* Tegra30 EMC runs on a clock rate of SDRAM bus. This means that
|
||||
* EMC clock rate is twice smaller than the peak data rate because
|
||||
* data is sampled on both EMC clock edges.
|
||||
*/
|
||||
do_div(rate, ddr * dram_data_bus_width_bytes);
|
||||
rate = min_t(u64, rate, U32_MAX);
|
||||
|
||||
err = emc_set_min_rate(emc, rate, EMC_RATE_ICC);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_emc_interconnect_init(struct tegra_emc *emc)
|
||||
{
|
||||
const struct tegra_mc_soc *soc = emc->mc->soc;
|
||||
struct icc_node *node;
|
||||
int err;
|
||||
|
||||
emc->provider.dev = emc->dev;
|
||||
emc->provider.set = emc_icc_set;
|
||||
emc->provider.data = &emc->provider;
|
||||
emc->provider.aggregate = soc->icc_ops->aggregate;
|
||||
emc->provider.xlate_extended = emc_of_icc_xlate_extended;
|
||||
|
||||
err = icc_provider_add(&emc->provider);
|
||||
if (err)
|
||||
goto err_msg;
|
||||
|
||||
/* create External Memory Controller node */
|
||||
node = icc_node_create(TEGRA_ICC_EMC);
|
||||
if (IS_ERR(node)) {
|
||||
err = PTR_ERR(node);
|
||||
goto del_provider;
|
||||
}
|
||||
|
||||
node->name = "External Memory Controller";
|
||||
icc_node_add(node, &emc->provider);
|
||||
|
||||
/* link External Memory Controller to External Memory (DRAM) */
|
||||
err = icc_link_create(node, TEGRA_ICC_EMEM);
|
||||
if (err)
|
||||
goto remove_nodes;
|
||||
|
||||
/* create External Memory node */
|
||||
node = icc_node_create(TEGRA_ICC_EMEM);
|
||||
if (IS_ERR(node)) {
|
||||
err = PTR_ERR(node);
|
||||
goto remove_nodes;
|
||||
}
|
||||
|
||||
node->name = "External Memory (DRAM)";
|
||||
icc_node_add(node, &emc->provider);
|
||||
|
||||
return 0;
|
||||
|
||||
remove_nodes:
|
||||
icc_nodes_remove(&emc->provider);
|
||||
del_provider:
|
||||
icc_provider_del(&emc->provider);
|
||||
err_msg:
|
||||
dev_err(emc->dev, "failed to initialize ICC: %d\n", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int tegra_emc_opp_table_init(struct tegra_emc *emc)
|
||||
{
|
||||
u32 hw_version = BIT(tegra_sku_info.soc_speedo_id);
|
||||
struct opp_table *clk_opp_table, *hw_opp_table;
|
||||
int err;
|
||||
|
||||
clk_opp_table = dev_pm_opp_set_clkname(emc->dev, NULL);
|
||||
err = PTR_ERR_OR_ZERO(clk_opp_table);
|
||||
if (err) {
|
||||
dev_err(emc->dev, "failed to set OPP clk: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
hw_opp_table = dev_pm_opp_set_supported_hw(emc->dev, &hw_version, 1);
|
||||
err = PTR_ERR_OR_ZERO(hw_opp_table);
|
||||
if (err) {
|
||||
dev_err(emc->dev, "failed to set OPP supported HW: %d\n", err);
|
||||
goto put_clk_table;
|
||||
}
|
||||
|
||||
err = dev_pm_opp_of_add_table(emc->dev);
|
||||
if (err) {
|
||||
if (err == -ENODEV)
|
||||
dev_err(emc->dev, "OPP table not found, please update your device tree\n");
|
||||
else
|
||||
dev_err(emc->dev, "failed to add OPP table: %d\n", err);
|
||||
|
||||
goto put_hw_table;
|
||||
}
|
||||
|
||||
dev_info(emc->dev, "OPP HW ver. 0x%x, current clock rate %lu MHz\n",
|
||||
hw_version, clk_get_rate(emc->clk) / 1000000);
|
||||
|
||||
/* first dummy rate-set initializes voltage state */
|
||||
err = dev_pm_opp_set_rate(emc->dev, clk_get_rate(emc->clk));
|
||||
if (err) {
|
||||
dev_err(emc->dev, "failed to initialize OPP clock: %d\n", err);
|
||||
goto remove_table;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
remove_table:
|
||||
dev_pm_opp_of_remove_table(emc->dev);
|
||||
put_hw_table:
|
||||
dev_pm_opp_put_supported_hw(hw_opp_table);
|
||||
put_clk_table:
|
||||
dev_pm_opp_put_clkname(clk_opp_table);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void devm_tegra_emc_unset_callback(void *data)
|
||||
{
|
||||
tegra20_clk_set_emc_round_callback(NULL, NULL);
|
||||
}
|
||||
|
||||
static void devm_tegra_emc_unreg_clk_notifier(void *data)
|
||||
{
|
||||
struct tegra_emc *emc = data;
|
||||
|
||||
clk_notifier_unregister(emc->clk, &emc->clk_nb);
|
||||
}
|
||||
|
||||
static int tegra_emc_init_clk(struct tegra_emc *emc)
|
||||
{
|
||||
int err;
|
||||
|
||||
tegra20_clk_set_emc_round_callback(emc_round_rate, emc);
|
||||
|
||||
err = devm_add_action_or_reset(emc->dev, devm_tegra_emc_unset_callback,
|
||||
NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
emc->clk = devm_clk_get(emc->dev, NULL);
|
||||
if (IS_ERR(emc->clk)) {
|
||||
dev_err(emc->dev, "failed to get EMC clock: %pe\n", emc->clk);
|
||||
return PTR_ERR(emc->clk);
|
||||
}
|
||||
|
||||
err = clk_notifier_register(emc->clk, &emc->clk_nb);
|
||||
if (err) {
|
||||
dev_err(emc->dev, "failed to register clk notifier: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = devm_add_action_or_reset(emc->dev,
|
||||
devm_tegra_emc_unreg_clk_notifier, emc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_emc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct platform_device *mc;
|
||||
struct device_node *np;
|
||||
struct tegra_emc *emc;
|
||||
int err;
|
||||
|
||||
if (of_get_child_count(pdev->dev.of_node) == 0) {
|
||||
dev_info(&pdev->dev,
|
||||
"device-tree node doesn't have memory timings\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
np = of_parse_phandle(pdev->dev.of_node, "nvidia,memory-controller", 0);
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "could not get memory controller node\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
mc = of_find_device_by_node(np);
|
||||
of_node_put(np);
|
||||
if (!mc)
|
||||
return -ENOENT;
|
||||
|
||||
np = emc_find_node_by_ram_code(&pdev->dev);
|
||||
if (!np)
|
||||
return -EINVAL;
|
||||
|
||||
emc = devm_kzalloc(&pdev->dev, sizeof(*emc), GFP_KERNEL);
|
||||
if (!emc) {
|
||||
of_node_put(np);
|
||||
if (!emc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
emc->mc = platform_get_drvdata(mc);
|
||||
if (!emc->mc)
|
||||
return -EPROBE_DEFER;
|
||||
emc->mc = devm_tegra_memory_controller_get(&pdev->dev);
|
||||
if (IS_ERR(emc->mc))
|
||||
return PTR_ERR(emc->mc);
|
||||
|
||||
mutex_init(&emc->rate_lock);
|
||||
emc->clk_nb.notifier_call = emc_clk_change_notify;
|
||||
emc->dev = &pdev->dev;
|
||||
|
||||
err = emc_load_timings_from_dt(emc, np);
|
||||
of_node_put(np);
|
||||
if (err)
|
||||
return err;
|
||||
np = emc_find_node_by_ram_code(&pdev->dev);
|
||||
if (np) {
|
||||
err = emc_load_timings_from_dt(emc, np);
|
||||
of_node_put(np);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
emc->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(emc->regs))
|
||||
@ -1311,10 +1610,9 @@ static int tegra_emc_probe(struct platform_device *pdev)
|
||||
return err;
|
||||
|
||||
err = platform_get_irq(pdev, 0);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "interrupt not specified: %d\n", err);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
emc->irq = err;
|
||||
|
||||
err = devm_request_irq(&pdev->dev, emc->irq, tegra_emc_isr, 0,
|
||||
@ -1324,31 +1622,27 @@ static int tegra_emc_probe(struct platform_device *pdev)
|
||||
return err;
|
||||
}
|
||||
|
||||
tegra20_clk_set_emc_round_callback(emc_round_rate, emc);
|
||||
err = tegra_emc_init_clk(emc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
emc->clk = devm_clk_get(&pdev->dev, "emc");
|
||||
if (IS_ERR(emc->clk)) {
|
||||
err = PTR_ERR(emc->clk);
|
||||
dev_err(&pdev->dev, "failed to get emc clock: %d\n", err);
|
||||
goto unset_cb;
|
||||
}
|
||||
|
||||
err = clk_notifier_register(emc->clk, &emc->clk_nb);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to register clk notifier: %d\n",
|
||||
err);
|
||||
goto unset_cb;
|
||||
}
|
||||
err = tegra_emc_opp_table_init(emc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
platform_set_drvdata(pdev, emc);
|
||||
tegra_emc_rate_requests_init(emc);
|
||||
tegra_emc_debugfs_init(emc);
|
||||
tegra_emc_interconnect_init(emc);
|
||||
|
||||
/*
|
||||
* Don't allow the kernel module to be unloaded. Unloading adds some
|
||||
* extra complexity which doesn't really worth the effort in a case of
|
||||
* this driver.
|
||||
*/
|
||||
try_module_get(THIS_MODULE);
|
||||
|
||||
return 0;
|
||||
|
||||
unset_cb:
|
||||
tegra20_clk_set_emc_round_callback(NULL, NULL);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int tegra_emc_suspend(struct device *dev)
|
||||
@ -1393,6 +1687,7 @@ static const struct of_device_id tegra_emc_of_match[] = {
|
||||
{ .compatible = "nvidia,tegra30-emc", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tegra_emc_of_match);
|
||||
|
||||
static struct platform_driver tegra_emc_driver = {
|
||||
.probe = tegra_emc_probe,
|
||||
@ -1401,11 +1696,11 @@ static struct platform_driver tegra_emc_driver = {
|
||||
.of_match_table = tegra_emc_of_match,
|
||||
.pm = &tegra_emc_pm_ops,
|
||||
.suppress_bind_attrs = true,
|
||||
.sync_state = icc_sync_state,
|
||||
},
|
||||
};
|
||||
module_platform_driver(tegra_emc_driver);
|
||||
|
||||
static int __init tegra_emc_init(void)
|
||||
{
|
||||
return platform_driver_register(&tegra_emc_driver);
|
||||
}
|
||||
subsys_initcall(tegra_emc_init);
|
||||
MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>");
|
||||
MODULE_DESCRIPTION("NVIDIA Tegra30 EMC driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -4,7 +4,8 @@
|
||||
*/
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <dt-bindings/memory/tegra30-mc.h>
|
||||
|
||||
@ -36,6 +37,13 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.id = 0x00,
|
||||
.name = "ptcr",
|
||||
.swgroup = TEGRA_SWGROUP_PTC,
|
||||
.la = {
|
||||
.reg = 0x34c,
|
||||
.shift = 0,
|
||||
.mask = 0xff,
|
||||
.def = 0x0,
|
||||
},
|
||||
.fifo_size = 16 * 2,
|
||||
}, {
|
||||
.id = 0x01,
|
||||
.name = "display0a",
|
||||
@ -50,6 +58,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x4e,
|
||||
},
|
||||
.fifo_size = 16 * 128,
|
||||
}, {
|
||||
.id = 0x02,
|
||||
.name = "display0ab",
|
||||
@ -64,6 +73,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x4e,
|
||||
},
|
||||
.fifo_size = 16 * 128,
|
||||
}, {
|
||||
.id = 0x03,
|
||||
.name = "display0b",
|
||||
@ -78,6 +88,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x4e,
|
||||
},
|
||||
.fifo_size = 16 * 64,
|
||||
}, {
|
||||
.id = 0x04,
|
||||
.name = "display0bb",
|
||||
@ -92,6 +103,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x4e,
|
||||
},
|
||||
.fifo_size = 16 * 64,
|
||||
}, {
|
||||
.id = 0x05,
|
||||
.name = "display0c",
|
||||
@ -106,6 +118,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x4e,
|
||||
},
|
||||
.fifo_size = 16 * 128,
|
||||
}, {
|
||||
.id = 0x06,
|
||||
.name = "display0cb",
|
||||
@ -120,6 +133,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x4e,
|
||||
},
|
||||
.fifo_size = 16 * 128,
|
||||
}, {
|
||||
.id = 0x07,
|
||||
.name = "display1b",
|
||||
@ -134,6 +148,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x4e,
|
||||
},
|
||||
.fifo_size = 16 * 64,
|
||||
}, {
|
||||
.id = 0x08,
|
||||
.name = "display1bb",
|
||||
@ -148,6 +163,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x4e,
|
||||
},
|
||||
.fifo_size = 16 * 64,
|
||||
}, {
|
||||
.id = 0x09,
|
||||
.name = "eppup",
|
||||
@ -162,6 +178,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x17,
|
||||
},
|
||||
.fifo_size = 16 * 8,
|
||||
}, {
|
||||
.id = 0x0a,
|
||||
.name = "g2pr",
|
||||
@ -176,6 +193,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x09,
|
||||
},
|
||||
.fifo_size = 16 * 64,
|
||||
}, {
|
||||
.id = 0x0b,
|
||||
.name = "g2sr",
|
||||
@ -190,6 +208,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x09,
|
||||
},
|
||||
.fifo_size = 16 * 64,
|
||||
}, {
|
||||
.id = 0x0c,
|
||||
.name = "mpeunifbr",
|
||||
@ -204,6 +223,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x50,
|
||||
},
|
||||
.fifo_size = 16 * 8,
|
||||
}, {
|
||||
.id = 0x0d,
|
||||
.name = "viruv",
|
||||
@ -218,6 +238,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x2c,
|
||||
},
|
||||
.fifo_size = 16 * 8,
|
||||
}, {
|
||||
.id = 0x0e,
|
||||
.name = "afir",
|
||||
@ -232,6 +253,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x10,
|
||||
},
|
||||
.fifo_size = 16 * 32,
|
||||
}, {
|
||||
.id = 0x0f,
|
||||
.name = "avpcarm7r",
|
||||
@ -246,6 +268,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x04,
|
||||
},
|
||||
.fifo_size = 16 * 2,
|
||||
}, {
|
||||
.id = 0x10,
|
||||
.name = "displayhc",
|
||||
@ -260,6 +283,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0xff,
|
||||
},
|
||||
.fifo_size = 16 * 2,
|
||||
}, {
|
||||
.id = 0x11,
|
||||
.name = "displayhcb",
|
||||
@ -274,6 +298,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0xff,
|
||||
},
|
||||
.fifo_size = 16 * 2,
|
||||
}, {
|
||||
.id = 0x12,
|
||||
.name = "fdcdrd",
|
||||
@ -288,6 +313,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x0a,
|
||||
},
|
||||
.fifo_size = 16 * 48,
|
||||
}, {
|
||||
.id = 0x13,
|
||||
.name = "fdcdrd2",
|
||||
@ -302,6 +328,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x0a,
|
||||
},
|
||||
.fifo_size = 16 * 48,
|
||||
}, {
|
||||
.id = 0x14,
|
||||
.name = "g2dr",
|
||||
@ -316,6 +343,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x0a,
|
||||
},
|
||||
.fifo_size = 16 * 48,
|
||||
}, {
|
||||
.id = 0x15,
|
||||
.name = "hdar",
|
||||
@ -330,6 +358,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0xff,
|
||||
},
|
||||
.fifo_size = 16 * 16,
|
||||
}, {
|
||||
.id = 0x16,
|
||||
.name = "host1xdmar",
|
||||
@ -344,6 +373,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x05,
|
||||
},
|
||||
.fifo_size = 16 * 16,
|
||||
}, {
|
||||
.id = 0x17,
|
||||
.name = "host1xr",
|
||||
@ -358,6 +388,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x50,
|
||||
},
|
||||
.fifo_size = 16 * 8,
|
||||
}, {
|
||||
.id = 0x18,
|
||||
.name = "idxsrd",
|
||||
@ -372,6 +403,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x13,
|
||||
},
|
||||
.fifo_size = 16 * 64,
|
||||
}, {
|
||||
.id = 0x19,
|
||||
.name = "idxsrd2",
|
||||
@ -386,6 +418,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x13,
|
||||
},
|
||||
.fifo_size = 16 * 64,
|
||||
}, {
|
||||
.id = 0x1a,
|
||||
.name = "mpe_ipred",
|
||||
@ -400,6 +433,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x80,
|
||||
},
|
||||
.fifo_size = 16 * 2,
|
||||
}, {
|
||||
.id = 0x1b,
|
||||
.name = "mpeamemrd",
|
||||
@ -414,6 +448,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x42,
|
||||
},
|
||||
.fifo_size = 16 * 64,
|
||||
}, {
|
||||
.id = 0x1c,
|
||||
.name = "mpecsrd",
|
||||
@ -428,6 +463,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0xff,
|
||||
},
|
||||
.fifo_size = 16 * 8,
|
||||
}, {
|
||||
.id = 0x1d,
|
||||
.name = "ppcsahbdmar",
|
||||
@ -442,6 +478,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x10,
|
||||
},
|
||||
.fifo_size = 16 * 2,
|
||||
}, {
|
||||
.id = 0x1e,
|
||||
.name = "ppcsahbslvr",
|
||||
@ -456,6 +493,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x12,
|
||||
},
|
||||
.fifo_size = 16 * 8,
|
||||
}, {
|
||||
.id = 0x1f,
|
||||
.name = "satar",
|
||||
@ -470,6 +508,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x33,
|
||||
},
|
||||
.fifo_size = 16 * 32,
|
||||
}, {
|
||||
.id = 0x20,
|
||||
.name = "texsrd",
|
||||
@ -484,6 +523,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x13,
|
||||
},
|
||||
.fifo_size = 16 * 64,
|
||||
}, {
|
||||
.id = 0x21,
|
||||
.name = "texsrd2",
|
||||
@ -498,6 +538,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x13,
|
||||
},
|
||||
.fifo_size = 16 * 64,
|
||||
}, {
|
||||
.id = 0x22,
|
||||
.name = "vdebsevr",
|
||||
@ -512,6 +553,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0xff,
|
||||
},
|
||||
.fifo_size = 16 * 8,
|
||||
}, {
|
||||
.id = 0x23,
|
||||
.name = "vdember",
|
||||
@ -526,6 +568,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0xd0,
|
||||
},
|
||||
.fifo_size = 16 * 4,
|
||||
}, {
|
||||
.id = 0x24,
|
||||
.name = "vdemcer",
|
||||
@ -540,6 +583,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x2a,
|
||||
},
|
||||
.fifo_size = 16 * 16,
|
||||
}, {
|
||||
.id = 0x25,
|
||||
.name = "vdetper",
|
||||
@ -554,6 +598,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x74,
|
||||
},
|
||||
.fifo_size = 16 * 16,
|
||||
}, {
|
||||
.id = 0x26,
|
||||
.name = "mpcorelpr",
|
||||
@ -564,6 +609,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x04,
|
||||
},
|
||||
.fifo_size = 16 * 14,
|
||||
}, {
|
||||
.id = 0x27,
|
||||
.name = "mpcorer",
|
||||
@ -574,6 +620,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x04,
|
||||
},
|
||||
.fifo_size = 16 * 14,
|
||||
}, {
|
||||
.id = 0x28,
|
||||
.name = "eppu",
|
||||
@ -588,6 +635,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x6c,
|
||||
},
|
||||
.fifo_size = 16 * 64,
|
||||
}, {
|
||||
.id = 0x29,
|
||||
.name = "eppv",
|
||||
@ -602,6 +650,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x6c,
|
||||
},
|
||||
.fifo_size = 16 * 64,
|
||||
}, {
|
||||
.id = 0x2a,
|
||||
.name = "eppy",
|
||||
@ -616,6 +665,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x6c,
|
||||
},
|
||||
.fifo_size = 16 * 64,
|
||||
}, {
|
||||
.id = 0x2b,
|
||||
.name = "mpeunifbw",
|
||||
@ -630,6 +680,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x13,
|
||||
},
|
||||
.fifo_size = 16 * 8,
|
||||
}, {
|
||||
.id = 0x2c,
|
||||
.name = "viwsb",
|
||||
@ -644,6 +695,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x12,
|
||||
},
|
||||
.fifo_size = 16 * 64,
|
||||
}, {
|
||||
.id = 0x2d,
|
||||
.name = "viwu",
|
||||
@ -658,6 +710,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0xb2,
|
||||
},
|
||||
.fifo_size = 16 * 64,
|
||||
}, {
|
||||
.id = 0x2e,
|
||||
.name = "viwv",
|
||||
@ -672,6 +725,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0xb2,
|
||||
},
|
||||
.fifo_size = 16 * 64,
|
||||
}, {
|
||||
.id = 0x2f,
|
||||
.name = "viwy",
|
||||
@ -686,6 +740,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x12,
|
||||
},
|
||||
.fifo_size = 16 * 64,
|
||||
}, {
|
||||
.id = 0x30,
|
||||
.name = "g2dw",
|
||||
@ -700,6 +755,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x9,
|
||||
},
|
||||
.fifo_size = 16 * 128,
|
||||
}, {
|
||||
.id = 0x31,
|
||||
.name = "afiw",
|
||||
@ -714,6 +770,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x0c,
|
||||
},
|
||||
.fifo_size = 16 * 32,
|
||||
}, {
|
||||
.id = 0x32,
|
||||
.name = "avpcarm7w",
|
||||
@ -728,6 +785,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x0e,
|
||||
},
|
||||
.fifo_size = 16 * 2,
|
||||
}, {
|
||||
.id = 0x33,
|
||||
.name = "fdcdwr",
|
||||
@ -742,6 +800,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x0a,
|
||||
},
|
||||
.fifo_size = 16 * 48,
|
||||
}, {
|
||||
.id = 0x34,
|
||||
.name = "fdcdwr2",
|
||||
@ -756,6 +815,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x0a,
|
||||
},
|
||||
.fifo_size = 16 * 48,
|
||||
}, {
|
||||
.id = 0x35,
|
||||
.name = "hdaw",
|
||||
@ -770,6 +830,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0xff,
|
||||
},
|
||||
.fifo_size = 16 * 16,
|
||||
}, {
|
||||
.id = 0x36,
|
||||
.name = "host1xw",
|
||||
@ -784,6 +845,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x10,
|
||||
},
|
||||
.fifo_size = 16 * 32,
|
||||
}, {
|
||||
.id = 0x37,
|
||||
.name = "ispw",
|
||||
@ -798,6 +860,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0xff,
|
||||
},
|
||||
.fifo_size = 16 * 64,
|
||||
}, {
|
||||
.id = 0x38,
|
||||
.name = "mpcorelpw",
|
||||
@ -808,6 +871,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x0e,
|
||||
},
|
||||
.fifo_size = 16 * 24,
|
||||
}, {
|
||||
.id = 0x39,
|
||||
.name = "mpcorew",
|
||||
@ -818,6 +882,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x0e,
|
||||
},
|
||||
.fifo_size = 16 * 24,
|
||||
}, {
|
||||
.id = 0x3a,
|
||||
.name = "mpecswr",
|
||||
@ -832,6 +897,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0xff,
|
||||
},
|
||||
.fifo_size = 16 * 8,
|
||||
}, {
|
||||
.id = 0x3b,
|
||||
.name = "ppcsahbdmaw",
|
||||
@ -846,6 +912,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x10,
|
||||
},
|
||||
.fifo_size = 16 * 2,
|
||||
}, {
|
||||
.id = 0x3c,
|
||||
.name = "ppcsahbslvw",
|
||||
@ -860,6 +927,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x06,
|
||||
},
|
||||
.fifo_size = 16 * 4,
|
||||
}, {
|
||||
.id = 0x3d,
|
||||
.name = "sataw",
|
||||
@ -874,6 +942,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x33,
|
||||
},
|
||||
.fifo_size = 16 * 32,
|
||||
}, {
|
||||
.id = 0x3e,
|
||||
.name = "vdebsevw",
|
||||
@ -888,6 +957,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0xff,
|
||||
},
|
||||
.fifo_size = 16 * 4,
|
||||
}, {
|
||||
.id = 0x3f,
|
||||
.name = "vdedbgw",
|
||||
@ -902,6 +972,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0xff,
|
||||
},
|
||||
.fifo_size = 16 * 16,
|
||||
}, {
|
||||
.id = 0x40,
|
||||
.name = "vdembew",
|
||||
@ -916,6 +987,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x42,
|
||||
},
|
||||
.fifo_size = 16 * 2,
|
||||
}, {
|
||||
.id = 0x41,
|
||||
.name = "vdetpmw",
|
||||
@ -930,6 +1002,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
.mask = 0xff,
|
||||
.def = 0x2a,
|
||||
},
|
||||
.fifo_size = 16 * 16,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1011,6 +1084,175 @@ static const struct tegra_mc_reset tegra30_mc_resets[] = {
|
||||
TEGRA30_MC_RESET(VI, 0x200, 0x204, 17),
|
||||
};
|
||||
|
||||
static void tegra30_mc_tune_client_latency(struct tegra_mc *mc,
|
||||
const struct tegra_mc_client *client,
|
||||
unsigned int bandwidth_mbytes_sec)
|
||||
{
|
||||
u32 arb_tolerance_compensation_nsec, arb_tolerance_compensation_div;
|
||||
const struct tegra_mc_la *la = &client->la;
|
||||
unsigned int fifo_size = client->fifo_size;
|
||||
u32 arb_nsec, la_ticks, value;
|
||||
|
||||
/* see 18.4.1 Client Configuration in Tegra3 TRM v03p */
|
||||
if (bandwidth_mbytes_sec)
|
||||
arb_nsec = fifo_size * NSEC_PER_USEC / bandwidth_mbytes_sec;
|
||||
else
|
||||
arb_nsec = U32_MAX;
|
||||
|
||||
/*
|
||||
* Latency allowness should be set with consideration for the module's
|
||||
* latency tolerance and internal buffering capabilities.
|
||||
*
|
||||
* Display memory clients use isochronous transfers and have very low
|
||||
* tolerance to a belated transfers. Hence we need to compensate the
|
||||
* memory arbitration imperfection for them in order to prevent FIFO
|
||||
* underflow condition when memory bus is busy.
|
||||
*
|
||||
* VI clients also need a stronger compensation.
|
||||
*/
|
||||
switch (client->swgroup) {
|
||||
case TEGRA_SWGROUP_MPCORE:
|
||||
case TEGRA_SWGROUP_PTC:
|
||||
/*
|
||||
* We always want lower latency for these clients, hence
|
||||
* don't touch them.
|
||||
*/
|
||||
return;
|
||||
|
||||
case TEGRA_SWGROUP_DC:
|
||||
case TEGRA_SWGROUP_DCB:
|
||||
arb_tolerance_compensation_nsec = 1050;
|
||||
arb_tolerance_compensation_div = 2;
|
||||
break;
|
||||
|
||||
case TEGRA_SWGROUP_VI:
|
||||
arb_tolerance_compensation_nsec = 1050;
|
||||
arb_tolerance_compensation_div = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
arb_tolerance_compensation_nsec = 150;
|
||||
arb_tolerance_compensation_div = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (arb_nsec > arb_tolerance_compensation_nsec)
|
||||
arb_nsec -= arb_tolerance_compensation_nsec;
|
||||
else
|
||||
arb_nsec = 0;
|
||||
|
||||
arb_nsec /= arb_tolerance_compensation_div;
|
||||
|
||||
/*
|
||||
* Latency allowance is a number of ticks a request from a particular
|
||||
* client may wait in the EMEM arbiter before it becomes a high-priority
|
||||
* request.
|
||||
*/
|
||||
la_ticks = arb_nsec / mc->tick;
|
||||
la_ticks = min(la_ticks, la->mask);
|
||||
|
||||
value = mc_readl(mc, la->reg);
|
||||
value &= ~(la->mask << la->shift);
|
||||
value |= la_ticks << la->shift;
|
||||
mc_writel(mc, value, la->reg);
|
||||
}
|
||||
|
||||
static int tegra30_mc_icc_set(struct icc_node *src, struct icc_node *dst)
|
||||
{
|
||||
struct tegra_mc *mc = icc_provider_to_tegra_mc(src->provider);
|
||||
const struct tegra_mc_client *client = &mc->soc->clients[src->id];
|
||||
u64 peak_bandwidth = icc_units_to_bps(src->peak_bw);
|
||||
|
||||
/*
|
||||
* Skip pre-initialization that is done by icc_node_add(), which sets
|
||||
* bandwidth to maximum for all clients before drivers are loaded.
|
||||
*
|
||||
* This doesn't make sense for us because we don't have drivers for all
|
||||
* clients and it's okay to keep configuration left from bootloader
|
||||
* during boot, at least for today.
|
||||
*/
|
||||
if (src == dst)
|
||||
return 0;
|
||||
|
||||
/* convert bytes/sec to megabytes/sec */
|
||||
do_div(peak_bandwidth, 1000000);
|
||||
|
||||
tegra30_mc_tune_client_latency(mc, client, peak_bandwidth);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra30_mc_icc_aggreate(struct icc_node *node, u32 tag, u32 avg_bw,
|
||||
u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
|
||||
{
|
||||
/*
|
||||
* ISO clients need to reserve extra bandwidth up-front because
|
||||
* there could be high bandwidth pressure during initial filling
|
||||
* of the client's FIFO buffers. Secondly, we need to take into
|
||||
* account impurities of the memory subsystem.
|
||||
*/
|
||||
if (tag & TEGRA_MC_ICC_TAG_ISO)
|
||||
peak_bw = tegra_mc_scale_percents(peak_bw, 400);
|
||||
|
||||
*agg_avg += avg_bw;
|
||||
*agg_peak = max(*agg_peak, peak_bw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct icc_node_data *
|
||||
tegra30_mc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
|
||||
{
|
||||
struct tegra_mc *mc = icc_provider_to_tegra_mc(data);
|
||||
const struct tegra_mc_client *client;
|
||||
unsigned int i, idx = spec->args[0];
|
||||
struct icc_node_data *ndata;
|
||||
struct icc_node *node;
|
||||
|
||||
list_for_each_entry(node, &mc->provider.nodes, node_list) {
|
||||
if (node->id != idx)
|
||||
continue;
|
||||
|
||||
ndata = kzalloc(sizeof(*ndata), GFP_KERNEL);
|
||||
if (!ndata)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
client = &mc->soc->clients[idx];
|
||||
ndata->node = node;
|
||||
|
||||
switch (client->swgroup) {
|
||||
case TEGRA_SWGROUP_DC:
|
||||
case TEGRA_SWGROUP_DCB:
|
||||
case TEGRA_SWGROUP_PTC:
|
||||
case TEGRA_SWGROUP_VI:
|
||||
/* these clients are isochronous by default */
|
||||
ndata->tag = TEGRA_MC_ICC_TAG_ISO;
|
||||
break;
|
||||
|
||||
default:
|
||||
ndata->tag = TEGRA_MC_ICC_TAG_DEFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
return ndata;
|
||||
}
|
||||
|
||||
for (i = 0; i < mc->soc->num_clients; i++) {
|
||||
if (mc->soc->clients[i].id == idx)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
|
||||
dev_err(mc->dev, "invalid ICC client ID %u\n", idx);
|
||||
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
static const struct tegra_mc_icc_ops tegra30_mc_icc_ops = {
|
||||
.xlate_extended = tegra30_mc_of_icc_xlate_extended,
|
||||
.aggregate = tegra30_mc_icc_aggreate,
|
||||
.set = tegra30_mc_icc_set,
|
||||
};
|
||||
|
||||
const struct tegra_mc_soc tegra30_mc_soc = {
|
||||
.clients = tegra30_mc_clients,
|
||||
.num_clients = ARRAY_SIZE(tegra30_mc_clients),
|
||||
@ -1025,4 +1267,5 @@ const struct tegra_mc_soc tegra30_mc_soc = {
|
||||
.reset_ops = &tegra_mc_reset_ops_common,
|
||||
.resets = tegra30_mc_resets,
|
||||
.num_resets = ARRAY_SIZE(tegra30_mc_resets),
|
||||
.icc_ops = &tegra30_mc_icc_ops,
|
||||
};
|
||||
|
@ -258,6 +258,7 @@ config OMAP_CF
|
||||
config AT91_CF
|
||||
tristate "AT91 CompactFlash Controller"
|
||||
depends on PCI
|
||||
depends on OF
|
||||
depends on PCMCIA && ARCH_AT91
|
||||
help
|
||||
Say Y here to support the CompactFlash controller on AT91 chips.
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/platform_data/atmel.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
@ -35,6 +34,17 @@
|
||||
#define CF_IO_PHYS (1 << 23)
|
||||
#define CF_MEM_PHYS (0x017ff800)
|
||||
|
||||
struct at91_cf_data {
|
||||
int irq_pin; /* I/O IRQ */
|
||||
int det_pin; /* Card detect */
|
||||
int vcc_pin; /* power switching */
|
||||
int rst_pin; /* card reset */
|
||||
u8 chipselect; /* EBI Chip Select number */
|
||||
u8 flags;
|
||||
#define AT91_CF_TRUE_IDE 0x01
|
||||
#define AT91_IDE_SWAP_A0_A2 0x02
|
||||
};
|
||||
|
||||
struct regmap *mc;
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@ -209,16 +219,18 @@ static struct pccard_operations at91_cf_ops = {
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static const struct of_device_id at91_cf_dt_ids[] = {
|
||||
{ .compatible = "atmel,at91rm9200-cf" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, at91_cf_dt_ids);
|
||||
|
||||
static int at91_cf_dt_init(struct platform_device *pdev)
|
||||
static int at91_cf_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct at91_cf_data *board;
|
||||
struct at91_cf_socket *cf;
|
||||
struct at91_cf_data *board;
|
||||
struct resource *io;
|
||||
int status;
|
||||
|
||||
board = devm_kzalloc(&pdev->dev, sizeof(*board), GFP_KERNEL);
|
||||
if (!board)
|
||||
@ -229,33 +241,9 @@ static int at91_cf_dt_init(struct platform_device *pdev)
|
||||
board->vcc_pin = of_get_gpio(pdev->dev.of_node, 2);
|
||||
board->rst_pin = of_get_gpio(pdev->dev.of_node, 3);
|
||||
|
||||
pdev->dev.platform_data = board;
|
||||
|
||||
mc = syscon_regmap_lookup_by_compatible("atmel,at91rm9200-sdramc");
|
||||
|
||||
return PTR_ERR_OR_ZERO(mc);
|
||||
}
|
||||
#else
|
||||
static int at91_cf_dt_init(struct platform_device *pdev)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int at91_cf_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct at91_cf_socket *cf;
|
||||
struct at91_cf_data *board = pdev->dev.platform_data;
|
||||
struct resource *io;
|
||||
int status;
|
||||
|
||||
if (!board) {
|
||||
status = at91_cf_dt_init(pdev);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
board = pdev->dev.platform_data;
|
||||
}
|
||||
if (IS_ERR(mc))
|
||||
return PTR_ERR(mc);
|
||||
|
||||
if (!gpio_is_valid(board->det_pin) || !gpio_is_valid(board->rst_pin))
|
||||
return -ENODEV;
|
||||
@ -399,7 +387,7 @@ static int at91_cf_resume(struct platform_device *pdev)
|
||||
static struct platform_driver at91_cf_driver = {
|
||||
.driver = {
|
||||
.name = "at91_cf",
|
||||
.of_match_table = of_match_ptr(at91_cf_dt_ids),
|
||||
.of_match_table = at91_cf_dt_ids,
|
||||
},
|
||||
.probe = at91_cf_probe,
|
||||
.remove = at91_cf_remove,
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/remoteproc.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include <linux/platform_data/wkup_m3.h>
|
||||
|
||||
@ -43,11 +44,13 @@ struct wkup_m3_mem {
|
||||
* @rproc: rproc handle
|
||||
* @pdev: pointer to platform device
|
||||
* @mem: WkupM3 memory information
|
||||
* @rsts: reset control
|
||||
*/
|
||||
struct wkup_m3_rproc {
|
||||
struct rproc *rproc;
|
||||
struct platform_device *pdev;
|
||||
struct wkup_m3_mem mem[WKUPM3_MEM_MAX];
|
||||
struct reset_control *rsts;
|
||||
};
|
||||
|
||||
static int wkup_m3_rproc_start(struct rproc *rproc)
|
||||
@ -56,13 +59,16 @@ static int wkup_m3_rproc_start(struct rproc *rproc)
|
||||
struct platform_device *pdev = wkupm3->pdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct wkup_m3_platform_data *pdata = dev_get_platdata(dev);
|
||||
int error = 0;
|
||||
|
||||
if (pdata->deassert_reset(pdev, pdata->reset_name)) {
|
||||
error = reset_control_deassert(wkupm3->rsts);
|
||||
|
||||
if (!wkupm3->rsts && pdata->deassert_reset(pdev, pdata->reset_name)) {
|
||||
dev_err(dev, "Unable to reset wkup_m3!\n");
|
||||
return -ENODEV;
|
||||
error = -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return error;
|
||||
}
|
||||
|
||||
static int wkup_m3_rproc_stop(struct rproc *rproc)
|
||||
@ -71,13 +77,16 @@ static int wkup_m3_rproc_stop(struct rproc *rproc)
|
||||
struct platform_device *pdev = wkupm3->pdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct wkup_m3_platform_data *pdata = dev_get_platdata(dev);
|
||||
int error = 0;
|
||||
|
||||
if (pdata->assert_reset(pdev, pdata->reset_name)) {
|
||||
error = reset_control_assert(wkupm3->rsts);
|
||||
|
||||
if (!wkupm3->rsts && pdata->assert_reset(pdev, pdata->reset_name)) {
|
||||
dev_err(dev, "Unable to assert reset of wkup_m3!\n");
|
||||
return -ENODEV;
|
||||
error = -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return error;
|
||||
}
|
||||
|
||||
static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len)
|
||||
@ -132,12 +141,6 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev)
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (!(pdata && pdata->deassert_reset && pdata->assert_reset &&
|
||||
pdata->reset_name)) {
|
||||
dev_err(dev, "Platform data missing!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = of_property_read_string(dev->of_node, "ti,pm-firmware",
|
||||
&fw_name);
|
||||
if (ret) {
|
||||
@ -165,6 +168,18 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev)
|
||||
wkupm3->rproc = rproc;
|
||||
wkupm3->pdev = pdev;
|
||||
|
||||
wkupm3->rsts = devm_reset_control_get_optional_shared(dev, "rstctrl");
|
||||
if (IS_ERR(wkupm3->rsts))
|
||||
return PTR_ERR(wkupm3->rsts);
|
||||
if (!wkupm3->rsts) {
|
||||
if (!(pdata && pdata->deassert_reset && pdata->assert_reset &&
|
||||
pdata->reset_name)) {
|
||||
dev_err(dev, "Platform data missing!\n");
|
||||
ret = -ENODEV;
|
||||
goto err_put_rproc;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mem_names); i++) {
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
mem_names[i]);
|
||||
@ -173,7 +188,7 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "devm_ioremap_resource failed for resource %d\n",
|
||||
i);
|
||||
ret = PTR_ERR(wkupm3->mem[i].cpu_addr);
|
||||
goto err;
|
||||
goto err_put_rproc;
|
||||
}
|
||||
wkupm3->mem[i].bus_addr = res->start;
|
||||
wkupm3->mem[i].size = resource_size(res);
|
||||
|
@ -102,7 +102,8 @@ config RESET_LPC18XX
|
||||
This enables the reset controller driver for NXP LPC18xx/43xx SoCs.
|
||||
|
||||
config RESET_MESON
|
||||
bool "Meson Reset Driver" if COMPILE_TEST
|
||||
tristate "Meson Reset Driver"
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
default ARCH_MESON
|
||||
help
|
||||
This enables the reset driver for Amlogic Meson SoCs.
|
||||
|
@ -208,6 +208,39 @@ static int reset_control_array_reset(struct reset_control_array *resets)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reset_control_array_rearm(struct reset_control_array *resets)
|
||||
{
|
||||
struct reset_control *rstc;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < resets->num_rstcs; i++) {
|
||||
rstc = resets->rstc[i];
|
||||
|
||||
if (!rstc)
|
||||
continue;
|
||||
|
||||
if (WARN_ON(IS_ERR(rstc)))
|
||||
return -EINVAL;
|
||||
|
||||
if (rstc->shared) {
|
||||
if (WARN_ON(atomic_read(&rstc->deassert_count) != 0))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (!rstc->acquired)
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < resets->num_rstcs; i++) {
|
||||
rstc = resets->rstc[i];
|
||||
|
||||
if (rstc && rstc->shared)
|
||||
WARN_ON(atomic_dec_return(&rstc->triggered_count) < 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reset_control_array_assert(struct reset_control_array *resets)
|
||||
{
|
||||
int ret, i;
|
||||
@ -325,6 +358,46 @@ int reset_control_reset(struct reset_control *rstc)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(reset_control_reset);
|
||||
|
||||
/**
|
||||
* reset_control_rearm - allow shared reset line to be re-triggered"
|
||||
* @rstc: reset controller
|
||||
*
|
||||
* On a shared reset line the actual reset pulse is only triggered once for the
|
||||
* lifetime of the reset_control instance, except if this call is used.
|
||||
*
|
||||
* Calls to this function must be balanced with calls to reset_control_reset,
|
||||
* a warning is thrown in case triggered_count ever dips below 0.
|
||||
*
|
||||
* Consumers must not use reset_control_(de)assert on shared reset lines when
|
||||
* reset_control_reset or reset_control_rearm have been used.
|
||||
*
|
||||
* If rstc is NULL the function will just return 0.
|
||||
*/
|
||||
int reset_control_rearm(struct reset_control *rstc)
|
||||
{
|
||||
if (!rstc)
|
||||
return 0;
|
||||
|
||||
if (WARN_ON(IS_ERR(rstc)))
|
||||
return -EINVAL;
|
||||
|
||||
if (reset_control_is_array(rstc))
|
||||
return reset_control_array_rearm(rstc_to_array(rstc));
|
||||
|
||||
if (rstc->shared) {
|
||||
if (WARN_ON(atomic_read(&rstc->deassert_count) != 0))
|
||||
return -EINVAL;
|
||||
|
||||
WARN_ON(atomic_dec_return(&rstc->triggered_count) < 0);
|
||||
} else {
|
||||
if (!rstc->acquired)
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(reset_control_rearm);
|
||||
|
||||
/**
|
||||
* reset_control_assert - asserts the reset line
|
||||
* @rstc: reset controller
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/slab.h>
|
||||
@ -104,6 +105,7 @@ static const struct of_device_id meson_reset_dt_ids[] = {
|
||||
{ .compatible = "amlogic,meson-a1-reset", .data = &meson_a1_param},
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, meson_reset_dt_ids);
|
||||
|
||||
static int meson_reset_probe(struct platform_device *pdev)
|
||||
{
|
||||
@ -142,4 +144,8 @@ static struct platform_driver meson_reset_driver = {
|
||||
.of_match_table = meson_reset_dt_ids,
|
||||
},
|
||||
};
|
||||
builtin_platform_driver(meson_reset_driver);
|
||||
module_platform_driver(meson_reset_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Amlogic Meson Reset Controller driver");
|
||||
MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
@ -44,7 +44,7 @@ static int a10_reset_init(struct device_node *np)
|
||||
data->membase = ioremap(res.start, size);
|
||||
if (!data->membase) {
|
||||
ret = -ENOMEM;
|
||||
goto err_alloc;
|
||||
goto release_region;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(np, "altr,modrst-offset", ®_offset))
|
||||
@ -59,7 +59,14 @@ static int a10_reset_init(struct device_node *np)
|
||||
data->rcdev.of_node = np;
|
||||
data->status_active_low = true;
|
||||
|
||||
return reset_controller_register(&data->rcdev);
|
||||
ret = reset_controller_register(&data->rcdev);
|
||||
if (ret)
|
||||
pr_err("unable to register device\n");
|
||||
|
||||
return ret;
|
||||
|
||||
release_region:
|
||||
release_mem_region(res.start, size);
|
||||
|
||||
err_alloc:
|
||||
kfree(data);
|
||||
|
@ -89,7 +89,7 @@ static int ti_syscon_reset_assert(struct reset_controller_dev *rcdev,
|
||||
mask = BIT(control->assert_bit);
|
||||
value = (control->flags & ASSERT_SET) ? mask : 0x0;
|
||||
|
||||
return regmap_update_bits(data->regmap, control->assert_offset, mask, value);
|
||||
return regmap_write_bits(data->regmap, control->assert_offset, mask, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -120,7 +120,7 @@ static int ti_syscon_reset_deassert(struct reset_controller_dev *rcdev,
|
||||
mask = BIT(control->deassert_bit);
|
||||
value = (control->flags & DEASSERT_SET) ? mask : 0x0;
|
||||
|
||||
return regmap_update_bits(data->regmap, control->deassert_offset, mask, value);
|
||||
return regmap_write_bits(data->regmap, control->deassert_offset, mask, value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4,7 +4,7 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_ARCH_ACTIONS) += actions/
|
||||
obj-$(CONFIG_SOC_ASPEED) += aspeed/
|
||||
obj-y += aspeed/
|
||||
obj-$(CONFIG_ARCH_AT91) += atmel/
|
||||
obj-y += bcm/
|
||||
obj-$(CONFIG_ARCH_DOVE) += dove/
|
||||
|
@ -9,7 +9,7 @@ config MESON_CANVAS
|
||||
Say yes to support the canvas IP for Amlogic SoCs.
|
||||
|
||||
config MESON_CLK_MEASURE
|
||||
bool "Amlogic Meson SoC Clock Measure driver"
|
||||
tristate "Amlogic Meson SoC Clock Measure driver"
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
default ARCH_MESON
|
||||
select REGMAP_MMIO
|
||||
@ -19,7 +19,7 @@ config MESON_CLK_MEASURE
|
||||
|
||||
config MESON_GX_SOCINFO
|
||||
bool "Amlogic Meson GX SoC Information driver"
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
depends on (ARM64 && ARCH_MESON) || COMPILE_TEST
|
||||
default ARCH_MESON
|
||||
select SOC_BUS
|
||||
help
|
||||
@ -27,7 +27,7 @@ config MESON_GX_SOCINFO
|
||||
information about the type, package and version.
|
||||
|
||||
config MESON_GX_PM_DOMAINS
|
||||
bool "Amlogic Meson GX Power Domains driver"
|
||||
tristate "Amlogic Meson GX Power Domains driver"
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
depends on PM && OF
|
||||
default ARCH_MESON
|
||||
@ -38,7 +38,7 @@ config MESON_GX_PM_DOMAINS
|
||||
Generic Power Domains.
|
||||
|
||||
config MESON_EE_PM_DOMAINS
|
||||
bool "Amlogic Meson Everything-Else Power Domains driver"
|
||||
tristate "Amlogic Meson Everything-Else Power Domains driver"
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
depends on PM && OF
|
||||
default ARCH_MESON
|
||||
@ -49,7 +49,7 @@ config MESON_EE_PM_DOMAINS
|
||||
Generic Power Domains.
|
||||
|
||||
config MESON_SECURE_PM_DOMAINS
|
||||
bool "Amlogic Meson Secure Power Domains driver"
|
||||
tristate "Amlogic Meson Secure Power Domains driver"
|
||||
depends on (ARCH_MESON || COMPILE_TEST) && MESON_SM
|
||||
depends on PM && OF
|
||||
depends on HAVE_ARM_SMCCC
|
||||
@ -63,7 +63,7 @@ config MESON_SECURE_PM_DOMAINS
|
||||
|
||||
config MESON_MX_SOCINFO
|
||||
bool "Amlogic Meson MX SoC Information driver"
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
depends on (ARM && ARCH_MESON) || COMPILE_TEST
|
||||
default ARCH_MESON
|
||||
select SOC_BUS
|
||||
help
|
||||
|
@ -72,8 +72,10 @@ struct meson_canvas *meson_canvas_get(struct device *dev)
|
||||
* current state, this driver probe cannot return -EPROBE_DEFER
|
||||
*/
|
||||
canvas = dev_get_drvdata(&canvas_pdev->dev);
|
||||
if (!canvas)
|
||||
if (!canvas) {
|
||||
put_device(&canvas_pdev->dev);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
static DEFINE_MUTEX(measure_lock);
|
||||
|
||||
@ -681,6 +682,7 @@ static const struct of_device_id meson_msr_match_table[] = {
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, meson_msr_match_table);
|
||||
|
||||
static struct platform_driver meson_msr_driver = {
|
||||
.probe = meson_msr_probe,
|
||||
@ -689,4 +691,5 @@ static struct platform_driver meson_msr_driver = {
|
||||
.of_match_table = meson_msr_match_table,
|
||||
},
|
||||
};
|
||||
builtin_platform_driver(meson_msr_driver);
|
||||
module_platform_driver(meson_msr_driver);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
#include <dt-bindings/power/meson8-power.h>
|
||||
#include <dt-bindings/power/meson-axg-power.h>
|
||||
#include <dt-bindings/power/meson-g12a-power.h>
|
||||
@ -412,8 +413,7 @@ static int meson_ee_pwrc_init_domain(struct platform_device *pdev,
|
||||
dev_warn(&pdev->dev, "Invalid resets count %d for domain %s\n",
|
||||
count, dom->desc.name);
|
||||
|
||||
dom->rstc = devm_reset_control_array_get(&pdev->dev, false,
|
||||
false);
|
||||
dom->rstc = devm_reset_control_array_get_exclusive(&pdev->dev);
|
||||
if (IS_ERR(dom->rstc))
|
||||
return PTR_ERR(dom->rstc);
|
||||
}
|
||||
@ -602,6 +602,7 @@ static const struct of_device_id meson_ee_pwrc_match_table[] = {
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, meson_ee_pwrc_match_table);
|
||||
|
||||
static struct platform_driver meson_ee_pwrc_driver = {
|
||||
.probe = meson_ee_pwrc_probe,
|
||||
@ -611,4 +612,5 @@ static struct platform_driver meson_ee_pwrc_driver = {
|
||||
.of_match_table = meson_ee_pwrc_match_table,
|
||||
},
|
||||
};
|
||||
builtin_platform_driver(meson_ee_pwrc_driver);
|
||||
module_platform_driver(meson_ee_pwrc_driver);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
/* AO Offsets */
|
||||
|
||||
@ -303,7 +304,7 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(regmap_hhi);
|
||||
}
|
||||
|
||||
rstc = devm_reset_control_array_get(&pdev->dev, false, false);
|
||||
rstc = devm_reset_control_array_get_exclusive(&pdev->dev);
|
||||
if (IS_ERR(rstc)) {
|
||||
if (PTR_ERR(rstc) != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "failed to get reset lines\n");
|
||||
@ -364,6 +365,7 @@ static const struct of_device_id meson_gx_pwrc_vpu_match_table[] = {
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, meson_gx_pwrc_vpu_match_table);
|
||||
|
||||
static struct platform_driver meson_gx_pwrc_vpu_driver = {
|
||||
.probe = meson_gx_pwrc_vpu_probe,
|
||||
@ -373,4 +375,5 @@ static struct platform_driver meson_gx_pwrc_vpu_driver = {
|
||||
.of_match_table = meson_gx_pwrc_vpu_match_table,
|
||||
},
|
||||
};
|
||||
builtin_platform_driver(meson_gx_pwrc_vpu_driver);
|
||||
module_platform_driver(meson_gx_pwrc_vpu_driver);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <dt-bindings/power/meson-a1-power.h>
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/firmware/meson/meson_sm.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define PWRC_ON 1
|
||||
#define PWRC_OFF 0
|
||||
@ -193,6 +194,7 @@ static const struct of_device_id meson_secure_pwrc_match_table[] = {
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, meson_secure_pwrc_match_table);
|
||||
|
||||
static struct platform_driver meson_secure_pwrc_driver = {
|
||||
.probe = meson_secure_pwrc_probe,
|
||||
@ -201,4 +203,5 @@ static struct platform_driver meson_secure_pwrc_driver = {
|
||||
.of_match_table = meson_secure_pwrc_match_table,
|
||||
},
|
||||
};
|
||||
builtin_platform_driver(meson_secure_pwrc_driver);
|
||||
module_platform_driver(meson_secure_pwrc_driver);
|
||||
MODULE_LICENSE("Dual MIT/GPL");
|
||||
|
@ -1,32 +1,47 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
menu "Aspeed SoC drivers"
|
||||
|
||||
config SOC_ASPEED
|
||||
def_bool y
|
||||
depends on ARCH_ASPEED || COMPILE_TEST
|
||||
if ARCH_ASPEED || COMPILE_TEST
|
||||
|
||||
menu "ASPEED SoC drivers"
|
||||
|
||||
config ASPEED_LPC_CTRL
|
||||
depends on SOC_ASPEED && REGMAP && MFD_SYSCON
|
||||
tristate "Aspeed ast2400/2500 HOST LPC to BMC bridge control"
|
||||
tristate "ASPEED LPC firmware cycle control"
|
||||
select REGMAP
|
||||
select MFD_SYSCON
|
||||
default ARCH_ASPEED
|
||||
help
|
||||
Control Aspeed ast2400/2500 HOST LPC to BMC mappings through
|
||||
ioctl()s, the driver also provides a read/write interface to a BMC ram
|
||||
region where the host LPC read/write region can be buffered.
|
||||
Control LPC firmware cycle mappings through ioctl()s. The driver
|
||||
also provides a read/write interface to a BMC ram region where the
|
||||
host LPC read/write region can be buffered.
|
||||
|
||||
config ASPEED_LPC_SNOOP
|
||||
tristate "Aspeed ast2500 HOST LPC snoop support"
|
||||
depends on SOC_ASPEED && REGMAP && MFD_SYSCON
|
||||
tristate "ASPEED LPC snoop support"
|
||||
select REGMAP
|
||||
select MFD_SYSCON
|
||||
default ARCH_ASPEED
|
||||
help
|
||||
Provides a driver to control the LPC snoop interface which
|
||||
allows the BMC to listen on and save the data written by
|
||||
the host to an arbitrary LPC I/O port.
|
||||
|
||||
config ASPEED_P2A_CTRL
|
||||
depends on SOC_ASPEED && REGMAP && MFD_SYSCON
|
||||
tristate "Aspeed ast2400/2500 HOST P2A VGA MMIO to BMC bridge control"
|
||||
tristate "ASPEED P2A (VGA MMIO to BMC) bridge control"
|
||||
select REGMAP
|
||||
select MFD_SYSCON
|
||||
default ARCH_ASPEED
|
||||
help
|
||||
Control Aspeed ast2400/2500 HOST P2A VGA MMIO to BMC mappings through
|
||||
ioctl()s, the driver also provides an interface for userspace mappings to
|
||||
a pre-defined region.
|
||||
Control ASPEED P2A VGA MMIO to BMC mappings through ioctl()s. The
|
||||
driver also provides an interface for userspace mappings to a
|
||||
pre-defined region.
|
||||
|
||||
config ASPEED_SOCINFO
|
||||
bool "ASPEED SoC Information driver"
|
||||
default ARCH_ASPEED
|
||||
select SOC_BUS
|
||||
default ARCH_ASPEED
|
||||
help
|
||||
Say yes to support decoding of ASPEED BMC information.
|
||||
|
||||
endmenu
|
||||
|
||||
endif
|
||||
|
@ -2,3 +2,4 @@
|
||||
obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
|
||||
obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
|
||||
obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o
|
||||
obj-$(CONFIG_ASPEED_SOCINFO) += aspeed-socinfo.o
|
||||
|
@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/mm.h>
|
||||
@ -21,6 +22,9 @@
|
||||
#define HICR5_ENL2H BIT(8)
|
||||
#define HICR5_ENFWH BIT(10)
|
||||
|
||||
#define HICR6 0x4
|
||||
#define SW_FWH2AHB BIT(17)
|
||||
|
||||
#define HICR7 0x8
|
||||
#define HICR8 0xc
|
||||
|
||||
@ -30,8 +34,9 @@ struct aspeed_lpc_ctrl {
|
||||
struct clk *clk;
|
||||
phys_addr_t mem_base;
|
||||
resource_size_t mem_size;
|
||||
u32 pnor_size;
|
||||
u32 pnor_base;
|
||||
u32 pnor_size;
|
||||
u32 pnor_base;
|
||||
bool fwh2ahb;
|
||||
};
|
||||
|
||||
static struct aspeed_lpc_ctrl *file_aspeed_lpc_ctrl(struct file *file)
|
||||
@ -176,6 +181,16 @@ static long aspeed_lpc_ctrl_ioctl(struct file *file, unsigned int cmd,
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* Switch to FWH2AHB mode, AST2600 only.
|
||||
*
|
||||
* The other bits in this register are interrupt status bits
|
||||
* that are cleared by writing 1. As we don't want to clear
|
||||
* them, set only the bit of interest.
|
||||
*/
|
||||
if (lpc_ctrl->fwh2ahb)
|
||||
regmap_write(lpc_ctrl->regmap, HICR6, SW_FWH2AHB);
|
||||
|
||||
/*
|
||||
* Enable LPC FHW cycles. This is required for the host to
|
||||
* access the regions specified.
|
||||
@ -241,6 +256,18 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
|
||||
|
||||
lpc_ctrl->mem_size = resource_size(&resm);
|
||||
lpc_ctrl->mem_base = resm.start;
|
||||
|
||||
if (!is_power_of_2(lpc_ctrl->mem_size)) {
|
||||
dev_err(dev, "Reserved memory size must be a power of 2, got %u\n",
|
||||
(unsigned int)lpc_ctrl->mem_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!IS_ALIGNED(lpc_ctrl->mem_base, lpc_ctrl->mem_size)) {
|
||||
dev_err(dev, "Reserved memory must be naturally aligned for size %u\n",
|
||||
(unsigned int)lpc_ctrl->mem_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
lpc_ctrl->regmap = syscon_node_to_regmap(
|
||||
@ -261,6 +288,9 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (of_device_is_compatible(dev->of_node, "aspeed,ast2600-lpc-ctrl"))
|
||||
lpc_ctrl->fwh2ahb = true;
|
||||
|
||||
lpc_ctrl->miscdev.minor = MISC_DYNAMIC_MINOR;
|
||||
lpc_ctrl->miscdev.name = DEVICE_NAME;
|
||||
lpc_ctrl->miscdev.fops = &aspeed_lpc_ctrl_fops;
|
||||
@ -291,6 +321,7 @@ static int aspeed_lpc_ctrl_remove(struct platform_device *pdev)
|
||||
static const struct of_device_id aspeed_lpc_ctrl_match[] = {
|
||||
{ .compatible = "aspeed,ast2400-lpc-ctrl" },
|
||||
{ .compatible = "aspeed,ast2500-lpc-ctrl" },
|
||||
{ .compatible = "aspeed,ast2600-lpc-ctrl" },
|
||||
{ },
|
||||
};
|
||||
|
||||
@ -308,4 +339,4 @@ module_platform_driver(aspeed_lpc_ctrl_driver);
|
||||
MODULE_DEVICE_TABLE(of, aspeed_lpc_ctrl_match);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Cyril Bur <cyrilbur@gmail.com>");
|
||||
MODULE_DESCRIPTION("Control for aspeed 2400/2500 LPC HOST to BMC mappings");
|
||||
MODULE_DESCRIPTION("Control for ASPEED LPC HOST to BMC mappings");
|
||||
|
@ -325,6 +325,8 @@ static const struct of_device_id aspeed_lpc_snoop_match[] = {
|
||||
.data = &ast2400_model_data },
|
||||
{ .compatible = "aspeed,ast2500-lpc-snoop",
|
||||
.data = &ast2500_model_data },
|
||||
{ .compatible = "aspeed,ast2600-lpc-snoop",
|
||||
.data = &ast2500_model_data },
|
||||
{ },
|
||||
};
|
||||
|
||||
|
135
drivers/soc/aspeed/aspeed-socinfo.c
Normal file
135
drivers/soc/aspeed/aspeed-socinfo.c
Normal file
@ -0,0 +1,135 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* Copyright 2019 IBM Corp. */
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sys_soc.h>
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
const u32 id;
|
||||
} const rev_table[] = {
|
||||
/* AST2400 */
|
||||
{ "AST2400", 0x02000303 },
|
||||
{ "AST1400", 0x02010103 },
|
||||
{ "AST1250", 0x02010303 },
|
||||
/* AST2500 */
|
||||
{ "AST2500", 0x04000303 },
|
||||
{ "AST2510", 0x04000103 },
|
||||
{ "AST2520", 0x04000203 },
|
||||
{ "AST2530", 0x04000403 },
|
||||
/* AST2600 */
|
||||
{ "AST2600", 0x05000303 },
|
||||
{ "AST2620", 0x05010203 },
|
||||
};
|
||||
|
||||
static const char *siliconid_to_name(u32 siliconid)
|
||||
{
|
||||
unsigned int id = siliconid & 0xff00ffff;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0 ; i < ARRAY_SIZE(rev_table) ; ++i) {
|
||||
if (rev_table[i].id == id)
|
||||
return rev_table[i].name;
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
static const char *siliconid_to_rev(u32 siliconid)
|
||||
{
|
||||
unsigned int rev = (siliconid >> 16) & 0xff;
|
||||
|
||||
switch (rev) {
|
||||
case 0:
|
||||
return "A0";
|
||||
case 1:
|
||||
return "A1";
|
||||
case 3:
|
||||
return "A2";
|
||||
}
|
||||
|
||||
return "??";
|
||||
}
|
||||
|
||||
static int __init aspeed_socinfo_init(void)
|
||||
{
|
||||
struct soc_device_attribute *attrs;
|
||||
struct soc_device *soc_dev;
|
||||
struct device_node *np;
|
||||
void __iomem *reg;
|
||||
bool has_chipid = false;
|
||||
u32 siliconid;
|
||||
u32 chipid[2];
|
||||
const char *machine = NULL;
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "aspeed,silicon-id");
|
||||
if (!of_device_is_available(np)) {
|
||||
of_node_put(np);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
reg = of_iomap(np, 0);
|
||||
if (!reg) {
|
||||
of_node_put(np);
|
||||
return -ENODEV;
|
||||
}
|
||||
siliconid = readl(reg);
|
||||
iounmap(reg);
|
||||
|
||||
/* This is optional, the ast2400 does not have it */
|
||||
reg = of_iomap(np, 1);
|
||||
if (reg) {
|
||||
has_chipid = true;
|
||||
chipid[0] = readl(reg);
|
||||
chipid[1] = readl(reg + 4);
|
||||
iounmap(reg);
|
||||
}
|
||||
of_node_put(np);
|
||||
|
||||
attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
|
||||
if (!attrs)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* Machine: Romulus BMC
|
||||
* Family: AST2500
|
||||
* Revision: A1
|
||||
* SoC ID: raw silicon revision id
|
||||
* Serial Number: 64-bit chipid
|
||||
*/
|
||||
|
||||
np = of_find_node_by_path("/");
|
||||
of_property_read_string(np, "model", &machine);
|
||||
if (machine)
|
||||
attrs->machine = kstrdup(machine, GFP_KERNEL);
|
||||
of_node_put(np);
|
||||
|
||||
attrs->family = siliconid_to_name(siliconid);
|
||||
attrs->revision = siliconid_to_rev(siliconid);
|
||||
attrs->soc_id = kasprintf(GFP_KERNEL, "%08x", siliconid);
|
||||
|
||||
if (has_chipid)
|
||||
attrs->serial_number = kasprintf(GFP_KERNEL, "%08x%08x",
|
||||
chipid[1], chipid[0]);
|
||||
|
||||
soc_dev = soc_device_register(attrs);
|
||||
if (IS_ERR(soc_dev)) {
|
||||
kfree(attrs->soc_id);
|
||||
kfree(attrs->serial_number);
|
||||
kfree(attrs);
|
||||
return PTR_ERR(soc_dev);
|
||||
}
|
||||
|
||||
pr_info("ASPEED %s rev %s (%s)\n",
|
||||
attrs->family,
|
||||
attrs->revision,
|
||||
attrs->soc_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
early_initcall(aspeed_socinfo_init);
|
@ -69,6 +69,12 @@ static const struct at91_soc __initconst socs[] = {
|
||||
#endif
|
||||
#ifdef CONFIG_SOC_SAM9X60
|
||||
AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_EXID_MATCH, "sam9x60", "sam9x60"),
|
||||
AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_D5M_EXID_MATCH,
|
||||
"sam9x60 64MiB DDR2 SiP", "sam9x60"),
|
||||
AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_D1G_EXID_MATCH,
|
||||
"sam9x60 128MiB DDR2 SiP", "sam9x60"),
|
||||
AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_D6K_EXID_MATCH,
|
||||
"sam9x60 8MiB SDRAM SiP", "sam9x60"),
|
||||
#endif
|
||||
#ifdef CONFIG_SOC_SAMA5
|
||||
AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D21CU_EXID_MATCH,
|
||||
|
@ -60,6 +60,9 @@ at91_soc_init(const struct at91_soc *socs);
|
||||
#define AT91SAM9CN11_EXID_MATCH 0x00000009
|
||||
|
||||
#define SAM9X60_EXID_MATCH 0x00000000
|
||||
#define SAM9X60_D5M_EXID_MATCH 0x00000001
|
||||
#define SAM9X60_D1G_EXID_MATCH 0x00000010
|
||||
#define SAM9X60_D6K_EXID_MATCH 0x00000011
|
||||
|
||||
#define AT91SAM9XE128_CIDR_MATCH 0x329973a0
|
||||
#define AT91SAM9XE256_CIDR_MATCH 0x329a93a0
|
||||
|
@ -111,6 +111,8 @@ enum bsp_initiate_command {
|
||||
|
||||
static struct brcmstb_pm_control ctrl;
|
||||
|
||||
noinline int brcmstb_pm_s3_finish(void);
|
||||
|
||||
static int (*brcmstb_pm_do_s2_sram)(void __iomem *aon_ctrl_base,
|
||||
void __iomem *ddr_phy_pll_status);
|
||||
|
||||
|
@ -424,7 +424,7 @@ int qbman_swp_interrupt_get_inhibit(struct qbman_swp *p)
|
||||
/**
|
||||
* qbman_swp_interrupt_set_inhibit() - write interrupt mask register
|
||||
* @p: the given software portal object
|
||||
* @mask: The mask to set in SWP_IIR register
|
||||
* @inhibit: whether to inhibit the IRQs
|
||||
*/
|
||||
void qbman_swp_interrupt_set_inhibit(struct qbman_swp *p, int inhibit)
|
||||
{
|
||||
@ -510,7 +510,7 @@ enum qb_enqueue_commands {
|
||||
#define QB_ENQUEUE_CMD_TARGET_TYPE_SHIFT 4
|
||||
#define QB_ENQUEUE_CMD_DCA_EN_SHIFT 7
|
||||
|
||||
/**
|
||||
/*
|
||||
* qbman_eq_desc_clear() - Clear the contents of a descriptor to
|
||||
* default/starting state.
|
||||
*/
|
||||
@ -522,7 +522,7 @@ void qbman_eq_desc_clear(struct qbman_eq_desc *d)
|
||||
/**
|
||||
* qbman_eq_desc_set_no_orp() - Set enqueue descriptor without orp
|
||||
* @d: the enqueue descriptor.
|
||||
* @response_success: 1 = enqueue with response always; 0 = enqueue with
|
||||
* @respond_success: 1 = enqueue with response always; 0 = enqueue with
|
||||
* rejections returned on a FQ.
|
||||
*/
|
||||
void qbman_eq_desc_set_no_orp(struct qbman_eq_desc *d, int respond_success)
|
||||
@ -932,7 +932,7 @@ int qbman_swp_enqueue_multiple_desc_mem_back(struct qbman_swp *s,
|
||||
|
||||
/**
|
||||
* qbman_swp_push_get() - Get the push dequeue setup
|
||||
* @p: the software portal object
|
||||
* @s: the software portal object
|
||||
* @channel_idx: the channel index to query
|
||||
* @enabled: returned boolean to show whether the push dequeue is enabled
|
||||
* for the given channel
|
||||
@ -947,7 +947,7 @@ void qbman_swp_push_get(struct qbman_swp *s, u8 channel_idx, int *enabled)
|
||||
|
||||
/**
|
||||
* qbman_swp_push_set() - Enable or disable push dequeue
|
||||
* @p: the software portal object
|
||||
* @s: the software portal object
|
||||
* @channel_idx: the channel index (0 to 15)
|
||||
* @enable: enable or disable push dequeue
|
||||
*/
|
||||
@ -1046,6 +1046,7 @@ void qbman_pull_desc_set_numframes(struct qbman_pull_desc *d, u8 numframes)
|
||||
|
||||
/**
|
||||
* qbman_pull_desc_set_fq() - Set fqid from which the dequeue command dequeues
|
||||
* @d: the pull dequeue descriptor to be set
|
||||
* @fqid: the frame queue index of the given FQ
|
||||
*/
|
||||
void qbman_pull_desc_set_fq(struct qbman_pull_desc *d, u32 fqid)
|
||||
@ -1057,6 +1058,7 @@ void qbman_pull_desc_set_fq(struct qbman_pull_desc *d, u32 fqid)
|
||||
|
||||
/**
|
||||
* qbman_pull_desc_set_wq() - Set wqid from which the dequeue command dequeues
|
||||
* @d: the pull dequeue descriptor to be set
|
||||
* @wqid: composed of channel id and wqid within the channel
|
||||
* @dct: the dequeue command type
|
||||
*/
|
||||
@ -1071,6 +1073,7 @@ void qbman_pull_desc_set_wq(struct qbman_pull_desc *d, u32 wqid,
|
||||
/**
|
||||
* qbman_pull_desc_set_channel() - Set channelid from which the dequeue command
|
||||
* dequeues
|
||||
* @d: the pull dequeue descriptor to be set
|
||||
* @chid: the channel id to be dequeued
|
||||
* @dct: the dequeue command type
|
||||
*/
|
||||
@ -1398,6 +1401,7 @@ int qbman_result_has_new_result(struct qbman_swp *s, const struct dpaa2_dq *dq)
|
||||
/**
|
||||
* qbman_release_desc_clear() - Clear the contents of a descriptor to
|
||||
* default/starting state.
|
||||
* @d: the pull dequeue descriptor to be cleared
|
||||
*/
|
||||
void qbman_release_desc_clear(struct qbman_release_desc *d)
|
||||
{
|
||||
@ -1407,6 +1411,8 @@ void qbman_release_desc_clear(struct qbman_release_desc *d)
|
||||
|
||||
/**
|
||||
* qbman_release_desc_set_bpid() - Set the ID of the buffer pool to release to
|
||||
* @d: the pull dequeue descriptor to be set
|
||||
* @bpid: the bpid value to be set
|
||||
*/
|
||||
void qbman_release_desc_set_bpid(struct qbman_release_desc *d, u16 bpid)
|
||||
{
|
||||
@ -1416,6 +1422,8 @@ void qbman_release_desc_set_bpid(struct qbman_release_desc *d, u16 bpid)
|
||||
/**
|
||||
* qbman_release_desc_set_rcdi() - Determines whether or not the portal's RCDI
|
||||
* interrupt source should be asserted after the release command is completed.
|
||||
* @d: the pull dequeue descriptor to be set
|
||||
* @enable: enable (1) or disable (0) value
|
||||
*/
|
||||
void qbman_release_desc_set_rcdi(struct qbman_release_desc *d, int enable)
|
||||
{
|
||||
|
@ -2622,7 +2622,7 @@ int qman_shutdown_fq(u32 fqid)
|
||||
union qm_mc_command *mcc;
|
||||
union qm_mc_result *mcr;
|
||||
int orl_empty, drain = 0, ret = 0;
|
||||
u32 channel, wq, res;
|
||||
u32 channel, res;
|
||||
u8 state;
|
||||
|
||||
p = get_affine_portal();
|
||||
@ -2655,7 +2655,7 @@ int qman_shutdown_fq(u32 fqid)
|
||||
DPAA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ);
|
||||
/* Need to store these since the MCR gets reused */
|
||||
channel = qm_fqd_get_chan(&mcr->queryfq.fqd);
|
||||
wq = qm_fqd_get_wq(&mcr->queryfq.fqd);
|
||||
qm_fqd_get_wq(&mcr->queryfq.fqd);
|
||||
|
||||
if (channel < qm_channel_pool1) {
|
||||
channel_portal = get_portal_for_channel(channel);
|
||||
@ -2697,7 +2697,6 @@ int qman_shutdown_fq(u32 fqid)
|
||||
* to dequeue from the channel the FQ is scheduled on
|
||||
*/
|
||||
int found_fqrn = 0;
|
||||
u16 dequeue_wq = 0;
|
||||
|
||||
/* Flag that we need to drain FQ */
|
||||
drain = 1;
|
||||
@ -2705,11 +2704,8 @@ int qman_shutdown_fq(u32 fqid)
|
||||
if (channel >= qm_channel_pool1 &&
|
||||
channel < qm_channel_pool1 + 15) {
|
||||
/* Pool channel, enable the bit in the portal */
|
||||
dequeue_wq = (channel -
|
||||
qm_channel_pool1 + 1)<<4 | wq;
|
||||
} else if (channel < qm_channel_pool1) {
|
||||
/* Dedicated channel */
|
||||
dequeue_wq = wq;
|
||||
} else {
|
||||
dev_err(dev, "Can't recover FQ 0x%x, ch: 0x%x",
|
||||
fqid, channel);
|
||||
|
@ -231,7 +231,7 @@ EXPORT_SYMBOL(cpm_muram_offset);
|
||||
|
||||
/**
|
||||
* cpm_muram_dma - turn a muram virtual address into a DMA address
|
||||
* @offset: virtual address from cpm_muram_addr() to convert
|
||||
* @addr: virtual address from cpm_muram_addr() to convert
|
||||
*/
|
||||
dma_addr_t cpm_muram_dma(void __iomem *addr)
|
||||
{
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user