Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 // Copyright (c) 2021, Michael Srba
0003 
0004 #include <linux/clk.h>
0005 #include <linux/delay.h>
0006 #include <linux/io.h>
0007 #include <linux/mfd/syscon.h>
0008 #include <linux/module.h>
0009 #include <linux/of_platform.h>
0010 #include <linux/platform_device.h>
0011 #include <linux/pm_clock.h>
0012 #include <linux/pm_domain.h>
0013 #include <linux/pm_runtime.h>
0014 #include <linux/regmap.h>
0015 #include <linux/reset.h>
0016 
0017 /* AXI Halt Register Offsets */
0018 #define AXI_HALTREQ_REG         0x0
0019 #define AXI_HALTACK_REG         0x4
0020 #define AXI_IDLE_REG            0x8
0021 
0022 #define SSCAON_CONFIG0_CLAMP_EN_OVRD        BIT(4)
0023 #define SSCAON_CONFIG0_CLAMP_EN_OVRD_VAL    BIT(5)
0024 
0025 static const char *const qcom_ssc_block_pd_names[] = {
0026     "ssc_cx",
0027     "ssc_mx"
0028 };
0029 
0030 struct qcom_ssc_block_bus_data {
0031     const char *const *pd_names;
0032     struct device *pds[ARRAY_SIZE(qcom_ssc_block_pd_names)];
0033     char __iomem *reg_mpm_sscaon_config0;
0034     char __iomem *reg_mpm_sscaon_config1;
0035     struct regmap *halt_map;
0036     struct clk *xo_clk;
0037     struct clk *aggre2_clk;
0038     struct clk *gcc_im_sleep_clk;
0039     struct clk *aggre2_north_clk;
0040     struct clk *ssc_xo_clk;
0041     struct clk *ssc_ahbs_clk;
0042     struct reset_control *ssc_bcr;
0043     struct reset_control *ssc_reset;
0044     u32 ssc_axi_halt;
0045     int num_pds;
0046 };
0047 
0048 static void reg32_set_bits(char __iomem *reg, u32 value)
0049 {
0050     u32 tmp = ioread32(reg);
0051 
0052     iowrite32(tmp | value, reg);
0053 }
0054 
0055 static void reg32_clear_bits(char __iomem *reg, u32 value)
0056 {
0057     u32 tmp = ioread32(reg);
0058 
0059     iowrite32(tmp & (~value), reg);
0060 }
0061 
0062 static int qcom_ssc_block_bus_init(struct device *dev)
0063 {
0064     int ret;
0065 
0066     struct qcom_ssc_block_bus_data *data = dev_get_drvdata(dev);
0067 
0068     ret = clk_prepare_enable(data->xo_clk);
0069     if (ret) {
0070         dev_err(dev, "error enabling xo_clk: %d\n", ret);
0071         goto err_xo_clk;
0072     }
0073 
0074     ret = clk_prepare_enable(data->aggre2_clk);
0075     if (ret) {
0076         dev_err(dev, "error enabling aggre2_clk: %d\n", ret);
0077         goto err_aggre2_clk;
0078     }
0079 
0080     ret = clk_prepare_enable(data->gcc_im_sleep_clk);
0081     if (ret) {
0082         dev_err(dev, "error enabling gcc_im_sleep_clk: %d\n", ret);
0083         goto err_gcc_im_sleep_clk;
0084     }
0085 
0086     /*
0087      * We need to intervene here because the HW logic driving these signals cannot handle
0088      * initialization after power collapse by itself.
0089      */
0090     reg32_clear_bits(data->reg_mpm_sscaon_config0,
0091              SSCAON_CONFIG0_CLAMP_EN_OVRD | SSCAON_CONFIG0_CLAMP_EN_OVRD_VAL);
0092     /* override few_ack/rest_ack */
0093     reg32_clear_bits(data->reg_mpm_sscaon_config1, BIT(31));
0094 
0095     ret = clk_prepare_enable(data->aggre2_north_clk);
0096     if (ret) {
0097         dev_err(dev, "error enabling aggre2_north_clk: %d\n", ret);
0098         goto err_aggre2_north_clk;
0099     }
0100 
0101     ret = reset_control_deassert(data->ssc_reset);
0102     if (ret) {
0103         dev_err(dev, "error deasserting ssc_reset: %d\n", ret);
0104         goto err_ssc_reset;
0105     }
0106 
0107     ret = reset_control_deassert(data->ssc_bcr);
0108     if (ret) {
0109         dev_err(dev, "error deasserting ssc_bcr: %d\n", ret);
0110         goto err_ssc_bcr;
0111     }
0112 
0113     regmap_write(data->halt_map, data->ssc_axi_halt + AXI_HALTREQ_REG, 0);
0114 
0115     ret = clk_prepare_enable(data->ssc_xo_clk);
0116     if (ret) {
0117         dev_err(dev, "error deasserting ssc_xo_clk: %d\n", ret);
0118         goto err_ssc_xo_clk;
0119     }
0120 
0121     ret = clk_prepare_enable(data->ssc_ahbs_clk);
0122     if (ret) {
0123         dev_err(dev, "error deasserting ssc_ahbs_clk: %d\n", ret);
0124         goto err_ssc_ahbs_clk;
0125     }
0126 
0127     return 0;
0128 
0129 err_ssc_ahbs_clk:
0130     clk_disable(data->ssc_xo_clk);
0131 
0132 err_ssc_xo_clk:
0133     regmap_write(data->halt_map, data->ssc_axi_halt + AXI_HALTREQ_REG, 1);
0134 
0135     reset_control_assert(data->ssc_bcr);
0136 
0137 err_ssc_bcr:
0138     reset_control_assert(data->ssc_reset);
0139 
0140 err_ssc_reset:
0141     clk_disable(data->aggre2_north_clk);
0142 
0143 err_aggre2_north_clk:
0144     reg32_set_bits(data->reg_mpm_sscaon_config0, BIT(4) | BIT(5));
0145     reg32_set_bits(data->reg_mpm_sscaon_config1, BIT(31));
0146 
0147     clk_disable(data->gcc_im_sleep_clk);
0148 
0149 err_gcc_im_sleep_clk:
0150     clk_disable(data->aggre2_clk);
0151 
0152 err_aggre2_clk:
0153     clk_disable(data->xo_clk);
0154 
0155 err_xo_clk:
0156     return ret;
0157 }
0158 
0159 static void qcom_ssc_block_bus_deinit(struct device *dev)
0160 {
0161     int ret;
0162 
0163     struct qcom_ssc_block_bus_data *data = dev_get_drvdata(dev);
0164 
0165     clk_disable(data->ssc_xo_clk);
0166     clk_disable(data->ssc_ahbs_clk);
0167 
0168     ret = reset_control_assert(data->ssc_bcr);
0169     if (ret)
0170         dev_err(dev, "error asserting ssc_bcr: %d\n", ret);
0171 
0172     regmap_write(data->halt_map, data->ssc_axi_halt + AXI_HALTREQ_REG, 1);
0173 
0174     reg32_set_bits(data->reg_mpm_sscaon_config1, BIT(31));
0175     reg32_set_bits(data->reg_mpm_sscaon_config0, BIT(4) | BIT(5));
0176 
0177     ret = reset_control_assert(data->ssc_reset);
0178     if (ret)
0179         dev_err(dev, "error asserting ssc_reset: %d\n", ret);
0180 
0181     clk_disable(data->gcc_im_sleep_clk);
0182 
0183     clk_disable(data->aggre2_north_clk);
0184 
0185     clk_disable(data->aggre2_clk);
0186     clk_disable(data->xo_clk);
0187 }
0188 
0189 static int qcom_ssc_block_bus_pds_attach(struct device *dev, struct device **pds,
0190                      const char *const *pd_names, size_t num_pds)
0191 {
0192     int ret;
0193     int i;
0194 
0195     for (i = 0; i < num_pds; i++) {
0196         pds[i] = dev_pm_domain_attach_by_name(dev, pd_names[i]);
0197         if (IS_ERR_OR_NULL(pds[i])) {
0198             ret = PTR_ERR(pds[i]) ? : -ENODATA;
0199             goto unroll_attach;
0200         }
0201     }
0202 
0203     return num_pds;
0204 
0205 unroll_attach:
0206     for (i--; i >= 0; i--)
0207         dev_pm_domain_detach(pds[i], false);
0208 
0209     return ret;
0210 };
0211 
0212 static void qcom_ssc_block_bus_pds_detach(struct device *dev, struct device **pds, size_t num_pds)
0213 {
0214     int i;
0215 
0216     for (i = 0; i < num_pds; i++)
0217         dev_pm_domain_detach(pds[i], false);
0218 }
0219 
0220 static int qcom_ssc_block_bus_pds_enable(struct device **pds, size_t num_pds)
0221 {
0222     int ret;
0223     int i;
0224 
0225     for (i = 0; i < num_pds; i++) {
0226         dev_pm_genpd_set_performance_state(pds[i], INT_MAX);
0227         ret = pm_runtime_get_sync(pds[i]);
0228         if (ret < 0)
0229             goto unroll_pd_votes;
0230     }
0231 
0232     return 0;
0233 
0234 unroll_pd_votes:
0235     for (i--; i >= 0; i--) {
0236         dev_pm_genpd_set_performance_state(pds[i], 0);
0237         pm_runtime_put(pds[i]);
0238     }
0239 
0240     return ret;
0241 };
0242 
0243 static void qcom_ssc_block_bus_pds_disable(struct device **pds, size_t num_pds)
0244 {
0245     int i;
0246 
0247     for (i = 0; i < num_pds; i++) {
0248         dev_pm_genpd_set_performance_state(pds[i], 0);
0249         pm_runtime_put(pds[i]);
0250     }
0251 }
0252 
0253 static int qcom_ssc_block_bus_probe(struct platform_device *pdev)
0254 {
0255     struct qcom_ssc_block_bus_data *data;
0256     struct device_node *np = pdev->dev.of_node;
0257     struct of_phandle_args halt_args;
0258     struct resource *res;
0259     int ret;
0260 
0261     data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
0262     if (!data)
0263         return -ENOMEM;
0264 
0265     platform_set_drvdata(pdev, data);
0266 
0267     data->pd_names = qcom_ssc_block_pd_names;
0268     data->num_pds = ARRAY_SIZE(qcom_ssc_block_pd_names);
0269 
0270     /* power domains */
0271     ret = qcom_ssc_block_bus_pds_attach(&pdev->dev, data->pds, data->pd_names, data->num_pds);
0272     if (ret < 0)
0273         return dev_err_probe(&pdev->dev, ret, "error when attaching power domains\n");
0274 
0275     ret = qcom_ssc_block_bus_pds_enable(data->pds, data->num_pds);
0276     if (ret < 0)
0277         return dev_err_probe(&pdev->dev, ret, "error when enabling power domains\n");
0278 
0279     /* low level overrides for when the HW logic doesn't "just work" */
0280     res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpm_sscaon_config0");
0281     data->reg_mpm_sscaon_config0 = devm_ioremap_resource(&pdev->dev, res);
0282     if (IS_ERR(data->reg_mpm_sscaon_config0))
0283         return dev_err_probe(&pdev->dev, PTR_ERR(data->reg_mpm_sscaon_config0),
0284                      "Failed to ioremap mpm_sscaon_config0\n");
0285 
0286     res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpm_sscaon_config1");
0287     data->reg_mpm_sscaon_config1 = devm_ioremap_resource(&pdev->dev, res);
0288     if (IS_ERR(data->reg_mpm_sscaon_config1))
0289         return dev_err_probe(&pdev->dev, PTR_ERR(data->reg_mpm_sscaon_config1),
0290                      "Failed to ioremap mpm_sscaon_config1\n");
0291 
0292     /* resets */
0293     data->ssc_bcr = devm_reset_control_get_exclusive(&pdev->dev, "ssc_bcr");
0294     if (IS_ERR(data->ssc_bcr))
0295         return dev_err_probe(&pdev->dev, PTR_ERR(data->ssc_bcr),
0296                      "Failed to acquire reset: scc_bcr\n");
0297 
0298     data->ssc_reset = devm_reset_control_get_exclusive(&pdev->dev, "ssc_reset");
0299     if (IS_ERR(data->ssc_reset))
0300         return dev_err_probe(&pdev->dev, PTR_ERR(data->ssc_reset),
0301                      "Failed to acquire reset: ssc_reset:\n");
0302 
0303     /* clocks */
0304     data->xo_clk = devm_clk_get(&pdev->dev, "xo");
0305     if (IS_ERR(data->xo_clk))
0306         return dev_err_probe(&pdev->dev, PTR_ERR(data->xo_clk),
0307                      "Failed to get clock: xo\n");
0308 
0309     data->aggre2_clk = devm_clk_get(&pdev->dev, "aggre2");
0310     if (IS_ERR(data->aggre2_clk))
0311         return dev_err_probe(&pdev->dev, PTR_ERR(data->aggre2_clk),
0312                      "Failed to get clock: aggre2\n");
0313 
0314     data->gcc_im_sleep_clk = devm_clk_get(&pdev->dev, "gcc_im_sleep");
0315     if (IS_ERR(data->gcc_im_sleep_clk))
0316         return dev_err_probe(&pdev->dev, PTR_ERR(data->gcc_im_sleep_clk),
0317                      "Failed to get clock: gcc_im_sleep\n");
0318 
0319     data->aggre2_north_clk = devm_clk_get(&pdev->dev, "aggre2_north");
0320     if (IS_ERR(data->aggre2_north_clk))
0321         return dev_err_probe(&pdev->dev, PTR_ERR(data->aggre2_north_clk),
0322                      "Failed to get clock: aggre2_north\n");
0323 
0324     data->ssc_xo_clk = devm_clk_get(&pdev->dev, "ssc_xo");
0325     if (IS_ERR(data->ssc_xo_clk))
0326         return dev_err_probe(&pdev->dev, PTR_ERR(data->ssc_xo_clk),
0327                      "Failed to get clock: ssc_xo\n");
0328 
0329     data->ssc_ahbs_clk = devm_clk_get(&pdev->dev, "ssc_ahbs");
0330     if (IS_ERR(data->ssc_ahbs_clk))
0331         return dev_err_probe(&pdev->dev, PTR_ERR(data->ssc_ahbs_clk),
0332                      "Failed to get clock: ssc_ahbs\n");
0333 
0334     ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, "qcom,halt-regs", 1, 0,
0335                            &halt_args);
0336     if (ret < 0)
0337         return dev_err_probe(&pdev->dev, ret, "Failed to parse qcom,halt-regs\n");
0338 
0339     data->halt_map = syscon_node_to_regmap(halt_args.np);
0340     of_node_put(halt_args.np);
0341     if (IS_ERR(data->halt_map))
0342         return PTR_ERR(data->halt_map);
0343 
0344     data->ssc_axi_halt = halt_args.args[0];
0345 
0346     qcom_ssc_block_bus_init(&pdev->dev);
0347 
0348     of_platform_populate(np, NULL, NULL, &pdev->dev);
0349 
0350     return 0;
0351 }
0352 
0353 static int qcom_ssc_block_bus_remove(struct platform_device *pdev)
0354 {
0355     struct qcom_ssc_block_bus_data *data = platform_get_drvdata(pdev);
0356 
0357     qcom_ssc_block_bus_deinit(&pdev->dev);
0358 
0359     iounmap(data->reg_mpm_sscaon_config0);
0360     iounmap(data->reg_mpm_sscaon_config1);
0361 
0362     qcom_ssc_block_bus_pds_disable(data->pds, data->num_pds);
0363     qcom_ssc_block_bus_pds_detach(&pdev->dev, data->pds, data->num_pds);
0364     pm_runtime_disable(&pdev->dev);
0365     pm_clk_destroy(&pdev->dev);
0366 
0367     return 0;
0368 }
0369 
0370 static const struct of_device_id qcom_ssc_block_bus_of_match[] = {
0371     { .compatible = "qcom,ssc-block-bus", },
0372     { /* sentinel */ }
0373 };
0374 MODULE_DEVICE_TABLE(of, qcom_ssc_block_bus_of_match);
0375 
0376 static struct platform_driver qcom_ssc_block_bus_driver = {
0377     .probe = qcom_ssc_block_bus_probe,
0378     .remove = qcom_ssc_block_bus_remove,
0379     .driver = {
0380         .name = "qcom-ssc-block-bus",
0381         .of_match_table = qcom_ssc_block_bus_of_match,
0382     },
0383 };
0384 
0385 module_platform_driver(qcom_ssc_block_bus_driver);
0386 
0387 MODULE_DESCRIPTION("A driver for handling the init sequence needed for accessing the SSC block on (some) qcom SoCs over AHB");
0388 MODULE_AUTHOR("Michael Srba <Michael.Srba@seznam.cz>");
0389 MODULE_LICENSE("GPL v2");