summaryrefslogtreecommitdiff
path: root/optee/watermark.c
blob: 36577dc6c0cca49ce0fc906e33313f52af8ef80b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
 * 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 OPTEE_WM_DEBUG      0

#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;
}

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 = NULL;
	char compatible_val[32] = {"amlogic, meson-"};
	struct device_node *compatible_node = NULL;

	for (root_prop = root_node->properties; root_prop; root_prop = root_prop->next) {
		if (of_prop_cmp(root_prop->name, "compatible") == 0) {
			soc = ((char *)root_prop->value) + strlen("amlogic, ");
			strcat(compatible_val, soc);
			compatible_node = of_find_compatible_node(NULL, NULL, compatible_val);
			if (compatible_node)
				irq_id = of_irq_get_byname(compatible_node, SRC_IRQ_NAME);
			goto exit;
		}
	}

exit:
	if (irq_id <= 0) {
		pr_err("SOC: %s; node: %p; node compatible value: %s; interrupt name: %s; interrupt id: %d;\n",
				soc, compatible_node, compatible_val,
				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) {
#ifdef OPTEE_WM_DEBUG
		pr_info("checking watermark status return 0x%08X\n", wm_sts);
#endif
		return -1;
	}

	g_irq_id = get_wm_irq_id();
#ifdef OPTEE_WM_DEBUG
	pr_info("%s interrupt id: %d\n", DST_IRQ_NAME, g_irq_id);
#endif

	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);
}