mirror of
https://github.com/hardkernel/kernel_common_drivers.git
synced 2026-06-25 12:03:48 +09:00
07a3857d46
PD#SWPL-176790 Problem: S6: support read cali data Solution: S6: support read cali data Verify: S6 BL208 Change-Id: I3c3d7ba9f6b9ad619141ef0496b74c6648007d4a Signed-off-by: Zhongfu Luo <zhongfu.luo@amlogic.com>
399 lines
8.0 KiB
C
399 lines
8.0 KiB
C
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include <linux/cdev.h>
|
|
#include <linux/types.h>
|
|
#include <linux/device.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/arm-smccc.h>
|
|
#include <linux/highmem.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/io.h>
|
|
#include <linux/amlogic/efuse.h>
|
|
#include <linux/kallsyms.h>
|
|
#include "efuse.h"
|
|
#include <linux/amlogic/secmon.h>
|
|
|
|
static ssize_t meson_efuse_fn_smc(struct efuse_hal_api_arg *arg)
|
|
{
|
|
long ret;
|
|
unsigned int cmd, offset, size;
|
|
unsigned long *retcnt = (unsigned long *)(arg->retcnt);
|
|
struct arm_smccc_res res;
|
|
|
|
if (arg->cmd == EFUSE_HAL_API_READ)
|
|
cmd = efuse_cmd.read_cmd;
|
|
else if (arg->cmd == EFUSE_HAL_API_WRITE)
|
|
cmd = efuse_cmd.write_cmd;
|
|
else
|
|
return -1;
|
|
|
|
offset = arg->offset;
|
|
size = arg->size;
|
|
|
|
meson_sm_mutex_lock();
|
|
|
|
if (arg->cmd == EFUSE_HAL_API_WRITE)
|
|
memcpy((void *)sharemem_input_base,
|
|
(const void *)arg->buffer, size);
|
|
|
|
asm __volatile__("" : : : "memory");
|
|
|
|
arm_smccc_smc(cmd, offset, size, 0, 0, 0, 0, 0, &res);
|
|
ret = res.a0;
|
|
*retcnt = res.a0;
|
|
|
|
if ((arg->cmd == EFUSE_HAL_API_READ) && (ret != 0))
|
|
memcpy((void *)arg->buffer,
|
|
(const void *)sharemem_output_base, ret);
|
|
|
|
meson_sm_mutex_unlock();
|
|
|
|
if (!ret)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t meson_trustzone_efuse(struct efuse_hal_api_arg *arg)
|
|
{
|
|
ssize_t ret;
|
|
struct cpumask task_cpumask;
|
|
|
|
if (!arg)
|
|
return -1;
|
|
|
|
cpumask_copy(&task_cpumask, current->cpus_ptr);
|
|
set_cpus_allowed_ptr(current, cpumask_of(0));
|
|
|
|
ret = meson_efuse_fn_smc(arg);
|
|
set_cpus_allowed_ptr(current, &task_cpumask);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static unsigned long efuse_data_process(unsigned long type,
|
|
unsigned long buffer,
|
|
unsigned long length,
|
|
unsigned long option)
|
|
{
|
|
struct arm_smccc_res res;
|
|
|
|
meson_sm_mutex_lock();
|
|
|
|
memcpy((void *)sharemem_input_base,
|
|
(const void *)buffer, length);
|
|
|
|
asm __volatile__("" : : : "memory");
|
|
|
|
do {
|
|
arm_smccc_smc((unsigned long)AML_DATA_PROCESS,
|
|
(unsigned long)type,
|
|
(unsigned long)get_secmon_phy_input_base(),
|
|
(unsigned long)length,
|
|
(unsigned long)option,
|
|
0, 0, 0, &res);
|
|
} while (0);
|
|
|
|
meson_sm_mutex_unlock();
|
|
|
|
return res.a0;
|
|
}
|
|
|
|
int efuse_amlogic_cali_item_read(unsigned int item)
|
|
{
|
|
struct arm_smccc_res res;
|
|
|
|
if (efuse_cali_item_read != 1)
|
|
return -EINVAL;
|
|
|
|
/* range check */
|
|
if (item < EFUSE_CALI_SUBITEM_WHOBURN ||
|
|
item > EFUSE_CALI_SUBITEM_MAX)
|
|
return -EINVAL;
|
|
|
|
meson_sm_mutex_lock();
|
|
|
|
do {
|
|
arm_smccc_smc((unsigned long)EFUSE_READ_CALI_ITEM,
|
|
(unsigned long)item,
|
|
0, 0, 0, 0, 0, 0, &res);
|
|
} while (0);
|
|
|
|
meson_sm_mutex_unlock();
|
|
return res.a0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(efuse_amlogic_cali_item_read);
|
|
|
|
/*
|
|
*return: 1: wrote, 0: not write, -1: fail or not support
|
|
*/
|
|
int efuse_amlogic_check_lockable_item(unsigned int item)
|
|
{
|
|
struct arm_smccc_res res;
|
|
|
|
/* range check */
|
|
if (item < EFUSE_LOCK_SUBITEM_BASE ||
|
|
item > EFUSE_LOCK_SUBITEM_MAX)
|
|
return -EINVAL;
|
|
|
|
meson_sm_mutex_lock();
|
|
|
|
do {
|
|
arm_smccc_smc((unsigned long)EFUSE_READ_CALI_ITEM,
|
|
(unsigned long)item,
|
|
0, 0, 0, 0, 0, 0, &res);
|
|
} while (0);
|
|
|
|
meson_sm_mutex_unlock();
|
|
return res.a0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(efuse_amlogic_check_lockable_item);
|
|
|
|
unsigned long efuse_amlogic_set(char *buf, size_t count)
|
|
{
|
|
unsigned long ret;
|
|
struct cpumask task_cpumask;
|
|
|
|
cpumask_copy(&task_cpumask, current->cpus_ptr);
|
|
set_cpus_allowed_ptr(current, cpumask_of(0));
|
|
|
|
ret = efuse_data_process(AML_D_P_W_EFUSE_AMLOGIC,
|
|
(unsigned long)buf, (unsigned long)count, 0);
|
|
set_cpus_allowed_ptr(current, &task_cpumask);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static u32 meson_efuse_obj_read(u32 obj_id, u8 *buff, u32 *size)
|
|
{
|
|
u32 rc = EFUSE_OBJ_ERR_UNKNOWN;
|
|
u32 len = 0;
|
|
struct arm_smccc_res res;
|
|
|
|
meson_sm_mutex_lock();
|
|
|
|
memcpy((void *)sharemem_input_base, buff, *size);
|
|
|
|
do {
|
|
arm_smccc_smc((unsigned long)EFUSE_OBJ_READ,
|
|
(unsigned long)obj_id,
|
|
(unsigned long)*size,
|
|
0, 0, 0, 0, 0, &res);
|
|
|
|
} while (0);
|
|
|
|
rc = res.a0;
|
|
len = res.a1;
|
|
|
|
if (rc == EFUSE_OBJ_SUCCESS) {
|
|
if (*size >= len) {
|
|
memcpy(buff, (const void *)sharemem_output_base, len);
|
|
*size = len;
|
|
} else {
|
|
rc = EFUSE_OBJ_ERR_SIZE;
|
|
}
|
|
}
|
|
|
|
meson_sm_mutex_unlock();
|
|
|
|
return rc;
|
|
}
|
|
|
|
static u32 meson_efuse_obj_write(u32 obj_id, u8 *buff, u32 size)
|
|
{
|
|
struct arm_smccc_res res;
|
|
|
|
meson_sm_mutex_lock();
|
|
|
|
memcpy((void *)sharemem_input_base, buff, size);
|
|
|
|
do {
|
|
arm_smccc_smc((unsigned long)EFUSE_OBJ_WRITE,
|
|
(unsigned long)obj_id,
|
|
(unsigned long)size,
|
|
0, 0, 0, 0, 0, &res);
|
|
|
|
} while (0);
|
|
|
|
meson_sm_mutex_unlock();
|
|
|
|
return res.a0;
|
|
}
|
|
|
|
u32 efuse_obj_write(u32 obj_id, char *name, u8 *buff, u32 size)
|
|
{
|
|
u32 ret;
|
|
struct efuse_obj_field_t efuseinfo;
|
|
struct cpumask task_cpumask;
|
|
|
|
if (efuse_obj_cmd_status != 1)
|
|
return EFUSE_OBJ_ERR_NOT_FOUND;
|
|
|
|
cpumask_copy(&task_cpumask, current->cpus_ptr);
|
|
set_cpus_allowed_ptr(current, cpumask_of(0));
|
|
|
|
memset(&efuseinfo, 0, sizeof(efuseinfo));
|
|
strncpy(efuseinfo.name, name, sizeof(efuseinfo.name) - 1);
|
|
if (size > sizeof(efuseinfo.data))
|
|
return EFUSE_OBJ_ERR_SIZE;
|
|
efuseinfo.size = size;
|
|
memcpy(efuseinfo.data, buff, efuseinfo.size);
|
|
ret = meson_efuse_obj_write(obj_id, (uint8_t *)&efuseinfo, sizeof(efuseinfo));
|
|
set_cpus_allowed_ptr(current, &task_cpumask);
|
|
|
|
return ret;
|
|
}
|
|
|
|
u32 efuse_obj_read(u32 obj_id, char *name, u8 *buff, u32 *size)
|
|
{
|
|
u32 ret;
|
|
struct efuse_obj_field_t efuseinfo;
|
|
struct cpumask task_cpumask;
|
|
|
|
if (efuse_obj_cmd_status != 1)
|
|
return EFUSE_OBJ_ERR_NOT_FOUND;
|
|
|
|
cpumask_copy(&task_cpumask, current->cpus_ptr);
|
|
set_cpus_allowed_ptr(current, cpumask_of(0));
|
|
|
|
memset(&efuseinfo, 0, sizeof(efuseinfo));
|
|
strncpy(efuseinfo.name, name, sizeof(efuseinfo.name) - 1);
|
|
*size = sizeof(efuseinfo);
|
|
ret = meson_efuse_obj_read(obj_id, (uint8_t *)&efuseinfo, size);
|
|
memcpy(buff, efuseinfo.data, efuseinfo.size);
|
|
*size = efuseinfo.size;
|
|
set_cpus_allowed_ptr(current, &task_cpumask);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(efuse_obj_read);
|
|
|
|
static ssize_t meson_trustzone_efuse_get_max(struct efuse_hal_api_arg *arg)
|
|
{
|
|
ssize_t ret;
|
|
unsigned int cmd;
|
|
struct arm_smccc_res res;
|
|
|
|
if (arg->cmd != EFUSE_HAL_API_USER_MAX)
|
|
return -1;
|
|
|
|
meson_sm_mutex_lock();
|
|
|
|
cmd = efuse_cmd.get_max_cmd;
|
|
|
|
asm __volatile__("" : : : "memory");
|
|
arm_smccc_smc(cmd, 0, 0, 0, 0, 0, 0, 0, &res);
|
|
ret = res.a0;
|
|
|
|
meson_sm_mutex_unlock();
|
|
|
|
if (!ret)
|
|
return -1;
|
|
|
|
return ret;
|
|
}
|
|
|
|
ssize_t efuse_get_max(void)
|
|
{
|
|
struct efuse_hal_api_arg arg;
|
|
ssize_t ret;
|
|
struct cpumask task_cpumask;
|
|
|
|
arg.cmd = EFUSE_HAL_API_USER_MAX;
|
|
|
|
cpumask_copy(&task_cpumask, current->cpus_ptr);
|
|
set_cpus_allowed_ptr(current, cpumask_of(0));
|
|
|
|
ret = meson_trustzone_efuse_get_max(&arg);
|
|
set_cpus_allowed_ptr(current, &task_cpumask);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t _efuse_read(char *buf, size_t count, loff_t *ppos)
|
|
{
|
|
unsigned int pos = *ppos;
|
|
|
|
struct efuse_hal_api_arg arg;
|
|
unsigned long retcnt;
|
|
ssize_t ret;
|
|
|
|
arg.cmd = EFUSE_HAL_API_READ;
|
|
arg.offset = pos;
|
|
arg.size = count;
|
|
arg.buffer = (unsigned long)buf;
|
|
arg.retcnt = (unsigned long)&retcnt;
|
|
ret = meson_trustzone_efuse(&arg);
|
|
if (ret == 0) {
|
|
*ppos += retcnt;
|
|
return retcnt;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t _efuse_write(const char *buf, size_t count, loff_t *ppos)
|
|
{
|
|
unsigned int pos = *ppos;
|
|
|
|
struct efuse_hal_api_arg arg;
|
|
unsigned long retcnt;
|
|
ssize_t ret;
|
|
|
|
arg.cmd = EFUSE_HAL_API_WRITE;
|
|
arg.offset = pos;
|
|
arg.size = count;
|
|
arg.buffer = (unsigned long)buf;
|
|
arg.retcnt = (unsigned long)&retcnt;
|
|
|
|
ret = meson_trustzone_efuse(&arg);
|
|
if (ret == 0) {
|
|
*ppos = retcnt;
|
|
return retcnt;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
ssize_t efuse_read_usr(char *buf, size_t count, loff_t *ppos)
|
|
{
|
|
char *pdata = NULL;
|
|
ssize_t ret;
|
|
loff_t pos;
|
|
|
|
pdata = kmalloc(count, GFP_KERNEL);
|
|
if (!pdata)
|
|
return -ENOMEM;
|
|
|
|
pos = *ppos;
|
|
|
|
ret = _efuse_read(pdata, count, (loff_t *)&pos);
|
|
|
|
memcpy(buf, pdata, count);
|
|
kfree(pdata);
|
|
|
|
return ret;
|
|
}
|
|
|
|
ssize_t efuse_write_usr(char *buf, size_t count, loff_t *ppos)
|
|
{
|
|
char *pdata = NULL;
|
|
ssize_t ret;
|
|
loff_t pos;
|
|
|
|
pdata = kmalloc(count, GFP_KERNEL);
|
|
if (!pdata)
|
|
return -ENOMEM;
|
|
|
|
memcpy(pdata, buf, count);
|
|
pos = *ppos;
|
|
|
|
ret = _efuse_write(pdata, count, (loff_t *)&pos);
|
|
kfree(pdata);
|
|
|
|
return ret;
|
|
}
|