blob: 7c2b4c96e2436c07705f1d2a544ac82426cb8883 [file] [log] [blame]
Michael Bohan5a52a642013-01-18 16:16:03 -08001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Gagan Macb91c4072012-05-09 16:00:31 -06002 *
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
14#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
15
16#include "msm_bus_core.h"
17#include <mach/msm_bus.h>
18#include <mach/msm_bus_board.h>
19#include <mach/rpm-smd.h>
20
21/* Stubs for backward compatibility */
22void msm_bus_rpm_set_mt_mask()
23{
24}
25
26bool msm_bus_rpm_is_mem_interleaved(void)
27{
28 return true;
29}
30
31struct commit_data {
32 struct msm_bus_node_hw_info *mas_arb;
33 struct msm_bus_node_hw_info *slv_arb;
34};
35
36#ifdef CONFIG_DEBUG_FS
37void msm_bus_rpm_fill_cdata_buffer(int *curr, char *buf, const int max_size,
38 void *cdata, int nmasters, int nslaves, int ntslaves)
39{
40 int c;
41 struct commit_data *cd = (struct commit_data *)cdata;
42
43 *curr += scnprintf(buf + *curr, max_size - *curr, "\nMas BW:\n");
44 for (c = 0; c < nmasters; c++)
45 *curr += scnprintf(buf + *curr, max_size - *curr,
46 "%d: %llu\t", cd->mas_arb[c].hw_id,
47 cd->mas_arb[c].bw);
48 *curr += scnprintf(buf + *curr, max_size - *curr, "\nSlave BW:\n");
49 for (c = 0; c < nslaves; c++) {
50 *curr += scnprintf(buf + *curr, max_size - *curr,
51 "%d: %llu\t", cd->slv_arb[c].hw_id,
52 cd->slv_arb[c].bw);
53 }
54}
55#endif
56
57static int msm_bus_rpm_compare_cdata(
58 struct msm_bus_fabric_registration *fab_pdata,
59 struct commit_data *cd1, struct commit_data *cd2)
60{
61 size_t n;
62 int ret;
63
64 n = sizeof(struct msm_bus_node_hw_info) * fab_pdata->nmasters * 2;
65 ret = memcmp(cd1->mas_arb, cd2->mas_arb, n);
66 if (ret) {
67 MSM_BUS_DBG("Master Arb Data not equal\n");
68 return ret;
69 }
70
71 n = sizeof(struct msm_bus_node_hw_info) * fab_pdata->nslaves * 2;
72 ret = memcmp(cd1->slv_arb, cd2->slv_arb, n);
73 if (ret) {
74 MSM_BUS_DBG("Master Arb Data not equal\n");
75 return ret;
76 }
77
78 return 0;
79}
80
81static int msm_bus_rpm_req(int ctx, uint32_t rsc_type, uint32_t key,
82 struct msm_bus_node_hw_info *hw_info, bool valid)
83{
84 struct msm_rpm_request *rpm_req;
85 int ret = 0, msg_id;
86
87 if (ctx == ACTIVE_CTX)
88 ctx = MSM_RPM_CTX_ACTIVE_SET;
89 else if (ctx == DUAL_CTX)
90 ctx = MSM_RPM_CTX_SLEEP_SET;
91
92 rpm_req = msm_rpm_create_request(ctx, rsc_type, hw_info->hw_id, 1);
93 if (rpm_req == NULL) {
94 MSM_BUS_WARN("RPM: Couldn't create RPM Request\n");
95 return -ENXIO;
96 }
97
98 if (valid) {
99 ret = msm_rpm_add_kvp_data(rpm_req, key, (const uint8_t *)
100 &hw_info->bw, (int)(sizeof(uint64_t)));
101 if (ret) {
102 MSM_BUS_WARN("RPM: Add KVP failed for RPM Req:%u\n",
103 rsc_type);
Michael Bohan5a52a642013-01-18 16:16:03 -0800104 goto free_rpm_request;
Gagan Macb91c4072012-05-09 16:00:31 -0600105 }
106
107 MSM_BUS_DBG("Added Key: %d, Val: %llu, size: %d\n", key,
108 hw_info->bw, sizeof(uint64_t));
109 } else {
110 /* Invalidate RPM requests */
111 ret = msm_rpm_add_kvp_data(rpm_req, 0, NULL, 0);
112 if (ret) {
113 MSM_BUS_WARN("RPM: Add KVP failed for RPM Req:%u\n",
114 rsc_type);
Michael Bohan5a52a642013-01-18 16:16:03 -0800115 goto free_rpm_request;
Gagan Macb91c4072012-05-09 16:00:31 -0600116 }
117 }
118
119 msg_id = msm_rpm_send_request(rpm_req);
120 if (!msg_id) {
121 MSM_BUS_WARN("RPM: No message ID for req\n");
Michael Bohan5a52a642013-01-18 16:16:03 -0800122 ret = -ENXIO;
123 goto free_rpm_request;
Gagan Macb91c4072012-05-09 16:00:31 -0600124 }
125
126 ret = msm_rpm_wait_for_ack(msg_id);
127 if (ret) {
128 MSM_BUS_WARN("RPM: Ack failed\n");
Michael Bohan5a52a642013-01-18 16:16:03 -0800129 goto free_rpm_request;
Gagan Macb91c4072012-05-09 16:00:31 -0600130 }
131
Michael Bohan5a52a642013-01-18 16:16:03 -0800132free_rpm_request:
133 msm_rpm_free_request(rpm_req);
134
Gagan Macb91c4072012-05-09 16:00:31 -0600135 return ret;
136}
137
138static int msm_bus_rpm_commit_arb(struct msm_bus_fabric_registration
139 *fab_pdata, int ctx, void *rpm_data,
140 struct commit_data *cd, bool valid)
141{
142 int i, status = 0, rsc_type, key;
143
144 MSM_BUS_DBG("Context: %d\n", ctx);
145 rsc_type = RPM_BUS_MASTER_REQ;
146 key = RPM_MASTER_FIELD_BW;
147 for (i = 0; i < fab_pdata->nmasters; i++) {
148 if (cd->mas_arb[i].dirty) {
149 MSM_BUS_DBG("MAS HWID: %d, BW: %llu DIRTY: %d\n",
150 cd->mas_arb[i].hw_id,
151 cd->mas_arb[i].bw,
152 cd->mas_arb[i].dirty);
153 status = msm_bus_rpm_req(ctx, rsc_type, key,
154 &cd->mas_arb[i], valid);
155 if (status) {
156 MSM_BUS_ERR("RPM: Req fail: mas:%d, bw:%llu\n",
157 cd->mas_arb[i].hw_id,
158 cd->mas_arb[i].bw);
159 break;
160 } else {
161 cd->mas_arb[i].dirty = false;
162 }
163 }
164 }
165
166 rsc_type = RPM_BUS_SLAVE_REQ;
167 key = RPM_SLAVE_FIELD_BW;
168 for (i = 0; i < fab_pdata->nslaves; i++) {
169 if (cd->slv_arb[i].dirty) {
170 MSM_BUS_DBG("SLV HWID: %d, BW: %llu DIRTY: %d\n",
171 cd->slv_arb[i].hw_id,
172 cd->slv_arb[i].bw,
173 cd->slv_arb[i].dirty);
174 status = msm_bus_rpm_req(ctx, rsc_type, key,
175 &cd->slv_arb[i], valid);
176 if (status) {
177 MSM_BUS_ERR("RPM: Req fail: slv:%d, bw:%llu\n",
178 cd->slv_arb[i].hw_id,
179 cd->slv_arb[i].bw);
180 break;
181 } else {
182 cd->slv_arb[i].dirty = false;
183 }
184 }
185 }
186
187 return status;
188}
189
190/**
191* msm_bus_remote_hw_commit() - Commit the arbitration data to RPM
192* @fabric: Fabric for which the data should be committed
193**/
194int msm_bus_remote_hw_commit(struct msm_bus_fabric_registration
195 *fab_pdata, void *hw_data, void **cdata)
196{
197
198 int ret;
199 bool valid;
200 struct commit_data *dual_cd, *act_cd;
201 void *rpm_data = hw_data;
202
203 MSM_BUS_DBG("\nReached RPM Commit\n");
204 dual_cd = (struct commit_data *)cdata[DUAL_CTX];
205 act_cd = (struct commit_data *)cdata[ACTIVE_CTX];
206
207 /*
208 * If the arb data for active set and sleep set is
209 * different, commit both sets.
210 * If the arb data for active set and sleep set is
211 * the same, invalidate the sleep set.
212 */
213 ret = msm_bus_rpm_compare_cdata(fab_pdata, act_cd, dual_cd);
214 if (!ret)
215 /* Invalidate sleep set.*/
216 valid = false;
217 else
218 valid = true;
219
220 ret = msm_bus_rpm_commit_arb(fab_pdata, DUAL_CTX, rpm_data,
221 dual_cd, valid);
222 if (ret)
223 MSM_BUS_ERR("Error comiting fabric:%d in %d ctx\n",
224 fab_pdata->id, DUAL_CTX);
225
226 valid = true;
227 ret = msm_bus_rpm_commit_arb(fab_pdata, ACTIVE_CTX, rpm_data, act_cd,
228 valid);
229 if (ret)
230 MSM_BUS_ERR("Error comiting fabric:%d in %d ctx\n",
231 fab_pdata->id, ACTIVE_CTX);
232
233 return ret;
234}
235
236int msm_bus_rpm_hw_init(struct msm_bus_fabric_registration *pdata,
237 struct msm_bus_hw_algorithm *hw_algo)
238{
239 if (!pdata->ahb)
240 pdata->rpm_enabled = 1;
241 return 0;
242}