Merge "msm: camera: utils: Add camera clk wrapper infrastructure" into camera-kernel.lnx.5.0

This commit is contained in:
Haritha Chintalapati
2021-05-05 22:06:15 -07:00
committato da Gerrit - the friendly Code Review server
8 ha cambiato i file con 607 aggiunte e 108 eliminazioni

Vedi File

@@ -76,8 +76,7 @@ static int cam_csid_ppi_enable_hw(struct cam_csid_ppi_hw *ppi_hw)
}
for (i = 0; i < soc_info->num_clk; i++) {
rc = cam_soc_util_clk_enable(soc_info->clk[i],
soc_info->clk_name[i], 0, NULL);
rc = cam_soc_util_clk_enable(soc_info, false, i, -1, NULL);
if (rc)
goto clk_disable;
}
@@ -107,8 +106,7 @@ static int cam_csid_ppi_enable_hw(struct cam_csid_ppi_hw *ppi_hw)
return 0;
clk_disable:
for (--i; i >= 0; i--)
cam_soc_util_clk_disable(soc_info->clk[i],
soc_info->clk_name[i]);
cam_soc_util_clk_disable(soc_info, false, i);
ppi_hw->hw_info->open_count--;
return rc;
}
@@ -154,8 +152,7 @@ static int cam_csid_ppi_disable_hw(struct cam_csid_ppi_hw *ppi_hw)
ppi_hw->device_enabled = 0;
for (i = 0; i < soc_info->num_clk; i++)
cam_soc_util_clk_disable(soc_info->clk[i],
soc_info->clk_name[i]);
cam_soc_util_clk_disable(soc_info, false, i);
return rc;
}

Vedi File

@@ -64,9 +64,8 @@ int cam_tfe_init_soc_resources(struct cam_hw_soc_info *soc_info,
clk_option:
rc = cam_soc_util_get_option_clk_by_name(soc_info,
CAM_TFE_DSP_CLK_NAME, &soc_private->dsp_clk,
&soc_private->dsp_clk_index, &soc_private->dsp_clk_rate);
rc = cam_soc_util_get_option_clk_by_name(soc_info, CAM_TFE_DSP_CLK_NAME,
&soc_private->dsp_clk_index);
if (rc)
CAM_WARN(CAM_ISP, "Option clk get failed with rc %d", rc);
@@ -129,10 +128,13 @@ int cam_tfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info)
"Error! Release platform resource failed rc=%d", rc);
rc = cam_soc_util_clk_put(&soc_private->dsp_clk);
if (rc < 0)
CAM_ERR(CAM_ISP,
"Error Put dsp clk failed rc=%d", rc);
if (soc_private->dsp_clk_index != -1) {
rc = cam_soc_util_put_optional_clk(soc_info,
soc_private->dsp_clk_index);
if (rc)
CAM_ERR(CAM_ISP,
"Error Put dsp clk failed rc=%d", rc);
}
kfree(soc_private);
@@ -198,8 +200,8 @@ int cam_tfe_soc_enable_clk(struct cam_hw_soc_info *soc_info,
soc_private = soc_info->soc_private;
if (strcmp(clk_name, CAM_TFE_DSP_CLK_NAME) == 0) {
rc = cam_soc_util_clk_enable(soc_private->dsp_clk,
CAM_TFE_DSP_CLK_NAME, soc_private->dsp_clk_rate, NULL);
rc = cam_soc_util_clk_enable(soc_info, true,
soc_private->dsp_clk_index, 0, NULL);
if (rc)
CAM_ERR(CAM_ISP,
"Error enable dsp clk failed rc=%d", rc);
@@ -222,8 +224,8 @@ int cam_tfe_soc_disable_clk(struct cam_hw_soc_info *soc_info,
soc_private = soc_info->soc_private;
if (strcmp(clk_name, CAM_TFE_DSP_CLK_NAME) == 0) {
rc = cam_soc_util_clk_disable(soc_private->dsp_clk,
CAM_TFE_DSP_CLK_NAME);
rc = cam_soc_util_clk_disable(soc_info, true,
soc_private->dsp_clk_index);
if (rc)
CAM_ERR(CAM_ISP,
"Error enable dsp clk failed rc=%d", rc);

Vedi File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
*/
#ifndef _CAM_TFE_SOC_H_
@@ -26,15 +26,14 @@ enum cam_cpas_handle_id {
* This handle is used for all further interface
* with CPAS.
* @cpas_version: Has cpas version read from Hardware
* @dsp_clk_index: DSP clk index in optional clocks
* @num_pid: number of pids of tfe
* @pid: TFE pid value list
*/
struct cam_tfe_soc_private {
uint32_t cpas_handle;
uint32_t cpas_version;
struct clk *dsp_clk;
int32_t dsp_clk_index;
int32_t dsp_clk_rate;
uint32_t num_pid;
uint32_t pid[CAM_ISP_HW_MAX_PID_VAL];
};

Vedi File

@@ -158,9 +158,8 @@ int cam_vfe_init_soc_resources(struct cam_hw_soc_info *soc_info,
goto free_soc_private;
}
rc = cam_soc_util_get_option_clk_by_name(soc_info,
CAM_VFE_DSP_CLK_NAME, &soc_private->dsp_clk,
&soc_private->dsp_clk_index, &soc_private->dsp_clk_rate);
rc = cam_soc_util_get_option_clk_by_name(soc_info, CAM_VFE_DSP_CLK_NAME,
&soc_private->dsp_clk_index);
if (rc)
CAM_DBG(CAM_ISP, "Option clk get failed with rc %d", rc);
@@ -222,8 +221,9 @@ int cam_vfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info)
"Error! Release platform resources failed rc=%d", rc);
if (soc_private->dsp_clk_index != -1) {
rc = cam_soc_util_clk_put(&soc_private->dsp_clk);
if (rc < 0)
rc = cam_soc_util_put_optional_clk(soc_info,
soc_private->dsp_clk_index);
if (rc)
CAM_ERR(CAM_ISP,
"Error Put dsp clk failed rc=%d", rc);
}
@@ -306,8 +306,8 @@ int cam_vfe_soc_enable_clk(struct cam_hw_soc_info *soc_info,
goto end;
}
rc = cam_soc_util_clk_enable(soc_private->dsp_clk,
CAM_VFE_DSP_CLK_NAME, soc_private->dsp_clk_rate, NULL);
rc = cam_soc_util_clk_enable(soc_info, true,
soc_private->dsp_clk_index, 0, NULL);
if (rc)
CAM_ERR(CAM_ISP,
"Error enable dsp clk failed rc=%d", rc);
@@ -338,8 +338,8 @@ int cam_vfe_soc_disable_clk(struct cam_hw_soc_info *soc_info,
goto end;
}
rc = cam_soc_util_clk_disable(soc_private->dsp_clk,
CAM_VFE_DSP_CLK_NAME);
rc = cam_soc_util_clk_disable(soc_info, true,
soc_private->dsp_clk_index);
if (rc)
CAM_ERR(CAM_ISP,
"Error disable dsp clk failed rc=%d", rc);

Vedi File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
*/
#ifndef _CAM_VFE_SOC_H_
@@ -22,6 +22,7 @@
* This handle is used for all further interface
* with CPAS.
* @cpas_version: Has cpas version read from Hardware
* @dsp_clk_index: DSP clk index in optional clocks
* @ubwc_static_ctrl: UBWC static control configuration
* @is_ife_lite: Flag to indicate full vs lite IFE
* @ife_clk_src: IFE source clock
@@ -31,9 +32,7 @@
struct cam_vfe_soc_private {
uint32_t cpas_handle;
uint32_t cpas_version;
struct clk *dsp_clk;
int32_t dsp_clk_index;
int32_t dsp_clk_rate;
uint32_t ubwc_static_ctrl[UBWC_STATIC_CONFIG_MAX];
bool is_ife_lite;
uint64_t ife_clk_src;

Vedi File

@@ -2087,12 +2087,13 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl,
power_setting->config_val;
for (j = 0; j < soc_info->num_clk; j++) {
rc = cam_soc_util_clk_enable(soc_info->clk[j],
soc_info->clk_name[j],
soc_info->clk_rate[0][j],
NULL);
if (rc)
rc = cam_soc_util_clk_enable(soc_info, false,
i, 0, NULL);
if (rc) {
CAM_ERR(CAM_UTIL,
"Failed in clk enable %d", i);
break;
}
}
if (rc < 0) {
@@ -2212,8 +2213,7 @@ power_up_failed:
switch (power_setting->seq_type) {
case SENSOR_MCLK:
for (i = soc_info->num_clk - 1; i >= 0; i--) {
cam_soc_util_clk_disable(soc_info->clk[i],
soc_info->clk_name[i]);
cam_soc_util_clk_disable(soc_info, false, i);
}
ret = cam_config_mclk_reg(ctrl, soc_info, index);
if (ret < 0) {
@@ -2370,8 +2370,7 @@ int cam_sensor_util_power_down(struct cam_sensor_power_ctrl_t *ctrl,
switch (pd->seq_type) {
case SENSOR_MCLK:
for (i = soc_info->num_clk - 1; i >= 0; i--) {
cam_soc_util_clk_disable(soc_info->clk[i],
soc_info->clk_name[i]);
cam_soc_util_clk_disable(soc_info, false, i);
}
ret = cam_config_mclk_reg(ctrl, soc_info, index);

Vedi File

@@ -13,8 +13,274 @@
#include "cam_cx_ipeak.h"
#include "cam_mem_mgr.h"
#define CAM_TO_MASK(bitn) (1 << (int)(bitn))
#define CAM_IS_BIT_SET(mask, bit) ((mask) & CAM_TO_MASK(bit))
#define CAM_SET_BIT(mask, bit) ((mask) |= CAM_TO_MASK(bit))
#define CAM_CLEAR_BIT(mask, bit) ((mask) &= ~CAM_TO_MASK(bit))
/**
* struct cam_clk_wrapper_clk: This represents an entry corresponding to a
* shared clock in Clk wrapper. Clients that share
* the same clock are registered to this clk entry
* and set rate from them is consolidated before
* setting it to clk driver.
*
* @list: List pointer to point to next shared clk entry
* @clk_id: Clk Id of this clock
* @curr_clk_rate: Current clock rate set for this clock
* @client_list: List of clients registered to this shared clock entry
* @num_clients: Number of clients
**/
struct cam_clk_wrapper_clk {
struct list_head list;
uint32_t clk_id;
int64_t curr_clk_rate;
struct list_head client_list;
uint32_t num_clients;
};
/**
* struct cam_clk_wrapper_client: This represents a client (device) that wants
* to share the clock with some other client.
*
* @list: List pointer to point to next client that share the
* same clock
* @soc_info: soc_info of client. This is used as unique identifier
* for a client
* @clk: Clk handle
* @curr_clk_rate: Current clock rate set for this client
**/
struct cam_clk_wrapper_client {
struct list_head list;
struct cam_hw_soc_info *soc_info;
struct clk *clk;
int64_t curr_clk_rate;
};
static char supported_clk_info[256];
static DEFINE_MUTEX(wrapper_lock);
static LIST_HEAD(wrapper_clk_list);
static int cam_soc_util_clk_wrapper_register_entry(
uint32_t clk_id, struct clk *clk, struct cam_hw_soc_info *soc_info,
const char *clk_name)
{
struct cam_clk_wrapper_clk *wrapper_clk;
struct cam_clk_wrapper_client *wrapper_client;
bool clock_found = false;
int rc = 0;
mutex_lock(&wrapper_lock);
list_for_each_entry(wrapper_clk, &wrapper_clk_list, list) {
CAM_DBG(CAM_UTIL, "Clk list id %d num clients %d",
wrapper_clk->clk_id, wrapper_clk->num_clients);
if (wrapper_clk->clk_id == clk_id) {
clock_found = true;
list_for_each_entry(wrapper_client,
&wrapper_clk->client_list, list) {
CAM_DBG(CAM_UTIL,
"Clk id %d entry client %s",
wrapper_clk->clk_id,
wrapper_client->soc_info->dev_name);
if (wrapper_client->soc_info == soc_info) {
CAM_ERR(CAM_UTIL,
"Register with same soc info, clk id %d, client %s",
clk_id, soc_info->dev_name);
rc = -EINVAL;
goto end;
}
}
break;
}
}
if (!clock_found) {
CAM_DBG(CAM_UTIL, "Adding new entry for clk id %d", clk_id);
wrapper_clk = kzalloc(sizeof(struct cam_clk_wrapper_clk),
GFP_KERNEL);
if (!wrapper_clk) {
CAM_ERR(CAM_UTIL,
"Failed in allocating new clk entry %d",
clk_id);
rc = -ENOMEM;
goto end;
}
wrapper_clk->clk_id = clk_id;
INIT_LIST_HEAD(&wrapper_clk->list);
INIT_LIST_HEAD(&wrapper_clk->client_list);
list_add_tail(&wrapper_clk->list, &wrapper_clk_list);
}
wrapper_client = kzalloc(sizeof(struct cam_clk_wrapper_client),
GFP_KERNEL);
if (!wrapper_client) {
CAM_ERR(CAM_UTIL, "Failed in allocating new client entry %d",
clk_id);
rc = -ENOMEM;
goto end;
}
wrapper_client->soc_info = soc_info;
wrapper_client->clk = clk;
INIT_LIST_HEAD(&wrapper_client->list);
list_add_tail(&wrapper_client->list, &wrapper_clk->client_list);
wrapper_clk->num_clients++;
CAM_DBG(CAM_UTIL,
"Adding new client %s for clk[%s] id %d, num clients %d",
soc_info->dev_name, clk_name, clk_id, wrapper_clk->num_clients);
end:
mutex_unlock(&wrapper_lock);
return rc;
}
static int cam_soc_util_clk_wrapper_unregister_entry(
uint32_t clk_id, struct cam_hw_soc_info *soc_info)
{
struct cam_clk_wrapper_clk *wrapper_clk;
struct cam_clk_wrapper_client *wrapper_client;
bool clock_found = false;
bool client_found = false;
int rc = 0;
mutex_lock(&wrapper_lock);
list_for_each_entry(wrapper_clk, &wrapper_clk_list, list) {
CAM_DBG(CAM_UTIL, "Clk list id %d num clients %d",
wrapper_clk->clk_id, wrapper_clk->num_clients);
if (wrapper_clk->clk_id == clk_id) {
clock_found = true;
list_for_each_entry(wrapper_client,
&wrapper_clk->client_list, list) {
CAM_DBG(CAM_UTIL, "Clk id %d entry client %s",
wrapper_clk->clk_id,
wrapper_client->soc_info->dev_name);
if (wrapper_client->soc_info == soc_info) {
client_found = true;
wrapper_clk->num_clients--;
list_del_init(&wrapper_client->list);
kfree(wrapper_client);
break;
}
}
break;
}
}
if (!clock_found) {
CAM_ERR(CAM_UTIL, "Shared clk id %d entry not found", clk_id);
rc = -EINVAL;
goto end;
}
if (!client_found) {
CAM_ERR(CAM_UTIL,
"Client %pK for Shared clk id %d entry not found",
soc_info, clk_id);
rc = -EINVAL;
goto end;
}
CAM_DBG(CAM_UTIL, "Unregister client %s for clk id %d, num clients %d",
soc_info->dev_name, clk_id, wrapper_clk->num_clients);
if (!wrapper_clk->num_clients) {
list_del_init(&wrapper_clk->list);
kfree(wrapper_clk);
}
end:
mutex_unlock(&wrapper_lock);
return rc;
}
static int cam_soc_util_clk_wrapper_set_clk_rate(
uint32_t clk_id, struct cam_hw_soc_info *soc_info,
struct clk *clk, int64_t clk_rate)
{
struct cam_clk_wrapper_clk *wrapper_clk;
struct cam_clk_wrapper_client *wrapper_client;
bool clk_found = false;
bool client_found = false;
int rc = 0;
int64_t final_clk_rate = 0;
if (!soc_info || !clk) {
CAM_ERR(CAM_UTIL, "Invalid param soc_info %pK clk %pK",
soc_info, clk);
return -EINVAL;
}
mutex_lock(&wrapper_lock);
list_for_each_entry(wrapper_clk, &wrapper_clk_list, list) {
CAM_DBG(CAM_UTIL, "Clk list id %d num clients %d",
wrapper_clk->clk_id, wrapper_clk->num_clients);
if (wrapper_clk->clk_id == clk_id) {
clk_found = true;
break;
}
}
if (!clk_found) {
CAM_ERR(CAM_UTIL, "Clk entry not found id %d client %s",
clk_id, soc_info->dev_name);
rc = -EINVAL;
goto end;
}
list_for_each_entry(wrapper_client, &wrapper_clk->client_list, list) {
CAM_DBG(CAM_UTIL, "Clk id %d client %s, clk rate %lld",
wrapper_clk->clk_id, wrapper_client->soc_info->dev_name,
wrapper_client->curr_clk_rate);
if (wrapper_client->soc_info == soc_info) {
client_found = true;
CAM_DBG(CAM_UTIL,
"Clk enable clk id %d, client %s curr %ld new %ld",
clk_id, wrapper_client->soc_info->dev_name,
wrapper_client->curr_clk_rate, clk_rate);
wrapper_client->curr_clk_rate = clk_rate;
}
if (final_clk_rate < wrapper_client->curr_clk_rate)
final_clk_rate = wrapper_client->curr_clk_rate;
}
if (!client_found) {
CAM_ERR(CAM_UTIL,
"Wrapper clk enable without client entry clk id %d client %s",
clk_id, soc_info->dev_name);
rc = -EINVAL;
goto end;
}
CAM_DBG(CAM_UTIL,
"Clk id %d, client %s, clients rate %ld, curr %ld final %ld",
wrapper_clk->clk_id, soc_info->dev_name, clk_rate,
wrapper_clk->curr_clk_rate, final_clk_rate);
if (final_clk_rate != wrapper_clk->curr_clk_rate) {
if (final_clk_rate) {
rc = clk_set_rate(clk, final_clk_rate);
if (rc) {
CAM_ERR(CAM_UTIL, "set_rate failed on clk %d",
wrapper_clk->clk_id);
goto end;
}
}
wrapper_clk->curr_clk_rate = final_clk_rate;
}
end:
mutex_unlock(&wrapper_lock);
return rc;
}
int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info,
int64_t clk_rate, int clk_idx, int32_t *clk_lvl)
{
@@ -367,18 +633,26 @@ long cam_soc_util_get_clk_round_rate(struct cam_hw_soc_info *soc_info,
* @clk: Clock structure information for which rate is to be set
* @clk_name: Name of the clock for which rate is being set
* @clk_rate: Clock rate to be set
* @shared_clk: Whether this is a shared clk
* @clk_id: Clock ID
* @applied_clk_rate: Final clock rate set to the clk
*
* @return: Success or failure
*/
static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name,
int64_t clk_rate, unsigned long *applied_clk_rate)
static int cam_soc_util_set_clk_rate(struct cam_hw_soc_info *soc_info,
struct clk *clk, const char *clk_name,
int64_t clk_rate, bool shared_clk, uint32_t clk_id,
unsigned long *applied_clk_rate)
{
int rc = 0;
long clk_rate_round = -1;
bool set_rate = false;
if (!clk || !clk_name)
if (!clk || !clk_name) {
CAM_ERR(CAM_UTIL, "Invalid input clk %pK clk_name %pK",
clk, clk_name);
return -EINVAL;
}
CAM_DBG(CAM_UTIL, "set %s, rate %lld", clk_name, clk_rate);
if (clk_rate > 0) {
@@ -389,11 +663,7 @@ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name,
clk_name, clk_rate_round);
return clk_rate_round;
}
rc = clk_set_rate(clk, clk_rate_round);
if (rc) {
CAM_ERR(CAM_UTIL, "set_rate failed on %s", clk_name);
return rc;
}
set_rate = true;
} else if (clk_rate == INIT_RATE) {
clk_rate_round = clk_get_rate(clk);
CAM_DBG(CAM_UTIL, "init new_rate %ld", clk_rate_round);
@@ -405,10 +675,23 @@ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name,
return clk_rate_round;
}
}
rc = clk_set_rate(clk, clk_rate_round);
if (rc) {
CAM_ERR(CAM_UTIL, "set_rate failed on %s", clk_name);
return rc;
set_rate = true;
}
if (set_rate) {
if (shared_clk) {
CAM_DBG(CAM_UTIL,
"Dev %s clk %s id %d Set Shared clk %ld",
soc_info->dev_name, clk_name, clk_id,
clk_rate_round);
cam_soc_util_clk_wrapper_set_clk_rate(
clk_id, soc_info, clk, clk_rate_round);
} else {
rc = clk_set_rate(clk, clk_rate_round);
if (rc) {
CAM_ERR(CAM_UTIL, "set_rate failed on %s", clk_name);
return rc;
}
}
}
@@ -462,8 +745,10 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info,
apply_level);
}
rc = cam_soc_util_set_clk_rate(clk,
rc = cam_soc_util_set_clk_rate(soc_info, clk,
soc_info->clk_name[src_clk_idx], clk_rate,
CAM_IS_BIT_SET(soc_info->shared_clk_mask, src_clk_idx),
soc_info->clk_id[src_clk_idx],
&soc_info->applied_src_clk_rate);
if (rc) {
CAM_ERR(CAM_UTIL,
@@ -482,9 +767,11 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info,
continue;
}
clk = soc_info->clk[scl_clk_idx];
rc = cam_soc_util_set_clk_rate(clk,
rc = cam_soc_util_set_clk_rate(soc_info, clk,
soc_info->clk_name[scl_clk_idx],
soc_info->clk_rate[apply_level][scl_clk_idx],
CAM_IS_BIT_SET(soc_info->shared_clk_mask, scl_clk_idx),
soc_info->clk_id[scl_clk_idx],
NULL);
if (rc) {
CAM_WARN(CAM_UTIL,
@@ -498,21 +785,26 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info,
return 0;
}
int cam_soc_util_clk_put(struct clk **clk)
int cam_soc_util_put_optional_clk(struct cam_hw_soc_info *soc_info,
int32_t clk_indx)
{
if (!(*clk)) {
CAM_ERR(CAM_UTIL, "Invalid params clk");
if (clk_indx < 0) {
CAM_ERR(CAM_UTIL, "Invalid params clk %d", clk_indx);
return -EINVAL;
}
clk_put(*clk);
*clk = NULL;
if (CAM_IS_BIT_SET(soc_info->optional_shared_clk_mask, clk_indx))
cam_soc_util_clk_wrapper_unregister_entry(
soc_info->optional_clk_id[clk_indx], soc_info);
clk_put(soc_info->optional_clk[clk_indx]);
soc_info->optional_clk[clk_indx] = NULL;
return 0;
}
static struct clk *cam_soc_util_option_clk_get(struct device_node *np,
int index)
int index, uint32_t *clk_id)
{
struct of_phandle_args clkspec;
struct clk *clk;
@@ -527,23 +819,25 @@ static struct clk *cam_soc_util_option_clk_get(struct device_node *np,
return ERR_PTR(rc);
clk = of_clk_get_from_provider(&clkspec);
*clk_id = clkspec.args[0];
of_node_put(clkspec.np);
return clk;
}
int cam_soc_util_get_option_clk_by_name(struct cam_hw_soc_info *soc_info,
const char *clk_name, struct clk **clk, int32_t *clk_index,
int32_t *clk_rate)
const char *clk_name, int32_t *clk_index)
{
int index = 0;
int rc = 0;
struct device_node *of_node = NULL;
uint32_t shared_clk_val;
if (!soc_info || !clk_name || !clk) {
if (!soc_info || !clk_name || !clk_index) {
CAM_ERR(CAM_UTIL,
"Invalid params soc_info %pK clk_name %s clk %pK",
soc_info, clk_name, clk);
"Invalid params soc_info %pK clk_name %s clk_index %pK",
soc_info, clk_name, clk_index);
return -EINVAL;
}
@@ -554,52 +848,129 @@ int cam_soc_util_get_option_clk_by_name(struct cam_hw_soc_info *soc_info,
if (index < 0) {
CAM_DBG(CAM_UTIL, "No clk data for %s", clk_name);
*clk_index = -1;
*clk = ERR_PTR(-EINVAL);
return -EINVAL;
}
*clk = cam_soc_util_option_clk_get(of_node, index);
if (IS_ERR(*clk)) {
if (index >= CAM_SOC_MAX_OPT_CLK) {
CAM_ERR(CAM_UTIL, "Insufficient optional clk entries %d %d",
index, CAM_SOC_MAX_OPT_CLK);
return -EINVAL;
}
of_property_read_string_index(of_node, "clock-names-option",
index, &(soc_info->optional_clk_name[index]));
soc_info->optional_clk[index] = cam_soc_util_option_clk_get(of_node,
index, &soc_info->optional_clk_id[index]);
if (IS_ERR(soc_info->optional_clk[index])) {
CAM_ERR(CAM_UTIL, "No clk named %s found. Dev %s", clk_name,
soc_info->dev_name);
*clk_index = -1;
*clk = NULL;
return -EFAULT;
}
*clk_index = index;
rc = of_property_read_u32_index(of_node, "clock-rates-option",
index, clk_rate);
index, &soc_info->optional_clk_rate[index]);
if (rc) {
CAM_ERR(CAM_UTIL,
"Error reading clock-rates clk_name %s index %d",
clk_name, index);
cam_soc_util_clk_put(clk);
*clk_rate = 0;
return rc;
goto error;
}
/*
* Option clocks are assumed to be available to single Device here.
* Hence use INIT_RATE instead of NO_SET_RATE.
*/
*clk_rate = (*clk_rate == 0) ? (int32_t)INIT_RATE : *clk_rate;
soc_info->optional_clk_rate[index] =
(soc_info->optional_clk_rate[index] == 0) ?
(int32_t)INIT_RATE : soc_info->optional_clk_rate[index];
CAM_DBG(CAM_UTIL, "clk_name %s index %d clk_rate %d",
clk_name, *clk_index, *clk_rate);
clk_name, *clk_index, soc_info->optional_clk_rate[index]);
rc = of_property_read_u32_index(of_node, "shared-clks-option",
index, &shared_clk_val);
if (rc) {
CAM_DBG(CAM_UTIL, "Not shared clk %s index %d",
clk_name, index);
} else if (shared_clk_val > 1) {
CAM_WARN(CAM_UTIL, "Invalid shared clk val %d", shared_clk_val);
} else {
CAM_DBG(CAM_UTIL,
"Dev %s shared clk %s index %d, clk id %d, shared_clk_val %d",
soc_info->dev_name, clk_name, index,
soc_info->optional_clk_id[index], shared_clk_val);
if (shared_clk_val) {
CAM_SET_BIT(soc_info->optional_shared_clk_mask, index);
/* Create a wrapper entry if this is a shared clock */
CAM_DBG(CAM_UTIL,
"Dev %s, clk %s, id %d register wrapper entry for shared clk",
soc_info->dev_name,
soc_info->optional_clk_name[index],
soc_info->optional_clk_id[index]);
rc = cam_soc_util_clk_wrapper_register_entry(
soc_info->optional_clk_id[index],
soc_info->optional_clk[index], soc_info,
soc_info->optional_clk_name[index]);
if (rc) {
CAM_ERR(CAM_UTIL,
"Failed in registering shared clk Dev %s id %d",
soc_info->dev_name,
soc_info->optional_clk_id[index]);
goto error;
}
}
}
return 0;
error:
clk_put(soc_info->optional_clk[index]);
soc_info->optional_clk_rate[index] = 0;
soc_info->optional_clk[index] = NULL;
*clk_index = -1;
return rc;
}
int cam_soc_util_clk_enable(struct clk *clk, const char *clk_name,
int32_t clk_rate, unsigned long *applied_clock_rate)
int cam_soc_util_clk_enable(struct cam_hw_soc_info *soc_info,
bool optional_clk, int32_t clk_idx, int32_t apply_level,
unsigned long *applied_clock_rate)
{
int rc = 0;
struct clk *clk;
const char *clk_name;
int32_t clk_rate;
uint32_t shared_clk_mask;
uint32_t clk_id;
if (!clk || !clk_name)
if (!soc_info || (clk_idx < 0) || (apply_level >= CAM_MAX_VOTE)) {
CAM_ERR(CAM_UTIL, "Invalid param %d %d", clk_idx, apply_level);
return -EINVAL;
}
rc = cam_soc_util_set_clk_rate(clk, clk_name, clk_rate,
if (optional_clk) {
clk = soc_info->optional_clk[clk_idx];
clk_name = soc_info->optional_clk_name[clk_idx];
clk_rate = (apply_level == -1) ?
0 : soc_info->optional_clk_rate[clk_idx];
shared_clk_mask = soc_info->optional_shared_clk_mask;
clk_id = soc_info->optional_clk_id[clk_idx];
} else {
clk = soc_info->clk[clk_idx];
clk_name = soc_info->clk_name[clk_idx];
clk_rate = (apply_level == -1) ?
0 : soc_info->clk_rate[apply_level][clk_idx];
shared_clk_mask = soc_info->shared_clk_mask;
clk_id = soc_info->clk_id[clk_idx];
}
rc = cam_soc_util_set_clk_rate(soc_info, clk, clk_name, clk_rate,
CAM_IS_BIT_SET(shared_clk_mask, clk_idx), clk_id,
applied_clock_rate);
if (rc)
return rc;
@@ -613,14 +984,42 @@ int cam_soc_util_clk_enable(struct clk *clk, const char *clk_name,
return rc;
}
int cam_soc_util_clk_disable(struct clk *clk, const char *clk_name)
int cam_soc_util_clk_disable(struct cam_hw_soc_info *soc_info,
bool optional_clk, int32_t clk_idx)
{
if (!clk || !clk_name)
struct clk *clk;
const char *clk_name;
uint32_t shared_clk_mask;
uint32_t clk_id;
if (!soc_info || (clk_idx < 0)) {
CAM_ERR(CAM_UTIL, "Invalid param %d", clk_idx);
return -EINVAL;
}
if (optional_clk) {
clk = soc_info->optional_clk[clk_idx];
clk_name = soc_info->optional_clk_name[clk_idx];
shared_clk_mask = soc_info->optional_shared_clk_mask;
clk_id = soc_info->optional_clk_id[clk_idx];
} else {
clk = soc_info->clk[clk_idx];
clk_name = soc_info->clk_name[clk_idx];
shared_clk_mask = soc_info->shared_clk_mask;
clk_id = soc_info->clk_id[clk_idx];
}
CAM_DBG(CAM_UTIL, "disable %s", clk_name);
clk_disable_unprepare(clk);
if (CAM_IS_BIT_SET(shared_clk_mask, clk_idx)) {
CAM_DBG(CAM_UTIL,
"Dev %s clk %s Disabling Shared clk, set 0 rate",
soc_info->dev_name, clk_name);
cam_soc_util_clk_wrapper_set_clk_rate(clk_id, soc_info, clk, 0);
}
return 0;
}
@@ -658,9 +1057,7 @@ int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info,
cam_cx_ipeak_update_vote_cx_ipeak(soc_info, apply_level);
for (i = 0; i < soc_info->num_clk; i++) {
rc = cam_soc_util_clk_enable(soc_info->clk[i],
soc_info->clk_name[i],
soc_info->clk_rate[apply_level][i],
rc = cam_soc_util_clk_enable(soc_info, false, i, apply_level,
&applied_clk_rate);
if (rc)
goto clk_disable;
@@ -684,8 +1081,7 @@ clk_disable:
if (soc_info->cam_cx_ipeak_enable)
cam_cx_ipeak_update_vote_cx_ipeak(soc_info, 0);
for (i--; i >= 0; i--) {
cam_soc_util_clk_disable(soc_info->clk[i],
soc_info->clk_name[i]);
cam_soc_util_clk_disable(soc_info, false, i);
}
return rc;
@@ -711,8 +1107,7 @@ void cam_soc_util_clk_disable_default(struct cam_hw_soc_info *soc_info)
if (soc_info->cam_cx_ipeak_enable)
cam_cx_ipeak_unvote_cx_ipeak(soc_info);
for (i = soc_info->num_clk - 1; i >= 0; i--)
cam_soc_util_clk_disable(soc_info->clk[i],
soc_info->clk_name[i]);
cam_soc_util_clk_disable(soc_info, false, i);
}
/**
@@ -737,6 +1132,8 @@ static int cam_soc_util_get_dt_clk_info(struct cam_hw_soc_info *soc_info)
const char *clk_control_debugfs = NULL;
const char *clk_cntl_lvl_string = NULL;
enum cam_vote_level level;
int shared_clk_cnt;
struct of_phandle_args clk_args = {0};
if (!soc_info || !soc_info->dev)
return -EINVAL;
@@ -857,8 +1254,54 @@ static int cam_soc_util_get_dt_clk_info(struct cam_hw_soc_info *soc_info)
soc_info->src_clk_idx = i;
CAM_DBG(CAM_UTIL, "src clock = %s, index = %d",
src_clk_str, i);
break;
}
rc = of_parse_phandle_with_args(of_node, "clocks",
"#clock-cells", i, &clk_args);
if (rc) {
CAM_ERR(CAM_CPAS,
"failed to clock info rc=%d", rc);
rc = -EINVAL;
goto end;
}
soc_info->clk_id[i] = clk_args.args[0];
of_node_put(clk_args.np);
CAM_DBG(CAM_UTIL, "Dev %s clk %s id %d",
soc_info->dev_name, soc_info->clk_name[i],
soc_info->clk_id[i]);
}
soc_info->shared_clk_mask = 0;
shared_clk_cnt = of_property_count_u32_elems(of_node, "shared-clks");
if (shared_clk_cnt <= 0) {
CAM_DBG(CAM_UTIL, "Dev %s, no shared clks", soc_info->dev_name);
} else if (shared_clk_cnt != count) {
CAM_ERR(CAM_UTIL, "Dev %s, incorrect shared clock count %d %d",
soc_info->dev_name, shared_clk_cnt, count);
rc = -EINVAL;
goto end;
} else {
uint32_t shared_clk_val;
for (i = 0; i < shared_clk_cnt; i++) {
rc = of_property_read_u32_index(of_node,
"shared-clks", i, &shared_clk_val);
if (rc || (shared_clk_val > 1)) {
CAM_ERR(CAM_UTIL,
"Incorrect shared clk info at %d, val=%d, count=%d",
i, shared_clk_val, shared_clk_cnt);
rc = -EINVAL;
goto end;
}
if (shared_clk_val)
CAM_SET_BIT(soc_info->shared_clk_mask, i);
}
CAM_DBG(CAM_UTIL, "Dev %s shared clk mask 0x%x",
soc_info->dev_name, soc_info->shared_clk_mask);
}
/* scalable clk info parsing */
@@ -953,9 +1396,11 @@ int cam_soc_util_set_clk_rate_level(struct cam_hw_soc_info *soc_info,
soc_info->clk_name[i],
soc_info->clk_rate[apply_level][i]);
rc = cam_soc_util_set_clk_rate(soc_info->clk[i],
rc = cam_soc_util_set_clk_rate(soc_info, soc_info->clk[i],
soc_info->clk_name[i],
soc_info->clk_rate[apply_level][i],
CAM_IS_BIT_SET(soc_info->shared_clk_mask, i),
soc_info->clk_id[i],
&applied_clk_rate);
if (rc < 0) {
CAM_DBG(CAM_UTIL,
@@ -1634,6 +2079,26 @@ int cam_soc_util_request_platform_resource(
rc = -ENOENT;
goto put_clk;
}
/* Create a wrapper entry if this is a shared clock */
if (CAM_IS_BIT_SET(soc_info->shared_clk_mask, i)) {
CAM_DBG(CAM_UTIL,
"Dev %s, clk %s, id %d register wrapper entry for shared clk",
soc_info->dev_name, soc_info->clk_name[i],
soc_info->clk_id[i]);
rc = cam_soc_util_clk_wrapper_register_entry(
soc_info->clk_id[i], soc_info->clk[i], soc_info,
soc_info->clk_name[i]);
if (rc) {
CAM_ERR(CAM_UTIL,
"Failed in registering shared clk Dev %s id %d",
soc_info->dev_name,
soc_info->clk_id[i]);
clk_put(soc_info->clk[i]);
soc_info->clk[i] = NULL;
goto put_clk;
}
}
}
rc = cam_soc_util_request_pinctrl(soc_info);
@@ -1656,6 +2121,10 @@ put_clk:
i = soc_info->num_clk;
for (i = i - 1; i >= 0; i--) {
if (soc_info->clk[i]) {
if (CAM_IS_BIT_SET(soc_info->shared_clk_mask, i))
cam_soc_util_clk_wrapper_unregister_entry(
soc_info->clk_id[i], soc_info);
clk_put(soc_info->clk[i]);
soc_info->clk[i] = NULL;
}
@@ -1703,6 +2172,10 @@ int cam_soc_util_release_platform_resource(struct cam_hw_soc_info *soc_info)
}
for (i = soc_info->num_clk - 1; i >= 0; i--) {
if (CAM_IS_BIT_SET(soc_info->shared_clk_mask, i))
cam_soc_util_clk_wrapper_unregister_entry(
soc_info->clk_id[i], soc_info);
clk_put(soc_info->clk[i]);
soc_info->clk[i] = NULL;
}

Vedi File

@@ -36,6 +36,9 @@
/* maximum number of device clock */
#define CAM_SOC_MAX_CLK 32
/* maximum number of optional device clock */
#define CAM_SOC_MAX_OPT_CLK 2
/* DDR device types */
#define DDR_TYPE_LPDDR4 6
#define DDR_TYPE_LPDDR4X 7
@@ -155,12 +158,23 @@ struct cam_soc_gpio_data {
* @clk: Array of associated clock resources
* @clk_rate: 2D array of clock rates representing clock rate
* values at different vote levels
* @clk_id Clock IDs
* @shared_clk_mask Mask indicating which of the clocks are shared with
* other devices. Set rate on these clocks needs to go
* through camera clk wrapper for aggregation.
* @prev_clk_level Last vote level
* @src_clk_idx: Source clock index that is rate-controllable
* @applied_src_clk_rate Current clock rate of the core source clk
* @clk_level_valid: Indicates whether corresponding level is valid
* @scl_clk_count: Number of scalable clocks present
* @scl_clk_idx: Index of scalable clocks
* @applied_src_clk_rate Current clock rate of the core source clk
* @optional_clk_name: Array of clock names
* @optional_clk: Array of associated clock resources
* @optional_clk_rate: Optional clock's clk rate
* @optional_clk_id Clock IDs
* @optional_shared_clk_mask Mask indicating which of the clocks are shared with
* other devices. Set rate on these clocks needs to go
* through camera clk wrapper for aggregation.
* @gpio_data: Pointer to gpio info
* @pinctrl_info: Pointer to pinctrl info
* @dentry: Debugfs entry
@@ -205,12 +219,19 @@ struct cam_hw_soc_info {
const char *clk_name[CAM_SOC_MAX_CLK];
struct clk *clk[CAM_SOC_MAX_CLK];
int32_t clk_rate[CAM_MAX_VOTE][CAM_SOC_MAX_CLK];
uint32_t clk_id[CAM_SOC_MAX_CLK];
uint32_t shared_clk_mask;
int32_t prev_clk_level;
int32_t src_clk_idx;
unsigned long applied_src_clk_rate;
bool clk_level_valid[CAM_MAX_VOTE];
int32_t scl_clk_count;
int32_t scl_clk_idx[CAM_SOC_MAX_CLK];
const char *optional_clk_name[CAM_SOC_MAX_OPT_CLK];
struct clk *optional_clk[CAM_SOC_MAX_OPT_CLK];
int32_t optional_clk_rate[CAM_SOC_MAX_OPT_CLK];
uint32_t optional_clk_id[CAM_SOC_MAX_OPT_CLK];
uint32_t optional_shared_clk_mask;
struct cam_soc_gpio_data *gpio_data;
struct cam_soc_pinctrl_info pinctrl_info;
@@ -427,42 +448,48 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info,
*
* @soc_info: Device soc information
* @clk_name: Name of clock to find reference for
* @clk: Clock reference pointer to be filled if Success
* @clk_index: Clk index in the option clk array to be returned
* @clk_rate: Clk rate in the option clk array
*
* @return: 0: Success
* Negative: Failure
*/
int cam_soc_util_get_option_clk_by_name(struct cam_hw_soc_info *soc_info,
const char *clk_name, struct clk **clk, int32_t *clk_index,
int32_t *clk_rate);
const char *clk_name, int32_t *clk_index);
/**
* cam_soc_util_clk_put()
* cam_soc_util_put_optional_clk()
*
* @brief: Put clock specified in params
* @brief: Put clock corresponding to index specified in params
*
* @clk: Reference to the Clock that needs to be put
* @soc_info: Device soc information
* @clk_idx: Clock index in optional clocks to put
*
* @return: Success or failure
*/
int cam_soc_util_clk_put(struct clk **clk);
int cam_soc_util_put_optional_clk(struct cam_hw_soc_info *soc_info,
int32_t clk_idx);
/**
* cam_soc_util_clk_enable()
*
* @brief: Enable clock specified in params
*
* @clk: Clock that needs to be turned ON
* @clk_name: Clocks name associated with clk
* @clk_rate: Clocks rate associated with clk
* @soc_info: Device soc information
* @optional_clk: Whether to set optional clk or normal clk with
* the idx given
* @clk_idx: Clock index to set
* @apply_level: Apply level.
* -1 for 0 rate
* any other value indicate level for normal clocks
* For optional clocks any other value means the rate saved
* in soc_info
* @applied_clock_rate Final Clock rate applied to the clk
*
* @return: Success or failure
*/
int cam_soc_util_clk_enable(struct clk *clk, const char *clk_name,
int32_t clk_rate, unsigned long *applied_clock_rate);
int cam_soc_util_clk_enable(struct cam_hw_soc_info *soc_info,
bool optional_clk, int32_t clk_idx, int32_t apply_level,
unsigned long *applied_clock_rate);
/**
* cam_soc_util_set_clk_rate_level()
@@ -485,12 +512,15 @@ int cam_soc_util_set_clk_rate_level(struct cam_hw_soc_info *soc_info,
*
* @brief: Disable clock specified in params
*
* @clk: Clock that needs to be turned OFF
* @clk_name: Clocks name associated with clk
* @soc_info: Device soc information
* @optional_clk: Whether to set optional clk or normal clk with
* the idx given
* @clk_idx: Clock index to disable
*
* @return: Success or failure
*/
int cam_soc_util_clk_disable(struct clk *clk, const char *clk_name);
int cam_soc_util_clk_disable(struct cam_hw_soc_info *soc_info,
bool optional_clk, int32_t clk_idx);
/**
* cam_soc_util_irq_enable()