1ee3e6beaSAlex Elder // SPDX-License-Identifier: GPL-2.0
2ee3e6beaSAlex Elder
3ee3e6beaSAlex Elder /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
4a4388da5SAlex Elder * Copyright (C) 2018-2022 Linaro Ltd.
5ee3e6beaSAlex Elder */
6ee3e6beaSAlex Elder
7ee3e6beaSAlex Elder #include <linux/types.h>
8ee3e6beaSAlex Elder #include <linux/kernel.h>
9ee3e6beaSAlex Elder
10ee3e6beaSAlex Elder #include "ipa.h"
11ee3e6beaSAlex Elder #include "ipa_data.h"
12ee3e6beaSAlex Elder #include "ipa_reg.h"
13ee3e6beaSAlex Elder #include "ipa_resource.h"
14ee3e6beaSAlex Elder
15ee3e6beaSAlex Elder /**
16ee3e6beaSAlex Elder * DOC: IPA Resources
17ee3e6beaSAlex Elder *
18ee3e6beaSAlex Elder * The IPA manages a set of resources internally for various purposes.
19ee3e6beaSAlex Elder * A given IPA version has a fixed number of resource types, and a fixed
20ee3e6beaSAlex Elder * total number of resources of each type. "Source" resource types
21ee3e6beaSAlex Elder * are separate from "destination" resource types.
22ee3e6beaSAlex Elder *
23ee3e6beaSAlex Elder * Each version of IPA also has some number of resource groups. Each
24ee3e6beaSAlex Elder * endpoint is assigned to a resource group, and all endpoints in the
25ee3e6beaSAlex Elder * same group share pools of each type of resource. A subset of the
26ee3e6beaSAlex Elder * total resources of each type is assigned for use by each group.
27ee3e6beaSAlex Elder */
28ee3e6beaSAlex Elder
ipa_resource_limits_valid(struct ipa * ipa,const struct ipa_resource_data * data)29ee3e6beaSAlex Elder static bool ipa_resource_limits_valid(struct ipa *ipa,
30ee3e6beaSAlex Elder const struct ipa_resource_data *data)
31ee3e6beaSAlex Elder {
32ee3e6beaSAlex Elder u32 group_count;
33ee3e6beaSAlex Elder u32 i;
34ee3e6beaSAlex Elder u32 j;
35ee3e6beaSAlex Elder
363219953bSAlex Elder /* We program at most 8 source or destination resource group limits */
373219953bSAlex Elder BUILD_BUG_ON(IPA_RESOURCE_GROUP_MAX > 8);
38ee3e6beaSAlex Elder
394fd704b3SAlex Elder group_count = data->rsrc_group_src_count;
40d9d1cddfSAlex Elder if (!group_count || group_count > IPA_RESOURCE_GROUP_MAX)
41ee3e6beaSAlex Elder return false;
42ee3e6beaSAlex Elder
43ee3e6beaSAlex Elder /* Return an error if a non-zero resource limit is specified
44ee3e6beaSAlex Elder * for a resource group not supported by hardware.
45ee3e6beaSAlex Elder */
46ee3e6beaSAlex Elder for (i = 0; i < data->resource_src_count; i++) {
477336ce1aSAlex Elder const struct ipa_resource *resource;
48ee3e6beaSAlex Elder
49ee3e6beaSAlex Elder resource = &data->resource_src[i];
50d9d1cddfSAlex Elder for (j = group_count; j < IPA_RESOURCE_GROUP_MAX; j++)
51ee3e6beaSAlex Elder if (resource->limits[j].min || resource->limits[j].max)
52ee3e6beaSAlex Elder return false;
53ee3e6beaSAlex Elder }
54ee3e6beaSAlex Elder
5527df68d5SKonrad Dybcio group_count = data->rsrc_group_dst_count;
56d9d1cddfSAlex Elder if (!group_count || group_count > IPA_RESOURCE_GROUP_MAX)
57ee3e6beaSAlex Elder return false;
58ee3e6beaSAlex Elder
59ee3e6beaSAlex Elder for (i = 0; i < data->resource_dst_count; i++) {
607336ce1aSAlex Elder const struct ipa_resource *resource;
61ee3e6beaSAlex Elder
62ee3e6beaSAlex Elder resource = &data->resource_dst[i];
63d9d1cddfSAlex Elder for (j = group_count; j < IPA_RESOURCE_GROUP_MAX; j++)
64ee3e6beaSAlex Elder if (resource->limits[j].min || resource->limits[j].max)
65ee3e6beaSAlex Elder return false;
66ee3e6beaSAlex Elder }
67442d68ebSAlex Elder
68ee3e6beaSAlex Elder return true;
69ee3e6beaSAlex Elder }
70ee3e6beaSAlex Elder
71ee3e6beaSAlex Elder static void
ipa_resource_config_common(struct ipa * ipa,u32 resource_type,const struct reg * reg,const struct ipa_resource_limits * xlimits,const struct ipa_resource_limits * ylimits)721c418c4aSAlex Elder ipa_resource_config_common(struct ipa *ipa, u32 resource_type,
7381772e44SAlex Elder const struct reg *reg,
74ee3e6beaSAlex Elder const struct ipa_resource_limits *xlimits,
75ee3e6beaSAlex Elder const struct ipa_resource_limits *ylimits)
76ee3e6beaSAlex Elder {
77ee3e6beaSAlex Elder u32 val;
78ee3e6beaSAlex Elder
79*f1470fd7SAlex Elder val = reg_encode(reg, X_MIN_LIM, xlimits->min);
80*f1470fd7SAlex Elder val |= reg_encode(reg, X_MAX_LIM, xlimits->max);
81ee3e6beaSAlex Elder if (ylimits) {
82*f1470fd7SAlex Elder val |= reg_encode(reg, Y_MIN_LIM, ylimits->min);
83*f1470fd7SAlex Elder val |= reg_encode(reg, Y_MAX_LIM, ylimits->max);
84ee3e6beaSAlex Elder }
85ee3e6beaSAlex Elder
86fc4cecf7SAlex Elder iowrite32(val, ipa->reg_virt + reg_n_offset(reg, resource_type));
87ee3e6beaSAlex Elder }
88ee3e6beaSAlex Elder
ipa_resource_config_src(struct ipa * ipa,u32 resource_type,const struct ipa_resource_data * data)894bcfb35eSAlex Elder static void ipa_resource_config_src(struct ipa *ipa, u32 resource_type,
9093c03729SAlex Elder const struct ipa_resource_data *data)
91ee3e6beaSAlex Elder {
924fd704b3SAlex Elder u32 group_count = data->rsrc_group_src_count;
93ee3e6beaSAlex Elder const struct ipa_resource_limits *ylimits;
9493c03729SAlex Elder const struct ipa_resource *resource;
9581772e44SAlex Elder const struct reg *reg;
96ee3e6beaSAlex Elder
9793c03729SAlex Elder resource = &data->resource_src[resource_type];
9893c03729SAlex Elder
996a244b75SAlex Elder reg = ipa_reg(ipa, SRC_RSRC_GRP_01_RSRC_TYPE);
100ee3e6beaSAlex Elder ylimits = group_count == 1 ? NULL : &resource->limits[1];
1011c418c4aSAlex Elder ipa_resource_config_common(ipa, resource_type, reg,
1021c418c4aSAlex Elder &resource->limits[0], ylimits);
103a749c6c0SAlex Elder if (group_count < 3)
104ee3e6beaSAlex Elder return;
105ee3e6beaSAlex Elder
1066a244b75SAlex Elder reg = ipa_reg(ipa, SRC_RSRC_GRP_23_RSRC_TYPE);
107ee3e6beaSAlex Elder ylimits = group_count == 3 ? NULL : &resource->limits[3];
1081c418c4aSAlex Elder ipa_resource_config_common(ipa, resource_type, reg,
1091c418c4aSAlex Elder &resource->limits[2], ylimits);
110a749c6c0SAlex Elder if (group_count < 5)
111ee3e6beaSAlex Elder return;
112ee3e6beaSAlex Elder
1136a244b75SAlex Elder reg = ipa_reg(ipa, SRC_RSRC_GRP_45_RSRC_TYPE);
114ee3e6beaSAlex Elder ylimits = group_count == 5 ? NULL : &resource->limits[5];
1151c418c4aSAlex Elder ipa_resource_config_common(ipa, resource_type, reg,
1161c418c4aSAlex Elder &resource->limits[4], ylimits);
1173219953bSAlex Elder if (group_count < 7)
1183219953bSAlex Elder return;
1193219953bSAlex Elder
1206a244b75SAlex Elder reg = ipa_reg(ipa, SRC_RSRC_GRP_67_RSRC_TYPE);
1213219953bSAlex Elder ylimits = group_count == 7 ? NULL : &resource->limits[7];
1221c418c4aSAlex Elder ipa_resource_config_common(ipa, resource_type, reg,
1231c418c4aSAlex Elder &resource->limits[6], ylimits);
124ee3e6beaSAlex Elder }
125ee3e6beaSAlex Elder
ipa_resource_config_dst(struct ipa * ipa,u32 resource_type,const struct ipa_resource_data * data)1264bcfb35eSAlex Elder static void ipa_resource_config_dst(struct ipa *ipa, u32 resource_type,
12793c03729SAlex Elder const struct ipa_resource_data *data)
128ee3e6beaSAlex Elder {
1294fd704b3SAlex Elder u32 group_count = data->rsrc_group_dst_count;
130ee3e6beaSAlex Elder const struct ipa_resource_limits *ylimits;
13193c03729SAlex Elder const struct ipa_resource *resource;
13281772e44SAlex Elder const struct reg *reg;
133ee3e6beaSAlex Elder
13493c03729SAlex Elder resource = &data->resource_dst[resource_type];
13593c03729SAlex Elder
1366a244b75SAlex Elder reg = ipa_reg(ipa, DST_RSRC_GRP_01_RSRC_TYPE);
137ee3e6beaSAlex Elder ylimits = group_count == 1 ? NULL : &resource->limits[1];
1381c418c4aSAlex Elder ipa_resource_config_common(ipa, resource_type, reg,
1391c418c4aSAlex Elder &resource->limits[0], ylimits);
140a749c6c0SAlex Elder if (group_count < 3)
141ee3e6beaSAlex Elder return;
142ee3e6beaSAlex Elder
1436a244b75SAlex Elder reg = ipa_reg(ipa, DST_RSRC_GRP_23_RSRC_TYPE);
144ee3e6beaSAlex Elder ylimits = group_count == 3 ? NULL : &resource->limits[3];
1451c418c4aSAlex Elder ipa_resource_config_common(ipa, resource_type, reg,
1461c418c4aSAlex Elder &resource->limits[2], ylimits);
147a749c6c0SAlex Elder if (group_count < 5)
148ee3e6beaSAlex Elder return;
149ee3e6beaSAlex Elder
1506a244b75SAlex Elder reg = ipa_reg(ipa, DST_RSRC_GRP_45_RSRC_TYPE);
151ee3e6beaSAlex Elder ylimits = group_count == 5 ? NULL : &resource->limits[5];
1521c418c4aSAlex Elder ipa_resource_config_common(ipa, resource_type, reg,
1531c418c4aSAlex Elder &resource->limits[4], ylimits);
1543219953bSAlex Elder if (group_count < 7)
1553219953bSAlex Elder return;
1563219953bSAlex Elder
1576a244b75SAlex Elder reg = ipa_reg(ipa, DST_RSRC_GRP_67_RSRC_TYPE);
1583219953bSAlex Elder ylimits = group_count == 7 ? NULL : &resource->limits[7];
1591c418c4aSAlex Elder ipa_resource_config_common(ipa, resource_type, reg,
1601c418c4aSAlex Elder &resource->limits[6], ylimits);
161ee3e6beaSAlex Elder }
162ee3e6beaSAlex Elder
16374858b63SAlex Elder /* Configure resources; there is no ipa_resource_deconfig() */
ipa_resource_config(struct ipa * ipa,const struct ipa_resource_data * data)164ee3e6beaSAlex Elder int ipa_resource_config(struct ipa *ipa, const struct ipa_resource_data *data)
165ee3e6beaSAlex Elder {
166ee3e6beaSAlex Elder u32 i;
167ee3e6beaSAlex Elder
168ee3e6beaSAlex Elder if (!ipa_resource_limits_valid(ipa, data))
169ee3e6beaSAlex Elder return -EINVAL;
170ee3e6beaSAlex Elder
171ee3e6beaSAlex Elder for (i = 0; i < data->resource_src_count; i++)
17293c03729SAlex Elder ipa_resource_config_src(ipa, i, data);
173ee3e6beaSAlex Elder
174ee3e6beaSAlex Elder for (i = 0; i < data->resource_dst_count; i++)
17593c03729SAlex Elder ipa_resource_config_dst(ipa, i, data);
176ee3e6beaSAlex Elder
177ee3e6beaSAlex Elder return 0;
178ee3e6beaSAlex Elder }
179