summaryrefslogtreecommitdiff
path: root/platform/exynos/lwis_platform_exynos.c
blob: 64cda9230064277bde342b9e9a4e862d312034be (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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
 * Google LWIS Lwis Exynos-specific platform functions
 *
 * Copyright (c) 2018 Google, LLC
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/slab.h>
#include <linux/pm_qos.h>
#include <linux/iommu.h>
#include <linux/exynos_iovmm.h>
#include <linux/of.h>

#include "lwis_platform.h"
#include "lwis_platform_exynos.h"

int lwis_platform_probe(struct lwis_device *lwis_dev)
{
	struct lwis_platform *platform;
	BUG_ON(!lwis_dev);
	platform = kzalloc(sizeof(struct lwis_platform), GFP_KERNEL);
	if (IS_ERR_OR_NULL(platform)) {
		return -ENOMEM;
	}
	lwis_dev->platform = platform;

	/* Enable runtime power management for the platform device */
	pm_runtime_enable(&lwis_dev->plat_dev->dev);

	return 0;
}

static int __attribute__((unused))
iovmm_fault_handler(struct iommu_domain *domain, struct device *dev,
		    unsigned long fault_addr, int fault_flag, void *token)
{
	struct lwis_device *lwis_dev = (struct lwis_device *)token;
	pr_err("IOVMM Fault - Addr: %016llx Flag: %08x Device: %p\n",
	       fault_addr, fault_flag, lwis_dev);
	return -EINVAL;
}

int lwis_platform_device_enable(struct lwis_device *lwis_dev)
{
	int ret;
	struct lwis_platform *platform;
	// TODO: Refactor
	const uint32_t int_cam_qos = 680000;
	const uint32_t int_qos = 465000;
	const uint32_t mif_qos = 2093000;
	const uint32_t cam_qos = 680000;
	const uint32_t hpg_qos = 1;
#if defined(CONFIG_SOC_GS101)
	const uint32_t tnr_qos = 664000;
#endif
	BUG_ON(!lwis_dev);
	platform = lwis_dev->platform;
	if (!platform) {
		return -ENODEV;
	}

	/* Upref the runtime power management controls for the platform dev */
	ret = pm_runtime_get_sync(&lwis_dev->plat_dev->dev);
	if (ret < 0) {
		pr_err("Unable to enable platform device\n");
		return ret;
	}
	if (lwis_dev->has_iommu) {
		/* Activate IOMMU/SYSMMU for the platform device */
		ret = iovmm_activate(&lwis_dev->plat_dev->dev);
		if (ret < 0) {
			pr_err("Failed to enable IOMMU for the device: %d\n",
			       ret);
			return ret;
		}
		/* Set SYSMMU fault handler */
		iovmm_set_fault_handler(&lwis_dev->plat_dev->dev,
					iovmm_fault_handler, lwis_dev);
	}
	/* Set hardcoded DVFS levels */
	if (!pm_qos_request_active(&platform->pm_qos_int_cam))
		pm_qos_add_request(&platform->pm_qos_int_cam,
				   PM_QOS_INTCAM_THROUGHPUT, int_cam_qos);
	if (!pm_qos_request_active(&platform->pm_qos_int))
		pm_qos_add_request(&platform->pm_qos_int,
				   PM_QOS_DEVICE_THROUGHPUT, int_qos);
	if (!pm_qos_request_active(&platform->pm_qos_mem))
		pm_qos_add_request(&platform->pm_qos_mem, PM_QOS_BUS_THROUGHPUT,
				   mif_qos);
	if (!pm_qos_request_active(&platform->pm_qos_cam))
		pm_qos_add_request(&platform->pm_qos_cam, PM_QOS_CAM_THROUGHPUT,
				   cam_qos);
	if (!pm_qos_request_active(&platform->pm_qos_hpg))
		pm_qos_add_request(&platform->pm_qos_hpg, PM_QOS_CPU_ONLINE_MIN,
				   hpg_qos);
#if defined(CONFIG_SOC_GS101)
	if (!pm_qos_request_active(&platform->pm_qos_tnr))
		pm_qos_add_request(&platform->pm_qos_tnr, PM_QOS_TNR_THROUGHPUT,
				   tnr_qos);
#endif

	return 0;
}

int lwis_platform_device_disable(struct lwis_device *lwis_dev)
{
	int ret;
	struct lwis_platform *platform;
	BUG_ON(!lwis_dev);
	platform = lwis_dev->platform;
	if (!platform) {
		return -ENODEV;
	}

	/* We can't remove fault handlers, so there's no call corresponding
	 * to the iovmm_set_fault_handler above */

	if (pm_qos_request_active(&platform->pm_qos_int_cam))
		pm_qos_remove_request(&platform->pm_qos_int_cam);
	if (pm_qos_request_active(&platform->pm_qos_int))
		pm_qos_remove_request(&platform->pm_qos_int);
	if (pm_qos_request_active(&platform->pm_qos_mem))
		pm_qos_remove_request(&platform->pm_qos_mem);
	if (pm_qos_request_active(&platform->pm_qos_cam))
		pm_qos_remove_request(&platform->pm_qos_cam);
	if (pm_qos_request_active(&platform->pm_qos_hpg))
		pm_qos_remove_request(&platform->pm_qos_hpg);
#if defined(CONFIG_SOC_GS101)
	if (pm_qos_request_active(&platform->pm_qos_tnr))
		pm_qos_remove_request(&platform->pm_qos_tnr);
#endif

	if (lwis_dev->has_iommu) {
		/* Deactivate IOMMU/SYSMMU */
		iovmm_deactivate(&lwis_dev->plat_dev->dev);
	}

	/* Disable platform device */
	ret = pm_runtime_put_sync(&lwis_dev->plat_dev->dev);

	return ret;
}