#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/sort.h>
#include <linux/tegra-icc.h>
#include <soc/tegra/fuse.h>
#include "mc.h"
static const struct of_device_id tegra_mc_of_match[] = …;
MODULE_DEVICE_TABLE(of, tegra_mc_of_match);
static void tegra_mc_devm_action_put_device(void *data)
{ … }
struct tegra_mc *devm_tegra_memory_controller_get(struct device *dev)
{ … }
EXPORT_SYMBOL_GPL(…);
int tegra_mc_probe_device(struct tegra_mc *mc, struct device *dev)
{ … }
EXPORT_SYMBOL_GPL(…);
int tegra_mc_get_carveout_info(struct tegra_mc *mc, unsigned int id,
phys_addr_t *base, u64 *size)
{ … }
EXPORT_SYMBOL_GPL(…);
static int tegra_mc_block_dma_common(struct tegra_mc *mc,
const struct tegra_mc_reset *rst)
{ … }
static bool tegra_mc_dma_idling_common(struct tegra_mc *mc,
const struct tegra_mc_reset *rst)
{ … }
static int tegra_mc_unblock_dma_common(struct tegra_mc *mc,
const struct tegra_mc_reset *rst)
{ … }
static int tegra_mc_reset_status_common(struct tegra_mc *mc,
const struct tegra_mc_reset *rst)
{ … }
const struct tegra_mc_reset_ops tegra_mc_reset_ops_common = …;
static inline struct tegra_mc *reset_to_mc(struct reset_controller_dev *rcdev)
{ … }
static const struct tegra_mc_reset *tegra_mc_reset_find(struct tegra_mc *mc,
unsigned long id)
{ … }
static int tegra_mc_hotreset_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{ … }
static int tegra_mc_hotreset_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{ … }
static int tegra_mc_hotreset_status(struct reset_controller_dev *rcdev,
unsigned long id)
{ … }
static const struct reset_control_ops tegra_mc_reset_ops = …;
static int tegra_mc_reset_setup(struct tegra_mc *mc)
{ … }
int tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate)
{ … }
EXPORT_SYMBOL_GPL(…);
unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc)
{ … }
EXPORT_SYMBOL_GPL(…);
#if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \
defined(CONFIG_ARCH_TEGRA_114_SOC) || \
defined(CONFIG_ARCH_TEGRA_124_SOC) || \
defined(CONFIG_ARCH_TEGRA_132_SOC) || \
defined(CONFIG_ARCH_TEGRA_210_SOC)
static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc)
{
unsigned long long tick;
unsigned int i;
u32 value;
tick = (unsigned long long)mc->tick * clk_get_rate(mc->clk);
do_div(tick, NSEC_PER_SEC);
value = mc_readl(mc, MC_EMEM_ARB_CFG);
value &= ~MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK;
value |= MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(tick);
mc_writel(mc, value, MC_EMEM_ARB_CFG);
for (i = 0; i < mc->soc->num_clients; i++) {
const struct tegra_mc_client *client = &mc->soc->clients[i];
u32 value;
value = mc_readl(mc, client->regs.la.reg);
value &= ~(client->regs.la.mask << client->regs.la.shift);
value |= (client->regs.la.def & client->regs.la.mask) << client->regs.la.shift;
mc_writel(mc, value, client->regs.la.reg);
}
mc_writel(mc, MC_TIMING_UPDATE, MC_TIMING_CONTROL);
return 0;
}
static int load_one_timing(struct tegra_mc *mc,
struct tegra_mc_timing *timing,
struct device_node *node)
{
int err;
u32 tmp;
err = of_property_read_u32(node, "clock-frequency", &tmp);
if (err) {
dev_err(mc->dev,
"timing %pOFn: failed to read rate\n", node);
return err;
}
timing->rate = tmp;
timing->emem_data = devm_kcalloc(mc->dev, mc->soc->num_emem_regs,
sizeof(u32), GFP_KERNEL);
if (!timing->emem_data)
return -ENOMEM;
err = of_property_read_u32_array(node, "nvidia,emem-configuration",
timing->emem_data,
mc->soc->num_emem_regs);
if (err) {
dev_err(mc->dev,
"timing %pOFn: failed to read EMEM configuration\n",
node);
return err;
}
return 0;
}
static int load_timings(struct tegra_mc *mc, struct device_node *node)
{
struct device_node *child;
struct tegra_mc_timing *timing;
int child_count = of_get_child_count(node);
int i = 0, err;
mc->timings = devm_kcalloc(mc->dev, child_count, sizeof(*timing),
GFP_KERNEL);
if (!mc->timings)
return -ENOMEM;
mc->num_timings = child_count;
for_each_child_of_node(node, child) {
timing = &mc->timings[i++];
err = load_one_timing(mc, timing, child);
if (err) {
of_node_put(child);
return err;
}
}
return 0;
}
static int tegra_mc_setup_timings(struct tegra_mc *mc)
{
struct device_node *node;
u32 ram_code, node_ram_code;
int err;
ram_code = tegra_read_ram_code();
mc->num_timings = 0;
for_each_child_of_node(mc->dev->of_node, node) {
err = of_property_read_u32(node, "nvidia,ram-code",
&node_ram_code);
if (err || (node_ram_code != ram_code))
continue;
err = load_timings(mc, node);
of_node_put(node);
if (err)
return err;
break;
}
if (mc->num_timings == 0)
dev_warn(mc->dev,
"no memory timings for RAM code %u registered\n",
ram_code);
return 0;
}
int tegra30_mc_probe(struct tegra_mc *mc)
{
int err;
mc->clk = devm_clk_get_optional(mc->dev, "mc");
if (IS_ERR(mc->clk)) {
dev_err(mc->dev, "failed to get MC clock: %ld\n", PTR_ERR(mc->clk));
return PTR_ERR(mc->clk);
}
mc_writel(mc, 0x00000000, MC_TIMING_CONTROL_DBG);
err = tegra_mc_setup_latency_allowance(mc);
if (err < 0) {
dev_err(mc->dev, "failed to setup latency allowance: %d\n", err);
return err;
}
err = tegra_mc_setup_timings(mc);
if (err < 0) {
dev_err(mc->dev, "failed to setup timings: %d\n", err);
return err;
}
return 0;
}
const struct tegra_mc_ops tegra30_mc_ops = {
.probe = tegra30_mc_probe,
.handle_irq = tegra30_mc_handle_irq,
};
#endif
static int mc_global_intstatus_to_channel(const struct tegra_mc *mc, u32 status,
unsigned int *mc_channel)
{ … }
static u32 mc_channel_to_global_intstatus(const struct tegra_mc *mc,
unsigned int channel)
{ … }
irqreturn_t tegra30_mc_handle_irq(int irq, void *data)
{ … }
const char *const tegra_mc_status_names[32] = …;
const char *const tegra_mc_error_names[8] = …;
struct icc_node *tegra_mc_icc_xlate(const struct of_phandle_args *spec, void *data)
{ … }
static int tegra_mc_icc_get(struct icc_node *node, u32 *average, u32 *peak)
{ … }
static int tegra_mc_icc_set(struct icc_node *src, struct icc_node *dst)
{ … }
const struct tegra_mc_icc_ops tegra_mc_icc_ops = …;
static int tegra_mc_interconnect_setup(struct tegra_mc *mc)
{ … }
static void tegra_mc_num_channel_enabled(struct tegra_mc *mc)
{ … }
static int tegra_mc_probe(struct platform_device *pdev)
{ … }
static void tegra_mc_sync_state(struct device *dev)
{ … }
static struct platform_driver tegra_mc_driver = …;
static int tegra_mc_init(void)
{ … }
arch_initcall(tegra_mc_init);
MODULE_AUTHOR(…) …;
MODULE_DESCRIPTION(…) …;