summaryrefslogtreecommitdiff
path: root/drivers/net/ipa/gsi_reg.c
blob: 1412b67304c8e9a12671d84a51c428b2a39660cb (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
146
147
148
149
150
151
// SPDX-License-Identifier: GPL-2.0

/* Copyright (C) 2023 Linaro Ltd. */

#include <linux/platform_device.h>
#include <linux/io.h>

#include "gsi.h"
#include "reg.h"
#include "gsi_reg.h"

/* Is this register ID valid for the current GSI version? */
static bool gsi_reg_id_valid(struct gsi *gsi, enum gsi_reg_id reg_id)
{
	switch (reg_id) {
	case INTER_EE_SRC_CH_IRQ_MSK:
	case INTER_EE_SRC_EV_CH_IRQ_MSK:
	case CH_C_CNTXT_0:
	case CH_C_CNTXT_1:
	case CH_C_CNTXT_2:
	case CH_C_CNTXT_3:
	case CH_C_QOS:
	case CH_C_SCRATCH_0:
	case CH_C_SCRATCH_1:
	case CH_C_SCRATCH_2:
	case CH_C_SCRATCH_3:
	case EV_CH_E_CNTXT_0:
	case EV_CH_E_CNTXT_1:
	case EV_CH_E_CNTXT_2:
	case EV_CH_E_CNTXT_3:
	case EV_CH_E_CNTXT_4:
	case EV_CH_E_CNTXT_8:
	case EV_CH_E_CNTXT_9:
	case EV_CH_E_CNTXT_10:
	case EV_CH_E_CNTXT_11:
	case EV_CH_E_CNTXT_12:
	case EV_CH_E_CNTXT_13:
	case EV_CH_E_SCRATCH_0:
	case EV_CH_E_SCRATCH_1:
	case CH_C_DOORBELL_0:
	case EV_CH_E_DOORBELL_0:
	case GSI_STATUS:
	case CH_CMD:
	case EV_CH_CMD:
	case GENERIC_CMD:
	case HW_PARAM_2:
	case CNTXT_TYPE_IRQ:
	case CNTXT_TYPE_IRQ_MSK:
	case CNTXT_SRC_CH_IRQ:
	case CNTXT_SRC_CH_IRQ_MSK:
	case CNTXT_SRC_CH_IRQ_CLR:
	case CNTXT_SRC_EV_CH_IRQ:
	case CNTXT_SRC_EV_CH_IRQ_MSK:
	case CNTXT_SRC_EV_CH_IRQ_CLR:
	case CNTXT_SRC_IEOB_IRQ:
	case CNTXT_SRC_IEOB_IRQ_MSK:
	case CNTXT_SRC_IEOB_IRQ_CLR:
	case CNTXT_GLOB_IRQ_STTS:
	case CNTXT_GLOB_IRQ_EN:
	case CNTXT_GLOB_IRQ_CLR:
	case CNTXT_GSI_IRQ_STTS:
	case CNTXT_GSI_IRQ_EN:
	case CNTXT_GSI_IRQ_CLR:
	case CNTXT_INTSET:
	case ERROR_LOG:
	case ERROR_LOG_CLR:
	case CNTXT_SCRATCH_0:
		return true;

	default:
		return false;
	}
}

const struct reg *gsi_reg(struct gsi *gsi, enum gsi_reg_id reg_id)
{
	if (WARN(!gsi_reg_id_valid(gsi, reg_id), "invalid reg %u\n", reg_id))
		return NULL;

	return reg(gsi->regs, reg_id);
}

static const struct regs *gsi_regs(struct gsi *gsi)
{
	switch (gsi->version) {
	case IPA_VERSION_3_1:
		return &gsi_regs_v3_1;

	case IPA_VERSION_3_5_1:
		return &gsi_regs_v3_5_1;

	case IPA_VERSION_4_2:
		return &gsi_regs_v4_0;

	case IPA_VERSION_4_5:
	case IPA_VERSION_4_7:
		return &gsi_regs_v4_5;

	case IPA_VERSION_4_9:
		return &gsi_regs_v4_9;

	case IPA_VERSION_4_11:
		return &gsi_regs_v4_11;

	default:
		return NULL;
	}
}

/* Sets gsi->virt and I/O maps the "gsi" memory range for registers */
int gsi_reg_init(struct gsi *gsi, struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct resource *res;
	resource_size_t size;

	/* Get GSI memory range and map it */
	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gsi");
	if (!res) {
		dev_err(dev, "DT error getting \"gsi\" memory property\n");
		return -ENODEV;
	}

	size = resource_size(res);
	if (res->start > U32_MAX || size > U32_MAX - res->start) {
		dev_err(dev, "DT memory resource \"gsi\" out of range\n");
		return -EINVAL;
	}

	gsi->regs = gsi_regs(gsi);
	if (!gsi->regs) {
		dev_err(dev, "unsupported IPA version %u (?)\n", gsi->version);
		return -EINVAL;
	}

	gsi->virt = ioremap(res->start, size);
	if (!gsi->virt) {
		dev_err(dev, "unable to remap \"gsi\" memory\n");
		return -ENOMEM;
	}

	return 0;
}

/* Inverse of gsi_reg_init() */
void gsi_reg_exit(struct gsi *gsi)
{
	iounmap(gsi->virt);
	gsi->virt = NULL;
	gsi->regs = NULL;
}