brintos

brintos / linux-shallow public Read only

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