Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Copyright (C) 2018 Xilinx, Inc.
0004  *
0005  */
0006 
0007 #include <linux/err.h>
0008 #include <linux/of.h>
0009 #include <linux/platform_device.h>
0010 #include <linux/reset-controller.h>
0011 #include <linux/firmware/xlnx-zynqmp.h>
0012 #include <linux/of_device.h>
0013 
0014 #define ZYNQMP_NR_RESETS (ZYNQMP_PM_RESET_END - ZYNQMP_PM_RESET_START)
0015 #define ZYNQMP_RESET_ID ZYNQMP_PM_RESET_START
0016 #define VERSAL_NR_RESETS    95
0017 
0018 struct zynqmp_reset_soc_data {
0019     u32 reset_id;
0020     u32 num_resets;
0021 };
0022 
0023 struct zynqmp_reset_data {
0024     struct reset_controller_dev rcdev;
0025     const struct zynqmp_reset_soc_data *data;
0026 };
0027 
0028 static inline struct zynqmp_reset_data *
0029 to_zynqmp_reset_data(struct reset_controller_dev *rcdev)
0030 {
0031     return container_of(rcdev, struct zynqmp_reset_data, rcdev);
0032 }
0033 
0034 static int zynqmp_reset_assert(struct reset_controller_dev *rcdev,
0035                    unsigned long id)
0036 {
0037     struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
0038 
0039     return zynqmp_pm_reset_assert(priv->data->reset_id + id,
0040                       PM_RESET_ACTION_ASSERT);
0041 }
0042 
0043 static int zynqmp_reset_deassert(struct reset_controller_dev *rcdev,
0044                  unsigned long id)
0045 {
0046     struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
0047 
0048     return zynqmp_pm_reset_assert(priv->data->reset_id + id,
0049                       PM_RESET_ACTION_RELEASE);
0050 }
0051 
0052 static int zynqmp_reset_status(struct reset_controller_dev *rcdev,
0053                    unsigned long id)
0054 {
0055     struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
0056     int err;
0057     u32 val;
0058 
0059     err = zynqmp_pm_reset_get_status(priv->data->reset_id + id, &val);
0060     if (err)
0061         return err;
0062 
0063     return val;
0064 }
0065 
0066 static int zynqmp_reset_reset(struct reset_controller_dev *rcdev,
0067                   unsigned long id)
0068 {
0069     struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev);
0070 
0071     return zynqmp_pm_reset_assert(priv->data->reset_id + id,
0072                       PM_RESET_ACTION_PULSE);
0073 }
0074 
0075 static int zynqmp_reset_of_xlate(struct reset_controller_dev *rcdev,
0076                  const struct of_phandle_args *reset_spec)
0077 {
0078     return reset_spec->args[0];
0079 }
0080 
0081 static const struct zynqmp_reset_soc_data zynqmp_reset_data = {
0082     .reset_id = ZYNQMP_RESET_ID,
0083     .num_resets = ZYNQMP_NR_RESETS,
0084 };
0085 
0086 static const struct zynqmp_reset_soc_data versal_reset_data = {
0087     .reset_id = 0,
0088     .num_resets = VERSAL_NR_RESETS,
0089 };
0090 
0091 static const struct reset_control_ops zynqmp_reset_ops = {
0092     .reset = zynqmp_reset_reset,
0093     .assert = zynqmp_reset_assert,
0094     .deassert = zynqmp_reset_deassert,
0095     .status = zynqmp_reset_status,
0096 };
0097 
0098 static int zynqmp_reset_probe(struct platform_device *pdev)
0099 {
0100     struct zynqmp_reset_data *priv;
0101 
0102     priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0103     if (!priv)
0104         return -ENOMEM;
0105 
0106     priv->data = of_device_get_match_data(&pdev->dev);
0107     if (!priv->data)
0108         return -EINVAL;
0109 
0110     platform_set_drvdata(pdev, priv);
0111 
0112     priv->rcdev.ops = &zynqmp_reset_ops;
0113     priv->rcdev.owner = THIS_MODULE;
0114     priv->rcdev.of_node = pdev->dev.of_node;
0115     priv->rcdev.nr_resets = priv->data->num_resets;
0116     priv->rcdev.of_reset_n_cells = 1;
0117     priv->rcdev.of_xlate = zynqmp_reset_of_xlate;
0118 
0119     return devm_reset_controller_register(&pdev->dev, &priv->rcdev);
0120 }
0121 
0122 static const struct of_device_id zynqmp_reset_dt_ids[] = {
0123     { .compatible = "xlnx,zynqmp-reset", .data = &zynqmp_reset_data, },
0124     { .compatible = "xlnx,versal-reset", .data = &versal_reset_data, },
0125     { /* sentinel */ },
0126 };
0127 
0128 static struct platform_driver zynqmp_reset_driver = {
0129     .probe  = zynqmp_reset_probe,
0130     .driver = {
0131         .name       = KBUILD_MODNAME,
0132         .of_match_table = zynqmp_reset_dt_ids,
0133     },
0134 };
0135 
0136 static int __init zynqmp_reset_init(void)
0137 {
0138     return platform_driver_register(&zynqmp_reset_driver);
0139 }
0140 
0141 arch_initcall(zynqmp_reset_init);