Pull ARM SoC-related driver updates from Olof Johansson: "Various driver updates for platforms and a couple of the small driver subsystems we merge through our tree: - A driver for SCU (system control) on NXP i.MX8QXP - Qualcomm Always-on Subsystem messaging driver (AOSS QMP) - Qualcomm PM support for MSM8998 - Support for a newer version of DRAM PHY driver for Broadcom (DPFE) - Reset controller support for Bitmain BM1880 - TI SCI (System Control Interface) support for CPU control on AM654 processors - More TI sysc refactoring and rework" * tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (84 commits) reset: remove redundant null check on pointer dev soc: rockchip: work around clang warning dt-bindings: reset: imx7: Fix the spelling of 'indices' soc: imx: Add i.MX8MN SoC driver support soc: aspeed: lpc-ctrl: Fix probe error handling soc: qcom: geni: Add support for ACPI firmware: ti_sci: Fix gcc unused-but-set-variable warning firmware: ti_sci: Use the correct style for SPDX License Identifier soc: imx8: Use existing of_root directly soc: imx8: Fix potential kernel dump in error path firmware/psci: psci_checker: Park kthreads before stopping them memory: move jedec_ddr.h from include/memory to drivers/memory/ memory: move jedec_ddr_data.c from lib/ to drivers/memory/ MAINTAINERS: Remove myself as qcom maintainer soc: aspeed: lpc-ctrl: make parameter optional soc: qcom: apr: Don't use reg for domain id soc: qcom: fix QCOM_AOSS_QMP dependency and build errors memory: tegra: Fix -Wunused-const-variable firmware: tegra: Early resume BPMP soc/tegra: Select pinctrl for Tegra194 ...
Unified · Split
| @@ -6,7 +6,7 @@ that are provided by the hardware platform it is running on, including power · 5 unmodified lines | ||
| 6 | 6 | and performance functions. |
| 7 | 7 | |
| 8 | 8 | This binding is intended to define the interface the firmware implementing |
| 9 | −the SCMI as described in ARM document number ARM DUI 0922B ("ARM System Control | |
| 9 | +the SCMI as described in ARM document number ARM DEN 0056A ("ARM System Control | |
| 10 | 10 | and Management Interface Platform Design Document")[0] provide for OSPM in |
| 11 | 11 | the device tree. |
| 12 | 12 | |
| @@ -0,0 +1,11 @@ | ||
| 1 | +DPAA2 console support | |
| 2 | + | |
| 3 | +Required properties: | |
| 4 | + | |
| 5 | + - compatible | |
| 6 | + Value type: <string> | |
| 7 | + Definition: Must be "fsl,dpaa2-console". | |
| 8 | + - reg | |
| 9 | + Value type: <prop-encoded-array> | |
| 10 | + Definition: A standard property. Specifies the region where the MCFBA | |
| 11 | + (MC firmware base address) register can be found. | |
| @@ -6,6 +6,8 @@ which then translates it into a corresponding voltage on a rail · 5 unmodified lines | ||
| 6 | 6 | Required Properties: |
| 7 | 7 | - compatible: Should be one of the following |
| 8 | 8 | * qcom,msm8996-rpmpd: RPM Power domain for the msm8996 family of SoC |
| 9 | + * qcom,msm8998-rpmpd: RPM Power domain for the msm8998 family of SoC | |
| 10 | + * qcom,qcs404-rpmpd: RPM Power domain for the qcs404 family of SoC | |
| 9 | 11 | * qcom,sdm845-rpmhpd: RPMh Power domain for the sdm845 family of SoC |
| 10 | 12 | - #power-domain-cells: number of cells in Power domain specifier |
| 11 | 13 | must be 1. |
| @@ -0,0 +1,18 @@ | ||
| 1 | +Bitmain BM1880 SoC Reset Controller | |
| 2 | +=================================== | |
| 3 | + | |
| 4 | +Please also refer to reset.txt in this directory for common reset | |
| 5 | +controller binding usage. | |
| 6 | + | |
| 7 | +Required properties: | |
| 8 | +- compatible: Should be "bitmain,bm1880-reset" | |
| 9 | +- reg: Offset and length of reset controller space in SCTRL. | |
| 10 | +- #reset-cells: Must be 1. | |
| 11 | + | |
| 12 | +Example: | |
| 13 | + | |
| 14 | + rst: reset-controller@c00 { | |
| 15 | + compatible = "bitmain,bm1880-reset"; | |
| 16 | + reg = <0xc00 0x8>; | |
| 17 | + #reset-cells = <1>; | |
| 18 | + }; | |
| @@ -45,6 +45,6 @@ Example: · 44 unmodified lines | ||
| 45 | 45 | }; |
| 46 | 46 | |
| 47 | 47 | |
| 48 | −For list of all valid reset indicies see | |
| 48 | +For list of all valid reset indices see | |
| 49 | 49 | <dt-bindings/reset/imx7-reset.h> for i.MX7 and |
| 50 | 50 | <dt-bindings/reset/imx8mq-reset.h> for i.MX8MQ |
| @@ -2,8 +2,8 @@ Amlogic Canvas · 1 unmodified line | ||
| 2 | 2 | ================================ |
| 3 | 3 | |
| 4 | 4 | A canvas is a collection of metadata that describes a pixel buffer. |
| 5 | −Those metadata include: width, height, phyaddr, wrapping, block mode | |
| 6 | −and endianness. | |
| 5 | +Those metadata include: width, height, phyaddr, wrapping and block mode. | |
| 6 | +Starting with GXBB the endianness can also be described. | |
| 7 | 7 | |
| 8 | 8 | Many IPs within Amlogic SoCs rely on canvas indexes to read/write pixel data |
| 9 | 9 | rather than use the phy addresses directly. For instance, this is the case for |
| @@ -18,7 +18,11 @@ Video Lookup Table · 8 unmodified lines | ||
| 18 | 18 | -------------------------- |
| 19 | 19 | |
| 20 | 20 | Required properties: |
| 21 | −- compatible: "amlogic,canvas" | |
| 21 | +- compatible: has to be one of: | |
| 22 | + - "amlogic,meson8-canvas", "amlogic,canvas" on Meson8 | |
| 23 | + - "amlogic,meson8b-canvas", "amlogic,canvas" on Meson8b | |
| 24 | + - "amlogic,meson8m2-canvas", "amlogic,canvas" on Meson8m2 | |
| 25 | + - "amlogic,canvas" on GXBB and newer | |
| 22 | 26 | - reg: Base physical address and size of the canvas registers. |
| 23 | 27 | |
| 24 | 28 | Example: |
| @@ -0,0 +1,81 @@ | ||
| 1 | +Qualcomm Always-On Subsystem side channel binding | |
| 2 | + | |
| 3 | +This binding describes the hardware component responsible for side channel | |
| 4 | +requests to the always-on subsystem (AOSS), used for certain power management | |
| 5 | +requests that is not handled by the standard RPMh interface. Each client in the | |
| 6 | +SoC has it's own block of message RAM and IRQ for communication with the AOSS. | |
| 7 | +The protocol used to communicate in the message RAM is known as Qualcomm | |
| 8 | +Messaging Protocol (QMP) | |
| 9 | + | |
| 10 | +The AOSS side channel exposes control over a set of resources, used to control | |
| 11 | +a set of debug related clocks and to affect the low power state of resources | |
| 12 | +related to the secondary subsystems. These resources are exposed as a set of | |
| 13 | +power-domains. | |
| 14 | + | |
| 15 | +- compatible: | |
| 16 | + Usage: required | |
| 17 | + Value type: <string> | |
| 18 | + Definition: must be "qcom,sdm845-aoss-qmp" | |
| 19 | + | |
| 20 | +- reg: | |
| 21 | + Usage: required | |
| 22 | + Value type: <prop-encoded-array> | |
| 23 | + Definition: the base address and size of the message RAM for this | |
| 24 | + client's communication with the AOSS | |
| 25 | + | |
| 26 | +- interrupts: | |
| 27 | + Usage: required | |
| 28 | + Value type: <prop-encoded-array> | |
| 29 | + Definition: should specify the AOSS message IRQ for this client | |
| 30 | + | |
| 31 | +- mboxes: | |
| 32 | + Usage: required | |
| 33 | + Value type: <prop-encoded-array> | |
| 34 | + Definition: reference to the mailbox representing the outgoing doorbell | |
| 35 | + in APCS for this client, as described in mailbox/mailbox.txt | |
| 36 | + | |
| 37 | +- #clock-cells: | |
| 38 | + Usage: optional | |
| 39 | + Value type: <u32> | |
| 40 | + Definition: must be 0 | |
| 41 | + The single clock represents the QDSS clock. | |
| 42 | + | |
| 43 | +- #power-domain-cells: | |
| 44 | + Usage: optional | |
| 45 | + Value type: <u32> | |
| 46 | + Definition: must be 1 | |
| 47 | + The provided power-domains are: | |
| 48 | + CDSP state (0), LPASS state (1), modem state (2), SLPI | |
| 49 | + state (3), SPSS state (4) and Venus state (5). | |
| 50 | + | |
| 51 | += SUBNODES | |
| 52 | +The AOSS side channel also provides the controls for three cooling devices, | |
| 53 | +these are expressed as subnodes of the QMP node. The name of the node is used | |
| 54 | +to identify the resource and must therefor be "cx", "mx" or "ebi". | |
| 55 | + | |
| 56 | +- #cooling-cells: | |
| 57 | + Usage: optional | |
| 58 | + Value type: <u32> | |
| 59 | + Definition: must be 2 | |
| 60 | + | |
| 61 | += EXAMPLE | |
| 62 | + | |
| 63 | +The following example represents the AOSS side-channel message RAM and the | |
| 64 | +mechanism exposing the power-domains, as found in SDM845. | |
| 65 | + | |
| 66 | + aoss_qmp: qmp@c300000 { | |
| 67 | + compatible = "qcom,sdm845-aoss-qmp"; | |
| 68 | + reg = <0x0c300000 0x100000>; | |
| 69 | + interrupts = <GIC_SPI 389 IRQ_TYPE_EDGE_RISING>; | |
| 70 | + mboxes = <&apss_shared 0>; | |
| 71 | + | |
| 72 | + #power-domain-cells = <1>; | |
| 73 | + | |
| 74 | + cx_cdev: cx { | |
| 75 | + #cooling-cells = <2>; | |
| 76 | + }; | |
| 77 | + | |
| 78 | + mx_cdev: mx { | |
| 79 | + #cooling-cells = <2>; | |
| 80 | + }; | |
| 81 | + }; | |
| @@ -9,7 +9,7 @@ used for audio/voice services on the QDSP. · 8 unmodified lines | ||
| 9 | 9 | Value type: <stringlist> |
| 10 | 10 | Definition: must be "qcom,apr-v<VERSION-NUMBER>", example "qcom,apr-v2" |
| 11 | 11 | |
| 12 | −- reg | |
| 12 | +- qcom,apr-domain | |
| 13 | 13 | Usage: required |
| 14 | 14 | Value type: <u32> |
| 15 | 15 | Definition: Destination processor ID. |
| @@ -49,9 +49,9 @@ by the individual bindings for the specific service · 33 unmodified lines | ||
| 49 | 49 | The following example represents a QDSP based sound card on a MSM8996 device |
| 50 | 50 | which uses apr as communication between Apps and QDSP. |
| 51 | 51 | |
| 52 | − apr@4 { | |
| 52 | + apr { | |
| 53 | 53 | compatible = "qcom,apr-v2"; |
| 54 | − reg = <APR_DOMAIN_ADSP>; | |
| 54 | + qcom,apr-domain = <APR_DOMAIN_ADSP>; | |
| 55 | 55 | |
| 56 | 56 | q6core@3 { |
| 57 | 57 | compatible = "qcom,q6core"; |
| @@ -2091,7 +2091,6 @@ S: Maintained · 2090 unmodified lines | ||
| 2091 | 2091 | |
| 2092 | 2092 | ARM/QUALCOMM SUPPORT |
| 2093 | 2093 | M: Andy Gross <agross@kernel.org> |
| 2094 | −M: David Brown <david.brown@linaro.org> | |
| 2095 | 2094 | L: linux-arm-msm@vger.kernel.org |
| 2096 | 2095 | S: Maintained |
| 2097 | 2096 | F: Documentation/devicetree/bindings/soc/qcom/ |
| @@ -2113,7 +2112,7 @@ F: drivers/i2c/busses/i2c-qup.c · 15 unmodified lines | ||
| 2113 | 2112 | F: drivers/i2c/busses/i2c-qcom-geni.c |
| 2114 | 2113 | F: drivers/mfd/ssbi.c |
| 2115 | 2114 | F: drivers/mmc/host/mmci_qcom* |
| 2116 | −F: drivers/mmc/host/sdhci_msm.c | |
| 2115 | +F: drivers/mmc/host/sdhci-msm.c | |
| 2117 | 2116 | F: drivers/pci/controller/dwc/pcie-qcom.c |
| 2118 | 2117 | F: drivers/phy/qualcomm/ |
| 2119 | 2118 | F: drivers/power/*/msm* |
| @@ -6527,6 +6526,7 @@ M: Li Yang <leoyang.li@nxp.com> · 4407 unmodified lines | ||
| 6527 | 6526 | L: linuxppc-dev@lists.ozlabs.org |
| 6528 | 6527 | L: linux-arm-kernel@lists.infradead.org |
| 6529 | 6528 | S: Maintained |
| 6529 | +F: Documentation/devicetree/bindings/misc/fsl,dpaa2-console.txt | |
| 6530 | 6530 | F: Documentation/devicetree/bindings/soc/fsl/ |
| 6531 | 6531 | F: drivers/soc/fsl/ |
| 6532 | 6532 | F: include/linux/fsl/ |
| @@ -11907,11 +11907,13 @@ F: include/linux/mtd/onenand*.h · 5374 unmodified lines | ||
| 11907 | 11907 | |
| 11908 | 11908 | OP-TEE DRIVER |
| 11909 | 11909 | M: Jens Wiklander <jens.wiklander@linaro.org> |
| 11910 | +L: tee-dev@lists.linaro.org | |
| 11910 | 11911 | S: Maintained |
| 11911 | 11912 | F: drivers/tee/optee/ |
| 11912 | 11913 | |
| 11913 | 11914 | OP-TEE RANDOM NUMBER GENERATOR (RNG) DRIVER |
| 11914 | 11915 | M: Sumit Garg <sumit.garg@linaro.org> |
| 11916 | +L: tee-dev@lists.linaro.org | |
| 11915 | 11917 | S: Maintained |
| 11916 | 11918 | F: drivers/char/hw_random/optee-rng.c |
| 11917 | 11919 | |
| @@ -13295,7 +13297,7 @@ M: Niklas Cassel <niklas.cassel@linaro.org> · 1377 unmodified lines | ||
| 13295 | 13297 | L: netdev@vger.kernel.org |
| 13296 | 13298 | S: Maintained |
| 13297 | 13299 | F: drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c |
| 13298 | −F: Documentation/devicetree/bindings/net/qcom,dwmac.txt | |
| 13300 | +F: Documentation/devicetree/bindings/net/qcom,ethqos.txt | |
| 13299 | 13301 | |
| 13300 | 13302 | QUALCOMM GENERIC INTERFACE I2C DRIVER |
| 13301 | 13303 | M: Alok Chauhan <alokc@codeaurora.org> |
| @@ -15745,6 +15747,7 @@ F: include/media/i2c/tw9910.h · 2443 unmodified lines | ||
| 15745 | 15747 | |
| 15746 | 15748 | TEE SUBSYSTEM |
| 15747 | 15749 | M: Jens Wiklander <jens.wiklander@linaro.org> |
| 15750 | +L: tee-dev@lists.linaro.org | |
| 15748 | 15751 | S: Maintained |
| 15749 | 15752 | F: include/linux/tee_drv.h |
| 15750 | 15753 | F: include/uapi/linux/tee.h |
| @@ -3442,6 +3442,7 @@ static int omap_hwmod_check_module(struct device *dev, · 3441 unmodified lines | ||
| 3442 | 3442 | * @dev: struct device |
| 3443 | 3443 | * @oh: module |
| 3444 | 3444 | * @sysc_fields: sysc register bits |
| 3445 | + * @clockdomain: clockdomain | |
| 3445 | 3446 | * @rev_offs: revision register offset |
| 3446 | 3447 | * @sysc_offs: sysconfig register offset |
| 3447 | 3448 | * @syss_offs: sysstatus register offset |
| @@ -3453,6 +3454,7 @@ static int omap_hwmod_check_module(struct device *dev, · 5 unmodified lines | ||
| 3453 | 3454 | static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh, |
| 3454 | 3455 | const struct ti_sysc_module_data *data, |
| 3455 | 3456 | struct sysc_regbits *sysc_fields, |
| 3457 | + struct clockdomain *clkdm, | |
| 3456 | 3458 | s32 rev_offs, s32 sysc_offs, |
| 3457 | 3459 | s32 syss_offs, u32 sysc_flags, |
| 3458 | 3460 | u32 idlemodes) |
| @@ -3460,8 +3462,6 @@ static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh, · 1 unmodified line | ||
| 3460 | 3462 | struct omap_hwmod_class_sysconfig *sysc; |
| 3461 | 3463 | struct omap_hwmod_class *class = NULL; |
| 3462 | 3464 | struct omap_hwmod_ocp_if *oi = NULL; |
| 3463 | − struct clockdomain *clkdm = NULL; | |
| 3464 | − struct clk *clk = NULL; | |
| 3465 | 3465 | void __iomem *regs = NULL; |
| 3466 | 3466 | unsigned long flags; |
| 3467 | 3467 | |
| @@ -3508,36 +3508,6 @@ static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh, · 40 unmodified lines | ||
| 3508 | 3508 | oi->user = OCP_USER_MPU | OCP_USER_SDMA; |
| 3509 | 3509 | } |
| 3510 | 3510 | |
| 3511 | − if (!oh->_clk) { | |
| 3512 | − struct clk_hw_omap *hwclk; | |
| 3513 | − | |
| 3514 | − clk = of_clk_get_by_name(dev->of_node, "fck"); | |
| 3515 | − if (!IS_ERR(clk)) | |
| 3516 | − clk_prepare(clk); | |
| 3517 | − else | |
| 3518 | − clk = NULL; | |
| 3519 | − | |
| 3520 | − /* | |
| 3521 | − * Populate clockdomain based on dts clock. It is needed for | |
| 3522 | − * clkdm_deny_idle() and clkdm_allow_idle() until we have have | |
| 3523 | − * interconnect driver and reset driver capable of blocking | |
| 3524 | − * clockdomain idle during reset, enable and idle. | |
| 3525 | − */ | |
| 3526 | − if (clk) { | |
| 3527 | − hwclk = to_clk_hw_omap(__clk_get_hw(clk)); | |
| 3528 | − if (hwclk && hwclk->clkdm_name) | |
| 3529 | − clkdm = clkdm_lookup(hwclk->clkdm_name); | |
| 3530 | − } | |
| 3531 | − | |
| 3532 | − /* | |
| 3533 | − * Note that we assume interconnect driver manages the clocks | |
| 3534 | − * and do not need to populate oh->_clk for dynamically | |
| 3535 | − * allocated modules. | |
| 3536 | − */ | |
| 3537 | − clk_unprepare(clk); | |
| 3538 | − clk_put(clk); | |
| 3539 | − } | |
| 3540 | − | |
| 3541 | 3511 | spin_lock_irqsave(&oh->_lock, flags); |
| 3542 | 3512 | if (regs) |
| 3543 | 3513 | oh->_mpu_rt_va = regs; |
| @@ -3623,7 +3593,7 @@ int omap_hwmod_init_module(struct device *dev, · 79 unmodified lines | ||
| 3623 | 3593 | u32 sysc_flags, idlemodes; |
| 3624 | 3594 | int error; |
| 3625 | 3595 | |
| 3626 | − if (!dev || !data) | |
| 3596 | + if (!dev || !data || !data->name || !cookie) | |
| 3627 | 3597 | return -EINVAL; |
| 3628 | 3598 | |
| 3629 | 3599 | oh = _lookup(data->name); |
| @@ -3694,7 +3664,8 @@ int omap_hwmod_init_module(struct device *dev, · 64 unmodified lines | ||
| 3694 | 3664 | return error; |
| 3695 | 3665 | |
| 3696 | 3666 | return omap_hwmod_allocate_module(dev, oh, data, sysc_fields, |
| 3697 | − rev_offs, sysc_offs, syss_offs, | |
| 3667 | + cookie->clkdm, rev_offs, | |
| 3668 | + sysc_offs, syss_offs, | |
| 3698 | 3669 | sysc_flags, idlemodes); |
| 3699 | 3670 | } |
| 3700 | 3671 | |
| @@ -26,6 +26,7 @@ · 25 unmodified lines | ||
| 26 | 26 | #include <linux/platform_data/wkup_m3.h> |
| 27 | 27 | #include <linux/platform_data/asoc-ti-mcbsp.h> |
| 28 | 28 | |
| 29 | +#include "clockdomain.h" | |
| 29 | 30 | #include "common.h" |
| 30 | 31 | #include "common-board-devices.h" |
| 31 | 32 | #include "control.h" |
| @@ -460,6 +461,62 @@ static void __init dra7x_evm_mmc_quirk(void) · 428 unmodified lines | ||
| 460 | 461 | } |
| 461 | 462 | #endif |
| 462 | 463 | |
| 464 | +static struct clockdomain *ti_sysc_find_one_clockdomain(struct clk *clk) | |
| 465 | +{ | |
| 466 | + struct clockdomain *clkdm = NULL; | |
| 467 | + struct clk_hw_omap *hwclk; | |
| 468 | + | |
| 469 | + hwclk = to_clk_hw_omap(__clk_get_hw(clk)); | |
| 470 | + if (hwclk && hwclk->clkdm_name) | |
| 471 | + clkdm = clkdm_lookup(hwclk->clkdm_name); | |
| 472 | + | |
| 473 | + return clkdm; | |
| 474 | +} | |
| 475 | + | |
| 476 | +/** | |
| 477 | + * ti_sysc_clkdm_init - find clockdomain based on clock | |
| 478 | + * @fck: device functional clock | |
| 479 | + * @ick: device interface clock | |
| 480 | + * @dev: struct device | |
| 481 | + * | |
| 482 | + * Populate clockdomain based on clock. It is needed for | |
| 483 | + * clkdm_deny_idle() and clkdm_allow_idle() for blocking clockdomain | |
| 484 | + * clockdomain idle during reset, enable and idle. | |
| 485 | + * | |
| 486 | + * Note that we assume interconnect driver manages the clocks | |
| 487 | + * and do not need to populate oh->_clk for dynamically | |
| 488 | + * allocated modules. | |
| 489 | + */ | |
| 490 | +static int ti_sysc_clkdm_init(struct device *dev, | |
| 491 | + struct clk *fck, struct clk *ick, | |
| 492 | + struct ti_sysc_cookie *cookie) | |
| 493 | +{ | |
| 494 | + if (fck) | |
| 495 | + cookie->clkdm = ti_sysc_find_one_clockdomain(fck); | |
| 496 | + if (cookie->clkdm) | |
| 497 | + return 0; | |
| 498 | + if (ick) | |
| 499 | + cookie->clkdm = ti_sysc_find_one_clockdomain(ick); | |
| 500 | + if (cookie->clkdm) | |
| 501 | + return 0; | |
| 502 | + | |
| 503 | + return -ENODEV; | |
| 504 | +} | |
| 505 | + | |
| 506 | +static void ti_sysc_clkdm_deny_idle(struct device *dev, | |
| 507 | + const struct ti_sysc_cookie *cookie) | |
| 508 | +{ | |
| 509 | + if (cookie->clkdm) | |
| 510 | + clkdm_deny_idle(cookie->clkdm); | |
| 511 | +} | |
| 512 | + | |
| 513 | +static void ti_sysc_clkdm_allow_idle(struct device *dev, | |
| 514 | + const struct ti_sysc_cookie *cookie) | |
| 515 | +{ | |
| 516 | + if (cookie->clkdm) | |
| 517 | + clkdm_allow_idle(cookie->clkdm); | |
| 518 | +} | |
| 519 | + | |
| 463 | 520 | static int ti_sysc_enable_module(struct device *dev, |
| 464 | 521 | const struct ti_sysc_cookie *cookie) |
| 465 | 522 | { |
| @@ -491,6 +548,9 @@ static struct of_dev_auxdata omap_auxdata_lookup[]; · 25 unmodified lines | ||
| 491 | 548 | |
| 492 | 549 | static struct ti_sysc_platform_data ti_sysc_pdata = { |
| 493 | 550 | .auxdata = omap_auxdata_lookup, |
| 551 | + .init_clockdomain = ti_sysc_clkdm_init, | |
| 552 | + .clkdm_deny_idle = ti_sysc_clkdm_deny_idle, | |
| 553 | + .clkdm_allow_idle = ti_sysc_clkdm_allow_idle, | |
| 494 | 554 | .init_module = omap_hwmod_init_module, |
| 495 | 555 | .enable_module = ti_sysc_enable_module, |
| 496 | 556 | .idle_module = ti_sysc_idle_module, |
| @@ -399,8 +399,8 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev) · 398 unmodified lines | ||
| 399 | 399 | &gisb_panic_notifier); |
| 400 | 400 | } |
| 401 | 401 | |
| 402 | − dev_info(&pdev->dev, "registered mem: %p, irqs: %d, %d\n", | |
| 403 | − gdev->base, timeout_irq, tea_irq); | |
| 402 | + dev_info(&pdev->dev, "registered irqs: %d, %d\n", | |
| 403 | + timeout_irq, tea_irq); | |
| 404 | 404 | |
| 405 | 405 | return 0; |
| 406 | 406 | } |
| @@ -443,11 +443,31 @@ int dprc_get_obj_region(struct fsl_mc_io *mc_io, · 442 unmodified lines | ||
| 443 | 443 | struct fsl_mc_command cmd = { 0 }; |
| 444 | 444 | struct dprc_cmd_get_obj_region *cmd_params; |
| 445 | 445 | struct dprc_rsp_get_obj_region *rsp_params; |
| 446 | + u16 major_ver, minor_ver; | |
| 446 | 447 | int err; |
| 447 | 448 | |
| 448 | 449 | /* prepare command */ |
| 449 | − cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG, | |
| 450 | − cmd_flags, token); | |
| 450 | + err = dprc_get_api_version(mc_io, 0, | |
| 451 | + &major_ver, | |
| 452 | + &minor_ver); | |
| 453 | + if (err) | |
| 454 | + return err; | |
| 455 | + | |
| 456 | + /** | |
| 457 | + * MC API version 6.3 introduced a new field to the region | |
| 458 | + * descriptor: base_address. If the older API is in use then the base | |
| 459 | + * address is set to zero to indicate it needs to be obtained elsewhere | |
| 460 | + * (typically the device tree). | |
| 461 | + */ | |
| 462 | + if (major_ver > 6 || (major_ver == 6 && minor_ver >= 3)) | |
| 463 | + cmd.header = | |
| 464 | + mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG_V2, | |
| 465 | + cmd_flags, token); | |
| 466 | + else | |
| 467 | + cmd.header = | |
| 468 | + mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG, | |
| 469 | + cmd_flags, token); | |
| 470 | + | |
| 451 | 471 | cmd_params = (struct dprc_cmd_get_obj_region *)cmd.params; |
| 452 | 472 | cmd_params->obj_id = cpu_to_le32(obj_id); |
| 453 | 473 | cmd_params->region_index = region_index; |
| @@ -461,8 +481,12 @@ int dprc_get_obj_region(struct fsl_mc_io *mc_io, · 7 unmodified lines | ||
| 461 | 481 | |
| 462 | 482 | /* retrieve response parameters */ |
| 463 | 483 | rsp_params = (struct dprc_rsp_get_obj_region *)cmd.params; |
| 464 | − region_desc->base_offset = le64_to_cpu(rsp_params->base_addr); | |
| 484 | + region_desc->base_offset = le64_to_cpu(rsp_params->base_offset); | |
| 465 | 485 | region_desc->size = le32_to_cpu(rsp_params->size); |
| 486 | + if (major_ver > 6 || (major_ver == 6 && minor_ver >= 3)) | |
| 487 | + region_desc->base_address = le64_to_cpu(rsp_params->base_addr); | |
| 488 | + else | |
| 489 | + region_desc->base_address = 0; | |
| 466 | 490 | |
| 467 | 491 | return 0; |
| 468 | 492 | } |
| @@ -487,10 +487,19 @@ static int fsl_mc_device_get_mmio_regions(struct fsl_mc_device *mc_dev, · 486 unmodified lines | ||
| 487 | 487 | "dprc_get_obj_region() failed: %d\n", error); |
| 488 | 488 | goto error_cleanup_regions; |
| 489 | 489 | } |
| 490 | − | |
| 491 | − error = translate_mc_addr(mc_dev, mc_region_type, | |
| 490 | + /* | |
| 491 | + * Older MC only returned region offset and no base address | |
| 492 | + * If base address is in the region_desc use it otherwise | |
| 493 | + * revert to old mechanism | |
| 494 | + */ | |
| 495 | + if (region_desc.base_address) | |
| 496 | + regions[i].start = region_desc.base_address + | |
| 497 | + region_desc.base_offset; | |
| 498 | + else | |
| 499 | + error = translate_mc_addr(mc_dev, mc_region_type, | |
| 492 | 500 | region_desc.base_offset, |
| 493 | 501 | ®ions[i].start); |
| 502 | + | |
| 494 | 503 | if (error < 0) { |
| 495 | 504 | dev_err(parent_dev, |
| 496 | 505 | "Invalid MC offset: %#x (for %s.%d\'s region %d)\n", |
| @@ -504,6 +513,8 @@ static int fsl_mc_device_get_mmio_regions(struct fsl_mc_device *mc_dev, · 7 unmodified lines | ||
| 504 | 513 | regions[i].flags = IORESOURCE_IO; |
| 505 | 514 | if (region_desc.flags & DPRC_REGION_CACHEABLE) |
| 506 | 515 | regions[i].flags |= IORESOURCE_CACHEABLE; |
| 516 | + if (region_desc.flags & DPRC_REGION_SHAREABLE) | |
| 517 | + regions[i].flags |= IORESOURCE_MEM; | |
| 507 | 518 | } |
| 508 | 519 | |
| 509 | 520 | mc_dev->regions = regions; |
| @@ -79,9 +79,11 @@ int dpmcp_reset(struct fsl_mc_io *mc_io, · 78 unmodified lines | ||
| 79 | 79 | |
| 80 | 80 | /* DPRC command versioning */ |
| 81 | 81 | #define DPRC_CMD_BASE_VERSION 1 |
| 82 | +#define DPRC_CMD_2ND_VERSION 2 | |
| 82 | 83 | #define DPRC_CMD_ID_OFFSET 4 |
| 83 | 84 | |
| 84 | 85 | #define DPRC_CMD(id) (((id) << DPRC_CMD_ID_OFFSET) | DPRC_CMD_BASE_VERSION) |
| 86 | +#define DPRC_CMD_V2(id) (((id) << DPRC_CMD_ID_OFFSET) | DPRC_CMD_2ND_VERSION) | |
| 85 | 87 | |
| 86 | 88 | /* DPRC command IDs */ |
| 87 | 89 | #define DPRC_CMDID_CLOSE DPRC_CMD(0x800) |
| @@ -100,6 +102,7 @@ int dpmcp_reset(struct fsl_mc_io *mc_io, · 12 unmodified lines | ||
| 100 | 102 | #define DPRC_CMDID_GET_OBJ_COUNT DPRC_CMD(0x159) |
| 101 | 103 | #define DPRC_CMDID_GET_OBJ DPRC_CMD(0x15A) |
| 102 | 104 | #define DPRC_CMDID_GET_OBJ_REG DPRC_CMD(0x15E) |
| 105 | +#define DPRC_CMDID_GET_OBJ_REG_V2 DPRC_CMD_V2(0x15E) | |
| 103 | 106 | #define DPRC_CMDID_SET_OBJ_IRQ DPRC_CMD(0x15F) |
| 104 | 107 | |
| 105 | 108 | struct dprc_cmd_open { |
| @@ -199,9 +202,16 @@ struct dprc_rsp_get_obj_region { · 93 unmodified lines | ||
| 199 | 202 | /* response word 0 */ |
| 200 | 203 | __le64 pad; |
| 201 | 204 | /* response word 1 */ |
| 202 | − __le64 base_addr; | |
| 205 | + __le64 base_offset; | |
| 203 | 206 | /* response word 2 */ |
| 204 | 207 | __le32 size; |
| 208 | + __le32 pad2; | |
| 209 | + /* response word 3 */ | |
| 210 | + __le32 flags; | |
| 211 | + __le32 pad3; | |
| 212 | + /* response word 4 */ | |
| 213 | + /* base_addr may be zero if older MC firmware is used */ | |
| 214 | + __le64 base_addr; | |
| 205 | 215 | }; |
| 206 | 216 | |
| 207 | 217 | struct dprc_cmd_set_obj_irq { |
| @@ -334,6 +344,7 @@ int dprc_set_obj_irq(struct fsl_mc_io *mc_io, · 126 unmodified lines | ||
| 334 | 344 | /* Region flags */ |
| 335 | 345 | /* Cacheable - Indicates that region should be mapped as cacheable */ |
| 336 | 346 | #define DPRC_REGION_CACHEABLE 0x00000001 |
| 347 | +#define DPRC_REGION_SHAREABLE 0x00000002 | |
| 337 | 348 | |
| 338 | 349 | /** |
| 339 | 350 | * enum dprc_region_type - Region type |
| @@ -342,7 +353,8 @@ int dprc_set_obj_irq(struct fsl_mc_io *mc_io, · 2 unmodified lines | ||
| 342 | 353 | */ |
| 343 | 354 | enum dprc_region_type { |
| 344 | 355 | DPRC_REGION_TYPE_MC_PORTAL, |
| 345 | − DPRC_REGION_TYPE_QBMAN_PORTAL | |
| 356 | + DPRC_REGION_TYPE_QBMAN_PORTAL, | |
| 357 | + DPRC_REGION_TYPE_QBMAN_MEM_BACKED_PORTAL | |
| 346 | 358 | }; |
| 347 | 359 | |
| 348 | 360 | /** |
| @@ -360,6 +372,7 @@ struct dprc_region_desc { · 11 unmodified lines | ||
| 360 | 372 | u32 size; |
| 361 | 373 | u32 flags; |
| 362 | 374 | enum dprc_region_type type; |
| 375 | + u64 base_address; | |
| 363 | 376 | }; |
| 364 | 377 | |
| 365 | 378 | int dprc_get_obj_region(struct fsl_mc_io *mc_io, |
| @@ -71,6 +71,9 @@ static const char * const clock_names[SYSC_MAX_CLOCKS] = { · 70 unmodified lines | ||
| 71 | 71 | * @name: name if available |
| 72 | 72 | * @revision: interconnect target module revision |
| 73 | 73 | * @needs_resume: runtime resume needed on resume from suspend |
| 74 | + * @clk_enable_quirk: module specific clock enable quirk | |
| 75 | + * @clk_disable_quirk: module specific clock disable quirk | |
| 76 | + * @reset_done_quirk: module specific reset done quirk | |
| 74 | 77 | */ |
| 75 | 78 | struct sysc { |
| 76 | 79 | struct device *dev; |
| @@ -89,10 +92,14 @@ struct sysc { · 12 unmodified lines | ||
| 89 | 92 | struct ti_sysc_cookie cookie; |
| 90 | 93 | const char *name; |
| 91 | 94 | u32 revision; |
| 92 | − bool enabled; | |
| 93 | − bool needs_resume; | |
| 94 | − bool child_needs_resume; | |
| 95 | + unsigned int enabled:1; | |
| 96 | + unsigned int needs_resume:1; | |
| 97 | + unsigned int child_needs_resume:1; | |
| 98 | + unsigned int disable_on_idle:1; | |
| 95 | 99 | struct delayed_work idle_work; |
| 100 | + void (*clk_enable_quirk)(struct sysc *sysc); | |
| 101 | + void (*clk_disable_quirk)(struct sysc *sysc); | |
| 102 | + void (*reset_done_quirk)(struct sysc *sysc); | |
| 96 | 103 | }; |
| 97 | 104 | |
| 98 | 105 | static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np, |
| @@ -100,6 +107,20 @@ static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np, · 1 unmodified line | ||
| 100 | 107 | |
| 101 | 108 | static void sysc_write(struct sysc *ddata, int offset, u32 value) |
| 102 | 109 | { |
| 110 | + if (ddata->cfg.quirks & SYSC_QUIRK_16BIT) { | |
| 111 | + writew_relaxed(value & 0xffff, ddata->module_va + offset); | |
| 112 | + | |
| 113 | + /* Only i2c revision has LO and HI register with stride of 4 */ | |
| 114 | + if (ddata->offsets[SYSC_REVISION] >= 0 && | |
| 115 | + offset == ddata->offsets[SYSC_REVISION]) { | |
| 116 | + u16 hi = value >> 16; | |
| 117 | + | |
| 118 | + writew_relaxed(hi, ddata->module_va + offset + 4); | |
| 119 | + } | |
| 120 | + | |
| 121 | + return; | |
| 122 | + } | |
| 123 | + | |
| 103 | 124 | writel_relaxed(value, ddata->module_va + offset); |
| 104 | 125 | } |
| 105 | 126 | |
| @@ -109,7 +130,14 @@ static u32 sysc_read(struct sysc *ddata, int offset) · 3 unmodified lines | ||
| 109 | 130 | u32 val; |
| 110 | 131 | |
| 111 | 132 | val = readw_relaxed(ddata->module_va + offset); |
| 112 | − val |= (readw_relaxed(ddata->module_va + offset + 4) << 16); | |
| 133 | + | |
| 134 | + /* Only i2c revision has LO and HI register with stride of 4 */ | |
| 135 | + if (ddata->offsets[SYSC_REVISION] >= 0 && | |
| 136 | + offset == ddata->offsets[SYSC_REVISION]) { | |
| 137 | + u16 tmp = readw_relaxed(ddata->module_va + offset + 4); | |
| 138 | + | |
| 139 | + val |= tmp << 16; | |
| 140 | + } | |
| 113 | 141 | |
| 114 | 142 | return val; |
| 115 | 143 | } |
| @@ -132,6 +160,26 @@ static u32 sysc_read_revision(struct sysc *ddata) · 16 unmodified lines | ||
| 132 | 160 | return sysc_read(ddata, offset); |
| 133 | 161 | } |
| 134 | 162 | |
| 163 | +static u32 sysc_read_sysconfig(struct sysc *ddata) | |
| 164 | +{ | |
| 165 | + int offset = ddata->offsets[SYSC_SYSCONFIG]; | |
| 166 | + | |
| 167 | + if (offset < 0) | |
| 168 | + return 0; | |
| 169 | + | |
| 170 | + return sysc_read(ddata, offset); | |
| 171 | +} | |
| 172 | + | |
| 173 | +static u32 sysc_read_sysstatus(struct sysc *ddata) | |
| 174 | +{ | |
| 175 | + int offset = ddata->offsets[SYSC_SYSSTATUS]; | |
| 176 | + | |
| 177 | + if (offset < 0) | |
| 178 | + return 0; | |
| 179 | + | |
| 180 | + return sysc_read(ddata, offset); | |
| 181 | +} | |
| 182 | + | |
| 135 | 183 | static int sysc_add_named_clock_from_child(struct sysc *ddata, |
| 136 | 184 | const char *name, |
| 137 | 185 | const char *optfck_name) |
| @@ -422,6 +470,30 @@ static void sysc_disable_opt_clocks(struct sysc *ddata) · 284 unmodified lines | ||
| 422 | 470 | } |
| 423 | 471 | } |
| 424 | 472 | |
| 473 | +static void sysc_clkdm_deny_idle(struct sysc *ddata) | |
| 474 | +{ | |
| 475 | + struct ti_sysc_platform_data *pdata; | |
| 476 | + | |
| 477 | + if (ddata->legacy_mode) | |
| 478 | + return; | |
| 479 | + | |
| 480 | + pdata = dev_get_platdata(ddata->dev); | |
| 481 | + if (pdata && pdata->clkdm_deny_idle) | |
| 482 | + pdata->clkdm_deny_idle(ddata->dev, &ddata->cookie); | |
| 483 | +} | |
| 484 | + | |
| 485 | +static void sysc_clkdm_allow_idle(struct sysc *ddata) | |
| 486 | +{ | |
| 487 | + struct ti_sysc_platform_data *pdata; | |
| 488 | + | |
| 489 | + if (ddata->legacy_mode) | |
| 490 | + return; | |
| 491 | + | |
| 492 | + pdata = dev_get_platdata(ddata->dev); | |
| 493 | + if (pdata && pdata->clkdm_allow_idle) | |
| 494 | + pdata->clkdm_allow_idle(ddata->dev, &ddata->cookie); | |
| 495 | +} | |
| 496 | + | |
| 425 | 497 | /** |
| 426 | 498 | * sysc_init_resets - init rstctrl reset line if configured |
| 427 | 499 | * @ddata: device driver data |
| @@ -431,7 +503,7 @@ static void sysc_disable_opt_clocks(struct sysc *ddata) · 3 unmodified lines | ||
| 431 | 503 | static int sysc_init_resets(struct sysc *ddata) |
| 432 | 504 | { |
| 433 | 505 | ddata->rsts = |
| 434 | − devm_reset_control_array_get_optional_exclusive(ddata->dev); | |
| 506 | + devm_reset_control_get_optional(ddata->dev, "rstctrl"); | |
| 435 | 507 | if (IS_ERR(ddata->rsts)) |
| 436 | 508 | return PTR_ERR(ddata->rsts); |
| 437 | 509 | |
| @@ -694,8 +766,11 @@ static int sysc_ioremap(struct sysc *ddata) · 256 unmodified lines | ||
| 694 | 766 | ddata->offsets[SYSC_SYSCONFIG], |
| 695 | 767 | ddata->offsets[SYSC_SYSSTATUS]); |
| 696 | 768 | |
| 769 | + if (size < SZ_1K) | |
| 770 | + size = SZ_1K; | |
| 771 | + | |
| 697 | 772 | if ((size + sizeof(u32)) > ddata->module_size) |
| 698 | − return -EINVAL; | |
| 773 | + size = ddata->module_size; | |
| 699 | 774 | } |
| 700 | 775 | |
| 701 | 776 | ddata->module_va = devm_ioremap(ddata->dev, |
| @@ -794,7 +869,9 @@ static void sysc_show_registers(struct sysc *ddata) · 92 unmodified lines | ||
| 794 | 869 | } |
| 795 | 870 | |
| 796 | 871 | #define SYSC_IDLE_MASK (SYSC_NR_IDLEMODES - 1) |
| 872 | +#define SYSC_CLOCACT_ICK 2 | |
| 797 | 873 | |
| 874 | +/* Caller needs to manage sysc_clkdm_deny_idle() and sysc_clkdm_allow_idle() */ | |
| 798 | 875 | static int sysc_enable_module(struct device *dev) |
| 799 | 876 | { |
| 800 | 877 | struct sysc *ddata; |
| @@ -805,23 +882,34 @@ static int sysc_enable_module(struct device *dev) · 4 unmodified lines | ||
| 805 | 882 | if (ddata->offsets[SYSC_SYSCONFIG] == -ENODEV) |
| 806 | 883 | return 0; |
| 807 | 884 | |
| 808 | − /* | |
| 809 | − * TODO: Need to prevent clockdomain autoidle? | |
| 810 | − * See clkdm_deny_idle() in arch/mach-omap2/omap_hwmod.c | |
| 811 | − */ | |
| 812 | − | |
| 813 | 885 | regbits = ddata->cap->regbits; |
| 814 | 886 | reg = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]); |
| 815 | 887 | |
| 888 | + /* Set CLOCKACTIVITY, we only use it for ick */ | |
| 889 | + if (regbits->clkact_shift >= 0 && | |
| 890 | + (ddata->cfg.quirks & SYSC_QUIRK_USE_CLOCKACT || | |
| 891 | + ddata->cfg.sysc_val & BIT(regbits->clkact_shift))) | |
| 892 | + reg |= SYSC_CLOCACT_ICK << regbits->clkact_shift; | |
| 893 | + | |
| 816 | 894 | /* Set SIDLE mode */ |
| 817 | 895 | idlemodes = ddata->cfg.sidlemodes; |
| 818 | 896 | if (!idlemodes || regbits->sidle_shift < 0) |
| 819 | 897 | goto set_midle; |
| 820 | 898 | |
| 821 | − best_mode = fls(ddata->cfg.sidlemodes) - 1; | |
| 822 | − if (best_mode > SYSC_IDLE_MASK) { | |
| 823 | − dev_err(dev, "%s: invalid sidlemode\n", __func__); | |
| 824 | − return -EINVAL; | |
| 899 | + if (ddata->cfg.quirks & (SYSC_QUIRK_SWSUP_SIDLE | | |
| 900 | + SYSC_QUIRK_SWSUP_SIDLE_ACT)) { | |
| 901 | + best_mode = SYSC_IDLE_NO; | |
| 902 | + } else { | |
| 903 | + best_mode = fls(ddata->cfg.sidlemodes) - 1; | |
| 904 | + if (best_mode > SYSC_IDLE_MASK) { | |
| 905 | + dev_err(dev, "%s: invalid sidlemode\n", __func__); | |
| 906 | + return -EINVAL; | |
| 907 | + } | |
| 908 | + | |
| 909 | + /* Set WAKEUP */ | |
| 910 | + if (regbits->enwkup_shift >= 0 && | |
| 911 | + ddata->cfg.sysc_val & BIT(regbits->enwkup_shift)) | |
| 912 | + reg |= BIT(regbits->enwkup_shift); | |
| 825 | 913 | } |
| 826 | 914 | |
| 827 | 915 | reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift); |
| @@ -832,7 +920,7 @@ set_midle: · 4 unmodified lines | ||
| 832 | 920 | /* Set MIDLE mode */ |
| 833 | 921 | idlemodes = ddata->cfg.midlemodes; |
| 834 | 922 | if (!idlemodes || regbits->midle_shift < 0) |
| 835 | − return 0; | |
| 923 | + goto set_autoidle; | |
| 836 | 924 | |
| 837 | 925 | best_mode = fls(ddata->cfg.midlemodes) - 1; |
| 838 | 926 | if (best_mode > SYSC_IDLE_MASK) { |
| @@ -844,6 +932,14 @@ set_midle: · 5 unmodified lines | ||
| 844 | 932 | reg |= best_mode << regbits->midle_shift; |
| 845 | 933 | sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg); |
| 846 | 934 | |
| 935 | +set_autoidle: | |
| 936 | + /* Autoidle bit must enabled separately if available */ | |
| 937 | + if (regbits->autoidle_shift >= 0 && | |
| 938 | + ddata->cfg.sysc_val & BIT(regbits->autoidle_shift)) { | |
| 939 | + reg |= 1 << regbits->autoidle_shift; | |
| 940 | + sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg); | |
| 941 | + } | |
| 942 | + | |
| 847 | 943 | return 0; |
| 848 | 944 | } |
| 849 | 945 | |
| @@ -861,6 +957,7 @@ static int sysc_best_idle_mode(u32 idlemodes, u32 *best_mode) · 11 unmodified lines | ||
| 861 | 957 | return 0; |
| 862 | 958 | } |
| 863 | 959 | |
| 960 | +/* Caller needs to manage sysc_clkdm_deny_idle() and sysc_clkdm_allow_idle() */ | |
| 864 | 961 | static int sysc_disable_module(struct device *dev) |
| 865 | 962 | { |
| 866 | 963 | struct sysc *ddata; |
| @@ -872,11 +969,6 @@ static int sysc_disable_module(struct device *dev) · 5 unmodified lines | ||
| 872 | 969 | if (ddata->offsets[SYSC_SYSCONFIG] == -ENODEV) |
| 873 | 970 | return 0; |
| 874 | 971 | |
| 875 | − /* | |
| 876 | − * TODO: Need to prevent clockdomain autoidle? | |
| 877 | − * See clkdm_deny_idle() in arch/mach-omap2/omap_hwmod.c | |
| 878 | − */ | |
| 879 | − | |
| 880 | 972 | regbits = ddata->cap->regbits; |
| 881 | 973 | reg = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]); |
| 882 | 974 | |
| @@ -901,14 +993,21 @@ set_sidle: · 18 unmodified lines | ||
| 901 | 993 | if (!idlemodes || regbits->sidle_shift < 0) |
| 902 | 994 | return 0; |
| 903 | 995 | |
| 904 | − ret = sysc_best_idle_mode(idlemodes, &best_mode); | |
| 905 | − if (ret) { | |
| 906 | − dev_err(dev, "%s: invalid sidlemode\n", __func__); | |
| 907 | − return ret; | |
| 996 | + if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_SIDLE) { | |
| 997 | + best_mode = SYSC_IDLE_FORCE; | |
| 998 | + } else { | |
| 999 | + ret = sysc_best_idle_mode(idlemodes, &best_mode); | |
| 1000 | + if (ret) { | |
| 1001 | + dev_err(dev, "%s: invalid sidlemode\n", __func__); | |
| 1002 | + return ret; | |
| 1003 | + } | |
| 908 | 1004 | } |
| 909 | 1005 | |
| 910 | 1006 | reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift); |
| 911 | 1007 | reg |= best_mode << regbits->sidle_shift; |
| 1008 | + if (regbits->autoidle_shift >= 0 && | |
| 1009 | + ddata->cfg.sysc_val & BIT(regbits->autoidle_shift)) | |
| 1010 | + reg |= 1 << regbits->autoidle_shift; | |
| 912 | 1011 | sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg); |
| 913 | 1012 | |
| 914 | 1013 | return 0; |
| @@ -932,6 +1031,9 @@ static int __maybe_unused sysc_runtime_suspend_legacy(struct device *dev, · 17 unmodified lines | ||
| 932 | 1031 | dev_err(dev, "%s: could not idle: %i\n", |
| 933 | 1032 | __func__, error); |
| 934 | 1033 | |
| 1034 | + if (ddata->disable_on_idle) | |
| 1035 | + reset_control_assert(ddata->rsts); | |
| 1036 | + | |
| 935 | 1037 | return 0; |
| 936 | 1038 | } |
| 937 | 1039 | |
| @@ -941,6 +1043,9 @@ static int __maybe_unused sysc_runtime_resume_legacy(struct device *dev, · 3 unmodified lines | ||
| 941 | 1043 | struct ti_sysc_platform_data *pdata; |
| 942 | 1044 | int error; |
| 943 | 1045 | |
| 1046 | + if (ddata->disable_on_idle) | |
| 1047 | + reset_control_deassert(ddata->rsts); | |
| 1048 | + | |
| 944 | 1049 | pdata = dev_get_platdata(ddata->dev); |
| 945 | 1050 | if (!pdata) |
| 946 | 1051 | return 0; |
| @@ -966,14 +1071,16 @@ static int __maybe_unused sysc_runtime_suspend(struct device *dev) · 19 unmodified lines | ||
| 966 | 1071 | if (!ddata->enabled) |
| 967 | 1072 | return 0; |
| 968 | 1073 | |
| 1074 | + sysc_clkdm_deny_idle(ddata); | |
| 1075 | + | |
| 969 | 1076 | if (ddata->legacy_mode) { |
| 970 | 1077 | error = sysc_runtime_suspend_legacy(dev, ddata); |
| 971 | 1078 | if (error) |
| 972 | − return error; | |
| 1079 | + goto err_allow_idle; | |
| 973 | 1080 | } else { |
| 974 | 1081 | error = sysc_disable_module(dev); |
| 975 | 1082 | if (error) |
| 976 | − return error; | |
| 1083 | + goto err_allow_idle; | |
| 977 | 1084 | } |
| 978 | 1085 | |
| 979 | 1086 | sysc_disable_main_clocks(ddata); |
| @@ -983,6 +1090,12 @@ static int __maybe_unused sysc_runtime_suspend(struct device *dev) · 3 unmodified lines | ||
| 983 | 1090 | |
| 984 | 1091 | ddata->enabled = false; |
| 985 | 1092 | |
| 1093 | +err_allow_idle: | |
| 1094 | + sysc_clkdm_allow_idle(ddata); | |
| 1095 | + | |
| 1096 | + if (ddata->disable_on_idle) | |
| 1097 | + reset_control_assert(ddata->rsts); | |
| 1098 | + | |
| 986 | 1099 | return error; |
| 987 | 1100 | } |
| 988 | 1101 | |
| @@ -996,10 +1109,15 @@ static int __maybe_unused sysc_runtime_resume(struct device *dev) · 7 unmodified lines | ||
| 996 | 1109 | if (ddata->enabled) |
| 997 | 1110 | return 0; |
| 998 | 1111 | |
| 1112 | + if (ddata->disable_on_idle) | |
| 1113 | + reset_control_deassert(ddata->rsts); | |
| 1114 | + | |
| 1115 | + sysc_clkdm_deny_idle(ddata); | |
| 1116 | + | |
| 999 | 1117 | if (sysc_opt_clks_needed(ddata)) { |
| 1000 | 1118 | error = sysc_enable_opt_clocks(ddata); |
| 1001 | 1119 | if (error) |
| 1002 | − return error; | |
| 1120 | + goto err_allow_idle; | |
| 1003 | 1121 | } |
| 1004 | 1122 | |
| 1005 | 1123 | error = sysc_enable_main_clocks(ddata); |
| @@ -1018,6 +1136,8 @@ static int __maybe_unused sysc_runtime_resume(struct device *dev) · 12 unmodified lines | ||
| 1018 | 1136 | |
| 1019 | 1137 | ddata->enabled = true; |
| 1020 | 1138 | |
| 1139 | + sysc_clkdm_allow_idle(ddata); | |
| 1140 | + | |
| 1021 | 1141 | return 0; |
| 1022 | 1142 | |
| 1023 | 1143 | err_main_clocks: |
| @@ -1025,6 +1145,8 @@ err_main_clocks: · 1 unmodified line | ||
| 1025 | 1145 | err_opt_clocks: |
| 1026 | 1146 | if (sysc_opt_clks_needed(ddata)) |
| 1027 | 1147 | sysc_disable_opt_clocks(ddata); |
| 1148 | +err_allow_idle: | |
| 1149 | + sysc_clkdm_allow_idle(ddata); | |
| 1028 | 1150 | |
| 1029 | 1151 | return error; |
| 1030 | 1152 | } |
| @@ -1106,8 +1228,10 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { · 75 unmodified lines | ||
| 1106 | 1228 | 0), |
| 1107 | 1229 | SYSC_QUIRK("timer", 0, 0, 0x10, -1, 0x4fff1301, 0xffff00ff, |
| 1108 | 1230 | 0), |
| 1231 | + SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000046, 0xffffffff, | |
| 1232 | + SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE), | |
| 1109 | 1233 | SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff, |
| 1110 | − SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE), | |
| 1234 | + SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE), | |
| 1111 | 1235 | /* Uarts on omap4 and later */ |
| 1112 | 1236 | SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x50411e03, 0xffff00ff, |
| 1113 | 1237 | SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE), |
| @@ -1119,6 +1243,22 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { · 5 unmodified lines | ||
| 1119 | 1243 | SYSC_QUIRK_EXT_OPT_CLOCK | SYSC_QUIRK_NO_RESET_ON_INIT | |
| 1120 | 1244 | SYSC_QUIRK_SWSUP_SIDLE), |
| 1121 | 1245 | |
| 1246 | + /* Quirks that need to be set based on detected module */ | |
| 1247 | + SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff, | |
| 1248 | + SYSC_MODULE_QUIRK_HDQ1W), | |
| 1249 | + SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x0000000a, 0xffffffff, | |
| 1250 | + SYSC_MODULE_QUIRK_HDQ1W), | |
| 1251 | + SYSC_QUIRK("i2c", 0, 0, 0x20, 0x10, 0x00000036, 0x000000ff, | |
| 1252 | + SYSC_MODULE_QUIRK_I2C), | |
| 1253 | + SYSC_QUIRK("i2c", 0, 0, 0x20, 0x10, 0x0000003c, 0x000000ff, | |
| 1254 | + SYSC_MODULE_QUIRK_I2C), | |
| 1255 | + SYSC_QUIRK("i2c", 0, 0, 0x20, 0x10, 0x00000040, 0x000000ff, | |
| 1256 | + SYSC_MODULE_QUIRK_I2C), | |
| 1257 | + SYSC_QUIRK("i2c", 0, 0, 0x10, 0x90, 0x5040000a, 0xfffff0f0, | |
| 1258 | + SYSC_MODULE_QUIRK_I2C), | |
| 1259 | + SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0, | |
| 1260 | + SYSC_MODULE_QUIRK_WDT), | |
| 1261 | + | |
| 1122 | 1262 | #ifdef DEBUG |
| 1123 | 1263 | SYSC_QUIRK("adc", 0, 0, 0x10, -1, 0x47300001, 0xffffffff, 0), |
| 1124 | 1264 | SYSC_QUIRK("atl", 0, 0, -1, -1, 0x0a070100, 0xffffffff, 0), |
| @@ -1132,11 +1272,8 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { · 7 unmodified lines | ||
| 1132 | 1272 | SYSC_QUIRK("dwc3", 0, 0, 0x10, -1, 0x500a0200, 0xffffffff, 0), |
| 1133 | 1273 | SYSC_QUIRK("epwmss", 0, 0, 0x4, -1, 0x47400001, 0xffffffff, 0), |
| 1134 | 1274 | SYSC_QUIRK("gpu", 0, 0x1fc00, 0x1fc10, -1, 0, 0, 0), |
| 1135 | − SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff, 0), | |
| 1136 | − SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x0000000a, 0xffffffff, 0), | |
| 1137 | 1275 | SYSC_QUIRK("hsi", 0, 0, 0x10, 0x14, 0x50043101, 0xffffffff, 0), |
| 1138 | 1276 | SYSC_QUIRK("iss", 0, 0, 0x10, -1, 0x40000101, 0xffffffff, 0), |
| 1139 | − SYSC_QUIRK("i2c", 0, 0, 0x10, 0x90, 0x5040000a, 0xfffff0f0, 0), | |
| 1140 | 1277 | SYSC_QUIRK("lcdc", 0, 0, 0x54, -1, 0x4f201000, 0xffffffff, 0), |
| 1141 | 1278 | SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44306302, 0xffffffff, 0), |
| 1142 | 1279 | SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44307b02, 0xffffffff, 0), |
| @@ -1172,7 +1309,6 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { · 29 unmodified lines | ||
| 1172 | 1309 | SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -1, 0x50700101, 0xffffffff, 0), |
| 1173 | 1310 | SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050, |
| 1174 | 1311 | 0xffffffff, 0), |
| 1175 | − SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0, 0), | |
| 1176 | 1312 | SYSC_QUIRK("vfpe", 0, 0, 0x104, -1, 0x4d001200, 0xffffffff, 0), |
| 1177 | 1313 | #endif |
| 1178 | 1314 | }; |
| @@ -1245,6 +1381,121 @@ static void sysc_init_revision_quirks(struct sysc *ddata) · 66 unmodified lines | ||
| 1245 | 1381 | } |
| 1246 | 1382 | } |
| 1247 | 1383 | |
| 1384 | +/* 1-wire needs module's internal clocks enabled for reset */ | |
| 1385 | +static void sysc_clk_enable_quirk_hdq1w(struct sysc *ddata) | |
| 1386 | +{ | |
| 1387 | + int offset = 0x0c; /* HDQ_CTRL_STATUS */ | |
| 1388 | + u16 val; | |
| 1389 | + | |
| 1390 | + val = sysc_read(ddata, offset); | |
| 1391 | + val |= BIT(5); | |
| 1392 | + sysc_write(ddata, offset, val); | |
| 1393 | +} | |
| 1394 | + | |
| 1395 | +/* I2C needs extra enable bit toggling for reset */ | |
| 1396 | +static void sysc_clk_quirk_i2c(struct sysc *ddata, bool enable) | |
| 1397 | +{ | |
| 1398 | + int offset; | |
| 1399 | + u16 val; | |
| 1400 | + | |
| 1401 | + /* I2C_CON, omap2/3 is different from omap4 and later */ | |
| 1402 | + if ((ddata->revision & 0xffffff00) == 0x001f0000) | |
| 1403 | + offset = 0x24; | |
| 1404 | + else | |
| 1405 | + offset = 0xa4; | |
| 1406 | + | |
| 1407 | + /* I2C_EN */ | |
| 1408 | + val = sysc_read(ddata, offset); | |
| 1409 | + if (enable) | |
| 1410 | + val |= BIT(15); | |
| 1411 | + else | |
| 1412 | + val &= ~BIT(15); | |
| 1413 | + sysc_write(ddata, offset, val); | |
| 1414 | +} | |
| 1415 | + | |
| 1416 | +static void sysc_clk_enable_quirk_i2c(struct sysc *ddata) | |
| 1417 | +{ | |
| 1418 | + sysc_clk_quirk_i2c(ddata, true); | |
| 1419 | +} | |
| 1420 | + | |
| 1421 | +static void sysc_clk_disable_quirk_i2c(struct sysc *ddata) | |
| 1422 | +{ | |
| 1423 | + sysc_clk_quirk_i2c(ddata, false); | |
| 1424 | +} | |
| 1425 | + | |
| 1426 | +/* Watchdog timer needs a disable sequence after reset */ | |
| 1427 | +static void sysc_reset_done_quirk_wdt(struct sysc *ddata) | |
| 1428 | +{ | |
| 1429 | + int wps, spr, error; | |
| 1430 | + u32 val; | |
| 1431 | + | |
| 1432 | + wps = 0x34; | |
| 1433 | + spr = 0x48; | |
| 1434 | + | |
| 1435 | + sysc_write(ddata, spr, 0xaaaa); | |
| 1436 | + error = readl_poll_timeout(ddata->module_va + wps, val, | |
| 1437 | + !(val & 0x10), 100, | |
| 1438 | + MAX_MODULE_SOFTRESET_WAIT); | |
| 1439 | + if (error) | |
| 1440 | + dev_warn(ddata->dev, "wdt disable spr failed\n"); | |
| 1441 | + | |
| 1442 | + sysc_write(ddata, wps, 0x5555); | |
| 1443 | + error = readl_poll_timeout(ddata->module_va + wps, val, | |
| 1444 | + !(val & 0x10), 100, | |
| 1445 | + MAX_MODULE_SOFTRESET_WAIT); | |
| 1446 | + if (error) | |
| 1447 | + dev_warn(ddata->dev, "wdt disable wps failed\n"); | |
| 1448 | +} | |
| 1449 | + | |
| 1450 | +static void sysc_init_module_quirks(struct sysc *ddata) | |
| 1451 | +{ | |
| 1452 | + if (ddata->legacy_mode || !ddata->name) | |
| 1453 | + return; | |
| 1454 | + | |
| 1455 | + if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_HDQ1W) { | |
| 1456 | + ddata->clk_enable_quirk = sysc_clk_enable_quirk_hdq1w; | |
| 1457 | + | |
| 1458 | + return; | |
| 1459 | + } | |
| 1460 | + | |
| 1461 | + if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_I2C) { | |
| 1462 | + ddata->clk_enable_quirk = sysc_clk_enable_quirk_i2c; | |
| 1463 | + ddata->clk_disable_quirk = sysc_clk_disable_quirk_i2c; | |
| 1464 | + | |
| 1465 | + return; | |
| 1466 | + } | |
| 1467 | + | |
| 1468 | + if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_WDT) | |
| 1469 | + ddata->reset_done_quirk = sysc_reset_done_quirk_wdt; | |
| 1470 | +} | |
| 1471 | + | |
| 1472 | +static int sysc_clockdomain_init(struct sysc *ddata) | |
| 1473 | +{ | |
| 1474 | + struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev); | |
| 1475 | + struct clk *fck = NULL, *ick = NULL; | |
| 1476 | + int error; | |
| 1477 | + | |
| 1478 | + if (!pdata || !pdata->init_clockdomain) | |
| 1479 | + return 0; | |
| 1480 | + | |
| 1481 | + switch (ddata->nr_clocks) { | |
| 1482 | + case 2: | |
| 1483 | + ick = ddata->clocks[SYSC_ICK]; | |
| 1484 | + /* fallthrough */ | |
| 1485 | + case 1: | |
| 1486 | + fck = ddata->clocks[SYSC_FCK]; | |
| 1487 | + break; | |
| 1488 | + case 0: | |
| 1489 | + return 0; | |
| 1490 | + } | |
| 1491 | + | |
| 1492 | + error = pdata->init_clockdomain(ddata->dev, fck, ick, &ddata->cookie); | |
| 1493 | + if (!error || error == -ENODEV) | |
| 1494 | + return 0; | |
| 1495 | + | |
| 1496 | + return error; | |
| 1497 | +} | |
| 1498 | + | |
| 1248 | 1499 | /* |
| 1249 | 1500 | * Note that pdata->init_module() typically does a reset first. After |
| 1250 | 1501 | * pdata->init_module() is done, PM runtime can be used for the interconnect |
| @@ -1255,7 +1506,7 @@ static int sysc_legacy_init(struct sysc *ddata) · 4 unmodified lines | ||
| 1255 | 1506 | struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev); |
| 1256 | 1507 | int error; |
| 1257 | 1508 | |
| 1258 | − if (!ddata->legacy_mode || !pdata || !pdata->init_module) | |
| 1509 | + if (!pdata || !pdata->init_module) | |
| 1259 | 1510 | return 0; |
| 1260 | 1511 | |
| 1261 | 1512 | error = pdata->init_module(ddata->dev, ddata->mdata, &ddata->cookie); |
| @@ -1280,7 +1531,7 @@ static int sysc_legacy_init(struct sysc *ddata) · 18 unmodified lines | ||
| 1280 | 1531 | */ |
| 1281 | 1532 | static int sysc_rstctrl_reset_deassert(struct sysc *ddata, bool reset) |
| 1282 | 1533 | { |
| 1283 | − int error; | |
| 1534 | + int error, val; | |
| 1284 | 1535 | |
| 1285 | 1536 | if (!ddata->rsts) |
| 1286 | 1537 | return 0; |
| @@ -1291,37 +1542,68 @@ static int sysc_rstctrl_reset_deassert(struct sysc *ddata, bool reset) · 4 unmodified lines | ||
| 1291 | 1542 | return error; |
| 1292 | 1543 | } |
| 1293 | 1544 | |
| 1294 | − return reset_control_deassert(ddata->rsts); | |
| 1545 | + error = reset_control_deassert(ddata->rsts); | |
| 1546 | + if (error == -EEXIST) | |
| 1547 | + return 0; | |
| 1548 | + | |
| 1549 | + error = readx_poll_timeout(reset_control_status, ddata->rsts, val, | |
| 1550 | + val == 0, 100, MAX_MODULE_SOFTRESET_WAIT); | |
| 1551 | + | |
| 1552 | + return error; | |
| 1295 | 1553 | } |
| 1296 | 1554 | |
| 1555 | +/* | |
| 1556 | + * Note that the caller must ensure the interconnect target module is enabled | |
| 1557 | + * before calling reset. Otherwise reset will not complete. | |
| 1558 | + */ | |
| 1297 | 1559 | static int sysc_reset(struct sysc *ddata) |
| 1298 | 1560 | { |
| 1299 | − int offset = ddata->offsets[SYSC_SYSCONFIG]; | |
| 1300 | − int val; | |
| 1561 | + int sysc_offset, syss_offset, sysc_val, rstval, quirks, error = 0; | |
| 1562 | + u32 sysc_mask, syss_done; | |
| 1563 | + | |
| 1564 | + sysc_offset = ddata->offsets[SYSC_SYSCONFIG]; | |
| 1565 | + syss_offset = ddata->offsets[SYSC_SYSSTATUS]; | |
| 1566 | + quirks = ddata->cfg.quirks; | |
| 1301 | 1567 | |
| 1302 | − if (ddata->legacy_mode || offset < 0 || | |
| 1568 | + if (ddata->legacy_mode || sysc_offset < 0 || | |
| 1569 | + ddata->cap->regbits->srst_shift < 0 || | |
| 1303 | 1570 | ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT) |
| 1304 | 1571 | return 0; |
| 1305 | 1572 | |
| 1306 | − /* | |
| 1307 | − * Currently only support reset status in sysstatus. | |
| 1308 | − * Warn and return error in all other cases | |
| 1309 | − */ | |
| 1310 | − if (!ddata->cfg.syss_mask) { | |
| 1311 | − dev_err(ddata->dev, "No ti,syss-mask. Reset failed\n"); | |
| 1312 | − return -EINVAL; | |
| 1313 | − } | |
| 1573 | + sysc_mask = BIT(ddata->cap->regbits->srst_shift); | |
| 1314 | 1574 | |
| 1315 | − val = sysc_read(ddata, offset); | |
| 1316 | − val |= (0x1 << ddata->cap->regbits->srst_shift); | |
| 1317 | − sysc_write(ddata, offset, val); | |
| 1575 | + if (ddata->cfg.quirks & SYSS_QUIRK_RESETDONE_INVERTED) | |
| 1576 | + syss_done = 0; | |
| 1577 | + else | |
| 1578 | + syss_done = ddata->cfg.syss_mask; | |
| 1579 | + | |
| 1580 | + if (ddata->clk_disable_quirk) | |
| 1581 | + ddata->clk_disable_quirk(ddata); | |
| 1582 | + | |
| 1583 | + sysc_val = sysc_read_sysconfig(ddata); | |
| 1584 | + sysc_val |= sysc_mask; | |
| 1585 | + sysc_write(ddata, sysc_offset, sysc_val); | |
| 1586 | + | |
| 1587 | + if (ddata->clk_enable_quirk) | |
| 1588 | + ddata->clk_enable_quirk(ddata); | |
| 1318 | 1589 | |
| 1319 | 1590 | /* Poll on reset status */ |
| 1320 | − offset = ddata->offsets[SYSC_SYSSTATUS]; | |
| 1591 | + if (syss_offset >= 0) { | |
| 1592 | + error = readx_poll_timeout(sysc_read_sysstatus, ddata, rstval, | |
| 1593 | + (rstval & ddata->cfg.syss_mask) == | |
| 1594 | + syss_done, | |
| 1595 | + 100, MAX_MODULE_SOFTRESET_WAIT); | |
| 1596 | + | |
| 1597 | + } else if (ddata->cfg.quirks & SYSC_QUIRK_RESET_STATUS) { | |
| 1598 | + error = readx_poll_timeout(sysc_read_sysconfig, ddata, rstval, | |
| 1599 | + !(rstval & sysc_mask), | |
| 1600 | + 100, MAX_MODULE_SOFTRESET_WAIT); | |
| 1601 | + } | |
| 1602 | + | |
| 1603 | + if (ddata->reset_done_quirk) | |
| 1604 | + ddata->reset_done_quirk(ddata); | |
| 1321 | 1605 | |
| 1322 | − return readl_poll_timeout(ddata->module_va + offset, val, | |
| 1323 | − (val & ddata->cfg.syss_mask) == 0x0, | |
| 1324 | − 100, MAX_MODULE_SOFTRESET_WAIT); | |
| 1606 | + return error; | |
| 1325 | 1607 | } |
| 1326 | 1608 | |
| 1327 | 1609 | /* |
| @@ -1334,12 +1616,8 @@ static int sysc_init_module(struct sysc *ddata) · 6 unmodified lines | ||
| 1334 | 1616 | { |
| 1335 | 1617 | int error = 0; |
| 1336 | 1618 | bool manage_clocks = true; |
| 1337 | − bool reset = true; | |
| 1338 | − | |
| 1339 | − if (ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT) | |
| 1340 | − reset = false; | |
| 1341 | 1619 | |
| 1342 | − error = sysc_rstctrl_reset_deassert(ddata, reset); | |
| 1620 | + error = sysc_rstctrl_reset_deassert(ddata, false); | |
| 1343 | 1621 | if (error) |
| 1344 | 1622 | return error; |
| 1345 | 1623 | |
| @@ -1347,7 +1625,13 @@ static int sysc_init_module(struct sysc *ddata) · 1 unmodified line | ||
| 1347 | 1625 | (SYSC_QUIRK_NO_IDLE | SYSC_QUIRK_NO_IDLE_ON_INIT)) |
| 1348 | 1626 | manage_clocks = false; |
| 1349 | 1627 | |
| 1628 | + error = sysc_clockdomain_init(ddata); | |
| 1629 | + if (error) | |
| 1630 | + return error; | |
| 1631 | + | |
| 1350 | 1632 | if (manage_clocks) { |
| 1633 | + sysc_clkdm_deny_idle(ddata); | |
| 1634 | + | |
| 1351 | 1635 | error = sysc_enable_opt_clocks(ddata); |
| 1352 | 1636 | if (error) |
| 1353 | 1637 | return error; |
| @@ -1357,23 +1641,43 @@ static int sysc_init_module(struct sysc *ddata) · 3 unmodified lines | ||
| 1357 | 1641 | goto err_opt_clocks; |
| 1358 | 1642 | } |
| 1359 | 1643 | |
| 1644 | + if (!(ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)) { | |
| 1645 | + error = sysc_rstctrl_reset_deassert(ddata, true); | |
| 1646 | + if (error) | |
| 1647 | + goto err_main_clocks; | |
| 1648 | + } | |
| 1649 | + | |
| 1360 | 1650 | ddata->revision = sysc_read_revision(ddata); |
| 1361 | 1651 | sysc_init_revision_quirks(ddata); |
| 1652 | + sysc_init_module_quirks(ddata); | |
| 1362 | 1653 | |
| 1363 | − error = sysc_legacy_init(ddata); | |
| 1364 | − if (error) | |
| 1365 | − goto err_main_clocks; | |
| 1654 | + if (ddata->legacy_mode) { | |
| 1655 | + error = sysc_legacy_init(ddata); | |
| 1656 | + if (error) | |
| 1657 | + goto err_main_clocks; | |
| 1658 | + } | |
| 1659 | + | |
| 1660 | + if (!ddata->legacy_mode && manage_clocks) { | |
| 1661 | + error = sysc_enable_module(ddata->dev); | |
| 1662 | + if (error) | |
| 1663 | + goto err_main_clocks; | |
| 1664 | + } | |
| 1366 | 1665 | |
| 1367 | 1666 | error = sysc_reset(ddata); |
| 1368 | 1667 | if (error) |
| 1369 | 1668 | dev_err(ddata->dev, "Reset failed with %d\n", error); |
| 1370 | 1669 | |
| 1670 | + if (!ddata->legacy_mode && manage_clocks) | |
| 1671 | + sysc_disable_module(ddata->dev); | |
| 1672 | + | |
| 1371 | 1673 | err_main_clocks: |
| 1372 | 1674 | if (manage_clocks) |
| 1373 | 1675 | sysc_disable_main_clocks(ddata); |
| 1374 | 1676 | err_opt_clocks: |
| 1375 | − if (manage_clocks) | |
| 1677 | + if (manage_clocks) { | |
| 1376 | 1678 | sysc_disable_opt_clocks(ddata); |
| 1679 | + sysc_clkdm_allow_idle(ddata); | |
| 1680 | + } | |
| 1377 | 1681 | |
| 1378 | 1682 | return error; |
| 1379 | 1683 | } |
| @@ -1663,9 +1967,6 @@ static struct dev_pm_domain sysc_child_pm_domain = { · 283 unmodified lines | ||
| 1663 | 1967 | */ |
| 1664 | 1968 | static void sysc_legacy_idle_quirk(struct sysc *ddata, struct device *child) |
| 1665 | 1969 | { |
| 1666 | − if (!ddata->legacy_mode) | |
| 1667 | − return; | |
| 1668 | − | |
| 1669 | 1970 | if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE) |
| 1670 | 1971 | dev_pm_domain_set(child, &sysc_child_pm_domain); |
| 1671 | 1972 | } |
| @@ -2005,6 +2306,7 @@ static const struct sysc_capabilities sysc_dra7_mcan = { · 333 unmodified lines | ||
| 2005 | 2306 | .type = TI_SYSC_DRA7_MCAN, |
| 2006 | 2307 | .sysc_mask = SYSC_DRA7_MCAN_ENAWAKEUP | SYSC_OMAP4_SOFTRESET, |
| 2007 | 2308 | .regbits = &sysc_regbits_dra7_mcan, |
| 2309 | + .mod_quirks = SYSS_QUIRK_RESETDONE_INVERTED, | |
| 2008 | 2310 | }; |
| 2009 | 2311 | |
| 2010 | 2312 | static int sysc_init_pdata(struct sysc *ddata) |
| @@ -2012,20 +2314,22 @@ static int sysc_init_pdata(struct sysc *ddata) · 1 unmodified line | ||
| 2012 | 2314 | struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev); |
| 2013 | 2315 | struct ti_sysc_module_data *mdata; |
| 2014 | 2316 | |
| 2015 | − if (!pdata || !ddata->legacy_mode) | |
| 2317 | + if (!pdata) | |
| 2016 | 2318 | return 0; |
| 2017 | 2319 | |
| 2018 | 2320 | mdata = devm_kzalloc(ddata->dev, sizeof(*mdata), GFP_KERNEL); |
| 2019 | 2321 | if (!mdata) |
| 2020 | 2322 | return -ENOMEM; |
| 2021 | 2323 | |
| 2022 | − mdata->name = ddata->legacy_mode; | |
| 2023 | − mdata->module_pa = ddata->module_pa; | |
| 2024 | − mdata->module_size = ddata->module_size; | |
| 2025 | − mdata->offsets = ddata->offsets; | |
| 2026 | − mdata->nr_offsets = SYSC_MAX_REGS; | |
| 2027 | − mdata->cap = ddata->cap; | |
| 2028 | − mdata->cfg = &ddata->cfg; | |
| 2324 | + if (ddata->legacy_mode) { | |
| 2325 | + mdata->name = ddata->legacy_mode; | |
| 2326 | + mdata->module_pa = ddata->module_pa; | |
| 2327 | + mdata->module_size = ddata->module_size; | |
| 2328 | + mdata->offsets = ddata->offsets; | |
| 2329 | + mdata->nr_offsets = SYSC_MAX_REGS; | |
| 2330 | + mdata->cap = ddata->cap; | |
| 2331 | + mdata->cfg = &ddata->cfg; | |
| 2332 | + } | |
| 2029 | 2333 | |
| 2030 | 2334 | ddata->mdata = mdata; |
| 2031 | 2335 | |
| @@ -2145,7 +2449,7 @@ static int sysc_probe(struct platform_device *pdev) · 113 unmodified lines | ||
| 2145 | 2449 | } |
| 2146 | 2450 | |
| 2147 | 2451 | if (!of_get_available_child_count(ddata->dev->of_node)) |
| 2148 | − reset_control_assert(ddata->rsts); | |
| 2452 | + ddata->disable_on_idle = true; | |
| 2149 | 2453 | |
| 2150 | 2454 | return 0; |
| 2151 | 2455 | |
| @@ -185,6 +185,8 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id, · 184 unmodified lines | ||
| 185 | 185 | if (rate_discrete) |
| 186 | 186 | clk->list.num_rates = tot_rate_cnt; |
| 187 | 187 | |
| 188 | + clk->rate_discrete = rate_discrete; | |
| 189 | + | |
| 188 | 190 | err: |
| 189 | 191 | scmi_xfer_put(handle, t); |
| 190 | 192 | return ret; |
| @@ -30,10 +30,12 @@ struct scmi_msg_resp_sensor_description { · 29 unmodified lines | ||
| 30 | 30 | __le32 id; |
| 31 | 31 | __le32 attributes_low; |
| 32 | 32 | #define SUPPORTS_ASYNC_READ(x) ((x) & BIT(31)) |
| 33 | −#define NUM_TRIP_POINTS(x) (((x) >> 4) & 0xff) | |
| 33 | +#define NUM_TRIP_POINTS(x) ((x) & 0xff) | |
| 34 | 34 | __le32 attributes_high; |
| 35 | 35 | #define SENSOR_TYPE(x) ((x) & 0xff) |
| 36 | −#define SENSOR_SCALE(x) (((x) >> 11) & 0x3f) | |
| 36 | +#define SENSOR_SCALE(x) (((x) >> 11) & 0x1f) | |
| 37 | +#define SENSOR_SCALE_SIGN BIT(4) | |
| 38 | +#define SENSOR_SCALE_EXTEND GENMASK(7, 5) | |
| 37 | 39 | #define SENSOR_UPDATE_SCALE(x) (((x) >> 22) & 0x1f) |
| 38 | 40 | #define SENSOR_UPDATE_BASE(x) (((x) >> 27) & 0x1f) |
| 39 | 41 | u8 name[SCMI_MAX_STR_SIZE]; |
| @@ -140,6 +142,10 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle, · 100 unmodified lines | ||
| 140 | 142 | s = &si->sensors[desc_index + cnt]; |
| 141 | 143 | s->id = le32_to_cpu(buf->desc[cnt].id); |
| 142 | 144 | s->type = SENSOR_TYPE(attrh); |
| 145 | + s->scale = SENSOR_SCALE(attrh); | |
| 146 | + /* Sign extend to a full s8 */ | |
| 147 | + if (s->scale & SENSOR_SCALE_SIGN) | |
| 148 | + s->scale |= SENSOR_SCALE_EXTEND; | |
| 143 | 149 | strlcpy(s->name, buf->desc[cnt].name, SCMI_MAX_STR_SIZE); |
| 144 | 150 | } |
| 145 | 151 | |
| @@ -359,16 +359,16 @@ static int suspend_test_thread(void *arg) · 358 unmodified lines | ||
| 359 | 359 | for (;;) { |
| 360 | 360 | /* Needs to be set first to avoid missing a wakeup. */ |
| 361 | 361 | set_current_state(TASK_INTERRUPTIBLE); |
| 362 | − if (kthread_should_stop()) { | |
| 363 | − __set_current_state(TASK_RUNNING); | |
| 362 | + if (kthread_should_park()) | |
| 364 | 363 | break; |
| 365 | − } | |
| 366 | 364 | schedule(); |
| 367 | 365 | } |
| 368 | 366 | |
| 369 | 367 | pr_info("CPU %d suspend test results: success %d, shallow states %d, errors %d\n", |
| 370 | 368 | cpu, nb_suspend, nb_shallow_sleep, nb_err); |
| 371 | 369 | |
| 370 | + kthread_parkme(); | |
| 371 | + | |
| 372 | 372 | return nb_err; |
| 373 | 373 | } |
| 374 | 374 | |
| @@ -433,8 +433,10 @@ static int suspend_tests(void) · 58 unmodified lines | ||
| 433 | 433 | |
| 434 | 434 | |
| 435 | 435 | /* Stop and destroy all threads, get return status. */ |
| 436 | − for (i = 0; i < nb_threads; ++i) | |
| 436 | + for (i = 0; i < nb_threads; ++i) { | |
| 437 | + err += kthread_park(threads[i]); | |
| 437 | 438 | err += kthread_stop(threads[i]); |
| 439 | + } | |
| 438 | 440 | out: |
| 439 | 441 | cpuidle_resume_and_unlock(); |
| 440 | 442 | kfree(threads); |
| @@ -803,7 +803,9 @@ static int __maybe_unused tegra_bpmp_resume(struct device *dev) · 802 unmodified lines | ||
| 803 | 803 | return 0; |
| 804 | 804 | } |
| 805 | 805 | |
| 806 | −static SIMPLE_DEV_PM_OPS(tegra_bpmp_pm_ops, NULL, tegra_bpmp_resume); | |
| 806 | +static const struct dev_pm_ops tegra_bpmp_pm_ops = { | |
| 807 | + .resume_early = tegra_bpmp_resume, | |
| 808 | +}; | |
| 807 | 809 | |
| 808 | 810 | #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \ |
| 809 | 811 | IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) |
| @@ -466,9 +466,9 @@ static int ti_sci_cmd_get_revision(struct ti_sci_info *info) · 465 unmodified lines | ||
| 466 | 466 | struct ti_sci_xfer *xfer; |
| 467 | 467 | int ret; |
| 468 | 468 | |
| 469 | − /* No need to setup flags since it is expected to respond */ | |
| 470 | 469 | xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_VERSION, |
| 471 | − 0x0, sizeof(struct ti_sci_msg_hdr), | |
| 470 | + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | |
| 471 | + sizeof(struct ti_sci_msg_hdr), | |
| 472 | 472 | sizeof(*rev_info)); |
| 473 | 473 | if (IS_ERR(xfer)) { |
| 474 | 474 | ret = PTR_ERR(xfer); |
| @@ -596,9 +596,9 @@ static int ti_sci_get_device_state(const struct ti_sci_handle *handle, · 121 unmodified lines | ||
| 596 | 596 | info = handle_to_ti_sci_info(handle); |
| 597 | 597 | dev = info->dev; |
| 598 | 598 | |
| 599 | − /* Response is expected, so need of any flags */ | |
| 600 | 599 | xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_GET_DEVICE_STATE, |
| 601 | − 0, sizeof(*req), sizeof(*resp)); | |
| 600 | + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | |
| 601 | + sizeof(*req), sizeof(*resp)); | |
| 602 | 602 | if (IS_ERR(xfer)) { |
| 603 | 603 | ret = PTR_ERR(xfer); |
| 604 | 604 | dev_err(dev, "Message alloc failed(%d)\n", ret); |
| @@ -2057,122 +2057,175 @@ static int ti_sci_cmd_free_event_map(const struct ti_sci_handle *handle, · 1452 unmodified lines | ||
| 2057 | 2057 | ia_id, vint, global_event, vint_status_bit, 0); |
| 2058 | 2058 | } |
| 2059 | 2059 | |
| 2060 | −/* | |
| 2061 | − * ti_sci_setup_ops() - Setup the operations structures | |
| 2062 | − * @info: pointer to TISCI pointer | |
| 2060 | +/** | |
| 2061 | + * ti_sci_cmd_ring_config() - configure RA ring | |
| 2062 | + * @handle: Pointer to TI SCI handle. | |
| 2063 | + * @valid_params: Bitfield defining validity of ring configuration | |
| 2064 | + * parameters | |
| 2065 | + * @nav_id: Device ID of Navigator Subsystem from which the ring is | |
| 2066 | + * allocated | |
| 2067 | + * @index: Ring index | |
| 2068 | + * @addr_lo: The ring base address lo 32 bits | |
| 2069 | + * @addr_hi: The ring base address hi 32 bits | |
| 2070 | + * @count: Number of ring elements | |
| 2071 | + * @mode: The mode of the ring | |
| 2072 | + * @size: The ring element size. | |
| 2073 | + * @order_id: Specifies the ring's bus order ID | |
| 2074 | + * | |
| 2075 | + * Return: 0 if all went well, else returns appropriate error value. | |
| 2076 | + * | |
| 2077 | + * See @ti_sci_msg_rm_ring_cfg_req for more info. | |
| 2063 | 2078 | */ |
| 2064 | −static void ti_sci_setup_ops(struct ti_sci_info *info) | |
| 2079 | +static int ti_sci_cmd_ring_config(const struct ti_sci_handle *handle, | |
| 2080 | + u32 valid_params, u16 nav_id, u16 index, | |
| 2081 | + u32 addr_lo, u32 addr_hi, u32 count, | |
| 2082 | + u8 mode, u8 size, u8 order_id) | |
| 2065 | 2083 | { |
| 2066 | − struct ti_sci_ops *ops = &info->handle.ops; | |
| 2067 | − struct ti_sci_core_ops *core_ops = &ops->core_ops; | |
| 2068 | − struct ti_sci_dev_ops *dops = &ops->dev_ops; | |
| 2069 | − struct ti_sci_clk_ops *cops = &ops->clk_ops; | |
| 2070 | − struct ti_sci_rm_core_ops *rm_core_ops = &ops->rm_core_ops; | |
| 2071 | − struct ti_sci_rm_irq_ops *iops = &ops->rm_irq_ops; | |
| 2072 | − | |
| 2073 | − core_ops->reboot_device = ti_sci_cmd_core_reboot; | |
| 2074 | − | |
| 2075 | − dops->get_device = ti_sci_cmd_get_device; | |
| 2076 | − dops->idle_device = ti_sci_cmd_idle_device; | |
| 2077 | − dops->put_device = ti_sci_cmd_put_device; | |
| 2084 | + struct ti_sci_msg_rm_ring_cfg_req *req; | |
| 2085 | + struct ti_sci_msg_hdr *resp; | |
| 2086 | + struct ti_sci_xfer *xfer; | |
| 2087 | + struct ti_sci_info *info; | |
| 2088 | + struct device *dev; | |
| 2089 | + int ret = 0; | |
| 2078 | 2090 | |
| 2079 | − dops->is_valid = ti_sci_cmd_dev_is_valid; | |
| 2080 | − dops->get_context_loss_count = ti_sci_cmd_dev_get_clcnt; | |
| 2081 | − dops->is_idle = ti_sci_cmd_dev_is_idle; | |
| 2082 | − dops->is_stop = ti_sci_cmd_dev_is_stop; | |
| 2083 | − dops->is_on = ti_sci_cmd_dev_is_on; | |
| 2084 | − dops->is_transitioning = ti_sci_cmd_dev_is_trans; | |
| 2085 | − dops->set_device_resets = ti_sci_cmd_set_device_resets; | |
| 2086 | − dops->get_device_resets = ti_sci_cmd_get_device_resets; | |
| 2091 | + if (IS_ERR_OR_NULL(handle)) | |
| 2092 | + return -EINVAL; | |
| 2087 | 2093 | |
| 2088 | − cops->get_clock = ti_sci_cmd_get_clock; | |
| 2089 | − cops->idle_clock = ti_sci_cmd_idle_clock; | |
| 2090 | − cops->put_clock = ti_sci_cmd_put_clock; | |
| 2091 | − cops->is_auto = ti_sci_cmd_clk_is_auto; | |
| 2092 | − cops->is_on = ti_sci_cmd_clk_is_on; | |
| 2093 | − cops->is_off = ti_sci_cmd_clk_is_off; | |
| 2094 | + info = handle_to_ti_sci_info(handle); | |
| 2095 | + dev = info->dev; | |
| 2094 | 2096 | |
| 2095 | − cops->set_parent = ti_sci_cmd_clk_set_parent; | |
| 2096 | − cops->get_parent = ti_sci_cmd_clk_get_parent; | |
| 2097 | − cops->get_num_parents = ti_sci_cmd_clk_get_num_parents; | |
| 2097 | + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_RM_RING_CFG, | |
| 2098 | + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | |
| 2099 | + sizeof(*req), sizeof(*resp)); | |
| 2100 | + if (IS_ERR(xfer)) { | |
| 2101 | + ret = PTR_ERR(xfer); | |
| 2102 | + dev_err(dev, "RM_RA:Message config failed(%d)\n", ret); | |
| 2103 | + return ret; | |
| 2104 | + } | |
| 2105 | + req = (struct ti_sci_msg_rm_ring_cfg_req *)xfer->xfer_buf; | |
| 2106 | + req->valid_params = valid_params; | |
| 2107 | + req->nav_id = nav_id; | |
| 2108 | + req->index = index; | |
| 2109 | + req->addr_lo = addr_lo; | |
| 2110 | + req->addr_hi = addr_hi; | |
| 2111 | + req->count = count; | |
| 2112 | + req->mode = mode; | |
| 2113 | + req->size = size; | |
| 2114 | + req->order_id = order_id; | |
| 2098 | 2115 | |
| 2099 | − cops->get_best_match_freq = ti_sci_cmd_clk_get_match_freq; | |
| 2100 | − cops->set_freq = ti_sci_cmd_clk_set_freq; | |
| 2101 | − cops->get_freq = ti_sci_cmd_clk_get_freq; | |
| 2116 | + ret = ti_sci_do_xfer(info, xfer); | |
| 2117 | + if (ret) { | |
| 2118 | + dev_err(dev, "RM_RA:Mbox config send fail %d\n", ret); | |
| 2119 | + goto fail; | |
| 2120 | + } | |
| 2102 | 2121 | |
| 2103 | − rm_core_ops->get_range = ti_sci_cmd_get_resource_range; | |
| 2104 | − rm_core_ops->get_range_from_shost = | |
| 2105 | − ti_sci_cmd_get_resource_range_from_shost; | |
| 2122 | + resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; | |
| 2123 | + ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV; | |
| 2106 | 2124 | |
| 2107 | − iops->set_irq = ti_sci_cmd_set_irq; | |
| 2108 | − iops->set_event_map = ti_sci_cmd_set_event_map; | |
| 2109 | − iops->free_irq = ti_sci_cmd_free_irq; | |
| 2110 | − iops->free_event_map = ti_sci_cmd_free_event_map; | |
| 2125 | +fail: | |
| 2126 | + ti_sci_put_one_xfer(&info->minfo, xfer); | |
| 2127 | + dev_dbg(dev, "RM_RA:config ring %u ret:%d\n", index, ret); | |
| 2128 | + return ret; | |
| 2111 | 2129 | } |
| 2112 | 2130 | |
| 2113 | 2131 | /** |
| 2114 | − * ti_sci_get_handle() - Get the TI SCI handle for a device | |
| 2115 | − * @dev: Pointer to device for which we want SCI handle | |
| 2132 | + * ti_sci_cmd_ring_get_config() - get RA ring configuration | |
| 2133 | + * @handle: Pointer to TI SCI handle. | |
| 2134 | + * @nav_id: Device ID of Navigator Subsystem from which the ring is | |
| 2135 | + * allocated | |
| 2136 | + * @index: Ring index | |
| 2137 | + * @addr_lo: Returns ring's base address lo 32 bits | |
| 2138 | + * @addr_hi: Returns ring's base address hi 32 bits | |
| 2139 | + * @count: Returns number of ring elements | |
| 2140 | + * @mode: Returns mode of the ring | |
| 2141 | + * @size: Returns ring element size | |
| 2142 | + * @order_id: Returns ring's bus order ID | |
| 2116 | 2143 | * |
| 2117 | − * NOTE: The function does not track individual clients of the framework | |
| 2118 | − * and is expected to be maintained by caller of TI SCI protocol library. | |
| 2119 | − * ti_sci_put_handle must be balanced with successful ti_sci_get_handle | |
| 2120 | − * Return: pointer to handle if successful, else: | |
| 2121 | − * -EPROBE_DEFER if the instance is not ready | |
| 2122 | − * -ENODEV if the required node handler is missing | |
| 2123 | − * -EINVAL if invalid conditions are encountered. | |
| 2144 | + * Return: 0 if all went well, else returns appropriate error value. | |
| 2145 | + * | |
| 2146 | + * See @ti_sci_msg_rm_ring_get_cfg_req for more info. | |
| 2124 | 2147 | */ |
| 2125 | −const struct ti_sci_handle *ti_sci_get_handle(struct device *dev) | |
| 2148 | +static int ti_sci_cmd_ring_get_config(const struct ti_sci_handle *handle, | |
| 2149 | + u32 nav_id, u32 index, u8 *mode, | |
| 2150 | + u32 *addr_lo, u32 *addr_hi, | |
| 2151 | + u32 *count, u8 *size, u8 *order_id) | |
| 2126 | 2152 | { |
| 2127 | − struct device_node *ti_sci_np; | |
| 2128 | − struct list_head *p; | |
| 2129 | − struct ti_sci_handle *handle = NULL; | |
| 2153 | + struct ti_sci_msg_rm_ring_get_cfg_resp *resp; | |
| 2154 | + struct ti_sci_msg_rm_ring_get_cfg_req *req; | |
| 2155 | + struct ti_sci_xfer *xfer; | |
| 2130 | 2156 | struct ti_sci_info *info; |
| 2157 | + struct device *dev; | |
| 2158 | + int ret = 0; | |
| 2131 | 2159 | |
| 2132 | − if (!dev) { | |
| 2133 | − pr_err("I need a device pointer\n"); | |
| 2134 | − return ERR_PTR(-EINVAL); | |
| 2135 | − } | |
| 2136 | − ti_sci_np = of_get_parent(dev->of_node); | |
| 2137 | − if (!ti_sci_np) { | |
| 2138 | − dev_err(dev, "No OF information\n"); | |
| 2139 | − return ERR_PTR(-EINVAL); | |
| 2160 | + if (IS_ERR_OR_NULL(handle)) | |
| 2161 | + return -EINVAL; | |
| 2162 | + | |
| 2163 | + info = handle_to_ti_sci_info(handle); | |
| 2164 | + dev = info->dev; | |
| 2165 | + | |
| 2166 | + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_RM_RING_GET_CFG, | |
| 2167 | + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | |
| 2168 | + sizeof(*req), sizeof(*resp)); | |
| 2169 | + if (IS_ERR(xfer)) { | |
| 2170 | + ret = PTR_ERR(xfer); | |
| 2171 | + dev_err(dev, | |
| 2172 | + "RM_RA:Message get config failed(%d)\n", ret); | |
| 2173 | + return ret; | |
| 2140 | 2174 | } |
| 2175 | + req = (struct ti_sci_msg_rm_ring_get_cfg_req *)xfer->xfer_buf; | |
| 2176 | + req->nav_id = nav_id; | |
| 2177 | + req->index = index; | |
| 2141 | 2178 | |
| 2142 | − mutex_lock(&ti_sci_list_mutex); | |
| 2143 | − list_for_each(p, &ti_sci_list) { | |
| 2144 | − info = list_entry(p, struct ti_sci_info, node); | |
| 2145 | − if (ti_sci_np == info->dev->of_node) { | |
| 2146 | − handle = &info->handle; | |
| 2147 | − info->users++; | |
| 2148 | − break; | |
| 2149 | − } | |
| 2179 | + ret = ti_sci_do_xfer(info, xfer); | |
| 2180 | + if (ret) { | |
| 2181 | + dev_err(dev, "RM_RA:Mbox get config send fail %d\n", ret); | |
| 2182 | + goto fail; | |
| 2150 | 2183 | } |
| 2151 | − mutex_unlock(&ti_sci_list_mutex); | |
| 2152 | − of_node_put(ti_sci_np); | |
| 2153 | 2184 | |
| 2154 | − if (!handle) | |
| 2155 | − return ERR_PTR(-EPROBE_DEFER); | |
| 2185 | + resp = (struct ti_sci_msg_rm_ring_get_cfg_resp *)xfer->xfer_buf; | |
| 2156 | 2186 | |
| 2157 | − return handle; | |
| 2187 | + if (!ti_sci_is_response_ack(resp)) { | |
| 2188 | + ret = -ENODEV; | |
| 2189 | + } else { | |
| 2190 | + if (mode) | |
| 2191 | + *mode = resp->mode; | |
| 2192 | + if (addr_lo) | |
| 2193 | + *addr_lo = resp->addr_lo; | |
| 2194 | + if (addr_hi) | |
| 2195 | + *addr_hi = resp->addr_hi; | |
| 2196 | + if (count) | |
| 2197 | + *count = resp->count; | |
| 2198 | + if (size) | |
| 2199 | + *size = resp->size; | |
| 2200 | + if (order_id) | |
| 2201 | + *order_id = resp->order_id; | |
| 2202 | + }; | |
| 2203 | + | |
| 2204 | +fail: | |
| 2205 | + ti_sci_put_one_xfer(&info->minfo, xfer); | |
| 2206 | + dev_dbg(dev, "RM_RA:get config ring %u ret:%d\n", index, ret); | |
| 2207 | + return ret; | |
| 2158 | 2208 | } |
| 2159 | −EXPORT_SYMBOL_GPL(ti_sci_get_handle); | |
| 2160 | 2209 | |
| 2161 | 2210 | /** |
| 2162 | − * ti_sci_put_handle() - Release the handle acquired by ti_sci_get_handle | |
| 2163 | − * @handle: Handle acquired by ti_sci_get_handle | |
| 2164 | − * | |
| 2165 | − * NOTE: The function does not track individual clients of the framework | |
| 2166 | − * and is expected to be maintained by caller of TI SCI protocol library. | |
| 2167 | − * ti_sci_put_handle must be balanced with successful ti_sci_get_handle | |
| 2211 | + * ti_sci_cmd_rm_psil_pair() - Pair PSI-L source to destination thread | |
| 2212 | + * @handle: Pointer to TI SCI handle. | |
| 2213 | + * @nav_id: Device ID of Navigator Subsystem which should be used for | |
| 2214 | + * pairing | |
| 2215 | + * @src_thread: Source PSI-L thread ID | |
| 2216 | + * @dst_thread: Destination PSI-L thread ID | |
| 2168 | 2217 | * |
| 2169 | − * Return: 0 is successfully released | |
| 2170 | − * if an error pointer was passed, it returns the error value back, | |
| 2171 | − * if null was passed, it returns -EINVAL; | |
| 2218 | + * Return: 0 if all went well, else returns appropriate error value. | |
| 2172 | 2219 | */ |
| 2173 | −int ti_sci_put_handle(const struct ti_sci_handle *handle) | |
| 2220 | +static int ti_sci_cmd_rm_psil_pair(const struct ti_sci_handle *handle, | |
| 2221 | + u32 nav_id, u32 src_thread, u32 dst_thread) | |
| 2174 | 2222 | { |
| 2223 | + struct ti_sci_msg_psil_pair *req; | |
| 2224 | + struct ti_sci_msg_hdr *resp; | |
| 2225 | + struct ti_sci_xfer *xfer; | |
| 2175 | 2226 | struct ti_sci_info *info; |
| 2227 | + struct device *dev; | |
| 2228 | + int ret = 0; | |
| 2176 | 2229 | |
| 2177 | 2230 | if (IS_ERR(handle)) |
| 2178 | 2231 | return PTR_ERR(handle); |
| @@ -2180,81 +2233,866 @@ int ti_sci_put_handle(const struct ti_sci_handle *handle) · 1 unmodified line | ||
| 2180 | 2233 | return -EINVAL; |
| 2181 | 2234 | |
| 2182 | 2235 | info = handle_to_ti_sci_info(handle); |
| 2183 | − mutex_lock(&ti_sci_list_mutex); | |
| 2184 | − if (!WARN_ON(!info->users)) | |
| 2185 | − info->users--; | |
| 2186 | − mutex_unlock(&ti_sci_list_mutex); | |
| 2236 | + dev = info->dev; | |
| 2187 | 2237 | |
| 2188 | − return 0; | |
| 2189 | −} | |
| 2190 | −EXPORT_SYMBOL_GPL(ti_sci_put_handle); | |
| 2238 | + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_RM_PSIL_PAIR, | |
| 2239 | + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | |
| 2240 | + sizeof(*req), sizeof(*resp)); | |
| 2241 | + if (IS_ERR(xfer)) { | |
| 2242 | + ret = PTR_ERR(xfer); | |
| 2243 | + dev_err(dev, "RM_PSIL:Message reconfig failed(%d)\n", ret); | |
| 2244 | + return ret; | |
| 2245 | + } | |
| 2246 | + req = (struct ti_sci_msg_psil_pair *)xfer->xfer_buf; | |
| 2247 | + req->nav_id = nav_id; | |
| 2248 | + req->src_thread = src_thread; | |
| 2249 | + req->dst_thread = dst_thread; | |
| 2191 | 2250 | |
| 2192 | −static void devm_ti_sci_release(struct device *dev, void *res) | |
| 2193 | −{ | |
| 2194 | − const struct ti_sci_handle **ptr = res; | |
| 2195 | − const struct ti_sci_handle *handle = *ptr; | |
| 2196 | − int ret; | |
| 2251 | + ret = ti_sci_do_xfer(info, xfer); | |
| 2252 | + if (ret) { | |
| 2253 | + dev_err(dev, "RM_PSIL:Mbox send fail %d\n", ret); | |
| 2254 | + goto fail; | |
| 2255 | + } | |
| 2197 | 2256 | |
| 2198 | − ret = ti_sci_put_handle(handle); | |
| 2199 | − if (ret) | |
| 2200 | − dev_err(dev, "failed to put handle %d\n", ret); | |
| 2257 | + resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; | |
| 2258 | + ret = ti_sci_is_response_ack(resp) ? 0 : -EINVAL; | |
| 2259 | + | |
| 2260 | +fail: | |
| 2261 | + ti_sci_put_one_xfer(&info->minfo, xfer); | |
| 2262 | + | |
| 2263 | + return ret; | |
| 2201 | 2264 | } |
| 2202 | 2265 | |
| 2203 | 2266 | /** |
| 2204 | − * devm_ti_sci_get_handle() - Managed get handle | |
| 2205 | − * @dev: device for which we want SCI handle for. | |
| 2267 | + * ti_sci_cmd_rm_psil_unpair() - Unpair PSI-L source from destination thread | |
| 2268 | + * @handle: Pointer to TI SCI handle. | |
| 2269 | + * @nav_id: Device ID of Navigator Subsystem which should be used for | |
| 2270 | + * unpairing | |
| 2271 | + * @src_thread: Source PSI-L thread ID | |
| 2272 | + * @dst_thread: Destination PSI-L thread ID | |
| 2206 | 2273 | * |
| 2207 | − * NOTE: This releases the handle once the device resources are | |
| 2208 | − * no longer needed. MUST NOT BE released with ti_sci_put_handle. | |
| 2209 | − * The function does not track individual clients of the framework | |
| 2210 | − * and is expected to be maintained by caller of TI SCI protocol library. | |
| 2211 | − * | |
| 2212 | − * Return: 0 if all went fine, else corresponding error. | |
| 2274 | + * Return: 0 if all went well, else returns appropriate error value. | |
| 2213 | 2275 | */ |
| 2214 | −const struct ti_sci_handle *devm_ti_sci_get_handle(struct device *dev) | |
| 2276 | +static int ti_sci_cmd_rm_psil_unpair(const struct ti_sci_handle *handle, | |
| 2277 | + u32 nav_id, u32 src_thread, u32 dst_thread) | |
| 2215 | 2278 | { |
| 2216 | − const struct ti_sci_handle **ptr; | |
| 2217 | − const struct ti_sci_handle *handle; | |
| 2279 | + struct ti_sci_msg_psil_unpair *req; | |
| 2280 | + struct ti_sci_msg_hdr *resp; | |
| 2281 | + struct ti_sci_xfer *xfer; | |
| 2282 | + struct ti_sci_info *info; | |
| 2283 | + struct device *dev; | |
| 2284 | + int ret = 0; | |
| 2218 | 2285 | |
| 2219 | − ptr = devres_alloc(devm_ti_sci_release, sizeof(*ptr), GFP_KERNEL); | |
| 2220 | − if (!ptr) | |
| 2221 | − return ERR_PTR(-ENOMEM); | |
| 2222 | − handle = ti_sci_get_handle(dev); | |
| 2286 | + if (IS_ERR(handle)) | |
| 2287 | + return PTR_ERR(handle); | |
| 2288 | + if (!handle) | |
| 2289 | + return -EINVAL; | |
| 2223 | 2290 | |
| 2224 | − if (!IS_ERR(handle)) { | |
| 2225 | − *ptr = handle; | |
| 2226 | − devres_add(dev, ptr); | |
| 2227 | − } else { | |
| 2228 | − devres_free(ptr); | |
| 2291 | + info = handle_to_ti_sci_info(handle); | |
| 2292 | + dev = info->dev; | |
| 2293 | + | |
| 2294 | + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_RM_PSIL_UNPAIR, | |
| 2295 | + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | |
| 2296 | + sizeof(*req), sizeof(*resp)); | |
| 2297 | + if (IS_ERR(xfer)) { | |
| 2298 | + ret = PTR_ERR(xfer); | |
| 2299 | + dev_err(dev, "RM_PSIL:Message reconfig failed(%d)\n", ret); | |
| 2300 | + return ret; | |
| 2229 | 2301 | } |
| 2302 | + req = (struct ti_sci_msg_psil_unpair *)xfer->xfer_buf; | |
| 2303 | + req->nav_id = nav_id; | |
| 2304 | + req->src_thread = src_thread; | |
| 2305 | + req->dst_thread = dst_thread; | |
| 2230 | 2306 | |
| 2231 | − return handle; | |
| 2307 | + ret = ti_sci_do_xfer(info, xfer); | |
| 2308 | + if (ret) { | |
| 2309 | + dev_err(dev, "RM_PSIL:Mbox send fail %d\n", ret); | |
| 2310 | + goto fail; | |
| 2311 | + } | |
| 2312 | + | |
| 2313 | + resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; | |
| 2314 | + ret = ti_sci_is_response_ack(resp) ? 0 : -EINVAL; | |
| 2315 | + | |
| 2316 | +fail: | |
| 2317 | + ti_sci_put_one_xfer(&info->minfo, xfer); | |
| 2318 | + | |
| 2319 | + return ret; | |
| 2232 | 2320 | } |
| 2233 | −EXPORT_SYMBOL_GPL(devm_ti_sci_get_handle); | |
| 2234 | 2321 | |
| 2235 | 2322 | /** |
| 2236 | − * ti_sci_get_by_phandle() - Get the TI SCI handle using DT phandle | |
| 2237 | − * @np: device node | |
| 2238 | − * @property: property name containing phandle on TISCI node | |
| 2323 | + * ti_sci_cmd_rm_udmap_tx_ch_cfg() - Configure a UDMAP TX channel | |
| 2324 | + * @handle: Pointer to TI SCI handle. | |
| 2325 | + * @params: Pointer to ti_sci_msg_rm_udmap_tx_ch_cfg TX channel config | |
| 2326 | + * structure | |
| 2239 | 2327 | * |
| 2240 | − * NOTE: The function does not track individual clients of the framework | |
| 2241 | − * and is expected to be maintained by caller of TI SCI protocol library. | |
| 2242 | − * ti_sci_put_handle must be balanced with successful ti_sci_get_by_phandle | |
| 2243 | − * Return: pointer to handle if successful, else: | |
| 2244 | − * -EPROBE_DEFER if the instance is not ready | |
| 2245 | − * -ENODEV if the required node handler is missing | |
| 2246 | − * -EINVAL if invalid conditions are encountered. | |
| 2328 | + * Return: 0 if all went well, else returns appropriate error value. | |
| 2329 | + * | |
| 2330 | + * See @ti_sci_msg_rm_udmap_tx_ch_cfg and @ti_sci_msg_rm_udmap_tx_ch_cfg_req for | |
| 2331 | + * more info. | |
| 2247 | 2332 | */ |
| 2248 | −const struct ti_sci_handle *ti_sci_get_by_phandle(struct device_node *np, | |
| 2249 | − const char *property) | |
| 2333 | +static int ti_sci_cmd_rm_udmap_tx_ch_cfg(const struct ti_sci_handle *handle, | |
| 2334 | + const struct ti_sci_msg_rm_udmap_tx_ch_cfg *params) | |
| 2250 | 2335 | { |
| 2251 | − struct ti_sci_handle *handle = NULL; | |
| 2252 | − struct device_node *ti_sci_np; | |
| 2336 | + struct ti_sci_msg_rm_udmap_tx_ch_cfg_req *req; | |
| 2337 | + struct ti_sci_msg_hdr *resp; | |
| 2338 | + struct ti_sci_xfer *xfer; | |
| 2253 | 2339 | struct ti_sci_info *info; |
| 2254 | − struct list_head *p; | |
| 2340 | + struct device *dev; | |
| 2341 | + int ret = 0; | |
| 2255 | 2342 | |
| 2256 | − if (!np) { | |
| 2257 | − pr_err("I need a device pointer\n"); | |
| 2343 | + if (IS_ERR_OR_NULL(handle)) | |
| 2344 | + return -EINVAL; | |
| 2345 | + | |
| 2346 | + info = handle_to_ti_sci_info(handle); | |
| 2347 | + dev = info->dev; | |
| 2348 | + | |
| 2349 | + xfer = ti_sci_get_one_xfer(info, TISCI_MSG_RM_UDMAP_TX_CH_CFG, | |
| 2350 | + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | |
| 2351 | + sizeof(*req), sizeof(*resp)); | |
| 2352 | + if (IS_ERR(xfer)) { | |
| 2353 | + ret = PTR_ERR(xfer); | |
| 2354 | + dev_err(dev, "Message TX_CH_CFG alloc failed(%d)\n", ret); | |
| 2355 | + return ret; | |
| 2356 | + } | |
| 2357 | + req = (struct ti_sci_msg_rm_udmap_tx_ch_cfg_req *)xfer->xfer_buf; | |
| 2358 | + req->valid_params = params->valid_params; | |
| 2359 | + req->nav_id = params->nav_id; | |
| 2360 | + req->index = params->index; | |
| 2361 | + req->tx_pause_on_err = params->tx_pause_on_err; | |
| 2362 | + req->tx_filt_einfo = params->tx_filt_einfo; | |
| 2363 | + req->tx_filt_pswords = params->tx_filt_pswords; | |
| 2364 | + req->tx_atype = params->tx_atype; | |
| 2365 | + req->tx_chan_type = params->tx_chan_type; | |
| 2366 | + req->tx_supr_tdpkt = params->tx_supr_tdpkt; | |
| 2367 | + req->tx_fetch_size = params->tx_fetch_size; | |
| 2368 | + req->tx_credit_count = params->tx_credit_count; | |
| 2369 | + req->txcq_qnum = params->txcq_qnum; | |
| 2370 | + req->tx_priority = params->tx_priority; | |
| 2371 | + req->tx_qos = params->tx_qos; | |
| 2372 | + req->tx_orderid = params->tx_orderid; | |
| 2373 | + req->fdepth = params->fdepth; | |
| 2374 | + req->tx_sched_priority = params->tx_sched_priority; | |
| 2375 | + req->tx_burst_size = params->tx_burst_size; | |
| 2376 | + | |
| 2377 | + ret = ti_sci_do_xfer(info, xfer); | |
| 2378 | + if (ret) { | |
| 2379 | + dev_err(dev, "Mbox send TX_CH_CFG fail %d\n", ret); | |
| 2380 | + goto fail; | |
| 2381 | + } | |
| 2382 | + | |
| 2383 | + resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; | |
| 2384 | + ret = ti_sci_is_response_ack(resp) ? 0 : -EINVAL; | |
| 2385 | + | |
| 2386 | +fail: | |
| 2387 | + ti_sci_put_one_xfer(&info->minfo, xfer); | |
| 2388 | + dev_dbg(dev, "TX_CH_CFG: chn %u ret:%u\n", params->index, ret); | |
| 2389 | + return ret; | |
| 2390 | +} | |
| 2391 | + | |
| 2392 | +/** | |
| 2393 | + * ti_sci_cmd_rm_udmap_rx_ch_cfg() - Configure a UDMAP RX channel | |
| 2394 | + * @handle: Pointer to TI SCI handle. | |
| 2395 | + * @params: Pointer to ti_sci_msg_rm_udmap_rx_ch_cfg RX channel config | |
| 2396 | + * structure | |
| 2397 | + * | |
| 2398 | + * Return: 0 if all went well, else returns appropriate error value. | |
| 2399 | + * | |
| 2400 | + * See @ti_sci_msg_rm_udmap_rx_ch_cfg and @ti_sci_msg_rm_udmap_rx_ch_cfg_req for | |
| 2401 | + * more info. | |
| 2402 | + */ | |
| 2403 | +static int ti_sci_cmd_rm_udmap_rx_ch_cfg(const struct ti_sci_handle *handle, | |
| 2404 | + const struct ti_sci_msg_rm_udmap_rx_ch_cfg *params) | |
| 2405 | +{ | |
| 2406 | + struct ti_sci_msg_rm_udmap_rx_ch_cfg_req *req; | |
| 2407 | + struct ti_sci_msg_hdr *resp; | |
| 2408 | + struct ti_sci_xfer *xfer; | |
| 2409 | + struct ti_sci_info *info; | |
| 2410 | + struct device *dev; | |
| 2411 | + int ret = 0; | |
| 2412 | + | |
| 2413 | + if (IS_ERR_OR_NULL(handle)) | |
| 2414 | + return -EINVAL; | |
| 2415 | + | |
| 2416 | + info = handle_to_ti_sci_info(handle); | |
| 2417 | + dev = info->dev; | |
| 2418 | + | |
| 2419 | + xfer = ti_sci_get_one_xfer(info, TISCI_MSG_RM_UDMAP_RX_CH_CFG, | |
| 2420 | + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | |
| 2421 | + sizeof(*req), sizeof(*resp)); | |
| 2422 | + if (IS_ERR(xfer)) { | |
| 2423 | + ret = PTR_ERR(xfer); | |
| 2424 | + dev_err(dev, "Message RX_CH_CFG alloc failed(%d)\n", ret); | |
| 2425 | + return ret; | |
| 2426 | + } | |
| 2427 | + req = (struct ti_sci_msg_rm_udmap_rx_ch_cfg_req *)xfer->xfer_buf; | |
| 2428 | + req->valid_params = params->valid_params; | |
| 2429 | + req->nav_id = params->nav_id; | |
| 2430 | + req->index = params->index; | |
| 2431 | + req->rx_fetch_size = params->rx_fetch_size; | |
| 2432 | + req->rxcq_qnum = params->rxcq_qnum; | |
| 2433 | + req->rx_priority = params->rx_priority; | |
| 2434 | + req->rx_qos = params->rx_qos; | |
| 2435 | + req->rx_orderid = params->rx_orderid; | |
| 2436 | + req->rx_sched_priority = params->rx_sched_priority; | |
| 2437 | + req->flowid_start = params->flowid_start; | |
| 2438 | + req->flowid_cnt = params->flowid_cnt; | |
| 2439 | + req->rx_pause_on_err = params->rx_pause_on_err; | |
| 2440 | + req->rx_atype = params->rx_atype; | |
| 2441 | + req->rx_chan_type = params->rx_chan_type; | |
| 2442 | + req->rx_ignore_short = params->rx_ignore_short; | |
| 2443 | + req->rx_ignore_long = params->rx_ignore_long; | |
| 2444 | + req->rx_burst_size = params->rx_burst_size; | |
| 2445 | + | |
| 2446 | + ret = ti_sci_do_xfer(info, xfer); | |
| 2447 | + if (ret) { | |
| 2448 | + dev_err(dev, "Mbox send RX_CH_CFG fail %d\n", ret); | |
| 2449 | + goto fail; | |
| 2450 | + } | |
| 2451 | + | |
| 2452 | + resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; | |
| 2453 | + ret = ti_sci_is_response_ack(resp) ? 0 : -EINVAL; | |
| 2454 | + | |
| 2455 | +fail: | |
| 2456 | + ti_sci_put_one_xfer(&info->minfo, xfer); | |
| 2457 | + dev_dbg(dev, "RX_CH_CFG: chn %u ret:%d\n", params->index, ret); | |
| 2458 | + return ret; | |
| 2459 | +} | |
| 2460 | + | |
| 2461 | +/** | |
| 2462 | + * ti_sci_cmd_rm_udmap_rx_flow_cfg() - Configure UDMAP RX FLOW | |
| 2463 | + * @handle: Pointer to TI SCI handle. | |
| 2464 | + * @params: Pointer to ti_sci_msg_rm_udmap_flow_cfg RX FLOW config | |
| 2465 | + * structure | |
| 2466 | + * | |
| 2467 | + * Return: 0 if all went well, else returns appropriate error value. | |
| 2468 | + * | |
| 2469 | + * See @ti_sci_msg_rm_udmap_flow_cfg and @ti_sci_msg_rm_udmap_flow_cfg_req for | |
| 2470 | + * more info. | |
| 2471 | + */ | |
| 2472 | +static int ti_sci_cmd_rm_udmap_rx_flow_cfg(const struct ti_sci_handle *handle, | |
| 2473 | + const struct ti_sci_msg_rm_udmap_flow_cfg *params) | |
| 2474 | +{ | |
| 2475 | + struct ti_sci_msg_rm_udmap_flow_cfg_req *req; | |
| 2476 | + struct ti_sci_msg_hdr *resp; | |
| 2477 | + struct ti_sci_xfer *xfer; | |
| 2478 | + struct ti_sci_info *info; | |
| 2479 | + struct device *dev; | |
| 2480 | + int ret = 0; | |
| 2481 | + | |
| 2482 | + if (IS_ERR_OR_NULL(handle)) | |
| 2483 | + return -EINVAL; | |
| 2484 | + | |
| 2485 | + info = handle_to_ti_sci_info(handle); | |
| 2486 | + dev = info->dev; | |
| 2487 | + | |
| 2488 | + xfer = ti_sci_get_one_xfer(info, TISCI_MSG_RM_UDMAP_FLOW_CFG, | |
| 2489 | + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | |
| 2490 | + sizeof(*req), sizeof(*resp)); | |
| 2491 | + if (IS_ERR(xfer)) { | |
| 2492 | + ret = PTR_ERR(xfer); | |
| 2493 | + dev_err(dev, "RX_FL_CFG: Message alloc failed(%d)\n", ret); | |
| 2494 | + return ret; | |
| 2495 | + } | |
| 2496 | + req = (struct ti_sci_msg_rm_udmap_flow_cfg_req *)xfer->xfer_buf; | |
| 2497 | + req->valid_params = params->valid_params; | |
| 2498 | + req->nav_id = params->nav_id; | |
| 2499 | + req->flow_index = params->flow_index; | |
| 2500 | + req->rx_einfo_present = params->rx_einfo_present; | |
| 2501 | + req->rx_psinfo_present = params->rx_psinfo_present; | |
| 2502 | + req->rx_error_handling = params->rx_error_handling; | |
| 2503 | + req->rx_desc_type = params->rx_desc_type; | |
| 2504 | + req->rx_sop_offset = params->rx_sop_offset; | |
| 2505 | + req->rx_dest_qnum = params->rx_dest_qnum; | |
| 2506 | + req->rx_src_tag_hi = params->rx_src_tag_hi; | |
| 2507 | + req->rx_src_tag_lo = params->rx_src_tag_lo; | |
| 2508 | + req->rx_dest_tag_hi = params->rx_dest_tag_hi; | |
| 2509 | + req->rx_dest_tag_lo = params->rx_dest_tag_lo; | |
| 2510 | + req->rx_src_tag_hi_sel = params->rx_src_tag_hi_sel; | |
| 2511 | + req->rx_src_tag_lo_sel = params->rx_src_tag_lo_sel; | |
| 2512 | + req->rx_dest_tag_hi_sel = params->rx_dest_tag_hi_sel; | |
| 2513 | + req->rx_dest_tag_lo_sel = params->rx_dest_tag_lo_sel; | |
| 2514 | + req->rx_fdq0_sz0_qnum = params->rx_fdq0_sz0_qnum; | |
| 2515 | + req->rx_fdq1_qnum = params->rx_fdq1_qnum; | |
| 2516 | + req->rx_fdq2_qnum = params->rx_fdq2_qnum; | |
| 2517 | + req->rx_fdq3_qnum = params->rx_fdq3_qnum; | |
| 2518 | + req->rx_ps_location = params->rx_ps_location; | |
| 2519 | + | |
| 2520 | + ret = ti_sci_do_xfer(info, xfer); | |
| 2521 | + if (ret) { | |
| 2522 | + dev_err(dev, "RX_FL_CFG: Mbox send fail %d\n", ret); | |
| 2523 | + goto fail; | |
| 2524 | + } | |
| 2525 | + | |
| 2526 | + resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; | |
| 2527 | + ret = ti_sci_is_response_ack(resp) ? 0 : -EINVAL; | |
| 2528 | + | |
| 2529 | +fail: | |
| 2530 | + ti_sci_put_one_xfer(&info->minfo, xfer); | |
| 2531 | + dev_dbg(info->dev, "RX_FL_CFG: %u ret:%d\n", params->flow_index, ret); | |
| 2532 | + return ret; | |
| 2533 | +} | |
| 2534 | + | |
| 2535 | +/** | |
| 2536 | + * ti_sci_cmd_proc_request() - Command to request a physical processor control | |
| 2537 | + * @handle: Pointer to TI SCI handle | |
| 2538 | + * @proc_id: Processor ID this request is for | |
| 2539 | + * | |
| 2540 | + * Return: 0 if all went well, else returns appropriate error value. | |
| 2541 | + */ | |
| 2542 | +static int ti_sci_cmd_proc_request(const struct ti_sci_handle *handle, | |
| 2543 | + u8 proc_id) | |
| 2544 | +{ | |
| 2545 | + struct ti_sci_msg_req_proc_request *req; | |
| 2546 | + struct ti_sci_msg_hdr *resp; | |
| 2547 | + struct ti_sci_info *info; | |
| 2548 | + struct ti_sci_xfer *xfer; | |
| 2549 | + struct device *dev; | |
| 2550 | + int ret = 0; | |
| 2551 | + | |
| 2552 | + if (!handle) | |
| 2553 | + return -EINVAL; | |
| 2554 | + if (IS_ERR(handle)) | |
| 2555 | + return PTR_ERR(handle); | |
| 2556 | + | |
| 2557 | + info = handle_to_ti_sci_info(handle); | |
| 2558 | + dev = info->dev; | |
| 2559 | + | |
| 2560 | + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_PROC_REQUEST, | |
| 2561 | + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | |
| 2562 | + sizeof(*req), sizeof(*resp)); | |
| 2563 | + if (IS_ERR(xfer)) { | |
| 2564 | + ret = PTR_ERR(xfer); | |
| 2565 | + dev_err(dev, "Message alloc failed(%d)\n", ret); | |
| 2566 | + return ret; | |
| 2567 | + } | |
| 2568 | + req = (struct ti_sci_msg_req_proc_request *)xfer->xfer_buf; | |
| 2569 | + req->processor_id = proc_id; | |
| 2570 | + | |
| 2571 | + ret = ti_sci_do_xfer(info, xfer); | |
| 2572 | + if (ret) { | |
| 2573 | + dev_err(dev, "Mbox send fail %d\n", ret); | |
| 2574 | + goto fail; | |
| 2575 | + } | |
| 2576 | + | |
| 2577 | + resp = (struct ti_sci_msg_hdr *)xfer->tx_message.buf; | |
| 2578 | + | |
| 2579 | + ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV; | |
| 2580 | + | |
| 2581 | +fail: | |
| 2582 | + ti_sci_put_one_xfer(&info->minfo, xfer); | |
| 2583 | + | |
| 2584 | + return ret; | |
| 2585 | +} | |
| 2586 | + | |
| 2587 | +/** | |
| 2588 | + * ti_sci_cmd_proc_release() - Command to release a physical processor control | |
| 2589 | + * @handle: Pointer to TI SCI handle | |
| 2590 | + * @proc_id: Processor ID this request is for | |
| 2591 | + * | |
| 2592 | + * Return: 0 if all went well, else returns appropriate error value. | |
| 2593 | + */ | |
| 2594 | +static int ti_sci_cmd_proc_release(const struct ti_sci_handle *handle, | |
| 2595 | + u8 proc_id) | |
| 2596 | +{ | |
| 2597 | + struct ti_sci_msg_req_proc_release *req; | |
| 2598 | + struct ti_sci_msg_hdr *resp; | |
| 2599 | + struct ti_sci_info *info; | |
| 2600 | + struct ti_sci_xfer *xfer; | |
| 2601 | + struct device *dev; | |
| 2602 | + int ret = 0; | |
| 2603 | + | |
| 2604 | + if (!handle) | |
| 2605 | + return -EINVAL; | |
| 2606 | + if (IS_ERR(handle)) | |
| 2607 | + return PTR_ERR(handle); | |
| 2608 | + | |
| 2609 | + info = handle_to_ti_sci_info(handle); | |
| 2610 | + dev = info->dev; | |
| 2611 | + | |
| 2612 | + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_PROC_RELEASE, | |
| 2613 | + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | |
| 2614 | + sizeof(*req), sizeof(*resp)); | |
| 2615 | + if (IS_ERR(xfer)) { | |
| 2616 | + ret = PTR_ERR(xfer); | |
| 2617 | + dev_err(dev, "Message alloc failed(%d)\n", ret); | |
| 2618 | + return ret; | |
| 2619 | + } | |
| 2620 | + req = (struct ti_sci_msg_req_proc_release *)xfer->xfer_buf; | |
| 2621 | + req->processor_id = proc_id; | |
| 2622 | + | |
| 2623 | + ret = ti_sci_do_xfer(info, xfer); | |
| 2624 | + if (ret) { | |
| 2625 | + dev_err(dev, "Mbox send fail %d\n", ret); | |
| 2626 | + goto fail; | |
| 2627 | + } | |
| 2628 | + | |
| 2629 | + resp = (struct ti_sci_msg_hdr *)xfer->tx_message.buf; | |
| 2630 | + | |
| 2631 | + ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV; | |
| 2632 | + | |
| 2633 | +fail: | |
| 2634 | + ti_sci_put_one_xfer(&info->minfo, xfer); | |
| 2635 | + | |
| 2636 | + return ret; | |
| 2637 | +} | |
| 2638 | + | |
| 2639 | +/** | |
| 2640 | + * ti_sci_cmd_proc_handover() - Command to handover a physical processor | |
| 2641 | + * control to a host in the processor's access | |
| 2642 | + * control list. | |
| 2643 | + * @handle: Pointer to TI SCI handle | |
| 2644 | + * @proc_id: Processor ID this request is for | |
| 2645 | + * @host_id: Host ID to get the control of the processor | |
| 2646 | + * | |
| 2647 | + * Return: 0 if all went well, else returns appropriate error value. | |
| 2648 | + */ | |
| 2649 | +static int ti_sci_cmd_proc_handover(const struct ti_sci_handle *handle, | |
| 2650 | + u8 proc_id, u8 host_id) | |
| 2651 | +{ | |
| 2652 | + struct ti_sci_msg_req_proc_handover *req; | |
| 2653 | + struct ti_sci_msg_hdr *resp; | |
| 2654 | + struct ti_sci_info *info; | |
| 2655 | + struct ti_sci_xfer *xfer; | |
| 2656 | + struct device *dev; | |
| 2657 | + int ret = 0; | |
| 2658 | + | |
| 2659 | + if (!handle) | |
| 2660 | + return -EINVAL; | |
| 2661 | + if (IS_ERR(handle)) | |
| 2662 | + return PTR_ERR(handle); | |
| 2663 | + | |
| 2664 | + info = handle_to_ti_sci_info(handle); | |
| 2665 | + dev = info->dev; | |
| 2666 | + | |
| 2667 | + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_PROC_HANDOVER, | |
| 2668 | + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | |
| 2669 | + sizeof(*req), sizeof(*resp)); | |
| 2670 | + if (IS_ERR(xfer)) { | |
| 2671 | + ret = PTR_ERR(xfer); | |
| 2672 | + dev_err(dev, "Message alloc failed(%d)\n", ret); | |
| 2673 | + return ret; | |
| 2674 | + } | |
| 2675 | + req = (struct ti_sci_msg_req_proc_handover *)xfer->xfer_buf; | |
| 2676 | + req->processor_id = proc_id; | |
| 2677 | + req->host_id = host_id; | |
| 2678 | + | |
| 2679 | + ret = ti_sci_do_xfer(info, xfer); | |
| 2680 | + if (ret) { | |
| 2681 | + dev_err(dev, "Mbox send fail %d\n", ret); | |
| 2682 | + goto fail; | |
| 2683 | + } | |
| 2684 | + | |
| 2685 | + resp = (struct ti_sci_msg_hdr *)xfer->tx_message.buf; | |
| 2686 | + | |
| 2687 | + ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV; | |
| 2688 | + | |
| 2689 | +fail: | |
| 2690 | + ti_sci_put_one_xfer(&info->minfo, xfer); | |
| 2691 | + | |
| 2692 | + return ret; | |
| 2693 | +} | |
| 2694 | + | |
| 2695 | +/** | |
| 2696 | + * ti_sci_cmd_proc_set_config() - Command to set the processor boot | |
| 2697 | + * configuration flags | |
| 2698 | + * @handle: Pointer to TI SCI handle | |
| 2699 | + * @proc_id: Processor ID this request is for | |
| 2700 | + * @config_flags_set: Configuration flags to be set | |
| 2701 | + * @config_flags_clear: Configuration flags to be cleared. | |
| 2702 | + * | |
| 2703 | + * Return: 0 if all went well, else returns appropriate error value. | |
| 2704 | + */ | |
| 2705 | +static int ti_sci_cmd_proc_set_config(const struct ti_sci_handle *handle, | |
| 2706 | + u8 proc_id, u64 bootvector, | |
| 2707 | + u32 config_flags_set, | |
| 2708 | + u32 config_flags_clear) | |
| 2709 | +{ | |
| 2710 | + struct ti_sci_msg_req_set_config *req; | |
| 2711 | + struct ti_sci_msg_hdr *resp; | |
| 2712 | + struct ti_sci_info *info; | |
| 2713 | + struct ti_sci_xfer *xfer; | |
| 2714 | + struct device *dev; | |
| 2715 | + int ret = 0; | |
| 2716 | + | |
| 2717 | + if (!handle) | |
| 2718 | + return -EINVAL; | |
| 2719 | + if (IS_ERR(handle)) | |
| 2720 | + return PTR_ERR(handle); | |
| 2721 | + | |
| 2722 | + info = handle_to_ti_sci_info(handle); | |
| 2723 | + dev = info->dev; | |
| 2724 | + | |
| 2725 | + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SET_CONFIG, | |
| 2726 | + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | |
| 2727 | + sizeof(*req), sizeof(*resp)); | |
| 2728 | + if (IS_ERR(xfer)) { | |
| 2729 | + ret = PTR_ERR(xfer); | |
| 2730 | + dev_err(dev, "Message alloc failed(%d)\n", ret); | |
| 2731 | + return ret; | |
| 2732 | + } | |
| 2733 | + req = (struct ti_sci_msg_req_set_config *)xfer->xfer_buf; | |
| 2734 | + req->processor_id = proc_id; | |
| 2735 | + req->bootvector_low = bootvector & TI_SCI_ADDR_LOW_MASK; | |
| 2736 | + req->bootvector_high = (bootvector & TI_SCI_ADDR_HIGH_MASK) >> | |
| 2737 | + TI_SCI_ADDR_HIGH_SHIFT; | |
| 2738 | + req->config_flags_set = config_flags_set; | |
| 2739 | + req->config_flags_clear = config_flags_clear; | |
| 2740 | + | |
| 2741 | + ret = ti_sci_do_xfer(info, xfer); | |
| 2742 | + if (ret) { | |
| 2743 | + dev_err(dev, "Mbox send fail %d\n", ret); | |
| 2744 | + goto fail; | |
| 2745 | + } | |
| 2746 | + | |
| 2747 | + resp = (struct ti_sci_msg_hdr *)xfer->tx_message.buf; | |
| 2748 | + | |
| 2749 | + ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV; | |
| 2750 | + | |
| 2751 | +fail: | |
| 2752 | + ti_sci_put_one_xfer(&info->minfo, xfer); | |
| 2753 | + | |
| 2754 | + return ret; | |
| 2755 | +} | |
| 2756 | + | |
| 2757 | +/** | |
| 2758 | + * ti_sci_cmd_proc_set_control() - Command to set the processor boot | |
| 2759 | + * control flags | |
| 2760 | + * @handle: Pointer to TI SCI handle | |
| 2761 | + * @proc_id: Processor ID this request is for | |
| 2762 | + * @control_flags_set: Control flags to be set | |
| 2763 | + * @control_flags_clear: Control flags to be cleared | |
| 2764 | + * | |
| 2765 | + * Return: 0 if all went well, else returns appropriate error value. | |
| 2766 | + */ | |
| 2767 | +static int ti_sci_cmd_proc_set_control(const struct ti_sci_handle *handle, | |
| 2768 | + u8 proc_id, u32 control_flags_set, | |
| 2769 | + u32 control_flags_clear) | |
| 2770 | +{ | |
| 2771 | + struct ti_sci_msg_req_set_ctrl *req; | |
| 2772 | + struct ti_sci_msg_hdr *resp; | |
| 2773 | + struct ti_sci_info *info; | |
| 2774 | + struct ti_sci_xfer *xfer; | |
| 2775 | + struct device *dev; | |
| 2776 | + int ret = 0; | |
| 2777 | + | |
| 2778 | + if (!handle) | |
| 2779 | + return -EINVAL; | |
| 2780 | + if (IS_ERR(handle)) | |
| 2781 | + return PTR_ERR(handle); | |
| 2782 | + | |
| 2783 | + info = handle_to_ti_sci_info(handle); | |
| 2784 | + dev = info->dev; | |
| 2785 | + | |
| 2786 | + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SET_CTRL, | |
| 2787 | + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | |
| 2788 | + sizeof(*req), sizeof(*resp)); | |
| 2789 | + if (IS_ERR(xfer)) { | |
| 2790 | + ret = PTR_ERR(xfer); | |
| 2791 | + dev_err(dev, "Message alloc failed(%d)\n", ret); | |
| 2792 | + return ret; | |
| 2793 | + } | |
| 2794 | + req = (struct ti_sci_msg_req_set_ctrl *)xfer->xfer_buf; | |
| 2795 | + req->processor_id = proc_id; | |
| 2796 | + req->control_flags_set = control_flags_set; | |
| 2797 | + req->control_flags_clear = control_flags_clear; | |
| 2798 | + | |
| 2799 | + ret = ti_sci_do_xfer(info, xfer); | |
| 2800 | + if (ret) { | |
| 2801 | + dev_err(dev, "Mbox send fail %d\n", ret); | |
| 2802 | + goto fail; | |
| 2803 | + } | |
| 2804 | + | |
| 2805 | + resp = (struct ti_sci_msg_hdr *)xfer->tx_message.buf; | |
| 2806 | + | |
| 2807 | + ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV; | |
| 2808 | + | |
| 2809 | +fail: | |
| 2810 | + ti_sci_put_one_xfer(&info->minfo, xfer); | |
| 2811 | + | |
| 2812 | + return ret; | |
| 2813 | +} | |
| 2814 | + | |
| 2815 | +/** | |
| 2816 | + * ti_sci_cmd_get_boot_status() - Command to get the processor boot status | |
| 2817 | + * @handle: Pointer to TI SCI handle | |
| 2818 | + * @proc_id: Processor ID this request is for | |
| 2819 | + * | |
| 2820 | + * Return: 0 if all went well, else returns appropriate error value. | |
| 2821 | + */ | |
| 2822 | +static int ti_sci_cmd_proc_get_status(const struct ti_sci_handle *handle, | |
| 2823 | + u8 proc_id, u64 *bv, u32 *cfg_flags, | |
| 2824 | + u32 *ctrl_flags, u32 *sts_flags) | |
| 2825 | +{ | |
| 2826 | + struct ti_sci_msg_resp_get_status *resp; | |
| 2827 | + struct ti_sci_msg_req_get_status *req; | |
| 2828 | + struct ti_sci_info *info; | |
| 2829 | + struct ti_sci_xfer *xfer; | |
| 2830 | + struct device *dev; | |
| 2831 | + int ret = 0; | |
| 2832 | + | |
| 2833 | + if (!handle) | |
| 2834 | + return -EINVAL; | |
| 2835 | + if (IS_ERR(handle)) | |
| 2836 | + return PTR_ERR(handle); | |
| 2837 | + | |
| 2838 | + info = handle_to_ti_sci_info(handle); | |
| 2839 | + dev = info->dev; | |
| 2840 | + | |
| 2841 | + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_GET_STATUS, | |
| 2842 | + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, | |
| 2843 | + sizeof(*req), sizeof(*resp)); | |
| 2844 | + if (IS_ERR(xfer)) { | |
| 2845 | + ret = PTR_ERR(xfer); | |
| 2846 | + dev_err(dev, "Message alloc failed(%d)\n", ret); | |
| 2847 | + return ret; | |
| 2848 | + } | |
| 2849 | + req = (struct ti_sci_msg_req_get_status *)xfer->xfer_buf; | |
| 2850 | + req->processor_id = proc_id; | |
| 2851 | + | |
| 2852 | + ret = ti_sci_do_xfer(info, xfer); | |
| 2853 | + if (ret) { | |
| 2854 | + dev_err(dev, "Mbox send fail %d\n", ret); | |
| 2855 | + goto fail; | |
| 2856 | + } | |
| 2857 | + | |
| 2858 | + resp = (struct ti_sci_msg_resp_get_status *)xfer->tx_message.buf; | |
| 2859 | + | |
| 2860 | + if (!ti_sci_is_response_ack(resp)) { | |
| 2861 | + ret = -ENODEV; | |
| 2862 | + } else { | |
| 2863 | + *bv = (resp->bootvector_low & TI_SCI_ADDR_LOW_MASK) | | |
| 2864 | + (((u64)resp->bootvector_high << TI_SCI_ADDR_HIGH_SHIFT) & | |
| 2865 | + TI_SCI_ADDR_HIGH_MASK); | |
| 2866 | + *cfg_flags = resp->config_flags; | |
| 2867 | + *ctrl_flags = resp->control_flags; | |
| 2868 | + *sts_flags = resp->status_flags; | |
| 2869 | + } | |
| 2870 | + | |
| 2871 | +fail: | |
| 2872 | + ti_sci_put_one_xfer(&info->minfo, xfer); | |
| 2873 | + | |
| 2874 | + return ret; | |
| 2875 | +} | |
| 2876 | + | |
| 2877 | +/* | |
| 2878 | + * ti_sci_setup_ops() - Setup the operations structures | |
| 2879 | + * @info: pointer to TISCI pointer | |
| 2880 | + */ | |
| 2881 | +static void ti_sci_setup_ops(struct ti_sci_info *info) | |
| 2882 | +{ | |
| 2883 | + struct ti_sci_ops *ops = &info->handle.ops; | |
| 2884 | + struct ti_sci_core_ops *core_ops = &ops->core_ops; | |
| 2885 | + struct ti_sci_dev_ops *dops = &ops->dev_ops; | |
| 2886 | + struct ti_sci_clk_ops *cops = &ops->clk_ops; | |
| 2887 | + struct ti_sci_rm_core_ops *rm_core_ops = &ops->rm_core_ops; | |
| 2888 | + struct ti_sci_rm_irq_ops *iops = &ops->rm_irq_ops; | |
| 2889 | + struct ti_sci_rm_ringacc_ops *rops = &ops->rm_ring_ops; | |
| 2890 | + struct ti_sci_rm_psil_ops *psilops = &ops->rm_psil_ops; | |
| 2891 | + struct ti_sci_rm_udmap_ops *udmap_ops = &ops->rm_udmap_ops; | |
| 2892 | + struct ti_sci_proc_ops *pops = &ops->proc_ops; | |
| 2893 | + | |
| 2894 | + core_ops->reboot_device = ti_sci_cmd_core_reboot; | |
| 2895 | + | |
| 2896 | + dops->get_device = ti_sci_cmd_get_device; | |
| 2897 | + dops->idle_device = ti_sci_cmd_idle_device; | |
| 2898 | + dops->put_device = ti_sci_cmd_put_device; | |
| 2899 | + | |
| 2900 | + dops->is_valid = ti_sci_cmd_dev_is_valid; | |
| 2901 | + dops->get_context_loss_count = ti_sci_cmd_dev_get_clcnt; | |
| 2902 | + dops->is_idle = ti_sci_cmd_dev_is_idle; | |
| 2903 | + dops->is_stop = ti_sci_cmd_dev_is_stop; | |
| 2904 | + dops->is_on = ti_sci_cmd_dev_is_on; | |
| 2905 | + dops->is_transitioning = ti_sci_cmd_dev_is_trans; | |
| 2906 | + dops->set_device_resets = ti_sci_cmd_set_device_resets; | |
| 2907 | + dops->get_device_resets = ti_sci_cmd_get_device_resets; | |
| 2908 | + | |
| 2909 | + cops->get_clock = ti_sci_cmd_get_clock; | |
| 2910 | + cops->idle_clock = ti_sci_cmd_idle_clock; | |
| 2911 | + cops->put_clock = ti_sci_cmd_put_clock; | |
| 2912 | + cops->is_auto = ti_sci_cmd_clk_is_auto; | |
| 2913 | + cops->is_on = ti_sci_cmd_clk_is_on; | |
| 2914 | + cops->is_off = ti_sci_cmd_clk_is_off; | |
| 2915 | + | |
| 2916 | + cops->set_parent = ti_sci_cmd_clk_set_parent; | |
| 2917 | + cops->get_parent = ti_sci_cmd_clk_get_parent; | |
| 2918 | + cops->get_num_parents = ti_sci_cmd_clk_get_num_parents; | |
| 2919 | + | |
| 2920 | + cops->get_best_match_freq = ti_sci_cmd_clk_get_match_freq; | |
| 2921 | + cops->set_freq = ti_sci_cmd_clk_set_freq; | |
| 2922 | + cops->get_freq = ti_sci_cmd_clk_get_freq; | |
| 2923 | + | |
| 2924 | + rm_core_ops->get_range = ti_sci_cmd_get_resource_range; | |
| 2925 | + rm_core_ops->get_range_from_shost = | |
| 2926 | + ti_sci_cmd_get_resource_range_from_shost; | |
| 2927 | + | |
| 2928 | + iops->set_irq = ti_sci_cmd_set_irq; | |
| 2929 | + iops->set_event_map = ti_sci_cmd_set_event_map; | |
| 2930 | + iops->free_irq = ti_sci_cmd_free_irq; | |
| 2931 | + iops->free_event_map = ti_sci_cmd_free_event_map; | |
| 2932 | + | |
| 2933 | + rops->config = ti_sci_cmd_ring_config; | |
| 2934 | + rops->get_config = ti_sci_cmd_ring_get_config; | |
| 2935 | + | |
| 2936 | + psilops->pair = ti_sci_cmd_rm_psil_pair; | |
| 2937 | + psilops->unpair = ti_sci_cmd_rm_psil_unpair; | |
| 2938 | + | |
| 2939 | + udmap_ops->tx_ch_cfg = ti_sci_cmd_rm_udmap_tx_ch_cfg; | |
| 2940 | + udmap_ops->rx_ch_cfg = ti_sci_cmd_rm_udmap_rx_ch_cfg; | |
| 2941 | + udmap_ops->rx_flow_cfg = ti_sci_cmd_rm_udmap_rx_flow_cfg; | |
| 2942 | + | |
| 2943 | + pops->request = ti_sci_cmd_proc_request; | |
| 2944 | + pops->release = ti_sci_cmd_proc_release; | |
| 2945 | + pops->handover = ti_sci_cmd_proc_handover; | |
| 2946 | + pops->set_config = ti_sci_cmd_proc_set_config; | |
| 2947 | + pops->set_control = ti_sci_cmd_proc_set_control; | |
| 2948 | + pops->get_status = ti_sci_cmd_proc_get_status; | |
| 2949 | +} | |
| 2950 | + | |
| 2951 | +/** | |
| 2952 | + * ti_sci_get_handle() - Get the TI SCI handle for a device | |
| 2953 | + * @dev: Pointer to device for which we want SCI handle | |
| 2954 | + * | |
| 2955 | + * NOTE: The function does not track individual clients of the framework | |
| 2956 | + * and is expected to be maintained by caller of TI SCI protocol library. | |
| 2957 | + * ti_sci_put_handle must be balanced with successful ti_sci_get_handle | |
| 2958 | + * Return: pointer to handle if successful, else: | |
| 2959 | + * -EPROBE_DEFER if the instance is not ready | |
| 2960 | + * -ENODEV if the required node handler is missing | |
| 2961 | + * -EINVAL if invalid conditions are encountered. | |
| 2962 | + */ | |
| 2963 | +const struct ti_sci_handle *ti_sci_get_handle(struct device *dev) | |
| 2964 | +{ | |
| 2965 | + struct device_node *ti_sci_np; | |
| 2966 | + struct list_head *p; | |
| 2967 | + struct ti_sci_handle *handle = NULL; | |
| 2968 | + struct ti_sci_info *info; | |
| 2969 | + | |
| 2970 | + if (!dev) { | |
| 2971 | + pr_err("I need a device pointer\n"); | |
| 2972 | + return ERR_PTR(-EINVAL); | |
| 2973 | + } | |
| 2974 | + ti_sci_np = of_get_parent(dev->of_node); | |
| 2975 | + if (!ti_sci_np) { | |
| 2976 | + dev_err(dev, "No OF information\n"); | |
| 2977 | + return ERR_PTR(-EINVAL); | |
| 2978 | + } | |
| 2979 | + | |
| 2980 | + mutex_lock(&ti_sci_list_mutex); | |
| 2981 | + list_for_each(p, &ti_sci_list) { | |
| 2982 | + info = list_entry(p, struct ti_sci_info, node); | |
| 2983 | + if (ti_sci_np == info->dev->of_node) { | |
| 2984 | + handle = &info->handle; | |
| 2985 | + info->users++; | |
| 2986 | + break; | |
| 2987 | + } | |
| 2988 | + } | |
| 2989 | + mutex_unlock(&ti_sci_list_mutex); | |
| 2990 | + of_node_put(ti_sci_np); | |
| 2991 | + | |
| 2992 | + if (!handle) | |
| 2993 | + return ERR_PTR(-EPROBE_DEFER); | |
| 2994 | + | |
| 2995 | + return handle; | |
| 2996 | +} | |
| 2997 | +EXPORT_SYMBOL_GPL(ti_sci_get_handle); | |
| 2998 | + | |
| 2999 | +/** | |
| 3000 | + * ti_sci_put_handle() - Release the handle acquired by ti_sci_get_handle | |
| 3001 | + * @handle: Handle acquired by ti_sci_get_handle | |
| 3002 | + * | |
| 3003 | + * NOTE: The function does not track individual clients of the framework | |
| 3004 | + * and is expected to be maintained by caller of TI SCI protocol library. | |
| 3005 | + * ti_sci_put_handle must be balanced with successful ti_sci_get_handle | |
| 3006 | + * | |
| 3007 | + * Return: 0 is successfully released | |
| 3008 | + * if an error pointer was passed, it returns the error value back, | |
| 3009 | + * if null was passed, it returns -EINVAL; | |
| 3010 | + */ | |
| 3011 | +int ti_sci_put_handle(const struct ti_sci_handle *handle) | |
| 3012 | +{ | |
| 3013 | + struct ti_sci_info *info; | |
| 3014 | + | |
| 3015 | + if (IS_ERR(handle)) | |
| 3016 | + return PTR_ERR(handle); | |
| 3017 | + if (!handle) | |
| 3018 | + return -EINVAL; | |
| 3019 | + | |
| 3020 | + info = handle_to_ti_sci_info(handle); | |
| 3021 | + mutex_lock(&ti_sci_list_mutex); | |
| 3022 | + if (!WARN_ON(!info->users)) | |
| 3023 | + info->users--; | |
| 3024 | + mutex_unlock(&ti_sci_list_mutex); | |
| 3025 | + | |
| 3026 | + return 0; | |
| 3027 | +} | |
| 3028 | +EXPORT_SYMBOL_GPL(ti_sci_put_handle); | |
| 3029 | + | |
| 3030 | +static void devm_ti_sci_release(struct device *dev, void *res) | |
| 3031 | +{ | |
| 3032 | + const struct ti_sci_handle **ptr = res; | |
| 3033 | + const struct ti_sci_handle *handle = *ptr; | |
| 3034 | + int ret; | |
| 3035 | + | |
| 3036 | + ret = ti_sci_put_handle(handle); | |
| 3037 | + if (ret) | |
| 3038 | + dev_err(dev, "failed to put handle %d\n", ret); | |
| 3039 | +} | |
| 3040 | + | |
| 3041 | +/** | |
| 3042 | + * devm_ti_sci_get_handle() - Managed get handle | |
| 3043 | + * @dev: device for which we want SCI handle for. | |
| 3044 | + * | |
| 3045 | + * NOTE: This releases the handle once the device resources are | |
| 3046 | + * no longer needed. MUST NOT BE released with ti_sci_put_handle. | |
| 3047 | + * The function does not track individual clients of the framework | |
| 3048 | + * and is expected to be maintained by caller of TI SCI protocol library. | |
| 3049 | + * | |
| 3050 | + * Return: 0 if all went fine, else corresponding error. | |
| 3051 | + */ | |
| 3052 | +const struct ti_sci_handle *devm_ti_sci_get_handle(struct device *dev) | |
| 3053 | +{ | |
| 3054 | + const struct ti_sci_handle **ptr; | |
| 3055 | + const struct ti_sci_handle *handle; | |
| 3056 | + | |
| 3057 | + ptr = devres_alloc(devm_ti_sci_release, sizeof(*ptr), GFP_KERNEL); | |
| 3058 | + if (!ptr) | |
| 3059 | + return ERR_PTR(-ENOMEM); | |
| 3060 | + handle = ti_sci_get_handle(dev); | |
| 3061 | + | |
| 3062 | + if (!IS_ERR(handle)) { | |
| 3063 | + *ptr = handle; | |
| 3064 | + devres_add(dev, ptr); | |
| 3065 | + } else { | |
| 3066 | + devres_free(ptr); | |
| 3067 | + } | |
| 3068 | + | |
| 3069 | + return handle; | |
| 3070 | +} | |
| 3071 | +EXPORT_SYMBOL_GPL(devm_ti_sci_get_handle); | |
| 3072 | + | |
| 3073 | +/** | |
| 3074 | + * ti_sci_get_by_phandle() - Get the TI SCI handle using DT phandle | |
| 3075 | + * @np: device node | |
| 3076 | + * @property: property name containing phandle on TISCI node | |
| 3077 | + * | |
| 3078 | + * NOTE: The function does not track individual clients of the framework | |
| 3079 | + * and is expected to be maintained by caller of TI SCI protocol library. | |
| 3080 | + * ti_sci_put_handle must be balanced with successful ti_sci_get_by_phandle | |
| 3081 | + * Return: pointer to handle if successful, else: | |
| 3082 | + * -EPROBE_DEFER if the instance is not ready | |
| 3083 | + * -ENODEV if the required node handler is missing | |
| 3084 | + * -EINVAL if invalid conditions are encountered. | |
| 3085 | + */ | |
| 3086 | +const struct ti_sci_handle *ti_sci_get_by_phandle(struct device_node *np, | |
| 3087 | + const char *property) | |
| 3088 | +{ | |
| 3089 | + struct ti_sci_handle *handle = NULL; | |
| 3090 | + struct device_node *ti_sci_np; | |
| 3091 | + struct ti_sci_info *info; | |
| 3092 | + struct list_head *p; | |
| 3093 | + | |
| 3094 | + if (!np) { | |
| 3095 | + pr_err("I need a device pointer\n"); | |
| 2258 | 3096 | return ERR_PTR(-EINVAL); |
| 2259 | 3097 | } |
| 2260 | 3098 | |
| @@ -2395,6 +3233,7 @@ devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle, · 134 unmodified lines | ||
| 2395 | 3233 | struct device *dev, u32 dev_id, char *of_prop) |
| 2396 | 3234 | { |
| 2397 | 3235 | struct ti_sci_resource *res; |
| 3236 | + bool valid_set = false; | |
| 2398 | 3237 | u32 resource_subtype; |
| 2399 | 3238 | int i, ret; |
| 2400 | 3239 | |
| @@ -2426,15 +3265,18 @@ devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle, · 25 unmodified lines | ||
| 2426 | 3265 | &res->desc[i].start, |
| 2427 | 3266 | &res->desc[i].num); |
| 2428 | 3267 | if (ret) { |
| 2429 | − dev_err(dev, "dev = %d subtype %d not allocated for this host\n", | |
| 3268 | + dev_dbg(dev, "dev = %d subtype %d not allocated for this host\n", | |
| 2430 | 3269 | dev_id, resource_subtype); |
| 2431 | − return ERR_PTR(ret); | |
| 3270 | + res->desc[i].start = 0; | |
| 3271 | + res->desc[i].num = 0; | |
| 3272 | + continue; | |
| 2432 | 3273 | } |
| 2433 | 3274 | |
| 2434 | 3275 | dev_dbg(dev, "dev = %d, subtype = %d, start = %d, num = %d\n", |
| 2435 | 3276 | dev_id, resource_subtype, res->desc[i].start, |
| 2436 | 3277 | res->desc[i].num); |
| 2437 | 3278 | |
| 3279 | + valid_set = true; | |
| 2438 | 3280 | res->desc[i].res_map = |
| 2439 | 3281 | devm_kzalloc(dev, BITS_TO_LONGS(res->desc[i].num) * |
| 2440 | 3282 | sizeof(*res->desc[i].res_map), GFP_KERNEL); |
| @@ -2443,7 +3285,10 @@ devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle, · 2 unmodified lines | ||
| 2443 | 3285 | } |
| 2444 | 3286 | raw_spin_lock_init(&res->lock); |
| 2445 | 3287 | |
| 2446 | − return res; | |
| 3288 | + if (valid_set) | |
| 3289 | + return res; | |
| 3290 | + | |
| 3291 | + return ERR_PTR(-EINVAL); | |
| 2447 | 3292 | } |
| 2448 | 3293 | |
| 2449 | 3294 | static int tisci_reboot_handler(struct notifier_block *nb, unsigned long mode, |
| @@ -42,6 +42,43 @@ · 41 unmodified lines | ||
| 42 | 42 | #define TI_SCI_MSG_SET_IRQ 0x1000 |
| 43 | 43 | #define TI_SCI_MSG_FREE_IRQ 0x1001 |
| 44 | 44 | |
| 45 | +/* NAVSS resource management */ | |
| 46 | +/* Ringacc requests */ | |
| 47 | +#define TI_SCI_MSG_RM_RING_ALLOCATE 0x1100 | |
| 48 | +#define TI_SCI_MSG_RM_RING_FREE 0x1101 | |
| 49 | +#define TI_SCI_MSG_RM_RING_RECONFIG 0x1102 | |
| 50 | +#define TI_SCI_MSG_RM_RING_RESET 0x1103 | |
| 51 | +#define TI_SCI_MSG_RM_RING_CFG 0x1110 | |
| 52 | +#define TI_SCI_MSG_RM_RING_GET_CFG 0x1111 | |
| 53 | + | |
| 54 | +/* PSI-L requests */ | |
| 55 | +#define TI_SCI_MSG_RM_PSIL_PAIR 0x1280 | |
| 56 | +#define TI_SCI_MSG_RM_PSIL_UNPAIR 0x1281 | |
| 57 | + | |
| 58 | +#define TI_SCI_MSG_RM_UDMAP_TX_ALLOC 0x1200 | |
| 59 | +#define TI_SCI_MSG_RM_UDMAP_TX_FREE 0x1201 | |
| 60 | +#define TI_SCI_MSG_RM_UDMAP_RX_ALLOC 0x1210 | |
| 61 | +#define TI_SCI_MSG_RM_UDMAP_RX_FREE 0x1211 | |
| 62 | +#define TI_SCI_MSG_RM_UDMAP_FLOW_CFG 0x1220 | |
| 63 | +#define TI_SCI_MSG_RM_UDMAP_OPT_FLOW_CFG 0x1221 | |
| 64 | + | |
| 65 | +#define TISCI_MSG_RM_UDMAP_TX_CH_CFG 0x1205 | |
| 66 | +#define TISCI_MSG_RM_UDMAP_TX_CH_GET_CFG 0x1206 | |
| 67 | +#define TISCI_MSG_RM_UDMAP_RX_CH_CFG 0x1215 | |
| 68 | +#define TISCI_MSG_RM_UDMAP_RX_CH_GET_CFG 0x1216 | |
| 69 | +#define TISCI_MSG_RM_UDMAP_FLOW_CFG 0x1230 | |
| 70 | +#define TISCI_MSG_RM_UDMAP_FLOW_SIZE_THRESH_CFG 0x1231 | |
| 71 | +#define TISCI_MSG_RM_UDMAP_FLOW_GET_CFG 0x1232 | |
| 72 | +#define TISCI_MSG_RM_UDMAP_FLOW_SIZE_THRESH_GET_CFG 0x1233 | |
| 73 | + | |
| 74 | +/* Processor Control requests */ | |
| 75 | +#define TI_SCI_MSG_PROC_REQUEST 0xc000 | |
| 76 | +#define TI_SCI_MSG_PROC_RELEASE 0xc001 | |
| 77 | +#define TI_SCI_MSG_PROC_HANDOVER 0xc005 | |
| 78 | +#define TI_SCI_MSG_SET_CONFIG 0xc100 | |
| 79 | +#define TI_SCI_MSG_SET_CTRL 0xc101 | |
| 80 | +#define TI_SCI_MSG_GET_STATUS 0xc400 | |
| 81 | + | |
| 45 | 82 | /** |
| 46 | 83 | * struct ti_sci_msg_hdr - Generic Message Header for All messages and responses |
| 47 | 84 | * @type: Type of messages: One of TI_SCI_MSG* values |
| @@ -604,4 +641,777 @@ struct ti_sci_msg_req_manage_irq { · 556 unmodified lines | ||
| 604 | 641 | u8 secondary_host; |
| 605 | 642 | } __packed; |
| 606 | 643 | |
| 644 | +/** | |
| 645 | + * struct ti_sci_msg_rm_ring_cfg_req - Configure a Navigator Subsystem ring | |
| 646 | + * | |
| 647 | + * Configures the non-real-time registers of a Navigator Subsystem ring. | |
| 648 | + * @hdr: Generic Header | |
| 649 | + * @valid_params: Bitfield defining validity of ring configuration parameters. | |
| 650 | + * The ring configuration fields are not valid, and will not be used for | |
| 651 | + * ring configuration, if their corresponding valid bit is zero. | |
| 652 | + * Valid bit usage: | |
| 653 | + * 0 - Valid bit for @tisci_msg_rm_ring_cfg_req addr_lo | |
| 654 | + * 1 - Valid bit for @tisci_msg_rm_ring_cfg_req addr_hi | |
| 655 | + * 2 - Valid bit for @tisci_msg_rm_ring_cfg_req count | |
| 656 | + * 3 - Valid bit for @tisci_msg_rm_ring_cfg_req mode | |
| 657 | + * 4 - Valid bit for @tisci_msg_rm_ring_cfg_req size | |
| 658 | + * 5 - Valid bit for @tisci_msg_rm_ring_cfg_req order_id | |
| 659 | + * @nav_id: Device ID of Navigator Subsystem from which the ring is allocated | |
| 660 | + * @index: ring index to be configured. | |
| 661 | + * @addr_lo: 32 LSBs of ring base address to be programmed into the ring's | |
| 662 | + * RING_BA_LO register | |
| 663 | + * @addr_hi: 16 MSBs of ring base address to be programmed into the ring's | |
| 664 | + * RING_BA_HI register. | |
| 665 | + * @count: Number of ring elements. Must be even if mode is CREDENTIALS or QM | |
| 666 | + * modes. | |
| 667 | + * @mode: Specifies the mode the ring is to be configured. | |
| 668 | + * @size: Specifies encoded ring element size. To calculate the encoded size use | |
| 669 | + * the formula (log2(size_bytes) - 2), where size_bytes cannot be | |
| 670 | + * greater than 256. | |
| 671 | + * @order_id: Specifies the ring's bus order ID. | |
| 672 | + */ | |
| 673 | +struct ti_sci_msg_rm_ring_cfg_req { | |
| 674 | + struct ti_sci_msg_hdr hdr; | |
| 675 | + u32 valid_params; | |
| 676 | + u16 nav_id; | |
| 677 | + u16 index; | |
| 678 | + u32 addr_lo; | |
| 679 | + u32 addr_hi; | |
| 680 | + u32 count; | |
| 681 | + u8 mode; | |
| 682 | + u8 size; | |
| 683 | + u8 order_id; | |
| 684 | +} __packed; | |
| 685 | + | |
| 686 | +/** | |
| 687 | + * struct ti_sci_msg_rm_ring_get_cfg_req - Get RA ring's configuration | |
| 688 | + * | |
| 689 | + * Gets the configuration of the non-real-time register fields of a ring. The | |
| 690 | + * host, or a supervisor of the host, who owns the ring must be the requesting | |
| 691 | + * host. The values of the non-real-time registers are returned in | |
| 692 | + * @ti_sci_msg_rm_ring_get_cfg_resp. | |
| 693 | + * | |
| 694 | + * @hdr: Generic Header | |
| 695 | + * @nav_id: Device ID of Navigator Subsystem from which the ring is allocated | |
| 696 | + * @index: ring index. | |
| 697 | + */ | |
| 698 | +struct ti_sci_msg_rm_ring_get_cfg_req { | |
| 699 | + struct ti_sci_msg_hdr hdr; | |
| 700 | + u16 nav_id; | |
| 701 | + u16 index; | |
| 702 | +} __packed; | |
| 703 | + | |
| 704 | +/** | |
| 705 | + * struct ti_sci_msg_rm_ring_get_cfg_resp - Ring get configuration response | |
| 706 | + * | |
| 707 | + * Response received by host processor after RM has handled | |
| 708 | + * @ti_sci_msg_rm_ring_get_cfg_req. The response contains the ring's | |
| 709 | + * non-real-time register values. | |
| 710 | + * | |
| 711 | + * @hdr: Generic Header | |
| 712 | + * @addr_lo: Ring 32 LSBs of base address | |
| 713 | + * @addr_hi: Ring 16 MSBs of base address. | |
| 714 | + * @count: Ring number of elements. | |
| 715 | + * @mode: Ring mode. | |
| 716 | + * @size: encoded Ring element size | |
| 717 | + * @order_id: ing order ID. | |
| 718 | + */ | |
| 719 | +struct ti_sci_msg_rm_ring_get_cfg_resp { | |
| 720 | + struct ti_sci_msg_hdr hdr; | |
| 721 | + u32 addr_lo; | |
| 722 | + u32 addr_hi; | |
| 723 | + u32 count; | |
| 724 | + u8 mode; | |
| 725 | + u8 size; | |
| 726 | + u8 order_id; | |
| 727 | +} __packed; | |
| 728 | + | |
| 729 | +/** | |
| 730 | + * struct ti_sci_msg_psil_pair - Pairs a PSI-L source thread to a destination | |
| 731 | + * thread | |
| 732 | + * @hdr: Generic Header | |
| 733 | + * @nav_id: SoC Navigator Subsystem device ID whose PSI-L config proxy is | |
| 734 | + * used to pair the source and destination threads. | |
| 735 | + * @src_thread: PSI-L source thread ID within the PSI-L System thread map. | |
| 736 | + * | |
| 737 | + * UDMAP transmit channels mapped to source threads will have their | |
| 738 | + * TCHAN_THRD_ID register programmed with the destination thread if the pairing | |
| 739 | + * is successful. | |
| 740 | + | |
| 741 | + * @dst_thread: PSI-L destination thread ID within the PSI-L System thread map. | |
| 742 | + * PSI-L destination threads start at index 0x8000. The request is NACK'd if | |
| 743 | + * the destination thread is not greater than or equal to 0x8000. | |
| 744 | + * | |
| 745 | + * UDMAP receive channels mapped to destination threads will have their | |
| 746 | + * RCHAN_THRD_ID register programmed with the source thread if the pairing | |
| 747 | + * is successful. | |
| 748 | + * | |
| 749 | + * Request type is TI_SCI_MSG_RM_PSIL_PAIR, response is a generic ACK or NACK | |
| 750 | + * message. | |
| 751 | + */ | |
| 752 | +struct ti_sci_msg_psil_pair { | |
| 753 | + struct ti_sci_msg_hdr hdr; | |
| 754 | + u32 nav_id; | |
| 755 | + u32 src_thread; | |
| 756 | + u32 dst_thread; | |
| 757 | +} __packed; | |
| 758 | + | |
| 759 | +/** | |
| 760 | + * struct ti_sci_msg_psil_unpair - Unpairs a PSI-L source thread from a | |
| 761 | + * destination thread | |
| 762 | + * @hdr: Generic Header | |
| 763 | + * @nav_id: SoC Navigator Subsystem device ID whose PSI-L config proxy is | |
| 764 | + * used to unpair the source and destination threads. | |
| 765 | + * @src_thread: PSI-L source thread ID within the PSI-L System thread map. | |
| 766 | + * | |
| 767 | + * UDMAP transmit channels mapped to source threads will have their | |
| 768 | + * TCHAN_THRD_ID register cleared if the unpairing is successful. | |
| 769 | + * | |
| 770 | + * @dst_thread: PSI-L destination thread ID within the PSI-L System thread map. | |
| 771 | + * PSI-L destination threads start at index 0x8000. The request is NACK'd if | |
| 772 | + * the destination thread is not greater than or equal to 0x8000. | |
| 773 | + * | |
| 774 | + * UDMAP receive channels mapped to destination threads will have their | |
| 775 | + * RCHAN_THRD_ID register cleared if the unpairing is successful. | |
| 776 | + * | |
| 777 | + * Request type is TI_SCI_MSG_RM_PSIL_UNPAIR, response is a generic ACK or NACK | |
| 778 | + * message. | |
| 779 | + */ | |
| 780 | +struct ti_sci_msg_psil_unpair { | |
| 781 | + struct ti_sci_msg_hdr hdr; | |
| 782 | + u32 nav_id; | |
| 783 | + u32 src_thread; | |
| 784 | + u32 dst_thread; | |
| 785 | +} __packed; | |
| 786 | + | |
| 787 | +/** | |
| 788 | + * struct ti_sci_msg_udmap_rx_flow_cfg - UDMAP receive flow configuration | |
| 789 | + * message | |
| 790 | + * @hdr: Generic Header | |
| 791 | + * @nav_id: SoC Navigator Subsystem device ID from which the receive flow is | |
| 792 | + * allocated | |
| 793 | + * @flow_index: UDMAP receive flow index for non-optional configuration. | |
| 794 | + * @rx_ch_index: Specifies the index of the receive channel using the flow_index | |
| 795 | + * @rx_einfo_present: UDMAP receive flow extended packet info present. | |
| 796 | + * @rx_psinfo_present: UDMAP receive flow PS words present. | |
| 797 | + * @rx_error_handling: UDMAP receive flow error handling configuration. Valid | |
| 798 | + * values are TI_SCI_RM_UDMAP_RX_FLOW_ERR_DROP/RETRY. | |
| 799 | + * @rx_desc_type: UDMAP receive flow descriptor type. It can be one of | |
| 800 | + * TI_SCI_RM_UDMAP_RX_FLOW_DESC_HOST/MONO. | |
| 801 | + * @rx_sop_offset: UDMAP receive flow start of packet offset. | |
| 802 | + * @rx_dest_qnum: UDMAP receive flow destination queue number. | |
| 803 | + * @rx_ps_location: UDMAP receive flow PS words location. | |
| 804 | + * 0 - end of packet descriptor | |
| 805 | + * 1 - Beginning of the data buffer | |
| 806 | + * @rx_src_tag_hi: UDMAP receive flow source tag high byte constant | |
| 807 | + * @rx_src_tag_lo: UDMAP receive flow source tag low byte constant | |
| 808 | + * @rx_dest_tag_hi: UDMAP receive flow destination tag high byte constant | |
| 809 | + * @rx_dest_tag_lo: UDMAP receive flow destination tag low byte constant | |
| 810 | + * @rx_src_tag_hi_sel: UDMAP receive flow source tag high byte selector | |
| 811 | + * @rx_src_tag_lo_sel: UDMAP receive flow source tag low byte selector | |
| 812 | + * @rx_dest_tag_hi_sel: UDMAP receive flow destination tag high byte selector | |
| 813 | + * @rx_dest_tag_lo_sel: UDMAP receive flow destination tag low byte selector | |
| 814 | + * @rx_size_thresh_en: UDMAP receive flow packet size based free buffer queue | |
| 815 | + * enable. If enabled, the ti_sci_rm_udmap_rx_flow_opt_cfg also need to be | |
| 816 | + * configured and sent. | |
| 817 | + * @rx_fdq0_sz0_qnum: UDMAP receive flow free descriptor queue 0. | |
| 818 | + * @rx_fdq1_qnum: UDMAP receive flow free descriptor queue 1. | |
| 819 | + * @rx_fdq2_qnum: UDMAP receive flow free descriptor queue 2. | |
| 820 | + * @rx_fdq3_qnum: UDMAP receive flow free descriptor queue 3. | |
| 821 | + * | |
| 822 | + * For detailed information on the settings, see the UDMAP section of the TRM. | |
| 823 | + */ | |
| 824 | +struct ti_sci_msg_udmap_rx_flow_cfg { | |
| 825 | + struct ti_sci_msg_hdr hdr; | |
| 826 | + u32 nav_id; | |
| 827 | + u32 flow_index; | |
| 828 | + u32 rx_ch_index; | |
| 829 | + u8 rx_einfo_present; | |
| 830 | + u8 rx_psinfo_present; | |
| 831 | + u8 rx_error_handling; | |
| 832 | + u8 rx_desc_type; | |
| 833 | + u16 rx_sop_offset; | |
| 834 | + u16 rx_dest_qnum; | |
| 835 | + u8 rx_ps_location; | |
| 836 | + u8 rx_src_tag_hi; | |
| 837 | + u8 rx_src_tag_lo; | |
| 838 | + u8 rx_dest_tag_hi; | |
| 839 | + u8 rx_dest_tag_lo; | |
| 840 | + u8 rx_src_tag_hi_sel; | |
| 841 | + u8 rx_src_tag_lo_sel; | |
| 842 | + u8 rx_dest_tag_hi_sel; | |
| 843 | + u8 rx_dest_tag_lo_sel; | |
| 844 | + u8 rx_size_thresh_en; | |
| 845 | + u16 rx_fdq0_sz0_qnum; | |
| 846 | + u16 rx_fdq1_qnum; | |
| 847 | + u16 rx_fdq2_qnum; | |
| 848 | + u16 rx_fdq3_qnum; | |
| 849 | +} __packed; | |
| 850 | + | |
| 851 | +/** | |
| 852 | + * struct rm_ti_sci_msg_udmap_rx_flow_opt_cfg - parameters for UDMAP receive | |
| 853 | + * flow optional configuration | |
| 854 | + * @hdr: Generic Header | |
| 855 | + * @nav_id: SoC Navigator Subsystem device ID from which the receive flow is | |
| 856 | + * allocated | |
| 857 | + * @flow_index: UDMAP receive flow index for optional configuration. | |
| 858 | + * @rx_ch_index: Specifies the index of the receive channel using the flow_index | |
| 859 | + * @rx_size_thresh0: UDMAP receive flow packet size threshold 0. | |
| 860 | + * @rx_size_thresh1: UDMAP receive flow packet size threshold 1. | |
| 861 | + * @rx_size_thresh2: UDMAP receive flow packet size threshold 2. | |
| 862 | + * @rx_fdq0_sz1_qnum: UDMAP receive flow free descriptor queue for size | |
| 863 | + * threshold 1. | |
| 864 | + * @rx_fdq0_sz2_qnum: UDMAP receive flow free descriptor queue for size | |
| 865 | + * threshold 2. | |
| 866 | + * @rx_fdq0_sz3_qnum: UDMAP receive flow free descriptor queue for size | |
| 867 | + * threshold 3. | |
| 868 | + * | |
| 869 | + * For detailed information on the settings, see the UDMAP section of the TRM. | |
| 870 | + */ | |
| 871 | +struct rm_ti_sci_msg_udmap_rx_flow_opt_cfg { | |
| 872 | + struct ti_sci_msg_hdr hdr; | |
| 873 | + u32 nav_id; | |
| 874 | + u32 flow_index; | |
| 875 | + u32 rx_ch_index; | |
| 876 | + u16 rx_size_thresh0; | |
| 877 | + u16 rx_size_thresh1; | |
| 878 | + u16 rx_size_thresh2; | |
| 879 | + u16 rx_fdq0_sz1_qnum; | |
| 880 | + u16 rx_fdq0_sz2_qnum; | |
| 881 | + u16 rx_fdq0_sz3_qnum; | |
| 882 | +} __packed; | |
| 883 | + | |
| 884 | +/** | |
| 885 | + * Configures a Navigator Subsystem UDMAP transmit channel | |
| 886 | + * | |
| 887 | + * Configures the non-real-time registers of a Navigator Subsystem UDMAP | |
| 888 | + * transmit channel. The channel index must be assigned to the host defined | |
| 889 | + * in the TISCI header via the RM board configuration resource assignment | |
| 890 | + * range list. | |
| 891 | + * | |
| 892 | + * @hdr: Generic Header | |
| 893 | + * | |
| 894 | + * @valid_params: Bitfield defining validity of tx channel configuration | |
| 895 | + * parameters. The tx channel configuration fields are not valid, and will not | |
| 896 | + * be used for ch configuration, if their corresponding valid bit is zero. | |
| 897 | + * Valid bit usage: | |
| 898 | + * 0 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_pause_on_err | |
| 899 | + * 1 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_atype | |
| 900 | + * 2 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_chan_type | |
| 901 | + * 3 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_fetch_size | |
| 902 | + * 4 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::txcq_qnum | |
| 903 | + * 5 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_priority | |
| 904 | + * 6 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_qos | |
| 905 | + * 7 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_orderid | |
| 906 | + * 8 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_sched_priority | |
| 907 | + * 9 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_filt_einfo | |
| 908 | + * 10 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_filt_pswords | |
| 909 | + * 11 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_supr_tdpkt | |
| 910 | + * 12 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_credit_count | |
| 911 | + * 13 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::fdepth | |
| 912 | + * 14 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_burst_size | |
| 913 | + * | |
| 914 | + * @nav_id: SoC device ID of Navigator Subsystem where tx channel is located | |
| 915 | + * | |
| 916 | + * @index: UDMAP transmit channel index. | |
| 917 | + * | |
| 918 | + * @tx_pause_on_err: UDMAP transmit channel pause on error configuration to | |
| 919 | + * be programmed into the tx_pause_on_err field of the channel's TCHAN_TCFG | |
| 920 | + * register. | |
| 921 | + * | |
| 922 | + * @tx_filt_einfo: UDMAP transmit channel extended packet information passing | |
| 923 | + * configuration to be programmed into the tx_filt_einfo field of the | |
| 924 | + * channel's TCHAN_TCFG register. | |
| 925 | + * | |
| 926 | + * @tx_filt_pswords: UDMAP transmit channel protocol specific word passing | |
| 927 | + * configuration to be programmed into the tx_filt_pswords field of the | |
| 928 | + * channel's TCHAN_TCFG register. | |
| 929 | + * | |
| 930 | + * @tx_atype: UDMAP transmit channel non Ring Accelerator access pointer | |
| 931 | + * interpretation configuration to be programmed into the tx_atype field of | |
| 932 | + * the channel's TCHAN_TCFG register. | |
| 933 | + * | |
| 934 | + * @tx_chan_type: UDMAP transmit channel functional channel type and work | |
| 935 | + * passing mechanism configuration to be programmed into the tx_chan_type | |
| 936 | + * field of the channel's TCHAN_TCFG register. | |
| 937 | + * | |
| 938 | + * @tx_supr_tdpkt: UDMAP transmit channel teardown packet generation suppression | |
| 939 | + * configuration to be programmed into the tx_supr_tdpkt field of the channel's | |
| 940 | + * TCHAN_TCFG register. | |
| 941 | + * | |
| 942 | + * @tx_fetch_size: UDMAP transmit channel number of 32-bit descriptor words to | |
| 943 | + * fetch configuration to be programmed into the tx_fetch_size field of the | |
| 944 | + * channel's TCHAN_TCFG register. The user must make sure to set the maximum | |
| 945 | + * word count that can pass through the channel for any allowed descriptor type. | |
| 946 | + * | |
| 947 | + * @tx_credit_count: UDMAP transmit channel transfer request credit count | |
| 948 | + * configuration to be programmed into the count field of the TCHAN_TCREDIT | |
| 949 | + * register. Specifies how many credits for complete TRs are available. | |
| 950 | + * | |
| 951 | + * @txcq_qnum: UDMAP transmit channel completion queue configuration to be | |
| 952 | + * programmed into the txcq_qnum field of the TCHAN_TCQ register. The specified | |
| 953 | + * completion queue must be assigned to the host, or a subordinate of the host, | |
| 954 | + * requesting configuration of the transmit channel. | |
| 955 | + * | |
| 956 | + * @tx_priority: UDMAP transmit channel transmit priority value to be programmed | |
| 957 | + * into the priority field of the channel's TCHAN_TPRI_CTRL register. | |
| 958 | + * | |
| 959 | + * @tx_qos: UDMAP transmit channel transmit qos value to be programmed into the | |
| 960 | + * qos field of the channel's TCHAN_TPRI_CTRL register. | |
| 961 | + * | |
| 962 | + * @tx_orderid: UDMAP transmit channel bus order id value to be programmed into | |
| 963 | + * the orderid field of the channel's TCHAN_TPRI_CTRL register. | |
| 964 | + * | |
| 965 | + * @fdepth: UDMAP transmit channel FIFO depth configuration to be programmed | |
| 966 | + * into the fdepth field of the TCHAN_TFIFO_DEPTH register. Sets the number of | |
| 967 | + * Tx FIFO bytes which are allowed to be stored for the channel. Check the UDMAP | |
| 968 | + * section of the TRM for restrictions regarding this parameter. | |
| 969 | + * | |
| 970 | + * @tx_sched_priority: UDMAP transmit channel tx scheduling priority | |
| 971 | + * configuration to be programmed into the priority field of the channel's | |
| 972 | + * TCHAN_TST_SCHED register. | |
| 973 | + * | |
| 974 | + * @tx_burst_size: UDMAP transmit channel burst size configuration to be | |
| 975 | + * programmed into the tx_burst_size field of the TCHAN_TCFG register. | |
| 976 | + */ | |
| 977 | +struct ti_sci_msg_rm_udmap_tx_ch_cfg_req { | |
| 978 | + struct ti_sci_msg_hdr hdr; | |
| 979 | + u32 valid_params; | |
| 980 | + u16 nav_id; | |
| 981 | + u16 index; | |
| 982 | + u8 tx_pause_on_err; | |
| 983 | + u8 tx_filt_einfo; | |
| 984 | + u8 tx_filt_pswords; | |
| 985 | + u8 tx_atype; | |
| 986 | + u8 tx_chan_type; | |
| 987 | + u8 tx_supr_tdpkt; | |
| 988 | + u16 tx_fetch_size; | |
| 989 | + u8 tx_credit_count; | |
| 990 | + u16 txcq_qnum; | |
| 991 | + u8 tx_priority; | |
| 992 | + u8 tx_qos; | |
| 993 | + u8 tx_orderid; | |
| 994 | + u16 fdepth; | |
| 995 | + u8 tx_sched_priority; | |
| 996 | + u8 tx_burst_size; | |
| 997 | +} __packed; | |
| 998 | + | |
| 999 | +/** | |
| 1000 | + * Configures a Navigator Subsystem UDMAP receive channel | |
| 1001 | + * | |
| 1002 | + * Configures the non-real-time registers of a Navigator Subsystem UDMAP | |
| 1003 | + * receive channel. The channel index must be assigned to the host defined | |
| 1004 | + * in the TISCI header via the RM board configuration resource assignment | |
| 1005 | + * range list. | |
| 1006 | + * | |
| 1007 | + * @hdr: Generic Header | |
| 1008 | + * | |
| 1009 | + * @valid_params: Bitfield defining validity of rx channel configuration | |
| 1010 | + * parameters. | |
| 1011 | + * The rx channel configuration fields are not valid, and will not be used for | |
| 1012 | + * ch configuration, if their corresponding valid bit is zero. | |
| 1013 | + * Valid bit usage: | |
| 1014 | + * 0 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_pause_on_err | |
| 1015 | + * 1 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_atype | |
| 1016 | + * 2 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_chan_type | |
| 1017 | + * 3 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_fetch_size | |
| 1018 | + * 4 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rxcq_qnum | |
| 1019 | + * 5 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_priority | |
| 1020 | + * 6 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_qos | |
| 1021 | + * 7 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_orderid | |
| 1022 | + * 8 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_sched_priority | |
| 1023 | + * 9 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::flowid_start | |
| 1024 | + * 10 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::flowid_cnt | |
| 1025 | + * 11 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_ignore_short | |
| 1026 | + * 12 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_ignore_long | |
| 1027 | + * 14 - Valid bit for @ti_sci_msg_rm_udmap_rx_ch_cfg_req::rx_burst_size | |
| 1028 | + * | |
| 1029 | + * @nav_id: SoC device ID of Navigator Subsystem where rx channel is located | |
| 1030 | + * | |
| 1031 | + * @index: UDMAP receive channel index. | |
| 1032 | + * | |
| 1033 | + * @rx_fetch_size: UDMAP receive channel number of 32-bit descriptor words to | |
| 1034 | + * fetch configuration to be programmed into the rx_fetch_size field of the | |
| 1035 | + * channel's RCHAN_RCFG register. | |
| 1036 | + * | |
| 1037 | + * @rxcq_qnum: UDMAP receive channel completion queue configuration to be | |
| 1038 | + * programmed into the rxcq_qnum field of the RCHAN_RCQ register. | |
| 1039 | + * The specified completion queue must be assigned to the host, or a subordinate | |
| 1040 | + * of the host, requesting configuration of the receive channel. | |
| 1041 | + * | |
| 1042 | + * @rx_priority: UDMAP receive channel receive priority value to be programmed | |
| 1043 | + * into the priority field of the channel's RCHAN_RPRI_CTRL register. | |
| 1044 | + * | |
| 1045 | + * @rx_qos: UDMAP receive channel receive qos value to be programmed into the | |
| 1046 | + * qos field of the channel's RCHAN_RPRI_CTRL register. | |
| 1047 | + * | |
| 1048 | + * @rx_orderid: UDMAP receive channel bus order id value to be programmed into | |
| 1049 | + * the orderid field of the channel's RCHAN_RPRI_CTRL register. | |
| 1050 | + * | |
| 1051 | + * @rx_sched_priority: UDMAP receive channel rx scheduling priority | |
| 1052 | + * configuration to be programmed into the priority field of the channel's | |
| 1053 | + * RCHAN_RST_SCHED register. | |
| 1054 | + * | |
| 1055 | + * @flowid_start: UDMAP receive channel additional flows starting index | |
| 1056 | + * configuration to program into the flow_start field of the RCHAN_RFLOW_RNG | |
| 1057 | + * register. Specifies the starting index for flow IDs the receive channel is to | |
| 1058 | + * make use of beyond the default flow. flowid_start and @ref flowid_cnt must be | |
| 1059 | + * set as valid and configured together. The starting flow ID set by | |
| 1060 | + * @ref flowid_cnt must be a flow index within the Navigator Subsystem's subset | |
| 1061 | + * of flows beyond the default flows statically mapped to receive channels. | |
| 1062 | + * The additional flows must be assigned to the host, or a subordinate of the | |
| 1063 | + * host, requesting configuration of the receive channel. | |
| 1064 | + * | |
| 1065 | + * @flowid_cnt: UDMAP receive channel additional flows count configuration to | |
| 1066 | + * program into the flowid_cnt field of the RCHAN_RFLOW_RNG register. | |
| 1067 | + * This field specifies how many flow IDs are in the additional contiguous range | |
| 1068 | + * of legal flow IDs for the channel. @ref flowid_start and flowid_cnt must be | |
| 1069 | + * set as valid and configured together. Disabling the valid_params field bit | |
| 1070 | + * for flowid_cnt indicates no flow IDs other than the default are to be | |
| 1071 | + * allocated and used by the receive channel. @ref flowid_start plus flowid_cnt | |
| 1072 | + * cannot be greater than the number of receive flows in the receive channel's | |
| 1073 | + * Navigator Subsystem. The additional flows must be assigned to the host, or a | |
| 1074 | + * subordinate of the host, requesting configuration of the receive channel. | |
| 1075 | + * | |
| 1076 | + * @rx_pause_on_err: UDMAP receive channel pause on error configuration to be | |
| 1077 | + * programmed into the rx_pause_on_err field of the channel's RCHAN_RCFG | |
| 1078 | + * register. | |
| 1079 | + * | |
| 1080 | + * @rx_atype: UDMAP receive channel non Ring Accelerator access pointer | |
| 1081 | + * interpretation configuration to be programmed into the rx_atype field of the | |
| 1082 | + * channel's RCHAN_RCFG register. | |
| 1083 | + * | |
| 1084 | + * @rx_chan_type: UDMAP receive channel functional channel type and work passing | |
| 1085 | + * mechanism configuration to be programmed into the rx_chan_type field of the | |
| 1086 | + * channel's RCHAN_RCFG register. | |
| 1087 | + * | |
| 1088 | + * @rx_ignore_short: UDMAP receive channel short packet treatment configuration | |
| 1089 | + * to be programmed into the rx_ignore_short field of the RCHAN_RCFG register. | |
| 1090 | + * | |
| 1091 | + * @rx_ignore_long: UDMAP receive channel long packet treatment configuration to | |
| 1092 | + * be programmed into the rx_ignore_long field of the RCHAN_RCFG register. | |
| 1093 | + * | |
| 1094 | + * @rx_burst_size: UDMAP receive channel burst size configuration to be | |
| 1095 | + * programmed into the rx_burst_size field of the RCHAN_RCFG register. | |
| 1096 | + */ | |
| 1097 | +struct ti_sci_msg_rm_udmap_rx_ch_cfg_req { | |
| 1098 | + struct ti_sci_msg_hdr hdr; | |
| 1099 | + u32 valid_params; | |
| 1100 | + u16 nav_id; | |
| 1101 | + u16 index; | |
| 1102 | + u16 rx_fetch_size; | |
| 1103 | + u16 rxcq_qnum; | |
| 1104 | + u8 rx_priority; | |
| 1105 | + u8 rx_qos; | |
| 1106 | + u8 rx_orderid; | |
| 1107 | + u8 rx_sched_priority; | |
| 1108 | + u16 flowid_start; | |
| 1109 | + u16 flowid_cnt; | |
| 1110 | + u8 rx_pause_on_err; | |
| 1111 | + u8 rx_atype; | |
| 1112 | + u8 rx_chan_type; | |
| 1113 | + u8 rx_ignore_short; | |
| 1114 | + u8 rx_ignore_long; | |
| 1115 | + u8 rx_burst_size; | |
| 1116 | +} __packed; | |
| 1117 | + | |
| 1118 | +/** | |
| 1119 | + * Configures a Navigator Subsystem UDMAP receive flow | |
| 1120 | + * | |
| 1121 | + * Configures a Navigator Subsystem UDMAP receive flow's registers. | |
| 1122 | + * Configuration does not include the flow registers which handle size-based | |
| 1123 | + * free descriptor queue routing. | |
| 1124 | + * | |
| 1125 | + * The flow index must be assigned to the host defined in the TISCI header via | |
| 1126 | + * the RM board configuration resource assignment range list. | |
| 1127 | + * | |
| 1128 | + * @hdr: Standard TISCI header | |
| 1129 | + * | |
| 1130 | + * @valid_params | |
| 1131 | + * Bitfield defining validity of rx flow configuration parameters. The | |
| 1132 | + * rx flow configuration fields are not valid, and will not be used for flow | |
| 1133 | + * configuration, if their corresponding valid bit is zero. Valid bit usage: | |
| 1134 | + * 0 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_einfo_present | |
| 1135 | + * 1 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_psinfo_present | |
| 1136 | + * 2 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_error_handling | |
| 1137 | + * 3 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_desc_type | |
| 1138 | + * 4 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_sop_offset | |
| 1139 | + * 5 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_dest_qnum | |
| 1140 | + * 6 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_src_tag_hi | |
| 1141 | + * 7 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_src_tag_lo | |
| 1142 | + * 8 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_dest_tag_hi | |
| 1143 | + * 9 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_dest_tag_lo | |
| 1144 | + * 10 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_src_tag_hi_sel | |
| 1145 | + * 11 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_src_tag_lo_sel | |
| 1146 | + * 12 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_dest_tag_hi_sel | |
| 1147 | + * 13 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_dest_tag_lo_sel | |
| 1148 | + * 14 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_fdq0_sz0_qnum | |
| 1149 | + * 15 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_fdq1_sz0_qnum | |
| 1150 | + * 16 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_fdq2_sz0_qnum | |
| 1151 | + * 17 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_fdq3_sz0_qnum | |
| 1152 | + * 18 - Valid bit for @tisci_msg_rm_udmap_flow_cfg_req::rx_ps_location | |
| 1153 | + * | |
| 1154 | + * @nav_id: SoC device ID of Navigator Subsystem from which the receive flow is | |
| 1155 | + * allocated | |
| 1156 | + * | |
| 1157 | + * @flow_index: UDMAP receive flow index for non-optional configuration. | |
| 1158 | + * | |
| 1159 | + * @rx_einfo_present: | |
| 1160 | + * UDMAP receive flow extended packet info present configuration to be | |
| 1161 | + * programmed into the rx_einfo_present field of the flow's RFLOW_RFA register. | |
| 1162 | + * | |
| 1163 | + * @rx_psinfo_present: | |
| 1164 | + * UDMAP receive flow PS words present configuration to be programmed into the | |
| 1165 | + * rx_psinfo_present field of the flow's RFLOW_RFA register. | |
| 1166 | + * | |
| 1167 | + * @rx_error_handling: | |
| 1168 | + * UDMAP receive flow error handling configuration to be programmed into the | |
| 1169 | + * rx_error_handling field of the flow's RFLOW_RFA register. | |
| 1170 | + * | |
| 1171 | + * @rx_desc_type: | |
| 1172 | + * UDMAP receive flow descriptor type configuration to be programmed into the | |
| 1173 | + * rx_desc_type field field of the flow's RFLOW_RFA register. | |
| 1174 | + * | |
| 1175 | + * @rx_sop_offset: | |
| 1176 | + * UDMAP receive flow start of packet offset configuration to be programmed | |
| 1177 | + * into the rx_sop_offset field of the RFLOW_RFA register. See the UDMAP | |
| 1178 | + * section of the TRM for more information on this setting. Valid values for | |
| 1179 | + * this field are 0-255 bytes. | |
| 1180 | + * | |
| 1181 | + * @rx_dest_qnum: | |
| 1182 | + * UDMAP receive flow destination queue configuration to be programmed into the | |
| 1183 | + * rx_dest_qnum field of the flow's RFLOW_RFA register. The specified | |
| 1184 | + * destination queue must be valid within the Navigator Subsystem and must be | |
| 1185 | + * owned by the host, or a subordinate of the host, requesting allocation and | |
| 1186 | + * configuration of the receive flow. | |
| 1187 | + * | |
| 1188 | + * @rx_src_tag_hi: | |
| 1189 | + * UDMAP receive flow source tag high byte constant configuration to be | |
| 1190 | + * programmed into the rx_src_tag_hi field of the flow's RFLOW_RFB register. | |
| 1191 | + * See the UDMAP section of the TRM for more information on this setting. | |
| 1192 | + * | |
| 1193 | + * @rx_src_tag_lo: | |
| 1194 | + * UDMAP receive flow source tag low byte constant configuration to be | |
| 1195 | + * programmed into the rx_src_tag_lo field of the flow's RFLOW_RFB register. | |
| 1196 | + * See the UDMAP section of the TRM for more information on this setting. | |
| 1197 | + * | |
| 1198 | + * @rx_dest_tag_hi: | |
| 1199 | + * UDMAP receive flow destination tag high byte constant configuration to be | |
| 1200 | + * programmed into the rx_dest_tag_hi field of the flow's RFLOW_RFB register. | |
| 1201 | + * See the UDMAP section of the TRM for more information on this setting. | |
| 1202 | + * | |
| 1203 | + * @rx_dest_tag_lo: | |
| 1204 | + * UDMAP receive flow destination tag low byte constant configuration to be | |
| 1205 | + * programmed into the rx_dest_tag_lo field of the flow's RFLOW_RFB register. | |
| 1206 | + * See the UDMAP section of the TRM for more information on this setting. | |
| 1207 | + * | |
| 1208 | + * @rx_src_tag_hi_sel: | |
| 1209 | + * UDMAP receive flow source tag high byte selector configuration to be | |
| 1210 | + * programmed into the rx_src_tag_hi_sel field of the RFLOW_RFC register. See | |
| 1211 | + * the UDMAP section of the TRM for more information on this setting. | |
| 1212 | + * | |
| 1213 | + * @rx_src_tag_lo_sel: | |
| 1214 | + * UDMAP receive flow source tag low byte selector configuration to be | |
| 1215 | + * programmed into the rx_src_tag_lo_sel field of the RFLOW_RFC register. See | |
| 1216 | + * the UDMAP section of the TRM for more information on this setting. | |
| 1217 | + * | |
| 1218 | + * @rx_dest_tag_hi_sel: | |
| 1219 | + * UDMAP receive flow destination tag high byte selector configuration to be | |
| 1220 | + * programmed into the rx_dest_tag_hi_sel field of the RFLOW_RFC register. See | |
| 1221 | + * the UDMAP section of the TRM for more information on this setting. | |
| 1222 | + * | |
| 1223 | + * @rx_dest_tag_lo_sel: | |
| 1224 | + * UDMAP receive flow destination tag low byte selector configuration to be | |
| 1225 | + * programmed into the rx_dest_tag_lo_sel field of the RFLOW_RFC register. See | |
| 1226 | + * the UDMAP section of the TRM for more information on this setting. | |
| 1227 | + * | |
| 1228 | + * @rx_fdq0_sz0_qnum: | |
| 1229 | + * UDMAP receive flow free descriptor queue 0 configuration to be programmed | |
| 1230 | + * into the rx_fdq0_sz0_qnum field of the flow's RFLOW_RFD register. See the | |
| 1231 | + * UDMAP section of the TRM for more information on this setting. The specified | |
| 1232 | + * free queue must be valid within the Navigator Subsystem and must be owned | |
| 1233 | + * by the host, or a subordinate of the host, requesting allocation and | |
| 1234 | + * configuration of the receive flow. | |
| 1235 | + * | |
| 1236 | + * @rx_fdq1_qnum: | |
| 1237 | + * UDMAP receive flow free descriptor queue 1 configuration to be programmed | |
| 1238 | + * into the rx_fdq1_qnum field of the flow's RFLOW_RFD register. See the | |
| 1239 | + * UDMAP section of the TRM for more information on this setting. The specified | |
| 1240 | + * free queue must be valid within the Navigator Subsystem and must be owned | |
| 1241 | + * by the host, or a subordinate of the host, requesting allocation and | |
| 1242 | + * configuration of the receive flow. | |
| 1243 | + * | |
| 1244 | + * @rx_fdq2_qnum: | |
| 1245 | + * UDMAP receive flow free descriptor queue 2 configuration to be programmed | |
| 1246 | + * into the rx_fdq2_qnum field of the flow's RFLOW_RFE register. See the | |
| 1247 | + * UDMAP section of the TRM for more information on this setting. The specified | |
| 1248 | + * free queue must be valid within the Navigator Subsystem and must be owned | |
| 1249 | + * by the host, or a subordinate of the host, requesting allocation and | |
| 1250 | + * configuration of the receive flow. | |
| 1251 | + * | |
| 1252 | + * @rx_fdq3_qnum: | |
| 1253 | + * UDMAP receive flow free descriptor queue 3 configuration to be programmed | |
| 1254 | + * into the rx_fdq3_qnum field of the flow's RFLOW_RFE register. See the | |
| 1255 | + * UDMAP section of the TRM for more information on this setting. The specified | |
| 1256 | + * free queue must be valid within the Navigator Subsystem and must be owned | |
| 1257 | + * by the host, or a subordinate of the host, requesting allocation and | |
| 1258 | + * configuration of the receive flow. | |
| 1259 | + * | |
| 1260 | + * @rx_ps_location: | |
| 1261 | + * UDMAP receive flow PS words location configuration to be programmed into the | |
| 1262 | + * rx_ps_location field of the flow's RFLOW_RFA register. | |
| 1263 | + */ | |
| 1264 | +struct ti_sci_msg_rm_udmap_flow_cfg_req { | |
| 1265 | + struct ti_sci_msg_hdr hdr; | |
| 1266 | + u32 valid_params; | |
| 1267 | + u16 nav_id; | |
| 1268 | + u16 flow_index; | |
| 1269 | + u8 rx_einfo_present; | |
| 1270 | + u8 rx_psinfo_present; | |
| 1271 | + u8 rx_error_handling; | |
| 1272 | + u8 rx_desc_type; | |
| 1273 | + u16 rx_sop_offset; | |
| 1274 | + u16 rx_dest_qnum; | |
| 1275 | + u8 rx_src_tag_hi; | |
| 1276 | + u8 rx_src_tag_lo; | |
| 1277 | + u8 rx_dest_tag_hi; | |
| 1278 | + u8 rx_dest_tag_lo; | |
| 1279 | + u8 rx_src_tag_hi_sel; | |
| 1280 | + u8 rx_src_tag_lo_sel; | |
| 1281 | + u8 rx_dest_tag_hi_sel; | |
| 1282 | + u8 rx_dest_tag_lo_sel; | |
| 1283 | + u16 rx_fdq0_sz0_qnum; | |
| 1284 | + u16 rx_fdq1_qnum; | |
| 1285 | + u16 rx_fdq2_qnum; | |
| 1286 | + u16 rx_fdq3_qnum; | |
| 1287 | + u8 rx_ps_location; | |
| 1288 | +} __packed; | |
| 1289 | + | |
| 1290 | +/** | |
| 1291 | + * struct ti_sci_msg_req_proc_request - Request a processor | |
| 1292 | + * @hdr: Generic Header | |
| 1293 | + * @processor_id: ID of processor being requested | |
| 1294 | + * | |
| 1295 | + * Request type is TI_SCI_MSG_PROC_REQUEST, response is a generic ACK/NACK | |
| 1296 | + * message. | |
| 1297 | + */ | |
| 1298 | +struct ti_sci_msg_req_proc_request { | |
| 1299 | + struct ti_sci_msg_hdr hdr; | |
| 1300 | + u8 processor_id; | |
| 1301 | +} __packed; | |
| 1302 | + | |
| 1303 | +/** | |
| 1304 | + * struct ti_sci_msg_req_proc_release - Release a processor | |
| 1305 | + * @hdr: Generic Header | |
| 1306 | + * @processor_id: ID of processor being released | |
| 1307 | + * | |
| 1308 | + * Request type is TI_SCI_MSG_PROC_RELEASE, response is a generic ACK/NACK | |
| 1309 | + * message. | |
| 1310 | + */ | |
| 1311 | +struct ti_sci_msg_req_proc_release { | |
| 1312 | + struct ti_sci_msg_hdr hdr; | |
| 1313 | + u8 processor_id; | |
| 1314 | +} __packed; | |
| 1315 | + | |
| 1316 | +/** | |
| 1317 | + * struct ti_sci_msg_req_proc_handover - Handover a processor to a host | |
| 1318 | + * @hdr: Generic Header | |
| 1319 | + * @processor_id: ID of processor being handed over | |
| 1320 | + * @host_id: Host ID the control needs to be transferred to | |
| 1321 | + * | |
| 1322 | + * Request type is TI_SCI_MSG_PROC_HANDOVER, response is a generic ACK/NACK | |
| 1323 | + * message. | |
| 1324 | + */ | |
| 1325 | +struct ti_sci_msg_req_proc_handover { | |
| 1326 | + struct ti_sci_msg_hdr hdr; | |
| 1327 | + u8 processor_id; | |
| 1328 | + u8 host_id; | |
| 1329 | +} __packed; | |
| 1330 | + | |
| 1331 | +/* Boot Vector masks */ | |
| 1332 | +#define TI_SCI_ADDR_LOW_MASK GENMASK_ULL(31, 0) | |
| 1333 | +#define TI_SCI_ADDR_HIGH_MASK GENMASK_ULL(63, 32) | |
| 1334 | +#define TI_SCI_ADDR_HIGH_SHIFT 32 | |
| 1335 | + | |
| 1336 | +/** | |
| 1337 | + * struct ti_sci_msg_req_set_config - Set Processor boot configuration | |
| 1338 | + * @hdr: Generic Header | |
| 1339 | + * @processor_id: ID of processor being configured | |
| 1340 | + * @bootvector_low: Lower 32 bit address (Little Endian) of boot vector | |
| 1341 | + * @bootvector_high: Higher 32 bit address (Little Endian) of boot vector | |
| 1342 | + * @config_flags_set: Optional Processor specific Config Flags to set. | |
| 1343 | + * Setting a bit here implies the corresponding mode | |
| 1344 | + * will be set | |
| 1345 | + * @config_flags_clear: Optional Processor specific Config Flags to clear. | |
| 1346 | + * Setting a bit here implies the corresponding mode | |
| 1347 | + * will be cleared | |
| 1348 | + * | |
| 1349 | + * Request type is TI_SCI_MSG_PROC_HANDOVER, response is a generic ACK/NACK | |
| 1350 | + * message. | |
| 1351 | + */ | |
| 1352 | +struct ti_sci_msg_req_set_config { | |
| 1353 | + struct ti_sci_msg_hdr hdr; | |
| 1354 | + u8 processor_id; | |
| 1355 | + u32 bootvector_low; | |
| 1356 | + u32 bootvector_high; | |
| 1357 | + u32 config_flags_set; | |
| 1358 | + u32 config_flags_clear; | |
| 1359 | +} __packed; | |
| 1360 | + | |
| 1361 | +/** | |
| 1362 | + * struct ti_sci_msg_req_set_ctrl - Set Processor boot control flags | |
| 1363 | + * @hdr: Generic Header | |
| 1364 | + * @processor_id: ID of processor being configured | |
| 1365 | + * @control_flags_set: Optional Processor specific Control Flags to set. | |
| 1366 | + * Setting a bit here implies the corresponding mode | |
| 1367 | + * will be set | |
| 1368 | + * @control_flags_clear:Optional Processor specific Control Flags to clear. | |
| 1369 | + * Setting a bit here implies the corresponding mode | |
| 1370 | + * will be cleared | |
| 1371 | + * | |
| 1372 | + * Request type is TI_SCI_MSG_SET_CTRL, response is a generic ACK/NACK | |
| 1373 | + * message. | |
| 1374 | + */ | |
| 1375 | +struct ti_sci_msg_req_set_ctrl { | |
| 1376 | + struct ti_sci_msg_hdr hdr; | |
| 1377 | + u8 processor_id; | |
| 1378 | + u32 control_flags_set; | |
| 1379 | + u32 control_flags_clear; | |
| 1380 | +} __packed; | |
| 1381 | + | |
| 1382 | +/** | |
| 1383 | + * struct ti_sci_msg_req_get_status - Processor boot status request | |
| 1384 | + * @hdr: Generic Header | |
| 1385 | + * @processor_id: ID of processor whose status is being requested | |
| 1386 | + * | |
| 1387 | + * Request type is TI_SCI_MSG_GET_STATUS, response is an appropriate | |
| 1388 | + * message, or NACK in case of inability to satisfy request. | |
| 1389 | + */ | |
| 1390 | +struct ti_sci_msg_req_get_status { | |
| 1391 | + struct ti_sci_msg_hdr hdr; | |
| 1392 | + u8 processor_id; | |
| 1393 | +} __packed; | |
| 1394 | + | |
| 1395 | +/** | |
| 1396 | + * struct ti_sci_msg_resp_get_status - Processor boot status response | |
| 1397 | + * @hdr: Generic Header | |
| 1398 | + * @processor_id: ID of processor whose status is returned | |
| 1399 | + * @bootvector_low: Lower 32 bit address (Little Endian) of boot vector | |
| 1400 | + * @bootvector_high: Higher 32 bit address (Little Endian) of boot vector | |
| 1401 | + * @config_flags: Optional Processor specific Config Flags set currently | |
| 1402 | + * @control_flags: Optional Processor specific Control Flags set currently | |
| 1403 | + * @status_flags: Optional Processor specific Status Flags set currently | |
| 1404 | + * | |
| 1405 | + * Response structure to a TI_SCI_MSG_GET_STATUS request. | |
| 1406 | + */ | |
| 1407 | +struct ti_sci_msg_resp_get_status { | |
| 1408 | + struct ti_sci_msg_hdr hdr; | |
| 1409 | + u8 processor_id; | |
| 1410 | + u32 bootvector_low; | |
| 1411 | + u32 bootvector_high; | |
| 1412 | + u32 config_flags; | |
| 1413 | + u32 control_flags; | |
| 1414 | + u32 status_flags; | |
| 1415 | +} __packed; | |
| 1416 | + | |
| 607 | 1417 | #endif /* __TI_SCI_H */ |
| @@ -18,6 +18,50 @@ struct scmi_sensors { · 17 unmodified lines | ||
| 18 | 18 | const struct scmi_sensor_info **info[hwmon_max]; |
| 19 | 19 | }; |
| 20 | 20 | |
| 21 | +static inline u64 __pow10(u8 x) | |
| 22 | +{ | |
| 23 | + u64 r = 1; | |
| 24 | + | |
| 25 | + while (x--) | |
| 26 | + r *= 10; | |
| 27 | + | |
| 28 | + return r; | |
| 29 | +} | |
| 30 | + | |
| 31 | +static int scmi_hwmon_scale(const struct scmi_sensor_info *sensor, u64 *value) | |
| 32 | +{ | |
| 33 | + s8 scale = sensor->scale; | |
| 34 | + u64 f; | |
| 35 | + | |
| 36 | + switch (sensor->type) { | |
| 37 | + case TEMPERATURE_C: | |
| 38 | + case VOLTAGE: | |
| 39 | + case CURRENT: | |
| 40 | + scale += 3; | |
| 41 | + break; | |
| 42 | + case POWER: | |
| 43 | + case ENERGY: | |
| 44 | + scale += 6; | |
| 45 | + break; | |
| 46 | + default: | |
| 47 | + break; | |
| 48 | + } | |
| 49 | + | |
| 50 | + if (scale == 0) | |
| 51 | + return 0; | |
| 52 | + | |
| 53 | + if (abs(scale) > 19) | |
| 54 | + return -E2BIG; | |
| 55 | + | |
| 56 | + f = __pow10(abs(scale)); | |
| 57 | + if (scale > 0) | |
| 58 | + *value *= f; | |
| 59 | + else | |
| 60 | + *value = div64_u64(*value, f); | |
| 61 | + | |
| 62 | + return 0; | |
| 63 | +} | |
| 64 | + | |
| 21 | 65 | static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, |
| 22 | 66 | u32 attr, int channel, long *val) |
| 23 | 67 | { |
| @@ -29,6 +73,10 @@ static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, · 5 unmodified lines | ||
| 29 | 73 | |
| 30 | 74 | sensor = *(scmi_sensors->info[type] + channel); |
| 31 | 75 | ret = h->sensor_ops->reading_get(h, sensor->id, false, &value); |
| 76 | + if (ret) | |
| 77 | + return ret; | |
| 78 | + | |
| 79 | + ret = scmi_hwmon_scale(sensor, &value); | |
| 32 | 80 | if (!ret) |
| 33 | 81 | *val = value; |
| 34 | 82 | |
| @@ -8,6 +8,14 @@ menuconfig MEMORY · 7 unmodified lines | ||
| 8 | 8 | |
| 9 | 9 | if MEMORY |
| 10 | 10 | |
| 11 | +config DDR | |
| 12 | + bool | |
| 13 | + help | |
| 14 | + Data from JEDEC specs for DDR SDRAM memories, | |
| 15 | + particularly the AC timing parameters and addressing | |
| 16 | + information. This data is useful for drivers handling | |
| 17 | + DDR SDRAM controllers. | |
| 18 | + | |
| 11 | 19 | config ARM_PL172_MPMC |
| 12 | 20 | tristate "ARM PL172 MPMC driver" |
| 13 | 21 | depends on ARM_AMBA && OF |
| @@ -3,6 +3,7 @@ · 2 unmodified lines | ||
| 3 | 3 | # Makefile for memory devices |
| 4 | 4 | # |
| 5 | 5 | |
| 6 | +obj-$(CONFIG_DDR) += jedec_ddr_data.o | |
| 6 | 7 | ifeq ($(CONFIG_DDR),y) |
| 7 | 8 | obj-$(CONFIG_OF) += of_memory.o |
| 8 | 9 | endif |
| @@ -33,10 +33,10 @@ · 32 unmodified lines | ||
| 33 | 33 | #include <linux/io.h> |
| 34 | 34 | #include <linux/module.h> |
| 35 | 35 | #include <linux/of_address.h> |
| 36 | +#include <linux/of_device.h> | |
| 36 | 37 | #include <linux/platform_device.h> |
| 37 | 38 | |
| 38 | 39 | #define DRVNAME "brcmstb-dpfe" |
| 39 | −#define FIRMWARE_NAME "dpfe.bin" | |
| 40 | 40 | |
| 41 | 41 | /* DCPU register offsets */ |
| 42 | 42 | #define REG_DCPU_RESET 0x0 |
| @@ -59,6 +59,7 @@ · 16 unmodified lines | ||
| 59 | 59 | #define DRAM_INFO_MR4 0x4 |
| 60 | 60 | #define DRAM_INFO_ERROR 0x8 |
| 61 | 61 | #define DRAM_INFO_MR4_MASK 0xff |
| 62 | +#define DRAM_INFO_MR4_SHIFT 24 /* We need to look at byte 3 */ | |
| 62 | 63 | |
| 63 | 64 | /* DRAM MR4 Offsets & Masks */ |
| 64 | 65 | #define DRAM_MR4_REFRESH 0x0 /* Refresh rate */ |
| @@ -73,13 +74,23 @@ · 8 unmodified lines | ||
| 73 | 74 | #define DRAM_MR4_TH_OFFS_MASK 0x3 |
| 74 | 75 | #define DRAM_MR4_TUF_MASK 0x1 |
| 75 | 76 | |
| 76 | −/* DRAM Vendor Offsets & Masks */ | |
| 77 | +/* DRAM Vendor Offsets & Masks (API v2) */ | |
| 77 | 78 | #define DRAM_VENDOR_MR5 0x0 |
| 78 | 79 | #define DRAM_VENDOR_MR6 0x4 |
| 79 | 80 | #define DRAM_VENDOR_MR7 0x8 |
| 80 | 81 | #define DRAM_VENDOR_MR8 0xc |
| 81 | 82 | #define DRAM_VENDOR_ERROR 0x10 |
| 82 | 83 | #define DRAM_VENDOR_MASK 0xff |
| 84 | +#define DRAM_VENDOR_SHIFT 24 /* We need to look at byte 3 */ | |
| 85 | + | |
| 86 | +/* DRAM Information Offsets & Masks (API v3) */ | |
| 87 | +#define DRAM_DDR_INFO_MR4 0x0 | |
| 88 | +#define DRAM_DDR_INFO_MR5 0x4 | |
| 89 | +#define DRAM_DDR_INFO_MR6 0x8 | |
| 90 | +#define DRAM_DDR_INFO_MR7 0xc | |
| 91 | +#define DRAM_DDR_INFO_MR8 0x10 | |
| 92 | +#define DRAM_DDR_INFO_ERROR 0x14 | |
| 93 | +#define DRAM_DDR_INFO_MASK 0xff | |
| 83 | 94 | |
| 84 | 95 | /* Reset register bits & masks */ |
| 85 | 96 | #define DCPU_RESET_SHIFT 0x0 |
| @@ -109,7 +120,7 @@ · 23 unmodified lines | ||
| 109 | 120 | #define DPFE_MSG_TYPE_COMMAND 1 |
| 110 | 121 | #define DPFE_MSG_TYPE_RESPONSE 2 |
| 111 | 122 | |
| 112 | −#define DELAY_LOOP_MAX 200000 | |
| 123 | +#define DELAY_LOOP_MAX 1000 | |
| 113 | 124 | |
| 114 | 125 | enum dpfe_msg_fields { |
| 115 | 126 | MSG_HEADER, |
| @@ -117,7 +128,7 @@ enum dpfe_msg_fields { · 1 unmodified line | ||
| 117 | 128 | MSG_ARG_COUNT, |
| 118 | 129 | MSG_ARG0, |
| 119 | 130 | MSG_CHKSUM, |
| 120 | − MSG_FIELD_MAX /* Last entry */ | |
| 131 | + MSG_FIELD_MAX = 16 /* Max number of arguments */ | |
| 121 | 132 | }; |
| 122 | 133 | |
| 123 | 134 | enum dpfe_commands { |
| @@ -127,14 +138,6 @@ enum dpfe_commands { · 3 unmodified lines | ||
| 127 | 138 | DPFE_CMD_MAX /* Last entry */ |
| 128 | 139 | }; |
| 129 | 140 | |
| 130 | −struct dpfe_msg { | |
| 131 | − u32 header; | |
| 132 | − u32 command; | |
| 133 | − u32 arg_count; | |
| 134 | − u32 arg0; | |
| 135 | − u32 chksum; /* This is the sum of all other entries. */ | |
| 136 | −}; | |
| 137 | − | |
| 138 | 141 | /* |
| 139 | 142 | * Format of the binary firmware file: |
| 140 | 143 | * |
| @@ -168,12 +171,21 @@ struct init_data { · 27 unmodified lines | ||
| 168 | 171 | bool is_big_endian; |
| 169 | 172 | }; |
| 170 | 173 | |
| 174 | +/* API version and corresponding commands */ | |
| 175 | +struct dpfe_api { | |
| 176 | + int version; | |
| 177 | + const char *fw_name; | |
| 178 | + const struct attribute_group **sysfs_attrs; | |
| 179 | + u32 command[DPFE_CMD_MAX][MSG_FIELD_MAX]; | |
| 180 | +}; | |
| 181 | + | |
| 171 | 182 | /* Things we need for as long as we are active. */ |
| 172 | 183 | struct private_data { |
| 173 | 184 | void __iomem *regs; |
| 174 | 185 | void __iomem *dmem; |
| 175 | 186 | void __iomem *imem; |
| 176 | 187 | struct device *dev; |
| 188 | + const struct dpfe_api *dpfe_api; | |
| 177 | 189 | struct mutex lock; |
| 178 | 190 | }; |
| 179 | 191 | |
| @@ -182,28 +194,99 @@ static const char *error_text[] = { · 2 unmodified lines | ||
| 182 | 194 | "Incorrect checksum", "Malformed command", "Timed out", |
| 183 | 195 | }; |
| 184 | 196 | |
| 185 | −/* List of supported firmware commands */ | |
| 186 | −static const u32 dpfe_commands[DPFE_CMD_MAX][MSG_FIELD_MAX] = { | |
| 187 | − [DPFE_CMD_GET_INFO] = { | |
| 188 | − [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND, | |
| 189 | − [MSG_COMMAND] = 1, | |
| 190 | − [MSG_ARG_COUNT] = 1, | |
| 191 | − [MSG_ARG0] = 1, | |
| 192 | − [MSG_CHKSUM] = 4, | |
| 193 | − }, | |
| 194 | − [DPFE_CMD_GET_REFRESH] = { | |
| 195 | − [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND, | |
| 196 | − [MSG_COMMAND] = 2, | |
| 197 | − [MSG_ARG_COUNT] = 1, | |
| 198 | − [MSG_ARG0] = 1, | |
| 199 | − [MSG_CHKSUM] = 5, | |
| 200 | − }, | |
| 201 | − [DPFE_CMD_GET_VENDOR] = { | |
| 202 | − [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND, | |
| 203 | − [MSG_COMMAND] = 2, | |
| 204 | − [MSG_ARG_COUNT] = 1, | |
| 205 | − [MSG_ARG0] = 2, | |
| 206 | − [MSG_CHKSUM] = 6, | |
| 197 | +/* | |
| 198 | + * Forward declaration of our sysfs attribute functions, so we can declare the | |
| 199 | + * attribute data structures early. | |
| 200 | + */ | |
| 201 | +static ssize_t show_info(struct device *, struct device_attribute *, char *); | |
| 202 | +static ssize_t show_refresh(struct device *, struct device_attribute *, char *); | |
| 203 | +static ssize_t store_refresh(struct device *, struct device_attribute *, | |
| 204 | + const char *, size_t); | |
| 205 | +static ssize_t show_vendor(struct device *, struct device_attribute *, char *); | |
| 206 | +static ssize_t show_dram(struct device *, struct device_attribute *, char *); | |
| 207 | + | |
| 208 | +/* | |
| 209 | + * Declare our attributes early, so they can be referenced in the API data | |
| 210 | + * structure. We need to do this, because the attributes depend on the API | |
| 211 | + * version. | |
| 212 | + */ | |
| 213 | +static DEVICE_ATTR(dpfe_info, 0444, show_info, NULL); | |
| 214 | +static DEVICE_ATTR(dpfe_refresh, 0644, show_refresh, store_refresh); | |
| 215 | +static DEVICE_ATTR(dpfe_vendor, 0444, show_vendor, NULL); | |
| 216 | +static DEVICE_ATTR(dpfe_dram, 0444, show_dram, NULL); | |
| 217 | + | |
| 218 | +/* API v2 sysfs attributes */ | |
| 219 | +static struct attribute *dpfe_v2_attrs[] = { | |
| 220 | + &dev_attr_dpfe_info.attr, | |
| 221 | + &dev_attr_dpfe_refresh.attr, | |
| 222 | + &dev_attr_dpfe_vendor.attr, | |
| 223 | + NULL | |
| 224 | +}; | |
| 225 | +ATTRIBUTE_GROUPS(dpfe_v2); | |
| 226 | + | |
| 227 | +/* API v3 sysfs attributes */ | |
| 228 | +static struct attribute *dpfe_v3_attrs[] = { | |
| 229 | + &dev_attr_dpfe_info.attr, | |
| 230 | + &dev_attr_dpfe_dram.attr, | |
| 231 | + NULL | |
| 232 | +}; | |
| 233 | +ATTRIBUTE_GROUPS(dpfe_v3); | |
| 234 | + | |
| 235 | +/* API v2 firmware commands */ | |
| 236 | +static const struct dpfe_api dpfe_api_v2 = { | |
| 237 | + .version = 2, | |
| 238 | + .fw_name = "dpfe.bin", | |
| 239 | + .sysfs_attrs = dpfe_v2_groups, | |
| 240 | + .command = { | |
| 241 | + [DPFE_CMD_GET_INFO] = { | |
| 242 | + [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND, | |
| 243 | + [MSG_COMMAND] = 1, | |
| 244 | + [MSG_ARG_COUNT] = 1, | |
| 245 | + [MSG_ARG0] = 1, | |
| 246 | + [MSG_CHKSUM] = 4, | |
| 247 | + }, | |
| 248 | + [DPFE_CMD_GET_REFRESH] = { | |
| 249 | + [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND, | |
| 250 | + [MSG_COMMAND] = 2, | |
| 251 | + [MSG_ARG_COUNT] = 1, | |
| 252 | + [MSG_ARG0] = 1, | |
| 253 | + [MSG_CHKSUM] = 5, | |
| 254 | + }, | |
| 255 | + [DPFE_CMD_GET_VENDOR] = { | |
| 256 | + [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND, | |
| 257 | + [MSG_COMMAND] = 2, | |
| 258 | + [MSG_ARG_COUNT] = 1, | |
| 259 | + [MSG_ARG0] = 2, | |
| 260 | + [MSG_CHKSUM] = 6, | |
| 261 | + }, | |
| 262 | + } | |
| 263 | +}; | |
| 264 | + | |
| 265 | +/* API v3 firmware commands */ | |
| 266 | +static const struct dpfe_api dpfe_api_v3 = { | |
| 267 | + .version = 3, | |
| 268 | + .fw_name = NULL, /* We expect the firmware to have been downloaded! */ | |
| 269 | + .sysfs_attrs = dpfe_v3_groups, | |
| 270 | + .command = { | |
| 271 | + [DPFE_CMD_GET_INFO] = { | |
| 272 | + [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND, | |
| 273 | + [MSG_COMMAND] = 0x0101, | |
| 274 | + [MSG_ARG_COUNT] = 1, | |
| 275 | + [MSG_ARG0] = 1, | |
| 276 | + [MSG_CHKSUM] = 0x104, | |
| 277 | + }, | |
| 278 | + [DPFE_CMD_GET_REFRESH] = { | |
| 279 | + [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND, | |
| 280 | + [MSG_COMMAND] = 0x0202, | |
| 281 | + [MSG_ARG_COUNT] = 0, | |
| 282 | + /* | |
| 283 | + * This is a bit ugly. Without arguments, the checksum | |
| 284 | + * follows right after the argument count and not at | |
| 285 | + * offset MSG_CHKSUM. | |
| 286 | + */ | |
| 287 | + [MSG_ARG0] = 0x203, | |
| 288 | + }, | |
| 289 | + /* There's no GET_VENDOR command in API v3. */ | |
| 207 | 290 | }, |
| 208 | 291 | }; |
| 209 | 292 | |
| @@ -248,13 +331,13 @@ static void __enable_dcpu(void __iomem *regs) · 38 unmodified lines | ||
| 248 | 331 | writel_relaxed(val, regs + REG_DCPU_RESET); |
| 249 | 332 | } |
| 250 | 333 | |
| 251 | −static unsigned int get_msg_chksum(const u32 msg[]) | |
| 334 | +static unsigned int get_msg_chksum(const u32 msg[], unsigned int max) | |
| 252 | 335 | { |
| 253 | 336 | unsigned int sum = 0; |
| 254 | 337 | unsigned int i; |
| 255 | 338 | |
| 256 | 339 | /* Don't include the last field in the checksum. */ |
| 257 | − for (i = 0; i < MSG_FIELD_MAX - 1; i++) | |
| 340 | + for (i = 0; i < max; i++) | |
| 258 | 341 | sum += msg[i]; |
| 259 | 342 | |
| 260 | 343 | return sum; |
| @@ -267,6 +350,11 @@ static void __iomem *get_msg_ptr(struct private_data *priv, u32 response, · 6 unmodified lines | ||
| 267 | 350 | unsigned int offset; |
| 268 | 351 | void __iomem *ptr = NULL; |
| 269 | 352 | |
| 353 | + /* There is no need to use this function for API v3 or later. */ | |
| 354 | + if (unlikely(priv->dpfe_api->version >= 3)) { | |
| 355 | + return NULL; | |
| 356 | + } | |
| 357 | + | |
| 270 | 358 | msg_type = (response >> DRAM_MSG_TYPE_OFFSET) & DRAM_MSG_TYPE_MASK; |
| 271 | 359 | offset = (response >> DRAM_MSG_ADDR_OFFSET) & DRAM_MSG_ADDR_MASK; |
| 272 | 360 | |
| @@ -294,12 +382,25 @@ static void __iomem *get_msg_ptr(struct private_data *priv, u32 response, · 21 unmodified lines | ||
| 294 | 382 | return ptr; |
| 295 | 383 | } |
| 296 | 384 | |
| 385 | +static void __finalize_command(struct private_data *priv) | |
| 386 | +{ | |
| 387 | + unsigned int release_mbox; | |
| 388 | + | |
| 389 | + /* | |
| 390 | + * It depends on the API version which MBOX register we have to write to | |
| 391 | + * to signal we are done. | |
| 392 | + */ | |
| 393 | + release_mbox = (priv->dpfe_api->version < 3) | |
| 394 | + ? REG_TO_HOST_MBOX : REG_TO_DCPU_MBOX; | |
| 395 | + writel_relaxed(0, priv->regs + release_mbox); | |
| 396 | +} | |
| 397 | + | |
| 297 | 398 | static int __send_command(struct private_data *priv, unsigned int cmd, |
| 298 | 399 | u32 result[]) |
| 299 | 400 | { |
| 300 | − const u32 *msg = dpfe_commands[cmd]; | |
| 401 | + const u32 *msg = priv->dpfe_api->command[cmd]; | |
| 301 | 402 | void __iomem *regs = priv->regs; |
| 302 | − unsigned int i, chksum; | |
| 403 | + unsigned int i, chksum, chksum_idx; | |
| 303 | 404 | int ret = 0; |
| 304 | 405 | u32 resp; |
| 305 | 406 | |
| @@ -308,6 +409,18 @@ static int __send_command(struct private_data *priv, unsigned int cmd, · 2 unmodified lines | ||
| 308 | 409 | |
| 309 | 410 | mutex_lock(&priv->lock); |
| 310 | 411 | |
| 412 | + /* Wait for DCPU to become ready */ | |
| 413 | + for (i = 0; i < DELAY_LOOP_MAX; i++) { | |
| 414 | + resp = readl_relaxed(regs + REG_TO_HOST_MBOX); | |
| 415 | + if (resp == 0) | |
| 416 | + break; | |
| 417 | + msleep(1); | |
| 418 | + } | |
| 419 | + if (resp != 0) { | |
| 420 | + mutex_unlock(&priv->lock); | |
| 421 | + return -ETIMEDOUT; | |
| 422 | + } | |
| 423 | + | |
| 311 | 424 | /* Write command and arguments to message area */ |
| 312 | 425 | for (i = 0; i < MSG_FIELD_MAX; i++) |
| 313 | 426 | writel_relaxed(msg[i], regs + DCPU_MSG_RAM(i)); |
| @@ -321,7 +434,7 @@ static int __send_command(struct private_data *priv, unsigned int cmd, · 7 unmodified lines | ||
| 321 | 434 | resp = readl_relaxed(regs + REG_TO_HOST_MBOX); |
| 322 | 435 | if (resp > 0) |
| 323 | 436 | break; |
| 324 | − udelay(5); | |
| 437 | + msleep(1); | |
| 325 | 438 | } |
| 326 | 439 | |
| 327 | 440 | if (i == DELAY_LOOP_MAX) { |
| @@ -331,10 +444,11 @@ static int __send_command(struct private_data *priv, unsigned int cmd, · 3 unmodified lines | ||
| 331 | 444 | /* Read response data */ |
| 332 | 445 | for (i = 0; i < MSG_FIELD_MAX; i++) |
| 333 | 446 | result[i] = readl_relaxed(regs + DCPU_MSG_RAM(i)); |
| 447 | + chksum_idx = result[MSG_ARG_COUNT] + MSG_ARG_COUNT + 1; | |
| 334 | 448 | } |
| 335 | 449 | |
| 336 | 450 | /* Tell DCPU we are done */ |
| 337 | − writel_relaxed(0, regs + REG_TO_HOST_MBOX); | |
| 451 | + __finalize_command(priv); | |
| 338 | 452 | |
| 339 | 453 | mutex_unlock(&priv->lock); |
| 340 | 454 | |
| @@ -342,8 +456,8 @@ static int __send_command(struct private_data *priv, unsigned int cmd, · 1 unmodified line | ||
| 342 | 456 | return ret; |
| 343 | 457 | |
| 344 | 458 | /* Verify response */ |
| 345 | − chksum = get_msg_chksum(result); | |
| 346 | − if (chksum != result[MSG_CHKSUM]) | |
| 459 | + chksum = get_msg_chksum(result, chksum_idx); | |
| 460 | + if (chksum != result[chksum_idx]) | |
| 347 | 461 | resp = DCPU_RET_ERR_CHKSUM; |
| 348 | 462 | |
| 349 | 463 | if (resp != DCPU_RET_SUCCESS) { |
| @@ -484,7 +598,15 @@ static int brcmstb_dpfe_download_firmware(struct platform_device *pdev, · 134 unmodified lines | ||
| 484 | 598 | return 0; |
| 485 | 599 | } |
| 486 | 600 | |
| 487 | − ret = request_firmware(&fw, FIRMWARE_NAME, dev); | |
| 601 | + /* | |
| 602 | + * If the firmware filename is NULL it means the boot firmware has to | |
| 603 | + * download the DCPU firmware for us. If that didn't work, we have to | |
| 604 | + * bail, since downloading it ourselves wouldn't work either. | |
| 605 | + */ | |
| 606 | + if (!priv->dpfe_api->fw_name) | |
| 607 | + return -ENODEV; | |
| 608 | + | |
| 609 | + ret = request_firmware(&fw, priv->dpfe_api->fw_name, dev); | |
| 488 | 610 | /* request_firmware() prints its own error messages. */ |
| 489 | 611 | if (ret) |
| 490 | 612 | return ret; |
| @@ -525,12 +647,10 @@ static int brcmstb_dpfe_download_firmware(struct platform_device *pdev, · 34 unmodified lines | ||
| 525 | 647 | } |
| 526 | 648 | |
| 527 | 649 | static ssize_t generic_show(unsigned int command, u32 response[], |
| 528 | − struct device *dev, char *buf) | |
| 650 | + struct private_data *priv, char *buf) | |
| 529 | 651 | { |
| 530 | − struct private_data *priv; | |
| 531 | 652 | int ret; |
| 532 | 653 | |
| 533 | − priv = dev_get_drvdata(dev); | |
| 534 | 654 | if (!priv) |
| 535 | 655 | return sprintf(buf, "ERROR: driver private data not set\n"); |
| 536 | 656 | |
| @@ -545,10 +665,12 @@ static ssize_t show_info(struct device *dev, struct device_attribute *devattr, · 8 unmodified lines | ||
| 545 | 665 | char *buf) |
| 546 | 666 | { |
| 547 | 667 | u32 response[MSG_FIELD_MAX]; |
| 668 | + struct private_data *priv; | |
| 548 | 669 | unsigned int info; |
| 549 | 670 | ssize_t ret; |
| 550 | 671 | |
| 551 | − ret = generic_show(DPFE_CMD_GET_INFO, response, dev, buf); | |
| 672 | + priv = dev_get_drvdata(dev); | |
| 673 | + ret = generic_show(DPFE_CMD_GET_INFO, response, priv, buf); | |
| 552 | 674 | if (ret) |
| 553 | 675 | return ret; |
| 554 | 676 | |
| @@ -571,17 +693,17 @@ static ssize_t show_refresh(struct device *dev, · 16 unmodified lines | ||
| 571 | 693 | u32 mr4; |
| 572 | 694 | ssize_t ret; |
| 573 | 695 | |
| 574 | − ret = generic_show(DPFE_CMD_GET_REFRESH, response, dev, buf); | |
| 696 | + priv = dev_get_drvdata(dev); | |
| 697 | + ret = generic_show(DPFE_CMD_GET_REFRESH, response, priv, buf); | |
| 575 | 698 | if (ret) |
| 576 | 699 | return ret; |
| 577 | 700 | |
| 578 | − priv = dev_get_drvdata(dev); | |
| 579 | − | |
| 580 | 701 | info = get_msg_ptr(priv, response[MSG_ARG0], buf, &ret); |
| 581 | 702 | if (!info) |
| 582 | 703 | return ret; |
| 583 | 704 | |
| 584 | − mr4 = readl_relaxed(info + DRAM_INFO_MR4) & DRAM_INFO_MR4_MASK; | |
| 705 | + mr4 = (readl_relaxed(info + DRAM_INFO_MR4) >> DRAM_INFO_MR4_SHIFT) & | |
| 706 | + DRAM_INFO_MR4_MASK; | |
| 585 | 707 | |
| 586 | 708 | refresh = (mr4 >> DRAM_MR4_REFRESH) & DRAM_MR4_REFRESH_MASK; |
| 587 | 709 | sr_abort = (mr4 >> DRAM_MR4_SR_ABORT) & DRAM_MR4_SR_ABORT_MASK; |
| @@ -608,7 +730,6 @@ static ssize_t store_refresh(struct device *dev, struct device_attribute *attr, · 20 unmodified lines | ||
| 608 | 730 | return -EINVAL; |
| 609 | 731 | |
| 610 | 732 | priv = dev_get_drvdata(dev); |
| 611 | − | |
| 612 | 733 | ret = __send_command(priv, DPFE_CMD_GET_REFRESH, response); |
| 613 | 734 | if (ret) |
| 614 | 735 | return ret; |
| @@ -623,30 +744,58 @@ static ssize_t store_refresh(struct device *dev, struct device_attribute *attr, · 8 unmodified lines | ||
| 623 | 744 | } |
| 624 | 745 | |
| 625 | 746 | static ssize_t show_vendor(struct device *dev, struct device_attribute *devattr, |
| 626 | − char *buf) | |
| 747 | + char *buf) | |
| 627 | 748 | { |
| 628 | 749 | u32 response[MSG_FIELD_MAX]; |
| 629 | 750 | struct private_data *priv; |
| 630 | 751 | void __iomem *info; |
| 631 | 752 | ssize_t ret; |
| 753 | + u32 mr5, mr6, mr7, mr8, err; | |
| 632 | 754 | |
| 633 | − ret = generic_show(DPFE_CMD_GET_VENDOR, response, dev, buf); | |
| 755 | + priv = dev_get_drvdata(dev); | |
| 756 | + ret = generic_show(DPFE_CMD_GET_VENDOR, response, priv, buf); | |
| 634 | 757 | if (ret) |
| 635 | 758 | return ret; |
| 636 | 759 | |
| 637 | − priv = dev_get_drvdata(dev); | |
| 638 | − | |
| 639 | 760 | info = get_msg_ptr(priv, response[MSG_ARG0], buf, &ret); |
| 640 | 761 | if (!info) |
| 641 | 762 | return ret; |
| 642 | 763 | |
| 643 | − return sprintf(buf, "%#x %#x %#x %#x %#x\n", | |
| 644 | − readl_relaxed(info + DRAM_VENDOR_MR5) & DRAM_VENDOR_MASK, | |
| 645 | − readl_relaxed(info + DRAM_VENDOR_MR6) & DRAM_VENDOR_MASK, | |
| 646 | − readl_relaxed(info + DRAM_VENDOR_MR7) & DRAM_VENDOR_MASK, | |
| 647 | − readl_relaxed(info + DRAM_VENDOR_MR8) & DRAM_VENDOR_MASK, | |
| 648 | − readl_relaxed(info + DRAM_VENDOR_ERROR) & | |
| 649 | − DRAM_VENDOR_MASK); | |
| 764 | + mr5 = (readl_relaxed(info + DRAM_VENDOR_MR5) >> DRAM_VENDOR_SHIFT) & | |
| 765 | + DRAM_VENDOR_MASK; | |
| 766 | + mr6 = (readl_relaxed(info + DRAM_VENDOR_MR6) >> DRAM_VENDOR_SHIFT) & | |
| 767 | + DRAM_VENDOR_MASK; | |
| 768 | + mr7 = (readl_relaxed(info + DRAM_VENDOR_MR7) >> DRAM_VENDOR_SHIFT) & | |
| 769 | + DRAM_VENDOR_MASK; | |
| 770 | + mr8 = (readl_relaxed(info + DRAM_VENDOR_MR8) >> DRAM_VENDOR_SHIFT) & | |
| 771 | + DRAM_VENDOR_MASK; | |
| 772 | + err = readl_relaxed(info + DRAM_VENDOR_ERROR) & DRAM_VENDOR_MASK; | |
| 773 | + | |
| 774 | + return sprintf(buf, "%#x %#x %#x %#x %#x\n", mr5, mr6, mr7, mr8, err); | |
| 775 | +} | |
| 776 | + | |
| 777 | +static ssize_t show_dram(struct device *dev, struct device_attribute *devattr, | |
| 778 | + char *buf) | |
| 779 | +{ | |
| 780 | + u32 response[MSG_FIELD_MAX]; | |
| 781 | + struct private_data *priv; | |
| 782 | + ssize_t ret; | |
| 783 | + u32 mr4, mr5, mr6, mr7, mr8, err; | |
| 784 | + | |
| 785 | + priv = dev_get_drvdata(dev); | |
| 786 | + ret = generic_show(DPFE_CMD_GET_REFRESH, response, priv, buf); | |
| 787 | + if (ret) | |
| 788 | + return ret; | |
| 789 | + | |
| 790 | + mr4 = response[MSG_ARG0 + 0] & DRAM_INFO_MR4_MASK; | |
| 791 | + mr5 = response[MSG_ARG0 + 1] & DRAM_DDR_INFO_MASK; | |
| 792 | + mr6 = response[MSG_ARG0 + 2] & DRAM_DDR_INFO_MASK; | |
| 793 | + mr7 = response[MSG_ARG0 + 3] & DRAM_DDR_INFO_MASK; | |
| 794 | + mr8 = response[MSG_ARG0 + 4] & DRAM_DDR_INFO_MASK; | |
| 795 | + err = response[MSG_ARG0 + 5] & DRAM_DDR_INFO_MASK; | |
| 796 | + | |
| 797 | + return sprintf(buf, "%#x %#x %#x %#x %#x %#x\n", mr4, mr5, mr6, mr7, | |
| 798 | + mr8, err); | |
| 650 | 799 | } |
| 651 | 800 | |
| 652 | 801 | static int brcmstb_dpfe_resume(struct platform_device *pdev) |
| @@ -656,17 +805,6 @@ static int brcmstb_dpfe_resume(struct platform_device *pdev) · 3 unmodified lines | ||
| 656 | 805 | return brcmstb_dpfe_download_firmware(pdev, &init); |
| 657 | 806 | } |
| 658 | 807 | |
| 659 | −static DEVICE_ATTR(dpfe_info, 0444, show_info, NULL); | |
| 660 | −static DEVICE_ATTR(dpfe_refresh, 0644, show_refresh, store_refresh); | |
| 661 | −static DEVICE_ATTR(dpfe_vendor, 0444, show_vendor, NULL); | |
| 662 | −static struct attribute *dpfe_attrs[] = { | |
| 663 | − &dev_attr_dpfe_info.attr, | |
| 664 | − &dev_attr_dpfe_refresh.attr, | |
| 665 | − &dev_attr_dpfe_vendor.attr, | |
| 666 | − NULL | |
| 667 | −}; | |
| 668 | −ATTRIBUTE_GROUPS(dpfe); | |
| 669 | − | |
| 670 | 808 | static int brcmstb_dpfe_probe(struct platform_device *pdev) |
| 671 | 809 | { |
| 672 | 810 | struct device *dev = &pdev->dev; |
| @@ -703,26 +841,47 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev) · 30 unmodified lines | ||
| 703 | 841 | return -ENOENT; |
| 704 | 842 | } |
| 705 | 843 | |
| 844 | + priv->dpfe_api = of_device_get_match_data(dev); | |
| 845 | + if (unlikely(!priv->dpfe_api)) { | |
| 846 | + /* | |
| 847 | + * It should be impossible to end up here, but to be safe we | |
| 848 | + * check anyway. | |
| 849 | + */ | |
| 850 | + dev_err(dev, "Couldn't determine API\n"); | |
| 851 | + return -ENOENT; | |
| 852 | + } | |
| 853 | + | |
| 706 | 854 | ret = brcmstb_dpfe_download_firmware(pdev, &init); |
| 707 | − if (ret) | |
| 855 | + if (ret) { | |
| 856 | + dev_err(dev, "Couldn't download firmware -- %d\n", ret); | |
| 708 | 857 | return ret; |
| 858 | + } | |
| 709 | 859 | |
| 710 | − ret = sysfs_create_groups(&pdev->dev.kobj, dpfe_groups); | |
| 860 | + ret = sysfs_create_groups(&pdev->dev.kobj, priv->dpfe_api->sysfs_attrs); | |
| 711 | 861 | if (!ret) |
| 712 | − dev_info(dev, "registered.\n"); | |
| 862 | + dev_info(dev, "registered with API v%d.\n", | |
| 863 | + priv->dpfe_api->version); | |
| 713 | 864 | |
| 714 | 865 | return ret; |
| 715 | 866 | } |
| 716 | 867 | |
| 717 | 868 | static int brcmstb_dpfe_remove(struct platform_device *pdev) |
| 718 | 869 | { |
| 719 | − sysfs_remove_groups(&pdev->dev.kobj, dpfe_groups); | |
| 870 | + struct private_data *priv = dev_get_drvdata(&pdev->dev); | |
| 871 | + | |
| 872 | + sysfs_remove_groups(&pdev->dev.kobj, priv->dpfe_api->sysfs_attrs); | |
| 720 | 873 | |
| 721 | 874 | return 0; |
| 722 | 875 | } |
| 723 | 876 | |
| 724 | 877 | static const struct of_device_id brcmstb_dpfe_of_match[] = { |
| 725 | − { .compatible = "brcm,dpfe-cpu", }, | |
| 878 | + /* Use legacy API v2 for a select number of chips */ | |
| 879 | + { .compatible = "brcm,bcm7268-dpfe-cpu", .data = &dpfe_api_v2 }, | |
| 880 | + { .compatible = "brcm,bcm7271-dpfe-cpu", .data = &dpfe_api_v2 }, | |
| 881 | + { .compatible = "brcm,bcm7278-dpfe-cpu", .data = &dpfe_api_v2 }, | |
| 882 | + { .compatible = "brcm,bcm7211-dpfe-cpu", .data = &dpfe_api_v2 }, | |
| 883 | + /* API v3 is the default going forward */ | |
| 884 | + { .compatible = "brcm,dpfe-cpu", .data = &dpfe_api_v3 }, | |
| 726 | 885 | {} |
| 727 | 886 | }; |
| 728 | 887 | MODULE_DEVICE_TABLE(of, brcmstb_dpfe_of_match); |
| @@ -23,8 +23,9 @@ · 22 unmodified lines | ||
| 23 | 23 | #include <linux/list.h> |
| 24 | 24 | #include <linux/spinlock.h> |
| 25 | 25 | #include <linux/pm.h> |
| 26 | −#include <memory/jedec_ddr.h> | |
| 26 | + | |
| 27 | 27 | #include "emif.h" |
| 28 | +#include "jedec_ddr.h" | |
| 28 | 29 | #include "of_memory.h" |
| 29 | 30 | |
| 30 | 31 | /** |
| @@ -6,8 +6,8 @@ · 5 unmodified lines | ||
| 6 | 6 | * |
| 7 | 7 | * Aneesh V <aneesh@ti.com> |
| 8 | 8 | */ |
| 9 | −#ifndef __LINUX_JEDEC_DDR_H | |
| 10 | −#define __LINUX_JEDEC_DDR_H | |
| 9 | +#ifndef __JEDEC_DDR_H | |
| 10 | +#define __JEDEC_DDR_H | |
| 11 | 11 | |
| 12 | 12 | #include <linux/types.h> |
| 13 | 13 | |
| @@ -169,4 +169,4 @@ extern const struct lpddr2_timings · 155 unmodified lines | ||
| 169 | 169 | lpddr2_jedec_timings[NUM_DDR_TIMING_TABLE_ENTRIES]; |
| 170 | 170 | extern const struct lpddr2_min_tck lpddr2_jedec_min_tck; |
| 171 | 171 | |
| 172 | −#endif /* __LINUX_JEDEC_DDR_H */ | |
| 172 | +#endif /* __JEDEC_DDR_H */ | |
| @@ -7,8 +7,9 @@ · 6 unmodified lines | ||
| 7 | 7 | * Aneesh V <aneesh@ti.com> |
| 8 | 8 | */ |
| 9 | 9 | |
| 10 | −#include <memory/jedec_ddr.h> | |
| 11 | −#include <linux/module.h> | |
| 10 | +#include <linux/export.h> | |
| 11 | + | |
| 12 | +#include "jedec_ddr.h" | |
| 12 | 13 | |
| 13 | 14 | /* LPDDR2 addressing details from JESD209-2 section 2.4 */ |
| 14 | 15 | const struct lpddr2_addressing |
| @@ -10,8 +10,9 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <linux/list.h> |
| 11 | 11 | #include <linux/of.h> |
| 12 | 12 | #include <linux/gfp.h> |
| 13 | −#include <memory/jedec_ddr.h> | |
| 14 | 13 | #include <linux/export.h> |
| 14 | + | |
| 15 | +#include "jedec_ddr.h" | |
| 15 | 16 | #include "of_memory.h" |
| 16 | 17 | |
| 17 | 18 | /** |
| @@ -30,28 +30,6 @@ · 29 unmodified lines | ||
| 30 | 30 | #define MC_EMEM_ARB_MISC1 0xdc |
| 31 | 31 | #define MC_EMEM_ARB_RING1_THROTTLE 0xe0 |
| 32 | 32 | |
| 33 | −static const unsigned long tegra124_mc_emem_regs[] = { | |
| 34 | − MC_EMEM_ARB_CFG, | |
| 35 | − MC_EMEM_ARB_OUTSTANDING_REQ, | |
| 36 | − MC_EMEM_ARB_TIMING_RCD, | |
| 37 | − MC_EMEM_ARB_TIMING_RP, | |
| 38 | − MC_EMEM_ARB_TIMING_RC, | |
| 39 | − MC_EMEM_ARB_TIMING_RAS, | |
| 40 | − MC_EMEM_ARB_TIMING_FAW, | |
| 41 | − MC_EMEM_ARB_TIMING_RRD, | |
| 42 | − MC_EMEM_ARB_TIMING_RAP2PRE, | |
| 43 | − MC_EMEM_ARB_TIMING_WAP2PRE, | |
| 44 | − MC_EMEM_ARB_TIMING_R2R, | |
| 45 | − MC_EMEM_ARB_TIMING_W2W, | |
| 46 | − MC_EMEM_ARB_TIMING_R2W, | |
| 47 | − MC_EMEM_ARB_TIMING_W2R, | |
| 48 | − MC_EMEM_ARB_DA_TURNS, | |
| 49 | − MC_EMEM_ARB_DA_COVERS, | |
| 50 | − MC_EMEM_ARB_MISC0, | |
| 51 | − MC_EMEM_ARB_MISC1, | |
| 52 | − MC_EMEM_ARB_RING1_THROTTLE | |
| 53 | −}; | |
| 54 | − | |
| 55 | 33 | static const struct tegra_mc_client tegra124_mc_clients[] = { |
| 56 | 34 | { |
| 57 | 35 | .id = 0x00, |
| @@ -1046,6 +1024,28 @@ static const struct tegra_mc_reset tegra124_mc_resets[] = { · 988 unmodified lines | ||
| 1046 | 1024 | }; |
| 1047 | 1025 | |
| 1048 | 1026 | #ifdef CONFIG_ARCH_TEGRA_124_SOC |
| 1027 | +static const unsigned long tegra124_mc_emem_regs[] = { | |
| 1028 | + MC_EMEM_ARB_CFG, | |
| 1029 | + MC_EMEM_ARB_OUTSTANDING_REQ, | |
| 1030 | + MC_EMEM_ARB_TIMING_RCD, | |
| 1031 | + MC_EMEM_ARB_TIMING_RP, | |
| 1032 | + MC_EMEM_ARB_TIMING_RC, | |
| 1033 | + MC_EMEM_ARB_TIMING_RAS, | |
| 1034 | + MC_EMEM_ARB_TIMING_FAW, | |
| 1035 | + MC_EMEM_ARB_TIMING_RRD, | |
| 1036 | + MC_EMEM_ARB_TIMING_RAP2PRE, | |
| 1037 | + MC_EMEM_ARB_TIMING_WAP2PRE, | |
| 1038 | + MC_EMEM_ARB_TIMING_R2R, | |
| 1039 | + MC_EMEM_ARB_TIMING_W2W, | |
| 1040 | + MC_EMEM_ARB_TIMING_R2W, | |
| 1041 | + MC_EMEM_ARB_TIMING_W2R, | |
| 1042 | + MC_EMEM_ARB_DA_TURNS, | |
| 1043 | + MC_EMEM_ARB_DA_COVERS, | |
| 1044 | + MC_EMEM_ARB_MISC0, | |
| 1045 | + MC_EMEM_ARB_MISC1, | |
| 1046 | + MC_EMEM_ARB_RING1_THROTTLE | |
| 1047 | +}; | |
| 1048 | + | |
| 1049 | 1049 | static const struct tegra_smmu_soc tegra124_smmu_soc = { |
| 1050 | 1050 | .clients = tegra124_mc_clients, |
| 1051 | 1051 | .num_clients = ARRAY_SIZE(tegra124_mc_clients), |
| @@ -118,7 +118,7 @@ config RESET_QCOM_PDC · 117 unmodified lines | ||
| 118 | 118 | |
| 119 | 119 | config RESET_SIMPLE |
| 120 | 120 | bool "Simple Reset Controller Driver" if COMPILE_TEST |
| 121 | − default ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED | |
| 121 | + default ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED || ARCH_BITMAIN | |
| 122 | 122 | help |
| 123 | 123 | This enables a simple reset controller driver for reset lines that |
| 124 | 124 | that can be asserted and deasserted by toggling bits in a contiguous, |
| @@ -130,6 +130,7 @@ config RESET_SIMPLE · 5 unmodified lines | ||
| 130 | 130 | - RCC reset controller in STM32 MCUs |
| 131 | 131 | - Allwinner SoCs |
| 132 | 132 | - ZTE's zx2967 family |
| 133 | + - Bitmain BM1880 SoC | |
| 133 | 134 | |
| 134 | 135 | config RESET_STM32MP157 |
| 135 | 136 | bool "STM32MP157 Reset Driver" if COMPILE_TEST |
| @@ -690,9 +690,6 @@ __reset_control_get_from_lookup(struct device *dev, const char *con_id, · 689 unmodified lines | ||
| 690 | 690 | const char *dev_id = dev_name(dev); |
| 691 | 691 | struct reset_control *rstc = NULL; |
| 692 | 692 | |
| 693 | − if (!dev) | |
| 694 | − return ERR_PTR(-EINVAL); | |
| 695 | − | |
| 696 | 693 | mutex_lock(&reset_lookup_mutex); |
| 697 | 694 | |
| 698 | 695 | list_for_each_entry(lookup, &reset_lookup_list, list) { |
| @@ -125,6 +125,8 @@ static const struct of_device_id reset_simple_dt_ids[] = { · 124 unmodified lines | ||
| 125 | 125 | .data = &reset_simple_active_low }, |
| 126 | 126 | { .compatible = "aspeed,ast2400-lpc-reset" }, |
| 127 | 127 | { .compatible = "aspeed,ast2500-lpc-reset" }, |
| 128 | + { .compatible = "bitmain,bm1880-reset", | |
| 129 | + .data = &reset_simple_active_low }, | |
| 128 | 130 | { /* sentinel */ }, |
| 129 | 131 | }; |
| 130 | 132 | |
| @@ -35,6 +35,7 @@ struct meson_canvas { · 34 unmodified lines | ||
| 35 | 35 | void __iomem *reg_base; |
| 36 | 36 | spinlock_t lock; /* canvas device lock */ |
| 37 | 37 | u8 used[NUM_CANVAS]; |
| 38 | + bool supports_endianness; | |
| 38 | 39 | }; |
| 39 | 40 | |
| 40 | 41 | static void canvas_write(struct meson_canvas *canvas, u32 reg, u32 val) |
| @@ -86,6 +87,12 @@ int meson_canvas_config(struct meson_canvas *canvas, u8 canvas_index, · 45 unmodified lines | ||
| 86 | 87 | { |
| 87 | 88 | unsigned long flags; |
| 88 | 89 | |
| 90 | + if (endian && !canvas->supports_endianness) { | |
| 91 | + dev_err(canvas->dev, | |
| 92 | + "Endianness is not supported on this SoC\n"); | |
| 93 | + return -EINVAL; | |
| 94 | + } | |
| 95 | + | |
| 89 | 96 | spin_lock_irqsave(&canvas->lock, flags); |
| 90 | 97 | if (!canvas->used[canvas_index]) { |
| 91 | 98 | dev_err(canvas->dev, |
| @@ -172,6 +179,8 @@ static int meson_canvas_probe(struct platform_device *pdev) · 80 unmodified lines | ||
| 172 | 179 | if (IS_ERR(canvas->reg_base)) |
| 173 | 180 | return PTR_ERR(canvas->reg_base); |
| 174 | 181 | |
| 182 | + canvas->supports_endianness = of_device_get_match_data(dev); | |
| 183 | + | |
| 175 | 184 | canvas->dev = dev; |
| 176 | 185 | spin_lock_init(&canvas->lock); |
| 177 | 186 | dev_set_drvdata(dev, canvas); |
| @@ -180,7 +189,10 @@ static int meson_canvas_probe(struct platform_device *pdev) · 2 unmodified lines | ||
| 180 | 189 | } |
| 181 | 190 | |
| 182 | 191 | static const struct of_device_id canvas_dt_match[] = { |
| 183 | − { .compatible = "amlogic,canvas" }, | |
| 192 | + { .compatible = "amlogic,meson8-canvas", .data = (void *)false, }, | |
| 193 | + { .compatible = "amlogic,meson8b-canvas", .data = (void *)false, }, | |
| 194 | + { .compatible = "amlogic,meson8m2-canvas", .data = (void *)false, }, | |
| 195 | + { .compatible = "amlogic,canvas", .data = (void *)true, }, | |
| 184 | 196 | {} |
| 185 | 197 | }; |
| 186 | 198 | MODULE_DEVICE_TABLE(of, canvas_dt_match); |
| @@ -64,6 +64,7 @@ static long aspeed_lpc_ctrl_ioctl(struct file *file, unsigned int cmd, · 63 unmodified lines | ||
| 64 | 64 | unsigned long param) |
| 65 | 65 | { |
| 66 | 66 | struct aspeed_lpc_ctrl *lpc_ctrl = file_aspeed_lpc_ctrl(file); |
| 67 | + struct device *dev = file->private_data; | |
| 67 | 68 | void __user *p = (void __user *)param; |
| 68 | 69 | struct aspeed_lpc_ctrl_mapping map; |
| 69 | 70 | u32 addr; |
| @@ -86,6 +87,12 @@ static long aspeed_lpc_ctrl_ioctl(struct file *file, unsigned int cmd, · 16 unmodified lines | ||
| 86 | 87 | if (map.window_id != 0) |
| 87 | 88 | return -EINVAL; |
| 88 | 89 | |
| 90 | + /* If memory-region is not described in device tree */ | |
| 91 | + if (!lpc_ctrl->mem_size) { | |
| 92 | + dev_dbg(dev, "Didn't find reserved memory\n"); | |
| 93 | + return -ENXIO; | |
| 94 | + } | |
| 95 | + | |
| 89 | 96 | map.size = lpc_ctrl->mem_size; |
| 90 | 97 | |
| 91 | 98 | return copy_to_user(p, &map, sizeof(map)) ? -EFAULT : 0; |
| @@ -122,9 +129,18 @@ static long aspeed_lpc_ctrl_ioctl(struct file *file, unsigned int cmd, · 30 unmodified lines | ||
| 122 | 129 | return -EINVAL; |
| 123 | 130 | |
| 124 | 131 | if (map.window_type == ASPEED_LPC_CTRL_WINDOW_FLASH) { |
| 132 | + if (!lpc_ctrl->pnor_size) { | |
| 133 | + dev_dbg(dev, "Didn't find host pnor flash\n"); | |
| 134 | + return -ENXIO; | |
| 135 | + } | |
| 125 | 136 | addr = lpc_ctrl->pnor_base; |
| 126 | 137 | size = lpc_ctrl->pnor_size; |
| 127 | 138 | } else if (map.window_type == ASPEED_LPC_CTRL_WINDOW_MEMORY) { |
| 139 | + /* If memory-region is not described in device tree */ | |
| 140 | + if (!lpc_ctrl->mem_size) { | |
| 141 | + dev_dbg(dev, "Didn't find reserved memory\n"); | |
| 142 | + return -ENXIO; | |
| 143 | + } | |
| 128 | 144 | addr = lpc_ctrl->mem_base; |
| 129 | 145 | size = lpc_ctrl->mem_size; |
| 130 | 146 | } else { |
| @@ -192,40 +208,41 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev) · 61 unmodified lines | ||
| 192 | 208 | if (!lpc_ctrl) |
| 193 | 209 | return -ENOMEM; |
| 194 | 210 | |
| 211 | + /* If flash is described in device tree then store */ | |
| 195 | 212 | node = of_parse_phandle(dev->of_node, "flash", 0); |
| 196 | 213 | if (!node) { |
| 197 | − dev_err(dev, "Didn't find host pnor flash node\n"); | |
| 198 | − return -ENODEV; | |
| 199 | − } | |
| 214 | + dev_dbg(dev, "Didn't find host pnor flash node\n"); | |
| 215 | + } else { | |
| 216 | + rc = of_address_to_resource(node, 1, &resm); | |
| 217 | + of_node_put(node); | |
| 218 | + if (rc) { | |
| 219 | + dev_err(dev, "Couldn't address to resource for flash\n"); | |
| 220 | + return rc; | |
| 221 | + } | |
| 200 | 222 | |
| 201 | − rc = of_address_to_resource(node, 1, &resm); | |
| 202 | − of_node_put(node); | |
| 203 | − if (rc) { | |
| 204 | − dev_err(dev, "Couldn't address to resource for flash\n"); | |
| 205 | − return rc; | |
| 223 | + lpc_ctrl->pnor_size = resource_size(&resm); | |
| 224 | + lpc_ctrl->pnor_base = resm.start; | |
| 206 | 225 | } |
| 207 | 226 | |
| 208 | − lpc_ctrl->pnor_size = resource_size(&resm); | |
| 209 | − lpc_ctrl->pnor_base = resm.start; | |
| 210 | 227 | |
| 211 | 228 | dev_set_drvdata(&pdev->dev, lpc_ctrl); |
| 212 | 229 | |
| 230 | + /* If memory-region is described in device tree then store */ | |
| 213 | 231 | node = of_parse_phandle(dev->of_node, "memory-region", 0); |
| 214 | 232 | if (!node) { |
| 215 | − dev_err(dev, "Didn't find reserved memory\n"); | |
| 216 | − return -EINVAL; | |
| 217 | − } | |
| 233 | + dev_dbg(dev, "Didn't find reserved memory\n"); | |
| 234 | + } else { | |
| 235 | + rc = of_address_to_resource(node, 0, &resm); | |
| 236 | + of_node_put(node); | |
| 237 | + if (rc) { | |
| 238 | + dev_err(dev, "Couldn't address to resource for reserved memory\n"); | |
| 239 | + return -ENXIO; | |
| 240 | + } | |
| 218 | 241 | |
| 219 | − rc = of_address_to_resource(node, 0, &resm); | |
| 220 | − of_node_put(node); | |
| 221 | − if (rc) { | |
| 222 | − dev_err(dev, "Couldn't address to resource for reserved memory\n"); | |
| 223 | − return -ENOMEM; | |
| 242 | + lpc_ctrl->mem_size = resource_size(&resm); | |
| 243 | + lpc_ctrl->mem_base = resm.start; | |
| 224 | 244 | } |
| 225 | 245 | |
| 226 | − lpc_ctrl->mem_size = resource_size(&resm); | |
| 227 | − lpc_ctrl->mem_base = resm.start; | |
| 228 | − | |
| 229 | 246 | lpc_ctrl->regmap = syscon_node_to_regmap( |
| 230 | 247 | pdev->dev.parent->of_node); |
| 231 | 248 | if (IS_ERR(lpc_ctrl->regmap)) { |
| @@ -254,8 +271,6 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev) · 22 unmodified lines | ||
| 254 | 271 | goto err; |
| 255 | 272 | } |
| 256 | 273 | |
| 257 | − dev_info(dev, "Loaded at %pr\n", &resm); | |
| 258 | − | |
| 259 | 274 | return 0; |
| 260 | 275 | |
| 261 | 276 | err: |
| @@ -30,4 +30,14 @@ config FSL_MC_DPIO · 29 unmodified lines | ||
| 30 | 30 | other DPAA2 objects. This driver does not expose the DPIO |
| 31 | 31 | objects individually, but groups them under a service layer |
| 32 | 32 | API. |
| 33 | + | |
| 34 | +config DPAA2_CONSOLE | |
| 35 | + tristate "QorIQ DPAA2 console driver" | |
| 36 | + depends on OF && (ARCH_LAYERSCAPE || COMPILE_TEST) | |
| 37 | + default y | |
| 38 | + help | |
| 39 | + Console driver for DPAA2 platforms. Exports 2 char devices, | |
| 40 | + /dev/dpaa2_mc_console and /dev/dpaa2_aiop_console, | |
| 41 | + which can be used to dump the Management Complex and AIOP | |
| 42 | + firmware logs. | |
| 33 | 43 | endmenu |
| @@ -8,3 +8,4 @@ obj-$(CONFIG_QUICC_ENGINE) += qe/ · 7 unmodified lines | ||
| 8 | 8 | obj-$(CONFIG_CPM) += qe/ |
| 9 | 9 | obj-$(CONFIG_FSL_GUTS) += guts.o |
| 10 | 10 | obj-$(CONFIG_FSL_MC_DPIO) += dpio/ |
| 11 | +obj-$(CONFIG_DPAA2_CONSOLE) += dpaa2-console.o | |
| @@ -0,0 +1,329 @@ | ||
| 1 | +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) | |
| 2 | +/* | |
| 3 | + * Freescale DPAA2 Platforms Console Driver | |
| 4 | + * | |
| 5 | + * Copyright 2015-2016 Freescale Semiconductor Inc. | |
| 6 | + * Copyright 2018 NXP | |
| 7 | + */ | |
| 8 | + | |
| 9 | +#define pr_fmt(fmt) "dpaa2-console: " fmt | |
| 10 | + | |
| 11 | +#include <linux/module.h> | |
| 12 | +#include <linux/of_device.h> | |
| 13 | +#include <linux/of_address.h> | |
| 14 | +#include <linux/miscdevice.h> | |
| 15 | +#include <linux/uaccess.h> | |
| 16 | +#include <linux/slab.h> | |
| 17 | +#include <linux/fs.h> | |
| 18 | +#include <linux/io.h> | |
| 19 | + | |
| 20 | +/* MC firmware base low/high registers indexes */ | |
| 21 | +#define MCFBALR_OFFSET 0 | |
| 22 | +#define MCFBAHR_OFFSET 1 | |
| 23 | + | |
| 24 | +/* Bit masks used to get the most/least significant part of the MC base addr */ | |
| 25 | +#define MC_FW_ADDR_MASK_HIGH 0x1FFFF | |
| 26 | +#define MC_FW_ADDR_MASK_LOW 0xE0000000 | |
| 27 | + | |
| 28 | +#define MC_BUFFER_OFFSET 0x01000000 | |
| 29 | +#define MC_BUFFER_SIZE (1024 * 1024 * 16) | |
| 30 | +#define MC_OFFSET_DELTA MC_BUFFER_OFFSET | |
| 31 | + | |
| 32 | +#define AIOP_BUFFER_OFFSET 0x06000000 | |
| 33 | +#define AIOP_BUFFER_SIZE (1024 * 1024 * 16) | |
| 34 | +#define AIOP_OFFSET_DELTA 0 | |
| 35 | + | |
| 36 | +#define LOG_HEADER_FLAG_BUFFER_WRAPAROUND 0x80000000 | |
| 37 | +#define LAST_BYTE(a) ((a) & ~(LOG_HEADER_FLAG_BUFFER_WRAPAROUND)) | |
| 38 | + | |
| 39 | +/* MC and AIOP Magic words */ | |
| 40 | +#define MAGIC_MC 0x4d430100 | |
| 41 | +#define MAGIC_AIOP 0x41494F50 | |
| 42 | + | |
| 43 | +struct log_header { | |
| 44 | + __le32 magic_word; | |
| 45 | + char reserved[4]; | |
| 46 | + __le32 buf_start; | |
| 47 | + __le32 buf_length; | |
| 48 | + __le32 last_byte; | |
| 49 | +}; | |
| 50 | + | |
| 51 | +struct console_data { | |
| 52 | + void __iomem *map_addr; | |
| 53 | + struct log_header __iomem *hdr; | |
| 54 | + void __iomem *start_addr; | |
| 55 | + void __iomem *end_addr; | |
| 56 | + void __iomem *end_of_data; | |
| 57 | + void __iomem *cur_ptr; | |
| 58 | +}; | |
| 59 | + | |
| 60 | +static struct resource mc_base_addr; | |
| 61 | + | |
| 62 | +static inline void adjust_end(struct console_data *cd) | |
| 63 | +{ | |
| 64 | + u32 last_byte = readl(&cd->hdr->last_byte); | |
| 65 | + | |
| 66 | + cd->end_of_data = cd->start_addr + LAST_BYTE(last_byte); | |
| 67 | +} | |
| 68 | + | |
| 69 | +static u64 get_mc_fw_base_address(void) | |
| 70 | +{ | |
| 71 | + u64 mcfwbase = 0ULL; | |
| 72 | + u32 __iomem *mcfbaregs; | |
| 73 | + | |
| 74 | + mcfbaregs = ioremap(mc_base_addr.start, resource_size(&mc_base_addr)); | |
| 75 | + if (!mcfbaregs) { | |
| 76 | + pr_err("could not map MC Firmaware Base registers\n"); | |
| 77 | + return 0; | |
| 78 | + } | |
| 79 | + | |
| 80 | + mcfwbase = readl(mcfbaregs + MCFBAHR_OFFSET) & | |
| 81 | + MC_FW_ADDR_MASK_HIGH; | |
| 82 | + mcfwbase <<= 32; | |
| 83 | + mcfwbase |= readl(mcfbaregs + MCFBALR_OFFSET) & MC_FW_ADDR_MASK_LOW; | |
| 84 | + iounmap(mcfbaregs); | |
| 85 | + | |
| 86 | + pr_debug("MC base address at 0x%016llx\n", mcfwbase); | |
| 87 | + return mcfwbase; | |
| 88 | +} | |
| 89 | + | |
| 90 | +static ssize_t dpaa2_console_size(struct console_data *cd) | |
| 91 | +{ | |
| 92 | + ssize_t size; | |
| 93 | + | |
| 94 | + if (cd->cur_ptr <= cd->end_of_data) | |
| 95 | + size = cd->end_of_data - cd->cur_ptr; | |
| 96 | + else | |
| 97 | + size = (cd->end_addr - cd->cur_ptr) + | |
| 98 | + (cd->end_of_data - cd->start_addr); | |
| 99 | + | |
| 100 | + return size; | |
| 101 | +} | |
| 102 | + | |
| 103 | +static int dpaa2_generic_console_open(struct inode *node, struct file *fp, | |
| 104 | + u64 offset, u64 size, | |
| 105 | + u32 expected_magic, | |
| 106 | + u32 offset_delta) | |
| 107 | +{ | |
| 108 | + u32 read_magic, wrapped, last_byte, buf_start, buf_length; | |
| 109 | + struct console_data *cd; | |
| 110 | + u64 base_addr; | |
| 111 | + int err; | |
| 112 | + | |
| 113 | + cd = kmalloc(sizeof(*cd), GFP_KERNEL); | |
| 114 | + if (!cd) | |
| 115 | + return -ENOMEM; | |
| 116 | + | |
| 117 | + base_addr = get_mc_fw_base_address(); | |
| 118 | + if (!base_addr) { | |
| 119 | + err = -EIO; | |
| 120 | + goto err_fwba; | |
| 121 | + } | |
| 122 | + | |
| 123 | + cd->map_addr = ioremap(base_addr + offset, size); | |
| 124 | + if (!cd->map_addr) { | |
| 125 | + pr_err("cannot map console log memory\n"); | |
| 126 | + err = -EIO; | |
| 127 | + goto err_ioremap; | |
| 128 | + } | |
| 129 | + | |
| 130 | + cd->hdr = (struct log_header __iomem *)cd->map_addr; | |
| 131 | + read_magic = readl(&cd->hdr->magic_word); | |
| 132 | + last_byte = readl(&cd->hdr->last_byte); | |
| 133 | + buf_start = readl(&cd->hdr->buf_start); | |
| 134 | + buf_length = readl(&cd->hdr->buf_length); | |
| 135 | + | |
| 136 | + if (read_magic != expected_magic) { | |
| 137 | + pr_warn("expected = %08x, read = %08x\n", | |
| 138 | + expected_magic, read_magic); | |
| 139 | + err = -EIO; | |
| 140 | + goto err_magic; | |
| 141 | + } | |
| 142 | + | |
| 143 | + cd->start_addr = cd->map_addr + buf_start - offset_delta; | |
| 144 | + cd->end_addr = cd->start_addr + buf_length; | |
| 145 | + | |
| 146 | + wrapped = last_byte & LOG_HEADER_FLAG_BUFFER_WRAPAROUND; | |
| 147 | + | |
| 148 | + adjust_end(cd); | |
| 149 | + if (wrapped && cd->end_of_data != cd->end_addr) | |
| 150 | + cd->cur_ptr = cd->end_of_data + 1; | |
| 151 | + else | |
| 152 | + cd->cur_ptr = cd->start_addr; | |
| 153 | + | |
| 154 | + fp->private_data = cd; | |
| 155 | + | |
| 156 | + return 0; | |
| 157 | + | |
| 158 | +err_magic: | |
| 159 | + iounmap(cd->map_addr); | |
| 160 | + | |
| 161 | +err_ioremap: | |
| 162 | +err_fwba: | |
| 163 | + kfree(cd); | |
| 164 | + | |
| 165 | + return err; | |
| 166 | +} | |
| 167 | + | |
| 168 | +static int dpaa2_mc_console_open(struct inode *node, struct file *fp) | |
| 169 | +{ | |
| 170 | + return dpaa2_generic_console_open(node, fp, | |
| 171 | + MC_BUFFER_OFFSET, MC_BUFFER_SIZE, | |
| 172 | + MAGIC_MC, MC_OFFSET_DELTA); | |
| 173 | +} | |
| 174 | + | |
| 175 | +static int dpaa2_aiop_console_open(struct inode *node, struct file *fp) | |
| 176 | +{ | |
| 177 | + return dpaa2_generic_console_open(node, fp, | |
| 178 | + AIOP_BUFFER_OFFSET, AIOP_BUFFER_SIZE, | |
| 179 | + MAGIC_AIOP, AIOP_OFFSET_DELTA); | |
| 180 | +} | |
| 181 | + | |
| 182 | +static int dpaa2_console_close(struct inode *node, struct file *fp) | |
| 183 | +{ | |
| 184 | + struct console_data *cd = fp->private_data; | |
| 185 | + | |
| 186 | + iounmap(cd->map_addr); | |
| 187 | + kfree(cd); | |
| 188 | + return 0; | |
| 189 | +} | |
| 190 | + | |
| 191 | +static ssize_t dpaa2_console_read(struct file *fp, char __user *buf, | |
| 192 | + size_t count, loff_t *f_pos) | |
| 193 | +{ | |
| 194 | + struct console_data *cd = fp->private_data; | |
| 195 | + size_t bytes = dpaa2_console_size(cd); | |
| 196 | + size_t bytes_end = cd->end_addr - cd->cur_ptr; | |
| 197 | + size_t written = 0; | |
| 198 | + void *kbuf; | |
| 199 | + int err; | |
| 200 | + | |
| 201 | + /* Check if we need to adjust the end of data addr */ | |
| 202 | + adjust_end(cd); | |
| 203 | + | |
| 204 | + if (cd->end_of_data == cd->cur_ptr) | |
| 205 | + return 0; | |
| 206 | + | |
| 207 | + if (count < bytes) | |
| 208 | + bytes = count; | |
| 209 | + | |
| 210 | + kbuf = kmalloc(bytes, GFP_KERNEL); | |
| 211 | + if (!kbuf) | |
| 212 | + return -ENOMEM; | |
| 213 | + | |
| 214 | + if (bytes > bytes_end) { | |
| 215 | + memcpy_fromio(kbuf, cd->cur_ptr, bytes_end); | |
| 216 | + if (copy_to_user(buf, kbuf, bytes_end)) { | |
| 217 | + err = -EFAULT; | |
| 218 | + goto err_free_buf; | |
| 219 | + } | |
| 220 | + buf += bytes_end; | |
| 221 | + cd->cur_ptr = cd->start_addr; | |
| 222 | + bytes -= bytes_end; | |
| 223 | + written += bytes_end; | |
| 224 | + } | |
| 225 | + | |
| 226 | + memcpy_fromio(kbuf, cd->cur_ptr, bytes); | |
| 227 | + if (copy_to_user(buf, kbuf, bytes)) { | |
| 228 | + err = -EFAULT; | |
| 229 | + goto err_free_buf; | |
| 230 | + } | |
| 231 | + cd->cur_ptr += bytes; | |
| 232 | + written += bytes; | |
| 233 | + | |
| 234 | + return written; | |
| 235 | + | |
| 236 | +err_free_buf: | |
| 237 | + kfree(kbuf); | |
| 238 | + | |
| 239 | + return err; | |
| 240 | +} | |
| 241 | + | |
| 242 | +static const struct file_operations dpaa2_mc_console_fops = { | |
| 243 | + .owner = THIS_MODULE, | |
| 244 | + .open = dpaa2_mc_console_open, | |
| 245 | + .release = dpaa2_console_close, | |
| 246 | + .read = dpaa2_console_read, | |
| 247 | +}; | |
| 248 | + | |
| 249 | +static struct miscdevice dpaa2_mc_console_dev = { | |
| 250 | + .minor = MISC_DYNAMIC_MINOR, | |
| 251 | + .name = "dpaa2_mc_console", | |
| 252 | + .fops = &dpaa2_mc_console_fops | |
| 253 | +}; | |
| 254 | + | |
| 255 | +static const struct file_operations dpaa2_aiop_console_fops = { | |
| 256 | + .owner = THIS_MODULE, | |
| 257 | + .open = dpaa2_aiop_console_open, | |
| 258 | + .release = dpaa2_console_close, | |
| 259 | + .read = dpaa2_console_read, | |
| 260 | +}; | |
| 261 | + | |
| 262 | +static struct miscdevice dpaa2_aiop_console_dev = { | |
| 263 | + .minor = MISC_DYNAMIC_MINOR, | |
| 264 | + .name = "dpaa2_aiop_console", | |
| 265 | + .fops = &dpaa2_aiop_console_fops | |
| 266 | +}; | |
| 267 | + | |
| 268 | +static int dpaa2_console_probe(struct platform_device *pdev) | |
| 269 | +{ | |
| 270 | + int error; | |
| 271 | + | |
| 272 | + error = of_address_to_resource(pdev->dev.of_node, 0, &mc_base_addr); | |
| 273 | + if (error < 0) { | |
| 274 | + pr_err("of_address_to_resource() failed for %pOF with %d\n", | |
| 275 | + pdev->dev.of_node, error); | |
| 276 | + return error; | |
| 277 | + } | |
| 278 | + | |
| 279 | + error = misc_register(&dpaa2_mc_console_dev); | |
| 280 | + if (error) { | |
| 281 | + pr_err("cannot register device %s\n", | |
| 282 | + dpaa2_mc_console_dev.name); | |
| 283 | + goto err_register_mc; | |
| 284 | + } | |
| 285 | + | |
| 286 | + error = misc_register(&dpaa2_aiop_console_dev); | |
| 287 | + if (error) { | |
| 288 | + pr_err("cannot register device %s\n", | |
| 289 | + dpaa2_aiop_console_dev.name); | |
| 290 | + goto err_register_aiop; | |
| 291 | + } | |
| 292 | + | |
| 293 | + return 0; | |
| 294 | + | |
| 295 | +err_register_aiop: | |
| 296 | + misc_deregister(&dpaa2_mc_console_dev); | |
| 297 | +err_register_mc: | |
| 298 | + return error; | |
| 299 | +} | |
| 300 | + | |
| 301 | +static int dpaa2_console_remove(struct platform_device *pdev) | |
| 302 | +{ | |
| 303 | + misc_deregister(&dpaa2_mc_console_dev); | |
| 304 | + misc_deregister(&dpaa2_aiop_console_dev); | |
| 305 | + | |
| 306 | + return 0; | |
| 307 | +} | |
| 308 | + | |
| 309 | +static const struct of_device_id dpaa2_console_match_table[] = { | |
| 310 | + { .compatible = "fsl,dpaa2-console",}, | |
| 311 | + {}, | |
| 312 | +}; | |
| 313 | + | |
| 314 | +MODULE_DEVICE_TABLE(of, dpaa2_console_match_table); | |
| 315 | + | |
| 316 | +static struct platform_driver dpaa2_console_driver = { | |
| 317 | + .driver = { | |
| 318 | + .name = "dpaa2-console", | |
| 319 | + .pm = NULL, | |
| 320 | + .of_match_table = dpaa2_console_match_table, | |
| 321 | + }, | |
| 322 | + .probe = dpaa2_console_probe, | |
| 323 | + .remove = dpaa2_console_remove, | |
| 324 | +}; | |
| 325 | +module_platform_driver(dpaa2_console_driver); | |
| 326 | + | |
| 327 | +MODULE_LICENSE("Dual BSD/GPL"); | |
| 328 | +MODULE_AUTHOR("Roy Pledge <roy.pledge@nxp.com>"); | |
| 329 | +MODULE_DESCRIPTION("DPAA2 console driver"); | |
| @@ -197,13 +197,22 @@ static int dpaa2_dpio_probe(struct fsl_mc_device *dpio_dev) · 196 unmodified lines | ||
| 197 | 197 | desc.cpu); |
| 198 | 198 | } |
| 199 | 199 | |
| 200 | − /* | |
| 201 | − * Set the CENA regs to be the cache inhibited area of the portal to | |
| 202 | − * avoid coherency issues if a user migrates to another core. | |
| 203 | − */ | |
| 204 | − desc.regs_cena = devm_memremap(dev, dpio_dev->regions[1].start, | |
| 205 | − resource_size(&dpio_dev->regions[1]), | |
| 206 | − MEMREMAP_WC); | |
| 200 | + if (dpio_dev->obj_desc.region_count < 3) { | |
| 201 | + /* No support for DDR backed portals, use classic mapping */ | |
| 202 | + /* | |
| 203 | + * Set the CENA regs to be the cache inhibited area of the | |
| 204 | + * portal to avoid coherency issues if a user migrates to | |
| 205 | + * another core. | |
| 206 | + */ | |
| 207 | + desc.regs_cena = devm_memremap(dev, dpio_dev->regions[1].start, | |
| 208 | + resource_size(&dpio_dev->regions[1]), | |
| 209 | + MEMREMAP_WC); | |
| 210 | + } else { | |
| 211 | + desc.regs_cena = devm_memremap(dev, dpio_dev->regions[2].start, | |
| 212 | + resource_size(&dpio_dev->regions[2]), | |
| 213 | + MEMREMAP_WB); | |
| 214 | + } | |
| 215 | + | |
| 207 | 216 | if (IS_ERR(desc.regs_cena)) { |
| 208 | 217 | dev_err(dev, "devm_memremap failed\n"); |
| 209 | 218 | err = PTR_ERR(desc.regs_cena); |
| @@ -15,6 +15,8 @@ · 14 unmodified lines | ||
| 15 | 15 | #define QMAN_REV_4000 0x04000000 |
| 16 | 16 | #define QMAN_REV_4100 0x04010000 |
| 17 | 17 | #define QMAN_REV_4101 0x04010001 |
| 18 | +#define QMAN_REV_5000 0x05000000 | |
| 19 | + | |
| 18 | 20 | #define QMAN_REV_MASK 0xffff0000 |
| 19 | 21 | |
| 20 | 22 | /* All QBMan command and result structures use this "valid bit" encoding */ |
| @@ -25,10 +27,17 @@ · 4 unmodified lines | ||
| 25 | 27 | #define QBMAN_WQCHAN_CONFIGURE 0x46 |
| 26 | 28 | |
| 27 | 29 | /* CINH register offsets */ |
| 30 | +#define QBMAN_CINH_SWP_EQCR_PI 0x800 | |
| 28 | 31 | #define QBMAN_CINH_SWP_EQAR 0x8c0 |
| 32 | +#define QBMAN_CINH_SWP_CR_RT 0x900 | |
| 33 | +#define QBMAN_CINH_SWP_VDQCR_RT 0x940 | |
| 34 | +#define QBMAN_CINH_SWP_EQCR_AM_RT 0x980 | |
| 35 | +#define QBMAN_CINH_SWP_RCR_AM_RT 0x9c0 | |
| 29 | 36 | #define QBMAN_CINH_SWP_DQPI 0xa00 |
| 30 | 37 | #define QBMAN_CINH_SWP_DCAP 0xac0 |
| 31 | 38 | #define QBMAN_CINH_SWP_SDQCR 0xb00 |
| 39 | +#define QBMAN_CINH_SWP_EQCR_AM_RT2 0xb40 | |
| 40 | +#define QBMAN_CINH_SWP_RCR_PI 0xc00 | |
| 32 | 41 | #define QBMAN_CINH_SWP_RAR 0xcc0 |
| 33 | 42 | #define QBMAN_CINH_SWP_ISR 0xe00 |
| 34 | 43 | #define QBMAN_CINH_SWP_IER 0xe40 |
| @@ -43,6 +52,13 @@ · 8 unmodified lines | ||
| 43 | 52 | #define QBMAN_CENA_SWP_RR(vb) (0x700 + ((u32)(vb) >> 1)) |
| 44 | 53 | #define QBMAN_CENA_SWP_VDQCR 0x780 |
| 45 | 54 | |
| 55 | +/* CENA register offsets in memory-backed mode */ | |
| 56 | +#define QBMAN_CENA_SWP_DQRR_MEM(n) (0x800 + ((u32)(n) << 6)) | |
| 57 | +#define QBMAN_CENA_SWP_RCR_MEM(n) (0x1400 + ((u32)(n) << 6)) | |
| 58 | +#define QBMAN_CENA_SWP_CR_MEM 0x1600 | |
| 59 | +#define QBMAN_CENA_SWP_RR_MEM 0x1680 | |
| 60 | +#define QBMAN_CENA_SWP_VDQCR_MEM 0x1780 | |
| 61 | + | |
| 46 | 62 | /* Reverse mapping of QBMAN_CENA_SWP_DQRR() */ |
| 47 | 63 | #define QBMAN_IDX_FROM_DQRR(p) (((unsigned long)(p) & 0x1ff) >> 6) |
| 48 | 64 | |
| @@ -96,10 +112,13 @@ static inline void *qbman_get_cmd(struct qbman_swp *p, u32 offset) · 47 unmodified lines | ||
| 96 | 112 | |
| 97 | 113 | #define SWP_CFG_DQRR_MF_SHIFT 20 |
| 98 | 114 | #define SWP_CFG_EST_SHIFT 16 |
| 115 | +#define SWP_CFG_CPBS_SHIFT 15 | |
| 99 | 116 | #define SWP_CFG_WN_SHIFT 14 |
| 100 | 117 | #define SWP_CFG_RPM_SHIFT 12 |
| 101 | 118 | #define SWP_CFG_DCM_SHIFT 10 |
| 102 | 119 | #define SWP_CFG_EPM_SHIFT 8 |
| 120 | +#define SWP_CFG_VPM_SHIFT 7 | |
| 121 | +#define SWP_CFG_CPM_SHIFT 6 | |
| 103 | 122 | #define SWP_CFG_SD_SHIFT 5 |
| 104 | 123 | #define SWP_CFG_SP_SHIFT 4 |
| 105 | 124 | #define SWP_CFG_SE_SHIFT 3 |
| @@ -125,6 +144,8 @@ static inline u32 qbman_set_swp_cfg(u8 max_fill, u8 wn, u8 est, u8 rpm, u8 dcm, · 19 unmodified lines | ||
| 125 | 144 | ep << SWP_CFG_EP_SHIFT); |
| 126 | 145 | } |
| 127 | 146 | |
| 147 | +#define QMAN_RT_MODE 0x00000100 | |
| 148 | + | |
| 128 | 149 | /** |
| 129 | 150 | * qbman_swp_init() - Create a functional object representing the given |
| 130 | 151 | * QBMan portal descriptor. |
| @@ -146,6 +167,8 @@ struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d) · 15 unmodified lines | ||
| 146 | 167 | p->sdq |= qbman_sdqcr_dct_prio_ics << QB_SDQCR_DCT_SHIFT; |
| 147 | 168 | p->sdq |= qbman_sdqcr_fc_up_to_3 << QB_SDQCR_FC_SHIFT; |
| 148 | 169 | p->sdq |= QMAN_SDQCR_TOKEN << QB_SDQCR_TOK_SHIFT; |
| 170 | + if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000) | |
| 171 | + p->mr.valid_bit = QB_VALID_BIT; | |
| 149 | 172 | |
| 150 | 173 | atomic_set(&p->vdq.available, 1); |
| 151 | 174 | p->vdq.valid_bit = QB_VALID_BIT; |
| @@ -163,6 +186,9 @@ struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d) · 11 unmodified lines | ||
| 163 | 186 | p->addr_cena = d->cena_bar; |
| 164 | 187 | p->addr_cinh = d->cinh_bar; |
| 165 | 188 | |
| 189 | + if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000) | |
| 190 | + memset(p->addr_cena, 0, 64 * 1024); | |
| 191 | + | |
| 166 | 192 | reg = qbman_set_swp_cfg(p->dqrr.dqrr_size, |
| 167 | 193 | 1, /* Writes Non-cacheable */ |
| 168 | 194 | 0, /* EQCR_CI stashing threshold */ |
| @@ -175,6 +201,10 @@ struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d) · 6 unmodified lines | ||
| 175 | 201 | 1, /* dequeue stashing priority == TRUE */ |
| 176 | 202 | 0, /* dequeue stashing enable == FALSE */ |
| 177 | 203 | 0); /* EQCR_CI stashing priority == FALSE */ |
| 204 | + if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000) | |
| 205 | + reg |= 1 << SWP_CFG_CPBS_SHIFT | /* memory-backed mode */ | |
| 206 | + 1 << SWP_CFG_VPM_SHIFT | /* VDQCR read triggered mode */ | |
| 207 | + 1 << SWP_CFG_CPM_SHIFT; /* CR read triggered mode */ | |
| 178 | 208 | |
| 179 | 209 | qbman_write_register(p, QBMAN_CINH_SWP_CFG, reg); |
| 180 | 210 | reg = qbman_read_register(p, QBMAN_CINH_SWP_CFG); |
| @@ -184,6 +214,10 @@ struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d) · 3 unmodified lines | ||
| 184 | 214 | return NULL; |
| 185 | 215 | } |
| 186 | 216 | |
| 217 | + if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000) { | |
| 218 | + qbman_write_register(p, QBMAN_CINH_SWP_EQCR_PI, QMAN_RT_MODE); | |
| 219 | + qbman_write_register(p, QBMAN_CINH_SWP_RCR_PI, QMAN_RT_MODE); | |
| 220 | + } | |
| 187 | 221 | /* |
| 188 | 222 | * SDQCR needs to be initialized to 0 when no channels are |
| 189 | 223 | * being dequeued from or else the QMan HW will indicate an |
| @@ -278,7 +312,10 @@ void qbman_swp_interrupt_set_inhibit(struct qbman_swp *p, int inhibit) · 88 unmodified lines | ||
| 278 | 312 | */ |
| 279 | 313 | void *qbman_swp_mc_start(struct qbman_swp *p) |
| 280 | 314 | { |
| 281 | − return qbman_get_cmd(p, QBMAN_CENA_SWP_CR); | |
| 315 | + if ((p->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) | |
| 316 | + return qbman_get_cmd(p, QBMAN_CENA_SWP_CR); | |
| 317 | + else | |
| 318 | + return qbman_get_cmd(p, QBMAN_CENA_SWP_CR_MEM); | |
| 282 | 319 | } |
| 283 | 320 | |
| 284 | 321 | /* |
| @@ -289,8 +326,14 @@ void qbman_swp_mc_submit(struct qbman_swp *p, void *cmd, u8 cmd_verb) · 4 unmodified lines | ||
| 289 | 326 | { |
| 290 | 327 | u8 *v = cmd; |
| 291 | 328 | |
| 292 | − dma_wmb(); | |
| 293 | − *v = cmd_verb | p->mc.valid_bit; | |
| 329 | + if ((p->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) { | |
| 330 | + dma_wmb(); | |
| 331 | + *v = cmd_verb | p->mc.valid_bit; | |
| 332 | + } else { | |
| 333 | + *v = cmd_verb | p->mc.valid_bit; | |
| 334 | + dma_wmb(); | |
| 335 | + qbman_write_register(p, QBMAN_CINH_SWP_CR_RT, QMAN_RT_MODE); | |
| 336 | + } | |
| 294 | 337 | } |
| 295 | 338 | |
| 296 | 339 | /* |
| @@ -301,13 +344,27 @@ void *qbman_swp_mc_result(struct qbman_swp *p) · 4 unmodified lines | ||
| 301 | 344 | { |
| 302 | 345 | u32 *ret, verb; |
| 303 | 346 | |
| 304 | − ret = qbman_get_cmd(p, QBMAN_CENA_SWP_RR(p->mc.valid_bit)); | |
| 347 | + if ((p->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) { | |
| 348 | + ret = qbman_get_cmd(p, QBMAN_CENA_SWP_RR(p->mc.valid_bit)); | |
| 349 | + /* Remove the valid-bit - command completed if the rest | |
| 350 | + * is non-zero. | |
| 351 | + */ | |
| 352 | + verb = ret[0] & ~QB_VALID_BIT; | |
| 353 | + if (!verb) | |
| 354 | + return NULL; | |
| 355 | + p->mc.valid_bit ^= QB_VALID_BIT; | |
| 356 | + } else { | |
| 357 | + ret = qbman_get_cmd(p, QBMAN_CENA_SWP_RR_MEM); | |
| 358 | + /* Command completed if the valid bit is toggled */ | |
| 359 | + if (p->mr.valid_bit != (ret[0] & QB_VALID_BIT)) | |
| 360 | + return NULL; | |
| 361 | + /* Command completed if the rest is non-zero */ | |
| 362 | + verb = ret[0] & ~QB_VALID_BIT; | |
| 363 | + if (!verb) | |
| 364 | + return NULL; | |
| 365 | + p->mr.valid_bit ^= QB_VALID_BIT; | |
| 366 | + } | |
| 305 | 367 | |
| 306 | − /* Remove the valid-bit - command completed if the rest is non-zero */ | |
| 307 | − verb = ret[0] & ~QB_VALID_BIT; | |
| 308 | − if (!verb) | |
| 309 | − return NULL; | |
| 310 | − p->mc.valid_bit ^= QB_VALID_BIT; | |
| 311 | 368 | return ret; |
| 312 | 369 | } |
| 313 | 370 | |
| @@ -384,6 +441,18 @@ void qbman_eq_desc_set_qd(struct qbman_eq_desc *d, u32 qdid, · 70 unmodified lines | ||
| 384 | 441 | #define EQAR_VB(eqar) ((eqar) & 0x80) |
| 385 | 442 | #define EQAR_SUCCESS(eqar) ((eqar) & 0x100) |
| 386 | 443 | |
| 444 | +static inline void qbman_write_eqcr_am_rt_register(struct qbman_swp *p, | |
| 445 | + u8 idx) | |
| 446 | +{ | |
| 447 | + if (idx < 16) | |
| 448 | + qbman_write_register(p, QBMAN_CINH_SWP_EQCR_AM_RT + idx * 4, | |
| 449 | + QMAN_RT_MODE); | |
| 450 | + else | |
| 451 | + qbman_write_register(p, QBMAN_CINH_SWP_EQCR_AM_RT2 + | |
| 452 | + (idx - 16) * 4, | |
| 453 | + QMAN_RT_MODE); | |
| 454 | +} | |
| 455 | + | |
| 387 | 456 | /** |
| 388 | 457 | * qbman_swp_enqueue() - Issue an enqueue command |
| 389 | 458 | * @s: the software portal used for enqueue |
| @@ -408,9 +477,15 @@ int qbman_swp_enqueue(struct qbman_swp *s, const struct qbman_eq_desc *d, · 18 unmodified lines | ||
| 408 | 477 | memcpy(&p->dca, &d->dca, 31); |
| 409 | 478 | memcpy(&p->fd, fd, sizeof(*fd)); |
| 410 | 479 | |
| 411 | − /* Set the verb byte, have to substitute in the valid-bit */ | |
| 412 | − dma_wmb(); | |
| 413 | − p->verb = d->verb | EQAR_VB(eqar); | |
| 480 | + if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) { | |
| 481 | + /* Set the verb byte, have to substitute in the valid-bit */ | |
| 482 | + dma_wmb(); | |
| 483 | + p->verb = d->verb | EQAR_VB(eqar); | |
| 484 | + } else { | |
| 485 | + p->verb = d->verb | EQAR_VB(eqar); | |
| 486 | + dma_wmb(); | |
| 487 | + qbman_write_eqcr_am_rt_register(s, EQAR_IDX(eqar)); | |
| 488 | + } | |
| 414 | 489 | |
| 415 | 490 | return 0; |
| 416 | 491 | } |
| @@ -587,17 +662,27 @@ int qbman_swp_pull(struct qbman_swp *s, struct qbman_pull_desc *d) · 170 unmodified lines | ||
| 587 | 662 | return -EBUSY; |
| 588 | 663 | } |
| 589 | 664 | s->vdq.storage = (void *)(uintptr_t)d->rsp_addr_virt; |
| 590 | − p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR); | |
| 665 | + if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) | |
| 666 | + p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR); | |
| 667 | + else | |
| 668 | + p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR_MEM); | |
| 591 | 669 | p->numf = d->numf; |
| 592 | 670 | p->tok = QMAN_DQ_TOKEN_VALID; |
| 593 | 671 | p->dq_src = d->dq_src; |
| 594 | 672 | p->rsp_addr = d->rsp_addr; |
| 595 | 673 | p->rsp_addr_virt = d->rsp_addr_virt; |
| 596 | − dma_wmb(); | |
| 597 | 674 | |
| 598 | − /* Set the verb byte, have to substitute in the valid-bit */ | |
| 599 | − p->verb = d->verb | s->vdq.valid_bit; | |
| 600 | − s->vdq.valid_bit ^= QB_VALID_BIT; | |
| 675 | + if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) { | |
| 676 | + dma_wmb(); | |
| 677 | + /* Set the verb byte, have to substitute in the valid-bit */ | |
| 678 | + p->verb = d->verb | s->vdq.valid_bit; | |
| 679 | + s->vdq.valid_bit ^= QB_VALID_BIT; | |
| 680 | + } else { | |
| 681 | + p->verb = d->verb | s->vdq.valid_bit; | |
| 682 | + s->vdq.valid_bit ^= QB_VALID_BIT; | |
| 683 | + dma_wmb(); | |
| 684 | + qbman_write_register(s, QBMAN_CINH_SWP_VDQCR_RT, QMAN_RT_MODE); | |
| 685 | + } | |
| 601 | 686 | |
| 602 | 687 | return 0; |
| 603 | 688 | } |
| @@ -655,7 +740,10 @@ const struct dpaa2_dq *qbman_swp_dqrr_next(struct qbman_swp *s) · 51 unmodified lines | ||
| 655 | 740 | QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx))); |
| 656 | 741 | } |
| 657 | 742 | |
| 658 | − p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx)); | |
| 743 | + if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) | |
| 744 | + p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx)); | |
| 745 | + else | |
| 746 | + p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR_MEM(s->dqrr.next_idx)); | |
| 659 | 747 | verb = p->dq.verb; |
| 660 | 748 | |
| 661 | 749 | /* |
| @@ -807,18 +895,28 @@ int qbman_swp_release(struct qbman_swp *s, const struct qbman_release_desc *d, · 145 unmodified lines | ||
| 807 | 895 | return -EBUSY; |
| 808 | 896 | |
| 809 | 897 | /* Start the release command */ |
| 810 | − p = qbman_get_cmd(s, QBMAN_CENA_SWP_RCR(RAR_IDX(rar))); | |
| 898 | + if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) | |
| 899 | + p = qbman_get_cmd(s, QBMAN_CENA_SWP_RCR(RAR_IDX(rar))); | |
| 900 | + else | |
| 901 | + p = qbman_get_cmd(s, QBMAN_CENA_SWP_RCR_MEM(RAR_IDX(rar))); | |
| 811 | 902 | /* Copy the caller's buffer pointers to the command */ |
| 812 | 903 | for (i = 0; i < num_buffers; i++) |
| 813 | 904 | p->buf[i] = cpu_to_le64(buffers[i]); |
| 814 | 905 | p->bpid = d->bpid; |
| 815 | 906 | |
| 816 | − /* | |
| 817 | − * Set the verb byte, have to substitute in the valid-bit and the number | |
| 818 | − * of buffers. | |
| 819 | − */ | |
| 820 | − dma_wmb(); | |
| 821 | − p->verb = d->verb | RAR_VB(rar) | num_buffers; | |
| 907 | + if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) { | |
| 908 | + /* | |
| 909 | + * Set the verb byte, have to substitute in the valid-bit | |
| 910 | + * and the number of buffers. | |
| 911 | + */ | |
| 912 | + dma_wmb(); | |
| 913 | + p->verb = d->verb | RAR_VB(rar) | num_buffers; | |
| 914 | + } else { | |
| 915 | + p->verb = d->verb | RAR_VB(rar) | num_buffers; | |
| 916 | + dma_wmb(); | |
| 917 | + qbman_write_register(s, QBMAN_CINH_SWP_RCR_AM_RT + | |
| 918 | + RAR_IDX(rar) * 4, QMAN_RT_MODE); | |
| 919 | + } | |
| 822 | 920 | |
| 823 | 921 | return 0; |
| 824 | 922 | } |
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | /* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ |
| 2 | 2 | /* |
| 3 | 3 | * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. |
| 4 | − * Copyright 2016 NXP | |
| 4 | + * Copyright 2016-2019 NXP | |
| 5 | 5 | * |
| 6 | 6 | */ |
| 7 | 7 | #ifndef __FSL_QBMAN_PORTAL_H |
| @@ -110,6 +110,11 @@ struct qbman_swp { · 102 unmodified lines | ||
| 110 | 110 | u32 valid_bit; /* 0x00 or 0x80 */ |
| 111 | 111 | } mc; |
| 112 | 112 | |
| 113 | + /* Management response */ | |
| 114 | + struct { | |
| 115 | + u32 valid_bit; /* 0x00 or 0x80 */ | |
| 116 | + } mr; | |
| 117 | + | |
| 113 | 118 | /* Push dequeues */ |
| 114 | 119 | u32 sdq; |
| 115 | 120 | |
| @@ -428,7 +433,7 @@ static inline int qbman_swp_CDAN_set_context_enable(struct qbman_swp *s, · 312 unmodified lines | ||
| 428 | 433 | static inline void *qbman_swp_mc_complete(struct qbman_swp *swp, void *cmd, |
| 429 | 434 | u8 cmd_verb) |
| 430 | 435 | { |
| 431 | − int loopvar = 1000; | |
| 436 | + int loopvar = 2000; | |
| 432 | 437 | |
| 433 | 438 | qbman_swp_mc_submit(swp, cmd, cmd_verb); |
| 434 | 439 | |
| @@ -97,6 +97,11 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = { · 96 unmodified lines | ||
| 97 | 97 | .svr = 0x87000000, |
| 98 | 98 | .mask = 0xfff70000, |
| 99 | 99 | }, |
| 100 | + /* Die: LX2160A, SoC: LX2160A/LX2120A/LX2080A */ | |
| 101 | + { .die = "LX2160A", | |
| 102 | + .svr = 0x87360000, | |
| 103 | + .mask = 0xff3f0000, | |
| 104 | + }, | |
| 100 | 105 | { }, |
| 101 | 106 | }; |
| 102 | 107 | |
| @@ -218,6 +223,7 @@ static const struct of_device_id fsl_guts_of_match[] = { · 115 unmodified lines | ||
| 218 | 223 | { .compatible = "fsl,ls1088a-dcfg", }, |
| 219 | 224 | { .compatible = "fsl,ls1012a-dcfg", }, |
| 220 | 225 | { .compatible = "fsl,ls1046a-dcfg", }, |
| 226 | + { .compatible = "fsl,lx2160a-dcfg", }, | |
| 221 | 227 | {} |
| 222 | 228 | }; |
| 223 | 229 | MODULE_DEVICE_TABLE(of, fsl_guts_of_match); |
| @@ -32,6 +32,7 @@ · 31 unmodified lines | ||
| 32 | 32 | |
| 33 | 33 | static struct bman_portal *affine_bportals[NR_CPUS]; |
| 34 | 34 | static struct cpumask portal_cpus; |
| 35 | +static int __bman_portals_probed; | |
| 35 | 36 | /* protect bman global registers and global data shared among portals */ |
| 36 | 37 | static DEFINE_SPINLOCK(bman_lock); |
| 37 | 38 | |
| @@ -87,6 +88,12 @@ static int bman_online_cpu(unsigned int cpu) · 49 unmodified lines | ||
| 87 | 88 | return 0; |
| 88 | 89 | } |
| 89 | 90 | |
| 91 | +int bman_portals_probed(void) | |
| 92 | +{ | |
| 93 | + return __bman_portals_probed; | |
| 94 | +} | |
| 95 | +EXPORT_SYMBOL_GPL(bman_portals_probed); | |
| 96 | + | |
| 90 | 97 | static int bman_portal_probe(struct platform_device *pdev) |
| 91 | 98 | { |
| 92 | 99 | struct device *dev = &pdev->dev; |
| @@ -104,8 +111,10 @@ static int bman_portal_probe(struct platform_device *pdev) · 11 unmodified lines | ||
| 104 | 111 | } |
| 105 | 112 | |
| 106 | 113 | pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL); |
| 107 | − if (!pcfg) | |
| 114 | + if (!pcfg) { | |
| 115 | + __bman_portals_probed = -1; | |
| 108 | 116 | return -ENOMEM; |
| 117 | + } | |
| 109 | 118 | |
| 110 | 119 | pcfg->dev = dev; |
| 111 | 120 | |
| @@ -113,14 +122,14 @@ static int bman_portal_probe(struct platform_device *pdev) · 1 unmodified line | ||
| 113 | 122 | DPAA_PORTAL_CE); |
| 114 | 123 | if (!addr_phys[0]) { |
| 115 | 124 | dev_err(dev, "Can't get %pOF property 'reg::CE'\n", node); |
| 116 | − return -ENXIO; | |
| 125 | + goto err_ioremap1; | |
| 117 | 126 | } |
| 118 | 127 | |
| 119 | 128 | addr_phys[1] = platform_get_resource(pdev, IORESOURCE_MEM, |
| 120 | 129 | DPAA_PORTAL_CI); |
| 121 | 130 | if (!addr_phys[1]) { |
| 122 | 131 | dev_err(dev, "Can't get %pOF property 'reg::CI'\n", node); |
| 123 | − return -ENXIO; | |
| 132 | + goto err_ioremap1; | |
| 124 | 133 | } |
| 125 | 134 | |
| 126 | 135 | pcfg->cpu = -1; |
| @@ -128,7 +137,7 @@ static int bman_portal_probe(struct platform_device *pdev) · 1 unmodified line | ||
| 128 | 137 | irq = platform_get_irq(pdev, 0); |
| 129 | 138 | if (irq <= 0) { |
| 130 | 139 | dev_err(dev, "Can't get %pOF IRQ'\n", node); |
| 131 | − return -ENXIO; | |
| 140 | + goto err_ioremap1; | |
| 132 | 141 | } |
| 133 | 142 | pcfg->irq = irq; |
| 134 | 143 | |
| @@ -150,6 +159,7 @@ static int bman_portal_probe(struct platform_device *pdev) · 15 unmodified lines | ||
| 150 | 159 | spin_lock(&bman_lock); |
| 151 | 160 | cpu = cpumask_next_zero(-1, &portal_cpus); |
| 152 | 161 | if (cpu >= nr_cpu_ids) { |
| 162 | + __bman_portals_probed = 1; | |
| 153 | 163 | /* unassigned portal, skip init */ |
| 154 | 164 | spin_unlock(&bman_lock); |
| 155 | 165 | return 0; |
| @@ -175,6 +185,8 @@ err_portal_init: · 19 unmodified lines | ||
| 175 | 185 | err_ioremap2: |
| 176 | 186 | memunmap(pcfg->addr_virt_ce); |
| 177 | 187 | err_ioremap1: |
| 188 | + __bman_portals_probed = -1; | |
| 189 | + | |
| 178 | 190 | return -ENXIO; |
| 179 | 191 | } |
| 180 | 192 | |
| @@ -596,7 +596,7 @@ static int qman_init_ccsr(struct device *dev) · 595 unmodified lines | ||
| 596 | 596 | } |
| 597 | 597 | |
| 598 | 598 | #define LIO_CFG_LIODN_MASK 0x0fff0000 |
| 599 | −void qman_liodn_fixup(u16 channel) | |
| 599 | +void __qman_liodn_fixup(u16 channel) | |
| 600 | 600 | { |
| 601 | 601 | static int done; |
| 602 | 602 | static u32 liodn_offset; |
| @@ -38,6 +38,7 @@ EXPORT_SYMBOL(qman_dma_portal); · 37 unmodified lines | ||
| 38 | 38 | #define CONFIG_FSL_DPA_PIRQ_FAST 1 |
| 39 | 39 | |
| 40 | 40 | static struct cpumask portal_cpus; |
| 41 | +static int __qman_portals_probed; | |
| 41 | 42 | /* protect qman global registers and global data shared among portals */ |
| 42 | 43 | static DEFINE_SPINLOCK(qman_lock); |
| 43 | 44 | |
| @@ -220,6 +221,12 @@ static int qman_online_cpu(unsigned int cpu) · 176 unmodified lines | ||
| 220 | 221 | return 0; |
| 221 | 222 | } |
| 222 | 223 | |
| 224 | +int qman_portals_probed(void) | |
| 225 | +{ | |
| 226 | + return __qman_portals_probed; | |
| 227 | +} | |
| 228 | +EXPORT_SYMBOL_GPL(qman_portals_probed); | |
| 229 | + | |
| 223 | 230 | static int qman_portal_probe(struct platform_device *pdev) |
| 224 | 231 | { |
| 225 | 232 | struct device *dev = &pdev->dev; |
| @@ -238,8 +245,10 @@ static int qman_portal_probe(struct platform_device *pdev) · 12 unmodified lines | ||
| 238 | 245 | } |
| 239 | 246 | |
| 240 | 247 | pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL); |
| 241 | − if (!pcfg) | |
| 248 | + if (!pcfg) { | |
| 249 | + __qman_portals_probed = -1; | |
| 242 | 250 | return -ENOMEM; |
| 251 | + } | |
| 243 | 252 | |
| 244 | 253 | pcfg->dev = dev; |
| 245 | 254 | |
| @@ -247,19 +256,20 @@ static int qman_portal_probe(struct platform_device *pdev) · 1 unmodified line | ||
| 247 | 256 | DPAA_PORTAL_CE); |
| 248 | 257 | if (!addr_phys[0]) { |
| 249 | 258 | dev_err(dev, "Can't get %pOF property 'reg::CE'\n", node); |
| 250 | − return -ENXIO; | |
| 259 | + goto err_ioremap1; | |
| 251 | 260 | } |
| 252 | 261 | |
| 253 | 262 | addr_phys[1] = platform_get_resource(pdev, IORESOURCE_MEM, |
| 254 | 263 | DPAA_PORTAL_CI); |
| 255 | 264 | if (!addr_phys[1]) { |
| 256 | 265 | dev_err(dev, "Can't get %pOF property 'reg::CI'\n", node); |
| 257 | − return -ENXIO; | |
| 266 | + goto err_ioremap1; | |
| 258 | 267 | } |
| 259 | 268 | |
| 260 | 269 | err = of_property_read_u32(node, "cell-index", &val); |
| 261 | 270 | if (err) { |
| 262 | 271 | dev_err(dev, "Can't get %pOF property 'cell-index'\n", node); |
| 272 | + __qman_portals_probed = -1; | |
| 263 | 273 | return err; |
| 264 | 274 | } |
| 265 | 275 | pcfg->channel = val; |
| @@ -267,7 +277,7 @@ static int qman_portal_probe(struct platform_device *pdev) · 1 unmodified line | ||
| 267 | 277 | irq = platform_get_irq(pdev, 0); |
| 268 | 278 | if (irq <= 0) { |
| 269 | 279 | dev_err(dev, "Can't get %pOF IRQ\n", node); |
| 270 | − return -ENXIO; | |
| 280 | + goto err_ioremap1; | |
| 271 | 281 | } |
| 272 | 282 | pcfg->irq = irq; |
| 273 | 283 | |
| @@ -291,6 +301,7 @@ static int qman_portal_probe(struct platform_device *pdev) · 17 unmodified lines | ||
| 291 | 301 | spin_lock(&qman_lock); |
| 292 | 302 | cpu = cpumask_next_zero(-1, &portal_cpus); |
| 293 | 303 | if (cpu >= nr_cpu_ids) { |
| 304 | + __qman_portals_probed = 1; | |
| 294 | 305 | /* unassigned portal, skip init */ |
| 295 | 306 | spin_unlock(&qman_lock); |
| 296 | 307 | return 0; |
| @@ -321,6 +332,8 @@ err_portal_init: · 24 unmodified lines | ||
| 321 | 332 | err_ioremap2: |
| 322 | 333 | memunmap(pcfg->addr_virt_ce); |
| 323 | 334 | err_ioremap1: |
| 335 | + __qman_portals_probed = -1; | |
| 336 | + | |
| 324 | 337 | return -ENXIO; |
| 325 | 338 | } |
| 326 | 339 | |
| @@ -193,7 +193,14 @@ extern struct gen_pool *qm_cgralloc; /* CGR ID allocator */ · 192 unmodified lines | ||
| 193 | 193 | u32 qm_get_pools_sdqcr(void); |
| 194 | 194 | |
| 195 | 195 | int qman_wq_alloc(void); |
| 196 | −void qman_liodn_fixup(u16 channel); | |
| 196 | +#ifdef CONFIG_FSL_PAMU | |
| 197 | +#define qman_liodn_fixup __qman_liodn_fixup | |
| 198 | +#else | |
| 199 | +static inline void qman_liodn_fixup(u16 channel) | |
| 200 | +{ | |
| 201 | +} | |
| 202 | +#endif | |
| 203 | +void __qman_liodn_fixup(u16 channel); | |
| 197 | 204 | void qman_set_sdest(u16 channel, unsigned int cpu_idx); |
| 198 | 205 | |
| 199 | 206 | struct qman_portal *qman_create_affine_portal( |
| @@ -8,4 +8,13 @@ config IMX_GPCV2_PM_DOMAINS · 7 unmodified lines | ||
| 8 | 8 | select PM_GENERIC_DOMAINS |
| 9 | 9 | default y if SOC_IMX7D |
| 10 | 10 | |
| 11 | +config IMX_SCU_SOC | |
| 12 | + bool "i.MX System Controller Unit SoC info support" | |
| 13 | + depends on IMX_SCU | |
| 14 | + select SOC_BUS | |
| 15 | + help | |
| 16 | + If you say yes here you get support for the NXP i.MX System | |
| 17 | + Controller Unit SoC info module, it will provide the SoC info | |
| 18 | + like SoC family, ID and revision etc. | |
| 19 | + | |
| 11 | 20 | endmenu |
| @@ -2,3 +2,4 @@ · 1 unmodified line | ||
| 2 | 2 | obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o |
| 3 | 3 | obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o |
| 4 | 4 | obj-$(CONFIG_ARCH_MXC) += soc-imx8.o |
| 5 | +obj-$(CONFIG_IMX_SCU_SOC) += soc-imx-scu.o | |
| @@ -0,0 +1,144 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * Copyright 2019 NXP. | |
| 4 | + */ | |
| 5 | + | |
| 6 | +#include <dt-bindings/firmware/imx/rsrc.h> | |
| 7 | +#include <linux/firmware/imx/sci.h> | |
| 8 | +#include <linux/slab.h> | |
| 9 | +#include <linux/sys_soc.h> | |
| 10 | +#include <linux/platform_device.h> | |
| 11 | +#include <linux/of.h> | |
| 12 | + | |
| 13 | +#define IMX_SCU_SOC_DRIVER_NAME "imx-scu-soc" | |
| 14 | + | |
| 15 | +static struct imx_sc_ipc *soc_ipc_handle; | |
| 16 | + | |
| 17 | +struct imx_sc_msg_misc_get_soc_id { | |
| 18 | + struct imx_sc_rpc_msg hdr; | |
| 19 | + union { | |
| 20 | + struct { | |
| 21 | + u32 control; | |
| 22 | + u16 resource; | |
| 23 | + } __packed req; | |
| 24 | + struct { | |
| 25 | + u32 id; | |
| 26 | + } resp; | |
| 27 | + } data; | |
| 28 | +} __packed; | |
| 29 | + | |
| 30 | +static int imx_scu_soc_id(void) | |
| 31 | +{ | |
| 32 | + struct imx_sc_msg_misc_get_soc_id msg; | |
| 33 | + struct imx_sc_rpc_msg *hdr = &msg.hdr; | |
| 34 | + int ret; | |
| 35 | + | |
| 36 | + hdr->ver = IMX_SC_RPC_VERSION; | |
| 37 | + hdr->svc = IMX_SC_RPC_SVC_MISC; | |
| 38 | + hdr->func = IMX_SC_MISC_FUNC_GET_CONTROL; | |
| 39 | + hdr->size = 3; | |
| 40 | + | |
| 41 | + msg.data.req.control = IMX_SC_C_ID; | |
| 42 | + msg.data.req.resource = IMX_SC_R_SYSTEM; | |
| 43 | + | |
| 44 | + ret = imx_scu_call_rpc(soc_ipc_handle, &msg, true); | |
| 45 | + if (ret) { | |
| 46 | + pr_err("%s: get soc info failed, ret %d\n", __func__, ret); | |
| 47 | + return ret; | |
| 48 | + } | |
| 49 | + | |
| 50 | + return msg.data.resp.id; | |
| 51 | +} | |
| 52 | + | |
| 53 | +static int imx_scu_soc_probe(struct platform_device *pdev) | |
| 54 | +{ | |
| 55 | + struct soc_device_attribute *soc_dev_attr; | |
| 56 | + struct soc_device *soc_dev; | |
| 57 | + int id, ret; | |
| 58 | + u32 val; | |
| 59 | + | |
| 60 | + ret = imx_scu_get_handle(&soc_ipc_handle); | |
| 61 | + if (ret) | |
| 62 | + return ret; | |
| 63 | + | |
| 64 | + soc_dev_attr = devm_kzalloc(&pdev->dev, sizeof(*soc_dev_attr), | |
| 65 | + GFP_KERNEL); | |
| 66 | + if (!soc_dev_attr) | |
| 67 | + return -ENOMEM; | |
| 68 | + | |
| 69 | + soc_dev_attr->family = "Freescale i.MX"; | |
| 70 | + | |
| 71 | + ret = of_property_read_string(of_root, | |
| 72 | + "model", | |
| 73 | + &soc_dev_attr->machine); | |
| 74 | + if (ret) | |
| 75 | + return ret; | |
| 76 | + | |
| 77 | + id = imx_scu_soc_id(); | |
| 78 | + if (id < 0) | |
| 79 | + return -EINVAL; | |
| 80 | + | |
| 81 | + /* format soc_id value passed from SCU firmware */ | |
| 82 | + val = id & 0x1f; | |
| 83 | + soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "0x%x", val); | |
| 84 | + if (!soc_dev_attr->soc_id) | |
| 85 | + return -ENOMEM; | |
| 86 | + | |
| 87 | + /* format revision value passed from SCU firmware */ | |
| 88 | + val = (id >> 5) & 0xf; | |
| 89 | + val = (((val >> 2) + 1) << 4) | (val & 0x3); | |
| 90 | + soc_dev_attr->revision = kasprintf(GFP_KERNEL, | |
| 91 | + "%d.%d", | |
| 92 | + (val >> 4) & 0xf, | |
| 93 | + val & 0xf); | |
| 94 | + if (!soc_dev_attr->revision) { | |
| 95 | + ret = -ENOMEM; | |
| 96 | + goto free_soc_id; | |
| 97 | + } | |
| 98 | + | |
| 99 | + soc_dev = soc_device_register(soc_dev_attr); | |
| 100 | + if (IS_ERR(soc_dev)) { | |
| 101 | + ret = PTR_ERR(soc_dev); | |
| 102 | + goto free_revision; | |
| 103 | + } | |
| 104 | + | |
| 105 | + return 0; | |
| 106 | + | |
| 107 | +free_revision: | |
| 108 | + kfree(soc_dev_attr->revision); | |
| 109 | +free_soc_id: | |
| 110 | + kfree(soc_dev_attr->soc_id); | |
| 111 | + return ret; | |
| 112 | +} | |
| 113 | + | |
| 114 | +static struct platform_driver imx_scu_soc_driver = { | |
| 115 | + .driver = { | |
| 116 | + .name = IMX_SCU_SOC_DRIVER_NAME, | |
| 117 | + }, | |
| 118 | + .probe = imx_scu_soc_probe, | |
| 119 | +}; | |
| 120 | + | |
| 121 | +static int __init imx_scu_soc_init(void) | |
| 122 | +{ | |
| 123 | + struct platform_device *pdev; | |
| 124 | + struct device_node *np; | |
| 125 | + int ret; | |
| 126 | + | |
| 127 | + np = of_find_compatible_node(NULL, NULL, "fsl,imx-scu"); | |
| 128 | + if (!np) | |
| 129 | + return -ENODEV; | |
| 130 | + | |
| 131 | + of_node_put(np); | |
| 132 | + | |
| 133 | + ret = platform_driver_register(&imx_scu_soc_driver); | |
| 134 | + if (ret) | |
| 135 | + return ret; | |
| 136 | + | |
| 137 | + pdev = platform_device_register_simple(IMX_SCU_SOC_DRIVER_NAME, | |
| 138 | + -1, NULL, 0); | |
| 139 | + if (IS_ERR(pdev)) | |
| 140 | + platform_driver_unregister(&imx_scu_soc_driver); | |
| 141 | + | |
| 142 | + return PTR_ERR_OR_ZERO(pdev); | |
| 143 | +} | |
| 144 | +device_initcall(imx_scu_soc_init); | |
| @@ -16,6 +16,9 @@ · 15 unmodified lines | ||
| 16 | 16 | #define IMX8MQ_SW_INFO_B1 0x40 |
| 17 | 17 | #define IMX8MQ_SW_MAGIC_B1 0xff0055aa |
| 18 | 18 | |
| 19 | +/* Same as ANADIG_DIGPROG_IMX7D */ | |
| 20 | +#define ANADIG_DIGPROG_IMX8MM 0x800 | |
| 21 | + | |
| 19 | 22 | struct imx8_soc_data { |
| 20 | 23 | char *name; |
| 21 | 24 | u32 (*soc_revision)(void); |
| @@ -46,13 +49,45 @@ out: · 24 unmodified lines | ||
| 46 | 49 | return rev; |
| 47 | 50 | } |
| 48 | 51 | |
| 52 | +static u32 __init imx8mm_soc_revision(void) | |
| 53 | +{ | |
| 54 | + struct device_node *np; | |
| 55 | + void __iomem *anatop_base; | |
| 56 | + u32 rev; | |
| 57 | + | |
| 58 | + np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-anatop"); | |
| 59 | + if (!np) | |
| 60 | + return 0; | |
| 61 | + | |
| 62 | + anatop_base = of_iomap(np, 0); | |
| 63 | + WARN_ON(!anatop_base); | |
| 64 | + | |
| 65 | + rev = readl_relaxed(anatop_base + ANADIG_DIGPROG_IMX8MM); | |
| 66 | + | |
| 67 | + iounmap(anatop_base); | |
| 68 | + of_node_put(np); | |
| 69 | + return rev; | |
| 70 | +} | |
| 71 | + | |
| 49 | 72 | static const struct imx8_soc_data imx8mq_soc_data = { |
| 50 | 73 | .name = "i.MX8MQ", |
| 51 | 74 | .soc_revision = imx8mq_soc_revision, |
| 52 | 75 | }; |
| 53 | 76 | |
| 77 | +static const struct imx8_soc_data imx8mm_soc_data = { | |
| 78 | + .name = "i.MX8MM", | |
| 79 | + .soc_revision = imx8mm_soc_revision, | |
| 80 | +}; | |
| 81 | + | |
| 82 | +static const struct imx8_soc_data imx8mn_soc_data = { | |
| 83 | + .name = "i.MX8MN", | |
| 84 | + .soc_revision = imx8mm_soc_revision, | |
| 85 | +}; | |
| 86 | + | |
| 54 | 87 | static const struct of_device_id imx8_soc_match[] = { |
| 55 | 88 | { .compatible = "fsl,imx8mq", .data = &imx8mq_soc_data, }, |
| 89 | + { .compatible = "fsl,imx8mm", .data = &imx8mm_soc_data, }, | |
| 90 | + { .compatible = "fsl,imx8mn", .data = &imx8mn_soc_data, }, | |
| 56 | 91 | { } |
| 57 | 92 | }; |
| 58 | 93 | |
| @@ -65,7 +100,6 @@ static int __init imx8_soc_init(void) · 6 unmodified lines | ||
| 65 | 100 | { |
| 66 | 101 | struct soc_device_attribute *soc_dev_attr; |
| 67 | 102 | struct soc_device *soc_dev; |
| 68 | − struct device_node *root; | |
| 69 | 103 | const struct of_device_id *id; |
| 70 | 104 | u32 soc_rev = 0; |
| 71 | 105 | const struct imx8_soc_data *data; |
| @@ -73,20 +107,19 @@ static int __init imx8_soc_init(void) · 1 unmodified line | ||
| 73 | 107 | |
| 74 | 108 | soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); |
| 75 | 109 | if (!soc_dev_attr) |
| 76 | − return -ENODEV; | |
| 110 | + return -ENOMEM; | |
| 77 | 111 | |
| 78 | 112 | soc_dev_attr->family = "Freescale i.MX"; |
| 79 | 113 | |
| 80 | − root = of_find_node_by_path("/"); | |
| 81 | − ret = of_property_read_string(root, "model", &soc_dev_attr->machine); | |
| 114 | + ret = of_property_read_string(of_root, "model", &soc_dev_attr->machine); | |
| 82 | 115 | if (ret) |
| 83 | 116 | goto free_soc; |
| 84 | 117 | |
| 85 | − id = of_match_node(imx8_soc_match, root); | |
| 86 | − if (!id) | |
| 118 | + id = of_match_node(imx8_soc_match, of_root); | |
| 119 | + if (!id) { | |
| 120 | + ret = -ENODEV; | |
| 87 | 121 | goto free_soc; |
| 88 | − | |
| 89 | − of_node_put(root); | |
| 122 | + } | |
| 90 | 123 | |
| 91 | 124 | data = id->data; |
| 92 | 125 | if (data) { |
| @@ -96,12 +129,16 @@ static int __init imx8_soc_init(void) · 3 unmodified lines | ||
| 96 | 129 | } |
| 97 | 130 | |
| 98 | 131 | soc_dev_attr->revision = imx8_revision(soc_rev); |
| 99 | − if (!soc_dev_attr->revision) | |
| 132 | + if (!soc_dev_attr->revision) { | |
| 133 | + ret = -ENOMEM; | |
| 100 | 134 | goto free_soc; |
| 135 | + } | |
| 101 | 136 | |
| 102 | 137 | soc_dev = soc_device_register(soc_dev_attr); |
| 103 | − if (IS_ERR(soc_dev)) | |
| 138 | + if (IS_ERR(soc_dev)) { | |
| 139 | + ret = PTR_ERR(soc_dev); | |
| 104 | 140 | goto free_rev; |
| 141 | + } | |
| 105 | 142 | |
| 106 | 143 | if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT)) |
| 107 | 144 | platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0); |
| @@ -109,10 +146,10 @@ static int __init imx8_soc_init(void) · 1 unmodified line | ||
| 109 | 146 | return 0; |
| 110 | 147 | |
| 111 | 148 | free_rev: |
| 112 | − kfree(soc_dev_attr->revision); | |
| 149 | + if (strcmp(soc_dev_attr->revision, "unknown")) | |
| 150 | + kfree(soc_dev_attr->revision); | |
| 113 | 151 | free_soc: |
| 114 | 152 | kfree(soc_dev_attr); |
| 115 | − of_node_put(root); | |
| 116 | − return -ENODEV; | |
| 153 | + return ret; | |
| 117 | 154 | } |
| 118 | 155 | device_initcall(imx8_soc_init); |
| @@ -4,6 +4,18 @@ · 3 unmodified lines | ||
| 4 | 4 | # |
| 5 | 5 | menu "Qualcomm SoC drivers" |
| 6 | 6 | |
| 7 | +config QCOM_AOSS_QMP | |
| 8 | + tristate "Qualcomm AOSS Driver" | |
| 9 | + depends on ARCH_QCOM || COMPILE_TEST | |
| 10 | + depends on MAILBOX | |
| 11 | + depends on COMMON_CLK && PM | |
| 12 | + select PM_GENERIC_DOMAINS | |
| 13 | + help | |
| 14 | + This driver provides the means of communicating with and controlling | |
| 15 | + the low-power state for resources related to the remoteproc | |
| 16 | + subsystems as well as controlling the debug clocks exposed by the Always On | |
| 17 | + Subsystem (AOSS) using Qualcomm Messaging Protocol (QMP). | |
| 18 | + | |
| 7 | 19 | config QCOM_COMMAND_DB |
| 8 | 20 | bool "Qualcomm Command DB" |
| 9 | 21 | depends on ARCH_QCOM || COMPILE_TEST |
| @@ -1,5 +1,6 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: GPL-2.0 |
| 2 | 2 | CFLAGS_rpmh-rsc.o := -I$(src) |
| 3 | +obj-$(CONFIG_QCOM_AOSS_QMP) += qcom_aoss.o | |
| 3 | 4 | obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o |
| 4 | 5 | obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o |
| 5 | 6 | obj-$(CONFIG_QCOM_GLINK_SSR) += glink_ssr.o |
| @@ -8,6 +8,7 @@ · 7 unmodified lines | ||
| 8 | 8 | #include <linux/spinlock.h> |
| 9 | 9 | #include <linux/idr.h> |
| 10 | 10 | #include <linux/slab.h> |
| 11 | +#include <linux/workqueue.h> | |
| 11 | 12 | #include <linux/of_device.h> |
| 12 | 13 | #include <linux/soc/qcom/apr.h> |
| 13 | 14 | #include <linux/rpmsg.h> |
| @@ -17,8 +18,18 @@ struct apr { · 3 unmodified lines | ||
| 17 | 18 | struct rpmsg_endpoint *ch; |
| 18 | 19 | struct device *dev; |
| 19 | 20 | spinlock_t svcs_lock; |
| 21 | + spinlock_t rx_lock; | |
| 20 | 22 | struct idr svcs_idr; |
| 21 | 23 | int dest_domain_id; |
| 24 | + struct workqueue_struct *rxwq; | |
| 25 | + struct work_struct rx_work; | |
| 26 | + struct list_head rx_list; | |
| 27 | +}; | |
| 28 | + | |
| 29 | +struct apr_rx_buf { | |
| 30 | + struct list_head node; | |
| 31 | + int len; | |
| 32 | + uint8_t buf[]; | |
| 22 | 33 | }; |
| 23 | 34 | |
| 24 | 35 | /** |
| @@ -62,11 +73,7 @@ static int apr_callback(struct rpmsg_device *rpdev, void *buf, · 37 unmodified lines | ||
| 62 | 73 | int len, void *priv, u32 addr) |
| 63 | 74 | { |
| 64 | 75 | struct apr *apr = dev_get_drvdata(&rpdev->dev); |
| 65 | − uint16_t hdr_size, msg_type, ver, svc_id; | |
| 66 | − struct apr_device *svc = NULL; | |
| 67 | − struct apr_driver *adrv = NULL; | |
| 68 | − struct apr_resp_pkt resp; | |
| 69 | − struct apr_hdr *hdr; | |
| 76 | + struct apr_rx_buf *abuf; | |
| 70 | 77 | unsigned long flags; |
| 71 | 78 | |
| 72 | 79 | if (len <= APR_HDR_SIZE) { |
| @@ -75,6 +82,34 @@ static int apr_callback(struct rpmsg_device *rpdev, void *buf, · 2 unmodified lines | ||
| 75 | 82 | return -EINVAL; |
| 76 | 83 | } |
| 77 | 84 | |
| 85 | + abuf = kzalloc(sizeof(*abuf) + len, GFP_ATOMIC); | |
| 86 | + if (!abuf) | |
| 87 | + return -ENOMEM; | |
| 88 | + | |
| 89 | + abuf->len = len; | |
| 90 | + memcpy(abuf->buf, buf, len); | |
| 91 | + | |
| 92 | + spin_lock_irqsave(&apr->rx_lock, flags); | |
| 93 | + list_add_tail(&abuf->node, &apr->rx_list); | |
| 94 | + spin_unlock_irqrestore(&apr->rx_lock, flags); | |
| 95 | + | |
| 96 | + queue_work(apr->rxwq, &apr->rx_work); | |
| 97 | + | |
| 98 | + return 0; | |
| 99 | +} | |
| 100 | + | |
| 101 | + | |
| 102 | +static int apr_do_rx_callback(struct apr *apr, struct apr_rx_buf *abuf) | |
| 103 | +{ | |
| 104 | + uint16_t hdr_size, msg_type, ver, svc_id; | |
| 105 | + struct apr_device *svc = NULL; | |
| 106 | + struct apr_driver *adrv = NULL; | |
| 107 | + struct apr_resp_pkt resp; | |
| 108 | + struct apr_hdr *hdr; | |
| 109 | + unsigned long flags; | |
| 110 | + void *buf = abuf->buf; | |
| 111 | + int len = abuf->len; | |
| 112 | + | |
| 78 | 113 | hdr = buf; |
| 79 | 114 | ver = APR_HDR_FIELD_VER(hdr->hdr_field); |
| 80 | 115 | if (ver > APR_PKT_VER + 1) |
| @@ -132,6 +167,23 @@ static int apr_callback(struct rpmsg_device *rpdev, void *buf, · 51 unmodified lines | ||
| 132 | 167 | return 0; |
| 133 | 168 | } |
| 134 | 169 | |
| 170 | +static void apr_rxwq(struct work_struct *work) | |
| 171 | +{ | |
| 172 | + struct apr *apr = container_of(work, struct apr, rx_work); | |
| 173 | + struct apr_rx_buf *abuf, *b; | |
| 174 | + unsigned long flags; | |
| 175 | + | |
| 176 | + if (!list_empty(&apr->rx_list)) { | |
| 177 | + list_for_each_entry_safe(abuf, b, &apr->rx_list, node) { | |
| 178 | + apr_do_rx_callback(apr, abuf); | |
| 179 | + spin_lock_irqsave(&apr->rx_lock, flags); | |
| 180 | + list_del(&abuf->node); | |
| 181 | + spin_unlock_irqrestore(&apr->rx_lock, flags); | |
| 182 | + kfree(abuf); | |
| 183 | + } | |
| 184 | + } | |
| 185 | +} | |
| 186 | + | |
| 135 | 187 | static int apr_device_match(struct device *dev, struct device_driver *drv) |
| 136 | 188 | { |
| 137 | 189 | struct apr_device *adev = to_apr_device(dev); |
| @@ -276,7 +328,7 @@ static int apr_probe(struct rpmsg_device *rpdev) · 138 unmodified lines | ||
| 276 | 328 | if (!apr) |
| 277 | 329 | return -ENOMEM; |
| 278 | 330 | |
| 279 | − ret = of_property_read_u32(dev->of_node, "reg", &apr->dest_domain_id); | |
| 331 | + ret = of_property_read_u32(dev->of_node, "qcom,apr-domain", &apr->dest_domain_id); | |
| 280 | 332 | if (ret) { |
| 281 | 333 | dev_err(dev, "APR Domain ID not specified in DT\n"); |
| 282 | 334 | return ret; |
| @@ -285,6 +337,14 @@ static int apr_probe(struct rpmsg_device *rpdev) · 2 unmodified lines | ||
| 285 | 337 | dev_set_drvdata(dev, apr); |
| 286 | 338 | apr->ch = rpdev->ept; |
| 287 | 339 | apr->dev = dev; |
| 340 | + apr->rxwq = create_singlethread_workqueue("qcom_apr_rx"); | |
| 341 | + if (!apr->rxwq) { | |
| 342 | + dev_err(apr->dev, "Failed to start Rx WQ\n"); | |
| 343 | + return -ENOMEM; | |
| 344 | + } | |
| 345 | + INIT_WORK(&apr->rx_work, apr_rxwq); | |
| 346 | + INIT_LIST_HEAD(&apr->rx_list); | |
| 347 | + spin_lock_init(&apr->rx_lock); | |
| 288 | 348 | spin_lock_init(&apr->svcs_lock); |
| 289 | 349 | idr_init(&apr->svcs_idr); |
| 290 | 350 | of_register_apr_devices(dev); |
| @@ -303,7 +363,11 @@ static int apr_remove_device(struct device *dev, void *null) · 12 unmodified lines | ||
| 303 | 363 | |
| 304 | 364 | static void apr_remove(struct rpmsg_device *rpdev) |
| 305 | 365 | { |
| 366 | + struct apr *apr = dev_get_drvdata(&rpdev->dev); | |
| 367 | + | |
| 306 | 368 | device_for_each_child(&rpdev->dev, NULL, apr_remove_device); |
| 369 | + flush_workqueue(apr->rxwq); | |
| 370 | + destroy_workqueue(apr->rxwq); | |
| 307 | 371 | } |
| 308 | 372 | |
| 309 | 373 | /* |
| @@ -0,0 +1,480 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * Copyright (c) 2019, Linaro Ltd | |
| 4 | + */ | |
| 5 | +#include <dt-bindings/power/qcom-aoss-qmp.h> | |
| 6 | +#include <linux/clk-provider.h> | |
| 7 | +#include <linux/interrupt.h> | |
| 8 | +#include <linux/io.h> | |
| 9 | +#include <linux/mailbox_client.h> | |
| 10 | +#include <linux/module.h> | |
| 11 | +#include <linux/platform_device.h> | |
| 12 | +#include <linux/pm_domain.h> | |
| 13 | + | |
| 14 | +#define QMP_DESC_MAGIC 0x0 | |
| 15 | +#define QMP_DESC_VERSION 0x4 | |
| 16 | +#define QMP_DESC_FEATURES 0x8 | |
| 17 | + | |
| 18 | +/* AOP-side offsets */ | |
| 19 | +#define QMP_DESC_UCORE_LINK_STATE 0xc | |
| 20 | +#define QMP_DESC_UCORE_LINK_STATE_ACK 0x10 | |
| 21 | +#define QMP_DESC_UCORE_CH_STATE 0x14 | |
| 22 | +#define QMP_DESC_UCORE_CH_STATE_ACK 0x18 | |
| 23 | +#define QMP_DESC_UCORE_MBOX_SIZE 0x1c | |
| 24 | +#define QMP_DESC_UCORE_MBOX_OFFSET 0x20 | |
| 25 | + | |
| 26 | +/* Linux-side offsets */ | |
| 27 | +#define QMP_DESC_MCORE_LINK_STATE 0x24 | |
| 28 | +#define QMP_DESC_MCORE_LINK_STATE_ACK 0x28 | |
| 29 | +#define QMP_DESC_MCORE_CH_STATE 0x2c | |
| 30 | +#define QMP_DESC_MCORE_CH_STATE_ACK 0x30 | |
| 31 | +#define QMP_DESC_MCORE_MBOX_SIZE 0x34 | |
| 32 | +#define QMP_DESC_MCORE_MBOX_OFFSET 0x38 | |
| 33 | + | |
| 34 | +#define QMP_STATE_UP GENMASK(15, 0) | |
| 35 | +#define QMP_STATE_DOWN GENMASK(31, 16) | |
| 36 | + | |
| 37 | +#define QMP_MAGIC 0x4d41494c /* mail */ | |
| 38 | +#define QMP_VERSION 1 | |
| 39 | + | |
| 40 | +/* 64 bytes is enough to store the requests and provides padding to 4 bytes */ | |
| 41 | +#define QMP_MSG_LEN 64 | |
| 42 | + | |
| 43 | +/** | |
| 44 | + * struct qmp - driver state for QMP implementation | |
| 45 | + * @msgram: iomem referencing the message RAM used for communication | |
| 46 | + * @dev: reference to QMP device | |
| 47 | + * @mbox_client: mailbox client used to ring the doorbell on transmit | |
| 48 | + * @mbox_chan: mailbox channel used to ring the doorbell on transmit | |
| 49 | + * @offset: offset within @msgram where messages should be written | |
| 50 | + * @size: maximum size of the messages to be transmitted | |
| 51 | + * @event: wait_queue for synchronization with the IRQ | |
| 52 | + * @tx_lock: provides synchronization between multiple callers of qmp_send() | |
| 53 | + * @qdss_clk: QDSS clock hw struct | |
| 54 | + * @pd_data: genpd data | |
| 55 | + */ | |
| 56 | +struct qmp { | |
| 57 | + void __iomem *msgram; | |
| 58 | + struct device *dev; | |
| 59 | + | |
| 60 | + struct mbox_client mbox_client; | |
| 61 | + struct mbox_chan *mbox_chan; | |
| 62 | + | |
| 63 | + size_t offset; | |
| 64 | + size_t size; | |
| 65 | + | |
| 66 | + wait_queue_head_t event; | |
| 67 | + | |
| 68 | + struct mutex tx_lock; | |
| 69 | + | |
| 70 | + struct clk_hw qdss_clk; | |
| 71 | + struct genpd_onecell_data pd_data; | |
| 72 | +}; | |
| 73 | + | |
| 74 | +struct qmp_pd { | |
| 75 | + struct qmp *qmp; | |
| 76 | + struct generic_pm_domain pd; | |
| 77 | +}; | |
| 78 | + | |
| 79 | +#define to_qmp_pd_resource(res) container_of(res, struct qmp_pd, pd) | |
| 80 | + | |
| 81 | +static void qmp_kick(struct qmp *qmp) | |
| 82 | +{ | |
| 83 | + mbox_send_message(qmp->mbox_chan, NULL); | |
| 84 | + mbox_client_txdone(qmp->mbox_chan, 0); | |
| 85 | +} | |
| 86 | + | |
| 87 | +static bool qmp_magic_valid(struct qmp *qmp) | |
| 88 | +{ | |
| 89 | + return readl(qmp->msgram + QMP_DESC_MAGIC) == QMP_MAGIC; | |
| 90 | +} | |
| 91 | + | |
| 92 | +static bool qmp_link_acked(struct qmp *qmp) | |
| 93 | +{ | |
| 94 | + return readl(qmp->msgram + QMP_DESC_MCORE_LINK_STATE_ACK) == QMP_STATE_UP; | |
| 95 | +} | |
| 96 | + | |
| 97 | +static bool qmp_mcore_channel_acked(struct qmp *qmp) | |
| 98 | +{ | |
| 99 | + return readl(qmp->msgram + QMP_DESC_MCORE_CH_STATE_ACK) == QMP_STATE_UP; | |
| 100 | +} | |
| 101 | + | |
| 102 | +static bool qmp_ucore_channel_up(struct qmp *qmp) | |
| 103 | +{ | |
| 104 | + return readl(qmp->msgram + QMP_DESC_UCORE_CH_STATE) == QMP_STATE_UP; | |
| 105 | +} | |
| 106 | + | |
| 107 | +static int qmp_open(struct qmp *qmp) | |
| 108 | +{ | |
| 109 | + int ret; | |
| 110 | + u32 val; | |
| 111 | + | |
| 112 | + if (!qmp_magic_valid(qmp)) { | |
| 113 | + dev_err(qmp->dev, "QMP magic doesn't match\n"); | |
| 114 | + return -EINVAL; | |
| 115 | + } | |
| 116 | + | |
| 117 | + val = readl(qmp->msgram + QMP_DESC_VERSION); | |
| 118 | + if (val != QMP_VERSION) { | |
| 119 | + dev_err(qmp->dev, "unsupported QMP version %d\n", val); | |
| 120 | + return -EINVAL; | |
| 121 | + } | |
| 122 | + | |
| 123 | + qmp->offset = readl(qmp->msgram + QMP_DESC_MCORE_MBOX_OFFSET); | |
| 124 | + qmp->size = readl(qmp->msgram + QMP_DESC_MCORE_MBOX_SIZE); | |
| 125 | + if (!qmp->size) { | |
| 126 | + dev_err(qmp->dev, "invalid mailbox size\n"); | |
| 127 | + return -EINVAL; | |
| 128 | + } | |
| 129 | + | |
| 130 | + /* Ack remote core's link state */ | |
| 131 | + val = readl(qmp->msgram + QMP_DESC_UCORE_LINK_STATE); | |
| 132 | + writel(val, qmp->msgram + QMP_DESC_UCORE_LINK_STATE_ACK); | |
| 133 | + | |
| 134 | + /* Set local core's link state to up */ | |
| 135 | + writel(QMP_STATE_UP, qmp->msgram + QMP_DESC_MCORE_LINK_STATE); | |
| 136 | + | |
| 137 | + qmp_kick(qmp); | |
| 138 | + | |
| 139 | + ret = wait_event_timeout(qmp->event, qmp_link_acked(qmp), HZ); | |
| 140 | + if (!ret) { | |
| 141 | + dev_err(qmp->dev, "ucore didn't ack link\n"); | |
| 142 | + goto timeout_close_link; | |
| 143 | + } | |
| 144 | + | |
| 145 | + writel(QMP_STATE_UP, qmp->msgram + QMP_DESC_MCORE_CH_STATE); | |
| 146 | + | |
| 147 | + qmp_kick(qmp); | |
| 148 | + | |
| 149 | + ret = wait_event_timeout(qmp->event, qmp_ucore_channel_up(qmp), HZ); | |
| 150 | + if (!ret) { | |
| 151 | + dev_err(qmp->dev, "ucore didn't open channel\n"); | |
| 152 | + goto timeout_close_channel; | |
| 153 | + } | |
| 154 | + | |
| 155 | + /* Ack remote core's channel state */ | |
| 156 | + writel(QMP_STATE_UP, qmp->msgram + QMP_DESC_UCORE_CH_STATE_ACK); | |
| 157 | + | |
| 158 | + qmp_kick(qmp); | |
| 159 | + | |
| 160 | + ret = wait_event_timeout(qmp->event, qmp_mcore_channel_acked(qmp), HZ); | |
| 161 | + if (!ret) { | |
| 162 | + dev_err(qmp->dev, "ucore didn't ack channel\n"); | |
| 163 | + goto timeout_close_channel; | |
| 164 | + } | |
| 165 | + | |
| 166 | + return 0; | |
| 167 | + | |
| 168 | +timeout_close_channel: | |
| 169 | + writel(QMP_STATE_DOWN, qmp->msgram + QMP_DESC_MCORE_CH_STATE); | |
| 170 | + | |
| 171 | +timeout_close_link: | |
| 172 | + writel(QMP_STATE_DOWN, qmp->msgram + QMP_DESC_MCORE_LINK_STATE); | |
| 173 | + qmp_kick(qmp); | |
| 174 | + | |
| 175 | + return -ETIMEDOUT; | |
| 176 | +} | |
| 177 | + | |
| 178 | +static void qmp_close(struct qmp *qmp) | |
| 179 | +{ | |
| 180 | + writel(QMP_STATE_DOWN, qmp->msgram + QMP_DESC_MCORE_CH_STATE); | |
| 181 | + writel(QMP_STATE_DOWN, qmp->msgram + QMP_DESC_MCORE_LINK_STATE); | |
| 182 | + qmp_kick(qmp); | |
| 183 | +} | |
| 184 | + | |
| 185 | +static irqreturn_t qmp_intr(int irq, void *data) | |
| 186 | +{ | |
| 187 | + struct qmp *qmp = data; | |
| 188 | + | |
| 189 | + wake_up_interruptible_all(&qmp->event); | |
| 190 | + | |
| 191 | + return IRQ_HANDLED; | |
| 192 | +} | |
| 193 | + | |
| 194 | +static bool qmp_message_empty(struct qmp *qmp) | |
| 195 | +{ | |
| 196 | + return readl(qmp->msgram + qmp->offset) == 0; | |
| 197 | +} | |
| 198 | + | |
| 199 | +/** | |
| 200 | + * qmp_send() - send a message to the AOSS | |
| 201 | + * @qmp: qmp context | |
| 202 | + * @data: message to be sent | |
| 203 | + * @len: length of the message | |
| 204 | + * | |
| 205 | + * Transmit @data to AOSS and wait for the AOSS to acknowledge the message. | |
| 206 | + * @len must be a multiple of 4 and not longer than the mailbox size. Access is | |
| 207 | + * synchronized by this implementation. | |
| 208 | + * | |
| 209 | + * Return: 0 on success, negative errno on failure | |
| 210 | + */ | |
| 211 | +static int qmp_send(struct qmp *qmp, const void *data, size_t len) | |
| 212 | +{ | |
| 213 | + long time_left; | |
| 214 | + int ret; | |
| 215 | + | |
| 216 | + if (WARN_ON(len + sizeof(u32) > qmp->size)) | |
| 217 | + return -EINVAL; | |
| 218 | + | |
| 219 | + if (WARN_ON(len % sizeof(u32))) | |
| 220 | + return -EINVAL; | |
| 221 | + | |
| 222 | + mutex_lock(&qmp->tx_lock); | |
| 223 | + | |
| 224 | + /* The message RAM only implements 32-bit accesses */ | |
| 225 | + __iowrite32_copy(qmp->msgram + qmp->offset + sizeof(u32), | |
| 226 | + data, len / sizeof(u32)); | |
| 227 | + writel(len, qmp->msgram + qmp->offset); | |
| 228 | + qmp_kick(qmp); | |
| 229 | + | |
| 230 | + time_left = wait_event_interruptible_timeout(qmp->event, | |
| 231 | + qmp_message_empty(qmp), HZ); | |
| 232 | + if (!time_left) { | |
| 233 | + dev_err(qmp->dev, "ucore did not ack channel\n"); | |
| 234 | + ret = -ETIMEDOUT; | |
| 235 | + | |
| 236 | + /* Clear message from buffer */ | |
| 237 | + writel(0, qmp->msgram + qmp->offset); | |
| 238 | + } else { | |
| 239 | + ret = 0; | |
| 240 | + } | |
| 241 | + | |
| 242 | + mutex_unlock(&qmp->tx_lock); | |
| 243 | + | |
| 244 | + return ret; | |
| 245 | +} | |
| 246 | + | |
| 247 | +static int qmp_qdss_clk_prepare(struct clk_hw *hw) | |
| 248 | +{ | |
| 249 | + static const char buf[QMP_MSG_LEN] = "{class: clock, res: qdss, val: 1}"; | |
| 250 | + struct qmp *qmp = container_of(hw, struct qmp, qdss_clk); | |
| 251 | + | |
| 252 | + return qmp_send(qmp, buf, sizeof(buf)); | |
| 253 | +} | |
| 254 | + | |
| 255 | +static void qmp_qdss_clk_unprepare(struct clk_hw *hw) | |
| 256 | +{ | |
| 257 | + static const char buf[QMP_MSG_LEN] = "{class: clock, res: qdss, val: 0}"; | |
| 258 | + struct qmp *qmp = container_of(hw, struct qmp, qdss_clk); | |
| 259 | + | |
| 260 | + qmp_send(qmp, buf, sizeof(buf)); | |
| 261 | +} | |
| 262 | + | |
| 263 | +static const struct clk_ops qmp_qdss_clk_ops = { | |
| 264 | + .prepare = qmp_qdss_clk_prepare, | |
| 265 | + .unprepare = qmp_qdss_clk_unprepare, | |
| 266 | +}; | |
| 267 | + | |
| 268 | +static int qmp_qdss_clk_add(struct qmp *qmp) | |
| 269 | +{ | |
| 270 | + static const struct clk_init_data qdss_init = { | |
| 271 | + .ops = &qmp_qdss_clk_ops, | |
| 272 | + .name = "qdss", | |
| 273 | + }; | |
| 274 | + int ret; | |
| 275 | + | |
| 276 | + qmp->qdss_clk.init = &qdss_init; | |
| 277 | + ret = clk_hw_register(qmp->dev, &qmp->qdss_clk); | |
| 278 | + if (ret < 0) { | |
| 279 | + dev_err(qmp->dev, "failed to register qdss clock\n"); | |
| 280 | + return ret; | |
| 281 | + } | |
| 282 | + | |
| 283 | + ret = of_clk_add_hw_provider(qmp->dev->of_node, of_clk_hw_simple_get, | |
| 284 | + &qmp->qdss_clk); | |
| 285 | + if (ret < 0) { | |
| 286 | + dev_err(qmp->dev, "unable to register of clk hw provider\n"); | |
| 287 | + clk_hw_unregister(&qmp->qdss_clk); | |
| 288 | + } | |
| 289 | + | |
| 290 | + return ret; | |
| 291 | +} | |
| 292 | + | |
| 293 | +static void qmp_qdss_clk_remove(struct qmp *qmp) | |
| 294 | +{ | |
| 295 | + of_clk_del_provider(qmp->dev->of_node); | |
| 296 | + clk_hw_unregister(&qmp->qdss_clk); | |
| 297 | +} | |
| 298 | + | |
| 299 | +static int qmp_pd_power_toggle(struct qmp_pd *res, bool enable) | |
| 300 | +{ | |
| 301 | + char buf[QMP_MSG_LEN] = {}; | |
| 302 | + | |
| 303 | + snprintf(buf, sizeof(buf), | |
| 304 | + "{class: image, res: load_state, name: %s, val: %s}", | |
| 305 | + res->pd.name, enable ? "on" : "off"); | |
| 306 | + return qmp_send(res->qmp, buf, sizeof(buf)); | |
| 307 | +} | |
| 308 | + | |
| 309 | +static int qmp_pd_power_on(struct generic_pm_domain *domain) | |
| 310 | +{ | |
| 311 | + return qmp_pd_power_toggle(to_qmp_pd_resource(domain), true); | |
| 312 | +} | |
| 313 | + | |
| 314 | +static int qmp_pd_power_off(struct generic_pm_domain *domain) | |
| 315 | +{ | |
| 316 | + return qmp_pd_power_toggle(to_qmp_pd_resource(domain), false); | |
| 317 | +} | |
| 318 | + | |
| 319 | +static const char * const sdm845_resources[] = { | |
| 320 | + [AOSS_QMP_LS_CDSP] = "cdsp", | |
| 321 | + [AOSS_QMP_LS_LPASS] = "adsp", | |
| 322 | + [AOSS_QMP_LS_MODEM] = "modem", | |
| 323 | + [AOSS_QMP_LS_SLPI] = "slpi", | |
| 324 | + [AOSS_QMP_LS_SPSS] = "spss", | |
| 325 | + [AOSS_QMP_LS_VENUS] = "venus", | |
| 326 | +}; | |
| 327 | + | |
| 328 | +static int qmp_pd_add(struct qmp *qmp) | |
| 329 | +{ | |
| 330 | + struct genpd_onecell_data *data = &qmp->pd_data; | |
| 331 | + struct device *dev = qmp->dev; | |
| 332 | + struct qmp_pd *res; | |
| 333 | + size_t num = ARRAY_SIZE(sdm845_resources); | |
| 334 | + int ret; | |
| 335 | + int i; | |
| 336 | + | |
| 337 | + res = devm_kcalloc(dev, num, sizeof(*res), GFP_KERNEL); | |
| 338 | + if (!res) | |
| 339 | + return -ENOMEM; | |
| 340 | + | |
| 341 | + data->domains = devm_kcalloc(dev, num, sizeof(*data->domains), | |
| 342 | + GFP_KERNEL); | |
| 343 | + if (!data->domains) | |
| 344 | + return -ENOMEM; | |
| 345 | + | |
| 346 | + for (i = 0; i < num; i++) { | |
| 347 | + res[i].qmp = qmp; | |
| 348 | + res[i].pd.name = sdm845_resources[i]; | |
| 349 | + res[i].pd.power_on = qmp_pd_power_on; | |
| 350 | + res[i].pd.power_off = qmp_pd_power_off; | |
| 351 | + | |
| 352 | + ret = pm_genpd_init(&res[i].pd, NULL, true); | |
| 353 | + if (ret < 0) { | |
| 354 | + dev_err(dev, "failed to init genpd\n"); | |
| 355 | + goto unroll_genpds; | |
| 356 | + } | |
| 357 | + | |
| 358 | + data->domains[i] = &res[i].pd; | |
| 359 | + } | |
| 360 | + | |
| 361 | + data->num_domains = i; | |
| 362 | + | |
| 363 | + ret = of_genpd_add_provider_onecell(dev->of_node, data); | |
| 364 | + if (ret < 0) | |
| 365 | + goto unroll_genpds; | |
| 366 | + | |
| 367 | + return 0; | |
| 368 | + | |
| 369 | +unroll_genpds: | |
| 370 | + for (i--; i >= 0; i--) | |
| 371 | + pm_genpd_remove(data->domains[i]); | |
| 372 | + | |
| 373 | + return ret; | |
| 374 | +} | |
| 375 | + | |
| 376 | +static void qmp_pd_remove(struct qmp *qmp) | |
| 377 | +{ | |
| 378 | + struct genpd_onecell_data *data = &qmp->pd_data; | |
| 379 | + struct device *dev = qmp->dev; | |
| 380 | + int i; | |
| 381 | + | |
| 382 | + of_genpd_del_provider(dev->of_node); | |
| 383 | + | |
| 384 | + for (i = 0; i < data->num_domains; i++) | |
| 385 | + pm_genpd_remove(data->domains[i]); | |
| 386 | +} | |
| 387 | + | |
| 388 | +static int qmp_probe(struct platform_device *pdev) | |
| 389 | +{ | |
| 390 | + struct resource *res; | |
| 391 | + struct qmp *qmp; | |
| 392 | + int irq; | |
| 393 | + int ret; | |
| 394 | + | |
| 395 | + qmp = devm_kzalloc(&pdev->dev, sizeof(*qmp), GFP_KERNEL); | |
| 396 | + if (!qmp) | |
| 397 | + return -ENOMEM; | |
| 398 | + | |
| 399 | + qmp->dev = &pdev->dev; | |
| 400 | + init_waitqueue_head(&qmp->event); | |
| 401 | + mutex_init(&qmp->tx_lock); | |
| 402 | + | |
| 403 | + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
| 404 | + qmp->msgram = devm_ioremap_resource(&pdev->dev, res); | |
| 405 | + if (IS_ERR(qmp->msgram)) | |
| 406 | + return PTR_ERR(qmp->msgram); | |
| 407 | + | |
| 408 | + qmp->mbox_client.dev = &pdev->dev; | |
| 409 | + qmp->mbox_client.knows_txdone = true; | |
| 410 | + qmp->mbox_chan = mbox_request_channel(&qmp->mbox_client, 0); | |
| 411 | + if (IS_ERR(qmp->mbox_chan)) { | |
| 412 | + dev_err(&pdev->dev, "failed to acquire ipc mailbox\n"); | |
| 413 | + return PTR_ERR(qmp->mbox_chan); | |
| 414 | + } | |
| 415 | + | |
| 416 | + irq = platform_get_irq(pdev, 0); | |
| 417 | + ret = devm_request_irq(&pdev->dev, irq, qmp_intr, IRQF_ONESHOT, | |
| 418 | + "aoss-qmp", qmp); | |
| 419 | + if (ret < 0) { | |
| 420 | + dev_err(&pdev->dev, "failed to request interrupt\n"); | |
| 421 | + goto err_free_mbox; | |
| 422 | + } | |
| 423 | + | |
| 424 | + ret = qmp_open(qmp); | |
| 425 | + if (ret < 0) | |
| 426 | + goto err_free_mbox; | |
| 427 | + | |
| 428 | + ret = qmp_qdss_clk_add(qmp); | |
| 429 | + if (ret) | |
| 430 | + goto err_close_qmp; | |
| 431 | + | |
| 432 | + ret = qmp_pd_add(qmp); | |
| 433 | + if (ret) | |
| 434 | + goto err_remove_qdss_clk; | |
| 435 | + | |
| 436 | + platform_set_drvdata(pdev, qmp); | |
| 437 | + | |
| 438 | + return 0; | |
| 439 | + | |
| 440 | +err_remove_qdss_clk: | |
| 441 | + qmp_qdss_clk_remove(qmp); | |
| 442 | +err_close_qmp: | |
| 443 | + qmp_close(qmp); | |
| 444 | +err_free_mbox: | |
| 445 | + mbox_free_channel(qmp->mbox_chan); | |
| 446 | + | |
| 447 | + return ret; | |
| 448 | +} | |
| 449 | + | |
| 450 | +static int qmp_remove(struct platform_device *pdev) | |
| 451 | +{ | |
| 452 | + struct qmp *qmp = platform_get_drvdata(pdev); | |
| 453 | + | |
| 454 | + qmp_qdss_clk_remove(qmp); | |
| 455 | + qmp_pd_remove(qmp); | |
| 456 | + | |
| 457 | + qmp_close(qmp); | |
| 458 | + mbox_free_channel(qmp->mbox_chan); | |
| 459 | + | |
| 460 | + return 0; | |
| 461 | +} | |
| 462 | + | |
| 463 | +static const struct of_device_id qmp_dt_match[] = { | |
| 464 | + { .compatible = "qcom,sdm845-aoss-qmp", }, | |
| 465 | + {} | |
| 466 | +}; | |
| 467 | +MODULE_DEVICE_TABLE(of, qmp_dt_match); | |
| 468 | + | |
| 469 | +static struct platform_driver qmp_driver = { | |
| 470 | + .driver = { | |
| 471 | + .name = "qcom_aoss_qmp", | |
| 472 | + .of_match_table = qmp_dt_match, | |
| 473 | + }, | |
| 474 | + .probe = qmp_probe, | |
| 475 | + .remove = qmp_remove, | |
| 476 | +}; | |
| 477 | +module_platform_driver(qmp_driver); | |
| 478 | + | |
| 479 | +MODULE_DESCRIPTION("Qualcomm AOSS QMP driver"); | |
| 480 | +MODULE_LICENSE("GPL v2"); | |
| @@ -16,56 +16,76 @@ · 15 unmodified lines | ||
| 16 | 16 | |
| 17 | 17 | #define domain_to_rpmpd(domain) container_of(domain, struct rpmpd, pd) |
| 18 | 18 | |
| 19 | −/* Resource types */ | |
| 19 | +/* Resource types: | |
| 20 | + * RPMPD_X is X encoded as a little-endian, lower-case, ASCII string */ | |
| 20 | 21 | #define RPMPD_SMPA 0x61706d73 |
| 21 | 22 | #define RPMPD_LDOA 0x616f646c |
| 23 | +#define RPMPD_RWCX 0x78637772 | |
| 24 | +#define RPMPD_RWMX 0x786d7772 | |
| 25 | +#define RPMPD_RWLC 0x636c7772 | |
| 26 | +#define RPMPD_RWLM 0x6d6c7772 | |
| 27 | +#define RPMPD_RWSC 0x63737772 | |
| 28 | +#define RPMPD_RWSM 0x6d737772 | |
| 22 | 29 | |
| 23 | 30 | /* Operation Keys */ |
| 24 | 31 | #define KEY_CORNER 0x6e726f63 /* corn */ |
| 25 | 32 | #define KEY_ENABLE 0x6e657773 /* swen */ |
| 26 | 33 | #define KEY_FLOOR_CORNER 0x636676 /* vfc */ |
| 34 | +#define KEY_FLOOR_LEVEL 0x6c6676 /* vfl */ | |
| 35 | +#define KEY_LEVEL 0x6c766c76 /* vlvl */ | |
| 27 | 36 | |
| 28 | −#define MAX_RPMPD_STATE 6 | |
| 37 | +#define MAX_8996_RPMPD_STATE 6 | |
| 29 | 38 | |
| 30 | −#define DEFINE_RPMPD_CORNER_SMPA(_platform, _name, _active, r_id) \ | |
| 39 | +#define DEFINE_RPMPD_PAIR(_platform, _name, _active, r_type, r_key, \ | |
| 40 | + r_id) \ | |
| 31 | 41 | static struct rpmpd _platform##_##_active; \ |
| 32 | 42 | static struct rpmpd _platform##_##_name = { \ |
| 33 | 43 | .pd = { .name = #_name, }, \ |
| 34 | 44 | .peer = &_platform##_##_active, \ |
| 35 | − .res_type = RPMPD_SMPA, \ | |
| 45 | + .res_type = RPMPD_##r_type, \ | |
| 36 | 46 | .res_id = r_id, \ |
| 37 | − .key = KEY_CORNER, \ | |
| 47 | + .key = KEY_##r_key, \ | |
| 38 | 48 | }; \ |
| 39 | 49 | static struct rpmpd _platform##_##_active = { \ |
| 40 | 50 | .pd = { .name = #_active, }, \ |
| 41 | 51 | .peer = &_platform##_##_name, \ |
| 42 | 52 | .active_only = true, \ |
| 43 | − .res_type = RPMPD_SMPA, \ | |
| 53 | + .res_type = RPMPD_##r_type, \ | |
| 44 | 54 | .res_id = r_id, \ |
| 45 | − .key = KEY_CORNER, \ | |
| 55 | + .key = KEY_##r_key, \ | |
| 46 | 56 | } |
| 47 | 57 | |
| 48 | −#define DEFINE_RPMPD_CORNER_LDOA(_platform, _name, r_id) \ | |
| 58 | +#define DEFINE_RPMPD_CORNER(_platform, _name, r_type, r_id) \ | |
| 49 | 59 | static struct rpmpd _platform##_##_name = { \ |
| 50 | 60 | .pd = { .name = #_name, }, \ |
| 51 | − .res_type = RPMPD_LDOA, \ | |
| 61 | + .res_type = RPMPD_##r_type, \ | |
| 52 | 62 | .res_id = r_id, \ |
| 53 | 63 | .key = KEY_CORNER, \ |
| 54 | 64 | } |
| 55 | 65 | |
| 56 | −#define DEFINE_RPMPD_VFC(_platform, _name, r_id, r_type) \ | |
| 66 | +#define DEFINE_RPMPD_LEVEL(_platform, _name, r_type, r_id) \ | |
| 57 | 67 | static struct rpmpd _platform##_##_name = { \ |
| 58 | 68 | .pd = { .name = #_name, }, \ |
| 59 | − .res_type = r_type, \ | |
| 69 | + .res_type = RPMPD_##r_type, \ | |
| 60 | 70 | .res_id = r_id, \ |
| 61 | − .key = KEY_FLOOR_CORNER, \ | |
| 71 | + .key = KEY_LEVEL, \ | |
| 62 | 72 | } |
| 63 | 73 | |
| 64 | −#define DEFINE_RPMPD_VFC_SMPA(_platform, _name, r_id) \ | |
| 65 | − DEFINE_RPMPD_VFC(_platform, _name, r_id, RPMPD_SMPA) | |
| 74 | +#define DEFINE_RPMPD_VFC(_platform, _name, r_type, r_id) \ | |
| 75 | + static struct rpmpd _platform##_##_name = { \ | |
| 76 | + .pd = { .name = #_name, }, \ | |
| 77 | + .res_type = RPMPD_##r_type, \ | |
| 78 | + .res_id = r_id, \ | |
| 79 | + .key = KEY_FLOOR_CORNER, \ | |
| 80 | + } | |
| 66 | 81 | |
| 67 | −#define DEFINE_RPMPD_VFC_LDOA(_platform, _name, r_id) \ | |
| 68 | − DEFINE_RPMPD_VFC(_platform, _name, r_id, RPMPD_LDOA) | |
| 82 | +#define DEFINE_RPMPD_VFL(_platform, _name, r_type, r_id) \ | |
| 83 | + static struct rpmpd _platform##_##_name = { \ | |
| 84 | + .pd = { .name = #_name, }, \ | |
| 85 | + .res_type = RPMPD_##r_type, \ | |
| 86 | + .res_id = r_id, \ | |
| 87 | + .key = KEY_FLOOR_LEVEL, \ | |
| 88 | + } | |
| 69 | 89 | |
| 70 | 90 | struct rpmpd_req { |
| 71 | 91 | __le32 key; |
| @@ -83,23 +103,25 @@ struct rpmpd { · 11 unmodified lines | ||
| 83 | 103 | const int res_type; |
| 84 | 104 | const int res_id; |
| 85 | 105 | struct qcom_smd_rpm *rpm; |
| 106 | + unsigned int max_state; | |
| 86 | 107 | __le32 key; |
| 87 | 108 | }; |
| 88 | 109 | |
| 89 | 110 | struct rpmpd_desc { |
| 90 | 111 | struct rpmpd **rpmpds; |
| 91 | 112 | size_t num_pds; |
| 113 | + unsigned int max_state; | |
| 92 | 114 | }; |
| 93 | 115 | |
| 94 | 116 | static DEFINE_MUTEX(rpmpd_lock); |
| 95 | 117 | |
| 96 | 118 | /* msm8996 RPM Power domains */ |
| 97 | −DEFINE_RPMPD_CORNER_SMPA(msm8996, vddcx, vddcx_ao, 1); | |
| 98 | −DEFINE_RPMPD_CORNER_SMPA(msm8996, vddmx, vddmx_ao, 2); | |
| 99 | −DEFINE_RPMPD_CORNER_LDOA(msm8996, vddsscx, 26); | |
| 119 | +DEFINE_RPMPD_PAIR(msm8996, vddcx, vddcx_ao, SMPA, CORNER, 1); | |
| 120 | +DEFINE_RPMPD_PAIR(msm8996, vddmx, vddmx_ao, SMPA, CORNER, 2); | |
| 121 | +DEFINE_RPMPD_CORNER(msm8996, vddsscx, LDOA, 26); | |
| 100 | 122 | |
| 101 | −DEFINE_RPMPD_VFC_SMPA(msm8996, vddcx_vfc, 1); | |
| 102 | −DEFINE_RPMPD_VFC_LDOA(msm8996, vddsscx_vfc, 26); | |
| 123 | +DEFINE_RPMPD_VFC(msm8996, vddcx_vfc, SMPA, 1); | |
| 124 | +DEFINE_RPMPD_VFC(msm8996, vddsscx_vfc, LDOA, 26); | |
| 103 | 125 | |
| 104 | 126 | static struct rpmpd *msm8996_rpmpds[] = { |
| 105 | 127 | [MSM8996_VDDCX] = &msm8996_vddcx, |
| @@ -114,10 +136,71 @@ static struct rpmpd *msm8996_rpmpds[] = { · 8 unmodified lines | ||
| 114 | 136 | static const struct rpmpd_desc msm8996_desc = { |
| 115 | 137 | .rpmpds = msm8996_rpmpds, |
| 116 | 138 | .num_pds = ARRAY_SIZE(msm8996_rpmpds), |
| 139 | + .max_state = MAX_8996_RPMPD_STATE, | |
| 140 | +}; | |
| 141 | + | |
| 142 | +/* msm8998 RPM Power domains */ | |
| 143 | +DEFINE_RPMPD_PAIR(msm8998, vddcx, vddcx_ao, RWCX, LEVEL, 0); | |
| 144 | +DEFINE_RPMPD_VFL(msm8998, vddcx_vfl, RWCX, 0); | |
| 145 | + | |
| 146 | +DEFINE_RPMPD_PAIR(msm8998, vddmx, vddmx_ao, RWMX, LEVEL, 0); | |
| 147 | +DEFINE_RPMPD_VFL(msm8998, vddmx_vfl, RWMX, 0); | |
| 148 | + | |
| 149 | +DEFINE_RPMPD_LEVEL(msm8998, vdd_ssccx, RWSC, 0); | |
| 150 | +DEFINE_RPMPD_VFL(msm8998, vdd_ssccx_vfl, RWSC, 0); | |
| 151 | + | |
| 152 | +DEFINE_RPMPD_LEVEL(msm8998, vdd_sscmx, RWSM, 0); | |
| 153 | +DEFINE_RPMPD_VFL(msm8998, vdd_sscmx_vfl, RWSM, 0); | |
| 154 | + | |
| 155 | +static struct rpmpd *msm8998_rpmpds[] = { | |
| 156 | + [MSM8998_VDDCX] = &msm8998_vddcx, | |
| 157 | + [MSM8998_VDDCX_AO] = &msm8998_vddcx_ao, | |
| 158 | + [MSM8998_VDDCX_VFL] = &msm8998_vddcx_vfl, | |
| 159 | + [MSM8998_VDDMX] = &msm8998_vddmx, | |
| 160 | + [MSM8998_VDDMX_AO] = &msm8998_vddmx_ao, | |
| 161 | + [MSM8998_VDDMX_VFL] = &msm8998_vddmx_vfl, | |
| 162 | + [MSM8998_SSCCX] = &msm8998_vdd_ssccx, | |
| 163 | + [MSM8998_SSCCX_VFL] = &msm8998_vdd_ssccx_vfl, | |
| 164 | + [MSM8998_SSCMX] = &msm8998_vdd_sscmx, | |
| 165 | + [MSM8998_SSCMX_VFL] = &msm8998_vdd_sscmx_vfl, | |
| 166 | +}; | |
| 167 | + | |
| 168 | +static const struct rpmpd_desc msm8998_desc = { | |
| 169 | + .rpmpds = msm8998_rpmpds, | |
| 170 | + .num_pds = ARRAY_SIZE(msm8998_rpmpds), | |
| 171 | + .max_state = RPM_SMD_LEVEL_BINNING, | |
| 172 | +}; | |
| 173 | + | |
| 174 | +/* qcs404 RPM Power domains */ | |
| 175 | +DEFINE_RPMPD_PAIR(qcs404, vddmx, vddmx_ao, RWMX, LEVEL, 0); | |
| 176 | +DEFINE_RPMPD_VFL(qcs404, vddmx_vfl, RWMX, 0); | |
| 177 | + | |
| 178 | +DEFINE_RPMPD_LEVEL(qcs404, vdd_lpicx, RWLC, 0); | |
| 179 | +DEFINE_RPMPD_VFL(qcs404, vdd_lpicx_vfl, RWLC, 0); | |
| 180 | + | |
| 181 | +DEFINE_RPMPD_LEVEL(qcs404, vdd_lpimx, RWLM, 0); | |
| 182 | +DEFINE_RPMPD_VFL(qcs404, vdd_lpimx_vfl, RWLM, 0); | |
| 183 | + | |
| 184 | +static struct rpmpd *qcs404_rpmpds[] = { | |
| 185 | + [QCS404_VDDMX] = &qcs404_vddmx, | |
| 186 | + [QCS404_VDDMX_AO] = &qcs404_vddmx_ao, | |
| 187 | + [QCS404_VDDMX_VFL] = &qcs404_vddmx_vfl, | |
| 188 | + [QCS404_LPICX] = &qcs404_vdd_lpicx, | |
| 189 | + [QCS404_LPICX_VFL] = &qcs404_vdd_lpicx_vfl, | |
| 190 | + [QCS404_LPIMX] = &qcs404_vdd_lpimx, | |
| 191 | + [QCS404_LPIMX_VFL] = &qcs404_vdd_lpimx_vfl, | |
| 192 | +}; | |
| 193 | + | |
| 194 | +static const struct rpmpd_desc qcs404_desc = { | |
| 195 | + .rpmpds = qcs404_rpmpds, | |
| 196 | + .num_pds = ARRAY_SIZE(qcs404_rpmpds), | |
| 197 | + .max_state = RPM_SMD_LEVEL_BINNING, | |
| 117 | 198 | }; |
| 118 | 199 | |
| 119 | 200 | static const struct of_device_id rpmpd_match_table[] = { |
| 120 | 201 | { .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc }, |
| 202 | + { .compatible = "qcom,msm8998-rpmpd", .data = &msm8998_desc }, | |
| 203 | + { .compatible = "qcom,qcs404-rpmpd", .data = &qcs404_desc }, | |
| 121 | 204 | { } |
| 122 | 205 | }; |
| 123 | 206 | |
| @@ -225,14 +308,16 @@ static int rpmpd_set_performance(struct generic_pm_domain *domain, · 101 unmodified lines | ||
| 225 | 308 | int ret = 0; |
| 226 | 309 | struct rpmpd *pd = domain_to_rpmpd(domain); |
| 227 | 310 | |
| 228 | − if (state > MAX_RPMPD_STATE) | |
| 229 | − goto out; | |
| 311 | + if (state > pd->max_state) | |
| 312 | + state = pd->max_state; | |
| 230 | 313 | |
| 231 | 314 | mutex_lock(&rpmpd_lock); |
| 232 | 315 | |
| 233 | 316 | pd->corner = state; |
| 234 | 317 | |
| 235 | − if (!pd->enabled && pd->key != KEY_FLOOR_CORNER) | |
| 318 | + /* Always send updates for vfc and vfl */ | |
| 319 | + if (!pd->enabled && pd->key != KEY_FLOOR_CORNER && | |
| 320 | + pd->key != KEY_FLOOR_LEVEL) | |
| 236 | 321 | goto out; |
| 237 | 322 | |
| 238 | 323 | ret = rpmpd_aggregate_corner(pd); |
| @@ -287,6 +372,7 @@ static int rpmpd_probe(struct platform_device *pdev) · 48 unmodified lines | ||
| 287 | 372 | } |
| 288 | 373 | |
| 289 | 374 | rpmpds[i]->rpm = rpm; |
| 375 | + rpmpds[i]->max_state = desc->max_state; | |
| 290 | 376 | rpmpds[i]->pd.power_off = rpmpd_power_off; |
| 291 | 377 | rpmpds[i]->pd.power_on = rpmpd_power_on; |
| 292 | 378 | rpmpds[i]->pd.set_performance_state = rpmpd_set_performance; |
| @@ -86,47 +86,47 @@ struct rockchip_pmu { · 85 unmodified lines | ||
| 86 | 86 | #define to_rockchip_pd(gpd) container_of(gpd, struct rockchip_pm_domain, genpd) |
| 87 | 87 | |
| 88 | 88 | #define DOMAIN(pwr, status, req, idle, ack, wakeup) \ |
| 89 | −{ \ | |
| 90 | − .pwr_mask = (pwr >= 0) ? BIT(pwr) : 0, \ | |
| 91 | − .status_mask = (status >= 0) ? BIT(status) : 0, \ | |
| 92 | − .req_mask = (req >= 0) ? BIT(req) : 0, \ | |
| 93 | − .idle_mask = (idle >= 0) ? BIT(idle) : 0, \ | |
| 94 | − .ack_mask = (ack >= 0) ? BIT(ack) : 0, \ | |
| 95 | − .active_wakeup = wakeup, \ | |
| 89 | +{ \ | |
| 90 | + .pwr_mask = (pwr), \ | |
| 91 | + .status_mask = (status), \ | |
| 92 | + .req_mask = (req), \ | |
| 93 | + .idle_mask = (idle), \ | |
| 94 | + .ack_mask = (ack), \ | |
| 95 | + .active_wakeup = (wakeup), \ | |
| 96 | 96 | } |
| 97 | 97 | |
| 98 | 98 | #define DOMAIN_M(pwr, status, req, idle, ack, wakeup) \ |
| 99 | 99 | { \ |
| 100 | − .pwr_w_mask = (pwr >= 0) ? BIT(pwr + 16) : 0, \ | |
| 101 | − .pwr_mask = (pwr >= 0) ? BIT(pwr) : 0, \ | |
| 102 | − .status_mask = (status >= 0) ? BIT(status) : 0, \ | |
| 103 | − .req_w_mask = (req >= 0) ? BIT(req + 16) : 0, \ | |
| 104 | − .req_mask = (req >= 0) ? BIT(req) : 0, \ | |
| 105 | − .idle_mask = (idle >= 0) ? BIT(idle) : 0, \ | |
| 106 | − .ack_mask = (ack >= 0) ? BIT(ack) : 0, \ | |
| 100 | + .pwr_w_mask = (pwr) << 16, \ | |
| 101 | + .pwr_mask = (pwr), \ | |
| 102 | + .status_mask = (status), \ | |
| 103 | + .req_w_mask = (req) << 16, \ | |
| 104 | + .req_mask = (req), \ | |
| 105 | + .idle_mask = (idle), \ | |
| 106 | + .ack_mask = (ack), \ | |
| 107 | 107 | .active_wakeup = wakeup, \ |
| 108 | 108 | } |
| 109 | 109 | |
| 110 | 110 | #define DOMAIN_RK3036(req, ack, idle, wakeup) \ |
| 111 | 111 | { \ |
| 112 | − .req_mask = (req >= 0) ? BIT(req) : 0, \ | |
| 113 | − .req_w_mask = (req >= 0) ? BIT(req + 16) : 0, \ | |
| 114 | − .ack_mask = (ack >= 0) ? BIT(ack) : 0, \ | |
| 115 | − .idle_mask = (idle >= 0) ? BIT(idle) : 0, \ | |
| 112 | + .req_mask = (req), \ | |
| 113 | + .req_w_mask = (req) << 16, \ | |
| 114 | + .ack_mask = (ack), \ | |
| 115 | + .idle_mask = (idle), \ | |
| 116 | 116 | .active_wakeup = wakeup, \ |
| 117 | 117 | } |
| 118 | 118 | |
| 119 | 119 | #define DOMAIN_PX30(pwr, status, req, wakeup) \ |
| 120 | − DOMAIN_M(pwr, status, req, (req) + 16, req, wakeup) | |
| 120 | + DOMAIN_M(pwr, status, req, (req) << 16, req, wakeup) | |
| 121 | 121 | |
| 122 | 122 | #define DOMAIN_RK3288(pwr, status, req, wakeup) \ |
| 123 | − DOMAIN(pwr, status, req, req, (req) + 16, wakeup) | |
| 123 | + DOMAIN(pwr, status, req, req, (req) << 16, wakeup) | |
| 124 | 124 | |
| 125 | 125 | #define DOMAIN_RK3328(pwr, status, req, wakeup) \ |
| 126 | − DOMAIN_M(pwr, pwr, req, (req) + 10, req, wakeup) | |
| 126 | + DOMAIN_M(pwr, pwr, req, (req) << 10, req, wakeup) | |
| 127 | 127 | |
| 128 | 128 | #define DOMAIN_RK3368(pwr, status, req, wakeup) \ |
| 129 | − DOMAIN(pwr, status, req, (req) + 16, req, wakeup) | |
| 129 | + DOMAIN(pwr, status, req, (req) << 16, req, wakeup) | |
| 130 | 130 | |
| 131 | 131 | #define DOMAIN_RK3399(pwr, status, req, wakeup) \ |
| 132 | 132 | DOMAIN(pwr, status, req, req, req, wakeup) |
| @@ -716,129 +716,129 @@ err_out: · 583 unmodified lines | ||
| 716 | 716 | } |
| 717 | 717 | |
| 718 | 718 | static const struct rockchip_domain_info px30_pm_domains[] = { |
| 719 | − [PX30_PD_USB] = DOMAIN_PX30(5, 5, 10, false), | |
| 720 | − [PX30_PD_SDCARD] = DOMAIN_PX30(8, 8, 9, false), | |
| 721 | − [PX30_PD_GMAC] = DOMAIN_PX30(10, 10, 6, false), | |
| 722 | − [PX30_PD_MMC_NAND] = DOMAIN_PX30(11, 11, 5, false), | |
| 723 | − [PX30_PD_VPU] = DOMAIN_PX30(12, 12, 14, false), | |
| 724 | − [PX30_PD_VO] = DOMAIN_PX30(13, 13, 7, false), | |
| 725 | − [PX30_PD_VI] = DOMAIN_PX30(14, 14, 8, false), | |
| 726 | − [PX30_PD_GPU] = DOMAIN_PX30(15, 15, 2, false), | |
| 719 | + [PX30_PD_USB] = DOMAIN_PX30(BIT(5), BIT(5), BIT(10), false), | |
| 720 | + [PX30_PD_SDCARD] = DOMAIN_PX30(BIT(8), BIT(8), BIT(9), false), | |
| 721 | + [PX30_PD_GMAC] = DOMAIN_PX30(BIT(10), BIT(10), BIT(6), false), | |
| 722 | + [PX30_PD_MMC_NAND] = DOMAIN_PX30(BIT(11), BIT(11), BIT(5), false), | |
| 723 | + [PX30_PD_VPU] = DOMAIN_PX30(BIT(12), BIT(12), BIT(14), false), | |
| 724 | + [PX30_PD_VO] = DOMAIN_PX30(BIT(13), BIT(13), BIT(7), false), | |
| 725 | + [PX30_PD_VI] = DOMAIN_PX30(BIT(14), BIT(14), BIT(8), false), | |
| 726 | + [PX30_PD_GPU] = DOMAIN_PX30(BIT(15), BIT(15), BIT(2), false), | |
| 727 | 727 | }; |
| 728 | 728 | |
| 729 | 729 | static const struct rockchip_domain_info rk3036_pm_domains[] = { |
| 730 | − [RK3036_PD_MSCH] = DOMAIN_RK3036(14, 23, 30, true), | |
| 731 | − [RK3036_PD_CORE] = DOMAIN_RK3036(13, 17, 24, false), | |
| 732 | − [RK3036_PD_PERI] = DOMAIN_RK3036(12, 18, 25, false), | |
| 733 | − [RK3036_PD_VIO] = DOMAIN_RK3036(11, 19, 26, false), | |
| 734 | − [RK3036_PD_VPU] = DOMAIN_RK3036(10, 20, 27, false), | |
| 735 | − [RK3036_PD_GPU] = DOMAIN_RK3036(9, 21, 28, false), | |
| 736 | − [RK3036_PD_SYS] = DOMAIN_RK3036(8, 22, 29, false), | |
| 730 | + [RK3036_PD_MSCH] = DOMAIN_RK3036(BIT(14), BIT(23), BIT(30), true), | |
| 731 | + [RK3036_PD_CORE] = DOMAIN_RK3036(BIT(13), BIT(17), BIT(24), false), | |
| 732 | + [RK3036_PD_PERI] = DOMAIN_RK3036(BIT(12), BIT(18), BIT(25), false), | |
| 733 | + [RK3036_PD_VIO] = DOMAIN_RK3036(BIT(11), BIT(19), BIT(26), false), | |
| 734 | + [RK3036_PD_VPU] = DOMAIN_RK3036(BIT(10), BIT(20), BIT(27), false), | |
| 735 | + [RK3036_PD_GPU] = DOMAIN_RK3036(BIT(9), BIT(21), BIT(28), false), | |
| 736 | + [RK3036_PD_SYS] = DOMAIN_RK3036(BIT(8), BIT(22), BIT(29), false), | |
| 737 | 737 | }; |
| 738 | 738 | |
| 739 | 739 | static const struct rockchip_domain_info rk3066_pm_domains[] = { |
| 740 | − [RK3066_PD_GPU] = DOMAIN(9, 9, 3, 24, 29, false), | |
| 741 | − [RK3066_PD_VIDEO] = DOMAIN(8, 8, 4, 23, 28, false), | |
| 742 | − [RK3066_PD_VIO] = DOMAIN(7, 7, 5, 22, 27, false), | |
| 743 | − [RK3066_PD_PERI] = DOMAIN(6, 6, 2, 25, 30, false), | |
| 744 | − [RK3066_PD_CPU] = DOMAIN(-1, 5, 1, 26, 31, false), | |
| 740 | + [RK3066_PD_GPU] = DOMAIN(BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false), | |
| 741 | + [RK3066_PD_VIDEO] = DOMAIN(BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false), | |
| 742 | + [RK3066_PD_VIO] = DOMAIN(BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false), | |
| 743 | + [RK3066_PD_PERI] = DOMAIN(BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false), | |
| 744 | + [RK3066_PD_CPU] = DOMAIN(0, BIT(5), BIT(1), BIT(26), BIT(31), false), | |
| 745 | 745 | }; |
| 746 | 746 | |
| 747 | 747 | static const struct rockchip_domain_info rk3128_pm_domains[] = { |
| 748 | − [RK3128_PD_CORE] = DOMAIN_RK3288(0, 0, 4, false), | |
| 749 | − [RK3128_PD_MSCH] = DOMAIN_RK3288(-1, -1, 6, true), | |
| 750 | − [RK3128_PD_VIO] = DOMAIN_RK3288(3, 3, 2, false), | |
| 751 | − [RK3128_PD_VIDEO] = DOMAIN_RK3288(2, 2, 1, false), | |
| 752 | − [RK3128_PD_GPU] = DOMAIN_RK3288(1, 1, 3, false), | |
| 748 | + [RK3128_PD_CORE] = DOMAIN_RK3288(BIT(0), BIT(0), BIT(4), false), | |
| 749 | + [RK3128_PD_MSCH] = DOMAIN_RK3288(0, 0, BIT(6), true), | |
| 750 | + [RK3128_PD_VIO] = DOMAIN_RK3288(BIT(3), BIT(3), BIT(2), false), | |
| 751 | + [RK3128_PD_VIDEO] = DOMAIN_RK3288(BIT(2), BIT(2), BIT(1), false), | |
| 752 | + [RK3128_PD_GPU] = DOMAIN_RK3288(BIT(1), BIT(1), BIT(3), false), | |
| 753 | 753 | }; |
| 754 | 754 | |
| 755 | 755 | static const struct rockchip_domain_info rk3188_pm_domains[] = { |
| 756 | − [RK3188_PD_GPU] = DOMAIN(9, 9, 3, 24, 29, false), | |
| 757 | − [RK3188_PD_VIDEO] = DOMAIN(8, 8, 4, 23, 28, false), | |
| 758 | − [RK3188_PD_VIO] = DOMAIN(7, 7, 5, 22, 27, false), | |
| 759 | − [RK3188_PD_PERI] = DOMAIN(6, 6, 2, 25, 30, false), | |
| 760 | − [RK3188_PD_CPU] = DOMAIN(5, 5, 1, 26, 31, false), | |
| 756 | + [RK3188_PD_GPU] = DOMAIN(BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false), | |
| 757 | + [RK3188_PD_VIDEO] = DOMAIN(BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false), | |
| 758 | + [RK3188_PD_VIO] = DOMAIN(BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false), | |
| 759 | + [RK3188_PD_PERI] = DOMAIN(BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false), | |
| 760 | + [RK3188_PD_CPU] = DOMAIN(BIT(5), BIT(5), BIT(1), BIT(26), BIT(31), false), | |
| 761 | 761 | }; |
| 762 | 762 | |
| 763 | 763 | static const struct rockchip_domain_info rk3228_pm_domains[] = { |
| 764 | − [RK3228_PD_CORE] = DOMAIN_RK3036(0, 0, 16, true), | |
| 765 | − [RK3228_PD_MSCH] = DOMAIN_RK3036(1, 1, 17, true), | |
| 766 | − [RK3228_PD_BUS] = DOMAIN_RK3036(2, 2, 18, true), | |
| 767 | − [RK3228_PD_SYS] = DOMAIN_RK3036(3, 3, 19, true), | |
| 768 | − [RK3228_PD_VIO] = DOMAIN_RK3036(4, 4, 20, false), | |
| 769 | − [RK3228_PD_VOP] = DOMAIN_RK3036(5, 5, 21, false), | |
| 770 | − [RK3228_PD_VPU] = DOMAIN_RK3036(6, 6, 22, false), | |
| 771 | − [RK3228_PD_RKVDEC] = DOMAIN_RK3036(7, 7, 23, false), | |
| 772 | − [RK3228_PD_GPU] = DOMAIN_RK3036(8, 8, 24, false), | |
| 773 | − [RK3228_PD_PERI] = DOMAIN_RK3036(9, 9, 25, true), | |
| 774 | − [RK3228_PD_GMAC] = DOMAIN_RK3036(10, 10, 26, false), | |
| 764 | + [RK3228_PD_CORE] = DOMAIN_RK3036(BIT(0), BIT(0), BIT(16), true), | |
| 765 | + [RK3228_PD_MSCH] = DOMAIN_RK3036(BIT(1), BIT(1), BIT(17), true), | |
| 766 | + [RK3228_PD_BUS] = DOMAIN_RK3036(BIT(2), BIT(2), BIT(18), true), | |
| 767 | + [RK3228_PD_SYS] = DOMAIN_RK3036(BIT(3), BIT(3), BIT(19), true), | |
| 768 | + [RK3228_PD_VIO] = DOMAIN_RK3036(BIT(4), BIT(4), BIT(20), false), | |
| 769 | + [RK3228_PD_VOP] = DOMAIN_RK3036(BIT(5), BIT(5), BIT(21), false), | |
| 770 | + [RK3228_PD_VPU] = DOMAIN_RK3036(BIT(6), BIT(6), BIT(22), false), | |
| 771 | + [RK3228_PD_RKVDEC] = DOMAIN_RK3036(BIT(7), BIT(7), BIT(23), false), | |
| 772 | + [RK3228_PD_GPU] = DOMAIN_RK3036(BIT(8), BIT(8), BIT(24), false), | |
| 773 | + [RK3228_PD_PERI] = DOMAIN_RK3036(BIT(9), BIT(9), BIT(25), true), | |
| 774 | + [RK3228_PD_GMAC] = DOMAIN_RK3036(BIT(10), BIT(10), BIT(26), false), | |
| 775 | 775 | }; |
| 776 | 776 | |
| 777 | 777 | static const struct rockchip_domain_info rk3288_pm_domains[] = { |
| 778 | − [RK3288_PD_VIO] = DOMAIN_RK3288(7, 7, 4, false), | |
| 779 | − [RK3288_PD_HEVC] = DOMAIN_RK3288(14, 10, 9, false), | |
| 780 | − [RK3288_PD_VIDEO] = DOMAIN_RK3288(8, 8, 3, false), | |
| 781 | − [RK3288_PD_GPU] = DOMAIN_RK3288(9, 9, 2, false), | |
| 778 | + [RK3288_PD_VIO] = DOMAIN_RK3288(BIT(7), BIT(7), BIT(4), false), | |
| 779 | + [RK3288_PD_HEVC] = DOMAIN_RK3288(BIT(14), BIT(10), BIT(9), false), | |
| 780 | + [RK3288_PD_VIDEO] = DOMAIN_RK3288(BIT(8), BIT(8), BIT(3), false), | |
| 781 | + [RK3288_PD_GPU] = DOMAIN_RK3288(BIT(9), BIT(9), BIT(2), false), | |
| 782 | 782 | }; |
| 783 | 783 | |
| 784 | 784 | static const struct rockchip_domain_info rk3328_pm_domains[] = { |
| 785 | − [RK3328_PD_CORE] = DOMAIN_RK3328(-1, 0, 0, false), | |
| 786 | − [RK3328_PD_GPU] = DOMAIN_RK3328(-1, 1, 1, false), | |
| 787 | − [RK3328_PD_BUS] = DOMAIN_RK3328(-1, 2, 2, true), | |
| 788 | − [RK3328_PD_MSCH] = DOMAIN_RK3328(-1, 3, 3, true), | |
| 789 | − [RK3328_PD_PERI] = DOMAIN_RK3328(-1, 4, 4, true), | |
| 790 | − [RK3328_PD_VIDEO] = DOMAIN_RK3328(-1, 5, 5, false), | |
| 791 | − [RK3328_PD_HEVC] = DOMAIN_RK3328(-1, 6, 6, false), | |
| 792 | − [RK3328_PD_VIO] = DOMAIN_RK3328(-1, 8, 8, false), | |
| 793 | − [RK3328_PD_VPU] = DOMAIN_RK3328(-1, 9, 9, false), | |
| 785 | + [RK3328_PD_CORE] = DOMAIN_RK3328(0, BIT(0), BIT(0), false), | |
| 786 | + [RK3328_PD_GPU] = DOMAIN_RK3328(0, BIT(1), BIT(1), false), | |
| 787 | + [RK3328_PD_BUS] = DOMAIN_RK3328(0, BIT(2), BIT(2), true), | |
| 788 | + [RK3328_PD_MSCH] = DOMAIN_RK3328(0, BIT(3), BIT(3), true), | |
| 789 | + [RK3328_PD_PERI] = DOMAIN_RK3328(0, BIT(4), BIT(4), true), | |
| 790 | + [RK3328_PD_VIDEO] = DOMAIN_RK3328(0, BIT(5), BIT(5), false), | |
| 791 | + [RK3328_PD_HEVC] = DOMAIN_RK3328(0, BIT(6), BIT(6), false), | |
| 792 | + [RK3328_PD_VIO] = DOMAIN_RK3328(0, BIT(8), BIT(8), false), | |
| 793 | + [RK3328_PD_VPU] = DOMAIN_RK3328(0, BIT(9), BIT(9), false), | |
| 794 | 794 | }; |
| 795 | 795 | |
| 796 | 796 | static const struct rockchip_domain_info rk3366_pm_domains[] = { |
| 797 | − [RK3366_PD_PERI] = DOMAIN_RK3368(10, 10, 6, true), | |
| 798 | − [RK3366_PD_VIO] = DOMAIN_RK3368(14, 14, 8, false), | |
| 799 | − [RK3366_PD_VIDEO] = DOMAIN_RK3368(13, 13, 7, false), | |
| 800 | − [RK3366_PD_RKVDEC] = DOMAIN_RK3368(11, 11, 7, false), | |
| 801 | − [RK3366_PD_WIFIBT] = DOMAIN_RK3368(8, 8, 9, false), | |
| 802 | − [RK3366_PD_VPU] = DOMAIN_RK3368(12, 12, 7, false), | |
| 803 | − [RK3366_PD_GPU] = DOMAIN_RK3368(15, 15, 2, false), | |
| 797 | + [RK3366_PD_PERI] = DOMAIN_RK3368(BIT(10), BIT(10), BIT(6), true), | |
| 798 | + [RK3366_PD_VIO] = DOMAIN_RK3368(BIT(14), BIT(14), BIT(8), false), | |
| 799 | + [RK3366_PD_VIDEO] = DOMAIN_RK3368(BIT(13), BIT(13), BIT(7), false), | |
| 800 | + [RK3366_PD_RKVDEC] = DOMAIN_RK3368(BIT(11), BIT(11), BIT(7), false), | |
| 801 | + [RK3366_PD_WIFIBT] = DOMAIN_RK3368(BIT(8), BIT(8), BIT(9), false), | |
| 802 | + [RK3366_PD_VPU] = DOMAIN_RK3368(BIT(12), BIT(12), BIT(7), false), | |
| 803 | + [RK3366_PD_GPU] = DOMAIN_RK3368(BIT(15), BIT(15), BIT(2), false), | |
| 804 | 804 | }; |
| 805 | 805 | |
| 806 | 806 | static const struct rockchip_domain_info rk3368_pm_domains[] = { |
| 807 | − [RK3368_PD_PERI] = DOMAIN_RK3368(13, 12, 6, true), | |
| 808 | − [RK3368_PD_VIO] = DOMAIN_RK3368(15, 14, 8, false), | |
| 809 | − [RK3368_PD_VIDEO] = DOMAIN_RK3368(14, 13, 7, false), | |
| 810 | − [RK3368_PD_GPU_0] = DOMAIN_RK3368(16, 15, 2, false), | |
| 811 | − [RK3368_PD_GPU_1] = DOMAIN_RK3368(17, 16, 2, false), | |
| 807 | + [RK3368_PD_PERI] = DOMAIN_RK3368(BIT(13), BIT(12), BIT(6), true), | |
| 808 | + [RK3368_PD_VIO] = DOMAIN_RK3368(BIT(15), BIT(14), BIT(8), false), | |
| 809 | + [RK3368_PD_VIDEO] = DOMAIN_RK3368(BIT(14), BIT(13), BIT(7), false), | |
| 810 | + [RK3368_PD_GPU_0] = DOMAIN_RK3368(BIT(16), BIT(15), BIT(2), false), | |
| 811 | + [RK3368_PD_GPU_1] = DOMAIN_RK3368(BIT(17), BIT(16), BIT(2), false), | |
| 812 | 812 | }; |
| 813 | 813 | |
| 814 | 814 | static const struct rockchip_domain_info rk3399_pm_domains[] = { |
| 815 | − [RK3399_PD_TCPD0] = DOMAIN_RK3399(8, 8, -1, false), | |
| 816 | − [RK3399_PD_TCPD1] = DOMAIN_RK3399(9, 9, -1, false), | |
| 817 | − [RK3399_PD_CCI] = DOMAIN_RK3399(10, 10, -1, true), | |
| 818 | − [RK3399_PD_CCI0] = DOMAIN_RK3399(-1, -1, 15, true), | |
| 819 | − [RK3399_PD_CCI1] = DOMAIN_RK3399(-1, -1, 16, true), | |
| 820 | − [RK3399_PD_PERILP] = DOMAIN_RK3399(11, 11, 1, true), | |
| 821 | − [RK3399_PD_PERIHP] = DOMAIN_RK3399(12, 12, 2, true), | |
| 822 | − [RK3399_PD_CENTER] = DOMAIN_RK3399(13, 13, 14, true), | |
| 823 | − [RK3399_PD_VIO] = DOMAIN_RK3399(14, 14, 17, false), | |
| 824 | − [RK3399_PD_GPU] = DOMAIN_RK3399(15, 15, 0, false), | |
| 825 | − [RK3399_PD_VCODEC] = DOMAIN_RK3399(16, 16, 3, false), | |
| 826 | − [RK3399_PD_VDU] = DOMAIN_RK3399(17, 17, 4, false), | |
| 827 | − [RK3399_PD_RGA] = DOMAIN_RK3399(18, 18, 5, false), | |
| 828 | − [RK3399_PD_IEP] = DOMAIN_RK3399(19, 19, 6, false), | |
| 829 | − [RK3399_PD_VO] = DOMAIN_RK3399(20, 20, -1, false), | |
| 830 | − [RK3399_PD_VOPB] = DOMAIN_RK3399(-1, -1, 7, false), | |
| 831 | − [RK3399_PD_VOPL] = DOMAIN_RK3399(-1, -1, 8, false), | |
| 832 | − [RK3399_PD_ISP0] = DOMAIN_RK3399(22, 22, 9, false), | |
| 833 | − [RK3399_PD_ISP1] = DOMAIN_RK3399(23, 23, 10, false), | |
| 834 | − [RK3399_PD_HDCP] = DOMAIN_RK3399(24, 24, 11, false), | |
| 835 | − [RK3399_PD_GMAC] = DOMAIN_RK3399(25, 25, 23, true), | |
| 836 | − [RK3399_PD_EMMC] = DOMAIN_RK3399(26, 26, 24, true), | |
| 837 | − [RK3399_PD_USB3] = DOMAIN_RK3399(27, 27, 12, true), | |
| 838 | − [RK3399_PD_EDP] = DOMAIN_RK3399(28, 28, 22, false), | |
| 839 | − [RK3399_PD_GIC] = DOMAIN_RK3399(29, 29, 27, true), | |
| 840 | − [RK3399_PD_SD] = DOMAIN_RK3399(30, 30, 28, true), | |
| 841 | − [RK3399_PD_SDIOAUDIO] = DOMAIN_RK3399(31, 31, 29, true), | |
| 815 | + [RK3399_PD_TCPD0] = DOMAIN_RK3399(BIT(8), BIT(8), 0, false), | |
| 816 | + [RK3399_PD_TCPD1] = DOMAIN_RK3399(BIT(9), BIT(9), 0, false), | |
| 817 | + [RK3399_PD_CCI] = DOMAIN_RK3399(BIT(10), BIT(10), 0, true), | |
| 818 | + [RK3399_PD_CCI0] = DOMAIN_RK3399(0, 0, BIT(15), true), | |
| 819 | + [RK3399_PD_CCI1] = DOMAIN_RK3399(0, 0, BIT(16), true), | |
| 820 | + [RK3399_PD_PERILP] = DOMAIN_RK3399(BIT(11), BIT(11), BIT(1), true), | |
| 821 | + [RK3399_PD_PERIHP] = DOMAIN_RK3399(BIT(12), BIT(12), BIT(2), true), | |
| 822 | + [RK3399_PD_CENTER] = DOMAIN_RK3399(BIT(13), BIT(13), BIT(14), true), | |
| 823 | + [RK3399_PD_VIO] = DOMAIN_RK3399(BIT(14), BIT(14), BIT(17), false), | |
| 824 | + [RK3399_PD_GPU] = DOMAIN_RK3399(BIT(15), BIT(15), BIT(0), false), | |
| 825 | + [RK3399_PD_VCODEC] = DOMAIN_RK3399(BIT(16), BIT(16), BIT(3), false), | |
| 826 | + [RK3399_PD_VDU] = DOMAIN_RK3399(BIT(17), BIT(17), BIT(4), false), | |
| 827 | + [RK3399_PD_RGA] = DOMAIN_RK3399(BIT(18), BIT(18), BIT(5), false), | |
| 828 | + [RK3399_PD_IEP] = DOMAIN_RK3399(BIT(19), BIT(19), BIT(6), false), | |
| 829 | + [RK3399_PD_VO] = DOMAIN_RK3399(BIT(20), BIT(20), 0, false), | |
| 830 | + [RK3399_PD_VOPB] = DOMAIN_RK3399(0, 0, BIT(7), false), | |
| 831 | + [RK3399_PD_VOPL] = DOMAIN_RK3399(0, 0, BIT(8), false), | |
| 832 | + [RK3399_PD_ISP0] = DOMAIN_RK3399(BIT(22), BIT(22), BIT(9), false), | |
| 833 | + [RK3399_PD_ISP1] = DOMAIN_RK3399(BIT(23), BIT(23), BIT(10), false), | |
| 834 | + [RK3399_PD_HDCP] = DOMAIN_RK3399(BIT(24), BIT(24), BIT(11), false), | |
| 835 | + [RK3399_PD_GMAC] = DOMAIN_RK3399(BIT(25), BIT(25), BIT(23), true), | |
| 836 | + [RK3399_PD_EMMC] = DOMAIN_RK3399(BIT(26), BIT(26), BIT(24), true), | |
| 837 | + [RK3399_PD_USB3] = DOMAIN_RK3399(BIT(27), BIT(27), BIT(12), true), | |
| 838 | + [RK3399_PD_EDP] = DOMAIN_RK3399(BIT(28), BIT(28), BIT(22), false), | |
| 839 | + [RK3399_PD_GIC] = DOMAIN_RK3399(BIT(29), BIT(29), BIT(27), true), | |
| 840 | + [RK3399_PD_SD] = DOMAIN_RK3399(BIT(30), BIT(30), BIT(28), true), | |
| 841 | + [RK3399_PD_SDIOAUDIO] = DOMAIN_RK3399(BIT(31), BIT(31), BIT(29), true), | |
| 842 | 842 | }; |
| 843 | 843 | |
| 844 | 844 | static const struct rockchip_pmu_info px30_pmu = { |
| @@ -109,6 +109,7 @@ config ARCH_TEGRA_186_SOC · 108 unmodified lines | ||
| 109 | 109 | config ARCH_TEGRA_194_SOC |
| 110 | 110 | bool "NVIDIA Tegra194 SoC" |
| 111 | 111 | select MAILBOX |
| 112 | + select PINCTRL_TEGRA194 | |
| 112 | 113 | select TEGRA_BPMP |
| 113 | 114 | select TEGRA_HSP_MBOX |
| 114 | 115 | select TEGRA_IVC |
| @@ -133,8 +133,10 @@ static int tegra_fuse_probe(struct platform_device *pdev) · 132 unmodified lines | ||
| 133 | 133 | |
| 134 | 134 | fuse->clk = devm_clk_get(&pdev->dev, "fuse"); |
| 135 | 135 | if (IS_ERR(fuse->clk)) { |
| 136 | − dev_err(&pdev->dev, "failed to get FUSE clock: %ld", | |
| 137 | − PTR_ERR(fuse->clk)); | |
| 136 | + if (PTR_ERR(fuse->clk) != -EPROBE_DEFER) | |
| 137 | + dev_err(&pdev->dev, "failed to get FUSE clock: %ld", | |
| 138 | + PTR_ERR(fuse->clk)); | |
| 139 | + | |
| 138 | 140 | fuse->base = base; |
| 139 | 141 | return PTR_ERR(fuse->clk); |
| 140 | 142 | } |
| @@ -232,6 +232,11 @@ struct tegra_pmc_soc { · 231 unmodified lines | ||
| 232 | 232 | const char * const *reset_levels; |
| 233 | 233 | unsigned int num_reset_levels; |
| 234 | 234 | |
| 235 | + /* | |
| 236 | + * These describe events that can wake the system from sleep (i.e. | |
| 237 | + * LP0 or SC7). Wakeup from other sleep states (such as LP1 or LP2) | |
| 238 | + * are dealt with in the LIC. | |
| 239 | + */ | |
| 235 | 240 | const struct tegra_wake_event *wake_events; |
| 236 | 241 | unsigned int num_wake_events; |
| 237 | 242 | }; |
| @@ -1855,6 +1860,9 @@ static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq, · 1617 unmodified lines | ||
| 1855 | 1860 | unsigned int i; |
| 1856 | 1861 | int err = 0; |
| 1857 | 1862 | |
| 1863 | + if (WARN_ON(num_irqs > 1)) | |
| 1864 | + return -EINVAL; | |
| 1865 | + | |
| 1858 | 1866 | for (i = 0; i < soc->num_wake_events; i++) { |
| 1859 | 1867 | const struct tegra_wake_event *event = &soc->wake_events[i]; |
| 1860 | 1868 | |
| @@ -1895,6 +1903,11 @@ static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq, · 34 unmodified lines | ||
| 1895 | 1903 | } |
| 1896 | 1904 | } |
| 1897 | 1905 | |
| 1906 | + /* | |
| 1907 | + * For interrupts that don't have associated wake events, assign a | |
| 1908 | + * dummy hardware IRQ number. This is used in the ->irq_set_type() | |
| 1909 | + * and ->irq_set_wake() callbacks to return early for these IRQs. | |
| 1910 | + */ | |
| 1898 | 1911 | if (i == soc->num_wake_events) |
| 1899 | 1912 | err = irq_domain_set_hwirq_and_chip(domain, virq, ULONG_MAX, |
| 1900 | 1913 | &pmc->irq, pmc); |
| @@ -1913,6 +1926,10 @@ static int tegra_pmc_irq_set_wake(struct irq_data *data, unsigned int on) · 12 unmodified lines | ||
| 1913 | 1926 | unsigned int offset, bit; |
| 1914 | 1927 | u32 value; |
| 1915 | 1928 | |
| 1929 | + /* nothing to do if there's no associated wake event */ | |
| 1930 | + if (WARN_ON(data->hwirq == ULONG_MAX)) | |
| 1931 | + return 0; | |
| 1932 | + | |
| 1916 | 1933 | offset = data->hwirq / 32; |
| 1917 | 1934 | bit = data->hwirq % 32; |
| 1918 | 1935 | |
| @@ -1940,6 +1957,7 @@ static int tegra_pmc_irq_set_type(struct irq_data *data, unsigned int type) · 21 unmodified lines | ||
| 1940 | 1957 | struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data); |
| 1941 | 1958 | u32 value; |
| 1942 | 1959 | |
| 1960 | + /* nothing to do if there's no associated wake event */ | |
| 1943 | 1961 | if (data->hwirq == ULONG_MAX) |
| 1944 | 1962 | return 0; |
| 1945 | 1963 | |
| @@ -0,0 +1,14 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | +/* Copyright (c) 2018, Linaro Ltd. */ | |
| 3 | + | |
| 4 | +#ifndef __DT_BINDINGS_POWER_QCOM_AOSS_QMP_H | |
| 5 | +#define __DT_BINDINGS_POWER_QCOM_AOSS_QMP_H | |
| 6 | + | |
| 7 | +#define AOSS_QMP_LS_CDSP 0 | |
| 8 | +#define AOSS_QMP_LS_LPASS 1 | |
| 9 | +#define AOSS_QMP_LS_MODEM 2 | |
| 10 | +#define AOSS_QMP_LS_SLPI 3 | |
| 11 | +#define AOSS_QMP_LS_SPSS 4 | |
| 12 | +#define AOSS_QMP_LS_VENUS 5 | |
| 13 | + | |
| 14 | +#endif | |
| @@ -36,4 +36,38 @@ · 35 unmodified lines | ||
| 36 | 36 | #define MSM8996_VDDSSCX 5 |
| 37 | 37 | #define MSM8996_VDDSSCX_VFC 6 |
| 38 | 38 | |
| 39 | +/* MSM8998 Power Domain Indexes */ | |
| 40 | +#define MSM8998_VDDCX 0 | |
| 41 | +#define MSM8998_VDDCX_AO 1 | |
| 42 | +#define MSM8998_VDDCX_VFL 2 | |
| 43 | +#define MSM8998_VDDMX 3 | |
| 44 | +#define MSM8998_VDDMX_AO 4 | |
| 45 | +#define MSM8998_VDDMX_VFL 5 | |
| 46 | +#define MSM8998_SSCCX 6 | |
| 47 | +#define MSM8998_SSCCX_VFL 7 | |
| 48 | +#define MSM8998_SSCMX 8 | |
| 49 | +#define MSM8998_SSCMX_VFL 9 | |
| 50 | + | |
| 51 | +/* QCS404 Power Domains */ | |
| 52 | +#define QCS404_VDDMX 0 | |
| 53 | +#define QCS404_VDDMX_AO 1 | |
| 54 | +#define QCS404_VDDMX_VFL 2 | |
| 55 | +#define QCS404_LPICX 3 | |
| 56 | +#define QCS404_LPICX_VFL 4 | |
| 57 | +#define QCS404_LPIMX 5 | |
| 58 | +#define QCS404_LPIMX_VFL 6 | |
| 59 | + | |
| 60 | +/* RPM SMD Power Domain performance levels */ | |
| 61 | +#define RPM_SMD_LEVEL_RETENTION 16 | |
| 62 | +#define RPM_SMD_LEVEL_RETENTION_PLUS 32 | |
| 63 | +#define RPM_SMD_LEVEL_MIN_SVS 48 | |
| 64 | +#define RPM_SMD_LEVEL_LOW_SVS 64 | |
| 65 | +#define RPM_SMD_LEVEL_SVS 128 | |
| 66 | +#define RPM_SMD_LEVEL_SVS_PLUS 192 | |
| 67 | +#define RPM_SMD_LEVEL_NOM 256 | |
| 68 | +#define RPM_SMD_LEVEL_NOM_PLUS 320 | |
| 69 | +#define RPM_SMD_LEVEL_TURBO 384 | |
| 70 | +#define RPM_SMD_LEVEL_TURBO_NO_CPR 416 | |
| 71 | +#define RPM_SMD_LEVEL_BINNING 512 | |
| 72 | + | |
| 39 | 73 | #endif |
| @@ -0,0 +1,51 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0+ */ | |
| 2 | +/* | |
| 3 | + * Copyright (c) 2018 Bitmain Ltd. | |
| 4 | + * Copyright (c) 2019 Linaro Ltd. | |
| 5 | + */ | |
| 6 | + | |
| 7 | +#ifndef _DT_BINDINGS_BM1880_RESET_H | |
| 8 | +#define _DT_BINDINGS_BM1880_RESET_H | |
| 9 | + | |
| 10 | +#define BM1880_RST_MAIN_AP 0 | |
| 11 | +#define BM1880_RST_SECOND_AP 1 | |
| 12 | +#define BM1880_RST_DDR 2 | |
| 13 | +#define BM1880_RST_VIDEO 3 | |
| 14 | +#define BM1880_RST_JPEG 4 | |
| 15 | +#define BM1880_RST_VPP 5 | |
| 16 | +#define BM1880_RST_GDMA 6 | |
| 17 | +#define BM1880_RST_AXI_SRAM 7 | |
| 18 | +#define BM1880_RST_TPU 8 | |
| 19 | +#define BM1880_RST_USB 9 | |
| 20 | +#define BM1880_RST_ETH0 10 | |
| 21 | +#define BM1880_RST_ETH1 11 | |
| 22 | +#define BM1880_RST_NAND 12 | |
| 23 | +#define BM1880_RST_EMMC 13 | |
| 24 | +#define BM1880_RST_SD 14 | |
| 25 | +#define BM1880_RST_SDMA 15 | |
| 26 | +#define BM1880_RST_I2S0 16 | |
| 27 | +#define BM1880_RST_I2S1 17 | |
| 28 | +#define BM1880_RST_UART0_1_CLK 18 | |
| 29 | +#define BM1880_RST_UART0_1_ACLK 19 | |
| 30 | +#define BM1880_RST_UART2_3_CLK 20 | |
| 31 | +#define BM1880_RST_UART2_3_ACLK 21 | |
| 32 | +#define BM1880_RST_MINER 22 | |
| 33 | +#define BM1880_RST_I2C0 23 | |
| 34 | +#define BM1880_RST_I2C1 24 | |
| 35 | +#define BM1880_RST_I2C2 25 | |
| 36 | +#define BM1880_RST_I2C3 26 | |
| 37 | +#define BM1880_RST_I2C4 27 | |
| 38 | +#define BM1880_RST_PWM0 28 | |
| 39 | +#define BM1880_RST_PWM1 29 | |
| 40 | +#define BM1880_RST_PWM2 30 | |
| 41 | +#define BM1880_RST_PWM3 31 | |
| 42 | +#define BM1880_RST_SPI 32 | |
| 43 | +#define BM1880_RST_GPIO0 33 | |
| 44 | +#define BM1880_RST_GPIO1 34 | |
| 45 | +#define BM1880_RST_GPIO2 35 | |
| 46 | +#define BM1880_RST_EFUSE 36 | |
| 47 | +#define BM1880_RST_WDT 37 | |
| 48 | +#define BM1880_RST_AHB_ROM 38 | |
| 49 | +#define BM1880_RST_SPIC 39 | |
| 50 | + | |
| 51 | +#endif /* _DT_BINDINGS_BM1880_RESET_H */ | |
| @@ -19,6 +19,7 @@ enum ti_sysc_module_type { · 18 unmodified lines | ||
| 19 | 19 | |
| 20 | 20 | struct ti_sysc_cookie { |
| 21 | 21 | void *data; |
| 22 | + void *clkdm; | |
| 22 | 23 | }; |
| 23 | 24 | |
| 24 | 25 | /** |
| @@ -46,6 +47,10 @@ struct sysc_regbits { · 21 unmodified lines | ||
| 46 | 47 | s8 emufree_shift; |
| 47 | 48 | }; |
| 48 | 49 | |
| 50 | +#define SYSC_MODULE_QUIRK_HDQ1W BIT(17) | |
| 51 | +#define SYSC_MODULE_QUIRK_I2C BIT(16) | |
| 52 | +#define SYSC_MODULE_QUIRK_WDT BIT(15) | |
| 53 | +#define SYSS_QUIRK_RESETDONE_INVERTED BIT(14) | |
| 49 | 54 | #define SYSC_QUIRK_SWSUP_MSTANDBY BIT(13) |
| 50 | 55 | #define SYSC_QUIRK_SWSUP_SIDLE_ACT BIT(12) |
| 51 | 56 | #define SYSC_QUIRK_SWSUP_SIDLE BIT(11) |
| @@ -125,9 +130,16 @@ struct ti_sysc_module_data { · 73 unmodified lines | ||
| 125 | 130 | }; |
| 126 | 131 | |
| 127 | 132 | struct device; |
| 133 | +struct clk; | |
| 128 | 134 | |
| 129 | 135 | struct ti_sysc_platform_data { |
| 130 | 136 | struct of_dev_auxdata *auxdata; |
| 137 | + int (*init_clockdomain)(struct device *dev, struct clk *fck, | |
| 138 | + struct clk *ick, struct ti_sysc_cookie *cookie); | |
| 139 | + void (*clkdm_deny_idle)(struct device *dev, | |
| 140 | + const struct ti_sysc_cookie *cookie); | |
| 141 | + void (*clkdm_allow_idle)(struct device *dev, | |
| 142 | + const struct ti_sysc_cookie *cookie); | |
| 131 | 143 | int (*init_module)(struct device *dev, |
| 132 | 144 | const struct ti_sysc_module_data *data, |
| 133 | 145 | struct ti_sysc_cookie *cookie); |
| @@ -144,6 +144,7 @@ struct scmi_power_ops { · 143 unmodified lines | ||
| 144 | 144 | struct scmi_sensor_info { |
| 145 | 145 | u32 id; |
| 146 | 146 | u8 type; |
| 147 | + s8 scale; | |
| 147 | 148 | char name[SCMI_MAX_STR_SIZE]; |
| 148 | 149 | }; |
| 149 | 150 | |
| @@ -241,12 +241,254 @@ struct ti_sci_rm_irq_ops { · 240 unmodified lines | ||
| 241 | 241 | u16 global_event, u8 vint_status_bit); |
| 242 | 242 | }; |
| 243 | 243 | |
| 244 | +/* RA config.addr_lo parameter is valid for RM ring configure TI_SCI message */ | |
| 245 | +#define TI_SCI_MSG_VALUE_RM_RING_ADDR_LO_VALID BIT(0) | |
| 246 | +/* RA config.addr_hi parameter is valid for RM ring configure TI_SCI message */ | |
| 247 | +#define TI_SCI_MSG_VALUE_RM_RING_ADDR_HI_VALID BIT(1) | |
| 248 | + /* RA config.count parameter is valid for RM ring configure TI_SCI message */ | |
| 249 | +#define TI_SCI_MSG_VALUE_RM_RING_COUNT_VALID BIT(2) | |
| 250 | +/* RA config.mode parameter is valid for RM ring configure TI_SCI message */ | |
| 251 | +#define TI_SCI_MSG_VALUE_RM_RING_MODE_VALID BIT(3) | |
| 252 | +/* RA config.size parameter is valid for RM ring configure TI_SCI message */ | |
| 253 | +#define TI_SCI_MSG_VALUE_RM_RING_SIZE_VALID BIT(4) | |
| 254 | +/* RA config.order_id parameter is valid for RM ring configure TISCI message */ | |
| 255 | +#define TI_SCI_MSG_VALUE_RM_RING_ORDER_ID_VALID BIT(5) | |
| 256 | + | |
| 257 | +#define TI_SCI_MSG_VALUE_RM_ALL_NO_ORDER \ | |
| 258 | + (TI_SCI_MSG_VALUE_RM_RING_ADDR_LO_VALID | \ | |
| 259 | + TI_SCI_MSG_VALUE_RM_RING_ADDR_HI_VALID | \ | |
| 260 | + TI_SCI_MSG_VALUE_RM_RING_COUNT_VALID | \ | |
| 261 | + TI_SCI_MSG_VALUE_RM_RING_MODE_VALID | \ | |
| 262 | + TI_SCI_MSG_VALUE_RM_RING_SIZE_VALID) | |
| 263 | + | |
| 264 | +/** | |
| 265 | + * struct ti_sci_rm_ringacc_ops - Ring Accelerator Management operations | |
| 266 | + * @config: configure the SoC Navigator Subsystem Ring Accelerator ring | |
| 267 | + * @get_config: get the SoC Navigator Subsystem Ring Accelerator ring | |
| 268 | + * configuration | |
| 269 | + */ | |
| 270 | +struct ti_sci_rm_ringacc_ops { | |
| 271 | + int (*config)(const struct ti_sci_handle *handle, | |
| 272 | + u32 valid_params, u16 nav_id, u16 index, | |
| 273 | + u32 addr_lo, u32 addr_hi, u32 count, u8 mode, | |
| 274 | + u8 size, u8 order_id | |
| 275 | + ); | |
| 276 | + int (*get_config)(const struct ti_sci_handle *handle, | |
| 277 | + u32 nav_id, u32 index, u8 *mode, | |
| 278 | + u32 *addr_lo, u32 *addr_hi, u32 *count, | |
| 279 | + u8 *size, u8 *order_id); | |
| 280 | +}; | |
| 281 | + | |
| 282 | +/** | |
| 283 | + * struct ti_sci_rm_psil_ops - PSI-L thread operations | |
| 284 | + * @pair: pair PSI-L source thread to a destination thread. | |
| 285 | + * If the src_thread is mapped to UDMA tchan, the corresponding channel's | |
| 286 | + * TCHAN_THRD_ID register is updated. | |
| 287 | + * If the dst_thread is mapped to UDMA rchan, the corresponding channel's | |
| 288 | + * RCHAN_THRD_ID register is updated. | |
| 289 | + * @unpair: unpair PSI-L source thread from a destination thread. | |
| 290 | + * If the src_thread is mapped to UDMA tchan, the corresponding channel's | |
| 291 | + * TCHAN_THRD_ID register is cleared. | |
| 292 | + * If the dst_thread is mapped to UDMA rchan, the corresponding channel's | |
| 293 | + * RCHAN_THRD_ID register is cleared. | |
| 294 | + */ | |
| 295 | +struct ti_sci_rm_psil_ops { | |
| 296 | + int (*pair)(const struct ti_sci_handle *handle, u32 nav_id, | |
| 297 | + u32 src_thread, u32 dst_thread); | |
| 298 | + int (*unpair)(const struct ti_sci_handle *handle, u32 nav_id, | |
| 299 | + u32 src_thread, u32 dst_thread); | |
| 300 | +}; | |
| 301 | + | |
| 302 | +/* UDMAP channel types */ | |
| 303 | +#define TI_SCI_RM_UDMAP_CHAN_TYPE_PKT_PBRR 2 | |
| 304 | +#define TI_SCI_RM_UDMAP_CHAN_TYPE_PKT_PBRR_SB 3 /* RX only */ | |
| 305 | +#define TI_SCI_RM_UDMAP_CHAN_TYPE_3RDP_PBRR 10 | |
| 306 | +#define TI_SCI_RM_UDMAP_CHAN_TYPE_3RDP_PBVR 11 | |
| 307 | +#define TI_SCI_RM_UDMAP_CHAN_TYPE_3RDP_BCOPY_PBRR 12 | |
| 308 | +#define TI_SCI_RM_UDMAP_CHAN_TYPE_3RDP_BCOPY_PBVR 13 | |
| 309 | + | |
| 310 | +#define TI_SCI_RM_UDMAP_RX_FLOW_DESC_HOST 0 | |
| 311 | +#define TI_SCI_RM_UDMAP_RX_FLOW_DESC_MONO 2 | |
| 312 | + | |
| 313 | +#define TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES 1 | |
| 314 | +#define TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_128_BYTES 2 | |
| 315 | +#define TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_256_BYTES 3 | |
| 316 | + | |
| 317 | +/* UDMAP TX/RX channel valid_params common declarations */ | |
| 318 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_PAUSE_ON_ERR_VALID BIT(0) | |
| 319 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_ATYPE_VALID BIT(1) | |
| 320 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_CHAN_TYPE_VALID BIT(2) | |
| 321 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_FETCH_SIZE_VALID BIT(3) | |
| 322 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_CQ_QNUM_VALID BIT(4) | |
| 323 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_PRIORITY_VALID BIT(5) | |
| 324 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_QOS_VALID BIT(6) | |
| 325 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_ORDER_ID_VALID BIT(7) | |
| 326 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_SCHED_PRIORITY_VALID BIT(8) | |
| 327 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_BURST_SIZE_VALID BIT(14) | |
| 328 | + | |
| 329 | +/** | |
| 330 | + * Configures a Navigator Subsystem UDMAP transmit channel | |
| 331 | + * | |
| 332 | + * Configures a Navigator Subsystem UDMAP transmit channel registers. | |
| 333 | + * See @ti_sci_msg_rm_udmap_tx_ch_cfg_req | |
| 334 | + */ | |
| 335 | +struct ti_sci_msg_rm_udmap_tx_ch_cfg { | |
| 336 | + u32 valid_params; | |
| 337 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_FILT_EINFO_VALID BIT(9) | |
| 338 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_FILT_PSWORDS_VALID BIT(10) | |
| 339 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_SUPR_TDPKT_VALID BIT(11) | |
| 340 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_CREDIT_COUNT_VALID BIT(12) | |
| 341 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_FDEPTH_VALID BIT(13) | |
| 342 | + u16 nav_id; | |
| 343 | + u16 index; | |
| 344 | + u8 tx_pause_on_err; | |
| 345 | + u8 tx_filt_einfo; | |
| 346 | + u8 tx_filt_pswords; | |
| 347 | + u8 tx_atype; | |
| 348 | + u8 tx_chan_type; | |
| 349 | + u8 tx_supr_tdpkt; | |
| 350 | + u16 tx_fetch_size; | |
| 351 | + u8 tx_credit_count; | |
| 352 | + u16 txcq_qnum; | |
| 353 | + u8 tx_priority; | |
| 354 | + u8 tx_qos; | |
| 355 | + u8 tx_orderid; | |
| 356 | + u16 fdepth; | |
| 357 | + u8 tx_sched_priority; | |
| 358 | + u8 tx_burst_size; | |
| 359 | +}; | |
| 360 | + | |
| 361 | +/** | |
| 362 | + * Configures a Navigator Subsystem UDMAP receive channel | |
| 363 | + * | |
| 364 | + * Configures a Navigator Subsystem UDMAP receive channel registers. | |
| 365 | + * See @ti_sci_msg_rm_udmap_rx_ch_cfg_req | |
| 366 | + */ | |
| 367 | +struct ti_sci_msg_rm_udmap_rx_ch_cfg { | |
| 368 | + u32 valid_params; | |
| 369 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_FLOWID_START_VALID BIT(9) | |
| 370 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_FLOWID_CNT_VALID BIT(10) | |
| 371 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_IGNORE_SHORT_VALID BIT(11) | |
| 372 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_IGNORE_LONG_VALID BIT(12) | |
| 373 | + u16 nav_id; | |
| 374 | + u16 index; | |
| 375 | + u16 rx_fetch_size; | |
| 376 | + u16 rxcq_qnum; | |
| 377 | + u8 rx_priority; | |
| 378 | + u8 rx_qos; | |
| 379 | + u8 rx_orderid; | |
| 380 | + u8 rx_sched_priority; | |
| 381 | + u16 flowid_start; | |
| 382 | + u16 flowid_cnt; | |
| 383 | + u8 rx_pause_on_err; | |
| 384 | + u8 rx_atype; | |
| 385 | + u8 rx_chan_type; | |
| 386 | + u8 rx_ignore_short; | |
| 387 | + u8 rx_ignore_long; | |
| 388 | + u8 rx_burst_size; | |
| 389 | +}; | |
| 390 | + | |
| 391 | +/** | |
| 392 | + * Configures a Navigator Subsystem UDMAP receive flow | |
| 393 | + * | |
| 394 | + * Configures a Navigator Subsystem UDMAP receive flow's registers. | |
| 395 | + * See @tis_ci_msg_rm_udmap_flow_cfg_req | |
| 396 | + */ | |
| 397 | +struct ti_sci_msg_rm_udmap_flow_cfg { | |
| 398 | + u32 valid_params; | |
| 399 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_EINFO_PRESENT_VALID BIT(0) | |
| 400 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_PSINFO_PRESENT_VALID BIT(1) | |
| 401 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_ERROR_HANDLING_VALID BIT(2) | |
| 402 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DESC_TYPE_VALID BIT(3) | |
| 403 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_SOP_OFFSET_VALID BIT(4) | |
| 404 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DEST_QNUM_VALID BIT(5) | |
| 405 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_SRC_TAG_HI_VALID BIT(6) | |
| 406 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_SRC_TAG_LO_VALID BIT(7) | |
| 407 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DEST_TAG_HI_VALID BIT(8) | |
| 408 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DEST_TAG_LO_VALID BIT(9) | |
| 409 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_SRC_TAG_HI_SEL_VALID BIT(10) | |
| 410 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_SRC_TAG_LO_SEL_VALID BIT(11) | |
| 411 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DEST_TAG_HI_SEL_VALID BIT(12) | |
| 412 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DEST_TAG_LO_SEL_VALID BIT(13) | |
| 413 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ0_SZ0_QNUM_VALID BIT(14) | |
| 414 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ1_QNUM_VALID BIT(15) | |
| 415 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ2_QNUM_VALID BIT(16) | |
| 416 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ3_QNUM_VALID BIT(17) | |
| 417 | +#define TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_PS_LOCATION_VALID BIT(18) | |
| 418 | + u16 nav_id; | |
| 419 | + u16 flow_index; | |
| 420 | + u8 rx_einfo_present; | |
| 421 | + u8 rx_psinfo_present; | |
| 422 | + u8 rx_error_handling; | |
| 423 | + u8 rx_desc_type; | |
| 424 | + u16 rx_sop_offset; | |
| 425 | + u16 rx_dest_qnum; | |
| 426 | + u8 rx_src_tag_hi; | |
| 427 | + u8 rx_src_tag_lo; | |
| 428 | + u8 rx_dest_tag_hi; | |
| 429 | + u8 rx_dest_tag_lo; | |
| 430 | + u8 rx_src_tag_hi_sel; | |
| 431 | + u8 rx_src_tag_lo_sel; | |
| 432 | + u8 rx_dest_tag_hi_sel; | |
| 433 | + u8 rx_dest_tag_lo_sel; | |
| 434 | + u16 rx_fdq0_sz0_qnum; | |
| 435 | + u16 rx_fdq1_qnum; | |
| 436 | + u16 rx_fdq2_qnum; | |
| 437 | + u16 rx_fdq3_qnum; | |
| 438 | + u8 rx_ps_location; | |
| 439 | +}; | |
| 440 | + | |
| 441 | +/** | |
| 442 | + * struct ti_sci_rm_udmap_ops - UDMA Management operations | |
| 443 | + * @tx_ch_cfg: configure SoC Navigator Subsystem UDMA transmit channel. | |
| 444 | + * @rx_ch_cfg: configure SoC Navigator Subsystem UDMA receive channel. | |
| 445 | + * @rx_flow_cfg1: configure SoC Navigator Subsystem UDMA receive flow. | |
| 446 | + */ | |
| 447 | +struct ti_sci_rm_udmap_ops { | |
| 448 | + int (*tx_ch_cfg)(const struct ti_sci_handle *handle, | |
| 449 | + const struct ti_sci_msg_rm_udmap_tx_ch_cfg *params); | |
| 450 | + int (*rx_ch_cfg)(const struct ti_sci_handle *handle, | |
| 451 | + const struct ti_sci_msg_rm_udmap_rx_ch_cfg *params); | |
| 452 | + int (*rx_flow_cfg)(const struct ti_sci_handle *handle, | |
| 453 | + const struct ti_sci_msg_rm_udmap_flow_cfg *params); | |
| 454 | +}; | |
| 455 | + | |
| 456 | +/** | |
| 457 | + * struct ti_sci_proc_ops - Processor Control operations | |
| 458 | + * @request: Request to control a physical processor. The requesting host | |
| 459 | + * should be in the processor access list | |
| 460 | + * @release: Relinquish a physical processor control | |
| 461 | + * @handover: Handover a physical processor control to another host | |
| 462 | + * in the permitted list | |
| 463 | + * @set_config: Set base configuration of a processor | |
| 464 | + * @set_control: Setup limited control flags in specific cases | |
| 465 | + * @get_status: Get the state of physical processor | |
| 466 | + * | |
| 467 | + * NOTE: The following paramteres are generic in nature for all these ops, | |
| 468 | + * -handle: Pointer to TI SCI handle as retrieved by *ti_sci_get_handle | |
| 469 | + * -pid: Processor ID | |
| 470 | + * -hid: Host ID | |
| 471 | + */ | |
| 472 | +struct ti_sci_proc_ops { | |
| 473 | + int (*request)(const struct ti_sci_handle *handle, u8 pid); | |
| 474 | + int (*release)(const struct ti_sci_handle *handle, u8 pid); | |
| 475 | + int (*handover)(const struct ti_sci_handle *handle, u8 pid, u8 hid); | |
| 476 | + int (*set_config)(const struct ti_sci_handle *handle, u8 pid, | |
| 477 | + u64 boot_vector, u32 cfg_set, u32 cfg_clr); | |
| 478 | + int (*set_control)(const struct ti_sci_handle *handle, u8 pid, | |
| 479 | + u32 ctrl_set, u32 ctrl_clr); | |
| 480 | + int (*get_status)(const struct ti_sci_handle *handle, u8 pid, | |
| 481 | + u64 *boot_vector, u32 *cfg_flags, u32 *ctrl_flags, | |
| 482 | + u32 *status_flags); | |
| 483 | +}; | |
| 484 | + | |
| 244 | 485 | /** |
| 245 | 486 | * struct ti_sci_ops - Function support for TI SCI |
| 246 | 487 | * @dev_ops: Device specific operations |
| 247 | 488 | * @clk_ops: Clock specific operations |
| 248 | 489 | * @rm_core_ops: Resource management core operations. |
| 249 | 490 | * @rm_irq_ops: IRQ management specific operations |
| 491 | + * @proc_ops: Processor Control specific operations | |
| 250 | 492 | */ |
| 251 | 493 | struct ti_sci_ops { |
| 252 | 494 | struct ti_sci_core_ops core_ops; |
| @@ -254,6 +496,10 @@ struct ti_sci_ops { · 1 unmodified line | ||
| 254 | 496 | struct ti_sci_clk_ops clk_ops; |
| 255 | 497 | struct ti_sci_rm_core_ops rm_core_ops; |
| 256 | 498 | struct ti_sci_rm_irq_ops rm_irq_ops; |
| 499 | + struct ti_sci_rm_ringacc_ops rm_ring_ops; | |
| 500 | + struct ti_sci_rm_psil_ops rm_psil_ops; | |
| 501 | + struct ti_sci_rm_udmap_ops rm_udmap_ops; | |
| 502 | + struct ti_sci_proc_ops proc_ops; | |
| 257 | 503 | }; |
| 258 | 504 | |
| 259 | 505 | /** |
| @@ -133,5 +133,13 @@ int bman_acquire(struct bman_pool *pool, struct bm_buffer *bufs, u8 num); · 132 unmodified lines | ||
| 133 | 133 | * failed to probe or 0 if the bman driver did not probed yet. |
| 134 | 134 | */ |
| 135 | 135 | int bman_is_probed(void); |
| 136 | +/** | |
| 137 | + * bman_portals_probed - Check if all cpu bound bman portals are probed | |
| 138 | + * | |
| 139 | + * Returns 1 if all the required cpu bound bman portals successfully probed, | |
| 140 | + * -1 if probe errors appeared or 0 if the bman portals did not yet finished | |
| 141 | + * probing. | |
| 142 | + */ | |
| 143 | +int bman_portals_probed(void); | |
| 136 | 144 | |
| 137 | 145 | #endif /* __FSL_BMAN_H */ |
| @@ -1194,6 +1194,15 @@ int qman_release_cgrid(u32 id); · 1193 unmodified lines | ||
| 1194 | 1194 | */ |
| 1195 | 1195 | int qman_is_probed(void); |
| 1196 | 1196 | |
| 1197 | +/** | |
| 1198 | + * qman_portals_probed - Check if all cpu bound qman portals are probed | |
| 1199 | + * | |
| 1200 | + * Returns 1 if all the required cpu bound qman portals successfully probed, | |
| 1201 | + * -1 if probe errors appeared or 0 if the qman portals did not yet finished | |
| 1202 | + * probing. | |
| 1203 | + */ | |
| 1204 | +int qman_portals_probed(void); | |
| 1205 | + | |
| 1197 | 1206 | /** |
| 1198 | 1207 | * qman_dqrr_get_ithresh - Get coalesce interrupt threshold |
| 1199 | 1208 | * @portal: portal to get the value for |
| @@ -531,14 +531,6 @@ config LRU_CACHE · 530 unmodified lines | ||
| 531 | 531 | config CLZ_TAB |
| 532 | 532 | bool |
| 533 | 533 | |
| 534 | −config DDR | |
| 535 | − bool "JEDEC DDR data" | |
| 536 | − help | |
| 537 | − Data from JEDEC specs for DDR SDRAM memories, | |
| 538 | − particularly the AC timing parameters and addressing | |
| 539 | − information. This data is useful for drivers handling | |
| 540 | − DDR SDRAM controllers. | |
| 541 | − | |
| 542 | 534 | config IRQ_POLL |
| 543 | 535 | bool "IRQ polling library" |
| 544 | 536 | help |
| @@ -209,8 +209,6 @@ obj-$(CONFIG_SIGNATURE) += digsig.o · 208 unmodified lines | ||
| 209 | 209 | |
| 210 | 210 | lib-$(CONFIG_CLZ_TAB) += clz_tab.o |
| 211 | 211 | |
| 212 | −obj-$(CONFIG_DDR) += jedec_ddr_data.o | |
| 213 | − | |
| 214 | 212 | obj-$(CONFIG_GENERIC_STRNCPY_FROM_USER) += strncpy_from_user.o |
| 215 | 213 | obj-$(CONFIG_GENERIC_STRNLEN_USER) += strnlen_user.o |
| 216 | 214 | |