summaryrefslogtreecommitdiff
path: root/drivers/edgetpu/abrolhos-pm.c
blob: 8bf40e2ec74b146ee1ab7d1bb6c7096d419db23d (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
// SPDX-License-Identifier: GPL-2.0
/*
 * Abrolhos EdgeTPU power management support
 *
 * Copyright (C) 2020 Google, Inc.
 */

#include <linux/delay.h>
#include <linux/gsa/gsa_tpu.h>
#include <linux/iopoll.h>

#include "edgetpu-config.h"
#include "edgetpu-firmware.h"
#include "edgetpu-internal.h"
#include "edgetpu-pm.h"
#include "mobile-pm.h"

#define TPU_DEFAULT_POWER_STATE		TPU_DEEP_SLEEP_CLOCKS_SLOW

#include "mobile-pm.c"

static int abrolhos_core_pwr_get(void *data, u64 *val)
{
	*val = exynos_acpm_get_rate(TPU_ACPM_DOMAIN,
			TPU_DEBUG_REQ | TPU_CORE_PWR_DEBUG);
	return 0;
}

static int abrolhos_core_pwr_set(void *data, u64 val)
{
	int ret;
	unsigned long dbg_rate_req;

	dbg_rate_req = TPU_DEBUG_REQ | TPU_CORE_PWR_DEBUG;
	dbg_rate_req |= val;

	ret = exynos_acpm_set_rate(TPU_ACPM_DOMAIN, dbg_rate_req);
	return ret;
}

DEFINE_DEBUGFS_ATTRIBUTE(fops_tpu_core_pwr, abrolhos_core_pwr_get,
		abrolhos_core_pwr_set, "%llu\n");

static int abrolhos_pm_after_create(struct edgetpu_dev *etdev)
{
	struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(etdev);
	struct edgetpu_mobile_platform_pwr *platform_pwr = &etmdev->platform_pwr;

	debugfs_create_file("core_pwr", 0660, platform_pwr->debugfs_dir, etdev, &fops_tpu_core_pwr);

	return 0;
}

static void abrolhos_firmware_down(struct edgetpu_dev *etdev)
{
	struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(etdev);

	if (!edgetpu_pchannel_power_down(etdev, false))
		return;

	etdev_warn(etdev, "Firmware shutdown request failed!\n");
	etdev_warn(etdev, "Attempting firmware restart\n");
	if (!edgetpu_firmware_restart_locked(etdev, true) &&
	    !edgetpu_pchannel_power_down(etdev, false))
		return;

	if (etmdev->gsa_dev) {
		etdev_warn(etdev, "Requesting early GSA reset\n");
		/*
		 * p-channel failed, request GSA shutdown to make sure the CPU is
		 * reset.
		 * The GSA->APM request will clear any pending DVFS status from the
		 * CPU.
		 */
		gsa_send_tpu_cmd(etmdev->gsa_dev, GSA_TPU_SHUTDOWN);
	}
}

int edgetpu_chip_pm_create(struct edgetpu_dev *etdev)
{
	struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(etdev);
	struct edgetpu_mobile_platform_pwr *platform_pwr = &etmdev->platform_pwr;

	platform_pwr->firmware_down = abrolhos_firmware_down;
	platform_pwr->after_create = abrolhos_pm_after_create;
	platform_pwr->acpm_set_rate = exynos_acpm_set_rate;

	return mobile_pm_create(etdev);
}