397 lines
11 KiB
C
397 lines
11 KiB
C
|
/**
|
||
|
* Copyright (c) 2015-2018, NVIDIA CORPORATION. All rights reserved.
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License version 2 as
|
||
|
* published by the Free Software Foundation.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||
|
* more details.
|
||
|
*/
|
||
|
|
||
|
#ifndef __EMC_BWMGR_H
|
||
|
#define __EMC_BWMGR_H
|
||
|
|
||
|
#include <linux/clk.h>
|
||
|
#include <linux/device.h>
|
||
|
#include <linux/of_address.h>
|
||
|
#include <linux/platform/tegra/iso_client.h>
|
||
|
|
||
|
/* keep in sync with tegra_bwmgr_client_names */
|
||
|
enum tegra_bwmgr_client_id {
|
||
|
TEGRA_BWMGR_CLIENT_CPU_CLUSTER_0,
|
||
|
TEGRA_BWMGR_CLIENT_CPU_CLUSTER_1,
|
||
|
TEGRA_BWMGR_CLIENT_CPU_CLUSTER_2,
|
||
|
TEGRA_BWMGR_CLIENT_CPU_CLUSTER_3,
|
||
|
TEGRA_BWMGR_CLIENT_DISP0,
|
||
|
TEGRA_BWMGR_CLIENT_DISP1,
|
||
|
TEGRA_BWMGR_CLIENT_DISP2,
|
||
|
TEGRA_BWMGR_CLIENT_DISP1_LA_EMC,
|
||
|
TEGRA_BWMGR_CLIENT_DISP2_LA_EMC,
|
||
|
TEGRA_BWMGR_CLIENT_USBD,
|
||
|
TEGRA_BWMGR_CLIENT_XHCI,
|
||
|
TEGRA_BWMGR_CLIENT_SDMMC1,
|
||
|
TEGRA_BWMGR_CLIENT_SDMMC2,
|
||
|
TEGRA_BWMGR_CLIENT_SDMMC3,
|
||
|
TEGRA_BWMGR_CLIENT_SDMMC4,
|
||
|
TEGRA_BWMGR_CLIENT_MON,
|
||
|
TEGRA_BWMGR_CLIENT_GPU,
|
||
|
TEGRA_BWMGR_CLIENT_MSENC,
|
||
|
TEGRA_BWMGR_CLIENT_NVENC1,
|
||
|
TEGRA_BWMGR_CLIENT_NVJPG,
|
||
|
TEGRA_BWMGR_CLIENT_NVDEC,
|
||
|
TEGRA_BWMGR_CLIENT_NVDEC1,
|
||
|
TEGRA_BWMGR_CLIENT_TSEC,
|
||
|
TEGRA_BWMGR_CLIENT_TSECB,
|
||
|
TEGRA_BWMGR_CLIENT_VI,
|
||
|
TEGRA_BWMGR_CLIENT_ISPA,
|
||
|
TEGRA_BWMGR_CLIENT_ISPB,
|
||
|
TEGRA_BWMGR_CLIENT_CAMERA,
|
||
|
TEGRA_BWMGR_CLIENT_CAMERA_NON_ISO,
|
||
|
TEGRA_BWMGR_CLIENT_CAMRTC,
|
||
|
TEGRA_BWMGR_CLIENT_ISOMGR,
|
||
|
TEGRA_BWMGR_CLIENT_THERMAL_CAP,
|
||
|
TEGRA_BWMGR_CLIENT_VIC,
|
||
|
TEGRA_BWMGR_CLIENT_APE_ADSP,
|
||
|
TEGRA_BWMGR_CLIENT_APE_ADMA,
|
||
|
TEGRA_BWMGR_CLIENT_PCIE,
|
||
|
TEGRA_BWMGR_CLIENT_PCIE_1,
|
||
|
TEGRA_BWMGR_CLIENT_PCIE_2,
|
||
|
TEGRA_BWMGR_CLIENT_PCIE_3,
|
||
|
TEGRA_BWMGR_CLIENT_PCIE_4,
|
||
|
TEGRA_BWMGR_CLIENT_PCIE_5,
|
||
|
TEGRA_BWMGR_CLIENT_BBC_0,
|
||
|
TEGRA_BWMGR_CLIENT_EQOS,
|
||
|
TEGRA_BWMGR_CLIENT_SE0,
|
||
|
TEGRA_BWMGR_CLIENT_SE1,
|
||
|
TEGRA_BWMGR_CLIENT_SE2,
|
||
|
TEGRA_BWMGR_CLIENT_SE3,
|
||
|
TEGRA_BWMGR_CLIENT_SE4,
|
||
|
TEGRA_BWMGR_CLIENT_PMQOS,
|
||
|
TEGRA_BWMGR_CLIENT_NVPMODEL,
|
||
|
TEGRA_BWMGR_CLIENT_DEBUG,
|
||
|
TEGRA_BWMGR_CLIENT_DLA0,
|
||
|
TEGRA_BWMGR_CLIENT_DLA1,
|
||
|
TEGRA_BWMGR_CLIENT_COUNT /* Should always be last */
|
||
|
};
|
||
|
|
||
|
enum tegra_bwmgr_request_type {
|
||
|
TEGRA_BWMGR_SET_EMC_FLOOR, /* lower bound */
|
||
|
TEGRA_BWMGR_SET_EMC_CAP, /* upper bound */
|
||
|
TEGRA_BWMGR_SET_EMC_ISO_CAP, /* upper bound that affects ISO Bw */
|
||
|
TEGRA_BWMGR_SET_EMC_SHARED_BW, /* shared bw request */
|
||
|
TEGRA_BWMGR_SET_EMC_SHARED_BW_ISO, /* for use by ISO Mgr only */
|
||
|
TEGRA_BWMGR_SET_EMC_REQ_COUNT /* Should always be last */
|
||
|
};
|
||
|
|
||
|
enum bwmgr_dram_types {
|
||
|
DRAM_TYPE_NONE,
|
||
|
DRAM_TYPE_LPDDR4_16CH_ECC,
|
||
|
DRAM_TYPE_LPDDR4_8CH_ECC,
|
||
|
DRAM_TYPE_LPDDR4_4CH_ECC,
|
||
|
DRAM_TYPE_LPDDR4_2CH_ECC,
|
||
|
DRAM_TYPE_LPDDR4_16CH,
|
||
|
DRAM_TYPE_LPDDR4_8CH,
|
||
|
DRAM_TYPE_LPDDR4_4CH,
|
||
|
DRAM_TYPE_LPDDR4_2CH,
|
||
|
DRAM_TYPE_LPDDR3_2CH,
|
||
|
DRAM_TYPE_DDR3_2CH
|
||
|
};
|
||
|
|
||
|
extern u8 bwmgr_dram_efficiency;
|
||
|
extern u8 bwmgr_dram_num_channels;
|
||
|
/* flag to determine supported memory and channel configuration */
|
||
|
extern u8 bwmgr_dram_config_supported;
|
||
|
extern u32 *bwmgr_dram_iso_eff_table;
|
||
|
extern u32 *bwmgr_dram_noniso_eff_table;
|
||
|
extern u32 *bwmgr_max_nvdis_bw_reqd;
|
||
|
extern u32 *bwmgr_max_vi_bw_reqd;
|
||
|
extern int *bwmgr_slope;
|
||
|
extern u32 *bwmgr_vi_bw_reqd_offset;
|
||
|
extern int bwmgr_iso_bw_percentage;
|
||
|
extern enum bwmgr_dram_types bwmgr_dram_type;
|
||
|
extern int emc_to_dram_freq_factor;
|
||
|
|
||
|
struct tegra_bwmgr_client;
|
||
|
|
||
|
struct bwmgr_ops {
|
||
|
unsigned long (*freq_to_bw)(unsigned long freq);
|
||
|
unsigned long (*bw_to_freq)(unsigned long bw);
|
||
|
u32 (*dvfs_latency)(u32 ufreq);
|
||
|
unsigned long (*bwmgr_apply_efficiency)(
|
||
|
unsigned long total_bw, unsigned long iso_bw,
|
||
|
unsigned long max_rate, u64 usage_flags,
|
||
|
unsigned long *iso_bw_min, unsigned long iso_bw_nvdis,
|
||
|
unsigned long iso_bw_vi);
|
||
|
unsigned long (*get_best_iso_freq)(long iso_bw,
|
||
|
long iso_bw_nvdis, long iso_bw_vi);
|
||
|
void (*update_efficiency)(unsigned long dram_refresh_rate);
|
||
|
u32 (*get_max_iso_bw)(enum tegra_iso_client client);
|
||
|
};
|
||
|
|
||
|
struct bwmgr_ops *bwmgr_eff_init_t21x(void);
|
||
|
struct bwmgr_ops *bwmgr_eff_init_t18x(void);
|
||
|
struct bwmgr_ops *bwmgr_eff_init_t19x(void);
|
||
|
|
||
|
#if defined(CONFIG_TEGRA_BWMGR)
|
||
|
/**
|
||
|
* tegra_bwmgr_register - register an EMC Bandwidth Manager client.
|
||
|
* Also see tegra_bwmgr_unregister().
|
||
|
* @client client id from tegra_bwmgr_client_id
|
||
|
*
|
||
|
* Returns a valid handle on successful registration, NULL on error.
|
||
|
*/
|
||
|
struct tegra_bwmgr_client *tegra_bwmgr_register(
|
||
|
enum tegra_bwmgr_client_id client);
|
||
|
|
||
|
/**
|
||
|
* tegra_bwmgr_unregister - unregister an EMC Bandwidth Manager client.
|
||
|
* Callers should match register/unregister calls.
|
||
|
* Persistence of old requests across
|
||
|
* register/unregister calls is undefined.
|
||
|
* Also see tegra_bwmgr_set_emc()
|
||
|
*
|
||
|
* @handle handle acquired during tegra_bwmgr_register
|
||
|
*/
|
||
|
void tegra_bwmgr_unregister(struct tegra_bwmgr_client *handle);
|
||
|
|
||
|
/**
|
||
|
* tegra_bwmgr_get_dram_num_channels - get the number of DRAM channels
|
||
|
*
|
||
|
* Returns the number of DRAM channels that are configured on the underlying
|
||
|
* platform.
|
||
|
*/
|
||
|
u8 tegra_bwmgr_get_dram_num_channels(void);
|
||
|
|
||
|
/**
|
||
|
* tegra_bwmgr_get_emc_rate - get the current EMC rate.
|
||
|
*
|
||
|
* Returns current memory clock rate in Hz.
|
||
|
*/
|
||
|
unsigned long tegra_bwmgr_get_emc_rate(void);
|
||
|
|
||
|
/**
|
||
|
* tegra_bwmgr_get_max_emc_rate - get the max EMC rate.
|
||
|
*
|
||
|
* Returns the max memory clock rate in Hz.
|
||
|
*/
|
||
|
unsigned long tegra_bwmgr_get_max_emc_rate(void);
|
||
|
|
||
|
/**
|
||
|
* tegra_bwmgr_get_core_emc_rate - get the actual emc frequency calculated
|
||
|
* using the dram frequency and emc_to_dram
|
||
|
* conversion factor.
|
||
|
*
|
||
|
* Returns the core emc rate in Hz.
|
||
|
*/
|
||
|
unsigned long tegra_bwmgr_get_core_emc_rate(void);
|
||
|
|
||
|
/**
|
||
|
* tegra_bwmgr_round_rate - round up to next EMC rate which can be provided
|
||
|
*
|
||
|
* @bw Input rate
|
||
|
*
|
||
|
* Returns the next higher rate from the Input rate that EMC can run at.
|
||
|
*/
|
||
|
unsigned long tegra_bwmgr_round_rate(unsigned long bw);
|
||
|
|
||
|
/**
|
||
|
* tegra_bwmgr_set_emc - request to bwmgr to set an EMC rate parameter.
|
||
|
* Actual clock rate depends on aggregation of
|
||
|
* requests by all clients. If needed, use
|
||
|
* tegra_bwmgr_get_emc_rate() to get the rate after
|
||
|
* a tegra_bwmgr_set_emc() call.
|
||
|
*
|
||
|
* Call tegra_bwmgr_set_emc() with same request type and
|
||
|
* val = 0 to clear request.
|
||
|
*
|
||
|
* @handle handle acquired during tegra_bwmgr_register
|
||
|
* @val value to be set in Hz, 0 to clear old request of the same type
|
||
|
* @req chosen type from tegra_bwmgr_request_type
|
||
|
*
|
||
|
* Returns success (0) or negative errno.
|
||
|
*/
|
||
|
int tegra_bwmgr_set_emc(struct tegra_bwmgr_client *handle, unsigned long val,
|
||
|
enum tegra_bwmgr_request_type req);
|
||
|
|
||
|
/**
|
||
|
* tegra_bwmgr_get_client_info - outputs the value previously set with
|
||
|
* tegra_bwmgr_set_emc or 0 if no value has been set.
|
||
|
*
|
||
|
* @handle handle acquired during tegra_bwmgr_register
|
||
|
* @out_val bandwidth value in Hz
|
||
|
* @req chosen type from tegra_bwmgr_request_type
|
||
|
*
|
||
|
* Returns success (0) or negative errno.
|
||
|
*/
|
||
|
int tegra_bwmgr_get_client_info(struct tegra_bwmgr_client *handle,
|
||
|
unsigned long *out_val,
|
||
|
enum tegra_bwmgr_request_type req);
|
||
|
|
||
|
/**
|
||
|
* tegra_bwmgr_notifier_register - register a notifier callback when
|
||
|
* emc rate changes. Must be called from non-atomic
|
||
|
* context. The callback must not call any bwmgr API.
|
||
|
* @nb linux notifier block
|
||
|
*
|
||
|
* Returns success (0) or negative errno.
|
||
|
*/
|
||
|
int tegra_bwmgr_notifier_register(struct notifier_block *nb);
|
||
|
|
||
|
/**
|
||
|
* tegra_bwmgr_notifier_unregister - unregister a notifier callback.
|
||
|
* @nb linux notifier block
|
||
|
*
|
||
|
* Returns success (0) or negative errno.
|
||
|
*/
|
||
|
int tegra_bwmgr_notifier_unregister(struct notifier_block *nb);
|
||
|
|
||
|
/*
|
||
|
* Initialize bwmgr.
|
||
|
* This api would be called by .init_machine during boot.
|
||
|
* bwmgr clients, don't call this api.
|
||
|
*/
|
||
|
int __init bwmgr_init(void);
|
||
|
|
||
|
void __exit bwmgr_exit(void);
|
||
|
|
||
|
/*
|
||
|
* Initialize pmqos bwmgr code which registers pmqos as bwmgr client and
|
||
|
* registers a notifier which gets called on update to PMQOS_EMC_FREQ_MIN.
|
||
|
*/
|
||
|
int __init pmqos_bwmgr_init(void);
|
||
|
|
||
|
#else /* CONFIG_TEGRA_BWMGR */
|
||
|
|
||
|
static inline struct tegra_bwmgr_client *tegra_bwmgr_register(
|
||
|
enum tegra_bwmgr_client_id client_id)
|
||
|
{
|
||
|
static int i;
|
||
|
/* return a dummy handle to allow client to function
|
||
|
* as if bwmgr were enabled.
|
||
|
*/
|
||
|
return (struct tegra_bwmgr_client *) &i;
|
||
|
}
|
||
|
|
||
|
static inline void tegra_bwmgr_unregister(struct tegra_bwmgr_client *handle) {}
|
||
|
|
||
|
static inline int bwmgr_init(void)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static inline void bwmgr_exit(void) {}
|
||
|
|
||
|
static inline u8 tegra_bwmgr_get_dram_num_channels(void)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static inline unsigned long tegra_bwmgr_get_emc_rate(void)
|
||
|
{
|
||
|
static struct clk *bwmgr_emc_clk;
|
||
|
struct device_node *dn;
|
||
|
|
||
|
if (!bwmgr_emc_clk) {
|
||
|
dn = of_find_compatible_node(NULL, NULL, "nvidia,bwmgr");
|
||
|
if (dn == NULL) {
|
||
|
pr_err("bwmgr: dt node not found.\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
bwmgr_emc_clk = of_clk_get(dn, 0);
|
||
|
if (IS_ERR_OR_NULL(bwmgr_emc_clk)) {
|
||
|
pr_err("bwmgr: couldn't find emc clock.\n");
|
||
|
bwmgr_emc_clk = NULL;
|
||
|
WARN_ON(true);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return clk_get_rate(bwmgr_emc_clk);
|
||
|
}
|
||
|
|
||
|
static inline unsigned long tegra_bwmgr_get_max_emc_rate(void)
|
||
|
{
|
||
|
static struct clk *bwmgr_emc_clk;
|
||
|
struct device_node *dn;
|
||
|
|
||
|
if (!bwmgr_emc_clk) {
|
||
|
dn = of_find_compatible_node(NULL, NULL, "nvidia,bwmgr");
|
||
|
if (dn == NULL) {
|
||
|
pr_err("bwmgr: dt node not found.\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
bwmgr_emc_clk = of_clk_get(dn, 0);
|
||
|
if (IS_ERR_OR_NULL(bwmgr_emc_clk)) {
|
||
|
pr_err("bwmgr: couldn't find emc clock.\n");
|
||
|
bwmgr_emc_clk = NULL;
|
||
|
WARN_ON(true);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Use LONG_MAX as clk_round_rate treats rate argument as signed */
|
||
|
return clk_round_rate(bwmgr_emc_clk, LONG_MAX);
|
||
|
}
|
||
|
|
||
|
static inline unsigned long tegra_bwmgr_get_core_emc_rate(void)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
static inline unsigned long tegra_bwmgr_round_rate(unsigned long bw)
|
||
|
{
|
||
|
static struct clk *bwmgr_emc_clk;
|
||
|
struct device_node *dn;
|
||
|
|
||
|
if (!bwmgr_emc_clk) {
|
||
|
dn = of_find_compatible_node(NULL, NULL, "nvidia,bwmgr");
|
||
|
if (dn == NULL) {
|
||
|
pr_err("bwmgr: dt node not found.\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
bwmgr_emc_clk = of_clk_get(dn, 0);
|
||
|
if (IS_ERR_OR_NULL(bwmgr_emc_clk)) {
|
||
|
pr_err("bwmgr: couldn't find emc clock.\n");
|
||
|
bwmgr_emc_clk = NULL;
|
||
|
WARN_ON(true);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return clk_round_rate(bwmgr_emc_clk, bw);
|
||
|
}
|
||
|
|
||
|
static inline int tegra_bwmgr_set_emc(struct tegra_bwmgr_client *handle,
|
||
|
unsigned long val, enum tegra_bwmgr_request_type req)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static inline int tegra_bwmgr_get_client_info(struct tegra_bwmgr_client *handle,
|
||
|
unsigned long *out_val,
|
||
|
enum tegra_bwmgr_request_type req)
|
||
|
{
|
||
|
if (!out_val)
|
||
|
return -EINVAL;
|
||
|
*out_val = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static inline int tegra_bwmgr_notifier_register(struct notifier_block *nb)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static inline int tegra_bwmgr_notifier_unregister(struct notifier_block *nb)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#endif /* CONFIG_TEGRA_BWMGR */
|
||
|
#endif /* __EMC_BWMGR_H */
|