1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2018 The Linux Foundation. All rights reserved. 4 */ 5 6 #include <linux/module.h> 7 #include <linux/of.h> 8 #include <linux/platform_device.h> 9 #include <linux/regmap.h> 10 #include <linux/reset-controller.h> 11 12 #include <dt-bindings/reset/qcom,sdm845-pdc.h> 13 14 #define RPMH_SDM845_PDC_SYNC_RESET 0x100 15 #define RPMH_SC7280_PDC_SYNC_RESET 0x1000 16 17 struct qcom_pdc_reset_map { 18 u8 bit; 19 }; 20 21 struct qcom_pdc_reset_desc { 22 const struct qcom_pdc_reset_map *resets; 23 size_t num_resets; 24 unsigned int offset; 25 }; 26 27 struct qcom_pdc_reset_data { 28 struct reset_controller_dev rcdev; 29 struct regmap *regmap; 30 const struct qcom_pdc_reset_desc *desc; 31 }; 32 33 static const struct regmap_config pdc_regmap_config = { 34 .name = "pdc-reset", 35 .reg_bits = 32, 36 .reg_stride = 4, 37 .val_bits = 32, 38 .max_register = 0x20000, 39 }; 40 41 static const struct qcom_pdc_reset_map sdm845_pdc_resets[] = { 42 [PDC_APPS_SYNC_RESET] = {0}, 43 [PDC_SP_SYNC_RESET] = {1}, 44 [PDC_AUDIO_SYNC_RESET] = {2}, 45 [PDC_SENSORS_SYNC_RESET] = {3}, 46 [PDC_AOP_SYNC_RESET] = {4}, 47 [PDC_DEBUG_SYNC_RESET] = {5}, 48 [PDC_GPU_SYNC_RESET] = {6}, 49 [PDC_DISPLAY_SYNC_RESET] = {7}, 50 [PDC_COMPUTE_SYNC_RESET] = {8}, 51 [PDC_MODEM_SYNC_RESET] = {9}, 52 }; 53 54 static const struct qcom_pdc_reset_desc sdm845_pdc_reset_desc = { 55 .resets = sdm845_pdc_resets, 56 .num_resets = ARRAY_SIZE(sdm845_pdc_resets), 57 .offset = RPMH_SDM845_PDC_SYNC_RESET, 58 }; 59 60 static const struct qcom_pdc_reset_map sc7280_pdc_resets[] = { 61 [PDC_APPS_SYNC_RESET] = {0}, 62 [PDC_SP_SYNC_RESET] = {1}, 63 [PDC_AUDIO_SYNC_RESET] = {2}, 64 [PDC_SENSORS_SYNC_RESET] = {3}, 65 [PDC_AOP_SYNC_RESET] = {4}, 66 [PDC_DEBUG_SYNC_RESET] = {5}, 67 [PDC_GPU_SYNC_RESET] = {6}, 68 [PDC_DISPLAY_SYNC_RESET] = {7}, 69 [PDC_COMPUTE_SYNC_RESET] = {8}, 70 [PDC_MODEM_SYNC_RESET] = {9}, 71 [PDC_WLAN_RF_SYNC_RESET] = {10}, 72 [PDC_WPSS_SYNC_RESET] = {11}, 73 }; 74 75 static const struct qcom_pdc_reset_desc sc7280_pdc_reset_desc = { 76 .resets = sc7280_pdc_resets, 77 .num_resets = ARRAY_SIZE(sc7280_pdc_resets), 78 .offset = RPMH_SC7280_PDC_SYNC_RESET, 79 }; 80 81 static inline struct qcom_pdc_reset_data *to_qcom_pdc_reset_data( 82 struct reset_controller_dev *rcdev) 83 { 84 return container_of(rcdev, struct qcom_pdc_reset_data, rcdev); 85 } 86 87 static int qcom_pdc_control_assert(struct reset_controller_dev *rcdev, 88 unsigned long idx) 89 { 90 struct qcom_pdc_reset_data *data = to_qcom_pdc_reset_data(rcdev); 91 u32 mask = BIT(data->desc->resets[idx].bit); 92 93 return regmap_update_bits(data->regmap, data->desc->offset, mask, mask); 94 } 95 96 static int qcom_pdc_control_deassert(struct reset_controller_dev *rcdev, 97 unsigned long idx) 98 { 99 struct qcom_pdc_reset_data *data = to_qcom_pdc_reset_data(rcdev); 100 u32 mask = BIT(data->desc->resets[idx].bit); 101 102 return regmap_update_bits(data->regmap, data->desc->offset, mask, 0); 103 } 104 105 static const struct reset_control_ops qcom_pdc_reset_ops = { 106 .assert = qcom_pdc_control_assert, 107 .deassert = qcom_pdc_control_deassert, 108 }; 109 110 static int qcom_pdc_reset_probe(struct platform_device *pdev) 111 { 112 const struct qcom_pdc_reset_desc *desc; 113 struct qcom_pdc_reset_data *data; 114 struct device *dev = &pdev->dev; 115 void __iomem *base; 116 117 desc = device_get_match_data(&pdev->dev); 118 if (!desc) 119 return -EINVAL; 120 121 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 122 if (!data) 123 return -ENOMEM; 124 125 data->desc = desc; 126 base = devm_platform_ioremap_resource(pdev, 0); 127 if (IS_ERR(base)) 128 return PTR_ERR(base); 129 130 data->regmap = devm_regmap_init_mmio(dev, base, &pdc_regmap_config); 131 if (IS_ERR(data->regmap)) { 132 dev_err(dev, "Unable to initialize regmap\n"); 133 return PTR_ERR(data->regmap); 134 } 135 136 data->rcdev.owner = THIS_MODULE; 137 data->rcdev.ops = &qcom_pdc_reset_ops; 138 data->rcdev.nr_resets = desc->num_resets; 139 data->rcdev.of_node = dev->of_node; 140 141 return devm_reset_controller_register(dev, &data->rcdev); 142 } 143 144 static const struct of_device_id qcom_pdc_reset_of_match[] = { 145 { .compatible = "qcom,sc7280-pdc-global", .data = &sc7280_pdc_reset_desc }, 146 { .compatible = "qcom,sdm845-pdc-global", .data = &sdm845_pdc_reset_desc }, 147 {} 148 }; 149 MODULE_DEVICE_TABLE(of, qcom_pdc_reset_of_match); 150 151 static struct platform_driver qcom_pdc_reset_driver = { 152 .probe = qcom_pdc_reset_probe, 153 .driver = { 154 .name = "qcom_pdc_reset", 155 .of_match_table = qcom_pdc_reset_of_match, 156 }, 157 }; 158 module_platform_driver(qcom_pdc_reset_driver); 159 160 MODULE_DESCRIPTION("Qualcomm PDC Reset Driver"); 161 MODULE_LICENSE("GPL v2"); 162