blob: 87d38b90eec0e27e1c3e425b569f1ea57e67dfca [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
2 *
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#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/device.h>
16#include <linux/slab.h>
17#include <linux/module.h>
18#include <linux/clk.h>
19#include <linux/radix-tree.h>
20#include <mach/clk.h>
21#include <mach/board.h>
22#include <mach/rpm.h>
23#include "msm_bus_core.h"
24
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025enum {
26 SLAVE_NODE,
27 MASTER_NODE,
28};
29
30enum {
31 DISABLE,
32 ENABLE,
33};
34
35struct msm_bus_fabric {
36 struct msm_bus_fabric_device fabdev;
37 int ahb;
38 void *cdata[NUM_CTX];
39 bool arb_dirty;
40 bool clk_dirty;
41 struct radix_tree_root fab_tree;
42 int num_nodes;
43 struct list_head gateways;
44 struct msm_bus_inode_info info;
45 const struct msm_bus_fab_algorithm *algo;
46 struct msm_bus_fabric_registration *pdata;
47 struct msm_rpm_iv_pair *rpm_data;
48};
49#define to_msm_bus_fabric(d) container_of(d, \
50 struct msm_bus_fabric, d)
51
52/**
53 * msm_bus_fabric_add_node() - Add a node to the fabric structure
54 * @fabric: Fabric device to which the node should be added
55 * @info: The node to be added
56 */
57static int msm_bus_fabric_add_node(struct msm_bus_fabric *fabric,
58 struct msm_bus_inode_info *info)
59{
60 int status = -ENOMEM;
61 MSM_FAB_DBG("msm_bus_fabric_add_node: ID %d Gw: %d\n",
62 info->node_info->priv_id, info->node_info->gateway);
63 status = radix_tree_preload(GFP_ATOMIC);
64 if (status)
65 goto out;
66 status = radix_tree_insert(&fabric->fab_tree, info->node_info->priv_id,
67 info);
68 if (IS_SLAVE(info->node_info->priv_id))
69 radix_tree_tag_set(&fabric->fab_tree, info->node_info->priv_id,
70 SLAVE_NODE);
71
72 if (info->node_info->slaveclk[DUAL_CTX]) {
73 info->nodeclk[DUAL_CTX].clk = clk_get(NULL,
74 info->node_info->slaveclk[DUAL_CTX]);
75 if (IS_ERR(info->nodeclk[DUAL_CTX].clk)) {
76 MSM_BUS_ERR("Could not get clock for %s\n",
77 info->node_info->slaveclk[DUAL_CTX]);
78 status = -EINVAL;
79 goto out;
80 }
81 info->nodeclk[DUAL_CTX].enable = false;
82 info->nodeclk[DUAL_CTX].dirty = false;
83 }
84 radix_tree_preload_end();
85out:
86 return status;
87}
88
89/**
90 * msm_bus_add_fab() - Add a fabric (gateway) to the current fabric
91 * @fabric: Fabric device to which the gateway info should be added
92 * @info: Gateway node to be added to the fabric
93 */
94static int msm_bus_fabric_add_fab(struct msm_bus_fabric *fabric,
95 struct msm_bus_inode_info *info)
96{
97 int status = 0;
98 struct msm_bus_fabnodeinfo *fabnodeinfo;
99 MSM_FAB_DBG("msm_bus_fabric_add_fab: ID %d Gw: %d\n",
100 info->node_info->priv_id, info->node_info->gateway);
101 fabnodeinfo = kzalloc(sizeof(struct msm_bus_fabnodeinfo), GFP_KERNEL);
102 if (!fabnodeinfo) {
103 MSM_FAB_ERR("msm_bus_fabric_add_fab: "
104 "No Node Info\n");
105 MSM_FAB_ERR("axi: Cannot register fabric!\n");
106 status = -ENOMEM;
107 }
108
109 fabnodeinfo->info = info;
110 fabnodeinfo->info->num_pnodes = -1;
111 list_add_tail(&fabnodeinfo->list, &fabric->gateways);
112 return status;
113}
114
115/**
116 * register_fabric_info() - Create the internal fabric structure and
117 * build the topology tree from platform specific data
118 *
119 * @fabric: Fabric to which the gateways, nodes should be added
120 *
121 * This function is called from probe. Iterates over the platform data,
122 * and builds the topology
123 */
124static int register_fabric_info(struct msm_bus_fabric *fabric)
125{
126 int i, ret = 0, err = 0;
127
128 MSM_FAB_DBG("id:%d pdata-id: %d len: %d\n", fabric->fabdev.id,
129 fabric->pdata->id, fabric->pdata->len);
130
131 for (i = 0; i < fabric->pdata->len; i++) {
132 struct msm_bus_inode_info *info;
133 int ctx;
134
135 info = kzalloc(sizeof(struct msm_bus_inode_info), GFP_KERNEL);
136 info->node_info = fabric->pdata->info + i;
137 info->commit_index = -1;
138 info->num_pnodes = -1;
139
140 for (ctx = 0; ctx < NUM_CTX; ctx++) {
141 if (info->node_info->slaveclk[ctx]) {
142 info->nodeclk[ctx].clk = clk_get(NULL,
143 info->node_info->slaveclk[ctx]);
144 if (IS_ERR(info->nodeclk[ctx].clk)) {
145 MSM_BUS_ERR("Couldn't get clk %s\n",
146 info->node_info->slaveclk[ctx]);
147 err = -EINVAL;
148 }
149 info->nodeclk[ctx].enable = false;
150 info->nodeclk[ctx].dirty = false;
151 }
152 }
153 if (info->node_info->memclk) {
154 info->memclk.clk = clk_get(NULL,
155 info->node_info->memclk);
156 if (IS_ERR(info->memclk.clk)) {
157 MSM_BUS_ERR("Couldn't get clk %s\n",
158 info->node_info->memclk);
159 err = -EINVAL;
160 }
161 info->memclk.enable = false;
162 info->memclk.dirty = false;
163 }
164
165 ret = info->node_info->gateway ?
166 msm_bus_fabric_add_fab(fabric, info) :
167 msm_bus_fabric_add_node(fabric, info);
168 if (ret) {
169 MSM_BUS_ERR("Unable to add node info, ret: %d\n", ret);
170 kfree(info);
171 goto error;
172 }
173 }
174
175 fabric->rpm_data = allocate_rpm_data(fabric->pdata);
176
177 MSM_FAB_DBG("Fabric: %d nmasters: %d nslaves: %d\n"
178 " ntieredslaves: %d, rpm_enabled: %d\n",
179 fabric->fabdev.id, fabric->pdata->nmasters,
180 fabric->pdata->nslaves, fabric->pdata->ntieredslaves,
181 fabric->pdata->rpm_enabled);
182 MSM_FAB_DBG("msm_bus_register_fabric_info i: %d\n", i);
183 fabric->num_nodes = fabric->pdata->len;
184error:
185 fabric->num_nodes = i;
186 msm_bus_dbg_commit_data(fabric->fabdev.name, NULL, 0, 0, 0,
187 MSM_BUS_DBG_REGISTER);
188 return ret | err;
189}
190
191/**
192 * msm_bus_fabric_update_clks() - Set the clocks for fabrics and slaves
193 * @fabric: Fabric for which the clocks need to be updated
194 * @slave: The node for which the clocks need to be updated
195 * @index: The index for which the current clocks are set
196 * @curr_clk_hz:Current clock value
197 * @req_clk_hz: Requested clock value
198 * @bwsum: Bandwidth Sum
199 * @clk_flag: Flag determining whether fabric clock or the slave clock has to
200 * be set. If clk_flag is set, fabric clock is set, else slave clock is set.
201 */
202static int msm_bus_fabric_update_clks(struct msm_bus_fabric_device *fabdev,
203 struct msm_bus_inode_info *slave, int index,
204 unsigned long curr_clk_hz, unsigned long req_clk_hz,
205 unsigned long bwsum_hz, int clk_flag, int ctx,
206 unsigned int cl_active_flag)
207{
208 int i, status = 0;
209 unsigned long max_pclk = 0, rate;
210 unsigned long *pclk = NULL;
211 struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
212 struct nodeclk *nodeclk;
213
214 /* Maximum for this gateway */
215 for (i = 0; i <= slave->num_pnodes; i++) {
216 if (i == index && (req_clk_hz < curr_clk_hz))
217 continue;
218 slave->pnode[i].sel_clk = &slave->pnode[i].clk[ctx];
219 max_pclk = max(max_pclk, *slave->pnode[i].sel_clk);
220 }
221
222 *slave->link_info.sel_clk =
223 max(max_pclk, max(bwsum_hz, req_clk_hz));
224 /* Is this gateway or slave? */
225 if (clk_flag && (!fabric->ahb)) {
226 struct msm_bus_fabnodeinfo *fabgw = NULL;
227 struct msm_bus_inode_info *info = NULL;
228 /* Maximum of all gateways set at fabric */
229 list_for_each_entry(fabgw, &fabric->gateways, list) {
230 info = fabgw->info;
231 if (!info)
232 continue;
233 info->link_info.sel_clk = &info->link_info.clk[ctx];
234 max_pclk = max(max_pclk, *info->link_info.sel_clk);
235 }
236 MSM_FAB_DBG("max_pclk from gateways: %lu\n", max_pclk);
237
238 /* Maximum of all slave clocks. */
239
240 for (i = 0; i < fabric->pdata->len; i++) {
241 if (fabric->pdata->info[i].gateway ||
242 (fabric->pdata->info[i].id < SLAVE_ID_KEY))
243 continue;
244 info = radix_tree_lookup(&fabric->fab_tree,
245 fabric->pdata->info[i].priv_id);
246 if (!info)
247 continue;
248 info->link_info.sel_clk = &info->link_info.clk[ctx];
249 max_pclk = max(max_pclk, *info->link_info.sel_clk);
250 }
251
252
253 MSM_FAB_DBG("max_pclk from slaves & gws: %lu\n", max_pclk);
254 fabric->info.link_info.sel_clk =
255 &fabric->info.link_info.clk[ctx];
256 pclk = fabric->info.link_info.sel_clk;
257 } else {
258 slave->link_info.sel_clk = &slave->link_info.clk[ctx];
259 pclk = slave->link_info.sel_clk;
260 }
261
262
263 *pclk = max(max_pclk, max(bwsum_hz, req_clk_hz));
264
265 if (!fabric->pdata->rpm_enabled)
266 goto skip_set_clks;
267
268 if (clk_flag) {
269 nodeclk = &fabric->info.nodeclk[ctx];
270 /**
271 * Send a clock request only when the client requests in active
272 * context and the ACTIVE_CTX clock rate is selected OR the
273 * client request is in normal context and normal clock rate
274 * is selected.
275 */
276 if (nodeclk->clk && (!((ctx == ACTIVE_CTX) ^ cl_active_flag))) {
277 MSM_BUS_DBG("clks: id: %d set-clk: %lu bwsum_hz:%lu\n",
278 fabric->fabdev.id, *pclk, bwsum_hz);
279 if (nodeclk->rate != *pclk) {
280 nodeclk->dirty = true;
281 nodeclk->rate = *pclk;
282 }
283 fabric->clk_dirty = true;
284 }
285 } else {
286 nodeclk = &slave->nodeclk[ctx];
287 if (nodeclk->clk && (!((ctx == ACTIVE_CTX) ^ cl_active_flag))) {
Gagan Macc7c0db62011-07-20 13:07:29 -0600288 rate = *pclk;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700289 MSM_BUS_DBG("AXI_clks: id: %d set-clk: %lu "
290 "bwsum_hz: %lu\n" , slave->node_info->priv_id, rate,
291 bwsum_hz);
Gagan Macc7c0db62011-07-20 13:07:29 -0600292 if (nodeclk->rate != rate) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700293 nodeclk->dirty = true;
294 nodeclk->rate = rate;
295 }
296 }
297 if (!status && slave->memclk.clk &&
298 (!((ctx == ACTIVE_CTX) ^ cl_active_flag))) {
Gagan Macc7c0db62011-07-20 13:07:29 -0600299 rate = *slave->link_info.sel_clk;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700300 if (slave->memclk.rate != rate) {
301 slave->memclk.rate = rate;
302 slave->memclk.dirty = true;
303 }
304 slave->memclk.rate = rate;
305 fabric->clk_dirty = true;
306 }
307 }
308skip_set_clks:
309 return status;
310}
311
312void msm_bus_fabric_update_bw(struct msm_bus_fabric_device *fabdev,
313 struct msm_bus_inode_info *hop, struct msm_bus_inode_info *info,
314 long int add_bw, int *master_tiers, int ctx)
315{
316 struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
317 void *sel_cdata;
318
319 sel_cdata = fabric->cdata[ctx];
320
321 /* If it's an ahb fabric, don't calculate arb values */
322 if (fabric->ahb) {
323 MSM_FAB_DBG("AHB fabric, skipping bw calculation\n");
324 return;
325 }
326 if (!add_bw) {
327 MSM_BUS_DBG("No bandwidth delta. Skipping commit\n");
328 return;
329 }
330
331 msm_bus_rpm_update_bw(hop, info, fabric->pdata, sel_cdata,
332 master_tiers, add_bw);
333 fabric->arb_dirty = true;
334}
335
336static int msm_bus_fabric_clk_set(int enable, struct msm_bus_inode_info *info)
337{
338 int i, status = 0;
339 for (i = 0; i < NUM_CTX; i++)
340 if (info->nodeclk[i].dirty) {
341 status = clk_set_min_rate(info->nodeclk[i].clk, info->
342 nodeclk[i].rate);
343 if (enable && !(info->nodeclk[i].enable)) {
344 clk_enable(info->nodeclk[i].clk);
345 info->nodeclk[i].dirty = false;
346 info->nodeclk[i].enable = true;
347 } else if ((info->nodeclk[i].rate == 0) && (!enable)
348 && (info->nodeclk[i].enable)) {
349 clk_disable(info->nodeclk[i].clk);
350 info->nodeclk[i].dirty = false;
351 info->nodeclk[i].enable = false;
352 }
353 }
354
355 if (info->memclk.dirty) {
356 status = clk_set_min_rate(info->memclk.clk, info->memclk.rate);
357 if (enable && !(info->memclk.enable)) {
358 clk_enable(info->memclk.clk);
359 info->memclk.dirty = false;
360 info->memclk.enable = true;
361 } else if (info->memclk.rate == 0 && (!enable) &&
362 (info->memclk.enable)) {
363 clk_disable(info->memclk.clk);
364 info->memclk.dirty = false;
365 info->memclk.enable = false;
366 }
367 }
368
369 return status;
370}
371
372/**
373 * msm_bus_fabric_clk_commit() - Call clock enable and update clock
374 * values.
375*/
376static int msm_bus_fabric_clk_commit(int enable, struct msm_bus_fabric *fabric)
377{
378 unsigned int i, nfound = 0, status = 0;
379 struct msm_bus_inode_info *info[fabric->pdata->nslaves];
380
381 if (fabric->clk_dirty == false) {
382 MSM_BUS_DBG("No clocks have been touched for fabric: %d\n",
383 fabric->fabdev.id);
384 goto out;
385 } else
386 status = msm_bus_fabric_clk_set(enable, &fabric->info);
387
388 if (status)
389 MSM_BUS_WARN("Error setting clocks on fabric: %d\n",
390 fabric->fabdev.id);
391
392 nfound = radix_tree_gang_lookup_tag(&fabric->fab_tree, (void **)&info,
393 fabric->fabdev.id, fabric->pdata->nslaves, SLAVE_NODE);
394 if (nfound == 0) {
395 MSM_BUS_DBG("No slaves found for fabric: %d\n",
396 fabric->fabdev.id);
397 goto out;
398 }
399
400 for (i = 0; i < nfound; i++) {
401 status = msm_bus_fabric_clk_set(enable, info[i]);
402 if (status)
403 MSM_BUS_WARN("Error setting clocks for node: %d\n",
404 info[i]->node_info->id);
405 }
406
407out:
408 return status;
409}
410
411/**
412 * msm_bus_fabric_rpm_commit() - Commit the arbitration data to RPM
413 * @fabric: Fabric for which the data should be committed
414 * */
415static int msm_bus_fabric_rpm_commit(struct msm_bus_fabric_device *fabdev,
416 int ctx)
417
418{
419 int status = 0;
420 struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
421 void *cdata;
422
423 /*
424 * For a non-zero bandwidth request, clocks should be enabled before
425 * sending the arbitration data to RPM, but should be disabled only
426 * after commiting the data.
427 */
428 status = msm_bus_fabric_clk_commit(ENABLE, fabric);
429 if (status)
430 MSM_BUS_DBG("Error setting clocks on fabric: %d\n",
431 fabric->fabdev.id);
432
433 if (!fabric->arb_dirty) {
434 MSM_BUS_DBG("Not committing as fabric not arb_dirty\n");
435 goto skip_arb;
436 }
437
438 cdata = fabric->cdata[ctx];
439 status = msm_bus_rpm_commit(fabric->pdata, ctx,
440 fabric->rpm_data, cdata);
441 if (status)
442 MSM_BUS_DBG("Error committing arb data for fabric: %d\n",
443 fabric->fabdev.id);
444
445 fabric->arb_dirty = false;
446skip_arb:
447 /*
448 * If the bandwidth request is 0 for a fabric, the clocks
449 * should be disabled after arbitration data is committed.
450 */
451 status = msm_bus_fabric_clk_commit(DISABLE, fabric);
452 if (status)
453 MSM_BUS_DBG("Error disabling clocks on fabric: %d\n",
454 fabric->fabdev.id);
455
456 fabric->clk_dirty = false;
457 return status;
458}
459
460/**
461 * msm_bus_fabric_port_halt() - Used to halt a master port
462 * @fabric: Fabric on which the current master node is present
463 * @portid: Port id of the master
464 */
465int msm_bus_fabric_port_halt(struct msm_bus_fabric_device *fabdev, int iid)
466{
467 struct msm_bus_halt_vector hvector = {0, 0};
468 struct msm_rpm_iv_pair rpm_data[2];
469 struct msm_bus_inode_info *info = NULL;
Gagan Macc7c0db62011-07-20 13:07:29 -0600470 uint8_t mport;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700471 uint32_t haltid = 0;
472 int status = 0;
473 struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
474
475 info = fabdev->algo->find_node(fabdev, iid);
476 if (!info) {
477 MSM_BUS_ERR("Error: Info not found for id: %u", iid);
478 return -EINVAL;
479 }
480
481 haltid = fabric->pdata->haltid;
Gagan Macc7c0db62011-07-20 13:07:29 -0600482 mport = info->node_info->masterp[0];
483 MSM_BUS_MASTER_HALT(hvector.haltmask, hvector.haltval, mport);
484 rpm_data[0].id = haltid;
485 rpm_data[0].value = hvector.haltval;
486 rpm_data[1].id = haltid + 1;
487 rpm_data[1].value = hvector.haltmask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488
Gagan Macc7c0db62011-07-20 13:07:29 -0600489 MSM_FAB_DBG("ctx: %d, id: %d, value: %d\n",
490 MSM_RPM_CTX_SET_0, rpm_data[0].id, rpm_data[0].value);
491 MSM_FAB_DBG("ctx: %d, id: %d, value: %d\n",
492 MSM_RPM_CTX_SET_0, rpm_data[1].id, rpm_data[1].value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700493
Gagan Macc7c0db62011-07-20 13:07:29 -0600494 if (fabric->pdata->rpm_enabled)
495 status = msm_rpm_set(MSM_RPM_CTX_SET_0, rpm_data, 2);
496 if (status)
497 MSM_BUS_ERR("msm_rpm_set returned: %d\n", status);
498
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700499 return status;
500}
501
502/**
503 * msm_bus_fabric_port_unhalt() - Used to unhalt a master port
504 * @fabric: Fabric on which the current master node is present
505 * @portid: Port id of the master
506 */
507int msm_bus_fabric_port_unhalt(struct msm_bus_fabric_device *fabdev, int iid)
508{
509 struct msm_bus_halt_vector hvector = {0, 0};
510 struct msm_rpm_iv_pair rpm_data[2];
511 struct msm_bus_inode_info *info = NULL;
Gagan Macc7c0db62011-07-20 13:07:29 -0600512 uint8_t mport;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513 uint32_t haltid = 0;
514 int status = 0;
515 struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
516
517 info = fabdev->algo->find_node(fabdev, iid);
518 if (!info) {
519 MSM_BUS_ERR("Error: Info not found for id: %u", iid);
520 return -EINVAL;
521 }
522
523 haltid = fabric->pdata->haltid;
Gagan Macc7c0db62011-07-20 13:07:29 -0600524 mport = info->node_info->masterp[0];
525 MSM_BUS_MASTER_UNHALT(hvector.haltmask, hvector.haltval,
526 mport);
527 rpm_data[0].id = haltid;
528 rpm_data[0].value = hvector.haltval;
529 rpm_data[1].id = haltid + 1;
530 rpm_data[1].value = hvector.haltmask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700531
Gagan Macc7c0db62011-07-20 13:07:29 -0600532 MSM_FAB_DBG("unalt: ctx: %d, id: %d, value: %d\n",
533 MSM_RPM_CTX_SET_SLEEP, rpm_data[0].id, rpm_data[0].value);
534 MSM_FAB_DBG("unhalt: ctx: %d, id: %d, value: %d\n",
535 MSM_RPM_CTX_SET_SLEEP, rpm_data[1].id, rpm_data[1].value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700536
Gagan Macc7c0db62011-07-20 13:07:29 -0600537 if (fabric->pdata->rpm_enabled)
538 status = msm_rpm_set(MSM_RPM_CTX_SET_0, rpm_data, 2);
539 if (status)
540 MSM_BUS_ERR("msm_rpm_set returned: %d\n", status);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700541
542 return status;
543}
544
545/**
546 * msm_bus_fabric_find_gw_node() - This function finds the gateway node
547 * attached on a given fabric
548 * @id: ID of the gateway node
549 * @fabric: Fabric to find the gateway node on
550 * Function returns: Pointer to the gateway node
551 */
552static struct msm_bus_inode_info *msm_bus_fabric_find_gw_node(struct
553 msm_bus_fabric_device * fabdev, int id)
554{
555 struct msm_bus_inode_info *info = NULL;
556 struct msm_bus_fabnodeinfo *fab;
557 struct msm_bus_fabric *fabric;
558 if (!fabdev) {
559 MSM_BUS_ERR("No fabric device found!\n");
560 return NULL;
561 }
562
563 fabric = to_msm_bus_fabric(fabdev);
564 if (!fabric || IS_ERR(fabric)) {
565 MSM_BUS_ERR("No fabric type found!\n");
566 return NULL;
567 }
568 list_for_each_entry(fab, &fabric->gateways, list) {
569 if (fab->info->node_info->priv_id == id) {
570 info = fab->info;
571 break;
572 }
573 }
574
575 return info;
576}
577
578static struct msm_bus_inode_info *msm_bus_fabric_find_node(struct
579 msm_bus_fabric_device * fabdev, int id)
580{
581 struct msm_bus_inode_info *info = NULL;
582 struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
583 info = radix_tree_lookup(&fabric->fab_tree, id);
584 if (!info)
585 MSM_FAB_DBG("Null info found for id %d\n", id);
586 return info;
587}
588
589static struct list_head *msm_bus_fabric_get_gw_list(struct msm_bus_fabric_device
590 *fabdev)
591{
592 struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
593 if (!fabric || IS_ERR(fabric)) {
594 MSM_BUS_ERR("No fabric found from fabdev\n");
595 return NULL;
596 }
597 return &fabric->gateways;
598
599}
600static struct msm_bus_fab_algorithm msm_bus_algo = {
601 .update_clks = msm_bus_fabric_update_clks,
602 .update_bw = msm_bus_fabric_update_bw,
603 .port_halt = msm_bus_fabric_port_halt,
604 .port_unhalt = msm_bus_fabric_port_unhalt,
605 .commit = msm_bus_fabric_rpm_commit,
606 .find_node = msm_bus_fabric_find_node,
607 .find_gw_node = msm_bus_fabric_find_gw_node,
608 .get_gw_list = msm_bus_fabric_get_gw_list,
609};
610
611static int msm_bus_fabric_probe(struct platform_device *pdev)
612{
613 int ctx, ret = 0;
614 struct msm_bus_fabric *fabric;
615 struct msm_bus_fabric_registration *pdata;
616
617 fabric = kzalloc(sizeof(struct msm_bus_fabric), GFP_KERNEL);
618 if (!fabric) {
619 MSM_BUS_ERR("Fabric alloc failed\n");
620 return -ENOMEM;
621 }
622
623 INIT_LIST_HEAD(&fabric->gateways);
624 INIT_RADIX_TREE(&fabric->fab_tree, GFP_ATOMIC);
625 fabric->num_nodes = 0;
626 fabric->fabdev.id = pdev->id;
627 fabric->fabdev.visited = false;
628
629 fabric->info.node_info = kzalloc(sizeof(struct msm_bus_node_info),
630 GFP_KERNEL);
631 if (!fabric->info.node_info) {
632 MSM_BUS_ERR("Fabric node info alloc failed\n");
633 kfree(fabric);
634 return -ENOMEM;
635 }
636 fabric->info.node_info->priv_id = fabric->fabdev.id;
637 fabric->info.node_info->id = fabric->fabdev.id;
638 fabric->info.num_pnodes = -1;
639 fabric->info.link_info.clk[DUAL_CTX] = 0;
640 fabric->info.link_info.bw[DUAL_CTX] = 0;
641 fabric->info.link_info.clk[ACTIVE_CTX] = 0;
642 fabric->info.link_info.bw[ACTIVE_CTX] = 0;
643
644 fabric->fabdev.id = pdev->id;
645 pdata = (struct msm_bus_fabric_registration *)pdev->dev.platform_data;
646 fabric->fabdev.name = pdata->name;
647 fabric->fabdev.algo = &msm_bus_algo;
648 fabric->ahb = pdata->ahb;
649 fabric->pdata = pdata;
650 msm_bus_board_assign_iids(fabric->pdata, fabric->fabdev.id);
651
652 for (ctx = 0; ctx < NUM_CTX; ctx++) {
653 if (pdata->fabclk[ctx]) {
654 fabric->info.nodeclk[ctx].clk = clk_get(NULL,
655 pdata->fabclk[ctx]);
656 if (IS_ERR(fabric->info.nodeclk[ctx].clk)) {
657 MSM_BUS_ERR("Couldn't get clock %s\n",
658 pdata->fabclk[ctx]);
659 ret = -EINVAL;
660 goto err;
661 }
662 fabric->info.nodeclk[ctx].enable = false;
663 fabric->info.nodeclk[ctx].dirty = false;
664 }
665 }
666
667 /* Find num. of slaves, masters, populate gateways, radix tree */
668 ret = register_fabric_info(fabric);
669 if (ret) {
670 MSM_BUS_ERR("Could not register fabric %d info, ret: %d\n",
671 fabric->fabdev.id, ret);
672 goto err;
673 }
674 if (!fabric->ahb) {
675 /* Allocate memory for commit data */
676 for (ctx = 0; ctx < NUM_CTX; ctx++) {
677 ret = allocate_commit_data(fabric->pdata, &fabric->
678 cdata[ctx]);
679 if (ret) {
680 MSM_BUS_ERR("Failed to alloc commit data for "
681 "fab: %d, ret = %d\n",
682 fabric->fabdev.id, ret);
683 goto err;
684 }
685 }
686 }
687 /*
688 * clk and bw for fabric->info will contain the max bw and clk
689 * it will allow. This info will come from the boards file.
690 */
691 ret = msm_bus_fabric_device_register(&fabric->fabdev);
692 if (ret) {
693 MSM_BUS_ERR("Error registering fabric %d ret %d\n",
694 fabric->fabdev.id, ret);
695 goto err;
696 }
697
698 return ret;
699err:
700 kfree(fabric->info.node_info);
701 kfree(fabric);
702 return ret;
703}
704
705static int msm_bus_fabric_remove(struct platform_device *pdev)
706{
707 struct msm_bus_fabric_device *fabdev = NULL;
708 struct msm_bus_fabric *fabric;
709 int i;
710 int ret = 0;
711
712 fabdev = platform_get_drvdata(pdev);
713 msm_bus_fabric_device_unregister(fabdev);
714 fabric = to_msm_bus_fabric(fabdev);
715 msm_bus_dbg_commit_data(fabric->fabdev.name, NULL, 0, 0, 0,
716 MSM_BUS_DBG_UNREGISTER);
717 for (i = 0; i < fabric->pdata->nmasters; i++)
718 radix_tree_delete(&fabric->fab_tree, fabric->fabdev.id + i);
719 for (i = (fabric->fabdev.id + SLAVE_ID_KEY); i <
720 fabric->pdata->nslaves; i++)
721 radix_tree_delete(&fabric->fab_tree, i);
722 if (!fabric->ahb) {
723 free_commit_data(fabric->cdata[DUAL_CTX]);
724 free_commit_data(fabric->cdata[ACTIVE_CTX]);
725 }
726
727 kfree(fabric->info.node_info);
728 kfree(fabric->rpm_data);
729 kfree(fabric);
730 return ret;
731}
732
733static struct platform_driver msm_bus_fabric_driver = {
734 .probe = msm_bus_fabric_probe,
735 .remove = msm_bus_fabric_remove,
736 .driver = {
737 .name = "msm_bus_fabric",
738 .owner = THIS_MODULE,
739 },
740};
741
742static int __init msm_bus_fabric_init_driver(void)
743{
744 MSM_BUS_ERR("msm_bus_fabric_init_driver\n");
745 return platform_driver_register(&msm_bus_fabric_driver);
746}
747postcore_initcall(msm_bus_fabric_init_driver);