^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2011-2017, The Linux Foundation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include "slimbus.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * slim_ctrl_clk_pause() - Called by slimbus controller to enter/exit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * 'clock pause'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * @ctrl: controller requesting bus to be paused or woken up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * @wakeup: Wakeup this controller from clock pause.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * @restart: Restart time value per spec used for clock pause. This value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * isn't used when controller is to be woken up.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * Slimbus specification needs this sequence to turn-off clocks for the bus.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * The sequence involves sending 3 broadcast messages (reconfiguration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * sequence) to inform all devices on the bus.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * To exit clock-pause, controller typically wakes up active framer device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * This API executes clock pause reconfiguration sequence if wakeup is false.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * If wakeup is true, controller's wakeup is called.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * For entering clock-pause, -EBUSY is returned if a message txn in pending.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) int slim_ctrl_clk_pause(struct slim_controller *ctrl, bool wakeup, u8 restart)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) int i, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct slim_sched *sched = &ctrl->sched;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct slim_val_inf msg = {0, 0, NULL, NULL};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) DEFINE_SLIM_BCAST_TXN(txn, SLIM_MSG_MC_BEGIN_RECONFIGURATION,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) 3, SLIM_LA_MANAGER, &msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) if (wakeup == false && restart > SLIM_CLK_UNSPECIFIED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) mutex_lock(&sched->m_reconf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) if (wakeup) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) if (sched->clk_state == SLIM_CLK_ACTIVE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) mutex_unlock(&sched->m_reconf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * Fine-tune calculation based on clock gear,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * message-bandwidth after bandwidth management
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) ret = wait_for_completion_timeout(&sched->pause_comp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) msecs_to_jiffies(100));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) if (!ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) mutex_unlock(&sched->m_reconf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) pr_err("Previous clock pause did not finish");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * Slimbus framework will call controller wakeup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * Controller should make sure that it sets active framer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * out of clock pause
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (sched->clk_state == SLIM_CLK_PAUSED && ctrl->wakeup)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) ret = ctrl->wakeup(ctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) sched->clk_state = SLIM_CLK_ACTIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) mutex_unlock(&sched->m_reconf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) /* already paused */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) if (ctrl->sched.clk_state == SLIM_CLK_PAUSED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) mutex_unlock(&sched->m_reconf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) spin_lock_irqsave(&ctrl->txn_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) for (i = 0; i < SLIM_MAX_TIDS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) /* Pending response for a message */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (idr_find(&ctrl->tid_idr, i)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) spin_unlock_irqrestore(&ctrl->txn_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) mutex_unlock(&sched->m_reconf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) spin_unlock_irqrestore(&ctrl->txn_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) sched->clk_state = SLIM_CLK_ENTERING_PAUSE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) /* clock pause sequence */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) ret = slim_do_transfer(ctrl, &txn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) goto clk_pause_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) txn.mc = SLIM_MSG_MC_NEXT_PAUSE_CLOCK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) txn.rl = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) msg.num_bytes = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) msg.wbuf = &restart;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) ret = slim_do_transfer(ctrl, &txn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) goto clk_pause_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) txn.mc = SLIM_MSG_MC_RECONFIGURE_NOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) txn.rl = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) msg.num_bytes = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) msg.wbuf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) ret = slim_do_transfer(ctrl, &txn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) clk_pause_ret:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) sched->clk_state = SLIM_CLK_ACTIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) sched->clk_state = SLIM_CLK_PAUSED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) complete(&sched->pause_comp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) mutex_unlock(&sched->m_reconf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) EXPORT_SYMBOL_GPL(slim_ctrl_clk_pause);