Commit d6ed7503 authored by Lukasz Stepnicki's avatar Lukasz Stepnicki Committed by Anas Nashif
Browse files

modules: hal_nordic: dvfs: added callback when scaling done



User can assign callback function to local domain dvfs handler
and get notification when scaling process is finished for
particular domain.
Reworked usage of DVFS_SERV_HDL_FREQ_CHANGE_IN_PROGRESS_BIT_POS
which was not initialized properly.

Signed-off-by: default avatarLukasz Stepnicki <lukasz.stepnicki@nordicsemi.no>
parent 0fbcf622
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -26,6 +26,11 @@ config NRFS_LOCAL_DOMAIN_DOWNSCALE_SAFETY_TIMEOUT_US
	default 1000000 if (NRFS_LOCAL_DOMAIN_DVFS_TEST || LOG)
	default 1500

config NRFS_LOCAL_DOMAIN_DOWNSCALE_FINISH_DELAY_TIMEOUT_US
	int "Additional delay to let secdom finish dowscale procedure in us"
	range 1 10000000
	default 1000

config NRFS_LOCAL_DOMAIN_DVFS_HANDLER_TASK_STACK_SIZE
	int "Stack size used for DVFS handling task"
	range 256 2048
+72 −12
Original line number Diff line number Diff line
@@ -19,10 +19,12 @@ static K_SEM_DEFINE(dvfs_service_sync_sem, 0, 1);
static K_SEM_DEFINE(dvfs_service_idle_sem, 0, 1);

#define DVFS_SERV_HDL_INIT_DONE_BIT_POS (0)
#define DVFS_SERV_HDL_FREQ_CHANGE_IN_PROGRESS_BIT_POS (1)
#define DVFS_SERV_HDL_FREQ_CHANGE_REQ_PENDING_BIT_POS (1)

static atomic_t dvfs_service_handler_state_bits;
static enum dvfs_frequency_setting current_freq_setting;
static volatile enum dvfs_frequency_setting current_freq_setting;
static volatile enum dvfs_frequency_setting requested_freq_setting;
static dvfs_service_handler_callback dvfs_frequency_change_applied_clb;

static void dvfs_service_handler_set_state_bit(uint32_t bit_pos)
{
@@ -44,9 +46,9 @@ static bool dvfs_service_handler_init_done(void)
	return dvfs_service_handler_get_state_bit(DVFS_SERV_HDL_INIT_DONE_BIT_POS);
}

static bool dvfs_service_handler_freq_change_in_progress(void)
static bool dvfs_service_handler_freq_change_req_pending(void)
{
	return dvfs_service_handler_get_state_bit(DVFS_SERV_HDL_FREQ_CHANGE_IN_PROGRESS_BIT_POS);
	return dvfs_service_handler_get_state_bit(DVFS_SERV_HDL_FREQ_CHANGE_REQ_PENDING_BIT_POS);
}

static void dvfs_service_handler_nrfs_error_check(nrfs_err_t err)
@@ -87,6 +89,12 @@ static enum dvfs_frequency_setting dvfs_service_handler_get_current_oppoint(void
	return current_freq_setting;
}

static enum dvfs_frequency_setting dvfs_service_handler_get_requested_oppoint(void)
{
	LOG_DBG("Requested LD freq setting: %d", requested_freq_setting);
	return requested_freq_setting;
}

/* Function to check if current operation is down-scaling */
static bool dvfs_service_handler_is_downscaling(enum dvfs_frequency_setting target_freq_setting)
{
@@ -143,7 +151,12 @@ static void dvfs_service_handler_scaling_finish(enum dvfs_frequency_setting oppo
			dvfs_service_handler_error(err);
		}
	}
	dvfs_service_handler_clear_state_bit(DVFS_SERV_HDL_FREQ_CHANGE_REQ_PENDING_BIT_POS);
	current_freq_setting = oppoint_freq;
	LOG_DBG("Current LD freq setting: %d", current_freq_setting);
	if (dvfs_frequency_change_applied_clb) {
		dvfs_frequency_change_applied_clb(current_freq_setting);
	}
}

/* Function to set hsfll to highest frequency when switched to ABB. */
@@ -152,11 +165,29 @@ static void dvfs_service_handler_set_initial_hsfll_config(void)
	int32_t err = ld_dvfs_configure_hsfll(DVFS_FREQ_HIGH);

	current_freq_setting = DVFS_FREQ_HIGH;
	requested_freq_setting = DVFS_FREQ_HIGH;
	if (err != 0) {
		dvfs_service_handler_error(err);
	}
}

/* Timer to add additional delay to finish downscale procedure when domain other than secure */
#if !defined(NRF_SECURE)
#define SCALING_FINISH_DELAY_TIMEOUT_US                                                            \
	K_USEC(CONFIG_NRFS_LOCAL_DOMAIN_DOWNSCALE_FINISH_DELAY_TIMEOUT_US)

static void dvfs_service_handler_scaling_finish_delay_timeout(struct k_timer *timer)
{
	if (timer) {
		dvfs_service_handler_scaling_finish(
			*(enum dvfs_frequency_setting *)timer->user_data);
	}
}

K_TIMER_DEFINE(dvfs_service_scaling_finish_delay_timer,
	       dvfs_service_handler_scaling_finish_delay_timeout, NULL);
#endif

/* DVFS event handler callback function.*/
static void nrfs_dvfs_evt_handler(nrfs_dvfs_evt_t const *p_evt, void *context)
{
@@ -182,7 +213,13 @@ static void nrfs_dvfs_evt_handler(nrfs_dvfs_evt_t const *p_evt, void *context)
		break;
	case NRFS_DVFS_EVT_OPPOINT_REQ_CONFIRMED:
		/* Optional confirmation from sysctrl, wait for oppoint.*/
		LOG_DBG("DVFS handler EVT_OPPOINT_REQ_CONFIRMED");
		dvfs_service_handler_clear_state_bit(DVFS_SERV_HDL_FREQ_CHANGE_REQ_PENDING_BIT_POS);
		LOG_DBG("DVFS handler EVT_OPPOINT_REQ_CONFIRMED %d", (uint32_t)p_evt->freq);
		if (dvfs_service_handler_get_requested_oppoint() == p_evt->freq) {
			if (dvfs_frequency_change_applied_clb) {
				dvfs_frequency_change_applied_clb(p_evt->freq);
			}
		}
		break;
	case NRFS_DVFS_EVT_OPPOINT_SCALING_PREPARE:
		/*Target oppoint will be received here.*/
@@ -196,7 +233,13 @@ static void nrfs_dvfs_evt_handler(nrfs_dvfs_evt_t const *p_evt, void *context)
			dvfs_service_handler_scaling_background_job(p_evt->freq);
			LOG_DBG("DVFS handler EVT_OPPOINT_SCALING_PREPARE handled");
#if !defined(NRF_SECURE)
			current_freq_setting = p_evt->freq;
			/* Additional delay for downscale to finish on secdom side */
			static enum dvfs_frequency_setting freq;

			freq = p_evt->freq;
			dvfs_service_scaling_finish_delay_timer.user_data = (void *)&freq;
			k_timer_start(&dvfs_service_scaling_finish_delay_timer,
				      SCALING_FINISH_DELAY_TIMEOUT_US, K_NO_WAIT);
		} else {
			LOG_ERR("DVFS handler - unexpected EVT_OPPOINT_SCALING_PREPARE");
		}
@@ -204,7 +247,6 @@ static void nrfs_dvfs_evt_handler(nrfs_dvfs_evt_t const *p_evt, void *context)
		break;
	case NRFS_DVFS_EVT_OPPOINT_SCALING_DONE:
		LOG_DBG("DVFS handler EVT_OPPOINT_SCALING_DONE");
		dvfs_service_handler_clear_state_bit(DVFS_SERV_HDL_FREQ_CHANGE_IN_PROGRESS_BIT_POS);
		dvfs_service_handler_scaling_finish(p_evt->freq);
		LOG_DBG("DVFS handler EVT_OPPOINT_SCALING_DONE handled");
		break;
@@ -275,18 +317,36 @@ int32_t dvfs_service_handler_change_freq_setting(enum dvfs_frequency_setting fre
		return -EAGAIN;
	}

	if (dvfs_service_handler_freq_change_in_progress()) {
		LOG_DBG("Frequency change in progress.");
		return -EBUSY;
	}

	if (!dvfs_service_handler_freq_setting_allowed(freq_setting)) {
		LOG_ERR("Requested frequency setting %d not supported.", freq_setting);
		return -ENXIO;
	}

	if (dvfs_service_handler_freq_change_req_pending()) {
		LOG_DBG("Frequency change request pending.");
		return -EBUSY;
	}

	dvfs_service_handler_set_state_bit(DVFS_SERV_HDL_FREQ_CHANGE_REQ_PENDING_BIT_POS);
	requested_freq_setting = freq_setting;

	nrfs_err_t status = nrfs_dvfs_oppoint_request(freq_setting, get_next_context());

	if (status != NRFS_SUCCESS) {
		dvfs_service_handler_clear_state_bit(DVFS_SERV_HDL_FREQ_CHANGE_REQ_PENDING_BIT_POS);
	}

	dvfs_service_handler_nrfs_error_check(status);

	return status;
}

void dvfs_service_handler_register_freq_setting_applied_callback(dvfs_service_handler_callback clb)
{
	if (clb) {
		LOG_DBG("Registered frequency applied callback");
		dvfs_frequency_change_applied_clb = clb;
	} else {
		LOG_ERR("Invalid callback function provided!");
	}
}
+15 −1
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@ extern "C" {
 * @brief Function to request LD frequency change.
 *
 * @param frequency requested frequency setting from enum dvfs_frequency_setting.
 * @return EBUSY                  Frequency change in progress.
 * @return EBUSY                  Frequency change request pending.
 * @return EAGAIN                 DVFS init in progress.
 * @return ENXIO                  Not supported frequency settings.
 * @return NRFS_SUCCESS           Request sent successfully.
@@ -26,6 +26,20 @@ extern "C" {
 */
int32_t dvfs_service_handler_change_freq_setting(enum dvfs_frequency_setting freq_setting);

/**
 * @brief Type to use as callback function in dvfs service
 *
 * @param new_setting applied frequency setting
 */
typedef void (*dvfs_service_handler_callback)(enum dvfs_frequency_setting new_setting);

/**
 * @brief Register callback function which will be called when new dvfs frequency is applied.
 *
 * @param clb dvfs_service_handler_callback to register
 */
void dvfs_service_handler_register_freq_setting_applied_callback(dvfs_service_handler_callback clb);

#ifdef __cplusplus
}
#endif