Merge tag 'reset-for-4.19' of git://git.pengutronix.de/git/pza/linux into next/drivers
authorOlof Johansson <olof@lixom.net>
Sat, 21 Jul 2018 22:05:03 +0000 (15:05 -0700)
committerOlof Johansson <olof@lixom.net>
Sat, 21 Jul 2018 22:05:03 +0000 (15:05 -0700)
Reset controller changes for v4.19

This adds new drivers and bindings for the SDM845 AOSS (always on
subsystem) reset controller and for the Uniphier USB3 core reset.
SPI controller resets are added to the Uniphier reset driver.

* tag 'reset-for-4.19' of git://git.pengutronix.de/git/pza/linux:
  reset: uniphier: add reset control support for SPI
  reset: uniphier: add USB3 core reset control
  dt-bindings: reset: uniphier: add USB3 core reset support
  reset: simple: export reset_simple_ops to be referred from modules
  reset: qcom: AOSS (always on subsystem) reset controller
  dt-bindings: reset: Add AOSS reset bindings for SDM845 SoCs

Signed-off-by: Olof Johansson <olof@lixom.net>
Documentation/devicetree/bindings/reset/qcom,aoss-reset.txt [new file with mode: 0644]
Documentation/devicetree/bindings/reset/uniphier-reset.txt
drivers/reset/Kconfig
drivers/reset/Makefile
drivers/reset/reset-qcom-aoss.c [new file with mode: 0644]
drivers/reset/reset-simple.c
drivers/reset/reset-uniphier-usb3.c [new file with mode: 0644]
drivers/reset/reset-uniphier.c
include/dt-bindings/reset/qcom,sdm845-aoss.h [new file with mode: 0644]

diff --git a/Documentation/devicetree/bindings/reset/qcom,aoss-reset.txt b/Documentation/devicetree/bindings/reset/qcom,aoss-reset.txt
new file mode 100644 (file)
index 0000000..510c748
--- /dev/null
@@ -0,0 +1,52 @@
+Qualcomm AOSS Reset Controller
+======================================
+
+This binding describes a reset-controller found on AOSS-CC (always on subsystem)
+for Qualcomm SDM845 SoCs.
+
+Required properties:
+- compatible:
+       Usage: required
+       Value type: <string>
+       Definition: must be:
+                   "qcom,sdm845-aoss-cc"
+
+- reg:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: must specify the base address and size of the register
+                   space.
+
+- #reset-cells:
+       Usage: required
+       Value type: <uint>
+       Definition: must be 1; cell entry represents the reset index.
+
+Example:
+
+aoss_reset: reset-controller@c2a0000 {
+       compatible = "qcom,sdm845-aoss-cc";
+       reg = <0xc2a0000 0x31000>;
+       #reset-cells = <1>;
+};
+
+Specifying reset lines connected to IP modules
+==============================================
+
+Device nodes that need access to reset lines should
+specify them as a reset phandle in their corresponding node as
+specified in reset.txt.
+
+For list of all valid reset indicies see
+<dt-bindings/reset/qcom,sdm845-aoss.h>
+
+Example:
+
+modem-pil@4080000 {
+       ...
+
+       resets = <&aoss_reset AOSS_CC_MSS_RESTART>;
+       reset-names = "mss_restart";
+
+       ...
+};
index 93efed629900c65f9c9b1d74265cb4d2c7936245..101743dda2235766b19564061a66282a35d02e0a 100644 (file)
@@ -118,3 +118,59 @@ Example:
 
                other nodes ...
        };
+
+
+USB3 core reset
+---------------
+
+USB3 core reset belongs to USB3 glue layer. Before using the core reset,
+it is necessary to control the clocks and resets to enable this layer.
+These clocks and resets should be described in each property.
+
+Required properties:
+- compatible: Should be
+    "socionext,uniphier-pro4-usb3-reset" - for Pro4 SoC
+    "socionext,uniphier-pxs2-usb3-reset" - for PXs2 SoC
+    "socionext,uniphier-ld20-usb3-reset" - for LD20 SoC
+    "socionext,uniphier-pxs3-usb3-reset" - for PXs3 SoC
+- #reset-cells: Should be 1.
+- reg: Specifies offset and length of the register set for the device.
+- clocks: A list of phandles to the clock gate for USB3 glue layer.
+       According to the clock-names, appropriate clocks are required.
+- clock-names: Should contain
+    "gio", "link" - for Pro4 SoC
+    "link"        - for others
+- resets: A list of phandles to the reset control for USB3 glue layer.
+       According to the reset-names, appropriate resets are required.
+- reset-names: Should contain
+    "gio", "link" - for Pro4 SoC
+    "link"        - for others
+
+Example:
+
+       usb-glue@65b00000 {
+               compatible = "socionext,uniphier-ld20-dwc3-glue",
+                            "simple-mfd";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0x65b00000 0x400>;
+
+               usb_rst: reset@0 {
+                       compatible = "socionext,uniphier-ld20-usb3-reset";
+                       reg = <0x0 0x4>;
+                       #reset-cells = <1>;
+                       clock-names = "link";
+                       clocks = <&sys_clk 14>;
+                       reset-names = "link";
+                       resets = <&sys_rst 14>;
+               };
+
+               regulator {
+                       ...
+               };
+
+               phy {
+                       ...
+               };
+               ...
+       };
index c0b292be1b72f1eb4d31b142636699d0736722f3..a70262cb7e569dc5c47874bd286bd3afd58a1f2e 100644 (file)
@@ -82,6 +82,15 @@ config RESET_PISTACHIO
        help
          This enables the reset driver for ImgTec Pistachio SoCs.
 
+config RESET_QCOM_AOSS
+       bool "Qcom AOSS Reset Driver"
+       depends on ARCH_QCOM || COMPILE_TEST
+       help
+         This enables the AOSS (always on subsystem) reset driver
+         for Qualcomm SDM845 SoCs. Say Y if you want to control
+         reset signals provided by AOSS for Modem, Venus, ADSP,
+         GPU, Camera, Wireless, Display subsystem. Otherwise, say N.
+
 config RESET_SIMPLE
        bool "Simple Reset Controller Driver" if COMPILE_TEST
        default ARCH_SOCFPGA || ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED
@@ -138,6 +147,16 @@ config RESET_UNIPHIER
          Say Y if you want to control reset signals provided by System Control
          block, Media I/O block, Peripheral Block.
 
+config RESET_UNIPHIER_USB3
+       tristate "USB3 reset driver for UniPhier SoCs"
+       depends on (ARCH_UNIPHIER || COMPILE_TEST) && OF
+       default ARCH_UNIPHIER
+       select RESET_SIMPLE
+       help
+         Support for the USB3 core reset on UniPhier SoCs.
+         Say Y if you want to control reset signals provided by
+         USB3 glue layer.
+
 config RESET_ZYNQ
        bool "ZYNQ Reset Driver" if COMPILE_TEST
        default ARCH_ZYNQ
index c1261dcfe9ad29e9b1640d47da804f2d2d40ed44..0676b6b1976f2e5c02c2e136ddf0d03c4c5aace5 100644 (file)
@@ -14,11 +14,13 @@ obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o
 obj-$(CONFIG_RESET_MESON) += reset-meson.o
 obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o
 obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o
+obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o
 obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
 obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o
 obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
 obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o
 obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o
 obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
+obj-$(CONFIG_RESET_UNIPHIER_USB3) += reset-uniphier-usb3.o
 obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
 
diff --git a/drivers/reset/reset-qcom-aoss.c b/drivers/reset/reset-qcom-aoss.c
new file mode 100644 (file)
index 0000000..36db967
--- /dev/null
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <dt-bindings/reset/qcom,sdm845-aoss.h>
+
+struct qcom_aoss_reset_map {
+       unsigned int reg;
+};
+
+struct qcom_aoss_desc {
+       const struct qcom_aoss_reset_map *resets;
+       size_t num_resets;
+};
+
+struct qcom_aoss_reset_data {
+       struct reset_controller_dev rcdev;
+       void __iomem *base;
+       const struct qcom_aoss_desc *desc;
+};
+
+static const struct qcom_aoss_reset_map sdm845_aoss_resets[] = {
+       [AOSS_CC_MSS_RESTART] = {0x10000},
+       [AOSS_CC_CAMSS_RESTART] = {0x11000},
+       [AOSS_CC_VENUS_RESTART] = {0x12000},
+       [AOSS_CC_GPU_RESTART] = {0x13000},
+       [AOSS_CC_DISPSS_RESTART] = {0x14000},
+       [AOSS_CC_WCSS_RESTART] = {0x20000},
+       [AOSS_CC_LPASS_RESTART] = {0x30000},
+};
+
+static const struct qcom_aoss_desc sdm845_aoss_desc = {
+       .resets = sdm845_aoss_resets,
+       .num_resets = ARRAY_SIZE(sdm845_aoss_resets),
+};
+
+static inline struct qcom_aoss_reset_data *to_qcom_aoss_reset_data(
+                               struct reset_controller_dev *rcdev)
+{
+       return container_of(rcdev, struct qcom_aoss_reset_data, rcdev);
+}
+
+static int qcom_aoss_control_assert(struct reset_controller_dev *rcdev,
+                                   unsigned long idx)
+{
+       struct qcom_aoss_reset_data *data = to_qcom_aoss_reset_data(rcdev);
+       const struct qcom_aoss_reset_map *map = &data->desc->resets[idx];
+
+       writel(1, data->base + map->reg);
+       /* Wait 6 32kHz sleep cycles for reset */
+       usleep_range(200, 300);
+       return 0;
+}
+
+static int qcom_aoss_control_deassert(struct reset_controller_dev *rcdev,
+                                     unsigned long idx)
+{
+       struct qcom_aoss_reset_data *data = to_qcom_aoss_reset_data(rcdev);
+       const struct qcom_aoss_reset_map *map = &data->desc->resets[idx];
+
+       writel(0, data->base + map->reg);
+       /* Wait 6 32kHz sleep cycles for reset */
+       usleep_range(200, 300);
+       return 0;
+}
+
+static int qcom_aoss_control_reset(struct reset_controller_dev *rcdev,
+                                       unsigned long idx)
+{
+       qcom_aoss_control_assert(rcdev, idx);
+
+       return qcom_aoss_control_deassert(rcdev, idx);
+}
+
+static const struct reset_control_ops qcom_aoss_reset_ops = {
+       .reset = qcom_aoss_control_reset,
+       .assert = qcom_aoss_control_assert,
+       .deassert = qcom_aoss_control_deassert,
+};
+
+static int qcom_aoss_reset_probe(struct platform_device *pdev)
+{
+       struct qcom_aoss_reset_data *data;
+       struct device *dev = &pdev->dev;
+       const struct qcom_aoss_desc *desc;
+       struct resource *res;
+
+       desc = of_device_get_match_data(dev);
+       if (!desc)
+               return -EINVAL;
+
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->desc = desc;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       data->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(data->base))
+               return PTR_ERR(data->base);
+
+       data->rcdev.owner = THIS_MODULE;
+       data->rcdev.ops = &qcom_aoss_reset_ops;
+       data->rcdev.nr_resets = desc->num_resets;
+       data->rcdev.of_node = dev->of_node;
+
+       return devm_reset_controller_register(dev, &data->rcdev);
+}
+
+static const struct of_device_id qcom_aoss_reset_of_match[] = {
+       { .compatible = "qcom,sdm845-aoss-cc", .data = &sdm845_aoss_desc },
+       {}
+};
+
+static struct platform_driver qcom_aoss_reset_driver = {
+       .probe = qcom_aoss_reset_probe,
+       .driver  = {
+               .name = "qcom_aoss_reset",
+               .of_match_table = qcom_aoss_reset_of_match,
+       },
+};
+
+builtin_platform_driver(qcom_aoss_reset_driver);
+
+MODULE_DESCRIPTION("Qualcomm AOSS Reset Driver");
+MODULE_LICENSE("GPL v2");
index f7ce8910a392ca77e235880f795e3e298ccf7eba..a91107fc9e272352a798301cddb34bae8bb3891c 100644 (file)
@@ -87,6 +87,7 @@ const struct reset_control_ops reset_simple_ops = {
        .deassert       = reset_simple_deassert,
        .status         = reset_simple_status,
 };
+EXPORT_SYMBOL_GPL(reset_simple_ops);
 
 /**
  * struct reset_simple_devdata - simple reset controller properties
diff --git a/drivers/reset/reset-uniphier-usb3.c b/drivers/reset/reset-uniphier-usb3.c
new file mode 100644 (file)
index 0000000..ffa1b19
--- /dev/null
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// reset-uniphier-usb3.c - USB3 reset driver for UniPhier
+// Copyright 2018 Socionext Inc.
+// Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#include "reset-simple.h"
+
+#define MAX_CLKS       2
+#define MAX_RSTS       2
+
+struct uniphier_usb3_reset_soc_data {
+       int nclks;
+       const char * const *clock_names;
+       int nrsts;
+       const char * const *reset_names;
+};
+
+struct uniphier_usb3_reset_priv {
+       struct clk_bulk_data clk[MAX_CLKS];
+       struct reset_control *rst[MAX_RSTS];
+       struct reset_simple_data rdata;
+       const struct uniphier_usb3_reset_soc_data *data;
+};
+
+static int uniphier_usb3_reset_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct uniphier_usb3_reset_priv *priv;
+       struct resource *res;
+       resource_size_t size;
+       const char *name;
+       int i, ret, nr;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->data = of_device_get_match_data(dev);
+       if (WARN_ON(!priv->data || priv->data->nclks > MAX_CLKS ||
+                   priv->data->nrsts > MAX_RSTS))
+               return -EINVAL;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       size = resource_size(res);
+       priv->rdata.membase = devm_ioremap_resource(dev, res);
+       if (IS_ERR(priv->rdata.membase))
+               return PTR_ERR(priv->rdata.membase);
+
+       for (i = 0; i < priv->data->nclks; i++)
+               priv->clk[i].id = priv->data->clock_names[i];
+       ret = devm_clk_bulk_get(dev, priv->data->nclks, priv->clk);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < priv->data->nrsts; i++) {
+               name = priv->data->reset_names[i];
+               priv->rst[i] = devm_reset_control_get_shared(dev, name);
+               if (IS_ERR(priv->rst[i]))
+                       return PTR_ERR(priv->rst[i]);
+       }
+
+       ret = clk_bulk_prepare_enable(priv->data->nclks, priv->clk);
+       if (ret)
+               return ret;
+
+       for (nr = 0; nr < priv->data->nrsts; nr++) {
+               ret = reset_control_deassert(priv->rst[nr]);
+               if (ret)
+                       goto out_rst_assert;
+       }
+
+       spin_lock_init(&priv->rdata.lock);
+       priv->rdata.rcdev.owner = THIS_MODULE;
+       priv->rdata.rcdev.nr_resets = size * BITS_PER_BYTE;
+       priv->rdata.rcdev.ops = &reset_simple_ops;
+       priv->rdata.rcdev.of_node = dev->of_node;
+       priv->rdata.active_low = true;
+
+       platform_set_drvdata(pdev, priv);
+
+       ret = devm_reset_controller_register(dev, &priv->rdata.rcdev);
+       if (ret)
+               goto out_rst_assert;
+
+       return 0;
+
+out_rst_assert:
+       while (nr--)
+               reset_control_assert(priv->rst[nr]);
+
+       clk_bulk_disable_unprepare(priv->data->nclks, priv->clk);
+
+       return ret;
+}
+
+static int uniphier_usb3_reset_remove(struct platform_device *pdev)
+{
+       struct uniphier_usb3_reset_priv *priv = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < priv->data->nrsts; i++)
+               reset_control_assert(priv->rst[i]);
+
+       clk_bulk_disable_unprepare(priv->data->nclks, priv->clk);
+
+       return 0;
+}
+
+static const char * const uniphier_pro4_clock_reset_names[] = {
+       "gio", "link",
+};
+
+static const struct uniphier_usb3_reset_soc_data uniphier_pro4_data = {
+       .nclks = ARRAY_SIZE(uniphier_pro4_clock_reset_names),
+       .clock_names = uniphier_pro4_clock_reset_names,
+       .nrsts = ARRAY_SIZE(uniphier_pro4_clock_reset_names),
+       .reset_names = uniphier_pro4_clock_reset_names,
+};
+
+static const char * const uniphier_pxs2_clock_reset_names[] = {
+       "link",
+};
+
+static const struct uniphier_usb3_reset_soc_data uniphier_pxs2_data = {
+       .nclks = ARRAY_SIZE(uniphier_pxs2_clock_reset_names),
+       .clock_names = uniphier_pxs2_clock_reset_names,
+       .nrsts = ARRAY_SIZE(uniphier_pxs2_clock_reset_names),
+       .reset_names = uniphier_pxs2_clock_reset_names,
+};
+
+static const struct of_device_id uniphier_usb3_reset_match[] = {
+       {
+               .compatible = "socionext,uniphier-pro4-usb3-reset",
+               .data = &uniphier_pro4_data,
+       },
+       {
+               .compatible = "socionext,uniphier-pxs2-usb3-reset",
+               .data = &uniphier_pxs2_data,
+       },
+       {
+               .compatible = "socionext,uniphier-ld20-usb3-reset",
+               .data = &uniphier_pxs2_data,
+       },
+       {
+               .compatible = "socionext,uniphier-pxs3-usb3-reset",
+               .data = &uniphier_pxs2_data,
+       },
+       { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_usb3_reset_match);
+
+static struct platform_driver uniphier_usb3_reset_driver = {
+       .probe = uniphier_usb3_reset_probe,
+       .remove = uniphier_usb3_reset_remove,
+       .driver = {
+               .name = "uniphier-usb3-reset",
+               .of_match_table = uniphier_usb3_reset_match,
+       },
+};
+module_platform_driver(uniphier_usb3_reset_driver);
+
+MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
+MODULE_DESCRIPTION("UniPhier USB3 Reset Driver");
+MODULE_LICENSE("GPL");
index e9030ff1bf2fa3d27e83b9848f012a13becb4500..5605745663ae0d76122ed1e52e417e741b5ea8b2 100644 (file)
@@ -202,6 +202,12 @@ static const struct uniphier_reset_data uniphier_pro5_sd_reset_data[] = {
 #define UNIPHIER_PERI_RESET_FI2C(id, ch)               \
        UNIPHIER_RESETX((id), 0x114, 24 + (ch))
 
+#define UNIPHIER_PERI_RESET_SCSSI(id)                  \
+       UNIPHIER_RESETX((id), 0x110, 17)
+
+#define UNIPHIER_PERI_RESET_MCSSI(id)                  \
+       UNIPHIER_RESETX((id), 0x114, 14)
+
 static const struct uniphier_reset_data uniphier_ld4_peri_reset_data[] = {
        UNIPHIER_PERI_RESET_UART(0, 0),
        UNIPHIER_PERI_RESET_UART(1, 1),
@@ -212,6 +218,7 @@ static const struct uniphier_reset_data uniphier_ld4_peri_reset_data[] = {
        UNIPHIER_PERI_RESET_I2C(6, 2),
        UNIPHIER_PERI_RESET_I2C(7, 3),
        UNIPHIER_PERI_RESET_I2C(8, 4),
+       UNIPHIER_PERI_RESET_SCSSI(11),
        UNIPHIER_RESET_END,
 };
 
@@ -227,6 +234,8 @@ static const struct uniphier_reset_data uniphier_pro4_peri_reset_data[] = {
        UNIPHIER_PERI_RESET_FI2C(8, 4),
        UNIPHIER_PERI_RESET_FI2C(9, 5),
        UNIPHIER_PERI_RESET_FI2C(10, 6),
+       UNIPHIER_PERI_RESET_SCSSI(11),
+       UNIPHIER_PERI_RESET_MCSSI(12),
        UNIPHIER_RESET_END,
 };
 
diff --git a/include/dt-bindings/reset/qcom,sdm845-aoss.h b/include/dt-bindings/reset/qcom,sdm845-aoss.h
new file mode 100644 (file)
index 0000000..476c5fc
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _DT_BINDINGS_RESET_AOSS_SDM_845_H
+#define _DT_BINDINGS_RESET_AOSS_SDM_845_H
+
+#define AOSS_CC_MSS_RESTART    0
+#define AOSS_CC_CAMSS_RESTART  1
+#define AOSS_CC_VENUS_RESTART  2
+#define AOSS_CC_GPU_RESTART    3
+#define AOSS_CC_DISPSS_RESTART 4
+#define AOSS_CC_WCSS_RESTART   5
+#define AOSS_CC_LPASS_RESTART  6
+
+#endif