blob: fd1aacdfe97c27efa49dd158df1625d07df0b5c2 [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -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
Stephen Boyd8704c7f2012-02-05 01:07:45 -080014#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
15
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070016#include <linux/kernel.h>
17#include <linux/init.h>
18#include <linux/device.h>
19#include <linux/module.h>
20#include <mach/msm_bus.h>
21#include <mach/msm_bus_board.h>
22#include <mach/board.h>
23#include <mach/rpm.h>
24#include "msm_bus_core.h"
Gagan Macdc1dc142011-09-16 15:13:35 -060025#include "../rpm_resources.h"
26
Gagan Macdc1dc142011-09-16 15:13:35 -060027void msm_bus_rpm_set_mt_mask()
28{
29#ifdef CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED
30 struct msm_rpm_iv_pair mt[1];
31 int mask = MSM_RPMRS_MASK_RPM_CTL_MULTI_TIER;
32 mt[0].id = MSM_RPM_ID_RPM_CTL;
33 mt[0].value = 2;
34 msm_rpmrs_set_bits_noirq(MSM_RPM_CTX_SET_0, mt, 1,
35 &mask);
36#endif
37}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038
Gagan Mac9c455662011-10-11 16:25:06 -060039bool msm_bus_rpm_is_mem_interleaved(void)
40{
41 int status = 0;
42 struct msm_rpm_iv_pair il[2];
43 uint16_t id[2];
44
45 il[0].value = 0;
46 il[1].value = 0;
47 status = msm_bus_board_rpm_get_il_ids(id);
48 if (status) {
49 MSM_BUS_DBG("Dynamic check not supported, "
50 "default: Interleaved memory\n");
51 goto inter;
52 }
53
54 il[0].id = id[0];
55 il[1].id = id[1];
56 status = msm_rpm_get_status(il, ARRAY_SIZE(il));
57 if (status) {
58 MSM_BUS_ERR("Status read for interleaving returned: %d\n"
59 "Using interleaved memory by default\n",
60 status);
61 goto inter;
62 }
63
64 /*
65 * If the start address of EBI1-CH0 is the same as
66 * the start address of EBI1-CH1, the memory is interleaved.
67 * The start addresses are stored in the 16 MSBs of the status
68 * register
69 */
70 if ((il[0].value & 0xFFFF0000) != (il[1].value & 0xFFFF0000)) {
71 MSM_BUS_DBG("Non-interleaved memory\n");
72 return false;
73 }
74
75inter:
76 MSM_BUS_DBG("Interleaved memory\n");
77 return true;
78}
79
Gagan Mac85c70492011-06-10 16:07:47 -060080#ifndef CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070081struct commit_data {
82 uint16_t *bwsum;
83 uint16_t *arb;
84 unsigned long *actarb;
85};
86
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070087/*
88 * The following macros are used for various operations on commit data.
89 * Commit data is an array of 32 bit integers. The size of arrays is unique
90 * to the fabric. Commit arrays are allocated at run-time based on the number
91 * of masters, slaves and tiered-slaves registered.
92 */
93
94#define MSM_BUS_GET_BW_INFO(val, type, bw) \
95 do { \
96 (type) = MSM_BUS_GET_BW_TYPE(val); \
97 (bw) = MSM_BUS_GET_BW(val); \
98 } while (0)
99
100
101#define MSM_BUS_GET_BW_INFO_BYTES (val, type, bw) \
102 do { \
103 (type) = MSM_BUS_GET_BW_TYPE(val); \
104 (bw) = msm_bus_get_bw_bytes(val); \
105 } while (0)
106
107#define ROUNDED_BW_VAL_FROM_BYTES(bw) \
108 ((((bw) >> 17) + 1) & 0x8000 ? 0x7FFF : (((bw) >> 17) + 1))
109
110#define BW_VAL_FROM_BYTES(bw) \
111 ((((bw) >> 17) & 0x8000) ? 0x7FFF : ((bw) >> 17))
112
Gagan Mac47a999a2012-01-18 20:36:12 -0700113static uint32_t msm_bus_set_bw_bytes(unsigned long bw)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700114{
115 return ((((bw) & 0x1FFFF) && (((bw) >> 17) == 0)) ?
116 ROUNDED_BW_VAL_FROM_BYTES(bw) : BW_VAL_FROM_BYTES(bw));
117
118}
119
120uint64_t msm_bus_get_bw_bytes(unsigned long val)
121{
122 return ((val) & 0x7FFF) << 17;
123}
124
125uint16_t msm_bus_get_bw(unsigned long val)
126{
127 return (val)&0x7FFF;
128}
129
Gagan Mac47a999a2012-01-18 20:36:12 -0700130static uint16_t msm_bus_create_bw_tier_pair_bytes(uint8_t type,
131 unsigned long bw)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132{
133 return ((((type) == MSM_BUS_BW_TIER1 ? 1 : 0) << 15) |
134 (msm_bus_set_bw_bytes(bw)));
135};
136
137uint16_t msm_bus_create_bw_tier_pair(uint8_t type, unsigned long bw)
138{
139 return (((type) == MSM_BUS_BW_TIER1 ? 1 : 0) << 15) | ((bw) & 0x7FFF);
140}
141
142void msm_bus_rpm_fill_cdata_buffer(int *curr, char *buf, const int max_size,
143 void *cdata, int nmasters, int nslaves, int ntslaves)
144{
145 int j, c;
146 struct commit_data *cd = (struct commit_data *)cdata;
147
148 *curr += scnprintf(buf + *curr, max_size - *curr, "BWSum:\n");
149 for (c = 0; c < nslaves; c++)
150 *curr += scnprintf(buf + *curr, max_size - *curr,
151 "0x%x\t", cd->bwsum[c]);
152 *curr += scnprintf(buf + *curr, max_size - *curr, "\nArb:");
153 for (c = 0; c < ntslaves; c++) {
154 *curr += scnprintf(buf + *curr, max_size - *curr,
155 "\nTSlave %d:\n", c);
156 for (j = 0; j < nmasters; j++)
157 *curr += scnprintf(buf + *curr, max_size - *curr,
158 " 0x%x\t", cd->arb[(c * nmasters) + j]);
159 }
160}
161
162/**
163 * allocate_commit_data() - Allocate the data for commit array in the
164 * format specified by RPM
165 * @fabric: Fabric device for which commit data is allocated
166 */
Gagan Mac47a999a2012-01-18 20:36:12 -0700167static int msm_bus_rpm_allocate_commit_data(struct msm_bus_fabric_registration
168 *fab_pdata, void **cdata, int ctx)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700169{
170 struct commit_data **cd = (struct commit_data **)cdata;
171 *cd = kzalloc(sizeof(struct commit_data), GFP_KERNEL);
172 if (!*cd) {
Gagan Mac6d7738a2011-07-21 14:23:31 -0600173 MSM_BUS_DBG("Couldn't alloc mem for cdata\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700174 return -ENOMEM;
175 }
176 (*cd)->bwsum = kzalloc((sizeof(uint16_t) * fab_pdata->nslaves),
177 GFP_KERNEL);
178 if (!(*cd)->bwsum) {
Gagan Mac6d7738a2011-07-21 14:23:31 -0600179 MSM_BUS_DBG("Couldn't alloc mem for slaves\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700180 kfree(*cd);
181 return -ENOMEM;
182 }
183 (*cd)->arb = kzalloc(((sizeof(uint16_t *)) *
184 (fab_pdata->ntieredslaves * fab_pdata->nmasters) + 1),
185 GFP_KERNEL);
186 if (!(*cd)->arb) {
Gagan Mac6d7738a2011-07-21 14:23:31 -0600187 MSM_BUS_DBG("Couldn't alloc memory for"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700188 " slaves\n");
189 kfree((*cd)->bwsum);
190 kfree(*cd);
191 return -ENOMEM;
192 }
193 (*cd)->actarb = kzalloc(((sizeof(unsigned long *)) *
194 (fab_pdata->ntieredslaves * fab_pdata->nmasters) + 1),
195 GFP_KERNEL);
196 if (!(*cd)->actarb) {
Gagan Mac6d7738a2011-07-21 14:23:31 -0600197 MSM_BUS_DBG("Couldn't alloc memory for"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700198 " slaves\n");
199 kfree((*cd)->bwsum);
200 kfree((*cd)->arb);
201 kfree(*cd);
202 return -ENOMEM;
203 }
204
205 return 0;
206}
207
Gagan Mac47a999a2012-01-18 20:36:12 -0700208static void free_commit_data(void *cdata)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700209{
210 struct commit_data *cd = (struct commit_data *)cdata;
211
212 kfree(cd->bwsum);
213 kfree(cd->arb);
214 kfree(cd->actarb);
215 kfree(cd);
216}
217
218/**
219 * allocate_rpm_data() - Allocate the id-value pairs to be
220 * sent to RPM
221 */
Gagan Mac47a999a2012-01-18 20:36:12 -0700222static void *msm_bus_rpm_allocate_rpm_data(struct platform_device *pdev,
223 struct msm_bus_fabric_registration *fab_pdata)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700224{
225 struct msm_rpm_iv_pair *rpm_data;
226 uint16_t count = ((fab_pdata->nmasters * fab_pdata->ntieredslaves) +
227 fab_pdata->nslaves + 1)/2;
228
229 rpm_data = kmalloc((sizeof(struct msm_rpm_iv_pair) * count),
230 GFP_KERNEL);
Gagan Mac47a999a2012-01-18 20:36:12 -0700231 return (void *)rpm_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700232}
233
234#define BWMASK 0x7FFF
235#define TIERMASK 0x8000
236#define GET_TIER(n) (((n) & TIERMASK) >> 15)
237
Gagan Mac47a999a2012-01-18 20:36:12 -0700238static void msm_bus_rpm_update_bw(struct msm_bus_inode_info *hop,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700239 struct msm_bus_inode_info *info,
240 struct msm_bus_fabric_registration *fab_pdata,
241 void *sel_cdata, int *master_tiers,
Gagan Macb2372ae2012-08-20 19:24:32 -0600242 int64_t add_bw)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700243{
Gagan Mac9c455662011-10-11 16:25:06 -0600244 int index, i, j, tiers, ports;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245 struct commit_data *sel_cd = (struct commit_data *)sel_cdata;
246
Gagan Mac9c455662011-10-11 16:25:06 -0600247 add_bw = INTERLEAVED_BW(fab_pdata, add_bw, info->node_info->num_mports);
248 ports = INTERLEAVED_VAL(fab_pdata, info->node_info->num_mports);
249 tiers = INTERLEAVED_VAL(fab_pdata, hop->node_info->num_tiers);
250 for (i = 0; i < tiers; i++) {
251 for (j = 0; j < ports; j++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700252 uint16_t hop_tier;
Gagan Macc7c0db62011-07-20 13:07:29 -0600253 /*
254 * For interleaved gateway ports and slave ports,
255 * there is one-one mapping between gateway port and
256 * the slave port
257 */
258 if (info->node_info->gateway && i != j &&
259 (hop->node_info->num_sports > 1))
260 continue;
261
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700262 if (!hop->node_info->tier)
263 hop_tier = MSM_BUS_BW_TIER2 - 1;
264 else
265 hop_tier = hop->node_info->tier[i] - 1;
266 index = ((hop_tier * fab_pdata->nmasters) +
267 (info->node_info->masterp[j]));
268 /* If there is tier, calculate arb for commit */
269 if (hop->node_info->tier) {
270 uint16_t tier;
271 unsigned long tieredbw = sel_cd->actarb[index];
272 if (GET_TIER(sel_cd->arb[index]))
273 tier = MSM_BUS_BW_TIER1;
274 else if (master_tiers)
275 /*
276 * By default master is only in the
277 * tier specified by default.
278 * To change the default tier, client
279 * needs to explicitly request for a
280 * different supported tier */
281 tier = master_tiers[0];
282 else
283 tier = MSM_BUS_BW_TIER2;
Gagan Macc7c0db62011-07-20 13:07:29 -0600284
285 /*
286 * Make sure gateway to slave port bandwidth
287 * is not divided when slave is interleaved
288 */
289 if (info->node_info->gateway
290 && hop->node_info->num_sports > 1)
291 tieredbw += add_bw;
292 else
Gagan Mac9c455662011-10-11 16:25:06 -0600293 tieredbw += INTERLEAVED_BW(fab_pdata,
294 add_bw, hop->node_info->
295 num_sports);
Gagan Macc7c0db62011-07-20 13:07:29 -0600296
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700297 /* If bw is 0, update tier to default */
298 if (!tieredbw)
299 tier = MSM_BUS_BW_TIER2;
300 /* Update Arb for fab,get HW Mport from enum */
301 sel_cd->arb[index] =
302 msm_bus_create_bw_tier_pair_bytes(tier,
303 tieredbw);
304 sel_cd->actarb[index] = tieredbw;
Gagan Macb2372ae2012-08-20 19:24:32 -0600305 MSM_BUS_DBG("tr:%d mpor:%d tbw:%ld bws: %lld\n",
306 hop_tier, info->node_info->masterp[i],
307 tieredbw, *hop->link_info.sel_bw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700308 }
309 }
310 }
311
312 /* Update bwsum for slaves on fabric */
Gagan Mac9c455662011-10-11 16:25:06 -0600313 ports = INTERLEAVED_VAL(fab_pdata, hop->node_info->num_sports);
314 for (i = 0; i < ports; i++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315 sel_cd->bwsum[hop->node_info->slavep[i]]
316 = (uint16_t)msm_bus_create_bw_tier_pair_bytes(0,
Gagan Macb2372ae2012-08-20 19:24:32 -0600317 (uint32_t)msm_bus_div64(hop->node_info->num_sports,
318 *hop->link_info.sel_bw));
319 MSM_BUS_DBG("slavep:%d, link_bw: %u\n",
320 hop->node_info->slavep[i], (uint32_t)
321 msm_bus_div64(hop->node_info->num_sports,
322 *hop->link_info.sel_bw));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700323 }
324}
325
326#define RPM_SHIFT_VAL 16
327#define RPM_SHIFT(n) ((n) << RPM_SHIFT_VAL)
Gagan Mac8661a0e2011-10-19 18:35:48 -0600328static int msm_bus_rpm_compare_cdata(
329 struct msm_bus_fabric_registration *fab_pdata,
330 struct commit_data *cd1, struct commit_data *cd2)
331{
332 size_t n;
333 int ret;
334 n = sizeof(uint16_t) * fab_pdata->nslaves;
335 ret = memcmp(cd1->bwsum, cd2->bwsum, n);
336 if (ret) {
337 MSM_BUS_DBG("Commit Data bwsum not equal\n");
338 return ret;
339 }
340
341 n = sizeof(uint16_t *) * ((fab_pdata->ntieredslaves *
342 fab_pdata->nmasters) + 1);
343 ret = memcmp(cd1->arb, cd2->arb, n);
344 if (ret) {
Stephen Boyd8704c7f2012-02-05 01:07:45 -0800345 MSM_BUS_DBG("Commit Data arb[%d] not equal\n", n);
Gagan Mac8661a0e2011-10-19 18:35:48 -0600346 return ret;
347 }
348
349 return 0;
350}
351
352static int msm_bus_rpm_commit_arb(struct msm_bus_fabric_registration
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700353 *fab_pdata, int ctx, struct msm_rpm_iv_pair *rpm_data,
Gagan Mac8661a0e2011-10-19 18:35:48 -0600354 struct commit_data *cd, bool valid)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700355{
356 int i, j, offset = 0, status = 0, count, index = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700357 /*
358 * count is the number of 2-byte words required to commit the
359 * data to rpm. This is calculated by the following formula.
360 * Commit data is split into two arrays:
361 * 1. arb[nmasters * ntieredslaves]
362 * 2. bwsum[nslaves]
363 */
364 count = ((fab_pdata->nmasters * fab_pdata->ntieredslaves)
365 + (fab_pdata->nslaves) + 1)/2;
366
367 offset = fab_pdata->offset;
368
369 /*
370 * Copy bwsum to rpm data
371 * Since bwsum is uint16, the values need to be adjusted to
372 * be copied to value field of rpm-data, which is 32 bits.
373 */
Gagan Macc7c0db62011-07-20 13:07:29 -0600374 for (i = 0; i < (fab_pdata->nslaves - 1); i += 2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375 rpm_data[index].id = offset + index;
376 rpm_data[index].value = RPM_SHIFT(*(cd->bwsum + i + 1)) |
377 *(cd->bwsum + i);
378 index++;
379 }
380 /* Account for odd number of slaves */
381 if (fab_pdata->nslaves & 1) {
382 rpm_data[index].id = offset + index;
383 rpm_data[index].value = *(cd->arb);
384 rpm_data[index].value = RPM_SHIFT(rpm_data[index].value) |
385 *(cd->bwsum + i);
386 index++;
387 i = 1;
388 } else
389 i = 0;
390
391 /* Copy arb values to rpm data */
392 for (; i < (fab_pdata->ntieredslaves * fab_pdata->nmasters);
393 i += 2) {
394 rpm_data[index].id = offset + index;
395 rpm_data[index].value = RPM_SHIFT(*(cd->arb + i + 1)) |
396 *(cd->arb + i);
397 index++;
398 }
399
Gagan Mac6d7738a2011-07-21 14:23:31 -0600400 MSM_BUS_DBG("rpm data for fab: %d\n", fab_pdata->id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401 for (i = 0; i < count; i++)
Gagan Mac6d7738a2011-07-21 14:23:31 -0600402 MSM_BUS_DBG("%d %x\n", rpm_data[i].id, rpm_data[i].value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700403
Gagan Mac6d7738a2011-07-21 14:23:31 -0600404 MSM_BUS_DBG("Commit Data: Fab: %d BWSum:\n", fab_pdata->id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700405 for (i = 0; i < fab_pdata->nslaves; i++)
Gagan Mac6d7738a2011-07-21 14:23:31 -0600406 MSM_BUS_DBG("fab_slaves:0x%x\n", cd->bwsum[i]);
407 MSM_BUS_DBG("Commit Data: Fab: %d Arb:\n", fab_pdata->id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700408 for (i = 0; i < fab_pdata->ntieredslaves; i++) {
Gagan Mac6d7738a2011-07-21 14:23:31 -0600409 MSM_BUS_DBG("tiered-slave: %d\n", i);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700410 for (j = 0; j < fab_pdata->nmasters; j++)
Gagan Mac6d7738a2011-07-21 14:23:31 -0600411 MSM_BUS_DBG(" 0x%x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700412 cd->arb[(i * fab_pdata->nmasters) + j]);
413 }
414
Gagan Mac6d7738a2011-07-21 14:23:31 -0600415 MSM_BUS_DBG("calling msm_rpm_set: %d\n", status);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700416 msm_bus_dbg_commit_data(fab_pdata->name, cd, fab_pdata->
417 nmasters, fab_pdata->nslaves, fab_pdata->ntieredslaves,
418 MSM_BUS_DBG_OP);
419 if (fab_pdata->rpm_enabled) {
Gagan Mac8661a0e2011-10-19 18:35:48 -0600420 if (valid) {
421 if (ctx == ACTIVE_CTX) {
422 status = msm_rpm_set(MSM_RPM_CTX_SET_0,
423 rpm_data, count);
424 MSM_BUS_DBG("msm_rpm_set returned: %d\n",
425 status);
426 } else if (ctx == DUAL_CTX) {
427 status = msm_rpm_set(MSM_RPM_CTX_SET_SLEEP,
428 rpm_data, count);
429 MSM_BUS_DBG("msm_rpm_set returned: %d\n",
430 status);
431 }
432 } else {
433 if (ctx == ACTIVE_CTX) {
434 status = msm_rpm_clear(MSM_RPM_CTX_SET_0,
435 rpm_data, count);
436 MSM_BUS_DBG("msm_rpm_clear returned: %d\n",
437 status);
438 } else if (ctx == DUAL_CTX) {
439 status = msm_rpm_clear(MSM_RPM_CTX_SET_SLEEP,
440 rpm_data, count);
441 MSM_BUS_DBG("msm_rpm_clear returned: %d\n",
442 status);
443 }
444 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700445 }
446
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700447 return status;
448}
449
Gagan Mac85c70492011-06-10 16:07:47 -0600450#else
451
452#define NUM_TIERS 2
453#define RPM_SHIFT24(n) ((n) << 24)
454#define RPM_SHIFT16(n) ((n) << 16)
455#define RPM_SHIFT8(n) ((n) << 8)
456struct commit_data {
457 uint16_t *bwsum;
458 uint8_t *arb[NUM_TIERS];
459 unsigned long *actarb[NUM_TIERS];
460};
461
462#define MODE_BIT(val) ((val) & 0x80)
463#define MODE0_IMM(val) ((val) & 0xF)
464#define MODE0_SHIFT(val) (((val) & 0x70) >> 4)
465#define MODE1_STEP 48 /* 48 MB */
466#define MODE1_OFFSET 512 /* 512 MB */
467#define MODE1_IMM(val) ((val) & 0x7F)
468#define __CLZ(x) ((8 * sizeof(uint32_t)) - 1 - __fls(x))
469
Gagan Mac47a999a2012-01-18 20:36:12 -0700470static uint8_t msm_bus_set_bw_bytes(unsigned long val)
Gagan Mac85c70492011-06-10 16:07:47 -0600471{
472 unsigned int shift;
473 unsigned int intVal;
474 unsigned char result;
475
476 /* Convert to MB */
477 intVal = (unsigned int)((val + ((1 << 20) - 1)) >> 20);
478 /**
479 * Divide by 2^20 and round up
480 * A value graeter than 0x1E0 will round up to 512 and overflow
481 * Mode 0 so it should be made Mode 1
482 */
483 if (0x1E0 > intVal) {
484 /**
485 * MODE 0
486 * Compute the shift value
487 * Shift value is 32 - the number of leading zeroes -
488 * 4 to save the most significant 4 bits of the value
489 */
490 shift = 32 - 4 - min((uint8_t)28, (uint8_t)__CLZ(intVal));
491
492 /* Add min value - 1 to force a round up when shifting right */
493 intVal += (1 << shift) - 1;
494
495 /* Recompute the shift value in case there was an overflow */
496 shift = 32 - 4 - min((uint8_t)28, (uint8_t)__CLZ(intVal));
497
498 /* Clear the mode bit (msb) and fill in the fields */
499 result = ((0x70 & (shift << 4)) |
500 (0x0F & (intVal >> shift)));
501 } else {
502 /* MODE 1 */
503 result = (unsigned char)(0x80 |
504 ((intVal - MODE1_OFFSET + MODE1_STEP - 1) /
505 MODE1_STEP));
506 }
507
508 return result;
509}
510
511uint64_t msm_bus_get_bw(unsigned long val)
512{
513 return MODE_BIT(val) ?
514 /* Mode 1 */
515 (MODE1_IMM(val) * MODE1_STEP + MODE1_OFFSET) :
516 /* Mode 0 */
517 (MODE0_IMM(val) << MODE0_SHIFT(val));
518}
519
520uint64_t msm_bus_get_bw_bytes(unsigned long val)
521{
522 return msm_bus_get_bw(val) << 20;
523}
524
Gagan Mac47a999a2012-01-18 20:36:12 -0700525static uint8_t msm_bus_create_bw_tier_pair_bytes(uint8_t type,
526 unsigned long bw)
Gagan Mac85c70492011-06-10 16:07:47 -0600527{
528 return msm_bus_set_bw_bytes(bw);
529};
530
531uint8_t msm_bus_create_bw_tier_pair(uint8_t type, unsigned long bw)
532{
533 return msm_bus_create_bw_tier_pair_bytes(type, bw);
534};
535
Gagan Mac47a999a2012-01-18 20:36:12 -0700536static int msm_bus_rpm_allocate_commit_data(struct msm_bus_fabric_registration
537 *fab_pdata, void **cdata, int ctx)
Gagan Mac85c70492011-06-10 16:07:47 -0600538{
539 struct commit_data **cd = (struct commit_data **)cdata;
540 int i;
541
542 *cd = kzalloc(sizeof(struct commit_data), GFP_KERNEL);
Gagan Mac47a999a2012-01-18 20:36:12 -0700543 if (!*cd) {
Gagan Mac60569172011-11-09 16:17:12 -0700544 MSM_BUS_DBG("Couldn't alloc mem for cdata\n");
Gagan Mac85c70492011-06-10 16:07:47 -0600545 goto cdata_err;
546 }
547
548 (*cd)->bwsum = kzalloc((sizeof(uint16_t) * fab_pdata->nslaves),
549 GFP_KERNEL);
550 if (!(*cd)->bwsum) {
Gagan Mac60569172011-11-09 16:17:12 -0700551 MSM_BUS_DBG("Couldn't alloc mem for slaves\n");
Gagan Mac85c70492011-06-10 16:07:47 -0600552 goto bwsum_err;
553 }
554
555 for (i = 0; i < NUM_TIERS; i++) {
556 (*cd)->arb[i] = kzalloc(((sizeof(uint8_t *)) *
557 (fab_pdata->ntieredslaves * fab_pdata->nmasters) + 1),
558 GFP_KERNEL);
559 if (!(*cd)->arb[i]) {
Gagan Mac60569172011-11-09 16:17:12 -0700560 MSM_BUS_DBG("Couldn't alloc memory for"
Gagan Mac85c70492011-06-10 16:07:47 -0600561 " slaves\n");
562 goto arb_err;
563 }
564
565 (*cd)->actarb[i] = kzalloc(((sizeof(unsigned long *)) *
566 (fab_pdata->ntieredslaves * fab_pdata->nmasters) + 1),
567 GFP_KERNEL);
568 if (!(*cd)->actarb[i]) {
Gagan Mac60569172011-11-09 16:17:12 -0700569 MSM_BUS_DBG("Couldn't alloc memory for"
Gagan Mac85c70492011-06-10 16:07:47 -0600570 " slaves\n");
571 kfree((*cd)->arb[i]);
572 goto arb_err;
573 }
574 }
575
576
577 return 0;
578
579arb_err:
580 for (i = i - 1; i >= 0; i--) {
581 kfree((*cd)->arb[i]);
582 kfree((*cd)->actarb[i]);
583 }
584bwsum_err:
585 kfree((*cd)->bwsum);
586cdata_err:
587 kfree(*cd);
588 return -ENOMEM;
589}
590
Gagan Mac47a999a2012-01-18 20:36:12 -0700591static void free_commit_data(void *cdata)
Gagan Mac85c70492011-06-10 16:07:47 -0600592{
593 int i;
594 struct commit_data *cd = (struct commit_data *)cdata;
595 kfree(cd->bwsum);
596 for (i = 0; i < NUM_TIERS; i++) {
597 kfree(cd->arb[i]);
598 kfree(cd->actarb[i]);
599 }
600 kfree(cd);
601}
602
Gagan Mac47a999a2012-01-18 20:36:12 -0700603static void *msm_bus_rpm_allocate_rpm_data(struct platform_device *pdev,
604 struct msm_bus_fabric_registration *fab_pdata)
Gagan Mac85c70492011-06-10 16:07:47 -0600605{
606 struct msm_rpm_iv_pair *rpm_data;
607 uint16_t count = (((fab_pdata->nmasters * fab_pdata->ntieredslaves *
608 NUM_TIERS)/2) + fab_pdata->nslaves + 1)/2;
609
610 rpm_data = kmalloc((sizeof(struct msm_rpm_iv_pair) * count),
611 GFP_KERNEL);
Gagan Mac47a999a2012-01-18 20:36:12 -0700612 return (void *)rpm_data;
Gagan Mac85c70492011-06-10 16:07:47 -0600613}
614
Gagan Mac8661a0e2011-10-19 18:35:48 -0600615static int msm_bus_rpm_compare_cdata(
616 struct msm_bus_fabric_registration *fab_pdata,
617 struct commit_data *cd1, struct commit_data *cd2)
Gagan Mac85c70492011-06-10 16:07:47 -0600618{
Gagan Mac8661a0e2011-10-19 18:35:48 -0600619 size_t n;
620 int i, ret;
621 n = sizeof(uint16_t) * fab_pdata->nslaves;
622 ret = memcmp(cd1->bwsum, cd2->bwsum, n);
623 if (ret) {
624 MSM_BUS_DBG("Commit Data bwsum not equal\n");
625 return ret;
626 }
Gagan Mac85c70492011-06-10 16:07:47 -0600627
Gagan Mac8661a0e2011-10-19 18:35:48 -0600628 n = sizeof(uint8_t *) * ((fab_pdata->ntieredslaves *
629 fab_pdata->nmasters) + 1);
630 for (i = 0; i < NUM_TIERS; i++) {
631 ret = memcmp(cd1->arb[i], cd2->arb[i], n);
632 if (ret) {
633 MSM_BUS_DBG("Commit Data arb[%d] not equal\n", i);
634 return ret;
635 }
636 }
637
638 return 0;
639}
640
641static int msm_bus_rpm_commit_arb(struct msm_bus_fabric_registration
642 *fab_pdata, int ctx, struct msm_rpm_iv_pair *rpm_data,
643 struct commit_data *cd, bool valid)
644{
Gagan Mac85c70492011-06-10 16:07:47 -0600645 int i, j, k, offset = 0, status = 0, count, index = 0;
Gagan Mac85c70492011-06-10 16:07:47 -0600646 /*
647 * count is the number of 2-byte words required to commit the
648 * data to rpm. This is calculated by the following formula.
649 * Commit data is split into two arrays:
650 * 1. arb[nmasters * ntieredslaves][num_tiers]
651 * 2. bwsum[nslaves]
652 */
653 count = (((fab_pdata->nmasters * fab_pdata->ntieredslaves * NUM_TIERS)
654 /2) + fab_pdata->nslaves + 1)/2;
655
656 offset = fab_pdata->offset;
657
658 /*
659 * Copy bwsum to rpm data
660 * Since bwsum is uint16, the values need to be adjusted to
661 * be copied to value field of rpm-data, which is 32 bits.
662 */
663 for (i = 0; i < (fab_pdata->nslaves - 1); i += 2) {
664 rpm_data[index].id = offset + index;
665 rpm_data[index].value = RPM_SHIFT16(*(cd->bwsum + i + 1)) |
666 *(cd->bwsum + i);
667 index++;
668 }
669 /* Account for odd number of slaves */
670 if (fab_pdata->nslaves & 1) {
671 rpm_data[index].id = offset + index;
672 rpm_data[index].value = RPM_SHIFT8(*cd->arb[1]) |
673 *(cd->arb[0]);
674 rpm_data[index].value = RPM_SHIFT16(rpm_data[index].value) |
675 *(cd->bwsum + i);
676 index++;
677 i = 1;
678 } else
679 i = 0;
680
681 /* Copy arb values to rpm data */
682 for (; i < (fab_pdata->ntieredslaves * fab_pdata->nmasters);
683 i += 2) {
684 uint16_t tv1, tv0;
685 rpm_data[index].id = offset + index;
686 tv0 = RPM_SHIFT8(*(cd->arb[1] + i)) | (*(cd->arb[0] + i));
687 tv1 = RPM_SHIFT8(*(cd->arb[1] + i + 1)) | (*(cd->arb[0] + i
688 + 1));
689 rpm_data[index].value = RPM_SHIFT16(tv1) | tv0;
690 index++;
691 }
692
693 MSM_BUS_DBG("rpm data for fab: %d\n", fab_pdata->id);
694 for (i = 0; i < count; i++)
Gagan Mac60569172011-11-09 16:17:12 -0700695 MSM_BUS_DBG("%d %x\n", rpm_data[i].id, rpm_data[i].value);
Gagan Mac85c70492011-06-10 16:07:47 -0600696
697 MSM_BUS_DBG("Commit Data: Fab: %d BWSum:\n", fab_pdata->id);
698 for (i = 0; i < fab_pdata->nslaves; i++)
Gagan Mac60569172011-11-09 16:17:12 -0700699 MSM_BUS_DBG("fab_slaves:0x%x\n", cd->bwsum[i]);
Gagan Mac85c70492011-06-10 16:07:47 -0600700 MSM_BUS_DBG("Commit Data: Fab: %d Arb:\n", fab_pdata->id);
701 for (k = 0; k < NUM_TIERS; k++) {
702 MSM_BUS_DBG("Tier: %d\n", k);
703 for (i = 0; i < fab_pdata->ntieredslaves; i++) {
704 MSM_BUS_DBG("tiered-slave: %d\n", i);
705 for (j = 0; j < fab_pdata->nmasters; j++)
706 MSM_BUS_DBG(" 0x%x\n",
707 cd->arb[k][(i * fab_pdata->nmasters)
708 + j]);
709 }
710 }
711
Gagan Mac60569172011-11-09 16:17:12 -0700712 MSM_BUS_DBG("calling msm_rpm_set: %d\n", status);
Gagan Mac8661a0e2011-10-19 18:35:48 -0600713 msm_bus_dbg_commit_data(fab_pdata->name, (void *)cd, fab_pdata->
Gagan Mac85c70492011-06-10 16:07:47 -0600714 nmasters, fab_pdata->nslaves, fab_pdata->ntieredslaves,
715 MSM_BUS_DBG_OP);
716 if (fab_pdata->rpm_enabled) {
Gagan Mac8661a0e2011-10-19 18:35:48 -0600717 if (valid) {
718 if (ctx == ACTIVE_CTX) {
719 status = msm_rpm_set(MSM_RPM_CTX_SET_0,
720 rpm_data, count);
721 MSM_BUS_DBG("msm_rpm_set returned: %d\n",
722 status);
723 } else if (ctx == DUAL_CTX) {
724 status = msm_rpm_set(MSM_RPM_CTX_SET_SLEEP,
725 rpm_data, count);
726 MSM_BUS_DBG("msm_rpm_set returned: %d\n",
727 status);
728 }
729 } else {
730 if (ctx == ACTIVE_CTX) {
731 status = msm_rpm_clear(MSM_RPM_CTX_SET_0,
732 rpm_data, count);
733 MSM_BUS_DBG("msm_rpm_clear returned: %d\n",
734 status);
735 } else if (ctx == DUAL_CTX) {
736 status = msm_rpm_clear(MSM_RPM_CTX_SET_SLEEP,
737 rpm_data, count);
738 MSM_BUS_DBG("msm_rpm_clear returned: %d\n",
739 status);
740 }
741 }
Gagan Mac85c70492011-06-10 16:07:47 -0600742 }
743
Gagan Mac85c70492011-06-10 16:07:47 -0600744 return status;
745}
746
747#define FORMAT_BW(x) \
748 ((x < 0) ? \
749 -(msm_bus_get_bw_bytes(msm_bus_create_bw_tier_pair_bytes(0, -(x)))) : \
750 (msm_bus_get_bw_bytes(msm_bus_create_bw_tier_pair_bytes(0, x))))
751
Gagan Mac47a999a2012-01-18 20:36:12 -0700752static uint16_t msm_bus_pack_bwsum_bytes(unsigned long bw)
Gagan Mac85c70492011-06-10 16:07:47 -0600753{
754 return (bw + ((1 << 20) - 1)) >> 20;
755};
756
Gagan Mac47a999a2012-01-18 20:36:12 -0700757static void msm_bus_rpm_update_bw(struct msm_bus_inode_info *hop,
Gagan Mac85c70492011-06-10 16:07:47 -0600758 struct msm_bus_inode_info *info,
759 struct msm_bus_fabric_registration *fab_pdata,
760 void *sel_cdata, int *master_tiers,
Gagan Macb2372ae2012-08-20 19:24:32 -0600761 int64_t add_bw)
Gagan Mac85c70492011-06-10 16:07:47 -0600762{
Gagan Mac9c455662011-10-11 16:25:06 -0600763 int index, i, j, tiers, ports;
Gagan Mac85c70492011-06-10 16:07:47 -0600764 struct commit_data *sel_cd = (struct commit_data *)sel_cdata;
765
Gagan Mac9c455662011-10-11 16:25:06 -0600766 add_bw = INTERLEAVED_BW(fab_pdata, add_bw, info->node_info->num_mports);
767 ports = INTERLEAVED_VAL(fab_pdata, info->node_info->num_mports);
768 tiers = INTERLEAVED_VAL(fab_pdata, hop->node_info->num_tiers);
769 for (i = 0; i < tiers; i++) {
770 for (j = 0; j < ports; j++) {
Gagan Mac85c70492011-06-10 16:07:47 -0600771 uint16_t hop_tier;
772 /*
773 * For interleaved gateway ports and slave ports,
774 * there is one-one mapping between gateway port and
775 * the slave port
776 */
777 if (info->node_info->gateway && i != j
778 && hop->node_info->num_sports > 1)
779 continue;
780
781 if (!hop->node_info->tier)
782 hop_tier = MSM_BUS_BW_TIER2 - 1;
783 else
784 hop_tier = hop->node_info->tier[i] - 1;
785 index = ((hop_tier * fab_pdata->nmasters) +
786 (info->node_info->masterp[j]));
787 /* If there is tier, calculate arb for commit */
788 if (hop->node_info->tier) {
789 uint16_t tier;
790 unsigned long tieredbw;
791 if (master_tiers)
792 tier = master_tiers[0] - 1;
793 else
794 tier = MSM_BUS_BW_TIER2 - 1;
795
796 tieredbw = sel_cd->actarb[tier][index];
797 /*
798 * Make sure gateway to slave port bandwidth
799 * is not divided when slave is interleaved
800 */
801 if (info->node_info->gateway
802 && hop->node_info->num_sports > 1)
803 tieredbw += add_bw;
804 else
Gagan Mac9c455662011-10-11 16:25:06 -0600805 tieredbw += INTERLEAVED_BW(fab_pdata,
806 add_bw, hop->node_info->
807 num_sports);
Gagan Mac85c70492011-06-10 16:07:47 -0600808
809 /* Update Arb for fab,get HW Mport from enum */
810 sel_cd->arb[tier][index] =
811 msm_bus_create_bw_tier_pair_bytes(0, tieredbw);
812 sel_cd->actarb[tier][index] = tieredbw;
Gagan Macb2372ae2012-08-20 19:24:32 -0600813 MSM_BUS_DBG("tr:%d mpor:%d tbw:%lu bws: %lld\n",
814 hop_tier, info->node_info->masterp[i], tieredbw,
815 *hop->link_info.sel_bw);
Gagan Mac85c70492011-06-10 16:07:47 -0600816 }
817 }
818 }
819
820 /* Update bwsum for slaves on fabric */
Gagan Mac9c455662011-10-11 16:25:06 -0600821
822 ports = INTERLEAVED_VAL(fab_pdata, hop->node_info->num_sports);
823 for (i = 0; i < ports; i++) {
Gagan Mac85c70492011-06-10 16:07:47 -0600824 sel_cd->bwsum[hop->node_info->slavep[i]]
Gagan Macb2372ae2012-08-20 19:24:32 -0600825 = msm_bus_pack_bwsum_bytes((uint32_t)
826 msm_bus_div64(hop->node_info->num_sports,
827 *hop->link_info.sel_bw));
828 MSM_BUS_DBG("slavep:%d, link_bw: %lld\n",
829 hop->node_info->slavep[i],
830 msm_bus_div64(hop->node_info->num_sports,
831 *hop->link_info.sel_bw));
Gagan Mac85c70492011-06-10 16:07:47 -0600832 }
833}
834
835
836void msm_bus_rpm_fill_cdata_buffer(int *curr, char *buf, const int max_size,
837 void *cdata, int nmasters, int nslaves, int ntslaves)
838{
839 int j, k, c;
840 struct commit_data *cd = (struct commit_data *)cdata;
841
842 *curr += scnprintf(buf + *curr, max_size - *curr, "BWSum:\n");
843 for (c = 0; c < nslaves; c++)
844 *curr += scnprintf(buf + *curr, max_size - *curr,
845 "0x%x\t", cd->bwsum[c]);
846 *curr += scnprintf(buf + *curr, max_size - *curr, "\nArb:");
847 for (k = 0; k < NUM_TIERS; k++) {
848 *curr += scnprintf(buf + *curr, max_size - *curr,
849 "\nTier %d:\n", k);
850 for (c = 0; c < ntslaves; c++) {
851 *curr += scnprintf(buf + *curr, max_size - *curr,
852 "TSlave %d:\n", c);
853 for (j = 0; j < nmasters; j++)
854 *curr += scnprintf(buf + *curr, max_size -
855 *curr, " 0x%x\t",
856 cd->arb[k][(c * nmasters) + j]);
857 }
858 }
859}
860#endif
Gagan Mac8661a0e2011-10-19 18:35:48 -0600861
862/**
863* msm_bus_rpm_commit() - Commit the arbitration data to RPM
864* @fabric: Fabric for which the data should be committed
865**/
Gagan Mac47a999a2012-01-18 20:36:12 -0700866static int msm_bus_rpm_commit(struct msm_bus_fabric_registration
867 *fab_pdata, void *hw_data, void **cdata)
Gagan Mac8661a0e2011-10-19 18:35:48 -0600868{
869
870 int ret;
871 bool valid;
872 struct commit_data *dual_cd, *act_cd;
Gagan Mac47a999a2012-01-18 20:36:12 -0700873 struct msm_rpm_iv_pair *rpm_data = (struct msm_rpm_iv_pair *)hw_data;
Gagan Mac8661a0e2011-10-19 18:35:48 -0600874 dual_cd = (struct commit_data *)cdata[DUAL_CTX];
875 act_cd = (struct commit_data *)cdata[ACTIVE_CTX];
876
877 /*
878 * If the arb data for active set and sleep set is
879 * different, commit both sets.
880 * If the arb data for active set and sleep set is
881 * the same, invalidate the sleep set.
882 */
883 ret = msm_bus_rpm_compare_cdata(fab_pdata, act_cd, dual_cd);
884 if (!ret)
885 /* Invalidate sleep set.*/
886 valid = false;
887 else
888 valid = true;
889
890 ret = msm_bus_rpm_commit_arb(fab_pdata, DUAL_CTX, rpm_data,
891 dual_cd, valid);
892 if (ret)
893 MSM_BUS_ERR("Error comiting fabric:%d in %d ctx\n",
894 fab_pdata->id, DUAL_CTX);
895
896 valid = true;
897 ret = msm_bus_rpm_commit_arb(fab_pdata, ACTIVE_CTX, rpm_data, act_cd,
898 valid);
899 if (ret)
900 MSM_BUS_ERR("Error comiting fabric:%d in %d ctx\n",
901 fab_pdata->id, ACTIVE_CTX);
902
903 return ret;
904}
Gagan Mac47a999a2012-01-18 20:36:12 -0700905
906static int msm_bus_rpm_port_halt(uint32_t haltid, uint8_t mport)
907{
908 int status = 0;
909 struct msm_bus_halt_vector hvector = {0, 0};
910 struct msm_rpm_iv_pair rpm_data[2];
911
912 MSM_BUS_MASTER_HALT(hvector.haltmask, hvector.haltval, mport);
913 rpm_data[0].id = haltid;
914 rpm_data[0].value = hvector.haltval;
915 rpm_data[1].id = haltid + 1;
916 rpm_data[1].value = hvector.haltmask;
917
918 MSM_BUS_DBG("ctx: %d, id: %d, value: %d\n",
919 MSM_RPM_CTX_SET_0, rpm_data[0].id, rpm_data[0].value);
920 MSM_BUS_DBG("ctx: %d, id: %d, value: %d\n",
921 MSM_RPM_CTX_SET_0, rpm_data[1].id, rpm_data[1].value);
922
923 status = msm_rpm_set(MSM_RPM_CTX_SET_0, rpm_data, 2);
924 if (status)
925 MSM_BUS_DBG("msm_rpm_set returned: %d\n", status);
926 return status;
927}
928
929static int msm_bus_rpm_port_unhalt(uint32_t haltid, uint8_t mport)
930{
931 int status = 0;
932 struct msm_bus_halt_vector hvector = {0, 0};
933 struct msm_rpm_iv_pair rpm_data[2];
934
935 MSM_BUS_MASTER_UNHALT(hvector.haltmask, hvector.haltval,
936 mport);
937 rpm_data[0].id = haltid;
938 rpm_data[0].value = hvector.haltval;
939 rpm_data[1].id = haltid + 1;
940 rpm_data[1].value = hvector.haltmask;
941
942 MSM_BUS_DBG("unalt: ctx: %d, id: %d, value: %d\n",
943 MSM_RPM_CTX_SET_SLEEP, rpm_data[0].id, rpm_data[0].value);
944 MSM_BUS_DBG("unhalt: ctx: %d, id: %d, value: %d\n",
945 MSM_RPM_CTX_SET_SLEEP, rpm_data[1].id, rpm_data[1].value);
946
947 status = msm_rpm_set(MSM_RPM_CTX_SET_0, rpm_data, 2);
948 if (status)
949 MSM_BUS_DBG("msm_rpm_set returned: %d\n", status);
950 return status;
951}
952
Gagan Macb91c4072012-05-09 16:00:31 -0600953int msm_bus_remote_hw_commit(struct msm_bus_fabric_registration
954 *fab_pdata, void *hw_data, void **cdata)
955{
956 return 0;
957}
958
Gagan Mac47a999a2012-01-18 20:36:12 -0700959int msm_bus_rpm_hw_init(struct msm_bus_fabric_registration *pdata,
960 struct msm_bus_hw_algorithm *hw_algo)
961{
962 pdata->il_flag = msm_bus_rpm_is_mem_interleaved();
963 hw_algo->allocate_commit_data = msm_bus_rpm_allocate_commit_data;
964 hw_algo->allocate_hw_data = msm_bus_rpm_allocate_rpm_data;
965 hw_algo->node_init = NULL;
966 hw_algo->free_commit_data = free_commit_data;
967 hw_algo->update_bw = msm_bus_rpm_update_bw;
968 hw_algo->commit = msm_bus_rpm_commit;
969 hw_algo->port_halt = msm_bus_rpm_port_halt;
970 hw_algo->port_unhalt = msm_bus_rpm_port_unhalt;
971 if (!pdata->ahb)
972 pdata->rpm_enabled = 1;
973 return 0;
974}