blob: fec256d99e76e760846cddb6e052e6bf6a7cbc72 [file] [log] [blame]
/*
* Samsung Exynos SoC series NPU driver
*
* Copyright (c) 2017 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include "npu-log.h"
#include "npu-config.h"
#include "npu-exynos.h"
extern struct npu_clk npu_clk_array[];
extern const u32 npu_clk_array_size;
extern const struct npu_clk_ops npu_clk_ops;
extern const struct npu_ctl_ops npu_ctl_ops;
int npu_clk_set_rate(struct device *dev, u32 index, ulong frequency)
{
int ret = 0;
struct clk *clk;
if (index >= npu_clk_array_size) {
npu_err("invalid(%d >= %d) index\n", index, npu_clk_array_size);
ret = -EINVAL;
goto p_err;
}
clk = npu_clk_array[index].clk;
if (IS_ERR_OR_NULL(clk)) {
npu_err("null(%d) in clk\n", index);
ret = -EINVAL;
goto p_err;
}
ret = clk_set_rate(clk, frequency);
if (ret) {
npu_err("fail(%d) in clk_set_rate\n", ret);
goto p_err;
}
p_err:
return ret;
}
ulong npu_clk_get_rate(struct device *dev, u32 index)
{
ulong frequency;
struct clk *clk;
if (index >= npu_clk_array_size) {
npu_err("invalid(%d >= %d) index\n", index, npu_clk_array_size);
frequency = -EINVAL;
goto p_err;
}
clk = npu_clk_array[index].clk;
if (IS_ERR_OR_NULL(clk)) {
npu_err("null(%d) in clk\n", index);
frequency = -EINVAL;
goto p_err;
}
frequency = clk_get_rate(clk);
p_err:
npu_info("%s : %ld(Mhz)\n", npu_clk_array[index].name, frequency/1000000);
return frequency;
}
int npu_clk_enable(struct device *dev, u32 index)
{
int ret = 0;
struct clk *clk;
if (index >= npu_clk_array_size) {
npu_err("invalid(%d >= %d) index\n", index, npu_clk_array_size);
ret = -EINVAL;
goto p_err;
}
clk = npu_clk_array[index].clk;
if (IS_ERR_OR_NULL(clk)) {
npu_err("null(%d) in clk\n", index);
ret = -EINVAL;
goto p_err;
}
ret = clk_prepare_enable(clk);
if (ret) {
npu_err("fail(%s) in clk_prepare_enable\n", npu_clk_array[index].name);
goto p_err;
}
p_err:
return ret;
}
int npu_clk_disable(struct device *dev, u32 index)
{
int ret = 0;
struct clk *clk;
if (index >= npu_clk_array_size) {
npu_err("invalid(%d >= %d) index\n", index, npu_clk_array_size);
ret = -EINVAL;
goto p_err;
}
clk = npu_clk_array[index].clk;
if (IS_ERR_OR_NULL(clk)) {
npu_err("null(%d) in clk\n", index);
ret = -EINVAL;
goto p_err;
}
clk_disable_unprepare(clk);
p_err:
return ret;
}
static int npu_exynos_clk_init(struct device *dev)
{
int ret = 0;
const char *name;
struct clk *clk;
u32 index;
for (index = 0; index < npu_clk_array_size; ++index) {
name = npu_clk_array[index].name;
if (!name) {
probe_err("name is NULL\n");
ret = -EINVAL;
break;
}
clk = clk_get(dev, name);
if (IS_ERR_OR_NULL(clk)) {
probe_err("%s clk is not found\n", name);
ret = -EINVAL;
break;
}
npu_clk_array[index].clk = clk;
}
return ret;
}
int npu_exynos_probe(struct npu_exynos *exynos, struct device *dev,
void *regs, void *ram0, void *ram1)
{
int ret = 0;
BUG_ON(!exynos);
BUG_ON(!dev);
exynos->regbase = regs;
exynos->ram0base = ram0;
exynos->ram1base = ram1;
exynos->clk_ops = &npu_clk_ops;
//exynos->ctl_ops = &npu_ctl_ops;
exynos->pinctrl = devm_pinctrl_get(dev);
if (IS_ERR_OR_NULL(exynos->pinctrl)) {
probe_err("devm_pinctrl_get is fail");
ret = PTR_ERR(exynos->pinctrl);
goto p_err;
}
ret = npu_exynos_clk_init(dev);
if (ret) {
probe_err("npu_exynos_clk_init is fail(%d)", ret);
goto p_err;
}
BUG_ON(!exynos);
BUG_ON(!dev);
p_err:
return ret;
}
void npu_readl(void __iomem *base_addr, struct npu_reg *reg, u32 *val)
{
*val = readl(base_addr + reg->offset);
npu_info("[REG][%s][0x%04X], val(R):[0x%08X]\n", reg->name, reg->offset, *val);
}
void npu_writel(void __iomem *base_addr, struct npu_reg *reg, u32 val)
{
npu_info("[REG][%s][0x%04X], val(W):[0x%08X]\n", reg->name, reg->offset, val);
writel(val, base_addr + reg->offset);
}
void npu_readf(void __iomem *base_addr, struct npu_reg *reg, struct npu_field *field, u32 *val)
{
*val = (readl(base_addr + reg->offset) >> (field->bit_start)) & ((1 << (field->bit_width)) - 1);
npu_info("[REG][%s][%s][0x%04X], val(R):[0x%08X]\n", reg->name, field->name, reg->offset, *val);
}
void npu_writef(void __iomem *base_addr, struct npu_reg *reg, struct npu_field *field, u32 val)
{
u32 mask, temp;
mask = ((1 << field->bit_width) - 1);
temp = readl(base_addr + reg->offset) & ~(mask << field->bit_start);
temp |= (val & mask) << (field->bit_start);
npu_info("[REG][%s][%s][0x%04X], val(W):[0x%08X]\n", reg->name, field->name, reg->offset, val);
writel(temp, base_addr + reg->offset);
}