summaryrefslogtreecommitdiff
path: root/drivers/net/ipa/ipa_reg.c
blob: 65d747200be3cb230a6c95deadd4ff15ae03ff71 (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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// SPDX-License-Identifier: GPL-2.0

/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
 * Copyright (C) 2019-2022 Linaro Ltd.
 */

#include <linux/io.h>

#include "ipa.h"
#include "ipa_reg.h"

/* Is this register ID valid for the current IPA version? */
static bool ipa_reg_id_valid(struct ipa *ipa, enum ipa_reg_id reg_id)
{
	enum ipa_version version = ipa->version;
	bool valid;

	/* Check for bogus (out of range) register IDs */
	if ((u32)reg_id >= ipa->regs->reg_count)
		return false;

	switch (reg_id) {
	case IPA_BCR:
	case COUNTER_CFG:
		valid = version < IPA_VERSION_4_5;
		break;

	case IPA_TX_CFG:
	case FLAVOR_0:
	case IDLE_INDICATION_CFG:
		valid = version >= IPA_VERSION_3_5;
		break;

	case QTIME_TIMESTAMP_CFG:
	case TIMERS_XO_CLK_DIV_CFG:
	case TIMERS_PULSE_GRAN_CFG:
		valid = version >= IPA_VERSION_4_5;
		break;

	case SRC_RSRC_GRP_45_RSRC_TYPE:
	case DST_RSRC_GRP_45_RSRC_TYPE:
		valid = version <= IPA_VERSION_3_1 ||
			version == IPA_VERSION_4_5;
		break;

	case SRC_RSRC_GRP_67_RSRC_TYPE:
	case DST_RSRC_GRP_67_RSRC_TYPE:
		valid = version <= IPA_VERSION_3_1;
		break;

	case ENDP_FILTER_ROUTER_HSH_CFG:
		valid = version != IPA_VERSION_4_2;
		break;

	case IRQ_SUSPEND_EN:
	case IRQ_SUSPEND_CLR:
		valid = version >= IPA_VERSION_3_1;
		break;

	case COMP_CFG:
	case CLKON_CFG:
	case ROUTE:
	case SHARED_MEM_SIZE:
	case QSB_MAX_WRITES:
	case QSB_MAX_READS:
	case FILT_ROUT_HASH_EN:
	case FILT_ROUT_CACHE_CFG:
	case FILT_ROUT_HASH_FLUSH:
	case FILT_ROUT_CACHE_FLUSH:
	case STATE_AGGR_ACTIVE:
	case LOCAL_PKT_PROC_CNTXT:
	case AGGR_FORCE_CLOSE:
	case SRC_RSRC_GRP_01_RSRC_TYPE:
	case SRC_RSRC_GRP_23_RSRC_TYPE:
	case DST_RSRC_GRP_01_RSRC_TYPE:
	case DST_RSRC_GRP_23_RSRC_TYPE:
	case ENDP_INIT_CTRL:
	case ENDP_INIT_CFG:
	case ENDP_INIT_NAT:
	case ENDP_INIT_HDR:
	case ENDP_INIT_HDR_EXT:
	case ENDP_INIT_HDR_METADATA_MASK:
	case ENDP_INIT_MODE:
	case ENDP_INIT_AGGR:
	case ENDP_INIT_HOL_BLOCK_EN:
	case ENDP_INIT_HOL_BLOCK_TIMER:
	case ENDP_INIT_DEAGGR:
	case ENDP_INIT_RSRC_GRP:
	case ENDP_INIT_SEQ:
	case ENDP_STATUS:
	case ENDP_FILTER_CACHE_CFG:
	case ENDP_ROUTER_CACHE_CFG:
	case IPA_IRQ_STTS:
	case IPA_IRQ_EN:
	case IPA_IRQ_CLR:
	case IPA_IRQ_UC:
	case IRQ_SUSPEND_INFO:
		valid = true;	/* These should be defined for all versions */
		break;

	default:
		valid = false;
		break;
	}

	/* To be valid, it must be defined */

	return valid && ipa->regs->reg[reg_id];
}

const struct ipa_reg *ipa_reg(struct ipa *ipa, enum ipa_reg_id reg_id)
{
	if (WARN_ON(!ipa_reg_id_valid(ipa, reg_id)))
		return NULL;

	return ipa->regs->reg[reg_id];
}

static const struct ipa_regs *ipa_regs(enum ipa_version version)
{
	switch (version) {
	case IPA_VERSION_3_1:
		return &ipa_regs_v3_1;
	case IPA_VERSION_3_5_1:
		return &ipa_regs_v3_5_1;
	case IPA_VERSION_4_2:
		return &ipa_regs_v4_2;
	case IPA_VERSION_4_5:
		return &ipa_regs_v4_5;
	case IPA_VERSION_4_7:
		return &ipa_regs_v4_7;
	case IPA_VERSION_4_9:
		return &ipa_regs_v4_9;
	case IPA_VERSION_4_11:
		return &ipa_regs_v4_11;
	default:
		return NULL;
	}
}

int ipa_reg_init(struct ipa *ipa)
{
	struct device *dev = &ipa->pdev->dev;
	const struct ipa_regs *regs;
	struct resource *res;

	regs = ipa_regs(ipa->version);
	if (!regs)
		return -EINVAL;

	if (WARN_ON(regs->reg_count > IPA_REG_ID_COUNT))
		return -EINVAL;

	/* Setup IPA register memory  */
	res = platform_get_resource_byname(ipa->pdev, IORESOURCE_MEM,
					   "ipa-reg");
	if (!res) {
		dev_err(dev, "DT error getting \"ipa-reg\" memory property\n");
		return -ENODEV;
	}

	ipa->reg_virt = ioremap(res->start, resource_size(res));
	if (!ipa->reg_virt) {
		dev_err(dev, "unable to remap \"ipa-reg\" memory\n");
		return -ENOMEM;
	}
	ipa->regs = regs;

	return 0;
}

void ipa_reg_exit(struct ipa *ipa)
{
	iounmap(ipa->reg_virt);
}