From 484a58607a808c3721917f5ca5fba7eff809e4df Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 4 Feb 2021 13:13:13 +0100 Subject: fpga: fpga-mgr: xilinx-spi: fix error messages on -EPROBE_DEFER The current code produces an error message on devm_gpiod_get() errors even when the error is -EPROBE_DEFER, which should be silent. This has been observed producing a significant amount of messages like: xlnx-slave-spi spi1.1: Failed to get PROGRAM_B gpio: -517 Fix and simplify code by using the dev_err_probe() helper function. Signed-off-by: Luca Ceresoli Fixes: dd2784c01d93 ("fpga manager: xilinx-spi: check INIT_B pin during write_init") Fixes: 061c97d13f1a ("fpga manager: Add Xilinx slave serial SPI driver") Signed-off-by: Moritz Fischer --- drivers/fpga/xilinx-spi.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c index 27defa98092d..fee4d0abf6bf 100644 --- a/drivers/fpga/xilinx-spi.c +++ b/drivers/fpga/xilinx-spi.c @@ -233,25 +233,19 @@ static int xilinx_spi_probe(struct spi_device *spi) /* PROGRAM_B is active low */ conf->prog_b = devm_gpiod_get(&spi->dev, "prog_b", GPIOD_OUT_LOW); - if (IS_ERR(conf->prog_b)) { - dev_err(&spi->dev, "Failed to get PROGRAM_B gpio: %ld\n", - PTR_ERR(conf->prog_b)); - return PTR_ERR(conf->prog_b); - } + if (IS_ERR(conf->prog_b)) + return dev_err_probe(&spi->dev, PTR_ERR(conf->prog_b), + "Failed to get PROGRAM_B gpio\n"); conf->init_b = devm_gpiod_get_optional(&spi->dev, "init-b", GPIOD_IN); - if (IS_ERR(conf->init_b)) { - dev_err(&spi->dev, "Failed to get INIT_B gpio: %ld\n", - PTR_ERR(conf->init_b)); - return PTR_ERR(conf->init_b); - } + if (IS_ERR(conf->init_b)) + return dev_err_probe(&spi->dev, PTR_ERR(conf->init_b), + "Failed to get INIT_B gpio\n"); conf->done = devm_gpiod_get(&spi->dev, "done", GPIOD_IN); - if (IS_ERR(conf->done)) { - dev_err(&spi->dev, "Failed to get DONE gpio: %ld\n", - PTR_ERR(conf->done)); - return PTR_ERR(conf->done); - } + if (IS_ERR(conf->done)) + return dev_err_probe(&spi->dev, PTR_ERR(conf->done), + "Failed to get DONE gpio\n"); mgr = devm_fpga_mgr_create(&spi->dev, "Xilinx Slave Serial FPGA Manager", -- cgit v1.2.3 From 2d6e820c4e9e7a6d681a413cca6c7dc53b420c97 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 4 Feb 2021 14:36:11 +0100 Subject: fpga: xilinx-pr-decoupler: Simplify code by using dev_err_probe() Use already prepared dev_err_probe() introduced by commit a787e5400a1c ("driver core: add device probe log helper"). It simplifies EPROBE_DEFER handling. Signed-off-by: Michal Simek Signed-off-by: Moritz Fischer --- drivers/fpga/xilinx-pr-decoupler.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/fpga/xilinx-pr-decoupler.c b/drivers/fpga/xilinx-pr-decoupler.c index 7d69af230567..b0eaf26af6e7 100644 --- a/drivers/fpga/xilinx-pr-decoupler.c +++ b/drivers/fpga/xilinx-pr-decoupler.c @@ -100,11 +100,9 @@ static int xlnx_pr_decoupler_probe(struct platform_device *pdev) return PTR_ERR(priv->io_base); priv->clk = devm_clk_get(&pdev->dev, "aclk"); - if (IS_ERR(priv->clk)) { - if (PTR_ERR(priv->clk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "input clock not found\n"); - return PTR_ERR(priv->clk); - } + if (IS_ERR(priv->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk), + "input clock not found\n"); err = clk_prepare_enable(priv->clk); if (err) { -- cgit v1.2.3 From 71c3980b8cc8ddaa523a3061392f5298c4798206 Mon Sep 17 00:00:00 2001 From: Nava kishore Manne Date: Thu, 11 Feb 2021 10:41:47 +0530 Subject: dt-bindings: fpga: Add compatible value for Xilinx DFX AXI shutdown manager This patch Adds compatible value for Xilinx Dynamic Function eXchnage(DFX) AXI Shutdown manager IP. Signed-off-by: Nava kishore Manne Reviewed-by: Tom Rix Reviewed-by: Rob Herring Signed-off-by: Moritz Fischer --- .../bindings/fpga/xilinx-pr-decoupler.txt | 24 +++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/fpga/xilinx-pr-decoupler.txt b/Documentation/devicetree/bindings/fpga/xilinx-pr-decoupler.txt index 4284d293fa61..0acdfa6d62a4 100644 --- a/Documentation/devicetree/bindings/fpga/xilinx-pr-decoupler.txt +++ b/Documentation/devicetree/bindings/fpga/xilinx-pr-decoupler.txt @@ -7,13 +7,24 @@ changes from passing through the bridge. The controller can also couple / enable the bridges which allows traffic to pass through the bridge normally. +Xilinx LogiCORE Dynamic Function eXchange(DFX) AXI shutdown manager +Softcore is compatible with the Xilinx LogiCORE pr-decoupler. + +The Dynamic Function eXchange AXI shutdown manager prevents AXI traffic +from passing through the bridge. The controller safely handles AXI4MM +and AXI4-Lite interfaces on a Reconfigurable Partition when it is +undergoing dynamic reconfiguration, preventing the system deadlock +that can occur if AXI transactions are interrupted by DFX + The Driver supports only MMIO handling. A PR region can have multiple PR Decouplers which can be handled independently or chained via decouple/ decouple_status signals. Required properties: - compatible : Should contain "xlnx,pr-decoupler-1.00" followed by - "xlnx,pr-decoupler" + "xlnx,pr-decoupler" or + "xlnx,dfx-axi-shutdown-manager-1.00" followed by + "xlnx,dfx-axi-shutdown-manager" - regs : base address and size for decoupler module - clocks : input clock to IP - clock-names : should contain "aclk" @@ -22,6 +33,7 @@ See Documentation/devicetree/bindings/fpga/fpga-region.txt and Documentation/devicetree/bindings/fpga/fpga-bridge.txt for generic bindings. Example: +Partial Reconfig Decoupler: fpga-bridge@100000450 { compatible = "xlnx,pr-decoupler-1.00", "xlnx-pr-decoupler"; @@ -30,3 +42,13 @@ Example: clock-names = "aclk"; bridge-enable = <0>; }; + +Dynamic Function eXchange AXI shutdown manager: + fpga-bridge@100000450 { + compatible = "xlnx,dfx-axi-shutdown-manager-1.00", + "xlnx,dfx-axi-shutdown-manager"; + regs = <0x10000045 0x10>; + clocks = <&clkc 15>; + clock-names = "aclk"; + bridge-enable = <0>; + }; -- cgit v1.2.3 From 6f1e376cfc6864a2f46538db909bbd5253c3c146 Mon Sep 17 00:00:00 2001 From: Nava kishore Manne Date: Thu, 11 Feb 2021 10:41:48 +0530 Subject: fpga: Add support for Xilinx DFX AXI Shutdown manager This patch adds support for Xilinx Dynamic Function eXchange(DFX) AXI shutdown manager IP. It can be used to safely handling the AXI traffic on a Reconfigurable Partition when it is undergoing dynamic reconfiguration and there by preventing system deadlock that may occur if AXI transactions are interrupted during reconfiguration. PR-Decoupler and AXI shutdown manager are completely different IPs. But both the IP registers are compatible and also both belong to the same sub-system (fpga-bridge).So using same driver for both IP's. Signed-off-by: Nava kishore Manne Reviewed-by: Tom Rix Signed-off-by: Moritz Fischer --- drivers/fpga/Kconfig | 9 ++++++++- drivers/fpga/xilinx-pr-decoupler.c | 37 ++++++++++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 5ff9438b7b46..d591dd9b7c60 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -118,10 +118,17 @@ config XILINX_PR_DECOUPLER depends on FPGA_BRIDGE depends on HAS_IOMEM help - Say Y to enable drivers for Xilinx LogiCORE PR Decoupler. + Say Y to enable drivers for Xilinx LogiCORE PR Decoupler + or Xilinx Dynamic Function eXchnage AIX Shutdown Manager. The PR Decoupler exists in the FPGA fabric to isolate one region of the FPGA from the busses while that region is being reprogrammed during partial reconfig. + The Dynamic Function eXchange AXI shutdown manager prevents + AXI traffic from passing through the bridge. The controller + safely handles AXI4MM and AXI4-Lite interfaces on a + Reconfigurable Partition when it is undergoing dynamic + reconfiguration, preventing the system deadlock that can + occur if AXI transactions are interrupted by DFX. config FPGA_REGION tristate "FPGA Region" diff --git a/drivers/fpga/xilinx-pr-decoupler.c b/drivers/fpga/xilinx-pr-decoupler.c index b0eaf26af6e7..ea2bde6e5bc4 100644 --- a/drivers/fpga/xilinx-pr-decoupler.c +++ b/drivers/fpga/xilinx-pr-decoupler.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017, National Instruments Corp. - * Copyright (c) 2017, Xilix Inc + * Copyright (c) 2017, Xilinx Inc * * FPGA Bridge Driver for the Xilinx LogiCORE Partial Reconfiguration * Decoupler IP Core. @@ -18,7 +18,12 @@ #define CTRL_CMD_COUPLE 0 #define CTRL_OFFSET 0 +struct xlnx_config_data { + const char *name; +}; + struct xlnx_pr_decoupler_data { + const struct xlnx_config_data *ipconfig; void __iomem *io_base; struct clk *clk; }; @@ -76,15 +81,28 @@ static const struct fpga_bridge_ops xlnx_pr_decoupler_br_ops = { .enable_show = xlnx_pr_decoupler_enable_show, }; +static const struct xlnx_config_data decoupler_config = { + .name = "Xilinx PR Decoupler", +}; + +static const struct xlnx_config_data shutdown_config = { + .name = "Xilinx DFX AXI Shutdown Manager", +}; + static const struct of_device_id xlnx_pr_decoupler_of_match[] = { - { .compatible = "xlnx,pr-decoupler-1.00", }, - { .compatible = "xlnx,pr-decoupler", }, + { .compatible = "xlnx,pr-decoupler-1.00", .data = &decoupler_config }, + { .compatible = "xlnx,pr-decoupler", .data = &decoupler_config }, + { .compatible = "xlnx,dfx-axi-shutdown-manager-1.00", + .data = &shutdown_config }, + { .compatible = "xlnx,dfx-axi-shutdown-manager", + .data = &shutdown_config }, {}, }; MODULE_DEVICE_TABLE(of, xlnx_pr_decoupler_of_match); static int xlnx_pr_decoupler_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct xlnx_pr_decoupler_data *priv; struct fpga_bridge *br; int err; @@ -94,6 +112,14 @@ static int xlnx_pr_decoupler_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + if (np) { + const struct of_device_id *match; + + match = of_match_node(xlnx_pr_decoupler_of_match, np); + if (match && match->data) + priv->ipconfig = match->data; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->io_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(priv->io_base)) @@ -112,7 +138,7 @@ static int xlnx_pr_decoupler_probe(struct platform_device *pdev) clk_disable(priv->clk); - br = devm_fpga_bridge_create(&pdev->dev, "Xilinx PR Decoupler", + br = devm_fpga_bridge_create(&pdev->dev, priv->ipconfig->name, &xlnx_pr_decoupler_br_ops, priv); if (!br) { err = -ENOMEM; @@ -123,7 +149,8 @@ static int xlnx_pr_decoupler_probe(struct platform_device *pdev) err = fpga_bridge_register(br); if (err) { - dev_err(&pdev->dev, "unable to register Xilinx PR Decoupler"); + dev_err(&pdev->dev, "unable to register %s", + priv->ipconfig->name); goto err_clk; } -- cgit v1.2.3 From 33ad2800348e6c20f05b86ef01e8216fc3e3c762 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Mon, 8 Mar 2021 15:09:45 +0200 Subject: dt-bindings: interconnect: Add bindings for Qualcomm SDM660 NoC Add the bindings for the Qualcomm SDM660-class NoC, valid for SDM630, SDM636, SDM660 and SDA variants. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20201017133718.31327-2-kholk11@gmail.com Signed-off-by: Georgi Djakov --- .../bindings/interconnect/qcom,sdm660.yaml | 147 +++++++++++++++++++++ include/dt-bindings/interconnect/qcom,sdm660.h | 116 ++++++++++++++++ 2 files changed, 263 insertions(+) create mode 100644 Documentation/devicetree/bindings/interconnect/qcom,sdm660.yaml create mode 100644 include/dt-bindings/interconnect/qcom,sdm660.h diff --git a/Documentation/devicetree/bindings/interconnect/qcom,sdm660.yaml b/Documentation/devicetree/bindings/interconnect/qcom,sdm660.yaml new file mode 100644 index 000000000000..29de7807df54 --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,sdm660.yaml @@ -0,0 +1,147 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,sdm660.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SDM660 Network-On-Chip interconnect + +maintainers: + - AngeloGioacchino Del Regno + +description: | + The Qualcomm SDM660 interconnect providers support adjusting the + bandwidth requirements between the various NoC fabrics. + +properties: + reg: + maxItems: 1 + + compatible: + enum: + - qcom,sdm660-a2noc + - qcom,sdm660-bimc + - qcom,sdm660-cnoc + - qcom,sdm660-gnoc + - qcom,sdm660-mnoc + - qcom,sdm660-snoc + + '#interconnect-cells': + const: 1 + + clocks: + minItems: 1 + maxItems: 3 + + clock-names: + minItems: 1 + maxItems: 3 + +required: + - compatible + - reg + - '#interconnect-cells' + - clock-names + - clocks + +additionalProperties: false + +allOf: + - if: + properties: + compatible: + contains: + enum: + - qcom,sdm660-mnoc + then: + properties: + clocks: + items: + - description: Bus Clock. + - description: Bus A Clock. + - description: CPU-NoC High-performance Bus Clock. + clock-names: + items: + - const: bus + - const: bus_a + - const: iface + + - if: + properties: + compatible: + contains: + enum: + - qcom,sdm660-a2noc + - qcom,sdm660-bimc + - qcom,sdm660-cnoc + - qcom,sdm660-gnoc + - qcom,sdm660-snoc + then: + properties: + clocks: + items: + - description: Bus Clock. + - description: Bus A Clock. + clock-names: + items: + - const: bus + - const: bus_a + +examples: + - | + #include + #include + + bimc: interconnect@1008000 { + compatible = "qcom,sdm660-bimc"; + reg = <0x01008000 0x78000>; + #interconnect-cells = <1>; + clock-names = "bus", "bus_a"; + clocks = <&rpmcc RPM_SMD_BIMC_CLK>, + <&rpmcc RPM_SMD_BIMC_A_CLK>; + }; + + cnoc: interconnect@1500000 { + compatible = "qcom,sdm660-cnoc"; + reg = <0x01500000 0x10000>; + #interconnect-cells = <1>; + clock-names = "bus", "bus_a"; + clocks = <&rpmcc RPM_SMD_CNOC_CLK>, + <&rpmcc RPM_SMD_CNOC_A_CLK>; + }; + + snoc: interconnect@1626000 { + compatible = "qcom,sdm660-snoc"; + reg = <0x01626000 0x7090>; + #interconnect-cells = <1>; + clock-names = "bus", "bus_a"; + clocks = <&rpmcc RPM_SMD_SNOC_CLK>, + <&rpmcc RPM_SMD_SNOC_A_CLK>; + }; + + a2noc: interconnect@1704000 { + compatible = "qcom,sdm660-a2noc"; + reg = <0x01704000 0xc100>; + #interconnect-cells = <1>; + clock-names = "bus", "bus_a"; + clocks = <&rpmcc RPM_SMD_AGGR2_NOC_CLK>, + <&rpmcc RPM_SMD_AGGR2_NOC_A_CLK>; + }; + + mnoc: interconnect@1745000 { + compatible = "qcom,sdm660-mnoc"; + reg = <0x01745000 0xa010>; + #interconnect-cells = <1>; + clock-names = "bus", "bus_a", "iface"; + clocks = <&rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&rpmcc RPM_SMD_MMSSNOC_AXI_CLK_A>, + <&mmcc AHB_CLK_SRC>; + }; + + gnoc: interconnect@17900000 { + compatible = "qcom,sdm660-gnoc"; + reg = <0x17900000 0xe000>; + #interconnect-cells = <1>; + clock-names = "bus", "bus_a"; + clocks = <&xo_board>, <&xo_board>; + }; diff --git a/include/dt-bindings/interconnect/qcom,sdm660.h b/include/dt-bindings/interconnect/qcom,sdm660.h new file mode 100644 index 000000000000..62e8d8670d5e --- /dev/null +++ b/include/dt-bindings/interconnect/qcom,sdm660.h @@ -0,0 +1,116 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* SDM660 interconnect IDs */ + +#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_SDM660_H +#define __DT_BINDINGS_INTERCONNECT_QCOM_SDM660_H + +/* A2NOC */ +#define MASTER_IPA 0 +#define MASTER_CNOC_A2NOC 1 +#define MASTER_SDCC_1 2 +#define MASTER_SDCC_2 3 +#define MASTER_BLSP_1 4 +#define MASTER_BLSP_2 5 +#define MASTER_UFS 6 +#define MASTER_USB_HS 7 +#define MASTER_USB3 8 +#define MASTER_CRYPTO_C0 9 +#define SLAVE_A2NOC_SNOC 10 + +/* BIMC */ +#define MASTER_GNOC_BIMC 0 +#define MASTER_OXILI 1 +#define MASTER_MNOC_BIMC 2 +#define MASTER_SNOC_BIMC 3 +#define MASTER_PIMEM 4 +#define SLAVE_EBI 5 +#define SLAVE_HMSS_L3 6 +#define SLAVE_BIMC_SNOC 7 + +/* CNOC */ +#define MASTER_SNOC_CNOC 0 +#define MASTER_QDSS_DAP 1 +#define SLAVE_CNOC_A2NOC 2 +#define SLAVE_MPM 3 +#define SLAVE_PMIC_ARB 4 +#define SLAVE_TLMM_NORTH 5 +#define SLAVE_TCSR 6 +#define SLAVE_PIMEM_CFG 7 +#define SLAVE_IMEM_CFG 8 +#define SLAVE_MESSAGE_RAM 9 +#define SLAVE_GLM 10 +#define SLAVE_BIMC_CFG 11 +#define SLAVE_PRNG 12 +#define SLAVE_SPDM 13 +#define SLAVE_QDSS_CFG 14 +#define SLAVE_CNOC_MNOC_CFG 15 +#define SLAVE_SNOC_CFG 16 +#define SLAVE_QM_CFG 17 +#define SLAVE_CLK_CTL 18 +#define SLAVE_MSS_CFG 19 +#define SLAVE_TLMM_SOUTH 20 +#define SLAVE_UFS_CFG 21 +#define SLAVE_A2NOC_CFG 22 +#define SLAVE_A2NOC_SMMU_CFG 23 +#define SLAVE_GPUSS_CFG 24 +#define SLAVE_AHB2PHY 25 +#define SLAVE_BLSP_1 26 +#define SLAVE_SDCC_1 27 +#define SLAVE_SDCC_2 28 +#define SLAVE_TLMM_CENTER 29 +#define SLAVE_BLSP_2 30 +#define SLAVE_PDM 31 +#define SLAVE_CNOC_MNOC_MMSS_CFG 32 +#define SLAVE_USB_HS 33 +#define SLAVE_USB3_0 34 +#define SLAVE_SRVC_CNOC 35 + +/* GNOC */ +#define MASTER_APSS_PROC 0 +#define SLAVE_GNOC_BIMC 1 +#define SLAVE_GNOC_SNOC 2 + +/* MNOC */ +#define MASTER_CPP 0 +#define MASTER_JPEG 1 +#define MASTER_MDP_P0 2 +#define MASTER_MDP_P1 3 +#define MASTER_VENUS 4 +#define MASTER_VFE 5 +#define SLAVE_MNOC_BIMC 6 +#define MASTER_CNOC_MNOC_MMSS_CFG 7 +#define MASTER_CNOC_MNOC_CFG 8 +#define SLAVE_CAMERA_CFG 9 +#define SLAVE_CAMERA_THROTTLE_CFG 10 +#define SLAVE_MISC_CFG 11 +#define SLAVE_VENUS_THROTTLE_CFG 12 +#define SLAVE_VENUS_CFG 13 +#define SLAVE_MMSS_CLK_XPU_CFG 14 +#define SLAVE_MMSS_CLK_CFG 15 +#define SLAVE_MNOC_MPU_CFG 16 +#define SLAVE_DISPLAY_CFG 17 +#define SLAVE_CSI_PHY_CFG 18 +#define SLAVE_DISPLAY_THROTTLE_CFG 19 +#define SLAVE_SMMU_CFG 20 +#define SLAVE_SRVC_MNOC 21 + +/* SNOC */ +#define MASTER_QDSS_ETR 0 +#define MASTER_QDSS_BAM 1 +#define MASTER_SNOC_CFG 2 +#define MASTER_BIMC_SNOC 3 +#define MASTER_A2NOC_SNOC 4 +#define MASTER_GNOC_SNOC 5 +#define SLAVE_HMSS 6 +#define SLAVE_LPASS 7 +#define SLAVE_WLAN 8 +#define SLAVE_CDSP 9 +#define SLAVE_IPA 10 +#define SLAVE_SNOC_BIMC 11 +#define SLAVE_SNOC_CNOC 12 +#define SLAVE_IMEM 13 +#define SLAVE_PIMEM 14 +#define SLAVE_QDSS_STM 15 +#define SLAVE_SRVC_SNOC 16 + +#endif -- cgit v1.2.3 From f80a1d41432869dd78dfe8373060371918a05326 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Mon, 8 Mar 2021 15:09:45 +0200 Subject: interconnect: qcom: Add SDM660 interconnect provider driver Introduce a driver for the Qualcomm interconnect busses found in the SDM630/SDM636/SDM660 SoCs. The topology consists of several NoCs that are controlled by a remote processor that collects the aggregated bandwidth for each master-slave pairs. On a note, these chips are managing the "bus QoS" in a "hybrid" fashion: some of the paths in the topology are managed through (and by, of course) the RPM uC, while some others are "AP Owned", meaning that the AP shall do direct writes to the appropriate QoS registers for the specific paths and ports, instead of sending an indication to the RPM and leaving the job to that one. Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20201017133718.31327-3-kholk11@gmail.com Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/Kconfig | 9 + drivers/interconnect/qcom/Makefile | 2 + drivers/interconnect/qcom/sdm660.c | 922 +++++++++++++++++++++++++++++++++++++ 3 files changed, 933 insertions(+) create mode 100644 drivers/interconnect/qcom/sdm660.c diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig index ca52647f8955..4b70eb30fbc9 100644 --- a/drivers/interconnect/qcom/Kconfig +++ b/drivers/interconnect/qcom/Kconfig @@ -74,6 +74,15 @@ config INTERCONNECT_QCOM_SC7180 This is a driver for the Qualcomm Network-on-Chip on sc7180-based platforms. +config INTERCONNECT_QCOM_SDM660 + tristate "Qualcomm SDM660 interconnect driver" + depends on INTERCONNECT_QCOM + depends on QCOM_SMD_RPM + select INTERCONNECT_QCOM_SMD_RPM + help + This is a driver for the Qualcomm Network-on-Chip on sdm660-based + platforms. + config INTERCONNECT_QCOM_SDM845 tristate "Qualcomm SDM845 interconnect driver" depends on INTERCONNECT_QCOM_RPMH_POSSIBLE diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile index c6a735df067e..3964e60ea611 100644 --- a/drivers/interconnect/qcom/Makefile +++ b/drivers/interconnect/qcom/Makefile @@ -8,6 +8,7 @@ icc-osm-l3-objs := osm-l3.o qnoc-qcs404-objs := qcs404.o icc-rpmh-obj := icc-rpmh.o qnoc-sc7180-objs := sc7180.o +qnoc-sdm660-objs := sdm660.o qnoc-sdm845-objs := sdm845.o qnoc-sdx55-objs := sdx55.o qnoc-sm8150-objs := sm8150.o @@ -22,6 +23,7 @@ obj-$(CONFIG_INTERCONNECT_QCOM_OSM_L3) += icc-osm-l3.o obj-$(CONFIG_INTERCONNECT_QCOM_QCS404) += qnoc-qcs404.o obj-$(CONFIG_INTERCONNECT_QCOM_RPMH) += icc-rpmh.o obj-$(CONFIG_INTERCONNECT_QCOM_SC7180) += qnoc-sc7180.o +obj-$(CONFIG_INTERCONNECT_QCOM_SDM660) += qnoc-sdm660.o obj-$(CONFIG_INTERCONNECT_QCOM_SDM845) += qnoc-sdm845.o obj-$(CONFIG_INTERCONNECT_QCOM_SDX55) += qnoc-sdx55.o obj-$(CONFIG_INTERCONNECT_QCOM_SM8150) += qnoc-sm8150.o diff --git a/drivers/interconnect/qcom/sdm660.c b/drivers/interconnect/qcom/sdm660.c new file mode 100644 index 000000000000..6953d6d99a11 --- /dev/null +++ b/drivers/interconnect/qcom/sdm660.c @@ -0,0 +1,922 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Qualcomm SDM630/SDM636/SDM660 Network-on-Chip (NoC) QoS driver + * Copyright (C) 2020, AngeloGioacchino Del Regno + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "smd-rpm.h" + +#define RPM_BUS_MASTER_REQ 0x73616d62 +#define RPM_BUS_SLAVE_REQ 0x766c7362 + +/* BIMC QoS */ +#define M_BKE_REG_BASE(n) (0x300 + (0x4000 * n)) +#define M_BKE_EN_ADDR(n) (M_BKE_REG_BASE(n)) +#define M_BKE_HEALTH_CFG_ADDR(i, n) (M_BKE_REG_BASE(n) + 0x40 + (0x4 * i)) + +#define M_BKE_HEALTH_CFG_LIMITCMDS_MASK 0x80000000 +#define M_BKE_HEALTH_CFG_AREQPRIO_MASK 0x300 +#define M_BKE_HEALTH_CFG_PRIOLVL_MASK 0x3 +#define M_BKE_HEALTH_CFG_AREQPRIO_SHIFT 0x8 +#define M_BKE_HEALTH_CFG_LIMITCMDS_SHIFT 0x1f + +#define M_BKE_EN_EN_BMASK 0x1 + +/* Valid for both NoC and BIMC */ +#define NOC_QOS_MODE_FIXED 0x0 +#define NOC_QOS_MODE_LIMITER 0x1 +#define NOC_QOS_MODE_BYPASS 0x2 + +/* NoC QoS */ +#define NOC_PERM_MODE_FIXED 1 +#define NOC_PERM_MODE_BYPASS (1 << NOC_QOS_MODE_BYPASS) + +#define NOC_QOS_PRIORITYn_ADDR(n) (0x8 + (n * 0x1000)) +#define NOC_QOS_PRIORITY_MASK 0xf +#define NOC_QOS_PRIORITY_P1_SHIFT 0x2 +#define NOC_QOS_PRIORITY_P0_SHIFT 0x3 + +#define NOC_QOS_MODEn_ADDR(n) (0xc + (n * 0x1000)) +#define NOC_QOS_MODEn_MASK 0x3 + +enum { + SDM660_MASTER_IPA = 1, + SDM660_MASTER_CNOC_A2NOC, + SDM660_MASTER_SDCC_1, + SDM660_MASTER_SDCC_2, + SDM660_MASTER_BLSP_1, + SDM660_MASTER_BLSP_2, + SDM660_MASTER_UFS, + SDM660_MASTER_USB_HS, + SDM660_MASTER_USB3, + SDM660_MASTER_CRYPTO_C0, + SDM660_MASTER_GNOC_BIMC, + SDM660_MASTER_OXILI, + SDM660_MASTER_MNOC_BIMC, + SDM660_MASTER_SNOC_BIMC, + SDM660_MASTER_PIMEM, + SDM660_MASTER_SNOC_CNOC, + SDM660_MASTER_QDSS_DAP, + SDM660_MASTER_APPS_PROC, + SDM660_MASTER_CNOC_MNOC_MMSS_CFG, + SDM660_MASTER_CNOC_MNOC_CFG, + SDM660_MASTER_CPP, + SDM660_MASTER_JPEG, + SDM660_MASTER_MDP_P0, + SDM660_MASTER_MDP_P1, + SDM660_MASTER_VENUS, + SDM660_MASTER_VFE, + SDM660_MASTER_QDSS_ETR, + SDM660_MASTER_QDSS_BAM, + SDM660_MASTER_SNOC_CFG, + SDM660_MASTER_BIMC_SNOC, + SDM660_MASTER_A2NOC_SNOC, + SDM660_MASTER_GNOC_SNOC, + + SDM660_SLAVE_A2NOC_SNOC, + SDM660_SLAVE_EBI, + SDM660_SLAVE_HMSS_L3, + SDM660_SLAVE_BIMC_SNOC, + SDM660_SLAVE_CNOC_A2NOC, + SDM660_SLAVE_MPM, + SDM660_SLAVE_PMIC_ARB, + SDM660_SLAVE_TLMM_NORTH, + SDM660_SLAVE_TCSR, + SDM660_SLAVE_PIMEM_CFG, + SDM660_SLAVE_IMEM_CFG, + SDM660_SLAVE_MESSAGE_RAM, + SDM660_SLAVE_GLM, + SDM660_SLAVE_BIMC_CFG, + SDM660_SLAVE_PRNG, + SDM660_SLAVE_SPDM, + SDM660_SLAVE_QDSS_CFG, + SDM660_SLAVE_CNOC_MNOC_CFG, + SDM660_SLAVE_SNOC_CFG, + SDM660_SLAVE_QM_CFG, + SDM660_SLAVE_CLK_CTL, + SDM660_SLAVE_MSS_CFG, + SDM660_SLAVE_TLMM_SOUTH, + SDM660_SLAVE_UFS_CFG, + SDM660_SLAVE_A2NOC_CFG, + SDM660_SLAVE_A2NOC_SMMU_CFG, + SDM660_SLAVE_GPUSS_CFG, + SDM660_SLAVE_AHB2PHY, + SDM660_SLAVE_BLSP_1, + SDM660_SLAVE_SDCC_1, + SDM660_SLAVE_SDCC_2, + SDM660_SLAVE_TLMM_CENTER, + SDM660_SLAVE_BLSP_2, + SDM660_SLAVE_PDM, + SDM660_SLAVE_CNOC_MNOC_MMSS_CFG, + SDM660_SLAVE_USB_HS, + SDM660_SLAVE_USB3_0, + SDM660_SLAVE_SRVC_CNOC, + SDM660_SLAVE_GNOC_BIMC, + SDM660_SLAVE_GNOC_SNOC, + SDM660_SLAVE_CAMERA_CFG, + SDM660_SLAVE_CAMERA_THROTTLE_CFG, + SDM660_SLAVE_MISC_CFG, + SDM660_SLAVE_VENUS_THROTTLE_CFG, + SDM660_SLAVE_VENUS_CFG, + SDM660_SLAVE_MMSS_CLK_XPU_CFG, + SDM660_SLAVE_MMSS_CLK_CFG, + SDM660_SLAVE_MNOC_MPU_CFG, + SDM660_SLAVE_DISPLAY_CFG, + SDM660_SLAVE_CSI_PHY_CFG, + SDM660_SLAVE_DISPLAY_THROTTLE_CFG, + SDM660_SLAVE_SMMU_CFG, + SDM660_SLAVE_MNOC_BIMC, + SDM660_SLAVE_SRVC_MNOC, + SDM660_SLAVE_HMSS, + SDM660_SLAVE_LPASS, + SDM660_SLAVE_WLAN, + SDM660_SLAVE_CDSP, + SDM660_SLAVE_IPA, + SDM660_SLAVE_SNOC_BIMC, + SDM660_SLAVE_SNOC_CNOC, + SDM660_SLAVE_IMEM, + SDM660_SLAVE_PIMEM, + SDM660_SLAVE_QDSS_STM, + SDM660_SLAVE_SRVC_SNOC, + + SDM660_A2NOC, + SDM660_BIMC, + SDM660_CNOC, + SDM660_GNOC, + SDM660_MNOC, + SDM660_SNOC, +}; + +#define to_qcom_provider(_provider) \ + container_of(_provider, struct qcom_icc_provider, provider) + +static const struct clk_bulk_data bus_clocks[] = { + { .id = "bus" }, + { .id = "bus_a" }, +}; + +static const struct clk_bulk_data bus_mm_clocks[] = { + { .id = "bus" }, + { .id = "bus_a" }, + { .id = "iface" }, +}; + +/** + * struct qcom_icc_provider - Qualcomm specific interconnect provider + * @provider: generic interconnect provider + * @bus_clks: the clk_bulk_data table of bus clocks + * @num_clks: the total number of clk_bulk_data entries + * @is_bimc_node: indicates whether to use bimc specific setting + * @mmio: NoC base iospace + */ +struct qcom_icc_provider { + struct icc_provider provider; + struct clk_bulk_data *bus_clks; + int num_clks; + bool is_bimc_node; + struct regmap *regmap; + void __iomem *mmio; +}; + +#define SDM660_MAX_LINKS 34 + +/** + * struct qcom_icc_qos - Qualcomm specific interconnect QoS parameters + * @areq_prio: node requests priority + * @prio_level: priority level for bus communication + * @limit_commands: activate/deactivate limiter mode during runtime + * @ap_owned: indicates if the node is owned by the AP or by the RPM + * @qos_mode: default qos mode for this node + * @qos_port: qos port number for finding qos registers of this node + */ +struct qcom_icc_qos { + u32 areq_prio; + u32 prio_level; + bool limit_commands; + bool ap_owned; + int qos_mode; + int qos_port; +}; + +/** + * struct qcom_icc_node - Qualcomm specific interconnect nodes + * @name: the node name used in debugfs + * @id: a unique node identifier + * @links: an array of nodes where we can go next while traversing + * @num_links: the total number of @links + * @buswidth: width of the interconnect between a node and the bus (bytes) + * @mas_rpm_id: RPM id for devices that are bus masters + * @slv_rpm_id: RPM id for devices that are bus slaves + * @qos: NoC QoS setting parameters + * @rate: current bus clock rate in Hz + */ +struct qcom_icc_node { + unsigned char *name; + u16 id; + u16 links[SDM660_MAX_LINKS]; + u16 num_links; + u16 buswidth; + int mas_rpm_id; + int slv_rpm_id; + struct qcom_icc_qos qos; + u64 rate; +}; + +struct qcom_icc_desc { + struct qcom_icc_node **nodes; + size_t num_nodes; + const struct regmap_config *regmap_cfg; +}; + +#define DEFINE_QNODE(_name, _id, _buswidth, _mas_rpm_id, _slv_rpm_id, \ + _ap_owned, _qos_mode, _qos_prio, _qos_port, ...) \ + static struct qcom_icc_node _name = { \ + .name = #_name, \ + .id = _id, \ + .buswidth = _buswidth, \ + .mas_rpm_id = _mas_rpm_id, \ + .slv_rpm_id = _slv_rpm_id, \ + .qos.ap_owned = _ap_owned, \ + .qos.qos_mode = _qos_mode, \ + .qos.areq_prio = _qos_prio, \ + .qos.prio_level = _qos_prio, \ + .qos.qos_port = _qos_port, \ + .num_links = ARRAY_SIZE(((int[]){ __VA_ARGS__ })), \ + .links = { __VA_ARGS__ }, \ + } + +DEFINE_QNODE(mas_ipa, SDM660_MASTER_IPA, 8, 59, -1, true, NOC_QOS_MODE_FIXED, 1, 3, SDM660_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(mas_cnoc_a2noc, SDM660_MASTER_CNOC_A2NOC, 8, 146, -1, true, -1, 0, -1, SDM660_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(mas_sdcc_1, SDM660_MASTER_SDCC_1, 8, 33, -1, false, -1, 0, -1, SDM660_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(mas_sdcc_2, SDM660_MASTER_SDCC_2, 8, 35, -1, false, -1, 0, -1, SDM660_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(mas_blsp_1, SDM660_MASTER_BLSP_1, 4, 41, -1, false, -1, 0, -1, SDM660_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(mas_blsp_2, SDM660_MASTER_BLSP_2, 4, 39, -1, false, -1, 0, -1, SDM660_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(mas_ufs, SDM660_MASTER_UFS, 8, 68, -1, true, NOC_QOS_MODE_FIXED, 1, 4, SDM660_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(mas_usb_hs, SDM660_MASTER_USB_HS, 8, 42, -1, true, NOC_QOS_MODE_FIXED, 1, 1, SDM660_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(mas_usb3, SDM660_MASTER_USB3, 8, 32, -1, true, NOC_QOS_MODE_FIXED, 1, 2, SDM660_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(mas_crypto, SDM660_MASTER_CRYPTO_C0, 8, 23, -1, true, NOC_QOS_MODE_FIXED, 1, 11, SDM660_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(mas_gnoc_bimc, SDM660_MASTER_GNOC_BIMC, 4, 144, -1, true, NOC_QOS_MODE_FIXED, 0, 0, SDM660_SLAVE_EBI); +DEFINE_QNODE(mas_oxili, SDM660_MASTER_OXILI, 4, 6, -1, true, NOC_QOS_MODE_BYPASS, 0, 1, SDM660_SLAVE_HMSS_L3, SDM660_SLAVE_EBI, SDM660_SLAVE_BIMC_SNOC); +DEFINE_QNODE(mas_mnoc_bimc, SDM660_MASTER_MNOC_BIMC, 4, 2, -1, true, NOC_QOS_MODE_BYPASS, 0, 2, SDM660_SLAVE_HMSS_L3, SDM660_SLAVE_EBI, SDM660_SLAVE_BIMC_SNOC); +DEFINE_QNODE(mas_snoc_bimc, SDM660_MASTER_SNOC_BIMC, 4, 3, -1, false, -1, 0, -1, SDM660_SLAVE_HMSS_L3, SDM660_SLAVE_EBI); +DEFINE_QNODE(mas_pimem, SDM660_MASTER_PIMEM, 4, 113, -1, true, NOC_QOS_MODE_FIXED, 1, 4, SDM660_SLAVE_HMSS_L3, SDM660_SLAVE_EBI); +DEFINE_QNODE(mas_snoc_cnoc, SDM660_MASTER_SNOC_CNOC, 8, 52, -1, true, -1, 0, -1, SDM660_SLAVE_CLK_CTL, SDM660_SLAVE_QDSS_CFG, SDM660_SLAVE_QM_CFG, SDM660_SLAVE_SRVC_CNOC, SDM660_SLAVE_UFS_CFG, SDM660_SLAVE_TCSR, SDM660_SLAVE_A2NOC_SMMU_CFG, SDM660_SLAVE_SNOC_CFG, SDM660_SLAVE_TLMM_SOUTH, SDM660_SLAVE_MPM, SDM660_SLAVE_CNOC_MNOC_MMSS_CFG, SDM660_SLAVE_SDCC_2, SDM660_SLAVE_SDCC_1, SDM660_SLAVE_SPDM, SDM660_SLAVE_PMIC_ARB, SDM660_SLAVE_PRNG, SDM660_SLAVE_MSS_CFG, SDM660_SLAVE_GPUSS_CFG, SDM660_SLAVE_IMEM_CFG, SDM660_SLAVE_USB3_0, SDM660_SLAVE_A2NOC_CFG, SDM660_SLAVE_TLMM_NORTH, SDM660_SLAVE_USB_HS, SDM660_SLAVE_PDM, SDM660_SLAVE_TLMM_CENTER, SDM660_SLAVE_AHB2PHY, SDM660_SLAVE_BLSP_2, SDM660_SLAVE_BLSP_1, SDM660_SLAVE_PIMEM_CFG, SDM660_SLAVE_GLM, SDM660_SLAVE_MESSAGE_RAM, SDM660_SLAVE_BIMC_CFG, SDM660_SLAVE_CNOC_MNOC_CFG); +DEFINE_QNODE(mas_qdss_dap, SDM660_MASTER_QDSS_DAP, 8, 49, -1, true, -1, 0, -1, SDM660_SLAVE_CLK_CTL, SDM660_SLAVE_QDSS_CFG, SDM660_SLAVE_QM_CFG, SDM660_SLAVE_SRVC_CNOC, SDM660_SLAVE_UFS_CFG, SDM660_SLAVE_TCSR, SDM660_SLAVE_A2NOC_SMMU_CFG, SDM660_SLAVE_SNOC_CFG, SDM660_SLAVE_TLMM_SOUTH, SDM660_SLAVE_MPM, SDM660_SLAVE_CNOC_MNOC_MMSS_CFG, SDM660_SLAVE_SDCC_2, SDM660_SLAVE_SDCC_1, SDM660_SLAVE_SPDM, SDM660_SLAVE_PMIC_ARB, SDM660_SLAVE_PRNG, SDM660_SLAVE_MSS_CFG, SDM660_SLAVE_GPUSS_CFG, SDM660_SLAVE_IMEM_CFG, SDM660_SLAVE_USB3_0, SDM660_SLAVE_A2NOC_CFG, SDM660_SLAVE_TLMM_NORTH, SDM660_SLAVE_USB_HS, SDM660_SLAVE_PDM, SDM660_SLAVE_TLMM_CENTER, SDM660_SLAVE_AHB2PHY, SDM660_SLAVE_BLSP_2, SDM660_SLAVE_BLSP_1, SDM660_SLAVE_PIMEM_CFG, SDM660_SLAVE_GLM, SDM660_SLAVE_MESSAGE_RAM, SDM660_SLAVE_CNOC_A2NOC, SDM660_SLAVE_BIMC_CFG, SDM660_SLAVE_CNOC_MNOC_CFG); +DEFINE_QNODE(mas_apss_proc, SDM660_MASTER_APPS_PROC, 16, 0, -1, true, -1, 0, -1, SDM660_SLAVE_GNOC_SNOC, SDM660_SLAVE_GNOC_BIMC); +DEFINE_QNODE(mas_cnoc_mnoc_mmss_cfg, SDM660_MASTER_CNOC_MNOC_MMSS_CFG, 8, 4, -1, true, -1, 0, -1, SDM660_SLAVE_VENUS_THROTTLE_CFG, SDM660_SLAVE_VENUS_CFG, SDM660_SLAVE_CAMERA_THROTTLE_CFG, SDM660_SLAVE_SMMU_CFG, SDM660_SLAVE_CAMERA_CFG, SDM660_SLAVE_CSI_PHY_CFG, SDM660_SLAVE_DISPLAY_THROTTLE_CFG, SDM660_SLAVE_DISPLAY_CFG, SDM660_SLAVE_MMSS_CLK_CFG, SDM660_SLAVE_MNOC_MPU_CFG, SDM660_SLAVE_MISC_CFG, SDM660_SLAVE_MMSS_CLK_XPU_CFG); +DEFINE_QNODE(mas_cnoc_mnoc_cfg, SDM660_MASTER_CNOC_MNOC_CFG, 4, 5, -1, true, -1, 0, -1, SDM660_SLAVE_SRVC_MNOC); +DEFINE_QNODE(mas_cpp, SDM660_MASTER_CPP, 16, 115, -1, true, NOC_QOS_MODE_BYPASS, 0, 4, SDM660_SLAVE_MNOC_BIMC); +DEFINE_QNODE(mas_jpeg, SDM660_MASTER_JPEG, 16, 7, -1, true, NOC_QOS_MODE_BYPASS, 0, 6, SDM660_SLAVE_MNOC_BIMC); +DEFINE_QNODE(mas_mdp_p0, SDM660_MASTER_MDP_P0, 16, 8, -1, true, NOC_QOS_MODE_BYPASS, 0, 0, SDM660_SLAVE_MNOC_BIMC); /* vrail-comp???? */ +DEFINE_QNODE(mas_mdp_p1, SDM660_MASTER_MDP_P1, 16, 61, -1, true, NOC_QOS_MODE_BYPASS, 0, 1, SDM660_SLAVE_MNOC_BIMC); /* vrail-comp??? */ +DEFINE_QNODE(mas_venus, SDM660_MASTER_VENUS, 16, 9, -1, true, NOC_QOS_MODE_BYPASS, 0, 1, SDM660_SLAVE_MNOC_BIMC); +DEFINE_QNODE(mas_vfe, SDM660_MASTER_VFE, 16, 11, -1, true, NOC_QOS_MODE_BYPASS, 0, 5, SDM660_SLAVE_MNOC_BIMC); +DEFINE_QNODE(mas_qdss_etr, SDM660_MASTER_QDSS_ETR, 8, 31, -1, true, NOC_QOS_MODE_FIXED, 1, 1, SDM660_SLAVE_PIMEM, SDM660_SLAVE_IMEM, SDM660_SLAVE_SNOC_CNOC, SDM660_SLAVE_SNOC_BIMC); +DEFINE_QNODE(mas_qdss_bam, SDM660_MASTER_QDSS_BAM, 4, 19, -1, true, NOC_QOS_MODE_FIXED, 1, 0, SDM660_SLAVE_PIMEM, SDM660_SLAVE_IMEM, SDM660_SLAVE_SNOC_CNOC, SDM660_SLAVE_SNOC_BIMC); +DEFINE_QNODE(mas_snoc_cfg, SDM660_MASTER_SNOC_CFG, 4, 20, -1, false, -1, 0, -1, SDM660_SLAVE_SRVC_SNOC); +DEFINE_QNODE(mas_bimc_snoc, SDM660_MASTER_BIMC_SNOC, 8, 21, -1, false, -1, 0, -1, SDM660_SLAVE_PIMEM, SDM660_SLAVE_IPA, SDM660_SLAVE_QDSS_STM, SDM660_SLAVE_LPASS, SDM660_SLAVE_HMSS, SDM660_SLAVE_CDSP, SDM660_SLAVE_SNOC_CNOC, SDM660_SLAVE_WLAN, SDM660_SLAVE_IMEM); +DEFINE_QNODE(mas_gnoc_snoc, SDM660_MASTER_GNOC_SNOC, 8, 150, -1, false, -1, 0, -1, SDM660_SLAVE_PIMEM, SDM660_SLAVE_IPA, SDM660_SLAVE_QDSS_STM, SDM660_SLAVE_LPASS, SDM660_SLAVE_HMSS, SDM660_SLAVE_CDSP, SDM660_SLAVE_SNOC_CNOC, SDM660_SLAVE_WLAN, SDM660_SLAVE_IMEM); +DEFINE_QNODE(mas_a2noc_snoc, SDM660_MASTER_A2NOC_SNOC, 16, 112, -1, false, -1, 0, -1, SDM660_SLAVE_PIMEM, SDM660_SLAVE_IPA, SDM660_SLAVE_QDSS_STM, SDM660_SLAVE_LPASS, SDM660_SLAVE_HMSS, SDM660_SLAVE_SNOC_BIMC, SDM660_SLAVE_CDSP, SDM660_SLAVE_SNOC_CNOC, SDM660_SLAVE_WLAN, SDM660_SLAVE_IMEM); +DEFINE_QNODE(slv_a2noc_snoc, SDM660_SLAVE_A2NOC_SNOC, 16, -1, 143, false, -1, 0, -1, SDM660_MASTER_A2NOC_SNOC); +DEFINE_QNODE(slv_ebi, SDM660_SLAVE_EBI, 4, -1, 0, false, -1, 0, -1, 0); +DEFINE_QNODE(slv_hmss_l3, SDM660_SLAVE_HMSS_L3, 4, -1, 160, false, -1, 0, -1, 0); +DEFINE_QNODE(slv_bimc_snoc, SDM660_SLAVE_BIMC_SNOC, 4, -1, 2, false, -1, 0, -1, SDM660_MASTER_BIMC_SNOC); +DEFINE_QNODE(slv_cnoc_a2noc, SDM660_SLAVE_CNOC_A2NOC, 8, -1, 208, true, -1, 0, -1, SDM660_MASTER_CNOC_A2NOC); +DEFINE_QNODE(slv_mpm, SDM660_SLAVE_MPM, 4, -1, 62, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_pmic_arb, SDM660_SLAVE_PMIC_ARB, 4, -1, 59, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_tlmm_north, SDM660_SLAVE_TLMM_NORTH, 8, -1, 214, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_tcsr, SDM660_SLAVE_TCSR, 4, -1, 50, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_pimem_cfg, SDM660_SLAVE_PIMEM_CFG, 4, -1, 167, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_imem_cfg, SDM660_SLAVE_IMEM_CFG, 4, -1, 54, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_message_ram, SDM660_SLAVE_MESSAGE_RAM, 4, -1, 55, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_glm, SDM660_SLAVE_GLM, 4, -1, 209, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_bimc_cfg, SDM660_SLAVE_BIMC_CFG, 4, -1, 56, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_prng, SDM660_SLAVE_PRNG, 4, -1, 44, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_spdm, SDM660_SLAVE_SPDM, 4, -1, 60, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_qdss_cfg, SDM660_SLAVE_QDSS_CFG, 4, -1, 63, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_cnoc_mnoc_cfg, SDM660_SLAVE_BLSP_1, 4, -1, 66, true, -1, 0, -1, SDM660_MASTER_CNOC_MNOC_CFG); +DEFINE_QNODE(slv_snoc_cfg, SDM660_SLAVE_SNOC_CFG, 4, -1, 70, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_qm_cfg, SDM660_SLAVE_QM_CFG, 4, -1, 212, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_clk_ctl, SDM660_SLAVE_CLK_CTL, 4, -1, 47, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_mss_cfg, SDM660_SLAVE_MSS_CFG, 4, -1, 48, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_tlmm_south, SDM660_SLAVE_TLMM_SOUTH, 4, -1, 217, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_ufs_cfg, SDM660_SLAVE_UFS_CFG, 4, -1, 92, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_a2noc_cfg, SDM660_SLAVE_A2NOC_CFG, 4, -1, 150, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_a2noc_smmu_cfg, SDM660_SLAVE_A2NOC_SMMU_CFG, 8, -1, 152, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_gpuss_cfg, SDM660_SLAVE_GPUSS_CFG, 8, -1, 11, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_ahb2phy, SDM660_SLAVE_AHB2PHY, 4, -1, 163, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_blsp_1, SDM660_SLAVE_BLSP_1, 4, -1, 39, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_sdcc_1, SDM660_SLAVE_SDCC_1, 4, -1, 31, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_sdcc_2, SDM660_SLAVE_SDCC_2, 4, -1, 33, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_tlmm_center, SDM660_SLAVE_TLMM_CENTER, 4, -1, 218, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_blsp_2, SDM660_SLAVE_BLSP_2, 4, -1, 37, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_pdm, SDM660_SLAVE_PDM, 4, -1, 41, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_cnoc_mnoc_mmss_cfg, SDM660_SLAVE_CNOC_MNOC_MMSS_CFG, 8, -1, 58, true, -1, 0, -1, SDM660_MASTER_CNOC_MNOC_MMSS_CFG); +DEFINE_QNODE(slv_usb_hs, SDM660_SLAVE_USB_HS, 4, -1, 40, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_usb3_0, SDM660_SLAVE_USB3_0, 4, -1, 22, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_srvc_cnoc, SDM660_SLAVE_SRVC_CNOC, 4, -1, 76, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_gnoc_bimc, SDM660_SLAVE_GNOC_BIMC, 16, -1, 210, true, -1, 0, -1, SDM660_MASTER_GNOC_BIMC); +DEFINE_QNODE(slv_gnoc_snoc, SDM660_SLAVE_GNOC_SNOC, 8, -1, 211, true, -1, 0, -1, SDM660_MASTER_GNOC_SNOC); +DEFINE_QNODE(slv_camera_cfg, SDM660_SLAVE_CAMERA_CFG, 4, -1, 3, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_camera_throttle_cfg, SDM660_SLAVE_CAMERA_THROTTLE_CFG, 4, -1, 154, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_misc_cfg, SDM660_SLAVE_MISC_CFG, 4, -1, 8, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_venus_throttle_cfg, SDM660_SLAVE_VENUS_THROTTLE_CFG, 4, -1, 178, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_venus_cfg, SDM660_SLAVE_VENUS_CFG, 4, -1, 10, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_mmss_clk_xpu_cfg, SDM660_SLAVE_MMSS_CLK_XPU_CFG, 4, -1, 13, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_mmss_clk_cfg, SDM660_SLAVE_MMSS_CLK_CFG, 4, -1, 12, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_mnoc_mpu_cfg, SDM660_SLAVE_MNOC_MPU_CFG, 4, -1, 14, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_display_cfg, SDM660_SLAVE_DISPLAY_CFG, 4, -1, 4, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_csi_phy_cfg, SDM660_SLAVE_CSI_PHY_CFG, 4, -1, 224, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_display_throttle_cfg, SDM660_SLAVE_DISPLAY_THROTTLE_CFG, 4, -1, 156, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_smmu_cfg, SDM660_SLAVE_SMMU_CFG, 8, -1, 205, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_mnoc_bimc, SDM660_SLAVE_MNOC_BIMC, 16, -1, 16, true, -1, 0, -1, SDM660_MASTER_MNOC_BIMC); +DEFINE_QNODE(slv_srvc_mnoc, SDM660_SLAVE_SRVC_MNOC, 8, -1, 17, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_hmss, SDM660_SLAVE_HMSS, 8, -1, 20, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_lpass, SDM660_SLAVE_LPASS, 4, -1, 21, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_wlan, SDM660_SLAVE_WLAN, 4, -1, 206, false, -1, 0, -1, 0); +DEFINE_QNODE(slv_cdsp, SDM660_SLAVE_CDSP, 4, -1, 221, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_ipa, SDM660_SLAVE_IPA, 4, -1, 183, true, -1, 0, -1, 0); +DEFINE_QNODE(slv_snoc_bimc, SDM660_SLAVE_SNOC_BIMC, 16, -1, 24, false, -1, 0, -1, SDM660_MASTER_SNOC_BIMC); +DEFINE_QNODE(slv_snoc_cnoc, SDM660_SLAVE_SNOC_CNOC, 8, -1, 25, false, -1, 0, -1, SDM660_MASTER_SNOC_CNOC); +DEFINE_QNODE(slv_imem, SDM660_SLAVE_IMEM, 8, -1, 26, false, -1, 0, -1, 0); +DEFINE_QNODE(slv_pimem, SDM660_SLAVE_PIMEM, 8, -1, 166, false, -1, 0, -1, 0); +DEFINE_QNODE(slv_qdss_stm, SDM660_SLAVE_QDSS_STM, 4, -1, 30, false, -1, 0, -1, 0); +DEFINE_QNODE(slv_srvc_snoc, SDM660_SLAVE_SRVC_SNOC, 16, -1, 29, false, -1, 0, -1, 0); + +static struct qcom_icc_node *sdm660_a2noc_nodes[] = { + [MASTER_IPA] = &mas_ipa, + [MASTER_CNOC_A2NOC] = &mas_cnoc_a2noc, + [MASTER_SDCC_1] = &mas_sdcc_1, + [MASTER_SDCC_2] = &mas_sdcc_2, + [MASTER_BLSP_1] = &mas_blsp_1, + [MASTER_BLSP_2] = &mas_blsp_2, + [MASTER_UFS] = &mas_ufs, + [MASTER_USB_HS] = &mas_usb_hs, + [MASTER_USB3] = &mas_usb3, + [MASTER_CRYPTO_C0] = &mas_crypto, + [SLAVE_A2NOC_SNOC] = &slv_a2noc_snoc, +}; + +static const struct regmap_config sdm660_a2noc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x20000, + .fast_io = true, +}; + +static struct qcom_icc_desc sdm660_a2noc = { + .nodes = sdm660_a2noc_nodes, + .num_nodes = ARRAY_SIZE(sdm660_a2noc_nodes), + .regmap_cfg = &sdm660_a2noc_regmap_config, +}; + +static struct qcom_icc_node *sdm660_bimc_nodes[] = { + [MASTER_GNOC_BIMC] = &mas_gnoc_bimc, + [MASTER_OXILI] = &mas_oxili, + [MASTER_MNOC_BIMC] = &mas_mnoc_bimc, + [MASTER_SNOC_BIMC] = &mas_snoc_bimc, + [MASTER_PIMEM] = &mas_pimem, + [SLAVE_EBI] = &slv_ebi, + [SLAVE_HMSS_L3] = &slv_hmss_l3, + [SLAVE_BIMC_SNOC] = &slv_bimc_snoc, +}; + +static const struct regmap_config sdm660_bimc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x80000, + .fast_io = true, +}; + +static struct qcom_icc_desc sdm660_bimc = { + .nodes = sdm660_bimc_nodes, + .num_nodes = ARRAY_SIZE(sdm660_bimc_nodes), + .regmap_cfg = &sdm660_bimc_regmap_config, +}; + +static struct qcom_icc_node *sdm660_cnoc_nodes[] = { + [MASTER_SNOC_CNOC] = &mas_snoc_cnoc, + [MASTER_QDSS_DAP] = &mas_qdss_dap, + [SLAVE_CNOC_A2NOC] = &slv_cnoc_a2noc, + [SLAVE_MPM] = &slv_mpm, + [SLAVE_PMIC_ARB] = &slv_pmic_arb, + [SLAVE_TLMM_NORTH] = &slv_tlmm_north, + [SLAVE_TCSR] = &slv_tcsr, + [SLAVE_PIMEM_CFG] = &slv_pimem_cfg, + [SLAVE_IMEM_CFG] = &slv_imem_cfg, + [SLAVE_MESSAGE_RAM] = &slv_message_ram, + [SLAVE_GLM] = &slv_glm, + [SLAVE_BIMC_CFG] = &slv_bimc_cfg, + [SLAVE_PRNG] = &slv_prng, + [SLAVE_SPDM] = &slv_spdm, + [SLAVE_QDSS_CFG] = &slv_qdss_cfg, + [SLAVE_CNOC_MNOC_CFG] = &slv_cnoc_mnoc_cfg, + [SLAVE_SNOC_CFG] = &slv_snoc_cfg, + [SLAVE_QM_CFG] = &slv_qm_cfg, + [SLAVE_CLK_CTL] = &slv_clk_ctl, + [SLAVE_MSS_CFG] = &slv_mss_cfg, + [SLAVE_TLMM_SOUTH] = &slv_tlmm_south, + [SLAVE_UFS_CFG] = &slv_ufs_cfg, + [SLAVE_A2NOC_CFG] = &slv_a2noc_cfg, + [SLAVE_A2NOC_SMMU_CFG] = &slv_a2noc_smmu_cfg, + [SLAVE_GPUSS_CFG] = &slv_gpuss_cfg, + [SLAVE_AHB2PHY] = &slv_ahb2phy, + [SLAVE_BLSP_1] = &slv_blsp_1, + [SLAVE_SDCC_1] = &slv_sdcc_1, + [SLAVE_SDCC_2] = &slv_sdcc_2, + [SLAVE_TLMM_CENTER] = &slv_tlmm_center, + [SLAVE_BLSP_2] = &slv_blsp_2, + [SLAVE_PDM] = &slv_pdm, + [SLAVE_CNOC_MNOC_MMSS_CFG] = &slv_cnoc_mnoc_mmss_cfg, + [SLAVE_USB_HS] = &slv_usb_hs, + [SLAVE_USB3_0] = &slv_usb3_0, + [SLAVE_SRVC_CNOC] = &slv_srvc_cnoc, +}; + +static const struct regmap_config sdm660_cnoc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x10000, + .fast_io = true, +}; + +static struct qcom_icc_desc sdm660_cnoc = { + .nodes = sdm660_cnoc_nodes, + .num_nodes = ARRAY_SIZE(sdm660_cnoc_nodes), + .regmap_cfg = &sdm660_cnoc_regmap_config, +}; + +static struct qcom_icc_node *sdm660_gnoc_nodes[] = { + [MASTER_APSS_PROC] = &mas_apss_proc, + [SLAVE_GNOC_BIMC] = &slv_gnoc_bimc, + [SLAVE_GNOC_SNOC] = &slv_gnoc_snoc, +}; + +static const struct regmap_config sdm660_gnoc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xe000, + .fast_io = true, +}; + +static struct qcom_icc_desc sdm660_gnoc = { + .nodes = sdm660_gnoc_nodes, + .num_nodes = ARRAY_SIZE(sdm660_gnoc_nodes), + .regmap_cfg = &sdm660_gnoc_regmap_config, +}; + +static struct qcom_icc_node *sdm660_mnoc_nodes[] = { + [MASTER_CPP] = &mas_cpp, + [MASTER_JPEG] = &mas_jpeg, + [MASTER_MDP_P0] = &mas_mdp_p0, + [MASTER_MDP_P1] = &mas_mdp_p1, + [MASTER_VENUS] = &mas_venus, + [MASTER_VFE] = &mas_vfe, + [MASTER_CNOC_MNOC_MMSS_CFG] = &mas_cnoc_mnoc_mmss_cfg, + [MASTER_CNOC_MNOC_CFG] = &mas_cnoc_mnoc_cfg, + [SLAVE_CAMERA_CFG] = &slv_camera_cfg, + [SLAVE_CAMERA_THROTTLE_CFG] = &slv_camera_throttle_cfg, + [SLAVE_MISC_CFG] = &slv_misc_cfg, + [SLAVE_VENUS_THROTTLE_CFG] = &slv_venus_throttle_cfg, + [SLAVE_VENUS_CFG] = &slv_venus_cfg, + [SLAVE_MMSS_CLK_XPU_CFG] = &slv_mmss_clk_xpu_cfg, + [SLAVE_MMSS_CLK_CFG] = &slv_mmss_clk_cfg, + [SLAVE_MNOC_MPU_CFG] = &slv_mnoc_mpu_cfg, + [SLAVE_DISPLAY_CFG] = &slv_display_cfg, + [SLAVE_CSI_PHY_CFG] = &slv_csi_phy_cfg, + [SLAVE_DISPLAY_THROTTLE_CFG] = &slv_display_throttle_cfg, + [SLAVE_SMMU_CFG] = &slv_smmu_cfg, + [SLAVE_SRVC_MNOC] = &slv_srvc_mnoc, + [SLAVE_MNOC_BIMC] = &slv_mnoc_bimc, +}; + +static const struct regmap_config sdm660_mnoc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x10000, + .fast_io = true, +}; + +static struct qcom_icc_desc sdm660_mnoc = { + .nodes = sdm660_mnoc_nodes, + .num_nodes = ARRAY_SIZE(sdm660_mnoc_nodes), + .regmap_cfg = &sdm660_mnoc_regmap_config, +}; + +static struct qcom_icc_node *sdm660_snoc_nodes[] = { + [MASTER_QDSS_ETR] = &mas_qdss_etr, + [MASTER_QDSS_BAM] = &mas_qdss_bam, + [MASTER_SNOC_CFG] = &mas_snoc_cfg, + [MASTER_BIMC_SNOC] = &mas_bimc_snoc, + [MASTER_A2NOC_SNOC] = &mas_a2noc_snoc, + [MASTER_GNOC_SNOC] = &mas_gnoc_snoc, + [SLAVE_HMSS] = &slv_hmss, + [SLAVE_LPASS] = &slv_lpass, + [SLAVE_WLAN] = &slv_wlan, + [SLAVE_CDSP] = &slv_cdsp, + [SLAVE_IPA] = &slv_ipa, + [SLAVE_SNOC_BIMC] = &slv_snoc_bimc, + [SLAVE_SNOC_CNOC] = &slv_snoc_cnoc, + [SLAVE_IMEM] = &slv_imem, + [SLAVE_PIMEM] = &slv_pimem, + [SLAVE_QDSS_STM] = &slv_qdss_stm, + [SLAVE_SRVC_SNOC] = &slv_srvc_snoc, +}; + +static const struct regmap_config sdm660_snoc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x20000, + .fast_io = true, +}; + +static struct qcom_icc_desc sdm660_snoc = { + .nodes = sdm660_snoc_nodes, + .num_nodes = ARRAY_SIZE(sdm660_snoc_nodes), + .regmap_cfg = &sdm660_snoc_regmap_config, +}; + +static int qcom_icc_bimc_set_qos_health(struct regmap *rmap, + struct qcom_icc_qos *qos, + int regnum) +{ + u32 val; + u32 mask; + + val = qos->prio_level; + mask = M_BKE_HEALTH_CFG_PRIOLVL_MASK; + + val |= qos->areq_prio << M_BKE_HEALTH_CFG_AREQPRIO_SHIFT; + mask |= M_BKE_HEALTH_CFG_AREQPRIO_MASK; + + /* LIMITCMDS is not present on M_BKE_HEALTH_3 */ + if (regnum != 3) { + val |= qos->limit_commands << M_BKE_HEALTH_CFG_LIMITCMDS_SHIFT; + mask |= M_BKE_HEALTH_CFG_LIMITCMDS_MASK; + } + + return regmap_update_bits(rmap, + M_BKE_HEALTH_CFG_ADDR(regnum, qos->qos_port), + mask, val); +} + +static int qcom_icc_set_bimc_qos(struct icc_node *src, u64 max_bw, + bool bypass_mode) +{ + struct qcom_icc_provider *qp; + struct qcom_icc_node *qn; + struct icc_provider *provider; + u32 mode = NOC_QOS_MODE_BYPASS; + u32 val = 0; + int i, rc = 0; + + qn = src->data; + provider = src->provider; + qp = to_qcom_provider(provider); + + if (qn->qos.qos_mode != -1) + mode = qn->qos.qos_mode; + + /* QoS Priority: The QoS Health parameters are getting considered + * only if we are NOT in Bypass Mode. + */ + if (mode != NOC_QOS_MODE_BYPASS) { + for (i = 3; i >= 0; i--) { + rc = qcom_icc_bimc_set_qos_health(qp->regmap, + &qn->qos, i); + if (rc) + return rc; + } + + /* Set BKE_EN to 1 when Fixed, Regulator or Limiter Mode */ + val = 1; + } + + return regmap_update_bits(qp->regmap, M_BKE_EN_ADDR(qn->qos.qos_port), + M_BKE_EN_EN_BMASK, val); +} + +static int qcom_icc_noc_set_qos_priority(struct regmap *rmap, + struct qcom_icc_qos *qos) +{ + u32 val; + int rc; + + /* Must be updated one at a time, P1 first, P0 last */ + val = qos->areq_prio << NOC_QOS_PRIORITY_P1_SHIFT; + rc = regmap_update_bits(rmap, NOC_QOS_PRIORITYn_ADDR(qos->qos_port), + NOC_QOS_PRIORITY_MASK, val); + if (rc) + return rc; + + val = qos->prio_level << NOC_QOS_PRIORITY_P0_SHIFT; + return regmap_update_bits(rmap, NOC_QOS_PRIORITYn_ADDR(qos->qos_port), + NOC_QOS_PRIORITY_MASK, val); +} + +static int qcom_icc_set_noc_qos(struct icc_node *src, u64 max_bw) +{ + struct qcom_icc_provider *qp; + struct qcom_icc_node *qn; + struct icc_provider *provider; + u32 mode = NOC_QOS_MODE_BYPASS; + int rc = 0; + + qn = src->data; + provider = src->provider; + qp = to_qcom_provider(provider); + + if (qn->qos.qos_port < 0) { + dev_dbg(src->provider->dev, + "NoC QoS: Skipping %s: vote aggregated on parent.\n", + qn->name); + return 0; + } + + if (qn->qos.qos_mode != -1) + mode = qn->qos.qos_mode; + + if (mode == NOC_QOS_MODE_FIXED) { + dev_dbg(src->provider->dev, "NoC QoS: %s: Set Fixed mode\n", + qn->name); + rc = qcom_icc_noc_set_qos_priority(qp->regmap, &qn->qos); + if (rc) + return rc; + } else if (mode == NOC_QOS_MODE_BYPASS) { + dev_dbg(src->provider->dev, "NoC QoS: %s: Set Bypass mode\n", + qn->name); + } + + return regmap_update_bits(qp->regmap, + NOC_QOS_MODEn_ADDR(qn->qos.qos_port), + NOC_QOS_MODEn_MASK, mode); +} + +static int qcom_icc_qos_set(struct icc_node *node, u64 sum_bw) +{ + struct qcom_icc_provider *qp = to_qcom_provider(node->provider); + struct qcom_icc_node *qn = node->data; + + dev_dbg(node->provider->dev, "Setting QoS for %s\n", qn->name); + + if (qp->is_bimc_node) + return qcom_icc_set_bimc_qos(node, sum_bw, + (qn->qos.qos_mode == NOC_QOS_MODE_BYPASS)); + + return qcom_icc_set_noc_qos(node, sum_bw); +} + +static int qcom_icc_rpm_set(int mas_rpm_id, int slv_rpm_id, u64 sum_bw) +{ + int ret = 0; + + if (mas_rpm_id != -1) { + ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE, + RPM_BUS_MASTER_REQ, + mas_rpm_id, + sum_bw); + if (ret) { + pr_err("qcom_icc_rpm_smd_send mas %d error %d\n", + mas_rpm_id, ret); + return ret; + } + } + + if (slv_rpm_id != -1) { + ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE, + RPM_BUS_SLAVE_REQ, + slv_rpm_id, + sum_bw); + if (ret) { + pr_err("qcom_icc_rpm_smd_send slv %d error %d\n", + slv_rpm_id, ret); + return ret; + } + } + + return ret; +} + +static int qcom_icc_set(struct icc_node *src, struct icc_node *dst) +{ + struct qcom_icc_provider *qp; + struct qcom_icc_node *qn; + struct icc_provider *provider; + struct icc_node *n; + u64 sum_bw; + u64 max_peak_bw; + u64 rate; + u32 agg_avg = 0; + u32 agg_peak = 0; + int ret, i; + + qn = src->data; + provider = src->provider; + qp = to_qcom_provider(provider); + + list_for_each_entry(n, &provider->nodes, node_list) + provider->aggregate(n, 0, n->avg_bw, n->peak_bw, + &agg_avg, &agg_peak); + + sum_bw = icc_units_to_bps(agg_avg); + max_peak_bw = icc_units_to_bps(agg_peak); + + if (!qn->qos.ap_owned) { + /* send bandwidth request message to the RPM processor */ + ret = qcom_icc_rpm_set(qn->mas_rpm_id, qn->slv_rpm_id, sum_bw); + if (ret) + return ret; + } else if (qn->qos.qos_mode != -1) { + /* set bandwidth directly from the AP */ + ret = qcom_icc_qos_set(src, sum_bw); + if (ret) + return ret; + } + + rate = max(sum_bw, max_peak_bw); + + do_div(rate, qn->buswidth); + + if (qn->rate == rate) + return 0; + + for (i = 0; i < qp->num_clks; i++) { + ret = clk_set_rate(qp->bus_clks[i].clk, rate); + if (ret) { + pr_err("%s clk_set_rate error: %d\n", + qp->bus_clks[i].id, ret); + return ret; + } + } + + qn->rate = rate; + + return 0; +} + +static int qnoc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct qcom_icc_desc *desc; + struct icc_onecell_data *data; + struct icc_provider *provider; + struct qcom_icc_node **qnodes; + struct qcom_icc_provider *qp; + struct icc_node *node; + struct resource *res; + size_t num_nodes, i; + int ret; + + /* wait for the RPM proxy */ + if (!qcom_icc_rpm_smd_available()) + return -EPROBE_DEFER; + + desc = of_device_get_match_data(dev); + if (!desc) + return -EINVAL; + + qnodes = desc->nodes; + num_nodes = desc->num_nodes; + + qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL); + if (!qp) + return -ENOMEM; + + data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + if (of_device_is_compatible(dev->of_node, "qcom,sdm660-mnoc")) { + qp->bus_clks = devm_kmemdup(dev, bus_mm_clocks, + sizeof(bus_mm_clocks), GFP_KERNEL); + qp->num_clks = ARRAY_SIZE(bus_mm_clocks); + } else { + if (of_device_is_compatible(dev->of_node, "qcom,sdm660-bimc")) + qp->is_bimc_node = true; + + qp->bus_clks = devm_kmemdup(dev, bus_clocks, sizeof(bus_clocks), + GFP_KERNEL); + qp->num_clks = ARRAY_SIZE(bus_clocks); + } + if (!qp->bus_clks) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + qp->mmio = devm_ioremap_resource(dev, res); + if (IS_ERR(qp->mmio)) { + dev_err(dev, "Cannot ioremap interconnect bus resource\n"); + return PTR_ERR(qp->mmio); + } + + qp->regmap = devm_regmap_init_mmio(dev, qp->mmio, desc->regmap_cfg); + if (IS_ERR(qp->regmap)) { + dev_err(dev, "Cannot regmap interconnect bus resource\n"); + return PTR_ERR(qp->regmap); + } + + ret = devm_clk_bulk_get(dev, qp->num_clks, qp->bus_clks); + if (ret) + return ret; + + ret = clk_bulk_prepare_enable(qp->num_clks, qp->bus_clks); + if (ret) + return ret; + + provider = &qp->provider; + INIT_LIST_HEAD(&provider->nodes); + provider->dev = dev; + provider->set = qcom_icc_set; + provider->aggregate = icc_std_aggregate; + provider->xlate = of_icc_xlate_onecell; + provider->data = data; + + ret = icc_provider_add(provider); + if (ret) { + dev_err(dev, "error adding interconnect provider: %d\n", ret); + clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); + return ret; + } + + for (i = 0; i < num_nodes; i++) { + size_t j; + + node = icc_node_create(qnodes[i]->id); + if (IS_ERR(node)) { + ret = PTR_ERR(node); + goto err; + } + + node->name = qnodes[i]->name; + node->data = qnodes[i]; + icc_node_add(node, provider); + + for (j = 0; j < qnodes[i]->num_links; j++) + icc_link_create(node, qnodes[i]->links[j]); + + data->nodes[i] = node; + } + data->num_nodes = num_nodes; + platform_set_drvdata(pdev, qp); + + return 0; +err: + icc_nodes_remove(provider); + clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); + icc_provider_del(provider); + + return ret; +} + +static int qnoc_remove(struct platform_device *pdev) +{ + struct qcom_icc_provider *qp = platform_get_drvdata(pdev); + + icc_nodes_remove(&qp->provider); + clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); + return icc_provider_del(&qp->provider); +} + +static const struct of_device_id sdm660_noc_of_match[] = { + { .compatible = "qcom,sdm660-a2noc", .data = &sdm660_a2noc }, + { .compatible = "qcom,sdm660-bimc", .data = &sdm660_bimc }, + { .compatible = "qcom,sdm660-cnoc", .data = &sdm660_cnoc }, + { .compatible = "qcom,sdm660-gnoc", .data = &sdm660_gnoc }, + { .compatible = "qcom,sdm660-mnoc", .data = &sdm660_mnoc }, + { .compatible = "qcom,sdm660-snoc", .data = &sdm660_snoc }, + { }, +}; +MODULE_DEVICE_TABLE(of, sdm660_noc_of_match); + +static struct platform_driver sdm660_noc_driver = { + .probe = qnoc_probe, + .remove = qnoc_remove, + .driver = { + .name = "qnoc-sdm660", + .of_match_table = sdm660_noc_of_match, + }, +}; +module_platform_driver(sdm660_noc_driver); +MODULE_DESCRIPTION("Qualcomm sdm660 NoC driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 9b4ab638c49ef6ea5f2f47bc5ce3eef3c9bb6e2d Mon Sep 17 00:00:00 2001 From: Benjamin Li Date: Mon, 8 Mar 2021 15:13:40 +0200 Subject: interconnect: qcom: icc-rpm: record slave RPM id in error log Add slave RPM ID to assist with identifying incorrect RPM config. Signed-off-by: Benjamin Li Reviewed-by: Jun Nie Link: https://lore.kernel.org/r/20210205015205.22947-2-benl@squareup.com Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/icc-rpm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/interconnect/qcom/icc-rpm.c b/drivers/interconnect/qcom/icc-rpm.c index cc6095492cbe..54de49ca7808 100644 --- a/drivers/interconnect/qcom/icc-rpm.c +++ b/drivers/interconnect/qcom/icc-rpm.c @@ -59,8 +59,8 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst) qn->slv_rpm_id, sum_bw); if (ret) { - pr_err("qcom_icc_rpm_smd_send slv error %d\n", - ret); + pr_err("qcom_icc_rpm_smd_send slv %d error %d\n", + qn->slv_rpm_id, ret); return ret; } } -- cgit v1.2.3 From fb11de92ac6e4af0b22a79b93602b175603cd30a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 16 Feb 2021 16:04:10 +0100 Subject: virtio_console: remove pointless check for debugfs_create_dir() It is impossible for debugfs_create_dir() to return NULL, so checking for it gives people a false sense that they actually are doing something if an error occurs. As there is no need to ever change kernel logic if debugfs is working "properly" or not, there is no need to check the return value of debugfs calls, so remove the checks here as they will never be triggered and are wrong. Cc: Amit Shah Cc: Arnd Bergmann Cc: virtualization@lists.linux-foundation.org Cc: linux-kernel@vger.kernel.org Reviewed-by: Amit Shah Link: https://lore.kernel.org/r/20210216150410.3844635-1-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- drivers/char/virtio_console.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 1836cc56e357..59dfd9c421a1 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1456,18 +1456,15 @@ static int add_port(struct ports_device *portdev, u32 id) */ send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); - if (pdrvdata.debugfs_dir) { - /* - * Finally, create the debugfs file that we can use to - * inspect a port's state at any time - */ - snprintf(debugfs_name, sizeof(debugfs_name), "vport%up%u", - port->portdev->vdev->index, id); - port->debugfs_file = debugfs_create_file(debugfs_name, 0444, - pdrvdata.debugfs_dir, - port, - &port_debugfs_fops); - } + /* + * Finally, create the debugfs file that we can use to + * inspect a port's state at any time + */ + snprintf(debugfs_name, sizeof(debugfs_name), "vport%up%u", + port->portdev->vdev->index, id); + port->debugfs_file = debugfs_create_file(debugfs_name, 0444, + pdrvdata.debugfs_dir, + port, &port_debugfs_fops); return 0; free_inbufs: @@ -2244,8 +2241,6 @@ static int __init init(void) } pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL); - if (!pdrvdata.debugfs_dir) - pr_warn("Error creating debugfs dir for virtio-ports\n"); INIT_LIST_HEAD(&pdrvdata.consoles); INIT_LIST_HEAD(&pdrvdata.portdevs); -- cgit v1.2.3 From 37b85bd5f20cbe28140d370a840738b6f2e85cbf Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 16 Feb 2021 16:12:09 +0100 Subject: drivers: vmw_balloon: remove dentry pointer for debugfs There is no need to keep the dentry pointer around for the created debugfs file, as it is only needed when removing it from the system. When it is to be removed, ask debugfs itself for the pointer, to save on storage and make things a bit simpler. Cc: Nadav Amit Cc: "VMware, Inc." Cc: Arnd Bergmann Cc: linux-kernel@vger.kernel.org Acked-by: Nadav Amit Link: https://lore.kernel.org/r/20210216151209.3954129-1-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_balloon.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index b837e7eba5f7..f1d8ba6d4857 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -346,11 +346,6 @@ struct vmballoon { /* statistics */ struct vmballoon_stats *stats; -#ifdef CONFIG_DEBUG_FS - /* debugfs file exporting statistics */ - struct dentry *dbg_entry; -#endif - /** * @b_dev_info: balloon device information descriptor. */ @@ -1709,14 +1704,14 @@ DEFINE_SHOW_ATTRIBUTE(vmballoon_debug); static void __init vmballoon_debugfs_init(struct vmballoon *b) { - b->dbg_entry = debugfs_create_file("vmmemctl", S_IRUGO, NULL, b, - &vmballoon_debug_fops); + debugfs_create_file("vmmemctl", S_IRUGO, NULL, b, + &vmballoon_debug_fops); } static void __exit vmballoon_debugfs_exit(struct vmballoon *b) { static_key_disable(&balloon_stat_enabled.key); - debugfs_remove(b->dbg_entry); + debugfs_remove(debugfs_lookup("vmmemctl", NULL)); kfree(b->stats); b->stats = NULL; } -- cgit v1.2.3 From bc6350167ef4e003e463c25417b48a446e48001d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 16 Feb 2021 16:08:28 +0100 Subject: drivers: habanalabs: remove unused dentry pointer for debugfs files The dentry for the created debugfs file was being saved, but never used anywhere. As the pointer isn't needed for anything, and the debugfs files are being properly removed by removing the parent directory, remove the saved pointer as well, saving a tiny bit of memory and logic. Cc: Oded Gabbay Cc: Arnd Bergmann Cc: Tomer Tayar Cc: Moti Haimovski Cc: Omer Shpigelman Cc: Ofir Bitton Cc: linux-kernel@vger.kernel.org Reviewed-by: Oded Gabbay Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20210216150828.3855810-1-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/habanalabs/common/debugfs.c | 5 +---- drivers/misc/habanalabs/common/habanalabs.h | 2 -- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/misc/habanalabs/common/debugfs.c b/drivers/misc/habanalabs/common/debugfs.c index df847a6d19f4..9f19bee7b592 100644 --- a/drivers/misc/habanalabs/common/debugfs.c +++ b/drivers/misc/habanalabs/common/debugfs.c @@ -992,7 +992,6 @@ void hl_debugfs_add_device(struct hl_device *hdev) struct hl_dbg_device_entry *dev_entry = &hdev->hl_debugfs; int count = ARRAY_SIZE(hl_debugfs_list); struct hl_debugfs_entry *entry; - struct dentry *ent; int i; dev_entry->hdev = hdev; @@ -1105,13 +1104,11 @@ void hl_debugfs_add_device(struct hl_device *hdev) &hl_security_violations_fops); for (i = 0, entry = dev_entry->entry_arr ; i < count ; i++, entry++) { - - ent = debugfs_create_file(hl_debugfs_list[i].name, + debugfs_create_file(hl_debugfs_list[i].name, 0444, dev_entry->root, entry, &hl_debugfs_fops); - entry->dent = ent; entry->info_ent = &hl_debugfs_list[i]; entry->dev_entry = dev_entry; } diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index d933878b24d1..4b321e4f8059 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -1465,12 +1465,10 @@ struct hl_info_list { /** * struct hl_debugfs_entry - debugfs dentry wrapper. - * @dent: base debugfs entry structure. * @info_ent: dentry realted ops. * @dev_entry: ASIC specific debugfs manager. */ struct hl_debugfs_entry { - struct dentry *dent; const struct hl_info_list *info_ent; struct hl_dbg_device_entry *dev_entry; }; -- cgit v1.2.3 From f8096ff38d5f62d8a2c473e1bec0163a1b2b86d8 Mon Sep 17 00:00:00 2001 From: Dinghao Liu Date: Mon, 1 Mar 2021 20:50:57 +0800 Subject: drivers: misc: ad525x_dpot: Add missing check in dpot_read_spi The use of dpot_read_r8d8() after checking dpot->uid is similar. However, we check the return value and return an error code only in one path, which is odd. Link: https://lore.kernel.org/r/20210301125057.28819-1-dinghao.liu@zju.edu.cn Signed-off-by: Dinghao Liu Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ad525x_dpot.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c index 6f164522b028..5d8f3f6a95f2 100644 --- a/drivers/misc/ad525x_dpot.c +++ b/drivers/misc/ad525x_dpot.c @@ -139,6 +139,9 @@ static s32 dpot_read_spi(struct dpot_data *dpot, u8 reg) value = dpot_read_r8d8(dpot, DPOT_AD5291_READ_RDAC << 2); + if (value < 0) + return value; + if (dpot->uid == DPOT_UID(AD5291_ID)) value = value >> 2; -- cgit v1.2.3 From 9ea48efdc528b019588a03417517c25fe7368684 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 5 Mar 2021 20:16:43 +0100 Subject: bus: mhi: pci_generic: Parametrable element count for events Not all hardwares need to use the same number of event ring elements. This change makes this parametrable. Signed-off-by: Loic Poulain Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1614971808-22156-1-git-send-email-loic.poulain@linaro.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/pci_generic.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/bus/mhi/pci_generic.c b/drivers/bus/mhi/pci_generic.c index 20673a4b4a3c..68c1c8633860 100644 --- a/drivers/bus/mhi/pci_generic.c +++ b/drivers/bus/mhi/pci_generic.c @@ -71,9 +71,9 @@ struct mhi_pci_dev_info { .doorbell_mode_switch = false, \ } -#define MHI_EVENT_CONFIG_CTRL(ev_ring) \ +#define MHI_EVENT_CONFIG_CTRL(ev_ring, el_count) \ { \ - .num_elements = 64, \ + .num_elements = el_count, \ .irq_moderation_ms = 0, \ .irq = (ev_ring) + 1, \ .priority = 1, \ @@ -114,9 +114,9 @@ struct mhi_pci_dev_info { .doorbell_mode_switch = true, \ } -#define MHI_EVENT_CONFIG_DATA(ev_ring) \ +#define MHI_EVENT_CONFIG_DATA(ev_ring, el_count) \ { \ - .num_elements = 128, \ + .num_elements = el_count, \ .irq_moderation_ms = 5, \ .irq = (ev_ring) + 1, \ .priority = 1, \ @@ -127,9 +127,9 @@ struct mhi_pci_dev_info { .offload_channel = false, \ } -#define MHI_EVENT_CONFIG_HW_DATA(ev_ring, ch_num) \ +#define MHI_EVENT_CONFIG_HW_DATA(ev_ring, el_count, ch_num) \ { \ - .num_elements = 2048, \ + .num_elements = el_count, \ .irq_moderation_ms = 1, \ .irq = (ev_ring) + 1, \ .priority = 1, \ @@ -156,12 +156,12 @@ static const struct mhi_channel_config modem_qcom_v1_mhi_channels[] = { static struct mhi_event_config modem_qcom_v1_mhi_events[] = { /* first ring is control+data ring */ - MHI_EVENT_CONFIG_CTRL(0), + MHI_EVENT_CONFIG_CTRL(0, 64), /* DIAG dedicated event ring */ - MHI_EVENT_CONFIG_DATA(1), + MHI_EVENT_CONFIG_DATA(1, 128), /* Hardware channels request dedicated hardware event rings */ - MHI_EVENT_CONFIG_HW_DATA(2, 100), - MHI_EVENT_CONFIG_HW_DATA(3, 101) + MHI_EVENT_CONFIG_HW_DATA(2, 1024, 100), + MHI_EVENT_CONFIG_HW_DATA(3, 2048, 101) }; static struct mhi_controller_config modem_qcom_v1_mhiv_config = { -- cgit v1.2.3 From ac4bf60bbaa090d3abfc5a340bd01ae933fadacf Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 5 Mar 2021 20:16:44 +0100 Subject: bus: mhi: pci_generic: Introduce quectel EM1XXGR-L support Add support for EM1XXGR-L modems, this modem series is based on SDX24 qcom chip. The modem is mainly based on MBIM protocol for both the data and control path. The drivers for these channels (mhi-net-mbim and mhi_uci) are not yet part of the kernel but will be integrated by different series. Signed-off-by: Loic Poulain Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1614971808-22156-2-git-send-email-loic.poulain@linaro.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/pci_generic.c | 73 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/drivers/bus/mhi/pci_generic.c b/drivers/bus/mhi/pci_generic.c index 68c1c8633860..275150338b9a 100644 --- a/drivers/bus/mhi/pci_generic.c +++ b/drivers/bus/mhi/pci_generic.c @@ -114,6 +114,36 @@ struct mhi_pci_dev_info { .doorbell_mode_switch = true, \ } +#define MHI_CHANNEL_CONFIG_UL_SBL(ch_num, ch_name, el_count, ev_ring) \ + { \ + .num = ch_num, \ + .name = ch_name, \ + .num_elements = el_count, \ + .event_ring = ev_ring, \ + .dir = DMA_TO_DEVICE, \ + .ee_mask = BIT(MHI_EE_SBL), \ + .pollcfg = 0, \ + .doorbell = MHI_DB_BRST_DISABLE, \ + .lpm_notify = false, \ + .offload_channel = false, \ + .doorbell_mode_switch = false, \ + } \ + +#define MHI_CHANNEL_CONFIG_DL_SBL(ch_num, ch_name, el_count, ev_ring) \ + { \ + .num = ch_num, \ + .name = ch_name, \ + .num_elements = el_count, \ + .event_ring = ev_ring, \ + .dir = DMA_FROM_DEVICE, \ + .ee_mask = BIT(MHI_EE_SBL), \ + .pollcfg = 0, \ + .doorbell = MHI_DB_BRST_DISABLE, \ + .lpm_notify = false, \ + .offload_channel = false, \ + .doorbell_mode_switch = false, \ + } + #define MHI_EVENT_CONFIG_DATA(ev_ring, el_count) \ { \ .num_elements = el_count, \ @@ -182,9 +212,52 @@ static const struct mhi_pci_dev_info mhi_qcom_sdx55_info = { .dma_data_width = 32 }; +static const struct mhi_channel_config mhi_quectel_em1xx_channels[] = { + MHI_CHANNEL_CONFIG_UL(0, "NMEA", 32, 0), + MHI_CHANNEL_CONFIG_DL(1, "NMEA", 32, 0), + MHI_CHANNEL_CONFIG_UL_SBL(2, "SAHARA", 32, 0), + MHI_CHANNEL_CONFIG_DL_SBL(3, "SAHARA", 32, 0), + MHI_CHANNEL_CONFIG_UL(4, "DIAG", 32, 1), + MHI_CHANNEL_CONFIG_DL(5, "DIAG", 32, 1), + MHI_CHANNEL_CONFIG_UL(12, "MBIM", 32, 0), + MHI_CHANNEL_CONFIG_DL(13, "MBIM", 32, 0), + MHI_CHANNEL_CONFIG_UL(32, "DUN", 32, 0), + MHI_CHANNEL_CONFIG_DL(33, "DUN", 32, 0), + MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0_MBIM", 128, 2), + MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0_MBIM", 128, 3), +}; + +static struct mhi_event_config mhi_quectel_em1xx_events[] = { + MHI_EVENT_CONFIG_CTRL(0, 128), + MHI_EVENT_CONFIG_DATA(1, 128), + MHI_EVENT_CONFIG_HW_DATA(2, 1024, 100), + MHI_EVENT_CONFIG_HW_DATA(3, 1024, 101) +}; + +static struct mhi_controller_config modem_quectel_em1xx_config = { + .max_channels = 128, + .timeout_ms = 20000, + .num_channels = ARRAY_SIZE(mhi_quectel_em1xx_channels), + .ch_cfg = mhi_quectel_em1xx_channels, + .num_events = ARRAY_SIZE(mhi_quectel_em1xx_events), + .event_cfg = mhi_quectel_em1xx_events, +}; + +static const struct mhi_pci_dev_info mhi_quectel_em1xx_info = { + .name = "quectel-em1xx", + .edl = "qcom/prog_firehose_sdx24.mbn", + .config = &modem_quectel_em1xx_config, + .bar_num = MHI_PCI_DEFAULT_BAR_NUM, + .dma_data_width = 32 +}; + static const struct pci_device_id mhi_pci_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0306), .driver_data = (kernel_ulong_t) &mhi_qcom_sdx55_info }, + { PCI_DEVICE(0x1eac, 0x1001), /* EM120R-GL (sdx24) */ + .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, + { PCI_DEVICE(0x1eac, 0x1002), /* EM160R-GL (sdx24) */ + .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, { } }; MODULE_DEVICE_TABLE(pci, mhi_pci_id_table); -- cgit v1.2.3 From 59d05b71729b96d809b89e70640b9332d559b20f Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 5 Mar 2021 20:16:45 +0100 Subject: bus: mhi: pci_generic: Add SDX24 based modem support Add generic info for SDX24 based modems. Also add the FIREHOSE channels used by the flash-programmer firmware loaded in EDL mode. Signed-off-by: Loic Poulain Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1614971808-22156-3-git-send-email-loic.poulain@linaro.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/pci_generic.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/bus/mhi/pci_generic.c b/drivers/bus/mhi/pci_generic.c index 275150338b9a..32c96f298c88 100644 --- a/drivers/bus/mhi/pci_generic.c +++ b/drivers/bus/mhi/pci_generic.c @@ -212,6 +212,14 @@ static const struct mhi_pci_dev_info mhi_qcom_sdx55_info = { .dma_data_width = 32 }; +static const struct mhi_pci_dev_info mhi_qcom_sdx24_info = { + .name = "qcom-sdx24", + .edl = "qcom/prog_firehose_sdx24.mbn", + .config = &modem_qcom_v1_mhiv_config, + .bar_num = MHI_PCI_DEFAULT_BAR_NUM, + .dma_data_width = 32 +}; + static const struct mhi_channel_config mhi_quectel_em1xx_channels[] = { MHI_CHANNEL_CONFIG_UL(0, "NMEA", 32, 0), MHI_CHANNEL_CONFIG_DL(1, "NMEA", 32, 0), @@ -254,6 +262,8 @@ static const struct mhi_pci_dev_info mhi_quectel_em1xx_info = { static const struct pci_device_id mhi_pci_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0306), .driver_data = (kernel_ulong_t) &mhi_qcom_sdx55_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0304), + .driver_data = (kernel_ulong_t) &mhi_qcom_sdx24_info }, { PCI_DEVICE(0x1eac, 0x1001), /* EM120R-GL (sdx24) */ .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, { PCI_DEVICE(0x1eac, 0x1002), /* EM160R-GL (sdx24) */ -- cgit v1.2.3 From e3e5e6508fc1c0e98a5a264853713dd30a60e5e5 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 5 Mar 2021 20:16:46 +0100 Subject: bus: mhi: pci_generic: No-Op for device_wake operations The wake_db register presence is highly speculative and can fuze MHI devices. Indeed, currently the wake_db register address is defined at entry 127 of the 'Channel doorbell array', thus writing to this address is equivalent to ringing the doorbell for channel 127, causing trouble with some devics (e.g. SDX24 based modems) that get an unexpected channel 127 doorbell interrupt. This change fixes that issue by setting wake get/put as no-op for pci_generic devices. The wake device sideband mechanism seems really specific to each device, and is AFAIK not defined by the MHI spec. It also removes zeroing initialization of wake_db register during MMIO initialization, the register being set via wake_get/put accessors few cycles later during M0 transition. Signed-off-by: Loic Poulain Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1614971808-22156-4-git-send-email-loic.poulain@linaro.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/init.c | 2 -- drivers/bus/mhi/pci_generic.c | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c index be4eebb0971b..bae8e0da2c6f 100644 --- a/drivers/bus/mhi/core/init.c +++ b/drivers/bus/mhi/core/init.c @@ -508,8 +508,6 @@ int mhi_init_mmio(struct mhi_controller *mhi_cntrl) /* Setup wake db */ mhi_cntrl->wake_db = base + val + (8 * MHI_DEV_WAKE_DB); - mhi_write_reg(mhi_cntrl, mhi_cntrl->wake_db, 4, 0); - mhi_write_reg(mhi_cntrl, mhi_cntrl->wake_db, 0, 0); mhi_cntrl->wake_set = false; /* Setup channel db address for each channel in tre_ring */ diff --git a/drivers/bus/mhi/pci_generic.c b/drivers/bus/mhi/pci_generic.c index 32c96f298c88..06a360ef743d 100644 --- a/drivers/bus/mhi/pci_generic.c +++ b/drivers/bus/mhi/pci_generic.c @@ -313,6 +313,21 @@ static void mhi_pci_status_cb(struct mhi_controller *mhi_cntrl, } } +static void mhi_pci_wake_get_nop(struct mhi_controller *mhi_cntrl, bool force) +{ + /* no-op */ +} + +static void mhi_pci_wake_put_nop(struct mhi_controller *mhi_cntrl, bool override) +{ + /* no-op */ +} + +static void mhi_pci_wake_toggle_nop(struct mhi_controller *mhi_cntrl) +{ + /* no-op */ +} + static bool mhi_pci_is_alive(struct mhi_controller *mhi_cntrl) { struct pci_dev *pdev = to_pci_dev(mhi_cntrl->cntrl_dev); @@ -516,6 +531,9 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) mhi_cntrl->status_cb = mhi_pci_status_cb; mhi_cntrl->runtime_get = mhi_pci_runtime_get; mhi_cntrl->runtime_put = mhi_pci_runtime_put; + mhi_cntrl->wake_get = mhi_pci_wake_get_nop; + mhi_cntrl->wake_put = mhi_pci_wake_put_nop; + mhi_cntrl->wake_toggle = mhi_pci_wake_toggle_nop; err = mhi_pci_claim(mhi_cntrl, info->bar_num, DMA_BIT_MASK(info->dma_data_width)); if (err) -- cgit v1.2.3 From e89878aa4b79a834d5c90abb96efcd64396c2163 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 5 Mar 2021 20:16:47 +0100 Subject: bus: mhi: pci_generic: Use generic PCI power management The PCI core can take care of proper PCI suspend/resume operations, but this is discarded when the driver saves PCI state by its own. This currently prevents the PCI core to enable PME (for modem initiated D3 exit) which is requested for proper runtime pm support. This change deletes explicit PCI state-saving and state-set from suspend callback, letting the PCI doing the appropriate work. Signed-off-by: Loic Poulain Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1614971808-22156-5-git-send-email-loic.poulain@linaro.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/pci_generic.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/bus/mhi/pci_generic.c b/drivers/bus/mhi/pci_generic.c index 06a360ef743d..ea46dda0ebf2 100644 --- a/drivers/bus/mhi/pci_generic.c +++ b/drivers/bus/mhi/pci_generic.c @@ -545,9 +545,12 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, mhi_pdev); - /* Have stored pci confspace at hand for restore in sudden PCI error */ + /* Have stored pci confspace at hand for restore in sudden PCI error. + * cache the state locally and discard the PCI core one. + */ pci_save_state(pdev); mhi_pdev->pci_state = pci_store_saved_state(pdev); + pci_load_saved_state(pdev, NULL); pci_enable_pcie_error_reporting(pdev); @@ -718,10 +721,8 @@ static int __maybe_unused mhi_pci_suspend(struct device *dev) /* Transition to M3 state */ mhi_pm_suspend(mhi_cntrl); - pci_save_state(pdev); pci_disable_device(pdev); pci_wake_from_d3(pdev, true); - pci_set_power_state(pdev, PCI_D3hot); return 0; } @@ -733,14 +734,13 @@ static int __maybe_unused mhi_pci_resume(struct device *dev) struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl; int err; - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - pci_set_master(pdev); - err = pci_enable_device(pdev); if (err) goto err_recovery; + pci_set_master(pdev); + pci_wake_from_d3(pdev, false); + /* Exit M3, transition to M0 state */ err = mhi_pm_resume(mhi_cntrl); if (err) { -- cgit v1.2.3 From d3800c1dce24c7964f37663b3a5549e93f345a5c Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 5 Mar 2021 20:16:48 +0100 Subject: bus: mhi: pci_generic: Add support for runtime PM When the device is idle it is possible to move it into the lowest MHI PM state (M3). In that mode, all MHI operations are suspended and the PCI device can be safely put into PCI D3 state. The device is then resumed from D3/M3 either because of host initiated MHI operation (e.g. buffer TX) or because the device (modem) has triggered wake-up via PME feature (e.g. on incoming data). Same procedures can be used for system wide or runtime suspend/resume. Signed-off-by: Loic Poulain Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1614971808-22156-6-git-send-email-loic.poulain@linaro.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/pci_generic.c | 95 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 86 insertions(+), 9 deletions(-) diff --git a/drivers/bus/mhi/pci_generic.c b/drivers/bus/mhi/pci_generic.c index ea46dda0ebf2..5cf44bcfe040 100644 --- a/drivers/bus/mhi/pci_generic.c +++ b/drivers/bus/mhi/pci_generic.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -274,6 +275,7 @@ MODULE_DEVICE_TABLE(pci, mhi_pci_id_table); enum mhi_pci_device_status { MHI_PCI_DEV_STARTED, + MHI_PCI_DEV_SUSPENDED, }; struct mhi_pci_device { @@ -307,6 +309,10 @@ static void mhi_pci_status_cb(struct mhi_controller *mhi_cntrl, case MHI_CB_FATAL_ERROR: case MHI_CB_SYS_ERROR: dev_warn(&pdev->dev, "firmware crashed (%u)\n", cb); + pm_runtime_forbid(&pdev->dev); + break; + case MHI_CB_EE_MISSION_MODE: + pm_runtime_allow(&pdev->dev); break; default: break; @@ -428,13 +434,19 @@ static int mhi_pci_get_irqs(struct mhi_controller *mhi_cntrl, static int mhi_pci_runtime_get(struct mhi_controller *mhi_cntrl) { - /* no PM for now */ - return 0; + /* The runtime_get() MHI callback means: + * Do whatever is requested to leave M3. + */ + return pm_runtime_get(mhi_cntrl->cntrl_dev); } static void mhi_pci_runtime_put(struct mhi_controller *mhi_cntrl) { - /* no PM for now */ + /* The runtime_put() MHI callback means: + * Device can be moved in M3 state. + */ + pm_runtime_mark_last_busy(mhi_cntrl->cntrl_dev); + pm_runtime_put(mhi_cntrl->cntrl_dev); } static void mhi_pci_recovery_work(struct work_struct *work) @@ -448,6 +460,7 @@ static void mhi_pci_recovery_work(struct work_struct *work) dev_warn(&pdev->dev, "device recovery started\n"); del_timer(&mhi_pdev->health_check_timer); + pm_runtime_forbid(&pdev->dev); /* Clean up MHI state */ if (test_and_clear_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status)) { @@ -455,7 +468,6 @@ static void mhi_pci_recovery_work(struct work_struct *work) mhi_unprepare_after_power_down(mhi_cntrl); } - /* Check if we can recover without full reset */ pci_set_power_state(pdev, PCI_D0); pci_load_saved_state(pdev, mhi_pdev->pci_state); pci_restore_state(pdev); @@ -489,6 +501,10 @@ static void health_check(struct timer_list *t) struct mhi_pci_device *mhi_pdev = from_timer(mhi_pdev, t, health_check_timer); struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl; + if (!test_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status) || + test_bit(MHI_PCI_DEV_SUSPENDED, &mhi_pdev->status)) + return; + if (!mhi_pci_is_alive(mhi_cntrl)) { dev_err(mhi_cntrl->cntrl_dev, "Device died\n"); queue_work(system_long_wq, &mhi_pdev->recovery_work); @@ -576,6 +592,14 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* start health check */ mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD); + /* Only allow runtime-suspend if PME capable (for wakeup) */ + if (pci_pme_capable(pdev, PCI_D3hot)) { + pm_runtime_set_autosuspend_delay(&pdev->dev, 2000); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + } + return 0; err_unprepare: @@ -599,6 +623,10 @@ static void mhi_pci_remove(struct pci_dev *pdev) mhi_unprepare_after_power_down(mhi_cntrl); } + /* balancing probe put_noidle */ + if (pci_pme_capable(pdev, PCI_D3hot)) + pm_runtime_get_noresume(&pdev->dev); + mhi_unregister_controller(mhi_cntrl); } @@ -709,31 +737,48 @@ static const struct pci_error_handlers mhi_pci_err_handler = { .reset_done = mhi_pci_reset_done, }; -static int __maybe_unused mhi_pci_suspend(struct device *dev) +static int __maybe_unused mhi_pci_runtime_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct mhi_pci_device *mhi_pdev = dev_get_drvdata(dev); struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl; + int err; + + if (test_and_set_bit(MHI_PCI_DEV_SUSPENDED, &mhi_pdev->status)) + return 0; del_timer(&mhi_pdev->health_check_timer); cancel_work_sync(&mhi_pdev->recovery_work); + if (!test_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status) || + mhi_cntrl->ee != MHI_EE_AMSS) + goto pci_suspend; /* Nothing to do at MHI level */ + /* Transition to M3 state */ - mhi_pm_suspend(mhi_cntrl); + err = mhi_pm_suspend(mhi_cntrl); + if (err) { + dev_err(&pdev->dev, "failed to suspend device: %d\n", err); + clear_bit(MHI_PCI_DEV_SUSPENDED, &mhi_pdev->status); + return -EBUSY; + } +pci_suspend: pci_disable_device(pdev); pci_wake_from_d3(pdev, true); return 0; } -static int __maybe_unused mhi_pci_resume(struct device *dev) +static int __maybe_unused mhi_pci_runtime_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct mhi_pci_device *mhi_pdev = dev_get_drvdata(dev); struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl; int err; + if (!test_and_clear_bit(MHI_PCI_DEV_SUSPENDED, &mhi_pdev->status)) + return 0; + err = pci_enable_device(pdev); if (err) goto err_recovery; @@ -741,6 +786,10 @@ static int __maybe_unused mhi_pci_resume(struct device *dev) pci_set_master(pdev); pci_wake_from_d3(pdev, false); + if (!test_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status) || + mhi_cntrl->ee != MHI_EE_AMSS) + return 0; /* Nothing to do at MHI level */ + /* Exit M3, transition to M0 state */ err = mhi_pm_resume(mhi_cntrl); if (err) { @@ -751,16 +800,44 @@ static int __maybe_unused mhi_pci_resume(struct device *dev) /* Resume health check */ mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD); + /* It can be a remote wakeup (no mhi runtime_get), update access time */ + pm_runtime_mark_last_busy(dev); + return 0; err_recovery: - /* The device may have loose power or crashed, try recovering it */ + /* Do not fail to not mess up our PCI device state, the device likely + * lost power (d3cold) and we simply need to reset it from the recovery + * procedure, trigger the recovery asynchronously to prevent system + * suspend exit delaying. + */ queue_work(system_long_wq, &mhi_pdev->recovery_work); + pm_runtime_mark_last_busy(dev); - return err; + return 0; +} + +static int __maybe_unused mhi_pci_suspend(struct device *dev) +{ + pm_runtime_disable(dev); + return mhi_pci_runtime_suspend(dev); +} + +static int __maybe_unused mhi_pci_resume(struct device *dev) +{ + int ret; + + /* Depending the platform, device may have lost power (d3cold), we need + * to resume it now to check its state and recover when necessary. + */ + ret = mhi_pci_runtime_resume(dev); + pm_runtime_enable(dev); + + return ret; } static const struct dev_pm_ops mhi_pci_pm_ops = { + SET_RUNTIME_PM_OPS(mhi_pci_runtime_suspend, mhi_pci_runtime_resume, NULL) SET_SYSTEM_SLEEP_PM_OPS(mhi_pci_suspend, mhi_pci_resume) }; -- cgit v1.2.3 From 0fccbf0a3b690b162f53b13ed8bc442ea33437dc Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Wed, 24 Feb 2021 11:18:50 +0100 Subject: bus: mhi: pci_generic: Remove WQ_MEM_RECLAIM flag from state workqueue A recent change created a dedicated workqueue for the state-change work with WQ_HIGHPRI (no strong reason for that) and WQ_MEM_RECLAIM flags, but the state-change work (mhi_pm_st_worker) does not guarantee forward progress under memory pressure, and will even wait on various memory allocations when e.g. creating devices, loading firmware, etc... The work is then not part of a memory reclaim path... Moreover, this causes a warning in check_flush_dependency() since we end up in code that flushes a non-reclaim workqueue: [ 40.969601] workqueue: WQ_MEM_RECLAIM mhi_hiprio_wq:mhi_pm_st_worker [mhi] is flushing !WQ_MEM_RECLAIM events_highpri:flush_backlog [ 40.969612] WARNING: CPU: 4 PID: 158 at kernel/workqueue.c:2607 check_flush_dependency+0x11c/0x140 [ 40.969733] Call Trace: [ 40.969740] __flush_work+0x97/0x1d0 [ 40.969745] ? wake_up_process+0x15/0x20 [ 40.969749] ? insert_work+0x70/0x80 [ 40.969750] ? __queue_work+0x14a/0x3e0 [ 40.969753] flush_work+0x10/0x20 [ 40.969756] rollback_registered_many+0x1c9/0x510 [ 40.969759] unregister_netdevice_queue+0x94/0x120 [ 40.969761] unregister_netdev+0x1d/0x30 [ 40.969765] mhi_net_remove+0x1a/0x40 [mhi_net] [ 40.969770] mhi_driver_remove+0x124/0x250 [mhi] [ 40.969776] device_release_driver_internal+0xf0/0x1d0 [ 40.969778] device_release_driver+0x12/0x20 [ 40.969782] bus_remove_device+0xe1/0x150 [ 40.969786] device_del+0x17b/0x3e0 [ 40.969791] mhi_destroy_device+0x9a/0x100 [mhi] [ 40.969796] ? mhi_unmap_single_use_bb+0x50/0x50 [mhi] [ 40.969799] device_for_each_child+0x5e/0xa0 [ 40.969804] mhi_pm_st_worker+0x921/0xf50 [mhi] Fixes: 8f7039787687 ("bus: mhi: core: Move to using high priority workqueue") Signed-off-by: Loic Poulain Reviewed-by: Bhaumik Bhatt Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1614161930-8513-1-git-send-email-loic.poulain@linaro.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/init.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c index bae8e0da2c6f..4014c574fe5b 100644 --- a/drivers/bus/mhi/core/init.c +++ b/drivers/bus/mhi/core/init.c @@ -888,8 +888,7 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl, INIT_WORK(&mhi_cntrl->st_worker, mhi_pm_st_worker); init_waitqueue_head(&mhi_cntrl->state_event); - mhi_cntrl->hiprio_wq = alloc_ordered_workqueue - ("mhi_hiprio_wq", WQ_MEM_RECLAIM | WQ_HIGHPRI); + mhi_cntrl->hiprio_wq = alloc_ordered_workqueue("mhi_hiprio_wq", WQ_HIGHPRI); if (!mhi_cntrl->hiprio_wq) { dev_err(mhi_cntrl->cntrl_dev, "Failed to allocate workqueue\n"); ret = -ENOMEM; -- cgit v1.2.3 From 0ecc1c70dcd32c0f081b173a1a5d89952686f271 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 26 Feb 2021 11:53:02 +0100 Subject: bus: mhi: core: Fix invalid error returning in mhi_queue mhi_queue returns an error when the doorbell is not accessible in the current state. This can happen when the device is in non M0 state, like M3, and needs to be waken-up prior ringing the DB. This case is managed earlier by triggering an asynchronous M3 exit via controller resume/suspend callbacks, that in turn will cause M0 transition and DB update. So, since it's not an error but just delaying of doorbell update, there is no reason to return an error. This also fixes a use after free error for skb case, indeed a caller queuing skb will try to free the skb if the queueing fails, but in that case queueing has been done. Fixes: a8f75cb348fd ("mhi: core: Factorize mhi queuing") Signed-off-by: Loic Poulain Reviewed-by: Jeffrey Hugo Reviewed-by: Bhaumik Bhatt Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1614336782-5809-1-git-send-email-loic.poulain@linaro.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/main.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index 4e0131b94056..5027423802cf 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -1014,12 +1014,8 @@ static int mhi_queue(struct mhi_device *mhi_dev, struct mhi_buf_info *buf_info, if (mhi_chan->dir == DMA_TO_DEVICE) atomic_inc(&mhi_cntrl->pending_pkts); - if (unlikely(!MHI_DB_ACCESS_VALID(mhi_cntrl))) { - ret = -EIO; - goto exit_unlock; - } - - mhi_ring_chan_db(mhi_cntrl, mhi_chan); + if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl))) + mhi_ring_chan_db(mhi_cntrl, mhi_chan); exit_unlock: read_unlock_irqrestore(&mhi_cntrl->pm_lock, flags); -- cgit v1.2.3 From e5b53b5be677b3e78960974d4c36acc752505f53 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Mon, 15 Feb 2021 16:42:33 +0100 Subject: bus: mhi: core: Rename debugfs directory name Use MHI controller device name instead of the 'bus' device name as debugfs dir name (e.g. /sys/kernel/debug/mhi0). That aligns with sysfs device name. Signed-off-by: Loic Poulain Tested-by: Jeffrey Hugo Reviewed-by: Manivannan Sadhasivam Reviewed-by: Jeffrey Hugo Link: https://lore.kernel.org/r/1613403753-1457-1-git-send-email-loic.poulain@linaro.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bus/mhi/core/debugfs.c b/drivers/bus/mhi/core/debugfs.c index 7d43138ce66d..858d7516410b 100644 --- a/drivers/bus/mhi/core/debugfs.c +++ b/drivers/bus/mhi/core/debugfs.c @@ -377,7 +377,7 @@ static struct dentry *mhi_debugfs_root; void mhi_create_debugfs(struct mhi_controller *mhi_cntrl) { mhi_cntrl->debugfs_dentry = - debugfs_create_dir(dev_name(mhi_cntrl->cntrl_dev), + debugfs_create_dir(dev_name(&mhi_cntrl->mhi_dev->dev), mhi_debugfs_root); debugfs_create_file("states", 0444, mhi_cntrl->debugfs_dentry, -- cgit v1.2.3 From 8de5ad99414347ad08e6ebc2260be1d2e009cb9a Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Tue, 9 Mar 2021 10:44:50 -0800 Subject: bus: mhi: core: Add missing checks for MMIO register entries As per documentation, fields marked as (required) in an MHI controller structure need to be populated by the controller driver before calling mhi_register_controller(). Ensure all required pointers and non-zero fields are present in the controller before proceeding with the registration. Signed-off-by: Bhaumik Bhatt Reviewed-by: Jeffrey Hugo Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1615315490-36017-1-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/init.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c index 4014c574fe5b..706484ffe169 100644 --- a/drivers/bus/mhi/core/init.c +++ b/drivers/bus/mhi/core/init.c @@ -861,12 +861,10 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl, u32 soc_info; int ret, i; - if (!mhi_cntrl) - return -EINVAL; - - if (!mhi_cntrl->runtime_get || !mhi_cntrl->runtime_put || + if (!mhi_cntrl || !mhi_cntrl->cntrl_dev || !mhi_cntrl->regs || + !mhi_cntrl->runtime_get || !mhi_cntrl->runtime_put || !mhi_cntrl->status_cb || !mhi_cntrl->read_reg || - !mhi_cntrl->write_reg || !mhi_cntrl->nr_irqs) + !mhi_cntrl->write_reg || !mhi_cntrl->nr_irqs || !mhi_cntrl->irq) return -EINVAL; ret = parse_config(mhi_cntrl, config); -- cgit v1.2.3 From 020d3b26c07abe274ac17f64999bbd3bf3342195 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 5 Mar 2021 17:14:01 +0100 Subject: bus: mhi: Early MHI resume failure in non M3 state MHI suspend/resume are symmetric and balanced procedures. If device is not in M3 state on a resume, that means something happened behind our back. In this case resume is aborted and error reported, to let the controller handle the situation. This is mainly requested for system wide suspend-resume operation in PCI context which may lead to power-down/reset of the controller which will then lose its MHI context. In such cases, PCI driver is supposed to recover and reinitialize the device. Signed-off-by: Loic Poulain Reviewed-by: Bhaumik Bhatt Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1614960841-20233-1-git-send-email-loic.poulain@linaro.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/pm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c index 681960c72d2a..d61e6369a6e1 100644 --- a/drivers/bus/mhi/core/pm.c +++ b/drivers/bus/mhi/core/pm.c @@ -880,6 +880,9 @@ int mhi_pm_resume(struct mhi_controller *mhi_cntrl) if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) return -EIO; + if (mhi_get_mhi_state(mhi_cntrl) != MHI_STATE_M3) + return -EINVAL; + /* Notify clients about exiting LPM */ list_for_each_entry_safe(itr, tmp, &mhi_cntrl->lpm_chans, node) { mutex_lock(&itr->mutex); -- cgit v1.2.3 From 925089c1900f588615db5bf4e1d9064a5f2c18c7 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Wed, 24 Feb 2021 15:23:02 -0800 Subject: bus: mhi: core: Destroy SBL devices when moving to mission mode Currently, client devices are created in SBL or AMSS (mission mode) and only destroyed after power down or SYS ERROR. When moving between certain execution environments, such as from SBL to AMSS, no clean-up is required. This presents an issue where SBL-specific channels are left open and client drivers now run in an execution environment where they cannot operate. Fix this by expanding the mhi_destroy_device() to do an execution environment specific clean-up if one is requested. Close the gap and destroy devices in such scenarios that allow SBL client drivers to clean up once device enters mission mode. Signed-off-by: Bhaumik Bhatt Reviewed-by: Loic Poulain Reviewed-by: Hemant Kumar Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1614208985-20851-2-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/main.c | 29 +++++++++++++++++++++++++---- drivers/bus/mhi/core/pm.c | 3 +++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index 5027423802cf..12aacacc6d37 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -244,8 +244,10 @@ static void mhi_del_ring_element(struct mhi_controller *mhi_cntrl, int mhi_destroy_device(struct device *dev, void *data) { + struct mhi_chan *ul_chan, *dl_chan; struct mhi_device *mhi_dev; struct mhi_controller *mhi_cntrl; + enum mhi_ee_type ee = MHI_EE_MAX; if (dev->bus != &mhi_bus_type) return 0; @@ -257,6 +259,17 @@ int mhi_destroy_device(struct device *dev, void *data) if (mhi_dev->dev_type == MHI_DEVICE_CONTROLLER) return 0; + ul_chan = mhi_dev->ul_chan; + dl_chan = mhi_dev->dl_chan; + + /* + * If execution environment is specified, remove only those devices that + * started in them based on ee_mask for the channels as we move on to a + * different execution environment + */ + if (data) + ee = *(enum mhi_ee_type *)data; + /* * For the suspend and resume case, this function will get called * without mhi_unregister_controller(). Hence, we need to drop the @@ -264,11 +277,19 @@ int mhi_destroy_device(struct device *dev, void *data) * be sure that there will be no instances of mhi_dev left after * this. */ - if (mhi_dev->ul_chan) - put_device(&mhi_dev->ul_chan->mhi_dev->dev); + if (ul_chan) { + if (ee != MHI_EE_MAX && !(ul_chan->ee_mask & BIT(ee))) + return 0; - if (mhi_dev->dl_chan) - put_device(&mhi_dev->dl_chan->mhi_dev->dev); + put_device(&ul_chan->mhi_dev->dev); + } + + if (dl_chan) { + if (ee != MHI_EE_MAX && !(dl_chan->ee_mask & BIT(ee))) + return 0; + + put_device(&dl_chan->mhi_dev->dev); + } dev_dbg(&mhi_cntrl->mhi_dev->dev, "destroy device for chan:%s\n", mhi_dev->name); diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c index d61e6369a6e1..ad49f69ee6a6 100644 --- a/drivers/bus/mhi/core/pm.c +++ b/drivers/bus/mhi/core/pm.c @@ -377,6 +377,7 @@ static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl) { struct mhi_event *mhi_event; struct device *dev = &mhi_cntrl->mhi_dev->dev; + enum mhi_ee_type current_ee = mhi_cntrl->ee; int i, ret; dev_dbg(dev, "Processing Mission Mode transition\n"); @@ -395,6 +396,8 @@ static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl) wake_up_all(&mhi_cntrl->state_event); + device_for_each_child(&mhi_cntrl->mhi_dev->dev, ¤t_ee, + mhi_destroy_device); mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_EE_MISSION_MODE); /* Force MHI to be in M0 state before continuing */ -- cgit v1.2.3 From 4884362f6977fc05cbec736625665241c0e0732f Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Wed, 24 Feb 2021 15:23:03 -0800 Subject: bus: mhi: core: Download AMSS image from appropriate function During full boot chain firmware download, the PM state worker downloads the AMSS image after a blocking wait for the SBL execution environment change when running in PBL transition itself. Improve this design by having the host download the AMSS image from the SBL transition of PM state worker thread when a DEV_ST_TRANSITION_SBL is queued instead of the blocking wait. Signed-off-by: Bhaumik Bhatt Reviewed-by: Manivannan Sadhasivam Reviewed-by: Loic Poulain Link: https://lore.kernel.org/r/1614208985-20851-3-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/boot.c | 51 +++++++++++++++++++---------------------- drivers/bus/mhi/core/internal.h | 1 + drivers/bus/mhi/core/pm.c | 2 ++ 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/drivers/bus/mhi/core/boot.c b/drivers/bus/mhi/core/boot.c index c2546bf229fb..08c28740dc4e 100644 --- a/drivers/bus/mhi/core/boot.c +++ b/drivers/bus/mhi/core/boot.c @@ -389,7 +389,6 @@ static void mhi_firmware_copy(struct mhi_controller *mhi_cntrl, void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) { const struct firmware *firmware = NULL; - struct image_info *image_info; struct device *dev = &mhi_cntrl->mhi_dev->dev; const char *fw_name; void *buf; @@ -491,44 +490,42 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) fw_load_ee_pthru: /* Transitioning into MHI RESET->READY state */ ret = mhi_ready_state_transition(mhi_cntrl); - - if (!mhi_cntrl->fbc_download) - return; - if (ret) { dev_err(dev, "MHI did not enter READY state\n"); goto error_ready_state; } - /* Wait for the SBL event */ - ret = wait_event_timeout(mhi_cntrl->state_event, - mhi_cntrl->ee == MHI_EE_SBL || - MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state), - msecs_to_jiffies(mhi_cntrl->timeout_ms)); + dev_info(dev, "Wait for device to enter SBL or Mission mode\n"); + return; - if (!ret || MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { - dev_err(dev, "MHI did not enter SBL\n"); - goto error_ready_state; +error_ready_state: + if (mhi_cntrl->fbc_download) { + mhi_free_bhie_table(mhi_cntrl, mhi_cntrl->fbc_image); + mhi_cntrl->fbc_image = NULL; } - /* Start full firmware image download */ - image_info = mhi_cntrl->fbc_image; +error_fw_load: + mhi_cntrl->pm_state = MHI_PM_FW_DL_ERR; + wake_up_all(&mhi_cntrl->state_event); +} + +int mhi_download_amss_image(struct mhi_controller *mhi_cntrl) +{ + struct image_info *image_info = mhi_cntrl->fbc_image; + struct device *dev = &mhi_cntrl->mhi_dev->dev; + int ret; + + if (!image_info) + return -EIO; + ret = mhi_fw_load_bhie(mhi_cntrl, /* Vector table is the last entry */ &image_info->mhi_buf[image_info->entries - 1]); if (ret) { - dev_err(dev, "MHI did not load image over BHIe, ret: %d\n", - ret); - goto error_fw_load; + dev_err(dev, "MHI did not load AMSS, ret:%d\n", ret); + mhi_cntrl->pm_state = MHI_PM_FW_DL_ERR; + wake_up_all(&mhi_cntrl->state_event); } - return; - -error_ready_state: - mhi_free_bhie_table(mhi_cntrl, mhi_cntrl->fbc_image); - mhi_cntrl->fbc_image = NULL; - -error_fw_load: - mhi_cntrl->pm_state = MHI_PM_FW_DL_ERR; - wake_up_all(&mhi_cntrl->state_event); + return ret; } diff --git a/drivers/bus/mhi/core/internal.h b/drivers/bus/mhi/core/internal.h index 6f80ec30c0cd..6f37439e5247 100644 --- a/drivers/bus/mhi/core/internal.h +++ b/drivers/bus/mhi/core/internal.h @@ -619,6 +619,7 @@ int mhi_pm_m3_transition(struct mhi_controller *mhi_cntrl); int __mhi_device_get_sync(struct mhi_controller *mhi_cntrl); int mhi_send_cmd(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, enum mhi_cmd_type cmd); +int mhi_download_amss_image(struct mhi_controller *mhi_cntrl); static inline bool mhi_is_active(struct mhi_controller *mhi_cntrl) { return (mhi_cntrl->dev_state >= MHI_STATE_M0 && diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c index ad49f69ee6a6..59ef2d5e3d90 100644 --- a/drivers/bus/mhi/core/pm.c +++ b/drivers/bus/mhi/core/pm.c @@ -758,6 +758,8 @@ void mhi_pm_st_worker(struct work_struct *work) * either SBL or AMSS states */ mhi_create_devices(mhi_cntrl); + if (mhi_cntrl->fbc_download) + mhi_download_amss_image(mhi_cntrl); break; case DEV_ST_TRANSITION_MISSION_MODE: mhi_pm_mission_mode_transition(mhi_cntrl); -- cgit v1.2.3 From ef2126c4e2ea2b92f543fae00a2a0332e4573c48 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Wed, 24 Feb 2021 15:23:04 -0800 Subject: bus: mhi: core: Process execution environment changes serially In current design, whenever the BHI interrupt is fired, the execution environment is updated. This can cause race conditions and impede ongoing power up/down processing. For example, if a power down is in progress, MHI host updates to a local "disabled" execution environment. If a BHI interrupt fires later, that value gets replaced with one from the BHI EE register. This impacts the controller as it does not expect multiple RDDM execution environment change status callbacks as an example. Another issue would be that the device can enter mission mode and the execution environment is updated, while device creation for SBL channels is still going on due to slower PM state worker thread run, leading to multiple attempts at opening the same channel. Ensure that EE changes are handled only from appropriate places and occur one after another and handle only PBL modes or RDDM EE changes as critical events directly from the interrupt handler. Simplify handling by waiting for SYS ERROR before handling RDDM. This also makes sure that we use the correct execution environment to notify the controller driver when the device resets to one of the PBL execution environments. Signed-off-by: Bhaumik Bhatt Reviewed-by: Loic Poulain Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1614208985-20851-4-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/main.c | 40 +++++++++++++++++++++------------------- drivers/bus/mhi/core/pm.c | 7 ++++--- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index 12aacacc6d37..f3b244a6255a 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -430,7 +430,7 @@ irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv) struct device *dev = &mhi_cntrl->mhi_dev->dev; enum mhi_state state = MHI_STATE_MAX; enum mhi_pm_state pm_state = 0; - enum mhi_ee_type ee = 0; + enum mhi_ee_type ee = MHI_EE_MAX; write_lock_irq(&mhi_cntrl->pm_lock); if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) { @@ -439,8 +439,7 @@ irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv) } state = mhi_get_mhi_state(mhi_cntrl); - ee = mhi_cntrl->ee; - mhi_cntrl->ee = mhi_get_exec_env(mhi_cntrl); + ee = mhi_get_exec_env(mhi_cntrl); dev_dbg(dev, "local ee:%s device ee:%s dev_state:%s\n", TO_MHI_EXEC_STR(mhi_cntrl->ee), TO_MHI_EXEC_STR(ee), TO_MHI_STATE_STR(state)); @@ -452,27 +451,30 @@ irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv) } write_unlock_irq(&mhi_cntrl->pm_lock); - /* If device supports RDDM don't bother processing SYS error */ - if (mhi_cntrl->rddm_image) { - /* host may be performing a device power down already */ - if (!mhi_is_active(mhi_cntrl)) - goto exit_intvec; + if (pm_state != MHI_PM_SYS_ERR_DETECT || ee == mhi_cntrl->ee) + goto exit_intvec; - if (mhi_cntrl->ee == MHI_EE_RDDM && mhi_cntrl->ee != ee) { + switch (ee) { + case MHI_EE_RDDM: + /* proceed if power down is not already in progress */ + if (mhi_cntrl->rddm_image && mhi_is_active(mhi_cntrl)) { mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_EE_RDDM); + mhi_cntrl->ee = ee; wake_up_all(&mhi_cntrl->state_event); } - goto exit_intvec; - } - - if (pm_state == MHI_PM_SYS_ERR_DETECT) { + break; + case MHI_EE_PBL: + case MHI_EE_EDL: + case MHI_EE_PTHRU: + mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_FATAL_ERROR); + mhi_cntrl->ee = ee; wake_up_all(&mhi_cntrl->state_event); - - /* For fatal errors, we let controller decide next step */ - if (MHI_IN_PBL(ee)) - mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_FATAL_ERROR); - else - mhi_pm_sys_err_handler(mhi_cntrl); + mhi_pm_sys_err_handler(mhi_cntrl); + break; + default: + wake_up_all(&mhi_cntrl->state_event); + mhi_pm_sys_err_handler(mhi_cntrl); + break; } exit_intvec: diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c index 59ef2d5e3d90..b4ee9295e7af 100644 --- a/drivers/bus/mhi/core/pm.c +++ b/drivers/bus/mhi/core/pm.c @@ -377,21 +377,22 @@ static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl) { struct mhi_event *mhi_event; struct device *dev = &mhi_cntrl->mhi_dev->dev; - enum mhi_ee_type current_ee = mhi_cntrl->ee; + enum mhi_ee_type ee = MHI_EE_MAX, current_ee = mhi_cntrl->ee; int i, ret; dev_dbg(dev, "Processing Mission Mode transition\n"); write_lock_irq(&mhi_cntrl->pm_lock); if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) - mhi_cntrl->ee = mhi_get_exec_env(mhi_cntrl); + ee = mhi_get_exec_env(mhi_cntrl); - if (!MHI_IN_MISSION_MODE(mhi_cntrl->ee)) { + if (!MHI_IN_MISSION_MODE(ee)) { mhi_cntrl->pm_state = MHI_PM_LD_ERR_FATAL_DETECT; write_unlock_irq(&mhi_cntrl->pm_lock); wake_up_all(&mhi_cntrl->state_event); return -EIO; } + mhi_cntrl->ee = ee; write_unlock_irq(&mhi_cntrl->pm_lock); wake_up_all(&mhi_cntrl->state_event); -- cgit v1.2.3 From aaca4233ea037394ecd0a96a40966f5954a48bfa Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Wed, 24 Feb 2021 15:23:05 -0800 Subject: bus: mhi: core: Update debug prints to include local device state Update debug prints to include local device in the BHI interrupt handler. This helps show transitions better between MHI states. Signed-off-by: Bhaumik Bhatt Reviewed-by: Manivannan Sadhasivam Reviewed-by: Loic Poulain Link: https://lore.kernel.org/r/1614208985-20851-5-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index f3b244a6255a..2c61dfd01353 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -440,9 +440,10 @@ irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv) state = mhi_get_mhi_state(mhi_cntrl); ee = mhi_get_exec_env(mhi_cntrl); - dev_dbg(dev, "local ee:%s device ee:%s dev_state:%s\n", - TO_MHI_EXEC_STR(mhi_cntrl->ee), TO_MHI_EXEC_STR(ee), - TO_MHI_STATE_STR(state)); + dev_dbg(dev, "local ee: %s state: %s device ee: %s state: %s\n", + TO_MHI_EXEC_STR(mhi_cntrl->ee), + TO_MHI_STATE_STR(mhi_cntrl->dev_state), + TO_MHI_EXEC_STR(ee), TO_MHI_STATE_STR(state)); if (state == MHI_STATE_SYS_ERR) { dev_dbg(dev, "System error detected\n"); -- cgit v1.2.3 From 6403298c58d4858d93648f553abf0bcbd2dfaca2 Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Fri, 12 Feb 2021 14:27:23 -0700 Subject: bus: mhi: core: Fix check for syserr at power_up The check to see if we have reset the device after detecting syserr at power_up is inverted. wait_for_event_timeout() returns 0 on failure, and a positive value on success. The check is looking for non-zero as a failure, which is likely to incorrectly cause a device init failure if syserr was detected at power_up. Fix this. Fixes: e18d4e9fa79b ("bus: mhi: core: Handle syserr during power_up") Signed-off-by: Jeffrey Hugo Reviewed-by: Loic Poulain Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1613165243-23359-1-git-send-email-jhugo@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c index b4ee9295e7af..adb0e80974f1 100644 --- a/drivers/bus/mhi/core/pm.c +++ b/drivers/bus/mhi/core/pm.c @@ -1101,7 +1101,7 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl) &val) || !val, msecs_to_jiffies(mhi_cntrl->timeout_ms)); - if (ret) { + if (!ret) { ret = -EIO; dev_info(dev, "Failed to reset MHI due to syserr state\n"); goto error_bhi_offset; -- cgit v1.2.3 From 4d5f52838d11981c4d76cdc4e73230120de1ac85 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Tue, 9 Mar 2021 10:46:35 -0800 Subject: bus: mhi: Make firmware image optional for controller Some controllers can opt to not have MHI download a firmware image to have the device bootup and can find the device in a pass through execution environment, ready to go. Thus, MHI controllers for those devices do not need fw_image defined. Make it optional to accommodate different bootup modes. Suggested-by: Loic Poulain Signed-off-by: Bhaumik Bhatt Reviewed-by: Jeffrey Hugo Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1615315595-37750-1-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- include/linux/mhi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/mhi.h b/include/linux/mhi.h index d26acc8b21cd..8f5bf409f663 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -296,7 +296,7 @@ struct mhi_controller_config { * @wake_db: MHI WAKE doorbell register address * @iova_start: IOMMU starting address for data (required) * @iova_stop: IOMMU stop address for data (required) - * @fw_image: Firmware image name for normal booting (required) + * @fw_image: Firmware image name for normal booting (optional) * @edl_image: Firmware image name for emergency download mode (optional) * @rddm_size: RAM dump size that host should allocate for debugging purpose * @sbl_size: SBL image size downloaded through BHIe (optional) -- cgit v1.2.3 From 015acd5d3addb0e2cae1c4e1ed81d5f0a1c785ad Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 26 Feb 2021 16:36:22 +0530 Subject: MAINTAINERS: Add linux-phy list and patchwork Linux-phy subsystem gained mailing list and a patchwork instance. Add the details to MAINTAINERS file Signed-off-by: Vinod Koul --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index d92f85ca831d..72453b2ecb7b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7476,8 +7476,9 @@ F: include/uapi/asm-generic/ GENERIC PHY FRAMEWORK M: Kishon Vijay Abraham I M: Vinod Koul -L: linux-kernel@vger.kernel.org +L: linux-phy@lists.infradead.org S: Supported +Q: https://patchwork.kernel.org/project/linux-phy/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy.git F: Documentation/devicetree/bindings/phy/ F: drivers/phy/ -- cgit v1.2.3 From eb445a15fa6910dd25b2fc1217ac39f47104b7d6 Mon Sep 17 00:00:00 2001 From: Liam Beguin Date: Fri, 11 Dec 2020 14:12:41 -0500 Subject: phy: tusb1210: use bitmasks to set VENDOR_SPECIFIC2 Start by reading the content of the VENDOR_SPECIFIC2 register and update each bit field based on device properties when defined. The use of bit masks prevents fields from overriding each other and enables users to clear bits which are set by default, like datapolarity in this instance. Signed-off-by: Liam Beguin Link: https://lore.kernel.org/r/20201211191241.21306-1-liambeguin@gmail.com Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-tusb1210.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/phy/ti/phy-tusb1210.c b/drivers/phy/ti/phy-tusb1210.c index d8d0cc11d187..a63213f5972a 100644 --- a/drivers/phy/ti/phy-tusb1210.c +++ b/drivers/phy/ti/phy-tusb1210.c @@ -7,15 +7,16 @@ * Author: Heikki Krogerus */ #include +#include #include #include #include #include #define TUSB1210_VENDOR_SPECIFIC2 0x80 -#define TUSB1210_VENDOR_SPECIFIC2_IHSTX_SHIFT 0 -#define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_SHIFT 4 -#define TUSB1210_VENDOR_SPECIFIC2_DP_SHIFT 6 +#define TUSB1210_VENDOR_SPECIFIC2_IHSTX_MASK GENMASK(3, 0) +#define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK GENMASK(5, 4) +#define TUSB1210_VENDOR_SPECIFIC2_DP_MASK BIT(6) struct tusb1210 { struct ulpi *ulpi; @@ -118,22 +119,22 @@ static int tusb1210_probe(struct ulpi *ulpi) * diagram optimization and DP/DM swap. */ + reg = ulpi_read(ulpi, TUSB1210_VENDOR_SPECIFIC2); + /* High speed output drive strength configuration */ - device_property_read_u8(&ulpi->dev, "ihstx", &val); - reg = val << TUSB1210_VENDOR_SPECIFIC2_IHSTX_SHIFT; + if (!device_property_read_u8(&ulpi->dev, "ihstx", &val)) + u8p_replace_bits(®, val, (u8)TUSB1210_VENDOR_SPECIFIC2_IHSTX_MASK); /* High speed output impedance configuration */ - device_property_read_u8(&ulpi->dev, "zhsdrv", &val); - reg |= val << TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_SHIFT; + if (!device_property_read_u8(&ulpi->dev, "zhsdrv", &val)) + u8p_replace_bits(®, val, (u8)TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK); /* DP/DM swap control */ - device_property_read_u8(&ulpi->dev, "datapolarity", &val); - reg |= val << TUSB1210_VENDOR_SPECIFIC2_DP_SHIFT; + if (!device_property_read_u8(&ulpi->dev, "datapolarity", &val)) + u8p_replace_bits(®, val, (u8)TUSB1210_VENDOR_SPECIFIC2_DP_MASK); - if (reg) { - ulpi_write(ulpi, TUSB1210_VENDOR_SPECIFIC2, reg); - tusb->vendor_specific2 = reg; - } + ulpi_write(ulpi, TUSB1210_VENDOR_SPECIFIC2, reg); + tusb->vendor_specific2 = reg; tusb->phy = ulpi_phy_create(ulpi, &phy_ops); if (IS_ERR(tusb->phy)) -- cgit v1.2.3 From 70f7025c854c7edc6965ec2ef4230d09ebb9ffd7 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 11 Mar 2021 11:17:27 +0000 Subject: bus: mhi: core: remove redundant initialization of variables state and ee The variables state and ee are being initialized with values that are never read and are being updated later with a new values. The initializations are redundant and can be removed. Signed-off-by: Colin Ian King Reviewed-by: Loic Poulain Reviewed-by: Manivannan Sadhasivam Addresses-Coverity: ("Unused value") Link: https://lore.kernel.org/r/20210311111727.8433-1-colin.king@canonical.com Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index 2c61dfd01353..3faf8bade520 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -428,9 +428,9 @@ irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv) { struct mhi_controller *mhi_cntrl = priv; struct device *dev = &mhi_cntrl->mhi_dev->dev; - enum mhi_state state = MHI_STATE_MAX; + enum mhi_state state; enum mhi_pm_state pm_state = 0; - enum mhi_ee_type ee = MHI_EE_MAX; + enum mhi_ee_type ee; write_lock_irq(&mhi_cntrl->pm_lock); if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) { -- cgit v1.2.3 From 12810cb9c2be12b0da64d295711fa932e9836ec9 Mon Sep 17 00:00:00 2001 From: Amelie Delaunay Date: Mon, 8 Feb 2021 12:46:58 +0100 Subject: dt-bindings: phy: phy-stm32-usbphyc: add #clock-cells property usbphyc provides a unique clock called ck_usbo_48m. STM32 USB OTG needs a 48Mhz clock (utmifs_clk48) for Full-Speed operation. ck_usbo_48m is a possible parent clock for USB OTG 48Mhz clock. ck_usbo_48m is available as soon as the PLL is enabled. Signed-off-by: Amelie Delaunay Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210208114659.15269-2-amelie.delaunay@foss.st.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.yaml b/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.yaml index 46df6786727a..018cc1246ee1 100644 --- a/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.yaml +++ b/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.yaml @@ -51,6 +51,10 @@ properties: vdda1v8-supply: description: regulator providing 1V8 power supply to the PLL block + '#clock-cells': + description: number of clock cells for ck_usbo_48m consumer + const: 0 + #Required child nodes: patternProperties: @@ -120,6 +124,7 @@ examples: vdda1v8-supply = <®18>; #address-cells = <1>; #size-cells = <0>; + #clock-cells = <0>; usbphyc_port0: usb-phy@0 { reg = <0>; -- cgit v1.2.3 From 7bc057dd65ab02995f21fa3b0f9d97261cd5aa2a Mon Sep 17 00:00:00 2001 From: Amelie Delaunay Date: Mon, 8 Feb 2021 12:46:59 +0100 Subject: phy: stm32: register usbphyc as clock provider of ck_usbo_48m clock ck_usbo_48m is generated by usbphyc PLL and used by OTG controller for Full-Speed use cases with dedicated Full-Speed transceiver. ck_usbo_48m is available as soon as the PLL is enabled. Signed-off-by: Amelie Delaunay Link: https://lore.kernel.org/r/20210208114659.15269-3-amelie.delaunay@foss.st.com Signed-off-by: Vinod Koul --- drivers/phy/st/Kconfig | 1 + drivers/phy/st/phy-stm32-usbphyc.c | 65 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/drivers/phy/st/Kconfig b/drivers/phy/st/Kconfig index b32f44ff9033..3fc3d0781fb8 100644 --- a/drivers/phy/st/Kconfig +++ b/drivers/phy/st/Kconfig @@ -36,6 +36,7 @@ config PHY_STIH407_USB config PHY_STM32_USBPHYC tristate "STMicroelectronics STM32 USB HS PHY Controller driver" depends on ARCH_STM32 || COMPILE_TEST + depends on COMMON_CLK select GENERIC_PHY help Enable this to support the High-Speed USB transceivers that are part diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c index d08fbb180e43..c184f4e34584 100644 --- a/drivers/phy/st/phy-stm32-usbphyc.c +++ b/drivers/phy/st/phy-stm32-usbphyc.c @@ -7,6 +7,7 @@ */ #include #include +#include #include #include #include @@ -70,6 +71,7 @@ struct stm32_usbphyc { struct regulator *vdda1v1; struct regulator *vdda1v8; atomic_t n_pll_cons; + struct clk_hw clk48_hw; int switch_setup; }; @@ -295,6 +297,61 @@ static const struct phy_ops stm32_usbphyc_phy_ops = { .owner = THIS_MODULE, }; +static int stm32_usbphyc_clk48_prepare(struct clk_hw *hw) +{ + struct stm32_usbphyc *usbphyc = container_of(hw, struct stm32_usbphyc, clk48_hw); + + return stm32_usbphyc_pll_enable(usbphyc); +} + +static void stm32_usbphyc_clk48_unprepare(struct clk_hw *hw) +{ + struct stm32_usbphyc *usbphyc = container_of(hw, struct stm32_usbphyc, clk48_hw); + + stm32_usbphyc_pll_disable(usbphyc); +} + +static unsigned long stm32_usbphyc_clk48_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + return 48000000; +} + +static const struct clk_ops usbphyc_clk48_ops = { + .prepare = stm32_usbphyc_clk48_prepare, + .unprepare = stm32_usbphyc_clk48_unprepare, + .recalc_rate = stm32_usbphyc_clk48_recalc_rate, +}; + +static void stm32_usbphyc_clk48_unregister(void *data) +{ + struct stm32_usbphyc *usbphyc = data; + + of_clk_del_provider(usbphyc->dev->of_node); + clk_hw_unregister(&usbphyc->clk48_hw); +} + +static int stm32_usbphyc_clk48_register(struct stm32_usbphyc *usbphyc) +{ + struct device_node *node = usbphyc->dev->of_node; + struct clk_init_data init = { }; + int ret = 0; + + init.name = "ck_usbo_48m"; + init.ops = &usbphyc_clk48_ops; + + usbphyc->clk48_hw.init = &init; + + ret = clk_hw_register(usbphyc->dev, &usbphyc->clk48_hw); + if (ret) + return ret; + + ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &usbphyc->clk48_hw); + if (ret) + clk_hw_unregister(&usbphyc->clk48_hw); + + return ret; +} + static void stm32_usbphyc_switch_setup(struct stm32_usbphyc *usbphyc, u32 utmi_switch) { @@ -473,6 +530,12 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) goto clk_disable; } + ret = stm32_usbphyc_clk48_register(usbphyc); + if (ret) { + dev_err(dev, "failed to register ck_usbo_48m clock: %d\n", ret); + goto clk_disable; + } + version = readl_relaxed(usbphyc->base + STM32_USBPHYC_VERSION); dev_info(dev, "registered rev:%lu.%lu\n", FIELD_GET(MAJREV, version), FIELD_GET(MINREV, version)); @@ -497,6 +560,8 @@ static int stm32_usbphyc_remove(struct platform_device *pdev) if (usbphyc->phys[port]->active) stm32_usbphyc_phy_exit(usbphyc->phys[port]->phy); + stm32_usbphyc_clk48_unregister(usbphyc); + clk_disable_unprepare(usbphyc->clk); return 0; -- cgit v1.2.3 From 6b5371adc3e56da66085aeef7e70bc8c33e6264c Mon Sep 17 00:00:00 2001 From: Junlin Yang Date: Tue, 16 Feb 2021 16:48:47 +0800 Subject: phy: rockchip-typec: add missing of_node_put Fix OF node leaks by calling of_node_put in for_each_available_child_of_node when the cycle returns. Generated by: scripts/coccinelle/iterators/for_each_child.cocci Signed-off-by: Junlin Yang Link: https://lore.kernel.org/r/20210216084847.1544-1-angkery@163.com Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-typec.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 70a31251b202..d2bbdc96a167 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -1180,6 +1180,7 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev) dev_err(dev, "failed to create phy: %pOFn\n", child_np); pm_runtime_disable(dev); + of_node_put(child_np); return PTR_ERR(phy); } -- cgit v1.2.3 From 00f2e6f668b05c259f3f8d1e943318bcad8486e7 Mon Sep 17 00:00:00 2001 From: Junlin Yang Date: Tue, 16 Feb 2021 16:27:39 +0800 Subject: phy: ti: j721e-wiz: add missing of_node_put Fix OF node leaks by calling of_node_put in for_each_child_of_node when the cycle returns. Generated by: scripts/coccinelle/iterators/for_each_child.cocci Signed-off-by: Junlin Yang Link: https://lore.kernel.org/r/20210216082739.1414-1-angkery@163.com Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-j721e-wiz.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index c9cfafe89cbf..8a4be1ec2816 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -792,6 +792,7 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz) dev_err(dev, "%s: Reading \"reg\" from \"%s\" failed: %d\n", __func__, subnode->name, ret); + of_node_put(subnode); return ret; } of_property_read_u32(subnode, "cdns,num-lanes", &num_lanes); -- cgit v1.2.3 From d0dde32dda5dd63a785f1b0d4a56055110f00e37 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 5 Mar 2021 04:02:19 -0600 Subject: phy: qcom-usb-hs: Fix fall-through warnings for Clang In preparation to enable -Wimplicit-fallthrough for Clang, fix a warning by explicitly adding a break statement instead of letting the code fall through to the next case. Link: https://github.com/KSPP/linux/issues/115 Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20210305100219.GA142595@embeddedor Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-usb-hs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/phy/qualcomm/phy-qcom-usb-hs.c b/drivers/phy/qualcomm/phy-qcom-usb-hs.c index 327df1a99f77..5c6c17673396 100644 --- a/drivers/phy/qualcomm/phy-qcom-usb-hs.c +++ b/drivers/phy/qualcomm/phy-qcom-usb-hs.c @@ -56,6 +56,7 @@ static int qcom_usb_hs_phy_set_mode(struct phy *phy, fallthrough; case PHY_MODE_USB_DEVICE: val |= ULPI_INT_SESS_VALID; + break; default: break; } -- cgit v1.2.3 From 261ab1fd5c5d2d7ff7d5bab3f5db3c69c4bcea58 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Fri, 5 Mar 2021 16:24:06 +0100 Subject: phy: phy-brcm-usb: select SOC_BRCMSTB on brcmstb only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit phy-brcm-usb has some conditional init code required on selected brcmstb devices. Execution of that code depends on family / product detected by brcmstb soc code. For ARCH_BCM4908 brcmstb soc code always return 0 values as ids. Don't bother selecting & compiling that redundant driver. Depends-on: 149ae80b1d50 ("soc: bcm: brcmstb: add stubs for getting platform IDs") Signed-off-by: Rafał Miłecki Acked-by: Florian Fainelli Link: https://lore.kernel.org/r/20210305152406.2588-1-zajec5@gmail.com Signed-off-by: Vinod Koul --- drivers/phy/broadcom/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/broadcom/Kconfig b/drivers/phy/broadcom/Kconfig index 09256339bd04..fd92b73b7109 100644 --- a/drivers/phy/broadcom/Kconfig +++ b/drivers/phy/broadcom/Kconfig @@ -94,7 +94,7 @@ config PHY_BRCM_USB depends on ARCH_BCM4908 || ARCH_BRCMSTB || COMPILE_TEST depends on OF select GENERIC_PHY - select SOC_BRCMSTB + select SOC_BRCMSTB if ARCH_BRCMSTB default ARCH_BCM4908 default ARCH_BRCMSTB help -- cgit v1.2.3 From d9de0cbd5b1f6b51c92a40937945f26a35d848ff Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Tue, 9 Mar 2021 19:26:16 +0100 Subject: dt-bindings: phy: brcm,brcmstb-usb-phy: add power-domains MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On BCM4908 USB PHY is managed using power controller so it needs describing properly using the power-domains. Signed-off-by: Rafał Miłecki Acked-by: Florian Fainelli Link: https://lore.kernel.org/r/20210309182616.25783-1-zajec5@gmail.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/brcm,brcmstb-usb-phy.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/brcm,brcmstb-usb-phy.yaml b/Documentation/devicetree/bindings/phy/brcm,brcmstb-usb-phy.yaml index 0497368d1fca..5f9e91bfb5ff 100644 --- a/Documentation/devicetree/bindings/phy/brcm,brcmstb-usb-phy.yaml +++ b/Documentation/devicetree/bindings/phy/brcm,brcmstb-usb-phy.yaml @@ -42,6 +42,9 @@ properties: - const: usb_mdio - const: bdc_ec + power-domains: + maxItems: 1 + clocks: minItems: 1 maxItems: 2 -- cgit v1.2.3 From 68731852f6e58d19f692971dc84deb64265f6d3f Mon Sep 17 00:00:00 2001 From: Fan Wu Date: Wed, 10 Mar 2021 13:40:03 -0700 Subject: bus: mhi: core: Return EAGAIN if MHI ring is full Currently ENOMEM is returned when MHI ring is full. This error code is very misleading. Change to EAGAIN instead. Signed-off-by: Fan Wu Signed-off-by: Jeffrey Hugo Reviewed-by: Hemant Kumar Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1615408803-7016-1-git-send-email-jhugo@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index 3faf8bade520..d377d07f269e 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -1020,7 +1020,7 @@ static int mhi_queue(struct mhi_device *mhi_dev, struct mhi_buf_info *buf_info, ret = mhi_is_ring_full(mhi_cntrl, tre_ring); if (unlikely(ret)) { - ret = -ENOMEM; + ret = -EAGAIN; goto exit_unlock; } -- cgit v1.2.3 From 9e40641f62cd812b21f2c73b5cfb3346eb466dea Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Wed, 10 Mar 2021 13:49:25 -0700 Subject: bus: mhi: core: Check state before processing power_down We cannot process a power_down if the power state is DISABLED. There is no valid mhi_ctxt in that case, so attepting to process the power_down will likely result in a null pointer dereference. If the power state is DISABLED, there is nothing to do anyways, so just bail early. Signed-off-by: Jeffrey Hugo Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1615409365-8165-1-git-send-email-jhugo@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/pm.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c index adb0e80974f1..fbe944730401 100644 --- a/drivers/bus/mhi/core/pm.c +++ b/drivers/bus/mhi/core/pm.c @@ -1134,6 +1134,7 @@ error_setup_irq: mhi_deinit_dev_ctxt(mhi_cntrl); error_dev_ctxt: + mhi_cntrl->pm_state = MHI_PM_DISABLE; mutex_unlock(&mhi_cntrl->pm_mutex); return ret; @@ -1145,12 +1146,19 @@ void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful) enum mhi_pm_state cur_state, transition_state; struct device *dev = &mhi_cntrl->mhi_dev->dev; + mutex_lock(&mhi_cntrl->pm_mutex); + write_lock_irq(&mhi_cntrl->pm_lock); + cur_state = mhi_cntrl->pm_state; + if (cur_state == MHI_PM_DISABLE) { + write_unlock_irq(&mhi_cntrl->pm_lock); + mutex_unlock(&mhi_cntrl->pm_mutex); + return; /* Already powered down */ + } + /* If it's not a graceful shutdown, force MHI to linkdown state */ transition_state = (graceful) ? MHI_PM_SHUTDOWN_PROCESS : MHI_PM_LD_ERR_FATAL_DETECT; - mutex_lock(&mhi_cntrl->pm_mutex); - write_lock_irq(&mhi_cntrl->pm_lock); cur_state = mhi_tryset_pm_state(mhi_cntrl, transition_state); if (cur_state != transition_state) { dev_err(dev, "Failed to move to state: %s from: %s\n", -- cgit v1.2.3 From 6c363eafc4d637ac4bd83d4a7dd06dd3cfbe7c5f Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 10 Mar 2021 16:57:43 +0530 Subject: dt-bindings: phy: ti,phy-j721e-wiz: Add bindings for AM64 SERDES Wrapper Add bindings for AM64 SERDES Wrapper. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210310112745.3445-2-kishon@ti.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/ti,phy-j721e-wiz.yaml | 4 ++++ include/dt-bindings/phy/phy-ti.h | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 include/dt-bindings/phy/phy-ti.h diff --git a/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml b/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml index bbbd85501ada..57e1d013a502 100644 --- a/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml +++ b/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml @@ -15,6 +15,7 @@ properties: enum: - ti,j721e-wiz-16g - ti,j721e-wiz-10g + - ti,am64-wiz-10g power-domains: maxItems: 1 @@ -42,6 +43,9 @@ properties: "#reset-cells": const: 1 + "#clock-cells": + const: 1 + ranges: true assigned-clocks: diff --git a/include/dt-bindings/phy/phy-ti.h b/include/dt-bindings/phy/phy-ti.h new file mode 100644 index 000000000000..ad955d3a56b4 --- /dev/null +++ b/include/dt-bindings/phy/phy-ti.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This header provides constants for TI SERDES. + */ + +#ifndef _DT_BINDINGS_TI_SERDES +#define _DT_BINDINGS_TI_SERDES + +/* Clock index for output clocks from WIZ */ + +/* MUX Clocks */ +#define TI_WIZ_PLL0_REFCLK 0 +#define TI_WIZ_PLL1_REFCLK 1 +#define TI_WIZ_REFCLK_DIG 2 + +/* Reserve index here for future additions */ + +/* MISC Clocks */ +#define TI_WIZ_PHY_EN_REFCLK 16 + +#endif /* _DT_BINDINGS_TI_SERDES */ -- cgit v1.2.3 From eaabb5595f99f357d8755573785ee62dbb649061 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 10 Mar 2021 16:57:44 +0530 Subject: dt-bindings: phy: cadence-torrent: Add binding for refclk driver Add binding for refclk driver used to route the refclk out of torrent SERDES. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210310112745.3445-3-kishon@ti.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/phy-cadence-torrent.yaml | 20 +++++++++++++++++--- include/dt-bindings/phy/phy-cadence-torrent.h | 2 ++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml b/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml index e266ade53d87..4608599a31d8 100644 --- a/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml +++ b/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml @@ -28,13 +28,27 @@ properties: '#size-cells': const: 0 + '#clock-cells': + const: 1 + clocks: - maxItems: 1 + minItems: 1 + maxItems: 2 description: - PHY reference clock. Must contain an entry in clock-names. + PHY reference clock for 1 item. Must contain an entry in clock-names. + Optional Parent to enable output reference clock. clock-names: - const: refclk + minItems: 1 + items: + - const: refclk + - const: phy_en_refclk + + assigned-clocks: + maxItems: 3 + + assigned-clock-parents: + maxItems: 3 reg: minItems: 1 diff --git a/include/dt-bindings/phy/phy-cadence-torrent.h b/include/dt-bindings/phy/phy-cadence-torrent.h index e387b6a95741..3c92c6192493 100644 --- a/include/dt-bindings/phy/phy-cadence-torrent.h +++ b/include/dt-bindings/phy/phy-cadence-torrent.h @@ -10,4 +10,6 @@ #define TORRENT_SERDES_EXTERNAL_SSC 1 #define TORRENT_SERDES_INTERNAL_SSC 2 +#define CDNS_TORRENT_REFCLK_DRIVER 0 + #endif /* _DT_BINDINGS_TORRENT_SERDES_H */ -- cgit v1.2.3 From 4709b21a0566bee2f00b1bd8fb926c08dd838438 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 10 Mar 2021 16:57:45 +0530 Subject: dt-bindings: ti-serdes-mux: Add defines for AM64 SoC AM64 has a single lane SERDES which can be configured to be used with either PCIe or USB. Define the possilbe values for the SERDES function in AM64 SoC here. Signed-off-by: Kishon Vijay Abraham I Acked-by: Peter Rosin Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210310112745.3445-4-kishon@ti.com Signed-off-by: Vinod Koul --- include/dt-bindings/mux/ti-serdes.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/dt-bindings/mux/ti-serdes.h b/include/dt-bindings/mux/ti-serdes.h index 9047ec6bd3cf..d417b9268b16 100644 --- a/include/dt-bindings/mux/ti-serdes.h +++ b/include/dt-bindings/mux/ti-serdes.h @@ -90,4 +90,9 @@ #define J7200_SERDES0_LANE3_USB 0x2 #define J7200_SERDES0_LANE3_IP4_UNUSED 0x3 +/* AM64 */ + +#define AM64_SERDES0_LANE0_PCIE0 0x0 +#define AM64_SERDES0_LANE0_USB 0x1 + #endif /* _DT_BINDINGS_MUX_TI_SERDES */ -- cgit v1.2.3 From 06c7af60e0e8b1e055eac57fd189ad2781dd4f21 Mon Sep 17 00:00:00 2001 From: Seiya Wang Date: Tue, 16 Mar 2021 19:14:40 +0800 Subject: dt-bindings: phy: Add compatible for Mediatek MT8195 This commit adds dt-binding documentation of T-Phy for Mediatek MT8195 SoC Platform. Signed-off-by: Seiya Wang Link: https://lore.kernel.org/r/20210316111443.3332-8-seiya.wang@mediatek.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/mediatek,tphy.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml index 602e6ff45785..c5b436ad6239 100644 --- a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml +++ b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml @@ -79,6 +79,7 @@ properties: - mediatek,mt2712-tphy - mediatek,mt7629-tphy - mediatek,mt8183-tphy + - mediatek,mt8195-tphy - const: mediatek,generic-tphy-v2 - const: mediatek,mt2701-u3phy deprecated: true -- cgit v1.2.3 From febe5ba3178dc01738bed3c38bf176291859a60d Mon Sep 17 00:00:00 2001 From: Seiya Wang Date: Tue, 16 Mar 2021 19:14:41 +0800 Subject: dt-bindings: phy: Add compatible for Mediatek MT8195 This commit adds dt-binding documentation of UFS M-Phy for Mediatek MT8195 SoC Platform. Signed-off-by: Seiya Wang Link: https://lore.kernel.org/r/20210316111443.3332-9-seiya.wang@mediatek.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/mediatek,ufs-phy.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/phy/mediatek,ufs-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,ufs-phy.yaml index 3a9be82e7f13..5235b1a0d188 100644 --- a/Documentation/devicetree/bindings/phy/mediatek,ufs-phy.yaml +++ b/Documentation/devicetree/bindings/phy/mediatek,ufs-phy.yaml @@ -22,6 +22,7 @@ properties: pattern: "^ufs-phy@[0-9a-f]+$" compatible: + enum: mediatek,mt8195-ufsphy const: mediatek,mt8183-ufsphy reg: -- cgit v1.2.3 From 13f99ac6c3586f030621e0b5f7bc598d6392d0a0 Mon Sep 17 00:00:00 2001 From: Steen Hegelund Date: Thu, 18 Feb 2021 17:14:48 +0100 Subject: dt-bindings: phy: Add sparx5-serdes bindings Document the Sparx5 ethernet serdes phy driver bindings. Signed-off-by: Lars Povlsen Signed-off-by: Steen Hegelund Reviewed-by: Rob Herring Reviewed-by: Andrew Lunn Reviewed-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210218161451.3489955-2-steen.hegelund@microchip.com Signed-off-by: Vinod Koul --- .../bindings/phy/microchip,sparx5-serdes.yaml | 100 +++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/microchip,sparx5-serdes.yaml diff --git a/Documentation/devicetree/bindings/phy/microchip,sparx5-serdes.yaml b/Documentation/devicetree/bindings/phy/microchip,sparx5-serdes.yaml new file mode 100644 index 000000000000..bdbdb3bbddbe --- /dev/null +++ b/Documentation/devicetree/bindings/phy/microchip,sparx5-serdes.yaml @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/microchip,sparx5-serdes.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microchip Sparx5 Serdes controller + +maintainers: + - Steen Hegelund + +description: | + The Sparx5 SERDES interfaces share the same basic functionality, but + support different operating modes and line rates. + + The following list lists the SERDES features: + + * RX Adaptive Decision Feedback Equalizer (DFE) + * Programmable continuous time linear equalizer (CTLE) + * Rx variable gain control + * Rx built-in fault detector (loss-of-lock/loss-of-signal) + * Adjustable tx de-emphasis (FFE) + * Tx output amplitude control + * Supports rx eye monitor + * Multiple loopback modes + * Prbs generator and checker + * Polarity inversion control + + SERDES6G: + + The SERDES6G is a high-speed SERDES interface, which can operate at + the following data rates: + + * 100 Mbps (100BASE-FX) + * 1.25 Gbps (SGMII/1000BASE-X/1000BASE-KX) + * 3.125 Gbps (2.5GBASE-X/2.5GBASE-KX) + * 5.15625 Gbps (5GBASE-KR/5G-USXGMII) + + SERDES10G + + The SERDES10G is a high-speed SERDES interface, which can operate at + the following data rates: + + * 100 Mbps (100BASE-FX) + * 1.25 Gbps (SGMII/1000BASE-X/1000BASE-KX) + * 3.125 Gbps (2.5GBASE-X/2.5GBASE-KX) + * 5 Gbps (QSGMII/USGMII) + * 5.15625 Gbps (5GBASE-KR/5G-USXGMII) + * 10 Gbps (10G-USGMII) + * 10.3125 Gbps (10GBASE-R/10GBASE-KR/USXGMII) + + SERDES25G + + The SERDES25G is a high-speed SERDES interface, which can operate at + the following data rates: + + * 1.25 Gbps (SGMII/1000BASE-X/1000BASE-KX) + * 3.125 Gbps (2.5GBASE-X/2.5GBASE-KX) + * 5 Gbps (QSGMII/USGMII) + * 5.15625 Gbps (5GBASE-KR/5G-USXGMII) + * 10 Gbps (10G-USGMII) + * 10.3125 Gbps (10GBASE-R/10GBASE-KR/USXGMII) + * 25.78125 Gbps (25GBASE-KR/25GBASE-CR/25GBASE-SR/25GBASE-LR/25GBASE-ER) + +properties: + $nodename: + pattern: "^serdes@[0-9a-f]+$" + + compatible: + const: microchip,sparx5-serdes + + reg: + minItems: 1 + + '#phy-cells': + const: 1 + description: | + - The main serdes input port + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - '#phy-cells' + - clocks + +additionalProperties: false + +examples: + - | + serdes: serdes@10808000 { + compatible = "microchip,sparx5-serdes"; + #phy-cells = <1>; + clocks = <&sys_clk>; + reg = <0x10808000 0x5d0000>; + }; + +... -- cgit v1.2.3 From 6c172e73690e59ba74ecf12139d841b8651693f8 Mon Sep 17 00:00:00 2001 From: Steen Hegelund Date: Thu, 18 Feb 2021 17:14:49 +0100 Subject: phy: Add media type and speed serdes configuration interfaces Provide new phy configuration interfaces for media type and speed that allows e.g. PHYs used for ethernet to be configured with this information. Signed-off-by: Lars Povlsen Signed-off-by: Steen Hegelund Reviewed-by: Andrew Lunn Reviewed-by: Alexandre Belloni Acked-By: Kishon Vijay Abraham I Link: https://lore.kernel.org/r/20210218161451.3489955-3-steen.hegelund@microchip.com Signed-off-by: Vinod Koul --- drivers/phy/phy-core.c | 30 ++++++++++++++++++++++++++++++ include/linux/phy/phy.h | 26 ++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 71cb10826326..ccb575b13777 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -373,6 +373,36 @@ int phy_set_mode_ext(struct phy *phy, enum phy_mode mode, int submode) } EXPORT_SYMBOL_GPL(phy_set_mode_ext); +int phy_set_media(struct phy *phy, enum phy_media media) +{ + int ret; + + if (!phy || !phy->ops->set_media) + return 0; + + mutex_lock(&phy->mutex); + ret = phy->ops->set_media(phy, media); + mutex_unlock(&phy->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(phy_set_media); + +int phy_set_speed(struct phy *phy, int speed) +{ + int ret; + + if (!phy || !phy->ops->set_speed) + return 0; + + mutex_lock(&phy->mutex); + ret = phy->ops->set_speed(phy, speed); + mutex_unlock(&phy->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(phy_set_speed); + int phy_reset(struct phy *phy) { int ret; diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index e435bdb0bab3..0ed434d02196 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h @@ -44,6 +44,12 @@ enum phy_mode { PHY_MODE_DP }; +enum phy_media { + PHY_MEDIA_DEFAULT, + PHY_MEDIA_SR, + PHY_MEDIA_DAC, +}; + /** * union phy_configure_opts - Opaque generic phy configuration * @@ -64,6 +70,8 @@ union phy_configure_opts { * @power_on: powering on the phy * @power_off: powering off the phy * @set_mode: set the mode of the phy + * @set_media: set the media type of the phy (optional) + * @set_speed: set the speed of the phy (optional) * @reset: resetting the phy * @calibrate: calibrate the phy * @release: ops to be performed while the consumer relinquishes the PHY @@ -75,6 +83,8 @@ struct phy_ops { int (*power_on)(struct phy *phy); int (*power_off)(struct phy *phy); int (*set_mode)(struct phy *phy, enum phy_mode mode, int submode); + int (*set_media)(struct phy *phy, enum phy_media media); + int (*set_speed)(struct phy *phy, int speed); /** * @configure: @@ -215,6 +225,8 @@ int phy_power_off(struct phy *phy); int phy_set_mode_ext(struct phy *phy, enum phy_mode mode, int submode); #define phy_set_mode(phy, mode) \ phy_set_mode_ext(phy, mode, 0) +int phy_set_media(struct phy *phy, enum phy_media media); +int phy_set_speed(struct phy *phy, int speed); int phy_configure(struct phy *phy, union phy_configure_opts *opts); int phy_validate(struct phy *phy, enum phy_mode mode, int submode, union phy_configure_opts *opts); @@ -344,6 +356,20 @@ static inline int phy_set_mode_ext(struct phy *phy, enum phy_mode mode, #define phy_set_mode(phy, mode) \ phy_set_mode_ext(phy, mode, 0) +static inline int phy_set_media(struct phy *phy, enum phy_media media) +{ + if (!phy) + return 0; + return -ENODEV; +} + +static inline int phy_set_speed(struct phy *phy, int speed) +{ + if (!phy) + return 0; + return -ENODEV; +} + static inline enum phy_mode phy_get_mode(struct phy *phy) { return PHY_MODE_INVALID; -- cgit v1.2.3 From 2ff8a1eeb5aa8bb471f3756a695b8b69841eb61f Mon Sep 17 00:00:00 2001 From: Steen Hegelund Date: Thu, 18 Feb 2021 17:14:50 +0100 Subject: phy: Add Sparx5 ethernet serdes PHY driver Add the Microchip Sparx5 ethernet serdes PHY driver for the 6G, 10G and 25G interfaces available in the Sparx5 SoC. Signed-off-by: Bjarni Jonasson Signed-off-by: Steen Hegelund Reviewed-by: Andrew Lunn Reviewed-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210218161451.3489955-4-steen.hegelund@microchip.com Signed-off-by: Vinod Koul --- drivers/phy/Kconfig | 1 + drivers/phy/Makefile | 1 + drivers/phy/microchip/Kconfig | 12 + drivers/phy/microchip/Makefile | 6 + drivers/phy/microchip/sparx5_serdes.c | 2480 +++++++++++++++++++++++++ drivers/phy/microchip/sparx5_serdes.h | 136 ++ drivers/phy/microchip/sparx5_serdes_regs.h | 2695 ++++++++++++++++++++++++++++ 7 files changed, 5331 insertions(+) create mode 100644 drivers/phy/microchip/Kconfig create mode 100644 drivers/phy/microchip/Makefile create mode 100644 drivers/phy/microchip/sparx5_serdes.c create mode 100644 drivers/phy/microchip/sparx5_serdes.h create mode 100644 drivers/phy/microchip/sparx5_serdes_regs.h diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 68d9c2f6a5ca..54c1f2f0985f 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -71,6 +71,7 @@ source "drivers/phy/ingenic/Kconfig" source "drivers/phy/lantiq/Kconfig" source "drivers/phy/marvell/Kconfig" source "drivers/phy/mediatek/Kconfig" +source "drivers/phy/microchip/Kconfig" source "drivers/phy/motorola/Kconfig" source "drivers/phy/mscc/Kconfig" source "drivers/phy/qualcomm/Kconfig" diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 32261e164abd..adac1b1a39d1 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -20,6 +20,7 @@ obj-y += allwinner/ \ lantiq/ \ marvell/ \ mediatek/ \ + microchip/ \ motorola/ \ mscc/ \ qualcomm/ \ diff --git a/drivers/phy/microchip/Kconfig b/drivers/phy/microchip/Kconfig new file mode 100644 index 000000000000..0b1a818e01b8 --- /dev/null +++ b/drivers/phy/microchip/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Phy drivers for Microchip devices +# + +config PHY_SPARX5_SERDES + tristate "Microchip Sparx5 SerDes PHY driver" + select GENERIC_PHY + depends on OF + depends on HAS_IOMEM + help + Enable this for support of the 10G/25G SerDes on Microchip Sparx5. diff --git a/drivers/phy/microchip/Makefile b/drivers/phy/microchip/Makefile new file mode 100644 index 000000000000..7b98345712aa --- /dev/null +++ b/drivers/phy/microchip/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for the Microchip phy drivers. +# + +obj-$(CONFIG_PHY_SPARX5_SERDES) := sparx5_serdes.o diff --git a/drivers/phy/microchip/sparx5_serdes.c b/drivers/phy/microchip/sparx5_serdes.c new file mode 100644 index 000000000000..06bcf0c166cf --- /dev/null +++ b/drivers/phy/microchip/sparx5_serdes.c @@ -0,0 +1,2480 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Microchip Sparx5 Switch SerDes driver + * + * Copyright (c) 2020 Microchip Technology Inc. and its subsidiaries. + * + * The Sparx5 Chip Register Model can be browsed at this location: + * https://github.com/microchip-ung/sparx-5_reginfo + * and the datasheet is available here: + * https://ww1.microchip.com/downloads/en/DeviceDoc/SparX-5_Family_L2L3_Enterprise_10G_Ethernet_Switches_Datasheet_00003822B.pdf + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sparx5_serdes.h" + +#define SPX5_CMU_MAX 14 + +#define SPX5_SERDES_10G_START 13 +#define SPX5_SERDES_25G_START 25 + +enum sparx5_10g28cmu_mode { + SPX5_SD10G28_CMU_MAIN = 0, + SPX5_SD10G28_CMU_AUX1 = 1, + SPX5_SD10G28_CMU_AUX2 = 3, + SPX5_SD10G28_CMU_NONE = 4, +}; + +enum sparx5_sd25g28_mode_preset_type { + SPX5_SD25G28_MODE_PRESET_25000, + SPX5_SD25G28_MODE_PRESET_10000, + SPX5_SD25G28_MODE_PRESET_5000, + SPX5_SD25G28_MODE_PRESET_SD_2G5, + SPX5_SD25G28_MODE_PRESET_1000BASEX, +}; + +enum sparx5_sd10g28_mode_preset_type { + SPX5_SD10G28_MODE_PRESET_10000, + SPX5_SD10G28_MODE_PRESET_SFI_5000_6G, + SPX5_SD10G28_MODE_PRESET_SFI_5000_10G, + SPX5_SD10G28_MODE_PRESET_QSGMII, + SPX5_SD10G28_MODE_PRESET_SD_2G5, + SPX5_SD10G28_MODE_PRESET_1000BASEX, +}; + +struct sparx5_serdes_io_resource { + enum sparx5_serdes_target id; + phys_addr_t offset; +}; + +struct sparx5_sd25g28_mode_preset { + u8 bitwidth; + u8 tx_pre_div; + u8 fifo_ck_div; + u8 pre_divsel; + u8 vco_div_mode; + u8 sel_div; + u8 ck_bitwidth; + u8 subrate; + u8 com_txcal_en; + u8 com_tx_reserve_msb; + u8 com_tx_reserve_lsb; + u8 cfg_itx_ipcml_base; + u8 tx_reserve_lsb; + u8 tx_reserve_msb; + u8 bw; + u8 rxterm; + u8 dfe_tap; + u8 dfe_enable; + bool txmargin; + u8 cfg_ctle_rstn; + u8 r_dfe_rstn; + u8 cfg_pi_bw_3_0; + u8 tx_tap_dly; + u8 tx_tap_adv; +}; + +struct sparx5_sd25g28_media_preset { + u8 cfg_eq_c_force_3_0; + u8 cfg_vga_ctrl_byp_4_0; + u8 cfg_eq_r_force_3_0; + u8 cfg_en_adv; + u8 cfg_en_main; + u8 cfg_en_dly; + u8 cfg_tap_adv_3_0; + u8 cfg_tap_main; + u8 cfg_tap_dly_4_0; + u8 cfg_alos_thr_2_0; +}; + +struct sparx5_sd25g28_args { + u8 if_width; /* UDL if-width: 10/16/20/32/64 */ + bool skip_cmu_cfg:1; /* Enable/disable CMU cfg */ + enum sparx5_10g28cmu_mode cmu_sel; /* Device/Mode serdes uses */ + bool no_pwrcycle:1; /* Omit initial power-cycle */ + bool txinvert:1; /* Enable inversion of output data */ + bool rxinvert:1; /* Enable inversion of input data */ + u16 txswing; /* Set output level */ + u8 rate; /* Rate of network interface */ + u8 pi_bw_gen1; + u8 duty_cycle; /* Set output level to half/full */ + bool mute:1; /* Mute Output Buffer */ + bool reg_rst:1; + u8 com_pll_reserve; +}; + +struct sparx5_sd25g28_params { + u8 reg_rst; + u8 cfg_jc_byp; + u8 cfg_common_reserve_7_0; + u8 r_reg_manual; + u8 r_d_width_ctrl_from_hwt; + u8 r_d_width_ctrl_2_0; + u8 r_txfifo_ck_div_pmad_2_0; + u8 r_rxfifo_ck_div_pmad_2_0; + u8 cfg_pll_lol_set; + u8 cfg_vco_div_mode_1_0; + u8 cfg_pre_divsel_1_0; + u8 cfg_sel_div_3_0; + u8 cfg_vco_start_code_3_0; + u8 cfg_pma_tx_ck_bitwidth_2_0; + u8 cfg_tx_prediv_1_0; + u8 cfg_rxdiv_sel_2_0; + u8 cfg_tx_subrate_2_0; + u8 cfg_rx_subrate_2_0; + u8 r_multi_lane_mode; + u8 cfg_cdrck_en; + u8 cfg_dfeck_en; + u8 cfg_dfe_pd; + u8 cfg_dfedmx_pd; + u8 cfg_dfetap_en_5_1; + u8 cfg_dmux_pd; + u8 cfg_dmux_clk_pd; + u8 cfg_erramp_pd; + u8 cfg_pi_dfe_en; + u8 cfg_pi_en; + u8 cfg_pd_ctle; + u8 cfg_summer_en; + u8 cfg_pmad_ck_pd; + u8 cfg_pd_clk; + u8 cfg_pd_cml; + u8 cfg_pd_driver; + u8 cfg_rx_reg_pu; + u8 cfg_pd_rms_det; + u8 cfg_dcdr_pd; + u8 cfg_ecdr_pd; + u8 cfg_pd_sq; + u8 cfg_itx_ipdriver_base_2_0; + u8 cfg_tap_dly_4_0; + u8 cfg_tap_main; + u8 cfg_en_main; + u8 cfg_tap_adv_3_0; + u8 cfg_en_adv; + u8 cfg_en_dly; + u8 cfg_iscan_en; + u8 l1_pcs_en_fast_iscan; + u8 l0_cfg_bw_1_0; + u8 l0_cfg_txcal_en; + u8 cfg_en_dummy; + u8 cfg_pll_reserve_3_0; + u8 l0_cfg_tx_reserve_15_8; + u8 l0_cfg_tx_reserve_7_0; + u8 cfg_tx_reserve_15_8; + u8 cfg_tx_reserve_7_0; + u8 cfg_bw_1_0; + u8 cfg_txcal_man_en; + u8 cfg_phase_man_4_0; + u8 cfg_quad_man_1_0; + u8 cfg_txcal_shift_code_5_0; + u8 cfg_txcal_valid_sel_3_0; + u8 cfg_txcal_en; + u8 cfg_cdr_kf_2_0; + u8 cfg_cdr_m_7_0; + u8 cfg_pi_bw_3_0; + u8 cfg_pi_steps_1_0; + u8 cfg_dis_2ndorder; + u8 cfg_ctle_rstn; + u8 r_dfe_rstn; + u8 cfg_alos_thr_2_0; + u8 cfg_itx_ipcml_base_1_0; + u8 cfg_rx_reserve_7_0; + u8 cfg_rx_reserve_15_8; + u8 cfg_rxterm_2_0; + u8 cfg_fom_selm; + u8 cfg_rx_sp_ctle_1_0; + u8 cfg_isel_ctle_1_0; + u8 cfg_vga_ctrl_byp_4_0; + u8 cfg_vga_byp; + u8 cfg_agc_adpt_byp; + u8 cfg_eqr_byp; + u8 cfg_eqr_force_3_0; + u8 cfg_eqc_force_3_0; + u8 cfg_sum_setcm_en; + u8 cfg_init_pos_iscan_6_0; + u8 cfg_init_pos_ipi_6_0; + u8 cfg_dfedig_m_2_0; + u8 cfg_en_dfedig; + u8 cfg_pi_DFE_en; + u8 cfg_tx2rx_lp_en; + u8 cfg_txlb_en; + u8 cfg_rx2tx_lp_en; + u8 cfg_rxlb_en; + u8 r_tx_pol_inv; + u8 r_rx_pol_inv; +}; + +struct sparx5_sd10g28_media_preset { + u8 cfg_en_adv; + u8 cfg_en_main; + u8 cfg_en_dly; + u8 cfg_tap_adv_3_0; + u8 cfg_tap_main; + u8 cfg_tap_dly_4_0; + u8 cfg_vga_ctrl_3_0; + u8 cfg_vga_cp_2_0; + u8 cfg_eq_res_3_0; + u8 cfg_eq_r_byp; + u8 cfg_eq_c_force_3_0; + u8 cfg_alos_thr_3_0; +}; + +struct sparx5_sd10g28_mode_preset { + u8 bwidth; /* interface width: 10/16/20/32/64 */ + enum sparx5_10g28cmu_mode cmu_sel; /* Device/Mode serdes uses */ + u8 rate; /* Rate of network interface */ + u8 dfe_tap; + u8 dfe_enable; + u8 pi_bw_gen1; + u8 duty_cycle; /* Set output level to half/full */ +}; + +struct sparx5_sd10g28_args { + bool skip_cmu_cfg:1; /* Enable/disable CMU cfg */ + bool no_pwrcycle:1; /* Omit initial power-cycle */ + bool txinvert:1; /* Enable inversion of output data */ + bool rxinvert:1; /* Enable inversion of input data */ + bool txmargin:1; /* Set output level to half/full */ + u16 txswing; /* Set output level */ + bool mute:1; /* Mute Output Buffer */ + bool is_6g:1; + bool reg_rst:1; +}; + +struct sparx5_sd10g28_params { + u8 cmu_sel; + u8 is_6g; + u8 skip_cmu_cfg; + u8 cfg_lane_reserve_7_0; + u8 cfg_ssc_rtl_clk_sel; + u8 cfg_lane_reserve_15_8; + u8 cfg_txrate_1_0; + u8 cfg_rxrate_1_0; + u8 r_d_width_ctrl_2_0; + u8 cfg_pma_tx_ck_bitwidth_2_0; + u8 cfg_rxdiv_sel_2_0; + u8 r_pcs2pma_phymode_4_0; + u8 cfg_lane_id_2_0; + u8 cfg_cdrck_en; + u8 cfg_dfeck_en; + u8 cfg_dfe_pd; + u8 cfg_dfetap_en_5_1; + u8 cfg_erramp_pd; + u8 cfg_pi_DFE_en; + u8 cfg_pi_en; + u8 cfg_pd_ctle; + u8 cfg_summer_en; + u8 cfg_pd_rx_cktree; + u8 cfg_pd_clk; + u8 cfg_pd_cml; + u8 cfg_pd_driver; + u8 cfg_rx_reg_pu; + u8 cfg_d_cdr_pd; + u8 cfg_pd_sq; + u8 cfg_rxdet_en; + u8 cfg_rxdet_str; + u8 r_multi_lane_mode; + u8 cfg_en_adv; + u8 cfg_en_main; + u8 cfg_en_dly; + u8 cfg_tap_adv_3_0; + u8 cfg_tap_main; + u8 cfg_tap_dly_4_0; + u8 cfg_vga_ctrl_3_0; + u8 cfg_vga_cp_2_0; + u8 cfg_eq_res_3_0; + u8 cfg_eq_r_byp; + u8 cfg_eq_c_force_3_0; + u8 cfg_en_dfedig; + u8 cfg_sum_setcm_en; + u8 cfg_en_preemph; + u8 cfg_itx_ippreemp_base_1_0; + u8 cfg_itx_ipdriver_base_2_0; + u8 cfg_ibias_tune_reserve_5_0; + u8 cfg_txswing_half; + u8 cfg_dis_2nd_order; + u8 cfg_rx_ssc_lh; + u8 cfg_pi_floop_steps_1_0; + u8 cfg_pi_ext_dac_23_16; + u8 cfg_pi_ext_dac_15_8; + u8 cfg_iscan_ext_dac_7_0; + u8 cfg_cdr_kf_gen1_2_0; + u8 cfg_cdr_kf_gen2_2_0; + u8 cfg_cdr_kf_gen3_2_0; + u8 cfg_cdr_kf_gen4_2_0; + u8 r_cdr_m_gen1_7_0; + u8 cfg_pi_bw_gen1_3_0; + u8 cfg_pi_bw_gen2; + u8 cfg_pi_bw_gen3; + u8 cfg_pi_bw_gen4; + u8 cfg_pi_ext_dac_7_0; + u8 cfg_pi_steps; + u8 cfg_mp_max_3_0; + u8 cfg_rstn_dfedig; + u8 cfg_alos_thr_3_0; + u8 cfg_predrv_slewrate_1_0; + u8 cfg_itx_ipcml_base_1_0; + u8 cfg_ip_pre_base_1_0; + u8 r_cdr_m_gen2_7_0; + u8 r_cdr_m_gen3_7_0; + u8 r_cdr_m_gen4_7_0; + u8 r_en_auto_cdr_rstn; + u8 cfg_oscal_afe; + u8 cfg_pd_osdac_afe; + u8 cfg_resetb_oscal_afe[2]; + u8 cfg_center_spreading; + u8 cfg_m_cnt_maxval_4_0; + u8 cfg_ncnt_maxval_7_0; + u8 cfg_ncnt_maxval_10_8; + u8 cfg_ssc_en; + u8 cfg_tx2rx_lp_en; + u8 cfg_txlb_en; + u8 cfg_rx2tx_lp_en; + u8 cfg_rxlb_en; + u8 r_tx_pol_inv; + u8 r_rx_pol_inv; + u8 fx_100; +}; + +struct sparx5_serdes_regval { + u32 value; + u32 mask; + void __iomem *addr; +}; + +static struct sparx5_sd25g28_media_preset media_presets_25g[] = { + { /* ETH_MEDIA_DEFAULT */ + .cfg_en_adv = 0, + .cfg_en_main = 1, + .cfg_en_dly = 0, + .cfg_tap_adv_3_0 = 0, + .cfg_tap_main = 1, + .cfg_tap_dly_4_0 = 0, + .cfg_eq_c_force_3_0 = 0xf, + .cfg_vga_ctrl_byp_4_0 = 4, + .cfg_eq_r_force_3_0 = 12, + .cfg_alos_thr_2_0 = 7, + }, + { /* ETH_MEDIA_SR */ + .cfg_en_adv = 1, + .cfg_en_main = 1, + .cfg_en_dly = 1, + .cfg_tap_adv_3_0 = 0, + .cfg_tap_main = 1, + .cfg_tap_dly_4_0 = 0x10, + .cfg_eq_c_force_3_0 = 0xf, + .cfg_vga_ctrl_byp_4_0 = 8, + .cfg_eq_r_force_3_0 = 4, + .cfg_alos_thr_2_0 = 0, + }, + { /* ETH_MEDIA_DAC */ + .cfg_en_adv = 0, + .cfg_en_main = 1, + .cfg_en_dly = 0, + .cfg_tap_adv_3_0 = 0, + .cfg_tap_main = 1, + .cfg_tap_dly_4_0 = 0, + .cfg_eq_c_force_3_0 = 0xf, + .cfg_vga_ctrl_byp_4_0 = 8, + .cfg_eq_r_force_3_0 = 0xc, + .cfg_alos_thr_2_0 = 0, + }, +}; + +static struct sparx5_sd25g28_mode_preset mode_presets_25g[] = { + { /* SPX5_SD25G28_MODE_PRESET_25000 */ + .bitwidth = 40, + .tx_pre_div = 0, + .fifo_ck_div = 0, + .pre_divsel = 1, + .vco_div_mode = 0, + .sel_div = 15, + .ck_bitwidth = 3, + .subrate = 0, + .com_txcal_en = 0, + .com_tx_reserve_msb = (0x26 << 1), + .com_tx_reserve_lsb = 0xf0, + .cfg_itx_ipcml_base = 0, + .tx_reserve_msb = 0xcc, + .tx_reserve_lsb = 0xfe, + .bw = 3, + .rxterm = 0, + .dfe_enable = 1, + .dfe_tap = 0x1f, + .txmargin = 1, + .cfg_ctle_rstn = 1, + .r_dfe_rstn = 1, + .cfg_pi_bw_3_0 = 0, + .tx_tap_dly = 8, + .tx_tap_adv = 0xc, + }, + { /* SPX5_SD25G28_MODE_PRESET_10000 */ + .bitwidth = 64, + .tx_pre_div = 0, + .fifo_ck_div = 2, + .pre_divsel = 0, + .vco_div_mode = 1, + .sel_div = 9, + .ck_bitwidth = 0, + .subrate = 0, + .com_txcal_en = 1, + .com_tx_reserve_msb = (0x20 << 1), + .com_tx_reserve_lsb = 0x40, + .cfg_itx_ipcml_base = 0, + .tx_reserve_msb = 0x4c, + .tx_reserve_lsb = 0x44, + .bw = 3, + .cfg_pi_bw_3_0 = 0, + .rxterm = 3, + .dfe_enable = 1, + .dfe_tap = 0x1f, + .txmargin = 0, + .cfg_ctle_rstn = 1, + .r_dfe_rstn = 1, + .tx_tap_dly = 0, + .tx_tap_adv = 0, + }, + { /* SPX5_SD25G28_MODE_PRESET_5000 */ + .bitwidth = 64, + .tx_pre_div = 0, + .fifo_ck_div = 2, + .pre_divsel = 0, + .vco_div_mode = 2, + .sel_div = 9, + .ck_bitwidth = 0, + .subrate = 0, + .com_txcal_en = 1, + .com_tx_reserve_msb = (0x20 << 1), + .com_tx_reserve_lsb = 0, + .cfg_itx_ipcml_base = 0, + .tx_reserve_msb = 0xe, + .tx_reserve_lsb = 0x80, + .bw = 0, + .rxterm = 0, + .cfg_pi_bw_3_0 = 6, + .dfe_enable = 0, + .dfe_tap = 0, + .tx_tap_dly = 0, + .tx_tap_adv = 0, + }, + { /* SPX5_SD25G28_MODE_PRESET_SD_2G5 */ + .bitwidth = 10, + .tx_pre_div = 0, + .fifo_ck_div = 0, + .pre_divsel = 0, + .vco_div_mode = 1, + .sel_div = 6, + .ck_bitwidth = 3, + .subrate = 2, + .com_txcal_en = 1, + .com_tx_reserve_msb = (0x26 << 1), + .com_tx_reserve_lsb = (0xf << 4), + .cfg_itx_ipcml_base = 2, + .tx_reserve_msb = 0x8, + .tx_reserve_lsb = 0x8a, + .bw = 0, + .cfg_pi_bw_3_0 = 0, + .rxterm = (1 << 2), + .dfe_enable = 0, + .dfe_tap = 0, + .tx_tap_dly = 0, + .tx_tap_adv = 0, + }, + { /* SPX5_SD25G28_MODE_PRESET_1000BASEX */ + .bitwidth = 10, + .tx_pre_div = 0, + .fifo_ck_div = 1, + .pre_divsel = 0, + .vco_div_mode = 1, + .sel_div = 8, + .ck_bitwidth = 3, + .subrate = 3, + .com_txcal_en = 1, + .com_tx_reserve_msb = (0x26 << 1), + .com_tx_reserve_lsb = 0xf0, + .cfg_itx_ipcml_base = 0, + .tx_reserve_msb = 0x8, + .tx_reserve_lsb = 0xce, + .bw = 0, + .rxterm = 0, + .cfg_pi_bw_3_0 = 0, + .dfe_enable = 0, + .dfe_tap = 0, + .tx_tap_dly = 0, + .tx_tap_adv = 0, + }, +}; + +static struct sparx5_sd10g28_media_preset media_presets_10g[] = { + { /* ETH_MEDIA_DEFAULT */ + .cfg_en_adv = 0, + .cfg_en_main = 1, + .cfg_en_dly = 0, + .cfg_tap_adv_3_0 = 0, + .cfg_tap_main = 1, + .cfg_tap_dly_4_0 = 0, + .cfg_vga_ctrl_3_0 = 5, + .cfg_vga_cp_2_0 = 0, + .cfg_eq_res_3_0 = 0xa, + .cfg_eq_r_byp = 1, + .cfg_eq_c_force_3_0 = 0x8, + .cfg_alos_thr_3_0 = 0x3, + }, + { /* ETH_MEDIA_SR */ + .cfg_en_adv = 1, + .cfg_en_main = 1, + .cfg_en_dly = 1, + .cfg_tap_adv_3_0 = 0, + .cfg_tap_main = 1, + .cfg_tap_dly_4_0 = 0xc, + .cfg_vga_ctrl_3_0 = 0xa, + .cfg_vga_cp_2_0 = 0x4, + .cfg_eq_res_3_0 = 0xa, + .cfg_eq_r_byp = 1, + .cfg_eq_c_force_3_0 = 0xF, + .cfg_alos_thr_3_0 = 0x3, + }, + { /* ETH_MEDIA_DAC */ + .cfg_en_adv = 1, + .cfg_en_main = 1, + .cfg_en_dly = 1, + .cfg_tap_adv_3_0 = 12, + .cfg_tap_main = 1, + .cfg_tap_dly_4_0 = 8, + .cfg_vga_ctrl_3_0 = 0xa, + .cfg_vga_cp_2_0 = 4, + .cfg_eq_res_3_0 = 0xa, + .cfg_eq_r_byp = 1, + .cfg_eq_c_force_3_0 = 0xf, + .cfg_alos_thr_3_0 = 0x0, + } +}; + +static struct sparx5_sd10g28_mode_preset mode_presets_10g[] = { + { /* SPX5_SD10G28_MODE_PRESET_10000 */ + .bwidth = 64, + .cmu_sel = SPX5_SD10G28_CMU_MAIN, + .rate = 0x0, + .dfe_enable = 1, + .dfe_tap = 0x1f, + .pi_bw_gen1 = 0x0, + .duty_cycle = 0x2, + }, + { /* SPX5_SD10G28_MODE_PRESET_SFI_5000_6G */ + .bwidth = 16, + .cmu_sel = SPX5_SD10G28_CMU_MAIN, + .rate = 0x1, + .dfe_enable = 0, + .dfe_tap = 0, + .pi_bw_gen1 = 0x5, + .duty_cycle = 0x0, + }, + { /* SPX5_SD10G28_MODE_PRESET_SFI_5000_10G */ + .bwidth = 64, + .cmu_sel = SPX5_SD10G28_CMU_MAIN, + .rate = 0x1, + .dfe_enable = 0, + .dfe_tap = 0, + .pi_bw_gen1 = 0x5, + .duty_cycle = 0x0, + }, + { /* SPX5_SD10G28_MODE_PRESET_QSGMII */ + .bwidth = 20, + .cmu_sel = SPX5_SD10G28_CMU_AUX1, + .rate = 0x1, + .dfe_enable = 0, + .dfe_tap = 0, + .pi_bw_gen1 = 0x5, + .duty_cycle = 0x0, + }, + { /* SPX5_SD10G28_MODE_PRESET_SD_2G5 */ + .bwidth = 10, + .cmu_sel = SPX5_SD10G28_CMU_AUX2, + .rate = 0x2, + .dfe_enable = 0, + .dfe_tap = 0, + .pi_bw_gen1 = 0x7, + .duty_cycle = 0x0, + }, + { /* SPX5_SD10G28_MODE_PRESET_1000BASEX */ + .bwidth = 10, + .cmu_sel = SPX5_SD10G28_CMU_AUX1, + .rate = 0x3, + .dfe_enable = 0, + .dfe_tap = 0, + .pi_bw_gen1 = 0x7, + .duty_cycle = 0x0, + }, +}; + +/* map from SD25G28 interface width to configuration value */ +static u8 sd25g28_get_iw_setting(struct device *dev, const u8 interface_width) +{ + switch (interface_width) { + case 10: return 0; + case 16: return 1; + case 32: return 3; + case 40: return 4; + case 64: return 5; + default: + dev_err(dev, "%s: Illegal value %d for interface width\n", + __func__, interface_width); + } + return 0; +} + +/* map from SD10G28 interface width to configuration value */ +static u8 sd10g28_get_iw_setting(struct device *dev, const u8 interface_width) +{ + switch (interface_width) { + case 10: return 0; + case 16: return 1; + case 20: return 2; + case 32: return 3; + case 40: return 4; + case 64: return 7; + default: + dev_err(dev, "%s: Illegal value %d for interface width\n", __func__, + interface_width); + return 0; + } +} + +static int sparx5_sd10g25_get_mode_preset(struct sparx5_serdes_macro *macro, + struct sparx5_sd25g28_mode_preset *mode) +{ + switch (macro->serdesmode) { + case SPX5_SD_MODE_SFI: + if (macro->speed == SPEED_25000) + *mode = mode_presets_25g[SPX5_SD25G28_MODE_PRESET_25000]; + else if (macro->speed == SPEED_10000) + *mode = mode_presets_25g[SPX5_SD25G28_MODE_PRESET_10000]; + else if (macro->speed == SPEED_5000) + *mode = mode_presets_25g[SPX5_SD25G28_MODE_PRESET_5000]; + break; + case SPX5_SD_MODE_2G5: + *mode = mode_presets_25g[SPX5_SD25G28_MODE_PRESET_SD_2G5]; + break; + case SPX5_SD_MODE_1000BASEX: + *mode = mode_presets_25g[SPX5_SD25G28_MODE_PRESET_1000BASEX]; + break; + case SPX5_SD_MODE_100FX: + /* Not supported */ + return -EINVAL; + default: + *mode = mode_presets_25g[SPX5_SD25G28_MODE_PRESET_25000]; + break; + } + return 0; +} + +static int sparx5_sd10g28_get_mode_preset(struct sparx5_serdes_macro *macro, + struct sparx5_sd10g28_mode_preset *mode, + struct sparx5_sd10g28_args *args) +{ + switch (macro->serdesmode) { + case SPX5_SD_MODE_SFI: + if (macro->speed == SPEED_10000) { + *mode = mode_presets_10g[SPX5_SD10G28_MODE_PRESET_10000]; + } else if (macro->speed == SPEED_5000) { + if (args->is_6g) + *mode = mode_presets_10g[SPX5_SD10G28_MODE_PRESET_SFI_5000_6G]; + else + *mode = mode_presets_10g[SPX5_SD10G28_MODE_PRESET_SFI_5000_10G]; + } else { + dev_err(macro->priv->dev, "%s: Illegal speed: %02u, sidx: %02u, mode (%u)", + __func__, macro->speed, macro->sidx, + macro->serdesmode); + return -EINVAL; + } + break; + case SPX5_SD_MODE_QSGMII: + *mode = mode_presets_10g[SPX5_SD10G28_MODE_PRESET_QSGMII]; + break; + case SPX5_SD_MODE_2G5: + *mode = mode_presets_10g[SPX5_SD10G28_MODE_PRESET_SD_2G5]; + break; + case SPX5_SD_MODE_100FX: + case SPX5_SD_MODE_1000BASEX: + *mode = mode_presets_10g[SPX5_SD10G28_MODE_PRESET_1000BASEX]; + break; + default: + *mode = mode_presets_10g[SPX5_SD10G28_MODE_PRESET_10000]; + break; + } + return 0; +} + +static void sparx5_sd25g28_get_params(struct sparx5_serdes_macro *macro, + struct sparx5_sd25g28_media_preset *media, + struct sparx5_sd25g28_mode_preset *mode, + struct sparx5_sd25g28_args *args, + struct sparx5_sd25g28_params *params) +{ + u8 iw = sd25g28_get_iw_setting(macro->priv->dev, mode->bitwidth); + struct sparx5_sd25g28_params init = { + .r_d_width_ctrl_2_0 = iw, + .r_txfifo_ck_div_pmad_2_0 = mode->fifo_ck_div, + .r_rxfifo_ck_div_pmad_2_0 = mode->fifo_ck_div, + .cfg_vco_div_mode_1_0 = mode->vco_div_mode, + .cfg_pre_divsel_1_0 = mode->pre_divsel, + .cfg_sel_div_3_0 = mode->sel_div, + .cfg_vco_start_code_3_0 = 0, + .cfg_pma_tx_ck_bitwidth_2_0 = mode->ck_bitwidth, + .cfg_tx_prediv_1_0 = mode->tx_pre_div, + .cfg_rxdiv_sel_2_0 = mode->ck_bitwidth, + .cfg_tx_subrate_2_0 = mode->subrate, + .cfg_rx_subrate_2_0 = mode->subrate, + .r_multi_lane_mode = 0, + .cfg_cdrck_en = 1, + .cfg_dfeck_en = mode->dfe_enable, + .cfg_dfe_pd = mode->dfe_enable == 1 ? 0 : 1, + .cfg_dfedmx_pd = 1, + .cfg_dfetap_en_5_1 = mode->dfe_tap, + .cfg_dmux_pd = 0, + .cfg_dmux_clk_pd = 1, + .cfg_erramp_pd = mode->dfe_enable == 1 ? 0 : 1, + .cfg_pi_DFE_en = mode->dfe_enable, + .cfg_pi_en = 1, + .cfg_pd_ctle = 0, + .cfg_summer_en = 1, + .cfg_pmad_ck_pd = 0, + .cfg_pd_clk = 0, + .cfg_pd_cml = 0, + .cfg_pd_driver = 0, + .cfg_rx_reg_pu = 1, + .cfg_pd_rms_det = 1, + .cfg_dcdr_pd = 0, + .cfg_ecdr_pd = 1, + .cfg_pd_sq = 1, + .cfg_itx_ipdriver_base_2_0 = mode->txmargin, + .cfg_tap_dly_4_0 = media->cfg_tap_dly_4_0, + .cfg_tap_main = media->cfg_tap_main, + .cfg_en_main = media->cfg_en_main, + .cfg_tap_adv_3_0 = media->cfg_tap_adv_3_0, + .cfg_en_adv = media->cfg_en_adv, + .cfg_en_dly = media->cfg_en_dly, + .cfg_iscan_en = 0, + .l1_pcs_en_fast_iscan = 0, + .l0_cfg_bw_1_0 = 0, + .cfg_en_dummy = 0, + .cfg_pll_reserve_3_0 = args->com_pll_reserve, + .l0_cfg_txcal_en = mode->com_txcal_en, + .l0_cfg_tx_reserve_15_8 = mode->com_tx_reserve_msb, + .l0_cfg_tx_reserve_7_0 = mode->com_tx_reserve_lsb, + .cfg_tx_reserve_15_8 = mode->tx_reserve_msb, + .cfg_tx_reserve_7_0 = mode->tx_reserve_lsb, + .cfg_bw_1_0 = mode->bw, + .cfg_txcal_man_en = 1, + .cfg_phase_man_4_0 = 0, + .cfg_quad_man_1_0 = 0, + .cfg_txcal_shift_code_5_0 = 2, + .cfg_txcal_valid_sel_3_0 = 4, + .cfg_txcal_en = 0, + .cfg_cdr_kf_2_0 = 1, + .cfg_cdr_m_7_0 = 6, + .cfg_pi_bw_3_0 = mode->cfg_pi_bw_3_0, + .cfg_pi_steps_1_0 = 0, + .cfg_dis_2ndorder = 1, + .cfg_ctle_rstn = mode->cfg_ctle_rstn, + .r_dfe_rstn = mode->r_dfe_rstn, + .cfg_alos_thr_2_0 = media->cfg_alos_thr_2_0, + .cfg_itx_ipcml_base_1_0 = mode->cfg_itx_ipcml_base, + .cfg_rx_reserve_7_0 = 0xbf, + .cfg_rx_reserve_15_8 = 0x61, + .cfg_rxterm_2_0 = mode->rxterm, + .cfg_fom_selm = 0, + .cfg_rx_sp_ctle_1_0 = 0, + .cfg_isel_ctle_1_0 = 0, + .cfg_vga_ctrl_byp_4_0 = media->cfg_vga_ctrl_byp_4_0, + .cfg_vga_byp = 1, + .cfg_agc_adpt_byp = 1, + .cfg_eqr_byp = 1, + .cfg_eqr_force_3_0 = media->cfg_eq_r_force_3_0, + .cfg_eqc_force_3_0 = media->cfg_eq_c_force_3_0, + .cfg_sum_setcm_en = 1, + .cfg_pi_dfe_en = 1, + .cfg_init_pos_iscan_6_0 = 6, + .cfg_init_pos_ipi_6_0 = 9, + .cfg_dfedig_m_2_0 = 6, + .cfg_en_dfedig = mode->dfe_enable, + .r_d_width_ctrl_from_hwt = 0, + .r_reg_manual = 1, + .reg_rst = args->reg_rst, + .cfg_jc_byp = 1, + .cfg_common_reserve_7_0 = 1, + .cfg_pll_lol_set = 1, + .cfg_tx2rx_lp_en = 0, + .cfg_txlb_en = 0, + .cfg_rx2tx_lp_en = 0, + .cfg_rxlb_en = 0, + .r_tx_pol_inv = args->txinvert, + .r_rx_pol_inv = args->rxinvert, + }; + + *params = init; +} + +static void sparx5_sd10g28_get_params(struct sparx5_serdes_macro *macro, + struct sparx5_sd10g28_media_preset *media, + struct sparx5_sd10g28_mode_preset *mode, + struct sparx5_sd10g28_args *args, + struct sparx5_sd10g28_params *params) +{ + u8 iw = sd10g28_get_iw_setting(macro->priv->dev, mode->bwidth); + struct sparx5_sd10g28_params init = { + .skip_cmu_cfg = args->skip_cmu_cfg, + .is_6g = args->is_6g, + .cmu_sel = mode->cmu_sel, + .cfg_lane_reserve_7_0 = (mode->cmu_sel % 2) << 6, + .cfg_ssc_rtl_clk_sel = (mode->cmu_sel / 2), + .cfg_lane_reserve_15_8 = mode->duty_cycle, + .cfg_txrate_1_0 = mode->rate, + .cfg_rxrate_1_0 = mode->rate, + .fx_100 = macro->serdesmode == SPX5_SD_MODE_100FX, + .r_d_width_ctrl_2_0 = iw, + .cfg_pma_tx_ck_bitwidth_2_0 = iw, + .cfg_rxdiv_sel_2_0 = iw, + .r_pcs2pma_phymode_4_0 = 0, + .cfg_lane_id_2_0 = 0, + .cfg_cdrck_en = 1, + .cfg_dfeck_en = mode->dfe_enable, + .cfg_dfe_pd = (mode->dfe_enable == 1) ? 0 : 1, + .cfg_dfetap_en_5_1 = mode->dfe_tap, + .cfg_erramp_pd = (mode->dfe_enable == 1) ? 0 : 1, + .cfg_pi_DFE_en = mode->dfe_enable, + .cfg_pi_en = 1, + .cfg_pd_ctle = 0, + .cfg_summer_en = 1, + .cfg_pd_rx_cktree = 0, + .cfg_pd_clk = 0, + .cfg_pd_cml = 0, + .cfg_pd_driver = 0, + .cfg_rx_reg_pu = 1, + .cfg_d_cdr_pd = 0, + .cfg_pd_sq = mode->dfe_enable, + .cfg_rxdet_en = 0, + .cfg_rxdet_str = 0, + .r_multi_lane_mode = 0, + .cfg_en_adv = media->cfg_en_adv, + .cfg_en_main = 1, + .cfg_en_dly = media->cfg_en_dly, + .cfg_tap_adv_3_0 = media->cfg_tap_adv_3_0, + .cfg_tap_main = media->cfg_tap_main, + .cfg_tap_dly_4_0 = media->cfg_tap_dly_4_0, + .cfg_vga_ctrl_3_0 = media->cfg_vga_ctrl_3_0, + .cfg_vga_cp_2_0 = media->cfg_vga_cp_2_0, + .cfg_eq_res_3_0 = media->cfg_eq_res_3_0, + .cfg_eq_r_byp = media->cfg_eq_r_byp, + .cfg_eq_c_force_3_0 = media->cfg_eq_c_force_3_0, + .cfg_en_dfedig = mode->dfe_enable, + .cfg_sum_setcm_en = 1, + .cfg_en_preemph = 0, + .cfg_itx_ippreemp_base_1_0 = 0, + .cfg_itx_ipdriver_base_2_0 = (args->txswing >> 6), + .cfg_ibias_tune_reserve_5_0 = (args->txswing & 63), + .cfg_txswing_half = (args->txmargin), + .cfg_dis_2nd_order = 0x1, + .cfg_rx_ssc_lh = 0x0, + .cfg_pi_floop_steps_1_0 = 0x0, + .cfg_pi_ext_dac_23_16 = (1 << 5), + .cfg_pi_ext_dac_15_8 = (0 << 6), + .cfg_iscan_ext_dac_7_0 = (1 << 7) + 9, + .cfg_cdr_kf_gen1_2_0 = 1, + .cfg_cdr_kf_gen2_2_0 = 1, + .cfg_cdr_kf_gen3_2_0 = 1, + .cfg_cdr_kf_gen4_2_0 = 1, + .r_cdr_m_gen1_7_0 = 4, + .cfg_pi_bw_gen1_3_0 = mode->pi_bw_gen1, + .cfg_pi_bw_gen2 = mode->pi_bw_gen1, + .cfg_pi_bw_gen3 = mode->pi_bw_gen1, + .cfg_pi_bw_gen4 = mode->pi_bw_gen1, + .cfg_pi_ext_dac_7_0 = 3, + .cfg_pi_steps = 0, + .cfg_mp_max_3_0 = 1, + .cfg_rstn_dfedig = mode->dfe_enable, + .cfg_alos_thr_3_0 = media->cfg_alos_thr_3_0, + .cfg_predrv_slewrate_1_0 = 3, + .cfg_itx_ipcml_base_1_0 = 0, + .cfg_ip_pre_base_1_0 = 0, + .r_cdr_m_gen2_7_0 = 2, + .r_cdr_m_gen3_7_0 = 2, + .r_cdr_m_gen4_7_0 = 2, + .r_en_auto_cdr_rstn = 0, + .cfg_oscal_afe = 1, + .cfg_pd_osdac_afe = 0, + .cfg_resetb_oscal_afe[0] = 0, + .cfg_resetb_oscal_afe[1] = 1, + .cfg_center_spreading = 0, + .cfg_m_cnt_maxval_4_0 = 15, + .cfg_ncnt_maxval_7_0 = 32, + .cfg_ncnt_maxval_10_8 = 6, + .cfg_ssc_en = 1, + .cfg_tx2rx_lp_en = 0, + .cfg_txlb_en = 0, + .cfg_rx2tx_lp_en = 0, + .cfg_rxlb_en = 0, + .r_tx_pol_inv = args->txinvert, + .r_rx_pol_inv = args->rxinvert, + }; + + *params = init; +} + +static void sparx5_sd25g28_reset(void __iomem *regs[], + struct sparx5_sd25g28_params *params, + u32 sd_index) +{ + if (params->reg_rst == 1) { + sdx5_rmw_addr(SD_LANE_25G_SD_LANE_CFG_EXT_CFG_RST_SET(1), + SD_LANE_25G_SD_LANE_CFG_EXT_CFG_RST, + sdx5_addr(regs, SD_LANE_25G_SD_LANE_CFG(sd_index))); + + usleep_range(1000, 2000); + + sdx5_rmw_addr(SD_LANE_25G_SD_LANE_CFG_EXT_CFG_RST_SET(0), + SD_LANE_25G_SD_LANE_CFG_EXT_CFG_RST, + sdx5_addr(regs, SD_LANE_25G_SD_LANE_CFG(sd_index))); + } +} + +static int sparx5_sd25g28_apply_params(struct device *dev, + void __iomem *regs[], + struct sparx5_sd25g28_params *params, + u32 sd_index) +{ + struct sparx5_serdes_regval item[] = { + { + SD_LANE_25G_SD_LANE_CFG_MACRO_RST_SET(1), + SD_LANE_25G_SD_LANE_CFG_MACRO_RST, + sdx5_addr(regs, SD_LANE_25G_SD_LANE_CFG(sd_index)) + }, + { + SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_SET(0xFF), + SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX, + sdx5_addr(regs, SD25G_LANE_CMU_FF(sd_index)) + }, + { + SD25G_LANE_CMU_1A_R_DWIDTHCTRL_FROM_HWT_SET + (params->r_d_width_ctrl_from_hwt) | + SD25G_LANE_CMU_1A_R_REG_MANUAL_SET(params->r_reg_manual), + SD25G_LANE_CMU_1A_R_DWIDTHCTRL_FROM_HWT | + SD25G_LANE_CMU_1A_R_REG_MANUAL, + sdx5_addr(regs, SD25G_LANE_CMU_1A(sd_index)) + }, + { + SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0_SET + (params->cfg_common_reserve_7_0), + SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0, + sdx5_addr(regs, SD25G_LANE_CMU_31(sd_index)) + }, + { + SD25G_LANE_CMU_09_CFG_EN_DUMMY_SET(params->cfg_en_dummy), + SD25G_LANE_CMU_09_CFG_EN_DUMMY, + sdx5_addr(regs, SD25G_LANE_CMU_09(sd_index)) + }, + { + SD25G_LANE_CMU_13_CFG_PLL_RESERVE_3_0_SET(params->cfg_pll_reserve_3_0), + SD25G_LANE_CMU_13_CFG_PLL_RESERVE_3_0, + sdx5_addr(regs, SD25G_LANE_CMU_13(sd_index)) + }, + { + SD25G_LANE_CMU_40_L0_CFG_TXCAL_EN_SET(params->l0_cfg_txcal_en), + SD25G_LANE_CMU_40_L0_CFG_TXCAL_EN, + sdx5_addr(regs, SD25G_LANE_CMU_40(sd_index)) + }, + { + SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8_SET + (params->l0_cfg_tx_reserve_15_8), + SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8, + sdx5_addr(regs, SD25G_LANE_CMU_46(sd_index)) + }, + { + SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0_SET(params->l0_cfg_tx_reserve_7_0), + SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0, + sdx5_addr(regs, SD25G_LANE_CMU_45(sd_index)) + }, + { + SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN_SET(0), + SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN, + sdx5_addr(regs, SD25G_LANE_CMU_0B(sd_index)) + }, + { + SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN_SET(1), + SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN, + sdx5_addr(regs, SD25G_LANE_CMU_0B(sd_index)) + }, + { + SD25G_LANE_CMU_19_R_CK_RESETB_SET(0), + SD25G_LANE_CMU_19_R_CK_RESETB, + sdx5_addr(regs, SD25G_LANE_CMU_19(sd_index)) + }, + { + SD25G_LANE_CMU_19_R_CK_RESETB_SET(1), + SD25G_LANE_CMU_19_R_CK_RESETB, + sdx5_addr(regs, SD25G_LANE_CMU_19(sd_index)) + }, + { + SD25G_LANE_CMU_18_R_PLL_RSTN_SET(0), + SD25G_LANE_CMU_18_R_PLL_RSTN, + sdx5_addr(regs, SD25G_LANE_CMU_18(sd_index)) + }, + { + SD25G_LANE_CMU_18_R_PLL_RSTN_SET(1), + SD25G_LANE_CMU_18_R_PLL_RSTN, + sdx5_addr(regs, SD25G_LANE_CMU_18(sd_index)) + }, + { + SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0_SET(params->r_d_width_ctrl_2_0), + SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0, + sdx5_addr(regs, SD25G_LANE_CMU_1A(sd_index)) + }, + { + SD25G_LANE_CMU_30_R_TXFIFO_CK_DIV_PMAD_2_0_SET + (params->r_txfifo_ck_div_pmad_2_0) | + SD25G_LANE_CMU_30_R_RXFIFO_CK_DIV_PMAD_2_0_SET + (params->r_rxfifo_ck_div_pmad_2_0), + SD25G_LANE_CMU_30_R_TXFIFO_CK_DIV_PMAD_2_0 | + SD25G_LANE_CMU_30_R_RXFIFO_CK_DIV_PMAD_2_0, + sdx5_addr(regs, SD25G_LANE_CMU_30(sd_index)) + }, + { + SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET_SET(params->cfg_pll_lol_set) | + SD25G_LANE_CMU_0C_CFG_VCO_DIV_MODE_1_0_SET(params->cfg_vco_div_mode_1_0), + SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET | + SD25G_LANE_CMU_0C_CFG_VCO_DIV_MODE_1_0, + sdx5_addr(regs, SD25G_LANE_CMU_0C(sd_index)) + }, + { + SD25G_LANE_CMU_0D_CFG_PRE_DIVSEL_1_0_SET(params->cfg_pre_divsel_1_0), + SD25G_LANE_CMU_0D_CFG_PRE_DIVSEL_1_0, + sdx5_addr(regs, SD25G_LANE_CMU_0D(sd_index)) + }, + { + SD25G_LANE_CMU_0E_CFG_SEL_DIV_3_0_SET(params->cfg_sel_div_3_0), + SD25G_LANE_CMU_0E_CFG_SEL_DIV_3_0, + sdx5_addr(regs, SD25G_LANE_CMU_0E(sd_index)) + }, + { + SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_SET(0x00), + SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX, + sdx5_addr(regs, SD25G_LANE_CMU_FF(sd_index)) + }, + { + SD25G_LANE_LANE_0C_LN_CFG_PMA_TX_CK_BITWIDTH_2_0_SET + (params->cfg_pma_tx_ck_bitwidth_2_0), + SD25G_LANE_LANE_0C_LN_CFG_PMA_TX_CK_BITWIDTH_2_0, + sdx5_addr(regs, SD25G_LANE_LANE_0C(sd_index)) + }, + { + SD25G_LANE_LANE_01_LN_CFG_TX_PREDIV_1_0_SET(params->cfg_tx_prediv_1_0), + SD25G_LANE_LANE_01_LN_CFG_TX_PREDIV_1_0, + sdx5_addr(regs, SD25G_LANE_LANE_01(sd_index)) + }, + { + SD25G_LANE_LANE_18_LN_CFG_RXDIV_SEL_2_0_SET(params->cfg_rxdiv_sel_2_0), + SD25G_LANE_LANE_18_LN_CFG_RXDIV_SEL_2_0, + sdx5_addr(regs, SD25G_LANE_LANE_18(sd_index)) + }, + { + SD25G_LANE_LANE_2C_LN_CFG_TX_SUBRATE_2_0_SET(params->cfg_tx_subrate_2_0), + SD25G_LANE_LANE_2C_LN_CFG_TX_SUBRATE_2_0, + sdx5_addr(regs, SD25G_LANE_LANE_2C(sd_index)) + }, + { + SD25G_LANE_LANE_28_LN_CFG_RX_SUBRATE_2_0_SET(params->cfg_rx_subrate_2_0), + SD25G_LANE_LANE_28_LN_CFG_RX_SUBRATE_2_0, + sdx5_addr(regs, SD25G_LANE_LANE_28(sd_index)) + }, + { + SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN_SET(params->cfg_cdrck_en), + SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN, + sdx5_addr(regs, SD25G_LANE_LANE_18(sd_index)) + }, + { + SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1_SET(params->cfg_dfetap_en_5_1), + SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1, + sdx5_addr(regs, SD25G_LANE_LANE_0F(sd_index)) + }, + { + SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD_SET(params->cfg_erramp_pd), + SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD, + sdx5_addr(regs, SD25G_LANE_LANE_18(sd_index)) + }, + { + SD25G_LANE_LANE_1D_LN_CFG_PI_DFE_EN_SET(params->cfg_pi_dfe_en), + SD25G_LANE_LANE_1D_LN_CFG_PI_DFE_EN, + sdx5_addr(regs, SD25G_LANE_LANE_1D(sd_index)) + }, + { + SD25G_LANE_LANE_19_LN_CFG_ECDR_PD_SET(params->cfg_ecdr_pd), + SD25G_LANE_LANE_19_LN_CFG_ECDR_PD, + sdx5_addr(regs, SD25G_LANE_LANE_19(sd_index)) + }, + { + SD25G_LANE_LANE_01_LN_CFG_ITX_IPDRIVER_BASE_2_0_SET + (params->cfg_itx_ipdriver_base_2_0), + SD25G_LANE_LANE_01_LN_CFG_ITX_IPDRIVER_BASE_2_0, + sdx5_addr(regs, SD25G_LANE_LANE_01(sd_index)) + }, + { + SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0_SET(params->cfg_tap_dly_4_0), + SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0, + sdx5_addr(regs, SD25G_LANE_LANE_03(sd_index)) + }, + { + SD25G_LANE_LANE_06_LN_CFG_TAP_ADV_3_0_SET(params->cfg_tap_adv_3_0), + SD25G_LANE_LANE_06_LN_CFG_TAP_ADV_3_0, + sdx5_addr(regs, SD25G_LANE_LANE_06(sd_index)) + }, + { + SD25G_LANE_LANE_07_LN_CFG_EN_ADV_SET(params->cfg_en_adv) | + SD25G_LANE_LANE_07_LN_CFG_EN_DLY_SET(params->cfg_en_dly), + SD25G_LANE_LANE_07_LN_CFG_EN_ADV | + SD25G_LANE_LANE_07_LN_CFG_EN_DLY, + sdx5_addr(regs, SD25G_LANE_LANE_07(sd_index)) + }, + { + SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8_SET(params->cfg_tx_reserve_15_8), + SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8, + sdx5_addr(regs, SD25G_LANE_LANE_43(sd_index)) + }, + { + SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0_SET(params->cfg_tx_reserve_7_0), + SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0, + sdx5_addr(regs, SD25G_LANE_LANE_42(sd_index)) + }, + { + SD25G_LANE_LANE_05_LN_CFG_BW_1_0_SET(params->cfg_bw_1_0), + SD25G_LANE_LANE_05_LN_CFG_BW_1_0, + sdx5_addr(regs, SD25G_LANE_LANE_05(sd_index)) + }, + { + SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN_SET(params->cfg_txcal_man_en), + SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN, + sdx5_addr(regs, SD25G_LANE_LANE_0B(sd_index)) + }, + { + SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0_SET + (params->cfg_txcal_shift_code_5_0), + SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0, + sdx5_addr(regs, SD25G_LANE_LANE_0A(sd_index)) + }, + { + SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0_SET + (params->cfg_txcal_valid_sel_3_0), + SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0, + sdx5_addr(regs, SD25G_LANE_LANE_09(sd_index)) + }, + { + SD25G_LANE_LANE_1A_LN_CFG_CDR_KF_2_0_SET(params->cfg_cdr_kf_2_0), + SD25G_LANE_LANE_1A_LN_CFG_CDR_KF_2_0, + sdx5_addr(regs, SD25G_LANE_LANE_1A(sd_index)) + }, + { + SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0_SET(params->cfg_cdr_m_7_0), + SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0, + sdx5_addr(regs, SD25G_LANE_LANE_1B(sd_index)) + }, + { + SD25G_LANE_LANE_2B_LN_CFG_PI_BW_3_0_SET(params->cfg_pi_bw_3_0), + SD25G_LANE_LANE_2B_LN_CFG_PI_BW_3_0, + sdx5_addr(regs, SD25G_LANE_LANE_2B(sd_index)) + }, + { + SD25G_LANE_LANE_2C_LN_CFG_DIS_2NDORDER_SET(params->cfg_dis_2ndorder), + SD25G_LANE_LANE_2C_LN_CFG_DIS_2NDORDER, + sdx5_addr(regs, SD25G_LANE_LANE_2C(sd_index)) + }, + { + SD25G_LANE_LANE_2E_LN_CFG_CTLE_RSTN_SET(params->cfg_ctle_rstn), + SD25G_LANE_LANE_2E_LN_CFG_CTLE_RSTN, + sdx5_addr(regs, SD25G_LANE_LANE_2E(sd_index)) + }, + { + SD25G_LANE_LANE_00_LN_CFG_ITX_IPCML_BASE_1_0_SET + (params->cfg_itx_ipcml_base_1_0), + SD25G_LANE_LANE_00_LN_CFG_ITX_IPCML_BASE_1_0, + sdx5_addr(regs, SD25G_LANE_LANE_00(sd_index)) + }, + { + SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0_SET(params->cfg_rx_reserve_7_0), + SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0, + sdx5_addr(regs, SD25G_LANE_LANE_44(sd_index)) + }, + { + SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8_SET(params->cfg_rx_reserve_15_8), + SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8, + sdx5_addr(regs, SD25G_LANE_LANE_45(sd_index)) + }, + { + SD25G_LANE_LANE_0D_LN_CFG_DFECK_EN_SET(params->cfg_dfeck_en) | + SD25G_LANE_LANE_0D_LN_CFG_RXTERM_2_0_SET(params->cfg_rxterm_2_0), + SD25G_LANE_LANE_0D_LN_CFG_DFECK_EN | + SD25G_LANE_LANE_0D_LN_CFG_RXTERM_2_0, + sdx5_addr(regs, SD25G_LANE_LANE_0D(sd_index)) + }, + { + SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0_SET + (params->cfg_vga_ctrl_byp_4_0), + SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0, + sdx5_addr(regs, SD25G_LANE_LANE_21(sd_index)) + }, + { + SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0_SET(params->cfg_eqr_force_3_0), + SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0, + sdx5_addr(regs, SD25G_LANE_LANE_22(sd_index)) + }, + { + SD25G_LANE_LANE_1C_LN_CFG_EQC_FORCE_3_0_SET(params->cfg_eqc_force_3_0) | + SD25G_LANE_LANE_1C_LN_CFG_DFE_PD_SET(params->cfg_dfe_pd), + SD25G_LANE_LANE_1C_LN_CFG_EQC_FORCE_3_0 | + SD25G_LANE_LANE_1C_LN_CFG_DFE_PD, + sdx5_addr(regs, SD25G_LANE_LANE_1C(sd_index)) + }, + { + SD25G_LANE_LANE_1E_LN_CFG_SUM_SETCM_EN_SET(params->cfg_sum_setcm_en), + SD25G_LANE_LANE_1E_LN_CFG_SUM_SETCM_EN, + sdx5_addr(regs, SD25G_LANE_LANE_1E(sd_index)) + }, + { + SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0_SET + (params->cfg_init_pos_iscan_6_0), + SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0, + sdx5_addr(regs, SD25G_LANE_LANE_25(sd_index)) + }, + { + SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0_SET + (params->cfg_init_pos_ipi_6_0), + SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0, + sdx5_addr(regs, SD25G_LANE_LANE_26(sd_index)) + }, + { + SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD_SET(params->cfg_erramp_pd), + SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD, + sdx5_addr(regs, SD25G_LANE_LANE_18(sd_index)) + }, + { + SD25G_LANE_LANE_0E_LN_CFG_DFEDIG_M_2_0_SET(params->cfg_dfedig_m_2_0), + SD25G_LANE_LANE_0E_LN_CFG_DFEDIG_M_2_0, + sdx5_addr(regs, SD25G_LANE_LANE_0E(sd_index)) + }, + { + SD25G_LANE_LANE_0E_LN_CFG_EN_DFEDIG_SET(params->cfg_en_dfedig), + SD25G_LANE_LANE_0E_LN_CFG_EN_DFEDIG, + sdx5_addr(regs, SD25G_LANE_LANE_0E(sd_index)) + }, + { + SD25G_LANE_LANE_40_LN_R_TX_POL_INV_SET(params->r_tx_pol_inv) | + SD25G_LANE_LANE_40_LN_R_RX_POL_INV_SET(params->r_rx_pol_inv), + SD25G_LANE_LANE_40_LN_R_TX_POL_INV | + SD25G_LANE_LANE_40_LN_R_RX_POL_INV, + sdx5_addr(regs, SD25G_LANE_LANE_40(sd_index)) + }, + { + SD25G_LANE_LANE_04_LN_CFG_RX2TX_LP_EN_SET(params->cfg_rx2tx_lp_en) | + SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN_SET(params->cfg_tx2rx_lp_en), + SD25G_LANE_LANE_04_LN_CFG_RX2TX_LP_EN | + SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN, + sdx5_addr(regs, SD25G_LANE_LANE_04(sd_index)) + }, + { + SD25G_LANE_LANE_1E_LN_CFG_RXLB_EN_SET(params->cfg_rxlb_en), + SD25G_LANE_LANE_1E_LN_CFG_RXLB_EN, + sdx5_addr(regs, SD25G_LANE_LANE_1E(sd_index)) + }, + { + SD25G_LANE_LANE_19_LN_CFG_TXLB_EN_SET(params->cfg_txlb_en), + SD25G_LANE_LANE_19_LN_CFG_TXLB_EN, + sdx5_addr(regs, SD25G_LANE_LANE_19(sd_index)) + }, + { + SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG_SET(0), + SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG, + sdx5_addr(regs, SD25G_LANE_LANE_2E(sd_index)) + }, + { + SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG_SET(1), + SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG, + sdx5_addr(regs, SD25G_LANE_LANE_2E(sd_index)) + }, + { + SD_LANE_25G_SD_LANE_CFG_MACRO_RST_SET(0), + SD_LANE_25G_SD_LANE_CFG_MACRO_RST, + sdx5_addr(regs, SD_LANE_25G_SD_LANE_CFG(sd_index)) + }, + { + SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN_SET(0), + SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN, + sdx5_addr(regs, SD25G_LANE_LANE_1C(sd_index)) + }, + }; + struct sparx5_serdes_regval item2[] = { + { + SD25G_LANE_CMU_2A_R_DBG_LOL_STATUS_SET(0x1), + SD25G_LANE_CMU_2A_R_DBG_LOL_STATUS, + sdx5_addr(regs, SD25G_LANE_CMU_2A(sd_index)) + }, + { + SD_LANE_25G_SD_SER_RST_SER_RST_SET(0x0), + SD_LANE_25G_SD_SER_RST_SER_RST, + sdx5_addr(regs, SD_LANE_25G_SD_SER_RST(sd_index)) + }, + { + SD_LANE_25G_SD_DES_RST_DES_RST_SET(0x0), + SD_LANE_25G_SD_DES_RST_DES_RST, + sdx5_addr(regs, SD_LANE_25G_SD_DES_RST(sd_index)) + }, + { + SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_SET(0), + SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX, + sdx5_addr(regs, SD25G_LANE_CMU_FF(sd_index)) + }, + { + SD25G_LANE_LANE_2D_LN_CFG_ALOS_THR_2_0_SET(params->cfg_alos_thr_2_0), + SD25G_LANE_LANE_2D_LN_CFG_ALOS_THR_2_0, + sdx5_addr(regs, SD25G_LANE_LANE_2D(sd_index)) + }, + { + SD25G_LANE_LANE_2E_LN_CFG_DIS_SQ_SET(0), + SD25G_LANE_LANE_2E_LN_CFG_DIS_SQ, + sdx5_addr(regs, SD25G_LANE_LANE_2E(sd_index)) + }, + { + SD25G_LANE_LANE_2E_LN_CFG_PD_SQ_SET(0), + SD25G_LANE_LANE_2E_LN_CFG_PD_SQ, + sdx5_addr(regs, SD25G_LANE_LANE_2E(sd_index)) + }, + + }; + u32 value; + int idx; + + for (idx = 0; idx < ARRAY_SIZE(item); ++idx) + sdx5_rmw_addr(item[idx].value, item[idx].mask, item[idx].addr); + usleep_range(1000, 2000); + + sdx5_rmw_addr(SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN_SET(1), + SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN, + sdx5_addr(regs, SD25G_LANE_LANE_1C(sd_index))); + + usleep_range(10000, 20000); + + sdx5_rmw_addr(SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_SET(0xff), + SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX, + sdx5_addr(regs, SD25G_LANE_CMU_FF(sd_index))); + + value = readl(sdx5_addr(regs, SD25G_LANE_CMU_C0(sd_index))); + value = SD25G_LANE_CMU_C0_PLL_LOL_UDL_GET(value); + + if (value) { + dev_err(dev, "25G PLL Loss of Lock: 0x%x\n", value); + return -EINVAL; + } + + value = readl(sdx5_addr(regs, SD_LANE_25G_SD_LANE_STAT(sd_index))); + value = SD_LANE_25G_SD_LANE_STAT_PMA_RST_DONE_GET(value); + + if (value != 0x1) { + dev_err(dev, "25G PMA Reset failed: 0x%x\n", value); + return -EINVAL; + } + for (idx = 0; idx < ARRAY_SIZE(item2); ++idx) + sdx5_rmw_addr(item2[idx].value, item2[idx].mask, item2[idx].addr); + return 0; +} + +static void sparx5_sd10g28_reset(void __iomem *regs[], + struct sparx5_sd10g28_params *params, + u32 lane_index, + u32 sd_index) +{ + /* Note: SerDes SD10G_LANE_1 is configured in 10G_LAN mode */ + sdx5_rmw_addr(SD_LANE_SD_LANE_CFG_EXT_CFG_RST_SET(1), + SD_LANE_SD_LANE_CFG_EXT_CFG_RST, + sdx5_addr(regs, SD_LANE_SD_LANE_CFG(lane_index))); + + usleep_range(1000, 2000); +} + +static int sparx5_sd10g28_apply_params(struct device *dev, + void __iomem *regs[], + struct sparx5_sd10g28_params *params, + void __iomem *sd_inst, + u32 lane_index, + u32 sd_index) +{ + struct sparx5_serdes_regval item[] = { + { + SD_LANE_SD_LANE_CFG_EXT_CFG_RST_SET(0), + SD_LANE_SD_LANE_CFG_EXT_CFG_RST, + sdx5_addr(regs, SD_LANE_SD_LANE_CFG(lane_index)) + }, + { + SD_LANE_SD_LANE_CFG_MACRO_RST_SET(1), + SD_LANE_SD_LANE_CFG_MACRO_RST, + sdx5_addr(regs, SD_LANE_SD_LANE_CFG(lane_index)) + }, + { + SD10G_LANE_LANE_93_R_DWIDTHCTRL_FROM_HWT_SET(0x0) | + SD10G_LANE_LANE_93_R_REG_MANUAL_SET(0x1) | + SD10G_LANE_LANE_93_R_AUXCKSEL_FROM_HWT_SET(0x1) | + SD10G_LANE_LANE_93_R_LANE_ID_FROM_HWT_SET(0x1) | + SD10G_LANE_LANE_93_R_EN_RATECHG_CTRL_SET(0x0), + SD10G_LANE_LANE_93_R_DWIDTHCTRL_FROM_HWT | + SD10G_LANE_LANE_93_R_REG_MANUAL | + SD10G_LANE_LANE_93_R_AUXCKSEL_FROM_HWT | + SD10G_LANE_LANE_93_R_LANE_ID_FROM_HWT | + SD10G_LANE_LANE_93_R_EN_RATECHG_CTRL, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_93(sd_index)) + }, + { + SD10G_LANE_LANE_94_R_ISCAN_REG_SET(0x1) | + SD10G_LANE_LANE_94_R_TXEQ_REG_SET(0x1) | + SD10G_LANE_LANE_94_R_MISC_REG_SET(0x1) | + SD10G_LANE_LANE_94_R_SWING_REG_SET(0x1), + SD10G_LANE_LANE_94_R_ISCAN_REG | + SD10G_LANE_LANE_94_R_TXEQ_REG | + SD10G_LANE_LANE_94_R_MISC_REG | + SD10G_LANE_LANE_94_R_SWING_REG, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_94(sd_index)) + }, + { + SD10G_LANE_LANE_9E_R_RXEQ_REG_SET(0x1), + SD10G_LANE_LANE_9E_R_RXEQ_REG, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_9E(sd_index)) + }, + { + SD10G_LANE_LANE_A1_R_SSC_FROM_HWT_SET(0x0) | + SD10G_LANE_LANE_A1_R_CDR_FROM_HWT_SET(0x0) | + SD10G_LANE_LANE_A1_R_PCLK_GATING_FROM_HWT_SET(0x1), + SD10G_LANE_LANE_A1_R_SSC_FROM_HWT | + SD10G_LANE_LANE_A1_R_CDR_FROM_HWT | + SD10G_LANE_LANE_A1_R_PCLK_GATING_FROM_HWT, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_A1(sd_index)) + }, + { + SD_LANE_SD_LANE_CFG_RX_REF_SEL_SET(params->cmu_sel) | + SD_LANE_SD_LANE_CFG_TX_REF_SEL_SET(params->cmu_sel), + SD_LANE_SD_LANE_CFG_RX_REF_SEL | + SD_LANE_SD_LANE_CFG_TX_REF_SEL, + sdx5_addr(regs, SD_LANE_SD_LANE_CFG(lane_index)) + }, + { + SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0_SET(params->cfg_lane_reserve_7_0), + SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_40(sd_index)) + }, + { + SD10G_LANE_LANE_50_CFG_SSC_RTL_CLK_SEL_SET(params->cfg_ssc_rtl_clk_sel), + SD10G_LANE_LANE_50_CFG_SSC_RTL_CLK_SEL, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_50(sd_index)) + }, + { + SD10G_LANE_LANE_35_CFG_TXRATE_1_0_SET(params->cfg_txrate_1_0) | + SD10G_LANE_LANE_35_CFG_RXRATE_1_0_SET(params->cfg_rxrate_1_0), + SD10G_LANE_LANE_35_CFG_TXRATE_1_0 | + SD10G_LANE_LANE_35_CFG_RXRATE_1_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_35(sd_index)) + }, + { + SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0_SET(params->r_d_width_ctrl_2_0), + SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_94(sd_index)) + }, + { + SD10G_LANE_LANE_01_CFG_PMA_TX_CK_BITWIDTH_2_0_SET + (params->cfg_pma_tx_ck_bitwidth_2_0), + SD10G_LANE_LANE_01_CFG_PMA_TX_CK_BITWIDTH_2_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_01(sd_index)) + }, + { + SD10G_LANE_LANE_30_CFG_RXDIV_SEL_2_0_SET(params->cfg_rxdiv_sel_2_0), + SD10G_LANE_LANE_30_CFG_RXDIV_SEL_2_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_30(sd_index)) + }, + { + SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0_SET + (params->r_pcs2pma_phymode_4_0), + SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_A2(sd_index)) + }, + { + SD10G_LANE_LANE_13_CFG_CDRCK_EN_SET(params->cfg_cdrck_en), + SD10G_LANE_LANE_13_CFG_CDRCK_EN, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_13(sd_index)) + }, + { + SD10G_LANE_LANE_23_CFG_DFECK_EN_SET(params->cfg_dfeck_en) | + SD10G_LANE_LANE_23_CFG_DFE_PD_SET(params->cfg_dfe_pd) | + SD10G_LANE_LANE_23_CFG_ERRAMP_PD_SET(params->cfg_erramp_pd), + SD10G_LANE_LANE_23_CFG_DFECK_EN | + SD10G_LANE_LANE_23_CFG_DFE_PD | + SD10G_LANE_LANE_23_CFG_ERRAMP_PD, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_23(sd_index)) + }, + { + SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1_SET(params->cfg_dfetap_en_5_1), + SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_22(sd_index)) + }, + { + SD10G_LANE_LANE_1A_CFG_PI_DFE_EN_SET(params->cfg_pi_DFE_en), + SD10G_LANE_LANE_1A_CFG_PI_DFE_EN, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_1A(sd_index)) + }, + { + SD10G_LANE_LANE_02_CFG_EN_ADV_SET(params->cfg_en_adv) | + SD10G_LANE_LANE_02_CFG_EN_MAIN_SET(params->cfg_en_main) | + SD10G_LANE_LANE_02_CFG_EN_DLY_SET(params->cfg_en_dly) | + SD10G_LANE_LANE_02_CFG_TAP_ADV_3_0_SET(params->cfg_tap_adv_3_0), + SD10G_LANE_LANE_02_CFG_EN_ADV | + SD10G_LANE_LANE_02_CFG_EN_MAIN | + SD10G_LANE_LANE_02_CFG_EN_DLY | + SD10G_LANE_LANE_02_CFG_TAP_ADV_3_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_02(sd_index)) + }, + { + SD10G_LANE_LANE_03_CFG_TAP_MAIN_SET(params->cfg_tap_main), + SD10G_LANE_LANE_03_CFG_TAP_MAIN, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_03(sd_index)) + }, + { + SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0_SET(params->cfg_tap_dly_4_0), + SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_04(sd_index)) + }, + { + SD10G_LANE_LANE_2F_CFG_VGA_CTRL_3_0_SET(params->cfg_vga_ctrl_3_0), + SD10G_LANE_LANE_2F_CFG_VGA_CTRL_3_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_2F(sd_index)) + }, + { + SD10G_LANE_LANE_2F_CFG_VGA_CP_2_0_SET(params->cfg_vga_cp_2_0), + SD10G_LANE_LANE_2F_CFG_VGA_CP_2_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_2F(sd_index)) + }, + { + SD10G_LANE_LANE_0B_CFG_EQ_RES_3_0_SET(params->cfg_eq_res_3_0), + SD10G_LANE_LANE_0B_CFG_EQ_RES_3_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_0B(sd_index)) + }, + { + SD10G_LANE_LANE_0D_CFG_EQR_BYP_SET(params->cfg_eq_r_byp), + SD10G_LANE_LANE_0D_CFG_EQR_BYP, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_0D(sd_index)) + }, + { + SD10G_LANE_LANE_0E_CFG_EQC_FORCE_3_0_SET(params->cfg_eq_c_force_3_0) | + SD10G_LANE_LANE_0E_CFG_SUM_SETCM_EN_SET(params->cfg_sum_setcm_en), + SD10G_LANE_LANE_0E_CFG_EQC_FORCE_3_0 | + SD10G_LANE_LANE_0E_CFG_SUM_SETCM_EN, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_0E(sd_index)) + }, + { + SD10G_LANE_LANE_23_CFG_EN_DFEDIG_SET(params->cfg_en_dfedig), + SD10G_LANE_LANE_23_CFG_EN_DFEDIG, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_23(sd_index)) + }, + { + SD10G_LANE_LANE_06_CFG_EN_PREEMPH_SET(params->cfg_en_preemph), + SD10G_LANE_LANE_06_CFG_EN_PREEMPH, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_06(sd_index)) + }, + { + SD10G_LANE_LANE_33_CFG_ITX_IPPREEMP_BASE_1_0_SET + (params->cfg_itx_ippreemp_base_1_0) | + SD10G_LANE_LANE_33_CFG_ITX_IPDRIVER_BASE_2_0_SET + (params->cfg_itx_ipdriver_base_2_0), + SD10G_LANE_LANE_33_CFG_ITX_IPPREEMP_BASE_1_0 | + SD10G_LANE_LANE_33_CFG_ITX_IPDRIVER_BASE_2_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_33(sd_index)) + }, + { + SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0_SET + (params->cfg_ibias_tune_reserve_5_0), + SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_52(sd_index)) + }, + { + SD10G_LANE_LANE_37_CFG_TXSWING_HALF_SET(params->cfg_txswing_half), + SD10G_LANE_LANE_37_CFG_TXSWING_HALF, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_37(sd_index)) + }, + { + SD10G_LANE_LANE_3C_CFG_DIS_2NDORDER_SET(params->cfg_dis_2nd_order), + SD10G_LANE_LANE_3C_CFG_DIS_2NDORDER, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_3C(sd_index)) + }, + { + SD10G_LANE_LANE_39_CFG_RX_SSC_LH_SET(params->cfg_rx_ssc_lh), + SD10G_LANE_LANE_39_CFG_RX_SSC_LH, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_39(sd_index)) + }, + { + SD10G_LANE_LANE_1A_CFG_PI_FLOOP_STEPS_1_0_SET + (params->cfg_pi_floop_steps_1_0), + SD10G_LANE_LANE_1A_CFG_PI_FLOOP_STEPS_1_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_1A(sd_index)) + }, + { + SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16_SET(params->cfg_pi_ext_dac_23_16), + SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_16(sd_index)) + }, + { + SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8_SET(params->cfg_pi_ext_dac_15_8), + SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_15(sd_index)) + }, + { + SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0_SET + (params->cfg_iscan_ext_dac_7_0), + SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_26(sd_index)) + }, + { + SD10G_LANE_LANE_42_CFG_CDR_KF_GEN1_2_0_SET(params->cfg_cdr_kf_gen1_2_0), + SD10G_LANE_LANE_42_CFG_CDR_KF_GEN1_2_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_42(sd_index)) + }, + { + SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0_SET(params->r_cdr_m_gen1_7_0), + SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_0F(sd_index)) + }, + { + SD10G_LANE_LANE_24_CFG_PI_BW_GEN1_3_0_SET(params->cfg_pi_bw_gen1_3_0), + SD10G_LANE_LANE_24_CFG_PI_BW_GEN1_3_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_24(sd_index)) + }, + { + SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0_SET(params->cfg_pi_ext_dac_7_0), + SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_14(sd_index)) + }, + { + SD10G_LANE_LANE_1A_CFG_PI_STEPS_SET(params->cfg_pi_steps), + SD10G_LANE_LANE_1A_CFG_PI_STEPS, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_1A(sd_index)) + }, + { + SD10G_LANE_LANE_3A_CFG_MP_MAX_3_0_SET(params->cfg_mp_max_3_0), + SD10G_LANE_LANE_3A_CFG_MP_MAX_3_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_3A(sd_index)) + }, + { + SD10G_LANE_LANE_31_CFG_RSTN_DFEDIG_SET(params->cfg_rstn_dfedig), + SD10G_LANE_LANE_31_CFG_RSTN_DFEDIG, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_31(sd_index)) + }, + { + SD10G_LANE_LANE_48_CFG_ALOS_THR_3_0_SET(params->cfg_alos_thr_3_0), + SD10G_LANE_LANE_48_CFG_ALOS_THR_3_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_48(sd_index)) + }, + { + SD10G_LANE_LANE_36_CFG_PREDRV_SLEWRATE_1_0_SET + (params->cfg_predrv_slewrate_1_0), + SD10G_LANE_LANE_36_CFG_PREDRV_SLEWRATE_1_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_36(sd_index)) + }, + { + SD10G_LANE_LANE_32_CFG_ITX_IPCML_BASE_1_0_SET + (params->cfg_itx_ipcml_base_1_0), + SD10G_LANE_LANE_32_CFG_ITX_IPCML_BASE_1_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_32(sd_index)) + }, + { + SD10G_LANE_LANE_37_CFG_IP_PRE_BASE_1_0_SET(params->cfg_ip_pre_base_1_0), + SD10G_LANE_LANE_37_CFG_IP_PRE_BASE_1_0, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_37(sd_index)) + }, + { + SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8_SET + (params->cfg_lane_reserve_15_8), + SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_41(sd_index)) + }, + { + SD10G_LANE_LANE_9E_R_EN_AUTO_CDR_RSTN_SET(params->r_en_auto_cdr_rstn), + SD10G_LANE_LANE_9E_R_EN_AUTO_CDR_RSTN, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_9E(sd_index)) + }, + { + SD10G_LANE_LANE_0C_CFG_OSCAL_AFE_SET(params->cfg_oscal_afe) | + SD10G_LANE_LANE_0C_CFG_PD_OSDAC_AFE_SET(params->cfg_pd_osdac_afe), + SD10G_LANE_LANE_0C_CFG_OSCAL_AFE | + SD10G_LANE_LANE_0C_CFG_PD_OSDAC_AFE, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_0C(sd_index)) + }, + { + SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE_SET + (params->cfg_resetb_oscal_afe[0]), + SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_0B(sd_index)) + }, + { + SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE_SET + (params->cfg_resetb_oscal_afe[1]), + SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_0B(sd_index)) + }, + { + SD10G_LANE_LANE_83_R_TX_POL_INV_SET(params->r_tx_pol_inv) | + SD10G_LANE_LANE_83_R_RX_POL_INV_SET(params->r_rx_pol_inv), + SD10G_LANE_LANE_83_R_TX_POL_INV | + SD10G_LANE_LANE_83_R_RX_POL_INV, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_83(sd_index)) + }, + { + SD10G_LANE_LANE_06_CFG_RX2TX_LP_EN_SET(params->cfg_rx2tx_lp_en) | + SD10G_LANE_LANE_06_CFG_TX2RX_LP_EN_SET(params->cfg_tx2rx_lp_en), + SD10G_LANE_LANE_06_CFG_RX2TX_LP_EN | + SD10G_LANE_LANE_06_CFG_TX2RX_LP_EN, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_06(sd_index)) + }, + { + SD10G_LANE_LANE_0E_CFG_RXLB_EN_SET(params->cfg_rxlb_en) | + SD10G_LANE_LANE_0E_CFG_TXLB_EN_SET(params->cfg_txlb_en), + SD10G_LANE_LANE_0E_CFG_RXLB_EN | + SD10G_LANE_LANE_0E_CFG_TXLB_EN, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_0E(sd_index)) + }, + { + SD_LANE_SD_LANE_CFG_MACRO_RST_SET(0), + SD_LANE_SD_LANE_CFG_MACRO_RST, + sdx5_addr(regs, SD_LANE_SD_LANE_CFG(lane_index)) + }, + { + SD10G_LANE_LANE_50_CFG_SSC_RESETB_SET(1), + SD10G_LANE_LANE_50_CFG_SSC_RESETB, + sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_50(sd_index)) + }, + { + SD10G_LANE_LANE_50_CFG_SSC_RESETB_SET(1), + SD10G_LANE_LANE_50_CFG_SSC_RESETB, + sdx5_addr(regs, SD10G_LANE_LANE_50(sd_index)) + }, + { + SD_LANE_MISC_SD_125_RST_DIS_SET(params->fx_100), + SD_LANE_MISC_SD_125_RST_DIS, + sdx5_addr(regs, SD_LANE_MISC(lane_index)) + }, + { + SD_LANE_MISC_RX_ENA_SET(params->fx_100), + SD_LANE_MISC_RX_ENA, + sdx5_addr(regs, SD_LANE_MISC(lane_index)) + }, + { + SD_LANE_MISC_MUX_ENA_SET(params->fx_100), + SD_LANE_MISC_MUX_ENA, + sdx5_addr(regs, SD_LANE_MISC(lane_index)) + }, + }; + u32 value; + int idx; + + for (idx = 0; idx < ARRAY_SIZE(item); ++idx) + sdx5_rmw_addr(item[idx].value, item[idx].mask, item[idx].addr); + usleep_range(3000, 6000); + + value = readl(sdx5_addr(regs, SD_LANE_SD_LANE_STAT(lane_index))); + value = SD_LANE_SD_LANE_STAT_PMA_RST_DONE_GET(value); + if (value != 1) { + dev_err(dev, "10G PMA Reset failed: 0x%x\n", value); + return -EINVAL; + } + + sdx5_rmw_addr(SD_LANE_SD_SER_RST_SER_RST_SET(0x0), + SD_LANE_SD_SER_RST_SER_RST, + sdx5_addr(regs, SD_LANE_SD_SER_RST(lane_index))); + + sdx5_rmw_addr(SD_LANE_SD_DES_RST_DES_RST_SET(0x0), + SD_LANE_SD_DES_RST_DES_RST, + sdx5_addr(regs, SD_LANE_SD_DES_RST(lane_index))); + + return 0; +} + +static int sparx5_sd25g28_config(struct sparx5_serdes_macro *macro, bool reset) +{ + struct sparx5_sd25g28_mode_preset mode; + struct sparx5_sd25g28_media_preset media = media_presets_25g[macro->media]; + struct sparx5_sd25g28_args args = { + .rxinvert = 1, + .txinvert = 0, + .txswing = 240, + .com_pll_reserve = 0xf, + .reg_rst = reset, + }; + struct sparx5_sd25g28_params params; + int err; + + err = sparx5_sd10g25_get_mode_preset(macro, &mode); + if (err) + return err; + sparx5_sd25g28_get_params(macro, &media, &mode, &args, ¶ms); + sparx5_sd25g28_reset(macro->priv->regs, ¶ms, macro->stpidx); + return sparx5_sd25g28_apply_params(macro->priv->dev, + macro->priv->regs, + ¶ms, + macro->stpidx); +} + +static int sparx5_sd10g28_config(struct sparx5_serdes_macro *macro, bool reset) +{ + struct sparx5_sd10g28_mode_preset mode; + struct sparx5_sd10g28_media_preset media = media_presets_10g[macro->media]; + struct sparx5_sd10g28_args args = { + .is_6g = (macro->serdestype == SPX5_SDT_6G), + .txinvert = 0, + .rxinvert = 1, + .txswing = 240, + .reg_rst = reset, + }; + struct sparx5_sd10g28_params params; + u32 sd_index = macro->stpidx; + void __iomem *sd_inst; + int err; + + err = sparx5_sd10g28_get_mode_preset(macro, &mode, &args); + if (err) + return err; + sparx5_sd10g28_get_params(macro, &media, &mode, &args, ¶ms); + sparx5_sd10g28_reset(macro->priv->regs, + ¶ms, + macro->sidx, + macro->stpidx); + if (macro->serdestype == SPX5_SDT_6G) + sd_inst = macro->priv->regs[TARGET_SD6G_LANE + sd_index]; + else + sd_inst = macro->priv->regs[TARGET_SD10G_LANE + sd_index]; + return sparx5_sd10g28_apply_params(macro->priv->dev, + macro->priv->regs, + ¶ms, + sd_inst, + macro->sidx, + sd_index); +} + +/* Power down serdes TX driver */ +static int sparx5_serdes_power_save(struct sparx5_serdes_macro *macro, u32 pwdn) +{ + void __iomem *sd_inst; + struct sparx5_serdes_private *priv = macro->priv; + + if (macro->serdestype == SPX5_SDT_6G) + sd_inst = sdx5_inst_get(priv, TARGET_SD6G_LANE, macro->stpidx); + else if (macro->serdestype == SPX5_SDT_10G) + sd_inst = sdx5_inst_get(priv, TARGET_SD10G_LANE, macro->stpidx); + else + sd_inst = sdx5_inst_get(priv, TARGET_SD25G_LANE, macro->stpidx); + + if (macro->serdestype == SPX5_SDT_25G) { + sdx5_inst_rmw(SD25G_LANE_LANE_04_LN_CFG_PD_DRIVER_SET(pwdn), + SD25G_LANE_LANE_04_LN_CFG_PD_DRIVER, + sd_inst, + SD25G_LANE_LANE_04(0)); + } else { + /* 6G and 10G */ + sdx5_inst_rmw(SD10G_LANE_LANE_06_CFG_PD_DRIVER_SET(pwdn), + SD10G_LANE_LANE_06_CFG_PD_DRIVER, + sd_inst, + SD10G_LANE_LANE_06(0)); + } + return 0; +} + +static int sparx5_serdes_clock_config(struct sparx5_serdes_macro *macro) +{ + struct sparx5_serdes_private *priv = macro->priv; + + if (macro->serdesmode == SPX5_SD_MODE_100FX) { + u32 freq = priv->coreclock == 250000000 ? 2 : + priv->coreclock == 500000000 ? 1 : 0; + + sdx5_rmw(SD_LANE_MISC_CORE_CLK_FREQ_SET(freq), + SD_LANE_MISC_CORE_CLK_FREQ, + priv, + SD_LANE_MISC(macro->sidx)); + } + return 0; +} + +static int sparx5_cmu_apply_cfg(struct device *dev, + void __iomem *regs[], + u32 cmu_idx, + void __iomem *cmu_tgt, + void __iomem *cmu_cfg_tgt, + u32 spd10g) +{ + struct sparx5_serdes_regval item[] = { + { + SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST_SET(1), + SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST, + sdx5_inst_addr(cmu_cfg_tgt, SD_CMU_CFG_SD_CMU_CFG(cmu_idx)) + }, + { + SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST_SET(0), + SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST, + sdx5_inst_addr(cmu_cfg_tgt, SD_CMU_CFG_SD_CMU_CFG(cmu_idx)) + }, + { + SD_CMU_CFG_SD_CMU_CFG_CMU_RST_SET(1), + SD_CMU_CFG_SD_CMU_CFG_CMU_RST, + sdx5_inst_addr(cmu_cfg_tgt, SD_CMU_CFG_SD_CMU_CFG(cmu_idx)) + }, + { + SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT_SET(0x1) | + SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT_SET(0x1) | + SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT_SET(0x1) | + SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT_SET(0x1) | + SD_CMU_CMU_45_R_EN_RATECHG_CTRL_SET(0x0), + SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT | + SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT | + SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT | + SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT | + SD_CMU_CMU_45_R_EN_RATECHG_CTRL, + sdx5_inst_addr(cmu_tgt, SD_CMU_CMU_45(cmu_idx)) + }, + { + SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0_SET(0), + SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0, + sdx5_inst_addr(cmu_tgt, SD_CMU_CMU_47(cmu_idx)) + }, + { + SD_CMU_CMU_1B_CFG_RESERVE_7_0_SET(0), + SD_CMU_CMU_1B_CFG_RESERVE_7_0, + sdx5_inst_addr(cmu_tgt, SD_CMU_CMU_1B(cmu_idx)) + }, + { + SD_CMU_CMU_0D_CFG_JC_BYP_SET(0x1), + SD_CMU_CMU_0D_CFG_JC_BYP, + sdx5_inst_addr(cmu_tgt, SD_CMU_CMU_0D(cmu_idx)) + }, + { + SD_CMU_CMU_1F_CFG_VTUNE_SEL_SET(1), + SD_CMU_CMU_1F_CFG_VTUNE_SEL, + sdx5_inst_addr(cmu_tgt, SD_CMU_CMU_1F(cmu_idx)) + }, + { + SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0_SET(3), + SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0, + sdx5_inst_addr(cmu_tgt, SD_CMU_CMU_00(cmu_idx)) + }, + { + SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0_SET(3), + SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0, + sdx5_inst_addr(cmu_tgt, SD_CMU_CMU_05(cmu_idx)) + }, + { + SD_CMU_CMU_30_R_PLL_DLOL_EN_SET(1), + SD_CMU_CMU_30_R_PLL_DLOL_EN, + sdx5_inst_addr(cmu_tgt, SD_CMU_CMU_30(cmu_idx)) + }, + { + SD_CMU_CMU_09_CFG_SW_10G_SET(spd10g), + SD_CMU_CMU_09_CFG_SW_10G, + sdx5_inst_addr(cmu_tgt, SD_CMU_CMU_09(cmu_idx)) + }, + { + SD_CMU_CFG_SD_CMU_CFG_CMU_RST_SET(0), + SD_CMU_CFG_SD_CMU_CFG_CMU_RST, + sdx5_inst_addr(cmu_cfg_tgt, SD_CMU_CFG_SD_CMU_CFG(cmu_idx)) + }, + }; + int value; + int idx; + + for (idx = 0; idx < ARRAY_SIZE(item); ++idx) + sdx5_rmw_addr(item[idx].value, item[idx].mask, item[idx].addr); + msleep(20); + + sdx5_inst_rmw(SD_CMU_CMU_44_R_PLL_RSTN_SET(0), + SD_CMU_CMU_44_R_PLL_RSTN, + cmu_tgt, + SD_CMU_CMU_44(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CMU_44_R_PLL_RSTN_SET(1), + SD_CMU_CMU_44_R_PLL_RSTN, + cmu_tgt, + SD_CMU_CMU_44(cmu_idx)); + + msleep(20); + + value = readl(sdx5_addr(regs, SD_CMU_CMU_E0(cmu_idx))); + value = SD_CMU_CMU_E0_PLL_LOL_UDL_GET(value); + + if (value) { + dev_err(dev, "CMU PLL Loss of Lock: 0x%x\n", value); + return -EINVAL; + } + sdx5_inst_rmw(SD_CMU_CMU_0D_CFG_PMA_TX_CK_PD_SET(0), + SD_CMU_CMU_0D_CFG_PMA_TX_CK_PD, + cmu_tgt, + SD_CMU_CMU_0D(cmu_idx)); + return 0; +} + +static int sparx5_cmu_cfg(struct sparx5_serdes_private *priv, u32 cmu_idx) +{ + void __iomem *cmu_tgt, *cmu_cfg_tgt; + u32 spd10g = 1; + + if (cmu_idx == 1 || cmu_idx == 4 || cmu_idx == 7 || + cmu_idx == 10 || cmu_idx == 13) { + spd10g = 0; + } + + cmu_tgt = sdx5_inst_get(priv, TARGET_SD_CMU, cmu_idx); + cmu_cfg_tgt = sdx5_inst_get(priv, TARGET_SD_CMU_CFG, cmu_idx); + + return sparx5_cmu_apply_cfg(priv->dev, priv->regs, cmu_idx, cmu_tgt, + cmu_cfg_tgt, spd10g); +} + +static int sparx5_serdes_cmu_enable(struct sparx5_serdes_private *priv) +{ + int idx, err = 0; + + if (!priv->cmu_enabled) { + for (idx = 0; idx < SPX5_CMU_MAX; idx++) { + err = sparx5_cmu_cfg(priv, idx); + if (err) { + dev_err(priv->dev, "CMU %u, error: %d\n", idx, err); + goto leave; + } + } + priv->cmu_enabled = true; + } +leave: + return err; +} + +static int sparx5_serdes_get_serdesmode(phy_interface_t portmode, int speed) +{ + switch (portmode) { + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: + if (speed == SPEED_2500) + return SPX5_SD_MODE_2G5; + if (speed == SPEED_100) + return SPX5_SD_MODE_100FX; + return SPX5_SD_MODE_1000BASEX; + case PHY_INTERFACE_MODE_SGMII: + /* The same Serdes mode is used for both SGMII and 1000BaseX */ + return SPX5_SD_MODE_1000BASEX; + case PHY_INTERFACE_MODE_QSGMII: + return SPX5_SD_MODE_QSGMII; + case PHY_INTERFACE_MODE_10GBASER: + return SPX5_SD_MODE_SFI; + default: + return -EINVAL; + } +} + +static int sparx5_serdes_config(struct sparx5_serdes_macro *macro) +{ + struct device *dev = macro->priv->dev; + int serdesmode; + int err; + + err = sparx5_serdes_cmu_enable(macro->priv); + if (err) + return err; + + serdesmode = sparx5_serdes_get_serdesmode(macro->portmode, macro->speed); + if (serdesmode < 0) { + dev_err(dev, "SerDes %u, interface not supported: %s\n", + macro->sidx, + phy_modes(macro->portmode)); + return serdesmode; + } + macro->serdesmode = serdesmode; + + sparx5_serdes_clock_config(macro); + + if (macro->serdestype == SPX5_SDT_25G) + err = sparx5_sd25g28_config(macro, false); + else + err = sparx5_sd10g28_config(macro, false); + if (err) { + dev_err(dev, "SerDes %u, config error: %d\n", + macro->sidx, err); + } + return err; +} + +static int sparx5_serdes_power_on(struct phy *phy) +{ + struct sparx5_serdes_macro *macro = phy_get_drvdata(phy); + + return sparx5_serdes_power_save(macro, false); +} + +static int sparx5_serdes_power_off(struct phy *phy) +{ + struct sparx5_serdes_macro *macro = phy_get_drvdata(phy); + + return sparx5_serdes_power_save(macro, true); +} + +static int sparx5_serdes_set_mode(struct phy *phy, enum phy_mode mode, int submode) +{ + struct sparx5_serdes_macro *macro; + + if (mode != PHY_MODE_ETHERNET) + return -EINVAL; + + switch (submode) { + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_QSGMII: + case PHY_INTERFACE_MODE_10GBASER: + macro = phy_get_drvdata(phy); + macro->portmode = submode; + sparx5_serdes_config(macro); + return 0; + default: + return -EINVAL; + } +} + +static int sparx5_serdes_set_media(struct phy *phy, enum phy_media media) +{ + struct sparx5_serdes_macro *macro = phy_get_drvdata(phy); + + if (media != macro->media) { + macro->media = media; + if (macro->serdesmode != SPX5_SD_MODE_NONE) + sparx5_serdes_config(macro); + } + return 0; +} + +static int sparx5_serdes_set_speed(struct phy *phy, int speed) +{ + struct sparx5_serdes_macro *macro = phy_get_drvdata(phy); + + if (macro->sidx < SPX5_SERDES_10G_START && speed > SPEED_5000) + return -EINVAL; + if (macro->sidx < SPX5_SERDES_25G_START && speed > SPEED_10000) + return -EINVAL; + if (speed != macro->speed) { + macro->speed = speed; + if (macro->serdesmode != SPX5_SD_MODE_NONE) + sparx5_serdes_config(macro); + } + return 0; +} + +static int sparx5_serdes_reset(struct phy *phy) +{ + struct sparx5_serdes_macro *macro = phy_get_drvdata(phy); + int err; + + err = sparx5_serdes_cmu_enable(macro->priv); + if (err) + return err; + if (macro->serdestype == SPX5_SDT_25G) + err = sparx5_sd25g28_config(macro, true); + else + err = sparx5_sd10g28_config(macro, true); + if (err) { + dev_err(&phy->dev, "SerDes %u, reset error: %d\n", + macro->sidx, err); + } + return err; +} + +static int sparx5_serdes_validate(struct phy *phy, enum phy_mode mode, + int submode, + union phy_configure_opts *opts) +{ + struct sparx5_serdes_macro *macro = phy_get_drvdata(phy); + + if (mode != PHY_MODE_ETHERNET) + return -EINVAL; + + if (macro->speed == 0) + return -EINVAL; + + if (macro->sidx < SPX5_SERDES_10G_START && macro->speed > SPEED_5000) + return -EINVAL; + if (macro->sidx < SPX5_SERDES_25G_START && macro->speed > SPEED_10000) + return -EINVAL; + + switch (submode) { + case PHY_INTERFACE_MODE_1000BASEX: + if (macro->speed != SPEED_100 && /* This is for 100BASE-FX */ + macro->speed != SPEED_1000) + return -EINVAL; + break; + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_2500BASEX: + case PHY_INTERFACE_MODE_QSGMII: + if (macro->speed >= SPEED_5000) + return -EINVAL; + break; + case PHY_INTERFACE_MODE_10GBASER: + if (macro->speed < SPEED_5000) + return -EINVAL; + break; + default: + return -EINVAL; + } + return 0; +} + +static const struct phy_ops sparx5_serdes_ops = { + .power_on = sparx5_serdes_power_on, + .power_off = sparx5_serdes_power_off, + .set_mode = sparx5_serdes_set_mode, + .set_media = sparx5_serdes_set_media, + .set_speed = sparx5_serdes_set_speed, + .reset = sparx5_serdes_reset, + .validate = sparx5_serdes_validate, + .owner = THIS_MODULE, +}; + +static int sparx5_phy_create(struct sparx5_serdes_private *priv, + int idx, struct phy **phy) +{ + struct sparx5_serdes_macro *macro; + + *phy = devm_phy_create(priv->dev, NULL, &sparx5_serdes_ops); + if (IS_ERR(*phy)) + return PTR_ERR(*phy); + + macro = devm_kzalloc(priv->dev, sizeof(*macro), GFP_KERNEL); + if (!macro) + return -ENOMEM; + + macro->sidx = idx; + macro->priv = priv; + macro->speed = SPEED_UNKNOWN; + if (idx < SPX5_SERDES_10G_START) { + macro->serdestype = SPX5_SDT_6G; + macro->stpidx = macro->sidx; + } else if (idx < SPX5_SERDES_25G_START) { + macro->serdestype = SPX5_SDT_10G; + macro->stpidx = macro->sidx - SPX5_SERDES_10G_START; + } else { + macro->serdestype = SPX5_SDT_25G; + macro->stpidx = macro->sidx - SPX5_SERDES_25G_START; + } + + phy_set_drvdata(*phy, macro); + + return 0; +} + +static struct sparx5_serdes_io_resource sparx5_serdes_iomap[] = { + { TARGET_SD_CMU, 0x0 }, /* 0x610808000: sd_cmu_0 */ + { TARGET_SD_CMU + 1, 0x8000 }, /* 0x610810000: sd_cmu_1 */ + { TARGET_SD_CMU + 2, 0x10000 }, /* 0x610818000: sd_cmu_2 */ + { TARGET_SD_CMU + 3, 0x18000 }, /* 0x610820000: sd_cmu_3 */ + { TARGET_SD_CMU + 4, 0x20000 }, /* 0x610828000: sd_cmu_4 */ + { TARGET_SD_CMU + 5, 0x28000 }, /* 0x610830000: sd_cmu_5 */ + { TARGET_SD_CMU + 6, 0x30000 }, /* 0x610838000: sd_cmu_6 */ + { TARGET_SD_CMU + 7, 0x38000 }, /* 0x610840000: sd_cmu_7 */ + { TARGET_SD_CMU + 8, 0x40000 }, /* 0x610848000: sd_cmu_8 */ + { TARGET_SD_CMU_CFG, 0x48000 }, /* 0x610850000: sd_cmu_cfg_0 */ + { TARGET_SD_CMU_CFG + 1, 0x50000 }, /* 0x610858000: sd_cmu_cfg_1 */ + { TARGET_SD_CMU_CFG + 2, 0x58000 }, /* 0x610860000: sd_cmu_cfg_2 */ + { TARGET_SD_CMU_CFG + 3, 0x60000 }, /* 0x610868000: sd_cmu_cfg_3 */ + { TARGET_SD_CMU_CFG + 4, 0x68000 }, /* 0x610870000: sd_cmu_cfg_4 */ + { TARGET_SD_CMU_CFG + 5, 0x70000 }, /* 0x610878000: sd_cmu_cfg_5 */ + { TARGET_SD_CMU_CFG + 6, 0x78000 }, /* 0x610880000: sd_cmu_cfg_6 */ + { TARGET_SD_CMU_CFG + 7, 0x80000 }, /* 0x610888000: sd_cmu_cfg_7 */ + { TARGET_SD_CMU_CFG + 8, 0x88000 }, /* 0x610890000: sd_cmu_cfg_8 */ + { TARGET_SD6G_LANE, 0x90000 }, /* 0x610898000: sd6g_lane_0 */ + { TARGET_SD6G_LANE + 1, 0x98000 }, /* 0x6108a0000: sd6g_lane_1 */ + { TARGET_SD6G_LANE + 2, 0xa0000 }, /* 0x6108a8000: sd6g_lane_2 */ + { TARGET_SD6G_LANE + 3, 0xa8000 }, /* 0x6108b0000: sd6g_lane_3 */ + { TARGET_SD6G_LANE + 4, 0xb0000 }, /* 0x6108b8000: sd6g_lane_4 */ + { TARGET_SD6G_LANE + 5, 0xb8000 }, /* 0x6108c0000: sd6g_lane_5 */ + { TARGET_SD6G_LANE + 6, 0xc0000 }, /* 0x6108c8000: sd6g_lane_6 */ + { TARGET_SD6G_LANE + 7, 0xc8000 }, /* 0x6108d0000: sd6g_lane_7 */ + { TARGET_SD6G_LANE + 8, 0xd0000 }, /* 0x6108d8000: sd6g_lane_8 */ + { TARGET_SD6G_LANE + 9, 0xd8000 }, /* 0x6108e0000: sd6g_lane_9 */ + { TARGET_SD6G_LANE + 10, 0xe0000 }, /* 0x6108e8000: sd6g_lane_10 */ + { TARGET_SD6G_LANE + 11, 0xe8000 }, /* 0x6108f0000: sd6g_lane_11 */ + { TARGET_SD6G_LANE + 12, 0xf0000 }, /* 0x6108f8000: sd6g_lane_12 */ + { TARGET_SD10G_LANE, 0xf8000 }, /* 0x610900000: sd10g_lane_0 */ + { TARGET_SD10G_LANE + 1, 0x100000 }, /* 0x610908000: sd10g_lane_1 */ + { TARGET_SD10G_LANE + 2, 0x108000 }, /* 0x610910000: sd10g_lane_2 */ + { TARGET_SD10G_LANE + 3, 0x110000 }, /* 0x610918000: sd10g_lane_3 */ + { TARGET_SD_LANE, 0x1a0000 }, /* 0x6109a8000: sd_lane_0 */ + { TARGET_SD_LANE + 1, 0x1a8000 }, /* 0x6109b0000: sd_lane_1 */ + { TARGET_SD_LANE + 2, 0x1b0000 }, /* 0x6109b8000: sd_lane_2 */ + { TARGET_SD_LANE + 3, 0x1b8000 }, /* 0x6109c0000: sd_lane_3 */ + { TARGET_SD_LANE + 4, 0x1c0000 }, /* 0x6109c8000: sd_lane_4 */ + { TARGET_SD_LANE + 5, 0x1c8000 }, /* 0x6109d0000: sd_lane_5 */ + { TARGET_SD_LANE + 6, 0x1d0000 }, /* 0x6109d8000: sd_lane_6 */ + { TARGET_SD_LANE + 7, 0x1d8000 }, /* 0x6109e0000: sd_lane_7 */ + { TARGET_SD_LANE + 8, 0x1e0000 }, /* 0x6109e8000: sd_lane_8 */ + { TARGET_SD_LANE + 9, 0x1e8000 }, /* 0x6109f0000: sd_lane_9 */ + { TARGET_SD_LANE + 10, 0x1f0000 }, /* 0x6109f8000: sd_lane_10 */ + { TARGET_SD_LANE + 11, 0x1f8000 }, /* 0x610a00000: sd_lane_11 */ + { TARGET_SD_LANE + 12, 0x200000 }, /* 0x610a08000: sd_lane_12 */ + { TARGET_SD_LANE + 13, 0x208000 }, /* 0x610a10000: sd_lane_13 */ + { TARGET_SD_LANE + 14, 0x210000 }, /* 0x610a18000: sd_lane_14 */ + { TARGET_SD_LANE + 15, 0x218000 }, /* 0x610a20000: sd_lane_15 */ + { TARGET_SD_LANE + 16, 0x220000 }, /* 0x610a28000: sd_lane_16 */ + { TARGET_SD_CMU + 9, 0x400000 }, /* 0x610c08000: sd_cmu_9 */ + { TARGET_SD_CMU + 10, 0x408000 }, /* 0x610c10000: sd_cmu_10 */ + { TARGET_SD_CMU + 11, 0x410000 }, /* 0x610c18000: sd_cmu_11 */ + { TARGET_SD_CMU + 12, 0x418000 }, /* 0x610c20000: sd_cmu_12 */ + { TARGET_SD_CMU + 13, 0x420000 }, /* 0x610c28000: sd_cmu_13 */ + { TARGET_SD_CMU_CFG + 9, 0x428000 }, /* 0x610c30000: sd_cmu_cfg_9 */ + { TARGET_SD_CMU_CFG + 10, 0x430000 }, /* 0x610c38000: sd_cmu_cfg_10 */ + { TARGET_SD_CMU_CFG + 11, 0x438000 }, /* 0x610c40000: sd_cmu_cfg_11 */ + { TARGET_SD_CMU_CFG + 12, 0x440000 }, /* 0x610c48000: sd_cmu_cfg_12 */ + { TARGET_SD_CMU_CFG + 13, 0x448000 }, /* 0x610c50000: sd_cmu_cfg_13 */ + { TARGET_SD10G_LANE + 4, 0x450000 }, /* 0x610c58000: sd10g_lane_4 */ + { TARGET_SD10G_LANE + 5, 0x458000 }, /* 0x610c60000: sd10g_lane_5 */ + { TARGET_SD10G_LANE + 6, 0x460000 }, /* 0x610c68000: sd10g_lane_6 */ + { TARGET_SD10G_LANE + 7, 0x468000 }, /* 0x610c70000: sd10g_lane_7 */ + { TARGET_SD10G_LANE + 8, 0x470000 }, /* 0x610c78000: sd10g_lane_8 */ + { TARGET_SD10G_LANE + 9, 0x478000 }, /* 0x610c80000: sd10g_lane_9 */ + { TARGET_SD10G_LANE + 10, 0x480000 }, /* 0x610c88000: sd10g_lane_10 */ + { TARGET_SD10G_LANE + 11, 0x488000 }, /* 0x610c90000: sd10g_lane_11 */ + { TARGET_SD25G_LANE, 0x490000 }, /* 0x610c98000: sd25g_lane_0 */ + { TARGET_SD25G_LANE + 1, 0x498000 }, /* 0x610ca0000: sd25g_lane_1 */ + { TARGET_SD25G_LANE + 2, 0x4a0000 }, /* 0x610ca8000: sd25g_lane_2 */ + { TARGET_SD25G_LANE + 3, 0x4a8000 }, /* 0x610cb0000: sd25g_lane_3 */ + { TARGET_SD25G_LANE + 4, 0x4b0000 }, /* 0x610cb8000: sd25g_lane_4 */ + { TARGET_SD25G_LANE + 5, 0x4b8000 }, /* 0x610cc0000: sd25g_lane_5 */ + { TARGET_SD25G_LANE + 6, 0x4c0000 }, /* 0x610cc8000: sd25g_lane_6 */ + { TARGET_SD25G_LANE + 7, 0x4c8000 }, /* 0x610cd0000: sd25g_lane_7 */ + { TARGET_SD_LANE + 17, 0x550000 }, /* 0x610d58000: sd_lane_17 */ + { TARGET_SD_LANE + 18, 0x558000 }, /* 0x610d60000: sd_lane_18 */ + { TARGET_SD_LANE + 19, 0x560000 }, /* 0x610d68000: sd_lane_19 */ + { TARGET_SD_LANE + 20, 0x568000 }, /* 0x610d70000: sd_lane_20 */ + { TARGET_SD_LANE + 21, 0x570000 }, /* 0x610d78000: sd_lane_21 */ + { TARGET_SD_LANE + 22, 0x578000 }, /* 0x610d80000: sd_lane_22 */ + { TARGET_SD_LANE + 23, 0x580000 }, /* 0x610d88000: sd_lane_23 */ + { TARGET_SD_LANE + 24, 0x588000 }, /* 0x610d90000: sd_lane_24 */ + { TARGET_SD_LANE_25G, 0x590000 }, /* 0x610d98000: sd_lane_25g_25 */ + { TARGET_SD_LANE_25G + 1, 0x598000 }, /* 0x610da0000: sd_lane_25g_26 */ + { TARGET_SD_LANE_25G + 2, 0x5a0000 }, /* 0x610da8000: sd_lane_25g_27 */ + { TARGET_SD_LANE_25G + 3, 0x5a8000 }, /* 0x610db0000: sd_lane_25g_28 */ + { TARGET_SD_LANE_25G + 4, 0x5b0000 }, /* 0x610db8000: sd_lane_25g_29 */ + { TARGET_SD_LANE_25G + 5, 0x5b8000 }, /* 0x610dc0000: sd_lane_25g_30 */ + { TARGET_SD_LANE_25G + 6, 0x5c0000 }, /* 0x610dc8000: sd_lane_25g_31 */ + { TARGET_SD_LANE_25G + 7, 0x5c8000 }, /* 0x610dd0000: sd_lane_25g_32 */ +}; + +/* Client lookup function, uses serdes index */ +static struct phy *sparx5_serdes_xlate(struct device *dev, + struct of_phandle_args *args) +{ + struct sparx5_serdes_private *priv = dev_get_drvdata(dev); + int idx; + unsigned int sidx; + + if (args->args_count != 1) + return ERR_PTR(-EINVAL); + + sidx = args->args[0]; + + /* Check validity: ERR_PTR(-ENODEV) if not valid */ + for (idx = 0; idx < SPX5_SERDES_MAX; idx++) { + struct sparx5_serdes_macro *macro = + phy_get_drvdata(priv->phys[idx]); + + if (sidx != macro->sidx) + continue; + + return priv->phys[idx]; + } + return ERR_PTR(-ENODEV); +} + +static int sparx5_serdes_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct sparx5_serdes_private *priv; + struct phy_provider *provider; + struct resource *iores; + void __iomem *iomem; + unsigned long clock; + struct clk *clk; + int idx; + int err; + + if (!np && !pdev->dev.platform_data) + return -ENODEV; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + priv->dev = &pdev->dev; + + /* Get coreclock */ + clk = devm_clk_get(priv->dev, NULL); + if (IS_ERR(clk)) { + dev_err(priv->dev, "Failed to get coreclock\n"); + return PTR_ERR(clk); + } + clock = clk_get_rate(clk); + if (clock == 0) { + dev_err(priv->dev, "Invalid coreclock %lu\n", clock); + return -EINVAL; + } + priv->coreclock = clock; + + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); + iomem = devm_ioremap(priv->dev, iores->start, iores->end - iores->start + 1); + if (IS_ERR(iomem)) { + dev_err(priv->dev, "Unable to get serdes registers: %s\n", + iores->name); + return PTR_ERR(iomem); + } + for (idx = 0; idx < ARRAY_SIZE(sparx5_serdes_iomap); idx++) { + struct sparx5_serdes_io_resource *iomap = &sparx5_serdes_iomap[idx]; + + priv->regs[iomap->id] = iomem + iomap->offset; + } + for (idx = 0; idx < SPX5_SERDES_MAX; idx++) { + err = sparx5_phy_create(priv, idx, &priv->phys[idx]); + if (err) + return err; + } + + provider = devm_of_phy_provider_register(priv->dev, sparx5_serdes_xlate); + + return PTR_ERR_OR_ZERO(provider); +} + +static const struct of_device_id sparx5_serdes_match[] = { + { .compatible = "microchip,sparx5-serdes" }, + { } +}; +MODULE_DEVICE_TABLE(of, sparx5_serdes_match); + +static struct platform_driver sparx5_serdes_driver = { + .probe = sparx5_serdes_probe, + .driver = { + .name = "sparx5-serdes", + .of_match_table = sparx5_serdes_match, + }, +}; + +module_platform_driver(sparx5_serdes_driver); + +MODULE_DESCRIPTION("Microchip Sparx5 switch serdes driver"); +MODULE_AUTHOR("Steen Hegelund "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/microchip/sparx5_serdes.h b/drivers/phy/microchip/sparx5_serdes.h new file mode 100644 index 000000000000..0a3e496e6210 --- /dev/null +++ b/drivers/phy/microchip/sparx5_serdes.h @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * Microchip Sparx5 SerDes driver + * + * Copyright (c) 2020 Microchip Technology Inc. + */ + +#ifndef _SPARX5_SERDES_H_ +#define _SPARX5_SERDES_H_ + +#include "sparx5_serdes_regs.h" + +#define SPX5_SERDES_MAX 33 + +enum sparx5_serdes_type { + SPX5_SDT_6G = 6, + SPX5_SDT_10G = 10, + SPX5_SDT_25G = 25, +}; + +enum sparx5_serdes_mode { + SPX5_SD_MODE_NONE, + SPX5_SD_MODE_2G5, + SPX5_SD_MODE_QSGMII, + SPX5_SD_MODE_100FX, + SPX5_SD_MODE_1000BASEX, + SPX5_SD_MODE_SFI, +}; + +struct sparx5_serdes_private { + struct device *dev; + void __iomem *regs[NUM_TARGETS]; + struct phy *phys[SPX5_SERDES_MAX]; + bool cmu_enabled; + unsigned long coreclock; +}; + +struct sparx5_serdes_macro { + struct sparx5_serdes_private *priv; + u32 sidx; + u32 stpidx; + enum sparx5_serdes_type serdestype; + enum sparx5_serdes_mode serdesmode; + phy_interface_t portmode; + int speed; + enum phy_media media; +}; + +/* Read, Write and modify registers content. + * The register definition macros start at the id + */ +static inline void __iomem *sdx5_addr(void __iomem *base[], + int id, int tinst, int tcnt, + int gbase, int ginst, + int gcnt, int gwidth, + int raddr, int rinst, + int rcnt, int rwidth) +{ + WARN_ON((tinst) >= tcnt); + WARN_ON((ginst) >= gcnt); + WARN_ON((rinst) >= rcnt); + return base[id + (tinst)] + + gbase + ((ginst) * gwidth) + + raddr + ((rinst) * rwidth); +} + +static inline void __iomem *sdx5_inst_baseaddr(void __iomem *base, + int gbase, int ginst, + int gcnt, int gwidth, + int raddr, int rinst, + int rcnt, int rwidth) +{ + WARN_ON((ginst) >= gcnt); + WARN_ON((rinst) >= rcnt); + return base + + gbase + ((ginst) * gwidth) + + raddr + ((rinst) * rwidth); +} + +static inline void sdx5_rmw(u32 val, u32 mask, struct sparx5_serdes_private *priv, + int id, int tinst, int tcnt, + int gbase, int ginst, int gcnt, int gwidth, + int raddr, int rinst, int rcnt, int rwidth) +{ + u32 nval; + void __iomem *addr = + sdx5_addr(priv->regs, id, tinst, tcnt, + gbase, ginst, gcnt, gwidth, + raddr, rinst, rcnt, rwidth); + nval = readl(addr); + nval = (nval & ~mask) | (val & mask); + writel(nval, addr); +} + +static inline void sdx5_inst_rmw(u32 val, u32 mask, void __iomem *iomem, + int id, int tinst, int tcnt, + int gbase, int ginst, int gcnt, int gwidth, + int raddr, int rinst, int rcnt, int rwidth) +{ + u32 nval; + void __iomem *addr = + sdx5_inst_baseaddr(iomem, + gbase, ginst, gcnt, gwidth, + raddr, rinst, rcnt, rwidth); + nval = readl(addr); + nval = (nval & ~mask) | (val & mask); + writel(nval, addr); +} + +static inline void sdx5_rmw_addr(u32 val, u32 mask, void __iomem *addr) +{ + u32 nval; + + nval = readl(addr); + nval = (nval & ~mask) | (val & mask); + writel(nval, addr); +} + +static inline void __iomem *sdx5_inst_get(struct sparx5_serdes_private *priv, + int id, int tinst) +{ + return priv->regs[id + tinst]; +} + +static inline void __iomem *sdx5_inst_addr(void __iomem *iomem, + int id, int tinst, int tcnt, + int gbase, + int ginst, int gcnt, int gwidth, + int raddr, + int rinst, int rcnt, int rwidth) +{ + return sdx5_inst_baseaddr(iomem, gbase, ginst, gcnt, gwidth, + raddr, rinst, rcnt, rwidth); +} + + +#endif /* _SPARX5_SERDES_REGS_H_ */ diff --git a/drivers/phy/microchip/sparx5_serdes_regs.h b/drivers/phy/microchip/sparx5_serdes_regs.h new file mode 100644 index 000000000000..b96386a4df5a --- /dev/null +++ b/drivers/phy/microchip/sparx5_serdes_regs.h @@ -0,0 +1,2695 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * Microchip Sparx5 SerDes driver + * + * Copyright (c) 2020 Microchip Technology Inc. + */ + +/* This file is autogenerated by cml-utils 2020-11-16 13:11:27 +0100. + * Commit ID: 13bdf073131d8bf40c54901df6988ae4e9c8f29f + */ + +#ifndef _SPARX5_SERDES_REGS_H_ +#define _SPARX5_SERDES_REGS_H_ + +#include +#include +#include + +enum sparx5_serdes_target { + TARGET_SD10G_LANE = 200, + TARGET_SD25G_LANE = 212, + TARGET_SD6G_LANE = 233, + TARGET_SD_CMU = 248, + TARGET_SD_CMU_CFG = 262, + TARGET_SD_LANE = 276, + TARGET_SD_LANE_25G = 301, + NUM_TARGETS = 332 +}; + +#define __REG(...) __VA_ARGS__ + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_01 */ +#define SD10G_LANE_LANE_01(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 4, 0, 1, 4) + +#define SD10G_LANE_LANE_01_CFG_PMA_TX_CK_BITWIDTH_2_0 GENMASK(2, 0) +#define SD10G_LANE_LANE_01_CFG_PMA_TX_CK_BITWIDTH_2_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_01_CFG_PMA_TX_CK_BITWIDTH_2_0, x) +#define SD10G_LANE_LANE_01_CFG_PMA_TX_CK_BITWIDTH_2_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_01_CFG_PMA_TX_CK_BITWIDTH_2_0, x) + +#define SD10G_LANE_LANE_01_CFG_RXDET_EN BIT(4) +#define SD10G_LANE_LANE_01_CFG_RXDET_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_01_CFG_RXDET_EN, x) +#define SD10G_LANE_LANE_01_CFG_RXDET_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_01_CFG_RXDET_EN, x) + +#define SD10G_LANE_LANE_01_CFG_RXDET_STR BIT(5) +#define SD10G_LANE_LANE_01_CFG_RXDET_STR_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_01_CFG_RXDET_STR, x) +#define SD10G_LANE_LANE_01_CFG_RXDET_STR_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_01_CFG_RXDET_STR, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_02 */ +#define SD10G_LANE_LANE_02(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 8, 0, 1, 4) + +#define SD10G_LANE_LANE_02_CFG_EN_ADV BIT(0) +#define SD10G_LANE_LANE_02_CFG_EN_ADV_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_02_CFG_EN_ADV, x) +#define SD10G_LANE_LANE_02_CFG_EN_ADV_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_02_CFG_EN_ADV, x) + +#define SD10G_LANE_LANE_02_CFG_EN_MAIN BIT(1) +#define SD10G_LANE_LANE_02_CFG_EN_MAIN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_02_CFG_EN_MAIN, x) +#define SD10G_LANE_LANE_02_CFG_EN_MAIN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_02_CFG_EN_MAIN, x) + +#define SD10G_LANE_LANE_02_CFG_EN_DLY BIT(2) +#define SD10G_LANE_LANE_02_CFG_EN_DLY_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_02_CFG_EN_DLY, x) +#define SD10G_LANE_LANE_02_CFG_EN_DLY_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_02_CFG_EN_DLY, x) + +#define SD10G_LANE_LANE_02_CFG_EN_DLY2 BIT(3) +#define SD10G_LANE_LANE_02_CFG_EN_DLY2_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_02_CFG_EN_DLY2, x) +#define SD10G_LANE_LANE_02_CFG_EN_DLY2_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_02_CFG_EN_DLY2, x) + +#define SD10G_LANE_LANE_02_CFG_TAP_ADV_3_0 GENMASK(7, 4) +#define SD10G_LANE_LANE_02_CFG_TAP_ADV_3_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_02_CFG_TAP_ADV_3_0, x) +#define SD10G_LANE_LANE_02_CFG_TAP_ADV_3_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_02_CFG_TAP_ADV_3_0, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_03 */ +#define SD10G_LANE_LANE_03(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 12, 0, 1, 4) + +#define SD10G_LANE_LANE_03_CFG_TAP_MAIN BIT(0) +#define SD10G_LANE_LANE_03_CFG_TAP_MAIN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_03_CFG_TAP_MAIN, x) +#define SD10G_LANE_LANE_03_CFG_TAP_MAIN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_03_CFG_TAP_MAIN, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_04 */ +#define SD10G_LANE_LANE_04(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 16, 0, 1, 4) + +#define SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0 GENMASK(4, 0) +#define SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0, x) +#define SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_06 */ +#define SD10G_LANE_LANE_06(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 24, 0, 1, 4) + +#define SD10G_LANE_LANE_06_CFG_PD_DRIVER BIT(0) +#define SD10G_LANE_LANE_06_CFG_PD_DRIVER_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_06_CFG_PD_DRIVER, x) +#define SD10G_LANE_LANE_06_CFG_PD_DRIVER_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_06_CFG_PD_DRIVER, x) + +#define SD10G_LANE_LANE_06_CFG_PD_CLK BIT(1) +#define SD10G_LANE_LANE_06_CFG_PD_CLK_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_06_CFG_PD_CLK, x) +#define SD10G_LANE_LANE_06_CFG_PD_CLK_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_06_CFG_PD_CLK, x) + +#define SD10G_LANE_LANE_06_CFG_PD_CML BIT(2) +#define SD10G_LANE_LANE_06_CFG_PD_CML_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_06_CFG_PD_CML, x) +#define SD10G_LANE_LANE_06_CFG_PD_CML_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_06_CFG_PD_CML, x) + +#define SD10G_LANE_LANE_06_CFG_TX2RX_LP_EN BIT(3) +#define SD10G_LANE_LANE_06_CFG_TX2RX_LP_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_06_CFG_TX2RX_LP_EN, x) +#define SD10G_LANE_LANE_06_CFG_TX2RX_LP_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_06_CFG_TX2RX_LP_EN, x) + +#define SD10G_LANE_LANE_06_CFG_RX2TX_LP_EN BIT(4) +#define SD10G_LANE_LANE_06_CFG_RX2TX_LP_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_06_CFG_RX2TX_LP_EN, x) +#define SD10G_LANE_LANE_06_CFG_RX2TX_LP_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_06_CFG_RX2TX_LP_EN, x) + +#define SD10G_LANE_LANE_06_CFG_EN_PREEMPH BIT(5) +#define SD10G_LANE_LANE_06_CFG_EN_PREEMPH_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_06_CFG_EN_PREEMPH, x) +#define SD10G_LANE_LANE_06_CFG_EN_PREEMPH_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_06_CFG_EN_PREEMPH, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0B */ +#define SD10G_LANE_LANE_0B(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 44, 0, 1, 4) + +#define SD10G_LANE_LANE_0B_CFG_EQ_RES_3_0 GENMASK(3, 0) +#define SD10G_LANE_LANE_0B_CFG_EQ_RES_3_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0B_CFG_EQ_RES_3_0, x) +#define SD10G_LANE_LANE_0B_CFG_EQ_RES_3_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0B_CFG_EQ_RES_3_0, x) + +#define SD10G_LANE_LANE_0B_CFG_PD_CTLE BIT(4) +#define SD10G_LANE_LANE_0B_CFG_PD_CTLE_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0B_CFG_PD_CTLE, x) +#define SD10G_LANE_LANE_0B_CFG_PD_CTLE_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0B_CFG_PD_CTLE, x) + +#define SD10G_LANE_LANE_0B_CFG_CTLE_TP_EN BIT(5) +#define SD10G_LANE_LANE_0B_CFG_CTLE_TP_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0B_CFG_CTLE_TP_EN, x) +#define SD10G_LANE_LANE_0B_CFG_CTLE_TP_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0B_CFG_CTLE_TP_EN, x) + +#define SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE BIT(6) +#define SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE, x) +#define SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE, x) + +#define SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_SQ BIT(7) +#define SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_SQ_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_SQ, x) +#define SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_SQ_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_SQ, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0C */ +#define SD10G_LANE_LANE_0C(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 48, 0, 1, 4) + +#define SD10G_LANE_LANE_0C_CFG_OSCAL_AFE BIT(0) +#define SD10G_LANE_LANE_0C_CFG_OSCAL_AFE_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0C_CFG_OSCAL_AFE, x) +#define SD10G_LANE_LANE_0C_CFG_OSCAL_AFE_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0C_CFG_OSCAL_AFE, x) + +#define SD10G_LANE_LANE_0C_CFG_OSCAL_SQ BIT(1) +#define SD10G_LANE_LANE_0C_CFG_OSCAL_SQ_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0C_CFG_OSCAL_SQ, x) +#define SD10G_LANE_LANE_0C_CFG_OSCAL_SQ_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0C_CFG_OSCAL_SQ, x) + +#define SD10G_LANE_LANE_0C_CFG_OSDAC_2X_AFE BIT(2) +#define SD10G_LANE_LANE_0C_CFG_OSDAC_2X_AFE_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0C_CFG_OSDAC_2X_AFE, x) +#define SD10G_LANE_LANE_0C_CFG_OSDAC_2X_AFE_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0C_CFG_OSDAC_2X_AFE, x) + +#define SD10G_LANE_LANE_0C_CFG_OSDAC_2X_SQ BIT(3) +#define SD10G_LANE_LANE_0C_CFG_OSDAC_2X_SQ_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0C_CFG_OSDAC_2X_SQ, x) +#define SD10G_LANE_LANE_0C_CFG_OSDAC_2X_SQ_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0C_CFG_OSDAC_2X_SQ, x) + +#define SD10G_LANE_LANE_0C_CFG_PD_OSDAC_AFE BIT(4) +#define SD10G_LANE_LANE_0C_CFG_PD_OSDAC_AFE_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0C_CFG_PD_OSDAC_AFE, x) +#define SD10G_LANE_LANE_0C_CFG_PD_OSDAC_AFE_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0C_CFG_PD_OSDAC_AFE, x) + +#define SD10G_LANE_LANE_0C_CFG_PD_OSDAC_SQ BIT(5) +#define SD10G_LANE_LANE_0C_CFG_PD_OSDAC_SQ_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0C_CFG_PD_OSDAC_SQ, x) +#define SD10G_LANE_LANE_0C_CFG_PD_OSDAC_SQ_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0C_CFG_PD_OSDAC_SQ, x) + +#define SD10G_LANE_LANE_0C_CFG_PD_RX_LS BIT(6) +#define SD10G_LANE_LANE_0C_CFG_PD_RX_LS_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0C_CFG_PD_RX_LS, x) +#define SD10G_LANE_LANE_0C_CFG_PD_RX_LS_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0C_CFG_PD_RX_LS, x) + +#define SD10G_LANE_LANE_0C_CFG_RX_PCIE_GEN12 BIT(7) +#define SD10G_LANE_LANE_0C_CFG_RX_PCIE_GEN12_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0C_CFG_RX_PCIE_GEN12, x) +#define SD10G_LANE_LANE_0C_CFG_RX_PCIE_GEN12_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0C_CFG_RX_PCIE_GEN12, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0D */ +#define SD10G_LANE_LANE_0D(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 52, 0, 1, 4) + +#define SD10G_LANE_LANE_0D_CFG_CTLE_M_THR_1_0 GENMASK(1, 0) +#define SD10G_LANE_LANE_0D_CFG_CTLE_M_THR_1_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0D_CFG_CTLE_M_THR_1_0, x) +#define SD10G_LANE_LANE_0D_CFG_CTLE_M_THR_1_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0D_CFG_CTLE_M_THR_1_0, x) + +#define SD10G_LANE_LANE_0D_CFG_EQR_BYP BIT(4) +#define SD10G_LANE_LANE_0D_CFG_EQR_BYP_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0D_CFG_EQR_BYP, x) +#define SD10G_LANE_LANE_0D_CFG_EQR_BYP_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0D_CFG_EQR_BYP, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0E */ +#define SD10G_LANE_LANE_0E(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 56, 0, 1, 4) + +#define SD10G_LANE_LANE_0E_CFG_EQC_FORCE_3_0 GENMASK(3, 0) +#define SD10G_LANE_LANE_0E_CFG_EQC_FORCE_3_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0E_CFG_EQC_FORCE_3_0, x) +#define SD10G_LANE_LANE_0E_CFG_EQC_FORCE_3_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0E_CFG_EQC_FORCE_3_0, x) + +#define SD10G_LANE_LANE_0E_CFG_RXLB_EN BIT(4) +#define SD10G_LANE_LANE_0E_CFG_RXLB_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0E_CFG_RXLB_EN, x) +#define SD10G_LANE_LANE_0E_CFG_RXLB_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0E_CFG_RXLB_EN, x) + +#define SD10G_LANE_LANE_0E_CFG_TXLB_EN BIT(5) +#define SD10G_LANE_LANE_0E_CFG_TXLB_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0E_CFG_TXLB_EN, x) +#define SD10G_LANE_LANE_0E_CFG_TXLB_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0E_CFG_TXLB_EN, x) + +#define SD10G_LANE_LANE_0E_CFG_SUM_SETCM_EN BIT(6) +#define SD10G_LANE_LANE_0E_CFG_SUM_SETCM_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0E_CFG_SUM_SETCM_EN, x) +#define SD10G_LANE_LANE_0E_CFG_SUM_SETCM_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0E_CFG_SUM_SETCM_EN, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0F */ +#define SD10G_LANE_LANE_0F(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 60, 0, 1, 4) + +#define SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0 GENMASK(7, 0) +#define SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0, x) +#define SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_13 */ +#define SD10G_LANE_LANE_13(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 76, 0, 1, 4) + +#define SD10G_LANE_LANE_13_CFG_DCDR_PD BIT(0) +#define SD10G_LANE_LANE_13_CFG_DCDR_PD_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_13_CFG_DCDR_PD, x) +#define SD10G_LANE_LANE_13_CFG_DCDR_PD_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_13_CFG_DCDR_PD, x) + +#define SD10G_LANE_LANE_13_CFG_PHID_1T BIT(1) +#define SD10G_LANE_LANE_13_CFG_PHID_1T_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_13_CFG_PHID_1T, x) +#define SD10G_LANE_LANE_13_CFG_PHID_1T_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_13_CFG_PHID_1T, x) + +#define SD10G_LANE_LANE_13_CFG_CDRCK_EN BIT(2) +#define SD10G_LANE_LANE_13_CFG_CDRCK_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_13_CFG_CDRCK_EN, x) +#define SD10G_LANE_LANE_13_CFG_CDRCK_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_13_CFG_CDRCK_EN, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_14 */ +#define SD10G_LANE_LANE_14(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 80, 0, 1, 4) + +#define SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0 GENMASK(7, 0) +#define SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0, x) +#define SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_15 */ +#define SD10G_LANE_LANE_15(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 84, 0, 1, 4) + +#define SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8 GENMASK(7, 0) +#define SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8, x) +#define SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_16 */ +#define SD10G_LANE_LANE_16(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 88, 0, 1, 4) + +#define SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16 GENMASK(7, 0) +#define SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16, x) +#define SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_1A */ +#define SD10G_LANE_LANE_1A(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 104, 0, 1, 4) + +#define SD10G_LANE_LANE_1A_CFG_PI_R_SCAN_EN BIT(0) +#define SD10G_LANE_LANE_1A_CFG_PI_R_SCAN_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_1A_CFG_PI_R_SCAN_EN, x) +#define SD10G_LANE_LANE_1A_CFG_PI_R_SCAN_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_1A_CFG_PI_R_SCAN_EN, x) + +#define SD10G_LANE_LANE_1A_CFG_PI_EN BIT(1) +#define SD10G_LANE_LANE_1A_CFG_PI_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_1A_CFG_PI_EN, x) +#define SD10G_LANE_LANE_1A_CFG_PI_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_1A_CFG_PI_EN, x) + +#define SD10G_LANE_LANE_1A_CFG_PI_DFE_EN BIT(2) +#define SD10G_LANE_LANE_1A_CFG_PI_DFE_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_1A_CFG_PI_DFE_EN, x) +#define SD10G_LANE_LANE_1A_CFG_PI_DFE_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_1A_CFG_PI_DFE_EN, x) + +#define SD10G_LANE_LANE_1A_CFG_PI_STEPS BIT(3) +#define SD10G_LANE_LANE_1A_CFG_PI_STEPS_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_1A_CFG_PI_STEPS, x) +#define SD10G_LANE_LANE_1A_CFG_PI_STEPS_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_1A_CFG_PI_STEPS, x) + +#define SD10G_LANE_LANE_1A_CFG_PI_FLOOP_STEPS_1_0 GENMASK(5, 4) +#define SD10G_LANE_LANE_1A_CFG_PI_FLOOP_STEPS_1_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_1A_CFG_PI_FLOOP_STEPS_1_0, x) +#define SD10G_LANE_LANE_1A_CFG_PI_FLOOP_STEPS_1_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_1A_CFG_PI_FLOOP_STEPS_1_0, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_22 */ +#define SD10G_LANE_LANE_22(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 136, 0, 1, 4) + +#define SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1 GENMASK(4, 0) +#define SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1, x) +#define SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_23 */ +#define SD10G_LANE_LANE_23(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 140, 0, 1, 4) + +#define SD10G_LANE_LANE_23_CFG_DFE_PD BIT(0) +#define SD10G_LANE_LANE_23_CFG_DFE_PD_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_23_CFG_DFE_PD, x) +#define SD10G_LANE_LANE_23_CFG_DFE_PD_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_23_CFG_DFE_PD, x) + +#define SD10G_LANE_LANE_23_CFG_EN_DFEDIG BIT(1) +#define SD10G_LANE_LANE_23_CFG_EN_DFEDIG_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_23_CFG_EN_DFEDIG, x) +#define SD10G_LANE_LANE_23_CFG_EN_DFEDIG_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_23_CFG_EN_DFEDIG, x) + +#define SD10G_LANE_LANE_23_CFG_DFECK_EN BIT(2) +#define SD10G_LANE_LANE_23_CFG_DFECK_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_23_CFG_DFECK_EN, x) +#define SD10G_LANE_LANE_23_CFG_DFECK_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_23_CFG_DFECK_EN, x) + +#define SD10G_LANE_LANE_23_CFG_ERRAMP_PD BIT(3) +#define SD10G_LANE_LANE_23_CFG_ERRAMP_PD_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_23_CFG_ERRAMP_PD, x) +#define SD10G_LANE_LANE_23_CFG_ERRAMP_PD_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_23_CFG_ERRAMP_PD, x) + +#define SD10G_LANE_LANE_23_CFG_DFEDIG_M_2_0 GENMASK(6, 4) +#define SD10G_LANE_LANE_23_CFG_DFEDIG_M_2_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_23_CFG_DFEDIG_M_2_0, x) +#define SD10G_LANE_LANE_23_CFG_DFEDIG_M_2_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_23_CFG_DFEDIG_M_2_0, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_24 */ +#define SD10G_LANE_LANE_24(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 144, 0, 1, 4) + +#define SD10G_LANE_LANE_24_CFG_PI_BW_GEN1_3_0 GENMASK(3, 0) +#define SD10G_LANE_LANE_24_CFG_PI_BW_GEN1_3_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_24_CFG_PI_BW_GEN1_3_0, x) +#define SD10G_LANE_LANE_24_CFG_PI_BW_GEN1_3_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_24_CFG_PI_BW_GEN1_3_0, x) + +#define SD10G_LANE_LANE_24_CFG_PI_BW_GEN2_3_0 GENMASK(7, 4) +#define SD10G_LANE_LANE_24_CFG_PI_BW_GEN2_3_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_24_CFG_PI_BW_GEN2_3_0, x) +#define SD10G_LANE_LANE_24_CFG_PI_BW_GEN2_3_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_24_CFG_PI_BW_GEN2_3_0, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_26 */ +#define SD10G_LANE_LANE_26(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 152, 0, 1, 4) + +#define SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0 GENMASK(7, 0) +#define SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0, x) +#define SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_2F */ +#define SD10G_LANE_LANE_2F(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 188, 0, 1, 4) + +#define SD10G_LANE_LANE_2F_CFG_VGA_CP_2_0 GENMASK(2, 0) +#define SD10G_LANE_LANE_2F_CFG_VGA_CP_2_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_2F_CFG_VGA_CP_2_0, x) +#define SD10G_LANE_LANE_2F_CFG_VGA_CP_2_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_2F_CFG_VGA_CP_2_0, x) + +#define SD10G_LANE_LANE_2F_CFG_VGA_CTRL_3_0 GENMASK(7, 4) +#define SD10G_LANE_LANE_2F_CFG_VGA_CTRL_3_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_2F_CFG_VGA_CTRL_3_0, x) +#define SD10G_LANE_LANE_2F_CFG_VGA_CTRL_3_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_2F_CFG_VGA_CTRL_3_0, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_30 */ +#define SD10G_LANE_LANE_30(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 192, 0, 1, 4) + +#define SD10G_LANE_LANE_30_CFG_SUMMER_EN BIT(0) +#define SD10G_LANE_LANE_30_CFG_SUMMER_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_30_CFG_SUMMER_EN, x) +#define SD10G_LANE_LANE_30_CFG_SUMMER_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_30_CFG_SUMMER_EN, x) + +#define SD10G_LANE_LANE_30_CFG_RXDIV_SEL_2_0 GENMASK(6, 4) +#define SD10G_LANE_LANE_30_CFG_RXDIV_SEL_2_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_30_CFG_RXDIV_SEL_2_0, x) +#define SD10G_LANE_LANE_30_CFG_RXDIV_SEL_2_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_30_CFG_RXDIV_SEL_2_0, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_31 */ +#define SD10G_LANE_LANE_31(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 196, 0, 1, 4) + +#define SD10G_LANE_LANE_31_CFG_PI_RSTN BIT(0) +#define SD10G_LANE_LANE_31_CFG_PI_RSTN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_31_CFG_PI_RSTN, x) +#define SD10G_LANE_LANE_31_CFG_PI_RSTN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_31_CFG_PI_RSTN, x) + +#define SD10G_LANE_LANE_31_CFG_CDR_RSTN BIT(1) +#define SD10G_LANE_LANE_31_CFG_CDR_RSTN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_31_CFG_CDR_RSTN, x) +#define SD10G_LANE_LANE_31_CFG_CDR_RSTN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_31_CFG_CDR_RSTN, x) + +#define SD10G_LANE_LANE_31_CFG_RSTN_DFEDIG BIT(2) +#define SD10G_LANE_LANE_31_CFG_RSTN_DFEDIG_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_31_CFG_RSTN_DFEDIG, x) +#define SD10G_LANE_LANE_31_CFG_RSTN_DFEDIG_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_31_CFG_RSTN_DFEDIG, x) + +#define SD10G_LANE_LANE_31_CFG_CTLE_RSTN BIT(3) +#define SD10G_LANE_LANE_31_CFG_CTLE_RSTN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_31_CFG_CTLE_RSTN, x) +#define SD10G_LANE_LANE_31_CFG_CTLE_RSTN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_31_CFG_CTLE_RSTN, x) + +#define SD10G_LANE_LANE_31_CFG_RSTN_DIV5_8 BIT(4) +#define SD10G_LANE_LANE_31_CFG_RSTN_DIV5_8_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_31_CFG_RSTN_DIV5_8, x) +#define SD10G_LANE_LANE_31_CFG_RSTN_DIV5_8_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_31_CFG_RSTN_DIV5_8, x) + +#define SD10G_LANE_LANE_31_CFG_R50_EN BIT(5) +#define SD10G_LANE_LANE_31_CFG_R50_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_31_CFG_R50_EN, x) +#define SD10G_LANE_LANE_31_CFG_R50_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_31_CFG_R50_EN, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_32 */ +#define SD10G_LANE_LANE_32(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 200, 0, 1, 4) + +#define SD10G_LANE_LANE_32_CFG_ITX_IPCLK_BASE_1_0 GENMASK(1, 0) +#define SD10G_LANE_LANE_32_CFG_ITX_IPCLK_BASE_1_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_32_CFG_ITX_IPCLK_BASE_1_0, x) +#define SD10G_LANE_LANE_32_CFG_ITX_IPCLK_BASE_1_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_32_CFG_ITX_IPCLK_BASE_1_0, x) + +#define SD10G_LANE_LANE_32_CFG_ITX_IPCML_BASE_1_0 GENMASK(5, 4) +#define SD10G_LANE_LANE_32_CFG_ITX_IPCML_BASE_1_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_32_CFG_ITX_IPCML_BASE_1_0, x) +#define SD10G_LANE_LANE_32_CFG_ITX_IPCML_BASE_1_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_32_CFG_ITX_IPCML_BASE_1_0, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_33 */ +#define SD10G_LANE_LANE_33(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 204, 0, 1, 4) + +#define SD10G_LANE_LANE_33_CFG_ITX_IPDRIVER_BASE_2_0 GENMASK(2, 0) +#define SD10G_LANE_LANE_33_CFG_ITX_IPDRIVER_BASE_2_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_33_CFG_ITX_IPDRIVER_BASE_2_0, x) +#define SD10G_LANE_LANE_33_CFG_ITX_IPDRIVER_BASE_2_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_33_CFG_ITX_IPDRIVER_BASE_2_0, x) + +#define SD10G_LANE_LANE_33_CFG_ITX_IPPREEMP_BASE_1_0 GENMASK(5, 4) +#define SD10G_LANE_LANE_33_CFG_ITX_IPPREEMP_BASE_1_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_33_CFG_ITX_IPPREEMP_BASE_1_0, x) +#define SD10G_LANE_LANE_33_CFG_ITX_IPPREEMP_BASE_1_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_33_CFG_ITX_IPPREEMP_BASE_1_0, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_35 */ +#define SD10G_LANE_LANE_35(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 212, 0, 1, 4) + +#define SD10G_LANE_LANE_35_CFG_TXRATE_1_0 GENMASK(1, 0) +#define SD10G_LANE_LANE_35_CFG_TXRATE_1_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_35_CFG_TXRATE_1_0, x) +#define SD10G_LANE_LANE_35_CFG_TXRATE_1_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_35_CFG_TXRATE_1_0, x) + +#define SD10G_LANE_LANE_35_CFG_RXRATE_1_0 GENMASK(5, 4) +#define SD10G_LANE_LANE_35_CFG_RXRATE_1_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_35_CFG_RXRATE_1_0, x) +#define SD10G_LANE_LANE_35_CFG_RXRATE_1_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_35_CFG_RXRATE_1_0, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_36 */ +#define SD10G_LANE_LANE_36(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 216, 0, 1, 4) + +#define SD10G_LANE_LANE_36_CFG_PREDRV_SLEWRATE_1_0 GENMASK(1, 0) +#define SD10G_LANE_LANE_36_CFG_PREDRV_SLEWRATE_1_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_36_CFG_PREDRV_SLEWRATE_1_0, x) +#define SD10G_LANE_LANE_36_CFG_PREDRV_SLEWRATE_1_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_36_CFG_PREDRV_SLEWRATE_1_0, x) + +#define SD10G_LANE_LANE_36_CFG_EID_LP BIT(4) +#define SD10G_LANE_LANE_36_CFG_EID_LP_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_36_CFG_EID_LP, x) +#define SD10G_LANE_LANE_36_CFG_EID_LP_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_36_CFG_EID_LP, x) + +#define SD10G_LANE_LANE_36_CFG_EN_PREDRV_EMPH BIT(5) +#define SD10G_LANE_LANE_36_CFG_EN_PREDRV_EMPH_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_36_CFG_EN_PREDRV_EMPH, x) +#define SD10G_LANE_LANE_36_CFG_EN_PREDRV_EMPH_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_36_CFG_EN_PREDRV_EMPH, x) + +#define SD10G_LANE_LANE_36_CFG_PRBS_SEL BIT(6) +#define SD10G_LANE_LANE_36_CFG_PRBS_SEL_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_36_CFG_PRBS_SEL, x) +#define SD10G_LANE_LANE_36_CFG_PRBS_SEL_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_36_CFG_PRBS_SEL, x) + +#define SD10G_LANE_LANE_36_CFG_PRBS_SETB BIT(7) +#define SD10G_LANE_LANE_36_CFG_PRBS_SETB_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_36_CFG_PRBS_SETB, x) +#define SD10G_LANE_LANE_36_CFG_PRBS_SETB_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_36_CFG_PRBS_SETB, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_37 */ +#define SD10G_LANE_LANE_37(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 220, 0, 1, 4) + +#define SD10G_LANE_LANE_37_CFG_RXDET_COMP_PD BIT(0) +#define SD10G_LANE_LANE_37_CFG_RXDET_COMP_PD_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_37_CFG_RXDET_COMP_PD, x) +#define SD10G_LANE_LANE_37_CFG_RXDET_COMP_PD_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_37_CFG_RXDET_COMP_PD, x) + +#define SD10G_LANE_LANE_37_CFG_PD_RX_CKTREE BIT(1) +#define SD10G_LANE_LANE_37_CFG_PD_RX_CKTREE_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_37_CFG_PD_RX_CKTREE, x) +#define SD10G_LANE_LANE_37_CFG_PD_RX_CKTREE_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_37_CFG_PD_RX_CKTREE, x) + +#define SD10G_LANE_LANE_37_CFG_TXSWING_HALF BIT(2) +#define SD10G_LANE_LANE_37_CFG_TXSWING_HALF_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_37_CFG_TXSWING_HALF, x) +#define SD10G_LANE_LANE_37_CFG_TXSWING_HALF_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_37_CFG_TXSWING_HALF, x) + +#define SD10G_LANE_LANE_37_CFG_IP_PRE_BASE_1_0 GENMASK(5, 4) +#define SD10G_LANE_LANE_37_CFG_IP_PRE_BASE_1_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_37_CFG_IP_PRE_BASE_1_0, x) +#define SD10G_LANE_LANE_37_CFG_IP_PRE_BASE_1_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_37_CFG_IP_PRE_BASE_1_0, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_39 */ +#define SD10G_LANE_LANE_39(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 228, 0, 1, 4) + +#define SD10G_LANE_LANE_39_CFG_RXFILT_Y_2_0 GENMASK(2, 0) +#define SD10G_LANE_LANE_39_CFG_RXFILT_Y_2_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_39_CFG_RXFILT_Y_2_0, x) +#define SD10G_LANE_LANE_39_CFG_RXFILT_Y_2_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_39_CFG_RXFILT_Y_2_0, x) + +#define SD10G_LANE_LANE_39_CFG_RX_SSC_LH BIT(4) +#define SD10G_LANE_LANE_39_CFG_RX_SSC_LH_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_39_CFG_RX_SSC_LH, x) +#define SD10G_LANE_LANE_39_CFG_RX_SSC_LH_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_39_CFG_RX_SSC_LH, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_3A */ +#define SD10G_LANE_LANE_3A(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 232, 0, 1, 4) + +#define SD10G_LANE_LANE_3A_CFG_MP_MIN_3_0 GENMASK(3, 0) +#define SD10G_LANE_LANE_3A_CFG_MP_MIN_3_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_3A_CFG_MP_MIN_3_0, x) +#define SD10G_LANE_LANE_3A_CFG_MP_MIN_3_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_3A_CFG_MP_MIN_3_0, x) + +#define SD10G_LANE_LANE_3A_CFG_MP_MAX_3_0 GENMASK(7, 4) +#define SD10G_LANE_LANE_3A_CFG_MP_MAX_3_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_3A_CFG_MP_MAX_3_0, x) +#define SD10G_LANE_LANE_3A_CFG_MP_MAX_3_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_3A_CFG_MP_MAX_3_0, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_3C */ +#define SD10G_LANE_LANE_3C(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 240, 0, 1, 4) + +#define SD10G_LANE_LANE_3C_CFG_DIS_ACC BIT(0) +#define SD10G_LANE_LANE_3C_CFG_DIS_ACC_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_3C_CFG_DIS_ACC, x) +#define SD10G_LANE_LANE_3C_CFG_DIS_ACC_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_3C_CFG_DIS_ACC, x) + +#define SD10G_LANE_LANE_3C_CFG_DIS_2NDORDER BIT(1) +#define SD10G_LANE_LANE_3C_CFG_DIS_2NDORDER_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_3C_CFG_DIS_2NDORDER, x) +#define SD10G_LANE_LANE_3C_CFG_DIS_2NDORDER_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_3C_CFG_DIS_2NDORDER, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_40 */ +#define SD10G_LANE_LANE_40(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 256, 0, 1, 4) + +#define SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0 GENMASK(7, 0) +#define SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0, x) +#define SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_41 */ +#define SD10G_LANE_LANE_41(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 260, 0, 1, 4) + +#define SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8 GENMASK(7, 0) +#define SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8, x) +#define SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8, x) + +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_42 */ +#define SD10G_LANE_LANE_42(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 264, 0, 1, 4) + +#define SD10G_LANE_LANE_42_CFG_CDR_KF_GEN1_2_0 GENMASK(2, 0) +#define SD10G_LANE_LANE_42_CFG_CDR_KF_GEN1_2_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_42_CFG_CDR_KF_GEN1_2_0, x) +#define SD10G_LANE_LANE_42_CFG_CDR_KF_GEN1_2_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_42_CFG_CDR_KF_GEN1_2_0, x) + +#define SD10G_LANE_LANE_42_CFG_CDR_KF_GEN2_2_0 GENMASK(6, 4) +#define SD10G_LANE_LANE_42_CFG_CDR_KF_GEN2_2_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_42_CFG_CDR_KF_GEN2_2_0, x) +#define SD10G_LANE_LANE_42_CFG_CDR_KF_GEN2_2_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_42_CFG_CDR_KF_GEN2_2_0, x) + +/* SD10G_LANE_TARGET:LANE_GRP_1:LANE_48 */ +#define SD10G_LANE_LANE_48(t) __REG(TARGET_SD10G_LANE, t, 12, 288, 0, 1, 40, 0, 0, 1, 4) + +#define SD10G_LANE_LANE_48_CFG_ALOS_THR_3_0 GENMASK(3, 0) +#define SD10G_LANE_LANE_48_CFG_ALOS_THR_3_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_48_CFG_ALOS_THR_3_0, x) +#define SD10G_LANE_LANE_48_CFG_ALOS_THR_3_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_48_CFG_ALOS_THR_3_0, x) + +#define SD10G_LANE_LANE_48_CFG_AUX_RXCK_SEL BIT(4) +#define SD10G_LANE_LANE_48_CFG_AUX_RXCK_SEL_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_48_CFG_AUX_RXCK_SEL, x) +#define SD10G_LANE_LANE_48_CFG_AUX_RXCK_SEL_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_48_CFG_AUX_RXCK_SEL, x) + +#define SD10G_LANE_LANE_48_CFG_CLK_ENQ BIT(5) +#define SD10G_LANE_LANE_48_CFG_CLK_ENQ_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_48_CFG_CLK_ENQ, x) +#define SD10G_LANE_LANE_48_CFG_CLK_ENQ_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_48_CFG_CLK_ENQ, x) + +/* SD10G_LANE_TARGET:LANE_GRP_1:LANE_50 */ +#define SD10G_LANE_LANE_50(t) __REG(TARGET_SD10G_LANE, t, 12, 288, 0, 1, 40, 32, 0, 1, 4) + +#define SD10G_LANE_LANE_50_CFG_SSC_PI_STEP_1_0 GENMASK(1, 0) +#define SD10G_LANE_LANE_50_CFG_SSC_PI_STEP_1_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_50_CFG_SSC_PI_STEP_1_0, x) +#define SD10G_LANE_LANE_50_CFG_SSC_PI_STEP_1_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_50_CFG_SSC_PI_STEP_1_0, x) + +#define SD10G_LANE_LANE_50_CFG_SSC_RESETB BIT(4) +#define SD10G_LANE_LANE_50_CFG_SSC_RESETB_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_50_CFG_SSC_RESETB, x) +#define SD10G_LANE_LANE_50_CFG_SSC_RESETB_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_50_CFG_SSC_RESETB, x) + +#define SD10G_LANE_LANE_50_CFG_SSC_RTL_CLK_SEL BIT(5) +#define SD10G_LANE_LANE_50_CFG_SSC_RTL_CLK_SEL_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_50_CFG_SSC_RTL_CLK_SEL, x) +#define SD10G_LANE_LANE_50_CFG_SSC_RTL_CLK_SEL_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_50_CFG_SSC_RTL_CLK_SEL, x) + +#define SD10G_LANE_LANE_50_CFG_AUX_TXCK_SEL BIT(6) +#define SD10G_LANE_LANE_50_CFG_AUX_TXCK_SEL_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_50_CFG_AUX_TXCK_SEL, x) +#define SD10G_LANE_LANE_50_CFG_AUX_TXCK_SEL_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_50_CFG_AUX_TXCK_SEL, x) + +#define SD10G_LANE_LANE_50_CFG_JT_EN BIT(7) +#define SD10G_LANE_LANE_50_CFG_JT_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_50_CFG_JT_EN, x) +#define SD10G_LANE_LANE_50_CFG_JT_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_50_CFG_JT_EN, x) + +/* SD10G_LANE_TARGET:LANE_GRP_2:LANE_52 */ +#define SD10G_LANE_LANE_52(t) __REG(TARGET_SD10G_LANE, t, 12, 328, 0, 1, 24, 0, 0, 1, 4) + +#define SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0 GENMASK(5, 0) +#define SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0, x) +#define SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0, x) + +/* SD10G_LANE_TARGET:LANE_GRP_4:LANE_83 */ +#define SD10G_LANE_LANE_83(t) __REG(TARGET_SD10G_LANE, t, 12, 464, 0, 1, 112, 60, 0, 1, 4) + +#define SD10G_LANE_LANE_83_R_TX_BIT_REVERSE BIT(0) +#define SD10G_LANE_LANE_83_R_TX_BIT_REVERSE_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_83_R_TX_BIT_REVERSE, x) +#define SD10G_LANE_LANE_83_R_TX_BIT_REVERSE_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_83_R_TX_BIT_REVERSE, x) + +#define SD10G_LANE_LANE_83_R_TX_POL_INV BIT(1) +#define SD10G_LANE_LANE_83_R_TX_POL_INV_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_83_R_TX_POL_INV, x) +#define SD10G_LANE_LANE_83_R_TX_POL_INV_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_83_R_TX_POL_INV, x) + +#define SD10G_LANE_LANE_83_R_RX_BIT_REVERSE BIT(2) +#define SD10G_LANE_LANE_83_R_RX_BIT_REVERSE_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_83_R_RX_BIT_REVERSE, x) +#define SD10G_LANE_LANE_83_R_RX_BIT_REVERSE_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_83_R_RX_BIT_REVERSE, x) + +#define SD10G_LANE_LANE_83_R_RX_POL_INV BIT(3) +#define SD10G_LANE_LANE_83_R_RX_POL_INV_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_83_R_RX_POL_INV, x) +#define SD10G_LANE_LANE_83_R_RX_POL_INV_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_83_R_RX_POL_INV, x) + +#define SD10G_LANE_LANE_83_R_DFE_RSTN BIT(4) +#define SD10G_LANE_LANE_83_R_DFE_RSTN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_83_R_DFE_RSTN, x) +#define SD10G_LANE_LANE_83_R_DFE_RSTN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_83_R_DFE_RSTN, x) + +#define SD10G_LANE_LANE_83_R_CDR_RSTN BIT(5) +#define SD10G_LANE_LANE_83_R_CDR_RSTN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_83_R_CDR_RSTN, x) +#define SD10G_LANE_LANE_83_R_CDR_RSTN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_83_R_CDR_RSTN, x) + +#define SD10G_LANE_LANE_83_R_CTLE_RSTN BIT(6) +#define SD10G_LANE_LANE_83_R_CTLE_RSTN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_83_R_CTLE_RSTN, x) +#define SD10G_LANE_LANE_83_R_CTLE_RSTN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_83_R_CTLE_RSTN, x) + +/* SD10G_LANE_TARGET:LANE_GRP_5:LANE_93 */ +#define SD10G_LANE_LANE_93(t) __REG(TARGET_SD10G_LANE, t, 12, 576, 0, 1, 64, 12, 0, 1, 4) + +#define SD10G_LANE_LANE_93_R_RXEI_FIFO_RST_EN BIT(0) +#define SD10G_LANE_LANE_93_R_RXEI_FIFO_RST_EN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_93_R_RXEI_FIFO_RST_EN, x) +#define SD10G_LANE_LANE_93_R_RXEI_FIFO_RST_EN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_93_R_RXEI_FIFO_RST_EN, x) + +#define SD10G_LANE_LANE_93_R_DWIDTHCTRL_FROM_HWT BIT(1) +#define SD10G_LANE_LANE_93_R_DWIDTHCTRL_FROM_HWT_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_93_R_DWIDTHCTRL_FROM_HWT, x) +#define SD10G_LANE_LANE_93_R_DWIDTHCTRL_FROM_HWT_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_93_R_DWIDTHCTRL_FROM_HWT, x) + +#define SD10G_LANE_LANE_93_R_DIS_RESTORE_DFE BIT(2) +#define SD10G_LANE_LANE_93_R_DIS_RESTORE_DFE_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_93_R_DIS_RESTORE_DFE, x) +#define SD10G_LANE_LANE_93_R_DIS_RESTORE_DFE_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_93_R_DIS_RESTORE_DFE, x) + +#define SD10G_LANE_LANE_93_R_EN_RATECHG_CTRL BIT(3) +#define SD10G_LANE_LANE_93_R_EN_RATECHG_CTRL_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_93_R_EN_RATECHG_CTRL, x) +#define SD10G_LANE_LANE_93_R_EN_RATECHG_CTRL_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_93_R_EN_RATECHG_CTRL, x) + +#define SD10G_LANE_LANE_93_R_REG_MANUAL BIT(4) +#define SD10G_LANE_LANE_93_R_REG_MANUAL_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_93_R_REG_MANUAL, x) +#define SD10G_LANE_LANE_93_R_REG_MANUAL_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_93_R_REG_MANUAL, x) + +#define SD10G_LANE_LANE_93_R_AUXCKSEL_FROM_HWT BIT(5) +#define SD10G_LANE_LANE_93_R_AUXCKSEL_FROM_HWT_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_93_R_AUXCKSEL_FROM_HWT, x) +#define SD10G_LANE_LANE_93_R_AUXCKSEL_FROM_HWT_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_93_R_AUXCKSEL_FROM_HWT, x) + +#define SD10G_LANE_LANE_93_R_LANE_ID_FROM_HWT BIT(6) +#define SD10G_LANE_LANE_93_R_LANE_ID_FROM_HWT_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_93_R_LANE_ID_FROM_HWT, x) +#define SD10G_LANE_LANE_93_R_LANE_ID_FROM_HWT_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_93_R_LANE_ID_FROM_HWT, x) + +#define SD10G_LANE_LANE_93_R_RX_PCIE_GEN12_FROM_HWT BIT(7) +#define SD10G_LANE_LANE_93_R_RX_PCIE_GEN12_FROM_HWT_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_93_R_RX_PCIE_GEN12_FROM_HWT, x) +#define SD10G_LANE_LANE_93_R_RX_PCIE_GEN12_FROM_HWT_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_93_R_RX_PCIE_GEN12_FROM_HWT, x) + +/* SD10G_LANE_TARGET:LANE_GRP_5:LANE_94 */ +#define SD10G_LANE_LANE_94(t) __REG(TARGET_SD10G_LANE, t, 12, 576, 0, 1, 64, 16, 0, 1, 4) + +#define SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0 GENMASK(2, 0) +#define SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0, x) +#define SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0, x) + +#define SD10G_LANE_LANE_94_R_ISCAN_REG BIT(4) +#define SD10G_LANE_LANE_94_R_ISCAN_REG_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_94_R_ISCAN_REG, x) +#define SD10G_LANE_LANE_94_R_ISCAN_REG_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_94_R_ISCAN_REG, x) + +#define SD10G_LANE_LANE_94_R_TXEQ_REG BIT(5) +#define SD10G_LANE_LANE_94_R_TXEQ_REG_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_94_R_TXEQ_REG, x) +#define SD10G_LANE_LANE_94_R_TXEQ_REG_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_94_R_TXEQ_REG, x) + +#define SD10G_LANE_LANE_94_R_MISC_REG BIT(6) +#define SD10G_LANE_LANE_94_R_MISC_REG_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_94_R_MISC_REG, x) +#define SD10G_LANE_LANE_94_R_MISC_REG_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_94_R_MISC_REG, x) + +#define SD10G_LANE_LANE_94_R_SWING_REG BIT(7) +#define SD10G_LANE_LANE_94_R_SWING_REG_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_94_R_SWING_REG, x) +#define SD10G_LANE_LANE_94_R_SWING_REG_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_94_R_SWING_REG, x) + +/* SD10G_LANE_TARGET:LANE_GRP_5:LANE_9E */ +#define SD10G_LANE_LANE_9E(t) __REG(TARGET_SD10G_LANE, t, 12, 576, 0, 1, 64, 56, 0, 1, 4) + +#define SD10G_LANE_LANE_9E_R_RXEQ_REG BIT(0) +#define SD10G_LANE_LANE_9E_R_RXEQ_REG_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_9E_R_RXEQ_REG, x) +#define SD10G_LANE_LANE_9E_R_RXEQ_REG_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_9E_R_RXEQ_REG, x) + +#define SD10G_LANE_LANE_9E_R_AUTO_RST_TREE_PD_MAN BIT(1) +#define SD10G_LANE_LANE_9E_R_AUTO_RST_TREE_PD_MAN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_9E_R_AUTO_RST_TREE_PD_MAN, x) +#define SD10G_LANE_LANE_9E_R_AUTO_RST_TREE_PD_MAN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_9E_R_AUTO_RST_TREE_PD_MAN, x) + +#define SD10G_LANE_LANE_9E_R_EN_AUTO_CDR_RSTN BIT(2) +#define SD10G_LANE_LANE_9E_R_EN_AUTO_CDR_RSTN_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_9E_R_EN_AUTO_CDR_RSTN, x) +#define SD10G_LANE_LANE_9E_R_EN_AUTO_CDR_RSTN_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_9E_R_EN_AUTO_CDR_RSTN, x) + +/* SD10G_LANE_TARGET:LANE_GRP_6:LANE_A1 */ +#define SD10G_LANE_LANE_A1(t) __REG(TARGET_SD10G_LANE, t, 12, 640, 0, 1, 128, 4, 0, 1, 4) + +#define SD10G_LANE_LANE_A1_R_PMA_TXCK_DIV_SEL_1_0 GENMASK(1, 0) +#define SD10G_LANE_LANE_A1_R_PMA_TXCK_DIV_SEL_1_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_A1_R_PMA_TXCK_DIV_SEL_1_0, x) +#define SD10G_LANE_LANE_A1_R_PMA_TXCK_DIV_SEL_1_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_A1_R_PMA_TXCK_DIV_SEL_1_0, x) + +#define SD10G_LANE_LANE_A1_R_SSC_FROM_HWT BIT(4) +#define SD10G_LANE_LANE_A1_R_SSC_FROM_HWT_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_A1_R_SSC_FROM_HWT, x) +#define SD10G_LANE_LANE_A1_R_SSC_FROM_HWT_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_A1_R_SSC_FROM_HWT, x) + +#define SD10G_LANE_LANE_A1_R_CDR_FROM_HWT BIT(5) +#define SD10G_LANE_LANE_A1_R_CDR_FROM_HWT_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_A1_R_CDR_FROM_HWT, x) +#define SD10G_LANE_LANE_A1_R_CDR_FROM_HWT_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_A1_R_CDR_FROM_HWT, x) + +#define SD10G_LANE_LANE_A1_R_PCLK_GATING_FROM_HWT BIT(6) +#define SD10G_LANE_LANE_A1_R_PCLK_GATING_FROM_HWT_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_A1_R_PCLK_GATING_FROM_HWT, x) +#define SD10G_LANE_LANE_A1_R_PCLK_GATING_FROM_HWT_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_A1_R_PCLK_GATING_FROM_HWT, x) + +#define SD10G_LANE_LANE_A1_R_PCLK_GATING BIT(7) +#define SD10G_LANE_LANE_A1_R_PCLK_GATING_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_A1_R_PCLK_GATING, x) +#define SD10G_LANE_LANE_A1_R_PCLK_GATING_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_A1_R_PCLK_GATING, x) + +/* SD10G_LANE_TARGET:LANE_GRP_6:LANE_A2 */ +#define SD10G_LANE_LANE_A2(t) __REG(TARGET_SD10G_LANE, t, 12, 640, 0, 1, 128, 8, 0, 1, 4) + +#define SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0 GENMASK(4, 0) +#define SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0, x) +#define SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0, x) + +/* SD10G_LANE_TARGET:LANE_GRP_8:LANE_DF */ +#define SD10G_LANE_LANE_DF(t) __REG(TARGET_SD10G_LANE, t, 12, 832, 0, 1, 84, 60, 0, 1, 4) + +#define SD10G_LANE_LANE_DF_LOL_UDL BIT(0) +#define SD10G_LANE_LANE_DF_LOL_UDL_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_DF_LOL_UDL, x) +#define SD10G_LANE_LANE_DF_LOL_UDL_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_DF_LOL_UDL, x) + +#define SD10G_LANE_LANE_DF_LOL BIT(1) +#define SD10G_LANE_LANE_DF_LOL_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_DF_LOL, x) +#define SD10G_LANE_LANE_DF_LOL_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_DF_LOL, x) + +#define SD10G_LANE_LANE_DF_PMA2PCS_RXEI_FILTERED BIT(2) +#define SD10G_LANE_LANE_DF_PMA2PCS_RXEI_FILTERED_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_DF_PMA2PCS_RXEI_FILTERED, x) +#define SD10G_LANE_LANE_DF_PMA2PCS_RXEI_FILTERED_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_DF_PMA2PCS_RXEI_FILTERED, x) + +#define SD10G_LANE_LANE_DF_SQUELCH BIT(3) +#define SD10G_LANE_LANE_DF_SQUELCH_SET(x)\ + FIELD_PREP(SD10G_LANE_LANE_DF_SQUELCH, x) +#define SD10G_LANE_LANE_DF_SQUELCH_GET(x)\ + FIELD_GET(SD10G_LANE_LANE_DF_SQUELCH, x) + +/* SD25G_TARGET:CMU_GRP_0:CMU_09 */ +#define SD25G_LANE_CMU_09(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 36, 0, 1, 4) + +#define SD25G_LANE_CMU_09_CFG_REFCK_TERM_EN BIT(0) +#define SD25G_LANE_CMU_09_CFG_REFCK_TERM_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_09_CFG_REFCK_TERM_EN, x) +#define SD25G_LANE_CMU_09_CFG_REFCK_TERM_EN_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_09_CFG_REFCK_TERM_EN, x) + +#define SD25G_LANE_CMU_09_CFG_EN_DUMMY BIT(1) +#define SD25G_LANE_CMU_09_CFG_EN_DUMMY_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_09_CFG_EN_DUMMY, x) +#define SD25G_LANE_CMU_09_CFG_EN_DUMMY_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_09_CFG_EN_DUMMY, x) + +#define SD25G_LANE_CMU_09_CFG_PLL_LOS_SET BIT(2) +#define SD25G_LANE_CMU_09_CFG_PLL_LOS_SET_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_09_CFG_PLL_LOS_SET, x) +#define SD25G_LANE_CMU_09_CFG_PLL_LOS_SET_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_09_CFG_PLL_LOS_SET, x) + +#define SD25G_LANE_CMU_09_CFG_CTRL_LOGIC_PD BIT(3) +#define SD25G_LANE_CMU_09_CFG_CTRL_LOGIC_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_09_CFG_CTRL_LOGIC_PD, x) +#define SD25G_LANE_CMU_09_CFG_CTRL_LOGIC_PD_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_09_CFG_CTRL_LOGIC_PD, x) + +#define SD25G_LANE_CMU_09_CFG_PLL_TP_SEL_1_0 GENMASK(5, 4) +#define SD25G_LANE_CMU_09_CFG_PLL_TP_SEL_1_0_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_09_CFG_PLL_TP_SEL_1_0, x) +#define SD25G_LANE_CMU_09_CFG_PLL_TP_SEL_1_0_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_09_CFG_PLL_TP_SEL_1_0, x) + +/* SD25G_TARGET:CMU_GRP_0:CMU_0B */ +#define SD25G_LANE_CMU_0B(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 44, 0, 1, 4) + +#define SD25G_LANE_CMU_0B_CFG_FORCE_RX_FILT BIT(0) +#define SD25G_LANE_CMU_0B_CFG_FORCE_RX_FILT_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0B_CFG_FORCE_RX_FILT, x) +#define SD25G_LANE_CMU_0B_CFG_FORCE_RX_FILT_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0B_CFG_FORCE_RX_FILT, x) + +#define SD25G_LANE_CMU_0B_CFG_DISLOL BIT(1) +#define SD25G_LANE_CMU_0B_CFG_DISLOL_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0B_CFG_DISLOL, x) +#define SD25G_LANE_CMU_0B_CFG_DISLOL_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0B_CFG_DISLOL, x) + +#define SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN_EN BIT(2) +#define SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN_EN, x) +#define SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN_EN_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN_EN, x) + +#define SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN BIT(3) +#define SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN, x) +#define SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN, x) + +#define SD25G_LANE_CMU_0B_CFG_VFILT2PAD BIT(4) +#define SD25G_LANE_CMU_0B_CFG_VFILT2PAD_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0B_CFG_VFILT2PAD, x) +#define SD25G_LANE_CMU_0B_CFG_VFILT2PAD_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0B_CFG_VFILT2PAD, x) + +#define SD25G_LANE_CMU_0B_CFG_DISLOS BIT(5) +#define SD25G_LANE_CMU_0B_CFG_DISLOS_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0B_CFG_DISLOS, x) +#define SD25G_LANE_CMU_0B_CFG_DISLOS_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0B_CFG_DISLOS, x) + +#define SD25G_LANE_CMU_0B_CFG_DCLOL BIT(6) +#define SD25G_LANE_CMU_0B_CFG_DCLOL_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0B_CFG_DCLOL, x) +#define SD25G_LANE_CMU_0B_CFG_DCLOL_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0B_CFG_DCLOL, x) + +#define SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN BIT(7) +#define SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN, x) +#define SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN, x) + +/* SD25G_TARGET:CMU_GRP_0:CMU_0C */ +#define SD25G_LANE_CMU_0C(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 48, 0, 1, 4) + +#define SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET BIT(0) +#define SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET, x) +#define SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET, x) + +#define SD25G_LANE_CMU_0C_CFG_EN_TX_CK_DN BIT(1) +#define SD25G_LANE_CMU_0C_CFG_EN_TX_CK_DN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0C_CFG_EN_TX_CK_DN, x) +#define SD25G_LANE_CMU_0C_CFG_EN_TX_CK_DN_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0C_CFG_EN_TX_CK_DN, x) + +#define SD25G_LANE_CMU_0C_CFG_VCO_PD BIT(2) +#define SD25G_LANE_CMU_0C_CFG_VCO_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0C_CFG_VCO_PD, x) +#define SD25G_LANE_CMU_0C_CFG_VCO_PD_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0C_CFG_VCO_PD, x) + +#define SD25G_LANE_CMU_0C_CFG_EN_TX_CK_UP BIT(3) +#define SD25G_LANE_CMU_0C_CFG_EN_TX_CK_UP_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0C_CFG_EN_TX_CK_UP, x) +#define SD25G_LANE_CMU_0C_CFG_EN_TX_CK_UP_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0C_CFG_EN_TX_CK_UP, x) + +#define SD25G_LANE_CMU_0C_CFG_VCO_DIV_MODE_1_0 GENMASK(5, 4) +#define SD25G_LANE_CMU_0C_CFG_VCO_DIV_MODE_1_0_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0C_CFG_VCO_DIV_MODE_1_0, x) +#define SD25G_LANE_CMU_0C_CFG_VCO_DIV_MODE_1_0_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0C_CFG_VCO_DIV_MODE_1_0, x) + +/* SD25G_TARGET:CMU_GRP_0:CMU_0D */ +#define SD25G_LANE_CMU_0D(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 52, 0, 1, 4) + +#define SD25G_LANE_CMU_0D_CFG_CK_TREE_PD BIT(0) +#define SD25G_LANE_CMU_0D_CFG_CK_TREE_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0D_CFG_CK_TREE_PD, x) +#define SD25G_LANE_CMU_0D_CFG_CK_TREE_PD_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0D_CFG_CK_TREE_PD, x) + +#define SD25G_LANE_CMU_0D_CFG_EN_RX_CK_DN BIT(1) +#define SD25G_LANE_CMU_0D_CFG_EN_RX_CK_DN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0D_CFG_EN_RX_CK_DN, x) +#define SD25G_LANE_CMU_0D_CFG_EN_RX_CK_DN_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0D_CFG_EN_RX_CK_DN, x) + +#define SD25G_LANE_CMU_0D_CFG_EN_RX_CK_UP BIT(2) +#define SD25G_LANE_CMU_0D_CFG_EN_RX_CK_UP_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0D_CFG_EN_RX_CK_UP, x) +#define SD25G_LANE_CMU_0D_CFG_EN_RX_CK_UP_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0D_CFG_EN_RX_CK_UP, x) + +#define SD25G_LANE_CMU_0D_CFG_VCO_CAL_BYP BIT(3) +#define SD25G_LANE_CMU_0D_CFG_VCO_CAL_BYP_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0D_CFG_VCO_CAL_BYP, x) +#define SD25G_LANE_CMU_0D_CFG_VCO_CAL_BYP_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0D_CFG_VCO_CAL_BYP, x) + +#define SD25G_LANE_CMU_0D_CFG_PRE_DIVSEL_1_0 GENMASK(5, 4) +#define SD25G_LANE_CMU_0D_CFG_PRE_DIVSEL_1_0_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0D_CFG_PRE_DIVSEL_1_0, x) +#define SD25G_LANE_CMU_0D_CFG_PRE_DIVSEL_1_0_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0D_CFG_PRE_DIVSEL_1_0, x) + +/* SD25G_TARGET:CMU_GRP_0:CMU_0E */ +#define SD25G_LANE_CMU_0E(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 56, 0, 1, 4) + +#define SD25G_LANE_CMU_0E_CFG_SEL_DIV_3_0 GENMASK(3, 0) +#define SD25G_LANE_CMU_0E_CFG_SEL_DIV_3_0_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0E_CFG_SEL_DIV_3_0, x) +#define SD25G_LANE_CMU_0E_CFG_SEL_DIV_3_0_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0E_CFG_SEL_DIV_3_0, x) + +#define SD25G_LANE_CMU_0E_CFG_PMAA_CENTR_CK_PD BIT(4) +#define SD25G_LANE_CMU_0E_CFG_PMAA_CENTR_CK_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_0E_CFG_PMAA_CENTR_CK_PD, x) +#define SD25G_LANE_CMU_0E_CFG_PMAA_CENTR_CK_PD_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_0E_CFG_PMAA_CENTR_CK_PD, x) + +/* SD25G_TARGET:CMU_GRP_0:CMU_13 */ +#define SD25G_LANE_CMU_13(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 76, 0, 1, 4) + +#define SD25G_LANE_CMU_13_CFG_PLL_RESERVE_3_0 GENMASK(3, 0) +#define SD25G_LANE_CMU_13_CFG_PLL_RESERVE_3_0_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_13_CFG_PLL_RESERVE_3_0, x) +#define SD25G_LANE_CMU_13_CFG_PLL_RESERVE_3_0_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_13_CFG_PLL_RESERVE_3_0, x) + +#define SD25G_LANE_CMU_13_CFG_JT_EN BIT(4) +#define SD25G_LANE_CMU_13_CFG_JT_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_13_CFG_JT_EN, x) +#define SD25G_LANE_CMU_13_CFG_JT_EN_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_13_CFG_JT_EN, x) + +/* SD25G_TARGET:CMU_GRP_0:CMU_18 */ +#define SD25G_LANE_CMU_18(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 96, 0, 1, 4) + +#define SD25G_LANE_CMU_18_R_PLL_RSTN BIT(0) +#define SD25G_LANE_CMU_18_R_PLL_RSTN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_18_R_PLL_RSTN, x) +#define SD25G_LANE_CMU_18_R_PLL_RSTN_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_18_R_PLL_RSTN, x) + +#define SD25G_LANE_CMU_18_R_PLL_LOL_SET BIT(1) +#define SD25G_LANE_CMU_18_R_PLL_LOL_SET_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_18_R_PLL_LOL_SET, x) +#define SD25G_LANE_CMU_18_R_PLL_LOL_SET_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_18_R_PLL_LOL_SET, x) + +#define SD25G_LANE_CMU_18_R_PLL_LOS_SET BIT(2) +#define SD25G_LANE_CMU_18_R_PLL_LOS_SET_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_18_R_PLL_LOS_SET, x) +#define SD25G_LANE_CMU_18_R_PLL_LOS_SET_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_18_R_PLL_LOS_SET, x) + +#define SD25G_LANE_CMU_18_R_PLL_TP_SEL_1_0 GENMASK(5, 4) +#define SD25G_LANE_CMU_18_R_PLL_TP_SEL_1_0_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_18_R_PLL_TP_SEL_1_0, x) +#define SD25G_LANE_CMU_18_R_PLL_TP_SEL_1_0_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_18_R_PLL_TP_SEL_1_0, x) + +/* SD25G_TARGET:CMU_GRP_0:CMU_19 */ +#define SD25G_LANE_CMU_19(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 100, 0, 1, 4) + +#define SD25G_LANE_CMU_19_R_CK_RESETB BIT(0) +#define SD25G_LANE_CMU_19_R_CK_RESETB_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_19_R_CK_RESETB, x) +#define SD25G_LANE_CMU_19_R_CK_RESETB_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_19_R_CK_RESETB, x) + +#define SD25G_LANE_CMU_19_R_PLL_DLOL_EN BIT(1) +#define SD25G_LANE_CMU_19_R_PLL_DLOL_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_19_R_PLL_DLOL_EN, x) +#define SD25G_LANE_CMU_19_R_PLL_DLOL_EN_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_19_R_PLL_DLOL_EN, x) + +/* SD25G_TARGET:CMU_GRP_0:CMU_1A */ +#define SD25G_LANE_CMU_1A(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 104, 0, 1, 4) + +#define SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0 GENMASK(2, 0) +#define SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0, x) +#define SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0, x) + +#define SD25G_LANE_CMU_1A_R_DWIDTHCTRL_FROM_HWT BIT(4) +#define SD25G_LANE_CMU_1A_R_DWIDTHCTRL_FROM_HWT_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_1A_R_DWIDTHCTRL_FROM_HWT, x) +#define SD25G_LANE_CMU_1A_R_DWIDTHCTRL_FROM_HWT_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_1A_R_DWIDTHCTRL_FROM_HWT, x) + +#define SD25G_LANE_CMU_1A_R_MASK_EI_SOURCE BIT(5) +#define SD25G_LANE_CMU_1A_R_MASK_EI_SOURCE_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_1A_R_MASK_EI_SOURCE, x) +#define SD25G_LANE_CMU_1A_R_MASK_EI_SOURCE_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_1A_R_MASK_EI_SOURCE, x) + +#define SD25G_LANE_CMU_1A_R_REG_MANUAL BIT(6) +#define SD25G_LANE_CMU_1A_R_REG_MANUAL_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_1A_R_REG_MANUAL, x) +#define SD25G_LANE_CMU_1A_R_REG_MANUAL_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_1A_R_REG_MANUAL, x) + +/* SD25G_TARGET:CMU_GRP_1:CMU_2A */ +#define SD25G_LANE_CMU_2A(t) __REG(TARGET_SD25G_LANE, t, 8, 132, 0, 1, 124, 36, 0, 1, 4) + +#define SD25G_LANE_CMU_2A_R_DBG_SEL_1_0 GENMASK(1, 0) +#define SD25G_LANE_CMU_2A_R_DBG_SEL_1_0_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_2A_R_DBG_SEL_1_0, x) +#define SD25G_LANE_CMU_2A_R_DBG_SEL_1_0_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_2A_R_DBG_SEL_1_0, x) + +#define SD25G_LANE_CMU_2A_R_DBG_LINK_LANE BIT(4) +#define SD25G_LANE_CMU_2A_R_DBG_LINK_LANE_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_2A_R_DBG_LINK_LANE, x) +#define SD25G_LANE_CMU_2A_R_DBG_LINK_LANE_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_2A_R_DBG_LINK_LANE, x) + +#define SD25G_LANE_CMU_2A_R_DBG_LOL_STATUS BIT(5) +#define SD25G_LANE_CMU_2A_R_DBG_LOL_STATUS_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_2A_R_DBG_LOL_STATUS, x) +#define SD25G_LANE_CMU_2A_R_DBG_LOL_STATUS_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_2A_R_DBG_LOL_STATUS, x) + +/* SD25G_TARGET:CMU_GRP_1:CMU_30 */ +#define SD25G_LANE_CMU_30(t) __REG(TARGET_SD25G_LANE, t, 8, 132, 0, 1, 124, 60, 0, 1, 4) + +#define SD25G_LANE_CMU_30_R_TXFIFO_CK_DIV_PMAD_2_0 GENMASK(2, 0) +#define SD25G_LANE_CMU_30_R_TXFIFO_CK_DIV_PMAD_2_0_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_30_R_TXFIFO_CK_DIV_PMAD_2_0, x) +#define SD25G_LANE_CMU_30_R_TXFIFO_CK_DIV_PMAD_2_0_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_30_R_TXFIFO_CK_DIV_PMAD_2_0, x) + +#define SD25G_LANE_CMU_30_R_RXFIFO_CK_DIV_PMAD_2_0 GENMASK(6, 4) +#define SD25G_LANE_CMU_30_R_RXFIFO_CK_DIV_PMAD_2_0_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_30_R_RXFIFO_CK_DIV_PMAD_2_0, x) +#define SD25G_LANE_CMU_30_R_RXFIFO_CK_DIV_PMAD_2_0_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_30_R_RXFIFO_CK_DIV_PMAD_2_0, x) + +/* SD25G_TARGET:CMU_GRP_1:CMU_31 */ +#define SD25G_LANE_CMU_31(t) __REG(TARGET_SD25G_LANE, t, 8, 132, 0, 1, 124, 64, 0, 1, 4) + +#define SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0 GENMASK(7, 0) +#define SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0, x) +#define SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0, x) + +/* SD25G_TARGET:CMU_GRP_2:CMU_40 */ +#define SD25G_LANE_CMU_40(t) __REG(TARGET_SD25G_LANE, t, 8, 256, 0, 1, 512, 0, 0, 1, 4) + +#define SD25G_LANE_CMU_40_L0_CFG_CKSKEW_CTRL BIT(0) +#define SD25G_LANE_CMU_40_L0_CFG_CKSKEW_CTRL_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_40_L0_CFG_CKSKEW_CTRL, x) +#define SD25G_LANE_CMU_40_L0_CFG_CKSKEW_CTRL_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_40_L0_CFG_CKSKEW_CTRL, x) + +#define SD25G_LANE_CMU_40_L0_CFG_ISCAN_HOLD BIT(1) +#define SD25G_LANE_CMU_40_L0_CFG_ISCAN_HOLD_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_40_L0_CFG_ISCAN_HOLD, x) +#define SD25G_LANE_CMU_40_L0_CFG_ISCAN_HOLD_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_40_L0_CFG_ISCAN_HOLD, x) + +#define SD25G_LANE_CMU_40_L0_CFG_PD_CLK BIT(2) +#define SD25G_LANE_CMU_40_L0_CFG_PD_CLK_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_40_L0_CFG_PD_CLK, x) +#define SD25G_LANE_CMU_40_L0_CFG_PD_CLK_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_40_L0_CFG_PD_CLK, x) + +#define SD25G_LANE_CMU_40_L0_CFG_TXCAL_EN BIT(3) +#define SD25G_LANE_CMU_40_L0_CFG_TXCAL_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_40_L0_CFG_TXCAL_EN, x) +#define SD25G_LANE_CMU_40_L0_CFG_TXCAL_EN_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_40_L0_CFG_TXCAL_EN, x) + +#define SD25G_LANE_CMU_40_L0_CFG_TXCAL_MAN_EN BIT(4) +#define SD25G_LANE_CMU_40_L0_CFG_TXCAL_MAN_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_40_L0_CFG_TXCAL_MAN_EN, x) +#define SD25G_LANE_CMU_40_L0_CFG_TXCAL_MAN_EN_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_40_L0_CFG_TXCAL_MAN_EN, x) + +#define SD25G_LANE_CMU_40_L0_CFG_TXCAL_RST BIT(5) +#define SD25G_LANE_CMU_40_L0_CFG_TXCAL_RST_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_40_L0_CFG_TXCAL_RST, x) +#define SD25G_LANE_CMU_40_L0_CFG_TXCAL_RST_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_40_L0_CFG_TXCAL_RST, x) + +/* SD25G_TARGET:CMU_GRP_2:CMU_45 */ +#define SD25G_LANE_CMU_45(t) __REG(TARGET_SD25G_LANE, t, 8, 256, 0, 1, 512, 20, 0, 1, 4) + +#define SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0 GENMASK(7, 0) +#define SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0, x) +#define SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0, x) + +/* SD25G_TARGET:CMU_GRP_2:CMU_46 */ +#define SD25G_LANE_CMU_46(t) __REG(TARGET_SD25G_LANE, t, 8, 256, 0, 1, 512, 24, 0, 1, 4) + +#define SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8 GENMASK(7, 0) +#define SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8, x) +#define SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8, x) + +/* SD25G_TARGET:CMU_GRP_3:CMU_C0 */ +#define SD25G_LANE_CMU_C0(t) __REG(TARGET_SD25G_LANE, t, 8, 768, 0, 1, 252, 0, 0, 1, 4) + +#define SD25G_LANE_CMU_C0_READ_VCO_CTUNE_3_0 GENMASK(3, 0) +#define SD25G_LANE_CMU_C0_READ_VCO_CTUNE_3_0_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_C0_READ_VCO_CTUNE_3_0, x) +#define SD25G_LANE_CMU_C0_READ_VCO_CTUNE_3_0_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_C0_READ_VCO_CTUNE_3_0, x) + +#define SD25G_LANE_CMU_C0_PLL_LOL_UDL BIT(4) +#define SD25G_LANE_CMU_C0_PLL_LOL_UDL_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_C0_PLL_LOL_UDL, x) +#define SD25G_LANE_CMU_C0_PLL_LOL_UDL_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_C0_PLL_LOL_UDL, x) + +/* SD25G_TARGET:CMU_GRP_4:CMU_FF */ +#define SD25G_LANE_CMU_FF(t) __REG(TARGET_SD25G_LANE, t, 8, 1020, 0, 1, 4, 0, 0, 1, 4) + +#define SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX GENMASK(7, 0) +#define SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_SET(x)\ + FIELD_PREP(SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX, x) +#define SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_GET(x)\ + FIELD_GET(SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_00 */ +#define SD25G_LANE_LANE_00(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 0, 0, 1, 4) + +#define SD25G_LANE_LANE_00_LN_CFG_ITX_VC_DRIVER_3_0 GENMASK(3, 0) +#define SD25G_LANE_LANE_00_LN_CFG_ITX_VC_DRIVER_3_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_00_LN_CFG_ITX_VC_DRIVER_3_0, x) +#define SD25G_LANE_LANE_00_LN_CFG_ITX_VC_DRIVER_3_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_00_LN_CFG_ITX_VC_DRIVER_3_0, x) + +#define SD25G_LANE_LANE_00_LN_CFG_ITX_IPCML_BASE_1_0 GENMASK(5, 4) +#define SD25G_LANE_LANE_00_LN_CFG_ITX_IPCML_BASE_1_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_00_LN_CFG_ITX_IPCML_BASE_1_0, x) +#define SD25G_LANE_LANE_00_LN_CFG_ITX_IPCML_BASE_1_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_00_LN_CFG_ITX_IPCML_BASE_1_0, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_01 */ +#define SD25G_LANE_LANE_01(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 4, 0, 1, 4) + +#define SD25G_LANE_LANE_01_LN_CFG_ITX_IPDRIVER_BASE_2_0 GENMASK(2, 0) +#define SD25G_LANE_LANE_01_LN_CFG_ITX_IPDRIVER_BASE_2_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_01_LN_CFG_ITX_IPDRIVER_BASE_2_0, x) +#define SD25G_LANE_LANE_01_LN_CFG_ITX_IPDRIVER_BASE_2_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_01_LN_CFG_ITX_IPDRIVER_BASE_2_0, x) + +#define SD25G_LANE_LANE_01_LN_CFG_TX_PREDIV_1_0 GENMASK(5, 4) +#define SD25G_LANE_LANE_01_LN_CFG_TX_PREDIV_1_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_01_LN_CFG_TX_PREDIV_1_0, x) +#define SD25G_LANE_LANE_01_LN_CFG_TX_PREDIV_1_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_01_LN_CFG_TX_PREDIV_1_0, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_03 */ +#define SD25G_LANE_LANE_03(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 12, 0, 1, 4) + +#define SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0 GENMASK(4, 0) +#define SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0, x) +#define SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_04 */ +#define SD25G_LANE_LANE_04(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 16, 0, 1, 4) + +#define SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN BIT(0) +#define SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN, x) +#define SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN, x) + +#define SD25G_LANE_LANE_04_LN_CFG_RX2TX_LP_EN BIT(1) +#define SD25G_LANE_LANE_04_LN_CFG_RX2TX_LP_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_04_LN_CFG_RX2TX_LP_EN, x) +#define SD25G_LANE_LANE_04_LN_CFG_RX2TX_LP_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_04_LN_CFG_RX2TX_LP_EN, x) + +#define SD25G_LANE_LANE_04_LN_CFG_PD_CML BIT(2) +#define SD25G_LANE_LANE_04_LN_CFG_PD_CML_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_04_LN_CFG_PD_CML, x) +#define SD25G_LANE_LANE_04_LN_CFG_PD_CML_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_04_LN_CFG_PD_CML, x) + +#define SD25G_LANE_LANE_04_LN_CFG_PD_CLK BIT(3) +#define SD25G_LANE_LANE_04_LN_CFG_PD_CLK_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_04_LN_CFG_PD_CLK, x) +#define SD25G_LANE_LANE_04_LN_CFG_PD_CLK_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_04_LN_CFG_PD_CLK, x) + +#define SD25G_LANE_LANE_04_LN_CFG_PD_DRIVER BIT(4) +#define SD25G_LANE_LANE_04_LN_CFG_PD_DRIVER_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_04_LN_CFG_PD_DRIVER, x) +#define SD25G_LANE_LANE_04_LN_CFG_PD_DRIVER_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_04_LN_CFG_PD_DRIVER, x) + +#define SD25G_LANE_LANE_04_LN_CFG_TAP_MAIN BIT(5) +#define SD25G_LANE_LANE_04_LN_CFG_TAP_MAIN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_04_LN_CFG_TAP_MAIN, x) +#define SD25G_LANE_LANE_04_LN_CFG_TAP_MAIN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_04_LN_CFG_TAP_MAIN, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_05 */ +#define SD25G_LANE_LANE_05(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 20, 0, 1, 4) + +#define SD25G_LANE_LANE_05_LN_CFG_TAP_DLY2_3_0 GENMASK(3, 0) +#define SD25G_LANE_LANE_05_LN_CFG_TAP_DLY2_3_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_05_LN_CFG_TAP_DLY2_3_0, x) +#define SD25G_LANE_LANE_05_LN_CFG_TAP_DLY2_3_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_05_LN_CFG_TAP_DLY2_3_0, x) + +#define SD25G_LANE_LANE_05_LN_CFG_BW_1_0 GENMASK(5, 4) +#define SD25G_LANE_LANE_05_LN_CFG_BW_1_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_05_LN_CFG_BW_1_0, x) +#define SD25G_LANE_LANE_05_LN_CFG_BW_1_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_05_LN_CFG_BW_1_0, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_06 */ +#define SD25G_LANE_LANE_06(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 24, 0, 1, 4) + +#define SD25G_LANE_LANE_06_LN_CFG_EN_MAIN BIT(0) +#define SD25G_LANE_LANE_06_LN_CFG_EN_MAIN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_06_LN_CFG_EN_MAIN, x) +#define SD25G_LANE_LANE_06_LN_CFG_EN_MAIN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_06_LN_CFG_EN_MAIN, x) + +#define SD25G_LANE_LANE_06_LN_CFG_TAP_ADV_3_0 GENMASK(7, 4) +#define SD25G_LANE_LANE_06_LN_CFG_TAP_ADV_3_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_06_LN_CFG_TAP_ADV_3_0, x) +#define SD25G_LANE_LANE_06_LN_CFG_TAP_ADV_3_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_06_LN_CFG_TAP_ADV_3_0, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_07 */ +#define SD25G_LANE_LANE_07(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 28, 0, 1, 4) + +#define SD25G_LANE_LANE_07_LN_CFG_EN_ADV BIT(0) +#define SD25G_LANE_LANE_07_LN_CFG_EN_ADV_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_07_LN_CFG_EN_ADV, x) +#define SD25G_LANE_LANE_07_LN_CFG_EN_ADV_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_07_LN_CFG_EN_ADV, x) + +#define SD25G_LANE_LANE_07_LN_CFG_EN_DLY2 BIT(1) +#define SD25G_LANE_LANE_07_LN_CFG_EN_DLY2_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_07_LN_CFG_EN_DLY2, x) +#define SD25G_LANE_LANE_07_LN_CFG_EN_DLY2_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_07_LN_CFG_EN_DLY2, x) + +#define SD25G_LANE_LANE_07_LN_CFG_EN_DLY BIT(2) +#define SD25G_LANE_LANE_07_LN_CFG_EN_DLY_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_07_LN_CFG_EN_DLY, x) +#define SD25G_LANE_LANE_07_LN_CFG_EN_DLY_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_07_LN_CFG_EN_DLY, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_09 */ +#define SD25G_LANE_LANE_09(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 36, 0, 1, 4) + +#define SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0 GENMASK(3, 0) +#define SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0, x) +#define SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_0A */ +#define SD25G_LANE_LANE_0A(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 40, 0, 1, 4) + +#define SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0 GENMASK(5, 0) +#define SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0, x) +#define SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_0B */ +#define SD25G_LANE_LANE_0B(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 44, 0, 1, 4) + +#define SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN BIT(0) +#define SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN, x) +#define SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN, x) + +#define SD25G_LANE_LANE_0B_LN_CFG_TXCAL_RST BIT(1) +#define SD25G_LANE_LANE_0B_LN_CFG_TXCAL_RST_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0B_LN_CFG_TXCAL_RST, x) +#define SD25G_LANE_LANE_0B_LN_CFG_TXCAL_RST_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0B_LN_CFG_TXCAL_RST, x) + +#define SD25G_LANE_LANE_0B_LN_CFG_QUAD_MAN_1_0 GENMASK(5, 4) +#define SD25G_LANE_LANE_0B_LN_CFG_QUAD_MAN_1_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0B_LN_CFG_QUAD_MAN_1_0, x) +#define SD25G_LANE_LANE_0B_LN_CFG_QUAD_MAN_1_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0B_LN_CFG_QUAD_MAN_1_0, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_0C */ +#define SD25G_LANE_LANE_0C(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 48, 0, 1, 4) + +#define SD25G_LANE_LANE_0C_LN_CFG_PMA_TX_CK_BITWIDTH_2_0 GENMASK(2, 0) +#define SD25G_LANE_LANE_0C_LN_CFG_PMA_TX_CK_BITWIDTH_2_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0C_LN_CFG_PMA_TX_CK_BITWIDTH_2_0, x) +#define SD25G_LANE_LANE_0C_LN_CFG_PMA_TX_CK_BITWIDTH_2_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0C_LN_CFG_PMA_TX_CK_BITWIDTH_2_0, x) + +#define SD25G_LANE_LANE_0C_LN_CFG_TXCAL_EN BIT(4) +#define SD25G_LANE_LANE_0C_LN_CFG_TXCAL_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0C_LN_CFG_TXCAL_EN, x) +#define SD25G_LANE_LANE_0C_LN_CFG_TXCAL_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0C_LN_CFG_TXCAL_EN, x) + +#define SD25G_LANE_LANE_0C_LN_CFG_RXTERM_PD BIT(5) +#define SD25G_LANE_LANE_0C_LN_CFG_RXTERM_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0C_LN_CFG_RXTERM_PD, x) +#define SD25G_LANE_LANE_0C_LN_CFG_RXTERM_PD_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0C_LN_CFG_RXTERM_PD, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_0D */ +#define SD25G_LANE_LANE_0D(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 52, 0, 1, 4) + +#define SD25G_LANE_LANE_0D_LN_CFG_RXTERM_2_0 GENMASK(2, 0) +#define SD25G_LANE_LANE_0D_LN_CFG_RXTERM_2_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0D_LN_CFG_RXTERM_2_0, x) +#define SD25G_LANE_LANE_0D_LN_CFG_RXTERM_2_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0D_LN_CFG_RXTERM_2_0, x) + +#define SD25G_LANE_LANE_0D_LN_CFG_RSTN_DIV5_8 BIT(4) +#define SD25G_LANE_LANE_0D_LN_CFG_RSTN_DIV5_8_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0D_LN_CFG_RSTN_DIV5_8, x) +#define SD25G_LANE_LANE_0D_LN_CFG_RSTN_DIV5_8_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0D_LN_CFG_RSTN_DIV5_8, x) + +#define SD25G_LANE_LANE_0D_LN_CFG_SUMMER_EN BIT(5) +#define SD25G_LANE_LANE_0D_LN_CFG_SUMMER_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0D_LN_CFG_SUMMER_EN, x) +#define SD25G_LANE_LANE_0D_LN_CFG_SUMMER_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0D_LN_CFG_SUMMER_EN, x) + +#define SD25G_LANE_LANE_0D_LN_CFG_DMUX_PD BIT(6) +#define SD25G_LANE_LANE_0D_LN_CFG_DMUX_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0D_LN_CFG_DMUX_PD, x) +#define SD25G_LANE_LANE_0D_LN_CFG_DMUX_PD_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0D_LN_CFG_DMUX_PD, x) + +#define SD25G_LANE_LANE_0D_LN_CFG_DFECK_EN BIT(7) +#define SD25G_LANE_LANE_0D_LN_CFG_DFECK_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0D_LN_CFG_DFECK_EN, x) +#define SD25G_LANE_LANE_0D_LN_CFG_DFECK_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0D_LN_CFG_DFECK_EN, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_0E */ +#define SD25G_LANE_LANE_0E(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 56, 0, 1, 4) + +#define SD25G_LANE_LANE_0E_LN_CFG_ISCAN_EN BIT(0) +#define SD25G_LANE_LANE_0E_LN_CFG_ISCAN_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0E_LN_CFG_ISCAN_EN, x) +#define SD25G_LANE_LANE_0E_LN_CFG_ISCAN_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0E_LN_CFG_ISCAN_EN, x) + +#define SD25G_LANE_LANE_0E_LN_CFG_DMUX_CLK_PD BIT(1) +#define SD25G_LANE_LANE_0E_LN_CFG_DMUX_CLK_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0E_LN_CFG_DMUX_CLK_PD, x) +#define SD25G_LANE_LANE_0E_LN_CFG_DMUX_CLK_PD_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0E_LN_CFG_DMUX_CLK_PD, x) + +#define SD25G_LANE_LANE_0E_LN_CFG_EN_DFEDIG BIT(2) +#define SD25G_LANE_LANE_0E_LN_CFG_EN_DFEDIG_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0E_LN_CFG_EN_DFEDIG, x) +#define SD25G_LANE_LANE_0E_LN_CFG_EN_DFEDIG_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0E_LN_CFG_EN_DFEDIG, x) + +#define SD25G_LANE_LANE_0E_LN_CFG_DFEDIG_M_2_0 GENMASK(6, 4) +#define SD25G_LANE_LANE_0E_LN_CFG_DFEDIG_M_2_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0E_LN_CFG_DFEDIG_M_2_0, x) +#define SD25G_LANE_LANE_0E_LN_CFG_DFEDIG_M_2_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0E_LN_CFG_DFEDIG_M_2_0, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_0F */ +#define SD25G_LANE_LANE_0F(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 60, 0, 1, 4) + +#define SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1 GENMASK(4, 0) +#define SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1, x) +#define SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_18 */ +#define SD25G_LANE_LANE_18(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 96, 0, 1, 4) + +#define SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN BIT(0) +#define SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN, x) +#define SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN, x) + +#define SD25G_LANE_LANE_18_LN_CFG_ADD_VOLT BIT(1) +#define SD25G_LANE_LANE_18_LN_CFG_ADD_VOLT_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_18_LN_CFG_ADD_VOLT, x) +#define SD25G_LANE_LANE_18_LN_CFG_ADD_VOLT_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_18_LN_CFG_ADD_VOLT, x) + +#define SD25G_LANE_LANE_18_LN_CFG_MAN_VOLT_EN BIT(2) +#define SD25G_LANE_LANE_18_LN_CFG_MAN_VOLT_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_18_LN_CFG_MAN_VOLT_EN, x) +#define SD25G_LANE_LANE_18_LN_CFG_MAN_VOLT_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_18_LN_CFG_MAN_VOLT_EN, x) + +#define SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD BIT(3) +#define SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD, x) +#define SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD, x) + +#define SD25G_LANE_LANE_18_LN_CFG_RXDIV_SEL_2_0 GENMASK(6, 4) +#define SD25G_LANE_LANE_18_LN_CFG_RXDIV_SEL_2_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_18_LN_CFG_RXDIV_SEL_2_0, x) +#define SD25G_LANE_LANE_18_LN_CFG_RXDIV_SEL_2_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_18_LN_CFG_RXDIV_SEL_2_0, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_19 */ +#define SD25G_LANE_LANE_19(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 100, 0, 1, 4) + +#define SD25G_LANE_LANE_19_LN_CFG_DCDR_PD BIT(0) +#define SD25G_LANE_LANE_19_LN_CFG_DCDR_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_19_LN_CFG_DCDR_PD, x) +#define SD25G_LANE_LANE_19_LN_CFG_DCDR_PD_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_19_LN_CFG_DCDR_PD, x) + +#define SD25G_LANE_LANE_19_LN_CFG_ECDR_PD BIT(1) +#define SD25G_LANE_LANE_19_LN_CFG_ECDR_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_19_LN_CFG_ECDR_PD, x) +#define SD25G_LANE_LANE_19_LN_CFG_ECDR_PD_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_19_LN_CFG_ECDR_PD, x) + +#define SD25G_LANE_LANE_19_LN_CFG_ISCAN_SEL BIT(2) +#define SD25G_LANE_LANE_19_LN_CFG_ISCAN_SEL_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_19_LN_CFG_ISCAN_SEL, x) +#define SD25G_LANE_LANE_19_LN_CFG_ISCAN_SEL_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_19_LN_CFG_ISCAN_SEL, x) + +#define SD25G_LANE_LANE_19_LN_CFG_TXLB_EN BIT(3) +#define SD25G_LANE_LANE_19_LN_CFG_TXLB_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_19_LN_CFG_TXLB_EN, x) +#define SD25G_LANE_LANE_19_LN_CFG_TXLB_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_19_LN_CFG_TXLB_EN, x) + +#define SD25G_LANE_LANE_19_LN_CFG_RX_REG_PU BIT(4) +#define SD25G_LANE_LANE_19_LN_CFG_RX_REG_PU_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_19_LN_CFG_RX_REG_PU, x) +#define SD25G_LANE_LANE_19_LN_CFG_RX_REG_PU_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_19_LN_CFG_RX_REG_PU, x) + +#define SD25G_LANE_LANE_19_LN_CFG_RX_REG_BYP BIT(5) +#define SD25G_LANE_LANE_19_LN_CFG_RX_REG_BYP_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_19_LN_CFG_RX_REG_BYP, x) +#define SD25G_LANE_LANE_19_LN_CFG_RX_REG_BYP_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_19_LN_CFG_RX_REG_BYP, x) + +#define SD25G_LANE_LANE_19_LN_CFG_PD_RMS_DET BIT(6) +#define SD25G_LANE_LANE_19_LN_CFG_PD_RMS_DET_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_19_LN_CFG_PD_RMS_DET, x) +#define SD25G_LANE_LANE_19_LN_CFG_PD_RMS_DET_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_19_LN_CFG_PD_RMS_DET, x) + +#define SD25G_LANE_LANE_19_LN_CFG_PD_CTLE BIT(7) +#define SD25G_LANE_LANE_19_LN_CFG_PD_CTLE_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_19_LN_CFG_PD_CTLE, x) +#define SD25G_LANE_LANE_19_LN_CFG_PD_CTLE_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_19_LN_CFG_PD_CTLE, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_1A */ +#define SD25G_LANE_LANE_1A(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 104, 0, 1, 4) + +#define SD25G_LANE_LANE_1A_LN_CFG_CTLE_TP_EN BIT(0) +#define SD25G_LANE_LANE_1A_LN_CFG_CTLE_TP_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1A_LN_CFG_CTLE_TP_EN, x) +#define SD25G_LANE_LANE_1A_LN_CFG_CTLE_TP_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1A_LN_CFG_CTLE_TP_EN, x) + +#define SD25G_LANE_LANE_1A_LN_CFG_CDR_KF_2_0 GENMASK(6, 4) +#define SD25G_LANE_LANE_1A_LN_CFG_CDR_KF_2_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1A_LN_CFG_CDR_KF_2_0, x) +#define SD25G_LANE_LANE_1A_LN_CFG_CDR_KF_2_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1A_LN_CFG_CDR_KF_2_0, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_1B */ +#define SD25G_LANE_LANE_1B(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 108, 0, 1, 4) + +#define SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0 GENMASK(7, 0) +#define SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0, x) +#define SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_1C */ +#define SD25G_LANE_LANE_1C(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 112, 0, 1, 4) + +#define SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN BIT(0) +#define SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN, x) +#define SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN, x) + +#define SD25G_LANE_LANE_1C_LN_CFG_DFE_PD BIT(1) +#define SD25G_LANE_LANE_1C_LN_CFG_DFE_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1C_LN_CFG_DFE_PD, x) +#define SD25G_LANE_LANE_1C_LN_CFG_DFE_PD_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1C_LN_CFG_DFE_PD, x) + +#define SD25G_LANE_LANE_1C_LN_CFG_DFEDMX_PD BIT(2) +#define SD25G_LANE_LANE_1C_LN_CFG_DFEDMX_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1C_LN_CFG_DFEDMX_PD, x) +#define SD25G_LANE_LANE_1C_LN_CFG_DFEDMX_PD_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1C_LN_CFG_DFEDMX_PD, x) + +#define SD25G_LANE_LANE_1C_LN_CFG_EQC_FORCE_3_0 GENMASK(7, 4) +#define SD25G_LANE_LANE_1C_LN_CFG_EQC_FORCE_3_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1C_LN_CFG_EQC_FORCE_3_0, x) +#define SD25G_LANE_LANE_1C_LN_CFG_EQC_FORCE_3_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1C_LN_CFG_EQC_FORCE_3_0, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_1D */ +#define SD25G_LANE_LANE_1D(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 116, 0, 1, 4) + +#define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_EXT_OVR BIT(0) +#define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_EXT_OVR_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1D_LN_CFG_ISCAN_EXT_OVR, x) +#define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_EXT_OVR_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1D_LN_CFG_ISCAN_EXT_OVR, x) + +#define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_HOLD BIT(1) +#define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_HOLD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1D_LN_CFG_ISCAN_HOLD, x) +#define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_HOLD_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1D_LN_CFG_ISCAN_HOLD, x) + +#define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_RSTN BIT(2) +#define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_RSTN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1D_LN_CFG_ISCAN_RSTN, x) +#define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_RSTN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1D_LN_CFG_ISCAN_RSTN, x) + +#define SD25G_LANE_LANE_1D_LN_CFG_AGC_ADPT_BYP BIT(3) +#define SD25G_LANE_LANE_1D_LN_CFG_AGC_ADPT_BYP_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1D_LN_CFG_AGC_ADPT_BYP, x) +#define SD25G_LANE_LANE_1D_LN_CFG_AGC_ADPT_BYP_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1D_LN_CFG_AGC_ADPT_BYP, x) + +#define SD25G_LANE_LANE_1D_LN_CFG_PHID_1T BIT(4) +#define SD25G_LANE_LANE_1D_LN_CFG_PHID_1T_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1D_LN_CFG_PHID_1T, x) +#define SD25G_LANE_LANE_1D_LN_CFG_PHID_1T_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1D_LN_CFG_PHID_1T, x) + +#define SD25G_LANE_LANE_1D_LN_CFG_PI_DFE_EN BIT(5) +#define SD25G_LANE_LANE_1D_LN_CFG_PI_DFE_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1D_LN_CFG_PI_DFE_EN, x) +#define SD25G_LANE_LANE_1D_LN_CFG_PI_DFE_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1D_LN_CFG_PI_DFE_EN, x) + +#define SD25G_LANE_LANE_1D_LN_CFG_PI_EXT_OVR BIT(6) +#define SD25G_LANE_LANE_1D_LN_CFG_PI_EXT_OVR_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1D_LN_CFG_PI_EXT_OVR, x) +#define SD25G_LANE_LANE_1D_LN_CFG_PI_EXT_OVR_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1D_LN_CFG_PI_EXT_OVR, x) + +#define SD25G_LANE_LANE_1D_LN_CFG_PI_HOLD BIT(7) +#define SD25G_LANE_LANE_1D_LN_CFG_PI_HOLD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1D_LN_CFG_PI_HOLD, x) +#define SD25G_LANE_LANE_1D_LN_CFG_PI_HOLD_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1D_LN_CFG_PI_HOLD, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_1E */ +#define SD25G_LANE_LANE_1E(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 120, 0, 1, 4) + +#define SD25G_LANE_LANE_1E_LN_CFG_PI_STEPS_1_0 GENMASK(1, 0) +#define SD25G_LANE_LANE_1E_LN_CFG_PI_STEPS_1_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1E_LN_CFG_PI_STEPS_1_0, x) +#define SD25G_LANE_LANE_1E_LN_CFG_PI_STEPS_1_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1E_LN_CFG_PI_STEPS_1_0, x) + +#define SD25G_LANE_LANE_1E_LN_CFG_RXLB_EN BIT(4) +#define SD25G_LANE_LANE_1E_LN_CFG_RXLB_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1E_LN_CFG_RXLB_EN, x) +#define SD25G_LANE_LANE_1E_LN_CFG_RXLB_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1E_LN_CFG_RXLB_EN, x) + +#define SD25G_LANE_LANE_1E_LN_CFG_SUM_SETCM_EN BIT(5) +#define SD25G_LANE_LANE_1E_LN_CFG_SUM_SETCM_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1E_LN_CFG_SUM_SETCM_EN, x) +#define SD25G_LANE_LANE_1E_LN_CFG_SUM_SETCM_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1E_LN_CFG_SUM_SETCM_EN, x) + +#define SD25G_LANE_LANE_1E_LN_CFG_R_OFFSET_DIR BIT(6) +#define SD25G_LANE_LANE_1E_LN_CFG_R_OFFSET_DIR_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1E_LN_CFG_R_OFFSET_DIR, x) +#define SD25G_LANE_LANE_1E_LN_CFG_R_OFFSET_DIR_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1E_LN_CFG_R_OFFSET_DIR, x) + +#define SD25G_LANE_LANE_1E_LN_CFG_PMAD_CK_PD BIT(7) +#define SD25G_LANE_LANE_1E_LN_CFG_PMAD_CK_PD_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_1E_LN_CFG_PMAD_CK_PD, x) +#define SD25G_LANE_LANE_1E_LN_CFG_PMAD_CK_PD_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_1E_LN_CFG_PMAD_CK_PD, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_21 */ +#define SD25G_LANE_LANE_21(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 132, 0, 1, 4) + +#define SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0 GENMASK(4, 0) +#define SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0, x) +#define SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_22 */ +#define SD25G_LANE_LANE_22(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 136, 0, 1, 4) + +#define SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0 GENMASK(3, 0) +#define SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0, x) +#define SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_25 */ +#define SD25G_LANE_LANE_25(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 148, 0, 1, 4) + +#define SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0 GENMASK(6, 0) +#define SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0, x) +#define SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_26 */ +#define SD25G_LANE_LANE_26(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 152, 0, 1, 4) + +#define SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0 GENMASK(6, 0) +#define SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0, x) +#define SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_28 */ +#define SD25G_LANE_LANE_28(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 160, 0, 1, 4) + +#define SD25G_LANE_LANE_28_LN_CFG_ISCAN_MODE_EN BIT(0) +#define SD25G_LANE_LANE_28_LN_CFG_ISCAN_MODE_EN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_28_LN_CFG_ISCAN_MODE_EN, x) +#define SD25G_LANE_LANE_28_LN_CFG_ISCAN_MODE_EN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_28_LN_CFG_ISCAN_MODE_EN, x) + +#define SD25G_LANE_LANE_28_LN_CFG_RX_SSC_LH BIT(1) +#define SD25G_LANE_LANE_28_LN_CFG_RX_SSC_LH_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_28_LN_CFG_RX_SSC_LH, x) +#define SD25G_LANE_LANE_28_LN_CFG_RX_SSC_LH_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_28_LN_CFG_RX_SSC_LH, x) + +#define SD25G_LANE_LANE_28_LN_CFG_FIGMERIT_SEL BIT(2) +#define SD25G_LANE_LANE_28_LN_CFG_FIGMERIT_SEL_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_28_LN_CFG_FIGMERIT_SEL, x) +#define SD25G_LANE_LANE_28_LN_CFG_FIGMERIT_SEL_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_28_LN_CFG_FIGMERIT_SEL, x) + +#define SD25G_LANE_LANE_28_LN_CFG_RX_SUBRATE_2_0 GENMASK(6, 4) +#define SD25G_LANE_LANE_28_LN_CFG_RX_SUBRATE_2_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_28_LN_CFG_RX_SUBRATE_2_0, x) +#define SD25G_LANE_LANE_28_LN_CFG_RX_SUBRATE_2_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_28_LN_CFG_RX_SUBRATE_2_0, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_2B */ +#define SD25G_LANE_LANE_2B(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 172, 0, 1, 4) + +#define SD25G_LANE_LANE_2B_LN_CFG_PI_BW_3_0 GENMASK(3, 0) +#define SD25G_LANE_LANE_2B_LN_CFG_PI_BW_3_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2B_LN_CFG_PI_BW_3_0, x) +#define SD25G_LANE_LANE_2B_LN_CFG_PI_BW_3_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2B_LN_CFG_PI_BW_3_0, x) + +#define SD25G_LANE_LANE_2B_LN_CFG_RSTN_DMUX_SUBR BIT(4) +#define SD25G_LANE_LANE_2B_LN_CFG_RSTN_DMUX_SUBR_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2B_LN_CFG_RSTN_DMUX_SUBR, x) +#define SD25G_LANE_LANE_2B_LN_CFG_RSTN_DMUX_SUBR_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2B_LN_CFG_RSTN_DMUX_SUBR, x) + +#define SD25G_LANE_LANE_2B_LN_CFG_RSTN_TXDUPU BIT(5) +#define SD25G_LANE_LANE_2B_LN_CFG_RSTN_TXDUPU_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2B_LN_CFG_RSTN_TXDUPU, x) +#define SD25G_LANE_LANE_2B_LN_CFG_RSTN_TXDUPU_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2B_LN_CFG_RSTN_TXDUPU, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_2C */ +#define SD25G_LANE_LANE_2C(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 176, 0, 1, 4) + +#define SD25G_LANE_LANE_2C_LN_CFG_TX_SUBRATE_2_0 GENMASK(2, 0) +#define SD25G_LANE_LANE_2C_LN_CFG_TX_SUBRATE_2_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2C_LN_CFG_TX_SUBRATE_2_0, x) +#define SD25G_LANE_LANE_2C_LN_CFG_TX_SUBRATE_2_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2C_LN_CFG_TX_SUBRATE_2_0, x) + +#define SD25G_LANE_LANE_2C_LN_CFG_DIS_2NDORDER BIT(4) +#define SD25G_LANE_LANE_2C_LN_CFG_DIS_2NDORDER_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2C_LN_CFG_DIS_2NDORDER, x) +#define SD25G_LANE_LANE_2C_LN_CFG_DIS_2NDORDER_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2C_LN_CFG_DIS_2NDORDER, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_2D */ +#define SD25G_LANE_LANE_2D(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 180, 0, 1, 4) + +#define SD25G_LANE_LANE_2D_LN_CFG_ALOS_THR_2_0 GENMASK(2, 0) +#define SD25G_LANE_LANE_2D_LN_CFG_ALOS_THR_2_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2D_LN_CFG_ALOS_THR_2_0, x) +#define SD25G_LANE_LANE_2D_LN_CFG_ALOS_THR_2_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2D_LN_CFG_ALOS_THR_2_0, x) + +#define SD25G_LANE_LANE_2D_LN_CFG_SAT_CNTSEL_2_0 GENMASK(6, 4) +#define SD25G_LANE_LANE_2D_LN_CFG_SAT_CNTSEL_2_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2D_LN_CFG_SAT_CNTSEL_2_0, x) +#define SD25G_LANE_LANE_2D_LN_CFG_SAT_CNTSEL_2_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2D_LN_CFG_SAT_CNTSEL_2_0, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_2E */ +#define SD25G_LANE_LANE_2E(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 184, 0, 1, 4) + +#define SD25G_LANE_LANE_2E_LN_CFG_EN_FAST_ISCAN BIT(0) +#define SD25G_LANE_LANE_2E_LN_CFG_EN_FAST_ISCAN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2E_LN_CFG_EN_FAST_ISCAN, x) +#define SD25G_LANE_LANE_2E_LN_CFG_EN_FAST_ISCAN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2E_LN_CFG_EN_FAST_ISCAN, x) + +#define SD25G_LANE_LANE_2E_LN_CFG_DIS_SQ BIT(1) +#define SD25G_LANE_LANE_2E_LN_CFG_DIS_SQ_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2E_LN_CFG_DIS_SQ, x) +#define SD25G_LANE_LANE_2E_LN_CFG_DIS_SQ_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2E_LN_CFG_DIS_SQ, x) + +#define SD25G_LANE_LANE_2E_LN_CFG_PD_SQ BIT(2) +#define SD25G_LANE_LANE_2E_LN_CFG_PD_SQ_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2E_LN_CFG_PD_SQ, x) +#define SD25G_LANE_LANE_2E_LN_CFG_PD_SQ_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2E_LN_CFG_PD_SQ, x) + +#define SD25G_LANE_LANE_2E_LN_CFG_DIS_ALOS BIT(3) +#define SD25G_LANE_LANE_2E_LN_CFG_DIS_ALOS_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2E_LN_CFG_DIS_ALOS, x) +#define SD25G_LANE_LANE_2E_LN_CFG_DIS_ALOS_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2E_LN_CFG_DIS_ALOS, x) + +#define SD25G_LANE_LANE_2E_LN_CFG_RESETN_AGC BIT(4) +#define SD25G_LANE_LANE_2E_LN_CFG_RESETN_AGC_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2E_LN_CFG_RESETN_AGC, x) +#define SD25G_LANE_LANE_2E_LN_CFG_RESETN_AGC_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2E_LN_CFG_RESETN_AGC, x) + +#define SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG BIT(5) +#define SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG, x) +#define SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG, x) + +#define SD25G_LANE_LANE_2E_LN_CFG_PI_RSTN BIT(6) +#define SD25G_LANE_LANE_2E_LN_CFG_PI_RSTN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2E_LN_CFG_PI_RSTN, x) +#define SD25G_LANE_LANE_2E_LN_CFG_PI_RSTN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2E_LN_CFG_PI_RSTN, x) + +#define SD25G_LANE_LANE_2E_LN_CFG_CTLE_RSTN BIT(7) +#define SD25G_LANE_LANE_2E_LN_CFG_CTLE_RSTN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_2E_LN_CFG_CTLE_RSTN, x) +#define SD25G_LANE_LANE_2E_LN_CFG_CTLE_RSTN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_2E_LN_CFG_CTLE_RSTN, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_40 */ +#define SD25G_LANE_LANE_40(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 256, 0, 1, 4) + +#define SD25G_LANE_LANE_40_LN_R_TX_BIT_REVERSE BIT(0) +#define SD25G_LANE_LANE_40_LN_R_TX_BIT_REVERSE_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_40_LN_R_TX_BIT_REVERSE, x) +#define SD25G_LANE_LANE_40_LN_R_TX_BIT_REVERSE_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_40_LN_R_TX_BIT_REVERSE, x) + +#define SD25G_LANE_LANE_40_LN_R_TX_POL_INV BIT(1) +#define SD25G_LANE_LANE_40_LN_R_TX_POL_INV_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_40_LN_R_TX_POL_INV, x) +#define SD25G_LANE_LANE_40_LN_R_TX_POL_INV_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_40_LN_R_TX_POL_INV, x) + +#define SD25G_LANE_LANE_40_LN_R_RX_BIT_REVERSE BIT(2) +#define SD25G_LANE_LANE_40_LN_R_RX_BIT_REVERSE_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_40_LN_R_RX_BIT_REVERSE, x) +#define SD25G_LANE_LANE_40_LN_R_RX_BIT_REVERSE_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_40_LN_R_RX_BIT_REVERSE, x) + +#define SD25G_LANE_LANE_40_LN_R_RX_POL_INV BIT(3) +#define SD25G_LANE_LANE_40_LN_R_RX_POL_INV_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_40_LN_R_RX_POL_INV, x) +#define SD25G_LANE_LANE_40_LN_R_RX_POL_INV_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_40_LN_R_RX_POL_INV, x) + +#define SD25G_LANE_LANE_40_LN_R_CDR_RSTN BIT(4) +#define SD25G_LANE_LANE_40_LN_R_CDR_RSTN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_40_LN_R_CDR_RSTN, x) +#define SD25G_LANE_LANE_40_LN_R_CDR_RSTN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_40_LN_R_CDR_RSTN, x) + +#define SD25G_LANE_LANE_40_LN_R_DFE_RSTN BIT(5) +#define SD25G_LANE_LANE_40_LN_R_DFE_RSTN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_40_LN_R_DFE_RSTN, x) +#define SD25G_LANE_LANE_40_LN_R_DFE_RSTN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_40_LN_R_DFE_RSTN, x) + +#define SD25G_LANE_LANE_40_LN_R_CTLE_RSTN BIT(6) +#define SD25G_LANE_LANE_40_LN_R_CTLE_RSTN_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_40_LN_R_CTLE_RSTN, x) +#define SD25G_LANE_LANE_40_LN_R_CTLE_RSTN_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_40_LN_R_CTLE_RSTN, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_42 */ +#define SD25G_LANE_LANE_42(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 264, 0, 1, 4) + +#define SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0 GENMASK(7, 0) +#define SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0, x) +#define SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_43 */ +#define SD25G_LANE_LANE_43(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 268, 0, 1, 4) + +#define SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8 GENMASK(7, 0) +#define SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8, x) +#define SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_44 */ +#define SD25G_LANE_LANE_44(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 272, 0, 1, 4) + +#define SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0 GENMASK(7, 0) +#define SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0, x) +#define SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0, x) + +/* SD25G_TARGET:LANE_GRP_0:LANE_45 */ +#define SD25G_LANE_LANE_45(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 276, 0, 1, 4) + +#define SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8 GENMASK(7, 0) +#define SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8, x) +#define SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8, x) + +/* SD25G_TARGET:LANE_GRP_1:LANE_DE */ +#define SD25G_LANE_LANE_DE(t) __REG(TARGET_SD25G_LANE, t, 8, 1792, 0, 1, 128, 120, 0, 1, 4) + +#define SD25G_LANE_LANE_DE_LN_LOL_UDL BIT(0) +#define SD25G_LANE_LANE_DE_LN_LOL_UDL_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_DE_LN_LOL_UDL, x) +#define SD25G_LANE_LANE_DE_LN_LOL_UDL_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_DE_LN_LOL_UDL, x) + +#define SD25G_LANE_LANE_DE_LN_LOL BIT(1) +#define SD25G_LANE_LANE_DE_LN_LOL_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_DE_LN_LOL, x) +#define SD25G_LANE_LANE_DE_LN_LOL_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_DE_LN_LOL, x) + +#define SD25G_LANE_LANE_DE_LN_PMA2PCS_RXEI_FILTERED BIT(2) +#define SD25G_LANE_LANE_DE_LN_PMA2PCS_RXEI_FILTERED_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_DE_LN_PMA2PCS_RXEI_FILTERED, x) +#define SD25G_LANE_LANE_DE_LN_PMA2PCS_RXEI_FILTERED_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_DE_LN_PMA2PCS_RXEI_FILTERED, x) + +#define SD25G_LANE_LANE_DE_LN_PMA_RXEI BIT(3) +#define SD25G_LANE_LANE_DE_LN_PMA_RXEI_SET(x)\ + FIELD_PREP(SD25G_LANE_LANE_DE_LN_PMA_RXEI, x) +#define SD25G_LANE_LANE_DE_LN_PMA_RXEI_GET(x)\ + FIELD_GET(SD25G_LANE_LANE_DE_LN_PMA_RXEI, x) + +/* SD10G_LANE_TARGET:LANE_GRP_8:LANE_DF */ +#define SD6G_LANE_LANE_DF(t) __REG(TARGET_SD6G_LANE, t, 13, 832, 0, 1, 84, 60, 0, 1, 4) + +#define SD6G_LANE_LANE_DF_LOL_UDL BIT(0) +#define SD6G_LANE_LANE_DF_LOL_UDL_SET(x)\ + FIELD_PREP(SD6G_LANE_LANE_DF_LOL_UDL, x) +#define SD6G_LANE_LANE_DF_LOL_UDL_GET(x)\ + FIELD_GET(SD6G_LANE_LANE_DF_LOL_UDL, x) + +#define SD6G_LANE_LANE_DF_LOL BIT(1) +#define SD6G_LANE_LANE_DF_LOL_SET(x)\ + FIELD_PREP(SD6G_LANE_LANE_DF_LOL, x) +#define SD6G_LANE_LANE_DF_LOL_GET(x)\ + FIELD_GET(SD6G_LANE_LANE_DF_LOL, x) + +#define SD6G_LANE_LANE_DF_PMA2PCS_RXEI_FILTERED BIT(2) +#define SD6G_LANE_LANE_DF_PMA2PCS_RXEI_FILTERED_SET(x)\ + FIELD_PREP(SD6G_LANE_LANE_DF_PMA2PCS_RXEI_FILTERED, x) +#define SD6G_LANE_LANE_DF_PMA2PCS_RXEI_FILTERED_GET(x)\ + FIELD_GET(SD6G_LANE_LANE_DF_PMA2PCS_RXEI_FILTERED, x) + +#define SD6G_LANE_LANE_DF_SQUELCH BIT(3) +#define SD6G_LANE_LANE_DF_SQUELCH_SET(x)\ + FIELD_PREP(SD6G_LANE_LANE_DF_SQUELCH, x) +#define SD6G_LANE_LANE_DF_SQUELCH_GET(x)\ + FIELD_GET(SD6G_LANE_LANE_DF_SQUELCH, x) + +/* SD10G_CMU_TARGET:CMU_GRP_0:CMU_00 */ +#define SD_CMU_CMU_00(t) __REG(TARGET_SD_CMU, t, 14, 0, 0, 1, 20, 0, 0, 1, 4) + +#define SD_CMU_CMU_00_R_HWT_SIMULATION_MODE BIT(0) +#define SD_CMU_CMU_00_R_HWT_SIMULATION_MODE_SET(x)\ + FIELD_PREP(SD_CMU_CMU_00_R_HWT_SIMULATION_MODE, x) +#define SD_CMU_CMU_00_R_HWT_SIMULATION_MODE_GET(x)\ + FIELD_GET(SD_CMU_CMU_00_R_HWT_SIMULATION_MODE, x) + +#define SD_CMU_CMU_00_CFG_PLL_LOL_SET BIT(1) +#define SD_CMU_CMU_00_CFG_PLL_LOL_SET_SET(x)\ + FIELD_PREP(SD_CMU_CMU_00_CFG_PLL_LOL_SET, x) +#define SD_CMU_CMU_00_CFG_PLL_LOL_SET_GET(x)\ + FIELD_GET(SD_CMU_CMU_00_CFG_PLL_LOL_SET, x) + +#define SD_CMU_CMU_00_CFG_PLL_LOS_SET BIT(2) +#define SD_CMU_CMU_00_CFG_PLL_LOS_SET_SET(x)\ + FIELD_PREP(SD_CMU_CMU_00_CFG_PLL_LOS_SET, x) +#define SD_CMU_CMU_00_CFG_PLL_LOS_SET_GET(x)\ + FIELD_GET(SD_CMU_CMU_00_CFG_PLL_LOS_SET, x) + +#define SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0 GENMASK(5, 4) +#define SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0_SET(x)\ + FIELD_PREP(SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0, x) +#define SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0_GET(x)\ + FIELD_GET(SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0, x) + +/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_05 */ +#define SD_CMU_CMU_05(t) __REG(TARGET_SD_CMU, t, 14, 20, 0, 1, 72, 0, 0, 1, 4) + +#define SD_CMU_CMU_05_CFG_REFCK_TERM_EN BIT(0) +#define SD_CMU_CMU_05_CFG_REFCK_TERM_EN_SET(x)\ + FIELD_PREP(SD_CMU_CMU_05_CFG_REFCK_TERM_EN, x) +#define SD_CMU_CMU_05_CFG_REFCK_TERM_EN_GET(x)\ + FIELD_GET(SD_CMU_CMU_05_CFG_REFCK_TERM_EN, x) + +#define SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0 GENMASK(5, 4) +#define SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0_SET(x)\ + FIELD_PREP(SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0, x) +#define SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0_GET(x)\ + FIELD_GET(SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0, x) + +/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_09 */ +#define SD_CMU_CMU_09(t) __REG(TARGET_SD_CMU, t, 14, 20, 0, 1, 72, 16, 0, 1, 4) + +#define SD_CMU_CMU_09_CFG_EN_TX_CK_UP BIT(0) +#define SD_CMU_CMU_09_CFG_EN_TX_CK_UP_SET(x)\ + FIELD_PREP(SD_CMU_CMU_09_CFG_EN_TX_CK_UP, x) +#define SD_CMU_CMU_09_CFG_EN_TX_CK_UP_GET(x)\ + FIELD_GET(SD_CMU_CMU_09_CFG_EN_TX_CK_UP, x) + +#define SD_CMU_CMU_09_CFG_EN_TX_CK_DN BIT(1) +#define SD_CMU_CMU_09_CFG_EN_TX_CK_DN_SET(x)\ + FIELD_PREP(SD_CMU_CMU_09_CFG_EN_TX_CK_DN, x) +#define SD_CMU_CMU_09_CFG_EN_TX_CK_DN_GET(x)\ + FIELD_GET(SD_CMU_CMU_09_CFG_EN_TX_CK_DN, x) + +#define SD_CMU_CMU_09_CFG_SW_8G BIT(4) +#define SD_CMU_CMU_09_CFG_SW_8G_SET(x)\ + FIELD_PREP(SD_CMU_CMU_09_CFG_SW_8G, x) +#define SD_CMU_CMU_09_CFG_SW_8G_GET(x)\ + FIELD_GET(SD_CMU_CMU_09_CFG_SW_8G, x) + +#define SD_CMU_CMU_09_CFG_SW_10G BIT(5) +#define SD_CMU_CMU_09_CFG_SW_10G_SET(x)\ + FIELD_PREP(SD_CMU_CMU_09_CFG_SW_10G, x) +#define SD_CMU_CMU_09_CFG_SW_10G_GET(x)\ + FIELD_GET(SD_CMU_CMU_09_CFG_SW_10G, x) + +/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_0D */ +#define SD_CMU_CMU_0D(t) __REG(TARGET_SD_CMU, t, 14, 20, 0, 1, 72, 32, 0, 1, 4) + +#define SD_CMU_CMU_0D_CFG_PD_DIV64 BIT(0) +#define SD_CMU_CMU_0D_CFG_PD_DIV64_SET(x)\ + FIELD_PREP(SD_CMU_CMU_0D_CFG_PD_DIV64, x) +#define SD_CMU_CMU_0D_CFG_PD_DIV64_GET(x)\ + FIELD_GET(SD_CMU_CMU_0D_CFG_PD_DIV64, x) + +#define SD_CMU_CMU_0D_CFG_PD_DIV66 BIT(1) +#define SD_CMU_CMU_0D_CFG_PD_DIV66_SET(x)\ + FIELD_PREP(SD_CMU_CMU_0D_CFG_PD_DIV66, x) +#define SD_CMU_CMU_0D_CFG_PD_DIV66_GET(x)\ + FIELD_GET(SD_CMU_CMU_0D_CFG_PD_DIV66, x) + +#define SD_CMU_CMU_0D_CFG_PMA_TX_CK_PD BIT(2) +#define SD_CMU_CMU_0D_CFG_PMA_TX_CK_PD_SET(x)\ + FIELD_PREP(SD_CMU_CMU_0D_CFG_PMA_TX_CK_PD, x) +#define SD_CMU_CMU_0D_CFG_PMA_TX_CK_PD_GET(x)\ + FIELD_GET(SD_CMU_CMU_0D_CFG_PMA_TX_CK_PD, x) + +#define SD_CMU_CMU_0D_CFG_JC_BYP BIT(3) +#define SD_CMU_CMU_0D_CFG_JC_BYP_SET(x)\ + FIELD_PREP(SD_CMU_CMU_0D_CFG_JC_BYP, x) +#define SD_CMU_CMU_0D_CFG_JC_BYP_GET(x)\ + FIELD_GET(SD_CMU_CMU_0D_CFG_JC_BYP, x) + +#define SD_CMU_CMU_0D_CFG_REFCK_PD BIT(4) +#define SD_CMU_CMU_0D_CFG_REFCK_PD_SET(x)\ + FIELD_PREP(SD_CMU_CMU_0D_CFG_REFCK_PD, x) +#define SD_CMU_CMU_0D_CFG_REFCK_PD_GET(x)\ + FIELD_GET(SD_CMU_CMU_0D_CFG_REFCK_PD, x) + +/* SD10G_CMU_TARGET:CMU_GRP_3:CMU_1B */ +#define SD_CMU_CMU_1B(t) __REG(TARGET_SD_CMU, t, 14, 104, 0, 1, 20, 4, 0, 1, 4) + +#define SD_CMU_CMU_1B_CFG_RESERVE_7_0 GENMASK(7, 0) +#define SD_CMU_CMU_1B_CFG_RESERVE_7_0_SET(x)\ + FIELD_PREP(SD_CMU_CMU_1B_CFG_RESERVE_7_0, x) +#define SD_CMU_CMU_1B_CFG_RESERVE_7_0_GET(x)\ + FIELD_GET(SD_CMU_CMU_1B_CFG_RESERVE_7_0, x) + +/* SD10G_CMU_TARGET:CMU_GRP_4:CMU_1F */ +#define SD_CMU_CMU_1F(t) __REG(TARGET_SD_CMU, t, 14, 124, 0, 1, 68, 0, 0, 1, 4) + +#define SD_CMU_CMU_1F_CFG_BIAS_DN_EN BIT(0) +#define SD_CMU_CMU_1F_CFG_BIAS_DN_EN_SET(x)\ + FIELD_PREP(SD_CMU_CMU_1F_CFG_BIAS_DN_EN, x) +#define SD_CMU_CMU_1F_CFG_BIAS_DN_EN_GET(x)\ + FIELD_GET(SD_CMU_CMU_1F_CFG_BIAS_DN_EN, x) + +#define SD_CMU_CMU_1F_CFG_BIAS_UP_EN BIT(1) +#define SD_CMU_CMU_1F_CFG_BIAS_UP_EN_SET(x)\ + FIELD_PREP(SD_CMU_CMU_1F_CFG_BIAS_UP_EN, x) +#define SD_CMU_CMU_1F_CFG_BIAS_UP_EN_GET(x)\ + FIELD_GET(SD_CMU_CMU_1F_CFG_BIAS_UP_EN, x) + +#define SD_CMU_CMU_1F_CFG_IC2IP_N BIT(2) +#define SD_CMU_CMU_1F_CFG_IC2IP_N_SET(x)\ + FIELD_PREP(SD_CMU_CMU_1F_CFG_IC2IP_N, x) +#define SD_CMU_CMU_1F_CFG_IC2IP_N_GET(x)\ + FIELD_GET(SD_CMU_CMU_1F_CFG_IC2IP_N, x) + +#define SD_CMU_CMU_1F_CFG_VTUNE_SEL BIT(3) +#define SD_CMU_CMU_1F_CFG_VTUNE_SEL_SET(x)\ + FIELD_PREP(SD_CMU_CMU_1F_CFG_VTUNE_SEL, x) +#define SD_CMU_CMU_1F_CFG_VTUNE_SEL_GET(x)\ + FIELD_GET(SD_CMU_CMU_1F_CFG_VTUNE_SEL, x) + +/* SD10G_CMU_TARGET:CMU_GRP_5:CMU_30 */ +#define SD_CMU_CMU_30(t) __REG(TARGET_SD_CMU, t, 14, 192, 0, 1, 72, 0, 0, 1, 4) + +#define SD_CMU_CMU_30_R_PLL_DLOL_EN BIT(0) +#define SD_CMU_CMU_30_R_PLL_DLOL_EN_SET(x)\ + FIELD_PREP(SD_CMU_CMU_30_R_PLL_DLOL_EN, x) +#define SD_CMU_CMU_30_R_PLL_DLOL_EN_GET(x)\ + FIELD_GET(SD_CMU_CMU_30_R_PLL_DLOL_EN, x) + +/* SD10G_CMU_TARGET:CMU_GRP_6:CMU_44 */ +#define SD_CMU_CMU_44(t) __REG(TARGET_SD_CMU, t, 14, 264, 0, 1, 632, 8, 0, 1, 4) + +#define SD_CMU_CMU_44_R_PLL_RSTN BIT(0) +#define SD_CMU_CMU_44_R_PLL_RSTN_SET(x)\ + FIELD_PREP(SD_CMU_CMU_44_R_PLL_RSTN, x) +#define SD_CMU_CMU_44_R_PLL_RSTN_GET(x)\ + FIELD_GET(SD_CMU_CMU_44_R_PLL_RSTN, x) + +#define SD_CMU_CMU_44_R_CK_RESETB BIT(1) +#define SD_CMU_CMU_44_R_CK_RESETB_SET(x)\ + FIELD_PREP(SD_CMU_CMU_44_R_CK_RESETB, x) +#define SD_CMU_CMU_44_R_CK_RESETB_GET(x)\ + FIELD_GET(SD_CMU_CMU_44_R_CK_RESETB, x) + +/* SD10G_CMU_TARGET:CMU_GRP_6:CMU_45 */ +#define SD_CMU_CMU_45(t) __REG(TARGET_SD_CMU, t, 14, 264, 0, 1, 632, 12, 0, 1, 4) + +#define SD_CMU_CMU_45_R_EN_RATECHG_CTRL BIT(0) +#define SD_CMU_CMU_45_R_EN_RATECHG_CTRL_SET(x)\ + FIELD_PREP(SD_CMU_CMU_45_R_EN_RATECHG_CTRL, x) +#define SD_CMU_CMU_45_R_EN_RATECHG_CTRL_GET(x)\ + FIELD_GET(SD_CMU_CMU_45_R_EN_RATECHG_CTRL, x) + +#define SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT BIT(1) +#define SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT_SET(x)\ + FIELD_PREP(SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT, x) +#define SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT_GET(x)\ + FIELD_GET(SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT, x) + +#define SD_CMU_CMU_45_RESERVED BIT(2) +#define SD_CMU_CMU_45_RESERVED_SET(x)\ + FIELD_PREP(SD_CMU_CMU_45_RESERVED, x) +#define SD_CMU_CMU_45_RESERVED_GET(x)\ + FIELD_GET(SD_CMU_CMU_45_RESERVED, x) + +#define SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT BIT(3) +#define SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT_SET(x)\ + FIELD_PREP(SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT, x) +#define SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT_GET(x)\ + FIELD_GET(SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT, x) + +#define SD_CMU_CMU_45_RESERVED_2 BIT(4) +#define SD_CMU_CMU_45_RESERVED_2_SET(x)\ + FIELD_PREP(SD_CMU_CMU_45_RESERVED_2, x) +#define SD_CMU_CMU_45_RESERVED_2_GET(x)\ + FIELD_GET(SD_CMU_CMU_45_RESERVED_2, x) + +#define SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT BIT(5) +#define SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT_SET(x)\ + FIELD_PREP(SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT, x) +#define SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT_GET(x)\ + FIELD_GET(SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT, x) + +#define SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT BIT(6) +#define SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT_SET(x)\ + FIELD_PREP(SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT, x) +#define SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT_GET(x)\ + FIELD_GET(SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT, x) + +#define SD_CMU_CMU_45_R_AUTO_RST_TREE_PD_MAN BIT(7) +#define SD_CMU_CMU_45_R_AUTO_RST_TREE_PD_MAN_SET(x)\ + FIELD_PREP(SD_CMU_CMU_45_R_AUTO_RST_TREE_PD_MAN, x) +#define SD_CMU_CMU_45_R_AUTO_RST_TREE_PD_MAN_GET(x)\ + FIELD_GET(SD_CMU_CMU_45_R_AUTO_RST_TREE_PD_MAN, x) + +/* SD10G_CMU_TARGET:CMU_GRP_6:CMU_47 */ +#define SD_CMU_CMU_47(t) __REG(TARGET_SD_CMU, t, 14, 264, 0, 1, 632, 20, 0, 1, 4) + +#define SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0 GENMASK(4, 0) +#define SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0_SET(x)\ + FIELD_PREP(SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0, x) +#define SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0_GET(x)\ + FIELD_GET(SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0, x) + +/* SD10G_CMU_TARGET:CMU_GRP_7:CMU_E0 */ +#define SD_CMU_CMU_E0(t) __REG(TARGET_SD_CMU, t, 14, 896, 0, 1, 8, 0, 0, 1, 4) + +#define SD_CMU_CMU_E0_READ_VCO_CTUNE_3_0 GENMASK(3, 0) +#define SD_CMU_CMU_E0_READ_VCO_CTUNE_3_0_SET(x)\ + FIELD_PREP(SD_CMU_CMU_E0_READ_VCO_CTUNE_3_0, x) +#define SD_CMU_CMU_E0_READ_VCO_CTUNE_3_0_GET(x)\ + FIELD_GET(SD_CMU_CMU_E0_READ_VCO_CTUNE_3_0, x) + +#define SD_CMU_CMU_E0_PLL_LOL_UDL BIT(4) +#define SD_CMU_CMU_E0_PLL_LOL_UDL_SET(x)\ + FIELD_PREP(SD_CMU_CMU_E0_PLL_LOL_UDL, x) +#define SD_CMU_CMU_E0_PLL_LOL_UDL_GET(x)\ + FIELD_GET(SD_CMU_CMU_E0_PLL_LOL_UDL, x) + +/* SD_CMU_TARGET:SD_CMU_CFG:SD_CMU_CFG */ +#define SD_CMU_CFG_SD_CMU_CFG(t) __REG(TARGET_SD_CMU_CFG, t, 14, 0, 0, 1, 8, 0, 0, 1, 4) + +#define SD_CMU_CFG_SD_CMU_CFG_CMU_RST BIT(0) +#define SD_CMU_CFG_SD_CMU_CFG_CMU_RST_SET(x)\ + FIELD_PREP(SD_CMU_CFG_SD_CMU_CFG_CMU_RST, x) +#define SD_CMU_CFG_SD_CMU_CFG_CMU_RST_GET(x)\ + FIELD_GET(SD_CMU_CFG_SD_CMU_CFG_CMU_RST, x) + +#define SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST BIT(1) +#define SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST_SET(x)\ + FIELD_PREP(SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST, x) +#define SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST_GET(x)\ + FIELD_GET(SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST, x) + +/* SD_LANE_TARGET:SD_RESET:SD_SER_RST */ +#define SD_LANE_SD_SER_RST(t) __REG(TARGET_SD_LANE, t, 25, 0, 0, 1, 8, 0, 0, 1, 4) + +#define SD_LANE_SD_SER_RST_SER_RST BIT(0) +#define SD_LANE_SD_SER_RST_SER_RST_SET(x)\ + FIELD_PREP(SD_LANE_SD_SER_RST_SER_RST, x) +#define SD_LANE_SD_SER_RST_SER_RST_GET(x)\ + FIELD_GET(SD_LANE_SD_SER_RST_SER_RST, x) + +/* SD_LANE_TARGET:SD_RESET:SD_DES_RST */ +#define SD_LANE_SD_DES_RST(t) __REG(TARGET_SD_LANE, t, 25, 0, 0, 1, 8, 4, 0, 1, 4) + +#define SD_LANE_SD_DES_RST_DES_RST BIT(0) +#define SD_LANE_SD_DES_RST_DES_RST_SET(x)\ + FIELD_PREP(SD_LANE_SD_DES_RST_DES_RST, x) +#define SD_LANE_SD_DES_RST_DES_RST_GET(x)\ + FIELD_GET(SD_LANE_SD_DES_RST_DES_RST, x) + +/* SD_LANE_TARGET:SD_LANE_CFG_STAT:SD_LANE_CFG */ +#define SD_LANE_SD_LANE_CFG(t) __REG(TARGET_SD_LANE, t, 25, 8, 0, 1, 8, 0, 0, 1, 4) + +#define SD_LANE_SD_LANE_CFG_MACRO_RST BIT(0) +#define SD_LANE_SD_LANE_CFG_MACRO_RST_SET(x)\ + FIELD_PREP(SD_LANE_SD_LANE_CFG_MACRO_RST, x) +#define SD_LANE_SD_LANE_CFG_MACRO_RST_GET(x)\ + FIELD_GET(SD_LANE_SD_LANE_CFG_MACRO_RST, x) + +#define SD_LANE_SD_LANE_CFG_EXT_CFG_RST BIT(1) +#define SD_LANE_SD_LANE_CFG_EXT_CFG_RST_SET(x)\ + FIELD_PREP(SD_LANE_SD_LANE_CFG_EXT_CFG_RST, x) +#define SD_LANE_SD_LANE_CFG_EXT_CFG_RST_GET(x)\ + FIELD_GET(SD_LANE_SD_LANE_CFG_EXT_CFG_RST, x) + +#define SD_LANE_SD_LANE_CFG_TX_REF_SEL GENMASK(5, 4) +#define SD_LANE_SD_LANE_CFG_TX_REF_SEL_SET(x)\ + FIELD_PREP(SD_LANE_SD_LANE_CFG_TX_REF_SEL, x) +#define SD_LANE_SD_LANE_CFG_TX_REF_SEL_GET(x)\ + FIELD_GET(SD_LANE_SD_LANE_CFG_TX_REF_SEL, x) + +#define SD_LANE_SD_LANE_CFG_RX_REF_SEL GENMASK(7, 6) +#define SD_LANE_SD_LANE_CFG_RX_REF_SEL_SET(x)\ + FIELD_PREP(SD_LANE_SD_LANE_CFG_RX_REF_SEL, x) +#define SD_LANE_SD_LANE_CFG_RX_REF_SEL_GET(x)\ + FIELD_GET(SD_LANE_SD_LANE_CFG_RX_REF_SEL, x) + +#define SD_LANE_SD_LANE_CFG_LANE_RST BIT(8) +#define SD_LANE_SD_LANE_CFG_LANE_RST_SET(x)\ + FIELD_PREP(SD_LANE_SD_LANE_CFG_LANE_RST, x) +#define SD_LANE_SD_LANE_CFG_LANE_RST_GET(x)\ + FIELD_GET(SD_LANE_SD_LANE_CFG_LANE_RST, x) + +#define SD_LANE_SD_LANE_CFG_LANE_TX_RST BIT(9) +#define SD_LANE_SD_LANE_CFG_LANE_TX_RST_SET(x)\ + FIELD_PREP(SD_LANE_SD_LANE_CFG_LANE_TX_RST, x) +#define SD_LANE_SD_LANE_CFG_LANE_TX_RST_GET(x)\ + FIELD_GET(SD_LANE_SD_LANE_CFG_LANE_TX_RST, x) + +#define SD_LANE_SD_LANE_CFG_LANE_RX_RST BIT(10) +#define SD_LANE_SD_LANE_CFG_LANE_RX_RST_SET(x)\ + FIELD_PREP(SD_LANE_SD_LANE_CFG_LANE_RX_RST, x) +#define SD_LANE_SD_LANE_CFG_LANE_RX_RST_GET(x)\ + FIELD_GET(SD_LANE_SD_LANE_CFG_LANE_RX_RST, x) + +/* SD_LANE_TARGET:SD_LANE_CFG_STAT:SD_LANE_STAT */ +#define SD_LANE_SD_LANE_STAT(t) __REG(TARGET_SD_LANE, t, 25, 8, 0, 1, 8, 4, 0, 1, 4) + +#define SD_LANE_SD_LANE_STAT_PMA_RST_DONE BIT(0) +#define SD_LANE_SD_LANE_STAT_PMA_RST_DONE_SET(x)\ + FIELD_PREP(SD_LANE_SD_LANE_STAT_PMA_RST_DONE, x) +#define SD_LANE_SD_LANE_STAT_PMA_RST_DONE_GET(x)\ + FIELD_GET(SD_LANE_SD_LANE_STAT_PMA_RST_DONE, x) + +#define SD_LANE_SD_LANE_STAT_DFE_RST_DONE BIT(1) +#define SD_LANE_SD_LANE_STAT_DFE_RST_DONE_SET(x)\ + FIELD_PREP(SD_LANE_SD_LANE_STAT_DFE_RST_DONE, x) +#define SD_LANE_SD_LANE_STAT_DFE_RST_DONE_GET(x)\ + FIELD_GET(SD_LANE_SD_LANE_STAT_DFE_RST_DONE, x) + +#define SD_LANE_SD_LANE_STAT_DBG_OBS GENMASK(31, 16) +#define SD_LANE_SD_LANE_STAT_DBG_OBS_SET(x)\ + FIELD_PREP(SD_LANE_SD_LANE_STAT_DBG_OBS, x) +#define SD_LANE_SD_LANE_STAT_DBG_OBS_GET(x)\ + FIELD_GET(SD_LANE_SD_LANE_STAT_DBG_OBS, x) + +/* SD_LANE_TARGET:CFG_STAT_FX100:MISC */ +#define SD_LANE_MISC(t) __REG(TARGET_SD_LANE, t, 25, 56, 0, 1, 56, 0, 0, 1, 4) + +#define SD_LANE_MISC_SD_125_RST_DIS BIT(0) +#define SD_LANE_MISC_SD_125_RST_DIS_SET(x)\ + FIELD_PREP(SD_LANE_MISC_SD_125_RST_DIS, x) +#define SD_LANE_MISC_SD_125_RST_DIS_GET(x)\ + FIELD_GET(SD_LANE_MISC_SD_125_RST_DIS, x) + +#define SD_LANE_MISC_RX_ENA BIT(1) +#define SD_LANE_MISC_RX_ENA_SET(x)\ + FIELD_PREP(SD_LANE_MISC_RX_ENA, x) +#define SD_LANE_MISC_RX_ENA_GET(x)\ + FIELD_GET(SD_LANE_MISC_RX_ENA, x) + +#define SD_LANE_MISC_MUX_ENA BIT(2) +#define SD_LANE_MISC_MUX_ENA_SET(x)\ + FIELD_PREP(SD_LANE_MISC_MUX_ENA, x) +#define SD_LANE_MISC_MUX_ENA_GET(x)\ + FIELD_GET(SD_LANE_MISC_MUX_ENA, x) + +#define SD_LANE_MISC_CORE_CLK_FREQ GENMASK(5, 4) +#define SD_LANE_MISC_CORE_CLK_FREQ_SET(x)\ + FIELD_PREP(SD_LANE_MISC_CORE_CLK_FREQ, x) +#define SD_LANE_MISC_CORE_CLK_FREQ_GET(x)\ + FIELD_GET(SD_LANE_MISC_CORE_CLK_FREQ, x) + +/* SD_LANE_TARGET:CFG_STAT_FX100:M_STAT_MISC */ +#define SD_LANE_M_STAT_MISC(t) __REG(TARGET_SD_LANE, t, 25, 56, 0, 1, 56, 36, 0, 1, 4) + +#define SD_LANE_M_STAT_MISC_M_RIS_EDGE_PTR_ADJ_SUM GENMASK(21, 0) +#define SD_LANE_M_STAT_MISC_M_RIS_EDGE_PTR_ADJ_SUM_SET(x)\ + FIELD_PREP(SD_LANE_M_STAT_MISC_M_RIS_EDGE_PTR_ADJ_SUM, x) +#define SD_LANE_M_STAT_MISC_M_RIS_EDGE_PTR_ADJ_SUM_GET(x)\ + FIELD_GET(SD_LANE_M_STAT_MISC_M_RIS_EDGE_PTR_ADJ_SUM, x) + +#define SD_LANE_M_STAT_MISC_M_LOCK_CNT GENMASK(31, 24) +#define SD_LANE_M_STAT_MISC_M_LOCK_CNT_SET(x)\ + FIELD_PREP(SD_LANE_M_STAT_MISC_M_LOCK_CNT, x) +#define SD_LANE_M_STAT_MISC_M_LOCK_CNT_GET(x)\ + FIELD_GET(SD_LANE_M_STAT_MISC_M_LOCK_CNT, x) + +/* SD25G_CFG_TARGET:SD_RESET:SD_SER_RST */ +#define SD_LANE_25G_SD_SER_RST(t) __REG(TARGET_SD_LANE_25G, t, 8, 0, 0, 1, 8, 0, 0, 1, 4) + +#define SD_LANE_25G_SD_SER_RST_SER_RST BIT(0) +#define SD_LANE_25G_SD_SER_RST_SER_RST_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_SER_RST_SER_RST, x) +#define SD_LANE_25G_SD_SER_RST_SER_RST_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_SER_RST_SER_RST, x) + +/* SD25G_CFG_TARGET:SD_RESET:SD_DES_RST */ +#define SD_LANE_25G_SD_DES_RST(t) __REG(TARGET_SD_LANE_25G, t, 8, 0, 0, 1, 8, 4, 0, 1, 4) + +#define SD_LANE_25G_SD_DES_RST_DES_RST BIT(0) +#define SD_LANE_25G_SD_DES_RST_DES_RST_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_DES_RST_DES_RST, x) +#define SD_LANE_25G_SD_DES_RST_DES_RST_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_DES_RST_DES_RST, x) + +/* SD25G_CFG_TARGET:SD_LANE_CFG_STAT:SD_LANE_CFG */ +#define SD_LANE_25G_SD_LANE_CFG(t) __REG(TARGET_SD_LANE_25G, t, 8, 8, 0, 1, 12, 0, 0, 1, 4) + +#define SD_LANE_25G_SD_LANE_CFG_MACRO_RST BIT(0) +#define SD_LANE_25G_SD_LANE_CFG_MACRO_RST_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_MACRO_RST, x) +#define SD_LANE_25G_SD_LANE_CFG_MACRO_RST_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_MACRO_RST, x) + +#define SD_LANE_25G_SD_LANE_CFG_EXT_CFG_RST BIT(1) +#define SD_LANE_25G_SD_LANE_CFG_EXT_CFG_RST_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_EXT_CFG_RST, x) +#define SD_LANE_25G_SD_LANE_CFG_EXT_CFG_RST_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_EXT_CFG_RST, x) + +#define SD_LANE_25G_SD_LANE_CFG_HWT_MULTI_LANE_MODE BIT(4) +#define SD_LANE_25G_SD_LANE_CFG_HWT_MULTI_LANE_MODE_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_HWT_MULTI_LANE_MODE, x) +#define SD_LANE_25G_SD_LANE_CFG_HWT_MULTI_LANE_MODE_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_HWT_MULTI_LANE_MODE, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_PHYMODE GENMASK(7, 5) +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_PHYMODE_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS2PMA_PHYMODE, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_PHYMODE_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS2PMA_PHYMODE, x) + +#define SD_LANE_25G_SD_LANE_CFG_LANE_RST BIT(8) +#define SD_LANE_25G_SD_LANE_CFG_LANE_RST_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_LANE_RST, x) +#define SD_LANE_25G_SD_LANE_CFG_LANE_RST_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_LANE_RST, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_ADV BIT(9) +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_ADV_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS_EN_ADV, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_ADV_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS_EN_ADV, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_MAIN BIT(10) +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_MAIN_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS_EN_MAIN, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_MAIN_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS_EN_MAIN, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_DLY BIT(11) +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_DLY_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS_EN_DLY, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_DLY_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS_EN_DLY, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS_TAP_ADV GENMASK(15, 12) +#define SD_LANE_25G_SD_LANE_CFG_PCS_TAP_ADV_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS_TAP_ADV, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS_TAP_ADV_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS_TAP_ADV, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS_TAP_MAIN BIT(16) +#define SD_LANE_25G_SD_LANE_CFG_PCS_TAP_MAIN_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS_TAP_MAIN, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS_TAP_MAIN_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS_TAP_MAIN, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS_TAP_DLY GENMASK(21, 17) +#define SD_LANE_25G_SD_LANE_CFG_PCS_TAP_DLY_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS_TAP_DLY, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS_TAP_DLY_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS_TAP_DLY, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS_ISCAN_EN BIT(22) +#define SD_LANE_25G_SD_LANE_CFG_PCS_ISCAN_EN_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS_ISCAN_EN, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS_ISCAN_EN_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS_ISCAN_EN, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_FAST_ISCAN BIT(23) +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_FAST_ISCAN_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS_EN_FAST_ISCAN, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS_EN_FAST_ISCAN_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS_EN_FAST_ISCAN, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXSWING BIT(24) +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXSWING_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXSWING, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXSWING_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXSWING, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXEI BIT(25) +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXEI_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXEI, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXEI_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXEI, x) + +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXMARGIN GENMASK(28, 26) +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXMARGIN_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXMARGIN, x) +#define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXMARGIN_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXMARGIN, x) + +/* SD25G_CFG_TARGET:SD_LANE_CFG_STAT:SD_LANE_CFG2 */ +#define SD_LANE_25G_SD_LANE_CFG2(t) __REG(TARGET_SD_LANE_25G, t, 8, 8, 0, 1, 12, 4, 0, 1, 4) + +#define SD_LANE_25G_SD_LANE_CFG2_DATA_WIDTH_SEL GENMASK(2, 0) +#define SD_LANE_25G_SD_LANE_CFG2_DATA_WIDTH_SEL_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_DATA_WIDTH_SEL, x) +#define SD_LANE_25G_SD_LANE_CFG2_DATA_WIDTH_SEL_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_DATA_WIDTH_SEL, x) + +#define SD_LANE_25G_SD_LANE_CFG2_PMA_TXCK_SEL GENMASK(5, 3) +#define SD_LANE_25G_SD_LANE_CFG2_PMA_TXCK_SEL_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_PMA_TXCK_SEL, x) +#define SD_LANE_25G_SD_LANE_CFG2_PMA_TXCK_SEL_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_PMA_TXCK_SEL, x) + +#define SD_LANE_25G_SD_LANE_CFG2_PMA_RXDIV_SEL GENMASK(8, 6) +#define SD_LANE_25G_SD_LANE_CFG2_PMA_RXDIV_SEL_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_PMA_RXDIV_SEL, x) +#define SD_LANE_25G_SD_LANE_CFG2_PMA_RXDIV_SEL_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_PMA_RXDIV_SEL, x) + +#define SD_LANE_25G_SD_LANE_CFG2_PCS2PMA_TX_SPEED GENMASK(10, 9) +#define SD_LANE_25G_SD_LANE_CFG2_PCS2PMA_TX_SPEED_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_PCS2PMA_TX_SPEED, x) +#define SD_LANE_25G_SD_LANE_CFG2_PCS2PMA_TX_SPEED_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_PCS2PMA_TX_SPEED, x) + +#define SD_LANE_25G_SD_LANE_CFG2_TXFIFO_CK_DIV GENMASK(13, 11) +#define SD_LANE_25G_SD_LANE_CFG2_TXFIFO_CK_DIV_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_TXFIFO_CK_DIV, x) +#define SD_LANE_25G_SD_LANE_CFG2_TXFIFO_CK_DIV_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_TXFIFO_CK_DIV, x) + +#define SD_LANE_25G_SD_LANE_CFG2_RXFIFO_CK_DIV GENMASK(16, 14) +#define SD_LANE_25G_SD_LANE_CFG2_RXFIFO_CK_DIV_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_RXFIFO_CK_DIV, x) +#define SD_LANE_25G_SD_LANE_CFG2_RXFIFO_CK_DIV_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_RXFIFO_CK_DIV, x) + +#define SD_LANE_25G_SD_LANE_CFG2_HWT_VCO_DIV_SEL GENMASK(19, 17) +#define SD_LANE_25G_SD_LANE_CFG2_HWT_VCO_DIV_SEL_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_HWT_VCO_DIV_SEL, x) +#define SD_LANE_25G_SD_LANE_CFG2_HWT_VCO_DIV_SEL_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_HWT_VCO_DIV_SEL, x) + +#define SD_LANE_25G_SD_LANE_CFG2_HWT_CFG_SEL_DIV GENMASK(23, 20) +#define SD_LANE_25G_SD_LANE_CFG2_HWT_CFG_SEL_DIV_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_HWT_CFG_SEL_DIV, x) +#define SD_LANE_25G_SD_LANE_CFG2_HWT_CFG_SEL_DIV_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_HWT_CFG_SEL_DIV, x) + +#define SD_LANE_25G_SD_LANE_CFG2_HWT_PRE_DIVSEL GENMASK(25, 24) +#define SD_LANE_25G_SD_LANE_CFG2_HWT_PRE_DIVSEL_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_HWT_PRE_DIVSEL, x) +#define SD_LANE_25G_SD_LANE_CFG2_HWT_PRE_DIVSEL_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_HWT_PRE_DIVSEL, x) + +#define SD_LANE_25G_SD_LANE_CFG2_TXRATE_SEL GENMASK(28, 26) +#define SD_LANE_25G_SD_LANE_CFG2_TXRATE_SEL_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_TXRATE_SEL, x) +#define SD_LANE_25G_SD_LANE_CFG2_TXRATE_SEL_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_TXRATE_SEL, x) + +#define SD_LANE_25G_SD_LANE_CFG2_RXRATE_SEL GENMASK(31, 29) +#define SD_LANE_25G_SD_LANE_CFG2_RXRATE_SEL_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_CFG2_RXRATE_SEL, x) +#define SD_LANE_25G_SD_LANE_CFG2_RXRATE_SEL_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_RXRATE_SEL, x) + +/* SD25G_CFG_TARGET:SD_LANE_CFG_STAT:SD_LANE_STAT */ +#define SD_LANE_25G_SD_LANE_STAT(t) __REG(TARGET_SD_LANE_25G, t, 8, 8, 0, 1, 12, 8, 0, 1, 4) + +#define SD_LANE_25G_SD_LANE_STAT_PMA_RST_DONE BIT(0) +#define SD_LANE_25G_SD_LANE_STAT_PMA_RST_DONE_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_STAT_PMA_RST_DONE, x) +#define SD_LANE_25G_SD_LANE_STAT_PMA_RST_DONE_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_STAT_PMA_RST_DONE, x) + +#define SD_LANE_25G_SD_LANE_STAT_LANE_RST_DONE BIT(1) +#define SD_LANE_25G_SD_LANE_STAT_LANE_RST_DONE_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_STAT_LANE_RST_DONE, x) +#define SD_LANE_25G_SD_LANE_STAT_LANE_RST_DONE_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_STAT_LANE_RST_DONE, x) + +#define SD_LANE_25G_SD_LANE_STAT_DBG_OBS GENMASK(31, 16) +#define SD_LANE_25G_SD_LANE_STAT_DBG_OBS_SET(x)\ + FIELD_PREP(SD_LANE_25G_SD_LANE_STAT_DBG_OBS, x) +#define SD_LANE_25G_SD_LANE_STAT_DBG_OBS_GET(x)\ + FIELD_GET(SD_LANE_25G_SD_LANE_STAT_DBG_OBS, x) + +#endif /* _SPARX5_SERDES_REGS_H_ */ -- cgit v1.2.3 From 6558b667a7297418b8951ba54da68d551035ecc5 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Tue, 2 Mar 2021 15:51:03 +0800 Subject: soundwire: add override addr ops Platform firmware may have incorrect _ADR values causing the driver probes to fail. Add the override_ops, which when configured will allow for quirks based on DMI etc to override the addr values. Co-developed-by: Bard Liao Signed-off-by: Bard Liao Signed-off-by: Vinod Koul Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20210302075105.11515-2-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/slave.c | 8 +++++++- include/linux/soundwire/sdw.h | 4 +++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c index 180f38bd003b..112b21967c7a 100644 --- a/drivers/soundwire/slave.c +++ b/drivers/soundwire/slave.c @@ -95,7 +95,7 @@ static bool find_slave(struct sdw_bus *bus, struct acpi_device *adev, struct sdw_slave_id *id) { - unsigned long long addr; + u64 addr; unsigned int link_id; acpi_status status; @@ -108,6 +108,12 @@ static bool find_slave(struct sdw_bus *bus, return false; } + if (bus->ops->override_adr) + addr = bus->ops->override_adr(bus, addr); + + if (!addr) + return false; + /* Extract link id from ADR, Bit 51 to 48 (included) */ link_id = SDW_DISCO_LINK_ID(addr); diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index d08039d65825..f0a3895e8faf 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -804,6 +804,7 @@ struct sdw_defer { /** * struct sdw_master_ops - Master driver ops * @read_prop: Read Master properties + * @override_adr: Override value read from firmware (quirk for buggy firmware) * @xfer_msg: Transfer message callback * @xfer_msg_defer: Defer version of transfer message callback * @reset_page_addr: Reset the SCP page address registers @@ -813,7 +814,8 @@ struct sdw_defer { */ struct sdw_master_ops { int (*read_prop)(struct sdw_bus *bus); - + u64 (*override_adr) + (struct sdw_bus *bus, u64 addr); enum sdw_command_response (*xfer_msg) (struct sdw_bus *bus, struct sdw_msg *msg); enum sdw_command_response (*xfer_msg_defer) -- cgit v1.2.3 From f6594cdfec4cde57484812271696fb9f40d125b7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:51:04 +0800 Subject: soundwire: Intel: introduce DMI quirks for HP Spectre x360 Convertible HP Spectre x360 Convertible devices expose invalid _ADR fields in the DSDT, which prevents codec drivers from probing. A possible solution is to override the DSDT, but that's just too painful for users. This patch suggests a simple DMI-based quirk to remap the existing invalid ADR information into valid ones. BugLink: https://github.com/thesofproject/linux/issues/2700 Co-developed-by: Bard Liao Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20210302075105.11515-3-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/Makefile | 2 +- drivers/soundwire/bus.h | 2 ++ drivers/soundwire/dmi-quirks.c | 66 ++++++++++++++++++++++++++++++++++++++++++ drivers/soundwire/intel.c | 1 + 4 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 drivers/soundwire/dmi-quirks.c diff --git a/drivers/soundwire/Makefile b/drivers/soundwire/Makefile index bf1e250d50dd..986776787b9e 100644 --- a/drivers/soundwire/Makefile +++ b/drivers/soundwire/Makefile @@ -20,7 +20,7 @@ soundwire-cadence-y := cadence_master.o obj-$(CONFIG_SOUNDWIRE_CADENCE) += soundwire-cadence.o #Intel driver -soundwire-intel-y := intel.o intel_init.o +soundwire-intel-y := intel.o intel_init.o dmi-quirks.o obj-$(CONFIG_SOUNDWIRE_INTEL) += soundwire-intel.o #Qualcomm driver diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h index 2e049d39c6e5..40354469860a 100644 --- a/drivers/soundwire/bus.h +++ b/drivers/soundwire/bus.h @@ -7,6 +7,8 @@ #define DEFAULT_BANK_SWITCH_TIMEOUT 3000 #define DEFAULT_PROBE_TIMEOUT 2000 +u64 sdw_dmi_override_adr(struct sdw_bus *bus, u64 addr); + #if IS_ENABLED(CONFIG_ACPI) int sdw_acpi_find_slaves(struct sdw_bus *bus); #else diff --git a/drivers/soundwire/dmi-quirks.c b/drivers/soundwire/dmi-quirks.c new file mode 100644 index 000000000000..249e476e49ea --- /dev/null +++ b/drivers/soundwire/dmi-quirks.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2021 Intel Corporation. + +/* + * Soundwire DMI quirks + */ + +#include +#include +#include +#include "bus.h" + +struct adr_remap { + u64 adr; + u64 remapped_adr; +}; + +/* + * HP Spectre 360 Convertible devices do not expose the correct _ADR + * in the DSDT. + * Remap the bad _ADR values to the ones reported by hardware + */ +static const struct adr_remap hp_spectre_360[] = { + { + 0x000010025D070100, + 0x000020025D071100 + }, + { + 0x000110025d070100, + 0x000120025D130800 + }, + {} +}; + +static const struct dmi_system_id adr_remap_quirk_table[] = { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Convertible"), + }, + .driver_data = (void *)hp_spectre_360, + }, + {} +}; + +u64 sdw_dmi_override_adr(struct sdw_bus *bus, u64 addr) +{ + const struct dmi_system_id *dmi_id; + + /* check if any address remap quirk applies */ + dmi_id = dmi_first_match(adr_remap_quirk_table); + if (dmi_id) { + struct adr_remap *map = dmi_id->driver_data; + + for (map = dmi_id->driver_data; map->adr; map++) { + if (map->adr == addr) { + dev_dbg(bus->dev, "remapped _ADR 0x%llx as 0x%llx\n", + addr, map->remapped_adr); + addr = map->remapped_adr; + break; + } + } + } + + return addr; +} diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index a2d5cdaa9998..a401e270a47f 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1302,6 +1302,7 @@ static int intel_prop_read(struct sdw_bus *bus) static struct sdw_master_ops sdw_intel_ops = { .read_prop = sdw_master_read_prop, + .override_adr = sdw_dmi_override_adr, .xfer_msg = cdns_xfer_msg, .xfer_msg_defer = cdns_xfer_msg_defer, .reset_page_addr = cdns_reset_page_addr, -- cgit v1.2.3 From be3ae00ff9a737c26d7d280caeffc8c7899abe92 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:51:05 +0800 Subject: soundwire: Intel: add DMI quirk for Dell SKU 0A3E We've been handling ACPI issues on early versions of the product with a local ACPI initrd override but now that we have the possibility of a kernel quirk let's get rid of the initrd override. This helps make sure that the kernel will support all versions of the BIOS, with or without updates. Co-developed-by: Bard Liao Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20210302075105.11515-4-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/dmi-quirks.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/soundwire/dmi-quirks.c b/drivers/soundwire/dmi-quirks.c index 249e476e49ea..82061c1d9835 100644 --- a/drivers/soundwire/dmi-quirks.c +++ b/drivers/soundwire/dmi-quirks.c @@ -32,6 +32,29 @@ static const struct adr_remap hp_spectre_360[] = { {} }; +/* + * The initial version of the Dell SKU 0A3E did not expose the devices + * on the correct links. + */ +static const struct adr_remap dell_sku_0A3E[] = { + /* rt715 on link0 */ + { + 0x00020025d071100, + 0x00021025d071500 + }, + /* rt711 on link1 */ + { + 0x000120025d130800, + 0x000120025d071100, + }, + /* rt1308 on link2 */ + { + 0x000220025d071500, + 0x000220025d130800 + }, + {} +}; + static const struct dmi_system_id adr_remap_quirk_table[] = { { .matches = { @@ -40,6 +63,13 @@ static const struct dmi_system_id adr_remap_quirk_table[] = { }, .driver_data = (void *)hp_spectre_360, }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E") + }, + .driver_data = (void *)dell_sku_0A3E, + }, {} }; -- cgit v1.2.3 From 5bb643c39b97c440b2981c69f05596c7ea868b73 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 2 Mar 2021 16:27:18 +0800 Subject: soundwire: add master quirks for bus clash and parity Currently quirks are only allowed for Slave devices. This patch describes the need for two quirks at the Master level. a) bus clash The SoundWire specification allows a Slave device to report a bus clash with the in-band interrupt mechanism when it detects a conflict while driving a bitSlot it owns. This can be a symptom of an electrical conflict or a programming error, and it's vital to detect reliably. Unfortunately, on some platforms, bus clashes are randomly reported by Slave devices after a bus reset, with an interrupt status set even before the bus clash interrupt is enabled. These initial spurious interrupts are not relevant and should optionally be filtered out, while leaving the interrupt mechanism enabled to detect 'true' issues. This patch suggests the addition of a Master level quirk to discard such interrupts. The quirk should in theory have been added at the Slave level, but since the problem was detected with different generations of Slave devices it's hard to point to a specific IP. The problem might also be board-dependent and hence dealing with a Master quirk is simpler. b) parity Additional tests on a new platform with the Maxim 98373 amplifier showed a rare case where the parity interrupt is also thrown on startup, at the same time as bus clashes. This issue only seems to happen infrequently and was only observed during suspend-resume stress tests while audio is streaming. We could make the problem go away by adding a Slave-level quirk, but there is no evidence that the issue is actually a Slave problem: the parity is provided by the Master, which could also set an invalid parity in corner cases. BugLink: https://github.com/thesofproject/linux/issues/2578 BugLink: https://github.com/thesofproject/linux/issues/2533 Co-developed-by: Pierre-Louis Bossart Signed-off-by: Pierre-Louis Bossart Signed-off-by: Bard Liao Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20210302082720.12322-2-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- include/linux/soundwire/sdw.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index f0a3895e8faf..eaa1486bdca9 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -405,6 +405,7 @@ struct sdw_slave_prop { * command * @mclk_freq: clock reference passed to SoundWire Master, in Hz. * @hw_disabled: if true, the Master is not functional, typically due to pin-mux + * @quirks: bitmask identifying optional behavior beyond the scope of the MIPI specification */ struct sdw_master_prop { u32 revision; @@ -421,8 +422,29 @@ struct sdw_master_prop { u32 err_threshold; u32 mclk_freq; bool hw_disabled; + u64 quirks; }; +/* Definitions for Master quirks */ + +/* + * In a number of platforms bus clashes are reported after a hardware + * reset but without any explanations or evidence of a real problem. + * The following quirk will discard all initial bus clash interrupts + * but will leave the detection on should real bus clashes happen + */ +#define SDW_MASTER_QUIRKS_CLEAR_INITIAL_CLASH BIT(0) + +/* + * Some Slave devices have known issues with incorrect parity errors + * reported after a hardware reset. However during integration unexplained + * parity errors can be reported by Slave devices, possibly due to electrical + * issues at the Master level. + * The following quirk will discard all initial parity errors but will leave + * the detection on should real parity errors happen. + */ +#define SDW_MASTER_QUIRKS_CLEAR_INITIAL_PARITY BIT(1) + int sdw_master_read_prop(struct sdw_bus *bus); int sdw_slave_read_prop(struct sdw_slave *slave); -- cgit v1.2.3 From 6b8caa6f9d3a428022d41913bf9660325599dac1 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 2 Mar 2021 16:27:19 +0800 Subject: soundwire: bus: handle master quirks for bus clash and parity Add optional interrupt status read/clear if the master quirks are set. In the case of the parity, the master quirk is only applied if the Slave doesn't already have a parity-related quirk. Co-developed-by: Pierre-Louis Bossart Signed-off-by: Pierre-Louis Bossart Signed-off-by: Bard Liao Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20210302082720.12322-3-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 46885429928a..04eb879de145 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -1253,6 +1253,7 @@ static int sdw_slave_set_frequency(struct sdw_slave *slave) static int sdw_initialize_slave(struct sdw_slave *slave) { struct sdw_slave_prop *prop = &slave->prop; + int status; int ret; u8 val; @@ -1260,6 +1261,44 @@ static int sdw_initialize_slave(struct sdw_slave *slave) if (ret < 0) return ret; + if (slave->bus->prop.quirks & SDW_MASTER_QUIRKS_CLEAR_INITIAL_CLASH) { + /* Clear bus clash interrupt before enabling interrupt mask */ + status = sdw_read_no_pm(slave, SDW_SCP_INT1); + if (status < 0) { + dev_err(&slave->dev, + "SDW_SCP_INT1 (BUS_CLASH) read failed:%d\n", status); + return status; + } + if (status & SDW_SCP_INT1_BUS_CLASH) { + dev_warn(&slave->dev, "Bus clash detected before INT mask is enabled\n"); + ret = sdw_write_no_pm(slave, SDW_SCP_INT1, SDW_SCP_INT1_BUS_CLASH); + if (ret < 0) { + dev_err(&slave->dev, + "SDW_SCP_INT1 (BUS_CLASH) write failed:%d\n", ret); + return ret; + } + } + } + if ((slave->bus->prop.quirks & SDW_MASTER_QUIRKS_CLEAR_INITIAL_PARITY) && + !(slave->prop.quirks & SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY)) { + /* Clear parity interrupt before enabling interrupt mask */ + status = sdw_read_no_pm(slave, SDW_SCP_INT1); + if (status < 0) { + dev_err(&slave->dev, + "SDW_SCP_INT1 (PARITY) read failed:%d\n", status); + return status; + } + if (status & SDW_SCP_INT1_PARITY) { + dev_warn(&slave->dev, "PARITY error detected before INT mask is enabled\n"); + ret = sdw_write_no_pm(slave, SDW_SCP_INT1, SDW_SCP_INT1_PARITY); + if (ret < 0) { + dev_err(&slave->dev, + "SDW_SCP_INT1 (PARITY) write failed:%d\n", ret); + return ret; + } + } + } + /* * Set SCP_INT1_MASK register, typically bus clash and * implementation-defined interrupt mask. The Parity detection -- cgit v1.2.3 From bb877bebae0f38048e844aad9ed93127a5eecc5c Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 2 Mar 2021 16:27:20 +0800 Subject: soundwire: intel: add master quirks for bus clash and parity Now that we have declarations and bus support, add quirks for Intel platforms. Co-developed-by: Pierre-Louis Bossart Signed-off-by: Pierre-Louis Bossart Signed-off-by: Bard Liao Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20210302082720.12322-4-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index a401e270a47f..d2254ee2fee2 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1286,6 +1286,9 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus) if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE) prop->hw_disabled = true; + prop->quirks = SDW_MASTER_QUIRKS_CLEAR_INITIAL_CLASH | + SDW_MASTER_QUIRKS_CLEAR_INITIAL_PARITY; + return 0; } -- cgit v1.2.3 From 4e3ea93e1399e808852b33753e0caf394b869ba3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 23 Mar 2021 08:58:51 +0800 Subject: soundwire: intel: add missing \n in dev_err() We fixed a lot of warnings in 2019 but the magic of copy-paste keeps adding new ones... Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210323005855.20890-2-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index d2254ee2fee2..e2e95115832a 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -997,7 +997,7 @@ static int intel_prepare(struct snd_pcm_substream *substream, dma = snd_soc_dai_get_dma_data(dai, substream); if (!dma) { - dev_err(dai->dev, "failed to get dma data in %s", + dev_err(dai->dev, "failed to get dma data in %s\n", __func__); return -EIO; } @@ -1061,7 +1061,7 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) ret = intel_free_stream(sdw, substream, dai, sdw->instance); if (ret < 0) { - dev_err(dai->dev, "intel_free_stream: failed %d", ret); + dev_err(dai->dev, "intel_free_stream: failed %d\n", ret); return ret; } @@ -1634,7 +1634,7 @@ static int __maybe_unused intel_suspend(struct device *dev) ret = intel_link_power_down(sdw); if (ret) { - dev_err(dev, "Link power down failed: %d", ret); + dev_err(dev, "Link power down failed: %d\n", ret); return ret; } @@ -1669,7 +1669,7 @@ static int __maybe_unused intel_suspend_runtime(struct device *dev) ret = intel_link_power_down(sdw); if (ret) { - dev_err(dev, "Link power down failed: %d", ret); + dev_err(dev, "Link power down failed: %d\n", ret); return ret; } @@ -1693,7 +1693,7 @@ static int __maybe_unused intel_suspend_runtime(struct device *dev) ret = intel_link_power_down(sdw); if (ret) { - dev_err(dev, "Link power down failed: %d", ret); + dev_err(dev, "Link power down failed: %d\n", ret); return ret; } @@ -1742,7 +1742,7 @@ static int __maybe_unused intel_resume(struct device *dev) ret = intel_init(sdw); if (ret) { - dev_err(dev, "%s failed: %d", __func__, ret); + dev_err(dev, "%s failed: %d\n", __func__, ret); return ret; } @@ -1826,7 +1826,7 @@ static int __maybe_unused intel_resume_runtime(struct device *dev) if (clock_stop_quirks & SDW_INTEL_CLK_STOP_TEARDOWN) { ret = intel_init(sdw); if (ret) { - dev_err(dev, "%s failed: %d", __func__, ret); + dev_err(dev, "%s failed: %d\n", __func__, ret); return ret; } @@ -1871,7 +1871,7 @@ static int __maybe_unused intel_resume_runtime(struct device *dev) } else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) { ret = intel_init(sdw); if (ret) { - dev_err(dev, "%s failed: %d", __func__, ret); + dev_err(dev, "%s failed: %d\n", __func__, ret); return ret; } @@ -1949,7 +1949,7 @@ static int __maybe_unused intel_resume_runtime(struct device *dev) ret = intel_init(sdw); if (ret) { - dev_err(dev, "%s failed: %d", __func__, ret); + dev_err(dev, "%s failed: %d\n", __func__, ret); return ret; } -- cgit v1.2.3 From 0eb7c387e625f012fd951ff7530d51c46605e07b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 23 Mar 2021 08:58:52 +0800 Subject: soundwire: bandwidth_allocation: add missing \n in dev_err() We fixed a lot of warnings in 2019 but the magic of copy-paste keeps adding new ones... Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210323005855.20890-3-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/generic_bandwidth_allocation.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index 0bdef38c9a30..a9abb9722fde 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -406,14 +406,14 @@ int sdw_compute_params(struct sdw_bus *bus) /* Computes clock frequency, frame shape and frame frequency */ ret = sdw_compute_bus_params(bus); if (ret < 0) { - dev_err(bus->dev, "Compute bus params failed: %d", ret); + dev_err(bus->dev, "Compute bus params failed: %d\n", ret); return ret; } /* Compute transport and port params */ ret = sdw_compute_port_params(bus); if (ret < 0) { - dev_err(bus->dev, "Compute transport params failed: %d", ret); + dev_err(bus->dev, "Compute transport params failed: %d\n", ret); return ret; } -- cgit v1.2.3 From 7dbdcd611066879d1065e71351d72d6a30fd3402 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 23 Mar 2021 08:58:53 +0800 Subject: soundwire: cadence: add missing \n in dev_err() We fixed a lot of warnings in 2019 but the magic of copy-paste keeps adding new ones... Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210323005855.20890-4-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/cadence_master.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index d05442e646a3..1b50cf7abe66 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -1462,7 +1462,7 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake) */ ret = sdw_bus_clk_stop(&cdns->bus); if (ret < 0 && slave_present && ret != -ENODATA) { - dev_err(cdns->dev, "bus clock stop failed %d", ret); + dev_err(cdns->dev, "bus clock stop failed %d\n", ret); return ret; } -- cgit v1.2.3 From 6122d3be2e9aa496434345dbe86c8ebe8084007d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 23 Mar 2021 08:58:54 +0800 Subject: soundwire: stream: add missing \n in dev_err() We fixed a lot of warnings in 2019 but the magic of copy-paste keeps adding new ones... Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210323005855.20890-5-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/stream.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 1099b5d1262b..4915676c4ac2 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -1513,7 +1513,7 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream, if (bus->compute_params) { ret = bus->compute_params(bus); if (ret < 0) { - dev_err(bus->dev, "Compute params failed: %d", + dev_err(bus->dev, "Compute params failed: %d\n", ret); return ret; } @@ -1791,7 +1791,7 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream) if (bus->compute_params) { ret = bus->compute_params(bus); if (ret < 0) { - dev_err(bus->dev, "Compute params failed: %d", + dev_err(bus->dev, "Compute params failed: %d\n", ret); return ret; } @@ -1855,7 +1855,7 @@ static int set_stream(struct snd_pcm_substream *substream, for_each_rtd_dais(rtd, i, dai) { ret = snd_soc_dai_set_sdw_stream(dai, sdw_stream, substream->stream); if (ret < 0) { - dev_err(rtd->dev, "failed to set stream pointer on dai %s", dai->name); + dev_err(rtd->dev, "failed to set stream pointer on dai %s\n", dai->name); break; } } @@ -1888,7 +1888,7 @@ int sdw_startup_stream(void *sdw_substream) sdw_stream = sdw_alloc_stream(name); if (!sdw_stream) { - dev_err(rtd->dev, "alloc stream failed for substream DAI %s", substream->name); + dev_err(rtd->dev, "alloc stream failed for substream DAI %s\n", substream->name); ret = -ENOMEM; goto error; } @@ -1927,7 +1927,7 @@ void sdw_shutdown_stream(void *sdw_substream) sdw_stream = snd_soc_dai_get_sdw_stream(dai, substream->stream); if (IS_ERR(sdw_stream)) { - dev_err(rtd->dev, "no stream found for DAI %s", dai->name); + dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); return; } -- cgit v1.2.3 From e6cb15b500658ef5e39c1e9170d7e521904752b7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 23 Mar 2021 08:58:55 +0800 Subject: soundwire: qcom: add missing \n in dev_err() We fixed a lot of warnings in 2019 but the magic of copy-paste keeps adding new ones... Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210323005855.20890-6-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/qcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 6d22df01f354..9cce09cba068 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -652,7 +652,7 @@ static int qcom_swrm_startup(struct snd_pcm_substream *substream, ret = snd_soc_dai_set_sdw_stream(codec_dai, sruntime, substream->stream); if (ret < 0 && ret != -ENOTSUPP) { - dev_err(dai->dev, "Failed to set sdw stream on %s", + dev_err(dai->dev, "Failed to set sdw stream on %s\n", codec_dai->name); sdw_release_stream(sruntime); return ret; -- cgit v1.2.3 From ce453ee6df018a8522373faae56e6032045a9606 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 4 Feb 2021 13:13:13 +0100 Subject: fpga: fpga-mgr: xilinx-spi: fix error messages on -EPROBE_DEFER The current code produces an error message on devm_gpiod_get() errors even when the error is -EPROBE_DEFER, which should be silent. This has been observed producing a significant amount of messages like: xlnx-slave-spi spi1.1: Failed to get PROGRAM_B gpio: -517 Fix and simplify code by using the dev_err_probe() helper function. Signed-off-by: Luca Ceresoli Fixes: dd2784c01d93 ("fpga manager: xilinx-spi: check INIT_B pin during write_init") Fixes: 061c97d13f1a ("fpga manager: Add Xilinx slave serial SPI driver") Signed-off-by: Moritz Fischer Signed-off-by: Greg Kroah-Hartman --- drivers/fpga/xilinx-spi.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c index 27defa98092d..fee4d0abf6bf 100644 --- a/drivers/fpga/xilinx-spi.c +++ b/drivers/fpga/xilinx-spi.c @@ -233,25 +233,19 @@ static int xilinx_spi_probe(struct spi_device *spi) /* PROGRAM_B is active low */ conf->prog_b = devm_gpiod_get(&spi->dev, "prog_b", GPIOD_OUT_LOW); - if (IS_ERR(conf->prog_b)) { - dev_err(&spi->dev, "Failed to get PROGRAM_B gpio: %ld\n", - PTR_ERR(conf->prog_b)); - return PTR_ERR(conf->prog_b); - } + if (IS_ERR(conf->prog_b)) + return dev_err_probe(&spi->dev, PTR_ERR(conf->prog_b), + "Failed to get PROGRAM_B gpio\n"); conf->init_b = devm_gpiod_get_optional(&spi->dev, "init-b", GPIOD_IN); - if (IS_ERR(conf->init_b)) { - dev_err(&spi->dev, "Failed to get INIT_B gpio: %ld\n", - PTR_ERR(conf->init_b)); - return PTR_ERR(conf->init_b); - } + if (IS_ERR(conf->init_b)) + return dev_err_probe(&spi->dev, PTR_ERR(conf->init_b), + "Failed to get INIT_B gpio\n"); conf->done = devm_gpiod_get(&spi->dev, "done", GPIOD_IN); - if (IS_ERR(conf->done)) { - dev_err(&spi->dev, "Failed to get DONE gpio: %ld\n", - PTR_ERR(conf->done)); - return PTR_ERR(conf->done); - } + if (IS_ERR(conf->done)) + return dev_err_probe(&spi->dev, PTR_ERR(conf->done), + "Failed to get DONE gpio\n"); mgr = devm_fpga_mgr_create(&spi->dev, "Xilinx Slave Serial FPGA Manager", -- cgit v1.2.3 From b5c6ecfd471ead372a158c7ca9167e4dcc2a1deb Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 4 Feb 2021 14:36:11 +0100 Subject: fpga: xilinx-pr-decoupler: Simplify code by using dev_err_probe() Use already prepared dev_err_probe() introduced by commit a787e5400a1c ("driver core: add device probe log helper"). It simplifies EPROBE_DEFER handling. Signed-off-by: Michal Simek Signed-off-by: Moritz Fischer Signed-off-by: Greg Kroah-Hartman --- drivers/fpga/xilinx-pr-decoupler.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/fpga/xilinx-pr-decoupler.c b/drivers/fpga/xilinx-pr-decoupler.c index 7d69af230567..b0eaf26af6e7 100644 --- a/drivers/fpga/xilinx-pr-decoupler.c +++ b/drivers/fpga/xilinx-pr-decoupler.c @@ -100,11 +100,9 @@ static int xlnx_pr_decoupler_probe(struct platform_device *pdev) return PTR_ERR(priv->io_base); priv->clk = devm_clk_get(&pdev->dev, "aclk"); - if (IS_ERR(priv->clk)) { - if (PTR_ERR(priv->clk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "input clock not found\n"); - return PTR_ERR(priv->clk); - } + if (IS_ERR(priv->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk), + "input clock not found\n"); err = clk_prepare_enable(priv->clk); if (err) { -- cgit v1.2.3 From 8058182fa4402361f25cd701bb90276fba331127 Mon Sep 17 00:00:00 2001 From: Nava kishore Manne Date: Thu, 11 Feb 2021 10:41:47 +0530 Subject: dt-bindings: fpga: Add compatible value for Xilinx DFX AXI shutdown manager This patch Adds compatible value for Xilinx Dynamic Function eXchnage(DFX) AXI Shutdown manager IP. Signed-off-by: Nava kishore Manne Reviewed-by: Tom Rix Reviewed-by: Rob Herring Signed-off-by: Moritz Fischer Signed-off-by: Greg Kroah-Hartman --- .../bindings/fpga/xilinx-pr-decoupler.txt | 24 +++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/fpga/xilinx-pr-decoupler.txt b/Documentation/devicetree/bindings/fpga/xilinx-pr-decoupler.txt index 4284d293fa61..0acdfa6d62a4 100644 --- a/Documentation/devicetree/bindings/fpga/xilinx-pr-decoupler.txt +++ b/Documentation/devicetree/bindings/fpga/xilinx-pr-decoupler.txt @@ -7,13 +7,24 @@ changes from passing through the bridge. The controller can also couple / enable the bridges which allows traffic to pass through the bridge normally. +Xilinx LogiCORE Dynamic Function eXchange(DFX) AXI shutdown manager +Softcore is compatible with the Xilinx LogiCORE pr-decoupler. + +The Dynamic Function eXchange AXI shutdown manager prevents AXI traffic +from passing through the bridge. The controller safely handles AXI4MM +and AXI4-Lite interfaces on a Reconfigurable Partition when it is +undergoing dynamic reconfiguration, preventing the system deadlock +that can occur if AXI transactions are interrupted by DFX + The Driver supports only MMIO handling. A PR region can have multiple PR Decouplers which can be handled independently or chained via decouple/ decouple_status signals. Required properties: - compatible : Should contain "xlnx,pr-decoupler-1.00" followed by - "xlnx,pr-decoupler" + "xlnx,pr-decoupler" or + "xlnx,dfx-axi-shutdown-manager-1.00" followed by + "xlnx,dfx-axi-shutdown-manager" - regs : base address and size for decoupler module - clocks : input clock to IP - clock-names : should contain "aclk" @@ -22,6 +33,7 @@ See Documentation/devicetree/bindings/fpga/fpga-region.txt and Documentation/devicetree/bindings/fpga/fpga-bridge.txt for generic bindings. Example: +Partial Reconfig Decoupler: fpga-bridge@100000450 { compatible = "xlnx,pr-decoupler-1.00", "xlnx-pr-decoupler"; @@ -30,3 +42,13 @@ Example: clock-names = "aclk"; bridge-enable = <0>; }; + +Dynamic Function eXchange AXI shutdown manager: + fpga-bridge@100000450 { + compatible = "xlnx,dfx-axi-shutdown-manager-1.00", + "xlnx,dfx-axi-shutdown-manager"; + regs = <0x10000045 0x10>; + clocks = <&clkc 15>; + clock-names = "aclk"; + bridge-enable = <0>; + }; -- cgit v1.2.3 From 30a2ac9a8bb5fce15e617038bee8f26e5d090667 Mon Sep 17 00:00:00 2001 From: Nava kishore Manne Date: Thu, 11 Feb 2021 10:41:48 +0530 Subject: fpga: Add support for Xilinx DFX AXI Shutdown manager This patch adds support for Xilinx Dynamic Function eXchange(DFX) AXI shutdown manager IP. It can be used to safely handling the AXI traffic on a Reconfigurable Partition when it is undergoing dynamic reconfiguration and there by preventing system deadlock that may occur if AXI transactions are interrupted during reconfiguration. PR-Decoupler and AXI shutdown manager are completely different IPs. But both the IP registers are compatible and also both belong to the same sub-system (fpga-bridge).So using same driver for both IP's. Signed-off-by: Nava kishore Manne Reviewed-by: Tom Rix Signed-off-by: Moritz Fischer Signed-off-by: Greg Kroah-Hartman --- drivers/fpga/Kconfig | 9 ++++++++- drivers/fpga/xilinx-pr-decoupler.c | 37 ++++++++++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 5ff9438b7b46..d591dd9b7c60 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -118,10 +118,17 @@ config XILINX_PR_DECOUPLER depends on FPGA_BRIDGE depends on HAS_IOMEM help - Say Y to enable drivers for Xilinx LogiCORE PR Decoupler. + Say Y to enable drivers for Xilinx LogiCORE PR Decoupler + or Xilinx Dynamic Function eXchnage AIX Shutdown Manager. The PR Decoupler exists in the FPGA fabric to isolate one region of the FPGA from the busses while that region is being reprogrammed during partial reconfig. + The Dynamic Function eXchange AXI shutdown manager prevents + AXI traffic from passing through the bridge. The controller + safely handles AXI4MM and AXI4-Lite interfaces on a + Reconfigurable Partition when it is undergoing dynamic + reconfiguration, preventing the system deadlock that can + occur if AXI transactions are interrupted by DFX. config FPGA_REGION tristate "FPGA Region" diff --git a/drivers/fpga/xilinx-pr-decoupler.c b/drivers/fpga/xilinx-pr-decoupler.c index b0eaf26af6e7..ea2bde6e5bc4 100644 --- a/drivers/fpga/xilinx-pr-decoupler.c +++ b/drivers/fpga/xilinx-pr-decoupler.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017, National Instruments Corp. - * Copyright (c) 2017, Xilix Inc + * Copyright (c) 2017, Xilinx Inc * * FPGA Bridge Driver for the Xilinx LogiCORE Partial Reconfiguration * Decoupler IP Core. @@ -18,7 +18,12 @@ #define CTRL_CMD_COUPLE 0 #define CTRL_OFFSET 0 +struct xlnx_config_data { + const char *name; +}; + struct xlnx_pr_decoupler_data { + const struct xlnx_config_data *ipconfig; void __iomem *io_base; struct clk *clk; }; @@ -76,15 +81,28 @@ static const struct fpga_bridge_ops xlnx_pr_decoupler_br_ops = { .enable_show = xlnx_pr_decoupler_enable_show, }; +static const struct xlnx_config_data decoupler_config = { + .name = "Xilinx PR Decoupler", +}; + +static const struct xlnx_config_data shutdown_config = { + .name = "Xilinx DFX AXI Shutdown Manager", +}; + static const struct of_device_id xlnx_pr_decoupler_of_match[] = { - { .compatible = "xlnx,pr-decoupler-1.00", }, - { .compatible = "xlnx,pr-decoupler", }, + { .compatible = "xlnx,pr-decoupler-1.00", .data = &decoupler_config }, + { .compatible = "xlnx,pr-decoupler", .data = &decoupler_config }, + { .compatible = "xlnx,dfx-axi-shutdown-manager-1.00", + .data = &shutdown_config }, + { .compatible = "xlnx,dfx-axi-shutdown-manager", + .data = &shutdown_config }, {}, }; MODULE_DEVICE_TABLE(of, xlnx_pr_decoupler_of_match); static int xlnx_pr_decoupler_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct xlnx_pr_decoupler_data *priv; struct fpga_bridge *br; int err; @@ -94,6 +112,14 @@ static int xlnx_pr_decoupler_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + if (np) { + const struct of_device_id *match; + + match = of_match_node(xlnx_pr_decoupler_of_match, np); + if (match && match->data) + priv->ipconfig = match->data; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->io_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(priv->io_base)) @@ -112,7 +138,7 @@ static int xlnx_pr_decoupler_probe(struct platform_device *pdev) clk_disable(priv->clk); - br = devm_fpga_bridge_create(&pdev->dev, "Xilinx PR Decoupler", + br = devm_fpga_bridge_create(&pdev->dev, priv->ipconfig->name, &xlnx_pr_decoupler_br_ops, priv); if (!br) { err = -ENOMEM; @@ -123,7 +149,8 @@ static int xlnx_pr_decoupler_probe(struct platform_device *pdev) err = fpga_bridge_register(br); if (err) { - dev_err(&pdev->dev, "unable to register Xilinx PR Decoupler"); + dev_err(&pdev->dev, "unable to register %s", + priv->ipconfig->name); goto err_clk; } -- cgit v1.2.3 From 40cc3a80bb42587db1e6ae21d6f3090582d33e89 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 22 Mar 2021 17:43:03 +0100 Subject: kgdb: fix gcc-11 warning on indentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gcc-11 starts warning about misleading indentation inside of macros: drivers/misc/kgdbts.c: In function ‘kgdbts_break_test’: drivers/misc/kgdbts.c:103:9: error: this ‘if’ clause does not guard... [-Werror=misleading-indentation] 103 | if (verbose > 1) \ | ^~ drivers/misc/kgdbts.c:200:9: note: in expansion of macro ‘v2printk’ 200 | v2printk("kgdbts: breakpoint complete\n"); | ^~~~~~~~ drivers/misc/kgdbts.c:105:17: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the ‘if’ 105 | touch_nmi_watchdog(); \ | ^~~~~~~~~~~~~~~~~~ The code looks correct to me, so just reindent it for readability. Fixes: e8d31c204e36 ("kgdb: add kgdb internal test suite") Acked-by: Daniel Thompson Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20210322164308.827846-1-arnd@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/kgdbts.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index 945701bce553..2e081a58da6c 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -95,19 +95,19 @@ #include -#define v1printk(a...) do { \ - if (verbose) \ - printk(KERN_INFO a); \ - } while (0) -#define v2printk(a...) do { \ - if (verbose > 1) \ - printk(KERN_INFO a); \ - touch_nmi_watchdog(); \ - } while (0) -#define eprintk(a...) do { \ - printk(KERN_ERR a); \ - WARN_ON(1); \ - } while (0) +#define v1printk(a...) do { \ + if (verbose) \ + printk(KERN_INFO a); \ +} while (0) +#define v2printk(a...) do { \ + if (verbose > 1) \ + printk(KERN_INFO a); \ + touch_nmi_watchdog(); \ +} while (0) +#define eprintk(a...) do { \ + printk(KERN_ERR a); \ + WARN_ON(1); \ +} while (0) #define MAX_CONFIG_LEN 40 static struct kgdb_io kgdbts_io_ops; -- cgit v1.2.3 From 25651f2df7833c5554f51652007862a405aac830 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 22 Mar 2021 15:17:48 +0100 Subject: uapi: map_to_7segment: Remove licence boilerplate Remove the license boilerplate (containing an obsolete address), because we now have the SPDX header. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20210322141748.1062733-1-geert@linux-m68k.org Signed-off-by: Greg Kroah-Hartman --- include/uapi/linux/map_to_7segment.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/include/uapi/linux/map_to_7segment.h b/include/uapi/linux/map_to_7segment.h index 8b02088f96e3..04c8b55812e7 100644 --- a/include/uapi/linux/map_to_7segment.h +++ b/include/uapi/linux/map_to_7segment.h @@ -1,20 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ /* * Copyright (c) 2005 Henk Vergonet - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef MAP_TO_7SEGMENT_H -- cgit v1.2.3 From 3641762c1c9c7cfd84a7061a0a73054f09b412e3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 17 Feb 2021 11:24:59 +0100 Subject: misc: lis3lv02d: Fix false-positive WARN on various HP models Before this commit lis3lv02d_get_pwron_wait() had a WARN_ONCE() to catch a potential divide by 0. WARN macros should only be used to catch internal kernel bugs and that is not the case here. We have been receiving a lot of bug reports about kernel backtraces caused by this WARN. The div value being checked comes from the lis3->odrs[] array. Which is sized to be a power-of-2 matching the number of bits in lis3->odr_mask. The only lis3 model where this array is not entirely filled with non zero values. IOW the only model where we can hit the div == 0 check is the 3dc ("8 bits 3DC sensor") model: int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000}; Note the 0 value at index 0, according to the datasheet an odr index of 0 means "Power-down mode". HP typically uses a lis3 accelerometer for HDD fall protection. What I believe is happening here is that on newer HP devices, which only contain a SDD, the BIOS is leaving the lis3 device powered-down since it is not used for HDD fall protection. Note that the lis3_3dc_rates array initializer only specifies 10 values, which matches the datasheet. So it also contains 6 zero values at the end. Replace the WARN with a normal check, which treats an odr index of 0 as power-down and uses a normal dev_err() to report the error in case odr index point past the initialized part of the array. Fixes: 1510dd5954be ("lis3lv02d: avoid divide by zero due to unchecked") Cc: stable@vger.kernel.org Signed-off-by: Hans de Goede BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=785814 BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1817027 BugLink: https://bugs.centos.org/view.php?id=10720 Link: https://lore.kernel.org/r/20210217102501.31758-1-hdegoede@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/lis3lv02d/lis3lv02d.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c index dd65cedf3b12..9d14bf444481 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d.c +++ b/drivers/misc/lis3lv02d/lis3lv02d.c @@ -208,7 +208,7 @@ static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000}; static int lis3_3dlh_rates[4] = {50, 100, 400, 1000}; /* ODR is Output Data Rate */ -static int lis3lv02d_get_odr(struct lis3lv02d *lis3) +static int lis3lv02d_get_odr_index(struct lis3lv02d *lis3) { u8 ctrl; int shift; @@ -216,15 +216,23 @@ static int lis3lv02d_get_odr(struct lis3lv02d *lis3) lis3->read(lis3, CTRL_REG1, &ctrl); ctrl &= lis3->odr_mask; shift = ffs(lis3->odr_mask) - 1; - return lis3->odrs[(ctrl >> shift)]; + return (ctrl >> shift); } static int lis3lv02d_get_pwron_wait(struct lis3lv02d *lis3) { - int div = lis3lv02d_get_odr(lis3); + int odr_idx = lis3lv02d_get_odr_index(lis3); + int div = lis3->odrs[odr_idx]; - if (WARN_ONCE(div == 0, "device returned spurious data")) + if (div == 0) { + if (odr_idx == 0) { + /* Power-down mode, not sampling no need to sleep */ + return 0; + } + + dev_err(&lis3->pdev->dev, "Error unknown odrs-index: %d\n", odr_idx); return -ENXIO; + } /* LIS3 power on delay is quite long */ msleep(lis3->pwron_delay / div); @@ -816,9 +824,12 @@ static ssize_t lis3lv02d_rate_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lis3lv02d *lis3 = dev_get_drvdata(dev); + int odr_idx; lis3lv02d_sysfs_poweron(lis3); - return sprintf(buf, "%d\n", lis3lv02d_get_odr(lis3)); + + odr_idx = lis3lv02d_get_odr_index(lis3); + return sprintf(buf, "%d\n", lis3->odrs[odr_idx]); } static ssize_t lis3lv02d_rate_set(struct device *dev, -- cgit v1.2.3 From bb6886bf1e2bf49627a1c4ac5e615cfe518c827f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 17 Feb 2021 11:25:00 +0100 Subject: misc: lis3lv02d: Change lis3lv02d_init_device() return value for unknown sensors to -ENODEV Modern HP laptops do not necessarily actually contain a lis3lv02d sensor, yet they still define a HPQ6007 device in there ACPI tables. This leads to the following messages being logged in dmesg: [ 17.376342] hp_accel: laptop model unknown, using default axes configuration [ 17.399766] lis3lv02d: unknown sensor type 0x0 [ 17.399804] hp_accel: probe of HPQ6007:00 failed with error -22 The third message is unnecessary and does not provide any useful info, change the return value for unknown sensors to -ENODEV. This is the proper return value to indicate that the driver will not be handling the device and it silences the pr_warn printing the third message. Signed-off-by: Hans de Goede BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=199715 Link: https://lore.kernel.org/r/20210217102501.31758-2-hdegoede@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/lis3lv02d/lis3lv02d.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c index 9d14bf444481..22dacfaad02f 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d.c +++ b/drivers/misc/lis3lv02d/lis3lv02d.c @@ -1173,7 +1173,7 @@ int lis3lv02d_init_device(struct lis3lv02d *lis3) break; default: pr_err("unknown sensor type 0x%X\n", lis3->whoami); - return -EINVAL; + return -ENODEV; } lis3->reg_cache = kzalloc(max(sizeof(lis3_wai8_regs), -- cgit v1.2.3 From 2278f0c385d88a3898d0e977d6e80e5d3d3d6020 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 17 Feb 2021 11:25:01 +0100 Subject: misc: lis3lv02d: Do not log an error when kmalloc fails Logging an error when kmalloc fails is not necessary (and in general should be avoided) because the malloc failure will already complain loudly itself. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210217102501.31758-3-hdegoede@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/lis3lv02d/lis3lv02d.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c index 22dacfaad02f..70c5bb1e6f49 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d.c +++ b/drivers/misc/lis3lv02d/lis3lv02d.c @@ -1179,10 +1179,8 @@ int lis3lv02d_init_device(struct lis3lv02d *lis3) lis3->reg_cache = kzalloc(max(sizeof(lis3_wai8_regs), sizeof(lis3_wai12_regs)), GFP_KERNEL); - if (lis3->reg_cache == NULL) { - printk(KERN_ERR DRIVER_NAME "out of memory\n"); + if (lis3->reg_cache == NULL) return -ENOMEM; - } mutex_init(&lis3->mutex); atomic_set(&lis3->wake_thread, 0); -- cgit v1.2.3 From 0ea43c23d4904d6a6e6b2b12a9da12b33ee0da1b Mon Sep 17 00:00:00 2001 From: Bhaskar Chowdhury Date: Mon, 22 Mar 2021 08:03:07 +0530 Subject: cxl: Fix couple of spellings s/filesytem/filesystem/ s/symantics/semantics/ Acked-by: Randy Dunlap Acked-by: Andrew Donnellan Signed-off-by: Bhaskar Chowdhury Link: https://lore.kernel.org/r/20210322023307.168754-1-unixbhaskar@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cxl/context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c index fb2eff69e449..e627b4056623 100644 --- a/drivers/misc/cxl/context.c +++ b/drivers/misc/cxl/context.c @@ -52,7 +52,7 @@ int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master) * can always access it when dereferenced from IDR. For the same * reason, the segment table is only destroyed after the context is * removed from the IDR. Access to this in the IOCTL is protected by - * Linux filesytem symantics (can't IOCTL until open is complete). + * Linux filesystem semantics (can't IOCTL until open is complete). */ i = cxl_alloc_sst(ctx); if (i) -- cgit v1.2.3 From 615d2ef05a97be05c12cbb50f5fce0b8e094d66c Mon Sep 17 00:00:00 2001 From: Laurent Dufour Date: Wed, 10 Mar 2021 18:44:05 +0100 Subject: cxl: don't manipulate the mm.mm_users field directly It is better to rely on the API provided by the MM layer instead of directly manipulating the mm_users field. Acked-by: Frederic Barrat Acked-by: Andrew Donnellan Signed-off-by: Laurent Dufour Link: https://lore.kernel.org/r/20210310174405.51044-1-ldufour@linux.ibm.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cxl/fault.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/cxl/fault.c b/drivers/misc/cxl/fault.c index 01153b74334a..60c829113299 100644 --- a/drivers/misc/cxl/fault.c +++ b/drivers/misc/cxl/fault.c @@ -200,7 +200,7 @@ static struct mm_struct *get_mem_context(struct cxl_context *ctx) if (ctx->mm == NULL) return NULL; - if (!atomic_inc_not_zero(&ctx->mm->mm_users)) + if (!mmget_not_zero(ctx->mm)) return NULL; return ctx->mm; -- cgit v1.2.3 From 1c15b334ca34dd22a19e1c595908fc860523be64 Mon Sep 17 00:00:00 2001 From: Shuo Liu Date: Thu, 11 Mar 2021 09:52:06 +0800 Subject: virt: acrn: Fix document of acrn_msi_inject() This fixes below build warning with extra build checks. $ make W=1 ../drivers/virt/acrn/vm.c:105: warning: expecting prototype for acrn_inject_msi(). Prototype was for acrn_msi_inject() instead Fixes: c7cf8d27244f ("virt: acrn: Introduce interrupt injection interfaces") Signed-off-by: Shuo Liu Link: https://lore.kernel.org/r/20210311015206.19715-1-shuo.a.liu@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/virt/acrn/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/virt/acrn/vm.c b/drivers/virt/acrn/vm.c index 7804a2492ad7..0d002a355a93 100644 --- a/drivers/virt/acrn/vm.c +++ b/drivers/virt/acrn/vm.c @@ -94,7 +94,7 @@ int acrn_vm_destroy(struct acrn_vm *vm) } /** - * acrn_inject_msi() - Inject a MSI interrupt into a User VM + * acrn_msi_inject() - Inject a MSI interrupt into a User VM * @vm: User VM * @msi_addr: The MSI address * @msi_data: The MSI data -- cgit v1.2.3 From f6d706dd9baaa1d7857ce5b03af491718a95e9bf Mon Sep 17 00:00:00 2001 From: Yang Li Date: Wed, 10 Mar 2021 17:00:34 +0800 Subject: char/mwave: turn tp3780I_Cleanup() into void function This function always return '0' and no callers use the return value. So make it a void function. This eliminates the following coccicheck warning: ./drivers/char/mwave/tp3780i.c:182:5-11: Unneeded variable: "retval". Return "0" on line 187 Reported-by: Abaci Robot Signed-off-by: Yang Li Link: https://lore.kernel.org/r/1615366834-20545-1-git-send-email-yang.lee@linux.alibaba.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/mwave/tp3780i.c | 6 +----- drivers/char/mwave/tp3780i.h | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/char/mwave/tp3780i.c b/drivers/char/mwave/tp3780i.c index 5e1618a76b2a..8588b51202e5 100644 --- a/drivers/char/mwave/tp3780i.c +++ b/drivers/char/mwave/tp3780i.c @@ -177,14 +177,10 @@ int tp3780I_InitializeBoardData(THINKPAD_BD_DATA * pBDData) return retval; } -int tp3780I_Cleanup(THINKPAD_BD_DATA * pBDData) +void tp3780I_Cleanup(THINKPAD_BD_DATA *pBDData) { - int retval = 0; - PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_Cleanup entry and exit pBDData %p\n", pBDData); - - return retval; } int tp3780I_CalcResources(THINKPAD_BD_DATA * pBDData) diff --git a/drivers/char/mwave/tp3780i.h b/drivers/char/mwave/tp3780i.h index 07685b68538f..8bd976d42fae 100644 --- a/drivers/char/mwave/tp3780i.h +++ b/drivers/char/mwave/tp3780i.h @@ -91,7 +91,7 @@ int tp3780I_DisableDSP(THINKPAD_BD_DATA * pBDData); int tp3780I_ResetDSP(THINKPAD_BD_DATA * pBDData); int tp3780I_StartDSP(THINKPAD_BD_DATA * pBDData); int tp3780I_QueryAbilities(THINKPAD_BD_DATA * pBDData, MW_ABILITIES * pAbilities); -int tp3780I_Cleanup(THINKPAD_BD_DATA * pBDData); +void tp3780I_Cleanup(THINKPAD_BD_DATA *pBDData); int tp3780I_ReadWriteDspDStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode, void __user *pvBuffer, unsigned int uCount, unsigned long ulDSPAddr); -- cgit v1.2.3 From 199c4d0efe7d9e5ed0036efeeb8ddb862dafe09a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 9 Mar 2021 19:06:52 +0300 Subject: w1: w1_therm: use clamp() in int_to_short() It's slightly cleaner to use the clamp() macro instead of open coding this. Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/YEedHNwqEH8fvjkD@mwanda Signed-off-by: Greg Kroah-Hartman --- drivers/w1/slaves/w1_therm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c index 976eea28f268..ad47c164bc05 100644 --- a/drivers/w1/slaves/w1_therm.c +++ b/drivers/w1/slaves/w1_therm.c @@ -906,8 +906,7 @@ static inline int temperature_from_RAM(struct w1_slave *sl, u8 rom[9]) static inline s8 int_to_short(int i) { /* Prepare to cast to short by eliminating out of range values */ - i = i > MAX_TEMP ? MAX_TEMP : i; - i = i < MIN_TEMP ? MIN_TEMP : i; + i = clamp(i, MIN_TEMP, MAX_TEMP); return (s8) i; } -- cgit v1.2.3 From b0ebbaeee3d78a68d3413bdaeb707e527c5d4dbe Mon Sep 17 00:00:00 2001 From: dongjian Date: Tue, 16 Mar 2021 14:59:47 +0800 Subject: w1: Use kobj_to_dev()[RESEND] Use kobj_to_dev() instead of open-coding it Signed-off-by: dongjian Link: https://lore.kernel.org/r/1615877987-32163-1-git-send-email-dj0227@163.com Signed-off-by: Greg Kroah-Hartman --- drivers/w1/slaves/w1_ds2780.c | 2 +- drivers/w1/slaves/w1_ds2781.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/w1/slaves/w1_ds2780.c b/drivers/w1/slaves/w1_ds2780.c index c281fe5ed688..9dcb5a54f7fc 100644 --- a/drivers/w1/slaves/w1_ds2780.c +++ b/drivers/w1/slaves/w1_ds2780.c @@ -90,7 +90,7 @@ static ssize_t w1_slave_read(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); return w1_ds2780_io(dev, buf, off, count, 0); } diff --git a/drivers/w1/slaves/w1_ds2781.c b/drivers/w1/slaves/w1_ds2781.c index f0d393ae070b..2cb7c020b607 100644 --- a/drivers/w1/slaves/w1_ds2781.c +++ b/drivers/w1/slaves/w1_ds2781.c @@ -87,7 +87,7 @@ static ssize_t w1_slave_read(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); return w1_ds2781_io(dev, buf, off, count, 0); } -- cgit v1.2.3 From d8da00e1a73e9577538242fb5a89c560c497369c Mon Sep 17 00:00:00 2001 From: Bhaskar Chowdhury Date: Fri, 19 Mar 2021 10:55:54 +0530 Subject: w1: slaves: Typo fixes s/mesured/measured/ .......twice Acked-by: Randy Dunlap Signed-off-by: Bhaskar Chowdhury Link: https://lore.kernel.org/r/20210319052554.966-1-unixbhaskar@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/w1/slaves/w1_therm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c index ad47c164bc05..9d08a1c9c445 100644 --- a/drivers/w1/slaves/w1_therm.c +++ b/drivers/w1/slaves/w1_therm.c @@ -63,8 +63,8 @@ static u16 bulk_read_device_counter; /* =0 as per C standard */ #define EEPROM_CMD_READ "restore" /* cmd for read eeprom sysfs */ #define BULK_TRIGGER_CMD "trigger" /* cmd to trigger a bulk read */ -#define MIN_TEMP -55 /* min temperature that can be mesured */ -#define MAX_TEMP 125 /* max temperature that can be mesured */ +#define MIN_TEMP -55 /* min temperature that can be measured */ +#define MAX_TEMP 125 /* max temperature that can be measured */ /* Allowed values for sysfs conv_time attribute */ #define CONV_TIME_DEFAULT 0 -- cgit v1.2.3 From ac41ae0b12c83229f2b1102c4ed9ad96bf8de946 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Tue, 16 Mar 2021 16:57:21 +0800 Subject: misc/sgi-xp: use NULL instead of using plain integer as pointer This fixes the following sparse warnings: drivers/misc/sgi-xp/xpc_main.c:210:23: warning: Using plain integer as NULL pointer Reported-by: Abaci Robot Reviewed-by: Steve Wahl Signed-off-by: Yang Li Link: https://lore.kernel.org/r/1615885041-68750-1-git-send-email-yang.lee@linux.alibaba.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/sgi-xp/xpc_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index 84610bbcc131..b2c3c22fc13c 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -207,7 +207,7 @@ xpc_start_hb_beater(void) { xpc_arch_ops.heartbeat_init(); timer_setup(&xpc_hb_timer, xpc_hb_beater, 0); - xpc_hb_beater(0); + xpc_hb_beater(NULL); } static void -- cgit v1.2.3 From 7b7d2261aa8dce949c08d58ed1d02e54a0fbbab5 Mon Sep 17 00:00:00 2001 From: Gleb Fotengauer-Malinovskiy Date: Tue, 2 Mar 2021 18:33:46 +0300 Subject: vmci_host: print unexpanded names of ioctl requests in debug messages __stringify macro function expands its arguments, but in this messages we expect to see ioctl request name instead of it's _IOC macro expansion. $ cat stringify.c #include #include #define __stringify_1(x) #x #define __stringify(x) __stringify_1(x) #define VMCI_DO_IOCTL(ioctl_name) \ char *name = __stringify(IOCTL_VMCI_ ## ioctl_name); int main() { VMCI_DO_IOCTL(INIT_CONTEXT) printf("%s\n", name); } $ cc stringify.c $ ./a.out (((0U) << (((0+8)+8)+14)) | (((7)) << (0+8)) | (((0xa0)) << 0) | ((0) << ((0+8)+8))) Signed-off-by: Gleb Fotengauer-Malinovskiy Link: https://lore.kernel.org/r/20210302153346.300416-1-glebfm@altlinux.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/vmw_vmci/vmci_host.c b/drivers/misc/vmw_vmci/vmci_host.c index 2d8328d928d5..da1e2a773823 100644 --- a/drivers/misc/vmw_vmci/vmci_host.c +++ b/drivers/misc/vmw_vmci/vmci_host.c @@ -908,7 +908,7 @@ static long vmci_host_unlocked_ioctl(struct file *filp, unsigned int iocmd, unsigned long ioarg) { #define VMCI_DO_IOCTL(ioctl_name, ioctl_fn) do { \ - char *name = __stringify(IOCTL_VMCI_ ## ioctl_name); \ + char *name = "IOCTL_VMCI_" # ioctl_name; \ return vmci_host_do_ ## ioctl_fn( \ vmci_host_dev, name, uptr); \ } while (0) -- cgit v1.2.3 From 432ff1e91694e4c55a5bf6bc0574f4c254970232 Mon Sep 17 00:00:00 2001 From: Marco Ballesio Date: Mon, 15 Mar 2021 18:16:28 -0700 Subject: binder: BINDER_FREEZE ioctl Frozen tasks can't process binder transactions, so a way is required to inform transmitting ends of communication failures due to the frozen state of their receiving counterparts. Additionally, races are possible between transitions to frozen state and binder transactions enqueued to a specific process. Implement BINDER_FREEZE ioctl for user space to inform the binder driver about the intention to freeze or unfreeze a process. When the ioctl is called, block the caller until any pending binder transactions toward the target process are flushed. Return an error to transactions to processes marked as frozen. Co-developed-by: Todd Kjos Acked-by: Todd Kjos Signed-off-by: Marco Ballesio Signed-off-by: Todd Kjos Signed-off-by: Li Li Link: https://lore.kernel.org/r/20210316011630.1121213-2-dualli@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 139 +++++++++++++++++++++++++++++++++--- drivers/android/binder_internal.h | 12 ++++ include/uapi/linux/android/binder.h | 13 ++++ 3 files changed, 154 insertions(+), 10 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index c119736ca56a..b93ca53bb90f 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -1506,6 +1506,12 @@ static void binder_free_transaction(struct binder_transaction *t) if (target_proc) { binder_inner_proc_lock(target_proc); + target_proc->outstanding_txns--; + if (target_proc->outstanding_txns < 0) + pr_warn("%s: Unexpected outstanding_txns %d\n", + __func__, target_proc->outstanding_txns); + if (!target_proc->outstanding_txns && target_proc->is_frozen) + wake_up_interruptible_all(&target_proc->freeze_wait); if (t->buffer) t->buffer->transaction = NULL; binder_inner_proc_unlock(target_proc); @@ -2331,10 +2337,11 @@ static int binder_fixup_parent(struct binder_transaction *t, * If the @thread parameter is not NULL, the transaction is always queued * to the waitlist of that specific thread. * - * Return: true if the transactions was successfully queued - * false if the target process or thread is dead + * Return: 0 if the transaction was successfully queued + * BR_DEAD_REPLY if the target process or thread is dead + * BR_FROZEN_REPLY if the target process or thread is frozen */ -static bool binder_proc_transaction(struct binder_transaction *t, +static int binder_proc_transaction(struct binder_transaction *t, struct binder_proc *proc, struct binder_thread *thread) { @@ -2354,10 +2361,11 @@ static bool binder_proc_transaction(struct binder_transaction *t, binder_inner_proc_lock(proc); - if (proc->is_dead || (thread && thread->is_dead)) { + if ((proc->is_frozen && !oneway) || proc->is_dead || + (thread && thread->is_dead)) { binder_inner_proc_unlock(proc); binder_node_unlock(node); - return false; + return proc->is_frozen ? BR_FROZEN_REPLY : BR_DEAD_REPLY; } if (!thread && !pending_async) @@ -2373,10 +2381,11 @@ static bool binder_proc_transaction(struct binder_transaction *t, if (!pending_async) binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */); + proc->outstanding_txns++; binder_inner_proc_unlock(proc); binder_node_unlock(node); - return true; + return 0; } /** @@ -3013,13 +3022,16 @@ static void binder_transaction(struct binder_proc *proc, if (reply) { binder_enqueue_thread_work(thread, tcomplete); binder_inner_proc_lock(target_proc); - if (target_thread->is_dead) { + if (target_thread->is_dead || target_proc->is_frozen) { + return_error = target_thread->is_dead ? + BR_DEAD_REPLY : BR_FROZEN_REPLY; binder_inner_proc_unlock(target_proc); goto err_dead_proc_or_thread; } BUG_ON(t->buffer->async_transaction != 0); binder_pop_transaction_ilocked(target_thread, in_reply_to); binder_enqueue_thread_work_ilocked(target_thread, &t->work); + target_proc->outstanding_txns++; binder_inner_proc_unlock(target_proc); wake_up_interruptible_sync(&target_thread->wait); binder_free_transaction(in_reply_to); @@ -3038,7 +3050,9 @@ static void binder_transaction(struct binder_proc *proc, t->from_parent = thread->transaction_stack; thread->transaction_stack = t; binder_inner_proc_unlock(proc); - if (!binder_proc_transaction(t, target_proc, target_thread)) { + return_error = binder_proc_transaction(t, + target_proc, target_thread); + if (return_error) { binder_inner_proc_lock(proc); binder_pop_transaction_ilocked(thread, t); binder_inner_proc_unlock(proc); @@ -3048,7 +3062,8 @@ static void binder_transaction(struct binder_proc *proc, BUG_ON(target_node == NULL); BUG_ON(t->buffer->async_transaction != 1); binder_enqueue_thread_work(thread, tcomplete); - if (!binder_proc_transaction(t, target_proc, NULL)) + return_error = binder_proc_transaction(t, target_proc, NULL); + if (return_error) goto err_dead_proc_or_thread; } if (target_thread) @@ -3065,7 +3080,6 @@ static void binder_transaction(struct binder_proc *proc, return; err_dead_proc_or_thread: - return_error = BR_DEAD_REPLY; return_error_line = __LINE__; binder_dequeue_work(proc, tcomplete); err_translate_failed: @@ -4298,6 +4312,9 @@ static void binder_free_proc(struct binder_proc *proc) BUG_ON(!list_empty(&proc->todo)); BUG_ON(!list_empty(&proc->delivered_death)); + if (proc->outstanding_txns) + pr_warn("%s: Unexpected outstanding_txns %d\n", + __func__, proc->outstanding_txns); device = container_of(proc->context, struct binder_device, context); if (refcount_dec_and_test(&device->ref)) { kfree(proc->context->name); @@ -4359,6 +4376,7 @@ static int binder_thread_release(struct binder_proc *proc, (t->to_thread == thread) ? "in" : "out"); if (t->to_thread == thread) { + thread->proc->outstanding_txns--; t->to_proc = NULL; t->to_thread = NULL; if (t->buffer) { @@ -4609,6 +4627,45 @@ static int binder_ioctl_get_node_debug_info(struct binder_proc *proc, return 0; } +static int binder_ioctl_freeze(struct binder_freeze_info *info, + struct binder_proc *target_proc) +{ + int ret = 0; + + if (!info->enable) { + binder_inner_proc_lock(target_proc); + target_proc->is_frozen = false; + binder_inner_proc_unlock(target_proc); + return 0; + } + + /* + * Freezing the target. Prevent new transactions by + * setting frozen state. If timeout specified, wait + * for transactions to drain. + */ + binder_inner_proc_lock(target_proc); + target_proc->is_frozen = true; + binder_inner_proc_unlock(target_proc); + + if (info->timeout_ms > 0) + ret = wait_event_interruptible_timeout( + target_proc->freeze_wait, + (!target_proc->outstanding_txns), + msecs_to_jiffies(info->timeout_ms)); + + if (!ret && target_proc->outstanding_txns) + ret = -EAGAIN; + + if (ret < 0) { + binder_inner_proc_lock(target_proc); + target_proc->is_frozen = false; + binder_inner_proc_unlock(target_proc); + } + + return ret; +} + static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int ret; @@ -4727,6 +4784,66 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; } + case BINDER_FREEZE: { + struct binder_freeze_info info; + struct binder_proc **target_procs = NULL, *target_proc; + int target_procs_count = 0, i = 0; + + ret = 0; + + if (copy_from_user(&info, ubuf, sizeof(info))) { + ret = -EFAULT; + goto err; + } + + mutex_lock(&binder_procs_lock); + hlist_for_each_entry(target_proc, &binder_procs, proc_node) { + if (target_proc->pid == info.pid) + target_procs_count++; + } + + if (target_procs_count == 0) { + mutex_unlock(&binder_procs_lock); + ret = -EINVAL; + goto err; + } + + target_procs = kcalloc(target_procs_count, + sizeof(struct binder_proc *), + GFP_KERNEL); + + if (!target_procs) { + mutex_unlock(&binder_procs_lock); + ret = -ENOMEM; + goto err; + } + + hlist_for_each_entry(target_proc, &binder_procs, proc_node) { + if (target_proc->pid != info.pid) + continue; + + binder_inner_proc_lock(target_proc); + target_proc->tmp_ref++; + binder_inner_proc_unlock(target_proc); + + target_procs[i++] = target_proc; + } + mutex_unlock(&binder_procs_lock); + + for (i = 0; i < target_procs_count; i++) { + if (ret >= 0) + ret = binder_ioctl_freeze(&info, + target_procs[i]); + + binder_proc_dec_tmpref(target_procs[i]); + } + + kfree(target_procs); + + if (ret < 0) + goto err; + break; + } default: ret = -EINVAL; goto err; @@ -4823,6 +4940,7 @@ static int binder_open(struct inode *nodp, struct file *filp) get_task_struct(current->group_leader); proc->tsk = current->group_leader; INIT_LIST_HEAD(&proc->todo); + init_waitqueue_head(&proc->freeze_wait); proc->default_priority = task_nice(current); /* binderfs stashes devices in i_private */ if (is_binderfs_device(nodp)) { @@ -5035,6 +5153,7 @@ static void binder_deferred_release(struct binder_proc *proc) proc->tmp_ref++; proc->is_dead = true; + proc->is_frozen = false; threads = 0; active_transactions = 0; while ((n = rb_first(&proc->threads))) { diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h index 6cd79011e35d..e6a53e98c6da 100644 --- a/drivers/android/binder_internal.h +++ b/drivers/android/binder_internal.h @@ -367,9 +367,18 @@ struct binder_ref { * (protected by binder_deferred_lock) * @deferred_work: bitmap of deferred work to perform * (protected by binder_deferred_lock) + * @outstanding_txns: number of transactions to be transmitted before + * processes in freeze_wait are woken up + * (protected by @inner_lock) * @is_dead: process is dead and awaiting free * when outstanding transactions are cleaned up * (protected by @inner_lock) + * @is_frozen: process is frozen and unable to service + * binder transactions + * (protected by @inner_lock) + * @freeze_wait: waitqueue of processes waiting for all outstanding + * transactions to be processed + * (protected by @inner_lock) * @todo: list of work for this process * (protected by @inner_lock) * @stats: per-process binder statistics @@ -410,7 +419,10 @@ struct binder_proc { struct task_struct *tsk; struct hlist_node deferred_work_node; int deferred_work; + int outstanding_txns; bool is_dead; + bool is_frozen; + wait_queue_head_t freeze_wait; struct list_head todo; struct binder_stats stats; diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h index ec84ad106568..7eb5b818b3c1 100644 --- a/include/uapi/linux/android/binder.h +++ b/include/uapi/linux/android/binder.h @@ -217,6 +217,12 @@ struct binder_node_info_for_ref { __u32 reserved3; }; +struct binder_freeze_info { + __u32 pid; + __u32 enable; + __u32 timeout_ms; +}; + #define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) #define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64) #define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32) @@ -227,6 +233,7 @@ struct binder_node_info_for_ref { #define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info) #define BINDER_GET_NODE_INFO_FOR_REF _IOWR('b', 12, struct binder_node_info_for_ref) #define BINDER_SET_CONTEXT_MGR_EXT _IOW('b', 13, struct flat_binder_object) +#define BINDER_FREEZE _IOW('b', 14, struct binder_freeze_info) /* * NOTE: Two special error codes you should check for when calling @@ -408,6 +415,12 @@ enum binder_driver_return_protocol { * The last transaction (either a bcTRANSACTION or * a bcATTEMPT_ACQUIRE) failed (e.g. out of memory). No parameters. */ + + BR_FROZEN_REPLY = _IO('r', 18), + /* + * The target of the last transaction (either a bcTRANSACTION or + * a bcATTEMPT_ACQUIRE) is frozen. No parameters. + */ }; enum binder_driver_command_protocol { -- cgit v1.2.3 From 95c16f9d9cf9db090ae16179f1f721284a6f3aef Mon Sep 17 00:00:00 2001 From: Marco Ballesio Date: Mon, 15 Mar 2021 18:16:29 -0700 Subject: binder: use EINTR for interrupted wait for work when interrupted by a signal, binder_wait_for_work currently returns -ERESTARTSYS. This error code isn't propagated to user space, but a way to handle interruption due to signals must be provided to code using this API. Replace this instance of -ERESTARTSYS with -EINTR, which is propagated to user space. binder_wait_for_work Signed-off-by: Marco Ballesio Signed-off-by: Li Li Test: built, booted, interrupted a worker thread within Acked-by: Todd Kjos Link: https://lore.kernel.org/r/20210316011630.1121213-3-dualli@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index b93ca53bb90f..fe16c455a76e 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3710,7 +3710,7 @@ static int binder_wait_for_work(struct binder_thread *thread, binder_inner_proc_lock(proc); list_del_init(&thread->waiting_thread_node); if (signal_pending(current)) { - ret = -ERESTARTSYS; + ret = -EINTR; break; } } @@ -4853,7 +4853,7 @@ err: if (thread) thread->looper_need_return = false; wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); - if (ret && ret != -ERESTARTSYS) + if (ret && ret != -EINTR) pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret); err_unlocked: trace_binder_ioctl_done(ret); -- cgit v1.2.3 From ae28c1be1e54f2eda1c8b4469c4652e8a24056ed Mon Sep 17 00:00:00 2001 From: Marco Ballesio Date: Mon, 15 Mar 2021 18:16:30 -0700 Subject: binder: BINDER_GET_FROZEN_INFO ioctl User space needs to know if binder transactions occurred to frozen processes. Introduce a new BINDER_GET_FROZEN ioctl and keep track of transactions occurring to frozen proceses. Signed-off-by: Marco Ballesio Signed-off-by: Li Li Acked-by: Todd Kjos Link: https://lore.kernel.org/r/20210316011630.1121213-4-dualli@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 55 +++++++++++++++++++++++++++++++++++++ drivers/android/binder_internal.h | 6 ++++ include/uapi/linux/android/binder.h | 7 +++++ 3 files changed, 68 insertions(+) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index fe16c455a76e..e1a484ab0366 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -2360,6 +2360,10 @@ static int binder_proc_transaction(struct binder_transaction *t, } binder_inner_proc_lock(proc); + if (proc->is_frozen) { + proc->sync_recv |= !oneway; + proc->async_recv |= oneway; + } if ((proc->is_frozen && !oneway) || proc->is_dead || (thread && thread->is_dead)) { @@ -4634,6 +4638,8 @@ static int binder_ioctl_freeze(struct binder_freeze_info *info, if (!info->enable) { binder_inner_proc_lock(target_proc); + target_proc->sync_recv = false; + target_proc->async_recv = false; target_proc->is_frozen = false; binder_inner_proc_unlock(target_proc); return 0; @@ -4645,6 +4651,8 @@ static int binder_ioctl_freeze(struct binder_freeze_info *info, * for transactions to drain. */ binder_inner_proc_lock(target_proc); + target_proc->sync_recv = false; + target_proc->async_recv = false; target_proc->is_frozen = true; binder_inner_proc_unlock(target_proc); @@ -4666,6 +4674,33 @@ static int binder_ioctl_freeze(struct binder_freeze_info *info, return ret; } +static int binder_ioctl_get_freezer_info( + struct binder_frozen_status_info *info) +{ + struct binder_proc *target_proc; + bool found = false; + + info->sync_recv = 0; + info->async_recv = 0; + + mutex_lock(&binder_procs_lock); + hlist_for_each_entry(target_proc, &binder_procs, proc_node) { + if (target_proc->pid == info->pid) { + found = true; + binder_inner_proc_lock(target_proc); + info->sync_recv |= target_proc->sync_recv; + info->async_recv |= target_proc->async_recv; + binder_inner_proc_unlock(target_proc); + } + } + mutex_unlock(&binder_procs_lock); + + if (!found) + return -EINVAL; + + return 0; +} + static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int ret; @@ -4844,6 +4879,24 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) goto err; break; } + case BINDER_GET_FROZEN_INFO: { + struct binder_frozen_status_info info; + + if (copy_from_user(&info, ubuf, sizeof(info))) { + ret = -EFAULT; + goto err; + } + + ret = binder_ioctl_get_freezer_info(&info); + if (ret < 0) + goto err; + + if (copy_to_user(ubuf, &info, sizeof(info))) { + ret = -EFAULT; + goto err; + } + break; + } default: ret = -EINVAL; goto err; @@ -5154,6 +5207,8 @@ static void binder_deferred_release(struct binder_proc *proc) proc->is_dead = true; proc->is_frozen = false; + proc->sync_recv = false; + proc->async_recv = false; threads = 0; active_transactions = 0; while ((n = rb_first(&proc->threads))) { diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h index e6a53e98c6da..2872a7de68e1 100644 --- a/drivers/android/binder_internal.h +++ b/drivers/android/binder_internal.h @@ -376,6 +376,10 @@ struct binder_ref { * @is_frozen: process is frozen and unable to service * binder transactions * (protected by @inner_lock) + * @sync_recv: process received sync transactions since last frozen + * (protected by @inner_lock) + * @async_recv: process received async transactions since last frozen + * (protected by @inner_lock) * @freeze_wait: waitqueue of processes waiting for all outstanding * transactions to be processed * (protected by @inner_lock) @@ -422,6 +426,8 @@ struct binder_proc { int outstanding_txns; bool is_dead; bool is_frozen; + bool sync_recv; + bool async_recv; wait_queue_head_t freeze_wait; struct list_head todo; diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h index 7eb5b818b3c1..156070d18c4f 100644 --- a/include/uapi/linux/android/binder.h +++ b/include/uapi/linux/android/binder.h @@ -223,6 +223,12 @@ struct binder_freeze_info { __u32 timeout_ms; }; +struct binder_frozen_status_info { + __u32 pid; + __u32 sync_recv; + __u32 async_recv; +}; + #define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) #define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64) #define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32) @@ -234,6 +240,7 @@ struct binder_freeze_info { #define BINDER_GET_NODE_INFO_FOR_REF _IOWR('b', 12, struct binder_node_info_for_ref) #define BINDER_SET_CONTEXT_MGR_EXT _IOW('b', 13, struct flat_binder_object) #define BINDER_FREEZE _IOW('b', 14, struct binder_freeze_info) +#define BINDER_GET_FROZEN_INFO _IOWR('b', 15, struct binder_frozen_status_info) /* * NOTE: Two special error codes you should check for when calling -- cgit v1.2.3 From a4780db3ad13b5381e0512b4507857390efea963 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 18 Mar 2021 15:03:15 +0200 Subject: pps: clients: gpio: Bail out on error when requesting GPIO echo line When requesting optional GPIO echo line, bail out on error, so user will know that something wrong with the existing property. Acked-by: Rodolfo Giometti Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210318130321.24227-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/pps/clients/pps-gpio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c index e0de1df2ede0..f89c31aa66f1 100644 --- a/drivers/pps/clients/pps-gpio.c +++ b/drivers/pps/clients/pps-gpio.c @@ -119,12 +119,12 @@ static int pps_gpio_setup(struct platform_device *pdev) data->echo_pin = devm_gpiod_get_optional(&pdev->dev, "echo", GPIOD_OUT_LOW); - if (data->echo_pin) { - if (IS_ERR(data->echo_pin)) { - dev_err(&pdev->dev, "failed to request ECHO GPIO\n"); - return PTR_ERR(data->echo_pin); - } + if (IS_ERR(data->echo_pin)) { + dev_err(&pdev->dev, "failed to request ECHO GPIO\n"); + return PTR_ERR(data->echo_pin); + } + if (data->echo_pin) { ret = of_property_read_u32(np, "echo-active-ms", &value); -- cgit v1.2.3 From 1a8fc4f7e21ce786f8ebdf26d631e6f359ff9dfd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 18 Mar 2021 15:03:16 +0200 Subject: pps: clients: gpio: Use dev_err_probe() to avoid log noise When GPIO APIs return -EPROBE_DEFER there is no need to print the message, especially taking into consideration that it may repeat several times. Use dev_err_probe() to avoid log noise in such cases. Acked-by: Rodolfo Giometti Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210318130321.24227-2-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/pps/clients/pps-gpio.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c index f89c31aa66f1..78c9680e8063 100644 --- a/drivers/pps/clients/pps-gpio.c +++ b/drivers/pps/clients/pps-gpio.c @@ -110,19 +110,16 @@ static int pps_gpio_setup(struct platform_device *pdev) data->gpio_pin = devm_gpiod_get(&pdev->dev, NULL, /* request "gpios" */ GPIOD_IN); - if (IS_ERR(data->gpio_pin)) { - dev_err(&pdev->dev, - "failed to request PPS GPIO\n"); - return PTR_ERR(data->gpio_pin); - } + if (IS_ERR(data->gpio_pin)) + return dev_err_probe(&pdev->dev, PTR_ERR(data->gpio_pin), + "failed to request PPS GPIO\n"); data->echo_pin = devm_gpiod_get_optional(&pdev->dev, "echo", GPIOD_OUT_LOW); - if (IS_ERR(data->echo_pin)) { - dev_err(&pdev->dev, "failed to request ECHO GPIO\n"); - return PTR_ERR(data->echo_pin); - } + if (IS_ERR(data->echo_pin)) + return dev_err_probe(&pdev->dev, PTR_ERR(data->echo_pin), + "failed to request ECHO GPIO\n"); if (data->echo_pin) { ret = of_property_read_u32(np, -- cgit v1.2.3 From fde046a8c490e296aacbb628748664fa54b6bdde Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 18 Mar 2021 15:03:17 +0200 Subject: pps: clients: gpio: Remove redundant condition in ->remove() The timer along with GPIO API are NULL-aware, there is no need to test against existing GPIO echo line. Acked-by: Rodolfo Giometti Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210318130321.24227-3-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/pps/clients/pps-gpio.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c index 78c9680e8063..dc9ed6fc3dae 100644 --- a/drivers/pps/clients/pps-gpio.c +++ b/drivers/pps/clients/pps-gpio.c @@ -240,11 +240,9 @@ static int pps_gpio_remove(struct platform_device *pdev) struct pps_gpio_device_data *data = platform_get_drvdata(pdev); pps_unregister_source(data->pps); - if (data->echo_pin) { - del_timer_sync(&data->echo_timer); - /* reset echo pin in any case */ - gpiod_set_value(data->echo_pin, 0); - } + del_timer_sync(&data->echo_timer); + /* reset echo pin in any case */ + gpiod_set_value(data->echo_pin, 0); dev_info(&pdev->dev, "removed IRQ %d as PPS source\n", data->irq); return 0; } -- cgit v1.2.3 From ee89646619ba07d054348c0240da4b953cd1e72f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 18 Mar 2021 15:03:18 +0200 Subject: pps: clients: gpio: Get rid of legacy platform data Platform data is a legacy interface to supply device properties to the driver. In this case we even don't have in-kernel users for it. Just remove it for good. Acked-by: Rodolfo Giometti Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210318130321.24227-4-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/pps/clients/pps-gpio.c | 17 +++-------------- include/linux/pps-gpio.h | 19 ------------------- 2 files changed, 3 insertions(+), 33 deletions(-) delete mode 100644 include/linux/pps-gpio.h diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c index dc9ed6fc3dae..291240dce79e 100644 --- a/drivers/pps/clients/pps-gpio.c +++ b/drivers/pps/clients/pps-gpio.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -164,7 +163,6 @@ static int pps_gpio_probe(struct platform_device *pdev) struct pps_gpio_device_data *data; int ret; int pps_default_params; - const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data; /* allocate space for device info */ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); @@ -173,18 +171,9 @@ static int pps_gpio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); /* GPIO setup */ - if (pdata) { - data->gpio_pin = pdata->gpio_pin; - data->echo_pin = pdata->echo_pin; - - data->assert_falling_edge = pdata->assert_falling_edge; - data->capture_clear = pdata->capture_clear; - data->echo_active_ms = pdata->echo_active_ms; - } else { - ret = pps_gpio_setup(pdev); - if (ret) - return -EINVAL; - } + ret = pps_gpio_setup(pdev); + if (ret) + return -EINVAL; /* IRQ setup */ ret = gpiod_to_irq(data->gpio_pin); diff --git a/include/linux/pps-gpio.h b/include/linux/pps-gpio.h deleted file mode 100644 index 7bf49908be06..000000000000 --- a/include/linux/pps-gpio.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * pps-gpio.h -- PPS client for GPIOs - * - * Copyright (C) 2011 James Nuss - */ - -#ifndef _PPS_GPIO_H -#define _PPS_GPIO_H - -struct pps_gpio_platform_data { - struct gpio_desc *gpio_pin; - struct gpio_desc *echo_pin; - bool assert_falling_edge; - bool capture_clear; - unsigned int echo_active_ms; -}; - -#endif /* _PPS_GPIO_H */ -- cgit v1.2.3 From 28d032510e6338b93db485e4b514d7bb996b9d33 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 18 Mar 2021 15:03:19 +0200 Subject: pps: clients: gpio: Make use of device properties Device property API allows to gather device resources from different sources, such as ACPI. Convert the drivers to unleash the power of device property API. Acked-by: Rodolfo Giometti Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210318130321.24227-5-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/pps/clients/pps-gpio.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c index 291240dce79e..c6db3a3b257b 100644 --- a/drivers/pps/clients/pps-gpio.c +++ b/drivers/pps/clients/pps-gpio.c @@ -12,14 +12,14 @@ #include #include #include +#include #include #include #include #include #include #include -#include -#include +#include #include #include @@ -102,7 +102,6 @@ static void pps_gpio_echo_timer_callback(struct timer_list *t) static int pps_gpio_setup(struct platform_device *pdev) { struct pps_gpio_device_data *data = platform_get_drvdata(pdev); - struct device_node *np = pdev->dev.of_node; int ret; u32 value; @@ -121,26 +120,24 @@ static int pps_gpio_setup(struct platform_device *pdev) "failed to request ECHO GPIO\n"); if (data->echo_pin) { - ret = of_property_read_u32(np, - "echo-active-ms", - &value); + ret = device_property_read_u32(&pdev->dev, "echo-active-ms", &value); if (ret) { dev_err(&pdev->dev, - "failed to get echo-active-ms from OF\n"); + "failed to get echo-active-ms from FW\n"); return ret; } data->echo_active_ms = value; /* sanity check on echo_active_ms */ if (!data->echo_active_ms || data->echo_active_ms > 999) { dev_err(&pdev->dev, - "echo-active-ms: %u - bad value from OF\n", + "echo-active-ms: %u - bad value from FW\n", data->echo_active_ms); return -EINVAL; } } - if (of_property_read_bool(np, "assert-falling-edge")) - data->assert_falling_edge = true; + data->assert_falling_edge = + device_property_read_bool(&pdev->dev, "assert-falling-edge"); return 0; } -- cgit v1.2.3 From 162a5deac67450310ce5a6f37882acda010eddda Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 18 Mar 2021 15:03:20 +0200 Subject: pps: clients: gpio: Use struct device pointer directly In most parts of the code the platform device is not used. Use struct device pointer directly to reduce code size and increase readability. Acked-by: Rodolfo Giometti Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210318130321.24227-6-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/pps/clients/pps-gpio.c | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c index c6db3a3b257b..b097da5a659a 100644 --- a/drivers/pps/clients/pps-gpio.c +++ b/drivers/pps/clients/pps-gpio.c @@ -99,45 +99,39 @@ static void pps_gpio_echo_timer_callback(struct timer_list *t) gpiod_set_value(info->echo_pin, 0); } -static int pps_gpio_setup(struct platform_device *pdev) +static int pps_gpio_setup(struct device *dev) { - struct pps_gpio_device_data *data = platform_get_drvdata(pdev); + struct pps_gpio_device_data *data = dev_get_drvdata(dev); int ret; u32 value; - data->gpio_pin = devm_gpiod_get(&pdev->dev, - NULL, /* request "gpios" */ - GPIOD_IN); + data->gpio_pin = devm_gpiod_get(dev, NULL, GPIOD_IN); if (IS_ERR(data->gpio_pin)) - return dev_err_probe(&pdev->dev, PTR_ERR(data->gpio_pin), + return dev_err_probe(dev, PTR_ERR(data->gpio_pin), "failed to request PPS GPIO\n"); - data->echo_pin = devm_gpiod_get_optional(&pdev->dev, - "echo", - GPIOD_OUT_LOW); + data->echo_pin = devm_gpiod_get_optional(dev, "echo", GPIOD_OUT_LOW); if (IS_ERR(data->echo_pin)) - return dev_err_probe(&pdev->dev, PTR_ERR(data->echo_pin), + return dev_err_probe(dev, PTR_ERR(data->echo_pin), "failed to request ECHO GPIO\n"); if (data->echo_pin) { - ret = device_property_read_u32(&pdev->dev, "echo-active-ms", &value); + ret = device_property_read_u32(dev, "echo-active-ms", &value); if (ret) { - dev_err(&pdev->dev, - "failed to get echo-active-ms from FW\n"); + dev_err(dev, "failed to get echo-active-ms from FW\n"); return ret; } data->echo_active_ms = value; /* sanity check on echo_active_ms */ if (!data->echo_active_ms || data->echo_active_ms > 999) { - dev_err(&pdev->dev, - "echo-active-ms: %u - bad value from FW\n", + dev_err(dev, "echo-active-ms: %u - bad value from FW\n", data->echo_active_ms); return -EINVAL; } } data->assert_falling_edge = - device_property_read_bool(&pdev->dev, "assert-falling-edge"); + device_property_read_bool(dev, "assert-falling-edge"); return 0; } @@ -158,24 +152,26 @@ get_irqf_trigger_flags(const struct pps_gpio_device_data *data) static int pps_gpio_probe(struct platform_device *pdev) { struct pps_gpio_device_data *data; + struct device *dev = &pdev->dev; int ret; int pps_default_params; /* allocate space for device info */ - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - platform_set_drvdata(pdev, data); + + dev_set_drvdata(dev, data); /* GPIO setup */ - ret = pps_gpio_setup(pdev); + ret = pps_gpio_setup(dev); if (ret) return -EINVAL; /* IRQ setup */ ret = gpiod_to_irq(data->gpio_pin); if (ret < 0) { - dev_err(&pdev->dev, "failed to map GPIO to IRQ: %d\n", ret); + dev_err(dev, "failed to map GPIO to IRQ: %d\n", ret); return -EINVAL; } data->irq = ret; @@ -201,17 +197,17 @@ static int pps_gpio_probe(struct platform_device *pdev) pps_default_params |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR; data->pps = pps_register_source(&data->info, pps_default_params); if (IS_ERR(data->pps)) { - dev_err(&pdev->dev, "failed to register IRQ %d as PPS source\n", + dev_err(dev, "failed to register IRQ %d as PPS source\n", data->irq); return PTR_ERR(data->pps); } /* register IRQ interrupt handler */ - ret = devm_request_irq(&pdev->dev, data->irq, pps_gpio_irq_handler, + ret = devm_request_irq(dev, data->irq, pps_gpio_irq_handler, get_irqf_trigger_flags(data), data->info.name, data); if (ret) { pps_unregister_source(data->pps); - dev_err(&pdev->dev, "failed to acquire IRQ %d\n", data->irq); + dev_err(dev, "failed to acquire IRQ %d\n", data->irq); return -EINVAL; } -- cgit v1.2.3 From 6b3bc8286529a78fa9befa329900f847ae02cc0c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 18 Mar 2021 15:03:21 +0200 Subject: pps: clients: gpio: Rearrange optional stuff in pps_gpio_setup() Rearrange optional stuff in pps_gpio_setup() so it will go after mandatory one and with reduced indentation. This will increase readability of the sources. Acked-by: Rodolfo Giometti Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210318130321.24227-7-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/pps/clients/pps-gpio.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c index b097da5a659a..35799e6401c9 100644 --- a/drivers/pps/clients/pps-gpio.c +++ b/drivers/pps/clients/pps-gpio.c @@ -110,28 +110,31 @@ static int pps_gpio_setup(struct device *dev) return dev_err_probe(dev, PTR_ERR(data->gpio_pin), "failed to request PPS GPIO\n"); + data->assert_falling_edge = + device_property_read_bool(dev, "assert-falling-edge"); + data->echo_pin = devm_gpiod_get_optional(dev, "echo", GPIOD_OUT_LOW); if (IS_ERR(data->echo_pin)) return dev_err_probe(dev, PTR_ERR(data->echo_pin), "failed to request ECHO GPIO\n"); - if (data->echo_pin) { - ret = device_property_read_u32(dev, "echo-active-ms", &value); - if (ret) { - dev_err(dev, "failed to get echo-active-ms from FW\n"); - return ret; - } - data->echo_active_ms = value; - /* sanity check on echo_active_ms */ - if (!data->echo_active_ms || data->echo_active_ms > 999) { - dev_err(dev, "echo-active-ms: %u - bad value from FW\n", - data->echo_active_ms); - return -EINVAL; - } + if (!data->echo_pin) + return 0; + + ret = device_property_read_u32(dev, "echo-active-ms", &value); + if (ret) { + dev_err(dev, "failed to get echo-active-ms from FW\n"); + return ret; } - data->assert_falling_edge = - device_property_read_bool(dev, "assert-falling-edge"); + /* sanity check on echo_active_ms */ + if (!value || value > 999) { + dev_err(dev, "echo-active-ms: %u - bad value from FW\n", value); + return -EINVAL; + } + + data->echo_active_ms = value; + return 0; } -- cgit v1.2.3 From 95e04eb04c68b8a9f71ff09abea1ed617a67a0a2 Mon Sep 17 00:00:00 2001 From: Qiang Ma Date: Tue, 9 Mar 2021 15:20:59 +0800 Subject: char: lp: remove redundant space around (inside) parenthesized expressions These two lines of code don't meet the linux kernel style, and use a space after these keywords: if, switch, case, for, do, while. Do not add spaces around (inside) parenthesized expressions. So remove the redundant space. Signed-off-by: Qiang Ma Link: https://lore.kernel.org/r/20210309072059.22107-1-maqianga@uniontech.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/lp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 862c2fd933c7..0e22e3b0a04e 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -546,7 +546,7 @@ static int lp_open(struct inode *inode, struct file *file) } /* Determine if the peripheral supports ECP mode */ lp_claim_parport_or_block(&lp_table[minor]); - if ( (lp_table[minor].dev->port->modes & PARPORT_MODE_ECP) && + if ((lp_table[minor].dev->port->modes & PARPORT_MODE_ECP) && !parport_negotiate(lp_table[minor].dev->port, IEEE1284_MODE_ECP)) { printk(KERN_INFO "lp%d: ECP mode\n", minor); @@ -590,7 +590,7 @@ static int lp_do_ioctl(unsigned int minor, unsigned int cmd, return -ENODEV; if ((LP_F(minor) & LP_EXIST) == 0) return -ENODEV; - switch ( cmd ) { + switch (cmd) { case LPTIME: if (arg > UINT_MAX / HZ) return -EINVAL; -- cgit v1.2.3 From 9a8d3cda8daf54b1f8e67ccb360876379b7e7895 Mon Sep 17 00:00:00 2001 From: Russ Weight Date: Tue, 23 Mar 2021 15:46:50 -0700 Subject: fpga: dfl: afu: harden port enable logic Port enable is not complete until ACK = 0. Change __afu_port_enable() to guarantee that the enable process is complete by polling for ACK == 0. Signed-off-by: Russ Weight Reviewed-by: Tom Rix Reviewed-by: Matthew Gerlach Acked-by: Wu Hao Signed-off-by: Moritz Fischer --- drivers/fpga/dfl-afu-error.c | 10 ++++++---- drivers/fpga/dfl-afu-main.c | 35 ++++++++++++++++++++++++----------- drivers/fpga/dfl-afu.h | 2 +- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/drivers/fpga/dfl-afu-error.c b/drivers/fpga/dfl-afu-error.c index c4691187cca9..ab7be6217368 100644 --- a/drivers/fpga/dfl-afu-error.c +++ b/drivers/fpga/dfl-afu-error.c @@ -52,7 +52,7 @@ static int afu_port_err_clear(struct device *dev, u64 err) struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); struct platform_device *pdev = to_platform_device(dev); void __iomem *base_err, *base_hdr; - int ret = -EBUSY; + int enable_ret = 0, ret = -EBUSY; u64 v; base_err = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_ERROR); @@ -96,18 +96,20 @@ static int afu_port_err_clear(struct device *dev, u64 err) v = readq(base_err + PORT_FIRST_ERROR); writeq(v, base_err + PORT_FIRST_ERROR); } else { + dev_warn(dev, "%s: received 0x%llx, expected 0x%llx\n", + __func__, v, err); ret = -EINVAL; } /* Clear mask */ __afu_port_err_mask(dev, false); - /* Enable the Port by clear the reset */ - __afu_port_enable(pdev); + /* Enable the Port by clearing the reset */ + enable_ret = __afu_port_enable(pdev); done: mutex_unlock(&pdata->lock); - return ret; + return enable_ret ? enable_ret : ret; } static ssize_t errors_show(struct device *dev, struct device_attribute *attr, diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c index 753cda4b2568..7f621e96d3b8 100644 --- a/drivers/fpga/dfl-afu-main.c +++ b/drivers/fpga/dfl-afu-main.c @@ -21,6 +21,9 @@ #include "dfl-afu.h" +#define RST_POLL_INVL 10 /* us */ +#define RST_POLL_TIMEOUT 1000 /* us */ + /** * __afu_port_enable - enable a port by clear reset * @pdev: port platform device. @@ -32,7 +35,7 @@ * * The caller needs to hold lock for protection. */ -void __afu_port_enable(struct platform_device *pdev) +int __afu_port_enable(struct platform_device *pdev) { struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); void __iomem *base; @@ -41,7 +44,7 @@ void __afu_port_enable(struct platform_device *pdev) WARN_ON(!pdata->disable_count); if (--pdata->disable_count != 0) - return; + return 0; base = dfl_get_feature_ioaddr_by_id(&pdev->dev, PORT_FEATURE_ID_HEADER); @@ -49,10 +52,20 @@ void __afu_port_enable(struct platform_device *pdev) v = readq(base + PORT_HDR_CTRL); v &= ~PORT_CTRL_SFTRST; writeq(v, base + PORT_HDR_CTRL); -} -#define RST_POLL_INVL 10 /* us */ -#define RST_POLL_TIMEOUT 1000 /* us */ + /* + * HW clears the ack bit to indicate that the port is fully out + * of reset. + */ + if (readq_poll_timeout(base + PORT_HDR_CTRL, v, + !(v & PORT_CTRL_SFTRST_ACK), + RST_POLL_INVL, RST_POLL_TIMEOUT)) { + dev_err(&pdev->dev, "timeout, failure to enable device\n"); + return -ETIMEDOUT; + } + + return 0; +} /** * __afu_port_disable - disable a port by hold reset @@ -86,7 +99,7 @@ int __afu_port_disable(struct platform_device *pdev) if (readq_poll_timeout(base + PORT_HDR_CTRL, v, v & PORT_CTRL_SFTRST_ACK, RST_POLL_INVL, RST_POLL_TIMEOUT)) { - dev_err(&pdev->dev, "timeout, fail to reset device\n"); + dev_err(&pdev->dev, "timeout, failure to disable device\n"); return -ETIMEDOUT; } @@ -110,10 +123,10 @@ static int __port_reset(struct platform_device *pdev) int ret; ret = __afu_port_disable(pdev); - if (!ret) - __afu_port_enable(pdev); + if (ret) + return ret; - return ret; + return __afu_port_enable(pdev); } static int port_reset(struct platform_device *pdev) @@ -872,11 +885,11 @@ static int afu_dev_destroy(struct platform_device *pdev) static int port_enable_set(struct platform_device *pdev, bool enable) { struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); - int ret = 0; + int ret; mutex_lock(&pdata->lock); if (enable) - __afu_port_enable(pdev); + ret = __afu_port_enable(pdev); else ret = __afu_port_disable(pdev); mutex_unlock(&pdata->lock); diff --git a/drivers/fpga/dfl-afu.h b/drivers/fpga/dfl-afu.h index 576e94960086..e5020e2b1f3d 100644 --- a/drivers/fpga/dfl-afu.h +++ b/drivers/fpga/dfl-afu.h @@ -80,7 +80,7 @@ struct dfl_afu { }; /* hold pdata->lock when call __afu_port_enable/disable */ -void __afu_port_enable(struct platform_device *pdev); +int __afu_port_enable(struct platform_device *pdev); int __afu_port_disable(struct platform_device *pdev); void afu_mmio_region_init(struct dfl_feature_platform_data *pdata); -- cgit v1.2.3 From 66b87358440ea50ec9d9d47d70c7c0af81fd62bf Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 16 Mar 2021 17:22:21 +0800 Subject: dt-bindings: phy: mediatek: dsi-phy: modify compatible dependence mt7623-mipi-tx is compatible to mt2701-mipi-tx, and use "mediatek,mt2701-mipi-tx" instead on MT7623, so modify the compatible items to make dependence clear. Cc: Chun-Kuang Hu Cc: Philipp Zabel Acked-by: Chun-Kuang Hu Reviewed-by: Rob Herring Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20210316092232.9806-2-chunfeng.yun@mediatek.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/mediatek,dsi-phy.yaml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/mediatek,dsi-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,dsi-phy.yaml index 71d4acea1f66..6e4d795f9b02 100644 --- a/Documentation/devicetree/bindings/phy/mediatek,dsi-phy.yaml +++ b/Documentation/devicetree/bindings/phy/mediatek,dsi-phy.yaml @@ -19,11 +19,14 @@ properties: pattern: "^dsi-phy@[0-9a-f]+$" compatible: - enum: - - mediatek,mt2701-mipi-tx - - mediatek,mt7623-mipi-tx - - mediatek,mt8173-mipi-tx - - mediatek,mt8183-mipi-tx + oneOf: + - items: + - enum: + - mediatek,mt7623-mipi-tx + - const: mediatek,mt2701-mipi-tx + - const: mediatek,mt2701-mipi-tx + - const: mediatek,mt8173-mipi-tx + - const: mediatek,mt8183-mipi-tx reg: maxItems: 1 -- cgit v1.2.3 From 9dbccfef1dde12279bbe71eaaf25ac13024f5a28 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 16 Mar 2021 17:22:22 +0800 Subject: dt-bindings: phy: mediatek: hdmi-phy: modify compatible items mt7623-hdmi-tx is compatible to mt2701-hdmi-tx, and the compatible "mediatek,mt7623-hdmi-tx" is not supported in driver, in fact uses "mediatek,mt2701-hdmi-tx" instead on MT7623, so changes the compatible items to make dependence clear. Cc: Chun-Kuang Hu Cc: Philipp Zabel Acked-by: Chun-Kuang Hu Reviewed-by: Rob Herring Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20210316092232.9806-3-chunfeng.yun@mediatek.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml index 4752517a1446..0d94950b84ca 100644 --- a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml +++ b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml @@ -21,10 +21,13 @@ properties: pattern: "^hdmi-phy@[0-9a-f]+$" compatible: - enum: - - mediatek,mt2701-hdmi-phy - - mediatek,mt7623-hdmi-phy - - mediatek,mt8173-hdmi-phy + oneOf: + - items: + - enum: + - mediatek,mt7623-hdmi-phy + - const: mediatek,mt2701-hdmi-phy + - const: mediatek,mt2701-hdmi-phy + - const: mediatek,mt8173-hdmi-phy reg: maxItems: 1 -- cgit v1.2.3 From 5c977c69c8b2be793b3f5a11a97addabdea47f8b Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 16 Mar 2021 17:22:23 +0800 Subject: dt-bindings: phy: mediatek: tphy: change patternProperties The phy may be named as pcie-phy when the T-PHY only supports PCIe mode, it's also the similar case for SATA, named as sata-phy. Reviewed-by: Rob Herring Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20210316092232.9806-4-chunfeng.yun@mediatek.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/mediatek,tphy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml index c5b436ad6239..b8a7651a3d9a 100644 --- a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml +++ b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml @@ -118,7 +118,7 @@ properties: # Required child node: patternProperties: - "^usb-phy@[0-9a-f]+$": + "^(usb|pcie|sata)-phy@[0-9a-f]+$": type: object description: A sub-node is required for each port the controller provides. -- cgit v1.2.3 From 6a7d15b850f802ca9b67011a80cb2f6ea96c830b Mon Sep 17 00:00:00 2001 From: Sandeep Maheswaram Date: Wed, 17 Mar 2021 16:31:40 +0530 Subject: dt-bindings: phy: qcom,usb-snps-femto-v2: Add bindings for SC7280 Add the compatible string for sc7280 SoC from Qualcomm Signed-off-by: Sandeep Maheswaram Reviewed-by: Matthias Kaehlcke Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/1615978901-4202-3-git-send-email-sanm@codeaurora.org Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml b/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml index ee77c6458326..20203a8a9e41 100644 --- a/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml @@ -16,6 +16,7 @@ properties: compatible: enum: - qcom,usb-snps-hs-7nm-phy + - qcom,sc7280-usb-hs-phy - qcom,sm8150-usb-hs-phy - qcom,sm8250-usb-hs-phy - qcom,sm8350-usb-hs-phy -- cgit v1.2.3 From c115c5680d09e9e37477937755da9f0423c5e9c9 Mon Sep 17 00:00:00 2001 From: Bhaskar Chowdhury Date: Sun, 21 Mar 2021 02:10:55 +0530 Subject: phy: intel: Fix a typo s/subsytem/subsystem/ Signed-off-by: Bhaskar Chowdhury Link: https://lore.kernel.org/r/20210320204055.26107-1-unixbhaskar@gmail.com Signed-off-by: Vinod Koul --- drivers/phy/intel/phy-intel-lgm-combo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/intel/phy-intel-lgm-combo.c b/drivers/phy/intel/phy-intel-lgm-combo.c index 360b1eb2ebd6..157683d10367 100644 --- a/drivers/phy/intel/phy-intel-lgm-combo.c +++ b/drivers/phy/intel/phy-intel-lgm-combo.c @@ -462,7 +462,7 @@ static int intel_cbphy_fwnode_parse(struct intel_combo_phy *cbphy) /* * syscfg and hsiocfg variables stores the handle of the registers set - * in which ComboPhy subsytem specific registers are subset. Using + * in which ComboPhy subsystem specific registers are subset. Using * Register map framework to access the registers set. */ ret = fwnode_property_get_reference_args(fwnode, "intel,syscfg", NULL, -- cgit v1.2.3 From 0d811cda22abeeeb8d3412ac17b687764f4b4c9f Mon Sep 17 00:00:00 2001 From: Zhang Yunkai Date: Fri, 19 Mar 2021 04:36:12 -0700 Subject: phy: qualcomm: remove duplicate argument 'HSUSB_CTRL_DPSEHV_CLAMP' in 'val' is duplicated. Signed-off-by: Zhang Yunkai Link: https://lore.kernel.org/r/20210319113612.494623-1-zhang.yunkai@zte.com.cn Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c b/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c index 9061ece7ff6a..bfff0c8c9130 100644 --- a/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c +++ b/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c @@ -276,8 +276,8 @@ static int qcom_ipq806x_usb_hs_phy_init(struct phy *phy) val = HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_DMSEHV_CLAMP | HSUSB_CTRL_RETENABLEN | HSUSB_CTRL_COMMONONN | HSUSB_CTRL_OTGSESSVLD_CLAMP | HSUSB_CTRL_ID_HV_CLAMP | - HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_UTMI_OTG_VBUS_VALID | - HSUSB_CTRL_UTMI_CLK_EN | HSUSB_CTRL_CLAMP_EN | 0x70; + HSUSB_CTRL_UTMI_OTG_VBUS_VALID | HSUSB_CTRL_UTMI_CLK_EN | + HSUSB_CTRL_CLAMP_EN | 0x70; /* use core clock if external reference is not present */ if (!phy_dwc3->xo_clk) -- cgit v1.2.3 From c009ffe661f68236deb37c91fa1c1c82e9ecdd9c Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 18 Mar 2021 15:16:16 +0530 Subject: dt-bindings: interconnect: Add Qualcomm SM8350 DT bindings The Qualcomm SM8350 platform has several bus fabrics that could be controlled and tuned dynamically according to the bandwidth demand. Signed-off-by: Vinod Koul Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210318094617.951212-2-vkoul@kernel.org Signed-off-by: Georgi Djakov --- .../bindings/interconnect/qcom,rpmh.yaml | 10 ++ include/dt-bindings/interconnect/qcom,sm8350.h | 172 +++++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 include/dt-bindings/interconnect/qcom,sm8350.h diff --git a/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml index 799e73cdb90b..cb6498108b78 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml @@ -71,6 +71,16 @@ properties: - qcom,sm8250-mmss-noc - qcom,sm8250-npu-noc - qcom,sm8250-system-noc + - qcom,sm8350-aggre1-noc + - qcom,sm8350-aggre2-noc + - qcom,sm8350-config-noc + - qcom,sm8350-dc-noc + - qcom,sm8350-gem-noc + - qcom,sm8350-lpass-ag-noc + - qcom,sm8350-mc-virt + - qcom,sm8350-mmss-noc + - qcom,sm8350-compute-noc + - qcom,sm8350-system-noc '#interconnect-cells': enum: [ 1, 2 ] diff --git a/include/dt-bindings/interconnect/qcom,sm8350.h b/include/dt-bindings/interconnect/qcom,sm8350.h new file mode 100644 index 000000000000..c7f7ed315aeb --- /dev/null +++ b/include/dt-bindings/interconnect/qcom,sm8350.h @@ -0,0 +1,172 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Qualcomm SM8350 interconnect IDs + * + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2021, Linaro Limited + */ + +#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_SM8350_H +#define __DT_BINDINGS_INTERCONNECT_QCOM_SM8350_H + +#define MASTER_QSPI_0 0 +#define MASTER_QUP_1 1 +#define MASTER_A1NOC_CFG 2 +#define MASTER_SDCC_4 3 +#define MASTER_UFS_MEM 4 +#define MASTER_USB3_0 5 +#define MASTER_USB3_1 6 +#define SLAVE_A1NOC_SNOC 7 +#define SLAVE_SERVICE_A1NOC 8 + +#define MASTER_QDSS_BAM 0 +#define MASTER_QUP_0 1 +#define MASTER_QUP_2 2 +#define MASTER_A2NOC_CFG 3 +#define MASTER_CRYPTO 4 +#define MASTER_IPA 5 +#define MASTER_PCIE_0 6 +#define MASTER_PCIE_1 7 +#define MASTER_QDSS_ETR 8 +#define MASTER_SDCC_2 9 +#define MASTER_UFS_CARD 10 +#define SLAVE_A2NOC_SNOC 11 +#define SLAVE_ANOC_PCIE_GEM_NOC 12 +#define SLAVE_SERVICE_A2NOC 13 + +#define MASTER_GEM_NOC_CNOC 0 +#define MASTER_GEM_NOC_PCIE_SNOC 1 +#define MASTER_QDSS_DAP 2 +#define SLAVE_AHB2PHY_SOUTH 3 +#define SLAVE_AHB2PHY_NORTH 4 +#define SLAVE_AOSS 5 +#define SLAVE_APPSS 6 +#define SLAVE_CAMERA_CFG 7 +#define SLAVE_CLK_CTL 8 +#define SLAVE_CDSP_CFG 9 +#define SLAVE_RBCPR_CX_CFG 10 +#define SLAVE_RBCPR_MMCX_CFG 11 +#define SLAVE_RBCPR_MX_CFG 12 +#define SLAVE_CRYPTO_0_CFG 13 +#define SLAVE_CX_RDPM 14 +#define SLAVE_DCC_CFG 15 +#define SLAVE_DISPLAY_CFG 16 +#define SLAVE_GFX3D_CFG 17 +#define SLAVE_HWKM 18 +#define SLAVE_IMEM_CFG 19 +#define SLAVE_IPA_CFG 20 +#define SLAVE_IPC_ROUTER_CFG 21 +#define SLAVE_LPASS 22 +#define SLAVE_CNOC_MSS 23 +#define SLAVE_MX_RDPM 24 +#define SLAVE_PCIE_0_CFG 25 +#define SLAVE_PCIE_1_CFG 26 +#define SLAVE_PDM 27 +#define SLAVE_PIMEM_CFG 28 +#define SLAVE_PKA_WRAPPER_CFG 29 +#define SLAVE_PMU_WRAPPER_CFG 30 +#define SLAVE_QDSS_CFG 31 +#define SLAVE_QSPI_0 32 +#define SLAVE_QUP_0 33 +#define SLAVE_QUP_1 34 +#define SLAVE_QUP_2 35 +#define SLAVE_SDCC_2 36 +#define SLAVE_SDCC_4 37 +#define SLAVE_SECURITY 38 +#define SLAVE_SPSS_CFG 39 +#define SLAVE_TCSR 40 +#define SLAVE_TLMM 41 +#define SLAVE_UFS_CARD_CFG 42 +#define SLAVE_UFS_MEM_CFG 43 +#define SLAVE_USB3_0 44 +#define SLAVE_USB3_1 45 +#define SLAVE_VENUS_CFG 46 +#define SLAVE_VSENSE_CTRL_CFG 47 +#define SLAVE_A1NOC_CFG 48 +#define SLAVE_A2NOC_CFG 49 +#define SLAVE_DDRSS_CFG 50 +#define SLAVE_CNOC_MNOC_CFG 51 +#define SLAVE_SNOC_CFG 52 +#define SLAVE_BOOT_IMEM 53 +#define SLAVE_IMEM 54 +#define SLAVE_PIMEM 55 +#define SLAVE_SERVICE_CNOC 56 +#define SLAVE_PCIE_0 57 +#define SLAVE_PCIE_1 58 +#define SLAVE_QDSS_STM 59 +#define SLAVE_TCU 60 + +#define MASTER_CNOC_DC_NOC 0 +#define SLAVE_LLCC_CFG 1 +#define SLAVE_GEM_NOC_CFG 2 + +#define MASTER_GPU_TCU 0 +#define MASTER_SYS_TCU 1 +#define MASTER_APPSS_PROC 2 +#define MASTER_COMPUTE_NOC 3 +#define MASTER_GEM_NOC_CFG 4 +#define MASTER_GFX3D 5 +#define MASTER_MNOC_HF_MEM_NOC 6 +#define MASTER_MNOC_SF_MEM_NOC 7 +#define MASTER_ANOC_PCIE_GEM_NOC 8 +#define MASTER_SNOC_GC_MEM_NOC 9 +#define MASTER_SNOC_SF_MEM_NOC 10 +#define SLAVE_MSS_PROC_MS_MPU_CFG 11 +#define SLAVE_MCDMA_MS_MPU_CFG 12 +#define SLAVE_GEM_NOC_CNOC 13 +#define SLAVE_LLCC 14 +#define SLAVE_MEM_NOC_PCIE_SNOC 15 +#define SLAVE_SERVICE_GEM_NOC_1 16 +#define SLAVE_SERVICE_GEM_NOC_2 17 +#define SLAVE_SERVICE_GEM_NOC 18 +#define MASTER_MNOC_HF_MEM_NOC_DISP 19 +#define MASTER_MNOC_SF_MEM_NOC_DISP 20 +#define SLAVE_LLCC_DISP 21 + +#define MASTER_CNOC_LPASS_AG_NOC 0 +#define SLAVE_LPASS_CORE_CFG 1 +#define SLAVE_LPASS_LPI_CFG 2 +#define SLAVE_LPASS_MPU_CFG 3 +#define SLAVE_LPASS_TOP_CFG 4 +#define SLAVE_SERVICES_LPASS_AML_NOC 5 +#define SLAVE_SERVICE_LPASS_AG_NOC 6 + +#define MASTER_LLCC 0 +#define SLAVE_EBI1 1 +#define MASTER_LLCC_DISP 2 +#define SLAVE_EBI1_DISP 3 + +#define MASTER_CAMNOC_HF 0 +#define MASTER_CAMNOC_ICP 1 +#define MASTER_CAMNOC_SF 2 +#define MASTER_CNOC_MNOC_CFG 3 +#define MASTER_VIDEO_P0 4 +#define MASTER_VIDEO_P1 5 +#define MASTER_VIDEO_PROC 6 +#define MASTER_MDP0 7 +#define MASTER_MDP1 8 +#define MASTER_ROTATOR 9 +#define SLAVE_MNOC_HF_MEM_NOC 10 +#define SLAVE_MNOC_SF_MEM_NOC 11 +#define SLAVE_SERVICE_MNOC 12 +#define MASTER_MDP0_DISP 13 +#define MASTER_MDP1_DISP 14 +#define MASTER_ROTATOR_DISP 15 +#define SLAVE_MNOC_HF_MEM_NOC_DISP 16 +#define SLAVE_MNOC_SF_MEM_NOC_DISP 17 + +#define MASTER_CDSP_NOC_CFG 0 +#define MASTER_CDSP_PROC 1 +#define SLAVE_CDSP_MEM_NOC 2 +#define SLAVE_SERVICE_NSP_NOC 3 + +#define MASTER_A1NOC_SNOC 0 +#define MASTER_A2NOC_SNOC 1 +#define MASTER_SNOC_CFG 2 +#define MASTER_PIMEM 3 +#define MASTER_GIC 4 +#define SLAVE_SNOC_GEM_NOC_GC 5 +#define SLAVE_SNOC_GEM_NOC_SF 6 +#define SLAVE_SERVICE_SNOC 7 + +#endif -- cgit v1.2.3 From d26a56674497dd12a0ac378203cf058b7a984124 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 18 Mar 2021 15:16:17 +0530 Subject: interconnect: qcom: Add SM8350 interconnect provider driver Add driver for the Qualcomm interconnect buses found in SM8350 based platforms. The topology consists of several NoCs that are controlled by a remote processor that collects the aggregated bandwidth for each master-slave pairs. Generated from downstream interconnect driver written by David Dai Signed-off-by: Vinod Koul Link: https://lore.kernel.org/r/20210318094617.951212-3-vkoul@kernel.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/Kconfig | 9 + drivers/interconnect/qcom/Makefile | 2 + drivers/interconnect/qcom/sm8350.c | 633 +++++++++++++++++++++++++++++++++++++ drivers/interconnect/qcom/sm8350.h | 168 ++++++++++ 4 files changed, 812 insertions(+) create mode 100644 drivers/interconnect/qcom/sm8350.c create mode 100644 drivers/interconnect/qcom/sm8350.h diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig index ca52647f8955..49bc8702782c 100644 --- a/drivers/interconnect/qcom/Kconfig +++ b/drivers/interconnect/qcom/Kconfig @@ -110,5 +110,14 @@ config INTERCONNECT_QCOM_SM8250 This is a driver for the Qualcomm Network-on-Chip on sm8250-based platforms. +config INTERCONNECT_QCOM_SM8350 + tristate "Qualcomm SM8350 interconnect driver" + depends on INTERCONNECT_QCOM_RPMH_POSSIBLE + select INTERCONNECT_QCOM_RPMH + select INTERCONNECT_QCOM_BCM_VOTER + help + This is a driver for the Qualcomm Network-on-Chip on SM8350-based + platforms. + config INTERCONNECT_QCOM_SMD_RPM tristate diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile index c6a735df067e..93d97e590836 100644 --- a/drivers/interconnect/qcom/Makefile +++ b/drivers/interconnect/qcom/Makefile @@ -12,6 +12,7 @@ qnoc-sdm845-objs := sdm845.o qnoc-sdx55-objs := sdx55.o qnoc-sm8150-objs := sm8150.o qnoc-sm8250-objs := sm8250.o +qnoc-sm8350-objs := sm8350.o icc-smd-rpm-objs := smd-rpm.o icc-rpm.o obj-$(CONFIG_INTERCONNECT_QCOM_BCM_VOTER) += icc-bcm-voter.o @@ -26,4 +27,5 @@ obj-$(CONFIG_INTERCONNECT_QCOM_SDM845) += qnoc-sdm845.o obj-$(CONFIG_INTERCONNECT_QCOM_SDX55) += qnoc-sdx55.o obj-$(CONFIG_INTERCONNECT_QCOM_SM8150) += qnoc-sm8150.o obj-$(CONFIG_INTERCONNECT_QCOM_SM8250) += qnoc-sm8250.o +obj-$(CONFIG_INTERCONNECT_QCOM_SM8350) += qnoc-sm8350.o obj-$(CONFIG_INTERCONNECT_QCOM_SMD_RPM) += icc-smd-rpm.o diff --git a/drivers/interconnect/qcom/sm8350.c b/drivers/interconnect/qcom/sm8350.c new file mode 100644 index 000000000000..f3aab02b8678 --- /dev/null +++ b/drivers/interconnect/qcom/sm8350.c @@ -0,0 +1,633 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2021, Linaro Limited + * + */ + +#include +#include +#include +#include + +#include "bcm-voter.h" +#include "icc-rpmh.h" +#include "sm8350.h" + +DEFINE_QNODE(qhm_qspi, SM8350_MASTER_QSPI_0, 1, 4, SM8350_SLAVE_A1NOC_SNOC); +DEFINE_QNODE(qhm_qup0, SM8350_MASTER_QUP_0, 1, 4, SM8350_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(qhm_qup1, SM8350_MASTER_QUP_1, 1, 4, SM8350_SLAVE_A1NOC_SNOC); +DEFINE_QNODE(qhm_qup2, SM8350_MASTER_QUP_2, 1, 4, SM8350_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(qnm_a1noc_cfg, SM8350_MASTER_A1NOC_CFG, 1, 4, SM8350_SLAVE_SERVICE_A1NOC); +DEFINE_QNODE(xm_sdc4, SM8350_MASTER_SDCC_4, 1, 8, SM8350_SLAVE_A1NOC_SNOC); +DEFINE_QNODE(xm_ufs_mem, SM8350_MASTER_UFS_MEM, 1, 8, SM8350_SLAVE_A1NOC_SNOC); +DEFINE_QNODE(xm_usb3_0, SM8350_MASTER_USB3_0, 1, 8, SM8350_SLAVE_A1NOC_SNOC); +DEFINE_QNODE(xm_usb3_1, SM8350_MASTER_USB3_1, 1, 8, SM8350_SLAVE_A1NOC_SNOC); +DEFINE_QNODE(qhm_qdss_bam, SM8350_MASTER_QDSS_BAM, 1, 4, SM8350_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(qnm_a2noc_cfg, SM8350_MASTER_A2NOC_CFG, 1, 4, SM8350_SLAVE_SERVICE_A2NOC); +DEFINE_QNODE(qxm_crypto, SM8350_MASTER_CRYPTO, 1, 8, SM8350_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(qxm_ipa, SM8350_MASTER_IPA, 1, 8, SM8350_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(xm_pcie3_0, SM8350_MASTER_PCIE_0, 1, 8, SM8350_SLAVE_ANOC_PCIE_GEM_NOC); +DEFINE_QNODE(xm_pcie3_1, SM8350_MASTER_PCIE_1, 1, 8, SM8350_SLAVE_ANOC_PCIE_GEM_NOC); +DEFINE_QNODE(xm_qdss_etr, SM8350_MASTER_QDSS_ETR, 1, 8, SM8350_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(xm_sdc2, SM8350_MASTER_SDCC_2, 1, 8, SM8350_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(xm_ufs_card, SM8350_MASTER_UFS_CARD, 1, 8, SM8350_SLAVE_A2NOC_SNOC); +DEFINE_QNODE(qnm_gemnoc_cnoc, SM8350_MASTER_GEM_NOC_CNOC, 1, 16, SM8350_SLAVE_AHB2PHY_SOUTH, SM8350_SLAVE_AHB2PHY_NORTH, SM8350_SLAVE_AOSS, SM8350_SLAVE_APPSS, SM8350_SLAVE_CAMERA_CFG, SM8350_SLAVE_CLK_CTL, SM8350_SLAVE_CDSP_CFG, SM8350_SLAVE_RBCPR_CX_CFG, SM8350_SLAVE_RBCPR_MMCX_CFG, SM8350_SLAVE_RBCPR_MX_CFG, SM8350_SLAVE_CRYPTO_0_CFG, SM8350_SLAVE_CX_RDPM, SM8350_SLAVE_DCC_CFG, SM8350_SLAVE_DISPLAY_CFG, SM8350_SLAVE_GFX3D_CFG, SM8350_SLAVE_HWKM, SM8350_SLAVE_IMEM_CFG, SM8350_SLAVE_IPA_CFG, SM8350_SLAVE_IPC_ROUTER_CFG, SM8350_SLAVE_LPASS, SM8350_SLAVE_CNOC_MSS, SM8350_SLAVE_MX_RDPM, SM8350_SLAVE_PCIE_0_CFG, SM8350_SLAVE_PCIE_1_CFG, SM8350_SLAVE_PDM, SM8350_SLAVE_PIMEM_CFG, SM8350_SLAVE_PKA_WRAPPER_CFG, SM8350_SLAVE_PMU_WRAPPER_CFG, SM8350_SLAVE_QDSS_CFG, SM8350_SLAVE_QSPI_0, SM8350_SLAVE_QUP_0, SM8350_SLAVE_QUP_1, SM8350_SLAVE_QUP_2, SM8350_SLAVE_SDCC_2, SM8350_SLAVE_SDCC_4, SM8350_SLAVE_SECURITY, SM8350_SLAVE_SPSS_CFG, SM8350_SLAVE_TCSR, SM8350_SLAVE_TLMM, SM8350_SLAVE_UFS_CARD_CFG, SM8350_SLAVE_UFS_MEM_CFG, SM8350_SLAVE_USB3_0, SM8350_SLAVE_USB3_1, SM8350_SLAVE_VENUS_CFG, SM8350_SLAVE_VSENSE_CTRL_CFG, SM8350_SLAVE_A1NOC_CFG, SM8350_SLAVE_A2NOC_CFG, SM8350_SLAVE_DDRSS_CFG, SM8350_SLAVE_CNOC_MNOC_CFG, SM8350_SLAVE_SNOC_CFG, SM8350_SLAVE_BOOT_IMEM, SM8350_SLAVE_IMEM, SM8350_SLAVE_PIMEM, SM8350_SLAVE_SERVICE_CNOC, SM8350_SLAVE_QDSS_STM, SM8350_SLAVE_TCU); +DEFINE_QNODE(qnm_gemnoc_pcie, SM8350_MASTER_GEM_NOC_PCIE_SNOC, 1, 8, SM8350_SLAVE_PCIE_0, SM8350_SLAVE_PCIE_1); +DEFINE_QNODE(xm_qdss_dap, SM8350_MASTER_QDSS_DAP, 1, 8, SM8350_SLAVE_AHB2PHY_SOUTH, SM8350_SLAVE_AHB2PHY_NORTH, SM8350_SLAVE_AOSS, SM8350_SLAVE_APPSS, SM8350_SLAVE_CAMERA_CFG, SM8350_SLAVE_CLK_CTL, SM8350_SLAVE_CDSP_CFG, SM8350_SLAVE_RBCPR_CX_CFG, SM8350_SLAVE_RBCPR_MMCX_CFG, SM8350_SLAVE_RBCPR_MX_CFG, SM8350_SLAVE_CRYPTO_0_CFG, SM8350_SLAVE_CX_RDPM, SM8350_SLAVE_DCC_CFG, SM8350_SLAVE_DISPLAY_CFG, SM8350_SLAVE_GFX3D_CFG, SM8350_SLAVE_HWKM, SM8350_SLAVE_IMEM_CFG, SM8350_SLAVE_IPA_CFG, SM8350_SLAVE_IPC_ROUTER_CFG, SM8350_SLAVE_LPASS, SM8350_SLAVE_CNOC_MSS, SM8350_SLAVE_MX_RDPM, SM8350_SLAVE_PCIE_0_CFG, SM8350_SLAVE_PCIE_1_CFG, SM8350_SLAVE_PDM, SM8350_SLAVE_PIMEM_CFG, SM8350_SLAVE_PKA_WRAPPER_CFG, SM8350_SLAVE_PMU_WRAPPER_CFG, SM8350_SLAVE_QDSS_CFG, SM8350_SLAVE_QSPI_0, SM8350_SLAVE_QUP_0, SM8350_SLAVE_QUP_1, SM8350_SLAVE_QUP_2, SM8350_SLAVE_SDCC_2, SM8350_SLAVE_SDCC_4, SM8350_SLAVE_SECURITY, SM8350_SLAVE_SPSS_CFG, SM8350_SLAVE_TCSR, SM8350_SLAVE_TLMM, SM8350_SLAVE_UFS_CARD_CFG, SM8350_SLAVE_UFS_MEM_CFG, SM8350_SLAVE_USB3_0, SM8350_SLAVE_USB3_1, SM8350_SLAVE_VENUS_CFG, SM8350_SLAVE_VSENSE_CTRL_CFG, SM8350_SLAVE_A1NOC_CFG, SM8350_SLAVE_A2NOC_CFG, SM8350_SLAVE_DDRSS_CFG, SM8350_SLAVE_CNOC_MNOC_CFG, SM8350_SLAVE_SNOC_CFG, SM8350_SLAVE_BOOT_IMEM, SM8350_SLAVE_IMEM, SM8350_SLAVE_PIMEM, SM8350_SLAVE_SERVICE_CNOC, SM8350_SLAVE_QDSS_STM, SM8350_SLAVE_TCU); +DEFINE_QNODE(qnm_cnoc_dc_noc, SM8350_MASTER_CNOC_DC_NOC, 1, 4, SM8350_SLAVE_LLCC_CFG, SM8350_SLAVE_GEM_NOC_CFG); +DEFINE_QNODE(alm_gpu_tcu, SM8350_MASTER_GPU_TCU, 1, 8, SM8350_SLAVE_GEM_NOC_CNOC, SM8350_SLAVE_LLCC); +DEFINE_QNODE(alm_sys_tcu, SM8350_MASTER_SYS_TCU, 1, 8, SM8350_SLAVE_GEM_NOC_CNOC, SM8350_SLAVE_LLCC); +DEFINE_QNODE(chm_apps, SM8350_MASTER_APPSS_PROC, 2, 32, SM8350_SLAVE_GEM_NOC_CNOC, SM8350_SLAVE_LLCC, SM8350_SLAVE_MEM_NOC_PCIE_SNOC); +DEFINE_QNODE(qnm_cmpnoc, SM8350_MASTER_COMPUTE_NOC, 2, 32, SM8350_SLAVE_GEM_NOC_CNOC, SM8350_SLAVE_LLCC); +DEFINE_QNODE(qnm_gemnoc_cfg, SM8350_MASTER_GEM_NOC_CFG, 1, 4, SM8350_SLAVE_MSS_PROC_MS_MPU_CFG, SM8350_SLAVE_MCDMA_MS_MPU_CFG, SM8350_SLAVE_SERVICE_GEM_NOC_1, SM8350_SLAVE_SERVICE_GEM_NOC_2, SM8350_SLAVE_SERVICE_GEM_NOC); +DEFINE_QNODE(qnm_gpu, SM8350_MASTER_GFX3D, 2, 32, SM8350_SLAVE_GEM_NOC_CNOC, SM8350_SLAVE_LLCC); +DEFINE_QNODE(qnm_mnoc_hf, SM8350_MASTER_MNOC_HF_MEM_NOC, 2, 32, SM8350_SLAVE_LLCC); +DEFINE_QNODE(qnm_mnoc_sf, SM8350_MASTER_MNOC_SF_MEM_NOC, 2, 32, SM8350_SLAVE_GEM_NOC_CNOC, SM8350_SLAVE_LLCC); +DEFINE_QNODE(qnm_pcie, SM8350_MASTER_ANOC_PCIE_GEM_NOC, 1, 16, SM8350_SLAVE_GEM_NOC_CNOC, SM8350_SLAVE_LLCC); +DEFINE_QNODE(qnm_snoc_gc, SM8350_MASTER_SNOC_GC_MEM_NOC, 1, 8, SM8350_SLAVE_LLCC); +DEFINE_QNODE(qnm_snoc_sf, SM8350_MASTER_SNOC_SF_MEM_NOC, 1, 16, SM8350_SLAVE_GEM_NOC_CNOC, SM8350_SLAVE_LLCC, SM8350_SLAVE_MEM_NOC_PCIE_SNOC); +DEFINE_QNODE(qhm_config_noc, SM8350_MASTER_CNOC_LPASS_AG_NOC, 1, 4, SM8350_SLAVE_LPASS_CORE_CFG, SM8350_SLAVE_LPASS_LPI_CFG, SM8350_SLAVE_LPASS_MPU_CFG, SM8350_SLAVE_LPASS_TOP_CFG, SM8350_SLAVE_SERVICES_LPASS_AML_NOC, SM8350_SLAVE_SERVICE_LPASS_AG_NOC); +DEFINE_QNODE(llcc_mc, SM8350_MASTER_LLCC, 4, 4, SM8350_SLAVE_EBI1); +DEFINE_QNODE(qnm_camnoc_hf, SM8350_MASTER_CAMNOC_HF, 2, 32, SM8350_SLAVE_MNOC_HF_MEM_NOC); +DEFINE_QNODE(qnm_camnoc_icp, SM8350_MASTER_CAMNOC_ICP, 1, 8, SM8350_SLAVE_MNOC_SF_MEM_NOC); +DEFINE_QNODE(qnm_camnoc_sf, SM8350_MASTER_CAMNOC_SF, 2, 32, SM8350_SLAVE_MNOC_SF_MEM_NOC); +DEFINE_QNODE(qnm_mnoc_cfg, SM8350_MASTER_CNOC_MNOC_CFG, 1, 4, SM8350_SLAVE_SERVICE_MNOC); +DEFINE_QNODE(qnm_video0, SM8350_MASTER_VIDEO_P0, 1, 32, SM8350_SLAVE_MNOC_SF_MEM_NOC); +DEFINE_QNODE(qnm_video1, SM8350_MASTER_VIDEO_P1, 1, 32, SM8350_SLAVE_MNOC_SF_MEM_NOC); +DEFINE_QNODE(qnm_video_cvp, SM8350_MASTER_VIDEO_PROC, 1, 32, SM8350_SLAVE_MNOC_SF_MEM_NOC); +DEFINE_QNODE(qxm_mdp0, SM8350_MASTER_MDP0, 1, 32, SM8350_SLAVE_MNOC_HF_MEM_NOC); +DEFINE_QNODE(qxm_mdp1, SM8350_MASTER_MDP1, 1, 32, SM8350_SLAVE_MNOC_HF_MEM_NOC); +DEFINE_QNODE(qxm_rot, SM8350_MASTER_ROTATOR, 1, 32, SM8350_SLAVE_MNOC_SF_MEM_NOC); +DEFINE_QNODE(qhm_nsp_noc_config, SM8350_MASTER_CDSP_NOC_CFG, 1, 4, SM8350_SLAVE_SERVICE_NSP_NOC); +DEFINE_QNODE(qxm_nsp, SM8350_MASTER_CDSP_PROC, 2, 32, SM8350_SLAVE_CDSP_MEM_NOC); +DEFINE_QNODE(qnm_aggre1_noc, SM8350_MASTER_A1NOC_SNOC, 1, 16, SM8350_SLAVE_SNOC_GEM_NOC_SF); +DEFINE_QNODE(qnm_aggre2_noc, SM8350_MASTER_A2NOC_SNOC, 1, 16, SM8350_SLAVE_SNOC_GEM_NOC_SF); +DEFINE_QNODE(qnm_snoc_cfg, SM8350_MASTER_SNOC_CFG, 1, 4, SM8350_SLAVE_SERVICE_SNOC); +DEFINE_QNODE(qxm_pimem, SM8350_MASTER_PIMEM, 1, 8, SM8350_SLAVE_SNOC_GEM_NOC_GC); +DEFINE_QNODE(xm_gic, SM8350_MASTER_GIC, 1, 8, SM8350_SLAVE_SNOC_GEM_NOC_GC); +DEFINE_QNODE(qnm_mnoc_hf_disp, SM8350_MASTER_MNOC_HF_MEM_NOC_DISP, 2, 32, SM8350_SLAVE_LLCC_DISP); +DEFINE_QNODE(qnm_mnoc_sf_disp, SM8350_MASTER_MNOC_SF_MEM_NOC_DISP, 2, 32, SM8350_SLAVE_LLCC_DISP); +DEFINE_QNODE(llcc_mc_disp, SM8350_MASTER_LLCC_DISP, 4, 4, SM8350_SLAVE_EBI1_DISP); +DEFINE_QNODE(qxm_mdp0_disp, SM8350_MASTER_MDP0_DISP, 1, 32, SM8350_SLAVE_MNOC_HF_MEM_NOC_DISP); +DEFINE_QNODE(qxm_mdp1_disp, SM8350_MASTER_MDP1_DISP, 1, 32, SM8350_SLAVE_MNOC_HF_MEM_NOC_DISP); +DEFINE_QNODE(qxm_rot_disp, SM8350_MASTER_ROTATOR_DISP, 1, 32, SM8350_SLAVE_MNOC_SF_MEM_NOC_DISP); +DEFINE_QNODE(qns_a1noc_snoc, SM8350_SLAVE_A1NOC_SNOC, 1, 16, SM8350_MASTER_A1NOC_SNOC); +DEFINE_QNODE(srvc_aggre1_noc, SM8350_SLAVE_SERVICE_A1NOC, 1, 4); +DEFINE_QNODE(qns_a2noc_snoc, SM8350_SLAVE_A2NOC_SNOC, 1, 16, SM8350_MASTER_A2NOC_SNOC); +DEFINE_QNODE(qns_pcie_mem_noc, SM8350_SLAVE_ANOC_PCIE_GEM_NOC, 1, 16, SM8350_MASTER_ANOC_PCIE_GEM_NOC); +DEFINE_QNODE(srvc_aggre2_noc, SM8350_SLAVE_SERVICE_A2NOC, 1, 4); +DEFINE_QNODE(qhs_ahb2phy0, SM8350_SLAVE_AHB2PHY_SOUTH, 1, 4); +DEFINE_QNODE(qhs_ahb2phy1, SM8350_SLAVE_AHB2PHY_NORTH, 1, 4); +DEFINE_QNODE(qhs_aoss, SM8350_SLAVE_AOSS, 1, 4); +DEFINE_QNODE(qhs_apss, SM8350_SLAVE_APPSS, 1, 8); +DEFINE_QNODE(qhs_camera_cfg, SM8350_SLAVE_CAMERA_CFG, 1, 4); +DEFINE_QNODE(qhs_clk_ctl, SM8350_SLAVE_CLK_CTL, 1, 4); +DEFINE_QNODE(qhs_compute_cfg, SM8350_SLAVE_CDSP_CFG, 1, 4); +DEFINE_QNODE(qhs_cpr_cx, SM8350_SLAVE_RBCPR_CX_CFG, 1, 4); +DEFINE_QNODE(qhs_cpr_mmcx, SM8350_SLAVE_RBCPR_MMCX_CFG, 1, 4); +DEFINE_QNODE(qhs_cpr_mx, SM8350_SLAVE_RBCPR_MX_CFG, 1, 4); +DEFINE_QNODE(qhs_crypto0_cfg, SM8350_SLAVE_CRYPTO_0_CFG, 1, 4); +DEFINE_QNODE(qhs_cx_rdpm, SM8350_SLAVE_CX_RDPM, 1, 4); +DEFINE_QNODE(qhs_dcc_cfg, SM8350_SLAVE_DCC_CFG, 1, 4); +DEFINE_QNODE(qhs_display_cfg, SM8350_SLAVE_DISPLAY_CFG, 1, 4); +DEFINE_QNODE(qhs_gpuss_cfg, SM8350_SLAVE_GFX3D_CFG, 1, 8); +DEFINE_QNODE(qhs_hwkm, SM8350_SLAVE_HWKM, 1, 4); +DEFINE_QNODE(qhs_imem_cfg, SM8350_SLAVE_IMEM_CFG, 1, 4); +DEFINE_QNODE(qhs_ipa, SM8350_SLAVE_IPA_CFG, 1, 4); +DEFINE_QNODE(qhs_ipc_router, SM8350_SLAVE_IPC_ROUTER_CFG, 1, 4); +DEFINE_QNODE(qhs_lpass_cfg, SM8350_SLAVE_LPASS, 1, 4, SM8350_MASTER_CNOC_LPASS_AG_NOC); +DEFINE_QNODE(qhs_mss_cfg, SM8350_SLAVE_CNOC_MSS, 1, 4); +DEFINE_QNODE(qhs_mx_rdpm, SM8350_SLAVE_MX_RDPM, 1, 4); +DEFINE_QNODE(qhs_pcie0_cfg, SM8350_SLAVE_PCIE_0_CFG, 1, 4); +DEFINE_QNODE(qhs_pcie1_cfg, SM8350_SLAVE_PCIE_1_CFG, 1, 4); +DEFINE_QNODE(qhs_pdm, SM8350_SLAVE_PDM, 1, 4); +DEFINE_QNODE(qhs_pimem_cfg, SM8350_SLAVE_PIMEM_CFG, 1, 4); +DEFINE_QNODE(qhs_pka_wrapper_cfg, SM8350_SLAVE_PKA_WRAPPER_CFG, 1, 4); +DEFINE_QNODE(qhs_pmu_wrapper_cfg, SM8350_SLAVE_PMU_WRAPPER_CFG, 1, 4); +DEFINE_QNODE(qhs_qdss_cfg, SM8350_SLAVE_QDSS_CFG, 1, 4); +DEFINE_QNODE(qhs_qspi, SM8350_SLAVE_QSPI_0, 1, 4); +DEFINE_QNODE(qhs_qup0, SM8350_SLAVE_QUP_0, 1, 4); +DEFINE_QNODE(qhs_qup1, SM8350_SLAVE_QUP_1, 1, 4); +DEFINE_QNODE(qhs_qup2, SM8350_SLAVE_QUP_2, 1, 4); +DEFINE_QNODE(qhs_sdc2, SM8350_SLAVE_SDCC_2, 1, 4); +DEFINE_QNODE(qhs_sdc4, SM8350_SLAVE_SDCC_4, 1, 4); +DEFINE_QNODE(qhs_security, SM8350_SLAVE_SECURITY, 1, 4); +DEFINE_QNODE(qhs_spss_cfg, SM8350_SLAVE_SPSS_CFG, 1, 4); +DEFINE_QNODE(qhs_tcsr, SM8350_SLAVE_TCSR, 1, 4); +DEFINE_QNODE(qhs_tlmm, SM8350_SLAVE_TLMM, 1, 4); +DEFINE_QNODE(qhs_ufs_card_cfg, SM8350_SLAVE_UFS_CARD_CFG, 1, 4); +DEFINE_QNODE(qhs_ufs_mem_cfg, SM8350_SLAVE_UFS_MEM_CFG, 1, 4); +DEFINE_QNODE(qhs_usb3_0, SM8350_SLAVE_USB3_0, 1, 4); +DEFINE_QNODE(qhs_usb3_1, SM8350_SLAVE_USB3_1, 1, 4); +DEFINE_QNODE(qhs_venus_cfg, SM8350_SLAVE_VENUS_CFG, 1, 4); +DEFINE_QNODE(qhs_vsense_ctrl_cfg, SM8350_SLAVE_VSENSE_CTRL_CFG, 1, 4); +DEFINE_QNODE(qns_a1_noc_cfg, SM8350_SLAVE_A1NOC_CFG, 1, 4); +DEFINE_QNODE(qns_a2_noc_cfg, SM8350_SLAVE_A2NOC_CFG, 1, 4); +DEFINE_QNODE(qns_ddrss_cfg, SM8350_SLAVE_DDRSS_CFG, 1, 4); +DEFINE_QNODE(qns_mnoc_cfg, SM8350_SLAVE_CNOC_MNOC_CFG, 1, 4); +DEFINE_QNODE(qns_snoc_cfg, SM8350_SLAVE_SNOC_CFG, 1, 4); +DEFINE_QNODE(qxs_boot_imem, SM8350_SLAVE_BOOT_IMEM, 1, 8); +DEFINE_QNODE(qxs_imem, SM8350_SLAVE_IMEM, 1, 8); +DEFINE_QNODE(qxs_pimem, SM8350_SLAVE_PIMEM, 1, 8); +DEFINE_QNODE(srvc_cnoc, SM8350_SLAVE_SERVICE_CNOC, 1, 4); +DEFINE_QNODE(xs_pcie_0, SM8350_SLAVE_PCIE_0, 1, 8); +DEFINE_QNODE(xs_pcie_1, SM8350_SLAVE_PCIE_1, 1, 8); +DEFINE_QNODE(xs_qdss_stm, SM8350_SLAVE_QDSS_STM, 1, 4); +DEFINE_QNODE(xs_sys_tcu_cfg, SM8350_SLAVE_TCU, 1, 8); +DEFINE_QNODE(qhs_llcc, SM8350_SLAVE_LLCC_CFG, 1, 4); +DEFINE_QNODE(qns_gemnoc, SM8350_SLAVE_GEM_NOC_CFG, 1, 4); +DEFINE_QNODE(qhs_mdsp_ms_mpu_cfg, SM8350_SLAVE_MSS_PROC_MS_MPU_CFG, 1, 4); +DEFINE_QNODE(qhs_modem_ms_mpu_cfg, SM8350_SLAVE_MCDMA_MS_MPU_CFG, 1, 4); +DEFINE_QNODE(qns_gem_noc_cnoc, SM8350_SLAVE_GEM_NOC_CNOC, 1, 16); +DEFINE_QNODE(qns_llcc, SM8350_SLAVE_LLCC, 4, 16, SM8350_MASTER_LLCC); +DEFINE_QNODE(qns_pcie, SM8350_SLAVE_MEM_NOC_PCIE_SNOC, 1, 8); +DEFINE_QNODE(srvc_even_gemnoc, SM8350_SLAVE_SERVICE_GEM_NOC_1, 1, 4); +DEFINE_QNODE(srvc_odd_gemnoc, SM8350_SLAVE_SERVICE_GEM_NOC_2, 1, 4); +DEFINE_QNODE(srvc_sys_gemnoc, SM8350_SLAVE_SERVICE_GEM_NOC, 1, 4); +DEFINE_QNODE(qhs_lpass_core, SM8350_SLAVE_LPASS_CORE_CFG, 1, 4); +DEFINE_QNODE(qhs_lpass_lpi, SM8350_SLAVE_LPASS_LPI_CFG, 1, 4); +DEFINE_QNODE(qhs_lpass_mpu, SM8350_SLAVE_LPASS_MPU_CFG, 1, 4); +DEFINE_QNODE(qhs_lpass_top, SM8350_SLAVE_LPASS_TOP_CFG, 1, 4); +DEFINE_QNODE(srvc_niu_aml_noc, SM8350_SLAVE_SERVICES_LPASS_AML_NOC, 1, 4); +DEFINE_QNODE(srvc_niu_lpass_agnoc, SM8350_SLAVE_SERVICE_LPASS_AG_NOC, 1, 4); +DEFINE_QNODE(ebi, SM8350_SLAVE_EBI1, 4, 4); +DEFINE_QNODE(qns_mem_noc_hf, SM8350_SLAVE_MNOC_HF_MEM_NOC, 2, 32, SM8350_MASTER_MNOC_HF_MEM_NOC); +DEFINE_QNODE(qns_mem_noc_sf, SM8350_SLAVE_MNOC_SF_MEM_NOC, 2, 32, SM8350_MASTER_MNOC_SF_MEM_NOC); +DEFINE_QNODE(srvc_mnoc, SM8350_SLAVE_SERVICE_MNOC, 1, 4); +DEFINE_QNODE(qns_nsp_gemnoc, SM8350_SLAVE_CDSP_MEM_NOC, 2, 32, SM8350_MASTER_COMPUTE_NOC); +DEFINE_QNODE(service_nsp_noc, SM8350_SLAVE_SERVICE_NSP_NOC, 1, 4); +DEFINE_QNODE(qns_gemnoc_gc, SM8350_SLAVE_SNOC_GEM_NOC_GC, 1, 8, SM8350_MASTER_SNOC_GC_MEM_NOC); +DEFINE_QNODE(qns_gemnoc_sf, SM8350_SLAVE_SNOC_GEM_NOC_SF, 1, 16, SM8350_MASTER_SNOC_SF_MEM_NOC); +DEFINE_QNODE(srvc_snoc, SM8350_SLAVE_SERVICE_SNOC, 1, 4); +DEFINE_QNODE(qns_llcc_disp, SM8350_SLAVE_LLCC_DISP, 4, 16, SM8350_MASTER_LLCC_DISP); +DEFINE_QNODE(ebi_disp, SM8350_SLAVE_EBI1_DISP, 4, 4); +DEFINE_QNODE(qns_mem_noc_hf_disp, SM8350_SLAVE_MNOC_HF_MEM_NOC_DISP, 2, 32, SM8350_MASTER_MNOC_HF_MEM_NOC_DISP); +DEFINE_QNODE(qns_mem_noc_sf_disp, SM8350_SLAVE_MNOC_SF_MEM_NOC_DISP, 2, 32, SM8350_MASTER_MNOC_SF_MEM_NOC_DISP); + +DEFINE_QBCM(bcm_acv, "ACV", false, &ebi); +DEFINE_QBCM(bcm_ce0, "CE0", false, &qxm_crypto); +DEFINE_QBCM(bcm_cn0, "CN0", true, &qnm_gemnoc_cnoc, &qnm_gemnoc_pcie); +DEFINE_QBCM(bcm_cn1, "CN1", false, &xm_qdss_dap, &qhs_ahb2phy0, &qhs_ahb2phy1, &qhs_aoss, &qhs_apss, &qhs_camera_cfg, &qhs_clk_ctl, &qhs_compute_cfg, &qhs_cpr_cx, &qhs_cpr_mmcx, &qhs_cpr_mx, &qhs_crypto0_cfg, &qhs_cx_rdpm, &qhs_dcc_cfg, &qhs_display_cfg, &qhs_gpuss_cfg, &qhs_hwkm, &qhs_imem_cfg, &qhs_ipa, &qhs_ipc_router, &qhs_mss_cfg, &qhs_mx_rdpm, &qhs_pcie0_cfg, &qhs_pcie1_cfg, &qhs_pimem_cfg, &qhs_pka_wrapper_cfg, &qhs_pmu_wrapper_cfg, &qhs_qdss_cfg, &qhs_qup0, &qhs_qup1, &qhs_qup2, &qhs_security, &qhs_spss_cfg, &qhs_tcsr, &qhs_tlmm, &qhs_ufs_card_cfg, &qhs_ufs_mem_cfg, &qhs_usb3_0, &qhs_usb3_1, &qhs_venus_cfg, &qhs_vsense_ctrl_cfg, &qns_a1_noc_cfg, &qns_a2_noc_cfg, &qns_ddrss_cfg, &qns_mnoc_cfg, &qns_snoc_cfg, &srvc_cnoc); +DEFINE_QBCM(bcm_cn2, "CN2", false, &qhs_lpass_cfg, &qhs_pdm, &qhs_qspi, &qhs_sdc2, &qhs_sdc4); +DEFINE_QBCM(bcm_co0, "CO0", false, &qns_nsp_gemnoc); +DEFINE_QBCM(bcm_co3, "CO3", false, &qxm_nsp); +DEFINE_QBCM(bcm_mc0, "MC0", true, &ebi); +DEFINE_QBCM(bcm_mm0, "MM0", true, &qns_mem_noc_hf); +DEFINE_QBCM(bcm_mm1, "MM1", false, &qnm_camnoc_hf, &qxm_mdp0, &qxm_mdp1); +DEFINE_QBCM(bcm_mm4, "MM4", false, &qns_mem_noc_sf); +DEFINE_QBCM(bcm_mm5, "MM5", false, &qnm_camnoc_icp, &qnm_camnoc_sf, &qnm_video0, &qnm_video1, &qnm_video_cvp, &qxm_rot); +DEFINE_QBCM(bcm_sh0, "SH0", true, &qns_llcc); +DEFINE_QBCM(bcm_sh2, "SH2", false, &alm_gpu_tcu, &alm_sys_tcu); +DEFINE_QBCM(bcm_sh3, "SH3", false, &qnm_cmpnoc); +DEFINE_QBCM(bcm_sh4, "SH4", false, &chm_apps); +DEFINE_QBCM(bcm_sn0, "SN0", true, &qns_gemnoc_sf); +DEFINE_QBCM(bcm_sn2, "SN2", false, &qns_gemnoc_gc); +DEFINE_QBCM(bcm_sn3, "SN3", false, &qxs_pimem); +DEFINE_QBCM(bcm_sn4, "SN4", false, &xs_qdss_stm); +DEFINE_QBCM(bcm_sn5, "SN5", false, &xm_pcie3_0); +DEFINE_QBCM(bcm_sn6, "SN6", false, &xm_pcie3_1); +DEFINE_QBCM(bcm_sn7, "SN7", false, &qnm_aggre1_noc); +DEFINE_QBCM(bcm_sn8, "SN8", false, &qnm_aggre2_noc); +DEFINE_QBCM(bcm_sn14, "SN14", false, &qns_pcie_mem_noc); +DEFINE_QBCM(bcm_acv_disp, "ACV", false, &ebi_disp); +DEFINE_QBCM(bcm_mc0_disp, "MC0", false, &ebi_disp); +DEFINE_QBCM(bcm_mm0_disp, "MM0", false, &qns_mem_noc_hf_disp); +DEFINE_QBCM(bcm_mm1_disp, "MM1", false, &qxm_mdp0_disp, &qxm_mdp1_disp); +DEFINE_QBCM(bcm_mm4_disp, "MM4", false, &qns_mem_noc_sf_disp); +DEFINE_QBCM(bcm_mm5_disp, "MM5", false, &qxm_rot_disp); +DEFINE_QBCM(bcm_sh0_disp, "SH0", false, &qns_llcc_disp); + +static struct qcom_icc_bcm *aggre1_noc_bcms[] = { +}; + +static struct qcom_icc_node *aggre1_noc_nodes[] = { + [MASTER_QSPI_0] = &qhm_qspi, + [MASTER_QUP_1] = &qhm_qup1, + [MASTER_A1NOC_CFG] = &qnm_a1noc_cfg, + [MASTER_SDCC_4] = &xm_sdc4, + [MASTER_UFS_MEM] = &xm_ufs_mem, + [MASTER_USB3_0] = &xm_usb3_0, + [MASTER_USB3_1] = &xm_usb3_1, + [SLAVE_A1NOC_SNOC] = &qns_a1noc_snoc, + [SLAVE_SERVICE_A1NOC] = &srvc_aggre1_noc, +}; + +static struct qcom_icc_desc sm8350_aggre1_noc = { + .nodes = aggre1_noc_nodes, + .num_nodes = ARRAY_SIZE(aggre1_noc_nodes), + .bcms = aggre1_noc_bcms, + .num_bcms = ARRAY_SIZE(aggre1_noc_bcms), +}; + +static struct qcom_icc_bcm *aggre2_noc_bcms[] = { + &bcm_ce0, + &bcm_sn5, + &bcm_sn6, + &bcm_sn14, +}; + +static struct qcom_icc_node *aggre2_noc_nodes[] = { + [SM8350_MASTER_QDSS_BAM] = &qhm_qdss_bam, + [SM8350_MASTER_QUP_0] = &qhm_qup0, + [SM8350_MASTER_QUP_2] = &qhm_qup2, + [SM8350_MASTER_A2NOC_CFG] = &qnm_a2noc_cfg, + [SM8350_MASTER_CRYPTO] = &qxm_crypto, + [SM8350_MASTER_IPA] = &qxm_ipa, + [SM8350_MASTER_PCIE_0] = &xm_pcie3_0, + [SM8350_MASTER_PCIE_1] = &xm_pcie3_1, + [SM8350_MASTER_QDSS_ETR] = &xm_qdss_etr, + [SM8350_MASTER_SDCC_2] = &xm_sdc2, + [SM8350_MASTER_UFS_CARD] = &xm_ufs_card, + [SM8350_SLAVE_A2NOC_SNOC] = &qns_a2noc_snoc, + [SM8350_SLAVE_ANOC_PCIE_GEM_NOC] = &qns_pcie_mem_noc, + [SM8350_SLAVE_SERVICE_A2NOC] = &srvc_aggre2_noc, +}; + +static struct qcom_icc_desc sm8350_aggre2_noc = { + .nodes = aggre2_noc_nodes, + .num_nodes = ARRAY_SIZE(aggre2_noc_nodes), + .bcms = aggre2_noc_bcms, + .num_bcms = ARRAY_SIZE(aggre2_noc_bcms), +}; + +static struct qcom_icc_bcm *config_noc_bcms[] = { + &bcm_cn0, + &bcm_cn1, + &bcm_cn2, + &bcm_sn3, + &bcm_sn4, +}; + +static struct qcom_icc_node *config_noc_nodes[] = { + [MASTER_GEM_NOC_CNOC] = &qnm_gemnoc_cnoc, + [MASTER_GEM_NOC_PCIE_SNOC] = &qnm_gemnoc_pcie, + [MASTER_QDSS_DAP] = &xm_qdss_dap, + [SLAVE_AHB2PHY_SOUTH] = &qhs_ahb2phy0, + [SLAVE_AHB2PHY_NORTH] = &qhs_ahb2phy1, + [SLAVE_AOSS] = &qhs_aoss, + [SLAVE_APPSS] = &qhs_apss, + [SLAVE_CAMERA_CFG] = &qhs_camera_cfg, + [SLAVE_CLK_CTL] = &qhs_clk_ctl, + [SLAVE_CDSP_CFG] = &qhs_compute_cfg, + [SLAVE_RBCPR_CX_CFG] = &qhs_cpr_cx, + [SLAVE_RBCPR_MMCX_CFG] = &qhs_cpr_mmcx, + [SLAVE_RBCPR_MX_CFG] = &qhs_cpr_mx, + [SLAVE_CRYPTO_0_CFG] = &qhs_crypto0_cfg, + [SLAVE_CX_RDPM] = &qhs_cx_rdpm, + [SLAVE_DCC_CFG] = &qhs_dcc_cfg, + [SLAVE_DISPLAY_CFG] = &qhs_display_cfg, + [SLAVE_GFX3D_CFG] = &qhs_gpuss_cfg, + [SLAVE_HWKM] = &qhs_hwkm, + [SLAVE_IMEM_CFG] = &qhs_imem_cfg, + [SLAVE_IPA_CFG] = &qhs_ipa, + [SLAVE_IPC_ROUTER_CFG] = &qhs_ipc_router, + [SLAVE_LPASS] = &qhs_lpass_cfg, + [SLAVE_CNOC_MSS] = &qhs_mss_cfg, + [SLAVE_MX_RDPM] = &qhs_mx_rdpm, + [SLAVE_PCIE_0_CFG] = &qhs_pcie0_cfg, + [SLAVE_PCIE_1_CFG] = &qhs_pcie1_cfg, + [SLAVE_PDM] = &qhs_pdm, + [SLAVE_PIMEM_CFG] = &qhs_pimem_cfg, + [SLAVE_PKA_WRAPPER_CFG] = &qhs_pka_wrapper_cfg, + [SLAVE_PMU_WRAPPER_CFG] = &qhs_pmu_wrapper_cfg, + [SLAVE_QDSS_CFG] = &qhs_qdss_cfg, + [SLAVE_QSPI_0] = &qhs_qspi, + [SLAVE_QUP_0] = &qhs_qup0, + [SLAVE_QUP_1] = &qhs_qup1, + [SLAVE_QUP_2] = &qhs_qup2, + [SLAVE_SDCC_2] = &qhs_sdc2, + [SLAVE_SDCC_4] = &qhs_sdc4, + [SLAVE_SECURITY] = &qhs_security, + [SLAVE_SPSS_CFG] = &qhs_spss_cfg, + [SLAVE_TCSR] = &qhs_tcsr, + [SLAVE_TLMM] = &qhs_tlmm, + [SLAVE_UFS_CARD_CFG] = &qhs_ufs_card_cfg, + [SLAVE_UFS_MEM_CFG] = &qhs_ufs_mem_cfg, + [SLAVE_USB3_0] = &qhs_usb3_0, + [SLAVE_USB3_1] = &qhs_usb3_1, + [SLAVE_VENUS_CFG] = &qhs_venus_cfg, + [SLAVE_VSENSE_CTRL_CFG] = &qhs_vsense_ctrl_cfg, + [SLAVE_A1NOC_CFG] = &qns_a1_noc_cfg, + [SLAVE_A2NOC_CFG] = &qns_a2_noc_cfg, + [SLAVE_DDRSS_CFG] = &qns_ddrss_cfg, + [SLAVE_CNOC_MNOC_CFG] = &qns_mnoc_cfg, + [SLAVE_SNOC_CFG] = &qns_snoc_cfg, + [SLAVE_BOOT_IMEM] = &qxs_boot_imem, + [SLAVE_IMEM] = &qxs_imem, + [SLAVE_PIMEM] = &qxs_pimem, + [SLAVE_SERVICE_CNOC] = &srvc_cnoc, + [SLAVE_PCIE_0] = &xs_pcie_0, + [SLAVE_PCIE_1] = &xs_pcie_1, + [SLAVE_QDSS_STM] = &xs_qdss_stm, + [SLAVE_TCU] = &xs_sys_tcu_cfg, +}; + +static struct qcom_icc_desc sm8350_config_noc = { + .nodes = config_noc_nodes, + .num_nodes = ARRAY_SIZE(config_noc_nodes), + .bcms = config_noc_bcms, + .num_bcms = ARRAY_SIZE(config_noc_bcms), +}; + +static struct qcom_icc_bcm *dc_noc_bcms[] = { +}; + +static struct qcom_icc_node *dc_noc_nodes[] = { + [MASTER_CNOC_DC_NOC] = &qnm_cnoc_dc_noc, + [SLAVE_LLCC_CFG] = &qhs_llcc, + [SLAVE_GEM_NOC_CFG] = &qns_gemnoc, +}; + +static struct qcom_icc_desc sm8350_dc_noc = { + .nodes = dc_noc_nodes, + .num_nodes = ARRAY_SIZE(dc_noc_nodes), + .bcms = dc_noc_bcms, + .num_bcms = ARRAY_SIZE(dc_noc_bcms), +}; + +static struct qcom_icc_bcm *gem_noc_bcms[] = { + &bcm_sh0, + &bcm_sh2, + &bcm_sh3, + &bcm_sh4, + &bcm_sh0_disp, +}; + +static struct qcom_icc_node *gem_noc_nodes[] = { + [MASTER_GPU_TCU] = &alm_gpu_tcu, + [MASTER_SYS_TCU] = &alm_sys_tcu, + [MASTER_APPSS_PROC] = &chm_apps, + [MASTER_COMPUTE_NOC] = &qnm_cmpnoc, + [MASTER_GEM_NOC_CFG] = &qnm_gemnoc_cfg, + [MASTER_GFX3D] = &qnm_gpu, + [MASTER_MNOC_HF_MEM_NOC] = &qnm_mnoc_hf, + [MASTER_MNOC_SF_MEM_NOC] = &qnm_mnoc_sf, + [MASTER_ANOC_PCIE_GEM_NOC] = &qnm_pcie, + [MASTER_SNOC_GC_MEM_NOC] = &qnm_snoc_gc, + [MASTER_SNOC_SF_MEM_NOC] = &qnm_snoc_sf, + [SLAVE_MSS_PROC_MS_MPU_CFG] = &qhs_mdsp_ms_mpu_cfg, + [SLAVE_MCDMA_MS_MPU_CFG] = &qhs_modem_ms_mpu_cfg, + [SLAVE_GEM_NOC_CNOC] = &qns_gem_noc_cnoc, + [SLAVE_LLCC] = &qns_llcc, + [SLAVE_MEM_NOC_PCIE_SNOC] = &qns_pcie, + [SLAVE_SERVICE_GEM_NOC_1] = &srvc_even_gemnoc, + [SLAVE_SERVICE_GEM_NOC_2] = &srvc_odd_gemnoc, + [SLAVE_SERVICE_GEM_NOC] = &srvc_sys_gemnoc, + [MASTER_MNOC_HF_MEM_NOC_DISP] = &qnm_mnoc_hf_disp, + [MASTER_MNOC_SF_MEM_NOC_DISP] = &qnm_mnoc_sf_disp, + [SLAVE_LLCC_DISP] = &qns_llcc_disp, +}; + +static struct qcom_icc_desc sm8350_gem_noc = { + .nodes = gem_noc_nodes, + .num_nodes = ARRAY_SIZE(gem_noc_nodes), + .bcms = gem_noc_bcms, + .num_bcms = ARRAY_SIZE(gem_noc_bcms), +}; + +static struct qcom_icc_bcm *lpass_ag_noc_bcms[] = { +}; + +static struct qcom_icc_node *lpass_ag_noc_nodes[] = { + [MASTER_CNOC_LPASS_AG_NOC] = &qhm_config_noc, + [SLAVE_LPASS_CORE_CFG] = &qhs_lpass_core, + [SLAVE_LPASS_LPI_CFG] = &qhs_lpass_lpi, + [SLAVE_LPASS_MPU_CFG] = &qhs_lpass_mpu, + [SLAVE_LPASS_TOP_CFG] = &qhs_lpass_top, + [SLAVE_SERVICES_LPASS_AML_NOC] = &srvc_niu_aml_noc, + [SLAVE_SERVICE_LPASS_AG_NOC] = &srvc_niu_lpass_agnoc, +}; + +static struct qcom_icc_desc sm8350_lpass_ag_noc = { + .nodes = lpass_ag_noc_nodes, + .num_nodes = ARRAY_SIZE(lpass_ag_noc_nodes), + .bcms = lpass_ag_noc_bcms, + .num_bcms = ARRAY_SIZE(lpass_ag_noc_bcms), +}; + +static struct qcom_icc_bcm *mc_virt_bcms[] = { + &bcm_acv, + &bcm_mc0, + &bcm_acv_disp, + &bcm_mc0_disp, +}; + +static struct qcom_icc_node *mc_virt_nodes[] = { + [SM8350_MASTER_LLCC] = &llcc_mc, + [SM8350_SLAVE_EBI1] = &ebi, + [SM8350_MASTER_LLCC_DISP] = &llcc_mc_disp, + [SM8350_SLAVE_EBI1_DISP] = &ebi_disp, +}; + +static struct qcom_icc_desc sm8350_mc_virt = { + .nodes = mc_virt_nodes, + .num_nodes = ARRAY_SIZE(mc_virt_nodes), + .bcms = mc_virt_bcms, + .num_bcms = ARRAY_SIZE(mc_virt_bcms), +}; + +static struct qcom_icc_bcm *mmss_noc_bcms[] = { + &bcm_mm0, + &bcm_mm1, + &bcm_mm4, + &bcm_mm5, + &bcm_mm0_disp, + &bcm_mm1_disp, + &bcm_mm4_disp, + &bcm_mm5_disp, +}; + +static struct qcom_icc_node *mmss_noc_nodes[] = { + [SM8350_MASTER_CAMNOC_HF] = &qnm_camnoc_hf, + [SM8350_MASTER_CAMNOC_ICP] = &qnm_camnoc_icp, + [SM8350_MASTER_CAMNOC_SF] = &qnm_camnoc_sf, + [SM8350_MASTER_CNOC_MNOC_CFG] = &qnm_mnoc_cfg, + [SM8350_MASTER_VIDEO_P0] = &qnm_video0, + [SM8350_MASTER_VIDEO_P1] = &qnm_video1, + [SM8350_MASTER_VIDEO_PROC] = &qnm_video_cvp, + [SM8350_MASTER_MDP0] = &qxm_mdp0, + [SM8350_MASTER_MDP1] = &qxm_mdp1, + [SM8350_MASTER_ROTATOR] = &qxm_rot, + [SM8350_SLAVE_MNOC_HF_MEM_NOC] = &qns_mem_noc_hf, + [SM8350_SLAVE_MNOC_SF_MEM_NOC] = &qns_mem_noc_sf, + [SM8350_SLAVE_SERVICE_MNOC] = &srvc_mnoc, + [SM8350_MASTER_MDP0_DISP] = &qxm_mdp0_disp, + [SM8350_MASTER_MDP1_DISP] = &qxm_mdp1_disp, + [SM8350_MASTER_ROTATOR_DISP] = &qxm_rot_disp, + [SM8350_SLAVE_MNOC_HF_MEM_NOC_DISP] = &qns_mem_noc_hf_disp, + [SM8350_SLAVE_MNOC_SF_MEM_NOC_DISP] = &qns_mem_noc_sf_disp, +}; + +static struct qcom_icc_desc sm8350_mmss_noc = { + .nodes = mmss_noc_nodes, + .num_nodes = ARRAY_SIZE(mmss_noc_nodes), + .bcms = mmss_noc_bcms, + .num_bcms = ARRAY_SIZE(mmss_noc_bcms), +}; + +static struct qcom_icc_bcm *nsp_noc_bcms[] = { + &bcm_co0, + &bcm_co3, +}; + +static struct qcom_icc_node *nsp_noc_nodes[] = { + [SM8350_MASTER_CDSP_NOC_CFG] = &qhm_nsp_noc_config, + [SM8350_MASTER_CDSP_PROC] = &qxm_nsp, + [SM8350_SLAVE_CDSP_MEM_NOC] = &qns_nsp_gemnoc, + [SM8350_SLAVE_SERVICE_NSP_NOC] = &service_nsp_noc, +}; + +static struct qcom_icc_desc sm8350_compute_noc = { + .nodes = nsp_noc_nodes, + .num_nodes = ARRAY_SIZE(nsp_noc_nodes), + .bcms = nsp_noc_bcms, + .num_bcms = ARRAY_SIZE(nsp_noc_bcms), +}; + +static struct qcom_icc_bcm *system_noc_bcms[] = { + &bcm_sn0, + &bcm_sn2, + &bcm_sn7, + &bcm_sn8, +}; + +static struct qcom_icc_node *system_noc_nodes[] = { + [MASTER_A1NOC_SNOC] = &qnm_aggre1_noc, + [MASTER_A2NOC_SNOC] = &qnm_aggre2_noc, + [MASTER_SNOC_CFG] = &qnm_snoc_cfg, + [MASTER_PIMEM] = &qxm_pimem, + [MASTER_GIC] = &xm_gic, + [SLAVE_SNOC_GEM_NOC_GC] = &qns_gemnoc_gc, + [SLAVE_SNOC_GEM_NOC_SF] = &qns_gemnoc_sf, + [SLAVE_SERVICE_SNOC] = &srvc_snoc, +}; + +static struct qcom_icc_desc sm8350_system_noc = { + .nodes = system_noc_nodes, + .num_nodes = ARRAY_SIZE(system_noc_nodes), + .bcms = system_noc_bcms, + .num_bcms = ARRAY_SIZE(system_noc_bcms), +}; + +static int qnoc_probe(struct platform_device *pdev) +{ + const struct qcom_icc_desc *desc; + struct icc_onecell_data *data; + struct icc_provider *provider; + struct qcom_icc_node **qnodes; + struct qcom_icc_provider *qp; + struct icc_node *node; + size_t num_nodes, i; + int ret; + + desc = of_device_get_match_data(&pdev->dev); + if (!desc) + return -EINVAL; + + qnodes = desc->nodes; + num_nodes = desc->num_nodes; + + qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL); + if (!qp) + return -ENOMEM; + + data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL); + if (!data) + return -ENOMEM; + + provider = &qp->provider; + provider->dev = &pdev->dev; + provider->set = qcom_icc_set; + provider->pre_aggregate = qcom_icc_pre_aggregate; + provider->aggregate = qcom_icc_aggregate; + provider->xlate = of_icc_xlate_onecell; + INIT_LIST_HEAD(&provider->nodes); + provider->data = data; + + qp->dev = &pdev->dev; + qp->bcms = desc->bcms; + qp->num_bcms = desc->num_bcms; + + qp->voter = of_bcm_voter_get(qp->dev, NULL); + if (IS_ERR(qp->voter)) + return PTR_ERR(qp->voter); + + ret = icc_provider_add(provider); + if (ret) { + dev_err(&pdev->dev, "error adding interconnect provider\n"); + return ret; + } + + for (i = 0; i < qp->num_bcms; i++) + qcom_icc_bcm_init(qp->bcms[i], &pdev->dev); + + for (i = 0; i < num_nodes; i++) { + size_t j; + + if (!qnodes[i]) + continue; + + node = icc_node_create(qnodes[i]->id); + if (IS_ERR(node)) { + ret = PTR_ERR(node); + goto err; + } + + node->name = qnodes[i]->name; + node->data = qnodes[i]; + icc_node_add(node, provider); + + for (j = 0; j < qnodes[i]->num_links; j++) + icc_link_create(node, qnodes[i]->links[j]); + + data->nodes[i] = node; + } + data->num_nodes = num_nodes; + + platform_set_drvdata(pdev, qp); + + return ret; + +err: + icc_nodes_remove(provider); + icc_provider_del(provider); + return ret; +} + +static int qnoc_remove(struct platform_device *pdev) +{ + struct qcom_icc_provider *qp = platform_get_drvdata(pdev); + + icc_nodes_remove(&qp->provider); + return icc_provider_del(&qp->provider); +} + +static const struct of_device_id qnoc_of_match[] = { + { .compatible = "qcom,sm8350-aggre1-noc", .data = &sm8350_aggre1_noc}, + { .compatible = "qcom,sm8350-aggre2-noc", .data = &sm8350_aggre2_noc}, + { .compatible = "qcom,sm8350-config-noc", .data = &sm8350_config_noc}, + { .compatible = "qcom,sm8350-dc-noc", .data = &sm8350_dc_noc}, + { .compatible = "qcom,sm8350-gem-noc", .data = &sm8350_gem_noc}, + { .compatible = "qcom,sm8350-lpass-ag-noc", .data = &sm8350_lpass_ag_noc}, + { .compatible = "qcom,sm8350-mc-virt", .data = &sm8350_mc_virt}, + { .compatible = "qcom,sm8350-mmss-noc", .data = &sm8350_mmss_noc}, + { .compatible = "qcom,sm8350-compute-noc", .data = &sm8350_compute_noc}, + { .compatible = "qcom,sm8350-system-noc", .data = &sm8350_system_noc}, + { } +}; +MODULE_DEVICE_TABLE(of, qnoc_of_match); + +static struct platform_driver qnoc_driver = { + .probe = qnoc_probe, + .remove = qnoc_remove, + .driver = { + .name = "qnoc-sm8350", + .of_match_table = qnoc_of_match, + .sync_state = icc_sync_state, + }, +}; +module_platform_driver(qnoc_driver); + +MODULE_DESCRIPTION("SM8350 NoC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/interconnect/qcom/sm8350.h b/drivers/interconnect/qcom/sm8350.h new file mode 100644 index 000000000000..328d15238a0d --- /dev/null +++ b/drivers/interconnect/qcom/sm8350.h @@ -0,0 +1,168 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Qualcomm SM8350 interconnect IDs + * + * Copyright (c) 2021, Linaro Limited + */ + +#ifndef __DRIVERS_INTERCONNECT_QCOM_SM8350_H +#define __DRIVERS_INTERCONNECT_QCOM_SM8350_H + +#define SM8350_MASTER_GPU_TCU 0 +#define SM8350_MASTER_SYS_TCU 1 +#define SM8350_MASTER_APPSS_PROC 2 +#define SM8350_MASTER_LLCC 3 +#define SM8350_MASTER_CNOC_LPASS_AG_NOC 4 +#define SM8350_MASTER_CDSP_NOC_CFG 5 +#define SM8350_MASTER_QDSS_BAM 6 +#define SM8350_MASTER_QSPI_0 7 +#define SM8350_MASTER_QUP_0 8 +#define SM8350_MASTER_QUP_1 9 +#define SM8350_MASTER_QUP_2 10 +#define SM8350_MASTER_A1NOC_CFG 11 +#define SM8350_MASTER_A2NOC_CFG 12 +#define SM8350_MASTER_A1NOC_SNOC 13 +#define SM8350_MASTER_A2NOC_SNOC 14 +#define SM8350_MASTER_CAMNOC_HF 15 +#define SM8350_MASTER_CAMNOC_ICP 16 +#define SM8350_MASTER_CAMNOC_SF 17 +#define SM8350_MASTER_COMPUTE_NOC 18 +#define SM8350_MASTER_CNOC_DC_NOC 19 +#define SM8350_MASTER_GEM_NOC_CFG 20 +#define SM8350_MASTER_GEM_NOC_CNOC 21 +#define SM8350_MASTER_GEM_NOC_PCIE_SNOC 22 +#define SM8350_MASTER_GFX3D 23 +#define SM8350_MASTER_CNOC_MNOC_CFG 24 +#define SM8350_MASTER_MNOC_HF_MEM_NOC 25 +#define SM8350_MASTER_MNOC_SF_MEM_NOC 26 +#define SM8350_MASTER_ANOC_PCIE_GEM_NOC 27 +#define SM8350_MASTER_SNOC_CFG 28 +#define SM8350_MASTER_SNOC_GC_MEM_NOC 29 +#define SM8350_MASTER_SNOC_SF_MEM_NOC 30 +#define SM8350_MASTER_VIDEO_P0 31 +#define SM8350_MASTER_VIDEO_P1 32 +#define SM8350_MASTER_VIDEO_PROC 33 +#define SM8350_MASTER_QUP_CORE_0 34 +#define SM8350_MASTER_QUP_CORE_1 35 +#define SM8350_MASTER_QUP_CORE_2 36 +#define SM8350_MASTER_CRYPTO 37 +#define SM8350_MASTER_IPA 38 +#define SM8350_MASTER_MDP0 39 +#define SM8350_MASTER_MDP1 40 +#define SM8350_MASTER_CDSP_PROC 41 +#define SM8350_MASTER_PIMEM 42 +#define SM8350_MASTER_ROTATOR 43 +#define SM8350_MASTER_GIC 44 +#define SM8350_MASTER_PCIE_0 45 +#define SM8350_MASTER_PCIE_1 46 +#define SM8350_MASTER_QDSS_DAP 47 +#define SM8350_MASTER_QDSS_ETR 48 +#define SM8350_MASTER_SDCC_2 49 +#define SM8350_MASTER_SDCC_4 50 +#define SM8350_MASTER_UFS_CARD 51 +#define SM8350_MASTER_UFS_MEM 52 +#define SM8350_MASTER_USB3_0 53 +#define SM8350_MASTER_USB3_1 54 +#define SM8350_SLAVE_EBI1 55 +#define SM8350_SLAVE_AHB2PHY_SOUTH 56 +#define SM8350_SLAVE_AHB2PHY_NORTH 57 +#define SM8350_SLAVE_AOSS 58 +#define SM8350_SLAVE_APPSS 59 +#define SM8350_SLAVE_CAMERA_CFG 60 +#define SM8350_SLAVE_CLK_CTL 61 +#define SM8350_SLAVE_CDSP_CFG 62 +#define SM8350_SLAVE_RBCPR_CX_CFG 63 +#define SM8350_SLAVE_RBCPR_MMCX_CFG 64 +#define SM8350_SLAVE_RBCPR_MX_CFG 65 +#define SM8350_SLAVE_CRYPTO_0_CFG 66 +#define SM8350_SLAVE_CX_RDPM 67 +#define SM8350_SLAVE_DCC_CFG 68 +#define SM8350_SLAVE_DISPLAY_CFG 69 +#define SM8350_SLAVE_GFX3D_CFG 70 +#define SM8350_SLAVE_HWKM 71 +#define SM8350_SLAVE_IMEM_CFG 72 +#define SM8350_SLAVE_IPA_CFG 73 +#define SM8350_SLAVE_IPC_ROUTER_CFG 74 +#define SM8350_SLAVE_LLCC_CFG 75 +#define SM8350_SLAVE_LPASS 76 +#define SM8350_SLAVE_LPASS_CORE_CFG 77 +#define SM8350_SLAVE_LPASS_LPI_CFG 78 +#define SM8350_SLAVE_LPASS_MPU_CFG 79 +#define SM8350_SLAVE_LPASS_TOP_CFG 80 +#define SM8350_SLAVE_MSS_PROC_MS_MPU_CFG 81 +#define SM8350_SLAVE_MCDMA_MS_MPU_CFG 82 +#define SM8350_SLAVE_CNOC_MSS 83 +#define SM8350_SLAVE_MX_RDPM 84 +#define SM8350_SLAVE_PCIE_0_CFG 85 +#define SM8350_SLAVE_PCIE_1_CFG 86 +#define SM8350_SLAVE_PDM 87 +#define SM8350_SLAVE_PIMEM_CFG 88 +#define SM8350_SLAVE_PKA_WRAPPER_CFG 89 +#define SM8350_SLAVE_PMU_WRAPPER_CFG 90 +#define SM8350_SLAVE_QDSS_CFG 91 +#define SM8350_SLAVE_QSPI_0 92 +#define SM8350_SLAVE_QUP_0 93 +#define SM8350_SLAVE_QUP_1 94 +#define SM8350_SLAVE_QUP_2 95 +#define SM8350_SLAVE_SDCC_2 96 +#define SM8350_SLAVE_SDCC_4 97 +#define SM8350_SLAVE_SECURITY 98 +#define SM8350_SLAVE_SPSS_CFG 99 +#define SM8350_SLAVE_TCSR 100 +#define SM8350_SLAVE_TLMM 101 +#define SM8350_SLAVE_UFS_CARD_CFG 102 +#define SM8350_SLAVE_UFS_MEM_CFG 103 +#define SM8350_SLAVE_USB3_0 104 +#define SM8350_SLAVE_USB3_1 105 +#define SM8350_SLAVE_VENUS_CFG 106 +#define SM8350_SLAVE_VSENSE_CTRL_CFG 107 +#define SM8350_SLAVE_A1NOC_CFG 108 +#define SM8350_SLAVE_A1NOC_SNOC 109 +#define SM8350_SLAVE_A2NOC_CFG 110 +#define SM8350_SLAVE_A2NOC_SNOC 111 +#define SM8350_SLAVE_DDRSS_CFG 112 +#define SM8350_SLAVE_GEM_NOC_CNOC 113 +#define SM8350_SLAVE_GEM_NOC_CFG 114 +#define SM8350_SLAVE_SNOC_GEM_NOC_GC 115 +#define SM8350_SLAVE_SNOC_GEM_NOC_SF 116 +#define SM8350_SLAVE_LLCC 117 +#define SM8350_SLAVE_MNOC_HF_MEM_NOC 118 +#define SM8350_SLAVE_MNOC_SF_MEM_NOC 119 +#define SM8350_SLAVE_CNOC_MNOC_CFG 120 +#define SM8350_SLAVE_CDSP_MEM_NOC 121 +#define SM8350_SLAVE_MEM_NOC_PCIE_SNOC 122 +#define SM8350_SLAVE_ANOC_PCIE_GEM_NOC 123 +#define SM8350_SLAVE_SNOC_CFG 124 +#define SM8350_SLAVE_QUP_CORE_0 125 +#define SM8350_SLAVE_QUP_CORE_1 126 +#define SM8350_SLAVE_QUP_CORE_2 127 +#define SM8350_SLAVE_BOOT_IMEM 128 +#define SM8350_SLAVE_IMEM 129 +#define SM8350_SLAVE_PIMEM 130 +#define SM8350_SLAVE_SERVICE_NSP_NOC 131 +#define SM8350_SLAVE_SERVICE_A1NOC 132 +#define SM8350_SLAVE_SERVICE_A2NOC 133 +#define SM8350_SLAVE_SERVICE_CNOC 134 +#define SM8350_SLAVE_SERVICE_GEM_NOC_1 135 +#define SM8350_SLAVE_SERVICE_MNOC 136 +#define SM8350_SLAVE_SERVICES_LPASS_AML_NOC 137 +#define SM8350_SLAVE_SERVICE_LPASS_AG_NOC 138 +#define SM8350_SLAVE_SERVICE_GEM_NOC_2 139 +#define SM8350_SLAVE_SERVICE_SNOC 140 +#define SM8350_SLAVE_SERVICE_GEM_NOC 141 +#define SM8350_SLAVE_PCIE_0 142 +#define SM8350_SLAVE_PCIE_1 143 +#define SM8350_SLAVE_QDSS_STM 144 +#define SM8350_SLAVE_TCU 145 +#define SM8350_MASTER_LLCC_DISP 146 +#define SM8350_MASTER_MNOC_HF_MEM_NOC_DISP 147 +#define SM8350_MASTER_MNOC_SF_MEM_NOC_DISP 148 +#define SM8350_MASTER_MDP0_DISP 149 +#define SM8350_MASTER_MDP1_DISP 150 +#define SM8350_MASTER_ROTATOR_DISP 151 +#define SM8350_SLAVE_EBI1_DISP 152 +#define SM8350_SLAVE_LLCC_DISP 153 +#define SM8350_SLAVE_MNOC_HF_MEM_NOC_DISP 154 +#define SM8350_SLAVE_MNOC_SF_MEM_NOC_DISP 155 + +#endif -- cgit v1.2.3 From d0e874705ef9ec028f0de6f65e3781c6b10d3fa1 Mon Sep 17 00:00:00 2001 From: Zou Wei Date: Wed, 24 Mar 2021 08:48:23 +0000 Subject: misc: sgi-xp: xp_main: make some symbols static The sparse tool complains as follows: drivers/misc/sgi-xp/xp_main.c:24:22: warning: symbol 'xp_dbg_name' was not declared. Should it be static? drivers/misc/sgi-xp/xp_main.c:28:15: warning: symbol 'xp_dbg_subname' was not declared. Should it be static? These symbols are not used outside of xp_main.c, so this commit marks them static. Reported-by: Hulk Robot Signed-off-by: Zou Wei Link: https://lore.kernel.org/r/20210324084823.7393-1-zou_wei@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/sgi-xp/xp_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/sgi-xp/xp_main.c b/drivers/misc/sgi-xp/xp_main.c index cf2965aa5c05..87d156c15f35 100644 --- a/drivers/misc/sgi-xp/xp_main.c +++ b/drivers/misc/sgi-xp/xp_main.c @@ -21,11 +21,11 @@ /* define the XP debug device structures to be used with dev_dbg() et al */ -struct device_driver xp_dbg_name = { +static struct device_driver xp_dbg_name = { .name = "xp" }; -struct device xp_dbg_subname = { +static struct device xp_dbg_subname = { .init_name = "", /* set to "" */ .driver = &xp_dbg_name }; -- cgit v1.2.3 From dbdc671d5c855f05125e3a002b819978ac2190b9 Mon Sep 17 00:00:00 2001 From: Bhaskar Chowdhury Date: Thu, 25 Mar 2021 07:25:13 +0530 Subject: misc: genwqe: Rudimentary typo fixes s/requsted/requested/ s/equests/requests/ s/occured/occurred/ s/conditon/condition/ s/emtpy/empty/ Acked-by: Randy Dunlap Signed-off-by: Bhaskar Chowdhury Link: https://lore.kernel.org/r/20210325015513.9373-1-unixbhaskar@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/genwqe/card_ddcb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/misc/genwqe/card_ddcb.c b/drivers/misc/genwqe/card_ddcb.c index 0db4000dedf2..500b1feaf1f6 100644 --- a/drivers/misc/genwqe/card_ddcb.c +++ b/drivers/misc/genwqe/card_ddcb.c @@ -316,7 +316,7 @@ static int enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_queue *queue, /** * copy_ddcb_results() - Copy output state from real DDCB to request - * @req: pointer to requsted DDCB parameters + * @req: pointer to requested DDCB parameters * @ddcb_no: pointer to ddcb number being tapped * * Copy DDCB ASV to request struct. There is no endian @@ -356,7 +356,7 @@ static void copy_ddcb_results(struct ddcb_requ *req, int ddcb_no) } /** - * genwqe_check_ddcb_queue() - Checks DDCB queue for completed work equests. + * genwqe_check_ddcb_queue() - Checks DDCB queue for completed work requests. * @cd: pointer to genwqe device descriptor * @queue: queue to be checked * @@ -498,7 +498,7 @@ int __genwqe_wait_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req) /* * We need to distinguish 3 cases here: - * 1. rc == 0 timeout occured + * 1. rc == 0 timeout occurred * 2. rc == -ERESTARTSYS signal received * 3. rc > 0 remaining jiffies condition is true */ @@ -982,7 +982,7 @@ static int genwqe_next_ddcb_ready(struct genwqe_dev *cd) spin_lock_irqsave(&queue->ddcb_lock, flags); - if (queue_empty(queue)) { /* emtpy queue */ + if (queue_empty(queue)) { /* empty queue */ spin_unlock_irqrestore(&queue->ddcb_lock, flags); return 0; } @@ -1002,7 +1002,7 @@ static int genwqe_next_ddcb_ready(struct genwqe_dev *cd) * @cd: pointer to genwqe device descriptor * * Keep track on the number of DDCBs which ware currently in the - * queue. This is needed for statistics as well as conditon if we want + * queue. This is needed for statistics as well as condition if we want * to wait or better do polling in case of no interrupts available. */ int genwqe_ddcbs_in_flight(struct genwqe_dev *cd) -- cgit v1.2.3 From 1114ab22e417427d8dced25be02c15f479de8d41 Mon Sep 17 00:00:00 2001 From: Daniel Thompson Date: Thu, 25 Mar 2021 09:48:07 +0000 Subject: kgdbts: Switch to do_sys_openat2() for breakpoint testing Currently kgdbts can get stuck waiting for do_sys_open() to be called in some of the current tests. This is because C compilers often automatically inline this function, which is a very thin wrapper around do_sys_openat2(), into some of its callers. gcc-10 does this on (at least) both x86 and arm64. We can fix the test suite by placing the breakpoints on do_sys_openat2() instead since that isn't (currently) inlined. However do_sys_openat2() is a static function so we cannot simply use an addressof. Since we are testing debug machinery it is acceptable to use kallsyms to lookup a suitable address because this is more or less what kdb does in the same circumstances. Re-implement lookup_addr() to be based on kallsyms rather than function pointers. Signed-off-by: Daniel Thompson Link: https://lore.kernel.org/r/20210325094807.3546702-1-daniel.thompson@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/kgdbts.c | 48 +++++++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index 2e081a58da6c..64d33e368509 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -92,6 +92,7 @@ #include #include #include +#include #include @@ -200,21 +201,30 @@ static noinline void kgdbts_break_test(void) v2printk("kgdbts: breakpoint complete\n"); } -/* Lookup symbol info in the kernel */ +/* + * This is a cached wrapper for kallsyms_lookup_name(). + * + * The cache is a big win for several tests. For example it more the doubles + * the cycles per second during the sys_open test. This is not theoretic, + * the performance improvement shows up at human scale, especially when + * testing using emulators. + * + * Obviously neither re-entrant nor thread-safe but that is OK since it + * can only be called from the debug trap (and therefore all other CPUs + * are halted). + */ static unsigned long lookup_addr(char *arg) { - unsigned long addr = 0; - - if (!strcmp(arg, "kgdbts_break_test")) - addr = (unsigned long)kgdbts_break_test; - else if (!strcmp(arg, "sys_open")) - addr = (unsigned long)do_sys_open; - else if (!strcmp(arg, "kernel_clone")) - addr = (unsigned long)kernel_clone; - else if (!strcmp(arg, "hw_break_val")) - addr = (unsigned long)&hw_break_val; - addr = (unsigned long) dereference_function_descriptor((void *)addr); - return addr; + static char cached_arg[KSYM_NAME_LEN]; + static unsigned long cached_addr; + + if (strcmp(arg, cached_arg)) { + strscpy(cached_arg, arg, KSYM_NAME_LEN); + cached_addr = kallsyms_lookup_name(arg); + } + + return (unsigned long)dereference_function_descriptor( + (void *)cached_addr); } static void break_helper(char *bp_type, char *arg, unsigned long vaddr) @@ -310,7 +320,7 @@ static int check_and_rewind_pc(char *put_str, char *arg) if (arch_needs_sstep_emulation && sstep_addr && ip + offset == sstep_addr && - ((!strcmp(arg, "sys_open") || !strcmp(arg, "kernel_clone")))) { + ((!strcmp(arg, "do_sys_openat2") || !strcmp(arg, "kernel_clone")))) { /* This is special case for emulated single step */ v2printk("Emul: rewind hit single step bp\n"); restart_from_top_after_write = 1; @@ -619,14 +629,14 @@ static struct test_struct do_kernel_clone_test[] = { */ static struct test_struct sys_open_test[] = { { "?", "S0*" }, /* Clear break points */ - { "sys_open", "OK", sw_break, }, /* set sw breakpoint */ + { "do_sys_openat2", "OK", sw_break, }, /* set sw breakpoint */ { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */ - { "sys_open", "OK", sw_rem_break }, /*remove breakpoint */ - { "g", "sys_open", NULL, check_and_rewind_pc }, /* check location */ + { "do_sys_openat2", "OK", sw_rem_break }, /*remove breakpoint */ + { "g", "do_sys_openat2", NULL, check_and_rewind_pc }, /* check location */ { "write", "OK", write_regs, emul_reset }, /* Write registers */ { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ - { "g", "sys_open", NULL, check_single_step }, - { "sys_open", "OK", sw_break, }, /* set sw breakpoint */ + { "g", "do_sys_openat2", NULL, check_single_step }, + { "do_sys_openat2", "OK", sw_break, }, /* set sw breakpoint */ { "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */ { "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */ { "", "", get_cont_catch, put_cont_catch }, -- cgit v1.2.3 From f20b2c2a07f88c9a7532578674a60e501a07b839 Mon Sep 17 00:00:00 2001 From: Kai Ye Date: Fri, 26 Mar 2021 17:09:07 +0800 Subject: uacce: delete unneeded variable initialization delete unneeded variable initialization. Signed-off-by: Kai Ye Link: https://lore.kernel.org/r/1616749747-3882-1-git-send-email-yekai13@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/uacce/uacce.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/uacce/uacce.c b/drivers/misc/uacce/uacce.c index d07af4edfcac..94843e0e51c6 100644 --- a/drivers/misc/uacce/uacce.c +++ b/drivers/misc/uacce/uacce.c @@ -126,7 +126,7 @@ static int uacce_fops_open(struct inode *inode, struct file *filep) { struct uacce_device *uacce; struct uacce_queue *q; - int ret = 0; + int ret; uacce = xa_load(&uacce_xa, iminor(inode)); if (!uacce) -- cgit v1.2.3 From 40635128fee8c762b4b3e8ab805a15f01d60b859 Mon Sep 17 00:00:00 2001 From: Bhaskar Chowdhury Date: Fri, 26 Mar 2021 14:44:43 +0530 Subject: scripts/spdxcheck.py: Fix a typo s/Initilize/Initialize/ Signed-off-by: Bhaskar Chowdhury Link: https://lore.kernel.org/r/20210326091443.26525-1-unixbhaskar@gmail.com Signed-off-by: Greg Kroah-Hartman --- scripts/spdxcheck.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/spdxcheck.py b/scripts/spdxcheck.py index cbdb5c83c08f..3e784cf9f401 100755 --- a/scripts/spdxcheck.py +++ b/scripts/spdxcheck.py @@ -243,7 +243,7 @@ if __name__ == '__main__': # Initialize SPDX data spdx = read_spdxdata(repo) - # Initilize the parser + # Initialize the parser parser = id_parser(spdx) except SPDXException as se: -- cgit v1.2.3 From 6880149e5a78962a055720981d37e5069f296ef7 Mon Sep 17 00:00:00 2001 From: Xu Jia Date: Wed, 24 Mar 2021 15:20:31 +0800 Subject: applicom: fix some err codes returned by ac_ioctl When cmd > 6 or copy_to_user() fail, The variable 'ret' would not be returned back. Fix the 'ret' set but not used. Reviewed-by: Arnd Bergmann Signed-off-by: Xu Jia Link: https://lore.kernel.org/r/20210324072031.941791-1-xujia39@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/applicom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index 14b2d8034c51..0ab765143354 100644 --- a/drivers/char/applicom.c +++ b/drivers/char/applicom.c @@ -839,7 +839,7 @@ static long ac_ioctl(struct file *file, unsigned int cmd, unsigned long arg) Dummy = readb(apbs[IndexCard].RamIO + VERS); kfree(adgl); mutex_unlock(&ac_mutex); - return 0; + return ret; err: if (warncount) { -- cgit v1.2.3 From 6861d27cf590d20a95b5d0724ac3768583b62947 Mon Sep 17 00:00:00 2001 From: Mihai Carabas Date: Wed, 24 Mar 2021 16:49:14 +0200 Subject: misc/pvpanic: split-up generic and platform dependent code Split-up generic and platform dependent code in order to be able to re-use generic event handling code in pvpanic PCI device driver in the next patches. The code from pvpanic.c was split in two new files: - pvpanic.c: generic code that handles pvpanic events - pvpanic-mmio.c: platform/bus dependent code Signed-off-by: Mihai Carabas Link: https://lore.kernel.org/r/1616597356-20696-2-git-send-email-mihai.carabas@oracle.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/Kconfig | 9 +- drivers/misc/Makefile | 2 +- drivers/misc/pvpanic.c | 161 ------------------------------------ drivers/misc/pvpanic/Kconfig | 19 +++++ drivers/misc/pvpanic/Makefile | 7 ++ drivers/misc/pvpanic/pvpanic-mmio.c | 134 ++++++++++++++++++++++++++++++ drivers/misc/pvpanic/pvpanic.c | 81 ++++++++++++++++++ drivers/misc/pvpanic/pvpanic.h | 15 ++++ 8 files changed, 258 insertions(+), 170 deletions(-) delete mode 100644 drivers/misc/pvpanic.c create mode 100644 drivers/misc/pvpanic/Kconfig create mode 100644 drivers/misc/pvpanic/Makefile create mode 100644 drivers/misc/pvpanic/pvpanic-mmio.c create mode 100644 drivers/misc/pvpanic/pvpanic.c create mode 100644 drivers/misc/pvpanic/pvpanic.h diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index f532c59bb59b..c5f20e939ca3 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -427,14 +427,6 @@ config MISC_RTSX tristate default MISC_RTSX_PCI || MISC_RTSX_USB -config PVPANIC - tristate "pvpanic device support" - depends on HAS_IOMEM && (ACPI || OF) - help - This driver provides support for the pvpanic device. pvpanic is - a paravirtualized device provided by QEMU; it lets a virtual machine - (guest) communicate panic events to the host. - config HISI_HIKEY_USB tristate "USB GPIO Hub on HiSilicon Hikey 960/970 Platform" depends on (OF && GPIOLIB) || COMPILE_TEST @@ -461,4 +453,5 @@ source "drivers/misc/bcm-vk/Kconfig" source "drivers/misc/cardreader/Kconfig" source "drivers/misc/habanalabs/Kconfig" source "drivers/misc/uacce/Kconfig" +source "drivers/misc/pvpanic/Kconfig" endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 99b6f15a3c70..fd5f87e149c5 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -51,7 +51,7 @@ obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o obj-$(CONFIG_OCXL) += ocxl/ obj-$(CONFIG_BCM_VK) += bcm-vk/ obj-y += cardreader/ -obj-$(CONFIG_PVPANIC) += pvpanic.o +obj-$(CONFIG_PVPANIC) += pvpanic/ obj-$(CONFIG_HABANA_AI) += habanalabs/ obj-$(CONFIG_UACCE) += uacce/ obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o diff --git a/drivers/misc/pvpanic.c b/drivers/misc/pvpanic.c deleted file mode 100644 index f1655f5ca016..000000000000 --- a/drivers/misc/pvpanic.c +++ /dev/null @@ -1,161 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Pvpanic Device Support - * - * Copyright (C) 2013 Fujitsu. - * Copyright (C) 2018 ZTE. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include - -#include - -static void __iomem *base; -static unsigned int capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED; -static unsigned int events; - -static ssize_t capability_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sysfs_emit(buf, "%x\n", capability); -} -static DEVICE_ATTR_RO(capability); - -static ssize_t events_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sysfs_emit(buf, "%x\n", events); -} - -static ssize_t events_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned int tmp; - int err; - - err = kstrtouint(buf, 16, &tmp); - if (err) - return err; - - if ((tmp & capability) != tmp) - return -EINVAL; - - events = tmp; - - return count; - -} -static DEVICE_ATTR_RW(events); - -static struct attribute *pvpanic_dev_attrs[] = { - &dev_attr_capability.attr, - &dev_attr_events.attr, - NULL -}; -ATTRIBUTE_GROUPS(pvpanic_dev); - -MODULE_AUTHOR("Hu Tao "); -MODULE_DESCRIPTION("pvpanic device driver"); -MODULE_LICENSE("GPL"); - -static void -pvpanic_send_event(unsigned int event) -{ - if (event & capability & events) - iowrite8(event, base); -} - -static int -pvpanic_panic_notify(struct notifier_block *nb, unsigned long code, - void *unused) -{ - unsigned int event = PVPANIC_PANICKED; - - if (kexec_crash_loaded()) - event = PVPANIC_CRASH_LOADED; - - pvpanic_send_event(event); - - return NOTIFY_DONE; -} - -static struct notifier_block pvpanic_panic_nb = { - .notifier_call = pvpanic_panic_notify, - .priority = 1, /* let this called before broken drm_fb_helper */ -}; - -static int pvpanic_mmio_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct resource *res; - - res = platform_get_mem_or_io(pdev, 0); - if (!res) - return -EINVAL; - - switch (resource_type(res)) { - case IORESOURCE_IO: - base = devm_ioport_map(dev, res->start, resource_size(res)); - if (!base) - return -ENOMEM; - break; - case IORESOURCE_MEM: - base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - break; - default: - return -EINVAL; - } - - /* initlize capability by RDPT */ - capability &= ioread8(base); - events = capability; - - if (capability) - atomic_notifier_chain_register(&panic_notifier_list, - &pvpanic_panic_nb); - - return 0; -} - -static int pvpanic_mmio_remove(struct platform_device *pdev) -{ - - if (capability) - atomic_notifier_chain_unregister(&panic_notifier_list, - &pvpanic_panic_nb); - - return 0; -} - -static const struct of_device_id pvpanic_mmio_match[] = { - { .compatible = "qemu,pvpanic-mmio", }, - {} -}; -MODULE_DEVICE_TABLE(of, pvpanic_mmio_match); - -static const struct acpi_device_id pvpanic_device_ids[] = { - { "QEMU0001", 0 }, - { "", 0 } -}; -MODULE_DEVICE_TABLE(acpi, pvpanic_device_ids); - -static struct platform_driver pvpanic_mmio_driver = { - .driver = { - .name = "pvpanic-mmio", - .of_match_table = pvpanic_mmio_match, - .acpi_match_table = pvpanic_device_ids, - .dev_groups = pvpanic_dev_groups, - }, - .probe = pvpanic_mmio_probe, - .remove = pvpanic_mmio_remove, -}; -module_platform_driver(pvpanic_mmio_driver); diff --git a/drivers/misc/pvpanic/Kconfig b/drivers/misc/pvpanic/Kconfig new file mode 100644 index 000000000000..454f1ee62b72 --- /dev/null +++ b/drivers/misc/pvpanic/Kconfig @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Pvpanic Kconfig +# +# Copyright (C) 2021 Oracle. +# + +config PVPANIC + bool "pvpanic device support" + help + This option allows to select a specific pvpanic device driver. + pvpanic is a paravirtualized device provided by QEMU; it lets + a virtual machine (guest) communicate panic events to the host. + +config PVPANIC_MMIO + tristate "pvpanic MMIO device support" + depends on HAS_IOMEM && (ACPI || OF) && PVPANIC + help + This driver provides support for the MMIO pvpanic device. diff --git a/drivers/misc/pvpanic/Makefile b/drivers/misc/pvpanic/Makefile new file mode 100644 index 000000000000..e12a2dc2e982 --- /dev/null +++ b/drivers/misc/pvpanic/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Pvpanic Makefile +# +# Copyright (C) 2021 Oracle. +# +obj-$(CONFIG_PVPANIC_MMIO) += pvpanic.o pvpanic-mmio.o diff --git a/drivers/misc/pvpanic/pvpanic-mmio.c b/drivers/misc/pvpanic/pvpanic-mmio.c new file mode 100644 index 000000000000..d7bf7db6c19c --- /dev/null +++ b/drivers/misc/pvpanic/pvpanic-mmio.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Pvpanic MMIO Device Support + * + * Copyright (C) 2013 Fujitsu. + * Copyright (C) 2018 ZTE. + * Copyright (C) 2021 Oracle. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "pvpanic.h" + +MODULE_AUTHOR("Hu Tao "); +MODULE_DESCRIPTION("pvpanic-mmio device driver"); +MODULE_LICENSE("GPL"); + +static void __iomem *base; +static unsigned int capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED; +static unsigned int events; + +static ssize_t capability_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%x\n", capability); +} +static DEVICE_ATTR_RO(capability); + +static ssize_t events_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%x\n", events); +} + +static ssize_t events_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int tmp; + int err; + + err = kstrtouint(buf, 16, &tmp); + if (err) + return err; + + if ((tmp & capability) != tmp) + return -EINVAL; + + events = tmp; + + pvpanic_set_events(events); + + return count; + +} +static DEVICE_ATTR_RW(events); + +static struct attribute *pvpanic_mmio_dev_attrs[] = { + &dev_attr_capability.attr, + &dev_attr_events.attr, + NULL +}; +ATTRIBUTE_GROUPS(pvpanic_mmio_dev); + +static int pvpanic_mmio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + + res = platform_get_mem_or_io(pdev, 0); + if (!res) + return -EINVAL; + + switch (resource_type(res)) { + case IORESOURCE_IO: + base = devm_ioport_map(dev, res->start, resource_size(res)); + if (!base) + return -ENOMEM; + break; + case IORESOURCE_MEM: + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + break; + default: + return -EINVAL; + } + + /* initlize capability by RDPT */ + capability &= ioread8(base); + events = capability; + + pvpanic_probe(base, capability); + + return 0; +} + +static int pvpanic_mmio_remove(struct platform_device *pdev) +{ + + pvpanic_remove(); + + return 0; +} + +static const struct of_device_id pvpanic_mmio_match[] = { + { .compatible = "qemu,pvpanic-mmio", }, + {} +}; +MODULE_DEVICE_TABLE(of, pvpanic_mmio_match); + +static const struct acpi_device_id pvpanic_device_ids[] = { + { "QEMU0001", 0 }, + { "", 0 } +}; +MODULE_DEVICE_TABLE(acpi, pvpanic_device_ids); + +static struct platform_driver pvpanic_mmio_driver = { + .driver = { + .name = "pvpanic-mmio", + .of_match_table = pvpanic_mmio_match, + .acpi_match_table = pvpanic_device_ids, + .dev_groups = pvpanic_mmio_dev_groups, + }, + .probe = pvpanic_mmio_probe, + .remove = pvpanic_mmio_remove, +}; +module_platform_driver(pvpanic_mmio_driver); diff --git a/drivers/misc/pvpanic/pvpanic.c b/drivers/misc/pvpanic/pvpanic.c new file mode 100644 index 000000000000..a9605f90c534 --- /dev/null +++ b/drivers/misc/pvpanic/pvpanic.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Pvpanic Device Support + * + * Copyright (C) 2013 Fujitsu. + * Copyright (C) 2018 ZTE. + * Copyright (C) 2021 Oracle. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "pvpanic.h" + +MODULE_AUTHOR("Mihai Carabas "); +MODULE_DESCRIPTION("pvpanic device driver "); +MODULE_LICENSE("GPL"); + +static void __iomem *base; +static unsigned int capability; +static unsigned int events; + +static void +pvpanic_send_event(unsigned int event) +{ + if (event & capability & events) + iowrite8(event, base); +} + +static int +pvpanic_panic_notify(struct notifier_block *nb, unsigned long code, + void *unused) +{ + unsigned int event = PVPANIC_PANICKED; + + if (kexec_crash_loaded()) + event = PVPANIC_CRASH_LOADED; + + pvpanic_send_event(event); + + return NOTIFY_DONE; +} + +static struct notifier_block pvpanic_panic_nb = { + .notifier_call = pvpanic_panic_notify, + .priority = 1, /* let this called before broken drm_fb_helper */ +}; + +void pvpanic_probe(void __iomem *pbase, unsigned int dev_cap) +{ + base = pbase; + capability = dev_cap; + events = capability; + + if (capability) + atomic_notifier_chain_register(&panic_notifier_list, + &pvpanic_panic_nb); +} +EXPORT_SYMBOL_GPL(pvpanic_probe); + +void pvpanic_remove(void) +{ + if (capability) + atomic_notifier_chain_unregister(&panic_notifier_list, + &pvpanic_panic_nb); + base = NULL; +} +EXPORT_SYMBOL_GPL(pvpanic_remove); + +void pvpanic_set_events(unsigned int dev_events) +{ + events = dev_events; +} +EXPORT_SYMBOL_GPL(pvpanic_set_events); diff --git a/drivers/misc/pvpanic/pvpanic.h b/drivers/misc/pvpanic/pvpanic.h new file mode 100644 index 000000000000..3abe15fa24b8 --- /dev/null +++ b/drivers/misc/pvpanic/pvpanic.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Pvpanic Device Support + * + * Copyright (C) 2021 Oracle. + */ + +#ifndef PVPANIC_H_ +#define PVPANIC_H_ + +void pvpanic_probe(void __iomem *base, unsigned int dev_cap); +void pvpanic_remove(void); +void pvpanic_set_events(unsigned int dev_events); + +#endif /* PVPANIC_H_ */ -- cgit v1.2.3 From b3c0f8774668fd30a3efb2d0afc1a6527dacb858 Mon Sep 17 00:00:00 2001 From: Mihai Carabas Date: Wed, 24 Mar 2021 16:49:15 +0200 Subject: misc/pvpanic: probe multiple instances Create the mecahism that allows multiple pvpanic instances to call pvpanic_probe and receive panic events. A global list will retain all the mapped addresses where to write panic events. Signed-off-by: Mihai Carabas Link: https://lore.kernel.org/r/1616597356-20696-3-git-send-email-mihai.carabas@oracle.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/pvpanic/pvpanic-mmio.c | 42 +++++++++++++--------- drivers/misc/pvpanic/pvpanic.c | 72 ++++++++++++++++++++++++++----------- drivers/misc/pvpanic/pvpanic.h | 12 +++++-- 3 files changed, 87 insertions(+), 39 deletions(-) diff --git a/drivers/misc/pvpanic/pvpanic-mmio.c b/drivers/misc/pvpanic/pvpanic-mmio.c index d7bf7db6c19c..4c0841776087 100644 --- a/drivers/misc/pvpanic/pvpanic-mmio.c +++ b/drivers/misc/pvpanic/pvpanic-mmio.c @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -23,25 +24,26 @@ MODULE_AUTHOR("Hu Tao "); MODULE_DESCRIPTION("pvpanic-mmio device driver"); MODULE_LICENSE("GPL"); -static void __iomem *base; -static unsigned int capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED; -static unsigned int events; - static ssize_t capability_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sysfs_emit(buf, "%x\n", capability); + struct pvpanic_instance *pi = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%x\n", pi->capability); } static DEVICE_ATTR_RO(capability); static ssize_t events_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sysfs_emit(buf, "%x\n", events); + struct pvpanic_instance *pi = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%x\n", pi->events); } static ssize_t events_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct pvpanic_instance *pi = dev_get_drvdata(dev); unsigned int tmp; int err; @@ -49,15 +51,12 @@ static ssize_t events_store(struct device *dev, struct device_attribute *attr, if (err) return err; - if ((tmp & capability) != tmp) + if ((tmp & pi->capability) != tmp) return -EINVAL; - events = tmp; - - pvpanic_set_events(events); + pi->events = tmp; return count; - } static DEVICE_ATTR_RW(events); @@ -71,7 +70,9 @@ ATTRIBUTE_GROUPS(pvpanic_mmio_dev); static int pvpanic_mmio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct pvpanic_instance *pi; struct resource *res; + void __iomem *base; res = platform_get_mem_or_io(pdev, 0); if (!res) @@ -92,19 +93,28 @@ static int pvpanic_mmio_probe(struct platform_device *pdev) return -EINVAL; } + pi = kmalloc(sizeof(*pi), GFP_ATOMIC); + if (!pi) + return -ENOMEM; + + pi->base = base; + pi->capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED; + /* initlize capability by RDPT */ - capability &= ioread8(base); - events = capability; + pi->capability &= ioread8(base); + pi->events = pi->capability; - pvpanic_probe(base, capability); + dev_set_drvdata(dev, pi); - return 0; + return pvpanic_probe(pi); } static int pvpanic_mmio_remove(struct platform_device *pdev) { + struct pvpanic_instance *pi = dev_get_drvdata(&pdev->dev); - pvpanic_remove(); + pvpanic_remove(pi); + kfree(pi); return 0; } diff --git a/drivers/misc/pvpanic/pvpanic.c b/drivers/misc/pvpanic/pvpanic.c index a9605f90c534..804099c2d7fa 100644 --- a/drivers/misc/pvpanic/pvpanic.c +++ b/drivers/misc/pvpanic/pvpanic.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include @@ -23,15 +25,20 @@ MODULE_AUTHOR("Mihai Carabas "); MODULE_DESCRIPTION("pvpanic device driver "); MODULE_LICENSE("GPL"); -static void __iomem *base; -static unsigned int capability; -static unsigned int events; +struct list_head pvpanic_list; +spinlock_t pvpanic_lock; static void pvpanic_send_event(unsigned int event) { - if (event & capability & events) - iowrite8(event, base); + struct pvpanic_instance *pi_cur; + + spin_lock(&pvpanic_lock); + list_for_each_entry(pi_cur, &pvpanic_list, list) { + if (event & pi_cur->capability & pi_cur->events) + iowrite8(event, pi_cur->base); + } + spin_unlock(&pvpanic_lock); } static int @@ -53,29 +60,54 @@ static struct notifier_block pvpanic_panic_nb = { .priority = 1, /* let this called before broken drm_fb_helper */ }; -void pvpanic_probe(void __iomem *pbase, unsigned int dev_cap) +int pvpanic_probe(struct pvpanic_instance *pi) { - base = pbase; - capability = dev_cap; - events = capability; + if (!pi || !pi->base) + return -EINVAL; + + spin_lock(&pvpanic_lock); + list_add(&pi->list, &pvpanic_list); + spin_unlock(&pvpanic_lock); - if (capability) - atomic_notifier_chain_register(&panic_notifier_list, - &pvpanic_panic_nb); + return 0; } EXPORT_SYMBOL_GPL(pvpanic_probe); -void pvpanic_remove(void) +void pvpanic_remove(struct pvpanic_instance *pi) { - if (capability) - atomic_notifier_chain_unregister(&panic_notifier_list, - &pvpanic_panic_nb); - base = NULL; + struct pvpanic_instance *pi_cur, *pi_next; + + if (!pi) + return; + + spin_lock(&pvpanic_lock); + list_for_each_entry_safe(pi_cur, pi_next, &pvpanic_list, list) { + if (pi_cur == pi) { + list_del(&pi_cur->list); + break; + } + } + spin_unlock(&pvpanic_lock); } EXPORT_SYMBOL_GPL(pvpanic_remove); -void pvpanic_set_events(unsigned int dev_events) +static int pvpanic_init(void) { - events = dev_events; + INIT_LIST_HEAD(&pvpanic_list); + spin_lock_init(&pvpanic_lock); + + atomic_notifier_chain_register(&panic_notifier_list, + &pvpanic_panic_nb); + + return 0; } -EXPORT_SYMBOL_GPL(pvpanic_set_events); + +static void pvpanic_exit(void) +{ + atomic_notifier_chain_unregister(&panic_notifier_list, + &pvpanic_panic_nb); + +} + +module_init(pvpanic_init); +module_exit(pvpanic_exit); diff --git a/drivers/misc/pvpanic/pvpanic.h b/drivers/misc/pvpanic/pvpanic.h index 3abe15fa24b8..1afccc2e9fec 100644 --- a/drivers/misc/pvpanic/pvpanic.h +++ b/drivers/misc/pvpanic/pvpanic.h @@ -8,8 +8,14 @@ #ifndef PVPANIC_H_ #define PVPANIC_H_ -void pvpanic_probe(void __iomem *base, unsigned int dev_cap); -void pvpanic_remove(void); -void pvpanic_set_events(unsigned int dev_events); +struct pvpanic_instance { + void __iomem *base; + unsigned int capability; + unsigned int events; + struct list_head list; +}; + +int pvpanic_probe(struct pvpanic_instance *pi); +void pvpanic_remove(struct pvpanic_instance *pi); #endif /* PVPANIC_H_ */ -- cgit v1.2.3 From db3a4f0abefd7be96089fcd74029c259df3bed76 Mon Sep 17 00:00:00 2001 From: Mihai Carabas Date: Wed, 24 Mar 2021 16:49:16 +0200 Subject: misc/pvpanic: add PCI driver Add support for pvpanic PCI device added in qemu [1]. At probe time, obtain the address where to read/write pvpanic events and pass it to the generic handling code. Will follow the same logic as pvpanic MMIO device driver. At remove time, unmap base address and disable PCI device. [1] https://github.com/qemu/qemu/commit/9df52f58e76e904fb141b10318362d718f470db2 Signed-off-by: Mihai Carabas Link: https://lore.kernel.org/r/1616597356-20696-4-git-send-email-mihai.carabas@oracle.com Signed-off-by: Greg Kroah-Hartman --- .../ABI/testing/sysfs-bus-pci-devices-pvpanic | 4 +- drivers/misc/pvpanic/Kconfig | 8 ++ drivers/misc/pvpanic/Makefile | 1 + drivers/misc/pvpanic/pvpanic-pci.c | 125 +++++++++++++++++++++ 4 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 drivers/misc/pvpanic/pvpanic-pci.c diff --git a/Documentation/ABI/testing/sysfs-bus-pci-devices-pvpanic b/Documentation/ABI/testing/sysfs-bus-pci-devices-pvpanic index 1936f7324155..4ec03cd36357 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci-devices-pvpanic +++ b/Documentation/ABI/testing/sysfs-bus-pci-devices-pvpanic @@ -1,4 +1,5 @@ -What: /sys/devices/pci0000:00/*/QEMU0001:00/capability +What: /sys/devices/pci0000:00/*/QEMU0001:00/capability for MMIO + /sys/bus/pci/drivers/pvpanic-pci/0000:00:0*.0/capability for PCI Date: Jan 2021 Contact: zhenwei pi Description: @@ -12,6 +13,7 @@ Description: https://git.qemu.org/?p=qemu.git;a=blob_plain;f=docs/specs/pvpanic.txt What: /sys/devices/pci0000:00/*/QEMU0001:00/events + /sys/bus/pci/drivers/pvpanic-pci/0000:00:0*.0/events for PCI Date: Jan 2021 Contact: zhenwei pi Description: diff --git a/drivers/misc/pvpanic/Kconfig b/drivers/misc/pvpanic/Kconfig index 454f1ee62b72..12d40a21f698 100644 --- a/drivers/misc/pvpanic/Kconfig +++ b/drivers/misc/pvpanic/Kconfig @@ -17,3 +17,11 @@ config PVPANIC_MMIO depends on HAS_IOMEM && (ACPI || OF) && PVPANIC help This driver provides support for the MMIO pvpanic device. + +config PVPANIC_PCI + tristate "pvpanic PCI device support" + depends on PCI && PVPANIC + help + This driver provides support for the PCI pvpanic device. + pvpanic is a paravirtualized device provided by QEMU which + forwards the panic events from the guest to the host. diff --git a/drivers/misc/pvpanic/Makefile b/drivers/misc/pvpanic/Makefile index e12a2dc2e982..9471df7d4f9c 100644 --- a/drivers/misc/pvpanic/Makefile +++ b/drivers/misc/pvpanic/Makefile @@ -5,3 +5,4 @@ # Copyright (C) 2021 Oracle. # obj-$(CONFIG_PVPANIC_MMIO) += pvpanic.o pvpanic-mmio.o +obj-$(CONFIG_PVPANIC_PCI) += pvpanic.o pvpanic-pci.o diff --git a/drivers/misc/pvpanic/pvpanic-pci.c b/drivers/misc/pvpanic/pvpanic-pci.c new file mode 100644 index 000000000000..f38a80a5bbc8 --- /dev/null +++ b/drivers/misc/pvpanic/pvpanic-pci.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Pvpanic PCI Device Support + * + * Copyright (C) 2021 Oracle. + */ + +#include +#include +#include +#include +#include + +#include + +#include "pvpanic.h" + +#define PCI_VENDOR_ID_REDHAT 0x1b36 +#define PCI_DEVICE_ID_REDHAT_PVPANIC 0x0011 + +MODULE_AUTHOR("Mihai Carabas "); +MODULE_DESCRIPTION("pvpanic device driver "); +MODULE_LICENSE("GPL"); + +static const struct pci_device_id pvpanic_pci_id_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_PVPANIC)}, + {} +}; + +static ssize_t capability_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pvpanic_instance *pi = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%x\n", pi->capability); +} +static DEVICE_ATTR_RO(capability); + +static ssize_t events_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pvpanic_instance *pi = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%x\n", pi->events); +} + +static ssize_t events_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct pvpanic_instance *pi = dev_get_drvdata(dev); + unsigned int tmp; + int err; + + err = kstrtouint(buf, 16, &tmp); + if (err) + return err; + + if ((tmp & pi->capability) != tmp) + return -EINVAL; + + pi->events = tmp; + + return count; +} +static DEVICE_ATTR_RW(events); + +static struct attribute *pvpanic_pci_dev_attrs[] = { + &dev_attr_capability.attr, + &dev_attr_events.attr, + NULL +}; +ATTRIBUTE_GROUPS(pvpanic_pci_dev); + +static int pvpanic_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct device *dev = &pdev->dev; + struct pvpanic_instance *pi; + void __iomem *base; + int ret; + + ret = pci_enable_device(pdev); + if (ret < 0) + return ret; + + base = pci_iomap(pdev, 0, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + pi = kmalloc(sizeof(*pi), GFP_ATOMIC); + if (!pi) + return -ENOMEM; + + pi->base = base; + pi->capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED; + + /* initlize capability by RDPT */ + pi->capability &= ioread8(base); + pi->events = pi->capability; + + dev_set_drvdata(dev, pi); + + return pvpanic_probe(pi); +} + +static void pvpanic_pci_remove(struct pci_dev *pdev) +{ + struct pvpanic_instance *pi = dev_get_drvdata(&pdev->dev); + + pvpanic_remove(pi); + iounmap(pi->base); + kfree(pi); + pci_disable_device(pdev); +} + +static struct pci_driver pvpanic_pci_driver = { + .name = "pvpanic-pci", + .id_table = pvpanic_pci_id_tbl, + .probe = pvpanic_pci_probe, + .remove = pvpanic_pci_remove, + .driver = { + .dev_groups = pvpanic_pci_dev_groups, + }, +}; + +module_pci_driver(pvpanic_pci_driver); -- cgit v1.2.3 From bbfb54e7b3e484943f8c00c58a0d6549e9078640 Mon Sep 17 00:00:00 2001 From: Xu Yilun Date: Mon, 8 Mar 2021 09:59:35 +0800 Subject: uio: uio_dfl: add userspace i/o driver for DFL bus This patch supports the DFL drivers be written in userspace. This is realized by exposing the userspace I/O device interfaces. The driver now only binds the ether group feature, which has no irq. So the irq support is not implemented yet. Reviewed-by: Tom Rix Signed-off-by: Xu Yilun Link: https://lore.kernel.org/r/1615168776-8553-2-git-send-email-yilun.xu@intel.com Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 + drivers/uio/Kconfig | 17 +++++++++++++ drivers/uio/Makefile | 1 + drivers/uio/uio_dfl.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 drivers/uio/uio_dfl.c diff --git a/MAINTAINERS b/MAINTAINERS index aa84121c5611..fca4a9f8f065 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6992,6 +6992,7 @@ S: Maintained F: Documentation/ABI/testing/sysfs-bus-dfl* F: Documentation/fpga/dfl.rst F: drivers/fpga/dfl* +F: drivers/uio/uio_dfl.c F: include/linux/dfl.h F: include/uapi/linux/fpga-dfl.h diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig index 202ee81cfc2b..5531f3afeb21 100644 --- a/drivers/uio/Kconfig +++ b/drivers/uio/Kconfig @@ -165,4 +165,21 @@ config UIO_HV_GENERIC to network and storage devices from userspace. If you compile this as a module, it will be called uio_hv_generic. + +config UIO_DFL + tristate "Generic driver for DFL (Device Feature List) bus" + depends on FPGA_DFL + help + Generic DFL (Device Feature List) driver for Userspace I/O devices. + It is useful to provide direct access to DFL devices from userspace. + A sample userspace application using this driver is available for + download in a git repository: + + git clone https://github.com/OPAE/opae-sdk.git + + It could be found at: + + opae-sdk/tools/libopaeuio/ + + If you compile this as a module, it will be called uio_dfl. endif diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile index c285dd2a4539..f2f416a14228 100644 --- a/drivers/uio/Makefile +++ b/drivers/uio/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_UIO_PRUSS) += uio_pruss.o obj-$(CONFIG_UIO_MF624) += uio_mf624.o obj-$(CONFIG_UIO_FSL_ELBC_GPCM) += uio_fsl_elbc_gpcm.o obj-$(CONFIG_UIO_HV_GENERIC) += uio_hv_generic.o +obj-$(CONFIG_UIO_DFL) += uio_dfl.o diff --git a/drivers/uio/uio_dfl.c b/drivers/uio/uio_dfl.c new file mode 100644 index 000000000000..89c0fc7b0cbc --- /dev/null +++ b/drivers/uio/uio_dfl.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Generic DFL driver for Userspace I/O devicess + * + * Copyright (C) 2021 Intel Corporation, Inc. + */ +#include +#include +#include +#include + +#define DRIVER_NAME "uio_dfl" + +static int uio_dfl_probe(struct dfl_device *ddev) +{ + struct resource *r = &ddev->mmio_res; + struct device *dev = &ddev->dev; + struct uio_info *uioinfo; + struct uio_mem *uiomem; + int ret; + + uioinfo = devm_kzalloc(dev, sizeof(struct uio_info), GFP_KERNEL); + if (!uioinfo) + return -ENOMEM; + + uioinfo->name = DRIVER_NAME; + uioinfo->version = "0"; + + uiomem = &uioinfo->mem[0]; + uiomem->memtype = UIO_MEM_PHYS; + uiomem->addr = r->start & PAGE_MASK; + uiomem->offs = r->start & ~PAGE_MASK; + uiomem->size = (uiomem->offs + resource_size(r) + + PAGE_SIZE - 1) & PAGE_MASK; + uiomem->name = r->name; + + /* Irq is yet to be supported */ + uioinfo->irq = UIO_IRQ_NONE; + + ret = devm_uio_register_device(dev, uioinfo); + if (ret) + dev_err(dev, "unable to register uio device\n"); + + return ret; +} + +#define FME_FEATURE_ID_ETH_GROUP 0x10 + +static const struct dfl_device_id uio_dfl_ids[] = { + { FME_ID, FME_FEATURE_ID_ETH_GROUP }, + { } +}; +MODULE_DEVICE_TABLE(dfl, uio_dfl_ids); + +static struct dfl_driver uio_dfl_driver = { + .drv = { + .name = DRIVER_NAME, + }, + .id_table = uio_dfl_ids, + .probe = uio_dfl_probe, +}; +module_dfl_driver(uio_dfl_driver); + +MODULE_DESCRIPTION("Generic DFL driver for Userspace I/O devices"); +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From d72260cc7879c72c186900e7c153007a6137ed8e Mon Sep 17 00:00:00 2001 From: Xu Yilun Date: Mon, 8 Mar 2021 09:59:36 +0800 Subject: Documentation: fpga: dfl: Add description for DFL UIO support This patch adds description for UIO support for dfl devices on DFL bus. Reviewed-by: Tom Rix Reviewed-by: Wu Hao Signed-off-by: Xu Yilun Link: https://lore.kernel.org/r/1615168776-8553-3-git-send-email-yilun.xu@intel.com Signed-off-by: Greg Kroah-Hartman --- Documentation/fpga/dfl.rst | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Documentation/fpga/dfl.rst b/Documentation/fpga/dfl.rst index c41ac76ffaae..f3a1223f2517 100644 --- a/Documentation/fpga/dfl.rst +++ b/Documentation/fpga/dfl.rst @@ -7,6 +7,7 @@ Authors: - Enno Luebbers - Xiao Guangrong - Wu Hao +- Xu Yilun The Device Feature List (DFL) FPGA framework (and drivers according to this framework) hides the very details of low layer hardwares and provides @@ -530,6 +531,31 @@ Being able to specify more than one DFL per BAR has been considered, but it was determined the use case did not provide value. Specifying a single DFL per BAR simplifies the implementation and allows for extra error checking. + +Userspace driver support for DFL devices +======================================== +The purpose of an FPGA is to be reprogrammed with newly developed hardware +components. New hardware can instantiate a new private feature in the DFL, and +then present a DFL device in the system. In some cases users may need a +userspace driver for the DFL device: + +* Users may need to run some diagnostic test for their hardware. +* Users may prototype the kernel driver in user space. +* Some hardware is designed for specific purposes and does not fit into one of + the standard kernel subsystems. + +This requires direct access to MMIO space and interrupt handling from +userspace. The uio_dfl module exposes the UIO device interfaces for this +purpose. + +Currently the uio_dfl driver only supports the Ether Group sub feature, which +has no irq in hardware. So the interrupt handling is not added in this driver. + +UIO_DFL should be selected to enable the uio_dfl module driver. To support a +new DFL feature via UIO direct access, its feature id should be added to the +driver's id_table. + + Open discussion =============== FME driver exports one ioctl (DFL_FPGA_FME_PORT_PR) for partial reconfiguration -- cgit v1.2.3 From 0196b52b83dd7e925879ac969f1dcd543b9ea774 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 17:11:12 +0800 Subject: soundwire: bus: use correct driver name in error messages None of the existing codec drivers set the sdw_driver.name, but instead set sdw_driver.driver.name. This leads to error messages such as [ 23.935355] rt700 sdw:2:25d:700:0: Probe of (null) failed: -19 We could remove this sdw_driver.name if it doesn't have any purpose. This patch only suggests using the proper indirection. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Reviewed-by: Kai Vehmanen Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210302091122.13952-2-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus_type.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index 575b9bad99d5..893296f3fe39 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -82,6 +82,7 @@ static int sdw_drv_probe(struct device *dev) struct sdw_slave *slave = dev_to_sdw_dev(dev); struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); const struct sdw_device_id *id; + const char *name; int ret; /* @@ -108,7 +109,10 @@ static int sdw_drv_probe(struct device *dev) ret = drv->probe(slave, id); if (ret) { - dev_err(dev, "Probe of %s failed: %d\n", drv->name, ret); + name = drv->name; + if (!name) + name = drv->driver.name; + dev_err(dev, "Probe of %s failed: %d\n", name, ret); dev_pm_domain_detach(dev, false); return ret; } @@ -174,11 +178,16 @@ static void sdw_drv_shutdown(struct device *dev) */ int __sdw_register_driver(struct sdw_driver *drv, struct module *owner) { + const char *name; + drv->driver.bus = &sdw_bus_type; if (!drv->probe) { - pr_err("driver %s didn't provide SDW probe routine\n", - drv->name); + name = drv->name; + if (!name) + name = drv->driver.name; + + pr_err("driver %s didn't provide SDW probe routine\n", name); return -EINVAL; } -- cgit v1.2.3 From 665cf215bc4cadfbf79c43b2aebe0fc818789aa2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 17:11:13 +0800 Subject: soundwire: bus: test read status In the existing code we may read a negative error value but still mask it and write it back. Make sure all reads are tested and errors not propagated further. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Reviewed-by: Kai Vehmanen Reviewed-by: Guennadi Liakhovetski Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210302091122.13952-3-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 04eb879de145..1c01cc192cbd 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -875,8 +875,12 @@ static int sdw_slave_clk_stop_prepare(struct sdw_slave *slave, if (wake_en) val |= SDW_SCP_SYSTEMCTRL_WAKE_UP_EN; } else { - val = sdw_read_no_pm(slave, SDW_SCP_SYSTEMCTRL); - + ret = sdw_read_no_pm(slave, SDW_SCP_SYSTEMCTRL); + if (ret < 0) { + dev_err(&slave->dev, "SDW_SCP_SYSTEMCTRL read failed:%d\n", ret); + return ret; + } + val = ret; val &= ~(SDW_SCP_SYSTEMCTRL_CLK_STP_PREP); } @@ -895,8 +899,12 @@ static int sdw_bus_wait_for_clk_prep_deprep(struct sdw_bus *bus, u16 dev_num) int val; do { - val = sdw_bread_no_pm(bus, dev_num, SDW_SCP_STAT) & - SDW_SCP_STAT_CLK_STP_NF; + val = sdw_bread_no_pm(bus, dev_num, SDW_SCP_STAT); + if (val < 0) { + dev_err(bus->dev, "SDW_SCP_STAT bread failed:%d\n", val); + return val; + } + val &= SDW_SCP_STAT_CLK_STP_NF; if (!val) { dev_info(bus->dev, "clock stop prep/de-prep done slave:%d", dev_num); -- cgit v1.2.3 From a5759f193fa3dbc7c256dd8675e41e6ca4f6abf6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 17:11:14 +0800 Subject: soundwire: bus: use consistent tests for return values We use different styles to check the return values of IO related routines. The majority of the cases use 'if (ret < 0)', align the remaining cases for consistency. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Reviewed-by: Kai Vehmanen Reviewed-by: Guennadi Liakhovetski Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210302091122.13952-4-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 1c01cc192cbd..d39e5baa3e64 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -44,13 +44,13 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, } ret = sdw_get_id(bus); - if (ret) { + if (ret < 0) { dev_err(parent, "Failed to get bus id\n"); return ret; } ret = sdw_master_device_add(bus, parent, fwnode); - if (ret) { + if (ret < 0) { dev_err(parent, "Failed to add master device at link %d\n", bus->link_id); return ret; @@ -121,7 +121,7 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, else ret = -ENOTSUPP; /* No ACPI/DT so error out */ - if (ret) { + if (ret < 0) { dev_err(bus->dev, "Finding slaves failed:%d\n", ret); return ret; } @@ -422,7 +422,7 @@ sdw_bread_no_pm(struct sdw_bus *bus, u16 dev_num, u32 addr) ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num, SDW_MSG_FLAG_READ, &buf); - if (ret) + if (ret < 0) return ret; ret = sdw_transfer(bus, &msg); @@ -440,7 +440,7 @@ sdw_bwrite_no_pm(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 value) ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num, SDW_MSG_FLAG_WRITE, &value); - if (ret) + if (ret < 0) return ret; return sdw_transfer(bus, &msg); @@ -454,7 +454,7 @@ int sdw_bread_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr) ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num, SDW_MSG_FLAG_READ, &buf); - if (ret) + if (ret < 0) return ret; ret = sdw_transfer_unlocked(bus, &msg); @@ -472,7 +472,7 @@ int sdw_bwrite_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 val ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num, SDW_MSG_FLAG_WRITE, &value); - if (ret) + if (ret < 0) return ret; return sdw_transfer_unlocked(bus, &msg); @@ -749,7 +749,7 @@ static int sdw_program_device_num(struct sdw_bus *bus) * dev_num */ ret = sdw_assign_device_num(slave); - if (ret) { + if (ret < 0) { dev_err(bus->dev, "Assign dev_num failed:%d\n", ret); @@ -886,7 +886,7 @@ static int sdw_slave_clk_stop_prepare(struct sdw_slave *slave, ret = sdw_write_no_pm(slave, SDW_SCP_SYSTEMCTRL, val); - if (ret != 0) + if (ret < 0) dev_err(&slave->dev, "Clock Stop prepare failed for slave: %d", ret); @@ -1748,7 +1748,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, if (status[0] == SDW_SLAVE_ATTACHED) { dev_dbg(bus->dev, "Slave attached, programming device number\n"); ret = sdw_program_device_num(bus); - if (ret) + if (ret < 0) dev_err(bus->dev, "Slave attach failed: %d\n", ret); /* * programming a device number will have side effects, @@ -1782,7 +1782,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, case SDW_SLAVE_ALERT: ret = sdw_handle_slave_alerts(slave); - if (ret) + if (ret < 0) dev_err(&slave->dev, "Slave %d alert handling failed: %d\n", i, ret); @@ -1801,7 +1801,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, attached_initializing = true; ret = sdw_initialize_slave(slave); - if (ret) + if (ret < 0) dev_err(&slave->dev, "Slave %d initialization failed: %d\n", i, ret); @@ -1815,7 +1815,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, } ret = sdw_update_slave_status(slave, status[i]); - if (ret) + if (ret < 0) dev_err(&slave->dev, "Update Slave status failed:%d\n", ret); if (attached_initializing) { -- cgit v1.2.3 From af7254b4b19f3ff9650a1419f329eea1a811d306 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 17:11:15 +0800 Subject: soundwire: bus: demote clock stop prepare log to dev_dbg() There is no real reason to provide this information except for debug sessions, hence dev_dbg() is a better fit. Reported-by: Guennadi Liakhovetski Signed-off-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Reviewed-by: Kai Vehmanen Reviewed-by: Guennadi Liakhovetski Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210302091122.13952-5-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index d39e5baa3e64..8b6d8fe934ae 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -906,8 +906,8 @@ static int sdw_bus_wait_for_clk_prep_deprep(struct sdw_bus *bus, u16 dev_num) } val &= SDW_SCP_STAT_CLK_STP_NF; if (!val) { - dev_info(bus->dev, "clock stop prep/de-prep done slave:%d", - dev_num); + dev_dbg(bus->dev, "clock stop prep/de-prep done slave:%d", + dev_num); return 0; } -- cgit v1.2.3 From b500127e3835fb2663af050008c74f62432ddb90 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 17:11:16 +0800 Subject: soundwire: bus: uniquify dev_err() for SCP_INT access We have multiple cases where we read/write SCP_INT registers, but the same error message in all cases. Add a distinct error message for each case to help debug. Reported-by: Guennadi Liakhovetski Signed-off-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Reviewed-by: Kai Vehmanen Reviewed-by: Guennadi Liakhovetski Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210302091122.13952-6-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 8b6d8fe934ae..a38b017f7a54 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -1636,7 +1636,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) ret = sdw_read_no_pm(slave, SDW_SCP_INT1); if (ret < 0) { dev_err(&slave->dev, - "SDW_SCP_INT1 read failed:%d\n", ret); + "SDW_SCP_INT1 recheck read failed:%d\n", ret); goto io_err; } _buf = ret; @@ -1644,7 +1644,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) ret = sdw_nread_no_pm(slave, SDW_SCP_INTSTAT2, 2, _buf2); if (ret < 0) { dev_err(&slave->dev, - "SDW_SCP_INT2/3 read failed:%d\n", ret); + "SDW_SCP_INT2/3 recheck read failed:%d\n", ret); goto io_err; } @@ -1652,7 +1652,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) ret = sdw_read_no_pm(slave, SDW_DP0_INT); if (ret < 0) { dev_err(&slave->dev, - "SDW_DP0_INT read failed:%d\n", ret); + "SDW_DP0_INT recheck read failed:%d\n", ret); goto io_err; } sdca_cascade = ret & SDW_DP0_SDCA_CASCADE; -- cgit v1.2.3 From 1429cc2655255fb593df4fa85cfb89d3a977e058 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 17:11:17 +0800 Subject: soundwire: bus: remove useless initialization Cppcheck complains about a possible null pointer dereference, but it's more like there is an unnecessary initialization before walking through a list. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Reviewed-by: Rander Wang Reviewed-by: Kai Vehmanen Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210302091122.13952-7-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index a38b017f7a54..1a9e307e6a4c 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -593,7 +593,7 @@ EXPORT_SYMBOL(sdw_write); /* called with bus_lock held */ static struct sdw_slave *sdw_get_slave(struct sdw_bus *bus, int i) { - struct sdw_slave *slave = NULL; + struct sdw_slave *slave; list_for_each_entry(slave, &bus->slaves, node) { if (slave->dev_num == i) -- cgit v1.2.3 From 6ae435bd8c57519ea956d9efafbfdb4546472a9f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 17:11:18 +0800 Subject: soundwire: generic_bandwidth_allocation: remove useless init Cppcheck complains about two possible null pointer dereferences, but it's more like there are unnecessary initializations before walking through a list. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Reviewed-by: Rander Wang Reviewed-by: Kai Vehmanen Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210302091122.13952-8-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/generic_bandwidth_allocation.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index a9abb9722fde..805f5b6ebe86 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -143,7 +143,7 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt, static void _sdw_compute_port_params(struct sdw_bus *bus, struct sdw_group_params *params, int count) { - struct sdw_master_runtime *m_rt = NULL; + struct sdw_master_runtime *m_rt; int hstop = bus->params.col - 1; int block_offset, port_bo, i; @@ -169,7 +169,7 @@ static int sdw_compute_group_params(struct sdw_bus *bus, struct sdw_group_params *params, int *rates, int count) { - struct sdw_master_runtime *m_rt = NULL; + struct sdw_master_runtime *m_rt; int sel_col = bus->params.col; unsigned int rate, bps, ch; int i, column_needed = 0; -- cgit v1.2.3 From 3f9c59ef8f7682d2a0572053034648b16d72df7f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 17:11:19 +0800 Subject: soundwire: intel: remove useless readl Cppcheck complains: drivers/soundwire/intel.c:564:15: style: Variable 'link_control' is assigned a value that is never used. [unreadVariable] link_control = intel_readl(shim, SDW_SHIM_LCTL); This looks like a leftover from a previous version, remove. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Reviewed-by: Rander Wang Reviewed-by: Kai Vehmanen Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210302091122.13952-9-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index e2e95115832a..fd95f94630b1 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -561,8 +561,6 @@ static int intel_link_power_down(struct sdw_intel *sdw) ret = intel_clear_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask); } - link_control = intel_readl(shim, SDW_SHIM_LCTL); - mutex_unlock(sdw->link_res->shim_lock); if (ret < 0) { -- cgit v1.2.3 From a5943e4fb14e36df980f1814e2bd5ed3e4de4e87 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 17:11:20 +0800 Subject: soundwire: qcom: check of_property_read status Cppcheck complains: drivers/soundwire/qcom.c:773:6: style: Variable 'ret' is assigned a value that is never used. [unreadVariable] ret = of_property_read_u8_array(np, "qcom,ports-block-pack-mode", ^ The return value is checked for all other cases, not sure why it was missed here. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Reviewed-by: Rander Wang Reviewed-by: Kai Vehmanen Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210302091122.13952-10-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/qcom.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 9cce09cba068..277f711e374d 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -772,6 +772,9 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) ret = of_property_read_u8_array(np, "qcom,ports-block-pack-mode", bp_mode, nports); + if (ret) + return ret; + for (i = 0; i < nports; i++) { ctrl->pconfig[i].si = si[i]; ctrl->pconfig[i].off1 = off1[i]; -- cgit v1.2.3 From 5920a29d1db50c9b8bae8514999fe6c69665a7d2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 17:11:21 +0800 Subject: soundwire: stream: remove useless initialization Cppcheck complains about possible null pointer dereferences, but it's more like there are unnecessary initializations before walking through a list. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Reviewed-by: Rander Wang Reviewed-by: Kai Vehmanen Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210302091122.13952-11-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/stream.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 4915676c4ac2..6a682179cd05 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -261,7 +261,7 @@ static int sdw_program_master_port_params(struct sdw_bus *bus, */ static int sdw_program_port_params(struct sdw_master_runtime *m_rt) { - struct sdw_slave_runtime *s_rt = NULL; + struct sdw_slave_runtime *s_rt; struct sdw_bus *bus = m_rt->bus; struct sdw_port_runtime *p_rt; int ret = 0; @@ -1470,7 +1470,7 @@ static void sdw_acquire_bus_lock(struct sdw_stream_runtime *stream) */ static void sdw_release_bus_lock(struct sdw_stream_runtime *stream) { - struct sdw_master_runtime *m_rt = NULL; + struct sdw_master_runtime *m_rt; struct sdw_bus *bus = NULL; /* Iterate for all Master(s) in Master list */ -- cgit v1.2.3 From 53e0a30438c49874082bc9906d41606f7dbb256a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 17:11:22 +0800 Subject: soundwire: stream: remove useless bus initializations There is no need to assign a pointer to NULL if it's only used in a loop and assigned within that loop. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Reviewed-by: Rander Wang Reviewed-by: Kai Vehmanen Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210302091122.13952-12-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/stream.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 6a682179cd05..9c064b672745 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -1449,7 +1449,7 @@ struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave, static void sdw_acquire_bus_lock(struct sdw_stream_runtime *stream) { struct sdw_master_runtime *m_rt; - struct sdw_bus *bus = NULL; + struct sdw_bus *bus; /* Iterate for all Master(s) in Master list */ list_for_each_entry(m_rt, &stream->master_list, stream_node) { @@ -1471,7 +1471,7 @@ static void sdw_acquire_bus_lock(struct sdw_stream_runtime *stream) static void sdw_release_bus_lock(struct sdw_stream_runtime *stream) { struct sdw_master_runtime *m_rt; - struct sdw_bus *bus = NULL; + struct sdw_bus *bus; /* Iterate for all Master(s) in Master list */ list_for_each_entry_reverse(m_rt, &stream->master_list, stream_node) { -- cgit v1.2.3 From b76f3fba016ce5f73cd3dbcfdf87e2ab48ec90d9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 1 Mar 2021 11:47:14 -0600 Subject: soundwire: cadence_master: fix kernel-doc v5.12-rc1 flags new warnings with make W=1, fix missing or broken function descriptors. drivers/soundwire/cadence_master.c:914: warning: expecting prototype for To update slave status in a work since we will need to handle(). Prototype was for cdns_update_slave_status_work() instead drivers/soundwire/cadence_master.c:976: warning: expecting prototype for sdw_cdns_enable_slave_interrupt(). Prototype was for cdns_enable_slave_interrupts() instead Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210301174714.117172-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/cadence_master.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 1b50cf7abe66..cc5b81121b2c 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -905,7 +905,7 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id) EXPORT_SYMBOL(sdw_cdns_irq); /** - * To update slave status in a work since we will need to handle + * cdns_update_slave_status_work - update slave status in a work since we will need to handle * other interrupts eg. CDNS_MCP_INT_RX_WL during the update slave * process. * @work: cdns worker thread @@ -968,7 +968,7 @@ int sdw_cdns_exit_reset(struct sdw_cdns *cdns) EXPORT_SYMBOL(sdw_cdns_exit_reset); /** - * sdw_cdns_enable_slave_interrupt() - Enable SDW slave interrupts + * cdns_enable_slave_interrupts() - Enable SDW slave interrupts * @cdns: Cadence instance * @state: boolean for true/false */ -- cgit v1.2.3 From f03690f4f6992225d05dbd1171212e5be5a370dd Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 9 Mar 2021 10:48:16 +0000 Subject: soundwire: bus: Fix device found flag correctly found flag is used to indicate SoundWire devices that are both enumerated on the bus and available in the device list. However this flag is not reset correctly after one iteration, This could miss some of the devices that are enumerated on the bus but not in device list. So reset this correctly to fix this issue! Fixes: d52d7a1be02c ("soundwire: Add Slave status handling helpers") Signed-off-by: Srinivas Kandagatla Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210309104816.20350-1-srinivas.kandagatla@linaro.org Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 1a9e307e6a4c..9bd83c91a873 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -705,7 +705,7 @@ static int sdw_program_device_num(struct sdw_bus *bus) struct sdw_slave *slave, *_s; struct sdw_slave_id id; struct sdw_msg msg; - bool found = false; + bool found; int count = 0, ret; u64 addr; @@ -737,6 +737,7 @@ static int sdw_program_device_num(struct sdw_bus *bus) sdw_extract_slave_id(bus, addr, &id); + found = false; /* Now compare with entries */ list_for_each_entry_safe(slave, _s, &bus->slaves, node) { if (sdw_compare_devid(slave, id) == 0) { -- cgit v1.2.3 From 886ce97a36a05e7a9c9d5d894e72d31f50146f5d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 23 Mar 2021 13:07:00 +0800 Subject: soundwire: add definition for DPn BlockPackingMode For some reason we don't have an enum for this concept. Add definitions following Table 102 of the SoundWire 1.2 specification. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210323050701.23760-2-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- include/linux/soundwire/sdw.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index eaa1486bdca9..350436db6ddb 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -125,6 +125,12 @@ enum sdw_dpn_grouping { SDW_BLK_GRP_CNT_4 = 3, }; +/* block packing mode enum */ +enum sdw_dpn_pkg_mode { + SDW_BLK_PKG_PER_PORT = 0, + SDW_BLK_PKG_PER_CHANNEL = 1 +}; + /** * enum sdw_stream_type: data stream type * -- cgit v1.2.3 From 8f29bb83586ea993e98b258e1fdb657367dd3c25 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 23 Mar 2021 13:07:01 +0800 Subject: soundwire: generic_allocation: fix confusion between group and packing The existing code makes no sense, we multiply a channel number by zero (SDW_BLK_GRP_CNT_1), and the result is used to configure the block packing mode. Sampling grouping and channel packing are two separate concepts in SoundWire. In addition, the bandwidth allocation allocates a vertical slice for each stream, which makes the use of the PER_CHANNEL packing mode irrelevant. Let's use the proper definition for block packing mode (PER_PORT). This change has no functional impact though since the net result is the same configuration of the DPN_BlockCtrl3 register, when implemented. Reported-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210323050701.23760-3-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/generic_bandwidth_allocation.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index 805f5b6ebe86..84d129587084 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -62,7 +62,7 @@ static void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt, sample_int, port_bo, port_bo >> 8, t_data->hstart, t_data->hstop, - (SDW_BLK_GRP_CNT_1 * ch), 0x0); + SDW_BLK_PKG_PER_PORT, 0x0); sdw_fill_port_params(&p_rt->port_params, p_rt->num, bps, @@ -95,7 +95,7 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt, struct sdw_bus *bus = m_rt->bus; struct sdw_bus_params *b_params = &bus->params; int sample_int, hstart = 0; - unsigned int rate, bps, ch, no_ch; + unsigned int rate, bps, ch; rate = m_rt->stream->params.rate; bps = m_rt->stream->params.bps; @@ -110,12 +110,11 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt, t_data.hstart = hstart; list_for_each_entry(p_rt, &m_rt->port_list, port_node) { - no_ch = sdw_ch_mask_to_ch(p_rt->ch_mask); sdw_fill_xport_params(&p_rt->transport_params, p_rt->num, false, SDW_BLK_GRP_CNT_1, sample_int, port_bo, port_bo >> 8, hstart, hstop, - (SDW_BLK_GRP_CNT_1 * no_ch), 0x0); + SDW_BLK_PKG_PER_PORT, 0x0); sdw_fill_port_params(&p_rt->port_params, p_rt->num, bps, -- cgit v1.2.3 From 58ef9356260c291a4321e07ff507f31a1d8212af Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 23 Mar 2021 09:37:07 +0800 Subject: soundwire: cadence: only prepare attached devices on clock stop We sometimes see COMMAND_IGNORED responses during the clock stop sequence. It turns out we already have information if devices are present on a link, so we should only prepare those when they are attached. In addition, even when COMMAND_IGNORED are received, we should still proceed with the clock stop. The device will not be prepared but that's not a problem. The only case where the clock stop will fail is if the Cadence IP reports an error (including a timeout), or if the devices throw a COMMAND_FAILED response. BugLink: https://github.com/thesofproject/linux/issues/2621 Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210323013707.21455-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/cadence_master.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index cc5b81121b2c..192dac10f0c2 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -1450,10 +1450,12 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake) } /* Prepare slaves for clock stop */ - ret = sdw_bus_prep_clk_stop(&cdns->bus); - if (ret < 0) { - dev_err(cdns->dev, "prepare clock stop failed %d", ret); - return ret; + if (slave_present) { + ret = sdw_bus_prep_clk_stop(&cdns->bus); + if (ret < 0 && ret != -ENODATA) { + dev_err(cdns->dev, "prepare clock stop failed %d\n", ret); + return ret; + } } /* -- cgit v1.2.3 From 173ef5f84b6d57b221215275346cf5b39ca5a425 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sun, 28 Mar 2021 22:46:18 +0530 Subject: MAINTAINERS: icc: add interconnect tree MAINTAINERS entry for ICC is missing the tree details, so add it. Signed-off-by: Vinod Koul Link: https://lore.kernel.org/r/20210328171618.2759956-1-vkoul@kernel.org Signed-off-by: Georgi Djakov --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index d92f85ca831d..647a5df83242 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9283,6 +9283,7 @@ INTERCONNECT API M: Georgi Djakov L: linux-pm@vger.kernel.org S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/djakov/icc.git F: Documentation/devicetree/bindings/interconnect/ F: Documentation/driver-api/interconnect.rst F: drivers/interconnect/ -- cgit v1.2.3 From 377785cc7c5d1dafadb1ae43c6d79ff934620f67 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 30 Mar 2021 15:47:11 +0100 Subject: dt-bindings: soundwire: qcom: clarify data port bus parameters Some of the parameters for data ports are not applicable or not implemented in IP. So mark them as invalid/not applicable in DT so that controller is aware of this. Add comment to these bindings to provide more clarity on the values! Signed-off-by: Srinivas Kandagatla Acked-by: Rob Herring Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210330144719.13284-2-srinivas.kandagatla@linaro.org Signed-off-by: Vinod Koul --- .../devicetree/bindings/soundwire/qcom,sdw.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Documentation/devicetree/bindings/soundwire/qcom,sdw.txt b/Documentation/devicetree/bindings/soundwire/qcom,sdw.txt index b104be131235..b93a2b3e029d 100644 --- a/Documentation/devicetree/bindings/soundwire/qcom,sdw.txt +++ b/Documentation/devicetree/bindings/soundwire/qcom,sdw.txt @@ -54,6 +54,8 @@ board specific bus parameters. Value type: Definition: should specify payload transport window offset1 of each data port. Out ports followed by In ports. + Value of 0xFF indicates that this option is not implemented + or applicable for the respective data port. More info in MIPI Alliance SoundWire 1.0 Specifications. - qcom,ports-offset2: @@ -61,6 +63,8 @@ board specific bus parameters. Value type: Definition: should specify payload transport window offset2 of each data port. Out ports followed by In ports. + Value of 0xFF indicates that this option is not implemented + or applicable for the respective data port. More info in MIPI Alliance SoundWire 1.0 Specifications. - qcom,ports-sinterval-low: @@ -69,12 +73,16 @@ board specific bus parameters. Definition: should be sample interval low of each data port. Out ports followed by In ports. Used for Sample Interval calculation. + Value of 0xFF indicates that this option is not implemented + or applicable for the respective data port. More info in MIPI Alliance SoundWire 1.0 Specifications. - qcom,ports-word-length: Usage: optional Value type: Definition: should be size of payload channel sample. + Value of 0xFF indicates that this option is not implemented + or applicable for the respective data port. More info in MIPI Alliance SoundWire 1.0 Specifications. - qcom,ports-block-pack-mode: @@ -84,6 +92,8 @@ board specific bus parameters. 0 to indicate Blocks are per Channel 1 to indicate Blocks are per Port. Out ports followed by In ports. + Value of 0xFF indicates that this option is not implemented + or applicable for the respective data port. More info in MIPI Alliance SoundWire 1.0 Specifications. - qcom,ports-block-group-count: @@ -92,6 +102,8 @@ board specific bus parameters. Definition: should be in range 1 to 4 to indicate how many sample intervals are combined into a payload. Out ports followed by In ports. + Value of 0xFF indicates that this option is not implemented + or applicable for the respective data port. More info in MIPI Alliance SoundWire 1.0 Specifications. - qcom,ports-lane-control: @@ -100,6 +112,8 @@ board specific bus parameters. Definition: should be in range 0 to 7 to identify which data lane the data port uses. Out ports followed by In ports. + Value of 0xFF indicates that this option is not implemented + or applicable for the respective data port. More info in MIPI Alliance SoundWire 1.0 Specifications. - qcom,ports-hstart: @@ -109,6 +123,8 @@ board specific bus parameters. SoundWire Frame, i.e. left edge of the Transport sub-frame for each port. Values between 0 and 15 are valid. Out ports followed by In ports. + Value of 0xFF indicates that this option is not implemented + or applicable for the respective data port. More info in MIPI Alliance SoundWire 1.0 Specifications. - qcom,ports-hstop: @@ -118,6 +134,8 @@ board specific bus parameters. SoundWire Frame, i.e. the right edge of the Transport sub-frame for each port. Values between 0 and 15 are valid. Out ports followed by In ports. + Value of 0xFF indicates that this option is not implemented + or applicable for the respective data port. More info in MIPI Alliance SoundWire 1.0 Specifications. - qcom,dports-type: @@ -128,6 +146,8 @@ board specific bus parameters. 1 for simple ports 2 for full port Out ports followed by In ports. + Value of 0xFF indicates that this option is not implemented + or applicable for the respective data port. More info in MIPI Alliance SoundWire 1.0 Specifications. Note: -- cgit v1.2.3 From 128eaf937adb87afc8a14124d3eba1f7a179af0b Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 30 Mar 2021 15:47:12 +0100 Subject: soundwire: qcom: add support to missing transport params Some of the transport parameters derived from device tree are not fully parsed by the driver. This patch adds support to parse those missing parameters. Signed-off-by: Srinivas Kandagatla Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210330144719.13284-3-srinivas.kandagatla@linaro.org Signed-off-by: Vinod Koul --- drivers/soundwire/qcom.c | 106 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 94 insertions(+), 12 deletions(-) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 277f711e374d..fdcb8ffb4284 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -54,7 +54,13 @@ #define SWRM_MCP_SLV_STATUS 0x1090 #define SWRM_MCP_SLV_STATUS_MASK GENMASK(1, 0) #define SWRM_DP_PORT_CTRL_BANK(n, m) (0x1124 + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DP_PORT_CTRL_2_BANK(n, m) (0x1128 + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DP_BLOCK_CTRL_1(n) (0x112C + 0x100 * (n - 1)) +#define SWRM_DP_BLOCK_CTRL2_BANK(n, m) (0x1130 + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DP_PORT_HCTRL_BANK(n, m) (0x1134 + 0x100 * (n - 1) + 0x40 * m) #define SWRM_DP_BLOCK_CTRL3_BANK(n, m) (0x1138 + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DIN_DPn_PCM_PORT_CTRL(n) (0x1054 + 0x100 * (n - 1)) + #define SWRM_DP_PORT_CTRL_EN_CHAN_SHFT 0x18 #define SWRM_DP_PORT_CTRL_OFFSET2_SHFT 0x10 #define SWRM_DP_PORT_CTRL_OFFSET1_SHFT 0x08 @@ -73,12 +79,20 @@ #define QCOM_SDW_MAX_PORTS 14 #define DEFAULT_CLK_FREQ 9600000 #define SWRM_MAX_DAIS 0xF +#define SWR_INVALID_PARAM 0xFF +#define SWR_HSTOP_MAX_VAL 0xF +#define SWR_HSTART_MIN_VAL 0x0 struct qcom_swrm_port_config { u8 si; u8 off1; u8 off2; u8 bp_mode; + u8 hstart; + u8 hstop; + u8 word_length; + u8 blk_group_count; + u8 lane_control; }; struct qcom_swrm_ctrl { @@ -396,8 +410,11 @@ static int qcom_swrm_port_params(struct sdw_bus *bus, struct sdw_port_params *p_params, unsigned int bank) { - /* TBD */ - return 0; + struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); + + return ctrl->reg_write(ctrl, SWRM_DP_BLOCK_CTRL_1(p_params->num), + p_params->bps - 1); + } static int qcom_swrm_transport_params(struct sdw_bus *bus, @@ -405,20 +422,45 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus, enum sdw_reg_bank bank) { struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); + struct qcom_swrm_port_config *pcfg; u32 value; int reg = SWRM_DP_PORT_CTRL_BANK((params->port_num), bank); int ret; - value = params->offset1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT; - value |= params->offset2 << SWRM_DP_PORT_CTRL_OFFSET2_SHFT; - value |= params->sample_interval - 1; + pcfg = &ctrl->pconfig[params->port_num - 1]; + + value = pcfg->off1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT; + value |= pcfg->off2 << SWRM_DP_PORT_CTRL_OFFSET2_SHFT; + value |= pcfg->si; ret = ctrl->reg_write(ctrl, reg, value); - if (!ret && params->blk_pkg_mode) { - reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank); + if (pcfg->lane_control != SWR_INVALID_PARAM) { + reg = SWRM_DP_PORT_CTRL_2_BANK(params->port_num, bank); + value = pcfg->lane_control; + ret = ctrl->reg_write(ctrl, reg, value); + } - ret = ctrl->reg_write(ctrl, reg, 1); + if (pcfg->blk_group_count != SWR_INVALID_PARAM) { + reg = SWRM_DP_BLOCK_CTRL2_BANK(params->port_num, bank); + value = pcfg->blk_group_count; + ret = ctrl->reg_write(ctrl, reg, value); + } + + if (pcfg->hstart != SWR_INVALID_PARAM + && pcfg->hstop != SWR_INVALID_PARAM) { + reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank); + value = (pcfg->hstop << 4) | pcfg->hstart; + ret = ctrl->reg_write(ctrl, reg, value); + } else { + reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank); + value = (SWR_HSTOP_MAX_VAL << 4) | SWR_HSTART_MIN_VAL; + ret = ctrl->reg_write(ctrl, reg, value); + } + + if (pcfg->bp_mode != SWR_INVALID_PARAM) { + reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank); + ret = ctrl->reg_write(ctrl, reg, pcfg->bp_mode); } return ret; @@ -466,10 +508,13 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus) list_for_each_entry(p_rt, &m_rt->port_list, port_node) { pcfg = &ctrl->pconfig[p_rt->num - 1]; p_rt->transport_params.port_num = p_rt->num; - p_rt->transport_params.sample_interval = pcfg->si + 1; - p_rt->transport_params.offset1 = pcfg->off1; - p_rt->transport_params.offset2 = pcfg->off2; - p_rt->transport_params.blk_pkg_mode = pcfg->bp_mode; + if (pcfg->word_length != SWR_INVALID_PARAM) { + sdw_fill_port_params(&p_rt->port_params, + p_rt->num, pcfg->word_length + 1, + SDW_PORT_FLOW_MODE_ISOCH, + SDW_PORT_DATA_MODE_NORMAL); + } + } list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { @@ -481,6 +526,18 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus) p_rt->transport_params.offset1 = pcfg->off1; p_rt->transport_params.offset2 = pcfg->off2; p_rt->transport_params.blk_pkg_mode = pcfg->bp_mode; + p_rt->transport_params.blk_grp_ctrl = pcfg->blk_group_count; + + p_rt->transport_params.hstart = pcfg->hstart; + p_rt->transport_params.hstop = pcfg->hstop; + p_rt->transport_params.lane_ctrl = pcfg->lane_control; + if (pcfg->word_length != SWR_INVALID_PARAM) { + sdw_fill_port_params(&p_rt->port_params, + p_rt->num, + pcfg->word_length + 1, + SDW_PORT_FLOW_MODE_ISOCH, + SDW_PORT_DATA_MODE_NORMAL); + } i++; } } @@ -728,6 +785,11 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) u8 off2[QCOM_SDW_MAX_PORTS]; u8 si[QCOM_SDW_MAX_PORTS]; u8 bp_mode[QCOM_SDW_MAX_PORTS] = { 0, }; + u8 hstart[QCOM_SDW_MAX_PORTS]; + u8 hstop[QCOM_SDW_MAX_PORTS]; + u8 word_length[QCOM_SDW_MAX_PORTS]; + u8 blk_group_count[QCOM_SDW_MAX_PORTS]; + u8 lane_control[QCOM_SDW_MAX_PORTS]; int i, ret, nports, val; ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val); @@ -775,11 +837,31 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) if (ret) return ret; + memset(hstart, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); + of_property_read_u8_array(np, "qcom,ports-hstart", hstart, nports); + + memset(hstop, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); + of_property_read_u8_array(np, "qcom,ports-hstop", hstop, nports); + + memset(word_length, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); + of_property_read_u8_array(np, "qcom,ports-word-length", word_length, nports); + + memset(blk_group_count, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); + of_property_read_u8_array(np, "qcom,ports-block-group-count", blk_group_count, nports); + + memset(lane_control, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); + of_property_read_u8_array(np, "qcom,ports-lane-control", lane_control, nports); + for (i = 0; i < nports; i++) { ctrl->pconfig[i].si = si[i]; ctrl->pconfig[i].off1 = off1[i]; ctrl->pconfig[i].off2 = off2[i]; ctrl->pconfig[i].bp_mode = bp_mode[i]; + ctrl->pconfig[i].hstart = hstart[i]; + ctrl->pconfig[i].hstop = hstop[i]; + ctrl->pconfig[i].word_length = word_length[i]; + ctrl->pconfig[i].blk_group_count = blk_group_count[i]; + ctrl->pconfig[i].lane_control = lane_control[i]; } return 0; -- cgit v1.2.3 From 542d3491cdd7975161efe964691f2a1b3bba950f Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 30 Mar 2021 15:47:13 +0100 Subject: soundwire: qcom: set continue execution flag for ignored commands version 1.5.1 and higher IPs of this controller required to set continue execution on ignored command flag. This patch sets this flag. Signed-off-by: Srinivas Kandagatla Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210330144719.13284-4-srinivas.kandagatla@linaro.org Signed-off-by: Vinod Koul --- drivers/soundwire/qcom.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index fdcb8ffb4284..edc77d18c245 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -40,6 +40,7 @@ #define SWRM_CMD_FIFO_CMD 0x308 #define SWRM_CMD_FIFO_STATUS 0x30C #define SWRM_CMD_FIFO_CFG_ADDR 0x314 +#define SWRM_CONTINUE_EXEC_ON_CMD_IGNORE BIT(31) #define SWRM_RD_WR_CMD_RETRIES 0x7 #define SWRM_CMD_FIFO_RD_FIFO_ADDR 0x318 #define SWRM_ENUMERATOR_CFG_ADDR 0x500 @@ -343,7 +344,15 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) ctrl->reg_write(ctrl, SWRM_MCP_CFG_ADDR, val); /* Configure number of retries of a read/write cmd */ - ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR, SWRM_RD_WR_CMD_RETRIES); + if (ctrl->version > 0x01050001) { + /* Only for versions >= 1.5.1 */ + ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR, + SWRM_RD_WR_CMD_RETRIES | + SWRM_CONTINUE_EXEC_ON_CMD_IGNORE); + } else { + ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR, + SWRM_RD_WR_CMD_RETRIES); + } /* Set IRQ to PULSE */ ctrl->reg_write(ctrl, SWRM_COMP_CFG_ADDR, -- cgit v1.2.3 From a866a049024c789f6d6c35aefab3ae9837a2fa73 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 30 Mar 2021 15:47:14 +0100 Subject: soundwire: qcom: start the clock during initialization Start the clock during initialization, doing this explicitly will add more clarity when we are adding clock stop feature. Signed-off-by: Srinivas Kandagatla Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210330144719.13284-5-srinivas.kandagatla@linaro.org Signed-off-by: Vinod Koul --- drivers/soundwire/qcom.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index edc77d18c245..0f2167433d2f 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -47,6 +47,8 @@ #define SWRM_MCP_FRAME_CTRL_BANK_ADDR(m) (0x101C + 0x40 * (m)) #define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK GENMASK(2, 0) #define SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK GENMASK(7, 3) +#define SWRM_MCP_BUS_CTRL 0x1044 +#define SWRM_MCP_BUS_CLK_START BIT(1) #define SWRM_MCP_CFG_ADDR 0x1048 #define SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK GENMASK(21, 17) #define SWRM_DEF_CMD_NO_PINGS 0x1f @@ -343,6 +345,7 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) u32p_replace_bits(&val, SWRM_DEF_CMD_NO_PINGS, SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK); ctrl->reg_write(ctrl, SWRM_MCP_CFG_ADDR, val); + ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL, SWRM_MCP_BUS_CLK_START); /* Configure number of retries of a read/write cmd */ if (ctrl->version > 0x01050001) { /* Only for versions >= 1.5.1 */ -- cgit v1.2.3 From ddea6cf7b619ec4b9a630d0073c4fc64d0ac2b9c Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 30 Mar 2021 15:47:15 +0100 Subject: soundwire: qcom: update register read/write routine In the existing code every soundwire register read and register write are kinda blocked. Each of these are using a special command id that generates interrupt after it successfully finishes. This is really overhead, limiting and not really necessary unless we are doing something special. We can simply read/write the fifo that should also give exactly what we need! This will also allow to read/write registers in interrupt context, which was not possible with the special command approach. With previous approach number of interrupts generated after enumeration are around 130: $ cat /proc/interrupts | grep soundwire 21: 130 0 0 0 0 0 0 0 GICv3 234 Edge soundwire after this patch they are just 3 interrupts $ cat /proc/interrupts | grep soundwire 21: 3 0 0 0 0 0 0 0 GICv3 234 Edge soundwire This has significantly not only reduced interrupting CPU during enumeration but also during streaming! Signed-off-by: Srinivas Kandagatla Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210330144719.13284-6-srinivas.kandagatla@linaro.org Signed-off-by: Vinod Koul --- drivers/soundwire/qcom.c | 179 ++++++++++++++++++++++++++--------------------- 1 file changed, 100 insertions(+), 79 deletions(-) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 0f2167433d2f..faa4c84dcf61 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -38,11 +38,13 @@ #define SWRM_CMD_FIFO_WR_CMD 0x300 #define SWRM_CMD_FIFO_RD_CMD 0x304 #define SWRM_CMD_FIFO_CMD 0x308 +#define SWRM_CMD_FIFO_FLUSH 0x1 #define SWRM_CMD_FIFO_STATUS 0x30C #define SWRM_CMD_FIFO_CFG_ADDR 0x314 #define SWRM_CONTINUE_EXEC_ON_CMD_IGNORE BIT(31) #define SWRM_RD_WR_CMD_RETRIES 0x7 #define SWRM_CMD_FIFO_RD_FIFO_ADDR 0x318 +#define SWRM_RD_FIFO_CMD_ID_MASK GENMASK(11, 8) #define SWRM_ENUMERATOR_CFG_ADDR 0x500 #define SWRM_MCP_FRAME_CTRL_BANK_ADDR(m) (0x101C + 0x40 * (m)) #define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK GENMASK(2, 0) @@ -78,13 +80,16 @@ #define SWRM_SPECIAL_CMD_ID 0xF #define MAX_FREQ_NUM 1 #define TIMEOUT_MS (2 * HZ) -#define QCOM_SWRM_MAX_RD_LEN 0xf +#define QCOM_SWRM_MAX_RD_LEN 0x1 #define QCOM_SDW_MAX_PORTS 14 #define DEFAULT_CLK_FREQ 9600000 #define SWRM_MAX_DAIS 0xF #define SWR_INVALID_PARAM 0xFF #define SWR_HSTOP_MAX_VAL 0xF #define SWR_HSTART_MIN_VAL 0x0 +#define SWR_BROADCAST_CMD_ID 0x0F +#define SWR_MAX_CMD_ID 14 +#define MAX_FIFO_RD_RETRY 3 struct qcom_swrm_port_config { u8 si; @@ -103,10 +108,8 @@ struct qcom_swrm_ctrl { struct device *dev; struct regmap *regmap; void __iomem *mmio; - struct completion *comp; + struct completion broadcast; struct work_struct slave_work; - /* read/write lock */ - spinlock_t comp_lock; /* Port alloc/free lock */ struct mutex port_lock; struct clk *hclk; @@ -120,6 +123,8 @@ struct qcom_swrm_ctrl { int rows_index; unsigned long dout_port_mask; unsigned long din_port_mask; + u8 rcmd_id; + u8 wcmd_id; struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS]; struct sdw_stream_runtime *sruntime[SWRM_MAX_DAIS]; enum sdw_slave_status status[SDW_MAX_DEVICES]; @@ -198,77 +203,106 @@ static int qcom_swrm_cpu_reg_write(struct qcom_swrm_ctrl *ctrl, int reg, return SDW_CMD_OK; } -static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *ctrl, u8 cmd_data, - u8 dev_addr, u16 reg_addr) +static u32 swrm_get_packed_reg_val(u8 *cmd_id, u8 cmd_data, + u8 dev_addr, u16 reg_addr) { - DECLARE_COMPLETION_ONSTACK(comp); - unsigned long flags; u32 val; - int ret; - - spin_lock_irqsave(&ctrl->comp_lock, flags); - ctrl->comp = ∁ - spin_unlock_irqrestore(&ctrl->comp_lock, flags); - val = SWRM_REG_VAL_PACK(cmd_data, dev_addr, - SWRM_SPECIAL_CMD_ID, reg_addr); - ret = ctrl->reg_write(ctrl, SWRM_CMD_FIFO_WR_CMD, val); - if (ret) - goto err; - - ret = wait_for_completion_timeout(ctrl->comp, - msecs_to_jiffies(TIMEOUT_MS)); + u8 id = *cmd_id; - if (!ret) - ret = SDW_CMD_IGNORED; - else - ret = SDW_CMD_OK; -err: - spin_lock_irqsave(&ctrl->comp_lock, flags); - ctrl->comp = NULL; - spin_unlock_irqrestore(&ctrl->comp_lock, flags); + if (id != SWR_BROADCAST_CMD_ID) { + if (id < SWR_MAX_CMD_ID) + id += 1; + else + id = 0; + *cmd_id = id; + } + val = SWRM_REG_VAL_PACK(cmd_data, dev_addr, id, reg_addr); - return ret; + return val; } -static int qcom_swrm_cmd_fifo_rd_cmd(struct qcom_swrm_ctrl *ctrl, - u8 dev_addr, u16 reg_addr, - u32 len, u8 *rval) + +static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *swrm, u8 cmd_data, + u8 dev_addr, u16 reg_addr) { - int i, ret; - u32 val; - DECLARE_COMPLETION_ONSTACK(comp); - unsigned long flags; - spin_lock_irqsave(&ctrl->comp_lock, flags); - ctrl->comp = ∁ - spin_unlock_irqrestore(&ctrl->comp_lock, flags); + u32 val; + int ret = 0; + u8 cmd_id = 0x0; - val = SWRM_REG_VAL_PACK(len, dev_addr, SWRM_SPECIAL_CMD_ID, reg_addr); - ret = ctrl->reg_write(ctrl, SWRM_CMD_FIFO_RD_CMD, val); - if (ret) - goto err; + if (dev_addr == SDW_BROADCAST_DEV_NUM) { + cmd_id = SWR_BROADCAST_CMD_ID; + val = swrm_get_packed_reg_val(&cmd_id, cmd_data, + dev_addr, reg_addr); + } else { + val = swrm_get_packed_reg_val(&swrm->wcmd_id, cmd_data, + dev_addr, reg_addr); + } - ret = wait_for_completion_timeout(ctrl->comp, - msecs_to_jiffies(TIMEOUT_MS)); + /* Its assumed that write is okay as we do not get any status back */ + swrm->reg_write(swrm, SWRM_CMD_FIFO_WR_CMD, val); + + /* version 1.3 or less */ + if (swrm->version <= 0x01030000) + usleep_range(150, 155); + + if (cmd_id == SWR_BROADCAST_CMD_ID) { + /* + * sleep for 10ms for MSM soundwire variant to allow broadcast + * command to complete. + */ + ret = wait_for_completion_timeout(&swrm->broadcast, + msecs_to_jiffies(TIMEOUT_MS)); + if (!ret) + ret = SDW_CMD_IGNORED; + else + ret = SDW_CMD_OK; - if (!ret) { - ret = SDW_CMD_IGNORED; - goto err; } else { ret = SDW_CMD_OK; } + return ret; +} - for (i = 0; i < len; i++) { - ctrl->reg_read(ctrl, SWRM_CMD_FIFO_RD_FIFO_ADDR, &val); - rval[i] = val & 0xFF; - } +static int qcom_swrm_cmd_fifo_rd_cmd(struct qcom_swrm_ctrl *swrm, + u8 dev_addr, u16 reg_addr, + u32 len, u8 *rval) +{ + u32 cmd_data, cmd_id, val, retry_attempt = 0; + + val = swrm_get_packed_reg_val(&swrm->rcmd_id, len, dev_addr, reg_addr); + + /* wait for FIFO RD to complete to avoid overflow */ + usleep_range(100, 105); + swrm->reg_write(swrm, SWRM_CMD_FIFO_RD_CMD, val); + /* wait for FIFO RD CMD complete to avoid overflow */ + usleep_range(250, 255); + + do { + swrm->reg_read(swrm, SWRM_CMD_FIFO_RD_FIFO_ADDR, &cmd_data); + rval[0] = cmd_data & 0xFF; + cmd_id = FIELD_GET(SWRM_RD_FIFO_CMD_ID_MASK, cmd_data); + + if (cmd_id != swrm->rcmd_id) { + if (retry_attempt < (MAX_FIFO_RD_RETRY - 1)) { + /* wait 500 us before retry on fifo read failure */ + usleep_range(500, 505); + swrm->reg_write(swrm, SWRM_CMD_FIFO_CMD, + SWRM_CMD_FIFO_FLUSH); + swrm->reg_write(swrm, SWRM_CMD_FIFO_RD_CMD, val); + } + retry_attempt++; + } else { + return SDW_CMD_OK; + } -err: - spin_lock_irqsave(&ctrl->comp_lock, flags); - ctrl->comp = NULL; - spin_unlock_irqrestore(&ctrl->comp_lock, flags); + } while (retry_attempt < MAX_FIFO_RD_RETRY); - return ret; + dev_err(swrm->dev, "failed to read fifo: reg: 0x%x, rcmd_id: 0x%x,\ + dev_num: 0x%x, cmd_data: 0x%x\n", + reg_addr, swrm->rcmd_id, dev_addr, cmd_data); + + return SDW_CMD_IGNORED; } static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl) @@ -291,7 +325,6 @@ static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id) { struct qcom_swrm_ctrl *ctrl = dev_id; u32 sts, value; - unsigned long flags; ctrl->reg_read(ctrl, SWRM_INTERRUPT_STATUS, &sts); @@ -304,8 +337,10 @@ static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id) } if ((sts & SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED) || - sts & SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS) - schedule_work(&ctrl->slave_work); + sts & SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS) { + qcom_swrm_get_device_status(ctrl); + sdw_handle_slave_status(&ctrl->bus, ctrl->status); + } /** * clear the interrupt before complete() is called, as complete can @@ -314,15 +349,12 @@ static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id) */ ctrl->reg_write(ctrl, SWRM_INTERRUPT_CLEAR, sts); - if (sts & SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED) { - spin_lock_irqsave(&ctrl->comp_lock, flags); - if (ctrl->comp) - complete(ctrl->comp); - spin_unlock_irqrestore(&ctrl->comp_lock, flags); - } + if (sts & SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED) + complete(&ctrl->broadcast); return IRQ_HANDLED; } + static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) { u32 val; @@ -562,16 +594,6 @@ static u32 qcom_swrm_freq_tbl[MAX_FREQ_NUM] = { DEFAULT_CLK_FREQ, }; -static void qcom_swrm_slave_wq(struct work_struct *work) -{ - struct qcom_swrm_ctrl *ctrl = - container_of(work, struct qcom_swrm_ctrl, slave_work); - - qcom_swrm_get_device_status(ctrl); - sdw_handle_slave_status(&ctrl->bus, ctrl->status); -} - - static void qcom_swrm_stream_free_ports(struct qcom_swrm_ctrl *ctrl, struct sdw_stream_runtime *stream) { @@ -930,9 +952,8 @@ static int qcom_swrm_probe(struct platform_device *pdev) ctrl->dev = dev; dev_set_drvdata(&pdev->dev, ctrl); - spin_lock_init(&ctrl->comp_lock); mutex_init(&ctrl->port_lock); - INIT_WORK(&ctrl->slave_work, qcom_swrm_slave_wq); + init_completion(&ctrl->broadcast); ctrl->bus.ops = &qcom_swrm_ops; ctrl->bus.port_ops = &qcom_swrm_port_ops; -- cgit v1.2.3 From c7d49c76d1d5f5a41f637c18ce3b756351c7fdf9 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 30 Mar 2021 15:47:16 +0100 Subject: soundwire: qcom: add support to new interrupts Add support to new interrupts which includes reporting some of the error interrupts and adding support to SLAVE pending interrupt! This patch also changes the interrupt handler behaviour on handling any pending interrupts by checking it before returning out of irq handler. Signed-off-by: Srinivas Kandagatla Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210330144719.13284-7-srinivas.kandagatla@linaro.org Signed-off-by: Vinod Koul --- drivers/soundwire/qcom.c | 161 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 135 insertions(+), 26 deletions(-) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index faa4c84dcf61..1ad07784db4b 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -28,10 +28,21 @@ #define SWRM_COMP_PARAMS_DIN_PORTS_MASK GENMASK(9, 5) #define SWRM_INTERRUPT_STATUS 0x200 #define SWRM_INTERRUPT_STATUS_RMSK GENMASK(16, 0) +#define SWRM_INTERRUPT_STATUS_SLAVE_PEND_IRQ BIT(0) #define SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED BIT(1) #define SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS BIT(2) +#define SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET BIT(3) +#define SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW BIT(4) +#define SWRM_INTERRUPT_STATUS_RD_FIFO_UNDERFLOW BIT(5) +#define SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW BIT(6) #define SWRM_INTERRUPT_STATUS_CMD_ERROR BIT(7) +#define SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION BIT(8) +#define SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH BIT(9) #define SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED BIT(10) +#define SWRM_INTERRUPT_STATUS_BUS_RESET_FINISHED_V2 BIT(13) +#define SWRM_INTERRUPT_STATUS_CLK_STOP_FINISHED_V2 BIT(14) +#define SWRM_INTERRUPT_STATUS_EXT_CLK_STOP_WAKEUP BIT(16) +#define SWRM_INTERRUPT_MAX 17 #define SWRM_INTERRUPT_MASK_ADDR 0x204 #define SWRM_INTERRUPT_CLEAR 0x208 #define SWRM_INTERRUPT_CPU_EN 0x210 @@ -58,6 +69,7 @@ #define SWRM_MCP_STATUS_BANK_NUM_MASK BIT(0) #define SWRM_MCP_SLV_STATUS 0x1090 #define SWRM_MCP_SLV_STATUS_MASK GENMASK(1, 0) +#define SWRM_MCP_SLV_STATUS_SZ 2 #define SWRM_DP_PORT_CTRL_BANK(n, m) (0x1124 + 0x100 * (n - 1) + 0x40 * m) #define SWRM_DP_PORT_CTRL_2_BANK(n, m) (0x1128 + 0x100 * (n - 1) + 0x40 * m) #define SWRM_DP_BLOCK_CTRL_1(n) (0x112C + 0x100 * (n - 1)) @@ -123,6 +135,7 @@ struct qcom_swrm_ctrl { int rows_index; unsigned long dout_port_mask; unsigned long din_port_mask; + u32 intr_mask; u8 rcmd_id; u8 wcmd_id; struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS]; @@ -305,6 +318,25 @@ static int qcom_swrm_cmd_fifo_rd_cmd(struct qcom_swrm_ctrl *swrm, return SDW_CMD_IGNORED; } +static int qcom_swrm_get_alert_slave_dev_num(struct qcom_swrm_ctrl *ctrl) +{ + u32 val, status; + int dev_num; + + ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val); + + for (dev_num = 0; dev_num < SDW_MAX_DEVICES; dev_num++) { + status = (val >> (dev_num * SWRM_MCP_SLV_STATUS_SZ)); + + if ((status & SWRM_MCP_SLV_STATUS_MASK) == SDW_SLAVE_ALERT) { + ctrl->status[dev_num] = status; + return dev_num; + } + } + + return -EINVAL; +} + static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl) { u32 val; @@ -323,36 +355,112 @@ static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl) static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id) { - struct qcom_swrm_ctrl *ctrl = dev_id; - u32 sts, value; + struct qcom_swrm_ctrl *swrm = dev_id; + u32 value, intr_sts, intr_sts_masked; + u32 i; + u8 devnum = 0; + int ret = IRQ_HANDLED; - ctrl->reg_read(ctrl, SWRM_INTERRUPT_STATUS, &sts); + swrm->reg_read(swrm, SWRM_INTERRUPT_STATUS, &intr_sts); + intr_sts_masked = intr_sts & swrm->intr_mask; - if (sts & SWRM_INTERRUPT_STATUS_CMD_ERROR) { - ctrl->reg_read(ctrl, SWRM_CMD_FIFO_STATUS, &value); - dev_err_ratelimited(ctrl->dev, - "CMD error, fifo status 0x%x\n", - value); - ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CMD, 0x1); - } - - if ((sts & SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED) || - sts & SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS) { - qcom_swrm_get_device_status(ctrl); - sdw_handle_slave_status(&ctrl->bus, ctrl->status); - } - - /** - * clear the interrupt before complete() is called, as complete can - * schedule new read/writes which require interrupts, clearing the - * interrupt would avoid missing interrupts in such cases. - */ - ctrl->reg_write(ctrl, SWRM_INTERRUPT_CLEAR, sts); + do { + for (i = 0; i < SWRM_INTERRUPT_MAX; i++) { + value = intr_sts_masked & BIT(i); + if (!value) + continue; + + switch (value) { + case SWRM_INTERRUPT_STATUS_SLAVE_PEND_IRQ: + devnum = qcom_swrm_get_alert_slave_dev_num(swrm); + if (devnum < 0) { + dev_err_ratelimited(swrm->dev, + "no slave alert found.spurious interrupt\n"); + } else { + sdw_handle_slave_status(&swrm->bus, swrm->status); + } - if (sts & SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED) - complete(&ctrl->broadcast); + break; + case SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED: + case SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS: + dev_err_ratelimited(swrm->dev, "%s: SWR new slave attached\n", + __func__); + qcom_swrm_get_device_status(swrm); + sdw_handle_slave_status(&swrm->bus, swrm->status); + break; + case SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET: + dev_err_ratelimited(swrm->dev, + "%s: SWR bus clsh detected\n", + __func__); + swrm->intr_mask &= ~SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET; + swrm->reg_write(swrm, SWRM_INTERRUPT_CPU_EN, swrm->intr_mask); + break; + case SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW: + swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value); + dev_err_ratelimited(swrm->dev, + "%s: SWR read FIFO overflow fifo status 0x%x\n", + __func__, value); + break; + case SWRM_INTERRUPT_STATUS_RD_FIFO_UNDERFLOW: + swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value); + dev_err_ratelimited(swrm->dev, + "%s: SWR read FIFO underflow fifo status 0x%x\n", + __func__, value); + break; + case SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW: + swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value); + dev_err(swrm->dev, + "%s: SWR write FIFO overflow fifo status %x\n", + __func__, value); + swrm->reg_write(swrm, SWRM_CMD_FIFO_CMD, 0x1); + break; + case SWRM_INTERRUPT_STATUS_CMD_ERROR: + swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value); + dev_err_ratelimited(swrm->dev, + "%s: SWR CMD error, fifo status 0x%x, flushing fifo\n", + __func__, value); + swrm->reg_write(swrm, SWRM_CMD_FIFO_CMD, 0x1); + break; + case SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION: + dev_err_ratelimited(swrm->dev, + "%s: SWR Port collision detected\n", + __func__); + swrm->intr_mask &= ~SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION; + swrm->reg_write(swrm, + SWRM_INTERRUPT_CPU_EN, swrm->intr_mask); + break; + case SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH: + dev_err_ratelimited(swrm->dev, + "%s: SWR read enable valid mismatch\n", + __func__); + swrm->intr_mask &= + ~SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH; + swrm->reg_write(swrm, + SWRM_INTERRUPT_CPU_EN, swrm->intr_mask); + break; + case SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED: + complete(&swrm->broadcast); + break; + case SWRM_INTERRUPT_STATUS_BUS_RESET_FINISHED_V2: + break; + case SWRM_INTERRUPT_STATUS_CLK_STOP_FINISHED_V2: + break; + case SWRM_INTERRUPT_STATUS_EXT_CLK_STOP_WAKEUP: + break; + default: + dev_err_ratelimited(swrm->dev, + "%s: SWR unknown interrupt value: %d\n", + __func__, value); + ret = IRQ_NONE; + break; + } + } + swrm->reg_write(swrm, SWRM_INTERRUPT_CLEAR, intr_sts); + swrm->reg_read(swrm, SWRM_INTERRUPT_STATUS, &intr_sts); + intr_sts_masked = intr_sts & swrm->intr_mask; + } while (intr_sts_masked); - return IRQ_HANDLED; + return ret; } static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) @@ -368,6 +476,7 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) /* Disable Auto enumeration */ ctrl->reg_write(ctrl, SWRM_ENUMERATOR_CFG_ADDR, 0); + ctrl->intr_mask = SWRM_INTERRUPT_STATUS_RMSK; /* Mask soundwire interrupts */ ctrl->reg_write(ctrl, SWRM_INTERRUPT_MASK_ADDR, SWRM_INTERRUPT_STATUS_RMSK); -- cgit v1.2.3 From 01ad444e3be719f8ad13f136a9b0d301806183c8 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 30 Mar 2021 15:47:17 +0100 Subject: soundwire: export sdw_compare_devid, sdw_extract_slave_id and sdw_slave_add Exporting these three functions makes sense as it can be used by other controllers like Qualcomm during auto-enumeration! Reported-by: kernel test robot Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210330144719.13284-8-srinivas.kandagatla@linaro.org Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 4 +++- drivers/soundwire/slave.c | 1 + include/linux/soundwire/sdw.h | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 9bd83c91a873..a9e0aa72654d 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -603,7 +603,7 @@ static struct sdw_slave *sdw_get_slave(struct sdw_bus *bus, int i) return NULL; } -static int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id) +int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id) { if (slave->id.mfg_id != id.mfg_id || slave->id.part_id != id.part_id || @@ -614,6 +614,7 @@ static int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id) return 0; } +EXPORT_SYMBOL(sdw_compare_devid); /* called with bus_lock held */ static int sdw_get_device_num(struct sdw_slave *slave) @@ -698,6 +699,7 @@ void sdw_extract_slave_id(struct sdw_bus *bus, "SDW Slave class_id 0x%02x, mfg_id 0x%04x, part_id 0x%04x, unique_id 0x%x, version 0x%x\n", id->class_id, id->mfg_id, id->part_id, id->unique_id, id->sdw_version); } +EXPORT_SYMBOL(sdw_extract_slave_id); static int sdw_program_device_num(struct sdw_bus *bus) { diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c index 112b21967c7a..0eed38a79c6d 100644 --- a/drivers/soundwire/slave.c +++ b/drivers/soundwire/slave.c @@ -88,6 +88,7 @@ int sdw_slave_add(struct sdw_bus *bus, return ret; } +EXPORT_SYMBOL(sdw_slave_add); #if IS_ENABLED(CONFIG_ACPI) diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 350436db6ddb..5ff9a8f37e91 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -1039,5 +1039,7 @@ int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value); int sdw_read_no_pm(struct sdw_slave *slave, u32 addr); int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val); int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val); +int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id); +void sdw_extract_slave_id(struct sdw_bus *bus, u64 addr, struct sdw_slave_id *id); #endif /* __SOUNDWIRE_H */ -- cgit v1.2.3 From a6e6581942caa0fab059634459c4c349fd7e4cc2 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 30 Mar 2021 15:47:18 +0100 Subject: soundwire: qcom: add auto enumeration support Qualcomm SoundWire controller supports Auto Enumeration of the devices within the IP. This patch enables support for this feature. Signed-off-by: Srinivas Kandagatla Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210330144719.13284-9-srinivas.kandagatla@linaro.org Signed-off-by: Vinod Koul --- drivers/soundwire/qcom.c | 86 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 5 deletions(-) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 1ad07784db4b..b1dbaf8263e5 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -57,6 +57,8 @@ #define SWRM_CMD_FIFO_RD_FIFO_ADDR 0x318 #define SWRM_RD_FIFO_CMD_ID_MASK GENMASK(11, 8) #define SWRM_ENUMERATOR_CFG_ADDR 0x500 +#define SWRM_ENUMERATOR_SLAVE_DEV_ID_1(m) (0x530 + 0x8 * (m)) +#define SWRM_ENUMERATOR_SLAVE_DEV_ID_2(m) (0x534 + 0x8 * (m)) #define SWRM_MCP_FRAME_CTRL_BANK_ADDR(m) (0x101C + 0x40 * (m)) #define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK GENMASK(2, 0) #define SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK GENMASK(7, 3) @@ -143,6 +145,7 @@ struct qcom_swrm_ctrl { enum sdw_slave_status status[SDW_MAX_DEVICES]; int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val); int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val); + u32 slave_status; }; struct qcom_swrm_data { @@ -343,6 +346,7 @@ static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl) int i; ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val); + ctrl->slave_status = val; for (i = 0; i < SDW_MAX_DEVICES; i++) { u32 s; @@ -353,10 +357,74 @@ static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl) } } +static void qcom_swrm_set_slave_dev_num(struct sdw_bus *bus, + struct sdw_slave *slave, int devnum) +{ + struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); + u32 status; + + ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &status); + status = (status >> (devnum * SWRM_MCP_SLV_STATUS_SZ)); + status &= SWRM_MCP_SLV_STATUS_MASK; + + if (status == SDW_SLAVE_ATTACHED) { + if (slave) + slave->dev_num = devnum; + mutex_lock(&bus->bus_lock); + set_bit(devnum, bus->assigned); + mutex_unlock(&bus->bus_lock); + } +} + +static int qcom_swrm_enumerate(struct sdw_bus *bus) +{ + struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); + struct sdw_slave *slave, *_s; + struct sdw_slave_id id; + u32 val1, val2; + bool found; + u64 addr; + int i; + char *buf1 = (char *)&val1, *buf2 = (char *)&val2; + + for (i = 1; i <= SDW_MAX_DEVICES; i++) { + /*SCP_Devid5 - Devid 4*/ + ctrl->reg_read(ctrl, SWRM_ENUMERATOR_SLAVE_DEV_ID_1(i), &val1); + + /*SCP_Devid3 - DevId 2 Devid 1 Devid 0*/ + ctrl->reg_read(ctrl, SWRM_ENUMERATOR_SLAVE_DEV_ID_2(i), &val2); + + if (!val1 && !val2) + break; + + addr = buf2[1] | (buf2[0] << 8) | (buf1[3] << 16) | + ((u64)buf1[2] << 24) | ((u64)buf1[1] << 32) | + ((u64)buf1[0] << 40); + + sdw_extract_slave_id(bus, addr, &id); + found = false; + /* Now compare with entries */ + list_for_each_entry_safe(slave, _s, &bus->slaves, node) { + if (sdw_compare_devid(slave, id) == 0) { + qcom_swrm_set_slave_dev_num(bus, slave, i); + found = true; + break; + } + } + + if (!found) { + qcom_swrm_set_slave_dev_num(bus, NULL, i); + sdw_slave_add(bus, &id, NULL); + } + } + + return 0; +} + static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id) { struct qcom_swrm_ctrl *swrm = dev_id; - u32 value, intr_sts, intr_sts_masked; + u32 value, intr_sts, intr_sts_masked, slave_status; u32 i; u8 devnum = 0; int ret = IRQ_HANDLED; @@ -385,8 +453,15 @@ static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id) case SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS: dev_err_ratelimited(swrm->dev, "%s: SWR new slave attached\n", __func__); - qcom_swrm_get_device_status(swrm); - sdw_handle_slave_status(&swrm->bus, swrm->status); + swrm->reg_read(swrm, SWRM_MCP_SLV_STATUS, &slave_status); + if (swrm->slave_status == slave_status) { + dev_err(swrm->dev, "Slave status not changed %x\n", + slave_status); + } else { + qcom_swrm_get_device_status(swrm); + qcom_swrm_enumerate(&swrm->bus); + sdw_handle_slave_status(&swrm->bus, swrm->status); + } break; case SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET: dev_err_ratelimited(swrm->dev, @@ -473,8 +548,8 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) ctrl->reg_write(ctrl, SWRM_MCP_FRAME_CTRL_BANK_ADDR(0), val); - /* Disable Auto enumeration */ - ctrl->reg_write(ctrl, SWRM_ENUMERATOR_CFG_ADDR, 0); + /* Enable Auto enumeration */ + ctrl->reg_write(ctrl, SWRM_ENUMERATOR_CFG_ADDR, 1); ctrl->intr_mask = SWRM_INTERRUPT_STATUS_RMSK; /* Mask soundwire interrupts */ @@ -508,6 +583,7 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) ctrl->reg_write(ctrl, SWRM_INTERRUPT_CPU_EN, SWRM_INTERRUPT_STATUS_RMSK); } + ctrl->slave_status = 0; return 0; } -- cgit v1.2.3 From 06dd96738d618391ae58e1b28f1ba49fef214c95 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 30 Mar 2021 15:47:19 +0100 Subject: soundwire: qcom: wait for enumeration to be complete in probe Signed-off-by: Srinivas Kandagatla Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210330144719.13284-10-srinivas.kandagatla@linaro.org Signed-off-by: Vinod Koul --- drivers/soundwire/qcom.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index b1dbaf8263e5..b08ecb9b418c 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -123,6 +123,7 @@ struct qcom_swrm_ctrl { struct regmap *regmap; void __iomem *mmio; struct completion broadcast; + struct completion enumeration; struct work_struct slave_work; /* Port alloc/free lock */ struct mutex port_lock; @@ -418,6 +419,7 @@ static int qcom_swrm_enumerate(struct sdw_bus *bus) } } + complete(&ctrl->enumeration); return 0; } @@ -1139,6 +1141,7 @@ static int qcom_swrm_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, ctrl); mutex_init(&ctrl->port_lock); init_completion(&ctrl->broadcast); + init_completion(&ctrl->enumeration); ctrl->bus.ops = &qcom_swrm_ops; ctrl->bus.port_ops = &qcom_swrm_port_ops; @@ -1185,6 +1188,8 @@ static int qcom_swrm_probe(struct platform_device *pdev) } qcom_swrm_init(ctrl); + wait_for_completion_timeout(&ctrl->enumeration, + msecs_to_jiffies(TIMEOUT_MS)); ret = qcom_swrm_register_dais(ctrl); if (ret) goto err_master_add; -- cgit v1.2.3 From 2fc989f74b8dac8a560b7c5e384c4f02b5cfd4b2 Mon Sep 17 00:00:00 2001 From: Konstantin Porotchkin Date: Sun, 7 Mar 2021 18:33:38 +0200 Subject: drivers: phy: add support for Armada CP110 UTMI PHY Add support for Marvell CP110 UTMI PHY driver allowing the USB2 port configuration independently from the boot loader setup. The CP110/CP115 dies have 2 UTMI PHYs that could be connected to two USB host controllers or to single USB device controller. Since there is only one USB device controller on die, only one of the UTMI PHYs could work in USB device mode. The CONFIG_PHY_MVEBU_CP110_UTMI should be enabled for usage of this driver. Signed-off-by: Konstantin Porotchkin Link: https://lore.kernel.org/r/20210307163343.25684-2-kostap@marvell.com Signed-off-by: Vinod Koul --- drivers/phy/marvell/Kconfig | 8 + drivers/phy/marvell/Makefile | 1 + drivers/phy/marvell/phy-mvebu-cp110-utmi.c | 384 +++++++++++++++++++++++++++++ 3 files changed, 393 insertions(+) create mode 100644 drivers/phy/marvell/phy-mvebu-cp110-utmi.c diff --git a/drivers/phy/marvell/Kconfig b/drivers/phy/marvell/Kconfig index 6c96f2bf5266..9208839019bd 100644 --- a/drivers/phy/marvell/Kconfig +++ b/drivers/phy/marvell/Kconfig @@ -67,6 +67,14 @@ config PHY_MVEBU_CP110_COMPHY lanes can be used by various controllers (Ethernet, sata, usb, PCIe...). +config PHY_MVEBU_CP110_UTMI + tristate "Marvell CP110 UTMI driver" + depends on ARCH_MVEBU || COMPILE_TEST + depends on OF + select GENERIC_PHY + help + Enable this to support Marvell CP110 UTMI PHY driver. + config PHY_MVEBU_SATA def_bool y depends on ARCH_DOVE || MACH_DOVE || MACH_KIRKWOOD diff --git a/drivers/phy/marvell/Makefile b/drivers/phy/marvell/Makefile index 7f296ef02829..90862c4daa26 100644 --- a/drivers/phy/marvell/Makefile +++ b/drivers/phy/marvell/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_PHY_MVEBU_A3700_COMPHY) += phy-mvebu-a3700-comphy.o obj-$(CONFIG_PHY_MVEBU_A3700_UTMI) += phy-mvebu-a3700-utmi.o obj-$(CONFIG_PHY_MVEBU_A38X_COMPHY) += phy-armada38x-comphy.o obj-$(CONFIG_PHY_MVEBU_CP110_COMPHY) += phy-mvebu-cp110-comphy.o +obj-$(CONFIG_PHY_MVEBU_CP110_UTMI) += phy-mvebu-cp110-utmi.o obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o obj-$(CONFIG_PHY_PXA_28NM_USB2) += phy-pxa-28nm-usb2.o diff --git a/drivers/phy/marvell/phy-mvebu-cp110-utmi.c b/drivers/phy/marvell/phy-mvebu-cp110-utmi.c new file mode 100644 index 000000000000..08d178a4dc13 --- /dev/null +++ b/drivers/phy/marvell/phy-mvebu-cp110-utmi.c @@ -0,0 +1,384 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Marvell + * + * Authors: + * Konstantin Porotchkin + * + * Marvell CP110 UTMI PHY driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define UTMI_PHY_PORTS 2 + +/* CP110 UTMI register macro definetions */ +#define SYSCON_USB_CFG_REG 0x420 +#define USB_CFG_DEVICE_EN_MASK BIT(0) +#define USB_CFG_DEVICE_MUX_OFFSET 1 +#define USB_CFG_DEVICE_MUX_MASK BIT(1) +#define USB_CFG_PLL_MASK BIT(25) + +#define SYSCON_UTMI_CFG_REG(id) (0x440 + (id) * 4) +#define UTMI_PHY_CFG_PU_MASK BIT(5) + +#define UTMI_PLL_CTRL_REG 0x0 +#define PLL_REFDIV_OFFSET 0 +#define PLL_REFDIV_MASK GENMASK(6, 0) +#define PLL_REFDIV_VAL 0x5 +#define PLL_FBDIV_OFFSET 16 +#define PLL_FBDIV_MASK GENMASK(24, 16) +#define PLL_FBDIV_VAL 0x60 +#define PLL_SEL_LPFR_MASK GENMASK(29, 28) +#define PLL_RDY BIT(31) +#define UTMI_CAL_CTRL_REG 0x8 +#define IMPCAL_VTH_OFFSET 8 +#define IMPCAL_VTH_MASK GENMASK(10, 8) +#define IMPCAL_VTH_VAL 0x7 +#define IMPCAL_DONE BIT(23) +#define PLLCAL_DONE BIT(31) +#define UTMI_TX_CH_CTRL_REG 0xC +#define DRV_EN_LS_OFFSET 12 +#define DRV_EN_LS_MASK GENMASK(15, 12) +#define IMP_SEL_LS_OFFSET 16 +#define IMP_SEL_LS_MASK GENMASK(19, 16) +#define TX_AMP_OFFSET 20 +#define TX_AMP_MASK GENMASK(22, 20) +#define TX_AMP_VAL 0x4 +#define UTMI_RX_CH_CTRL0_REG 0x14 +#define SQ_DET_EN BIT(15) +#define SQ_ANA_DTC_SEL BIT(28) +#define UTMI_RX_CH_CTRL1_REG 0x18 +#define SQ_AMP_CAL_OFFSET 0 +#define SQ_AMP_CAL_MASK GENMASK(2, 0) +#define SQ_AMP_CAL_VAL 1 +#define SQ_AMP_CAL_EN BIT(3) +#define UTMI_CTRL_STATUS0_REG 0x24 +#define SUSPENDM BIT(22) +#define TEST_SEL BIT(25) +#define UTMI_CHGDTC_CTRL_REG 0x38 +#define VDAT_OFFSET 8 +#define VDAT_MASK GENMASK(9, 8) +#define VDAT_VAL 1 +#define VSRC_OFFSET 10 +#define VSRC_MASK GENMASK(11, 10) +#define VSRC_VAL 1 + +#define PLL_LOCK_DELAY_US 10000 +#define PLL_LOCK_TIMEOUT_US 1000000 + +#define PORT_REGS(p) ((p)->priv->regs + (p)->id * 0x1000) + +/** + * struct mvebu_cp110_utmi - PHY driver data + * + * @regs: PHY registers + * @syscom: Regmap with system controller registers + * @dev: device driver handle + * @caps: PHY capabilities + */ +struct mvebu_cp110_utmi { + void __iomem *regs; + struct regmap *syscon; + struct device *dev; + const struct phy_ops *ops; +}; + +/** + * struct mvebu_cp110_utmi_port - PHY port data + * + * @priv: PHY driver data + * @id: PHY port ID + * @dr_mode: PHY connection: USB_DR_MODE_HOST or USB_DR_MODE_PERIPHERAL + */ +struct mvebu_cp110_utmi_port { + struct mvebu_cp110_utmi *priv; + u32 id; + enum usb_dr_mode dr_mode; +}; + +static void mvebu_cp110_utmi_port_setup(struct mvebu_cp110_utmi_port *port) +{ + u32 reg; + + /* + * Setup PLL. + * The reference clock is the frequency of quartz resonator + * connected to pins REFCLK_XIN and REFCLK_XOUT of the SoC. + * Register init values are matching the 40MHz default clock. + * The crystal used for all platform boards is now 25MHz. + * See the functional specification for details. + */ + reg = readl(PORT_REGS(port) + UTMI_PLL_CTRL_REG); + reg &= ~(PLL_REFDIV_MASK | PLL_FBDIV_MASK | PLL_SEL_LPFR_MASK); + reg |= (PLL_REFDIV_VAL << PLL_REFDIV_OFFSET) | + (PLL_FBDIV_VAL << PLL_FBDIV_OFFSET); + writel(reg, PORT_REGS(port) + UTMI_PLL_CTRL_REG); + + /* Impedance Calibration Threshold Setting */ + reg = readl(PORT_REGS(port) + UTMI_CAL_CTRL_REG); + reg &= ~IMPCAL_VTH_MASK; + reg |= IMPCAL_VTH_VAL << IMPCAL_VTH_OFFSET; + writel(reg, PORT_REGS(port) + UTMI_CAL_CTRL_REG); + + /* Set LS TX driver strength coarse control */ + reg = readl(PORT_REGS(port) + UTMI_TX_CH_CTRL_REG); + reg &= ~TX_AMP_MASK; + reg |= TX_AMP_VAL << TX_AMP_OFFSET; + writel(reg, PORT_REGS(port) + UTMI_TX_CH_CTRL_REG); + + /* Disable SQ and enable analog squelch detect */ + reg = readl(PORT_REGS(port) + UTMI_RX_CH_CTRL0_REG); + reg &= ~SQ_DET_EN; + reg |= SQ_ANA_DTC_SEL; + writel(reg, PORT_REGS(port) + UTMI_RX_CH_CTRL0_REG); + + /* + * Set External squelch calibration number and + * enable the External squelch calibration + */ + reg = readl(PORT_REGS(port) + UTMI_RX_CH_CTRL1_REG); + reg &= ~SQ_AMP_CAL_MASK; + reg |= (SQ_AMP_CAL_VAL << SQ_AMP_CAL_OFFSET) | SQ_AMP_CAL_EN; + writel(reg, PORT_REGS(port) + UTMI_RX_CH_CTRL1_REG); + + /* + * Set Control VDAT Reference Voltage - 0.325V and + * Control VSRC Reference Voltage - 0.6V + */ + reg = readl(PORT_REGS(port) + UTMI_CHGDTC_CTRL_REG); + reg &= ~(VDAT_MASK | VSRC_MASK); + reg |= (VDAT_VAL << VDAT_OFFSET) | (VSRC_VAL << VSRC_OFFSET); + writel(reg, PORT_REGS(port) + UTMI_CHGDTC_CTRL_REG); +} + +static int mvebu_cp110_utmi_phy_power_off(struct phy *phy) +{ + struct mvebu_cp110_utmi_port *port = phy_get_drvdata(phy); + struct mvebu_cp110_utmi *utmi = port->priv; + int i; + + /* Power down UTMI PHY port */ + regmap_clear_bits(utmi->syscon, SYSCON_UTMI_CFG_REG(port->id), + UTMI_PHY_CFG_PU_MASK); + + for (i = 0; i < UTMI_PHY_PORTS; i++) { + int test = regmap_test_bits(utmi->syscon, + SYSCON_UTMI_CFG_REG(i), + UTMI_PHY_CFG_PU_MASK); + /* skip PLL shutdown if there are active UTMI PHY ports */ + if (test != 0) + return 0; + } + + /* PLL Power down if all UTMI PHYs are down */ + regmap_clear_bits(utmi->syscon, SYSCON_USB_CFG_REG, USB_CFG_PLL_MASK); + + return 0; +} + +static int mvebu_cp110_utmi_phy_power_on(struct phy *phy) +{ + struct mvebu_cp110_utmi_port *port = phy_get_drvdata(phy); + struct mvebu_cp110_utmi *utmi = port->priv; + struct device *dev = &phy->dev; + int ret; + u32 reg; + + /* It is necessary to power off UTMI before configuration */ + ret = mvebu_cp110_utmi_phy_power_off(phy); + if (ret) { + dev_err(dev, "UTMI power OFF before power ON failed\n"); + return ret; + } + + /* + * If UTMI port is connected to USB Device controller, + * configure the USB MUX prior to UTMI PHY initialization. + * The single USB device controller can be connected + * to UTMI0 or to UTMI1 PHY port, but not to both. + */ + if (port->dr_mode == USB_DR_MODE_PERIPHERAL) { + regmap_update_bits(utmi->syscon, SYSCON_USB_CFG_REG, + USB_CFG_DEVICE_EN_MASK | USB_CFG_DEVICE_MUX_MASK, + USB_CFG_DEVICE_EN_MASK | + (port->id << USB_CFG_DEVICE_MUX_OFFSET)); + } + + /* Set Test suspendm mode and enable Test UTMI select */ + reg = readl(PORT_REGS(port) + UTMI_CTRL_STATUS0_REG); + reg |= SUSPENDM | TEST_SEL; + writel(reg, PORT_REGS(port) + UTMI_CTRL_STATUS0_REG); + + /* Wait for UTMI power down */ + mdelay(1); + + /* PHY port setup first */ + mvebu_cp110_utmi_port_setup(port); + + /* Power UP UTMI PHY */ + regmap_set_bits(utmi->syscon, SYSCON_UTMI_CFG_REG(port->id), + UTMI_PHY_CFG_PU_MASK); + + /* Disable Test UTMI select */ + reg = readl(PORT_REGS(port) + UTMI_CTRL_STATUS0_REG); + reg &= ~TEST_SEL; + writel(reg, PORT_REGS(port) + UTMI_CTRL_STATUS0_REG); + + /* Wait for impedance calibration */ + ret = readl_poll_timeout(PORT_REGS(port) + UTMI_CAL_CTRL_REG, reg, + reg & IMPCAL_DONE, + PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US); + if (ret) { + dev_err(dev, "Failed to end UTMI impedance calibration\n"); + return ret; + } + + /* Wait for PLL calibration */ + ret = readl_poll_timeout(PORT_REGS(port) + UTMI_CAL_CTRL_REG, reg, + reg & PLLCAL_DONE, + PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US); + if (ret) { + dev_err(dev, "Failed to end UTMI PLL calibration\n"); + return ret; + } + + /* Wait for PLL ready */ + ret = readl_poll_timeout(PORT_REGS(port) + UTMI_PLL_CTRL_REG, reg, + reg & PLL_RDY, + PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US); + if (ret) { + dev_err(dev, "PLL is not ready\n"); + return ret; + } + + /* PLL Power up */ + regmap_set_bits(utmi->syscon, SYSCON_USB_CFG_REG, USB_CFG_PLL_MASK); + + return 0; +} + +static const struct phy_ops mvebu_cp110_utmi_phy_ops = { + .power_on = mvebu_cp110_utmi_phy_power_on, + .power_off = mvebu_cp110_utmi_phy_power_off, + .owner = THIS_MODULE, +}; + +static const struct of_device_id mvebu_cp110_utmi_of_match[] = { + { .compatible = "marvell,cp110-utmi-phy" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mvebu_cp110_utmi_of_match); + +static int mvebu_cp110_utmi_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mvebu_cp110_utmi *utmi; + struct phy_provider *provider; + struct device_node *child; + u32 usb_devices = 0; + + utmi = devm_kzalloc(dev, sizeof(*utmi), GFP_KERNEL); + if (!utmi) + return -ENOMEM; + + utmi->dev = dev; + + /* Get system controller region */ + utmi->syscon = syscon_regmap_lookup_by_phandle(dev->of_node, + "marvell,system-controller"); + if (IS_ERR(utmi->syscon)) { + dev_err(dev, "Missing UTMI system controller\n"); + return PTR_ERR(utmi->syscon); + } + + /* Get UTMI memory region */ + utmi->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(utmi->regs)) + return PTR_ERR(utmi->regs); + + for_each_available_child_of_node(dev->of_node, child) { + struct mvebu_cp110_utmi_port *port; + struct phy *phy; + int ret; + u32 port_id; + + ret = of_property_read_u32(child, "reg", &port_id); + if ((ret < 0) || (port_id >= UTMI_PHY_PORTS)) { + dev_err(dev, + "invalid 'reg' property on child %pOF\n", + child); + continue; + } + + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) { + of_node_put(child); + return -ENOMEM; + } + + port->dr_mode = of_usb_get_dr_mode_by_phy(child, -1); + if ((port->dr_mode != USB_DR_MODE_HOST) && + (port->dr_mode != USB_DR_MODE_PERIPHERAL)) { + dev_err(&pdev->dev, + "Missing dual role setting of the port%d, will use HOST mode\n", + port_id); + port->dr_mode = USB_DR_MODE_HOST; + } + + if (port->dr_mode == USB_DR_MODE_PERIPHERAL) { + usb_devices++; + if (usb_devices > 1) { + dev_err(dev, + "Single USB device allowed! Port%d will use HOST mode\n", + port_id); + port->dr_mode = USB_DR_MODE_HOST; + } + } + + /* Retrieve PHY capabilities */ + utmi->ops = &mvebu_cp110_utmi_phy_ops; + + /* Instantiate the PHY */ + phy = devm_phy_create(dev, child, utmi->ops); + if (IS_ERR(phy)) { + dev_err(dev, "Failed to create the UTMI PHY\n"); + of_node_put(child); + return PTR_ERR(phy); + } + + port->priv = utmi; + port->id = port_id; + phy_set_drvdata(phy, port); + + /* Ensure the PHY is powered off */ + mvebu_cp110_utmi_phy_power_off(phy); + } + + dev_set_drvdata(dev, utmi); + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(provider); +} + +static struct platform_driver mvebu_cp110_utmi_driver = { + .probe = mvebu_cp110_utmi_phy_probe, + .driver = { + .name = "mvebu-cp110-utmi-phy", + .of_match_table = mvebu_cp110_utmi_of_match, + }, +}; +module_platform_driver(mvebu_cp110_utmi_driver); + +MODULE_AUTHOR("Konstatin Porotchkin "); +MODULE_DESCRIPTION("Marvell Armada CP110 UTMI PHY driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 6569d83863888bfae31edf33297465f783189681 Mon Sep 17 00:00:00 2001 From: Konstantin Porotchkin Date: Sun, 7 Mar 2021 18:33:39 +0200 Subject: dt-bindings: phy: convert phy-mvebu-utmi to YAML schema The new file name is marvell,armada-3700-utmi-phy.yaml Signed-off-by: Konstantin Porotchkin Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210307163343.25684-3-kostap@marvell.com Signed-off-by: Vinod Koul --- .../bindings/phy/marvell,armada-3700-utmi-phy.yaml | 57 ++++++++++++++++++++++ .../devicetree/bindings/phy/phy-mvebu-utmi.txt | 38 --------------- 2 files changed, 57 insertions(+), 38 deletions(-) create mode 100644 Documentation/devicetree/bindings/phy/marvell,armada-3700-utmi-phy.yaml delete mode 100644 Documentation/devicetree/bindings/phy/phy-mvebu-utmi.txt diff --git a/Documentation/devicetree/bindings/phy/marvell,armada-3700-utmi-phy.yaml b/Documentation/devicetree/bindings/phy/marvell,armada-3700-utmi-phy.yaml new file mode 100644 index 000000000000..2437c3683326 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/marvell,armada-3700-utmi-phy.yaml @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) + +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/phy/marvell,armada-3700-utmi-phy.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Marvell Armada UTMI/UTMI+ PHY + +maintainers: + - Miquel Raynal + +description: + On Armada 3700, there are two USB controllers, one is compatible with + the USB2 and USB3 specifications and supports OTG. The other one is USB2 + compliant and only supports host mode. Both of these controllers come with + a slightly different UTMI PHY. + +properties: + compatible: + enum: + - marvell,a3700-utmi-host-phy + - marvell,a3700-utmi-otg-phy + reg: + maxItems: 1 + + "#phy-cells": + const: 0 + + marvell,usb-misc-reg: + description: + Phandle on the "USB miscellaneous registers" shared region + covering registers related to both the host controller and + the PHY. + $ref: /schemas/types.yaml#/definitions/phandle + +required: + - compatible + - reg + - "#phy-cells" + - marvell,usb-misc-reg + +additionalProperties: false + +examples: + - | + usb2_utmi_host_phy: phy@5f000 { + compatible = "marvell,armada-3700-utmi-host-phy"; + reg = <0x5f000 0x800>; + marvell,usb-misc-reg = <&usb2_syscon>; + #phy-cells = <0>; + }; + + usb2_syscon: system-controller@5f800 { + compatible = "marvell,armada-3700-usb2-host-misc", "syscon"; + reg = <0x5f800 0x800>; + }; diff --git a/Documentation/devicetree/bindings/phy/phy-mvebu-utmi.txt b/Documentation/devicetree/bindings/phy/phy-mvebu-utmi.txt deleted file mode 100644 index aa99ceec73b0..000000000000 --- a/Documentation/devicetree/bindings/phy/phy-mvebu-utmi.txt +++ /dev/null @@ -1,38 +0,0 @@ -MVEBU A3700 UTMI PHY --------------------- - -USB2 UTMI+ PHY controllers can be found on the following Marvell MVEBU SoCs: -* Armada 3700 - -On Armada 3700, there are two USB controllers, one is compatible with the USB2 -and USB3 specifications and supports OTG. The other one is USB2 compliant and -only supports host mode. Both of these controllers come with a slightly -different UTMI PHY. - -Required Properties: - -- compatible: Should be one of: - * "marvell,a3700-utmi-host-phy" for the PHY connected to - the USB2 host-only controller. - * "marvell,a3700-utmi-otg-phy" for the PHY connected to - the USB3 and USB2 OTG capable controller. -- reg: PHY IP register range. -- marvell,usb-misc-reg: handle on the "USB miscellaneous registers" shared - region covering registers related to both the host - controller and the PHY. -- #phy-cells: Standard property (Documentation: phy-bindings.txt) Should be 0. - - -Example: - - usb2_utmi_host_phy: phy@5f000 { - compatible = "marvell,armada-3700-utmi-host-phy"; - reg = <0x5f000 0x800>; - marvell,usb-misc-reg = <&usb2_syscon>; - #phy-cells = <0>; - }; - - usb2_syscon: system-controller@5f800 { - compatible = "marvell,armada-3700-usb2-host-misc", "syscon"; - reg = <0x5f800 0x800>; - }; -- cgit v1.2.3 From b8900c539eabaa091cc6aff70f56a25aa78739bf Mon Sep 17 00:00:00 2001 From: Konstantin Porotchkin Date: Sun, 7 Mar 2021 18:33:40 +0200 Subject: devicetree/bindings: add support for CP110 UTMI PHY Add DTS binding for Marvell CP110 UTMI PHY Signed-off-by: Konstantin Porotchkin Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210307163343.25684-4-kostap@marvell.com Signed-off-by: Vinod Koul --- .../phy/marvell,armada-cp110-utmi-phy.yaml | 109 +++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/marvell,armada-cp110-utmi-phy.yaml diff --git a/Documentation/devicetree/bindings/phy/marvell,armada-cp110-utmi-phy.yaml b/Documentation/devicetree/bindings/phy/marvell,armada-cp110-utmi-phy.yaml new file mode 100644 index 000000000000..30f3b5f32a95 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/marvell,armada-cp110-utmi-phy.yaml @@ -0,0 +1,109 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) + +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/phy/marvell,armada-cp110-utmi-phy.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Marvell Armada CP110/CP115 UTMI PHY + +maintainers: + - Konstantin Porotchkin + +description: + On Armada 7k/8k and CN913x, there are two host and one device USB controllers. + Each of two exiting UTMI PHYs could be connected to either USB host or USB device + controller. + The USB device controller can only be connected to a single UTMI PHY port + 0.H----- USB HOST0 + UTMI PHY0 --------/ + 0.D-----0 + \------ USB DEVICE + 1.D-----1 + UTMI PHY1 --------\ + 1.H----- USB HOST1 + +properties: + compatible: + const: marvell,cp110-utmi-phy + + reg: + maxItems: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + marvell,system-controller: + description: + Phandle to the system controller node + $ref: /schemas/types.yaml#/definitions/phandle + +#Required child nodes: + +patternProperties: + "^usb-phy@[0|1]$": + type: object + description: + Each UTMI PHY port must be represented as a sub-node. + + properties: + reg: + description: phy port index. + maxItems: 1 + + "#phy-cells": + const: 0 + + required: + - reg + - "#phy-cells" + + additionalProperties: false + +required: + - compatible + - reg + - "#address-cells" + - "#size-cells" + - marvell,system-controller + +additionalProperties: false + +examples: + - | + cp0_utmi: utmi@580000 { + compatible = "marvell,cp110-utmi-phy"; + reg = <0x580000 0x2000>; + marvell,system-controller = <&cp0_syscon0>; + #address-cells = <1>; + #size-cells = <0>; + + cp0_utmi0: usb-phy@0 { + reg = <0>; + #phy-cells = <0>; + }; + + cp0_utmi1: usb-phy@1 { + reg = <1>; + #phy-cells = <0>; + }; + }; + + cp0_usb3_0 { + usb-phy = <&cp0_usb3_0_phy0>; + phys = <&cp0_utmi0>; + phy-names = "utmi"; + /* UTMI0 is connected to USB host controller (default mode) */ + dr_mode = "host"; + }; + + cp0_usb3_1 { + usb-phy = <&cp0_usb3_0_phy1>; + phys = <&cp0_utmi1>; + phy-names = "utmi"; + /* UTMI1 is connected to USB device controller */ + dr_mode = "peripheral"; + }; -- cgit v1.2.3 From 549cb1ae3e56e71ccd2547c3c40ff2556af8ce49 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 10 Mar 2021 17:38:35 +0530 Subject: phy: ti: j721e-wiz: Remove "regmap_field" from wiz_clk_{mux|div}_sel Both "struct wiz_clk_div_sel" and "struct wiz_clk_mux_sel" are static data that is common for all wiz instances. Including "struct regmap_field" for each of the wiz instances can yield undesirable results. Move "struct regmap_field" out of "struct wiz_clk_div_sel" and "struct wiz_clk_mux_sel" and make them point to constant data. So far no issues are observed since both these structures are not accessed outside the probe. Signed-off-by: Kishon Vijay Abraham I Link: https://lore.kernel.org/r/20210310120840.16447-2-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-j721e-wiz.c | 75 +++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 41 deletions(-) diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index 8a4be1ec2816..18dd8fc6fe5c 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -107,7 +107,7 @@ static const struct reg_field typec_ln10_swap = struct wiz_clk_mux { struct clk_hw hw; struct regmap_field *field; - u32 *table; + const u32 *table; struct clk_init_data clk_data; }; @@ -123,18 +123,16 @@ struct wiz_clk_divider { #define to_wiz_clk_div(_hw) container_of(_hw, struct wiz_clk_divider, hw) struct wiz_clk_mux_sel { - struct regmap_field *field; u32 table[4]; const char *node_name; }; struct wiz_clk_div_sel { - struct regmap_field *field; - const struct clk_div_table *table; + const struct clk_div_table *table; const char *node_name; }; -static struct wiz_clk_mux_sel clk_mux_sel_16g[] = { +static const struct wiz_clk_mux_sel clk_mux_sel_16g[] = { { /* * Mux value to be configured for each of the input clocks @@ -153,7 +151,7 @@ static struct wiz_clk_mux_sel clk_mux_sel_16g[] = { }, }; -static struct wiz_clk_mux_sel clk_mux_sel_10g[] = { +static const struct wiz_clk_mux_sel clk_mux_sel_10g[] = { { /* * Mux value to be configured for each of the input clocks @@ -179,7 +177,7 @@ static const struct clk_div_table clk_div_table[] = { { .val = 3, .div = 8, }, }; -static struct wiz_clk_div_sel clk_div_sel[] = { +static const struct wiz_clk_div_sel clk_div_sel[] = { { .table = clk_div_table, .node_name = "cmn-refclk-dig-div", @@ -201,8 +199,8 @@ enum wiz_type { struct wiz { struct regmap *regmap; enum wiz_type type; - struct wiz_clk_mux_sel *clk_mux_sel; - struct wiz_clk_div_sel *clk_div_sel; + const struct wiz_clk_mux_sel *clk_mux_sel; + const struct wiz_clk_div_sel *clk_div_sel; unsigned int clk_div_sel_num; struct regmap_field *por_en; struct regmap_field *phy_reset_n; @@ -214,6 +212,8 @@ struct wiz { struct regmap_field *pma_cmn_refclk_mode; struct regmap_field *pma_cmn_refclk_dig_div; struct regmap_field *pma_cmn_refclk1_dig_div; + struct regmap_field *mux_sel_field[WIZ_MUX_NUM_CLOCKS]; + struct regmap_field *div_sel_field[WIZ_DIV_NUM_CLOCKS_16G]; struct regmap_field *typec_ln10_swap; struct device *dev; @@ -310,8 +310,6 @@ static int wiz_init(struct wiz *wiz) static int wiz_regfield_init(struct wiz *wiz) { - struct wiz_clk_mux_sel *clk_mux_sel; - struct wiz_clk_div_sel *clk_div_sel; struct regmap *regmap = wiz->regmap; int num_lanes = wiz->num_lanes; struct device *dev = wiz->dev; @@ -344,54 +342,49 @@ static int wiz_regfield_init(struct wiz *wiz) return PTR_ERR(wiz->pma_cmn_refclk_mode); } - clk_div_sel = &wiz->clk_div_sel[CMN_REFCLK_DIG_DIV]; - clk_div_sel->field = devm_regmap_field_alloc(dev, regmap, - pma_cmn_refclk_dig_div); - if (IS_ERR(clk_div_sel->field)) { + wiz->div_sel_field[CMN_REFCLK_DIG_DIV] = + devm_regmap_field_alloc(dev, regmap, pma_cmn_refclk_dig_div); + if (IS_ERR(wiz->div_sel_field[CMN_REFCLK_DIG_DIV])) { dev_err(dev, "PMA_CMN_REFCLK_DIG_DIV reg field init failed\n"); - return PTR_ERR(clk_div_sel->field); + return PTR_ERR(wiz->div_sel_field[CMN_REFCLK_DIG_DIV]); } if (wiz->type == J721E_WIZ_16G) { - clk_div_sel = &wiz->clk_div_sel[CMN_REFCLK1_DIG_DIV]; - clk_div_sel->field = + wiz->div_sel_field[CMN_REFCLK1_DIG_DIV] = devm_regmap_field_alloc(dev, regmap, pma_cmn_refclk1_dig_div); - if (IS_ERR(clk_div_sel->field)) { + if (IS_ERR(wiz->div_sel_field[CMN_REFCLK1_DIG_DIV])) { dev_err(dev, "PMA_CMN_REFCLK1_DIG_DIV reg field init failed\n"); - return PTR_ERR(clk_div_sel->field); + return PTR_ERR(wiz->div_sel_field[CMN_REFCLK1_DIG_DIV]); } } - clk_mux_sel = &wiz->clk_mux_sel[PLL0_REFCLK]; - clk_mux_sel->field = devm_regmap_field_alloc(dev, regmap, - pll0_refclk_mux_sel); - if (IS_ERR(clk_mux_sel->field)) { + wiz->mux_sel_field[PLL0_REFCLK] = + devm_regmap_field_alloc(dev, regmap, pll0_refclk_mux_sel); + if (IS_ERR(wiz->mux_sel_field[PLL0_REFCLK])) { dev_err(dev, "PLL0_REFCLK_SEL reg field init failed\n"); - return PTR_ERR(clk_mux_sel->field); + return PTR_ERR(wiz->mux_sel_field[PLL0_REFCLK]); } - clk_mux_sel = &wiz->clk_mux_sel[PLL1_REFCLK]; - clk_mux_sel->field = devm_regmap_field_alloc(dev, regmap, - pll1_refclk_mux_sel); - if (IS_ERR(clk_mux_sel->field)) { + wiz->mux_sel_field[PLL1_REFCLK] = + devm_regmap_field_alloc(dev, regmap, pll1_refclk_mux_sel); + if (IS_ERR(wiz->mux_sel_field[PLL1_REFCLK])) { dev_err(dev, "PLL1_REFCLK_SEL reg field init failed\n"); - return PTR_ERR(clk_mux_sel->field); + return PTR_ERR(wiz->mux_sel_field[PLL1_REFCLK]); } - clk_mux_sel = &wiz->clk_mux_sel[REFCLK_DIG]; if (wiz->type == J721E_WIZ_10G) - clk_mux_sel->field = + wiz->mux_sel_field[REFCLK_DIG] = devm_regmap_field_alloc(dev, regmap, refclk_dig_sel_10g); else - clk_mux_sel->field = + wiz->mux_sel_field[REFCLK_DIG] = devm_regmap_field_alloc(dev, regmap, refclk_dig_sel_16g); - if (IS_ERR(clk_mux_sel->field)) { + if (IS_ERR(wiz->mux_sel_field[REFCLK_DIG])) { dev_err(dev, "REFCLK_DIG_SEL reg field init failed\n"); - return PTR_ERR(clk_mux_sel->field); + return PTR_ERR(wiz->mux_sel_field[REFCLK_DIG]); } for (i = 0; i < num_lanes; i++) { @@ -443,7 +436,7 @@ static u8 wiz_clk_mux_get_parent(struct clk_hw *hw) unsigned int val; regmap_field_read(field, &val); - return clk_mux_val_to_index(hw, mux->table, 0, val); + return clk_mux_val_to_index(hw, (u32 *)mux->table, 0, val); } static int wiz_clk_mux_set_parent(struct clk_hw *hw, u8 index) @@ -462,7 +455,7 @@ static const struct clk_ops wiz_clk_mux_ops = { }; static int wiz_mux_clk_register(struct wiz *wiz, struct device_node *node, - struct regmap_field *field, u32 *table) + struct regmap_field *field, const u32 *table) { struct device *dev = wiz->dev; struct clk_init_data *init; @@ -606,7 +599,7 @@ static int wiz_div_clk_register(struct wiz *wiz, struct device_node *node, static void wiz_clock_cleanup(struct wiz *wiz, struct device_node *node) { - struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel; + const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel; struct device_node *clk_node; int i; @@ -619,7 +612,7 @@ static void wiz_clock_cleanup(struct wiz *wiz, struct device_node *node) static int wiz_clock_init(struct wiz *wiz, struct device_node *node) { - struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel; + const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel; struct device *dev = wiz->dev; struct device_node *clk_node; const char *node_name; @@ -663,7 +656,7 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node) goto err; } - ret = wiz_mux_clk_register(wiz, clk_node, clk_mux_sel[i].field, + ret = wiz_mux_clk_register(wiz, clk_node, wiz->mux_sel_field[i], clk_mux_sel[i].table); if (ret) { dev_err(dev, "Failed to register %s clock\n", @@ -684,7 +677,7 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node) goto err; } - ret = wiz_div_clk_register(wiz, clk_node, clk_div_sel[i].field, + ret = wiz_div_clk_register(wiz, clk_node, wiz->div_sel_field[i], clk_div_sel[i].table); if (ret) { dev_err(dev, "Failed to register %s clock\n", -- cgit v1.2.3 From 7e52a39f1942b771213678c56002ce90a2f126d2 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 10 Mar 2021 17:38:36 +0530 Subject: phy: ti: j721e-wiz: Delete "clk_div_sel" clk provider during cleanup commit 091876cc355d ("phy: ti: j721e-wiz: Add support for WIZ module present in TI J721E SoC") modeled both MUX clocks and DIVIDER clocks in wiz. However during cleanup, it removed only the MUX clock provider. Remove the DIVIDER clock provider here. Fixes: 091876cc355d ("phy: ti: j721e-wiz: Add support for WIZ module present in TI J721E SoC") Signed-off-by: Kishon Vijay Abraham I Link: https://lore.kernel.org/r/20210310120840.16447-3-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-j721e-wiz.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index 18dd8fc6fe5c..5042e256a7e1 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -608,6 +608,12 @@ static void wiz_clock_cleanup(struct wiz *wiz, struct device_node *node) of_clk_del_provider(clk_node); of_node_put(clk_node); } + + for (i = 0; i < wiz->clk_div_sel_num; i++) { + clk_node = of_get_child_by_name(node, clk_div_sel[i].node_name); + of_clk_del_provider(clk_node); + of_node_put(clk_node); + } } static int wiz_clock_init(struct wiz *wiz, struct device_node *node) -- cgit v1.2.3 From 6ecac2f8ff1abbae464d6ce451ee07d49cdb2982 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 10 Mar 2021 17:38:37 +0530 Subject: phy: ti: j721e-wiz: Configure full rate divider for AM64 The frequency of the txmclk between PCIe and SERDES has changed to 250MHz from 500MHz. Configure full rate divider for AM64 accordingly. Signed-off-by: Kishon Vijay Abraham I Link: https://lore.kernel.org/r/20210310120840.16447-4-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-j721e-wiz.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index 5042e256a7e1..f5128f2690a6 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -101,6 +101,13 @@ static const struct reg_field p_standard_mode[WIZ_MAX_LANES] = { REG_FIELD(WIZ_LANECTL(3), 24, 25), }; +static const struct reg_field p0_fullrt_div[WIZ_MAX_LANES] = { + REG_FIELD(WIZ_LANECTL(0), 22, 23), + REG_FIELD(WIZ_LANECTL(1), 22, 23), + REG_FIELD(WIZ_LANECTL(2), 22, 23), + REG_FIELD(WIZ_LANECTL(3), 22, 23), +}; + static const struct reg_field typec_ln10_swap = REG_FIELD(WIZ_SERDES_TYPEC, 30, 30); @@ -191,6 +198,7 @@ static const struct wiz_clk_div_sel clk_div_sel[] = { enum wiz_type { J721E_WIZ_16G, J721E_WIZ_10G, + AM64_WIZ_10G, }; #define WIZ_TYPEC_DIR_DEBOUNCE_MIN 100 /* ms */ @@ -208,6 +216,7 @@ struct wiz { struct regmap_field *p_align[WIZ_MAX_LANES]; struct regmap_field *p_raw_auto_start[WIZ_MAX_LANES]; struct regmap_field *p_standard_mode[WIZ_MAX_LANES]; + struct regmap_field *p0_fullrt_div[WIZ_MAX_LANES]; struct regmap_field *pma_cmn_refclk_int_mode; struct regmap_field *pma_cmn_refclk_mode; struct regmap_field *pma_cmn_refclk_dig_div; @@ -373,7 +382,7 @@ static int wiz_regfield_init(struct wiz *wiz) return PTR_ERR(wiz->mux_sel_field[PLL1_REFCLK]); } - if (wiz->type == J721E_WIZ_10G) + if (wiz->type == J721E_WIZ_10G || wiz->type == AM64_WIZ_10G) wiz->mux_sel_field[REFCLK_DIG] = devm_regmap_field_alloc(dev, regmap, refclk_dig_sel_10g); @@ -417,6 +426,12 @@ static int wiz_regfield_init(struct wiz *wiz) i); return PTR_ERR(wiz->p_standard_mode[i]); } + + wiz->p0_fullrt_div[i] = devm_regmap_field_alloc(dev, regmap, p0_fullrt_div[i]); + if (IS_ERR(wiz->p0_fullrt_div[i])) { + dev_err(dev, "P%d_FULLRT_DIV reg field init failed\n", i); + return PTR_ERR(wiz->p0_fullrt_div[i]); + } } wiz->typec_ln10_swap = devm_regmap_field_alloc(dev, regmap, @@ -718,6 +733,17 @@ static int wiz_phy_reset_assert(struct reset_controller_dev *rcdev, return ret; } +static int wiz_phy_fullrt_div(struct wiz *wiz, int lane) +{ + if (wiz->type != AM64_WIZ_10G) + return 0; + + if (wiz->lane_phy_type[lane] == PHY_TYPE_PCIE) + return regmap_field_write(wiz->p0_fullrt_div[lane], 0x1); + + return 0; +} + static int wiz_phy_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) { @@ -741,6 +767,10 @@ static int wiz_phy_reset_deassert(struct reset_controller_dev *rcdev, return ret; } + ret = wiz_phy_fullrt_div(wiz, id - 1); + if (ret) + return ret; + if (wiz->lane_phy_type[id - 1] == PHY_TYPE_DP) ret = regmap_field_write(wiz->p_enable[id - 1], P_ENABLE); else @@ -768,6 +798,9 @@ static const struct of_device_id wiz_id_table[] = { { .compatible = "ti,j721e-wiz-10g", .data = (void *)J721E_WIZ_10G }, + { + .compatible = "ti,am64-wiz-10g", .data = (void *)AM64_WIZ_10G + }, {} }; MODULE_DEVICE_TABLE(of, wiz_id_table); @@ -900,14 +933,14 @@ static int wiz_probe(struct platform_device *pdev) wiz->dev = dev; wiz->regmap = regmap; wiz->num_lanes = num_lanes; - if (wiz->type == J721E_WIZ_10G) + if (wiz->type == J721E_WIZ_10G || wiz->type == AM64_WIZ_10G) wiz->clk_mux_sel = clk_mux_sel_10g; else wiz->clk_mux_sel = clk_mux_sel_16g; wiz->clk_div_sel = clk_div_sel; - if (wiz->type == J721E_WIZ_10G) + if (wiz->type == J721E_WIZ_10G || wiz->type == AM64_WIZ_10G) wiz->clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G; else wiz->clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_16G; -- cgit v1.2.3 From 040cbe7687316e265199ce892d3f7c24c041aaec Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 10 Mar 2021 17:38:38 +0530 Subject: phy: ti: j721e-wiz: Model the internal clocks without device tree input commit 091876cc355d ("phy: ti: j721e-wiz: Add support for WIZ module present in TI J721E SoC") modeled the internal clocks depending on the subnodes that are populated in device tree. However recent discussions in the mailing list [1] suggested to just add #clock cells in the parent DT node and model the clocks within the driver. Model the mux clocks without device tree input for AM64x SoC. Don't remove the earlier design since DT nodes for J7200 and J721e are already upstreamed. [1] -> http://lore.kernel.org/r/20210108025943.GA1790601@robh.at.kernel.org Signed-off-by: Kishon Vijay Abraham I Link: https://lore.kernel.org/r/20210310120840.16447-5-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-j721e-wiz.c | 144 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 139 insertions(+), 5 deletions(-) diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index f5128f2690a6..8a8c973d7dec 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -27,6 +28,10 @@ #define WIZ_SERDES_TYPEC 0x410 #define WIZ_LANECTL(n) (0x480 + (0x40 * (n))) +#define WIZ_MAX_INPUT_CLOCKS 4 +/* To include mux clocks, divider clocks and gate clocks */ +#define WIZ_MAX_OUTPUT_CLOCKS 32 + #define WIZ_MAX_LANES 4 #define WIZ_MUX_NUM_CLOCKS 3 #define WIZ_DIV_NUM_CLOCKS_16G 2 @@ -52,6 +57,13 @@ enum wiz_refclk_div_sel { CMN_REFCLK1_DIG_DIV, }; +enum wiz_clock_input { + WIZ_CORE_REFCLK, + WIZ_EXT_REFCLK, + WIZ_CORE_REFCLK1, + WIZ_EXT_REFCLK1, +}; + static const struct reg_field por_en = REG_FIELD(WIZ_SERDES_CTRL, 31, 31); static const struct reg_field phy_reset_n = REG_FIELD(WIZ_SERDES_RST, 31, 31); static const struct reg_field pll1_refclk_mux_sel = @@ -70,6 +82,11 @@ static const struct reg_field pma_cmn_refclk_dig_div = REG_FIELD(WIZ_SERDES_TOP_CTRL, 26, 27); static const struct reg_field pma_cmn_refclk1_dig_div = REG_FIELD(WIZ_SERDES_TOP_CTRL, 24, 25); +static const char * const output_clk_names[] = { + [TI_WIZ_PLL0_REFCLK] = "pll0-refclk", + [TI_WIZ_PLL1_REFCLK] = "pll1-refclk", + [TI_WIZ_REFCLK_DIG] = "refclk-dig", +}; static const struct reg_field p_enable[WIZ_MAX_LANES] = { REG_FIELD(WIZ_LANECTL(0), 30, 31), @@ -130,8 +147,10 @@ struct wiz_clk_divider { #define to_wiz_clk_div(_hw) container_of(_hw, struct wiz_clk_divider, hw) struct wiz_clk_mux_sel { - u32 table[4]; + u32 table[WIZ_MAX_INPUT_CLOCKS]; const char *node_name; + u32 num_parents; + u32 parents[WIZ_MAX_INPUT_CLOCKS]; }; struct wiz_clk_div_sel { @@ -164,14 +183,20 @@ static const struct wiz_clk_mux_sel clk_mux_sel_10g[] = { * Mux value to be configured for each of the input clocks * in the order populated in device tree */ + .num_parents = 2, + .parents = { WIZ_CORE_REFCLK, WIZ_EXT_REFCLK }, .table = { 1, 0 }, .node_name = "pll0-refclk", }, { + .num_parents = 2, + .parents = { WIZ_CORE_REFCLK, WIZ_EXT_REFCLK }, .table = { 1, 0 }, .node_name = "pll1-refclk", }, { + .num_parents = 2, + .parents = { WIZ_CORE_REFCLK, WIZ_EXT_REFCLK }, .table = { 1, 0 }, .node_name = "refclk-dig", }, @@ -232,6 +257,9 @@ struct wiz { struct gpio_desc *gpio_typec_dir; int typec_dir_delay; u32 lane_phy_type[WIZ_MAX_LANES]; + struct clk *input_clks[WIZ_MAX_INPUT_CLOCKS]; + struct clk *output_clks[WIZ_MAX_OUTPUT_CLOCKS]; + struct clk_onecell_data clk_data; }; static int wiz_reset(struct wiz *wiz) @@ -469,8 +497,69 @@ static const struct clk_ops wiz_clk_mux_ops = { .get_parent = wiz_clk_mux_get_parent, }; -static int wiz_mux_clk_register(struct wiz *wiz, struct device_node *node, - struct regmap_field *field, const u32 *table) +static int wiz_mux_clk_register(struct wiz *wiz, struct regmap_field *field, + const struct wiz_clk_mux_sel *mux_sel, int clk_index) +{ + struct device *dev = wiz->dev; + struct clk_init_data *init; + const char **parent_names; + unsigned int num_parents; + struct wiz_clk_mux *mux; + char clk_name[100]; + struct clk *clk; + int ret = 0, i; + + mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); + if (!mux) + return -ENOMEM; + + num_parents = mux_sel->num_parents; + + parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL); + if (!parent_names) + return -ENOMEM; + + for (i = 0; i < num_parents; i++) { + clk = wiz->input_clks[mux_sel->parents[i]]; + if (IS_ERR_OR_NULL(clk)) { + dev_err(dev, "Failed to get parent clk for %s\n", + output_clk_names[clk_index]); + ret = -EINVAL; + goto err; + } + parent_names[i] = __clk_get_name(clk); + } + + snprintf(clk_name, sizeof(clk_name), "%s_%s", dev_name(dev), output_clk_names[clk_index]); + + init = &mux->clk_data; + + init->ops = &wiz_clk_mux_ops; + init->flags = CLK_SET_RATE_NO_REPARENT; + init->parent_names = parent_names; + init->num_parents = num_parents; + init->name = clk_name; + + mux->field = field; + mux->table = mux_sel->table; + mux->hw.init = init; + + clk = devm_clk_register(dev, &mux->hw); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto err; + } + + wiz->output_clks[clk_index] = clk; + +err: + kfree(parent_names); + + return ret; +} + +static int wiz_mux_of_clk_register(struct wiz *wiz, struct device_node *node, + struct regmap_field *field, const u32 *table) { struct device *dev = wiz->dev; struct clk_init_data *init; @@ -615,9 +704,15 @@ static int wiz_div_clk_register(struct wiz *wiz, struct device_node *node, static void wiz_clock_cleanup(struct wiz *wiz, struct device_node *node) { const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel; + struct device *dev = wiz->dev; struct device_node *clk_node; int i; + if (wiz->type == AM64_WIZ_10G) { + of_clk_del_provider(dev->of_node); + return; + } + for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++) { clk_node = of_get_child_by_name(node, clk_mux_sel[i].node_name); of_clk_del_provider(clk_node); @@ -631,6 +726,36 @@ static void wiz_clock_cleanup(struct wiz *wiz, struct device_node *node) } } +static int wiz_clock_register(struct wiz *wiz) +{ + const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel; + struct device *dev = wiz->dev; + struct device_node *node = dev->of_node; + int clk_index; + int ret; + int i; + + if (wiz->type != AM64_WIZ_10G) + return 0; + + clk_index = TI_WIZ_PLL0_REFCLK; + for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++, clk_index++) { + ret = wiz_mux_clk_register(wiz, wiz->mux_sel_field[i], &clk_mux_sel[i], clk_index); + if (ret) { + dev_err(dev, "Failed to register clk: %s\n", output_clk_names[clk_index]); + return ret; + } + } + + wiz->clk_data.clks = wiz->output_clks; + wiz->clk_data.clk_num = WIZ_MAX_OUTPUT_CLOCKS; + ret = of_clk_add_provider(node, of_clk_src_onecell_get, &wiz->clk_data); + if (ret) + dev_err(dev, "Failed to add clock provider: %s\n", node->name); + + return ret; +} + static int wiz_clock_init(struct wiz *wiz, struct device_node *node) { const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel; @@ -648,6 +773,7 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node) ret = PTR_ERR(clk); return ret; } + wiz->input_clks[WIZ_CORE_REFCLK] = clk; rate = clk_get_rate(clk); if (rate >= 100000000) @@ -661,6 +787,7 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node) ret = PTR_ERR(clk); return ret; } + wiz->input_clks[WIZ_EXT_REFCLK] = clk; rate = clk_get_rate(clk); if (rate >= 100000000) @@ -668,6 +795,13 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node) else regmap_field_write(wiz->pma_cmn_refclk_mode, 0x2); + if (wiz->type == AM64_WIZ_10G) { + ret = wiz_clock_register(wiz); + if (ret) + dev_err(dev, "Failed to register wiz clocks\n"); + return ret; + } + for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++) { node_name = clk_mux_sel[i].node_name; clk_node = of_get_child_by_name(node, node_name); @@ -677,8 +811,8 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node) goto err; } - ret = wiz_mux_clk_register(wiz, clk_node, wiz->mux_sel_field[i], - clk_mux_sel[i].table); + ret = wiz_mux_of_clk_register(wiz, clk_node, wiz->mux_sel_field[i], + clk_mux_sel[i].table); if (ret) { dev_err(dev, "Failed to register %s clock\n", node_name); -- cgit v1.2.3 From 9e405f87b69b1c84bb960da76af1d1aa5c52e5f4 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 10 Mar 2021 17:38:39 +0530 Subject: phy: ti: j721e-wiz: Enable reference clock output in cmn_refclk_

cmn_refclk_

lines in Torrent SERDES is used for connecting external reference clock. cmn_refclk_

can also be configured to output the reference clock. In order to drive the refclk out from the SERDES (Cadence Torrent), PHY_EN_REFCLK should be set in SERDES_RST of WIZ. Model PHY_EN_REFCLK as a clock, so that platforms like AM642 EVM can enable it. Signed-off-by: Kishon Vijay Abraham I Link: https://lore.kernel.org/r/20210310120840.16447-6-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-j721e-wiz.c | 89 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index 8a8c973d7dec..a4b4e9d11761 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -66,6 +66,7 @@ enum wiz_clock_input { static const struct reg_field por_en = REG_FIELD(WIZ_SERDES_CTRL, 31, 31); static const struct reg_field phy_reset_n = REG_FIELD(WIZ_SERDES_RST, 31, 31); +static const struct reg_field phy_en_refclk = REG_FIELD(WIZ_SERDES_RST, 30, 30); static const struct reg_field pll1_refclk_mux_sel = REG_FIELD(WIZ_SERDES_RST, 29, 29); static const struct reg_field pll0_refclk_mux_sel = @@ -86,6 +87,7 @@ static const char * const output_clk_names[] = { [TI_WIZ_PLL0_REFCLK] = "pll0-refclk", [TI_WIZ_PLL1_REFCLK] = "pll1-refclk", [TI_WIZ_REFCLK_DIG] = "refclk-dig", + [TI_WIZ_PHY_EN_REFCLK] = "phy-en-refclk", }; static const struct reg_field p_enable[WIZ_MAX_LANES] = { @@ -158,6 +160,14 @@ struct wiz_clk_div_sel { const char *node_name; }; +struct wiz_phy_en_refclk { + struct clk_hw hw; + struct regmap_field *phy_en_refclk; + struct clk_init_data clk_data; +}; + +#define to_wiz_phy_en_refclk(_hw) container_of(_hw, struct wiz_phy_en_refclk, hw) + static const struct wiz_clk_mux_sel clk_mux_sel_16g[] = { { /* @@ -237,6 +247,7 @@ struct wiz { unsigned int clk_div_sel_num; struct regmap_field *por_en; struct regmap_field *phy_reset_n; + struct regmap_field *phy_en_refclk; struct regmap_field *p_enable[WIZ_MAX_LANES]; struct regmap_field *p_align[WIZ_MAX_LANES]; struct regmap_field *p_raw_auto_start[WIZ_MAX_LANES]; @@ -469,6 +480,76 @@ static int wiz_regfield_init(struct wiz *wiz) return PTR_ERR(wiz->typec_ln10_swap); } + wiz->phy_en_refclk = devm_regmap_field_alloc(dev, regmap, phy_en_refclk); + if (IS_ERR(wiz->phy_en_refclk)) { + dev_err(dev, "PHY_EN_REFCLK reg field init failed\n"); + return PTR_ERR(wiz->phy_en_refclk); + } + + return 0; +} + +static int wiz_phy_en_refclk_enable(struct clk_hw *hw) +{ + struct wiz_phy_en_refclk *wiz_phy_en_refclk = to_wiz_phy_en_refclk(hw); + struct regmap_field *phy_en_refclk = wiz_phy_en_refclk->phy_en_refclk; + + regmap_field_write(phy_en_refclk, 1); + + return 0; +} + +static void wiz_phy_en_refclk_disable(struct clk_hw *hw) +{ + struct wiz_phy_en_refclk *wiz_phy_en_refclk = to_wiz_phy_en_refclk(hw); + struct regmap_field *phy_en_refclk = wiz_phy_en_refclk->phy_en_refclk; + + regmap_field_write(phy_en_refclk, 0); +} + +static int wiz_phy_en_refclk_is_enabled(struct clk_hw *hw) +{ + struct wiz_phy_en_refclk *wiz_phy_en_refclk = to_wiz_phy_en_refclk(hw); + struct regmap_field *phy_en_refclk = wiz_phy_en_refclk->phy_en_refclk; + int val; + + regmap_field_read(phy_en_refclk, &val); + + return !!val; +} + +static const struct clk_ops wiz_phy_en_refclk_ops = { + .enable = wiz_phy_en_refclk_enable, + .disable = wiz_phy_en_refclk_disable, + .is_enabled = wiz_phy_en_refclk_is_enabled, +}; + +static int wiz_phy_en_refclk_register(struct wiz *wiz) +{ + struct wiz_phy_en_refclk *wiz_phy_en_refclk; + struct device *dev = wiz->dev; + struct clk_init_data *init; + struct clk *clk; + + wiz_phy_en_refclk = devm_kzalloc(dev, sizeof(*wiz_phy_en_refclk), GFP_KERNEL); + if (!wiz_phy_en_refclk) + return -ENOMEM; + + init = &wiz_phy_en_refclk->clk_data; + + init->ops = &wiz_phy_en_refclk_ops; + init->flags = 0; + init->name = output_clk_names[TI_WIZ_PHY_EN_REFCLK]; + + wiz_phy_en_refclk->phy_en_refclk = wiz->phy_en_refclk; + wiz_phy_en_refclk->hw.init = init; + + clk = devm_clk_register(dev, &wiz_phy_en_refclk->hw); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + wiz->output_clks[TI_WIZ_PHY_EN_REFCLK] = clk; + return 0; } @@ -724,6 +805,8 @@ static void wiz_clock_cleanup(struct wiz *wiz, struct device_node *node) of_clk_del_provider(clk_node); of_node_put(clk_node); } + + of_clk_del_provider(wiz->dev->of_node); } static int wiz_clock_register(struct wiz *wiz) @@ -747,6 +830,12 @@ static int wiz_clock_register(struct wiz *wiz) } } + ret = wiz_phy_en_refclk_register(wiz); + if (ret) { + dev_err(dev, "Failed to add phy-en-refclk\n"); + return ret; + } + wiz->clk_data.clks = wiz->output_clks; wiz->clk_data.clk_num = WIZ_MAX_OUTPUT_CLOCKS; ret = of_clk_add_provider(node, of_clk_src_onecell_get, &wiz->clk_data); -- cgit v1.2.3 From 2cca0228f3641e68ac2433a8e75b130d907ce78a Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 10 Mar 2021 17:38:40 +0530 Subject: phy: cadence-torrent: Add support to drive refclk out cmn_refclk_

lines in Torrent SERDES is used for connecting external reference clock. cmn_refclk_

can also be configured to output the reference clock. Model this derived reference clock as a "clock" so that platforms like AM642 EVM can enable it. This is used by PCIe to use the same refclk both in local SERDES and remote device. Add support here to drive refclk out. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Swapnil Jakhade Link: https://lore.kernel.org/r/20210310120840.16447-7-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/Kconfig | 1 + drivers/phy/cadence/phy-cadence-torrent.c | 188 +++++++++++++++++++++++++++++- 2 files changed, 186 insertions(+), 3 deletions(-) diff --git a/drivers/phy/cadence/Kconfig b/drivers/phy/cadence/Kconfig index 432832bdbd16..27e9d6c377e5 100644 --- a/drivers/phy/cadence/Kconfig +++ b/drivers/phy/cadence/Kconfig @@ -7,6 +7,7 @@ config PHY_CADENCE_TORRENT tristate "Cadence Torrent PHY driver" depends on OF depends on HAS_IOMEM + depends on COMMON_CLK select GENERIC_PHY help Support for Cadence Torrent PHY. diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index 591a15834b48..c6fee7f75f57 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -7,7 +7,9 @@ */ #include +#include #include +#include #include #include #include @@ -84,6 +86,8 @@ #define CMN_PLLSM1_PLLLOCK_TMR 0x0034U #define CMN_CDIAG_CDB_PWRI_OVRD 0x0041U #define CMN_CDIAG_XCVRC_PWRI_OVRD 0x0047U +#define CMN_CDIAG_REFCLK_OVRD 0x004CU +#define CMN_CDIAG_REFCLK_DRV0_CTRL 0x0050U #define CMN_BGCAL_INIT_TMR 0x0064U #define CMN_BGCAL_ITER_TMR 0x0065U #define CMN_IBCAL_INIT_TMR 0x0074U @@ -206,6 +210,7 @@ #define RX_DIAG_ACYA 0x01FFU /* PHY PCS common registers */ +#define PHY_PIPE_CMN_CTRL1 0x0000U #define PHY_PLL_CFG 0x000EU #define PHY_PIPE_USB3_GEN2_PRE_CFG0 0x0020U #define PHY_PIPE_USB3_GEN2_POST_CFG0 0x0022U @@ -216,6 +221,10 @@ #define PHY_PMA_CMN_CTRL2 0x0001U #define PHY_PMA_PLL_RAW_CTRL 0x0003U +static const char * const clk_names[] = { + [CDNS_TORRENT_REFCLK_DRIVER] = "refclk-driver", +}; + static const struct reg_field phy_pll_cfg = REG_FIELD(PHY_PLL_CFG, 0, 1); @@ -231,6 +240,26 @@ static const struct reg_field phy_pma_pll_raw_ctrl = static const struct reg_field phy_reset_ctrl = REG_FIELD(PHY_RESET, 8, 8); +static const struct reg_field phy_pipe_cmn_ctrl1_0 = REG_FIELD(PHY_PIPE_CMN_CTRL1, 0, 0); + +#define REFCLK_OUT_NUM_CMN_CONFIG 5 + +enum cdns_torrent_refclk_out_cmn { + CMN_CDIAG_REFCLK_OVRD_4, + CMN_CDIAG_REFCLK_DRV0_CTRL_1, + CMN_CDIAG_REFCLK_DRV0_CTRL_4, + CMN_CDIAG_REFCLK_DRV0_CTRL_5, + CMN_CDIAG_REFCLK_DRV0_CTRL_6, +}; + +static const struct reg_field refclk_out_cmn_cfg[] = { + [CMN_CDIAG_REFCLK_OVRD_4] = REG_FIELD(CMN_CDIAG_REFCLK_OVRD, 4, 4), + [CMN_CDIAG_REFCLK_DRV0_CTRL_1] = REG_FIELD(CMN_CDIAG_REFCLK_DRV0_CTRL, 1, 1), + [CMN_CDIAG_REFCLK_DRV0_CTRL_4] = REG_FIELD(CMN_CDIAG_REFCLK_DRV0_CTRL, 4, 4), + [CMN_CDIAG_REFCLK_DRV0_CTRL_5] = REG_FIELD(CMN_CDIAG_REFCLK_DRV0_CTRL, 5, 5), + [CMN_CDIAG_REFCLK_DRV0_CTRL_6] = REG_FIELD(CMN_CDIAG_REFCLK_DRV0_CTRL, 6, 6), +}; + enum cdns_torrent_phy_type { TYPE_NONE, TYPE_DP, @@ -279,6 +308,8 @@ struct cdns_torrent_phy { struct regmap_field *phy_pma_cmn_ctrl_2; struct regmap_field *phy_pma_pll_raw_ctrl; struct regmap_field *phy_reset_ctrl; + struct clk *clks[CDNS_TORRENT_REFCLK_DRIVER + 1]; + struct clk_onecell_data clk_data; }; enum phy_powerstate { @@ -288,6 +319,16 @@ enum phy_powerstate { POWERSTATE_A3 = 3, }; +struct cdns_torrent_derived_refclk { + struct clk_hw hw; + struct regmap_field *phy_pipe_cmn_ctrl1_0; + struct regmap_field *cmn_fields[REFCLK_OUT_NUM_CMN_CONFIG]; + struct clk_init_data clk_data; +}; + +#define to_cdns_torrent_derived_refclk(_hw) \ + container_of(_hw, struct cdns_torrent_derived_refclk, hw) + static int cdns_torrent_phy_init(struct phy *phy); static int cdns_torrent_dp_init(struct phy *phy); static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy, @@ -1604,6 +1645,108 @@ static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy, u32 num_lanes) return ret; } +static int cdns_torrent_derived_refclk_enable(struct clk_hw *hw) +{ + struct cdns_torrent_derived_refclk *derived_refclk = to_cdns_torrent_derived_refclk(hw); + + regmap_field_write(derived_refclk->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_6], 0); + regmap_field_write(derived_refclk->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_4], 1); + regmap_field_write(derived_refclk->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_5], 1); + regmap_field_write(derived_refclk->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_1], 0); + regmap_field_write(derived_refclk->cmn_fields[CMN_CDIAG_REFCLK_OVRD_4], 1); + regmap_field_write(derived_refclk->phy_pipe_cmn_ctrl1_0, 1); + + return 0; +} + +static void cdns_torrent_derived_refclk_disable(struct clk_hw *hw) +{ + struct cdns_torrent_derived_refclk *derived_refclk = to_cdns_torrent_derived_refclk(hw); + + regmap_field_write(derived_refclk->phy_pipe_cmn_ctrl1_0, 0); +} + +static int cdns_torrent_derived_refclk_is_enabled(struct clk_hw *hw) +{ + struct cdns_torrent_derived_refclk *derived_refclk = to_cdns_torrent_derived_refclk(hw); + int val; + + regmap_field_read(derived_refclk->phy_pipe_cmn_ctrl1_0, &val); + + return !!val; +} + +static const struct clk_ops cdns_torrent_derived_refclk_ops = { + .enable = cdns_torrent_derived_refclk_enable, + .disable = cdns_torrent_derived_refclk_disable, + .is_enabled = cdns_torrent_derived_refclk_is_enabled, +}; + +static int cdns_torrent_derived_refclk_register(struct cdns_torrent_phy *cdns_phy) +{ + struct cdns_torrent_derived_refclk *derived_refclk; + struct device *dev = cdns_phy->dev; + struct regmap_field *field; + struct clk_init_data *init; + const char *parent_name; + struct regmap *regmap; + char clk_name[100]; + struct clk *clk; + int i; + + derived_refclk = devm_kzalloc(dev, sizeof(*derived_refclk), GFP_KERNEL); + if (!derived_refclk) + return -ENOMEM; + + snprintf(clk_name, sizeof(clk_name), "%s_%s", dev_name(dev), + clk_names[CDNS_TORRENT_REFCLK_DRIVER]); + + clk = devm_clk_get_optional(dev, "phy_en_refclk"); + if (IS_ERR(clk)) { + dev_err(dev, "No parent clock for derived_refclk\n"); + return PTR_ERR(clk); + } + + init = &derived_refclk->clk_data; + + if (clk) { + parent_name = __clk_get_name(clk); + init->parent_names = &parent_name; + init->num_parents = 1; + } + init->ops = &cdns_torrent_derived_refclk_ops; + init->flags = 0; + init->name = clk_name; + + regmap = cdns_phy->regmap_phy_pcs_common_cdb; + field = devm_regmap_field_alloc(dev, regmap, phy_pipe_cmn_ctrl1_0); + if (IS_ERR(field)) { + dev_err(dev, "phy_pipe_cmn_ctrl1_0 reg field init failed\n"); + return PTR_ERR(field); + } + derived_refclk->phy_pipe_cmn_ctrl1_0 = field; + + regmap = cdns_phy->regmap_common_cdb; + for (i = 0; i < REFCLK_OUT_NUM_CMN_CONFIG; i++) { + field = devm_regmap_field_alloc(dev, regmap, refclk_out_cmn_cfg[i]); + if (IS_ERR(field)) { + dev_err(dev, "CMN reg field init failed\n"); + return PTR_ERR(field); + } + derived_refclk->cmn_fields[i] = field; + } + + derived_refclk->hw.init = init; + + clk = devm_clk_register(dev, &derived_refclk->hw); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + cdns_phy->clks[CDNS_TORRENT_REFCLK_DRIVER] = clk; + + return 0; +} + static int cdns_torrent_phy_on(struct phy *phy) { struct cdns_torrent_inst *inst = phy_get_drvdata(phy); @@ -2071,6 +2214,37 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) return 0; } +static void cdns_torrent_clk_cleanup(struct cdns_torrent_phy *cdns_phy) +{ + struct device *dev = cdns_phy->dev; + + of_clk_del_provider(dev->of_node); +} + +static int cdns_torrent_clk_register(struct cdns_torrent_phy *cdns_phy) +{ + struct device *dev = cdns_phy->dev; + struct device_node *node = dev->of_node; + int ret; + + ret = cdns_torrent_derived_refclk_register(cdns_phy); + if (ret) { + dev_err(dev, "failed to register derived refclk\n"); + return ret; + } + + cdns_phy->clk_data.clks = cdns_phy->clks; + cdns_phy->clk_data.clk_num = CDNS_TORRENT_REFCLK_DRIVER + 1; + + ret = of_clk_add_provider(node, of_clk_src_onecell_get, &cdns_phy->clk_data); + if (ret) { + dev_err(dev, "Failed to add clock provider: %s\n", node->name); + return ret; + } + + return 0; +} + static int cdns_torrent_phy_probe(struct platform_device *pdev) { struct cdns_torrent_phy *cdns_phy; @@ -2134,17 +2308,21 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev) if (ret) return ret; + ret = cdns_torrent_clk_register(cdns_phy); + if (ret) + return ret; + ret = clk_prepare_enable(cdns_phy->clk); if (ret) { dev_err(cdns_phy->dev, "Failed to prepare ref clock\n"); - return ret; + goto clk_cleanup; } cdns_phy->ref_clk_rate = clk_get_rate(cdns_phy->clk); if (!(cdns_phy->ref_clk_rate)) { dev_err(cdns_phy->dev, "Failed to get ref clock rate\n"); - clk_disable_unprepare(cdns_phy->clk); - return -EINVAL; + ret = -EINVAL; + goto clk_disable; } /* Enable APB */ @@ -2323,7 +2501,10 @@ put_lnk_rst: reset_control_put(cdns_phy->phys[i].lnk_rst); of_node_put(child); reset_control_assert(cdns_phy->apb_rst); +clk_disable: clk_disable_unprepare(cdns_phy->clk); +clk_cleanup: + cdns_torrent_clk_cleanup(cdns_phy); return ret; } @@ -2340,6 +2521,7 @@ static int cdns_torrent_phy_remove(struct platform_device *pdev) } clk_disable_unprepare(cdns_phy->clk); + cdns_torrent_clk_cleanup(cdns_phy); return 0; } -- cgit v1.2.3 From e25c9dbcfc17bfe4fb0b72cdb6926db708f1ed6b Mon Sep 17 00:00:00 2001 From: Swapnil Jakhade Date: Thu, 4 Mar 2021 07:08:13 +0100 Subject: phy: cadence-torrent: Update PCIe + QSGMII config for correct PLL1 clock For PCIe + QSGMII configuration where QSGMII was using PLL1 and was expecting 10GHz clock, configuration was giving 8GHz clock. Update register sequences to get correct PLL1 configuration. Also, update single link PCIe and single link SGMII/QSGMII configurations with related changes. Signed-off-by: Swapnil Jakhade Signed-off-by: Kishon Vijay Abraham I Link: https://lore.kernel.org/r/1614838096-32291-2-git-send-email-sjakhade@cadence.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-torrent.c | 77 ++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 28 deletions(-) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index c6fee7f75f57..6da8270060a6 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -126,6 +126,8 @@ #define CMN_PLL1_FRACDIVH_M0 0x00D2U #define CMN_PLL1_HIGH_THR_M0 0x00D3U #define CMN_PLL1_DSM_DIAG_M0 0x00D4U +#define CMN_PLL1_DSM_FBH_OVRD_M0 0x00D5U +#define CMN_PLL1_DSM_FBL_OVRD_M0 0x00D6U #define CMN_PLL1_SS_CTRL1_M0 0x00D8U #define CMN_PLL1_SS_CTRL2_M0 0x00D9U #define CMN_PLL1_SS_CTRL3_M0 0x00DAU @@ -167,6 +169,7 @@ #define TX_TXCC_CPOST_MULT_00 0x004CU #define TX_TXCC_CPOST_MULT_01 0x004DU #define TX_TXCC_MGNFS_MULT_000 0x0050U +#define TX_TXCC_MGNFS_MULT_100 0x0054U #define DRV_DIAG_TX_DRV 0x00C6U #define XCVR_DIAG_PLLDRC_CTRL 0x00E5U #define XCVR_DIAG_HSCLK_SEL 0x00E6U @@ -2827,12 +2830,22 @@ static struct cdns_torrent_vals sgmii_pcie_xcvr_diag_ln_vals = { }; /* SGMII 100 MHz Ref clk, no SSC */ -static struct cdns_reg_pairs sgmii_100_no_ssc_cmn_regs[] = { +static struct cdns_reg_pairs sl_sgmii_100_no_ssc_cmn_regs[] = { + {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, + {0x001E, CMN_PLL1_DSM_FBH_OVRD_M0}, + {0x000C, CMN_PLL1_DSM_FBL_OVRD_M0}, {0x0003, CMN_PLL0_VCOCAL_TCTRL}, - {0x0003, CMN_PLL1_VCOCAL_TCTRL}, - {0x3700, CMN_DIAG_BIAS_OVRD1}, - {0x0008, CMN_TXPUCAL_TUNE}, - {0x0008, CMN_TXPDCAL_TUNE} + {0x0003, CMN_PLL1_VCOCAL_TCTRL} +}; + +static struct cdns_torrent_vals sl_sgmii_100_no_ssc_cmn_vals = { + .reg_pairs = sl_sgmii_100_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(sl_sgmii_100_no_ssc_cmn_regs), +}; + +static struct cdns_reg_pairs sgmii_100_no_ssc_cmn_regs[] = { + {0x007F, CMN_TXPUCAL_TUNE}, + {0x007F, CMN_TXPDCAL_TUNE} }; static struct cdns_reg_pairs sgmii_100_no_ssc_tx_ln_regs[] = { @@ -2918,17 +2931,14 @@ static struct cdns_reg_pairs sgmii_100_int_ssc_cmn_regs[] = { {0x0C5E, CMN_PLL1_VCOCAL_REFTIM_START}, {0x0C56, CMN_PLL0_VCOCAL_PLLCNT_START}, {0x0C56, CMN_PLL1_VCOCAL_PLLCNT_START}, - {0x0003, CMN_PLL0_VCOCAL_TCTRL}, - {0x0003, CMN_PLL1_VCOCAL_TCTRL}, {0x00C7, CMN_PLL0_LOCK_REFCNT_START}, {0x00C7, CMN_PLL1_LOCK_REFCNT_START}, {0x00C7, CMN_PLL0_LOCK_PLLCNT_START}, {0x00C7, CMN_PLL1_LOCK_PLLCNT_START}, {0x0005, CMN_PLL0_LOCK_PLLCNT_THR}, {0x0005, CMN_PLL1_LOCK_PLLCNT_THR}, - {0x3700, CMN_DIAG_BIAS_OVRD1}, - {0x0008, CMN_TXPUCAL_TUNE}, - {0x0008, CMN_TXPDCAL_TUNE} + {0x007F, CMN_TXPUCAL_TUNE}, + {0x007F, CMN_TXPDCAL_TUNE} }; static struct cdns_torrent_vals sgmii_100_int_ssc_cmn_vals = { @@ -2937,16 +2947,30 @@ static struct cdns_torrent_vals sgmii_100_int_ssc_cmn_vals = { }; /* QSGMII 100 MHz Ref clk, no SSC */ -static struct cdns_reg_pairs qsgmii_100_no_ssc_cmn_regs[] = { +static struct cdns_reg_pairs sl_qsgmii_100_no_ssc_cmn_regs[] = { + {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, + {0x001E, CMN_PLL1_DSM_FBH_OVRD_M0}, + {0x000C, CMN_PLL1_DSM_FBL_OVRD_M0}, {0x0003, CMN_PLL0_VCOCAL_TCTRL}, {0x0003, CMN_PLL1_VCOCAL_TCTRL} }; +static struct cdns_torrent_vals sl_qsgmii_100_no_ssc_cmn_vals = { + .reg_pairs = sl_qsgmii_100_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(sl_qsgmii_100_no_ssc_cmn_regs), +}; + +static struct cdns_reg_pairs qsgmii_100_no_ssc_cmn_regs[] = { + {0x007F, CMN_TXPUCAL_TUNE}, + {0x007F, CMN_TXPDCAL_TUNE} +}; + static struct cdns_reg_pairs qsgmii_100_no_ssc_tx_ln_regs[] = { {0x00F3, TX_PSC_A0}, {0x04A2, TX_PSC_A2}, {0x04A2, TX_PSC_A3}, {0x0000, TX_TXCC_CPOST_MULT_00}, + {0x0011, TX_TXCC_MGNFS_MULT_100}, {0x0003, DRV_DIAG_TX_DRV} }; @@ -3025,14 +3049,14 @@ static struct cdns_reg_pairs qsgmii_100_int_ssc_cmn_regs[] = { {0x0C5E, CMN_PLL1_VCOCAL_REFTIM_START}, {0x0C56, CMN_PLL0_VCOCAL_PLLCNT_START}, {0x0C56, CMN_PLL1_VCOCAL_PLLCNT_START}, - {0x0003, CMN_PLL0_VCOCAL_TCTRL}, - {0x0003, CMN_PLL1_VCOCAL_TCTRL}, {0x00C7, CMN_PLL0_LOCK_REFCNT_START}, {0x00C7, CMN_PLL1_LOCK_REFCNT_START}, {0x00C7, CMN_PLL0_LOCK_PLLCNT_START}, {0x00C7, CMN_PLL1_LOCK_PLLCNT_START}, {0x0005, CMN_PLL0_LOCK_PLLCNT_THR}, - {0x0005, CMN_PLL1_LOCK_PLLCNT_THR} + {0x0005, CMN_PLL1_LOCK_PLLCNT_THR}, + {0x007F, CMN_TXPUCAL_TUNE}, + {0x007F, CMN_TXPDCAL_TUNE} }; static struct cdns_torrent_vals qsgmii_100_int_ssc_cmn_vals = { @@ -3104,8 +3128,6 @@ static struct cdns_reg_pairs pcie_100_int_ssc_cmn_regs[] = { {0x0C5E, CMN_PLL1_VCOCAL_REFTIM_START}, {0x0C56, CMN_PLL0_VCOCAL_PLLCNT_START}, {0x0C56, CMN_PLL1_VCOCAL_PLLCNT_START}, - {0x0003, CMN_PLL0_VCOCAL_TCTRL}, - {0x0003, CMN_PLL1_VCOCAL_TCTRL}, {0x00C7, CMN_PLL0_LOCK_REFCNT_START}, {0x00C7, CMN_PLL1_LOCK_REFCNT_START}, {0x00C7, CMN_PLL0_LOCK_PLLCNT_START}, @@ -3161,8 +3183,6 @@ static struct cdns_reg_pairs sl_pcie_100_int_ssc_cmn_regs[] = { {0x0C5E, CMN_PLL1_VCOCAL_REFTIM_START}, {0x0C56, CMN_PLL0_VCOCAL_PLLCNT_START}, {0x0C56, CMN_PLL1_VCOCAL_PLLCNT_START}, - {0x0003, CMN_PLL0_VCOCAL_TCTRL}, - {0x0003, CMN_PLL1_VCOCAL_TCTRL}, {0x00C7, CMN_PLL0_LOCK_REFCNT_START}, {0x00C7, CMN_PLL1_LOCK_REFCNT_START}, {0x00C7, CMN_PLL0_LOCK_PLLCNT_START}, @@ -3178,8 +3198,9 @@ static struct cdns_torrent_vals sl_pcie_100_int_ssc_cmn_vals = { /* PCIe, 100 MHz Ref clk, no SSC & external SSC */ static struct cdns_reg_pairs pcie_100_ext_no_ssc_cmn_regs[] = { - {0x0003, CMN_PLL0_VCOCAL_TCTRL}, - {0x0003, CMN_PLL1_VCOCAL_TCTRL} + {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, + {0x001E, CMN_PLL1_DSM_FBH_OVRD_M0}, + {0x000C, CMN_PLL1_DSM_FBL_OVRD_M0} }; static struct cdns_reg_pairs pcie_100_ext_no_ssc_rx_ln_regs[] = { @@ -3380,8 +3401,8 @@ static const struct cdns_torrent_data cdns_map_torrent = { .cmn_vals = { [TYPE_PCIE] = { [TYPE_NONE] = { - [NO_SSC] = &pcie_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, + [NO_SSC] = NULL, + [EXTERNAL_SSC] = NULL, [INTERNAL_SSC] = &sl_pcie_100_int_ssc_cmn_vals, }, [TYPE_SGMII] = { @@ -3402,7 +3423,7 @@ static const struct cdns_torrent_data cdns_map_torrent = { }, [TYPE_SGMII] = { [TYPE_NONE] = { - [NO_SSC] = &sgmii_100_no_ssc_cmn_vals, + [NO_SSC] = &sl_sgmii_100_no_ssc_cmn_vals, }, [TYPE_PCIE] = { [NO_SSC] = &sgmii_100_no_ssc_cmn_vals, @@ -3417,7 +3438,7 @@ static const struct cdns_torrent_data cdns_map_torrent = { }, [TYPE_QSGMII] = { [TYPE_NONE] = { - [NO_SSC] = &qsgmii_100_no_ssc_cmn_vals, + [NO_SSC] = &sl_qsgmii_100_no_ssc_cmn_vals, }, [TYPE_PCIE] = { [NO_SSC] = &qsgmii_100_no_ssc_cmn_vals, @@ -3789,8 +3810,8 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { .cmn_vals = { [TYPE_PCIE] = { [TYPE_NONE] = { - [NO_SSC] = &pcie_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, + [NO_SSC] = NULL, + [EXTERNAL_SSC] = NULL, [INTERNAL_SSC] = &sl_pcie_100_int_ssc_cmn_vals, }, [TYPE_SGMII] = { @@ -3811,7 +3832,7 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, [TYPE_SGMII] = { [TYPE_NONE] = { - [NO_SSC] = &sgmii_100_no_ssc_cmn_vals, + [NO_SSC] = &sl_sgmii_100_no_ssc_cmn_vals, }, [TYPE_PCIE] = { [NO_SSC] = &sgmii_100_no_ssc_cmn_vals, @@ -3826,7 +3847,7 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, [TYPE_QSGMII] = { [TYPE_NONE] = { - [NO_SSC] = &qsgmii_100_no_ssc_cmn_vals, + [NO_SSC] = &sl_qsgmii_100_no_ssc_cmn_vals, }, [TYPE_PCIE] = { [NO_SSC] = &qsgmii_100_no_ssc_cmn_vals, -- cgit v1.2.3 From 488209909be38faf17398bfa243426e3eaff9ea6 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 4 Mar 2021 07:08:14 +0100 Subject: phy: ti: j721e-wiz: Add support for configuring QSGMII Configure MAC clock dividers required for QSGMII to be functional. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Swapnil Jakhade Link: https://lore.kernel.org/r/1614838096-32291-3-git-send-email-sjakhade@cadence.com Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-j721e-wiz.c | 64 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index a4b4e9d11761..124a3eddd189 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -27,6 +27,7 @@ #define WIZ_SERDES_RST 0x40c #define WIZ_SERDES_TYPEC 0x410 #define WIZ_LANECTL(n) (0x480 + (0x40 * (n))) +#define WIZ_LANEDIV(n) (0x484 + (0x40 * (n))) #define WIZ_MAX_INPUT_CLOCKS 4 /* To include mux clocks, divider clocks and gate clocks */ @@ -127,6 +128,20 @@ static const struct reg_field p0_fullrt_div[WIZ_MAX_LANES] = { REG_FIELD(WIZ_LANECTL(3), 22, 23), }; +static const struct reg_field p_mac_div_sel0[WIZ_MAX_LANES] = { + REG_FIELD(WIZ_LANEDIV(0), 16, 22), + REG_FIELD(WIZ_LANEDIV(1), 16, 22), + REG_FIELD(WIZ_LANEDIV(2), 16, 22), + REG_FIELD(WIZ_LANEDIV(3), 16, 22), +}; + +static const struct reg_field p_mac_div_sel1[WIZ_MAX_LANES] = { + REG_FIELD(WIZ_LANEDIV(0), 0, 8), + REG_FIELD(WIZ_LANEDIV(1), 0, 8), + REG_FIELD(WIZ_LANEDIV(2), 0, 8), + REG_FIELD(WIZ_LANEDIV(3), 0, 8), +}; + static const struct reg_field typec_ln10_swap = REG_FIELD(WIZ_SERDES_TYPEC, 30, 30); @@ -252,6 +267,8 @@ struct wiz { struct regmap_field *p_align[WIZ_MAX_LANES]; struct regmap_field *p_raw_auto_start[WIZ_MAX_LANES]; struct regmap_field *p_standard_mode[WIZ_MAX_LANES]; + struct regmap_field *p_mac_div_sel0[WIZ_MAX_LANES]; + struct regmap_field *p_mac_div_sel1[WIZ_MAX_LANES]; struct regmap_field *p0_fullrt_div[WIZ_MAX_LANES]; struct regmap_field *pma_cmn_refclk_int_mode; struct regmap_field *pma_cmn_refclk_mode; @@ -290,6 +307,27 @@ static int wiz_reset(struct wiz *wiz) return 0; } +static int wiz_p_mac_div_sel(struct wiz *wiz) +{ + u32 num_lanes = wiz->num_lanes; + int ret; + int i; + + for (i = 0; i < num_lanes; i++) { + if (wiz->lane_phy_type[i] == PHY_TYPE_QSGMII) { + ret = regmap_field_write(wiz->p_mac_div_sel0[i], 1); + if (ret) + return ret; + + ret = regmap_field_write(wiz->p_mac_div_sel1[i], 2); + if (ret) + return ret; + } + } + + return 0; +} + static int wiz_mode_select(struct wiz *wiz) { u32 num_lanes = wiz->num_lanes; @@ -300,8 +338,8 @@ static int wiz_mode_select(struct wiz *wiz) for (i = 0; i < num_lanes; i++) { if (wiz->lane_phy_type[i] == PHY_TYPE_DP) mode = LANE_MODE_GEN1; - else - mode = LANE_MODE_GEN4; + else if (wiz->lane_phy_type[i] == PHY_TYPE_QSGMII) + mode = LANE_MODE_GEN2; ret = regmap_field_write(wiz->p_standard_mode[i], mode); if (ret) @@ -347,6 +385,12 @@ static int wiz_init(struct wiz *wiz) return ret; } + ret = wiz_p_mac_div_sel(wiz); + if (ret) { + dev_err(dev, "Configuring P0 MAC DIV SEL failed\n"); + return ret; + } + ret = wiz_init_raw_interface(wiz, true); if (ret) { dev_err(dev, "WIZ interface initialization failed\n"); @@ -471,6 +515,22 @@ static int wiz_regfield_init(struct wiz *wiz) dev_err(dev, "P%d_FULLRT_DIV reg field init failed\n", i); return PTR_ERR(wiz->p0_fullrt_div[i]); } + + wiz->p_mac_div_sel0[i] = + devm_regmap_field_alloc(dev, regmap, p_mac_div_sel0[i]); + if (IS_ERR(wiz->p_mac_div_sel0[i])) { + dev_err(dev, "P%d_MAC_DIV_SEL0 reg field init fail\n", + i); + return PTR_ERR(wiz->p_mac_div_sel0[i]); + } + + wiz->p_mac_div_sel1[i] = + devm_regmap_field_alloc(dev, regmap, p_mac_div_sel1[i]); + if (IS_ERR(wiz->p_mac_div_sel1[i])) { + dev_err(dev, "P%d_MAC_DIV_SEL1 reg field init fail\n", + i); + return PTR_ERR(wiz->p_mac_div_sel1[i]); + } } wiz->typec_ln10_swap = devm_regmap_field_alloc(dev, regmap, -- cgit v1.2.3 From 70901a7d64cb018df452b1a2880aba7f4416f508 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 4 Mar 2021 07:08:15 +0100 Subject: phy: cadence-torrent: Update SGMII/QSGMII configuration specific to TI Update SGMII/QSGMII configuration specific to TI. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Swapnil Jakhade Link: https://lore.kernel.org/r/1614838096-32291-4-git-send-email-sjakhade@cadence.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-torrent.c | 58 +++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index 6da8270060a6..9a963f1c1b0b 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -174,6 +174,7 @@ #define XCVR_DIAG_PLLDRC_CTRL 0x00E5U #define XCVR_DIAG_HSCLK_SEL 0x00E6U #define XCVR_DIAG_HSCLK_DIV 0x00E7U +#define XCVR_DIAG_RXCLK_CTRL 0x00E9U #define XCVR_DIAG_BIDI_CTRL 0x00EAU #define XCVR_DIAG_PSC_OVRD 0x00EBU #define TX_PSC_A0 0x0100U @@ -2856,6 +2857,15 @@ static struct cdns_reg_pairs sgmii_100_no_ssc_tx_ln_regs[] = { {0x00B3, DRV_DIAG_TX_DRV} }; +static struct cdns_reg_pairs ti_sgmii_100_no_ssc_tx_ln_regs[] = { + {0x00F3, TX_PSC_A0}, + {0x04A2, TX_PSC_A2}, + {0x04A2, TX_PSC_A3}, + {0x0000, TX_TXCC_CPOST_MULT_00}, + {0x00B3, DRV_DIAG_TX_DRV}, + {0x4000, XCVR_DIAG_RXCLK_CTRL}, +}; + static struct cdns_reg_pairs sgmii_100_no_ssc_rx_ln_regs[] = { {0x091D, RX_PSC_A0}, {0x0900, RX_PSC_A2}, @@ -2884,6 +2894,11 @@ static struct cdns_torrent_vals sgmii_100_no_ssc_tx_ln_vals = { .num_regs = ARRAY_SIZE(sgmii_100_no_ssc_tx_ln_regs), }; +static struct cdns_torrent_vals ti_sgmii_100_no_ssc_tx_ln_vals = { + .reg_pairs = ti_sgmii_100_no_ssc_tx_ln_regs, + .num_regs = ARRAY_SIZE(ti_sgmii_100_no_ssc_tx_ln_regs), +}; + static struct cdns_torrent_vals sgmii_100_no_ssc_rx_ln_vals = { .reg_pairs = sgmii_100_no_ssc_rx_ln_regs, .num_regs = ARRAY_SIZE(sgmii_100_no_ssc_rx_ln_regs), @@ -2974,6 +2989,16 @@ static struct cdns_reg_pairs qsgmii_100_no_ssc_tx_ln_regs[] = { {0x0003, DRV_DIAG_TX_DRV} }; +static struct cdns_reg_pairs ti_qsgmii_100_no_ssc_tx_ln_regs[] = { + {0x00F3, TX_PSC_A0}, + {0x04A2, TX_PSC_A2}, + {0x04A2, TX_PSC_A3}, + {0x0000, TX_TXCC_CPOST_MULT_00}, + {0x0011, TX_TXCC_MGNFS_MULT_100}, + {0x0003, DRV_DIAG_TX_DRV}, + {0x4000, XCVR_DIAG_RXCLK_CTRL}, +}; + static struct cdns_reg_pairs qsgmii_100_no_ssc_rx_ln_regs[] = { {0x091D, RX_PSC_A0}, {0x0900, RX_PSC_A2}, @@ -3002,6 +3027,11 @@ static struct cdns_torrent_vals qsgmii_100_no_ssc_tx_ln_vals = { .num_regs = ARRAY_SIZE(qsgmii_100_no_ssc_tx_ln_regs), }; +static struct cdns_torrent_vals ti_qsgmii_100_no_ssc_tx_ln_vals = { + .reg_pairs = ti_qsgmii_100_no_ssc_tx_ln_regs, + .num_regs = ARRAY_SIZE(ti_qsgmii_100_no_ssc_tx_ln_regs), +}; + static struct cdns_torrent_vals qsgmii_100_no_ssc_rx_ln_vals = { .reg_pairs = qsgmii_100_no_ssc_rx_ln_regs, .num_regs = ARRAY_SIZE(qsgmii_100_no_ssc_rx_ln_regs), @@ -3908,32 +3938,32 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, [TYPE_SGMII] = { [TYPE_NONE] = { - [NO_SSC] = &sgmii_100_no_ssc_tx_ln_vals, + [NO_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, }, [TYPE_PCIE] = { - [NO_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals, + [NO_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, }, [TYPE_USB] = { - [NO_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals, + [NO_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, }, }, [TYPE_QSGMII] = { [TYPE_NONE] = { - [NO_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, + [NO_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, }, [TYPE_PCIE] = { - [NO_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, + [NO_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, }, [TYPE_USB] = { - [NO_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, + [NO_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, }, }, [TYPE_USB] = { -- cgit v1.2.3 From ed9e07f815cd66405895781dd29033c1a7b47b8a Mon Sep 17 00:00:00 2001 From: Swapnil Jakhade Date: Thu, 4 Mar 2021 07:08:16 +0100 Subject: phy: cadence-torrent: Update PCIe + USB config for correct PLL1 clock Update PCIe + USB register sequences for correct PLL1 clock configuration. Also, update sequences for other USB configurations with dependent changes. Signed-off-by: Swapnil Jakhade Signed-off-by: Kishon Vijay Abraham I Link: https://lore.kernel.org/r/1614838096-32291-5-git-send-email-sjakhade@cadence.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-torrent.c | 47 ++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index 9a963f1c1b0b..95160da3e667 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -2641,8 +2641,6 @@ static struct cdns_reg_pairs usb_100_int_ssc_cmn_regs[] = { {0x0C5E, CMN_PLL1_VCOCAL_REFTIM_START}, {0x0C56, CMN_PLL0_VCOCAL_PLLCNT_START}, {0x0C56, CMN_PLL1_VCOCAL_PLLCNT_START}, - {0x0003, CMN_PLL0_VCOCAL_TCTRL}, - {0x0003, CMN_PLL1_VCOCAL_TCTRL}, {0x00C7, CMN_PLL0_LOCK_REFCNT_START}, {0x00C7, CMN_PLL1_LOCK_REFCNT_START}, {0x00C7, CMN_PLL0_LOCK_PLLCNT_START}, @@ -2650,7 +2648,9 @@ static struct cdns_reg_pairs usb_100_int_ssc_cmn_regs[] = { {0x0005, CMN_PLL0_LOCK_PLLCNT_THR}, {0x0005, CMN_PLL1_LOCK_PLLCNT_THR}, {0x8200, CMN_CDIAG_CDB_PWRI_OVRD}, - {0x8200, CMN_CDIAG_XCVRC_PWRI_OVRD} + {0x8200, CMN_CDIAG_XCVRC_PWRI_OVRD}, + {0x007F, CMN_TXPUCAL_TUNE}, + {0x007F, CMN_TXPDCAL_TUNE} }; static struct cdns_torrent_vals usb_100_int_ssc_cmn_vals = { @@ -2693,13 +2693,28 @@ static struct cdns_torrent_vals usb_phy_pcs_cmn_vals = { }; /* USB 100 MHz Ref clk, no SSC */ -static struct cdns_reg_pairs usb_100_no_ssc_cmn_regs[] = { +static struct cdns_reg_pairs sl_usb_100_no_ssc_cmn_regs[] = { + {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, + {0x001E, CMN_PLL1_DSM_FBH_OVRD_M0}, + {0x000C, CMN_PLL1_DSM_FBL_OVRD_M0}, {0x0003, CMN_PLL0_VCOCAL_TCTRL}, {0x0003, CMN_PLL1_VCOCAL_TCTRL}, {0x8200, CMN_CDIAG_CDB_PWRI_OVRD}, {0x8200, CMN_CDIAG_XCVRC_PWRI_OVRD} }; +static struct cdns_torrent_vals sl_usb_100_no_ssc_cmn_vals = { + .reg_pairs = sl_usb_100_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(sl_usb_100_no_ssc_cmn_regs), +}; + +static struct cdns_reg_pairs usb_100_no_ssc_cmn_regs[] = { + {0x8200, CMN_CDIAG_CDB_PWRI_OVRD}, + {0x8200, CMN_CDIAG_XCVRC_PWRI_OVRD}, + {0x007F, CMN_TXPUCAL_TUNE}, + {0x007F, CMN_TXPDCAL_TUNE} +}; + static struct cdns_reg_pairs usb_100_no_ssc_tx_ln_regs[] = { {0x02FF, TX_PSC_A0}, {0x06AF, TX_PSC_A1}, @@ -3483,8 +3498,8 @@ static const struct cdns_torrent_data cdns_map_torrent = { }, [TYPE_USB] = { [TYPE_NONE] = { - [NO_SSC] = &usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals, + [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, }, [TYPE_PCIE] = { @@ -3493,13 +3508,13 @@ static const struct cdns_torrent_data cdns_map_torrent = { [INTERNAL_SSC] = &usb_100_int_ssc_cmn_vals, }, [TYPE_SGMII] = { - [NO_SSC] = &usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals, + [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, }, [TYPE_QSGMII] = { - [NO_SSC] = &usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals, + [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, }, }, @@ -3892,8 +3907,8 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, [TYPE_USB] = { [TYPE_NONE] = { - [NO_SSC] = &usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals, + [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, }, [TYPE_PCIE] = { @@ -3902,13 +3917,13 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { [INTERNAL_SSC] = &usb_100_int_ssc_cmn_vals, }, [TYPE_SGMII] = { - [NO_SSC] = &usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals, + [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, }, [TYPE_QSGMII] = { - [NO_SSC] = &usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals, + [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, }, }, -- cgit v1.2.3 From 982313c38f2f3793b6435ff50997ae96a2274f5a Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Tue, 2 Mar 2021 11:54:12 +0100 Subject: phy: ralink: phy-mt7621-pci: fix XTAL bitmask When this was rewriten to get mainlined and start to use 'linux/bitfield.h' headers, XTAL_MASK was wrong. It must mask three bits but only two were used. Hence properly fix it to make things work. Fixes: d87da32372a0 ("phy: ralink: Add PHY driver for MT7621 PCIe PHY") Signed-off-by: Sergio Paracuellos Link: https://lore.kernel.org/r/20210302105412.16221-1-sergio.paracuellos@gmail.com Signed-off-by: Vinod Koul --- drivers/phy/ralink/phy-mt7621-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/ralink/phy-mt7621-pci.c b/drivers/phy/ralink/phy-mt7621-pci.c index 9a610b414b1f..84ee2b5c2228 100644 --- a/drivers/phy/ralink/phy-mt7621-pci.c +++ b/drivers/phy/ralink/phy-mt7621-pci.c @@ -62,7 +62,7 @@ #define RG_PE1_FRC_MSTCKDIV BIT(5) -#define XTAL_MASK GENMASK(7, 6) +#define XTAL_MASK GENMASK(8, 6) #define MAX_PHYS 2 -- cgit v1.2.3 From f26fde369c3d59e5711ff35a08c244888db137bb Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 25 Feb 2021 17:17:54 +0800 Subject: phy: ti: j721e-wiz: add missing call to of_node_put() In one of the error paths of the for_each_child_of_node() loop in of_property_read_u32, add missing call to of_node_put(). Fix the following coccicheck warning: ./drivers/phy/ti/phy-j721e-wiz.c:786:1-23: WARNING: Function "for_each_child_of_node" should have of_node_put() before return around line 795. Reported-by: Abaci Robot Signed-off-by: Yang Li Link: https://lore.kernel.org/r/1614244674-66556-1-git-send-email-yang.lee@linux.alibaba.com Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-j721e-wiz.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index 124a3eddd189..3c003f9d0b6f 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -1104,6 +1104,7 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz) ret = of_property_read_u32(subnode, "reg", ®); if (ret) { + of_node_put(subnode); dev_err(dev, "%s: Reading \"reg\" from \"%s\" failed: %d\n", __func__, subnode->name, ret); -- cgit v1.2.3 From 6cb17707aad869de163d7bf42c253caf501be4e2 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 8 Feb 2021 16:02:52 +0100 Subject: phy: marvell: ARMADA375_USBCLUSTER_PHY should not default to y, unconditionally Merely enabling CONFIG_COMPILE_TEST should not enable additional code. To fix this, restrict the automatic enabling of ARMADA375_USBCLUSTER_PHY to MACH_ARMADA_375, and ask the user in case of compile-testing. Fixes: eee47538ec1f2619 ("phy: add support for USB cluster on the Armada 375 SoC") Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20210208150252.424706-1-geert+renesas@glider.be Signed-off-by: Vinod Koul --- drivers/phy/marvell/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/phy/marvell/Kconfig b/drivers/phy/marvell/Kconfig index 9208839019bd..c5651ef70666 100644 --- a/drivers/phy/marvell/Kconfig +++ b/drivers/phy/marvell/Kconfig @@ -3,8 +3,8 @@ # Phy drivers for Marvell platforms # config ARMADA375_USBCLUSTER_PHY - def_bool y - depends on MACH_ARMADA_375 || COMPILE_TEST + bool "Armada 375 USB cluster PHY support" if COMPILE_TEST + default y if MACH_ARMADA_375 depends on OF && HAS_IOMEM select GENERIC_PHY -- cgit v1.2.3 From b976c987511e34a2e9b23545de912a121a9eded5 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 5 Mar 2021 03:49:31 +0000 Subject: phy: ralink: phy-mt7621-pci: fix return value check in mt7621_pci_phy_probe() Fix the return value check which testing the wrong variable in mt7621_pci_phy_probe(). Fixes: d87da32372a0 ("phy: ralink: Add PHY driver for MT7621 PCIe PHY") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Reviewed-by: Sergio Paracuellos Link: https://lore.kernel.org/r/20210305034931.3237558-1-weiyongjun1@huawei.com Signed-off-by: Vinod Koul --- drivers/phy/ralink/phy-mt7621-pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/phy/ralink/phy-mt7621-pci.c b/drivers/phy/ralink/phy-mt7621-pci.c index 84ee2b5c2228..753cb5bab930 100644 --- a/drivers/phy/ralink/phy-mt7621-pci.c +++ b/drivers/phy/ralink/phy-mt7621-pci.c @@ -319,9 +319,9 @@ static int mt7621_pci_phy_probe(struct platform_device *pdev) return PTR_ERR(phy->regmap); phy->phy = devm_phy_create(dev, dev->of_node, &mt7621_pci_phy_ops); - if (IS_ERR(phy)) { + if (IS_ERR(phy->phy)) { dev_err(dev, "failed to create phy\n"); - return PTR_ERR(phy); + return PTR_ERR(phy->phy); } phy_set_drvdata(phy->phy, phy); -- cgit v1.2.3 From 446c200ee3e8f6faf189ef6f25a0f5bb294afae4 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 5 Mar 2021 03:49:33 +0000 Subject: phy: ingenic: Fix a typo in ingenic_usb_phy_probe() Fix the return value check typo which testing the wrong variable in ingenic_usb_phy_probe(). Fixes: 31de313dfdcf ("PHY: Ingenic: Add USB PHY driver using generic PHY framework.") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Acked-by: Paul Cercueil Link: https://lore.kernel.org/r/20210305034933.3240914-1-weiyongjun1@huawei.com Signed-off-by: Vinod Koul --- drivers/phy/ingenic/phy-ingenic-usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/phy/ingenic/phy-ingenic-usb.c b/drivers/phy/ingenic/phy-ingenic-usb.c index ea127b177f46..28c28d816484 100644 --- a/drivers/phy/ingenic/phy-ingenic-usb.c +++ b/drivers/phy/ingenic/phy-ingenic-usb.c @@ -352,8 +352,8 @@ static int ingenic_usb_phy_probe(struct platform_device *pdev) } priv->phy = devm_phy_create(dev, NULL, &ingenic_usb_phy_ops); - if (IS_ERR(priv)) - return PTR_ERR(priv); + if (IS_ERR(priv->phy)) + return PTR_ERR(priv->phy); phy_set_drvdata(priv->phy, priv); -- cgit v1.2.3 From 3f2ec77c954c6707a7caab1be35afe0ccf57135e Mon Sep 17 00:00:00 2001 From: Kuogee Hsieh Date: Tue, 16 Mar 2021 10:12:41 -0700 Subject: phy: qcom-qmp: add hbr3_hbr2 voltage and premphasis swing table Add hbr3_hbr2 voltage and premphasis swing table to support HBR3 link rate. Signed-off-by: Kuogee Hsieh Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/1615914761-12300-1-git-send-email-khsieh@codeaurora.org Fixes: 52e013d0bffa ("phy: qcom-qmp: Add support for DP in USB3+DP combo phy") Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index 9cdebe7f26cb..1c79a713780d 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -3375,6 +3375,20 @@ static void qcom_qmp_phy_dp_aux_init(struct qmp_phy *qphy) qphy->pcs + QSERDES_V3_DP_PHY_AUX_INTERRUPT_MASK); } +static const u8 qmp_dp_v3_pre_emphasis_hbr3_hbr2[4][4] = { + { 0x00, 0x0c, 0x15, 0x1a }, + { 0x02, 0x0e, 0x16, 0xff }, + { 0x02, 0x11, 0xff, 0xff }, + { 0x04, 0xff, 0xff, 0xff } +}; + +static const u8 qmp_dp_v3_voltage_swing_hbr3_hbr2[4][4] = { + { 0x02, 0x12, 0x16, 0x1a }, + { 0x09, 0x19, 0x1f, 0xff }, + { 0x10, 0x1f, 0xff, 0xff }, + { 0x1f, 0xff, 0xff, 0xff } +}; + static const u8 qmp_dp_v3_pre_emphasis_hbr_rbr[4][4] = { { 0x00, 0x0c, 0x14, 0x19 }, { 0x00, 0x0b, 0x12, 0xff }, @@ -3410,8 +3424,13 @@ static void qcom_qmp_phy_configure_dp_tx(struct qmp_phy *qphy) drvr_en = 0x10; } - voltage_swing_cfg = qmp_dp_v3_voltage_swing_hbr_rbr[v_level][p_level]; - pre_emphasis_cfg = qmp_dp_v3_pre_emphasis_hbr_rbr[v_level][p_level]; + if (dp_opts->link_rate <= 2700) { + voltage_swing_cfg = qmp_dp_v3_voltage_swing_hbr_rbr[v_level][p_level]; + pre_emphasis_cfg = qmp_dp_v3_pre_emphasis_hbr_rbr[v_level][p_level]; + } else { + voltage_swing_cfg = qmp_dp_v3_voltage_swing_hbr3_hbr2[v_level][p_level]; + pre_emphasis_cfg = qmp_dp_v3_pre_emphasis_hbr3_hbr2[v_level][p_level]; + } /* TODO: Move check to config check */ if (voltage_swing_cfg == 0xFF && pre_emphasis_cfg == 0xFF) -- cgit v1.2.3 From 5b4f5757f83be34d1428a1ffbb68d4a1966e9aae Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 19 Mar 2021 18:11:16 +0530 Subject: phy: cadence: Sierra: Fix PHY power_on sequence Commit 44d30d622821d ("phy: cadence: Add driver for Sierra PHY") de-asserts PHY_RESET even before the configurations are loaded in phy_init(). However PHY_RESET should be de-asserted only after all the configurations has been initialized, instead of de-asserting in probe. Fix it here. Fixes: 44d30d622821d ("phy: cadence: Add driver for Sierra PHY") Signed-off-by: Kishon Vijay Abraham I Cc: # v5.4+ Reviewed-by: Philipp Zabel Link: https://lore.kernel.org/r/20210319124128.13308-2-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-sierra.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c index 26a0badabe38..19f32ae877b9 100644 --- a/drivers/phy/cadence/phy-cadence-sierra.c +++ b/drivers/phy/cadence/phy-cadence-sierra.c @@ -319,6 +319,12 @@ static int cdns_sierra_phy_on(struct phy *gphy) u32 val; int ret; + ret = reset_control_deassert(sp->phy_rst); + if (ret) { + dev_err(dev, "Failed to take the PHY out of reset\n"); + return ret; + } + /* Take the PHY lane group out of reset */ ret = reset_control_deassert(ins->lnk_rst); if (ret) { @@ -616,7 +622,6 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev) pm_runtime_enable(dev); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - reset_control_deassert(sp->phy_rst); return PTR_ERR_OR_ZERO(phy_provider); put_child: -- cgit v1.2.3 From f7eb147d306ad2efae6837e20d2944f03be42eb4 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 19 Mar 2021 18:11:17 +0530 Subject: phy: ti: j721e-wiz: Invoke wiz_init() before of_platform_device_create() Invoke wiz_init() before configuring anything else in Sierra/Torrent (invoked as part of of_platform_device_create()). wiz_init() resets the SERDES device and any configuration done in the probe() of Sierra/Torrent will be lost. In order to prevent SERDES configuration from getting reset, invoke wiz_init() immediately before invoking of_platform_device_create(). Fixes: 091876cc355d ("phy: ti: j721e-wiz: Add support for WIZ module present in TI J721E SoC") Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Swapnil Jakhade Cc: # v5.10 Link: https://lore.kernel.org/r/20210319124128.13308-3-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-j721e-wiz.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index 3c003f9d0b6f..53d01da2894a 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -1264,27 +1264,24 @@ static int wiz_probe(struct platform_device *pdev) goto err_get_sync; } + ret = wiz_init(wiz); + if (ret) { + dev_err(dev, "WIZ initialization failed\n"); + goto err_wiz_init; + } + serdes_pdev = of_platform_device_create(child_node, NULL, dev); if (!serdes_pdev) { dev_WARN(dev, "Unable to create SERDES platform device\n"); ret = -ENOMEM; - goto err_pdev_create; - } - wiz->serdes_pdev = serdes_pdev; - - ret = wiz_init(wiz); - if (ret) { - dev_err(dev, "WIZ initialization failed\n"); goto err_wiz_init; } + wiz->serdes_pdev = serdes_pdev; of_node_put(child_node); return 0; err_wiz_init: - of_platform_device_destroy(&serdes_pdev->dev, NULL); - -err_pdev_create: wiz_clock_cleanup(wiz, node); err_get_sync: -- cgit v1.2.3 From 03ada5a37c3a98396026c98015d18337c88b09b3 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 19 Mar 2021 18:11:18 +0530 Subject: phy: cadence: Sierra: Create PHY only for "phy" or "link" sub-nodes Cadence Sierra PHY driver registers PHY using devm_phy_create() for all sub-nodes of Sierra device tree node. However Sierra device tree node can have sub-nodes for the various clocks in addtion to the PHY. Use devm_phy_create() only for nodes with name "phy" (or "link" for old device tree) which represent the actual PHY. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Swapnil Jakhade Link: https://lore.kernel.org/r/20210319124128.13308-4-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-sierra.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c index 19f32ae877b9..f7ba0ed416bc 100644 --- a/drivers/phy/cadence/phy-cadence-sierra.c +++ b/drivers/phy/cadence/phy-cadence-sierra.c @@ -577,6 +577,10 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev) for_each_available_child_of_node(dn, child) { struct phy *gphy; + if (!(of_node_name_eq(child, "phy") || + of_node_name_eq(child, "link"))) + continue; + sp->phys[node].lnk_rst = of_reset_control_array_get_exclusive(child); -- cgit v1.2.3 From 3fb9545657f7cac262eb5f08712dbc8ebdba5096 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 19 Mar 2021 18:11:19 +0530 Subject: phy: ti: j721e-wiz: Get PHY properties only for "phy" or "link" subnode "serdes" node (child node of WIZ) can have sub-nodes for representing links or it can have sub-nodes for representing the various clocks within the serdes. Instead of trying to read "reg" from every child node used for assigning "lane_phy_type", read only if the child node's name is "phy" or "link" subnode. Ideally all PHY dt nodes should have node name as "phy", however existing devicetree used "link" as subnode. So in order to maintain old DT compatibility get PHY properties for "phy" or "link" subnode. Signed-off-by: Kishon Vijay Abraham I Link: https://lore.kernel.org/r/20210319124128.13308-5-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-j721e-wiz.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index 53d01da2894a..02c47b2df01f 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -1102,6 +1102,10 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz) u32 reg, num_lanes = 1, phy_type = PHY_NONE; int ret, i; + if (!(of_node_name_eq(subnode, "phy") || + of_node_name_eq(subnode, "link"))) + continue; + ret = of_property_read_u32(subnode, "reg", ®); if (ret) { of_node_put(subnode); -- cgit v1.2.3 From 7e016cbc526dd3b25837a2f628801d02cbc801dd Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 19 Mar 2021 18:11:20 +0530 Subject: phy: cadence: Sierra: Move all clk_get_*() to a separate function No functional change. Group all devm_clk_get_optional() to a separate function. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Swapnil Jakhade Link: https://lore.kernel.org/r/20210319124128.13308-6-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-sierra.c | 57 ++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c index f7ba0ed416bc..7bf1b4c7774a 100644 --- a/drivers/phy/cadence/phy-cadence-sierra.c +++ b/drivers/phy/cadence/phy-cadence-sierra.c @@ -477,6 +477,38 @@ static int cdns_regmap_init_blocks(struct cdns_sierra_phy *sp, return 0; } +static int cdns_sierra_phy_get_clocks(struct cdns_sierra_phy *sp, + struct device *dev) +{ + struct clk *clk; + int ret; + + clk = devm_clk_get_optional(dev, "phy_clk"); + if (IS_ERR(clk)) { + dev_err(dev, "failed to get clock phy_clk\n"); + return PTR_ERR(clk); + } + sp->clk = clk; + + clk = devm_clk_get_optional(dev, "cmn_refclk_dig_div"); + if (IS_ERR(clk)) { + dev_err(dev, "cmn_refclk_dig_div clock not found\n"); + ret = PTR_ERR(clk); + return ret; + } + sp->cmn_refclk_dig_div = clk; + + clk = devm_clk_get_optional(dev, "cmn_refclk1_dig_div"); + if (IS_ERR(clk)) { + dev_err(dev, "cmn_refclk1_dig_div clock not found\n"); + ret = PTR_ERR(clk); + return ret; + } + sp->cmn_refclk1_dig_div = clk; + + return 0; +} + static int cdns_sierra_phy_probe(struct platform_device *pdev) { struct cdns_sierra_phy *sp; @@ -487,7 +519,6 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev) unsigned int id_value; int i, ret, node = 0; void __iomem *base; - struct clk *clk; struct device_node *dn = dev->of_node, *child; if (of_get_child_count(dn) == 0) @@ -524,11 +555,9 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev) platform_set_drvdata(pdev, sp); - sp->clk = devm_clk_get_optional(dev, "phy_clk"); - if (IS_ERR(sp->clk)) { - dev_err(dev, "failed to get clock phy_clk\n"); - return PTR_ERR(sp->clk); - } + ret = cdns_sierra_phy_get_clocks(sp, dev); + if (ret) + return ret; sp->phy_rst = devm_reset_control_get(dev, "sierra_reset"); if (IS_ERR(sp->phy_rst)) { @@ -542,22 +571,6 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev) return PTR_ERR(sp->apb_rst); } - clk = devm_clk_get_optional(dev, "cmn_refclk_dig_div"); - if (IS_ERR(clk)) { - dev_err(dev, "cmn_refclk_dig_div clock not found\n"); - ret = PTR_ERR(clk); - return ret; - } - sp->cmn_refclk_dig_div = clk; - - clk = devm_clk_get_optional(dev, "cmn_refclk1_dig_div"); - if (IS_ERR(clk)) { - dev_err(dev, "cmn_refclk1_dig_div clock not found\n"); - ret = PTR_ERR(clk); - return ret; - } - sp->cmn_refclk1_dig_div = clk; - ret = clk_prepare_enable(sp->clk); if (ret) return ret; -- cgit v1.2.3 From 1d5f40e021f3c047119d2745ae542700871a0833 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 19 Mar 2021 18:11:21 +0530 Subject: phy: cadence: Sierra: Move all reset_control_get*() to a separate function No functional change. Group devm_reset_control_get() and devm_reset_control_get_optional() to a separate function. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Philipp Zabel Link: https://lore.kernel.org/r/20210319124128.13308-7-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-sierra.c | 36 ++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c index 7bf1b4c7774a..935f165404e4 100644 --- a/drivers/phy/cadence/phy-cadence-sierra.c +++ b/drivers/phy/cadence/phy-cadence-sierra.c @@ -509,6 +509,28 @@ static int cdns_sierra_phy_get_clocks(struct cdns_sierra_phy *sp, return 0; } +static int cdns_sierra_phy_get_resets(struct cdns_sierra_phy *sp, + struct device *dev) +{ + struct reset_control *rst; + + rst = devm_reset_control_get(dev, "sierra_reset"); + if (IS_ERR(rst)) { + dev_err(dev, "failed to get reset\n"); + return PTR_ERR(rst); + } + sp->phy_rst = rst; + + rst = devm_reset_control_get_optional(dev, "sierra_apb"); + if (IS_ERR(rst)) { + dev_err(dev, "failed to get apb reset\n"); + return PTR_ERR(rst); + } + sp->apb_rst = rst; + + return 0; +} + static int cdns_sierra_phy_probe(struct platform_device *pdev) { struct cdns_sierra_phy *sp; @@ -559,17 +581,9 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev) if (ret) return ret; - sp->phy_rst = devm_reset_control_get(dev, "sierra_reset"); - if (IS_ERR(sp->phy_rst)) { - dev_err(dev, "failed to get reset\n"); - return PTR_ERR(sp->phy_rst); - } - - sp->apb_rst = devm_reset_control_get_optional(dev, "sierra_apb"); - if (IS_ERR(sp->apb_rst)) { - dev_err(dev, "failed to get apb reset\n"); - return PTR_ERR(sp->apb_rst); - } + ret = cdns_sierra_phy_get_resets(sp, dev); + if (ret) + return ret; ret = clk_prepare_enable(sp->clk); if (ret) -- cgit v1.2.3 From 15b0b82d51a39334da37b718bd014f4460117326 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 19 Mar 2021 18:11:22 +0530 Subject: phy: cadence: Sierra: Explicitly request exclusive reset control No functional change. Since the reset controls obtained in Sierra is exclusively used by the Sierra device, use exclusive reset control request API calls. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Philipp Zabel Link: https://lore.kernel.org/r/20210319124128.13308-8-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-sierra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c index 935f165404e4..44c52a0842dc 100644 --- a/drivers/phy/cadence/phy-cadence-sierra.c +++ b/drivers/phy/cadence/phy-cadence-sierra.c @@ -514,14 +514,14 @@ static int cdns_sierra_phy_get_resets(struct cdns_sierra_phy *sp, { struct reset_control *rst; - rst = devm_reset_control_get(dev, "sierra_reset"); + rst = devm_reset_control_get_exclusive(dev, "sierra_reset"); if (IS_ERR(rst)) { dev_err(dev, "failed to get reset\n"); return PTR_ERR(rst); } sp->phy_rst = rst; - rst = devm_reset_control_get_optional(dev, "sierra_apb"); + rst = devm_reset_control_get_optional_exclusive(dev, "sierra_apb"); if (IS_ERR(rst)) { dev_err(dev, "failed to get apb reset\n"); return PTR_ERR(rst); -- cgit v1.2.3 From fd7abc3c5b8769e22a3759b0ea1893e18aa2caff Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 19 Mar 2021 18:11:23 +0530 Subject: phy: cadence-torrent: Use a common header file for Cadence SERDES No functional change. In order to have a single header file for all Cadence SERDES move phy-cadence-torrent.h to phy-cadence.h. This is in preparation for adding Cadence Sierra SERDES specific macros. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Swapnil Jakhade Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210319124128.13308-9-kishon@ti.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/phy-cadence-torrent.yaml | 2 +- drivers/phy/cadence/phy-cadence-torrent.c | 2 +- include/dt-bindings/phy/phy-cadence-torrent.h | 15 --------------- include/dt-bindings/phy/phy-cadence.h | 16 ++++++++++++++++ 4 files changed, 18 insertions(+), 17 deletions(-) delete mode 100644 include/dt-bindings/phy/phy-cadence-torrent.h create mode 100644 include/dt-bindings/phy/phy-cadence.h diff --git a/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml b/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml index 4608599a31d8..01dcd14e7b2a 100644 --- a/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml +++ b/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml @@ -184,7 +184,7 @@ examples: }; - | #include - #include + #include bus { #address-cells = <2>; diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index 95160da3e667..3fdab0d288c4 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -7,7 +7,7 @@ */ #include -#include +#include #include #include #include diff --git a/include/dt-bindings/phy/phy-cadence-torrent.h b/include/dt-bindings/phy/phy-cadence-torrent.h deleted file mode 100644 index 3c92c6192493..000000000000 --- a/include/dt-bindings/phy/phy-cadence-torrent.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * This header provides constants for Cadence Torrent SERDES. - */ - -#ifndef _DT_BINDINGS_TORRENT_SERDES_H -#define _DT_BINDINGS_TORRENT_SERDES_H - -#define TORRENT_SERDES_NO_SSC 0 -#define TORRENT_SERDES_EXTERNAL_SSC 1 -#define TORRENT_SERDES_INTERNAL_SSC 2 - -#define CDNS_TORRENT_REFCLK_DRIVER 0 - -#endif /* _DT_BINDINGS_TORRENT_SERDES_H */ diff --git a/include/dt-bindings/phy/phy-cadence.h b/include/dt-bindings/phy/phy-cadence.h new file mode 100644 index 000000000000..4a5ea52a856f --- /dev/null +++ b/include/dt-bindings/phy/phy-cadence.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This header provides constants for Cadence SERDES. + */ + +#ifndef _DT_BINDINGS_CADENCE_SERDES_H +#define _DT_BINDINGS_CADENCE_SERDES_H + +/* Torrent */ +#define TORRENT_SERDES_NO_SSC 0 +#define TORRENT_SERDES_EXTERNAL_SSC 1 +#define TORRENT_SERDES_INTERNAL_SSC 2 + +#define CDNS_TORRENT_REFCLK_DRIVER 0 + +#endif /* _DT_BINDINGS_CADENCE_SERDES_H */ -- cgit v1.2.3 From a0c30cd783b9dfb319ab2d88bb02434b4a815f79 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 19 Mar 2021 18:11:24 +0530 Subject: phy: cadence: Sierra: Add array of input clocks in "struct cdns_sierra_phy" Instead of having separate structure members for each input clock, add an array for the input clocks within "struct cdns_sierra_phy". This is in preparation for adding more input clocks required for supporting additional clock combination. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Swapnil Jakhade Link: https://lore.kernel.org/r/20210319124128.13308-10-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-sierra.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c index 44c52a0842dc..a45278c30948 100644 --- a/drivers/phy/cadence/phy-cadence-sierra.c +++ b/drivers/phy/cadence/phy-cadence-sierra.c @@ -144,6 +144,13 @@ #define SIERRA_MAX_LANES 16 #define PLL_LOCK_TIME 100000 +#define CDNS_SIERRA_INPUT_CLOCKS 3 +enum cdns_sierra_clock_input { + PHY_CLK, + CMN_REFCLK_DIG_DIV, + CMN_REFCLK1_DIG_DIV, +}; + static const struct reg_field macro_id_type = REG_FIELD(SIERRA_MACRO_ID_REG, 0, 15); static const struct reg_field phy_pll_cfg_1 = @@ -197,9 +204,7 @@ struct cdns_sierra_phy { struct regmap_field *macro_id_type; struct regmap_field *phy_pll_cfg_1; struct regmap_field *pllctrl_lock[SIERRA_MAX_LANES]; - struct clk *clk; - struct clk *cmn_refclk_dig_div; - struct clk *cmn_refclk1_dig_div; + struct clk *input_clks[CDNS_SIERRA_INPUT_CLOCKS]; int nsubnodes; u32 num_lanes; bool autoconf; @@ -281,8 +286,8 @@ static int cdns_sierra_phy_init(struct phy *gphy) if (phy->autoconf) return 0; - clk_set_rate(phy->cmn_refclk_dig_div, 25000000); - clk_set_rate(phy->cmn_refclk1_dig_div, 25000000); + clk_set_rate(phy->input_clks[CMN_REFCLK_DIG_DIV], 25000000); + clk_set_rate(phy->input_clks[CMN_REFCLK1_DIG_DIV], 25000000); if (ins->phy_type == PHY_TYPE_PCIE) { num_cmn_regs = phy->init_data->pcie_cmn_regs; num_ln_regs = phy->init_data->pcie_ln_regs; @@ -488,7 +493,7 @@ static int cdns_sierra_phy_get_clocks(struct cdns_sierra_phy *sp, dev_err(dev, "failed to get clock phy_clk\n"); return PTR_ERR(clk); } - sp->clk = clk; + sp->input_clks[PHY_CLK] = clk; clk = devm_clk_get_optional(dev, "cmn_refclk_dig_div"); if (IS_ERR(clk)) { @@ -496,7 +501,7 @@ static int cdns_sierra_phy_get_clocks(struct cdns_sierra_phy *sp, ret = PTR_ERR(clk); return ret; } - sp->cmn_refclk_dig_div = clk; + sp->input_clks[CMN_REFCLK_DIG_DIV] = clk; clk = devm_clk_get_optional(dev, "cmn_refclk1_dig_div"); if (IS_ERR(clk)) { @@ -504,7 +509,7 @@ static int cdns_sierra_phy_get_clocks(struct cdns_sierra_phy *sp, ret = PTR_ERR(clk); return ret; } - sp->cmn_refclk1_dig_div = clk; + sp->input_clks[CMN_REFCLK1_DIG_DIV] = clk; return 0; } @@ -585,7 +590,7 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev) if (ret) return ret; - ret = clk_prepare_enable(sp->clk); + ret = clk_prepare_enable(sp->input_clks[PHY_CLK]); if (ret) return ret; @@ -662,7 +667,7 @@ put_child2: reset_control_put(sp->phys[i].lnk_rst); of_node_put(child); clk_disable: - clk_disable_unprepare(sp->clk); + clk_disable_unprepare(sp->input_clks[PHY_CLK]); reset_control_assert(sp->apb_rst); return ret; } -- cgit v1.2.3 From 29c2d02adbc817e91f078ace1c625c34928bf73a Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 19 Mar 2021 18:11:25 +0530 Subject: phy: cadence: Sierra: Add missing clk_disable_unprepare() in .remove callback commit 44d30d622821 ("phy: cadence: Add driver for Sierra PHY") enabled the clock in probe and failed to disable in remove callback. Add missing clk_disable_unprepare() in cdns_sierra_phy_remove(). Fixes: 44d30d622821 ("phy: cadence: Add driver for Sierra PHY") Signed-off-by: Kishon Vijay Abraham I Link: https://lore.kernel.org/r/20210319124128.13308-11-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-sierra.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c index a45278c30948..ac32b7b0289f 100644 --- a/drivers/phy/cadence/phy-cadence-sierra.c +++ b/drivers/phy/cadence/phy-cadence-sierra.c @@ -689,6 +689,9 @@ static int cdns_sierra_phy_remove(struct platform_device *pdev) reset_control_assert(phy->phys[i].lnk_rst); reset_control_put(phy->phys[i].lnk_rst); } + + clk_disable_unprepare(phy->input_clks[PHY_CLK]); + return 0; } -- cgit v1.2.3 From db7a346405dc71be0c4ad7f39dd7978d4d20dee0 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 19 Mar 2021 18:11:26 +0530 Subject: dt-bindings: phy: phy-cadence-sierra: Add binding to model Sierra as clock provider Add #clock-cells binding to model Sierra as clock provider and include clock IDs for PLL_CMNLC and PLL_CMNLC1. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210319124128.13308-12-kishon@ti.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/phy-cadence-sierra.yaml | 17 ++++++++++++++++- include/dt-bindings/phy/phy-cadence.h | 4 ++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml b/Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml index d210843863df..84383e2e0b34 100644 --- a/Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml +++ b/Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml @@ -26,6 +26,9 @@ properties: '#size-cells': const: 0 + '#clock-cells': + const: 1 + resets: minItems: 1 maxItems: 2 @@ -49,12 +52,24 @@ properties: const: serdes clocks: - maxItems: 2 + minItems: 2 + maxItems: 4 clock-names: + minItems: 2 items: - const: cmn_refclk_dig_div - const: cmn_refclk1_dig_div + - const: pll0_refclk + - const: pll1_refclk + + assigned-clocks: + minItems: 1 + maxItems: 2 + + assigned-clock-parents: + minItems: 1 + maxItems: 2 cdns,autoconf: type: boolean diff --git a/include/dt-bindings/phy/phy-cadence.h b/include/dt-bindings/phy/phy-cadence.h index 4a5ea52a856f..4652bcb86265 100644 --- a/include/dt-bindings/phy/phy-cadence.h +++ b/include/dt-bindings/phy/phy-cadence.h @@ -13,4 +13,8 @@ #define CDNS_TORRENT_REFCLK_DRIVER 0 +/* Sierra */ +#define CDNS_SIERRA_PLL_CMNLC 0 +#define CDNS_SIERRA_PLL_CMNLC1 1 + #endif /* _DT_BINDINGS_CADENCE_SERDES_H */ -- cgit v1.2.3 From 28081b72859f0fa3d5b56cfd84b2f5ba578765d2 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 19 Mar 2021 18:11:27 +0530 Subject: phy: cadence: Sierra: Model PLL_CMNLC and PLL_CMNLC1 as clocks (mux clocks) Sierra has two PLLs, PLL_CMNLC and PLL_CMNLC1 and each of these PLLs has two inputs, plllc_refclk (input from pll0_refclk) and refrcv (input from pll1_refclk). Model PLL_CMNLC and PLL_CMNLC1 as clocks so that it's possible to select one of these two inputs from device tree. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Swapnil Jakhade Link: https://lore.kernel.org/r/20210319124128.13308-13-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/Kconfig | 1 + drivers/phy/cadence/phy-cadence-sierra.c | 267 ++++++++++++++++++++++++++++++- 2 files changed, 265 insertions(+), 3 deletions(-) diff --git a/drivers/phy/cadence/Kconfig b/drivers/phy/cadence/Kconfig index 27e9d6c377e5..a62910ff5591 100644 --- a/drivers/phy/cadence/Kconfig +++ b/drivers/phy/cadence/Kconfig @@ -25,6 +25,7 @@ config PHY_CADENCE_DPHY config PHY_CADENCE_SIERRA tristate "Cadence Sierra PHY Driver" depends on OF && HAS_IOMEM && RESET_CONTROLLER + depends on COMMON_CLK select GENERIC_PHY help Enable this to support the Cadence Sierra PHY driver diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c index ac32b7b0289f..039ca10db59d 100644 --- a/drivers/phy/cadence/phy-cadence-sierra.c +++ b/drivers/phy/cadence/phy-cadence-sierra.c @@ -7,6 +7,7 @@ * */ #include +#include #include #include #include @@ -20,10 +21,12 @@ #include #include #include +#include /* PHY register offsets */ #define SIERRA_COMMON_CDB_OFFSET 0x0 #define SIERRA_MACRO_ID_REG 0x0 +#define SIERRA_CMN_PLLLC_GEN_PREG 0x42 #define SIERRA_CMN_PLLLC_MODE_PREG 0x48 #define SIERRA_CMN_PLLLC_LF_COEFF_MODE1_PREG 0x49 #define SIERRA_CMN_PLLLC_LF_COEFF_MODE0_PREG 0x4A @@ -31,6 +34,9 @@ #define SIERRA_CMN_PLLLC_BWCAL_MODE1_PREG 0x4F #define SIERRA_CMN_PLLLC_BWCAL_MODE0_PREG 0x50 #define SIERRA_CMN_PLLLC_SS_TIME_STEPSIZE_MODE_PREG 0x62 +#define SIERRA_CMN_REFRCV_PREG 0x98 +#define SIERRA_CMN_REFRCV1_PREG 0xB8 +#define SIERRA_CMN_PLLLC1_GEN_PREG 0xC2 #define SIERRA_LANE_CDB_OFFSET(ln, block_offset, reg_offset) \ ((0x4000 << (block_offset)) + \ @@ -144,13 +150,19 @@ #define SIERRA_MAX_LANES 16 #define PLL_LOCK_TIME 100000 -#define CDNS_SIERRA_INPUT_CLOCKS 3 +#define CDNS_SIERRA_OUTPUT_CLOCKS 2 +#define CDNS_SIERRA_INPUT_CLOCKS 5 enum cdns_sierra_clock_input { PHY_CLK, CMN_REFCLK_DIG_DIV, CMN_REFCLK1_DIG_DIV, + PLL0_REFCLK, + PLL1_REFCLK, }; +#define SIERRA_NUM_CMN_PLLC 2 +#define SIERRA_NUM_CMN_PLLC_PARENTS 2 + static const struct reg_field macro_id_type = REG_FIELD(SIERRA_MACRO_ID_REG, 0, 15); static const struct reg_field phy_pll_cfg_1 = @@ -158,6 +170,53 @@ static const struct reg_field phy_pll_cfg_1 = static const struct reg_field pllctrl_lock = REG_FIELD(SIERRA_PLLCTRL_STATUS_PREG, 0, 0); +static const char * const clk_names[] = { + [CDNS_SIERRA_PLL_CMNLC] = "pll_cmnlc", + [CDNS_SIERRA_PLL_CMNLC1] = "pll_cmnlc1", +}; + +enum cdns_sierra_cmn_plllc { + CMN_PLLLC, + CMN_PLLLC1, +}; + +struct cdns_sierra_pll_mux_reg_fields { + struct reg_field pfdclk_sel_preg; + struct reg_field plllc1en_field; + struct reg_field termen_field; +}; + +static const struct cdns_sierra_pll_mux_reg_fields cmn_plllc_pfdclk1_sel_preg[] = { + [CMN_PLLLC] = { + .pfdclk_sel_preg = REG_FIELD(SIERRA_CMN_PLLLC_GEN_PREG, 1, 1), + .plllc1en_field = REG_FIELD(SIERRA_CMN_REFRCV1_PREG, 8, 8), + .termen_field = REG_FIELD(SIERRA_CMN_REFRCV1_PREG, 0, 0), + }, + [CMN_PLLLC1] = { + .pfdclk_sel_preg = REG_FIELD(SIERRA_CMN_PLLLC1_GEN_PREG, 1, 1), + .plllc1en_field = REG_FIELD(SIERRA_CMN_REFRCV_PREG, 8, 8), + .termen_field = REG_FIELD(SIERRA_CMN_REFRCV_PREG, 0, 0), + }, +}; + +struct cdns_sierra_pll_mux { + struct clk_hw hw; + struct regmap_field *pfdclk_sel_preg; + struct regmap_field *plllc1en_field; + struct regmap_field *termen_field; + struct clk_init_data clk_data; +}; + +#define to_cdns_sierra_pll_mux(_hw) \ + container_of(_hw, struct cdns_sierra_pll_mux, hw) + +static const int pll_mux_parent_index[][SIERRA_NUM_CMN_PLLC_PARENTS] = { + [CMN_PLLLC] = { PLL0_REFCLK, PLL1_REFCLK }, + [CMN_PLLLC1] = { PLL1_REFCLK, PLL0_REFCLK }, +}; + +static u32 cdns_sierra_pll_mux_table[] = { 0, 1 }; + struct cdns_sierra_inst { struct phy *phy; u32 phy_type; @@ -204,10 +263,15 @@ struct cdns_sierra_phy { struct regmap_field *macro_id_type; struct regmap_field *phy_pll_cfg_1; struct regmap_field *pllctrl_lock[SIERRA_MAX_LANES]; + struct regmap_field *cmn_refrcv_refclk_plllc1en_preg[SIERRA_NUM_CMN_PLLC]; + struct regmap_field *cmn_refrcv_refclk_termen_preg[SIERRA_NUM_CMN_PLLC]; + struct regmap_field *cmn_plllc_pfdclk1_sel_preg[SIERRA_NUM_CMN_PLLC]; struct clk *input_clks[CDNS_SIERRA_INPUT_CLOCKS]; int nsubnodes; u32 num_lanes; bool autoconf; + struct clk_onecell_data clk_data; + struct clk *output_clks[CDNS_SIERRA_OUTPUT_CLOCKS]; }; static int cdns_regmap_write(void *context, unsigned int reg, unsigned int val) @@ -369,6 +433,153 @@ static const struct phy_ops ops = { .owner = THIS_MODULE, }; +static u8 cdns_sierra_pll_mux_get_parent(struct clk_hw *hw) +{ + struct cdns_sierra_pll_mux *mux = to_cdns_sierra_pll_mux(hw); + struct regmap_field *field = mux->pfdclk_sel_preg; + unsigned int val; + + regmap_field_read(field, &val); + return clk_mux_val_to_index(hw, cdns_sierra_pll_mux_table, 0, val); +} + +static int cdns_sierra_pll_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct cdns_sierra_pll_mux *mux = to_cdns_sierra_pll_mux(hw); + struct regmap_field *plllc1en_field = mux->plllc1en_field; + struct regmap_field *termen_field = mux->termen_field; + struct regmap_field *field = mux->pfdclk_sel_preg; + int val, ret; + + ret = regmap_field_write(plllc1en_field, 0); + ret |= regmap_field_write(termen_field, 0); + if (index == 1) { + ret |= regmap_field_write(plllc1en_field, 1); + ret |= regmap_field_write(termen_field, 1); + } + + val = cdns_sierra_pll_mux_table[index]; + ret |= regmap_field_write(field, val); + + return ret; +} + +static const struct clk_ops cdns_sierra_pll_mux_ops = { + .set_parent = cdns_sierra_pll_mux_set_parent, + .get_parent = cdns_sierra_pll_mux_get_parent, +}; + +static int cdns_sierra_pll_mux_register(struct cdns_sierra_phy *sp, + struct regmap_field *pfdclk1_sel_field, + struct regmap_field *plllc1en_field, + struct regmap_field *termen_field, + int clk_index) +{ + struct cdns_sierra_pll_mux *mux; + struct device *dev = sp->dev; + struct clk_init_data *init; + const char **parent_names; + unsigned int num_parents; + char clk_name[100]; + struct clk *clk; + int i; + + mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); + if (!mux) + return -ENOMEM; + + num_parents = SIERRA_NUM_CMN_PLLC_PARENTS; + parent_names = devm_kzalloc(dev, (sizeof(char *) * num_parents), GFP_KERNEL); + if (!parent_names) + return -ENOMEM; + + for (i = 0; i < num_parents; i++) { + clk = sp->input_clks[pll_mux_parent_index[clk_index][i]]; + if (IS_ERR_OR_NULL(clk)) { + dev_err(dev, "No parent clock for derived_refclk\n"); + return PTR_ERR(clk); + } + parent_names[i] = __clk_get_name(clk); + } + + snprintf(clk_name, sizeof(clk_name), "%s_%s", dev_name(dev), clk_names[clk_index]); + + init = &mux->clk_data; + + init->ops = &cdns_sierra_pll_mux_ops; + init->flags = CLK_SET_RATE_NO_REPARENT; + init->parent_names = parent_names; + init->num_parents = num_parents; + init->name = clk_name; + + mux->pfdclk_sel_preg = pfdclk1_sel_field; + mux->plllc1en_field = plllc1en_field; + mux->termen_field = termen_field; + mux->hw.init = init; + + clk = devm_clk_register(dev, &mux->hw); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + sp->output_clks[clk_index] = clk; + + return 0; +} + +static int cdns_sierra_phy_register_pll_mux(struct cdns_sierra_phy *sp) +{ + struct regmap_field *pfdclk1_sel_field; + struct regmap_field *plllc1en_field; + struct regmap_field *termen_field; + struct device *dev = sp->dev; + int ret = 0, i, clk_index; + + clk_index = CDNS_SIERRA_PLL_CMNLC; + for (i = 0; i < SIERRA_NUM_CMN_PLLC; i++, clk_index++) { + pfdclk1_sel_field = sp->cmn_plllc_pfdclk1_sel_preg[i]; + plllc1en_field = sp->cmn_refrcv_refclk_plllc1en_preg[i]; + termen_field = sp->cmn_refrcv_refclk_termen_preg[i]; + + ret = cdns_sierra_pll_mux_register(sp, pfdclk1_sel_field, plllc1en_field, + termen_field, clk_index); + if (ret) { + dev_err(dev, "Fail to register cmn plllc mux\n"); + return ret; + } + } + + return 0; +} + +static void cdns_sierra_clk_unregister(struct cdns_sierra_phy *sp) +{ + struct device *dev = sp->dev; + struct device_node *node = dev->of_node; + + of_clk_del_provider(node); +} + +static int cdns_sierra_clk_register(struct cdns_sierra_phy *sp) +{ + struct device *dev = sp->dev; + struct device_node *node = dev->of_node; + int ret; + + ret = cdns_sierra_phy_register_pll_mux(sp); + if (ret) { + dev_err(dev, "Failed to pll mux clocks\n"); + return ret; + } + + sp->clk_data.clks = sp->output_clks; + sp->clk_data.clk_num = CDNS_SIERRA_OUTPUT_CLOCKS; + ret = of_clk_add_provider(node, of_clk_src_onecell_get, &sp->clk_data); + if (ret) + dev_err(dev, "Failed to add clock provider: %s\n", node->name); + + return ret; +} + static int cdns_sierra_get_optional(struct cdns_sierra_inst *inst, struct device_node *child) { @@ -407,6 +618,7 @@ static int cdns_regfield_init(struct cdns_sierra_phy *sp) { struct device *dev = sp->dev; struct regmap_field *field; + struct reg_field reg_field; struct regmap *regmap; int i; @@ -418,6 +630,32 @@ static int cdns_regfield_init(struct cdns_sierra_phy *sp) } sp->macro_id_type = field; + for (i = 0; i < SIERRA_NUM_CMN_PLLC; i++) { + reg_field = cmn_plllc_pfdclk1_sel_preg[i].pfdclk_sel_preg; + field = devm_regmap_field_alloc(dev, regmap, reg_field); + if (IS_ERR(field)) { + dev_err(dev, "PLLLC%d_PFDCLK1_SEL failed\n", i); + return PTR_ERR(field); + } + sp->cmn_plllc_pfdclk1_sel_preg[i] = field; + + reg_field = cmn_plllc_pfdclk1_sel_preg[i].plllc1en_field; + field = devm_regmap_field_alloc(dev, regmap, reg_field); + if (IS_ERR(field)) { + dev_err(dev, "REFRCV%d_REFCLK_PLLLC1EN failed\n", i); + return PTR_ERR(field); + } + sp->cmn_refrcv_refclk_plllc1en_preg[i] = field; + + reg_field = cmn_plllc_pfdclk1_sel_preg[i].termen_field; + field = devm_regmap_field_alloc(dev, regmap, reg_field); + if (IS_ERR(field)) { + dev_err(dev, "REFRCV%d_REFCLK_TERMEN failed\n", i); + return PTR_ERR(field); + } + sp->cmn_refrcv_refclk_termen_preg[i] = field; + } + regmap = sp->regmap_phy_config_ctrl; field = devm_regmap_field_alloc(dev, regmap, phy_pll_cfg_1); if (IS_ERR(field)) { @@ -511,6 +749,22 @@ static int cdns_sierra_phy_get_clocks(struct cdns_sierra_phy *sp, } sp->input_clks[CMN_REFCLK1_DIG_DIV] = clk; + clk = devm_clk_get_optional(dev, "pll0_refclk"); + if (IS_ERR(clk)) { + dev_err(dev, "pll0_refclk clock not found\n"); + ret = PTR_ERR(clk); + return ret; + } + sp->input_clks[PLL0_REFCLK] = clk; + + clk = devm_clk_get_optional(dev, "pll1_refclk"); + if (IS_ERR(clk)) { + dev_err(dev, "pll1_refclk clock not found\n"); + ret = PTR_ERR(clk); + return ret; + } + sp->input_clks[PLL1_REFCLK] = clk; + return 0; } @@ -586,13 +840,17 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev) if (ret) return ret; - ret = cdns_sierra_phy_get_resets(sp, dev); + ret = cdns_sierra_clk_register(sp); if (ret) return ret; + ret = cdns_sierra_phy_get_resets(sp, dev); + if (ret) + goto unregister_clk; + ret = clk_prepare_enable(sp->input_clks[PHY_CLK]); if (ret) - return ret; + goto unregister_clk; /* Enable APB */ reset_control_deassert(sp->apb_rst); @@ -669,6 +927,8 @@ put_child2: clk_disable: clk_disable_unprepare(sp->input_clks[PHY_CLK]); reset_control_assert(sp->apb_rst); +unregister_clk: + cdns_sierra_clk_unregister(sp); return ret; } @@ -691,6 +951,7 @@ static int cdns_sierra_phy_remove(struct platform_device *pdev) } clk_disable_unprepare(phy->input_clks[PHY_CLK]); + cdns_sierra_clk_unregister(phy); return 0; } -- cgit v1.2.3 From 1436ec309e6251b372b757bfacf88f5954b8f3fd Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 19 Mar 2021 18:11:28 +0530 Subject: phy: cadence: Sierra: Enable pll_cmnlc and pll_cmnlc1 clocks Get pll_cmnlc and pll_cmnlc1 optional clocks and enable them. This will enable REFRCV/1 in case the pll_cmnlc/1 takes input from REFRCV/1 respectively. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Swapnil Jakhade Link: https://lore.kernel.org/r/20210319124128.13308-14-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-sierra.c | 40 +++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c index 039ca10db59d..5c68e31c5939 100644 --- a/drivers/phy/cadence/phy-cadence-sierra.c +++ b/drivers/phy/cadence/phy-cadence-sierra.c @@ -768,6 +768,40 @@ static int cdns_sierra_phy_get_clocks(struct cdns_sierra_phy *sp, return 0; } +static int cdns_sierra_phy_enable_clocks(struct cdns_sierra_phy *sp) +{ + int ret; + + ret = clk_prepare_enable(sp->input_clks[PHY_CLK]); + if (ret) + return ret; + + ret = clk_prepare_enable(sp->output_clks[CDNS_SIERRA_PLL_CMNLC]); + if (ret) + goto err_pll_cmnlc; + + ret = clk_prepare_enable(sp->output_clks[CDNS_SIERRA_PLL_CMNLC1]); + if (ret) + goto err_pll_cmnlc1; + + return 0; + +err_pll_cmnlc1: + clk_disable_unprepare(sp->output_clks[CDNS_SIERRA_PLL_CMNLC]); + +err_pll_cmnlc: + clk_disable_unprepare(sp->input_clks[PHY_CLK]); + + return ret; +} + +static void cdns_sierra_phy_disable_clocks(struct cdns_sierra_phy *sp) +{ + clk_disable_unprepare(sp->output_clks[CDNS_SIERRA_PLL_CMNLC1]); + clk_disable_unprepare(sp->output_clks[CDNS_SIERRA_PLL_CMNLC]); + clk_disable_unprepare(sp->input_clks[PHY_CLK]); +} + static int cdns_sierra_phy_get_resets(struct cdns_sierra_phy *sp, struct device *dev) { @@ -848,7 +882,7 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev) if (ret) goto unregister_clk; - ret = clk_prepare_enable(sp->input_clks[PHY_CLK]); + ret = cdns_sierra_phy_enable_clocks(sp); if (ret) goto unregister_clk; @@ -925,7 +959,7 @@ put_child2: reset_control_put(sp->phys[i].lnk_rst); of_node_put(child); clk_disable: - clk_disable_unprepare(sp->input_clks[PHY_CLK]); + cdns_sierra_phy_disable_clocks(sp); reset_control_assert(sp->apb_rst); unregister_clk: cdns_sierra_clk_unregister(sp); @@ -941,6 +975,7 @@ static int cdns_sierra_phy_remove(struct platform_device *pdev) reset_control_assert(phy->apb_rst); pm_runtime_disable(&pdev->dev); + cdns_sierra_phy_disable_clocks(phy); /* * The device level resets will be put automatically. * Need to put the subnode resets here though. @@ -950,7 +985,6 @@ static int cdns_sierra_phy_remove(struct platform_device *pdev) reset_control_put(phy->phys[i].lnk_rst); } - clk_disable_unprepare(phy->input_clks[PHY_CLK]); cdns_sierra_clk_unregister(phy); return 0; -- cgit v1.2.3 From 725c7b8d300f8f26163435628b41a4c0a014dd24 Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Tue, 30 Mar 2021 16:31:34 +0530 Subject: phy: ti: j721e-wiz: Do not configure wiz if its already configured Serdes lanes might be shared between multiple cores in some usecases and its not possible to lock PLLs for both the lanes independently by the two cores. This requires a bootloader to configure both the lanes at early boot time. To handle this case, skip all configuration if any of the lanes has already been enabled. Signed-off-by: Faiz Abbas Signed-off-by: Kishon Vijay Abraham I Link: https://lore.kernel.org/r/20210330110138.24356-2-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-j721e-wiz.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index 02c47b2df01f..25238051680d 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -1134,13 +1134,14 @@ static int wiz_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; struct platform_device *serdes_pdev; + bool already_configured = false; struct device_node *child_node; struct regmap *regmap; struct resource res; void __iomem *base; struct wiz *wiz; + int ret, val, i; u32 num_lanes; - int ret; wiz = devm_kzalloc(dev, sizeof(*wiz), GFP_KERNEL); if (!wiz) @@ -1268,10 +1269,20 @@ static int wiz_probe(struct platform_device *pdev) goto err_get_sync; } - ret = wiz_init(wiz); - if (ret) { - dev_err(dev, "WIZ initialization failed\n"); - goto err_wiz_init; + for (i = 0; i < wiz->num_lanes; i++) { + regmap_field_read(wiz->p_enable[i], &val); + if (val & (P_ENABLE | P_ENABLE_FORCE)) { + already_configured = true; + break; + } + } + + if (!already_configured) { + ret = wiz_init(wiz); + if (ret) { + dev_err(dev, "WIZ initialization failed\n"); + goto err_wiz_init; + } } serdes_pdev = of_platform_device_create(child_node, NULL, dev); -- cgit v1.2.3 From d44b4bf49e0bc8f6195630eb9b397abb5bc162a8 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Tue, 30 Mar 2021 16:31:35 +0530 Subject: phy: cadence-torrent: Group reset APIs and clock APIs No functional change intended. Group reset APIs and clock APIs in preparation for adding support to skip configuration if the SERDES is already configured by bootloader. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Swapnil Jakhade Link: https://lore.kernel.org/r/20210330110138.24356-3-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-torrent.c | 84 +++++++++++++++++++------------ 1 file changed, 53 insertions(+), 31 deletions(-) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index 3fdab0d288c4..ab51c4bf7b30 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -2249,6 +2249,54 @@ static int cdns_torrent_clk_register(struct cdns_torrent_phy *cdns_phy) return 0; } +static int cdns_torrent_reset(struct cdns_torrent_phy *cdns_phy) +{ + struct device *dev = cdns_phy->dev; + + cdns_phy->phy_rst = devm_reset_control_get_exclusive_by_index(dev, 0); + if (IS_ERR(cdns_phy->phy_rst)) { + dev_err(dev, "%s: failed to get reset\n", + dev->of_node->full_name); + return PTR_ERR(cdns_phy->phy_rst); + } + + cdns_phy->apb_rst = devm_reset_control_get_optional(dev, "torrent_apb"); + if (IS_ERR(cdns_phy->apb_rst)) { + dev_err(dev, "%s: failed to get apb reset\n", + dev->of_node->full_name); + return PTR_ERR(cdns_phy->apb_rst); + } + + return 0; +} + +static int cdns_torrent_clk(struct cdns_torrent_phy *cdns_phy) +{ + struct device *dev = cdns_phy->dev; + int ret; + + cdns_phy->clk = devm_clk_get(dev, "refclk"); + if (IS_ERR(cdns_phy->clk)) { + dev_err(dev, "phy ref clock not found\n"); + return PTR_ERR(cdns_phy->clk); + } + + ret = clk_prepare_enable(cdns_phy->clk); + if (ret) { + dev_err(cdns_phy->dev, "Failed to prepare ref clock\n"); + return ret; + } + + cdns_phy->ref_clk_rate = clk_get_rate(cdns_phy->clk); + if (!(cdns_phy->ref_clk_rate)) { + dev_err(cdns_phy->dev, "Failed to get ref clock rate\n"); + clk_disable_unprepare(cdns_phy->clk); + return -EINVAL; + } + + return 0; +} + static int cdns_torrent_phy_probe(struct platform_device *pdev) { struct cdns_torrent_phy *cdns_phy; @@ -2274,26 +2322,6 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev) cdns_phy->dev = dev; cdns_phy->init_data = data; - cdns_phy->phy_rst = devm_reset_control_get_exclusive_by_index(dev, 0); - if (IS_ERR(cdns_phy->phy_rst)) { - dev_err(dev, "%s: failed to get reset\n", - dev->of_node->full_name); - return PTR_ERR(cdns_phy->phy_rst); - } - - cdns_phy->apb_rst = devm_reset_control_get_optional(dev, "torrent_apb"); - if (IS_ERR(cdns_phy->apb_rst)) { - dev_err(dev, "%s: failed to get apb reset\n", - dev->of_node->full_name); - return PTR_ERR(cdns_phy->apb_rst); - } - - cdns_phy->clk = devm_clk_get(dev, "refclk"); - if (IS_ERR(cdns_phy->clk)) { - dev_err(dev, "phy ref clock not found\n"); - return PTR_ERR(cdns_phy->clk); - } - cdns_phy->sd_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(cdns_phy->sd_base)) return PTR_ERR(cdns_phy->sd_base); @@ -2316,18 +2344,13 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev) if (ret) return ret; - ret = clk_prepare_enable(cdns_phy->clk); - if (ret) { - dev_err(cdns_phy->dev, "Failed to prepare ref clock\n"); + ret = cdns_torrent_reset(cdns_phy); + if (ret) goto clk_cleanup; - } - cdns_phy->ref_clk_rate = clk_get_rate(cdns_phy->clk); - if (!(cdns_phy->ref_clk_rate)) { - dev_err(cdns_phy->dev, "Failed to get ref clock rate\n"); - ret = -EINVAL; - goto clk_disable; - } + ret = cdns_torrent_clk(cdns_phy); + if (ret) + goto clk_cleanup; /* Enable APB */ reset_control_deassert(cdns_phy->apb_rst); @@ -2505,7 +2528,6 @@ put_lnk_rst: reset_control_put(cdns_phy->phys[i].lnk_rst); of_node_put(child); reset_control_assert(cdns_phy->apb_rst); -clk_disable: clk_disable_unprepare(cdns_phy->clk); clk_cleanup: cdns_torrent_clk_cleanup(cdns_phy); -- cgit v1.2.3 From b69d39f6841965559afbc3ecb0e3a8366c8999e8 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Tue, 30 Mar 2021 16:31:36 +0530 Subject: phy: cadence-torrent: Do not configure SERDES if it's already configured Do not configure torrent SERDES if it's already configured. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Swapnil Jakhade Link: https://lore.kernel.org/r/20210330110138.24356-4-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-torrent.c | 32 +++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index ab51c4bf7b30..5ee1657f5a1c 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -371,6 +371,10 @@ static const struct phy_ops cdns_torrent_phy_ops = { .owner = THIS_MODULE, }; +static const struct phy_ops noop_ops = { + .owner = THIS_MODULE, +}; + struct cdns_reg_pairs { u32 val; u32 off; @@ -2306,6 +2310,7 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev) struct device_node *child; int ret, subnodes, node = 0, i; u32 total_num_lanes = 0; + int already_configured; u8 init_dp_regmap = 0; u32 phy_type; @@ -2344,16 +2349,20 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev) if (ret) return ret; - ret = cdns_torrent_reset(cdns_phy); - if (ret) - goto clk_cleanup; + regmap_field_read(cdns_phy->phy_pma_cmn_ctrl_1, &already_configured); - ret = cdns_torrent_clk(cdns_phy); - if (ret) - goto clk_cleanup; + if (!already_configured) { + ret = cdns_torrent_reset(cdns_phy); + if (ret) + goto clk_cleanup; + + ret = cdns_torrent_clk(cdns_phy); + if (ret) + goto clk_cleanup; - /* Enable APB */ - reset_control_deassert(cdns_phy->apb_rst); + /* Enable APB */ + reset_control_deassert(cdns_phy->apb_rst); + } for_each_available_child_of_node(dev->of_node, child) { struct phy *gphy; @@ -2423,7 +2432,10 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev) of_property_read_u32(child, "cdns,ssc-mode", &cdns_phy->phys[node].ssc_mode); - gphy = devm_phy_create(dev, child, &cdns_torrent_phy_ops); + if (!already_configured) + gphy = devm_phy_create(dev, child, &cdns_torrent_phy_ops); + else + gphy = devm_phy_create(dev, child, &noop_ops); if (IS_ERR(gphy)) { ret = PTR_ERR(gphy); goto put_child; @@ -2507,7 +2519,7 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev) goto put_lnk_rst; } - if (cdns_phy->nsubnodes > 1) { + if (cdns_phy->nsubnodes > 1 && !already_configured) { ret = cdns_torrent_phy_configure_multilink(cdns_phy); if (ret) goto put_lnk_rst; -- cgit v1.2.3 From e0611d6d9639b79bd2605a9eb2e5cae28edc3e85 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Tue, 30 Mar 2021 16:31:37 +0530 Subject: phy: cadence-torrent: Explicitly request exclusive reset control No functional change. Since the reset controls obtained in Torrent is exclusively used by the Torrent device, use exclusive reset control request API calls. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Swapnil Jakhade Link: https://lore.kernel.org/r/20210330110138.24356-5-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-torrent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index 5ee1657f5a1c..ff8bb4b724c0 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -2264,7 +2264,7 @@ static int cdns_torrent_reset(struct cdns_torrent_phy *cdns_phy) return PTR_ERR(cdns_phy->phy_rst); } - cdns_phy->apb_rst = devm_reset_control_get_optional(dev, "torrent_apb"); + cdns_phy->apb_rst = devm_reset_control_get_optional_exclusive(dev, "torrent_apb"); if (IS_ERR(cdns_phy->apb_rst)) { dev_err(dev, "%s: failed to get apb reset\n", dev->of_node->full_name); -- cgit v1.2.3 From b20da3c6b9dd0787e3eec996de806829e1bcaad1 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Tue, 30 Mar 2021 16:31:38 +0530 Subject: phy: cadence-torrent: Add delay for PIPE clock to be stable The Torrent spec specifies delay of 660.5us after phy_reset is asserted by the controller. To be on the safe side provide a delay of 5ms to 10ms in ->phy_on() callback where the SERDES is already configured in bootloader. Signed-off-by: Kishon Vijay Abraham I Link: https://lore.kernel.org/r/20210330110138.24356-6-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-torrent.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index ff8bb4b724c0..0477e7beebbf 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -371,7 +371,16 @@ static const struct phy_ops cdns_torrent_phy_ops = { .owner = THIS_MODULE, }; +static int cdns_torrent_noop_phy_on(struct phy *phy) +{ + /* Give 5ms to 10ms delay for the PIPE clock to be stable */ + usleep_range(5000, 10000); + + return 0; +} + static const struct phy_ops noop_ops = { + .power_on = cdns_torrent_noop_phy_on, .owner = THIS_MODULE, }; -- cgit v1.2.3 From a113ef0a5e2eb3015da2e6dee0656d78e66fd691 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 31 Mar 2021 10:19:37 +0200 Subject: phy: microchip: PHY_SPARX5_SERDES should depend on ARCH_SPARX5 The Microchip Sparx5 SerDes PHY is present only Microchip Sparx5 SoCs. Hence add a dependency on ARCH_SPARX5, to prevent asking the user about this driver when configuring a kernel without support for Sparx5 SoCs. Fixes: 2ff8a1eeb5aa8bb4 ("phy: Add Sparx5 ethernet serdes PHY driver") Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20210331081937.367408-1-geert+renesas@glider.be Signed-off-by: Vinod Koul --- drivers/phy/microchip/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/phy/microchip/Kconfig b/drivers/phy/microchip/Kconfig index 0b1a818e01b8..3728a284bf64 100644 --- a/drivers/phy/microchip/Kconfig +++ b/drivers/phy/microchip/Kconfig @@ -6,6 +6,7 @@ config PHY_SPARX5_SERDES tristate "Microchip Sparx5 SerDes PHY driver" select GENERIC_PHY + depends on ARCH_SPARX5 || COMPILE_TEST depends on OF depends on HAS_IOMEM help -- cgit v1.2.3 From 418bec695696abd1b4d5abca85f143ead2ffedac Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Mon, 29 Mar 2021 18:28:18 -0700 Subject: bus: mhi: core: Rely on accurate method to determine EDL mode Relying on the current execution environment to determine if EDL image was downloaded should not be done as the execution environment can change at this point in error cases and we may misread it. Instead, MHI can rely on the local 'fw_name' variable as a safer alternative. Signed-off-by: Bhaumik Bhatt Reviewed-by: Manivannan Sadhasivam Reviewed-by: Loic Poulain Link: https://lore.kernel.org/r/1617067704-28850-2-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/boot.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/bus/mhi/core/boot.c b/drivers/bus/mhi/core/boot.c index 08c28740dc4e..84c21178144a 100644 --- a/drivers/bus/mhi/core/boot.c +++ b/drivers/bus/mhi/core/boot.c @@ -460,7 +460,8 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) goto error_fw_load; } - if (mhi_cntrl->ee == MHI_EE_EDL) { + /* Exit if EDL image was loaded */ + if (fw_name == mhi_cntrl->edl_image) { release_firmware(firmware); return; } -- cgit v1.2.3 From 4f214496ac7421b027a41d067e7753ee0bc5ad6c Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Mon, 29 Mar 2021 18:28:19 -0700 Subject: bus: mhi: core: Wait for ready after an EDL firmware download Currently, the firmware load handler returns after the EDL image is downloaded. Wait for an MHI READY transition instead as the specification expects so as to proceed with further bootup such as device entering Flash Programmer execution environment. Signed-off-by: Bhaumik Bhatt Reviewed-by: Manivannan Sadhasivam Reviewed-by: Loic Poulain Link: https://lore.kernel.org/r/1617067704-28850-3-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/boot.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/bus/mhi/core/boot.c b/drivers/bus/mhi/core/boot.c index 84c21178144a..0f0ae8816e29 100644 --- a/drivers/bus/mhi/core/boot.c +++ b/drivers/bus/mhi/core/boot.c @@ -418,7 +418,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) /* If device is in pass through, do reset to ready state transition */ if (mhi_cntrl->ee == MHI_EE_PTHRU) - goto fw_load_ee_pthru; + goto fw_load_ready_state; fw_name = (mhi_cntrl->ee == MHI_EE_EDL) ? mhi_cntrl->edl_image : mhi_cntrl->fw_image; @@ -460,10 +460,10 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) goto error_fw_load; } - /* Exit if EDL image was loaded */ + /* Wait for ready since EDL image was loaded */ if (fw_name == mhi_cntrl->edl_image) { release_firmware(firmware); - return; + goto fw_load_ready_state; } write_lock_irq(&mhi_cntrl->pm_lock); @@ -488,7 +488,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) release_firmware(firmware); -fw_load_ee_pthru: +fw_load_ready_state: /* Transitioning into MHI RESET->READY state */ ret = mhi_ready_state_transition(mhi_cntrl); if (ret) { -- cgit v1.2.3 From ad416db9fabe43b53a80deb4444d2a2e246b1cf1 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Mon, 29 Mar 2021 18:28:20 -0700 Subject: bus: mhi: core: Handle EDL mode entry appropriately Device entering EDL or Emergency Download Mode will be in a SYS_ERROR MHI state. This requires MHI host to proceed with the EDL image download over BHI before device can enter an MHI READY state and proceed with further bootup. Allow this to be handled by relying on the execution environment check after SYS_ERROR processing to determine whether to wait for an MHI READY or download the EDL image over BHI after moving MHI PM state to Power on Reset internally. This way handling is contained well within the MHI core driver and helps pave the way for Flash Programmer execution environment functionality. Signed-off-by: Bhaumik Bhatt Reviewed-by: Loic Poulain Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1617067704-28850-4-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/pm.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c index fbe944730401..b65222eda5e6 100644 --- a/drivers/bus/mhi/core/pm.c +++ b/drivers/bus/mhi/core/pm.c @@ -564,6 +564,7 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl) static void mhi_pm_sys_error_transition(struct mhi_controller *mhi_cntrl) { enum mhi_pm_state cur_state, prev_state; + enum dev_st_transition next_state; struct mhi_event *mhi_event; struct mhi_cmd_ctxt *cmd_ctxt; struct mhi_cmd *mhi_cmd; @@ -677,7 +678,23 @@ static void mhi_pm_sys_error_transition(struct mhi_controller *mhi_cntrl) er_ctxt->wp = er_ctxt->rbase; } - mhi_ready_state_transition(mhi_cntrl); + /* Transition to next state */ + if (MHI_IN_PBL(mhi_get_exec_env(mhi_cntrl))) { + write_lock_irq(&mhi_cntrl->pm_lock); + cur_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_POR); + write_unlock_irq(&mhi_cntrl->pm_lock); + if (cur_state != MHI_PM_POR) { + dev_err(dev, "Error moving to state %s from %s\n", + to_mhi_pm_state_str(MHI_PM_POR), + to_mhi_pm_state_str(cur_state)); + goto exit_sys_error_transition; + } + next_state = DEV_ST_TRANSITION_PBL; + } else { + next_state = DEV_ST_TRANSITION_READY; + } + + mhi_queue_state_transition(mhi_cntrl, next_state); exit_sys_error_transition: dev_dbg(dev, "Exiting with PM state: %s, MHI state: %s\n", -- cgit v1.2.3 From 3f3ec9b692a391f0e4fa0b6aab6d3c28935d610e Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Mon, 29 Mar 2021 18:50:41 +0200 Subject: dt-bindings: phy: bcm-ns-usb2-phy: convert to yaml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Convert from txt to yaml 2. Drop "Driver for" from the title 3. Document "#phy-cells" 4. Fix example node name (noticed by dt_binding_check) 5. Add #include to example (noticed by dt_binding_check) 6. Specify license Signed-off-by: Rafał Miłecki Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210329165041.31574-1-zajec5@gmail.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/bcm-ns-usb2-phy.txt | 21 -------- .../devicetree/bindings/phy/bcm-ns-usb2-phy.yaml | 59 ++++++++++++++++++++++ 2 files changed, 59 insertions(+), 21 deletions(-) delete mode 100644 Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.txt create mode 100644 Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.yaml diff --git a/Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.txt b/Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.txt deleted file mode 100644 index a7aee9ea8926..000000000000 --- a/Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.txt +++ /dev/null @@ -1,21 +0,0 @@ -Driver for Broadcom Northstar USB 2.0 PHY - -Required properties: -- compatible: brcm,ns-usb2-phy -- reg: iomem address range of DMU (Device Management Unit) -- reg-names: "dmu", the only needed & supported reg right now -- clocks: USB PHY reference clock -- clock-names: "phy-ref-clk", the only needed & supported clock right now - -To initialize USB 2.0 PHY driver needs to setup PLL correctly. To do this it -requires passing phandle to the USB PHY reference clock. - -Example: - usb2-phy { - compatible = "brcm,ns-usb2-phy"; - reg = <0x1800c000 0x1000>; - reg-names = "dmu"; - #phy-cells = <0>; - clocks = <&genpll BCM_NSP_GENPLL_USB_PHY_REF_CLK>; - clock-names = "phy-ref-clk"; - }; diff --git a/Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.yaml b/Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.yaml new file mode 100644 index 000000000000..05b4dcd80019 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/bcm-ns-usb2-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Broadcom Northstar USB 2.0 PHY + +description: > + To initialize USB 2.0 PHY driver needs to setup PLL correctly. + To do this it requires passing phandle to the USB PHY reference clock. + +maintainers: + - Rafał Miłecki + +properties: + compatible: + const: brcm,ns-usb2-phy + + reg: + items: + - description: iomem address range of DMU (Device Management Unit) + + reg-names: + items: + - const: dmu + + clocks: + items: + - description: USB PHY reference clock + + clock-names: + items: + - const: phy-ref-clk + + "#phy-cells": + const: 0 + +required: + - compatible + - reg + - reg-names + - clocks + - clock-names + - "#phy-cells" + +additionalProperties: false + +examples: + - | + #include + phy@1800c000 { + compatible = "brcm,ns-usb2-phy"; + reg = <0x1800c000 0x1000>; + reg-names = "dmu"; + clocks = <&genpll BCM_NSP_GENPLL_USB_PHY_REF_CLK>; + clock-names = "phy-ref-clk"; + #phy-cells = <0>; + }; -- cgit v1.2.3 From 5e15fdc302d1aed8ec8df65ef655242a2ac24e91 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Mon, 29 Mar 2021 18:50:56 +0200 Subject: dt-bindings: phy: bcm-ns-usb3-phy: convert to yaml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Change syntax from txt to yaml 2. Drop "Driver for" from the title 3. Drop "reg = <0x0>;" from example (noticed by dt_binding_check) 4. Specify license Signed-off-by: Rafał Miłecki Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210329165056.31647-1-zajec5@gmail.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/bcm-ns-usb3-phy.txt | 34 ------------ .../devicetree/bindings/phy/bcm-ns-usb3-phy.yaml | 62 ++++++++++++++++++++++ 2 files changed, 62 insertions(+), 34 deletions(-) delete mode 100644 Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.txt create mode 100644 Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.yaml diff --git a/Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.txt b/Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.txt deleted file mode 100644 index 32f057260351..000000000000 --- a/Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.txt +++ /dev/null @@ -1,34 +0,0 @@ -Driver for Broadcom Northstar USB 3.0 PHY - -Required properties: - -- compatible: one of: "brcm,ns-ax-usb3-phy", "brcm,ns-bx-usb3-phy". -- reg: address of MDIO bus device -- usb3-dmp-syscon: phandle to syscon with DMP (Device Management Plugin) - registers -- #phy-cells: must be 0 - -Initialization of USB 3.0 PHY depends on Northstar version. There are currently -three known series: Ax, Bx and Cx. -Known A0: BCM4707 rev 0 -Known B0: BCM4707 rev 4, BCM53573 rev 2 -Known B1: BCM4707 rev 6 -Known C0: BCM47094 rev 0 - -Example: - mdio: mdio@0 { - reg = <0x0>; - #size-cells = <1>; - #address-cells = <0>; - - usb3-phy@10 { - compatible = "brcm,ns-ax-usb3-phy"; - reg = <0x10>; - usb3-dmp-syscon = <&usb3_dmp>; - #phy-cells = <0>; - }; - }; - - usb3_dmp: syscon@18105000 { - reg = <0x18105000 0x1000>; - }; diff --git a/Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.yaml b/Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.yaml new file mode 100644 index 000000000000..7fd419db45d0 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/bcm-ns-usb3-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Broadcom Northstar USB 3.0 PHY + +description: | + Initialization of USB 3.0 PHY depends on Northstar version. There are currently + three known series: Ax, Bx and Cx. + Known A0: BCM4707 rev 0 + Known B0: BCM4707 rev 4, BCM53573 rev 2 + Known B1: BCM4707 rev 6 + Known C0: BCM47094 rev 0 + +maintainers: + - Rafał Miłecki + +properties: + compatible: + enum: + - brcm,ns-ax-usb3-phy + - brcm,ns-bx-usb3-phy + + reg: + description: address of MDIO bus device + maxItems: 1 + + usb3-dmp-syscon: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to the DMP (Device Management Plugin) syscon + + "#phy-cells": + const: 0 + +required: + - compatible + - reg + - usb3-dmp-syscon + - "#phy-cells" + +additionalProperties: false + +examples: + - | + mdio { + #address-cells = <1>; + #size-cells = <0>; + + usb3-phy@10 { + compatible = "brcm,ns-ax-usb3-phy"; + reg = <0x10>; + usb3-dmp-syscon = <&usb3_dmp>; + #phy-cells = <0>; + }; + }; + + usb3_dmp: syscon@18105000 { + reg = <0x18105000 0x1000>; + }; -- cgit v1.2.3 From 66ac7985b2af310aaca14869d6e43b0290e98c07 Mon Sep 17 00:00:00 2001 From: Carl Yin Date: Mon, 29 Mar 2021 18:28:21 -0700 Subject: bus: mhi: core: Add support for Flash Programmer execution environment MHI WWAN modems support downloading firmware to NAND or eMMC using Firehose protocol with process as follows: 1. Modem boots up, enters AMSS execution environment and the device later enters EDL (Emergency Download) mode through any mechanism host can use such as a diag command. 2. Modem enters SYS_ERROR, MHI host handles SYS_ERROR transition. 3. EDL image for device to enter 'Flash Programmer' execution environment is then flashed via BHI interface from host. 4. Modem enters MHI READY -> M0 and sends the Flash Programmer execution environment change to host. 5. Following that, EDL/FIREHOSE channels (34, 35) are made available from the host. 6. User space tool for downloading firmware image to modem over the EDL channels using Firehose protocol. Link to USB flashing tool: https://git.linaro.org/landing-teams/working/qualcomm/qdl.git/ Make the necessary changes to allow for this sequence to occur and allow using the Flash Programmer execution environment. Signed-off-by: Carl Yin Co-developed-by: Bhaumik Bhatt Signed-off-by: Bhaumik Bhatt Reviewed-by: Loic Poulain Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1617067704-28850-5-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/init.c | 2 ++ drivers/bus/mhi/core/internal.h | 1 + drivers/bus/mhi/core/main.c | 3 +++ drivers/bus/mhi/core/pm.c | 6 ++++++ include/linux/mhi.h | 4 +++- 5 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c index 706484ffe169..ee67712f66c0 100644 --- a/drivers/bus/mhi/core/init.c +++ b/drivers/bus/mhi/core/init.c @@ -29,6 +29,7 @@ const char * const mhi_ee_str[MHI_EE_MAX] = { [MHI_EE_WFW] = "WFW", [MHI_EE_PTHRU] = "PASS THRU", [MHI_EE_EDL] = "EDL", + [MHI_EE_FP] = "FLASH PROGRAMMER", [MHI_EE_DISABLE_TRANSITION] = "DISABLE", [MHI_EE_NOT_SUPPORTED] = "NOT SUPPORTED", }; @@ -38,6 +39,7 @@ const char * const dev_state_tran_str[DEV_ST_TRANSITION_MAX] = { [DEV_ST_TRANSITION_READY] = "READY", [DEV_ST_TRANSITION_SBL] = "SBL", [DEV_ST_TRANSITION_MISSION_MODE] = "MISSION_MODE", + [DEV_ST_TRANSITION_FP] = "FLASH_PROGRAMMER", [DEV_ST_TRANSITION_SYS_ERR] = "SYS_ERR", [DEV_ST_TRANSITION_DISABLE] = "DISABLE", }; diff --git a/drivers/bus/mhi/core/internal.h b/drivers/bus/mhi/core/internal.h index 6f37439e5247..b1b5f2b82393 100644 --- a/drivers/bus/mhi/core/internal.h +++ b/drivers/bus/mhi/core/internal.h @@ -386,6 +386,7 @@ enum dev_st_transition { DEV_ST_TRANSITION_READY, DEV_ST_TRANSITION_SBL, DEV_ST_TRANSITION_MISSION_MODE, + DEV_ST_TRANSITION_FP, DEV_ST_TRANSITION_SYS_ERR, DEV_ST_TRANSITION_DISABLE, DEV_ST_TRANSITION_MAX, diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index d377d07f269e..8b68657c76c3 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -831,6 +831,9 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, case MHI_EE_AMSS: st = DEV_ST_TRANSITION_MISSION_MODE; break; + case MHI_EE_FP: + st = DEV_ST_TRANSITION_FP; + break; case MHI_EE_RDDM: mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_EE_RDDM); write_lock_irq(&mhi_cntrl->pm_lock); diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c index b65222eda5e6..7ac9dfe54895 100644 --- a/drivers/bus/mhi/core/pm.c +++ b/drivers/bus/mhi/core/pm.c @@ -782,6 +782,12 @@ void mhi_pm_st_worker(struct work_struct *work) case DEV_ST_TRANSITION_MISSION_MODE: mhi_pm_mission_mode_transition(mhi_cntrl); break; + case DEV_ST_TRANSITION_FP: + write_lock_irq(&mhi_cntrl->pm_lock); + mhi_cntrl->ee = MHI_EE_FP; + write_unlock_irq(&mhi_cntrl->pm_lock); + mhi_create_devices(mhi_cntrl); + break; case DEV_ST_TRANSITION_READY: mhi_ready_state_transition(mhi_cntrl); break; diff --git a/include/linux/mhi.h b/include/linux/mhi.h index 8f5bf409f663..b16afd36b444 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -117,6 +117,7 @@ struct mhi_link_info { * @MHI_EE_WFW: WLAN firmware mode * @MHI_EE_PTHRU: Passthrough * @MHI_EE_EDL: Embedded downloader + * @MHI_EE_FP: Flash Programmer Environment */ enum mhi_ee_type { MHI_EE_PBL, @@ -126,7 +127,8 @@ enum mhi_ee_type { MHI_EE_WFW, MHI_EE_PTHRU, MHI_EE_EDL, - MHI_EE_MAX_SUPPORTED = MHI_EE_EDL, + MHI_EE_FP, + MHI_EE_MAX_SUPPORTED = MHI_EE_FP, MHI_EE_DISABLE_TRANSITION, /* local EE, not related to mhi spec */ MHI_EE_NOT_SUPPORTED, MHI_EE_MAX, -- cgit v1.2.3 From d20e82d4d0167925191f57ccff8b6c406c06176f Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Mon, 29 Mar 2021 18:28:22 -0700 Subject: bus: mhi: core: Identify Flash Programmer as a mission mode use case MHI power up can go through an EDL to Flash Programmer path when the device has a blank NAND. In those cases, mhi_sync_power_up() can timeout waiting for a mission mode execution environment. Allow a successful power up instead by identifying Flash Programmer as a valid mission mode execution environment with a purpose to flash the device image contents. Signed-off-by: Bhaumik Bhatt Reviewed-by: Manivannan Sadhasivam Reviewed-by: Loic Poulain Link: https://lore.kernel.org/r/1617067704-28850-6-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/internal.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/bus/mhi/core/internal.h b/drivers/bus/mhi/core/internal.h index b1b5f2b82393..7aa5cfd874e4 100644 --- a/drivers/bus/mhi/core/internal.h +++ b/drivers/bus/mhi/core/internal.h @@ -379,7 +379,8 @@ extern const char * const mhi_ee_str[MHI_EE_MAX]; #define MHI_IN_PBL(ee) (ee == MHI_EE_PBL || ee == MHI_EE_PTHRU || \ ee == MHI_EE_EDL) -#define MHI_IN_MISSION_MODE(ee) (ee == MHI_EE_AMSS || ee == MHI_EE_WFW) +#define MHI_IN_MISSION_MODE(ee) (ee == MHI_EE_AMSS || ee == MHI_EE_WFW || \ + ee == MHI_EE_FP) enum dev_st_transition { DEV_ST_TRANSITION_PBL, -- cgit v1.2.3 From e72919cebd19618b7341e69034b4d9f7120ff4de Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Mon, 29 Mar 2021 18:28:23 -0700 Subject: bus: mhi: core: Wait for MHI READY state in most scenarios When moving from SYS_ERROR transition to a different execution environment, MHI host relies on the BHI register read to spawn the next image download or wait for READY -> M0 states. The device can at times move the execution environment to mission mode when a pass through is expected, which can result in a stall. Initiate a wait for MHI READY and write M0 such that the device can proceed with state change event updates for any new execution environment being entered. This allows us to remove conditionals in handling firmware load for PBL modes and keeps the execution environment out of the picture as it can change at any time. Signed-off-by: Bhaumik Bhatt Reviewed-by: Loic Poulain Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1617067704-28850-7-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/boot.c | 4 ++-- drivers/bus/mhi/core/pm.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/bus/mhi/core/boot.c b/drivers/bus/mhi/core/boot.c index 0f0ae8816e29..8100cf51cd09 100644 --- a/drivers/bus/mhi/core/boot.c +++ b/drivers/bus/mhi/core/boot.c @@ -416,8 +416,8 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) } } - /* If device is in pass through, do reset to ready state transition */ - if (mhi_cntrl->ee == MHI_EE_PTHRU) + /* wait for ready on pass through or any other execution environment */ + if (mhi_cntrl->ee != MHI_EE_EDL && mhi_cntrl->ee != MHI_EE_PBL) goto fw_load_ready_state; fw_name = (mhi_cntrl->ee == MHI_EE_EDL) ? diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c index 7ac9dfe54895..b6920a5369a0 100644 --- a/drivers/bus/mhi/core/pm.c +++ b/drivers/bus/mhi/core/pm.c @@ -763,8 +763,7 @@ void mhi_pm_st_worker(struct work_struct *work) if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) mhi_cntrl->ee = mhi_get_exec_env(mhi_cntrl); write_unlock_irq(&mhi_cntrl->pm_lock); - if (MHI_IN_PBL(mhi_cntrl->ee)) - mhi_fw_load_handler(mhi_cntrl); + mhi_fw_load_handler(mhi_cntrl); break; case DEV_ST_TRANSITION_SBL: write_lock_irq(&mhi_cntrl->pm_lock); -- cgit v1.2.3 From 19e60d6e88a63df70091574b3dfe85945d2fd70f Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Mon, 29 Mar 2021 18:28:24 -0700 Subject: bus: mhi: core: Improve state strings for debug messages As of now abbreviations are being used for many state and execution environment strings. Improve and expand those such that debug messages are clear. Signed-off-by: Bhaumik Bhatt Reviewed-by: Manivannan Sadhasivam Reviewed-by: Loic Poulain Link: https://lore.kernel.org/r/1617067704-28850-8-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/init.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c index ee67712f66c0..d1d9b0d9158e 100644 --- a/drivers/bus/mhi/core/init.c +++ b/drivers/bus/mhi/core/init.c @@ -22,13 +22,13 @@ static DEFINE_IDA(mhi_controller_ida); const char * const mhi_ee_str[MHI_EE_MAX] = { - [MHI_EE_PBL] = "PBL", - [MHI_EE_SBL] = "SBL", - [MHI_EE_AMSS] = "AMSS", - [MHI_EE_RDDM] = "RDDM", - [MHI_EE_WFW] = "WFW", - [MHI_EE_PTHRU] = "PASS THRU", - [MHI_EE_EDL] = "EDL", + [MHI_EE_PBL] = "PRIMARY BOOTLOADER", + [MHI_EE_SBL] = "SECONDARY BOOTLOADER", + [MHI_EE_AMSS] = "MISSION MODE", + [MHI_EE_RDDM] = "RAMDUMP DOWNLOAD MODE", + [MHI_EE_WFW] = "WLAN FIRMWARE", + [MHI_EE_PTHRU] = "PASS THROUGH", + [MHI_EE_EDL] = "EMERGENCY DOWNLOAD", [MHI_EE_FP] = "FLASH PROGRAMMER", [MHI_EE_DISABLE_TRANSITION] = "DISABLE", [MHI_EE_NOT_SUPPORTED] = "NOT SUPPORTED", @@ -38,9 +38,9 @@ const char * const dev_state_tran_str[DEV_ST_TRANSITION_MAX] = { [DEV_ST_TRANSITION_PBL] = "PBL", [DEV_ST_TRANSITION_READY] = "READY", [DEV_ST_TRANSITION_SBL] = "SBL", - [DEV_ST_TRANSITION_MISSION_MODE] = "MISSION_MODE", - [DEV_ST_TRANSITION_FP] = "FLASH_PROGRAMMER", - [DEV_ST_TRANSITION_SYS_ERR] = "SYS_ERR", + [DEV_ST_TRANSITION_MISSION_MODE] = "MISSION MODE", + [DEV_ST_TRANSITION_FP] = "FLASH PROGRAMMER", + [DEV_ST_TRANSITION_SYS_ERR] = "SYS ERROR", [DEV_ST_TRANSITION_DISABLE] = "DISABLE", }; @@ -51,24 +51,24 @@ const char * const mhi_state_str[MHI_STATE_MAX] = { [MHI_STATE_M1] = "M1", [MHI_STATE_M2] = "M2", [MHI_STATE_M3] = "M3", - [MHI_STATE_M3_FAST] = "M3_FAST", + [MHI_STATE_M3_FAST] = "M3 FAST", [MHI_STATE_BHI] = "BHI", - [MHI_STATE_SYS_ERR] = "SYS_ERR", + [MHI_STATE_SYS_ERR] = "SYS ERROR", }; static const char * const mhi_pm_state_str[] = { [MHI_PM_STATE_DISABLE] = "DISABLE", - [MHI_PM_STATE_POR] = "POR", + [MHI_PM_STATE_POR] = "POWER ON RESET", [MHI_PM_STATE_M0] = "M0", [MHI_PM_STATE_M2] = "M2", [MHI_PM_STATE_M3_ENTER] = "M?->M3", [MHI_PM_STATE_M3] = "M3", [MHI_PM_STATE_M3_EXIT] = "M3->M0", - [MHI_PM_STATE_FW_DL_ERR] = "FW DL Error", - [MHI_PM_STATE_SYS_ERR_DETECT] = "SYS_ERR Detect", - [MHI_PM_STATE_SYS_ERR_PROCESS] = "SYS_ERR Process", + [MHI_PM_STATE_FW_DL_ERR] = "Firmware Download Error", + [MHI_PM_STATE_SYS_ERR_DETECT] = "SYS ERROR Detect", + [MHI_PM_STATE_SYS_ERR_PROCESS] = "SYS ERROR Process", [MHI_PM_STATE_SHUTDOWN_PROCESS] = "SHUTDOWN Process", - [MHI_PM_STATE_LD_ERR_FATAL_DETECT] = "LD or Error Fatal Detect", + [MHI_PM_STATE_LD_ERR_FATAL_DETECT] = "Linkdown or Error Fatal Detect", }; const char *to_mhi_pm_state_str(enum mhi_pm_state state) -- cgit v1.2.3 From 67097754afc90a5def9d54c599d0862fe992f5a0 Mon Sep 17 00:00:00 2001 From: Manish Narani Date: Wed, 24 Mar 2021 17:48:45 +0530 Subject: phy: zynqmp: Handle the clock enable/disable properly The current driver is not handling the clock enable/disable operations properly. The clocks need to be handled correctly by enabling or disabling at appropriate places. This patch adds code to handle the same. Signed-off-by: Manish Narani Reviewed-by: Laurent Pinchart Acked-by: Michal Simek Link: https://lore.kernel.org/r/1616588325-95602-1-git-send-email-manish.narani@xilinx.com Signed-off-by: Vinod Koul --- drivers/phy/xilinx/phy-zynqmp.c | 58 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/drivers/phy/xilinx/phy-zynqmp.c b/drivers/phy/xilinx/phy-zynqmp.c index 2b65f84a5f89..35652152ce5d 100644 --- a/drivers/phy/xilinx/phy-zynqmp.c +++ b/drivers/phy/xilinx/phy-zynqmp.c @@ -208,6 +208,7 @@ struct xpsgtr_phy { * @gtr_mutex: mutex for locking * @phys: PHY lanes * @refclk_sscs: spread spectrum settings for the reference clocks + * @clk: reference clocks * @tx_term_fix: fix for GT issue * @saved_icm_cfg0: stored value of ICM CFG0 register * @saved_icm_cfg1: stored value of ICM CFG1 register @@ -219,6 +220,7 @@ struct xpsgtr_dev { struct mutex gtr_mutex; /* mutex for locking */ struct xpsgtr_phy phys[NUM_LANES]; const struct xpsgtr_ssc *refclk_sscs[NUM_LANES]; + struct clk *clk[NUM_LANES]; bool tx_term_fix; unsigned int saved_icm_cfg0; unsigned int saved_icm_cfg1; @@ -818,11 +820,15 @@ static struct phy *xpsgtr_xlate(struct device *dev, static int __maybe_unused xpsgtr_suspend(struct device *dev) { struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev); + unsigned int i; /* Save the snapshot ICM_CFG registers. */ gtr_dev->saved_icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0); gtr_dev->saved_icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1); + for (i = 0; i < ARRAY_SIZE(gtr_dev->clk); i++) + clk_disable_unprepare(gtr_dev->clk[i]); + return 0; } @@ -832,6 +838,13 @@ static int __maybe_unused xpsgtr_resume(struct device *dev) unsigned int icm_cfg0, icm_cfg1; unsigned int i; bool skip_phy_init; + int err; + + for (i = 0; i < ARRAY_SIZE(gtr_dev->clk); i++) { + err = clk_prepare_enable(gtr_dev->clk[i]); + if (err) + goto err_clk_put; + } icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0); icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1); @@ -852,6 +865,12 @@ static int __maybe_unused xpsgtr_resume(struct device *dev) gtr_dev->phys[i].skip_phy_init = skip_phy_init; return 0; + +err_clk_put: + while (i--) + clk_disable_unprepare(gtr_dev->clk[i]); + + return err; } static const struct dev_pm_ops xpsgtr_pm_ops = { @@ -865,6 +884,7 @@ static const struct dev_pm_ops xpsgtr_pm_ops = { static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev) { unsigned int refclk; + int ret; for (refclk = 0; refclk < ARRAY_SIZE(gtr_dev->refclk_sscs); ++refclk) { unsigned long rate; @@ -874,14 +894,22 @@ static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev) snprintf(name, sizeof(name), "ref%u", refclk); clk = devm_clk_get_optional(gtr_dev->dev, name); - if (IS_ERR(clk)) - return dev_err_probe(gtr_dev->dev, PTR_ERR(clk), - "Failed to get reference clock %u\n", - refclk); + if (IS_ERR(clk)) { + ret = dev_err_probe(gtr_dev->dev, PTR_ERR(clk), + "Failed to get reference clock %u\n", + refclk); + goto err_clk_put; + } if (!clk) continue; + ret = clk_prepare_enable(clk); + if (ret) + goto err_clk_put; + + gtr_dev->clk[refclk] = clk; + /* * Get the spread spectrum (SSC) settings for the reference * clock rate. @@ -899,11 +927,18 @@ static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev) dev_err(gtr_dev->dev, "Invalid rate %lu for reference clock %u\n", rate, refclk); - return -EINVAL; + ret = -EINVAL; + goto err_clk_put; } } return 0; + +err_clk_put: + while (refclk--) + clk_disable_unprepare(gtr_dev->clk[refclk]); + + return ret; } static int xpsgtr_probe(struct platform_device *pdev) @@ -912,6 +947,7 @@ static int xpsgtr_probe(struct platform_device *pdev) struct xpsgtr_dev *gtr_dev; struct phy_provider *provider; unsigned int port; + unsigned int i; int ret; gtr_dev = devm_kzalloc(&pdev->dev, sizeof(*gtr_dev), GFP_KERNEL); @@ -951,7 +987,8 @@ static int xpsgtr_probe(struct platform_device *pdev) phy = devm_phy_create(&pdev->dev, np, &xpsgtr_phyops); if (IS_ERR(phy)) { dev_err(&pdev->dev, "failed to create PHY\n"); - return PTR_ERR(phy); + ret = PTR_ERR(phy); + goto err_clk_put; } gtr_phy->phy = phy; @@ -962,9 +999,16 @@ static int xpsgtr_probe(struct platform_device *pdev) provider = devm_of_phy_provider_register(&pdev->dev, xpsgtr_xlate); if (IS_ERR(provider)) { dev_err(&pdev->dev, "registering provider failed\n"); - return PTR_ERR(provider); + ret = PTR_ERR(provider); + goto err_clk_put; } return 0; + +err_clk_put: + for (i = 0; i < ARRAY_SIZE(gtr_dev->clk); i++) + clk_disable_unprepare(gtr_dev->clk[i]); + + return ret; } static const struct of_device_id xpsgtr_of_match[] = { -- cgit v1.2.3 From d57cd79db1a3c147b63fb0c64ccd26855eb8f86e Mon Sep 17 00:00:00 2001 From: Seiya Wang Date: Fri, 19 Mar 2021 10:34:26 +0800 Subject: dt-bindings: phy: fix dt_binding_check warning in mediatek, ufs-phy.yaml This commit fixes the warning messages of make dt_binding_check from newly added mediatek,mt8195-ufsphy in mediatek,ufs-phy.yaml Signed-off-by: Seiya Wang Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210319023427.16711-9-seiya.wang@mediatek.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/mediatek,ufs-phy.yaml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/mediatek,ufs-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,ufs-phy.yaml index 5235b1a0d188..74cc32c1d2e8 100644 --- a/Documentation/devicetree/bindings/phy/mediatek,ufs-phy.yaml +++ b/Documentation/devicetree/bindings/phy/mediatek,ufs-phy.yaml @@ -22,8 +22,12 @@ properties: pattern: "^ufs-phy@[0-9a-f]+$" compatible: - enum: mediatek,mt8195-ufsphy - const: mediatek,mt8183-ufsphy + oneOf: + - items: + - enum: + - mediatek,mt8195-ufsphy + - const: mediatek,mt8183-ufsphy + - const: mediatek,mt8183-ufsphy reg: maxItems: 1 -- cgit v1.2.3 From 36a813839cdee99c87e17a2d52a009b5517d54a9 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 31 Mar 2021 18:44:17 +0530 Subject: phy: ti: j721e-wiz: Configure 'p_standard_mode' only for DP/QSGMII Configure 'p_standard_mode' only for DP/QSGMII as for other modes it's not used as per the programming sequence. Add "continue" in the else to prevent random value from being written to p_standard_mode. Signed-off-by: Kishon Vijay Abraham I Link: https://lore.kernel.org/r/20210331131417.15596-1-kishon@ti.com Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-j721e-wiz.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index 25238051680d..2b354680a272 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -340,6 +340,8 @@ static int wiz_mode_select(struct wiz *wiz) mode = LANE_MODE_GEN1; else if (wiz->lane_phy_type[i] == PHY_TYPE_QSGMII) mode = LANE_MODE_GEN2; + else + continue; ret = regmap_field_write(wiz->p_standard_mode[i], mode); if (ret) -- cgit v1.2.3 From 94c34600b6173a2b9dd7d9694a42d86fb8768e62 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 31 Mar 2021 18:16:08 +0300 Subject: dt-bindings: phy: qcom,qmp-usb3-dp-phy: move usb3 compatibles back to qcom,qmp-phy.yaml The commit 724fabf5df13 ("dt-bindings: phy: qcom,qmp-usb3-dp: Add DP phy information") has support for DP part of USB3+DP combo PHYs. However this change is not backwards compatible, placing additional requirements onto qcom,sc7180-qmp-usb3-phy and qcom,sdm845-qmp-usb3-phy device nodes (to include separate DP part, etc). However the aforementioned nodes do not inclue DP part, they strictly follow the schema defined in the qcom,qmp-phy.yaml file. Move those compatibles, leaving qcom,qmp-usb3-dp-phy.yaml to describe only real "combo" USB3+DP device nodes. Fixes: 724fabf5df13 ("dt-bindings: phy: qcom,qmp-usb3-dp: Add DP phy information") Cc: Stephen Boyd Cc: Sandeep Maheswaram Signed-off-by: Dmitry Baryshkov Acked-by: Rob Herring Reviewed-by: Stephen Boyd Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210331151614.3810197-2-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml | 2 ++ Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml index 626447fee092..7808ec8bc712 100644 --- a/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml @@ -25,11 +25,13 @@ properties: - qcom,msm8998-qmp-pcie-phy - qcom,msm8998-qmp-ufs-phy - qcom,msm8998-qmp-usb3-phy + - qcom,sc7180-qmp-usb3-phy - qcom,sc8180x-qmp-ufs-phy - qcom,sc8180x-qmp-usb3-phy - qcom,sdm845-qhp-pcie-phy - qcom,sdm845-qmp-pcie-phy - qcom,sdm845-qmp-ufs-phy + - qcom,sdm845-qmp-usb3-phy - qcom,sdm845-qmp-usb3-uni-phy - qcom,sm8150-qmp-ufs-phy - qcom,sm8150-qmp-usb3-phy diff --git a/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml index 33974ad10afe..62c0179d1765 100644 --- a/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml @@ -14,9 +14,7 @@ properties: compatible: enum: - qcom,sc7180-qmp-usb3-dp-phy - - qcom,sc7180-qmp-usb3-phy - qcom,sdm845-qmp-usb3-dp-phy - - qcom,sdm845-qmp-usb3-phy reg: items: - description: Address and length of PHY's USB serdes block. -- cgit v1.2.3 From 87899d9a66f3165ec70e8a386ba06f67ad148ca2 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 31 Mar 2021 18:16:09 +0300 Subject: dt-bindings: phy: qcom,qmp-usb3-dp: Add support for SM8250 Add compatible for SM8250 in QMP USB3 DP PHY bindings. Signed-off-by: Dmitry Baryshkov Acked-by: Rob Herring Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210331151614.3810197-3-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml index 62c0179d1765..217aa6c91893 100644 --- a/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml @@ -15,6 +15,7 @@ properties: enum: - qcom,sc7180-qmp-usb3-dp-phy - qcom,sdm845-qmp-usb3-dp-phy + - qcom,sm8250-qmp-usb3-dp-phy reg: items: - description: Address and length of PHY's USB serdes block. -- cgit v1.2.3 From 5f0d28f20eebf8eff887ecd231178b659764c676 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 31 Mar 2021 18:16:10 +0300 Subject: phy: qcom-qmp: move DP functions to callbacks In preparation to adding support for V4 DP PHY move DP functions to callbacks at struct qmp_phy_cfg. Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20210331151614.3810197-4-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp.c | 73 ++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 22 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index 1c79a713780d..854f6ff7faef 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -2268,6 +2268,8 @@ static const struct qmp_phy_init_tbl sm8350_usb3_uniphy_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x21), }; +struct qmp_phy; + /* struct qmp_phy_cfg - per-PHY initialization config */ struct qmp_phy_cfg { /* phy-type - PCIE/UFS/USB */ @@ -2307,6 +2309,12 @@ struct qmp_phy_cfg { const struct qmp_phy_init_tbl *serdes_tbl_hbr3; int serdes_tbl_hbr3_num; + /* DP PHY callbacks */ + int (*configure_dp_phy)(struct qmp_phy *qphy); + void (*configure_dp_tx)(struct qmp_phy *qphy); + int (*calibrate_dp_phy)(struct qmp_phy *qphy); + void (*dp_aux_init)(struct qmp_phy *qphy); + /* clock ids to be requested */ const char * const *clk_list; int num_clks; @@ -2423,6 +2431,11 @@ struct qcom_qmp { struct reset_control *ufs_reset; }; +static void qcom_qmp_v3_phy_dp_aux_init(struct qmp_phy *qphy); +static void qcom_qmp_v3_phy_configure_dp_tx(struct qmp_phy *qphy); +static int qcom_qmp_v3_phy_configure_dp_phy(struct qmp_phy *qphy); +static int qcom_qmp_v3_dp_phy_calibrate(struct qmp_phy *qphy); + static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val) { u32 reg; @@ -2871,6 +2884,11 @@ static const struct qmp_phy_cfg sc7180_dpphy_cfg = { .has_phy_dp_com_ctrl = true, .is_dual_lane_phy = true, + + .dp_aux_init = qcom_qmp_v3_phy_dp_aux_init, + .configure_dp_tx = qcom_qmp_v3_phy_configure_dp_tx, + .configure_dp_phy = qcom_qmp_v3_phy_configure_dp_phy, + .calibrate_dp_phy = qcom_qmp_v3_dp_phy_calibrate, }; static const struct qmp_phy_combo_cfg sc7180_usb3dpphy_cfg = { @@ -3332,7 +3350,7 @@ static int qcom_qmp_phy_serdes_init(struct qmp_phy *qphy) return 0; } -static void qcom_qmp_phy_dp_aux_init(struct qmp_phy *qphy) +static void qcom_qmp_v3_phy_dp_aux_init(struct qmp_phy *qphy) { writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, @@ -3403,7 +3421,7 @@ static const u8 qmp_dp_v3_voltage_swing_hbr_rbr[4][4] = { { 0x1f, 0xff, 0xff, 0xff } }; -static void qcom_qmp_phy_configure_dp_tx(struct qmp_phy *qphy) +static void qcom_qmp_v3_phy_configure_dp_tx(struct qmp_phy *qphy) { const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts; unsigned int v_level = 0, p_level = 0; @@ -3451,21 +3469,7 @@ static void qcom_qmp_phy_configure_dp_tx(struct qmp_phy *qphy) writel(bias_en, qphy->tx2 + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN); } -static int qcom_qmp_dp_phy_configure(struct phy *phy, union phy_configure_opts *opts) -{ - const struct phy_configure_opts_dp *dp_opts = &opts->dp; - struct qmp_phy *qphy = phy_get_drvdata(phy); - - memcpy(&qphy->dp_opts, dp_opts, sizeof(*dp_opts)); - if (qphy->dp_opts.set_voltages) { - qcom_qmp_phy_configure_dp_tx(qphy); - qphy->dp_opts.set_voltages = 0; - } - - return 0; -} - -static int qcom_qmp_phy_configure_dp_phy(struct qmp_phy *qphy) +static int qcom_qmp_v3_phy_configure_dp_phy(struct qmp_phy *qphy) { const struct qmp_phy_dp_clks *dp_clks = qphy->dp_clks; const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts; @@ -3561,9 +3565,8 @@ static int qcom_qmp_phy_configure_dp_phy(struct qmp_phy *qphy) * We need to calibrate the aux setting here as many times * as the caller tries */ -static int qcom_qmp_dp_phy_calibrate(struct phy *phy) +static int qcom_qmp_v3_dp_phy_calibrate(struct qmp_phy *qphy) { - struct qmp_phy *qphy = phy_get_drvdata(phy); static const u8 cfg1_settings[] = { 0x13, 0x23, 0x1d }; u8 val; @@ -3576,6 +3579,32 @@ static int qcom_qmp_dp_phy_calibrate(struct phy *phy) return 0; } +static int qcom_qmp_dp_phy_configure(struct phy *phy, union phy_configure_opts *opts) +{ + const struct phy_configure_opts_dp *dp_opts = &opts->dp; + struct qmp_phy *qphy = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qphy->cfg; + + memcpy(&qphy->dp_opts, dp_opts, sizeof(*dp_opts)); + if (qphy->dp_opts.set_voltages) { + cfg->configure_dp_tx(qphy); + qphy->dp_opts.set_voltages = 0; + } + + return 0; +} + +static int qcom_qmp_dp_phy_calibrate(struct phy *phy) +{ + struct qmp_phy *qphy = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qphy->cfg; + + if (cfg->calibrate_dp_phy) + return cfg->calibrate_dp_phy(qphy); + + return 0; +} + static int qcom_qmp_phy_com_init(struct qmp_phy *qphy) { struct qcom_qmp *qmp = qphy->qmp; @@ -3748,7 +3777,7 @@ static int qcom_qmp_phy_init(struct phy *phy) return ret; if (cfg->type == PHY_TYPE_DP) - qcom_qmp_phy_dp_aux_init(qphy); + cfg->dp_aux_init(qphy); return 0; } @@ -3802,7 +3831,7 @@ static int qcom_qmp_phy_power_on(struct phy *phy) /* Configure special DP tx tunings */ if (cfg->type == PHY_TYPE_DP) - qcom_qmp_phy_configure_dp_tx(qphy); + cfg->configure_dp_tx(qphy); qcom_qmp_phy_configure_lane(rx, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num, 1); @@ -3821,7 +3850,7 @@ static int qcom_qmp_phy_power_on(struct phy *phy) /* Configure link rate, swing, etc. */ if (cfg->type == PHY_TYPE_DP) { - qcom_qmp_phy_configure_dp_phy(qphy); + cfg->configure_dp_phy(qphy); } else { qcom_qmp_phy_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num); if (cfg->pcs_tbl_sec) -- cgit v1.2.3 From 5c3939174fe4d186604e0e78e9711b883e9cc858 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 31 Mar 2021 18:16:11 +0300 Subject: phy: qcom-qmp: rename common registers A plenty of DP PHY registers are common between V3 and V4. To simplify V4 code, rename all common registers. Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20210331151614.3810197-5-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp.c | 50 ++++++++++++++++++------------------- drivers/phy/qualcomm/phy-qcom-qmp.h | 37 ++++++++++++++------------- 2 files changed, 44 insertions(+), 43 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index 854f6ff7faef..e1dbc9d936e7 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -3354,20 +3354,20 @@ static void qcom_qmp_v3_phy_dp_aux_init(struct qmp_phy *qphy) { writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, - qphy->pcs + QSERDES_V3_DP_PHY_PD_CTL); + qphy->pcs + QSERDES_DP_PHY_PD_CTL); /* Turn on BIAS current for PHY/PLL */ writel(QSERDES_V3_COM_BIAS_EN | QSERDES_V3_COM_BIAS_EN_MUX | QSERDES_V3_COM_CLKBUF_L_EN | QSERDES_V3_COM_EN_SYSCLK_TX_SEL, qphy->serdes + QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN); - writel(DP_PHY_PD_CTL_PSR_PWRDN, qphy->pcs + QSERDES_V3_DP_PHY_PD_CTL); + writel(DP_PHY_PD_CTL_PSR_PWRDN, qphy->pcs + QSERDES_DP_PHY_PD_CTL); writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN | DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, - qphy->pcs + QSERDES_V3_DP_PHY_PD_CTL); + qphy->pcs + QSERDES_DP_PHY_PD_CTL); writel(QSERDES_V3_COM_BIAS_EN | QSERDES_V3_COM_BIAS_EN_MUX | QSERDES_V3_COM_CLKBUF_R_EN | @@ -3375,16 +3375,16 @@ static void qcom_qmp_v3_phy_dp_aux_init(struct qmp_phy *qphy) QSERDES_V3_COM_CLKBUF_RX_DRIVE_L, qphy->serdes + QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN); - writel(0x00, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG0); - writel(0x13, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG1); - writel(0x24, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG2); - writel(0x00, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG3); - writel(0x0a, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG4); - writel(0x26, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG5); - writel(0x0a, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG6); - writel(0x03, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG7); - writel(0xbb, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG8); - writel(0x03, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG9); + writel(0x00, qphy->pcs + QSERDES_DP_PHY_AUX_CFG0); + writel(0x13, qphy->pcs + QSERDES_DP_PHY_AUX_CFG1); + writel(0x24, qphy->pcs + QSERDES_DP_PHY_AUX_CFG2); + writel(0x00, qphy->pcs + QSERDES_DP_PHY_AUX_CFG3); + writel(0x0a, qphy->pcs + QSERDES_DP_PHY_AUX_CFG4); + writel(0x26, qphy->pcs + QSERDES_DP_PHY_AUX_CFG5); + writel(0x0a, qphy->pcs + QSERDES_DP_PHY_AUX_CFG6); + writel(0x03, qphy->pcs + QSERDES_DP_PHY_AUX_CFG7); + writel(0xbb, qphy->pcs + QSERDES_DP_PHY_AUX_CFG8); + writel(0x03, qphy->pcs + QSERDES_DP_PHY_AUX_CFG9); qphy->dp_aux_cfg = 0; writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK | @@ -3494,9 +3494,9 @@ static int qcom_qmp_v3_phy_configure_dp_phy(struct qmp_phy *qphy) * writel(0x4c, qphy->pcs + QSERDES_V3_DP_PHY_MODE); */ val |= DP_PHY_PD_CTL_LANE_2_3_PWRDN; - writel(val, qphy->pcs + QSERDES_V3_DP_PHY_PD_CTL); + writel(val, qphy->pcs + QSERDES_DP_PHY_PD_CTL); - writel(0x5c, qphy->pcs + QSERDES_V3_DP_PHY_MODE); + writel(0x5c, qphy->pcs + QSERDES_DP_PHY_MODE); writel(0x05, qphy->pcs + QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL); writel(0x05, qphy->pcs + QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL); @@ -3526,11 +3526,11 @@ static int qcom_qmp_v3_phy_configure_dp_phy(struct qmp_phy *qphy) clk_set_rate(dp_clks->dp_link_hw.clk, dp_opts->link_rate * 100000); clk_set_rate(dp_clks->dp_pixel_hw.clk, pixel_freq); - writel(0x04, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG2); - writel(0x01, qphy->pcs + QSERDES_V3_DP_PHY_CFG); - writel(0x05, qphy->pcs + QSERDES_V3_DP_PHY_CFG); - writel(0x01, qphy->pcs + QSERDES_V3_DP_PHY_CFG); - writel(0x09, qphy->pcs + QSERDES_V3_DP_PHY_CFG); + writel(0x04, qphy->pcs + QSERDES_DP_PHY_AUX_CFG2); + writel(0x01, qphy->pcs + QSERDES_DP_PHY_CFG); + writel(0x05, qphy->pcs + QSERDES_DP_PHY_CFG); + writel(0x01, qphy->pcs + QSERDES_DP_PHY_CFG); + writel(0x09, qphy->pcs + QSERDES_DP_PHY_CFG); writel(0x20, qphy->serdes + QSERDES_V3_COM_RESETSM_CNTRL); @@ -3541,7 +3541,7 @@ static int qcom_qmp_v3_phy_configure_dp_phy(struct qmp_phy *qphy) 10000)) return -ETIMEDOUT; - writel(0x19, qphy->pcs + QSERDES_V3_DP_PHY_CFG); + writel(0x19, qphy->pcs + QSERDES_DP_PHY_CFG); if (readl_poll_timeout(qphy->pcs + QSERDES_V3_DP_PHY_STATUS, status, @@ -3550,9 +3550,9 @@ static int qcom_qmp_v3_phy_configure_dp_phy(struct qmp_phy *qphy) 10000)) return -ETIMEDOUT; - writel(0x18, qphy->pcs + QSERDES_V3_DP_PHY_CFG); + writel(0x18, qphy->pcs + QSERDES_DP_PHY_CFG); udelay(2000); - writel(0x19, qphy->pcs + QSERDES_V3_DP_PHY_CFG); + writel(0x19, qphy->pcs + QSERDES_DP_PHY_CFG); return readl_poll_timeout(qphy->pcs + QSERDES_V3_DP_PHY_STATUS, status, @@ -3574,7 +3574,7 @@ static int qcom_qmp_v3_dp_phy_calibrate(struct qmp_phy *qphy) qphy->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings); val = cfg1_settings[qphy->dp_aux_cfg]; - writel(val, qphy->pcs + QSERDES_V3_DP_PHY_AUX_CFG1); + writel(val, qphy->pcs + QSERDES_DP_PHY_AUX_CFG1); return 0; } @@ -3922,7 +3922,7 @@ static int qcom_qmp_phy_power_off(struct phy *phy) if (cfg->type == PHY_TYPE_DP) { /* Assert DP PHY power down */ - writel(DP_PHY_PD_CTL_PSR_PWRDN, qphy->pcs + QSERDES_V3_DP_PHY_PD_CTL); + writel(DP_PHY_PD_CTL_PSR_PWRDN, qphy->pcs + QSERDES_DP_PHY_PD_CTL); } else { /* PHY reset */ if (!cfg->no_pcs_sw_reset) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h index 71ce3aa174ae..981d8ee891c0 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp.h @@ -349,13 +349,13 @@ #define QPHY_V3_PCS_MISC_OSC_DTCT_MODE2_CONFIG4 0x5c #define QPHY_V3_PCS_MISC_OSC_DTCT_MODE2_CONFIG5 0x60 -/* Only for QMP V3 PHY - DP PHY registers */ -#define QSERDES_V3_DP_PHY_REVISION_ID0 0x000 -#define QSERDES_V3_DP_PHY_REVISION_ID1 0x004 -#define QSERDES_V3_DP_PHY_REVISION_ID2 0x008 -#define QSERDES_V3_DP_PHY_REVISION_ID3 0x00c -#define QSERDES_V3_DP_PHY_CFG 0x010 -#define QSERDES_V3_DP_PHY_PD_CTL 0x018 +/* QMP PHY - DP PHY registers */ +#define QSERDES_DP_PHY_REVISION_ID0 0x000 +#define QSERDES_DP_PHY_REVISION_ID1 0x004 +#define QSERDES_DP_PHY_REVISION_ID2 0x008 +#define QSERDES_DP_PHY_REVISION_ID3 0x00c +#define QSERDES_DP_PHY_CFG 0x010 +#define QSERDES_DP_PHY_PD_CTL 0x018 # define DP_PHY_PD_CTL_PWRDN 0x001 # define DP_PHY_PD_CTL_PSR_PWRDN 0x002 # define DP_PHY_PD_CTL_AUX_PWRDN 0x004 @@ -363,18 +363,19 @@ # define DP_PHY_PD_CTL_LANE_2_3_PWRDN 0x010 # define DP_PHY_PD_CTL_PLL_PWRDN 0x020 # define DP_PHY_PD_CTL_DP_CLAMP_EN 0x040 -#define QSERDES_V3_DP_PHY_MODE 0x01c -#define QSERDES_V3_DP_PHY_AUX_CFG0 0x020 -#define QSERDES_V3_DP_PHY_AUX_CFG1 0x024 -#define QSERDES_V3_DP_PHY_AUX_CFG2 0x028 -#define QSERDES_V3_DP_PHY_AUX_CFG3 0x02c -#define QSERDES_V3_DP_PHY_AUX_CFG4 0x030 -#define QSERDES_V3_DP_PHY_AUX_CFG5 0x034 -#define QSERDES_V3_DP_PHY_AUX_CFG6 0x038 -#define QSERDES_V3_DP_PHY_AUX_CFG7 0x03c -#define QSERDES_V3_DP_PHY_AUX_CFG8 0x040 -#define QSERDES_V3_DP_PHY_AUX_CFG9 0x044 +#define QSERDES_DP_PHY_MODE 0x01c +#define QSERDES_DP_PHY_AUX_CFG0 0x020 +#define QSERDES_DP_PHY_AUX_CFG1 0x024 +#define QSERDES_DP_PHY_AUX_CFG2 0x028 +#define QSERDES_DP_PHY_AUX_CFG3 0x02c +#define QSERDES_DP_PHY_AUX_CFG4 0x030 +#define QSERDES_DP_PHY_AUX_CFG5 0x034 +#define QSERDES_DP_PHY_AUX_CFG6 0x038 +#define QSERDES_DP_PHY_AUX_CFG7 0x03c +#define QSERDES_DP_PHY_AUX_CFG8 0x040 +#define QSERDES_DP_PHY_AUX_CFG9 0x044 +/* Only for QMP V3 PHY - DP PHY registers */ #define QSERDES_V3_DP_PHY_AUX_INTERRUPT_MASK 0x048 # define PHY_AUX_STOP_ERR_MASK 0x01 # define PHY_AUX_DEC_ERR_MASK 0x02 -- cgit v1.2.3 From aff188feb5e1f67a61808f547c4dc0e150ee8278 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 31 Mar 2021 18:16:12 +0300 Subject: phy: qcom-qmp: add support for sm8250-usb3-dp phy Add support for QMP V4 Combo USB3+DP PHY (for SM8250 platform). Signed-off-by: Dmitry Baryshkov Acked-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210331151614.3810197-6-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp.c | 394 ++++++++++++++++++++++++++++++++++-- drivers/phy/qualcomm/phy-qcom-qmp.h | 40 +++- 2 files changed, 412 insertions(+), 22 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index e1dbc9d936e7..7877f70cf86f 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -1840,6 +1840,86 @@ static const struct qmp_phy_init_tbl sm8250_usb3_uniphy_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x21), }; +static const struct qmp_phy_init_tbl qmp_v4_dp_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SVS_MODE_CLK_SEL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x3b), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYS_CLK_CTRL, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_ENABLE1, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_BUF_ENABLE, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_CONFIG, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_INTEGLOOP_GAIN0_MODE0, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_MAP, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORECLK_DIV_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_CTRL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN, 0x17), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORE_CLK_EN, 0x1f), +}; + +static const struct qmp_phy_init_tbl qmp_v4_dp_serdes_tbl_rbr[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0x69), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x6f), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x04), +}; + +static const struct qmp_phy_init_tbl qmp_v4_dp_serdes_tbl_hbr[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0x69), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x08), +}; + +static const struct qmp_phy_init_tbl qmp_v4_dp_serdes_tbl_hbr2[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0x8c), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x08), +}; + +static const struct qmp_phy_init_tbl qmp_v4_dp_serdes_tbl_hbr3[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0x69), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x2f), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x2a), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x08), +}; + +static const struct qmp_phy_init_tbl qmp_v4_dp_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_TX_VMODE_CTRL1, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_PRE_STALL_LDO_BOOST_EN, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_INTERFACE_SELECT, 0x3b), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_CLKBUF_ENABLE, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_RESET_TSYNC_EN, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_TRAN_DRVR_EMP_EN, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_PARRATE_REC_DETECT_IDLE_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_TX_INTERFACE_MODE, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_OFFSET_TX, 0x11), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_OFFSET_RX, 0x11), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_TX_BAND, 0x4), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_TX_POL_INV, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_TX_DRV_LVL, 0x2a), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_TX_EMP_POST1_LVL, 0x20), +}; + static const struct qmp_phy_init_tbl sm8250_qmp_pcie_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x08), QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_SELECT, 0x34), @@ -2436,6 +2516,11 @@ static void qcom_qmp_v3_phy_configure_dp_tx(struct qmp_phy *qphy); static int qcom_qmp_v3_phy_configure_dp_phy(struct qmp_phy *qphy); static int qcom_qmp_v3_dp_phy_calibrate(struct qmp_phy *qphy); +static void qcom_qmp_v4_phy_dp_aux_init(struct qmp_phy *qphy); +static void qcom_qmp_v4_phy_configure_dp_tx(struct qmp_phy *qphy); +static int qcom_qmp_v4_phy_configure_dp_phy(struct qmp_phy *qphy); +static int qcom_qmp_v4_dp_phy_calibrate(struct qmp_phy *qphy); + static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val) { u32 reg; @@ -3141,6 +3226,46 @@ static const struct qmp_phy_cfg sm8250_usb3_uniphy_cfg = { .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, }; +static const struct qmp_phy_cfg sm8250_dpphy_cfg = { + .type = PHY_TYPE_DP, + .nlanes = 1, + + .serdes_tbl = qmp_v4_dp_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl), + .tx_tbl = qmp_v4_dp_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(qmp_v4_dp_tx_tbl), + + .serdes_tbl_rbr = qmp_v4_dp_serdes_tbl_rbr, + .serdes_tbl_rbr_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_rbr), + .serdes_tbl_hbr = qmp_v4_dp_serdes_tbl_hbr, + .serdes_tbl_hbr_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr), + .serdes_tbl_hbr2 = qmp_v4_dp_serdes_tbl_hbr2, + .serdes_tbl_hbr2_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr2), + .serdes_tbl_hbr3 = qmp_v4_dp_serdes_tbl_hbr3, + .serdes_tbl_hbr3_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr3), + + .clk_list = qmp_v4_phy_clk_l, + .num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l), + .reset_list = msm8996_usb3phy_reset_l, + .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v4_usb3phy_regs_layout, + + .has_phy_dp_com_ctrl = true, + .is_dual_lane_phy = true, + + .dp_aux_init = qcom_qmp_v4_phy_dp_aux_init, + .configure_dp_tx = qcom_qmp_v4_phy_configure_dp_tx, + .configure_dp_phy = qcom_qmp_v4_phy_configure_dp_phy, + .calibrate_dp_phy = qcom_qmp_v4_dp_phy_calibrate, +}; + +static const struct qmp_phy_combo_cfg sm8250_usb3dpphy_cfg = { + .usb_cfg = &sm8250_usb3phy_cfg, + .dp_cfg = &sm8250_dpphy_cfg, +}; + static const struct qmp_phy_cfg sdx55_usb3_uniphy_cfg = { .type = PHY_TYPE_USB3, .nlanes = 1, @@ -3421,11 +3546,11 @@ static const u8 qmp_dp_v3_voltage_swing_hbr_rbr[4][4] = { { 0x1f, 0xff, 0xff, 0xff } }; -static void qcom_qmp_v3_phy_configure_dp_tx(struct qmp_phy *qphy) +static int qcom_qmp_phy_configure_dp_swing(struct qmp_phy *qphy, + unsigned int drv_lvl_reg, unsigned int emp_post_reg) { const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts; unsigned int v_level = 0, p_level = 0; - u32 bias_en, drvr_en; u8 voltage_swing_cfg, pre_emphasis_cfg; int i; @@ -3434,14 +3559,6 @@ static void qcom_qmp_v3_phy_configure_dp_tx(struct qmp_phy *qphy) p_level = max(p_level, dp_opts->pre[i]); } - if (dp_opts->lanes == 1) { - bias_en = 0x3e; - drvr_en = 0x13; - } else { - bias_en = 0x3f; - drvr_en = 0x10; - } - if (dp_opts->link_rate <= 2700) { voltage_swing_cfg = qmp_dp_v3_voltage_swing_hbr_rbr[v_level][p_level]; pre_emphasis_cfg = qmp_dp_v3_pre_emphasis_hbr_rbr[v_level][p_level]; @@ -3452,16 +3569,37 @@ static void qcom_qmp_v3_phy_configure_dp_tx(struct qmp_phy *qphy) /* TODO: Move check to config check */ if (voltage_swing_cfg == 0xFF && pre_emphasis_cfg == 0xFF) - return; + return -EINVAL; /* Enable MUX to use Cursor values from these registers */ voltage_swing_cfg |= DP_PHY_TXn_TX_DRV_LVL_MUX_EN; pre_emphasis_cfg |= DP_PHY_TXn_TX_EMP_POST1_LVL_MUX_EN; - writel(voltage_swing_cfg, qphy->tx + QSERDES_V3_TX_TX_DRV_LVL); - writel(pre_emphasis_cfg, qphy->tx + QSERDES_V3_TX_TX_EMP_POST1_LVL); - writel(voltage_swing_cfg, qphy->tx2 + QSERDES_V3_TX_TX_DRV_LVL); - writel(pre_emphasis_cfg, qphy->tx2 + QSERDES_V3_TX_TX_EMP_POST1_LVL); + writel(voltage_swing_cfg, qphy->tx + drv_lvl_reg); + writel(pre_emphasis_cfg, qphy->tx + emp_post_reg); + writel(voltage_swing_cfg, qphy->tx2 + drv_lvl_reg); + writel(pre_emphasis_cfg, qphy->tx2 + emp_post_reg); + + return 0; +} + +static void qcom_qmp_v3_phy_configure_dp_tx(struct qmp_phy *qphy) +{ + const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts; + u32 bias_en, drvr_en; + + if (qcom_qmp_phy_configure_dp_swing(qphy, + QSERDES_V3_TX_TX_DRV_LVL, + QSERDES_V3_TX_TX_EMP_POST1_LVL) < 0) + return; + + if (dp_opts->lanes == 1) { + bias_en = 0x3e; + drvr_en = 0x13; + } else { + bias_en = 0x3f; + drvr_en = 0x10; + } writel(drvr_en, qphy->tx + QSERDES_V3_TX_HIGHZ_DRVR_EN); writel(bias_en, qphy->tx + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN); @@ -3469,12 +3607,10 @@ static void qcom_qmp_v3_phy_configure_dp_tx(struct qmp_phy *qphy) writel(bias_en, qphy->tx2 + QSERDES_V3_TX_TRANSCEIVER_BIAS_EN); } -static int qcom_qmp_v3_phy_configure_dp_phy(struct qmp_phy *qphy) +static bool qcom_qmp_phy_configure_dp_mode(struct qmp_phy *qphy) { - const struct qmp_phy_dp_clks *dp_clks = qphy->dp_clks; - const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts; - u32 val, phy_vco_div, status; - unsigned long pixel_freq; + u32 val; + bool reverse = false; val = DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN; @@ -3497,6 +3633,19 @@ static int qcom_qmp_v3_phy_configure_dp_phy(struct qmp_phy *qphy) writel(val, qphy->pcs + QSERDES_DP_PHY_PD_CTL); writel(0x5c, qphy->pcs + QSERDES_DP_PHY_MODE); + + return reverse; +} + +static int qcom_qmp_v3_phy_configure_dp_phy(struct qmp_phy *qphy) +{ + const struct qmp_phy_dp_clks *dp_clks = qphy->dp_clks; + const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts; + u32 phy_vco_div, status; + unsigned long pixel_freq; + + qcom_qmp_phy_configure_dp_mode(qphy); + writel(0x05, qphy->pcs + QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL); writel(0x05, qphy->pcs + QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL); @@ -3579,6 +3728,204 @@ static int qcom_qmp_v3_dp_phy_calibrate(struct qmp_phy *qphy) return 0; } +static void qcom_qmp_v4_phy_dp_aux_init(struct qmp_phy *qphy) +{ + writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_PSR_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | + DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, + qphy->pcs + QSERDES_DP_PHY_PD_CTL); + + /* Turn on BIAS current for PHY/PLL */ + writel(0x17, qphy->serdes + QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN); + + writel(0x00, qphy->pcs + QSERDES_DP_PHY_AUX_CFG0); + writel(0x13, qphy->pcs + QSERDES_DP_PHY_AUX_CFG1); + writel(0xa4, qphy->pcs + QSERDES_DP_PHY_AUX_CFG2); + writel(0x00, qphy->pcs + QSERDES_DP_PHY_AUX_CFG3); + writel(0x0a, qphy->pcs + QSERDES_DP_PHY_AUX_CFG4); + writel(0x26, qphy->pcs + QSERDES_DP_PHY_AUX_CFG5); + writel(0x0a, qphy->pcs + QSERDES_DP_PHY_AUX_CFG6); + writel(0x03, qphy->pcs + QSERDES_DP_PHY_AUX_CFG7); + writel(0xb7, qphy->pcs + QSERDES_DP_PHY_AUX_CFG8); + writel(0x03, qphy->pcs + QSERDES_DP_PHY_AUX_CFG9); + qphy->dp_aux_cfg = 0; + + writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK | + PHY_AUX_SYNC_ERR_MASK | PHY_AUX_ALIGN_ERR_MASK | + PHY_AUX_REQ_ERR_MASK, + qphy->pcs + QSERDES_V4_DP_PHY_AUX_INTERRUPT_MASK); +} + +static void qcom_qmp_v4_phy_configure_dp_tx(struct qmp_phy *qphy) +{ + /* Program default values before writing proper values */ + writel(0x27, qphy->tx + QSERDES_V4_TX_TX_DRV_LVL); + writel(0x27, qphy->tx2 + QSERDES_V4_TX_TX_DRV_LVL); + + writel(0x20, qphy->tx + QSERDES_V4_TX_TX_EMP_POST1_LVL); + writel(0x20, qphy->tx2 + QSERDES_V4_TX_TX_EMP_POST1_LVL); + + qcom_qmp_phy_configure_dp_swing(qphy, + QSERDES_V4_TX_TX_DRV_LVL, + QSERDES_V4_TX_TX_EMP_POST1_LVL); +} + +static int qcom_qmp_v4_phy_configure_dp_phy(struct qmp_phy *qphy) +{ + const struct qmp_phy_dp_clks *dp_clks = qphy->dp_clks; + const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts; + u32 phy_vco_div, status; + unsigned long pixel_freq; + u32 bias0_en, drvr0_en, bias1_en, drvr1_en; + bool reverse; + + writel(0x0f, qphy->pcs + QSERDES_V4_DP_PHY_CFG_1); + + reverse = qcom_qmp_phy_configure_dp_mode(qphy); + + writel(0x13, qphy->pcs + QSERDES_DP_PHY_AUX_CFG1); + writel(0xa4, qphy->pcs + QSERDES_DP_PHY_AUX_CFG2); + + writel(0x05, qphy->pcs + QSERDES_V4_DP_PHY_TX0_TX1_LANE_CTL); + writel(0x05, qphy->pcs + QSERDES_V4_DP_PHY_TX2_TX3_LANE_CTL); + + switch (dp_opts->link_rate) { + case 1620: + phy_vco_div = 0x1; + pixel_freq = 1620000000UL / 2; + break; + case 2700: + phy_vco_div = 0x1; + pixel_freq = 2700000000UL / 2; + break; + case 5400: + phy_vco_div = 0x2; + pixel_freq = 5400000000UL / 4; + break; + case 8100: + phy_vco_div = 0x0; + pixel_freq = 8100000000UL / 6; + break; + default: + /* Other link rates aren't supported */ + return -EINVAL; + } + writel(phy_vco_div, qphy->pcs + QSERDES_V4_DP_PHY_VCO_DIV); + + clk_set_rate(dp_clks->dp_link_hw.clk, dp_opts->link_rate * 100000); + clk_set_rate(dp_clks->dp_pixel_hw.clk, pixel_freq); + + writel(0x01, qphy->pcs + QSERDES_DP_PHY_CFG); + writel(0x05, qphy->pcs + QSERDES_DP_PHY_CFG); + writel(0x01, qphy->pcs + QSERDES_DP_PHY_CFG); + writel(0x09, qphy->pcs + QSERDES_DP_PHY_CFG); + + writel(0x20, qphy->serdes + QSERDES_V4_COM_RESETSM_CNTRL); + + if (readl_poll_timeout(qphy->serdes + QSERDES_V4_COM_C_READY_STATUS, + status, + ((status & BIT(0)) > 0), + 500, + 10000)) + return -ETIMEDOUT; + + if (readl_poll_timeout(qphy->serdes + QSERDES_V4_COM_CMN_STATUS, + status, + ((status & BIT(0)) > 0), + 500, + 10000)) + return -ETIMEDOUT; + + if (readl_poll_timeout(qphy->serdes + QSERDES_V4_COM_CMN_STATUS, + status, + ((status & BIT(1)) > 0), + 500, + 10000)) + return -ETIMEDOUT; + + writel(0x19, qphy->pcs + QSERDES_DP_PHY_CFG); + + if (readl_poll_timeout(qphy->pcs + QSERDES_V4_DP_PHY_STATUS, + status, + ((status & BIT(0)) > 0), + 500, + 10000)) + return -ETIMEDOUT; + + if (readl_poll_timeout(qphy->pcs + QSERDES_V4_DP_PHY_STATUS, + status, + ((status & BIT(1)) > 0), + 500, + 10000)) + return -ETIMEDOUT; + + /* + * At least for 7nm DP PHY this has to be done after enabling link + * clock. + */ + + if (dp_opts->lanes == 1) { + bias0_en = reverse ? 0x3e : 0x15; + bias1_en = reverse ? 0x15 : 0x3e; + drvr0_en = reverse ? 0x13 : 0x10; + drvr1_en = reverse ? 0x10 : 0x13; + } else if (dp_opts->lanes == 2) { + bias0_en = reverse ? 0x3f : 0x15; + bias1_en = reverse ? 0x15 : 0x3f; + drvr0_en = 0x10; + drvr1_en = 0x10; + } else { + bias0_en = 0x3f; + bias1_en = 0x3f; + drvr0_en = 0x10; + drvr1_en = 0x10; + } + + writel(drvr0_en, qphy->tx + QSERDES_V4_TX_HIGHZ_DRVR_EN); + writel(bias0_en, qphy->tx + QSERDES_V4_TX_TRANSCEIVER_BIAS_EN); + writel(drvr1_en, qphy->tx2 + QSERDES_V4_TX_HIGHZ_DRVR_EN); + writel(bias1_en, qphy->tx2 + QSERDES_V4_TX_TRANSCEIVER_BIAS_EN); + + writel(0x18, qphy->pcs + QSERDES_DP_PHY_CFG); + udelay(2000); + writel(0x19, qphy->pcs + QSERDES_DP_PHY_CFG); + + if (readl_poll_timeout(qphy->pcs + QSERDES_V4_DP_PHY_STATUS, + status, + ((status & BIT(1)) > 0), + 500, + 10000)) + return -ETIMEDOUT; + + writel(0x0a, qphy->tx + QSERDES_V4_TX_TX_POL_INV); + writel(0x0a, qphy->tx2 + QSERDES_V4_TX_TX_POL_INV); + + writel(0x27, qphy->tx + QSERDES_V4_TX_TX_DRV_LVL); + writel(0x27, qphy->tx2 + QSERDES_V4_TX_TX_DRV_LVL); + + writel(0x20, qphy->tx + QSERDES_V4_TX_TX_EMP_POST1_LVL); + writel(0x20, qphy->tx2 + QSERDES_V4_TX_TX_EMP_POST1_LVL); + + return 0; +} + +/* + * We need to calibrate the aux setting here as many times + * as the caller tries + */ +static int qcom_qmp_v4_dp_phy_calibrate(struct qmp_phy *qphy) +{ + static const u8 cfg1_settings[] = { 0x20, 0x13, 0x23, 0x1d }; + u8 val; + + qphy->dp_aux_cfg++; + qphy->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings); + val = cfg1_settings[qphy->dp_aux_cfg]; + + writel(val, qphy->pcs + QSERDES_DP_PHY_AUX_CFG1); + + return 0; +} + static int qcom_qmp_dp_phy_configure(struct phy *phy, union phy_configure_opts *opts) { const struct phy_configure_opts_dp *dp_opts = &opts->dp; @@ -4625,6 +4972,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = { }, { .compatible = "qcom,sm8250-qmp-usb3-phy", .data = &sm8250_usb3phy_cfg, + }, { + .compatible = "qcom,sm8250-qmp-usb3-dp-phy", + /* It's a combo phy */ }, { .compatible = "qcom,sm8250-qmp-usb3-uni-phy", .data = &sm8250_usb3_uniphy_cfg, @@ -4659,6 +5009,10 @@ static const struct of_device_id qcom_qmp_combo_phy_of_match_table[] = { .compatible = "qcom,sc7180-qmp-usb3-dp-phy", .data = &sc7180_usb3dpphy_cfg, }, + { + .compatible = "qcom,sm8250-qmp-usb3-dp-phy", + .data = &sm8250_usb3dpphy_cfg, + }, { } }; diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h index 981d8ee891c0..67bd2dd0d8c5 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp.h @@ -397,6 +397,7 @@ #define QSERDES_V3_DP_PHY_STATUS 0x0c0 /* Only for QMP V4 PHY - QSERDES COM registers */ +#define QSERDES_V4_COM_BG_TIMER 0x00c #define QSERDES_V4_COM_SSC_EN_CENTER 0x010 #define QSERDES_V4_COM_SSC_PER1 0x01c #define QSERDES_V4_COM_SSC_PER2 0x020 @@ -404,7 +405,9 @@ #define QSERDES_V4_COM_SSC_STEP_SIZE2_MODE0 0x028 #define QSERDES_V4_COM_SSC_STEP_SIZE1_MODE1 0x030 #define QSERDES_V4_COM_SSC_STEP_SIZE2_MODE1 0x034 +#define QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN 0x044 #define QSERDES_V4_COM_CLK_ENABLE1 0x048 +#define QSERDES_V4_COM_SYS_CLK_CTRL 0x04c #define QSERDES_V4_COM_SYSCLK_BUF_ENABLE 0x050 #define QSERDES_V4_COM_PLL_IVCO 0x058 #define QSERDES_V4_COM_CMN_IPTRIM 0x060 @@ -415,6 +418,7 @@ #define QSERDES_V4_COM_PLL_CCTRL_MODE0 0x084 #define QSERDES_V4_COM_PLL_CCTRL_MODE1 0x088 #define QSERDES_V4_COM_SYSCLK_EN_SEL 0x094 +#define QSERDES_V4_COM_RESETSM_CNTRL 0x09c #define QSERDES_V4_COM_LOCK_CMP_EN 0x0a4 #define QSERDES_V4_COM_LOCK_CMP1_MODE0 0x0ac #define QSERDES_V4_COM_LOCK_CMP2_MODE0 0x0b0 @@ -428,16 +432,24 @@ #define QSERDES_V4_COM_DIV_FRAC_START1_MODE1 0x0d8 #define QSERDES_V4_COM_DIV_FRAC_START2_MODE1 0x0dc #define QSERDES_V4_COM_DIV_FRAC_START3_MODE1 0x0e0 +#define QSERDES_V4_COM_INTEGLOOP_GAIN0_MODE0 0x0ec +#define QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE0 0x0f0 +#define QSERDES_V4_COM_VCO_TUNE_CTRL 0x108 #define QSERDES_V4_COM_VCO_TUNE_MAP 0x10c #define QSERDES_V4_COM_VCO_TUNE1_MODE0 0x110 #define QSERDES_V4_COM_VCO_TUNE2_MODE0 0x114 #define QSERDES_V4_COM_VCO_TUNE1_MODE1 0x118 #define QSERDES_V4_COM_VCO_TUNE2_MODE1 0x11c #define QSERDES_V4_COM_VCO_TUNE_INITVAL2 0x124 +#define QSERDES_V4_COM_CMN_STATUS 0x140 #define QSERDES_V4_COM_CLK_SELECT 0x154 #define QSERDES_V4_COM_HSCLK_SEL 0x158 #define QSERDES_V4_COM_HSCLK_HS_SWITCH_SEL 0x15c +#define QSERDES_V4_COM_CORECLK_DIV_MODE0 0x168 #define QSERDES_V4_COM_CORECLK_DIV_MODE1 0x16c +#define QSERDES_V4_COM_CORE_CLK_EN 0x174 +#define QSERDES_V4_COM_C_READY_STATUS 0x178 +#define QSERDES_V4_COM_CMN_CONFIG 0x17c #define QSERDES_V4_COM_SVS_MODE_CLK_SEL 0x184 #define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE0 0x1ac #define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE0 0x1b0 @@ -446,19 +458,32 @@ #define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE1 0x1b8 /* Only for QMP V4 PHY - TX registers */ +#define QSERDES_V4_TX_CLKBUF_ENABLE 0x08 +#define QSERDES_V4_TX_TX_EMP_POST1_LVL 0x0c +#define QSERDES_V4_TX_TX_DRV_LVL 0x14 +#define QSERDES_V4_TX_RESET_TSYNC_EN 0x1c +#define QSERDES_V4_TX_PRE_STALL_LDO_BOOST_EN 0x20 +#define QSERDES_V4_TX_TX_BAND 0x24 +#define QSERDES_V4_TX_INTERFACE_SELECT 0x2c #define QSERDES_V4_TX_RES_CODE_LANE_TX 0x34 #define QSERDES_V4_TX_RES_CODE_LANE_RX 0x38 #define QSERDES_V4_TX_RES_CODE_LANE_OFFSET_TX 0x3c #define QSERDES_V4_TX_RES_CODE_LANE_OFFSET_RX 0x40 +#define QSERDES_V4_TX_TRANSCEIVER_BIAS_EN 0x54 +#define QSERDES_V4_TX_HIGHZ_DRVR_EN 0x58 +#define QSERDES_V4_TX_TX_POL_INV 0x5c +#define QSERDES_V4_TX_PARRATE_REC_DETECT_IDLE_EN 0x60 #define QSERDES_V4_TX_LANE_MODE_1 0x84 #define QSERDES_V4_TX_LANE_MODE_2 0x88 #define QSERDES_V4_TX_RCV_DETECT_LVL_2 0x9c +#define QSERDES_V4_TX_TRAN_DRVR_EMP_EN 0xb8 +#define QSERDES_V4_TX_TX_INTERFACE_MODE 0xbc #define QSERDES_V4_TX_PWM_GEAR_1_DIVIDER_BAND0_1 0xd8 #define QSERDES_V4_TX_PWM_GEAR_2_DIVIDER_BAND0_1 0xdC #define QSERDES_V4_TX_PWM_GEAR_3_DIVIDER_BAND0_1 0xe0 #define QSERDES_V4_TX_PWM_GEAR_4_DIVIDER_BAND0_1 0xe4 -#define QSERDES_V4_TX_TRAN_DRVR_EMP_EN 0xb8 -#define QSERDES_V4_TX_PI_QEC_CTRL 0x104 +#define QSERDES_V4_TX_VMODE_CTRL1 0xe8 +#define QSERDES_V4_TX_PI_QEC_CTRL 0x104 /* Only for QMP V4 PHY - RX registers */ #define QSERDES_V4_RX_UCDR_FO_GAIN 0x008 @@ -515,6 +540,17 @@ #define QSERDES_V4_RX_DCC_CTRL1 0x1bc #define QSERDES_V4_RX_VTH_CODE 0x1c4 +/* Only for QMP V4 PHY - DP PHY registers */ +#define QSERDES_V4_DP_PHY_CFG_1 0x014 +#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_MASK 0x054 +#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_CLEAR 0x058 +#define QSERDES_V4_DP_PHY_VCO_DIV 0x070 +#define QSERDES_V4_DP_PHY_TX0_TX1_LANE_CTL 0x078 +#define QSERDES_V4_DP_PHY_TX2_TX3_LANE_CTL 0x09c +#define QSERDES_V4_DP_PHY_SPARE0 0x0c8 +#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_STATUS 0x0d8 +#define QSERDES_V4_DP_PHY_STATUS 0x0dc + /* Only for QMP V4 PHY - UFS PCS registers */ #define QPHY_V4_PCS_UFS_PHY_START 0x000 #define QPHY_V4_PCS_UFS_POWER_DOWN_CONTROL 0x004 -- cgit v1.2.3 From 1a42aef2588052c4e3f7df241b947425641f05c9 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Wed, 31 Mar 2021 11:34:24 -0700 Subject: bus: mhi: core: Introduce internal register poll helper function Introduce helper function to allow MHI core driver to poll for a value in a register field. This helps reach a common path to read and poll register values along with a retry time interval. Signed-off-by: Bhaumik Bhatt Reviewed-by: Loic Poulain Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1617215665-19593-2-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/internal.h | 3 +++ drivers/bus/mhi/core/main.c | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/drivers/bus/mhi/core/internal.h b/drivers/bus/mhi/core/internal.h index 7aa5cfd874e4..e690f154212f 100644 --- a/drivers/bus/mhi/core/internal.h +++ b/drivers/bus/mhi/core/internal.h @@ -646,6 +646,9 @@ int __must_check mhi_read_reg(struct mhi_controller *mhi_cntrl, int __must_check mhi_read_reg_field(struct mhi_controller *mhi_cntrl, void __iomem *base, u32 offset, u32 mask, u32 shift, u32 *out); +int __must_check mhi_poll_reg_field(struct mhi_controller *mhi_cntrl, + void __iomem *base, u32 offset, u32 mask, + u32 shift, u32 val, u32 delayus); void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *base, u32 offset, u32 val); void mhi_write_reg_field(struct mhi_controller *mhi_cntrl, void __iomem *base, diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index 8b68657c76c3..58b8111ce66c 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -4,6 +4,7 @@ * */ +#include #include #include #include @@ -37,6 +38,28 @@ int __must_check mhi_read_reg_field(struct mhi_controller *mhi_cntrl, return 0; } +int __must_check mhi_poll_reg_field(struct mhi_controller *mhi_cntrl, + void __iomem *base, u32 offset, + u32 mask, u32 shift, u32 val, u32 delayus) +{ + int ret; + u32 out, retry = (mhi_cntrl->timeout_ms * 1000) / delayus; + + while (retry--) { + ret = mhi_read_reg_field(mhi_cntrl, base, offset, mask, shift, + &out); + if (ret) + return ret; + + if (out == val) + return 0; + + fsleep(delayus); + } + + return -ETIMEDOUT; +} + void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *base, u32 offset, u32 val) { -- cgit v1.2.3 From 79d056976485baaa6225ff2331b83084051c98a8 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Wed, 31 Mar 2021 11:34:25 -0700 Subject: bus: mhi: core: Move to polling method to wait for MHI ready In certain devices, it is likely that there is no incoming MHI interrupt for a transition to MHI READY state. One such example is the move from Pass Through to an SBL or AMSS execution environment. In order to facilitate faster bootup times as there is no need to wait until timeout_ms completes, MHI host can poll every 25 milliseconds to check if device has entered MHI READY until a maximum timeout of twice the timeout_ms is reached. Signed-off-by: Bhaumik Bhatt Reviewed-by: Loic Poulain Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1617215665-19593-3-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/pm.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c index b6920a5369a0..e4aff777d74b 100644 --- a/drivers/bus/mhi/core/pm.c +++ b/drivers/bus/mhi/core/pm.c @@ -153,35 +153,33 @@ static void mhi_toggle_dev_wake(struct mhi_controller *mhi_cntrl) /* Handle device ready state transition */ int mhi_ready_state_transition(struct mhi_controller *mhi_cntrl) { - void __iomem *base = mhi_cntrl->regs; struct mhi_event *mhi_event; enum mhi_pm_state cur_state; struct device *dev = &mhi_cntrl->mhi_dev->dev; - u32 reset = 1, ready = 0; + u32 interval_us = 25000; /* poll register field every 25 milliseconds */ int ret, i; - /* Wait for RESET to be cleared and READY bit to be set by the device */ - wait_event_timeout(mhi_cntrl->state_event, - MHI_PM_IN_FATAL_STATE(mhi_cntrl->pm_state) || - mhi_read_reg_field(mhi_cntrl, base, MHICTRL, - MHICTRL_RESET_MASK, - MHICTRL_RESET_SHIFT, &reset) || - mhi_read_reg_field(mhi_cntrl, base, MHISTATUS, - MHISTATUS_READY_MASK, - MHISTATUS_READY_SHIFT, &ready) || - (!reset && ready), - msecs_to_jiffies(mhi_cntrl->timeout_ms)); - /* Check if device entered error state */ if (MHI_PM_IN_FATAL_STATE(mhi_cntrl->pm_state)) { dev_err(dev, "Device link is not accessible\n"); return -EIO; } - /* Timeout if device did not transition to ready state */ - if (reset || !ready) { - dev_err(dev, "Device Ready timeout\n"); - return -ETIMEDOUT; + /* Wait for RESET to be cleared and READY bit to be set by the device */ + ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL, + MHICTRL_RESET_MASK, MHICTRL_RESET_SHIFT, 0, + interval_us); + if (ret) { + dev_err(dev, "Device failed to clear MHI Reset\n"); + return ret; + } + + ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHISTATUS, + MHISTATUS_READY_MASK, MHISTATUS_READY_SHIFT, 1, + interval_us); + if (ret) { + dev_err(dev, "Device failed to enter MHI Ready\n"); + return ret; } dev_dbg(dev, "Device in READY State\n"); -- cgit v1.2.3 From b26b48749b18eedb079866c94c4ea99e6a9ef52c Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Wed, 31 Mar 2021 21:25:20 +0530 Subject: soundwire: qcom: use signed variable for error return We get warning of using a unsigned variable being compared to less than zero. The comparison is correct as it checks for errors from previous call to qcom_swrm_get_alert_slave_dev_num(), so we should use a signed variable here. While at it, drop the superfluous initialization as well drivers/soundwire/qcom.c: qcom_swrm_irq_handler() warn: impossible condition '(devnum < 0) => (0-255 < 0)' Reported-by: kernel test robot Signed-off-by: Vinod Koul Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210331155520.2987823-1-vkoul@kernel.org Signed-off-by: Vinod Koul --- drivers/soundwire/qcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index b08ecb9b418c..ec86c4e53fdb 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -428,7 +428,7 @@ static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id) struct qcom_swrm_ctrl *swrm = dev_id; u32 value, intr_sts, intr_sts_masked, slave_status; u32 i; - u8 devnum = 0; + int devnum; int ret = IRQ_HANDLED; swrm->reg_read(swrm, SWRM_INTERRUPT_STATUS, &intr_sts); -- cgit v1.2.3 From 7014dfee4e83348d04c450c698ae29add6e9f58f Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Fri, 2 Apr 2021 12:59:07 +0300 Subject: interconnect: qcom: sdm660: Fix kerneldoc warning Fix the following warning: sdm660.c:191:warning: Function parameter or member 'regmap' not described in 'qcom_icc_provider' Link: https://lore.kernel.org/r/20210401094714.29075-1-georgi.djakov@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/sdm660.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/interconnect/qcom/sdm660.c b/drivers/interconnect/qcom/sdm660.c index 6953d6d99a11..632dbdd21915 100644 --- a/drivers/interconnect/qcom/sdm660.c +++ b/drivers/interconnect/qcom/sdm660.c @@ -179,6 +179,7 @@ static const struct clk_bulk_data bus_mm_clocks[] = { * @bus_clks: the clk_bulk_data table of bus clocks * @num_clks: the total number of clk_bulk_data entries * @is_bimc_node: indicates whether to use bimc specific setting + * @regmap: regmap for QoS registers read/write access * @mmio: NoC base iospace */ struct qcom_icc_provider { -- cgit v1.2.3 From 7a3aad40c68a9968ff4e8067098422208f04d8ed Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Fri, 2 Apr 2021 13:09:07 +0300 Subject: interconnect: qcom: sm8350: Use the correct ids For creating an array with the members for each NoC, we should be using a local indexes, as otherwise unnecessary large arrays would be created. Using an incorrect indexes will also result error for the consumers when they try to find a valid path between the endpoints. Let's fix this and use the correct ids. Reported-by: Alex Elder Acked-by: Alex Elder Link: https://lore.kernel.org/r/20210401094334.28871-1-georgi.djakov@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/sm8350.c | 80 +++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/drivers/interconnect/qcom/sm8350.c b/drivers/interconnect/qcom/sm8350.c index f3aab02b8678..01202989a5b2 100644 --- a/drivers/interconnect/qcom/sm8350.c +++ b/drivers/interconnect/qcom/sm8350.c @@ -228,20 +228,20 @@ static struct qcom_icc_bcm *aggre2_noc_bcms[] = { }; static struct qcom_icc_node *aggre2_noc_nodes[] = { - [SM8350_MASTER_QDSS_BAM] = &qhm_qdss_bam, - [SM8350_MASTER_QUP_0] = &qhm_qup0, - [SM8350_MASTER_QUP_2] = &qhm_qup2, - [SM8350_MASTER_A2NOC_CFG] = &qnm_a2noc_cfg, - [SM8350_MASTER_CRYPTO] = &qxm_crypto, - [SM8350_MASTER_IPA] = &qxm_ipa, - [SM8350_MASTER_PCIE_0] = &xm_pcie3_0, - [SM8350_MASTER_PCIE_1] = &xm_pcie3_1, - [SM8350_MASTER_QDSS_ETR] = &xm_qdss_etr, - [SM8350_MASTER_SDCC_2] = &xm_sdc2, - [SM8350_MASTER_UFS_CARD] = &xm_ufs_card, - [SM8350_SLAVE_A2NOC_SNOC] = &qns_a2noc_snoc, - [SM8350_SLAVE_ANOC_PCIE_GEM_NOC] = &qns_pcie_mem_noc, - [SM8350_SLAVE_SERVICE_A2NOC] = &srvc_aggre2_noc, + [MASTER_QDSS_BAM] = &qhm_qdss_bam, + [MASTER_QUP_0] = &qhm_qup0, + [MASTER_QUP_2] = &qhm_qup2, + [MASTER_A2NOC_CFG] = &qnm_a2noc_cfg, + [MASTER_CRYPTO] = &qxm_crypto, + [MASTER_IPA] = &qxm_ipa, + [MASTER_PCIE_0] = &xm_pcie3_0, + [MASTER_PCIE_1] = &xm_pcie3_1, + [MASTER_QDSS_ETR] = &xm_qdss_etr, + [MASTER_SDCC_2] = &xm_sdc2, + [MASTER_UFS_CARD] = &xm_ufs_card, + [SLAVE_A2NOC_SNOC] = &qns_a2noc_snoc, + [SLAVE_ANOC_PCIE_GEM_NOC] = &qns_pcie_mem_noc, + [SLAVE_SERVICE_A2NOC] = &srvc_aggre2_noc, }; static struct qcom_icc_desc sm8350_aggre2_noc = { @@ -414,10 +414,10 @@ static struct qcom_icc_bcm *mc_virt_bcms[] = { }; static struct qcom_icc_node *mc_virt_nodes[] = { - [SM8350_MASTER_LLCC] = &llcc_mc, - [SM8350_SLAVE_EBI1] = &ebi, - [SM8350_MASTER_LLCC_DISP] = &llcc_mc_disp, - [SM8350_SLAVE_EBI1_DISP] = &ebi_disp, + [MASTER_LLCC] = &llcc_mc, + [SLAVE_EBI1] = &ebi, + [MASTER_LLCC_DISP] = &llcc_mc_disp, + [SLAVE_EBI1_DISP] = &ebi_disp, }; static struct qcom_icc_desc sm8350_mc_virt = { @@ -439,24 +439,24 @@ static struct qcom_icc_bcm *mmss_noc_bcms[] = { }; static struct qcom_icc_node *mmss_noc_nodes[] = { - [SM8350_MASTER_CAMNOC_HF] = &qnm_camnoc_hf, - [SM8350_MASTER_CAMNOC_ICP] = &qnm_camnoc_icp, - [SM8350_MASTER_CAMNOC_SF] = &qnm_camnoc_sf, - [SM8350_MASTER_CNOC_MNOC_CFG] = &qnm_mnoc_cfg, - [SM8350_MASTER_VIDEO_P0] = &qnm_video0, - [SM8350_MASTER_VIDEO_P1] = &qnm_video1, - [SM8350_MASTER_VIDEO_PROC] = &qnm_video_cvp, - [SM8350_MASTER_MDP0] = &qxm_mdp0, - [SM8350_MASTER_MDP1] = &qxm_mdp1, - [SM8350_MASTER_ROTATOR] = &qxm_rot, - [SM8350_SLAVE_MNOC_HF_MEM_NOC] = &qns_mem_noc_hf, - [SM8350_SLAVE_MNOC_SF_MEM_NOC] = &qns_mem_noc_sf, - [SM8350_SLAVE_SERVICE_MNOC] = &srvc_mnoc, - [SM8350_MASTER_MDP0_DISP] = &qxm_mdp0_disp, - [SM8350_MASTER_MDP1_DISP] = &qxm_mdp1_disp, - [SM8350_MASTER_ROTATOR_DISP] = &qxm_rot_disp, - [SM8350_SLAVE_MNOC_HF_MEM_NOC_DISP] = &qns_mem_noc_hf_disp, - [SM8350_SLAVE_MNOC_SF_MEM_NOC_DISP] = &qns_mem_noc_sf_disp, + [MASTER_CAMNOC_HF] = &qnm_camnoc_hf, + [MASTER_CAMNOC_ICP] = &qnm_camnoc_icp, + [MASTER_CAMNOC_SF] = &qnm_camnoc_sf, + [MASTER_CNOC_MNOC_CFG] = &qnm_mnoc_cfg, + [MASTER_VIDEO_P0] = &qnm_video0, + [MASTER_VIDEO_P1] = &qnm_video1, + [MASTER_VIDEO_PROC] = &qnm_video_cvp, + [MASTER_MDP0] = &qxm_mdp0, + [MASTER_MDP1] = &qxm_mdp1, + [MASTER_ROTATOR] = &qxm_rot, + [SLAVE_MNOC_HF_MEM_NOC] = &qns_mem_noc_hf, + [SLAVE_MNOC_SF_MEM_NOC] = &qns_mem_noc_sf, + [SLAVE_SERVICE_MNOC] = &srvc_mnoc, + [MASTER_MDP0_DISP] = &qxm_mdp0_disp, + [MASTER_MDP1_DISP] = &qxm_mdp1_disp, + [MASTER_ROTATOR_DISP] = &qxm_rot_disp, + [SLAVE_MNOC_HF_MEM_NOC_DISP] = &qns_mem_noc_hf_disp, + [SLAVE_MNOC_SF_MEM_NOC_DISP] = &qns_mem_noc_sf_disp, }; static struct qcom_icc_desc sm8350_mmss_noc = { @@ -472,10 +472,10 @@ static struct qcom_icc_bcm *nsp_noc_bcms[] = { }; static struct qcom_icc_node *nsp_noc_nodes[] = { - [SM8350_MASTER_CDSP_NOC_CFG] = &qhm_nsp_noc_config, - [SM8350_MASTER_CDSP_PROC] = &qxm_nsp, - [SM8350_SLAVE_CDSP_MEM_NOC] = &qns_nsp_gemnoc, - [SM8350_SLAVE_SERVICE_NSP_NOC] = &service_nsp_noc, + [MASTER_CDSP_NOC_CFG] = &qhm_nsp_noc_config, + [MASTER_CDSP_PROC] = &qxm_nsp, + [SLAVE_CDSP_MEM_NOC] = &qns_nsp_gemnoc, + [SLAVE_SERVICE_NSP_NOC] = &service_nsp_noc, }; static struct qcom_icc_desc sm8350_compute_noc = { -- cgit v1.2.3 From 91b940526b84601dfd26da410da6e4d60bda91a6 Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Fri, 2 Apr 2021 13:09:07 +0300 Subject: interconnect: qcom: sm8350: Add missing link between nodes There is a link between the GEM NoC and C NoC nodes, which is currently missing from the topology. Let's add it to allow consumers request paths that use this link. Reported-by: Alex Elder Tested-by: Alex Elder Link: https://lore.kernel.org/r/20210401094435.28937-1-georgi.djakov@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/sm8350.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/interconnect/qcom/sm8350.c b/drivers/interconnect/qcom/sm8350.c index 01202989a5b2..579b6ce8e046 100644 --- a/drivers/interconnect/qcom/sm8350.c +++ b/drivers/interconnect/qcom/sm8350.c @@ -139,7 +139,7 @@ DEFINE_QNODE(qhs_llcc, SM8350_SLAVE_LLCC_CFG, 1, 4); DEFINE_QNODE(qns_gemnoc, SM8350_SLAVE_GEM_NOC_CFG, 1, 4); DEFINE_QNODE(qhs_mdsp_ms_mpu_cfg, SM8350_SLAVE_MSS_PROC_MS_MPU_CFG, 1, 4); DEFINE_QNODE(qhs_modem_ms_mpu_cfg, SM8350_SLAVE_MCDMA_MS_MPU_CFG, 1, 4); -DEFINE_QNODE(qns_gem_noc_cnoc, SM8350_SLAVE_GEM_NOC_CNOC, 1, 16); +DEFINE_QNODE(qns_gem_noc_cnoc, SM8350_SLAVE_GEM_NOC_CNOC, 1, 16, SM8350_MASTER_GEM_NOC_CNOC); DEFINE_QNODE(qns_llcc, SM8350_SLAVE_LLCC, 4, 16, SM8350_MASTER_LLCC); DEFINE_QNODE(qns_pcie, SM8350_SLAVE_MEM_NOC_PCIE_SNOC, 1, 8); DEFINE_QNODE(srvc_even_gemnoc, SM8350_SLAVE_SERVICE_GEM_NOC_1, 1, 4); -- cgit v1.2.3 From 642fa28bb5ee2cf72e7d86b2fa9d06f2b04c9fb3 Mon Sep 17 00:00:00 2001 From: Qiheng Lin Date: Tue, 30 Mar 2021 09:36:59 +0800 Subject: misc/pvpanic: fix return value check in pvpanic_pci_probe() In case of error, the function pci_iomap() returns NULL pointer not ERR_PTR(). The IS_ERR() test in the return value check should be replaced with NULL test. Reported-by: Hulk Robot Signed-off-by: Qiheng Lin Link: https://lore.kernel.org/r/20210330013659.916-1-linqiheng@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/pvpanic/pvpanic-pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/pvpanic/pvpanic-pci.c b/drivers/misc/pvpanic/pvpanic-pci.c index f38a80a5bbc8..9ecc4e8559d5 100644 --- a/drivers/misc/pvpanic/pvpanic-pci.c +++ b/drivers/misc/pvpanic/pvpanic-pci.c @@ -83,8 +83,8 @@ static int pvpanic_pci_probe(struct pci_dev *pdev, return ret; base = pci_iomap(pdev, 0, 0); - if (IS_ERR(base)) - return PTR_ERR(base); + if (!base) + return -ENOMEM; pi = kmalloc(sizeof(*pi), GFP_ATOMIC); if (!pi) -- cgit v1.2.3 From 391e2415e9668a47d423c6c935a25340f02b0685 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 31 Mar 2021 20:17:06 +0800 Subject: misc/pvpanic: Make some symbols static Fix sparse warnings: drivers/misc/pvpanic/pvpanic.c:28:18: warning: symbol 'pvpanic_list' was not declared. Should it be static? drivers/misc/pvpanic/pvpanic.c:29:12: warning: symbol 'pvpanic_lock' was not declared. Should it be static? Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20210331121706.15268-1-yuehaibing@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/pvpanic/pvpanic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/pvpanic/pvpanic.c b/drivers/misc/pvpanic/pvpanic.c index 804099c2d7fa..65f70a4da8c0 100644 --- a/drivers/misc/pvpanic/pvpanic.c +++ b/drivers/misc/pvpanic/pvpanic.c @@ -25,8 +25,8 @@ MODULE_AUTHOR("Mihai Carabas "); MODULE_DESCRIPTION("pvpanic device driver "); MODULE_LICENSE("GPL"); -struct list_head pvpanic_list; -spinlock_t pvpanic_lock; +static struct list_head pvpanic_list; +static spinlock_t pvpanic_lock; static void pvpanic_send_event(unsigned int event) -- cgit v1.2.3 From cb4a2d5486b80cf23f11729cd5933f6e2b72a3c1 Mon Sep 17 00:00:00 2001 From: Matt Hsiao Date: Mon, 29 Mar 2021 10:53:52 +0800 Subject: misc: hpilo: MAINTAINERS: add entry for hpilo The original maintainer left the company, add myself as the successor. Signed-off-by: Matt Hsiao Link: https://lore.kernel.org/r/20210329025352.21485-1-matt.hsiao@hpe.com Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index fca4a9f8f065..fd53ff52ba61 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7893,6 +7893,11 @@ W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git F: drivers/media/usb/hdpvr/ +HEWLETT PACKARD ENTERPRISE ILO CHIF DRIVER +M: Matt Hsiao +S: Supported +F: drivers/misc/hpilo.[ch] + HEWLETT PACKARD ENTERPRISE ILO NMI WATCHDOG DRIVER M: Jerry Hoemann S: Supported -- cgit v1.2.3 From 012ac583aa9b512707b39b5a9afb303089a222fe Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Fri, 26 Mar 2021 16:22:54 +0100 Subject: greybus: remove stray nul byte in apb_log_enable_read output Including a nul byte in the otherwise human-readable ascii output from this debugfs file is probably not intended. Acked-by: Alex Elder Signed-off-by: Rasmus Villemoes Link: https://lore.kernel.org/r/20210326152254.733066-1-linux@rasmusvillemoes.dk Signed-off-by: Greg Kroah-Hartman --- drivers/greybus/es2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/greybus/es2.c b/drivers/greybus/es2.c index 48ad154df3a7..86a7fbc7fe13 100644 --- a/drivers/greybus/es2.c +++ b/drivers/greybus/es2.c @@ -1171,7 +1171,7 @@ static ssize_t apb_log_enable_read(struct file *f, char __user *buf, char tmp_buf[3]; sprintf(tmp_buf, "%d\n", enable); - return simple_read_from_buffer(buf, count, ppos, tmp_buf, 3); + return simple_read_from_buffer(buf, count, ppos, tmp_buf, 2); } static ssize_t apb_log_enable_write(struct file *f, const char __user *buf, -- cgit v1.2.3 From c23146e15e570e64b5d8d0ce3b7b82a0bc00ff8f Mon Sep 17 00:00:00 2001 From: Brad Warrum Date: Tue, 30 Mar 2021 16:22:38 -0500 Subject: MAINTAINERS: Update entry for ibmvmc driver Steve Royer has moved on to a different project and has asked that Ritu and I take over maintainership of the IBM Power Virtual Management Channel Driver. Signed-off-by: Brad Warrum Acked-by: Steven Royer Link: https://lore.kernel.org/r/20210330212238.2747-1-bwarrum@linux.ibm.com Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index fd53ff52ba61..f3a745f57a16 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8552,7 +8552,8 @@ S: Supported F: drivers/scsi/ibmvscsi/ibmvfc* IBM Power Virtual Management Channel Driver -M: Steven Royer +M: Brad Warrum +M: Ritu Agarwal S: Supported F: drivers/misc/ibmvmc.* -- cgit v1.2.3 From 2c4134e78203eb3a1506f9fc51012a3fda4068cb Mon Sep 17 00:00:00 2001 From: Shixin Liu Date: Mon, 29 Mar 2021 17:40:14 +0800 Subject: drivers: most: use DEFINE_SPINLOCK() for spinlock spinlock can be initialized automatically with DEFINE_SPINLOCK() rather than explicitly calling spin_lock_init(). Signed-off-by: Shixin Liu Link: https://lore.kernel.org/r/20210329094015.66942-1-liushixin2@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/most/most_cdev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/most/most_cdev.c b/drivers/most/most_cdev.c index 044880760b58..8b69cf3ca60b 100644 --- a/drivers/most/most_cdev.c +++ b/drivers/most/most_cdev.c @@ -45,7 +45,7 @@ struct comp_channel { #define to_channel(d) container_of(d, struct comp_channel, cdev) static struct list_head channel_list; -static spinlock_t ch_list_lock; +static DEFINE_SPINLOCK(ch_list_lock); static inline bool ch_has_mbo(struct comp_channel *c) { @@ -495,7 +495,6 @@ static int __init mod_init(void) return PTR_ERR(comp.class); INIT_LIST_HEAD(&channel_list); - spin_lock_init(&ch_list_lock); ida_init(&comp.minor_id); err = alloc_chrdev_region(&comp.devno, 0, CHRDEV_REGION_SIZE, "cdev"); -- cgit v1.2.3 From 5751564085e70caf4a5fb31d75cbaeaa723a7511 Mon Sep 17 00:00:00 2001 From: Shixin Liu Date: Mon, 29 Mar 2021 17:40:15 +0800 Subject: drivers: most: use LIST_HEAD() for list_head There's no need to declare a list and then init it manually, just use the LIST_HEAD() macro. Signed-off-by: Shixin Liu Link: https://lore.kernel.org/r/20210329094015.66942-2-liushixin2@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/most/most_cdev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/most/most_cdev.c b/drivers/most/most_cdev.c index 8b69cf3ca60b..8908b9363a96 100644 --- a/drivers/most/most_cdev.c +++ b/drivers/most/most_cdev.c @@ -44,7 +44,7 @@ struct comp_channel { }; #define to_channel(d) container_of(d, struct comp_channel, cdev) -static struct list_head channel_list; +static LIST_HEAD(channel_list); static DEFINE_SPINLOCK(ch_list_lock); static inline bool ch_has_mbo(struct comp_channel *c) @@ -494,7 +494,6 @@ static int __init mod_init(void) if (IS_ERR(comp.class)) return PTR_ERR(comp.class); - INIT_LIST_HEAD(&channel_list); ida_init(&comp.minor_id); err = alloc_chrdev_region(&comp.devno, 0, CHRDEV_REGION_SIZE, "cdev"); -- cgit v1.2.3 From 2a1405a14c3a741cc6a9154422b852fbafed6c9a Mon Sep 17 00:00:00 2001 From: Ryan Wu Date: Tue, 30 Mar 2021 12:12:32 +0100 Subject: dt-bindings: nvmem: mediatek: add support for MediaTek mt8192 SoC This updates dt-binding documentation for MediaTek mt8192 Acked-by: Rob Herring Signed-off-by: Ryan Wu Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210330111241.19401-2-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/nvmem/mtk-efuse.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/nvmem/mtk-efuse.txt b/Documentation/devicetree/bindings/nvmem/mtk-efuse.txt index ef93c3b95424..2f2895b1f06d 100644 --- a/Documentation/devicetree/bindings/nvmem/mtk-efuse.txt +++ b/Documentation/devicetree/bindings/nvmem/mtk-efuse.txt @@ -8,6 +8,7 @@ Required properties: "mediatek,mt7623-efuse", "mediatek,efuse": for MT7623 "mediatek,mt8173-efuse" or "mediatek,efuse": for MT8173 "mediatek,mt8516-efuse", "mediatek,efuse": for MT8516 + "mediatek,mt8192-efuse", "mediatek,efuse": for MT8192 - reg: Should contain registers location and length = Data cells = -- cgit v1.2.3 From e050f160d4832ce5227fb6ca934969cec0fc48be Mon Sep 17 00:00:00 2001 From: Zheng Yongjun Date: Tue, 30 Mar 2021 12:12:33 +0100 Subject: nvmem: convert comma to semicolon Replace a comma between expression statements by a semicolon. Reviewed-by: Bjorn Andersson Signed-off-by: Zheng Yongjun Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210330111241.19401-3-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/qcom-spmi-sdam.c | 2 +- drivers/nvmem/snvs_lpgpr.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/nvmem/qcom-spmi-sdam.c b/drivers/nvmem/qcom-spmi-sdam.c index f6e9f96933ca..4fcb63507ecd 100644 --- a/drivers/nvmem/qcom-spmi-sdam.c +++ b/drivers/nvmem/qcom-spmi-sdam.c @@ -141,7 +141,7 @@ static int sdam_probe(struct platform_device *pdev) sdam->sdam_config.dev = &pdev->dev; sdam->sdam_config.name = "spmi_sdam"; sdam->sdam_config.id = NVMEM_DEVID_AUTO; - sdam->sdam_config.owner = THIS_MODULE, + sdam->sdam_config.owner = THIS_MODULE; sdam->sdam_config.stride = 1; sdam->sdam_config.word_size = 1; sdam->sdam_config.reg_read = sdam_read; diff --git a/drivers/nvmem/snvs_lpgpr.c b/drivers/nvmem/snvs_lpgpr.c index c527d26ca6ac..4692aa985bd6 100644 --- a/drivers/nvmem/snvs_lpgpr.c +++ b/drivers/nvmem/snvs_lpgpr.c @@ -123,7 +123,7 @@ static int snvs_lpgpr_probe(struct platform_device *pdev) cfg->dev = dev; cfg->stride = 4; cfg->word_size = 4; - cfg->size = dcfg->size, + cfg->size = dcfg->size; cfg->owner = THIS_MODULE; cfg->reg_read = snvs_lpgpr_read; cfg->reg_write = snvs_lpgpr_write; -- cgit v1.2.3 From 9ec4f4b0e9fd3ad4b9a38bddb75b516ea09f4628 Mon Sep 17 00:00:00 2001 From: Ravi Kumar Bokka Date: Tue, 30 Mar 2021 12:12:34 +0100 Subject: drivers: nvmem: Fix voltage settings for QTI qfprom-efuse QFPROM controller hardware requires 1.8V min for fuse blowing. So, this change sets the voltage to 1.8V, required to blow the fuse for qfprom-efuse controller. To disable fuse blowing, we set the voltage to 0V since this may be a shared rail and may be able to run at a lower rate when we're not blowing fuses. Fixes: 93b4e49f8c86 ("nvmem: qfprom: Add fuse blowing support") Reported-by: Douglas Anderson Suggested-by: Douglas Anderson Reviewed-by: Douglas Anderson Signed-off-by: Ravi Kumar Bokka Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210330111241.19401-4-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/qfprom.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c index 6cace24dfbf7..100d69d8f2e1 100644 --- a/drivers/nvmem/qfprom.c +++ b/drivers/nvmem/qfprom.c @@ -127,6 +127,16 @@ static void qfprom_disable_fuse_blowing(const struct qfprom_priv *priv, { int ret; + /* + * This may be a shared rail and may be able to run at a lower rate + * when we're not blowing fuses. At the moment, the regulator framework + * applies voltage constraints even on disabled rails, so remove our + * constraints and allow the rail to be adjusted by other users. + */ + ret = regulator_set_voltage(priv->vcc, 0, INT_MAX); + if (ret) + dev_warn(priv->dev, "Failed to set 0 voltage (ignoring)\n"); + ret = regulator_disable(priv->vcc); if (ret) dev_warn(priv->dev, "Failed to disable regulator (ignoring)\n"); @@ -172,6 +182,17 @@ static int qfprom_enable_fuse_blowing(const struct qfprom_priv *priv, goto err_clk_prepared; } + /* + * Hardware requires 1.8V min for fuse blowing; this may be + * a rail shared do don't specify a max--regulator constraints + * will handle. + */ + ret = regulator_set_voltage(priv->vcc, 1800000, INT_MAX); + if (ret) { + dev_err(priv->dev, "Failed to set 1.8 voltage\n"); + goto err_clk_rate_set; + } + ret = regulator_enable(priv->vcc); if (ret) { dev_err(priv->dev, "Failed to enable regulator\n"); -- cgit v1.2.3 From 5783bd1970b3046cd3b4493138155a5a22fde873 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Tue, 30 Mar 2021 12:12:35 +0100 Subject: dt-bindings: nvmem: add Broadcom's NVRAM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Broadcom's NVRAM structure contains device data and can be accessed using I/O mapping. Reviewed-by: Rob Herring Signed-off-by: Rafał Miłecki Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210330111241.19401-5-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/nvmem/brcm,nvram.yaml | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Documentation/devicetree/bindings/nvmem/brcm,nvram.yaml diff --git a/Documentation/devicetree/bindings/nvmem/brcm,nvram.yaml b/Documentation/devicetree/bindings/nvmem/brcm,nvram.yaml new file mode 100644 index 000000000000..58ff6b0bdb1a --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/brcm,nvram.yaml @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/nvmem/brcm,nvram.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Broadcom's NVRAM + +description: | + Broadcom's NVRAM is a structure containing device specific environment + variables. It is used for storing device configuration, booting parameters + and calibration data. + + NVRAM can be accessed on Broadcom BCM47xx MIPS and Northstar ARM Cortex-A9 + devices usiong I/O mapped memory. + +maintainers: + - Rafał Miłecki + +allOf: + - $ref: "nvmem.yaml#" + +properties: + compatible: + const: brcm,nvram + +unevaluatedProperties: false + +examples: + - | + nvram@1eff0000 { + compatible = "brcm,nvram"; + reg = <0x1eff0000 0x10000>; + }; -- cgit v1.2.3 From 3fef9ed0627af30753a2404b8bd59d92cdb4c0ce Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Tue, 30 Mar 2021 12:12:36 +0100 Subject: nvmem: brcm_nvram: new driver exposing Broadcom's NVRAM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver provides access to Broadcom's NVRAM. Signed-off-by: Rafał Miłecki Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210330111241.19401-6-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/Kconfig | 9 ++++++ drivers/nvmem/Makefile | 2 ++ drivers/nvmem/brcm_nvram.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 drivers/nvmem/brcm_nvram.c diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index 75d2594c16e1..642ddc699fd1 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -278,4 +278,13 @@ config NVMEM_RMEM This driver can also be built as a module. If so, the module will be called nvmem-rmem. + +config NVMEM_BRCM_NVRAM + tristate "Broadcom's NVRAM support" + depends on ARCH_BCM_5301X || COMPILE_TEST + depends on HAS_IOMEM + help + This driver provides support for Broadcom's NVRAM that can be accessed + using I/O mapping. + endif diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index 5376b8e0dae5..bbea1410240a 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -57,3 +57,5 @@ obj-$(CONFIG_SPRD_EFUSE) += nvmem_sprd_efuse.o nvmem_sprd_efuse-y := sprd-efuse.o obj-$(CONFIG_NVMEM_RMEM) += nvmem-rmem.o nvmem-rmem-y := rmem.o +obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o +nvmem_brcm_nvram-y := brcm_nvram.o diff --git a/drivers/nvmem/brcm_nvram.c b/drivers/nvmem/brcm_nvram.c new file mode 100644 index 000000000000..bd2ecaaf4585 --- /dev/null +++ b/drivers/nvmem/brcm_nvram.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 Rafał Miłecki + */ + +#include +#include +#include +#include +#include + +struct brcm_nvram { + struct device *dev; + void __iomem *base; +}; + +static int brcm_nvram_read(void *context, unsigned int offset, void *val, + size_t bytes) +{ + struct brcm_nvram *priv = context; + u8 *dst = val; + + while (bytes--) + *dst++ = readb(priv->base + offset++); + + return 0; +} + +static int brcm_nvram_probe(struct platform_device *pdev) +{ + struct nvmem_config config = { + .name = "brcm-nvram", + .reg_read = brcm_nvram_read, + }; + struct device *dev = &pdev->dev; + struct resource *res; + struct brcm_nvram *priv; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + config.dev = dev; + config.priv = priv; + config.size = resource_size(res); + + return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &config)); +} + +static const struct of_device_id brcm_nvram_of_match_table[] = { + { .compatible = "brcm,nvram", }, + {}, +}; + +static struct platform_driver brcm_nvram_driver = { + .probe = brcm_nvram_probe, + .driver = { + .name = "brcm_nvram", + .of_match_table = brcm_nvram_of_match_table, + }, +}; + +static int __init brcm_nvram_init(void) +{ + return platform_driver_register(&brcm_nvram_driver); +} + +subsys_initcall_sync(brcm_nvram_init); + +MODULE_AUTHOR("Rafał Miłecki"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(of, brcm_nvram_of_match_table); -- cgit v1.2.3 From a28e824fb8270eda43fd0f65c2a5fdf33f55c5eb Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 30 Mar 2021 12:12:37 +0100 Subject: nvmem: core: Add functions to make number reading easy Sometimes the clients of nvmem just want to get a number out of nvmem. They don't want to think about exactly how many bytes the nvmem cell took up. They just want the number. Let's make it easy. In general this concept is useful because nvmem space is precious and usually the fewest bits are allocated that will hold a given value on a given system. However, even though small numbers might be fine on one system that doesn't mean that logically the number couldn't be bigger. Imagine nvmem containing a max frequency for a component. On one system perhaps that fits in 16 bits. On another system it might fit in 32 bits. The code reading this number doesn't care--it just wants the number. We'll provide two functions: nvmem_cell_read_variable_le_u32() and nvmem_cell_read_variable_le_u64(). Comparing these to the existing functions like nvmem_cell_read_u32(): * These new functions have no problems if the value was stored in nvmem in fewer bytes. It's OK to use these function as long as the value stored will fit in 32-bits (or 64-bits). * These functions avoid problems that the earlier APIs had with bit offsets. For instance, you can't use nvmem_cell_read_u32() to read a value has nbits=32 and bit_offset=4 because the nvmem cell must be at least 5 bytes big to hold this value. The new API accounts for this and works fine. * These functions make it very explicit that they assume that the number was stored in little endian format. The old functions made this assumption whenever bit_offset was non-zero (see nvmem_shift_read_buffer_in_place()) but didn't whenever the bit_offset was zero. NOTE: it's assumed that we don't need an 8-bit or 16-bit version of this function. The 32-bit version of the function can be used to read 8-bit or 16-bit data. At the moment, I'm only adding the "unsigned" versions of these functions, but if it ends up being useful someone could add a "signed" version that did 2's complement sign extension. At the moment, I'm only adding the "little endian" versions of these functions. Adding the "big endian" version would require adding "big endian" support to nvmem_shift_read_buffer_in_place(). Signed-off-by: Douglas Anderson Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210330111241.19401-7-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 95 ++++++++++++++++++++++++++++++++++++++++++ include/linux/nvmem-consumer.h | 4 ++ 2 files changed, 99 insertions(+) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index a5ab1e0c74cf..635e3131eb5f 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -1606,6 +1606,101 @@ int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val) } EXPORT_SYMBOL_GPL(nvmem_cell_read_u64); +static void *nvmem_cell_read_variable_common(struct device *dev, + const char *cell_id, + size_t max_len, size_t *len) +{ + struct nvmem_cell *cell; + int nbits; + void *buf; + + cell = nvmem_cell_get(dev, cell_id); + if (IS_ERR(cell)) + return cell; + + nbits = cell->nbits; + buf = nvmem_cell_read(cell, len); + nvmem_cell_put(cell); + if (IS_ERR(buf)) + return buf; + + /* + * If nbits is set then nvmem_cell_read() can significantly exaggerate + * the length of the real data. Throw away the extra junk. + */ + if (nbits) + *len = DIV_ROUND_UP(nbits, 8); + + if (*len > max_len) { + kfree(buf); + return ERR_PTR(-ERANGE); + } + + return buf; +} + +/** + * nvmem_cell_read_variable_le_u32() - Read up to 32-bits of data as a little endian number. + * + * @dev: Device that requests the nvmem cell. + * @cell_id: Name of nvmem cell to read. + * @val: pointer to output value. + * + * Return: 0 on success or negative errno. + */ +int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id, + u32 *val) +{ + size_t len; + u8 *buf; + int i; + + buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + /* Copy w/ implicit endian conversion */ + *val = 0; + for (i = 0; i < len; i++) + *val |= buf[i] << (8 * i); + + kfree(buf); + + return 0; +} +EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u32); + +/** + * nvmem_cell_read_variable_le_u64() - Read up to 64-bits of data as a little endian number. + * + * @dev: Device that requests the nvmem cell. + * @cell_id: Name of nvmem cell to read. + * @val: pointer to output value. + * + * Return: 0 on success or negative errno. + */ +int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id, + u64 *val) +{ + size_t len; + u8 *buf; + int i; + + buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + /* Copy w/ implicit endian conversion */ + *val = 0; + for (i = 0; i < len; i++) + *val |= buf[i] << (8 * i); + + kfree(buf); + + return 0; +} +EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u64); + /** * nvmem_device_cell_read() - Read a given nvmem device and cell * diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h index 052293f4cbdb..923dada24eb4 100644 --- a/include/linux/nvmem-consumer.h +++ b/include/linux/nvmem-consumer.h @@ -65,6 +65,10 @@ int nvmem_cell_read_u8(struct device *dev, const char *cell_id, u8 *val); int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val); int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val); int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val); +int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id, + u32 *val); +int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id, + u64 *val); /* direct nvmem device read/write interface */ struct nvmem_device *nvmem_device_get(struct device *dev, const char *name); -- cgit v1.2.3 From 55022fdeace8e432f008787ce03703bdcc9c3ca9 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 30 Mar 2021 12:12:38 +0100 Subject: nvmem: core: Fix unintentional sign extension issue The shifting of the u8 integer buf[3] by 24 bits to the left will be promoted to a 32 bit signed int and then sign-extended to a u64. In the event that the top bit of buf[3] is set then all then all the upper 32 bits of the u64 end up as also being set because of the sign-extension. Fix this by casting buf[i] to a u64 before the shift. Fixes: a28e824fb827 ("nvmem: core: Add functions to make number reading easy") Reviewed-by: Douglas Anderson Signed-off-by: Colin Ian King Signed-off-by: Srinivas Kandagatla Addresses-Coverity: ("Unintended sign extension") Link: https://lore.kernel.org/r/20210330111241.19401-8-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 635e3131eb5f..bca671ff4e54 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -1693,7 +1693,7 @@ int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id, /* Copy w/ implicit endian conversion */ *val = 0; for (i = 0; i < len; i++) - *val |= buf[i] << (8 * i); + *val |= (uint64_t)buf[i] << (8 * i); kfree(buf); -- cgit v1.2.3 From cc1bc56fdc76a55bb8fae9a145a2e60bf22fb129 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 30 Mar 2021 12:12:39 +0100 Subject: nvmem: rmem: fix undefined reference to memremap Fix below error reporte by kernel test robot rmem.c:(.text+0x14e): undefined reference to memremap s390x-linux-gnu-ld: rmem.c:(.text+0x1b6): undefined reference to memunmap Fixes: 5a3fa75a4d9c ("nvmem: Add driver to expose reserved memory as nvmem") Reported-by: kernel test robot Reviewed-by: Nicolas Saenz Julienne Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210330111241.19401-9-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index 642ddc699fd1..dd2019006838 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -272,6 +272,7 @@ config SPRD_EFUSE config NVMEM_RMEM tristate "Reserved Memory Based Driver Support" + depends on HAS_IOMEM help This driver maps reserved memory into an nvmem device. It might be useful to expose information left by firmware in memory. -- cgit v1.2.3 From b1f20fd04577a24bef4616a67a61c6dfe1eedb6b Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Tue, 30 Mar 2021 12:12:40 +0100 Subject: dt-bindings: nvmem: Add SoC compatible for sc7280 Document SoC compatible for sc7280 Acked-by: Rob Herring Signed-off-by: Rajendra Nayak Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210330111241.19401-10-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml index 992777c90a0b..861b205016b1 100644 --- a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml +++ b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml @@ -24,6 +24,7 @@ properties: - qcom,msm8998-qfprom - qcom,qcs404-qfprom - qcom,sc7180-qfprom + - qcom,sc7280-qfprom - qcom,sdm845-qfprom - const: qcom,qfprom -- cgit v1.2.3 From 5a1bea2a2572ce5eb4bdcf432a6929681ee381f2 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Tue, 30 Mar 2021 12:12:41 +0100 Subject: nvmem: qfprom: Add support for fuse blowing on sc7280 Handle the differences across LDO voltage needed for blowing fuses, and the blow timer value, identified using a minor version of 15 on sc7280. Signed-off-by: Rajendra Nayak Signed-off-by: Ravi Kumar Bokka Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210330111241.19401-11-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/qfprom.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c index 100d69d8f2e1..d6d3f24685a8 100644 --- a/drivers/nvmem/qfprom.c +++ b/drivers/nvmem/qfprom.c @@ -45,11 +45,13 @@ MODULE_PARM_DESC(read_raw_data, "Read raw instead of corrected data"); * @qfprom_blow_timer_value: The timer value of qfprom when doing efuse blow. * @qfprom_blow_set_freq: The frequency required to set when we start the * fuse blowing. + * @qfprom_blow_uV: LDO voltage to be set when doing efuse blow */ struct qfprom_soc_data { u32 accel_value; u32 qfprom_blow_timer_value; u32 qfprom_blow_set_freq; + int qfprom_blow_uV; }; /** @@ -111,6 +113,15 @@ static const struct qfprom_soc_compatible_data sc7180_qfprom = { .nkeepout = ARRAY_SIZE(sc7180_qfprom_keepout) }; +static const struct nvmem_keepout sc7280_qfprom_keepout[] = { + {.start = 0x128, .end = 0x148}, + {.start = 0x238, .end = 0x248} +}; + +static const struct qfprom_soc_compatible_data sc7280_qfprom = { + .keepout = sc7280_qfprom_keepout, + .nkeepout = ARRAY_SIZE(sc7280_qfprom_keepout) +}; /** * qfprom_disable_fuse_blowing() - Undo enabling of fuse blowing. * @priv: Our driver data. @@ -168,6 +179,7 @@ static int qfprom_enable_fuse_blowing(const struct qfprom_priv *priv, struct qfprom_touched_values *old) { int ret; + int qfprom_blow_uV = priv->soc_data->qfprom_blow_uV; ret = clk_prepare_enable(priv->secclk); if (ret) { @@ -187,9 +199,9 @@ static int qfprom_enable_fuse_blowing(const struct qfprom_priv *priv, * a rail shared do don't specify a max--regulator constraints * will handle. */ - ret = regulator_set_voltage(priv->vcc, 1800000, INT_MAX); + ret = regulator_set_voltage(priv->vcc, qfprom_blow_uV, INT_MAX); if (ret) { - dev_err(priv->dev, "Failed to set 1.8 voltage\n"); + dev_err(priv->dev, "Failed to set %duV\n", qfprom_blow_uV); goto err_clk_rate_set; } @@ -311,6 +323,14 @@ static const struct qfprom_soc_data qfprom_7_8_data = { .accel_value = 0xD10, .qfprom_blow_timer_value = 25, .qfprom_blow_set_freq = 4800000, + .qfprom_blow_uV = 1800000, +}; + +static const struct qfprom_soc_data qfprom_7_15_data = { + .accel_value = 0xD08, + .qfprom_blow_timer_value = 24, + .qfprom_blow_set_freq = 4800000, + .qfprom_blow_uV = 1900000, }; static int qfprom_probe(struct platform_device *pdev) @@ -379,6 +399,8 @@ static int qfprom_probe(struct platform_device *pdev) if (major_version == 7 && minor_version == 8) priv->soc_data = &qfprom_7_8_data; + if (major_version == 7 && minor_version == 15) + priv->soc_data = &qfprom_7_15_data; priv->vcc = devm_regulator_get(&pdev->dev, "vcc"); if (IS_ERR(priv->vcc)) @@ -405,6 +427,7 @@ static int qfprom_probe(struct platform_device *pdev) static const struct of_device_id qfprom_of_match[] = { { .compatible = "qcom,qfprom",}, { .compatible = "qcom,sc7180-qfprom", .data = &sc7180_qfprom}, + { .compatible = "qcom,sc7280-qfprom", .data = &sc7280_qfprom}, {/* sentinel */}, }; MODULE_DEVICE_TABLE(of, qfprom_of_match); -- cgit v1.2.3 From 5c777233c90f80a75cbd79c1b2fd713453dd02ff Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 30 Mar 2021 22:33:23 +0300 Subject: mux: gpio: Use bitmap API instead of direct assignment Assigning bitmaps like it's done in the driver might be error prone. Fix this by using bitmap API. Acked-by: Peter Rosin Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210330193325.68362-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/mux/gpio.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/mux/gpio.c b/drivers/mux/gpio.c index 02c1f2c014e8..d1b4aa923657 100644 --- a/drivers/mux/gpio.c +++ b/drivers/mux/gpio.c @@ -7,6 +7,7 @@ * Author: Peter Rosin */ +#include #include #include #include @@ -23,8 +24,9 @@ static int mux_gpio_set(struct mux_control *mux, int state) { struct mux_gpio *mux_gpio = mux_chip_priv(mux->chip); DECLARE_BITMAP(values, BITS_PER_TYPE(state)); + u32 value = state; - values[0] = state; + bitmap_from_arr32(values, &value, BITS_PER_TYPE(value)); gpiod_set_array_value_cansleep(mux_gpio->gpios->ndescs, mux_gpio->gpios->desc, @@ -71,7 +73,7 @@ static int mux_gpio_probe(struct platform_device *pdev) return ret; } WARN_ON(pins != mux_gpio->gpios->ndescs); - mux_chip->mux->states = 1 << pins; + mux_chip->mux->states = BIT(pins); ret = device_property_read_u32(dev, "idle-state", (u32 *)&idle_state); if (ret >= 0 && idle_state != MUX_IDLE_AS_IS) { -- cgit v1.2.3 From 7fef54e25541c49c99ba5787bfb45216c30df3e7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 30 Mar 2021 22:33:24 +0300 Subject: mux: gpio: Make it OF independent Module doesn't use OF APIs anyhow, make it OF independent by replacing headers and dropping useless of_match_ptr() call. Acked-by: Peter Rosin Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210330193325.68362-2-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/mux/gpio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mux/gpio.c b/drivers/mux/gpio.c index d1b4aa923657..92cc476c916e 100644 --- a/drivers/mux/gpio.c +++ b/drivers/mux/gpio.c @@ -10,9 +10,9 @@ #include #include #include +#include #include #include -#include #include #include @@ -98,7 +98,7 @@ static int mux_gpio_probe(struct platform_device *pdev) static struct platform_driver mux_gpio_driver = { .driver = { .name = "gpio-mux", - .of_match_table = of_match_ptr(mux_gpio_dt_ids), + .of_match_table = mux_gpio_dt_ids, }, .probe = mux_gpio_probe, }; -- cgit v1.2.3 From 38ab861493de18c672b101765751f5e6bb17ec0d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 30 Mar 2021 22:33:25 +0300 Subject: mux: gpio: Simplify code by using dev_err_probe() Use already prepared dev_err_probe() introduced by the commit a787e5400a1c ("driver core: add device probe log helper"). It simplifies EPROBE_DEFER handling. Acked-by: Peter Rosin Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210330193325.68362-3-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/mux/gpio.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/mux/gpio.c b/drivers/mux/gpio.c index 92cc476c916e..cc5f2c1861d4 100644 --- a/drivers/mux/gpio.c +++ b/drivers/mux/gpio.c @@ -66,12 +66,9 @@ static int mux_gpio_probe(struct platform_device *pdev) mux_chip->ops = &mux_gpio_ops; mux_gpio->gpios = devm_gpiod_get_array(dev, "mux", GPIOD_OUT_LOW); - if (IS_ERR(mux_gpio->gpios)) { - ret = PTR_ERR(mux_gpio->gpios); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get gpios\n"); - return ret; - } + if (IS_ERR(mux_gpio->gpios)) + return dev_err_probe(dev, PTR_ERR(mux_gpio->gpios), + "failed to get gpios\n"); WARN_ON(pins != mux_gpio->gpios->ndescs); mux_chip->mux->states = BIT(pins); -- cgit v1.2.3 From b0077b4b085f636e5f8a1fd9cd6e568907471b24 Mon Sep 17 00:00:00 2001 From: Evan Green Date: Thu, 1 Apr 2021 14:04:36 -0700 Subject: firmware: google: Enable s0ix logging by default Many moons ago, support was added to the SMI handlers to log s0ix entry and exit. Early iterations of firmware on Apollo Lake correctly returned "unsupported" for this new command they did not recognize, but unfortunately also contained a quirk where this command would cause them to power down rather than resume from s0ix. Fixes for this quirk were pushed out long ago, so all APL devices still in the field should have updated firmware. As such, we no longer need to have the s0ix_logging_enable be opt-in, where every new platform has to add this to their kernel commandline parameters. Change it to be on by default. In theory we could remove the parameter altogether: updated versions of Chrome OS containing a kernel with this change would also be coupled with firmware that behaves properly with these commands. Eventually we should probably do that. For now, convert this to an opt-out parameter so there's an emergency valve for people who are deliberately running old firmware, or as an escape hatch in case of unforeseen regressions. Signed-off-by: Evan Green Link: https://lore.kernel.org/r/20210401140430.1.Ie141e6044d9b0d5aba72cb08857fdb43660c54d3@changeid Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/google/gsmi.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index 3d77f26c1e8c..bb6e77ee3898 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c @@ -136,12 +136,16 @@ MODULE_PARM_DESC(spincount, "The number of loop iterations to use when using the spin handshake."); /* - * Platforms might not support S0ix logging in their GSMI handlers. In order to - * avoid any side-effects of generating an SMI for S0ix logging, use the S0ix - * related GSMI commands only for those platforms that explicitly enable this - * option. + * Some older platforms with Apollo Lake chipsets do not support S0ix logging + * in their GSMI handlers, and behaved poorly when resuming via power button + * press if the logging was attempted. Updated firmware with proper behavior + * has long since shipped, removing the need for this opt-in parameter. It + * now exists as an opt-out parameter for folks defiantly running old + * firmware, or unforeseen circumstances. After the change from opt-in to + * opt-out has baked sufficiently, this parameter should probably be removed + * entirely. */ -static bool s0ix_logging_enable; +static bool s0ix_logging_enable = true; module_param(s0ix_logging_enable, bool, 0600); static struct gsmi_buf *gsmi_buf_alloc(void) -- cgit v1.2.3 From f9d2d86dc52118bc237ed081128df30faa4a5761 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 2 Apr 2021 13:57:49 +0200 Subject: dt-bindings: fpga: fpga-region: Convert to sugar syntax Using overlay sugar syntax makes the DTS files easier to read (and write). While at it, fix two build issues: - "/dts-v1/" and "/plugin/" must be separate statements. - Add a missing closing curly brace. Signed-off-by: Geert Uytterhoeven Signed-off-by: Moritz Fischer --- .../devicetree/bindings/fpga/fpga-region.txt | 187 ++++++++++----------- 1 file changed, 85 insertions(+), 102 deletions(-) diff --git a/Documentation/devicetree/bindings/fpga/fpga-region.txt b/Documentation/devicetree/bindings/fpga/fpga-region.txt index e811cf825019..d787d57491a1 100644 --- a/Documentation/devicetree/bindings/fpga/fpga-region.txt +++ b/Documentation/devicetree/bindings/fpga/fpga-region.txt @@ -245,36 +245,31 @@ Base tree contains: Overlay contains: -/dts-v1/ /plugin/; -/ { - fragment@0 { - target = <&fpga_region0>; - #address-cells = <1>; - #size-cells = <1>; - __overlay__ { - #address-cells = <1>; - #size-cells = <1>; - - firmware-name = "soc_system.rbf"; - fpga-bridges = <&fpga_bridge1>; - ranges = <0x20000 0xff200000 0x100000>, - <0x0 0xc0000000 0x20000000>; - - gpio@10040 { - compatible = "altr,pio-1.0"; - reg = <0x10040 0x20>; - altr,ngpio = <4>; - #gpio-cells = <2>; - clocks = <2>; - gpio-controller; - }; - - onchip-memory { - device_type = "memory"; - compatible = "altr,onchipmem-15.1"; - reg = <0x0 0x10000>; - }; - }; +/dts-v1/; +/plugin/; + +&fpga_region0 { + #address-cells = <1>; + #size-cells = <1>; + + firmware-name = "soc_system.rbf"; + fpga-bridges = <&fpga_bridge1>; + ranges = <0x20000 0xff200000 0x100000>, + <0x0 0xc0000000 0x20000000>; + + gpio@10040 { + compatible = "altr,pio-1.0"; + reg = <0x10040 0x20>; + altr,ngpio = <4>; + #gpio-cells = <2>; + clocks = <2>; + gpio-controller; + }; + + onchip-memory { + device_type = "memory"; + compatible = "altr,onchipmem-15.1"; + reg = <0x0 0x10000>; }; }; @@ -371,25 +366,22 @@ Live Device Tree contains: }; DT Overlay contains: -/dts-v1/ /plugin/; -/ { -fragment@0 { - target = <&fpga_region0>; + +/dts-v1/; +/plugin/; + +&fpga_region0 { #address-cells = <1>; #size-cells = <1>; - __overlay__ { - #address-cells = <1>; - #size-cells = <1>; - firmware-name = "zynq-gpio.bin"; + firmware-name = "zynq-gpio.bin"; - gpio1: gpio@40000000 { - compatible = "xlnx,xps-gpio-1.00.a"; - reg = <0x40000000 0x10000>; - gpio-controller; - #gpio-cells = <0x2>; - xlnx,gpio-width= <0x6>; - }; + gpio1: gpio@40000000 { + compatible = "xlnx,xps-gpio-1.00.a"; + reg = <0x40000000 0x10000>; + gpio-controller; + #gpio-cells = <0x2>; + xlnx,gpio-width= <0x6>; }; }; @@ -402,41 +394,37 @@ This example programs the FPGA to have two regions that can later be partially configured. Each region has its own bridge in the FPGA fabric. DT Overlay contains: -/dts-v1/ /plugin/; -/ { - fragment@0 { - target = <&fpga_region0>; - #address-cells = <1>; - #size-cells = <1>; - __overlay__ { - #address-cells = <1>; - #size-cells = <1>; - - firmware-name = "base.rbf"; - - fpga-bridge@4400 { - compatible = "altr,freeze-bridge-controller"; - reg = <0x4400 0x10>; - - fpga_region1: fpga-region1 { - compatible = "fpga-region"; - #address-cells = <0x1>; - #size-cells = <0x1>; - ranges; - }; - }; - - fpga-bridge@4420 { - compatible = "altr,freeze-bridge-controller"; - reg = <0x4420 0x10>; - - fpga_region2: fpga-region2 { - compatible = "fpga-region"; - #address-cells = <0x1>; - #size-cells = <0x1>; - ranges; - }; - }; + +/dts-v1/; +/plugin/; + +&fpga_region0 { + #address-cells = <1>; + #size-cells = <1>; + + firmware-name = "base.rbf"; + + fpga-bridge@4400 { + compatible = "altr,freeze-bridge-controller"; + reg = <0x4400 0x10>; + + fpga_region1: fpga-region1 { + compatible = "fpga-region"; + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges; + }; + }; + + fpga-bridge@4420 { + compatible = "altr,freeze-bridge-controller"; + reg = <0x4420 0x10>; + + fpga_region2: fpga-region2 { + compatible = "fpga-region"; + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges; }; }; }; @@ -451,28 +439,23 @@ differences are that the FPGA is partially reconfigured due to the "partial-fpga-config" boolean and the only bridge that is controlled during programming is the FPGA based bridge of fpga_region1. -/dts-v1/ /plugin/; -/ { - fragment@0 { - target = <&fpga_region1>; - #address-cells = <1>; - #size-cells = <1>; - __overlay__ { - #address-cells = <1>; - #size-cells = <1>; - - firmware-name = "soc_image2.rbf"; - partial-fpga-config; - - gpio@10040 { - compatible = "altr,pio-1.0"; - reg = <0x10040 0x20>; - clocks = <0x2>; - altr,ngpio = <0x4>; - #gpio-cells = <0x2>; - gpio-controller; - }; - }; +/dts-v1/; +/plugin/; + +&fpga_region1 { + #address-cells = <1>; + #size-cells = <1>; + + firmware-name = "soc_image2.rbf"; + partial-fpga-config; + + gpio@10040 { + compatible = "altr,pio-1.0"; + reg = <0x10040 0x20>; + clocks = <0x2>; + altr,ngpio = <0x4>; + #gpio-cells = <0x2>; + gpio-controller; }; }; -- cgit v1.2.3 From 376565b9717c30cd58ad33860fa42697615fa2e4 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Fri, 2 Apr 2021 21:17:41 +0900 Subject: misc: vmw_vmci: explicitly initialize vmci_notify_bm_set_msg struct KMSAN complains that the vmci_use_ppn64() == false path in vmci_dbell_register_notification_bitmap() left upper 32bits of bitmap_set_msg.bitmap_ppn64 member uninitialized. ===================================================== BUG: KMSAN: uninit-value in kmsan_check_memory+0xd/0x10 CPU: 1 PID: 1 Comm: swapper/0 Not tainted 5.11.0-rc7+ #4 Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 02/27/2020 Call Trace: dump_stack+0x21c/0x280 kmsan_report+0xfb/0x1e0 kmsan_internal_check_memory+0x484/0x520 kmsan_check_memory+0xd/0x10 iowrite8_rep+0x86/0x380 vmci_send_datagram+0x150/0x280 vmci_dbell_register_notification_bitmap+0x133/0x1e0 vmci_guest_probe_device+0xcab/0x1e70 pci_device_probe+0xab3/0xe70 really_probe+0xd16/0x24d0 driver_probe_device+0x29d/0x3a0 device_driver_attach+0x25a/0x490 __driver_attach+0x78c/0x840 bus_for_each_dev+0x210/0x340 driver_attach+0x89/0xb0 bus_add_driver+0x677/0xc40 driver_register+0x485/0x8e0 __pci_register_driver+0x1ff/0x350 vmci_guest_init+0x3e/0x41 vmci_drv_init+0x1d6/0x43f do_one_initcall+0x39c/0x9a0 do_initcall_level+0x1d7/0x259 do_initcalls+0x127/0x1cb do_basic_setup+0x33/0x36 kernel_init_freeable+0x29a/0x3ed kernel_init+0x1f/0x840 ret_from_fork+0x1f/0x30 Local variable ----bitmap_set_msg@vmci_dbell_register_notification_bitmap created at: vmci_dbell_register_notification_bitmap+0x50/0x1e0 vmci_dbell_register_notification_bitmap+0x50/0x1e0 Bytes 28-31 of 32 are uninitialized Memory access of size 32 starts at ffff88810098f570 ===================================================== Fixes: 83e2ec765be03e8a ("VMCI: doorbell implementation.") Cc: Signed-off-by: Tetsuo Handa Link: https://lore.kernel.org/r/20210402121742.3917-1-penguin-kernel@I-love.SAKURA.ne.jp Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_doorbell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/vmw_vmci/vmci_doorbell.c b/drivers/misc/vmw_vmci/vmci_doorbell.c index 345addd9306d..fa8a7fce4481 100644 --- a/drivers/misc/vmw_vmci/vmci_doorbell.c +++ b/drivers/misc/vmw_vmci/vmci_doorbell.c @@ -326,7 +326,7 @@ int vmci_dbell_host_context_notify(u32 src_cid, struct vmci_handle handle) bool vmci_dbell_register_notification_bitmap(u64 bitmap_ppn) { int result; - struct vmci_notify_bm_set_msg bitmap_set_msg; + struct vmci_notify_bm_set_msg bitmap_set_msg = { }; bitmap_set_msg.hdr.dst = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID, VMCI_SET_NOTIFY_BITMAP); -- cgit v1.2.3 From b2192cfeba8481224da0a4ec3b4a7ccd80b1623b Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Fri, 2 Apr 2021 21:17:42 +0900 Subject: misc: vmw_vmci: explicitly initialize vmci_datagram payload KMSAN complains that vmci_check_host_caps() left the payload part of check_msg uninitialized. ===================================================== BUG: KMSAN: uninit-value in kmsan_check_memory+0xd/0x10 CPU: 1 PID: 1 Comm: swapper/0 Tainted: G B 5.11.0-rc7+ #4 Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 02/27/2020 Call Trace: dump_stack+0x21c/0x280 kmsan_report+0xfb/0x1e0 kmsan_internal_check_memory+0x202/0x520 kmsan_check_memory+0xd/0x10 iowrite8_rep+0x86/0x380 vmci_guest_probe_device+0xf0b/0x1e70 pci_device_probe+0xab3/0xe70 really_probe+0xd16/0x24d0 driver_probe_device+0x29d/0x3a0 device_driver_attach+0x25a/0x490 __driver_attach+0x78c/0x840 bus_for_each_dev+0x210/0x340 driver_attach+0x89/0xb0 bus_add_driver+0x677/0xc40 driver_register+0x485/0x8e0 __pci_register_driver+0x1ff/0x350 vmci_guest_init+0x3e/0x41 vmci_drv_init+0x1d6/0x43f do_one_initcall+0x39c/0x9a0 do_initcall_level+0x1d7/0x259 do_initcalls+0x127/0x1cb do_basic_setup+0x33/0x36 kernel_init_freeable+0x29a/0x3ed kernel_init+0x1f/0x840 ret_from_fork+0x1f/0x30 Uninit was created at: kmsan_internal_poison_shadow+0x5c/0xf0 kmsan_slab_alloc+0x8d/0xe0 kmem_cache_alloc+0x84f/0xe30 vmci_guest_probe_device+0xd11/0x1e70 pci_device_probe+0xab3/0xe70 really_probe+0xd16/0x24d0 driver_probe_device+0x29d/0x3a0 device_driver_attach+0x25a/0x490 __driver_attach+0x78c/0x840 bus_for_each_dev+0x210/0x340 driver_attach+0x89/0xb0 bus_add_driver+0x677/0xc40 driver_register+0x485/0x8e0 __pci_register_driver+0x1ff/0x350 vmci_guest_init+0x3e/0x41 vmci_drv_init+0x1d6/0x43f do_one_initcall+0x39c/0x9a0 do_initcall_level+0x1d7/0x259 do_initcalls+0x127/0x1cb do_basic_setup+0x33/0x36 kernel_init_freeable+0x29a/0x3ed kernel_init+0x1f/0x840 ret_from_fork+0x1f/0x30 Bytes 28-31 of 36 are uninitialized Memory access of size 36 starts at ffff8881675e5f00 ===================================================== Fixes: 1f166439917b69d3 ("VMCI: guest side driver implementation.") Cc: Signed-off-by: Tetsuo Handa Link: https://lore.kernel.org/r/20210402121742.3917-2-penguin-kernel@I-love.SAKURA.ne.jp Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_guest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c index cc8eeb361fcd..1018dc77269d 100644 --- a/drivers/misc/vmw_vmci/vmci_guest.c +++ b/drivers/misc/vmw_vmci/vmci_guest.c @@ -168,7 +168,7 @@ static int vmci_check_host_caps(struct pci_dev *pdev) VMCI_UTIL_NUM_RESOURCES * sizeof(u32); struct vmci_datagram *check_msg; - check_msg = kmalloc(msg_size, GFP_KERNEL); + check_msg = kzalloc(msg_size, GFP_KERNEL); if (!check_msg) { dev_err(&pdev->dev, "%s: Insufficient memory\n", __func__); return -ENOMEM; -- cgit v1.2.3 From e8a30eef6ef6da4998fcdaaffaaf8d29777c5d7d Mon Sep 17 00:00:00 2001 From: Gustavo Pimentel Date: Mon, 29 Mar 2021 13:17:45 +0200 Subject: misc: Add Synopsys DesignWare xData IP driver Add Synopsys DesignWare xData IP driver. This driver enables/disables the PCI traffic generator module pertain to the Synopsys DesignWare prototype. Signed-off-by: Gustavo Pimentel Link: https://lore.kernel.org/r/daa1efe23850e77d6807dc3f371728fc0b7548b8.1617016509.git.gustavo.pimentel@synopsys.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/Kconfig | 10 ++ drivers/misc/Makefile | 1 + drivers/misc/dw-xdata-pcie.c | 420 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 431 insertions(+) create mode 100644 drivers/misc/dw-xdata-pcie.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index c5f20e939ca3..f4fb5c52b863 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -402,6 +402,16 @@ config SRAM config SRAM_EXEC bool +config DW_XDATA_PCIE + depends on PCI + tristate "Synopsys DesignWare xData PCIe driver" + help + This driver allows controlling Synopsys DesignWare PCIe traffic + generator IP also known as xData, present in Synopsys DesignWare + PCIe Endpoint prototype. + + If unsure, say N. + config PCI_ENDPOINT_TEST depends on PCI select CRC32 diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index fd5f87e149c5..e92a56d4442f 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_SRAM_EXEC) += sram-exec.o obj-$(CONFIG_GENWQE) += genwqe/ obj-$(CONFIG_ECHO) += echo/ obj-$(CONFIG_CXL_BASE) += cxl/ +obj-$(CONFIG_DW_XDATA_PCIE) += dw-xdata-pcie.o obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o obj-$(CONFIG_OCXL) += ocxl/ obj-$(CONFIG_BCM_VK) += bcm-vk/ diff --git a/drivers/misc/dw-xdata-pcie.c b/drivers/misc/dw-xdata-pcie.c new file mode 100644 index 000000000000..257c25da5199 --- /dev/null +++ b/drivers/misc/dw-xdata-pcie.c @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Synopsys, Inc. and/or its affiliates. + * Synopsys DesignWare xData driver + * + * Author: Gustavo Pimentel + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DW_XDATA_DRIVER_NAME "dw-xdata-pcie" + +#define DW_XDATA_EP_MEM_OFFSET 0x8000000 + +static DEFINE_IDA(xdata_ida); + +#define STATUS_DONE BIT(0) + +#define CONTROL_DOORBELL BIT(0) +#define CONTROL_IS_WRITE BIT(1) +#define CONTROL_LENGTH(a) FIELD_PREP(GENMASK(13, 2), a) +#define CONTROL_PATTERN_INC BIT(16) +#define CONTROL_NO_ADDR_INC BIT(18) + +#define XPERF_CONTROL_ENABLE BIT(5) + +#define BURST_REPEAT BIT(31) +#define BURST_VALUE 0x1001 + +#define PATTERN_VALUE 0x0 + +struct dw_xdata_regs { + u32 addr_lsb; /* 0x000 */ + u32 addr_msb; /* 0x004 */ + u32 burst_cnt; /* 0x008 */ + u32 control; /* 0x00c */ + u32 pattern; /* 0x010 */ + u32 status; /* 0x014 */ + u32 RAM_addr; /* 0x018 */ + u32 RAM_port; /* 0x01c */ + u32 _reserved0[14]; /* 0x020..0x054 */ + u32 perf_control; /* 0x058 */ + u32 _reserved1[41]; /* 0x05c..0x0fc */ + u32 wr_cnt_lsb; /* 0x100 */ + u32 wr_cnt_msb; /* 0x104 */ + u32 rd_cnt_lsb; /* 0x108 */ + u32 rd_cnt_msb; /* 0x10c */ +} __packed; + +struct dw_xdata_region { + phys_addr_t paddr; /* physical address */ + void __iomem *vaddr; /* virtual address */ +}; + +struct dw_xdata { + struct dw_xdata_region rg_region; /* registers */ + size_t max_wr_len; /* max wr xfer len */ + size_t max_rd_len; /* max rd xfer len */ + struct mutex mutex; + struct pci_dev *pdev; + struct miscdevice misc_dev; +}; + +static inline struct dw_xdata_regs __iomem *__dw_regs(struct dw_xdata *dw) +{ + return dw->rg_region.vaddr; +} + +static void dw_xdata_stop(struct dw_xdata *dw) +{ + u32 burst; + + mutex_lock(&dw->mutex); + + burst = readl(&(__dw_regs(dw)->burst_cnt)); + + if (burst & BURST_REPEAT) { + burst &= ~(u32)BURST_REPEAT; + writel(burst, &(__dw_regs(dw)->burst_cnt)); + } + + mutex_unlock(&dw->mutex); +} + +static void dw_xdata_start(struct dw_xdata *dw, bool write) +{ + struct device *dev = &dw->pdev->dev; + u32 control, status; + + /* Stop first if xfer in progress */ + dw_xdata_stop(dw); + + mutex_lock(&dw->mutex); + + /* Clear status register */ + writel(0x0, &(__dw_regs(dw)->status)); + + /* Burst count register set for continuous until stopped */ + writel(BURST_REPEAT | BURST_VALUE, &(__dw_regs(dw)->burst_cnt)); + + /* Pattern register */ + writel(PATTERN_VALUE, &(__dw_regs(dw)->pattern)); + + /* Control register */ + control = CONTROL_DOORBELL | CONTROL_PATTERN_INC | CONTROL_NO_ADDR_INC; + if (write) { + control |= CONTROL_IS_WRITE; + control |= CONTROL_LENGTH(dw->max_wr_len); + } else { + control |= CONTROL_LENGTH(dw->max_rd_len); + } + writel(control, &(__dw_regs(dw)->control)); + + /* + * The xData HW block needs about 100 ms to initiate the traffic + * generation according this HW block datasheet. + */ + usleep_range(100, 150); + + status = readl(&(__dw_regs(dw)->status)); + + mutex_unlock(&dw->mutex); + + if (!(status & STATUS_DONE)) + dev_dbg(dev, "xData: started %s direction\n", + write ? "write" : "read"); +} + +static void dw_xdata_perf_meas(struct dw_xdata *dw, u64 *data, bool write) +{ + if (write) { + *data = readl(&(__dw_regs(dw)->wr_cnt_msb)); + *data <<= 32; + *data |= readl(&(__dw_regs(dw)->wr_cnt_lsb)); + } else { + *data = readl(&(__dw_regs(dw)->rd_cnt_msb)); + *data <<= 32; + *data |= readl(&(__dw_regs(dw)->rd_cnt_lsb)); + } +} + +static u64 dw_xdata_perf_diff(u64 *m1, u64 *m2, u64 time) +{ + u64 rate = (*m1 - *m2); + + rate *= (1000 * 1000 * 1000); + rate >>= 20; + rate = DIV_ROUND_CLOSEST_ULL(rate, time); + + return rate; +} + +static void dw_xdata_perf(struct dw_xdata *dw, u64 *rate, bool write) +{ + struct device *dev = &dw->pdev->dev; + u64 data[2], time[2], diff; + + mutex_lock(&dw->mutex); + + /* First acquisition of current count frames */ + writel(0x0, &(__dw_regs(dw)->perf_control)); + dw_xdata_perf_meas(dw, &data[0], write); + time[0] = jiffies; + writel((u32)XPERF_CONTROL_ENABLE, &(__dw_regs(dw)->perf_control)); + + /* + * Wait 100ms between the 1st count frame acquisition and the 2nd + * count frame acquisition, in order to calculate the speed later + */ + mdelay(100); + + /* Second acquisition of current count frames */ + writel(0x0, &(__dw_regs(dw)->perf_control)); + dw_xdata_perf_meas(dw, &data[1], write); + time[1] = jiffies; + writel((u32)XPERF_CONTROL_ENABLE, &(__dw_regs(dw)->perf_control)); + + /* + * Speed calculation + * + * rate = (2nd count frames - 1st count frames) / (time elapsed) + */ + diff = jiffies_to_nsecs(time[1] - time[0]); + *rate = dw_xdata_perf_diff(&data[1], &data[0], diff); + + mutex_unlock(&dw->mutex); + + dev_dbg(dev, "xData: time=%llu us, %s=%llu MB/s\n", + diff, write ? "write" : "read", *rate); +} + +static struct dw_xdata *misc_dev_to_dw(struct miscdevice *misc_dev) +{ + return container_of(misc_dev, struct dw_xdata, misc_dev); +} + +static ssize_t write_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct miscdevice *misc_dev = dev_get_drvdata(dev); + struct dw_xdata *dw = misc_dev_to_dw(misc_dev); + u64 rate; + + dw_xdata_perf(dw, &rate, true); + + return sysfs_emit(buf, "%llu\n", rate); +} + +static ssize_t write_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + struct miscdevice *misc_dev = dev_get_drvdata(dev); + struct dw_xdata *dw = misc_dev_to_dw(misc_dev); + bool enabled; + int ret; + + ret = kstrtobool(buf, &enabled); + if (ret < 0) + return ret; + + if (enabled) { + dev_dbg(dev, "xData: requested write transfer\n"); + dw_xdata_start(dw, true); + } else { + dev_dbg(dev, "xData: requested stop transfer\n"); + dw_xdata_stop(dw); + } + + return size; +} + +static DEVICE_ATTR_RW(write); + +static ssize_t read_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct miscdevice *misc_dev = dev_get_drvdata(dev); + struct dw_xdata *dw = misc_dev_to_dw(misc_dev); + u64 rate; + + dw_xdata_perf(dw, &rate, false); + + return sysfs_emit(buf, "%llu\n", rate); +} + +static ssize_t read_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + struct miscdevice *misc_dev = dev_get_drvdata(dev); + struct dw_xdata *dw = misc_dev_to_dw(misc_dev); + bool enabled; + int ret; + + ret = kstrtobool(buf, &enabled); + if (ret < 0) + return ret; + + if (enabled) { + dev_dbg(dev, "xData: requested read transfer\n"); + dw_xdata_start(dw, false); + } else { + dev_dbg(dev, "xData: requested stop transfer\n"); + dw_xdata_stop(dw); + } + + return size; +} + +static DEVICE_ATTR_RW(read); + +static struct attribute *xdata_attrs[] = { + &dev_attr_write.attr, + &dev_attr_read.attr, + NULL, +}; + +ATTRIBUTE_GROUPS(xdata); + +static int dw_xdata_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *pid) +{ + struct device *dev = &pdev->dev; + struct dw_xdata *dw; + char name[24]; + u64 addr; + int err; + int id; + + /* Enable PCI device */ + err = pcim_enable_device(pdev); + if (err) { + dev_err(dev, "enabling device failed\n"); + return err; + } + + /* Mapping PCI BAR regions */ + err = pcim_iomap_regions(pdev, BIT(BAR_0), pci_name(pdev)); + if (err) { + dev_err(dev, "xData BAR I/O remapping failed\n"); + return err; + } + + pci_set_master(pdev); + + /* Allocate memory */ + dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL); + if (!dw) + return -ENOMEM; + + /* Data structure initialization */ + mutex_init(&dw->mutex); + + dw->rg_region.vaddr = pcim_iomap_table(pdev)[BAR_0]; + if (!dw->rg_region.vaddr) + return -ENOMEM; + + dw->rg_region.paddr = pdev->resource[BAR_0].start; + + dw->max_wr_len = pcie_get_mps(pdev); + dw->max_wr_len >>= 2; + + dw->max_rd_len = pcie_get_readrq(pdev); + dw->max_rd_len >>= 2; + + dw->pdev = pdev; + + id = ida_simple_get(&xdata_ida, 0, 0, GFP_KERNEL); + if (id < 0) { + dev_err(dev, "xData: unable to get id\n"); + return id; + } + + snprintf(name, sizeof(name), DW_XDATA_DRIVER_NAME ".%d", id); + dw->misc_dev.name = kstrdup(name, GFP_KERNEL); + if (!dw->misc_dev.name) { + err = -ENOMEM; + goto err_ida_remove; + } + + dw->misc_dev.minor = MISC_DYNAMIC_MINOR; + dw->misc_dev.parent = dev; + dw->misc_dev.groups = xdata_groups; + + writel(0x0, &(__dw_regs(dw)->RAM_addr)); + writel(0x0, &(__dw_regs(dw)->RAM_port)); + + addr = dw->rg_region.paddr + DW_XDATA_EP_MEM_OFFSET; + writel(lower_32_bits(addr), &(__dw_regs(dw)->addr_lsb)); + writel(upper_32_bits(addr), &(__dw_regs(dw)->addr_msb)); + dev_dbg(dev, "xData: target address = 0x%.16llx\n", addr); + + dev_dbg(dev, "xData: wr_len = %zu, rd_len = %zu\n", + dw->max_wr_len * 4, dw->max_rd_len * 4); + + /* Saving data structure reference */ + pci_set_drvdata(pdev, dw); + + /* Register misc device */ + err = misc_register(&dw->misc_dev); + if (err) { + dev_err(dev, "xData: failed to register device\n"); + goto err_kfree_name; + } + + return 0; + +err_kfree_name: + kfree(dw->misc_dev.name); + +err_ida_remove: + ida_simple_remove(&xdata_ida, id); + + return err; +} + +static void dw_xdata_pcie_remove(struct pci_dev *pdev) +{ + struct dw_xdata *dw = pci_get_drvdata(pdev); + int id; + + if (sscanf(dw->misc_dev.name, DW_XDATA_DRIVER_NAME ".%d", &id) != 1) + return; + + if (id < 0) + return; + + dw_xdata_stop(dw); + misc_deregister(&dw->misc_dev); + kfree(dw->misc_dev.name); + ida_simple_remove(&xdata_ida, id); +} + +static const struct pci_device_id dw_xdata_pcie_id_table[] = { + { PCI_DEVICE_DATA(SYNOPSYS, EDDA, NULL) }, + { } +}; +MODULE_DEVICE_TABLE(pci, dw_xdata_pcie_id_table); + +static struct pci_driver dw_xdata_pcie_driver = { + .name = DW_XDATA_DRIVER_NAME, + .id_table = dw_xdata_pcie_id_table, + .probe = dw_xdata_pcie_probe, + .remove = dw_xdata_pcie_remove, +}; + +module_pci_driver(dw_xdata_pcie_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Synopsys DesignWare xData PCIe driver"); +MODULE_AUTHOR("Gustavo Pimentel "); + -- cgit v1.2.3 From e1181b5bbc3c3b6a16a0a80a870279ad1dccfeea Mon Sep 17 00:00:00 2001 From: Gustavo Pimentel Date: Mon, 29 Mar 2021 13:17:46 +0200 Subject: Documentation: misc-devices: Add Documentation for dw-xdata-pcie driver Add Documentation for dw-xdata-pcie driver. Signed-off-by: Gustavo Pimentel Link: https://lore.kernel.org/r/764b9bf744d7fe20c7a216019eef8ddf482c1bd7.1617016509.git.gustavo.pimentel@synopsys.com Signed-off-by: Greg Kroah-Hartman --- Documentation/misc-devices/dw-xdata-pcie.rst | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 Documentation/misc-devices/dw-xdata-pcie.rst diff --git a/Documentation/misc-devices/dw-xdata-pcie.rst b/Documentation/misc-devices/dw-xdata-pcie.rst new file mode 100644 index 000000000000..fd75c9321f47 --- /dev/null +++ b/Documentation/misc-devices/dw-xdata-pcie.rst @@ -0,0 +1,40 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=========================================================================== +Driver for Synopsys DesignWare PCIe traffic generator (also known as xData) +=========================================================================== + +This driver should be used as a host-side (Root Complex) driver and Synopsys +DesignWare prototype that includes this IP. + +The "dw-xdata-pcie" driver can be used to enable/disable PCIe traffic +generator in either direction (mutual exclusion) besides allowing the +PCIe link performance analysis. + +The interaction with this driver is done through the module parameter and +can be changed in runtime. The driver outputs the requested command state +information to /var/log/kern.log or dmesg. + +Request write TLPs traffic generation - Root Complex to Endpoint direction +- Command: + echo 1 > /sys/class/misc/dw-xdata-pcie/write + +Get write TLPs traffic link throughput in MB/s +- Command: + cat /sys/class/misc/dw-xdata-pcie/write +- Output example: + 204 + +Request read TLPs traffic generation - Endpoint to Root Complex direction: +- Command: + echo 1 > /sys/class/misc/dw-xdata-pcie/read + +Get read TLPs traffic link throughput in MB/s +- Command: + cat /sys/class/misc/dw-xdata-pcie/read +- Output example: + 199 + +Request to stop any current TLP transfer: +- Command: + echo 1 > /sys/class/misc/dw-xdata-pcie/stop -- cgit v1.2.3 From 49917294ab29bc0d06177049955eceb3ee53c1c6 Mon Sep 17 00:00:00 2001 From: Gustavo Pimentel Date: Mon, 29 Mar 2021 13:17:47 +0200 Subject: MAINTAINERS: Add Synopsys xData IP driver maintainer Add Synopsys xData IP driver maintainer. This driver aims to support Synopsys xData IP and is normally distributed along with Synopsys PCIe EndPoint IP as a PCIe traffic generator (depends of the use and licensing agreement). Signed-off-by: Gustavo Pimentel Link: https://lore.kernel.org/r/c8fb9af0ba8c86c5cf8afbfc0eb07fc99a642270.1617016509.git.gustavo.pimentel@synopsys.com Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index cc6d9d552df1..6ae3955525a9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5099,6 +5099,13 @@ S: Maintained F: drivers/dma/dw-edma/ F: include/linux/dma/edma.h +DESIGNWARE XDATA IP DRIVER +M: Gustavo Pimentel +L: linux-pci@vger.kernel.org +S: Maintained +F: Documentation/misc-devices/dw-xdata-pcie.rst +F: drivers/misc/dw-xdata-pcie.c + DESIGNWARE USB2 DRD IP DRIVER M: Minas Harutyunyan L: linux-usb@vger.kernel.org -- cgit v1.2.3 From 177260a705a9c45efa55345881724208421f7f3e Mon Sep 17 00:00:00 2001 From: Gustavo Pimentel Date: Mon, 29 Mar 2021 13:17:48 +0200 Subject: docs: ABI: Add sysfs documentation interface of dw-xdata-pcie driver This patch describes the sysfs interface implemented on the dw-xdata-pcie driver. Signed-off-by: Gustavo Pimentel Link: https://lore.kernel.org/r/438c4ca9f6cc9e1cb29a65c0d2cca9a3d3f181b1.1617016509.git.gustavo.pimentel@synopsys.com Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-driver-xdata | 49 ++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-driver-xdata diff --git a/Documentation/ABI/testing/sysfs-driver-xdata b/Documentation/ABI/testing/sysfs-driver-xdata new file mode 100644 index 000000000000..f574e8e6dca2 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-xdata @@ -0,0 +1,49 @@ +What: /sys/class/misc/drivers/dw-xdata-pcie./write +Date: April 2021 +KernelVersion: 5.13 +Contact: Gustavo Pimentel +Description: Allows the user to enable the PCIe traffic generator which + will create write TLPs frames - from the Root Complex to the + Endpoint direction or to disable the PCIe traffic generator + in all directions. + + Write y/1/on to enable, n/0/off to disable + + Usage e.g. + echo 1 > /sys/class/misc/dw-xdata-pcie./write + or + echo 0 > /sys/class/misc/dw-xdata-pcie./write + + The user can read the current PCIe link throughput generated + through this generator in MB/s. + + Usage e.g. + cat /sys/class/misc/dw-xdata-pcie./write + 204 + + The file is read and write. + +What: /sys/class/misc/dw-xdata-pcie./read +Date: April 2021 +KernelVersion: 5.13 +Contact: Gustavo Pimentel +Description: Allows the user to enable the PCIe traffic generator which + will create read TLPs frames - from the Endpoint to the Root + Complex direction or to disable the PCIe traffic generator + in all directions. + + Write y/1/on to enable, n/0/off to disable + + Usage e.g. + echo 1 > /sys/class/misc/dw-xdata-pcie./read + or + echo 0 > /sys/class/misc/dw-xdata-pcie./read + + The user can read the current PCIe link throughput generated + through this generator in MB/s. + + Usage e.g. + cat /sys/class/misc/dw-xdata-pcie./read + 199 + + The file is read and write. -- cgit v1.2.3 From a78a51a851ed3edc83264a67e2ba77a34f27965f Mon Sep 17 00:00:00 2001 From: Russ Weight Date: Mon, 5 Apr 2021 16:52:59 -0700 Subject: fpga: dfl: pci: add DID for D5005 PAC cards This patch adds the approved PCI Express Device IDs for the PF and VF for the card for D5005 PAC cards. Signed-off-by: Russ Weight Signed-off-by: Matthew Gerlach Signed-off-by: Moritz Fischer --- drivers/fpga/dfl-pci.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c index 04e47e266f26..b44523ea8c91 100644 --- a/drivers/fpga/dfl-pci.c +++ b/drivers/fpga/dfl-pci.c @@ -69,14 +69,16 @@ static void cci_pci_free_irq(struct pci_dev *pcidev) } /* PCI Device ID */ -#define PCIE_DEVICE_ID_PF_INT_5_X 0xBCBD -#define PCIE_DEVICE_ID_PF_INT_6_X 0xBCC0 -#define PCIE_DEVICE_ID_PF_DSC_1_X 0x09C4 -#define PCIE_DEVICE_ID_INTEL_PAC_N3000 0x0B30 +#define PCIE_DEVICE_ID_PF_INT_5_X 0xBCBD +#define PCIE_DEVICE_ID_PF_INT_6_X 0xBCC0 +#define PCIE_DEVICE_ID_PF_DSC_1_X 0x09C4 +#define PCIE_DEVICE_ID_INTEL_PAC_N3000 0x0B30 +#define PCIE_DEVICE_ID_INTEL_PAC_D5005 0x0B2B /* VF Device */ -#define PCIE_DEVICE_ID_VF_INT_5_X 0xBCBF -#define PCIE_DEVICE_ID_VF_INT_6_X 0xBCC1 -#define PCIE_DEVICE_ID_VF_DSC_1_X 0x09C5 +#define PCIE_DEVICE_ID_VF_INT_5_X 0xBCBF +#define PCIE_DEVICE_ID_VF_INT_6_X 0xBCC1 +#define PCIE_DEVICE_ID_VF_DSC_1_X 0x09C5 +#define PCIE_DEVICE_ID_INTEL_PAC_D5005_VF 0x0B2C static struct pci_device_id cci_pcie_id_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_5_X),}, @@ -86,6 +88,8 @@ static struct pci_device_id cci_pcie_id_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_DSC_1_X),}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_DSC_1_X),}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_N3000),}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005),}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005_VF),}, {0,} }; MODULE_DEVICE_TABLE(pci, cci_pcie_id_tbl); -- cgit v1.2.3 From 48f17f96a81763c7c8bf5500460a359b9939359f Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Wed, 31 Mar 2021 08:46:10 +0800 Subject: soundwire: stream: fix memory leak in stream config error path When stream config is failed, master runtime will release all slave runtime in the slave_rt_list, but slave runtime is not added to the list at this time. This patch frees slave runtime in the config error path to fix the memory leak. Fixes: 89e590535f32 ("soundwire: Add support for SoundWire stream management") Signed-off-by: Rander Wang Reviewed-by: Keyon Jie Reviewed-by: Guennadi Liakhovetski Reviewed-by: Pierre-Louis Bossart Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210331004610.12242-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/stream.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 9c064b672745..1eaedaaba094 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -1375,8 +1375,16 @@ int sdw_stream_add_slave(struct sdw_slave *slave, } ret = sdw_config_stream(&slave->dev, stream, stream_config, true); - if (ret) + if (ret) { + /* + * sdw_release_master_stream will release s_rt in slave_rt_list in + * stream_error case, but s_rt is only added to slave_rt_list + * when sdw_config_stream is successful, so free s_rt explicitly + * when sdw_config_stream is failed. + */ + kfree(s_rt); goto stream_error; + } list_add_tail(&s_rt->m_rt_node, &m_rt->slave_rt_list); -- cgit v1.2.3 From f4022062e5417ab7228e95aec1a8687059a19db7 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 15 Mar 2021 16:56:46 +0000 Subject: soundwire: add static port mapping support Some of the SoundWire device ports are statically mapped to Controller ports during design, however there is no way to expose this information to the controller. Controllers like Qualcomm ones use this info to setup static bandwidth parameters for those ports. A generic port allocation is not possible in this cases! So this patch adds a new member m_port_map to struct sdw_slave to expose this static map. Signed-off-by: Srinivas Kandagatla Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210315165650.13392-2-srinivas.kandagatla@linaro.org Signed-off-by: Vinod Koul --- include/linux/soundwire/sdw.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 5ff9a8f37e91..ced07f8fde87 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -642,6 +642,7 @@ struct sdw_slave_ops { * @debugfs: Slave debugfs * @node: node for bus list * @port_ready: Port ready completion flag for each Slave port + * @m_port_map: static Master port map for each Slave port * @dev_num: Current Device Number, values can be 0 or dev_num_sticky * @dev_num_sticky: one-time static Device Number assigned by Bus * @probed: boolean tracking driver state @@ -673,6 +674,7 @@ struct sdw_slave { #endif struct list_head node; struct completion port_ready[SDW_MAX_PORTS]; + unsigned int m_port_map[SDW_MAX_PORTS]; enum sdw_clk_stop_mode curr_clk_stop_mode; u16 dev_num; u16 dev_num_sticky; -- cgit v1.2.3 From 650dfdb894f0f2bc568a29ab91c704dca587458b Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 15 Mar 2021 16:56:47 +0000 Subject: soundwire: qcom: update port map allocation bit mask currently the internal bitmask used for allocating ports starts with offset 0. This is bit confusing as data port numbers on Qualcomm controller are valid from 1 to 14. So adjust this bit mask accordingly, this will also help while adding static port map support. Signed-off-by: Srinivas Kandagatla Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210315165650.13392-3-srinivas.kandagatla@linaro.org Signed-off-by: Vinod Koul --- drivers/soundwire/qcom.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index ec86c4e53fdb..9493b50a79d5 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -797,7 +797,7 @@ static void qcom_swrm_stream_free_ports(struct qcom_swrm_ctrl *ctrl, port_mask = &ctrl->din_port_mask; list_for_each_entry(p_rt, &m_rt->port_list, port_node) - clear_bit(p_rt->num - 1, port_mask); + clear_bit(p_rt->num, port_mask); } mutex_unlock(&ctrl->port_lock); @@ -830,13 +830,13 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, list_for_each_entry(p_rt, &s_rt->port_list, port_node) { /* Port numbers start from 1 - 14*/ pn = find_first_zero_bit(port_mask, maxport); - if (pn > (maxport - 1)) { + if (pn > maxport) { dev_err(ctrl->dev, "All ports busy\n"); ret = -EBUSY; goto err; } set_bit(pn, port_mask); - pconfig[nports].num = pn + 1; + pconfig[nports].num = pn; pconfig[nports].ch_mask = p_rt->ch_mask; nports++; } @@ -858,7 +858,7 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, err: if (ret) { for (i = 0; i < nports; i++) - clear_bit(pconfig[i].num - 1, port_mask); + clear_bit(pconfig[i].num, port_mask); } mutex_unlock(&ctrl->port_lock); @@ -1037,6 +1037,9 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) ctrl->num_dout_ports = val; nports = ctrl->num_dout_ports + ctrl->num_din_ports; + /* Valid port numbers are from 1-14, so mask out port 0 explicitly */ + set_bit(0, &ctrl->dout_port_mask); + set_bit(0, &ctrl->din_port_mask); ret = of_property_read_u8_array(np, "qcom,ports-offset1", off1, nports); -- cgit v1.2.3 From eb5a909441a896fe9e230086363284a09c23e5df Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 15 Mar 2021 16:56:48 +0000 Subject: soundwire: qcom: add static port map support SoundWire device ports are statically mapped to Controller ports during design. Add support to read these from SoundWire devices. This controller uses static port map info to setup bandwidth parameters for those ports. A generic port allocation is not possible in this cases! Signed-off-by: Srinivas Kandagatla Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210315165650.13392-4-srinivas.kandagatla@linaro.org Signed-off-by: Vinod Koul --- drivers/soundwire/qcom.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 9493b50a79d5..5eb8b4079438 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -733,6 +733,8 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus) struct sdw_slave_runtime *s_rt; struct sdw_port_runtime *p_rt; struct qcom_swrm_port_config *pcfg; + struct sdw_slave *slave; + unsigned int m_port; int i = 0; list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { @@ -749,8 +751,14 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus) } list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { + slave = s_rt->slave; list_for_each_entry(p_rt, &s_rt->port_list, port_node) { - pcfg = &ctrl->pconfig[i]; + m_port = slave->m_port_map[p_rt->num]; + /* port config starts at offset 0 so -1 from actual port number */ + if (m_port) + pcfg = &ctrl->pconfig[m_port - 1]; + else + pcfg = &ctrl->pconfig[i]; p_rt->transport_params.port_num = p_rt->num; p_rt->transport_params.sample_interval = pcfg->si + 1; @@ -813,8 +821,10 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, struct sdw_master_runtime *m_rt; struct sdw_slave_runtime *s_rt; struct sdw_port_runtime *p_rt; + struct sdw_slave *slave; unsigned long *port_mask; int i, maxport, pn, nports = 0, ret = 0; + unsigned int m_port; mutex_lock(&ctrl->port_lock); list_for_each_entry(m_rt, &stream->master_list, stream_node) { @@ -827,9 +837,15 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, } list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { + slave = s_rt->slave; list_for_each_entry(p_rt, &s_rt->port_list, port_node) { + m_port = slave->m_port_map[p_rt->num]; /* Port numbers start from 1 - 14*/ - pn = find_first_zero_bit(port_mask, maxport); + if (m_port) + pn = m_port; + else + pn = find_first_zero_bit(port_mask, maxport); + if (pn > maxport) { dev_err(ctrl->dev, "All ports busy\n"); ret = -EBUSY; -- cgit v1.2.3 From a661308c34de8cbd22165edf63dbd24ccb914981 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 1 Apr 2021 10:00:58 +0100 Subject: soundwire: qcom: wait for fifo space to be available before read/write If we write registers very fast we can endup in a situation where some of the writes will be dropped without any notice. So wait for the fifo space to be available before reading/writing the soundwire registers. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210401090058.24041-1-srinivas.kandagatla@linaro.org Signed-off-by: Vinod Koul --- drivers/soundwire/qcom.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 5eb8b4079438..190e4d7f486a 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -24,6 +24,8 @@ #define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK BIT(1) #define SWRM_COMP_CFG_ENABLE_MSK BIT(0) #define SWRM_COMP_PARAMS 0x100 +#define SWRM_COMP_PARAMS_WR_FIFO_DEPTH GENMASK(14, 10) +#define SWRM_COMP_PARAMS_RD_FIFO_DEPTH GENMASK(19, 15) #define SWRM_COMP_PARAMS_DOUT_PORTS_MASK GENMASK(4, 0) #define SWRM_COMP_PARAMS_DIN_PORTS_MASK GENMASK(9, 5) #define SWRM_INTERRUPT_STATUS 0x200 @@ -51,6 +53,8 @@ #define SWRM_CMD_FIFO_CMD 0x308 #define SWRM_CMD_FIFO_FLUSH 0x1 #define SWRM_CMD_FIFO_STATUS 0x30C +#define SWRM_RD_CMD_FIFO_CNT_MASK GENMASK(20, 16) +#define SWRM_WR_CMD_FIFO_CNT_MASK GENMASK(12, 8) #define SWRM_CMD_FIFO_CFG_ADDR 0x314 #define SWRM_CONTINUE_EXEC_ON_CMD_IGNORE BIT(31) #define SWRM_RD_WR_CMD_RETRIES 0x7 @@ -104,6 +108,7 @@ #define SWR_BROADCAST_CMD_ID 0x0F #define SWR_MAX_CMD_ID 14 #define MAX_FIFO_RD_RETRY 3 +#define SWR_OVERFLOW_RETRY_COUNT 30 struct qcom_swrm_port_config { u8 si; @@ -147,6 +152,8 @@ struct qcom_swrm_ctrl { int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val); int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val); u32 slave_status; + u32 wr_fifo_depth; + u32 rd_fifo_depth; }; struct qcom_swrm_data { @@ -238,6 +245,55 @@ static u32 swrm_get_packed_reg_val(u8 *cmd_id, u8 cmd_data, return val; } +static int swrm_wait_for_rd_fifo_avail(struct qcom_swrm_ctrl *swrm) +{ + u32 fifo_outstanding_data, value; + int fifo_retry_count = SWR_OVERFLOW_RETRY_COUNT; + + do { + /* Check for fifo underflow during read */ + swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value); + fifo_outstanding_data = FIELD_GET(SWRM_RD_CMD_FIFO_CNT_MASK, value); + + /* Check if read data is available in read fifo */ + if (fifo_outstanding_data > 0) + return 0; + + usleep_range(500, 510); + } while (fifo_retry_count--); + + if (fifo_outstanding_data == 0) { + dev_err_ratelimited(swrm->dev, "%s err read underflow\n", __func__); + return -EIO; + } + + return 0; +} + +static int swrm_wait_for_wr_fifo_avail(struct qcom_swrm_ctrl *swrm) +{ + u32 fifo_outstanding_cmds, value; + int fifo_retry_count = SWR_OVERFLOW_RETRY_COUNT; + + do { + /* Check for fifo overflow during write */ + swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value); + fifo_outstanding_cmds = FIELD_GET(SWRM_WR_CMD_FIFO_CNT_MASK, value); + + /* Check for space in write fifo before writing */ + if (fifo_outstanding_cmds < swrm->wr_fifo_depth) + return 0; + + usleep_range(500, 510); + } while (fifo_retry_count--); + + if (fifo_outstanding_cmds == swrm->wr_fifo_depth) { + dev_err_ratelimited(swrm->dev, "%s err write overflow\n", __func__); + return -EIO; + } + + return 0; +} static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *swrm, u8 cmd_data, u8 dev_addr, u16 reg_addr) @@ -256,6 +312,9 @@ static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *swrm, u8 cmd_data, dev_addr, reg_addr); } + if (swrm_wait_for_wr_fifo_avail(swrm)) + return SDW_CMD_FAIL_OTHER; + /* Its assumed that write is okay as we do not get any status back */ swrm->reg_write(swrm, SWRM_CMD_FIFO_WR_CMD, val); @@ -295,6 +354,9 @@ static int qcom_swrm_cmd_fifo_rd_cmd(struct qcom_swrm_ctrl *swrm, /* wait for FIFO RD CMD complete to avoid overflow */ usleep_range(250, 255); + if (swrm_wait_for_rd_fifo_avail(swrm)) + return SDW_CMD_FAIL_OTHER; + do { swrm->reg_read(swrm, SWRM_CMD_FIFO_RD_FIFO_ADDR, &cmd_data); rval[0] = cmd_data & 0xFF; @@ -586,6 +648,10 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) SWRM_INTERRUPT_STATUS_RMSK); } ctrl->slave_status = 0; + ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val); + ctrl->rd_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_RD_FIFO_DEPTH, val); + ctrl->wr_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_WR_FIFO_DEPTH, val); + return 0; } -- cgit v1.2.3 From 9916c02ccd74e672b62dd1a9017ac2f237ebf512 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 1 Apr 2021 10:24:54 +0100 Subject: soundwire: qcom: cleanup internal port config indexing Internally used portconfig array for storing port bandwidth params starts from offset zero. However port zero is not really used and we also copy the bus parameters to offset zero. So basically we endup with a code which has to subtract 1 from port number to get to port parameters. This is bit confusing to the reader so, make this bit more obvious by only copying the parameters to offset 1 instead of zero. This will avoid doing -1 every time when we try to get port params. Similar thing has been recently done with din/dout_port_mask. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210401092454.21299-1-srinivas.kandagatla@linaro.org Signed-off-by: Vinod Koul --- drivers/soundwire/qcom.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 190e4d7f486a..892027e6df5f 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -724,7 +724,7 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus, int reg = SWRM_DP_PORT_CTRL_BANK((params->port_num), bank); int ret; - pcfg = &ctrl->pconfig[params->port_num - 1]; + pcfg = &ctrl->pconfig[params->port_num]; value = pcfg->off1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT; value |= pcfg->off2 << SWRM_DP_PORT_CTRL_OFFSET2_SHFT; @@ -801,11 +801,11 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus) struct qcom_swrm_port_config *pcfg; struct sdw_slave *slave; unsigned int m_port; - int i = 0; + int i = 1; list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { list_for_each_entry(p_rt, &m_rt->port_list, port_node) { - pcfg = &ctrl->pconfig[p_rt->num - 1]; + pcfg = &ctrl->pconfig[p_rt->num]; p_rt->transport_params.port_num = p_rt->num; if (pcfg->word_length != SWR_INVALID_PARAM) { sdw_fill_port_params(&p_rt->port_params, @@ -822,7 +822,7 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus) m_port = slave->m_port_map[p_rt->num]; /* port config starts at offset 0 so -1 from actual port number */ if (m_port) - pcfg = &ctrl->pconfig[m_port - 1]; + pcfg = &ctrl->pconfig[m_port]; else pcfg = &ctrl->pconfig[i]; p_rt->transport_params.port_num = p_rt->num; @@ -1159,15 +1159,16 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) of_property_read_u8_array(np, "qcom,ports-lane-control", lane_control, nports); for (i = 0; i < nports; i++) { - ctrl->pconfig[i].si = si[i]; - ctrl->pconfig[i].off1 = off1[i]; - ctrl->pconfig[i].off2 = off2[i]; - ctrl->pconfig[i].bp_mode = bp_mode[i]; - ctrl->pconfig[i].hstart = hstart[i]; - ctrl->pconfig[i].hstop = hstop[i]; - ctrl->pconfig[i].word_length = word_length[i]; - ctrl->pconfig[i].blk_group_count = blk_group_count[i]; - ctrl->pconfig[i].lane_control = lane_control[i]; + /* Valid port number range is from 1-14 */ + ctrl->pconfig[i + 1].si = si[i]; + ctrl->pconfig[i + 1].off1 = off1[i]; + ctrl->pconfig[i + 1].off2 = off2[i]; + ctrl->pconfig[i + 1].bp_mode = bp_mode[i]; + ctrl->pconfig[i + 1].hstart = hstart[i]; + ctrl->pconfig[i + 1].hstop = hstop[i]; + ctrl->pconfig[i + 1].word_length = word_length[i]; + ctrl->pconfig[i + 1].blk_group_count = blk_group_count[i]; + ctrl->pconfig[i + 1].lane_control = lane_control[i]; } return 0; -- cgit v1.2.3 From e729e0fdc63d8f22cbce61159cee88c04e42b3e2 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 1 Apr 2021 10:15:02 +0100 Subject: soundwire: qcom: handle return correctly in qcom_swrm_transport_params Looks like return from reg_write is set but not checked. Fix this by adding error return path. Reported-by: coverity-bot Addresses-Coverity-ID: 1503591 ("UNUSED_VALUE") Fixes: 128eaf937adb ("soundwire: qcom: add support to missing transport params") Signed-off-by: Srinivas Kandagatla Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20210401091502.15825-1-srinivas.kandagatla@linaro.org Signed-off-by: Vinod Koul --- drivers/soundwire/qcom.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 892027e6df5f..2827085a323b 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -731,17 +731,23 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus, value |= pcfg->si; ret = ctrl->reg_write(ctrl, reg, value); + if (ret) + goto err; if (pcfg->lane_control != SWR_INVALID_PARAM) { reg = SWRM_DP_PORT_CTRL_2_BANK(params->port_num, bank); value = pcfg->lane_control; ret = ctrl->reg_write(ctrl, reg, value); + if (ret) + goto err; } if (pcfg->blk_group_count != SWR_INVALID_PARAM) { reg = SWRM_DP_BLOCK_CTRL2_BANK(params->port_num, bank); value = pcfg->blk_group_count; ret = ctrl->reg_write(ctrl, reg, value); + if (ret) + goto err; } if (pcfg->hstart != SWR_INVALID_PARAM @@ -755,11 +761,15 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus, ret = ctrl->reg_write(ctrl, reg, value); } + if (ret) + goto err; + if (pcfg->bp_mode != SWR_INVALID_PARAM) { reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank); ret = ctrl->reg_write(ctrl, reg, pcfg->bp_mode); } +err: return ret; } -- cgit v1.2.3 From 14968dd36a507866be0edfc2a05d48c997da5d99 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 6 Apr 2021 09:01:01 +0800 Subject: soundwire: intel_init: test link->cdns intel_link_probe() could return error and dev_get_drvdata() will return null in such case. So we have to test link->cdns after link->cdns = dev_get_drvdata(&ldev->auxdev.dev); Otherwise, we will meet the "kernel NULL pointer dereference" error. Signed-off-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210406010101.11442-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel_init.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index 05b726cdfebc..30ce95ec2d70 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -178,6 +178,15 @@ static struct sdw_intel_ctx link->pdev = pdev; link->cdns = platform_get_drvdata(pdev); + if (!link->cdns) { + dev_err(&adev->dev, "failed to get link->cdns\n"); + /* + * 1 will be subtracted from i in the err label, but we need to call + * intel_link_dev_unregister for this ldev, so plus 1 now + */ + i++; + goto err; + } list_add_tail(&link->list, &ctx->link_list); bus = &link->cdns->bus; /* Calculate number of slaves */ -- cgit v1.2.3 From 183bf0917e491e83881ccf6fb7d3df0aa843b756 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 1 Apr 2021 14:00:45 -0700 Subject: phy: marvell: phy-mvebu-cp11i-utmi needs USB_COMMON When USB and USB_COMMON are not enabled, phy-mvebu-cp110-utmi suffers a build error due to a missing interface that is provided by CONFIG_USB_COMMON, so make the driver depend on USB_COMMON. ld: drivers/phy/marvell/phy-mvebu-cp110-utmi.o: in function `mvebu_cp110_utmi_phy_probe': phy-mvebu-cp110-utmi.c:(.text+0x152): undefined reference to `of_usb_get_dr_mode_by_phy' Signed-off-by: Randy Dunlap Cc: Kostya Porotchkin Cc: Kishon Vijay Abraham I Cc: Vinod Koul Cc: linux-phy@lists.infradead.org Link: https://lore.kernel.org/r/20210401210045.23525-1-rdunlap@infradead.org Signed-off-by: Vinod Koul --- drivers/phy/marvell/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/marvell/Kconfig b/drivers/phy/marvell/Kconfig index c5651ef70666..bdb87c976243 100644 --- a/drivers/phy/marvell/Kconfig +++ b/drivers/phy/marvell/Kconfig @@ -70,7 +70,7 @@ config PHY_MVEBU_CP110_COMPHY config PHY_MVEBU_CP110_UTMI tristate "Marvell CP110 UTMI driver" depends on ARCH_MVEBU || COMPILE_TEST - depends on OF + depends on OF && USB_COMMON select GENERIC_PHY help Enable this to support Marvell CP110 UTMI PHY driver. -- cgit v1.2.3 From 646944853db763f449fc762fbd8e6ba056d77451 Mon Sep 17 00:00:00 2001 From: Hao Fang Date: Thu, 1 Apr 2021 20:02:17 +0800 Subject: phy: hisilicon: Use the correct HiSilicon copyright s/Hisilicon/HiSilicon/g. It should use capital S, according to the official website. Signed-off-by: Hao Fang Link: https://lore.kernel.org/r/1617278537-26102-1-git-send-email-fanghao11@huawei.com Signed-off-by: Vinod Koul --- drivers/phy/hisilicon/phy-hi6220-usb.c | 2 +- drivers/phy/hisilicon/phy-hix5hd2-sata.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/phy/hisilicon/phy-hi6220-usb.c b/drivers/phy/hisilicon/phy-hi6220-usb.c index be05292df8b8..e92ba78da4c8 100644 --- a/drivers/phy/hisilicon/phy-hi6220-usb.c +++ b/drivers/phy/hisilicon/phy-hi6220-usb.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2015 Linaro Ltd. - * Copyright (c) 2015 Hisilicon Limited. + * Copyright (c) 2015 HiSilicon Limited. */ #include diff --git a/drivers/phy/hisilicon/phy-hix5hd2-sata.c b/drivers/phy/hisilicon/phy-hix5hd2-sata.c index c67b78cd2602..b0f99a9ac857 100644 --- a/drivers/phy/hisilicon/phy-hix5hd2-sata.c +++ b/drivers/phy/hisilicon/phy-hix5hd2-sata.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2014 Linaro Ltd. - * Copyright (c) 2014 Hisilicon Limited. + * Copyright (c) 2014 HiSilicon Limited. */ #include -- cgit v1.2.3 From 8595ffb52fa3a1dd8620f0029a0e22ee37efd17f Mon Sep 17 00:00:00 2001 From: Steen Hegelund Date: Mon, 29 Mar 2021 16:13:09 +0200 Subject: phy: Sparx5 Eth SerDes: Use direct register operations Use direct register operations instead of a table of register information to lower the stack usage. Signed-off-by: Steen Hegelund Reported-by: kernel test robot Link: https://lore.kernel.org/r/20210329141309.612459-2-steen.hegelund@microchip.com Signed-off-by: Vinod Koul --- drivers/phy/microchip/sparx5_serdes.c | 1869 +++++++++++++++++---------------- 1 file changed, 951 insertions(+), 918 deletions(-) diff --git a/drivers/phy/microchip/sparx5_serdes.c b/drivers/phy/microchip/sparx5_serdes.c index 06bcf0c166cf..338a4220b45f 100644 --- a/drivers/phy/microchip/sparx5_serdes.c +++ b/drivers/phy/microchip/sparx5_serdes.c @@ -343,12 +343,6 @@ struct sparx5_sd10g28_params { u8 fx_100; }; -struct sparx5_serdes_regval { - u32 value; - u32 mask; - void __iomem *addr; -}; - static struct sparx5_sd25g28_media_preset media_presets_25g[] = { { /* ETH_MEDIA_DEFAULT */ .cfg_en_adv = 0, @@ -945,431 +939,411 @@ static void sparx5_sd25g28_reset(void __iomem *regs[], } } -static int sparx5_sd25g28_apply_params(struct device *dev, - void __iomem *regs[], - struct sparx5_sd25g28_params *params, - u32 sd_index) +static int sparx5_sd25g28_apply_params(struct sparx5_serdes_macro *macro, + struct sparx5_sd25g28_params *params) { - struct sparx5_serdes_regval item[] = { - { - SD_LANE_25G_SD_LANE_CFG_MACRO_RST_SET(1), - SD_LANE_25G_SD_LANE_CFG_MACRO_RST, - sdx5_addr(regs, SD_LANE_25G_SD_LANE_CFG(sd_index)) - }, - { - SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_SET(0xFF), - SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX, - sdx5_addr(regs, SD25G_LANE_CMU_FF(sd_index)) - }, - { - SD25G_LANE_CMU_1A_R_DWIDTHCTRL_FROM_HWT_SET - (params->r_d_width_ctrl_from_hwt) | - SD25G_LANE_CMU_1A_R_REG_MANUAL_SET(params->r_reg_manual), - SD25G_LANE_CMU_1A_R_DWIDTHCTRL_FROM_HWT | - SD25G_LANE_CMU_1A_R_REG_MANUAL, - sdx5_addr(regs, SD25G_LANE_CMU_1A(sd_index)) - }, - { - SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0_SET - (params->cfg_common_reserve_7_0), - SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0, - sdx5_addr(regs, SD25G_LANE_CMU_31(sd_index)) - }, - { - SD25G_LANE_CMU_09_CFG_EN_DUMMY_SET(params->cfg_en_dummy), - SD25G_LANE_CMU_09_CFG_EN_DUMMY, - sdx5_addr(regs, SD25G_LANE_CMU_09(sd_index)) - }, - { - SD25G_LANE_CMU_13_CFG_PLL_RESERVE_3_0_SET(params->cfg_pll_reserve_3_0), - SD25G_LANE_CMU_13_CFG_PLL_RESERVE_3_0, - sdx5_addr(regs, SD25G_LANE_CMU_13(sd_index)) - }, - { - SD25G_LANE_CMU_40_L0_CFG_TXCAL_EN_SET(params->l0_cfg_txcal_en), - SD25G_LANE_CMU_40_L0_CFG_TXCAL_EN, - sdx5_addr(regs, SD25G_LANE_CMU_40(sd_index)) - }, - { - SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8_SET - (params->l0_cfg_tx_reserve_15_8), - SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8, - sdx5_addr(regs, SD25G_LANE_CMU_46(sd_index)) - }, - { - SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0_SET(params->l0_cfg_tx_reserve_7_0), - SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0, - sdx5_addr(regs, SD25G_LANE_CMU_45(sd_index)) - }, - { - SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN_SET(0), - SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN, - sdx5_addr(regs, SD25G_LANE_CMU_0B(sd_index)) - }, - { - SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN_SET(1), - SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN, - sdx5_addr(regs, SD25G_LANE_CMU_0B(sd_index)) - }, - { - SD25G_LANE_CMU_19_R_CK_RESETB_SET(0), - SD25G_LANE_CMU_19_R_CK_RESETB, - sdx5_addr(regs, SD25G_LANE_CMU_19(sd_index)) - }, - { - SD25G_LANE_CMU_19_R_CK_RESETB_SET(1), - SD25G_LANE_CMU_19_R_CK_RESETB, - sdx5_addr(regs, SD25G_LANE_CMU_19(sd_index)) - }, - { - SD25G_LANE_CMU_18_R_PLL_RSTN_SET(0), - SD25G_LANE_CMU_18_R_PLL_RSTN, - sdx5_addr(regs, SD25G_LANE_CMU_18(sd_index)) - }, - { - SD25G_LANE_CMU_18_R_PLL_RSTN_SET(1), - SD25G_LANE_CMU_18_R_PLL_RSTN, - sdx5_addr(regs, SD25G_LANE_CMU_18(sd_index)) - }, - { - SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0_SET(params->r_d_width_ctrl_2_0), - SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0, - sdx5_addr(regs, SD25G_LANE_CMU_1A(sd_index)) - }, - { - SD25G_LANE_CMU_30_R_TXFIFO_CK_DIV_PMAD_2_0_SET - (params->r_txfifo_ck_div_pmad_2_0) | - SD25G_LANE_CMU_30_R_RXFIFO_CK_DIV_PMAD_2_0_SET - (params->r_rxfifo_ck_div_pmad_2_0), - SD25G_LANE_CMU_30_R_TXFIFO_CK_DIV_PMAD_2_0 | - SD25G_LANE_CMU_30_R_RXFIFO_CK_DIV_PMAD_2_0, - sdx5_addr(regs, SD25G_LANE_CMU_30(sd_index)) - }, - { - SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET_SET(params->cfg_pll_lol_set) | - SD25G_LANE_CMU_0C_CFG_VCO_DIV_MODE_1_0_SET(params->cfg_vco_div_mode_1_0), - SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET | - SD25G_LANE_CMU_0C_CFG_VCO_DIV_MODE_1_0, - sdx5_addr(regs, SD25G_LANE_CMU_0C(sd_index)) - }, - { - SD25G_LANE_CMU_0D_CFG_PRE_DIVSEL_1_0_SET(params->cfg_pre_divsel_1_0), - SD25G_LANE_CMU_0D_CFG_PRE_DIVSEL_1_0, - sdx5_addr(regs, SD25G_LANE_CMU_0D(sd_index)) - }, - { - SD25G_LANE_CMU_0E_CFG_SEL_DIV_3_0_SET(params->cfg_sel_div_3_0), - SD25G_LANE_CMU_0E_CFG_SEL_DIV_3_0, - sdx5_addr(regs, SD25G_LANE_CMU_0E(sd_index)) - }, - { - SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_SET(0x00), - SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX, - sdx5_addr(regs, SD25G_LANE_CMU_FF(sd_index)) - }, - { - SD25G_LANE_LANE_0C_LN_CFG_PMA_TX_CK_BITWIDTH_2_0_SET - (params->cfg_pma_tx_ck_bitwidth_2_0), - SD25G_LANE_LANE_0C_LN_CFG_PMA_TX_CK_BITWIDTH_2_0, - sdx5_addr(regs, SD25G_LANE_LANE_0C(sd_index)) - }, - { - SD25G_LANE_LANE_01_LN_CFG_TX_PREDIV_1_0_SET(params->cfg_tx_prediv_1_0), - SD25G_LANE_LANE_01_LN_CFG_TX_PREDIV_1_0, - sdx5_addr(regs, SD25G_LANE_LANE_01(sd_index)) - }, - { - SD25G_LANE_LANE_18_LN_CFG_RXDIV_SEL_2_0_SET(params->cfg_rxdiv_sel_2_0), - SD25G_LANE_LANE_18_LN_CFG_RXDIV_SEL_2_0, - sdx5_addr(regs, SD25G_LANE_LANE_18(sd_index)) - }, - { - SD25G_LANE_LANE_2C_LN_CFG_TX_SUBRATE_2_0_SET(params->cfg_tx_subrate_2_0), - SD25G_LANE_LANE_2C_LN_CFG_TX_SUBRATE_2_0, - sdx5_addr(regs, SD25G_LANE_LANE_2C(sd_index)) - }, - { - SD25G_LANE_LANE_28_LN_CFG_RX_SUBRATE_2_0_SET(params->cfg_rx_subrate_2_0), - SD25G_LANE_LANE_28_LN_CFG_RX_SUBRATE_2_0, - sdx5_addr(regs, SD25G_LANE_LANE_28(sd_index)) - }, - { - SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN_SET(params->cfg_cdrck_en), - SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN, - sdx5_addr(regs, SD25G_LANE_LANE_18(sd_index)) - }, - { - SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1_SET(params->cfg_dfetap_en_5_1), - SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1, - sdx5_addr(regs, SD25G_LANE_LANE_0F(sd_index)) - }, - { - SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD_SET(params->cfg_erramp_pd), - SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD, - sdx5_addr(regs, SD25G_LANE_LANE_18(sd_index)) - }, - { - SD25G_LANE_LANE_1D_LN_CFG_PI_DFE_EN_SET(params->cfg_pi_dfe_en), - SD25G_LANE_LANE_1D_LN_CFG_PI_DFE_EN, - sdx5_addr(regs, SD25G_LANE_LANE_1D(sd_index)) - }, - { - SD25G_LANE_LANE_19_LN_CFG_ECDR_PD_SET(params->cfg_ecdr_pd), - SD25G_LANE_LANE_19_LN_CFG_ECDR_PD, - sdx5_addr(regs, SD25G_LANE_LANE_19(sd_index)) - }, - { - SD25G_LANE_LANE_01_LN_CFG_ITX_IPDRIVER_BASE_2_0_SET - (params->cfg_itx_ipdriver_base_2_0), - SD25G_LANE_LANE_01_LN_CFG_ITX_IPDRIVER_BASE_2_0, - sdx5_addr(regs, SD25G_LANE_LANE_01(sd_index)) - }, - { - SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0_SET(params->cfg_tap_dly_4_0), - SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0, - sdx5_addr(regs, SD25G_LANE_LANE_03(sd_index)) - }, - { - SD25G_LANE_LANE_06_LN_CFG_TAP_ADV_3_0_SET(params->cfg_tap_adv_3_0), - SD25G_LANE_LANE_06_LN_CFG_TAP_ADV_3_0, - sdx5_addr(regs, SD25G_LANE_LANE_06(sd_index)) - }, - { - SD25G_LANE_LANE_07_LN_CFG_EN_ADV_SET(params->cfg_en_adv) | - SD25G_LANE_LANE_07_LN_CFG_EN_DLY_SET(params->cfg_en_dly), - SD25G_LANE_LANE_07_LN_CFG_EN_ADV | - SD25G_LANE_LANE_07_LN_CFG_EN_DLY, - sdx5_addr(regs, SD25G_LANE_LANE_07(sd_index)) - }, - { - SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8_SET(params->cfg_tx_reserve_15_8), - SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8, - sdx5_addr(regs, SD25G_LANE_LANE_43(sd_index)) - }, - { - SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0_SET(params->cfg_tx_reserve_7_0), - SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0, - sdx5_addr(regs, SD25G_LANE_LANE_42(sd_index)) - }, - { - SD25G_LANE_LANE_05_LN_CFG_BW_1_0_SET(params->cfg_bw_1_0), - SD25G_LANE_LANE_05_LN_CFG_BW_1_0, - sdx5_addr(regs, SD25G_LANE_LANE_05(sd_index)) - }, - { - SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN_SET(params->cfg_txcal_man_en), - SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN, - sdx5_addr(regs, SD25G_LANE_LANE_0B(sd_index)) - }, - { - SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0_SET - (params->cfg_txcal_shift_code_5_0), - SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0, - sdx5_addr(regs, SD25G_LANE_LANE_0A(sd_index)) - }, - { - SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0_SET - (params->cfg_txcal_valid_sel_3_0), - SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0, - sdx5_addr(regs, SD25G_LANE_LANE_09(sd_index)) - }, - { - SD25G_LANE_LANE_1A_LN_CFG_CDR_KF_2_0_SET(params->cfg_cdr_kf_2_0), - SD25G_LANE_LANE_1A_LN_CFG_CDR_KF_2_0, - sdx5_addr(regs, SD25G_LANE_LANE_1A(sd_index)) - }, - { - SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0_SET(params->cfg_cdr_m_7_0), - SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0, - sdx5_addr(regs, SD25G_LANE_LANE_1B(sd_index)) - }, - { - SD25G_LANE_LANE_2B_LN_CFG_PI_BW_3_0_SET(params->cfg_pi_bw_3_0), - SD25G_LANE_LANE_2B_LN_CFG_PI_BW_3_0, - sdx5_addr(regs, SD25G_LANE_LANE_2B(sd_index)) - }, - { - SD25G_LANE_LANE_2C_LN_CFG_DIS_2NDORDER_SET(params->cfg_dis_2ndorder), - SD25G_LANE_LANE_2C_LN_CFG_DIS_2NDORDER, - sdx5_addr(regs, SD25G_LANE_LANE_2C(sd_index)) - }, - { - SD25G_LANE_LANE_2E_LN_CFG_CTLE_RSTN_SET(params->cfg_ctle_rstn), - SD25G_LANE_LANE_2E_LN_CFG_CTLE_RSTN, - sdx5_addr(regs, SD25G_LANE_LANE_2E(sd_index)) - }, - { - SD25G_LANE_LANE_00_LN_CFG_ITX_IPCML_BASE_1_0_SET - (params->cfg_itx_ipcml_base_1_0), - SD25G_LANE_LANE_00_LN_CFG_ITX_IPCML_BASE_1_0, - sdx5_addr(regs, SD25G_LANE_LANE_00(sd_index)) - }, - { - SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0_SET(params->cfg_rx_reserve_7_0), - SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0, - sdx5_addr(regs, SD25G_LANE_LANE_44(sd_index)) - }, - { - SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8_SET(params->cfg_rx_reserve_15_8), - SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8, - sdx5_addr(regs, SD25G_LANE_LANE_45(sd_index)) - }, - { - SD25G_LANE_LANE_0D_LN_CFG_DFECK_EN_SET(params->cfg_dfeck_en) | - SD25G_LANE_LANE_0D_LN_CFG_RXTERM_2_0_SET(params->cfg_rxterm_2_0), - SD25G_LANE_LANE_0D_LN_CFG_DFECK_EN | - SD25G_LANE_LANE_0D_LN_CFG_RXTERM_2_0, - sdx5_addr(regs, SD25G_LANE_LANE_0D(sd_index)) - }, - { - SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0_SET - (params->cfg_vga_ctrl_byp_4_0), - SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0, - sdx5_addr(regs, SD25G_LANE_LANE_21(sd_index)) - }, - { - SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0_SET(params->cfg_eqr_force_3_0), - SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0, - sdx5_addr(regs, SD25G_LANE_LANE_22(sd_index)) - }, - { - SD25G_LANE_LANE_1C_LN_CFG_EQC_FORCE_3_0_SET(params->cfg_eqc_force_3_0) | - SD25G_LANE_LANE_1C_LN_CFG_DFE_PD_SET(params->cfg_dfe_pd), - SD25G_LANE_LANE_1C_LN_CFG_EQC_FORCE_3_0 | - SD25G_LANE_LANE_1C_LN_CFG_DFE_PD, - sdx5_addr(regs, SD25G_LANE_LANE_1C(sd_index)) - }, - { - SD25G_LANE_LANE_1E_LN_CFG_SUM_SETCM_EN_SET(params->cfg_sum_setcm_en), - SD25G_LANE_LANE_1E_LN_CFG_SUM_SETCM_EN, - sdx5_addr(regs, SD25G_LANE_LANE_1E(sd_index)) - }, - { - SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0_SET - (params->cfg_init_pos_iscan_6_0), - SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0, - sdx5_addr(regs, SD25G_LANE_LANE_25(sd_index)) - }, - { - SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0_SET - (params->cfg_init_pos_ipi_6_0), - SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0, - sdx5_addr(regs, SD25G_LANE_LANE_26(sd_index)) - }, - { - SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD_SET(params->cfg_erramp_pd), - SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD, - sdx5_addr(regs, SD25G_LANE_LANE_18(sd_index)) - }, - { - SD25G_LANE_LANE_0E_LN_CFG_DFEDIG_M_2_0_SET(params->cfg_dfedig_m_2_0), - SD25G_LANE_LANE_0E_LN_CFG_DFEDIG_M_2_0, - sdx5_addr(regs, SD25G_LANE_LANE_0E(sd_index)) - }, - { - SD25G_LANE_LANE_0E_LN_CFG_EN_DFEDIG_SET(params->cfg_en_dfedig), - SD25G_LANE_LANE_0E_LN_CFG_EN_DFEDIG, - sdx5_addr(regs, SD25G_LANE_LANE_0E(sd_index)) - }, - { - SD25G_LANE_LANE_40_LN_R_TX_POL_INV_SET(params->r_tx_pol_inv) | - SD25G_LANE_LANE_40_LN_R_RX_POL_INV_SET(params->r_rx_pol_inv), - SD25G_LANE_LANE_40_LN_R_TX_POL_INV | - SD25G_LANE_LANE_40_LN_R_RX_POL_INV, - sdx5_addr(regs, SD25G_LANE_LANE_40(sd_index)) - }, - { - SD25G_LANE_LANE_04_LN_CFG_RX2TX_LP_EN_SET(params->cfg_rx2tx_lp_en) | - SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN_SET(params->cfg_tx2rx_lp_en), - SD25G_LANE_LANE_04_LN_CFG_RX2TX_LP_EN | - SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN, - sdx5_addr(regs, SD25G_LANE_LANE_04(sd_index)) - }, - { - SD25G_LANE_LANE_1E_LN_CFG_RXLB_EN_SET(params->cfg_rxlb_en), - SD25G_LANE_LANE_1E_LN_CFG_RXLB_EN, - sdx5_addr(regs, SD25G_LANE_LANE_1E(sd_index)) - }, - { - SD25G_LANE_LANE_19_LN_CFG_TXLB_EN_SET(params->cfg_txlb_en), - SD25G_LANE_LANE_19_LN_CFG_TXLB_EN, - sdx5_addr(regs, SD25G_LANE_LANE_19(sd_index)) - }, - { - SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG_SET(0), - SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG, - sdx5_addr(regs, SD25G_LANE_LANE_2E(sd_index)) - }, - { - SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG_SET(1), - SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG, - sdx5_addr(regs, SD25G_LANE_LANE_2E(sd_index)) - }, - { - SD_LANE_25G_SD_LANE_CFG_MACRO_RST_SET(0), - SD_LANE_25G_SD_LANE_CFG_MACRO_RST, - sdx5_addr(regs, SD_LANE_25G_SD_LANE_CFG(sd_index)) - }, - { - SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN_SET(0), - SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN, - sdx5_addr(regs, SD25G_LANE_LANE_1C(sd_index)) - }, - }; - struct sparx5_serdes_regval item2[] = { - { - SD25G_LANE_CMU_2A_R_DBG_LOL_STATUS_SET(0x1), - SD25G_LANE_CMU_2A_R_DBG_LOL_STATUS, - sdx5_addr(regs, SD25G_LANE_CMU_2A(sd_index)) - }, - { - SD_LANE_25G_SD_SER_RST_SER_RST_SET(0x0), - SD_LANE_25G_SD_SER_RST_SER_RST, - sdx5_addr(regs, SD_LANE_25G_SD_SER_RST(sd_index)) - }, - { - SD_LANE_25G_SD_DES_RST_DES_RST_SET(0x0), - SD_LANE_25G_SD_DES_RST_DES_RST, - sdx5_addr(regs, SD_LANE_25G_SD_DES_RST(sd_index)) - }, - { - SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_SET(0), - SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX, - sdx5_addr(regs, SD25G_LANE_CMU_FF(sd_index)) - }, - { - SD25G_LANE_LANE_2D_LN_CFG_ALOS_THR_2_0_SET(params->cfg_alos_thr_2_0), - SD25G_LANE_LANE_2D_LN_CFG_ALOS_THR_2_0, - sdx5_addr(regs, SD25G_LANE_LANE_2D(sd_index)) - }, - { - SD25G_LANE_LANE_2E_LN_CFG_DIS_SQ_SET(0), - SD25G_LANE_LANE_2E_LN_CFG_DIS_SQ, - sdx5_addr(regs, SD25G_LANE_LANE_2E(sd_index)) - }, - { - SD25G_LANE_LANE_2E_LN_CFG_PD_SQ_SET(0), - SD25G_LANE_LANE_2E_LN_CFG_PD_SQ, - sdx5_addr(regs, SD25G_LANE_LANE_2E(sd_index)) - }, - - }; + struct sparx5_serdes_private *priv = macro->priv; + void __iomem **regs = priv->regs; + struct device *dev = priv->dev; + u32 sd_index = macro->stpidx; u32 value; - int idx; - for (idx = 0; idx < ARRAY_SIZE(item); ++idx) - sdx5_rmw_addr(item[idx].value, item[idx].mask, item[idx].addr); + sdx5_rmw(SD_LANE_25G_SD_LANE_CFG_MACRO_RST_SET(1), + SD_LANE_25G_SD_LANE_CFG_MACRO_RST, + priv, + SD_LANE_25G_SD_LANE_CFG(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_SET(0xFF), + SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX, + priv, + SD25G_LANE_CMU_FF(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_1A_R_DWIDTHCTRL_FROM_HWT_SET + (params->r_d_width_ctrl_from_hwt) | + SD25G_LANE_CMU_1A_R_REG_MANUAL_SET(params->r_reg_manual), + SD25G_LANE_CMU_1A_R_DWIDTHCTRL_FROM_HWT | + SD25G_LANE_CMU_1A_R_REG_MANUAL, + priv, + SD25G_LANE_CMU_1A(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0_SET + (params->cfg_common_reserve_7_0), + SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0, + priv, + SD25G_LANE_CMU_31(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_09_CFG_EN_DUMMY_SET(params->cfg_en_dummy), + SD25G_LANE_CMU_09_CFG_EN_DUMMY, + priv, + SD25G_LANE_CMU_09(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_13_CFG_PLL_RESERVE_3_0_SET + (params->cfg_pll_reserve_3_0), + SD25G_LANE_CMU_13_CFG_PLL_RESERVE_3_0, + priv, + SD25G_LANE_CMU_13(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_40_L0_CFG_TXCAL_EN_SET(params->l0_cfg_txcal_en), + SD25G_LANE_CMU_40_L0_CFG_TXCAL_EN, + priv, + SD25G_LANE_CMU_40(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8_SET + (params->l0_cfg_tx_reserve_15_8), + SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8, + priv, + SD25G_LANE_CMU_46(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0_SET + (params->l0_cfg_tx_reserve_7_0), + SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0, + priv, + SD25G_LANE_CMU_45(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN_SET(0), + SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN, + priv, + SD25G_LANE_CMU_0B(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN_SET(1), + SD25G_LANE_CMU_0B_CFG_VCO_CAL_RESETN, + priv, + SD25G_LANE_CMU_0B(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_19_R_CK_RESETB_SET(0), + SD25G_LANE_CMU_19_R_CK_RESETB, + priv, + SD25G_LANE_CMU_19(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_19_R_CK_RESETB_SET(1), + SD25G_LANE_CMU_19_R_CK_RESETB, + priv, + SD25G_LANE_CMU_19(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_18_R_PLL_RSTN_SET(0), + SD25G_LANE_CMU_18_R_PLL_RSTN, + priv, + SD25G_LANE_CMU_18(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_18_R_PLL_RSTN_SET(1), + SD25G_LANE_CMU_18_R_PLL_RSTN, + priv, + SD25G_LANE_CMU_18(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0_SET(params->r_d_width_ctrl_2_0), + SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0, + priv, + SD25G_LANE_CMU_1A(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_30_R_TXFIFO_CK_DIV_PMAD_2_0_SET + (params->r_txfifo_ck_div_pmad_2_0) | + SD25G_LANE_CMU_30_R_RXFIFO_CK_DIV_PMAD_2_0_SET + (params->r_rxfifo_ck_div_pmad_2_0), + SD25G_LANE_CMU_30_R_TXFIFO_CK_DIV_PMAD_2_0 | + SD25G_LANE_CMU_30_R_RXFIFO_CK_DIV_PMAD_2_0, + priv, + SD25G_LANE_CMU_30(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET_SET(params->cfg_pll_lol_set) | + SD25G_LANE_CMU_0C_CFG_VCO_DIV_MODE_1_0_SET + (params->cfg_vco_div_mode_1_0), + SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET | + SD25G_LANE_CMU_0C_CFG_VCO_DIV_MODE_1_0, + priv, + SD25G_LANE_CMU_0C(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_0D_CFG_PRE_DIVSEL_1_0_SET + (params->cfg_pre_divsel_1_0), + SD25G_LANE_CMU_0D_CFG_PRE_DIVSEL_1_0, + priv, + SD25G_LANE_CMU_0D(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_0E_CFG_SEL_DIV_3_0_SET(params->cfg_sel_div_3_0), + SD25G_LANE_CMU_0E_CFG_SEL_DIV_3_0, + priv, + SD25G_LANE_CMU_0E(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_SET(0x00), + SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX, + priv, + SD25G_LANE_CMU_FF(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_0C_LN_CFG_PMA_TX_CK_BITWIDTH_2_0_SET + (params->cfg_pma_tx_ck_bitwidth_2_0), + SD25G_LANE_LANE_0C_LN_CFG_PMA_TX_CK_BITWIDTH_2_0, + priv, + SD25G_LANE_LANE_0C(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_01_LN_CFG_TX_PREDIV_1_0_SET + (params->cfg_tx_prediv_1_0), + SD25G_LANE_LANE_01_LN_CFG_TX_PREDIV_1_0, + priv, + SD25G_LANE_LANE_01(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_18_LN_CFG_RXDIV_SEL_2_0_SET + (params->cfg_rxdiv_sel_2_0), + SD25G_LANE_LANE_18_LN_CFG_RXDIV_SEL_2_0, + priv, + SD25G_LANE_LANE_18(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_2C_LN_CFG_TX_SUBRATE_2_0_SET + (params->cfg_tx_subrate_2_0), + SD25G_LANE_LANE_2C_LN_CFG_TX_SUBRATE_2_0, + priv, + SD25G_LANE_LANE_2C(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_28_LN_CFG_RX_SUBRATE_2_0_SET + (params->cfg_rx_subrate_2_0), + SD25G_LANE_LANE_28_LN_CFG_RX_SUBRATE_2_0, + priv, + SD25G_LANE_LANE_28(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN_SET(params->cfg_cdrck_en), + SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN, + priv, + SD25G_LANE_LANE_18(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1_SET + (params->cfg_dfetap_en_5_1), + SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1, + priv, + SD25G_LANE_LANE_0F(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD_SET(params->cfg_erramp_pd), + SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD, + priv, + SD25G_LANE_LANE_18(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_1D_LN_CFG_PI_DFE_EN_SET(params->cfg_pi_dfe_en), + SD25G_LANE_LANE_1D_LN_CFG_PI_DFE_EN, + priv, + SD25G_LANE_LANE_1D(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_19_LN_CFG_ECDR_PD_SET(params->cfg_ecdr_pd), + SD25G_LANE_LANE_19_LN_CFG_ECDR_PD, + priv, + SD25G_LANE_LANE_19(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_01_LN_CFG_ITX_IPDRIVER_BASE_2_0_SET + (params->cfg_itx_ipdriver_base_2_0), + SD25G_LANE_LANE_01_LN_CFG_ITX_IPDRIVER_BASE_2_0, + priv, + SD25G_LANE_LANE_01(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0_SET(params->cfg_tap_dly_4_0), + SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0, + priv, + SD25G_LANE_LANE_03(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_06_LN_CFG_TAP_ADV_3_0_SET(params->cfg_tap_adv_3_0), + SD25G_LANE_LANE_06_LN_CFG_TAP_ADV_3_0, + priv, + SD25G_LANE_LANE_06(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_07_LN_CFG_EN_ADV_SET(params->cfg_en_adv) | + SD25G_LANE_LANE_07_LN_CFG_EN_DLY_SET(params->cfg_en_dly), + SD25G_LANE_LANE_07_LN_CFG_EN_ADV | + SD25G_LANE_LANE_07_LN_CFG_EN_DLY, + priv, + SD25G_LANE_LANE_07(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8_SET + (params->cfg_tx_reserve_15_8), + SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8, + priv, + SD25G_LANE_LANE_43(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0_SET + (params->cfg_tx_reserve_7_0), + SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0, + priv, + SD25G_LANE_LANE_42(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_05_LN_CFG_BW_1_0_SET(params->cfg_bw_1_0), + SD25G_LANE_LANE_05_LN_CFG_BW_1_0, + priv, + SD25G_LANE_LANE_05(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN_SET + (params->cfg_txcal_man_en), + SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN, + priv, + SD25G_LANE_LANE_0B(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0_SET + (params->cfg_txcal_shift_code_5_0), + SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0, + priv, + SD25G_LANE_LANE_0A(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0_SET + (params->cfg_txcal_valid_sel_3_0), + SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0, + priv, + SD25G_LANE_LANE_09(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_1A_LN_CFG_CDR_KF_2_0_SET(params->cfg_cdr_kf_2_0), + SD25G_LANE_LANE_1A_LN_CFG_CDR_KF_2_0, + priv, + SD25G_LANE_LANE_1A(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0_SET(params->cfg_cdr_m_7_0), + SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0, + priv, + SD25G_LANE_LANE_1B(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_2B_LN_CFG_PI_BW_3_0_SET(params->cfg_pi_bw_3_0), + SD25G_LANE_LANE_2B_LN_CFG_PI_BW_3_0, + priv, + SD25G_LANE_LANE_2B(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_2C_LN_CFG_DIS_2NDORDER_SET + (params->cfg_dis_2ndorder), + SD25G_LANE_LANE_2C_LN_CFG_DIS_2NDORDER, + priv, + SD25G_LANE_LANE_2C(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_2E_LN_CFG_CTLE_RSTN_SET(params->cfg_ctle_rstn), + SD25G_LANE_LANE_2E_LN_CFG_CTLE_RSTN, + priv, + SD25G_LANE_LANE_2E(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_00_LN_CFG_ITX_IPCML_BASE_1_0_SET + (params->cfg_itx_ipcml_base_1_0), + SD25G_LANE_LANE_00_LN_CFG_ITX_IPCML_BASE_1_0, + priv, + SD25G_LANE_LANE_00(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0_SET + (params->cfg_rx_reserve_7_0), + SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0, + priv, + SD25G_LANE_LANE_44(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8_SET + (params->cfg_rx_reserve_15_8), + SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8, + priv, + SD25G_LANE_LANE_45(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_0D_LN_CFG_DFECK_EN_SET(params->cfg_dfeck_en) | + SD25G_LANE_LANE_0D_LN_CFG_RXTERM_2_0_SET(params->cfg_rxterm_2_0), + SD25G_LANE_LANE_0D_LN_CFG_DFECK_EN | + SD25G_LANE_LANE_0D_LN_CFG_RXTERM_2_0, + priv, + SD25G_LANE_LANE_0D(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0_SET + (params->cfg_vga_ctrl_byp_4_0), + SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0, + priv, + SD25G_LANE_LANE_21(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0_SET + (params->cfg_eqr_force_3_0), + SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0, + priv, + SD25G_LANE_LANE_22(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_1C_LN_CFG_EQC_FORCE_3_0_SET + (params->cfg_eqc_force_3_0) | + SD25G_LANE_LANE_1C_LN_CFG_DFE_PD_SET(params->cfg_dfe_pd), + SD25G_LANE_LANE_1C_LN_CFG_EQC_FORCE_3_0 | + SD25G_LANE_LANE_1C_LN_CFG_DFE_PD, + priv, + SD25G_LANE_LANE_1C(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_1E_LN_CFG_SUM_SETCM_EN_SET + (params->cfg_sum_setcm_en), + SD25G_LANE_LANE_1E_LN_CFG_SUM_SETCM_EN, + priv, + SD25G_LANE_LANE_1E(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0_SET + (params->cfg_init_pos_iscan_6_0), + SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0, + priv, + SD25G_LANE_LANE_25(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0_SET + (params->cfg_init_pos_ipi_6_0), + SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0, + priv, + SD25G_LANE_LANE_26(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD_SET(params->cfg_erramp_pd), + SD25G_LANE_LANE_18_LN_CFG_ERRAMP_PD, + priv, + SD25G_LANE_LANE_18(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_0E_LN_CFG_DFEDIG_M_2_0_SET + (params->cfg_dfedig_m_2_0), + SD25G_LANE_LANE_0E_LN_CFG_DFEDIG_M_2_0, + priv, + SD25G_LANE_LANE_0E(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_0E_LN_CFG_EN_DFEDIG_SET(params->cfg_en_dfedig), + SD25G_LANE_LANE_0E_LN_CFG_EN_DFEDIG, + priv, + SD25G_LANE_LANE_0E(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_40_LN_R_TX_POL_INV_SET(params->r_tx_pol_inv) | + SD25G_LANE_LANE_40_LN_R_RX_POL_INV_SET(params->r_rx_pol_inv), + SD25G_LANE_LANE_40_LN_R_TX_POL_INV | + SD25G_LANE_LANE_40_LN_R_RX_POL_INV, + priv, + SD25G_LANE_LANE_40(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_04_LN_CFG_RX2TX_LP_EN_SET(params->cfg_rx2tx_lp_en) | + SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN_SET(params->cfg_tx2rx_lp_en), + SD25G_LANE_LANE_04_LN_CFG_RX2TX_LP_EN | + SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN, + priv, + SD25G_LANE_LANE_04(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_1E_LN_CFG_RXLB_EN_SET(params->cfg_rxlb_en), + SD25G_LANE_LANE_1E_LN_CFG_RXLB_EN, + priv, + SD25G_LANE_LANE_1E(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_19_LN_CFG_TXLB_EN_SET(params->cfg_txlb_en), + SD25G_LANE_LANE_19_LN_CFG_TXLB_EN, + priv, + SD25G_LANE_LANE_19(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG_SET(0), + SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG, + priv, + SD25G_LANE_LANE_2E(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG_SET(1), + SD25G_LANE_LANE_2E_LN_CFG_RSTN_DFEDIG, + priv, + SD25G_LANE_LANE_2E(sd_index)); + + sdx5_rmw(SD_LANE_25G_SD_LANE_CFG_MACRO_RST_SET(0), + SD_LANE_25G_SD_LANE_CFG_MACRO_RST, + priv, + SD_LANE_25G_SD_LANE_CFG(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN_SET(0), + SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN, + priv, + SD25G_LANE_LANE_1C(sd_index)); + usleep_range(1000, 2000); - sdx5_rmw_addr(SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN_SET(1), + sdx5_rmw(SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN_SET(1), SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN, - sdx5_addr(regs, SD25G_LANE_LANE_1C(sd_index))); + priv, + SD25G_LANE_LANE_1C(sd_index)); usleep_range(10000, 20000); - sdx5_rmw_addr(SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_SET(0xff), + sdx5_rmw(SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_SET(0xff), SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX, - sdx5_addr(regs, SD25G_LANE_CMU_FF(sd_index))); + priv, + SD25G_LANE_CMU_FF(sd_index)); value = readl(sdx5_addr(regs, SD25G_LANE_CMU_C0(sd_index))); value = SD25G_LANE_CMU_C0_PLL_LOL_UDL_GET(value); @@ -1386,15 +1360,46 @@ static int sparx5_sd25g28_apply_params(struct device *dev, dev_err(dev, "25G PMA Reset failed: 0x%x\n", value); return -EINVAL; } - for (idx = 0; idx < ARRAY_SIZE(item2); ++idx) - sdx5_rmw_addr(item2[idx].value, item2[idx].mask, item2[idx].addr); + sdx5_rmw(SD25G_LANE_CMU_2A_R_DBG_LOL_STATUS_SET(0x1), + SD25G_LANE_CMU_2A_R_DBG_LOL_STATUS, + priv, + SD25G_LANE_CMU_2A(sd_index)); + + sdx5_rmw(SD_LANE_25G_SD_SER_RST_SER_RST_SET(0x0), + SD_LANE_25G_SD_SER_RST_SER_RST, + priv, + SD_LANE_25G_SD_SER_RST(sd_index)); + + sdx5_rmw(SD_LANE_25G_SD_DES_RST_DES_RST_SET(0x0), + SD_LANE_25G_SD_DES_RST_DES_RST, + priv, + SD_LANE_25G_SD_DES_RST(sd_index)); + + sdx5_rmw(SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_SET(0), + SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX, + priv, + SD25G_LANE_CMU_FF(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_2D_LN_CFG_ALOS_THR_2_0_SET + (params->cfg_alos_thr_2_0), + SD25G_LANE_LANE_2D_LN_CFG_ALOS_THR_2_0, + priv, + SD25G_LANE_LANE_2D(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_2E_LN_CFG_DIS_SQ_SET(0), + SD25G_LANE_LANE_2E_LN_CFG_DIS_SQ, + priv, + SD25G_LANE_LANE_2E(sd_index)); + + sdx5_rmw(SD25G_LANE_LANE_2E_LN_CFG_PD_SQ_SET(0), + SD25G_LANE_LANE_2E_LN_CFG_PD_SQ, + priv, + SD25G_LANE_LANE_2E(sd_index)); + return 0; } -static void sparx5_sd10g28_reset(void __iomem *regs[], - struct sparx5_sd10g28_params *params, - u32 lane_index, - u32 sd_index) +static void sparx5_sd10g28_reset(void __iomem *regs[], u32 lane_index) { /* Note: SerDes SD10G_LANE_1 is configured in 10G_LAN mode */ sdx5_rmw_addr(SD_LANE_SD_LANE_CFG_EXT_CFG_RST_SET(1), @@ -1402,388 +1407,428 @@ static void sparx5_sd10g28_reset(void __iomem *regs[], sdx5_addr(regs, SD_LANE_SD_LANE_CFG(lane_index))); usleep_range(1000, 2000); + + sdx5_rmw_addr(SD_LANE_SD_LANE_CFG_EXT_CFG_RST_SET(0), + SD_LANE_SD_LANE_CFG_EXT_CFG_RST, + sdx5_addr(regs, SD_LANE_SD_LANE_CFG(lane_index))); } -static int sparx5_sd10g28_apply_params(struct device *dev, - void __iomem *regs[], - struct sparx5_sd10g28_params *params, - void __iomem *sd_inst, - u32 lane_index, - u32 sd_index) +static int sparx5_sd10g28_apply_params(struct sparx5_serdes_macro *macro, + struct sparx5_sd10g28_params *params) { - struct sparx5_serdes_regval item[] = { - { - SD_LANE_SD_LANE_CFG_EXT_CFG_RST_SET(0), - SD_LANE_SD_LANE_CFG_EXT_CFG_RST, - sdx5_addr(regs, SD_LANE_SD_LANE_CFG(lane_index)) - }, - { - SD_LANE_SD_LANE_CFG_MACRO_RST_SET(1), - SD_LANE_SD_LANE_CFG_MACRO_RST, - sdx5_addr(regs, SD_LANE_SD_LANE_CFG(lane_index)) - }, - { - SD10G_LANE_LANE_93_R_DWIDTHCTRL_FROM_HWT_SET(0x0) | - SD10G_LANE_LANE_93_R_REG_MANUAL_SET(0x1) | - SD10G_LANE_LANE_93_R_AUXCKSEL_FROM_HWT_SET(0x1) | - SD10G_LANE_LANE_93_R_LANE_ID_FROM_HWT_SET(0x1) | - SD10G_LANE_LANE_93_R_EN_RATECHG_CTRL_SET(0x0), - SD10G_LANE_LANE_93_R_DWIDTHCTRL_FROM_HWT | - SD10G_LANE_LANE_93_R_REG_MANUAL | - SD10G_LANE_LANE_93_R_AUXCKSEL_FROM_HWT | - SD10G_LANE_LANE_93_R_LANE_ID_FROM_HWT | - SD10G_LANE_LANE_93_R_EN_RATECHG_CTRL, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_93(sd_index)) - }, - { - SD10G_LANE_LANE_94_R_ISCAN_REG_SET(0x1) | - SD10G_LANE_LANE_94_R_TXEQ_REG_SET(0x1) | - SD10G_LANE_LANE_94_R_MISC_REG_SET(0x1) | - SD10G_LANE_LANE_94_R_SWING_REG_SET(0x1), - SD10G_LANE_LANE_94_R_ISCAN_REG | - SD10G_LANE_LANE_94_R_TXEQ_REG | - SD10G_LANE_LANE_94_R_MISC_REG | - SD10G_LANE_LANE_94_R_SWING_REG, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_94(sd_index)) - }, - { - SD10G_LANE_LANE_9E_R_RXEQ_REG_SET(0x1), - SD10G_LANE_LANE_9E_R_RXEQ_REG, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_9E(sd_index)) - }, - { - SD10G_LANE_LANE_A1_R_SSC_FROM_HWT_SET(0x0) | - SD10G_LANE_LANE_A1_R_CDR_FROM_HWT_SET(0x0) | - SD10G_LANE_LANE_A1_R_PCLK_GATING_FROM_HWT_SET(0x1), - SD10G_LANE_LANE_A1_R_SSC_FROM_HWT | - SD10G_LANE_LANE_A1_R_CDR_FROM_HWT | - SD10G_LANE_LANE_A1_R_PCLK_GATING_FROM_HWT, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_A1(sd_index)) - }, - { - SD_LANE_SD_LANE_CFG_RX_REF_SEL_SET(params->cmu_sel) | - SD_LANE_SD_LANE_CFG_TX_REF_SEL_SET(params->cmu_sel), - SD_LANE_SD_LANE_CFG_RX_REF_SEL | - SD_LANE_SD_LANE_CFG_TX_REF_SEL, - sdx5_addr(regs, SD_LANE_SD_LANE_CFG(lane_index)) - }, - { - SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0_SET(params->cfg_lane_reserve_7_0), - SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_40(sd_index)) - }, - { - SD10G_LANE_LANE_50_CFG_SSC_RTL_CLK_SEL_SET(params->cfg_ssc_rtl_clk_sel), - SD10G_LANE_LANE_50_CFG_SSC_RTL_CLK_SEL, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_50(sd_index)) - }, - { - SD10G_LANE_LANE_35_CFG_TXRATE_1_0_SET(params->cfg_txrate_1_0) | - SD10G_LANE_LANE_35_CFG_RXRATE_1_0_SET(params->cfg_rxrate_1_0), - SD10G_LANE_LANE_35_CFG_TXRATE_1_0 | - SD10G_LANE_LANE_35_CFG_RXRATE_1_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_35(sd_index)) - }, - { - SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0_SET(params->r_d_width_ctrl_2_0), - SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_94(sd_index)) - }, - { - SD10G_LANE_LANE_01_CFG_PMA_TX_CK_BITWIDTH_2_0_SET - (params->cfg_pma_tx_ck_bitwidth_2_0), - SD10G_LANE_LANE_01_CFG_PMA_TX_CK_BITWIDTH_2_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_01(sd_index)) - }, - { - SD10G_LANE_LANE_30_CFG_RXDIV_SEL_2_0_SET(params->cfg_rxdiv_sel_2_0), - SD10G_LANE_LANE_30_CFG_RXDIV_SEL_2_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_30(sd_index)) - }, - { - SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0_SET - (params->r_pcs2pma_phymode_4_0), - SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_A2(sd_index)) - }, - { - SD10G_LANE_LANE_13_CFG_CDRCK_EN_SET(params->cfg_cdrck_en), - SD10G_LANE_LANE_13_CFG_CDRCK_EN, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_13(sd_index)) - }, - { - SD10G_LANE_LANE_23_CFG_DFECK_EN_SET(params->cfg_dfeck_en) | - SD10G_LANE_LANE_23_CFG_DFE_PD_SET(params->cfg_dfe_pd) | - SD10G_LANE_LANE_23_CFG_ERRAMP_PD_SET(params->cfg_erramp_pd), - SD10G_LANE_LANE_23_CFG_DFECK_EN | - SD10G_LANE_LANE_23_CFG_DFE_PD | - SD10G_LANE_LANE_23_CFG_ERRAMP_PD, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_23(sd_index)) - }, - { - SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1_SET(params->cfg_dfetap_en_5_1), - SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_22(sd_index)) - }, - { - SD10G_LANE_LANE_1A_CFG_PI_DFE_EN_SET(params->cfg_pi_DFE_en), - SD10G_LANE_LANE_1A_CFG_PI_DFE_EN, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_1A(sd_index)) - }, - { - SD10G_LANE_LANE_02_CFG_EN_ADV_SET(params->cfg_en_adv) | - SD10G_LANE_LANE_02_CFG_EN_MAIN_SET(params->cfg_en_main) | - SD10G_LANE_LANE_02_CFG_EN_DLY_SET(params->cfg_en_dly) | - SD10G_LANE_LANE_02_CFG_TAP_ADV_3_0_SET(params->cfg_tap_adv_3_0), - SD10G_LANE_LANE_02_CFG_EN_ADV | - SD10G_LANE_LANE_02_CFG_EN_MAIN | - SD10G_LANE_LANE_02_CFG_EN_DLY | - SD10G_LANE_LANE_02_CFG_TAP_ADV_3_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_02(sd_index)) - }, - { - SD10G_LANE_LANE_03_CFG_TAP_MAIN_SET(params->cfg_tap_main), - SD10G_LANE_LANE_03_CFG_TAP_MAIN, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_03(sd_index)) - }, - { - SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0_SET(params->cfg_tap_dly_4_0), - SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_04(sd_index)) - }, - { - SD10G_LANE_LANE_2F_CFG_VGA_CTRL_3_0_SET(params->cfg_vga_ctrl_3_0), - SD10G_LANE_LANE_2F_CFG_VGA_CTRL_3_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_2F(sd_index)) - }, - { - SD10G_LANE_LANE_2F_CFG_VGA_CP_2_0_SET(params->cfg_vga_cp_2_0), - SD10G_LANE_LANE_2F_CFG_VGA_CP_2_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_2F(sd_index)) - }, - { - SD10G_LANE_LANE_0B_CFG_EQ_RES_3_0_SET(params->cfg_eq_res_3_0), - SD10G_LANE_LANE_0B_CFG_EQ_RES_3_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_0B(sd_index)) - }, - { - SD10G_LANE_LANE_0D_CFG_EQR_BYP_SET(params->cfg_eq_r_byp), - SD10G_LANE_LANE_0D_CFG_EQR_BYP, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_0D(sd_index)) - }, - { - SD10G_LANE_LANE_0E_CFG_EQC_FORCE_3_0_SET(params->cfg_eq_c_force_3_0) | - SD10G_LANE_LANE_0E_CFG_SUM_SETCM_EN_SET(params->cfg_sum_setcm_en), - SD10G_LANE_LANE_0E_CFG_EQC_FORCE_3_0 | - SD10G_LANE_LANE_0E_CFG_SUM_SETCM_EN, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_0E(sd_index)) - }, - { - SD10G_LANE_LANE_23_CFG_EN_DFEDIG_SET(params->cfg_en_dfedig), - SD10G_LANE_LANE_23_CFG_EN_DFEDIG, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_23(sd_index)) - }, - { - SD10G_LANE_LANE_06_CFG_EN_PREEMPH_SET(params->cfg_en_preemph), - SD10G_LANE_LANE_06_CFG_EN_PREEMPH, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_06(sd_index)) - }, - { - SD10G_LANE_LANE_33_CFG_ITX_IPPREEMP_BASE_1_0_SET - (params->cfg_itx_ippreemp_base_1_0) | - SD10G_LANE_LANE_33_CFG_ITX_IPDRIVER_BASE_2_0_SET - (params->cfg_itx_ipdriver_base_2_0), - SD10G_LANE_LANE_33_CFG_ITX_IPPREEMP_BASE_1_0 | - SD10G_LANE_LANE_33_CFG_ITX_IPDRIVER_BASE_2_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_33(sd_index)) - }, - { - SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0_SET - (params->cfg_ibias_tune_reserve_5_0), - SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_52(sd_index)) - }, - { - SD10G_LANE_LANE_37_CFG_TXSWING_HALF_SET(params->cfg_txswing_half), - SD10G_LANE_LANE_37_CFG_TXSWING_HALF, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_37(sd_index)) - }, - { - SD10G_LANE_LANE_3C_CFG_DIS_2NDORDER_SET(params->cfg_dis_2nd_order), - SD10G_LANE_LANE_3C_CFG_DIS_2NDORDER, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_3C(sd_index)) - }, - { - SD10G_LANE_LANE_39_CFG_RX_SSC_LH_SET(params->cfg_rx_ssc_lh), - SD10G_LANE_LANE_39_CFG_RX_SSC_LH, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_39(sd_index)) - }, - { - SD10G_LANE_LANE_1A_CFG_PI_FLOOP_STEPS_1_0_SET - (params->cfg_pi_floop_steps_1_0), - SD10G_LANE_LANE_1A_CFG_PI_FLOOP_STEPS_1_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_1A(sd_index)) - }, - { - SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16_SET(params->cfg_pi_ext_dac_23_16), - SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_16(sd_index)) - }, - { - SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8_SET(params->cfg_pi_ext_dac_15_8), - SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_15(sd_index)) - }, - { - SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0_SET - (params->cfg_iscan_ext_dac_7_0), - SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_26(sd_index)) - }, - { - SD10G_LANE_LANE_42_CFG_CDR_KF_GEN1_2_0_SET(params->cfg_cdr_kf_gen1_2_0), - SD10G_LANE_LANE_42_CFG_CDR_KF_GEN1_2_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_42(sd_index)) - }, - { - SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0_SET(params->r_cdr_m_gen1_7_0), - SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_0F(sd_index)) - }, - { - SD10G_LANE_LANE_24_CFG_PI_BW_GEN1_3_0_SET(params->cfg_pi_bw_gen1_3_0), - SD10G_LANE_LANE_24_CFG_PI_BW_GEN1_3_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_24(sd_index)) - }, - { - SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0_SET(params->cfg_pi_ext_dac_7_0), - SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_14(sd_index)) - }, - { - SD10G_LANE_LANE_1A_CFG_PI_STEPS_SET(params->cfg_pi_steps), - SD10G_LANE_LANE_1A_CFG_PI_STEPS, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_1A(sd_index)) - }, - { - SD10G_LANE_LANE_3A_CFG_MP_MAX_3_0_SET(params->cfg_mp_max_3_0), - SD10G_LANE_LANE_3A_CFG_MP_MAX_3_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_3A(sd_index)) - }, - { - SD10G_LANE_LANE_31_CFG_RSTN_DFEDIG_SET(params->cfg_rstn_dfedig), - SD10G_LANE_LANE_31_CFG_RSTN_DFEDIG, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_31(sd_index)) - }, - { - SD10G_LANE_LANE_48_CFG_ALOS_THR_3_0_SET(params->cfg_alos_thr_3_0), - SD10G_LANE_LANE_48_CFG_ALOS_THR_3_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_48(sd_index)) - }, - { - SD10G_LANE_LANE_36_CFG_PREDRV_SLEWRATE_1_0_SET - (params->cfg_predrv_slewrate_1_0), - SD10G_LANE_LANE_36_CFG_PREDRV_SLEWRATE_1_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_36(sd_index)) - }, - { - SD10G_LANE_LANE_32_CFG_ITX_IPCML_BASE_1_0_SET - (params->cfg_itx_ipcml_base_1_0), - SD10G_LANE_LANE_32_CFG_ITX_IPCML_BASE_1_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_32(sd_index)) - }, - { - SD10G_LANE_LANE_37_CFG_IP_PRE_BASE_1_0_SET(params->cfg_ip_pre_base_1_0), - SD10G_LANE_LANE_37_CFG_IP_PRE_BASE_1_0, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_37(sd_index)) - }, - { - SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8_SET - (params->cfg_lane_reserve_15_8), - SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_41(sd_index)) - }, - { - SD10G_LANE_LANE_9E_R_EN_AUTO_CDR_RSTN_SET(params->r_en_auto_cdr_rstn), - SD10G_LANE_LANE_9E_R_EN_AUTO_CDR_RSTN, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_9E(sd_index)) - }, - { - SD10G_LANE_LANE_0C_CFG_OSCAL_AFE_SET(params->cfg_oscal_afe) | - SD10G_LANE_LANE_0C_CFG_PD_OSDAC_AFE_SET(params->cfg_pd_osdac_afe), - SD10G_LANE_LANE_0C_CFG_OSCAL_AFE | - SD10G_LANE_LANE_0C_CFG_PD_OSDAC_AFE, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_0C(sd_index)) - }, - { - SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE_SET - (params->cfg_resetb_oscal_afe[0]), - SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_0B(sd_index)) - }, - { - SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE_SET - (params->cfg_resetb_oscal_afe[1]), - SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_0B(sd_index)) - }, - { - SD10G_LANE_LANE_83_R_TX_POL_INV_SET(params->r_tx_pol_inv) | - SD10G_LANE_LANE_83_R_RX_POL_INV_SET(params->r_rx_pol_inv), - SD10G_LANE_LANE_83_R_TX_POL_INV | - SD10G_LANE_LANE_83_R_RX_POL_INV, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_83(sd_index)) - }, - { - SD10G_LANE_LANE_06_CFG_RX2TX_LP_EN_SET(params->cfg_rx2tx_lp_en) | - SD10G_LANE_LANE_06_CFG_TX2RX_LP_EN_SET(params->cfg_tx2rx_lp_en), - SD10G_LANE_LANE_06_CFG_RX2TX_LP_EN | - SD10G_LANE_LANE_06_CFG_TX2RX_LP_EN, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_06(sd_index)) - }, - { - SD10G_LANE_LANE_0E_CFG_RXLB_EN_SET(params->cfg_rxlb_en) | - SD10G_LANE_LANE_0E_CFG_TXLB_EN_SET(params->cfg_txlb_en), - SD10G_LANE_LANE_0E_CFG_RXLB_EN | - SD10G_LANE_LANE_0E_CFG_TXLB_EN, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_0E(sd_index)) - }, - { - SD_LANE_SD_LANE_CFG_MACRO_RST_SET(0), - SD_LANE_SD_LANE_CFG_MACRO_RST, - sdx5_addr(regs, SD_LANE_SD_LANE_CFG(lane_index)) - }, - { - SD10G_LANE_LANE_50_CFG_SSC_RESETB_SET(1), - SD10G_LANE_LANE_50_CFG_SSC_RESETB, - sdx5_inst_addr(sd_inst, SD10G_LANE_LANE_50(sd_index)) - }, - { - SD10G_LANE_LANE_50_CFG_SSC_RESETB_SET(1), - SD10G_LANE_LANE_50_CFG_SSC_RESETB, - sdx5_addr(regs, SD10G_LANE_LANE_50(sd_index)) - }, - { - SD_LANE_MISC_SD_125_RST_DIS_SET(params->fx_100), - SD_LANE_MISC_SD_125_RST_DIS, - sdx5_addr(regs, SD_LANE_MISC(lane_index)) - }, - { - SD_LANE_MISC_RX_ENA_SET(params->fx_100), - SD_LANE_MISC_RX_ENA, - sdx5_addr(regs, SD_LANE_MISC(lane_index)) - }, - { - SD_LANE_MISC_MUX_ENA_SET(params->fx_100), - SD_LANE_MISC_MUX_ENA, - sdx5_addr(regs, SD_LANE_MISC(lane_index)) - }, - }; + struct sparx5_serdes_private *priv = macro->priv; + void __iomem **regs = priv->regs; + struct device *dev = priv->dev; + u32 lane_index = macro->sidx; + u32 sd_index = macro->stpidx; + void __iomem *sd_inst; u32 value; - int idx; - for (idx = 0; idx < ARRAY_SIZE(item); ++idx) - sdx5_rmw_addr(item[idx].value, item[idx].mask, item[idx].addr); + if (params->is_6g) + sd_inst = sdx5_inst_get(priv, TARGET_SD6G_LANE, sd_index); + else + sd_inst = sdx5_inst_get(priv, TARGET_SD10G_LANE, sd_index); + + sdx5_rmw(SD_LANE_SD_LANE_CFG_MACRO_RST_SET(1), + SD_LANE_SD_LANE_CFG_MACRO_RST, + priv, + SD_LANE_SD_LANE_CFG(lane_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_93_R_DWIDTHCTRL_FROM_HWT_SET(0x0) | + SD10G_LANE_LANE_93_R_REG_MANUAL_SET(0x1) | + SD10G_LANE_LANE_93_R_AUXCKSEL_FROM_HWT_SET(0x1) | + SD10G_LANE_LANE_93_R_LANE_ID_FROM_HWT_SET(0x1) | + SD10G_LANE_LANE_93_R_EN_RATECHG_CTRL_SET(0x0), + SD10G_LANE_LANE_93_R_DWIDTHCTRL_FROM_HWT | + SD10G_LANE_LANE_93_R_REG_MANUAL | + SD10G_LANE_LANE_93_R_AUXCKSEL_FROM_HWT | + SD10G_LANE_LANE_93_R_LANE_ID_FROM_HWT | + SD10G_LANE_LANE_93_R_EN_RATECHG_CTRL, + sd_inst, + SD10G_LANE_LANE_93(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_94_R_ISCAN_REG_SET(0x1) | + SD10G_LANE_LANE_94_R_TXEQ_REG_SET(0x1) | + SD10G_LANE_LANE_94_R_MISC_REG_SET(0x1) | + SD10G_LANE_LANE_94_R_SWING_REG_SET(0x1), + SD10G_LANE_LANE_94_R_ISCAN_REG | + SD10G_LANE_LANE_94_R_TXEQ_REG | + SD10G_LANE_LANE_94_R_MISC_REG | + SD10G_LANE_LANE_94_R_SWING_REG, + sd_inst, + SD10G_LANE_LANE_94(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_9E_R_RXEQ_REG_SET(0x1), + SD10G_LANE_LANE_9E_R_RXEQ_REG, + sd_inst, + SD10G_LANE_LANE_9E(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_A1_R_SSC_FROM_HWT_SET(0x0) | + SD10G_LANE_LANE_A1_R_CDR_FROM_HWT_SET(0x0) | + SD10G_LANE_LANE_A1_R_PCLK_GATING_FROM_HWT_SET(0x1), + SD10G_LANE_LANE_A1_R_SSC_FROM_HWT | + SD10G_LANE_LANE_A1_R_CDR_FROM_HWT | + SD10G_LANE_LANE_A1_R_PCLK_GATING_FROM_HWT, + sd_inst, + SD10G_LANE_LANE_A1(sd_index)); + + sdx5_rmw(SD_LANE_SD_LANE_CFG_RX_REF_SEL_SET(params->cmu_sel) | + SD_LANE_SD_LANE_CFG_TX_REF_SEL_SET(params->cmu_sel), + SD_LANE_SD_LANE_CFG_RX_REF_SEL | + SD_LANE_SD_LANE_CFG_TX_REF_SEL, + priv, + SD_LANE_SD_LANE_CFG(lane_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0_SET + (params->cfg_lane_reserve_7_0), + SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0, + sd_inst, + SD10G_LANE_LANE_40(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_50_CFG_SSC_RTL_CLK_SEL_SET + (params->cfg_ssc_rtl_clk_sel), + SD10G_LANE_LANE_50_CFG_SSC_RTL_CLK_SEL, + sd_inst, + SD10G_LANE_LANE_50(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_35_CFG_TXRATE_1_0_SET + (params->cfg_txrate_1_0) | + SD10G_LANE_LANE_35_CFG_RXRATE_1_0_SET + (params->cfg_rxrate_1_0), + SD10G_LANE_LANE_35_CFG_TXRATE_1_0 | + SD10G_LANE_LANE_35_CFG_RXRATE_1_0, + sd_inst, + SD10G_LANE_LANE_35(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0_SET + (params->r_d_width_ctrl_2_0), + SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0, + sd_inst, + SD10G_LANE_LANE_94(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_01_CFG_PMA_TX_CK_BITWIDTH_2_0_SET + (params->cfg_pma_tx_ck_bitwidth_2_0), + SD10G_LANE_LANE_01_CFG_PMA_TX_CK_BITWIDTH_2_0, + sd_inst, + SD10G_LANE_LANE_01(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_30_CFG_RXDIV_SEL_2_0_SET + (params->cfg_rxdiv_sel_2_0), + SD10G_LANE_LANE_30_CFG_RXDIV_SEL_2_0, + sd_inst, + SD10G_LANE_LANE_30(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0_SET + (params->r_pcs2pma_phymode_4_0), + SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0, + sd_inst, + SD10G_LANE_LANE_A2(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_13_CFG_CDRCK_EN_SET(params->cfg_cdrck_en), + SD10G_LANE_LANE_13_CFG_CDRCK_EN, + sd_inst, + SD10G_LANE_LANE_13(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_23_CFG_DFECK_EN_SET + (params->cfg_dfeck_en) | + SD10G_LANE_LANE_23_CFG_DFE_PD_SET(params->cfg_dfe_pd) | + SD10G_LANE_LANE_23_CFG_ERRAMP_PD_SET + (params->cfg_erramp_pd), + SD10G_LANE_LANE_23_CFG_DFECK_EN | + SD10G_LANE_LANE_23_CFG_DFE_PD | + SD10G_LANE_LANE_23_CFG_ERRAMP_PD, + sd_inst, + SD10G_LANE_LANE_23(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1_SET + (params->cfg_dfetap_en_5_1), + SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1, + sd_inst, + SD10G_LANE_LANE_22(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_1A_CFG_PI_DFE_EN_SET + (params->cfg_pi_DFE_en), + SD10G_LANE_LANE_1A_CFG_PI_DFE_EN, + sd_inst, + SD10G_LANE_LANE_1A(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_02_CFG_EN_ADV_SET(params->cfg_en_adv) | + SD10G_LANE_LANE_02_CFG_EN_MAIN_SET(params->cfg_en_main) | + SD10G_LANE_LANE_02_CFG_EN_DLY_SET(params->cfg_en_dly) | + SD10G_LANE_LANE_02_CFG_TAP_ADV_3_0_SET + (params->cfg_tap_adv_3_0), + SD10G_LANE_LANE_02_CFG_EN_ADV | + SD10G_LANE_LANE_02_CFG_EN_MAIN | + SD10G_LANE_LANE_02_CFG_EN_DLY | + SD10G_LANE_LANE_02_CFG_TAP_ADV_3_0, + sd_inst, + SD10G_LANE_LANE_02(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_03_CFG_TAP_MAIN_SET(params->cfg_tap_main), + SD10G_LANE_LANE_03_CFG_TAP_MAIN, + sd_inst, + SD10G_LANE_LANE_03(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0_SET + (params->cfg_tap_dly_4_0), + SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0, + sd_inst, + SD10G_LANE_LANE_04(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_2F_CFG_VGA_CTRL_3_0_SET + (params->cfg_vga_ctrl_3_0), + SD10G_LANE_LANE_2F_CFG_VGA_CTRL_3_0, + sd_inst, + SD10G_LANE_LANE_2F(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_2F_CFG_VGA_CP_2_0_SET + (params->cfg_vga_cp_2_0), + SD10G_LANE_LANE_2F_CFG_VGA_CP_2_0, + sd_inst, + SD10G_LANE_LANE_2F(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_0B_CFG_EQ_RES_3_0_SET + (params->cfg_eq_res_3_0), + SD10G_LANE_LANE_0B_CFG_EQ_RES_3_0, + sd_inst, + SD10G_LANE_LANE_0B(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_0D_CFG_EQR_BYP_SET(params->cfg_eq_r_byp), + SD10G_LANE_LANE_0D_CFG_EQR_BYP, + sd_inst, + SD10G_LANE_LANE_0D(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_0E_CFG_EQC_FORCE_3_0_SET + (params->cfg_eq_c_force_3_0) | + SD10G_LANE_LANE_0E_CFG_SUM_SETCM_EN_SET + (params->cfg_sum_setcm_en), + SD10G_LANE_LANE_0E_CFG_EQC_FORCE_3_0 | + SD10G_LANE_LANE_0E_CFG_SUM_SETCM_EN, + sd_inst, + SD10G_LANE_LANE_0E(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_23_CFG_EN_DFEDIG_SET + (params->cfg_en_dfedig), + SD10G_LANE_LANE_23_CFG_EN_DFEDIG, + sd_inst, + SD10G_LANE_LANE_23(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_06_CFG_EN_PREEMPH_SET + (params->cfg_en_preemph), + SD10G_LANE_LANE_06_CFG_EN_PREEMPH, + sd_inst, + SD10G_LANE_LANE_06(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_33_CFG_ITX_IPPREEMP_BASE_1_0_SET + (params->cfg_itx_ippreemp_base_1_0) | + SD10G_LANE_LANE_33_CFG_ITX_IPDRIVER_BASE_2_0_SET + (params->cfg_itx_ipdriver_base_2_0), + SD10G_LANE_LANE_33_CFG_ITX_IPPREEMP_BASE_1_0 | + SD10G_LANE_LANE_33_CFG_ITX_IPDRIVER_BASE_2_0, + sd_inst, + SD10G_LANE_LANE_33(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0_SET + (params->cfg_ibias_tune_reserve_5_0), + SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0, + sd_inst, + SD10G_LANE_LANE_52(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_37_CFG_TXSWING_HALF_SET + (params->cfg_txswing_half), + SD10G_LANE_LANE_37_CFG_TXSWING_HALF, + sd_inst, + SD10G_LANE_LANE_37(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_3C_CFG_DIS_2NDORDER_SET + (params->cfg_dis_2nd_order), + SD10G_LANE_LANE_3C_CFG_DIS_2NDORDER, + sd_inst, + SD10G_LANE_LANE_3C(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_39_CFG_RX_SSC_LH_SET + (params->cfg_rx_ssc_lh), + SD10G_LANE_LANE_39_CFG_RX_SSC_LH, + sd_inst, + SD10G_LANE_LANE_39(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_1A_CFG_PI_FLOOP_STEPS_1_0_SET + (params->cfg_pi_floop_steps_1_0), + SD10G_LANE_LANE_1A_CFG_PI_FLOOP_STEPS_1_0, + sd_inst, + SD10G_LANE_LANE_1A(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16_SET + (params->cfg_pi_ext_dac_23_16), + SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16, + sd_inst, + SD10G_LANE_LANE_16(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8_SET + (params->cfg_pi_ext_dac_15_8), + SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8, + sd_inst, + SD10G_LANE_LANE_15(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0_SET + (params->cfg_iscan_ext_dac_7_0), + SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0, + sd_inst, + SD10G_LANE_LANE_26(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_42_CFG_CDR_KF_GEN1_2_0_SET + (params->cfg_cdr_kf_gen1_2_0), + SD10G_LANE_LANE_42_CFG_CDR_KF_GEN1_2_0, + sd_inst, + SD10G_LANE_LANE_42(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0_SET + (params->r_cdr_m_gen1_7_0), + SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0, + sd_inst, + SD10G_LANE_LANE_0F(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_24_CFG_PI_BW_GEN1_3_0_SET + (params->cfg_pi_bw_gen1_3_0), + SD10G_LANE_LANE_24_CFG_PI_BW_GEN1_3_0, + sd_inst, + SD10G_LANE_LANE_24(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0_SET + (params->cfg_pi_ext_dac_7_0), + SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0, + sd_inst, + SD10G_LANE_LANE_14(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_1A_CFG_PI_STEPS_SET(params->cfg_pi_steps), + SD10G_LANE_LANE_1A_CFG_PI_STEPS, + sd_inst, + SD10G_LANE_LANE_1A(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_3A_CFG_MP_MAX_3_0_SET + (params->cfg_mp_max_3_0), + SD10G_LANE_LANE_3A_CFG_MP_MAX_3_0, + sd_inst, + SD10G_LANE_LANE_3A(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_31_CFG_RSTN_DFEDIG_SET + (params->cfg_rstn_dfedig), + SD10G_LANE_LANE_31_CFG_RSTN_DFEDIG, + sd_inst, + SD10G_LANE_LANE_31(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_48_CFG_ALOS_THR_3_0_SET + (params->cfg_alos_thr_3_0), + SD10G_LANE_LANE_48_CFG_ALOS_THR_3_0, + sd_inst, + SD10G_LANE_LANE_48(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_36_CFG_PREDRV_SLEWRATE_1_0_SET + (params->cfg_predrv_slewrate_1_0), + SD10G_LANE_LANE_36_CFG_PREDRV_SLEWRATE_1_0, + sd_inst, + SD10G_LANE_LANE_36(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_32_CFG_ITX_IPCML_BASE_1_0_SET + (params->cfg_itx_ipcml_base_1_0), + SD10G_LANE_LANE_32_CFG_ITX_IPCML_BASE_1_0, + sd_inst, + SD10G_LANE_LANE_32(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_37_CFG_IP_PRE_BASE_1_0_SET + (params->cfg_ip_pre_base_1_0), + SD10G_LANE_LANE_37_CFG_IP_PRE_BASE_1_0, + sd_inst, + SD10G_LANE_LANE_37(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8_SET + (params->cfg_lane_reserve_15_8), + SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8, + sd_inst, + SD10G_LANE_LANE_41(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_9E_R_EN_AUTO_CDR_RSTN_SET + (params->r_en_auto_cdr_rstn), + SD10G_LANE_LANE_9E_R_EN_AUTO_CDR_RSTN, + sd_inst, + SD10G_LANE_LANE_9E(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_0C_CFG_OSCAL_AFE_SET + (params->cfg_oscal_afe) | + SD10G_LANE_LANE_0C_CFG_PD_OSDAC_AFE_SET + (params->cfg_pd_osdac_afe), + SD10G_LANE_LANE_0C_CFG_OSCAL_AFE | + SD10G_LANE_LANE_0C_CFG_PD_OSDAC_AFE, + sd_inst, + SD10G_LANE_LANE_0C(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE_SET + (params->cfg_resetb_oscal_afe[0]), + SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE, + sd_inst, + SD10G_LANE_LANE_0B(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE_SET + (params->cfg_resetb_oscal_afe[1]), + SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_AFE, + sd_inst, + SD10G_LANE_LANE_0B(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_83_R_TX_POL_INV_SET + (params->r_tx_pol_inv) | + SD10G_LANE_LANE_83_R_RX_POL_INV_SET + (params->r_rx_pol_inv), + SD10G_LANE_LANE_83_R_TX_POL_INV | + SD10G_LANE_LANE_83_R_RX_POL_INV, + sd_inst, + SD10G_LANE_LANE_83(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_06_CFG_RX2TX_LP_EN_SET + (params->cfg_rx2tx_lp_en) | + SD10G_LANE_LANE_06_CFG_TX2RX_LP_EN_SET + (params->cfg_tx2rx_lp_en), + SD10G_LANE_LANE_06_CFG_RX2TX_LP_EN | + SD10G_LANE_LANE_06_CFG_TX2RX_LP_EN, + sd_inst, + SD10G_LANE_LANE_06(sd_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_0E_CFG_RXLB_EN_SET(params->cfg_rxlb_en) | + SD10G_LANE_LANE_0E_CFG_TXLB_EN_SET(params->cfg_txlb_en), + SD10G_LANE_LANE_0E_CFG_RXLB_EN | + SD10G_LANE_LANE_0E_CFG_TXLB_EN, + sd_inst, + SD10G_LANE_LANE_0E(sd_index)); + + sdx5_rmw(SD_LANE_SD_LANE_CFG_MACRO_RST_SET(0), + SD_LANE_SD_LANE_CFG_MACRO_RST, + priv, + SD_LANE_SD_LANE_CFG(lane_index)); + + sdx5_inst_rmw(SD10G_LANE_LANE_50_CFG_SSC_RESETB_SET(1), + SD10G_LANE_LANE_50_CFG_SSC_RESETB, + sd_inst, + SD10G_LANE_LANE_50(sd_index)); + + sdx5_rmw(SD10G_LANE_LANE_50_CFG_SSC_RESETB_SET(1), + SD10G_LANE_LANE_50_CFG_SSC_RESETB, + priv, + SD10G_LANE_LANE_50(sd_index)); + + sdx5_rmw(SD_LANE_MISC_SD_125_RST_DIS_SET(params->fx_100), + SD_LANE_MISC_SD_125_RST_DIS, + priv, + SD_LANE_MISC(lane_index)); + + sdx5_rmw(SD_LANE_MISC_RX_ENA_SET(params->fx_100), + SD_LANE_MISC_RX_ENA, + priv, + SD_LANE_MISC(lane_index)); + + sdx5_rmw(SD_LANE_MISC_MUX_ENA_SET(params->fx_100), + SD_LANE_MISC_MUX_ENA, + priv, + SD_LANE_MISC(lane_index)); + usleep_range(3000, 6000); value = readl(sdx5_addr(regs, SD_LANE_SD_LANE_STAT(lane_index))); @@ -1793,21 +1838,23 @@ static int sparx5_sd10g28_apply_params(struct device *dev, return -EINVAL; } - sdx5_rmw_addr(SD_LANE_SD_SER_RST_SER_RST_SET(0x0), + sdx5_rmw(SD_LANE_SD_SER_RST_SER_RST_SET(0x0), SD_LANE_SD_SER_RST_SER_RST, - sdx5_addr(regs, SD_LANE_SD_SER_RST(lane_index))); + priv, + SD_LANE_SD_SER_RST(lane_index)); - sdx5_rmw_addr(SD_LANE_SD_DES_RST_DES_RST_SET(0x0), + sdx5_rmw(SD_LANE_SD_DES_RST_DES_RST_SET(0x0), SD_LANE_SD_DES_RST_DES_RST, - sdx5_addr(regs, SD_LANE_SD_DES_RST(lane_index))); + priv, + SD_LANE_SD_DES_RST(lane_index)); return 0; } static int sparx5_sd25g28_config(struct sparx5_serdes_macro *macro, bool reset) { - struct sparx5_sd25g28_mode_preset mode; struct sparx5_sd25g28_media_preset media = media_presets_25g[macro->media]; + struct sparx5_sd25g28_mode_preset mode; struct sparx5_sd25g28_args args = { .rxinvert = 1, .txinvert = 0, @@ -1823,16 +1870,14 @@ static int sparx5_sd25g28_config(struct sparx5_serdes_macro *macro, bool reset) return err; sparx5_sd25g28_get_params(macro, &media, &mode, &args, ¶ms); sparx5_sd25g28_reset(macro->priv->regs, ¶ms, macro->stpidx); - return sparx5_sd25g28_apply_params(macro->priv->dev, - macro->priv->regs, - ¶ms, - macro->stpidx); + return sparx5_sd25g28_apply_params(macro, ¶ms); } static int sparx5_sd10g28_config(struct sparx5_serdes_macro *macro, bool reset) { - struct sparx5_sd10g28_mode_preset mode; struct sparx5_sd10g28_media_preset media = media_presets_10g[macro->media]; + struct sparx5_sd10g28_mode_preset mode; + struct sparx5_sd10g28_params params; struct sparx5_sd10g28_args args = { .is_6g = (macro->serdestype == SPX5_SDT_6G), .txinvert = 0, @@ -1840,36 +1885,21 @@ static int sparx5_sd10g28_config(struct sparx5_serdes_macro *macro, bool reset) .txswing = 240, .reg_rst = reset, }; - struct sparx5_sd10g28_params params; - u32 sd_index = macro->stpidx; - void __iomem *sd_inst; int err; err = sparx5_sd10g28_get_mode_preset(macro, &mode, &args); if (err) return err; sparx5_sd10g28_get_params(macro, &media, &mode, &args, ¶ms); - sparx5_sd10g28_reset(macro->priv->regs, - ¶ms, - macro->sidx, - macro->stpidx); - if (macro->serdestype == SPX5_SDT_6G) - sd_inst = macro->priv->regs[TARGET_SD6G_LANE + sd_index]; - else - sd_inst = macro->priv->regs[TARGET_SD10G_LANE + sd_index]; - return sparx5_sd10g28_apply_params(macro->priv->dev, - macro->priv->regs, - ¶ms, - sd_inst, - macro->sidx, - sd_index); + sparx5_sd10g28_reset(macro->priv->regs, macro->sidx); + return sparx5_sd10g28_apply_params(macro, ¶ms); } /* Power down serdes TX driver */ static int sparx5_serdes_power_save(struct sparx5_serdes_macro *macro, u32 pwdn) { - void __iomem *sd_inst; struct sparx5_serdes_private *priv = macro->priv; + void __iomem *sd_inst; if (macro->serdestype == SPX5_SDT_6G) sd_inst = sdx5_inst_get(priv, TARGET_SD6G_LANE, macro->stpidx); @@ -1909,93 +1939,97 @@ static int sparx5_serdes_clock_config(struct sparx5_serdes_macro *macro) return 0; } -static int sparx5_cmu_apply_cfg(struct device *dev, - void __iomem *regs[], - u32 cmu_idx, - void __iomem *cmu_tgt, - void __iomem *cmu_cfg_tgt, - u32 spd10g) +static int sparx5_cmu_apply_cfg(struct sparx5_serdes_private *priv, + u32 cmu_idx, + void __iomem *cmu_tgt, + void __iomem *cmu_cfg_tgt, + u32 spd10g) { - struct sparx5_serdes_regval item[] = { - { - SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST_SET(1), - SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST, - sdx5_inst_addr(cmu_cfg_tgt, SD_CMU_CFG_SD_CMU_CFG(cmu_idx)) - }, - { - SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST_SET(0), - SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST, - sdx5_inst_addr(cmu_cfg_tgt, SD_CMU_CFG_SD_CMU_CFG(cmu_idx)) - }, - { - SD_CMU_CFG_SD_CMU_CFG_CMU_RST_SET(1), - SD_CMU_CFG_SD_CMU_CFG_CMU_RST, - sdx5_inst_addr(cmu_cfg_tgt, SD_CMU_CFG_SD_CMU_CFG(cmu_idx)) - }, - { - SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT_SET(0x1) | - SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT_SET(0x1) | - SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT_SET(0x1) | - SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT_SET(0x1) | - SD_CMU_CMU_45_R_EN_RATECHG_CTRL_SET(0x0), - SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT | - SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT | - SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT | - SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT | - SD_CMU_CMU_45_R_EN_RATECHG_CTRL, - sdx5_inst_addr(cmu_tgt, SD_CMU_CMU_45(cmu_idx)) - }, - { - SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0_SET(0), - SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0, - sdx5_inst_addr(cmu_tgt, SD_CMU_CMU_47(cmu_idx)) - }, - { - SD_CMU_CMU_1B_CFG_RESERVE_7_0_SET(0), - SD_CMU_CMU_1B_CFG_RESERVE_7_0, - sdx5_inst_addr(cmu_tgt, SD_CMU_CMU_1B(cmu_idx)) - }, - { - SD_CMU_CMU_0D_CFG_JC_BYP_SET(0x1), - SD_CMU_CMU_0D_CFG_JC_BYP, - sdx5_inst_addr(cmu_tgt, SD_CMU_CMU_0D(cmu_idx)) - }, - { - SD_CMU_CMU_1F_CFG_VTUNE_SEL_SET(1), - SD_CMU_CMU_1F_CFG_VTUNE_SEL, - sdx5_inst_addr(cmu_tgt, SD_CMU_CMU_1F(cmu_idx)) - }, - { - SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0_SET(3), - SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0, - sdx5_inst_addr(cmu_tgt, SD_CMU_CMU_00(cmu_idx)) - }, - { - SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0_SET(3), - SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0, - sdx5_inst_addr(cmu_tgt, SD_CMU_CMU_05(cmu_idx)) - }, - { - SD_CMU_CMU_30_R_PLL_DLOL_EN_SET(1), - SD_CMU_CMU_30_R_PLL_DLOL_EN, - sdx5_inst_addr(cmu_tgt, SD_CMU_CMU_30(cmu_idx)) - }, - { - SD_CMU_CMU_09_CFG_SW_10G_SET(spd10g), - SD_CMU_CMU_09_CFG_SW_10G, - sdx5_inst_addr(cmu_tgt, SD_CMU_CMU_09(cmu_idx)) - }, - { - SD_CMU_CFG_SD_CMU_CFG_CMU_RST_SET(0), - SD_CMU_CFG_SD_CMU_CFG_CMU_RST, - sdx5_inst_addr(cmu_cfg_tgt, SD_CMU_CFG_SD_CMU_CFG(cmu_idx)) - }, - }; + void __iomem **regs = priv->regs; + struct device *dev = priv->dev; int value; - int idx; - for (idx = 0; idx < ARRAY_SIZE(item); ++idx) - sdx5_rmw_addr(item[idx].value, item[idx].mask, item[idx].addr); + cmu_tgt = sdx5_inst_get(priv, TARGET_SD_CMU, cmu_idx); + cmu_cfg_tgt = sdx5_inst_get(priv, TARGET_SD_CMU_CFG, cmu_idx); + + if (cmu_idx == 1 || cmu_idx == 4 || cmu_idx == 7 || + cmu_idx == 10 || cmu_idx == 13) { + spd10g = 0; + } + + sdx5_inst_rmw(SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST_SET(1), + SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST, + cmu_cfg_tgt, + SD_CMU_CFG_SD_CMU_CFG(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST_SET(0), + SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST, + cmu_cfg_tgt, + SD_CMU_CFG_SD_CMU_CFG(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CFG_SD_CMU_CFG_CMU_RST_SET(1), + SD_CMU_CFG_SD_CMU_CFG_CMU_RST, + cmu_cfg_tgt, + SD_CMU_CFG_SD_CMU_CFG(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT_SET(0x1) | + SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT_SET(0x1) | + SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT_SET(0x1) | + SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT_SET(0x1) | + SD_CMU_CMU_45_R_EN_RATECHG_CTRL_SET(0x0), + SD_CMU_CMU_45_R_DWIDTHCTRL_FROM_HWT | + SD_CMU_CMU_45_R_REFCK_SSC_EN_FROM_HWT | + SD_CMU_CMU_45_R_LINK_BUF_EN_FROM_HWT | + SD_CMU_CMU_45_R_BIAS_EN_FROM_HWT | + SD_CMU_CMU_45_R_EN_RATECHG_CTRL, + cmu_tgt, + SD_CMU_CMU_45(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0_SET(0), + SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0, + cmu_tgt, + SD_CMU_CMU_47(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CMU_1B_CFG_RESERVE_7_0_SET(0), + SD_CMU_CMU_1B_CFG_RESERVE_7_0, + cmu_tgt, + SD_CMU_CMU_1B(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CMU_0D_CFG_JC_BYP_SET(0x1), + SD_CMU_CMU_0D_CFG_JC_BYP, + cmu_tgt, + SD_CMU_CMU_0D(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CMU_1F_CFG_VTUNE_SEL_SET(1), + SD_CMU_CMU_1F_CFG_VTUNE_SEL, + cmu_tgt, + SD_CMU_CMU_1F(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0_SET(3), + SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0, + cmu_tgt, + SD_CMU_CMU_00(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0_SET(3), + SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0, + cmu_tgt, + SD_CMU_CMU_05(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CMU_30_R_PLL_DLOL_EN_SET(1), + SD_CMU_CMU_30_R_PLL_DLOL_EN, + cmu_tgt, + SD_CMU_CMU_30(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CMU_09_CFG_SW_10G_SET(spd10g), + SD_CMU_CMU_09_CFG_SW_10G, + cmu_tgt, + SD_CMU_CMU_09(cmu_idx)); + + sdx5_inst_rmw(SD_CMU_CFG_SD_CMU_CFG_CMU_RST_SET(0), + SD_CMU_CFG_SD_CMU_CFG_CMU_RST, + cmu_cfg_tgt, + SD_CMU_CFG_SD_CMU_CFG(cmu_idx)); + msleep(20); sdx5_inst_rmw(SD_CMU_CMU_44_R_PLL_RSTN_SET(0), @@ -2037,8 +2071,7 @@ static int sparx5_cmu_cfg(struct sparx5_serdes_private *priv, u32 cmu_idx) cmu_tgt = sdx5_inst_get(priv, TARGET_SD_CMU, cmu_idx); cmu_cfg_tgt = sdx5_inst_get(priv, TARGET_SD_CMU_CFG, cmu_idx); - return sparx5_cmu_apply_cfg(priv->dev, priv->regs, cmu_idx, cmu_tgt, - cmu_cfg_tgt, spd10g); + return sparx5_cmu_apply_cfg(priv, cmu_idx, cmu_tgt, cmu_cfg_tgt, spd10g); } static int sparx5_serdes_cmu_enable(struct sparx5_serdes_private *priv) -- cgit v1.2.3 From cbc336c09b6d6dfb24d20c955599123308fa2fe2 Mon Sep 17 00:00:00 2001 From: kernel test robot Date: Fri, 19 Mar 2021 07:28:44 +0800 Subject: phy: fix resource_size.cocci warnings drivers/phy/microchip/sparx5_serdes.c:2440:54-57: ERROR: Missing resource_size with iores Use resource_size function on resource object instead of explicit computation. Generated by: scripts/coccinelle/api/resource_size.cocci Fixes: 2ff8a1eeb5aa ("phy: Add Sparx5 ethernet serdes PHY driver") CC: Steen Hegelund Reported-by: kernel test robot Signed-off-by: kernel test robot Link: https://lore.kernel.org/r/20210318232844.GA65886@63b0c5462fda Signed-off-by: Vinod Koul --- drivers/phy/microchip/sparx5_serdes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/microchip/sparx5_serdes.c b/drivers/phy/microchip/sparx5_serdes.c index 338a4220b45f..c8a7d0927ced 100644 --- a/drivers/phy/microchip/sparx5_serdes.c +++ b/drivers/phy/microchip/sparx5_serdes.c @@ -2470,7 +2470,7 @@ static int sparx5_serdes_probe(struct platform_device *pdev) priv->coreclock = clock; iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - iomem = devm_ioremap(priv->dev, iores->start, iores->end - iores->start + 1); + iomem = devm_ioremap(priv->dev, iores->start, resource_size(iores)); if (IS_ERR(iomem)) { dev_err(priv->dev, "Unable to get serdes registers: %s\n", iores->name); -- cgit v1.2.3 From 4547a749be997eb12ea7edcf361ec2a5329f7aec Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Tue, 6 Apr 2021 11:11:54 +0200 Subject: bus: mhi: core: Fix MHI runtime_pm behavior This change ensures that PM reference is always get during packet queueing and released either after queuing completion (RX) or once the buffer has been consumed (TX). This guarantees proper update for underlying MHI controller runtime status (e.g. last_busy timestamp) and prevents suspend to be triggered while TX packets are flying, or before we completed update of the RX ring. Signed-off-by: Loic Poulain Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1617700315-12492-1-git-send-email-loic.poulain@linaro.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/main.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index 58b8111ce66c..7eed2741fcf9 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -617,8 +617,11 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl, /* notify client */ mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result); - if (mhi_chan->dir == DMA_TO_DEVICE) + if (mhi_chan->dir == DMA_TO_DEVICE) { atomic_dec(&mhi_cntrl->pending_pkts); + /* Release the reference got from mhi_queue() */ + mhi_cntrl->runtime_put(mhi_cntrl); + } /* * Recycle the buffer if buffer is pre-allocated, @@ -1054,9 +1057,11 @@ static int mhi_queue(struct mhi_device *mhi_dev, struct mhi_buf_info *buf_info, if (unlikely(ret)) goto exit_unlock; - /* trigger M3 exit if necessary */ - if (MHI_PM_IN_SUSPEND_STATE(mhi_cntrl->pm_state)) - mhi_trigger_resume(mhi_cntrl); + /* Packet is queued, take a usage ref to exit M3 if necessary + * for host->device buffer, balanced put is done on buffer completion + * for device->host buffer, balanced put is after ringing the DB + */ + mhi_cntrl->runtime_get(mhi_cntrl); /* Assert dev_wake (to exit/prevent M1/M2)*/ mhi_cntrl->wake_toggle(mhi_cntrl); @@ -1067,6 +1072,9 @@ static int mhi_queue(struct mhi_device *mhi_dev, struct mhi_buf_info *buf_info, if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl))) mhi_ring_chan_db(mhi_cntrl, mhi_chan); + if (dir == DMA_FROM_DEVICE) + mhi_cntrl->runtime_put(mhi_cntrl); + exit_unlock: read_unlock_irqrestore(&mhi_cntrl->pm_lock, flags); @@ -1449,8 +1457,11 @@ static void mhi_reset_data_chan(struct mhi_controller *mhi_cntrl, while (tre_ring->rp != tre_ring->wp) { struct mhi_buf_info *buf_info = buf_ring->rp; - if (mhi_chan->dir == DMA_TO_DEVICE) + if (mhi_chan->dir == DMA_TO_DEVICE) { atomic_dec(&mhi_cntrl->pending_pkts); + /* Release the reference got from mhi_queue() */ + mhi_cntrl->runtime_put(mhi_cntrl); + } if (!buf_info->pre_mapped) mhi_cntrl->unmap_single(mhi_cntrl, buf_info); -- cgit v1.2.3 From 8f910c8c2a977476d96f3deab8080cd7b6a1cb11 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Tue, 6 Apr 2021 11:11:55 +0200 Subject: bus: mhi: pm: reduce PM state change verbosity Since M3 can be entered/exited quite a lot when used for runtime PM, keep the mhi suspend/resume transitions quiet. Signed-off-by: Loic Poulain Reviewed-by: Bhaumik Bhatt Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1617700315-12492-2-git-send-email-loic.poulain@linaro.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/pm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c index e4aff777d74b..dafcd9847cc6 100644 --- a/drivers/bus/mhi/core/pm.c +++ b/drivers/bus/mhi/core/pm.c @@ -848,7 +848,7 @@ int mhi_pm_suspend(struct mhi_controller *mhi_cntrl) return -EBUSY; } - dev_info(dev, "Allowing M3 transition\n"); + dev_dbg(dev, "Allowing M3 transition\n"); new_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_M3_ENTER); if (new_state != MHI_PM_M3_ENTER) { write_unlock_irq(&mhi_cntrl->pm_lock); @@ -862,7 +862,7 @@ int mhi_pm_suspend(struct mhi_controller *mhi_cntrl) /* Set MHI to M3 and wait for completion */ mhi_set_mhi_state(mhi_cntrl, MHI_STATE_M3); write_unlock_irq(&mhi_cntrl->pm_lock); - dev_info(dev, "Wait for M3 completion\n"); + dev_dbg(dev, "Waiting for M3 completion\n"); ret = wait_event_timeout(mhi_cntrl->state_event, mhi_cntrl->dev_state == MHI_STATE_M3 || @@ -896,9 +896,9 @@ int mhi_pm_resume(struct mhi_controller *mhi_cntrl) enum mhi_pm_state cur_state; int ret; - dev_info(dev, "Entered with PM state: %s, MHI state: %s\n", - to_mhi_pm_state_str(mhi_cntrl->pm_state), - TO_MHI_STATE_STR(mhi_cntrl->dev_state)); + dev_dbg(dev, "Entered with PM state: %s, MHI state: %s\n", + to_mhi_pm_state_str(mhi_cntrl->pm_state), + TO_MHI_STATE_STR(mhi_cntrl->dev_state)); if (mhi_cntrl->pm_state == MHI_PM_DISABLE) return 0; -- cgit v1.2.3 From eee87072e2fb9000b12c5e752ebd4a05882da2e4 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Thu, 1 Apr 2021 14:41:49 -0700 Subject: bus: mhi: core: Remove pre_init flag used for power purposes Some controllers can choose to skip preparation for power up. In that case, device context is initialized based on the pre_init flag not being set during mhi_prepare_for_power_up(). There is no reason MHI host driver should maintain and provide controllers with two separate paths for preparing MHI. Going forward, all controllers will be required to call the mhi_prepare_for_power_up() API followed by their choice of sync or async power up. This allows MHI host driver to get rid of the pre_init flag and sets up a common way for all controllers to use MHI. This also helps controllers fail early on during preparation phase in some failure cases. Signed-off-by: Bhaumik Bhatt Reviewed-by: Hemant Kumar Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1617313309-24035-1-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/init.c | 3 --- drivers/bus/mhi/core/pm.c | 20 -------------------- include/linux/mhi.h | 2 -- 3 files changed, 25 deletions(-) diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c index d1d9b0d9158e..1f6135213251 100644 --- a/drivers/bus/mhi/core/init.c +++ b/drivers/bus/mhi/core/init.c @@ -1080,8 +1080,6 @@ int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl) mhi_rddm_prepare(mhi_cntrl, mhi_cntrl->rddm_image); } - mhi_cntrl->pre_init = true; - mutex_unlock(&mhi_cntrl->pm_mutex); return 0; @@ -1112,7 +1110,6 @@ void mhi_unprepare_after_power_down(struct mhi_controller *mhi_cntrl) } mhi_deinit_dev_ctxt(mhi_cntrl); - mhi_cntrl->pre_init = false; } EXPORT_SYMBOL_GPL(mhi_unprepare_after_power_down); diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c index dafcd9847cc6..e2e59a341fef 100644 --- a/drivers/bus/mhi/core/pm.c +++ b/drivers/bus/mhi/core/pm.c @@ -1062,13 +1062,6 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl) mutex_lock(&mhi_cntrl->pm_mutex); mhi_cntrl->pm_state = MHI_PM_DISABLE; - if (!mhi_cntrl->pre_init) { - /* Setup device context */ - ret = mhi_init_dev_ctxt(mhi_cntrl); - if (ret) - goto error_dev_ctxt; - } - ret = mhi_init_irq_setup(mhi_cntrl); if (ret) goto error_setup_irq; @@ -1150,10 +1143,6 @@ error_bhi_offset: mhi_deinit_free_irq(mhi_cntrl); error_setup_irq: - if (!mhi_cntrl->pre_init) - mhi_deinit_dev_ctxt(mhi_cntrl); - -error_dev_ctxt: mhi_cntrl->pm_state = MHI_PM_DISABLE; mutex_unlock(&mhi_cntrl->pm_mutex); @@ -1203,15 +1192,6 @@ void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful) flush_work(&mhi_cntrl->st_worker); free_irq(mhi_cntrl->irq[0], mhi_cntrl); - - if (!mhi_cntrl->pre_init) { - /* Free all allocated resources */ - if (mhi_cntrl->fbc_image) { - mhi_free_bhie_table(mhi_cntrl, mhi_cntrl->fbc_image); - mhi_cntrl->fbc_image = NULL; - } - mhi_deinit_dev_ctxt(mhi_cntrl); - } } EXPORT_SYMBOL_GPL(mhi_power_down); diff --git a/include/linux/mhi.h b/include/linux/mhi.h index b16afd36b444..c9b36a34cc7f 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -354,7 +354,6 @@ struct mhi_controller_config { * @index: Index of the MHI controller instance * @bounce_buf: Use of bounce buffer * @fbc_download: MHI host needs to do complete image transfer (optional) - * @pre_init: MHI host needs to do pre-initialization before power up * @wake_set: Device wakeup set flag * @irq_flags: irq flags passed to request_irq (optional) * @@ -447,7 +446,6 @@ struct mhi_controller { int index; bool bounce_buf; bool fbc_download; - bool pre_init; bool wake_set; unsigned long irq_flags; }; -- cgit v1.2.3 From 49d38ebb6faad9e2abc7ce91b35956f19652b51f Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Fri, 2 Apr 2021 14:33:19 -0700 Subject: bus: mhi: pci_generic: Add SDX65 based modem support Add generic info for SDX65 based modems. Signed-off-by: Bhaumik Bhatt Reviewed-by: Manivannan Sadhasivam Reviewed-by: Loic Poulain Link: https://lore.kernel.org/r/1617399199-35172-1-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/pci_generic.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/bus/mhi/pci_generic.c b/drivers/bus/mhi/pci_generic.c index 5cf44bcfe040..544853c67e02 100644 --- a/drivers/bus/mhi/pci_generic.c +++ b/drivers/bus/mhi/pci_generic.c @@ -204,6 +204,15 @@ static struct mhi_controller_config modem_qcom_v1_mhiv_config = { .event_cfg = modem_qcom_v1_mhi_events, }; +static const struct mhi_pci_dev_info mhi_qcom_sdx65_info = { + .name = "qcom-sdx65m", + .fw = "qcom/sdx65m/xbl.elf", + .edl = "qcom/sdx65m/edl.mbn", + .config = &modem_qcom_v1_mhiv_config, + .bar_num = MHI_PCI_DEFAULT_BAR_NUM, + .dma_data_width = 32 +}; + static const struct mhi_pci_dev_info mhi_qcom_sdx55_info = { .name = "qcom-sdx55m", .fw = "qcom/sdx55m/sbl1.mbn", @@ -269,6 +278,8 @@ static const struct pci_device_id mhi_pci_id_table[] = { .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, { PCI_DEVICE(0x1eac, 0x1002), /* EM160R-GL (sdx24) */ .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0308), + .driver_data = (kernel_ulong_t) &mhi_qcom_sdx65_info }, { } }; MODULE_DEVICE_TABLE(pci, mhi_pci_id_table); -- cgit v1.2.3 From 5a62e39b45b585726e0dcbf383bfc70dc9f07637 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Thu, 1 Apr 2021 14:16:10 -0700 Subject: bus: mhi: core: Allow sending the STOP channel command Add support to allow sending the STOP channel command. If a client driver would like to STOP a channel and have the device retain the channel context instead of issuing a RESET to it and clearing the context, this would provide support for it after the ability to send this command is exposed to clients. Signed-off-by: Bhaumik Bhatt Reviewed-by: Hemant Kumar Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1617311778-1254-2-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index 7eed2741fcf9..4a7d3c7ec554 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -1216,6 +1216,11 @@ int mhi_send_cmd(struct mhi_controller *mhi_cntrl, cmd_tre->dword[0] = MHI_TRE_CMD_RESET_DWORD0; cmd_tre->dword[1] = MHI_TRE_CMD_RESET_DWORD1(chan); break; + case MHI_CMD_STOP_CHAN: + cmd_tre->ptr = MHI_TRE_CMD_STOP_PTR; + cmd_tre->dword[0] = MHI_TRE_CMD_STOP_DWORD0; + cmd_tre->dword[1] = MHI_TRE_CMD_STOP_DWORD1(chan); + break; case MHI_CMD_START_CHAN: cmd_tre->ptr = MHI_TRE_CMD_START_PTR; cmd_tre->dword[0] = MHI_TRE_CMD_START_DWORD0; -- cgit v1.2.3 From 4e44ae3d6d9c2c2a6d9356dd279c925532d5cd8c Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Thu, 1 Apr 2021 14:16:11 -0700 Subject: bus: mhi: core: Clear context for stopped channels from remove() If a channel was explicitly stopped but not reset and a driver remove is issued, clean up the channel context such that it is reflected on the device. This move is useful if a client driver module is unloaded or a device crash occurs with the host having placed the channel in a stopped state. Signed-off-by: Bhaumik Bhatt Reviewed-by: Hemant Kumar Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1617311778-1254-3-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c index 1f6135213251..a507895f6209 100644 --- a/drivers/bus/mhi/core/init.c +++ b/drivers/bus/mhi/core/init.c @@ -1290,7 +1290,8 @@ static int mhi_driver_remove(struct device *dev) mutex_lock(&mhi_chan->mutex); - if (ch_state[dir] == MHI_CH_STATE_ENABLED && + if ((ch_state[dir] == MHI_CH_STATE_ENABLED || + ch_state[dir] == MHI_CH_STATE_STOP) && !mhi_chan->offload_ch) mhi_deinit_chan_ctxt(mhi_cntrl, mhi_chan); -- cgit v1.2.3 From 3317dc6cea294566e56bddb1b6f2309e6facbfa3 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Thu, 1 Apr 2021 14:16:12 -0700 Subject: bus: mhi: core: Improvements to the channel handling state machine Improve the channel handling state machine such that all commands go through a common function and a validation process to ensure that the state machine is not violated in any way and adheres to the MHI specification. Using this common function allows MHI to eliminate some unnecessary debug messages and code duplication. Signed-off-by: Bhaumik Bhatt Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1617311778-1254-4-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/init.c | 6 ++ drivers/bus/mhi/core/internal.h | 12 ++++ drivers/bus/mhi/core/main.c | 151 ++++++++++++++++++++++------------------ 3 files changed, 100 insertions(+), 69 deletions(-) diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c index a507895f6209..0e54384e9fc5 100644 --- a/drivers/bus/mhi/core/init.c +++ b/drivers/bus/mhi/core/init.c @@ -56,6 +56,12 @@ const char * const mhi_state_str[MHI_STATE_MAX] = { [MHI_STATE_SYS_ERR] = "SYS ERROR", }; +const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX] = { + [MHI_CH_STATE_TYPE_RESET] = "RESET", + [MHI_CH_STATE_TYPE_STOP] = "STOP", + [MHI_CH_STATE_TYPE_START] = "START", +}; + static const char * const mhi_pm_state_str[] = { [MHI_PM_STATE_DISABLE] = "DISABLE", [MHI_PM_STATE_POR] = "POWER ON RESET", diff --git a/drivers/bus/mhi/core/internal.h b/drivers/bus/mhi/core/internal.h index e690f154212f..5b9ea66b92dc 100644 --- a/drivers/bus/mhi/core/internal.h +++ b/drivers/bus/mhi/core/internal.h @@ -369,6 +369,18 @@ enum mhi_ch_state { MHI_CH_STATE_ERROR = 0x5, }; +enum mhi_ch_state_type { + MHI_CH_STATE_TYPE_RESET, + MHI_CH_STATE_TYPE_STOP, + MHI_CH_STATE_TYPE_START, + MHI_CH_STATE_TYPE_MAX, +}; + +extern const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX]; +#define TO_CH_STATE_TYPE_STR(state) (((state) >= MHI_CH_STATE_TYPE_MAX) ? \ + "INVALID_STATE" : \ + mhi_ch_state_type_str[(state)]) + #define MHI_INVALID_BRSTMODE(mode) (mode != MHI_DB_BRST_DISABLE && \ mode != MHI_DB_BRST_ENABLE) diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index 4a7d3c7ec554..16bf8ec4e289 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -1242,56 +1242,105 @@ int mhi_send_cmd(struct mhi_controller *mhi_cntrl, return 0; } -static void __mhi_unprepare_channel(struct mhi_controller *mhi_cntrl, - struct mhi_chan *mhi_chan) +static int mhi_update_channel_state(struct mhi_controller *mhi_cntrl, + struct mhi_chan *mhi_chan, + enum mhi_ch_state_type to_state) { - int ret; struct device *dev = &mhi_cntrl->mhi_dev->dev; + enum mhi_cmd_type cmd = MHI_CMD_NOP; + int ret; - dev_dbg(dev, "Entered: unprepare channel:%d\n", mhi_chan->chan); - - /* no more processing events for this channel */ - mutex_lock(&mhi_chan->mutex); - write_lock_irq(&mhi_chan->lock); - if (mhi_chan->ch_state != MHI_CH_STATE_ENABLED && - mhi_chan->ch_state != MHI_CH_STATE_SUSPENDED) { + dev_dbg(dev, "%d: Updating channel state to: %s\n", mhi_chan->chan, + TO_CH_STATE_TYPE_STR(to_state)); + + switch (to_state) { + case MHI_CH_STATE_TYPE_RESET: + write_lock_irq(&mhi_chan->lock); + if (mhi_chan->ch_state != MHI_CH_STATE_STOP && + mhi_chan->ch_state != MHI_CH_STATE_ENABLED && + mhi_chan->ch_state != MHI_CH_STATE_SUSPENDED) { + write_unlock_irq(&mhi_chan->lock); + return -EINVAL; + } + mhi_chan->ch_state = MHI_CH_STATE_DISABLED; write_unlock_irq(&mhi_chan->lock); - mutex_unlock(&mhi_chan->mutex); - return; - } - mhi_chan->ch_state = MHI_CH_STATE_DISABLED; - write_unlock_irq(&mhi_chan->lock); + cmd = MHI_CMD_RESET_CHAN; + break; + case MHI_CH_STATE_TYPE_STOP: + if (mhi_chan->ch_state != MHI_CH_STATE_ENABLED) + return -EINVAL; - reinit_completion(&mhi_chan->completion); - read_lock_bh(&mhi_cntrl->pm_lock); - if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { - read_unlock_bh(&mhi_cntrl->pm_lock); - goto error_invalid_state; + cmd = MHI_CMD_STOP_CHAN; + break; + case MHI_CH_STATE_TYPE_START: + if (mhi_chan->ch_state != MHI_CH_STATE_STOP && + mhi_chan->ch_state != MHI_CH_STATE_DISABLED) + return -EINVAL; + + cmd = MHI_CMD_START_CHAN; + break; + default: + dev_err(dev, "%d: Channel state update to %s not allowed\n", + mhi_chan->chan, TO_CH_STATE_TYPE_STR(to_state)); + return -EINVAL; } mhi_cntrl->wake_toggle(mhi_cntrl); - read_unlock_bh(&mhi_cntrl->pm_lock); - mhi_cntrl->runtime_get(mhi_cntrl); mhi_cntrl->runtime_put(mhi_cntrl); - ret = mhi_send_cmd(mhi_cntrl, mhi_chan, MHI_CMD_RESET_CHAN); - if (ret) - goto error_invalid_state; - /* even if it fails we will still reset */ + reinit_completion(&mhi_chan->completion); + ret = mhi_send_cmd(mhi_cntrl, mhi_chan, cmd); + if (ret) { + dev_err(dev, "%d: Failed to send %s channel command\n", + mhi_chan->chan, TO_CH_STATE_TYPE_STR(to_state)); + return ret; + } + ret = wait_for_completion_timeout(&mhi_chan->completion, - msecs_to_jiffies(mhi_cntrl->timeout_ms)); - if (!ret || mhi_chan->ccs != MHI_EV_CC_SUCCESS) + msecs_to_jiffies(mhi_cntrl->timeout_ms)); + if (!ret || mhi_chan->ccs != MHI_EV_CC_SUCCESS) { dev_err(dev, - "Failed to receive cmd completion, still resetting\n"); + "%d: Failed to receive %s channel command completion\n", + mhi_chan->chan, TO_CH_STATE_TYPE_STR(to_state)); + return -EIO; + } + + if (to_state != MHI_CH_STATE_TYPE_RESET) { + write_lock_irq(&mhi_chan->lock); + mhi_chan->ch_state = (to_state == MHI_CH_STATE_TYPE_START) ? + MHI_CH_STATE_ENABLED : MHI_CH_STATE_STOP; + write_unlock_irq(&mhi_chan->lock); + } + + dev_dbg(dev, "%d: Channel state change to %s successful\n", + mhi_chan->chan, TO_CH_STATE_TYPE_STR(to_state)); + + return 0; +} + +static void __mhi_unprepare_channel(struct mhi_controller *mhi_cntrl, + struct mhi_chan *mhi_chan) +{ + int ret; + struct device *dev = &mhi_cntrl->mhi_dev->dev; + + mutex_lock(&mhi_chan->mutex); + + /* no more processing events for this channel */ + ret = mhi_update_channel_state(mhi_cntrl, mhi_chan, + MHI_CH_STATE_TYPE_RESET); + if (ret) + dev_err(dev, "%d: Failed to reset channel, still resetting\n", + mhi_chan->chan); -error_invalid_state: if (!mhi_chan->offload_ch) { mhi_reset_chan(mhi_cntrl, mhi_chan); mhi_deinit_chan_ctxt(mhi_cntrl, mhi_chan); } - dev_dbg(dev, "chan:%d successfully resetted\n", mhi_chan->chan); + dev_dbg(dev, "%d: successfully reset\n", mhi_chan->chan); + mutex_unlock(&mhi_chan->mutex); } @@ -1301,8 +1350,6 @@ int mhi_prepare_channel(struct mhi_controller *mhi_cntrl, int ret = 0; struct device *dev = &mhi_cntrl->mhi_dev->dev; - dev_dbg(dev, "Preparing channel: %d\n", mhi_chan->chan); - if (!(BIT(mhi_cntrl->ee) & mhi_chan->ee_mask)) { dev_err(dev, "Current EE: %s Required EE Mask: 0x%x for chan: %s\n", @@ -1313,14 +1360,6 @@ int mhi_prepare_channel(struct mhi_controller *mhi_cntrl, mutex_lock(&mhi_chan->mutex); - /* If channel is not in disable state, do not allow it to start */ - if (mhi_chan->ch_state != MHI_CH_STATE_DISABLED) { - ret = -EIO; - dev_dbg(dev, "channel: %d is not in disabled state\n", - mhi_chan->chan); - goto error_init_chan; - } - /* Check of client manages channel context for offload channels */ if (!mhi_chan->offload_ch) { ret = mhi_init_chan_ctxt(mhi_cntrl, mhi_chan); @@ -1328,34 +1367,11 @@ int mhi_prepare_channel(struct mhi_controller *mhi_cntrl, goto error_init_chan; } - reinit_completion(&mhi_chan->completion); - read_lock_bh(&mhi_cntrl->pm_lock); - if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { - read_unlock_bh(&mhi_cntrl->pm_lock); - ret = -EIO; - goto error_pm_state; - } - - mhi_cntrl->wake_toggle(mhi_cntrl); - read_unlock_bh(&mhi_cntrl->pm_lock); - mhi_cntrl->runtime_get(mhi_cntrl); - mhi_cntrl->runtime_put(mhi_cntrl); - - ret = mhi_send_cmd(mhi_cntrl, mhi_chan, MHI_CMD_START_CHAN); + ret = mhi_update_channel_state(mhi_cntrl, mhi_chan, + MHI_CH_STATE_TYPE_START); if (ret) goto error_pm_state; - ret = wait_for_completion_timeout(&mhi_chan->completion, - msecs_to_jiffies(mhi_cntrl->timeout_ms)); - if (!ret || mhi_chan->ccs != MHI_EV_CC_SUCCESS) { - ret = -EIO; - goto error_pm_state; - } - - write_lock_irq(&mhi_chan->lock); - mhi_chan->ch_state = MHI_CH_STATE_ENABLED; - write_unlock_irq(&mhi_chan->lock); - /* Pre-allocate buffer for xfer ring */ if (mhi_chan->pre_alloc) { int nr_el = get_nr_avail_ring_elements(mhi_cntrl, @@ -1393,9 +1409,6 @@ int mhi_prepare_channel(struct mhi_controller *mhi_cntrl, mutex_unlock(&mhi_chan->mutex); - dev_dbg(dev, "Chan: %d successfully moved to start state\n", - mhi_chan->chan); - return 0; error_pm_state: -- cgit v1.2.3 From cde61bb0470df8cfb5d49ebe88e9802fb0f817f0 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Thu, 1 Apr 2021 14:16:13 -0700 Subject: bus: mhi: core: Update debug messages to use client device Debug messages dealing with client devices use the generic MHI controller or parent device along with a channel number. It would be better to instead use the client device directly and enable better log messages for channel updates. Suggested-by: Manivannan Sadhasivam Signed-off-by: Bhaumik Bhatt Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1617311778-1254-5-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/main.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index 16bf8ec4e289..ef778389476f 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -1246,7 +1246,7 @@ static int mhi_update_channel_state(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, enum mhi_ch_state_type to_state) { - struct device *dev = &mhi_cntrl->mhi_dev->dev; + struct device *dev = &mhi_chan->mhi_dev->dev; enum mhi_cmd_type cmd = MHI_CMD_NOP; int ret; @@ -1324,7 +1324,7 @@ static void __mhi_unprepare_channel(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan) { int ret; - struct device *dev = &mhi_cntrl->mhi_dev->dev; + struct device *dev = &mhi_chan->mhi_dev->dev; mutex_lock(&mhi_chan->mutex); @@ -1348,13 +1348,11 @@ int mhi_prepare_channel(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan) { int ret = 0; - struct device *dev = &mhi_cntrl->mhi_dev->dev; + struct device *dev = &mhi_chan->mhi_dev->dev; if (!(BIT(mhi_cntrl->ee) & mhi_chan->ee_mask)) { - dev_err(dev, - "Current EE: %s Required EE Mask: 0x%x for chan: %s\n", - TO_MHI_EXEC_STR(mhi_cntrl->ee), mhi_chan->ee_mask, - mhi_chan->name); + dev_err(dev, "Current EE: %s Required EE Mask: 0x%x\n", + TO_MHI_EXEC_STR(mhi_cntrl->ee), mhi_chan->ee_mask); return -ENOTCONN; } -- cgit v1.2.3 From 73b7aebcc8cbc2cddfb34be9840542807ad61044 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Thu, 1 Apr 2021 14:16:14 -0700 Subject: bus: mhi: core: Hold device wake for channel update commands MHI host can fail early if device is in a bad state by attempting to assert device wake and holding the runtime PM vote before sending a channel update command instead of performing a wake toggle and waiting for a timeout if the send were to fail. This can help improve the design and enable shorter wait periods for device to respond as votes are already held. Signed-off-by: Bhaumik Bhatt Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1617311778-1254-6-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/main.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index ef778389476f..b4b87a9e17a4 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -1286,16 +1286,18 @@ static int mhi_update_channel_state(struct mhi_controller *mhi_cntrl, return -EINVAL; } - mhi_cntrl->wake_toggle(mhi_cntrl); + /* bring host and device out of suspended states */ + ret = mhi_device_get_sync(mhi_cntrl->mhi_dev); + if (ret) + return ret; mhi_cntrl->runtime_get(mhi_cntrl); - mhi_cntrl->runtime_put(mhi_cntrl); reinit_completion(&mhi_chan->completion); ret = mhi_send_cmd(mhi_cntrl, mhi_chan, cmd); if (ret) { dev_err(dev, "%d: Failed to send %s channel command\n", mhi_chan->chan, TO_CH_STATE_TYPE_STR(to_state)); - return ret; + goto exit_channel_update; } ret = wait_for_completion_timeout(&mhi_chan->completion, @@ -1304,9 +1306,12 @@ static int mhi_update_channel_state(struct mhi_controller *mhi_cntrl, dev_err(dev, "%d: Failed to receive %s channel command completion\n", mhi_chan->chan, TO_CH_STATE_TYPE_STR(to_state)); - return -EIO; + ret = -EIO; + goto exit_channel_update; } + ret = 0; + if (to_state != MHI_CH_STATE_TYPE_RESET) { write_lock_irq(&mhi_chan->lock); mhi_chan->ch_state = (to_state == MHI_CH_STATE_TYPE_START) ? @@ -1317,7 +1322,11 @@ static int mhi_update_channel_state(struct mhi_controller *mhi_cntrl, dev_dbg(dev, "%d: Channel state change to %s successful\n", mhi_chan->chan, TO_CH_STATE_TYPE_STR(to_state)); - return 0; +exit_channel_update: + mhi_cntrl->runtime_put(mhi_cntrl); + mhi_device_put(mhi_cntrl->mhi_dev); + + return ret; } static void __mhi_unprepare_channel(struct mhi_controller *mhi_cntrl, -- cgit v1.2.3 From 47705c08465931923e2f2b506986ca0bdf80380d Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Thu, 1 Apr 2021 14:16:15 -0700 Subject: bus: mhi: core: Clear configuration from channel context during reset When clearing up the channel context after client drivers are done using channels, the configuration is currently not being reset entirely. Ensure this is done to appropriately handle issues where clients unaware of the context state end up calling functions which expect a context. Signed-off-by: Bhaumik Bhatt Reviewed-by: Hemant Kumar Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1617311778-1254-7-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/init.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c index 0e54384e9fc5..c81b377fca8f 100644 --- a/drivers/bus/mhi/core/init.c +++ b/drivers/bus/mhi/core/init.c @@ -558,6 +558,7 @@ void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl, struct mhi_ring *buf_ring; struct mhi_ring *tre_ring; struct mhi_chan_ctxt *chan_ctxt; + u32 tmp; buf_ring = &mhi_chan->buf_ring; tre_ring = &mhi_chan->tre_ring; @@ -571,7 +572,19 @@ void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl, vfree(buf_ring->base); buf_ring->base = tre_ring->base = NULL; + tre_ring->ctxt_wp = NULL; chan_ctxt->rbase = 0; + chan_ctxt->rlen = 0; + chan_ctxt->rp = 0; + chan_ctxt->wp = 0; + + tmp = chan_ctxt->chcfg; + tmp &= ~CHAN_CTX_CHSTATE_MASK; + tmp |= (MHI_CH_STATE_DISABLED << CHAN_CTX_CHSTATE_SHIFT); + chan_ctxt->chcfg = tmp; + + /* Update to all cores */ + smp_wmb(); } int mhi_init_chan_ctxt(struct mhi_controller *mhi_cntrl, -- cgit v1.2.3 From 8e06e9fb990975a55b64c6e4c5b6b183962f849a Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Thu, 1 Apr 2021 14:16:16 -0700 Subject: bus: mhi: core: Check channel execution environment before issuing reset A client can attempt to unprepare certain channels for transfer even after the execution environment they are supposed to run in has changed. In the event that happens, the device need not be notified of the reset and the host can proceed with clean up for the channel context and memory allocated for it on the host as the device will no longer be able to respond to such a request. Signed-off-by: Bhaumik Bhatt Reviewed-by: Hemant Kumar Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1617311778-1254-8-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/main.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index b4b87a9e17a4..0be1e7747cd7 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -1337,6 +1337,12 @@ static void __mhi_unprepare_channel(struct mhi_controller *mhi_cntrl, mutex_lock(&mhi_chan->mutex); + if (!(BIT(mhi_cntrl->ee) & mhi_chan->ee_mask)) { + dev_dbg(dev, "Current EE: %s Required EE Mask: 0x%x\n", + TO_MHI_EXEC_STR(mhi_cntrl->ee), mhi_chan->ee_mask); + goto exit_unprepare_channel; + } + /* no more processing events for this channel */ ret = mhi_update_channel_state(mhi_cntrl, mhi_chan, MHI_CH_STATE_TYPE_RESET); @@ -1344,6 +1350,11 @@ static void __mhi_unprepare_channel(struct mhi_controller *mhi_cntrl, dev_err(dev, "%d: Failed to reset channel, still resetting\n", mhi_chan->chan); +exit_unprepare_channel: + write_lock_irq(&mhi_chan->lock); + mhi_chan->ch_state = MHI_CH_STATE_DISABLED; + write_unlock_irq(&mhi_chan->lock); + if (!mhi_chan->offload_ch) { mhi_reset_chan(mhi_cntrl, mhi_chan); mhi_deinit_chan_ctxt(mhi_cntrl, mhi_chan); -- cgit v1.2.3 From 8aaa288f709e3df98717562fb3d817af1b2a1f9b Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Thu, 1 Apr 2021 14:16:17 -0700 Subject: bus: mhi: core: Remove __ prefix for MHI channel unprepare function The __mhi_unprepare_channel() API does not require the __ prefix. Get rid of it and make the internal function consistent with the other function names. Signed-off-by: Bhaumik Bhatt Reviewed-by: Manivannan Sadhasivam Reviewed-by: Hemant Kumar Link: https://lore.kernel.org/r/1617311778-1254-9-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index 0be1e7747cd7..55aa7db11e4f 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -1329,8 +1329,8 @@ exit_channel_update: return ret; } -static void __mhi_unprepare_channel(struct mhi_controller *mhi_cntrl, - struct mhi_chan *mhi_chan) +static void mhi_unprepare_channel(struct mhi_controller *mhi_cntrl, + struct mhi_chan *mhi_chan) { int ret; struct device *dev = &mhi_chan->mhi_dev->dev; @@ -1440,7 +1440,7 @@ error_init_chan: error_pre_alloc: mutex_unlock(&mhi_chan->mutex); - __mhi_unprepare_channel(mhi_cntrl, mhi_chan); + mhi_unprepare_channel(mhi_cntrl, mhi_chan); return ret; } @@ -1560,7 +1560,7 @@ error_open_chan: if (!mhi_chan) continue; - __mhi_unprepare_channel(mhi_cntrl, mhi_chan); + mhi_unprepare_channel(mhi_cntrl, mhi_chan); } return ret; @@ -1578,7 +1578,7 @@ void mhi_unprepare_from_transfer(struct mhi_device *mhi_dev) if (!mhi_chan) continue; - __mhi_unprepare_channel(mhi_cntrl, mhi_chan); + mhi_unprepare_channel(mhi_cntrl, mhi_chan); } } EXPORT_SYMBOL_GPL(mhi_unprepare_from_transfer); -- cgit v1.2.3 From 6731fefd95671575ceaba8e1c60881d529537352 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Thu, 1 Apr 2021 14:16:18 -0700 Subject: bus: mhi: Improve documentation on channel transfer setup APIs The mhi_prepare_for_transfer() and mhi_unprepare_from_transfer() APIs could use better explanation. Add details on what MHI does when these APIs are used. Signed-off-by: Bhaumik Bhatt Reviewed-by: Hemant Kumar Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1617311778-1254-10-git-send-email-bbhatt@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- include/linux/mhi.h | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/include/linux/mhi.h b/include/linux/mhi.h index c9b36a34cc7f..d095fba37d1e 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -712,13 +712,27 @@ int mhi_device_get_sync(struct mhi_device *mhi_dev); void mhi_device_put(struct mhi_device *mhi_dev); /** - * mhi_prepare_for_transfer - Setup channel for data transfer + * mhi_prepare_for_transfer - Setup UL and DL channels for data transfer. + * Allocate and initialize the channel context and + * also issue the START channel command to both + * channels. Channels can be started only if both + * host and device execution environments match and + * channels are in a DISABLED state. * @mhi_dev: Device associated with the channels */ int mhi_prepare_for_transfer(struct mhi_device *mhi_dev); /** - * mhi_unprepare_from_transfer - Unprepare the channels + * mhi_unprepare_from_transfer - Reset UL and DL channels for data transfer. + * Issue the RESET channel command and let the + * device clean-up the context so no incoming + * transfers are seen on the host. Free memory + * associated with the context on host. If device + * is unresponsive, only perform a host side + * clean-up. Channels can be reset only if both + * host and device execution environments match + * and channels are in an ENABLED, STOPPED or + * SUSPENDED state. * @mhi_dev: Device associated with the channels */ void mhi_unprepare_from_transfer(struct mhi_device *mhi_dev); -- cgit v1.2.3 From 757072abe1c0b67cb226936c709291889658a222 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 19 Mar 2021 16:50:37 +0100 Subject: bus: mhi: pci_generic: Implement PCI shutdown callback Deinit the device on shutdown to halt MHI/PCI operation on device side. This change fixes floating device state with some hosts that do not fully shutdown PCIe device when rebooting. Signed-off-by: Loic Poulain Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1616169037-7969-1-git-send-email-loic.poulain@linaro.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/pci_generic.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/bus/mhi/pci_generic.c b/drivers/bus/mhi/pci_generic.c index 544853c67e02..f5992ec7eeb7 100644 --- a/drivers/bus/mhi/pci_generic.c +++ b/drivers/bus/mhi/pci_generic.c @@ -641,6 +641,12 @@ static void mhi_pci_remove(struct pci_dev *pdev) mhi_unregister_controller(mhi_cntrl); } +static void mhi_pci_shutdown(struct pci_dev *pdev) +{ + mhi_pci_remove(pdev); + pci_set_power_state(pdev, PCI_D3hot); +} + static void mhi_pci_reset_prepare(struct pci_dev *pdev) { struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev); @@ -857,6 +863,7 @@ static struct pci_driver mhi_pci_driver = { .id_table = mhi_pci_id_table, .probe = mhi_pci_probe, .remove = mhi_pci_remove, + .shutdown = mhi_pci_shutdown, .err_handler = &mhi_pci_err_handler, .driver.pm = &mhi_pci_pm_ops }; -- cgit v1.2.3 From 11134390d742bd22e574d03280fe0ec8d3d4974e Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Wed, 7 Apr 2021 10:41:00 +0200 Subject: bus: mhi: pci_generic: Add FIREHOSE channels When device enters flash programmer context (FP), it exposes firehose protocol through the EDL dedicated channels. Signed-off-by: Loic Poulain Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/1617784860-32439-1-git-send-email-loic.poulain@linaro.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/pci_generic.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/bus/mhi/pci_generic.c b/drivers/bus/mhi/pci_generic.c index f5992ec7eeb7..aa8f8d541371 100644 --- a/drivers/bus/mhi/pci_generic.c +++ b/drivers/bus/mhi/pci_generic.c @@ -145,6 +145,36 @@ struct mhi_pci_dev_info { .doorbell_mode_switch = false, \ } +#define MHI_CHANNEL_CONFIG_UL_FP(ch_num, ch_name, el_count, ev_ring) \ + { \ + .num = ch_num, \ + .name = ch_name, \ + .num_elements = el_count, \ + .event_ring = ev_ring, \ + .dir = DMA_TO_DEVICE, \ + .ee_mask = BIT(MHI_EE_FP), \ + .pollcfg = 0, \ + .doorbell = MHI_DB_BRST_DISABLE, \ + .lpm_notify = false, \ + .offload_channel = false, \ + .doorbell_mode_switch = false, \ + } \ + +#define MHI_CHANNEL_CONFIG_DL_FP(ch_num, ch_name, el_count, ev_ring) \ + { \ + .num = ch_num, \ + .name = ch_name, \ + .num_elements = el_count, \ + .event_ring = ev_ring, \ + .dir = DMA_FROM_DEVICE, \ + .ee_mask = BIT(MHI_EE_FP), \ + .pollcfg = 0, \ + .doorbell = MHI_DB_BRST_DISABLE, \ + .lpm_notify = false, \ + .offload_channel = false, \ + .doorbell_mode_switch = false, \ + } + #define MHI_EVENT_CONFIG_DATA(ev_ring, el_count) \ { \ .num_elements = el_count, \ @@ -181,6 +211,8 @@ static const struct mhi_channel_config modem_qcom_v1_mhi_channels[] = { MHI_CHANNEL_CONFIG_DL(15, "QMI", 4, 0), MHI_CHANNEL_CONFIG_UL(20, "IPCR", 8, 0), MHI_CHANNEL_CONFIG_DL(21, "IPCR", 8, 0), + MHI_CHANNEL_CONFIG_UL_FP(34, "FIREHOSE", 32, 0), + MHI_CHANNEL_CONFIG_DL_FP(35, "FIREHOSE", 32, 0), MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0", 128, 2), MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0", 128, 3), }; @@ -241,6 +273,9 @@ static const struct mhi_channel_config mhi_quectel_em1xx_channels[] = { MHI_CHANNEL_CONFIG_DL(13, "MBIM", 32, 0), MHI_CHANNEL_CONFIG_UL(32, "DUN", 32, 0), MHI_CHANNEL_CONFIG_DL(33, "DUN", 32, 0), + /* The EDL firmware is a flash-programmer exposing firehose protocol */ + MHI_CHANNEL_CONFIG_UL_FP(34, "FIREHOSE", 32, 0), + MHI_CHANNEL_CONFIG_DL_FP(35, "FIREHOSE", 32, 0), MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0_MBIM", 128, 2), MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0_MBIM", 128, 3), }; -- cgit v1.2.3 From ec58594972255165c03344d7e15fb1242f5d3c4e Mon Sep 17 00:00:00 2001 From: Sai Prakash Ranjan Date: Wed, 7 Apr 2021 10:00:04 -0600 Subject: coresight: etm4x: Add ETM PID for Cortex-A78 Add ETM PID for Cortex-A78 to the list of supported ETMs. Link: https://lore.kernel.org/r/20210213112829.26834-1-saiprakash.ranjan@codeaurora.org Reviewed-by: Mike Leach Signed-off-by: Sai Prakash Ranjan Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20210407160007.418053-2-mathieu.poirier@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-etm4x-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 15016f757828..a5b13a7779c3 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -1951,6 +1951,7 @@ static const struct amba_id etm4_ids[] = { CS_AMBA_UCI_ID(0x000bbd05, uci_id_etm4),/* Cortex-A55 */ CS_AMBA_UCI_ID(0x000bbd0a, uci_id_etm4),/* Cortex-A75 */ CS_AMBA_UCI_ID(0x000bbd0c, uci_id_etm4),/* Neoverse N1 */ + CS_AMBA_UCI_ID(0x000bbd41, uci_id_etm4),/* Cortex-A78 */ CS_AMBA_UCI_ID(0x000f0205, uci_id_etm4),/* Qualcomm Kryo */ CS_AMBA_UCI_ID(0x000f0211, uci_id_etm4),/* Qualcomm Kryo */ CS_AMBA_UCI_ID(0x000bb802, uci_id_etm4),/* Qualcomm Kryo 385 Cortex-A55 */ -- cgit v1.2.3 From d8844295184cbbba54f27d6c5c0b3475d2a96042 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 7 Apr 2021 10:00:05 -0600 Subject: coresight: etm: perf: Make symbol 'format_attr_contextid' static The sparse tool complains as follows: drivers/hwtracing/coresight/coresight-etm-perf.c:61:25: warning: symbol 'format_attr_contextid' was not declared. Should it be static? This symbol is not used outside of coresight-etm-perf.c, so this commit marks it static. Link: https://lore.kernel.org/r/20210308123250.2417947-1-weiyongjun1@huawei.com Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20210407160007.418053-3-mathieu.poirier@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-etm-perf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 0f603b4094f2..bdbb77334329 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -58,7 +58,7 @@ static ssize_t format_attr_contextid_show(struct device *dev, return sprintf(page, "config:%d\n", pid_fmt); } -struct device_attribute format_attr_contextid = +static struct device_attribute format_attr_contextid = __ATTR(contextid, 0444, format_attr_contextid_show, NULL); static struct attribute *etm_config_formats_attr[] = { -- cgit v1.2.3 From 023e0294e1ed6c497c405d86573be267691a09a8 Mon Sep 17 00:00:00 2001 From: Qi Liu Date: Wed, 7 Apr 2021 10:00:06 -0600 Subject: coresight: core: Fix typo in coresight-core.c Fix the following checkpatch warning: WARNING: 'compoment' may be misspelled - perhaps 'component'? Link: https://lore.kernel.org/r/1616487086-50418-1-git-send-email-liuqi115@huawei.com Signed-off-by: Qi Liu Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20210407160007.418053-4-mathieu.poirier@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 0062c8935653..b57bea167102 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -86,7 +86,7 @@ static int coresight_id_match(struct device *dev, void *data) i_csdev->type != CORESIGHT_DEV_TYPE_SOURCE) return 0; - /* Get the source ID for both compoment */ + /* Get the source ID for both components */ trace_id = source_ops(csdev)->trace_id(csdev); i_trace_id = source_ops(i_csdev)->trace_id(i_csdev); -- cgit v1.2.3 From e76e8b56fe1ab1e9d28e341fac614ddb1a82f8e5 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Wed, 7 Apr 2021 10:00:07 -0600 Subject: MAINTAINERS: Add CoreSight header files Adding CoreSight headers to the list of supported files so that maintainers can be notified when changes are submitted. Link: https://lore.kernel.org/r/20210326155431.2011889-1-mathieu.poirier@linaro.org Signed-off-by: Mathieu Poirier Link: https://lore.kernel.org/r/20210407160007.418053-5-mathieu.poirier@linaro.org Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 6ae3955525a9..aa86b4d0bfce 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1764,6 +1764,7 @@ F: Documentation/devicetree/bindings/arm/coresight.txt F: Documentation/trace/coresight/* F: drivers/hwtracing/coresight/* F: include/dt-bindings/arm/coresight-cti-dt.h +F: include/linux/coresight* F: tools/perf/arch/arm/util/auxtrace.c F: tools/perf/arch/arm/util/cs-etm.c F: tools/perf/arch/arm/util/cs-etm.h -- cgit v1.2.3 From 17e8ff013e3e82a66d239777d113b2aaa97a77d4 Mon Sep 17 00:00:00 2001 From: Timon Baetz Date: Wed, 30 Dec 2020 20:51:53 +0000 Subject: extcon: max8997: Add CHGINS and CHGRM interrupt handling This allows the MAX8997 charger to set the current limit depending on the detected extcon charger type. Signed-off-by: Timon Baetz Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-max8997.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c index 337b0eea4e62..e1408075ef7d 100644 --- a/drivers/extcon/extcon-max8997.c +++ b/drivers/extcon/extcon-max8997.c @@ -44,6 +44,8 @@ static struct max8997_muic_irq muic_irqs[] = { { MAX8997_MUICIRQ_ChgDetRun, "muic-CHGDETRUN" }, { MAX8997_MUICIRQ_ChgTyp, "muic-CHGTYP" }, { MAX8997_MUICIRQ_OVP, "muic-OVP" }, + { MAX8997_PMICIRQ_CHGINS, "pmic-CHGINS" }, + { MAX8997_PMICIRQ_CHGRM, "pmic-CHGRM" }, }; /* Define supported cable type */ @@ -538,6 +540,8 @@ static void max8997_muic_irq_work(struct work_struct *work) case MAX8997_MUICIRQ_DCDTmr: case MAX8997_MUICIRQ_ChgDetRun: case MAX8997_MUICIRQ_ChgTyp: + case MAX8997_PMICIRQ_CHGINS: + case MAX8997_PMICIRQ_CHGRM: /* Handle charger cable */ ret = max8997_muic_chg_handler(info); break; -- cgit v1.2.3 From e3f60329097be9e6c314de36c8dd0c7c5c2c0c7b Mon Sep 17 00:00:00 2001 From: Nikita Travkin Date: Tue, 19 Jan 2021 18:33:47 +0500 Subject: extcon: sm5502: Detect OTG when USB_ID is connected to ground In it's curent state this driver ignores OTG adapters with ID pin connected to ground. This commit adds a check to set extcon into host mode when such OTG adapter is connected. Signed-off-by: Nikita Travkin Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-sm5502.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c index 106d4da647bd..db41d1c58efd 100644 --- a/drivers/extcon/extcon-sm5502.c +++ b/drivers/extcon/extcon-sm5502.c @@ -144,6 +144,7 @@ enum sm5502_muic_acc_type { SM5502_MUIC_ADC_AUDIO_TYPE1_FULL_REMOTE = 0x3e, /* | 001|11110| */ SM5502_MUIC_ADC_AUDIO_TYPE1_SEND_END = 0x5e, /* | 010|11110| */ /* |Dev Type1|--ADC| */ + SM5502_MUIC_ADC_GROUND_USB_OTG = 0x80, /* | 100|00000| */ SM5502_MUIC_ADC_OPEN_USB = 0x5f, /* | 010|11111| */ SM5502_MUIC_ADC_OPEN_TA = 0xdf, /* | 110|11111| */ SM5502_MUIC_ADC_OPEN_USB_OTG = 0xff, /* | 111|11111| */ @@ -291,11 +292,27 @@ static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info) * connected with to MUIC device. */ cable_type = adc & SM5502_REG_ADC_MASK; - if (cable_type == SM5502_MUIC_ADC_GROUND) - return SM5502_MUIC_ADC_GROUND; switch (cable_type) { case SM5502_MUIC_ADC_GROUND: + ret = regmap_read(info->regmap, SM5502_REG_DEV_TYPE1, + &dev_type1); + if (ret) { + dev_err(info->dev, "failed to read DEV_TYPE1 reg\n"); + return ret; + } + + switch (dev_type1) { + case SM5502_REG_DEV_TYPE1_USB_OTG_MASK: + cable_type = SM5502_MUIC_ADC_GROUND_USB_OTG; + break; + default: + dev_dbg(info->dev, + "cannot identify the cable type: adc(0x%x), dev_type1(0x%x)\n", + adc, dev_type1); + return -EINVAL; + } + break; case SM5502_MUIC_ADC_SEND_END_BUTTON: case SM5502_MUIC_ADC_REMOTE_S1_BUTTON: case SM5502_MUIC_ADC_REMOTE_S2_BUTTON: @@ -396,6 +413,7 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info, con_sw = DM_DP_SWITCH_OPEN; vbus_sw = VBUSIN_SWITCH_VBUSOUT; break; + case SM5502_MUIC_ADC_GROUND_USB_OTG: case SM5502_MUIC_ADC_OPEN_USB_OTG: id = EXTCON_USB_HOST; con_sw = DM_DP_SWITCH_USB; -- cgit v1.2.3 From dd6f5afb1c2db352f8dd2d181597b3835f132657 Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Mon, 25 Jan 2021 16:38:30 -0800 Subject: bindings: pm8941-misc: Convert bindings to YAML Convert bindings from txt to YAML. Signed-off-by: Guru Das Srinagesh Reviewed-by: Rob Herring Signed-off-by: Chanwoo Choi --- .../bindings/extcon/qcom,pm8941-misc.txt | 41 --------------- .../bindings/extcon/qcom,pm8941-misc.yaml | 59 ++++++++++++++++++++++ 2 files changed, 59 insertions(+), 41 deletions(-) delete mode 100644 Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.txt create mode 100644 Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.yaml diff --git a/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.txt b/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.txt deleted file mode 100644 index 35383adb10f1..000000000000 --- a/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.txt +++ /dev/null @@ -1,41 +0,0 @@ -Qualcomm's PM8941 USB ID Extcon device - -Some Qualcomm PMICs have a "misc" module that can be used to detect when -the USB ID pin has been pulled low or high. - -PROPERTIES - -- compatible: - Usage: required - Value type: - Definition: Should contain "qcom,pm8941-misc"; - -- reg: - Usage: required - Value type: - Definition: Should contain the offset to the misc address space - -- interrupts: - Usage: required - Value type: - Definition: Should contain the usb id interrupt - -- interrupt-names: - Usage: required - Value type: - Definition: Should contain the string "usb_id" for the usb id interrupt - -Example: - - pmic { - usb_id: misc@900 { - compatible = "qcom,pm8941-misc"; - reg = <0x900>; - interrupts = <0x0 0x9 0 IRQ_TYPE_EDGE_BOTH>; - interrupt-names = "usb_id"; - }; - } - - usb-controller { - extcon = <&usb_id>; - }; diff --git a/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.yaml b/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.yaml new file mode 100644 index 000000000000..e8eea8304340 --- /dev/null +++ b/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/extcon/qcom,pm8941-misc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. PM8941 USB ID Extcon device + +maintainers: + - Guru Das Srinagesh + +description: | + Some Qualcomm PMICs have a "misc" module that can be used to detect when + the USB ID pin has been pulled low or high. + +properties: + compatible: + items: + - const: qcom,pm8941-misc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + interrupt-names: + items: + - const: usb_id + +required: + - compatible + - reg + - interrupts + - interrupt-names + +additionalProperties: false + +examples: + - | + #include + + pmic { + #address-cells = <1>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + + usb_id: misc@900 { + compatible = "qcom,pm8941-misc"; + reg = <0x900>; + interrupts = <0x0 0x9 0 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "usb_id"; + }; + }; + + usb-controller { + extcon = <&usb_id>; + }; -- cgit v1.2.3 From 4fcdd677c4ea0f57eda1be6fcd965ddd7d9551d6 Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Mon, 25 Jan 2021 16:38:31 -0800 Subject: bindings: pm8941-misc: Add support for VBUS detection Add interrupt support for reporting VBUS detection status that can be detected via a dedicated PMIC pin. Signed-off-by: Anirudh Ghayal Signed-off-by: Guru Das Srinagesh Reviewed-by: Rob Herring Signed-off-by: Chanwoo Choi --- Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.yaml b/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.yaml index e8eea8304340..6a9c96f0352a 100644 --- a/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.yaml +++ b/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.yaml @@ -22,11 +22,14 @@ properties: maxItems: 1 interrupts: - maxItems: 1 + minItems: 1 + maxItems: 2 interrupt-names: + minItems: 1 items: - const: usb_id + - const: usb_vbus required: - compatible -- cgit v1.2.3 From 7b1222b224aff41739319ae81cd266825464ad8f Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Mon, 25 Jan 2021 16:38:32 -0800 Subject: extcon: qcom-spmi: Add support for VBUS detection VBUS can be detected via a dedicated PMIC pin. Add support for reporting the VBUS status. Signed-off-by: Anirudh Ghayal Signed-off-by: Kavya Nunna Signed-off-by: Guru Das Srinagesh Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-qcom-spmi-misc.c | 99 +++++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 19 deletions(-) diff --git a/drivers/extcon/extcon-qcom-spmi-misc.c b/drivers/extcon/extcon-qcom-spmi-misc.c index 6b836ae62176..9e8ccfbea026 100644 --- a/drivers/extcon/extcon-qcom-spmi-misc.c +++ b/drivers/extcon/extcon-qcom-spmi-misc.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /** * extcon-qcom-spmi-misc.c - Qualcomm USB extcon driver to support USB ID - * detection based on extcon-usb-gpio.c. + * and VBUS detection based on extcon-usb-gpio.c. * * Copyright (C) 2016 Linaro, Ltd. * Stephen Boyd @@ -21,30 +21,56 @@ struct qcom_usb_extcon_info { struct extcon_dev *edev; - int irq; + int id_irq; + int vbus_irq; struct delayed_work wq_detcable; unsigned long debounce_jiffies; }; static const unsigned int qcom_usb_extcon_cable[] = { + EXTCON_USB, EXTCON_USB_HOST, EXTCON_NONE, }; static void qcom_usb_extcon_detect_cable(struct work_struct *work) { - bool id; + bool state = false; int ret; + union extcon_property_value val; struct qcom_usb_extcon_info *info = container_of(to_delayed_work(work), struct qcom_usb_extcon_info, wq_detcable); - /* check ID and update cable state */ - ret = irq_get_irqchip_state(info->irq, IRQCHIP_STATE_LINE_LEVEL, &id); - if (ret) - return; + if (info->id_irq > 0) { + /* check ID and update cable state */ + ret = irq_get_irqchip_state(info->id_irq, + IRQCHIP_STATE_LINE_LEVEL, &state); + if (ret) + return; + + if (!state) { + val.intval = true; + extcon_set_property(info->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_SS, val); + } + extcon_set_state_sync(info->edev, EXTCON_USB_HOST, !state); + } - extcon_set_state_sync(info->edev, EXTCON_USB_HOST, !id); + if (info->vbus_irq > 0) { + /* check VBUS and update cable state */ + ret = irq_get_irqchip_state(info->vbus_irq, + IRQCHIP_STATE_LINE_LEVEL, &state); + if (ret) + return; + + if (state) { + val.intval = true; + extcon_set_property(info->edev, EXTCON_USB, + EXTCON_PROP_USB_SS, val); + } + extcon_set_state_sync(info->edev, EXTCON_USB, state); + } } static irqreturn_t qcom_usb_irq_handler(int irq, void *dev_id) @@ -79,21 +105,48 @@ static int qcom_usb_extcon_probe(struct platform_device *pdev) return ret; } + ret = extcon_set_property_capability(info->edev, + EXTCON_USB, EXTCON_PROP_USB_SS); + ret |= extcon_set_property_capability(info->edev, + EXTCON_USB_HOST, EXTCON_PROP_USB_SS); + if (ret) { + dev_err(dev, "failed to register extcon props rc=%d\n", + ret); + return ret; + } + info->debounce_jiffies = msecs_to_jiffies(USB_ID_DEBOUNCE_MS); INIT_DELAYED_WORK(&info->wq_detcable, qcom_usb_extcon_detect_cable); - info->irq = platform_get_irq_byname(pdev, "usb_id"); - if (info->irq < 0) - return info->irq; + info->id_irq = platform_get_irq_byname(pdev, "usb_id"); + if (info->id_irq > 0) { + ret = devm_request_threaded_irq(dev, info->id_irq, NULL, + qcom_usb_irq_handler, + IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + pdev->name, info); + if (ret < 0) { + dev_err(dev, "failed to request handler for ID IRQ\n"); + return ret; + } + } - ret = devm_request_threaded_irq(dev, info->irq, NULL, + info->vbus_irq = platform_get_irq_byname(pdev, "usb_vbus"); + if (info->vbus_irq > 0) { + ret = devm_request_threaded_irq(dev, info->vbus_irq, NULL, qcom_usb_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, pdev->name, info); - if (ret < 0) { - dev_err(dev, "failed to request handler for ID IRQ\n"); - return ret; + if (ret < 0) { + dev_err(dev, "failed to request handler for VBUS IRQ\n"); + return ret; + } + } + + if (info->id_irq < 0 && info->vbus_irq < 0) { + dev_err(dev, "ID and VBUS IRQ not found\n"); + return -EINVAL; } platform_set_drvdata(pdev, info); @@ -120,8 +173,12 @@ static int qcom_usb_extcon_suspend(struct device *dev) struct qcom_usb_extcon_info *info = dev_get_drvdata(dev); int ret = 0; - if (device_may_wakeup(dev)) - ret = enable_irq_wake(info->irq); + if (device_may_wakeup(dev)) { + if (info->id_irq > 0) + ret = enable_irq_wake(info->id_irq); + if (info->vbus_irq > 0) + ret = enable_irq_wake(info->vbus_irq); + } return ret; } @@ -131,8 +188,12 @@ static int qcom_usb_extcon_resume(struct device *dev) struct qcom_usb_extcon_info *info = dev_get_drvdata(dev); int ret = 0; - if (device_may_wakeup(dev)) - ret = disable_irq_wake(info->irq); + if (device_may_wakeup(dev)) { + if (info->id_irq > 0) + ret = disable_irq_wake(info->id_irq); + if (info->vbus_irq > 0) + ret = disable_irq_wake(info->vbus_irq); + } return ret; } -- cgit v1.2.3 From ec32332df7645e0ba463a08d483fe97665167071 Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Wed, 10 Mar 2021 14:30:55 -0700 Subject: bus: mhi: core: Sanity check values from remote device before use When parsing the structures in the shared memory, there are values which come from the remote device. For example, a transfer completion event will have a pointer to the tre in the relevant channel's transfer ring. As another example, event ring elements may specify a channel in which the event occurred, however the specified channel value may not be valid as no channel is defined at that index even though the index may be less than the maximum allowed index. Such values should be considered to be untrusted, and validated before use. If we blindly use such values, we may access invalid data or crash if the values are corrupted. If validation fails, drop the relevant event. Signed-off-by: Jeffrey Hugo Reviewed-by: Manivannan Sadhasivam Reviewed-by: Hemant Kumar Link: https://lore.kernel.org/r/1615411855-15053-1-git-send-email-jhugo@codeaurora.org Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/main.c | 81 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 7 deletions(-) diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index 55aa7db11e4f..b0c8afe16e3a 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -265,6 +265,11 @@ static void mhi_del_ring_element(struct mhi_controller *mhi_cntrl, smp_wmb(); } +static bool is_valid_ring_ptr(struct mhi_ring *ring, dma_addr_t addr) +{ + return addr >= ring->iommu_base && addr < ring->iommu_base + ring->len; +} + int mhi_destroy_device(struct device *dev, void *data) { struct mhi_chan *ul_chan, *dl_chan; @@ -427,7 +432,16 @@ irqreturn_t mhi_irq_handler(int irq_number, void *dev) struct mhi_event_ctxt *er_ctxt = &mhi_cntrl->mhi_ctxt->er_ctxt[mhi_event->er_index]; struct mhi_ring *ev_ring = &mhi_event->ring; - void *dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); + dma_addr_t ptr = er_ctxt->rp; + void *dev_rp; + + if (!is_valid_ring_ptr(ev_ring, ptr)) { + dev_err(&mhi_cntrl->mhi_dev->dev, + "Event ring rp points outside of the event ring\n"); + return IRQ_HANDLED; + } + + dev_rp = mhi_to_virtual(ev_ring, ptr); /* Only proceed if event ring has pending events */ if (ev_ring->rp == dev_rp) @@ -583,6 +597,11 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl, struct mhi_buf_info *buf_info; u16 xfer_len; + if (!is_valid_ring_ptr(tre_ring, ptr)) { + dev_err(&mhi_cntrl->mhi_dev->dev, + "Event element points outside of the tre ring\n"); + break; + } /* Get the TRB this event points to */ ev_tre = mhi_to_virtual(tre_ring, ptr); @@ -745,6 +764,12 @@ static void mhi_process_cmd_completion(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan; u32 chan; + if (!is_valid_ring_ptr(mhi_ring, ptr)) { + dev_err(&mhi_cntrl->mhi_dev->dev, + "Event element points outside of the cmd ring\n"); + return; + } + cmd_pkt = mhi_to_virtual(mhi_ring, ptr); chan = MHI_TRE_GET_CMD_CHID(cmd_pkt); @@ -769,6 +794,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, struct device *dev = &mhi_cntrl->mhi_dev->dev; u32 chan; int count = 0; + dma_addr_t ptr = er_ctxt->rp; /* * This is a quick check to avoid unnecessary event processing @@ -778,7 +804,13 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, if (unlikely(MHI_EVENT_ACCESS_INVALID(mhi_cntrl->pm_state))) return -EIO; - dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); + if (!is_valid_ring_ptr(ev_ring, ptr)) { + dev_err(&mhi_cntrl->mhi_dev->dev, + "Event ring rp points outside of the event ring\n"); + return -EIO; + } + + dev_rp = mhi_to_virtual(ev_ring, ptr); local_rp = ev_ring->rp; while (dev_rp != local_rp) { @@ -887,6 +919,8 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, */ if (chan < mhi_cntrl->max_chan) { mhi_chan = &mhi_cntrl->mhi_chan[chan]; + if (!mhi_chan->configured) + break; parse_xfer_event(mhi_cntrl, local_rp, mhi_chan); event_quota--; } @@ -898,7 +932,15 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, mhi_recycle_ev_ring_element(mhi_cntrl, ev_ring); local_rp = ev_ring->rp; - dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); + + ptr = er_ctxt->rp; + if (!is_valid_ring_ptr(ev_ring, ptr)) { + dev_err(&mhi_cntrl->mhi_dev->dev, + "Event ring rp points outside of the event ring\n"); + return -EIO; + } + + dev_rp = mhi_to_virtual(ev_ring, ptr); count++; } @@ -921,11 +963,18 @@ int mhi_process_data_event_ring(struct mhi_controller *mhi_cntrl, int count = 0; u32 chan; struct mhi_chan *mhi_chan; + dma_addr_t ptr = er_ctxt->rp; if (unlikely(MHI_EVENT_ACCESS_INVALID(mhi_cntrl->pm_state))) return -EIO; - dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); + if (!is_valid_ring_ptr(ev_ring, ptr)) { + dev_err(&mhi_cntrl->mhi_dev->dev, + "Event ring rp points outside of the event ring\n"); + return -EIO; + } + + dev_rp = mhi_to_virtual(ev_ring, ptr); local_rp = ev_ring->rp; while (dev_rp != local_rp && event_quota > 0) { @@ -939,7 +988,8 @@ int mhi_process_data_event_ring(struct mhi_controller *mhi_cntrl, * Only process the event ring elements whose channel * ID is within the maximum supported range. */ - if (chan < mhi_cntrl->max_chan) { + if (chan < mhi_cntrl->max_chan && + mhi_cntrl->mhi_chan[chan].configured) { mhi_chan = &mhi_cntrl->mhi_chan[chan]; if (likely(type == MHI_PKT_TYPE_TX_EVENT)) { @@ -953,7 +1003,15 @@ int mhi_process_data_event_ring(struct mhi_controller *mhi_cntrl, mhi_recycle_ev_ring_element(mhi_cntrl, ev_ring); local_rp = ev_ring->rp; - dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); + + ptr = er_ctxt->rp; + if (!is_valid_ring_ptr(ev_ring, ptr)) { + dev_err(&mhi_cntrl->mhi_dev->dev, + "Event ring rp points outside of the event ring\n"); + return -EIO; + } + + dev_rp = mhi_to_virtual(ev_ring, ptr); count++; } read_lock_bh(&mhi_cntrl->pm_lock); @@ -1455,6 +1513,7 @@ static void mhi_mark_stale_events(struct mhi_controller *mhi_cntrl, struct mhi_ring *ev_ring; struct device *dev = &mhi_cntrl->mhi_dev->dev; unsigned long flags; + dma_addr_t ptr; dev_dbg(dev, "Marking all events for chan: %d as stale\n", chan); @@ -1462,7 +1521,15 @@ static void mhi_mark_stale_events(struct mhi_controller *mhi_cntrl, /* mark all stale events related to channel as STALE event */ spin_lock_irqsave(&mhi_event->lock, flags); - dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); + + ptr = er_ctxt->rp; + if (!is_valid_ring_ptr(ev_ring, ptr)) { + dev_err(&mhi_cntrl->mhi_dev->dev, + "Event ring rp points outside of the event ring\n"); + dev_rp = ev_ring->rp; + } else { + dev_rp = mhi_to_virtual(ev_ring, ptr); + } local_rp = ev_ring->rp; while (dev_rp != local_rp) { -- cgit v1.2.3 From aac426562f568520b674f0d5ae3929977be9f1c0 Mon Sep 17 00:00:00 2001 From: Jarvis Jiang Date: Thu, 8 Apr 2021 02:55:24 -0700 Subject: bus: mhi: pci_generic: Introduce Foxconn T99W175 support Add support for T99W175 modems, this modem series is based on SDX55 qcom chip. The modem is mainly based on MBIM protocol for both the data and control path. This patch adds support for below modems: - T99W175(based on sdx55), Both for eSIM and Non-eSIM - DW5930e(based on sdx55), With eSIM, It's also T99W175 - DW5930e(based on sdx55), Non-eSIM, It's also T99W175 This patch was tested with Ubuntu 20.04 X86_64 PC as host Signed-off-by: Jarvis Jiang Reviewed-by: Loic Poulain Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20210408095524.3559-1-jarvis.w.jiang@gmail.com Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/pci_generic.c | 47 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/drivers/bus/mhi/pci_generic.c b/drivers/bus/mhi/pci_generic.c index aa8f8d541371..8f715519ba08 100644 --- a/drivers/bus/mhi/pci_generic.c +++ b/drivers/bus/mhi/pci_generic.c @@ -304,6 +304,44 @@ static const struct mhi_pci_dev_info mhi_quectel_em1xx_info = { .dma_data_width = 32 }; +static const struct mhi_channel_config mhi_foxconn_sdx55_channels[] = { + MHI_CHANNEL_CONFIG_UL(0, "LOOPBACK", 32, 0), + MHI_CHANNEL_CONFIG_DL(1, "LOOPBACK", 32, 0), + MHI_CHANNEL_CONFIG_UL(4, "DIAG", 32, 1), + MHI_CHANNEL_CONFIG_DL(5, "DIAG", 32, 1), + MHI_CHANNEL_CONFIG_UL(12, "MBIM", 32, 0), + MHI_CHANNEL_CONFIG_DL(13, "MBIM", 32, 0), + MHI_CHANNEL_CONFIG_UL(32, "AT", 32, 0), + MHI_CHANNEL_CONFIG_DL(33, "AT", 32, 0), + MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0_MBIM", 128, 2), + MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0_MBIM", 128, 3), +}; + +static struct mhi_event_config mhi_foxconn_sdx55_events[] = { + MHI_EVENT_CONFIG_CTRL(0, 128), + MHI_EVENT_CONFIG_DATA(1, 128), + MHI_EVENT_CONFIG_HW_DATA(2, 1024, 100), + MHI_EVENT_CONFIG_HW_DATA(3, 1024, 101) +}; + +static struct mhi_controller_config modem_foxconn_sdx55_config = { + .max_channels = 128, + .timeout_ms = 20000, + .num_channels = ARRAY_SIZE(mhi_foxconn_sdx55_channels), + .ch_cfg = mhi_foxconn_sdx55_channels, + .num_events = ARRAY_SIZE(mhi_foxconn_sdx55_events), + .event_cfg = mhi_foxconn_sdx55_events, +}; + +static const struct mhi_pci_dev_info mhi_foxconn_sdx55_info = { + .name = "foxconn-sdx55", + .fw = "qcom/sdx55m/sbl1.mbn", + .edl = "qcom/sdx55m/edl.mbn", + .config = &modem_foxconn_sdx55_config, + .bar_num = MHI_PCI_DEFAULT_BAR_NUM, + .dma_data_width = 32 +}; + static const struct pci_device_id mhi_pci_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0306), .driver_data = (kernel_ulong_t) &mhi_qcom_sdx55_info }, @@ -315,6 +353,15 @@ static const struct pci_device_id mhi_pci_id_table[] = { .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0308), .driver_data = (kernel_ulong_t) &mhi_qcom_sdx65_info }, + /* T99W175 (sdx55), Both for eSIM and Non-eSIM */ + { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0ab), + .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info }, + /* DW5930e (sdx55), With eSIM, It's also T99W175 */ + { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0b0), + .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info }, + /* DW5930e (sdx55), Non-eSIM, It's also T99W175 */ + { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0b1), + .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info }, { } }; MODULE_DEVICE_TABLE(pci, mhi_pci_id_table); -- cgit v1.2.3 From 5630c1009bd960c37ddb3c80055668f59fbeabcb Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 8 Apr 2021 19:15:29 +0530 Subject: bus: mhi: pci_generic: Constify mhi_controller_config struct definitions "mhi_controller_config" struct is not modified inside "mhi_pci_dev_info" struct. So constify the instances. Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/pci_generic.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/bus/mhi/pci_generic.c b/drivers/bus/mhi/pci_generic.c index 8f715519ba08..7c810f02a2ef 100644 --- a/drivers/bus/mhi/pci_generic.c +++ b/drivers/bus/mhi/pci_generic.c @@ -227,7 +227,7 @@ static struct mhi_event_config modem_qcom_v1_mhi_events[] = { MHI_EVENT_CONFIG_HW_DATA(3, 2048, 101) }; -static struct mhi_controller_config modem_qcom_v1_mhiv_config = { +static const struct mhi_controller_config modem_qcom_v1_mhiv_config = { .max_channels = 128, .timeout_ms = 8000, .num_channels = ARRAY_SIZE(modem_qcom_v1_mhi_channels), @@ -287,7 +287,7 @@ static struct mhi_event_config mhi_quectel_em1xx_events[] = { MHI_EVENT_CONFIG_HW_DATA(3, 1024, 101) }; -static struct mhi_controller_config modem_quectel_em1xx_config = { +static const struct mhi_controller_config modem_quectel_em1xx_config = { .max_channels = 128, .timeout_ms = 20000, .num_channels = ARRAY_SIZE(mhi_quectel_em1xx_channels), @@ -324,7 +324,7 @@ static struct mhi_event_config mhi_foxconn_sdx55_events[] = { MHI_EVENT_CONFIG_HW_DATA(3, 1024, 101) }; -static struct mhi_controller_config modem_foxconn_sdx55_config = { +static const struct mhi_controller_config modem_foxconn_sdx55_config = { .max_channels = 128, .timeout_ms = 20000, .num_channels = ARRAY_SIZE(mhi_foxconn_sdx55_channels), -- cgit v1.2.3 From 683e77cadc839b39cd712c18dbb317cae49357c0 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Fri, 9 Apr 2021 10:11:05 +0530 Subject: bus: mhi: core: Fix shadow declarations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixes below sparse warnings with W=2 about shadow declarations: drivers/bus/mhi/core/main.c: In function ‘parse_xfer_event’: drivers/bus/mhi/core/main.c:667:17: warning: declaration of ‘flags’ shadows a previous local [-Wshadow] 667 | unsigned long flags; | ^~~~~ drivers/bus/mhi/core/main.c:565:16: note: shadowed declaration is here 565 | unsigned long flags = 0; | ^~~~~ drivers/bus/mhi/core/main.c: In function ‘mhi_process_ctrl_ev_ring’: drivers/bus/mhi/core/main.c:856:23: warning: declaration of ‘new_state’ shadows a previous local [-Wshadow] 856 | enum mhi_pm_state new_state; | ^~~~~~~~~ drivers/bus/mhi/core/main.c:837:19: note: shadowed declaration is here 837 | enum mhi_state new_state; | ^~~~~~~~~ Signed-off-by: Manivannan Sadhasivam --- drivers/bus/mhi/core/main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index b0c8afe16e3a..22acde118bc3 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -664,15 +664,15 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl, case MHI_EV_CC_OOB: case MHI_EV_CC_DB_MODE: { - unsigned long flags; + unsigned long pm_lock_flags; mhi_chan->db_cfg.db_mode = 1; - read_lock_irqsave(&mhi_cntrl->pm_lock, flags); + read_lock_irqsave(&mhi_cntrl->pm_lock, pm_lock_flags); if (tre_ring->wp != tre_ring->rp && MHI_DB_ACCESS_VALID(mhi_cntrl)) { mhi_ring_chan_db(mhi_cntrl, mhi_chan); } - read_unlock_irqrestore(&mhi_cntrl->pm_lock, flags); + read_unlock_irqrestore(&mhi_cntrl->pm_lock, pm_lock_flags); break; } case MHI_EV_CC_BAD_TRE: @@ -853,14 +853,14 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, break; case MHI_STATE_SYS_ERR: { - enum mhi_pm_state new_state; + enum mhi_pm_state pm_state; dev_dbg(dev, "System error detected\n"); write_lock_irq(&mhi_cntrl->pm_lock); - new_state = mhi_tryset_pm_state(mhi_cntrl, + pm_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_SYS_ERR_DETECT); write_unlock_irq(&mhi_cntrl->pm_lock); - if (new_state == MHI_PM_SYS_ERR_DETECT) + if (pm_state == MHI_PM_SYS_ERR_DETECT) mhi_pm_sys_err_handler(mhi_cntrl); break; } -- cgit v1.2.3 From b6821b3c65c80f11f92f1abb27be2ad9683acefc Mon Sep 17 00:00:00 2001 From: farah kassabri Date: Sun, 7 Feb 2021 12:34:52 +0200 Subject: habanalabs: set max asid to 2 currently we support only 2 asids in all asics. asid 0 for driver, and asic 1 for user. no need to setup 1024 asids configurations at init phase. Signed-off-by: farah kassabri Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/include/gaudi/gaudi.h | 2 +- drivers/misc/habanalabs/include/goya/goya.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi.h b/drivers/misc/habanalabs/include/gaudi/gaudi.h index f9ea897ae42c..ffae107b1693 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi.h @@ -38,7 +38,7 @@ #define QMAN_PQ_ENTRY_SIZE 16 /* Bytes */ -#define MAX_ASID 1024 +#define MAX_ASID 2 #define PROT_BITS_OFFS 0xF80 diff --git a/drivers/misc/habanalabs/include/goya/goya.h b/drivers/misc/habanalabs/include/goya/goya.h index 43d241891e45..1b4ca435021d 100644 --- a/drivers/misc/habanalabs/include/goya/goya.h +++ b/drivers/misc/habanalabs/include/goya/goya.h @@ -30,7 +30,7 @@ #define QMAN_PQ_ENTRY_SIZE 16 /* Bytes */ -#define MAX_ASID 1024 +#define MAX_ASID 2 #define PROT_BITS_OFFS 0xF80 -- cgit v1.2.3 From 8e9445a678cab4478aa90a5f8898ba093371e30f Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Wed, 10 Feb 2021 14:29:33 +0200 Subject: habanalabs: add reset support when user closes FD In order to support command submissions that are done directly from user space, the driver must perform soft reset once user closes its FD. In case the soft reset fails or device is not idle, a hard reset should be performed. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/device.c | 20 ++++++++++++++++++-- drivers/misc/habanalabs/common/habanalabs.h | 2 ++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index 334009e83823..c74bdf4ae6aa 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -103,8 +103,24 @@ static int hl_device_release(struct inode *inode, struct file *filp) return 0; } - hl_cb_mgr_fini(hpriv->hdev, &hpriv->cb_mgr); - hl_ctx_mgr_fini(hpriv->hdev, &hpriv->ctx_mgr); + hl_cb_mgr_fini(hdev, &hpriv->cb_mgr); + hl_ctx_mgr_fini(hdev, &hpriv->ctx_mgr); + + if (hdev->reset_upon_device_release) { + u64 idle_mask[HL_BUSY_ENGINES_MASK_EXT_SIZE] = {0}; + + /* We try soft reset first */ + hl_device_reset(hdev, false, false); + + /* If device is not idle perform hard reset */ + if (!hdev->asic_funcs->is_device_idle(hdev, idle_mask, + HL_BUSY_ENGINES_MASK_EXT_SIZE, NULL)) { + dev_info(hdev->dev, + "device is not idle (mask %#llx %#llx) after soft reset, performing hard reset", + idle_mask[0], idle_mask[1]); + hl_device_reset(hdev, true, false); + } + } hl_hpriv_put(hpriv); diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 4b321e4f8059..4fdb4fa5728d 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -1920,6 +1920,7 @@ struct hl_mmu_funcs { * @device_fini_pending: true if device_fini was called and might be * waiting for the reset thread to finish * @supports_staged_submission: true if staged submissions are supported + * @reset_upon_device_release: true if reset is required upon device release */ struct hl_device { struct pci_dev *pdev; @@ -2026,6 +2027,7 @@ struct hl_device { u8 process_kill_trial_cnt; u8 device_fini_pending; u8 supports_staged_submission; + u8 reset_upon_device_release; /* Parameters for bring-up */ u64 nic_ports_mask; -- cgit v1.2.3 From 35862d1c99471e3a03175e94d267815a0921e9ca Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Tue, 16 Feb 2021 22:34:24 +0200 Subject: habanalabs: reset after device is actually released The device is actually released only after the refcnt of the hpriv structure is 0, which means all its contexts were closed. If we reset the device while a context is still open, there are possibilities for unexpected behavior and crashes. For example, if the process has a mapping of a register block that is now currently being reset, and the process writes/reads to that block during the reset, the device can get stuck. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/device.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index c74bdf4ae6aa..cba23e5f1bb3 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -70,6 +70,22 @@ static void hpriv_release(struct kref *ref) mutex_unlock(&hdev->fpriv_list_lock); kfree(hpriv); + + if (hdev->reset_upon_device_release) { + u64 idle_mask[HL_BUSY_ENGINES_MASK_EXT_SIZE] = {0}; + + /* We try soft reset first */ + hl_device_reset(hdev, false, false); + + /* If device is not idle perform hard reset */ + if (!hdev->asic_funcs->is_device_idle(hdev, idle_mask, + HL_BUSY_ENGINES_MASK_EXT_SIZE, NULL)) { + dev_info(hdev->dev, + "device is not idle (mask %#llx %#llx) after soft reset, performing hard reset", + idle_mask[0], idle_mask[1]); + hl_device_reset(hdev, true, false); + } + } } void hl_hpriv_get(struct hl_fpriv *hpriv) @@ -106,22 +122,6 @@ static int hl_device_release(struct inode *inode, struct file *filp) hl_cb_mgr_fini(hdev, &hpriv->cb_mgr); hl_ctx_mgr_fini(hdev, &hpriv->ctx_mgr); - if (hdev->reset_upon_device_release) { - u64 idle_mask[HL_BUSY_ENGINES_MASK_EXT_SIZE] = {0}; - - /* We try soft reset first */ - hl_device_reset(hdev, false, false); - - /* If device is not idle perform hard reset */ - if (!hdev->asic_funcs->is_device_idle(hdev, idle_mask, - HL_BUSY_ENGINES_MASK_EXT_SIZE, NULL)) { - dev_info(hdev->dev, - "device is not idle (mask %#llx %#llx) after soft reset, performing hard reset", - idle_mask[0], idle_mask[1]); - hl_device_reset(hdev, true, false); - } - } - hl_hpriv_put(hpriv); return 0; -- cgit v1.2.3 From 23c3efd1fb0eb19b9e39eeb07515b167f6d4517a Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Tue, 16 Feb 2021 22:46:17 +0200 Subject: habanalabs: fail reset if device is not idle After any reset (soft or hard) the device (the engines/QMANs) should be idle. If they are not idle, fail the reset. If it is soft-reset, the driver will try to do hard-reset automatically. If it is hard-reset, the driver will make the device non-operational. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/device.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index cba23e5f1bb3..1d18c41d331a 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -71,21 +71,8 @@ static void hpriv_release(struct kref *ref) kfree(hpriv); - if (hdev->reset_upon_device_release) { - u64 idle_mask[HL_BUSY_ENGINES_MASK_EXT_SIZE] = {0}; - - /* We try soft reset first */ + if (hdev->reset_upon_device_release) hl_device_reset(hdev, false, false); - - /* If device is not idle perform hard reset */ - if (!hdev->asic_funcs->is_device_idle(hdev, idle_mask, - HL_BUSY_ENGINES_MASK_EXT_SIZE, NULL)) { - dev_info(hdev->dev, - "device is not idle (mask %#llx %#llx) after soft reset, performing hard reset", - idle_mask[0], idle_mask[1]); - hl_device_reset(hdev, true, false); - } - } } void hl_hpriv_get(struct hl_fpriv *hpriv) @@ -948,6 +935,7 @@ static void device_disable_open_processes(struct hl_device *hdev) int hl_device_reset(struct hl_device *hdev, bool hard_reset, bool from_hard_reset_thread) { + u64 idle_mask[HL_BUSY_ENGINES_MASK_EXT_SIZE] = {0}; int i, rc; if (!hdev->init_done) { @@ -1167,6 +1155,16 @@ kill_processes: goto out_err; } + /* If device is not idle fail the reset process */ + if (!hdev->asic_funcs->is_device_idle(hdev, idle_mask, + HL_BUSY_ENGINES_MASK_EXT_SIZE, NULL)) { + dev_err(hdev->dev, + "device is not idle (mask %#llx %#llx) after reset\n", + idle_mask[0], idle_mask[1]); + rc = -EIO; + goto out_err; + } + /* Check that the communication with the device is working */ rc = hdev->asic_funcs->test_queues(hdev); if (rc) { -- cgit v1.2.3 From d3ee681afd7dcf62b592d343d8091c0361efc07a Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Tue, 16 Feb 2021 22:49:27 +0200 Subject: habanalabs: reset_upon_device_release is for bring-up Move the field to correct location in structure and remove comment. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/habanalabs.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 4fdb4fa5728d..51a6b911bb2e 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -1920,7 +1920,6 @@ struct hl_mmu_funcs { * @device_fini_pending: true if device_fini was called and might be * waiting for the reset thread to finish * @supports_staged_submission: true if staged submissions are supported - * @reset_upon_device_release: true if reset is required upon device release */ struct hl_device { struct pci_dev *pdev; @@ -2027,7 +2026,6 @@ struct hl_device { u8 process_kill_trial_cnt; u8 device_fini_pending; u8 supports_staged_submission; - u8 reset_upon_device_release; /* Parameters for bring-up */ u64 nic_ports_mask; @@ -2045,6 +2043,7 @@ struct hl_device { u8 bmc_enable; u8 rl_enable; u8 reset_on_preboot_fail; + u8 reset_upon_device_release; }; -- cgit v1.2.3 From 278b5f7acbe1ae299aae8b9669a3e67d5a2635ff Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Thu, 18 Feb 2021 10:24:02 +0200 Subject: habanalabs: print if device is used on FD close Notify to the user that although he closed the FD, the device is still in use because there are live CS and/or memory mappings (mmaps). Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/device.c | 8 +++++--- drivers/misc/habanalabs/common/habanalabs.h | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index 1d18c41d331a..17e9e205557b 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -80,9 +80,9 @@ void hl_hpriv_get(struct hl_fpriv *hpriv) kref_get(&hpriv->refcount); } -void hl_hpriv_put(struct hl_fpriv *hpriv) +int hl_hpriv_put(struct hl_fpriv *hpriv) { - kref_put(&hpriv->refcount, hpriv_release); + return kref_put(&hpriv->refcount, hpriv_release); } /* @@ -109,7 +109,9 @@ static int hl_device_release(struct inode *inode, struct file *filp) hl_cb_mgr_fini(hdev, &hpriv->cb_mgr); hl_ctx_mgr_fini(hdev, &hpriv->ctx_mgr); - hl_hpriv_put(hpriv); + if (!hl_hpriv_put(hpriv)) + dev_warn(hdev->dev, + "Device is still in use because there are live CS and/or memory mappings\n"); return 0; } diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 51a6b911bb2e..8eb22f0e459c 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -2182,7 +2182,7 @@ int hl_device_resume(struct hl_device *hdev); int hl_device_reset(struct hl_device *hdev, bool hard_reset, bool from_hard_reset_thread); void hl_hpriv_get(struct hl_fpriv *hpriv); -void hl_hpriv_put(struct hl_fpriv *hpriv); +int hl_hpriv_put(struct hl_fpriv *hpriv); int hl_device_set_frequency(struct hl_device *hdev, enum hl_pll_frequency freq); uint32_t hl_device_utilization(struct hl_device *hdev, uint32_t period_ms); -- cgit v1.2.3 From 17b59dd3399c45d8e96dcc2c7d1761231dc638b6 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Wed, 17 Feb 2021 13:34:44 +0200 Subject: habanalabs: change default CS timeout to 30 seconds Because our graph contains network operations, we need to account for delay in the network. 5 seconds timeout per CS is not enough to account for that. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/habanalabs_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/habanalabs/common/habanalabs_drv.c b/drivers/misc/habanalabs/common/habanalabs_drv.c index 032d114f01ea..f695ea6253c1 100644 --- a/drivers/misc/habanalabs/common/habanalabs_drv.c +++ b/drivers/misc/habanalabs/common/habanalabs_drv.c @@ -27,13 +27,13 @@ static struct class *hl_class; static DEFINE_IDR(hl_devs_idr); static DEFINE_MUTEX(hl_devs_idr_lock); -static int timeout_locked = 5; +static int timeout_locked = 30; static int reset_on_lockup = 1; static int memory_scrub = 1; module_param(timeout_locked, int, 0444); MODULE_PARM_DESC(timeout_locked, - "Device lockup timeout in seconds (0 = disabled, default 5s)"); + "Device lockup timeout in seconds (0 = disabled, default 30s)"); module_param(reset_on_lockup, int, 0444); MODULE_PARM_DESC(reset_on_lockup, -- cgit v1.2.3 From 5d6a198f9dba12c78f82a0436d64bd683c031b13 Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Mon, 8 Feb 2021 14:53:56 +0200 Subject: habanalabs: reset device in case of sync error As the F/wW is the first to detect out of sync event, a new event is added to notify the driver on such event. In which case the driver performs hard reset. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 18 +++++++++++++++++ drivers/misc/habanalabs/goya/goya.c | 23 ++++++++++++++++++++++ drivers/misc/habanalabs/include/common/cpucp_if.h | 9 +++++++++ .../habanalabs/include/gaudi/gaudi_async_events.h | 1 + .../habanalabs/include/goya/goya_async_events.h | 1 + 5 files changed, 52 insertions(+) diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 9152242778f5..c1f00237273c 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -7097,6 +7097,15 @@ static void gaudi_print_irq_info(struct hl_device *hdev, u16 event_type, } } +static void gaudi_print_out_of_sync_info(struct hl_device *hdev, + struct cpucp_pkt_sync_err *sync_err) +{ + struct hl_hw_queue *q = &hdev->kernel_queues[GAUDI_QUEUE_ID_CPU_PQ]; + + dev_err(hdev->dev, "Out of sync with FW, FW: pi=%u, ci=%u, LKD: pi=%u, ci=%u\n", + sync_err->pi, sync_err->ci, q->pi, atomic_read(&q->ci)); +} + static int gaudi_soft_reset_late_init(struct hl_device *hdev) { struct gaudi_device *gaudi = hdev->asic_specific; @@ -7552,6 +7561,15 @@ static void gaudi_handle_eqe(struct hl_device *hdev, event_type, cause); break; + case GAUDI_EVENT_PKT_QUEUE_OUT_SYNC: + gaudi_print_irq_info(hdev, event_type, false); + gaudi_print_out_of_sync_info(hdev, &eq_entry->pkt_sync_err); + if (hdev->hard_reset_on_fw_events) + hl_device_reset(hdev, true, false); + else + hl_fw_unmask_irq(hdev, event_type); + break; + default: dev_err(hdev->dev, "Received invalid H/W interrupt %d\n", event_type); diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index ed566c52ccaa..a40c428fed94 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -4401,6 +4401,8 @@ static const char *_goya_get_event_desc(u16 event_type) return "THERMAL_ENV_S"; case GOYA_ASYNC_EVENT_ID_FIX_THERMAL_ENV_E: return "THERMAL_ENV_E"; + case GOYA_ASYNC_EVENT_PKT_QUEUE_OUT_SYNC: + return "QUEUE_OUT_OF_SYNC"; default: return "N/A"; } @@ -4483,6 +4485,9 @@ static void goya_get_event_desc(u16 event_type, char *desc, size_t size) index = event_type - GOYA_ASYNC_EVENT_ID_DMA_BM_CH0; snprintf(desc, size, _goya_get_event_desc(event_type), index); break; + case GOYA_ASYNC_EVENT_PKT_QUEUE_OUT_SYNC: + snprintf(desc, size, _goya_get_event_desc(event_type)); + break; default: snprintf(desc, size, _goya_get_event_desc(event_type)); break; @@ -4534,6 +4539,15 @@ static void goya_print_mmu_error_info(struct hl_device *hdev) } } +static void goya_print_out_of_sync_info(struct hl_device *hdev, + struct cpucp_pkt_sync_err *sync_err) +{ + struct hl_hw_queue *q = &hdev->kernel_queues[GOYA_QUEUE_ID_CPU_PQ]; + + dev_err(hdev->dev, "Out of sync with FW, FW: pi=%u, ci=%u, LKD: pi=%u, ci=%u\n", + sync_err->pi, sync_err->ci, q->pi, atomic_read(&q->ci)); +} + static void goya_print_irq_info(struct hl_device *hdev, u16 event_type, bool razwi) { @@ -4754,6 +4768,15 @@ void goya_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entry) goya_unmask_irq(hdev, event_type); break; + case GOYA_ASYNC_EVENT_PKT_QUEUE_OUT_SYNC: + goya_print_irq_info(hdev, event_type, false); + goya_print_out_of_sync_info(hdev, &eq_entry->pkt_sync_err); + if (hdev->hard_reset_on_fw_events) + hl_device_reset(hdev, true, false); + else + hl_fw_unmask_irq(hdev, event_type); + break; + default: dev_err(hdev->dev, "Received invalid H/W interrupt %d\n", event_type); diff --git a/drivers/misc/habanalabs/include/common/cpucp_if.h b/drivers/misc/habanalabs/include/common/cpucp_if.h index b77c1c16c32c..bf4e7900d8c8 100644 --- a/drivers/misc/habanalabs/include/common/cpucp_if.h +++ b/drivers/misc/habanalabs/include/common/cpucp_if.h @@ -28,6 +28,14 @@ #define CPUCP_PKT_HBM_ECC_INFO_HBM_CH_SHIFT 6 #define CPUCP_PKT_HBM_ECC_INFO_HBM_CH_MASK 0x000007C0 +/* + * info of the pkt queue pointers in the first async occurrence + */ +struct cpucp_pkt_sync_err { + __le32 pi; + __le32 ci; +}; + struct hl_eq_hbm_ecc_data { /* SERR counter */ __le32 sec_cnt; @@ -77,6 +85,7 @@ struct hl_eq_entry { struct hl_eq_ecc_data ecc_data; struct hl_eq_hbm_ecc_data hbm_ecc_data; struct hl_eq_sm_sei_data sm_sei_data; + struct cpucp_pkt_sync_err pkt_sync_err; __le64 data[7]; }; }; diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h b/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h index 49335e8334b4..0a0fa57024f8 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h @@ -303,6 +303,7 @@ enum gaudi_async_event_id { GAUDI_EVENT_NIC3_QP1 = 619, GAUDI_EVENT_NIC4_QP0 = 620, GAUDI_EVENT_NIC4_QP1 = 621, + GAUDI_EVENT_PKT_QUEUE_OUT_SYNC = 647, GAUDI_EVENT_FIX_POWER_ENV_S = 658, GAUDI_EVENT_FIX_POWER_ENV_E = 659, GAUDI_EVENT_FIX_THERMAL_ENV_S = 660, diff --git a/drivers/misc/habanalabs/include/goya/goya_async_events.h b/drivers/misc/habanalabs/include/goya/goya_async_events.h index 5fb92362fc5f..09081401cb1d 100644 --- a/drivers/misc/habanalabs/include/goya/goya_async_events.h +++ b/drivers/misc/habanalabs/include/goya/goya_async_events.h @@ -188,6 +188,7 @@ enum goya_async_event_id { GOYA_ASYNC_EVENT_ID_HALT_MACHINE = 485, GOYA_ASYNC_EVENT_ID_INTS_REGISTER = 486, GOYA_ASYNC_EVENT_ID_SOFT_RESET = 487, + GOYA_ASYNC_EVENT_PKT_QUEUE_OUT_SYNC = 506, GOYA_ASYNC_EVENT_ID_FIX_POWER_ENV_S = 507, GOYA_ASYNC_EVENT_ID_FIX_POWER_ENV_E = 508, GOYA_ASYNC_EVENT_ID_FIX_THERMAL_ENV_S = 509, -- cgit v1.2.3 From 2d44c6f6b3a10c1d82d667b92a39621c3753b229 Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Tue, 12 Jan 2021 14:43:09 +0200 Subject: habanalabs: enable all IRQs for user interrupt support In order to support user interrupts, driver must enable all MSI-X interrupts for any case user will trigger them. We differentiate between a valid user interrupt and a non valid one. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/device.c | 20 +++++++++++++-- drivers/misc/habanalabs/common/habanalabs.h | 16 ++++++++++++ drivers/misc/habanalabs/common/irq.c | 40 +++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index 17e9e205557b..24e3ea15b2b9 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -1251,7 +1251,7 @@ out_err: */ int hl_device_init(struct hl_device *hdev, struct class *hclass) { - int i, rc, cq_cnt, cq_ready_cnt; + int i, rc, cq_cnt, user_interrupt_cnt, cq_ready_cnt; char *name; bool add_cdev_sysfs_on_err = false; @@ -1340,6 +1340,19 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass) hdev->completion_queue[i].cq_idx = i; } + user_interrupt_cnt = hdev->asic_prop.user_interrupt_count; + + if (user_interrupt_cnt) { + hdev->user_interrupt = kcalloc(user_interrupt_cnt, + sizeof(*hdev->user_interrupt), + GFP_KERNEL); + + if (!hdev->user_interrupt) { + rc = -ENOMEM; + goto cq_fini; + } + } + /* * Initialize the event queue. Must be done before hw_init, * because there the address of the event queue is being @@ -1348,7 +1361,7 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass) rc = hl_eq_init(hdev, &hdev->event_queue); if (rc) { dev_err(hdev->dev, "failed to initialize event queue\n"); - goto cq_fini; + goto user_interrupts_fini; } /* MMU S/W must be initialized before kernel context is created */ @@ -1486,6 +1499,8 @@ mmu_fini: hl_mmu_fini(hdev); eq_fini: hl_eq_fini(hdev, &hdev->event_queue); +user_interrupts_fini: + kfree(hdev->user_interrupt); cq_fini: for (i = 0 ; i < cq_ready_cnt ; i++) hl_cq_fini(hdev, &hdev->completion_queue[i]); @@ -1625,6 +1640,7 @@ void hl_device_fini(struct hl_device *hdev) for (i = 0 ; i < hdev->asic_prop.completion_queues_count ; i++) hl_cq_fini(hdev, &hdev->completion_queue[i]); kfree(hdev->completion_queue); + kfree(hdev->user_interrupt); hl_hw_queues_destroy(hdev); diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 8eb22f0e459c..7ffd4b84ae90 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -412,6 +412,7 @@ struct hl_mmu_properties { * @first_available_user_msix_interrupt: first available msix interrupt * reserved for the user * @first_available_cq: first available CQ for the user. + * @user_interrupt_count: number of user interrupts. * @tpc_enabled_mask: which TPCs are enabled. * @completion_queues_count: number of completion queues. * @fw_security_disabled: true if security measures are disabled in firmware, @@ -475,6 +476,7 @@ struct asic_fixed_properties { u16 first_available_user_mon[HL_MAX_DCORES]; u16 first_available_user_msix_interrupt; u16 first_available_cq[HL_MAX_DCORES]; + u16 user_interrupt_count; u8 tpc_enabled_mask; u8 completion_queues_count; u8 fw_security_disabled; @@ -689,6 +691,16 @@ struct hl_cq { atomic_t free_slots_cnt; }; +/** + * struct hl_user_interrupt - holds user interrupt information + * @hdev: pointer to the device structure + * @interrupt_id: msix interrupt id + */ +struct hl_user_interrupt { + struct hl_device *hdev; + u32 interrupt_id; +}; + /** * struct hl_eq - describes the event queue (single one per device) * @hdev: pointer to the device structure @@ -1821,6 +1833,7 @@ struct hl_mmu_funcs { * @asic_name: ASIC specific name. * @asic_type: ASIC specific type. * @completion_queue: array of hl_cq. + * @user_interrupt: array of hl_user_interrupt. * @cq_wq: work queues of completion queues for executing work in process * context. * @eq_wq: work queue of event queue for executing work in process context. @@ -1937,6 +1950,7 @@ struct hl_device { char status[HL_DEV_STS_MAX][HL_STR_MAX]; enum hl_asic_type asic_type; struct hl_cq *completion_queue; + struct hl_user_interrupt *user_interrupt; struct workqueue_struct **cq_wq; struct workqueue_struct *eq_wq; struct hl_ctx *kernel_ctx; @@ -2158,6 +2172,8 @@ void hl_cq_reset(struct hl_device *hdev, struct hl_cq *q); void hl_eq_reset(struct hl_device *hdev, struct hl_eq *q); irqreturn_t hl_irq_handler_cq(int irq, void *arg); irqreturn_t hl_irq_handler_eq(int irq, void *arg); +irqreturn_t hl_irq_handler_user_cq(int irq, void *arg); +irqreturn_t hl_irq_handler_default(int irq, void *arg); u32 hl_cq_inc_ptr(u32 ptr); int hl_asid_init(struct hl_device *hdev); diff --git a/drivers/misc/habanalabs/common/irq.c b/drivers/misc/habanalabs/common/irq.c index 44a0522b59b9..c8b5dc07e6ca 100644 --- a/drivers/misc/habanalabs/common/irq.c +++ b/drivers/misc/habanalabs/common/irq.c @@ -137,6 +137,46 @@ irqreturn_t hl_irq_handler_cq(int irq, void *arg) return IRQ_HANDLED; } +/** + * hl_irq_handler_user_cq - irq handler for user completion queues + * + * @irq: irq number + * @arg: pointer to user interrupt structure + * + */ +irqreturn_t hl_irq_handler_user_cq(int irq, void *arg) +{ + struct hl_user_interrupt *user_cq = arg; + struct hl_device *hdev = user_cq->hdev; + u32 interrupt_id = user_cq->interrupt_id; + + dev_info(hdev->dev, + "got user completion interrupt id %u", + interrupt_id); + + return IRQ_HANDLED; +} + +/** + * hl_irq_handler_default - default irq handler + * + * @irq: irq number + * @arg: pointer to user interrupt structure + * + */ +irqreturn_t hl_irq_handler_default(int irq, void *arg) +{ + struct hl_user_interrupt *user_interrupt = arg; + struct hl_device *hdev = user_interrupt->hdev; + u32 interrupt_id = user_interrupt->interrupt_id; + + dev_err(hdev->dev, + "got invalid user interrupt %u", + interrupt_id); + + return IRQ_HANDLED; +} + /** * hl_irq_handler_eq - irq handler for event queue * -- cgit v1.2.3 From ab5f5c3089a2c9b863ad0b67e89f168ec7e8f7e5 Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Tue, 12 Jan 2021 18:37:19 +0200 Subject: habanalabs: wait for interrupt support In order to support command submissions from user space, the driver need to add support for user interrupt completions. The driver will allow multiple user threads to wait for an interrupt and perform a comparison with a given user address once interrupt expires. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- .../misc/habanalabs/common/command_submission.c | 213 ++++++++++++++++++++- drivers/misc/habanalabs/common/device.c | 44 +++-- drivers/misc/habanalabs/common/habanalabs.h | 28 ++- drivers/misc/habanalabs/common/habanalabs_ioctl.c | 2 +- drivers/misc/habanalabs/common/irq.c | 22 ++- include/uapi/misc/habanalabs.h | 42 +++- 6 files changed, 322 insertions(+), 29 deletions(-) diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index 7bd4a03b3429..4e6b4cf23181 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -778,6 +778,44 @@ void hl_pending_cb_list_flush(struct hl_ctx *ctx) } } +static void +wake_pending_user_interrupt_threads(struct hl_user_interrupt *interrupt) +{ + struct hl_user_pending_interrupt *pend; + + spin_lock(&interrupt->wait_list_lock); + list_for_each_entry(pend, &interrupt->wait_list_head, wait_list_node) { + pend->fence.error = -EIO; + complete_all(&pend->fence.completion); + } + spin_unlock(&interrupt->wait_list_lock); +} + +void hl_release_pending_user_interrupts(struct hl_device *hdev) +{ + struct asic_fixed_properties *prop = &hdev->asic_prop; + struct hl_user_interrupt *interrupt; + int i; + + if (!prop->user_interrupt_count) + return; + + /* We iterate through the user interrupt requests and waking up all + * user threads waiting for interrupt completion. We iterate the + * list under a lock, this is why all user threads, once awake, + * will wait on the same lock and will release the waiting object upon + * unlock. + */ + + for (i = 0 ; i < prop->user_interrupt_count ; i++) { + interrupt = &hdev->user_interrupt[i]; + wake_pending_user_interrupt_threads(interrupt); + } + + interrupt = &hdev->common_user_interrupt; + wake_pending_user_interrupt_threads(interrupt); +} + static void job_wq_completion(struct work_struct *work) { struct hl_cs_job *job = container_of(work, struct hl_cs_job, @@ -1818,7 +1856,7 @@ static int _hl_cs_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx, return rc; } -int hl_cs_wait_ioctl(struct hl_fpriv *hpriv, void *data) +static int hl_cs_wait_ioctl(struct hl_fpriv *hpriv, void *data) { struct hl_device *hdev = hpriv->hdev; union hl_wait_cs_args *args = data; @@ -1873,3 +1911,176 @@ int hl_cs_wait_ioctl(struct hl_fpriv *hpriv, void *data) return 0; } + +static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx, + u32 timeout_us, u64 user_address, + u32 target_value, u16 interrupt_offset, + enum hl_cs_wait_status *status) +{ + struct hl_user_pending_interrupt *pend; + struct hl_user_interrupt *interrupt; + unsigned long timeout; + long completion_rc; + u32 completion_value; + int rc = 0; + + if (timeout_us == MAX_SCHEDULE_TIMEOUT) + timeout = timeout_us; + else + timeout = usecs_to_jiffies(timeout_us); + + hl_ctx_get(hdev, ctx); + + pend = kmalloc(sizeof(*pend), GFP_ATOMIC); + if (!pend) { + hl_ctx_put(ctx); + return -ENOMEM; + } + + hl_fence_init(&pend->fence, ULONG_MAX); + + if (interrupt_offset == HL_COMMON_USER_INTERRUPT_ID) + interrupt = &hdev->common_user_interrupt; + else + interrupt = &hdev->user_interrupt[interrupt_offset]; + + spin_lock(&interrupt->wait_list_lock); + if (!hl_device_operational(hdev, NULL)) { + rc = -EPERM; + goto unlock_and_free_fence; + } + + if (copy_from_user(&completion_value, u64_to_user_ptr(user_address), 4)) { + dev_err(hdev->dev, + "Failed to copy completion value from user\n"); + rc = -EFAULT; + goto unlock_and_free_fence; + } + + if (completion_value >= target_value) + *status = CS_WAIT_STATUS_COMPLETED; + else + *status = CS_WAIT_STATUS_BUSY; + + if (!timeout_us || (*status == CS_WAIT_STATUS_COMPLETED)) + goto unlock_and_free_fence; + + /* Add pending user interrupt to relevant list for the interrupt + * handler to monitor + */ + list_add_tail(&pend->wait_list_node, &interrupt->wait_list_head); + spin_unlock(&interrupt->wait_list_lock); + +wait_again: + /* Wait for interrupt handler to signal completion */ + completion_rc = + wait_for_completion_interruptible_timeout( + &pend->fence.completion, timeout); + + /* If timeout did not expire we need to perform the comparison. + * If comparison fails, keep waiting until timeout expires + */ + if (completion_rc > 0) { + if (copy_from_user(&completion_value, + u64_to_user_ptr(user_address), 4)) { + dev_err(hdev->dev, + "Failed to copy completion value from user\n"); + rc = -EFAULT; + goto remove_pending_user_interrupt; + } + + if (completion_value >= target_value) { + *status = CS_WAIT_STATUS_COMPLETED; + } else { + timeout -= jiffies_to_usecs(completion_rc); + goto wait_again; + } + } else { + *status = CS_WAIT_STATUS_BUSY; + } + +remove_pending_user_interrupt: + spin_lock(&interrupt->wait_list_lock); + list_del(&pend->wait_list_node); + +unlock_and_free_fence: + spin_unlock(&interrupt->wait_list_lock); + kfree(pend); + hl_ctx_put(ctx); + + return rc; +} + +static int hl_interrupt_wait_ioctl(struct hl_fpriv *hpriv, void *data) +{ + u16 interrupt_id, interrupt_offset, first_interrupt, last_interrupt; + struct hl_device *hdev = hpriv->hdev; + struct asic_fixed_properties *prop; + union hl_wait_cs_args *args = data; + enum hl_cs_wait_status status; + int rc; + + prop = &hdev->asic_prop; + + if (!prop->user_interrupt_count) { + dev_err(hdev->dev, "no user interrupts allowed"); + return -EPERM; + } + + interrupt_id = + FIELD_GET(HL_WAIT_CS_FLAGS_INTERRUPT_MASK, args->in.flags); + + first_interrupt = prop->first_available_user_msix_interrupt; + last_interrupt = prop->first_available_user_msix_interrupt + + prop->user_interrupt_count - 1; + + if ((interrupt_id < first_interrupt || interrupt_id > last_interrupt) && + interrupt_id != HL_COMMON_USER_INTERRUPT_ID) { + dev_err(hdev->dev, "invalid user interrupt %u", interrupt_id); + return -EINVAL; + } + + if (interrupt_id == HL_COMMON_USER_INTERRUPT_ID) + interrupt_offset = HL_COMMON_USER_INTERRUPT_ID; + else + interrupt_offset = interrupt_id - first_interrupt; + + rc = _hl_interrupt_wait_ioctl(hdev, hpriv->ctx, + args->in.interrupt_timeout_us, args->in.addr, + args->in.target, interrupt_offset, &status); + + memset(args, 0, sizeof(*args)); + + if (rc) { + dev_err_ratelimited(hdev->dev, + "interrupt_wait_ioctl failed (%d)\n", rc); + + return rc; + } + + switch (status) { + case CS_WAIT_STATUS_COMPLETED: + args->out.status = HL_WAIT_CS_STATUS_COMPLETED; + break; + case CS_WAIT_STATUS_BUSY: + default: + args->out.status = HL_WAIT_CS_STATUS_BUSY; + break; + } + + return 0; +} + +int hl_wait_ioctl(struct hl_fpriv *hpriv, void *data) +{ + union hl_wait_cs_args *args = data; + u32 flags = args->in.flags; + int rc; + + if (flags & HL_WAIT_CS_FLAGS_INTERRUPT) + rc = hl_interrupt_wait_ioctl(hpriv, data); + else + rc = hl_cs_wait_ioctl(hpriv, data); + + return rc; +} diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index 24e3ea15b2b9..96b8f39c2539 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -106,6 +106,11 @@ static int hl_device_release(struct inode *inode, struct file *filp) return 0; } + /* Each pending user interrupt holds the user's context, hence we + * must release them all before calling hl_ctx_mgr_fini(). + */ + hl_release_pending_user_interrupts(hpriv->hdev); + hl_cb_mgr_fini(hdev, &hpriv->cb_mgr); hl_ctx_mgr_fini(hdev, &hpriv->ctx_mgr); @@ -1036,6 +1041,11 @@ again: /* Go over all the queues, release all CS and their jobs */ hl_cs_rollback_all(hdev); + /* Release all pending user interrupts, each pending user interrupt + * holds a reference to user context + */ + hl_release_pending_user_interrupts(hdev); + kill_processes: if (hard_reset) { /* Kill processes here after CS rollback. This is because the @@ -1290,13 +1300,26 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass) if (rc) goto free_dev_ctrl; + user_interrupt_cnt = hdev->asic_prop.user_interrupt_count; + + if (user_interrupt_cnt) { + hdev->user_interrupt = kcalloc(user_interrupt_cnt, + sizeof(*hdev->user_interrupt), + GFP_KERNEL); + + if (!hdev->user_interrupt) { + rc = -ENOMEM; + goto early_fini; + } + } + /* * Start calling ASIC initialization. First S/W then H/W and finally * late init */ rc = hdev->asic_funcs->sw_init(hdev); if (rc) - goto early_fini; + goto user_interrupts_fini; /* * Initialize the H/W queues. Must be done before hw_init, because @@ -1340,19 +1363,6 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass) hdev->completion_queue[i].cq_idx = i; } - user_interrupt_cnt = hdev->asic_prop.user_interrupt_count; - - if (user_interrupt_cnt) { - hdev->user_interrupt = kcalloc(user_interrupt_cnt, - sizeof(*hdev->user_interrupt), - GFP_KERNEL); - - if (!hdev->user_interrupt) { - rc = -ENOMEM; - goto cq_fini; - } - } - /* * Initialize the event queue. Must be done before hw_init, * because there the address of the event queue is being @@ -1361,7 +1371,7 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass) rc = hl_eq_init(hdev, &hdev->event_queue); if (rc) { dev_err(hdev->dev, "failed to initialize event queue\n"); - goto user_interrupts_fini; + goto cq_fini; } /* MMU S/W must be initialized before kernel context is created */ @@ -1499,8 +1509,6 @@ mmu_fini: hl_mmu_fini(hdev); eq_fini: hl_eq_fini(hdev, &hdev->event_queue); -user_interrupts_fini: - kfree(hdev->user_interrupt); cq_fini: for (i = 0 ; i < cq_ready_cnt ; i++) hl_cq_fini(hdev, &hdev->completion_queue[i]); @@ -1509,6 +1517,8 @@ hw_queues_destroy: hl_hw_queues_destroy(hdev); sw_fini: hdev->asic_funcs->sw_fini(hdev); +user_interrupts_fini: + kfree(hdev->user_interrupt); early_fini: device_early_fini(hdev); free_dev_ctrl: diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 7ffd4b84ae90..b8ab346e53ff 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -63,6 +63,8 @@ #define HL_IDLE_BUSY_TS_ARR_SIZE 4096 +#define HL_COMMON_USER_INTERRUPT_ID 0xFFF + /* Memory */ #define MEM_HASH_TABLE_BITS 7 /* 1 << 7 buckets */ @@ -694,13 +696,28 @@ struct hl_cq { /** * struct hl_user_interrupt - holds user interrupt information * @hdev: pointer to the device structure + * @wait_list_head: head to the list of user threads pending on this interrupt + * @wait_list_lock: protects wait_list_head * @interrupt_id: msix interrupt id */ struct hl_user_interrupt { struct hl_device *hdev; + struct list_head wait_list_head; + spinlock_t wait_list_lock; u32 interrupt_id; }; +/** + * struct hl_user_pending_interrupt - holds a context to a user thread + * pending on an interrupt + * @wait_list_node: node in the list of user threads pending on an interrupt + * @fence: hl fence object for interrupt completion + */ +struct hl_user_pending_interrupt { + struct list_head wait_list_node; + struct hl_fence fence; +}; + /** * struct hl_eq - describes the event queue (single one per device) * @hdev: pointer to the device structure @@ -1833,7 +1850,12 @@ struct hl_mmu_funcs { * @asic_name: ASIC specific name. * @asic_type: ASIC specific type. * @completion_queue: array of hl_cq. - * @user_interrupt: array of hl_user_interrupt. + * @user_interrupt: array of hl_user_interrupt. upon the corresponding user + * interrupt, driver will monitor the list of fences + * registered to this interrupt. + * @common_user_interrupt: common user interrupt for all user interrupts. + * upon any user interrupt, driver will monitor the + * list of fences registered to this common structure. * @cq_wq: work queues of completion queues for executing work in process * context. * @eq_wq: work queue of event queue for executing work in process context. @@ -1951,6 +1973,7 @@ struct hl_device { enum hl_asic_type asic_type; struct hl_cq *completion_queue; struct hl_user_interrupt *user_interrupt; + struct hl_user_interrupt common_user_interrupt; struct workqueue_struct **cq_wq; struct workqueue_struct *eq_wq; struct hl_ctx *kernel_ctx; @@ -2351,6 +2374,7 @@ int hl_set_voltage(struct hl_device *hdev, int sensor_index, u32 attr, long value); int hl_set_current(struct hl_device *hdev, int sensor_index, u32 attr, long value); +void hl_release_pending_user_interrupts(struct hl_device *hdev); #ifdef CONFIG_DEBUG_FS @@ -2451,7 +2475,7 @@ long hl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); long hl_ioctl_control(struct file *filep, unsigned int cmd, unsigned long arg); int hl_cb_ioctl(struct hl_fpriv *hpriv, void *data); int hl_cs_ioctl(struct hl_fpriv *hpriv, void *data); -int hl_cs_wait_ioctl(struct hl_fpriv *hpriv, void *data); +int hl_wait_ioctl(struct hl_fpriv *hpriv, void *data); int hl_mem_ioctl(struct hl_fpriv *hpriv, void *data); #endif /* HABANALABSP_H_ */ diff --git a/drivers/misc/habanalabs/common/habanalabs_ioctl.c b/drivers/misc/habanalabs/common/habanalabs_ioctl.c index 083a30969c5f..848c2e588301 100644 --- a/drivers/misc/habanalabs/common/habanalabs_ioctl.c +++ b/drivers/misc/habanalabs/common/habanalabs_ioctl.c @@ -596,7 +596,7 @@ static const struct hl_ioctl_desc hl_ioctls[] = { HL_IOCTL_DEF(HL_IOCTL_INFO, hl_info_ioctl), HL_IOCTL_DEF(HL_IOCTL_CB, hl_cb_ioctl), HL_IOCTL_DEF(HL_IOCTL_CS, hl_cs_ioctl), - HL_IOCTL_DEF(HL_IOCTL_WAIT_CS, hl_cs_wait_ioctl), + HL_IOCTL_DEF(HL_IOCTL_WAIT_CS, hl_wait_ioctl), HL_IOCTL_DEF(HL_IOCTL_MEMORY, hl_mem_ioctl), HL_IOCTL_DEF(HL_IOCTL_DEBUG, hl_debug_ioctl) }; diff --git a/drivers/misc/habanalabs/common/irq.c b/drivers/misc/habanalabs/common/irq.c index c8b5dc07e6ca..27129868c711 100644 --- a/drivers/misc/habanalabs/common/irq.c +++ b/drivers/misc/habanalabs/common/irq.c @@ -137,6 +137,17 @@ irqreturn_t hl_irq_handler_cq(int irq, void *arg) return IRQ_HANDLED; } +static void handle_user_cq(struct hl_device *hdev, + struct hl_user_interrupt *user_cq) +{ + struct hl_user_pending_interrupt *pend; + + spin_lock(&user_cq->wait_list_lock); + list_for_each_entry(pend, &user_cq->wait_list_head, wait_list_node) + complete_all(&pend->fence.completion); + spin_unlock(&user_cq->wait_list_lock); +} + /** * hl_irq_handler_user_cq - irq handler for user completion queues * @@ -148,11 +159,16 @@ irqreturn_t hl_irq_handler_user_cq(int irq, void *arg) { struct hl_user_interrupt *user_cq = arg; struct hl_device *hdev = user_cq->hdev; - u32 interrupt_id = user_cq->interrupt_id; - dev_info(hdev->dev, + dev_dbg(hdev->dev, "got user completion interrupt id %u", - interrupt_id); + user_cq->interrupt_id); + + /* Handle user cq interrupts registered on all interrupts */ + handle_user_cq(hdev, &hdev->common_user_interrupt); + + /* Handle user cq interrupts registered on this specific interrupt */ + handle_user_cq(hdev, user_cq); return IRQ_HANDLED; } diff --git a/include/uapi/misc/habanalabs.h b/include/uapi/misc/habanalabs.h index 5a86b521a450..05c7cf4e727e 100644 --- a/include/uapi/misc/habanalabs.h +++ b/include/uapi/misc/habanalabs.h @@ -682,14 +682,46 @@ union hl_cs_args { struct hl_cs_out out; }; +#define HL_WAIT_CS_FLAGS_INTERRUPT 0x2 +#define HL_WAIT_CS_FLAGS_INTERRUPT_MASK 0xFFF00000 + struct hl_wait_cs_in { - /* Command submission sequence number */ - __u64 seq; - /* Absolute timeout to wait in microseconds */ - __u64 timeout_us; + union { + struct { + /* Command submission sequence number */ + __u64 seq; + /* Absolute timeout to wait for command submission + * in microseconds + */ + __u64 timeout_us; + }; + + struct { + /* User address for completion comparison. + * upon interrupt, driver will compare the value pointed + * by this address with the supplied target value. + * in order not to perform any comparison, set address + * to all 1s. + * Relevant only when HL_WAIT_CS_FLAGS_INTERRUPT is set + */ + __u64 addr; + /* Target value for completion comparison */ + __u32 target; + /* Absolute timeout to wait for interrupt + * in microseconds + */ + __u32 interrupt_timeout_us; + }; + }; + /* Context ID - Currently not in use */ __u32 ctx_id; - __u32 pad; + /* HL_WAIT_CS_FLAGS_* + * If HL_WAIT_CS_FLAGS_INTERRUPT is set, this field should include + * interrupt id according to HL_WAIT_CS_FLAGS_INTERRUPT_MASK, in order + * not to specify an interrupt id ,set mask to all 1s. + */ + __u32 flags; }; #define HL_WAIT_CS_STATUS_COMPLETED 0 -- cgit v1.2.3 From 366addb0c3c582bf7b9a2162bb398eb450b17218 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Wed, 17 Feb 2021 09:14:55 +0200 Subject: habanalabs: use correct define for 32-bit max value Timeout in wait for interrupt is in 32-bit variable so we need to use the correct maximum value to compare. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/command_submission.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index 4e6b4cf23181..e1a441e2b2a2 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -1924,7 +1924,7 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx, u32 completion_value; int rc = 0; - if (timeout_us == MAX_SCHEDULE_TIMEOUT) + if (timeout_us == U32_MAX) timeout = timeout_us; else timeout = usecs_to_jiffies(timeout_us); -- cgit v1.2.3 From 6a2f5d7098c868eeb9349ed02210ca1c04aa5cfb Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Mon, 15 Feb 2021 13:23:04 +0200 Subject: habanalabs: use a single FW loading bringup flag For simplicity, use a single bringup flag indicating which FW binaries should loaded to device. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 10 +++++++--- drivers/misc/habanalabs/common/habanalabs.h | 11 +++++++---- drivers/misc/habanalabs/common/habanalabs_drv.c | 3 +-- drivers/misc/habanalabs/gaudi/gaudi.c | 2 +- drivers/misc/habanalabs/goya/goya.c | 2 +- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 09706c571e95..6f3692bf5eff 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -623,7 +623,11 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, u32 status, security_status; int rc; - if (!hdev->cpu_enable) + /* pldm was added for cases in which we use preboot on pldm and want + * to load boot fit, but we can't wait for preboot because it runs + * very slowly + */ + if (!(hdev->fw_components & FW_TYPE_PREBOOT_CPU) || hdev->pldm) return 0; /* Need to check two possible scenarios: @@ -710,7 +714,7 @@ int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg, u32 status; int rc; - if (!(hdev->fw_loading & FW_TYPE_BOOT_CPU)) + if (!(hdev->fw_components & FW_TYPE_BOOT_CPU)) return 0; dev_info(hdev->dev, "Going to wait for device boot (up to %lds)\n", @@ -801,7 +805,7 @@ int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg, goto out; } - if (!(hdev->fw_loading & FW_TYPE_LINUX)) { + if (!(hdev->fw_components & FW_TYPE_LINUX)) { dev_info(hdev->dev, "Skip loading Linux F/W\n"); goto out; } diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index b8ab346e53ff..66e5150023e9 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -171,15 +171,19 @@ enum hl_fw_component { }; /** - * enum hl_fw_types - F/W types to load + * enum hl_fw_types - F/W types present in the system * @FW_TYPE_LINUX: Linux image for device CPU * @FW_TYPE_BOOT_CPU: Boot image for device CPU + * @FW_TYPE_PREBOOT_CPU: Indicates pre-loaded CPUs are present in the system + * (preboot, ppboot etc...) * @FW_TYPE_ALL_TYPES: Mask for all types */ enum hl_fw_types { FW_TYPE_LINUX = 0x1, FW_TYPE_BOOT_CPU = 0x2, - FW_TYPE_ALL_TYPES = (FW_TYPE_LINUX | FW_TYPE_BOOT_CPU) + FW_TYPE_PREBOOT_CPU = 0x4, + FW_TYPE_ALL_TYPES = + (FW_TYPE_LINUX | FW_TYPE_BOOT_CPU | FW_TYPE_PREBOOT_CPU) }; /** @@ -2066,10 +2070,9 @@ struct hl_device { /* Parameters for bring-up */ u64 nic_ports_mask; - u64 fw_loading; + u64 fw_components; u8 mmu_enable; u8 mmu_huge_page_opt; - u8 cpu_enable; u8 reset_pcilink; u8 cpu_queues_enable; u8 pldm; diff --git a/drivers/misc/habanalabs/common/habanalabs_drv.c b/drivers/misc/habanalabs/common/habanalabs_drv.c index f695ea6253c1..59896566dca1 100644 --- a/drivers/misc/habanalabs/common/habanalabs_drv.c +++ b/drivers/misc/habanalabs/common/habanalabs_drv.c @@ -234,8 +234,7 @@ out_err: static void set_driver_behavior_per_device(struct hl_device *hdev) { - hdev->cpu_enable = 1; - hdev->fw_loading = FW_TYPE_ALL_TYPES; + hdev->fw_components = FW_TYPE_ALL_TYPES; hdev->cpu_queues_enable = 1; hdev->heartbeat = 1; hdev->mmu_enable = 1; diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index c1f00237273c..4f39737b4808 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -3701,7 +3701,7 @@ static int gaudi_init_cpu(struct hl_device *hdev) struct gaudi_device *gaudi = hdev->asic_specific; int rc; - if (!hdev->cpu_enable) + if (!(hdev->fw_components & FW_TYPE_PREBOOT_CPU)) return 0; if (gaudi->hw_cap_initialized & HW_CAP_CPU) diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index a40c428fed94..20abed6ef7e6 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -2429,7 +2429,7 @@ static int goya_init_cpu(struct hl_device *hdev) struct goya_device *goya = hdev->asic_specific; int rc; - if (!hdev->cpu_enable) + if (!(hdev->fw_components & FW_TYPE_PREBOOT_CPU)) return 0; if (goya->hw_cap_initialized & HW_CAP_CPU) -- cgit v1.2.3 From a4371c1a1ec150bc8bb87333e0a59935c4a630e2 Mon Sep 17 00:00:00 2001 From: Sagiv Ozeri Date: Tue, 23 Feb 2021 11:01:08 +0200 Subject: habanalabs: support HW blocks vm show Improve "vm" debugfs node to print also the virtual addresses which are currently mapped to HW blocks in the device. Signed-off-by: Sagiv Ozeri Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- .../ABI/testing/debugfs-driver-habanalabs | 2 +- drivers/misc/habanalabs/common/context.c | 14 ++++- drivers/misc/habanalabs/common/debugfs.c | 16 ++++++ drivers/misc/habanalabs/common/habanalabs.h | 24 ++++++++ drivers/misc/habanalabs/common/memory.c | 65 ++++++++++++++++++++-- 5 files changed, 113 insertions(+), 8 deletions(-) diff --git a/Documentation/ABI/testing/debugfs-driver-habanalabs b/Documentation/ABI/testing/debugfs-driver-habanalabs index d447a611c41b..f9e233cbdc37 100644 --- a/Documentation/ABI/testing/debugfs-driver-habanalabs +++ b/Documentation/ABI/testing/debugfs-driver-habanalabs @@ -174,7 +174,7 @@ Date: Jan 2019 KernelVersion: 5.1 Contact: ogabbay@kernel.org Description: Displays a list with information about all the active virtual - address mappings per ASID + address mappings per ASID and all user mappings of HW blocks What: /sys/kernel/debug/habanalabs/hl/stop_on_err Date: Mar 2020 diff --git a/drivers/misc/habanalabs/common/context.c b/drivers/misc/habanalabs/common/context.c index cda871afb8f4..62d705889ca8 100644 --- a/drivers/misc/habanalabs/common/context.c +++ b/drivers/misc/habanalabs/common/context.c @@ -20,6 +20,11 @@ static void hl_ctx_fini(struct hl_ctx *ctx) */ hl_pending_cb_list_flush(ctx); + /* Release all allocated HW block mapped list entries and destroy + * the mutex. + */ + hl_hw_block_mem_fini(ctx); + /* * If we arrived here, there are no jobs waiting for this context * on its queues so we can safely remove it. @@ -160,13 +165,15 @@ int hl_ctx_init(struct hl_device *hdev, struct hl_ctx *ctx, bool is_kernel_ctx) if (!ctx->cs_pending) return -ENOMEM; + hl_hw_block_mem_init(ctx); + if (is_kernel_ctx) { ctx->asid = HL_KERNEL_ASID_ID; /* Kernel driver gets ASID 0 */ rc = hl_vm_ctx_init(ctx); if (rc) { dev_err(hdev->dev, "Failed to init mem ctx module\n"); rc = -ENOMEM; - goto err_free_cs_pending; + goto err_hw_block_mem_fini; } rc = hdev->asic_funcs->ctx_init(ctx); @@ -179,7 +186,7 @@ int hl_ctx_init(struct hl_device *hdev, struct hl_ctx *ctx, bool is_kernel_ctx) if (!ctx->asid) { dev_err(hdev->dev, "No free ASID, failed to create context\n"); rc = -ENOMEM; - goto err_free_cs_pending; + goto err_hw_block_mem_fini; } rc = hl_vm_ctx_init(ctx); @@ -214,7 +221,8 @@ err_vm_ctx_fini: err_asid_free: if (ctx->asid != HL_KERNEL_ASID_ID) hl_asid_free(hdev, ctx->asid); -err_free_cs_pending: +err_hw_block_mem_fini: + hl_hw_block_mem_fini(ctx); kfree(ctx->cs_pending); return rc; diff --git a/drivers/misc/habanalabs/common/debugfs.c b/drivers/misc/habanalabs/common/debugfs.c index 9f19bee7b592..a6a4fe0bf2e9 100644 --- a/drivers/misc/habanalabs/common/debugfs.c +++ b/drivers/misc/habanalabs/common/debugfs.c @@ -229,6 +229,7 @@ static int vm_show(struct seq_file *s, void *data) { struct hl_debugfs_entry *entry = s->private; struct hl_dbg_device_entry *dev_entry = entry->dev_entry; + struct hl_vm_hw_block_list_node *lnode; struct hl_ctx *ctx; struct hl_vm *vm; struct hl_vm_hash_node *hnode; @@ -272,6 +273,21 @@ static int vm_show(struct seq_file *s, void *data) } mutex_unlock(&ctx->mem_hash_lock); + if (ctx->asid != HL_KERNEL_ASID_ID && + !list_empty(&ctx->hw_block_mem_list)) { + seq_puts(s, "\nhw_block mappings:\n\n"); + seq_puts(s, " virtual address size HW block id\n"); + seq_puts(s, "-------------------------------------------\n"); + mutex_lock(&ctx->hw_block_list_lock); + list_for_each_entry(lnode, &ctx->hw_block_mem_list, + node) { + seq_printf(s, + " 0x%-14lx %-6u %-9u\n", + lnode->vaddr, lnode->size, lnode->id); + } + mutex_unlock(&ctx->hw_block_list_lock); + } + vm = &ctx->hdev->vm; spin_lock(&vm->idr_lock); diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 66e5150023e9..fdb2a8c91f60 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -1103,9 +1103,11 @@ struct hl_pending_cb { * @mem_hash_lock: protects the mem_hash. * @mmu_lock: protects the MMU page tables. Any change to the PGT, modifying the * MMU hash or walking the PGT requires talking this lock. + * @hw_block_list_lock: protects the HW block memory list. * @debugfs_list: node in debugfs list of contexts. * pending_cb_list: list of pending command buffers waiting to be sent upon * next user command submission context. + * @hw_block_mem_list: list of HW block virtual mapped addresses. * @cs_counters: context command submission counters. * @cb_va_pool: device VA pool for command buffers which are mapped to the * device's MMU. @@ -1142,8 +1144,10 @@ struct hl_ctx { struct hl_va_range *va_range[HL_VA_RANGE_TYPE_MAX]; struct mutex mem_hash_lock; struct mutex mmu_lock; + struct mutex hw_block_list_lock; struct list_head debugfs_list; struct list_head pending_cb_list; + struct list_head hw_block_mem_list; struct hl_cs_counters_atomic cs_counters; struct gen_pool *cb_va_pool; u64 cs_sequence; @@ -1362,6 +1366,23 @@ struct hl_vm_hash_node { void *ptr; }; +/** + * struct hl_vm_hw_block_list_node - list element from user virtual address to + * HW block id. + * @node: node to hang on the list in context object. + * @ctx: the context this node belongs to. + * @vaddr: virtual address of the HW block. + * @size: size of the block. + * @id: HW block id (handle). + */ +struct hl_vm_hw_block_list_node { + struct list_head node; + struct hl_ctx *ctx; + unsigned long vaddr; + u32 size; + u32 id; +}; + /** * struct hl_vm_phys_pg_pack - physical page pack. * @vm_type: describes the type of the virtual area descriptor. @@ -2278,6 +2299,9 @@ void hl_vm_ctx_fini(struct hl_ctx *ctx); int hl_vm_init(struct hl_device *hdev); void hl_vm_fini(struct hl_device *hdev); +void hl_hw_block_mem_init(struct hl_ctx *ctx); +void hl_hw_block_mem_fini(struct hl_ctx *ctx); + u64 hl_reserve_va_block(struct hl_device *hdev, struct hl_ctx *ctx, enum hl_va_range_type type, u32 size, u32 alignment); int hl_unreserve_va_block(struct hl_device *hdev, struct hl_ctx *ctx, diff --git a/drivers/misc/habanalabs/common/memory.c b/drivers/misc/habanalabs/common/memory.c index 1f5910517b0e..c2679896aa50 100644 --- a/drivers/misc/habanalabs/common/memory.c +++ b/drivers/misc/habanalabs/common/memory.c @@ -1305,9 +1305,15 @@ static int map_block(struct hl_device *hdev, u64 address, u64 *handle, static void hw_block_vm_close(struct vm_area_struct *vma) { - struct hl_ctx *ctx = (struct hl_ctx *) vma->vm_private_data; + struct hl_vm_hw_block_list_node *lnode = + (struct hl_vm_hw_block_list_node *) vma->vm_private_data; + struct hl_ctx *ctx = lnode->ctx; + mutex_lock(&ctx->hw_block_list_lock); + list_del(&lnode->node); + mutex_unlock(&ctx->hw_block_list_lock); hl_ctx_put(ctx); + kfree(lnode); vma->vm_private_data = NULL; } @@ -1325,7 +1331,9 @@ static const struct vm_operations_struct hw_block_vm_ops = { */ int hl_hw_block_mmap(struct hl_fpriv *hpriv, struct vm_area_struct *vma) { + struct hl_vm_hw_block_list_node *lnode; struct hl_device *hdev = hpriv->hdev; + struct hl_ctx *ctx = hpriv->ctx; u32 block_id, block_size; int rc; @@ -1351,17 +1359,31 @@ int hl_hw_block_mmap(struct hl_fpriv *hpriv, struct vm_area_struct *vma) return -EINVAL; } + lnode = kzalloc(sizeof(*lnode), GFP_KERNEL); + if (!lnode) + return -ENOMEM; + vma->vm_ops = &hw_block_vm_ops; - vma->vm_private_data = hpriv->ctx; + vma->vm_private_data = lnode; - hl_ctx_get(hdev, hpriv->ctx); + hl_ctx_get(hdev, ctx); rc = hdev->asic_funcs->hw_block_mmap(hdev, vma, block_id, block_size); if (rc) { - hl_ctx_put(hpriv->ctx); + hl_ctx_put(ctx); + kfree(lnode); return rc; } + lnode->ctx = ctx; + lnode->vaddr = vma->vm_start; + lnode->size = block_size; + lnode->id = block_id; + + mutex_lock(&ctx->hw_block_list_lock); + list_add_tail(&lnode->node, &ctx->hw_block_mem_list); + mutex_unlock(&ctx->hw_block_list_lock); + vma->vm_pgoff = block_id; return 0; @@ -2122,3 +2144,38 @@ void hl_vm_fini(struct hl_device *hdev) vm->init_done = false; } + +/** + * hl_hw_block_mem_init() - HW block memory initialization. + * @ctx: pointer to the habanalabs context structure. + * + * This function initializes the HW block virtual mapped addresses list and + * it's lock. + */ +void hl_hw_block_mem_init(struct hl_ctx *ctx) +{ + mutex_init(&ctx->hw_block_list_lock); + INIT_LIST_HEAD(&ctx->hw_block_mem_list); +} + +/** + * hl_hw_block_mem_fini() - HW block memory teardown. + * @ctx: pointer to the habanalabs context structure. + * + * This function clears the HW block virtual mapped addresses list and destroys + * it's lock. + */ +void hl_hw_block_mem_fini(struct hl_ctx *ctx) +{ + struct hl_vm_hw_block_list_node *lnode, *tmp; + + if (!list_empty(&ctx->hw_block_mem_list)) + dev_crit(ctx->hdev->dev, "HW block mem list isn't empty\n"); + + list_for_each_entry_safe(lnode, tmp, &ctx->hw_block_mem_list, node) { + list_del(&lnode->node); + kfree(lnode); + } + + mutex_destroy(&ctx->hw_block_list_lock); +} -- cgit v1.2.3 From 586f2caf0ef952ca5e0f38a00b7ba8d945345cf7 Mon Sep 17 00:00:00 2001 From: Sagiv Ozeri Date: Tue, 23 Feb 2021 18:00:05 +0200 Subject: habanalabs: return current power via INFO IOCTL Add driver implementation for reading the current power from the device CPU F/W. Signed-off-by: Sagiv Ozeri Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 23 +++++++++++++++++++++++ drivers/misc/habanalabs/common/habanalabs.h | 1 + drivers/misc/habanalabs/common/habanalabs_ioctl.c | 22 ++++++++++++++++++++++ drivers/misc/habanalabs/include/common/cpucp_if.h | 5 +++++ include/uapi/misc/habanalabs.h | 9 +++++++++ 5 files changed, 60 insertions(+) diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 6f3692bf5eff..2a58edaf984a 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -565,6 +565,29 @@ int hl_fw_cpucp_pll_info_get(struct hl_device *hdev, u16 pll_index, return rc; } +int hl_fw_cpucp_power_get(struct hl_device *hdev, u64 *power) +{ + struct cpucp_packet pkt; + u64 result; + int rc; + + memset(&pkt, 0, sizeof(pkt)); + + pkt.ctl = cpu_to_le32(CPUCP_PACKET_POWER_GET << + CPUCP_PKT_CTL_OPCODE_SHIFT); + + rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), + HL_CPUCP_INFO_TIMEOUT_USEC, &result); + if (rc) { + dev_err(hdev->dev, "Failed to read power, error %d\n", rc); + return rc; + } + + *power = result; + + return rc; +} + static void detect_cpu_boot_status(struct hl_device *hdev, u32 status) { /* Some of the status codes below are deprecated in newer f/w diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index fdb2a8c91f60..392a4a569049 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -2361,6 +2361,7 @@ int hl_fw_cpucp_total_energy_get(struct hl_device *hdev, u64 *total_energy); int hl_fw_cpucp_pll_info_get(struct hl_device *hdev, u16 pll_index, u16 *pll_freq_arr); +int hl_fw_cpucp_power_get(struct hl_device *hdev, u64 *power); int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg, u32 msg_to_cpu_reg, u32 cpu_msg_status_reg, u32 cpu_security_boot_status_reg, u32 boot_err0_reg, diff --git a/drivers/misc/habanalabs/common/habanalabs_ioctl.c b/drivers/misc/habanalabs/common/habanalabs_ioctl.c index 848c2e588301..9fc429b82a92 100644 --- a/drivers/misc/habanalabs/common/habanalabs_ioctl.c +++ b/drivers/misc/habanalabs/common/habanalabs_ioctl.c @@ -446,6 +446,25 @@ static int pll_frequency_info(struct hl_fpriv *hpriv, struct hl_info_args *args) min((size_t) max_size, sizeof(freq_info))) ? -EFAULT : 0; } +static int power_info(struct hl_fpriv *hpriv, struct hl_info_args *args) +{ + struct hl_device *hdev = hpriv->hdev; + u32 max_size = args->return_size; + struct hl_power_info power_info = {0}; + void __user *out = (void __user *) (uintptr_t) args->return_pointer; + int rc; + + if ((!max_size) || (!out)) + return -EINVAL; + + rc = hl_fw_cpucp_power_get(hdev, &power_info.power); + if (rc) + return rc; + + return copy_to_user(out, &power_info, + min((size_t) max_size, sizeof(power_info))) ? -EFAULT : 0; +} + static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data, struct device *dev) { @@ -526,6 +545,9 @@ static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data, case HL_INFO_PLL_FREQUENCY: return pll_frequency_info(hpriv, args); + case HL_INFO_POWER: + return power_info(hpriv, args); + default: dev_err(dev, "Invalid request %d\n", args->op); rc = -ENOTTY; diff --git a/drivers/misc/habanalabs/include/common/cpucp_if.h b/drivers/misc/habanalabs/include/common/cpucp_if.h index bf4e7900d8c8..6ba480a316ce 100644 --- a/drivers/misc/habanalabs/include/common/cpucp_if.h +++ b/drivers/misc/habanalabs/include/common/cpucp_if.h @@ -296,6 +296,9 @@ enum pq_init_status { * The result is composed of 4 outputs, each is 16-bit * frequency in MHz. * + * CPUCP_PACKET_POWER_GET + * Fetch the present power consumption of the device (Current * Voltage). + * */ enum cpucp_packet_id { @@ -329,6 +332,8 @@ enum cpucp_packet_id { CPUCP_PACKET_PCIE_REPLAY_CNT_GET, /* internal */ CPUCP_PACKET_TOTAL_ENERGY_GET, /* internal */ CPUCP_PACKET_PLL_INFO_GET, /* internal */ + CPUCP_PACKET_NIC_STATUS, /* internal */ + CPUCP_PACKET_POWER_GET, /* internal */ }; #define CPUCP_PACKET_FENCE_VAL 0xFE8CE7A5 diff --git a/include/uapi/misc/habanalabs.h b/include/uapi/misc/habanalabs.h index 05c7cf4e727e..92fd000ce0d3 100644 --- a/include/uapi/misc/habanalabs.h +++ b/include/uapi/misc/habanalabs.h @@ -297,6 +297,7 @@ enum hl_device_status { #define HL_INFO_SYNC_MANAGER 14 #define HL_INFO_TOTAL_ENERGY 15 #define HL_INFO_PLL_FREQUENCY 16 +#define HL_INFO_POWER 17 #define HL_INFO_VERSION_MAX_LEN 128 #define HL_INFO_CARD_NAME_MAX_LEN 16 @@ -410,6 +411,14 @@ struct hl_pll_frequency_info { __u16 output[HL_PLL_NUM_OUTPUTS]; }; +/** + * struct hl_power_info - power information + * @power: power consumption + */ +struct hl_power_info { + __u64 power; +}; + /** * struct hl_info_sync_manager - sync manager information * @first_available_sync_object: first available sob -- cgit v1.2.3 From f209e5ad1848828474c46a357441505078cca5c0 Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Thu, 25 Feb 2021 12:48:06 +0200 Subject: habanalabs/gaudi: update extended async event header Update to the latest definition of the firmware Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- .../habanalabs/include/gaudi/gaudi_async_ids_map_extended.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h b/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h index 737176ba06fb..9106395eb920 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h @@ -301,10 +301,10 @@ static struct gaudi_async_events_ids_map gaudi_irq_map_table[] = { { .fc_id = 274, .cpu_id = 128, .valid = 0, .name = "" }, { .fc_id = 275, .cpu_id = 128, .valid = 0, .name = "" }, { .fc_id = 276, .cpu_id = 128, .valid = 0, .name = "" }, - { .fc_id = 277, .cpu_id = 129, .valid = 0, .name = "" }, - { .fc_id = 278, .cpu_id = 129, .valid = 0, .name = "" }, - { .fc_id = 279, .cpu_id = 129, .valid = 0, .name = "" }, - { .fc_id = 280, .cpu_id = 129, .valid = 0, .name = "" }, + { .fc_id = 277, .cpu_id = 129, .valid = 1, .name = "DMA_IF_SEI_0" }, + { .fc_id = 278, .cpu_id = 129, .valid = 1, .name = "DMA_IF_SEI_1" }, + { .fc_id = 279, .cpu_id = 129, .valid = 1, .name = "DMA_IF_SEI_2" }, + { .fc_id = 280, .cpu_id = 129, .valid = 1, .name = "DMA_IF_SEI_3" }, { .fc_id = 281, .cpu_id = 130, .valid = 0, .name = "" }, { .fc_id = 282, .cpu_id = 131, .valid = 0, .name = "" }, { .fc_id = 283, .cpu_id = 132, .valid = 0, .name = "" }, @@ -681,7 +681,7 @@ static struct gaudi_async_events_ids_map gaudi_irq_map_table[] = { { .fc_id = 654, .cpu_id = 503, .valid = 0, .name = "" }, { .fc_id = 655, .cpu_id = 504, .valid = 0, .name = "" }, { .fc_id = 656, .cpu_id = 505, .valid = 0, .name = "" }, - { .fc_id = 657, .cpu_id = 506, .valid = 0, .name = "" }, + { .fc_id = 657, .cpu_id = 506, .valid = 1, .name = "PKT_QUEUE_ASYNC" }, { .fc_id = 658, .cpu_id = 507, .valid = 1, .name = "FIX_POWER_ENV_S" }, { .fc_id = 659, .cpu_id = 508, .valid = 1, .name = "FIX_POWER_ENV_E" }, { .fc_id = 660, .cpu_id = 509, .valid = 1, -- cgit v1.2.3 From d5eb8373b2cee72a6f1f2157130b56e6a88894dc Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Sun, 14 Feb 2021 15:35:56 +0200 Subject: habanalabs: replace GFP_ATOMIC with GFP_KERNEL As there are incorrect assumptions in which some of the initialization and data path flows cannot sleep, most allocations are being done using GFP_ATOMIC. We modify the code to use GFP_ATOMIC only when realy needed, as sleepable flow should use GFP_KERNEL. In addition add a fallback to allocate memory using GFP_KERNEL, once ATOMIC allocation fails. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/command_buffer.c | 12 +++++++++--- .../misc/habanalabs/common/command_submission.c | 22 +++++++++++++++++++++- drivers/misc/habanalabs/common/device.c | 2 +- drivers/misc/habanalabs/common/memory.c | 10 +++------- drivers/misc/habanalabs/gaudi/gaudi.c | 2 +- drivers/misc/habanalabs/goya/goya.c | 2 +- 6 files changed, 36 insertions(+), 14 deletions(-) diff --git a/drivers/misc/habanalabs/common/command_buffer.c b/drivers/misc/habanalabs/common/command_buffer.c index d9adb9a5e4d8..719168c980a4 100644 --- a/drivers/misc/habanalabs/common/command_buffer.c +++ b/drivers/misc/habanalabs/common/command_buffer.c @@ -181,7 +181,7 @@ static void cb_release(struct kref *ref) static struct hl_cb *hl_cb_alloc(struct hl_device *hdev, u32 cb_size, int ctx_id, bool internal_cb) { - struct hl_cb *cb; + struct hl_cb *cb = NULL; u32 cb_offset; void *p; @@ -193,9 +193,10 @@ static struct hl_cb *hl_cb_alloc(struct hl_device *hdev, u32 cb_size, * the kernel's copy. Hence, we must never sleep in this code section * and must use GFP_ATOMIC for all memory allocations. */ - if (ctx_id == HL_KERNEL_ASID_ID) + if (ctx_id == HL_KERNEL_ASID_ID && !hdev->disabled) cb = kzalloc(sizeof(*cb), GFP_ATOMIC); - else + + if (!cb) cb = kzalloc(sizeof(*cb), GFP_KERNEL); if (!cb) @@ -214,6 +215,9 @@ static struct hl_cb *hl_cb_alloc(struct hl_device *hdev, u32 cb_size, } else if (ctx_id == HL_KERNEL_ASID_ID) { p = hdev->asic_funcs->asic_dma_alloc_coherent(hdev, cb_size, &cb->bus_address, GFP_ATOMIC); + if (!p) + p = hdev->asic_funcs->asic_dma_alloc_coherent(hdev, + cb_size, &cb->bus_address, GFP_KERNEL); } else { p = hdev->asic_funcs->asic_dma_alloc_coherent(hdev, cb_size, &cb->bus_address, @@ -310,6 +314,8 @@ int hl_cb_create(struct hl_device *hdev, struct hl_cb_mgr *mgr, spin_lock(&mgr->cb_lock); rc = idr_alloc(&mgr->cb_handles, cb, 1, 0, GFP_ATOMIC); + if (rc < 0) + rc = idr_alloc(&mgr->cb_handles, cb, 1, 0, GFP_KERNEL); spin_unlock(&mgr->cb_lock); if (rc < 0) { diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index e1a441e2b2a2..20c3793feb27 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -638,6 +638,9 @@ static int allocate_cs(struct hl_device *hdev, struct hl_ctx *ctx, cntr = &hdev->aggregated_cs_counters; cs = kzalloc(sizeof(*cs), GFP_ATOMIC); + if (!cs) + cs = kzalloc(sizeof(*cs), GFP_KERNEL); + if (!cs) { atomic64_inc(&ctx->cs_counters.out_of_mem_drop_cnt); atomic64_inc(&cntr->out_of_mem_drop_cnt); @@ -657,6 +660,9 @@ static int allocate_cs(struct hl_device *hdev, struct hl_ctx *ctx, spin_lock_init(&cs->job_lock); cs_cmpl = kmalloc(sizeof(*cs_cmpl), GFP_ATOMIC); + if (!cs_cmpl) + cs_cmpl = kmalloc(sizeof(*cs_cmpl), GFP_KERNEL); + if (!cs_cmpl) { atomic64_inc(&ctx->cs_counters.out_of_mem_drop_cnt); atomic64_inc(&cntr->out_of_mem_drop_cnt); @@ -698,6 +704,10 @@ static int allocate_cs(struct hl_device *hdev, struct hl_ctx *ctx, cs->jobs_in_queue_cnt = kcalloc(hdev->asic_prop.max_queues, sizeof(*cs->jobs_in_queue_cnt), GFP_ATOMIC); + if (!cs->jobs_in_queue_cnt) + cs->jobs_in_queue_cnt = kcalloc(hdev->asic_prop.max_queues, + sizeof(*cs->jobs_in_queue_cnt), GFP_KERNEL); + if (!cs->jobs_in_queue_cnt) { atomic64_inc(&ctx->cs_counters.out_of_mem_drop_cnt); atomic64_inc(&cntr->out_of_mem_drop_cnt); @@ -927,6 +937,9 @@ struct hl_cs_job *hl_cs_allocate_job(struct hl_device *hdev, struct hl_cs_job *job; job = kzalloc(sizeof(*job), GFP_ATOMIC); + if (!job) + job = kzalloc(sizeof(*job), GFP_KERNEL); + if (!job) return NULL; @@ -1029,6 +1042,9 @@ static int hl_cs_copy_chunk_array(struct hl_device *hdev, *cs_chunk_array = kmalloc_array(num_chunks, sizeof(**cs_chunk_array), GFP_ATOMIC); + if (!*cs_chunk_array) + *cs_chunk_array = kmalloc_array(num_chunks, + sizeof(**cs_chunk_array), GFP_KERNEL); if (!*cs_chunk_array) { atomic64_inc(&ctx->cs_counters.out_of_mem_drop_cnt); atomic64_inc(&hdev->aggregated_cs_counters.out_of_mem_drop_cnt); @@ -1483,6 +1499,10 @@ static int cs_ioctl_extract_signal_seq(struct hl_device *hdev, signal_seq_arr = kmalloc_array(signal_seq_arr_len, sizeof(*signal_seq_arr), GFP_ATOMIC); + if (!signal_seq_arr) + signal_seq_arr = kmalloc_array(signal_seq_arr_len, + sizeof(*signal_seq_arr), + GFP_KERNEL); if (!signal_seq_arr) { atomic64_inc(&ctx->cs_counters.out_of_mem_drop_cnt); atomic64_inc(&hdev->aggregated_cs_counters.out_of_mem_drop_cnt); @@ -1931,7 +1951,7 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx, hl_ctx_get(hdev, ctx); - pend = kmalloc(sizeof(*pend), GFP_ATOMIC); + pend = kmalloc(sizeof(*pend), GFP_KERNEL); if (!pend) { hl_ctx_put(ctx); return -ENOMEM; diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index 96b8f39c2539..c94e8ca6edf1 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -344,7 +344,7 @@ static int device_early_init(struct hl_device *hdev) if (hdev->asic_prop.completion_queues_count) { hdev->cq_wq = kcalloc(hdev->asic_prop.completion_queues_count, sizeof(*hdev->cq_wq), - GFP_ATOMIC); + GFP_KERNEL); if (!hdev->cq_wq) { rc = -ENOMEM; goto asid_fini; diff --git a/drivers/misc/habanalabs/common/memory.c b/drivers/misc/habanalabs/common/memory.c index c2679896aa50..1b69573369cf 100644 --- a/drivers/misc/habanalabs/common/memory.c +++ b/drivers/misc/habanalabs/common/memory.c @@ -145,7 +145,7 @@ static int alloc_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args, spin_lock(&vm->idr_lock); handle = idr_alloc(&vm->phys_pg_pack_handles, phys_pg_pack, 1, 0, - GFP_ATOMIC); + GFP_KERNEL); spin_unlock(&vm->idr_lock); if (handle < 0) { @@ -1596,7 +1596,7 @@ static int get_user_memory(struct hl_device *hdev, u64 addr, u64 size, rc = sg_alloc_table_from_pages(userptr->sgt, userptr->pages, - npages, offset, size, GFP_ATOMIC); + npages, offset, size, GFP_KERNEL); if (rc < 0) { dev_err(hdev->dev, "failed to create SG table from pages\n"); goto put_pages; @@ -1646,11 +1646,7 @@ int hl_pin_host_memory(struct hl_device *hdev, u64 addr, u64 size, return -EINVAL; } - /* - * This function can be called also from data path, hence use atomic - * always as it is not a big allocation. - */ - userptr->sgt = kzalloc(sizeof(*userptr->sgt), GFP_ATOMIC); + userptr->sgt = kzalloc(sizeof(*userptr->sgt), GFP_KERNEL); if (!userptr->sgt) return -ENOMEM; diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 4f39737b4808..eee9387c8a26 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -4873,7 +4873,7 @@ static int gaudi_pin_memory_before_cs(struct hl_device *hdev, parser->job_userptr_list, &userptr)) goto already_pinned; - userptr = kzalloc(sizeof(*userptr), GFP_ATOMIC); + userptr = kzalloc(sizeof(*userptr), GFP_KERNEL); if (!userptr) return -ENOMEM; diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 20abed6ef7e6..1eaf9c06227c 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -3221,7 +3221,7 @@ static int goya_pin_memory_before_cs(struct hl_device *hdev, parser->job_userptr_list, &userptr)) goto already_pinned; - userptr = kzalloc(sizeof(*userptr), GFP_ATOMIC); + userptr = kzalloc(sizeof(*userptr), GFP_KERNEL); if (!userptr) return -ENOMEM; -- cgit v1.2.3 From e42a6400fb381060c4a18ab76648ff542e7d4566 Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Wed, 17 Feb 2021 20:42:48 +0200 Subject: habanalabs: skip DISABLE PCI packet to FW on heartbeat if reset is due to heartbeat, device CPU is no responsive in which case no point sending PCI disable message to it. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- .../misc/habanalabs/common/command_submission.c | 4 +-- drivers/misc/habanalabs/common/debugfs.c | 2 +- drivers/misc/habanalabs/common/device.c | 25 ++++++++------ drivers/misc/habanalabs/common/habanalabs.h | 20 +++++++++-- drivers/misc/habanalabs/common/sysfs.c | 4 +-- drivers/misc/habanalabs/gaudi/gaudi.c | 40 +++++++++------------- drivers/misc/habanalabs/goya/goya.c | 8 ++--- 7 files changed, 59 insertions(+), 44 deletions(-) diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index 20c3793feb27..720588aed28b 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -620,7 +620,7 @@ static void cs_timedout(struct work_struct *work) cs_put(cs); if (hdev->reset_on_lockup) - hl_device_reset(hdev, false, false); + hl_device_reset(hdev, 0); else hdev->needs_reset = true; } @@ -1473,7 +1473,7 @@ wait_again: out: if ((rc == -ETIMEDOUT || rc == -EBUSY) && (need_soft_reset)) - hl_device_reset(hdev, false, false); + hl_device_reset(hdev, 0); return rc; } diff --git a/drivers/misc/habanalabs/common/debugfs.c b/drivers/misc/habanalabs/common/debugfs.c index a6a4fe0bf2e9..fd3135c422b6 100644 --- a/drivers/misc/habanalabs/common/debugfs.c +++ b/drivers/misc/habanalabs/common/debugfs.c @@ -887,7 +887,7 @@ static ssize_t hl_stop_on_err_write(struct file *f, const char __user *buf, hdev->stop_on_err = value ? 1 : 0; - hl_device_reset(hdev, false, false); + hl_device_reset(hdev, 0); return count; } diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index c94e8ca6edf1..e22df6824bc3 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -72,7 +72,7 @@ static void hpriv_release(struct kref *ref) kfree(hpriv); if (hdev->reset_upon_device_release) - hl_device_reset(hdev, false, false); + hl_device_reset(hdev, 0); } void hl_hpriv_get(struct hl_fpriv *hpriv) @@ -293,7 +293,7 @@ static void device_hard_reset_pending(struct work_struct *work) struct hl_device *hdev = device_reset_work->hdev; int rc; - rc = hl_device_reset(hdev, true, true); + rc = hl_device_reset(hdev, HL_RESET_HARD | HL_RESET_FROM_RESET_THREAD); if ((rc == -EBUSY) && !hdev->device_fini_pending) { dev_info(hdev->dev, "Could not reset device. will try again in %u seconds", @@ -495,7 +495,7 @@ static void hl_device_heartbeat(struct work_struct *work) goto reschedule; dev_err(hdev->dev, "Device heartbeat failed!\n"); - hl_device_reset(hdev, true, false); + hl_device_reset(hdev, HL_RESET_HARD | HL_RESET_HEARTBEAT); return; @@ -819,7 +819,7 @@ int hl_device_resume(struct hl_device *hdev) hdev->disabled = false; atomic_set(&hdev->in_reset, 0); - rc = hl_device_reset(hdev, true, false); + rc = hl_device_reset(hdev, HL_RESET_HARD); if (rc) { dev_err(hdev->dev, "Failed to reset device during resume\n"); goto disable_device; @@ -925,9 +925,7 @@ static void device_disable_open_processes(struct hl_device *hdev) * hl_device_reset - reset the device * * @hdev: pointer to habanalabs device structure - * @hard_reset: should we do hard reset to all engines or just reset the - * compute/dma engines - * @from_hard_reset_thread: is the caller the hard-reset thread + * @flags: reset flags. * * Block future CS and wait for pending CS to be enqueued * Call ASIC H/W fini @@ -939,10 +937,10 @@ static void device_disable_open_processes(struct hl_device *hdev) * * Returns 0 for success or an error on failure. */ -int hl_device_reset(struct hl_device *hdev, bool hard_reset, - bool from_hard_reset_thread) +int hl_device_reset(struct hl_device *hdev, u32 flags) { u64 idle_mask[HL_BUSY_ENGINES_MASK_EXT_SIZE] = {0}; + bool hard_reset, from_hard_reset_thread; int i, rc; if (!hdev->init_done) { @@ -951,6 +949,9 @@ int hl_device_reset(struct hl_device *hdev, bool hard_reset, return 0; } + hard_reset = (flags & HL_RESET_HARD) != 0; + from_hard_reset_thread = (flags & HL_RESET_FROM_RESET_THREAD) != 0; + if ((!hard_reset) && (!hdev->supports_soft_reset)) { dev_dbg(hdev->dev, "Doing hard-reset instead of soft-reset\n"); hard_reset = true; @@ -971,7 +972,11 @@ int hl_device_reset(struct hl_device *hdev, bool hard_reset, if (rc) return 0; - if (hard_reset) { + /* + * if reset is due to heartbeat, device CPU is no responsive in + * which case no point sending PCI disable message to it + */ + if (hard_reset && !(flags & HL_RESET_HEARTBEAT)) { /* Disable PCI access from device F/W so he won't send * us additional interrupts. We disable MSI/MSI-X at * the halt_engines function and we can't have the F/W diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 392a4a569049..780adde16387 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -104,6 +104,23 @@ enum hl_mmu_page_table_location { #define HL_MAX_DCORES 4 +/* + * Reset Flags + * + * - HL_RESET_HARD + * If set do hard reset to all engines. If not set reset just + * compute/DMA engines. + * + * - HL_RESET_FROM_RESET_THREAD + * Set if the caller is the hard-reset thread + * + * - HL_RESET_HEARTBEAT + * Set if reset is due to heartbeat + */ +#define HL_RESET_HARD (1 << 0) +#define HL_RESET_FROM_RESET_THREAD (1 << 1) +#define HL_RESET_HEARTBEAT (1 << 2) + #define HL_MAX_SOBS_PER_MONITOR 8 /** @@ -2242,8 +2259,7 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass); void hl_device_fini(struct hl_device *hdev); int hl_device_suspend(struct hl_device *hdev); int hl_device_resume(struct hl_device *hdev); -int hl_device_reset(struct hl_device *hdev, bool hard_reset, - bool from_hard_reset_thread); +int hl_device_reset(struct hl_device *hdev, u32 flags); void hl_hpriv_get(struct hl_fpriv *hpriv); int hl_hpriv_put(struct hl_fpriv *hpriv); int hl_device_set_frequency(struct hl_device *hdev, enum hl_pll_frequency freq); diff --git a/drivers/misc/habanalabs/common/sysfs.c b/drivers/misc/habanalabs/common/sysfs.c index 4366d8f93842..9bd13bdc1ba9 100644 --- a/drivers/misc/habanalabs/common/sysfs.c +++ b/drivers/misc/habanalabs/common/sysfs.c @@ -203,7 +203,7 @@ static ssize_t soft_reset_store(struct device *dev, dev_warn(hdev->dev, "Soft-Reset requested through sysfs\n"); - hl_device_reset(hdev, false, false); + hl_device_reset(hdev, 0); out: return count; @@ -226,7 +226,7 @@ static ssize_t hard_reset_store(struct device *dev, dev_warn(hdev->dev, "Hard-Reset requested through sysfs\n"); - hl_device_reset(hdev, true, false); + hl_device_reset(hdev, HL_RESET_HARD); out: return count; diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index eee9387c8a26..37e3f4cd05c0 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -7380,18 +7380,14 @@ static void gaudi_handle_eqe(struct hl_device *hdev, case GAUDI_EVENT_MMU_DERR: gaudi_print_irq_info(hdev, event_type, true); gaudi_handle_ecc_event(hdev, event_type, &eq_entry->ecc_data); - if (hdev->hard_reset_on_fw_events) - hl_device_reset(hdev, true, false); - break; + goto reset_device; case GAUDI_EVENT_GIC500: case GAUDI_EVENT_AXI_ECC: case GAUDI_EVENT_L2_RAM_ECC: case GAUDI_EVENT_PLL0 ... GAUDI_EVENT_PLL17: gaudi_print_irq_info(hdev, event_type, false); - if (hdev->hard_reset_on_fw_events) - hl_device_reset(hdev, true, false); - break; + goto reset_device; case GAUDI_EVENT_HBM0_SPI_0: case GAUDI_EVENT_HBM1_SPI_0: @@ -7401,9 +7397,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, gaudi_hbm_read_interrupts(hdev, gaudi_hbm_event_to_dev(event_type), &eq_entry->hbm_ecc_data); - if (hdev->hard_reset_on_fw_events) - hl_device_reset(hdev, true, false); - break; + goto reset_device; case GAUDI_EVENT_HBM0_SPI_1: case GAUDI_EVENT_HBM1_SPI_1: @@ -7432,8 +7426,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, dev_err(hdev->dev, "hard reset required due to %s\n", gaudi_irq_map_table[event_type].name); - if (hdev->hard_reset_on_fw_events) - hl_device_reset(hdev, true, false); + goto reset_device; } else { hl_fw_unmask_irq(hdev, event_type); } @@ -7455,8 +7448,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, dev_err(hdev->dev, "hard reset required due to %s\n", gaudi_irq_map_table[event_type].name); - if (hdev->hard_reset_on_fw_events) - hl_device_reset(hdev, true, false); + goto reset_device; } else { hl_fw_unmask_irq(hdev, event_type); } @@ -7525,9 +7517,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, case GAUDI_EVENT_RAZWI_OR_ADC_SW: gaudi_print_irq_info(hdev, event_type, true); - if (hdev->hard_reset_on_fw_events) - hl_device_reset(hdev, true, false); - break; + goto reset_device; case GAUDI_EVENT_TPC0_BMON_SPMU: case GAUDI_EVENT_TPC1_BMON_SPMU: @@ -7564,17 +7554,21 @@ static void gaudi_handle_eqe(struct hl_device *hdev, case GAUDI_EVENT_PKT_QUEUE_OUT_SYNC: gaudi_print_irq_info(hdev, event_type, false); gaudi_print_out_of_sync_info(hdev, &eq_entry->pkt_sync_err); - if (hdev->hard_reset_on_fw_events) - hl_device_reset(hdev, true, false); - else - hl_fw_unmask_irq(hdev, event_type); - break; + goto reset_device; default: dev_err(hdev->dev, "Received invalid H/W interrupt %d\n", event_type); break; } + + return; + +reset_device: + if (hdev->hard_reset_on_fw_events) + hl_device_reset(hdev, HL_RESET_HARD); + else + hl_fw_unmask_irq(hdev, event_type); } static void *gaudi_get_events_stat(struct hl_device *hdev, bool aggregate, @@ -7625,7 +7619,7 @@ static int gaudi_mmu_invalidate_cache(struct hl_device *hdev, bool is_hard, if (rc) { dev_err_ratelimited(hdev->dev, "MMU cache invalidation timeout\n"); - hl_device_reset(hdev, true, false); + hl_device_reset(hdev, HL_RESET_HARD); } return rc; @@ -7674,7 +7668,7 @@ static int gaudi_mmu_invalidate_cache_range(struct hl_device *hdev, if (rc) { dev_err_ratelimited(hdev->dev, "MMU cache invalidation timeout\n"); - hl_device_reset(hdev, true, false); + hl_device_reset(hdev, HL_RESET_HARD); } return rc; diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 1eaf9c06227c..452bef461fe4 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -4712,7 +4712,7 @@ void goya_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entry) case GOYA_ASYNC_EVENT_ID_PSOC_GPIO_05_SW_RESET: goya_print_irq_info(hdev, event_type, false); if (hdev->hard_reset_on_fw_events) - hl_device_reset(hdev, true, false); + hl_device_reset(hdev, HL_RESET_HARD); break; case GOYA_ASYNC_EVENT_ID_PCIE_DEC: @@ -4772,7 +4772,7 @@ void goya_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entry) goya_print_irq_info(hdev, event_type, false); goya_print_out_of_sync_info(hdev, &eq_entry->pkt_sync_err); if (hdev->hard_reset_on_fw_events) - hl_device_reset(hdev, true, false); + hl_device_reset(hdev, HL_RESET_HARD); else hl_fw_unmask_irq(hdev, event_type); break; @@ -5106,7 +5106,7 @@ static int goya_mmu_invalidate_cache(struct hl_device *hdev, bool is_hard, if (rc) { dev_err_ratelimited(hdev->dev, "MMU cache invalidation timeout\n"); - hl_device_reset(hdev, true, false); + hl_device_reset(hdev, HL_RESET_HARD); } return rc; @@ -5157,7 +5157,7 @@ static int goya_mmu_invalidate_cache_range(struct hl_device *hdev, if (rc) { dev_err_ratelimited(hdev->dev, "MMU cache invalidation timeout\n"); - hl_device_reset(hdev, true, false); + hl_device_reset(hdev, HL_RESET_HARD); } return rc; -- cgit v1.2.3 From 99cb017e728227f5c046a044a6acec088f68a1c8 Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Wed, 24 Feb 2021 12:42:01 +0200 Subject: habanalabs: update hl_boot_if.h Update to the latest version of the file as supplied by the F/W. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/include/common/hl_boot_if.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/misc/habanalabs/include/common/hl_boot_if.h b/drivers/misc/habanalabs/include/common/hl_boot_if.h index e87f5a98e193..d17185b6aea9 100644 --- a/drivers/misc/habanalabs/include/common/hl_boot_if.h +++ b/drivers/misc/habanalabs/include/common/hl_boot_if.h @@ -170,6 +170,15 @@ * is set to the PI counter. * Initialized in: linux * + * CPU_BOOT_DEV_STS0_FW_LD_COM_EN Flexible FW loading communication + * protocol is enabled. + * Initialized in: preboot + * + * CPU_BOOT_DEV_STS0_FW_IATU_CONF_EN FW iATU configuration is enabled. + * This bit if set, means the iATU has been + * configured and is ready for use. + * Initialized in: ppboot + * * CPU_BOOT_DEV_STS0_ENABLED Device status register enabled. * This is a main indication that the * running FW populates the device status @@ -195,6 +204,8 @@ #define CPU_BOOT_DEV_STS0_CLK_GATE_EN (1 << 13) #define CPU_BOOT_DEV_STS0_HBM_ECC_EN (1 << 14) #define CPU_BOOT_DEV_STS0_PKT_PI_ACK_EN (1 << 15) +#define CPU_BOOT_DEV_STS0_FW_LD_COM_EN (1 << 16) +#define CPU_BOOT_DEV_STS0_FW_IATU_CONF_EN (1 << 17) #define CPU_BOOT_DEV_STS0_ENABLED (1 << 31) enum cpu_boot_status { -- cgit v1.2.3 From dd0a25c77a00e2b10d7520af31cfac949e51bbba Mon Sep 17 00:00:00 2001 From: Yang Li Date: Tue, 23 Feb 2021 17:12:24 +0800 Subject: habanalabs: Switch to using the new API kobj_to_dev() fixed the following coccicheck: ./drivers/misc/habanalabs/common/sysfs.c:347:60-61: WARNING opportunity for kobj_to_dev() Reported-by: Abaci Robot Signed-off-by: Yang Li Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/habanalabs/common/sysfs.c b/drivers/misc/habanalabs/common/sysfs.c index 9bd13bdc1ba9..f37634cf8b65 100644 --- a/drivers/misc/habanalabs/common/sysfs.c +++ b/drivers/misc/habanalabs/common/sysfs.c @@ -344,7 +344,7 @@ static ssize_t eeprom_read_handler(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t offset, size_t max_size) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct hl_device *hdev = dev_get_drvdata(dev); char *data; int rc; -- cgit v1.2.3 From a5778d10a12da26de55f88a9d03cbea78f73f8c4 Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Wed, 24 Feb 2021 11:51:40 +0200 Subject: habanalabs: debugfs access to user mapped host addresses In order to have a better debuggability we allow debugfs access to user mmu mapped host memory. Non-user host memory access will be rejected. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/debugfs.c | 87 ++++++++++++++++++++++------- drivers/misc/habanalabs/common/habanalabs.h | 12 ++-- drivers/misc/habanalabs/common/mmu/mmu.c | 2 + drivers/misc/habanalabs/gaudi/gaudi.c | 40 ++++++++++--- drivers/misc/habanalabs/goya/goya.c | 44 ++++++++++++--- 5 files changed, 144 insertions(+), 41 deletions(-) diff --git a/drivers/misc/habanalabs/common/debugfs.c b/drivers/misc/habanalabs/common/debugfs.c index fd3135c422b6..33de54092543 100644 --- a/drivers/misc/habanalabs/common/debugfs.c +++ b/drivers/misc/habanalabs/common/debugfs.c @@ -457,21 +457,58 @@ out: return false; } -static int device_va_to_pa(struct hl_device *hdev, u64 virt_addr, - u64 *phys_addr) +static int device_va_to_pa(struct hl_device *hdev, u64 virt_addr, u32 size, + u64 *phys_addr) { + struct hl_vm_phys_pg_pack *phys_pg_pack; struct hl_ctx *ctx = hdev->compute_ctx; - int rc = 0; + struct hl_vm_hash_node *hnode; + struct hl_userptr *userptr; + enum vm_type_t *vm_type; + bool valid = false; + u64 end_address; + u32 range_size; + int i, rc = 0; if (!ctx) { dev_err(hdev->dev, "no ctx available\n"); return -EINVAL; } + /* Verify address is mapped */ + mutex_lock(&ctx->mem_hash_lock); + hash_for_each(ctx->mem_hash, i, hnode, node) { + vm_type = hnode->ptr; + + if (*vm_type == VM_TYPE_USERPTR) { + userptr = hnode->ptr; + range_size = userptr->size; + } else { + phys_pg_pack = hnode->ptr; + range_size = phys_pg_pack->total_size; + } + + end_address = virt_addr + size; + if ((virt_addr >= hnode->vaddr) && + (end_address <= hnode->vaddr + range_size)) { + valid = true; + break; + } + } + mutex_unlock(&ctx->mem_hash_lock); + + if (!valid) { + dev_err(hdev->dev, + "virt addr 0x%llx is not mapped\n", + virt_addr); + return -EINVAL; + } + rc = hl_mmu_va_to_pa(ctx, virt_addr, phys_addr); if (rc) { - dev_err(hdev->dev, "virt addr 0x%llx is not mapped to phys addr\n", - virt_addr); + dev_err(hdev->dev, + "virt addr 0x%llx is not mapped to phys addr\n", + virt_addr); rc = -EINVAL; } @@ -483,10 +520,11 @@ static ssize_t hl_data_read32(struct file *f, char __user *buf, { struct hl_dbg_device_entry *entry = file_inode(f)->i_private; struct hl_device *hdev = entry->hdev; - char tmp_buf[32]; u64 addr = entry->addr; - u32 val; + bool user_address; + char tmp_buf[32]; ssize_t rc; + u32 val; if (atomic_read(&hdev->in_reset)) { dev_warn_ratelimited(hdev->dev, "Can't read during reset\n"); @@ -496,13 +534,14 @@ static ssize_t hl_data_read32(struct file *f, char __user *buf, if (*ppos) return 0; - if (hl_is_device_va(hdev, addr)) { - rc = device_va_to_pa(hdev, addr, &addr); + user_address = hl_is_device_va(hdev, addr); + if (user_address) { + rc = device_va_to_pa(hdev, addr, sizeof(val), &addr); if (rc) return rc; } - rc = hdev->asic_funcs->debugfs_read32(hdev, addr, &val); + rc = hdev->asic_funcs->debugfs_read32(hdev, addr, user_address, &val); if (rc) { dev_err(hdev->dev, "Failed to read from 0x%010llx\n", addr); return rc; @@ -519,6 +558,7 @@ static ssize_t hl_data_write32(struct file *f, const char __user *buf, struct hl_dbg_device_entry *entry = file_inode(f)->i_private; struct hl_device *hdev = entry->hdev; u64 addr = entry->addr; + bool user_address; u32 value; ssize_t rc; @@ -531,13 +571,14 @@ static ssize_t hl_data_write32(struct file *f, const char __user *buf, if (rc) return rc; - if (hl_is_device_va(hdev, addr)) { - rc = device_va_to_pa(hdev, addr, &addr); + user_address = hl_is_device_va(hdev, addr); + if (user_address) { + rc = device_va_to_pa(hdev, addr, sizeof(value), &addr); if (rc) return rc; } - rc = hdev->asic_funcs->debugfs_write32(hdev, addr, value); + rc = hdev->asic_funcs->debugfs_write32(hdev, addr, user_address, value); if (rc) { dev_err(hdev->dev, "Failed to write 0x%08x to 0x%010llx\n", value, addr); @@ -552,21 +593,23 @@ static ssize_t hl_data_read64(struct file *f, char __user *buf, { struct hl_dbg_device_entry *entry = file_inode(f)->i_private; struct hl_device *hdev = entry->hdev; - char tmp_buf[32]; u64 addr = entry->addr; - u64 val; + bool user_address; + char tmp_buf[32]; ssize_t rc; + u64 val; if (*ppos) return 0; - if (hl_is_device_va(hdev, addr)) { - rc = device_va_to_pa(hdev, addr, &addr); + user_address = hl_is_device_va(hdev, addr); + if (user_address) { + rc = device_va_to_pa(hdev, addr, sizeof(val), &addr); if (rc) return rc; } - rc = hdev->asic_funcs->debugfs_read64(hdev, addr, &val); + rc = hdev->asic_funcs->debugfs_read64(hdev, addr, user_address, &val); if (rc) { dev_err(hdev->dev, "Failed to read from 0x%010llx\n", addr); return rc; @@ -583,6 +626,7 @@ static ssize_t hl_data_write64(struct file *f, const char __user *buf, struct hl_dbg_device_entry *entry = file_inode(f)->i_private; struct hl_device *hdev = entry->hdev; u64 addr = entry->addr; + bool user_address; u64 value; ssize_t rc; @@ -590,13 +634,14 @@ static ssize_t hl_data_write64(struct file *f, const char __user *buf, if (rc) return rc; - if (hl_is_device_va(hdev, addr)) { - rc = device_va_to_pa(hdev, addr, &addr); + user_address = hl_is_device_va(hdev, addr); + if (user_address) { + rc = device_va_to_pa(hdev, addr, sizeof(value), &addr); if (rc) return rc; } - rc = hdev->asic_funcs->debugfs_write64(hdev, addr, value); + rc = hdev->asic_funcs->debugfs_write64(hdev, addr, user_address, value); if (rc) { dev_err(hdev->dev, "Failed to write 0x%016llx to 0x%010llx\n", value, addr); diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 780adde16387..2dcefd6485e5 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -969,10 +969,14 @@ struct hl_asic_funcs { void (*update_eq_ci)(struct hl_device *hdev, u32 val); int (*context_switch)(struct hl_device *hdev, u32 asid); void (*restore_phase_topology)(struct hl_device *hdev); - int (*debugfs_read32)(struct hl_device *hdev, u64 addr, u32 *val); - int (*debugfs_write32)(struct hl_device *hdev, u64 addr, u32 val); - int (*debugfs_read64)(struct hl_device *hdev, u64 addr, u64 *val); - int (*debugfs_write64)(struct hl_device *hdev, u64 addr, u64 val); + int (*debugfs_read32)(struct hl_device *hdev, u64 addr, + bool user_address, u32 *val); + int (*debugfs_write32)(struct hl_device *hdev, u64 addr, + bool user_address, u32 val); + int (*debugfs_read64)(struct hl_device *hdev, u64 addr, + bool user_address, u64 *val); + int (*debugfs_write64)(struct hl_device *hdev, u64 addr, + bool user_address, u64 val); void (*add_device_attr)(struct hl_device *hdev, struct attribute_group *dev_attr_grp); void (*handle_eqe)(struct hl_device *hdev, diff --git a/drivers/misc/habanalabs/common/mmu/mmu.c b/drivers/misc/habanalabs/common/mmu/mmu.c index 93c9e5f587e1..ae1778103e23 100644 --- a/drivers/misc/habanalabs/common/mmu/mmu.c +++ b/drivers/misc/habanalabs/common/mmu/mmu.c @@ -532,6 +532,8 @@ int hl_mmu_va_to_pa(struct hl_ctx *ctx, u64 virt_addr, u64 *phys_addr) struct hl_mmu_hop_info hops; int rc; + memset(&hops, 0, sizeof(hops)); + rc = hl_mmu_get_tlb_info(ctx, virt_addr, &hops); if (rc) return rc; diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 37e3f4cd05c0..8be75f7c97f8 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -5911,13 +5911,16 @@ static void gaudi_restore_phase_topology(struct hl_device *hdev) } -static int gaudi_debugfs_read32(struct hl_device *hdev, u64 addr, u32 *val) +static int gaudi_debugfs_read32(struct hl_device *hdev, u64 addr, + bool user_address, u32 *val) { struct asic_fixed_properties *prop = &hdev->asic_prop; struct gaudi_device *gaudi = hdev->asic_specific; - u64 hbm_bar_addr; + u64 hbm_bar_addr, host_phys_end; int rc = 0; + host_phys_end = HOST_PHYS_BASE + HOST_PHYS_SIZE; + if ((addr >= CFG_BASE) && (addr < CFG_BASE + CFG_SIZE)) { if ((gaudi->hw_cap_initialized & HW_CAP_CLK_GATE) && @@ -5949,6 +5952,9 @@ static int gaudi_debugfs_read32(struct hl_device *hdev, u64 addr, u32 *val) } if (hbm_bar_addr == U64_MAX) rc = -EIO; + } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end && + user_address && !iommu_present(&pci_bus_type)) { + *val = *(u32 *) phys_to_virt(addr - HOST_PHYS_BASE); } else { rc = -EFAULT; } @@ -5956,13 +5962,16 @@ static int gaudi_debugfs_read32(struct hl_device *hdev, u64 addr, u32 *val) return rc; } -static int gaudi_debugfs_write32(struct hl_device *hdev, u64 addr, u32 val) +static int gaudi_debugfs_write32(struct hl_device *hdev, u64 addr, + bool user_address, u32 val) { struct asic_fixed_properties *prop = &hdev->asic_prop; struct gaudi_device *gaudi = hdev->asic_specific; - u64 hbm_bar_addr; + u64 hbm_bar_addr, host_phys_end; int rc = 0; + host_phys_end = HOST_PHYS_BASE + HOST_PHYS_SIZE; + if ((addr >= CFG_BASE) && (addr < CFG_BASE + CFG_SIZE)) { if ((gaudi->hw_cap_initialized & HW_CAP_CLK_GATE) && @@ -5994,6 +6003,9 @@ static int gaudi_debugfs_write32(struct hl_device *hdev, u64 addr, u32 val) } if (hbm_bar_addr == U64_MAX) rc = -EIO; + } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end && + user_address && !iommu_present(&pci_bus_type)) { + *(u32 *) phys_to_virt(addr - HOST_PHYS_BASE) = val; } else { rc = -EFAULT; } @@ -6001,13 +6013,16 @@ static int gaudi_debugfs_write32(struct hl_device *hdev, u64 addr, u32 val) return rc; } -static int gaudi_debugfs_read64(struct hl_device *hdev, u64 addr, u64 *val) +static int gaudi_debugfs_read64(struct hl_device *hdev, u64 addr, + bool user_address, u64 *val) { struct asic_fixed_properties *prop = &hdev->asic_prop; struct gaudi_device *gaudi = hdev->asic_specific; - u64 hbm_bar_addr; + u64 hbm_bar_addr, host_phys_end; int rc = 0; + host_phys_end = HOST_PHYS_BASE + HOST_PHYS_SIZE; + if ((addr >= CFG_BASE) && (addr <= CFG_BASE + CFG_SIZE - sizeof(u64))) { if ((gaudi->hw_cap_initialized & HW_CAP_CLK_GATE) && @@ -6043,6 +6058,9 @@ static int gaudi_debugfs_read64(struct hl_device *hdev, u64 addr, u64 *val) } if (hbm_bar_addr == U64_MAX) rc = -EIO; + } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end && + user_address && !iommu_present(&pci_bus_type)) { + *val = *(u64 *) phys_to_virt(addr - HOST_PHYS_BASE); } else { rc = -EFAULT; } @@ -6050,13 +6068,16 @@ static int gaudi_debugfs_read64(struct hl_device *hdev, u64 addr, u64 *val) return rc; } -static int gaudi_debugfs_write64(struct hl_device *hdev, u64 addr, u64 val) +static int gaudi_debugfs_write64(struct hl_device *hdev, u64 addr, + bool user_address, u64 val) { struct asic_fixed_properties *prop = &hdev->asic_prop; struct gaudi_device *gaudi = hdev->asic_specific; - u64 hbm_bar_addr; + u64 hbm_bar_addr, host_phys_end; int rc = 0; + host_phys_end = HOST_PHYS_BASE + HOST_PHYS_SIZE; + if ((addr >= CFG_BASE) && (addr <= CFG_BASE + CFG_SIZE - sizeof(u64))) { if ((gaudi->hw_cap_initialized & HW_CAP_CLK_GATE) && @@ -6091,6 +6112,9 @@ static int gaudi_debugfs_write64(struct hl_device *hdev, u64 addr, u64 val) } if (hbm_bar_addr == U64_MAX) rc = -EIO; + } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end && + user_address && !iommu_present(&pci_bus_type)) { + *(u64 *) phys_to_virt(addr - HOST_PHYS_BASE) = val; } else { rc = -EFAULT; } diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 452bef461fe4..9e7531167c73 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -4101,12 +4101,15 @@ static void goya_clear_sm_regs(struct hl_device *hdev) * lead to undefined behavior and therefore, should be done with extreme care * */ -static int goya_debugfs_read32(struct hl_device *hdev, u64 addr, u32 *val) +static int goya_debugfs_read32(struct hl_device *hdev, u64 addr, + bool user_address, u32 *val) { struct asic_fixed_properties *prop = &hdev->asic_prop; - u64 ddr_bar_addr; + u64 ddr_bar_addr, host_phys_end; int rc = 0; + host_phys_end = HOST_PHYS_BASE + HOST_PHYS_SIZE; + if ((addr >= CFG_BASE) && (addr < CFG_BASE + CFG_SIZE)) { *val = RREG32(addr - CFG_BASE); @@ -4132,6 +4135,10 @@ static int goya_debugfs_read32(struct hl_device *hdev, u64 addr, u32 *val) if (ddr_bar_addr == U64_MAX) rc = -EIO; + } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end && + user_address && !iommu_present(&pci_bus_type)) { + *val = *(u32 *) phys_to_virt(addr - HOST_PHYS_BASE); + } else { rc = -EFAULT; } @@ -4154,12 +4161,15 @@ static int goya_debugfs_read32(struct hl_device *hdev, u64 addr, u32 *val) * lead to undefined behavior and therefore, should be done with extreme care * */ -static int goya_debugfs_write32(struct hl_device *hdev, u64 addr, u32 val) +static int goya_debugfs_write32(struct hl_device *hdev, u64 addr, + bool user_address, u32 val) { struct asic_fixed_properties *prop = &hdev->asic_prop; - u64 ddr_bar_addr; + u64 ddr_bar_addr, host_phys_end; int rc = 0; + host_phys_end = HOST_PHYS_BASE + HOST_PHYS_SIZE; + if ((addr >= CFG_BASE) && (addr < CFG_BASE + CFG_SIZE)) { WREG32(addr - CFG_BASE, val); @@ -4185,6 +4195,10 @@ static int goya_debugfs_write32(struct hl_device *hdev, u64 addr, u32 val) if (ddr_bar_addr == U64_MAX) rc = -EIO; + } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end && + user_address && !iommu_present(&pci_bus_type)) { + *(u32 *) phys_to_virt(addr - HOST_PHYS_BASE) = val; + } else { rc = -EFAULT; } @@ -4192,12 +4206,15 @@ static int goya_debugfs_write32(struct hl_device *hdev, u64 addr, u32 val) return rc; } -static int goya_debugfs_read64(struct hl_device *hdev, u64 addr, u64 *val) +static int goya_debugfs_read64(struct hl_device *hdev, u64 addr, + bool user_address, u64 *val) { struct asic_fixed_properties *prop = &hdev->asic_prop; - u64 ddr_bar_addr; + u64 ddr_bar_addr, host_phys_end; int rc = 0; + host_phys_end = HOST_PHYS_BASE + HOST_PHYS_SIZE; + if ((addr >= CFG_BASE) && (addr <= CFG_BASE + CFG_SIZE - sizeof(u64))) { u32 val_l = RREG32(addr - CFG_BASE); u32 val_h = RREG32(addr + sizeof(u32) - CFG_BASE); @@ -4227,6 +4244,10 @@ static int goya_debugfs_read64(struct hl_device *hdev, u64 addr, u64 *val) if (ddr_bar_addr == U64_MAX) rc = -EIO; + } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end && + user_address && !iommu_present(&pci_bus_type)) { + *val = *(u64 *) phys_to_virt(addr - HOST_PHYS_BASE); + } else { rc = -EFAULT; } @@ -4234,12 +4255,15 @@ static int goya_debugfs_read64(struct hl_device *hdev, u64 addr, u64 *val) return rc; } -static int goya_debugfs_write64(struct hl_device *hdev, u64 addr, u64 val) +static int goya_debugfs_write64(struct hl_device *hdev, u64 addr, + bool user_address, u64 val) { struct asic_fixed_properties *prop = &hdev->asic_prop; - u64 ddr_bar_addr; + u64 ddr_bar_addr, host_phys_end; int rc = 0; + host_phys_end = HOST_PHYS_BASE + HOST_PHYS_SIZE; + if ((addr >= CFG_BASE) && (addr <= CFG_BASE + CFG_SIZE - sizeof(u64))) { WREG32(addr - CFG_BASE, lower_32_bits(val)); WREG32(addr + sizeof(u32) - CFG_BASE, upper_32_bits(val)); @@ -4267,6 +4291,10 @@ static int goya_debugfs_write64(struct hl_device *hdev, u64 addr, u64 val) if (ddr_bar_addr == U64_MAX) rc = -EIO; + } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end && + user_address && !iommu_present(&pci_bus_type)) { + *(u64 *) phys_to_virt(addr - HOST_PHYS_BASE) = val; + } else { rc = -EFAULT; } -- cgit v1.2.3 From 2ea09537ad7747944c20ff70078be304a71b3e33 Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Wed, 3 Mar 2021 13:23:47 +0200 Subject: habanalabs/gaudi: reset device upon BMC request In case the BMC of the devices' box wants to initiate a reset of a specific device, it must go through driver. Once driver will receive the request it will initiate a hard reset flow. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 4 ++++ drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h | 1 + drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 8be75f7c97f8..099c51350be6 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -7575,6 +7575,10 @@ static void gaudi_handle_eqe(struct hl_device *hdev, event_type, cause); break; + case GAUDI_EVENT_BMC_RESET_CMD: + gaudi_print_irq_info(hdev, event_type, false); + goto reset_device; + case GAUDI_EVENT_PKT_QUEUE_OUT_SYNC: gaudi_print_irq_info(hdev, event_type, false); gaudi_print_out_of_sync_info(hdev, &eq_entry->pkt_sync_err); diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h b/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h index 0a0fa57024f8..25f835ba2cd6 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h @@ -303,6 +303,7 @@ enum gaudi_async_event_id { GAUDI_EVENT_NIC3_QP1 = 619, GAUDI_EVENT_NIC4_QP0 = 620, GAUDI_EVENT_NIC4_QP1 = 621, + GAUDI_EVENT_BMC_RESET_CMD = 646, GAUDI_EVENT_PKT_QUEUE_OUT_SYNC = 647, GAUDI_EVENT_FIX_POWER_ENV_S = 658, GAUDI_EVENT_FIX_POWER_ENV_E = 659, diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h b/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h index 9106395eb920..079be1fb8f70 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h @@ -670,7 +670,7 @@ static struct gaudi_async_events_ids_map gaudi_irq_map_table[] = { { .fc_id = 643, .cpu_id = 492, .valid = 0, .name = "" }, { .fc_id = 644, .cpu_id = 493, .valid = 0, .name = "" }, { .fc_id = 645, .cpu_id = 494, .valid = 0, .name = "" }, - { .fc_id = 646, .cpu_id = 495, .valid = 0, .name = "" }, + { .fc_id = 646, .cpu_id = 495, .valid = 1, .name = "BMC_RST_CMD" }, { .fc_id = 647, .cpu_id = 496, .valid = 0, .name = "" }, { .fc_id = 648, .cpu_id = 497, .valid = 0, .name = "" }, { .fc_id = 649, .cpu_id = 498, .valid = 0, .name = "" }, -- cgit v1.2.3 From 12e66a172773320e66df29908d7533f4f4663938 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Mon, 8 Mar 2021 18:06:57 +0200 Subject: habanalabs/gaudi: always use single-msi mode The device can get into deadlock in case it use indirect mode for MSI interrupts (multi-msi) and have hard-reset during interrupt storm. To prevent that, always use direct mode which means single-msi mode. The F/W will prevent the host from writing to the indirect MSI registers to prevent any malicious user from causing this scenario. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 099c51350be6..0bcee675e1db 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -1766,8 +1766,7 @@ static int gaudi_enable_msi(struct hl_device *hdev) if (gaudi->hw_cap_initialized & HW_CAP_MSI) return 0; - rc = pci_alloc_irq_vectors(hdev->pdev, 1, GAUDI_MSI_ENTRIES, - PCI_IRQ_MSI); + rc = pci_alloc_irq_vectors(hdev->pdev, 1, 1, PCI_IRQ_MSI); if (rc < 0) { dev_err(hdev->dev, "MSI: Failed to enable support %d\n", rc); return rc; -- cgit v1.2.3 From f951eb08a96b43fd2a8c3e9c6293fc2e7b6750bb Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Wed, 10 Mar 2021 08:50:01 +0200 Subject: habanalabs/gaudi: unsecure TPC cfg status registers Unsecure relevant registers as TPC engine need access to TPC status. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi_security.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/misc/habanalabs/gaudi/gaudi_security.c b/drivers/misc/habanalabs/gaudi/gaudi_security.c index 7085f45814ae..9a706c5980ef 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi_security.c +++ b/drivers/misc/habanalabs/gaudi/gaudi_security.c @@ -9556,7 +9556,6 @@ static void gaudi_init_tpc_protection_bits(struct hl_device *hdev) mask = 1U << ((mmTPC0_CFG_PROT & 0x7F) >> 2); mask |= 1U << ((mmTPC0_CFG_VFLAGS & 0x7F) >> 2); mask |= 1U << ((mmTPC0_CFG_SFLAGS & 0x7F) >> 2); - mask |= 1U << ((mmTPC0_CFG_STATUS & 0x7F) >> 2); mask |= 1U << ((mmTPC0_CFG_CFG_BASE_ADDRESS_HIGH & 0x7F) >> 2); mask |= 1U << ((mmTPC0_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2); mask |= 1U << ((mmTPC0_CFG_TPC_STALL & 0x7F) >> 2); @@ -10011,7 +10010,6 @@ static void gaudi_init_tpc_protection_bits(struct hl_device *hdev) mask = 1U << ((mmTPC1_CFG_PROT & 0x7F) >> 2); mask |= 1U << ((mmTPC1_CFG_VFLAGS & 0x7F) >> 2); mask |= 1U << ((mmTPC1_CFG_SFLAGS & 0x7F) >> 2); - mask |= 1U << ((mmTPC1_CFG_STATUS & 0x7F) >> 2); mask |= 1U << ((mmTPC1_CFG_CFG_BASE_ADDRESS_HIGH & 0x7F) >> 2); mask |= 1U << ((mmTPC1_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2); mask |= 1U << ((mmTPC1_CFG_TPC_STALL & 0x7F) >> 2); @@ -10465,7 +10463,6 @@ static void gaudi_init_tpc_protection_bits(struct hl_device *hdev) mask = 1U << ((mmTPC2_CFG_PROT & 0x7F) >> 2); mask |= 1U << ((mmTPC2_CFG_VFLAGS & 0x7F) >> 2); mask |= 1U << ((mmTPC2_CFG_SFLAGS & 0x7F) >> 2); - mask |= 1U << ((mmTPC2_CFG_STATUS & 0x7F) >> 2); mask |= 1U << ((mmTPC2_CFG_CFG_BASE_ADDRESS_HIGH & 0x7F) >> 2); mask |= 1U << ((mmTPC2_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2); mask |= 1U << ((mmTPC2_CFG_TPC_STALL & 0x7F) >> 2); @@ -10919,7 +10916,6 @@ static void gaudi_init_tpc_protection_bits(struct hl_device *hdev) mask = 1U << ((mmTPC3_CFG_PROT & 0x7F) >> 2); mask |= 1U << ((mmTPC3_CFG_VFLAGS & 0x7F) >> 2); mask |= 1U << ((mmTPC3_CFG_SFLAGS & 0x7F) >> 2); - mask |= 1U << ((mmTPC3_CFG_STATUS & 0x7F) >> 2); mask |= 1U << ((mmTPC3_CFG_CFG_BASE_ADDRESS_HIGH & 0x7F) >> 2); mask |= 1U << ((mmTPC3_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2); mask |= 1U << ((mmTPC3_CFG_TPC_STALL & 0x7F) >> 2); @@ -11373,7 +11369,6 @@ static void gaudi_init_tpc_protection_bits(struct hl_device *hdev) mask = 1U << ((mmTPC4_CFG_PROT & 0x7F) >> 2); mask |= 1U << ((mmTPC4_CFG_VFLAGS & 0x7F) >> 2); mask |= 1U << ((mmTPC4_CFG_SFLAGS & 0x7F) >> 2); - mask |= 1U << ((mmTPC4_CFG_STATUS & 0x7F) >> 2); mask |= 1U << ((mmTPC4_CFG_CFG_BASE_ADDRESS_HIGH & 0x7F) >> 2); mask |= 1U << ((mmTPC4_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2); mask |= 1U << ((mmTPC4_CFG_TPC_STALL & 0x7F) >> 2); @@ -11827,7 +11822,6 @@ static void gaudi_init_tpc_protection_bits(struct hl_device *hdev) mask = 1U << ((mmTPC5_CFG_PROT & 0x7F) >> 2); mask |= 1U << ((mmTPC5_CFG_VFLAGS & 0x7F) >> 2); mask |= 1U << ((mmTPC5_CFG_SFLAGS & 0x7F) >> 2); - mask |= 1U << ((mmTPC5_CFG_STATUS & 0x7F) >> 2); mask |= 1U << ((mmTPC5_CFG_CFG_BASE_ADDRESS_HIGH & 0x7F) >> 2); mask |= 1U << ((mmTPC5_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2); mask |= 1U << ((mmTPC5_CFG_TPC_STALL & 0x7F) >> 2); @@ -12283,7 +12277,6 @@ static void gaudi_init_tpc_protection_bits(struct hl_device *hdev) mask = 1U << ((mmTPC6_CFG_PROT & 0x7F) >> 2); mask |= 1U << ((mmTPC6_CFG_VFLAGS & 0x7F) >> 2); mask |= 1U << ((mmTPC6_CFG_SFLAGS & 0x7F) >> 2); - mask |= 1U << ((mmTPC6_CFG_STATUS & 0x7F) >> 2); mask |= 1U << ((mmTPC6_CFG_CFG_BASE_ADDRESS_HIGH & 0x7F) >> 2); mask |= 1U << ((mmTPC6_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2); mask |= 1U << ((mmTPC6_CFG_TPC_STALL & 0x7F) >> 2); @@ -12739,7 +12732,6 @@ static void gaudi_init_tpc_protection_bits(struct hl_device *hdev) mask = 1U << ((mmTPC7_CFG_PROT & 0x7F) >> 2); mask |= 1U << ((mmTPC7_CFG_VFLAGS & 0x7F) >> 2); mask |= 1U << ((mmTPC7_CFG_SFLAGS & 0x7F) >> 2); - mask |= 1U << ((mmTPC7_CFG_STATUS & 0x7F) >> 2); mask |= 1U << ((mmTPC7_CFG_CFG_BASE_ADDRESS_HIGH & 0x7F) >> 2); mask |= 1U << ((mmTPC7_CFG_CFG_SUBTRACT_VALUE & 0x7F) >> 2); mask |= 1U << ((mmTPC7_CFG_TPC_STALL & 0x7F) >> 2); -- cgit v1.2.3 From d661d79930b41d3103c0cc959757deec4421e8ff Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Tue, 9 Mar 2021 14:45:04 +0200 Subject: habanalabs/gaudi: Update async events header Update with latest version from the Firmware team. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 2 +- .../habanalabs/include/gaudi/gaudi_async_events.h | 2 +- .../include/gaudi/gaudi_async_ids_map_extended.h | 35 ++++++++++++++-------- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 0bcee675e1db..a65ae0dbdb92 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -7574,7 +7574,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, event_type, cause); break; - case GAUDI_EVENT_BMC_RESET_CMD: + case GAUDI_EVENT_DEV_RESET_REQ: gaudi_print_irq_info(hdev, event_type, false); goto reset_device; diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h b/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h index 25f835ba2cd6..e8651abf84f2 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h @@ -303,7 +303,7 @@ enum gaudi_async_event_id { GAUDI_EVENT_NIC3_QP1 = 619, GAUDI_EVENT_NIC4_QP0 = 620, GAUDI_EVENT_NIC4_QP1 = 621, - GAUDI_EVENT_BMC_RESET_CMD = 646, + GAUDI_EVENT_DEV_RESET_REQ = 646, GAUDI_EVENT_PKT_QUEUE_OUT_SYNC = 647, GAUDI_EVENT_FIX_POWER_ENV_S = 658, GAUDI_EVENT_FIX_POWER_ENV_E = 659, diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h b/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h index 079be1fb8f70..3dc79c131805 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h @@ -670,18 +670,29 @@ static struct gaudi_async_events_ids_map gaudi_irq_map_table[] = { { .fc_id = 643, .cpu_id = 492, .valid = 0, .name = "" }, { .fc_id = 644, .cpu_id = 493, .valid = 0, .name = "" }, { .fc_id = 645, .cpu_id = 494, .valid = 0, .name = "" }, - { .fc_id = 646, .cpu_id = 495, .valid = 1, .name = "BMC_RST_CMD" }, - { .fc_id = 647, .cpu_id = 496, .valid = 0, .name = "" }, - { .fc_id = 648, .cpu_id = 497, .valid = 0, .name = "" }, - { .fc_id = 649, .cpu_id = 498, .valid = 0, .name = "" }, - { .fc_id = 650, .cpu_id = 499, .valid = 0, .name = "" }, - { .fc_id = 651, .cpu_id = 500, .valid = 0, .name = "" }, - { .fc_id = 652, .cpu_id = 501, .valid = 0, .name = "" }, - { .fc_id = 653, .cpu_id = 502, .valid = 0, .name = "" }, - { .fc_id = 654, .cpu_id = 503, .valid = 0, .name = "" }, - { .fc_id = 655, .cpu_id = 504, .valid = 0, .name = "" }, - { .fc_id = 656, .cpu_id = 505, .valid = 0, .name = "" }, - { .fc_id = 657, .cpu_id = 506, .valid = 1, .name = "PKT_QUEUE_ASYNC" }, + { .fc_id = 646, .cpu_id = 495, .valid = 1, .name = "DEV_RESET_REQ" }, + { .fc_id = 647, .cpu_id = 496, .valid = 1, + .name = "PKT_QUEUE_OUT_SYNC" }, + { .fc_id = 648, .cpu_id = 497, .valid = 1, + .name = "STATUS_NIC0_ENG0" }, + { .fc_id = 649, .cpu_id = 498, .valid = 1, + .name = "STATUS_NIC0_ENG1" }, + { .fc_id = 650, .cpu_id = 499, .valid = 1, + .name = "STATUS_NIC1_ENG0" }, + { .fc_id = 651, .cpu_id = 500, .valid = 1, + .name = "STATUS_NIC1_ENG1" }, + { .fc_id = 652, .cpu_id = 501, .valid = 1, + .name = "STATUS_NIC2_ENG0" }, + { .fc_id = 653, .cpu_id = 502, .valid = 1, + .name = "STATUS_NIC2_ENG1" }, + { .fc_id = 654, .cpu_id = 503, .valid = 1, + .name = "STATUS_NIC3_ENG0" }, + { .fc_id = 655, .cpu_id = 504, .valid = 1, + .name = "STATUS_NIC3_ENG1" }, + { .fc_id = 656, .cpu_id = 505, .valid = 1, + .name = "STATUS_NIC4_ENG0" }, + { .fc_id = 657, .cpu_id = 506, .valid = 1, + .name = "STATUS_NIC4_ENG1" }, { .fc_id = 658, .cpu_id = 507, .valid = 1, .name = "FIX_POWER_ENV_S" }, { .fc_id = 659, .cpu_id = 508, .valid = 1, .name = "FIX_POWER_ENV_E" }, { .fc_id = 660, .cpu_id = 509, .valid = 1, -- cgit v1.2.3 From 2f6274e4773570ab763d5a588504ff35b908b2cf Mon Sep 17 00:00:00 2001 From: farah kassabri Date: Thu, 11 Mar 2021 11:24:57 +0200 Subject: habanalabs: avoid soft lockup bug upon mapping error Add a little sleep between page unmappings in case mapping of large number of host pages failed, in order to avoid soft lockup bug during the rollback. Signed-off-by: farah kassabri Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/memory.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/misc/habanalabs/common/memory.c b/drivers/misc/habanalabs/common/memory.c index 1b69573369cf..6530fddbbc21 100644 --- a/drivers/misc/habanalabs/common/memory.c +++ b/drivers/misc/habanalabs/common/memory.c @@ -857,6 +857,7 @@ static int map_phys_pg_pack(struct hl_ctx *ctx, u64 vaddr, u64 next_vaddr = vaddr, paddr, mapped_pg_cnt = 0, i; u32 page_size = phys_pg_pack->page_size; int rc = 0; + bool is_host_addr; for (i = 0 ; i < phys_pg_pack->npages ; i++) { paddr = phys_pg_pack->pages[i]; @@ -878,6 +879,8 @@ static int map_phys_pg_pack(struct hl_ctx *ctx, u64 vaddr, return 0; err: + is_host_addr = !hl_is_dram_va(hdev, vaddr); + next_vaddr = vaddr; for (i = 0 ; i < mapped_pg_cnt ; i++) { if (hl_mmu_unmap_page(ctx, next_vaddr, page_size, @@ -888,6 +891,17 @@ err: phys_pg_pack->pages[i], page_size); next_vaddr += page_size; + + /* + * unmapping on Palladium can be really long, so avoid a CPU + * soft lockup bug by sleeping a little between unmapping pages + * + * In addition, on host num of pages could be huge, + * because page size could be 4KB, so when unmapping host + * pages sleep every 32K pages to avoid soft lockup + */ + if (hdev->pldm || (is_host_addr && (i & 0x7FFF) == 0)) + usleep_range(50, 200); } return rc; @@ -921,9 +935,9 @@ static void unmap_phys_pg_pack(struct hl_ctx *ctx, u64 vaddr, * unmapping on Palladium can be really long, so avoid a CPU * soft lockup bug by sleeping a little between unmapping pages * - * In addition, when unmapping host memory we pass through - * the Linux kernel to unpin the pages and that takes a long - * time. Therefore, sleep every 32K pages to avoid soft lockup + * In addition, on host num of pages could be huge, + * because page size could be 4KB, so when unmapping host + * pages sleep every 32K pages to avoid soft lockup */ if (hdev->pldm || (is_host_addr && (i & 0x7FFF) == 0)) usleep_range(50, 200); -- cgit v1.2.3 From 8445dde1b9fb8025ef05c148966f384a4d014824 Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Thu, 18 Mar 2021 17:36:57 +0200 Subject: habanalabs: move relevant datapath work outside cs lock In order to shorten the time cs lock is being held, we move any possible work outside of the cs lock. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- .../misc/habanalabs/common/command_submission.c | 86 +++++++++++++--------- drivers/misc/habanalabs/common/device.c | 13 +++- drivers/misc/habanalabs/common/habanalabs.h | 4 + 3 files changed, 68 insertions(+), 35 deletions(-) diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index 720588aed28b..ba6d3e317255 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -84,6 +84,38 @@ int hl_gen_sob_mask(u16 sob_base, u8 sob_mask, u8 *mask) return 0; } +static void sob_reset_work(struct work_struct *work) +{ + struct hl_cs_compl *hl_cs_cmpl = + container_of(work, struct hl_cs_compl, sob_reset_work); + struct hl_device *hdev = hl_cs_cmpl->hdev; + + /* + * A signal CS can get completion while the corresponding wait + * for signal CS is on its way to the PQ. The wait for signal CS + * will get stuck if the signal CS incremented the SOB to its + * max value and there are no pending (submitted) waits on this + * SOB. + * We do the following to void this situation: + * 1. The wait for signal CS must get a ref for the signal CS as + * soon as possible in cs_ioctl_signal_wait() and put it + * before being submitted to the PQ but after it incremented + * the SOB refcnt in init_signal_wait_cs(). + * 2. Signal/Wait for signal CS will decrement the SOB refcnt + * here. + * These two measures guarantee that the wait for signal CS will + * reset the SOB upon completion rather than the signal CS and + * hence the above scenario is avoided. + */ + kref_put(&hl_cs_cmpl->hw_sob->kref, hl_sob_reset); + + if (hl_cs_cmpl->type == CS_TYPE_COLLECTIVE_WAIT) + hdev->asic_funcs->reset_sob_group(hdev, + hl_cs_cmpl->sob_group); + + kfree(hl_cs_cmpl); +} + static void hl_fence_release(struct kref *kref) { struct hl_fence *fence = @@ -109,28 +141,9 @@ static void hl_fence_release(struct kref *kref) hl_cs_cmpl->hw_sob->sob_id, hl_cs_cmpl->sob_val); - /* - * A signal CS can get completion while the corresponding wait - * for signal CS is on its way to the PQ. The wait for signal CS - * will get stuck if the signal CS incremented the SOB to its - * max value and there are no pending (submitted) waits on this - * SOB. - * We do the following to void this situation: - * 1. The wait for signal CS must get a ref for the signal CS as - * soon as possible in cs_ioctl_signal_wait() and put it - * before being submitted to the PQ but after it incremented - * the SOB refcnt in init_signal_wait_cs(). - * 2. Signal/Wait for signal CS will decrement the SOB refcnt - * here. - * These two measures guarantee that the wait for signal CS will - * reset the SOB upon completion rather than the signal CS and - * hence the above scenario is avoided. - */ - kref_put(&hl_cs_cmpl->hw_sob->kref, hl_sob_reset); + queue_work(hdev->sob_reset_wq, &hl_cs_cmpl->sob_reset_work); - if (hl_cs_cmpl->type == CS_TYPE_COLLECTIVE_WAIT) - hdev->asic_funcs->reset_sob_group(hdev, - hl_cs_cmpl->sob_group); + return; } free: @@ -670,9 +683,23 @@ static int allocate_cs(struct hl_device *hdev, struct hl_ctx *ctx, goto free_cs; } + cs->jobs_in_queue_cnt = kcalloc(hdev->asic_prop.max_queues, + sizeof(*cs->jobs_in_queue_cnt), GFP_ATOMIC); + if (!cs->jobs_in_queue_cnt) + cs->jobs_in_queue_cnt = kcalloc(hdev->asic_prop.max_queues, + sizeof(*cs->jobs_in_queue_cnt), GFP_KERNEL); + + if (!cs->jobs_in_queue_cnt) { + atomic64_inc(&ctx->cs_counters.out_of_mem_drop_cnt); + atomic64_inc(&cntr->out_of_mem_drop_cnt); + rc = -ENOMEM; + goto free_cs_cmpl; + } + cs_cmpl->hdev = hdev; cs_cmpl->type = cs->type; spin_lock_init(&cs_cmpl->lock); + INIT_WORK(&cs_cmpl->sob_reset_work, sob_reset_work); cs->fence = &cs_cmpl->base_fence; spin_lock(&ctx->cs_lock); @@ -702,19 +729,6 @@ static int allocate_cs(struct hl_device *hdev, struct hl_ctx *ctx, goto free_fence; } - cs->jobs_in_queue_cnt = kcalloc(hdev->asic_prop.max_queues, - sizeof(*cs->jobs_in_queue_cnt), GFP_ATOMIC); - if (!cs->jobs_in_queue_cnt) - cs->jobs_in_queue_cnt = kcalloc(hdev->asic_prop.max_queues, - sizeof(*cs->jobs_in_queue_cnt), GFP_KERNEL); - - if (!cs->jobs_in_queue_cnt) { - atomic64_inc(&ctx->cs_counters.out_of_mem_drop_cnt); - atomic64_inc(&cntr->out_of_mem_drop_cnt); - rc = -ENOMEM; - goto free_fence; - } - /* init hl_fence */ hl_fence_init(&cs_cmpl->base_fence, cs_cmpl->cs_seq); @@ -737,6 +751,8 @@ static int allocate_cs(struct hl_device *hdev, struct hl_ctx *ctx, free_fence: spin_unlock(&ctx->cs_lock); + kfree(cs->jobs_in_queue_cnt); +free_cs_cmpl: kfree(cs_cmpl); free_cs: kfree(cs); @@ -759,6 +775,8 @@ void hl_cs_rollback_all(struct hl_device *hdev) int i; struct hl_cs *cs, *tmp; + flush_workqueue(hdev->sob_reset_wq); + /* flush all completions before iterating over the CS mirror list in * order to avoid a race with the release functions */ diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index e22df6824bc3..53bc5ccb612f 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -368,11 +368,19 @@ static int device_early_init(struct hl_device *hdev) goto free_cq_wq; } + hdev->sob_reset_wq = alloc_workqueue("hl-sob-reset", WQ_UNBOUND, 0); + if (!hdev->sob_reset_wq) { + dev_err(hdev->dev, + "Failed to allocate SOB reset workqueue\n"); + rc = -ENOMEM; + goto free_eq_wq; + } + hdev->hl_chip_info = kzalloc(sizeof(struct hwmon_chip_info), GFP_KERNEL); if (!hdev->hl_chip_info) { rc = -ENOMEM; - goto free_eq_wq; + goto free_sob_reset_wq; } hdev->idle_busy_ts_arr = kmalloc_array(HL_IDLE_BUSY_TS_ARR_SIZE, @@ -418,6 +426,8 @@ free_idle_busy_ts_arr: kfree(hdev->idle_busy_ts_arr); free_chip_info: kfree(hdev->hl_chip_info); +free_sob_reset_wq: + destroy_workqueue(hdev->sob_reset_wq); free_eq_wq: destroy_workqueue(hdev->eq_wq); free_cq_wq: @@ -454,6 +464,7 @@ static void device_early_fini(struct hl_device *hdev) kfree(hdev->idle_busy_ts_arr); kfree(hdev->hl_chip_info); + destroy_workqueue(hdev->sob_reset_wq); destroy_workqueue(hdev->eq_wq); destroy_workqueue(hdev->device_reset_work.wq); diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 2dcefd6485e5..65f34918faed 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -528,6 +528,7 @@ struct hl_fence { /** * struct hl_cs_compl - command submission completion object. + * @sob_reset_work: workqueue object to run SOB reset flow. * @base_fence: hl fence object. * @lock: spinlock to protect fence. * @hdev: habanalabs device structure. @@ -538,6 +539,7 @@ struct hl_fence { * @sob_group: the SOB group that is used in this collective wait CS. */ struct hl_cs_compl { + struct work_struct sob_reset_work; struct hl_fence base_fence; spinlock_t lock; struct hl_device *hdev; @@ -1905,6 +1907,7 @@ struct hl_mmu_funcs { * @cq_wq: work queues of completion queues for executing work in process * context. * @eq_wq: work queue of event queue for executing work in process context. + * @sob_reset_wq: work queue for sob reset executions. * @kernel_ctx: Kernel driver context structure. * @kernel_queues: array of hl_hw_queue. * @cs_mirror_list: CS mirror list for TDR. @@ -2022,6 +2025,7 @@ struct hl_device { struct hl_user_interrupt common_user_interrupt; struct workqueue_struct **cq_wq; struct workqueue_struct *eq_wq; + struct workqueue_struct *sob_reset_wq; struct hl_ctx *kernel_ctx; struct hl_hw_queue *kernel_queues; struct list_head cs_mirror_list; -- cgit v1.2.3 From e8f9392a5c7fabe0fdeb33b354b489c8c4b236bc Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Mon, 15 Mar 2021 20:49:28 +0200 Subject: habanalabs: support legacy and new pll indexes In order to use minimum of hard coded values common to LKD and F/W a dynamic method to work with PLLs is introduced in this patch. Formerly asic specific PLL numbering is now common for all asics. To be backward compatible a bit in dev status is defined, if the bit is not set LKD will keep working with old PLL numbering. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 49 +++++++++++++++++++++- drivers/misc/habanalabs/common/habanalabs.h | 14 +++++-- drivers/misc/habanalabs/common/sysfs.c | 24 ++++++++--- drivers/misc/habanalabs/gaudi/gaudi.c | 33 +++++++++++++++ drivers/misc/habanalabs/goya/goya.c | 26 ++++++++++++ drivers/misc/habanalabs/include/common/cpucp_if.h | 41 ++++++++++++++++++ .../misc/habanalabs/include/common/hl_boot_if.h | 6 +++ .../misc/habanalabs/include/gaudi/gaudi_fw_if.h | 14 ------- drivers/misc/habanalabs/include/goya/goya_fw_if.h | 11 ----- 9 files changed, 182 insertions(+), 36 deletions(-) diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 2a58edaf984a..092691a8917d 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -539,18 +539,63 @@ int hl_fw_cpucp_total_energy_get(struct hl_device *hdev, u64 *total_energy) return rc; } -int hl_fw_cpucp_pll_info_get(struct hl_device *hdev, u16 pll_index, +int get_used_pll_index(struct hl_device *hdev, enum pll_index input_pll_index, + enum pll_index *pll_index) +{ + struct asic_fixed_properties *prop = &hdev->asic_prop; + u8 pll_byte, pll_bit_off; + bool dynamic_pll; + + if (input_pll_index >= PLL_MAX) { + dev_err(hdev->dev, "PLL index %d is out of range\n", + input_pll_index); + return -EINVAL; + } + + dynamic_pll = prop->fw_security_status_valid && + (prop->fw_app_security_map & CPU_BOOT_DEV_STS0_DYN_PLL_EN); + + if (!dynamic_pll) { + /* + * in case we are working with legacy FW (each asic has unique + * PLL numbering) extract the legacy numbering + */ + *pll_index = hdev->legacy_pll_map[input_pll_index]; + return 0; + } + + /* PLL map is a u8 array */ + pll_byte = prop->cpucp_info.pll_map[input_pll_index >> 3]; + pll_bit_off = input_pll_index & 0x7; + + if (!(pll_byte & BIT(pll_bit_off))) { + dev_err(hdev->dev, "PLL index %d is not supported\n", + input_pll_index); + return -EINVAL; + } + + *pll_index = input_pll_index; + + return 0; +} + +int hl_fw_cpucp_pll_info_get(struct hl_device *hdev, enum pll_index pll_index, u16 *pll_freq_arr) { struct cpucp_packet pkt; + enum pll_index used_pll_idx; u64 result; int rc; + rc = get_used_pll_index(hdev, pll_index, &used_pll_idx); + if (rc) + return rc; + memset(&pkt, 0, sizeof(pkt)); pkt.ctl = cpu_to_le32(CPUCP_PACKET_PLL_INFO_GET << CPUCP_PKT_CTL_OPCODE_SHIFT); - pkt.pll_type = __cpu_to_le16(pll_index); + pkt.pll_type = __cpu_to_le16((u16)used_pll_idx); rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), HL_CPUCP_INFO_TIMEOUT_USEC, &result); diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 65f34918faed..dc8126b270d1 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -1946,6 +1946,8 @@ struct hl_mmu_funcs { * @aggregated_cs_counters: aggregated cs counters among all contexts * @mmu_priv: device-specific MMU data. * @mmu_func: device-related MMU functions. + * @legacy_pll_map: map holding map between dynamic (common) PLL indexes and + * static (asic specific) PLL indexes. * @dram_used_mem: current DRAM memory consumption. * @timeout_jiffies: device CS timeout value. * @max_power: the max power of the device, as configured by the sysadmin. This @@ -2070,6 +2072,8 @@ struct hl_device { struct hl_mmu_priv mmu_priv; struct hl_mmu_funcs mmu_func[MMU_NUM_PGT_LOCATIONS]; + enum pll_index *legacy_pll_map; + atomic64_t dram_used_mem; u64 timeout_jiffies; u64 max_power; @@ -2383,7 +2387,9 @@ int hl_fw_cpucp_pci_counters_get(struct hl_device *hdev, struct hl_info_pci_counters *counters); int hl_fw_cpucp_total_energy_get(struct hl_device *hdev, u64 *total_energy); -int hl_fw_cpucp_pll_info_get(struct hl_device *hdev, u16 pll_index, +int get_used_pll_index(struct hl_device *hdev, enum pll_index input_pll_index, + enum pll_index *pll_index); +int hl_fw_cpucp_pll_info_get(struct hl_device *hdev, enum pll_index pll_index, u16 *pll_freq_arr); int hl_fw_cpucp_power_get(struct hl_device *hdev, u64 *power); int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg, @@ -2404,8 +2410,10 @@ int hl_pci_set_outbound_region(struct hl_device *hdev, int hl_pci_init(struct hl_device *hdev); void hl_pci_fini(struct hl_device *hdev); -long hl_get_frequency(struct hl_device *hdev, u32 pll_index, bool curr); -void hl_set_frequency(struct hl_device *hdev, u32 pll_index, u64 freq); +long hl_get_frequency(struct hl_device *hdev, enum pll_index pll_index, + bool curr); +void hl_set_frequency(struct hl_device *hdev, enum pll_index pll_index, + u64 freq); int hl_get_temperature(struct hl_device *hdev, int sensor_index, u32 attr, long *value); int hl_set_temperature(struct hl_device *hdev, diff --git a/drivers/misc/habanalabs/common/sysfs.c b/drivers/misc/habanalabs/common/sysfs.c index f37634cf8b65..c7ac5dc0cda4 100644 --- a/drivers/misc/habanalabs/common/sysfs.c +++ b/drivers/misc/habanalabs/common/sysfs.c @@ -9,12 +9,18 @@ #include -long hl_get_frequency(struct hl_device *hdev, u32 pll_index, bool curr) +long hl_get_frequency(struct hl_device *hdev, enum pll_index pll_index, + bool curr) { struct cpucp_packet pkt; + u32 used_pll_idx; u64 result; int rc; + rc = get_used_pll_index(hdev, pll_index, &used_pll_idx); + if (rc) + return rc; + memset(&pkt, 0, sizeof(pkt)); if (curr) @@ -23,7 +29,7 @@ long hl_get_frequency(struct hl_device *hdev, u32 pll_index, bool curr) else pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_GET << CPUCP_PKT_CTL_OPCODE_SHIFT); - pkt.pll_index = cpu_to_le32(pll_index); + pkt.pll_index = cpu_to_le32((u32)used_pll_idx); rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, &result); @@ -31,23 +37,29 @@ long hl_get_frequency(struct hl_device *hdev, u32 pll_index, bool curr) if (rc) { dev_err(hdev->dev, "Failed to get frequency of PLL %d, error %d\n", - pll_index, rc); + used_pll_idx, rc); return rc; } return (long) result; } -void hl_set_frequency(struct hl_device *hdev, u32 pll_index, u64 freq) +void hl_set_frequency(struct hl_device *hdev, enum pll_index pll_index, + u64 freq) { struct cpucp_packet pkt; + u32 used_pll_idx; int rc; + rc = get_used_pll_index(hdev, pll_index, &used_pll_idx); + if (rc) + return; + memset(&pkt, 0, sizeof(pkt)); pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_SET << CPUCP_PKT_CTL_OPCODE_SHIFT); - pkt.pll_index = cpu_to_le32(pll_index); + pkt.pll_index = cpu_to_le32((u32)used_pll_idx); pkt.value = cpu_to_le64(freq); rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), @@ -56,7 +68,7 @@ void hl_set_frequency(struct hl_device *hdev, u32 pll_index, u64 freq) if (rc) dev_err(hdev->dev, "Failed to set frequency to PLL %d, error %d\n", - pll_index, rc); + used_pll_idx, rc); } u64 hl_get_max_power(struct hl_device *hdev) diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index a65ae0dbdb92..8fa190fde462 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -105,6 +105,36 @@ #define GAUDI_PLL_MAX 10 +/* + * this enum kept here for compatibility with old FW (in which each asic has + * unique PLL numbering + */ +enum gaudi_pll_index { + GAUDI_CPU_PLL = 0, + GAUDI_PCI_PLL, + GAUDI_SRAM_PLL, + GAUDI_HBM_PLL, + GAUDI_NIC_PLL, + GAUDI_DMA_PLL, + GAUDI_MESH_PLL, + GAUDI_MME_PLL, + GAUDI_TPC_PLL, + GAUDI_IF_PLL, +}; + +static enum pll_index gaudi_pll_map[PLL_MAX] = { + [CPU_PLL] = GAUDI_CPU_PLL, + [PCI_PLL] = GAUDI_PCI_PLL, + [SRAM_PLL] = GAUDI_SRAM_PLL, + [HBM_PLL] = GAUDI_HBM_PLL, + [NIC_PLL] = GAUDI_NIC_PLL, + [DMA_PLL] = GAUDI_DMA_PLL, + [MESH_PLL] = GAUDI_MESH_PLL, + [MME_PLL] = GAUDI_MME_PLL, + [TPC_PLL] = GAUDI_TPC_PLL, + [IF_PLL] = GAUDI_IF_PLL, +}; + static const char gaudi_irq_name[GAUDI_MSI_ENTRIES][GAUDI_MAX_STRING_LEN] = { "gaudi cq 0_0", "gaudi cq 0_1", "gaudi cq 0_2", "gaudi cq 0_3", "gaudi cq 1_0", "gaudi cq 1_1", "gaudi cq 1_2", "gaudi cq 1_3", @@ -1588,6 +1618,9 @@ static int gaudi_sw_init(struct hl_device *hdev) hdev->asic_specific = gaudi; + /* store legacy PLL map */ + hdev->legacy_pll_map = gaudi_pll_map; + /* Create DMA pool for small allocations */ hdev->dma_pool = dma_pool_create(dev_name(hdev->dev), &hdev->pdev->dev, GAUDI_DMA_POOL_BLK_SIZE, 8, 0); diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 9e7531167c73..f3b3145b206f 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -118,6 +118,29 @@ #define IS_MME_IDLE(mme_arch_sts) \ (((mme_arch_sts) & MME_ARCH_IDLE_MASK) == MME_ARCH_IDLE_MASK) +/* + * this enum kept here for compatibility with old FW (in which each asic has + * unique PLL numbering + */ +enum goya_pll_index { + GOYA_CPU_PLL = 0, + GOYA_IC_PLL, + GOYA_MC_PLL, + GOYA_MME_PLL, + GOYA_PCI_PLL, + GOYA_EMMC_PLL, + GOYA_TPC_PLL, +}; + +static enum pll_index goya_pll_map[PLL_MAX] = { + [CPU_PLL] = GOYA_CPU_PLL, + [IC_PLL] = GOYA_IC_PLL, + [MC_PLL] = GOYA_MC_PLL, + [MME_PLL] = GOYA_MME_PLL, + [PCI_PLL] = GOYA_PCI_PLL, + [EMMC_PLL] = GOYA_EMMC_PLL, + [TPC_PLL] = GOYA_TPC_PLL, +}; static const char goya_irq_name[GOYA_MSIX_ENTRIES][GOYA_MAX_STRING_LEN] = { "goya cq 0", "goya cq 1", "goya cq 2", "goya cq 3", @@ -853,6 +876,9 @@ static int goya_sw_init(struct hl_device *hdev) hdev->asic_specific = goya; + /* store legacy PLL map */ + hdev->legacy_pll_map = goya_pll_map; + /* Create DMA pool for small allocations */ hdev->dma_pool = dma_pool_create(dev_name(hdev->dev), &hdev->pdev->dev, GOYA_DMA_POOL_BLK_SIZE, 8, 0); diff --git a/drivers/misc/habanalabs/include/common/cpucp_if.h b/drivers/misc/habanalabs/include/common/cpucp_if.h index 6ba480a316ce..88e8ce6e0694 100644 --- a/drivers/misc/habanalabs/include/common/cpucp_if.h +++ b/drivers/misc/habanalabs/include/common/cpucp_if.h @@ -28,6 +28,9 @@ #define CPUCP_PKT_HBM_ECC_INFO_HBM_CH_SHIFT 6 #define CPUCP_PKT_HBM_ECC_INFO_HBM_CH_MASK 0x000007C0 +#define PLL_MAP_MAX_BITS 128 +#define PLL_MAP_LEN (PLL_MAP_MAX_BITS / 8) + /* * info of the pkt queue pointers in the first async occurrence */ @@ -473,6 +476,42 @@ enum cpucp_pll_type_attributes { cpucp_pll_pci, }; +/* + * PLL enumeration table used for all ASICs and future SW versions. + * For future ASIC-LKD compatibility, we can only add new enumerations. + * at the end of the table. + * Changing the order of entries or removing entries is not allowed. + */ +enum pll_index { + CPU_PLL = 0, + PCI_PLL = 1, + NIC_PLL = 2, + DMA_PLL = 3, + MESH_PLL = 4, + MME_PLL = 5, + TPC_PLL = 6, + IF_PLL = 7, + SRAM_PLL = 8, + NS_DCORE_PLL = 9, + MESH_DCORE_PLL = 10, + HBM_PLL = 11, + TPC_DCORE_PLL = 12, + VIDEO_DCORE_PLL = 13, + SRAM_DCORE_PLL = 14, + NIC_PHY_DCORE_PLL = 15, + MSS_DCORE_PLL = 16, + DMA_DCORE_PLL = 17, + SIF_PLL = 18, + DDR_PLL = 19, + VID_PLL = 20, + BANK_PLL = 21, + MMU_PLL = 22, + IC_PLL = 23, + MC_PLL = 24, + EMMC_PLL = 25, + PLL_MAX +}; + /* Event Queue Packets */ struct eq_generic_event { @@ -547,6 +586,7 @@ struct cpucp_security_info { * @dram_size: available DRAM size. * @card_name: card name that will be displayed in HWMON subsystem on the host * @sec_info: security information + * @pll_map: Bit map of supported PLLs for current ASIC version. */ struct cpucp_info { struct cpucp_sensor sensors[CPUCP_MAX_SENSORS]; @@ -568,6 +608,7 @@ struct cpucp_info { __u8 pad[7]; struct cpucp_security_info sec_info; __le32 reserved6; + __u8 pll_map[PLL_MAP_LEN]; }; struct cpucp_mac_addr { diff --git a/drivers/misc/habanalabs/include/common/hl_boot_if.h b/drivers/misc/habanalabs/include/common/hl_boot_if.h index d17185b6aea9..1717874ff306 100644 --- a/drivers/misc/habanalabs/include/common/hl_boot_if.h +++ b/drivers/misc/habanalabs/include/common/hl_boot_if.h @@ -179,6 +179,11 @@ * configured and is ready for use. * Initialized in: ppboot * + * CPU_BOOT_DEV_STS0_DYN_PLL_EN Dynamic PLL configuration is enabled. + * FW sends to host a bitmap of supported + * PLLs. + * Initialized in: linux + * * CPU_BOOT_DEV_STS0_ENABLED Device status register enabled. * This is a main indication that the * running FW populates the device status @@ -206,6 +211,7 @@ #define CPU_BOOT_DEV_STS0_PKT_PI_ACK_EN (1 << 15) #define CPU_BOOT_DEV_STS0_FW_LD_COM_EN (1 << 16) #define CPU_BOOT_DEV_STS0_FW_IATU_CONF_EN (1 << 17) +#define CPU_BOOT_DEV_STS0_DYN_PLL_EN (1 << 19) #define CPU_BOOT_DEV_STS0_ENABLED (1 << 31) enum cpu_boot_status { diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h b/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h index 25acd9e87e20..a9f51f9f9e92 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h @@ -20,20 +20,6 @@ #define UBOOT_FW_OFFSET 0x100000 /* 1MB in SRAM */ #define LINUX_FW_OFFSET 0x800000 /* 8MB in HBM */ -enum gaudi_pll_index { - CPU_PLL = 0, - PCI_PLL, - SRAM_PLL, - HBM_PLL, - NIC_PLL, - DMA_PLL, - MESH_PLL, - MME_PLL, - TPC_PLL, - IF_PLL, - PLL_MAX -}; - enum gaudi_nic_axi_error { RXB, RXE, diff --git a/drivers/misc/habanalabs/include/goya/goya_fw_if.h b/drivers/misc/habanalabs/include/goya/goya_fw_if.h index daf8d8cd14be..bc05f86c73ac 100644 --- a/drivers/misc/habanalabs/include/goya/goya_fw_if.h +++ b/drivers/misc/habanalabs/include/goya/goya_fw_if.h @@ -15,17 +15,6 @@ #define UBOOT_FW_OFFSET 0x100000 /* 1MB in SRAM */ #define LINUX_FW_OFFSET 0x800000 /* 8MB in DDR */ -enum goya_pll_index { - CPU_PLL = 0, - IC_PLL, - MC_PLL, - MME_PLL, - PCI_PLL, - EMMC_PLL, - TPC_PLL, - PLL_MAX -}; - #define GOYA_PLL_FREQ_LOW 50000000 /* 50 MHz */ #endif /* GOYA_FW_IF_H */ -- cgit v1.2.3 From cd5def8020637836b7836fc8228b70cdc9af4ea1 Mon Sep 17 00:00:00 2001 From: Koby Elbaz Date: Tue, 23 Feb 2021 21:31:27 +0200 Subject: habanalabs: improve utilization calculation The new approach is based on the notion that the relative current power consumption is in relation of proportionality to device's true utilization. Utilization info ranges between [0,100]% Currently, dc_power values are hard-coded. Signed-off-by: Koby Elbaz Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- .../misc/habanalabs/common/command_submission.c | 18 --- drivers/misc/habanalabs/common/device.c | 121 +++------------------ drivers/misc/habanalabs/common/habanalabs.h | 25 +---- drivers/misc/habanalabs/common/habanalabs_ioctl.c | 11 +- drivers/misc/habanalabs/common/hw_queue.c | 8 -- drivers/misc/habanalabs/gaudi/gaudi.c | 20 +++- drivers/misc/habanalabs/gaudi/gaudiP.h | 3 + drivers/misc/habanalabs/goya/goya.c | 1 + drivers/misc/habanalabs/goya/goyaP.h | 2 + 9 files changed, 40 insertions(+), 169 deletions(-) diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index ba6d3e317255..21a60b7c2091 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -505,24 +505,6 @@ static void cs_do_release(struct kref *ref) goto out; } - hdev->asic_funcs->hw_queues_lock(hdev); - - hdev->cs_active_cnt--; - if (!hdev->cs_active_cnt) { - struct hl_device_idle_busy_ts *ts; - - ts = &hdev->idle_busy_ts_arr[hdev->idle_busy_ts_idx++]; - ts->busy_to_idle_ts = ktime_get(); - - if (hdev->idle_busy_ts_idx == HL_IDLE_BUSY_TS_ARR_SIZE) - hdev->idle_busy_ts_idx = 0; - } else if (hdev->cs_active_cnt < 0) { - dev_crit(hdev->dev, "CS active cnt %d is negative\n", - hdev->cs_active_cnt); - } - - hdev->asic_funcs->hw_queues_unlock(hdev); - /* Need to update CI for all queue jobs that does not get completion */ hl_hw_queue_update_ci(cs); diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index 53bc5ccb612f..e64c60d48d42 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -383,17 +383,9 @@ static int device_early_init(struct hl_device *hdev) goto free_sob_reset_wq; } - hdev->idle_busy_ts_arr = kmalloc_array(HL_IDLE_BUSY_TS_ARR_SIZE, - sizeof(struct hl_device_idle_busy_ts), - (GFP_KERNEL | __GFP_ZERO)); - if (!hdev->idle_busy_ts_arr) { - rc = -ENOMEM; - goto free_chip_info; - } - rc = hl_mmu_if_set_funcs(hdev); if (rc) - goto free_idle_busy_ts_arr; + goto free_chip_info; hl_cb_mgr_init(&hdev->kernel_cb_mgr); @@ -422,8 +414,6 @@ static int device_early_init(struct hl_device *hdev) free_cb_mgr: hl_cb_mgr_fini(hdev, &hdev->kernel_cb_mgr); -free_idle_busy_ts_arr: - kfree(hdev->idle_busy_ts_arr); free_chip_info: kfree(hdev->hl_chip_info); free_sob_reset_wq: @@ -461,7 +451,6 @@ static void device_early_fini(struct hl_device *hdev) hl_cb_mgr_fini(hdev, &hdev->kernel_cb_mgr); - kfree(hdev->idle_busy_ts_arr); kfree(hdev->hl_chip_info); destroy_workqueue(hdev->sob_reset_wq); @@ -582,100 +571,24 @@ static void device_late_fini(struct hl_device *hdev) hdev->late_init_done = false; } -uint32_t hl_device_utilization(struct hl_device *hdev, uint32_t period_ms) +int hl_device_utilization(struct hl_device *hdev, u32 *utilization) { - struct hl_device_idle_busy_ts *ts; - ktime_t zero_ktime, curr = ktime_get(); - u32 overlap_cnt = 0, last_index = hdev->idle_busy_ts_idx; - s64 period_us, last_start_us, last_end_us, last_busy_time_us, - total_busy_time_us = 0, total_busy_time_ms; - - zero_ktime = ktime_set(0, 0); - period_us = period_ms * USEC_PER_MSEC; - ts = &hdev->idle_busy_ts_arr[last_index]; - - /* check case that device is currently in idle */ - if (!ktime_compare(ts->busy_to_idle_ts, zero_ktime) && - !ktime_compare(ts->idle_to_busy_ts, zero_ktime)) { - - last_index--; - /* Handle case idle_busy_ts_idx was 0 */ - if (last_index > HL_IDLE_BUSY_TS_ARR_SIZE) - last_index = HL_IDLE_BUSY_TS_ARR_SIZE - 1; - - ts = &hdev->idle_busy_ts_arr[last_index]; - } - - while (overlap_cnt < HL_IDLE_BUSY_TS_ARR_SIZE) { - /* Check if we are in last sample case. i.e. if the sample - * begun before the sampling period. This could be a real - * sample or 0 so need to handle both cases - */ - last_start_us = ktime_to_us( - ktime_sub(curr, ts->idle_to_busy_ts)); - - if (last_start_us > period_us) { - - /* First check two cases: - * 1. If the device is currently busy - * 2. If the device was idle during the whole sampling - * period - */ - - if (!ktime_compare(ts->busy_to_idle_ts, zero_ktime)) { - /* Check if the device is currently busy */ - if (ktime_compare(ts->idle_to_busy_ts, - zero_ktime)) - return 100; - - /* We either didn't have any activity or we - * reached an entry which is 0. Either way, - * exit and return what was accumulated so far - */ - break; - } - - /* If sample has finished, check it is relevant */ - last_end_us = ktime_to_us( - ktime_sub(curr, ts->busy_to_idle_ts)); - - if (last_end_us > period_us) - break; - - /* It is relevant so add it but with adjustment */ - last_busy_time_us = ktime_to_us( - ktime_sub(ts->busy_to_idle_ts, - ts->idle_to_busy_ts)); - total_busy_time_us += last_busy_time_us - - (last_start_us - period_us); - break; - } - - /* Check if the sample is finished or still open */ - if (ktime_compare(ts->busy_to_idle_ts, zero_ktime)) - last_busy_time_us = ktime_to_us( - ktime_sub(ts->busy_to_idle_ts, - ts->idle_to_busy_ts)); - else - last_busy_time_us = ktime_to_us( - ktime_sub(curr, ts->idle_to_busy_ts)); - - total_busy_time_us += last_busy_time_us; + u64 max_power, curr_power, dc_power, dividend; + int rc; - last_index--; - /* Handle case idle_busy_ts_idx was 0 */ - if (last_index > HL_IDLE_BUSY_TS_ARR_SIZE) - last_index = HL_IDLE_BUSY_TS_ARR_SIZE - 1; + max_power = hdev->asic_prop.max_power_default; + dc_power = hdev->asic_prop.dc_power_default; + rc = hl_fw_cpucp_power_get(hdev, &curr_power); - ts = &hdev->idle_busy_ts_arr[last_index]; + if (rc) + return rc; - overlap_cnt++; - } + curr_power = clamp(curr_power, dc_power, max_power); - total_busy_time_ms = DIV_ROUND_UP_ULL(total_busy_time_us, - USEC_PER_MSEC); + dividend = (curr_power - dc_power) * 100; + *utilization = (u32) div_u64(dividend, (max_power - dc_power)); - return DIV_ROUND_UP_ULL(total_busy_time_ms * 100, period_ms); + return 0; } /* @@ -1110,14 +1023,6 @@ kill_processes: for (i = 0 ; i < hdev->asic_prop.completion_queues_count ; i++) hl_cq_reset(hdev, &hdev->completion_queue[i]); - hdev->idle_busy_ts_idx = 0; - hdev->idle_busy_ts_arr[0].busy_to_idle_ts = ktime_set(0, 0); - hdev->idle_busy_ts_arr[0].idle_to_busy_ts = ktime_set(0, 0); - - if (hdev->cs_active_cnt) - dev_crit(hdev->dev, "CS active cnt %d is not 0 during reset\n", - hdev->cs_active_cnt); - mutex_lock(&hdev->fpriv_list_lock); /* Make sure the context switch phase will run again */ diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index dc8126b270d1..ddb65639f518 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -61,8 +61,6 @@ #define HL_SIM_MAX_TIMEOUT_US 10000000 /* 10s */ -#define HL_IDLE_BUSY_TS_ARR_SIZE 4096 - #define HL_COMMON_USER_INTERRUPT_ID 0xFFF /* Memory */ @@ -391,6 +389,7 @@ struct hl_mmu_properties { * @dram_size: DRAM total size. * @dram_pci_bar_size: size of PCI bar towards DRAM. * @max_power_default: max power of the device after reset + * @dc_power_default: power consumed by the device in mode idle. * @dram_size_for_default_page_mapping: DRAM size needed to map to avoid page * fault. * @pcie_dbi_base_address: Base address of the PCIE_DBI block. @@ -463,6 +462,7 @@ struct asic_fixed_properties { u64 dram_size; u64 dram_pci_bar_size; u64 max_power_default; + u64 dc_power_default; u64 dram_size_for_default_page_mapping; u64 pcie_dbi_base_address; u64 pcie_aux_dbi_reg_addr; @@ -1760,16 +1760,6 @@ struct hl_device_reset_work { struct hl_device *hdev; }; -/** - * struct hl_device_idle_busy_ts - used for calculating device utilization rate. - * @idle_to_busy_ts: timestamp where device changed from idle to busy. - * @busy_to_idle_ts: timestamp where device changed from busy to idle. - */ -struct hl_device_idle_busy_ts { - ktime_t idle_to_busy_ts; - ktime_t busy_to_idle_ts; -}; - /** * struct hr_mmu_hop_addrs - used for holding per-device host-resident mmu hop * information. @@ -1941,8 +1931,6 @@ struct hl_mmu_funcs { * when a user opens the device * @fpriv_list_lock: protects the fpriv_list * @compute_ctx: current compute context executing. - * @idle_busy_ts_arr: array to hold time stamps of transitions from idle to busy - * and vice-versa * @aggregated_cs_counters: aggregated cs counters among all contexts * @mmu_priv: device-specific MMU data. * @mmu_func: device-related MMU functions. @@ -1960,13 +1948,10 @@ struct hl_mmu_funcs { * @curr_pll_profile: current PLL profile. * @card_type: Various ASICs have several card types. This indicates the card * type of the current device. - * @cs_active_cnt: number of active command submissions on this device (active - * means already in H/W queues) * @major: habanalabs kernel driver major. * @high_pll: high PLL profile frequency. * @soft_reset_cnt: number of soft reset since the driver was loaded. * @hard_reset_cnt: number of hard reset since the driver was loaded. - * @idle_busy_ts_idx: index of current entry in idle_busy_ts_arr * @clk_throttling_reason: bitmask represents the current clk throttling reasons * @id: device minor. * @id_control: minor of the control device @@ -2065,8 +2050,6 @@ struct hl_device { struct hl_ctx *compute_ctx; - struct hl_device_idle_busy_ts *idle_busy_ts_arr; - struct hl_cs_counters_atomic aggregated_cs_counters; struct hl_mmu_priv mmu_priv; @@ -2081,12 +2064,10 @@ struct hl_device { atomic_t in_reset; enum hl_pll_frequency curr_pll_profile; enum cpucp_card_types card_type; - int cs_active_cnt; u32 major; u32 high_pll; u32 soft_reset_cnt; u32 hard_reset_cnt; - u32 idle_busy_ts_idx; u32 clk_throttling_reason; u16 id; u16 id_control; @@ -2275,7 +2256,7 @@ int hl_device_reset(struct hl_device *hdev, u32 flags); void hl_hpriv_get(struct hl_fpriv *hpriv); int hl_hpriv_put(struct hl_fpriv *hpriv); int hl_device_set_frequency(struct hl_device *hdev, enum hl_pll_frequency freq); -uint32_t hl_device_utilization(struct hl_device *hdev, uint32_t period_ms); +int hl_device_utilization(struct hl_device *hdev, u32 *utilization); int hl_build_hwmon_channel_info(struct hl_device *hdev, struct cpucp_sensor *sensors_arr); diff --git a/drivers/misc/habanalabs/common/habanalabs_ioctl.c b/drivers/misc/habanalabs/common/habanalabs_ioctl.c index 9fc429b82a92..33841c272eb6 100644 --- a/drivers/misc/habanalabs/common/habanalabs_ioctl.c +++ b/drivers/misc/habanalabs/common/habanalabs_ioctl.c @@ -226,19 +226,14 @@ static int device_utilization(struct hl_device *hdev, struct hl_info_args *args) struct hl_info_device_utilization device_util = {0}; u32 max_size = args->return_size; void __user *out = (void __user *) (uintptr_t) args->return_pointer; + int rc; if ((!max_size) || (!out)) return -EINVAL; - if ((args->period_ms < 100) || (args->period_ms > 1000) || - (args->period_ms % 100)) { - dev_err(hdev->dev, - "period %u must be between 100 - 1000 and must be divisible by 100\n", - args->period_ms); + rc = hl_device_utilization(hdev, &device_util.utilization); + if (rc) return -EINVAL; - } - - device_util.utilization = hl_device_utilization(hdev, args->period_ms); return copy_to_user(out, &device_util, min((size_t) max_size, sizeof(device_util))) ? -EFAULT : 0; diff --git a/drivers/misc/habanalabs/common/hw_queue.c b/drivers/misc/habanalabs/common/hw_queue.c index 0f335182267f..4acc25dccad3 100644 --- a/drivers/misc/habanalabs/common/hw_queue.c +++ b/drivers/misc/habanalabs/common/hw_queue.c @@ -635,14 +635,6 @@ int hl_hw_queue_schedule_cs(struct hl_cs *cs) spin_unlock(&hdev->cs_mirror_lock); - if (!hdev->cs_active_cnt++) { - struct hl_device_idle_busy_ts *ts; - - ts = &hdev->idle_busy_ts_arr[hdev->idle_busy_ts_idx]; - ts->busy_to_idle_ts = ktime_set(0, 0); - ts->idle_to_busy_ts = ktime_get(); - } - list_for_each_entry_safe(job, tmp, &cs->job_list, cs_node) switch (job->queue_type) { case QUEUE_TYPE_EXT: diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 8fa190fde462..f273b792bc5d 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -426,6 +426,19 @@ get_collective_mode(struct hl_device *hdev, u32 queue_id) return HL_COLLECTIVE_NOT_SUPPORTED; } +static inline void set_default_power_values(struct hl_device *hdev) +{ + struct asic_fixed_properties *prop = &hdev->asic_prop; + + if (hdev->card_type == cpucp_card_type_pmc) { + prop->max_power_default = MAX_POWER_DEFAULT_PMC; + prop->dc_power_default = DC_POWER_DEFAULT_PMC; + } else { + prop->max_power_default = MAX_POWER_DEFAULT_PCI; + prop->dc_power_default = DC_POWER_DEFAULT_PCI; + } +} + static int gaudi_get_fixed_properties(struct hl_device *hdev) { struct asic_fixed_properties *prop = &hdev->asic_prop; @@ -537,7 +550,7 @@ static int gaudi_get_fixed_properties(struct hl_device *hdev) prop->num_of_events = GAUDI_EVENT_SIZE; prop->tpc_enabled_mask = TPC_ENABLED_MASK; - prop->max_power_default = MAX_POWER_DEFAULT_PCI; + set_default_power_values(hdev); prop->cb_pool_cb_cnt = GAUDI_CB_POOL_CB_CNT; prop->cb_pool_cb_size = GAUDI_CB_POOL_CB_SIZE; @@ -7796,10 +7809,7 @@ static int gaudi_cpucp_info_get(struct hl_device *hdev) hdev->card_type = le32_to_cpu(hdev->asic_prop.cpucp_info.card_type); - if (hdev->card_type == cpucp_card_type_pci) - prop->max_power_default = MAX_POWER_DEFAULT_PCI; - else if (hdev->card_type == cpucp_card_type_pmc) - prop->max_power_default = MAX_POWER_DEFAULT_PMC; + set_default_power_values(hdev); hdev->max_power = prop->max_power_default; diff --git a/drivers/misc/habanalabs/gaudi/gaudiP.h b/drivers/misc/habanalabs/gaudi/gaudiP.h index 50bb4ad570fd..5929be81ec23 100644 --- a/drivers/misc/habanalabs/gaudi/gaudiP.h +++ b/drivers/misc/habanalabs/gaudi/gaudiP.h @@ -47,6 +47,9 @@ #define MAX_POWER_DEFAULT_PCI 200000 /* 200W */ #define MAX_POWER_DEFAULT_PMC 350000 /* 350W */ +#define DC_POWER_DEFAULT_PCI 60000 /* 60W */ +#define DC_POWER_DEFAULT_PMC 60000 /* 60W */ + #define GAUDI_CPU_TIMEOUT_USEC 30000000 /* 30s */ #define TPC_ENABLED_MASK 0xFF diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index f3b3145b206f..09b423455439 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -469,6 +469,7 @@ int goya_get_fixed_properties(struct hl_device *hdev) prop->cb_pool_cb_cnt = GOYA_CB_POOL_CB_CNT; prop->cb_pool_cb_size = GOYA_CB_POOL_CB_SIZE; prop->max_power_default = MAX_POWER_DEFAULT; + prop->dc_power_default = DC_POWER_DEFAULT; prop->tpc_enabled_mask = TPC_ENABLED_MASK; prop->pcie_dbi_base_address = mmPCIE_DBI_BASE; prop->pcie_aux_dbi_reg_addr = CFG_BASE + mmPCIE_AUX_DBI; diff --git a/drivers/misc/habanalabs/goya/goyaP.h b/drivers/misc/habanalabs/goya/goyaP.h index 23fe099ed218..ef8c6c8b5c8d 100644 --- a/drivers/misc/habanalabs/goya/goyaP.h +++ b/drivers/misc/habanalabs/goya/goyaP.h @@ -49,6 +49,8 @@ #define MAX_POWER_DEFAULT 200000 /* 200W */ +#define DC_POWER_DEFAULT 20000 /* 20W */ + #define DRAM_PHYS_DEFAULT_SIZE 0x100000000ull /* 4GB */ #define GOYA_DEFAULT_CARD_NAME "HL1000" -- cgit v1.2.3 From cf39395034c6b927d49abe554fb4e93730d00543 Mon Sep 17 00:00:00 2001 From: Alon Mizrahi Date: Mon, 22 Feb 2021 15:53:24 +0200 Subject: habanalabs: add custom timeout flag per cs There is a need to allow to user to send command submissions with custom timeout as some CS take longer than the max timeout that is used by default. Signed-off-by: Alon Mizrahi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- .../misc/habanalabs/common/command_submission.c | 35 ++++++++++++---------- drivers/misc/habanalabs/common/habanalabs.h | 2 ++ drivers/misc/habanalabs/common/hw_queue.c | 2 +- include/uapi/misc/habanalabs.h | 15 ++++++++-- 4 files changed, 36 insertions(+), 18 deletions(-) diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index 21a60b7c2091..ff8791a651fd 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -467,8 +467,7 @@ static void cs_handle_tdr(struct hl_device *hdev, struct hl_cs *cs) if (next_entry_found && !next->tdr_active) { next->tdr_active = true; - schedule_delayed_work(&next->work_tdr, - hdev->timeout_jiffies); + schedule_delayed_work(&next->work_tdr, next->timeout_jiffies); } spin_unlock(&hdev->cs_mirror_lock); @@ -622,7 +621,7 @@ static void cs_timedout(struct work_struct *work) static int allocate_cs(struct hl_device *hdev, struct hl_ctx *ctx, enum hl_cs_type cs_type, u64 user_sequence, - struct hl_cs **cs_new) + struct hl_cs **cs_new, u32 flags, u32 timeout) { struct hl_cs_counters_atomic *cntr; struct hl_fence *other = NULL; @@ -649,6 +648,8 @@ static int allocate_cs(struct hl_device *hdev, struct hl_ctx *ctx, cs->submitted = false; cs->completed = false; cs->type = cs_type; + cs->timestamp = !!(flags & HL_CS_FLAGS_TIMESTAMP); + cs->timeout_jiffies = timeout; INIT_LIST_HEAD(&cs->job_list); INIT_DELAYED_WORK(&cs->work_tdr, cs_timedout); kref_init(&cs->refcount); @@ -1092,7 +1093,8 @@ static int cs_staged_submission(struct hl_device *hdev, struct hl_cs *cs, } static int cs_ioctl_default(struct hl_fpriv *hpriv, void __user *chunks, - u32 num_chunks, u64 *cs_seq, u32 flags) + u32 num_chunks, u64 *cs_seq, u32 flags, + u32 timeout) { bool staged_mid, int_queues_only = true; struct hl_device *hdev = hpriv->hdev; @@ -1121,11 +1123,11 @@ static int cs_ioctl_default(struct hl_fpriv *hpriv, void __user *chunks, staged_mid = false; rc = allocate_cs(hdev, hpriv->ctx, CS_TYPE_DEFAULT, - staged_mid ? user_sequence : ULLONG_MAX, &cs); + staged_mid ? user_sequence : ULLONG_MAX, &cs, flags, + timeout); if (rc) goto free_cs_chunk_array; - cs->timestamp = !!(flags & HL_CS_FLAGS_TIMESTAMP); *cs_seq = cs->sequence; hl_debugfs_add_cs(cs); @@ -1323,7 +1325,8 @@ static int hl_submit_pending_cb(struct hl_fpriv *hpriv) list_move_tail(&pending_cb->cb_node, &local_cb_list); spin_unlock(&ctx->pending_cb_lock); - rc = allocate_cs(hdev, ctx, CS_TYPE_DEFAULT, ULLONG_MAX, &cs); + rc = allocate_cs(hdev, ctx, CS_TYPE_DEFAULT, ULLONG_MAX, &cs, 0, + hdev->timeout_jiffies); if (rc) goto add_list_elements; @@ -1424,7 +1427,7 @@ static int hl_cs_ctx_switch(struct hl_fpriv *hpriv, union hl_cs_args *args, rc = 0; } else { rc = cs_ioctl_default(hpriv, chunks, num_chunks, - cs_seq, 0); + cs_seq, 0, hdev->timeout_jiffies); } mutex_unlock(&hpriv->restore_phase_mutex); @@ -1594,7 +1597,7 @@ static int cs_ioctl_signal_wait_create_jobs(struct hl_device *hdev, static int cs_ioctl_signal_wait(struct hl_fpriv *hpriv, enum hl_cs_type cs_type, void __user *chunks, u32 num_chunks, - u64 *cs_seq, bool timestamp) + u64 *cs_seq, u32 flags, u32 timeout) { struct hl_cs_chunk *cs_chunk_array, *chunk; struct hw_queue_properties *hw_queue_prop; @@ -1700,7 +1703,7 @@ static int cs_ioctl_signal_wait(struct hl_fpriv *hpriv, enum hl_cs_type cs_type, } } - rc = allocate_cs(hdev, ctx, cs_type, ULLONG_MAX, &cs); + rc = allocate_cs(hdev, ctx, cs_type, ULLONG_MAX, &cs, flags, timeout); if (rc) { if (cs_type == CS_TYPE_WAIT || cs_type == CS_TYPE_COLLECTIVE_WAIT) @@ -1708,8 +1711,6 @@ static int cs_ioctl_signal_wait(struct hl_fpriv *hpriv, enum hl_cs_type cs_type, goto free_cs_chunk_array; } - cs->timestamp = !!timestamp; - /* * Save the signal CS fence for later initialization right before * hanging the wait CS on the queue. @@ -1767,7 +1768,7 @@ int hl_cs_ioctl(struct hl_fpriv *hpriv, void *data) enum hl_cs_type cs_type; u64 cs_seq = ULONG_MAX; void __user *chunks; - u32 num_chunks, flags; + u32 num_chunks, flags, timeout; int rc; rc = hl_cs_sanity_checks(hpriv, args); @@ -1793,16 +1794,20 @@ int hl_cs_ioctl(struct hl_fpriv *hpriv, void *data) !(flags & HL_CS_FLAGS_STAGED_SUBMISSION_FIRST)) cs_seq = args->in.seq; + timeout = flags & HL_CS_FLAGS_CUSTOM_TIMEOUT + ? msecs_to_jiffies(args->in.timeout * 1000) + : hpriv->hdev->timeout_jiffies; + switch (cs_type) { case CS_TYPE_SIGNAL: case CS_TYPE_WAIT: case CS_TYPE_COLLECTIVE_WAIT: rc = cs_ioctl_signal_wait(hpriv, cs_type, chunks, num_chunks, - &cs_seq, args->in.cs_flags & HL_CS_FLAGS_TIMESTAMP); + &cs_seq, args->in.cs_flags, timeout); break; default: rc = cs_ioctl_default(hpriv, chunks, num_chunks, &cs_seq, - args->in.cs_flags); + args->in.cs_flags, timeout); break; } diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index ddb65639f518..54d7735991c7 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -1245,6 +1245,7 @@ struct hl_userptr { * @sequence: the sequence number of this CS. * @staged_sequence: the sequence of the staged submission this CS is part of, * relevant only if staged_cs is set. + * @timeout_jiffies: cs timeout in jiffies. * @type: CS_TYPE_*. * @submitted: true if CS was submitted to H/W. * @completed: true if CS was completed by device. @@ -1273,6 +1274,7 @@ struct hl_cs { struct list_head debugfs_list; u64 sequence; u64 staged_sequence; + u64 timeout_jiffies; enum hl_cs_type type; u8 submitted; u8 completed; diff --git a/drivers/misc/habanalabs/common/hw_queue.c b/drivers/misc/habanalabs/common/hw_queue.c index 4acc25dccad3..173438461835 100644 --- a/drivers/misc/habanalabs/common/hw_queue.c +++ b/drivers/misc/habanalabs/common/hw_queue.c @@ -629,7 +629,7 @@ int hl_hw_queue_schedule_cs(struct hl_cs *cs) if ((hdev->timeout_jiffies != MAX_SCHEDULE_TIMEOUT) && first_entry && cs_needs_timeout(cs)) { cs->tdr_active = true; - schedule_delayed_work(&cs->work_tdr, hdev->timeout_jiffies); + schedule_delayed_work(&cs->work_tdr, cs->timeout_jiffies); } diff --git a/include/uapi/misc/habanalabs.h b/include/uapi/misc/habanalabs.h index 92fd000ce0d3..90798eaac728 100644 --- a/include/uapi/misc/habanalabs.h +++ b/include/uapi/misc/habanalabs.h @@ -630,6 +630,7 @@ struct hl_cs_chunk { #define HL_CS_FLAGS_STAGED_SUBMISSION 0x40 #define HL_CS_FLAGS_STAGED_SUBMISSION_FIRST 0x80 #define HL_CS_FLAGS_STAGED_SUBMISSION_LAST 0x100 +#define HL_CS_FLAGS_CUSTOM_TIMEOUT 0x200 #define HL_CS_STATUS_SUCCESS 0 @@ -665,8 +666,18 @@ struct hl_cs_in { */ __u32 num_chunks_execute; - /* Number of chunks in restore phase array - Currently not in use */ - __u32 num_chunks_store; + union { + /* Number of chunks in restore phase array - + * Currently not in use + */ + __u32 num_chunks_store; + + /* timeout in seconds - valid only if HL_CS_FLAGS_CUSTOM_TIMEOUT + * is set. this parameter is ignored in case of future multiple + * users support. + */ + __u32 timeout; + }; /* HL_CS_FLAGS_* */ __u32 cs_flags; -- cgit v1.2.3 From e65448faf4cfeddd95a0e661aabf2fae1efc9831 Mon Sep 17 00:00:00 2001 From: farah kassabri Date: Tue, 30 Mar 2021 16:38:02 +0300 Subject: habanalabs/gaudi: sync stream add protection to SOB reset flow Since we moved the SOB reset flow to workqueue and not part of the fence release flow, we might reach a scenario where new context is created while we in the middle of resetting the SOB. in such cases the reset may fail due to idle check. This will mess up the streams sync since the SOB value is invalid. so we protect this area with a mutex, to delay context creation. Signed-off-by: farah kassabri Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index f273b792bc5d..bd711c8d3874 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -5729,18 +5729,26 @@ release_cb: static int gaudi_schedule_register_memset(struct hl_device *hdev, u32 hw_queue_id, u64 reg_base, u32 num_regs, u32 val) { - struct hl_ctx *ctx = hdev->compute_ctx; + struct hl_ctx *ctx; struct hl_pending_cb *pending_cb; struct packet_msg_long *pkt; u32 cb_size, ctl; struct hl_cb *cb; - int i; + int i, rc; + + mutex_lock(&hdev->fpriv_list_lock); + ctx = hdev->compute_ctx; /* If no compute context available or context is going down * memset registers directly */ - if (!ctx || kref_read(&ctx->refcount) == 0) - return gaudi_memset_registers(hdev, reg_base, num_regs, val); + if (!ctx || kref_read(&ctx->refcount) == 0) { + rc = gaudi_memset_registers(hdev, reg_base, num_regs, val); + mutex_unlock(&hdev->fpriv_list_lock); + return rc; + } + + mutex_unlock(&hdev->fpriv_list_lock); cb_size = (sizeof(*pkt) * num_regs) + sizeof(struct packet_msg_prot) * 2; -- cgit v1.2.3 From 639781dcab8261f39c7028db4ed4fd0e760d69fa Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Fri, 2 Apr 2021 01:43:18 +0300 Subject: habanalabs/gaudi: add debugfs to DMA from the device When trying to debug program, the user often needs to dump large parts of the device's DRAM, which can reach to tens of GBs. Because reading from the device's internal memory through the PCI BAR is extremely slow, the debug can take hours. Instead, we can provide the user to copy data through one of the DMA engines. This will make the operation much faster. Currently, only GAUDI is supported. In GAUDI, we need to find a PCI DMA engine that is IDLE and set the DMA as secured to be able to bypass our MMU as we currently don't map the temporary buffer to the MMU. Example bash one-line to dump entire HBM to file (~2 minutes): for (( i=0x0; i < 0x800000000; i+=0x8000000 )); do \ printf '0x%x\n' $i | sudo tee /sys/kernel/debug/habanalabs/hl0/addr ; \ echo 0x8000000 | sudo tee /sys/kernel/debug/habanalabs/hl0/dma_size ; \ sudo cat /sys/kernel/debug/habanalabs/hl0/data_dma >> hbm.txt ; done Signed-off-by: Oded Gabbay --- .../ABI/testing/debugfs-driver-habanalabs | 68 +++++++-- drivers/misc/habanalabs/common/debugfs.c | 119 ++++++++++++++- drivers/misc/habanalabs/common/habanalabs.h | 17 ++- drivers/misc/habanalabs/gaudi/gaudi.c | 159 +++++++++++++++++++++ drivers/misc/habanalabs/goya/goya.c | 8 ++ 5 files changed, 351 insertions(+), 20 deletions(-) diff --git a/Documentation/ABI/testing/debugfs-driver-habanalabs b/Documentation/ABI/testing/debugfs-driver-habanalabs index f9e233cbdc37..c78fc9282876 100644 --- a/Documentation/ABI/testing/debugfs-driver-habanalabs +++ b/Documentation/ABI/testing/debugfs-driver-habanalabs @@ -82,6 +82,24 @@ Description: Allows the root user to read or write 64 bit data directly If the IOMMU is disabled, it also allows the root user to read or write from the host a device VA of a host mapped memory +What: /sys/kernel/debug/habanalabs/hl/data_dma +Date: Apr 2021 +KernelVersion: 5.13 +Contact: ogabbay@kernel.org +Description: Allows the root user to read from the device's internal + memory (DRAM/SRAM) through a DMA engine. + This property is a binary blob that contains the result of the + DMA transfer. + This custom interface is needed (instead of using the generic + Linux user-space PCI mapping) because the amount of internal + memory is huge (>32GB) and reading it via the PCI bar will take + a very long time. + This interface doesn't support concurrency in the same device. + In GAUDI and GOYA, this action can cause undefined behavior + in case the it is done while the device is executing user + workloads. + Only supported on GAUDI at this stage. + What: /sys/kernel/debug/habanalabs/hl/device Date: Jan 2019 KernelVersion: 5.1 @@ -90,6 +108,24 @@ Description: Enables the root user to set the device to specific state. Valid values are "disable", "enable", "suspend", "resume". User can read this property to see the valid values +What: /sys/kernel/debug/habanalabs/hl/dma_size +Date: Apr 2021 +KernelVersion: 5.13 +Contact: ogabbay@kernel.org +Description: Specify the size of the DMA transaction when using DMA to read + from the device's internal memory. The value can not be larger + than 128MB. Writing to this value initiates the DMA transfer. + When the write is finished, the user can read the "data_dma" + blob + +What: /sys/kernel/debug/habanalabs/hl/dump_security_violations +Date: Jan 2021 +KernelVersion: 5.12 +Contact: ogabbay@kernel.org +Description: Dumps all security violations to dmesg. This will also ack + all security violations meanings those violations will not be + dumped next time user calls this API + What: /sys/kernel/debug/habanalabs/hl/engines Date: Jul 2019 KernelVersion: 5.3 @@ -154,6 +190,16 @@ Description: Displays the hop values and physical address for a given ASID e.g. to display info about VA 0x1000 for ASID 1 you need to do: echo "1 0x1000" > /sys/kernel/debug/habanalabs/hl0/mmu +What: /sys/kernel/debug/habanalabs/hl/mmu_error +Date: Mar 2021 +KernelVersion: 5.12 +Contact: fkassabri@habana.ai +Description: Check and display page fault or access violation mmu errors for + all MMUs specified in mmu_cap_mask. + e.g. to display error info for MMU hw cap bit 9, you need to do: + echo "0x200" > /sys/kernel/debug/habanalabs/hl0/mmu_error + cat /sys/kernel/debug/habanalabs/hl0/mmu_error + What: /sys/kernel/debug/habanalabs/hl/set_power_state Date: Jan 2019 KernelVersion: 5.1 @@ -161,6 +207,13 @@ Contact: ogabbay@kernel.org Description: Sets the PCI power state. Valid values are "1" for D0 and "2" for D3Hot +What: /sys/kernel/debug/habanalabs/hl/stop_on_err +Date: Mar 2020 +KernelVersion: 5.6 +Contact: ogabbay@kernel.org +Description: Sets the stop-on_error option for the device engines. Value of + "0" is for disable, otherwise enable. + What: /sys/kernel/debug/habanalabs/hl/userptr Date: Jan 2019 KernelVersion: 5.1 @@ -175,18 +228,3 @@ KernelVersion: 5.1 Contact: ogabbay@kernel.org Description: Displays a list with information about all the active virtual address mappings per ASID and all user mappings of HW blocks - -What: /sys/kernel/debug/habanalabs/hl/stop_on_err -Date: Mar 2020 -KernelVersion: 5.6 -Contact: ogabbay@kernel.org -Description: Sets the stop-on_error option for the device engines. Value of - "0" is for disable, otherwise enable. - -What: /sys/kernel/debug/habanalabs/hl/dump_security_violations -Date: Jan 2021 -KernelVersion: 5.12 -Contact: ogabbay@kernel.org -Description: Dumps all security violations to dmesg. This will also ack - all security violations meanings those violations will not be - dumped next time user calls this API diff --git a/drivers/misc/habanalabs/common/debugfs.c b/drivers/misc/habanalabs/common/debugfs.c index 33de54092543..8381155578a0 100644 --- a/drivers/misc/habanalabs/common/debugfs.c +++ b/drivers/misc/habanalabs/common/debugfs.c @@ -9,8 +9,8 @@ #include "../include/hw_ip/mmu/mmu_general.h" #include -#include #include +#include #define MMU_ADDR_BUF_SIZE 40 #define MMU_ASID_BUF_SIZE 10 @@ -457,6 +457,34 @@ out: return false; } +static bool hl_is_device_internal_memory_va(struct hl_device *hdev, u64 addr, + u32 size) +{ + struct asic_fixed_properties *prop = &hdev->asic_prop; + u64 dram_start_addr, dram_end_addr; + + if (!hdev->mmu_enable) + return false; + + if (prop->dram_supports_virtual_memory) { + dram_start_addr = prop->dmmu.start_addr; + dram_end_addr = prop->dmmu.end_addr; + } else { + dram_start_addr = prop->dram_base_address; + dram_end_addr = prop->dram_end_address; + } + + if (hl_mem_area_inside_range(addr, size, dram_start_addr, + dram_end_addr)) + return true; + + if (hl_mem_area_inside_range(addr, size, prop->sram_base_address, + prop->sram_end_address)) + return true; + + return false; +} + static int device_va_to_pa(struct hl_device *hdev, u64 virt_addr, u32 size, u64 *phys_addr) { @@ -599,6 +627,11 @@ static ssize_t hl_data_read64(struct file *f, char __user *buf, ssize_t rc; u64 val; + if (atomic_read(&hdev->in_reset)) { + dev_warn_ratelimited(hdev->dev, "Can't read during reset\n"); + return 0; + } + if (*ppos) return 0; @@ -630,6 +663,11 @@ static ssize_t hl_data_write64(struct file *f, const char __user *buf, u64 value; ssize_t rc; + if (atomic_read(&hdev->in_reset)) { + dev_warn_ratelimited(hdev->dev, "Can't write during reset\n"); + return 0; + } + rc = kstrtoull_from_user(buf, count, 16, &value); if (rc) return rc; @@ -651,6 +689,63 @@ static ssize_t hl_data_write64(struct file *f, const char __user *buf, return count; } +static ssize_t hl_dma_size_write(struct file *f, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct hl_dbg_device_entry *entry = file_inode(f)->i_private; + struct hl_device *hdev = entry->hdev; + u64 addr = entry->addr; + ssize_t rc; + u32 size; + + if (atomic_read(&hdev->in_reset)) { + dev_warn_ratelimited(hdev->dev, "Can't DMA during reset\n"); + return 0; + } + rc = kstrtouint_from_user(buf, count, 16, &size); + if (rc) + return rc; + + if (!size) { + dev_err(hdev->dev, "DMA read failed. size can't be 0\n"); + return -EINVAL; + } + + if (size > SZ_128M) { + dev_err(hdev->dev, + "DMA read failed. size can't be larger than 128MB\n"); + return -EINVAL; + } + + if (!hl_is_device_internal_memory_va(hdev, addr, size)) { + dev_err(hdev->dev, + "DMA read failed. Invalid 0x%010llx + 0x%08x\n", + addr, size); + return -EINVAL; + } + + /* Free the previous allocation, if there was any */ + entry->blob_desc.size = 0; + vfree(entry->blob_desc.data); + + entry->blob_desc.data = vmalloc(size); + if (!entry->blob_desc.data) + return -ENOMEM; + + rc = hdev->asic_funcs->debugfs_read_dma(hdev, addr, size, + entry->blob_desc.data); + if (rc) { + dev_err(hdev->dev, "Failed to DMA from 0x%010llx\n", addr); + vfree(entry->blob_desc.data); + entry->blob_desc.data = NULL; + return -EIO; + } + + entry->blob_desc.size = size; + + return count; +} + static ssize_t hl_get_power_state(struct file *f, char __user *buf, size_t count, loff_t *ppos) { @@ -960,6 +1055,11 @@ static const struct file_operations hl_data64b_fops = { .write = hl_data_write64 }; +static const struct file_operations hl_dma_size_fops = { + .owner = THIS_MODULE, + .write = hl_dma_size_write +}; + static const struct file_operations hl_i2c_data_fops = { .owner = THIS_MODULE, .read = hl_i2c_data_read, @@ -1062,6 +1162,9 @@ void hl_debugfs_add_device(struct hl_device *hdev) if (!dev_entry->entry_arr) return; + dev_entry->blob_desc.size = 0; + dev_entry->blob_desc.data = NULL; + INIT_LIST_HEAD(&dev_entry->file_list); INIT_LIST_HEAD(&dev_entry->cb_list); INIT_LIST_HEAD(&dev_entry->cs_list); @@ -1164,6 +1267,17 @@ void hl_debugfs_add_device(struct hl_device *hdev) dev_entry, &hl_security_violations_fops); + debugfs_create_file("dma_size", + 0200, + dev_entry->root, + dev_entry, + &hl_dma_size_fops); + + debugfs_create_blob("data_dma", + 0400, + dev_entry->root, + &dev_entry->blob_desc); + for (i = 0, entry = dev_entry->entry_arr ; i < count ; i++, entry++) { debugfs_create_file(hl_debugfs_list[i].name, 0444, @@ -1182,6 +1296,9 @@ void hl_debugfs_remove_device(struct hl_device *hdev) debugfs_remove_recursive(entry->root); mutex_destroy(&entry->file_mutex); + + vfree(entry->blob_desc.data); + kfree(entry->entry_arr); } diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 54d7735991c7..d89ae4c3d634 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -854,8 +855,12 @@ enum div_select_defs { * @update_eq_ci: update event queue CI. * @context_switch: called upon ASID context switch. * @restore_phase_topology: clear all SOBs amd MONs. - * @debugfs_read32: debug interface for reading u32 from DRAM/SRAM. - * @debugfs_write32: debug interface for writing u32 to DRAM/SRAM. + * @debugfs_read32: debug interface for reading u32 from DRAM/SRAM/Host memory. + * @debugfs_write32: debug interface for writing u32 to DRAM/SRAM/Host memory. + * @debugfs_read64: debug interface for reading u64 from DRAM/SRAM/Host memory. + * @debugfs_write64: debug interface for writing u64 to DRAM/SRAM/Host memory. + * @debugfs_read_dma: debug interface for reading up to 2MB from the device's + * internal memory via DMA engine. * @add_device_attr: add ASIC specific device attributes. * @handle_eqe: handle event queue entry (IRQ) from CPU-CP. * @set_pll_profile: change PLL profile (manual/automatic). @@ -979,6 +984,8 @@ struct hl_asic_funcs { bool user_address, u64 *val); int (*debugfs_write64)(struct hl_device *hdev, u64 addr, bool user_address, u64 val); + int (*debugfs_read_dma)(struct hl_device *hdev, u64 addr, u32 size, + void *blob_addr); void (*add_device_attr)(struct hl_device *hdev, struct attribute_group *dev_attr_grp); void (*handle_eqe)(struct hl_device *hdev, @@ -1569,12 +1576,13 @@ struct hl_debugfs_entry { * @userptr_spinlock: protects userptr_list. * @ctx_mem_hash_list: list of available contexts with MMU mappings. * @ctx_mem_hash_spinlock: protects cb_list. + * @blob_desc: descriptor of blob * @addr: next address to read/write from/to in read/write32. * @mmu_addr: next virtual address to translate to physical address in mmu_show. * @mmu_asid: ASID to use while translating in mmu_show. * @i2c_bus: generic u8 debugfs file for bus value to use in i2c_data_read. - * @i2c_bus: generic u8 debugfs file for address value to use in i2c_data_read. - * @i2c_bus: generic u8 debugfs file for register value to use in i2c_data_read. + * @i2c_addr: generic u8 debugfs file for address value to use in i2c_data_read. + * @i2c_reg: generic u8 debugfs file for register value to use in i2c_data_read. */ struct hl_dbg_device_entry { struct dentry *root; @@ -1592,6 +1600,7 @@ struct hl_dbg_device_entry { spinlock_t userptr_spinlock; struct list_head ctx_mem_hash_list; spinlock_t ctx_mem_hash_spinlock; + struct debugfs_blob_wrapper blob_desc; u64 addr; u64 mmu_addr; u32 mmu_asid; diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index bd711c8d3874..03d3fb643e79 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -6175,6 +6175,164 @@ static int gaudi_debugfs_write64(struct hl_device *hdev, u64 addr, return rc; } +static int gaudi_dma_core_transfer(struct hl_device *hdev, int dma_id, u64 addr, + u32 size_to_dma, dma_addr_t dma_addr) +{ + u32 err_cause, val; + u64 dma_offset; + int rc; + + dma_offset = dma_id * DMA_CORE_OFFSET; + + WREG32(mmDMA0_CORE_SRC_BASE_LO + dma_offset, lower_32_bits(addr)); + WREG32(mmDMA0_CORE_SRC_BASE_HI + dma_offset, upper_32_bits(addr)); + WREG32(mmDMA0_CORE_DST_BASE_LO + dma_offset, lower_32_bits(dma_addr)); + WREG32(mmDMA0_CORE_DST_BASE_HI + dma_offset, upper_32_bits(dma_addr)); + WREG32(mmDMA0_CORE_DST_TSIZE_0 + dma_offset, size_to_dma); + WREG32(mmDMA0_CORE_COMMIT + dma_offset, + (1 << DMA0_CORE_COMMIT_LIN_SHIFT)); + + rc = hl_poll_timeout( + hdev, + mmDMA0_CORE_STS0 + dma_offset, + val, + ((val & DMA0_CORE_STS0_BUSY_MASK) == 0), + 0, + 1000000); + + if (rc) { + dev_err(hdev->dev, + "DMA %d timed-out during reading of 0x%llx\n", + dma_id, addr); + return -EIO; + } + + /* Verify DMA is OK */ + err_cause = RREG32(mmDMA0_CORE_ERR_CAUSE + dma_offset); + if (err_cause) { + dev_err(hdev->dev, "DMA Failed, cause 0x%x\n", err_cause); + dev_dbg(hdev->dev, + "Clearing DMA0 engine from errors (cause 0x%x)\n", + err_cause); + WREG32(mmDMA0_CORE_ERR_CAUSE + dma_offset, err_cause); + + return -EIO; + } + + return 0; +} + +static int gaudi_debugfs_read_dma(struct hl_device *hdev, u64 addr, u32 size, + void *blob_addr) +{ + u32 dma_core_sts0, err_cause, cfg1, size_left, pos, size_to_dma; + struct gaudi_device *gaudi = hdev->asic_specific; + u64 dma_offset, qm_offset; + dma_addr_t dma_addr; + void *kernel_addr; + bool is_eng_idle; + int rc, dma_id; + + kernel_addr = hdev->asic_funcs->asic_dma_alloc_coherent( + hdev, SZ_2M, + &dma_addr, + GFP_KERNEL | __GFP_ZERO); + + if (!kernel_addr) + return -ENOMEM; + + mutex_lock(&gaudi->clk_gate_mutex); + + hdev->asic_funcs->disable_clock_gating(hdev); + + hdev->asic_funcs->hw_queues_lock(hdev); + + dma_id = gaudi_dma_assignment[GAUDI_PCI_DMA_1]; + dma_offset = dma_id * DMA_CORE_OFFSET; + qm_offset = dma_id * DMA_QMAN_OFFSET; + dma_core_sts0 = RREG32(mmDMA0_CORE_STS0 + dma_offset); + is_eng_idle = IS_DMA_IDLE(dma_core_sts0); + + if (!is_eng_idle) { + dma_id = gaudi_dma_assignment[GAUDI_PCI_DMA_2]; + dma_offset = dma_id * DMA_CORE_OFFSET; + qm_offset = dma_id * DMA_QMAN_OFFSET; + dma_core_sts0 = RREG32(mmDMA0_CORE_STS0 + dma_offset); + is_eng_idle = IS_DMA_IDLE(dma_core_sts0); + + if (!is_eng_idle) { + dev_err_ratelimited(hdev->dev, + "Can't read via DMA because it is BUSY\n"); + rc = -EAGAIN; + goto out; + } + } + + cfg1 = RREG32(mmDMA0_QM_GLBL_CFG1 + qm_offset); + WREG32(mmDMA0_QM_GLBL_CFG1 + qm_offset, + 0xF << DMA0_QM_GLBL_CFG1_CP_STOP_SHIFT); + + /* TODO: remove this by mapping the DMA temporary buffer to the MMU + * using the compute ctx ASID, if exists. If not, use the kernel ctx + * ASID + */ + WREG32_OR(mmDMA0_CORE_PROT + dma_offset, BIT(DMA0_CORE_PROT_VAL_SHIFT)); + + /* Verify DMA is OK */ + err_cause = RREG32(mmDMA0_CORE_ERR_CAUSE + dma_offset); + if (err_cause) { + dev_dbg(hdev->dev, + "Clearing DMA0 engine from errors (cause 0x%x)\n", + err_cause); + WREG32(mmDMA0_CORE_ERR_CAUSE + dma_offset, err_cause); + } + + pos = 0; + size_left = size; + size_to_dma = SZ_2M; + + while (size_left > 0) { + + if (size_left < SZ_2M) + size_to_dma = size_left; + + rc = gaudi_dma_core_transfer(hdev, dma_id, addr, size_to_dma, + dma_addr); + if (rc) + break; + + memcpy(blob_addr + pos, kernel_addr, size_to_dma); + + if (size_left <= SZ_2M) + break; + + pos += SZ_2M; + addr += SZ_2M; + size_left -= SZ_2M; + } + + /* TODO: remove this by mapping the DMA temporary buffer to the MMU + * using the compute ctx ASID, if exists. If not, use the kernel ctx + * ASID + */ + WREG32_AND(mmDMA0_CORE_PROT + dma_offset, + ~BIT(DMA0_CORE_PROT_VAL_SHIFT)); + + WREG32(mmDMA0_QM_GLBL_CFG1 + qm_offset, cfg1); + +out: + hdev->asic_funcs->hw_queues_unlock(hdev); + + hdev->asic_funcs->set_clock_gating(hdev); + + mutex_unlock(&gaudi->clk_gate_mutex); + + hdev->asic_funcs->asic_dma_free_coherent(hdev, SZ_2M, kernel_addr, + dma_addr); + + return rc; +} + static u64 gaudi_read_pte(struct hl_device *hdev, u64 addr) { struct gaudi_device *gaudi = hdev->asic_specific; @@ -8639,6 +8797,7 @@ static const struct hl_asic_funcs gaudi_funcs = { .debugfs_write32 = gaudi_debugfs_write32, .debugfs_read64 = gaudi_debugfs_read64, .debugfs_write64 = gaudi_debugfs_write64, + .debugfs_read_dma = gaudi_debugfs_read_dma, .add_device_attr = gaudi_add_device_attr, .handle_eqe = gaudi_handle_eqe, .set_pll_profile = gaudi_set_pll_profile, diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 09b423455439..175b7b0af450 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -4329,6 +4329,13 @@ static int goya_debugfs_write64(struct hl_device *hdev, u64 addr, return rc; } +static int goya_debugfs_read_dma(struct hl_device *hdev, u64 addr, u32 size, + void *blob_addr) +{ + dev_err(hdev->dev, "Reading via DMA is unimplemented yet\n"); + return -EPERM; +} + static u64 goya_read_pte(struct hl_device *hdev, u64 addr) { struct goya_device *goya = hdev->asic_specific; @@ -5521,6 +5528,7 @@ static const struct hl_asic_funcs goya_funcs = { .debugfs_write32 = goya_debugfs_write32, .debugfs_read64 = goya_debugfs_read64, .debugfs_write64 = goya_debugfs_write64, + .debugfs_read_dma = goya_debugfs_read_dma, .add_device_attr = goya_add_device_attr, .handle_eqe = goya_handle_eqe, .set_pll_profile = goya_set_pll_profile, -- cgit v1.2.3 From 131d1ba1304a9a2040648cb03309d9444e7fe45f Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Fri, 2 Apr 2021 22:24:38 +0300 Subject: habanalabs: remove the store jobs array from CS IOCTL The store part was never implemented in the code and never been used by the userspace applications. We currently use the related parameters to a different purpose with a defined union. However, there is no point in that and it is better to just remove the union and the store parameters. Signed-off-by: Oded Gabbay --- include/uapi/misc/habanalabs.h | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/include/uapi/misc/habanalabs.h b/include/uapi/misc/habanalabs.h index 90798eaac728..d3e017b5f0db 100644 --- a/include/uapi/misc/habanalabs.h +++ b/include/uapi/misc/habanalabs.h @@ -644,17 +644,10 @@ struct hl_cs_in { /* holds address of array of hl_cs_chunk for execution phase */ __u64 chunks_execute; - union { - /* this holds address of array of hl_cs_chunk for store phase - - * Currently not in use - */ - __u64 chunks_store; - - /* Sequence number of a staged submission CS - * valid only if HL_CS_FLAGS_STAGED_SUBMISSION is set - */ - __u64 seq; - }; + /* Sequence number of a staged submission CS + * valid only if HL_CS_FLAGS_STAGED_SUBMISSION is set + */ + __u64 seq; /* Number of chunks in restore phase array. Maximum number is * HL_MAX_JOBS_PER_CS @@ -666,18 +659,10 @@ struct hl_cs_in { */ __u32 num_chunks_execute; - union { - /* Number of chunks in restore phase array - - * Currently not in use - */ - __u32 num_chunks_store; - - /* timeout in seconds - valid only if HL_CS_FLAGS_CUSTOM_TIMEOUT - * is set. this parameter is ignored in case of future multiple - * users support. - */ - __u32 timeout; - }; + /* timeout in seconds - valid only if HL_CS_FLAGS_CUSTOM_TIMEOUT + * is set + */ + __u32 timeout; /* HL_CS_FLAGS_* */ __u32 cs_flags; @@ -1051,8 +1036,8 @@ struct hl_debug_args { * Each JOB will be enqueued on a specific queue, according to the user's input. * There can be more then one JOB per queue. * - * The CS IOCTL will receive three sets of JOBS. One set is for "restore" phase, - * a second set is for "execution" phase and a third set is for "store" phase. + * The CS IOCTL will receive two sets of JOBS. One set is for "restore" phase + * and a second set is for "execution" phase. * The JOBS on the "restore" phase are enqueued only after context-switch * (or if its the first CS for this context). The user can also order the * driver to run the "restore" phase explicitly -- cgit v1.2.3 From ae382c22fc06058b24bb49c92f3b0af653499589 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Sat, 3 Apr 2021 16:37:29 +0300 Subject: habanalabs: use strscpy instead of sprintf and strlcpy Prefer the use of strscpy when copying the ASIC name into a char array, to prevent accidentally exceeding the array's length. In addition, strlcpy is frowned upon so replace it. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index e64c60d48d42..2ed4f2bedc08 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -321,11 +321,11 @@ static int device_early_init(struct hl_device *hdev) switch (hdev->asic_type) { case ASIC_GOYA: goya_set_asic_funcs(hdev); - strlcpy(hdev->asic_name, "GOYA", sizeof(hdev->asic_name)); + strscpy(hdev->asic_name, "GOYA", sizeof(hdev->asic_name)); break; case ASIC_GAUDI: gaudi_set_asic_funcs(hdev); - sprintf(hdev->asic_name, "GAUDI"); + strscpy(hdev->asic_name, "GAUDI", sizeof(hdev->asic_name)); break; default: dev_err(hdev->dev, "Unrecognized ASIC type %d\n", -- cgit v1.2.3 From 7d21114b03618a1b528804a631098b471eac6481 Mon Sep 17 00:00:00 2001 From: Koby Elbaz Date: Thu, 11 Mar 2021 15:32:55 +0200 Subject: habanalabs: support DEVICE_UNUSABLE error indication from FW In case of multiple ECC errors, FW will set the DEVICE_UNUSABLE bit. On boot-up, the driver will therefore fail inserting the device. Signed-off-by: Koby Elbaz Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 3 +++ drivers/misc/habanalabs/include/common/hl_boot_if.h | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 092691a8917d..d81a8d537373 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -342,6 +342,9 @@ static int fw_read_errors(struct hl_device *hdev, u32 boot_err0_reg, dev_err(hdev->dev, "Device boot error - eFuse failure\n"); if (err_val & CPU_BOOT_ERR0_PLL_FAIL) dev_err(hdev->dev, "Device boot error - PLL failure\n"); + if (err_val & CPU_BOOT_ERR0_DEVICE_UNUSABLE_FAIL) + dev_err(hdev->dev, + "Device boot error - device unusable failure\n"); security_val = RREG32(cpu_security_boot_status_reg); if (security_val & CPU_BOOT_DEV_STS0_ENABLED) diff --git a/drivers/misc/habanalabs/include/common/hl_boot_if.h b/drivers/misc/habanalabs/include/common/hl_boot_if.h index 1717874ff306..980b432fd76e 100644 --- a/drivers/misc/habanalabs/include/common/hl_boot_if.h +++ b/drivers/misc/habanalabs/include/common/hl_boot_if.h @@ -73,6 +73,9 @@ * CPU_BOOT_ERR0_PLL_FAIL PLL settings failed, meaning that one * of the PLLs remains in REF_CLK * + * CPU_BOOT_ERR0_DEVICE_UNUSABLE_FAIL Device is unusable and customer support + * should be contacted. + * * CPU_BOOT_ERR0_ENABLED Error registers enabled. * This is a main indication that the * running FW populates the error @@ -92,6 +95,7 @@ #define CPU_BOOT_ERR0_PRI_IMG_VER_FAIL (1 << 10) #define CPU_BOOT_ERR0_SEC_IMG_VER_FAIL (1 << 11) #define CPU_BOOT_ERR0_PLL_FAIL (1 << 12) +#define CPU_BOOT_ERR0_DEVICE_UNUSABLE_FAIL (1 << 13) #define CPU_BOOT_ERR0_ENABLED (1 << 31) /* -- cgit v1.2.3 From 1b4971573fde0c4d4ed7de70c3a9cfd08330a541 Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Tue, 6 Apr 2021 13:32:20 +0300 Subject: habanalabs/gaudi: clear QM errors only if not in stop_on_err mode Clearing QM errors by the driver will prevent these H/W blocks from stopping in case they are configured to stop on errors, so perform this clearing only if this mode is not in use. Signed-off-by: Tomer Tayar Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 03d3fb643e79..791434278904 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -7086,7 +7086,8 @@ static void gaudi_handle_qman_err_generic(struct hl_device *hdev, } /* Write 1 clear errors */ - WREG32(glbl_sts_addr + 4 * i, glbl_sts_clr_val); + if (!hdev->stop_on_err) + WREG32(glbl_sts_addr + 4 * i, glbl_sts_clr_val); } arb_err_val = RREG32(arb_err_addr); -- cgit v1.2.3 From e9c2003be4d4809c7e3bf17167ef08a3be7b43d2 Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Mon, 22 Mar 2021 14:30:52 +0200 Subject: habanalabs: send dynamic msi-x indexes to f/w In order to minimize hard coded values between F/W and the driver, we send msi-x indexes dynamically to the F/W. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 67 ++++++++++++++++++++ drivers/misc/habanalabs/common/habanalabs.h | 4 ++ drivers/misc/habanalabs/gaudi/gaudi.c | 2 +- drivers/misc/habanalabs/goya/goya.c | 2 +- drivers/misc/habanalabs/include/common/cpucp_if.h | 75 ++++++++++++++++++----- 5 files changed, 131 insertions(+), 19 deletions(-) diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index d81a8d537373..532a2fd7bfb4 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -422,6 +422,73 @@ out: return rc; } +static int hl_fw_send_msi_info_msg(struct hl_device *hdev) +{ + struct cpucp_array_data_packet *pkt; + size_t total_pkt_size, data_size; + u64 result; + int rc; + + /* skip sending this info for unsupported ASICs */ + if (!hdev->asic_funcs->get_msi_info) + return 0; + + data_size = CPUCP_NUM_OF_MSI_TYPES * sizeof(u32); + total_pkt_size = sizeof(struct cpucp_array_data_packet) + data_size; + + /* data should be aligned to 8 bytes in order to CPU-CP to copy it */ + total_pkt_size = (total_pkt_size + 0x7) & ~0x7; + + /* total_pkt_size is casted to u16 later on */ + if (total_pkt_size > USHRT_MAX) { + dev_err(hdev->dev, "CPUCP array data is too big\n"); + return -EINVAL; + } + + pkt = kzalloc(total_pkt_size, GFP_KERNEL); + if (!pkt) + return -ENOMEM; + + pkt->length = cpu_to_le32(CPUCP_NUM_OF_MSI_TYPES); + + hdev->asic_funcs->get_msi_info((u32 *)&pkt->data); + + pkt->cpucp_pkt.ctl = cpu_to_le32(CPUCP_PACKET_MSI_INFO_SET << + CPUCP_PKT_CTL_OPCODE_SHIFT); + + rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *)pkt, + total_pkt_size, 0, &result); + + /* + * in case packet result is invalid it means that FW does not support + * this feature and will use default/hard coded MSI values. no reason + * to stop the boot + */ + if (rc && result == cpucp_packet_invalid) + rc = 0; + + if (rc) + dev_err(hdev->dev, "failed to send CPUCP array data\n"); + + kfree(pkt); + + return rc; +} + +int hl_fw_cpucp_handshake(struct hl_device *hdev, + u32 cpu_security_boot_status_reg, + u32 boot_err0_reg) +{ + int rc; + + rc = hl_fw_cpucp_info_get(hdev, cpu_security_boot_status_reg, + boot_err0_reg); + if (rc) + return rc; + + return hl_fw_send_msi_info_msg(hdev); +} + int hl_fw_get_eeprom_data(struct hl_device *hdev, void *data, size_t max_size) { struct cpucp_packet pkt = {}; diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index d89ae4c3d634..867986ef4588 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -1049,6 +1049,7 @@ struct hl_asic_funcs { int (*hw_block_mmap)(struct hl_device *hdev, struct vm_area_struct *vma, u32 block_id, u32 block_size); void (*enable_events_from_fw)(struct hl_device *hdev); + void (*get_msi_info)(u32 *table); }; @@ -2374,6 +2375,9 @@ int hl_fw_send_heartbeat(struct hl_device *hdev); int hl_fw_cpucp_info_get(struct hl_device *hdev, u32 cpu_security_boot_status_reg, u32 boot_err0_reg); +int hl_fw_cpucp_handshake(struct hl_device *hdev, + u32 cpu_security_boot_status_reg, + u32 boot_err0_reg); int hl_fw_get_eeprom_data(struct hl_device *hdev, void *data, size_t max_size); int hl_fw_cpucp_pci_counters_get(struct hl_device *hdev, struct hl_info_pci_counters *counters); diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 791434278904..62e3c63bec20 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -7966,7 +7966,7 @@ static int gaudi_cpucp_info_get(struct hl_device *hdev) if (!(gaudi->hw_cap_initialized & HW_CAP_CPU_Q)) return 0; - rc = hl_fw_cpucp_info_get(hdev, mmCPU_BOOT_DEV_STS0, mmCPU_BOOT_ERR0); + rc = hl_fw_cpucp_handshake(hdev, mmCPU_BOOT_DEV_STS0, mmCPU_BOOT_ERR0); if (rc) return rc; diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 175b7b0af450..9d49ba649db0 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -5245,7 +5245,7 @@ int goya_cpucp_info_get(struct hl_device *hdev) if (!(goya->hw_cap_initialized & HW_CAP_CPU_Q)) return 0; - rc = hl_fw_cpucp_info_get(hdev, mmCPU_BOOT_DEV_STS0, mmCPU_BOOT_ERR0); + rc = hl_fw_cpucp_handshake(hdev, mmCPU_BOOT_DEV_STS0, mmCPU_BOOT_ERR0); if (rc) return rc; diff --git a/drivers/misc/habanalabs/include/common/cpucp_if.h b/drivers/misc/habanalabs/include/common/cpucp_if.h index 88e8ce6e0694..20a710f7a369 100644 --- a/drivers/misc/habanalabs/include/common/cpucp_if.h +++ b/drivers/misc/habanalabs/include/common/cpucp_if.h @@ -302,6 +302,27 @@ enum pq_init_status { * CPUCP_PACKET_POWER_GET * Fetch the present power consumption of the device (Current * Voltage). * + * CPUCP_PACKET_NIC_PFC_SET - + * Enable/Disable the NIC PFC feature. The packet's arguments specify the + * NIC port, relevant lanes to configure and one bit indication for + * enable/disable. + * + * CPUCP_PACKET_NIC_FAULT_GET - + * Fetch the current indication for local/remote faults from the NIC MAC. + * The result is 32-bit value of the relevant register. + * + * CPUCP_PACKET_NIC_LPBK_SET - + * Enable/Disable the MAC loopback feature. The packet's arguments specify + * the NIC port, relevant lanes to configure and one bit indication for + * enable/disable. + * + * CPUCP_PACKET_NIC_MAC_INIT - + * Configure the NIC MAC channels. The packet's arguments specify the + * NIC port and the speed. + * + * CPUCP_PACKET_MSI_INFO_SET - + * set the index number for each supported msi type going from + * host to device */ enum cpucp_packet_id { @@ -337,6 +358,11 @@ enum cpucp_packet_id { CPUCP_PACKET_PLL_INFO_GET, /* internal */ CPUCP_PACKET_NIC_STATUS, /* internal */ CPUCP_PACKET_POWER_GET, /* internal */ + CPUCP_PACKET_NIC_PFC_SET, /* internal */ + CPUCP_PACKET_NIC_FAULT_GET, /* internal */ + CPUCP_PACKET_NIC_LPBK_SET, /* internal */ + CPUCP_PACKET_NIC_MAC_CFG, /* internal */ + CPUCP_PACKET_MSI_INFO_SET, /* internal */ }; #define CPUCP_PACKET_FENCE_VAL 0xFE8CE7A5 @@ -408,6 +434,12 @@ struct cpucp_unmask_irq_arr_packet { __le32 irqs[0]; }; +struct cpucp_array_data_packet { + struct cpucp_packet cpucp_pkt; + __le32 length; + __le32 data[0]; +}; + enum cpucp_packet_rc { cpucp_packet_success, cpucp_packet_invalid, @@ -476,6 +508,22 @@ enum cpucp_pll_type_attributes { cpucp_pll_pci, }; +/* + * MSI type enumeration table for all ASICs and future SW versions. + * For future ASIC-LKD compatibility, we can only add new enumerations. + * at the end of the table (before CPUCP_NUM_OF_MSI_TYPES). + * Changing the order of entries or removing entries is not allowed. + */ +enum cpucp_msi_type { + CPUCP_EVENT_QUEUE_MSI_TYPE, + CPUCP_NIC_PORT1_MSI_TYPE, + CPUCP_NIC_PORT3_MSI_TYPE, + CPUCP_NIC_PORT5_MSI_TYPE, + CPUCP_NIC_PORT7_MSI_TYPE, + CPUCP_NIC_PORT9_MSI_TYPE, + CPUCP_NUM_OF_MSI_TYPES +}; + /* * PLL enumeration table used for all ASICs and future SW versions. * For future ASIC-LKD compatibility, we can only add new enumerations. @@ -492,23 +540,16 @@ enum pll_index { TPC_PLL = 6, IF_PLL = 7, SRAM_PLL = 8, - NS_DCORE_PLL = 9, - MESH_DCORE_PLL = 10, - HBM_PLL = 11, - TPC_DCORE_PLL = 12, - VIDEO_DCORE_PLL = 13, - SRAM_DCORE_PLL = 14, - NIC_PHY_DCORE_PLL = 15, - MSS_DCORE_PLL = 16, - DMA_DCORE_PLL = 17, - SIF_PLL = 18, - DDR_PLL = 19, - VID_PLL = 20, - BANK_PLL = 21, - MMU_PLL = 22, - IC_PLL = 23, - MC_PLL = 24, - EMMC_PLL = 25, + NS_PLL = 9, + HBM_PLL = 10, + MSS_PLL = 11, + DDR_PLL = 12, + VID_PLL = 13, + BANK_PLL = 14, + MMU_PLL = 15, + IC_PLL = 16, + MC_PLL = 17, + EMMC_PLL = 18, PLL_MAX }; -- cgit v1.2.3 From d4b1e5da54c067ca248191aaee5f531c4d30ba29 Mon Sep 17 00:00:00 2001 From: Bharat Jauhari Date: Thu, 18 Mar 2021 12:11:19 +0200 Subject: habanalabs: move dram scrub to free sequence DRAM scrubbing can take time hence it adds to latency during allocation. To minimize latency during initialization, scrubbing is moved to release call. In case scrubbing fails it means the device is in a bad state, hence HARD reset is initiated. Signed-off-by: Bharat Jauhari Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/memory.c | 87 ++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/drivers/misc/habanalabs/common/memory.c b/drivers/misc/habanalabs/common/memory.c index 6530fddbbc21..2938cbbafbbc 100644 --- a/drivers/misc/habanalabs/common/memory.c +++ b/drivers/misc/habanalabs/common/memory.c @@ -81,16 +81,6 @@ static int alloc_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args, num_pgs, total_size); return -ENOMEM; } - - if (hdev->memory_scrub) { - rc = hdev->asic_funcs->scrub_device_mem(hdev, paddr, - total_size); - if (rc) { - dev_err(hdev->dev, - "Failed to scrub contiguous device memory\n"); - goto pages_pack_err; - } - } } phys_pg_pack = kzalloc(sizeof(*phys_pg_pack), GFP_KERNEL); @@ -128,17 +118,6 @@ static int alloc_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args, goto page_err; } - if (hdev->memory_scrub) { - rc = hdev->asic_funcs->scrub_device_mem(hdev, - phys_pg_pack->pages[i], - page_size); - if (rc) { - dev_err(hdev->dev, - "Failed to scrub device memory\n"); - goto page_err; - } - } - num_curr_pgs++; } } @@ -280,37 +259,67 @@ static void dram_pg_pool_do_release(struct kref *ref) * @phys_pg_pack: physical page pack to free. * * This function does the following: - * - For DRAM memory only, iterate over the pack and free each physical block - * structure by returning it to the general pool. + * - For DRAM memory only + * - iterate over the pack, scrub and free each physical block structure by + * returning it to the general pool. + * In case of error during scrubbing, initiate hard reset. + * Once hard reset is triggered, scrubbing is bypassed while freeing the + * memory continues. * - Free the hl_vm_phys_pg_pack structure. */ -static void free_phys_pg_pack(struct hl_device *hdev, +static int free_phys_pg_pack(struct hl_device *hdev, struct hl_vm_phys_pg_pack *phys_pg_pack) { struct hl_vm *vm = &hdev->vm; u64 i; + int rc = 0; + + if (phys_pg_pack->created_from_userptr) + goto end; - if (!phys_pg_pack->created_from_userptr) { - if (phys_pg_pack->contiguous) { - gen_pool_free(vm->dram_pg_pool, phys_pg_pack->pages[0], + if (phys_pg_pack->contiguous) { + if (hdev->memory_scrub && !hdev->disabled) { + rc = hdev->asic_funcs->scrub_device_mem(hdev, + phys_pg_pack->pages[0], phys_pg_pack->total_size); + if (rc) + dev_err(hdev->dev, + "Failed to scrub contiguous device memory\n"); + } - for (i = 0; i < phys_pg_pack->npages ; i++) - kref_put(&vm->dram_pg_pool_refcount, - dram_pg_pool_do_release); - } else { - for (i = 0 ; i < phys_pg_pack->npages ; i++) { - gen_pool_free(vm->dram_pg_pool, + gen_pool_free(vm->dram_pg_pool, phys_pg_pack->pages[0], + phys_pg_pack->total_size); + + for (i = 0; i < phys_pg_pack->npages ; i++) + kref_put(&vm->dram_pg_pool_refcount, + dram_pg_pool_do_release); + } else { + for (i = 0 ; i < phys_pg_pack->npages ; i++) { + if (hdev->memory_scrub && !hdev->disabled && rc == 0) { + rc = hdev->asic_funcs->scrub_device_mem( + hdev, phys_pg_pack->pages[i], phys_pg_pack->page_size); - kref_put(&vm->dram_pg_pool_refcount, - dram_pg_pool_do_release); + if (rc) + dev_err(hdev->dev, + "Failed to scrub device memory\n"); } + gen_pool_free(vm->dram_pg_pool, + phys_pg_pack->pages[i], + phys_pg_pack->page_size); + kref_put(&vm->dram_pg_pool_refcount, + dram_pg_pool_do_release); } } + if (rc && !hdev->disabled) + hl_device_reset(hdev, HL_RESET_HARD); + +end: kvfree(phys_pg_pack->pages); kfree(phys_pg_pack); + + return rc; } /** @@ -349,7 +358,7 @@ static int free_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args) atomic64_sub(phys_pg_pack->total_size, &ctx->dram_phys_mem); atomic64_sub(phys_pg_pack->total_size, &hdev->dram_used_mem); - free_phys_pg_pack(hdev, phys_pg_pack); + return free_phys_pg_pack(hdev, phys_pg_pack); } else { spin_unlock(&vm->idr_lock); dev_err(hdev->dev, @@ -1131,9 +1140,9 @@ static int map_device_va(struct hl_ctx *ctx, struct hl_mem_in *args, *device_addr = ret_vaddr; if (is_userptr) - free_phys_pg_pack(hdev, phys_pg_pack); + rc = free_phys_pg_pack(hdev, phys_pg_pack); - return 0; + return rc; map_err: if (add_va_block(hdev, va_range, ret_vaddr, @@ -1286,7 +1295,7 @@ static int unmap_device_va(struct hl_ctx *ctx, struct hl_mem_in *args, kfree(hnode); if (is_userptr) { - free_phys_pg_pack(hdev, phys_pg_pack); + rc = free_phys_pg_pack(hdev, phys_pg_pack); dma_unmap_host_va(hdev, userptr); } -- cgit v1.2.3 From e5042a6fa6d4aa1168b3521298c92a53978c9d99 Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Thu, 1 Apr 2021 13:43:40 +0300 Subject: habanalabs/gaudi: derive security status from pci id As F/ security indication must be available before driver approaches PCI bus, F/W security should be derived from PCI id rather than be fetched during boot handshake with F/W. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/device.c | 4 ++++ drivers/misc/habanalabs/common/firmware_if.c | 6 +++--- drivers/misc/habanalabs/common/habanalabs.h | 4 +++- drivers/misc/habanalabs/common/habanalabs_drv.c | 21 +++++++++++++++++++++ drivers/misc/habanalabs/common/mmu/mmu.c | 1 + drivers/misc/habanalabs/common/sysfs.c | 3 +++ drivers/misc/habanalabs/gaudi/gaudi.c | 2 -- drivers/misc/habanalabs/goya/goya.c | 2 -- 8 files changed, 35 insertions(+), 8 deletions(-) diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index 2ed4f2bedc08..00e92b678828 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -327,6 +327,10 @@ static int device_early_init(struct hl_device *hdev) gaudi_set_asic_funcs(hdev); strscpy(hdev->asic_name, "GAUDI", sizeof(hdev->asic_name)); break; + case ASIC_GAUDI_SEC: + gaudi_set_asic_funcs(hdev); + strscpy(hdev->asic_name, "GAUDI SEC", sizeof(hdev->asic_name)); + break; default: dev_err(hdev->dev, "Unrecognized ASIC type %d\n", hdev->asic_type); diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 532a2fd7bfb4..652571d3b8e6 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -819,16 +819,16 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, if (security_status & CPU_BOOT_DEV_STS0_ENABLED) { prop->fw_security_status_valid = 1; + /* FW security should be derived from PCI ID, we keep this + * check for backward compatibility + */ if (security_status & CPU_BOOT_DEV_STS0_SECURITY_EN) prop->fw_security_disabled = false; - else - prop->fw_security_disabled = true; if (security_status & CPU_BOOT_DEV_STS0_FW_HARD_RST_EN) prop->hard_reset_done_by_fw = true; } else { prop->fw_security_status_valid = 0; - prop->fw_security_disabled = true; } dev_dbg(hdev->dev, "Firmware preboot security status %#x\n", diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 867986ef4588..c1b46126c522 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -766,11 +766,13 @@ struct hl_eq { * @ASIC_INVALID: Invalid ASIC type. * @ASIC_GOYA: Goya device. * @ASIC_GAUDI: Gaudi device. + * @ASIC_GAUDI_SEC: Gaudi secured device (HL-2000). */ enum hl_asic_type { ASIC_INVALID, ASIC_GOYA, - ASIC_GAUDI + ASIC_GAUDI, + ASIC_GAUDI_SEC }; struct hl_cs_parser; diff --git a/drivers/misc/habanalabs/common/habanalabs_drv.c b/drivers/misc/habanalabs/common/habanalabs_drv.c index 59896566dca1..7135f1e03864 100644 --- a/drivers/misc/habanalabs/common/habanalabs_drv.c +++ b/drivers/misc/habanalabs/common/habanalabs_drv.c @@ -47,10 +47,12 @@ MODULE_PARM_DESC(memory_scrub, #define PCI_IDS_GOYA 0x0001 #define PCI_IDS_GAUDI 0x1000 +#define PCI_IDS_GAUDI_SEC 0x1010 static const struct pci_device_id ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_HABANALABS, PCI_IDS_GOYA), }, { PCI_DEVICE(PCI_VENDOR_ID_HABANALABS, PCI_IDS_GAUDI), }, + { PCI_DEVICE(PCI_VENDOR_ID_HABANALABS, PCI_IDS_GAUDI_SEC), }, { 0, } }; MODULE_DEVICE_TABLE(pci, ids); @@ -74,6 +76,9 @@ static enum hl_asic_type get_asic_type(u16 device) case PCI_IDS_GAUDI: asic_type = ASIC_GAUDI; break; + case PCI_IDS_GAUDI_SEC: + asic_type = ASIC_GAUDI_SEC; + break; default: asic_type = ASIC_INVALID; break; @@ -82,6 +87,16 @@ static enum hl_asic_type get_asic_type(u16 device) return asic_type; } +static bool is_asic_secured(enum hl_asic_type asic_type) +{ + switch (asic_type) { + case ASIC_GAUDI_SEC: + return true; + default: + return false; + } +} + /* * hl_device_open - open function for habanalabs device * @@ -287,6 +302,12 @@ int create_hdev(struct hl_device **dev, struct pci_dev *pdev, hdev->asic_type = asic_type; } + if (pdev) + hdev->asic_prop.fw_security_disabled = + !is_asic_secured(pdev->device); + else + hdev->asic_prop.fw_security_disabled = true; + /* Assign status description string */ strncpy(hdev->status[HL_DEVICE_STATUS_MALFUNCTION], "disabled", HL_STR_MAX); diff --git a/drivers/misc/habanalabs/common/mmu/mmu.c b/drivers/misc/habanalabs/common/mmu/mmu.c index ae1778103e23..b37189956b14 100644 --- a/drivers/misc/habanalabs/common/mmu/mmu.c +++ b/drivers/misc/habanalabs/common/mmu/mmu.c @@ -591,6 +591,7 @@ int hl_mmu_if_set_funcs(struct hl_device *hdev) switch (hdev->asic_type) { case ASIC_GOYA: case ASIC_GAUDI: + case ASIC_GAUDI_SEC: hl_mmu_v1_set_funcs(hdev, &hdev->mmu_func[MMU_DR_PGT]); break; default: diff --git a/drivers/misc/habanalabs/common/sysfs.c b/drivers/misc/habanalabs/common/sysfs.c index c7ac5dc0cda4..9fa61573a89d 100644 --- a/drivers/misc/habanalabs/common/sysfs.c +++ b/drivers/misc/habanalabs/common/sysfs.c @@ -257,6 +257,9 @@ static ssize_t device_type_show(struct device *dev, case ASIC_GAUDI: str = "GAUDI"; break; + case ASIC_GAUDI_SEC: + str = "GAUDI SEC"; + break; default: dev_err(hdev->dev, "Unrecognized ASIC type %d\n", hdev->asic_type); diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 62e3c63bec20..841748392e49 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -575,8 +575,6 @@ static int gaudi_get_fixed_properties(struct hl_device *hdev) for (i = 0 ; i < HL_MAX_DCORES ; i++) prop->first_available_cq[i] = USHRT_MAX; - /* disable fw security for now, set it in a later stage */ - prop->fw_security_disabled = true; prop->fw_security_status_valid = false; prop->hard_reset_done_by_fw = false; diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 9d49ba649db0..44dd4d8d8822 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -484,8 +484,6 @@ int goya_get_fixed_properties(struct hl_device *hdev) for (i = 0 ; i < HL_MAX_DCORES ; i++) prop->first_available_cq[i] = USHRT_MAX; - /* disable fw security for now, set it in a later stage */ - prop->fw_security_disabled = true; prop->fw_security_status_valid = false; prop->hard_reset_done_by_fw = false; -- cgit v1.2.3 From 41f458f205a508dcdce58bdaa0af35bb6ef6efdb Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Wed, 10 Mar 2021 15:08:44 +0200 Subject: habanalabs/gaudi: skip iATU if F/W security is enabled As part of the securing GAUDI, the F/W will configure the PCI iATU regions. If the driver identifies a secured PCI ID, it will know to skip iATU configuration in a very early stage. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/habanalabs.h | 3 ++ drivers/misc/habanalabs/common/pci/pci.c | 52 +++++++++++++++++++++++++++++ drivers/misc/habanalabs/gaudi/gaudi.c | 23 +++++++++++++ drivers/misc/habanalabs/goya/goya.c | 24 ++++++++++++- 4 files changed, 101 insertions(+), 1 deletion(-) diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index c1b46126c522..44e89da30b4a 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -445,6 +445,7 @@ struct hl_mmu_properties { * @dram_supports_virtual_memory: is there an MMU towards the DRAM * @hard_reset_done_by_fw: true if firmware is handling hard reset flow * @num_functional_hbms: number of functional HBMs in each DCORE. + * @iatu_done_by_fw: true if iATU configuration is being done by FW. */ struct asic_fixed_properties { struct hw_queue_properties *hw_queues_props; @@ -508,6 +509,7 @@ struct asic_fixed_properties { u8 dram_supports_virtual_memory; u8 hard_reset_done_by_fw; u8 num_functional_hbms; + u8 iatu_done_by_fw; }; /** @@ -2400,6 +2402,7 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, int hl_pci_bars_map(struct hl_device *hdev, const char * const name[3], bool is_wc[3]); +int hl_pci_elbi_read(struct hl_device *hdev, u64 addr, u32 *data); int hl_pci_iatu_write(struct hl_device *hdev, u32 addr, u32 data); int hl_pci_set_inbound_region(struct hl_device *hdev, u8 region, struct hl_inbound_pci_region *pci_region); diff --git a/drivers/misc/habanalabs/common/pci/pci.c b/drivers/misc/habanalabs/common/pci/pci.c index b799f9258fb0..e941b7eef346 100644 --- a/drivers/misc/habanalabs/common/pci/pci.c +++ b/drivers/misc/habanalabs/common/pci/pci.c @@ -85,6 +85,58 @@ static void hl_pci_bars_unmap(struct hl_device *hdev) pci_release_regions(pdev); } +int hl_pci_elbi_read(struct hl_device *hdev, u64 addr, u32 *data) +{ + struct pci_dev *pdev = hdev->pdev; + ktime_t timeout; + u64 msec; + u32 val; + + if (hdev->pldm) + msec = HL_PLDM_PCI_ELBI_TIMEOUT_MSEC; + else + msec = HL_PCI_ELBI_TIMEOUT_MSEC; + + /* Clear previous status */ + pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_STS, 0); + + pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_ADDR, (u32) addr); + pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_CTRL, 0); + + timeout = ktime_add_ms(ktime_get(), msec); + for (;;) { + pci_read_config_dword(pdev, mmPCI_CONFIG_ELBI_STS, &val); + if (val & PCI_CONFIG_ELBI_STS_MASK) + break; + if (ktime_compare(ktime_get(), timeout) > 0) { + pci_read_config_dword(pdev, mmPCI_CONFIG_ELBI_STS, + &val); + break; + } + + usleep_range(300, 500); + } + + if ((val & PCI_CONFIG_ELBI_STS_MASK) == PCI_CONFIG_ELBI_STS_DONE) { + pci_read_config_dword(pdev, mmPCI_CONFIG_ELBI_DATA, data); + + return 0; + } + + if (val & PCI_CONFIG_ELBI_STS_ERR) { + dev_err(hdev->dev, "Error reading from ELBI\n"); + return -EIO; + } + + if (!(val & PCI_CONFIG_ELBI_STS_MASK)) { + dev_err(hdev->dev, "ELBI read didn't finish in time\n"); + return -EIO; + } + + dev_err(hdev->dev, "ELBI read has undefined bits in status\n"); + return -EIO; +} + /** * hl_pci_elbi_write() - Write through the ELBI interface. * @hdev: Pointer to hl_device structure. diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 841748392e49..8730b691ec61 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -629,6 +629,11 @@ static int gaudi_init_iatu(struct hl_device *hdev) struct hl_outbound_pci_region outbound_region; int rc; + if (hdev->asic_prop.iatu_done_by_fw) { + hdev->asic_funcs->set_dma_mask_from_fw(hdev); + return 0; + } + /* Inbound Region 0 - Bar 0 - Point to SRAM + CFG */ inbound_region.mode = PCI_BAR_MATCH_MODE; inbound_region.bar = SRAM_BAR_ID; @@ -673,6 +678,7 @@ static int gaudi_early_init(struct hl_device *hdev) { struct asic_fixed_properties *prop = &hdev->asic_prop; struct pci_dev *pdev = hdev->pdev; + u32 fw_boot_status; int rc; rc = gaudi_get_fixed_properties(hdev); @@ -706,6 +712,23 @@ static int gaudi_early_init(struct hl_device *hdev) prop->dram_pci_bar_size = pci_resource_len(pdev, HBM_BAR_ID); + /* If FW security is enabled at this point it means no access to ELBI */ + if (!hdev->asic_prop.fw_security_disabled) { + hdev->asic_prop.iatu_done_by_fw = true; + goto pci_init; + } + + rc = hl_pci_elbi_read(hdev, CFG_BASE + mmCPU_BOOT_DEV_STS0, + &fw_boot_status); + if (rc) + goto free_queue_props; + + /* Check whether FW is configuring iATU */ + if ((fw_boot_status & CPU_BOOT_DEV_STS0_ENABLED) && + (fw_boot_status & CPU_BOOT_DEV_STS0_FW_IATU_CONF_EN)) + hdev->asic_prop.iatu_done_by_fw = true; + +pci_init: rc = hl_pci_init(hdev); if (rc) goto free_queue_props; diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 44dd4d8d8822..e27338f4aad2 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -555,6 +555,11 @@ static int goya_init_iatu(struct hl_device *hdev) struct hl_outbound_pci_region outbound_region; int rc; + if (hdev->asic_prop.iatu_done_by_fw) { + hdev->asic_funcs->set_dma_mask_from_fw(hdev); + return 0; + } + /* Inbound Region 0 - Bar 0 - Point to SRAM and CFG */ inbound_region.mode = PCI_BAR_MATCH_MODE; inbound_region.bar = SRAM_CFG_BAR_ID; @@ -602,7 +607,7 @@ static int goya_early_init(struct hl_device *hdev) { struct asic_fixed_properties *prop = &hdev->asic_prop; struct pci_dev *pdev = hdev->pdev; - u32 val; + u32 fw_boot_status, val; int rc; rc = goya_get_fixed_properties(hdev); @@ -636,6 +641,23 @@ static int goya_early_init(struct hl_device *hdev) prop->dram_pci_bar_size = pci_resource_len(pdev, DDR_BAR_ID); + /* If FW security is enabled at this point it means no access to ELBI */ + if (!hdev->asic_prop.fw_security_disabled) { + hdev->asic_prop.iatu_done_by_fw = true; + goto pci_init; + } + + rc = hl_pci_elbi_read(hdev, CFG_BASE + mmCPU_BOOT_DEV_STS0, + &fw_boot_status); + if (rc) + goto free_queue_props; + + /* Check whether FW is configuring iATU */ + if ((fw_boot_status & CPU_BOOT_DEV_STS0_ENABLED) && + (fw_boot_status & CPU_BOOT_DEV_STS0_FW_IATU_CONF_EN)) + hdev->asic_prop.iatu_done_by_fw = true; + +pci_init: rc = hl_pci_init(hdev); if (rc) goto free_queue_props; -- cgit v1.2.3 From 669b018835326b3caa42572ba7cb31f84fa22f9d Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Wed, 7 Apr 2021 17:09:36 +0300 Subject: habanalabs: update to latest F/W communication header update files to latest version from F/W team. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/include/common/cpucp_if.h | 3 +- .../misc/habanalabs/include/common/hl_boot_if.h | 198 +++++++++++++++++++++ 2 files changed, 200 insertions(+), 1 deletion(-) diff --git a/drivers/misc/habanalabs/include/common/cpucp_if.h b/drivers/misc/habanalabs/include/common/cpucp_if.h index 20a710f7a369..27cd0ba99aa3 100644 --- a/drivers/misc/habanalabs/include/common/cpucp_if.h +++ b/drivers/misc/habanalabs/include/common/cpucp_if.h @@ -11,6 +11,8 @@ #include #include +#include "hl_boot_if.h" + #define NUM_HBM_PSEUDO_CH 2 #define NUM_HBM_CH_PER_DEV 8 #define CPUCP_PKT_HBM_ECC_INFO_WR_PAR_SHIFT 0 @@ -564,7 +566,6 @@ struct eq_generic_event { */ #define CARD_NAME_MAX_LEN 16 -#define VERSION_MAX_LEN 128 #define CPUCP_MAX_SENSORS 128 #define CPUCP_MAX_NICS 128 #define CPUCP_LANES_PER_NIC 4 diff --git a/drivers/misc/habanalabs/include/common/hl_boot_if.h b/drivers/misc/habanalabs/include/common/hl_boot_if.h index 980b432fd76e..e0a259e0495c 100644 --- a/drivers/misc/habanalabs/include/common/hl_boot_if.h +++ b/drivers/misc/habanalabs/include/common/hl_boot_if.h @@ -13,6 +13,8 @@ #define BOOT_FIT_SRAM_OFFSET 0x200000 +#define VERSION_MAX_LEN 128 + /* * CPU error bits in BOOT_ERROR registers * @@ -251,6 +253,7 @@ enum kmd_msg { KMD_MSG_SKIP_BMC, RESERVED, KMD_MSG_RST_DEV, + KMD_MSG_LAST }; enum cpu_msg_status { @@ -259,4 +262,199 @@ enum cpu_msg_status { CPU_MSG_ERR, }; +/* communication registers mapping - consider ABI when changing */ +struct cpu_dyn_regs { + uint32_t cpu_pq_base_addr_low; + uint32_t cpu_pq_base_addr_high; + uint32_t cpu_pq_length; + uint32_t cpu_pq_init_status; + uint32_t cpu_eq_base_addr_low; + uint32_t cpu_eq_base_addr_high; + uint32_t cpu_eq_length; + uint32_t cpu_eq_ci; + uint32_t cpu_cq_base_addr_low; + uint32_t cpu_cq_base_addr_high; + uint32_t cpu_cq_length; + uint32_t cpu_pf_pq_pi; + uint32_t cpu_boot_dev_sts0; + uint32_t cpu_boot_dev_sts1; + uint32_t cpu_boot_err0; + uint32_t cpu_boot_err1; + uint32_t cpu_boot_status; + uint32_t fw_upd_sts; + uint32_t fw_upd_cmd; + uint32_t fw_upd_pending_sts; + uint32_t fuse_ver_offset; + uint32_t preboot_ver_offset; + uint32_t uboot_ver_offset; + uint32_t hw_state; + uint32_t kmd_msg_to_cpu; + uint32_t cpu_cmd_status_to_host; + uint32_t reserved1[32]; /* reserve for future use */ +}; + +/* HCDM - Habana Communications Descriptor Magic */ +#define HL_COMMS_DESC_MAGIC 0x4843444D +#define HL_COMMS_DESC_VER 1 + +/* this is the comms descriptor header - meta data */ +struct comms_desc_header { + uint32_t magic; /* magic for validation */ + uint32_t crc32; /* CRC32 of the descriptor w/o header */ + uint16_t size; /* size of the descriptor w/o header */ + uint8_t version; /* descriptor version */ + uint8_t reserved[5]; /* pad to 64 bit */ +}; + +/* this is the main FW descriptor - consider ABI when changing */ +struct lkd_fw_comms_desc { + struct comms_desc_header header; + struct cpu_dyn_regs cpu_dyn_regs; + char fuse_ver[VERSION_MAX_LEN]; + char cur_fw_ver[VERSION_MAX_LEN]; + /* can be used for 1 more version w/o ABI change */ + char reserved0[VERSION_MAX_LEN]; + uint64_t img_addr; /* address for next FW component load */ +}; + +/* + * LKD commands: + * + * COMMS_NOOP Used to clear the command register and no actual + * command is send. + * + * COMMS_CLR_STS Clear status command - FW should clear the + * status register. Used for synchronization + * between the commands as part of the race free + * protocol. + * + * COMMS_RST_STATE Reset the current communication state which is + * kept by FW for proper responses. + * Should be used in the beginning of the + * communication cycle to clean any leftovers from + * previous communication attempts. + * + * COMMS_PREP_DESC Prepare descriptor for setting up the + * communication and other dynamic data: + * struct lkd_fw_comms_desc. + * This command has a parameter stating the next FW + * component size, so the FW can actually prepare a + * space for it and in the status response provide + * the descriptor offset. The Offset of the next FW + * data component is a part of the descriptor + * structure. + * + * COMMS_DATA_RDY The FW data has been uploaded and is ready for + * validation. + * + * COMMS_EXEC Execute the next FW component. + * + * COMMS_RST_DEV Reset the device. + * + * COMMS_GOTO_WFE Execute WFE command. Allowed only on non-secure + * devices. + * + * COMMS_SKIP_BMC Perform actions required for BMC-less servers. + * Do not wait for BMC response. + * + * COMMS_LOW_PLL_OPP Initialize PLLs for low OPP. + */ +enum comms_cmd { + COMMS_NOOP = 0, + COMMS_CLR_STS = 1, + COMMS_RST_STATE = 2, + COMMS_PREP_DESC = 3, + COMMS_DATA_RDY = 4, + COMMS_EXEC = 5, + COMMS_RST_DEV = 6, + COMMS_GOTO_WFE = 7, + COMMS_SKIP_BMC = 8, + COMMS_LOW_PLL_OPP = 9, + COMMS_INVLD_LAST +}; + +#define COMMS_COMMAND_SIZE_SHIFT 0 +#define COMMS_COMMAND_SIZE_MASK 0x1FFFFFF +#define COMMS_COMMAND_CMD_SHIFT 27 +#define COMMS_COMMAND_CMD_MASK 0xF8000000 + +/* + * LKD command to FW register structure + * @size - FW component size + * @cmd - command from enum comms_cmd + */ +struct comms_command { + union { /* bit fields are only for FW use */ + struct { + unsigned int size :25; /* 32MB max. */ + unsigned int reserved :2; + enum comms_cmd cmd :5; /* 32 commands */ + }; + unsigned int val; + }; +}; + +/* + * FW status + * + * COMMS_STS_NOOP Used to clear the status register and no actual + * status is provided. + * + * COMMS_STS_ACK Command has been received and recognized. + * + * COMMS_STS_OK Command execution has finished successfully. + * + * COMMS_STS_ERR Command execution was unsuccessful and resulted + * in error. + * + * COMMS_STS_VALID_ERR FW validation has failed. + * + * COMMS_STS_TIMEOUT_ERR Command execution has timed out. + */ +enum comms_sts { + COMMS_STS_NOOP = 0, + COMMS_STS_ACK = 1, + COMMS_STS_OK = 2, + COMMS_STS_ERR = 3, + COMMS_STS_VALID_ERR = 4, + COMMS_STS_TIMEOUT_ERR = 5, + COMMS_STS_INVLD_LAST +}; + +/* RAM types for FW components loading - defines the base address */ +enum comms_ram_types { + COMMS_SRAM = 0, + COMMS_DRAM = 1, +}; + +#define COMMS_STATUS_OFFSET_SHIFT 0 +#define COMMS_STATUS_OFFSET_MASK 0x03FFFFFF +#define COMMS_STATUS_OFFSET_ALIGN_SHIFT 2 +#define COMMS_STATUS_RAM_TYPE_SHIFT 26 +#define COMMS_STATUS_RAM_TYPE_MASK 0x0C000000 +#define COMMS_STATUS_STATUS_SHIFT 28 +#define COMMS_STATUS_STATUS_MASK 0xF0000000 + +/* + * FW status to LKD register structure + * @offset - an offset from the base of the ram_type shifted right by + * 2 bits (always aligned to 32 bits). + * Allows a maximum addressable offset of 256MB from RAM base. + * Example: for real offset in RAM of 0x800000 (8MB), the value + * in offset field is (0x800000 >> 2) = 0x200000. + * @ram_type - the RAM type that should be used for offset from + * enum comms_ram_types + * @status - status from enum comms_sts + */ +struct comms_status { + union { /* bit fields are only for FW use */ + struct { + unsigned int offset :26; + unsigned int ram_type :2; + enum comms_sts status :4; /* 16 statuses */ + }; + unsigned int val; + }; +}; + #endif /* HL_BOOT_IF_H */ -- cgit v1.2.3 From b575a7673e3d0396992fc72fce850723d39264e3 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Thu, 8 Apr 2021 09:38:32 +0300 Subject: habanalabs: print f/w boot unknown error We need to print a message to the kernel log in case we encounter an unknown error in the f/w boot to help the user understand what happened. In addition, we shouldn't print unknown error in case of known errors. Moreover, in case of warnings/info, we shouldn't return -EIO that will fail the initialization and mark the device as disabled Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 84 ++++++++++++++++++++++------ 1 file changed, 68 insertions(+), 16 deletions(-) diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 652571d3b8e6..832dd5c5bb06 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -293,6 +293,7 @@ static int fw_read_errors(struct hl_device *hdev, u32 boot_err0_reg, u32 cpu_security_boot_status_reg) { u32 err_val, security_val; + bool err_exists = false; /* Some of the firmware status codes are deprecated in newer f/w * versions. In those versions, the errors are reported @@ -307,51 +308,102 @@ static int fw_read_errors(struct hl_device *hdev, u32 boot_err0_reg, if (!(err_val & CPU_BOOT_ERR0_ENABLED)) return 0; - if (err_val & CPU_BOOT_ERR0_DRAM_INIT_FAIL) + if (err_val & CPU_BOOT_ERR0_DRAM_INIT_FAIL) { dev_err(hdev->dev, "Device boot error - DRAM initialization failed\n"); - if (err_val & CPU_BOOT_ERR0_FIT_CORRUPTED) + err_exists = true; + } + + if (err_val & CPU_BOOT_ERR0_FIT_CORRUPTED) { dev_err(hdev->dev, "Device boot error - FIT image corrupted\n"); - if (err_val & CPU_BOOT_ERR0_TS_INIT_FAIL) + err_exists = true; + } + + if (err_val & CPU_BOOT_ERR0_TS_INIT_FAIL) { dev_err(hdev->dev, "Device boot error - Thermal Sensor initialization failed\n"); - if (err_val & CPU_BOOT_ERR0_DRAM_SKIPPED) + err_exists = true; + } + + if (err_val & CPU_BOOT_ERR0_DRAM_SKIPPED) { dev_warn(hdev->dev, "Device boot warning - Skipped DRAM initialization\n"); + /* This is a warning so we don't want it to disable the + * device + */ + err_val &= ~CPU_BOOT_ERR0_DRAM_SKIPPED; + } if (err_val & CPU_BOOT_ERR0_BMC_WAIT_SKIPPED) { - if (hdev->bmc_enable) - dev_warn(hdev->dev, + if (hdev->bmc_enable) { + dev_err(hdev->dev, "Device boot error - Skipped waiting for BMC\n"); - else + err_exists = true; + } else { + dev_info(hdev->dev, + "Device boot message - Skipped waiting for BMC\n"); + /* This is an info so we don't want it to disable the + * device + */ err_val &= ~CPU_BOOT_ERR0_BMC_WAIT_SKIPPED; + } } - if (err_val & CPU_BOOT_ERR0_NIC_DATA_NOT_RDY) + if (err_val & CPU_BOOT_ERR0_NIC_DATA_NOT_RDY) { dev_err(hdev->dev, "Device boot error - Serdes data from BMC not available\n"); - if (err_val & CPU_BOOT_ERR0_NIC_FW_FAIL) + err_exists = true; + } + + if (err_val & CPU_BOOT_ERR0_NIC_FW_FAIL) { dev_err(hdev->dev, "Device boot error - NIC F/W initialization failed\n"); - if (err_val & CPU_BOOT_ERR0_SECURITY_NOT_RDY) + err_exists = true; + } + + if (err_val & CPU_BOOT_ERR0_SECURITY_NOT_RDY) { dev_warn(hdev->dev, "Device boot warning - security not ready\n"); - if (err_val & CPU_BOOT_ERR0_SECURITY_FAIL) + /* This is a warning so we don't want it to disable the + * device + */ + err_val &= ~CPU_BOOT_ERR0_SECURITY_NOT_RDY; + } + + if (err_val & CPU_BOOT_ERR0_SECURITY_FAIL) { dev_err(hdev->dev, "Device boot error - security failure\n"); - if (err_val & CPU_BOOT_ERR0_EFUSE_FAIL) + err_exists = true; + } + + if (err_val & CPU_BOOT_ERR0_EFUSE_FAIL) { dev_err(hdev->dev, "Device boot error - eFuse failure\n"); - if (err_val & CPU_BOOT_ERR0_PLL_FAIL) + err_exists = true; + } + + if (err_val & CPU_BOOT_ERR0_PLL_FAIL) { dev_err(hdev->dev, "Device boot error - PLL failure\n"); - if (err_val & CPU_BOOT_ERR0_DEVICE_UNUSABLE_FAIL) + err_exists = true; + } + + if (err_val & CPU_BOOT_ERR0_DEVICE_UNUSABLE_FAIL) { dev_err(hdev->dev, - "Device boot error - device unusable failure\n"); + "Device boot error - device unusable\n"); + err_exists = true; + } security_val = RREG32(cpu_security_boot_status_reg); if (security_val & CPU_BOOT_DEV_STS0_ENABLED) dev_dbg(hdev->dev, "Device security status %#x\n", security_val); - if (err_val & ~CPU_BOOT_ERR0_ENABLED) + if (!err_exists && (err_val & ~CPU_BOOT_ERR0_ENABLED)) { + dev_err(hdev->dev, + "Device boot error - unknown error 0x%08x\n", + err_val); + err_exists = true; + } + + if (err_exists) return -EIO; return 0; -- cgit v1.2.3 From a503d1628c9c341dc5e1a26272e38182dca3e823 Mon Sep 17 00:00:00 2001 From: Jarvis Jiang Date: Thu, 8 Apr 2021 03:02:20 -0700 Subject: bus: mhi: fix typo in comments for struct mhi_channel_config The word 'rung' is a typo in below comment, fix it. * @event_ring: The event rung index that services this channel Signed-off-by: Jarvis Jiang Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20210408100220.3853-1-jarvis.w.jiang@gmail.com Signed-off-by: Manivannan Sadhasivam --- include/linux/mhi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/mhi.h b/include/linux/mhi.h index d095fba37d1e..944aa3aa3035 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -205,7 +205,7 @@ enum mhi_db_brst_mode { * @num: The number assigned to this channel * @num_elements: The number of elements that can be queued to this channel * @local_elements: The local ring length of the channel - * @event_ring: The event rung index that services this channel + * @event_ring: The event ring index that services this channel * @dir: Direction that data may flow on this channel * @type: Channel type * @ee_mask: Execution Environment mask for this channel -- cgit v1.2.3 From 005169157448ca41eff8716d79dc1b8f158229d2 Mon Sep 17 00:00:00 2001 From: Hang Lu Date: Fri, 9 Apr 2021 17:40:45 +0800 Subject: binder: fix the missing BR_FROZEN_REPLY in binder_return_strings Add BR_FROZEN_REPLY in binder_return_strings to support stat function. Fixes: ae28c1be1e54 ("binder: BINDER_GET_FROZEN_INFO ioctl") Acked-by: Todd Kjos Signed-off-by: Hang Lu Link: https://lore.kernel.org/r/1617961246-4502-2-git-send-email-hangl@codeaurora.org Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 3 ++- drivers/android/binder_internal.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index e1a484ab0366..be34da3dd077 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -5559,7 +5559,8 @@ static const char * const binder_return_strings[] = { "BR_FINISHED", "BR_DEAD_BINDER", "BR_CLEAR_DEATH_NOTIFICATION_DONE", - "BR_FAILED_REPLY" + "BR_FAILED_REPLY", + "BR_FROZEN_REPLY", }; static const char * const binder_command_strings[] = { diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h index 2872a7de68e1..a50716696fad 100644 --- a/drivers/android/binder_internal.h +++ b/drivers/android/binder_internal.h @@ -155,7 +155,7 @@ enum binder_stat_types { }; struct binder_stats { - atomic_t br[_IOC_NR(BR_FAILED_REPLY) + 1]; + atomic_t br[_IOC_NR(BR_FROZEN_REPLY) + 1]; atomic_t bc[_IOC_NR(BC_REPLY_SG) + 1]; atomic_t obj_created[BINDER_STAT_COUNT]; atomic_t obj_deleted[BINDER_STAT_COUNT]; -- cgit v1.2.3 From a7dc1e6f99df59799ab0128d9c4e47bbeceb934d Mon Sep 17 00:00:00 2001 From: Hang Lu Date: Fri, 9 Apr 2021 17:40:46 +0800 Subject: binder: tell userspace to dump current backtrace when detected oneway spamming When async binder buffer got exhausted, some normal oneway transactions will also be discarded and may cause system or application failures. By that time, the binder debug information we dump may not be relevant to the root cause. And this issue is difficult to debug if without the backtrace of the thread sending spam. This change will send BR_ONEWAY_SPAM_SUSPECT to userspace when oneway spamming is detected, request to dump current backtrace. Oneway spamming will be reported only once when exceeding the threshold (target process dips below 80% of its oneway space, and current process is responsible for either more than 50 transactions, or more than 50% of the oneway space). And the detection will restart when the async buffer has returned to a healthy state. Acked-by: Todd Kjos Signed-off-by: Hang Lu Link: https://lore.kernel.org/r/1617961246-4502-3-git-send-email-hangl@codeaurora.org Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 27 ++++++++++++++++++++++++--- drivers/android/binder_alloc.c | 15 ++++++++++++--- drivers/android/binder_alloc.h | 8 +++++++- drivers/android/binder_internal.h | 6 +++++- include/uapi/linux/android/binder.h | 8 ++++++++ 5 files changed, 56 insertions(+), 8 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index be34da3dd077..63d2c4339689 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3020,7 +3020,10 @@ static void binder_transaction(struct binder_proc *proc, goto err_bad_object_type; } } - tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; + if (t->buffer->oneway_spam_suspect) + tcomplete->type = BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT; + else + tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; t->work.type = BINDER_WORK_TRANSACTION; if (reply) { @@ -3893,9 +3896,14 @@ retry: binder_stat_br(proc, thread, cmd); } break; - case BINDER_WORK_TRANSACTION_COMPLETE: { + case BINDER_WORK_TRANSACTION_COMPLETE: + case BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT: { + if (proc->oneway_spam_detection_enabled && + w->type == BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT) + cmd = BR_ONEWAY_SPAM_SUSPECT; + else + cmd = BR_TRANSACTION_COMPLETE; binder_inner_proc_unlock(proc); - cmd = BR_TRANSACTION_COMPLETE; kfree(w); binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); if (put_user(cmd, (uint32_t __user *)ptr)) @@ -4897,6 +4905,18 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; } + case BINDER_ENABLE_ONEWAY_SPAM_DETECTION: { + uint32_t enable; + + if (copy_from_user(&enable, ubuf, sizeof(enable))) { + ret = -EINVAL; + goto err; + } + binder_inner_proc_lock(proc); + proc->oneway_spam_detection_enabled = (bool)enable; + binder_inner_proc_unlock(proc); + break; + } default: ret = -EINVAL; goto err; @@ -5561,6 +5581,7 @@ static const char * const binder_return_strings[] = { "BR_CLEAR_DEATH_NOTIFICATION_DONE", "BR_FAILED_REPLY", "BR_FROZEN_REPLY", + "BR_ONEWAY_SPAM_SUSPECT", }; static const char * const binder_command_strings[] = { diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 7caf74ad2405..340515f54498 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -338,7 +338,7 @@ static inline struct vm_area_struct *binder_alloc_get_vma( return vma; } -static void debug_low_async_space_locked(struct binder_alloc *alloc, int pid) +static bool debug_low_async_space_locked(struct binder_alloc *alloc, int pid) { /* * Find the amount and size of buffers allocated by the current caller; @@ -366,13 +366,19 @@ static void debug_low_async_space_locked(struct binder_alloc *alloc, int pid) /* * Warn if this pid has more than 50 transactions, or more than 50% of - * async space (which is 25% of total buffer size). + * async space (which is 25% of total buffer size). Oneway spam is only + * detected when the threshold is exceeded. */ if (num_buffers > 50 || total_alloc_size > alloc->buffer_size / 4) { binder_alloc_debug(BINDER_DEBUG_USER_ERROR, "%d: pid %d spamming oneway? %zd buffers allocated for a total size of %zd\n", alloc->pid, pid, num_buffers, total_alloc_size); + if (!alloc->oneway_spam_detected) { + alloc->oneway_spam_detected = true; + return true; + } } + return false; } static struct binder_buffer *binder_alloc_new_buf_locked( @@ -525,6 +531,7 @@ static struct binder_buffer *binder_alloc_new_buf_locked( buffer->async_transaction = is_async; buffer->extra_buffers_size = extra_buffers_size; buffer->pid = pid; + buffer->oneway_spam_suspect = false; if (is_async) { alloc->free_async_space -= size + sizeof(struct binder_buffer); binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, @@ -536,7 +543,9 @@ static struct binder_buffer *binder_alloc_new_buf_locked( * of async space left (which is less than 10% of total * buffer size). */ - debug_low_async_space_locked(alloc, pid); + buffer->oneway_spam_suspect = debug_low_async_space_locked(alloc, pid); + } else { + alloc->oneway_spam_detected = false; } } return buffer; diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h index 6e8e001381af..7dea57a84c79 100644 --- a/drivers/android/binder_alloc.h +++ b/drivers/android/binder_alloc.h @@ -26,6 +26,8 @@ struct binder_transaction; * @clear_on_free: %true if buffer must be zeroed after use * @allow_user_free: %true if user is allowed to free buffer * @async_transaction: %true if buffer is in use for an async txn + * @oneway_spam_suspect: %true if total async allocate size just exceed + * spamming detect threshold * @debug_id: unique ID for debugging * @transaction: pointer to associated struct binder_transaction * @target_node: struct binder_node associated with this buffer @@ -45,7 +47,8 @@ struct binder_buffer { unsigned clear_on_free:1; unsigned allow_user_free:1; unsigned async_transaction:1; - unsigned debug_id:28; + unsigned oneway_spam_suspect:1; + unsigned debug_id:27; struct binder_transaction *transaction; @@ -87,6 +90,8 @@ struct binder_lru_page { * @buffer_size: size of address space specified via mmap * @pid: pid for associated binder_proc (invariant after init) * @pages_high: high watermark of offset in @pages + * @oneway_spam_detected: %true if oneway spam detection fired, clear that + * flag once the async buffer has returned to a healthy state * * Bookkeeping structure for per-proc address space management for binder * buffers. It is normally initialized during binder_init() and binder_mmap() @@ -107,6 +112,7 @@ struct binder_alloc { uint32_t buffer_free; int pid; size_t pages_high; + bool oneway_spam_detected; }; #ifdef CONFIG_ANDROID_BINDER_IPC_SELFTEST diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h index a50716696fad..810c0b84d3f8 100644 --- a/drivers/android/binder_internal.h +++ b/drivers/android/binder_internal.h @@ -155,7 +155,7 @@ enum binder_stat_types { }; struct binder_stats { - atomic_t br[_IOC_NR(BR_FROZEN_REPLY) + 1]; + atomic_t br[_IOC_NR(BR_ONEWAY_SPAM_SUSPECT) + 1]; atomic_t bc[_IOC_NR(BC_REPLY_SG) + 1]; atomic_t obj_created[BINDER_STAT_COUNT]; atomic_t obj_deleted[BINDER_STAT_COUNT]; @@ -174,6 +174,7 @@ struct binder_work { enum binder_work_type { BINDER_WORK_TRANSACTION = 1, BINDER_WORK_TRANSACTION_COMPLETE, + BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT, BINDER_WORK_RETURN_ERROR, BINDER_WORK_NODE, BINDER_WORK_DEAD_BINDER, @@ -409,6 +410,8 @@ struct binder_ref { * @outer_lock: no nesting under innor or node lock * Lock order: 1) outer, 2) node, 3) inner * @binderfs_entry: process-specific binderfs log file + * @oneway_spam_detection_enabled: process enabled oneway spam detection + * or not * * Bookkeeping structure for binder processes */ @@ -444,6 +447,7 @@ struct binder_proc { spinlock_t inner_lock; spinlock_t outer_lock; struct dentry *binderfs_entry; + bool oneway_spam_detection_enabled; }; /** diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h index 156070d18c4f..20e435fe657a 100644 --- a/include/uapi/linux/android/binder.h +++ b/include/uapi/linux/android/binder.h @@ -241,6 +241,7 @@ struct binder_frozen_status_info { #define BINDER_SET_CONTEXT_MGR_EXT _IOW('b', 13, struct flat_binder_object) #define BINDER_FREEZE _IOW('b', 14, struct binder_freeze_info) #define BINDER_GET_FROZEN_INFO _IOWR('b', 15, struct binder_frozen_status_info) +#define BINDER_ENABLE_ONEWAY_SPAM_DETECTION _IOW('b', 16, __u32) /* * NOTE: Two special error codes you should check for when calling @@ -428,6 +429,13 @@ enum binder_driver_return_protocol { * The target of the last transaction (either a bcTRANSACTION or * a bcATTEMPT_ACQUIRE) is frozen. No parameters. */ + + BR_ONEWAY_SPAM_SUSPECT = _IO('r', 19), + /* + * Current process sent too many oneway calls to target, and the last + * asynchronous transaction makes the allocated async buffer size exceed + * detection threshold. No parameters. + */ }; enum binder_driver_command_protocol { -- cgit v1.2.3 From 88adcd66108eae9d96aac7e38686a77fcb4cde24 Mon Sep 17 00:00:00 2001 From: Chen Huang Date: Thu, 8 Apr 2021 13:09:53 +0000 Subject: w1: ds2805: Use module_w1_family to simplify the code module_w1_family() makes the code simpler by eliminating boilerplate code. Signed-off-by: Chen Huang Link: https://lore.kernel.org/r/20210408130954.1158963-1-chenhuang5@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/w1/slaves/w1_ds2805.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/w1/slaves/w1_ds2805.c b/drivers/w1/slaves/w1_ds2805.c index 206186db727d..6b5d12ba1b65 100644 --- a/drivers/w1/slaves/w1_ds2805.c +++ b/drivers/w1/slaves/w1_ds2805.c @@ -291,20 +291,7 @@ static struct w1_family w1_family_0d = { .fops = &w1_f0d_fops, }; -static int __init w1_f0d_init(void) -{ - pr_info("%s()\n", __func__); - return w1_register_family(&w1_family_0d); -} - -static void __exit w1_f0d_fini(void) -{ - pr_info("%s()\n", __func__); - w1_unregister_family(&w1_family_0d); -} - -module_init(w1_f0d_init); -module_exit(w1_f0d_fini); +module_w1_family(w1_family_0d); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Andrew Worsley amworsley@gmail.com"); -- cgit v1.2.3 From 6c00365d531163a44ce57d862883db9424bd19ab Mon Sep 17 00:00:00 2001 From: Chen Huang Date: Thu, 8 Apr 2021 13:09:54 +0000 Subject: w1: ds28e17: Use module_w1_family to simplify the code module_w1_family() makes the code simpler by eliminating boilerplate code. Signed-off-by: Chen Huang Link: https://lore.kernel.org/r/20210408130954.1158963-2-chenhuang5@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/w1/slaves/w1_ds28e17.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/w1/slaves/w1_ds28e17.c b/drivers/w1/slaves/w1_ds28e17.c index 6b00db7169ab..aed10b72fc99 100644 --- a/drivers/w1/slaves/w1_ds28e17.c +++ b/drivers/w1/slaves/w1_ds28e17.c @@ -752,18 +752,4 @@ static struct w1_family w1_family_19 = { .fops = &w1_f19_fops, }; - -/* Module init and remove functions. */ -static int __init w1_f19_init(void) -{ - return w1_register_family(&w1_family_19); -} - -static void __exit w1_f19_fini(void) -{ - w1_unregister_family(&w1_family_19); -} - -module_init(w1_f19_init); -module_exit(w1_f19_fini); - +module_w1_family(w1_family_19); -- cgit v1.2.3 From 0d5cf954656387a595a8d5bb7e376f31829aae4d Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 6 Apr 2021 11:44:34 +0800 Subject: speakup: i18n: Switch to kmemdup_nul() in spk_msg_set() Use kmemdup_nul() helper instead of open-coding to simplify the code in spk_msg_set(). Reported-by: Hulk Robot Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20210406034434.442251-1-yangyingliang@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/accessibility/speakup/i18n.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/accessibility/speakup/i18n.c b/drivers/accessibility/speakup/i18n.c index ee240d36f947..46bd50f3c3a4 100644 --- a/drivers/accessibility/speakup/i18n.c +++ b/drivers/accessibility/speakup/i18n.c @@ -548,12 +548,10 @@ ssize_t spk_msg_set(enum msg_index_t index, char *text, size_t length) if ((index < MSG_FIRST_INDEX) || (index >= MSG_LAST_INDEX)) return -EINVAL; - newstr = kmalloc(length + 1, GFP_KERNEL); + newstr = kmemdup_nul(text, length, GFP_KERNEL); if (!newstr) return -ENOMEM; - memcpy(newstr, text, length); - newstr[length] = '\0'; if (index >= MSG_FORMATTED_START && index <= MSG_FORMATTED_END && !fmt_validate(speakup_default_msgs[index], newstr)) { -- cgit v1.2.3 From 2954a6f12f250890ec2433cec03ba92784d613e8 Mon Sep 17 00:00:00 2001 From: He Ying Date: Tue, 6 Apr 2021 05:42:00 -0400 Subject: firmware: qcom-scm: Fix QCOM_SCM configuration When CONFIG_QCOM_SCM is y and CONFIG_HAVE_ARM_SMCCC is not set, compiling errors are encountered as follows: drivers/firmware/qcom_scm-smc.o: In function `__scm_smc_do_quirk': qcom_scm-smc.c:(.text+0x36): undefined reference to `__arm_smccc_smc' drivers/firmware/qcom_scm-legacy.o: In function `scm_legacy_call': qcom_scm-legacy.c:(.text+0xe2): undefined reference to `__arm_smccc_smc' drivers/firmware/qcom_scm-legacy.o: In function `scm_legacy_call_atomic': qcom_scm-legacy.c:(.text+0x1f0): undefined reference to `__arm_smccc_smc' Note that __arm_smccc_smc is defined when HAVE_ARM_SMCCC is y. So add dependency on HAVE_ARM_SMCCC in QCOM_SCM configuration. Fixes: 916f743da354 ("firmware: qcom: scm: Move the scm driver to drivers/firmware") Reported-by: Hulk Robot Signed-off-by: He Ying Link: https://lore.kernel.org/r/20210406094200.60952-1-heying24@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 3f14dffb9669..5dd19dbd67a3 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -237,6 +237,7 @@ config INTEL_STRATIX10_RSU config QCOM_SCM bool depends on ARM || ARM64 + depends on HAVE_ARM_SMCCC select RESET_CONTROLLER config QCOM_SCM_DOWNLOAD_MODE_DEFAULT -- cgit v1.2.3 From 19ab233989d0f7ab1de19a036e247afa4a0a1e9c Mon Sep 17 00:00:00 2001 From: Phillip Potter Date: Wed, 31 Mar 2021 23:07:19 +0100 Subject: fbdev: zero-fill colormap in fbcmap.c Use kzalloc() rather than kmalloc() for the dynamically allocated parts of the colormap in fb_alloc_cmap_gfp, to prevent a leak of random kernel data to userspace under certain circumstances. Fixes a KMSAN-found infoleak bug reported by syzbot at: https://syzkaller.appspot.com/bug?id=741578659feabd108ad9e06696f0c1f2e69c4b6e Reported-by: syzbot+47fa9c9c648b765305b9@syzkaller.appspotmail.com Cc: stable Reviewed-by: Geert Uytterhoeven Signed-off-by: Phillip Potter Link: https://lore.kernel.org/r/20210331220719.1499743-1-phil@philpotter.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/video/fbdev/core/fbcmap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/video/fbdev/core/fbcmap.c b/drivers/video/fbdev/core/fbcmap.c index 757d5c3f620b..ff09e57f3c38 100644 --- a/drivers/video/fbdev/core/fbcmap.c +++ b/drivers/video/fbdev/core/fbcmap.c @@ -101,17 +101,17 @@ int fb_alloc_cmap_gfp(struct fb_cmap *cmap, int len, int transp, gfp_t flags) if (!len) return 0; - cmap->red = kmalloc(size, flags); + cmap->red = kzalloc(size, flags); if (!cmap->red) goto fail; - cmap->green = kmalloc(size, flags); + cmap->green = kzalloc(size, flags); if (!cmap->green) goto fail; - cmap->blue = kmalloc(size, flags); + cmap->blue = kzalloc(size, flags); if (!cmap->blue) goto fail; if (transp) { - cmap->transp = kmalloc(size, flags); + cmap->transp = kzalloc(size, flags); if (!cmap->transp) goto fail; } else { -- cgit v1.2.3 From b21a57636c71c95deac98c9136ac91c975aa6e6c Mon Sep 17 00:00:00 2001 From: Gustavo Pimentel Date: Sat, 10 Apr 2021 16:52:58 +0200 Subject: dw-xdata-pcie: Fix documentation build warns Fixes documentation build warns related to indentation, text formatting, and missing reference on toc. This fix solves the following warnings: WARNING: Unexpected indentation. WARNING: Block quote ends without a blank line; unexpected unindent. WARNING: document isn't included in any toctree Link: https://lore.kernel.org/linux-next/20210406214615.40cf3493@canb.auug.org.au/ Fixes: e1181b5bbc3c ("Documentation: misc-devices: Add Documentation for dw-xdata-pcie driver") Reported-by: Stephen Rothwell Signed-off-by: Gustavo Pimentel Link: https://lore.kernel.org/r/42ed2d9d27579291dc7cce89c0164bd9255fe337.1618066164.git.gustavo.pimentel@synopsys.com Signed-off-by: Greg Kroah-Hartman --- Documentation/misc-devices/dw-xdata-pcie.rst | 14 +++++++------- Documentation/misc-devices/index.rst | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Documentation/misc-devices/dw-xdata-pcie.rst b/Documentation/misc-devices/dw-xdata-pcie.rst index fd75c9321f47..cbc9f694d406 100644 --- a/Documentation/misc-devices/dw-xdata-pcie.rst +++ b/Documentation/misc-devices/dw-xdata-pcie.rst @@ -17,24 +17,24 @@ information to /var/log/kern.log or dmesg. Request write TLPs traffic generation - Root Complex to Endpoint direction - Command: - echo 1 > /sys/class/misc/dw-xdata-pcie/write +echo 1 > /sys/class/misc/dw-xdata-pcie/write Get write TLPs traffic link throughput in MB/s - Command: - cat /sys/class/misc/dw-xdata-pcie/write +cat /sys/class/misc/dw-xdata-pcie/write - Output example: - 204 +204 Request read TLPs traffic generation - Endpoint to Root Complex direction: - Command: - echo 1 > /sys/class/misc/dw-xdata-pcie/read +echo 1 > /sys/class/misc/dw-xdata-pcie/read Get read TLPs traffic link throughput in MB/s - Command: - cat /sys/class/misc/dw-xdata-pcie/read +cat /sys/class/misc/dw-xdata-pcie/read - Output example: - 199 +199 Request to stop any current TLP transfer: - Command: - echo 1 > /sys/class/misc/dw-xdata-pcie/stop +echo 1 > /sys/class/misc/dw-xdata-pcie/stop diff --git a/Documentation/misc-devices/index.rst b/Documentation/misc-devices/index.rst index 64420b3314fe..30ac58f81901 100644 --- a/Documentation/misc-devices/index.rst +++ b/Documentation/misc-devices/index.rst @@ -19,6 +19,7 @@ fit into other categories. bh1770glc eeprom c2port + dw-xdata-pcie ibmvmc ics932s401 isl29003 -- cgit v1.2.3 From 23188e0d45c505b9c3175121855b793578ee50f0 Mon Sep 17 00:00:00 2001 From: Gustavo Pimentel Date: Sat, 10 Apr 2021 16:52:59 +0200 Subject: dw-xdata-pcie: Update outdated info and improve text format Removes old information related to the stop file interface in sysfs left by mistake during patch revision. Improves the document text format to be more user-friendly and adds basic driver related information, such as support, datasheet, and author. Signed-off-by: Gustavo Pimentel Link: https://lore.kernel.org/r/4e72f931474a784d478e5a67961ecf116911997a.1618066164.git.gustavo.pimentel@synopsys.com Signed-off-by: Greg Kroah-Hartman --- Documentation/misc-devices/dw-xdata-pcie.rst | 76 ++++++++++++++++++---------- 1 file changed, 50 insertions(+), 26 deletions(-) diff --git a/Documentation/misc-devices/dw-xdata-pcie.rst b/Documentation/misc-devices/dw-xdata-pcie.rst index cbc9f694d406..781c6794a506 100644 --- a/Documentation/misc-devices/dw-xdata-pcie.rst +++ b/Documentation/misc-devices/dw-xdata-pcie.rst @@ -4,37 +4,61 @@ Driver for Synopsys DesignWare PCIe traffic generator (also known as xData) =========================================================================== +Supported chips: +Synopsys DesignWare PCIe prototype solution + +Datasheet: +Not freely available + +Author: +Gustavo Pimentel + +Description +----------- + This driver should be used as a host-side (Root Complex) driver and Synopsys DesignWare prototype that includes this IP. -The "dw-xdata-pcie" driver can be used to enable/disable PCIe traffic +The dw-xdata-pcie driver can be used to enable/disable PCIe traffic generator in either direction (mutual exclusion) besides allowing the PCIe link performance analysis. The interaction with this driver is done through the module parameter and can be changed in runtime. The driver outputs the requested command state -information to /var/log/kern.log or dmesg. - -Request write TLPs traffic generation - Root Complex to Endpoint direction -- Command: -echo 1 > /sys/class/misc/dw-xdata-pcie/write - -Get write TLPs traffic link throughput in MB/s -- Command: -cat /sys/class/misc/dw-xdata-pcie/write -- Output example: -204 - -Request read TLPs traffic generation - Endpoint to Root Complex direction: -- Command: -echo 1 > /sys/class/misc/dw-xdata-pcie/read - -Get read TLPs traffic link throughput in MB/s -- Command: -cat /sys/class/misc/dw-xdata-pcie/read -- Output example: -199 - -Request to stop any current TLP transfer: -- Command: -echo 1 > /sys/class/misc/dw-xdata-pcie/stop +information to ``/var/log/kern.log`` or dmesg. + +Example +------- + +Write TLPs traffic generation - Root Complex to Endpoint direction +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Generate traffic:: + + # echo 1 > /sys/class/misc/dw-xdata-pcie.0/write + +Get link throughput in MB/s:: + + # cat /sys/class/misc/dw-xdata-pcie.0/write + 204 + +Stop traffic in any direction:: + + # echo 0 > /sys/class/misc/dw-xdata-pcie.0/write + +Read TLPs traffic generation - Endpoint to Root Complex direction +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Generate traffic:: + + # echo 1 > /sys/class/misc/dw-xdata-pcie.0/read + +Get link throughput in MB/s:: + + # cat /sys/class/misc/dw-xdata-pcie.0/read + 199 + +Stop traffic in any direction:: + + # echo 0 > /sys/class/misc/dw-xdata-pcie.0/read + -- cgit v1.2.3 From 0df74278faedf20f9696bf2755cf0ce34afa4c3a Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 14 Apr 2021 07:52:00 +0300 Subject: mei: me: add Alder Lake P device id. Add Alder Lake P device ID. Cc: Signed-off-by: Tomas Winkler Link: https://lore.kernel.org/r/20210414045200.3498241-1-tomas.winkler@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me-regs.h | 1 + drivers/misc/mei/pci-me.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index 14be76d4c2e6..cb34925e10f1 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -105,6 +105,7 @@ #define MEI_DEV_ID_ADP_S 0x7AE8 /* Alder Lake Point S */ #define MEI_DEV_ID_ADP_LP 0x7A60 /* Alder Lake Point LP */ +#define MEI_DEV_ID_ADP_P 0x51E0 /* Alder Lake Point P */ /* * MEI HW Section diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index a7e179626b63..c3393b383e59 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -111,6 +111,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_S, MEI_ME_PCH15_CFG)}, {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_LP, MEI_ME_PCH15_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_P, MEI_ME_PCH15_CFG)}, /* required last entry */ {0, } -- cgit v1.2.3 From 39d2a7898d7fb61276ec766046940dda9080fd4b Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 14 Apr 2021 22:43:38 -0700 Subject: greybus: es2: fix kernel-doc warnings Fix these kernel-doc complaints: ../drivers/greybus/es2.c:79: warning: bad line: ../drivers/greybus/es2.c:100: warning: cannot understand function prototype: 'struct es2_ap_dev ' es2.c:126: warning: Function parameter or member 'cdsi1_in_use' not described in 'es2_ap_dev' Cc: Johan Hovold Cc: Alex Elder Cc: Greg Kroah-Hartman Cc: greybus-dev@lists.linaro.org (moderated for non-subscribers) Signed-off-by: Randy Dunlap Link: https://lore.kernel.org/r/20210415054338.2223-1-rdunlap@infradead.org Signed-off-by: Greg Kroah-Hartman --- drivers/greybus/es2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/greybus/es2.c b/drivers/greybus/es2.c index 86a7fbc7fe13..15661c7f3633 100644 --- a/drivers/greybus/es2.c +++ b/drivers/greybus/es2.c @@ -72,11 +72,11 @@ struct es2_cport_in { }; /** - * es2_ap_dev - ES2 USB Bridge to AP structure + * struct es2_ap_dev - ES2 USB Bridge to AP structure * @usb_dev: pointer to the USB device we are. * @usb_intf: pointer to the USB interface we are bound to. * @hd: pointer to our gb_host_device structure - + * * @cport_in: endpoint, urbs and buffer for cport in messages * @cport_out_endpoint: endpoint for for cport out messages * @cport_out_urb: array of urbs for the CPort out messages @@ -85,7 +85,7 @@ struct es2_cport_in { * @cport_out_urb_cancelled: array of flags indicating whether the * corresponding @cport_out_urb is being cancelled * @cport_out_urb_lock: locks the @cport_out_urb_busy "list" - * + * @cdsi1_in_use: true if cport CDSI1 is in use * @apb_log_task: task pointer for logging thread * @apb_log_dentry: file system entry for the log file interface * @apb_log_enable_dentry: file system entry for enabling logging -- cgit v1.2.3 From b4e964f84c1a44b0c63a5036efb24cf0f938db0a Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 12 Apr 2021 17:10:12 +0100 Subject: habanalabs/gaudi: Fix uninitialized return code rc when read size is zero In the case where size is zero the while loop never assigns rc and the return value is uninitialized. Fix this by initializing rc to zero. Fixes: 639781dcab82 ("habanalabs/gaudi: add debugfs to DMA from the device") Reviewed-by: Oded Gabbay Acked-by: Arnd Bergmann Signed-off-by: Colin Ian King Addresses-Coverity: ("Uninitialized scalar variable") Link: https://lore.kernel.org/r/20210412161012.1628202-1-colin.king@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/habanalabs/gaudi/gaudi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 8730b691ec61..b751652f80a8 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -6252,7 +6252,7 @@ static int gaudi_debugfs_read_dma(struct hl_device *hdev, u64 addr, u32 size, dma_addr_t dma_addr; void *kernel_addr; bool is_eng_idle; - int rc, dma_id; + int rc = 0, dma_id; kernel_addr = hdev->asic_funcs->asic_dma_alloc_coherent( hdev, SZ_2M, -- cgit v1.2.3 From 3fae829eac71a1a1e3265337b3d25eaf80d41d9b Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Wed, 14 Apr 2021 20:12:45 +0300 Subject: stm class: Remove an unused function Fix the following clang warning: drivers/hwtracing/stm/policy.c:60:21: warning: unused function 'stp_policy_node_name' [-Wunused-function]. Reported-by: Abaci Robot Signed-off-by: Jiapeng Chong Signed-off-by: Alexander Shishkin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210414171251.14672-2-alexander.shishkin@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/stm/policy.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/hwtracing/stm/policy.c b/drivers/hwtracing/stm/policy.c index 603b4a9969d3..42103c3a177f 100644 --- a/drivers/hwtracing/stm/policy.c +++ b/drivers/hwtracing/stm/policy.c @@ -57,11 +57,6 @@ void stp_policy_node_get_ranges(struct stp_policy_node *policy_node, *cend = policy_node->last_channel; } -static inline char *stp_policy_node_name(struct stp_policy_node *policy_node) -{ - return policy_node->group.cg_item.ci_name ? : ""; -} - static inline struct stp_policy *to_stp_policy(struct config_item *item) { return item ? -- cgit v1.2.3 From a525ed1787abfc007eb892c38b098352707137bc Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Wed, 14 Apr 2021 20:12:47 +0300 Subject: intel_th: Constify all drvdata references Anything that deals with drvdata structures should leave them intact. Reflect this in function signatures. Signed-off-by: Alexander Shishkin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210414171251.14672-4-alexander.shishkin@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/intel_th/core.c | 2 +- drivers/hwtracing/intel_th/intel_th.h | 6 +++--- drivers/hwtracing/intel_th/pci.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c index c9ac3dc65113..24d0c974bfd5 100644 --- a/drivers/hwtracing/intel_th/core.c +++ b/drivers/hwtracing/intel_th/core.c @@ -844,7 +844,7 @@ static irqreturn_t intel_th_irq(int irq, void *data) * @irq: irq number */ struct intel_th * -intel_th_alloc(struct device *dev, struct intel_th_drvdata *drvdata, +intel_th_alloc(struct device *dev, const struct intel_th_drvdata *drvdata, struct resource *devres, unsigned int ndevres) { int err, r, nr_mmios = 0; diff --git a/drivers/hwtracing/intel_th/intel_th.h b/drivers/hwtracing/intel_th/intel_th.h index 5fe694708b7a..05fa2dab37d1 100644 --- a/drivers/hwtracing/intel_th/intel_th.h +++ b/drivers/hwtracing/intel_th/intel_th.h @@ -74,7 +74,7 @@ struct intel_th_drvdata { */ struct intel_th_device { struct device dev; - struct intel_th_drvdata *drvdata; + const struct intel_th_drvdata *drvdata; struct resource *resource; unsigned int num_resources; unsigned int type; @@ -224,7 +224,7 @@ static inline struct intel_th *to_intel_th(struct intel_th_device *thdev) } struct intel_th * -intel_th_alloc(struct device *dev, struct intel_th_drvdata *drvdata, +intel_th_alloc(struct device *dev, const struct intel_th_drvdata *drvdata, struct resource *devres, unsigned int ndevres); void intel_th_free(struct intel_th *th); @@ -272,7 +272,7 @@ struct intel_th { struct intel_th_device *thdev[TH_SUBDEVICE_MAX]; struct intel_th_device *hub; - struct intel_th_drvdata *drvdata; + const struct intel_th_drvdata *drvdata; struct resource resource[TH_MMIO_END]; int (*activate)(struct intel_th *); diff --git a/drivers/hwtracing/intel_th/pci.c b/drivers/hwtracing/intel_th/pci.c index 251e75c9ba9d..759994055cb4 100644 --- a/drivers/hwtracing/intel_th/pci.c +++ b/drivers/hwtracing/intel_th/pci.c @@ -71,7 +71,7 @@ static void intel_th_pci_deactivate(struct intel_th *th) static int intel_th_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - struct intel_th_drvdata *drvdata = (void *)id->driver_data; + const struct intel_th_drvdata *drvdata = (void *)id->driver_data; struct resource resource[TH_MMIO_END + TH_NVEC_MAX] = { [TH_MMIO_CONFIG] = pdev->resource[TH_PCI_CONFIG_BAR], [TH_MMIO_SW] = pdev->resource[TH_PCI_STH_SW_BAR], -- cgit v1.2.3 From d9962f6f428449fe227f1c88c65ac3fffdf7dceb Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Wed, 14 Apr 2021 20:12:48 +0300 Subject: intel_th: Constify attribute_group structs The only usage of them is to pass their address to sysfs_create_group() and sysfs_remove_group(), both which have pointers to const attribute_group structs as input. Make them const to allow the compiler to put them in read-only memory. Signed-off-by: Rikard Falkeborn Signed-off-by: Alexander Shishkin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210414171251.14672-5-alexander.shishkin@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/intel_th/intel_th.h | 2 +- drivers/hwtracing/intel_th/msu.c | 2 +- drivers/hwtracing/intel_th/pti.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/hwtracing/intel_th/intel_th.h b/drivers/hwtracing/intel_th/intel_th.h index 05fa2dab37d1..89c67e0e1d34 100644 --- a/drivers/hwtracing/intel_th/intel_th.h +++ b/drivers/hwtracing/intel_th/intel_th.h @@ -178,7 +178,7 @@ struct intel_th_driver { /* file_operations for those who want a device node */ const struct file_operations *fops; /* optional attributes */ - struct attribute_group *attr_group; + const struct attribute_group *attr_group; /* source ops */ int (*set_output)(struct intel_th_device *thdev, diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c index 7d95242db900..2edc4666633d 100644 --- a/drivers/hwtracing/intel_th/msu.c +++ b/drivers/hwtracing/intel_th/msu.c @@ -2095,7 +2095,7 @@ static struct attribute *msc_output_attrs[] = { NULL, }; -static struct attribute_group msc_output_group = { +static const struct attribute_group msc_output_group = { .attrs = msc_output_attrs, }; diff --git a/drivers/hwtracing/intel_th/pti.c b/drivers/hwtracing/intel_th/pti.c index 0da6b787f553..09132ab8bc23 100644 --- a/drivers/hwtracing/intel_th/pti.c +++ b/drivers/hwtracing/intel_th/pti.c @@ -142,7 +142,7 @@ static struct attribute *pti_output_attrs[] = { NULL, }; -static struct attribute_group pti_output_group = { +static const struct attribute_group pti_output_group = { .attrs = pti_output_attrs, }; @@ -295,7 +295,7 @@ static struct attribute *lpp_output_attrs[] = { NULL, }; -static struct attribute_group lpp_output_group = { +static const struct attribute_group lpp_output_group = { .attrs = lpp_output_attrs, }; -- cgit v1.2.3 From 18ffbc47d45a1489b664dd68fb3a7610a6e1dea3 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Wed, 14 Apr 2021 20:12:49 +0300 Subject: intel_th: Consistency and off-by-one fix Consistently use "< ... +1" in for loops. Fix of-by-one in for_each_set_bit(). Signed-off-by: Pavel Machek Signed-off-by: Alexander Shishkin Link: https://lore.kernel.org/lkml/20190724095841.GA6952@amd/ Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210414171251.14672-6-alexander.shishkin@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/intel_th/gth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/intel_th/gth.c b/drivers/hwtracing/intel_th/gth.c index f72803a02391..28509b02a0b5 100644 --- a/drivers/hwtracing/intel_th/gth.c +++ b/drivers/hwtracing/intel_th/gth.c @@ -543,7 +543,7 @@ static void intel_th_gth_disable(struct intel_th_device *thdev, output->active = false; for_each_set_bit(master, gth->output[output->port].master, - TH_CONFIGURABLE_MASTERS) { + TH_CONFIGURABLE_MASTERS + 1) { gth_master_set(gth, master, -1); } spin_unlock(>h->gth_lock); @@ -697,7 +697,7 @@ static void intel_th_gth_unassign(struct intel_th_device *thdev, othdev->output.port = -1; othdev->output.active = false; gth->output[port].output = NULL; - for (master = 0; master <= TH_CONFIGURABLE_MASTERS; master++) + for (master = 0; master < TH_CONFIGURABLE_MASTERS + 1; master++) if (gth->master[master] == port) gth->master[master] = -1; spin_unlock(>h->gth_lock); -- cgit v1.2.3 From 9f7f2a5e01ab4ee56b6d9c0572536fe5fd56e376 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Wed, 14 Apr 2021 20:12:50 +0300 Subject: intel_th: pci: Add Rocket Lake CPU support This adds support for the Trace Hub in Rocket Lake CPUs. Signed-off-by: Alexander Shishkin Reviewed-by: Andy Shevchenko Cc: stable # v4.14+ Link: https://lore.kernel.org/r/20210414171251.14672-7-alexander.shishkin@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/intel_th/pci.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/hwtracing/intel_th/pci.c b/drivers/hwtracing/intel_th/pci.c index 759994055cb4..a756c995fc7a 100644 --- a/drivers/hwtracing/intel_th/pci.c +++ b/drivers/hwtracing/intel_th/pci.c @@ -278,6 +278,11 @@ static const struct pci_device_id intel_th_pci_id_table[] = { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x466f), .driver_data = (kernel_ulong_t)&intel_th_2x, }, + { + /* Rocket Lake CPU */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4c19), + .driver_data = (kernel_ulong_t)&intel_th_2x, + }, { 0 }, }; -- cgit v1.2.3 From 48cb17531b15967d9d3f34c770a25cc6c4ca6ad1 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Wed, 14 Apr 2021 20:12:51 +0300 Subject: intel_th: pci: Add Alder Lake-M support This adds support for the Trace Hub in Alder Lake-M PCH. Signed-off-by: Alexander Shishkin Reviewed-by: Andy Shevchenko Cc: stable@vger.kernel.org # v4.14+ Link: https://lore.kernel.org/r/20210414171251.14672-8-alexander.shishkin@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/intel_th/pci.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/hwtracing/intel_th/pci.c b/drivers/hwtracing/intel_th/pci.c index a756c995fc7a..7da4f298ed01 100644 --- a/drivers/hwtracing/intel_th/pci.c +++ b/drivers/hwtracing/intel_th/pci.c @@ -273,6 +273,11 @@ static const struct pci_device_id intel_th_pci_id_table[] = { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x51a6), .driver_data = (kernel_ulong_t)&intel_th_2x, }, + { + /* Alder Lake-M */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x54a6), + .driver_data = (kernel_ulong_t)&intel_th_2x, + }, { /* Alder Lake CPU */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x466f), -- cgit v1.2.3 From 41c9f7fb64f8423750b0ccd916a8a3cf4f5c99c1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 15 Apr 2021 12:15:55 +0300 Subject: stm class: Use correct UUID APIs It appears that the STM code didn't manage to accurately decypher the delicate inner workings of an alternative thought process behind the UUID API and directly called generate_random_uuid() that clearly needs to be a static function in lib/uuid.c. At the same time, said STM code is poking directly at the byte array inside the uuid_t when it uses the UUID for its internal purposes. Fix these two transgressions by using intended APIs instead. Signed-off-by: Andy Shevchenko [ash: changed back to uuid_t and updated the commit message] Signed-off-by: Alexander Shishkin Link: https://lore.kernel.org/r/20210415091555.88085-1-alexander.shishkin@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/stm/p_sys-t.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/stm/p_sys-t.c b/drivers/hwtracing/stm/p_sys-t.c index 360b5c03df95..8254971c02e7 100644 --- a/drivers/hwtracing/stm/p_sys-t.c +++ b/drivers/hwtracing/stm/p_sys-t.c @@ -92,7 +92,7 @@ static void sys_t_policy_node_init(void *priv) { struct sys_t_policy_node *pn = priv; - generate_random_uuid(pn->uuid.b); + uuid_gen(&pn->uuid); } static int sys_t_output_open(void *priv, struct stm_output *output) @@ -292,6 +292,7 @@ static ssize_t sys_t_write(struct stm_data *data, struct stm_output *output, unsigned int m = output->master; const unsigned char nil = 0; u32 header = DATA_HEADER; + u8 uuid[UUID_SIZE]; ssize_t sz; /* We require an existing policy node to proceed */ @@ -322,7 +323,8 @@ static ssize_t sys_t_write(struct stm_data *data, struct stm_output *output, return sz; /* GUID */ - sz = stm_data_write(data, m, c, false, op->node.uuid.b, UUID_SIZE); + export_uuid(uuid, &op->node.uuid); + sz = stm_data_write(data, m, c, false, uuid, sizeof(op->node.uuid)); if (sz <= 0) return sz; -- cgit v1.2.3 From e1723d8b87b73ab363256e7ca3af3ddb75855680 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 7 Apr 2021 17:27:16 +0800 Subject: phy: phy-twl4030-usb: Fix possible use-after-free in twl4030_usb_remove() This driver's remove path calls cancel_delayed_work(). However, that function does not wait until the work function finishes. This means that the callback function may still be running after the driver's remove function has finished, which would result in a use-after-free. Fix by calling cancel_delayed_work_sync(), which ensures that the work is properly cancelled, no longer running, and unable to re-schedule itself. Reported-by: Hulk Robot Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20210407092716.3270248-1-yangyingliang@huawei.com Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/phy/ti/phy-twl4030-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/ti/phy-twl4030-usb.c b/drivers/phy/ti/phy-twl4030-usb.c index 9887f908f540..812e5409d359 100644 --- a/drivers/phy/ti/phy-twl4030-usb.c +++ b/drivers/phy/ti/phy-twl4030-usb.c @@ -779,7 +779,7 @@ static int twl4030_usb_remove(struct platform_device *pdev) usb_remove_phy(&twl->phy); pm_runtime_get_sync(twl->dev); - cancel_delayed_work(&twl->id_workaround_work); + cancel_delayed_work_sync(&twl->id_workaround_work); device_remove_file(twl->dev, &dev_attr_vbus); /* set transceiver mode to power on defaults */ -- cgit v1.2.3 From 76b453873628946d4794964fee75835114e5f35b Mon Sep 17 00:00:00 2001 From: Shixin Liu Date: Thu, 8 Apr 2021 09:28:29 +0800 Subject: phy: ti: j721e-wiz: Add missing include linux/slab.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When compiling with CONFIG_PHY_J721E_WIZ, Hulk Robot reported: drivers/phy/ti/phy-j721e-wiz.c: In function ‘wiz_mux_clk_register’: drivers/phy/ti/phy-j721e-wiz.c:659:17: error: implicit declaration of function ‘kzalloc’; did you mean ‘vzalloc’? [-Werror=implicit-function-declaration] 659 | parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL); | ^~~~~~~ | vzalloc drivers/phy/ti/phy-j721e-wiz.c:659:15: warning: assignment to ‘const char **’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion] 659 | parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL); | ^ drivers/phy/ti/phy-j721e-wiz.c:697:2: error: implicit declaration of function ‘kfree’; did you mean ‘vfree’? [-Werror=implicit-function-declaration] 697 | kfree(parent_names); | ^~~~~ | vfre Fixes: 040cbe768731 ("phy: ti: j721e-wiz: Model the internal clocks without device tree input") Reported-by: Hulk Robot Signed-off-by: Shixin Liu Link: https://lore.kernel.org/r/20210408012829.432938-1-liushixin2@huawei.com Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/phy/ti/phy-j721e-wiz.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index 2b354680a272..ab28fb2e01db 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include -- cgit v1.2.3 From ed917b028d0cea5d6f81472a9b7c3266feb9dd42 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 8 Apr 2021 11:59:14 +0530 Subject: phy: Revert "phy: ti: j721e-wiz: add missing of_node_put" This reverts commit 00f2e6f668b0 ("phy: ti: j721e-wiz: add missing of_node_put") as it erroneously adds the of_node_put() as incorrect place. Reported-by: Junlin Yang Link: https://lore.kernel.org/r/20210408062914.3813102-1-vkoul@kernel.org Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/phy/ti/phy-j721e-wiz.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index ab28fb2e01db..9eb6d37c907e 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -1115,7 +1115,6 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz) dev_err(dev, "%s: Reading \"reg\" from \"%s\" failed: %d\n", __func__, subnode->name, ret); - of_node_put(subnode); return ret; } of_property_read_u32(subnode, "cdns,num-lanes", &num_lanes); -- cgit v1.2.3 From 9204ff94868496f2d9b8b173af52ec455160c364 Mon Sep 17 00:00:00 2001 From: Mike Leach Date: Thu, 15 Apr 2021 14:24:04 -0600 Subject: coresight: etm-perf: Fix define build issue when built as module CONFIG_CORESIGHT_SOURCE_ETM4X is undefined when built as module, CONFIG_CORESIGHT_SOURCE_ETM4X_MODULE is defined instead. Therefore code in format_attr_contextid_show() not correctly complied when coresight built as module. Use IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X) to correct this. Link: https://lore.kernel.org/r/20210414194808.22872-1-mike.leach@linaro.org Fixes: 88f11864cf1d ("coresight: etm-perf: Support PID tracing for kernel at EL2") Reviewed-by: Leo Yan Signed-off-by: Mike Leach Signed-off-by: Mathieu Poirier Cc: stable Link: https://lore.kernel.org/r/20210415202404.945368-2-mathieu.poirier@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-etm-perf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index bdbb77334329..c1bec2ad3911 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -52,7 +52,7 @@ static ssize_t format_attr_contextid_show(struct device *dev, { int pid_fmt = ETM_OPT_CTXTID; -#if defined(CONFIG_CORESIGHT_SOURCE_ETM4X) +#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X) pid_fmt = is_kernel_in_hyp_mode() ? ETM_OPT_CTXTID2 : ETM_OPT_CTXTID; #endif return sprintf(page, "config:%d\n", pid_fmt); -- cgit v1.2.3 From e2cb6b891ad2b8caa9131e3be70f45243df82a80 Mon Sep 17 00:00:00 2001 From: Lin Ma Date: Mon, 12 Apr 2021 19:17:57 +0800 Subject: bluetooth: eliminate the potential race condition when removing the HCI controller There is a possible race condition vulnerability between issuing a HCI command and removing the cont. Specifically, functions hci_req_sync() and hci_dev_do_close() can race each other like below: thread-A in hci_req_sync() | thread-B in hci_dev_do_close() | hci_req_sync_lock(hdev); test_bit(HCI_UP, &hdev->flags); | ... | test_and_clear_bit(HCI_UP, &hdev->flags) hci_req_sync_lock(hdev); | | In this commit we alter the sequence in function hci_req_sync(). Hence, the thread-A cannot issue th. Signed-off-by: Lin Ma Cc: Marcel Holtmann Fixes: 7c6a329e4447 ("[Bluetooth] Fix regression from using default link policy") Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/hci_request.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index e55976db4403..805ce546b813 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -272,12 +272,16 @@ int hci_req_sync(struct hci_dev *hdev, int (*req)(struct hci_request *req, { int ret; - if (!test_bit(HCI_UP, &hdev->flags)) - return -ENETDOWN; - /* Serialize all requests */ hci_req_sync_lock(hdev); - ret = __hci_req_sync(hdev, req, opt, timeout, hci_status); + /* check the state after obtaing the lock to protect the HCI_UP + * against any races from hci_dev_do_close when the controller + * gets removed. + */ + if (test_bit(HCI_UP, &hdev->flags)) + ret = __hci_req_sync(hdev, req, opt, timeout, hci_status); + else + ret = -ENETDOWN; hci_req_sync_unlock(hdev); return ret; -- cgit v1.2.3