blob: 988d7202def87e1cc123fc246260569a6933e420 [file] [log] [blame]
Girish Mahadevanb020a5b2013-12-06 13:37:06 -07001/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
Gagan Mac8cbbb802012-02-08 15:35:54 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#define pr_fmt(fmt) "AXI: NOC: %s(): " fmt, __func__
14
15#include <linux/slab.h>
16#include <linux/io.h>
17#include <mach/msm_bus_board.h>
18#include "msm_bus_core.h"
19#include "msm_bus_noc.h"
20
21/* NOC_QOS generic */
22#define __CLZ(x) ((8 * sizeof(uint32_t)) - 1 - __fls(x))
23#define SAT_SCALE 16 /* 16 bytes minimum for saturation */
24#define BW_SCALE 256 /* 1/256 byte per cycle unit */
Girish Mahadevanb020a5b2013-12-06 13:37:06 -070025#define QOS_DEFAULT_BASEOFFSET 0x00003000
Gagan Mac8cbbb802012-02-08 15:35:54 -070026#define MAX_BW_FIELD (NOC_QOS_BWn_BW_BMSK >> NOC_QOS_BWn_BW_SHFT)
27#define MAX_SAT_FIELD (NOC_QOS_SATn_SAT_BMSK >> NOC_QOS_SATn_SAT_SHFT)
28
Girish Mahadevanb020a5b2013-12-06 13:37:06 -070029#define NOC_QOS_REG_BASE(b, o) ((b) + (o))
Gagan Mac8cbbb802012-02-08 15:35:54 -070030
Girish Mahadevanb020a5b2013-12-06 13:37:06 -070031#define NOC_QOS_ID_COREIDn_ADDR(b, o, n) \
32 (NOC_QOS_REG_BASE(b, o) + 0x80 * (n))
Gagan Mac8cbbb802012-02-08 15:35:54 -070033enum noc_qos_id_coreidn {
34 NOC_QOS_ID_COREIDn_RMSK = 0xffffffff,
35 NOC_QOS_ID_COREIDn_MAXn = 32,
36 NOC_QOS_ID_COREIDn_CORECHSUM_BMSK = 0xffffff00,
37 NOC_QOS_ID_COREIDn_CORECHSUM_SHFT = 0x8,
38 NOC_QOS_ID_COREIDn_CORETYPEID_BMSK = 0xff,
39 NOC_QOS_ID_COREIDn_CORETYPEID_SHFT = 0x0,
40};
41
Girish Mahadevanb020a5b2013-12-06 13:37:06 -070042#define NOC_QOS_ID_REVISIONIDn_ADDR(b, o, n) \
43 (NOC_QOS_REG_BASE(b, o) + 0x4 + 0x80 * (n))
Gagan Mac8cbbb802012-02-08 15:35:54 -070044enum noc_qos_id_revisionidn {
45 NOC_QOS_ID_REVISIONIDn_RMSK = 0xffffffff,
46 NOC_QOS_ID_REVISIONIDn_MAXn = 32,
47 NOC_QOS_ID_REVISIONIDn_FLEXNOCID_BMSK = 0xffffff00,
48 NOC_QOS_ID_REVISIONIDn_FLEXNOCID_SHFT = 0x8,
49 NOC_QOS_ID_REVISIONIDn_USERID_BMSK = 0xff,
50 NOC_QOS_ID_REVISIONIDn_USERID_SHFT = 0x0,
51};
52
Girish Mahadevanb020a5b2013-12-06 13:37:06 -070053#define NOC_QOS_PRIORITYn_ADDR(b, o, n) \
54 (NOC_QOS_REG_BASE(b, o) + 0x8 + 0x80 * (n))
Gagan Mac8cbbb802012-02-08 15:35:54 -070055enum noc_qos_id_priorityn {
56 NOC_QOS_PRIORITYn_RMSK = 0x0000000f,
57 NOC_QOS_PRIORITYn_MAXn = 32,
58 NOC_QOS_PRIORITYn_P1_BMSK = 0xc,
59 NOC_QOS_PRIORITYn_P1_SHFT = 0x2,
60 NOC_QOS_PRIORITYn_P0_BMSK = 0x3,
61 NOC_QOS_PRIORITYn_P0_SHFT = 0x0,
62};
63
Girish Mahadevanb020a5b2013-12-06 13:37:06 -070064#define NOC_QOS_MODEn_ADDR(b, o, n) \
65 (NOC_QOS_REG_BASE(b, o) + 0xC + 0x80 * (n))
Gagan Mac8cbbb802012-02-08 15:35:54 -070066enum noc_qos_id_moden_rmsk {
67 NOC_QOS_MODEn_RMSK = 0x00000003,
68 NOC_QOS_MODEn_MAXn = 32,
69 NOC_QOS_MODEn_MODE_BMSK = 0x3,
70 NOC_QOS_MODEn_MODE_SHFT = 0x0,
71};
72
Girish Mahadevanb020a5b2013-12-06 13:37:06 -070073#define NOC_QOS_BWn_ADDR(b, o, n) \
74 (NOC_QOS_REG_BASE(b, o) + 0x10 + 0x80 * (n))
Gagan Mac8cbbb802012-02-08 15:35:54 -070075enum noc_qos_id_bwn {
76 NOC_QOS_BWn_RMSK = 0x0000ffff,
77 NOC_QOS_BWn_MAXn = 32,
78 NOC_QOS_BWn_BW_BMSK = 0xffff,
79 NOC_QOS_BWn_BW_SHFT = 0x0,
80};
81
82/* QOS Saturation registers */
Girish Mahadevanb020a5b2013-12-06 13:37:06 -070083#define NOC_QOS_SATn_ADDR(b, o, n) \
84 (NOC_QOS_REG_BASE(b, o) + 0x14 + 0x80 * (n))
Gagan Mac8cbbb802012-02-08 15:35:54 -070085enum noc_qos_id_saturationn {
86 NOC_QOS_SATn_RMSK = 0x000003ff,
87 NOC_QOS_SATn_MAXn = 32,
88 NOC_QOS_SATn_SAT_BMSK = 0x3ff,
89 NOC_QOS_SATn_SAT_SHFT = 0x0,
90};
91
92static int noc_div(uint64_t *a, uint32_t b)
93{
94 if ((*a > 0) && (*a < b))
95 return 1;
96 else
97 return do_div(*a, b);
98}
99
100/**
101 * Calculates bw hardware is using from register values
102 * bw returned is in bytes/sec
103 */
104static uint64_t noc_bw(uint32_t bw_field, uint32_t qos_freq)
105{
106 uint64_t res;
107 uint32_t rem, scale;
108
109 res = 2 * qos_freq * bw_field;
110 scale = BW_SCALE * 1000;
111 rem = noc_div(&res, scale);
112 MSM_BUS_DBG("NOC: Calculated bw: %llu\n", res * 1000000ULL);
113 return res * 1000000ULL;
114}
115
116static uint32_t noc_bw_ceil(long int bw_field, uint32_t qos_freq)
117{
118 uint64_t bw_temp = 2 * qos_freq * bw_field;
119 uint32_t scale = 1000 * BW_SCALE;
120 noc_div(&bw_temp, scale);
121 return bw_temp * 1000000;
122}
123#define MAX_BW(timebase) noc_bw_ceil(MAX_BW_FIELD, (timebase))
124
125/**
126 * Calculates ws hardware is using from register values
127 * ws returned is in nanoseconds
128 */
129static uint32_t noc_ws(uint64_t bw, uint32_t sat, uint32_t qos_freq)
130{
131 if (bw && qos_freq) {
132 uint32_t bwf = bw * qos_freq;
133 uint64_t scale = 1000000000000LL * BW_SCALE *
134 SAT_SCALE * sat;
135 noc_div(&scale, bwf);
136 MSM_BUS_DBG("NOC: Calculated ws: %llu\n", scale);
137 return scale;
138 }
139
140 return 0;
141}
142#define MAX_WS(bw, timebase) noc_ws((bw), MAX_SAT_FIELD, (timebase))
143
144/* Calculate bandwidth field value for requested bandwidth */
145static uint32_t noc_bw_field(uint64_t bw, uint32_t qos_freq)
146{
147 uint32_t bw_field = 0;
148
149 if (bw) {
150 uint32_t rem;
151 uint64_t bw_capped = min_t(uint64_t, bw, MAX_BW(qos_freq));
152 uint64_t bwc = bw_capped * BW_SCALE;
153 uint64_t qf = 2 * qos_freq * 1000;
154
155 rem = noc_div(&bwc, qf);
156 bw_field = (uint32_t)min_t(uint64_t, bwc, MAX_BW_FIELD);
157 }
158
159 MSM_BUS_DBG("NOC: bw_field: %u\n", bw_field);
160 return bw_field;
161}
162
163static uint32_t noc_sat_field(uint64_t bw, uint32_t ws, uint32_t qos_freq)
164{
165 uint32_t sat_field = 0, win;
166
167 if (bw) {
168 /* Limit to max bw and scale bw to 100 KB increments */
169 uint64_t tbw, tscale;
170 uint64_t bw_scaled = min_t(uint64_t, bw, MAX_BW(qos_freq));
171 uint32_t rem = noc_div(&bw_scaled, 100000);
172
173 /**
174 * Calculate saturation from windows size.
175 * WS must be at least one arb period.
176 * Saturation must not exceed max field size
177 *
178 * Bandwidth is in 100KB increments
179 * Window size is in ns
180 * qos_freq is in KHz
181 */
182 win = max(ws, 1000000 / qos_freq);
183 tbw = bw_scaled * win * qos_freq;
184 tscale = 10000000ULL * BW_SCALE * SAT_SCALE;
185 rem = noc_div(&tbw, tscale);
186 sat_field = (uint32_t)min_t(uint64_t, tbw, MAX_SAT_FIELD);
187 }
188
189 MSM_BUS_DBG("NOC: sat_field: %d\n", sat_field);
190 return sat_field;
191}
192
193static void noc_set_qos_mode(struct msm_bus_noc_info *ninfo, uint32_t mport,
Gagan Macfa8dff72012-08-30 15:03:40 -0600194 uint8_t mode, uint8_t perm_mode)
Gagan Mac8cbbb802012-02-08 15:35:54 -0700195{
196 if (mode < NOC_QOS_MODE_MAX &&
Gagan Macfa8dff72012-08-30 15:03:40 -0600197 ((1 << mode) & perm_mode)) {
Gagan Mac8cbbb802012-02-08 15:35:54 -0700198 uint32_t reg_val;
199
200 reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
Girish Mahadevanb020a5b2013-12-06 13:37:06 -0700201 ninfo->qos_baseoffset, mport)) & NOC_QOS_MODEn_RMSK;
Gagan Mac8cbbb802012-02-08 15:35:54 -0700202 writel_relaxed(((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK))) |
203 (mode & NOC_QOS_MODEn_MODE_BMSK)),
Girish Mahadevanb020a5b2013-12-06 13:37:06 -0700204 NOC_QOS_MODEn_ADDR(ninfo->base, ninfo->qos_baseoffset,
205 mport));
Gagan Mac8cbbb802012-02-08 15:35:54 -0700206 }
207 /* Ensure qos mode is set before exiting */
208 wmb();
209}
210
211static void noc_set_qos_priority(struct msm_bus_noc_info *ninfo, uint32_t mport,
212 struct msm_bus_noc_qos_priority *priority)
213{
214 uint32_t reg_val, val;
215
Girish Mahadevanb020a5b2013-12-06 13:37:06 -0700216 reg_val = readl_relaxed(NOC_QOS_PRIORITYn_ADDR(ninfo->base,
217 ninfo->qos_baseoffset, mport))
218 & NOC_QOS_PRIORITYn_RMSK;
Gagan Mac8cbbb802012-02-08 15:35:54 -0700219 val = priority->p1 << NOC_QOS_PRIORITYn_P1_SHFT;
220 writel_relaxed(((reg_val & (~(NOC_QOS_PRIORITYn_P1_BMSK))) |
221 (val & NOC_QOS_PRIORITYn_P1_BMSK)),
Girish Mahadevanb020a5b2013-12-06 13:37:06 -0700222 NOC_QOS_PRIORITYn_ADDR(ninfo->base, ninfo->qos_baseoffset,
223 mport));
Gagan Mac8cbbb802012-02-08 15:35:54 -0700224
Girish Mahadevanb020a5b2013-12-06 13:37:06 -0700225 reg_val = readl_relaxed(NOC_QOS_PRIORITYn_ADDR(ninfo->base,
226 ninfo->qos_baseoffset,
227 mport))
228 & NOC_QOS_PRIORITYn_RMSK;
Gagan Mac8cbbb802012-02-08 15:35:54 -0700229 writel_relaxed(((reg_val & (~(NOC_QOS_PRIORITYn_P0_BMSK))) |
230 (priority->p0 & NOC_QOS_PRIORITYn_P0_BMSK)),
Girish Mahadevanb020a5b2013-12-06 13:37:06 -0700231 NOC_QOS_PRIORITYn_ADDR(ninfo->base, ninfo->qos_baseoffset,
232 mport));
Gagan Mac8cbbb802012-02-08 15:35:54 -0700233 /* Ensure qos priority is set before exiting */
234 wmb();
235}
236
237static void msm_bus_noc_set_qos_bw(struct msm_bus_noc_info *ninfo,
238 uint32_t mport, uint8_t perm_mode, struct msm_bus_noc_qos_bw *qbw)
239{
240 uint32_t reg_val, val, mode;
241
242 if (!ninfo->qos_freq) {
243 MSM_BUS_DBG("Zero QoS Freq\n");
244 return;
245 }
246
247
248 /* If Limiter or Regulator modes are not supported, bw not available*/
249 if (perm_mode & (NOC_QOS_PERM_MODE_LIMITER |
250 NOC_QOS_PERM_MODE_REGULATOR)) {
251 uint32_t bw_val = noc_bw_field(qbw->bw, ninfo->qos_freq);
252 uint32_t sat_val = noc_sat_field(qbw->bw, qbw->ws,
253 ninfo->qos_freq);
254
255 MSM_BUS_DBG("NOC: BW: perm_mode: %d bw_val: %d, sat_val: %d\n",
256 perm_mode, bw_val, sat_val);
257 /*
258 * If in Limiter/Regulator mode, first go to fixed mode.
259 * Clear QoS accumulator
260 **/
261 mode = readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
Girish Mahadevanb020a5b2013-12-06 13:37:06 -0700262 ninfo->qos_baseoffset, mport))
263 & NOC_QOS_MODEn_MODE_BMSK;
Gagan Mac8cbbb802012-02-08 15:35:54 -0700264 if (mode == NOC_QOS_MODE_REGULATOR || mode ==
265 NOC_QOS_MODE_LIMITER) {
266 reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->
Girish Mahadevanb020a5b2013-12-06 13:37:06 -0700267 base, ninfo->qos_baseoffset, mport));
Gagan Mac8cbbb802012-02-08 15:35:54 -0700268 val = NOC_QOS_MODE_FIXED;
269 writel_relaxed((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK)))
270 | (val & NOC_QOS_MODEn_MODE_BMSK),
Girish Mahadevanb020a5b2013-12-06 13:37:06 -0700271 NOC_QOS_MODEn_ADDR(ninfo->base,
272 ninfo->qos_baseoffset, mport));
Gagan Mac8cbbb802012-02-08 15:35:54 -0700273 }
274
Girish Mahadevanb020a5b2013-12-06 13:37:06 -0700275 reg_val = readl_relaxed(NOC_QOS_BWn_ADDR(ninfo->base,
276 ninfo->qos_baseoffset, mport));
Gagan Mac8cbbb802012-02-08 15:35:54 -0700277 val = bw_val << NOC_QOS_BWn_BW_SHFT;
278 writel_relaxed(((reg_val & (~(NOC_QOS_BWn_BW_BMSK))) |
279 (val & NOC_QOS_BWn_BW_BMSK)),
Girish Mahadevanb020a5b2013-12-06 13:37:06 -0700280 NOC_QOS_BWn_ADDR(ninfo->base, ninfo->qos_baseoffset,
281 mport));
Gagan Mac8cbbb802012-02-08 15:35:54 -0700282
283 MSM_BUS_DBG("NOC: BW: Wrote value: 0x%x\n", ((reg_val &
284 (~NOC_QOS_BWn_BW_BMSK)) | (val &
285 NOC_QOS_BWn_BW_BMSK)));
286
287 reg_val = readl_relaxed(NOC_QOS_SATn_ADDR(ninfo->base,
Girish Mahadevanb020a5b2013-12-06 13:37:06 -0700288 ninfo->qos_baseoffset, mport));
Gagan Mac8cbbb802012-02-08 15:35:54 -0700289 val = sat_val << NOC_QOS_SATn_SAT_SHFT;
290 writel_relaxed(((reg_val & (~(NOC_QOS_SATn_SAT_BMSK))) |
291 (val & NOC_QOS_SATn_SAT_BMSK)),
Girish Mahadevanb020a5b2013-12-06 13:37:06 -0700292 NOC_QOS_SATn_ADDR(ninfo->base, ninfo->qos_baseoffset,
293 mport));
Gagan Mac8cbbb802012-02-08 15:35:54 -0700294
295 MSM_BUS_DBG("NOC: SAT: Wrote value: 0x%x\n", ((reg_val &
296 (~NOC_QOS_SATn_SAT_BMSK)) | (val &
297 NOC_QOS_SATn_SAT_BMSK)));
298
299 /* Set mode back to what it was initially */
300 reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
Girish Mahadevanb020a5b2013-12-06 13:37:06 -0700301 ninfo->qos_baseoffset, mport));
Gagan Mac8cbbb802012-02-08 15:35:54 -0700302 writel_relaxed((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK)))
303 | (mode & NOC_QOS_MODEn_MODE_BMSK),
Girish Mahadevanb020a5b2013-12-06 13:37:06 -0700304 NOC_QOS_MODEn_ADDR(ninfo->base, ninfo->qos_baseoffset,
305 mport));
Gagan Mac8cbbb802012-02-08 15:35:54 -0700306 /* Ensure that all writes for bandwidth registers have
307 * completed before returning
308 */
309 wmb();
310 }
311}
312
313uint8_t msm_bus_noc_get_qos_mode(struct msm_bus_noc_info *ninfo,
Gagan Macfa8dff72012-08-30 15:03:40 -0600314 uint32_t mport, uint32_t mode, uint32_t perm_mode)
Gagan Mac8cbbb802012-02-08 15:35:54 -0700315{
Gagan Macfa8dff72012-08-30 15:03:40 -0600316 if (NOC_QOS_MODES_ALL_PERM == perm_mode)
Gagan Mac8cbbb802012-02-08 15:35:54 -0700317 return readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
Girish Mahadevanb020a5b2013-12-06 13:37:06 -0700318 ninfo->qos_baseoffset, mport)) &
319 NOC_QOS_MODEn_MODE_BMSK;
Gagan Mac8cbbb802012-02-08 15:35:54 -0700320 else
Gagan Macfa8dff72012-08-30 15:03:40 -0600321 return 31 - __CLZ(mode &
Gagan Mac8cbbb802012-02-08 15:35:54 -0700322 NOC_QOS_MODES_ALL_PERM);
323}
324
325void msm_bus_noc_get_qos_priority(struct msm_bus_noc_info *ninfo,
326 uint32_t mport, struct msm_bus_noc_qos_priority *priority)
327{
328 priority->p1 = (readl_relaxed(NOC_QOS_PRIORITYn_ADDR(ninfo->base,
Girish Mahadevanb020a5b2013-12-06 13:37:06 -0700329 ninfo->qos_baseoffset, mport)) & NOC_QOS_PRIORITYn_P1_BMSK) >>
Gagan Mac8cbbb802012-02-08 15:35:54 -0700330 NOC_QOS_PRIORITYn_P1_SHFT;
331
332 priority->p0 = (readl_relaxed(NOC_QOS_PRIORITYn_ADDR(ninfo->base,
Girish Mahadevanb020a5b2013-12-06 13:37:06 -0700333 ninfo->qos_baseoffset, mport)) & NOC_QOS_PRIORITYn_P0_BMSK) >>
Gagan Mac8cbbb802012-02-08 15:35:54 -0700334 NOC_QOS_PRIORITYn_P0_SHFT;
335}
336
337void msm_bus_noc_get_qos_bw(struct msm_bus_noc_info *ninfo,
Gagan Macfa8dff72012-08-30 15:03:40 -0600338 uint32_t mport, uint8_t perm_mode, struct msm_bus_noc_qos_bw *qbw)
Gagan Mac8cbbb802012-02-08 15:35:54 -0700339{
Gagan Macfa8dff72012-08-30 15:03:40 -0600340 if (perm_mode & (NOC_QOS_PERM_MODE_LIMITER |
Gagan Mac8cbbb802012-02-08 15:35:54 -0700341 NOC_QOS_PERM_MODE_REGULATOR)) {
342 uint32_t bw_val = readl_relaxed(NOC_QOS_BWn_ADDR(ninfo->
Girish Mahadevanb020a5b2013-12-06 13:37:06 -0700343 base, ninfo->qos_baseoffset, mport)) &
344 NOC_QOS_BWn_BW_BMSK;
Gagan Mac8cbbb802012-02-08 15:35:54 -0700345 uint32_t sat = readl_relaxed(NOC_QOS_SATn_ADDR(ninfo->
Girish Mahadevanb020a5b2013-12-06 13:37:06 -0700346 base, ninfo->qos_baseoffset, mport)) &
347 NOC_QOS_SATn_SAT_BMSK;
Gagan Mac8cbbb802012-02-08 15:35:54 -0700348
349 qbw->bw = noc_bw(bw_val, ninfo->qos_freq);
350 qbw->ws = noc_ws(qbw->bw, sat, ninfo->qos_freq);
351 } else {
352 qbw->bw = 0;
353 qbw->ws = 0;
354 }
355}
356
357static int msm_bus_noc_mas_init(struct msm_bus_noc_info *ninfo,
358 struct msm_bus_inode_info *info)
359{
360 int i;
361 struct msm_bus_noc_qos_priority *prio;
362 prio = kzalloc(sizeof(struct msm_bus_noc_qos_priority),
363 GFP_KERNEL);
364 if (!prio) {
365 MSM_BUS_WARN("Couldn't alloc prio data for node: %d\n",
366 info->node_info->id);
367 return -ENOMEM;
368 }
369
370 prio->read_prio = info->node_info->prio_rd;
371 prio->write_prio = info->node_info->prio_wr;
372 prio->p1 = info->node_info->prio1;
373 prio->p0 = info->node_info->prio0;
374 info->hw_data = (void *)prio;
375
376 if (!info->node_info->qport) {
377 MSM_BUS_DBG("No QoS Ports to init\n");
378 return 0;
379 }
380
381 for (i = 0; i < info->node_info->num_mports; i++) {
Gagan Mac9addee02012-11-06 16:40:42 -0700382 if (info->node_info->mode != NOC_QOS_MODE_BYPASS) {
Gagan Mac8cbbb802012-02-08 15:35:54 -0700383 noc_set_qos_priority(ninfo, info->node_info->qport[i],
384 prio);
385
Gagan Mac9addee02012-11-06 16:40:42 -0700386 if (info->node_info->mode != NOC_QOS_MODE_FIXED) {
387 struct msm_bus_noc_qos_bw qbw;
388 qbw.ws = info->node_info->ws;
389 qbw.bw = 0;
390 msm_bus_noc_set_qos_bw(ninfo, info->node_info->
391 qport[i], info->node_info->perm_mode,
392 &qbw);
393 }
Gagan Mac8cbbb802012-02-08 15:35:54 -0700394 }
395
396 noc_set_qos_mode(ninfo, info->node_info->qport[i], info->
Gagan Macfa8dff72012-08-30 15:03:40 -0600397 node_info->mode, info->node_info->perm_mode);
Gagan Mac8cbbb802012-02-08 15:35:54 -0700398 }
399
400 return 0;
401}
402
403static void msm_bus_noc_node_init(void *hw_data,
404 struct msm_bus_inode_info *info)
405{
406 struct msm_bus_noc_info *ninfo =
407 (struct msm_bus_noc_info *)hw_data;
408
409 if (!IS_SLAVE(info->node_info->priv_id))
Gagan Macfe0cb542012-08-13 11:23:02 -0600410 if (info->node_info->hw_sel != MSM_BUS_RPM)
411 msm_bus_noc_mas_init(ninfo, info);
Gagan Mac8cbbb802012-02-08 15:35:54 -0700412}
413
414static int msm_bus_noc_allocate_commit_data(struct msm_bus_fabric_registration
415 *fab_pdata, void **cdata, int ctx)
416{
417 struct msm_bus_noc_commit **cd = (struct msm_bus_noc_commit **)cdata;
418 struct msm_bus_noc_info *ninfo =
419 (struct msm_bus_noc_info *)fab_pdata->hw_data;
420
421 *cd = kzalloc(sizeof(struct msm_bus_noc_commit), GFP_KERNEL);
422 if (!*cd) {
423 MSM_BUS_DBG("Couldn't alloc mem for cdata\n");
424 return -ENOMEM;
425 }
426
427 (*cd)->mas = ninfo->cdata[ctx].mas;
428 (*cd)->slv = ninfo->cdata[ctx].slv;
429
430 return 0;
431}
432
433static void *msm_bus_noc_allocate_noc_data(struct platform_device *pdev,
434 struct msm_bus_fabric_registration *fab_pdata)
435{
436 struct resource *noc_mem;
437 struct resource *noc_io;
438 struct msm_bus_noc_info *ninfo;
439 int i;
440
441 ninfo = kzalloc(sizeof(struct msm_bus_noc_info), GFP_KERNEL);
442 if (!ninfo) {
443 MSM_BUS_DBG("Couldn't alloc mem for noc info\n");
444 return NULL;
445 }
446
447 ninfo->nmasters = fab_pdata->nmasters;
448 ninfo->nqos_masters = fab_pdata->nmasters;
449 ninfo->nslaves = fab_pdata->nslaves;
450 ninfo->qos_freq = fab_pdata->qos_freq;
Girish Mahadevanb020a5b2013-12-06 13:37:06 -0700451
452 if (!fab_pdata->qos_baseoffset)
453 ninfo->qos_baseoffset = QOS_DEFAULT_BASEOFFSET;
454 else
455 ninfo->qos_baseoffset = fab_pdata->qos_baseoffset;
456
Gagan Mac8cbbb802012-02-08 15:35:54 -0700457 ninfo->mas_modes = kzalloc(sizeof(uint32_t) * fab_pdata->nmasters,
458 GFP_KERNEL);
459 if (!ninfo->mas_modes) {
460 MSM_BUS_DBG("Couldn't alloc mem for noc master-modes\n");
461 return NULL;
462 }
463
464 for (i = 0; i < NUM_CTX; i++) {
465 ninfo->cdata[i].mas = kzalloc(sizeof(struct
466 msm_bus_node_hw_info) * fab_pdata->nmasters * 2,
467 GFP_KERNEL);
468 if (!ninfo->cdata[i].mas) {
469 MSM_BUS_DBG("Couldn't alloc mem for noc master-bw\n");
470 kfree(ninfo->mas_modes);
471 kfree(ninfo);
472 return NULL;
473 }
474
475 ninfo->cdata[i].slv = kzalloc(sizeof(struct
476 msm_bus_node_hw_info) * fab_pdata->nslaves * 2,
477 GFP_KERNEL);
478 if (!ninfo->cdata[i].slv) {
479 MSM_BUS_DBG("Couldn't alloc mem for noc master-bw\n");
480 kfree(ninfo->cdata[i].mas);
481 goto err;
482 }
483 }
484
485 /* If it's a virtual fabric, don't get memory info */
486 if (fab_pdata->virt)
487 goto skip_mem;
488
489 noc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
490 if (!noc_mem && !fab_pdata->virt) {
491 MSM_BUS_ERR("Cannot get NoC Base address\n");
492 goto err;
493 }
494
495 noc_io = request_mem_region(noc_mem->start,
496 resource_size(noc_mem), pdev->name);
497 if (!noc_io) {
498 MSM_BUS_ERR("NoC memory unavailable\n");
499 goto err;
500 }
501
502 ninfo->base = ioremap(noc_mem->start, resource_size(noc_mem));
503 if (!ninfo->base) {
504 MSM_BUS_ERR("IOremap failed for NoC!\n");
505 release_mem_region(noc_mem->start, resource_size(noc_mem));
506 goto err;
507 }
508
509skip_mem:
510 fab_pdata->hw_data = (void *)ninfo;
511 return (void *)ninfo;
512
513err:
514 kfree(ninfo->mas_modes);
515 kfree(ninfo);
516 return NULL;
517}
518
519static void free_commit_data(void *cdata)
520{
521 struct msm_bus_noc_commit *cd = (struct msm_bus_noc_commit *)cdata;
522
523 kfree(cd->mas);
524 kfree(cd->slv);
525 kfree(cd);
526}
527
528static void msm_bus_noc_update_bw(struct msm_bus_inode_info *hop,
529 struct msm_bus_inode_info *info,
530 struct msm_bus_fabric_registration *fab_pdata,
531 void *sel_cdata, int *master_tiers,
Gagan Macb2372ae2012-08-20 19:24:32 -0600532 int64_t add_bw)
Gagan Mac8cbbb802012-02-08 15:35:54 -0700533{
534 struct msm_bus_noc_info *ninfo;
535 struct msm_bus_noc_qos_bw qos_bw;
536 int i, ports;
Alok Chauhanad1730e2013-09-18 18:00:20 +0530537 int64_t bw;
Gagan Mac8cbbb802012-02-08 15:35:54 -0700538 struct msm_bus_noc_commit *sel_cd =
539 (struct msm_bus_noc_commit *)sel_cdata;
540
541 ninfo = (struct msm_bus_noc_info *)fab_pdata->hw_data;
542 if (!ninfo->qos_freq) {
543 MSM_BUS_DBG("NOC: No qos frequency to update bw\n");
544 return;
545 }
546
Gagan Macb91c4072012-05-09 16:00:31 -0600547 if (info->node_info->num_mports == 0) {
548 MSM_BUS_DBG("NOC: Skip Master BW\n");
549 goto skip_mas_bw;
Gagan Mac8cbbb802012-02-08 15:35:54 -0700550 }
551
552 ports = info->node_info->num_mports;
Gagan Mac8cbbb802012-02-08 15:35:54 -0700553 bw = INTERLEAVED_BW(fab_pdata, add_bw, ports);
554
Gagan Macb2372ae2012-08-20 19:24:32 -0600555 MSM_BUS_DBG("NOC: Update bw for: %d: %lld\n",
Gagan Mac8cbbb802012-02-08 15:35:54 -0700556 info->node_info->priv_id, add_bw);
557 for (i = 0; i < ports; i++) {
558 sel_cd->mas[info->node_info->masterp[i]].bw += bw;
559 sel_cd->mas[info->node_info->masterp[i]].hw_id =
560 info->node_info->mas_hw_id;
Gagan Macb91c4072012-05-09 16:00:31 -0600561 MSM_BUS_DBG("NOC: Update mas_bw: ID: %d, BW: %llu ports:%d\n",
Gagan Mac8cbbb802012-02-08 15:35:54 -0700562 info->node_info->priv_id,
563 sel_cd->mas[info->node_info->masterp[i]].bw,
Gagan Macb91c4072012-05-09 16:00:31 -0600564 ports);
Gagan Mac8cbbb802012-02-08 15:35:54 -0700565 /* Check if info is a shared master.
566 * If it is, mark it dirty
567 * If it isn't, then set QOS Bandwidth
568 **/
569 if (info->node_info->hw_sel == MSM_BUS_RPM)
570 sel_cd->mas[info->node_info->masterp[i]].dirty = 1;
Gagan Macb91c4072012-05-09 16:00:31 -0600571 else {
572 if (!info->node_info->qport) {
573 MSM_BUS_DBG("No qos ports to update!\n");
574 break;
575 }
576 qos_bw.bw = sel_cd->mas[info->node_info->masterp[i]].
577 bw;
578 qos_bw.ws = info->node_info->ws;
Gagan Mac8cbbb802012-02-08 15:35:54 -0700579 msm_bus_noc_set_qos_bw(ninfo,
580 info->node_info->qport[i],
581 info->node_info->perm_mode, &qos_bw);
Gagan Macb91c4072012-05-09 16:00:31 -0600582 MSM_BUS_DBG("NOC: QoS: Update mas_bw: ws: %u\n",
583 qos_bw.ws);
584 }
Gagan Mac8cbbb802012-02-08 15:35:54 -0700585 }
586
Gagan Macb91c4072012-05-09 16:00:31 -0600587skip_mas_bw:
Gagan Mac8cbbb802012-02-08 15:35:54 -0700588 ports = hop->node_info->num_sports;
Gagan Mac8cbbb802012-02-08 15:35:54 -0700589 for (i = 0; i < ports; i++) {
Girish Mahadevan32d61792014-02-03 18:20:48 -0700590 sel_cd->slv[hop->node_info->slavep[i]].bw += add_bw;
Gagan Mac8cbbb802012-02-08 15:35:54 -0700591 sel_cd->slv[hop->node_info->slavep[i]].hw_id =
592 hop->node_info->slv_hw_id;
Gagan Macb91c4072012-05-09 16:00:31 -0600593 MSM_BUS_DBG("NOC: Update slave_bw for ID: %d -> %llu\n",
Gagan Mac8cbbb802012-02-08 15:35:54 -0700594 hop->node_info->priv_id,
595 sel_cd->slv[hop->node_info->slavep[i]].bw);
596 MSM_BUS_DBG("NOC: Update slave_bw for hw_id: %d, index: %d\n",
597 hop->node_info->slv_hw_id, hop->node_info->slavep[i]);
598 /* Check if hop is a shared slave.
599 * If it is, mark it dirty
600 * If it isn't, then nothing to be done as the
601 * slaves are in bypass mode.
602 **/
603 if (hop->node_info->hw_sel == MSM_BUS_RPM)
604 sel_cd->slv[hop->node_info->slavep[i]].dirty = 1;
605 }
606}
607
608static int msm_bus_noc_commit(struct msm_bus_fabric_registration
609 *fab_pdata, void *hw_data, void **cdata)
610{
611 MSM_BUS_DBG("\nReached NOC Commit\n");
Gagan Macb91c4072012-05-09 16:00:31 -0600612 msm_bus_remote_hw_commit(fab_pdata, hw_data, cdata);
Gagan Mac8cbbb802012-02-08 15:35:54 -0700613 return 0;
614}
615
616static int msm_bus_noc_port_halt(uint32_t haltid, uint8_t mport)
617{
618 return 0;
619}
620
621static int msm_bus_noc_port_unhalt(uint32_t haltid, uint8_t mport)
622{
623 return 0;
624}
625
626int msm_bus_noc_hw_init(struct msm_bus_fabric_registration *pdata,
627 struct msm_bus_hw_algorithm *hw_algo)
628{
629 /* Set interleaving to true by default */
630 pdata->il_flag = true;
631 hw_algo->allocate_commit_data = msm_bus_noc_allocate_commit_data;
632 hw_algo->allocate_hw_data = msm_bus_noc_allocate_noc_data;
633 hw_algo->node_init = msm_bus_noc_node_init;
634 hw_algo->free_commit_data = free_commit_data;
635 hw_algo->update_bw = msm_bus_noc_update_bw;
636 hw_algo->commit = msm_bus_noc_commit;
637 hw_algo->port_halt = msm_bus_noc_port_halt;
638 hw_algo->port_unhalt = msm_bus_noc_port_unhalt;
Gagan Mac068e84d2013-05-28 18:22:33 -0600639 hw_algo->config_master = NULL;
Gagan Mac8cbbb802012-02-08 15:35:54 -0700640
641 return 0;
642}
643