blob: 3e79e18e95289aa206a0c4bc3521b604c5f37bac [file] [log] [blame]
/*
* Copyright (c) 2017, Amlogic, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/irqreturn.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include "optee_smc.h"
#include "optee_private.h"
#define SRC_IRQ_NAME "viu-vsync"
#define DST_IRQ_NAME "wm-vsync"
static int g_irq_id = 0;
static uint32_t check_wm_status(void)
{
struct arm_smccc_res res;
arm_smccc_smc(OPTEE_SMC_CHECK_WM_STATUS, 0, 0, 0, 0, 0, 0, 0, &res);
return res.a0;
}
static uint32_t flush_wm(void)
{
struct arm_smccc_res res;
arm_smccc_smc(OPTEE_SMC_FLUSH_WM, 0, 0, 0, 0, 0, 0, 0, &res);
return res.a0;
}
static irqreturn_t vsync_isr(int irq, void *dev_id)
{
flush_wm();
return IRQ_HANDLED;
}
void parse_soc(char *src, char soc[32])
{
strcpy(soc, src + strlen("amlogic, "));
if (strcmp(soc, "s4d") == 0)
soc[2] = '\0';
}
static int get_wm_irq_id(void)
{
int irq_id = 0;
struct device_node *root_node = of_find_node_by_path("/");
struct property *root_prop = NULL;
char soc[32] = { '\0' };
char com_val_meson[32] = {"amlogic, meson-"};
char com_val_fb[32] = {"amlogic, fb-"};
struct device_node *com_node = NULL;
for (root_prop = root_node->properties; root_prop; root_prop = root_prop->next) {
if (of_prop_cmp(root_prop->name, "compatible") == 0) {
parse_soc((char *)root_prop->value, soc);
strcat(com_val_meson, soc);
com_node = of_find_compatible_node(NULL, NULL, com_val_meson);
if (com_node) {
irq_id = of_irq_get_byname(com_node, SRC_IRQ_NAME);
goto exit;
}
strcat(com_val_fb, soc);
com_node = of_find_compatible_node(NULL, NULL, com_val_fb);
if (com_node) {
irq_id = of_irq_get_byname(com_node, SRC_IRQ_NAME);
goto exit;
}
}
}
exit:
if (irq_id <= 0) {
pr_err("SOC: %s; node: %p; node compatible value: %s/%s; interrupt name: %s; interrupt id: %d;\n",
soc, com_node, com_val_meson, com_val_fb,
SRC_IRQ_NAME, irq_id);
pr_err("not found %s interrupt\n", SRC_IRQ_NAME);
}
return irq_id;
}
int optee_wm_irq_register(void)
{
uint32_t wm_sts = 0;
int err_num = 0;
wm_sts = check_wm_status();
if (wm_sts) {
pr_info("checking watermark status return 0x%08X\n", wm_sts);
return -1;
}
g_irq_id = get_wm_irq_id();
pr_info("%s interrupt id: %d\n", DST_IRQ_NAME, g_irq_id);
err_num = request_irq(g_irq_id, &vsync_isr, IRQF_SHARED, DST_IRQ_NAME, (void *)&g_irq_id);
if (err_num)
pr_err("can't request %s interrupt for vsync, err_num = %d\n", DST_IRQ_NAME, -err_num);
return -1;
}
void optee_wm_irq_free(void)
{
if (g_irq_id > 0)
free_irq(g_irq_id, (void *)&g_irq_id);
}