0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/kernel.h>
0010 #include <linux/platform_device.h>
0011 #include <linux/interconnect.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/module.h>
0014 #include <linux/soc/qcom/qcom_aoss.h>
0015 #include <linux/soc/qcom/smem.h>
0016 #include <linux/soc/qcom/smem_state.h>
0017 #include <linux/remoteproc.h>
0018 #include "qcom_common.h"
0019 #include "qcom_q6v5.h"
0020
0021 #define Q6V5_LOAD_STATE_MSG_LEN 64
0022 #define Q6V5_PANIC_DELAY_MS 200
0023
0024 static int q6v5_load_state_toggle(struct qcom_q6v5 *q6v5, bool enable)
0025 {
0026 char buf[Q6V5_LOAD_STATE_MSG_LEN];
0027 int ret;
0028
0029 if (!q6v5->qmp)
0030 return 0;
0031
0032 ret = snprintf(buf, sizeof(buf),
0033 "{class: image, res: load_state, name: %s, val: %s}",
0034 q6v5->load_state, enable ? "on" : "off");
0035
0036 WARN_ON(ret >= Q6V5_LOAD_STATE_MSG_LEN);
0037
0038 ret = qmp_send(q6v5->qmp, buf, sizeof(buf));
0039 if (ret)
0040 dev_err(q6v5->dev, "failed to toggle load state\n");
0041
0042 return ret;
0043 }
0044
0045
0046
0047
0048
0049
0050
0051 int qcom_q6v5_prepare(struct qcom_q6v5 *q6v5)
0052 {
0053 int ret;
0054
0055 ret = icc_set_bw(q6v5->path, 0, UINT_MAX);
0056 if (ret < 0) {
0057 dev_err(q6v5->dev, "failed to set bandwidth request\n");
0058 return ret;
0059 }
0060
0061 ret = q6v5_load_state_toggle(q6v5, true);
0062 if (ret) {
0063 icc_set_bw(q6v5->path, 0, 0);
0064 return ret;
0065 }
0066
0067 reinit_completion(&q6v5->start_done);
0068 reinit_completion(&q6v5->stop_done);
0069
0070 q6v5->running = true;
0071 q6v5->handover_issued = false;
0072
0073 enable_irq(q6v5->handover_irq);
0074
0075 return 0;
0076 }
0077 EXPORT_SYMBOL_GPL(qcom_q6v5_prepare);
0078
0079
0080
0081
0082
0083
0084
0085 int qcom_q6v5_unprepare(struct qcom_q6v5 *q6v5)
0086 {
0087 disable_irq(q6v5->handover_irq);
0088 q6v5_load_state_toggle(q6v5, false);
0089
0090
0091 icc_set_bw(q6v5->path, 0, 0);
0092
0093 return !q6v5->handover_issued;
0094 }
0095 EXPORT_SYMBOL_GPL(qcom_q6v5_unprepare);
0096
0097 static irqreturn_t q6v5_wdog_interrupt(int irq, void *data)
0098 {
0099 struct qcom_q6v5 *q6v5 = data;
0100 size_t len;
0101 char *msg;
0102
0103
0104 if (!q6v5->running) {
0105 complete(&q6v5->stop_done);
0106 return IRQ_HANDLED;
0107 }
0108
0109 msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, q6v5->crash_reason, &len);
0110 if (!IS_ERR(msg) && len > 0 && msg[0])
0111 dev_err(q6v5->dev, "watchdog received: %s\n", msg);
0112 else
0113 dev_err(q6v5->dev, "watchdog without message\n");
0114
0115 q6v5->running = false;
0116 rproc_report_crash(q6v5->rproc, RPROC_WATCHDOG);
0117
0118 return IRQ_HANDLED;
0119 }
0120
0121 static irqreturn_t q6v5_fatal_interrupt(int irq, void *data)
0122 {
0123 struct qcom_q6v5 *q6v5 = data;
0124 size_t len;
0125 char *msg;
0126
0127 if (!q6v5->running)
0128 return IRQ_HANDLED;
0129
0130 msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, q6v5->crash_reason, &len);
0131 if (!IS_ERR(msg) && len > 0 && msg[0])
0132 dev_err(q6v5->dev, "fatal error received: %s\n", msg);
0133 else
0134 dev_err(q6v5->dev, "fatal error without message\n");
0135
0136 q6v5->running = false;
0137 rproc_report_crash(q6v5->rproc, RPROC_FATAL_ERROR);
0138
0139 return IRQ_HANDLED;
0140 }
0141
0142 static irqreturn_t q6v5_ready_interrupt(int irq, void *data)
0143 {
0144 struct qcom_q6v5 *q6v5 = data;
0145
0146 complete(&q6v5->start_done);
0147
0148 return IRQ_HANDLED;
0149 }
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160 int qcom_q6v5_wait_for_start(struct qcom_q6v5 *q6v5, int timeout)
0161 {
0162 int ret;
0163
0164 ret = wait_for_completion_timeout(&q6v5->start_done, timeout);
0165 if (!ret)
0166 disable_irq(q6v5->handover_irq);
0167
0168 return !ret ? -ETIMEDOUT : 0;
0169 }
0170 EXPORT_SYMBOL_GPL(qcom_q6v5_wait_for_start);
0171
0172 static irqreturn_t q6v5_handover_interrupt(int irq, void *data)
0173 {
0174 struct qcom_q6v5 *q6v5 = data;
0175
0176 if (q6v5->handover)
0177 q6v5->handover(q6v5);
0178
0179 icc_set_bw(q6v5->path, 0, 0);
0180
0181 q6v5->handover_issued = true;
0182
0183 return IRQ_HANDLED;
0184 }
0185
0186 static irqreturn_t q6v5_stop_interrupt(int irq, void *data)
0187 {
0188 struct qcom_q6v5 *q6v5 = data;
0189
0190 complete(&q6v5->stop_done);
0191
0192 return IRQ_HANDLED;
0193 }
0194
0195
0196
0197
0198
0199
0200
0201
0202 int qcom_q6v5_request_stop(struct qcom_q6v5 *q6v5, struct qcom_sysmon *sysmon)
0203 {
0204 int ret;
0205
0206 q6v5->running = false;
0207
0208
0209 if (qcom_sysmon_shutdown_acked(sysmon))
0210 return 0;
0211
0212 qcom_smem_state_update_bits(q6v5->state,
0213 BIT(q6v5->stop_bit), BIT(q6v5->stop_bit));
0214
0215 ret = wait_for_completion_timeout(&q6v5->stop_done, 5 * HZ);
0216
0217 qcom_smem_state_update_bits(q6v5->state, BIT(q6v5->stop_bit), 0);
0218
0219 return ret == 0 ? -ETIMEDOUT : 0;
0220 }
0221 EXPORT_SYMBOL_GPL(qcom_q6v5_request_stop);
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232 unsigned long qcom_q6v5_panic(struct qcom_q6v5 *q6v5)
0233 {
0234 qcom_smem_state_update_bits(q6v5->state,
0235 BIT(q6v5->stop_bit), BIT(q6v5->stop_bit));
0236
0237 return Q6V5_PANIC_DELAY_MS;
0238 }
0239 EXPORT_SYMBOL_GPL(qcom_q6v5_panic);
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252 int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
0253 struct rproc *rproc, int crash_reason, const char *load_state,
0254 void (*handover)(struct qcom_q6v5 *q6v5))
0255 {
0256 int ret;
0257
0258 q6v5->rproc = rproc;
0259 q6v5->dev = &pdev->dev;
0260 q6v5->crash_reason = crash_reason;
0261 q6v5->handover = handover;
0262
0263 init_completion(&q6v5->start_done);
0264 init_completion(&q6v5->stop_done);
0265
0266 q6v5->wdog_irq = platform_get_irq_byname(pdev, "wdog");
0267 if (q6v5->wdog_irq < 0)
0268 return q6v5->wdog_irq;
0269
0270 ret = devm_request_threaded_irq(&pdev->dev, q6v5->wdog_irq,
0271 NULL, q6v5_wdog_interrupt,
0272 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
0273 "q6v5 wdog", q6v5);
0274 if (ret) {
0275 dev_err(&pdev->dev, "failed to acquire wdog IRQ\n");
0276 return ret;
0277 }
0278
0279 q6v5->fatal_irq = platform_get_irq_byname(pdev, "fatal");
0280 if (q6v5->fatal_irq < 0)
0281 return q6v5->fatal_irq;
0282
0283 ret = devm_request_threaded_irq(&pdev->dev, q6v5->fatal_irq,
0284 NULL, q6v5_fatal_interrupt,
0285 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
0286 "q6v5 fatal", q6v5);
0287 if (ret) {
0288 dev_err(&pdev->dev, "failed to acquire fatal IRQ\n");
0289 return ret;
0290 }
0291
0292 q6v5->ready_irq = platform_get_irq_byname(pdev, "ready");
0293 if (q6v5->ready_irq < 0)
0294 return q6v5->ready_irq;
0295
0296 ret = devm_request_threaded_irq(&pdev->dev, q6v5->ready_irq,
0297 NULL, q6v5_ready_interrupt,
0298 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
0299 "q6v5 ready", q6v5);
0300 if (ret) {
0301 dev_err(&pdev->dev, "failed to acquire ready IRQ\n");
0302 return ret;
0303 }
0304
0305 q6v5->handover_irq = platform_get_irq_byname(pdev, "handover");
0306 if (q6v5->handover_irq < 0)
0307 return q6v5->handover_irq;
0308
0309 ret = devm_request_threaded_irq(&pdev->dev, q6v5->handover_irq,
0310 NULL, q6v5_handover_interrupt,
0311 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
0312 "q6v5 handover", q6v5);
0313 if (ret) {
0314 dev_err(&pdev->dev, "failed to acquire handover IRQ\n");
0315 return ret;
0316 }
0317 disable_irq(q6v5->handover_irq);
0318
0319 q6v5->stop_irq = platform_get_irq_byname(pdev, "stop-ack");
0320 if (q6v5->stop_irq < 0)
0321 return q6v5->stop_irq;
0322
0323 ret = devm_request_threaded_irq(&pdev->dev, q6v5->stop_irq,
0324 NULL, q6v5_stop_interrupt,
0325 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
0326 "q6v5 stop", q6v5);
0327 if (ret) {
0328 dev_err(&pdev->dev, "failed to acquire stop-ack IRQ\n");
0329 return ret;
0330 }
0331
0332 q6v5->state = devm_qcom_smem_state_get(&pdev->dev, "stop", &q6v5->stop_bit);
0333 if (IS_ERR(q6v5->state)) {
0334 dev_err(&pdev->dev, "failed to acquire stop state\n");
0335 return PTR_ERR(q6v5->state);
0336 }
0337
0338 q6v5->load_state = devm_kstrdup_const(&pdev->dev, load_state, GFP_KERNEL);
0339 q6v5->qmp = qmp_get(&pdev->dev);
0340 if (IS_ERR(q6v5->qmp)) {
0341 if (PTR_ERR(q6v5->qmp) != -ENODEV)
0342 return dev_err_probe(&pdev->dev, PTR_ERR(q6v5->qmp),
0343 "failed to acquire load state\n");
0344 q6v5->qmp = NULL;
0345 } else if (!q6v5->load_state) {
0346 if (!load_state)
0347 dev_err(&pdev->dev, "load state resource string empty\n");
0348
0349 qmp_put(q6v5->qmp);
0350 return load_state ? -ENOMEM : -EINVAL;
0351 }
0352
0353 q6v5->path = devm_of_icc_get(&pdev->dev, NULL);
0354 if (IS_ERR(q6v5->path))
0355 return dev_err_probe(&pdev->dev, PTR_ERR(q6v5->path),
0356 "failed to acquire interconnect path\n");
0357
0358 return 0;
0359 }
0360 EXPORT_SYMBOL_GPL(qcom_q6v5_init);
0361
0362
0363
0364
0365
0366 void qcom_q6v5_deinit(struct qcom_q6v5 *q6v5)
0367 {
0368 qmp_put(q6v5->qmp);
0369 }
0370 EXPORT_SYMBOL_GPL(qcom_q6v5_deinit);
0371
0372 MODULE_LICENSE("GPL v2");
0373 MODULE_DESCRIPTION("Qualcomm Peripheral Image Loader for Q6V5");