Lines Matching +full:tcs +full:- +full:wait
1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
21 #include <soc/qcom/cmd-db.h>
22 #include <soc/qcom/tcs.h>
23 #include <dt-bindings/soc/qcom,rpmh-rsc.h>
25 #include "rpmh-internal.h"
28 #include "trace-rpmh.h"
57 /* TCS CMD register bit mask */
66 return readl_relaxed(drv->tcs_base + reg + RSC_DRV_TCS_OFFSET * tcs_id + in read_tcs_reg()
73 writel_relaxed(data, drv->tcs_base + reg + RSC_DRV_TCS_OFFSET * tcs_id + in write_tcs_cmd()
79 writel_relaxed(data, drv->tcs_base + reg + RSC_DRV_TCS_OFFSET * tcs_id); in write_tcs_reg()
85 writel(data, drv->tcs_base + reg + RSC_DRV_TCS_OFFSET * tcs_id); in write_tcs_reg_sync()
87 if (data == readl(drv->tcs_base + reg + in write_tcs_reg_sync()
96 return !test_bit(tcs_id, drv->tcs_in_use) && in tcs_is_free()
102 return &drv->tcs[type]; in get_tcs_of_type()
108 struct tcs_group *tcs; in tcs_invalidate() local
110 tcs = get_tcs_of_type(drv, type); in tcs_invalidate()
112 spin_lock(&tcs->lock); in tcs_invalidate()
113 if (bitmap_empty(tcs->slots, MAX_TCS_SLOTS)) { in tcs_invalidate()
114 spin_unlock(&tcs->lock); in tcs_invalidate()
118 for (m = tcs->offset; m < tcs->offset + tcs->num_tcs; m++) { in tcs_invalidate()
120 spin_unlock(&tcs->lock); in tcs_invalidate()
121 return -EAGAIN; in tcs_invalidate()
126 bitmap_zero(tcs->slots, MAX_TCS_SLOTS); in tcs_invalidate()
127 spin_unlock(&tcs->lock); in tcs_invalidate()
133 * rpmh_rsc_invalidate - Invalidate sleep and wake TCSes
152 struct tcs_group *tcs; in get_tcs_for_msg() local
154 switch (msg->state) { in get_tcs_for_msg()
165 return ERR_PTR(-EINVAL); in get_tcs_for_msg()
170 * dedicated TCS for active state use, then re-purpose a wake TCS to in get_tcs_for_msg()
173 tcs = get_tcs_of_type(drv, type); in get_tcs_for_msg()
174 if (msg->state == RPMH_ACTIVE_ONLY_STATE && !tcs->num_tcs) in get_tcs_for_msg()
175 tcs = get_tcs_of_type(drv, WAKE_TCS); in get_tcs_for_msg()
177 return tcs; in get_tcs_for_msg()
183 struct tcs_group *tcs; in get_req_from_tcs() local
187 tcs = &drv->tcs[i]; in get_req_from_tcs()
188 if (tcs->mask & BIT(tcs_id)) in get_req_from_tcs()
189 return tcs->req[tcs_id - tcs->offset]; in get_req_from_tcs()
200 * HW req: Clear the DRV_CONTROL and enable TCS again in __tcs_set_trigger()
211 /* Enable the AMC mode on the TCS and then trigger the TCS */ in __tcs_set_trigger()
252 for (j = 0; j < req->num_cmds; j++) { in tcs_tx_done()
255 cmd = &req->cmds[j]; in tcs_tx_done()
258 ((req->wait_for_compl || cmd->wait) && in tcs_tx_done()
261 drv->name, cmd->addr, cmd->data); in tcs_tx_done()
262 err = -EIO; in tcs_tx_done()
269 * If wake tcs was re-purposed for sending active in tcs_tx_done()
271 * disable interrupt for this TCS in tcs_tx_done()
273 if (!drv->tcs[ACTIVE_TCS].num_tcs) in tcs_tx_done()
276 /* Reclaim the TCS */ in tcs_tx_done()
280 spin_lock(&drv->lock); in tcs_tx_done()
281 clear_bit(i, drv->tcs_in_use); in tcs_tx_done()
283 * Disable interrupt for WAKE TCS to avoid being in tcs_tx_done()
287 if (!drv->tcs[ACTIVE_TCS].num_tcs) in tcs_tx_done()
289 spin_unlock(&drv->lock); in tcs_tx_done()
307 cmd_msgid |= msg->wait_for_compl ? CMD_MSGID_RESP_REQ : 0; in __tcs_buffer_write()
312 for (i = 0, j = cmd_id; i < msg->num_cmds; i++, j++) { in __tcs_buffer_write()
313 cmd = &msg->cmds[i]; in __tcs_buffer_write()
315 cmd_complete |= cmd->wait << j; in __tcs_buffer_write()
317 msgid |= cmd->wait ? CMD_MSGID_RESP_REQ : 0; in __tcs_buffer_write()
320 write_tcs_cmd(drv, RSC_DRV_CMD_ADDR, tcs_id, j, cmd->addr); in __tcs_buffer_write()
321 write_tcs_cmd(drv, RSC_DRV_CMD_DATA, tcs_id, j, cmd->data); in __tcs_buffer_write()
330 static int check_for_req_inflight(struct rsc_drv *drv, struct tcs_group *tcs, in check_for_req_inflight() argument
336 int tcs_id = tcs->offset; in check_for_req_inflight()
338 for (i = 0; i < tcs->num_tcs; i++, tcs_id++) { in check_for_req_inflight()
346 for (k = 0; k < msg->num_cmds; k++) { in check_for_req_inflight()
347 if (addr == msg->cmds[k].addr) in check_for_req_inflight()
348 return -EBUSY; in check_for_req_inflight()
356 static int find_free_tcs(struct tcs_group *tcs) in find_free_tcs() argument
360 for (i = 0; i < tcs->num_tcs; i++) { in find_free_tcs()
361 if (tcs_is_free(tcs->drv, tcs->offset + i)) in find_free_tcs()
362 return tcs->offset + i; in find_free_tcs()
365 return -EBUSY; in find_free_tcs()
370 struct tcs_group *tcs; in tcs_write() local
375 tcs = get_tcs_for_msg(drv, msg); in tcs_write()
376 if (IS_ERR(tcs)) in tcs_write()
377 return PTR_ERR(tcs); in tcs_write()
379 spin_lock_irqsave(&tcs->lock, flags); in tcs_write()
380 spin_lock(&drv->lock); in tcs_write()
383 * when one is already in-flight or being processed. in tcs_write()
385 ret = check_for_req_inflight(drv, tcs, msg); in tcs_write()
387 spin_unlock(&drv->lock); in tcs_write()
391 tcs_id = find_free_tcs(tcs); in tcs_write()
394 spin_unlock(&drv->lock); in tcs_write()
398 tcs->req[tcs_id - tcs->offset] = msg; in tcs_write()
399 set_bit(tcs_id, drv->tcs_in_use); in tcs_write()
400 if (msg->state == RPMH_ACTIVE_ONLY_STATE && tcs->type != ACTIVE_TCS) { in tcs_write()
403 * repurposed TCS to avoid triggering them. tcs->slots will be in tcs_write()
410 spin_unlock(&drv->lock); in tcs_write()
416 spin_unlock_irqrestore(&tcs->lock, flags); in tcs_write()
422 * appropriate TCS block.
427 * Return: 0 on success, -EINVAL on error.
428 * Note: This call blocks until a valid data is written to the TCS.
434 if (!msg || !msg->cmds || !msg->num_cmds || in rpmh_rsc_send_data()
435 msg->num_cmds > MAX_RPMH_PAYLOAD) { in rpmh_rsc_send_data()
437 return -EINVAL; in rpmh_rsc_send_data()
442 if (ret == -EBUSY) { in rpmh_rsc_send_data()
443 pr_info_ratelimited("TCS Busy, retrying RPMH message send: addr=%#x\n", in rpmh_rsc_send_data()
444 msg->cmds[0].addr); in rpmh_rsc_send_data()
447 } while (ret == -EBUSY); in rpmh_rsc_send_data()
452 static int find_match(const struct tcs_group *tcs, const struct tcs_cmd *cmd, in find_match() argument
458 for_each_set_bit(i, tcs->slots, MAX_TCS_SLOTS) { in find_match()
459 if (tcs->cmd_cache[i] != cmd[0].addr) in find_match()
461 if (i + len >= tcs->num_tcs * tcs->ncpt) in find_match()
464 if (tcs->cmd_cache[i + j] != cmd[j].addr) in find_match()
470 return -ENODATA; in find_match()
474 return -EINVAL; in find_match()
477 static int find_slots(struct tcs_group *tcs, const struct tcs_request *msg, in find_slots() argument
483 /* Find if we already have the msg in our TCS */ in find_slots()
484 slot = find_match(tcs, msg->cmds, msg->num_cmds); in find_slots()
488 /* Do over, until we can fit the full payload in a TCS */ in find_slots()
490 slot = bitmap_find_next_zero_area(tcs->slots, MAX_TCS_SLOTS, in find_slots()
491 i, msg->num_cmds, 0); in find_slots()
492 if (slot == tcs->num_tcs * tcs->ncpt) in find_slots()
493 return -ENOMEM; in find_slots()
494 i += tcs->ncpt; in find_slots()
495 } while (slot + msg->num_cmds - 1 >= i); in find_slots()
498 bitmap_set(tcs->slots, slot, msg->num_cmds); in find_slots()
500 for (i = 0; i < msg->num_cmds; i++) in find_slots()
501 tcs->cmd_cache[slot + i] = msg->cmds[i].addr; in find_slots()
503 offset = slot / tcs->ncpt; in find_slots()
504 *tcs_id = offset + tcs->offset; in find_slots()
505 *cmd_id = slot % tcs->ncpt; in find_slots()
512 struct tcs_group *tcs; in tcs_ctrl_write() local
517 tcs = get_tcs_for_msg(drv, msg); in tcs_ctrl_write()
518 if (IS_ERR(tcs)) in tcs_ctrl_write()
519 return PTR_ERR(tcs); in tcs_ctrl_write()
521 spin_lock_irqsave(&tcs->lock, flags); in tcs_ctrl_write()
522 /* find the TCS id and the command in the TCS to write to */ in tcs_ctrl_write()
523 ret = find_slots(tcs, msg, &tcs_id, &cmd_id); in tcs_ctrl_write()
526 spin_unlock_irqrestore(&tcs->lock, flags); in tcs_ctrl_write()
541 if (!msg || !msg->cmds || !msg->num_cmds || in rpmh_rsc_write_ctrl_data()
542 msg->num_cmds > MAX_RPMH_PAYLOAD) { in rpmh_rsc_write_ctrl_data()
544 return -EINVAL; in rpmh_rsc_write_ctrl_data()
548 if (msg->state == RPMH_ACTIVE_ONLY_STATE) in rpmh_rsc_write_ctrl_data()
549 return -EINVAL; in rpmh_rsc_write_ctrl_data()
561 struct device_node *dn = pdev->dev.of_node; in rpmh_probe_tcs_config()
564 struct tcs_group *tcs; in rpmh_probe_tcs_config() local
569 snprintf(drv_id, ARRAY_SIZE(drv_id), "drv-%d", drv->id); in rpmh_probe_tcs_config()
571 base = devm_ioremap_resource(&pdev->dev, res); in rpmh_probe_tcs_config()
575 ret = of_property_read_u32(dn, "qcom,tcs-offset", &offset); in rpmh_probe_tcs_config()
578 drv->tcs_base = base + offset; in rpmh_probe_tcs_config()
583 max_tcs &= DRV_NUM_TCS_MASK << (DRV_NUM_TCS_SHIFT * drv->id); in rpmh_probe_tcs_config()
584 max_tcs = max_tcs >> (DRV_NUM_TCS_SHIFT * drv->id); in rpmh_probe_tcs_config()
589 n = of_property_count_u32_elems(dn, "qcom,tcs-config"); in rpmh_probe_tcs_config()
591 return -EINVAL; in rpmh_probe_tcs_config()
594 ret = of_property_read_u32_index(dn, "qcom,tcs-config", in rpmh_probe_tcs_config()
599 return -EINVAL; in rpmh_probe_tcs_config()
601 ret = of_property_read_u32_index(dn, "qcom,tcs-config", in rpmh_probe_tcs_config()
606 return -EINVAL; in rpmh_probe_tcs_config()
610 tcs = &drv->tcs[tcs_cfg[i].type]; in rpmh_probe_tcs_config()
611 if (tcs->drv) in rpmh_probe_tcs_config()
612 return -EINVAL; in rpmh_probe_tcs_config()
613 tcs->drv = drv; in rpmh_probe_tcs_config()
614 tcs->type = tcs_cfg[i].type; in rpmh_probe_tcs_config()
615 tcs->num_tcs = tcs_cfg[i].n; in rpmh_probe_tcs_config()
616 tcs->ncpt = ncpt; in rpmh_probe_tcs_config()
617 spin_lock_init(&tcs->lock); in rpmh_probe_tcs_config()
619 if (!tcs->num_tcs || tcs->type == CONTROL_TCS) in rpmh_probe_tcs_config()
622 if (st + tcs->num_tcs > max_tcs || in rpmh_probe_tcs_config()
623 st + tcs->num_tcs >= BITS_PER_BYTE * sizeof(tcs->mask)) in rpmh_probe_tcs_config()
624 return -EINVAL; in rpmh_probe_tcs_config()
626 tcs->mask = ((1 << tcs->num_tcs) - 1) << st; in rpmh_probe_tcs_config()
627 tcs->offset = st; in rpmh_probe_tcs_config()
628 st += tcs->num_tcs; in rpmh_probe_tcs_config()
632 * avoid reading TCS register memory. in rpmh_probe_tcs_config()
634 if (tcs->type == ACTIVE_TCS) in rpmh_probe_tcs_config()
637 tcs->cmd_cache = devm_kcalloc(&pdev->dev, in rpmh_probe_tcs_config()
638 tcs->num_tcs * ncpt, sizeof(u32), in rpmh_probe_tcs_config()
640 if (!tcs->cmd_cache) in rpmh_probe_tcs_config()
641 return -ENOMEM; in rpmh_probe_tcs_config()
644 drv->num_tcs = st; in rpmh_probe_tcs_config()
651 struct device_node *dn = pdev->dev.of_node; in rpmh_rsc_probe()
656 * Even though RPMh doesn't directly use cmd-db, all of its children in rpmh_rsc_probe()
661 if (ret != -EPROBE_DEFER) in rpmh_rsc_probe()
662 dev_err(&pdev->dev, "Command DB not available (%d)\n", in rpmh_rsc_probe()
667 drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); in rpmh_rsc_probe()
669 return -ENOMEM; in rpmh_rsc_probe()
671 ret = of_property_read_u32(dn, "qcom,drv-id", &drv->id); in rpmh_rsc_probe()
675 drv->name = of_get_property(dn, "label", NULL); in rpmh_rsc_probe()
676 if (!drv->name) in rpmh_rsc_probe()
677 drv->name = dev_name(&pdev->dev); in rpmh_rsc_probe()
683 spin_lock_init(&drv->lock); in rpmh_rsc_probe()
684 bitmap_zero(drv->tcs_in_use, MAX_TCS_NR); in rpmh_rsc_probe()
686 irq = platform_get_irq(pdev, drv->id); in rpmh_rsc_probe()
690 ret = devm_request_irq(&pdev->dev, irq, tcs_tx_done, in rpmh_rsc_probe()
692 drv->name, drv); in rpmh_rsc_probe()
696 /* Enable the active TCS to send requests immediately */ in rpmh_rsc_probe()
697 write_tcs_reg(drv, RSC_DRV_IRQ_ENABLE, 0, drv->tcs[ACTIVE_TCS].mask); in rpmh_rsc_probe()
699 spin_lock_init(&drv->client.cache_lock); in rpmh_rsc_probe()
700 INIT_LIST_HEAD(&drv->client.cache); in rpmh_rsc_probe()
701 INIT_LIST_HEAD(&drv->client.batch_cache); in rpmh_rsc_probe()
703 dev_set_drvdata(&pdev->dev, drv); in rpmh_rsc_probe()
705 return devm_of_platform_populate(&pdev->dev); in rpmh_rsc_probe()
709 { .compatible = "qcom,rpmh-rsc", },